Decompiled source of VepMod v1.0.3

VepMod.dll

Decompiled 2 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using Photon.Realtime;
using Photon.Voice;
using REPOLib.Objects.Sdk;
using TMPro;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.Animations;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using VepMod.Enemies.Whispral;
using VepMod.Patchs;
using VepMod.VepFramework;
using VepMod.VepFramework.Config;
using VepMod.VepFramework.Extensions;
using VepMod.VepFramework.Structures.FSM;
using VepMod.VepFramework.Structures.Range;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: IgnoresAccessChecksTo("")]
[assembly: AssemblyCompany("Vep")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+964f939a0a8b38515bbd611a6cc973183debaf02")]
[assembly: AssemblyProduct("VepMod")]
[assembly: AssemblyTitle("VepMod")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace VepMod
{
	public static class ConfigRanges
	{
		public static readonly RangeValue<float> Volume = RangeValue.Percentage();

		public static readonly RangeValue<int> SamplesPerPlayer = RangeValue.Int(5, 20, 20);

		public static readonly RangeValue<int> SamplingRate = RangeValue.Int(16000, 48000, 48000);

		public static readonly MinMaxRange<float> ShareDelay = MinMaxRange.Float(10f, 60f, 10f, 10f, 120f, 30f);

		public static readonly MinMaxRange<float> VoiceDelay = MinMaxRange.Float(6f, 30f, 8f, 6f, 30f, 15f);
	}
	[BepInPlugin("com.vep.vepMod", "VepMod", "1.0.2")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class VepMod : BaseUnityPlugin
	{
		private static Harmony _harmony;

		public static ConfigEntry<float> ConfigVoiceVolume;

		public static ConfigEntry<int> ConfigSamplingRate;

		public static BoundMinMaxRange<float> ShareDelay;

		public static ConfigEntry<int> ConfigSamplesPerPlayer;

		public static BoundMinMaxRange<float> VoiceDelay;

		public static ConfigEntry<bool> ConfigVoiceFilterEnabled;

		public static readonly Dictionary<string, ConfigEntry<bool>> EnemyConfigEntries = new Dictionary<string, ConfigEntry<bool>>();

		internal Harmony? Harmony { get; set; }

		private void Awake()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			_harmony = new Harmony("VepMod.Plugin");
			PreventDelete();
			InitConfig();
			_harmony.PatchAll();
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"{((BaseUnityPlugin)this).Info.Metadata.GUID} v{((BaseUnityPlugin)this).Info.Metadata.Version} has loaded!");
			((MonoBehaviour)this).StartCoroutine(DroidPrefabLoader.PreloadAsync(delegate(bool success)
			{
				if (success)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)"LostDroid prefab preloaded successfully.");
				}
				else
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)"LostDroid prefab preload failed - hallucinations may not work.");
				}
			}));
		}

		public void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Scene loaded: " + ((Scene)(ref scene)).name));
		}

		private void InitConfig()
		{
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Expected O, but got Unknown
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Initializing config for VepMod...");
			ConfigVoiceVolume = ((BaseUnityPlugin)this).Config.BindRange("General", "Volume", ConfigRanges.Volume, "Volume of the mimic voices.");
			ShareDelay = ((BaseUnityPlugin)this).Config.BindMinMax("Audio Sharing", "Share Min Delay", "Share Max Delay", ConfigRanges.ShareDelay, "Minimum time between sharing audio clips with other players.", "Maximum time between sharing audio clips with other players.");
			ConfigSamplesPerPlayer = ((BaseUnityPlugin)this).Config.BindRange("Audio Sharing", "Samples Per Player", ConfigRanges.SamplesPerPlayer, "Maximum number of audio samples stored per player.");
			VoiceDelay = ((BaseUnityPlugin)this).Config.BindMinMax("Voice Playback", "Voice Min Delay", "Voice Max Delay", ConfigRanges.VoiceDelay, "Minimum time between voice playback commands during Whispral debuff.", "Maximum time between voice playback commands during Whispral debuff.");
			ConfigVoiceFilterEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Voice Playback", "Voice Filter Enabled?", false, new ConfigDescription("Turning this will enable modifiable filters for which enemies can play back voices during the Whispral debuff.", (AcceptableValueBase)null, Array.Empty<object>()));
			ConfigSamplingRate = ((BaseUnityPlugin)this).Config.BindRange("Experimental", "Sampling Rate", ConfigRanges.SamplingRate, "Only change this value if the console gives you a warning about your microphone frequency not being supported.");
		}

		private void PreventDelete()
		{
			((Component)this).gameObject.transform.parent = null;
			((Object)((Component)this).gameObject).hideFlags = (HideFlags)61;
		}

		internal void Unpatch()
		{
			_harmony.UnpatchSelf();
		}
	}
}
namespace VepMod.VepFramework
{
	public sealed class VepLogger
	{
		private const string Prefix = "VepMod";

		private readonly ManualLogSource _log;

		public bool DebugEnabled { get; set; }

		private VepLogger(string className, bool debugEnabled = false)
		{
			_log = Logger.CreateLogSource("VepMod." + className);
			DebugEnabled = debugEnabled;
		}

		public static VepLogger Create<T>(bool debugEnabled = false)
		{
			return new VepLogger(typeof(T).Name, debugEnabled);
		}

		public static VepLogger Create(string className, bool debugEnabled = false)
		{
			return new VepLogger(className, debugEnabled);
		}

		public void Debug(string message)
		{
			if (DebugEnabled)
			{
				_log.LogDebug((object)message);
			}
		}

		public void Info(string message)
		{
			_log.LogInfo((object)message);
		}

		public void Warning(string message)
		{
			_log.LogWarning((object)message);
		}

		public void Error(string message)
		{
			_log.LogError((object)message);
		}
	}
}
namespace VepMod.VepFramework.Structures.Range
{
	public sealed class MinMaxRange<T> where T : struct, IComparable<T>
	{
		public RangeValue<T> MinRange { get; }

		public RangeValue<T> MaxRange { get; }

		public MinMaxRange(RangeValue<T> minRange, RangeValue<T> maxRange)
		{
			MinRange = minRange;
			MaxRange = maxRange;
		}

		public T GetMin(T minValue, T maxValue)
		{
			if (minValue.CompareTo(maxValue) > 0)
			{
				return maxValue;
			}
			return minValue;
		}

		public T GetMax(T minValue, T maxValue)
		{
			if (maxValue.CompareTo(minValue) < 0)
			{
				return minValue;
			}
			return maxValue;
		}
	}
	public static class MinMaxRange
	{
		public static MinMaxRange<float> Float(float minLower, float minUpper, float minDefault, float maxLower, float maxUpper, float maxDefault)
		{
			return new MinMaxRange<float>(RangeValue.Float(minLower, minUpper, minDefault), RangeValue.Float(maxLower, maxUpper, maxDefault));
		}
	}
	public sealed class RangeValue<T> where T : struct, IComparable<T>
	{
		public T Min { get; }

		public T Max { get; }

		public T Default { get; }

		public RangeValue(T min, T max, T defaultValue)
		{
			if (min.CompareTo(max) > 0)
			{
				throw new ArgumentException($"Min ({min}) cannot be greater than Max ({max})");
			}
			Min = min;
			Max = max;
			Default = Clamp(defaultValue);
		}

		public T Clamp(T value)
		{
			if (value.CompareTo(Min) < 0)
			{
				return Min;
			}
			if (value.CompareTo(Max) > 0)
			{
				return Max;
			}
			return value;
		}
	}
	public static class RangeValue
	{
		public static RangeValue<float> Float(float min, float max, float defaultValue)
		{
			return new RangeValue<float>(min, max, defaultValue);
		}

		public static RangeValue<int> Int(int min, int max, int defaultValue)
		{
			return new RangeValue<int>(min, max, defaultValue);
		}

		public static RangeValue<float> Percentage(float defaultValue = 1f)
		{
			return new RangeValue<float>(0f, 1f, defaultValue);
		}
	}
}
namespace VepMod.VepFramework.Structures.FSM
{
	public class StateMachineBase<TMachine, TStateId> where TMachine : StateMachineBase<TMachine, TStateId>
	{
		public class StateBase
		{
			public TMachine Machine { get; set; }

			public virtual void OnStateEnter(TStateId previous)
			{
			}

			public virtual void OnStateExit(TStateId next)
			{
			}

			public virtual void OnStateUpdate()
			{
			}
		}

		public class StateBaseTimed : StateBase
		{
			public float TimeElapsed { get; protected set; }

			public override void OnStateEnter(TStateId previous)
			{
				base.OnStateEnter(previous);
				TimeElapsed = 0f;
			}

			public override void OnStateUpdate()
			{
				base.OnStateUpdate();
				TimeElapsed += Time.deltaTime;
			}
		}

		public class StateBaseTransition : StateBaseTimed
		{
			public float Duration;

			public TStateId NextState;

			public StateBaseTransition(float duration, TStateId nextState)
			{
				Duration = duration;
				NextState = nextState;
			}

			public override void OnStateEnter(TStateId previous)
			{
				base.OnStateEnter(previous);
				if (Duration <= 0f)
				{
					base.Machine.NextStateStateId = NextState;
				}
			}

			public override void OnStateUpdate()
			{
				base.OnStateUpdate();
				if (base.TimeElapsed >= Duration)
				{
					base.Machine.NextStateStateId = NextState;
				}
			}
		}

		private readonly StateBase Default = new StateBase();

		private readonly Dictionary<TStateId, StateBase> states = new Dictionary<TStateId, StateBase>();

		private StateBase _currentStateBaseRunning;

		public TStateId CurrentStateStateId { get; private set; }

		public TStateId NextStateStateId { get; set; }

		public StateMachineBase(TStateId defaultStateId)
		{
			CurrentStateStateId = defaultStateId;
			NextStateStateId = defaultStateId;
		}

		public void AddState(TStateId stateId, StateBase stateBase)
		{
			stateBase.Machine = this as TMachine;
			if (states.ContainsKey(stateId))
			{
				Debug.LogWarning((object)$"[FSM] Fsm already defines a state with key {stateId}, it will be overidden");
			}
			states[stateId] = stateBase;
		}

		public StateBase GetState(TStateId stateId)
		{
			if (!states.TryGetValue(stateId, out StateBase value))
			{
				return Default;
			}
			return value;
		}

		public T GetStateTyped<T>(TStateId stateId) where T : StateBase
		{
			return GetState(stateId) as T;
		}

		private void RefreshStatesIO()
		{
			for (StateBase state = GetState(NextStateStateId); state != _currentStateBaseRunning; state = GetState(NextStateStateId))
			{
				TStateId nextStateStateId = NextStateStateId;
				_currentStateBaseRunning?.OnStateExit(nextStateStateId);
				if (!states.ContainsKey(nextStateStateId))
				{
					Debug.LogWarning((object)$"[FSM] Fsm does not define any state with key {nextStateStateId}, it will play default state");
				}
				_currentStateBaseRunning = GetState(nextStateStateId);
				_currentStateBaseRunning?.OnStateEnter(CurrentStateStateId);
				CurrentStateStateId = nextStateStateId;
			}
		}

		public void Update()
		{
			RefreshStatesIO();
			_currentStateBaseRunning?.OnStateUpdate();
			RefreshStatesIO();
		}
	}
	public abstract class StateMachineComponent<TOwner, TStateId> : MonoBehaviour where TOwner : StateMachineComponent<TOwner, TStateId>
	{
		protected sealed class StateMachine : StateMachineBase<StateMachine, TStateId>
		{
			public TOwner Owner { get; }

			public StateMachine(TOwner owner, TStateId defaultKey)
				: base(defaultKey)
			{
				Owner = owner;
			}
		}

		protected StateMachine Fsm;

		protected abstract TStateId DefaultState { get; }

		protected virtual void Awake()
		{
			Fsm = new StateMachine(this as TOwner, DefaultState);
		}

		protected virtual void Update()
		{
			Fsm.Update();
		}
	}
}
namespace VepMod.VepFramework.Extensions
{
	public static class TaskExtensions
	{
		[CompilerGenerated]
		private sealed class <AsCoroutine>d__0 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public Task task;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <AsCoroutine>d__0(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					break;
				case 1:
					<>1__state = -1;
					break;
				}
				if (!task.IsCompleted)
				{
					<>2__current = null;
					<>1__state = 1;
					return true;
				}
				if (task.Exception != null)
				{
					throw task.Exception;
				}
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[IteratorStateMachine(typeof(<AsCoroutine>d__0))]
		public static IEnumerator AsCoroutine(this Task task)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <AsCoroutine>d__0(0)
			{
				task = task
			};
		}
	}
}
namespace VepMod.VepFramework.Config
{
	public sealed class BoundMinMaxRange<T> where T : struct, IComparable<T>
	{
		private readonly MinMaxRange<T> _range;

		private readonly ConfigEntry<T> _minEntry;

		private readonly ConfigEntry<T> _maxEntry;

		public T Min => _range.GetMin(_minEntry.Value, _maxEntry.Value);

		public T Max => _range.GetMax(_minEntry.Value, _maxEntry.Value);

		public BoundMinMaxRange(MinMaxRange<T> range, ConfigEntry<T> minEntry, ConfigEntry<T> maxEntry)
		{
			_range = range;
			_minEntry = minEntry;
			_maxEntry = maxEntry;
		}
	}
	public static class ConfigExtensions
	{
		private static AcceptableValueRange<T> ToAcceptableValueRange<T>(this RangeValue<T> range) where T : struct, IComparable, IComparable<T>
		{
			return new AcceptableValueRange<T>(range.Min, range.Max);
		}

		private static ConfigDescription ToConfigDescription<T>(this RangeValue<T> range, string description) where T : struct, IComparable, IComparable<T>
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Expected O, but got Unknown
			return new ConfigDescription(description, (AcceptableValueBase)(object)range.ToAcceptableValueRange(), Array.Empty<object>());
		}

		public static ConfigEntry<T> BindRange<T>(this ConfigFile config, string section, string key, RangeValue<T> range, string description) where T : struct, IComparable, IComparable<T>
		{
			return config.Bind<T>(section, key, range.Default, range.ToConfigDescription(description));
		}

		public static BoundMinMaxRange<T> BindMinMax<T>(this ConfigFile config, string section, string minKey, string maxKey, MinMaxRange<T> range, string minDescription, string maxDescription) where T : struct, IComparable, IComparable<T>
		{
			ConfigEntry<T> minEntry = config.Bind<T>(section, minKey, range.MinRange.Default, range.MinRange.ToConfigDescription(minDescription));
			ConfigEntry<T> maxEntry = config.Bind<T>(section, maxKey, range.MaxRange.Default, range.MaxRange.ToConfigDescription(maxDescription));
			return new BoundMinMaxRange<T>(range, minEntry, maxEntry);
		}
	}
}
namespace VepMod.Patchs
{
	[HarmonyPatch(typeof(EnemyDirector), "FirstSpawnPointAdd")]
	public class EnemyLoggerPatch
	{
		private static readonly VepLogger LOG = VepLogger.Create<EnemyLoggerPatch>();

		[HarmonyPrefix]
		private static void Prefix(EnemyParent _enemyParent)
		{
			LOG.Info($"EnemyDirector.FirstSpawnPointAdd: {_enemyParent} added as first spawn point.");
		}
	}
	[HarmonyPatch(typeof(LocalVoiceFramed<short>), "PushDataAsync")]
	internal class LocalVoiceFramedPatch
	{
		private static readonly VepLogger LOG = VepLogger.Create<LocalVoiceFramedPatch>();

		private static void Prefix(short[] buf, LocalVoiceFramed<short> __instance)
		{
			VepFinder.EnsureInitialized();
			if (!IsNotReady())
			{
				VepFinder.LocalMimics.ProcessVoiceData(buf);
			}
		}

		private static bool IsNotReady()
		{
			bool flag = !PhotonNetwork.IsConnectedAndReady;
			WhispralMimics localMimics = VepFinder.LocalMimics;
			bool flag2 = (Object)(object)localMimics == (Object)null;
			if (flag || flag2)
			{
				return true;
			}
			bool flag3 = (Object)(object)((Component)localMimics).gameObject == (Object)null;
			bool flag4 = (Object)(object)localMimics.PhotonView == (Object)null || !localMimics.PhotonView.IsMine;
			return flag3 || flag4;
		}
	}
	[HarmonyPatch(typeof(Materials))]
	internal static class MaterialsImpulsePatch
	{
		[HarmonyPrefix]
		[HarmonyPatch("Impulse")]
		private static bool Impulse_Prefix(Vector3 origin, bool footstep, HostType hostType)
		{
			//IL_000d: 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_0012: Invalid comparison between Unknown and I4
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			if (!footstep)
			{
				return true;
			}
			if ((int)hostType != 0 && (int)hostType != 1)
			{
				return true;
			}
			if (InvisiblePlayerDebuff.IsPositionNearHiddenPlayer(origin))
			{
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(PlayerAvatar), "Awake")]
	internal class PlayerAvatarPatch
	{
		private static readonly VepLogger LOG = VepLogger.Create<PlayerAvatarPatch>();

		private static void Postfix(PlayerAvatar __instance)
		{
			if (PhotonNetwork.IsConnectedAndReady)
			{
				WhispralMimics whispralMimics = ((Component)__instance).GetComponent<WhispralMimics>();
				if (!Object.op_Implicit((Object)(object)whispralMimics))
				{
					whispralMimics = ((Component)__instance).gameObject.AddComponent<WhispralMimics>();
					LOG.Debug("Added Mimics component to PlayerAvatar: " + ((Object)__instance).name);
				}
				else
				{
					LOG.Warning("PlayerAvatar: " + ((Object)__instance).name + " already has a WhispralMimics component.");
				}
				PhotonView component = ((Component)__instance).GetComponent<PhotonView>();
				if (!Object.op_Implicit((Object)(object)component) || !component.IsMine)
				{
					LOG.Warning("PhotonView is null or not owned by local player.");
					return;
				}
				VepFinder.LocalMimics = whispralMimics;
				LOG.Info("Set LocalMimics for local PlayerAvatar: " + ((Object)__instance).name);
			}
		}
	}
	[HarmonyPatch(typeof(PlayerController))]
	internal static class PlayerControllerPatch
	{
	}
	[HarmonyPatch(typeof(ValuableDirector), "Spawn")]
	public class ValuableLoggerPatch
	{
		[HarmonyPrefix]
		private static void Prefix(PrefabRef _valuable, ValuableVolume _volume, string _path)
		{
		}
	}
	public class VepFinder : MonoBehaviour
	{
		private static VepFinder _instance;

		private static bool _initialized;

		private static readonly VepLogger LOG = VepLogger.Create<VepFinder>();

		public static WhispralMimics LocalMimics { get; set; }

		private void OnDestroy()
		{
			if (_initialized)
			{
				LocalMimics = null;
				_instance = null;
				LOG.Info("VepFinder destroyed, clearing cache.");
			}
		}

		public static void EnsureInitialized()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)_instance))
			{
				_instance = new GameObject("VepFinder").AddComponent<VepFinder>();
				_initialized = true;
				Object.DontDestroyOnLoad((Object)(object)((Component)_instance).gameObject);
				Player localPlayer = PhotonNetwork.LocalPlayer;
				LOG.Info($"MimicsFinder initialized for Player {((localPlayer != null) ? localPlayer.ActorNumber : (-1))}");
			}
		}
	}
}
namespace VepMod.Enemies.Whispral
{
	public static class AudioFilters
	{
		private const float TwoPi = MathF.PI * 2f;

		private const float Int16MaxValue = 32768f;

		private const float AlienVibratoFrequency = 5f;

		private const float AlienVibratoDepth = 0.05f;

		private const float AlienRingModFrequency = 200f;

		private const float AlienRingModMix = 0.3f;

		public const float PitchShiftLow = 0.5f;

		public const float PitchShiftHigh = 1.2f;

		private const float DefaultLowPassCutoff = 4500f;

		public static float[] ApplyAlienFilter(float[] samples, int sampleRate)
		{
			float[] array = new float[samples.Length];
			for (int i = 0; i < samples.Length; i++)
			{
				float num = (float)i / (float)sampleRate;
				float num2 = 1f + Mathf.Sin(MathF.PI * 10f * num) * 0.05f;
				float num3 = (float)i * num2;
				int num4 = (int)num3;
				float num5 = num3 - (float)num4;
				float num6 = ((num4 + 1 >= samples.Length) ? ((num4 >= samples.Length) ? 0f : samples[num4]) : (samples[num4] * (1f - num5) + samples[num4 + 1] * num5));
				float num7 = Mathf.Sin(MathF.PI * 400f * num);
				float num8 = num6 * num7 * 0.3f;
				array[i] = Mathf.Clamp(num6 * 0.7f + num8, -1f, 1f);
			}
			return array;
		}

		public static float[] ApplyLowPassFilter(float[] samples, int sampleRate, float cutoffFrequency = 4500f)
		{
			float num = 1f / (MathF.PI * 2f * cutoffFrequency);
			float num2 = 1f / (float)sampleRate;
			float num3 = num2 / (num + num2);
			float[] array = new float[samples.Length];
			array[0] = samples[0];
			for (int i = 1; i < samples.Length; i++)
			{
				array[i] = array[i - 1] + num3 * (samples[i] - array[i - 1]);
			}
			float[] array2 = new float[samples.Length];
			array2[samples.Length - 1] = array[samples.Length - 1];
			for (int num4 = samples.Length - 2; num4 >= 0; num4--)
			{
				array2[num4] = array2[num4 + 1] + num3 * (array[num4] - array2[num4 + 1]);
			}
			return array2;
		}

		public static float[] ApplyPitchShift(float[] samples, float pitchFactor)
		{
			int num = (int)((float)samples.Length / pitchFactor);
			float[] array = new float[num];
			for (int i = 0; i < num; i++)
			{
				float num2 = (float)i * pitchFactor;
				int num3 = (int)num2;
				float num4 = num2 - (float)num3;
				if (num3 + 1 < samples.Length)
				{
					array[i] = samples[num3] * (1f - num4) + samples[num3 + 1] * num4;
				}
				else if (num3 < samples.Length)
				{
					array[i] = samples[num3];
				}
			}
			return array;
		}

		public static float[] ConvertBytesToFloats(byte[] byteArray)
		{
			int num = byteArray.Length / 2;
			float[] array = new float[num];
			for (int i = 0; i < num; i++)
			{
				short num2 = (short)(byteArray[i * 2] | (byteArray[i * 2 + 1] << 8));
				array[i] = (float)num2 / 32768f;
			}
			return array;
		}

		public static byte[] ConvertFloatsToBytes(float[] floatArray)
		{
			byte[] array = new byte[floatArray.Length * 2];
			for (int i = 0; i < floatArray.Length; i++)
			{
				short num = (short)(floatArray[i] * 32767f);
				array[i * 2] = (byte)((uint)num & 0xFFu);
				array[i * 2 + 1] = (byte)((uint)(num >> 8) & 0xFFu);
			}
			return array;
		}

		public static float[] ApplyFadeAndPadding(float[] samples, int sampleRate)
		{
			int num = (int)((float)sampleRate * 0.5f);
			int num2 = (int)((float)sampleRate * 0.02f);
			float[] array = new float[samples.Length + 2 * num];
			for (int i = 0; i < num; i++)
			{
				array[i] = 0f;
			}
			for (int j = 0; j < samples.Length; j++)
			{
				float num3 = 1f;
				if (j < num2)
				{
					num3 = (float)j / (float)num2;
				}
				else if (j >= samples.Length - num2)
				{
					num3 = (float)(samples.Length - j) / (float)num2;
				}
				array[j + num] = samples[j] * num3;
			}
			for (int k = samples.Length + num; k < array.Length; k++)
			{
				array[k] = 0f;
			}
			return array;
		}
	}
	public sealed class DilatedPupilsDebuff : MonoBehaviour
	{
		private const float PupilSizeMultiplier = 3f;

		private const int Priority = 5;

		private const float SpringSpeedIn = 10f;

		private const float SpringDampIn = 0.5f;

		private const float SpringSpeedOut = 5f;

		private const float SpringDampOut = 0.3f;

		private const float RefreshInterval = 0.1f;

		private static readonly VepLogger LOG = VepLogger.Create<DilatedPupilsDebuff>();

		private PlayerAvatar? playerAvatar;

		private float refreshTimer;

		public bool IsActive { get; private set; }

		private void Awake()
		{
			playerAvatar = ((Component)this).GetComponent<PlayerAvatar>();
		}

		private void Update()
		{
			if (IsActive && !((Object)(object)playerAvatar == (Object)null))
			{
				refreshTimer -= Time.deltaTime;
				if (refreshTimer <= 0f)
				{
					ApplyPupilEffect();
					refreshTimer = 0.1f;
				}
			}
		}

		public void ApplyDebuff(bool dilated)
		{
			IsActive = dilated;
			LOG.Debug($"Applying dilated pupils debuff: {dilated}");
			if (dilated)
			{
				refreshTimer = 0f;
				ApplyPupilEffect();
			}
		}

		private void ApplyPupilEffect()
		{
			if (!((Object)(object)playerAvatar == (Object)null))
			{
				playerAvatar.OverridePupilSize(3f, 5, 10f, 0.5f, 5f, 0.3f, 0.15f);
			}
		}
	}
	public sealed class DroidController : StateMachineComponent<DroidController, DroidController.StateId>
	{
		public enum StateId
		{
			Idle,
			Wander,
			Sprint,
			CheckMap,
			StalkApproach,
			StalkStare,
			StalkFlee
		}

		private sealed class IdleState : StateMachineBase<StateMachine, StateId>.StateBaseTimed
		{
			private const string ClipName = "LostDroidStand";

			private const float IdleLoopStart = 0f;

			private const float IdleLoopEnd = 4.5f;

			private const float BlendDelay = 0.3f;

			private const float MinIdleTime = 2f;

			private const float MaxIdleTime = 4f;

			private const float PrecomputeRetryInterval = 1f;

			private const float CheckMapChance = 0.25f;

			private Animator _animator;

			private bool _animatorTakenOver;

			private AnimationClip? _clip;

			private float _currentTime;

			private float _duration;

			private float _precomputeTimer;

			private GameObject? _targetObject;

			public override void OnStateEnter(StateId previous)
			{
				base.OnStateEnter(previous);
				_duration = Random.Range(2f, 4f);
				_precomputeTimer = 0f;
				_animatorTakenOver = false;
				base.Machine.Owner.ResetPath();
				base.Machine.Owner.HasChangedMovementState = false;
				_animator = base.Machine.Owner.Animator;
				if ((Object)(object)_animator != (Object)null)
				{
					_clip = DroidHelpers.GetAnimationClip(_animator, "LostDroidStand");
					if ((Object)(object)_clip != (Object)null)
					{
						_targetObject = ((Component)_animator).gameObject;
					}
				}
				base.Machine.Owner.StartPrecomputeDestination();
			}

			public override void OnStateUpdate()
			{
				base.OnStateUpdate();
				if (!_animatorTakenOver && (Object)(object)_clip != (Object)null && (Object)(object)_targetObject != (Object)null && base.TimeElapsed >= 0.3f)
				{
					((Behaviour)_animator).enabled = false;
					_currentTime = 0f;
					_animatorTakenOver = true;
				}
				if (_animatorTakenOver && (Object)(object)_clip != (Object)null && (Object)(object)_targetObject != (Object)null)
				{
					_currentTime += Time.deltaTime;
					if (_currentTime >= 4.5f)
					{
						_currentTime = 0f;
					}
					_clip.SampleAnimation(_targetObject, _currentTime);
				}
				if (!base.Machine.Owner.HasPrecomputedDestination)
				{
					_precomputeTimer -= Time.deltaTime;
					if (_precomputeTimer <= 0f)
					{
						base.Machine.Owner.StartPrecomputeDestination();
						_precomputeTimer = 1f;
					}
				}
				if (!(base.TimeElapsed >= _duration))
				{
					return;
				}
				float distanceToPlayer = base.Machine.Owner.GetDistanceToPlayer();
				if (distanceToPlayer > 15f && Random.value < 0.1f)
				{
					base.Machine.NextStateStateId = StateId.StalkApproach;
					return;
				}
				float value = Random.value;
				if (value < 0.25f)
				{
					base.Machine.NextStateStateId = StateId.CheckMap;
				}
				else
				{
					base.Machine.NextStateStateId = ((!(Random.value < 0.5f)) ? StateId.Wander : StateId.Sprint);
				}
			}

			public override void OnStateExit(StateId next)
			{
				base.OnStateExit(next);
				if ((Object)(object)_animator != (Object)null && next != StateId.CheckMap)
				{
					((Behaviour)_animator).enabled = true;
				}
			}
		}

		private abstract class MovementState : StateMachineBase<StateMachine, StateId>.StateBaseTimed
		{
			private const float SwitchCheckInterval = 1f;

			private const float SwitchChance = 0.2f;

			private const float PrecomputeForwardInterval = 0.5f;

			private float _duration;

			private float _nextSwitchCheck;

			private float _nextPrecomputeForward;

			protected abstract float MinDuration { get; }

			protected abstract float MaxDuration { get; }

			protected abstract float Speed { get; }

			protected abstract StateId SwitchTargetState { get; }

			protected abstract void SetMovementFlag(bool value);

			public override void OnStateEnter(StateId previous)
			{
				base.OnStateEnter(previous);
				_duration = Random.Range(MinDuration, MaxDuration);
				_nextSwitchCheck = 1f;
				_nextPrecomputeForward = 0.5f;
				if ((uint)(previous - 1) <= 1u)
				{
					base.Machine.Owner.TryExtendCurrentPath();
				}
				else if (!base.Machine.Owner.TrySetRandomDestination())
				{
					base.Machine.NextStateStateId = StateId.Idle;
					return;
				}
				base.Machine.Owner.SetSpeed(Speed);
				SetMovementFlag(value: true);
				base.Machine.Owner.StartPrecomputeForwardDestination();
			}

			public override void OnStateExit(StateId next)
			{
				base.OnStateExit(next);
				SetMovementFlag(value: false);
				if ((uint)(next - 1) > 1u)
				{
					base.Machine.Owner.ClearPrecomputedForwardDestination();
				}
			}

			public override void OnStateUpdate()
			{
				base.OnStateUpdate();
				if (base.Machine.Owner.HasReachedDestination() || base.TimeElapsed >= _duration)
				{
					base.Machine.NextStateStateId = StateId.Idle;
					return;
				}
				_nextPrecomputeForward -= Time.deltaTime;
				if (_nextPrecomputeForward <= 0f)
				{
					_nextPrecomputeForward = 0.5f;
					base.Machine.Owner.StartPrecomputeForwardDestination();
				}
				if (!base.Machine.Owner.HasChangedMovementState && base.TimeElapsed >= _nextSwitchCheck)
				{
					_nextSwitchCheck += 1f;
					if (Random.value < 0.2f)
					{
						base.Machine.Owner.HasChangedMovementState = true;
						base.Machine.NextStateStateId = SwitchTargetState;
					}
				}
			}
		}

		private sealed class WanderState : MovementState
		{
			protected override float MinDuration => 5f;

			protected override float MaxDuration => 15f;

			protected override float Speed => 2f;

			protected override StateId SwitchTargetState => StateId.Sprint;

			protected override void SetMovementFlag(bool value)
			{
				base.Machine.Owner.IsWalking = value;
			}
		}

		private sealed class SprintState : MovementState
		{
			protected override float MinDuration => 3f;

			protected override float MaxDuration => 8f;

			protected override float Speed => 5f;

			protected override StateId SwitchTargetState => StateId.Wander;

			protected override void SetMovementFlag(bool value)
			{
				base.Machine.Owner.IsSprinting = value;
			}
		}

		private sealed class CheckMapState : StateMachineBase<StateMachine, StateId>.StateBaseTimed
		{
			private enum Phase
			{
				Raise,
				Look,
				Lower
			}

			private const string ClipName = "LostDroidStand";

			private const float RaiseStartTime = 4.65f;

			private const float LookStartTime = 5.5f;

			private const float LookEndTime = 6.9333334f;

			private const float LowerEndTime = 7.15f;

			private const float MinLookDuration = 0.5f;

			private const float MaxLookDuration = 3f;

			private Animator? _animator;

			private AnimationClip? _clip;

			private Phase _currentPhase;

			private float _currentTime;

			private float _lookDuration;

			private float _lookTimer;

			private GameObject? _targetObject;

			public override void OnStateEnter(StateId previous)
			{
				base.OnStateEnter(previous);
				_animator = base.Machine.Owner.Animator;
				if ((Object)(object)_animator == (Object)null)
				{
					LOG.Warning("CheckMapState: Animator is null!");
					base.Machine.NextStateStateId = StateId.Idle;
					return;
				}
				_clip = DroidHelpers.GetAnimationClip(_animator, "LostDroidStand");
				if ((Object)(object)_clip == (Object)null)
				{
					LOG.Warning("CheckMapState: Clip 'LostDroidStand' not found!");
					base.Machine.NextStateStateId = StateId.Idle;
					return;
				}
				_targetObject = ((Component)_animator).gameObject;
				base.Machine.Owner.IsWalking = false;
				base.Machine.Owner.IsSprinting = false;
				base.Machine.Owner.ResetPath();
				((Behaviour)_animator).enabled = false;
				_lookDuration = Random.Range(0.5f, 3f);
				_lookTimer = 0f;
				_currentPhase = Phase.Raise;
				_currentTime = 4.65f;
				LOG.Debug($"CheckMapState: ENTER - Clip length={_clip.length}s, starting at {_currentTime}s");
				LOG.Debug($"CheckMapState: Thresholds - Raise={4.65f}s, Look={5.5f}s-{6.9333334f}s, Lower={7.15f}s");
				LOG.Debug($"CheckMapState: LookDuration={_lookDuration:F1}s");
				_clip.SampleAnimation(_targetObject, _currentTime);
			}

			public override void OnStateUpdate()
			{
				base.OnStateUpdate();
				if ((Object)(object)_clip == (Object)null || (Object)(object)_targetObject == (Object)null)
				{
					base.Machine.NextStateStateId = StateId.Idle;
					return;
				}
				_currentTime += Time.deltaTime;
				switch (_currentPhase)
				{
				case Phase.Raise:
					if (_currentTime >= 5.5f)
					{
						LOG.Debug("CheckMapState: Transitioning to Phase.Look");
						_currentPhase = Phase.Look;
						_lookTimer = 0f;
					}
					break;
				case Phase.Look:
					_lookTimer += Time.deltaTime;
					if (_currentTime >= 6.9333334f)
					{
						if (_lookTimer < _lookDuration)
						{
							_currentTime = 5.5f;
							break;
						}
						LOG.Debug("CheckMapState: Transitioning to Phase.Lower");
						_currentPhase = Phase.Lower;
					}
					break;
				case Phase.Lower:
					if (_currentTime >= 7.15f)
					{
						LOG.Debug("CheckMapState: Animation complete, returning to Idle");
						base.Machine.NextStateStateId = StateId.Idle;
						return;
					}
					break;
				}
				_clip.SampleAnimation(_targetObject, _currentTime);
			}

			public override void OnStateExit(StateId next)
			{
				base.OnStateExit(next);
				LOG.Debug($"CheckMapState: EXIT -> {next}");
				if ((Object)(object)_animator != (Object)null)
				{
					((Behaviour)_animator).enabled = true;
				}
			}
		}

		private sealed class StalkApproachState : StateMachineBase<StateMachine, StateId>.StateBaseTimed
		{
			private const float MaxApproachTime = 30f;

			private const float DestinationUpdateInterval = 1f;

			private float _nextDestinationUpdate;

			public override void OnStateEnter(StateId previous)
			{
				base.OnStateEnter(previous);
				LOG.Debug("=== STALK: Approach started - running towards player ===");
				base.Machine.Owner.IsSprinting = true;
				base.Machine.Owner.SetSpeed(5f);
				_nextDestinationUpdate = 0f;
				if (!base.Machine.Owner.TrySetDestinationToPlayer())
				{
					LOG.Debug("STALK: Failed to set destination to player, aborting");
					base.Machine.NextStateStateId = StateId.Idle;
				}
			}

			public override void OnStateUpdate()
			{
				base.OnStateUpdate();
				float distanceToPlayer = base.Machine.Owner.GetDistanceToPlayer();
				bool flag = base.Machine.Owner.HasReachedDestination();
				if (base.TimeElapsed >= 30f)
				{
					LOG.Debug($"STALK: Approach timeout, dist={distanceToPlayer:F1}m, aborting");
					base.Machine.NextStateStateId = StateId.Idle;
					return;
				}
				if (distanceToPlayer <= 5f)
				{
					LOG.Debug($"STALK: Arrived near player (distance={distanceToPlayer:F1}m)");
					base.Machine.NextStateStateId = StateId.StalkStare;
					return;
				}
				if (flag)
				{
					LOG.Debug($"STALK: Reached nav destination but player still at {distanceToPlayer:F1}m, starting stare anyway");
					base.Machine.NextStateStateId = StateId.StalkStare;
					return;
				}
				_nextDestinationUpdate -= Time.deltaTime;
				if (_nextDestinationUpdate <= 0f)
				{
					base.Machine.Owner.TrySetDestinationToPlayer();
					_nextDestinationUpdate = 1f;
				}
			}

			public override void OnStateExit(StateId next)
			{
				base.OnStateExit(next);
				base.Machine.Owner.IsSprinting = false;
				base.Machine.Owner.ResetPath();
			}
		}

		private sealed class StalkStareState : StateMachineBase<StateMachine, StateId>.StateBaseTimed
		{
			private const float MaxStareTime = 30f;

			private const float DestinationUpdateInterval = 0.5f;

			private float _fleeCountdown;

			private bool _hasBeenSeen;

			private float _nextDestinationUpdate;

			public override void OnStateEnter(StateId previous)
			{
				base.OnStateEnter(previous);
				LOG.Debug("=== STALK: Staring at player ===");
				_hasBeenSeen = false;
				_fleeCountdown = 2f;
				_nextDestinationUpdate = 0f;
				base.Machine.Owner.IsWalking = true;
				base.Machine.Owner.IsSprinting = false;
				base.Machine.Owner.SetSpeed(2f);
			}

			public override void OnStateUpdate()
			{
				base.OnStateUpdate();
				base.Machine.Owner.LookAtPlayer();
				float distanceToPlayer = base.Machine.Owner.GetDistanceToPlayer();
				if (base.Machine.Owner.IsPlayerLookingAtMe && !_hasBeenSeen)
				{
					_hasBeenSeen = true;
					LOG.Debug("=== STALK: Player sees me! Maintaining eye contact... ===");
					base.Machine.Owner.IsWalking = false;
					base.Machine.Owner.ResetPath();
				}
				if (_hasBeenSeen)
				{
					_fleeCountdown -= Time.deltaTime;
					if (_fleeCountdown <= 0f)
					{
						LOG.Debug("=== STALK: Eye contact over, fleeing! ===");
						base.Machine.NextStateStateId = StateId.StalkFlee;
						return;
					}
				}
				else if (distanceToPlayer > 3f)
				{
					_nextDestinationUpdate -= Time.deltaTime;
					if (_nextDestinationUpdate <= 0f)
					{
						base.Machine.Owner.TrySetDestinationToPlayer();
						_nextDestinationUpdate = 0.5f;
					}
				}
				else
				{
					base.Machine.Owner.ResetPath();
				}
				if (base.TimeElapsed >= 30f)
				{
					LOG.Debug("STALK: Stare timeout, fleeing");
					base.Machine.NextStateStateId = StateId.StalkFlee;
				}
			}

			public override void OnStateExit(StateId next)
			{
				base.OnStateExit(next);
				base.Machine.Owner.IsWalking = false;
			}
		}

		private sealed class StalkFleeState : StateMachineBase<StateMachine, StateId>.StateBaseTimed
		{
			private const float MaxFleeTime = 10f;

			public override void OnStateEnter(StateId previous)
			{
				base.OnStateEnter(previous);
				LOG.Debug("=== STALK: Fleeing from player! ===");
				base.Machine.Owner.IsSprinting = true;
				base.Machine.Owner.SetSpeed(5f);
				if (!base.Machine.Owner.TrySetFleeDestination())
				{
					LOG.Debug("STALK: Failed to set flee destination, going to idle");
					base.Machine.NextStateStateId = StateId.Idle;
				}
			}

			public override void OnStateUpdate()
			{
				base.OnStateUpdate();
				if (base.Machine.Owner.HasReachedDestination() || base.TimeElapsed >= 10f)
				{
					LOG.Debug("=== STALK: Flee complete, returning to idle ===");
					base.Machine.NextStateStateId = StateId.Idle;
				}
			}

			public override void OnStateExit(StateId next)
			{
				base.OnStateExit(next);
				base.Machine.Owner.IsSprinting = false;
			}
		}

		internal const float WalkSpeed = 2f;

		internal const float SprintSpeed = 5f;

		internal const float SprintChance = 0.5f;

		internal const float StalkMinDistance = 15f;

		internal const float StalkChance = 0.1f;

		internal const float StalkArrivalDistance = 5f;

		internal const float StalkMinKeepDistance = 3f;

		internal const float StalkFleeDistance = 20f;

		internal const float StalkStareBeforeFlee = 2f;

		private static readonly VepLogger LOG = VepLogger.Create<DroidController>();

		private static readonly int IsWalkingKey = Animator.StringToHash("isWalking");

		private static readonly int IsSprintingKey = Animator.StringToHash("isSprinting");

		private static readonly int IsTurningKey = Animator.StringToHash("isTurning");

		private static readonly int StunKey = Animator.StringToHash("stun");

		private static readonly int AlbedoColorKey = Shader.PropertyToID("_AlbedoColor");

		private readonly MaterialTrigger _materialTrigger = new MaterialTrigger();

		private DroidFaceAnimationController _animController;

		private CharacterController _charController;

		private DroidNameplate _nameplateController;

		private NavMeshAgent _navAgent;

		private Transform _rigidbodyTransform;

		private int _savedAgentTypeID;

		private int _savedAreaMask = -1;

		internal Animator Animator;

		public bool IsWalking { get; set; }

		public bool IsSprinting { get; set; }

		public bool IsTurning { get; private set; }

		public bool HasChangedMovementState { get; set; }

		public PlayerAvatar SourcePlayer { get; private set; }

		public Transform ControllerTransform { get; private set; }

		public DroidMovementController Movement { get; private set; }

		public bool IsPlayerLookingAtMe => _animController.IsPlayerLookingAtMe;

		public bool IsStalking
		{
			get
			{
				StateId currentStateStateId = Fsm.CurrentStateStateId;
				if ((uint)(currentStateStateId - 4) <= 2u)
				{
					return true;
				}
				return false;
			}
		}

		protected override StateId DefaultState => StateId.Idle;

		public bool HasPrecomputedDestination => Movement.HasPrecomputedDestination;

		protected override void Awake()
		{
		}

		protected override void Update()
		{
			if (!((Object)(object)Movement == (Object)null) && !((Object)(object)_navAgent == (Object)null) && _navAgent.isOnNavMesh && !((Object)(object)ControllerTransform == (Object)null))
			{
				Fsm.Update();
				StateId currentStateStateId = Fsm.CurrentStateStateId;
				bool isMovementState = DroidHelpers.IsMovementState(currentStateStateId);
				Movement.UpdateMovement(isMovementState);
				Movement.UpdateRotation();
				Movement.SyncVisualsToController(((Component)Animator).transform);
				UpdateAnimationFlags();
				Movement.SyncNavAgentPosition(isMovementState);
			}
		}

		public void PlayVoice(bool applyFilter = false)
		{
			if ((Object)(object)SourcePlayer == (Object)null || (Object)(object)ControllerTransform == (Object)null)
			{
				return;
			}
			PlayerAvatar instance = PlayerAvatar.instance;
			if (!((Object)(object)instance == (Object)null))
			{
				WhispralMimics component = ((Component)instance).GetComponent<WhispralMimics>();
				if ((Object)(object)component == (Object)null)
				{
					LOG.Warning("WhispralMimics not found on local player");
				}
				else
				{
					component.PlayAudioAtTransform(ControllerTransform, SourcePlayer.playerName, applyFilter);
				}
			}
		}

		private void UpdateAnimationFlags()
		{
			//IL_003f: 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)
			StateId currentStateStateId = Fsm.CurrentStateStateId;
			if (DroidHelpers.IsMovementState(currentStateStateId) && (Object)(object)ControllerTransform != (Object)null && (Object)(object)Movement != (Object)null)
			{
				float num = Quaternion.Angle(ControllerTransform.rotation, Movement.TargetRotation);
				IsTurning = num > 7f;
			}
			else
			{
				IsTurning = false;
			}
			if ((Object)(object)Animator != (Object)null)
			{
				Animator.SetBool(IsWalkingKey, IsWalking);
				Animator.SetBool(IsSprintingKey, IsSprinting);
				Animator.SetBool(IsTurningKey, IsTurning);
				Animator.SetBool(StunKey, false);
			}
		}

		public bool TrySetRandomDestination()
		{
			return (Object)(object)Movement != (Object)null && Movement.TrySetRandomDestination();
		}

		public bool TryExtendCurrentPath()
		{
			return (Object)(object)Movement != (Object)null && Movement.TryExtendCurrentPath();
		}

		public void StartPrecomputeForwardDestination()
		{
			Movement?.StartPrecomputeForwardDestination();
		}

		public void ClearPrecomputedForwardDestination()
		{
			Movement?.ClearPrecomputedForwardDestination();
		}

		public void StartPrecomputeDestination()
		{
			Movement.StartPrecomputeDestination();
		}

		public void ResetPath()
		{
			Movement.ResetPath();
		}

		public bool HasReachedDestination()
		{
			return Movement.HasReachedDestination();
		}

		public float GetDistanceToPlayer()
		{
			return Movement.GetDistanceToPlayer();
		}

		public bool TrySetDestinationToPlayer()
		{
			return (Object)(object)Movement != (Object)null && Movement.TrySetDestinationToPlayer();
		}

		public bool TrySetFleeDestination()
		{
			return (Object)(object)Movement != (Object)null && Movement.TrySetFleeDestination(20f);
		}

		public void LookAtPlayer()
		{
			Movement.LookAtPlayer();
		}

		public void SetSpeed(float speed)
		{
			Movement.SetSpeed(speed);
		}

		public static DroidController? Create(PlayerAvatar sourcePlayer, Vector3 spawnPosition)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			if (!DroidPrefabLoader.IsAvailable)
			{
				LOG.Warning("LostDroid prefab not available");
				return null;
			}
			GameObject val = Object.Instantiate<GameObject>(DroidPrefabLoader.LostDroidPrefab, spawnPosition, Quaternion.identity);
			if ((Object)(object)val == (Object)null)
			{
				LOG.Error("Failed to instantiate LostDroid prefab");
				return null;
			}
			((Object)val).name = "HallucinationDroid_" + sourcePlayer.playerName;
			DroidController droidController = val.AddComponent<DroidController>();
			droidController.Initialize(sourcePlayer);
			return droidController;
		}

		private void Initialize(PlayerAvatar sourcePlayer)
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			SourcePlayer = sourcePlayer;
			FindCriticalTransforms();
			SaveNavMeshSettings();
			DisableEnemyComponents();
			SetupNavigation();
			SetupMovementController();
			SetupAnimator();
			SetupAnimationController();
			ApplyPlayerColor();
			SetupNameplate();
			InitializeFsm();
			LOG.Info($"HallucinationDroid created for {sourcePlayer.playerName} at {ControllerTransform.position}");
		}

		private void SetupMovementController()
		{
			if (!((Object)(object)ControllerTransform == (Object)null))
			{
				Movement = ((Component)this).gameObject.AddComponent<DroidMovementController>();
				Movement.Initialize(ControllerTransform, _rigidbodyTransform, _navAgent, _charController, _savedAreaMask);
				Movement.OnNavMeshError += HandleNavMeshError;
			}
		}

		private void HandleNavMeshError()
		{
			Fsm.NextStateStateId = StateId.Idle;
		}

		private void SetupAnimationController()
		{
			_animController = ((Component)this).gameObject.AddComponent<DroidFaceAnimationController>();
			_animController.Initialize(this, ControllerTransform);
			Transform val = DroidHelpers.FindChildByName(((Component)this).transform, "code_head_top");
			if ((Object)(object)val != (Object)null)
			{
				_animController.SetupTalking(val);
			}
			SetupEyelidsForAnimController();
		}

		private void SetupEyelidsForAnimController()
		{
			try
			{
				Transform val = DroidHelpers.FindChildByName(((Component)this).transform, "ANIM EYE LEFT");
				Transform val2 = DroidHelpers.FindChildByName(((Component)this).transform, "ANIM EYE RIGHT");
				if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null)
				{
					LOG.Warning("ANIM EYE LEFT/RIGHT not found for angry eyes effect");
					return;
				}
				Transform val3 = FindEyelidSource();
				if ((Object)(object)val3 == (Object)null)
				{
					LOG.Warning("No PlayerAvatar found to copy eyelid structure");
					return;
				}
				Transform droidEye = DroidHelpers.FindChildByName(((Component)this).transform, "code_eye_left") ?? val;
				Transform droidEye2 = DroidHelpers.FindChildByName(((Component)this).transform, "code_eye_right") ?? val2;
				Transform upperRotationX;
				Transform upperRotationZ;
				Transform lowerRotationX;
				GameObject val4 = SetupEyeFromPlayer(droidEye, val3, "LEFT", out upperRotationX, out upperRotationZ, out lowerRotationX);
				Transform upperRotationX2;
				Transform upperRotationZ2;
				Transform lowerRotationX2;
				GameObject val5 = SetupEyeFromPlayer(droidEye2, val3, "RIGHT", out upperRotationX2, out upperRotationZ2, out lowerRotationX2);
				if ((Object)(object)val4 != (Object)null)
				{
					val4.SetActive(false);
				}
				if ((Object)(object)val5 != (Object)null)
				{
					val5.SetActive(false);
				}
				_animController.SetupEyelids(val4, val5, upperRotationX, upperRotationZ, lowerRotationX, upperRotationX2, upperRotationZ2, lowerRotationX2);
				LOG.Info($"Angry eyes setup: left={(Object)(object)val4 != (Object)null}, right={(Object)(object)val5 != (Object)null}");
			}
			catch (Exception ex)
			{
				LOG.Error("SetupEyelidsForAnimController: Exception - " + ex.Message + "\n" + ex.StackTrace);
			}
		}

		private void LateUpdate()
		{
			_nameplateController.UpdateNameplate();
			_animController.UpdateAnimations();
		}

		private void OnDestroy()
		{
			if ((Object)(object)Movement != (Object)null)
			{
				Movement.OnNavMeshError -= HandleNavMeshError;
			}
		}

		private Material? GetDroidBodyMaterial()
		{
			MeshRenderer[] componentsInChildren = ((Component)this).GetComponentsInChildren<MeshRenderer>(true);
			foreach (MeshRenderer val in componentsInChildren)
			{
				string text = ((Object)((Component)val).gameObject).name.ToLower();
				if (!text.Contains("eye") && !text.Contains("pupil") && !text.Contains("eyelid") && (Object)(object)((Renderer)val).material != (Object)null)
				{
					return ((Renderer)val).material;
				}
			}
			return null;
		}

		private Transform? FindEyelidSource()
		{
			PlayerAvatarVisuals[] array = Object.FindObjectsOfType<PlayerAvatarVisuals>();
			PlayerAvatarVisuals[] array2 = array;
			foreach (PlayerAvatarVisuals val in array2)
			{
				Transform[] componentsInChildren = ((Component)val).GetComponentsInChildren<Transform>(true);
				foreach (Transform val2 in componentsInChildren)
				{
					if (((Object)val2).name == "EYELIDS LEFT")
					{
						return ((Component)val).transform;
					}
				}
			}
			LOG.Warning("No PlayerAvatarVisuals with EYELIDS LEFT found");
			return null;
		}

		private GameObject? SetupEyeFromPlayer(Transform droidEye, Transform playerSource, string side, out Transform? upperRotationX, out Transform? upperRotationZ, out Transform? lowerRotationX)
		{
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Expected O, but got Unknown
			//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)
			upperRotationX = null;
			upperRotationZ = null;
			lowerRotationX = null;
			string text = "EYELIDS " + side;
			Transform val = null;
			Transform[] componentsInChildren = ((Component)playerSource).GetComponentsInChildren<Transform>(true);
			foreach (Transform val2 in componentsInChildren)
			{
				if (((Object)val2).name == text)
				{
					val = val2;
					break;
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				LOG.Warning(text + " not found on player source");
				return null;
			}
			Transform val3 = null;
			foreach (Transform item in droidEye)
			{
				Transform val4 = item;
				if (((Object)val4).name == text)
				{
					val3 = val4;
					break;
				}
			}
			if ((Object)(object)val3 == (Object)null)
			{
				val3 = CopyTransformHierarchy(val, droidEye);
				val3.localScale = Vector3.one * 1.3f;
				Material droidBodyMaterial = GetDroidBodyMaterial();
				if ((Object)(object)droidBodyMaterial != (Object)null)
				{
					MeshRenderer[] componentsInChildren2 = ((Component)val3).GetComponentsInChildren<MeshRenderer>(true);
					foreach (MeshRenderer val5 in componentsInChildren2)
					{
						((Renderer)val5).material = droidBodyMaterial;
					}
				}
			}
			Transform[] componentsInChildren3 = ((Component)val3).GetComponentsInChildren<Transform>(true);
			foreach (Transform val6 in componentsInChildren3)
			{
				switch (((Object)val6).name)
				{
				case "eyelid_upper":
					upperRotationX = val6;
					break;
				case "eyelid_upper_rotation":
					upperRotationZ = val6;
					break;
				case "eyelid_lower":
					lowerRotationX = val6;
					break;
				}
			}
			return ((Component)val3).gameObject;
		}

		private Transform CopyTransformHierarchy(Transform source, Transform newParent)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Expected O, but got Unknown
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: 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_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Expected O, but got Unknown
			GameObject val = new GameObject(((Object)source).name);
			val.transform.SetParent(newParent, false);
			val.transform.localPosition = source.localPosition;
			val.transform.localRotation = source.localRotation;
			val.transform.localScale = source.localScale;
			MeshFilter component = ((Component)source).GetComponent<MeshFilter>();
			MeshRenderer component2 = ((Component)source).GetComponent<MeshRenderer>();
			if ((Object)(object)component != (Object)null && (Object)(object)component2 != (Object)null)
			{
				MeshFilter val2 = val.AddComponent<MeshFilter>();
				MeshRenderer val3 = val.AddComponent<MeshRenderer>();
				val2.sharedMesh = component.sharedMesh;
				((Renderer)val3).sharedMaterials = ((Renderer)component2).sharedMaterials;
				((Renderer)val3).shadowCastingMode = ((Renderer)component2).shadowCastingMode;
				((Renderer)val3).receiveShadows = ((Renderer)component2).receiveShadows;
			}
			foreach (Transform item in source)
			{
				Transform source2 = item;
				CopyTransformHierarchy(source2, val.transform);
			}
			return val.transform;
		}

		public void PlayMediumFootstep()
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)ControllerTransform == (Object)null))
			{
				Vector3 val = ControllerTransform.position + Vector3.up * 0.1f;
				Materials.Instance.Impulse(val, Vector3.down, (SoundType)1, true, true, _materialTrigger, (HostType)1);
			}
		}

		private void SetupNameplate()
		{
			_nameplateController = ((Component)this).gameObject.AddComponent<DroidNameplate>();
			_nameplateController.Initialize(ControllerTransform, SourcePlayer);
		}

		private void ApplyPlayerColor()
		{
			//IL_005e: 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_0176: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)SourcePlayer == (Object)null)
			{
				return;
			}
			int playerColor = StatsManager.instance.GetPlayerColor(SourcePlayer.steamID);
			if (playerColor < 0 || playerColor >= AssetManager.instance.playerColors.Count)
			{
				return;
			}
			Color val = AssetManager.instance.playerColors[playerColor];
			Transform val2 = ((Component)this).transform.Find("Rigidbody/Cube") ?? ((Component)this).transform.Find("Cube");
			if ((Object)(object)val2 == (Object)null)
			{
				Transform[] componentsInChildren = ((Component)this).GetComponentsInChildren<Transform>();
				foreach (Transform val3 in componentsInChildren)
				{
					if (((Object)val3).name == "Cube")
					{
						val2 = val3;
						break;
					}
				}
			}
			if ((Object)(object)val2 == (Object)null)
			{
				LOG.Warning("Cube transform not found for color application");
				return;
			}
			Renderer[] componentsInChildren2 = ((Component)val2).GetComponentsInChildren<Renderer>();
			foreach (Renderer val4 in componentsInChildren2)
			{
				string name = ((Object)((Component)val4).gameObject).name;
				if (!name.Contains("eye") && !name.Contains("pupil") && !name.Contains("mesh_health"))
				{
					Material[] materials = val4.materials;
					foreach (Material val5 in materials)
					{
						val5.SetColor(AlbedoColorKey, val);
					}
				}
			}
		}

		private void InitializeFsm()
		{
			Fsm = new StateMachineComponent<DroidController, StateId>.StateMachine(this, DefaultState);
			Fsm.AddState(StateId.Idle, new IdleState());
			Fsm.AddState(StateId.Wander, new WanderState());
			Fsm.AddState(StateId.Sprint, new SprintState());
			Fsm.AddState(StateId.CheckMap, new CheckMapState());
			Fsm.AddState(StateId.StalkApproach, new StalkApproachState());
			Fsm.AddState(StateId.StalkStare, new StalkStareState());
			Fsm.AddState(StateId.StalkFlee, new StalkFleeState());
		}

		private void FindCriticalTransforms()
		{
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Expected O, but got Unknown
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			ControllerTransform = ((Component)this).transform.Find("Controller");
			if ((Object)(object)ControllerTransform == (Object)null)
			{
				Transform[] componentsInChildren = ((Component)this).GetComponentsInChildren<Transform>();
				foreach (Transform val in componentsInChildren)
				{
					if (((Object)val).name == "Controller")
					{
						ControllerTransform = val;
						break;
					}
				}
			}
			if ((Object)(object)ControllerTransform == (Object)null)
			{
				LOG.Warning("Controller transform not found, creating one");
				GameObject val2 = new GameObject("Controller");
				val2.transform.SetParent(((Component)this).transform);
				val2.transform.localPosition = Vector3.zero;
				ControllerTransform = val2.transform;
			}
			_rigidbodyTransform = ((Component)this).transform.Find("Rigidbody");
			if ((Object)(object)_rigidbodyTransform == (Object)null)
			{
				Transform[] componentsInChildren2 = ((Component)this).GetComponentsInChildren<Transform>();
				foreach (Transform val3 in componentsInChildren2)
				{
					if (((Object)val3).name == "Rigidbody")
					{
						_rigidbodyTransform = val3;
						break;
					}
				}
			}
			if ((Object)(object)_rigidbodyTransform == (Object)null)
			{
				LOG.Warning("Rigidbody transform not found");
			}
		}

		private void SaveNavMeshSettings()
		{
			NavMeshAgent val = null;
			if ((Object)(object)ControllerTransform != (Object)null)
			{
				val = ((Component)ControllerTransform).GetComponent<NavMeshAgent>();
			}
			if ((Object)(object)val == (Object)null)
			{
				val = ((Component)this).GetComponentInChildren<NavMeshAgent>();
			}
			if ((Object)(object)val != (Object)null)
			{
				_savedAgentTypeID = val.agentTypeID;
				_savedAreaMask = val.areaMask;
			}
			else
			{
				_savedAgentTypeID = -334000983;
				_savedAreaMask = 1;
			}
		}

		private void DisableEnemyComponents()
		{
			//IL_0279: Unknown result type (might be due to invalid IL or missing references)
			//IL_0286: Unknown result type (might be due to invalid IL or missing references)
			List<Component> list = new List<Component>();
			List<MonoBehaviour> list2 = new List<MonoBehaviour>();
			Component[] componentsInChildren = ((Component)this).GetComponentsInChildren<Component>(true);
			foreach (Component val in componentsInChildren)
			{
				if ((Object)(object)val == (Object)null || (Object)(object)val == (Object)(object)this)
				{
					continue;
				}
				string name = ((object)val).GetType().Name;
				string text = ((object)val).GetType().FullName ?? "";
				if (val is Transform || val is Animator || val is Renderer || val is MeshFilter || val is SkinnedMeshRenderer || val is NavMeshAgent)
				{
					continue;
				}
				if (text.Contains("Photon") || name.Contains("Photon") || text.Contains("Enemy") || text.Contains("LostDroid") || name.Contains("Enemy") || name.Contains("LostDroid"))
				{
					list.Add(val);
					continue;
				}
				MonoBehaviour val2 = (MonoBehaviour)(object)((val is MonoBehaviour) ? val : null);
				if (val2 != null)
				{
					list2.Add(val2);
				}
			}
			for (int j = 0; j < 5; j++)
			{
				int num = 0;
				foreach (Component item in list)
				{
					if ((Object)(object)item != (Object)null)
					{
						try
						{
							Object.DestroyImmediate((Object)(object)item);
							num++;
						}
						catch
						{
						}
					}
				}
				if (num == 0)
				{
					break;
				}
			}
			foreach (MonoBehaviour item2 in list2)
			{
				if ((Object)(object)item2 != (Object)null && (Object)(object)item2 != (Object)(object)this)
				{
					((Behaviour)item2).enabled = false;
				}
			}
			Rigidbody[] componentsInChildren2 = ((Component)this).GetComponentsInChildren<Rigidbody>();
			foreach (Rigidbody val3 in componentsInChildren2)
			{
				val3.isKinematic = true;
				val3.useGravity = false;
				val3.velocity = Vector3.zero;
				val3.angularVelocity = Vector3.zero;
			}
			Collider[] componentsInChildren3 = ((Component)this).GetComponentsInChildren<Collider>();
			foreach (Collider val4 in componentsInChildren3)
			{
				val4.isTrigger = true;
			}
		}

		private void SetupAnimator()
		{
			Animator = ((Component)this).GetComponentInChildren<Animator>();
			if ((Object)(object)Animator != (Object)null)
			{
				((Behaviour)Animator).enabled = true;
				Animator.applyRootMotion = false;
				ParentConstraint component = ((Component)Animator).GetComponent<ParentConstraint>();
				if ((Object)(object)component != (Object)null && !component.constraintActive)
				{
					component.constraintActive = true;
				}
				DroidFootstepsEventReceiver orAddComponent = ComponentHolderProtocol.GetOrAddComponent<DroidFootstepsEventReceiver>((Object)(object)Animator);
				orAddComponent.Initialize(this);
			}
			else
			{
				LOG.Warning("No Animator found on prefab");
			}
		}

		private void SetupNavigation()
		{
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: 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_009a: 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_00c5: 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_0222: 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_0102: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ControllerTransform == (Object)null)
			{
				LOG.Error("Cannot setup navigation: Controller is null");
				return;
			}
			_navAgent = ((Component)ControllerTransform).GetComponent<NavMeshAgent>();
			if ((Object)(object)_navAgent == (Object)null)
			{
				_navAgent = ((Component)ControllerTransform).gameObject.AddComponent<NavMeshAgent>();
			}
			Vector3 position = ControllerTransform.position;
			Vector3 val = position;
			bool flag = false;
			NavMeshQueryFilter val2 = default(NavMeshQueryFilter);
			((NavMeshQueryFilter)(ref val2)).agentTypeID = _savedAgentTypeID;
			((NavMeshQueryFilter)(ref val2)).areaMask = _savedAreaMask;
			NavMeshQueryFilter val3 = val2;
			float[] array = new float[4] { 5f, 10f, 20f, 50f };
			float[] array2 = array;
			NavMeshHit val4 = default(NavMeshHit);
			foreach (float num in array2)
			{
				if (NavMesh.SamplePosition(position, ref val4, num, val3))
				{
					val = ((NavMeshHit)(ref val4)).position;
					flag = true;
					break;
				}
			}
			if (!flag)
			{
				LOG.Error($"No NavMesh found near {position}");
				return;
			}
			((Behaviour)_navAgent).enabled = false;
			_navAgent.agentTypeID = _savedAgentTypeID;
			_navAgent.areaMask = _savedAreaMask;
			_navAgent.baseOffset = 0f;
			_navAgent.speed = 2f;
			_navAgent.angularSpeed = 999f;
			_navAgent.acceleration = 15f;
			_navAgent.stoppingDistance = 0f;
			_navAgent.autoBraking = true;
			_navAgent.updatePosition = false;
			_navAgent.updateRotation = false;
			_navAgent.radius = 0.7f;
			_navAgent.height = 2f;
			_navAgent.obstacleAvoidanceType = (ObstacleAvoidanceType)4;
			_navAgent.avoidancePriority = 10;
			_navAgent.autoTraverseOffMeshLink = true;
			_navAgent.autoRepath = true;
			ControllerTransform.position = val;
			_navAgent.Warp(val);
			((Behaviour)_navAgent).enabled = true;
			SetupCharacterController();
		}

		private void SetupCharacterController()
		{
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)ControllerTransform == (Object)null))
			{
				CharacterController component = ((Component)ControllerTransform).GetComponent<CharacterController>();
				if ((Object)(object)component != (Object)null)
				{
					Object.DestroyImmediate((Object)(object)component);
				}
				_charController = ((Component)ControllerTransform).gameObject.AddComponent<CharacterController>();
				_charController.height = 2f;
				_charController.radius = 0.5f;
				_charController.center = new Vector3(0f, 1f, 0f);
				_charController.slopeLimit = 45f;
				_charController.stepOffset = 0.3f;
				_charController.skinWidth = 0.08f;
				_charController.minMoveDistance = 0.001f;
			}
		}
	}
	public sealed class DroidDebuff : MonoBehaviour
	{
		private static readonly VepLogger LOG = VepLogger.Create<DroidDebuff>();

		private readonly Dictionary<PlayerAvatar, DroidController> _droids = new Dictionary<PlayerAvatar, DroidController>();

		private WhispralDebuffManager _debuffManager;

		private InvisiblePlayerDebuff _invisiblePlayerDebuff;

		public bool IsActive { get; private set; }

		private void Update()
		{
			if (IsActive && !((Object)(object)_invisiblePlayerDebuff == (Object)null))
			{
				SyncHallucinations();
			}
		}

		private void OnDestroy()
		{
			DestroyAllHallucinations();
		}

		public void ApplyDebuff(bool active, InvisiblePlayerDebuff sourcePlayerDebuff)
		{
			if (!SemiFunc.IsMultiplayer())
			{
				LOG.Debug("Singleplayer mode detected, skipping hallucinations.");
				return;
			}
			IsActive = active;
			_invisiblePlayerDebuff = sourcePlayerDebuff;
			_debuffManager = ((Component)this).GetComponent<WhispralDebuffManager>();
			if (active)
			{
				CreateHallucinations();
			}
			else
			{
				DestroyAllHallucinations();
			}
		}

		public DroidController? GetDroidByPlayerName(string playerName)
		{
			foreach (KeyValuePair<PlayerAvatar, DroidController> droid in _droids)
			{
				if (Object.op_Implicit((Object)(object)droid.Key) && Object.op_Implicit((Object)(object)droid.Value) && droid.Key.playerName == playerName)
				{
					return droid.Value;
				}
			}
			return null;
		}

		private void CreateHallucination(PlayerAvatar sourcePlayer)
		{
			//IL_0074: 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)
			LOG.Debug("Creating hallucination for player " + sourcePlayer.playerName);
			if (!DroidPrefabLoader.IsAvailable)
			{
				LOG.Warning("LostDroid prefab not available - cannot create hallucination");
				return;
			}
			Vector3? val = FindSpawnPosition();
			if (!val.HasValue)
			{
				LOG.Warning("Could not find spawn position for hallucination of " + sourcePlayer.playerName);
				return;
			}
			DroidController droidController = DroidController.Create(sourcePlayer, val.Value);
			if ((Object)(object)droidController == (Object)null)
			{
				LOG.Warning("Hallucination for " + sourcePlayer.playerName + " failed to create");
				return;
			}
			_droids[sourcePlayer] = droidController;
			LOG.Debug($"Hallucination created at {((Component)droidController).transform.position}");
		}

		private void CreateHallucinations()
		{
			if ((Object)(object)_invisiblePlayerDebuff == (Object)null)
			{
				return;
			}
			LOG.Debug("Creating hallucinations for hidden players.");
			foreach (PlayerAvatar hiddenPlayer in _invisiblePlayerDebuff.HiddenPlayers)
			{
				if (Object.op_Implicit((Object)(object)hiddenPlayer) && !_droids.ContainsKey(hiddenPlayer))
				{
					CreateHallucination(hiddenPlayer);
				}
			}
		}

		private void DestroyAllHallucinations()
		{
			LOG.Debug("Destroying all hallucinations.");
			foreach (KeyValuePair<PlayerAvatar, DroidController> droid in _droids)
			{
				if (Object.op_Implicit((Object)(object)droid.Value))
				{
					Object.Destroy((Object)(object)((Component)droid.Value).gameObject);
				}
			}
			_droids.Clear();
		}

		private void DestroyHallucination(PlayerAvatar? player)
		{
			if (!((Object)(object)player == (Object)null) && _droids.TryGetValue(player, out DroidController value))
			{
				LOG.Debug("Destroying hallucination for player " + player.playerName);
				if (Object.op_Implicit((Object)(object)value))
				{
					Object.Destroy((Object)(object)((Component)value).gameObject);
				}
				_droids.Remove(player);
			}
		}

		private Vector3? FindSpawnPosition()
		{
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: 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_0038: 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_00da: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_debuffManager != (Object)null)
			{
				Vector3? precomputedSpawnPosition = _debuffManager.GetPrecomputedSpawnPosition();
				if (precomputedSpawnPosition.HasValue)
				{
					LOG.Debug($"Using precomputed spawn position: {precomputedSpawnPosition.Value}");
					return precomputedSpawnPosition.Value;
				}
			}
			LOG.Warning("No precomputed position available, falling back to sync search");
			Vector3 position = ((Component)PlayerAvatar.instance).transform.position;
			LevelPoint val = SemiFunc.LevelPointGet(position, 5f, 15f) ?? SemiFunc.LevelPointGet(position, 0f, 999f);
			if (!Object.op_Implicit((Object)(object)val))
			{
				LOG.Warning("No LevelPoint found for hallucination spawn");
				return null;
			}
			return ((Component)val).transform.position;
		}

		private void SyncHallucinations()
		{
			IReadOnlyList<PlayerAvatar> hiddenPlayers = _invisiblePlayerDebuff.HiddenPlayers;
			foreach (PlayerAvatar item in hiddenPlayers)
			{
				if (Object.op_Implicit((Object)(object)item) && !_droids.ContainsKey(item))
				{
					CreateHallucination(item);
				}
			}
			List<PlayerAvatar> list = new List<PlayerAvatar>();
			foreach (KeyValuePair<PlayerAvatar, DroidController> droid in _droids)
			{
				if (!Object.op_Implicit((Object)(object)droid.Key) || !Object.op_Implicit((Object)(object)droid.Value) || !hiddenPlayers.Contains(droid.Key))
				{
					list.Add(droid.Key);
				}
			}
			foreach (PlayerAvatar item2 in list)
			{
				DestroyHallucination(item2);
			}
		}
	}
	public sealed class DroidFaceAnimationController : MonoBehaviour
	{
		private static class AngryExpression
		{
			public const float UpperLidAngleLeft = -34f;

			public const float UpperLidAngleRight = 34f;

			public const float UpperLidClosed = 83f;

			public const float LowerLidClosed = -83f;
		}

		private const float LookAtAngle = 50f;

		private const float LookAtMaxDistance = 30f;

		private const float AngryEyesCooldown = 0.3f;

		private const float TalkRotationMaxAngle = 25f;

		private const int SampleDataLength = 256;

		private const float StalkStareBeforeFlee = 3.030303f;

		private static readonly VepLogger LOG = VepLogger.Create<DroidFaceAnimationController>();

		private float _angryTimer;

		private Transform _controllerTransform;

		private DroidController _droidController;

		private GameObject? _eyelidsLeft;

		private GameObject? _eyelidsRight;

		private Transform? _headTopTransform;

		private bool _isAngry;

		private Transform? _leftLowerEyelidRotationX;

		private Transform? _leftUpperEyelidRotationX;

		private Transform? _leftUpperEyelidRotationZ;

		private Transform? _rightLowerEyelidRotationX;

		private Transform? _rightUpperEyelidRotationX;

		private Transform? _rightUpperEyelidRotationZ;

		private float[]? _sampleData;

		private AudioSource? _talkingAudioSource;

		private bool _wasPlayerLooking;

		public bool IsPlayerLookingAtMe { get; private set; }

		public void Initialize(DroidController droidController, Transform controllerTransform)
		{
			_droidController = droidController;
			_controllerTransform = droidController.ControllerTransform;
		}

		public void SetupEyelids(GameObject? eyelidsLeft, GameObject? eyelidsRight, Transform? leftUpperX, Transform? leftUpperZ, Transform? leftLowerX, Transform? rightUpperX, Transform? rightUpperZ, Transform? rightLowerX)
		{
			_eyelidsLeft = eyelidsLeft;
			_eyelidsRight = eyelidsRight;
			_leftUpperEyelidRotationX = leftUpperX;
			_leftUpperEyelidRotationZ = leftUpperZ;
			_leftLowerEyelidRotationX = leftLowerX;
			_rightUpperEyelidRotationX = rightUpperX;
			_rightUpperEyelidRotationZ = rightUpperZ;
			_rightLowerEyelidRotationX = rightLowerX;
		}

		public void SetupTalking(Transform headTopTransform)
		{
			_headTopTransform = headTopTransform;
		}

		public void UpdateAnimations()
		{
			UpdatePlayerLookDetection();
			UpdateAngryEyes();
			UpdateTalkingAnimation();
		}

		private void UpdateAngryEyes()
		{
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cf: 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_0209: 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_023b: Unknown result type (might be due to invalid IL or missing references)
			//IL_024b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0252: Unknown result type (might be due to invalid IL or missing references)
			//IL_027d: Unknown result type (might be due to invalid IL or missing references)
			//IL_028d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0294: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0305: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_eyelidsLeft == (Object)null || (Object)(object)_eyelidsRight == (Object)null || (Object)(object)_leftUpperEyelidRotationX == (Object)null || (Object)(object)_rightUpperEyelidRotationX == (Object)null)
			{
				return;
			}
			if (IsPlayerLookingAtMe && !_wasPlayerLooking)
			{
				_angryTimer = (_droidController.IsStalking ? 3.030303f : 0.3f);
			}
			_wasPlayerLooking = IsPlayerLookingAtMe;
			if (IsPlayerLookingAtMe)
			{
				_angryTimer -= Time.deltaTime;
				if (_angryTimer <= 0f)
				{
					_isAngry = false;
				}
			}
			else
			{
				_isAngry = true;
			}
			if (_isAngry && !_eyelidsLeft.activeSelf)
			{
				_eyelidsLeft.SetActive(true);
				_eyelidsRight.SetActive(true);
			}
			float num = (_isAngry ? 83f : 0f);
			float num2 = (_isAngry ? (-83f) : 0f);
			float num3 = (_isAngry ? (-34f) : 0f);
			float num4 = (_isAngry ? 34f : 0f);
			float num5 = Time.deltaTime * 8f;
			_leftUpperEyelidRotationX.localRotation = Quaternion.Slerp(_leftUpperEyelidRotationX.localRotation, Quaternion.Euler(num, 0f, 0f), num5);
			_rightUpperEyelidRotationX.localRotation = Quaternion.Slerp(_rightUpperEyelidRotationX.localRotation, Quaternion.Euler(num, 0f, 0f), num5);
			if ((Object)(object)_leftUpperEyelidRotationZ != (Object)null)
			{
				_leftUpperEyelidRotationZ.localRotation = Quaternion.Slerp(_leftUpperEyelidRotationZ.localRotation, Quaternion.Euler(0f, 0f, num3), num5);
			}
			if ((Object)(object)_rightUpperEyelidRotationZ != (Object)null)
			{
				_rightUpperEyelidRotationZ.localRotation = Quaternion.Slerp(_rightUpperEyelidRotationZ.localRotation, Quaternion.Euler(0f, 0f, num4), num5);
			}
			if ((Object)(object)_leftLowerEyelidRotationX != (Object)null)
			{
				_leftLowerEyelidRotationX.localRotation = Quaternion.Slerp(_leftLowerEyelidRotationX.localRotation, Quaternion.Euler(num2, 0f, 0f), num5);
			}
			if ((Object)(object)_rightLowerEyelidRotationX != (Object)null)
			{
				_rightLowerEyelidRotationX.localRotation = Quaternion.Slerp(_rightLowerEyelidRotationX.localRotation, Quaternion.Euler(num2, 0f, 0f), num5);
			}
			if (!_isAngry && _eyelidsLeft.activeSelf)
			{
				float num6 = Mathf.Abs(_leftUpperEyelidRotationX.localEulerAngles.x);
				if ((num6 < 10f || num6 > 350f) ? true : false)
				{
					_eyelidsLeft.SetActive(false);
					_eyelidsRight.SetActive(false);
				}
			}
		}

		private void UpdatePlayerLookDetection()
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: 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_0078: 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_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			Camera main = Camera.main;
			if ((Object)(object)main == (Object)null || (Object)(object)_controllerTransform == (Object)null)
			{
				IsPlayerLookingAtMe = false;
				return;
			}
			Vector3 val = _controllerTransform.position + Vector3.up;
			Vector3 position = ((Component)main).transform.position;
			float num = Vector3.Distance(position, val);
			if (num > 30f)
			{
				IsPlayerLookingAtMe = false;
				return;
			}
			Vector3 val2 = val - position;
			Vector3 normalized = ((Vector3)(ref val2)).normalized;
			float num2 = Vector3.Dot(((Component)main).transform.forward, normalized);
			float num3 = Mathf.Cos(0.87266463f);
			IsPlayerLookingAtMe = num2 >= num3;
		}

		private void UpdateTalkingAnimation()
		{
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_headTopTransform == (Object)null)
			{
				return;
			}
			float num = 0f;
			if ((Object)(object)_talkingAudioSource == (Object)null && (Object)(object)_controllerTransform != (Object)null)
			{
				_talkingAudioSource = ((Component)_controllerTransform).GetComponent<AudioSource>();
			}
			if ((Object)(object)_talkingAudioSource != (Object)null && _talkingAudioSource.isPlaying)
			{
				if (_sampleData == null)
				{
					_sampleData = new float[256];
				}
				_talkingAudioSource.GetOutputData(_sampleData, 0);
				float num2 = 0f;
				float[] sampleData = _sampleData;
				foreach (float num3 in sampleData)
				{
					num2 += Mathf.Abs(num3);
				}
				num2 /= 256f;
				if (num2 > 0.01f)
				{
					num = Mathf.Lerp(0f, -25f, num2 * 10f);
				}
			}
			else
			{
				_talkingAudioSource = null;
			}
			_headTopTransform.localRotation = Quaternion.Slerp(_headTopTransform.localRotation, Quaternion.Euler(num, 0f, 0f), Time.deltaTime * 20f);
		}
	}
	public sealed class DroidFootstepsEventReceiver : MonoBehaviour
	{
		private static readonly VepLogger LOG = VepLogger.Create<DroidFootstepsEventReceiver>();

		private DroidController _droid;

		public void Initialize(DroidController droidController)
		{
			_droid = droidController;
		}

		public void PlayMediumFootstep()
		{
			_droid.PlayMediumFootstep();
		}
	}
	public static class DroidHelpers
	{
		public static bool IsMovementState(DroidController.StateId state)
		{
			if ((uint)(state - 1) <= 1u || (uint)(state - 4) <= 2u)
			{
				return true;
			}
			return false;
		}

		public static Transform? FindChildByName(Transform? root, string name, bool includeInactive = true)
		{
			if ((Object)(object)root == (Object)null)
			{
				return null;
			}
			Transform[] componentsInChildren = ((Component)root).GetComponentsInChildren<Transform>(includeInactive);
			foreach (Transform val in componentsInChildren)
			{
				if (((Object)val).name == name)
				{
					return val;
				}
			}
			return null;
		}

		public static void FindChildrenByNames(Transform root, bool includeInactive, params (string name, Action<Transform> onFound)[] searches)
		{
			if ((Object)(object)root == (Object)null)
			{
				return;
			}
			int num = searches.Length;
			Transform[] componentsInChildren = ((Component)root).GetComponentsInChildren<Transform>(includeInactive);
			foreach (Transform val in componentsInChildren)
			{
				for (int j = 0; j < searches.Length; j++)
				{
					var (text, action) = searches[j];
					if (((Object)val).name == text)
					{
						action(val);
						num--;
						if (num == 0)
						{
							return;
						}
					}
				}
			}
		}

		public static bool TryGetNavMeshPosition(Vector3 position, out Vector3 result, int areaMask, float maxDistance = 5f)
		{
			//IL_0001: 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_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			NavMeshHit val = default(NavMeshHit);
			if (NavMesh.SamplePosition(position, ref val, maxDistance, areaMask))
			{
				result = ((NavMeshHit)(ref val)).position;
				return true;
			}
			result = position;
			return false;
		}

		public static AnimationClip? GetAnimationClip(Animator animator, string clipName)
		{
			if ((Object)(object)animator == (Object)null || (Object)(object)animator.runtimeAnimatorController == (Object)null)
			{
				return null;
			}
			AnimationClip[] animationClips = animator.runtimeAnimatorController.animationClips;
			foreach (AnimationClip val in animationClips)
			{
				if (((Object)val).name == clipName)
				{
					return val;
				}
			}
			return null;
		}

		public static bool IsNavAgentValid(NavMeshAgent agent)
		{
			return (Object)(object)agent != (Object)null && agent.isOnNavMesh;
		}

		public static Vector3? GetLocalPlayerPosition()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			PlayerAvatar instance = PlayerAvatar.instance;
			return ((Object)(object)instance != (Object)null) ? new Vector3?(((Component)instance).transform.position) : null;
		}
	}
	public sealed class DroidMovementController : MonoBehaviour
	{
		[CompilerGenerated]
		private sealed class <PrecomputeDestinationCoroutine>d__46 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public DroidMovementController <>4__this;

			private Vector3 <controllerPos>5__1;

			private LevelPoint <levelPoint>5__2;

			private Vector3 <targetPos>5__3;

			private NavMeshHit <hit>5__4;

			private NavMeshPath <path>5__5;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <PrecomputeDestinationCoroutine>d__46(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<levelPoint>5__2 = null;
				<path>5__5 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//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_00f9: Unknown result type (might be due to invalid IL or missing references)
				//IL_014c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0151: Unknown result type (might be due to invalid IL or missing references)
				//IL_0156: 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_006e: Unknown result type (might be due to invalid IL or missing references)
				//IL_005c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0194: Unknown result type (might be due to invalid IL or missing references)
				//IL_019e: Expected O, but got Unknown
				//IL_0073: 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_01c1: Unknown result type (might be due to invalid IL or missing references)
				//IL_0093: Unknown result type (might be due to invalid IL or missing references)
				//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
				//IL_01df: Invalid comparison between Unknown and I4
				//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>4__this._isPrecomputingDestination = true;
					<controllerPos>5__1 = (((Object)(object)<>4__this._controllerTransform != (Object)null) ? <>4__this._controllerTransform.position : ((Component)<>4__this).transform.position);
					<levelPoint>5__2 = SemiFunc.LevelPointGet(<controllerPos>5__1, 5f, 15f) ?? SemiFunc.LevelPointGet(<controllerPos>5__1, 0f, 20f);
					if ((Object)(object)<levelPoint>5__2 == (Object)null)
					{
						<>4__this._isPrecomputingDestination = false;
						return false;
					}
					<>2__current = null;
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					<targetPos>5__3 = ((Component)<levelPoint>5__2).transform.position;
					if (!NavMesh.SamplePosition(<targetPos>5__3, ref <hit>5__4, 5f, <>4__this._savedAreaMask))
					{
						<>4__this._isPrecomputingDestination = false;
						return false;
					}
					<>2__current = null;
					<>1__state = 2;
					return true;
				case 2:
					<>1__state = -1;
					if (!Physics.Raycast(((NavMeshHit)(ref <hit>5__4)).position + Vector3.up, Vector3.down, 5f, LayerMask.GetMask(new string[1] { "Default" })))
					{
						<>4__this._isPrecomputingDestination = false;
						return false;
					}
					<path>5__5 = new NavMeshPath();
					if (DroidHelpers.IsNavAgentValid(<>4__this._navAgent) && <>4__this._navAgent.CalculatePath(((NavMeshHit)(ref <hit>5__4)).position, <path>5__5) && (int)<path>5__5.status == 0)
					{
						<>4__this._precomputedDestination = ((NavMeshHit)(ref <hit>5__4)).position;
					}
					<>4__this._isPrecomputingDestination = false;
					return false;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <PrecomputeForwardDestinationCoroutine>d__49 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public float minDistance;

			public float maxDistance;

			public float maxAngleDeviation;

			public DroidMovementController <>4__this;

			private Vector3 <direction>5__1;

			private string <directionSource>5__2;

			private float <angleDeviation>5__3;

			private float <distance>5__4;

			private Vector3 <currentPos>5__5;

			private Vector3 <targetPos>5__6;

			private NavMeshHit <hit>5__7;

			private NavMeshPath <path>5__8;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <PrecomputeForwardDestinationCoroutine>d__49(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<directionSource>5__2 = null;
				<path>5__8 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_018b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0191: Unknown result type (might be due to invalid IL or missing references)
				//IL_0196: Unknown result type (might be due to invalid IL or missing references)
				//IL_019b: Unknown result type (might be due to invalid IL or missing references)
				//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
				//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
				//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
				//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
				//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
				//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
				//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
				//IL_0238: Unknown result type (might be due to invalid IL or missing references)
				//IL_02a8: Unknown result type (might be due to invalid IL or missing references)
				//IL_02b2: Expected O, but got Unknown
				//IL_02c3: Unknown result type (might be due to invalid IL or missing references)
				//IL_026d: Unknown result type (might be due to invalid IL or missing references)
				//IL_02db: Unknown result type (might be due to invalid IL or missing references)
				//IL_02e1: Invalid comparison between Unknown and I4
				//IL_00ae: 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_032c: Unknown result type (might be due to invalid IL or missing references)
				//IL_034b: Unknown result type (might be due to invalid IL or missing references)
				//IL_02fd: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
				//IL_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_00fb: Unknown result type (might be due to invalid IL or missing references)
				//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
				//IL_0103: Unknown result type (might be due to invalid IL or missing references)
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>4__this._isPrecomputingForward = true;
					LOG.Debug("PrecomputeForward: Starting coroutine");
					if ((Object)(object)<>4__this._controllerTransform == (Object)null || !DroidHelpers.IsNavAgentValid(<>4__this._navAgent))
					{
						LOG.Debug("PrecomputeForward: Invalid controller or NavAgent");
						<>4__this._isPrecomputingForward = false;
						return false;
					}
					<direction>5__1 = ((Vector3)(ref <>4__this._currentVelocity)).normalized;
					<directionSource>5__2 = "velocity";
					if (((Vector3)(ref <direction>5__1)).sqrMagnitude < 0.01f)
					{
						Vector3 val = <>4__this._destination - <>4__this._controllerTransform.position;
						<direction>5__1 = ((Vector3)(ref val)).normalized;
						<directionSource>5__2 = "destination";
					}
					if (((Vector3)(ref <direction>5__1)).sqrMagnitude < 0.01f)
					{
						LOG.Debug("PrecomputeForward: No valid direction found");
						<>4__this._isPrecomputingForward = false;
						return false;
					}
					<>2__current = null;
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					<angleDeviation>5__3 = Random.Range(0f - maxAngleDeviation, maxAngleDeviation);
					<direction>5__1 = Quaternion.Euler(0f, <angleDeviation>5__3, 0f) * <direction>5__1;
					<distance>5__4 = Random.Range(minDistance, maxDistance);
					<currentPos>5__5 = <>4__this._controllerTransform.position;
					<targetPos>5__6 = <currentPos>5__5 + <direction>5__1 * <distance>5__4;
					LOG.Debug($"PrecomputeForward: source={<directionSource>5__2}, angle={<angleDeviation>5__3:F1}°, dist={<distance>5__4:F1}m");
					<>2__current = null;
					<>1__state = 2;
					return true;
				case 2:
					<>1__state = -1;
					if (!NavMesh.SamplePosition(<targetPos>5__6, ref <hit>5__7, 10f, <>4__this._savedAreaMask))
					{
						LOG.Debug($"PrecomputeForward: No NavMesh position found near {<targetPos>5__6}");
						<>4__this._isPrecomputingForward = false;
						return false;
					}
					<>2__current = null;
					<>1__state = 3;
					return true;
				case 3:
					<>1__state = -1;
					<path>5__8 = new NavMeshPath();
					if (!<>4__this._navAgent.CalculatePath(((NavMeshHit)(ref <hit>5__7)).position, <path>5__8) || (int)<path>5__8.status > 0)
					{
						LOG.Debug($"PrecomputeForward: Path calculation failed to {((NavMeshHit)(ref <hit>5__7)).position}");
						<>4__this._isPrecomputingForward = false;
						return false;
					}
					<>4__this._precomputedForwardDestination = ((NavMeshHit)(ref <hit>5__7)).position;
					LOG.Debug($"PrecomputeForward: SUCCESS - precomputed destination at {((NavMeshHit)(ref <hit>5__7)).position}");
					<>4__this._isPrecomputingForward = false;
					return false;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		private const float RotationSpeed = 10f;

		private const float VisualYOffset = 0.25f;

		private static readonly VepLogger LOG = VepLogger.Create<DroidMovementController>();

		private CharacterController _charController;

		private Transform _controllerTransform;

		private Vector3 _currentVelocity;

		private Vector3 _destination;

		private bool _isPrecomputingDestination;

		private bool _isPrecomputingForward;

		private NavMeshAgent _navAgent;

		private Vector3? _precomputedDestination;

		private Vector3? _precomputedForwardDestination;

		private Transform? _rigidbodyTransform;

		private int _savedAreaMask = -1;

		public bool HasPrecomputedDestination => _precomputedDestination.HasValue;

		public bool HasPrecomputedForwardDestination => _precomputedForwardDestination.HasValue;

		public Quaternion TargetRotation { get; private set; } = Quaternion.identity;


		public Vector3 CurrentVelocity => _currentVelocity;

		public event Action? OnNavMeshError;

		public float GetDistanceToPlayer()
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			Vector3? localPlayerPosition = DroidHelpers.GetLocalPlayerPosition();
			if (!localPlayerPosition.HasValue || (Object)(object)_controllerTransform == (Object)null)
			{
				return float.MaxValue;
			}
			return Vector3.Distance(_controllerTransform.position, localPlayerPosition.Value);
		}

		public bool HasReachedDestination()
		{
			//IL_0046: 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_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_004e: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_navAgent == (Object)null || _navAgent.pathPending)
			{
				return false;
			}
			Vector3 val = (((Object)(object)_controllerTransform != (Object)null) ? _controllerTransform.position : ((Component)this).transform.position);
			float num = Vector3.Distance(val, _destination);
			return !_navAgent.hasPath || num <= _navAgent.stoppingDistance;
		}

		public void Initialize(Transform controllerTransform, Transform rigidbodyTransform, NavMeshAgent navAgent, CharacterController charController, int areaMask)
		{
			_controllerTransform = controllerTransform;
			_rigidbodyTransform = rigidbodyTransform;
			_navAgent = navAgent;
			_charController = charController;
			_savedAreaMask = areaMask;
		}

		public void LookAtPlayer()
		{
			//IL_002b: 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_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: 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)
			PlayerAvatar instance = PlayerAvatar.instance;
			if (!((Object)(object)instance == (Object)null) && !((Object)(object)_c