Decompiled source of SoundEffectVolumeLimiter v1.0.2

SoundEffectVolumeLimiter/SoundEffectVolumeLimiter.dll

Decompiled 9 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("SoundEffectVolumeLimiter")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("Sound Effect Volume Limiter")]
[assembly: AssemblyTitle("SoundEffectVolumeLimiter")]
[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.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace SoundEffectVolumeLimiter
{
	[BepInPlugin("com.Exocet.SoundEffectVolumeLimiter", "Sound Effect Volume Limiter", "1.0.2")]
	public class SoundEffectVolumeLimiterPlugin : BaseUnityPlugin
	{
		public const string PLUGIN_GUID = "com.Exocet.SoundEffectVolumeLimiter";

		public const string PLUGIN_NAME = "Sound Effect Volume Limiter";

		public const string PLUGIN_VERSION = "1.0.2";

		private void Awake()
		{
			ShipSoundCaps.Bind(((BaseUnityPlugin)this).Config);
			((Component)this).gameObject.AddComponent<ShipSoundCaps>();
		}
	}
	internal sealed class ConfigurationManagerAttributes
	{
		public int? Order;
	}
	public class ShipSoundCaps : MonoBehaviour
	{
		private sealed class SoundGroup
		{
			public string Name;

			public string[] Keywords;
		}

		private static readonly string[] DefaultGroupNames = new string[10] { "Footsteps", "Helm Creak", "Boat Creaking", "Hull Wash", "Waves", "Rigging", "Weather", "Misc Effects", "Custom 1", "Custom 2" };

		private static readonly string[][] DefaultGroupKeywords = new string[10][]
		{
			new string[5] { "footstep", "footsteps", "foot", "step", "steps" },
			new string[1] { "wheel creak" },
			new string[1] { "boat creak" },
			new string[3] { "hull", "hitting-bow", "bow" },
			new string[5] { "oceanwave", "wave", "splash", "ocean", "shore" },
			new string[4] { "sail", "rope", "flap", "snap" },
			new string[4] { "rain", "thunder", "storm", "wind" },
			new string[6] { "click", "eat", "swallow", "scrape", "fishing", "seagulls" },
			new string[1] { "bell" },
			new string[1] { "pump" }
		};

		private static readonly SoundGroup[] DefaultGroups = CreateDefaultGroups();

		private static SoundGroup[] _groups = CreateDefaultGroups();

		private static ConfigEntry<string>[] _groupNames;

		private static ConfigEntry<string>[] _groupKeywords;

		private static ConfigEntry<float>[] _caps;

		private static ConfigEntry<KeyboardShortcut> _dumpKey;

		private static ConfigEntry<KeyboardShortcut> _refreshGroupsKey;

		private static ConfigEntry<KeyboardShortcut> _restoreDefaultGroupsKey;

		private static readonly HashSet<ShipSoundCaps> Instances = new HashSet<ShipSoundCaps>();

		private static readonly List<AudioSource> SceneAudioSources = new List<AudioSource>();

		private readonly List<AudioSource>[] _byGroup = new List<AudioSource>[DefaultGroups.Length];

		private readonly HashSet<AudioSource> _mutedByUs = new HashSet<AudioSource>();

		private float _nextScan;

		private static SoundGroup[] CreateDefaultGroups()
		{
			SoundGroup[] array = new SoundGroup[DefaultGroupNames.Length];
			for (int i = 0; i < DefaultGroupNames.Length; i++)
			{
				array[i] = new SoundGroup
				{
					Name = DefaultGroupNames[i],
					Keywords = CopyKeywords(DefaultGroupKeywords[i])
				};
			}
			return array;
		}

		private static string[] CopyKeywords(string[] keywords)
		{
			string[] array = new string[keywords.Length];
			for (int i = 0; i < keywords.Length; i++)
			{
				array[i] = keywords[i].ToLowerInvariant();
			}
			return array;
		}

		public static void Bind(ConfigFile cfg)
		{
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Expected O, but got Unknown
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Expected O, but got Unknown
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e0: Expected O, but got Unknown
			//IL_020b: 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_023e: Expected O, but got Unknown
			//IL_0258: Unknown result type (might be due to invalid IL or missing references)
			//IL_0281: Unknown result type (might be due to invalid IL or missing references)
			//IL_028b: Expected O, but got Unknown
			//IL_02a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d8: Expected O, but got Unknown
			_groupNames = new ConfigEntry<string>[DefaultGroupNames.Length];
			_groupKeywords = new ConfigEntry<string>[DefaultGroupNames.Length];
			for (int i = 0; i < DefaultGroupNames.Length; i++)
			{
				_groupNames[i] = cfg.Bind<string>("Ship sound", "Group " + (i + 1) + " name", DefaultGroupNames[i], new ConfigDescription("Display name for this ship sound group.", (AcceptableValueBase)null, new object[1]
				{
					new ConfigurationManagerAttributes
					{
						Order = GroupOrder(i, 0)
					}
				}));
				_groupKeywords[i] = cfg.Bind<string>("Ship sound", "Group " + (i + 1) + " keywords", string.Join(";", DefaultGroupKeywords[i]), new ConfigDescription("Semicolon-separated clip fragments used to detect sounds for this group. Example: wave; splash", (AcceptableValueBase)null, new object[1]
				{
					new ConfigurationManagerAttributes
					{
						Order = GroupOrder(i, 1)
					}
				}));
				_groupNames[i].SettingChanged += delegate
				{
					RefreshGroupsFromConfig();
				};
				_groupKeywords[i].SettingChanged += delegate
				{
					RefreshGroupsFromConfig();
				};
			}
			RefreshGroupsFromConfig();
			_caps = new ConfigEntry<float>[_groups.Length];
			for (int num = 0; num < _groups.Length; num++)
			{
				_caps[num] = cfg.Bind<float>("Ship sound", _groups[num].Name + " volume ceiling", 1f, new ConfigDescription("1 = untouched, 0 = silent. This is a ceiling: anything already quieter than this is left alone.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), new object[1]
				{
					new ConfigurationManagerAttributes
					{
						Order = GroupOrder(num, 2)
					}
				}));
			}
			_dumpKey = cfg.Bind<KeyboardShortcut>("Ship sound", "List the clips on this ship", new KeyboardShortcut((KeyCode)292, Array.Empty<KeyCode>()), new ConfigDescription("Press this key in-game to list matching and ungrouped audio clips.", (AcceptableValueBase)null, new object[1]
			{
				new ConfigurationManagerAttributes
				{
					Order = 520
				}
			}));
			_refreshGroupsKey = cfg.Bind<KeyboardShortcut>("Ship sound", "Refresh groups key", new KeyboardShortcut((KeyCode)290, Array.Empty<KeyCode>()), new ConfigDescription("Press this key in-game to rebuild the configured groups and rescan all active audio sources.", (AcceptableValueBase)null, new object[1]
			{
				new ConfigurationManagerAttributes
				{
					Order = 540
				}
			}));
			_restoreDefaultGroupsKey = cfg.Bind<KeyboardShortcut>("Ship sound", "Restore default groups key", new KeyboardShortcut((KeyCode)289, Array.Empty<KeyCode>()), new ConfigDescription("Press this key in-game to restore the default group names and keyword sets without changing volume ceilings.", (AcceptableValueBase)null, new object[1]
			{
				new ConfigurationManagerAttributes
				{
					Order = 560
				}
			}));
		}

		private static int GroupOrder(int groupIndex, int settingOffset)
		{
			return 1000 - groupIndex * 30 - settingOffset;
		}

		private static void RefreshGroupsFromConfig()
		{
			if (_groupNames == null || _groupKeywords == null)
			{
				return;
			}
			_groups = new SoundGroup[_groupNames.Length];
			for (int i = 0; i < _groupNames.Length; i++)
			{
				string text = ((_groupNames[i] != null && !string.IsNullOrWhiteSpace(_groupNames[i].Value)) ? _groupNames[i].Value.Trim() : DefaultGroups[i].Name);
				List<string> list = new List<string>();
				list.Add(text.ToLowerInvariant());
				if (_groupKeywords[i] != null && !string.IsNullOrEmpty(_groupKeywords[i].Value))
				{
					string[] array = _groupKeywords[i].Value.Split(new char[3] { ';', ',', '|' }, StringSplitOptions.RemoveEmptyEntries);
					for (int j = 0; j < array.Length; j++)
					{
						string text2 = array[j].Trim();
						if (!string.IsNullOrEmpty(text2))
						{
							list.Add(text2.ToLowerInvariant());
						}
					}
				}
				if (list.Count == 1)
				{
					for (int k = 0; k < DefaultGroups[i].Keywords.Length; k++)
					{
						list.Add(DefaultGroups[i].Keywords[k]);
					}
				}
				_groups[i] = new SoundGroup
				{
					Name = text,
					Keywords = list.ToArray()
				};
			}
		}

		private void Awake()
		{
			Instances.Add(this);
			for (int i = 0; i < _groups.Length; i++)
			{
				_byGroup[i] = new List<AudioSource>();
			}
			Rescan();
		}

		private void OnDestroy()
		{
			Instances.Remove(this);
		}

		private static List<AudioSource> FindSceneAudioSources()
		{
			//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)
			AudioSource[] array = Resources.FindObjectsOfTypeAll<AudioSource>();
			SceneAudioSources.Clear();
			foreach (AudioSource val in array)
			{
				if ((Object)(object)val != (Object)null)
				{
					Scene scene = ((Component)val).gameObject.scene;
					if (((Scene)(ref scene)).IsValid())
					{
						SceneAudioSources.Add(val);
					}
				}
			}
			return SceneAudioSources;
		}

		private void Rescan()
		{
			_mutedByUs.RemoveWhere(IsDestroyedAudioSource);
			for (int i = 0; i < _byGroup.Length; i++)
			{
				_byGroup[i].Clear();
			}
			List<AudioSource> list = FindSceneAudioSources();
			for (int j = 0; j < list.Count; j++)
			{
				AudioSource val = list[j];
				if (!((Object)(object)val == (Object)null) && !((Object)(object)val.clip == (Object)null) && ((Object)val.clip).name != null)
				{
					string clipName = ((Object)val.clip).name.ToLowerInvariant();
					int num = FindMatchingGroup(clipName);
					if (num >= 0)
					{
						_byGroup[num].Add(val);
					}
				}
			}
		}

		private static int FindMatchingGroup(string clipName)
		{
			for (int i = 0; i < _groups.Length; i++)
			{
				SoundGroup soundGroup = _groups[i];
				for (int j = 0; j < soundGroup.Keywords.Length; j++)
				{
					string value = soundGroup.Keywords[j];
					if (!string.IsNullOrEmpty(value) && clipName.Contains(value))
					{
						return i;
					}
				}
			}
			return -1;
		}

		private void LateUpdate()
		{
			//IL_004c: 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_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_009c: 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)
			if (_caps == null)
			{
				return;
			}
			if (Time.time >= _nextScan)
			{
				_nextScan = Time.time + 5f;
				Rescan();
			}
			KeyboardShortcut value;
			if (_dumpKey != null)
			{
				value = _dumpKey.Value;
				if (((KeyboardShortcut)(ref value)).IsDown())
				{
					Dump();
				}
			}
			if (_refreshGroupsKey != null)
			{
				value = _refreshGroupsKey.Value;
				if (((KeyboardShortcut)(ref value)).IsDown())
				{
					Rescan();
				}
			}
			if (_restoreDefaultGroupsKey != null)
			{
				value = _restoreDefaultGroupsKey.Value;
				if (((KeyboardShortcut)(ref value)).IsDown())
				{
					RestoreDefaultGroups();
				}
			}
			for (int i = 0; i < _byGroup.Length; i++)
			{
				float value2 = _caps[i].Value;
				List<AudioSource> list = _byGroup[i];
				for (int j = 0; j < list.Count; j++)
				{
					AudioSource val = list[j];
					if ((Object)(object)val == (Object)null)
					{
						continue;
					}
					if (value2 <= 0.001f)
					{
						if (!val.mute)
						{
							val.mute = true;
							_mutedByUs.Add(val);
						}
						continue;
					}
					if (_mutedByUs.Contains(val))
					{
						val.mute = false;
						_mutedByUs.Remove(val);
					}
					if (!(value2 >= 0.999f))
					{
						val.volume = Mathf.Min(val.volume, value2);
					}
				}
			}
		}

		private static bool IsDestroyedAudioSource(AudioSource source)
		{
			return (Object)(object)source == (Object)null;
		}

		private static void RestoreDefaultGroups()
		{
			if (_groupNames != null && _groupKeywords != null)
			{
				for (int i = 0; i < DefaultGroupNames.Length; i++)
				{
					_groupNames[i].Value = DefaultGroupNames[i];
					_groupKeywords[i].Value = string.Join(";", DefaultGroupKeywords[i]);
				}
				RefreshGroupsFromConfig();
				RescanAllInstances();
				Debug.Log((object)"[ShipSound] Restored default group order and keyword sets.");
			}
		}

		private static void RescanAllInstances()
		{
			foreach (ShipSoundCaps instance in Instances)
			{
				if ((Object)(object)instance != (Object)null)
				{
					instance.Rescan();
				}
			}
		}

		private void Dump()
		{
			Rescan();
			for (int i = 0; i < _byGroup.Length; i++)
			{
				StringBuilder stringBuilder = new StringBuilder();
				for (int j = 0; j < _byGroup[i].Count; j++)
				{
					if ((Object)(object)_byGroup[i][j] != (Object)null && (Object)(object)_byGroup[i][j].clip != (Object)null)
					{
						stringBuilder.Append(((Object)_byGroup[i][j].clip).name).Append("  ");
					}
				}
				Debug.Log((object)("[ShipSound] " + _groups[i].Name + " (" + _byGroup[i].Count + "): " + stringBuilder));
			}
			List<AudioSource> list = FindSceneAudioSources();
			StringBuilder stringBuilder2 = new StringBuilder();
			for (int k = 0; k < list.Count; k++)
			{
				if ((Object)(object)list[k] == (Object)null || (Object)(object)list[k].clip == (Object)null)
				{
					continue;
				}
				bool flag = false;
				for (int l = 0; l < _byGroup.Length; l++)
				{
					if (flag)
					{
						break;
					}
					flag = _byGroup[l].Contains(list[k]);
				}
				if (!flag)
				{
					stringBuilder2.Append(((Object)list[k].clip).name).Append("  ");
				}
			}
			Debug.Log((object)("[ShipSound] UNGROUPED: " + stringBuilder2));
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "SoundEffectVolumeLimiter";

		public const string PLUGIN_NAME = "Sound Effect Volume Limiter";

		public const string PLUGIN_VERSION = "1.0.0";
	}
}