Decompiled source of CombatSounds v1.0.1

BepInEx/plugins/CombatSounds/CombatSounds.dll

Decompiled 6 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ComputerysModdingUtilities;
using HarmonyLib;
using UnityEngine;
using UnityEngine.Networking;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("CombatSounds")]
[assembly: AssemblyDescription("STRAFTAT: pick your own hit, head hit and kill sounds, client-side.")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: StraftatMod(true)]
[assembly: AssemblyVersion("1.0.1.0")]
namespace CombatSounds;

[BepInPlugin("dorsth.straftat.combatsounds", "CombatSounds", "1.0.1")]
public sealed class CombatSoundsPlugin : BaseUnityPlugin
{
	public const string Guid = "dorsth.straftat.combatsounds";

	public const string Name = "CombatSounds";

	public const string Version = "1.0.1";

	internal static ManualLogSource Log;

	internal static SoundSlot Hit;

	internal static SoundSlot HeadHit;

	internal static SoundSlot Kill;

	private void Awake()
	{
		//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fe: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		Log.LogMessage((object)"Dorsth was here");
		string text = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location);
		if (string.Equals(Path.GetFullPath(text).TrimEnd('\\', '/'), Path.GetFullPath(Paths.PluginPath).TrimEnd('\\', '/'), StringComparison.OrdinalIgnoreCase))
		{
			text = Path.Combine(text, "CombatSounds");
		}
		Hit = new SoundSlot(((BaseUnityPlugin)this).Config, "Hit Sound", Path.Combine(text, "HitSounds"), "Sound when you hit a player.");
		HeadHit = new SoundSlot(((BaseUnityPlugin)this).Config, "Head Hit Sound", Path.Combine(text, "HeadHitSounds"), "Sound when you hit a player in the head. Same as Hit = your hit sound, at this volume.", Hit);
		Kill = new SoundSlot(((BaseUnityPlugin)this).Config, "Kill Sound", Path.Combine(text, "KillSounds"), "Sound when you kill a player. Plays on top of the hit sound.");
		try
		{
			Hooks.Install(new Harmony("dorsth.straftat.combatsounds"));
		}
		catch (Exception ex)
		{
			Log.LogError((object)("Couldn't hook the game's hit sounds, so the mod is off. (" + ex.Message + ")"));
		}
	}
}
internal sealed class SoundSlot
{
	private const string Default = "Default";

	private const string None = "None";

	private const string SameAsHit = "Same as Hit";

	private static GameObject _speaker;

	private readonly ConfigEntry<string> _choice;

	private readonly ConfigEntry<int> _volume;

	private readonly Dictionary<string, string> _files = new Dictionary<string, string>();

	private readonly string _name;

	private readonly SoundSlot _hit;

	private AudioSource _source;

	private AudioClip _clip;

	private AudioClip _louder;

	private AudioClip _louderOf;

	private string _sound;

	private bool _none;

	private bool _following;

	private int _loadId;

	private int _louderVolume;

	private float _nextPreview;

	private SoundSlot Pick
	{
		get
		{
			if (!_following)
			{
				return this;
			}
			return _hit;
		}
	}

	internal bool ReplacesGameSound
	{
		get
		{
			SoundSlot pick = Pick;
			if (!((Object)(object)pick._clip != (Object)null))
			{
				return pick._none;
			}
			return true;
		}
	}

	internal bool HasSound => (Object)(object)Pick._clip != (Object)null;

	internal SoundSlot(ConfigFile config, string name, string folder, string description, SoundSlot hit = null)
	{
		//IL_0189: Unknown result type (might be due to invalid IL or missing references)
		//IL_0193: Expected O, but got Unknown
		//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
		//IL_01db: Expected O, but got Unknown
		_name = name;
		_hit = hit;
		List<string> list = new List<string>
		{
			(hit != null) ? "Same as Hit" : "Default",
			"None"
		};
		try
		{
			Directory.CreateDirectory(folder);
			string[] files = Directory.GetFiles(folder);
			Array.Sort(files, (IComparer<string>?)StringComparer.OrdinalIgnoreCase);
			string[] array = files;
			foreach (string text in array)
			{
				string text2 = Path.GetExtension(text).ToLowerInvariant();
				string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(text);
				if ((!(text2 != ".wav") || !(text2 != ".ogg") || !(text2 != ".mp3")) && !list.Contains(fileNameWithoutExtension))
				{
					list.Add(fileNameWithoutExtension);
					_files[fileNameWithoutExtension] = text;
				}
			}
		}
		catch (Exception ex)
		{
			CombatSoundsPlugin.Log.LogWarning((object)("Couldn't read " + folder + ": " + ex.Message));
		}
		string text3 = (folder.StartsWith(Paths.GameRootPath, StringComparison.OrdinalIgnoreCase) ? folder.Substring(Paths.GameRootPath.Length).TrimStart('\\', '/') : folder);
		_choice = config.Bind<string>("Sounds", name, list[0], new ConfigDescription(description + ((hit != null) ? "" : " Default = the game's own sound.") + " None = no sound. To add your own, put .wav, .ogg or .mp3 files in " + text3 + " and restart the game.", (AcceptableValueBase)(object)new AcceptableValueList<string>(list.ToArray()), Array.Empty<object>()));
		_volume = config.Bind<int>("Sounds", name + " Volume", 100, new ConfigDescription("Volume of the " + name.ToLowerInvariant() + ". 100 = normal, 200 = twice as loud.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 200), Array.Empty<object>()));
		_choice.SettingChanged += delegate
		{
			Load(preview: true);
		};
		_volume.SettingChanged += delegate
		{
			if (!(Time.unscaledTime < _nextPreview))
			{
				_nextPreview = Time.unscaledTime + 0.3f;
				Play();
			}
		};
		Load(preview: false);
	}

	internal bool SameSound(SoundSlot other)
	{
		if (other != null)
		{
			return string.Equals(Pick._sound, other.Pick._sound, StringComparison.OrdinalIgnoreCase);
		}
		return false;
	}

	internal void Play()
	{
		AudioClip clip = Pick._clip;
		if (!((Object)(object)clip == (Object)null))
		{
			if ((Object)(object)_source == (Object)null)
			{
				_source = NewSource();
			}
			int value = _volume.Value;
			_source.clip = ((value > 100) ? Louder(clip, value) : clip);
			_source.volume = ((value > 100) ? 1f : ((float)value / 100f));
			_source.Play();
		}
	}

	internal void Stop()
	{
		if ((Object)(object)_source != (Object)null)
		{
			_source.Stop();
		}
	}

	private static AudioSource NewSource()
	{
		//IL_0012: 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_0024: Expected O, but got Unknown
		if ((Object)(object)_speaker == (Object)null)
		{
			_speaker = new GameObject("CombatSounds")
			{
				hideFlags = (HideFlags)61
			};
			Object.DontDestroyOnLoad((Object)(object)_speaker);
		}
		AudioSource obj = _speaker.AddComponent<AudioSource>();
		obj.playOnAwake = false;
		obj.spatialBlend = 0f;
		obj.priority = 0;
		bool flag = (obj.bypassReverbZones = true);
		bool bypassEffects = (obj.bypassListenerEffects = flag);
		obj.bypassEffects = bypassEffects;
		return obj;
	}

	private AudioClip Louder(AudioClip clip, int volume)
	{
		if (_louderVolume == volume && (Object)(object)_louderOf == (Object)(object)clip)
		{
			return _louder ?? clip;
		}
		_louderVolume = volume;
		_louderOf = clip;
		DropLouder();
		try
		{
			float[] array = new float[clip.samples * clip.channels];
			if (!clip.GetData(array, 0))
			{
				return clip;
			}
			float num = (float)volume / 100f;
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = Mathf.Clamp(array[i] * num, -1f, 1f);
			}
			_louder = AudioClip.Create(((Object)clip).name + " (louder)", clip.samples, clip.channels, clip.frequency, false);
			_louder.SetData(array, 0);
			return _louder;
		}
		catch (Exception ex)
		{
			CombatSoundsPlugin.Log.LogWarning((object)("Couldn't make " + ((Object)clip).name + " louder, so it plays at 100. (" + ex.Message + ")"));
			DropLouder();
			return clip;
		}
	}

	private void DropLouder()
	{
		if ((Object)(object)_louder != (Object)null)
		{
			Object.Destroy((Object)(object)_louder);
		}
		_louder = null;
	}

	private void Load(bool preview)
	{
		//IL_010c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0119: Unknown result type (might be due to invalid IL or missing references)
		int id = ++_loadId;
		string choice = _choice.Value;
		_none = choice == "None";
		_following = _hit != null && choice == "Same as Hit";
		if ((Object)(object)_clip != (Object)null)
		{
			Object.Destroy((Object)(object)_clip);
		}
		_clip = null;
		_sound = null;
		DropLouder();
		_louderVolume = 0;
		if (!_files.TryGetValue(choice, out var file))
		{
			if (preview && _following)
			{
				Play();
			}
			return;
		}
		string text = Path.GetExtension(file).ToLowerInvariant();
		AudioType val = (AudioType)((text == ".ogg") ? 14 : ((text == ".mp3") ? 13 : 20));
		UnityWebRequest request = UnityWebRequestMultimedia.GetAudioClip(new Uri(file), val);
		((AsyncOperation)request.SendWebRequest()).completed += delegate
		{
			try
			{
				AudioClip val2 = (string.IsNullOrEmpty(request.error) ? DownloadHandlerAudioClip.GetContent(request) : null);
				if (id != _loadId)
				{
					if ((Object)(object)val2 != (Object)null)
					{
						Object.Destroy((Object)(object)val2);
					}
				}
				else if ((Object)(object)val2 == (Object)null || val2.samples == 0)
				{
					CombatSoundsPlugin.Log.LogWarning((object)("Couldn't load " + Path.GetFileName(file) + " (" + (request.error ?? "not a sound Unity can play") + "), so the game's own " + _name.ToLowerInvariant() + " plays."));
				}
				else
				{
					((Object)val2).name = choice;
					_clip = val2;
					_sound = choice;
					if (preview)
					{
						Play();
					}
				}
			}
			catch (Exception ex)
			{
				CombatSoundsPlugin.Log.LogWarning((object)("Couldn't load " + Path.GetFileName(file) + ": " + ex.Message));
			}
			finally
			{
				request.Dispose();
			}
		};
	}
}
internal static class Hooks
{
	private static int _frame = -1;

	private static SoundSlot _hit;

	private static SoundSlot _kill;

	private static int _headLayerFrame = -1;

	private static bool _errorLogged;

	internal static void Install(Harmony harmony)
	{
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		//IL_0035: Expected O, but got Unknown
		//IL_005e: Unknown result type (might be due to invalid IL or missing references)
		//IL_006b: Expected O, but got Unknown
		//IL_0094: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a1: Expected O, but got Unknown
		//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b8: Expected O, but got Unknown
		harmony.Patch((MethodBase)AccessTools.Method(typeof(Settings), "IncreaseBodyshotsAmount", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(Hooks), "HitPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		harmony.Patch((MethodBase)AccessTools.Method(typeof(Settings), "IncreaseHeadshotsAmount", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(Hooks), "HeadHitPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		harmony.Patch((MethodBase)AccessTools.Method(typeof(Settings), "IncreaseKillsAmount", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(Hooks), "KillPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		HarmonyMethod val = new HarmonyMethod(typeof(Hooks), "GameSoundPrefix", (Type[])null);
		Type[] typesFromAssembly = AccessTools.GetTypesFromAssembly(typeof(Weapon).Assembly);
		foreach (Type type in typesFromAssembly)
		{
			if (typeof(Weapon).IsAssignableFrom(type))
			{
				MethodInfo methodInfo = AccessTools.DeclaredMethod(type, "LocalSound", new Type[1] { typeof(int) }, (Type[])null);
				if (methodInfo != null)
				{
					harmony.Patch((MethodBase)methodInfo, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
			}
		}
	}

	private static void HitPostfix()
	{
		Play(CombatSoundsPlugin.Hit, kill: false);
	}

	private static void HeadHitPostfix()
	{
		Play(CombatSoundsPlugin.HeadHit, kill: false);
	}

	private static void KillPostfix()
	{
		Play(CombatSoundsPlugin.Kill, kill: true);
	}

	private static void Play(SoundSlot slot, bool kill)
	{
		try
		{
			if (!slot.HasSound)
			{
				return;
			}
			int frameCount = Time.frameCount;
			if (frameCount != _frame)
			{
				_frame = frameCount;
				_hit = (_kill = null);
			}
			if (kill)
			{
				if (_kill == null)
				{
					_kill = slot;
					if (!slot.SameSound(_hit))
					{
						slot.Play();
					}
				}
			}
			else if (_hit != slot && _hit != CombatSoundsPlugin.HeadHit)
			{
				if (_hit != null)
				{
					_hit.Stop();
				}
				_hit = slot;
				if (!slot.SameSound(_kill))
				{
					slot.Play();
				}
			}
		}
		catch (Exception ex)
		{
			if (!_errorLogged)
			{
				_errorLogged = true;
				CombatSoundsPlugin.Log.LogError((object)("Error (further errors are not logged): " + ex));
			}
		}
	}

	private static bool GameSoundPrefix(int __0)
	{
		switch (__0)
		{
		case 0:
			_headLayerFrame = Time.frameCount;
			return !CombatSoundsPlugin.HeadHit.ReplacesGameSound;
		case 1:
		{
			bool num = _headLayerFrame == Time.frameCount;
			_headLayerFrame = -1;
			return !(num ? CombatSoundsPlugin.HeadHit : CombatSoundsPlugin.Hit).ReplacesGameSound;
		}
		case 2:
			return !CombatSoundsPlugin.Kill.ReplacesGameSound;
		default:
			return true;
		}
	}
}