Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of VepMod v2.1.2
VepMod.dll
Decompiled 3 days ago
The result has been truncated due to the large size, download it to view full contents!
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 agousing 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); } } }