using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using System.Threading; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using Concentus.Celt; using Concentus.Celt.Structs; using Concentus.Common; using Concentus.Common.CPlusPlus; using Concentus.Enums; using Concentus.Silk; using Concentus.Silk.Enums; using Concentus.Silk.Structs; using Concentus.Structs; using HarmonyLib; using JetBrains.Annotations; using LocalizationManager; using Microsoft.CodeAnalysis; using ProximityVoiceChat.UI; using ProximityVoiceChat.Voice; using ProximityVoiceChat.Voice.Audio; using ServerSync; using Splatform; using Steamworks; using TMPro; using UIManager; using UnityEngine; using UnityEngine.Audio; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.SceneManagement; using UnityEngine.U2D; using UnityEngine.UI; using UserManagement; using Valheim.SettingsGui; using Valheim.UI; using YamlDotNet.Core; using YamlDotNet.Core.Events; using YamlDotNet.Core.ObjectPool; using YamlDotNet.Core.Tokens; using YamlDotNet.Helpers; using YamlDotNet.Serialization; using YamlDotNet.Serialization.BufferedDeserialization; using YamlDotNet.Serialization.BufferedDeserialization.TypeDiscriminators; using YamlDotNet.Serialization.Callbacks; using YamlDotNet.Serialization.Converters; using YamlDotNet.Serialization.EventEmitters; using YamlDotNet.Serialization.NamingConventions; using YamlDotNet.Serialization.NodeDeserializers; using YamlDotNet.Serialization.NodeTypeResolvers; using YamlDotNet.Serialization.ObjectFactories; using YamlDotNet.Serialization.ObjectGraphTraversalStrategies; using YamlDotNet.Serialization.ObjectGraphVisitors; using YamlDotNet.Serialization.Schemas; using YamlDotNet.Serialization.TypeInspectors; using YamlDotNet.Serialization.TypeResolvers; using YamlDotNet.Serialization.Utilities; using YamlDotNet.Serialization.ValueDeserializers; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("ProximityVoiceChat")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Azumatt")] [assembly: AssemblyProduct("ProximityVoiceChat")] [assembly: AssemblyCopyright("Copyright © 2022")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("E0E2F92E-557C-4A05-9D89-AA92A0BD75C4")] [assembly: AssemblyFileVersion("1.0.2")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.2.0")] [module: UnverifiableCode] [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; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class ExtensionMarkerAttribute : Attribute { public ExtensionMarkerAttribute(string name) { } } } namespace ProximityVoiceChat { [BepInPlugin("Azumatt.ProximityVoiceChat", "ProximityVoiceChat", "1.0.2")] public class ProximityVoiceChatPlugin : BaseUnityPlugin { public enum Toggle { On = 1, Off = 0 } public enum Bone { X, Y, Z } private class AcceptableShortcuts : AcceptableValueBase { public AcceptableShortcuts() : base(typeof(KeyboardShortcut)) { } public override object Clamp(object value) { return value; } public override bool IsValid(object value) { return true; } public override string ToDescriptionString() { return "# Acceptable values: " + string.Join(", ", UnityInput.Current.SupportedKeyCodes); } } private class ConfigurationManagerAttributes { [UsedImplicitly] public int? Order; [UsedImplicitly] public bool? Browsable; [UsedImplicitly] public string? Category; [UsedImplicitly] public Action? CustomDrawer; } internal const string ModName = "ProximityVoiceChat"; internal const string ModVersion = "1.0.2"; internal const string Author = "Azumatt"; private const string ModGUID = "Azumatt.ProximityVoiceChat"; private static readonly string ConfigFileName = "Azumatt.ProximityVoiceChat.cfg"; private static readonly string ConfigFileFullPath = Paths.ConfigPath + Path.DirectorySeparatorChar + ConfigFileName; private readonly Harmony _harmony = new Harmony("Azumatt.ProximityVoiceChat"); private static GameObject _runtimeObject = null; internal static ProximityVoiceChatPlugin? Instance; public static readonly ManualLogSource Log = Logger.CreateLogSource("ProximityVoiceChat"); private static readonly ConfigSync ConfigSync = new ConfigSync("Azumatt.ProximityVoiceChat") { DisplayName = "ProximityVoiceChat", CurrentVersion = "1.0.2", MinimumRequiredVersion = "1.0.2", IsLocked = false }; private static ConfigEntry _serverConfigLocked = null; internal static ConfigEntry MaxRange = null; internal static ConfigEntry RangeHysteresis = null; internal static ConfigEntry FullVolumeRange = null; internal static ConfigEntry EnableVoice = null; internal static ConfigEntry InputDevice = null; internal static ConfigEntry MuteSelf = null; internal static ConfigEntry MuteSelfKey = null; internal static ConfigEntry UseVoiceActivation = null; internal static ConfigEntry PushToTalkKey = null; internal static ConfigEntry ActivationThreshold = null; internal static ConfigEntry MicGain = null; internal static ConfigEntry AutoGain = null; internal static ConfigEntry AutoGainTarget = null; internal static ConfigEntry Bitrate = null; internal static ConfigEntry ExpectedPacketLoss = null; internal static ConfigEntry UseDtx = null; internal static ConfigEntry AdaptiveFec = null; internal static ConfigEntry VoiceVolume = null; internal static ConfigEntry Deafen = null; internal static ConfigEntry DeafenKey = null; internal static ConfigEntry MonitorVolume = null; internal static ConfigEntry JitterTargetMs = null; internal static ConfigEntry JitterMaxMs = null; internal static ConfigEntry AdaptiveJitter = null; internal static ConfigEntry DuckMusic = null; internal static ConfigEntry DuckMusicAmount = null; internal static ConfigEntry Occlusion = null; internal static ConfigEntry OccludedCutoff = null; internal static ConfigEntry OccludedVolume = null; internal static ConfigEntry UnderwaterMuffle = null; internal static ConfigEntry UnderwaterCutoff = null; internal static ConfigEntry VoiceReverb = null; internal static ConfigEntry ReverbMix = null; internal static ConfigEntry ShowSpeakingIndicator = null; internal static ConfigEntry SpeakingIndicatorHeight = null; internal static ConfigEntry PeerIndicators = null; internal static ConfigEntry PeerIndicatorHeight = null; internal static ConfigEntry PeerIndicatorScale = null; internal static ConfigEntry PeerIndicatorThroughWalls = null; internal static ConfigEntry JawMovement = null; internal static ConfigEntry JawMaxAngle = null; internal static ConfigEntry JawSensitivity = null; internal static ConfigEntry JawAxis = null; internal static ConfigEntry HotkeyMessages = null; internal static ConfigEntry TestTone = null; internal static ConfigEntry LoopbackTest = null; internal static ConfigEntry PerPlayerSettings = null; public void Awake() { //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Expected O, but got Unknown //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Expected O, but got Unknown //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Expected O, but got Unknown //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Expected O, but got Unknown //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_01d4: Expected O, but got Unknown //IL_0202: Unknown result type (might be due to invalid IL or missing references) //IL_020d: Expected O, but got Unknown //IL_023b: Unknown result type (might be due to invalid IL or missing references) //IL_0246: Expected O, but got Unknown //IL_0290: Unknown result type (might be due to invalid IL or missing references) //IL_029b: Expected O, but got Unknown //IL_02c9: Unknown result type (might be due to invalid IL or missing references) //IL_02d4: Expected O, but got Unknown //IL_02f7: Unknown result type (might be due to invalid IL or missing references) //IL_0302: Expected O, but got Unknown //IL_0368: Unknown result type (might be due to invalid IL or missing references) //IL_0373: Expected O, but got Unknown //IL_03a5: Unknown result type (might be due to invalid IL or missing references) //IL_03b9: Unknown result type (might be due to invalid IL or missing references) //IL_03c4: Expected O, but got Unknown //IL_03f2: Unknown result type (might be due to invalid IL or missing references) //IL_03fd: Expected O, but got Unknown //IL_0425: Unknown result type (might be due to invalid IL or missing references) //IL_0430: Expected O, but got Unknown //IL_045b: Unknown result type (might be due to invalid IL or missing references) //IL_0466: Expected O, but got Unknown //IL_04cc: Unknown result type (might be due to invalid IL or missing references) //IL_04d7: Expected O, but got Unknown //IL_0521: Unknown result type (might be due to invalid IL or missing references) //IL_052c: Expected O, but got Unknown //IL_055a: Unknown result type (might be due to invalid IL or missing references) //IL_0565: Expected O, but got Unknown //IL_05af: Unknown result type (might be due to invalid IL or missing references) //IL_05ba: Expected O, but got Unknown //IL_0604: Unknown result type (might be due to invalid IL or missing references) //IL_060f: Expected O, but got Unknown //IL_0659: Unknown result type (might be due to invalid IL or missing references) //IL_0664: Expected O, but got Unknown //IL_06ae: Unknown result type (might be due to invalid IL or missing references) //IL_06b9: Expected O, but got Unknown //IL_06e7: Unknown result type (might be due to invalid IL or missing references) //IL_06f2: Expected O, but got Unknown //IL_0758: Unknown result type (might be due to invalid IL or missing references) //IL_0763: Expected O, but got Unknown //IL_0791: Unknown result type (might be due to invalid IL or missing references) //IL_079c: Expected O, but got Unknown //IL_0841: Unknown result type (might be due to invalid IL or missing references) //IL_084c: Expected O, but got Unknown //IL_088b: Unknown result type (might be due to invalid IL or missing references) //IL_0895: Expected O, but got Unknown Instance = this; Localizer.Load(); bool saveOnConfigSet = ((BaseUnityPlugin)this).Config.SaveOnConfigSet; ((BaseUnityPlugin)this).Config.SaveOnConfigSet = false; _serverConfigLocked = config("1 - General", "Lock Configuration", Toggle.On, "If on, only server admins can change the synced settings."); ConfigSync.AddLockingConfigEntry(_serverConfigLocked); MaxRange = config("2 - Proximity", "Max Range", 45f, new ConfigDescription("Max distance you can hear other players", (AcceptableValueBase)(object)new AcceptableValueRange(10f, 200f), Array.Empty())); RangeHysteresis = config("2 - Proximity", "Range Buffer", 8f, new ConfigDescription("Extra distance before a player disconnects from voice. Helps prevent audio cutting in and out near max range.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 50f), Array.Empty())); FullVolumeRange = config("2 - Proximity", "Full Volume Range", 4f, new ConfigDescription("Players within this distance are heard at full volume. Beyond it, volume fades with distance.", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 40f), Array.Empty())); EnableVoice = config("3 - Microphone", "Enable Voice", Toggle.On, "Turn microphone capture off entirely.", synchronizedSetting: false); InputDevice = config("3 - Microphone", "Input Device", "", "Microphone to use. Leave blank to use your system default.", synchronizedSetting: false); MuteSelf = config("3 - Microphone", "Mute Self", Toggle.Off, "Stops sending your voice without turning off the microphone.", synchronizedSetting: false); MuteSelfKey = config("3 - Microphone", "Mute Self Key", new KeyboardShortcut((KeyCode)0, Array.Empty()), new ConfigDescription("Toggles your microphone mute. Unbound by default to avoid conflicts with other mods.", (AcceptableValueBase)(object)new AcceptableShortcuts(), Array.Empty()), synchronizedSetting: false); UseVoiceActivation = config("3 - Microphone", "Use Voice Activation", Toggle.Off, "Automatically transmits when you speak. Turn this off to use push-to-talk.", synchronizedSetting: false); PushToTalkKey = config("3 - Microphone", "Push To Talk", new KeyboardShortcut((KeyCode)98, Array.Empty()), new ConfigDescription("Hold this key to talk when Voice Activation is off.", (AcceptableValueBase)(object)new AcceptableShortcuts(), Array.Empty()), synchronizedSetting: false); ActivationThreshold = config("3 - Microphone", "Activation Threshold", 0.02f, new ConfigDescription("How loud you need to speak before voice activation starts transmitting. Lower values are more sensitive.", (AcceptableValueBase)(object)new AcceptableValueRange(0.001f, 0.3f), Array.Empty()), synchronizedSetting: false); MicGain = config("3 - Microphone", "Microphone Gain", 1f, new ConfigDescription("Boosts or lowers your microphone volume before it is sent. Checked before encoding", (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 8f), Array.Empty()), synchronizedSetting: false); AutoGain = config("3 - Microphone", "Auto Gain", Toggle.On, "Chases a steady speaking level so you do not have to hunt for a gain number. Microphone Gain still multiplies on top.", synchronizedSetting: false); AutoGainTarget = config("3 - Microphone", "Auto Gain Target", 0.12f, new ConfigDescription("Target speaking volume used by Automatic Gain. Higher values make your voice louder.", (AcceptableValueBase)(object)new AcceptableValueRange(0.02f, 0.4f), Array.Empty()), synchronizedSetting: false); Bitrate = config("4 - Codec", "Bitrate", 24000, new ConfigDescription("Opus target bitrate in bits per second. Voice quality and bandwidth usage. Higher is better but uses more bandwidth.", (AcceptableValueBase)(object)new AcceptableValueRange(6000, 64000), Array.Empty())); ExpectedPacketLoss = config("4 - Codec", "Expected Packet Loss", 5, new ConfigDescription("How much packet loss Opus should expect. Higher values use more error correction.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 40), Array.Empty())); UseDtx = config("4 - Codec", "Use DTX", Toggle.Off, "Stops sending audio while you are silent. Saves bandwidth, but very quiet words may get cut off."); AdaptiveFec = config("4 - Codec", "Adaptive FEC", Toggle.On, "Adds more error correction when other players report lost audio packets.", synchronizedSetting: false); VoiceVolume = config("5 - Playback", "Voice Volume", 1f, new ConfigDescription("Overall volume of voice chat.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 3f), Array.Empty()), synchronizedSetting: false); Deafen = config("5 - Playback", "Deafen", Toggle.Off, "Stops all incoming voice and stops you transmitting.", synchronizedSetting: false); DeafenKey = config("5 - Playback", "Deafen Key", new KeyboardShortcut((KeyCode)0, Array.Empty()), new ConfigDescription("Toggles Deafen. Unbound by default to avoid conflicts with other mods.", (AcceptableValueBase)(object)new AcceptableShortcuts(), Array.Empty()), synchronizedSetting: false); MonitorVolume = config("5 - Playback", "Monitor Volume", 0.7f, new ConfigDescription("How loudly you hear yourself while Hear Myself While I Talk is enabled.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 2f), Array.Empty()), synchronizedSetting: false); JitterTargetMs = config("5 - Playback", "Jitter Buffer Target", 60, new ConfigDescription("Audio buffered to smooth out network hiccups. Lower means less delay; higher is more stable.", (AcceptableValueBase)(object)new AcceptableValueRange(20, 300), Array.Empty()), synchronizedSetting: false); JitterMaxMs = config("5 - Playback", "Jitter Buffer Max", 200, new ConfigDescription("Maximum buffer size allowed when Automatic Voice Buffer is enabled.", (AcceptableValueBase)(object)new AcceptableValueRange(40, 600), Array.Empty()), synchronizedSetting: false); AdaptiveJitter = config("5 - Playback", "Adaptive Jitter", Toggle.On, "Automatically adjusts each player's audio buffer based on their connection.", synchronizedSetting: false); DuckMusic = config("5 - Playback", "Duck Music", Toggle.On, "Lowers Valheim's music while a nearby player is speaking.", synchronizedSetting: false); DuckMusicAmount = config("5 - Playback", "Duck Music Amount", 0.35f, new ConfigDescription("Music volume while someone is speaking. 0 is silent, 1 is unchanged.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty()), synchronizedSetting: false); Occlusion = config("5 - Playback", "Occlusion", Toggle.On, "Makes voices quieter and muffled when something solid is between you.", synchronizedSetting: false); OccludedCutoff = config("5 - Playback", "Occluded Cutoff", 900f, new ConfigDescription("How muffled voices sound through walls. Lower values sound more muffled.", (AcceptableValueBase)(object)new AcceptableValueRange(200f, 8000f), Array.Empty()), synchronizedSetting: false); OccludedVolume = config("5 - Playback", "Occluded Volume", 0.7f, new ConfigDescription("Volume of voices heard through walls. 1 is full volume.", (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 1f), Array.Empty()), synchronizedSetting: false); UnderwaterMuffle = config("5 - Playback", "Underwater Muffle", Toggle.On, "Muffles voice chat while you are swimming.", synchronizedSetting: false); UnderwaterCutoff = config("5 - Playback", "Underwater Cutoff", 500f, new ConfigDescription("How muffled voices sound underwater. Lower values sound more muffled.", (AcceptableValueBase)(object)new AcceptableValueRange(150f, 4000f), Array.Empty()), synchronizedSetting: false); VoiceReverb = config("5 - Playback", "Voice Reverb", Toggle.Off, "Let the game's reverb zones colour voices, so caves and halls sound like caves and halls.", synchronizedSetting: false); ReverbMix = config("5 - Playback", "Reverb Mix", 0.3f, new ConfigDescription("How much of the game's reverb a voice picks up. A full send drowns speech in echo.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty()), synchronizedSetting: false); ShowSpeakingIndicator = config("6 - UI", "Speaking Indicator", Toggle.On, "Shows a speaker icon above your character while you are transmitting.", synchronizedSetting: false); SpeakingIndicatorHeight = config("6 - UI", "Speaking Indicator Height", 0.5f, new ConfigDescription("How high the speaker icon sits above your head.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 2f), Array.Empty()), synchronizedSetting: false); PeerIndicators = config("6 - UI", "Peer Speaking Indicators", Toggle.Off, "Shows a speaker icon above other players while they are talking.", synchronizedSetting: false); PeerIndicatorHeight = config("6 - UI", "Peer Indicator Height", 0.9f, new ConfigDescription("How high speaker icons sit above other players.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 3f), Array.Empty()), synchronizedSetting: false); PeerIndicatorScale = config("6 - UI", "Peer Indicator Scale", 1f, new ConfigDescription("Size of the speaker icons shown above other players.", (AcceptableValueBase)(object)new AcceptableValueRange(0.3f, 3f), Array.Empty()), synchronizedSetting: false); PeerIndicatorThroughWalls = config("6 - UI", "Peer Indicator Through Walls", Toggle.Off, "Keeps speaking indicators visible even when a wall is between you.", synchronizedSetting: false); JawMovement = config("6 - UI", "Jaw Movement", Toggle.On, "Moves player jaws while they are speaking. Yours and others.", synchronizedSetting: false); JawMaxAngle = config("6 - UI", "Jaw Max Angle", 14f, new ConfigDescription("Maximum amount the jaw opens while speaking.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 40f), Array.Empty()), synchronizedSetting: false); JawSensitivity = config("6 - UI", "Jaw Sensitivity", 12f, new ConfigDescription("How strongly voice volume moves the jaw. Raise this if mouths barely move.", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 60f), Array.Empty()), synchronizedSetting: false); JawAxis = config("6 - UI", "Jaw Axis", Bone.X, "Change this if the head twists instead of the mouth opening. Default is good for Valheim model, but might not be for VRMs", synchronizedSetting: false); HotkeyMessages = config("6 - UI", "Hotkey Messages", Toggle.On, "Shows a short message when you mute or deafen yourself with a hotkey.", synchronizedSetting: false); TestTone = config("6 - UI", "Test Tone", Toggle.Off, "Sends a test tone instead of microphone audio. Useful for testing without a working microphone.", synchronizedSetting: false); LoopbackTest = config("6 - UI", "Loopback Test", Toggle.Off, "Plays your outgoing voice back to you so you can hear what other players hear.", synchronizedSetting: false); PerPlayerSettings = config("6 - UI", "Per Player Settings", "", new ConfigDescription("Saved data. Don't write here manually, unless you know what you're doing. Written by the player list. steamid:volume:muted, semicolon separated.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Browsable = false } }), synchronizedSetting: false); TestTone.Value = Toggle.Off; LoopbackTest.Value = Toggle.Off; PeerPreferences.Load(PerPlayerSettings.Value); _harmony.PatchAll(Assembly.GetExecutingAssembly()); _runtimeObject = new GameObject("ProximityVoiceChat_Runtime"); Object.DontDestroyOnLoad((Object)(object)_runtimeObject); ((Object)_runtimeObject).hideFlags = (HideFlags)61; _runtimeObject.AddComponent(); _runtimeObject.AddComponent(); _runtimeObject.AddComponent(); _runtimeObject.AddComponent(); UIRoot.Init(Log, _harmony); SetupWatcher(); ((BaseUnityPlugin)this).Config.Save(); if (saveOnConfigSet) { ((BaseUnityPlugin)this).Config.SaveOnConfigSet = saveOnConfigSet; } } private void OnDestroy() { if ((Object)(object)_runtimeObject != (Object)null) { Object.Destroy((Object)(object)_runtimeObject); } if (PeerPreferences.TryFlush(out string serialized)) { PerPlayerSettings.Value = serialized; } ((BaseUnityPlugin)this).Config.Save(); } internal static void SaveConfig() { if (PeerPreferences.TryFlush(out string serialized)) { PerPlayerSettings.Value = serialized; } ProximityVoiceChatPlugin? instance = Instance; if (instance != null) { ((BaseUnityPlugin)instance).Config.Save(); } } private void SetupWatcher() { FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(Paths.ConfigPath, ConfigFileName); fileSystemWatcher.Changed += ReadConfigValues; fileSystemWatcher.Created += ReadConfigValues; fileSystemWatcher.Renamed += ReadConfigValues; fileSystemWatcher.IncludeSubdirectories = true; fileSystemWatcher.SynchronizingObject = ThreadingHelper.SynchronizingObject; fileSystemWatcher.EnableRaisingEvents = true; } private void ReadConfigValues(object sender, FileSystemEventArgs e) { if (!File.Exists(ConfigFileFullPath)) { return; } try { Log.LogDebug((object)"ReadConfigValues called"); ((BaseUnityPlugin)this).Config.Reload(); } catch { Log.LogError((object)("There was an issue loading your " + ConfigFileName)); Log.LogError((object)"Please check your config entries for spelling and format!"); } } private ConfigEntry config(string group, string name, T value, ConfigDescription description, bool synchronizedSetting = true) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown ConfigDescription val = new ConfigDescription(description.Description + (synchronizedSetting ? " [Synced with Server]" : " [Not Synced with Server]"), description.AcceptableValues, description.Tags); ConfigEntry val2 = ((BaseUnityPlugin)this).Config.Bind(group, name, value, val); ConfigSync.AddConfigEntry(val2).SynchronizedConfig = synchronizedSetting; return val2; } private ConfigEntry config(string group, string name, T value, string description, bool synchronizedSetting = true) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown return config(group, name, value, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty()), synchronizedSetting); } } public static class KeyboardExtensions { [SpecialName] public sealed class $8D1D3E80A18AA9715780B6CB7003B2F1 { [SpecialName] public static class $895AB635D4D087636CF1C26BA650BA11 { } [ExtensionMarker("$895AB635D4D087636CF1C26BA650BA11")] public bool IsKeyDown() { throw null; } [ExtensionMarker("$895AB635D4D087636CF1C26BA650BA11")] public bool IsKeyHeld() { throw null; } } public static bool IsKeyDown(this KeyboardShortcut shortcut) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) if ((int)((KeyboardShortcut)(ref shortcut)).MainKey != 0 && Input.GetKeyDown(((KeyboardShortcut)(ref shortcut)).MainKey)) { return ((KeyboardShortcut)(ref shortcut)).Modifiers.All((Func)Input.GetKey); } return false; } public static bool IsKeyHeld(this KeyboardShortcut shortcut) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) if ((int)((KeyboardShortcut)(ref shortcut)).MainKey != 0 && Input.GetKey(((KeyboardShortcut)(ref shortcut)).MainKey)) { return ((KeyboardShortcut)(ref shortcut)).Modifiers.All((Func)Input.GetKey); } return false; } } public static class ToggleExtensions { [SpecialName] public sealed class $BDF3EF541E575CBEE3FDDD5BBDE7E281 { [SpecialName] public static class $E3FDBDD135D264042C5DDA2535FB9962 { } [ExtensionMarker("$E3FDBDD135D264042C5DDA2535FB9962")] public bool IsOn() { throw null; } [ExtensionMarker("$E3FDBDD135D264042C5DDA2535FB9962")] public bool IsOff() { throw null; } } public static bool IsOn(this ProximityVoiceChatPlugin.Toggle toggle) { return toggle == ProximityVoiceChatPlugin.Toggle.On; } public static bool IsOff(this ProximityVoiceChatPlugin.Toggle toggle) { return toggle == ProximityVoiceChatPlugin.Toggle.Off; } } } namespace ProximityVoiceChat.UI { internal static class SettingsTabInjector { internal const string TabLabel = "Voice"; internal static void Inject(Settings? settings) { //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_0200: Unknown result type (might be due to invalid IL or missing references) //IL_0206: Unknown result type (might be due to invalid IL or missing references) //IL_020d: Expected O, but got Unknown //IL_0210: Unknown result type (might be due to invalid IL or missing references) //IL_021d: Unknown result type (might be due to invalid IL or missing references) //IL_022a: Unknown result type (might be due to invalid IL or missing references) //IL_0237: Unknown result type (might be due to invalid IL or missing references) //IL_0244: Unknown result type (might be due to invalid IL or missing references) //IL_0250: Unknown result type (might be due to invalid IL or missing references) //IL_025a: Unknown result type (might be due to invalid IL or missing references) //IL_026d: Unknown result type (might be due to invalid IL or missing references) //IL_0272: Unknown result type (might be due to invalid IL or missing references) //IL_0279: Unknown result type (might be due to invalid IL or missing references) //IL_0281: Unknown result type (might be due to invalid IL or missing references) //IL_0288: Unknown result type (might be due to invalid IL or missing references) //IL_0289: Unknown result type (might be due to invalid IL or missing references) //IL_0293: Expected O, but got Unknown //IL_0298: Expected O, but got Unknown if ((Object)(object)settings == (Object)null) { return; } TabHandler val = (((Object)(object)settings.m_tabHandler != (Object)null) ? settings.m_tabHandler : ((Component)settings).GetComponentInChildren()); if ((Object)(object)val == (Object)null) { ProximityVoiceChatPlugin.Log.LogWarning((object)"Voice tab: no TabHandler in the settings prefab"); return; } if (val.m_tabs.Count == 0) { ProximityVoiceChatPlugin.Log.LogWarning((object)"Voice tab: settings prefab has no tabs"); return; } foreach (Tab tab in val.m_tabs) { if ((Object)(object)tab.m_button != (Object)null && ((Object)tab.m_button).name == "Voice") { return; } } Button val2 = null; RectTransform val3 = null; foreach (Tab tab2 in val.m_tabs) { if ((Object)(object)tab2.m_button != (Object)null) { val2 = tab2.m_button; } if ((Object)(object)tab2.m_page != (Object)null && (Object)(object)val3 == (Object)null) { val3 = tab2.m_page; } } if ((Object)(object)val2 == (Object)null || (Object)(object)val3 == (Object)null) { ProximityVoiceChatPlugin.Log.LogWarning((object)$"Voice tab: no usable template, button {(Object)(object)val2 != (Object)null}, page {(Object)(object)val3 != (Object)null}"); return; } Button val4 = Object.Instantiate