Decompiled source of LouderMonsters v1.2.0

LouderMonsters.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyVersion("0.0.0.0")]
[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 LouderMonsters
{
	[BepInPlugin("rev.loudermonsters", "LouderMonsters", "1.2.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "rev.loudermonsters";

		public const string Name = "LouderMonsters";

		public const string Version = "1.2.0";

		private const int PresetRevision = 2;

		private static readonly Dictionary<string, (float gain, float range)> Presets = new Dictionary<string, (float, float)>
		{
			{
				"Animal",
				(1.5f, 1.35f)
			},
			{
				"Clown",
				(1.5f, 1.35f)
			},
			{
				"Upscream",
				(1.5f, 1.35f)
			},
			{
				"Trudge",
				(1.5f, 1.35f)
			},
			{
				"Banger",
				(0.5f, 0.6f)
			},
			{
				"Clown Laser",
				(1.5f, 1.3f)
			}
		};

		internal static ManualLogSource Log;

		internal static ConfigFile Cfg;

		internal static MonsterAudio General;

		private static readonly Dictionary<string, MonsterAudio> Groups = new Dictionary<string, MonsterAudio>();

		private static int configRevision;

		private void Awake()
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Expected O, but got Unknown
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Expected O, but got Unknown
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			Cfg = ((BaseUnityPlugin)this).Config;
			configRevision = ReadConfigRevision(((BaseUnityPlugin)this).Config.ConfigFilePath);
			General = new MonsterAudio(null, ((BaseUnityPlugin)this).Config.Bind<float>("General", "Gain", 2f, new ConfigDescription("Signal amplification for all monster sounds. 1 = vanilla, 2 = twice as loud.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 4f), Array.Empty<object>())), ((BaseUnityPlugin)this).Config.Bind<float>("General", "Range", 1.3f, new ConfigDescription("Audible distance multiplier for all monster sounds. 1 = vanilla. Applies to newly spawned monsters.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 3f), Array.Empty<object>())));
			if (configRevision < 2 && Mathf.Approximately(General.RangeEntry.Value, 1.5f))
			{
				General.RangeEntry.Value = 1.3f;
			}
			foreach (KeyValuePair<string, (float, float)> preset in Presets)
			{
				GetGroup(preset.Key);
			}
			((BaseUnityPlugin)this).Config.Bind<int>("Internal", "PresetRevision", 2, "Used by the mod to update default values after upgrades. Do not edit.").Value = 2;
			new Harmony("rev.loudermonsters").PatchAll(typeof(Patches));
			Log.LogInfo((object)string.Format("{0} {1} loaded (gain x{2}, range x{3})", "LouderMonsters", "1.2.0", General.GainEntry.Value, General.RangeEntry.Value));
		}

		private static int ReadConfigRevision(string path)
		{
			if (!File.Exists(path))
			{
				return 2;
			}
			string[] array = File.ReadAllLines(path);
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (text.StartsWith("PresetRevision") && int.TryParse(text.Substring(text.IndexOf('=') + 1).Trim(), out var result))
				{
					return result;
				}
			}
			return 1;
		}

		internal static MonsterAudio GetMonster(string enemyName)
		{
			return GetGroup(enemyName);
		}

		internal static MonsterAudio GetLaser(string enemyName)
		{
			return GetGroup(enemyName + " Laser", GetMonster(enemyName));
		}

		private static MonsterAudio GetGroup(string groupName, MonsterAudio parent = null)
		{
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Expected O, but got Unknown
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Expected O, but got Unknown
			if (Groups.TryGetValue(groupName, out var value))
			{
				return value;
			}
			if (parent == null && groupName.EndsWith(" Laser"))
			{
				parent = GetGroup(groupName.Substring(0, groupName.Length - " Laser".Length));
			}
			string text = SanitizeKey(groupName);
			(float, float) value2;
			bool flag = Presets.TryGetValue(groupName, out value2);
			float num;
			if (flag)
			{
				(num, _) = value2;
			}
			else
			{
				num = 1f;
			}
			float num2 = num;
			float num3 = (flag ? value2.Item2 : 1f);
			string text2 = ((parent != null) ? parent.DisplayName : "General");
			ConfigEntry<float> val = Cfg.Bind<float>("Monsters", text + " Gain", num2, new ConfigDescription("Extra amplification for " + groupName + ", multiplied with " + text2 + " Gain. Below 1 makes it quieter.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 4f), Array.Empty<object>()));
			ConfigEntry<float> val2 = Cfg.Bind<float>("Monsters", text + " Range", num3, new ConfigDescription("Extra audible distance for " + groupName + ", multiplied with " + text2 + " Range. Below 1 makes it heard from closer.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 3f), Array.Empty<object>()));
			if (flag && configRevision < 2)
			{
				if (Mathf.Approximately(val.Value, 1f))
				{
					val.Value = num2;
				}
				if (Mathf.Approximately(val2.Value, 1f) || Mathf.Approximately(val2.Value, 1.5f))
				{
					val2.Value = num3;
				}
			}
			value = new MonsterAudio(parent ?? General, val, val2, groupName);
			Groups[groupName] = value;
			return value;
		}

		private static string SanitizeKey(string name)
		{
			char[] array = name.ToCharArray();
			for (int i = 0; i < array.Length; i++)
			{
				if ("=\n\t\\\"'[]".IndexOf(array[i]) >= 0)
				{
					array[i] = '_';
				}
			}
			return new string(array).Trim();
		}
	}
	internal class MonsterAudio
	{
		public readonly ConfigEntry<float> GainEntry;

		public readonly ConfigEntry<float> RangeEntry;

		public readonly string DisplayName;

		private readonly MonsterAudio parent;

		public volatile float Gain = 1f;

		public float Range => RangeEntry.Value * ((parent != null) ? parent.Range : 1f);

		public event Action Changed;

		public MonsterAudio(MonsterAudio parent, ConfigEntry<float> gain, ConfigEntry<float> range, string displayName = "General")
		{
			this.parent = parent;
			GainEntry = gain;
			RangeEntry = range;
			DisplayName = displayName;
			Refresh();
			gain.SettingChanged += delegate
			{
				Refresh();
			};
			if (parent != null)
			{
				parent.Changed += Refresh;
			}
		}

		private void Refresh()
		{
			Gain = GainEntry.Value * ((parent != null) ? parent.Gain : 1f);
			this.Changed?.Invoke();
		}
	}
	internal static class EnemySounds
	{
		private static readonly ConditionalWeakTable<Sound, MonsterAudio> Registered = new ConditionalWeakTable<Sound, MonsterAudio>();

		private static readonly Dictionary<Type, FieldInfo[]> FieldCache = new Dictionary<Type, FieldInfo[]>();

		public static MonsterAudio Find(Sound sound)
		{
			if (sound == null || !Registered.TryGetValue(sound, out var value))
			{
				return null;
			}
			return value;
		}

		public static void RegisterEnemy(EnemyParent enemy)
		{
			string text = (string.IsNullOrEmpty(enemy.enemyName) ? ((Object)enemy).name : enemy.enemyName);
			MonsterAudio monster = Plugin.GetMonster(text);
			MonoBehaviour[] componentsInChildren = ((Component)enemy).GetComponentsInChildren<MonoBehaviour>(true);
			HashSet<SemiLaser> hashSet = new HashSet<SemiLaser>(((Component)enemy).GetComponentsInChildren<SemiLaser>(true));
			MonoBehaviour[] array = componentsInChildren;
			foreach (MonoBehaviour obj in array)
			{
				EnemyBeamer val = (EnemyBeamer)(object)((obj is EnemyBeamer) ? obj : null);
				if (val != null && (Object)(object)val.laser != (Object)null)
				{
					hashSet.Add(val.laser);
				}
			}
			int num = 0;
			if (hashSet.Count > 0)
			{
				MonsterAudio laser = Plugin.GetLaser(text);
				foreach (SemiLaser item in hashSet)
				{
					num += RegisterBehaviour((MonoBehaviour)(object)item, laser);
				}
			}
			int num2 = 0;
			array = componentsInChildren;
			foreach (MonoBehaviour val2 in array)
			{
				if ((Object)(object)val2 != (Object)null && !(val2 is SemiLaser))
				{
					num2 += RegisterBehaviour(val2, monster);
				}
			}
			string text2 = ((num > 0) ? $", laser {num} sounds" : "");
			Plugin.Log.LogInfo((object)$"Monster spawned: {text} ({num2} sounds{text2}, gain x{monster.Gain:0.##}, range x{monster.Range:0.##})");
		}

		private static int RegisterBehaviour(MonoBehaviour behaviour, MonsterAudio audio)
		{
			int num = 0;
			FieldInfo[] soundFields = GetSoundFields(((object)behaviour).GetType());
			for (int i = 0; i < soundFields.Length; i++)
			{
				object value = soundFields[i].GetValue(behaviour);
				Sound val = (Sound)((value is Sound) ? value : null);
				if (val != null)
				{
					num += Register(val, audio);
				}
				else
				{
					if (!(value is IEnumerable<Sound> enumerable))
					{
						continue;
					}
					foreach (Sound item in enumerable)
					{
						num += Register(item, audio);
					}
				}
			}
			return num;
		}

		private static int Register(Sound sound, MonsterAudio audio)
		{
			if (sound == null || Registered.TryGetValue(sound, out var _))
			{
				return 0;
			}
			Registered.Add(sound, audio);
			if ((Object)(object)sound.Source != (Object)null)
			{
				float range = audio.Range;
				AudioSource source = sound.Source;
				source.minDistance *= range;
				AudioSource source2 = sound.Source;
				source2.maxDistance *= range;
				AttachGain(((Component)sound.Source).gameObject, audio);
			}
			return 1;
		}

		public static void AttachGain(GameObject go, MonsterAudio audio)
		{
			GainFilter gainFilter = go.GetComponent<GainFilter>();
			if ((Object)(object)gainFilter == (Object)null)
			{
				gainFilter = go.AddComponent<GainFilter>();
			}
			gainFilter.Audio = audio;
		}

		private static FieldInfo[] GetSoundFields(Type type)
		{
			if (FieldCache.TryGetValue(type, out var value))
			{
				return value;
			}
			List<FieldInfo> list = new List<FieldInfo>();
			Type type2 = type;
			while (type2 != null && type2 != typeof(MonoBehaviour))
			{
				FieldInfo[] fields = type2.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (FieldInfo fieldInfo in fields)
				{
					Type fieldType = fieldInfo.FieldType;
					if (fieldType == typeof(Sound) || typeof(IEnumerable<Sound>).IsAssignableFrom(fieldType))
					{
						list.Add(fieldInfo);
					}
				}
				type2 = type2.BaseType;
			}
			value = list.ToArray();
			FieldCache[type] = value;
			return value;
		}
	}
	internal class GainFilter : MonoBehaviour
	{
		private const float Knee = 0.7f;

		internal volatile MonsterAudio Audio;

		private void OnAudioFilterRead(float[] data, int channels)
		{
			MonsterAudio audio = Audio;
			if (audio == null)
			{
				return;
			}
			float gain = audio.Gain;
			if (Mathf.Abs(gain - 1f) < 0.001f)
			{
				return;
			}
			for (int i = 0; i < data.Length; i++)
			{
				float num = data[i] * gain;
				float num2 = ((num < 0f) ? (0f - num) : num);
				if (num2 > 0.7f)
				{
					float num3 = 0.7f + 0.3f * (float)Math.Tanh((num2 - 0.7f) / 0.3f);
					num = ((num < 0f) ? (0f - num3) : num3);
				}
				data[i] = num;
			}
		}
	}
	internal static class Patches
	{
		[HarmonyPatch(typeof(EnemyParent), "Awake")]
		[HarmonyPostfix]
		private static void EnemyParentAwake(EnemyParent __instance)
		{
			try
			{
				EnemySounds.RegisterEnemy(__instance);
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Failed to register sounds on {((Object)__instance).name}: {arg}");
			}
		}

		[HarmonyPatch(typeof(Sound), "Play", new Type[]
		{
			typeof(Vector3),
			typeof(float),
			typeof(float),
			typeof(float),
			typeof(float)
		})]
		[HarmonyPrefix]
		private static void PlayPrefix(Sound __instance, ref float falloffMultiplier)
		{
			if (!((Object)(object)__instance.Source != (Object)null))
			{
				MonsterAudio monsterAudio = EnemySounds.Find(__instance);
				if (monsterAudio != null)
				{
					falloffMultiplier *= monsterAudio.Range;
				}
			}
		}

		[HarmonyPatch(typeof(Sound), "Play", new Type[]
		{
			typeof(Vector3),
			typeof(float),
			typeof(float),
			typeof(float),
			typeof(float)
		})]
		[HarmonyPostfix]
		private static void PlayPostfix(Sound __instance, AudioSource __result)
		{
			if (!((Object)(object)__result == (Object)null))
			{
				MonsterAudio monsterAudio = EnemySounds.Find(__instance);
				if (monsterAudio != null)
				{
					EnemySounds.AttachGain(((Component)__result).gameObject, monsterAudio);
				}
			}
		}
	}
}