Decompiled source of VepMod v1.1.0

VepMod.dll

Decompiled a month 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.Rendering;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using VepMod.Enemies.Whispral;
using VepMod.Enemies.Whispral.Visuals;
using VepMod.Patchs;
using VepMod.VepFramework;
using VepMod.VepFramework.Audio;
using VepMod.VepFramework.Config;
using VepMod.VepFramework.Extensions;
using VepMod.VepFramework.Structures.FSM;
using VepMod.VepFramework.Structures.Range;
using WebRtcVadSharp;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Vep")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+be4c087c041c4823a6c3e289f18800a10bce2486")]
[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]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace 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);

		public static readonly RangeValue<float> AudioMinDuration = RangeValue.Float(0.1f, 2f, 0.3f);
	}
	[BepInPlugin("com.vep.vepMod", "VepMod", "1.1.0")]
	[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 ConfigEntry<float> ConfigAudioMinDuration;

		public static ConfigEntry<bool> ConfigVadEnabled;

		public static ConfigEntry<VadSensitivity> ConfigVadSensitivity;

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

		internal Harmony? Harmony { get; set; }

		private void Awake()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: 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_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: 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.");
			ConfigAudioMinDuration = ((BaseUnityPlugin)this).Config.BindRange("Audio Quality", "Min Duration", ConfigRanges.AudioMinDuration, "Minimum duration in seconds. Shorter recordings are rejected.");
			ConfigVadEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Audio Quality", "VAD Enabled", true, "Enable Voice Activity Detection (VAD) for speech filtering. Uses WebRTC ML model (requires x64). Disable if you have issues.");
			ConfigVadSensitivity = ((BaseUnityPlugin)this).Config.Bind<VadSensitivity>("Audio Quality", "VAD Sensitivity", VadSensitivity.Balanced, "Speech detection strictness. Permissive (ratio 0.20) keeps almost all voice but lets through more noise. Balanced (0.40) is the default best-F1 setting. Strict (0.60) filters more aggressively but may drop quiet voice.");
		}

		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 FileSystemSanitizer
	{
		private const string DefaultFallback = "unknown";

		private static readonly HashSet<string> WindowsReservedNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
		{
			"CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6",
			"COM7", "COM8", "COM9", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7",
			"LPT8", "LPT9"
		};

		public static string Sanitize(string input, string fallback = "unknown")
		{
			if (string.IsNullOrEmpty(input))
			{
				return fallback;
			}
			char[] invalidFileNameChars = Path.GetInvalidFileNameChars();
			string text = string.Join("_", input.Split(invalidFileNameChars, StringSplitOptions.RemoveEmptyEntries));
			text = text.TrimEnd('.', ' ');
			if (string.IsNullOrEmpty(text))
			{
				return fallback;
			}
			if (WindowsReservedNames.Contains(text))
			{
				text = "_" + text + "_";
			}
			return text;
		}
	}
	public static class TaskExtensions
	{
		public static IEnumerator AsCoroutine(this Task task)
		{
			while (!task.IsCompleted)
			{
				yield return null;
			}
			if (task.Exception != null)
			{
				throw task.Exception;
			}
		}
	}
}
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_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: 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.VepFramework.Audio
{
	public sealed class VadAudioValidator : IDisposable
	{
		private readonly VadValidationCriteria _criteria;

		private readonly WebRtcVad _vad;

		private readonly object _gate = new object();

		private bool _disposed;

		public VadAudioValidator(VadValidationCriteria? criteria = null)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Expected O, but got Unknown
			_criteria = criteria ?? VadValidationCriteria.FromSensitivity(VadSensitivity.Balanced);
			_vad = new WebRtcVad
			{
				OperatingMode = _criteria.OperatingMode,
				FrameLength = _criteria.FrameLength,
				SampleRate = _criteria.SampleRate
			};
		}

		public void Dispose()
		{
			lock (_gate)
			{
				if (!_disposed)
				{
					_vad.Dispose();
					_disposed = true;
				}
			}
		}

		public VadValidationResult Validate(float[] samples, int sampleRate)
		{
			//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_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Invalid comparison between I4 and Unknown
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Expected I4, but got Unknown
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			if (samples == null || samples.Length == 0)
			{
				return VadValidationResult.Rejected(VadRejectionReason.EmptyBuffer, null);
			}
			float num = (float)samples.Length / (float)sampleRate;
			if (num < _criteria.MinDurationSeconds)
			{
				return VadValidationResult.Rejected(VadRejectionReason.TooShort, new VadAnalysisResult(num, 0, 0, 0f));
			}
			byte[] array = ConvertToPcm16(samples);
			SampleRate targetSampleRate = GetTargetSampleRate(sampleRate);
			int frameSamplesCount = GetFrameSamplesCount(targetSampleRate, _criteria.FrameLength);
			int num2 = frameSamplesCount * 2;
			if (sampleRate != (int)targetSampleRate)
			{
				array = Resample(array, sampleRate, (int)targetSampleRate);
			}
			int num3 = array.Length / num2;
			if (num3 == 0)
			{
				return VadValidationResult.Rejected(VadRejectionReason.TooShort, new VadAnalysisResult(num, 0, 0, 0f));
			}
			int num4 = 0;
			byte[] array2 = new byte[num2];
			lock (_gate)
			{
				if (_disposed)
				{
					return VadValidationResult.Accepted(new VadAnalysisResult(num, num3, 0, 0f));
				}
				for (int i = 0; i < num3; i++)
				{
					int num5 = i * num2;
					if (num5 + num2 > array.Length)
					{
						break;
					}
					Array.Copy(array, num5, array2, 0, num2);
					if (_vad.HasSpeech(array2, targetSampleRate, _criteria.FrameLength))
					{
						num4++;
					}
				}
			}
			float num6 = (float)num4 / (float)num3;
			VadAnalysisResult vadAnalysisResult = new VadAnalysisResult(num, num3, num4, num6);
			if (num6 < _criteria.MinSpeechRatio)
			{
				return VadValidationResult.Rejected(VadRejectionReason.NotEnoughSpeech, vadAnalysisResult);
			}
			return VadValidationResult.Accepted(vadAnalysisResult);
		}

		private static byte[] ConvertToPcm16(float[] samples)
		{
			byte[] array = new byte[samples.Length * 2];
			for (int i = 0; i < samples.Length; i++)
			{
				short num = (short)(samples[i] * 32767f);
				array[i * 2] = (byte)(num & 0xFF);
				array[i * 2 + 1] = (byte)((num >> 8) & 0xFF);
			}
			return array;
		}

		private static SampleRate GetTargetSampleRate(int sampleRate)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			return (SampleRate)(sampleRate switch
			{
				8000 => 8000, 
				16000 => 16000, 
				32000 => 32000, 
				48000 => 48000, 
				_ => 16000, 
			});
		}

		private static int GetFrameSamplesCount(SampleRate sampleRate, FrameLength frameLength)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Expected I4, but got Unknown
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Invalid comparison between Unknown and I8
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Invalid comparison between Unknown and I8
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Invalid comparison between Unknown and I8
			int num = (int)sampleRate;
			int num2 = (((long)frameLength == 10) ? 10 : (((long)frameLength == 20) ? 20 : (((long)frameLength != 30) ? 20 : 30)));
			int num3 = num2;
			return num * num3 / 1000;
		}

		private static byte[] Resample(byte[] pcmBytes, int sourceSampleRate, int targetSampleRate)
		{
			if (pcmBytes == null || pcmBytes.Length < 2)
			{
				return Array.Empty<byte>();
			}
			if (sourceSampleRate == targetSampleRate)
			{
				return pcmBytes;
			}
			int num = pcmBytes.Length / 2;
			short[] array = new short[num];
			int num2 = 0;
			int num3 = 0;
			while (num2 < num)
			{
				array[num2] = (short)(pcmBytes[num3] | (pcmBytes[num3 + 1] << 8));
				num2++;
				num3 += 2;
			}
			double num4 = (double)sourceSampleRate / (double)targetSampleRate;
			int num5 = (int)Math.Floor((double)(num - 1) / num4);
			if (num5 <= 0)
			{
				return Array.Empty<byte>();
			}
			short[] array2 = new short[num5];
			double num6 = 0.0;
			for (int i = 0; i < num5; i++)
			{
				int num7 = (int)num6;
				double num8 = num6 - (double)num7;
				short num9 = array[num7];
				short num10 = array[num7 + 1];
				double num11 = (double)num9 + (double)(num10 - num9) * num8;
				if (num11 > 32767.0)
				{
					num11 = 32767.0;
				}
				else if (num11 < -32768.0)
				{
					num11 = -32768.0;
				}
				array2[i] = (short)num11;
				num6 += num4;
				if (num6 >= (double)(num - 1))
				{
					num6 = (double)num - 1.000001;
				}
			}
			byte[] array3 = new byte[num5 * 2];
			int num12 = 0;
			int num13 = 0;
			while (num12 < num5)
			{
				short num14 = array2[num12];
				array3[num13] = (byte)(num14 & 0xFF);
				array3[num13 + 1] = (byte)((num14 >> 8) & 0xFF);
				num12++;
				num13 += 2;
			}
			return array3;
		}
	}
	public sealed class VadValidationCriteria
	{
		public float MinDurationSeconds { get; set; } = 0.3f;

		public float MinSpeechRatio { get; set; } = 0.1f;

		public OperatingMode OperatingMode { get; set; }

		public FrameLength FrameLength { get; set; } = (FrameLength)20;

		public SampleRate SampleRate { get; set; } = (SampleRate)16000;

		public static VadValidationCriteria FromSensitivity(VadSensitivity sensitivity)
		{
			float minSpeechRatio = sensitivity switch
			{
				VadSensitivity.Permissive => 0.2f, 
				VadSensitivity.Strict => 0.6f, 
				_ => 0.4f, 
			};
			return new VadValidationCriteria
			{
				MinDurationSeconds = 0f,
				MinSpeechRatio = minSpeechRatio,
				OperatingMode = (OperatingMode)0,
				FrameLength = (FrameLength)20,
				SampleRate = (SampleRate)16000
			};
		}
	}
	public enum VadSensitivity
	{
		Permissive,
		Balanced,
		Strict
	}
	public readonly struct VadAnalysisResult
	{
		public float DurationSeconds { get; }

		public int TotalFrames { get; }

		public int SpeechFrames { get; }

		public float SpeechRatio { get; }

		public VadAnalysisResult(float durationSeconds, int totalFrames, int speechFrames, float speechRatio)
		{
			DurationSeconds = durationSeconds;
			TotalFrames = totalFrames;
			SpeechFrames = speechFrames;
			SpeechRatio = speechRatio;
		}

		public override string ToString()
		{
			return $"Duration: {DurationSeconds:F2}s, Speech: {SpeechFrames}/{TotalFrames} frames ({SpeechRatio:P1})";
		}
	}
	public readonly struct VadValidationResult
	{
		public bool IsValid { get; }

		public VadRejectionReason RejectionReason { get; }

		public VadAnalysisResult? Analysis { get; }

		private VadValidationResult(bool isValid, VadRejectionReason reason, VadAnalysisResult? analysis)
		{
			IsValid = isValid;
			RejectionReason = reason;
			Analysis = analysis;
		}

		public static VadValidationResult Accepted(VadAnalysisResult analysis)
		{
			return new VadValidationResult(isValid: true, VadRejectionReason.None, analysis);
		}

		public static VadValidationResult Rejected(VadRejectionReason reason, VadAnalysisResult? analysis)
		{
			return new VadValidationResult(isValid: false, reason, analysis);
		}

		public override string ToString()
		{
			if (!IsValid)
			{
				return $"Rejected ({RejectionReason}) - {Analysis}";
			}
			return $"Valid - {Analysis}";
		}
	}
	public enum VadRejectionReason
	{
		None,
		EmptyBuffer,
		TooShort,
		NotEnoughSpeech
	}
}
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())
			{
				var (frameSampleRate, channels) = VoiceFormatResolver.Resolve(__instance, buf.Length);
				VepFinder.LocalMimics.ProcessVoiceData(buf, frameSampleRate, channels);
			}
		}

		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_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Invalid comparison between Unknown and I4
			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
	{
	}
	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_0012: 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))}");
			}
		}
	}
	public static class VoiceFormatResolver
	{
		private sealed class Format
		{
			public int SampleRate { get; }

			public int Channels { get; }

			public Format(int sampleRate, int channels)
			{
				SampleRate = sampleRate;
				Channels = channels;
			}
		}

		private const int MinPlausibleRate = 8000;

		private const int MaxPlausibleRate = 48000;

		private static readonly VepLogger LOG = VepLogger.Create("VoiceFormatResolver", debugEnabled: true);

		private static readonly ConditionalWeakTable<object, Format> Cache = new ConditionalWeakTable<object, Format>();

		public static (int sampleRate, int channels) Resolve(object voice, int bufferLength)
		{
			if (voice == null)
			{
				return (sampleRate: 48000, channels: 1);
			}
			if (Cache.TryGetValue(voice, out Format value))
			{
				return (sampleRate: value.SampleRate, channels: value.Channels);
			}
			Format format = ResolveUncached(voice, bufferLength);
			Cache.Add(voice, format);
			return (sampleRate: format.SampleRate, channels: format.Channels);
		}

		private static Format ResolveUncached(object voice, int bufferLength)
		{
			object obj = null;
			try
			{
				obj = GetMemberValue(voice, "Info");
			}
			catch (Exception ex)
			{
				LOG.Warning("Could not read voice Info: " + ex.Message);
			}
			int? num = TryGetInt(voice, "InputSamplingRate");
			int? num2 = TryGetInt(voice, "InputChannels");
			int? num3 = TryGetInt(voice, "ForceChannels");
			int? num4 = ((obj != null) ? TryGetInt(obj, "SamplingRate") : ((int?)null));
			int? num5 = ((obj != null) ? TryGetInt(obj, "Channels") : ((int?)null));
			int? value = ((obj != null) ? TryGetInt(obj, "FrameDurationUs") : ((int?)null));
			int num6 = FirstPlausibleChannels(num2, num3, num5) ?? 1;
			int num7;
			string source;
			if (IsPlausibleRate(num))
			{
				num7 = num.Value;
				source = "InputSamplingRate";
			}
			else if (value.HasValue && value.GetValueOrDefault() > 0 && bufferLength > 0)
			{
				double num8 = (double)bufferLength / (double)num6;
				int num9 = (int)Math.Round(num8 * 1000000.0 / (double)value.Value);
				if (IsPlausibleRate(num9))
				{
					num7 = num9;
					source = "derived(FrameDurationUs)";
				}
				else
				{
					num7 = FallbackRate(num4, out source);
				}
			}
			else
			{
				num7 = FallbackRate(num4, out source);
			}
			LOG.Info($"Voice source format resolved: {num7} Hz, {num6} ch (via {source}). " + "Candidates: InputSamplingRate=" + Fmt(num) + ", InputChannels=" + Fmt(num2) + ", ForceChannels=" + Fmt(num3) + ", encoder=" + Fmt(num4) + "Hz/" + Fmt(num5) + "ch, " + $"FrameDurationUs={Fmt(value)}, bufferLength={bufferLength}.");
			return new Format(num7, num6);
		}

		private static int FallbackRate(int? encoderRate, out string source)
		{
			if (IsPlausibleRate(encoderRate))
			{
				source = "Info.SamplingRate(fallback)";
				return encoderRate.Value;
			}
			source = "default(fallback)";
			return 48000;
		}

		private static int? FirstPlausibleChannels(params int?[] candidates)
		{
			for (int i = 0; i < candidates.Length; i++)
			{
				int? result = candidates[i];
				if (result.HasValue)
				{
					int valueOrDefault = result.GetValueOrDefault();
					if (valueOrDefault >= 1 && valueOrDefault <= 8)
					{
						return result;
					}
				}
			}
			return null;
		}

		private static bool IsPlausibleRate(int? rate)
		{
			if (rate.HasValue)
			{
				int valueOrDefault = rate.GetValueOrDefault();
				if (valueOrDefault >= 8000)
				{
					return valueOrDefault <= 48000;
				}
			}
			return false;
		}

		private static int? TryGetInt(object obj, string name)
		{
			try
			{
				object memberValue = GetMemberValue(obj, name);
				object obj2 = memberValue;
				return (obj2 == null) ? ((int?)null) : ((obj2 is int value) ? new int?(value) : ((!(obj2 is Enum)) ? ((!(memberValue is IConvertible)) ? ((int?)null) : new int?(Convert.ToInt32(memberValue))) : new int?(Convert.ToInt32(memberValue))));
			}
			catch
			{
				return null;
			}
		}

		private static object? GetMemberValue(object obj, string name)
		{
			Type type = obj.GetType();
			while (type != null)
			{
				PropertyInfo property = type.GetProperty(name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (property != null && property.CanRead)
				{
					return property.GetValue(obj);
				}
				FieldInfo field = type.GetField(name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (field != null)
				{
					return field.GetValue(obj);
				}
				type = type.BaseType;
			}
			return null;
		}

		private static string Fmt(int? value)
		{
			return value?.ToString() ?? "n/a";
		}
	}
}
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)(num & 0xFF);
				array[i * 2 + 1] = (byte)((num >> 8) & 0xFF);
			}
			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 DroidAvatarAnimationController : MonoBehaviour
	{
		private static readonly VepLogger LOG = VepLogger.Create<DroidAvatarAnimationController>();

		private static readonly int MovingKey = Animator.StringToHash("Moving");

		private static readonly int SprintingKey = Animator.StringToHash("Sprinting");

		private static readonly int TurningKey = Animator.StringToHash("Turning");

		private static readonly int GrabbingKey = Animator.StringToHash("Grabbing");

		private static readonly int CrouchingKey = Animator.StringToHash("Crouching");

		private static readonly int CrawlingKey = Animator.StringToHash("Crawling");

		private static readonly int TumblingKey = Animator.StringToHash("Tumbling");

		private static readonly int TumblingMoveKey = Animator.StringToHash("TumblingMove");

		private static readonly int SlidingKey = Animator.StringToHash("Sliding");

		private static readonly int JumpingKey = Animator.StringToHash("Jumping");

		private static readonly int FallingKey = Animator.StringToHash("Falling");

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

		private static readonly int SprintingImpulseKey = Animator.StringToHash("SprintingImpulse");

		private DroidController _droid;

		private Animator _animator;

		private bool _wasSprinting;

		public float AnimationSpeedMultiplier { get; set; } = 1f;

		public void Initialize(DroidController droid, Animator animator)
		{
			_droid = droid;
			_animator = animator;
		}

		private void Update()
		{
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_animator == (Object)null) && !((Object)(object)_droid == (Object)null))
			{
				bool isInMovementState = _droid.IsInMovementState;
				bool flag = false;
				if (isInMovementState && (Object)(object)_droid.ControllerTransform != (Object)null && (Object)(object)_droid.Movement != (Object)null)
				{
					float num = Quaternion.Angle(_droid.ControllerTransform.rotation, _droid.Movement.TargetRotation);
					flag = num > 7f;
				}
				bool isSprinting = _droid.IsSprinting;
				bool flag2 = _droid.IsWalking || isSprinting;
				_animator.SetBool(MovingKey, flag2);
				_animator.SetBool(SprintingKey, isSprinting);
				_animator.SetBool(TurningKey, flag);
				_animator.SetBool(GrabbingKey, _droid.WantsGrabbing);
				_animator.SetBool(CrouchingKey, false);
				_animator.SetBool(CrawlingKey, false);
				_animator.SetBool(TumblingKey, false);
				_animator.SetBool(TumblingMoveKey, false);
				_animator.SetBool(SlidingKey, false);
				_animator.SetBool(JumpingKey, false);
				_animator.SetBool(FallingKey, _droid.IsFalling);
				_animator.SetBool(StunKey, false);
				if (isSprinting && !_wasSprinting)
				{
					_animator.SetTrigger(SprintingImpulseKey);
				}
				_wasSprinting = isSprinting;
				_animator.speed = AnimationSpeedMultiplier;
			}
		}
	}
	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;
					LOG.Debug($"IdleState: -> StalkApproach (dist={distanceToPlayer:F1})");
					return;
				}
				float value = Random.value;
				if (value < 0.25f)
				{
					base.Machine.NextStateStateId = StateId.CheckMap;
					LOG.Debug($"IdleState: -> CheckMap (roll={value:F2} < {0.25f})");
				}
				else
				{
					base.Machine.NextStateStateId = ((!(Random.value < 0.5f)) ? StateId.Wander : StateId.Sprint);
					LOG.Debug($"IdleState: -> {base.Machine.NextStateStateId}");
				}
			}

			public override void OnStateExit(StateId next)
			{
				base.OnStateExit(next);
				if ((Object)(object)_animator != (Object)null)
				{
					((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 _nextPrecomputeForward;

			private float _nextSwitchCheck;

			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 float RaiseDuration = 0.85f;

			private const float LowerDuration = 0.22f;

			private const float MinLookDuration = 0.5f;

			private const float MaxLookDuration = 3f;

			private Phase _currentPhase;

			private float _lookDuration;

			private float _phaseTimer;

			public override void OnStateEnter(StateId previous)
			{
				base.OnStateEnter(previous);
				base.Machine.Owner.IsWalking = false;
				base.Machine.Owner.IsSprinting = false;
				base.Machine.Owner.ResetPath();
				base.Machine.Owner.ShowMapTool(visible: true);
				_lookDuration = Random.Range(0.5f, 3f);
				_currentPhase = Phase.Raise;
				_phaseTimer = 0f;
				LOG.Debug(string.Format("CheckMapState: ENTER - LookDuration={0:F1}s, mapToolClone={1}", _lookDuration, ((Object)(object)base.Machine.Owner._mapToolClone != (Object)null) ? "ok" : "NULL"));
			}

			public override void OnStateUpdate()
			{
				base.OnStateUpdate();
				_phaseTimer += Time.deltaTime;
				switch (_currentPhase)
				{
				case Phase.Raise:
					if (_phaseTimer >= 0.85f)
					{
						_currentPhase = Phase.Look;
						_phaseTimer = 0f;
						LOG.Debug("CheckMapState: -> Look");
					}
					break;
				case Phase.Look:
					if (_phaseTimer >= _lookDuration)
					{
						base.Machine.Owner.ShowMapTool(visible: false);
						_currentPhase = Phase.Lower;
						_phaseTimer = 0f;
						LOG.Debug("CheckMapState: -> Lower");
					}
					break;
				case Phase.Lower:
					if (_phaseTimer >= 0.22f)
					{
						LOG.Debug("CheckMapState: Done, back to Idle");
						base.Machine.NextStateStateId = StateId.Idle;
					}
					break;
				}
			}

			public override void OnStateExit(StateId next)
			{
				base.OnStateExit(next);
				LOG.Debug($"CheckMapState: EXIT -> {next}");
				base.Machine.Owner.ShowMapTool(visible: false);
			}
		}

		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 readonly MaterialTrigger _materialTrigger = new MaterialTrigger();

		private DroidFaceAnimationController _animController;

		private DroidRightArmPoseController? _armPoseController;

		private DroidLeftArmPoseController? _leftArmPoseController;

		private DroidAvatarAnimationController _avatarAnimController;

		private CharacterController _charController;

		private DroidEyeLookAtController? _eyeLookController;

		private GameObject? _mapToolClone;

		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 HasChangedMovementState { get; set; }

		public bool WantsGrabbing { 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;
			}
		}

		public bool IsInMovementState => DroidHelpers.IsMovementState(Fsm.CurrentStateStateId);

		public bool IsFalling
		{
			get
			{
				if ((Object)(object)Movement != (Object)null)
				{
					return Movement.IsFalling;
				}
				return false;
			}
		}

		public string DebugStateName => Fsm.CurrentStateStateId.ToString();

		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(((Object)(object)Animator != (Object)null) ? ((Component)Animator).transform : null);
				Movement.SyncNavAgentPosition(isMovementState);
			}
		}

		public void ShowMapTool(bool visible)
		{
			LOG.Debug(string.Format("ShowMapTool({0}) - clone={1}", visible, ((Object)(object)_mapToolClone != (Object)null) ? "ok" : "NULL"));
			if ((Object)(object)_mapToolClone != (Object)null)
			{
				_mapToolClone.SetActive(visible);
			}
			WantsGrabbing = visible;
		}

		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);
				}
			}
		}

		public void DebugTeleport(Vector3 worldPosition)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)ControllerTransform == (Object)null))
			{
				if ((Object)(object)_charController != (Object)null)
				{
					((Collider)_charController).enabled = false;
				}
				ControllerTransform.position = worldPosition;
				if ((Object)(object)_charController != (Object)null)
				{
					((Collider)_charController).enabled = true;
				}
			}
		}

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

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

		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()
		{
			if ((Object)(object)Movement != (Object)null)
			{
				return Movement.TrySetDestinationToPlayer();
			}
			return false;
		}

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

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

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

		public static DroidController? Create(PlayerAvatar sourcePlayer, Vector3 spawnPosition)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			if (!DroidPrefabLoader.IsAvailable)
			{
				LOG.Warning("LostDroid prefab not available");
				return null;
			}
			GameObject val = Object.Instantiate<GameObject>(DroidPrefabLoader.DroidPrefab, 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_0053: Unknown result type (might be due to invalid IL or missing references)
			SourcePlayer = sourcePlayer;
			FindCriticalTransforms();
			SaveNavMeshSettings();
			DisableEnemyComponents();
			SetupNavigation();
			SetupMovementController();
			SetupClonedVisuals();
			SetupAnimationController();
			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);
			if ((Object)(object)Animator != (Object)null)
			{
				_avatarAnimController = ((Component)this).gameObject.AddComponent<DroidAvatarAnimationController>();
				_avatarAnimController.Initialize(this, Animator);
			}
			Transform val = (((Object)(object)Animator != (Object)null) ? ((Component)Animator).transform : ((Component)this).transform);
			Transform val2 = DroidHelpers.FindChildByName(val, "code_head_top");
			if ((Object)(object)val2 != (Object)null)
			{
				_animController.SetupTalking(val2);
			}
			SetupEyelidsFromClone(val);
		}

		private void SetupEyelidsFromClone(Transform visualsRoot)
		{
			try
			{
				Transform val = DroidHelpers.FindChildByName(visualsRoot, "EYELIDS LEFT");
				Transform val2 = DroidHelpers.FindChildByName(visualsRoot, "EYELIDS RIGHT");
				if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null)
				{
					LOG.Warning("EYELIDS LEFT/RIGHT not found on cloned visuals");
					return;
				}
				FindEyelidRotations(val, out Transform upperX, out Transform upperZ, out Transform lowerX);
				FindEyelidRotations(val2, out Transform upperX2, out Transform upperZ2, out Transform lowerX2);
				((Component)val).gameObject.SetActive(false);
				((Component)val2).gameObject.SetActive(false);
				_animController.SetupEyelids(((Component)val).gameObject, ((Component)val2).gameObject, upperX, upperZ, lowerX, upperX2, upperZ2, lowerX2);
			}
			catch (Exception ex)
			{
				LOG.Error("SetupEyelidsFromClone: Exception - " + ex.Message + "\n" + ex.StackTrace);
			}
		}

		private static void FindEyelidRotations(Transform eyelidsRoot, out Transform? upperX, out Transform? upperZ, out Transform? lowerX)
		{
			upperX = null;
			upperZ = null;
			lowerX = null;
			Transform[] componentsInChildren = ((Component)eyelidsRoot).GetComponentsInChildren<Transform>(true);
			foreach (Transform val in componentsInChildren)
			{
				switch (((Object)val).name)
				{
				case "eyelid_upper":
					upperX = val;
					break;
				case "eyelid_upper_rotation":
					upperZ = val;
					break;
				case "eyelid_lower":
					lowerX = val;
					break;
				}
			}
		}

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

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

		public void PlayMediumFootstep()
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			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 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_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Expected O, but got Unknown
			//IL_0097: 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_01ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			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 SetupClonedVisuals()
		{
			if ((Object)(object)SourcePlayer == (Object)null)
			{
				LOG.Error("Cannot clone visuals: source player is null");
				return;
			}
			Transform val = DroidVisualsClone.FindCube(((Component)this).transform);
			if ((Object)(object)val == (Object)null)
			{
				LOG.Error("Cannot clone visuals: MyDroid/Enable/Cube not found");
				return;
			}
			DroidVisualsClone.SanitizeCube(val);
			Animator = ((Component)val).GetComponent<Animator>();
			DroidVisualsClone.StripExistingRig(val);
			if (!DroidVisualsClone.TryCloneRig(SourcePlayer, val, out GameObject cloneRig))
			{
				LOG.Warning("Failed to clone source player [RIG]");
			}
			else if ((Object)(object)Animator != (Object)null && (Object)(object)cloneRig != (Object)null)
			{
				((Behaviour)Animator).enabled = true;
				Animator.applyRootMotion = false;
				Animator.Rebind();
				Animator.Update(0f);
				DroidVisualsClone.AttachRelay(Animator, this, cloneRig);
				DroidVisualsClone.TryCloneFlashlight(SourcePlayer, cloneRig);
				DroidVisualsClone.TryCloneMapTool(SourcePlayer, cloneRig, out _mapToolClone);
				SetupArmAndEyeMimics(cloneRig);
			}
			else if ((Object)(object)Animator == (Object)null)
			{
				LOG.Warning("Cube has no Animator after SanitizeCube");
			}
		}

		private void SetupArmAndEyeMimics(GameObject cloneRig)
		{
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)SourcePlayer == (Object)null || (Object)(object)cloneRig == (Object)null)
			{
				return;
			}
			PlayerAvatarVisuals playerAvatarVisuals = SourcePlayer.playerAvatarVisuals;
			if ((Object)(object)playerAvatarVisuals == (Object)null)
			{
				LOG.Warning("SetupArmAndEyeMimics: SourcePlayer.playerAvatarVisuals is null");
				return;
			}
			PlayerAvatarRightArm component = ((Component)playerAvatarVisuals).GetComponent<PlayerAvatarRightArm>();
			if ((Object)(object)component != (Object)null && (Object)(object)component.rightArmTransform != (Object)null)
			{
				Transform val = DroidHelpers.FindChildByName(cloneRig.transform, ((Object)component.rightArmTransform).name);
				if ((Object)(object)val != (Object)null)
				{
					_armPoseController = ((Component)this).gameObject.AddComponent<DroidRightArmPoseController>();
					_armPoseController.Initialize(this, val, component.basePose, component.mapPose, component.poseCurve, component.poseSpeed);
					LOG.Debug("DroidRightArmPoseController initialized on bone '" + ((Object)component.rightArmTransform).name + "'");
				}
				else
				{
					LOG.Warning("SetupArmAndEyeMimics: bone '" + ((Object)component.rightArmTransform).name + "' not found in clone rig");
				}
			}
			else
			{
				LOG.Warning("SetupArmAndEyeMimics: no PlayerAvatarRightArm on source player");
			}
			PlayerAvatarLeftArm component2 = ((Component)playerAvatarVisuals).GetComponent<PlayerAvatarLeftArm>();
			if ((Object)(object)component2 != (Object)null && (Object)(object)component2.leftArmTransform != (Object)null)
			{
				Transform val2 = DroidHelpers.FindChildByName(cloneRig.transform, ((Object)component2.leftArmTransform).name);
				if ((Object)(object)val2 != (Object)null)
				{
					_leftArmPoseController = ((Component)this).gameObject.AddComponent<DroidLeftArmPoseController>();
					_leftArmPoseController.Initialize(val2, component2.basePose, component2.flashlightPose, component2.poseCurve, component2.poseSpeed);
					LOG.Debug("DroidLeftArmPoseController initialized on bone '" + ((Object)component2.leftArmTransform).name + "'");
				}
				else
				{
					LOG.Warning("SetupArmAndEyeMimics: left arm bone '" + ((Object)component2.leftArmTransform).name + "' not found in clone rig");
				}
			}
			else
			{
				LOG.Warning("SetupArmAndEyeMimics: no PlayerAvatarLeftArm on source player");
			}
			PlayerEyes component3 = ((Component)playerAvatarVisuals).GetComponent<PlayerEyes>();
			if ((Object)(object)component3 != (Object)null && (Object)(object)component3.eyeLeft != (Object)null && (Object)(object)component3.eyeRight != (Object)null)
			{
				Transform val3 = DroidHelpers.FindChildByName(cloneRig.transform, ((Object)component3.eyeLeft).name);
				Transform val4 = DroidHelpers.FindChildByName(cloneRig.transform, ((Object)component3.eyeRight).name);
				Transform val5 = (((Object)(object)_mapToolClone != (Object)null) ? DroidHelpers.FindChildByName(_mapToolClone.transform, "Player Look Target") : null);
				if ((Object)(object)val3 != (Object)null && (Object)(object)val4 != (Object)null && (Object)(object)val5 != (Object)null)
				{
					_eyeLookController = ((Component)this).gameObject.AddComponent<DroidEyeLookAtController>();
					_eyeLookController.Initialize(this, val3, val4, val5);
					LOG.Debug("DroidEyeLookAtController initialized");
				}
				else
				{
					LOG.Warning("SetupArmAndEyeMimics: eye bones or lookTarget missing " + $"(eyeL={(Object)(object)val3 != (Object)null}, eyeR={(Object)(object)val4 != (Object)null}, lookTarget={(Object)(object)val5 != (Object)null})");
				}
			}
			else
			{
				LOG.Warning("SetupArmAndEyeMimics: no PlayerEyes on source player or eyeLeft/Right null");
			}
		}

		private void SetupNavigation()
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)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_0075: 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_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			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_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: 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 DroidEyeLookAtController : MonoBehaviour
	{
		private const float ClampX = 50f;

		private const float ClampY = 30f;

		private const float ReturnSpeed = 8f;

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

		private DroidController _droid;

		private Transform _eyeLeft;

		private Quaternion _eyeLeftRest;

		private Transform _eyeRight;

		private Quaternion _eyeRightRest;

		private Transform _lookTarget;

		private void LateUpdate()
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_droid == (Object)null)
			{
				return;
			}
			if (_droid.WantsGrabbing && (Object)(object)_lookTarget != (Object)null)
			{
				ApplyLookAt(_eyeLeft);
				ApplyLookAt(_eyeRight);
				return;
			}
			if ((Object)(object)_eyeLeft != (Object)null)
			{
				_eyeLeft.localRotation = Quaternion.Slerp(_eyeLeft.localRotation, _eyeLeftRest, 8f * Time.deltaTime);
			}
			if ((Object)(object)_eyeRight != (Object)null)
			{
				_eyeRight.localRotation = Quaternion.Slerp(_eyeRight.localRotation, _eyeRightRest, 8f * Time.deltaTime);
			}
		}

		public void Initialize(DroidController droid, Transform eyeLeft, Transform eyeRight, Transform lookTarget)
		{
			//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_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			_droid = droid;
			_eyeLeft = eyeLeft;
			_eyeRight = eyeRight;
			_lookTarget = lookTarget;
			if ((Object)(object)eyeLeft != (Object)null)
			{
				_eyeLeftRest = eyeLeft.localRotation;
			}
			if ((Object)(object)eyeRight != (Object)null)
			{
				_eyeRightRest = eyeRight.localRotation;
			}
		}

		private void ApplyLookAt(Transform eye)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: 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_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: 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_0072: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)eye == (Object)null))
			{
				Vector3 val = _lookTarget.position - eye.position;
				if (!(((Vector3)(ref val)).sqrMagnitude < 0.0001f))
				{
					eye.rotation = Quaternion.LookRotation(val);
					Vector3 localEulerAngles = eye.localEulerAngles;
					localEulerAngles.y = ClampAngle(localEulerAngles.y, 30f);
					localEulerAngles.x = ClampAngle(localEulerAngles.x, 50f);
					eye.localEulerAngles = localEulerAngles;
				}
			}
		}

		private static float ClampAngle(float angle, float limit)
		{
			if (angle > limit && angle < 180f)
			{
				return limit;
			}
			if (angle < 360f - limit && angle > 180f)
			{
				return 360f - limit;
			}
			return angle;
		}
	}
	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_0146: 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_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0200: Unknown result type (might be due to invalid IL or missing references)
			//IL_0224: Unknown result type (might be due to invalid IL or missing references)
			//IL_0234: 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_025f: Unknown result type (might be due to invalid IL or missing references)
			//IL_026f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0276: Unknown result type (might be due to invalid IL or missing references)
			//IL_029b: 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_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: 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_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			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_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_

WebRtcVadSharp.dll

Decompiled a month ago
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using WebRtcVadSharp.WebRtc;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("Jay Miller")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright (c) 2020 Jay Miller")]
[assembly: AssemblyDescription(".NET Standard interface for the WebRTC voice activity detection (VAD) component.")]
[assembly: AssemblyFileVersion("1.3.2.0")]
[assembly: AssemblyInformationalVersion("1.3.2+fdd4f4ef0570520f9031f994d8b587fba0e4f31c")]
[assembly: AssemblyProduct("WebRtcVadSharp")]
[assembly: AssemblyTitle("WebRtcVadSharp")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/ladenedge/WebRtcVadSharp.git")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.3.2.0")]
[module: UnverifiableCode]
namespace WebRtcVadSharp
{
	public enum FrameLength : long
	{
		Is10ms = 10L,
		Is20ms = 20L,
		Is30ms = 30L
	}
	public interface IWebRtcVad
	{
		SampleRate SampleRate { get; set; }

		FrameLength FrameLength { get; set; }

		OperatingMode OperatingMode { get; set; }

		bool HasSpeech(byte[] audioFrame);

		bool HasSpeech(byte[] audioFrame, SampleRate sampleRate, FrameLength frameLength);

		bool HasSpeech(short[] audioFrame);

		bool HasSpeech(short[] audioFrame, SampleRate sampleRate, FrameLength frameLength);

		bool HasSpeech(IntPtr audioFrame);

		bool HasSpeech(IntPtr audioFrame, SampleRate sampleRate, FrameLength frameLength);
	}
	public enum OperatingMode
	{
		HighQuality,
		LowBitrate,
		Aggressive,
		VeryAggressive
	}
	public enum SampleRate
	{
		Is8kHz = 8000,
		Is16kHz = 16000,
		Is32kHz = 32000,
		Is48kHz = 48000
	}
	public class WebRtcVad : IWebRtcVad, IDisposable
	{
		private readonly IWebRtcDll _webrtc;

		private IntPtr _handle;

		private SampleRate _rate;

		private FrameLength _length;

		private OperatingMode _mode;

		private bool hasDisposed;

		public SampleRate SampleRate
		{
			get
			{
				return _rate;
			}
			set
			{
				ValidateRateAndFrameLength(value, FrameLength);
				_rate = value;
			}
		}

		public FrameLength FrameLength
		{
			get
			{
				return _length;
			}
			set
			{
				ValidateRateAndFrameLength(SampleRate, value);
				_length = value;
			}
		}

		public OperatingMode OperatingMode
		{
			get
			{
				return _mode;
			}
			set
			{
				int result = _webrtc.SetMode(_handle, (int)value);
				ValidateSetMode(result, _handle, value);
				_mode = value;
			}
		}

		public WebRtcVad()
			: this(new WebRtcDll())
		{
		}

		public WebRtcVad(IWebRtcDll library)
		{
			_webrtc = library ?? throw new ArgumentNullException("library");
			_mode = OperatingMode.HighQuality;
			_rate = SampleRate.Is8kHz;
			_length = FrameLength.Is10ms;
			try
			{
				_handle = _webrtc.Create();
				int result = _webrtc.Init(_handle);
				ValidateInitialize(result, _handle);
			}
			catch (DllNotFoundException inner)
			{
				string currentDirectory = Directory.GetCurrentDirectory();
				throw new DllNotFoundException("Unable to load DLL 'WebRtcVad.dll' or a dependency. Be sure it exists in '" + currentDirectory + "' or elsewhere in the DLL search path.", inner);
			}
		}

		public bool HasSpeech(byte[] audioFrame)
		{
			return HasSpeech(audioFrame, _rate, _length);
		}

		public bool HasSpeech(byte[] audioFrame, SampleRate sampleRate, FrameLength frameLength)
		{
			ulong frame_length = CalculateSamples(sampleRate, frameLength);
			int result = _webrtc.Process(_handle, (int)sampleRate, audioFrame, frame_length);
			return ValidateProcess(result, _handle, sampleRate, audioFrame, frameLength);
		}

		public bool HasSpeech(short[] audioFrame)
		{
			return HasSpeech(audioFrame, _rate, _length);
		}

		public bool HasSpeech(short[] audioFrame, SampleRate sampleRate, FrameLength frameLength)
		{
			ulong frame_length = CalculateSamples(sampleRate, frameLength);
			int result = _webrtc.Process(_handle, (int)sampleRate, audioFrame, frame_length);
			return ValidateProcess(result, _handle, sampleRate, audioFrame, frameLength);
		}

		public bool HasSpeech(IntPtr audioFrame)
		{
			return HasSpeech(audioFrame, _rate, _length);
		}

		public bool HasSpeech(IntPtr audioFrame, SampleRate sampleRate, FrameLength frameLength)
		{
			ulong frame_length = CalculateSamples(sampleRate, frameLength);
			int result = _webrtc.Process(_handle, (int)sampleRate, audioFrame, frame_length);
			return ValidateProcess(result, _handle, sampleRate, audioFrame, frameLength);
		}

		private ulong CalculateSamples(SampleRate rate, FrameLength length)
		{
			return (ulong)rate / 1000uL * (ulong)length;
		}

		private void ValidateInitialize(int result, IntPtr handle)
		{
			if (result == 0)
			{
				return;
			}
			ValidateHandle(handle);
			throw new InvalidOperationException($"Could not initialize WebRTC [Init({handle}) = {result}].");
		}

		private void ValidateSetMode(int result, IntPtr handle, OperatingMode mode)
		{
			if (result == 0)
			{
				return;
			}
			ValidateHandle(handle);
			ValidateEnum(mode);
			throw new InvalidOperationException($"Could not set operating mode [SetMode({handle}, {mode}) = {result}].");
		}

		private void ValidateRateAndFrameLength(SampleRate sampleRate, FrameLength frameLength)
		{
			ulong num = CalculateSamples(sampleRate, frameLength);
			int num2 = _webrtc.ValidRateAndFrameLength((int)sampleRate, num);
			if (num2 == 0)
			{
				return;
			}
			ValidateEnum(sampleRate);
			ValidateEnum(frameLength);
			throw new InvalidOperationException($"Could not validate rate/length [ValidRateAndFrameLength({(int)sampleRate}, {num}) = {num2}].");
		}

		private bool ValidateProcess(int result, IntPtr handle, SampleRate sampleRate, byte[] audioFrame, FrameLength frameLength)
		{
			return ValidateProcess(result, handle, sampleRate, $"byte[{audioFrame.Length}]", frameLength);
		}

		private bool ValidateProcess(int result, IntPtr handle, SampleRate sampleRate, short[] audioFrame, FrameLength frameLength)
		{
			return ValidateProcess(result, handle, sampleRate, $"short[{audioFrame.Length}]", frameLength);
		}

		private bool ValidateProcess(int result, IntPtr handle, SampleRate sampleRate, IntPtr audioFrame, FrameLength frameLength)
		{
			return ValidateProcess(result, handle, sampleRate, "0x" + audioFrame.ToInt64().ToString("X8"), frameLength);
		}

		private bool ValidateProcess(int result, IntPtr handle, SampleRate sampleRate, string frameDescription, FrameLength frameLength)
		{
			switch (result)
			{
			case 0:
				return false;
			case 1:
				return true;
			default:
				ValidateHandle(handle);
				ValidateEnum(sampleRate);
				ValidateEnum(frameLength);
				throw new InvalidOperationException($"Could not process audio frame [Process({handle}, {sampleRate}, <{frameDescription}>, {frameLength}) = {result}].");
			}
		}

		private void ValidateHandle(IntPtr handle)
		{
			if (handle == IntPtr.Zero)
			{
				throw new ObjectDisposedException("Invalid WebRTC handle; object appears to have been disposed.");
			}
		}

		private void ValidateEnum<T>(T val)
		{
			if (Enum.IsDefined(typeof(T), val))
			{
				return;
			}
			string arg = string.Join(", ", Enum.GetValues(typeof(T)).OfType<T>());
			throw new ArgumentException($"{val} was not a valid {typeof(T).Name}. Valid values are [{arg}].");
		}

		protected virtual void Dispose(bool disposing)
		{
			if (hasDisposed)
			{
				return;
			}
			if (disposing)
			{
				if (_webrtc != null)
				{
					_webrtc.Free(_handle);
				}
				_handle = IntPtr.Zero;
			}
			hasDisposed = true;
		}

		public void Dispose()
		{
			Dispose(disposing: true);
		}
	}
}
namespace WebRtcVadSharp.WebRtc
{
	public interface IWebRtcDll
	{
		IntPtr Create();

		int Init(IntPtr handle);

		int SetMode(IntPtr self, int mode);

		int ValidRateAndFrameLength(int rate, ulong frame_length);

		int Process(IntPtr handle, int fs, byte[] audio_frame, ulong frame_length);

		int Process(IntPtr handle, int fs, short[] audio_frame, ulong frame_length);

		int Process(IntPtr handle, int fs, IntPtr audio_frame, ulong frame_length);

		void Free(IntPtr handle);
	}
	public class WebRtcDll : IWebRtcDll
	{
		private class NativeMethods
		{
			[DllImport("webrtcvad")]
			public static extern IntPtr Vad_Create();

			[DllImport("webrtcvad")]
			public static extern int Vad_Init(IntPtr handle);

			[DllImport("webrtcvad")]
			public static extern int Vad_SetMode(IntPtr self, int mode);

			[DllImport("webrtcvad")]
			public static extern int Vad_ValidRateAndFrameLength(int rate, UIntPtr frame_length);

			[DllImport("webrtcvad")]
			public static extern int Vad_Process(IntPtr handle, int fs, IntPtr audio_frame, UIntPtr frame_length);

			[DllImport("webrtcvad")]
			public static extern void Vad_Free(IntPtr handle);
		}

		public IntPtr Create()
		{
			return NativeMethods.Vad_Create();
		}

		public int Init(IntPtr handle)
		{
			return NativeMethods.Vad_Init(handle);
		}

		public unsafe int Process(IntPtr handle, int fs, byte[] audio_frame, ulong frame_length)
		{
			UIntPtr frame_length2 = new UIntPtr(frame_length);
			fixed (byte* ptr = audio_frame)
			{
				return NativeMethods.Vad_Process(handle, fs, (IntPtr)ptr, frame_length2);
			}
		}

		public unsafe int Process(IntPtr handle, int fs, short[] audio_frame, ulong frame_length)
		{
			UIntPtr frame_length2 = new UIntPtr(frame_length);
			fixed (short* ptr = audio_frame)
			{
				return NativeMethods.Vad_Process(handle, fs, (IntPtr)ptr, frame_length2);
			}
		}

		public int Process(IntPtr handle, int fs, IntPtr audio_frame, ulong frame_length)
		{
			UIntPtr frame_length2 = new UIntPtr(frame_length);
			return NativeMethods.Vad_Process(handle, fs, audio_frame, frame_length2);
		}

		public int SetMode(IntPtr self, int mode)
		{
			return NativeMethods.Vad_SetMode(self, mode);
		}

		public int ValidRateAndFrameLength(int rate, ulong frame_length)
		{
			UIntPtr frame_length2 = new UIntPtr(frame_length);
			return NativeMethods.Vad_ValidRateAndFrameLength(rate, frame_length2);
		}

		public void Free(IntPtr handle)
		{
			NativeMethods.Vad_Free(handle);
		}
	}
}