Decompiled source of VepMod v2.1.2

VepMod.dll

Decompiled 3 days ago
using System;
using System.Buffers.Binary;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
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.Text;
using System.Threading;
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 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.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+3967bce5509c24fd9bd2a39aec29923da4cd5f99")]
[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;
		}
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, Inherited = false)]
	internal sealed class InterpolatedStringHandlerAttribute : Attribute
	{
	}
}
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 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", "2.1.2")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class VepMod : BaseUnityPlugin
	{
		public static ConfigEntry<float> ConfigVoiceVolume;

		public static ConfigEntry<bool> ConfigLethalHallucinations;

		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;

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

		private static VadAudioValidator? _vad;

		public static VoiceBanks VoiceBanks { get; private set; }

		public static VoiceRecorder VoiceRecorder { get; private set; }

		public static SpeechCheck? SpeechCheck { get; private set; }

		private void Awake()
		{
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			PreventDelete();
			InitConfig();
			LethalHallucinations.Init();
			VoiceBanks = new VoiceBanks(Path.Combine(Application.dataPath, "AudioFiles"), () => ConfigSamplesPerPlayer.Value);
			VepLogger lOG = LOG;
			InvariantLogMessage message = new InvariantLogMessage(29, 1);
			message.AppendLiteral("Voice Bank store created at ");
			message.AppendFormatted(VoiceBanks.RootFolder);
			message.AppendLiteral(".");
			lOG.Debug(ref message);
			VoiceRecorder = new VoiceRecorder(VepLogger.Create<VoiceRecorder>(debugEnabled: true).Debug);
			SpeechCheck = CreateSpeechCheck();
			new Harmony("VepMod.Plugin").PatchAll();
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"{((BaseUnityPlugin)this).Info.Metadata.GUID} v{((BaseUnityPlugin)this).Info.Metadata.Version} has loaded!");
			((MonoBehaviour)this).StartCoroutine(HallucinationPrefabLoader.PreloadAsync(delegate(bool success)
			{
				if (success)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)"Hallucination prefab preloaded successfully.");
				}
				else
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)"Hallucination prefab preload failed - hallucinations may not work.");
				}
			}));
		}

		private void OnDestroy()
		{
			_vad?.Dispose();
		}

		private static SpeechCheck? CreateSpeechCheck()
		{
			if (!ConfigVadEnabled.Value)
			{
				LOG.Info("VAD disabled in the config: Captures will not be checked for speech.");
				return null;
			}
			try
			{
				VadValidationCriteria vadValidationCriteria = VadValidationCriteria.FromSensitivity(ConfigVadSensitivity.Value);
				VadAudioValidator vad = new VadAudioValidator(vadValidationCriteria);
				_vad = vad;
				VepLogger lOG = LOG;
				InvariantLogMessage message = new InvariantLogMessage(49, 2);
				message.AppendLiteral("VAD handle created (sensitivity=");
				message.AppendFormatted(ConfigVadSensitivity.Value);
				message.AppendLiteral(", ");
				message.AppendLiteral("speechRatio>=");
				message.AppendFormatted(vadValidationCriteria.MinSpeechRatio, "F2");
				message.AppendLiteral(").");
				lOG.Info(ref message);
				return delegate(float[] speech, int sampleRate)
				{
					VadValidationResult vadValidationResult = vad.Validate(speech, sampleRate);
					return (hasSpeech: vadValidationResult.IsValid, analysis: vadValidationResult.ToString());
				};
			}
			catch (Exception ex)
			{
				VepLogger lOG2 = LOG;
				InvariantLogMessage message2 = new InvariantLogMessage(68, 1);
				message2.AppendLiteral("VAD initialization failed, Captures will not be checked for speech: ");
				message2.AppendFormatted(ex.Message);
				lOG2.Warning(ref message2);
				return null;
			}
		}

		private void InitConfig()
		{
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: 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.");
			ConfigLethalHallucinations = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Lethal Hallucinations", true, "Whether a Hallucination stalking a player who never looks at it kills them. Only the host's value counts.");
			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 Mimics while Haunted by a Whispral.", "Maximum time between Mimics while Haunted by a Whispral.");
			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 while Haunted by a Whispral.", (AcceptableValueBase)null, Array.Empty<object>()));
			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;
		}
	}
}
namespace VepMod.VepFramework
{
	[InterpolatedStringHandler]
	public ref struct InvariantLogMessage
	{
		private readonly StringBuilder _builder;

		public InvariantLogMessage(int literalLength, int formattedCount)
		{
			_builder = new StringBuilder(literalLength + formattedCount * 8);
		}

		public void AppendLiteral(string value)
		{
			_builder.Append(value);
		}

		public void AppendFormatted<T>(T value)
		{
			AppendFormatted(value, null);
		}

		public void AppendFormatted<T>(T value, string? format)
		{
			_builder.Append((value is IFormattable formattable) ? formattable.ToString(format, CultureInfo.InvariantCulture) : value?.ToString());
		}

		public override string ToString()
		{
			return _builder.ToString();
		}
	}
	public sealed class VepLogger
	{
		private const string Prefix = "VepMod";

		private const bool DebugBuild = false;

		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)Stamped(message));
			}
		}

		public void Debug(ref InvariantLogMessage message)
		{
			Debug(message.ToString());
		}

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

		public void Info(ref InvariantLogMessage message)
		{
			Info(message.ToString());
		}

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

		public void Warning(ref InvariantLogMessage message)
		{
			Warning(message.ToString());
		}

		public void Error(string message)
		{
			_log.LogError((object)Stamped(message));
		}

		public void Error(ref InvariantLogMessage message)
		{
			Error(message.ToString());
		}

		private static string Stamped(string message)
		{
			return $"{DateTime.UtcNow:HH:mm:ss.fff} {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 = (TMachine)this;
			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)
		{
			VepLogger lOG = LOG;
			InvariantLogMessage message = new InvariantLogMessage(62, 1);
			message.AppendLiteral("EnemyDirector.FirstSpawnPointAdd: ");
			message.AppendFormatted<EnemyParent>(_enemyParent);
			message.AppendLiteral(" added as first spawn point.");
			lOG.Debug(ref message);
		}
	}
	[HarmonyPatch(typeof(RoundDirector), "ExtractionCompletedAllRPC")]
	public class ExtractionsCompletedLoggerPatch
	{
		private static readonly VepLogger LOG = VepLogger.Create<ExtractionsCompletedLoggerPatch>();

		[HarmonyPostfix]
		private static void Postfix(RoundDirector __instance)
		{
			if (__instance.allExtractionPointsCompleted)
			{
				LOG.Debug("RoundDirector: every extraction point is completed, the end-of-level rule now moves every enemy.");
			}
		}
	}
	[HarmonyPatch]
	internal static class FakePlayerAvatarPatch
	{
		[HarmonyPrefix]
		[HarmonyPatch(typeof(PlayerAvatar), "Awake")]
		private static bool Awake_Prefix(PlayerAvatar __instance)
		{
			return !HallucinationBody.BlocksCall(__instance, "Awake");
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(PlayerAvatar), "Start")]
		private static bool Start_Prefix(PlayerAvatar __instance)
		{
			return !HallucinationBody.BlocksCall(__instance, "Start");
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(PlayerAvatar), "OnDestroy")]
		private static bool OnDestroy_Prefix(PlayerAvatar __instance)
		{
			return !HallucinationBody.BlocksCall(__instance, "OnDestroy");
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(PlayerAvatar), "Footstep")]
		private static bool Footstep_Prefix(PlayerAvatar __instance)
		{
			return !HallucinationBody.BlocksCall(__instance, "Footstep");
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(PlayerAvatar), "StandToCrouch")]
		private static bool StandToCrouch_Prefix(PlayerAvatar __instance)
		{
			return !HallucinationBody.BlocksCall(__instance, "StandToCrouch");
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(PlayerAvatar), "CrouchToStand")]
		private static bool CrouchToStand_Prefix(PlayerAvatar __instance)
		{
			return !HallucinationBody.BlocksCall(__instance, "CrouchToStand");
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(PlayerAvatar), "CrouchToCrawl")]
		private static bool CrouchToCrawl_Prefix(PlayerAvatar __instance)
		{
			return !HallucinationBody.BlocksCall(__instance, "CrouchToCrawl");
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(PlayerAvatar), "CrawlToCrouch")]
		private static bool CrawlToCrouch_Prefix(PlayerAvatar __instance)
		{
			return !HallucinationBody.BlocksCall(__instance, "CrawlToCrouch");
		}
	}
	[HarmonyPatch]
	internal static class ImitationsPatch
	{
		private const float SeenCooldownHold = 1f;

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Materials), "Impulse")]
		private static bool Impulse_Prefix(MaterialTrigger materialTrigger)
		{
			return !IsImitatedPlayerSound(materialTrigger);
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Materials), "Slide")]
		private static bool Slide_Prefix(MaterialTrigger materialTrigger)
		{
			return !IsImitatedPlayerSound(materialTrigger);
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Materials), "SlideLoop")]
		private static bool SlideLoop_Prefix(MaterialTrigger materialTrigger)
		{
			return !IsImitatedPlayerSound(materialTrigger);
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Sound), "Play", new Type[]
		{
			typeof(Vector3),
			typeof(float),
			typeof(float),
			typeof(float),
			typeof(float)
		})]
		private static void Play_Postfix(Sound __instance, AudioSource? __result)
		{
			MuteIfImitated(__instance, __result, __instance);
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Sound), "Play", new Type[]
		{
			typeof(Transform),
			typeof(float),
			typeof(float),
			typeof(float),
			typeof(float)
		})]
		private static void PlayFollowing_Postfix(Sound __instance, AudioSource? __result, Transform followTarget)
		{
			MuteIfImitated(__instance, __result, followTarget);
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Sound), "Play", new Type[]
		{
			typeof(Transform),
			typeof(Vector3),
			typeof(float),
			typeof(float),
			typeof(float),
			typeof(float)
		})]
		private static void PlayFollowingAtContact_Postfix(Sound __instance, AudioSource? __result, Transform followTarget)
		{
			MuteIfImitated(__instance, __result, followTarget);
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(PlayerDeathHead), "Update")]
		private static void DeathHeadUpdate_Prefix(PlayerDeathHead __instance, ref float ___seenCooldownTimer)
		{
			if (!(___seenCooldownTimer >= 1f) && Object.op_Implicit((Object)(object)__instance.playerAvatar))
			{
				Imitations local = Imitations.Local;
				if (Object.op_Implicit((Object)(object)local) && local.IsImitatedPlayer(__instance.playerAvatar))
				{
					___seenCooldownTimer = 1f;
				}
			}
		}

		private static void MuteIfImitated(Sound sound, AudioSource? played, object emitter)
		{
			if (Object.op_Implicit((Object)(object)played) && !played.mute && !Object.op_Implicit((Object)(object)sound.Source) && IsImitatedPlayerSound(emitter))
			{
				played.mute = true;
			}
		}

		private static bool IsImitatedPlayerSound(object emitter)
		{
			Imitations local = Imitations.Local;
			if (Object.op_Implicit((Object)(object)local))
			{
				return local.IsImitatedPlayerSound(emitter);
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(NetworkConnect), "OnJoinedRoom")]
	internal static class JoinedRoomPatch
	{
		private static void Postfix()
		{
			LethalHallucinations.OnJoinedRoom();
		}
	}
	[HarmonyPatch(typeof(LocalVoiceFramed<short>), "PushDataAsync")]
	internal class LocalVoiceFramedPatch
	{
		private static void Prefix(short[] buf, LocalVoiceFramed<short> __instance)
		{
			PlayerVoiceChat instance = PlayerVoiceChat.instance;
			if (instance != null)
			{
				var (sampleRate, channels) = VoiceFormatResolver.Resolve(__instance, buf.Length);
				VepMod.VoiceRecorder.PushFrame(instance.isTalking, buf, sampleRate, channels);
			}
		}
	}
	[HarmonyPatch(typeof(PlayerAvatar), "Awake")]
	internal class PlayerAvatarPatch
	{
		private static readonly VepLogger LOG = VepLogger.Create<PlayerAvatarPatch>();

		private static void Postfix(PlayerAvatar __instance)
		{
			if (PhotonNetwork.IsConnectedAndReady)
			{
				if (__instance.photonView.IsMine)
				{
					VepLogger lOG = LOG;
					InvariantLogMessage message = new InvariantLogMessage(23, 2);
					message.AppendLiteral("Local player ");
					message.AppendFormatted(PhotonNetwork.LocalPlayer.NickName);
					message.AppendLiteral(", Master: ");
					message.AppendFormatted(PhotonNetwork.IsMasterClient);
					lOG.Info(ref message);
				}
				((Component)__instance).gameObject.AddComponent<VoiceSampleSharing>();
				VepLogger lOG2 = LOG;
				InvariantLogMessage message2 = new InvariantLogMessage(44, 1);
				message2.AppendLiteral("Voice Sample sharing added to PlayerAvatar: ");
				message2.AppendFormatted(((Object)__instance).name);
				lOG2.Debug(ref message2);
			}
		}
	}
	[HarmonyPatch(typeof(PlayerAvatar), "SetSpectate")]
	internal static class SpectatePatch
	{
		private static readonly VepLogger LOG = VepLogger.Create("SpectatePatch");

		private static void Postfix()
		{
			VepLogger lOG = LOG;
			InvariantLogMessage message = new InvariantLogMessage(53, 2);
			message.AppendLiteral("Spectate starts: camera aim override ");
			message.AppendFormatted(CameraAim.Instance.AimTargetActive ? "on" : "off");
			message.AppendLiteral(", ");
			message.AppendLiteral("zoom override ");
			message.AppendFormatted(CameraZoom.Instance.OverrideActive ? "on" : "off");
			lOG.Debug(ref message);
		}
	}
	[HarmonyPatch(typeof(PlayerAvatar), "AddToStatsManagerRPC")]
	internal class VoiceBankMigrationPatch
	{
		private static readonly VepLogger LOG = VepLogger.Create<VoiceBankMigrationPatch>();

		private static void Postfix(PlayerAvatar __instance)
		{
			PlayerKey playerKey = __instance.VoiceBankKey();
			try
			{
				int? num = VepMod.VoiceBanks.MigrateLegacyBank(playerKey);
				LOG.Debug((!num.HasValue) ? $"No legacy Voice Bank to migrate for {playerKey}." : $"Legacy Voice Bank of nickname {playerKey.Nickname} migrated to Steam ID {playerKey.SteamId}: {num} Voice Samples after merge.");
			}
			catch (Exception ex)
			{
				VepLogger lOG = LOG;
				InvariantLogMessage message = new InvariantLogMessage(45, 2);
				message.AppendLiteral("Could not migrate the legacy Voice Bank of ");
				message.AppendFormatted(playerKey);
				message.AppendLiteral(": ");
				message.AppendFormatted(ex.Message);
				lOG.Warning(ref message);
			}
		}
	}
}
namespace VepMod.Enemies.Whispral
{
	internal sealed class AngryEyes
	{
		private const float CalmDelay = 0.3f;

		private float _gazeTime;

		public bool IsAngry { get; private set; }

		public void Update(bool isUnderGaze, bool isStalkingBeforeFlee, float deltaTime)
		{
			_gazeTime = (isUnderGaze ? (_gazeTime + deltaTime) : 0f);
			IsAngry = !isUnderGaze || isStalkingBeforeFlee || _gazeTime < 0.3f;
		}
	}
	public enum HauntedTransition
	{
		NoChange,
		BecameHaunted,
		StoppedBeingHaunted
	}
	public sealed class Attachments
	{
		private readonly HashSet<int> _whispralViewIDs = new HashSet<int>();

		public bool IsHaunted => _whispralViewIDs.Count > 0;

		public HauntedTransition Attach(int whispralViewID)
		{
			if (!_whispralViewIDs.Add(whispralViewID) || _whispralViewIDs.Count != 1)
			{
				return HauntedTransition.NoChange;
			}
			return HauntedTransition.BecameHaunted;
		}

		public HauntedTransition Detach(int whispralViewID)
		{
			if (!_whispralViewIDs.Remove(whispralViewID) || _whispralViewIDs.Count != 0)
			{
				return HauntedTransition.NoChange;
			}
			return HauntedTransition.StoppedBeingHaunted;
		}
	}
	public static class AudioFilters
	{
		private const float TwoPi = MathF.PI * 2f;

		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 const float SilencePadding = 0.5f;

		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[] 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;
		}
	}
	internal static class Avoidance
	{
		private const float Reach = 2f;

		private const float Strength = 2f;

		public static (float X, float Z) Deflection(float dirX, float dirZ, float toOtherX, float toOtherZ)
		{
			float num = MathF.Sqrt(toOtherX * toOtherX + toOtherZ * toOtherZ);
			if (toOtherX * dirX + toOtherZ * dirZ <= 0f || num >= 2f)
			{
				return (X: 0f, Z: 0f);
			}
			bool flag = dirX * toOtherZ - dirZ * toOtherX < 0f;
			float num2 = 2f * (1f - num / 2f) * (flag ? (-1f) : 1f);
			return (X: dirZ * num2, Z: (0f - dirX) * num2);
		}
	}
	internal sealed class ChangeOfMind
	{
		public readonly struct Change
		{
			public readonly float? Roll;

			public readonly bool Asked;

			public readonly bool Capped;

			public Change(float? roll, bool asked, bool capped)
			{
				Roll = roll;
				Asked = asked;
				Capped = capped;
			}
		}

		private const float Chance = 0.03f;

		private const float RollInterval = 1f;

		private readonly Func<float> _roll;

		private int _changesAsked;

		private bool _changed;

		private bool _refusalReported;

		private float _sinceRoll;

		public ChangeOfMind(Func<float> roll)
		{
			_roll = roll;
		}

		public void Start()
		{
			_changed = false;
			_refusalReported = false;
			_sinceRoll = 0f;
		}

		public void ChangeNow()
		{
			_changesAsked++;
		}

		public Change? Update(float deltaTime)
		{
			if (_changed)
			{
				if (_changesAsked == 0 || _refusalReported)
				{
					return null;
				}
				_refusalReported = true;
				return new Change(null, asked: true, capped: true);
			}
			if (_changesAsked > 0)
			{
				_changesAsked--;
				_changed = true;
				return new Change(null, asked: true, capped: false);
			}
			_sinceRoll += deltaTime;
			if (_sinceRoll < 1f)
			{
				return null;
			}
			_sinceRoll -= 1f;
			float num = _roll();
			if (num >= 0.03f)
			{
				return null;
			}
			_changed = true;
			return new Change(num, asked: false, capped: false);
		}
	}
	internal sealed class DeadTeammateEffect : MonoBehaviour
	{
		private const float Duration = 2f;

		private static readonly MethodInfo VignetteOverride = AccessTools.Method(typeof(PostProcessing), "VignetteOverride", (Type[])null, (Type[])null);

		private static readonly MethodInfo SaturationOverride = AccessTools.Method(typeof(PostProcessing), "SaturationOverride", (Type[])null, (Type[])null);

		private static readonly MethodInfo ContrastOverride = AccessTools.Method(typeof(PostProcessing), "ContrastOverride", (Type[])null, (Type[])null);

		private float _left;

		private object?[] _vignetteArgs;

		private object?[] _saturationArgs;

		private object?[] _contrastArgs;

		private void Awake()
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			_vignetteArgs = WithDefaults(VignetteOverride, new object[7]
			{
				Color.black,
				0.4f,
				1f,
				1f,
				0.5f,
				0.1f,
				((Component)this).gameObject
			});
			_saturationArgs = WithDefaults(SaturationOverride, new object[5]
			{
				-50f,
				1f,
				0.5f,
				0.1f,
				((Component)this).gameObject
			});
			_contrastArgs = WithDefaults(ContrastOverride, new object[5]
			{
				5f,
				1f,
				0.5f,
				0.1f,
				((Component)this).gameObject
			});
		}

		private static object?[] WithDefaults(MethodInfo method, object[] args)
		{
			return method.GetParameters().Select((ParameterInfo parameter, int i) => (i >= args.Length) ? parameter.DefaultValue : args[i]).ToArray();
		}

		public void Play()
		{
			_left = 2f;
			GameDirector.instance.CameraImpact.Shake(2f, 0.5f);
			GameDirector.instance.CameraShake.Shake(2f, 1f);
		}

		private void Update()
		{
			if (!(_left <= 0f))
			{
				_left -= Time.deltaTime;
				CameraZoom.Instance.OverrideZoomSet(75f, 0.1f, 0.25f, 0.25f, ((Component)this).gameObject, 150);
				VignetteOverride.Invoke(PostProcessing.Instance, _vignetteArgs);
				SaturationOverride.Invoke(PostProcessing.Instance, _saturationArgs);
				ContrastOverride.Invoke(PostProcessing.Instance, _contrastArgs);
				GameDirector.instance.CameraImpact.Shake(10f * Time.deltaTime, 0.1f);
				GameDirector.instance.CameraShake.Shake(10f * Time.deltaTime, 1f);
			}
		}
	}
	public sealed class DilatedPupils : 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<DilatedPupils>();

		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 Apply(bool dilated)
		{
			IsActive = dilated;
			VepLogger lOG = LOG;
			InvariantLogMessage message = new InvariantLogMessage(16, 1);
			message.AppendLiteral("Dilated Pupils: ");
			message.AppendFormatted(dilated);
			lOG.Debug(ref message);
			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 class EnemyWhispral : StateMachineComponent<EnemyWhispral, EnemyWhispral.State>
	{
		public enum State
		{
			Spawn,
			Idle,
			Roam,
			Investigate,
			NoticePlayer,
			GoToPlayer,
			PrepareAttach,
			Attached,
			Detach,
			DetachWait,
			Leave,
			Stun,
			StunEnd,
			Despawn
		}

		private abstract class WhispralStateBase : StateMachineBase<StateMachine, State>.StateBase
		{
			protected StateMachine Fsm => base.Machine;

			protected EnemyWhispral Whispral => Fsm.Owner;

			protected Enemy Enemy => Whispral.enemy;

			protected EnemyWhispralAnim Anim => Whispral.enemyWhispralAnim;

			public override void OnStateEnter(State previous)
			{
				//IL_0061: Unknown result type (might be due to invalid IL or missing references)
				//IL_0067: Unknown result type (might be due to invalid IL or missing references)
				base.OnStateEnter(previous);
				Enemy.Rigidbody.StuckReset();
				if (GameManager.Multiplayer())
				{
					Whispral._photonView.RPC("UpdateStateRPC", (RpcTarget)0, new object[1] { Fsm.NextStateStateId });
				}
				else
				{
					Whispral.UpdateStateRPC(Fsm.NextStateStateId);
				}
			}
		}

		private sealed class SpawnState : WhispralStateBase
		{
			private float _timer;

			public override void OnStateEnter(State previous)
			{
				base.OnStateEnter(previous);
				_timer = 1f;
			}

			public override void OnStateUpdate()
			{
				_timer -= Time.deltaTime;
				if (_timer <= 0f)
				{
					base.Fsm.NextStateStateId = State.Idle;
				}
			}
		}

		private sealed class IdleState : WhispralStateBase
		{
			private bool _startPauseSkipReported;

			private float _timer;

			public override void OnStateEnter(State previous)
			{
				//IL_0037: Unknown result type (might be due to invalid IL or missing references)
				base.OnStateEnter(previous);
				_timer = Random.Range(1f, 3f);
				base.Enemy.NavMeshAgent.Warp(((Component)base.Enemy.Rigidbody).transform.position, false);
				base.Enemy.NavMeshAgent.ResetPath();
				if (!_startPauseSkipReported && SemiFunc.EnemySpawnIdlePause())
				{
					_startPauseSkipReported = true;
					VepLogger lOG = LOG;
					InvariantLogMessage message = new InvariantLogMessage(53, 2);
					message.AppendLiteral("Whispral ");
					message.AppendFormatted(base.Whispral._photonView.ViewID);
					message.AppendLiteral(" skips the director's start pause ");
					message.AppendLiteral("(");
					message.AppendFormatted(EnemyDirector.instance.spawnIdlePauseTimer, "F0");
					message.AppendLiteral(" s left).");
					lOG.Debug(ref message);
				}
			}

			public override void OnStateUpdate()
			{
				_timer -= Time.deltaTime;
				if (_timer <= 0f)
				{
					base.Fsm.NextStateStateId = State.Roam;
				}
				if (SemiFunc.EnemyForceLeave(base.Enemy))
				{
					base.Fsm.NextStateStateId = State.Leave;
				}
			}
		}

		private sealed class RoamState : WhispralStateBase
		{
			private const float TimeToStopRoaming = 2f;

			private const float TimeToRoam = 5f;

			private bool _hasDestination;

			private float _timer;

			public override void OnStateEnter(State previous)
			{
				//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_002a: Unknown result type (might be due to invalid IL or missing references)
				//IL_003b: Unknown result type (might be due to invalid IL or missing references)
				//IL_004b: Unknown result type (might be due to invalid IL or missing references)
				//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
				//IL_0135: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
				//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
				//IL_0215: Unknown result type (might be due to invalid IL or missing references)
				base.OnStateEnter(previous);
				_timer = 5f;
				_hasDestination = false;
				Vector3 position = ((Component)base.Whispral).transform.position;
				(LevelPoint, Presence.RoamPointSource)? tuple = Presence.RoamPoint<LevelPoint>(SemiFunc.LevelPointGetPlayerDistance(position, 18f, 35f, false), SemiFunc.LevelPointGet(position, 10f, 25f), SemiFunc.LevelPointGet(position, 0f, 999f));
				if (tuple.HasValue)
				{
					(LevelPoint, Presence.RoamPointSource) valueOrDefault = tuple.GetValueOrDefault();
					(LevelPoint, Presence.RoamPointSource) tuple2 = valueOrDefault;
					LevelPoint item = tuple2.Item1;
					Presence.RoamPointSource item2 = tuple2.Item2;
					Vector3 position2 = ((Component)item).transform.position;
					float value = NearestPlayerDistance(position2);
					if (!SamplePosition(item, out var hit) || !Raycast(hit))
					{
						VepLogger lOG = LOG;
						InvariantLogMessage message = new InvariantLogMessage(70, 4);
						message.AppendLiteral("Whispral ");
						message.AppendFormatted(base.Whispral._photonView.ViewID);
						message.AppendLiteral(" finds no NavMesh near ");
						message.AppendFormatted<Vector3>(position2);
						message.AppendLiteral(" (");
						message.AppendFormatted(item2);
						message.AppendLiteral(", ");
						message.AppendFormatted(value, "F1");
						message.AppendLiteral(" m from the nearest alive player).");
						lOG.Debug(ref message);
					}
					else
					{
						VepLogger lOG2 = LOG;
						InvariantLogMessage message2 = new InvariantLogMessage(57, 4);
						message2.AppendLiteral("Whispral ");
						message2.AppendFormatted(base.Whispral._photonView.ViewID);
						message2.AppendLiteral(" roams to ");
						message2.AppendFormatted<Vector3>(position2);
						message2.AppendLiteral(" (");
						message2.AppendFormatted(item2);
						message2.AppendLiteral("), ");
						message2.AppendFormatted(value, "F1");
						message2.AppendLiteral(" m from the nearest alive player.");
						lOG2.Debug(ref message2);
						base.Enemy.NavMeshAgent.SetDestination(((NavMeshHit)(ref hit)).position);
						base.Enemy.Rigidbody.notMovingTimer = 0f;
						_hasDestination = true;
					}
				}
				else
				{
					VepLogger lOG3 = LOG;
					InvariantLogMessage message3 = new InvariantLogMessage(30, 1);
					message3.AppendLiteral("Whispral ");
					message3.AppendFormatted(base.Whispral._photonView.ViewID);
					message3.AppendLiteral(" finds no roam point.");
					lOG3.Debug(ref message3);
				}
			}

			public override void OnStateUpdate()
			{
				if (SemiFunc.EnemyForceLeave(base.Enemy))
				{
					base.Fsm.NextStateStateId = State.Leave;
					return;
				}
				if (!_hasDestination)
				{
					base.Fsm.NextStateStateId = State.Idle;
					return;
				}
				SemiFunc.EnemyCartJump(base.Enemy);
				if (base.Enemy.Rigidbody.notMovingTimer > 2f)
				{
					_timer -= Time.deltaTime;
				}
				if (_timer <= 0f || !base.Enemy.NavMeshAgent.HasPath())
				{
					SemiFunc.EnemyCartJumpReset(base.Enemy);
					base.Fsm.NextStateStateId = State.Idle;
				}
			}

			private static bool Raycast(NavMeshHit hit)
			{
				//IL_0002: Unknown result type (might be due to invalid IL or missing references)
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				return Physics.Raycast(((NavMeshHit)(ref hit)).position, Vector3.down, 5f, LayerMask.GetMask(new string[1] { "Default" }));
			}

			private static bool SamplePosition(LevelPoint levelPoint, out NavMeshHit hit)
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_000b: Unknown result type (might be due to invalid IL or missing references)
				//IL_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)
				return NavMesh.SamplePosition(((Component)levelPoint).transform.position + Random.insideUnitSphere * 3f, ref hit, 5f, -1);
			}
		}

		private sealed class InvestigateState : WhispralStateBase
		{
			private float _timer;

			public override void OnStateEnter(State previous)
			{
				base.OnStateEnter(previous);
				_timer = 5f;
				base.Enemy.Rigidbody.notMovingTimer = 0f;
			}

			public override void OnStateUpdate()
			{
				//IL_002c: Unknown result type (might be due to invalid IL or missing references)
				if (SemiFunc.EnemyForceLeave(base.Enemy))
				{
					base.Fsm.NextStateStateId = State.Leave;
					return;
				}
				base.Enemy.NavMeshAgent.SetDestination(base.Whispral.agentDestination);
				SemiFunc.EnemyCartJump(base.Enemy);
				if (base.Enemy.Rigidbody.notMovingTimer > 2f)
				{
					_timer -= Time.deltaTime;
				}
				if (_timer <= 0f || !base.Enemy.NavMeshAgent.HasPath())
				{
					SemiFunc.EnemyCartJumpReset(base.Enemy);
					base.Fsm.NextStateStateId = State.Idle;
				}
			}
		}

		private sealed class PlayerNoticeState : WhispralStateBase
		{
			private const float TimeToNoticePlayer = 2f;

			private float _timer;

			public override void OnStateEnter(State previous)
			{
				//IL_0022: Unknown result type (might be due to invalid IL or missing references)
				base.OnStateEnter(previous);
				base.Enemy.NavMeshAgent.Warp(((Component)base.Enemy.Rigidbody).transform.position, false);
				base.Enemy.NavMeshAgent.ResetPath();
				_timer = 2f;
			}

			public override void OnStateUpdate()
			{
				_timer -= Time.deltaTime;
				if (_timer <= 0f)
				{
					base.Fsm.NextStateStateId = State.GoToPlayer;
				}
			}
		}

		private sealed class PlayerGoToState : WhispralStateBase
		{
			private const float TimeToStopGoingToPlayer = 2f;

			private const float AttachDistanceThreshold = 1.5f;

			private bool _agentSet;

			private float _timer;

			public override void OnStateEnter(State previous)
			{
				base.OnStateEnter(previous);
				_timer = 2f;
				_agentSet = true;
			}

			public void RefreshTimer()
			{
				_timer = 2f;
			}

			public override void OnStateUpdate()
			{
				//IL_0050: Unknown result type (might be due to invalid IL or missing references)
				//IL_0055: Unknown result type (might be due to invalid IL or missing references)
				//IL_009e: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
				//IL_00af: Unknown result type (might be due to invalid IL or missing references)
				//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
				//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
				//IL_0104: Unknown result type (might be due to invalid IL or missing references)
				//IL_0109: Unknown result type (might be due to invalid IL or missing references)
				//IL_0113: Unknown result type (might be due to invalid IL or missing references)
				//IL_0118: Unknown result type (might be due to invalid IL or missing references)
				//IL_0128: Unknown result type (might be due to invalid IL or missing references)
				//IL_0176: Unknown result type (might be due to invalid IL or missing references)
				//IL_015b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0160: Unknown result type (might be due to invalid IL or missing references)
				//IL_0161: Unknown result type (might be due to invalid IL or missing references)
				_timer -= Time.deltaTime;
				PlayerAvatar playerTarget = base.Whispral.playerTarget;
				if ((Object)(object)playerTarget == (Object)null || playerTarget.isDisabled || _timer <= 0f)
				{
					base.Fsm.NextStateStateId = State.Leave;
					return;
				}
				Vector3 position = ((Component)playerTarget).transform.position;
				SemiFunc.EnemyCartJump(base.Enemy);
				if (base.Enemy.Jump.jumping)
				{
					base.Enemy.NavMeshAgent.Disable(0.5f);
					((Component)base.Whispral).transform.position = Vector3.MoveTowards(((Component)base.Whispral).transform.position, position, 5f * Time.deltaTime);
					_agentSet = true;
				}
				else if (!base.Enemy.NavMeshAgent.IsDisabled())
				{
					if (!_agentSet && base.Enemy.NavMeshAgent.HasPath() && Vector3.Distance(((Component)base.Enemy.Rigidbody).transform.position + Vector3.down * 0.75f, base.Enemy.NavMeshAgent.GetDestination()) < 0.25f)
					{
						base.Enemy.Jump.StuckTrigger(((Component)base.Enemy.Rigidbody).transform.position - position);
					}
					base.Enemy.NavMeshAgent.SetDestination(position);
					base.Enemy.NavMeshAgent.OverrideAgent(5f, 10f, 0.25f);
					_agentSet = false;
				}
				if (Vector3.Distance(((Component)base.Enemy.Rigidbody).transform.position, position) < 1.5f)
				{
					SemiFunc.EnemyCartJumpReset(base.Enemy);
					base.Fsm.NextStateStateId = State.PrepareAttach;
				}
			}
		}

		private sealed class AttachPrepareState : WhispralStateBase
		{
			private const float TimeToPrepareAttach = 1f;

			private float _timer;

			public override void OnStateEnter(State previous)
			{
				//IL_002d: Unknown result type (might be due to invalid IL or missing references)
				base.OnStateEnter(previous);
				_timer = 1f;
				base.Enemy.NavMeshAgent.Warp(((Component)base.Enemy.Rigidbody).transform.position, false);
				base.Enemy.NavMeshAgent.ResetPath();
			}

			public override void OnStateUpdate()
			{
				PlayerAvatar playerTarget = base.Whispral.playerTarget;
				if ((Object)(object)playerTarget == (Object)null || playerTarget.isDisabled)
				{
					base.Fsm.NextStateStateId = State.Leave;
					return;
				}
				_timer -= Time.deltaTime;
				if (_timer <= 0f)
				{
					base.Fsm.NextStateStateId = State.Attached;
				}
			}
		}

		private sealed class AttachedState : WhispralStateBase
		{
			private int? _victimViewID;

			private float _voiceTimer;

			public override void OnStateEnter(State previous)
			{
				base.OnStateEnter(previous);
				base.Whispral.attachedTimer = base.Whispral.attachedDuration;
				_voiceTimer = GetRandomVoiceDelay();
				PlayerAvatar playerTarget = base.Whispral.playerTarget;
				if (!((Object)(object)playerTarget == (Object)null))
				{
					base.Whispral.attachAnchor = SemiFunc.PlayerGetFaceEyeTransform(playerTarget);
					_victimViewID = playerTarget.photonView.ViewID;
					VepLogger lOG = LOG;
					InvariantLogMessage message = new InvariantLogMessage(36, 2);
					message.AppendLiteral("Whispral ");
					message.AppendFormatted(base.Whispral._photonView.ViewID);
					message.AppendLiteral(" starts its Attachment to ");
					message.AppendFormatted(playerTarget.playerName);
					message.AppendLiteral(".");
					lOG.Debug(ref message);
					base.Whispral.ReportAttachment(_victimViewID.Value, attached: true);
				}
			}

			public override void OnStateExit(State next)
			{
				base.OnStateExit(next);
				base.Whispral.attachAnchor = null;
				if (_victimViewID.HasValue)
				{
					VepLogger lOG = LOG;
					InvariantLogMessage message = new InvariantLogMessage(47, 3);
					message.AppendLiteral("Whispral ");
					message.AppendFormatted(base.Whispral._photonView.ViewID);
					message.AppendLiteral(" ends its Attachment to ViewID ");
					message.AppendFormatted(_victimViewID);
					message.AppendLiteral(" (-> ");
					message.AppendFormatted(next);
					message.AppendLiteral(").");
					lOG.Debug(ref message);
					base.Whispral.ReportAttachment(_victimViewID.Value, attached: false);
					_victimViewID = null;
				}
			}

			public override void OnStateUpdate()
			{
				if (CheckLeaveState())
				{
					return;
				}
				CheckDetachState();
				if (SemiFunc.IsMasterClientOrSingleplayer())
				{
					_voiceTimer -= Time.deltaTime;
					if (_voiceTimer <= 0f)
					{
						SendVoiceCommand();
						_voiceTimer = GetRandomVoiceDelay();
					}
				}
			}

			private static float GetRandomVoiceDelay()
			{
				if (VepMod.VoiceDelay == null)
				{
					return Random.Range(3f, 8f);
				}
				return Random.Range(VepMod.VoiceDelay.Min, VepMod.VoiceDelay.Max);
			}

			private void SendVoiceCommand()
			{
				PlayerAvatar victim = base.Whispral.playerTarget;
				if (!((Object)(object)victim == (Object)null))
				{
					if (!SemiFunc.PlayerGetList().Any((PlayerAvatar p) => Object.op_Implicit((Object)(object)p) && (Object)(object)p != (Object)(object)victim))
					{
						VepLogger lOG = LOG;
						InvariantLogMessage message = new InvariantLogMessage(49, 1);
						message.AppendLiteral("No Mimic command to ");
						message.AppendFormatted(victim.playerName);
						message.AppendLiteral(": they are alone in the room.");
						lOG.Debug(ref message);
					}
					else
					{
						base.Whispral.SendMimicCommand(victim, Hallucination.RollVoiceFilter());
					}
				}
			}

			private void CheckDetachState()
			{
				base.Whispral.attachedTimer -= Time.deltaTime;
				PlayerAvatar playerTarget = base.Whispral.playerTarget;
				if (base.Whispral.attachedTimer <= 0f || (Object)(object)playerTarget == (Object)null || playerTarget.isDisabled || playerTarget.isTumbling)
				{
					LOG.Debug($"Whispral {base.Whispral._photonView.ViewID} detaches: " + ((base.Whispral.attachedTimer <= 0f) ? "its Attachment's time ran out." : "its Victim tumbles."));
					base.Fsm.NextStateStateId = State.Detach;
				}
			}

			private bool CheckLeaveState()
			{
				PlayerAvatar playerTarget = base.Whispral.playerTarget;
				if ((Object)(object)playerTarget == (Object)null || playerTarget.isDisabled)
				{
					base.Fsm.NextStateStateId = State.Leave;
					return true;
				}
				return false;
			}
		}

		private class DetachState : WhispralStateBase
		{
			private float _timer;

			public override void OnStateEnter(State previous)
			{
				//IL_002d: Unknown result type (might be due to invalid IL or missing references)
				base.OnStateEnter(previous);
				_timer = 0.5f;
				base.Enemy.NavMeshAgent.Warp(((Component)base.Enemy.Rigidbody).transform.position, false);
				base.Enemy.NavMeshAgent.ResetPath();
			}

			public override void OnStateUpdate()
			{
				_timer -= Time.deltaTime;
				if (_timer <= 0f)
				{
					base.Fsm.NextStateStateId = State.DetachWait;
				}
			}
		}

		private class DetachWaitState : WhispralStateBase
		{
			private const float TimeToLeaveAfterDetach = 2f;

			private float _timer;

			public override void OnStateEnter(State previous)
			{
				base.OnStateEnter(previous);
				_timer = 2f;
			}

			public override void OnStateUpdate()
			{
				_timer -= Time.deltaTime;
				if (_timer <= 0f)
				{
					base.Fsm.NextStateStateId = State.Leave;
				}
			}
		}

		private class LeaveState : WhispralStateBase
		{
			private const float TimeToLeave = 5f;

			private bool _hasDestination;

			private float _timer;

			public override void OnStateEnter(State previous)
			{
				//IL_0024: Unknown result type (might be due to invalid IL or missing references)
				//IL_004e: Unknown result type (might be due to invalid IL or missing references)
				//IL_006c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0071: Unknown result type (might be due to invalid IL or missing references)
				//IL_007b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0080: Unknown result type (might be due to invalid IL or missing references)
				//IL_0096: Unknown result type (might be due to invalid IL or missing references)
				//IL_009b: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
				//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
				base.OnStateEnter(previous);
				_timer = 5f;
				_hasDestination = false;
				LevelPoint val = SemiFunc.LevelPointGetPlayerDistance(((Component)base.Whispral).transform.position, 30f, 50f, false);
				if ((Object)(object)val == (Object)null)
				{
					val = SemiFunc.LevelPointGetFurthestFromPlayer(((Component)base.Whispral).transform.position, 5f);
				}
				NavMeshHit val2 = default(NavMeshHit);
				if (Object.op_Implicit((Object)(object)val) && NavMesh.SamplePosition(((Component)val).transform.position + Random.insideUnitSphere * 3f, ref val2, 5f, -1) && Physics.Raycast(((NavMeshHit)(ref val2)).position, Vector3.down, 5f, LayerMask.GetMask(new string[1] { "Default" })))
				{
					base.Whispral.agentDestination = ((NavMeshHit)(ref val2)).position;
					_hasDestination = true;
				}
				SemiFunc.EnemyLeaveStart(base.Enemy);
			}

			public override void OnStateExit(State next)
			{
				base.OnStateExit(next);
				if (next != State.Despawn)
				{
					VepLogger lOG = LOG;
					InvariantLogMessage message = new InvariantLogMessage(60, 3);
					message.AppendLiteral("Whispral ");
					message.AppendFormatted(base.Whispral._photonView.ViewID);
					message.AppendLiteral(" ends its flee (-> ");
					message.AppendFormatted(next);
					message.AppendLiteral(") still present, ");
					message.AppendLiteral("spawn timer ");
					message.AppendFormatted(base.Enemy.EnemyParent.SpawnedTimer, "F1");
					message.AppendLiteral(" s.");
					lOG.Debug(ref message);
				}
			}

			public override void OnStateUpdate()
			{
				//IL_004f: Unknown result type (might be due to invalid IL or missing references)
				//IL_008e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0099: Unknown result type (might be due to invalid IL or missing references)
				if (!_hasDestination)
				{
					base.Fsm.NextStateStateId = State.Idle;
					return;
				}
				if (base.Enemy.Rigidbody.notMovingTimer > 2f)
				{
					_timer -= Time.deltaTime;
				}
				base.Enemy.NavMeshAgent.SetDestination(base.Whispral.agentDestination);
				base.Enemy.NavMeshAgent.OverrideAgent(5f, 10f, 0.25f);
				SemiFunc.EnemyCartJump(base.Enemy);
				if (Vector3.Distance(((Component)base.Whispral).transform.position, base.Whispral.agentDestination) < 1f || _timer <= 0f)
				{
					SemiFunc.EnemyCartJumpReset(base.Enemy);
					base.Fsm.NextStateStateId = State.Idle;
				}
			}
		}

		private class StunState : WhispralStateBase
		{
			public override void OnStateEnter(State previous)
			{
				base.OnStateEnter(previous);
				VepLogger lOG = LOG;
				InvariantLogMessage message = new InvariantLogMessage(28, 2);
				message.AppendLiteral("Whispral ");
				message.AppendFormatted(base.Whispral._photonView.ViewID);
				message.AppendLiteral(" stunned in state ");
				message.AppendFormatted(previous);
				message.AppendLiteral(".");
				lOG.Debug(ref message);
			}

			public override void OnStateUpdate()
			{
				if (!base.Enemy.IsStunned())
				{
					base.Fsm.NextStateStateId = State.StunEnd;
				}
			}
		}

		private class StunEndState : WhispralStateBase
		{
			private const float TimeToRecoverStun = 1f;

			private float _timer;

			public override void OnStateEnter(State previous)
			{
				base.OnStateEnter(previous);
				_timer = 1f;
			}

			public override void OnStateUpdate()
			{
				_timer -= Time.deltaTime;
				if (_timer <= 0f)
				{
					base.Fsm.NextStateStateId = State.Leave;
				}
			}
		}

		private class DespawnState : WhispralStateBase
		{
			public override void OnStateEnter(State previous)
			{
				base.OnStateEnter(previous);
				base.Enemy.EnemyParent.Despawn();
				VepLogger lOG = LOG;
				InvariantLogMessage message = new InvariantLogMessage(59, 3);
				message.AppendLiteral("Whispral ");
				message.AppendFormatted(base.Whispral._photonView.ViewID);
				message.AppendLiteral(" despawns from state ");
				message.AppendFormatted(previous);
				message.AppendLiteral(" ");
				message.AppendLiteral("(game's despawned timer ");
				message.AppendFormatted(base.Enemy.EnemyParent.DespawnedTimer, "F0");
				message.AppendLiteral(" s).");
				lOG.Debug(ref message);
				base.Fsm.NextStateStateId = State.Spawn;
			}
		}

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

		[Header("Core refs")]
		public Enemy enemy;

		public EnemyWhispralAnim enemyWhispralAnim;

		[Header("Attach settings")]
		[Tooltip("How long the Whispral stays attached to its Victim, in seconds.")]
		public float attachedDuration = 240f;

		[Space]
		public SpringQuaternion rotationSpring;

		[HideInInspector]
		public Vector3 agentDestination;

		[HideInInspector]
		public PlayerAvatar? playerTarget;

		[HideInInspector]
		public Transform? attachAnchor;

		[HideInInspector]
		public float attachedTimer;

		private State _currentState;

		private float? _diedAt;

		private float _grabAggroTimer;

		private float _returnDelay;

		private PhotonView _photonView;

		private Quaternion _rotationTarget;

		protected override State DefaultState => State.Spawn;

		public State CurrentState
		{
			get
			{
				if (!SemiFunc.IsMasterClientOrSingleplayer())
				{
					return _currentState;
				}
				return Fsm.CurrentStateStateId;
			}
			set
			{
				if (!SemiFunc.IsMasterClientOrSingleplayer())
				{
					_currentState = value;
				}
			}
		}

		protected override void Awake()
		{
			base.Awake();
			_photonView = ((Component)this).GetComponent<PhotonView>();
			Fsm.AddState(State.Spawn, new SpawnState());
			Fsm.AddState(State.Idle, new IdleState());
			Fsm.AddState(State.Roam, new RoamState());
			Fsm.AddState(State.Investigate, new InvestigateState());
			Fsm.AddState(State.NoticePlayer, new PlayerNoticeState());
			Fsm.AddState(State.GoToPlayer, new PlayerGoToState());
			Fsm.AddState(State.PrepareAttach, new AttachPrepareState());
			Fsm.AddState(State.Attached, new AttachedState());
			Fsm.AddState(State.Detach, new DetachState());
			Fsm.AddState(State.DetachWait, new DetachWaitState());
			Fsm.AddState(State.Leave, new LeaveState());
			Fsm.AddState(State.Stun, new StunState());
			Fsm.AddState(State.StunEnd, new StunEndState());
			Fsm.AddState(State.Despawn, new DespawnState());
		}

		protected override void Update()
		{
			if (SemiFunc.IsMasterClientOrSingleplayer())
			{
				UpdateGrabAggroTimer();
				RefillSpawnTimer();
				CheckForStunState();
				CheckForDespawnState();
				RotationLogic();
				base.Update();
			}
		}

		private void FixedUpdate()
		{
			if (SemiFunc.IsMasterClientOrSingleplayer())
			{
				AttachFollowLogic();
			}
		}

		private void RefillSpawnTimer()
		{
			EnemyParent enemyParent = enemy.EnemyParent;
			float? num = Presence.RefilledSpawnTimer(enemyParent.SpawnedTimer);
			if (num.HasValue)
			{
				float valueOrDefault = num.GetValueOrDefault();
				VepLogger lOG = LOG;
				InvariantLogMessage message = new InvariantLogMessage(41, 3);
				message.AppendLiteral("Whispral ");
				message.AppendFormatted(_photonView.ViewID);
				message.AppendLiteral(" spawn timer refilled: ");
				message.AppendFormatted(enemyParent.SpawnedTimer, "F2");
				message.AppendLiteral(" s -> ");
				message.AppendFormatted(valueOrDefault, "F0");
				message.AppendLiteral(" s.");
				lOG.Debug(ref message);
				enemyParent.SpawnedTimer = valueOrDefault;
			}
		}

		internal static float NearestPlayerDistance(Vector3 position)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			float num = float.PositiveInfinity;
			foreach (PlayerAvatar item in SemiFunc.PlayerGetList())
			{
				if (!item.isDisabled)
				{
					num = Mathf.Min(num, Vector3.Distance(position, ((Component)item).transform.position));
				}
			}
			return num;
		}

		private void CheckForDespawnState()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Invalid comparison between Unknown and I4
			if ((int)enemy.CurrentState == 11 && !enemy.IsStunned())
			{
				Fsm.NextStateStateId = State.Despawn;
			}
		}

		private void CheckForStunState()
		{
			if (enemy.IsStunned())
			{
				Fsm.NextStateStateId = State.Stun;
			}
		}

		private void UpdateGrabAggroTimer()
		{
			if (_grabAggroTimer > 0f)
			{
				_grabAggroTimer -= Time.deltaTime;
				if (_grabAggroTimer < 0f)
				{
					_grabAggroTimer = 0f;
				}
			}
		}

		private void RotationLogic()
		{
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: 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_003f: 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_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			State currentState = CurrentState;
			bool flag = (uint)(currentState - 4) <= 2u;
			if (flag && (Object)(object)playerTarget != (Object)null)
			{
				if (Vector3.Distance(((Component)playerTarget).transform.position, ((Component)this).transform.position) > 0.1f)
				{
					Quaternion rotationTarget = Quaternion.LookRotation(((Component)playerTarget).transform.position - ((Component)this).transform.position);
					((Quaternion)(ref rotationTarget)).eulerAngles = new Vector3(0f, ((Quaternion)(ref rotationTarget)).eulerAngles.y, 0f);
					_rotationTarget = rotationTarget;
				}
			}
			else
			{
				Vector3 normalized = ((Vector3)(ref enemy.NavMeshAgent.AgentVelocity)).normalized;
				if (((Vector3)(ref normalized)).magnitude > 0.1f)
				{
					Quaternion rotationTarget2 = Quaternion.LookRotation(((Vector3)(ref enemy.NavMeshAgent.AgentVelocity)).normalized);
					((Quaternion)(ref rotationTarget2)).eulerAngles = new Vector3(0f, ((Quaternion)(ref rotationTarget2)).eulerAngles.y, 0f);
					_rotationTarget = rotationTarget2;
				}
			}
			((Component)this).transform.rotation = SemiFunc.SpringQuaternionGet(rotationSpring, _rotationTarget, -1f);
		}

		private void AttachFollowLogic()
		{
			//IL_003a: 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_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_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			if (CurrentState == State.Attached && !((Object)(object)playerTarget == (Object)null) && !playerTarget.isDisabled && !((Object)(object)attachAnchor == (Object)null))
			{
				Vector3 val = attachAnchor.position + attachAnchor.TransformDirection(new Vector3(0f, 0.3f, -0.3f));
				((Component)enemy.Rigidbody).transform.position = Vector3.Lerp(((Component)enemy.Rigidbody).transform.position, val, 10f * Time.fixedDeltaTime);
				Quaternion val2 = Quaternion.LookRotation(attachAnchor.forward, Vector3.up);
				((Component)enemy.Rigidbody).transform.rotation = Quaternion.Slerp(((Component)enemy.Rigidbody).transform.rotation, val2, 10f * Time.fixedDeltaTime);
			}
		}

		[PunRPC]
		private void UpdateStateRPC(State state, PhotonMessageInfo _info = default(PhotonMessageInfo))
		{
			//IL_0000: 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_0026: Unknown result type (might be due to invalid IL or missing references)
			bool flag = _info.Sender != null && _info.Sender.UserId == PhotonNetwork.LocalPlayer.UserId;
			if (SemiFunc.MasterOnlyRPC(_info))
			{
				if (state == State.Despawn)
				{
					enemyWhispralAnim.Despawn();
				}
				if (!flag)
				{
					CurrentState = state;
				}
			}
		}

		[PunRPC]
		private void UpdatePlayerTargetRPC(int _photonViewID, PhotonMessageInfo _info = default(PhotonMessageInfo))
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			if (!SemiFunc.MasterOnlyRPC(_info))
			{
				return;
			}
			foreach (PlayerAvatar item in SemiFunc.PlayerGetList())
			{
				if (item.photonView.ViewID == _photonViewID)
				{
					playerTarget = item;
					attachAnchor = SemiFunc.PlayerGetFaceEyeTransform(item);
					break;
				}
			}
		}

		[PunRPC]
		private void AttachmentRPC(int victimViewID, int whispralViewID, bool attached, PhotonMessageInfo _info = default(PhotonMessageInfo))
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			if (!SemiFunc.MasterOnlyRPC(_info))
			{
				return;
			}
			PlayerAvatar val = SemiFunc.PlayerAvatarGetFromPhotonID(victimViewID);
			if (!Object.op_Implicit((Object)(object)val))
			{
				VepLogger lOG = LOG;
				InvariantLogMessage message = new InvariantLogMessage(38, 1);
				message.AppendLiteral("AttachmentRPC: no player with ViewID ");
				message.AppendFormatted(victimViewID);
				message.AppendLiteral(".");
				lOG.Debug(ref message);
			}
			else
			{
				Haunting orAddComponent = ComponentHolderProtocol.GetOrAddComponent<Haunting>((Object)(object)val);
				if (attached)
				{
					orAddComponent.Attach(whispralViewID);
				}
				else
				{
					orAddComponent.Detach(whispralViewID);
				}
			}
		}

		internal void SendMimicCommand(PlayerAvatar victim, bool voiceFilter)
		{
			VepLogger lOG = LOG;
			InvariantLogMessage message = new InvariantLogMessage(37, 2);
			message.AppendLiteral("Mimic command: Victim=");
			message.AppendFormatted(victim.playerName);
			message.AppendLiteral(", voice filter=");
			message.AppendFormatted(voiceFilter);
			lOG.Debug(ref message);
			_photonView.RPC("MimicRPC", victim.photonView.Owner, new object[1] { voiceFilter });
		}

		[PunRPC]
		private void MimicRPC(bool voiceFilter, PhotonMessageInfo _info = default(PhotonMessageInfo))
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			if (!SemiFunc.MasterOnlyRPC(_info))
			{
				return;
			}
			Imitations local = Imitations.Local;
			if (!Object.op_Implicit((Object)(object)local))
			{
				LOG.Debug("Mimic command: the local player is not a Victim, nothing plays.");
				return;
			}
			Hallucination hallucination = local.PickMimicSpeaker();
			if (Object.op_Implicit((Object)(object)hallucination))
			{
				hallucination.PlayMimic(voiceFilter);
			}
		}

		private void ReportAttachment(int victimViewID, bool attached)
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			if (SemiFunc.IsMultiplayer())
			{
				_photonView.RPC("AttachmentRPC", (RpcTarget)0, new object[3] { victimViewID, _photonView.ViewID, attached });
			}
			else
			{
				AttachmentRPC(victimViewID, ((Object)this).GetInstanceID(), attached);
			}
		}

		public void OnSpawn()
		{
			if (SemiFunc.IsMasterClientOrSingleplayer() && SemiFunc.EnemySpawn(enemy))
			{
				float? diedAt = _diedAt;
				object obj;
				if (diedAt.HasValue)
				{
					float valueOrDefault = diedAt.GetValueOrDefault();
					obj = $", {Time.time - valueOrDefault:F0} s after its death (return delay {_returnDelay:F0} s)";
				}
				else
				{
					obj = "";
				}
				string value = (string)obj;
				VepLogger lOG = LOG;
				InvariantLogMessage message = new InvariantLogMessage(17, 2);
				message.AppendLiteral("Whispral ");
				message.AppendFormatted(_photonView.ViewID);
				message.AppendLiteral(" spawns");
				message.AppendFormatted(value);
				message.AppendLiteral(".");
				lOG.Debug(ref message);
				_diedAt = null;
				Fsm.NextStateStateId = State.Spawn;
			}
		}

		public void OnHurt()
		{
			enemyWhispralAnim.Hurt();
		}

		public void OnDeath()
		{
			enemyWhispralAnim.Death();
			if (SemiFunc.IsMasterClientOrSingleplayer())
			{
				VepLogger lOG = LOG;
				InvariantLogMessage message = new InvariantLogMessage(27, 2);
				message.AppendLiteral("Whispral ");
				message.AppendFormatted(_photonView.ViewID);
				message.AppendLiteral(" killed in state ");
				message.AppendFormatted(CurrentState);
				message.AppendLiteral(".");
				lOG.Debug(ref message);
				Fsm.NextStateStateId = State.Despawn;
				Fsm.Update();
				EnemyParent enemyParent = enemy.EnemyParent;
				float despawnedTimer = enemyParent.DespawnedTimer;
				_returnDelay = Presence.ReturnDelay(Random.value);
				enemyParent.DespawnedTimerSet(_returnDelay, false);
				_diedAt = Time.time;
				VepLogger lOG2 = LOG;
				InvariantLogMessage message2 = new InvariantLogMessage(54, 4);
				message2.AppendLiteral("Whispral ");
				message2.AppendFormatted(_photonView.ViewID);
				message2.AppendLiteral(" returns in ");
				message2.AppendFormatted(enemyParent.DespawnedTimer, "F0");
				message2.AppendLiteral(" s ");
				message2.AppendLiteral("(drawn ");
				message2.AppendFormatted(_returnDelay, "F0");
				message2.AppendLiteral(" s), not the game's ");
				message2.AppendFormatted(despawnedTimer, "F0");
				message2.AppendLiteral(" s.");
				lOG2.Debug(ref message2);
			}
		}

		public void OnInvestigate()
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			State currentState = CurrentState;
			bool flag = (uint)(currentState - 1) <= 2u;
			bool flag2 = flag;
			if (SemiFunc.IsMasterClientOrSingleplayer() && flag2)
			{
				agentDestination = enemy.StateInvestigate.onInvestigateTriggeredPosition;
				Fsm.NextStateStateId = State.Investigate;
			}
		}

		public void OnVision()
		{
			if (!SemiFunc.IsMasterClientOrSingleplayer())
			{
				return;
			}
			State currentState = CurrentState;
			if (((uint)(currentState - 1) <= 2u || currentState == State.Leave) ? true : false)
			{
				playerTarget = enemy.Vision.onVisionTriggeredPlayer;
				if (SemiFunc.IsMultiplayer())
				{
					_photonView.RPC("UpdatePlayerTargetRPC", (RpcTarget)0, new object[1] { playerTarget.photonView.ViewID });
				}
				Fsm.NextStateStateId = State.NoticePlayer;
			}
			else if (CurrentState == State.GoToPlayer)
			{
				Fsm.GetStateTyped<PlayerGoToState>(State.GoToPlayer)?.RefreshTimer();
			}
		}

		public void OnGrabbed()
		{
			bool flag = !(_grabAggroTimer > 0f);
			if (SemiFunc.IsMasterClientOrSingleplayer() && flag && CurrentState == State.Leave)
			{
				_grabAggroTimer = 60f;
				playerTarget = enemy.Rigidbody.onGrabbedPlayerAvatar;
				if (SemiFunc.IsMultiplayer())
				{
					_photonView.RPC("UpdatePlayerTargetRPC", (RpcTarget)0, new object[1] { playerTarget.photonView.ViewID });
				}
				Fsm.NextStateStateId = State.NoticePlayer;
			}
		}
	}
	public class EnemyWhispralAnim : MonoBehaviour
	{
		private static readonly VepLogger LOG = VepLogger.Create<EnemyWhispralAnim>();

		[Space]
		[SerializeField]
		private Enemy enemy;

		[SerializeField]
		private EnemyWhispral enemyWhispral;

		[Space]
		[SerializeField]
		private Sound soundHurt;

		[SerializeField]
		private Sound soundDeath;

		[Space]
		[SerializeField]
		private GameObject visuals;

		[SerializeField]
		private GameObject rigidBody;

		private bool _hidden;

		private void Update()
		{
			EnemyWhispral.State currentState = enemyWhispral.CurrentState;
			SetHidden(currentState == EnemyWhispral.State.Attached && !enemy.Jump.jumping, currentState);
		}

		public void Death()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			soundDeath.Play(((Component)enemy).transform.position, 1f, 1f, 1f, 1f);
		}

		public void Hurt()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			soundHurt.Play(((Component)enemy).transform.position, 1f, 1f, 1f, 1f);
		}

		public void Despawn()
		{
			SetHidden(hidden: false, EnemyWhispral.State.Despawn);
		}

		private void SetHidden(bool hidden, EnemyWhispral.State state)
		{
			if (hidden != _hidden)
			{
				_hidden = hidden;
				visuals.SetActive(!hidden);
				rigidBody.SetActive(!hidden);
				VepLogger lOG = LOG;
				InvariantLogMessage message = new InvariantLogMessage(21, 3);
				message.AppendLiteral("Whispral ");
				message.AppendFormatted(enemy.PhotonView.ViewID);
				message.AppendLiteral(" ");
				message.AppendFormatted(hidden ? "hidden" : "shown");
				message.AppendLiteral(" in state ");
				message.AppendFormatted(state);
				message.AppendLiteral(".");
				lOG.Debug(ref message);
			}
		}
	}
	public sealed class Hallucination : StateMachineComponent<Hallucination, Hallucination.StateId>
	{
		public enum StateId
		{
			Idle,
			Wander,
			Sprint,
			CheckMap,
			StalkApproach,
			StalkStare,
			StalkLunge,
			StalkFlee
		}

		private sealed class IdleState : StateMachineBase<StateMachine, StateId>.StateBaseTimed
		{
			private const float PrecomputeRetryInterval = 1f;

			private const float CheckMapChance = 0.25f;

			private float _facing;

			private int _glances;

			private float _precomputeTimer;

			private Wait Wait => base.Machine.Owner._wait;

			public override void OnStateEnter(StateId previous)
			{
				//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_0072: Unknown result type (might be due to invalid IL or missing references)
				base.OnStateEnter(previous);
				_precomputeTimer = 0f;
				_glances = 0;
				base.Machine.Owner.Movement.Stop();
				base.Machine.Owner.BodyPose.Move(Gait.Still);
				base.Machine.Owner.Movement.StartPrecomputeDestination();
				Quaternion targetRotation = base.Machine.Owner.Movement.TargetRotation;
				_facing = ((Quaternion)(ref targetRotation)).eulerAngles.y;
				bool flag = Wait.Start();
				LOG.Debug($"IdleState: {((Object)base.Machine.Owner).name} waits {Wait.Duration:F1}s" + (flag ? ", turning round first" : ""));
				if (flag)
				{
					_facing += 180f;
					base.Machine.Owner.Movement.Face(_facing);
					base.Machine.Owner.BodyPose.Glance(_facing);
				}
			}

			public override void OnStateExit(StateId next)
			{
				base.OnStateExit(next);
				base.Machine.Owner.BodyPose.Glance(null);
				VepLogger lOG = LOG;
				InvariantLogMessage message = new InvariantLogMessage(43, 3);
				message.AppendLiteral("IdleState: ");
				message.AppendFormatted(((Object)base.Machine.Owner).name);
				message.AppendLiteral(" glanced ");
				message.AppendFormatted(_glances);
				message.AppendLiteral(" times in its wait of ");
				message.AppendFormatted(Wait.Duration, "F1");
				message.AppendLiteral("s");
				lOG.Debug(ref message);
			}

			public override void OnStateUpdate()
			{
				base.OnStateUpdate();
				Wait.Glance? glance = Wait.Update(Time.deltaTime);
				if (glance.HasValue)
				{
					Wait.Glance valueOrDefault = glance.GetValueOrDefault();
					_glances++;
					base.Machine.Owner.Movement.Face(_facing + valueOrDefault.Body);
					base.Machine.Owner.BodyPose.Glance(_facing + valueOrDefault.Head);
					LOG.Debug($"IdleState: {((Object)base.Machine.Owner).name} glances {valueOrDefault.Head:F0}° from its wait's facing, " + $"{valueOrDefault.OffBody:F0}° off the body, " + (valueOrDefault.BodyFollows ? $"the body following to {valueOrDefault.Body:F0}°" : "the head alone"));
				}
				if (!base.Machine.Owner.Movement.HasPrecomputedDestination)
				{
					_precomputeTimer -= Time.deltaTime;
					if (_precomputeTimer <= 0f)
					{
						base.Machine.Owner.Movement.StartPrecomputeDestination();
						_precomputeTimer = 1f;
					}
				}
				if (!Wait.IsOver)
				{
					return;
				}
				float distanceToPlayer = base.Machine.Owner.Movement.GetDistanceToPlayer();
				bool stalkingRollForced = base.Machine.Owner._stalkingRollForced;
				if (distanceToPlayer > 15f && (stalkingRollForced || Random.value < 0.1f))
				{
					base.Machine.Owner._stalkingRollForced = false;
					string value = (stalkingRollForced ? "forced" : "rolled");
					Hallucination hallucination = base.Machine.Owner.OtherStalker();
					if (hallucination != null)
					{
						VepLogger lOG = LOG;
						InvariantLogMessage message = new InvariantLogMessage(50, 3);
						message.AppendLiteral("IdleState: ");
						message.AppendFormatted(((Object)base.Machine.Owner).name);
						message.AppendLiteral(" refused the Stalking it ");
						message.AppendFormatted(value);
						message.AppendLiteral(": ");
						message.AppendFormatted(((Object)hallucination).name);
						message.AppendLiteral(" is Stalking");
						lOG.Debug(ref message);
					}
					else
					{
						if (!base.Machine.Owner.IsPlayingMimic)
						{
							base.Machine.NextStateStateId = StateId.StalkApproach;
							VepLogger lOG2 = LOG;
							InvariantLogMessage message2 = new InvariantLogMessage(38, 3);
							message2.AppendLiteral("IdleState: ");
							message2.AppendFormatted(((Object)base.Machine.Owner).name);
							message2.AppendLiteral(" -> StalkApproach, ");
							message2.AppendFormatted(value);
							message2.AppendLiteral(" ");
							message2.AppendLiteral("(dist=");
							message2.AppendFormatted(distanceToPlayer, "F1");
							message2.AppendLiteral(")");
							lOG2.Debug(ref message2);
							return;
						}
						VepLogger lOG3 = LOG;
						InvariantLogMessage message3 = new InvariantLogMessage(55, 2);
						message3.AppendLiteral("IdleState: ");
						message3.AppendFormatted(((Object)base.Machine.Owner).name);
						message3.AppendLiteral(" refused the Stalking it ");
						message3.AppendFormatted(value);
						message3.AppendLiteral(": it speaks a Mimic");
						lOG3.Debug(ref message3);
					}
				}
				float value2 = Random.value;
				if (value2 < 0.25f)
				{
					base.Machine.NextStateStateId = StateId.CheckMap;
					VepLogger lOG4 = LOG;
					InvariantLogMessage message4 = new InvariantLogMessage(34, 3);
					message4.AppendLiteral("IdleState: ");
					message4.AppendFormatted(((Object)base.Machine.Owner).name);
					message4.AppendLiteral(" -> CheckMap (roll=");
					message4.AppendFormatted(value2, "F2");
					message4.AppendLiteral(" < ");
					message4.AppendFormatted(0.25f);
					message4.AppendLiteral(")");
					lOG4.Debug(ref message4);
				}
				else
				{
					base.Machine.NextStateStateId = ((!(Random.value < 0.5f)) ? StateId.Wander : StateId.Sprint);
					VepLogger lOG5 = LOG;
					InvariantLogMessage message5 = new InvariantLogMessage(15, 2);
					message5.AppendLiteral("IdleState: ");
					message5.AppendFormatted(((Object)base.Machine.Owner).name);
					message5.AppendLiteral(" -> ");
					message5.AppendFormatted(base.Machine.NextStateStateId);
					lOG5.Debug(ref message5);
				}
			}
		}

		private abstract class MovementState : StateMachineBase<StateMachine, StateId>.StateBaseTimed
		{
			private enum MindChange
			{
				None,
				Stopping,
				Glancing
			}

			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;

			private bool _enteredFromSwitch;

			private MindChange _mindChange;

			private float _glanceEnd;

			private TripChain TripChain => base.Machine.Owner._tripChain;

			private ChangeOfMind ChangeOfMind => base.Machine.Owner._changeOfMind;

			protected abstract float MinDuration { get; }

			protected abstract float MaxDuration { get; }

			protected abstract float Speed { get; }

			protected abstract StateId SwitchTargetState { get; }

			protected abstract Gait Gait { get; }

			public override void OnStateEnter(StateId previous)
			{
				base.OnStateEnter(previous);
				_mindChange = MindChange.None;
				bool enteredFromSwitch = (uint)(previous - 1) <= 1u;
				_enteredFromSwitch = enteredFromSwitch;
				if (_enteredFromSwitch)
				{
					base.Machine.Owner.Movement.TryExtendCurrentPath();
				}
				else
				{
					if (!base.Machine.Owner.Movement.TrySetRandomDestination())
					{
						base.Machine.NextStateStateId = StateId.Idle;
						return;
					}
					TripChain.Start();
					ChangeOfMind.Start();
				}
				SetOff();
			}

			public override void OnStateExit(StateId next)
			{
				base.OnStateExit(next);
				base.Machine.Owner.BodyPose.Glance(null);
				if ((uint)(next - 1) > 1u)
				{
					base.Machine.Owner.Movement.ClearPrecomputedForwardDestination();
				}
			}

			public override void OnStateUpdate()
			{
				base.OnStateUpdate();
				if (_mindChange != MindChange.None)
				{
					UpdateMindChange();
				}
				else if (base.Machine.Owner.Movement.HasReachedDestination())
				{
					if (!ChainsTrip())
					{
						base.Machine.NextStateStateId = StateId.Idle;
					}
				}
				else if (base.TimeElapsed >= _duration)
				{
					base.Machine.NextStateStateId = StateId.Idle;
				}
				else
				{
					if (ChangesMind())
					{
						return;
					}
					_nextPrecomputeForward -= Time.deltaTime;
					if (_nextPrecomputeForward <= 0f)
					{
						_nextPrecomputeForward = 0.5f;
						base.Machine.Owner.Movement.StartPrecomputeForwardDestination();
					}
					if (!_enteredFromSwitch && base.TimeElapsed >= _nextSwitchCheck)
					{
						_nextSwitchCheck += 1f;
						if (Random.value < 0.2f)
						{
							base.Machine.NextStateStateId = SwitchTargetState;
						}
					}
				}
			}

			private bool ChainsTrip()
			{
				TripChain.Arrival arrival = TripChain.Arrive();
				bool flag = arrival.Chains && base.Machine.Owner.Movement.TrySetNearbyDestination();
				LOG.Debug($"{GetType().Name}: {((Object)base.Machine.Owner).name} reached its point, roll={arrival.Roll:F2}" + (arrival.Asked ? " (chain asked)" : "") + ", " + (flag ? "chains a Trip" : (arrival.Capped ? "waits after two Trips in a row" : (arrival.Chains ? "waits, no point to chain to" : "waits"))));
				if (!flag)
				{
					return false;
				}
				ChangeOfMind.Start();
				SetOff();
				return true;
			}

			private bool ChangesMind()
			{
				ChangeOfMind.Change? change = ChangeOfMind.Update(Time.deltaTime);
				if (change.HasValue)
				{
					ChangeOfMind.Change valueOrDefault = change.GetValueOrDefault();
					if (valueOrDefault.Capped)
					{
						LOG.Debug(GetType().Name + ": " + ((Object)base.Machine.Owner).name + " was asked to change its mind, but already did on this Trip: kept for its next Trip");
						return false;
					}
					LOG.Debug(GetType().Name + ": " + ((Object)base.Machine.Owner).name + " changes its mind" + (valueOrDefault.Asked ? " (asked)" : $", roll={valueOrDefault.Roll:F3}") + ", easing to a stop");
					_mindChange = MindChange.Stopping;
					base.Machine.Owner

WebRtcVadSharp.dll

Decompiled 3 days 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);
		}
	}
}