using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; 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 Photon.Voice; using Photon.Voice.Unity; 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: AssemblyCompany("MicGain")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("MicGain")] [assembly: AssemblyTitle("MicGain")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.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 MicGain { public class ModConfig { public readonly ConfigEntry Gain; public ModConfig(ConfigFile cfg) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown cfg.SaveOnConfigSet = false; Gain = cfg.Bind("General", "Mic Gain", 1f, new ConfigDescription("Microphone gain multiplier. 1.0 = normal, 0.5 = half volume, 0.0 = muted.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 2f), Array.Empty())); ClearOrphanedEntries(cfg); cfg.Save(); cfg.SaveOnConfigSet = true; } private static void ClearOrphanedEntries(ConfigFile cfg) { ((Dictionary)AccessTools.Property(typeof(ConfigFile), "OrphanedEntries").GetValue(cfg)).Clear(); } } public class GainProcessorFloat : IProcessor, IDisposable { public Func GetGain; public float[] Process(float[] buf) { float num = GetGain(); if (Math.Abs(num - 1f) < 0.001f) { return buf; } for (int i = 0; i < buf.Length; i++) { buf[i] *= num; } return buf; } public void Dispose() { } } public class GainProcessorShort : IProcessor, IDisposable { public Func GetGain; public short[] Process(short[] buf) { float num = GetGain(); if (Math.Abs(num - 1f) < 0.001f) { return buf; } for (int i = 0; i < buf.Length; i++) { buf[i] = (short)Math.Max(-32768f, Math.Min(32767f, (float)buf[i] * num)); } return buf; } public void Dispose() { } } [HarmonyPatch(typeof(CharacterVoiceHandler), "Start")] public static class PatchVoiceHandlerStart { [CompilerGenerated] private sealed class d__1 : IEnumerator, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public Recorder recorder; private float 5__2; private float 5__3; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__1(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; 5__2 = 30f; 5__3 = 0f; break; case 1: { <>1__state = -1; 5__3 += 0.5f; object value = Traverse.Create((object)recorder).Field("voice").GetValue(); if (value == null) { break; } Type type = value.GetType(); if (type.Name.Contains("Dummy")) { break; } MethodInfo methodInfo = null; Type type2 = type; while (type2 != null && methodInfo == null) { methodInfo = type2.GetMethod("AddPostProcessor", BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public); type2 = type2.BaseType; } if (methodInfo == null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)"AddPostProcessor not found on LocalVoice."); } return false; } bool flag = type.FullName.Contains("Short"); try { if (flag) { GainProcessorShort value2 = new GainProcessorShort { GetGain = () => Plugin.BoundConfig.Gain.Value }; Array array = Array.CreateInstance(typeof(IProcessor), 1); array.SetValue(value2, 0); methodInfo.Invoke(value, new object[1] { array }); } else { GainProcessorFloat value3 = new GainProcessorFloat { GetGain = () => Plugin.BoundConfig.Gain.Value }; Array array2 = Array.CreateInstance(typeof(IProcessor), 1); array2.SetValue(value3, 0); methodInfo.Invoke(value, new object[1] { array2 }); } ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)("Gain processor injected successfully! (type: " + (flag ? "short" : "float") + ")")); } } catch (Exception arg) { ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogError((object)$"Failed to invoke AddPostProcessor: {arg}"); } } return false; } } if (5__3 < 5__2) { <>2__current = (object)new WaitForSeconds(0.5f); <>1__state = 1; return true; } ManualLogSource log4 = Plugin.Log; if (log4 != null) { log4.LogWarning((object)"Timed out waiting for real LocalVoice."); } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private static void Postfix(CharacterVoiceHandler __instance) { try { Character componentInParent = ((Component)__instance).GetComponentInParent(); if (!((Object)(object)componentInParent == (Object)null) && componentInParent.IsLocal) { Recorder component = ((Component)__instance).GetComponent(); if (!((Object)(object)component == (Object)null)) { ((MonoBehaviour)Plugin.Instance).StartCoroutine(WaitAndInjectProcessor(component)); } } } catch (Exception arg) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)$"MicGain patch error: {arg}"); } } } [IteratorStateMachine(typeof(d__1))] private static IEnumerator WaitAndInjectProcessor(Recorder recorder) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__1(0) { recorder = recorder }; } } [BepInPlugin("MicGain", "MicGain", "1.0.0")] public class Plugin : BaseUnityPlugin { public const string Id = "MicGain"; private readonly Harmony harmony = new Harmony("MicGain"); internal static ManualLogSource Log { get; private set; } internal static Plugin Instance { get; private set; } internal static ModConfig BoundConfig { get; private set; } private void Awake() { if ((Object)(object)Instance != (Object)null && (Object)(object)Instance != (Object)(object)this) { Object.Destroy((Object)(object)this); return; } Instance = this; Log = ((BaseUnityPlugin)this).Logger; BoundConfig = new ModConfig(((BaseUnityPlugin)this).Config); harmony.PatchAll(); Log.LogInfo((object)"MicGain loaded."); } } }