using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Threading.Tasks; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Photon.Pun; using Photon.Realtime; using Photon.Voice; using REPOLib.Objects.Sdk; using TMPro; using Unity.VisualScripting; using UnityEngine; using UnityEngine.AI; using UnityEngine.Animations; using UnityEngine.Rendering; using UnityEngine.SceneManagement; using UnityEngine.UI; using VepMod.Enemies.Whispral; using VepMod.Enemies.Whispral.Visuals; using VepMod.Patchs; using VepMod.VepFramework; using VepMod.VepFramework.Audio; using VepMod.VepFramework.Config; using VepMod.VepFramework.Extensions; using VepMod.VepFramework.Structures.FSM; using VepMod.VepFramework.Structures.Range; using WebRtcVadSharp; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("Vep")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+be4c087c041c4823a6c3e289f18800a10bce2486")] [assembly: AssemblyProduct("VepMod")] [assembly: AssemblyTitle("VepMod")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace VepMod { public static class ConfigRanges { public static readonly RangeValue Volume = RangeValue.Percentage(); public static readonly RangeValue SamplesPerPlayer = RangeValue.Int(5, 20, 20); public static readonly RangeValue SamplingRate = RangeValue.Int(16000, 48000, 48000); public static readonly MinMaxRange ShareDelay = MinMaxRange.Float(10f, 60f, 10f, 10f, 120f, 30f); public static readonly MinMaxRange VoiceDelay = MinMaxRange.Float(6f, 30f, 8f, 6f, 30f, 15f); public static readonly RangeValue AudioMinDuration = RangeValue.Float(0.1f, 2f, 0.3f); } [BepInPlugin("com.vep.vepMod", "VepMod", "1.1.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class VepMod : BaseUnityPlugin { private static Harmony _harmony; public static ConfigEntry ConfigVoiceVolume; public static ConfigEntry ConfigSamplingRate; public static BoundMinMaxRange ShareDelay; public static ConfigEntry ConfigSamplesPerPlayer; public static BoundMinMaxRange VoiceDelay; public static ConfigEntry ConfigVoiceFilterEnabled; public static ConfigEntry ConfigAudioMinDuration; public static ConfigEntry ConfigVadEnabled; public static ConfigEntry ConfigVadSensitivity; public static readonly Dictionary> EnemyConfigEntries = new Dictionary>(); internal Harmony? Harmony { get; set; } private void Awake() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Expected O, but got Unknown _harmony = new Harmony("VepMod.Plugin"); PreventDelete(); InitConfig(); _harmony.PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"{((BaseUnityPlugin)this).Info.Metadata.GUID} v{((BaseUnityPlugin)this).Info.Metadata.Version} has loaded!"); ((MonoBehaviour)this).StartCoroutine(DroidPrefabLoader.PreloadAsync(delegate(bool success) { if (success) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"LostDroid prefab preloaded successfully."); } else { ((BaseUnityPlugin)this).Logger.LogWarning((object)"LostDroid prefab preload failed - hallucinations may not work."); } })); } public void OnSceneLoaded(Scene scene, LoadSceneMode mode) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Scene loaded: " + ((Scene)(ref scene)).name)); } private void InitConfig() { //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Expected O, but got Unknown ((BaseUnityPlugin)this).Logger.LogInfo((object)"Initializing config for VepMod..."); ConfigVoiceVolume = ((BaseUnityPlugin)this).Config.BindRange("General", "Volume", ConfigRanges.Volume, "Volume of the mimic voices."); ShareDelay = ((BaseUnityPlugin)this).Config.BindMinMax("Audio Sharing", "Share Min Delay", "Share Max Delay", ConfigRanges.ShareDelay, "Minimum time between sharing audio clips with other players.", "Maximum time between sharing audio clips with other players."); ConfigSamplesPerPlayer = ((BaseUnityPlugin)this).Config.BindRange("Audio Sharing", "Samples Per Player", ConfigRanges.SamplesPerPlayer, "Maximum number of audio samples stored per player."); VoiceDelay = ((BaseUnityPlugin)this).Config.BindMinMax("Voice Playback", "Voice Min Delay", "Voice Max Delay", ConfigRanges.VoiceDelay, "Minimum time between voice playback commands during Whispral debuff.", "Maximum time between voice playback commands during Whispral debuff."); ConfigVoiceFilterEnabled = ((BaseUnityPlugin)this).Config.Bind("Voice Playback", "Voice Filter Enabled?", false, new ConfigDescription("Turning this will enable modifiable filters for which enemies can play back voices during the Whispral debuff.", (AcceptableValueBase)null, Array.Empty())); ConfigSamplingRate = ((BaseUnityPlugin)this).Config.BindRange("Experimental", "Sampling Rate", ConfigRanges.SamplingRate, "Only change this value if the console gives you a warning about your microphone frequency not being supported."); ConfigAudioMinDuration = ((BaseUnityPlugin)this).Config.BindRange("Audio Quality", "Min Duration", ConfigRanges.AudioMinDuration, "Minimum duration in seconds. Shorter recordings are rejected."); ConfigVadEnabled = ((BaseUnityPlugin)this).Config.Bind("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("Audio Quality", "VAD Sensitivity", VadSensitivity.Balanced, "Speech detection strictness. Permissive (ratio 0.20) keeps almost all voice but lets through more noise. Balanced (0.40) is the default best-F1 setting. Strict (0.60) filters more aggressively but may drop quiet voice."); } private void PreventDelete() { ((Component)this).gameObject.transform.parent = null; ((Object)((Component)this).gameObject).hideFlags = (HideFlags)61; } internal void Unpatch() { _harmony.UnpatchSelf(); } } } namespace VepMod.VepFramework { public sealed class VepLogger { private const string Prefix = "VepMod"; private readonly ManualLogSource _log; public bool DebugEnabled { get; set; } private VepLogger(string className, bool debugEnabled = false) { _log = Logger.CreateLogSource("VepMod." + className); DebugEnabled = debugEnabled; } public static VepLogger Create(bool debugEnabled = false) { return new VepLogger(typeof(T).Name, debugEnabled); } public static VepLogger Create(string className, bool debugEnabled = false) { return new VepLogger(className, debugEnabled); } public void Debug(string message) { if (DebugEnabled) { _log.LogDebug((object)message); } } public void Info(string message) { _log.LogInfo((object)message); } public void Warning(string message) { _log.LogWarning((object)message); } public void Error(string message) { _log.LogError((object)message); } } } namespace VepMod.VepFramework.Structures.Range { public sealed class MinMaxRange where T : struct, IComparable { public RangeValue MinRange { get; } public RangeValue MaxRange { get; } public MinMaxRange(RangeValue minRange, RangeValue 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 minLower, float minUpper, float minDefault, float maxLower, float maxUpper, float maxDefault) { return new MinMaxRange(RangeValue.Float(minLower, minUpper, minDefault), RangeValue.Float(maxLower, maxUpper, maxDefault)); } } public sealed class RangeValue where T : struct, IComparable { 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 min, float max, float defaultValue) { return new RangeValue(min, max, defaultValue); } public static RangeValue Int(int min, int max, int defaultValue) { return new RangeValue(min, max, defaultValue); } public static RangeValue Percentage(float defaultValue = 1f) { return new RangeValue(0f, 1f, defaultValue); } } } namespace VepMod.VepFramework.Structures.FSM { public class StateMachineBase where TMachine : StateMachineBase { 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 states = new Dictionary(); private StateBase _currentStateBaseRunning; public TStateId CurrentStateStateId { get; private set; } public TStateId NextStateStateId { get; set; } public StateMachineBase(TStateId defaultStateId) { CurrentStateStateId = defaultStateId; NextStateStateId = defaultStateId; } public void AddState(TStateId stateId, StateBase stateBase) { stateBase.Machine = this as TMachine; if (states.ContainsKey(stateId)) { Debug.LogWarning((object)$"[FSM] Fsm already defines a state with key {stateId}, it will be overidden"); } states[stateId] = stateBase; } public StateBase GetState(TStateId stateId) { if (!states.TryGetValue(stateId, out StateBase value)) { return Default; } return value; } public T GetStateTyped(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 : MonoBehaviour where TOwner : StateMachineComponent { protected sealed class StateMachine : StateMachineBase { 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 WindowsReservedNames = new HashSet(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 where T : struct, IComparable { private readonly MinMaxRange _range; private readonly ConfigEntry _minEntry; private readonly ConfigEntry _maxEntry; public T Min => _range.GetMin(_minEntry.Value, _maxEntry.Value); public T Max => _range.GetMax(_minEntry.Value, _maxEntry.Value); public BoundMinMaxRange(MinMaxRange range, ConfigEntry minEntry, ConfigEntry maxEntry) { _range = range; _minEntry = minEntry; _maxEntry = maxEntry; } } public static class ConfigExtensions { private static AcceptableValueRange ToAcceptableValueRange(this RangeValue range) where T : struct, IComparable, IComparable { return new AcceptableValueRange(range.Min, range.Max); } private static ConfigDescription ToConfigDescription(this RangeValue range, string description) where T : struct, IComparable, IComparable { //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()); } public static ConfigEntry BindRange(this ConfigFile config, string section, string key, RangeValue range, string description) where T : struct, IComparable, IComparable { return config.Bind(section, key, range.Default, range.ToConfigDescription(description)); } public static BoundMinMaxRange BindMinMax(this ConfigFile config, string section, string minKey, string maxKey, MinMaxRange range, string minDescription, string maxDescription) where T : struct, IComparable, IComparable { ConfigEntry minEntry = config.Bind(section, minKey, range.MinRange.Default, range.MinRange.ToConfigDescription(minDescription)); ConfigEntry maxEntry = config.Bind(section, maxKey, range.MaxRange.Default, range.MaxRange.ToConfigDescription(maxDescription)); return new BoundMinMaxRange(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(); } 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(); } 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(); [HarmonyPrefix] private static void Prefix(EnemyParent _enemyParent) { LOG.Info($"EnemyDirector.FirstSpawnPointAdd: {_enemyParent} added as first spawn point."); } } [HarmonyPatch(typeof(LocalVoiceFramed), "PushDataAsync")] internal class LocalVoiceFramedPatch { private static readonly VepLogger LOG = VepLogger.Create(); private static void Prefix(short[] buf, LocalVoiceFramed __instance) { VepFinder.EnsureInitialized(); if (!IsNotReady()) { var (frameSampleRate, channels) = VoiceFormatResolver.Resolve(__instance, buf.Length); VepFinder.LocalMimics.ProcessVoiceData(buf, frameSampleRate, channels); } } private static bool IsNotReady() { bool flag = !PhotonNetwork.IsConnectedAndReady; WhispralMimics localMimics = VepFinder.LocalMimics; bool flag2 = (Object)(object)localMimics == (Object)null; if (flag || flag2) { return true; } bool flag3 = (Object)(object)((Component)localMimics).gameObject == (Object)null; bool flag4 = (Object)(object)localMimics.PhotonView == (Object)null || !localMimics.PhotonView.IsMine; return flag3 || flag4; } } [HarmonyPatch(typeof(Materials))] internal static class MaterialsImpulsePatch { [HarmonyPrefix] [HarmonyPatch("Impulse")] private static bool Impulse_Prefix(Vector3 origin, bool footstep, HostType hostType) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Invalid comparison between Unknown and I4 if (!footstep) { return true; } if ((int)hostType != 0 && (int)hostType != 1) { return true; } if (InvisiblePlayerDebuff.IsPositionNearHiddenPlayer(origin)) { return false; } return true; } } [HarmonyPatch(typeof(PlayerAvatar), "Awake")] internal class PlayerAvatarPatch { private static readonly VepLogger LOG = VepLogger.Create(); private static void Postfix(PlayerAvatar __instance) { if (PhotonNetwork.IsConnectedAndReady) { WhispralMimics whispralMimics = ((Component)__instance).GetComponent(); if (!Object.op_Implicit((Object)(object)whispralMimics)) { whispralMimics = ((Component)__instance).gameObject.AddComponent(); LOG.Debug("Added Mimics component to PlayerAvatar: " + ((Object)__instance).name); } else { LOG.Warning("PlayerAvatar: " + ((Object)__instance).name + " already has a WhispralMimics component."); } PhotonView component = ((Component)__instance).GetComponent(); if (!Object.op_Implicit((Object)(object)component) || !component.IsMine) { LOG.Warning("PhotonView is null or not owned by local player."); return; } VepFinder.LocalMimics = whispralMimics; LOG.Info("Set LocalMimics for local PlayerAvatar: " + ((Object)__instance).name); } } } [HarmonyPatch(typeof(PlayerController))] internal static class PlayerControllerPatch { } public class VepFinder : MonoBehaviour { private static VepFinder _instance; private static bool _initialized; private static readonly VepLogger LOG = VepLogger.Create(); public static WhispralMimics LocalMimics { get; set; } private void OnDestroy() { if (_initialized) { LocalMimics = null; _instance = null; LOG.Info("VepFinder destroyed, clearing cache."); } } public static void EnsureInitialized() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)_instance)) { _instance = new GameObject("VepFinder").AddComponent(); _initialized = true; Object.DontDestroyOnLoad((Object)(object)((Component)_instance).gameObject); Player localPlayer = PhotonNetwork.LocalPlayer; LOG.Info($"MimicsFinder initialized for Player {((localPlayer != null) ? localPlayer.ActorNumber : (-1))}"); } } } public static class VoiceFormatResolver { private sealed class Format { public int SampleRate { get; } public int Channels { get; } public Format(int sampleRate, int channels) { SampleRate = sampleRate; Channels = channels; } } private const int MinPlausibleRate = 8000; private const int MaxPlausibleRate = 48000; private static readonly VepLogger LOG = VepLogger.Create("VoiceFormatResolver", debugEnabled: true); private static readonly ConditionalWeakTable Cache = new ConditionalWeakTable(); public static (int sampleRate, int channels) Resolve(object voice, int bufferLength) { if (voice == null) { return (sampleRate: 48000, channels: 1); } if (Cache.TryGetValue(voice, out Format value)) { return (sampleRate: value.SampleRate, channels: value.Channels); } Format format = ResolveUncached(voice, bufferLength); Cache.Add(voice, format); return (sampleRate: format.SampleRate, channels: format.Channels); } private static Format ResolveUncached(object voice, int bufferLength) { object obj = null; try { obj = GetMemberValue(voice, "Info"); } catch (Exception ex) { LOG.Warning("Could not read voice Info: " + ex.Message); } int? num = TryGetInt(voice, "InputSamplingRate"); int? num2 = TryGetInt(voice, "InputChannels"); int? num3 = TryGetInt(voice, "ForceChannels"); int? num4 = ((obj != null) ? TryGetInt(obj, "SamplingRate") : ((int?)null)); int? num5 = ((obj != null) ? TryGetInt(obj, "Channels") : ((int?)null)); int? value = ((obj != null) ? TryGetInt(obj, "FrameDurationUs") : ((int?)null)); int num6 = FirstPlausibleChannels(num2, num3, num5) ?? 1; int num7; string source; if (IsPlausibleRate(num)) { num7 = num.Value; source = "InputSamplingRate"; } else if (value.HasValue && value.GetValueOrDefault() > 0 && bufferLength > 0) { double num8 = (double)bufferLength / (double)num6; int num9 = (int)Math.Round(num8 * 1000000.0 / (double)value.Value); if (IsPlausibleRate(num9)) { num7 = num9; source = "derived(FrameDurationUs)"; } else { num7 = FallbackRate(num4, out source); } } else { num7 = FallbackRate(num4, out source); } LOG.Info($"Voice source format resolved: {num7} Hz, {num6} ch (via {source}). " + "Candidates: InputSamplingRate=" + Fmt(num) + ", InputChannels=" + Fmt(num2) + ", ForceChannels=" + Fmt(num3) + ", encoder=" + Fmt(num4) + "Hz/" + Fmt(num5) + "ch, " + $"FrameDurationUs={Fmt(value)}, bufferLength={bufferLength}."); return new Format(num7, num6); } private static int FallbackRate(int? encoderRate, out string source) { if (IsPlausibleRate(encoderRate)) { source = "Info.SamplingRate(fallback)"; return encoderRate.Value; } source = "default(fallback)"; return 48000; } private static int? FirstPlausibleChannels(params int?[] candidates) { for (int i = 0; i < candidates.Length; i++) { int? result = candidates[i]; if (result.HasValue) { int valueOrDefault = result.GetValueOrDefault(); if (valueOrDefault >= 1 && valueOrDefault <= 8) { return result; } } } return null; } private static bool IsPlausibleRate(int? rate) { if (rate.HasValue) { int valueOrDefault = rate.GetValueOrDefault(); if (valueOrDefault >= 8000) { return valueOrDefault <= 48000; } } return false; } private static int? TryGetInt(object obj, string name) { try { object memberValue = GetMemberValue(obj, name); object obj2 = memberValue; return (obj2 == null) ? ((int?)null) : ((obj2 is int value) ? new int?(value) : ((!(obj2 is Enum)) ? ((!(memberValue is IConvertible)) ? ((int?)null) : new int?(Convert.ToInt32(memberValue))) : new int?(Convert.ToInt32(memberValue)))); } catch { return null; } } private static object? GetMemberValue(object obj, string name) { Type type = obj.GetType(); while (type != null) { PropertyInfo property = type.GetProperty(name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property != null && property.CanRead) { return property.GetValue(obj); } FieldInfo field = type.GetField(name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { return field.GetValue(obj); } type = type.BaseType; } return null; } private static string Fmt(int? value) { return value?.ToString() ?? "n/a"; } } } namespace VepMod.Enemies.Whispral { public static class AudioFilters { private const float TwoPi = MathF.PI * 2f; private const float Int16MaxValue = 32768f; private const float AlienVibratoFrequency = 5f; private const float AlienVibratoDepth = 0.05f; private const float AlienRingModFrequency = 200f; private const float AlienRingModMix = 0.3f; public const float PitchShiftLow = 0.5f; public const float PitchShiftHigh = 1.2f; private const float DefaultLowPassCutoff = 4500f; public static float[] ApplyAlienFilter(float[] samples, int sampleRate) { float[] array = new float[samples.Length]; for (int i = 0; i < samples.Length; i++) { float num = (float)i / (float)sampleRate; float num2 = 1f + Mathf.Sin(MathF.PI * 10f * num) * 0.05f; float num3 = (float)i * num2; int num4 = (int)num3; float num5 = num3 - (float)num4; float num6 = ((num4 + 1 >= samples.Length) ? ((num4 >= samples.Length) ? 0f : samples[num4]) : (samples[num4] * (1f - num5) + samples[num4 + 1] * num5)); float num7 = Mathf.Sin(MathF.PI * 400f * num); float num8 = num6 * num7 * 0.3f; array[i] = Mathf.Clamp(num6 * 0.7f + num8, -1f, 1f); } return array; } public static float[] ApplyLowPassFilter(float[] samples, int sampleRate, float cutoffFrequency = 4500f) { float num = 1f / (MathF.PI * 2f * cutoffFrequency); float num2 = 1f / (float)sampleRate; float num3 = num2 / (num + num2); float[] array = new float[samples.Length]; array[0] = samples[0]; for (int i = 1; i < samples.Length; i++) { array[i] = array[i - 1] + num3 * (samples[i] - array[i - 1]); } float[] array2 = new float[samples.Length]; array2[samples.Length - 1] = array[samples.Length - 1]; for (int num4 = samples.Length - 2; num4 >= 0; num4--) { array2[num4] = array2[num4 + 1] + num3 * (array[num4] - array2[num4 + 1]); } return array2; } public static float[] ApplyPitchShift(float[] samples, float pitchFactor) { int num = (int)((float)samples.Length / pitchFactor); float[] array = new float[num]; for (int i = 0; i < num; i++) { float num2 = (float)i * pitchFactor; int num3 = (int)num2; float num4 = num2 - (float)num3; if (num3 + 1 < samples.Length) { array[i] = samples[num3] * (1f - num4) + samples[num3 + 1] * num4; } else if (num3 < samples.Length) { array[i] = samples[num3]; } } return array; } public static float[] ConvertBytesToFloats(byte[] byteArray) { int num = byteArray.Length / 2; float[] array = new float[num]; for (int i = 0; i < num; i++) { short num2 = (short)(byteArray[i * 2] | (byteArray[i * 2 + 1] << 8)); array[i] = (float)num2 / 32768f; } return array; } public static byte[] ConvertFloatsToBytes(float[] floatArray) { byte[] array = new byte[floatArray.Length * 2]; for (int i = 0; i < floatArray.Length; i++) { short num = (short)(floatArray[i] * 32767f); array[i * 2] = (byte)(num & 0xFF); array[i * 2 + 1] = (byte)((num >> 8) & 0xFF); } return array; } public static float[] ApplyFadeAndPadding(float[] samples, int sampleRate) { int num = (int)((float)sampleRate * 0.5f); int num2 = (int)((float)sampleRate * 0.02f); float[] array = new float[samples.Length + 2 * num]; for (int i = 0; i < num; i++) { array[i] = 0f; } for (int j = 0; j < samples.Length; j++) { float num3 = 1f; if (j < num2) { num3 = (float)j / (float)num2; } else if (j >= samples.Length - num2) { num3 = (float)(samples.Length - j) / (float)num2; } array[j + num] = samples[j] * num3; } for (int k = samples.Length + num; k < array.Length; k++) { array[k] = 0f; } return array; } } public sealed class DilatedPupilsDebuff : MonoBehaviour { private const float PupilSizeMultiplier = 3f; private const int Priority = 5; private const float SpringSpeedIn = 10f; private const float SpringDampIn = 0.5f; private const float SpringSpeedOut = 5f; private const float SpringDampOut = 0.3f; private const float RefreshInterval = 0.1f; private static readonly VepLogger LOG = VepLogger.Create(); private PlayerAvatar? playerAvatar; private float refreshTimer; public bool IsActive { get; private set; } private void Awake() { playerAvatar = ((Component)this).GetComponent(); } private void Update() { if (IsActive && !((Object)(object)playerAvatar == (Object)null)) { refreshTimer -= Time.deltaTime; if (refreshTimer <= 0f) { ApplyPupilEffect(); refreshTimer = 0.1f; } } } public void ApplyDebuff(bool dilated) { IsActive = dilated; LOG.Debug($"Applying dilated pupils debuff: {dilated}"); if (dilated) { refreshTimer = 0f; ApplyPupilEffect(); } } private void ApplyPupilEffect() { if (!((Object)(object)playerAvatar == (Object)null)) { playerAvatar.OverridePupilSize(3f, 5, 10f, 0.5f, 5f, 0.3f, 0.15f); } } } public sealed class DroidAvatarAnimationController : MonoBehaviour { private static readonly VepLogger LOG = VepLogger.Create(); private static readonly int MovingKey = Animator.StringToHash("Moving"); private static readonly int SprintingKey = Animator.StringToHash("Sprinting"); private static readonly int TurningKey = Animator.StringToHash("Turning"); private static readonly int GrabbingKey = Animator.StringToHash("Grabbing"); private static readonly int CrouchingKey = Animator.StringToHash("Crouching"); private static readonly int CrawlingKey = Animator.StringToHash("Crawling"); private static readonly int TumblingKey = Animator.StringToHash("Tumbling"); private static readonly int TumblingMoveKey = Animator.StringToHash("TumblingMove"); private static readonly int SlidingKey = Animator.StringToHash("Sliding"); private static readonly int JumpingKey = Animator.StringToHash("Jumping"); private static readonly int FallingKey = Animator.StringToHash("Falling"); private static readonly int StunKey = Animator.StringToHash("stun"); private static readonly int SprintingImpulseKey = Animator.StringToHash("SprintingImpulse"); private DroidController _droid; private Animator _animator; private bool _wasSprinting; public float AnimationSpeedMultiplier { get; set; } = 1f; public void Initialize(DroidController droid, Animator animator) { _droid = droid; _animator = animator; } private void Update() { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_animator == (Object)null) && !((Object)(object)_droid == (Object)null)) { bool isInMovementState = _droid.IsInMovementState; bool flag = false; if (isInMovementState && (Object)(object)_droid.ControllerTransform != (Object)null && (Object)(object)_droid.Movement != (Object)null) { float num = Quaternion.Angle(_droid.ControllerTransform.rotation, _droid.Movement.TargetRotation); flag = num > 7f; } bool isSprinting = _droid.IsSprinting; bool flag2 = _droid.IsWalking || isSprinting; _animator.SetBool(MovingKey, flag2); _animator.SetBool(SprintingKey, isSprinting); _animator.SetBool(TurningKey, flag); _animator.SetBool(GrabbingKey, _droid.WantsGrabbing); _animator.SetBool(CrouchingKey, false); _animator.SetBool(CrawlingKey, false); _animator.SetBool(TumblingKey, false); _animator.SetBool(TumblingMoveKey, false); _animator.SetBool(SlidingKey, false); _animator.SetBool(JumpingKey, false); _animator.SetBool(FallingKey, _droid.IsFalling); _animator.SetBool(StunKey, false); if (isSprinting && !_wasSprinting) { _animator.SetTrigger(SprintingImpulseKey); } _wasSprinting = isSprinting; _animator.speed = AnimationSpeedMultiplier; } } } public sealed class DroidController : StateMachineComponent { public enum StateId { Idle, Wander, Sprint, CheckMap, StalkApproach, StalkStare, StalkFlee } private sealed class IdleState : StateMachineBase.StateBaseTimed { private const string ClipName = "LostDroidStand"; private const float IdleLoopStart = 0f; private const float IdleLoopEnd = 4.5f; private const float BlendDelay = 0.3f; private const float MinIdleTime = 2f; private const float MaxIdleTime = 4f; private const float PrecomputeRetryInterval = 1f; private const float CheckMapChance = 0.25f; private Animator _animator; private bool _animatorTakenOver; private AnimationClip? _clip; private float _currentTime; private float _duration; private float _precomputeTimer; private GameObject? _targetObject; public override void OnStateEnter(StateId previous) { base.OnStateEnter(previous); _duration = Random.Range(2f, 4f); _precomputeTimer = 0f; _animatorTakenOver = false; base.Machine.Owner.ResetPath(); base.Machine.Owner.HasChangedMovementState = false; _animator = base.Machine.Owner.Animator; if ((Object)(object)_animator != (Object)null) { _clip = DroidHelpers.GetAnimationClip(_animator, "LostDroidStand"); if ((Object)(object)_clip != (Object)null) { _targetObject = ((Component)_animator).gameObject; } } base.Machine.Owner.StartPrecomputeDestination(); } public override void OnStateUpdate() { base.OnStateUpdate(); if (!_animatorTakenOver && (Object)(object)_clip != (Object)null && (Object)(object)_targetObject != (Object)null && base.TimeElapsed >= 0.3f) { ((Behaviour)_animator).enabled = false; _currentTime = 0f; _animatorTakenOver = true; } if (_animatorTakenOver && (Object)(object)_clip != (Object)null && (Object)(object)_targetObject != (Object)null) { _currentTime += Time.deltaTime; if (_currentTime >= 4.5f) { _currentTime = 0f; } _clip.SampleAnimation(_targetObject, _currentTime); } if (!base.Machine.Owner.HasPrecomputedDestination) { _precomputeTimer -= Time.deltaTime; if (_precomputeTimer <= 0f) { base.Machine.Owner.StartPrecomputeDestination(); _precomputeTimer = 1f; } } if (!(base.TimeElapsed >= _duration)) { return; } float distanceToPlayer = base.Machine.Owner.GetDistanceToPlayer(); if (distanceToPlayer > 15f && Random.value < 0.1f) { base.Machine.NextStateStateId = StateId.StalkApproach; LOG.Debug($"IdleState: -> StalkApproach (dist={distanceToPlayer:F1})"); return; } float value = Random.value; if (value < 0.25f) { base.Machine.NextStateStateId = StateId.CheckMap; LOG.Debug($"IdleState: -> CheckMap (roll={value:F2} < {0.25f})"); } else { base.Machine.NextStateStateId = ((!(Random.value < 0.5f)) ? StateId.Wander : StateId.Sprint); LOG.Debug($"IdleState: -> {base.Machine.NextStateStateId}"); } } public override void OnStateExit(StateId next) { base.OnStateExit(next); if ((Object)(object)_animator != (Object)null) { ((Behaviour)_animator).enabled = true; } } } private abstract class MovementState : StateMachineBase.StateBaseTimed { private const float SwitchCheckInterval = 1f; private const float SwitchChance = 0.2f; private const float PrecomputeForwardInterval = 0.5f; private float _duration; private float _nextPrecomputeForward; private float _nextSwitchCheck; protected abstract float MinDuration { get; } protected abstract float MaxDuration { get; } protected abstract float Speed { get; } protected abstract StateId SwitchTargetState { get; } protected abstract void SetMovementFlag(bool value); public override void OnStateEnter(StateId previous) { base.OnStateEnter(previous); _duration = Random.Range(MinDuration, MaxDuration); _nextSwitchCheck = 1f; _nextPrecomputeForward = 0.5f; if ((uint)(previous - 1) <= 1u) { base.Machine.Owner.TryExtendCurrentPath(); } else if (!base.Machine.Owner.TrySetRandomDestination()) { base.Machine.NextStateStateId = StateId.Idle; return; } base.Machine.Owner.SetSpeed(Speed); SetMovementFlag(value: true); base.Machine.Owner.StartPrecomputeForwardDestination(); } public override void OnStateExit(StateId next) { base.OnStateExit(next); SetMovementFlag(value: false); if ((uint)(next - 1) > 1u) { base.Machine.Owner.ClearPrecomputedForwardDestination(); } } public override void OnStateUpdate() { base.OnStateUpdate(); if (base.Machine.Owner.HasReachedDestination() || base.TimeElapsed >= _duration) { base.Machine.NextStateStateId = StateId.Idle; return; } _nextPrecomputeForward -= Time.deltaTime; if (_nextPrecomputeForward <= 0f) { _nextPrecomputeForward = 0.5f; base.Machine.Owner.StartPrecomputeForwardDestination(); } if (!base.Machine.Owner.HasChangedMovementState && base.TimeElapsed >= _nextSwitchCheck) { _nextSwitchCheck += 1f; if (Random.value < 0.2f) { base.Machine.Owner.HasChangedMovementState = true; base.Machine.NextStateStateId = SwitchTargetState; } } } } private sealed class WanderState : MovementState { protected override float MinDuration => 5f; protected override float MaxDuration => 15f; protected override float Speed => 2f; protected override StateId SwitchTargetState => StateId.Sprint; protected override void SetMovementFlag(bool value) { base.Machine.Owner.IsWalking = value; } } private sealed class SprintState : MovementState { protected override float MinDuration => 3f; protected override float MaxDuration => 8f; protected override float Speed => 5f; protected override StateId SwitchTargetState => StateId.Wander; protected override void SetMovementFlag(bool value) { base.Machine.Owner.IsSprinting = value; } } private sealed class CheckMapState : StateMachineBase.StateBaseTimed { private enum Phase { Raise, Look, Lower } private const float RaiseDuration = 0.85f; private const float LowerDuration = 0.22f; private const float MinLookDuration = 0.5f; private const float MaxLookDuration = 3f; private Phase _currentPhase; private float _lookDuration; private float _phaseTimer; public override void OnStateEnter(StateId previous) { base.OnStateEnter(previous); base.Machine.Owner.IsWalking = false; base.Machine.Owner.IsSprinting = false; base.Machine.Owner.ResetPath(); base.Machine.Owner.ShowMapTool(visible: true); _lookDuration = Random.Range(0.5f, 3f); _currentPhase = Phase.Raise; _phaseTimer = 0f; LOG.Debug(string.Format("CheckMapState: ENTER - LookDuration={0:F1}s, mapToolClone={1}", _lookDuration, ((Object)(object)base.Machine.Owner._mapToolClone != (Object)null) ? "ok" : "NULL")); } public override void OnStateUpdate() { base.OnStateUpdate(); _phaseTimer += Time.deltaTime; switch (_currentPhase) { case Phase.Raise: if (_phaseTimer >= 0.85f) { _currentPhase = Phase.Look; _phaseTimer = 0f; LOG.Debug("CheckMapState: -> Look"); } break; case Phase.Look: if (_phaseTimer >= _lookDuration) { base.Machine.Owner.ShowMapTool(visible: false); _currentPhase = Phase.Lower; _phaseTimer = 0f; LOG.Debug("CheckMapState: -> Lower"); } break; case Phase.Lower: if (_phaseTimer >= 0.22f) { LOG.Debug("CheckMapState: Done, back to Idle"); base.Machine.NextStateStateId = StateId.Idle; } break; } } public override void OnStateExit(StateId next) { base.OnStateExit(next); LOG.Debug($"CheckMapState: EXIT -> {next}"); base.Machine.Owner.ShowMapTool(visible: false); } } private sealed class StalkApproachState : StateMachineBase.StateBaseTimed { private const float MaxApproachTime = 30f; private const float DestinationUpdateInterval = 1f; private float _nextDestinationUpdate; public override void OnStateEnter(StateId previous) { base.OnStateEnter(previous); LOG.Debug("=== STALK: Approach started - running towards player ==="); base.Machine.Owner.IsSprinting = true; base.Machine.Owner.SetSpeed(5f); _nextDestinationUpdate = 0f; if (!base.Machine.Owner.TrySetDestinationToPlayer()) { LOG.Debug("STALK: Failed to set destination to player, aborting"); base.Machine.NextStateStateId = StateId.Idle; } } public override void OnStateUpdate() { base.OnStateUpdate(); float distanceToPlayer = base.Machine.Owner.GetDistanceToPlayer(); bool flag = base.Machine.Owner.HasReachedDestination(); if (base.TimeElapsed >= 30f) { LOG.Debug($"STALK: Approach timeout, dist={distanceToPlayer:F1}m, aborting"); base.Machine.NextStateStateId = StateId.Idle; return; } if (distanceToPlayer <= 5f) { LOG.Debug($"STALK: Arrived near player (distance={distanceToPlayer:F1}m)"); base.Machine.NextStateStateId = StateId.StalkStare; return; } if (flag) { LOG.Debug($"STALK: Reached nav destination but player still at {distanceToPlayer:F1}m, starting stare anyway"); base.Machine.NextStateStateId = StateId.StalkStare; return; } _nextDestinationUpdate -= Time.deltaTime; if (_nextDestinationUpdate <= 0f) { base.Machine.Owner.TrySetDestinationToPlayer(); _nextDestinationUpdate = 1f; } } public override void OnStateExit(StateId next) { base.OnStateExit(next); base.Machine.Owner.IsSprinting = false; base.Machine.Owner.ResetPath(); } } private sealed class StalkStareState : StateMachineBase.StateBaseTimed { private const float MaxStareTime = 30f; private const float DestinationUpdateInterval = 0.5f; private float _fleeCountdown; private bool _hasBeenSeen; private float _nextDestinationUpdate; public override void OnStateEnter(StateId previous) { base.OnStateEnter(previous); LOG.Debug("=== STALK: Staring at player ==="); _hasBeenSeen = false; _fleeCountdown = 2f; _nextDestinationUpdate = 0f; base.Machine.Owner.IsWalking = true; base.Machine.Owner.IsSprinting = false; base.Machine.Owner.SetSpeed(2f); } public override void OnStateUpdate() { base.OnStateUpdate(); base.Machine.Owner.LookAtPlayer(); float distanceToPlayer = base.Machine.Owner.GetDistanceToPlayer(); if (base.Machine.Owner.IsPlayerLookingAtMe && !_hasBeenSeen) { _hasBeenSeen = true; LOG.Debug("=== STALK: Player sees me! Maintaining eye contact... ==="); base.Machine.Owner.IsWalking = false; base.Machine.Owner.ResetPath(); } if (_hasBeenSeen) { _fleeCountdown -= Time.deltaTime; if (_fleeCountdown <= 0f) { LOG.Debug("=== STALK: Eye contact over, fleeing! ==="); base.Machine.NextStateStateId = StateId.StalkFlee; return; } } else if (distanceToPlayer > 3f) { _nextDestinationUpdate -= Time.deltaTime; if (_nextDestinationUpdate <= 0f) { base.Machine.Owner.TrySetDestinationToPlayer(); _nextDestinationUpdate = 0.5f; } } else { base.Machine.Owner.ResetPath(); } if (base.TimeElapsed >= 30f) { LOG.Debug("STALK: Stare timeout, fleeing"); base.Machine.NextStateStateId = StateId.StalkFlee; } } public override void OnStateExit(StateId next) { base.OnStateExit(next); base.Machine.Owner.IsWalking = false; } } private sealed class StalkFleeState : StateMachineBase.StateBaseTimed { private const float MaxFleeTime = 10f; public override void OnStateEnter(StateId previous) { base.OnStateEnter(previous); LOG.Debug("=== STALK: Fleeing from player! ==="); base.Machine.Owner.IsSprinting = true; base.Machine.Owner.SetSpeed(5f); if (!base.Machine.Owner.TrySetFleeDestination()) { LOG.Debug("STALK: Failed to set flee destination, going to idle"); base.Machine.NextStateStateId = StateId.Idle; } } public override void OnStateUpdate() { base.OnStateUpdate(); if (base.Machine.Owner.HasReachedDestination() || base.TimeElapsed >= 10f) { LOG.Debug("=== STALK: Flee complete, returning to idle ==="); base.Machine.NextStateStateId = StateId.Idle; } } public override void OnStateExit(StateId next) { base.OnStateExit(next); base.Machine.Owner.IsSprinting = false; } } internal const float WalkSpeed = 2f; internal const float SprintSpeed = 5f; internal const float SprintChance = 0.5f; internal const float StalkMinDistance = 15f; internal const float StalkChance = 0.1f; internal const float StalkArrivalDistance = 5f; internal const float StalkMinKeepDistance = 3f; internal const float StalkFleeDistance = 20f; internal const float StalkStareBeforeFlee = 2f; private static readonly VepLogger LOG = VepLogger.Create(); private readonly MaterialTrigger _materialTrigger = new MaterialTrigger(); private DroidFaceAnimationController _animController; private DroidRightArmPoseController? _armPoseController; private DroidLeftArmPoseController? _leftArmPoseController; private DroidAvatarAnimationController _avatarAnimController; private CharacterController _charController; private DroidEyeLookAtController? _eyeLookController; private GameObject? _mapToolClone; private DroidNameplate _nameplateController; private NavMeshAgent _navAgent; private Transform _rigidbodyTransform; private int _savedAgentTypeID; private int _savedAreaMask = -1; internal Animator Animator; public bool IsWalking { get; set; } public bool IsSprinting { get; set; } public bool HasChangedMovementState { get; set; } public bool WantsGrabbing { get; set; } public PlayerAvatar SourcePlayer { get; private set; } public Transform ControllerTransform { get; private set; } public DroidMovementController Movement { get; private set; } public bool IsPlayerLookingAtMe => _animController.IsPlayerLookingAtMe; public bool IsStalking { get { StateId currentStateStateId = Fsm.CurrentStateStateId; if ((uint)(currentStateStateId - 4) <= 2u) { return true; } return false; } } public bool IsInMovementState => DroidHelpers.IsMovementState(Fsm.CurrentStateStateId); public bool IsFalling { get { if ((Object)(object)Movement != (Object)null) { return Movement.IsFalling; } return false; } } public string DebugStateName => Fsm.CurrentStateStateId.ToString(); protected override StateId DefaultState => StateId.Idle; public bool HasPrecomputedDestination => Movement.HasPrecomputedDestination; protected override void Awake() { } protected override void Update() { if (!((Object)(object)Movement == (Object)null) && !((Object)(object)_navAgent == (Object)null) && _navAgent.isOnNavMesh && !((Object)(object)ControllerTransform == (Object)null)) { Fsm.Update(); StateId currentStateStateId = Fsm.CurrentStateStateId; bool isMovementState = DroidHelpers.IsMovementState(currentStateStateId); Movement.UpdateMovement(isMovementState); Movement.UpdateRotation(); Movement.SyncVisualsToController(((Object)(object)Animator != (Object)null) ? ((Component)Animator).transform : null); Movement.SyncNavAgentPosition(isMovementState); } } public void ShowMapTool(bool visible) { LOG.Debug(string.Format("ShowMapTool({0}) - clone={1}", visible, ((Object)(object)_mapToolClone != (Object)null) ? "ok" : "NULL")); if ((Object)(object)_mapToolClone != (Object)null) { _mapToolClone.SetActive(visible); } WantsGrabbing = visible; } public void PlayVoice(bool applyFilter = false) { if ((Object)(object)SourcePlayer == (Object)null || (Object)(object)ControllerTransform == (Object)null) { return; } PlayerAvatar instance = PlayerAvatar.instance; if (!((Object)(object)instance == (Object)null)) { WhispralMimics component = ((Component)instance).GetComponent(); if ((Object)(object)component == (Object)null) { LOG.Warning("WhispralMimics not found on local player"); } else { component.PlayAudioAtTransform(ControllerTransform, SourcePlayer.playerName, applyFilter); } } } public void DebugTeleport(Vector3 worldPosition) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)ControllerTransform == (Object)null)) { if ((Object)(object)_charController != (Object)null) { ((Collider)_charController).enabled = false; } ControllerTransform.position = worldPosition; if ((Object)(object)_charController != (Object)null) { ((Collider)_charController).enabled = true; } } } public bool TrySetRandomDestination() { if ((Object)(object)Movement != (Object)null) { return Movement.TrySetRandomDestination(); } return false; } public bool TryExtendCurrentPath() { if ((Object)(object)Movement != (Object)null) { return Movement.TryExtendCurrentPath(); } return false; } public void StartPrecomputeForwardDestination() { Movement?.StartPrecomputeForwardDestination(); } public void ClearPrecomputedForwardDestination() { Movement?.ClearPrecomputedForwardDestination(); } public void StartPrecomputeDestination() { Movement.StartPrecomputeDestination(); } public void ResetPath() { Movement.ResetPath(); } public bool HasReachedDestination() { return Movement.HasReachedDestination(); } public float GetDistanceToPlayer() { return Movement.GetDistanceToPlayer(); } public bool TrySetDestinationToPlayer() { if ((Object)(object)Movement != (Object)null) { return Movement.TrySetDestinationToPlayer(); } return false; } public bool TrySetFleeDestination() { if ((Object)(object)Movement != (Object)null) { return Movement.TrySetFleeDestination(20f); } return false; } public void LookAtPlayer() { Movement.LookAtPlayer(); } public void SetSpeed(float speed) { Movement.SetSpeed(speed); } public static DroidController? Create(PlayerAvatar sourcePlayer, Vector3 spawnPosition) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) if (!DroidPrefabLoader.IsAvailable) { LOG.Warning("LostDroid prefab not available"); return null; } GameObject val = Object.Instantiate(DroidPrefabLoader.DroidPrefab, spawnPosition, Quaternion.identity); if ((Object)(object)val == (Object)null) { LOG.Error("Failed to instantiate LostDroid prefab"); return null; } ((Object)val).name = "HallucinationDroid_" + sourcePlayer.playerName; DroidController droidController = val.AddComponent(); droidController.Initialize(sourcePlayer); return droidController; } private void Initialize(PlayerAvatar sourcePlayer) { //IL_0053: Unknown result type (might be due to invalid IL or missing references) SourcePlayer = sourcePlayer; FindCriticalTransforms(); SaveNavMeshSettings(); DisableEnemyComponents(); SetupNavigation(); SetupMovementController(); SetupClonedVisuals(); SetupAnimationController(); SetupNameplate(); InitializeFsm(); LOG.Info($"HallucinationDroid created for {sourcePlayer.playerName} at {ControllerTransform.position}"); } private void SetupMovementController() { if (!((Object)(object)ControllerTransform == (Object)null)) { Movement = ((Component)this).gameObject.AddComponent(); Movement.Initialize(ControllerTransform, _rigidbodyTransform, _navAgent, _charController, _savedAreaMask); Movement.OnNavMeshError += HandleNavMeshError; } } private void HandleNavMeshError() { Fsm.NextStateStateId = StateId.Idle; } private void SetupAnimationController() { _animController = ((Component)this).gameObject.AddComponent(); _animController.Initialize(this, ControllerTransform); if ((Object)(object)Animator != (Object)null) { _avatarAnimController = ((Component)this).gameObject.AddComponent(); _avatarAnimController.Initialize(this, Animator); } Transform val = (((Object)(object)Animator != (Object)null) ? ((Component)Animator).transform : ((Component)this).transform); Transform val2 = DroidHelpers.FindChildByName(val, "code_head_top"); if ((Object)(object)val2 != (Object)null) { _animController.SetupTalking(val2); } SetupEyelidsFromClone(val); } private void SetupEyelidsFromClone(Transform visualsRoot) { try { Transform val = DroidHelpers.FindChildByName(visualsRoot, "EYELIDS LEFT"); Transform val2 = DroidHelpers.FindChildByName(visualsRoot, "EYELIDS RIGHT"); if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null) { LOG.Warning("EYELIDS LEFT/RIGHT not found on cloned visuals"); return; } FindEyelidRotations(val, out Transform upperX, out Transform upperZ, out Transform lowerX); FindEyelidRotations(val2, out Transform upperX2, out Transform upperZ2, out Transform lowerX2); ((Component)val).gameObject.SetActive(false); ((Component)val2).gameObject.SetActive(false); _animController.SetupEyelids(((Component)val).gameObject, ((Component)val2).gameObject, upperX, upperZ, lowerX, upperX2, upperZ2, lowerX2); } catch (Exception ex) { LOG.Error("SetupEyelidsFromClone: Exception - " + ex.Message + "\n" + ex.StackTrace); } } private static void FindEyelidRotations(Transform eyelidsRoot, out Transform? upperX, out Transform? upperZ, out Transform? lowerX) { upperX = null; upperZ = null; lowerX = null; Transform[] componentsInChildren = ((Component)eyelidsRoot).GetComponentsInChildren(true); foreach (Transform val in componentsInChildren) { switch (((Object)val).name) { case "eyelid_upper": upperX = val; break; case "eyelid_upper_rotation": upperZ = val; break; case "eyelid_lower": lowerX = val; break; } } } private void LateUpdate() { _nameplateController.UpdateNameplate(); _animController.UpdateAnimations(); } private void OnDestroy() { if ((Object)(object)Movement != (Object)null) { Movement.OnNavMeshError -= HandleNavMeshError; } } public void PlayMediumFootstep() { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)ControllerTransform == (Object)null)) { Vector3 val = ControllerTransform.position + Vector3.up * 0.1f; Materials.Instance.Impulse(val, Vector3.down, (SoundType)1, true, true, _materialTrigger, (HostType)1); } } private void SetupNameplate() { _nameplateController = ((Component)this).gameObject.AddComponent(); _nameplateController.Initialize(ControllerTransform, SourcePlayer); } private void InitializeFsm() { Fsm = new StateMachineComponent.StateMachine(this, DefaultState); Fsm.AddState(StateId.Idle, new IdleState()); Fsm.AddState(StateId.Wander, new WanderState()); Fsm.AddState(StateId.Sprint, new SprintState()); Fsm.AddState(StateId.CheckMap, new CheckMapState()); Fsm.AddState(StateId.StalkApproach, new StalkApproachState()); Fsm.AddState(StateId.StalkStare, new StalkStareState()); Fsm.AddState(StateId.StalkFlee, new StalkFleeState()); } private void FindCriticalTransforms() { //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Expected O, but got Unknown //IL_0097: Unknown result type (might be due to invalid IL or missing references) ControllerTransform = ((Component)this).transform.Find("Controller"); if ((Object)(object)ControllerTransform == (Object)null) { Transform[] componentsInChildren = ((Component)this).GetComponentsInChildren(); foreach (Transform val in componentsInChildren) { if (((Object)val).name == "Controller") { ControllerTransform = val; break; } } } if ((Object)(object)ControllerTransform == (Object)null) { LOG.Warning("Controller transform not found, creating one"); GameObject val2 = new GameObject("Controller"); val2.transform.SetParent(((Component)this).transform); val2.transform.localPosition = Vector3.zero; ControllerTransform = val2.transform; } _rigidbodyTransform = ((Component)this).transform.Find("Rigidbody"); if ((Object)(object)_rigidbodyTransform == (Object)null) { Transform[] componentsInChildren2 = ((Component)this).GetComponentsInChildren(); foreach (Transform val3 in componentsInChildren2) { if (((Object)val3).name == "Rigidbody") { _rigidbodyTransform = val3; break; } } } if ((Object)(object)_rigidbodyTransform == (Object)null) { LOG.Warning("Rigidbody transform not found"); } } private void SaveNavMeshSettings() { NavMeshAgent val = null; if ((Object)(object)ControllerTransform != (Object)null) { val = ((Component)ControllerTransform).GetComponent(); } if ((Object)(object)val == (Object)null) { val = ((Component)this).GetComponentInChildren(); } if ((Object)(object)val != (Object)null) { _savedAgentTypeID = val.agentTypeID; _savedAreaMask = val.areaMask; } else { _savedAgentTypeID = -334000983; _savedAreaMask = 1; } } private void DisableEnemyComponents() { //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Unknown result type (might be due to invalid IL or missing references) List list = new List(); List list2 = new List(); Component[] componentsInChildren = ((Component)this).GetComponentsInChildren(true); foreach (Component val in componentsInChildren) { if ((Object)(object)val == (Object)null || (Object)(object)val == (Object)(object)this) { continue; } string name = ((object)val).GetType().Name; string text = ((object)val).GetType().FullName ?? ""; if (val is Transform || val is Animator || val is Renderer || val is MeshFilter || val is SkinnedMeshRenderer || val is NavMeshAgent) { continue; } if (text.Contains("Photon") || name.Contains("Photon") || text.Contains("Enemy") || text.Contains("LostDroid") || name.Contains("Enemy") || name.Contains("LostDroid")) { list.Add(val); continue; } MonoBehaviour val2 = (MonoBehaviour)(object)((val is MonoBehaviour) ? val : null); if (val2 != null) { list2.Add(val2); } } for (int j = 0; j < 5; j++) { int num = 0; foreach (Component item in list) { if ((Object)(object)item != (Object)null) { try { Object.DestroyImmediate((Object)(object)item); num++; } catch { } } } if (num == 0) { break; } } foreach (MonoBehaviour item2 in list2) { if ((Object)(object)item2 != (Object)null && (Object)(object)item2 != (Object)(object)this) { ((Behaviour)item2).enabled = false; } } Rigidbody[] componentsInChildren2 = ((Component)this).GetComponentsInChildren(); foreach (Rigidbody val3 in componentsInChildren2) { val3.isKinematic = true; val3.useGravity = false; val3.velocity = Vector3.zero; val3.angularVelocity = Vector3.zero; } Collider[] componentsInChildren3 = ((Component)this).GetComponentsInChildren(); foreach (Collider val4 in componentsInChildren3) { val4.isTrigger = true; } } private void SetupClonedVisuals() { if ((Object)(object)SourcePlayer == (Object)null) { LOG.Error("Cannot clone visuals: source player is null"); return; } Transform val = DroidVisualsClone.FindCube(((Component)this).transform); if ((Object)(object)val == (Object)null) { LOG.Error("Cannot clone visuals: MyDroid/Enable/Cube not found"); return; } DroidVisualsClone.SanitizeCube(val); Animator = ((Component)val).GetComponent(); DroidVisualsClone.StripExistingRig(val); if (!DroidVisualsClone.TryCloneRig(SourcePlayer, val, out GameObject cloneRig)) { LOG.Warning("Failed to clone source player [RIG]"); } else if ((Object)(object)Animator != (Object)null && (Object)(object)cloneRig != (Object)null) { ((Behaviour)Animator).enabled = true; Animator.applyRootMotion = false; Animator.Rebind(); Animator.Update(0f); DroidVisualsClone.AttachRelay(Animator, this, cloneRig); DroidVisualsClone.TryCloneFlashlight(SourcePlayer, cloneRig); DroidVisualsClone.TryCloneMapTool(SourcePlayer, cloneRig, out _mapToolClone); SetupArmAndEyeMimics(cloneRig); } else if ((Object)(object)Animator == (Object)null) { LOG.Warning("Cube has no Animator after SanitizeCube"); } } private void SetupArmAndEyeMimics(GameObject cloneRig) { //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)SourcePlayer == (Object)null || (Object)(object)cloneRig == (Object)null) { return; } PlayerAvatarVisuals playerAvatarVisuals = SourcePlayer.playerAvatarVisuals; if ((Object)(object)playerAvatarVisuals == (Object)null) { LOG.Warning("SetupArmAndEyeMimics: SourcePlayer.playerAvatarVisuals is null"); return; } PlayerAvatarRightArm component = ((Component)playerAvatarVisuals).GetComponent(); if ((Object)(object)component != (Object)null && (Object)(object)component.rightArmTransform != (Object)null) { Transform val = DroidHelpers.FindChildByName(cloneRig.transform, ((Object)component.rightArmTransform).name); if ((Object)(object)val != (Object)null) { _armPoseController = ((Component)this).gameObject.AddComponent(); _armPoseController.Initialize(this, val, component.basePose, component.mapPose, component.poseCurve, component.poseSpeed); LOG.Debug("DroidRightArmPoseController initialized on bone '" + ((Object)component.rightArmTransform).name + "'"); } else { LOG.Warning("SetupArmAndEyeMimics: bone '" + ((Object)component.rightArmTransform).name + "' not found in clone rig"); } } else { LOG.Warning("SetupArmAndEyeMimics: no PlayerAvatarRightArm on source player"); } PlayerAvatarLeftArm component2 = ((Component)playerAvatarVisuals).GetComponent(); if ((Object)(object)component2 != (Object)null && (Object)(object)component2.leftArmTransform != (Object)null) { Transform val2 = DroidHelpers.FindChildByName(cloneRig.transform, ((Object)component2.leftArmTransform).name); if ((Object)(object)val2 != (Object)null) { _leftArmPoseController = ((Component)this).gameObject.AddComponent(); _leftArmPoseController.Initialize(val2, component2.basePose, component2.flashlightPose, component2.poseCurve, component2.poseSpeed); LOG.Debug("DroidLeftArmPoseController initialized on bone '" + ((Object)component2.leftArmTransform).name + "'"); } else { LOG.Warning("SetupArmAndEyeMimics: left arm bone '" + ((Object)component2.leftArmTransform).name + "' not found in clone rig"); } } else { LOG.Warning("SetupArmAndEyeMimics: no PlayerAvatarLeftArm on source player"); } PlayerEyes component3 = ((Component)playerAvatarVisuals).GetComponent(); if ((Object)(object)component3 != (Object)null && (Object)(object)component3.eyeLeft != (Object)null && (Object)(object)component3.eyeRight != (Object)null) { Transform val3 = DroidHelpers.FindChildByName(cloneRig.transform, ((Object)component3.eyeLeft).name); Transform val4 = DroidHelpers.FindChildByName(cloneRig.transform, ((Object)component3.eyeRight).name); Transform val5 = (((Object)(object)_mapToolClone != (Object)null) ? DroidHelpers.FindChildByName(_mapToolClone.transform, "Player Look Target") : null); if ((Object)(object)val3 != (Object)null && (Object)(object)val4 != (Object)null && (Object)(object)val5 != (Object)null) { _eyeLookController = ((Component)this).gameObject.AddComponent(); _eyeLookController.Initialize(this, val3, val4, val5); LOG.Debug("DroidEyeLookAtController initialized"); } else { LOG.Warning("SetupArmAndEyeMimics: eye bones or lookTarget missing " + $"(eyeL={(Object)(object)val3 != (Object)null}, eyeR={(Object)(object)val4 != (Object)null}, lookTarget={(Object)(object)val5 != (Object)null})"); } } else { LOG.Warning("SetupArmAndEyeMimics: no PlayerEyes on source player or eyeLeft/Right null"); } } private void SetupNavigation() { //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01f5: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)ControllerTransform == (Object)null) { LOG.Error("Cannot setup navigation: Controller is null"); return; } _navAgent = ((Component)ControllerTransform).GetComponent(); if ((Object)(object)_navAgent == (Object)null) { _navAgent = ((Component)ControllerTransform).gameObject.AddComponent(); } Vector3 position = ControllerTransform.position; Vector3 val = position; bool flag = false; NavMeshQueryFilter val2 = default(NavMeshQueryFilter); ((NavMeshQueryFilter)(ref val2)).agentTypeID = _savedAgentTypeID; ((NavMeshQueryFilter)(ref val2)).areaMask = _savedAreaMask; NavMeshQueryFilter val3 = val2; float[] array = new float[4] { 5f, 10f, 20f, 50f }; float[] array2 = array; NavMeshHit val4 = default(NavMeshHit); foreach (float num in array2) { if (NavMesh.SamplePosition(position, ref val4, num, val3)) { val = ((NavMeshHit)(ref val4)).position; flag = true; break; } } if (!flag) { LOG.Error($"No NavMesh found near {position}"); return; } ((Behaviour)_navAgent).enabled = false; _navAgent.agentTypeID = _savedAgentTypeID; _navAgent.areaMask = _savedAreaMask; _navAgent.baseOffset = 0f; _navAgent.speed = 2f; _navAgent.angularSpeed = 999f; _navAgent.acceleration = 15f; _navAgent.stoppingDistance = 0f; _navAgent.autoBraking = true; _navAgent.updatePosition = false; _navAgent.updateRotation = false; _navAgent.radius = 0.7f; _navAgent.height = 2f; _navAgent.obstacleAvoidanceType = (ObstacleAvoidanceType)4; _navAgent.avoidancePriority = 10; _navAgent.autoTraverseOffMeshLink = true; _navAgent.autoRepath = true; ControllerTransform.position = val; _navAgent.Warp(val); ((Behaviour)_navAgent).enabled = true; SetupCharacterController(); } private void SetupCharacterController() { //IL_0075: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)ControllerTransform == (Object)null)) { CharacterController component = ((Component)ControllerTransform).GetComponent(); if ((Object)(object)component != (Object)null) { Object.DestroyImmediate((Object)(object)component); } _charController = ((Component)ControllerTransform).gameObject.AddComponent(); _charController.height = 2f; _charController.radius = 0.5f; _charController.center = new Vector3(0f, 1f, 0f); _charController.slopeLimit = 45f; _charController.stepOffset = 0.3f; _charController.skinWidth = 0.08f; _charController.minMoveDistance = 0.001f; } } } public sealed class DroidDebuff : MonoBehaviour { private static readonly VepLogger LOG = VepLogger.Create(); private readonly Dictionary _droids = new Dictionary(); private WhispralDebuffManager _debuffManager; private InvisiblePlayerDebuff _invisiblePlayerDebuff; public bool IsActive { get; private set; } private void Update() { if (IsActive && !((Object)(object)_invisiblePlayerDebuff == (Object)null)) { SyncHallucinations(); } } private void OnDestroy() { DestroyAllHallucinations(); } public void ApplyDebuff(bool active, InvisiblePlayerDebuff sourcePlayerDebuff) { if (!SemiFunc.IsMultiplayer()) { LOG.Debug("Singleplayer mode detected, skipping hallucinations."); return; } IsActive = active; _invisiblePlayerDebuff = sourcePlayerDebuff; _debuffManager = ((Component)this).GetComponent(); if (active) { CreateHallucinations(); } else { DestroyAllHallucinations(); } } public DroidController? GetDroidByPlayerName(string playerName) { foreach (KeyValuePair droid in _droids) { if (Object.op_Implicit((Object)(object)droid.Key) && Object.op_Implicit((Object)(object)droid.Value) && droid.Key.playerName == playerName) { return droid.Value; } } return null; } private void CreateHallucination(PlayerAvatar sourcePlayer) { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) LOG.Debug("Creating hallucination for player " + sourcePlayer.playerName); if (!DroidPrefabLoader.IsAvailable) { LOG.Warning("LostDroid prefab not available - cannot create hallucination"); return; } Vector3? val = FindSpawnPosition(); if (!val.HasValue) { LOG.Warning("Could not find spawn position for hallucination of " + sourcePlayer.playerName); return; } DroidController droidController = DroidController.Create(sourcePlayer, val.Value); if ((Object)(object)droidController == (Object)null) { LOG.Warning("Hallucination for " + sourcePlayer.playerName + " failed to create"); return; } _droids[sourcePlayer] = droidController; LOG.Debug($"Hallucination created at {((Component)droidController).transform.position}"); } private void CreateHallucinations() { if ((Object)(object)_invisiblePlayerDebuff == (Object)null) { return; } LOG.Debug("Creating hallucinations for hidden players."); foreach (PlayerAvatar hiddenPlayer in _invisiblePlayerDebuff.HiddenPlayers) { if (Object.op_Implicit((Object)(object)hiddenPlayer) && !_droids.ContainsKey(hiddenPlayer)) { CreateHallucination(hiddenPlayer); } } } private void DestroyAllHallucinations() { LOG.Debug("Destroying all hallucinations."); foreach (KeyValuePair droid in _droids) { if (Object.op_Implicit((Object)(object)droid.Value)) { Object.Destroy((Object)(object)((Component)droid.Value).gameObject); } } _droids.Clear(); } private void DestroyHallucination(PlayerAvatar? player) { if (!((Object)(object)player == (Object)null) && _droids.TryGetValue(player, out DroidController value)) { LOG.Debug("Destroying hallucination for player " + player.playerName); if (Object.op_Implicit((Object)(object)value)) { Object.Destroy((Object)(object)((Component)value).gameObject); } _droids.Remove(player); } } private Vector3? FindSpawnPosition() { //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_debuffManager != (Object)null) { Vector3? precomputedSpawnPosition = _debuffManager.GetPrecomputedSpawnPosition(); if (precomputedSpawnPosition.HasValue) { LOG.Debug($"Using precomputed spawn position: {precomputedSpawnPosition.Value}"); return precomputedSpawnPosition.Value; } } LOG.Warning("No precomputed position available, falling back to sync search"); Vector3 position = ((Component)PlayerAvatar.instance).transform.position; LevelPoint val = SemiFunc.LevelPointGet(position, 5f, 15f) ?? SemiFunc.LevelPointGet(position, 0f, 999f); if (!Object.op_Implicit((Object)(object)val)) { LOG.Warning("No LevelPoint found for hallucination spawn"); return null; } return ((Component)val).transform.position; } private void SyncHallucinations() { IReadOnlyList hiddenPlayers = _invisiblePlayerDebuff.HiddenPlayers; foreach (PlayerAvatar item in hiddenPlayers) { if (Object.op_Implicit((Object)(object)item) && !_droids.ContainsKey(item)) { CreateHallucination(item); } } List list = new List(); foreach (KeyValuePair droid in _droids) { if (!Object.op_Implicit((Object)(object)droid.Key) || !Object.op_Implicit((Object)(object)droid.Value) || !hiddenPlayers.Contains(droid.Key)) { list.Add(droid.Key); } } foreach (PlayerAvatar item2 in list) { DestroyHallucination(item2); } } } public sealed class DroidEyeLookAtController : MonoBehaviour { private const float ClampX = 50f; private const float ClampY = 30f; private const float ReturnSpeed = 8f; private static readonly VepLogger LOG = VepLogger.Create(); private DroidController _droid; private Transform _eyeLeft; private Quaternion _eyeLeftRest; private Transform _eyeRight; private Quaternion _eyeRightRest; private Transform _lookTarget; private void LateUpdate() { //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_droid == (Object)null) { return; } if (_droid.WantsGrabbing && (Object)(object)_lookTarget != (Object)null) { ApplyLookAt(_eyeLeft); ApplyLookAt(_eyeRight); return; } if ((Object)(object)_eyeLeft != (Object)null) { _eyeLeft.localRotation = Quaternion.Slerp(_eyeLeft.localRotation, _eyeLeftRest, 8f * Time.deltaTime); } if ((Object)(object)_eyeRight != (Object)null) { _eyeRight.localRotation = Quaternion.Slerp(_eyeRight.localRotation, _eyeRightRest, 8f * Time.deltaTime); } } public void Initialize(DroidController droid, Transform eyeLeft, Transform eyeRight, Transform lookTarget) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) _droid = droid; _eyeLeft = eyeLeft; _eyeRight = eyeRight; _lookTarget = lookTarget; if ((Object)(object)eyeLeft != (Object)null) { _eyeLeftRest = eyeLeft.localRotation; } if ((Object)(object)eyeRight != (Object)null) { _eyeRightRest = eyeRight.localRotation; } } private void ApplyLookAt(Transform eye) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)eye == (Object)null)) { Vector3 val = _lookTarget.position - eye.position; if (!(((Vector3)(ref val)).sqrMagnitude < 0.0001f)) { eye.rotation = Quaternion.LookRotation(val); Vector3 localEulerAngles = eye.localEulerAngles; localEulerAngles.y = ClampAngle(localEulerAngles.y, 30f); localEulerAngles.x = ClampAngle(localEulerAngles.x, 50f); eye.localEulerAngles = localEulerAngles; } } } private static float ClampAngle(float angle, float limit) { if (angle > limit && angle < 180f) { return limit; } if (angle < 360f - limit && angle > 180f) { return 360f - limit; } return angle; } } public sealed class DroidFaceAnimationController : MonoBehaviour { private static class AngryExpression { public const float UpperLidAngleLeft = -34f; public const float UpperLidAngleRight = 34f; public const float UpperLidClosed = 83f; public const float LowerLidClosed = -83f; } private const float LookAtAngle = 50f; private const float LookAtMaxDistance = 30f; private const float AngryEyesCooldown = 0.3f; private const float TalkRotationMaxAngle = 25f; private const int SampleDataLength = 256; private const float StalkStareBeforeFlee = 3.030303f; private static readonly VepLogger LOG = VepLogger.Create(); private float _angryTimer; private Transform _controllerTransform; private DroidController _droidController; private GameObject? _eyelidsLeft; private GameObject? _eyelidsRight; private Transform? _headTopTransform; private bool _isAngry; private Transform? _leftLowerEyelidRotationX; private Transform? _leftUpperEyelidRotationX; private Transform? _leftUpperEyelidRotationZ; private Transform? _rightLowerEyelidRotationX; private Transform? _rightUpperEyelidRotationX; private Transform? _rightUpperEyelidRotationZ; private float[]? _sampleData; private AudioSource? _talkingAudioSource; private bool _wasPlayerLooking; public bool IsPlayerLookingAtMe { get; private set; } public void Initialize(DroidController droidController, Transform controllerTransform) { _droidController = droidController; _controllerTransform = droidController.ControllerTransform; } public void SetupEyelids(GameObject? eyelidsLeft, GameObject? eyelidsRight, Transform? leftUpperX, Transform? leftUpperZ, Transform? leftLowerX, Transform? rightUpperX, Transform? rightUpperZ, Transform? rightLowerX) { _eyelidsLeft = eyelidsLeft; _eyelidsRight = eyelidsRight; _leftUpperEyelidRotationX = leftUpperX; _leftUpperEyelidRotationZ = leftUpperZ; _leftLowerEyelidRotationX = leftLowerX; _rightUpperEyelidRotationX = rightUpperX; _rightUpperEyelidRotationZ = rightUpperZ; _rightLowerEyelidRotationX = rightLowerX; } public void SetupTalking(Transform headTopTransform) { _headTopTransform = headTopTransform; } public void UpdateAnimations() { UpdatePlayerLookDetection(); UpdateAngryEyes(); UpdateTalkingAnimation(); } private void UpdateAngryEyes() { //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01f9: Unknown result type (might be due to invalid IL or missing references) //IL_0200: Unknown result type (might be due to invalid IL or missing references) //IL_0224: Unknown result type (might be due to invalid IL or missing references) //IL_0234: Unknown result type (might be due to invalid IL or missing references) //IL_023b: Unknown result type (might be due to invalid IL or missing references) //IL_025f: Unknown result type (might be due to invalid IL or missing references) //IL_026f: Unknown result type (might be due to invalid IL or missing references) //IL_0276: Unknown result type (might be due to invalid IL or missing references) //IL_029b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_eyelidsLeft == (Object)null || (Object)(object)_eyelidsRight == (Object)null || (Object)(object)_leftUpperEyelidRotationX == (Object)null || (Object)(object)_rightUpperEyelidRotationX == (Object)null) { return; } if (IsPlayerLookingAtMe && !_wasPlayerLooking) { _angryTimer = (_droidController.IsStalking ? 3.030303f : 0.3f); } _wasPlayerLooking = IsPlayerLookingAtMe; if (IsPlayerLookingAtMe) { _angryTimer -= Time.deltaTime; if (_angryTimer <= 0f) { _isAngry = false; } } else { _isAngry = true; } if (_isAngry && !_eyelidsLeft.activeSelf) { _eyelidsLeft.SetActive(true); _eyelidsRight.SetActive(true); } float num = (_isAngry ? 83f : 0f); float num2 = (_isAngry ? (-83f) : 0f); float num3 = (_isAngry ? (-34f) : 0f); float num4 = (_isAngry ? 34f : 0f); float num5 = Time.deltaTime * 8f; _leftUpperEyelidRotationX.localRotation = Quaternion.Slerp(_leftUpperEyelidRotationX.localRotation, Quaternion.Euler(num, 0f, 0f), num5); _rightUpperEyelidRotationX.localRotation = Quaternion.Slerp(_rightUpperEyelidRotationX.localRotation, Quaternion.Euler(num, 0f, 0f), num5); if ((Object)(object)_leftUpperEyelidRotationZ != (Object)null) { _leftUpperEyelidRotationZ.localRotation = Quaternion.Slerp(_leftUpperEyelidRotationZ.localRotation, Quaternion.Euler(0f, 0f, num3), num5); } if ((Object)(object)_rightUpperEyelidRotationZ != (Object)null) { _rightUpperEyelidRotationZ.localRotation = Quaternion.Slerp(_rightUpperEyelidRotationZ.localRotation, Quaternion.Euler(0f, 0f, num4), num5); } if ((Object)(object)_leftLowerEyelidRotationX != (Object)null) { _leftLowerEyelidRotationX.localRotation = Quaternion.Slerp(_leftLowerEyelidRotationX.localRotation, Quaternion.Euler(num2, 0f, 0f), num5); } if ((Object)(object)_rightLowerEyelidRotationX != (Object)null) { _rightLowerEyelidRotationX.localRotation = Quaternion.Slerp(_rightLowerEyelidRotationX.localRotation, Quaternion.Euler(num2, 0f, 0f), num5); } if (!_isAngry && _eyelidsLeft.activeSelf) { float num6 = Mathf.Abs(_leftUpperEyelidRotationX.localEulerAngles.x); if ((num6 < 10f || num6 > 350f) ? true : false) { _eyelidsLeft.SetActive(false); _eyelidsRight.SetActive(false); } } } private void UpdatePlayerLookDetection() { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) Camera main = Camera.main; if ((Object)(object)main == (Object)null || (Object)(object)_controllerTransform == (Object)null) { IsPlayerLookingAtMe = false; return; } Vector3 val = _controllerTransform.position + Vector3.up; Vector3 position = ((Component)main).transform.position; float num = Vector3.Distance(position, val); if (num > 30f) { IsPlayerLookingAtMe = false; return; } Vector3 val2 = val - position; Vector3 normalized = ((Vector3)(ref val2)).normalized; float num2 = Vector3.Dot(((Component)main).transform.forward, normalized); float num3 = Mathf.Cos(0.87266463f); IsPlayerLookingAtMe = num2 >= num3; } private void UpdateTalkingAnimation() { //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_headTopTransform == (Object)null) { return; } float num = 0f; if ((Object)(object)_talkingAudioSource == (Object)null && (Object)(object)_controllerTransform != (Object)null) { _talkingAudioSource = ((Component)_controllerTransform).GetComponent(); } if ((Object)(object)_talkingAudioSource != (Object)null && _talkingAudioSource.isPlaying) { if (_sampleData == null) { _sampleData = new float[256]; } _talkingAudioSource.GetOutputData(_sampleData, 0); float num2 = 0f; float[] sampleData = _sampleData; foreach (float num3 in sampleData) { num2 += Mathf.Abs(num3); } num2 /= 256f; if (num2 > 0.01f) { num = Mathf.Lerp(0f, -25f, num2 * 10f); } } else { _talkingAudioSource = null; } _headTopTransform.localRotation = Quaternion.Slerp(_headTopTransform.localRotation, Quaternion.Euler(num, 0f, 0f), Time.deltaTime * 20f); } } public static class DroidHelpers { public static bool IsMovementState(DroidController.StateId state) { if ((uint)(state - 1) <= 1u || (uint)(state - 4) <= 2u) { return true; } return false; } public static Transform? FindChildByName(Transform? root, string name, bool includeInactive = true) { if ((Object)(object)root == (Object)null) { return null; } Transform[] componentsInChildren = ((Component)root).GetComponentsInChildren(includeInactive); foreach (Transform val in componentsInChildren) { if (((Object)val).name == name) { return val; } } return null; } public static void FindChildrenByNames(Transform root, bool includeInactive, params (string name, Action onFound)[] searches) { if ((Object)(object)root == (Object)null) { return; } int num = searches.Length; Transform[] componentsInChildren = ((Component)root).GetComponentsInChildren(includeInactive); foreach (Transform val in componentsInChildren) { for (int j = 0; j < searches.Length; j++) { var (text, action) = searches[j]; if (((Object)val).name == text) { action(val); num--; if (num == 0) { return; } } } } } public static bool TryGetNavMeshPosition(Vector3 position, out Vector3 result, int areaMask, float maxDistance = 5f) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) NavMeshHit val = default(NavMeshHit); if (NavMesh.SamplePosition(position, ref val, maxDistance, areaMask)) { result = ((NavMeshHit)(ref val)).position; return true; } result = position; return false; } public static AnimationClip? GetAnimationClip(Animator animator, string clipName) { if ((Object)(object)animator == (Object)null || (Object)(object)animator.runtimeAnimatorController == (Object)null) { return null; } AnimationClip[] animationClips = animator.runtimeAnimatorController.animationClips; foreach (AnimationClip val in animationClips) { if (((Object)val).name == clipName) { return val; } } return null; } public static bool IsNavAgentValid(NavMeshAgent agent) { if ((Object)(object)agent != (Object)null) { return agent.isOnNavMesh; } return false; } public static Vector3? GetLocalPlayerPosition() { //IL_001f: Unknown result type (might be due to invalid IL or missing references) PlayerAvatar instance = PlayerAvatar.instance; if (!((Object)(object)instance != (Object)null)) { return null; } return ((Component)instance).transform.position; } } public sealed class DroidLeftArmPoseController : MonoBehaviour { private static readonly VepLogger LOG = VepLogger.Create(); private Transform _leftArmTransform; private Vector3 _flashlightPose; private AnimationCurve _poseCurve; private float _poseSpeed; private Vector3 _poseCurrent; private Vector3 _poseOld; private float _poseLerp; private void Update() { //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0089: 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_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_leftArmTransform == (Object)null)) { if (_poseLerp < 1f) { _poseLerp += _poseSpeed * Time.deltaTime; float num = ((_poseCurve != null) ? _poseCurve.Evaluate(_poseLerp) : Mathf.Clamp01(_poseLerp)); _poseCurrent = Vector3.LerpUnclamped(_poseOld, _flashlightPose, num); } else { _poseCurrent = _flashlightPose; } _leftArmTransform.localEulerAngles = _poseCurrent; } } public void Initialize(Transform leftArmTransform, Vector3 basePose, Vector3 flashlightPose, AnimationCurve poseCurve, float poseSpeed) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) _leftArmTransform = leftArmTransform; _flashlightPose = flashlightPose; _poseCurve = poseCurve; _poseSpeed = poseSpeed; _poseOld = basePose; _poseCurrent = basePose; _poseLerp = 0f; } } public sealed class DroidMovementController : MonoBehaviour { private const float RotationSpeed = 10f; private const float VisualYOffset = 0.25f; private const float GroundedStickSpeed = 2f; private const float MaxFallSpeed = 55f; private const float FallAnimDelay = 0.12f; private static readonly VepLogger LOG = VepLogger.Create(); private CharacterController _charController; private Transform _controllerTransform; private Vector3 _currentVelocity; private float _verticalVelocity; private float _airborneTime; private Vector3 _destination; private bool _isPrecomputingDestination; private bool _isPrecomputingForward; private NavMeshAgent _navAgent; private Vector3? _precomputedDestination; private Vector3? _precomputedForwardDestination; private Transform? _rigidbodyTransform; private int _savedAreaMask = -1; public bool HasPrecomputedDestination => _precomputedDestination.HasValue; public bool HasPrecomputedForwardDestination => _precomputedForwardDestination.HasValue; public Quaternion TargetRotation { get; private set; } = Quaternion.identity; public Vector3 CurrentVelocity => _currentVelocity; public bool IsFalling { get { if ((Object)(object)_charController != (Object)null && !_charController.isGrounded && _airborneTime >= 0.12f) { return _verticalVelocity < 0f; } return false; } } public float DebugVerticalVelocity => _verticalVelocity; public bool DebugIsGrounded { get { if ((Object)(object)_charController != (Object)null) { return _charController.isGrounded; } return false; } } public event Action? OnNavMeshError; public float GetDistanceToPlayer() { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) Vector3? localPlayerPosition = DroidHelpers.GetLocalPlayerPosition(); if (!localPlayerPosition.HasValue || (Object)(object)_controllerTransform == (Object)null) { return float.MaxValue; } return Vector3.Distance(_controllerTransform.position, localPlayerPosition.Value); } public bool HasReachedDestination() { //IL_003e: 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_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_navAgent == (Object)null || _navAgent.pathPending) { return false; } Vector3 val = (((Object)(object)_controllerTransform != (Object)null) ? _controllerTransform.position : ((Component)this).transform.position); float num = Vector3.Distance(val, _destination); if (_navAgent.hasPath) { return num <= _navAgent.stoppingDistance; } return true; } public void Initialize(Transform controllerTransform, Transform rigidbodyTransform, NavMeshAgent navAgent, CharacterController charController, int areaMask) { _controllerTransform = controllerTransform; _rigidbodyTransform = rigidbodyTransform; _navAgent = navAgent; _charController = charController; _savedAreaMask = areaMask; } public void LookAtPlayer() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_005d: 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) PlayerAvatar instance = PlayerAvatar.instance; if (!((Object)(object)instance == (Object)null) && !((Object)(object)_controllerTransform == (Object)null)) { Vector3 val = ((Component)instance).transform.position - _controllerTransform.position; Vector3 normalized = ((Vector3)(ref val)).normalized; normalized.y = 0f; if (((Vector3)(ref normalized)).sqrMagnitude > 0.01f) { TargetRotation = Quaternion.LookRotation(normalized); } } } public void ResetPath() { if (DroidHelpers.IsNavAgentValid(_navAgent)) { _navAgent.ResetPath(); } } public void SetSpeed(float speed) { if ((Object)(object)_navAgent != (Object)null) { _navAgent.speed = speed; } } public void StartPrecomputeDestination() { if (!_isPrecomputingDestination && !_precomputedDestination.HasValue) { ((MonoBehaviour)this).StartCoroutine(PrecomputeDestinationCoroutine()); } } public void StartPrecomputeForwardDestination(float minDistance = 5f, float maxDistance = 15f, float maxAngleDeviation = 30f) { if (!_isPrecomputingForward) { _precomputedForwardDestination = null; ((MonoBehaviour)this).StartCoroutine(PrecomputeForwardDestinationCoroutine(minDistance, maxDistance, maxAngleDeviation)); } } public void ClearPrecomputedForwardDestination() { _precomputedForwardDestination = null; } public void SyncNavAgentPosition(bool isMovementState) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_0062: 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_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_navAgent == (Object)null || (Object)(object)_controllerTransform == (Object)null || ((Object)(object)_charController != (Object)null && !_charController.isGrounded)) { return; } Vector3 position = _controllerTransform.position; NavMeshHit val = default(NavMeshHit); if (NavMesh.SamplePosition(position, ref val, 2f, _savedAreaMask)) { _navAgent.nextPosition = ((NavMeshHit)(ref val)).position; if (Vector3.Distance(position, ((NavMeshHit)(ref val)).position) > 0.5f && isMovementState && _navAgent.hasPath) { _navAgent.SetDestination(_destination); } } else { LOG.Warning($"Controller off NavMesh at {position}"); this.OnNavMeshError?.Invoke(); } } public void SyncVisualsToController(Transform? animatorTransform) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_rigidbodyTransform == (Object)null) && !((Object)(object)_controllerTransform == (Object)null)) { Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(0f, 0.25f, 0f); _rigidbodyTransform.position = _controllerTransform.position + val; _rigidbodyTransform.rotation = _controllerTransform.rotation; if ((Object)(object)animatorTransform != (Object)null && animatorTransform.localPosition != Vector3.zero) { animatorTransform.localPosition = Vector3.zero; } } } public bool TrySetDestinationToPlayer() { //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_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Expected O, but got Unknown //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_005d: 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) PlayerAvatar instance = PlayerAvatar.instance; if ((Object)(object)instance == (Object)null || !DroidHelpers.IsNavAgentValid(_navAgent)) { return false; } Vector3 position = ((Component)instance).transform.position; NavMeshHit val = default(NavMeshHit); if (!NavMesh.SamplePosition(position, ref val, 5f, _savedAreaMask)) { return false; } NavMeshPath val2 = new NavMeshPath(); if (!_navAgent.CalculatePath(((NavMeshHit)(ref val)).position, val2) || (int)val2.status != 0) { return false; } _destination = ((NavMeshHit)(ref val)).position; _navAgent.SetPath(val2); return true; } public bool TrySetFleeDestination(float fleeDistance) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_005c: 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_0089: Expected O, but got Unknown //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) PlayerAvatar instance = PlayerAvatar.instance; if ((Object)(object)instance == (Object)null || (Object)(object)_controllerTransform == (Object)null) { return false; } Vector3 val = _controllerTransform.position - ((Component)instance).transform.position; Vector3 normalized = ((Vector3)(ref val)).normalized; Vector3 val2 = _controllerTransform.position + normalized * fleeDistance; NavMeshHit val3 = default(NavMeshHit); if (!NavMesh.SamplePosition(val2, ref val3, 10f, _savedAreaMask)) { return false; } if (!DroidHelpers.IsNavAgentValid(_navAgent)) { return false; } NavMeshPath val4 = new NavMeshPath(); if (!_navAgent.CalculatePath(((NavMeshHit)(ref val3)).position, val4) || (int)val4.status != 0) { return false; } _destination = ((NavMeshHit)(ref val3)).position; _navAgent.SetPath(val4); return true; } public bool TrySetRandomDestination() { //IL_0014: Unknown result type (might be due to invalid IL or missing references) if (_precomputedDestination.HasValue) { return TrySetDestination(_precomputedDestination.Value); } LOG.Warning("No precomputed destination, falling back to sync search"); return TrySetDestinationSync(); } public bool TryExtendCurrentPath() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) if (_precomputedForwardDestination.HasValue) { LOG.Debug($"TryExtendCurrentPath: Using precomputed forward destination at {_precomputedForwardDestination.Value}"); return TrySetForwardDestination(_precomputedForwardDestination.Value); } LOG.Debug("TryExtendCurrentPath: No precomputed forward destination, falling back to sync calculation"); return TryExtendCurrentPathSync(); } private bool TryExtendCurrentPathSync(float minDistance = 5f, float maxDistance = 15f, float maxAngleDeviation = 30f) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_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_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Expected O, but got Unknown //IL_0135: 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_0158: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_controllerTransform == (Object)null || !DroidHelpers.IsNavAgentValid(_navAgent)) { LOG.Debug("TryExtendCurrentPathSync: Invalid controller or NavAgent"); return false; } Vector3 val = ((Vector3)(ref _currentVelocity)).normalized; string arg = "velocity"; if (((Vector3)(ref val)).sqrMagnitude < 0.01f) { Vector3 val2 = _destination - _controllerTransform.position; val = ((Vector3)(ref val2)).normalized; arg = "destination"; } if (((Vector3)(ref val)).sqrMagnitude < 0.01f) { LOG.Debug("TryExtendCurrentPathSync: No valid direction found"); return false; } float num = Random.Range(0f - maxAngleDeviation, maxAngleDeviation); val = Quaternion.Euler(0f, num, 0f) * val; float num2 = Random.Range(minDistance, maxDistance); Vector3 val3 = _controllerTransform.position + val * num2; LOG.Debug($"TryExtendCurrentPathSync: source={arg}, angle={num:F1}°, dist={num2:F1}m"); NavMeshHit val4 = default(NavMeshHit); if (!NavMesh.SamplePosition(val3, ref val4, 10f, _savedAreaMask)) { LOG.Debug($"TryExtendCurrentPathSync: No NavMesh position found near {val3}"); return false; } NavMeshPath val5 = new NavMeshPath(); if (!_navAgent.CalculatePath(((NavMeshHit)(ref val4)).position, val5) || (int)val5.status != 0) { LOG.Debug($"TryExtendCurrentPathSync: Path calculation failed to {((NavMeshHit)(ref val4)).position}"); return false; } LOG.Debug($"TryExtendCurrentPathSync: SUCCESS - new destination at {((NavMeshHit)(ref val4)).position}"); _destination = ((NavMeshHit)(ref val4)).position; _navAgent.SetPath(val5); return true; } private bool TrySetForwardDestination(Vector3 destination) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0031: 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_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) _precomputedForwardDestination = null; if (!DroidHelpers.IsNavAgentValid(_navAgent)) { return false; } NavMeshPath val = new NavMeshPath(); if (!_navAgent.CalculatePath(destination, val) || (int)val.status != 0) { LOG.Debug($"TrySetForwardDestination: Path recalculation failed to {destination}"); return false; } LOG.Debug($"TrySetForwardDestination: SUCCESS - destination set to {destination}"); _destination = destination; _navAgent.SetPath(val); return true; } public void UpdateMovement(bool isMovementState) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_0035: 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_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_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_charController == (Object)null) { return; } Vector3 val = Vector3.zero; if (isMovementState && (Object)(object)_navAgent != (Object)null && _navAgent.hasPath) { _currentVelocity = Vector3.Lerp(_currentVelocity, _navAgent.desiredVelocity, 5f * Time.deltaTime); val = _currentVelocity; val.y = 0f; } else { _currentVelocity = Vector3.zero; } if (_charController.isGrounded) { _verticalVelocity = -2f; _airborneTime = 0f; } else { _verticalVelocity -= Mathf.Abs(Physics.gravity.y) * Time.deltaTime; if (_verticalVelocity < -55f) { _verticalVelocity = -55f; } _airborneTime += Time.deltaTime; } Vector3 val2 = val; val2.y = _verticalVelocity; _charController.Move(val2 * Time.deltaTime); } public void UpdateRotation() { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_controllerTransform == (Object)null) { return; } if (((Vector3)(ref _currentVelocity)).magnitude > 0.1f) { Vector3 normalized = ((Vector3)(ref _currentVelocity)).normalized; normalized.y = 0f; if (((Vector3)(ref normalized)).sqrMagnitude > 0.01f) { TargetRotation = Quaternion.LookRotation(normalized); } } _controllerTransform.rotation = Quaternion.Slerp(_controllerTransform.rotation, TargetRotation, 10f * Time.deltaTime); } private IEnumerator PrecomputeDestinationCoroutine() { _isPrecomputingDestination = true; Vector3 val = (((Object)(object)_controllerTransform != (Object)null) ? _controllerTransform.position : ((Component)this).transform.position); LevelPoint levelPoint = SemiFunc.LevelPointGet(val, 5f, 15f) ?? SemiFunc.LevelPointGet(val, 0f, 20f); if ((Object)(object)levelPoint == (Object)null) { _isPrecomputingDestination = false; yield break; } yield return null; Vector3 position = ((Component)levelPoint).transform.position; NavMeshHit hit = default(NavMeshHit); if (!NavMesh.SamplePosition(position, ref hit, 5f, _savedAreaMask)) { _isPrecomputingDestination = false; yield break; } yield return null; if (!Physics.Raycast(((NavMeshHit)(ref hit)).position + Vector3.up, Vector3.down, 5f, LayerMask.GetMask(new string[1] { "Default" }))) { _isPrecomputingDestination = false; yield break; } NavMeshPath val2 = new NavMeshPath(); if (DroidHelpers.IsNavAgentValid(_navAgent) && _navAgent.CalculatePath(((NavMeshHit)(ref hit)).position, val2) && (int)val2.status == 0) { _precomputedDestination = ((NavMeshHit)(ref hit)).position; } _isPrecomputingDestination = false; } private bool TrySetDestination(Vector3 destination) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown //IL_0027: 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_003b: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) _precomputedDestination = null; if (!DroidHelpers.IsNavAgentValid(_navAgent)) { return false; } NavMeshPath val = new NavMeshPath(); if (!_navAgent.CalculatePath(destination, val) || (int)val.status != 0) { return false; } _destination = destination; _navAgent.SetPath(val); return true; } private bool TrySetDestinationSync() { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0027: 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_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008b: 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_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Expected O, but got Unknown //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) Vector3 val = (((Object)(object)_controllerTransform != (Object)null) ? _controllerTransform.position : ((Component)this).transform.position); LevelPoint val2 = SemiFunc.LevelPointGet(val, 5f, 15f) ?? SemiFunc.LevelPointGet(val, 0f, 20f); if ((Object)(object)val2 == (Object)null) { return false; } Vector3 position = ((Component)val2).transform.position; NavMeshHit val3 = default(NavMeshHit); if (!NavMesh.SamplePosition(position, ref val3, 5f, _savedAreaMask)) { return false; } if (!Physics.Raycast(((NavMeshHit)(ref val3)).position + Vector3.up, Vector3.down, 5f, LayerMask.GetMask(new string[1] { "Default" }))) { return false; } _destination = ((NavMeshHit)(ref val3)).position; NavMeshPath val4 = new NavMeshPath(); if (!_navAgent.CalculatePath(_destination, val4) || (int)val4.status != 0) { return false; } _navAgent.SetPath(val4); return true; } private IEnumerator PrecomputeForwardDestinationCoroutine(float minDistance, float maxDistance, float maxAngleDeviation) { _isPrecomputingForward = true; LOG.Debug("PrecomputeForward: Starting coroutine"); if ((Object)(object)_controllerTransform == (Object)null || !DroidHelpers.IsNavAgentValid(_navAgent)) { LOG.Debug("PrecomputeForward: Invalid controller or NavAgent"); _isPrecomputingForward = false; yield break; } Vector3 direction = ((Vector3)(ref _currentVelocity)).normalized; string directionSource = "velocity"; if (((Vector3)(ref direction)).sqrMagnitude < 0.01f) { Vector3 val = _destination - _controllerTransform.position; direction = ((Vector3)(ref val)).normalized; directionSource = "destination"; } if (((Vector3)(ref direction)).sqrMagnitude < 0.01f) { LOG.Debug("PrecomputeForward: No valid direction found"); _isPrecomputingForward = false; yield break; } yield return null; float num = Random.Range(0f - maxAngleDeviation, maxAngleDeviation); direction = Quaternion.Euler(0f, num, 0f) * direction; float num2 = Random.Range(minDistance, maxDistance); Vector3 position = _controllerTransform.position; Vector3 targetPos = position + direction * num2; LOG.Debug($"PrecomputeForward: source={directionSource}, angle={num:F1}°, dist={num2:F1}m"); yield return null; NavMeshHit hit = default(NavMeshHit); if (!NavMesh.SamplePosition(targetPos, ref hit, 10f, _savedAreaMask)) { LOG.Debug($"PrecomputeForward: No NavMesh position found near {targetPos}"); _isPrecomputingForward = false; yield break; } yield return null; NavMeshPath val2 = new NavMeshPath(); if (!_navAgent.CalculatePath(((NavMeshHit)(ref hit)).position, val2) || (int)val2.status != 0) { LOG.Debug($"PrecomputeForward: Path calculation failed to {((NavMeshHit)(ref hit)).position}"); _isPrecomputingForward = false; } else { _precomputedForwardDestination = ((NavMeshHit)(ref hit)).position; LOG.Debug($"PrecomputeForward: SUCCESS - precomputed destination at {((NavMeshHit)(ref hit)).position}"); _isPrecomputingForward = false; } } } public sealed class DroidNameplate : MonoBehaviour { private const float NameplateHeight = 1.9f; private const float MaxVisibleDistance = 8f; private const float FadeSpeed = 5f; private const float MinFontSize = 8f; private const float MaxFontSize = 20f; private static readonly VepLogger LOG = VepLogger.Create(); private Transform _controllerTransform; private WorldSpaceUIPlayerName? _nameplate; private PlayerAvatar _sourcePlayer; public void Initialize(Transform controllerTransform, PlayerAvatar sourcePlayer) { _controllerTransform = controllerTransform; _sourcePlayer = sourcePlayer; CreateNameplate(); } public void UpdateNameplate() { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: 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_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0064: 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_006a: 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_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: 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_0107: 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_010d: 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_012a: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_nameplate == (Object)null) && !((Object)(object)_controllerTransform == (Object)null) && !((Object)(object)Camera.main == (Object)null)) { Vector3 val = _controllerTransform.position + Vector3.up * 1.9f; Vector3 position = ((Component)Camera.main).transform.position; float num = Vector3.Distance(val, position); Vector3 val2 = val - position; bool flag = !Physics.Raycast(position, ((Vector3)(ref val2)).normalized, num, LayerMask.GetMask(new string[1] { "Default" }), (QueryTriggerInteraction)1); float num2 = Mathf.Clamp01(1f - num / 8f); float num3 = (flag ? num2 : 0f); Color color = ((Graphic)_nameplate.text).color; float num4 = Mathf.Lerp(color.a, num3, Time.deltaTime * 5f); ((Graphic)_nameplate.text).color = new Color(1f, 1f, 1f, num4); Vector3 val3 = SemiFunc.UIWorldToCanvasPosition(val); RectTransform component = ((Component)_nameplate).GetComponent(); if ((Object)(object)component != (Object)null) { component.anchoredPosition = Vector2.op_Implicit(val3); } ((TMP_Text)_nameplate.text).fontSize = Mathf.Clamp(20f - num, 8f, 20f); } } private void CreateNameplate() { if ((Object)(object)_sourcePlayer == (Object)null || (Object)(object)WorldSpaceUIParent.instance == (Object)null) { return; } GameObject playerNamePrefab = WorldSpaceUIParent.instance.playerNamePrefab; if (!((Object)(object)playerNamePrefab == (Object)null)) { GameObject val = Object.Instantiate(playerNamePrefab, ((Component)WorldSpaceUIParent.instance).transform); _nameplate = val.GetComponent(); if ((Object)(object)_nameplate != (Object)null) { _nameplate.playerAvatar = _sourcePlayer; ((TMP_Text)_nameplate.text).text = _sourcePlayer.playerName; } } } private void OnDestroy() { if ((Object)(object)_nameplate != (Object)null) { Object.Destroy((Object)(object)((Component)_nameplate).gameObject); } } } public static class DroidPrefabLoader { private const string BundleFileName = "vepmod_prefabs"; private const string DroidPrefabName = "MyDroid"; private const string EmbeddedBundleResourceName = "VepMod.Resources.vepmod_prefabs"; private static readonly VepLogger LOG = VepLogger.Create("DroidPrefabLoader"); private static AssetBundle? _bundle; public static GameObject? DroidPrefab { get; private set; } public static bool IsAvailable => (Object)(object)DroidPrefab != (Object)null; public static bool IsLoading { get; private set; } public static bool LoadCompleted { get; private set; } public static IEnumerator PreloadAsync(Action? onComplete = null) { if (LoadCompleted || IsLoading) { onComplete?.Invoke(IsAvailable); yield break; } IsLoading = true; LOG.Info("Starting async preload of Droid prefab..."); bool embeddedLoaded = false; using (Stream stream = typeof(DroidPrefabLoader).Assembly.GetManifestResourceStream("VepMod.Resources.vepmod_prefabs")) { if (stream != null) { LOG.Info("Found embedded AssetBundle resource, loading from DLL..."); byte[] array; using (MemoryStream memoryStream = new MemoryStream()) { stream.CopyTo(memoryStream); array = memoryStream.ToArray(); } AssetBundleCreateRequest bundleRequest = AssetBundle.LoadFromMemoryAsync(array); yield return bundleRequest; _bundle = bundleRequest.assetBundle; if ((Object)(object)_bundle != (Object)null) { LOG.Info("AssetBundle loaded successfully from embedded resource"); embeddedLoaded = true; } else { LOG.Warning("Failed to load AssetBundle from embedded resource, falling back to file..."); } } else { LOG.Debug("No embedded AssetBundle found, falling back to file..."); } } if (!embeddedLoaded) { string bundlePath = FindBundlePath(); if (string.IsNullOrEmpty(bundlePath)) { LOG.Warning("VepMod AssetBundle not found - Droid hallucinations disabled"); FinishLoading(success: false, onComplete); yield break; } AssetBundleCreateRequest bundleRequest = AssetBundle.LoadFromFileAsync(bundlePath); yield return bundleRequest; _bundle = bundleRequest.assetBundle; if ((Object)(object)_bundle == (Object)null) { LOG.Error("Failed to load AssetBundle from " + bundlePath); FinishLoading(success: false, onComplete); yield break; } LOG.Info("AssetBundle loaded from file: " + bundlePath); } AssetBundleRequest assetRequest = _bundle.LoadAssetAsync("MyDroid"); yield return assetRequest; if (assetRequest.asset != (Object)null) { Object asset = assetRequest.asset; DroidPrefab = (GameObject?)(object)((asset is GameObject) ? asset : null); LOG.Info("Droid prefab loaded directly from bundle"); FinishLoading(success: true, onComplete); yield break; } string[] allAssetNames = _bundle.GetAllAssetNames(); LOG.Debug($"Bundle contains {allAssetNames.Length} assets"); string[] array2 = allAssetNames; foreach (string bundlePath in array2) { if (bundlePath.ToLower().Contains("MyDroid".ToLower()) && bundlePath.EndsWith(".prefab")) { AssetBundleRequest prefabRequest = _bundle.LoadAssetAsync(bundlePath); yield return prefabRequest; if (prefabRequest.asset != (Object)null) { Object asset2 = prefabRequest.asset; DroidPrefab = (GameObject?)(object)((asset2 is GameObject) ? asset2 : null); LOG.Info("Droid prefab loaded from: " + bundlePath); FinishLoading(success: true, onComplete); yield break; } } } LOG.Error("Failed to load Droid prefab from bundle - all methods exhausted"); FinishLoading(success: false, onComplete); } private static void FinishLoading(bool success, Action? onComplete) { IsLoading = false; LoadCompleted = true; onComplete?.Invoke(success); } private static GameObject? GetPrefabFromContent(EnemyContent content) { Type type = ((object)content).GetType(); PropertyInfo[] properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (PropertyInfo propertyInfo in properties) { if (!(propertyInfo.PropertyType == typeof(GameObject)) && !propertyInfo.PropertyType.IsSubclassOf(typeof(Object))) { continue; } try { object? value = propertyInfo.GetValue(content); GameObject val = (GameObject)((value is GameObject) ? value : null); if (val != null && (Object)(object)val != (Object)null) { return val; } } catch { } } FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fields) { if (!(fieldInfo.FieldType == typeof(GameObject)) && !fieldInfo.FieldType.IsSubclassOf(typeof(Object))) { continue; } try { object? value2 = fieldInfo.GetValue(content); GameObject val2 = (GameObject)((value2 is GameObject) ? value2 : null); if (val2 != null && (Object)(object)val2 != (Object)null) { return val2; } } catch { } } return null; } private static string? FindBundlePath() { string location = Assembly.GetExecutingAssembly().Location; if (!string.IsNullOrEmpty(location)) { string directoryName = Path.GetDirectoryName(location); if (!string.IsNullOrEmpty(directoryName)) { string directoryName2 = Path.GetDirectoryName(directoryName); if (directoryName2 != null && Directory.Exists(directoryName2)) { string[] files = Directory.GetFiles(directoryName2, "vepmod_prefabs", SearchOption.AllDirectories); if (files.Length != 0) { return files[0]; } } string[] files2 = Directory.GetFiles(directoryName, "vepmod_prefabs", SearchOption.AllDirectories); if (files2.Length != 0) { return files2[0]; } } } string path = Path.Combine(Application.dataPath, "..", "BepInEx", "plugins"); if (Directory.Exists(path)) { string[] files3 = Directory.GetFiles(path, "vepmod_prefabs", SearchOption.AllDirectories); if (files3.Length != 0) { return files3[0]; } } string path2 = Path.Combine(Application.dataPath, ".."); if (Directory.Exists(path2)) { string[] files4 = Directory.GetFiles(path2, "vepmod_prefabs", SearchOption.AllDirectories); if (files4.Length != 0) { return files4[0]; } } return null; } public static void Unload() { if ((Object)(object)_bundle != (Object)null) { _bundle.Unload(false); _bundle = null; } DroidPrefab = null; IsLoading = false; LoadCompleted = false; } } public sealed class DroidRightArmPoseController : MonoBehaviour { private static readonly VepLogger LOG = VepLogger.Create(); private Vector3 _basePose; private DroidController _droid; private Vector3 _mapPose; private Vector3 _poseCurrent; private AnimationCurve _poseCurve; private float _poseLerp; private Vector3 _poseNew; private Vector3 _poseOld; private float _poseSpeed; private Transform _rightArmTransform; private void Update() { //IL_0033: 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) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //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_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_droid == (Object)null) && !((Object)(object)_rightArmTransform == (Object)null)) { Vector3 val = (_droid.WantsGrabbing ? _mapPose : _basePose); if (val != _poseNew) { _poseOld = _poseCurrent; _poseNew = val; _poseLerp = 0f; } if (_poseLerp < 1f) { _poseLerp += _poseSpeed * Time.deltaTime; float num = ((_poseCurve != null) ? _poseCurve.Evaluate(_poseLerp) : Mathf.Clamp01(_poseLerp)); _poseCurrent = Vector3.LerpUnclamped(_poseOld, _poseNew, num); } else { _poseCurrent = _poseNew; } _rightArmTransform.localEulerAngles = _poseCurrent; } } public void Initialize(DroidController droid, Transform rightArmTransform, Vector3 basePose, Vector3 mapPose, AnimationCurve poseCurve, float poseSpeed) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_002e: 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_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) _droid = droid; _rightArmTransform = rightArmTransform; _basePose = basePose; _mapPose = mapPose; _poseCurve = poseCurve; _poseSpeed = poseSpeed; _poseCurrent = basePose; _poseNew = basePose; _poseOld = basePose; _poseLerp = 1f; } } public class EnemyWhispral : StateMachineComponent { public enum State { Spawn, Idle, Roam, Investigate, NoticePlayer, GoToPlayer, PrepareAttach, Attached, Detach, DetachWait, Leave, Stun, StunEnd, Despawn } private abstract class WhispralStateBase : StateMachineBase.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); } } protected void CleanupAttachmentIfNeeded(State previous) { if ((uint)(previous - 6) > 1u) { return; } PlayerAvatar playerTarget = Whispral.playerTarget; if ((Object)(object)playerTarget == (Object)null) { return; } LOG.Debug($"Whispral interrupted while attached (-> {Fsm.CurrentStateStateId}), cleaning up debuffs."); if (SemiFunc.IsMultiplayer()) { Whispral.photonView.RPC("WhispralAttachmentRPC", (RpcTarget)0, new object[2] { playerTarget.photonView.ViewID, false }); } else { WhispralDebuffManager component = ((Component)playerTarget).GetComponent(); if (Object.op_Implicit((Object)(object)component)) { component.UnregisterAttachment(); } } Whispral.attachAnchor = null; } } 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 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(); } public override void OnStateUpdate() { if (!SemiFunc.EnemySpawnIdlePause()) { _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_0047: 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_0083: Unknown result type (might be due to invalid IL or missing references) base.OnStateEnter(previous); _timer = 5f; _hasDestination = false; LevelPoint val = SemiFunc.LevelPointGet(((Component)base.Whispral).transform.position, 10f, 25f) ?? SemiFunc.LevelPointGet(((Component)base.Whispral).transform.position, 0f, 999f); if (Object.op_Implicit((Object)(object)val) && SamplePosition(val, out var hit) && Raycast(hit)) { base.Enemy.NavMeshAgent.SetDestination(((NavMeshHit)(ref hit)).position); base.Enemy.Rigidbody.notMovingTimer = 0f; _hasDestination = true; } } 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 const float PrecomputeInterval = 0.5f; private const int MaxPrecomputedPositions = 4; private bool _agentSet; private int _precomputedCount; private float _precomputeTimer; private float _timer; public override void OnStateEnter(State previous) { base.OnStateEnter(previous); _timer = 2f; _agentSet = true; _precomputeTimer = 0f; _precomputedCount = 0; PrecomputeSpawnPosition(); } public void RefreshTimer() { _timer = 2f; } public override void OnStateUpdate() { //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_019a: 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; } _precomputeTimer -= Time.deltaTime; if (_precomputeTimer <= 0f && _precomputedCount < 4) { PrecomputeSpawnPosition(); _precomputeTimer = 0.5f; } 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 void PrecomputeSpawnPosition() { PlayerAvatar playerTarget = base.Whispral.playerTarget; if (!((Object)(object)playerTarget == (Object)null)) { _precomputedCount++; if (SemiFunc.IsMultiplayer()) { base.Whispral.photonView.RPC("PrecomputeSpawnPositionRPC", (RpcTarget)0, new object[1] { playerTarget.photonView.ViewID }); } else { ((Component)playerTarget).GetComponent()?.PrecomputeSpawnPosition(); } } } } 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 const float VoiceFilterProbability = 0.5f; 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; base.Whispral.attachAnchor = (Object.op_Implicit((Object)(object)playerTarget) ? SemiFunc.PlayerGetFaceEyeTransform(playerTarget) : null); StartAttachEffects(); } 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 playerTarget = base.Whispral.playerTarget; if ((Object)(object)playerTarget == (Object)null) { return; } WhispralMimics localMimics = VepFinder.LocalMimics; if (!Object.op_Implicit((Object)(object)localMimics)) { LOG.Warning("LocalMimics not found, cannot send voice command."); return; } int viewID = playerTarget.photonView.ViewID; string text = ChooseRandomSourcePlayer(playerTarget); if (text == null) { LOG.Warning("No source player available for voice command."); return; } bool flag = VepMod.ConfigVoiceFilterEnabled.Value && Random.value < 0.5f; LOG.Debug($"Sending voice command: target={playerTarget.photonView.Owner.NickName}, source={text}, filter={flag}"); localMimics.SendPlayVoiceCommand(viewID, text, flag); } private static string? ChooseRandomSourcePlayer(PlayerAvatar targetPlayer) { Player owner = targetPlayer.photonView.Owner; string targetNickName = ((owner != null) ? owner.NickName : null); List list = PhotonNetwork.PlayerList.Where((Player p) => !string.IsNullOrEmpty(p.NickName) && p.NickName != targetNickName).ToList(); if (list.Count == 0) { return null; } return list[Random.Range(0, list.Count)].NickName; } private void StartAttachEffects() { PlayerAvatar playerTarget = base.Whispral.playerTarget; if (!((Object)(object)playerTarget == (Object)null)) { LOG.Debug("Whispral attached to player, sending debuff RPC."); if (SemiFunc.IsMultiplayer()) { base.Whispral.photonView.RPC("WhispralAttachmentRPC", (RpcTarget)0, new object[2] { playerTarget.photonView.ViewID, true }); } else { WhispralDebuffManager orAddComponent = ComponentHolderProtocol.GetOrAddComponent((Object)(object)playerTarget); orAddComponent.RegisterAttachment(); } } } 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) { 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(); StopAttachEffects(); } public override void OnStateUpdate() { _timer -= Time.deltaTime; if (_timer <= 0f) { base.Whispral.attachAnchor = null; base.Fsm.NextStateStateId = State.DetachWait; } } private void StopAttachEffects() { PlayerAvatar playerTarget = base.Whispral.playerTarget; if ((Object)(object)playerTarget == (Object)null) { return; } LOG.Debug("Whispral detached from player, sending debuff RPC."); if (SemiFunc.IsMultiplayer()) { base.Whispral.photonView.RPC("WhispralAttachmentRPC", (RpcTarget)0, new object[2] { playerTarget.photonView.ViewID, false }); return; } WhispralDebuffManager component = ((Component)playerTarget).GetComponent(); if (Object.op_Implicit((Object)(object)component)) { component.UnregisterAttachment(); } } } 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_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0090: 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_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: 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) ?? 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); if (_hasDestination) { base.Enemy.EnemyParent.SpawnedTimerSet(1f); } } 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); CleanupAttachmentIfNeeded(previous); } 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); CleanupAttachmentIfNeeded(previous); base.Enemy.EnemyParent.Despawn(); base.Fsm.NextStateStateId = State.Spawn; } } private static readonly VepLogger LOG = VepLogger.Create(); [Header("Core refs")] public Enemy enemy; public EnemyWhispralAnim enemyWhispralAnim; [Header("Attach settings")] [Tooltip("Temps pendant lequel l’ennemi reste collé au joueur.")] public float attachedDuration = 200f; public EnemyWhispralAnim enemyWhispralAnima; [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 grabAggroTimer; 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(); 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(); CheckForStunState(); CheckForDespawnState(); RotationLogic(); base.Update(); } } private void FixedUpdate() { if (SemiFunc.IsMasterClientOrSingleplayer()) { AttachFollowLogic(); } } 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 val = Quaternion.LookRotation(((Component)playerTarget).transform.position - ((Component)this).transform.position); ((Quaternion)(ref val)).eulerAngles = new Vector3(0f, ((Quaternion)(ref val)).eulerAngles.y, 0f); rotationTarget = val; } } else { Vector3 normalized = ((Vector3)(ref enemy.NavMeshAgent.AgentVelocity)).normalized; if (((Vector3)(ref normalized)).magnitude > 0.1f) { Quaternion val2 = Quaternion.LookRotation(((Vector3)(ref enemy.NavMeshAgent.AgentVelocity)).normalized); ((Quaternion)(ref val2)).eulerAngles = new Vector3(0f, ((Quaternion)(ref val2)).eulerAngles.y, 0f); rotationTarget = val2; } } ((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) && !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 WhispralAttachmentRPC(int targetViewID, bool attach, 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 = null; foreach (PlayerAvatar player in GameDirector.instance.PlayerList) { if (Object.op_Implicit((Object)(object)player) && Object.op_Implicit((Object)(object)player.photonView) && player.photonView.ViewID == targetViewID) { val = player; break; } } if ((Object)(object)val == (Object)null) { LOG.Warning($"WhispralAttachmentRPC: Player with ViewID {targetViewID} not found."); return; } LOG.Debug($"WhispralAttachmentRPC received: attach={attach} for player {val.playerName}"); WhispralDebuffManager orAddComponent = ComponentHolderProtocol.GetOrAddComponent((Object)(object)val); if (attach) { orAddComponent.RegisterAttachment(); } else { orAddComponent.UnregisterAttachment(); } } [PunRPC] private void PrecomputeSpawnPositionRPC(int targetViewID, 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 = null; foreach (PlayerAvatar player in GameDirector.instance.PlayerList) { if (Object.op_Implicit((Object)(object)player) && Object.op_Implicit((Object)(object)player.photonView) && player.photonView.ViewID == targetViewID) { val = player; break; } } if (!((Object)(object)val == (Object)null)) { ((Component)val).GetComponent()?.PrecomputeSpawnPosition(); } } public void OnSpawn() { if (SemiFunc.IsMasterClientOrSingleplayer() && SemiFunc.EnemySpawn(enemy)) { Fsm.NextStateStateId = State.Spawn; } } public void OnHurt() { enemyWhispralAnim.Hurt(); } public void OnDeath() { enemyWhispralAnim.Death(); if (SemiFunc.IsMasterClientOrSingleplayer()) { enemy.EnemyParent.Despawn(); } } 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(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; } } private void ForceDetach() { State currentState = CurrentState; if ((uint)(currentState - 6) <= 1u) { Fsm.NextStateStateId = State.Detach; } } } public class EnemyWhispralAnim : StateMachineComponent { public enum State { NoBreathing, BreatheIn, BreatheOut } private sealed class NoBreathing : StateMachineBase.StateBase { public NoBreathing(EnemyWhispralAnim owner) { } } private sealed class BreathingState(EnemyWhispralAnim owner, Sound sound, Vector2 durationRange, State nextState) : StateMachineBase.StateBaseTransition(P.x, nextState) { private const float MinDuration = 3f; private readonly State _nextState = nextState; private AudioSource? _audioSource; public override void OnStateEnter(State previous) { //IL_0053: Unknown result type (might be due to invalid IL or missing references) base.OnStateEnter(previous); owner.Show(show: false); Duration = GetDuration(); if ((Object)(object)owner.enemyWhispral.playerTarget != (Object)null) { _audioSource = sound.Play(((Component)owner.enemyWhispral.playerTarget).transform.position, 1f, 1f, 1f, 1f); } } private float GetDuration() { float num = Mathf.Max(durationRange.x, 3f); if (durationRange.x < 3f) { LOG.Warning($"Adjusted min duration from {durationRange.x} to {3f} (minimum allowed)."); } float num2 = Mathf.Max(durationRange.y, num); if (durationRange.y < num) { LOG.Warning($"Adjusted max duration from {durationRange.y} to {num} (must be >= min)."); } return Random.Range(num, num2); } public override void OnStateExit(State next) { base.OnStateExit(next); if (Object.op_Implicit((Object)(object)_audioSource)) { _audioSource.Stop(); } if (next != nextState) { owner.Show(show: true); } } } private static readonly VepLogger LOG = VepLogger.Create(); [Space] [SerializeField] private Enemy enemy; [SerializeField] private EnemyWhispral enemyWhispral; [Space] [SerializeField] private Sound soundHurt; [SerializeField] private Sound soundDeath; [Space] [SerializeField] private Sound soundBreatheIn; [SerializeField] private Sound soundBreatheOut; [SerializeField] private Vector2 breathingDurationInRange; [SerializeField] private Vector2 breathingDurationOutRange; [Space] [SerializeField] private GameObject visuals; [SerializeField] private GameObject rigidBody; protected override State DefaultState => State.NoBreathing; protected override void Awake() { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) base.Awake(); Fsm.AddState(State.NoBreathing, new NoBreathing(this)); Fsm.AddState(State.BreatheIn, new BreathingState(this, soundBreatheIn, breathingDurationInRange, State.BreatheOut)); Fsm.AddState(State.BreatheOut, new BreathingState(this, soundBreatheOut, breathingDurationOutRange, State.BreatheIn)); ConfigBreathingSound(soundBreatheIn); ConfigBreathingSound(soundBreatheOut); } protected override void Update() { if (enemyWhispral.CurrentState == EnemyWhispral.State.Attached && !enemy.Jump.jumping) { State currentStateStateId = Fsm.CurrentStateStateId; if (currentStateStateId != State.BreatheIn && currentStateStateId != State.BreatheOut) { Fsm.NextStateStateId = State.BreatheIn; } } else { Fsm.NextStateStateId = State.NoBreathing; } base.Update(); } public void Death() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) StopBreathing(); soundDeath.Play(((Component)enemy).transform.position, 1f, 1f, 1f, 1f); } public void Hurt() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) StopBreathing(); soundHurt.Play(((Component)enemy).transform.position, 1f, 1f, 1f, 1f); } public void Show(bool show) { visuals.gameObject.SetActive(show); rigidBody.gameObject.SetActive(show); } public void StopBreathing() { Fsm.NextStateStateId = State.NoBreathing; } private static void ConfigBreathingSound(Sound soundBreathe) { soundBreathe.Volume = 0.5f; soundBreathe.VolumeRandom = 0f; soundBreathe.Pitch = 0.8f; soundBreathe.PitchRandom = 0f; soundBreathe.SpatialBlend = 1f; soundBreathe.Doppler = 1f; soundBreathe.ReverbMix = 1f; soundBreathe.FalloffMultiplier = 1f; soundBreathe.OffscreenVolume = 1f; soundBreathe.OffscreenFalloff = 1f; } } public sealed class InvisiblePlayerDebuff : MonoBehaviour { private static readonly VepLogger LOG = VepLogger.Create(); private static readonly HashSet GlobalHiddenPlayers = new HashSet(); private readonly List _hiddenPlayers = new List(); private readonly Dictionary _mapToolCache = new Dictionary(); public bool IsActive { get; private set; } public IReadOnlyList HiddenPlayers => _hiddenPlayers; private void LateUpdate() { LateCheckDeactivateVisuals(); } private void OnDestroy() { if (!IsActive || _hiddenPlayers.Count == 0) { return; } LOG.Debug("InvisiblePlayerDebuff destroyed while active, restoring visibility."); foreach (PlayerAvatar hiddenPlayer in _hiddenPlayers) { if (Object.op_Implicit((Object)(object)hiddenPlayer)) { GlobalHiddenPlayers.Remove(hiddenPlayer); SetPlayerVisibility(hiddenPlayer, visible: true); } } _hiddenPlayers.Clear(); _mapToolCache.Clear(); IsActive = false; } public void ApplyDebuff(bool invisible) { IsActive = invisible; if (!SemiFunc.IsMultiplayer()) { LOG.Debug("Singleplayer mode detected, skipping invisibility application."); return; } LOG.Debug($"Applying invisibility debuff: {invisible}"); List playerList = GameDirector.instance.PlayerList; foreach (PlayerAvatar item in playerList) { if (CheckNull(item)) { continue; } if (item.photonView.IsMine) { LOG.Debug("Skipping local player " + item.photonView.Owner.NickName + "."); continue; } LOG.Debug($"Setting invisibility for Player {item.photonView.Owner.NickName} to {invisible}"); SetPlayerVisibility(item, !invisible); if (invisible) { _hiddenPlayers.Add(item); GlobalHiddenPlayers.Add(item); } else { _hiddenPlayers.Remove(item); GlobalHiddenPlayers.Remove(item); } } } public static bool IsPlayerHidden(PlayerAvatar player) { if ((Object)(object)player != (Object)null) { return GlobalHiddenPlayers.Contains(player); } return false; } public static bool IsPositionNearHiddenPlayer(Vector3 position, float radius = 2f) { //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_002b: Unknown result type (might be due to invalid IL or missing references) foreach (PlayerAvatar globalHiddenPlayer in GlobalHiddenPlayers) { if (!((Object)(object)globalHiddenPlayer == (Object)null)) { Vector3 position2 = ((Component)globalHiddenPlayer).transform.position; if (Vector3.Distance(position, position2) <= radius) { return true; } } } return false; } private static bool CheckNull(PlayerAvatar player) { if (!Object.op_Implicit((Object)(object)player)) { LOG.Warning("Encountered null PlayerAvatar reference, skipping."); return true; } if (!Object.op_Implicit((Object)(object)player.photonView) || player.photonView.Owner == null) { LOG.Warning($"PlayerAvatar {player} has null photonView or Owner, skipping."); return true; } return false; } private void LateCheckDeactivateVisuals() { if (!IsActive || _hiddenPlayers.Count == 0) { return; } foreach (PlayerAvatar hiddenPlayer in _hiddenPlayers) { if (!Object.op_Implicit((Object)(object)hiddenPlayer)) { continue; } if (Object.op_Implicit((Object)(object)hiddenPlayer.flashlightController)) { FlashlightController flashlightController = hiddenPlayer.flashlightController; bool flag = Object.op_Implicit((Object)(object)flashlightController.mesh) && ((Renderer)flashlightController.mesh).enabled; bool flag2 = Object.op_Implicit((Object)(object)flashlightController.spotlight) && ((Behaviour)flashlightController.spotlight).enabled; bool flag3 = Object.op_Implicit((Object)(object)flashlightController.halo) && flashlightController.halo.enabled; if (flag || flag2 || flag3) { ToggleFlashlight(hiddenPlayer, visible: false); LOG.Debug("Re-deactivated flashlight for Player " + hiddenPlayer.photonView.Owner.NickName + " in LateUpdate."); } } MapToolController mapToolController = GetMapToolController(hiddenPlayer); if ((Object)(object)mapToolController != (Object)null && Object.op_Implicit((Object)(object)mapToolController.VisualTransform) && ((Component)mapToolController.VisualTransform).gameObject.activeSelf) { ((Component)mapToolController.VisualTransform).gameObject.SetActive(false); LOG.Debug("Re-deactivated Map Tool VisualTransform for Player " + hiddenPlayer.photonView.Owner.NickName + " in LateUpdate."); } } } private void SetPlayerVisibility(PlayerAvatar player, bool visible) { ToggleMesh(player, visible); ToggleNameplate(player, visible); ToggleFlashlight(player, visible); ToggleVoiceCom(player, visible); ToggleMapTool(player, visible); } private static void ToggleFlashlight(PlayerAvatar player, bool visible) { LOG.Debug($"Set flashlight visibility for Player {player.photonView.Owner.NickName} to {visible}"); if (Object.op_Implicit((Object)(object)player.flashlightController)) { ((Behaviour)player.flashlightController.spotlight).enabled = visible; ((Renderer)player.flashlightController.mesh).enabled = visible; if (Object.op_Implicit((Object)(object)player.flashlightController.halo)) { player.flashlightController.halo.enabled = visible; } } } private static void ToggleMesh(PlayerAvatar player, bool visible) { LOG.Debug($"Set mesh visibility for Player {player.photonView.Owner.NickName} to {visible}"); if (Object.op_Implicit((Object)(object)(Object.op_Implicit((Object)(object)player.playerAvatarVisuals) ? player.playerAvatarVisuals.meshParent : null))) { player.playerAvatarVisuals.meshParent.SetActive(visible); } } private static void ToggleNameplate(PlayerAvatar player, bool visible) { LOG.Debug($"Set nameplate visibility for Player {player.photonView.Owner.NickName} to {visible}"); if (Object.op_Implicit((Object)(object)player.worldSpaceUIPlayerName)) { ((Component)player.worldSpaceUIPlayerName).gameObject.SetActive(visible); } } private static void ToggleVoiceCom(PlayerAvatar player, bool visible) { LOG.Debug($"Set voice chat mute for Player {player.photonView.Owner.NickName} to {visible}"); if (Object.op_Implicit((Object)(object)(Object.op_Implicit((Object)(object)player.voiceChat) ? player.voiceChat.audioSource : null))) { player.voiceChat.audioSource.mute = !visible; } } private void ToggleMapTool(PlayerAvatar player, bool visible) { MapToolController mapToolController = GetMapToolController(player); if (!((Object)(object)mapToolController == (Object)null)) { LOG.Debug($"Set Map Tool visibility for Player {player.photonView.Owner.NickName} to {visible}"); if (Object.op_Implicit((Object)(object)mapToolController.VisualTransform)) { ((Component)mapToolController.VisualTransform).gameObject.SetActive(visible); } } } private MapToolController? GetMapToolController(PlayerAvatar player) { if (_mapToolCache.TryGetValue(player, out MapToolController value)) { return value; } MapToolController[] array = Object.FindObjectsOfType(true); MapToolController[] array2 = array; foreach (MapToolController val in array2) { if ((Object)(object)val.PlayerAvatar == (Object)(object)player) { _mapToolCache[player] = val; LOG.Debug("Cached MapToolController for Player " + player.photonView.Owner.NickName); return val; } } LOG.Warning("MapToolController not found for Player " + player.photonView.Owner.NickName); return null; } } internal class LostDroid : MonoBehaviour { public enum State { Spawn, Idle, Wander, RWander, RSwing, Stun, Notice, Follow, Transform, RAttack, RShortAttack, Despawn } public Renderer[] renderers; public Transform _bulletPosition; public Transform feetTransform; public GameObject bulletPrefab; [Header("Sounds")] public Sound soundHit; public Sound genericLines; public Sound SadLines; public Sound EnvyLines; public Sound HateLines; public Sound CuteLines; public Sound MurderLines; public Sound RageLines; public AnimationCurve shootLineWidthCurve; public ParticleSystem minigunParticles; public bool Terminator; public bool Transformed; [Header("State")] [SerializeField] public State CurrentState; [SerializeField] public float stateTimer; [SerializeField] public float stateHaltTimer; [Header("Animation")] [SerializeField] private AnimationCurve hurtCurve; [SerializeField] private SkinnedMeshRenderer[] _skinnedMeshRenderer; [SerializeField] private MeshRenderer[] _MeshRenderer; [Header("Rotation and LookAt")] public SpringQuaternion horizontalRotationSpring; public LostDroidAnimationController LostDroidAnim; private readonly List _hurtMaterial = new List(); private readonly Color[] colors = (Color[])(object)new Color[5]; private Vector3 _agentDestination; internal float _animSpeed = 1f; private float _attackCooldown; internal bool _attackImpulse; internal bool _attackShortImpulse; private float _avoidDist; private float _bulletFireCooldown; private float _bulletSpread; internal int _damageAmount; internal bool _deathImpulse; internal bool _despawnImpulse; internal Enemy _enemy; internal bool _fireBullets; internal bool _firstStun; internal bool _hasSpawned; private Quaternion _horizontalRotationTarget = Quaternion.identity; private int _hurtAmount; private bool _hurtImpulse; internal bool _isSprinting; internal bool _isStun; internal bool _isTurning; internal bool _isTurningToPlayer; internal bool _isWalking; private float _overrideAgentLerp; private PhotonView _photonView; private bool _stateImpulse; internal bool _swingImpulse; private bool _talker; private float _talkTimer; private PlayerAvatar _targetPlayer; private Vector3 _targetPosition; internal float _transformCount; internal float _transformCountMax; internal bool _transformImpulse; private Vector3 _turnPosition; private int droidVariant; private float hurtLerp; private EnemyNavMeshAgent _navMeshAgent => _enemy.NavMeshAgent; private EnemyRigidbody _rigidbody => _enemy.Rigidbody; private EnemyParent _enemyParent => _enemy.EnemyParent; private EnemyVision _Vision => _enemy.Vision; public Enemy Enemy => _enemy; private void Awake() { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0068: 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_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) _enemy = ((Component)this).GetComponent(); _photonView = ((Component)this).GetComponent(); _hurtAmount = Shader.PropertyToID("_ColorOverlayAmount"); colors[0] = new Color(1f, 0.1764706f, 0.1764706f, 0f); colors[1] = new Color(0.4117647f, 7f / 15f, 1f, 0f); colors[2] = new Color(1f, 0.7607843f, 0f, 0f); colors[3] = new Color(0.95686275f, 0.08627451f, 40f / 51f, 0f); colors[4] = new Color(1f, 1f, 1f, 0f); if (Terminator) { _transformCount = 5f; _transformCountMax = Random.Range(5f, 10f); _bulletSpread = 10f; } else { _transformCount = 8f; _transformCountMax = Random.Range(6f, 12f); _bulletSpread = 20f; } _talker = (double)Random.value < 0.5; _talkTimer = Random.Range(5f, 28f); _avoidDist = Random.Range(2f, 4f); SkinnedMeshRenderer[] skinnedMeshRenderer = _skinnedMeshRenderer; foreach (SkinnedMeshRenderer val in skinnedMeshRenderer) { if ((Object)(object)val != (Object)null) { _hurtMaterial.AddRange(((Renderer)val).materials); } } MeshRenderer[] meshRenderer = _MeshRenderer; foreach (MeshRenderer val2 in meshRenderer) { if ((Object)(object)val2 != (Object)null) { _hurtMaterial.AddRange(((Renderer)val2).materials); } } hurtCurve = AssetManager.instance.animationCurveImpact; } private void Update() { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Invalid comparison between Unknown and I4 if (!SemiFunc.IsMasterClientOrSingleplayer() || !LevelGenerator.Instance.Generated) { return; } if (!_enemy.IsStunned()) { if ((int)_enemy.EnemyParent.Enemy.CurrentState == 11 && CurrentState != State.Despawn) { UpdateState(State.Despawn); } switch (CurrentState) { case State.Spawn: StateSpawn(); break; case State.Idle: StateIdle(); break; case State.Wander: StateWander(); break; case State.RWander: StateWander(); break; case State.RSwing: StateRSwing(); break; case State.Stun: StateStun(); break; case State.Notice: StateNotice(); break; case State.Follow: StateFollow(); break; case State.Transform: StateTransform(); break; case State.RAttack: StateRAttack(); break; case State.RShortAttack: StateRShortAttack(); break; case State.Despawn: StateDespawn(); break; default: throw new ArgumentOutOfRangeException(); } RotationLogic(); } else { UpdateState(State.Stun); StateStun(); } HurtEffect(); if (_transformCount < _transformCountMax) { _transformCount += Time.deltaTime * 0.25f; } if (_attackCooldown > 0f) { _attackCooldown -= Time.deltaTime; } if (_talkTimer > 0f) { _talkTimer -= Time.deltaTime; return; } Talk(); if (SemiFunc.IsMasterClientOrSingleplayer()) { _talkTimer = Random.Range(5f, 28f); } } public void FireBullets() { if (_fireBullets) { if (_bulletFireCooldown <= 0f) { _bulletFireCooldown = 0.02f; FireBulletRPC(); } _bulletFireCooldown -= Time.deltaTime; } } public bool isPlayerNear(Transform baseTransform) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) using List.Enumerator enumerator = GameDirector.instance.PlayerList.GetEnumerator(); if (enumerator.MoveNext()) { PlayerAvatar current = enumerator.Current; return !current.spectating && Vector3.Distance(((Component)current).transform.position, baseTransform.position) < 32f; } return false; } public void OnDeath() { _deathImpulse = true; _enemy.Stunned = false; LostDroidAnim.PlayDeathParticles(); if (SemiFunc.IsMasterClientOrSingleplayer()) { _enemy.EnemyParent.Despawn(); } } public void OnDestroyerVision() { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) if (CurrentState != State.RWander) { return; } _targetPlayer = _enemy.StateInvestigate.Player.playerAvatarScript; if (!_targetPlayer.isCrawling && !_targetPlayer.isCrouching) { if (Vector3.Distance(((Component)_targetPlayer).transform.position, ((Component)this).transform.position) < 2f) { UpdateState(State.RSwing); } else { UpdateState(State.RShortAttack); } if (GameManager.Multiplayer()) { _photonView.RPC("TargetPlayerRPC", (RpcTarget)0, new object[1] { _targetPlayer.photonView.ViewID }); } } } public void OnGrab() { _targetPlayer = _enemy.Vision.onVisionTriggeredPlayer; if (CurrentState == State.Idle || CurrentState == State.Wander) { if (GameManager.Multiplayer() && (Object)(object)_targetPlayer != (Object)null) { _photonView.RPC("TargetPlayerRPC", (RpcTarget)0, new object[1] { _targetPlayer.photonView.ViewID }); } if (!((Object)(object)_targetPlayer == (Object)null)) { UpdateState(State.Notice); } } else if (CurrentState == State.RWander) { if (GameManager.Multiplayer() && (Object)(object)_targetPlayer != (Object)null) { _photonView.RPC("TargetPlayerRPC", (RpcTarget)0, new object[1] { _targetPlayer.photonView.ViewID }); } UpdateState(State.RSwing); } } public void OnHurt() { if (!Transformed && isPlayerNear(((Component)this).transform)) { if (_damageAmount < 2) { _damageAmount++; } else { UpdateState(State.Transform); } } } public void OnSpawn() { if (SemiFunc.IsMasterClientOrSingleplayer() && SemiFunc.EnemySpawn(_enemy)) { UpdateState(State.Spawn); } _damageAmount = 0; _talker = (double)Random.value < 0.5; _talkTimer = Random.Range(5f, 28f); _avoidDist = Random.Range(2f, 4f); if (GameManager.Multiplayer()) { _photonView.RPC("IsStunnedRPC", (RpcTarget)0, new object[1] { false }); } else { IsStunnedRPC(value: false); } if (!Terminator) { int num = Random.Range(0, colors.Length); if (GameManager.Multiplayer() && SemiFunc.IsMasterClientOrSingleplayer()) { _photonView.RPC("PickRandomVariantRPC", (RpcTarget)0, new object[1] { num }); } else { PickRandomVariantRPC(num); } } } public void OnVision() { //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) if (!Transformed) { if (CurrentState == State.Wander || CurrentState == State.Idle) { _targetPlayer = _enemy.Vision.onVisionTriggeredPlayer; if (!_targetPlayer.isCrawling && !_targetPlayer.isCrouching) { UpdateState(State.Notice); if (GameManager.Multiplayer()) { _photonView.RPC("TargetPlayerRPC", (RpcTarget)0, new object[1] { _targetPlayer.photonView.ViewID }); } } } else if ((CurrentState == State.Follow || CurrentState == State.Notice) && (Object)(object)_targetPlayer == (Object)(object)_enemy.Vision.onVisionTriggeredPlayer && !_targetPlayer.isCrawling && !_targetPlayer.isCrouching) { stateTimer = MathF.Max(stateTimer, 6f); } } else { if (CurrentState != State.RWander) { return; } _targetPlayer = _enemy.Vision.onVisionTriggeredPlayer; if (!_targetPlayer.isCrawling) { if (Vector3.Distance(((Component)_targetPlayer).transform.position, ((Component)this).transform.position) < 3f) { UpdateState(State.RSwing); } else if (_attackCooldown > 0f) { UpdateState(State.RShortAttack); } else { UpdateState(State.RAttack); } if (GameManager.Multiplayer()) { _photonView.RPC("TargetPlayerRPC", (RpcTarget)0, new object[1] { _targetPlayer.photonView.ViewID }); } } } } [PunRPC] public void ShootBulletRPC(Vector3 _endPosition, bool _hit) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0017: 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_0029: 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) ItemGunBullet component = Object.Instantiate(bulletPrefab, _bulletPosition.position, _bulletPosition.rotation).GetComponent(); component.hitPosition = _endPosition; component.bulletHit = _hit; soundHit.Play(_endPosition, 1f, 1f, 1f, 1f); component.shootLineWidthCurve = shootLineWidthCurve; component.ActivateAll(); } [PunRPC] private void AttackImpulseRPC() { _attackImpulse = true; } [PunRPC] private void AttackShortImpulseRPC() { _attackShortImpulse = true; } [PunRPC] private void ChangeAnimSpeedRPC(float value) { _animSpeed = value; } private bool CheckPathCompletion() { return _navMeshAgent.Agent.remainingDistance <= 0.07f; } [PunRPC] private void DespawnImpulseRPC() { _despawnImpulse = true; } [PunRPC] private void FireBulletRPC() { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: 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_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: 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_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) if (SemiFunc.IsMasterClientOrSingleplayer()) { Vector3 endPosition = _bulletPosition.position; bool hit = false; bool flag = false; Vector3 forward = _bulletPosition.forward; float num = Random.Range(0f, _bulletSpread); float num2 = Random.Range(0f, 360f); Vector3 val = Vector3.Cross(forward, Random.onUnitSphere); Vector3 normalized = ((Vector3)(ref val)).normalized; Quaternion val2 = Quaternion.AngleAxis(num, normalized); val = Quaternion.AngleAxis(num2, forward) * val2 * forward; Vector3 normalized2 = ((Vector3)(ref val)).normalized; RaycastHit val3 = default(RaycastHit); if (Physics.Raycast(_bulletPosition.position, normalized2, ref val3, 80f, LayerMask.op_Implicit(SemiFunc.LayerMaskGetVisionObstruct()) + LayerMask.GetMask(new string[1] { "enemy" }))) { endPosition = ((RaycastHit)(ref val3)).point; hit = true; } else { flag = true; } if (flag) { endPosition = _bulletPosition.position + _bulletPosition.forward * 80f; } ShootBullet(endPosition, hit); } } private void HurtEffect() { if (!_hurtImpulse) { return; } hurtLerp += 2.5f * Time.deltaTime; hurtLerp = Mathf.Clamp01(hurtLerp); foreach (Material item in _hurtMaterial) { if ((Object)(object)item != (Object)null) { item.SetFloat(_hurtAmount, hurtCurve.Evaluate(hurtLerp)); } if (hurtLerp >= 1f) { hurtLerp = 0f; _hurtImpulse = false; if ((Object)(object)item != (Object)null) { item.SetFloat(_hurtAmount, 0f); } } } } [PunRPC] private void IsSprintingRPC(bool value) { _isSprinting = value; } [PunRPC] private void IsStunnedRPC(bool value) { _isStun = value; } [PunRPC] private void IsTurningRPC(bool value) { _isTurning = value; } [PunRPC] private void IsWalkingRPC(bool value) { _isWalking = value; } [PunRPC] private void PickRandomVariantRPC(int value) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) droidVariant = value; Renderer[] array = renderers; foreach (Renderer val in array) { val.material.SetColor("_AlbedoColor", colors[droidVariant]); } } private void PlayVoicelineMultiplayer(int value) { if (SemiFunc.IsMasterClientOrSingleplayer()) { if (GameManager.Multiplayer()) { _photonView.RPC("PlayVoicelineRPC", (RpcTarget)0, new object[1] { value }); } else { PlayVoicelineRPC(value); } } } [PunRPC] private void PlayVoicelineRPC(int value) { //IL_0039: 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_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) switch (value) { case 0: HateLines.Play(((Component)genericLines.Source).transform.position, 1f, 1f, 1f, 1f); break; case 1: SadLines.Play(((Component)genericLines.Source).transform.position, 1f, 1f, 1f, 1f); break; case 2: EnvyLines.Play(((Component)genericLines.Source).transform.position, 1f, 1f, 1f, 1f); break; case 3: CuteLines.Play(((Component)genericLines.Source).transform.position, 1f, 1f, 1f, 1f); break; case 4: genericLines.Play(((Component)genericLines.Source).transform.position, 1f, 1f, 1f, 1f); break; case 5: RageLines.Play(((Component)genericLines.Source).transform.position, 1f, 1f, 1f, 1f); break; case 6: MurderLines.Play(((Component)genericLines.Source).transform.position, 1f, 1f, 1f, 1f); break; } } private void RotationLogic() { //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Unknown result type (might be due to invalid IL or missing references) //IL_0238: Unknown result type (might be due to invalid IL or missing references) //IL_0243: Unknown result type (might be due to invalid IL or missing references) //IL_0248: Unknown result type (might be due to invalid IL or missing references) //IL_024d: Unknown result type (might be due to invalid IL or missing references) //IL_024e: Unknown result type (might be due to invalid IL or missing references) //IL_024f: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_02a3: Unknown result type (might be due to invalid IL or missing references) //IL_02ad: Unknown result type (might be due to invalid IL or missing references) //IL_025c: Unknown result type (might be due to invalid IL or missing references) //IL_025d: Unknown result type (might be due to invalid IL or missing references) //IL_0262: Unknown result type (might be due to invalid IL or missing references) //IL_0267: Unknown result type (might be due to invalid IL or missing references) //IL_027d: Unknown result type (might be due to invalid IL or missing references) //IL_028c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) if (CurrentState != State.Stun && CurrentState != State.Idle && CurrentState != State.Notice && CurrentState != State.Transform && CurrentState != State.RAttack && CurrentState != State.RShortAttack && CurrentState != State.RSwing) { horizontalRotationSpring.speed = 10f; horizontalRotationSpring.damping = 1f; Vector3 normalized = ((Vector3)(ref _navMeshAgent.AgentVelocity)).normalized; if (((Vector3)(ref normalized)).magnitude > 0.1f) { _horizontalRotationTarget = Quaternion.LookRotation(((Vector3)(ref _navMeshAgent.AgentVelocity)).normalized); ((Quaternion)(ref _horizontalRotationTarget)).eulerAngles = new Vector3(0f, ((Quaternion)(ref _horizontalRotationTarget)).eulerAngles.y, 0f); } else if (_isTurningToPlayer) { _horizontalRotationTarget = Quaternion.LookRotation(((Component)_targetPlayer).transform.position - ((Component)this).transform.position, Vector3.up); ((Quaternion)(ref _horizontalRotationTarget)).eulerAngles = new Vector3(0f, ((Quaternion)(ref _horizontalRotationTarget)).eulerAngles.y, 0f); TurnDroid(); } } else if (CurrentState == State.Notice) { horizontalRotationSpring.speed = 10f; horizontalRotationSpring.damping = 1f; Vector3 val = ((Component)_targetPlayer).transform.position - ((Component)this).transform.position; if (val != Vector3.zero) { _horizontalRotationTarget = Quaternion.LookRotation(val, Vector3.up); ((Quaternion)(ref _horizontalRotationTarget)).eulerAngles = new Vector3(0f, ((Quaternion)(ref _horizontalRotationTarget)).eulerAngles.y, 0f); } TurnDroid(); } else if (CurrentState == State.RSwing || CurrentState == State.RShortAttack || (CurrentState == State.RAttack && _isTurningToPlayer)) { horizontalRotationSpring.speed = 5f; horizontalRotationSpring.damping = 0.5f; Vector3 val2 = _turnPosition - ((Component)this).transform.position; if (val2 != Vector3.zero) { _horizontalRotationTarget = Quaternion.LookRotation(val2, Vector3.up); ((Quaternion)(ref _horizontalRotationTarget)).eulerAngles = new Vector3(0f, ((Quaternion)(ref _horizontalRotationTarget)).eulerAngles.y, 0f); } } ((Component)this).transform.rotation = SemiFunc.SpringQuaternionGet(horizontalRotationSpring, _horizontalRotationTarget, -1f); } private void ShootBullet(Vector3 _endPosition, bool _hit) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) if (SemiFunc.IsMasterClientOrSingleplayer()) { minigunParticles.Play(); if (SemiFunc.IsMultiplayer()) { _photonView.RPC("ShootBulletRPC", (RpcTarget)0, new object[2] { _endPosition, _hit }); } else { ShootBulletRPC(_endPosition, _hit); } } } private void StateDespawn() { //IL_0021: Unknown result type (might be due to invalid IL or missing references) if (_stateImpulse) { _stateImpulse = false; _enemy.NavMeshAgent.Warp(feetTransform.position, false); _enemy.NavMeshAgent.ResetPath(); if (GameManager.Multiplayer()) { _photonView.RPC("DespawnImpulseRPC", (RpcTarget)0, Array.Empty()); } else { DespawnImpulseRPC(); } } } private void StateFollow() { //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) if (_stateImpulse) { stateTimer = 6f; _stateImpulse = false; if (GameManager.Multiplayer()) { _photonView.RPC("IsSprintingRPC", (RpcTarget)0, new object[1] { true }); _photonView.RPC("IsTurningRPC", (RpcTarget)0, new object[1] { false }); } else { IsSprintingRPC(value: true); IsTurningRPC(value: false); } return; } if (Vector3.Distance(((Component)this).transform.position, ((Component)_targetPlayer).transform.position) > _avoidDist) { _overrideAgentLerp -= Time.deltaTime / 0.01f; _enemy.Rigidbody.OverrideFollowPosition(0.2f, 5f, 30f); _overrideAgentLerp = Mathf.Clamp(_overrideAgentLerp, 0f, 1f); float num = 25f; float num2 = 25f; float num3 = Mathf.Lerp(_enemy.NavMeshAgent.DefaultSpeed, num, _overrideAgentLerp); float num4 = Mathf.Lerp(_enemy.Rigidbody.positionSpeedChase, num2, _overrideAgentLerp); _enemy.NavMeshAgent.OverrideAgent(num3 * 2f, _enemy.NavMeshAgent.DefaultAcceleration, 0.2f); _enemy.Rigidbody.OverrideFollowPosition(1f, num4 * 2f, -1f); _targetPosition = ((Component)_targetPlayer).transform.position; _enemy.NavMeshAgent.SetDestination(_targetPosition); _isTurningToPlayer = false; if (GameManager.Multiplayer()) { _photonView.RPC("IsSprintingRPC", (RpcTarget)0, new object[1] { true }); _photonView.RPC("IsTurningRPC", (RpcTarget)0, new object[1] { false }); } else { IsSprintingRPC(value: true); IsTurningRPC(value: false); } } else { _navMeshAgent.Agent.ResetPath(); _isTurningToPlayer = true; if (GameManager.Multiplayer()) { _photonView.RPC("IsSprintingRPC", (RpcTarget)0, new object[1] { false }); _photonView.RPC("IsWalkingRPC", (RpcTarget)0, new object[1] { false }); } else { IsSprintingRPC(value: false); IsWalkingRPC(value: false); } } if (_transformCount > 0f) { _transformCount -= Time.deltaTime * 0.8f; stateTimer -= Time.deltaTime; if (stateTimer <= 0f) { UpdateState(State.Wander); } } else if (isPlayerNear(((Component)this).transform)) { UpdateState(State.Transform); } else { UpdateState(State.Wander); } } private void StateIdle() { //IL_0025: Unknown result type (might be due to invalid IL or missing references) if (_stateImpulse) { _stateImpulse = false; _isTurningToPlayer = false; _navMeshAgent.Warp(((Component)this).transform.position, false); _navMeshAgent.ResetPath(); stateTimer = Random.Range(6f, 8f); if (GameManager.Multiplayer()) { _photonView.RPC("IsSprintingRPC", (RpcTarget)0, new object[1] { false }); _photonView.RPC("IsWalkingRPC", (RpcTarget)0, new object[1] { false }); _photonView.RPC("IsTurningRPC", (RpcTarget)0, new object[1] { false }); } else { IsSprintingRPC(value: false); IsWalkingRPC(value: false); IsTurningRPC(value: false); } } else { stateTimer -= Time.deltaTime; if (stateTimer <= 0f) { UpdateState(State.Wander); } } } private void StateNotice() { //IL_001e: Unknown result type (might be due to invalid IL or missing references) if (_stateImpulse) { _stateImpulse = false; _navMeshAgent.Warp(((Component)this).transform.position, false); _navMeshAgent.ResetPath(); stateTimer = Random.Range(2f, 4f); if (GameManager.Multiplayer()) { _photonView.RPC("IsSprintingRPC", (RpcTarget)0, new object[1] { false }); _photonView.RPC("IsWalkingRPC", (RpcTarget)0, new object[1] { false }); } else { IsSprintingRPC(value: false); IsWalkingRPC(value: false); } return; } if (_transformCount > 0f) { _transformCount -= Time.deltaTime * 0.4f; stateTimer -= Time.deltaTime; if (stateTimer <= 0f) { UpdateState(State.Idle); } } else if (isPlayerNear(((Component)this).transform)) { UpdateState(State.Transform); } else { UpdateState(State.Wander); } stateTimer -= Time.deltaTime; if (stateTimer <= 0f) { UpdateState(State.Follow); } } private void StateRAttack() { //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: 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) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) if (_stateImpulse) { if (Terminator) { stateTimer = 17f; if (GameManager.Multiplayer()) { _photonView.RPC("ChangeAnimSpeedRPC", (RpcTarget)0, new object[1] { 1f }); } else { ChangeAnimSpeedRPC(1f); } } else { stateTimer = 19.4f; } _attackCooldown = Random.Range(22f, 32f); _stateImpulse = false; _navMeshAgent.Warp(((Component)this).transform.position, false); _navMeshAgent.ResetPath(); _turnPosition = ((Component)this).transform.position; if ((Object)(object)_targetPlayer != (Object)null) { _turnPosition = ((Component)_targetPlayer).transform.position; } if (GameManager.Multiplayer()) { _photonView.RPC("AttackImpulseRPC", (RpcTarget)0, Array.Empty()); _photonView.RPC("IsWalkingRPC", (RpcTarget)0, new object[1] { false }); } else { AttackImpulseRPC(); IsWalkingRPC(value: false); } } else { FireBullets(); stateTimer -= Time.deltaTime; if (stateTimer <= 0f) { UpdateState(State.RWander); } } } private void StateRShortAttack() { //IL_0017: 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) if (_stateImpulse) { _navMeshAgent.Warp(((Component)this).transform.position, false); _navMeshAgent.ResetPath(); _stateImpulse = false; stateTimer = 5.5f; if ((Object)(object)_targetPlayer != (Object)null) { _turnPosition = ((Component)_targetPlayer).transform.position; } if (Terminator) { if (GameManager.Multiplayer()) { _photonView.RPC("ChangeAnimSpeedRPC", (RpcTarget)0, new object[1] { 1f }); } else { ChangeAnimSpeedRPC(1f); } } if (GameManager.Multiplayer()) { _photonView.RPC("AttackShortImpulseRPC", (RpcTarget)0, Array.Empty()); _photonView.RPC("IsWalkingRPC", (RpcTarget)0, new object[1] { false }); } else { AttackShortImpulseRPC(); IsWalkingRPC(value: false); } } else { FireBullets(); stateTimer -= Time.deltaTime; if (stateTimer <= 0f) { UpdateState(State.RWander); } } } private void StateRSwing() { //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) if (_stateImpulse) { if (Terminator) { if (GameManager.Multiplayer()) { _photonView.RPC("ChangeAnimSpeedRPC", (RpcTarget)0, new object[1] { 2f }); } else { ChangeAnimSpeedRPC(2f); } stateTimer = 1.2f; } else { stateTimer = 2.4f; } _stateImpulse = false; _navMeshAgent.Warp(((Component)this).transform.position, false); _navMeshAgent.ResetPath(); _turnPosition = ((Component)_targetPlayer).transform.position; if (GameManager.Multiplayer()) { _photonView.RPC("SwingImpulseRPC", (RpcTarget)0, Array.Empty()); _photonView.RPC("IsWalkingRPC", (RpcTarget)0, new object[1] { false }); } else { SwingImpulseRPC(); IsWalkingRPC(value: false); } return; } stateTimer -= Time.deltaTime; if (stateTimer <= 0f) { if (Vector3.Distance(((Component)_targetPlayer).transform.position, ((Component)this).transform.position) < 1f) { UpdateState(State.RSwing); _stateImpulse = true; } else { UpdateState(State.RWander); } } } private void StateSpawn() { //IL_001e: Unknown result type (might be due to invalid IL or missing references) if (_stateImpulse) { _stateImpulse = false; _navMeshAgent.Warp(((Component)this).transform.position, false); _navMeshAgent.ResetPath(); if (GameManager.Multiplayer()) { _photonView.RPC("ChangeAnimSpeedRPC", (RpcTarget)0, new object[1] { 1f }); _photonView.RPC("IsSprintingRPC", (RpcTarget)0, new object[1] { false }); _photonView.RPC("IsWalkingRPC", (RpcTarget)0, new object[1] { false }); _photonView.RPC("IsTurningRPC", (RpcTarget)0, new object[1] { false }); } else { ChangeAnimSpeedRPC(1f); IsSprintingRPC(value: false); IsWalkingRPC(value: false); IsTurningRPC(value: false); } stateTimer = 2f; } else { UpdateState(State.Wander); _hasSpawned = true; } } private void StateStun() { if (_stateImpulse) { _isTurningToPlayer = false; if (Terminator) { if (GameManager.Multiplayer()) { _photonView.RPC("ChangeAnimSpeedRPC", (RpcTarget)0, new object[1] { 1f }); } else { ChangeAnimSpeedRPC(1f); } } _stateImpulse = false; if (!Transformed) { if (!_firstStun && _hasSpawned) { if (GameManager.Multiplayer()) { _photonView.RPC("IsStunnedRPC", (RpcTarget)0, new object[1] { true }); } else { IsStunnedRPC(value: true); } _firstStun = true; } } else if (GameManager.Multiplayer()) { _photonView.RPC("IsStunnedRPC", (RpcTarget)0, new object[1] { true }); } else { IsStunnedRPC(value: true); } } if (_enemy.IsStunned()) { return; } if (GameManager.Multiplayer()) { _photonView.RPC("IsStunnedRPC", (RpcTarget)0, new object[1] { false }); } else { IsStunnedRPC(value: false); } if (Transformed) { if (_attackCooldown > 0f) { UpdateState(State.RShortAttack); } else { UpdateState(State.RAttack); } } else if (isPlayerNear(((Component)this).transform)) { UpdateState(State.Transform); } else { UpdateState(State.Idle); } } private void StateTransform() { //IL_0030: Unknown result type (might be due to invalid IL or missing references) if (_stateImpulse) { stateTimer = 12f; _stateImpulse = false; _isTurningToPlayer = false; _navMeshAgent.Warp(((Component)this).transform.position, false); _navMeshAgent.ResetPath(); if (GameManager.Multiplayer()) { _photonView.RPC("TransformImpulseRPC", (RpcTarget)0, Array.Empty()); _photonView.RPC("IsSprintingRPC", (RpcTarget)0, new object[1] { false }); _photonView.RPC("IsWalkingRPC", (RpcTarget)0, new object[1] { false }); _photonView.RPC("IsTurningRPC", (RpcTarget)0, new object[1] { false }); } else { TransformImpulseRPC(); IsSprintingRPC(value: false); IsWalkingRPC(value: false); IsTurningRPC(value: false); } } else { stateTimer -= Time.deltaTime; if (stateTimer <= 0f) { UpdateState(State.RAttack); Transformed = true; } } } private void StateWander() { //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_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_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: 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_020c: Unknown result type (might be due to invalid IL or missing references) if (_stateImpulse) { bool flag = false; LevelPoint val = SemiFunc.LevelPointGet(((Component)this).transform.position, 10f, 20f); stateTimer = ((!Transformed) ? 18f : 30f); if ((Object)(object)val == (Object)null) { val = SemiFunc.LevelPointGet(((Component)this).transform.position, 5f, 999f); } NavMeshHit val2 = default(NavMeshHit); if ((Object)(object)val != (Object)null && NavMesh.SamplePosition(((Component)val).transform.position + Random.insideUnitSphere * 4f, ref val2, 8f, -1) && Physics.Raycast(((NavMeshHit)(ref val2)).position, Vector3.down, 5f, LayerMask.GetMask(new string[1] { "Default" }))) { _agentDestination = ((NavMeshHit)(ref val2)).position; flag = true; } if (!flag) { return; } if (GameManager.Multiplayer()) { _photonView.RPC("IsWalkingRPC", (RpcTarget)0, new object[1] { true }); _photonView.RPC("IsSprintingRPC", (RpcTarget)0, new object[1] { false }); _photonView.RPC("IsTurningRPC", (RpcTarget)0, new object[1] { false }); } else { IsWalkingRPC(value: true); IsTurningRPC(value: false); IsSprintingRPC(value: false); } _enemy.Rigidbody.notMovingTimer = 0f; _stateImpulse = false; if (Transformed) { if (Terminator) { _navMeshAgent.Agent.speed = 0.75f; if (GameManager.Multiplayer()) { _photonView.RPC("ChangeAnimSpeedRPC", (RpcTarget)0, new object[1] { 3f }); } else { ChangeAnimSpeedRPC(3f); } } else { _navMeshAgent.Agent.speed = 0.25f; } } else { _navMeshAgent.Agent.speed = 1.4f; } _navMeshAgent.SetDestination(_agentDestination); return; } _navMeshAgent.SetDestination(_agentDestination); if (_enemy.Rigidbody.notMovingTimer > 2f) { stateTimer -= Time.deltaTime; } if (stateTimer <= 0f || CheckPathCompletion()) { if (Transformed) { UpdateState(State.RWander); _stateImpulse = true; } else { UpdateState(State.Idle); } } } [PunRPC] private void SwingImpulseRPC() { _swingImpulse = true; } private void Talk() { if (!_talker) { return; } if (!Terminator && !Transformed && CurrentState != State.Transform) { if (_transformCount < _transformCountMax / 6f * 2f) { PlayVoicelineMultiplayer(5); } else if (Random.value < 0.95f) { switch (droidVariant) { case 0: PlayVoicelineMultiplayer(0); break; case 1: PlayVoicelineMultiplayer(1); break; case 2: PlayVoicelineMultiplayer(2); break; case 3: PlayVoicelineMultiplayer(3); break; case 4: PlayVoicelineMultiplayer(4); break; } } else { PlayVoicelineMultiplayer(4); } } else { PlayVoicelineMultiplayer(6); } } [PunRPC] private void TargetPlayerRPC(int _playerID) { foreach (PlayerAvatar player in GameDirector.instance.PlayerList) { if (player.photonView.ViewID == _playerID) { _targetPlayer = player; } } } [PunRPC] private void TransformImpulseRPC() { _transformImpulse = true; } private void TurnDroid() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) float num = Quaternion.Angle(((Component)this).transform.rotation, _horizontalRotationTarget); if (num > 7f || num < -7f) { if (GameManager.Multiplayer()) { _photonView.RPC("IsTurningRPC", (RpcTarget)0, new object[1] { true }); } else { IsTurningRPC(value: true); } } else if (GameManager.Multiplayer()) { _photonView.RPC("IsTurningRPC", (RpcTarget)0, new object[1] { false }); } else { IsTurningRPC(value: false); } } private void UpdateState(State _newState) { if (CurrentState != _newState) { CurrentState = _newState; stateTimer = 0f; _stateImpulse = true; if (GameManager.Multiplayer()) { _photonView.RPC("UpdateStateRPC", (RpcTarget)0, new object[1] { CurrentState }); } else { UpdateStateRPC(CurrentState); } } } [PunRPC] private void UpdateStateRPC(State _state) { CurrentState = _state; if (CurrentState == State.Spawn) { LostDroidAnim.SetSpawn(); } } } internal class LostDroidAnimationController : MonoBehaviour { [Header("References")] public LostDroid Controller; public Animator animator; public Transform minigunFirePosition; public GameObject ExplosionPrefab; [Header("Particles")] public ParticleSystem[] Deathparticles; public ParticleSystem footstepParticles; public ParticleSystem goreExplosion; [Header("Sounds")] [SerializeField] private Sound mediumFootstepSounds; [SerializeField] private Sound mediumWoodFootstepSounds; [SerializeField] private Sound mediumStoneFootstepSounds; [SerializeField] private Sound smallFootstepSounds; [SerializeField] private Sound largeFootstepSounds; [SerializeField] private Sound transformSounds; [SerializeField] private Sound stingerSounds; [SerializeField] public Sound minigunAttackSounds; [SerializeField] public Sound minigunShortAttackSounds; [SerializeField] public Sound minigunAttackGlobalSounds; [SerializeField] public Sound minigunShortAttackGlobalSounds; [SerializeField] private Sound hurtSounds; [SerializeField] private Sound deathSounds; [SerializeField] private Sound whipSounds; [SerializeField] private Sound explodeSounds; private void Update() { //IL_017d: Unknown result type (might be due to invalid IL or missing references) animator.SetBool("isSprinting", Controller._isSprinting); animator.SetBool("isWalking", Controller._isWalking); animator.SetBool("isTurning", Controller._isTurning); animator.SetBool("stun", Controller._isStun); if (Controller._animSpeed != animator.speed) { animator.speed = Controller._animSpeed; } if (Controller._despawnImpulse) { Controller._despawnImpulse = false; animator.SetTrigger("despawn"); } if (Controller._transformImpulse) { Controller._transformImpulse = false; animator.SetTrigger("transform"); } if (Controller._attackImpulse) { Controller._attackImpulse = false; animator.SetTrigger("attack"); } if (Controller._attackShortImpulse) { Controller._attackShortImpulse = false; animator.SetTrigger("attack2"); } if (Controller._deathImpulse) { Controller._deathImpulse = false; animator.SetTrigger("death"); deathSounds.Play(Controller._enemy.CenterTransform.position, 1f, 1f, 1f, 1f); } if (Controller._swingImpulse) { Controller._swingImpulse = false; animator.SetTrigger("swing"); } } public void Despawn() { Controller._enemy.EnemyParent.Despawn(); } public void ExplodeMinigun() { Object.Instantiate(ExplosionPrefab, minigunFirePosition); PlayExplode(); } public void PlayAttackSmall() { //IL_0016: Unknown result type (might be due to invalid IL or missing references) stingerSounds.Play(Controller.Enemy.CenterTransform.position, 1f, 1f, 1f, 1f); } public void PlayDeathParticles() { PlayDeathsound(); ParticleSystem[] deathparticles = Deathparticles; foreach (ParticleSystem val in deathparticles) { val.Play(); } } public void PlayDeathsound() { //IL_0016: Unknown result type (might be due to invalid IL or missing references) deathSounds.Play(Controller.Enemy.CenterTransform.position, 1f, 1f, 1f, 1f); } public void PlayExplode() { //IL_0016: Unknown result type (might be due to invalid IL or missing references) explodeSounds.Play(Controller.Enemy.CenterTransform.position, 1f, 1f, 1f, 1f); } public void PlayGorePartExplosion() { goreExplosion.Play(); } public void PlayHurtSound() { //IL_0016: Unknown result type (might be due to invalid IL or missing references) hurtSounds.Play(Controller.Enemy.CenterTransform.position, 1f, 1f, 1f, 1f); } public void PlayLargeFootstep() { //IL_0016: Unknown result type (might be due to invalid IL or missing references) largeFootstepSounds.Play(Controller.Enemy.CenterTransform.position, 1f, 1f, 1f, 1f); } public void PlayMediumFootstep() { //IL_0031: 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_0109: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) if (LevelGenerator.Instance.Level.NarrativeName == "McJannek Station") { mediumFootstepSounds.Play(Controller.Enemy.CenterTransform.position, 1f, 1f, 1f, 1f); } else if (LevelGenerator.Instance.Level.NarrativeName == "Headman Manor") { mediumWoodFootstepSounds.Play(Controller.Enemy.CenterTransform.position, 1f, 1f, 1f, 1f); } else if (LevelGenerator.Instance.Level.NarrativeName == "Swiftbroom Academy") { mediumStoneFootstepSounds.Play(Controller.Enemy.CenterTransform.position, 1f, 1f, 1f, 1f); } else { mediumStoneFootstepSounds.Play(Controller.Enemy.CenterTransform.position, 1f, 1f, 1f, 1f); } } public void PlayShortStinger() { //IL_0016: 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) minigunShortAttackSounds.Play(Controller.Enemy.CenterTransform.position, 1f, 1f, 1f, 1f); minigunShortAttackGlobalSounds.Play(Controller.Enemy.CenterTransform.position, 1f, 1f, 1f, 1f); } public void PlaySmallFootstep() { //IL_0016: Unknown result type (might be due to invalid IL or missing references) smallFootstepSounds.Play(Controller.Enemy.CenterTransform.position, 1f, 1f, 1f, 1f); } public void PlayStinger() { //IL_0016: 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_0080: Unknown result type (might be due to invalid IL or missing references) stingerSounds.Play(Controller.Enemy.CenterTransform.position, 1f, 1f, 1f, 1f); minigunAttackSounds.Play(Controller.Enemy.CenterTransform.position, 1f, 1f, 1f, 1f); minigunAttackGlobalSounds.Play(Controller.Enemy.CenterTransform.position, 1f, 1f, 1f, 1f); } public void PlayTransform() { //IL_0016: Unknown result type (might be due to invalid IL or missing references) transformSounds.Play(Controller.Enemy.CenterTransform.position, 1f, 1f, 1f, 1f); } public void PlayWhipSound() { //IL_0016: Unknown result type (might be due to invalid IL or missing references) whipSounds.Play(Controller.Enemy.CenterTransform.position, 1f, 1f, 1f, 1f); } public void SetDespawn() { if (SemiFunc.IsMasterClientOrSingleplayer()) { Controller._enemy.EnemyParent.Despawn(); } } public void SetSpawn() { animator.Play("New State", -1, 0f); Controller._damageAmount = 0; Controller.Transformed = false; if (Controller.Terminator) { Controller._transformCount = 5f; Controller._transformCountMax = Random.Range(5f, 10f); } else { Controller._transformCount = 8f; Controller._transformCountMax = Random.Range(6f, 12f); } } public void ShakeCameraBig() { //IL_001f: Unknown result type (might be due to invalid IL or missing references) GameDirector.instance.CameraShake.ShakeDistance(6f, 5f, 15f, ((Component)this).transform.position, 1.8f); } public void ShakeCameraFire() { //IL_001f: 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) GameDirector.instance.CameraShake.ShakeDistance(7f, 10f, 20f, ((Component)this).transform.position, 8.64f); EnemyDirector.instance.SetInvestigate(((Component)this).transform.position, 40f, false); } public void ShakeCameraSmall() { //IL_001f: Unknown result type (might be due to invalid IL or missing references) GameDirector.instance.CameraShake.ShakeDistance(2f, 5f, 15f, ((Component)this).transform.position, 0.8f); } public void ShakeCameraStep() { //IL_001f: Unknown result type (might be due to invalid IL or missing references) GameDirector.instance.CameraShake.ShakeDistance(3f, 5f, 15f, ((Component)this).transform.position, 1f); footstepParticles.Play(); } public void StartFiring() { Controller._fireBullets = true; } public void StartTurning() { Controller._isTurningToPlayer = true; } public void StopFiring() { Controller._fireBullets = false; } public void StopFiringSounds() { } public void StopTurning() { Controller._isTurningToPlayer = false; } } public sealed class WavFileManager { private const string WavExtension = "*.wav"; private const string AudioFolderName = "AudioFiles"; private const string PlayerFolderPrefix = "player_"; private static readonly VepLogger LOG = VepLogger.Create(); public string BaseFolderPath { get; } public int MaxSamplesPerPlayer { get; } public WavFileManager(int maxSamplesPerPlayer = 10) { MaxSamplesPerPlayer = maxSamplesPerPlayer; BaseFolderPath = Path.Combine(Application.dataPath, "AudioFiles"); Directory.CreateDirectory(BaseFolderPath); } public (byte[]? data, int sampleRate) GetRandomFile(string playerNickName) { string playerFolder = GetPlayerFolder(playerNickName); if (!Directory.Exists(playerFolder)) { return (data: null, sampleRate: 0); } string[] files = Directory.GetFiles(playerFolder, "*.wav"); if (files.Length == 0) { LOG.Debug("No audio files found for player " + playerNickName + "."); return (data: null, sampleRate: 0); } string path = files[Random.Range(0, files.Length)]; byte[] array = File.ReadAllBytes(path); int num = ReadSampleRateFromWav(array); LOG.Debug($"Loaded audio file for {playerNickName} with sample rate {num} Hz"); return (data: array, sampleRate: num); } private static int ReadSampleRateFromWav(byte[] wavData) { if (wavData.Length < 28) { LOG.Warning("WAV data too short to read sample rate, using default 48000"); return 48000; } return BitConverter.ToInt32(wavData, 24); } internal static void WriteWavHeader(BinaryWriter writer, int sampleCount, int sampleRate) { int value = sampleRate * 16 / 8; int num = sampleCount * 16 / 8; writer.Write("RIFF".ToCharArray()); writer.Write(36 + num); writer.Write("WAVE".ToCharArray()); writer.Write("fmt ".ToCharArray()); writer.Write(16); writer.Write((short)1); writer.Write((short)1); writer.Write(sampleRate); writer.Write(value); writer.Write((short)2); writer.Write((short)16); writer.Write("data".ToCharArray()); writer.Write(num); } private string GetPlayerFolder(string playerNickName) { string text = FileSystemSanitizer.Sanitize(playerNickName); if (text == "unknown" && !string.IsNullOrEmpty(playerNickName)) { LOG.Warning("Player nickname '" + playerNickName + "' was fully sanitized to fallback 'unknown'."); } return Path.Combine(BaseFolderPath, "player_" + text); } public string[] GetAllPlayerNickNames() { if (!Directory.Exists(BaseFolderPath)) { return Array.Empty(); } return (from name in Directory.GetDirectories(BaseFolderPath).Select(Path.GetFileName) where name?.StartsWith("player_") ?? false select name.Substring("player_".Length)).ToArray(); } public async Task SaveAsync(float[] audioData, int sampleRate, string playerNickName) { string playerFolder = GetPlayerFolder(playerNickName); Directory.CreateDirectory(playerFolder); await EnsureCapacityAsync(playerNickName); string text = Path.Combine(playerFolder, $"sample_{DateTime.Now.Ticks}.wav"); byte[] buffer = AudioFilters.ConvertFloatsToBytes(audioData); string result; await using (FileStream fileStream = new FileStream(text, FileMode.Create, FileAccess.Write)) { string text2; await using (BinaryWriter binaryWriter = new BinaryWriter(fileStream)) { WriteWavHeader(binaryWriter, audioData.Length, sampleRate); binaryWriter.Write(buffer); LOG.Debug("Audio saved for player " + playerNickName + ": " + Path.GetFileName(text)); text2 = text; } result = text2; } return result; } public async Task SaveFromBytesAsync(byte[] audioBytes, int sampleRate, string playerNickName) { string playerFolder = GetPlayerFolder(playerNickName); Directory.CreateDirectory(playerFolder); await EnsureCapacityAsync(playerNickName); string filePath = Path.Combine(playerFolder, $"sample_{DateTime.Now.Ticks}.wav"); await File.WriteAllBytesAsync(filePath, audioBytes); LOG.Debug("Audio saved from bytes for player " + playerNickName + ": " + Path.GetFileName(filePath)); return filePath; } private async Task EnsureCapacityAsync(string playerNickName) { string playerFolder = GetPlayerFolder(playerNickName); if (!Directory.Exists(playerFolder)) { return; } List files = Directory.GetFiles(playerFolder, "*.wav").OrderBy(File.GetCreationTime).ToList(); while (files.Count >= MaxSamplesPerPlayer) { string oldestFile = files[0]; await Task.Run(delegate { File.Delete(oldestFile); }); LOG.Debug("Deleted oldest audio file for player " + playerNickName + ": " + Path.GetFileName(oldestFile)); files.RemoveAt(0); } } } public sealed class WhispralDebuffManager : MonoBehaviour { public const float SpawnDistanceMin = 5f; public const float SpawnDistanceMax = 15f; private static readonly VepLogger LOG = VepLogger.Create(); private readonly Queue _precomputedSpawnPositions = new Queue(); private PlayerAvatar playerAvatar; public int AttachedCount { get; private set; } public bool HasWhispralAttached => AttachedCount > 0; public int PrecomputedPositionCount => _precomputedSpawnPositions.Count; private void Awake() { playerAvatar = ((Component)this).GetComponent(); } private void OnDestroy() { if (HasWhispralAttached) { LOG.Debug("WhispralDebuffManager destroyed while debuffs active, forcing cleanup."); AttachedCount = 0; OnDebuffsDeactivated(); } } public Vector3? GetPrecomputedSpawnPosition() { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) if (_precomputedSpawnPositions.Count > 0) { Vector3 val = _precomputedSpawnPositions.Dequeue(); LOG.Debug($"Using precomputed spawn position: {val} (remaining: {_precomputedSpawnPositions.Count})"); return val; } return null; } public void PrecomputeSpawnPosition() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) PlayerAvatar obj = playerAvatar; Vector3 val = ((obj != null) ? ((Component)obj).transform.position : ((Component)this).transform.position); LevelPoint val2 = SemiFunc.LevelPointGet(val, 5f, 15f) ?? SemiFunc.LevelPointGet(val, 0f, 999f); if (Object.op_Implicit((Object)(object)val2)) { _precomputedSpawnPositions.Enqueue(((Component)val2).transform.position); LOG.Debug($"Precomputed spawn position: {((Component)val2).transform.position} (queue size: {_precomputedSpawnPositions.Count})"); } } public void RegisterAttachment() { bool flag = AttachedCount > 0; AttachedCount++; LOG.Debug($"Whispral attached, count: {AttachedCount}"); if (!flag) { OnDebuffsActivated(); } } public void UnregisterAttachment() { AttachedCount--; LOG.Debug($"Whispral detached, count: {AttachedCount}"); if (AttachedCount <= 0) { AttachedCount = 0; OnDebuffsDeactivated(); } } private void OnDebuffsActivated() { LOG.Debug("First Whispral attached, enabling debuffs."); if (!SemiFunc.IsMultiplayer() || (Object.op_Implicit((Object)(object)playerAvatar) && Object.op_Implicit((Object)(object)playerAvatar.photonView) && playerAvatar.photonView.IsMine)) { InvisiblePlayerDebuff orAddComponent = ComponentHolderProtocol.GetOrAddComponent((Object)(object)((Component)this).gameObject); orAddComponent.ApplyDebuff(invisible: true); DroidDebuff orAddComponent2 = ComponentHolderProtocol.GetOrAddComponent((Object)(object)((Component)this).gameObject); orAddComponent2.ApplyDebuff(active: true, orAddComponent); } else { DilatedPupilsDebuff orAddComponent3 = ComponentHolderProtocol.GetOrAddComponent((Object)(object)((Component)this).gameObject); orAddComponent3.ApplyDebuff(dilated: true); } } private void OnDebuffsDeactivated() { LOG.Debug("Last Whispral detached, disabling debuffs."); if (!SemiFunc.IsMultiplayer() || (Object.op_Implicit((Object)(object)playerAvatar) && Object.op_Implicit((Object)(object)playerAvatar.photonView) && playerAvatar.photonView.IsMine)) { InvisiblePlayerDebuff component = ((Component)this).GetComponent(); DroidDebuff component2 = ((Component)this).GetComponent(); if (Object.op_Implicit((Object)(object)component2)) { component2.ApplyDebuff(active: false, component); } if (Object.op_Implicit((Object)(object)component)) { component.ApplyDebuff(invisible: false); } } else { DilatedPupilsDebuff component3 = ((Component)this).GetComponent(); if (Object.op_Implicit((Object)(object)component3)) { component3.ApplyDebuff(dilated: false); } } _precomputedSpawnPositions.Clear(); } } public sealed class WhispralMimics : MonoBehaviour { private static readonly VepLogger LOG = VepLogger.Create(debugEnabled: true); private const int AudioBufferDurationSeconds = 6; private const float SilenceTimeoutSeconds = 0.5f; private const int ChunkSizeBytes = 8192; private const int ChunkDelayMs = 125; private const float SpatialBlend = 1f; private const float DopplerLevel = 0.5f; private const float MinDistance = 5f; private const float MaxDistance = 25f; private PlayerVoiceChat playerVoiceChat; private WavFileManager wavFileManager; private VadAudioValidator? vadValidator; private string localPlayerNickName; private FieldInfo? voiceChatField; private FieldInfo recorderField; private FieldInfo isTalkingField; private float[]? audioBuffer; private int bufferPosition; private int sampleRate; private int channelCount = 1; private bool isRecording; private bool capturingSpeech; private bool fileSaved; private float silenceTimer; private byte[]? lastSavedAudioBytes; private bool hasNewRecording; private readonly Dictionary> receivedChunksByPlayer = new Dictionary>(); private readonly Dictionary expectedChunkCountByPlayer = new Dictionary(); public PhotonView PhotonView { get; private set; } private void Awake() { PhotonView = ((Component)this).GetComponent(); if (!Object.op_Implicit((Object)(object)PhotonView)) { LOG.Error("PhotonView not found."); return; } PlayerAvatar component = ((Component)this).GetComponent(); if (!Object.op_Implicit((Object)(object)component)) { LOG.Error("PlayerAvatar not found."); } else if (InitializeReflectionFields()) { sampleRate = VepMod.ConfigSamplingRate.Value; ((MonoBehaviour)this).StartCoroutine(WaitForVoiceChat(component)); } } private void OnDestroy() { vadValidator?.Dispose(); } private bool InitializeReflectionFields() { voiceChatField = typeof(PlayerAvatar).GetField("voiceChat", BindingFlags.Instance | BindingFlags.NonPublic); if (voiceChatField == null) { LOG.Error("Could not find 'voiceChat' field in PlayerAvatar."); return false; } recorderField = typeof(PlayerVoiceChat).GetField("recorder", BindingFlags.Instance | BindingFlags.NonPublic); if (recorderField == null) { LOG.Error("Could not find 'recorder' field in PlayerVoiceChat."); return false; } isTalkingField = typeof(PlayerVoiceChat).GetField("isTalking", BindingFlags.Instance | BindingFlags.NonPublic); if (isTalkingField == null) { LOG.Error("Could not find 'isTalking' field in PlayerVoiceChat."); return false; } return true; } private IEnumerator WaitForVoiceChat(PlayerAvatar playerAvatar) { while (!Object.op_Implicit((Object)(object)playerVoiceChat)) { if (voiceChatField == null) { yield break; } playerVoiceChat = (PlayerVoiceChat)voiceChatField.GetValue(playerAvatar); yield return null; } LOG.Info("PlayerVoiceChat initialized."); DetectSampleRate(); if (!SemiFunc.RunIsLevel()) { yield break; } wavFileManager = new WavFileManager(VepMod.ConfigSamplesPerPlayer.Value); localPlayerNickName = PhotonNetwork.LocalPlayer.NickName ?? "unknown"; if (VepMod.ConfigVadEnabled.Value) { try { VadSensitivity value = VepMod.ConfigVadSensitivity.Value; VadValidationCriteria vadValidationCriteria = VadValidationCriteria.FromSensitivity(value); vadValidator = new VadAudioValidator(vadValidationCriteria); LOG.Info($"VAD validation enabled (sensitivity={value}, speechRatio>={vadValidationCriteria.MinSpeechRatio:F2})."); } catch (Exception ex) { LOG.Warning("VAD initialization failed, recordings will not be filtered: " + ex.Message); vadValidator = null; } } if (PhotonView.IsMine) { LOG.Info("WhispralMimics initialized for local player: " + localPlayerNickName); ((MonoBehaviour)this).StartCoroutine(ShareAudioLoop()); } else { LOG.Info("WhispralMimics initialized for remote player (RPC reception only)."); } } private void DetectSampleRate() { object value = recorderField.GetValue(playerVoiceChat); if (value != null) { Type type = value.GetType(); PropertyInfo propertyInfo = type.GetProperty("SamplingRate") ?? type.GetProperty("RecordingSampleRate") ?? type.GetProperty("SamplingRateOverride"); if (propertyInfo != null) { object value2 = propertyInfo.GetValue(value); if (value2 is int num && num > 0) { sampleRate = num; LOG.Debug($"Detected sample rate: {sampleRate} Hz"); return; } if (value2 != null && value2.GetType().IsEnum) { sampleRate = (int)value2; LOG.Debug($"Detected enum sample rate: {sampleRate} Hz"); return; } } } if (sampleRate <= 0) { sampleRate = AudioSettings.outputSampleRate; LOG.Warning($"Fallback to AudioSettings.outputSampleRate: {sampleRate} Hz"); } } public void ProcessVoiceData(short[] voiceData, int frameSampleRate, int channels) { if (!isRecording || !PhotonView.IsMine) { return; } bool flag = (bool)isTalkingField.GetValue(playerVoiceChat); if (flag && !capturingSpeech) { capturingSpeech = true; bufferPosition = 0; fileSaved = false; silenceTimer = 0f; if (frameSampleRate > 0) { sampleRate = frameSampleRate; } channelCount = ((channels < 1) ? 1 : channels); LOG.Debug($"Speech detected, capturing audio ({sampleRate} Hz, {channelCount} ch, frame {voiceData.Length})."); } if (!capturingSpeech) { return; } EnsureBufferAllocated(); CopyVoiceDataToBuffer(voiceData); if (flag) { silenceTimer = 0f; } else { float num = ((sampleRate > 0) ? ((float)(voiceData.Length / channelCount) / (float)sampleRate) : 0f); silenceTimer += num; if (silenceTimer >= 0.5f && bufferPosition > 0 && !fileSaved) { LOG.Debug($"Silence detected for {0.5f}s, finalizing early."); FinalizeRecording(); return; } } if (audioBuffer != null && bufferPosition >= audioBuffer.Length && !fileSaved) { FinalizeRecording(); } } private void EnsureBufferAllocated() { if (audioBuffer == null) { audioBuffer = new float[sampleRate * 6]; LOG.Debug($"Audio buffer allocated: {audioBuffer.Length} samples ({sampleRate} Hz, {channelCount} ch, {6}s)"); } } private void CopyVoiceDataToBuffer(short[] voiceData) { if (audioBuffer == null) { return; } int num = voiceData.Length / channelCount; int num2 = Mathf.Min(num, audioBuffer.Length - bufferPosition); for (int i = 0; i < num2; i++) { float num3 = 0f; int num4 = i * channelCount; for (int j = 0; j < channelCount; j++) { num3 += (float)voiceData[num4 + j]; } audioBuffer[bufferPosition + i] = num3 / ((float)channelCount * 32768f); } bufferPosition += num2; } private void FinalizeRecording() { isRecording = false; capturingSpeech = false; fileSaved = true; if (audioBuffer == null || bufferPosition == 0) { return; } float[] array = new float[bufferPosition]; Array.Copy(audioBuffer, array, bufferPosition); float num = (float)bufferPosition / (float)sampleRate; if (num < VepMod.ConfigAudioMinDuration.Value) { LOG.Debug($"Recording rejected: too short ({num:F2}s < {VepMod.ConfigAudioMinDuration.Value}s)"); return; } if (vadValidator != null) { float[] array2 = array; int num2 = Mathf.RoundToInt(silenceTimer * (float)sampleRate); if (num2 > 0) { int num3 = bufferPosition - num2; if (num3 >= sampleRate / 10) { array2 = new float[num3]; Array.Copy(array, array2, num3); } } try { VadValidationResult vadValidationResult = vadValidator.Validate(array2, sampleRate); if (!vadValidationResult.IsValid) { LOG.Debug($"Recording rejected (VAD): {vadValidationResult.RejectionReason} - {vadValidationResult.Analysis}"); return; } LOG.Debug($"Recording passed VAD: {vadValidationResult.Analysis}"); } catch (Exception ex) { LOG.Warning("VAD Validate threw, accepting recording (fail-open): " + ex.Message); } } LOG.Debug($"Recording validated and finalized: {bufferPosition} samples ({num:F2}s)"); SaveRecordingAsync(array); } private void StartRecording() { if (!isRecording) { LOG.Debug($"StartRecording (sampleRate={sampleRate})"); audioBuffer = null; bufferPosition = 0; isRecording = true; capturingSpeech = false; fileSaved = false; } } private async void SaveRecordingAsync(float[] audioData) { try { await wavFileManager.SaveAsync(audioData, sampleRate, localPlayerNickName); byte[] buffer = AudioFilters.ConvertFloatsToBytes(audioData); using MemoryStream memoryStream = new MemoryStream(); using BinaryWriter binaryWriter = new BinaryWriter(memoryStream); WavFileManager.WriteWavHeader(binaryWriter, audioData.Length, sampleRate); binaryWriter.Write(buffer); lastSavedAudioBytes = memoryStream.ToArray(); hasNewRecording = true; LOG.Debug($"Audio saved and ready for sharing: {lastSavedAudioBytes.Length} bytes"); } catch (Exception ex) { LOG.Error("Error saving recording: " + ex.Message); } } private IEnumerator ShareAudioLoop() { LOG.Info("ShareAudioLoop started."); while (true) { float num = Random.Range(VepMod.ShareDelay.Min, VepMod.ShareDelay.Max); yield return (object)new WaitForSeconds(num); StartRecording(); float timeout = 7f; while (isRecording && timeout > 0f) { timeout -= 0.1f; yield return (object)new WaitForSeconds(0.1f); } if (hasNewRecording && lastSavedAudioBytes != null) { hasNewRecording = false; yield return ShareAudioWithOthersAsync(lastSavedAudioBytes).AsCoroutine(); } } } private async Task ShareAudioWithOthersAsync(byte[] audioData) { if (!PhotonNetwork.IsConnectedAndReady) { LOG.Warning("Photon not connected, skipping share."); return; } List chunks = ChunkAudioData(audioData); LOG.Debug($"Sharing audio: {audioData.Length} bytes in {chunks.Count} chunks"); for (int i = 0; i < chunks.Count; i++) { if (!PhotonNetwork.IsConnectedAndReady) { LOG.Warning("Photon disconnected, aborting share."); return; } PhotonView.RPC("ReceiveSharedAudioChunk", (RpcTarget)1, new object[5] { chunks[i], i, chunks.Count, localPlayerNickName, sampleRate }); await Task.Delay(125); } LOG.Debug($"Audio shared successfully: {chunks.Count} chunks sent."); } private static List ChunkAudioData(byte[] audioData) { List list = new List(); for (int i = 0; i < audioData.Length; i += 8192) { int num = Mathf.Min(8192, audioData.Length - i); byte[] array = new byte[num]; Array.Copy(audioData, i, array, 0, num); list.Add(array); } return list; } [PunRPC] public void ReceiveSharedAudioChunk(byte[] chunk, int chunkIndex, int totalChunks, string sourcePlayerNickName, int srcSampleRate) { if (sourcePlayerNickName == localPlayerNickName) { return; } if (chunkIndex == 0) { receivedChunksByPlayer[sourcePlayerNickName] = new List(); expectedChunkCountByPlayer[sourcePlayerNickName] = totalChunks; LOG.Debug($"Receiving shared audio from {sourcePlayerNickName}: {totalChunks} chunks at {srcSampleRate} Hz"); } if (!receivedChunksByPlayer.TryGetValue(sourcePlayerNickName, out List value)) { LOG.Warning("Received chunk for unknown player: " + sourcePlayerNickName); return; } while (value.Count <= chunkIndex) { value.Add(null); } value[chunkIndex] = chunk; int valueOrDefault = expectedChunkCountByPlayer.GetValueOrDefault(sourcePlayerNickName, 0); if (value.Count >= valueOrDefault && value.All((byte[] c) => c != null)) { LOG.Debug("All chunks received from " + sourcePlayerNickName + ", saving audio."); byte[] audioData = CombineChunks(value); SaveReceivedAudioAsync(audioData, srcSampleRate, sourcePlayerNickName); receivedChunksByPlayer.Remove(sourcePlayerNickName); expectedChunkCountByPlayer.Remove(sourcePlayerNickName); } } private static byte[] CombineChunks(List chunks) { int num = chunks.Sum((byte[] c) => c.Length); byte[] array = new byte[num]; int num2 = 0; foreach (byte[] chunk in chunks) { Array.Copy(chunk, 0, array, num2, chunk.Length); num2 += chunk.Length; } return array; } private async void SaveReceivedAudioAsync(byte[] audioData, int srcSampleRate, string sourcePlayerNickName) { try { await wavFileManager.SaveFromBytesAsync(audioData, srcSampleRate, sourcePlayerNickName); LOG.Debug("Audio from " + sourcePlayerNickName + " saved successfully."); } catch (Exception ex) { LOG.Error("Error saving audio from " + sourcePlayerNickName + ": " + ex.Message); } } [PunRPC] public void PlayVoiceCommandRPC(int targetViewID, string sourcePlayerNickName, bool applyFilter) { PlayerAvatar instance = PlayerAvatar.instance; if (!Object.op_Implicit((Object)(object)instance) || instance.photonView.ViewID != targetViewID) { return; } DroidDebuff component = ((Component)instance).GetComponent(); if ((Object)(object)component != (Object)null && component.IsActive) { DroidController droidByPlayerName = component.GetDroidByPlayerName(sourcePlayerNickName); if ((Object)(object)droidByPlayerName != (Object)null) { LOG.Debug("Playing voice from " + sourcePlayerNickName + " on hallucination droid"); droidByPlayerName.PlayVoice(applyFilter); } } } public void SendPlayVoiceCommand(int targetViewID, string sourcePlayerName, bool applyFilter) { if (!PhotonNetwork.IsConnectedAndReady) { LOG.Warning("Photon not connected, cannot send voice command."); return; } PhotonView.RPC("PlayVoiceCommandRPC", (RpcTarget)0, new object[3] { targetViewID, sourcePlayerName, applyFilter }); } public string[] GetAvailablePlayerIds() { return wavFileManager?.GetAllPlayerNickNames() ?? Array.Empty(); } private float[] ProcessReceivedAudio(byte[] audioData, bool applyVoiceFilter, int receivedSampleRate) { float[] samples = AudioFilters.ConvertBytesToFloats(audioData); samples = AudioFilters.ApplyLowPassFilter(samples, receivedSampleRate); if (applyVoiceFilter) { samples = ApplyRandomVoiceFilter(samples, receivedSampleRate); } return AudioFilters.ApplyFadeAndPadding(samples, receivedSampleRate); } private float[] ApplyRandomVoiceFilter(float[] samples, int receivedSampleRate) { return Random.Range(0, 3) switch { 0 => AudioFilters.ApplyPitchShift(samples, 0.5f), 1 => AudioFilters.ApplyPitchShift(samples, 1.2f), 2 => AudioFilters.ApplyAlienFilter(samples, receivedSampleRate), _ => samples, }; } public void PlayAudioAtTransform(Transform target, string sourcePlayerNickName, bool applyFilter) { if ((Object)(object)target == (Object)null) { LOG.Warning("PlayAudioAtTransform: target is null"); return; } var (array, num) = wavFileManager.GetRandomFile(sourcePlayerNickName); if (array == null) { LOG.Debug("No audio found for player " + sourcePlayerNickName); return; } float[] array2 = ProcessReceivedAudio(array, applyFilter, num); AudioClip val = AudioClip.Create("HallucinationClip", array2.Length, 1, num, false); val.SetData(array2, 0); PlayAtTransform(target, val); } private void PlayAtTransform(Transform target, AudioClip clip) { AudioSource orAddComponent = ComponentHolderProtocol.GetOrAddComponent((Object)(object)((Component)target).gameObject); ((Behaviour)orAddComponent).enabled = true; ConfigureAudioSource(orAddComponent, clip); AudioLowPassFilter orAddComponent2 = ComponentHolderProtocol.GetOrAddComponent((Object)(object)((Component)target).gameObject); AudioLowPassLogic orAddComponent3 = ComponentHolderProtocol.GetOrAddComponent((Object)(object)((Component)target).gameObject); orAddComponent3.ForceStart = true; orAddComponent3.AlwaysActive = true; orAddComponent3.Fetch = true; orAddComponent3.Setup(); orAddComponent.Play(); ((MonoBehaviour)this).StartCoroutine(DestroyAudioSourceAfterPlayback(orAddComponent, clip.length + 0.1f)); } private void ConfigureAudioSource(AudioSource source, AudioClip clip) { //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: 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_00af: Expected O, but got Unknown source.clip = clip; source.volume = VepMod.ConfigVoiceVolume.Value; source.spatialBlend = 1f; source.dopplerLevel = 0.5f; source.minDistance = 5f; source.maxDistance = 25f; source.spread = 0f; source.priority = 0; source.bypassEffects = false; source.bypassListenerEffects = false; source.bypassReverbZones = false; source.rolloffMode = (AudioRolloffMode)2; source.SetCustomCurve((AudioSourceCurveType)0, new AnimationCurve((Keyframe[])(object)new Keyframe[2] { new Keyframe(0.2f, 1f), new Keyframe(1f, 0f) })); source.outputAudioMixerGroup = playerVoiceChat.mixerMicrophoneSound; } private static IEnumerator DestroyAudioSourceAfterPlayback(AudioSource source, float delay) { yield return (object)new WaitForSeconds(delay); if (!((Object)(object)source == (Object)null)) { GameObject go = ((Component)source).gameObject; AudioLowPassLogic component = go.GetComponent(); if ((Object)(object)component != (Object)null) { Object.Destroy((Object)(object)component); yield return null; } AudioLowPassFilter component2 = go.GetComponent(); if ((Object)(object)component2 != (Object)null) { Object.Destroy((Object)(object)component2); yield return null; } if ((Object)(object)source != (Object)null) { Object.Destroy((Object)(object)source); } } } } } namespace VepMod.Enemies.Whispral.Visuals { public sealed class DroidAvatarVisualsRelay : MonoBehaviour { private static readonly VepLogger LOG = VepLogger.Create(); private CosmeticCustomSpring[] _customSprings = Array.Empty(); private DroidController _droid; private CosmeticSprings[] _springs = Array.Empty(); private Dictionary _springTypes = new Dictionary(); public void Initialize(DroidController droid, GameObject cloneRoot, Dictionary springTypes) { _droid = droid; _springTypes = springTypes ?? new Dictionary(); if ((Object)(object)cloneRoot != (Object)null) { _springs = cloneRoot.GetComponentsInChildren(true); _customSprings = cloneRoot.GetComponentsInChildren(true); } } private bool TryGetSpringType(CosmeticSprings spring, out CosmeticType type) { return _springTypes.TryGetValue(spring, out type); } public void FootstepLight() { PlayFootstep(); } public void FootstepMedium() { PlayFootstep(); } public void FootstepHeavy() { PlayFootstep(); } public void StandToCrouch() { } public void CrouchToStand() { } public void CrouchToCrawl() { } public void CrawlToCrouch() { } public void RightFootUp() { ImpulseRight(2f, -30f); } public void RightFootDown() { ImpulseRight(-2f, 30f); } public void RightFootUpSlow() { ImpulseRight(1f, 30f); } public void RightFootDownSlow() { ImpulseRight(-1f, -30f); } public void LeftFootUp() { ImpulseLeft(2f, -30f); } public void LeftFootDown() { ImpulseLeft(-2f, 30f); } public void LeftFootUpSlow() { ImpulseLeft(1f, -30f); } public void LeftFootDownSlow() { ImpulseLeft(-1f, 30f); } private void PlayFootstep() { if ((Object)(object)_droid != (Object)null) { _droid.PlayMediumFootstep(); } } private void ImpulseRight(float springForce, float customForce) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Invalid comparison between Unknown and I4 //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Invalid comparison between Unknown and I4 //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Invalid comparison between Unknown and I4 CosmeticSprings[] springs = _springs; foreach (CosmeticSprings val in springs) { if (!((Object)(object)val == (Object)null) && TryGetSpringType(val, out var type) && ((int)type == 3 || (int)type == 11 || (int)type == 19)) { val.Impulse(springForce); } } CosmeticCustomSpring[] customSprings = _customSprings; foreach (CosmeticCustomSpring val2 in customSprings) { if ((Object)(object)val2 != (Object)null && (int)val2.type == 0) { val2.Impulse(customForce); } } } private void ImpulseLeft(float springForce, float customForce) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Invalid comparison between Unknown and I4 //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Invalid comparison between Unknown and I4 //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Invalid comparison between Unknown and I4 //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Invalid comparison between Unknown and I4 CosmeticSprings[] springs = _springs; foreach (CosmeticSprings val in springs) { if (!((Object)(object)val == (Object)null) && TryGetSpringType(val, out var type) && ((int)type == 4 || (int)type == 12 || (int)type == 22)) { val.Impulse(springForce); } } CosmeticCustomSpring[] customSprings = _customSprings; foreach (CosmeticCustomSpring val2 in customSprings) { if ((Object)(object)val2 != (Object)null && (int)val2.type == 1) { val2.Impulse(customForce); } } } } internal static class DroidVisualsClone { private const string RigName = "[RIG]"; private const string FlashlightAnchorName = "Flashlight Target Client"; private const string MapToolAnchorName = "Map Tool Target Client"; private static readonly VepLogger LOG = VepLogger.Create("DroidVisualsClone", debugEnabled: true); private static readonly HashSet KeepTypeNames = new HashSet { "PlayerMaterial", "PlayerSpringImpulse" }; private static readonly HashSet DestroyCosmeticTypeNames = new HashSet { "Cosmetic", "CosmeticBlocked" }; private static Dictionary? SpringTypeCache; private static readonly (string Name, Vector3 Pos)[] FlashlightNeutralNodes = new(string, Vector3)[5] { ("Back Away Offset", new Vector3(0f, 0f, -0.044f)), ("Back Away", new Vector3(0f, 0f, 0.044f)), ("Flashlight Sprint", Vector3.zero), ("Flashlight Hide", Vector3.zero), ("Flashlight Click", Vector3.zero) }; private static readonly HashSet IdentityResetBones = new HashSet { "ANIM ARM L", "ANIM ARM R", "ANIM ARM R SCALE", "ANIM BODY BOT", "ANIM BODY TOP", "ANIM BOT", "ANIM HEAD BOT", "ANIM LEG L BOT", "ANIM LEG L TOP", "ANIM LEG R BOT", "ANIM LEG R TOP", "Cosmetic Parent - Head Bottom Mesh", "Player Spring Impulse - Body Bottom", "Player Spring Impulse - Body Top", "code_arm_l" }; private static readonly HashSet ActivateParents = new HashSet { "Cosmetic Parent - Body Bottom Mesh", "Cosmetic Parent - Body Top Mesh" }; private const string MapToolAnchorBone = "Map Tool Target Client"; private static readonly Vector3 MapToolAnchorPos = new Vector3(0.007999987f, -0.084999986f, 0.4980001f); private static readonly Quaternion MapToolAnchorRot = new Quaternion(-0.58078414f, -0.22498398f, 0.48120198f, 0.6168604f); public static Transform? FindCube(Transform droidRoot) { Transform val = droidRoot.Find("Enable/Cube") ?? droidRoot.Find("Cube"); if ((Object)(object)val != (Object)null) { return val; } Transform[] componentsInChildren = ((Component)droidRoot).GetComponentsInChildren(true); foreach (Transform val2 in componentsInChildren) { if ((Object)(object)val2 != (Object)null && ((Object)val2).name == "Cube") { return val2; } } LOG.Warning("FindCube: Cube transform not found under droid root"); return null; } public static void SanitizeCube(Transform cube) { if ((Object)(object)cube == (Object)null) { return; } Component[] components = ((Component)cube).GetComponents(); foreach (Component val in components) { if (!((Object)(object)val == (Object)null) && !ShouldKeep(val)) { Object.DestroyImmediate((Object)(object)val); } } } public static void StripExistingRig(Transform cube) { if (!((Object)(object)cube == (Object)null)) { Transform val = cube.Find("[RIG]"); if ((Object)(object)val != (Object)null) { Object.DestroyImmediate((Object)(object)((Component)val).gameObject); } } } public static bool TryCloneRig(PlayerAvatar sourcePlayer, Transform cube, out GameObject? cloneRig) { //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) cloneRig = null; if ((Object)(object)sourcePlayer == (Object)null || (Object)(object)cube == (Object)null) { LOG.Warning("TryCloneRig: sourcePlayer or cube is null"); return false; } PlayerAvatarVisuals playerAvatarVisuals = sourcePlayer.playerAvatarVisuals; if ((Object)(object)playerAvatarVisuals == (Object)null) { LOG.Warning("TryCloneRig: sourcePlayer " + sourcePlayer.playerName + " has no playerAvatarVisuals"); return false; } Transform val = ((Component)playerAvatarVisuals).transform.Find("[RIG]"); if ((Object)(object)val == (Object)null) { LOG.Warning("TryCloneRig: source [RIG] not found under " + sourcePlayer.playerName + ".playerAvatarVisuals"); return false; } GameObject val2 = Object.Instantiate(((Component)val).gameObject, cube); ((Object)val2).name = "[RIG]"; val2.transform.localPosition = Vector3.zero; val2.transform.localRotation = Quaternion.identity; val2.transform.localScale = Vector3.one; val2.SetActive(true); Dictionary springTypeCache = CaptureSpringTypes(val2); SpringTypeCache = springTypeCache; Sanitize(val2); ApplyColors(val2, sourcePlayer); NormalizeRendering(val2); ForceStandingPose(val2); cloneRig = val2; int num = val2.GetComponentsInChildren(true).Length; LOG.Debug($"Cloned [RIG] from {sourcePlayer.playerName}: cubePos={cube.position}, " + $"rigLocalPos={val2.transform.localPosition}, " + $"cubeLossy={cube.lossyScale}, " + $"rigLossy={val2.transform.lossyScale}, " + $"renderers={num}, isLocal={sourcePlayer.isLocal}"); return true; } public static bool TryCloneFlashlight(PlayerAvatar sourcePlayer, GameObject cloneRig) { //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)sourcePlayer == (Object)null || (Object)(object)cloneRig == (Object)null) { return false; } FlashlightController val = sourcePlayer.flashlightController ?? ((Component)sourcePlayer).GetComponentInChildren(true); if ((Object)(object)val == (Object)null) { LOG.Warning("TryCloneFlashlight: no FlashlightController on " + sourcePlayer.playerName); return false; } Transform val2 = DroidHelpers.FindChildByName(cloneRig.transform, "Flashlight Target Client"); if ((Object)(object)val2 == (Object)null) { LOG.Warning("TryCloneFlashlight: anchor 'Flashlight Target Client' not found in clone rig (Player Spring Impulse - Arm Left peut-être strippé par Sanitize)"); return false; } GameObject gameObject = ((Component)val).gameObject; GameObject val3 = Object.Instantiate(gameObject, val2); ((Object)val3).name = "Flashlight"; val3.transform.localPosition = Vector3.zero; val3.transform.localRotation = Quaternion.identity; val3.transform.localScale = Vector3.one; FlashlightController component = val3.GetComponent(); MeshRenderer val4 = (((Object)(object)component != (Object)null) ? component.mesh : null); MeshRenderer val5 = (((Object)(object)component != (Object)null) ? component.meshShadows : null); Light val6 = (((Object)(object)component != (Object)null) ? component.spotlight : null); Behaviour val7 = (((Object)(object)component != (Object)null) ? component.halo : null); Component[] componentsInChildren = val3.GetComponentsInChildren(true); foreach (Component val8 in componentsInChildren) { if (!((Object)(object)val8 == (Object)null) && !(val8 is Transform) && !(val8 is MeshFilter) && !(val8 is MeshRenderer) && !(val8 is Light)) { Object.DestroyImmediate((Object)(object)val8); } } if ((Object)(object)val4 != (Object)null) { ((Renderer)val4).enabled = true; } if ((Object)(object)val5 != (Object)null) { ((Renderer)val5).enabled = true; } if ((Object)(object)val6 != (Object)null) { ((Behaviour)val6).enabled = true; } if ((Object)(object)val7 != (Object)null) { val7.enabled = true; } ResetFlashlightInternals(val3); int num = LayerMask.NameToLayer("PlayerVisuals"); if (num < 0) { num = 0; } Transform[] componentsInChildren2 = val3.GetComponentsInChildren(true); foreach (Transform val9 in componentsInChildren2) { if ((Object)(object)val9 != (Object)null) { ((Component)val9).gameObject.layer = num; } } val3.SetActive(true); LOG.Debug("Flashlight cloned under 'Flashlight Target Client'"); return true; } private static void ResetFlashlightInternals(GameObject clone) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) (string, Vector3)[] flashlightNeutralNodes = FlashlightNeutralNodes; for (int i = 0; i < flashlightNeutralNodes.Length; i++) { (string, Vector3) tuple = flashlightNeutralNodes[i]; string item = tuple.Item1; Vector3 item2 = tuple.Item2; Transform val = DroidHelpers.FindChildByName(clone.transform, item); if (!((Object)(object)val == (Object)null)) { val.localPosition = item2; val.localRotation = Quaternion.identity; val.localScale = Vector3.one; } } } public static bool TryCloneMapTool(PlayerAvatar sourcePlayer, GameObject cloneRig, out GameObject? clonedMapTool) { //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) clonedMapTool = null; if ((Object)(object)sourcePlayer == (Object)null || (Object)(object)cloneRig == (Object)null) { return false; } Transform val = ((Component)sourcePlayer).transform.root.Find("Map Tool"); if ((Object)(object)val == (Object)null) { LOG.Warning("TryCloneMapTool: 'Map Tool' not found under root of " + sourcePlayer.playerName); return false; } Transform val2 = DroidHelpers.FindChildByName(cloneRig.transform, "Map Tool Target Client"); if ((Object)(object)val2 == (Object)null) { LOG.Warning("TryCloneMapTool: anchor 'Map Tool Target Client' not found in clone rig (Player Spring Impulse - Arm Right peut-être strippé par Sanitize)"); return false; } GameObject gameObject = ((Component)val).gameObject; GameObject val3 = Object.Instantiate(gameObject, val2); ((Object)val3).name = "Map Tool"; val3.transform.localPosition = Vector3.zero; val3.transform.localRotation = Quaternion.identity; val3.transform.localScale = Vector3.one; Component[] componentsInChildren = val3.GetComponentsInChildren(true); foreach (Component val4 in componentsInChildren) { if (!((Object)(object)val4 == (Object)null) && !(val4 is Transform) && !(val4 is MeshFilter) && !(val4 is MeshRenderer) && !(val4 is SkinnedMeshRenderer) && !(val4 is Light)) { Object.DestroyImmediate((Object)(object)val4); } } Renderer[] componentsInChildren2 = val3.GetComponentsInChildren(true); foreach (Renderer val5 in componentsInChildren2) { if ((Object)(object)val5 != (Object)null) { val5.enabled = true; } } Transform val6 = DroidHelpers.FindChildByName(val3.transform, "Visuals"); if ((Object)(object)val6 != (Object)null) { ((Component)val6).gameObject.SetActive(true); } Transform val7 = DroidHelpers.FindChildByName(val3.transform, "Hide"); if ((Object)(object)val7 != (Object)null) { val7.localRotation = Quaternion.identity; val7.localScale = Vector3.one; } int num = LayerMask.NameToLayer("PlayerVisuals"); if (num < 0) { num = 0; } Transform[] componentsInChildren3 = val3.GetComponentsInChildren(true); foreach (Transform val8 in componentsInChildren3) { if ((Object)(object)val8 != (Object)null) { ((Component)val8).gameObject.layer = num; } } int num2 = val3.GetComponentsInChildren(true).Length; LOG.Debug("MapTool cloned under 'Map Tool Target Client' " + $"(renderers={num2}, visualsFound={(Object)(object)val6 != (Object)null}, hideFound={(Object)(object)val7 != (Object)null})"); val3.SetActive(false); clonedMapTool = val3; return true; } public static void AttachRelay(Animator animator, DroidController droid, GameObject cloneRig) { if (!((Object)(object)animator == (Object)null)) { DroidAvatarVisualsRelay droidAvatarVisualsRelay = ((Component)animator).gameObject.AddComponent(); droidAvatarVisualsRelay.Initialize(droid, cloneRig, SpringTypeCache ?? new Dictionary()); SpringTypeCache = null; } } private static Dictionary CaptureSpringTypes(GameObject clone) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: 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) Dictionary dictionary = new Dictionary(); Cosmetic[] componentsInChildren = clone.GetComponentsInChildren(true); foreach (Cosmetic val in componentsInChildren) { if ((Object)(object)val == (Object)null) { continue; } CosmeticType type = val.type; CosmeticSprings[] componentsInChildren2 = ((Component)val).GetComponentsInChildren(true); foreach (CosmeticSprings val2 in componentsInChildren2) { if ((Object)(object)val2 != (Object)null) { dictionary[val2] = type; } } } return dictionary; } private static void Sanitize(GameObject clone) { Component[] componentsInChildren = clone.GetComponentsInChildren(true); foreach (Component val in componentsInChildren) { if (!((Object)(object)val == (Object)null) && !ShouldKeep(val)) { Object.DestroyImmediate((Object)(object)val); } } } private static bool ShouldKeep(Component comp) { if (comp is Transform) { return true; } if (comp is Animator) { return true; } if (comp is Renderer) { return true; } if (comp is MeshFilter) { return true; } if (comp is ParticleSystem) { return true; } if (comp is Light) { return true; } if (comp is IConstraint) { return true; } string name = ((object)comp).GetType().Name; if (DestroyCosmeticTypeNames.Contains(name)) { return false; } if (name.StartsWith("Cosmetic")) { return true; } if (KeepTypeNames.Contains(name)) { return true; } return false; } private static void ApplyColors(GameObject clone, PlayerAvatar sourcePlayer) { //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Expected I4, but got Unknown PlayerCosmetics playerCosmetics = sourcePlayer.playerCosmetics; if ((Object)(object)playerCosmetics == (Object)null || playerCosmetics.colorsEquipped == null || (Object)(object)MetaManager.instance == (Object)null || MetaManager.instance.colors == null) { return; } int count = MetaManager.instance.colors.Count; if (count == 0) { return; } int num = Shader.PropertyToID("_AlbedoColor"); int num2 = Shader.PropertyToID("_EmissionColor"); int num3 = Shader.PropertyToID("_FresnelColor"); int[] colorsEquipped = playerCosmetics.colorsEquipped; PlayerMaterial[] componentsInChildren = clone.GetComponentsInChildren(true); foreach (PlayerMaterial val in componentsInChildren) { if ((Object)(object)val == (Object)null) { continue; } val.Setup(); if ((Object)(object)val.material == (Object)null) { continue; } int num4 = (int)val.cosmeticType; if (num4 >= 0 && num4 < colorsEquipped.Length) { int num5 = colorsEquipped[num4]; if (num5 >= 0 && num5 < count) { val.ColorSet(num, num2, num3, num5); } } } } private static void ForceStandingPose(GameObject clone) { //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) Transform[] componentsInChildren = clone.GetComponentsInChildren(true); foreach (Transform val in componentsInChildren) { if ((Object)(object)val == (Object)null) { continue; } string name = ((Object)val).name; if (!(name == "Mesh Sphere")) { if (name == "Mesh Flat") { ((Component)val).gameObject.SetActive(false); } else if (ActivateParents.Contains(((Object)val).name)) { ((Component)val).gameObject.SetActive(true); } else if (((Object)val).name == "Map Tool Target Client") { val.localPosition = MapToolAnchorPos; val.localRotation = MapToolAnchorRot; val.localScale = Vector3.one; } else if (IdentityResetBones.Contains(((Object)val).name)) { val.localPosition = Vector3.zero; val.localRotation = Quaternion.identity; val.localScale = Vector3.one; } } else { ((Component)val).gameObject.SetActive(true); } } } private static void NormalizeRendering(GameObject clone) { int num = LayerMask.NameToLayer("PlayerVisuals"); if (num < 0) { num = 0; } Renderer[] componentsInChildren = clone.GetComponentsInChildren(true); foreach (Renderer val in componentsInChildren) { if (!((Object)(object)val == (Object)null)) { val.shadowCastingMode = (ShadowCastingMode)1; val.enabled = true; ((Component)val).gameObject.layer = num; } } SkinnedMeshRenderer[] componentsInChildren2 = clone.GetComponentsInChildren(true); foreach (SkinnedMeshRenderer val2 in componentsInChildren2) { if (!((Object)(object)val2 == (Object)null)) { val2.updateWhenOffscreen = true; } } } } }