Decompiled source of Join Notifier v1.1.0

JoinNotifier.dll

Decompiled a month ago
using 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();
		}
	}
}