Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of Join Notifier v1.1.1
JoinNotifier.dll
Decompiled 3 months agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; 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 Photon.Realtime; using UnityEngine; using UnityEngine.Audio; using UnityEngine.Networking; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: IgnoresAccessChecksTo("")] [assembly: AssemblyCompany("Omniscye")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("JoinNotifier")] [assembly: AssemblyTitle("JoinNotifier")] [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.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] [Microsoft.CodeAnalysis.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] [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 JoinNotifier { [BepInPlugin("Omniscye.JoinNotifier", "JoinNotifier", "1.1.1")] public class JoinNotifier : BaseUnityPlugin { [CompilerGenerated] private sealed class <LoadClipFromConfig>d__26 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public JoinNotifier <>4__this; private string <resolved>5__1; private string <ext>5__2; private AudioType <at>5__3; private string <uri>5__4; private string <path>5__5; private string <dllDir>5__6; private Exception <ex>5__7; private UnityWebRequest <req>5__8; private bool <ok>5__9; private AudioClip <clip>5__10; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <LoadClipFromConfig>d__26(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } <resolved>5__1 = null; <ext>5__2 = null; <uri>5__4 = null; <path>5__5 = null; <dllDir>5__6 = null; <ex>5__7 = null; <req>5__8 = null; <clip>5__10 = null; <>1__state = -2; } private bool MoveNext() { //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Invalid comparison between Unknown and I4 //IL_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_0236: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) bool result; try { switch (<>1__state) { default: result = false; break; case 0: { <>1__state = -1; <resolved>5__1 = null; try { <path>5__5 = <>4__this._audioFilePath.Value?.Trim() ?? string.Empty; if (!string.IsNullOrEmpty(<path>5__5)) { <dllDir>5__6 = Path.GetDirectoryName(((BaseUnityPlugin)<>4__this).Info.Location); <resolved>5__1 = (Path.IsPathRooted(<path>5__5) ? <path>5__5 : Path.Combine(<dllDir>5__6 ?? Paths.PluginPath, <path>5__5)); <dllDir>5__6 = null; } <path>5__5 = null; } catch (Exception ex) { <ex>5__7 = ex; Logger.LogWarning((object)("Path resolution failed: " + <ex>5__7.Message)); <resolved>5__1 = null; } if (string.IsNullOrEmpty(<resolved>5__1) || !File.Exists(<resolved>5__1)) { Logger.LogWarning((object)("Join alert file not found: '" + (<resolved>5__1 ?? "<null>") + "'. Using fallback beep.")); <>4__this.BuildFallbackBeep(); result = false; break; } <ext>5__2 = Path.GetExtension(<resolved>5__1).ToLowerInvariant(); if (1 == 0) { } AudioType val = (AudioType)(<ext>5__2 switch { ".wav" => 20, ".ogg" => 14, ".mp3" => 13, _ => 0, }); if (1 == 0) { } <at>5__3 = val; if ((int)<at>5__3 == 0) { Logger.LogWarning((object)("Unsupported extension '" + <ext>5__2 + "'. Using fallback beep.")); <>4__this.BuildFallbackBeep(); result = false; break; } <uri>5__4 = new Uri(<resolved>5__1).AbsoluteUri; <req>5__8 = UnityWebRequestMultimedia.GetAudioClip(<uri>5__4, <at>5__3); <>1__state = -3; <>2__current = <req>5__8.SendWebRequest(); <>1__state = 1; result = true; break; } case 1: <>1__state = -3; <ok>5__9 = !<req>5__8.isNetworkError && !<req>5__8.isHttpError; if (!<ok>5__9) { Logger.LogWarning((object)("Failed to load join alert clip: " + <req>5__8.error + ". Using fallback beep.")); <>4__this.BuildFallbackBeep(); result = false; } else { <clip>5__10 = DownloadHandlerAudioClip.GetContent(<req>5__8); if (!((Object)(object)<clip>5__10 == (Object)null)) { <>4__this._clip = <clip>5__10; Logger.LogInfo((object)$"Loaded join alert clip: {Path.GetFileName(<resolved>5__1)} ({<>4__this._clip.frequency}Hz, {<>4__this._clip.channels}ch, {<>4__this._clip.samples} samples)"); <clip>5__10 = null; <>m__Finally1(); <req>5__8 = null; result = false; break; } Logger.LogWarning((object)"AudioClip load returned null. Using fallback beep."); <>4__this.BuildFallbackBeep(); result = false; } <>m__Finally1(); break; } } catch { //try-fault ((IDisposable)this).Dispose(); throw; } return result; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; if (<req>5__8 != null) { ((IDisposable)<req>5__8).Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private ConfigEntry<bool> _enabled = null; private ConfigEntry<string> _audioFilePath = null; private ConfigEntry<float> _volume = null; private ConfigEntry<float> _pitch = null; private ConfigEntry<float> _throttleSeconds = null; private const string HostName = "JoinNotifier.AudioHost"; private AudioSource _source = null; private AudioClip? _clip; private float _lastPlay; internal static JoinNotifier Instance { get; private set; } internal static ManualLogSource Logger => Instance._logger; private ManualLogSource _logger => ((BaseUnityPlugin)this).Logger; internal Harmony? Harmony { get; set; } private void Awake() { //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Expected O, but got Unknown //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Expected O, but got Unknown //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Expected O, but got Unknown Instance = this; _enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Master toggle for the join sound."); _audioFilePath = ((BaseUnityPlugin)this).Config.Bind<string>("General", "AudioFile", "JoinAlert.ogg", "Path to the audio file (.wav, .ogg, .mp3). Relative paths resolve next to this plugin DLL."); _volume = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Volume", 0.85f, new ConfigDescription("Playback volume (0..1).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); _pitch = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Pitch", 1f, new ConfigDescription("Playback pitch multiplier.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 3f), Array.Empty<object>())); _throttleSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("General", "ThrottleSeconds", 0.35f, new ConfigDescription("Minimum seconds between join sounds to avoid spam if multiple players connect at once.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 5f), Array.Empty<object>())); EnsureAudioHost(); TryHookMixer(); ((MonoBehaviour)this).StartCoroutine(LoadClipFromConfig()); _audioFilePath.SettingChanged += delegate { ((MonoBehaviour)this).StartCoroutine(LoadClipFromConfig()); }; Patch(); Logger.LogInfo((object)$"{((BaseUnityPlugin)this).Info.Metadata.GUID} v{((BaseUnityPlugin)this).Info.Metadata.Version} has loaded!"); } private void TryHookMixer() { try { Type type = AccessTools.TypeByName("AudioManager"); object obj = (type?.GetField("instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic))?.GetValue(null); object? obj2 = (type?.GetProperty("SoundMasterGroup", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))?.GetValue(obj, null); AudioMixerGroup val = (AudioMixerGroup)((obj2 is AudioMixerGroup) ? obj2 : null); if ((Object)(object)val != (Object)null && (Object)(object)_source != (Object)null) { _source.outputAudioMixerGroup = val; } } catch { } } private void EnsureAudioHost() { //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Expected O, but got Unknown if ((Object)(object)_source != (Object)null) { return; } GameObject val = GameObject.Find("JoinNotifier.AudioHost"); if ((Object)(object)val != (Object)null) { _source = val.GetComponent<AudioSource>(); if ((Object)(object)_source == (Object)null) { _source = val.AddComponent<AudioSource>(); } } else { GameObject val2 = new GameObject("JoinNotifier.AudioHost"); val2.transform.SetParent((Transform)null); Object.DontDestroyOnLoad((Object)(object)val2); _source = val2.AddComponent<AudioSource>(); } _source.spatialBlend = 0f; _source.playOnAwake = false; _source.loop = false; ((Object)_source).hideFlags = (HideFlags)61; } internal void Patch() { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown //IL_0026: Expected O, but got Unknown if (Harmony == null) { Harmony val = new Harmony(((BaseUnityPlugin)this).Info.Metadata.GUID); Harmony val2 = val; Harmony = val; } Harmony.PatchAll(); } internal void Unpatch() { Harmony? harmony = Harmony; if (harmony != null) { harmony.UnpatchSelf(); } } [IteratorStateMachine(typeof(<LoadClipFromConfig>d__26))] private IEnumerator LoadClipFromConfig() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <LoadClipFromConfig>d__26(0) { <>4__this = this }; } private void BuildFallbackBeep() { int num = Mathf.CeilToInt(12000f); float[] array = new float[num]; for (int i = 0; i < num; i++) { array[i] = Mathf.Sin(MathF.PI * 1760f * (float)i / 48000f) * 0.5f; } _clip = AudioClip.Create("JoinNotifier.Beep", num, 1, 48000, false); _clip.SetData(array, 0); } internal void PlayJoinSound() { if (!_enabled.Value) { return; } if ((Object)(object)_source == (Object)null) { Logger.LogWarning((object)"AudioSource was null at playback time. Recreating host."); EnsureAudioHost(); TryHookMixer(); } if ((Object)(object)_clip == (Object)null) { Logger.LogDebug((object)"No clip loaded yet; skipping join sound."); } else if ((Object)(object)_source == (Object)null) { Logger.LogError((object)"Failed to create AudioSource; join sound aborted."); } else if (!(Time.realtimeSinceStartup - _lastPlay < _throttleSeconds.Value)) { try { _source.pitch = Mathf.Clamp(_pitch.Value, 0.1f, 3f); _source.PlayOneShot(_clip, Mathf.Clamp01(_volume.Value)); _lastPlay = Time.realtimeSinceStartup; } catch (Exception arg) { Logger.LogError((object)$"PlayJoinSound failed: {arg}"); } } } private void Update() { } } [HarmonyPatch] internal static class JoinNotifier_JoinPatch { [CompilerGenerated] private sealed class <TargetMethods>d__0 : IEnumerable<MethodBase>, IEnumerable, IEnumerator<MethodBase>, IEnumerator, IDisposable { private int <>1__state; private MethodBase <>2__current; private int <>l__initialThreadId; private Type <playerType>5__1; private Assembly[] <>s__2; private int <>s__3; private Assembly <asm>5__4; private Type[] <types>5__5; private ReflectionTypeLoadException <rtl>5__6; private Type[] <>s__7; private int <>s__8; private Type <t>5__9; private MethodInfo <m>5__10; private MethodInfo <mi>5__11; private bool <hasBody>5__12; private MethodImplAttributes <impl>5__13; MethodBase IEnumerator<MethodBase>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <TargetMethods>d__0(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { <playerType>5__1 = null; <>s__2 = null; <asm>5__4 = null; <types>5__5 = null; <rtl>5__6 = null; <>s__7 = null; <t>5__9 = null; <m>5__10 = null; <mi>5__11 = null; <>1__state = -2; } private bool MoveNext() { int num = <>1__state; if (num != 0) { if (num != 1) { return false; } <>1__state = -1; <m>5__10 = null; <mi>5__11 = null; <t>5__9 = null; goto IL_0226; } <>1__state = -1; <playerType>5__1 = typeof(Player); <>s__2 = AppDomain.CurrentDomain.GetAssemblies(); <>s__3 = 0; goto IL_026b; IL_026b: if (<>s__3 < <>s__2.Length) { <asm>5__4 = <>s__2[<>s__3]; try { <types>5__5 = <asm>5__4.GetTypes(); } catch (ReflectionTypeLoadException ex) { <rtl>5__6 = ex; <types>5__5 = <rtl>5__6.Types.Where((Type t) => t != null).Cast<Type>().ToArray(); } catch { goto IL_025d; } <>s__7 = <types>5__5; <>s__8 = 0; goto IL_0234; } <>s__2 = null; return false; IL_0226: <>s__8++; goto IL_0234; IL_025d: <>s__3++; goto IL_026b; IL_0234: if (<>s__8 < <>s__7.Length) { <t>5__9 = <>s__7[<>s__8]; if (!(<t>5__9 == null) && !<t>5__9.IsInterface) { <m>5__10 = <t>5__9.GetMethod("OnPlayerEnteredRoom", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { <playerType>5__1 }, null); if ((object)<m>5__10 != null) { <mi>5__11 = <m>5__10; if (true && !<mi>5__11.IsAbstract && !<mi>5__11.ContainsGenericParameters) { <hasBody>5__12 = false; try { <hasBody>5__12 = <mi>5__11.GetMethodBody() != null; } catch { <hasBody>5__12 = false; } if (<hasBody>5__12) { <impl>5__13 = <mi>5__11.MethodImplementationFlags; if ((<impl>5__13 & (MethodImplAttributes)4101) == 0) { <>2__current = <mi>5__11; <>1__state = 1; return true; } } } } } goto IL_0226; } <>s__7 = null; <types>5__5 = null; <asm>5__4 = null; goto IL_025d; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator<MethodBase> IEnumerable<MethodBase>.GetEnumerator() { if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; return this; } return new <TargetMethods>d__0(0); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable<MethodBase>)this).GetEnumerator(); } } [IteratorStateMachine(typeof(<TargetMethods>d__0))] private static IEnumerable<MethodBase> TargetMethods() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <TargetMethods>d__0(-2); } private static void Postfix([HarmonyArgument(0)] Player player) { JoinNotifier.Instance?.PlayJoinSound(); } } }