using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using FistVR; using H3MP; using H3MP.Networking; using H3MP.Scripts; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.Networking; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyCompany("Niko666")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("PlayerFootsteps but synced in H3MP! All clients need to install this in order to sync. Can also be used in singleplayer.")] [assembly: AssemblyFileVersion("0.3.0.0")] [assembly: AssemblyInformationalVersion("0.3.0")] [assembly: AssemblyProduct("Niko666.H3MPFootstep")] [assembly: AssemblyTitle("H3MP Footsteps")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.3.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.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace BepInEx { [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] [Conditional("CodeGeneration")] internal sealed class BepInAutoPluginAttribute : Attribute { public BepInAutoPluginAttribute(string id = null, string name = null, string version = null) { } } } namespace BepInEx.Preloader.Core.Patching { [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] [Conditional("CodeGeneration")] internal sealed class PatcherAutoPluginAttribute : Attribute { public PatcherAutoPluginAttribute(string id = null, string name = null, string version = null) { } } } namespace Niko666.H3MPFootstep { public static class FootstepAudioBank { private static readonly string[] PackMaterials = new string[18] { "Concrete", "Generic", "Grass", "Gravel", "MetalThick", "MetalThin", "Mud", "Meat", "SoftMaterial", "Water", "WoodHeavy", "WoodLight", "Sand", "Brick", "Rock", "Ice", "Glass", "SnowNorthestDakota" }; private static readonly Dictionary> _clips = new Dictionary>(); private static bool _loadStarted; private static bool _loadDone; private static AudioSource[] _pool; private static int _poolIndex; private const int PoolSize = 8; public static bool LoadDone => _loadDone; public static bool HasClips(string material) { if (_clips.TryGetValue(material, out var value) && value != null) { return value.Count > 0; } return false; } public static AudioClip RandomClip(string material) { if (!_clips.TryGetValue(material, out var value) || value == null || value.Count == 0) { return null; } return value[Random.Range(0, value.Count)]; } public static void StartLoad() { if (!_loadStarted) { _loadStarted = true; H3MPFootstepPlugin instance = H3MPFootstepPlugin.Instance; if (!((Object)(object)instance == (Object)null)) { ((MonoBehaviour)instance).StartCoroutine(LoadAll()); } } } public static string MaterialFor(BulletImpactSoundType t) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Expected I4, but got Unknown switch ((int)t) { case 10: return "Grass"; case 25: return "WoodHeavy"; case 26: case 27: return "WoodLight"; case 11: return "Gravel"; case 17: return "Mud"; case 13: return "Meat"; case 24: return "Water"; case 23: return "SoftMaterial"; case 21: case 22: return "Sand"; case 15: return "MetalThick"; case 1: case 2: case 14: case 16: return "MetalThin"; case 3: return "Brick"; case 20: return "Rock"; case 12: return "Ice"; case 6: case 7: case 8: case 9: return "Glass"; case 4: return "Concrete"; default: return "Generic"; } } private static IEnumerator LoadAll() { _clips.Clear(); int loaded = 0; string[] packMaterials = PackMaterials; foreach (string mat in packMaterials) { List list = new List(); _clips[mat] = list; string pluginPath = Paths.PluginPath; if (Directory.Exists(pluginPath)) { string[] files = Directory.GetFiles(pluginPath, "PlayerFootsteps_" + mat + "*.wav", SearchOption.AllDirectories); string[] array = files; foreach (string path in array) { Action onDone = delegate(AudioClip clip) { if ((Object)(object)clip != (Object)null) { list.Add(clip); int num = loaded; loaded = num + 1; } }; yield return LoadClip(path, onDone); } } if (list.Count != 0) { continue; } string text = PluginResourcePath(mat + ".wav"); if (!File.Exists(text)) { continue; } string path2 = text; Action onDone2 = delegate(AudioClip clip) { if ((Object)(object)clip != (Object)null) { list.Add(clip); int num = loaded; loaded = num + 1; } }; yield return LoadClip(path2, onDone2); } _loadDone = true; H3MPFootstepPlugin.Log.LogInfo((object)$"Footstep audio bank loaded: {loaded} clips."); } private static string PluginResourcePath(string file) { H3MPFootstepPlugin instance = H3MPFootstepPlugin.Instance; if ((Object)(object)instance == (Object)null || ((BaseUnityPlugin)instance).Info == null) { return file; } string directoryName = Path.GetDirectoryName(((BaseUnityPlugin)instance).Info.Location); string text = Path.Combine(directoryName, file); if (File.Exists(text)) { return text; } return Path.Combine(Path.Combine(directoryName, "resources"), file); } public static void Play(BulletImpactSoundType matType, Vector3 pos, float volume, float pitch, AudioImpactIntensity intensity, float maxDist) { //IL_0084: 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_008a: 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_008e: 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_006c: 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) H3MPFootstepPlugin instance = H3MPFootstepPlugin.Instance; AudioClip val = null; if ((Object)(object)instance != (Object)null && instance.ConfigCustomAudio.Value) { string text = MaterialFor(matType); if (text == "Generic" && (Object)(object)GM.TNH_Manager != (Object)null && GM.TNH_Manager.LevelName == "NorthestDakota") { text = "SnowNorthestDakota"; } val = RandomClip(text); } if ((Object)(object)val != (Object)null) { PlayPooled(val, pos, Mathf.Clamp(volume, 0.02f, 2f), pitch); return; } MatSoundType val2 = MapToVanilla(matType); SM.PlayImpactSound((ImpactType)30, val2, intensity, pos, (FVRPooledAudioType)41, maxDist, volume, pitch); } private static MatSoundType MapToVanilla(BulletImpactSoundType t) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Expected I4, but got Unknown switch (t - 1) { case 24: case 25: case 26: return (MatSoundType)1; case 0: case 1: case 13: case 14: case 15: return (MatSoundType)4; case 9: case 10: case 16: case 20: case 21: return (MatSoundType)3; case 12: return (MatSoundType)8; case 23: return (MatSoundType)9; case 11: case 22: return (MatSoundType)2; default: return (MatSoundType)0; } } private static void PlayPooled(AudioClip clip, Vector3 pos, float volume, float pitch) { //IL_006a: Unknown result type (might be due to invalid IL or missing references) if (_pool == null) { CreatePool(); } AudioSource val = _pool[_poolIndex]; _poolIndex = (_poolIndex + 1) % _pool.Length; if ((Object)(object)val == (Object)null) { CreatePool(); val = _pool[_poolIndex]; _poolIndex = (_poolIndex + 1) % _pool.Length; if ((Object)(object)val == (Object)null) { return; } } ((Component)val).transform.position = pos; val.volume = volume; val.pitch = pitch; val.PlayOneShot(clip); } private static void CreatePool() { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown _pool = (AudioSource[])(object)new AudioSource[8]; if (!((Object)(object)H3MPFootstepPlugin.Instance == (Object)null)) { GameObject val = new GameObject("H3MPFootstep_AudioPool"); Object.DontDestroyOnLoad((Object)(object)val); for (int i = 0; i < 8; i++) { AudioSource val2 = val.AddComponent(); val2.playOnAwake = false; val2.spatialBlend = 1f; val2.dopplerLevel = 0f; val2.loop = false; val2.rolloffMode = (AudioRolloffMode)1; val2.maxDistance = 60f; val2.minDistance = 1f; _pool[i] = val2; } } } private static IEnumerator LoadClip(string path, Action onDone) { AudioClip clip = null; UnityWebRequest www; try { www = UnityWebRequest.GetAudioClip(path, (AudioType)20); } catch (Exception ex) { H3MPFootstepPlugin.Log.LogWarning((object)("Failed to load " + path + ": " + ex.Message)); onDone?.Invoke(null); yield break; } yield return www.Send(); if (!www.isError) { clip = DownloadHandlerAudioClip.GetContent(www); } else { H3MPFootstepPlugin.Log.LogWarning((object)("Failed to load " + path + ": " + www.error)); } www.Dispose(); onDone?.Invoke(clip); } } public class FootstepLocalController : MonoBehaviour { private const float TeleportDist = 3f; private const float MaxSprintSpeed = 6.5f; private const float CrouchNeckHeight = 1.1f; private Vector3 _lastPos; private bool _hasLastPos; private float _accumulatedDist; private float _lastStepRealTime; private bool _nextFootIsLeft = true; private float _suppressUntil; private void Update() { //IL_0026: 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_0049: 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_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_0057: 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_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) //IL_012c: 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) //IL_013b: 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) FVRPlayerBody currentPlayerBody = GM.CurrentPlayerBody; if ((Object)(object)currentPlayerBody == (Object)null || (Object)(object)currentPlayerBody.NeckJointTransform == (Object)null) { _hasLastPos = false; return; } Vector3 headPositionFiltered = currentPlayerBody.headPositionFiltered; float time = Time.time; if (!_hasLastPos) { _lastPos = headPositionFiltered; _hasLastPos = true; return; } Vector3 val = headPositionFiltered - _lastPos; _lastPos = headPositionFiltered; if (((Vector3)(ref val)).magnitude > 3f) { _accumulatedDist = 0f; _suppressUntil = time + 0.4f; } else { if (time < _suppressUntil) { return; } val.y = 0f; float magnitude = ((Vector3)(ref val)).magnitude; float num = Mathf.Max(Time.deltaTime, 0.0001f); float num2 = magnitude / num; if (num2 < H3MPFootstepPlugin.Instance.ConfigMinStepSpeed.Value) { _accumulatedDist = Mathf.Max(0f, _accumulatedDist - magnitude); return; } _accumulatedDist += magnitude; float num3 = ComputeStepLength(num2); if (_accumulatedDist >= num3 && time - _lastStepRealTime >= MinInterval()) { _accumulatedDist = 0f; _lastStepRealTime = time; if (H3MPFootstepPlugin.ProbeFloor(headPositionFiltered, out var mat, out var floorPos)) { FireStep(headPositionFiltered, floorPos, mat, num2); } } } } private static float MinInterval() { return Mathf.Max(0.15f, H3MPFootstepPlugin.Instance.ConfigSprintStepInterval.Value * 0.8f); } private float ComputeStepLength(float speed) { //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_0030: 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_0044: Unknown result type (might be due to invalid IL or missing references) _ = H3MPFootstepPlugin.Instance; float num = Mathf.Clamp01(speed / 6.5f); float num2 = Mathf.Lerp(0.85f, 1.05f, num); Vector3 headPositionFiltered = GM.CurrentPlayerBody.headPositionFiltered; if (H3MPFootstepPlugin.ProbeFloor(headPositionFiltered, out var _, out var floorPos) && headPositionFiltered.y - floorPos.y < 1.1f) { num2 *= 0.65f; } return num2; } private void FireStep(Vector3 neckPos, Vector3 floorPos, BulletImpactSoundType mat, float speed) { //IL_0039: 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_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: 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) H3MPFootstepPlugin instance = H3MPFootstepPlugin.Instance; float num = Mathf.Clamp01(speed / 6.5f); float value = instance.ConfigBaseLoudness.Value; value *= Mathf.Lerp(1f, instance.ConfigSprintLoudnessMult.Value, num); bool flag = neckPos.y - floorPos.y < 1.1f; if (flag) { value *= instance.ConfigCrouchLoudnessMult.Value; } float num2 = (_nextFootIsLeft ? 0.96f : 1.04f); _nextFootIsLeft = !_nextFootIsLeft; float num3 = value * num2; float pitch = Random.Range(0.9f, 1.1f); if (instance.ConfigPlayLocalFootsteps.Value) { FootstepAudioBank.Play(mat, floorPos, num3 * 0.8f, pitch, (AudioImpactIntensity)((num > 0.66f) ? 2 : ((num > 0.25f) ? 1 : 0)), instance.ConfigMaxHearingDistance.Value); } if (FootstepNet.IsNetworkReady()) { FootstepNet.SendFootstep(floorPos, mat, num3, speed, flag); } H3MPFootstepPlugin.LogDebug($"[local] step: mat={mat} loud={num3:F2} speed={speed:F2} crouch={flag} net={FootstepNet.IsNetworkReady()}"); } } public class FootstepNet : MonoBehaviour { [CompilerGenerated] private static class <>O { public static CustomPacketHandlerReceivedDelegate <0>__OnCustomPacketHandlerReceived; public static CustomPacketHandler <1>__OnFootstepPacketReceived; } private const byte ProtocolVersion = 1; private const string PacketID = "Niko666.H3MPFootstep.Footstep"; private const byte FlagCrouched = 1; private static FootstepNet _instance; private static int _footstepPacketID = -1; private static bool _awaitingRegistrationResponse; private static float _registrationRequestTime; private const float RegistrationRetryDelay = 5f; private static readonly Dictionary _remotes = new Dictionary(); private static bool IsHost => ThreadManager.host; private void Awake() { _instance = this; } private void OnDestroy() { if ((Object)(object)_instance == (Object)(object)this) { _instance = null; } } public static bool IsNetworkReady() { return (Object)(object)Mod.managerObject != (Object)null; } private void Update() { //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_003d: Expected O, but got Unknown if (!IsNetworkReady()) { if (_footstepPacketID >= 0 || _awaitingRegistrationResponse) { _footstepPacketID = -1; _awaitingRegistrationResponse = false; object obj = <>O.<0>__OnCustomPacketHandlerReceived; if (obj == null) { CustomPacketHandlerReceivedDelegate val = OnCustomPacketHandlerReceived; <>O.<0>__OnCustomPacketHandlerReceived = val; obj = (object)val; } Mod.CustomPacketHandlerReceived -= (CustomPacketHandlerReceivedDelegate)obj; } } else { TryRegisterPacket(); PruneStaleRemotes(); } } private static void TryRegisterPacket() { //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Expected O, but got Unknown //IL_00fb: 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: Expected O, but got Unknown if (_footstepPacketID >= 0) { return; } if (Mod.registeredCustomPacketIDs.TryGetValue("Niko666.H3MPFootstep.Footstep", out var value)) { _footstepPacketID = value; HookHandler(value); H3MPFootstepPlugin.Log.LogInfo((object)$"Footstep packet already registered as index {value}."); return; } if (_awaitingRegistrationResponse) { if (Time.time - _registrationRequestTime < 5f) { return; } _awaitingRegistrationResponse = false; H3MPFootstepPlugin.Log.LogWarning((object)"Footstep packet registration timed out - retrying."); } if (IsHost) { _footstepPacketID = Server.RegisterCustomPacketType("Niko666.H3MPFootstep.Footstep", 0); HookHandler(_footstepPacketID); H3MPFootstepPlugin.Log.LogInfo((object)$"Host registered footstep packet as index {_footstepPacketID}."); } else if ((Object)(object)Client.singleton != (Object)null && Client.singleton.isConnected) { object obj = <>O.<0>__OnCustomPacketHandlerReceived; if (obj == null) { CustomPacketHandlerReceivedDelegate val = OnCustomPacketHandlerReceived; <>O.<0>__OnCustomPacketHandlerReceived = val; obj = (object)val; } Mod.CustomPacketHandlerReceived -= (CustomPacketHandlerReceivedDelegate)obj; object obj2 = <>O.<0>__OnCustomPacketHandlerReceived; if (obj2 == null) { CustomPacketHandlerReceivedDelegate val2 = OnCustomPacketHandlerReceived; <>O.<0>__OnCustomPacketHandlerReceived = val2; obj2 = (object)val2; } Mod.CustomPacketHandlerReceived += (CustomPacketHandlerReceivedDelegate)obj2; ClientSend.RegisterCustomPacketType("Niko666.H3MPFootstep.Footstep"); _awaitingRegistrationResponse = true; _registrationRequestTime = Time.time; H3MPFootstepPlugin.Log.LogInfo((object)"Requested footstep packet registration from server."); } } private static void OnCustomPacketHandlerReceived(string id, int index) { if (!(id != "Niko666.H3MPFootstep.Footstep")) { _footstepPacketID = index; HookHandler(index); H3MPFootstepPlugin.Log.LogInfo((object)$"Server assigned footstep packet index {index}."); } } private static void HookHandler(int index) { //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_002f: Expected O, but got Unknown if (index >= 0 && index < Mod.customPacketHandlers.Length) { CustomPacketHandler[] customPacketHandlers = Mod.customPacketHandlers; object obj = <>O.<1>__OnFootstepPacketReceived; if (obj == null) { CustomPacketHandler val = OnFootstepPacketReceived; <>O.<1>__OnFootstepPacketReceived = val; obj = (object)val; } customPacketHandlers[index] = (CustomPacketHandler)obj; } } public static void SendFootstep(Vector3 footPos, BulletImpactSoundType mat, float loudness, float speed, bool crouched) { //IL_00e8: 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_00b1: 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) if (!IsNetworkReady() || _footstepPacketID < 0) { return; } if (IsHost) { List list = new List(); foreach (KeyValuePair player in GameManager.players) { if (player.Key != GameManager.ID && !((Object)(object)player.Value == (Object)null) && !(player.Value.scene != GameManager.scene) && player.Value.instance == GameManager.instance) { list.Add(player.Key); } } if (list.Count > 0) { SendDirectToClients(BuildPacket(GameManager.ID, mat, loudness, speed, footPos, crouched), list); H3MPFootstepPlugin.LogDebug($"[net] host sent footstep to {list.Count} clients (loud {loudness:F2})"); } } else { Packet val = BuildPacket(GameManager.ID, mat, loudness, speed, footPos, crouched); try { ClientSend.SendUDPData(val, true); } finally { ((IDisposable)val)?.Dispose(); } H3MPFootstepPlugin.LogDebug("[net] client sent footstep to server"); } } private static Packet BuildPacket(int senderID, BulletImpactSoundType mat, float loudness, float speed, Vector3 footPos, bool crouched) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0011: 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_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0033: 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_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown Packet val = new Packet(_footstepPacketID); val.Write((byte)1); val.Write(senderID); val.Write(crouched ? ((byte)1) : ((byte)0)); val.Write(loudness); val.Write(speed); val.Write((byte)mat); val.Write(footPos); return val; } private static void OnFootstepPacketReceived(int clientID, Packet packet) { //IL_003a: 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_004b: 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_0076: 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) try { if (packet.ReadByte(true) != 1) { return; } int num = packet.ReadInt(true); byte b = packet.ReadByte(true); float loudness = packet.ReadFloat(true); float speed = packet.ReadFloat(true); byte b2 = packet.ReadByte(true); Vector3 footPos = packet.ReadVector3(true); if (b2 > 28) { return; } BulletImpactSoundType mat = (BulletImpactSoundType)b2; int num2 = (IsHost ? clientID : num); bool crouched = (b & 1) != 0; if (num2 != GameManager.ID) { if (IsHost) { RelayToOthers(num2, mat, loudness, speed, footPos, crouched); } PlayRemoteFootstep(num2, footPos, mat, loudness, speed, crouched); } } catch (Exception ex) { H3MPFootstepPlugin.Log.LogWarning((object)$"Bad footstep packet from {clientID}: {ex.Message}"); } } private static void RelayToOthers(int senderID, BulletImpactSoundType mat, float loudness, float speed, Vector3 footPos, bool crouched) { //IL_0098: 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) if (_footstepPacketID < 0) { return; } List list = new List(); foreach (KeyValuePair player in GameManager.players) { if (player.Key != senderID && !((Object)(object)player.Value == (Object)null) && !(player.Value.scene != GameManager.scene) && player.Value.instance == GameManager.instance) { list.Add(player.Key); } } if (list.Count != 0) { Packet val = BuildPacket(senderID, mat, loudness, speed, footPos, crouched); try { SendDirectToClients(val, list); } finally { ((IDisposable)val)?.Dispose(); } H3MPFootstepPlugin.LogDebug($"[net] host relayed footstep from {senderID} to {list.Count} clients"); } } private static void SendDirectToClients(Packet packet, List clientIDs) { byte[] bytes = BitConverter.GetBytes(BitConverter.ToInt32(new byte[4] { packet.buffer[0], packet.buffer[1], packet.buffer[2], packet.buffer[3] }, 0) * -1 - 2); for (int i = 0; i < 4; i++) { packet.buffer[i] = bytes[i]; } packet.WriteLength(); foreach (int clientID in clientIDs) { if (Server.clients.TryGetValue(clientID, out var value) && value != null && value.udp != null) { Server.SendUDPData(value.udp.endPoint, packet); } } } private static void PlayRemoteFootstep(int clientID, Vector3 footPos, BulletImpactSoundType mat, float loudness, float speed, bool crouched) { //IL_0053: 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_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: 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_00ab: Unknown result type (might be due to invalid IL or missing references) if (loudness <= 0.01f) { return; } float time = Time.time; if (_remotes.TryGetValue(clientID, out var value) && time - value < 0.15f) { return; } _remotes[clientID] = time; FVRPlayerBody currentPlayerBody = GM.CurrentPlayerBody; if ((Object)(object)currentPlayerBody == (Object)null || (Object)(object)currentPlayerBody.Head == (Object)null) { return; } float num = Vector3.Distance(footPos, currentPlayerBody.Head.position); float value2 = H3MPFootstepPlugin.Instance.ConfigMaxHearingDistance.Value; if (!(num > value2)) { float num2 = Mathf.Clamp01(speed / 4.5f); AudioImpactIntensity intensity = (AudioImpactIntensity)((num2 > 0.66f) ? 2 : ((num2 > 0.25f) ? 1 : 0)); if (crouched) { intensity = (AudioImpactIntensity)0; } float pitch = Random.Range(0.92f, 1.1f); float num3 = loudness * H3MPFootstepPlugin.Instance.ConfigMasterVolume.Value * Random.Range(0.9f, 1.1f); FootstepAudioBank.Play(mat, footPos, num3, pitch, intensity, value2); H3MPFootstepPlugin.LogDebug($"[remote {clientID}] play: mat={mat} vol={num3:F2} dist={num:F1}"); } } private static void PruneStaleRemotes() { if (_remotes.Count == 0) { return; } List list = null; foreach (KeyValuePair remote in _remotes) { if (!GameManager.players.ContainsKey(remote.Key)) { if (list == null) { list = new List(); } list.Add(remote.Key); } } if (list == null) { return; } foreach (int item in list) { _remotes.Remove(item); } } } public class FootstepSceneWatcher : MonoBehaviour { private void OnEnable() { SceneManager.sceneLoaded += OnSceneLoaded; } private void OnDisable() { SceneManager.sceneLoaded -= OnSceneLoaded; } private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { H3MPFootstepPlugin.Log.LogInfo((object)("Scene '" + ((Scene)(ref scene)).name + "' loaded - footstep net standing by.")); } } [BepInProcess("h3vr.exe")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInPlugin("Niko666.H3MPFootstep", "H3MP Footsteps", "0.3.0")] public class H3MPFootstepPlugin : BaseUnityPlugin { internal static ManualLogSource Log; internal static H3MPFootstepPlugin Instance; internal ConfigEntry ConfigMasterVolume; internal ConfigEntry ConfigBaseLoudness; internal ConfigEntry ConfigSprintLoudnessMult; internal ConfigEntry ConfigCrouchLoudnessMult; internal ConfigEntry ConfigSpeedStepInterval; internal ConfigEntry ConfigSprintStepInterval; internal ConfigEntry ConfigMinStepSpeed; internal ConfigEntry ConfigMaxHearingDistance; internal ConfigEntry ConfigPlayLocalFootsteps; internal ConfigEntry ConfigCustomAudio; internal ConfigEntry ConfigDebugLogging; private GameObject _managerObj; private FootstepLocalController _localController; public const string Id = "Niko666.H3MPFootstep"; public static string Name => "H3MP Footsteps"; public static string Version => "0.3.0"; private void Awake() { Instance = this; Log = ((BaseUnityPlugin)this).Logger; BindConfigs(); Harmony.CreateAndPatchAll(typeof(ReloadConfigPatch), (string)null); Log.LogMessage((object)string.Format("{0} {1} loaded. H3MP present: {2}", "Niko666.H3MPFootstep", Version, IsH3MPAvailable())); } private void BindConfigs() { ConfigMasterVolume = ((BaseUnityPlugin)this).Config.Bind("General", "MasterVolume", 1f, "Master volume multiplier for remote players' footstep sounds."); ConfigBaseLoudness = ((BaseUnityPlugin)this).Config.Bind("General", "BaseLoudness", 1f, "Base loudness of a walking footstep."); ConfigSprintLoudnessMult = ((BaseUnityPlugin)this).Config.Bind("General", "SprintLoudnessMult", 2f, "Loudness multiplier when the remote player is sprinting."); ConfigCrouchLoudnessMult = ((BaseUnityPlugin)this).Config.Bind("General", "CrouchLoudnessMult", 0.05f, "Loudness multiplier when the remote player is crouched (slow movement)."); ConfigSpeedStepInterval = ((BaseUnityPlugin)this).Config.Bind("Cadence", "WalkStepInterval", 0.65f, "Seconds between footsteps at normal walking speed."); ConfigSprintStepInterval = ((BaseUnityPlugin)this).Config.Bind("Cadence", "SprintStepInterval", 0.35f, "Seconds between footsteps when sprinting."); ConfigMinStepSpeed = ((BaseUnityPlugin)this).Config.Bind("Cadence", "MinStepSpeed", 0.5f, "Minimum horizontal speed (m/s) for footsteps to trigger. Lower = more sensitive."); ConfigMaxHearingDistance = ((BaseUnityPlugin)this).Config.Bind("General", "MaxHearingDistance", 60f, "Max distance (m) at which remote footsteps can be heard."); ConfigPlayLocalFootsteps = ((BaseUnityPlugin)this).Config.Bind("General", "PlayLocalFootsteps", true, "Play your own footsteps (local, non-networked). When enabled this Mod also works as a standalone footstep mod without H3MP."); ConfigCustomAudio = ((BaseUnityPlugin)this).Config.Bind("General", "CustomAudio", true, "Use custom footstep wavs (Kodeman PlayerFootsteps compatible packs). When disabled, remote footsteps fall back to H3VR's built-in impact sounds."); ConfigDebugLogging = ((BaseUnityPlugin)this).Config.Bind("Debug", "DebugLogging", false, "Print verbose footstep network logs."); } private void Start() { FootstepAudioBank.StartLoad(); TryWireManager(); } private bool IsH3MPAvailable() { return Chainloader.PluginInfos.ContainsKey("VIP.TommySoucy.H3MP"); } private void TryWireManager() { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected O, but got Unknown if (!((Object)(object)_managerObj != (Object)null)) { _managerObj = new GameObject("H3MPFootstep_Manager"); Object.DontDestroyOnLoad((Object)(object)_managerObj); _localController = _managerObj.AddComponent(); _managerObj.AddComponent(); if (IsH3MPAvailable()) { _managerObj.AddComponent(); Log.LogMessage((object)"H3MPFootstep manager created (networked). Monitoring player movement."); } else { Log.LogWarning((object)"H3MP (VIP.TommySoucy.H3MP) not found - remote footstep sync disabled. Local footsteps still work; install H3MP on all clients to enable multiplayer sync."); } } } private void Update() { if ((Object)(object)_managerObj == (Object)null) { TryWireManager(); } } internal static bool ProbeFloor(Vector3 fromNeck, out BulletImpactSoundType mat, out Vector3 floorPos) { //IL_0004: 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_0011: 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_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Expected I4, but got Unknown //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Expected I4, but got Unknown mat = (BulletImpactSoundType)5; floorPos = default(Vector3); int num = 528384; RaycastHit val = default(RaycastHit); if (Physics.Raycast(fromNeck, Vector3.down, ref val, 2.2f, num, (QueryTriggerInteraction)1)) { floorPos = ((RaycastHit)(ref val)).point; PMat val2 = ((Component)((RaycastHit)(ref val)).collider).GetComponent(); if ((Object)(object)val2 == (Object)null) { val2 = ((Component)((RaycastHit)(ref val)).collider).GetComponentInParent(); } if ((Object)(object)val2 != (Object)null && (Object)(object)val2.MatDef != (Object)null) { mat = (BulletImpactSoundType)(int)val2.MatDef.BulletImpactSound; } else { MatDef matDef_Default = ManagerSingleton.Instance.MatDef_Default; if ((Object)(object)matDef_Default != (Object)null) { mat = (BulletImpactSoundType)(int)matDef_Default.BulletImpactSound; } } return true; } return false; } internal static void LogDebug(string msg) { if ((Object)(object)Instance != (Object)null && Instance.ConfigDebugLogging.Value) { Log.LogInfo((object)msg); } } } internal static class ReloadConfigPatch { [HarmonyPatch(typeof(SteamVR_LoadLevel), "Begin")] [HarmonyPrefix] public static bool BeginPatch() { ((BaseUnityPlugin)H3MPFootstepPlugin.Instance).Config.Reload(); H3MPFootstepPlugin.LogDebug("Configuration reloaded."); return true; } } }