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.InteropServices;
using BepInEx;
using BepInEx.Configuration;
using FistVR;
using UnityEngine;
using UnityEngine.Networking;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("PlayerFootsteps")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("PlayerFootsteps")]
[assembly: AssemblyCopyright("Copyright © 2023")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("9FB99B0D-2F7F-426A-A05F-592AF5914A01")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace PlayerFootsteps;
public class AudioData
{
public string Name;
public List<AudioClip> Clips;
}
[BepInPlugin("h3vr.kodeman.playerfootsteps", "Player Footsteps", "1.1.1")]
[BepInProcess("h3vr.exe")]
public class PlayerFootsteps : BaseUnityPlugin
{
private ConfigEntry<bool> AIDetectsSounds;
private ConfigEntry<bool> MeatyFeet;
private ConfigEntry<bool> QuietWalking;
private ConfigEntry<float> AIDetectionSoundsMultiplier;
private ConfigEntry<float> PlayerHeight;
private ConfigEntry<float> PlayerCrouchHeight;
private ConfigEntry<float> SoundVolume;
private ConfigEntry<float> QuietWalkingSpeed;
private List<AudioData> _audioClips = new List<AudioData>();
private Vector3 _lastPlayerPos;
private AudioSource _audioSource;
private bool _initialized;
private float _lastHitDistFromHead;
private float _stepTimer;
private Sosig _sosigPrefab;
private MethodInfo _soundMethod;
private bool _usesOldSoundMethod;
private void Awake()
{
_audioSource = ((Component)this).gameObject.AddComponent<AudioSource>();
_audioSource.dopplerLevel = 0f;
_audioSource.playOnAwake = false;
Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject);
AIDetectsSounds = ((BaseUnityPlugin)this).Config.Bind<bool>("FootstepsSounds", "AIDetectsSounds", true, "If enabled, AI will detect player footsteps based on ground material and the player speed.");
MeatyFeet = ((BaseUnityPlugin)this).Config.Bind<bool>("FootstepsSounds", "MeatyFeet", false, "If enabled, replaces footsteps sounds with meaty footstep sounds.");
AIDetectionSoundsMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("FootstepsSounds", "AIDetectionSoundsMultiplier", 1f, "Multiplier for AI detection range based on player speed.");
PlayerHeight = ((BaseUnityPlugin)this).Config.Bind<float>("FootstepsSounds", "PlayerHeight", 1.8f, "Player height in meters. If head is higher than this value, the player is considered flying and will not produce footsteps sounds.");
PlayerCrouchHeight = ((BaseUnityPlugin)this).Config.Bind<float>("FootstepsSounds", "PlayerCrouchHeight", 1.25f, "If player head is lower than this value, the player is considered crouching and will not be detected by AI.");
SoundVolume = ((BaseUnityPlugin)this).Config.Bind<float>("FootstepsSounds", "SoundVolume", 1f, "Volume of footsteps sounds. Value range is 0-1");
QuietWalking = ((BaseUnityPlugin)this).Config.Bind<bool>("FootstepsSounds", "QuietWalking", false, "If enabled, player will not alert sosigs when walking slowly without crouching.");
QuietWalkingSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("FootstepsSounds", "QuietWalkingSpeed", 2f, "If QuietWalking is enabled, walking slower than this value will not alert sosigs.");
SoundVolume.Value = Mathf.Clamp(SoundVolume.Value, 0f, 1f);
((BaseUnityPlugin)this).Logger.LogInfo((object)"Player Footsteps mod loaded");
}
private IEnumerator Start()
{
yield return (object)new WaitForSeconds(1f);
_lastPlayerPos = ((Component)GM.CurrentPlayerBody.Head).transform.position;
LoadAllAudioClips();
if (MeatyFeet.Value)
{
_sosigPrefab = ((AnvilAsset)ManagerSingleton<IM>.Instance.odicSosigObjsByID[(SosigEnemyID)108].SosigPrefabs[0]).GetGameObject().GetComponent<Sosig>();
}
_soundMethod = LoadSoundFunction();
_initialized = true;
}
private void Update()
{
//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)
//IL_008a: Unknown result type (might be due to invalid IL or missing references)
//IL_008f: 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)
//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
//IL_00b6: 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)
//IL_00ca: 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_0133: Unknown result type (might be due to invalid IL or missing references)
//IL_0136: Unknown result type (might be due to invalid IL or missing references)
if (!_initialized)
{
return;
}
_stepTimer += Time.deltaTime;
if (_stepTimer < 0.23f || (MeatyFeet.Value && (double)_stepTimer < 0.3))
{
return;
}
Vector3 position = ((Component)GM.CurrentPlayerBody.Head).transform.position;
position.y = 0f;
Vector3 lastPlayerPos = _lastPlayerPos;
lastPlayerPos.y = 0f;
if (!(Vector3.Distance(lastPlayerPos, position) > 1f))
{
return;
}
_lastPlayerPos = position;
RaycastHit val = default(RaycastHit);
if (Physics.Raycast(GM.CurrentPlayerBody.Head.position, Vector3.down, ref val, PlayerHeight.Value, 528384))
{
_stepTimer = 0f;
_lastHitDistFromHead = ((RaycastHit)(ref val)).distance;
if (Object.op_Implicit((Object)(object)((Component)((RaycastHit)(ref val)).collider).GetComponent<PMat>()))
{
BulletImpactSoundType bulletImpactSound = ((Component)((RaycastHit)(ref val)).collider).GetComponent<PMat>().MatDef.BulletImpactSound;
PlayFootstepSound(bulletImpactSound);
}
else
{
PlayFootstepSound((BulletImpactSoundType)5, noPMat: true);
}
}
}
private void PlayFootstepSound(BulletImpactSoundType soundType, bool noPMat = false)
{
//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
//IL_01ac: 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_01b0: Unknown result type (might be due to invalid IL or missing references)
//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
//IL_022d: Expected I4, but got Unknown
float topSpeedInLastSecond = GM.CurrentMovementManager.GetTopSpeedInLastSecond();
float num = RemapClamped(topSpeedInLastSecond, 3f, 7f, 0f, 0.35f);
float num2 = Random.Range(0.5f, 0.7f) + num;
float pitch = Random.Range(0.75f, 1.15f);
if (topSpeedInLastSecond > 4.25f)
{
num2 = 1f;
}
bool flag = QuietWalking.Value && topSpeedInLastSecond < QuietWalkingSpeed.Value;
if (_lastHitDistFromHead <= PlayerCrouchHeight.Value)
{
num2 -= 0.4f;
}
else if (flag)
{
num2 -= 0.25f;
}
num2 *= SoundVolume.Value;
_audioSource.volume = num2;
_audioSource.pitch = pitch;
HandleAIDetection();
if (MeatyFeet.Value)
{
_audioSource.pitch = Random.Range(0.95f, 1.05f);
AudioSource audioSource = _audioSource;
audioSource.volume *= 0.6f;
int index = Random.Range(0, _sosigPrefab.AudEvent_FootSteps.Clips.Count);
_audioSource.PlayOneShot(_sosigPrefab.AudEvent_FootSteps.Clips[index]);
return;
}
if (noPMat && Object.op_Implicit((Object)(object)GM.TNH_Manager) && GM.TNH_Manager.LevelName == "NorthestDakota")
{
PlayAudio("SnowNorthestDakota");
return;
}
switch ((int)soundType)
{
case 10:
PlayAudio("Grass");
break;
case 25:
PlayAudio("WoodHeavy");
break;
case 26:
case 27:
PlayAudio("WoodLight");
break;
case 11:
PlayAudio("Gravel");
break;
case 17:
PlayAudio("Mud");
break;
case 13:
PlayAudio("Meat");
break;
case 24:
PlayAudio("Water");
break;
case 23:
PlayAudio("SoftMaterial");
break;
case 21:
case 22:
PlayAudio("Sand");
break;
case 15:
PlayAudio("MetalThick");
break;
case 1:
case 2:
case 14:
case 16:
PlayAudio("MetalThin");
break;
case 3:
PlayAudio("Brick");
break;
case 20:
PlayAudio("Rock");
break;
case 12:
PlayAudio("Ice");
break;
case 6:
case 7:
case 8:
case 9:
PlayAudio("Glass");
break;
case 0:
break;
case 4:
PlayAudio("Concrete");
break;
default:
PlayAudio("Generic");
break;
}
}
private void PlayAudio(string clipName)
{
AudioClip randomAudio = GetRandomAudio(clipName);
_audioSource.PlayOneShot(randomAudio);
}
private AudioClip GetRandomAudio(string clipName)
{
for (int i = 0; i < _audioClips.Count; i++)
{
if (_audioClips[i].Name == clipName)
{
int index = Random.Range(0, _audioClips[i].Clips.Count);
return _audioClips[i].Clips[index];
}
}
throw new Exception("Audio clip " + clipName + " not found");
}
private void HandleAIDetection()
{
//IL_006d: 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_0159: Unknown result type (might be due to invalid IL or missing references)
//IL_010e: Unknown result type (might be due to invalid IL or missing references)
if (!AIDetectsSounds.Value)
{
return;
}
float topSpeedInLastSecond = GM.CurrentMovementManager.GetTopSpeedInLastSecond();
bool flag = topSpeedInLastSecond > 4.25f;
bool flag2 = _lastHitDistFromHead <= 1.25f;
bool flag3 = QuietWalking.Value && topSpeedInLastSecond < QuietWalkingSpeed.Value;
Vector3 position = ((Component)GM.CurrentPlayerBody.Head).transform.position;
int playerIFF = GM.CurrentPlayerBody.GetPlayerIFF();
float num = 5f;
if (flag && !flag2)
{
num = 10f;
}
num *= AIDetectionSoundsMultiplier.Value;
if ((!flag2 || flag) && !flag3 && Object.op_Implicit((Object)(object)GM.CurrentAIManager))
{
if (_usesOldSoundMethod)
{
_soundMethod.Invoke(GM.CurrentSceneSettings, new object[4]
{
GM.CurrentSceneSettings.BaseLoudness,
num,
position,
playerIFF
});
}
else
{
_soundMethod.Invoke(GM.CurrentSceneSettings, new object[5]
{
GM.CurrentSceneSettings.BaseLoudness,
num,
position,
playerIFF,
GM.CurrentPlayerBody.PlayerEntities[0]
});
}
}
}
private MethodInfo LoadSoundFunction()
{
MethodInfo method = ((object)GM.CurrentSceneSettings).GetType().GetMethod("OnPerceiveableSound", new Type[5]
{
typeof(float),
typeof(float),
typeof(Vector3),
typeof(int),
typeof(AIEntity)
});
if ((object)method == null)
{
method = ((object)GM.CurrentSceneSettings).GetType().GetMethod("OnPerceiveableSound", new Type[4]
{
typeof(float),
typeof(float),
typeof(Vector3),
typeof(int)
});
_usesOldSoundMethod = true;
}
return method;
}
private void LoadAllAudioClips()
{
_audioClips.Clear();
string[] array = new string[18]
{
"Concrete", "Generic", "Grass", "Gravel", "MetalThick", "MetalThin", "Mud", "Meat", "SoftMaterial", "Water",
"WoodHeavy", "WoodLight", "Sand", "Brick", "Rock", "Ice", "Glass", "SnowNorthestDakota"
};
string text = Paths.PluginPath + "\\Kodeman-PlayerFootsteps\\";
string pluginPath = Paths.PluginPath;
string[] array2 = array;
foreach (string text2 in array2)
{
List<string> list = Directory.GetFiles(pluginPath, "PlayerFootsteps_" + text2 + "*.wav", SearchOption.AllDirectories).ToList();
AudioData audioData = new AudioData
{
Name = text2,
Clips = new List<AudioClip>()
};
if (list.Count > 0)
{
for (int j = 0; j < list.Count; j++)
{
string text3 = $"{list[j]}{j}.wav";
((MonoBehaviour)this).StartCoroutine(LoadAudioClip(list[j], audioData));
}
}
else
{
string text4 = text2 + ".wav";
((MonoBehaviour)this).StartCoroutine(LoadAudioClip(text + text4, audioData));
}
_audioClips.Add(audioData);
}
}
private IEnumerator LoadAudioClip(string path, AudioData data)
{
UnityWebRequest www = UnityWebRequest.GetAudioClip(path, (AudioType)20);
try
{
yield return www.Send();
if (www.isError)
{
Debug.Log((object)("There was an error loading the audio clip for path: " + path + " \n " + www.error));
}
else
{
data.Clips.Add(DownloadHandlerAudioClip.GetContent(www));
}
}
finally
{
((IDisposable)www)?.Dispose();
}
}
private float RemapClamped(float aValue, float aIn1, float aIn2, float aOut1, float aOut2)
{
float num = (aValue - aIn1) / (aIn2 - aIn1);
if (num > 1f)
{
return aOut2;
}
if (num < 0f)
{
return aOut1;
}
return aOut1 + (aOut2 - aOut1) * num;
}
}