The BepInEx console will not appear when launching like it does for other games on Thunderstore (you can turn it back on in your BepInEx.cfg file). If your PEAK crashes on startup, add -dx12 to your launch parameters.
Decompiled source of PEAK Voice Volume Saver v0.2.0
VoiceVolumeSaver.dll
Decompiled 2 months agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using TMPro; using UnityEngine; [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("VoiceVolumeSaver")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+0a3938f61ae36e802e8a9733c06b5a5d15e57542")] [assembly: AssemblyProduct("Voice Volume Saver")] [assembly: AssemblyTitle("VoiceVolumeSaver")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [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 VoiceVolumeSaver { [BepInPlugin("VoiceVolumeSaver", "Voice Volume Saver", "1.0.0")] public class Plugin : BaseUnityPlugin { public class InitPatch { [HarmonyPatch(typeof(AudioLevelSlider), "Init")] [HarmonyPostfix] private static void Postfix(AudioLevelSlider __instance) { if (__instance.player != null) { Logger.LogInfo((object)("Player Joined: " + __instance.player.NickName)); if (__instance.player != null && !__instance.player.IsLocal && _voiceVolumes.TryGetValue(__instance.player.NickName, out var value)) { Logger.LogInfo((object)$"Player Volume: {value}"); AudioLevels.SetPlayerLevel(__instance.player.ActorNumber, value); __instance.slider.SetValueWithoutNotify(AudioLevels.GetPlayerLevel(__instance.player.ActorNumber)); ((TMP_Text)__instance.percent).text = Mathf.RoundToInt(__instance.slider.value * 200f) + "%"; } } } } public class OnSliderChangedPatch { [HarmonyPatch(typeof(AudioLevelSlider), "OnSliderChanged")] [HarmonyPostfix] private static void Postfix(float newValue, AudioLevelSlider __instance) { if (__instance.player != null) { Logger.LogInfo((object)$"Player saving: {__instance.player.NickName} {newValue}"); if (_voiceVolumes.ContainsKey(__instance.player.NickName)) { _voiceVolumes[__instance.player.NickName] = newValue; } else { _voiceVolumes.Add(__instance.player.NickName, newValue); } plugin.SaveDictionaryToConfig(); } } } internal static ManualLogSource Logger; private readonly Harmony _harmony = new Harmony("VoiceVolumeSaver"); private static Dictionary<string, float> _voiceVolumes = new Dictionary<string, float>(); private static ConfigEntry<string> configDictionary; private static Plugin plugin; private void Awake() { plugin = this; configDictionary = ((BaseUnityPlugin)this).Config.Bind<string>("General", "SavedData", "", "Serialized key=value pairs"); Logger = ((BaseUnityPlugin)this).Logger; if (configDictionary.Value != "") { LoadDictionaryFromConfig(); } Logger.LogInfo((object)"Plugin VoiceVolumeSaver is patching Init!"); _harmony.PatchAll(typeof(InitPatch)); Logger.LogInfo((object)"Plugin VoiceVolumeSaver is patching OnSliderChanged!"); _harmony.PatchAll(typeof(OnSliderChangedPatch)); Logger.LogInfo((object)"Plugin VoiceVolumeSaver has finished loading!"); } private void LoadDictionaryFromConfig() { _voiceVolumes = DeserializeDictionary(configDictionary.Value); } public static Dictionary<string, float> DeserializeDictionary(string data) { Logger.LogInfo((object)"Plugin VoiceVolumeSaver is deserializing data!"); Dictionary<string, float> dictionary = new Dictionary<string, float>(); if (string.IsNullOrWhiteSpace(data)) { return dictionary; } string[] array = data.Split(new char[1] { ';' }); string[] array2 = array; foreach (string text in array2) { string[] array3 = text.Split(new char[1] { '=' }); if (array3.Length == 2) { string key = array3[0]; if (float.TryParse(array3[1], out var result)) { dictionary[key] = result; } } } return dictionary; } public string SerializeDictionary() { Logger.LogInfo((object)"Plugin VoiceVolumeSaver is serializing data!"); return string.Join(";", _voiceVolumes.Select((KeyValuePair<string, float> kvp) => $"{kvp.Key}={kvp.Value}")); } private void SaveDictionaryToConfig() { Logger.LogInfo((object)"Plugin VoiceVolumeSaver is pre serializing data!"); configDictionary.Value = SerializeDictionary(); ((BaseUnityPlugin)this).Config.Save(); } } public static class MyPluginInfo { public const string PLUGIN_GUID = "VoiceVolumeSaver"; public const string PLUGIN_NAME = "Voice Volume Saver"; public const string PLUGIN_VERSION = "1.0.0"; } }