Decompiled source of MimicREUPLOADED v0.7.0

Mods/MimicMod.dll

Decompiled 2 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text.Json;
using BoneLib.BoneMenu;
using MelonLoader;
using Microsoft.CodeAnalysis;
using MimicMod;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(Mod), "Mimic Mod", "0.6.0", "GoldenNull", null)]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("MimicMod")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("MimicMod")]
[assembly: AssemblyTitle("MimicMod")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[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 MimicMod
{
	internal sealed class MimicAI : IDisposable
	{
		private sealed class BotRuntime
		{
			public float NextAttackAt;

			public float AttackModeUntil;

			public float AttackWindupUntil;

			public bool AttackPending;

			public float NextCoverAt;

			public Vector3 LastGoal;

			public bool HasGoal;

			public bool EncounterRecorded;

			public float NextRushRecordAt;

			public MimicBehavior Behavior = new MimicBehavior();

			public float RestoreVisualAt;

			public Renderer[] FlickerRenderers;

			public bool[] RendererStates;

			public Vector3 NavigationTarget;

			public Vector3 CurrentWaypoint;

			public bool HasNavigationTarget;

			public bool HasCurrentWaypoint;

			public float NextPathUpdateAt;

			public Vector3 LastKnownPlayerPosition;

			public float LastSeenPlayerAt = -1000f;

			public float NextInvestigationAt;

			public bool HasLastKnownPlayerPosition;
		}

		private readonly Instance _log;

		private MimicSettings _settings = new MimicSettings();

		private MimicLearning _learning;

		private MimicEncounters _encounters;

		private float _nextJumpscareAt;

		private float _nextLearningSampleAt;

		private readonly ArrayList _bots = new ArrayList();

		private readonly Dictionary<object, BotRuntime> _runtime = new Dictionary<object, BotRuntime>();

		private readonly List<GameObject> _goalObjects = new List<GameObject>();

		private readonly Dictionary<object, GameObject> _goalMarkers = new Dictionary<object, GameObject>();

		private Type _managerType;

		private PropertyInfo _allProperty;

		private bool _enabled;

		private bool _selfAware;

		private bool _coverEnabled = true;

		private bool _attacksEnabled = true;

		private bool _visualGlitches;

		private bool _disposed;

		private bool _coverWarningLogged;

		private bool _pathfindingEnabled = true;

		private float _pathRefreshInterval = 0.8f;

		private float _obstacleClearance = 1.4f;

		private float _waypointReachDistance = 1.1f;

		private float _nextRefresh;

		private float _nextDecision;

		private float _nextGlitch;

		private float _sceneRefreshUntil;

		private int _decision;

		private const BindingFlags Flags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;

		private const float AttackRange = 2.15f;

		private const float AttackWindup = 0.55f;

		private const float CoverRadius = 5.5f;

		public MimicAI(Instance logger)
		{
			_log = logger;
			ResolveDoppel();
		}

		public void NotifySceneLoaded(string sceneName)
		{
			_bots.Clear();
			_runtime.Clear();
			_goalMarkers.Clear();
			for (int i = 0; i < _goalObjects.Count; i++)
			{
				try
				{
					if ((Object)(object)_goalObjects[i] != (Object)null)
					{
						Object.Destroy((Object)(object)_goalObjects[i]);
					}
				}
				catch
				{
				}
			}
			_goalObjects.Clear();
			_managerType = null;
			_allProperty = null;
			_nextRefresh = 0f;
			_nextDecision = 0f;
			_nextLearningSampleAt = 0f;
			_sceneRefreshUntil = Time.time + 30f;
			_log.Msg("Mimic detected level load/reload ('" + (sceneName ?? "unknown") + "'); refreshing Doppel bots.");
		}

		public void Configure(MimicSettings settings, MimicLearning learning, MimicEncounters encounters)
		{
			_settings = settings ?? new MimicSettings();
			_settings.ClampValues();
			_learning = learning;
			_encounters = encounters;
			_selfAware = _settings.selfAwareEnabled;
			_coverEnabled = _settings.stalkingEnabled;
			_attacksEnabled = _settings.attacksEnabled && _settings.behaviorMode != MimicBehaviorMode.NonHostile && _settings.behaviorMode != MimicBehaviorMode.Jumpscare;
			_visualGlitches = _settings.visualGlitchesEnabled || _settings.behaviorMode == MimicBehaviorMode.Jumpscare;
			_pathfindingEnabled = _settings.pathfindingEnabled;
			_pathRefreshInterval = _settings.pathRefreshInterval;
			_obstacleClearance = _settings.obstacleClearance;
			_waypointReachDistance = _settings.waypointReachDistance;
		}

		public void SetEnabled(bool enabled)
		{
			if (_enabled != enabled)
			{
				_enabled = enabled;
				if (!enabled)
				{
					RestoreBots();
				}
				else
				{
					_nextRefresh = 0f;
					_sceneRefreshUntil = Time.time + 30f;
					RefreshBots();
					_nextDecision = Time.time + 0.5f;
				}
				_log.Msg("Mimic AI " + (enabled ? "enabled." : "disabled.") + ".");
			}
		}

		public void SetSelfAware(bool enabled)
		{
			_selfAware = enabled;
			_log.Msg("Experimental self-aware behavior " + (enabled ? "enabled." : "disabled.") + ".");
		}

		public void SetCoverEnabled(bool enabled)
		{
			_coverEnabled = enabled;
			_log.Msg("Cover seeking and stalking " + (enabled ? "enabled." : "disabled.") + ".");
		}

		public void SetAttacksEnabled(bool enabled)
		{
			_attacksEnabled = enabled;
			_log.Msg("Close-range attacks " + (enabled ? "enabled." : "disabled.") + ".");
		}

		public void SetVisualGlitches(bool enabled)
		{
			_visualGlitches = enabled;
			if (!enabled)
			{
				RestoreAllFlickers();
			}
			_log.Msg("Visual glitches " + (enabled ? "enabled." : "disabled.") + ".");
		}

		public void RefreshBots()
		{
			RefreshBots(logResult: true);
		}

		private void RefreshBots(bool logResult)
		{
			ResolveDoppel();
			_bots.Clear();
			if (_allProperty == null)
			{
				if (logResult)
				{
					_log.Warning("Doppel BotManager.All was not found. Ensure Doppel is installed and loaded.");
				}
				return;
			}
			try
			{
				if (_allProperty.GetValue(null, null) is IEnumerable enumerable)
				{
					foreach (object item in enumerable)
					{
						if (item != null)
						{
							_bots.Add(item);
							if (!_runtime.ContainsKey(item))
							{
								_runtime[item] = new BotRuntime();
							}
						}
					}
				}
				List<object> list = null;
				foreach (object key in _runtime.Keys)
				{
					bool flag = false;
					for (int i = 0; i < _bots.Count; i++)
					{
						if (key == _bots[i] || object.Equals(key, _bots[i]))
						{
							flag = true;
							break;
						}
					}
					if (!flag)
					{
						if (list == null)
						{
							list = new List<object>();
						}
						list.Add(key);
					}
				}
				if (list != null)
				{
					for (int j = 0; j < list.Count; j++)
					{
						_runtime.Remove(list[j]);
					}
				}
				if (logResult)
				{
					_log.Msg("Mimic found " + _bots.Count + " existing Doppel bot(s).");
				}
			}
			catch (Exception ex)
			{
				if (logResult)
				{
					_log.Error("Doppel bot refresh failed: " + ex.Message);
				}
			}
		}

		private void ResolveDoppel()
		{
			if (_managerType != null && _allProperty != null)
			{
				return;
			}
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			foreach (Assembly assembly in assemblies)
			{
				try
				{
					Type type = assembly.GetType("ThirdEyeBonelabMod.Bots.BotManager", throwOnError: false);
					if (type == null)
					{
						continue;
					}
					_managerType = type;
					_allProperty = type.GetProperty("All", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
					break;
				}
				catch
				{
				}
			}
		}

		public void Update()
		{
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01de: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_0212: Unknown result type (might be due to invalid IL or missing references)
			//IL_0219: Unknown result type (might be due to invalid IL or missing references)
			//IL_022f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0234: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_04aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_07ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_07f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0588: Unknown result type (might be due to invalid IL or missing references)
			//IL_0804: Unknown result type (might be due to invalid IL or missing references)
			//IL_05ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_05d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_080f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0811: Unknown result type (might be due to invalid IL or missing references)
			//IL_05e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_05ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_05ee: Unknown result type (might be due to invalid IL or missing references)
			if (_disposed)
			{
				return;
			}
			UpdateFlickerRestores();
			if (!_enabled)
			{
				return;
			}
			if (Time.time >= _nextRefresh)
			{
				bool flag = Time.time < _sceneRefreshUntil;
				_nextRefresh = Time.time + (flag ? 1f : 8f);
				RefreshBots(logResult: false);
				if (_bots.Count > 0)
				{
					_sceneRefreshUntil = 0f;
					_nextRefresh = Time.time + 8f;
				}
			}
			if (_visualGlitches && Time.time >= _nextGlitch)
			{
				_nextGlitch = Time.time + Random.Range(8f, 18f);
				TryStartRandomFlicker();
			}
			if (Time.time < _nextDecision || _bots.Count == 0)
			{
				return;
			}
			_nextDecision = Time.time + 0.35f;
			Transform val = (((Object)(object)Camera.main != (Object)null) ? ((Component)Camera.main).transform : null);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			MimicLearning mimicLearning = (_settings.learningEnabled ? _learning : null);
			if (mimicLearning != null && Time.time >= _nextLearningSampleAt)
			{
				_nextLearningSampleAt = Time.time + 0.4f;
				mimicLearning.Observe(val.position, val.forward, Time.time);
			}
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			int num4 = 0;
			for (int num5 = _bots.Count - 1; num5 >= 0; num5--)
			{
				object obj = _bots[num5];
				if (obj == null)
				{
					_bots.RemoveAt(num5);
					continue;
				}
				BotRuntime runtime = GetRuntime(obj);
				Transform botTransform = GetBotTransform(obj);
				if ((Object)(object)botTransform == (Object)null)
				{
					SetModeIfDifferent(obj, "Brain");
					continue;
				}
				UpdatePathfinding(obj, botTransform, runtime);
				float num6 = Vector3.Distance(botTransform.position, val.position);
				bool flag2 = IsPlayerLookingAt(val, botTransform.position, num6, _settings.selfAwareDistance, _settings.selfAwareLookDot) && HasLineOfSight(val.position, botTransform.position);
				if (flag2)
				{
					runtime.LastKnownPlayerPosition = val.position;
					runtime.LastSeenPlayerAt = Time.time;
					runtime.HasLastKnownPlayerPosition = true;
				}
				if (_selfAware && !flag2 && runtime.HasLastKnownPlayerPosition && Time.time - runtime.LastSeenPlayerAt <= _settings.selfAwareMemorySeconds && num6 > 2.15f && Time.time >= runtime.NextInvestigationAt)
				{
					runtime.NextInvestigationAt = Time.time + Mathf.Max(0.5f, _settings.pathRefreshInterval);
					if (TrySetGoal(obj, runtime.LastKnownPlayerPosition))
					{
						SetModeIfDifferent(obj, "Brain");
					}
					else
					{
						SetModeIfDifferent(obj, "Follow");
					}
					continue;
				}
				if (_encounters != null && num6 < 20f && !runtime.EncounterRecorded)
				{
					_encounters.Record("encounter", "Mimic entered player proximity; distance=" + num6.ToString("F1"));
					runtime.EncounterRecorded = true;
				}
				if (num6 > 25f)
				{
					runtime.EncounterRecorded = false;
				}
				if (_settings.behaviorMode == MimicBehaviorMode.Jumpscare)
				{
					if (num6 <= 5f && flag2 && Time.time >= _nextJumpscareAt)
					{
						_nextJumpscareAt = Time.time + _settings.jumpscareCooldown;
						if (_visualGlitches)
						{
							TryStartFlickerForBot(obj);
						}
						if (_encounters != null)
						{
							_encounters.Record("jumpscare", "Close-range jumpscare trigger; recorded audio feature is disabled.");
						}
					}
					if (num6 > 2.15f)
					{
						if (!TrySetRushMode(obj))
						{
							SetModeIfDifferent(obj, "Follow");
						}
					}
					else
					{
						SetModeIfDifferent(obj, "Stand");
					}
					continue;
				}
				if (_settings.behaviorMode == MimicBehaviorMode.NonHostile)
				{
					runtime.AttackPending = false;
					runtime.AttackModeUntil = 0f;
					if (!SetModeIfDifferent(obj, "Wander"))
					{
						SetModeIfDifferent(obj, "Stand");
					}
					continue;
				}
				if (_settings.behaviorMode == MimicBehaviorMode.RuthlessAttacker && num6 > 2.15f)
				{
					if (!TrySetRushMode(obj))
					{
						SetModeIfDifferent(obj, "Follow");
					}
					continue;
				}
				if (_settings.behaviorMode == MimicBehaviorMode.AdaptiveStalker)
				{
					MimicAction mimicAction = runtime.Behavior.Decide(_settings, mimicLearning, Time.time, num6, flag2, HasLineOfSight(val.position, botTransform.position), mimicLearning != null && mimicLearning.AverageSpeed() > 0.12f, num6 <= 2.15f, Time.time >= _nextJumpscareAt);
					if (_coverEnabled && mimicAction == MimicAction.Rush)
					{
						if (!TrySetRushMode(obj))
						{
							SetModeIfDifferent(obj, "Follow");
						}
						if (_encounters != null && Time.time >= runtime.NextRushRecordAt)
						{
							_encounters.Record("rush", "Adaptive behavior selected a rush.");
							runtime.NextRushRecordAt = Time.time + 5f;
						}
						continue;
					}
					if (_coverEnabled && mimicAction == MimicAction.Stalk)
					{
						SetModeIfDifferent(obj, "Follow");
						continue;
					}
					if (_coverEnabled && mimicAction == MimicAction.Investigate)
					{
						if (TrySetGoal(obj, val.position))
						{
							SetModeIfDifferent(obj, "Brain");
						}
						else
						{
							SetModeIfDifferent(obj, "Follow");
						}
						continue;
					}
					if (mimicAction == MimicAction.TakeCover && _coverEnabled && TryFindCover(botTransform.position, val.position, out var result) && TrySetGoal(obj, result))
					{
						runtime.LastGoal = result;
						runtime.HasGoal = true;
						SetModeIfDifferent(obj, "Brain");
						continue;
					}
				}
				if (_selfAware && flag2 && num6 < 20f)
				{
					SetModeIfDifferent(obj, "Stand");
					num4++;
					continue;
				}
				if (_attacksEnabled && num6 <= 2.15f)
				{
					if (runtime.AttackPending)
					{
						if (Time.time < runtime.AttackWindupUntil)
						{
							SetModeIfDifferent(obj, "Stand");
							continue;
						}
						runtime.AttackPending = false;
						runtime.AttackModeUntil = Time.time + 0.8f;
						SetModeIfDifferent(obj, "Fists");
						if (_encounters != null)
						{
							_encounters.Record("attack", "Doppel Fists mode entered after wind-up.");
						}
						num++;
					}
					else if (runtime.AttackModeUntil > Time.time)
					{
						SetModeIfDifferent(obj, "Fists");
						num++;
					}
					else if (Time.time >= runtime.NextAttackAt)
					{
						runtime.AttackPending = true;
						runtime.AttackWindupUntil = Time.time + 0.55f;
						runtime.NextAttackAt = Time.time + Mathf.Max(0.5f, _settings.attackCooldown);
						SetModeIfDifferent(obj, "Stand");
					}
					else
					{
						SetModeIfDifferent(obj, "Brain");
					}
					continue;
				}
				if (runtime.AttackModeUntil > 0f && runtime.AttackModeUntil <= Time.time)
				{
					runtime.AttackModeUntil = 0f;
					SetModeIfDifferent(obj, "Brain");
				}
				if (num6 > 2.15f && runtime.AttackPending)
				{
					runtime.AttackPending = false;
				}
				bool flag3 = false;
				if (_coverEnabled && Time.time >= runtime.NextCoverAt)
				{
					runtime.NextCoverAt = Time.time + Random.Range(2.8f, 4.8f);
					if (TryFindCover(botTransform.position, val.position, out var result2) && TrySetGoal(obj, result2))
					{
						runtime.LastGoal = result2;
						runtime.HasGoal = true;
						if (_encounters != null)
						{
							_encounters.Record("cover", "Assigned cover goal.");
						}
						SetModeIfDifferent(obj, "Brain");
						num2++;
						flag3 = true;
					}
				}
				if (!flag3)
				{
					int num7 = (_decision + num5) % 9;
					string modeName = ((!_coverEnabled) ? "Brain" : (num7 switch
					{
						5 => "Follow", 
						0 => "Wander", 
						_ => "Brain", 
					}));
					SetModeIfDifferent(obj, modeName);
					num3++;
				}
			}
			_decision++;
			if (num > 0)
			{
				_log.Msg("Mimic: close-range Doppel combat active for " + num + " bot(s).");
			}
			else if (num2 > 0)
			{
				_log.Msg("Mimic: assigned physics-tested cover goal to " + num2 + " bot(s).");
			}
			else if (num4 > 0)
			{
				_log.Msg("Mimic self-aware behavior: pausing while observed.");
			}
		}

		private BotRuntime GetRuntime(object bot)
		{
			if (!_runtime.TryGetValue(bot, out var value))
			{
				value = new BotRuntime();
				_runtime[bot] = value;
			}
			return value;
		}

		private bool TryFindCover(Vector3 botPosition, Vector3 playerPosition, out Vector3 result)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: 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_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)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: 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_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: 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_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: 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_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: 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_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: 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_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			result = botPosition;
			Vector3 val = botPosition - playerPosition;
			val.y = 0f;
			if (((Vector3)(ref val)).sqrMagnitude < 0.1f)
			{
				val = Vector3.back;
			}
			((Vector3)(ref val)).Normalize();
			Vector3 val2 = Vector3.Cross(Vector3.up, val);
			Vector3 normalized = ((Vector3)(ref val2)).normalized;
			float[] array = new float[4] { 2f, 3.2f, 4.5f, 5.5f };
			float[] array2 = new float[5] { 0f, 1.3f, -1.3f, 2.4f, -2.4f };
			float num = float.MaxValue;
			bool result2 = false;
			RaycastHit val4 = default(RaycastHit);
			RaycastHit val7 = default(RaycastHit);
			for (int i = 0; i < array.Length; i++)
			{
				for (int j = 0; j < array2.Length; j++)
				{
					Vector3 val3 = playerPosition + val * array[i] + normalized * array2[j];
					if (!Physics.Raycast(val3 + Vector3.up * 2.2f, Vector3.down, ref val4, 5f, -1, (QueryTriggerInteraction)1))
					{
						continue;
					}
					val3 = ((RaycastHit)(ref val4)).point + Vector3.up * 0.1f;
					Vector3 val5 = val3 + Vector3.up * 1.1f;
					Vector3 val6 = playerPosition + Vector3.up * 1f - val5;
					float magnitude = ((Vector3)(ref val6)).magnitude;
					if (!(magnitude < 0.2f) && Physics.Raycast(val5, val6 / magnitude, ref val7, magnitude, -1, (QueryTriggerInteraction)1) && !Physics.CheckSphere(val3 + Vector3.up * 0.7f, 0.28f, -1, (QueryTriggerInteraction)1))
					{
						float num2 = Vector3.Distance(botPosition, val3) + Vector3.Distance(playerPosition, val3) * 0.25f;
						if (num2 < num && Vector3.Distance(botPosition, val3) > 1f)
						{
							num = num2;
							result = val3;
							result2 = true;
						}
					}
				}
			}
			return result2;
		}

		private static bool HasLineOfSight(Vector3 from, Vector3 to)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: 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_001d: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = to - from;
			float magnitude = ((Vector3)(ref val)).magnitude;
			if (magnitude < 0.1f)
			{
				return true;
			}
			RaycastHit val2 = default(RaycastHit);
			return !Physics.Raycast(from, val / magnitude, ref val2, magnitude, -1, (QueryTriggerInteraction)1);
		}

		private static bool IsPlayerLookingAt(Transform player, Vector3 target, float distance, float maxDistance, float lookDot)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			if (distance > maxDistance)
			{
				return false;
			}
			Vector3 val = target + Vector3.up * 0.8f - player.position;
			if (((Vector3)(ref val)).sqrMagnitude < 0.001f)
			{
				return true;
			}
			return Vector3.Dot(player.forward, ((Vector3)(ref val)).normalized) > lookDot;
		}

		private bool TrySetGoal(object bot, Vector3 goal)
		{
			//IL_0021: 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_003e: 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_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			Transform botTransform = GetBotTransform(bot);
			if ((Object)(object)botTransform == (Object)null)
			{
				return TrySetGoalRaw(bot, goal);
			}
			BotRuntime runtime = GetRuntime(bot);
			runtime.NavigationTarget = goal;
			runtime.HasNavigationTarget = _pathfindingEnabled;
			runtime.NextPathUpdateAt = 0f;
			Vector3 waypoint = goal;
			if (_pathfindingEnabled)
			{
				MimicPathfinder.TryFindWaypoint(botTransform.position, goal, _obstacleClearance, out waypoint);
			}
			runtime.CurrentWaypoint = waypoint;
			runtime.HasCurrentWaypoint = true;
			runtime.NextPathUpdateAt = Time.time + _pathRefreshInterval;
			return TrySetGoalRaw(bot, waypoint);
		}

		private void UpdatePathfinding(object bot, Transform botTransform, BotRuntime state)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: 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_0094: 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_00b5: Unknown result type (might be due to invalid IL or missing references)
			if (_pathfindingEnabled && state.HasNavigationTarget && !((Object)(object)botTransform == (Object)null))
			{
				if (Vector3.Distance(botTransform.position, state.NavigationTarget) <= _waypointReachDistance)
				{
					state.HasNavigationTarget = false;
				}
				else if ((state.HasCurrentWaypoint && Vector3.Distance(botTransform.position, state.CurrentWaypoint) <= _waypointReachDistance) || !(Time.time < state.NextPathUpdateAt))
				{
					Vector3 waypoint = state.NavigationTarget;
					MimicPathfinder.TryFindWaypoint(botTransform.position, state.NavigationTarget, _obstacleClearance, out waypoint);
					state.CurrentWaypoint = waypoint;
					state.HasCurrentWaypoint = true;
					state.NextPathUpdateAt = Time.time + _pathRefreshInterval;
					TrySetGoalRaw(bot, waypoint);
				}
			}
		}

		private bool TrySetGoalRaw(object bot, Vector3 goal)
		{
			//IL_0026: 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)
			try
			{
				Type type = bot.GetType();
				FieldInfo field = type.GetField("goal", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				if (field != null && TryConvertGoal(bot, field.FieldType, goal, out var value))
				{
					field.SetValue(bot, value);
					return true;
				}
				PropertyInfo property = type.GetProperty("goal", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				if (property != null && property.CanWrite && TryConvertGoal(bot, property.PropertyType, goal, out var value2))
				{
					property.SetValue(bot, value2, null);
					return true;
				}
			}
			catch (Exception ex)
			{
				if (!_coverWarningLogged)
				{
					_log.Warning("Doppel goal assignment failed; using built-in AI modes instead. " + ex.Message);
					_coverWarningLogged = true;
				}
			}
			if (!_coverWarningLogged)
			{
				_log.Warning("This Doppel build does not expose a writable compatible 'goal' member. Custom waypoint navigation is unavailable; using Doppel Brain/Wander instead.");
				_coverWarningLogged = true;
			}
			return false;
		}

		private bool TryConvertGoal(object bot, Type targetType, Vector3 goal, out object value)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Expected O, but got Unknown
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			value = null;
			if (targetType == typeof(Vector3))
			{
				value = goal;
				return true;
			}
			if (targetType == typeof(Transform) || targetType == typeof(GameObject))
			{
				if (!_goalMarkers.TryGetValue(bot, out var value2) || (Object)(object)value2 == (Object)null)
				{
					value2 = new GameObject("MimicMod_CoverGoal");
					((Object)value2).hideFlags = (HideFlags)61;
					_goalMarkers[bot] = value2;
					_goalObjects.Add(value2);
				}
				value2.transform.position = goal;
				value = ((targetType == typeof(Transform)) ? ((object)value2.transform) : ((object)value2));
				return true;
			}
			return false;
		}

		private static Transform GetBotTransform(object bot)
		{
			try
			{
				Component val = (Component)((bot is Component) ? bot : null);
				if (val != null)
				{
					return val.transform;
				}
				GameObject val2 = (GameObject)((bot is GameObject) ? bot : null);
				if (val2 != null)
				{
					return val2.transform;
				}
				Type type = bot.GetType();
				string[] array = new string[3] { "rig", "transform", "gameObject" };
				foreach (string name in array)
				{
					object obj = ReadMember(type, bot, name);
					Transform val3 = AsTransform(obj);
					if ((Object)(object)val3 != (Object)null)
					{
						return val3;
					}
					if (obj != null)
					{
						Transform val4 = AsTransform(ReadMember(obj.GetType(), obj, "transform"));
						if ((Object)(object)val4 != (Object)null)
						{
							return val4;
						}
					}
				}
			}
			catch
			{
			}
			return null;
		}

		private static object ReadMember(Type type, object instance, string name)
		{
			FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			if (field != null)
			{
				return field.GetValue(instance);
			}
			PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			if (property != null && property.GetIndexParameters().Length == 0)
			{
				return property.GetValue(instance, null);
			}
			return null;
		}

		private static Transform AsTransform(object value)
		{
			Transform val = (Transform)((value is Transform) ? value : null);
			if (val != null)
			{
				return val;
			}
			Component val2 = (Component)((value is Component) ? value : null);
			if (val2 != null)
			{
				return val2.transform;
			}
			GameObject val3 = (GameObject)((value is GameObject) ? value : null);
			if (val3 != null)
			{
				return val3.transform;
			}
			return null;
		}

		private bool SetModeIfDifferent(object bot, string modeName)
		{
			try
			{
				Type type = bot.GetType();
				MethodInfo method = type.GetMethod("SetMode", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				if (method == null)
				{
					return false;
				}
				ParameterInfo[] parameters = method.GetParameters();
				if (parameters.Length != 1 || !parameters[0].ParameterType.IsEnum)
				{
					return false;
				}
				object obj = Enum.Parse(parameters[0].ParameterType, modeName, ignoreCase: true);
				object obj2 = ReadMember(type, bot, "mode");
				if (obj2 != null && obj2.Equals(obj))
				{
					return true;
				}
				method.Invoke(bot, new object[1] { obj });
				return true;
			}
			catch
			{
				return false;
			}
		}

		private bool TrySetRushMode(object bot)
		{
			if (!SetModeIfDifferent(bot, "Run") && !SetModeIfDifferent(bot, "Sprint") && !SetModeIfDifferent(bot, "Chase"))
			{
				return SetModeIfDifferent(bot, "Follow");
			}
			return true;
		}

		private void TryStartFlickerForBot(object bot)
		{
			Transform val = ((bot == null) ? null : GetBotTransform(bot));
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			Renderer[] componentsInChildren = ((Component)val).GetComponentsInChildren<Renderer>(true);
			if (componentsInChildren == null || componentsInChildren.Length == 0)
			{
				return;
			}
			BotRuntime runtime = GetRuntime(bot);
			if (runtime.RestoreVisualAt > Time.time)
			{
				return;
			}
			runtime.FlickerRenderers = componentsInChildren;
			runtime.RendererStates = new bool[componentsInChildren.Length];
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				runtime.RendererStates[i] = (Object)(object)componentsInChildren[i] != (Object)null && componentsInChildren[i].enabled;
				if ((Object)(object)componentsInChildren[i] != (Object)null)
				{
					componentsInChildren[i].enabled = false;
				}
			}
			runtime.RestoreVisualAt = Time.time + Random.Range(0.08f, 0.16f);
		}

		private void TryStartRandomFlicker()
		{
			if (_bots.Count == 0)
			{
				return;
			}
			for (int i = 0; i < _bots.Count; i++)
			{
				object obj = _bots[Random.Range(0, _bots.Count)];
				Transform val = ((obj == null) ? null : GetBotTransform(obj));
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				Renderer[] componentsInChildren = ((Component)val).GetComponentsInChildren<Renderer>(true);
				if (componentsInChildren == null || componentsInChildren.Length == 0)
				{
					break;
				}
				BotRuntime runtime = GetRuntime(obj);
				if (runtime.RestoreVisualAt > Time.time)
				{
					break;
				}
				runtime.FlickerRenderers = componentsInChildren;
				runtime.RendererStates = new bool[componentsInChildren.Length];
				for (int j = 0; j < componentsInChildren.Length; j++)
				{
					runtime.RendererStates[j] = (Object)(object)componentsInChildren[j] != (Object)null && componentsInChildren[j].enabled;
					if ((Object)(object)componentsInChildren[j] != (Object)null)
					{
						componentsInChildren[j].enabled = false;
					}
				}
				runtime.RestoreVisualAt = Time.time + Random.Range(0.07f, 0.14f);
				break;
			}
		}

		private void UpdateFlickerRestores()
		{
			foreach (KeyValuePair<object, BotRuntime> item in _runtime)
			{
				BotRuntime value = item.Value;
				if (!(value.RestoreVisualAt <= 0f) && !(Time.time < value.RestoreVisualAt))
				{
					RestoreFlicker(value);
				}
			}
		}

		private void RestoreFlicker(BotRuntime state)
		{
			if (state.FlickerRenderers != null && state.RendererStates != null)
			{
				for (int i = 0; i < state.FlickerRenderers.Length && i < state.RendererStates.Length; i++)
				{
					if ((Object)(object)state.FlickerRenderers[i] != (Object)null)
					{
						state.FlickerRenderers[i].enabled = state.RendererStates[i];
					}
				}
			}
			state.FlickerRenderers = null;
			state.RendererStates = null;
			state.RestoreVisualAt = 0f;
		}

		private void RestoreAllFlickers()
		{
			foreach (BotRuntime value in _runtime.Values)
			{
				RestoreFlicker(value);
			}
		}

		private void RestoreBots()
		{
			RestoreAllFlickers();
			foreach (object bot in _bots)
			{
				if (bot != null)
				{
					SetModeIfDifferent(bot, "Stand");
				}
			}
		}

		public void Dispose()
		{
			if (_disposed)
			{
				return;
			}
			_disposed = true;
			RestoreBots();
			_bots.Clear();
			foreach (GameObject goalObject in _goalObjects)
			{
				if ((Object)(object)goalObject != (Object)null)
				{
					Object.Destroy((Object)(object)goalObject);
				}
			}
			_goalObjects.Clear();
			_goalMarkers.Clear();
			_runtime.Clear();
			_log.Msg("Mimic AI disposed.");
		}
	}
	internal enum MimicAction
	{
		Observe,
		Stalk,
		TakeCover,
		Investigate,
		Rush,
		Attack,
		Jumpscare,
		Ignore
	}
	internal sealed class MimicBehavior
	{
		private float _nextDecisionAt;

		private float _lastJumpscareAt = -99999f;

		private float _lastAttackAt = -99999f;

		public MimicAction Decide(MimicSettings settings, MimicLearning learning, float now, float distanceToPlayer, bool playerLookingAtMimic, bool lineOfSight, bool playerMoving, bool canAttack, bool jumpscareAvailable)
		{
			if (settings == null || !settings.enabled)
			{
				return MimicAction.Observe;
			}
			if (settings.behaviorMode == MimicBehaviorMode.NonHostile)
			{
				if (!lineOfSight)
				{
					return MimicAction.Investigate;
				}
				return MimicAction.Observe;
			}
			if (settings.behaviorMode == MimicBehaviorMode.Jumpscare && jumpscareAvailable && now - _lastJumpscareAt >= settings.jumpscareCooldown && distanceToPlayer < 5f && lineOfSight)
			{
				_lastJumpscareAt = now;
				return MimicAction.Jumpscare;
			}
			if (settings.behaviorMode == MimicBehaviorMode.RuthlessAttacker)
			{
				if (settings.attacksEnabled && canAttack && now - _lastAttackAt >= settings.attackCooldown)
				{
					_lastAttackAt = now;
					return MimicAction.Attack;
				}
				if (!(distanceToPlayer > 2.2f))
				{
					return MimicAction.Attack;
				}
				return MimicAction.Rush;
			}
			if (now < _nextDecisionAt)
			{
				return MimicAction.Observe;
			}
			_nextDecisionAt = now + Random.Range(0.65f, 1.8f);
			if (settings.attacksEnabled && canAttack && distanceToPlayer < 2.15f && now - _lastAttackAt >= settings.attackCooldown && Random.value < 0.25f)
			{
				_lastAttackAt = now;
				return MimicAction.Attack;
			}
			if (playerLookingAtMimic && distanceToPlayer > 3f)
			{
				return MimicAction.TakeCover;
			}
			if (!lineOfSight)
			{
				return MimicAction.Investigate;
			}
			if (distanceToPlayer > settings.stalkDistance)
			{
				if (!(Random.value < settings.rushChance))
				{
					return MimicAction.Stalk;
				}
				return MimicAction.Rush;
			}
			if (learning != null && learning.AveragePause() > 2.5f && Random.value < settings.rushChance * 0.5f)
			{
				return MimicAction.Rush;
			}
			if (!playerMoving)
			{
				if (!(Random.value < 0.35f))
				{
					return MimicAction.Observe;
				}
				return MimicAction.TakeCover;
			}
			return MimicAction.Stalk;
		}
	}
	internal sealed class MimicDataManager
	{
		private readonly Instance _log;

		private readonly JsonSerializerOptions _options = new JsonSerializerOptions
		{
			WriteIndented = true,
			IncludeFields = true
		};

		public MimicSettings Settings { get; private set; }

		public MimicLearning Learning { get; private set; }

		public MimicEncounters Encounters { get; private set; }

		public string DirectoryPath { get; private set; }

		public MimicDataManager(Instance logger, string rootDirectory = null)
		{
			_log = logger;
			DirectoryPath = Path.Combine(string.IsNullOrWhiteSpace(rootDirectory) ? Environment.CurrentDirectory : rootDirectory, "Userdata", "Mimic");
			Settings = new MimicSettings();
			Learning = new MimicLearning();
			Encounters = new MimicEncounters();
		}

		public void Load()
		{
			Directory.CreateDirectory(DirectoryPath);
			Settings = LoadFile("MimicSettings.json", Settings);
			Learning = LoadFile("MimicLearning.json", Learning);
			Encounters = LoadFile("MimicEncounters.json", Encounters);
			if (Settings == null)
			{
				Settings = new MimicSettings();
			}
			if (Learning == null)
			{
				Learning = new MimicLearning();
			}
			if (Encounters == null)
			{
				Encounters = new MimicEncounters();
			}
			Settings.ClampValues();
			SaveAll();
			_log.Msg("Mimic data directory: " + DirectoryPath);
		}

		public void SaveAll()
		{
			SaveFile("MimicSettings.json", Settings);
			SaveFile("MimicLearning.json", Learning);
			SaveFile("MimicEncounters.json", Encounters);
			SaveBrain(JsonSerializer.Serialize(new
			{
				version = 1,
				behaviorMode = Settings.behaviorMode.ToString(),
				enabled = Settings.enabled,
				learningEnabled = Settings.learningEnabled,
				sessions = Learning.sessions,
				averageSpeed = Learning.AverageSpeed(),
				averagePause = Learning.AveragePause(),
				averageTurn = Learning.AverageTurn(),
				savedUtc = DateTime.UtcNow.ToString("o")
			}, _options));
		}

		public void SaveBrain(string json)
		{
			try
			{
				WriteAtomically(Path.Combine(DirectoryPath, "MimicBrain.json"), json ?? "{}");
			}
			catch (Exception ex)
			{
				_log.Error("Could not save MimicBrain.json: " + ex.Message);
			}
		}

		private T LoadFile<T>(string name, T fallback) where T : class
		{
			string path = Path.Combine(DirectoryPath, name);
			if (!File.Exists(path))
			{
				return fallback;
			}
			try
			{
				return JsonSerializer.Deserialize<T>(File.ReadAllText(path), _options) ?? fallback;
			}
			catch (Exception ex)
			{
				_log.Warning("Could not load " + name + ": " + ex.Message + ". Keeping defaults.");
				return fallback;
			}
		}

		private void SaveFile<T>(string name, T value)
		{
			try
			{
				string content = JsonSerializer.Serialize(value, _options);
				WriteAtomically(Path.Combine(DirectoryPath, name), content);
			}
			catch (Exception ex)
			{
				_log.Error("Could not save " + name + ": " + ex.Message);
			}
		}

		private static void WriteAtomically(string path, string content)
		{
			Directory.CreateDirectory(Path.GetDirectoryName(path));
			string text = path + ".tmp";
			File.WriteAllText(text, content);
			if (File.Exists(path))
			{
				string destinationBackupFileName = path + ".bak";
				try
				{
					File.Replace(text, path, destinationBackupFileName, ignoreMetadataErrors: true);
					return;
				}
				catch
				{
					File.Copy(text, path, overwrite: true);
					File.Delete(text);
					return;
				}
			}
			File.Move(text, path);
		}
	}
	[Serializable]
	public sealed class MimicEncounterRecord
	{
		public string utc;

		public string eventType;

		public string note;
	}
	[Serializable]
	public sealed class MimicEncounters
	{
		public int version = 1;

		public int totalEncounters;

		public int totalRushes;

		public int totalAttacks;

		public int totalJumpscares;

		public string lastEncounterUtc = "";

		public List<MimicEncounterRecord> history = new List<MimicEncounterRecord>();

		public void Record(string eventType, string note = "")
		{
			string text = (eventType ?? "event").Trim().ToLowerInvariant();
			string utc = (lastEncounterUtc = DateTime.UtcNow.ToString("o"));
			if (text.Contains("encounter"))
			{
				totalEncounters++;
			}
			if (text.Contains("rush"))
			{
				totalRushes++;
			}
			if (text.Contains("attack"))
			{
				totalAttacks++;
			}
			if (text.Contains("jumpscare"))
			{
				totalJumpscares++;
			}
			history.Add(new MimicEncounterRecord
			{
				utc = utc,
				eventType = text,
				note = (note ?? "")
			});
			if (history.Count > 250)
			{
				history.RemoveAt(0);
			}
		}
	}
	[Serializable]
	public sealed class MimicLearning
	{
		public int version = 1;

		public int sessions;

		public List<float> movementGaps = new List<float>();

		public List<float> walkingBursts = new List<float>();

		public List<float> pauses = new List<float>();

		public List<float> turns = new List<float>();

		public List<float> directionChanges = new List<float>();

		public List<string> observations = new List<string>();

		[NonSerialized]
		private Vector3 _lastPosition;

		[NonSerialized]
		private Vector3 _lastForward;

		[NonSerialized]
		private float _lastSampleAt;

		[NonSerialized]
		private float _lastMovingAt;

		[NonSerialized]
		private bool _initialized;

		[NonSerialized]
		private bool _wasMoving;

		public void BeginSession()
		{
			sessions++;
			_initialized = false;
		}

		public void Observe(Vector3 position, Vector3 forward, float now)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: 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_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			if (!_initialized)
			{
				_lastPosition = position;
				_lastForward = forward;
				_lastSampleAt = now;
				_lastMovingAt = now;
				_initialized = true;
				return;
			}
			float num = Mathf.Clamp(now - _lastSampleAt, 0f, 5f);
			if (!(num <= 0.001f))
			{
				float num2 = Vector3.Distance(position, _lastPosition) / num;
				bool flag = num2 > 0.12f;
				Add(movementGaps, num, 80);
				if (flag)
				{
					Add(walkingBursts, num2, 80);
				}
				if (_wasMoving && !flag)
				{
					Add(pauses, Mathf.Max(0f, now - _lastMovingAt), 80);
					Add(observations, "pause:" + (now - _lastMovingAt).ToString("F2"), 150);
				}
				if (flag && !_wasMoving)
				{
					_lastMovingAt = now;
					Add(observations, "move-start:" + now.ToString("F2"), 150);
				}
				float num3 = Vector3.Angle(_lastForward, forward);
				if (num3 >= 12f)
				{
					Add(turns, num3, 80);
				}
				Vector3 val = position - _lastPosition;
				if (((Vector3)(ref val)).sqrMagnitude > 0.02f && flag && Vector3.Dot(((Vector3)(ref val)).normalized, forward) < -0.1f)
				{
					Add(directionChanges, num3, 80);
				}
				if (flag)
				{
					_lastMovingAt = now;
				}
				_wasMoving = flag;
				_lastPosition = position;
				_lastForward = forward;
				_lastSampleAt = now;
			}
		}

		public float AverageSpeed()
		{
			return Average(walkingBursts);
		}

		public float AveragePause()
		{
			return Average(pauses);
		}

		public float AverageTurn()
		{
			return Average(turns);
		}

		private static void Add(List<float> list, float value, int max)
		{
			list.Add(value);
			if (list.Count > max)
			{
				list.RemoveAt(0);
			}
		}

		private static void Add(List<string> list, string value, int max)
		{
			list.Add(value);
			if (list.Count > max)
			{
				list.RemoveAt(0);
			}
		}

		private static float Average(List<float> list)
		{
			if (list == null || list.Count == 0)
			{
				return 0f;
			}
			float num = 0f;
			foreach (float item in list)
			{
				num += item;
			}
			return num / (float)list.Count;
		}
	}
	internal static class MimicPathfinder
	{
		public static bool TryFindWaypoint(Vector3 start, Vector3 target, float clearance, out Vector3 waypoint)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: 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_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: 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_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: 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_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_01af: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01de: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0204: Unknown result type (might be due to invalid IL or missing references)
			//IL_0209: Unknown result type (might be due to invalid IL or missing references)
			//IL_020e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0210: Unknown result type (might be due to invalid IL or missing references)
			//IL_0212: Unknown result type (might be due to invalid IL or missing references)
			//IL_021c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0221: Unknown result type (might be due to invalid IL or missing references)
			//IL_0226: Unknown result type (might be due to invalid IL or missing references)
			//IL_0228: Unknown result type (might be due to invalid IL or missing references)
			//IL_022a: Unknown result type (might be due to invalid IL or missing references)
			//IL_022c: Unknown result type (might be due to invalid IL or missing references)
			//IL_022e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0233: Unknown result type (might be due to invalid IL or missing references)
			//IL_0237: Unknown result type (might be due to invalid IL or missing references)
			//IL_023e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0240: Unknown result type (might be due to invalid IL or missing references)
			//IL_0253: Unknown result type (might be due to invalid IL or missing references)
			//IL_0254: Unknown result type (might be due to invalid IL or missing references)
			//IL_0259: Unknown result type (might be due to invalid IL or missing references)
			//IL_025e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0260: Unknown result type (might be due to invalid IL or missing references)
			//IL_0265: Unknown result type (might be due to invalid IL or missing references)
			//IL_026a: Unknown result type (might be due to invalid IL or missing references)
			//IL_026f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0283: Unknown result type (might be due to invalid IL or missing references)
			//IL_0285: Unknown result type (might be due to invalid IL or missing references)
			//IL_028a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0291: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02da: Unknown result type (might be due to invalid IL or missing references)
			waypoint = target;
			Vector3 val = target - start;
			val.y = 0f;
			float magnitude = ((Vector3)(ref val)).magnitude;
			if (magnitude < 1.25f)
			{
				return false;
			}
			Vector3 val2 = val / magnitude;
			Vector3 val3 = start + Vector3.up * 1.15f;
			Vector3 val4 = target + Vector3.up * 1f;
			Vector3 val5 = val4 - val3;
			RaycastHit val6 = default(RaycastHit);
			if (!Physics.Raycast(val3, ((Vector3)(ref val5)).normalized, ref val6, Vector3.Distance(val3, val4), -1, (QueryTriggerInteraction)1))
			{
				return false;
			}
			val5 = Vector3.Cross(Vector3.up, val2);
			Vector3 normalized = ((Vector3)(ref val5)).normalized;
			float num = Mathf.Clamp(clearance, 0.65f, 3.5f);
			Vector3 point = ((RaycastHit)(ref val6)).point;
			Vector3[] array = (Vector3[])(object)new Vector3[5]
			{
				point + normalized * num,
				point - normalized * num,
				point + normalized * (num * 1.65f),
				point - normalized * (num * 1.65f),
				point + ((RaycastHit)(ref val6)).normal * num
			};
			float num2 = float.MaxValue;
			bool result = false;
			RaycastHit val8 = default(RaycastHit);
			RaycastHit val11 = default(RaycastHit);
			for (int i = 0; i < array.Length; i++)
			{
				Vector3 val7 = array[i];
				if (!Physics.Raycast(val7 + Vector3.up * 2.2f, Vector3.down, ref val8, 5f, -1, (QueryTriggerInteraction)1))
				{
					continue;
				}
				val7 = ((RaycastHit)(ref val8)).point + Vector3.up * 0.08f;
				if (Vector3.Distance(start, val7) < 0.8f || Vector3.Distance(val7, target) < 0.8f || Physics.CheckSphere(val7 + Vector3.up * 0.75f, 0.28f, -1, (QueryTriggerInteraction)1))
				{
					continue;
				}
				Vector3 val9 = start + Vector3.up * 1f;
				Vector3 val10 = val7 + Vector3.up * 1f;
				val5 = val10 - val9;
				if (!Physics.Raycast(val9, ((Vector3)(ref val5)).normalized, ref val11, Vector3.Distance(val9, val10), -1, (QueryTriggerInteraction)1))
				{
					Vector3 val12 = target + Vector3.up - (val7 + Vector3.up);
					float magnitude2 = ((Vector3)(ref val12)).magnitude;
					bool flag = magnitude2 < 0.2f || !Physics.Raycast(val7 + Vector3.up, ((Vector3)(ref val12)).normalized, ref val11, magnitude2, -1, (QueryTriggerInteraction)1);
					float num3 = Vector3.Distance(start, val7) + Vector3.Distance(val7, target) * (flag ? 0.18f : 0.45f);
					if (num3 < num2)
					{
						num2 = num3;
						waypoint = val7;
						result = true;
					}
				}
			}
			return result;
		}
	}
	public enum MimicBehaviorMode
	{
		AdaptiveStalker,
		Jumpscare,
		RuthlessAttacker,
		NonHostile
	}
	[Serializable]
	public sealed class MimicSettings
	{
		public int version = 1;

		public MimicBehaviorMode behaviorMode;

		public bool enabled;

		public bool stalkingEnabled = true;

		public bool attacksEnabled = true;

		public bool visualGlitchesEnabled;

		public bool learningEnabled = true;

		public bool selfAwareEnabled;

		public float selfAwareMemorySeconds = 7f;

		public float selfAwareDistance = 20f;

		public float selfAwareLookDot = 0.84f;

		public bool pathfindingEnabled = true;

		public float pathRefreshInterval = 0.8f;

		public float obstacleClearance = 1.4f;

		public float waypointReachDistance = 1.1f;

		public float stalkDistance = 7f;

		public float rushChance = 0.22f;

		public float attackCooldown = 4f;

		public float jumpscareCooldown = 30f;

		public void ClampValues()
		{
			stalkDistance = Clamp(stalkDistance, 2f, 25f);
			rushChance = Clamp(rushChance, 0f, 1f);
			attackCooldown = Clamp(attackCooldown, 0.5f, 60f);
			jumpscareCooldown = Clamp(jumpscareCooldown, 1f, 300f);
			pathRefreshInterval = Clamp(pathRefreshInterval, 0.25f, 3f);
			obstacleClearance = Clamp(obstacleClearance, 0.65f, 3.5f);
			waypointReachDistance = Clamp(waypointReachDistance, 0.5f, 2.5f);
			selfAwareMemorySeconds = Clamp(selfAwareMemorySeconds, 1f, 30f);
			selfAwareDistance = Clamp(selfAwareDistance, 5f, 35f);
			selfAwareLookDot = Clamp(selfAwareLookDot, 0.5f, 0.98f);
		}

		private static float Clamp(float v, float min, float max)
		{
			if (!(v < min))
			{
				if (!(v > max))
				{
					return v;
				}
				return max;
			}
			return min;
		}
	}
	public sealed class Mod : MelonMod
	{
		private MimicAI _ai;

		private MimicDataManager _data;

		private float _nextSaveAt;

		private bool _menuCreated;

		public override void OnInitializeMelon()
		{
			_data = new MimicDataManager(((MelonBase)this).LoggerInstance);
			_data.Load();
			if (_data.Learning != null)
			{
				_data.Learning.BeginSession();
			}
			_ai = new MimicAI(((MelonBase)this).LoggerInstance);
			ApplySettingsToAI();
			((MelonBase)this).LoggerInstance.Msg("Mimic 0.6.0 merged build initialized. Microphone features are not included.");
		}

		public override void OnLateInitializeMelon()
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			if (!_menuCreated && _data != null)
			{
				_menuCreated = true;
				Page root = Page.Root.CreatePage("Mimic", Color.cyan, 0, true);
				BuildMainPage(root);
				BuildBehaviorPages(root);
				BuildPathfindingPage(root);
				BuildLearningPage(root);
				BuildDiagnosticsPage(root);
				((MelonBase)this).LoggerInstance.Msg("Mimic 0.6.0 merged BoneMenu created: AI, behavior, pathfinding, learning, diagnostics. Voice/TTS and microphone features are removed.");
			}
		}

		private void BuildMainPage(Page root)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: 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_0152: Unknown result type (might be due to invalid IL or missing references)
			Page obj = root.CreatePage("AI Control", Color.cyan, 0, true);
			obj.CreateBool("Mimic AI Enabled", Color.cyan, _data.Settings.enabled, (Action<bool>)delegate(bool value)
			{
				_data.Settings.enabled = value;
				ApplySettingsToAI();
				Save();
			});
			obj.CreateEnum("Behavior Mode", Color.cyan, (Enum)_data.Settings.behaviorMode, (Action<Enum>)delegate(Enum value)
			{
				_data.Settings.behaviorMode = (MimicBehaviorMode)(object)value;
				ApplySettingsToAI();
				Save();
			});
			obj.CreateFunction("Refresh Existing Doppel Bots", Color.white, (Action)delegate
			{
				_ai?.RefreshBots();
				((MelonBase)this).LoggerInstance.Msg("Requested a refresh of existing Doppel bots.");
			});
			obj.CreateFunction("Reapply Settings", Color.white, (Action)delegate
			{
				ApplySettingsToAI();
				Save();
				((MelonBase)this).LoggerInstance.Msg("Mimic settings reapplied.");
			});
			obj.CreateFunction("Save All Data Now", Color.green, (Action)Save);
			Page obj2 = obj.CreatePage("Quick Profiles", Color.cyan, 0, true);
			obj2.CreateFunction("Balanced Stalker", Color.cyan, (Action)delegate
			{
				ApplyProfile(MimicBehaviorMode.AdaptiveStalker, stalking: true, attacks: true, glitches: false, learning: true, 7f, 0.22f, 4f, 30f);
			});
			obj2.CreateFunction("Patient / Less Aggressive", Color.cyan, (Action)delegate
			{
				ApplyProfile(MimicBehaviorMode.AdaptiveStalker, stalking: true, attacks: false, glitches: false, learning: true, 10f, 0.08f, 7f, 45f);
			});
			obj2.CreateFunction("Aggressive Pursuer", Color.red, (Action)delegate
			{
				ApplyProfile(MimicBehaviorMode.RuthlessAttacker, stalking: true, attacks: true, glitches: false, learning: true, 5f, 0.55f, 2f, 20f);
			});
			obj2.CreateFunction("Jumpscare Focus", Color.magenta, (Action)delegate
			{
				ApplyProfile(MimicBehaviorMode.Jumpscare, stalking: true, attacks: false, glitches: true, learning: true, 7f, 0.15f, 4f, 18f);
			});
			obj2.CreateFunction("Non-Hostile Observer", Color.white, (Action)delegate
			{
				ApplyProfile(MimicBehaviorMode.NonHostile, stalking: false, attacks: true, glitches: false, learning: true, 9f, 0f, 4f, 30f);
			});
		}

		private void BuildBehaviorPages(Page root)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: 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_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: 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_0126: 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_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0220: Unknown result type (might be due to invalid IL or missing references)
			Page obj = root.CreatePage("Behavior Tuning", Color.cyan, 0, true);
			Page obj2 = obj.CreatePage("Stalking & Movement", Color.cyan, 0, true);
			obj2.CreateBool("Stalking / Cover Enabled", Color.cyan, _data.Settings.stalkingEnabled, (Action<bool>)delegate(bool value)
			{
				_data.Settings.stalkingEnabled = value;
				ApplySettingsToAI();
				Save();
			});
			obj2.CreateFunction("Increase Stalk Distance (+1m)", Color.cyan, (Action)delegate
			{
				ChangeFloat("stalk distance", 1f, 2f, 25f, delegate(float value)
				{
					_data.Settings.stalkDistance = value;
				}, () => _data.Settings.stalkDistance);
			});
			obj2.CreateFunction("Decrease Stalk Distance (-1m)", Color.cyan, (Action)delegate
			{
				ChangeFloat("stalk distance", -1f, 2f, 25f, delegate(float value)
				{
					_data.Settings.stalkDistance = value;
				}, () => _data.Settings.stalkDistance);
			});
			obj2.CreateFunction("Increase Rush Chance (+5%)", Color.cyan, (Action)delegate
			{
				ChangeFloat("rush chance", 0.05f, 0f, 1f, delegate(float value)
				{
					_data.Settings.rushChance = value;
				}, () => _data.Settings.rushChance, percent: true);
			});
			obj2.CreateFunction("Decrease Rush Chance (-5%)", Color.cyan, (Action)delegate
			{
				ChangeFloat("rush chance", -0.05f, 0f, 1f, delegate(float value)
				{
					_data.Settings.rushChance = value;
				}, () => _data.Settings.rushChance, percent: true);
			});
			obj2.CreateFunction("Show Movement Tuning", Color.white, (Action)delegate
			{
				((MelonBase)this).LoggerInstance.Msg("Stalk distance=" + _data.Settings.stalkDistance.ToString("F1") + "m; rush chance=" + (_data.Settings.rushChance * 100f).ToString("F0") + "%.");
			});
			Page obj3 = obj.CreatePage("Combat & Cooldowns", Color.red, 0, true);
			obj3.CreateBool("Close-Range Attacks Enabled", Color.red, _data.Settings.attacksEnabled, (Action<bool>)delegate(bool value)
			{
				_data.Settings.attacksEnabled = value;
				ApplySettingsToAI();
				Save();
			});
			obj3.CreateFunction("Faster Attacks (-0.5s cooldown)", Color.red, (Action)delegate
			{
				ChangeFloat("attack cooldown", -0.5f, 0.5f, 60f, delegate(float value)
				{
					_data.Settings.attackCooldown = value;
				}, () => _data.Settings.attackCooldown);
			});
			obj3.CreateFunction("Slower Attacks (+0.5s cooldown)", Color.red, (Action)delegate
			{
				ChangeFloat("attack cooldown", 0.5f, 0.5f, 60f, delegate(float value)
				{
					_data.Settings.attackCooldown = value;
				}, () => _data.Settings.attackCooldown);
			});
			obj3.CreateFunction("Shorter Jumpscare Cooldown (-5s)", Color.magenta, (Action)delegate
			{
				ChangeFloat("jumpscare cooldown", -5f, 1f, 300f, delegate(float value)
				{
					_data.Settings.jumpscareCooldown = value;
				}, () => _data.Settings.jumpscareCooldown);
			});
			obj3.CreateFunction("Longer Jumpscare Cooldown (+5s)", Color.magenta, (Action)delegate
			{
				ChangeFloat("jumpscare cooldown", 5f, 1f, 300f, delegate(float value)
				{
					_data.Settings.jumpscareCooldown = value;
				}, () => _data.Settings.jumpscareCooldown);
			});
			obj3.CreateFunction("Show Combat Tuning", Color.white, (Action)delegate
			{
				((MelonBase)this).LoggerInstance.Msg("Attacks=" + _data.Settings.attacksEnabled + "; attack cooldown=" + _data.Settings.attackCooldown.ToString("F1") + "s; jumpscare cooldown=" + _data.Settings.jumpscareCooldown.ToString("F1") + "s.");
			});
			Page obj4 = obj.CreatePage("Experimental", Color.magenta, 0, true);
			obj4.CreateBool("Self-Aware Mode", Color.magenta, _data.Settings.selfAwareEnabled, (Action<bool>)delegate(bool value)
			{
				_data.Settings.selfAwareEnabled = value;
				ApplySettingsToAI();
				Save();
			});
			obj4.CreateBool("Visual Glitches", Color.magenta, _data.Settings.visualGlitchesEnabled, (Action<bool>)delegate(bool value)
			{
				_data.Settings.visualGlitchesEnabled = value;
				ApplySettingsToAI();
				Save();
			});
			obj4.CreateFunction("Reset Experimental Toggles", Color.white, (Action)delegate
			{
				_data.Settings.selfAwareEnabled = false;
				_data.Settings.visualGlitchesEnabled = false;
				ApplySettingsToAI();
				Save();
				((MelonBase)this).LoggerInstance.Msg("Self-aware mode and visual glitches disabled.");
			});
		}

		private void BuildPathfindingPage(Page root)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: 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_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			Page obj = root.CreatePage("Pathfinding & Navigation", Color.cyan, 0, true);
			obj.CreateBool("Obstacle Waypoint Pathfinding", Color.cyan, _data.Settings.pathfindingEnabled, (Action<bool>)delegate(bool value)
			{
				_data.Settings.pathfindingEnabled = value;
				ApplySettingsToAI();
				Save();
				((MelonBase)this).LoggerInstance.Msg("Mimic waypoint pathfinding " + (value ? "enabled" : "disabled") + ".");
			});
			obj.CreateFunction("Faster Path Updates (-0.1s)", Color.cyan, (Action)delegate
			{
				ChangeFloat("path refresh interval", -0.1f, 0.25f, 3f, delegate(float value)
				{
					_data.Settings.pathRefreshInterval = value;
				}, () => _data.Settings.pathRefreshInterval);
			});
			obj.CreateFunction("Slower Path Updates (+0.1s)", Color.cyan, (Action)delegate
			{
				ChangeFloat("path refresh interval", 0.1f, 0.25f, 3f, delegate(float value)
				{
					_data.Settings.pathRefreshInterval = value;
				}, () => _data.Settings.pathRefreshInterval);
			});
			obj.CreateFunction("Increase Obstacle Clearance (+0.2m)", Color.cyan, (Action)delegate
			{
				ChangeFloat("obstacle clearance", 0.2f, 0.65f, 3.5f, delegate(float value)
				{
					_data.Settings.obstacleClearance = value;
				}, () => _data.Settings.obstacleClearance);
			});
			obj.CreateFunction("Decrease Obstacle Clearance (-0.2m)", Color.cyan, (Action)delegate
			{
				ChangeFloat("obstacle clearance", -0.2f, 0.65f, 3.5f, delegate(float value)
				{
					_data.Settings.obstacleClearance = value;
				}, () => _data.Settings.obstacleClearance);
			});
			obj.CreateFunction("Increase Waypoint Reach Radius (+0.2m)", Color.cyan, (Action)delegate
			{
				ChangeFloat("waypoint reach distance", 0.2f, 0.5f, 2.5f, delegate(float value)
				{
					_data.Settings.waypointReachDistance = value;
				}, () => _data.Settings.waypointReachDistance);
			});
			obj.CreateFunction("Decrease Waypoint Reach Radius (-0.2m)", Color.cyan, (Action)delegate
			{
				ChangeFloat("waypoint reach distance", -0.2f, 0.5f, 2.5f, delegate(float value)
				{
					_data.Settings.waypointReachDistance = value;
				}, () => _data.Settings.waypointReachDistance);
			});
			obj.CreateFunction("Show Navigation Settings", Color.white, (Action)delegate
			{
				((MelonBase)this).LoggerInstance.Msg("Pathfinding=" + _data.Settings.pathfindingEnabled + "; refresh=" + _data.Settings.pathRefreshInterval.ToString("F2") + "s; clearance=" + _data.Settings.obstacleClearance.ToString("F1") + "m; waypoint reach=" + _data.Settings.waypointReachDistance.ToString("F1") + "m.");
			});
		}

		private void BuildLearningPage(Page root)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: 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_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			Page obj = root.CreatePage("Learning & Memory", Color.cyan, 0, true);
			obj.CreateBool("Player Learning Enabled", Color.cyan, _data.Settings.learningEnabled, (Action<bool>)delegate(bool value)
			{
				_data.Settings.learningEnabled = value;
				ApplySettingsToAI();
				Save();
			});
			obj.CreateFunction("Show Learning Statistics", Color.white, (Action)PrintLearningStats);
			obj.CreateFunction("Save Learning & Settings", Color.green, (Action)Save);
			obj.CreateFunction("Forget Learned Movement History", Color.red, (Action)delegate
			{
				_data.Learning.movementGaps.Clear();
				_data.Learning.walkingBursts.Clear();
				_data.Learning.pauses.Clear();
				_data.Learning.turns.Clear();
				_data.Learning.directionChanges.Clear();
				_data.Learning.observations.Clear();
				_data.Learning.sessions = 0;
				Save();
				((MelonBase)this).LoggerInstance.Msg("Mimic movement history cleared. Encounter history was preserved.");
			});
			obj.CreateFunction("Forget Encounter History", Color.red, (Action)delegate
			{
				_data.Encounters.history.Clear();
				_data.Encounters.totalEncounters = 0;
				_data.Encounters.totalRushes = 0;
				_data.Encounters.totalAttacks = 0;
				_data.Encounters.totalJumpscares = 0;
				_data.Encounters.lastEncounterUtc = string.Empty;
				Save();
				((MelonBase)this).LoggerInstance.Msg("Mimic encounter history cleared. Movement learning was preserved.");
			});
		}

		private void BuildDiagnosticsPage(Page root)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: 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_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			Page obj = root.CreatePage("Diagnostics & Tools", Color.white, 0, true);
			obj.CreateFunction("Refresh Existing Doppel Bots", Color.white, (Action)delegate
			{
				_ai?.RefreshBots();
			});
			obj.CreateFunction("Show Encounter Counts", Color.white, (Action)delegate
			{
				((MelonBase)this).LoggerInstance.Msg("Encounters=" + _data.Encounters.totalEncounters + ", rushes=" + _data.Encounters.totalRushes + ", attacks=" + _data.Encounters.totalAttacks + ", jumpscares=" + _data.Encounters.totalJumpscares);
			});
			obj.CreateFunction("Print Data Directory", Color.white, (Action)delegate
			{
				((MelonBase)this).LoggerInstance.Msg("Mimic data path: " + _data.DirectoryPath);
			});
			obj.CreateFunction("Print Current Settings", Color.white, (Action)PrintSettings);
			obj.CreateFunction("Save All JSON Files", Color.green, (Action)Save);
			obj.CreateFunction("Reapply Settings to AI", Color.cyan, (Action)ApplySettingsToAI);
		}

		private void ApplyProfile(MimicBehaviorMode mode, bool stalking, bool attacks, bool glitches, bool learning, float stalkDistance, float rushChance, float attackCooldown, float jumpscareCooldown)
		{
			MimicSettings settings = _data.Settings;
			settings.behaviorMode = mode;
			settings.enabled = true;
			settings.stalkingEnabled = stalking;
			settings.attacksEnabled = attacks;
			settings.visualGlitchesEnabled = glitches;
			settings.learningEnabled = learning;
			settings.stalkDistance = stalkDistance;
			settings.rushChance = rushChance;
			settings.attackCooldown = attackCooldown;
			settings.jumpscareCooldown = jumpscareCooldown;
			ApplySettingsToAI();
			Save();
			((MelonBase)this).LoggerInstance.Msg("Applied Mimic profile: " + mode.ToString() + ". Review the Behavior Tuning pages to customize it.");
		}

		private void ChangeFloat(string label, float delta, float min, float max, Action<float> setter, Func<float> getter, bool percent = false)
		{
			if (_data != null)
			{
				float num = Mathf.Clamp(getter() + delta, min, max);
				setter(num);
				_data.Settings.ClampValues();
				ApplySettingsToAI();
				Save();
				((MelonBase)this).LoggerInstance.Msg("Mimic " + label + " set to " + (percent ? ((num * 100f).ToString("F0") + "%") : num.ToString("F2")) + ".");
			}
		}

		private void PrintLearningStats()
		{
			MimicLearning learning = _data.Learning;
			((MelonBase)this).LoggerInstance.Msg("Mimic learning: sessions=" + learning.sessions + ", average movement speed=" + learning.AverageSpeed().ToString("F2") + ", average pause=" + learning.AveragePause().ToString("F2") + "s, average turn=" + learning.AverageTurn().ToString("F1") + " degrees, movement samples=" + learning.walkingBursts.Count + ", observations=" + learning.observations.Count + ". Data: " + _data.DirectoryPath);
		}

		private void PrintSettings()
		{
			MimicSettings settings = _data.Settings;
			((MelonBase)this).LoggerInstance.Msg("Mimic settings: enabled=" + settings.enabled + ", mode=" + settings.behaviorMode.ToString() + ", stalking=" + settings.stalkingEnabled + ", attacks=" + settings.attacksEnabled + ", selfAware=" + settings.selfAwareEnabled + ", visualGlitches=" + settings.visualGlitchesEnabled + ", learning=" + settings.learningEnabled + ", stalkDistance=" + settings.stalkDistance.ToString("F1") + ", rushChance=" + (settings.rushChance * 100f).ToString("F0") + "%, attackCooldown=" + settings.attackCooldown.ToString("F1") + "s, jumpscareCooldown=" + settings.jumpscareCooldown.ToString("F1") + "s.");
		}

		private void ApplySettingsToAI()
		{
			if (_ai != null && _data != null)
			{
				MimicSettings settings = _data.Settings;
				settings.ClampValues();
				_ai.Configure(settings, _data.Learning, _data.Encounters);
				bool attacksEnabled = settings.attacksEnabled && settings.behaviorMode != MimicBehaviorMode.NonHostile && settings.behaviorMode != MimicBehaviorMode.Jumpscare;
				bool coverEnabled = settings.stalkingEnabled && settings.behaviorMode != MimicBehaviorMode.RuthlessAttacker;
				_ai.SetEnabled(settings.enabled);
				_ai.SetCoverEnabled(coverEnabled);
				_ai.SetAttacksEnabled(attacksEnabled);
				_ai.SetSelfAware(settings.selfAwareEnabled);
				_ai.SetVisualGlitches(settings.visualGlitchesEnabled);
			}
		}

		private void Save()
		{
			if (_data != null)
			{
				_data.Settings.ClampValues();
				_data.SaveAll();
			}
		}

		public override void OnSceneWasLoaded(int buildIndex, string sceneName)
		{
			_ai?.NotifySceneLoaded(sceneName);
		}

		public override void OnUpdate()
		{
			_ai?.Update();
			if (_data != null && Time.unscaledTime >= _nextSaveAt)
			{
				_nextSaveAt = Time.unscaledTime + 30f;
				Save();
			}
		}

		public override void OnDeinitializeMelon()
		{
			Save();
			_ai?.Dispose();
			_ai = null;
			_data = null;
			((MelonBase)this).LoggerInstance.Msg("Mimic Mod shut down.");
		}
	}
}