Decompiled source of SpeedrunTypingSound v1.0.0

BepInEx/plugins/Oxylight.SpeedrunTypingSound/SpeedrunTypingSound.dll

Decompiled 5 days ago
using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("SpeedrunTypingSound")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("SpeedrunTypingSound")]
[assembly: AssemblyTitle("SpeedrunTypingSound")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[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 SpeedrunTypingSound
{
	internal static class Events
	{
		public const uint TERMINAL_INPUT_1ST_PERSON = 971951075u;

		public const uint TERMINAL_INPUT_3RD_PERSON = 637303252u;

		public const int VolumeStepCount = 30;

		public const float VolumeStepDb = 2f;

		public const int VolumeTenthsPerStep = 20;

		public const int DistanceStepM = 5;

		public const int MinConfigDistanceM = 0;

		public const int MinBankDistanceM = 5;

		public const int MaxDistanceM = 50;

		public const uint SILENT = 0u;

		public static uint Hash(string name)
		{
			uint num = 2166136261u;
			string text = name.ToLowerInvariant();
			foreach (char c in text)
			{
				num *= 16777619;
				num ^= (byte)c;
			}
			return num;
		}

		public static uint TypingEvent(int stepIndex, bool positional, int distanceM = 0)
		{
			return Hash(positional ? $"SPEEDRUN_TYPING3D_D{distanceM}_DB{stepIndex * 20}" : $"SPEEDRUN_TYPING_DB{stepIndex * 20}");
		}

		public static int SnapDistance(int metres)
		{
			return Mathf.Clamp(Mathf.RoundToInt((float)metres / 5f) * 5, 5, 50);
		}

		public static float StepDb(int stepIndex)
		{
			return -2f * (float)stepIndex;
		}
	}
	internal static class Redirect
	{
		private static uint _target2D;

		private static uint _target3D;

		private static float _lastVolume = float.NaN;

		private static int _lastDistance = int.MinValue;

		public static void Recalculate()
		{
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Expected O, but got Unknown
			float value = Plugin.Volume.Value;
			float num = Mathf.Clamp01(value);
			_lastVolume = value;
			int num2 = (_lastDistance = Plugin.HearingDistance.Value);
			int distanceM = 0;
			if (num <= 0f)
			{
				_target2D = 0u;
				_target3D = 0u;
				Plugin.Logger.LogInfo((object)"Volume 0.00 -> muted");
				return;
			}
			int stepIndex = Mathf.Clamp(Mathf.RoundToInt((1f - num) * 30f), 0, 30);
			_target2D = Events.TypingEvent(stepIndex, positional: false);
			if (num2 <= 0)
			{
				_target3D = 0u;
			}
			else
			{
				distanceM = Events.SnapDistance(num2);
				_target3D = Events.TypingEvent(stepIndex, positional: true, distanceM);
			}
			ManualLogSource logger = Plugin.Logger;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(51, 5, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Volume ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(num, "0.000");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" -> ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(Events.StepDb(stepIndex), "0.0");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" dB, hearing distance ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>((num2 <= 0) ? "muted" : (distanceM + " m"));
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("-> events 2D=");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<uint>(_target2D);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" 3D=");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<uint>(_target3D);
			}
			logger.LogInfo(val);
		}

		public static void Apply(ref uint eventID)
		{
			if (Plugin.Enabled.Value)
			{
				if (Plugin.Volume.Value != _lastVolume || Plugin.HearingDistance.Value != _lastDistance)
				{
					Recalculate();
				}
				if (eventID == 971951075)
				{
					eventID = _target2D;
				}
				else if (eventID == 637303252 && Plugin.ThirdPerson.Value)
				{
					eventID = _target3D;
				}
			}
		}
	}
	[HarmonyPatch(typeof(CellSoundPlayer), "Post", new Type[]
	{
		typeof(uint),
		typeof(bool)
	})]
	internal static class Patch_Post_Global
	{
		[HarmonyPrefix]
		private static void Prefix(ref uint eventID)
		{
			Redirect.Apply(ref eventID);
		}
	}
	[HarmonyPatch(typeof(CellSoundPlayer), "Post", new Type[]
	{
		typeof(uint),
		typeof(Vector3)
	})]
	internal static class Patch_Post_Positional
	{
		[HarmonyPrefix]
		private static void Prefix(ref uint eventID)
		{
			Redirect.Apply(ref eventID);
		}
	}
	[BepInPlugin("Oxylight.SpeedrunTypingSound", "SpeedrunTypingSound", "1.0.0")]
	[BepInProcess("GTFO.exe")]
	internal sealed class Plugin : BasePlugin
	{
		public const string GUID = "Oxylight.SpeedrunTypingSound";

		public const string NAME = "SpeedrunTypingSound";

		public const string VERSION = "1.0.0";

		internal static ManualLogSource Logger;

		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<bool> ThirdPerson;

		internal static ConfigEntry<float> Volume;

		internal static ConfigEntry<int> HearingDistance;

		private Harmony? _harmony;

		private FileSystemWatcher? _watcher;

		public override void Load()
		{
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Expected O, but got Unknown
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Expected O, but got Unknown
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Expected O, but got Unknown
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Expected O, but got Unknown
			Logger = ((BasePlugin)this).Log;
			Enabled = ((BasePlugin)this).Config.Bind<bool>("General", "Enabled", true, "Replace the terminal typing sound.");
			ThirdPerson = ((BasePlugin)this).Config.Bind<bool>("General", "ReplaceThirdPerson", true, "Also replace the typing sound other players hear from your terminal.");
			Volume = ((BasePlugin)this).Config.Bind<float>("General", "Volume", 0.5f, new ConfigDescription("Loudness of the replacement typing sound. The scale is linear in decibels, so it tracks perceived loudness: 1.0 = 0 dB (original, very loud), 0.75 = -15 dB, 0.5 = -30 dB (default), 0.25 = -45 dB, 0.0 = fully muted. Resolution is 0.5 dB per step. Saving this file while the game runs applies the change on the next keystroke.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			HearingDistance = ((BasePlugin)this).Config.Bind<int>("General", "HearingDistanceMeters", 15, new ConfigDescription("How far away other players can hear your terminal typing, in metres. The sound fades to silence at this distance. 0 means other players hear nothing at all. Values are rounded to the nearest 5 m. Only affects the 3rd-person sound; your own typing is not positional and is unaffected.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 50), Array.Empty<object>()));
			Redirect.Recalculate();
			StartConfigWatcher();
			_harmony = new Harmony("Oxylight.SpeedrunTypingSound");
			_harmony.PatchAll(typeof(Patch_Post_Global));
			_harmony.PatchAll(typeof(Patch_Post_Positional));
			ManualLogSource logger = Logger;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(10, 2, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("SpeedrunTypingSound");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" v");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("1.0.0");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" loaded.");
			}
			logger.LogInfo(val);
		}

		private void StartConfigWatcher()
		{
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Expected O, but got Unknown
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Expected O, but got Unknown
			bool flag = default(bool);
			try
			{
				string configFilePath = ((BasePlugin)this).Config.ConfigFilePath;
				string directoryName = Path.GetDirectoryName(configFilePath);
				if (string.IsNullOrEmpty(directoryName))
				{
					return;
				}
				_watcher = new FileSystemWatcher(directoryName, Path.GetFileName(configFilePath))
				{
					NotifyFilter = (NotifyFilters.Size | NotifyFilters.LastWrite),
					EnableRaisingEvents = true
				};
				_watcher.Changed += delegate
				{
					//IL_001b: Unknown result type (might be due to invalid IL or missing references)
					//IL_0021: Expected O, but got Unknown
					try
					{
						((BasePlugin)this).Config.Reload();
					}
					catch (IOException)
					{
					}
					catch (Exception ex3)
					{
						ManualLogSource logger3 = Logger;
						bool flag2 = default(bool);
						BepInExWarningLogInterpolatedStringHandler val3 = new BepInExWarningLogInterpolatedStringHandler(22, 1, ref flag2);
						if (flag2)
						{
							((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("Config reload failed: ");
							((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(ex3.Message);
						}
						logger3.LogWarning(val3);
					}
				};
				ManualLogSource logger = Logger;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(34, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Watching ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(Path.GetFileName(configFilePath));
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" for live volume changes.");
				}
				logger.LogInfo(val);
			}
			catch (Exception ex)
			{
				ManualLogSource logger2 = Logger;
				BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(61, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Could not watch the config file, volume will need a restart: ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.Message);
				}
				logger2.LogWarning(val2);
			}
		}

		public override bool Unload()
		{
			_watcher?.Dispose();
			Harmony? harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			return ((BasePlugin)this).Unload();
		}
	}
}