Decompiled source of PlayerFootsteps v1.1.1

PlayerFootsteps.dll

Decompiled 2 months ago
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;
	}
}