Decompiled source of DiscordRichPresence v1.0.0

Mods/DiscordRichPresence.dll

Decompiled 3 days ago
using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text.RegularExpressions;
using DiscordRichPresence;
using Il2CppRUMBLE.Managers;
using Il2CppRUMBLE.Utilities;
using MelonLoader;
using Microsoft.CodeAnalysis;
using NetDiscordRpc;
using NetDiscordRpc.Core.Logger;
using NetDiscordRpc.RPC;
using RumbleModdingAPI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: MelonInfo(typeof(Class1), "DiscordRichPresence", "1.0.0", "PeppaStone", null)]
[assembly: MelonGame("Buckethead Entertainment", "RUMBLE")]
[assembly: MelonColor(255, 255, 51, 238)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("DiscordRichPresence")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("DiscordRichPresence")]
[assembly: AssemblyTitle("DiscordRichPresence")]
[assembly: AssemblyVersion("1.0.0.0")]
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;
		}
	}
}
namespace DiscordRichPresence
{
	public class Class1 : MelonMod
	{
		public static DiscordRPC DiscordRpc;

		private string currentScene;

		public override void OnSceneWasLoaded(int buildIndex, string sceneName)
		{
			currentScene = sceneName;
		}

		public void SceneLoaded()
		{
			switch (currentScene)
			{
			case "Gym":
				DiscordRpc.UpdateState("");
				DiscordRpc.UpdateDetails("In the Gym");
				break;
			case "Map0":
				if (Singleton<PlayerManager>.Instance.AllPlayers.Count >= 2)
				{
					DiscordRpc.UpdateState("Fighting " + RemoveTags(Singleton<PlayerManager>.Instance.AllPlayers[1].Data.GeneralData.PublicUsername));
				}
				else
				{
					DiscordRpc.UpdateState("Alone");
				}
				DiscordRpc.UpdateDetails("In the Ring");
				break;
			case "Map1":
				if (Singleton<PlayerManager>.Instance.AllPlayers.Count >= 2)
				{
					DiscordRpc.UpdateState("Fighting " + RemoveTags(Singleton<PlayerManager>.Instance.AllPlayers[1].Data.GeneralData.PublicUsername));
				}
				else
				{
					DiscordRpc.UpdateState("Alone");
				}
				DiscordRpc.UpdateDetails("In the Pit");
				break;
			case "Park":
				DiscordRpc.UpdateState("");
				DiscordRpc.UpdateDetails("In the Park");
				break;
			}
		}

		public static string RemoveTags(string input)
		{
			string pattern = "<#.*?>";
			return Regex.Replace(input, pattern, string.Empty);
		}

		public override void OnLateInitializeMelon()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Expected O, but got Unknown
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Expected O, but got Unknown
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Expected O, but got Unknown
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Expected O, but got Unknown
			DiscordRpc = new DiscordRPC("1319243922274390027");
			DiscordRpc.Logger = (IConsoleLogger)new ConsoleLogger();
			DiscordRpc.Logger = (IConsoleLogger)new NullLogger();
			DiscordRpc.Initialize();
			DiscordRPC discordRpc = DiscordRpc;
			RichPresence val = new RichPresence();
			((RichPresenceBase)val).Details = "In the Gym";
			((RichPresenceBase)val).State = "";
			((RichPresenceBase)val).Assets = new Assets
			{
				LargeImageKey = "largeimage",
				LargeImageText = "RUMBLE",
				SmallImageKey = "smallimage",
				SmallImageText = "RUMBLE"
			};
			((RichPresenceBase)val).Timestamps = Timestamps.Now;
			val.Buttons = (Button[])(object)new Button[1]
			{
				new Button
				{
					Label = "Get RUMBLE",
					Url = "https://store.steampowered.com/app/890550/RUMBLE/"
				}
			};
			discordRpc.SetPresence(val);
			DiscordRpc.Invoke();
			Calls.onMapInitialized += SceneLoaded;
		}
	}
}

UserLibs/NetDiscordRpc.dll

Decompiled 3 days ago
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.IO.Pipes;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Threading;
using Microsoft.Win32;
using NetDiscordRpc.Core.Converters;
using NetDiscordRpc.Core.Exceptions;
using NetDiscordRpc.Core.Helpers;
using NetDiscordRpc.Core.IO;
using NetDiscordRpc.Core.Logger;
using NetDiscordRpc.Core.Registry;
using NetDiscordRpc.Events;
using NetDiscordRpc.Message;
using NetDiscordRpc.Message.Messages;
using NetDiscordRpc.RPC;
using NetDiscordRpc.RPC.Commands;
using NetDiscordRpc.RPC.Payload;
using NetDiscordRpc.Users;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETCoreApp,Version=v5.0", FrameworkDisplayName = "")]
[assembly: AssemblyVersion("0.0.0.0")]
namespace NetDiscordRpc
{
	public class Configuration
	{
		[JsonProperty("api_endpoint")]
		public string ApiEndpoint { get; set; }

		[JsonProperty("cdn_host")]
		public string CdnHost { get; set; }

		[JsonProperty("enviroment")]
		public string Enviroment { get; set; }
	}
	public sealed class DiscordRPC : IDisposable
	{
		private IConsoleLogger _logger;

		private RpcConnection connection;

		private bool _shutdownOnly = true;

		private object _sync = new object();

		public bool HasRegisteredUriScheme { get; private set; }

		public string ApplicationID { get; private set; }

		public string SteamID { get; private set; }

		public int ProcessID { get; private set; }

		public int MaxQueueSize { get; private set; }

		public bool IsDisposed { get; private set; }

		public IConsoleLogger Logger
		{
			get
			{
				return _logger;
			}
			set
			{
				_logger = value;
				if (connection != null)
				{
					connection.Logger = value;
				}
			}
		}

		public bool AutoEvents { get; private set; }

		public bool SkipIdenticalPresence { get; set; }

		public int TargetPipe { get; private set; }

		public RichPresence CurrentPresence { get; private set; }

		public EventTypes Subscription { get; private set; }

		public Button[] Buttons { get; set; }

		public User CurrentUser { get; private set; }

		public Configuration Configuration { get; private set; }

		public bool IsInitialized { get; private set; }

		public bool ShutdownOnly
		{
			get
			{
				return _shutdownOnly;
			}
			set
			{
				_shutdownOnly = value;
				if (connection != null)
				{
					connection.ShutdownOnly = value;
				}
			}
		}

		public event OnReadyEvent OnReady;

		public event OnCloseEvent OnClose;

		public event OnErrorEvent OnError;

		public event OnPresenceUpdateEvent OnPresenceUpdate;

		public event OnSubscribeEvent OnSubscribe;

		public event OnUnsubscribeEvent OnUnsubscribe;

		public event OnJoinEvent OnJoin;

		public event OnSpectateEvent OnSpectate;

		public event OnJoinRequestedEvent OnJoinRequested;

		public event OnConnectionEstablishedEvent OnConnectionEstablished;

		public event OnConnectionFailedEvent OnConnectionFailed;

		public event OnRpcMessageEvent OnRpcMessage;

		public DiscordRPC(string applicationID)
			: this(applicationID, -1, null, autoEvents: true, null)
		{
		}

		public DiscordRPC(string applicationID, int pipe = -1, IConsoleLogger logger = null, bool autoEvents = true, INamedPipeClient client = null)
		{
			if (string.IsNullOrEmpty(applicationID))
			{
				throw new ArgumentNullException("applicationID");
			}
			Type typeFromHandle = typeof(JsonConverter);
			if (typeFromHandle == null)
			{
				throw new Exception("JsonConverter Type Not Found");
			}
			ApplicationID = applicationID.Trim();
			TargetPipe = pipe;
			ProcessID = Environment.ProcessId;
			HasRegisteredUriScheme = false;
			AutoEvents = autoEvents;
			SkipIdenticalPresence = true;
			_logger = logger ?? new NullLogger();
			connection = new RpcConnection(ApplicationID, ProcessID, TargetPipe, client ?? new ManagedNamedPipeClient(), (!autoEvents) ? 128u : 0u)
			{
				ShutdownOnly = _shutdownOnly,
				Logger = _logger
			};
			connection.OnRpcMessage += delegate(object _, IMessage msg)
			{
				this.OnRpcMessage?.Invoke(this, msg);
				if (AutoEvents)
				{
					ProcessMessage(msg);
				}
			};
		}

		public IMessage[] Invoke()
		{
			if (AutoEvents)
			{
				Logger.Error("Cannot Invoke client when AutomaticallyInvokeEvents has been set.");
				return Array.Empty<IMessage>();
			}
			IMessage[] array = connection.DequeueMessages();
			foreach (IMessage message in array)
			{
				ProcessMessage(message);
			}
			return array;
		}

		private void ProcessMessage(IMessage message)
		{
			if (message == null)
			{
				return;
			}
			switch (message.Type)
			{
			case MessageTypes.PresenceUpdate:
				lock (_sync)
				{
					if (message is PresenceMessage presenceMessage)
					{
						if (CurrentPresence == null)
						{
							CurrentPresence = new RichPresence().Merge(presenceMessage.Presence);
						}
						else if (presenceMessage.Presence == null)
						{
							CurrentPresence = null;
						}
						else
						{
							CurrentPresence.Merge(presenceMessage.Presence);
						}
						presenceMessage.Presence = CurrentPresence;
					}
				}
				break;
			case MessageTypes.Ready:
				if (message is ReadyMessage readyMessage)
				{
					lock (_sync)
					{
						Configuration = readyMessage.Configuration;
						CurrentUser = readyMessage.User;
					}
					SynchronizeState();
				}
				break;
			case MessageTypes.JoinRequest:
				if (Configuration != null && message is JoinRequestMessage joinRequestMessage)
				{
					joinRequestMessage.User.SetConfiguration(Configuration);
				}
				break;
			case MessageTypes.Subscribe:
				lock (_sync)
				{
					SubscribeMessage subscribeMessage = message as SubscribeMessage;
					Subscription |= subscribeMessage.Event;
				}
				break;
			case MessageTypes.Unsubscribe:
				lock (_sync)
				{
					UnsubscribeMessage unsubscribeMessage = message as UnsubscribeMessage;
					Subscription &= ~unsubscribeMessage.Event;
				}
				break;
			}
			switch (message.Type)
			{
			case MessageTypes.Ready:
				this.OnReady?.Invoke(this, message as ReadyMessage);
				break;
			case MessageTypes.Close:
				this.OnClose?.Invoke(this, message as CloseMessage);
				break;
			case MessageTypes.Error:
				this.OnError?.Invoke(this, message as ErrorMessage);
				break;
			case MessageTypes.PresenceUpdate:
				this.OnPresenceUpdate?.Invoke(this, message as PresenceMessage);
				break;
			case MessageTypes.Subscribe:
				this.OnSubscribe?.Invoke(this, message as SubscribeMessage);
				break;
			case MessageTypes.Unsubscribe:
				this.OnUnsubscribe?.Invoke(this, message as UnsubscribeMessage);
				break;
			case MessageTypes.Join:
				this.OnJoin?.Invoke(this, message as JoinMessage);
				break;
			case MessageTypes.Spectate:
				this.OnSpectate?.Invoke(this, message as SpectateMessage);
				break;
			case MessageTypes.JoinRequest:
				this.OnJoinRequested?.Invoke(this, message as JoinRequestMessage);
				break;
			case MessageTypes.ConnectionEstablished:
				this.OnConnectionEstablished?.Invoke(this, message as ConnectionEstablishedMessage);
				break;
			case MessageTypes.ConnectionFailed:
				this.OnConnectionFailed?.Invoke(this, message as ConnectionFailedMessage);
				break;
			default:
				Logger.Error($"Message was queued with no appropriate handle! {message.Type}");
				break;
			}
		}

		public void Respond(JoinRequestMessage request, bool acceptRequest)
		{
			if (IsDisposed)
			{
				throw new ObjectDisposedException("Discord IPC Client");
			}
			if (connection == null)
			{
				throw new ObjectDisposedException("Connection", "Cannot initialize as the connection has been deinitialized");
			}
			if (!IsInitialized)
			{
				throw new UninitializedException();
			}
			connection.EnqueueCommand(new RespondCommand
			{
				Accept = acceptRequest,
				UserID = request.User.ID.ToString()
			});
		}

		public void SetPresence(RichPresence presence)
		{
			if (IsDisposed)
			{
				throw new ObjectDisposedException("Discord IPC Client");
			}
			if (connection == null)
			{
				throw new ObjectDisposedException("Connection", "Cannot initialize as the connection has been deinitialized");
			}
			if (!IsInitialized)
			{
				Logger.Warning("The client is not yet initialized, storing the presence as a state instead.");
			}
			if (!presence)
			{
				if (!SkipIdenticalPresence || CurrentPresence != null)
				{
					connection.EnqueueCommand(new PresenceCommand
					{
						PID = ProcessID,
						Presence = null
					});
				}
			}
			else
			{
				if (presence.HasSecrets() && !HasRegisteredUriScheme)
				{
					throw new BadPresenceException("Cannot send a presence with secrets as this object has not registered a URI scheme. Please enable the uri scheme registration in the DiscordRpcClient constructor.");
				}
				if (presence.HasParty() && presence.Party.Max < presence.Party.Size)
				{
					throw new BadPresenceException("Presence maximum party size cannot be smaller than the current size.");
				}
				if (presence.HasSecrets() && !presence.HasParty())
				{
					Logger.Warning("The presence has set the secrets but no buttons will show as there is no party available.");
				}
				if (!SkipIdenticalPresence || !presence.Matches(CurrentPresence))
				{
					connection.EnqueueCommand(new PresenceCommand
					{
						PID = ProcessID,
						Presence = presence.Clone()
					});
				}
			}
			lock (_sync)
			{
				CurrentPresence = presence?.Clone();
			}
		}

		public RichPresence UpdateDetails(string details = null)
		{
			if (!IsInitialized)
			{
				throw new UninitializedException();
			}
			RichPresence richPresence;
			lock (_sync)
			{
				richPresence = ((CurrentPresence != null) ? CurrentPresence.Clone() : new RichPresence());
			}
			richPresence.Details = details;
			SetPresence(richPresence);
			return richPresence;
		}

		public RichPresence UpdateState(string state = null)
		{
			if (!IsInitialized)
			{
				throw new UninitializedException();
			}
			RichPresence richPresence;
			lock (_sync)
			{
				richPresence = ((CurrentPresence != null) ? CurrentPresence.Clone() : new RichPresence());
			}
			richPresence.State = state;
			SetPresence(richPresence);
			return richPresence;
		}

		public RichPresence UpdateParty(Party party = null)
		{
			if (!IsInitialized)
			{
				throw new UninitializedException();
			}
			RichPresence richPresence;
			lock (_sync)
			{
				richPresence = ((CurrentPresence != null) ? CurrentPresence.Clone() : new RichPresence());
			}
			richPresence.Party = party;
			SetPresence(richPresence);
			return richPresence;
		}

		public RichPresence UpdatePartySize(int size)
		{
			if (!IsInitialized)
			{
				throw new UninitializedException();
			}
			RichPresence richPresence;
			lock (_sync)
			{
				richPresence = ((CurrentPresence != null) ? CurrentPresence.Clone() : new RichPresence());
			}
			if (richPresence.Party == null)
			{
				throw new BadPresenceException("Cannot set the size of the party if the party does not exist");
			}
			richPresence.Party.Size = size;
			SetPresence(richPresence);
			return richPresence;
		}

		public RichPresence UpdatePartySize(int size, int max)
		{
			if (!IsInitialized)
			{
				throw new UninitializedException();
			}
			RichPresence richPresence;
			lock (_sync)
			{
				richPresence = ((CurrentPresence != null) ? CurrentPresence.Clone() : new RichPresence());
			}
			if (richPresence.Party == null)
			{
				throw new BadPresenceException("Cannot set the size of the party if the party does not exist");
			}
			richPresence.Party.Size = size;
			richPresence.Party.Max = max;
			SetPresence(richPresence);
			return richPresence;
		}

		public RichPresence UpdateLargeAsset(string key = null, string tooltip = null)
		{
			if (!IsInitialized)
			{
				throw new UninitializedException();
			}
			RichPresence richPresence;
			lock (_sync)
			{
				richPresence = ((CurrentPresence != null) ? CurrentPresence.Clone() : new RichPresence());
			}
			if (richPresence.Assets == null)
			{
				richPresence.Assets = new Assets();
			}
			richPresence.Assets.LargeImageKey = key ?? richPresence.Assets.LargeImageKey;
			richPresence.Assets.LargeImageText = tooltip ?? richPresence.Assets.LargeImageText;
			SetPresence(richPresence);
			return richPresence;
		}

		public RichPresence UpdateSmallAsset(string key = null, string tooltip = null)
		{
			if (!IsInitialized)
			{
				throw new UninitializedException();
			}
			RichPresence richPresence;
			lock (_sync)
			{
				richPresence = ((CurrentPresence != null) ? CurrentPresence.Clone() : new RichPresence());
			}
			if (richPresence.Assets == null)
			{
				richPresence.Assets = new Assets();
			}
			richPresence.Assets.SmallImageKey = key ?? richPresence.Assets.SmallImageKey;
			richPresence.Assets.SmallImageText = tooltip ?? richPresence.Assets.SmallImageText;
			SetPresence(richPresence);
			return richPresence;
		}

		public RichPresence UpdateSecrets(Secrets secrets = null)
		{
			if (!IsInitialized)
			{
				throw new UninitializedException();
			}
			RichPresence richPresence;
			lock (_sync)
			{
				richPresence = ((CurrentPresence != null) ? CurrentPresence.Clone() : new RichPresence());
			}
			richPresence.Secrets = secrets;
			SetPresence(richPresence);
			return richPresence;
		}

		public RichPresence UpdateStartTime()
		{
			return UpdateStartTime(DateTime.UtcNow);
		}

		public RichPresence UpdateTimestamps(Timestamps timestamps)
		{
			if (!IsInitialized)
			{
				throw new UninitializedException();
			}
			RichPresence richPresence;
			lock (_sync)
			{
				richPresence = ((CurrentPresence != null) ? CurrentPresence.Clone() : new RichPresence());
			}
			if (richPresence.Timestamps == null)
			{
				richPresence.Timestamps = new Timestamps();
			}
			richPresence.Timestamps = timestamps;
			SetPresence(richPresence);
			return richPresence;
		}

		public RichPresence UpdateStartTime(DateTime time)
		{
			if (!IsInitialized)
			{
				throw new UninitializedException();
			}
			RichPresence richPresence;
			lock (_sync)
			{
				richPresence = ((CurrentPresence != null) ? CurrentPresence.Clone() : new RichPresence());
			}
			if (richPresence.Timestamps == null)
			{
				richPresence.Timestamps = new Timestamps();
			}
			richPresence.Timestamps.Start = time;
			SetPresence(richPresence);
			return richPresence;
		}

		public RichPresence UpdateEndTime()
		{
			return UpdateEndTime(DateTime.UtcNow);
		}

		public RichPresence UpdateEndTime(DateTime time)
		{
			if (!IsInitialized)
			{
				throw new UninitializedException();
			}
			RichPresence richPresence;
			lock (_sync)
			{
				richPresence = ((CurrentPresence != null) ? CurrentPresence.Clone() : new RichPresence());
			}
			if (richPresence.Timestamps == null)
			{
				richPresence.Timestamps = new Timestamps();
			}
			richPresence.Timestamps.End = time;
			SetPresence(richPresence);
			return richPresence;
		}

		public RichPresence UpdateClearTime()
		{
			if (!IsInitialized)
			{
				throw new UninitializedException();
			}
			RichPresence richPresence;
			lock (_sync)
			{
				richPresence = ((CurrentPresence != null) ? CurrentPresence.Clone() : new RichPresence());
			}
			richPresence.Timestamps = null;
			SetPresence(richPresence);
			return richPresence;
		}

		public void ClearPresence()
		{
			if (IsDisposed)
			{
				throw new ObjectDisposedException("Discord IPC Client");
			}
			if (!IsInitialized)
			{
				throw new UninitializedException();
			}
			if (connection == null)
			{
				throw new ObjectDisposedException("Connection", "Cannot initialize as the connection has been deinitialized");
			}
			SetPresence(null);
		}

		public RichPresence UpdateButtons(Button[] button = null)
		{
			if (!IsInitialized)
			{
				throw new UninitializedException();
			}
			RichPresence richPresence;
			lock (_sync)
			{
				richPresence = ((CurrentPresence != null) ? CurrentPresence.Clone() : new RichPresence());
			}
			richPresence.Buttons = button;
			SetPresence(richPresence);
			return richPresence;
		}

		public RichPresence UpdateButtons(Button[] button, int buttonId)
		{
			if (!IsInitialized)
			{
				throw new UninitializedException();
			}
			int num = buttonId - 1;
			RichPresence richPresence;
			lock (_sync)
			{
				richPresence = ((CurrentPresence != null) ? CurrentPresence.Clone() : new RichPresence());
			}
			richPresence.Buttons[num] = button[num];
			SetPresence(richPresence);
			return richPresence;
		}

		public RichPresence RemoveLargeAsset()
		{
			if (!IsInitialized)
			{
				throw new UninitializedException();
			}
			RichPresence richPresence;
			lock (_sync)
			{
				richPresence = ((CurrentPresence != null) ? CurrentPresence.Clone() : new RichPresence());
			}
			if (richPresence.Assets == null)
			{
				richPresence.Assets = new Assets();
			}
			richPresence.Assets.LargeImageKey = null;
			richPresence.Assets.LargeImageText = null;
			SetPresence(richPresence);
			return richPresence;
		}

		public RichPresence RemoveSmallAsset()
		{
			if (!IsInitialized)
			{
				throw new UninitializedException();
			}
			RichPresence richPresence;
			lock (_sync)
			{
				richPresence = ((CurrentPresence != null) ? CurrentPresence.Clone() : new RichPresence());
			}
			if (richPresence.Assets == null)
			{
				richPresence.Assets = new Assets();
			}
			richPresence.Assets.LargeImageKey = null;
			richPresence.Assets.LargeImageText = null;
			SetPresence(richPresence);
			return richPresence;
		}

		public bool RegisterUriScheme(string steamAppID = null, string executable = null)
		{
			UriSchemeRegister uriSchemeRegister = new UriSchemeRegister(_logger, ApplicationID, steamAppID, executable);
			return HasRegisteredUriScheme = uriSchemeRegister.RegisterUriScheme();
		}

		public void Subscribe(EventTypes type)
		{
			SetSubscription(Subscription | type);
		}

		public void Unsubscribe(EventTypes type)
		{
			SetSubscription(Subscription & ~type);
		}

		public void SetSubscription(EventTypes type)
		{
			if (IsInitialized)
			{
				SubscribeToTypes(Subscription & ~type, isUnsubscribe: true);
				SubscribeToTypes(~Subscription & type, isUnsubscribe: false);
			}
			else
			{
				Logger.Warning("Client has not yet initialized, but events are being subscribed too. Storing them as state instead.");
			}
			lock (_sync)
			{
				Subscription = type;
			}
		}

		private void SubscribeToTypes(EventTypes type, bool isUnsubscribe)
		{
			if (type != 0)
			{
				if (IsDisposed)
				{
					throw new ObjectDisposedException("Discord IPC Client");
				}
				if (!IsInitialized)
				{
					throw new UninitializedException();
				}
				if (connection == null)
				{
					throw new ObjectDisposedException("Connection", "Cannot initialize as the connection has been deinitialized");
				}
				if (!HasRegisteredUriScheme)
				{
					throw new InvalidConfigurationException("Cannot subscribe/unsubscribe to an event as this application has not registered a URI Scheme. Call RegisterUriScheme().");
				}
				if ((type & EventTypes.Spectate) == EventTypes.Spectate)
				{
					connection.EnqueueCommand(new SubscribeCommand
					{
						Event = ServerEvent.ActivitySpectate,
						IsUnsubscribe = isUnsubscribe
					});
				}
				if ((type & EventTypes.Join) == EventTypes.Join)
				{
					connection.EnqueueCommand(new SubscribeCommand
					{
						Event = ServerEvent.ActivityJoin,
						IsUnsubscribe = isUnsubscribe
					});
				}
				if ((type & EventTypes.JoinRequest) == EventTypes.JoinRequest)
				{
					connection.EnqueueCommand(new SubscribeCommand
					{
						Event = ServerEvent.ActivityJoinRequest,
						IsUnsubscribe = isUnsubscribe
					});
				}
			}
		}

		public void SynchronizeState()
		{
			if (!IsInitialized)
			{
				throw new UninitializedException();
			}
			SetPresence(CurrentPresence);
			if (HasRegisteredUriScheme)
			{
				SubscribeToTypes(Subscription, isUnsubscribe: false);
			}
		}

		public bool Initialize()
		{
			if (IsDisposed)
			{
				throw new ObjectDisposedException("Discord IPC Client");
			}
			if (IsInitialized)
			{
				throw new UninitializedException("Cannot initialize a client that is already initialized");
			}
			if (connection == null)
			{
				throw new ObjectDisposedException("Connection", "Cannot initialize as the connection has been deinitialized");
			}
			return IsInitialized = connection.AttemptConnection();
		}

		public void Deinitialize()
		{
			if (!IsInitialized)
			{
				throw new UninitializedException("Cannot deinitialize a client that has not been initalized.");
			}
			connection.Close();
			IsInitialized = false;
		}

		public void Dispose()
		{
			if (!IsDisposed)
			{
				if (IsInitialized)
				{
					Deinitialize();
				}
				IsDisposed = true;
			}
		}
	}
}
namespace NetDiscordRpc.Users
{
	public enum AvatarFormats
	{
		PNG,
		JPEG,
		WebP,
		GIF
	}
	public enum AvatarSizes
	{
		x16 = 0x10,
		x32 = 0x20,
		x64 = 0x40,
		x128 = 0x80,
		x256 = 0x100,
		x512 = 0x200,
		x1024 = 0x400,
		x2048 = 0x800
	}
	public enum PremiumTypes
	{
		None,
		NitroClassic,
		Nitro
	}
	public class User
	{
		[JsonProperty("id")]
		public ulong ID { get; private set; }

		[JsonProperty("username")]
		public string Username { get; private set; }

		[JsonProperty("discriminator")]
		public int Discriminator { get; private set; }

		[JsonProperty("avatar")]
		public string Avatar { get; private set; }

		[JsonProperty("flags")]
		public UserFlags Flags { get; private set; }

		[JsonProperty("premium_type")]
		public PremiumTypes Premium { get; private set; }

		public string CdnEndpoint { get; private set; }

		internal User()
		{
			CdnEndpoint = "cdn.discordapp.com";
		}

		internal void SetConfiguration(Configuration configuration)
		{
			CdnEndpoint = configuration.CdnHost;
		}

		public string GetAvatar(AvatarFormats format, AvatarSizes size = AvatarSizes.x128)
		{
			string text = $"/avatars/{ID}/{Avatar}";
			if (!string.IsNullOrEmpty(Avatar))
			{
				return $"{CdnEndpoint}/{text}.{GetAvatarExtension(format)}?size={size}";
			}
			if (format != 0)
			{
				throw new BadImageFormatException("The user has no avatar and the requested format " + format.ToString() + " is not supported. (Only supports PNG).");
			}
			text = $"/embed/avatars/{Discriminator % 5}";
			return $"https://{CdnEndpoint}/{text}.{GetAvatarExtension(format)}?size={size}";
		}

		public static string GetAvatarExtension(AvatarFormats format)
		{
			return format.ToString().ToLowerInvariant();
		}

		public override string ToString()
		{
			return Username + "#" + Discriminator.ToString("D4");
		}
	}
	public enum UserFlags
	{
		None = 0,
		Employee = 1,
		Partner = 2,
		HypeSquad = 4,
		BugHunter = 8,
		HouseBravery = 0x40,
		HouseBrilliance = 0x80,
		HouseBalance = 0x100,
		EarlySupporter = 0x200,
		TeamUser = 0x400
	}
}
namespace NetDiscordRpc.RPC
{
	[Serializable]
	public class Assets
	{
		private string _largeimagekey;

		private string _largeimagetext;

		private string _smallimagekey;

		private string _smallimagetext;

		private ulong? _largeimageID;

		private ulong? _smallimageID;

		[JsonIgnore]
		public ulong? LargeImageID => _largeimageID;

		[JsonIgnore]
		public ulong? SmallImageID => _smallimageID;

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public string LargeImageKey
		{
			get
			{
				return _largeimagekey;
			}
			set
			{
				if (!RichPresenceBase.ValidateString(value, out _largeimagekey, 32, Encoding.UTF8))
				{
					throw new StringOutOfRangeException(32);
				}
				_largeimageID = null;
			}
		}

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public string LargeImageText
		{
			get
			{
				return _largeimagetext;
			}
			set
			{
				if (!RichPresenceBase.ValidateString(value, out _largeimagetext, 128, Encoding.UTF8))
				{
					throw new StringOutOfRangeException(128);
				}
			}
		}

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public string SmallImageKey
		{
			get
			{
				return _smallimagekey;
			}
			set
			{
				if (!RichPresenceBase.ValidateString(value, out _smallimagekey, 32, Encoding.UTF8))
				{
					throw new StringOutOfRangeException(32);
				}
				_smallimageID = null;
			}
		}

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public string SmallImageText
		{
			get
			{
				return _smallimagetext;
			}
			set
			{
				if (!RichPresenceBase.ValidateString(value, out _smallimagetext, 128, Encoding.UTF8))
				{
					throw new StringOutOfRangeException(128);
				}
			}
		}

		internal void Merge(Assets other)
		{
			_smallimagetext = other._smallimagetext;
			_largeimagetext = other._largeimagetext;
			if (ulong.TryParse(other._largeimagekey, out var result))
			{
				_largeimageID = result;
			}
			else
			{
				_largeimagekey = other._largeimagekey;
				_largeimageID = null;
			}
			if (ulong.TryParse(other._smallimagekey, out var result2))
			{
				_smallimageID = result2;
				return;
			}
			_smallimagekey = other._smallimagekey;
			_smallimageID = null;
		}
	}
	public class Button
	{
		private string _label;

		private string _url;

		[JsonProperty("label")]
		public string Label
		{
			get
			{
				return _label;
			}
			set
			{
				if (!RichPresenceBase.ValidateString(value, out _label, 32, Encoding.UTF8))
				{
					throw new StringOutOfRangeException(512);
				}
			}
		}

		[JsonProperty("url")]
		public string Url
		{
			get
			{
				return _url;
			}
			set
			{
				if (!RichPresenceBase.ValidateString(value, out _url, 512, Encoding.UTF8))
				{
					throw new StringOutOfRangeException(512);
				}
				if (!Uri.TryCreate(_url, UriKind.Absolute, out Uri _))
				{
					throw new ArgumentException("Url must be a valid URI");
				}
			}
		}
	}
	[Serializable]
	public class Party
	{
		private string _partyid;

		[JsonIgnore]
		public int Size { get; set; }

		[JsonIgnore]
		public int Max { get; set; }

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public PartyPrivacySettings Privacy { get; set; }

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public string ID
		{
			get
			{
				return _partyid;
			}
			set
			{
				_partyid = value.GetNullOrString();
			}
		}

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		private int[] _size
		{
			get
			{
				int num = Math.Max(1, Size);
				return new int[2]
				{
					num,
					Math.Max(num, Max)
				};
			}
			set
			{
				if (value.Length != 2)
				{
					Size = 0;
					Max = 0;
				}
				else
				{
					Size = value[0];
					Max = value[1];
				}
			}
		}
	}
	public enum PartyPrivacySettings
	{
		Private,
		Public
	}
	public sealed class RichPresence : RichPresenceBase
	{
		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public Button[] Buttons { get; set; }

		public bool HasButtons()
		{
			return Buttons != null && Buttons.Length != 0;
		}

		public RichPresence WithState(string state)
		{
			base.State = state;
			return this;
		}

		public RichPresence WithDetails(string details)
		{
			base.Details = details;
			return this;
		}

		public RichPresence WithTimestamps(Timestamps timestamps)
		{
			base.Timestamps = timestamps;
			return this;
		}

		public RichPresence WithAssets(Assets assets)
		{
			base.Assets = assets;
			return this;
		}

		public RichPresence WithParty(Party party)
		{
			base.Party = party;
			return this;
		}

		public RichPresence WithSecrets(Secrets secrets)
		{
			base.Secrets = secrets;
			return this;
		}

		public RichPresence Clone()
		{
			RichPresence richPresence = new RichPresence();
			richPresence.State = ((_state != null) ? (_state.Clone() as string) : null);
			richPresence.Details = ((_details != null) ? (_details.Clone() as string) : null);
			richPresence.Buttons = ((!HasButtons()) ? null : (Buttons.Clone() as Button[]));
			richPresence.Secrets = ((!HasSecrets()) ? null : new Secrets
			{
				JoinSecret = ((base.Secrets.JoinSecret != null) ? (base.Secrets.JoinSecret.Clone() as string) : null),
				SpectateSecret = ((base.Secrets.SpectateSecret != null) ? (base.Secrets.SpectateSecret.Clone() as string) : null)
			});
			richPresence.Timestamps = ((!HasTimestamps()) ? null : new Timestamps
			{
				Start = base.Timestamps.Start,
				End = base.Timestamps.End
			});
			richPresence.Assets = ((!HasAssets()) ? null : new Assets
			{
				LargeImageKey = ((base.Assets.LargeImageKey != null) ? (base.Assets.LargeImageKey.Clone() as string) : null),
				LargeImageText = ((base.Assets.LargeImageText != null) ? (base.Assets.LargeImageText.Clone() as string) : null),
				SmallImageKey = ((base.Assets.SmallImageKey != null) ? (base.Assets.SmallImageKey.Clone() as string) : null),
				SmallImageText = ((base.Assets.SmallImageText != null) ? (base.Assets.SmallImageText.Clone() as string) : null)
			});
			richPresence.Party = ((!HasParty()) ? null : new Party
			{
				ID = base.Party.ID,
				Size = base.Party.Size,
				Max = base.Party.Max,
				Privacy = base.Party.Privacy
			});
			return richPresence;
		}

		internal RichPresence Merge(RichPresenceBase presence)
		{
			_state = presence.State;
			_details = presence.Details;
			base.Party = presence.Party;
			base.Timestamps = presence.Timestamps;
			base.Secrets = presence.Secrets;
			if (presence.HasAssets())
			{
				if (!HasAssets())
				{
					base.Assets = presence.Assets;
				}
				else
				{
					base.Assets.Merge(presence.Assets);
				}
			}
			else
			{
				base.Assets = null;
			}
			return this;
		}

		internal override bool Matches(RichPresence other)
		{
			if (!base.Matches(other) || ((Buttons == null) ^ (other.Buttons == null)))
			{
				return false;
			}
			if (Buttons == null)
			{
				return true;
			}
			if (Buttons.Length != other.Buttons.Length)
			{
				return false;
			}
			for (int i = 0; i < Buttons.Length; i++)
			{
				Button button = Buttons[i];
				Button button2 = other.Buttons[i];
				if (button.Label != button2.Label || button.Url != button2.Url)
				{
					return false;
				}
			}
			return true;
		}

		public static implicit operator bool(RichPresence presesnce)
		{
			return presesnce != null;
		}
	}
	[Serializable]
	[JsonObject(/*Could not decode attribute arguments.*/)]
	public class RichPresenceBase
	{
		protected internal string _state;

		protected internal string _details;

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public Timestamps Timestamps { get; set; }

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public Assets Assets { get; set; }

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public Party Party { get; set; }

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public Secrets Secrets { get; set; }

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		private bool Instance { get; set; }

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public string State
		{
			get
			{
				return _state;
			}
			set
			{
				if (!ValidateString(value, out _state, 128, Encoding.UTF8))
				{
					throw new StringOutOfRangeException("State", 0, 128);
				}
			}
		}

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public string Details
		{
			get
			{
				return _details;
			}
			set
			{
				if (!ValidateString(value, out _details, 128, Encoding.UTF8))
				{
					throw new StringOutOfRangeException(128);
				}
			}
		}

		internal static bool ValidateString(string text, out string result, int bytes, Encoding encoding)
		{
			result = text;
			if (text == null)
			{
				return true;
			}
			string str = text.Trim();
			if (!str.WithinLength(bytes, encoding))
			{
				return false;
			}
			result = str.GetNullOrString();
			return true;
		}

		public static implicit operator bool(RichPresenceBase presesnce)
		{
			return presesnce != null;
		}

		internal virtual bool Matches(RichPresence other)
		{
			if (other == null)
			{
				return false;
			}
			if (State != other.State || Details != other.Details)
			{
				return false;
			}
			if (Timestamps == null)
			{
				if (other.Timestamps == null || other.Timestamps.StartUnixMilliseconds != Timestamps.StartUnixMilliseconds || other.Timestamps.EndUnixMilliseconds != Timestamps.EndUnixMilliseconds)
				{
					return false;
				}
			}
			else if (other.Timestamps != null)
			{
				return false;
			}
			if (Secrets != null)
			{
				if (other.Secrets == null || other.Secrets.JoinSecret != Secrets.JoinSecret || other.Secrets.SpectateSecret != Secrets.SpectateSecret)
				{
					return false;
				}
			}
			else if (other.Secrets != null)
			{
				return false;
			}
			if (Party != null)
			{
				if (other.Party == null || other.Party.ID != Party.ID || other.Party.Max != Party.Max || other.Party.Size != Party.Size || other.Party.Privacy != Party.Privacy)
				{
					return false;
				}
			}
			else if (other.Party != null)
			{
				return false;
			}
			if (Assets != null)
			{
				if (other.Assets == null || other.Assets.LargeImageKey != Assets.LargeImageKey || other.Assets.LargeImageText != Assets.LargeImageText || other.Assets.SmallImageKey != Assets.SmallImageKey || other.Assets.SmallImageText != Assets.SmallImageText)
				{
					return false;
				}
			}
			else if (other.Assets != null)
			{
				return false;
			}
			return Instance == other.Instance;
		}

		public RichPresence ToRichPresence()
		{
			RichPresence richPresence = new RichPresence();
			richPresence.State = State;
			richPresence.Details = Details;
			richPresence.Party = ((!HasParty()) ? Party : null);
			richPresence.Secrets = ((!HasSecrets()) ? Secrets : null);
			if (HasAssets())
			{
				richPresence.Assets = new Assets
				{
					SmallImageKey = Assets.SmallImageKey,
					SmallImageText = Assets.SmallImageText,
					LargeImageKey = Assets.LargeImageKey,
					LargeImageText = Assets.LargeImageText
				};
			}
			if (!HasTimestamps())
			{
				return richPresence;
			}
			richPresence.Timestamps = new Timestamps();
			if (Timestamps.Start.HasValue)
			{
				richPresence.Timestamps.Start = Timestamps.Start;
			}
			if (Timestamps.End.HasValue)
			{
				richPresence.Timestamps.End = Timestamps.End;
			}
			return richPresence;
		}

		public bool HasTimestamps()
		{
			return Timestamps != null && (Timestamps.Start.HasValue || Timestamps.End.HasValue);
		}

		public bool HasAssets()
		{
			return Assets != null;
		}

		public bool HasParty()
		{
			return Party != null && Party.ID != null;
		}

		public bool HasSecrets()
		{
			return Secrets != null && (Secrets.JoinSecret != null || Secrets.SpectateSecret != null);
		}
	}
	internal sealed class RichPresenceResponse : RichPresenceBase
	{
		[JsonProperty("application_id")]
		public string ClientID { get; private set; }

		[JsonProperty("name")]
		public string Name { get; private set; }
	}
	internal class RpcConnection : IDisposable
	{
		public const int VERSION = 1;

		public const int POLL_RATE = 1000;

		private const bool CLEAR_ON_SHUTDOWN = true;

		private const bool LOCK_STEP = false;

		private IConsoleLogger _logger;

		private RpcStates _state;

		private readonly object l_states = new object();

		private Configuration _configuration;

		private readonly object l_config = new object();

		private volatile bool aborting;

		private volatile bool shutdown;

		private string applicationID;

		private int processID;

		private long nonce;

		private Thread thread;

		private INamedPipeClient namedPipe;

		private int targetPipe;

		private readonly object l_rtqueue = new object();

		private readonly uint _maxRtQueueSize;

		private Queue<ICommand> _rtqueue;

		private readonly object l_rxqueue;

		private readonly uint _maxRxQueueSize;

		private Queue<IMessage> _rxqueue;

		private AutoResetEvent queueUpdatedEvent = new AutoResetEvent(initialState: false);

		private BackoffDelay delay;

		public IConsoleLogger Logger
		{
			get
			{
				return _logger;
			}
			set
			{
				_logger = value;
				if (namedPipe != null)
				{
					namedPipe.Logger = value;
				}
			}
		}

		public RpcStates State
		{
			get
			{
				RpcStates result = RpcStates.Disconnected;
				lock (l_states)
				{
					result = _state;
				}
				return result;
			}
		}

		public Configuration Configuration
		{
			get
			{
				Configuration result = null;
				lock (l_config)
				{
					result = _configuration;
				}
				return result;
			}
		}

		public bool IsRunning => thread != null;

		public bool ShutdownOnly { get; set; }

		public event OnRpcMessageEvent OnRpcMessage;

		public RpcConnection(string applicationID, int processID, int targetPipe, INamedPipeClient client, uint maxRxQueueSize = 128u, uint maxRtQueueSize = 512u)
		{
			this.applicationID = applicationID;
			this.processID = processID;
			this.targetPipe = targetPipe;
			namedPipe = client;
			ShutdownOnly = true;
			Logger = new ConsoleLogger();
			delay = new BackoffDelay(500, 60000);
			_maxRtQueueSize = maxRtQueueSize;
			_rtqueue = new Queue<ICommand>((int)(_maxRtQueueSize + 1));
			_maxRxQueueSize = maxRxQueueSize;
			_rxqueue = new Queue<IMessage>((int)(_maxRxQueueSize + 1));
			nonce = 0L;
		}

		private long GetNextNonce()
		{
			return ++nonce;
		}

		internal void EnqueueCommand(ICommand command)
		{
			Logger.Trace("Enqueue Command: " + command.GetType().FullName);
			if (aborting || shutdown)
			{
				return;
			}
			lock (l_rtqueue)
			{
				if (_rtqueue.Count == _maxRtQueueSize)
				{
					Logger.Error("Too many enqueued commands, dropping oldest one. Maybe you are pushing new presences to fast?");
					_rtqueue.Dequeue();
				}
				_rtqueue.Enqueue(command);
			}
		}

		private void EnqueueMessage(IMessage message)
		{
			try
			{
				this.OnRpcMessage?.Invoke(this, message);
			}
			catch (Exception ex)
			{
				Logger.Error("Unhandled Exception while processing event: " + ex.GetType().FullName);
				Logger.Error(ex.Message);
				Logger.Error(ex.StackTrace);
			}
			if (_maxRxQueueSize == 0)
			{
				Logger.Trace("Enqueued Message, but queue size is 0.");
				return;
			}
			Logger.Trace($"Enqueue Message: {message.Type}");
			lock (l_rxqueue)
			{
				if (_rxqueue.Count == _maxRxQueueSize)
				{
					Logger.Warning("Too many enqueued messages, dropping oldest one.");
					_rxqueue.Dequeue();
				}
				_rxqueue.Enqueue(message);
			}
		}

		internal IMessage DequeueMessage()
		{
			lock (l_rxqueue)
			{
				return (_rxqueue.Count == 0) ? null : _rxqueue.Dequeue();
			}
		}

		internal IMessage[] DequeueMessages()
		{
			lock (l_rxqueue)
			{
				IMessage[] result = _rxqueue.ToArray();
				_rxqueue.Clear();
				return result;
			}
		}

		private void MainLoop()
		{
			Logger.Info("RPC Connection Started");
			if (Logger != null)
			{
				Logger.Trace("============================");
				Logger.Trace("Assembly:             " + Assembly.GetAssembly(typeof(RichPresence)).FullName);
				Logger.Trace("Pipe:                 " + namedPipe.GetType().FullName);
				Logger.Trace($"Platform:             {Environment.OSVersion}");
				Logger.Trace("applicationID:        " + applicationID);
				Logger.Trace($"targetPipe:           {targetPipe}");
				Logger.Trace($"POLL_RATE:            {1000}");
				Logger.Trace($"_maxRtQueueSize:      {_maxRtQueueSize}");
				Logger.Trace($"_maxRxQueueSize:      {_maxRxQueueSize}");
				Logger.Trace("============================");
			}
			while (!aborting && !shutdown)
			{
				try
				{
					if (namedPipe == null)
					{
						Logger.Error("Something bad has happened with our pipe client!");
						aborting = true;
						return;
					}
					Logger.Trace("Connecting to the pipe through the " + namedPipe.GetType().FullName);
					if (namedPipe.Connect(targetPipe))
					{
						Logger.Trace("Connected to the pipe. Attempting to establish handshake...");
						EnqueueMessage(new ConnectionEstablishedMessage
						{
							ConnectedPipe = namedPipe.ConnectedPipe
						});
						EstablishHandshake();
						Logger.Trace("Connection Established. Starting reading loop...");
						bool flag = true;
						while (flag && !aborting && !shutdown && namedPipe.IsConnected)
						{
							if (namedPipe.ReadFrame(out var frame))
							{
								Logger.Trace($"Read Payload: {frame.Opcode}");
								switch (frame.Opcode)
								{
								case OpCode.Close:
								{
									ClosePayload @object = frame.GetObject<ClosePayload>();
									Logger.Warning($"We have been told to terminate by discord: ({@object.Code}) {@object.Reason}");
									EnqueueMessage(new CloseMessage
									{
										Code = @object.Code,
										Reason = @object.Reason
									});
									flag = false;
									break;
								}
								case OpCode.Ping:
									Logger.Trace("PING");
									frame.Opcode = OpCode.Pong;
									namedPipe.WriteFrame(frame);
									break;
								case OpCode.Pong:
									Logger.Trace("PONG");
									break;
								case OpCode.Frame:
								{
									if (shutdown)
									{
										Logger.Warning("Skipping frame because we are shutting down.");
										break;
									}
									if (frame.Data == null)
									{
										Logger.Error("We received no data from the frame so we cannot get the event payload!");
										break;
									}
									EventPayload eventPayload = null;
									try
									{
										eventPayload = frame.GetObject<EventPayload>();
									}
									catch (Exception ex)
									{
										Logger.Error("Failed to parse event! " + ex.Message);
										Logger.Error("Data: " + frame.Message);
									}
									try
									{
										if (eventPayload != null)
										{
											ProcessFrame(eventPayload);
										}
									}
									catch (Exception ex2)
									{
										Logger.Error("Failed to process event! " + ex2.Message);
										Logger.Error("Data: " + frame.Message);
									}
									break;
								}
								default:
									Logger.Error($"Invalid opcode: {frame.Opcode}");
									flag = false;
									break;
								}
							}
							if (!aborting && namedPipe.IsConnected)
							{
								ProcessCommandQueue();
								queueUpdatedEvent.WaitOne(1000);
							}
						}
						Logger.Trace($"Left main read loop for some reason. Aborting: {aborting}, Shutting Down: {shutdown}");
					}
					else
					{
						Logger.Error("Failed to connect for some reason.");
						EnqueueMessage(new ConnectionFailedMessage
						{
							FailedPipe = targetPipe
						});
					}
					if (!aborting && !shutdown)
					{
						long num = delay.NextDelay();
						Logger.Trace($"Waiting {num}ms before attempting to connect again");
						Thread.Sleep(delay.NextDelay());
					}
				}
				catch (Exception ex3)
				{
					Logger.Error("Unhandled Exception: " + ex3.GetType().FullName);
					Logger.Error(ex3.Message);
					Logger.Error(ex3.StackTrace);
				}
				finally
				{
					if (namedPipe.IsConnected)
					{
						Logger.Trace("Closing the named pipe.");
						namedPipe.Close();
					}
					SetConnectionState(RpcStates.Disconnected);
				}
			}
			Logger.Trace("Left Main Loop");
			namedPipe?.Dispose();
			Logger.Info("Thread Terminated, no longer performing RPC connection.");
		}

		private void ProcessFrame(EventPayload response)
		{
			//IL_0203: Unknown result type (might be due to invalid IL or missing references)
			//IL_020a: Expected O, but got Unknown
			Logger.Info($"Handling Response. Cmd: {response.Command}, Event: {response.Event}");
			if (response.Event.HasValue && response.Event.Value == ServerEvent.Error)
			{
				Logger.Error("Error received from the RPC");
				ErrorMessage @object = response.GetObject<ErrorMessage>();
				Logger.Error("Server responded with an error message: (" + @object.Code.ToString() + ") " + @object.Message);
				EnqueueMessage(@object);
			}
			else if (State == RpcStates.Connecting && response.Command == NetDiscordRpc.RPC.Payload.Commands.Dispatch && response.Event.HasValue && response.Event.Value == ServerEvent.Ready)
			{
				Logger.Info("Connection established with the RPC");
				SetConnectionState(RpcStates.Connected);
				delay.Reset();
				ReadyMessage object2 = response.GetObject<ReadyMessage>();
				lock (l_config)
				{
					_configuration = object2.Configuration;
					object2.User.SetConfiguration(_configuration);
				}
				EnqueueMessage(object2);
			}
			else if (State == RpcStates.Connected)
			{
				switch (response.Command)
				{
				case NetDiscordRpc.RPC.Payload.Commands.Dispatch:
					ProcessDispatch(response);
					break;
				case NetDiscordRpc.RPC.Payload.Commands.SetActivity:
					if (response.Data == null)
					{
						EnqueueMessage(new PresenceMessage());
					}
					else
					{
						EnqueueMessage(new PresenceMessage(response.GetObject<RichPresenceResponse>()));
					}
					break;
				case NetDiscordRpc.RPC.Payload.Commands.Subscribe:
				case NetDiscordRpc.RPC.Payload.Commands.Unsubscribe:
				{
					JsonSerializer val = new JsonSerializer();
					((Collection<JsonConverter>)(object)val.Converters).Add((JsonConverter)(object)new EnumSnakeCaseConverter());
					ServerEvent value = response.GetObject<EventPayload>().Event.Value;
					if (response.Command == NetDiscordRpc.RPC.Payload.Commands.Subscribe)
					{
						EnqueueMessage(new SubscribeMessage(value));
					}
					else
					{
						EnqueueMessage(new UnsubscribeMessage(value));
					}
					break;
				}
				case NetDiscordRpc.RPC.Payload.Commands.SendActivityJoinInvite:
					Logger.Trace("Got invite response ack.");
					break;
				case NetDiscordRpc.RPC.Payload.Commands.CloseActivityJoinRequest:
					Logger.Trace("Got invite response reject ack.");
					break;
				default:
					Logger.Error($"Unkown frame was received! {response.Command}");
					break;
				}
			}
			else
			{
				Logger.Trace($"Received a frame while we are disconnected. Ignoring. Cmd: {response.Command}, Event: {response.Event}");
			}
		}

		private void ProcessDispatch(EventPayload response)
		{
			if (response.Command == NetDiscordRpc.RPC.Payload.Commands.Dispatch && response.Event.HasValue)
			{
				switch (response.Event.Value)
				{
				case ServerEvent.ActivitySpectate:
				{
					SpectateMessage object3 = response.GetObject<SpectateMessage>();
					EnqueueMessage(object3);
					break;
				}
				case ServerEvent.ActivityJoin:
				{
					JoinMessage object2 = response.GetObject<JoinMessage>();
					EnqueueMessage(object2);
					break;
				}
				case ServerEvent.ActivityJoinRequest:
				{
					JoinRequestMessage @object = response.GetObject<JoinRequestMessage>();
					EnqueueMessage(@object);
					break;
				}
				case ServerEvent.Ready:
				case ServerEvent.Error:
					break;
				default:
					Logger.Warning($"Ignoring {response.Event.Value}");
					break;
				}
			}
		}

		private void ProcessCommandQueue()
		{
			if (State != RpcStates.Connected)
			{
				return;
			}
			if (aborting)
			{
				Logger.Warning("We have been told to write a queue but we have also been aborted.");
			}
			bool flag = true;
			while (flag && namedPipe.IsConnected)
			{
				ICommand command;
				lock (l_rtqueue)
				{
					flag = _rtqueue.Count > 0;
					if (!flag)
					{
						break;
					}
					command = _rtqueue.Peek();
				}
				if (!shutdown)
				{
					if (aborting)
					{
					}
				}
				else if (true)
				{
					flag = false;
				}
				IPayload payload = command.PreparePayload(GetNextNonce());
				Logger.Trace($"Attempting to send payload: {payload.Command}");
				PipeFrame frame = default(PipeFrame);
				if (command is CloseCommand)
				{
					SendHandwave();
					Logger.Trace("Handwave sent, ending queue processing.");
					lock (l_rtqueue)
					{
						_rtqueue.Dequeue();
						break;
					}
				}
				if (aborting)
				{
					Logger.Warning("- skipping frame because of abort.");
					lock (l_rtqueue)
					{
						_rtqueue.Dequeue();
					}
					continue;
				}
				frame.SetObject(OpCode.Frame, payload);
				Logger.Trace($"Sending payload: {payload.Command}");
				if (namedPipe.WriteFrame(frame))
				{
					Logger.Trace("Sent Successfully.");
					lock (l_rtqueue)
					{
						_rtqueue.Dequeue();
					}
					continue;
				}
				Logger.Warning("Something went wrong during writing!");
				break;
			}
		}

		private void EstablishHandshake()
		{
			Logger.Trace("Attempting to establish a handshake...");
			if (State != 0)
			{
				Logger.Error("State must be disconnected in order to start a handshake!");
				return;
			}
			Logger.Trace("Sending Handshake...");
			if (!namedPipe.WriteFrame(new PipeFrame(OpCode.Handshake, new Handshake
			{
				Version = 1,
				ClientID = applicationID
			})))
			{
				Logger.Error("Failed to write a handshake.");
			}
			else
			{
				SetConnectionState(RpcStates.Connecting);
			}
		}

		private void SendHandwave()
		{
			Logger.Info("Attempting to wave goodbye...");
			if (State == RpcStates.Disconnected)
			{
				Logger.Error("State must NOT be disconnected in order to send a handwave!");
			}
			else if (!namedPipe.WriteFrame(new PipeFrame(OpCode.Close, new Handshake
			{
				Version = 1,
				ClientID = applicationID
			})))
			{
				Logger.Error("failed to write a handwave.");
			}
		}

		public bool AttemptConnection()
		{
			Logger.Info("Attempting a new connection");
			if (thread != null)
			{
				Logger.Error("Cannot attempt a new connection as the previous connection thread is not null!");
				return false;
			}
			if (State != 0)
			{
				Logger.Warning("Cannot attempt a new connection as the previous connection hasn't changed state yet.");
				return false;
			}
			if (aborting)
			{
				Logger.Error("Cannot attempt a new connection while aborting!");
				return false;
			}
			thread = new Thread(MainLoop);
			thread.Name = "Discord IPC Thread";
			thread.IsBackground = true;
			thread.Start();
			return true;
		}

		private void SetConnectionState(RpcStates state)
		{
			Logger.Trace("Setting the connection state to " + state.ToString().ToSnakeCase().ToUpperInvariant());
			lock (l_states)
			{
				_state = state;
			}
		}

		public void Shutdown()
		{
			Logger.Trace("Initiated shutdown procedure");
			shutdown = true;
			lock (l_rtqueue)
			{
				_rtqueue.Clear();
				bool flag = true;
				_rtqueue.Enqueue(new PresenceCommand
				{
					PID = processID,
					Presence = null
				});
				_rtqueue.Enqueue(new CloseCommand());
			}
			queueUpdatedEvent.Set();
		}

		public void Close()
		{
			if (thread == null)
			{
				Logger.Error("Cannot close as it is not available!");
				return;
			}
			if (aborting)
			{
				Logger.Error("Cannot abort as it has already been aborted");
				return;
			}
			if (ShutdownOnly)
			{
				Shutdown();
				return;
			}
			Logger.Trace("Updating Abort State...");
			aborting = true;
			queueUpdatedEvent.Set();
		}

		public void Dispose()
		{
			ShutdownOnly = false;
			Close();
		}
	}
	internal enum RpcStates
	{
		Disconnected,
		Connecting,
		Connected
	}
	[Serializable]
	public class Secrets
	{
		private string _joinSecret;

		private string _spectateSecret;

		public static Encoding Encoding => Encoding.UTF8;

		public static int SecretLength => 128;

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public string JoinSecret
		{
			get
			{
				return _joinSecret;
			}
			set
			{
				if (!RichPresenceBase.ValidateString(value, out _joinSecret, 128, Encoding.UTF8))
				{
					throw new StringOutOfRangeException(128);
				}
			}
		}

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public string SpectateSecret
		{
			get
			{
				return _spectateSecret;
			}
			set
			{
				if (!RichPresenceBase.ValidateString(value, out _spectateSecret, 128, Encoding.UTF8))
				{
					throw new StringOutOfRangeException(128);
				}
			}
		}

		public static string CreateSecret(Random random)
		{
			byte[] array = new byte[SecretLength];
			random.NextBytes(array);
			return Encoding.GetString(array);
		}

		public static string CreateFriendlySecret(Random random)
		{
			string text = "";
			for (int i = 0; i < SecretLength; i++)
			{
				text += "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"[random.Next("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".Length)];
			}
			return text;
		}
	}
	[Serializable]
	public class Timestamps
	{
		[JsonIgnore]
		public DateTime? Start { get; set; }

		[JsonIgnore]
		public DateTime? End { get; set; }

		public static Timestamps Now => new Timestamps(DateTime.UtcNow);

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public ulong? StartUnixMilliseconds
		{
			get
			{
				return Start.HasValue ? new ulong?(ToUnixMilliseconds(Start.Value)) : null;
			}
			set
			{
				Start = (value.HasValue ? new DateTime?(FromUnixMilliseconds(value.Value)) : null);
			}
		}

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public ulong? EndUnixMilliseconds
		{
			get
			{
				return End.HasValue ? new ulong?(ToUnixMilliseconds(End.Value)) : null;
			}
			set
			{
				End = (value.HasValue ? new DateTime?(FromUnixMilliseconds(value.Value)) : null);
			}
		}

		public Timestamps()
		{
			Start = null;
			End = null;
		}

		public Timestamps(DateTime start, DateTime? end = null)
		{
			Start = start;
			End = end;
		}

		public static Timestamps FromTimeSpan(double seconds)
		{
			return FromTimeSpan(TimeSpan.FromSeconds(seconds));
		}

		public static Timestamps FromTimeSpan(TimeSpan timespan)
		{
			return new Timestamps
			{
				Start = DateTime.UtcNow,
				End = DateTime.UtcNow + timespan
			};
		}

		public static DateTime FromUnixMilliseconds(ulong unixTime)
		{
			return new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddMilliseconds(Convert.ToDouble(unixTime));
		}

		public static ulong ToUnixMilliseconds(DateTime date)
		{
			DateTime dateTime = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
			return Convert.ToUInt64((date - dateTime).TotalMilliseconds);
		}
	}
}
namespace NetDiscordRpc.RPC.Payload
{
	internal class ArgumentPayload : IPayload
	{
		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public JObject Arguments { get; set; }

		public ArgumentPayload()
		{
			Arguments = null;
		}

		public ArgumentPayload(long nonce)
			: base(nonce)
		{
			Arguments = null;
		}

		public ArgumentPayload(object args, long nonce)
			: base(nonce)
		{
			SetObject(args);
		}

		public void SetObject(object obj)
		{
			Arguments = JObject.FromObject(obj);
		}

		public T GetObject<T>()
		{
			return ((JToken)Arguments).ToObject<T>();
		}

		public override string ToString()
		{
			return "Argument " + base.ToString();
		}
	}
	internal class ClosePayload : IPayload
	{
		[JsonProperty("code")]
		public int Code { get; set; }

		[JsonProperty("message")]
		public string Reason { get; set; }
	}
	public enum Commands
	{
		[EnumValue("DISPATCH")]
		Dispatch,
		[EnumValue("SET_ACTIVITY")]
		SetActivity,
		[EnumValue("SUBSCRIBE")]
		Subscribe,
		[EnumValue("UNSUBSCRIBE")]
		Unsubscribe,
		[EnumValue("SEND_ACTIVITY_JOIN_INVITE")]
		SendActivityJoinInvite,
		[EnumValue("CLOSE_ACTIVITY_JOIN_REQUEST")]
		CloseActivityJoinRequest
	}
	internal abstract class IPayload
	{
		[JsonProperty("cmd")]
		[JsonConverter(typeof(EnumSnakeCaseConverter))]
		public Commands Command { get; set; }

		[JsonProperty("nonce")]
		public string Nonce { get; set; }

		protected IPayload()
		{
		}

		protected IPayload(long nonce)
		{
			Nonce = nonce.ToString();
		}

		public override string ToString()
		{
			return "Payload || Command: " + Command.ToString() + ", Nonce: " + ((Nonce != null) ? Nonce : "NULL");
		}
	}
	internal class EventPayload : IPayload
	{
		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public JObject Data { get; set; }

		[JsonProperty("evt")]
		[JsonConverter(typeof(EnumSnakeCaseConverter))]
		public ServerEvent? Event { get; set; }

		public EventPayload()
		{
			Data = null;
		}

		public EventPayload(long nonce)
			: base(nonce)
		{
			Data = null;
		}

		public T GetObject<T>()
		{
			return (Data == null) ? default(T) : ((JToken)Data).ToObject<T>();
		}

		public override string ToString()
		{
			return "Event " + base.ToString() + ", Event: " + (Event.HasValue ? Event.ToString() : "N/A");
		}
	}
	internal enum ServerEvent
	{
		[EnumValue("READY")]
		Ready,
		[EnumValue("ERROR")]
		Error,
		[EnumValue("ACTIVITY_JOIN")]
		ActivityJoin,
		[EnumValue("ACTIVITY_SPECTATE")]
		ActivitySpectate,
		[EnumValue("ACTIVITY_JOIN_REQUEST")]
		ActivityJoinRequest
	}
}
namespace NetDiscordRpc.RPC.Commands
{
	internal class CloseCommand : ICommand
	{
		[JsonProperty("close_reason")]
		public string value = "Unity 5.5 doesn't handle thread aborts. Can you please close me discord?";

		[JsonProperty("pid")]
		public int PID { get; set; }

		public IPayload PreparePayload(long nonce)
		{
			return new ArgumentPayload
			{
				Command = NetDiscordRpc.RPC.Payload.Commands.Dispatch,
				Nonce = null,
				Arguments = null
			};
		}
	}
	internal interface ICommand
	{
		IPayload PreparePayload(long nonce);
	}
	internal class PresenceCommand : ICommand
	{
		[JsonProperty("pid")]
		public int PID { get; set; }

		[JsonProperty("activity")]
		public RichPresence Presence { get; set; }

		public IPayload PreparePayload(long nonce)
		{
			return new ArgumentPayload(this, nonce)
			{
				Command = NetDiscordRpc.RPC.Payload.Commands.SetActivity
			};
		}
	}
	internal class RespondCommand : ICommand
	{
		[JsonProperty("user_id")]
		public string UserID { get; set; }

		[JsonIgnore]
		public bool Accept { get; set; }

		public IPayload PreparePayload(long nonce)
		{
			return new ArgumentPayload(this, nonce)
			{
				Command = (Accept ? NetDiscordRpc.RPC.Payload.Commands.SendActivityJoinInvite : NetDiscordRpc.RPC.Payload.Commands.CloseActivityJoinRequest)
			};
		}
	}
	internal class SubscribeCommand : ICommand
	{
		public ServerEvent Event { get; set; }

		public bool IsUnsubscribe { get; set; }

		public IPayload PreparePayload(long nonce)
		{
			return new EventPayload(nonce)
			{
				Command = (IsUnsubscribe ? NetDiscordRpc.RPC.Payload.Commands.Unsubscribe : NetDiscordRpc.RPC.Payload.Commands.Subscribe),
				Event = Event
			};
		}
	}
}
namespace NetDiscordRpc.Message
{
	public enum ErrorCodes
	{
		Success = 0,
		PipeException = 1,
		ReadCorrupt = 2,
		NotImplemented = 10,
		UnkownError = 1000,
		InvalidPayload = 4000,
		InvalidCommand = 4002,
		InvalidEvent = 4004
	}
	public abstract class IMessage
	{
		private DateTime _timecreated;

		public abstract MessageTypes Type { get; }

		public DateTime TimeCreated => _timecreated;

		public IMessage()
		{
			_timecreated = DateTime.Now;
		}
	}
	public enum MessageTypes
	{
		Ready,
		Close,
		Error,
		PresenceUpdate,
		Subscribe,
		Unsubscribe,
		Join,
		Spectate,
		JoinRequest,
		ConnectionEstablished,
		ConnectionFailed
	}
}
namespace NetDiscordRpc.Message.Messages
{
	public class CloseMessage : IMessage
	{
		public string Reason { get; internal set; }

		public int Code { get; internal set; }

		public override MessageTypes Type => MessageTypes.Close;

		internal CloseMessage()
		{
		}

		internal CloseMessage(string reason)
		{
			Reason = reason;
		}
	}
	public class ConnectionEstablishedMessage : IMessage
	{
		public int ConnectedPipe { get; internal set; }

		public override MessageTypes Type => MessageTypes.ConnectionEstablished;
	}
	public class ConnectionFailedMessage : IMessage
	{
		public int FailedPipe { get; internal set; }

		public override MessageTypes Type => MessageTypes.ConnectionFailed;
	}
	public class ErrorMessage : IMessage
	{
		[JsonProperty("code")]
		public ErrorCodes Code { get; internal set; }

		[JsonProperty("message")]
		public string Message { get; internal set; }

		public override MessageTypes Type => MessageTypes.Error;
	}
	public class JoinMessage : IMessage
	{
		[JsonProperty("secret")]
		public string Secret { get; internal set; }

		public override MessageTypes Type => MessageTypes.Join;
	}
	public class JoinRequestMessage : IMessage
	{
		[JsonProperty("user")]
		public User User { get; internal set; }

		public override MessageTypes Type => MessageTypes.JoinRequest;
	}
	public class PresenceMessage : IMessage
	{
		public string Name { get; internal set; }

		public string ApplicationID { get; internal set; }

		public RichPresenceBase Presence { get; internal set; }

		public override MessageTypes Type => MessageTypes.PresenceUpdate;

		internal PresenceMessage()
			: this(null)
		{
		}

		internal PresenceMessage(RichPresenceResponse rpr)
		{
			if (rpr == null)
			{
				Presence = null;
				Name = "No Rich Presence";
				ApplicationID = "";
			}
			else
			{
				Presence = rpr;
				Name = rpr.Name;
				ApplicationID = rpr.ClientID;
			}
		}
	}
	public class ReadyMessage : IMessage
	{
		[JsonProperty("config")]
		public Configuration Configuration { get; set; }

		[JsonProperty("user")]
		public User User { get; set; }

		[JsonProperty("v")]
		public int Version { get; set; }

		public override MessageTypes Type => MessageTypes.Ready;
	}
	public class SpectateMessage : IMessage
	{
		public override MessageTypes Type => MessageTypes.Spectate;
	}
	public class SubscribeMessage : IMessage
	{
		public EventTypes Event { get; internal set; }

		public override MessageTypes Type => MessageTypes.Subscribe;

		internal SubscribeMessage(ServerEvent evt)
		{
			if (1 == 0)
			{
			}
			EventTypes @event = evt switch
			{
				ServerEvent.ActivityJoin => EventTypes.Join, 
				ServerEvent.ActivityJoinRequest => EventTypes.JoinRequest, 
				ServerEvent.ActivitySpectate => EventTypes.Spectate, 
				_ => Event, 
			};
			if (1 == 0)
			{
			}
			Event = @event;
		}
	}
	public class UnsubscribeMessage : IMessage
	{
		public EventTypes Event { get; internal set; }

		public override MessageTypes Type => MessageTypes.Unsubscribe;

		internal UnsubscribeMessage(ServerEvent evt)
		{
			if (1 == 0)
			{
			}
			EventTypes @event = evt switch
			{
				ServerEvent.ActivityJoin => EventTypes.Join, 
				ServerEvent.ActivityJoinRequest => EventTypes.JoinRequest, 
				ServerEvent.ActivitySpectate => EventTypes.Spectate, 
				_ => Event, 
			};
			if (1 == 0)
			{
			}
			Event = @event;
		}
	}
}
namespace NetDiscordRpc.Events
{
	public delegate void OnReadyEvent(object sender, ReadyMessage args);
	public delegate void OnCloseEvent(object sender, CloseMessage args);
	public delegate void OnErrorEvent(object sender, ErrorMessage args);
	public delegate void OnPresenceUpdateEvent(object sender, PresenceMessage args);
	public delegate void OnSubscribeEvent(object sender, SubscribeMessage args);
	public delegate void OnUnsubscribeEvent(object sender, UnsubscribeMessage args);
	public delegate void OnJoinEvent(object sender, JoinMessage args);
	public delegate void OnSpectateEvent(object sender, SpectateMessage args);
	public delegate void OnJoinRequestedEvent(object sender, JoinRequestMessage args);
	public delegate void OnConnectionEstablishedEvent(object sender, ConnectionEstablishedMessage args);
	public delegate void OnConnectionFailedEvent(object sender, ConnectionFailedMessage args);
	public delegate void OnRpcMessageEvent(object sender, IMessage msg);
	[Flags]
	public enum EventTypes
	{
		None = 0,
		Spectate = 1,
		Join = 2,
		JoinRequest = 4
	}
}
namespace NetDiscordRpc.Core.Registry
{
	public interface IUriSchemeCreator
	{
		bool RegisterUriScheme(UriSchemeRegister register);
	}
	internal class MacUriSchemeCreator : IUriSchemeCreator
	{
		private IConsoleLogger logger;

		public MacUriSchemeCreator(IConsoleLogger logger)
		{
			this.logger = logger;
		}

		public bool RegisterUriScheme(UriSchemeRegister register)
		{
			string executablePath = register.ExecutablePath;
			if (string.IsNullOrEmpty(executablePath))
			{
				logger.Error("Failed to register because the application could not be located.");
				return false;
			}
			logger.Trace("Registering Steam Command");
			string text = executablePath;
			if (register.UsingSteamApp)
			{
				text = "steam://rungameid/" + register.SteamAppID;
			}
			else
			{
				logger.Warning("This library does not fully support MacOS URI Scheme Registration.");
			}
			DirectoryInfo directoryInfo = Directory.CreateDirectory("~/Library/Application Support/discord/games");
			if (!directoryInfo.Exists)
			{
				logger.Error("Failed to register because ~/Library/Application Support/discord/games does not exist");
				return false;
			}
			File.WriteAllText("~/Library/Application Support/discord/games/" + register.ApplicationID + ".json", "{ \"command\": \"" + text + "\" }");
			logger.Trace("Registered ~/Library/Application Support/discord/games/" + register.ApplicationID + ".json, " + text);
			return true;
		}
	}
	internal class UnixUriSchemeCreator : IUriSchemeCreator
	{
		private IConsoleLogger logger;

		public UnixUriSchemeCreator(IConsoleLogger logger)
		{
			this.logger = logger;
		}

		public bool RegisterUriScheme(UriSchemeRegister register)
		{
			string environmentVariable = Environment.GetEnvironmentVariable("HOME");
			if (string.IsNullOrEmpty(environmentVariable))
			{
				logger.Error("Failed to register because the HOME variable was not set.");
				return false;
			}
			string executablePath = register.ExecutablePath;
			if (string.IsNullOrEmpty(executablePath))
			{
				logger.Error("Failed to register because the application was not located.");
				return false;
			}
			string text = ((!register.UsingSteamApp) ? executablePath : ("xdg-open steam://rungameid/" + register.SteamAppID));
			string text2 = $"[Desktop Entry]Name=Game {register.ApplicationID}Exec={text} %uType=ApplicationNoDisplay=trueCategories=Discord;Games;MimeType=x-scheme-handler/discord-{register.ApplicationID}";
			string text3 = "/discord-" + register.ApplicationID + ".desktop";
			string text4 = environmentVariable + "/.local/share/applications";
			DirectoryInfo directoryInfo = Directory.CreateDirectory(text4);
			if (!directoryInfo.Exists)
			{
				logger.Error("Failed to register because " + text4 + " does not exist");
				return false;
			}
			File.WriteAllText(text4 + text3, text2);
			if (!RegisterMime(register.ApplicationID))
			{
				logger.Error("Failed to register because the Mime failed.");
				return false;
			}
			logger.Trace("Registered " + text4 + text3 + ", " + text2 + ", " + text);
			return true;
		}

		private static bool RegisterMime(string appid)
		{
			string arguments = string.Format("default discord-{0}.desktop x-scheme-handler/discord-{0}", appid);
			Process process = Process.Start("xdg-mime", arguments);
			process.WaitForExit();
			return process.ExitCode >= 0;
		}
	}
	public class UriSchemeRegister
	{
		private IConsoleLogger _logger;

		public string ApplicationID { get; set; }

		public string SteamAppID { get; set; }

		public bool UsingSteamApp => !string.IsNullOrEmpty(SteamAppID) && SteamAppID != "";

		public string ExecutablePath { get; set; }

		public UriSchemeRegister(IConsoleLogger logger, string applicationID, string steamAppID = null, string executable = null)
		{
			_logger = logger;
			ApplicationID = applicationID.Trim();
			SteamAppID = steamAppID?.Trim();
			ExecutablePath = executable ?? GetApplicationLocation();
		}

		public bool RegisterUriScheme()
		{
			IUriSchemeCreator uriSchemeCreator;
			switch (Environment.OSVersion.Platform)
			{
			case PlatformID.Win32S:
			case PlatformID.Win32Windows:
			case PlatformID.Win32NT:
			case PlatformID.WinCE:
				_logger.Trace("Creating Windows Scheme Creator");
				uriSchemeCreator = new WindowsUriSchemeCreator(_logger);
				break;
			case PlatformID.Unix:
				_logger.Trace("Creating Unix Scheme Creator");
				uriSchemeCreator = new UnixUriSchemeCreator(_logger);
				break;
			case PlatformID.MacOSX:
				_logger.Trace("Creating MacOSX Scheme Creator");
				uriSchemeCreator = new MacUriSchemeCreator(_logger);
				break;
			case PlatformID.Xbox:
			case PlatformID.Other:
				_logger.Error($"Unkown Platform: {Environment.OSVersion.Platform}");
				throw new PlatformNotSupportedException("Platform does not support registration.");
			default:
				_logger.Error($"Unkown Platform: {Environment.OSVersion.Platform}");
				throw new PlatformNotSupportedException("Platform does not support registration.");
			}
			if (!uriSchemeCreator.RegisterUriScheme(this))
			{
				return false;
			}
			_logger.Info("URI scheme registered.");
			return true;
		}

		public static string GetApplicationLocation()
		{
			return Process.GetCurrentProcess().MainModule.FileName;
		}
	}
	internal class WindowsUriSchemeCreator : IUriSchemeCreator
	{
		private IConsoleLogger logger;

		public WindowsUriSchemeCreator(IConsoleLogger logger)
		{
			this.logger = logger;
		}

		public bool RegisterUriScheme(UriSchemeRegister register)
		{
			PlatformID platform = Environment.OSVersion.Platform;
			if (platform == PlatformID.Unix || platform == PlatformID.MacOSX)
			{
				throw new PlatformNotSupportedException("URI schemes can only be registered on Windows");
			}
			string executablePath = register.ExecutablePath;
			if (executablePath == null)
			{
				logger.Error("Failed to register application because the location was null.");
				return false;
			}
			string scheme = "discord-" + register.ApplicationID;
			string friendlyName = "Run game " + register.ApplicationID + " protocol";
			string command = executablePath;
			if (register.UsingSteamApp)
			{
				string steamLocation = GetSteamLocation();
				if (steamLocation != null)
				{
					command = "\"" + steamLocation + "\" steam://rungameid/" + register.SteamAppID;
				}
			}
			CreateUriScheme(scheme, friendlyName, executablePath, command);
			return true;
		}

		private void CreateUriScheme(string scheme, string friendlyName, string defaultIcon, string command)
		{
			using (RegistryKey registryKey = Microsoft.Win32.Registry.CurrentUser.CreateSubKey("SOFTWARE\\Classes\\" + scheme))
			{
				registryKey.SetValue("", "URL:" + friendlyName);
				registryKey.SetValue("URL Protocol", "");
				using (RegistryKey registryKey2 = registryKey.CreateSubKey("DefaultIcon"))
				{
					registryKey2.SetValue("", defaultIcon);
				}
				using RegistryKey registryKey3 = registryKey.CreateSubKey("shell\\open\\command");
				registryKey3.SetValue("", command);
			}
			logger.Trace("Registered " + scheme + ", " + friendlyName + ", " + command);
		}

		public static string GetSteamLocation()
		{
			using RegistryKey registryKey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey("Software\\Valve\\Steam");
			return registryKey?.GetValue("SteamExe") as string;
		}
	}
}
namespace NetDiscordRpc.Core.Logger
{
	public class ConsoleLogger : IConsoleLogger
	{
		private static string GetLogType(ConsoleLogLevel level)
		{
			if (1 == 0)
			{
			}
			string result = level switch
			{
				ConsoleLogLevel.Info => "info ", 
				ConsoleLogLevel.Warning => "warn ", 
				ConsoleLogLevel.Error => "error", 
				ConsoleLogLevel.Trace => "trace", 
				ConsoleLogLevel.None => "none ", 
				_ => throw new ArgumentOutOfRangeException("level"), 
			};
			if (1 == 0)
			{
			}
			return result;
		}

		public void Trace(string message)
		{
			Log(ConsoleLogLevel.Trace, ConsoleColor.Gray, message);
		}

		public void Info(string message)
		{
			Log(ConsoleLogLevel.Info, ConsoleColor.White, message);
		}

		public void Warning(string message)
		{
			Log(ConsoleLogLevel.Warning, ConsoleColor.Yellow, message);
		}

		public void Error(string message)
		{
			Log(ConsoleLogLevel.Error, ConsoleColor.Red, message);
		}

		private static void Log(ConsoleLogLevel level, ConsoleColor color, string log)
		{
			Console.ForegroundColor = color;
			Console.WriteLine($"[{DateTime.Now}] {GetLogType(level)}: {log}");
			Console.ResetColor();
		}
	}
	public enum ConsoleLogLevel
	{
		Trace = 1,
		Info = 2,
		Warning = 3,
		Error = 4,
		None = 256
	}
	public interface IConsoleLogger
	{
		void Trace(string message);

		void Info(string message);

		void Warning(string message);

		void Error(string message);
	}
	public class NullLogger : IConsoleLogger
	{
		public void Trace(string message)
		{
		}

		public void Info(string message)
		{
		}

		public void Warning(string message)
		{
		}

		public void Error(string message)
		{
		}
	}
}
namespace NetDiscordRpc.Core.IO
{
	internal class Handshake
	{
		[JsonProperty("v")]
		public int Version { get; set; }

		[JsonProperty("client_id")]
		public string ClientID { get; set; }
	}
	public interface INamedPipeClient : IDisposable
	{
		IConsoleLogger Logger { get; set; }

		bool IsConnected { get; }

		int ConnectedPipe { get; }

		bool Connect(int pipe);

		bool ReadFrame(out PipeFrame frame);

		bool WriteFrame(PipeFrame frame);

		void Close();
	}
	public sealed class ManagedNamedPipeClient : INamedPipeClient, IDisposable
	{
		private const string PipeName = "discord-ipc-{0}";

		private int _connectedPipe;

		private NamedPipeClientStream _stream;

		private byte[] _buffer = new byte[PipeFrame.MAX_SIZE];

		private Queue<PipeFrame> _framequeue = new Queue<PipeFrame>();

		private object _framequeuelock = new object();

		private volatile bool _isDisposed;

		private volatile bool _isClosed = true;

		private object l_stream = new object();

		public IConsoleLogger Logger { get; set; }

		public bool IsConnected
		{
			get
			{
				if (_isClosed)
				{
					return false;
				}
				lock (l_stream)
				{
					return _stream != null && _stream.IsConnected;
				}
			}
		}

		public int ConnectedPipe => _connectedPipe;

		public ManagedNamedPipeClient()
		{
			_buffer = new byte[PipeFrame.MAX_SIZE];
			Logger = new ConsoleLogger();
			_stream = null;
		}

		public bool Connect(int pipe)
		{
			Logger.Trace($"ManagedNamedPipeClient.Connection({pipe})");
			if (_isDisposed)
			{
				throw new ObjectDisposedException("NamedPipe");
			}
			if (pipe <= 9)
			{
				if (pipe < 0)
				{
					for (int i = 0; i < 10; i++)
					{
						if (AttemptConnection(i) || AttemptConnection(i, isSandbox: true))
						{
							BeginReadStream();
							return true;
						}
					}
					return false;
				}
				if (!AttemptConnection(pipe) && !AttemptConnection(pipe, isSandbox: true))
				{
					return false;
				}
				BeginReadStream();
				return true;
			}
			throw new ArgumentOutOfRangeException("pipe", "Argument cannot be greater than 9");
		}

		private bool AttemptConnection(int pipe, bool isSandbox = false)
		{
			if (_isDisposed)
			{
				throw new ObjectDisposedException("_stream");
			}
			string text = (isSandbox ? GetPipeSandbox() : "");
			if (isSandbox && text == null)
			{
				Logger.Trace("Skipping sandbox connection.");
				return false;
			}
			Logger.Trace($"Connection Attempt {pipe} ({text})");
			string pipeName = GetPipeName(pipe, text);
			try
			{
				lock (l_stream)
				{
					Logger.Info("Attempting to connect to " + pipeName);
					_stream = new NamedPipeClientStream(".", pipeName, PipeDirection.InOut, PipeOptions.Asynchronous);
					_stream.Connect(1000);
					Logger.Trace("Waiting for connection...");
					do
					{
						Thread.Sleep(10);
					}
					while (!_stream.IsConnected);
				}
				Logger.Info("Connected to " + pipeName);
				_connectedPipe = pipe;
				_isClosed = false;
			}
			catch (Exception ex)
			{
				Logger.Error("Failed connection to " + pipeName + ". " + ex.Message);
				Close();
			}
			Logger.Trace($"Done. Result: {_isClosed}");
			return !_isClosed;
		}

		private void BeginReadStream()
		{
			if (_isClosed)
			{
				return;
			}
			try
			{
				lock (l_stream)
				{
					NamedPipeClientStream stream = _stream;
					if (stream != null && stream.IsConnected)
					{
						Logger.Trace($"Begining Read of {_buffer.Length} bytes");
						_stream.BeginRead(_buffer, 0, _buffer.Length, EndReadStream, _stream.IsConnected);
					}
				}
			}
			catch (ObjectDisposedException)
			{
				Logger.Warning("Attempted to start reading from a disposed pipe");
			}
			catch (InvalidOperationException)
			{
				Logger.Warning("Attempted to start reading from a closed pipe");
			}
			catch (Exception ex3)
			{
				Logger.Error("An exception occured while starting to read a stream: " + ex3.Message);
				Logger.Error(ex3.StackTrace);
			}
		}

		private void EndReadStream(IAsyncResult callback)
		{
			Logger.Trace("Ending Read");
			int num;
			try
			{
				lock (l_stream)
				{
					NamedPipeClientStream stream = _stream;
					if (stream == null || !stream.IsConnected)
					{
						return;
					}
					num = _stream.EndRead(callback);
				}
			}
			catch (IOException)
			{
				Logger.Warning("Attempted to end reading from a closed pipe");
				return;
			}
			catch (NullReferenceException)
			{
				Logger.Warning("Attempted to read from a null pipe");
				return;
			}
			catch (ObjectDisposedException)
			{
				Logger.Warning("Attemped to end reading from a disposed pipe");
				return;
			}
			catch (Exception ex4)
			{
				Logger.Error($"An exception occured while ending a read of a stream: {ex4.Message}");
				Logger.Error(ex4.StackTrace);
				return;
			}
			Logger.Trace($"Read {num} bytes");
			if (num > 0)
			{
				using MemoryStream stream2 = new MemoryStream(_buffer, 0, num);
				try
				{
					PipeFrame item = default(PipeFrame);
					if (item.ReadStream(stream2))
					{
						Logger.Trace($"Read a frame: {item.Opcode}");
						lock (_framequeuelock)
						{
							_framequeue.Enqueue(item);
						}
					}
					else
					{
						Logger.Error("Pipe failed to read from the data received by the stream.");
						Close();
					}
				}
				catch (Exception ex5)
				{
					Logger.Error("A exception has occured while trying to parse the pipe data: " + ex5.Message);
					Close();
				}
			}
			else if (IsUnix())
			{
				Logger.Error($"Empty frame was read on {Environment.OSVersion} aborting.");
				Close();
			}
			else
			{
				Logger.Warning("Empty frame was read. Please send report to Lachee.");
			}
			if (!_isClosed && IsConnected)
			{
				Logger.Trace("Starting another read");
				BeginReadStream();
			}
		}

		public bool ReadFrame(out PipeFrame frame)
		{
			if (_isDisposed)
			{
				throw new ObjectDisposedException("_stream");
			}
			lock (_framequeuelock)
			{
				if (_framequeue.Count == 0)
				{
					frame = default(PipeFrame);
					return false;
				}
				frame = _framequeue.Dequeue();
				return true;
			}
		}

		public bool WriteFrame(PipeFrame frame)
		{
			if (_isDisposed)
			{
				throw new ObjectDisposedException("_stream");
			}
			if (_isClosed || !IsConnected)
			{
				Logger.Error("Failed to write frame because the stream is closed");
				return false;
			}
			try
			{
				frame.WriteStream(_stream);
				return true;
			}
			catch (IOException ex)
			{
				Logger.Error("Failed to write frame because of a IO Exception: " + ex.Message);
			}
			catch (ObjectDisposedException)
			{
				Logger.Warning("Failed to write frame as the stream was already disposed");
			}
			catch (InvalidOperationException)
			{
				Logger.Warning("Failed to write frame because of a invalid operation");
			}
			return false;
		}

		public void Close()
		{
			if (_isClosed)
			{
				Logger.Warning("Tried to close a already closed pipe.");
				return;
			}
			try
			{
				lock (l_stream)
				{
					if (_stream != null)
					{
						try
						{
							_stream.Flush();
							_stream.Dispose();
						}
						catch (Exception ex)
						{
							Logger.Error("Something went wrong when closing the stream: [" + ex.Message + "]");
						}
						_stream = null;
						_isClosed = true;
					}
					else
					{
						Logger.Warning("Stream was closed, but no stream was available to begin with!");
					}
				}
			}
			catch (ObjectDisposedException)
			{
				Logger.Warning("Tried to dispose already disposed stream");
			}
			finally
			{
				_isClosed = true;
				_connectedPipe = -1;
			}
		}

		public void Dispose()
		{
			if (_isDisposed)
			{
				return;
			}
			if (!_isClosed)
			{
				Close();
			}
			lock (l_stream)
			{
				if (_stream != null)
				{
					_stream.Dispose();
					_stream = null;
				}
			}
			_isDisposed = true;
		}

		public static string GetPipeName(int pipe, string sandbox = "")
		{
			if (!IsUnix())
			{
				return sandbox + $"discord-ipc-{pipe}";
			}
			return Path.Combine(GetTemporaryDirectory(), sandbox + $"discord-ipc-{pipe}");
		}

		public static string GetPipeSandbox()
		{
			PlatformID platform = Environment.OSVersion.Platform;
			if (1 == 0)
			{
			}
			string result = ((platform != PlatformID.Unix) ? null : "snap.discord/");
			if (1 == 0)
			{
			}
			return result;
		}

		private static string GetTemporaryDirectory()
		{
			string text = null;
			text = text ?? Environment.GetEnvironmentVariable("XDG_RUNTIME_DIR");
			text = text ?? Environment.GetEnvironmentVariable("TMPDIR");
			text = text ?? Environment.GetEnvironmentVariable("TMP");
			text = text ?? Environment.GetEnvironmentVariable("TEMP");
			return text ?? "/tmp";
		}

		public static bool IsUnix()
		{
			switch (Environment.OSVersion.Platform)
			{
			case PlatformID.Win32S:
			case PlatformID.Win32Windows:
			case PlatformID.Win32NT:
			case PlatformID.WinCE:
			case PlatformID.Xbox:
			case PlatformID.Other:
				return false;
			default:
				return false;
			case PlatformID.Unix:
			case PlatformID.MacOSX:
				return true;
			}
		}
	}
	public enum OpCode : uint
	{
		Handshake,
		Frame,
		Close,
		Ping,
		Pong
	}
	public struct PipeFrame
	{
		public static readonly int MAX_SIZE = 16384;

		public OpCode Opcode { get; set; }

		public uint Length => (uint)Data.Length;

		public byte[] Data { get; set; }

		public string Message
		{
			get
			{
				return GetMessage();
			}
			set
			{
				SetMessage(value);
			}
		}

		public static Encoding MessageEncoding => Encoding.UTF8;

		public PipeFrame(OpCode opcode, object data)
		{
			Opcode = opcode;
			Data = null;
			SetObject(data);
		}

		private void SetMessage(string str)
		{
			Data = MessageEncoding.GetBytes(str);
		}

		private string GetMessage()
		{
			return MessageEncoding.GetString(Data);
		}

		public void SetObject(object obj)
		{
			SetMessage(JsonConvert.SerializeObject(obj));
		}

		public void SetObject(OpCode opcode, object obj)
		{
			Opcode = opcode;
			SetObject(obj);
		}

		public T GetObject<T>()
		{
			return JsonConvert.DeserializeObject<T>(GetMessage());
		}

		public bool ReadStream(Stream stream)
		{
			if (!TryReadUInt32(stream, out var value))
			{
				return false;
			}
			if (!TryReadUInt32(stream, out var value2))
			{
				return false;
			}
			uint num = value2;
			using MemoryStream memoryStream = new MemoryStream();
			byte[] array = new byte[Min(2048, value2)];
			int count;
			while ((count = stream.Read(array, 0, Min(array.Length, num))) > 0)
			{
				num -= value2;
				memoryStream.Write(array, 0, count);
			}
			byte[] array2 = memoryStream.ToArray();
			if (array2.LongLength != value2)
			{
				return false;
			}
			Opcode = (OpCode)value;
			Data = array2;
			return true;
		}

		private static int Min(int a, uint b)
		{
			if (b >= a)
			{
				return a;
			}
			return (int)b;
		}

		private static bool TryReadUInt32(Stream stream, out uint value)
		{
			byte[] array = new byte[4];
			int num = stream.Read(array, 0, array.Length);
			if (num != 4)
			{
				value = 0u;
				return false;
			}
			value = BitConverter.ToUInt32(array, 0);
			return true;
		}

		public void WriteStream(Stream stream)
		{
			byte[] bytes = BitConverter.GetBytes((uint)Opcode);
			byte[] bytes2 = BitConverter.GetBytes(Length);
			byte[] array = new byte[bytes.Length + bytes2.Length + Data.Length];
			bytes.CopyTo(array, 0);
			bytes2.CopyTo(array, bytes.Length);
			Data.CopyTo(array, bytes.Length + bytes2.Length);
			stream.Write(array, 0, array.Length);
		}
	}
}
namespace NetDiscordRpc.Core.Helpers
{
	internal class BackoffDelay
	{
		private int _current;

		private int _fails;

		public int Maximum { get; private set; }

		public int Minimum { get; private set; }

		public int Current => _current;

		public int Fails => _fails;

		public Random Random { get; set; }

		private BackoffDelay()
		{
		}

		public BackoffDelay(int min, int max)
			: this(min, max, new Random())
		{
		}

		public BackoffDelay(int min, int max, Random random)
		{
			Minimum = min;
			Maximum = max;
			_current = min;
			_fails = 0;
			Random = random;
		}

		public void Reset()
		{
			_fails = 0;
			_current = Minimum;
		}

		public int NextDelay()
		{
			_fails++;
			double num = (double)(Maximum - Minimum) / 100.0;
			_current = (int)Math.Floor(num * (double)_fails) + Minimum;
			return Math.Min(Math.Max(_current, Minimum), Maximum);
		}
	}
	public static class StringHelper
	{
		public static string GetNullOrString(this string str)
		{
			return (str.Length == 0 || string.IsNullOrEmpty(str.Trim())) ? null : str;
		}

		public static bool WithinLength(this string str, int bytes)
		{
			return str.WithinLength(bytes, Encoding.UTF8);
		}

		public static bool WithinLength(this string str, int bytes, Encoding encoding)
		{
			return encoding.GetByteCount(str) <= bytes;
		}

		public static string ToCamelCase(this string str)
		{
			return (from s in str?.ToLower().Split(new string[2] { "_", " " }, StringSplitOptions.RemoveEmptyEntries)
				select char.ToUpper(s[0]) + s.Substring(1, s.Length - 1)).Aggregate(string.Empty, (string s1, string s2) => s1 + s2);
		}

		public static string ToSnakeCase(this string str)
		{
			if (str == null)
			{
				return null;
			}
			string text = string.Concat(str.Select((char x, int i) => (i > 0 && char.IsUpper(x)) ? ("_" + x) : x.ToString()).ToArray());
			return text.ToUpper();
		}
	}
}
namespace NetDiscordRpc.Core.Exceptions
{
	public class BadPresenceException : Exception
	{
		internal BadPresenceException(string message)
			: base(message)
		{
		}
	}
	public class InvalidConfigurationException : Exception
	{
		internal InvalidConfigurationException(string message)
			: base(message)
		{
		}
	}
	public class NetDiscordRpcException : Exception
	{
		public NetDiscordRpcException(string message)
			: base(message)
		{
		}
	}
	public class StringOutOfRangeException : Exception
	{
		public int MaximumLength { get; private set; }

		public int MinimumLength { get; private set; }

		internal StringOutOfRangeException(string message, int min, int max)
			: base(message)
		{
			MinimumLength = min;
			MaximumLength = max;
		}

		internal StringOutOfRangeException(int minumum, int max)
			: this("Length of string is out of range. Expected a value between " + minumum + " and " + max, minumum, max)
		{
		}

		internal StringOutOfRangeException(int max)
			: this("Length of string is out of range. Expected a value with a maximum length of " + max, 0, max)
		{
		}
	}
	public class UninitializedException : Exception
	{
		internal UninitializedException(string message)
			: base(message)
		{
		}

		internal UninitializedException()
			: this("Cannot perform action because the client has not been initialized yet or has been deinitialized.")
		{
		}
	}
}
namespace NetDiscordRpc.Core.Converters
{
	internal class EnumSnakeCaseConverter : JsonConverter
	{
		public override bool CanConvert(Type objectType)
		{
			return objectType.IsEnum;
		}

		public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
		{
			if (reader.Value == null)
			{
				return null;
			}
			object obj;
			return TryParseEnum(objectType, (string)reader.Value, out obj) ? obj : existingValue;
		}

		public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
		{
			Type type = value.GetType();
			string text = Enum.GetName(type, value);
			MemberInfo[] members = type.GetMembers(BindingFlags.Static | BindingFlags.Public);
			MemberInfo[] array = members;
			foreach (MemberInfo memberInfo in array)
			{
				if (memberInfo.Name.Equals(text))
				{
					object[] customAttributes = memberInfo.GetCustomAttributes(typeof(EnumValueAttribute), inherit: true);
					if (customAttributes.Length != 0)
					{
						text = ((EnumValueAttribute)customAttributes[0]).Value;
					}
				}
			}
			writer.WriteValue(text);
		}

		public static bool TryParseEnum(Type enumType, string str, out object obj)
		{
			if (str == null)
			{
				obj = null;
				return false;
			}
			Type type = enumType;
			if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
			{
				type = type.GetGenericArguments().First();
			}
			if (!type.IsEnum)
			{
				obj = null;
				return false;
			}
			MemberInfo[] members = type.GetMembers(BindingFlags.Static | BindingFlags.Public);
			MemberInfo[] array = members;
			foreach (MemberInfo memberInfo in array)
			{
				object[] customAttributes = memberInfo.GetCustomAttributes(typeof(EnumValueAttribute), inherit: true);
				if (customAttributes.Cast<EnumValueAttribute>().Any((EnumValueAttribute enumval) => str.Equals(enumval.Value)))
				{
					obj = Enum.Parse(type, memberInfo.Name, ignoreCase: true);
					return true;
				}
			}
			obj = null;
			return false;
		}
	}
	internal class EnumValueAttribute : Attribute
	{
		public string Value { get; set; }

		public EnumValueAttribute(string value)
		{
			Value = value;
		}
	}
}