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 VikingAI v0.1.1
VikingAI.dll
Decompiled a day 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.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Entities; using Jotunn.Managers; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.AI; using VikingAI.Configuration; using VikingAI.Core; using VikingAI.FlowField; using VikingAI.Locomotion; using VikingAI.NPC.Affordances; using VikingAI.NPC.Prefabs; using VikingAI.NPC.Utility; using VikingAI.Navigation; using VikingAI.Patches; using VikingAI.Profiles; using VikingAI.Simulation; using VikingAI.Tactics; using VikingAI.Telemetry; [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("DigitalVikings")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Foundational 2.5D navigation graph, flow-field steering, tactical pack coordination, smart-object affordances, and virtual NPC simulation framework for Valheim.")] [assembly: AssemblyFileVersion("0.1.1.0")] [assembly: AssemblyInformationalVersion("0.1.1+1819713a0086c92118d209a9c814ec4b38edc8fc")] [assembly: AssemblyProduct("VikingAI")] [assembly: AssemblyTitle("VikingAI")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.1.1.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] 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 VikingAI { [BepInPlugin("com.digitalvikings.vikingai", "VikingAI", "0.1.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class VikingAIPlugin : BaseUnityPlugin { public const string ModGuid = "com.digitalvikings.vikingai"; public const string ModName = "VikingAI"; public const string ModVersion = "0.1.1"; private Harmony _harmony; public static VikingAIPlugin Instance { get; private set; } public static ManualLogSource Log { get; internal set; } private void Awake() { //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; Log.LogInfo((object)"VikingAI v0.1.1 initializing..."); ModConfig.Init(((BaseUnityPlugin)this).Config); BrainPipeline.RegisterModule(new PackFlankBrainModule()); BrainPipeline.RegisterModule(new InvestigateBrainModule()); BrainPipeline.RegisterModule(new SmartAffordanceBrainModule()); ((Component)this).gameObject.AddComponent<NavDebugOverlay>(); VikingAIConsoleCommand.Register(); _harmony = new Harmony("com.digitalvikings.vikingai"); _harmony.PatchAll(); Log.LogInfo((object)"VikingAI v0.1.1 loaded successfully."); if (Chainloader.PluginInfos.ContainsKey("com.jotunn.jotunn")) { HookJotunnSync(); } } private void Update() { if (ModConfig.ModEnabled.Value) { VirtualAgentDirector.UpdateDirector(Time.deltaTime); if (NavDebugOverlay.ActiveMode != DebugDrawMode.Off) { NavGraphManager.DrawDebugTelemetry(); TacticalFlowField.DrawDebugTelemetry(); AffordanceRegistry.DrawDebugTelemetry(); } } } [MethodImpl(MethodImplOptions.NoInlining)] private void HookJotunnSync() { SynchronizationManager.OnConfigurationSynchronized += delegate { Log.LogInfo((object)"Server configuration synchronized successfully."); }; } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } } namespace VikingAI.Telemetry { [Flags] public enum DebugDrawMode { Off = 0, Grid = 1, Flow = 2, Steering = 4, Tokens = 8, Affordances = 0x10, Senses = 0x20, All = 0x3F } public struct DebugLineSegment { public Vector3 Start; public Vector3 End; public Color Color; } public struct DebugWorldLabel { public Vector3 WorldPos; public string Text; public Color Color; } public sealed class NavDebugOverlay : MonoBehaviour { private static readonly List<DebugLineSegment> _frameLines = new List<DebugLineSegment>(512); private static readonly List<DebugWorldLabel> _frameLabels = new List<DebugWorldLabel>(128); private static Material? _lineMaterial; private static int _lastClearedFrame = -1; public static DebugDrawMode ActiveMode { get; set; } = DebugDrawMode.Off; public static bool IsModeActive(DebugDrawMode mode) { return (ActiveMode & mode) != 0; } public static void AddLine(Vector3 start, Vector3 end, Color color) { //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_0035: 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_003d: 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 (ActiveMode != DebugDrawMode.Off) { EnsureFrameCleared(); if (_frameLines.Count < 4096) { _frameLines.Add(new DebugLineSegment { Start = start, End = end, Color = color }); } } } public static void AddLabel(Vector3 worldPos, string text, Color color) { //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_003d: 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 (ActiveMode != DebugDrawMode.Off) { EnsureFrameCleared(); if (_frameLabels.Count < 256) { _frameLabels.Add(new DebugWorldLabel { WorldPos = worldPos, Text = text, Color = color }); } } } private static void EnsureFrameCleared() { int frameCount = Time.frameCount; if (_lastClearedFrame != frameCount) { _lastClearedFrame = frameCount; _frameLines.Clear(); _frameLabels.Clear(); } } private static void EnsureMaterial() { //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_0035: Expected O, but got Unknown if (!((Object)(object)_lineMaterial != (Object)null)) { Shader val = Shader.Find("Hidden/Internal-Colored"); if ((Object)(object)val != (Object)null) { _lineMaterial = new Material(val) { hideFlags = (HideFlags)61 }; _lineMaterial.SetInt("_SrcBlend", 5); _lineMaterial.SetInt("_DstBlend", 10); _lineMaterial.SetInt("_Cull", 0); _lineMaterial.SetInt("_ZWrite", 0); } } } private void OnRenderObject() { //IL_004f: 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_0070: 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_008b: 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) if (ActiveMode == DebugDrawMode.Off || _frameLines.Count == 0) { return; } EnsureMaterial(); if (!((Object)(object)_lineMaterial == (Object)null)) { _lineMaterial.SetPass(0); GL.PushMatrix(); GL.Begin(1); for (int i = 0; i < _frameLines.Count; i++) { DebugLineSegment debugLineSegment = _frameLines[i]; GL.Color(debugLineSegment.Color); GL.Vertex3(debugLineSegment.Start.x, debugLineSegment.Start.y, debugLineSegment.Start.z); GL.Vertex3(debugLineSegment.End.x, debugLineSegment.End.y, debugLineSegment.End.z); } GL.End(); GL.PopMatrix(); } } private void OnGUI() { //IL_0018: 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_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_0073: 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_0087: 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_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_00c9: 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_00e5: Unknown result type (might be due to invalid IL or missing references) if (ActiveMode == DebugDrawMode.Off) { return; } Camera mainCamera = Utils.GetMainCamera(); if ((Object)(object)mainCamera == (Object)null) { return; } GUI.color = Color.cyan; GUI.Label(new Rect(16f, 16f, 480f, 26f), $"[VikingAI Telemetry] Active Modes: {ActiveMode}"); for (int i = 0; i < _frameLabels.Count; i++) { DebugWorldLabel debugWorldLabel = _frameLabels[i]; Vector3 val = mainCamera.WorldToScreenPoint(debugWorldLabel.WorldPos); if (!(val.z <= 0f)) { float num = (float)Screen.height - val.y; GUI.color = Color.black; GUI.Label(new Rect(val.x + 1f, num + 1f, 260f, 44f), debugWorldLabel.Text); GUI.color = debugWorldLabel.Color; GUI.Label(new Rect(val.x, num, 260f, 44f), debugWorldLabel.Text); } } } } public sealed class VikingAIConsoleCommand : ConsoleCommand { public override string Name => "vikingai"; public override string Help => "VikingAI diagnostic telemetry and debug visualization (subcommands: debug, stats)"; public override bool IsCheat => false; public static void Register() { CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new VikingAIConsoleCommand()); } public override void Run(string[] args) { if (args == null || args.Length == 0) { Console.instance.Print("Usage: vikingai debug [grid|flow|steering|tokens|affordances|senses|all|off] | vikingai stats"); return; } string text = args[0].ToLowerInvariant(); if (text == "debug") { string text2 = ((args.Length > 1) ? args[1].ToLowerInvariant() : "all"); switch (text2) { case "off": case "none": NavDebugOverlay.ActiveMode = DebugDrawMode.Off; break; case "grid": ToggleFlag(DebugDrawMode.Grid); break; case "flow": ToggleFlag(DebugDrawMode.Flow); break; case "steering": ToggleFlag(DebugDrawMode.Steering); break; case "tokens": ToggleFlag(DebugDrawMode.Tokens); break; case "affordances": ToggleFlag(DebugDrawMode.Affordances); break; case "senses": ToggleFlag(DebugDrawMode.Senses); break; case "all": NavDebugOverlay.ActiveMode = DebugDrawMode.All; break; default: Console.instance.Print("Unknown debug mode '" + text2 + "'. Valid modes: grid, flow, steering, tokens, affordances, senses, all, off"); return; } Console.instance.Print($"[VikingAI] Debug overlay mode: {NavDebugOverlay.ActiveMode}"); } else if (text == "stats") { Console.instance.Print($"[VikingAI] Tracked pieces — Doors: {PieceRegistry.Doors.Count}, " + $"Smelters: {PieceRegistry.Smelters.Count}, Containers: {PieceRegistry.Containers.Count}, " + $"Fireplaces: {PieceRegistry.Fireplaces.Count}, Plants: {PieceRegistry.Plants.Count}, " + $"Pickables: {PieceRegistry.Pickables.Count}, Beds: {PieceRegistry.Beds.Count}, Chairs: {PieceRegistry.Chairs.Count}"); } else { Console.instance.Print("Unknown subcommand. Usage: vikingai debug [mode] | vikingai stats"); } } public override List<string> CommandOptionList() { return new List<string> { "debug", "stats" }; } private static void ToggleFlag(DebugDrawMode flag) { if ((NavDebugOverlay.ActiveMode & flag) != DebugDrawMode.Off) { NavDebugOverlay.ActiveMode &= ~flag; } else { NavDebugOverlay.ActiveMode |= flag; } } } } namespace VikingAI.Tactics { public static class BrainPipeline { private static readonly List<IAIBrainModule> _modules = new List<IAIBrainModule>(8); private static readonly ConditionalWeakTable<BaseAI, IAIBrainModule> _activeModuleByAi = new ConditionalWeakTable<BaseAI, IAIBrainModule>(); public static void RegisterModule(IAIBrainModule module) { if (module != null) { _modules.RemoveAll((IAIBrainModule m) => m.Id == module.Id); _modules.Add(module); } } public static IAIBrainModule? GetActiveModule(BaseAI ai) { if ((Object)(object)ai != (Object)null && _activeModuleByAi.TryGetValue(ai, out IAIBrainModule value)) { return value; } return null; } public static bool TryExecuteModules(BaseAI ai, Character character, float dt) { if (!ModConfig.ModEnabled.Value || _modules.Count == 0) { return false; } AgentBehaviorProfile profile = AgentProfileRegistry.GetProfile(character); IAIBrainModule iAIBrainModule = null; float num = 0f; for (int i = 0; i < _modules.Count; i++) { IAIBrainModule iAIBrainModule2 = _modules[i]; float num2 = iAIBrainModule2.EvaluateUtility(ai, character, profile); if (num2 > num) { num = num2; iAIBrainModule = iAIBrainModule2; } } _activeModuleByAi.Remove(ai); if (iAIBrainModule == null) { return false; } _activeModuleByAi.Add(ai, iAIBrainModule); return iAIBrainModule.Tick(ai, character, profile, dt); } } public static class CombatPackCoordinator { private sealed class TokenAllocation { public Character Holder; public float Weight; public float GrantedAtTime; public float ExpiresAtTime; } private static readonly List<ITargetScorer> _scorers = new List<ITargetScorer> { new ProximityThreatScorer() }; private static readonly Dictionary<Character, List<TokenAllocation>> _tokensByTarget = new Dictionary<Character, List<TokenAllocation>>(8); private static readonly List<Character> _nearbyPackTemp = new List<Character>(16); public static void RegisterTargetScorer(ITargetScorer scorer) { if (scorer != null) { _scorers.RemoveAll((ITargetScorer s) => s.Id == scorer.Id); _scorers.Add(scorer); } } public static float EvaluateTotalTargetScore(BaseAI ai, Character agent, AgentBehaviorProfile profile, Character candidate) { float num = 0f; for (int i = 0; i < _scorers.Count; i++) { num += _scorers[i].ScoreTarget(ai, agent, profile, candidate); } return num; } public static bool RequestOrHoldAttackToken(Character attacker, AgentBehaviorProfile profile, Character target) { //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_0131: 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_0174: Unknown result type (might be due to invalid IL or missing references) //IL_017f: 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_0189: Unknown result type (might be due to invalid IL or missing references) if (!profile.UsePackAttackTokens) { return true; } float time = Time.time; if (!_tokensByTarget.TryGetValue(target, out List<TokenAllocation> value)) { value = new List<TokenAllocation>(6); _tokensByTarget[target] = value; } float num = 0f; TokenAllocation tokenAllocation = null; for (int num2 = value.Count - 1; num2 >= 0; num2--) { TokenAllocation tokenAllocation2 = value[num2]; if ((Object)(object)tokenAllocation2.Holder == (Object)null || tokenAllocation2.Holder.IsDead() || time > tokenAllocation2.ExpiresAtTime) { value.RemoveAt(num2); } else if ((Object)(object)tokenAllocation2.Holder == (Object)(object)attacker) { tokenAllocation = tokenAllocation2; } else { num += tokenAllocation2.Weight; } } if (tokenAllocation != null) { tokenAllocation.ExpiresAtTime = time + 2.8f; return true; } float value2 = ModConfig.MaxSimultaneousAttackTokens.Value; float num3 = Mathf.Max(0.5f, profile.AttackTokenWeight); if (num + num3 <= value2 + 0.01f || value.Count == 0) { value.Add(new TokenAllocation { Holder = attacker, Weight = num3, GrantedAtTime = time, ExpiresAtTime = time + 2.8f }); return true; } Vector3 val = ((Component)attacker).transform.position - ((Component)target).transform.position; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; for (int i = 0; i < value.Count; i++) { TokenAllocation tokenAllocation3 = value[i]; if (!(time - tokenAllocation3.GrantedAtTime < 1.8f)) { val = ((Component)tokenAllocation3.Holder).transform.position - ((Component)target).transform.position; float sqrMagnitude2 = ((Vector3)(ref val)).sqrMagnitude; if (sqrMagnitude + 9f < sqrMagnitude2) { value[i] = new TokenAllocation { Holder = attacker, Weight = num3, GrantedAtTime = time, ExpiresAtTime = time + 2.8f }; return true; } } } return false; } public static Vector3 GetFlankingRingPosition(Character attacker, Character 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_0016: 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_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) Vector3 position = ((Component)target).transform.position; _nearbyPackTemp.Clear(); SpatialCharacterGrid.QueryRadius(position, 18f, _nearbyPackTemp, target); int num = 0; int instanceID = ((Object)attacker).GetInstanceID(); for (int i = 0; i < _nearbyPackTemp.Count; i++) { Character val = _nearbyPackTemp[i]; if ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)attacker && ((Object)val).GetInstanceID() < instanceID) { num++; } } float num2 = (float)(num % 8) * 45f; float num3 = Mathf.Sin(Time.time * 0.65f + (float)num * 1.3f) * 22f; float num4 = (num2 + num3) * (MathF.PI / 180f); float num5 = 4.4f + (float)(num / 8) * 1.5f + target.GetRadius(); return position + new Vector3(Mathf.Sin(num4) * num5, 0f, Mathf.Cos(num4) * num5); } } public sealed class PackFlankBrainModule : IAIBrainModule { private static readonly MethodInfo _moveToMethod = AccessTools.Method(typeof(BaseAI), "MoveTo", (Type[])null, (Type[])null); private static readonly MethodInfo _havePathMethod = AccessTools.Method(typeof(BaseAI), "HavePath", (Type[])null, (Type[])null); public string Id => "VikingAI.PackFlankAndAntiPerch"; public float EvaluateUtility(BaseAI ai, Character character, AgentBehaviorProfile profile) { //IL_0074: 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_00b7: 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_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_0126: 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) MonsterAI val = (MonsterAI)(object)((ai is MonsterAI) ? ai : null); if (val == null) { return 0f; } Character targetCreature = ((BaseAI)val).GetTargetCreature(); if ((Object)(object)targetCreature == (Object)null || targetCreature.IsDead() || !ai.IsAlerted()) { return 0f; } Humanoid val2 = (Humanoid)(object)((character is Humanoid) ? character : null); if (val2 != null) { ItemData currentWeapon = val2.GetCurrentWeapon(); if (currentWeapon != null && currentWeapon.m_shared != null && currentWeapon.m_shared.m_aiAttackRange > 5f) { return 0f; } } if (((Component)targetCreature).transform.position.y - ((Component)character).transform.position.y > 2.2f && _havePathMethod != null && !(bool)_havePathMethod.Invoke(ai, new object[1] { ((Component)targetCreature).transform.position })) { return 75f; } if (!profile.UsePackAttackTokens) { return 0f; } bool flag = CombatPackCoordinator.RequestOrHoldAttackToken(character, profile, targetCreature); if (NavDebugOverlay.IsModeActive(DebugDrawMode.Tokens)) { NavDebugOverlay.AddLabel(character.GetTopPoint() + Vector3.up * 0.25f, flag ? "[TOKEN: ENGAGE]" : "[FLANKING RING]", flag ? Color.green : Color.cyan); } if (flag) { return 0f; } return 70f; } public bool Tick(BaseAI ai, Character character, AgentBehaviorProfile profile, float dt) { //IL_0031: 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_0070: 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_0075: 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_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_0090: 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_00e8: 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) MonsterAI val = (MonsterAI)(object)((ai is MonsterAI) ? ai : null); if (val == null || _moveToMethod == null) { return false; } Character targetCreature = ((BaseAI)val).GetTargetCreature(); if ((Object)(object)targetCreature == (Object)null) { return false; } Vector3 val2 = ((Component)targetCreature).transform.position - ((Component)character).transform.position; val2.y = 0f; Vector3 val3 = ((((Vector3)(ref val2)).sqrMagnitude > 0.01f) ? ((Vector3)(ref val2)).normalized : ((Component)character).transform.forward); LocomotionPatches.ActiveLookDirOverride = val3; try { Vector3 flankingRingPosition = CombatPackCoordinator.GetFlankingRingPosition(character, targetCreature); if (Utils.DistanceXZ(((Component)character).transform.position, flankingRingPosition) > 1.1f) { _moveToMethod.Invoke(ai, new object[4] { dt, flankingRingPosition, 0.5f, false }); } else { ai.StopMoving(); ai.LookTowards(val3); } } finally { LocomotionPatches.ActiveLookDirOverride = null; } return true; } } public sealed class TargetCoverState { public float IlluminationFactor = 1f; public float FoliageConcealment; public float AcousticRadius = 5f; public float LastSampleTime = -999f; } public static class EnvironmentCoverSampler { private static readonly ConditionalWeakTable<Character, TargetCoverState> _states = new ConditionalWeakTable<Character, TargetCoverState>(); private static readonly Collider[] _overlapBuffer = (Collider[])(object)new Collider[48]; private static int _shadowLayerMask; public static TargetCoverState GetOrSample(Character target) { if (!_states.TryGetValue(target, out TargetCoverState value)) { value = new TargetCoverState(); _states.Add(target, value); } float time = Time.time; if (time - value.LastSampleTime >= 0.25f) { value.LastSampleTime = time; UpdateTargetCover(target, value); } return value; } private static void UpdateTargetCover(Character target, TargetCoverState state) { //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_008a: Unknown result type (might be due to invalid IL or missing references) //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_0096: 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_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: 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_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_0270: Unknown result type (might be due to invalid IL or missing references) //IL_0275: Unknown result type (might be due to invalid IL or missing references) if (_shadowLayerMask == 0) { _shadowLayerMask = LayerMask.GetMask(new string[5] { "terrain", "Default", "static_solid", "piece", "piece_nonsolid" }); } Vector3 centerPoint = target.GetCenterPoint(); float num = 1f; if ((Object)(object)EnvMan.instance != (Object)null) { if (EnvMan.IsNight()) { num = 0.42f; } else if (EnvMan.IsAfternoon()) { num = 0.82f; } } Light sun = RenderSettings.sun; if ((Object)(object)sun != (Object)null) { Vector3 val = -((Component)sun).transform.forward; if (val.y > 0.05f && Physics.Raycast(centerPoint, val, 80f, _shadowLayerMask)) { num *= 0.65f; } } foreach (Fireplace fireplace in PieceRegistry.Fireplaces) { if (!((Object)(object)fireplace == (Object)null) && fireplace.IsBurning()) { Vector3 val2 = ((Component)fireplace).transform.position - centerPoint; float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude; if (sqrMagnitude < 81f) { float num2 = (1f - Mathf.Sqrt(sqrMagnitude) / 9f) * 0.55f; num = Mathf.Min(1.25f, num + num2); } } } state.IlluminationFactor = Mathf.Clamp(num, 0.2f, 1.25f); float foliageConcealment = 0f; int num3 = Mathf.Min(Physics.OverlapSphereNonAlloc(centerPoint, 1.85f, _overlapBuffer, _shadowLayerMask), 12); for (int i = 0; i < num3; i++) { Collider val3 = _overlapBuffer[i]; if (!((Object)(object)val3 == (Object)null) && IsFoliageColliderName(((Object)((Component)val3).gameObject).name)) { foliageConcealment = (target.IsCrouching() ? 0.48f : 0.22f); break; } } state.FoliageConcealment = foliageConcealment; float num4 = 0f; Humanoid val4 = (Humanoid)(object)((target is Humanoid) ? target : null); if (val4 != null) { Inventory inventory = val4.GetInventory(); if (inventory != null) { List<ItemData> allItems = inventory.GetAllItems(); for (int j = 0; j < allItems.Count; j++) { ItemData val5 = allItems[j]; if (val5 != null && val5.m_equipped && val5.m_shared != null) { num4 += val5.GetWeight(-1); } } } } float num5 = 1f + Mathf.Clamp01((num4 - 8f) / 36f) * 0.45f; Vector3 velocity = target.GetVelocity(); velocity.y = 0f; float magnitude = ((Vector3)(ref velocity)).magnitude; float num6 = (target.InAttack() ? 18f : ((magnitude < 0.25f) ? 0.5f : (target.IsCrouching() ? (2.2f * num5) : ((!target.IsRunning() && !(magnitude > 5f)) ? (6.5f * num5) : (14f * num5))))); state.AcousticRadius = Mathf.Max(num6, target.GetNoiseRange() * 0.35f); } private static bool IsFoliageColliderName(string name) { if (string.IsNullOrEmpty(name)) { return false; } if (name.IndexOf("Bush", StringComparison.OrdinalIgnoreCase) < 0 && name.IndexOf("Shrub", StringComparison.OrdinalIgnoreCase) < 0 && name.IndexOf("Fern", StringComparison.OrdinalIgnoreCase) < 0 && name.IndexOf("Raspberry", StringComparison.OrdinalIgnoreCase) < 0 && name.IndexOf("Blueberry", StringComparison.OrdinalIgnoreCase) < 0 && name.IndexOf("Cloudberry", StringComparison.OrdinalIgnoreCase) < 0 && name.IndexOf("Sapling", StringComparison.OrdinalIgnoreCase) < 0) { return name.IndexOf("Thistle", StringComparison.OrdinalIgnoreCase) >= 0; } return true; } } public interface IAIBrainModule { string Id { get; } float EvaluateUtility(BaseAI ai, Character character, AgentBehaviorProfile profile); bool Tick(BaseAI ai, Character character, AgentBehaviorProfile profile, float dt); } public interface ITargetScorer { string Id { get; } float ScoreTarget(BaseAI ai, Character agent, AgentBehaviorProfile profile, Character candidateTarget); } public sealed class ProximityThreatScorer : ITargetScorer { public string Id => "VikingAI.ProximityThreat"; public float ScoreTarget(BaseAI ai, Character agent, AgentBehaviorProfile profile, Character candidateTarget) { //IL_001f: 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 ((Object)(object)candidateTarget == (Object)null || candidateTarget.IsDead()) { return -1000f; } float num = Vector3.Distance(((Component)agent).transform.position, ((Component)candidateTarget).transform.position); float num2 = Mathf.Max(0f, 60f - num); MonsterAI val = (MonsterAI)(object)((ai is MonsterAI) ? ai : null); if (val != null && (Object)(object)((BaseAI)val).GetTargetCreature() == (Object)(object)candidateTarget) { num2 += 12f; } if (candidateTarget.GetHealthPercentage() < 0.25f) { num2 += 8f; } return num2; } } public enum DetectionStage : byte { Unaware, Suspicious, Alerted, Engaged } public sealed class SensoryTrack { public Character? Target; public float DetectionLevel; public DetectionStage Stage; public Vector3 LastKnownPos; public float LastStimulusTime; public float SearchTimeRemaining; } public static class SensoryMemoryController { private struct PendingAllyCall { public Character Caller; public Character Target; public Vector3 KnownPos; public float Radius; } private static readonly ConditionalWeakTable<BaseAI, SensoryTrack> _tracks = new ConditionalWeakTable<BaseAI, SensoryTrack>(); private static readonly PendingAllyCall[] _allyCallRing = new PendingAllyCall[32]; private static int _ringHead; private static int _ringTail; private static int _ringCount; private static readonly List<Character> _allyQueryTemp = new List<Character>(16); private static readonly FieldRef<BaseAI, Character> _aiCharacter = AccessTools.FieldRefAccess<BaseAI, Character>("m_character"); private static readonly FieldRef<int>? _viewBlockMask = ((AccessTools.Field(typeof(BaseAI), "m_viewBlockMask") != null) ? AccessTools.StaticFieldRefAccess<int>(AccessTools.Field(typeof(BaseAI), "m_viewBlockMask")) : null); private static int _fallbackViewBlockMask; private static int GetViewBlockMask() { if (_viewBlockMask != null) { int num = _viewBlockMask.Invoke(); if (num != 0) { return num; } } if (_fallbackViewBlockMask == 0) { _fallbackViewBlockMask = LayerMask.GetMask(new string[7] { "Default", "static_solid", "Default_small", "piece", "terrain", "viewblock", "vehicle" }); } return _fallbackViewBlockMask; } public static SensoryTrack GetOrCreateTrack(BaseAI ai) { if (!_tracks.TryGetValue(ai, out SensoryTrack value)) { value = new SensoryTrack(); _tracks.Add(ai, value); } return value; } public static bool ShouldUseSensoryEngine(BaseAI ai, out Character? observer, out AgentBehaviorProfile profile) { observer = _aiCharacter.Invoke(ai); if ((Object)(object)observer == (Object)null || !ModConfig.ModEnabled.Value || !ModConfig.EnableSensoryPerceptionEngine.Value) { profile = new AgentBehaviorProfile(); return false; } if (AgentProfileRegistry.IsPerceptionExempt(observer)) { profile = new AgentBehaviorProfile(); return false; } profile = AgentProfileRegistry.GetProfile(observer); return profile.UseSensoryEngine; } public static bool EvaluateVisualStimulus(BaseAI ai, Character observer, AgentBehaviorProfile profile, Character target) { //IL_004b: 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_0050: 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_0083: 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_0075: 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_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0128: 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_00d7: 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_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_01ec: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)target == (Object)null || target.IsDead()) { return false; } Player val = (Player)(object)((target is Player) ? target : null); if (val != null && (val.InDebugFlyMode() || ((Character)val).InGhostMode())) { return false; } Vector3 val2 = (((Object)(object)observer.m_eye != (Object)null) ? observer.m_eye.position : observer.GetCenterPoint()); Vector3 val3 = (target.IsCrouching() ? target.GetCenterPoint() : (((Object)(object)target.m_eye != (Object)null) ? target.m_eye.position : target.GetCenterPoint())); Vector3 val4 = val3 - val2; float magnitude = ((Vector3)(ref val4)).magnitude; float num = Mathf.Min(ai.m_viewRange, ModConfig.MaxVisualRange.Value); if (magnitude > num) { return false; } SensoryTrack orCreateTrack = GetOrCreateTrack(ai); if (orCreateTrack.Stage != DetectionStage.Engaged || !((Object)(object)orCreateTrack.Target == (Object)(object)target)) { float num2 = Vector3.Angle(val4, ((Component)observer).transform.forward); float num3 = (((int)orCreateTrack.Stage >= 1) ? Mathf.Min(135f, ModConfig.VisionConeHalfAngle.Value * 1.45f) : ModConfig.VisionConeHalfAngle.Value); if (num2 > num3) { return false; } } int viewBlockMask = GetViewBlockMask(); if (Physics.Raycast(val2, val4 / Mathf.Max(0.01f, magnitude), magnitude, viewBlockMask)) { return false; } if (!ai.m_mistVision && ParticleMist.IsMistBlocked(val2, val3)) { return false; } TargetCoverState orSample = EnvironmentCoverSampler.GetOrSample(target); float num4 = target.GetStealthFactor() * orSample.IlluminationFactor * (1f - orSample.FoliageConcealment); float num5 = num * Mathf.Clamp(num4, 0.15f, 1.3f); if (magnitude > num5) { return false; } float num6 = Mathf.Clamp01(1.15f - magnitude / Mathf.Max(1f, num5)); float num7 = ModConfig.AlertGainRate.Value * num6 * 0.25f; if (magnitude < 4f) { num7 *= 2.5f; } ApplyStimulus(ai, observer, profile, target, ((Component)target).transform.position, num7); return (int)orCreateTrack.Stage >= 3; } public static bool EvaluateAuditoryStimulus(BaseAI ai, Character observer, AgentBehaviorProfile profile, Character target) { //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) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)target == (Object)null || target.IsDead()) { return false; } Player val = (Player)(object)((target is Player) ? target : null); if (val != null && (val.InDebugFlyMode() || ((Character)val).InGhostMode())) { return false; } float num = Vector3.Distance(((Component)observer).transform.position, ((Component)target).transform.position); float num2 = Mathf.Min(ai.m_hearRange, ModConfig.MaxHearingRange.Value); if (Character.InInterior(((Component)observer).transform)) { num2 = Mathf.Min(12f, num2); } if (num > num2) { return false; } TargetCoverState orSample = EnvironmentCoverSampler.GetOrSample(target); if (num > orSample.AcousticRadius) { return false; } float num3 = Mathf.Clamp01(1f - num / Mathf.Max(1f, orSample.AcousticRadius)); float deltaDetection = ModConfig.SuspicionGainRate.Value * num3 * 0.2f; ApplyStimulus(ai, observer, profile, target, ((Component)target).transform.position, deltaDetection); return (int)GetOrCreateTrack(ai).Stage >= 3; } public static void NotifyDamaged(BaseAI ai, Character? attacker) { //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_007a: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)attacker == (Object)null)) { Character val = _aiCharacter.Invoke(ai); if (!((Object)(object)val == (Object)null)) { AgentBehaviorProfile profile = AgentProfileRegistry.GetProfile(val); SensoryTrack orCreateTrack = GetOrCreateTrack(ai); orCreateTrack.Target = attacker; orCreateTrack.DetectionLevel = 1f; orCreateTrack.Stage = DetectionStage.Engaged; orCreateTrack.LastKnownPos = ((Component)attacker).transform.position; orCreateTrack.LastStimulusTime = Time.time; orCreateTrack.SearchTimeRemaining = ModConfig.SearchDurationSeconds.Value; EnqueueAllyCall(val, attacker, ((Component)attacker).transform.position, profile.CallForHelpRadius); } } } public static void NotifySoundImpulse(BaseAI ai, Character? source, Vector3 soundPosition, float impulseAmount) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) Character val = _aiCharacter.Invoke(ai); if (!((Object)(object)val == (Object)null)) { AgentBehaviorProfile profile = AgentProfileRegistry.GetProfile(val); ApplyStimulus(ai, val, profile, source, soundPosition, impulseAmount); } } public static void TickAgentMemory(BaseAI ai, Character observer, AgentBehaviorProfile profile, float dt) { //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: 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) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: 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_0102: 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_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) ProcessOneQueuedAllyCall(); if (profile.UseSensoryEngine && ModConfig.EnableSensoryPerceptionEngine.Value && _tracks.TryGetValue(ai, out SensoryTrack value)) { if (Time.time - value.LastStimulusTime > 1.25f && value.DetectionLevel > 0f) { value.DetectionLevel = Mathf.Max(0f, value.DetectionLevel - ModConfig.DetectionDecayRate.Value * dt); UpdateStageFromLevel(ai, observer, profile, value); } if (value.SearchTimeRemaining > 0f) { value.SearchTimeRemaining = Mathf.Max(0f, value.SearchTimeRemaining - dt); } if (NavDebugOverlay.IsModeActive(DebugDrawMode.Senses) && value.DetectionLevel > 0.01f) { Color color = (Color)(value.Stage switch { DetectionStage.Engaged => Color.red, DetectionStage.Alerted => new Color(1f, 0.55f, 0f), DetectionStage.Suspicious => Color.yellow, _ => Color.white, }); NavDebugOverlay.AddLabel(observer.GetTopPoint() + Vector3.up * 0.45f, $"{value.Stage} ({value.DetectionLevel * 100f:F0}%)", color); } } } private static void ApplyStimulus(BaseAI ai, Character observer, AgentBehaviorProfile profile, Character? target, Vector3 stimulusPos, float deltaDetection) { //IL_0037: 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_0099: Unknown result type (might be due to invalid IL or missing references) SensoryTrack orCreateTrack = GetOrCreateTrack(ai); float time = Time.time; if (!(time - orCreateTrack.LastStimulusTime < 0.12f) || !(deltaDetection < 0.5f)) { if ((Object)(object)target != (Object)null) { orCreateTrack.Target = target; } orCreateTrack.LastKnownPos = stimulusPos; orCreateTrack.LastStimulusTime = time; orCreateTrack.SearchTimeRemaining = ModConfig.SearchDurationSeconds.Value; orCreateTrack.DetectionLevel = Mathf.Clamp01(orCreateTrack.DetectionLevel + deltaDetection); DetectionStage stage = orCreateTrack.Stage; UpdateStageFromLevel(ai, observer, profile, orCreateTrack); if ((int)stage < 3 && orCreateTrack.Stage == DetectionStage.Engaged && (Object)(object)orCreateTrack.Target != (Object)null) { EnqueueAllyCall(observer, orCreateTrack.Target, stimulusPos, profile.CallForHelpRadius); } } } private static void UpdateStageFromLevel(BaseAI ai, Character observer, AgentBehaviorProfile profile, SensoryTrack track) { if (track.DetectionLevel >= 0.85f) { track.Stage = DetectionStage.Engaged; } else if (track.DetectionLevel >= 0.5f) { track.Stage = DetectionStage.Alerted; } else if (track.DetectionLevel >= 0.2f) { track.Stage = DetectionStage.Suspicious; } else { track.Stage = DetectionStage.Unaware; } } private static void EnqueueAllyCall(Character caller, Character target, Vector3 pos, float radius) { //IL_003b: 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) if (!(radius <= 0.5f) && _ringCount < _allyCallRing.Length) { _allyCallRing[_ringTail] = new PendingAllyCall { Caller = caller, Target = target, KnownPos = pos, Radius = radius }; _ringTail = (_ringTail + 1) % _allyCallRing.Length; _ringCount++; } } private static void ProcessOneQueuedAllyCall() { //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) if (_ringCount <= 0) { return; } PendingAllyCall pendingAllyCall = _allyCallRing[_ringHead]; _ringHead = (_ringHead + 1) % _allyCallRing.Length; _ringCount--; if ((Object)(object)pendingAllyCall.Caller == (Object)null || pendingAllyCall.Caller.IsDead() || (Object)(object)pendingAllyCall.Target == (Object)null) { return; } _allyQueryTemp.Clear(); SpatialCharacterGrid.QueryRadius(((Component)pendingAllyCall.Caller).transform.position, pendingAllyCall.Radius, _allyQueryTemp, pendingAllyCall.Caller); for (int i = 0; i < _allyQueryTemp.Count; i++) { Character val = _allyQueryTemp[i]; if ((Object)(object)val == (Object)null || val.IsDead() || !BaseAI.IsEnemy(val, pendingAllyCall.Target) || BaseAI.IsEnemy(pendingAllyCall.Caller, val)) { continue; } BaseAI baseAI = val.GetBaseAI(); if (!((Object)(object)baseAI == (Object)null)) { SensoryTrack orCreateTrack = GetOrCreateTrack(baseAI); if ((int)orCreateTrack.Stage < 2) { orCreateTrack.Target = pendingAllyCall.Target; orCreateTrack.LastKnownPos = pendingAllyCall.KnownPos; orCreateTrack.LastStimulusTime = Time.time; orCreateTrack.SearchTimeRemaining = ModConfig.SearchDurationSeconds.Value; orCreateTrack.DetectionLevel = Mathf.Max(orCreateTrack.DetectionLevel, 0.65f); orCreateTrack.Stage = DetectionStage.Alerted; } } } } } public sealed class InvestigateBrainModule : IAIBrainModule { private static readonly MethodInfo _moveToMethod = AccessTools.Method(typeof(BaseAI), "MoveTo", (Type[])null, (Type[])null); private static readonly MethodInfo _lookAtMethod = AccessTools.Method(typeof(BaseAI), "LookAt", (Type[])null, (Type[])null); private static readonly MethodInfo _randomMovementMethod = AccessTools.Method(typeof(BaseAI), "RandomMovement", (Type[])null, (Type[])null); public string Id => "VikingAI.SensoryInvestigate"; public float EvaluateUtility(BaseAI ai, Character character, AgentBehaviorProfile profile) { if (!ModConfig.EnableSensoryPerceptionEngine.Value || !profile.UseSensoryEngine) { return 0f; } if (ai.IsAlerted()) { MonsterAI val = (MonsterAI)(object)((ai is MonsterAI) ? ai : null); if (val != null && (Object)(object)((BaseAI)val).GetTargetCreature() != (Object)null && SensoryMemoryController.GetOrCreateTrack(ai).Stage == DetectionStage.Engaged) { return 0f; } } SensoryTrack orCreateTrack = SensoryMemoryController.GetOrCreateTrack(ai); if ((orCreateTrack.Stage == DetectionStage.Suspicious || orCreateTrack.Stage == DetectionStage.Alerted) && orCreateTrack.SearchTimeRemaining > 0.1f) { return 55f; } return 0f; } public bool Tick(BaseAI ai, Character character, AgentBehaviorProfile profile, float dt) { //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_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_0074: 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_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) SensoryTrack orCreateTrack = SensoryMemoryController.GetOrCreateTrack(ai); if (orCreateTrack.Stage == DetectionStage.Suspicious) { ai.StopMoving(); _lookAtMethod?.Invoke(ai, new object[1] { orCreateTrack.LastKnownPos + Vector3.up * 1.2f }); return true; } if (orCreateTrack.Stage == DetectionStage.Alerted && _moveToMethod != null) { if (Utils.DistanceXZ(((Component)character).transform.position, orCreateTrack.LastKnownPos) > 2.2f) { _moveToMethod.Invoke(ai, new object[4] { dt, orCreateTrack.LastKnownPos, 1.5f, false }); } else { _randomMovementMethod?.Invoke(ai, new object[3] { dt, orCreateTrack.LastKnownPos, true }); } return true; } return false; } } } namespace VikingAI.Simulation { public interface IVirtualAgentTask { string Id { get; } NpcRoleFlags RequiredRole { get; } void TickUnloadedZdo(ZDO agentZdo, NpcRoleFlags roles, float dtSeconds); void ApplyCatchUpOnLoad(Character agent, AgentBehaviorProfile profile, double elapsedOfflineSeconds); } public sealed class PatrolVirtualTask : IVirtualAgentTask { private static readonly int _zdoPatrolCenter = StringExtensionMethods.GetStableHashCode("VAI_v1_PatrolPos"); private static readonly int _zdoPatrolPhase = StringExtensionMethods.GetStableHashCode("VAI_v1_PatrolPhase"); public string Id => "VikingAI.VirtualPatrol"; public NpcRoleFlags RequiredRole => NpcRoleFlags.Guard; public void TickUnloadedZdo(ZDO agentZdo, NpcRoleFlags roles, float dtSeconds) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //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_0064: 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_0072: 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) if (agentZdo.IsValid() && agentZdo.IsOwner()) { Vector3 vec = agentZdo.GetVec3(_zdoPatrolCenter, agentZdo.GetPosition()); float num = agentZdo.GetFloat(_zdoPatrolPhase, 0f) + dtSeconds * 0.25f; agentZdo.Set(_zdoPatrolPhase, num); float num2 = Mathf.Sin(num) * 6f; float num3 = Mathf.Cos(num) * 6f; Vector3 position = default(Vector3); ((Vector3)(ref position))..ctor(vec.x + num2, vec.y, vec.z + num3); agentZdo.SetPosition(position); } } public void ApplyCatchUpOnLoad(Character agent, AgentBehaviorProfile profile, double elapsedOfflineSeconds) { if (elapsedOfflineSeconds > 30.0 && !agent.IsDead() && agent.GetHealthPercentage() < 1f) { agent.Heal(agent.GetMaxHealth() * 0.25f, true); } } } [HarmonyPatch] public static class VirtualAgentDirector { public static readonly int ZdoKeyLastSimTicks = StringExtensionMethods.GetStableHashCode("VAI_v1_LastTicks"); public static readonly int ZdoKeyPatrolAnchor = StringExtensionMethods.GetStableHashCode("VAI_v1_PatrolPos"); private static readonly List<IVirtualAgentTask> _tasks = new List<IVirtualAgentTask> { new PatrolVirtualTask() }; private static readonly HashSet<ZDO> _trackedNpcZdos = new HashSet<ZDO>(); private static readonly List<Character> _portalFollowersTemp = new List<Character>(8); private static float _virtualTickTimer; private static readonly FieldRef<ZDOMan, Dictionary<ZDOID, ZDO>> _zdoObjectsById = AccessTools.FieldRefAccess<ZDOMan, Dictionary<ZDOID, ZDO>>("m_objectsByID"); public static event Action<ZDO>? OnAgentRestored; public static void RegisterTask(IVirtualAgentTask task) { if (task != null) { _tasks.RemoveAll((IVirtualAgentTask t) => t.Id == task.Id); _tasks.Add(task); } } public static ZDO? SpawnVirtualAgentZdo(string prefabName, Vector3 position, Quaternion rotation, NpcRoleFlags roles, bool isCustomNpc = true) { //IL_001d: 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_005f: Unknown result type (might be due to invalid IL or missing references) if (ZDOMan.instance == null || string.IsNullOrEmpty(prefabName)) { return null; } int stableHashCode = StringExtensionMethods.GetStableHashCode(prefabName); ZDO val = ZDOMan.instance.CreateNewZDO(position, stableHashCode); if (val == null) { return null; } val.SetPrefab(stableHashCode); val.SetRotation(rotation); val.Persistent = true; val.Set(AgentProfileRegistry.ZdoKeyCustomNpc, isCustomNpc); val.Set(AgentProfileRegistry.ZdoKeyRoleFlags, (int)roles, false); val.Set(ZdoKeyPatrolAnchor, position); if ((Object)(object)ZNet.instance != (Object)null) { val.Set(ZdoKeyLastSimTicks, ZNet.instance.GetTime().Ticks); } if (isCustomNpc) { int seed = (int)(((ZDOID)(ref val.m_uid)).ID ^ ((ZDOID)(ref val.m_uid)).UserID) ^ Environment.TickCount; HumanoidPrefabBuilder.ApplyDeterministicAppearanceToZdo(val, seed); } _trackedNpcZdos.Add(val); return val; } public static void TrackZdoDirectly(ZDO zdo) { if (zdo != null && zdo.IsValid()) { _trackedNpcZdos.Add(zdo); } } public static int RestoreTrackedAgents() { _trackedNpcZdos.Clear(); if (ZDOMan.instance == null) { return 0; } int num = 0; foreach (ZDO value in _zdoObjectsById.Invoke(ZDOMan.instance).Values) { if (value != null && value.GetInt(AgentProfileRegistry.ZdoKeyRoleFlags, 0) != 0) { _trackedNpcZdos.Add(value); num++; try { VirtualAgentDirector.OnAgentRestored?.Invoke(value); } catch (Exception arg) { VikingAIPlugin.Log.LogError((object)$"[VirtualAgentDirector] OnAgentRestored handler failed: {arg}"); } } } VikingAIPlugin.Log.LogInfo((object)$"[VirtualAgentDirector] Restored {num} persisted agent ZDO(s) after world load."); return num; } [HarmonyPatch(typeof(ZNet), "ServerLoadWorld")] [HarmonyPostfix] private static void ZNet_ServerLoadWorld_Postfix() { if (ModConfig.ModEnabled.Value) { RestoreTrackedAgents(); } } public static bool MoveZdoAlongTerrain(ZDO zdo, Vector3 targetPos, float speedMetersPerSec, float dtSeconds, float arrivalRadius = 3f) { //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_001d: 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_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) //IL_0046: 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_0053: 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_005b: 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_009a: 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_006e: 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_00b5: 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_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) if (zdo == null || !zdo.IsValid() || !zdo.IsOwner()) { return false; } Vector3 position = zdo.GetPosition(); Vector3 val = targetPos - position; val.y = 0f; float magnitude = ((Vector3)(ref val)).magnitude; if (magnitude <= arrivalRadius) { return true; } Vector3 val2 = val / magnitude; float num = Mathf.Min(magnitude, speedMetersPerSec * dtSeconds); Vector3 val3 = position + val2 * num; if (WorldGenerator.instance != null) { float height = WorldGenerator.instance.GetHeight(val3.x, val3.z); val3.y = Mathf.Max(30f, height); } else { val3.y = Mathf.Lerp(position.y, targetPos.y, num / magnitude); } zdo.SetPosition(val3); if (((Vector3)(ref val2)).sqrMagnitude > 0.01f) { zdo.SetRotation(Quaternion.LookRotation(val2, Vector3.up)); } return magnitude - num <= arrivalRadius; } public static void TrackNpcZdo(Character npc, AgentBehaviorProfile profile) { //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_006a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)npc == (Object)null) { return; } ZNetView nView = AgentProfileRegistry.GetNView(npc); if ((Object)(object)nView == (Object)null || !nView.IsValid()) { return; } ZDO zDO = nView.GetZDO(); if (zDO != null) { _trackedNpcZdos.Add(zDO); if (nView.IsOwner() && zDO.GetVec3(ZdoKeyPatrolAnchor, Vector3.zero) == Vector3.zero) { zDO.Set(ZdoKeyPatrolAnchor, ((Component)npc).transform.position); } } } public static void UpdateDirector(float dt) { if (!ModConfig.ModEnabled.Value || !ModConfig.EnableUnloadedZoneSimulation.Value) { return; } float num = Mathf.Max(0.25f, ModConfig.VirtualTickIntervalSeconds.Value); _virtualTickTimer += dt; if (_virtualTickTimer < num) { return; } float virtualTickTimer = _virtualTickTimer; _virtualTickTimer = 0f; if ((Object)(object)ZNetScene.instance == (Object)null || (Object)(object)ZNet.instance == (Object)null) { return; } long ticks = ZNet.instance.GetTime().Ticks; bool flag = false; foreach (ZDO trackedNpcZdo in _trackedNpcZdos) { if (trackedNpcZdo == null || !trackedNpcZdo.IsValid()) { flag = true; continue; } if ((Object)(object)ZNetScene.instance.FindInstance(trackedNpcZdo) != (Object)null) { if (trackedNpcZdo.IsOwner()) { trackedNpcZdo.Set(ZdoKeyLastSimTicks, ticks); } continue; } NpcRoleFlags npcRoleFlags = (NpcRoleFlags)trackedNpcZdo.GetInt(AgentProfileRegistry.ZdoKeyRoleFlags, 0); if (npcRoleFlags == NpcRoleFlags.None) { continue; } for (int i = 0; i < _tasks.Count; i++) { IVirtualAgentTask virtualAgentTask = _tasks[i]; if ((npcRoleFlags & virtualAgentTask.RequiredRole) != NpcRoleFlags.None) { virtualAgentTask.TickUnloadedZdo(trackedNpcZdo, npcRoleFlags, virtualTickTimer); } } if (trackedNpcZdo.IsOwner()) { trackedNpcZdo.Set(ZdoKeyLastSimTicks, ticks); } } if (flag) { _trackedNpcZdos.RemoveWhere((ZDO z) => z == null || !z.IsValid()); } } [HarmonyPatch(typeof(Character), "Start")] [HarmonyPostfix] private static void Character_Start_Postfix(Character __instance) { if (!ModConfig.ModEnabled.Value || (Object)(object)__instance == (Object)null || __instance.IsPlayer()) { return; } AgentBehaviorProfile profile = AgentProfileRegistry.GetProfile(__instance); if (!profile.IsCustomNpc && profile.Roles == NpcRoleFlags.None) { return; } TrackNpcZdo(__instance, profile); if (!ModConfig.EnableUnloadedZoneSimulation.Value || (Object)(object)ZNet.instance == (Object)null) { return; } ZNetView nView = AgentProfileRegistry.GetNView(__instance); if ((Object)(object)nView == (Object)null || !nView.IsValid()) { return; } ZDO zDO = nView.GetZDO(); long num = zDO.GetLong(ZdoKeyLastSimTicks, 0L); long ticks = ZNet.instance.GetTime().Ticks; if (num > 0 && ticks > num) { double totalSeconds = TimeSpan.FromTicks(ticks - num).TotalSeconds; if (totalSeconds >= 2.0) { for (int i = 0; i < _tasks.Count; i++) { IVirtualAgentTask virtualAgentTask = _tasks[i]; if ((profile.Roles & virtualAgentTask.RequiredRole) != NpcRoleFlags.None) { virtualAgentTask.ApplyCatchUpOnLoad(__instance, profile, totalSeconds); } } } } if (nView.IsOwner()) { zDO.Set(ZdoKeyLastSimTicks, ticks); } } [HarmonyPatch(typeof(Player), "TeleportTo")] [HarmonyPostfix] private static void Player_TeleportTo_Postfix(Player __instance, Vector3 pos, Quaternion rot, bool __result) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0128: 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_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_014b: 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) if (!__result || !ModConfig.ModEnabled.Value || !ModConfig.EnableFollowerPortalTransit.Value || (Object)(object)__instance == (Object)null) { return; } _portalFollowersTemp.Clear(); SpatialCharacterGrid.QueryRadius(((Component)__instance).transform.position, 20f, _portalFollowersTemp, (Character?)(object)__instance); int num = 0; Vector3 val3 = default(Vector3); for (int i = 0; i < _portalFollowersTemp.Count; i++) { Character val = _portalFollowersTemp[i]; if ((Object)(object)val == (Object)null || val.IsDead() || val.IsPlayer()) { continue; } BaseAI baseAI = val.GetBaseAI(); MonsterAI val2 = (MonsterAI)(object)((baseAI is MonsterAI) ? baseAI : null); if (val2 == null || (Object)(object)val2.GetFollowTarget() != (Object)(object)((Component)__instance).gameObject || !AgentProfileRegistry.GetProfile(val).CanTraversePortals) { continue; } ZNetView nView = AgentProfileRegistry.GetNView(val); if (!((Object)(object)nView == (Object)null) && nView.IsValid()) { if (!nView.IsOwner()) { nView.ClaimOwnership(); } float num2 = (150f + (float)num * 30f) * (MathF.PI / 180f); ((Vector3)(ref val3))..ctor(Mathf.Sin(num2) * 1.8f, 0.25f, Mathf.Cos(num2) * 1.8f); Vector3 position = pos + rot * val3; nView.GetZDO().SetPosition(position); ((Component)val).transform.position = position; ((Component)val).transform.rotation = rot; num++; } } } } } namespace VikingAI.Profiles { [Flags] public enum NpcRoleFlags : uint { None = 0u, Companion = 1u, Guard = 2u, SmelterTender = 4u, Lumberjack = 8u, Farmer = 0x10u, Builder = 0x20u, Hauler = 0x40u, AllSettlement = 0x7Eu } public sealed class AgentBehaviorProfile { public string PrefabName { get; set; } = ""; public bool IsCustomNpc { get; set; } public NpcRoleFlags Roles { get; set; } public bool CanOpenDoors { get; set; } public bool AutoCloseDoors { get; set; } public float MaxJumpUpHeight { get; set; } public float MaxDropDownHeight { get; set; } public bool AllowSiegeBreachPathing { get; set; } public float StructuralDpsEstimate { get; set; } = 25f; public bool StrafeInCombat { get; set; } public bool YieldToPlayers { get; set; } public bool UseFormationFollowing { get; set; } public bool CanTraversePortals { get; set; } public bool UsePackAttackTokens { get; set; } public float AttackTokenWeight { get; set; } = 1f; public bool UseSensoryEngine { get; set; } public float CallForHelpRadius { get; set; } = 20f; public AgentBehaviorProfile Clone() { return (AgentBehaviorProfile)MemberwiseClone(); } public static AgentBehaviorProfile CreateCompanionDefault(string prefabName = "") { return new AgentBehaviorProfile { PrefabName = prefabName, IsCustomNpc = true, Roles = (NpcRoleFlags.Companion | NpcRoleFlags.Guard), CanOpenDoors = true, AutoCloseDoors = true, MaxJumpUpHeight = 1.5f, MaxDropDownHeight = 3f, AllowSiegeBreachPathing = false, StrafeInCombat = true, YieldToPlayers = true, UseFormationFollowing = true, CanTraversePortals = true, UsePackAttackTokens = true, AttackTokenWeight = 1f, UseSensoryEngine = true, CallForHelpRadius = 25f }; } public static AgentBehaviorProfile CreateVillagerDefault(string prefabName = "", NpcRoleFlags roles = NpcRoleFlags.AllSettlement) { return new AgentBehaviorProfile { PrefabName = prefabName, IsCustomNpc = true, Roles = roles, CanOpenDoors = true, AutoCloseDoors = true, MaxJumpUpHeight = 1.2f, MaxDropDownHeight = 2.5f, AllowSiegeBreachPathing = false, StrafeInCombat = true, YieldToPlayers = true, UseFormationFollowing = true, CanTraversePortals = false, UsePackAttackTokens = true, AttackTokenWeight = 1f, UseSensoryEngine = true, CallForHelpRadius = 30f }; } } public static class AgentProfileRegistry { public static readonly int ZdoKeyRoleFlags = StringExtensionMethods.GetStableHashCode("VAI_v1_Roles"); public static readonly int ZdoKeyCustomNpc = StringExtensionMethods.GetStableHashCode("VAI_v1_IsNpc"); public static readonly int ZdoKeyPerceptionExempt = StringExtensionMethods.GetStableHashCode("VAI_PerceptionExempt"); public static readonly int ZdoKeySoMExempt = StringExtensionMethods.GetStableHashCode("SoMStealthExempt"); private static readonly FieldRef<Character, ZNetView> _charNView = AccessTools.FieldRefAccess<Character, ZNetView>("m_nview"); private static readonly Dictionary<string, AgentBehaviorProfile> _prefabProfiles = new Dictionary<string, AgentBehaviorProfile>(StringComparer.OrdinalIgnoreCase); private static readonly ConditionalWeakTable<Character, AgentBehaviorProfile> _instanceProfiles = new ConditionalWeakTable<Character, AgentBehaviorProfile>(); public static ZNetView? GetNView(Character? character) { if (!((Object)(object)character != (Object)null)) { return null; } return _charNView.Invoke(character); } public static void RegisterPrefabProfile(string prefabName, AgentBehaviorProfile profile) { if (!string.IsNullOrEmpty(prefabName) && profile != null) { profile.PrefabName = prefabName; _prefabProfiles[CleanName(prefabName)] = profile; } } public static void SetInstanceProfile(Character character, AgentBehaviorProfile profile, bool persistRoleToZdo = false) { if (!((Object)(object)character == (Object)null) && profile != null) { _instanceProfiles.Remove(character); _instanceProfiles.Add(character, profile); ZNetView nView = GetNView(character); if (persistRoleToZdo && (Object)(object)nView != (Object)null && nView.IsValid() && nView.IsOwner()) { ZDO zDO = nView.GetZDO(); zDO.Set(ZdoKeyCustomNpc, profile.IsCustomNpc); zDO.Set(ZdoKeyRoleFlags, (int)profile.Roles, false); } } } public static AgentBehaviorProfile GetProfile(Character character) { if ((Object)(object)character == (Object)null) { return new AgentBehaviorProfile(); } if (_instanceProfiles.TryGetValue(character, out AgentBehaviorProfile value)) { SyncDynamicTamedFlags(character, value); return value; } string text = CleanName(((Object)((Component)character).gameObject).name); AgentBehaviorProfile value2; AgentBehaviorProfile agentBehaviorProfile = ((!_prefabProfiles.TryGetValue(text, out value2)) ? BuildDynamicDefaultProfile(character, text) : value2.Clone()); ZNetView nView = GetNView(character); if ((Object)(object)nView != (Object)null && nView.IsValid()) { ZDO zDO = nView.GetZDO(); if (zDO != null && zDO.GetBool(ZdoKeyCustomNpc, false)) { int roles = zDO.GetInt(ZdoKeyRoleFlags, 0); agentBehaviorProfile = AgentBehaviorProfile.CreateVillagerDefault(text, (NpcRoleFlags)roles); if ((agentBehaviorProfile.Roles & NpcRoleFlags.Companion) != NpcRoleFlags.None) { agentBehaviorProfile.CanTraversePortals = true; } } } SyncDynamicTamedFlags(character, agentBehaviorProfile); _instanceProfiles.Add(character, agentBehaviorProfile); return agentBehaviorProfile; } public static bool IsPerceptionExempt(Character character) { ZNetView nView = GetNView(character); if ((Object)(object)nView == (Object)null || !nView.IsValid()) { return false; } ZDO zDO = nView.GetZDO(); if (zDO == null) { return false; } if (zDO.GetInt(ZdoKeyPerceptionExempt, 0) == 0) { return zDO.GetInt(ZdoKeySoMExempt, 0) != 0; } return true; } private static AgentBehaviorProfile BuildDynamicDefaultProfile(Character character, string prefabName) { //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: Invalid comparison between Unknown and I4 //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Invalid comparison between Unknown and I4 //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Invalid comparison between Unknown and I4 //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Invalid comparison between Unknown and I4 bool flag = character is Humanoid; BaseAI baseAI = character.GetBaseAI(); AgentType val = (AgentType)((!((Object)(object)baseAI != (Object)null)) ? 1 : ((int)baseAI.m_pathAgentType)); float attackTokenWeight = (((int)val == 2 || (int)val == 12 || (int)val == 3 || (int)val == 10) ? 1.5f : 1f); return new AgentBehaviorProfile { PrefabName = prefabName, IsCustomNpc = false, Roles = NpcRoleFlags.None, CanOpenDoors = false, AutoCloseDoors = false, MaxJumpUpHeight = (ModConfig.VanillaEnemiesJumpLedges.Value ? 1.4f : 0f), MaxDropDownHeight = (ModConfig.VanillaEnemiesJumpLedges.Value ? 2.5f : 0f), AllowSiegeBreachPathing = ModConfig.VanillaEnemiesBreachWeakWalls.Value, StrafeInCombat = (flag && ModConfig.VanillaHumanoidsStrafeInCombat.Value), YieldToPlayers = character.IsTamed(), UseFormationFollowing = character.IsTamed(), CanTraversePortals = false, UsePackAttackTokens = ModConfig.VanillaEnemiesUsePackTokens.Value, AttackTokenWeight = attackTokenWeight, UseSensoryEngine = ModConfig.VanillaEnemiesUseSensoryEngine.Value, CallForHelpRadius = 20f }; } private static void SyncDynamicTamedFlags(Character character, AgentBehaviorProfile profile) { if (character.IsTamed()) { profile.YieldToPlayers = ModConfig.EnablePlayerYieldOnApproach.Value; profile.UseFormationFollowing = ModConfig.EnableFollowerFormations.Value; } else if (!profile.IsCustomNpc) { profile.UsePackAttackTokens = ModConfig.VanillaEnemiesUsePackTokens.Value; profile.StrafeInCombat = character is Humanoid && ModConfig.VanillaHumanoidsStrafeInCombat.Value; profile.MaxJumpUpHeight = (ModConfig.VanillaEnemiesJumpLedges.Value ? 1.4f : 0f); profile.AllowSiegeBreachPathing = ModConfig.VanillaEnemiesBreachWeakWalls.Value; profile.UseSensoryEngine = ModConfig.VanillaEnemiesUseSensoryEngine.Value; } } private static string CleanName(string name) { int num = name.IndexOf('('); if (num <= 0) { return name.Trim(); } return name.Substring(0, num).Trim(); } } } namespace VikingAI.Patches { [HarmonyPatch] public static class LocomotionPatches { private static readonly FieldRef<BaseAI, Character> _aiCharacter = AccessTools.FieldRefAccess<BaseAI, Character>("m_character"); private static readonly FieldRef<BaseAI, List<Vector3>> _aiPath = AccessTools.FieldRefAccess<BaseAI, List<Vector3>>("m_path"); private static readonly FieldRef<BaseAI, float> _aiJumpTimer = AccessTools.FieldRefAccess<BaseAI, float>("m_jumpTimer"); private static readonly MethodInfo _moveToMethod = AccessTools.Method(typeof(BaseAI), "MoveTo", (Type[])null, (Type[])null); public static Vector3? ActiveLookDirOverride { get; set; } [HarmonyPatch(typeof(BaseAI), "MoveTowards")] [HarmonyPrefix] private static bool BaseAI_MoveTowards_Prefix(BaseAI __instance, ref Vector3 dir, bool run, bool __runOriginal) { //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_0053: 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_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_0158: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_0104: 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) //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_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_00ee: Unknown result type (might be due to invalid IL or missing references) if (!__runOriginal) { return false; } if (!ModConfig.ModEnabled.Value) { return true; } Character val = _aiCharacter.Invoke(__instance); if ((Object)(object)val == (Object)null || val.IsFlying() || __instance.m_serpentMovement) { return true; } AgentBehaviorProfile profile = AgentProfileRegistry.GetProfile(val); Vector3 val2 = ((Vector3)(ref dir)).normalized; if (profile.CanOpenDoors) { DoorTraversalController.CheckAndActuateDoors(val, profile, val2); } if (ModConfig.EnableContextSteering.Value) { val2 = SteeringPipeline.Evaluate(val, profile, val2); } Vector3? val3 = ActiveLookDirOverride; if (!val3.HasValue && profile.StrafeInCombat) { MonsterAI val4 = (MonsterAI)(object)((__instance is MonsterAI) ? __instance : null); if (val4 != null) { Character targetCreature = ((BaseAI)val4).GetTargetCreature(); if ((Object)(object)targetCreature != (Object)null) { Vector3 val5 = ((Component)targetCreature).transform.position - ((Component)val).transform.position; val5.y = 0f; if (((Vector3)(ref val5)).sqrMagnitude > 0.04f && ((Vector3)(ref val5)).sqrMagnitude <= 144f) { val3 = ((Vector3)(ref val5)).normalized; } } } } if (val3.HasValue) { __instance.LookTowards(val3.Value); val.SetMoveDir(val2); val.SetRun(run); if (__instance.m_jumpInterval > 0f && _aiJumpTimer.Invoke(__instance) >= __instance.m_jumpInterval) { _aiJumpTimer.Invoke(__instance) = 0f; val.Jump(false); } return false; } dir = val2; return true; } [HarmonyPatch(typeof(BaseAI), "MoveTo")] [HarmonyPostfix] private static void BaseAI_MoveTo_Postfix(BaseAI __instance) { //IL_005c: 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_006d: 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_007c: Unknown result type (might be due to invalid IL or missing references) if (!ModConfig.ModEnabled.Value) { return; } Character val = _aiCharacter.Invoke(__instance); if ((Object)(object)val == (Object)null || val.IsFlying()) { return; } AgentBehaviorProfile profile = AgentProfileRegistry.GetProfile(val); if (profile.MaxJumpUpHeight <= 0.01f) { return; } List<Vector3> list = _aiPath.Invoke(__instance); if (list != null && list.Count != 0) { Vector3 val2 = list[0]; Vector3 position = ((Component)val).transform.position; float num = val2.y - position.y; float num2 = Utils.DistanceXZ(val2, position); if (num > 0.55f && num <= profile.MaxJumpUpHeight && num2 < 1.9f && val.IsOnGround()) { val.Jump(false); } } } [HarmonyPatch(typeof(BaseAI), "Follow")] [HarmonyPrefix] private static bool BaseAI_Follow_Prefix(BaseAI __instance, GameObject go, float dt, bool __runOriginal) { //IL_0047: 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_0082: 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_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) if (!__runOriginal) { return false; } if (!ModConfig.ModEnabled.Value || (Object)(object)go == (Object)null) { return true; } Character val = _aiCharacter.Invoke(__instance); if ((Object)(object)val == (Object)null) { return true; } AgentBehaviorProfile profile = AgentProfileRegistry.GetProfile(val); if (SteeringPipeline.TryGetPlayerYieldStep(val, profile, out var yieldDir)) { __instance.MoveTowards(yieldDir, false); return false; } if (ModConfig.EnableFollowerFormations.Value && profile.UseFormationFollowing && _moveToMethod != null) { Vector3 val2 = SteeringPipeline.ComputeFollowerSlotPosition(val, go); float num = Utils.DistanceXZ(val2, ((Component)val).transform.position); bool flag = Vector3.Distance(go.transform.position, ((Component)val).transform.position) > 9.5f || num > 7.5f; if (num < 1.15f) { __instance.StopMoving(); } else { _moveToMethod.Invoke(__instance, new object[4] { dt, val2, 0.5f, flag }); } return false; } return true; } } [HarmonyPatch] public static class PathfindingPatches { private static readonly FieldRef<BaseAI, Character> _aiCharacter = AccessTools.FieldRefAccess<BaseAI, Character>("m_character"); private static readonly FieldRef<Pathfinding, NavMeshPath> _pfPath = AccessTools.FieldRefAccess<Pathfinding, NavMeshPath>("m_path"); private static readonly FieldRef<Pathfinding, AsyncOperation> _pfBuildOp = AccessTools.FieldRefAccess<Pathfinding, AsyncOperation>("m_buildOperation"); private static readonly MethodInfo _buildTilesMethod = AccessTools.Method(typeof(Pathfinding), "Buildtiles", (Type[])null, (Type[])null); [HarmonyPatch(typeof(Pathfinding), "Awake")] [HarmonyPostfix] private static void Pathfinding_Awake_Postfix(Pathfinding __instance) { if (ModConfig.ModEnabled.Value && ModConfig.EnableTileSeamCostFix.Value) { __instance.m_linkCost = ModConfig.TileSeamCostModifier.Value; } } [HarmonyPatch(typeof(Pathfinding), "ConnectAlongEdge")] [HarmonyPrefix] private static void Pathfinding_ConnectAlongEdge_Prefix(Pathfinding __instance) { if (ModConfig.ModEnabled.Value) { __instance.m_linkCost = (ModConfig.EnableTileSeamCostFix.Value ? ModConfig.TileSeamCostModifier.Value : 10f); } } [HarmonyPatch(typeof(Pathfinding), "UpdatePathfinding")] [HarmonyPostfix] private static void Pathfinding_UpdatePathfinding_Postfix(Pathfinding __instance) { if (!ModConfig.ModEnabled.Value || _buildTilesMethod == null) { return; } int num = ModConfig.MaxAsyncTileBuildsPerTick.Value - 1; for (int i = 0; i < num; i++) { AsyncOperation val = _pfBuildOp.Invoke(__instance); if (val == null || val.isDone) { _buildTilesMethod.Invoke(__instance, null); continue; } break; } } [HarmonyPatch(typeof(BaseAI), "FindPath")] [HarmonyPrefix] private static void BaseAI_FindPath_Prefix(BaseAI __instance) { NavGraphManager.CurrentPathingCharacter = _aiCharacter.Invoke(__instance); } [HarmonyPatch(typeof(BaseAI), "FindPath")] [HarmonyFinalizer] private static void BaseAI_FindPath_Finalizer() { NavGraphManager.CurrentPathingCharacter = null; } [HarmonyPatch(typeof(BaseAI), "HavePath")] [HarmonyPrefix] private static void BaseAI_HavePath_Prefix(BaseAI __instance) { NavGraphManager.CurrentPathingCharacter = _aiCharacter.Invoke(__instance); } [HarmonyPatch(typeof(BaseAI), "HavePath")] [HarmonyFinalizer] private static void BaseAI_HavePath_Finalizer() { NavGraphManager.CurrentPathingCharacter = null; } [HarmonyPatch(typeof(Pathfinding), "GetPath")] [HarmonyPostfix] private static void Pathfinding_GetPath_Postfix(Pathfinding __instance, Vector3 from, Vector3 to, List<Vector3>? path, AgentType agentType, ref bool __result) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Invalid comparison between Unknown and I4 //IL_003f: 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_0041: Unknown result type (might be due to invalid IL or missing references) if (ModConfig.ModEnabled.Value && ModConfig.EnableUnifiedNavGraph.Value) { NavMeshPath val = _pfPath.Invoke(__instance); if ((!__result || (val != null && (int)val.status > 0)) && NavGraphManager.TrySolvePath(from, to, agentType, path)) { __result = true; } } } [HarmonyPatch(typeof(Piece), "SetCreator")] [HarmonyPostfix] private static void Piece_SetCreator_Postfix(Piece __instance) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance != (Object)null) { NavGraphManager.InvalidatePosition(((Component)__instance).transform.position); } } [HarmonyPatch(typeof(WearNTear), "OnDestroy")] [HarmonyPostfix] private static void WearNTear_OnDestroy_Postfix(WearNTear __instance) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance != (Object)null) { NavGraphManager.InvalidatePosition(((Component)__instance).transform.position); } } } [HarmonyPatch] public static class TacticsPatches { private static readonly FieldRef<BaseAI, Character> _aiCharacter = AccessTools.FieldRefAccess<BaseAI, Character>("m_character"); private static readonly FieldRef<BaseAI, ZNetView> _aiNView = AccessTools.FieldRefAccess<BaseAI, ZNetView>("m_nview"); private static readonly MethodInfo _updateSleepMethod = AccessTools.Method(typeof(MonsterAI), "UpdateSleep", (Type[])null, (Type[])null); private static readonly MethodInfo _updateTargetMethod = AccessTools.Method(typeof(MonsterAI), "UpdateTarget", (Type[])null, (Type[])null); [HarmonyPatch(typeof(BaseAI), "CanSeeTarget", new Type[] { typeof(Character) })] [HarmonyPrefix] private static bool BaseAI_CanSeeTarget_Prefix(BaseAI __instance, Character target, ref bool __result, bool __runOriginal) { if (!__runOriginal) { return false; } if (!SensoryMemoryController.ShouldUseSensoryEngine(__instance, out Character observer, out AgentBehaviorProfile profile) || (Object)(object)observer == (Object)null) { return true; } __result = SensoryMemoryController.EvaluateVisualStimulus(__instance, observer, profile, target); return false; } [HarmonyPatch(typeof(BaseAI), "CanHearTarget", new Type[] { typeof(Character) })] [HarmonyPrefix] private static bool BaseAI_CanHearTarget_Prefix(BaseAI __instance, Character target, ref bool __result, bool __runOriginal) { if (!__runOriginal) { return false; } if (!SensoryMemoryController.ShouldUseSensoryEngine(__instance, out Character observer, out AgentBehaviorProfile profile) || (Object)(object)observer == (Object)null) { return true; } __result = SensoryMemoryController.EvaluateAuditoryStimulus(__instance, observer, profile, target); return false; } [HarmonyPatch(typeof(BaseAI), "CanSenseTarget", new Type[] { typeof(Character), typeof(bool) })] [HarmonyPrefix] private static bool BaseAI_CanSenseTarget_Prefix(BaseAI __instance, Character target, bool passiveAggresive, ref bool __result, bool __runOriginal) { if (!__runOriginal) { return false; } if (!SensoryMemoryController.ShouldUseSensoryEngine(__instance, out Character observer, out AgentBehaviorProfile profile) || (Object)(object)observer == (Object)null) { return true; } if (!passiveAggresive && (Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.GetGlobalKey((GlobalKeys)30) && (!observer.IsTamed() || !target.GetBaseAI().IsAlerted())) { __result = false; return false; } bool flag = SensoryMemoryController.EvaluateAuditoryStimulus(__instance, observer, profile, target); bool flag2 = SensoryMemoryController.EvaluateVisualStimulus(__instance, observer, profile, target); __result = flag || flag2; return false; } [HarmonyPatch(typeof(MonsterAI), "OnDamaged")] [HarmonyPostfix] private static void MonsterAI_OnDamaged_Postfix(MonsterAI __instance, Character attacker) { if (ModConfig.ModEnabled.Value) { SensoryMemoryController.NotifyDamaged((BaseAI)(object)__instance, attacker); } } [HarmonyPatch(typeof(MonsterAI), "RPC_OnNearProjectileHit")] [HarmonyPrefix] private static bool MonsterAI_RPC_OnNearProjectileHit_Prefix(MonsterAI __instance, Vector3 center, ZDOID attackerID, bool __runOriginal) { //IL_0089: 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 (!__runOriginal) { return false; } if (!SensoryMemoryController.ShouldUseSensoryEngine((BaseAI)(object)__instance, out Character observer, out AgentBehaviorProfile _) || (Object)(object)observer == (Object)null) { return true; } ZNetView val = _aiNView.Invoke((BaseAI)(object)__instance); if ((Object)(object)val == (Object)null || !val.IsOwner()) { return false; } if ((Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.GetGlobalKey((GlobalKeys)30)) { return false; } Character source = null; if ((Object)(object)ZNetScene.instance != (Object)null) { GameObject val2 = ZNetScene.instance.FindInstance(attackerID); if ((Object)(object)val2 != (Object)null) { source = val2.GetComponent<Character>(); } } SensoryMemoryController.NotifySoundImpulse((BaseAI)(object)__instance, source, center, 0.55f); return false; } [HarmonyPatch(typeof(MonsterAI), "UpdateAI")] [HarmonyPrefix] private static bool MonsterAI_UpdateAI_Prefix(MonsterAI __instance, float dt, ref bool __result, bool __runOriginal) { if (!__runOriginal) { return false; } if (!ModConfig.ModEnabled.Value) { return true; } ZNetView val = _aiNView.Invoke((BaseAI)(object)__instance); if ((Object)(object)val == (Object)null || !val.IsValid() || !val.IsOwner()) { return true; } DoorTraversalController.UpdatePendingAutoCloses(); Character val2 = _aiCharacter.Invoke((BaseAI)(object)__instance); if ((Object)(object)val2 == (Object)null || val2.IsDead()) { return true; } AgentBehaviorProfile profile = AgentProfileRegistry.GetProfile(val2); SensoryMemoryController.TickAgentMemory((BaseAI)(object)__instance, val2, profile, dt); if (((BaseAI)__instance).IsSleeping()) { return true; } if (BrainPipeline.TryExecuteModules((BaseAI)(object)__instance, val2, dt)) { if (_updateTargetMethod != null) { object[] parameters = new object[4] { (val2 is Humanoid) ? val2 : null, dt, false, false }; _updateTargetMethod.Invoke(__instance, parameters); } __result = true; return false; } return true; } } } namespace VikingAI.NPC.Utility { public sealed class SmartAffordanceBrainModule : IAIBrainModule { private sealed class AgentWorkState { public AffordanceCandidate CurrentCandidate; public bool HasActiveTask; public float WorkProgressSeconds; public float NextScanTime; } private static readonly ConditionalWeakTable<Character, AgentWorkState> _workStates = new ConditionalWeakTable<Character, AgentWorkState>(); private static readonly MethodInfo _moveToMethod = AccessTools.Method(typeof(BaseAI), "MoveTo", (Type[])null, (Type[])null); private static readonly MethodInfo _lookAtMethod = AccessTools.Method(typeof(BaseAI), "LookAt", (Type[])null, (Type[])null); public string Id => "VikingAI.SmartAffordanceWork"; public float EvaluateUtility(BaseAI ai, Character character, AgentBehaviorProfile profile) { //IL_0053: 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) if (profile.Roles == NpcRoleFlags.None) { return 0f; } if (ai.IsAlerted()) { return 0f; } MonsterAI val = (MonsterAI)(object)((ai is MonsterAI) ? ai : null); if (val != null) { if ((Object)(object)((BaseAI)val).GetTargetCreature() != (Object)null) { return 0f; } GameObject followTarget = val.GetFollowTarget(); if ((Object)(object)followTarget != (Object)null && Vector3.Distance(followTarget.transform.position, ((Component)character).transform.position) > 6.5f) { return 0f; } } if (!_workStates.TryGetValue(character, out AgentWorkState value)) { value = new AgentWorkState(); _workStates.Add(character, value); } float time = Time.time; if (value.HasActiveTask) { if (!((Object)(object)value.CurrentCandidate.TargetComponent == (Object)null) && !AffordanceRegistry.IsReservedByOther(value.CurrentCandidate.TargetComponent, character)) { return 35f; } value.HasActiveTask = false; } if (time < value.NextScanTime) { return 0f; } value.NextScanTime = time + 2.5f; if (AffordanceRegistry.TrySelectBestTask(character, profile, 28f, out var bestCandidate) && AffordanceRegistry.TryReserve(bestCandidate.TargetComponent, character, 15f)) { value.CurrentCandidate = bestCandidate; value.HasActiveTask = true; value.WorkProgressSeconds = 0f; return 35f; } return 0f; } public bool Tick(BaseAI ai, Character character, AgentBehaviorProfile profile, float dt) { //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_00c9: 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 (!_workStates.TryGetValue(character, out AgentWorkState value) || !value.HasActiveTask) { return false; } AffordanceCandidate candidate = value.CurrentCandidate; if ((Object)(object)candidate.TargetComponent == (Object)null) { value.HasActiveTask = false; return false; } AffordanceRegistry.TryReserve(candidate.TargetComponent, character, 10f); if (Utils.DistanceXZ(((Component)character).transform.position, candidate.InteractionPoint) > 2.1f) { _moveToMethod?.Invoke(ai, new object[4] { dt, candidate.InteractionPoint, 1.5f, false }); return true; } ai.StopMoving(); _lookAtMethod?.Invoke(ai, new object[1] { candidate.InteractionPoint }); value.WorkProgressSeconds += dt; if (value.WorkProgressSeconds >= candidate.WorkDurationSeconds) { AffordanceRegistry.GetProvider(candidate.ProviderId)?.CompleteInteraction(character, profile, in candidate); AffordanceRegistry.ReleaseReservation(candidate.TargetComponent, character); value.HasActiveTask = false; value.NextScanTime = Time.time + 2f; } return true; } } } namespace VikingAI.NPC.Prefabs { public sealed class HumanoidPrefabConfig { public string PrefabName { get; set; } = "VAI_HumanoidNpc"; public string DisplayName { get; set; } = "Wayfarer"; public Faction Faction { get; set; } public string Group { get; set; } = "VAI_Exiles"; public float MaxHealth { get; set; } = 120f; public bool IsAggravatable { get; set; } = true; public bool AttackPlayerObjects { get; set; } public string[] DefaultItemNames { get; set; } = new string[2] { "ArmorRagsChest", "ArmorRagsLegs" }; public string[] RandomWeaponNames { get; set; } = Array.Empty<string>(); public string[] RandomShieldNames { get; set; } = Array.Empty<string>(); public AgentBehaviorProfile? BehaviorProfile { get; set; } } public static class HumanoidPrefabBuilder { private static readonly FieldRef<CharacterAnimEvent, Character> _animEventChar = AccessTools.FieldRefAccess<CharacterAnimEvent, Character>("m_character"); private static readonly Vector3[] _skinTones = (Vector3[])(object)new Vector3[4] { new Vector3(1f, 0.92f, 0.84f), new Vector3(0.95f, 0.85f, 0.74f), new Vector3(0.88f, 0.76f, 0.65f), new Vector3(0.76f, 0.64f, 0.54f) }; private static readonly Vector3[] _hairTones = (Vector3[])(object)new Vector3[5] { new Vector3(0.9f, 0.78f, 0.45f), new Vector3(0.75f, 0.36f, 0.18f), new Vector3(0.38f, 0.26f, 0.16f), new Vector3(0.16f, 0.14f, 0.12f), new Vector3(0.78f, 0.78f, 0.8f) }; public static GameObject? CreateHumanoidNpcPrefab(HumanoidPrefabConfig config) { //IL_0118: 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_03b7: Unknown result type (might be due to invalid IL or missing references) //IL_03c1: Expected O, but got Unknown if (config == null || string.IsNullOrEmpty(config.PrefabName)) { return null; } GameObject prefab = PrefabManager.Instance.GetPrefab(config.PrefabName); if ((Object)(object)prefab != (Object)null) { return prefab; } GameObject prefab2 = PrefabManager.Instance.GetPrefab("Player"); GameObject prefab3 = PrefabManager.Instance.GetPrefab("Dverger"); if ((Object)(object)prefab2 == (Object)null || (Object)(object)prefab3 == (Object)null) { VikingAIPlugin.Log.LogError((object)("[HumanoidPrefabBuilder] Cannot build '" + config.PrefabName + "': Player or Dverger template missing.")); return null; } GameObject val = PrefabManager.Instance.CreateClonedPrefab(config.PrefabName, prefab2); val.tag = "Untagged"; Player component = val.GetComponent<Player>(); CapsuleCollider component2 = val.GetComponent<CapsuleCollider>(); if ((Object)(object)component2 != (Object)null) { component2.radius = Mathf.Min(component2.radius, 0.35f); } Humanoid val2 = val.AddComponent<Humanoid>(); if ((Object)(object)component != (Object)null) { CopyDeclaredFields(component, val2, typeof(Character)); CopyDeclaredFields(component, val2, typeof(Humanoid)); } ((Character)val2).m_name = config.DisplayName; ((Character)val2).m_faction = config.Faction; ((Character)val2).m_group = config.Group; ((Character)val2).m_health = config.MaxHealth; ((Character)val2).m_boss = false; val2.m_defaultItems = ResolvePrefabs(config.DefaultItemNames); val2.m_randomWeapon = ResolvePrefabs(config.RandomWeaponNames); val2.m_randomShield = ResolvePrefabs(config.RandomShieldNames); val2.m_randomArmor = Array.Empty<GameObject>(); val2.m_randomSets = Array.Empty<ItemSet>(); val2.m_randomItems = Array.Empty<RandomItem>(); CharacterAnimEvent componentInChildren = val.GetComponentInChildren<CharacterAnimEvent>(); if ((Object)(object)componentInChildren != (Object)null) { _animEventChar.Invoke(componentInChildren) = (Character)(object)val2; } MonsterAI val3 = val.AddComponent<MonsterAI>(); MonsterAI component3 = prefab3.GetComponent<MonsterAI>(); if ((Object)(object)component3 != (Object)null) { CopyDeclaredFields(component3, val3, typeof(BaseAI)); CopyDeclaredFields(component3, val3, typeof(MonsterAI)); } val3.m_attackPlayerObjects = config.AttackPlayerObjects; ((BaseAI)val3).m_aggravatable = config.IsAggravatable; val3.m_enableHuntPlayer = false; val3.m_sleeping = false; val3.m_fallAsleepDistance = 0f; val3.m_wakeupRange = 0f; val3.m_consumeItems = new List<ItemDrop>(); ((BaseAI)val3).m_randomMoveRange = 6f; ((BaseAI)val3).m_randomMoveInterval = 8f; ((BaseAI)val3).m_viewRange = 28f; ((BaseAI)val3).m_hearRange = 18f; val3.m_alertRange = 14f; val3.m_fleeIfLowHealth = 0f; ((BaseAI)val3).m_avoidWater = true; ((BaseAI)val3).m_avoidFire = false; ((BaseAI)val3).m_smoothMovement = true; ((BaseAI)val3).m_spawnMessage = ""; ((BaseAI)val3).m_deathMessage = ""; ((BaseAI)val3).m_alertedMessage = ""; NpcTalk val4 = val.GetComponent<NpcTalk>() ?? val.AddComponent<NpcTalk>(); NpcTalk component4 = prefab3.GetComponent<NpcTalk>(); if ((Object)(object)component4 != (Object)null) { CopyDeclaredFields(component4, val4, typeof(NpcTalk)); } val4.m_name = config.DisplayName; val4.m_maxRange = 12f; val4.m_greetRange = 6f; val4.m_byeRange = 10f; val4.m_minTalkInterval = 8f; val4.m_randomTalkInterval = 25f; Dest