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();
}
}
}