Decompiled source of LabPresence v1.3.0

UserLibs/DiscordRPC.dll

Decompiled 2 months ago
using System;
using System.Collections;
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.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using System.Threading;
using DiscordRPC.Converters;
using DiscordRPC.Events;
using DiscordRPC.Exceptions;
using DiscordRPC.Helper;
using DiscordRPC.IO;
using DiscordRPC.Logging;
using DiscordRPC.Message;
using DiscordRPC.RPC;
using DiscordRPC.RPC.Commands;
using DiscordRPC.RPC.Payload;
using DiscordRPC.Registry;
using Microsoft.Win32;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("Discord RPC")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Discord RPC")]
[assembly: AssemblyCopyright("Copyright ©  2021")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("819d20d6-8d88-45c1-a4d2-aa21f10abd19")]
[assembly: AssemblyFileVersion("1.6.2.72")]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")]
[assembly: AssemblyVersion("1.6.2.72")]
namespace DiscordRPC
{
	public class Configuration
	{
		[JsonProperty("api_endpoint")]
		public string ApiEndpoint { get; set; }

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

		[JsonProperty("environment")]
		public string Environment { get; set; }
	}
	public sealed class DiscordRpcClient : IDisposable
	{
		private ILogger _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 ILogger 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 EventType Subscription { get; private 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 DiscordRpcClient(string applicationID)
			: this(applicationID, -1, null, autoEvents: true, null)
		{
		}

		public DiscordRpcClient(string applicationID, int pipe = -1, ILogger logger = null, bool autoEvents = true, INamedPipeClient client = null)
		{
			if (string.IsNullOrEmpty(applicationID))
			{
				throw new ArgumentNullException("applicationID");
			}
			ApplicationID = applicationID.Trim();
			TargetPipe = pipe;
			ProcessID = Process.GetCurrentProcess().Id;
			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 sender, IMessage msg)
			{
				if (this.OnRpcMessage != null)
				{
					this.OnRpcMessage(this, msg);
				}
				if (AutoEvents)
				{
					ProcessMessage(msg);
				}
			};
		}

		public IMessage[] Invoke()
		{
			if (AutoEvents)
			{
				Logger.Error("Cannot Invoke client when AutomaticallyInvokeEvents has been set.");
				return new IMessage[0];
			}
			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 MessageType.PresenceUpdate:
				lock (_sync)
				{
					if (message is PresenceMessage presenceMessage)
					{
						if (presenceMessage.Presence == null)
						{
							CurrentPresence = null;
						}
						else if (CurrentPresence == null)
						{
							CurrentPresence = new RichPresence().Merge(presenceMessage.Presence);
						}
						else
						{
							CurrentPresence.Merge(presenceMessage.Presence);
						}
						presenceMessage.Presence = CurrentPresence;
					}
				}
				if (this.OnPresenceUpdate != null)
				{
					this.OnPresenceUpdate(this, message as PresenceMessage);
				}
				break;
			case MessageType.Ready:
				if (message is ReadyMessage readyMessage)
				{
					lock (_sync)
					{
						Configuration = readyMessage.Configuration;
						CurrentUser = readyMessage.User;
					}
					SynchronizeState();
				}
				if (this.OnReady != null)
				{
					this.OnReady(this, message as ReadyMessage);
				}
				break;
			case MessageType.Close:
				if (this.OnClose != null)
				{
					this.OnClose(this, message as CloseMessage);
				}
				break;
			case MessageType.Error:
				if (this.OnError != null)
				{
					this.OnError(this, message as ErrorMessage);
				}
				break;
			case MessageType.JoinRequest:
				if (Configuration != null && message is JoinRequestMessage joinRequestMessage)
				{
					joinRequestMessage.User.SetConfiguration(Configuration);
				}
				if (this.OnJoinRequested != null)
				{
					this.OnJoinRequested(this, message as JoinRequestMessage);
				}
				break;
			case MessageType.Subscribe:
				lock (_sync)
				{
					SubscribeMessage subscribeMessage = message as SubscribeMessage;
					Subscription |= subscribeMessage.Event;
				}
				if (this.OnSubscribe != null)
				{
					this.OnSubscribe(this, message as SubscribeMessage);
				}
				break;
			case MessageType.Unsubscribe:
				lock (_sync)
				{
					UnsubscribeMessage unsubscribeMessage = message as UnsubscribeMessage;
					Subscription &= ~unsubscribeMessage.Event;
				}
				if (this.OnUnsubscribe != null)
				{
					this.OnUnsubscribe(this, message as UnsubscribeMessage);
				}
				break;
			case MessageType.Join:
				if (this.OnJoin != null)
				{
					this.OnJoin(this, message as JoinMessage);
				}
				break;
			case MessageType.Spectate:
				if (this.OnSpectate != null)
				{
					this.OnSpectate(this, message as SpectateMessage);
				}
				break;
			case MessageType.ConnectionEstablished:
				if (this.OnConnectionEstablished != null)
				{
					this.OnConnectionEstablished(this, message as ConnectionEstablishedMessage);
				}
				break;
			case MessageType.ConnectionFailed:
				if (this.OnConnectionFailed != null)
				{
					this.OnConnectionFailed(this, message as ConnectionFailedMessage);
				}
				break;
			default:
				Logger.Error("Message was queued with no appropriate handle! {0}", 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 == null)
			{
				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 Update(Action<RichPresence> func)
		{
			if (!IsInitialized)
			{
				throw new UninitializedException();
			}
			RichPresence richPresence;
			lock (_sync)
			{
				richPresence = ((CurrentPresence == null) ? new RichPresence() : CurrentPresence.Clone());
			}
			func(richPresence);
			SetPresence(richPresence);
			return richPresence;
		}

		public RichPresence UpdateType(ActivityType type)
		{
			return Update(delegate(RichPresence p)
			{
				p.Type = type;
			});
		}

		public RichPresence UpdateStatusDisplayType(StatusDisplayType type)
		{
			return Update(delegate(RichPresence p)
			{
				p.StatusDisplay = type;
			});
		}

		public RichPresence UpdateButtons(Button[] buttons = null)
		{
			return Update(delegate(RichPresence p)
			{
				p.Buttons = buttons;
			});
		}

		public RichPresence SetButton(Button button, int index = 0)
		{
			return Update(delegate(RichPresence p)
			{
				p.Buttons[index] = button;
			});
		}

		public RichPresence UpdateDetails(string details)
		{
			return Update(delegate(RichPresence p)
			{
				p.Details = details;
			});
		}

		public RichPresence UpdateState(string state)
		{
			return Update(delegate(RichPresence p)
			{
				p.State = state;
			});
		}

		public RichPresence UpdateParty(Party party)
		{
			return Update(delegate(RichPresence p)
			{
				p.Party = party;
			});
		}

		public RichPresence UpdatePartySize(int size)
		{
			return Update(delegate(RichPresence p)
			{
				if (p.Party == null)
				{
					throw new BadPresenceException("Cannot set the size of the party if the party does not exist");
				}
				p.Party.Size = size;
			});
		}

		public RichPresence UpdatePartySize(int size, int max)
		{
			return Update(delegate(RichPresence p)
			{
				if (p.Party == null)
				{
					throw new BadPresenceException("Cannot set the size of the party if the party does not exist");
				}
				p.Party.Size = size;
				p.Party.Max = max;
			});
		}

		public RichPresence UpdateLargeAsset(string key = null, string tooltip = null)
		{
			return Update(delegate(RichPresence p)
			{
				if (p.Assets == null)
				{
					p.Assets = new Assets();
				}
				p.Assets.LargeImageKey = key ?? p.Assets.LargeImageKey;
				p.Assets.LargeImageText = tooltip ?? p.Assets.LargeImageText;
			});
		}

		public RichPresence UpdateSmallAsset(string key = null, string tooltip = null)
		{
			return Update(delegate(RichPresence p)
			{
				if (p.Assets == null)
				{
					p.Assets = new Assets();
				}
				p.Assets.SmallImageKey = key ?? p.Assets.SmallImageKey;
				p.Assets.SmallImageText = tooltip ?? p.Assets.SmallImageText;
			});
		}

		public RichPresence UpdateSecrets(Secrets secrets)
		{
			return Update(delegate(RichPresence p)
			{
				p.Secrets = secrets;
			});
		}

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

		public RichPresence UpdateStartTime(DateTime time)
		{
			return Update(delegate(RichPresence p)
			{
				if (p.Timestamps == null)
				{
					p.Timestamps = new Timestamps();
				}
				p.Timestamps.Start = time;
			});
		}

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

		public RichPresence UpdateEndTime(DateTime time)
		{
			return Update(delegate(RichPresence p)
			{
				if (p.Timestamps == null)
				{
					p.Timestamps = new Timestamps();
				}
				p.Timestamps.End = time;
			});
		}

		public RichPresence UpdateClearTime()
		{
			return Update(delegate(RichPresence p)
			{
				p.Timestamps = null;
			});
		}

		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 bool RegisterUriScheme(string steamAppID = null, string executable = null)
		{
			SchemeInfo schemeInfo = default(SchemeInfo);
			schemeInfo.ApplicationID = ApplicationID;
			schemeInfo.SteamAppID = steamAppID;
			schemeInfo.ExecutablePath = executable ?? Process.GetCurrentProcess().MainModule.FileName;
			SchemeInfo info = schemeInfo;
			return HasRegisteredUriScheme = UriScheme.Register(info, _logger);
		}

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

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

		public void SetSubscription(EventType 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(EventType 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 & EventType.Spectate) == EventType.Spectate)
				{
					connection.EnqueueCommand(new SubscribeCommand
					{
						Event = ServerEvent.ActivitySpectate,
						IsUnsubscribe = isUnsubscribe
					});
				}
				if ((type & EventType.Join) == EventType.Join)
				{
					connection.EnqueueCommand(new SubscribeCommand
					{
						Event = ServerEvent.ActivityJoin,
						IsUnsubscribe = isUnsubscribe
					});
				}
				if ((type & EventType.JoinRequest) == EventType.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;
			}
		}
	}
	public enum ActivityType
	{
		Playing = 0,
		Listening = 2,
		Watching = 3,
		Competing = 5
	}
	[Serializable]
	public class Assets
	{
		private const string EXTERNAL_KEY_PREFIX = "mp:external";

		private string _largeimagekey;

		private string _largeimagetext;

		private string _largeimageurl;

		private string _smallimagekey;

		private string _smallimagetext;

		private string _smallimageurl;

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public string LargeImageKey
		{
			get
			{
				return _largeimagekey;
			}
			set
			{
				if (!BaseRichPresence.ValidateString(value, out _largeimagekey, useBytes: false, 256))
				{
					throw new StringOutOfRangeException(256);
				}
				LargeImageID = null;
			}
		}

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

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public string LargeImageUrl
		{
			get
			{
				return _largeimageurl;
			}
			set
			{
				if (!BaseRichPresence.ValidateString(value, out _largeimageurl, useBytes: false, 256))
				{
					throw new StringOutOfRangeException(256);
				}
				if (!BaseRichPresence.ValidateUrl(_largeimageurl))
				{
					throw new ArgumentException("Url must be a valid URI");
				}
			}
		}

		[JsonIgnore]
		public string LargeImageID { get; private set; }

		[JsonIgnore]
		public bool IsLargeImageKeyExternal { get; private set; }

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public string SmallImageKey
		{
			get
			{
				return _smallimagekey;
			}
			set
			{
				if (!BaseRichPresence.ValidateString(value, out _smallimagekey, useBytes: false, 256))
				{
					throw new StringOutOfRangeException(256);
				}
				SmallImageID = null;
			}
		}

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

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public string SmallImageUrl
		{
			get
			{
				return _smallimageurl;
			}
			set
			{
				if (!BaseRichPresence.ValidateString(value, out _smallimageurl, useBytes: false, 256))
				{
					throw new StringOutOfRangeException(256);
				}
				if (!BaseRichPresence.ValidateUrl(_smallimageurl))
				{
					throw new ArgumentException("Url must be a valid URI");
				}
			}
		}

		[JsonIgnore]
		public string SmallImageID { get; private set; }

		[JsonIgnore]
		public bool IsSmallImageKeyExternal { get; private set; }

		internal void Merge(Assets other)
		{
			_smallimagetext = other._smallimagetext;
			_smallimageurl = other._smallimageurl;
			_largeimagetext = other._largeimagetext;
			_largeimageurl = other._largeimageurl;
			string text = other._largeimagekey ?? "";
			ulong result;
			if (text.StartsWith("mp:external"))
			{
				IsLargeImageKeyExternal = true;
				LargeImageID = text;
			}
			else if (ulong.TryParse(text, out result))
			{
				IsLargeImageKeyExternal = false;
				LargeImageID = text;
			}
			else
			{
				IsLargeImageKeyExternal = false;
				LargeImageID = null;
				_largeimagekey = text;
			}
			string text2 = other._smallimagekey ?? "";
			if (text2.StartsWith("mp:external"))
			{
				IsSmallImageKeyExternal = true;
				SmallImageID = text2;
			}
			else if (ulong.TryParse(text2, out result))
			{
				IsSmallImageKeyExternal = false;
				SmallImageID = text2;
			}
			else
			{
				IsSmallImageKeyExternal = false;
				SmallImageID = null;
				_smallimagekey = text2;
			}
		}
	}
	public class Button
	{
		private string _label;

		private string _url;

		[JsonProperty("label")]
		public string Label
		{
			get
			{
				return _label;
			}
			set
			{
				if (!BaseRichPresence.ValidateString(value, out _label, useBytes: true, 31, Encoding.UTF8))
				{
					throw new StringOutOfRangeException(31);
				}
			}
		}

		[JsonProperty("url")]
		public string Url
		{
			get
			{
				return _url;
			}
			set
			{
				if (!BaseRichPresence.ValidateString(value, out _url, useBytes: false, 512))
				{
					throw new StringOutOfRangeException(512);
				}
				if (!BaseRichPresence.ValidateUrl(_url))
				{
					throw new ArgumentException("Url must be a valid URI");
				}
			}
		}
	}
	[Serializable]
	public class Party
	{
		public enum PrivacySetting
		{
			Private,
			Public
		}

		private string _partyid;

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

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

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

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

		[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];
				}
			}
		}
	}
	[Serializable]
	[JsonObject(/*Could not decode attribute arguments.*/)]
	public class BaseRichPresence
	{
		protected internal string _state;

		protected internal string _stateUrl;

		protected internal string _details;

		protected internal string _detailsUrl;

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

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public string StateUrl
		{
			get
			{
				return _stateUrl;
			}
			set
			{
				if (!ValidateString(value, out _stateUrl, useBytes: false, 256))
				{
					throw new StringOutOfRangeException(256);
				}
				if (!ValidateUrl(_stateUrl))
				{
					throw new ArgumentException("Url must be a valid URI");
				}
			}
		}

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

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public string DetailsUrl
		{
			get
			{
				return _detailsUrl;
			}
			set
			{
				if (!ValidateString(value, out _detailsUrl, useBytes: false, 256))
				{
					throw new StringOutOfRangeException(256);
				}
				if (!ValidateUrl(_detailsUrl))
				{
					throw new ArgumentException("Url must be a valid URI");
				}
			}
		}

		[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.*/)]
		public ActivityType Type { get; set; }

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

		public bool HasTimestamps()
		{
			if (Timestamps != null)
			{
				if (!Timestamps.Start.HasValue)
				{
					return Timestamps.End.HasValue;
				}
				return true;
			}
			return false;
		}

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

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

		public bool HasSecrets()
		{
			if (Secrets != null)
			{
				if (Secrets.JoinSecret == null)
				{
					return Secrets.SpectateSecret != null;
				}
				return true;
			}
			return false;
		}

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

		internal static bool ValidateUrl(string url)
		{
			if (string.IsNullOrEmpty(url))
			{
				return true;
			}
			if (!Uri.TryCreate(url, UriKind.Absolute, out Uri _))
			{
				return false;
			}
			return true;
		}

		public static implicit operator bool(BaseRichPresence presence)
		{
			return presence != null;
		}

		internal virtual bool Matches(RichPresence other)
		{
			if (other == null)
			{
				return false;
			}
			if (State != other.State || StateUrl != other.StateUrl || Details != other.Details || DetailsUrl != other.DetailsUrl || Type != other.Type)
			{
				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.LargeImageUrl != Assets.LargeImageUrl || other.Assets.SmallImageKey != Assets.SmallImageKey || other.Assets.SmallImageText != Assets.SmallImageText || other.Assets.SmallImageUrl != Assets.SmallImageUrl)
				{
					return false;
				}
			}
			else if (other.Assets != null)
			{
				return false;
			}
			return true;
		}

		public RichPresence ToRichPresence()
		{
			RichPresence richPresence = new RichPresence();
			richPresence.State = State;
			richPresence.StateUrl = StateUrl;
			richPresence.Details = Details;
			richPresence.DetailsUrl = DetailsUrl;
			richPresence.Type = Type;
			richPresence.StatusDisplay = StatusDisplay;
			richPresence.Party = ((!HasParty()) ? Party : null);
			richPresence.Secrets = ((!HasSecrets()) ? Secrets : null);
			if (HasAssets())
			{
				richPresence.Assets = new Assets
				{
					SmallImageKey = Assets.SmallImageKey,
					SmallImageText = Assets.SmallImageText,
					SmallImageUrl = Assets.SmallImageUrl,
					LargeImageKey = Assets.LargeImageKey,
					LargeImageText = Assets.LargeImageText,
					LargeImageUrl = Assets.LargeImageUrl
				};
			}
			if (HasTimestamps())
			{
				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 sealed class RichPresence : BaseRichPresence
	{
		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public Button[] Buttons { get; set; }

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

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

		public RichPresence WithStateUrl(string stateUrl)
		{
			base.StateUrl = stateUrl;
			return this;
		}

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

		public RichPresence WithDetailsUrl(string detailsUrl)
		{
			base.DetailsUrl = detailsUrl;
			return this;
		}

		public RichPresence WithType(ActivityType type)
		{
			base.Type = type;
			return this;
		}

		public RichPresence WithStatusDisplay(StatusDisplayType statusDisplay)
		{
			base.StatusDisplay = statusDisplay;
			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 WithButtons(Button topButton, Button bottomButton = null)
		{
			if (topButton != null && bottomButton != null)
			{
				Buttons = new Button[2] { topButton, bottomButton };
			}
			else if (topButton == null && bottomButton == null)
			{
				Buttons = null;
			}
			else
			{
				Buttons = new Button[1] { topButton ?? bottomButton };
			}
			return this;
		}

		public RichPresence Clone()
		{
			return new RichPresence
			{
				State = ((_state != null) ? (_state.Clone() as string) : null),
				StateUrl = ((_stateUrl != null) ? (_stateUrl.Clone() as string) : null),
				Details = ((_details != null) ? (_details.Clone() as string) : null),
				DetailsUrl = ((_detailsUrl != null) ? (_detailsUrl.Clone() as string) : null),
				Type = base.Type,
				StatusDisplay = base.StatusDisplay,
				Buttons = ((!HasButtons()) ? null : (Buttons.Clone() as Button[])),
				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)
				}),
				Timestamps = ((!HasTimestamps()) ? null : new Timestamps
				{
					Start = base.Timestamps.Start,
					End = base.Timestamps.End
				}),
				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),
					LargeImageUrl = ((base.Assets.LargeImageUrl != null) ? (base.Assets.LargeImageUrl.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),
					SmallImageUrl = ((base.Assets.SmallImageUrl != null) ? (base.Assets.SmallImageUrl.Clone() as string) : null)
				}),
				Party = ((!HasParty()) ? null : new Party
				{
					ID = base.Party.ID,
					Size = base.Party.Size,
					Max = base.Party.Max,
					Privacy = base.Party.Privacy
				})
			};
		}

		internal RichPresence Merge(BaseRichPresence presence)
		{
			_state = presence.State;
			_stateUrl = presence.StateUrl;
			_details = presence.Details;
			_detailsUrl = presence.DetailsUrl;
			base.Type = presence.Type;
			base.StatusDisplay = presence.StatusDisplay;
			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))
			{
				return false;
			}
			if ((Buttons == null) ^ (other.Buttons == null))
			{
				return false;
			}
			if (Buttons != null)
			{
				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;
		}
	}
	internal sealed class RichPresenceResponse : BaseRichPresence
	{
		[JsonProperty("application_id")]
		public string ClientID { get; private set; }

		[JsonProperty("name")]
		public string Name { get; private set; }
	}
	[Serializable]
	public class Secrets
	{
		[Obsolete("This feature has been deprecated my Mason in issue #152 on the offical library. Was originally used as a Notify Me feature, it has been replaced with Join / Spectate.", true)]
		public string MatchSecret;

		private string _joinSecret;

		private string _spectateSecret;

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

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

		public static Encoding Encoding => Encoding.UTF8;

		public static int SecretLength => 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 = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
			StringBuilder stringBuilder = new StringBuilder();
			for (int i = 0; i < SecretLength; i++)
			{
				stringBuilder.Append(text[random.Next(text.Length)]);
			}
			return stringBuilder.ToString();
		}
	}
	public enum StatusDisplayType
	{
		Name,
		State,
		Details
	}
	[Serializable]
	public class Timestamps
	{
		public static Timestamps Now => new Timestamps(DateTime.UtcNow);

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

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

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

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

		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 Timestamps()
		{
			Start = null;
			End = null;
		}

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

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

		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);
		}
	}
	public class User
	{
		public enum AvatarFormat
		{
			PNG,
			JPEG,
			WebP,
			GIF
		}

		public enum AvatarSize
		{
			x16 = 0x10,
			x32 = 0x20,
			x64 = 0x40,
			x128 = 0x80,
			x256 = 0x100,
			x512 = 0x200,
			x1024 = 0x400,
			x2048 = 0x800
		}

		public struct AvatarDecorationData
		{
			[JsonProperty("asset")]
			public string Asset { get; private set; }

			[JsonProperty("skuId")]
			public string SKU { get; private set; }
		}

		[Flags]
		public enum Flag
		{
			None = 0,
			Employee = 1,
			Partner = 2,
			HypeSquad = 4,
			BugHunter = 8,
			HouseBravery = 0x40,
			HouseBrilliance = 0x80,
			HouseBalance = 0x100,
			EarlySupporter = 0x200,
			TeamUser = 0x400,
			BugHunterLevel2 = 0x4000,
			VerifiedBot = 0x10000,
			VerifiedDeveloper = 0x20000,
			CertifiedModerator = 0x40000,
			BotHttpInteractions = 0x80000,
			ActiveDeveloper = 0x400000
		}

		public enum PremiumType
		{
			None,
			NitroClassic,
			Nitro,
			NitroBasic
		}

		[JsonProperty("id")]
		public ulong ID { get; private set; }

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

		[JsonProperty("discriminator")]
		[Obsolete("Discord no longer uses discriminators.")]
		public int Discriminator { get; private set; }

		[JsonProperty("global_name")]
		public string DisplayName { get; private set; }

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

		public bool IsAvatarAnimated
		{
			get
			{
				if (Avatar != null)
				{
					return Avatar.StartsWith("a_");
				}
				return false;
			}
		}

		[JsonProperty("avatar_decoration_data")]
		public AvatarDecorationData? AvatarDecoration { get; private set; }

		[JsonProperty("bot")]
		public bool Bot { get; private set; }

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

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public PremiumType 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 GetAvatarURL()
		{
			return GetAvatarURL(AvatarFormat.PNG, AvatarSize.x128);
		}

		public string GetAvatarURL(AvatarFormat format)
		{
			return GetAvatarURL(format, AvatarSize.x128);
		}

		public string GetAvatarURL(AvatarFormat format, AvatarSize size)
		{
			string text = $"/avatars/{ID}/{Avatar}";
			if (string.IsNullOrEmpty(Avatar))
			{
				if (format != 0)
				{
					throw new BadImageFormatException("The user has no avatar and the requested format " + format.ToString() + " is not supported. (Only supports PNG).");
				}
				int num = (int)((ID >> 22) % 6);
				if (Discriminator > 0)
				{
					num = Discriminator % 5;
				}
				text = $"/embed/avatars/{num}";
			}
			return $"https://{CdnEndpoint}{text}{GetAvatarExtension(format)}?size={(int)size}&animated=true";
		}

		public string GetAvatarDecorationURL()
		{
			return GetAvatarDecorationURL(AvatarFormat.PNG);
		}

		public string GetAvatarDecorationURL(AvatarFormat format)
		{
			if (!AvatarDecoration.HasValue)
			{
				return null;
			}
			string arg = "/avatar-decoration-presets/" + AvatarDecoration.Value.Asset;
			return $"https://{CdnEndpoint}{arg}{GetAvatarExtension(format)}";
		}

		public string GetAvatarExtension(AvatarFormat format)
		{
			return "." + format.ToString().ToLowerInvariant();
		}

		public override string ToString()
		{
			if (!string.IsNullOrEmpty(DisplayName))
			{
				return DisplayName;
			}
			if (Discriminator != 0)
			{
				return Username + "#" + Discriminator.ToString("D4");
			}
			return Username;
		}
	}
	[Flags]
	public enum EventType
	{
		None = 0,
		Spectate = 1,
		Join = 2,
		JoinRequest = 4
	}
}
namespace DiscordRPC.RPC
{
	internal class RpcConnection : IDisposable
	{
		public static readonly int VERSION = 1;

		public static readonly int POLL_RATE = 1000;

		private static readonly bool CLEAR_ON_SHUTDOWN = true;

		private static readonly bool LOCK_STEP = false;

		private ILogger _logger;

		private RpcState _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 = new object();

		private readonly uint _maxRxQueueSize;

		private Queue<IMessage> _rxqueue;

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

		private BackoffDelay delay;

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

		public RpcState State
		{
			get
			{
				lock (l_states)
				{
					return _state;
				}
			}
		}

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

		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()
		{
			nonce++;
			return nonce;
		}

		internal void EnqueueCommand(ICommand command)
		{
			Logger.Trace("Enqueue Command: {0}", 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
			{
				if (this.OnRpcMessage != null)
				{
					this.OnRpcMessage(this, message);
				}
			}
			catch (Exception ex)
			{
				Logger.Error("Unhandled Exception while processing event: {0}", 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: {0}", 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)
			{
				if (_rxqueue.Count == 0)
				{
					return null;
				}
				return _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.Level <= LogLevel.Trace)
			{
				Logger.Trace("============================");
				Logger.Trace("Assembly:             " + Assembly.GetAssembly(typeof(RichPresence)).FullName);
				Logger.Trace("Pipe:                 " + namedPipe.GetType().FullName);
				Logger.Trace("Platform:             " + Environment.OSVersion.ToString());
				Logger.Trace("DotNet:               " + Environment.Version.ToString());
				Logger.Trace("applicationID:        " + applicationID);
				Logger.Trace("targetPipe:           " + targetPipe);
				ILogger logger = Logger;
				int pOLL_RATE = POLL_RATE;
				logger.Trace("POLL_RATE:            " + pOLL_RATE);
				ILogger logger2 = Logger;
				uint maxRtQueueSize = _maxRtQueueSize;
				logger2.Trace("_maxRtQueueSize:      " + maxRtQueueSize);
				ILogger logger3 = Logger;
				maxRtQueueSize = _maxRxQueueSize;
				logger3.Trace("_maxRxQueueSize:      " + maxRtQueueSize);
				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 {0}", 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: {0}", frame.Opcode);
								switch (frame.Opcode)
								{
								case Opcode.Close:
								{
									ClosePayload @object = frame.GetObject<ClosePayload>();
									Logger.Warning("We have been told to terminate by discord: ({0}) {1}", @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! {0}", ex.Message);
										Logger.Error("Data: {0}", frame.Message);
									}
									try
									{
										if (eventPayload != null)
										{
											ProcessFrame(eventPayload);
										}
									}
									catch (Exception ex2)
									{
										Logger.Error("Failed to process event! {0}", ex2.Message);
										Logger.Error("Data: {0}", frame.Message);
									}
									break;
								}
								default:
									Logger.Error("Invalid opcode: {0}", frame.Opcode);
									flag = false;
									break;
								}
							}
							if (!aborting && namedPipe.IsConnected)
							{
								ProcessCommandQueue();
								queueUpdatedEvent.WaitOne(POLL_RATE);
							}
						}
						Logger.Trace("Left main read loop for some reason. Aborting: {0}, Shutting Down: {1}", aborting, 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 {0}ms before attempting to connect again", num);
						Thread.Sleep(delay.NextDelay());
					}
				}
				catch (Exception ex3)
				{
					Logger.Error("Unhandled Exception: {0}", ex3.GetType().FullName);
					Logger.Error(ex3.Message);
					Logger.Error(ex3.StackTrace);
				}
				finally
				{
					if (namedPipe.IsConnected)
					{
						Logger.Trace("Closing the named pipe.");
						namedPipe.Close();
					}
					SetConnectionState(RpcState.Disconnected);
				}
			}
			Logger.Trace("Left Main Loop");
			if (namedPipe != null)
			{
				namedPipe.Dispose();
			}
			Logger.Info("Thread Terminated, no longer performing RPC connection.");
		}

		private void ProcessFrame(EventPayload response)
		{
			//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
			Logger.Info("Handling Response. Cmd: {0}, Event: {1}", response.Command, 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: ({0}) {1}", @object.Code.ToString(), @object.Message);
				EnqueueMessage(@object);
			}
			else if (State == RpcState.Connecting && response.Command == Command.Dispatch && response.Event.HasValue && response.Event.Value == ServerEvent.Ready)
			{
				Logger.Info("Connection established with the RPC");
				SetConnectionState(RpcState.Connected);
				delay.Reset();
				ReadyMessage object2 = response.GetObject<ReadyMessage>();
				lock (l_config)
				{
					_configuration = object2.Configuration;
					object2.User.SetConfiguration(_configuration);
				}
				EnqueueMessage(object2);
			}
			else if (State == RpcState.Connected)
			{
				switch (response.Command)
				{
				case Command.Dispatch:
					ProcessDispatch(response);
					break;
				case Command.SetActivity:
				{
					if (response.Data == null)
					{
						EnqueueMessage(new PresenceMessage());
						break;
					}
					RichPresenceResponse object3 = response.GetObject<RichPresenceResponse>();
					EnqueueMessage(new PresenceMessage(object3));
					break;
				}
				case Command.Subscribe:
				case Command.Unsubscribe:
				{
					((Collection<JsonConverter>)(object)new JsonSerializer().Converters).Add((JsonConverter)(object)new EnumSnakeCaseConverter());
					ServerEvent value = response.GetObject<EventPayload>().Event.Value;
					if (response.Command == Command.Subscribe)
					{
						EnqueueMessage(new SubscribeMessage(value));
					}
					else
					{
						EnqueueMessage(new UnsubscribeMessage(value));
					}
					break;
				}
				case Command.SendActivityJoinInvite:
					Logger.Trace("Got invite response ack.");
					break;
				case Command.CloseActivityJoinRequest:
					Logger.Trace("Got invite response reject ack.");
					break;
				default:
					Logger.Error("Unknown frame was received! {0}", response.Command);
					break;
				}
			}
			else
			{
				Logger.Trace("Received a frame while we are disconnected. Ignoring. Cmd: {0}, Event: {1}", response.Command, response.Event);
			}
		}

		private void ProcessDispatch(EventPayload response)
		{
			if (response.Command == Command.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;
				}
				default:
					Logger.Warning("Ignoring {0}", response.Event.Value);
					break;
				}
			}
		}

		private void ProcessCommandQueue()
		{
			if (State != RpcState.Connected)
			{
				return;
			}
			if (aborting)
			{
				Logger.Warning("We have been told to write a queue but we have also been aborted.");
			}
			bool flag = true;
			ICommand command = null;
			while (flag && namedPipe.IsConnected)
			{
				lock (l_rtqueue)
				{
					flag = _rtqueue.Count > 0;
					if (!flag)
					{
						break;
					}
					command = _rtqueue.Peek();
				}
				if (shutdown || (!aborting && LOCK_STEP))
				{
					flag = false;
				}
				IPayload payload = command.PreparePayload(GetNextNonce());
				Logger.Trace("Attempting to send payload: {0}", 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: {0}", 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 = VERSION,
				ClientID = applicationID
			})))
			{
				Logger.Error("Failed to write a handshake.");
			}
			else
			{
				SetConnectionState(RpcState.Connecting);
			}
		}

		private void SendHandwave()
		{
			Logger.Info("Attempting to wave goodbye...");
			if (State == RpcState.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 = VERSION,
				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(RpcState state)
		{
			Logger.Trace("Setting the connection state to {0}", state.ToString().ToSnakeCase().ToUpperInvariant());
			lock (l_states)
			{
				_state = state;
			}
		}

		public void Shutdown()
		{
			Logger.Trace("Initiated shutdown procedure");
			shutdown = true;
			lock (l_rtqueue)
			{
				_rtqueue.Clear();
				if (CLEAR_ON_SHUTDOWN)
				{
					_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 RpcState
	{
		Disconnected,
		Connecting,
		Connected
	}
}
namespace DiscordRPC.RPC.Payload
{
	internal class ClosePayload : IPayload
	{
		[JsonProperty("code")]
		public int Code { get; set; }

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

		[JsonConstructor]
		public ClosePayload()
		{
			Code = -1;
			Reason = "";
		}
	}
	internal enum Command
	{
		[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,
		[Obsolete("This value is appart of the RPC API and is not supported by this library.", true)]
		Authorize,
		[Obsolete("This value is appart of the RPC API and is not supported by this library.", true)]
		Authenticate,
		[Obsolete("This value is appart of the RPC API and is not supported by this library.", true)]
		GetGuild,
		[Obsolete("This value is appart of the RPC API and is not supported by this library.", true)]
		GetGuilds,
		[Obsolete("This value is appart of the RPC API and is not supported by this library.", true)]
		GetChannel,
		[Obsolete("This value is appart of the RPC API and is not supported by this library.", true)]
		GetChannels,
		[Obsolete("This value is appart of the RPC API and is not supported by this library.", true)]
		SetUserVoiceSettings,
		[Obsolete("This value is appart of the RPC API and is not supported by this library.", true)]
		SelectVoiceChannel,
		[Obsolete("This value is appart of the RPC API and is not supported by this library.", true)]
		GetSelectedVoiceChannel,
		[Obsolete("This value is appart of the RPC API and is not supported by this library.", true)]
		SelectTextChannel,
		[Obsolete("This value is appart of the RPC API and is not supported by this library.", true)]
		GetVoiceSettings,
		[Obsolete("This value is appart of the RPC API and is not supported by this library.", true)]
		SetVoiceSettings,
		[Obsolete("This value is appart of the RPC API and is not supported by this library.", true)]
		CaptureShortcut
	}
	internal abstract class IPayload
	{
		[JsonProperty("cmd")]
		[JsonConverter(typeof(EnumSnakeCaseConverter))]
		public Command 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}, Nonce: {Nonce}";
		}
	}
	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 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>()
		{
			if (Data == null)
			{
				return default(T);
			}
			return ((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 DiscordRPC.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 = Command.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 = Command.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 ? Command.SendActivityJoinInvite : Command.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 ? Command.Unsubscribe : Command.Subscribe),
				Event = Event
			};
		}
	}
}
namespace DiscordRPC.Registry
{
	public interface IRegisterUriScheme
	{
		bool Register(SchemeInfo info);
	}
	public sealed class MacUriScheme : IRegisterUriScheme
	{
		private ILogger logger;

		public MacUriScheme(ILogger logger)
		{
			this.logger = logger;
		}

		public bool Register(SchemeInfo info)
		{
			string executablePath = info.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 (info.UsingSteamApp)
			{
				text = "steam://rungameid/" + info.SteamAppID;
			}
			else
			{
				logger.Warning("This library does not fully support MacOS URI Scheme Registration.");
			}
			string text2 = "~/Library/Application Support/discord/games";
			if (!Directory.CreateDirectory(text2).Exists)
			{
				logger.Error("Failed to register because {0} does not exist", text2);
				return false;
			}
			string text3 = text2 + "/" + info.ApplicationID + ".json";
			File.WriteAllText(text3, "{ \"command\": \"" + text + "\" }");
			logger.Trace("Registered {0}, {1}", text3, text);
			return true;
		}
	}
	public sealed class UnixUriScheme : IRegisterUriScheme
	{
		private ILogger logger;

		public UnixUriScheme(ILogger logger)
		{
			this.logger = logger;
		}

		public bool Register(SchemeInfo info)
		{
			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 = info.ExecutablePath;
			if (string.IsNullOrEmpty(executablePath))
			{
				logger.Error("Failed to register because the application was not located.");
				return false;
			}
			string text = null;
			text = ((!info.UsingSteamApp) ? executablePath : ("xdg-open steam://rungameid/" + info.SteamAppID));
			string text2 = $"[Desktop Entry]\nName=Game {info.ApplicationID}\nExec={text} %u\nType=Application\nNoDisplay=true\nCategories=Discord;Games;\nMimeType=x-scheme-handler/discord-{info.ApplicationID}";
			string text3 = "/discord-" + info.ApplicationID + ".desktop";
			string text4 = environmentVariable + "/.local/share/applications";
			if (!Directory.CreateDirectory(text4).Exists)
			{
				logger.Error("Failed to register because {0} does not exist", text4);
				return false;
			}
			File.WriteAllText(text4 + text3, text2);
			if (!RegisterMime(info.ApplicationID))
			{
				logger.Error("Failed to register because the Mime failed.");
				return false;
			}
			logger.Trace("Registered {0}, {1}, {2}", text4 + text3, text2, text);
			return true;
		}

		private 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 struct SchemeInfo
	{
		public string ApplicationID { get; set; }

		public string SteamAppID { get; set; }

		public string ExecutablePath { get; set; }

		public bool UsingSteamApp => !string.IsNullOrEmpty(SteamAppID);
	}
	public static class UriScheme
	{
		public static bool Register(SchemeInfo info, ILogger logger = null)
		{
			if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
			{
				return new WindowsUriScheme(logger).Register(info);
			}
			if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
			{
				return new UnixUriScheme(logger).Register(info);
			}
			if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
			{
				return new MacUriScheme(logger).Register(info);
			}
			logger?.Error("Unknown Platform: {0}", RuntimeInformation.OSDescription);
			throw new PlatformNotSupportedException("Platform does not support registration.");
		}
	}
	public sealed class WindowsUriScheme : IRegisterUriScheme
	{
		private ILogger logger;

		public WindowsUriScheme(ILogger logger)
		{
			this.logger = logger;
		}

		public bool Register(SchemeInfo info)
		{
			string executablePath = info.ExecutablePath;
			if (executablePath == null)
			{
				logger.Error("Failed to register application because the location was null.");
				return false;
			}
			string scheme = "discord-" + info.ApplicationID;
			string friendlyName = "Run game " + info.ApplicationID + " protocol";
			string defaultIcon = executablePath;
			string command = executablePath;
			if (info.UsingSteamApp)
			{
				string steamLocation = GetSteamLocation();
				if (steamLocation != null)
				{
					command = $"\"{steamLocation}\" steam://rungameid/{info.SteamAppID}";
				}
			}
			CreateUriScheme(scheme, friendlyName, defaultIcon, command);
			return true;
		}

		private void CreateUriScheme(string scheme, string friendlyName, string defaultIcon, string command)
		{
			if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
			{
				throw new PlatformNotSupportedException("Requires Windows to use the Registry");
			}
			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 {0}, {1}, {2}", scheme, friendlyName, command);
		}

		public string GetSteamLocation()
		{
			if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
			{
				throw new PlatformNotSupportedException("Requires Windows to use the Registry");
			}
			using RegistryKey registryKey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey("Software\\Valve\\Steam");
			if (registryKey == null)
			{
				return null;
			}
			return registryKey.GetValue("SteamExe") as string;
		}
	}
}
namespace DiscordRPC.Message
{
	public class CloseMessage : IMessage
	{
		public override MessageType Type => MessageType.Close;

		public string Reason { get; internal set; }

		public int Code { get; internal set; }

		internal CloseMessage()
		{
		}

		internal CloseMessage(string reason)
		{
			Reason = reason;
		}
	}
	public class ConnectionEstablishedMessage : IMessage
	{
		public override MessageType Type => MessageType.ConnectionEstablished;

		[Obsolete("The connected pipe is not neccessary information.")]
		public int ConnectedPipe { get; internal set; }
	}
	public class ConnectionFailedMessage : IMessage
	{
		public override MessageType Type => MessageType.ConnectionFailed;

		public int FailedPipe { get; internal set; }
	}
	public class ErrorMessage : IMessage
	{
		public override MessageType Type => MessageType.Error;

		[JsonProperty("code")]
		public ErrorCode Code { get; internal set; }

		[JsonProperty("message")]
		public string Message { get; internal set; }
	}
	public enum ErrorCode
	{
		Success = 0,
		PipeException = 1,
		ReadCorrupt = 2,
		NotImplemented = 10,
		UnknownError = 1000,
		InvalidPayload = 4000,
		InvalidCommand = 4002,
		InvalidEvent = 4004
	}
	public abstract class IMessage
	{
		private DateTime _timecreated;

		public abstract MessageType Type { get; }

		public DateTime TimeCreated => _timecreated;

		public IMessage()
		{
			_timecreated = DateTime.Now;
		}
	}
	public class JoinMessage : IMessage
	{
		public override MessageType Type => MessageType.Join;

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

		[JsonProperty("user")]
		public User User { get; internal set; }
	}
	public enum MessageType
	{
		Ready,
		Close,
		Error,
		PresenceUpdate,
		Subscribe,
		Unsubscribe,
		Join,
		Spectate,
		JoinRequest,
		ConnectionEstablished,
		ConnectionFailed
	}
	public class PresenceMessage : IMessage
	{
		public override MessageType Type => MessageType.PresenceUpdate;

		public BaseRichPresence Presence { get; internal set; }

		public string Name { get; internal set; }

		public string ApplicationID { get; internal set; }

		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
	{
		public override MessageType Type => MessageType.Ready;

		[JsonProperty("config")]
		public Configuration Configuration { get; set; }

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

		[JsonProperty("v")]
		public int Version { get; set; }
	}
	public class SpectateMessage : JoinMessage
	{
		public override MessageType Type => MessageType.Spectate;
	}
	public class SubscribeMessage : IMessage
	{
		public override MessageType Type => MessageType.Subscribe;

		public EventType Event { get; internal set; }

		internal SubscribeMessage(ServerEvent evt)
		{
			switch (evt)
			{
			default:
				Event = EventType.Join;
				break;
			case ServerEvent.ActivityJoinRequest:
				Event = EventType.JoinRequest;
				break;
			case ServerEvent.ActivitySpectate:
				Event = EventType.Spectate;
				break;
			}
		}
	}
	public class UnsubscribeMessage : IMessage
	{
		public override MessageType Type => MessageType.Unsubscribe;

		public EventType Event { get; internal set; }

		internal UnsubscribeMessage(ServerEvent evt)
		{
			switch (evt)
			{
			default:
				Event = EventType.Join;
				break;
			case ServerEvent.ActivityJoinRequest:
				Event = EventType.JoinRequest;
				break;
			case ServerEvent.ActivitySpectate:
				Event = EventType.Spectate;
				break;
			}
		}
	}
}
namespace DiscordRPC.Logging
{
	public class ConsoleLogger : ILogger
	{
		public LogLevel Level { get; set; }

		public bool Coloured { get; set; }

		public bool Colored
		{
			get
			{
				return Coloured;
			}
			set
			{
				Coloured = value;
			}
		}

		public ConsoleLogger()
		{
			Level = LogLevel.Info;
			Coloured = false;
		}

		public ConsoleLogger(LogLevel level)
			: this()
		{
			Level = level;
		}

		public ConsoleLogger(LogLevel level, bool coloured)
		{
			Level = level;
			Coloured = coloured;
		}

		public void Trace(string message, params object[] args)
		{
			if (Level <= LogLevel.Trace)
			{
				if (Coloured)
				{
					Console.ForegroundColor = ConsoleColor.Gray;
				}
				string text = "TRACE: " + message;
				if (args.Length != 0)
				{
					Console.WriteLine(text, args);
				}
				else
				{
					Console.WriteLine(text);
				}
			}
		}

		public void Info(string message, params object[] args)
		{
			if (Level <= LogLevel.Info)
			{
				if (Coloured)
				{
					Console.ForegroundColor = ConsoleColor.White;
				}
				string text = "INFO: " + message;
				if (args.Length != 0)
				{
					Console.WriteLine(text, args);
				}
				else
				{
					Console.WriteLine(text);
				}
			}
		}

		public void Warning(string message, params object[] args)
		{
			if (Level <= LogLevel.Warning)
			{
				if (Coloured)
				{
					Console.ForegroundColor = ConsoleColor.Yellow;
				}
				string text = "WARN: " + message;
				if (args.Length != 0)
				{
					Console.WriteLine(text, args);
				}
				else
				{
					Console.WriteLine(text);
				}
			}
		}

		public void Error(string message, params object[] args)
		{
			if (Level <= LogLevel.Error)
			{
				if (Coloured)
				{
					Console.ForegroundColor = ConsoleColor.Red;
				}
				string text = "ERR : " + message;
				if (args.Length != 0)
				{
					Console.WriteLine(text, args);
				}
				else
				{
					Console.WriteLine(text);
				}
			}
		}
	}
	public class FileLogger : ILogger
	{
		private object filelock;

		public LogLevel Level { get; set; }

		public string File { get; set; }

		public FileLogger(string path)
			: this(path, LogLevel.Info)
		{
		}

		public FileLogger(string path, LogLevel level)
		{
			Level = level;
			File = path;
			filelock = new object();
		}

		public void Trace(string message, params object[] args)
		{
			if (Level > LogLevel.Trace)
			{
				return;
			}
			lock (filelock)
			{
				System.IO.File.AppendAllText(File, "\r\nTRCE: " + ((args.Length != 0) ? string.Format(message, args) : message));
			}
		}

		public void Info(string message, params object[] args)
		{
			if (Level > LogLevel.Info)
			{
				return;
			}
			lock (filelock)
			{
				System.IO.File.AppendAllText(File, "\r\nINFO: " + ((args.Length != 0) ? string.Format(message, args) : message));
			}
		}

		public void Warning(string message, params object[] args)
		{
			if (Level > LogLevel.Warning)
			{
				return;
			}
			lock (filelock)
			{
				System.IO.File.AppendAllText(File, "\r\nWARN: " + ((args.Length != 0) ? string.Format(message, args) : message));
			}
		}

		public void Error(string message, params object[] args)
		{
			if (Level > LogLevel.Error)
			{
				return;
			}
			lock (filelock)
			{
				System.IO.File.AppendAllText(File, "\r\nERR : " + ((args.Length != 0) ? string.Format(message, args) : message));
			}
		}
	}
	public interface ILogger
	{
		LogLevel Level { get; set; }

		void Trace(string message, params object[] args);

		void Info(string message, params object[] args);

		void Warning(string message, params object[] args);

		void Error(string message, params object[] args);
	}
	public enum LogLevel
	{
		Trace = 1,
		Info = 2,
		Warning = 3,
		Error = 4,
		None = 256
	}
	public class NullLogger : ILogger
	{
		public LogLevel Level { get; set; }

		public void Trace(string message, params object[] args)
		{
		}

		public void Info(string message, params object[] args)
		{
		}

		public void Warning(string message, params object[] args)
		{
		}

		public void Error(string message, params object[] args)
		{
		}
	}
}
namespace DiscordRPC.IO
{
	internal class Handshake
	{
		[JsonProperty("v")]
		public int Version { get; set; }

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

		bool IsConnected { get; }

		[Obsolete("The connected pipe is not neccessary information.")]
		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 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 ILogger Logger { get; set; }

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

		public int ConnectedPipe { get; private set; }

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

		public bool Connect(int pipe)
		{
			Logger.Trace("ManagedNamedPipeClient.Connection({0})", pipe);
			if (_isDisposed)
			{
				throw new ObjectDisposedException("NamedPipe");
			}
			if (pipe > 9)
			{
				throw new ArgumentOutOfRangeException("pipe", "Argument cannot be greater than 9");
			}
			int startPipe = 0;
			if (pipe >= 0)
			{
				startPipe = pipe;
			}
			foreach (string pipe2 in PipeLocation.GetPipes(startPipe))
			{
				if (AttemptConnection(pipe2))
				{
					BeginReadStream();
					return true;
				}
			}
			return false;
		}

		private bool AttemptConnection(string pipename)
		{
			if (_isDisposed)
			{
				throw new ObjectDisposedException("_stream");
			}
			try
			{
				lock (l_stream)
				{
					Logger.Info("Attempting to connect to '{0}'", pipename);
					_stream = new NamedPipeClientStream(".", pipename, PipeDirection.InOut, PipeOptions.Asynchronous);
					_stream.Connect(0);
					Logger.Trace("Waiting for connection...");
					do
					{
						Thread.Sleep(10);
					}
					while (!_stream.IsConnected);
				}
				Logger.Info("Connected to '{0}'", pipename);
				ConnectedPipe = int.Parse(pipename.Substring(pipename.LastIndexOf('-')));
				_isClosed = false;
			}
			catch (Exception ex)
			{
				Logger.Error("Failed connection to {0}. {1}", pipename, ex.Message);
				Close();
			}
			Logger.Trace("Done. Result: {0}", _isClosed);
			return !_isClosed;
		}

		private void BeginReadStream()
		{
			if (_isClosed)
			{
				return;
			}
			try
			{
				lock (l_stream)
				{
					if (_stream != null && _stream.IsConnected)
					{
						Logger.Trace("Begining Read of {0} bytes", _buffer.Length);
						_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: {0}", ex3.Message);
				Logger.Error(ex3.StackTrace);
			}
		}

		private void EndReadStream(IAsyncResult callback)
		{
			Logger.Trace("Ending Read");
			int num = 0;
			try
			{
				lock (l_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: {0}", ex4.Message);
				Logger.Error(ex4.StackTrace);
				return;
			}
			Logger.Trace("Read {0} bytes", num);
			if (num > 0)
			{
				using MemoryStream stream = new MemoryStream(_buffer, 0, num);
				try
				{
					PipeFrame item = default(PipeFrame);
					if (item.ReadStream(stream))
					{
						Logger.Trace("Read a frame: {0}", 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: {0}", ex5.Message);
					Close();
				}
			}
			else
			{
				Logger.Error("Empty frame was read on {0}, aborting.", Environment.OSVersion);
				Close();
			}
			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: {0}", 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)
						{
						}
						_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;
			}
		}

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

		[Obsolete("Use PipePermutation.GetPipes instead", true)]
		public static string GetPipeName(int pipe)
		{
			return string.Empty;
		}

		[Obsolete("Use PipePermutation.GetPipes instead", true)]
		public static string GetPipeName(int pipe, string sandbox)
		{
			return string.Empty;
		}

		[Obsolete("Use PipePermutation.GetPipes instead", true)]
		public static string GetPipeSandbox()
		{
			return string.Empty;
		}

		[Obsolete("Use PipePermutation.GetPipes instead", true)]
		public static bool IsUnix()
		{
			return true;
		}
	}
	public enum Opcode : uint
	{
		Handshake,
		Frame,
		Close,
		Ping,
		Pong
	}
	public struct PipeFrame : IEquatable<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 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)
		{
			string message = JsonConvert.SerializeObject(obj);
			SetMessage(message);
		}

		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();
			uint num2 = (uint)Min(2048, value2);
			byte[] array = new byte[num2];
			int count;
			while ((count = stream.Read(array, 0, Min(array.Length, num))) > 0)
			{
				num -= num2;
				memoryStream.Write(array, 0, count);
			}
			byte[] array2 = memoryStream.ToArray();
			if (array2.LongLength != value2)
			{
				return false;
			}
			Opcode = (Opcode)value;
			Data = array2;
			return true;
		}

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

		private bool TryReadUInt32(Stream stream, out uint value)
		{
			byte[] array = new byte[4];
			if (stream.Read(array, 0, array.Length) != 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);
		}

		public bool Equals(PipeFrame other)
		{
			if (Opcode == other.Opcode && Length == other.Length)
			{
				return Data == other.Data;
			}
			return false;
		}
	}
	public static class PipeLocation
	{
		[CompilerGenerated]
		private sealed class <GetUnixPipes>d__5 : IEnumerable<string>, IEnumerable, IEnumerator<string>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private string <>2__current;

			private int <>l__initialThreadId;

			private int index;

			public int <>3__index;

			private IEnumerator<string> <>7__wrap1;

			private string <tempDir>5__3;

			private string[] <>7__wrap3;

			private int <>7__wrap4;

			string IEnumerator<string>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <GetUnixPipes>d__5(int <>1__state)
			{
				this.<>1__state = <>1__state;
				<>l__initialThreadId = Environment.CurrentManagedThreadId;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				int num = <>1__state;
				if (num == -3 || (uint)(num - 1) <= 1u)
				{
					try
					{
					}
					finally
					{
						<>m__Finally1();
					}
				}
				<>7__wrap1 = null;
				<tempDir>5__3 = null;
				<>7__wrap3 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				try
				{
					switch (<>1__state)
					{
					default:
						return false;
					case 0:
						<>1__state = -1;
						<>7__wrap1 = TemporaryDirectories().GetEnumerator();
						<>1__state = -3;
						break;
					case 1:
						<>1__state = -3;
						<>7__wrap3 = LinuxPackageManagers;
						<>7__wrap4 = 0;
						goto IL_0105;
					case 2:
						{
							<>1__state = -3;
							<>7__wrap4++;
							goto IL_0105;
						}
						IL_0105:
						if (<>7__wrap4 < <>7__wrap3.Length)
						{
							string path = <>7__wrap3[<>7__wrap4];
							<>2__current = Path.Combine(<tempDir>5__3, path, string.Format("{0}{1}", "discord-ipc-", index));
							<>1__state = 2;
							return true;
						}
						<>7__wrap3 = null;
						<tempDir>5__3 = null;
						break;
					}
					if (<>7__wrap1.MoveNext())
					{
						<tempDir>5__3 = <>7__wrap1.Current;
						<>2__current = Path.Combine(<tempDir>5__3, string.Format("{0}{1}", "discord-ipc-", index));
						<>1__state = 1;
						return true;
					}
					<>m__Finally1();
					<>7__wrap1 = null;
					return false;
				}
				catch
				{
					//try-fault
					((IDisposable)this).Dispose();
					throw;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			private void <>m__Finally1()
			{
				<>1__state = -1;
				if (<>7__wrap1 != null)
				{
					<>7__wrap1.Dispose();
				}
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}

			[DebuggerHidden]
			IEnumerator<string> IEnumerable<string>.GetEnumerator()
			{
				<GetUnixPipes>d__5 <GetUnixPipes>d__;
				if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
				{
					<>1__state = 0;
					<GetUnixPipes>d__ = this;
				}
				else
				{
					<GetUnixPipes>d__ = new <GetUnixPipes>d__5(0);
				}
				<GetUnixPipes>d__.index = <>3__index;
				return <GetUnixPipes>d__;
			}

			[DebuggerHidden]
			IEnumerator IEnumerable.GetEnumerator()
			{
				return ((IEnumerable<string>)this).GetEnumerator();
			}
		}

		[CompilerGenerated]
		private sealed class <GetWindowsPipes>d__4 : IEnumerable<string>, IEnumerable, IEnumerator<string>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private string <>2__current;

			private int <>l__initialThreadId;

			private int index;

			public int <>3__index;

			string IEnumerator<string>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <GetWindowsPipes>d__4(int <>1__state)
			{
				this.<>1__state = <>1__state;
				<>l__initialThreadId = Environment.CurrentManagedThreadId;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = string.Format("{0}{1}", "discord-ipc-", index);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					return false;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}

			[DebuggerHidden]
			IEnumerator<string> IEnumerable<string>.GetEnumerator()
			{
				<GetWindowsPipes>d__4 <GetWindowsPipes>d__;
				if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
				{
					<>1__state = 0;
					<GetWindowsPipes>d__ = this;
				}
				else
				{
					<GetWindowsPipes>d__ = new <GetWindowsPipes>d__4(0);
				}
				<GetWindowsPipes>d__.index = <>3__index;
				return <GetWindowsPipes>d__;
			}

			[DebuggerHidden]
			IEnumerator IEnumerable.GetEnumerator()
			{
				return ((IEnumerable<string>)this).GetEnumerator();
			}
		}

		[CompilerGenerated]
		private sealed class <TemporaryDirectories>d__6 : IEnumerable<string>, IEnumerable, IEnumerator<string>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private string <>2__current;

			private int <>l__initialThreadId;

			string IEnumerator<string>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <TemporaryDirectories>d__6(int <>1__state)
			{
				this.<>1__state = <>1__state;
				<>l__initialThreadId = Environment.CurrentManagedThreadId;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				string environmentVariable;
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					environmentVariable = Environment.GetEnvironmentVariable("XDG_RUNTIME_DIR");
					if (environmentVariable != null)
					{
						<>2__current = environmentVariable;
						<>1__state = 1;
						return true;
					}
					goto IL_0053;
				case 1:
					<>1__state = -1;
					goto IL_0053;
				case 2:
					<>1__state = -1;
					goto IL_0078;
				case 3:
					<>1__state = -1;
					goto IL_009d;
				case 4:
					<>1__state = -1;
					goto IL_00c2;
				case 5:
					{
						<>1__state = -1;
						return false;
					}
					IL_009d:
					environmentVariable = Environment.GetEnvironmentVariable("TEMP");
					if (environmentVariable != null)
					{
						<>2__current = environmentVariable;
						<>1__state = 4;
						return true;
					}
					goto IL_00c2;
					IL_0053:
					environmentVariable = Environment.GetEnvironmentVariable("TMPDIR");
					if (environmentVariable != null)
					{
						<>2__current = environmentVariable;
						<>1__state = 2;
						return true;
					}
					goto IL_0078;
					IL_0078:
					environmentVariable = Environment.GetEnvironmentVariable("TMP");
					if (environmentVariable != null)
					{
						<>2__current = environmentVariable;
						<>1__state = 3;
						return true;
					}
					goto IL_009d;
					IL_00c2:
					<>2__current = "/temp";
					<>1__state = 5;
					return true;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}

			[DebuggerHidden]
			IEnumerator<string> IEnumerable<string>.GetEnumerator()
			{
				if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
				{
					<>1__state = 0;
					return this;
				}
				return new <TemporaryDirectories>d__6(0);
			}

			[DebuggerHidden]
			IEnumerator IEnumerable.GetEnumerator()
			{
				return ((IEnumerable<string>)this).GetEnumerator();
			}
		}

		private const string DiscordPipePrefix = "discord-ipc-";

		private const int MaximumPipeVariations = 10;

		private static readonly string[] LinuxPackageManagers = new string[2] { "app/com.discordapp.Discord/", "snap.discord/" };

		public static IEnumerable<string> GetPipes(int startPipe = 0)
		{
			IsOSUnix();
			if (IsOSUnix())
			{
				return Enumerable.Range(startPipe, 10).SelectMany(GetUnixPipes);
			}
			return Enumerable.Range(startPipe, 10).SelectMany(GetWindowsPipes);
		}

		[IteratorStateMachine(typeof(<GetWindowsPipes>d__4))]
		private static IEnumerable<string> GetWindowsPipes(int index)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <GetWindowsPipes>d__4(-2)
			{
				<>3__index = index
			};
		}

		[IteratorStateMachine(typeof(<GetUnixPipes>d__5))]
		private static IEnumerable<string> GetUnixPipes(int index)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <GetUnixPipes>d__5(-2)
			{
				<>3__index = index
			};
		}

		[IteratorStateMachine(typeof(<TemporaryDirectories>d__6))]
		private static IEnumerable<string> TemporaryDirectories()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <TemporaryDirectories>d__6(-2);
		}

		private static bool IsOSUnix()
		{
			if (Environment.OSVersion.Platform == PlatformID.Unix)
			{
				return true;
			}
			return false;
		}
	}
}
namespace DiscordRPC.Helper
{
	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 = (float)(Maximum - Minimum) / 100f;
			_current = (int)Math.Floor(num * (double)_fails) + Minimum;
			return Math.Min(Math.Max(_current, Minimum), Maximum);
		}
	}
	public static class StringTools
	{
		public static string GetNullOrString(this string str)
		{
			if (str.Length != 0 && !string.IsNullOrEmpty(str.Trim()))
			{
				return str;
			}
			return null;
		}

		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?.ToLowerInvariant().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;
			}
			return string.Concat(str.Select((char x, int i) => (i <= 0 || !char.IsUpper(x)) ? x.ToString() : ("_" + x)).ToArray()).ToUpperInvariant();
		}
	}
}
namespace DiscordRPC.Exceptions
{
	public class BadPresenceException : Exception
	{
		internal BadPresenceException(string message)
			: base(message)
		{
		}
	}
	public class InvalidConfigurationException : Exception
	{
		internal InvalidConfigurationException(string message)
			: base(message)
		{
		}
	}
	[Obsolete("Not actually used anywhere")]
	public class InvalidPipeException : Exception
	{
		internal InvalidPipeException(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 DiscordRPC.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);
}
namespace DiscordRPC.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 = null;
			if (TryParseEnum(objectType, (string)reader.Value, out obj))
			{
				return obj;
			}
			return 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);
			foreach (MemberInfo memberInfo in members)
			{
				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 bool TryParseEnum(Type enumType, string str, out object obj

UserLibs/Scriban.dll

Decompiled 2 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Numerics;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Scriban.Functions;
using Scriban.Helpers;
using Scriban.Parsing;
using Scriban.Runtime;
using Scriban.Runtime.Accessors;
using Scriban.Syntax;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: InternalsVisibleTo("Scriban.Tests")]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")]
[assembly: AssemblyCompany("Alexandre Mutel")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Alexandre Mutel")]
[assembly: AssemblyDescription("Scriban is a fast, powerful, safe and lightweight scripting language and engine for .NET, which was primarily developed for text templating with a compatibility mode for parsing liquid templates.")]
[assembly: AssemblyFileVersion("6.5.7.0")]
[assembly: AssemblyInformationalVersion("6.5.7+44876ae9de7b2855f1eb51d041c7b3ce5e1fe224")]
[assembly: AssemblyProduct("Scriban")]
[assembly: AssemblyTitle("Scriban")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/scriban/scriban")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: AssemblyVersion("6.0.0.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class IsReadOnlyAttribute : Attribute
	{
	}
	[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 Scriban
{
	[DebuggerDisplay("Count: {Count}")]
	public class LogMessageBag : IReadOnlyList<LogMessage>, IEnumerable<LogMessage>, IEnumerable, IReadOnlyCollection<LogMessage>
	{
		private readonly List<LogMessage> _messages;

		public int Count => _messages.Count;

		public LogMessage this[int index] => _messages[index];

		public bool HasErrors { get; private set; }

		public LogMessageBag()
		{
			_messages = new List<LogMessage>();
		}

		public void Add(LogMessage message)
		{
			if (message == null)
			{
				throw new ArgumentNullException("message");
			}
			if (message.Type == ParserMessageType.Error)
			{
				HasErrors = true;
			}
			_messages.Add(message);
		}

		public void AddRange(IEnumerable<LogMessage> messages)
		{
			if (messages == null)
			{
				throw new ArgumentNullException("messages");
			}
			foreach (LogMessage message in messages)
			{
				Add(message);
			}
		}

		public IEnumerator<LogMessage> GetEnumerator()
		{
			return _messages.GetEnumerator();
		}

		IEnumerator IEnumerable.GetEnumerator()
		{
			return ((IEnumerable)_messages).GetEnumerator();
		}

		public override string ToString()
		{
			StringBuilder stringBuilder = new StringBuilder();
			foreach (LogMessage message in _messages)
			{
				stringBuilder.AppendLine(message.ToString());
			}
			return stringBuilder.ToString();
		}
	}
	public class Template
	{
		public string SourceFilePath { get; }

		public ScriptPage Page { get; private set; }

		public bool HasErrors { get; private set; }

		public LogMessageBag Messages { get; }

		public ParserOptions ParserOptions { get; }

		public LexerOptions LexerOptions { get; }

		private async ValueTask<object> EvaluateAndRenderAsync(TemplateContext context, bool render)
		{
			if (context == null)
			{
				throw new ArgumentNullException("context");
			}
			CheckErrors();
			if (SourceFilePath != null)
			{
				context.PushSourceFile(SourceFilePath);
			}
			try
			{
				context.UseScientific = LexerOptions.Lang == ScriptLang.Scientific;
				object result = await context.EvaluateAsync(Page).ConfigureAwait(continueOnCapturedContext: false);
				if (render && Page != null && context.EnableOutput && result != null)
				{
					await context.WriteAsync(Page.Span, result).ConfigureAwait(continueOnCapturedContext: false);
				}
				return result;
			}
			finally
			{
				if (SourceFilePath != null)
				{
					context.PopSourceFile();
				}
			}
		}

		public async ValueTask<object> EvaluateAsync(TemplateContext context)
		{
			bool previousOutput = context.EnableOutput;
			try
			{
				context.UseScientific = LexerOptions.Lang == ScriptLang.Scientific;
				context.EnableOutput = false;
				return await EvaluateAndRenderAsync(context, render: false).ConfigureAwait(continueOnCapturedContext: false);
			}
			finally
			{
				context.EnableOutput = previousOutput;
			}
		}

		public static async ValueTask<object> EvaluateAsync(string expression, TemplateContext context)
		{
			if (expression == null)
			{
				throw new ArgumentNullException("expression");
			}
			LexerOptions lexerOptions = default(LexerOptions);
			lexerOptions.Mode = ScriptMode.ScriptOnly;
			LexerOptions value = lexerOptions;
			LexerOptions? lexerOptions2 = value;
			return await Parse(expression, null, null, lexerOptions2).EvaluateAsync(context).ConfigureAwait(continueOnCapturedContext: false);
		}

		public async ValueTask<object> EvaluateAsync(object model = null, MemberRenamerDelegate memberRenamer = null, MemberFilterDelegate memberFilter = null)
		{
			ScriptObject scriptObject = new ScriptObject();
			if (model != null)
			{
				scriptObject.Import(model, memberFilter, memberRenamer);
			}
			TemplateContext context = ((LexerOptions.Lang == ScriptLang.Liquid) ? new LiquidTemplateContext() : new TemplateContext());
			context.EnableOutput = false;
			context.MemberRenamer = memberRenamer;
			context.MemberFilter = memberFilter;
			context.UseScientific = LexerOptions.Lang == ScriptLang.Scientific;
			context.PushGlobal(scriptObject);
			object result = await EvaluateAsync(context).ConfigureAwait(continueOnCapturedContext: false);
			context.PopGlobal();
			return result;
		}

		public static async ValueTask<object> EvaluateAsync(string expression, object model, MemberRenamerDelegate memberRenamer = null, MemberFilterDelegate memberFilter = null)
		{
			if (expression == null)
			{
				throw new ArgumentNullException("expression");
			}
			LexerOptions lexerOptions = default(LexerOptions);
			lexerOptions.Mode = ScriptMode.ScriptOnly;
			LexerOptions value = lexerOptions;
			LexerOptions? lexerOptions2 = value;
			return await Parse(expression, null, null, lexerOptions2).EvaluateAsync(model, memberRenamer, memberFilter).ConfigureAwait(continueOnCapturedContext: false);
		}

		public async ValueTask<string> RenderAsync(TemplateContext context)
		{
			await EvaluateAndRenderAsync(context, render: true).ConfigureAwait(continueOnCapturedContext: false);
			string? result = context.Output.ToString();
			if (context.Output is StringBuilderOutput stringBuilderOutput)
			{
				stringBuilderOutput.Builder.Length = 0;
			}
			return result;
		}

		public async ValueTask<string> RenderAsync(object model = null, MemberRenamerDelegate memberRenamer = null, MemberFilterDelegate memberFilter = null)
		{
			ScriptObject scriptObject = new ScriptObject();
			if (model != null)
			{
				scriptObject.Import(model, memberFilter, memberRenamer);
			}
			TemplateContext templateContext = ((LexerOptions.Lang == ScriptLang.Liquid) ? new LiquidTemplateContext() : new TemplateContext());
			templateContext.MemberRenamer = memberRenamer;
			templateContext.MemberFilter = memberFilter;
			templateContext.PushGlobal(scriptObject);
			return await RenderAsync(templateContext).ConfigureAwait(continueOnCapturedContext: false);
		}

		private Template(ParserOptions? parserOptions, LexerOptions? lexerOptions, string sourceFilePath)
		{
			ParserOptions = parserOptions.GetValueOrDefault();
			LexerOptions = lexerOptions.GetValueOrDefault();
			Messages = new LogMessageBag();
			SourceFilePath = sourceFilePath;
		}

		public static Template Parse(string text, string sourceFilePath = null, ParserOptions? parserOptions = null, LexerOptions? lexerOptions = null)
		{
			Template template = new Template(parserOptions, lexerOptions, sourceFilePath);
			template.ParseInternal(text, sourceFilePath);
			return template;
		}

		public static Template ParseLiquid(string text, string sourceFilePath = null, ParserOptions? parserOptions = null, LexerOptions? lexerOptions = null)
		{
			LexerOptions valueOrDefault = lexerOptions.GetValueOrDefault();
			valueOrDefault.Lang = ScriptLang.Liquid;
			return Parse(text, sourceFilePath, parserOptions, valueOrDefault);
		}

		public static object Evaluate(string expression, TemplateContext context)
		{
			if (expression == null)
			{
				throw new ArgumentNullException("expression");
			}
			LexerOptions lexerOptions = default(LexerOptions);
			lexerOptions.Mode = ScriptMode.ScriptOnly;
			LexerOptions value = lexerOptions;
			LexerOptions? lexerOptions2 = value;
			return Parse(expression, null, null, lexerOptions2).Evaluate(context);
		}

		public static object Evaluate(string expression, object model, MemberRenamerDelegate memberRenamer = null, MemberFilterDelegate memberFilter = null)
		{
			if (expression == null)
			{
				throw new ArgumentNullException("expression");
			}
			LexerOptions lexerOptions = default(LexerOptions);
			lexerOptions.Mode = ScriptMode.ScriptOnly;
			LexerOptions value = lexerOptions;
			LexerOptions? lexerOptions2 = value;
			return Parse(expression, null, null, lexerOptions2).Evaluate(model, memberRenamer, memberFilter);
		}

		public object Evaluate(TemplateContext context)
		{
			bool enableOutput = context.EnableOutput;
			try
			{
				context.UseScientific = LexerOptions.Lang == ScriptLang.Scientific;
				context.EnableOutput = false;
				return EvaluateAndRender(context, render: false);
			}
			finally
			{
				context.EnableOutput = enableOutput;
			}
		}

		public object Evaluate(object model = null, MemberRenamerDelegate memberRenamer = null, MemberFilterDelegate memberFilter = null)
		{
			ScriptObject scriptObject = new ScriptObject();
			if (model != null)
			{
				scriptObject.Import(model, memberFilter, memberRenamer);
			}
			TemplateContext templateContext = ((LexerOptions.Lang == ScriptLang.Liquid) ? new LiquidTemplateContext() : new TemplateContext());
			templateContext.EnableOutput = false;
			templateContext.MemberRenamer = memberRenamer;
			templateContext.MemberFilter = memberFilter;
			templateContext.UseScientific = LexerOptions.Lang == ScriptLang.Scientific;
			templateContext.PushGlobal(scriptObject);
			object result = Evaluate(templateContext);
			templateContext.PopGlobal();
			return result;
		}

		public string Render(TemplateContext context)
		{
			EvaluateAndRender(context, render: true);
			string? result = context.Output.ToString();
			if (context.Output is StringBuilderOutput stringBuilderOutput)
			{
				stringBuilderOutput.Builder.Length = 0;
			}
			return result;
		}

		public string Render(object model = null, MemberRenamerDelegate memberRenamer = null, MemberFilterDelegate memberFilter = null)
		{
			ScriptObject scriptObject = new ScriptObject();
			if (model != null)
			{
				scriptObject.Import(model, memberFilter, memberRenamer);
			}
			TemplateContext templateContext = ((LexerOptions.Lang == ScriptLang.Liquid) ? new LiquidTemplateContext() : new TemplateContext());
			templateContext.MemberRenamer = memberRenamer;
			templateContext.MemberFilter = memberFilter;
			templateContext.PushGlobal(scriptObject);
			return Render(templateContext);
		}

		public string ToText(ScriptPrinterOptions options = default(ScriptPrinterOptions))
		{
			CheckErrors();
			TextWriterOutput textWriterOutput = new TextWriterOutput();
			new ScriptPrinter(textWriterOutput, options).Write(Page);
			return textWriterOutput.ToString();
		}

		private object EvaluateAndRender(TemplateContext context, bool render)
		{
			if (context == null)
			{
				throw new ArgumentNullException("context");
			}
			CheckErrors();
			if (SourceFilePath != null)
			{
				context.PushSourceFile(SourceFilePath);
			}
			try
			{
				context.UseScientific = LexerOptions.Lang == ScriptLang.Scientific;
				object obj = context.Evaluate(Page);
				if (render && Page != null && context.EnableOutput && obj != null)
				{
					context.Write(Page.Span, obj);
				}
				return obj;
			}
			finally
			{
				if (SourceFilePath != null)
				{
					context.PopSourceFile();
				}
			}
		}

		private void CheckErrors()
		{
			if (HasErrors)
			{
				throw new InvalidOperationException("This template has errors. Check the <Template.HasError> and <Template.Messages> before evaluating a template. Messages:\n" + string.Join("\n", Messages));
			}
		}

		private void ParseInternal(string text, string sourceFilePath)
		{
			if (string.IsNullOrEmpty(text))
			{
				HasErrors = false;
				Page = new ScriptPage
				{
					Span = new SourceSpan(sourceFilePath, default(TextPosition), TextPosition.Eof)
				};
			}
			else
			{
				Parser parser = new Parser(new Lexer(text, sourceFilePath, LexerOptions), ParserOptions);
				Page = parser.Run();
				HasErrors = parser.HasErrors;
				Messages.AddRange(parser.Messages);
			}
		}
	}
	public class TemplateContext : IFormatProvider
	{
		public delegate bool TryGetMemberDelegate(TemplateContext context, SourceSpan span, object target, string member, out object value);

		public delegate bool TryGetVariableDelegate(TemplateContext context, SourceSpan span, ScriptVariable variable, out object value);

		public delegate string RenderRuntimeExceptionDelegate(ScriptRuntimeException exception);

		internal enum LoopType
		{
			Default,
			Queryable
		}

		private class VariableContext
		{
			public IScriptObject LocalObject;

			public FastStack<ScriptObject> Loops;

			public VariableContext(IScriptObject localObject)
			{
				LocalObject = localObject;
				Loops = new FastStack<ScriptObject>(4);
			}
		}

		private enum VariableScope
		{
			Local,
			Loop
		}

		[CompilerGenerated]
		private sealed class <GetStoreForRead>d__306 : IEnumerable<IScriptObject>, IEnumerable, IEnumerator<IScriptObject>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private IScriptObject <>2__current;

			private int <>l__initialThreadId;

			private ScriptVariable variable;

			public ScriptVariable <>3__variable;

			public TemplateContext <>4__this;

			private bool <isInLoop>5__2;

			private int <i>5__3;

			private VariableContext <context>5__4;

			private ScriptObject[] <loopItems>5__5;

			private int <j>5__6;

			IScriptObject IEnumerator<IScriptObject>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <GetStoreForRead>d__306(int <>1__state)
			{
				this.<>1__state = <>1__state;
				<>l__initialThreadId = Environment.CurrentManagedThreadId;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<context>5__4 = null;
				<loopItems>5__5 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				int num = <>1__state;
				TemplateContext templateContext = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
				{
					<>1__state = -1;
					ScriptVariableScope scope = variable.Scope;
					if (scope != 0)
					{
						if (scope == ScriptVariableScope.Local)
						{
							<loopItems>5__5 = templateContext._currentLocalContext.Loops.Items;
							<i>5__3 = templateContext._currentLocalContext.Loops.Count - 1;
							goto IL_01bf;
						}
						throw new NotImplementedException($"Variable scope `{scope}` is not implemented");
					}
					<isInLoop>5__2 = templateContext.IsInLoop;
					<i>5__3 = templateContext._globalContexts.Count - 1;
					goto IL_0149;
				}
				case 1:
					<>1__state = -1;
					<j>5__6--;
					goto IL_00ff;
				case 2:
					<>1__state = -1;
					<context>5__4 = null;
					<i>5__3--;
					goto IL_0149;
				case 3:
					<>1__state = -1;
					<i>5__3--;
					goto IL_01bf;
				case 4:
					<>1__state = -1;
					break;
				case 5:
					{
						<>1__state = -1;
						break;
					}
					IL_0149:
					if (<i>5__3 < 0)
					{
						break;
					}
					<context>5__4 = templateContext._globalContexts.Items[<i>5__3];
					if (<isInLoop>5__2)
					{
						int count = <context>5__4.Loops.Count;
						if (count > 0)
						{
							<loopItems>5__5 = <context>5__4.Loops.Items;
							<j>5__6 = count - 1;
							goto IL_00ff;
						}
					}
					goto IL_010f;
					IL_010f:
					<>2__current = <context>5__4.LocalObject;
					<>1__state = 2;
					return true;
					IL_01bf:
					if (<i>5__3 >= 0)
					{
						<>2__current = <loopItems>5__5[<i>5__3];
						<>1__state = 3;
						return true;
					}
					if (templateContext._currentLocalContext.LocalObject != null)
					{
						<>2__current = templateContext._currentLocalContext.LocalObject;
						<>1__state = 4;
						return true;
					}
					if (templateContext._globalContexts.Count > 0)
					{
						<>2__current = templateContext._globalContexts.Peek().LocalObject;
						<>1__state = 5;
						return true;
					}
					throw new ScriptRuntimeException(variable.Span, $"Invalid usage of the local variable `{variable}` in the current context");
					IL_00ff:
					if (<j>5__6 >= 0)
					{
						<>2__current = <loopItems>5__5[<j>5__6];
						<>1__state = 1;
						return true;
					}
					<loopItems>5__5 = null;
					goto IL_010f;
				}
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}

			[DebuggerHidden]
			IEnumerator<IScriptObject> IEnumerable<IScriptObject>.GetEnumerator()
			{
				<GetStoreForRead>d__306 <GetStoreForRead>d__;
				if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
				{
					<>1__state = 0;
					<GetStoreForRead>d__ = this;
				}
				else
				{
					<GetStoreForRead>d__ = new <GetStoreForRead>d__306(0)
					{
						<>4__this = <>4__this
					};
				}
				<GetStoreForRead>d__.variable = <>3__variable;
				return <GetStoreForRead>d__;
			}

			[DebuggerHidden]
			IEnumerator IEnumerable.GetEnumerator()
			{
				return ((IEnumerable<IScriptObject>)this).GetEnumerator();
			}
		}

		private FastStack<ScriptObject> _availableStores;

		internal FastStack<ScriptBlockStatement> BlockDelegates;

		private FastStack<VariableContext> _globalContexts;

		private FastStack<CultureInfo> _cultures;

		private readonly Dictionary<Type, IListAccessor> _listAccessors;

		private FastStack<ScriptLoopStatementBase> _loops;

		private readonly Dictionary<Type, IObjectAccessor> _memberAccessors;

		private FastStack<IScriptOutput> _outputs;

		private FastStack<VariableContext> _localContexts;

		private VariableContext _currentLocalContext;

		private IScriptOutput _output;

		private FastStack<string> _sourceFiles;

		private FastStack<object> _caseValues;

		private int _callDepth;

		private bool _isFunctionCallDisabled;

		private int _loopStep;

		private int _getOrSetValueLevel;

		private FastStack<VariableContext> _availableGlobalContexts;

		private FastStack<VariableContext> _availableLocalContexts;

		private FastStack<ScriptPipeArguments> _availablePipeArguments;

		private FastStack<ScriptPipeArguments> _pipeArguments;

		private FastStack<List<ScriptExpression>> _availableScriptExpressionLists;

		private object[][] _availableReflectionArguments;

		private ScriptPipeArguments _currentPipeArguments;

		private bool _previousTextWasNewLine;

		private readonly IEqualityComparer<string> _keyComparer;

		public static RenderRuntimeExceptionDelegate RenderRuntimeExceptionDefault = (ScriptRuntimeException ex) => $"[{ex.OriginalMessage}]";

		private static readonly object TrueObject = true;

		private static readonly object FalseObject = false;

		private int _objectToStringLevel;

		private int _currentToStringLength;

		internal bool AllowPipeArguments => _getOrSetValueLevel <= 1;

		public CultureInfo CurrentCulture
		{
			get
			{
				if (_cultures.Count != 0)
				{
					return _cultures.Peek();
				}
				return CultureInfo.InvariantCulture;
			}
		}

		public ITemplateLoader TemplateLoader { get; set; }

		public bool IsLiquid { get; protected set; }

		public bool AutoIndent { get; set; }

		public bool IndentOnEmptyLines { get; set; }

		[Obsolete("Use AutoIndent instead. Note that AutoIndent is true by default.")]
		public bool IndentWithInclude
		{
			get
			{
				return AutoIndent;
			}
			set
			{
				AutoIndent = value;
			}
		}

		public int LimitToString { get; set; }

		public int ObjectRecursionLimit { get; set; }

		public string NewLine { get; set; }

		public ScriptLang Language { get; set; }

		public CancellationToken CancellationToken { get; set; }

		public ParserOptions TemplateLoaderParserOptions { get; set; }

		public LexerOptions TemplateLoaderLexerOptions { get; set; }

		public MemberRenamerDelegate MemberRenamer { get; set; }

		public MemberFilterDelegate MemberFilter { get; set; }

		public int LoopLimit { get; set; }

		public int? LoopLimitQueryable { get; set; }

		public int RecursiveLimit { get; set; }

		public bool EnableOutput { get; set; }

		public IScriptOutput Output => _output;

		public bool UseScientific { get; set; }

		public bool ErrorForStatementFunctionAsExpression { get; set; }

		public ScriptObject BuiltinObject { get; }

		public IScriptObject CurrentGlobal => _globalContexts.Peek()?.LocalObject;

		public Dictionary<string, Template> CachedTemplates { get; }

		public string CurrentSourceFile => _sourceFiles.Peek();

		public TryGetVariableDelegate TryGetVariable { get; set; }

		public RenderRuntimeExceptionDelegate RenderRuntimeException { get; set; }

		public TryGetMemberDelegate TryGetMember { get; set; }

		public Dictionary<object, object> Tags { get; }

		internal ScriptPipeArguments CurrentPipeArguments => _currentPipeArguments;

		public int GlobalCount => _globalContexts.Count;

		public int OutputCount => _outputs.Count;

		public int CultureCount => _cultures.Count;

		public int SourceFileCount => _sourceFiles.Count;

		internal ScriptFlowState FlowState { get; set; }

		public TimeSpan RegexTimeOut { get; set; }

		public bool StrictVariables { get; set; }

		public bool EnableBreakAndContinueAsReturnOutsideLoop { get; set; }

		public bool EnableRelaxedTargetAccess { get; set; }

		public bool EnableRelaxedMemberAccess { get; set; }

		public bool EnableRelaxedFunctionAccess { get; set; }

		public bool EnableRelaxedIndexerAccess { get; set; }

		public bool EnableNullIndexer { get; set; }

		public ScriptNode CurrentNode { get; private set; }

		public SourceSpan CurrentSpan => CurrentNode?.Span ?? default(SourceSpan);

		public string CurrentIndent { get; set; }

		internal bool IsInLoop => _loops.Count > 0;

		internal bool IgnoreExceptionsWhileRewritingScientific { get; set; }

		protected virtual async ValueTask<Template> CreateTemplateAsync(string templatePath, ScriptNode callerContext)
		{
			string text;
			try
			{
				text = await TemplateLoader.LoadAsync(this, callerContext.Span, templatePath).ConfigureAwait(continueOnCapturedContext: false);
			}
			catch (Exception ex) when (!(ex is ScriptRuntimeException))
			{
				throw new ScriptRuntimeException(callerContext.Span, "Unexpected exception while creating template from path `" + templatePath + "`", ex);
			}
			if (text == null)
			{
				throw new ScriptRuntimeException(callerContext.Span, "The result of including `" + templatePath + "` cannot be null");
			}
			Template template = Template.Parse(text, templatePath, TemplateLoaderParserOptions, TemplateLoaderLexerOptions);
			if (template.HasErrors)
			{
				throw new ScriptParserRuntimeException(callerContext.Span, "Error while parsing template `" + templatePath + "`", template.Messages);
			}
			CachedTemplates.Add(templatePath, template);
			return template;
		}

		public virtual async ValueTask<object> EvaluateAsync(ScriptNode scriptNode, bool aliasReturnedFunction)
		{
			if (scriptNode == null)
			{
				return null;
			}
			bool previousFunctionCallState = _isFunctionCallDisabled;
			int previousLevel = _getOrSetValueLevel;
			ScriptNode previousNode = CurrentNode;
			try
			{
				CurrentNode = scriptNode;
				_getOrSetValueLevel = 0;
				_isFunctionCallDisabled = aliasReturnedFunction;
				return await scriptNode.EvaluateAsync(this).ConfigureAwait(continueOnCapturedContext: false);
			}
			catch (ScriptRuntimeException exception) when (RenderRuntimeException != null)
			{
				return RenderRuntimeException(exception);
			}
			catch (Exception ex) when (!(ex is ScriptRuntimeException))
			{
				ScriptRuntimeException ex2 = new ScriptRuntimeException(scriptNode.Span, ex.Message, ex);
				if (RenderRuntimeException != null)
				{
					return RenderRuntimeException(ex2);
				}
				throw ex2;
			}
			finally
			{
				CurrentNode = previousNode;
				_getOrSetValueLevel = previousLevel;
				_isFunctionCallDisabled = previousFunctionCallState;
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public async ValueTask<object> EvaluateAsync(ScriptNode scriptNode)
		{
			return await EvaluateAsync(scriptNode, aliasReturnedFunction: false).ConfigureAwait(continueOnCapturedContext: false);
		}

		public async ValueTask<Template> GetOrCreateTemplateAsync(string templatePath, ScriptNode callerContext)
		{
			if (!CachedTemplates.TryGetValue(templatePath, out var value))
			{
				value = await CreateTemplateAsync(templatePath, callerContext).ConfigureAwait(continueOnCapturedContext: false);
				CachedTemplates[templatePath] = value;
			}
			return value;
		}

		private async ValueTask<object> GetOrSetValueAsync(ScriptExpression targetExpression, object valueToSet, bool setter)
		{
			object value = null;
			try
			{
				if (targetExpression is IScriptVariablePath scriptVariablePath)
				{
					if (setter)
					{
						await scriptVariablePath.SetValueAsync(this, valueToSet).ConfigureAwait(continueOnCapturedContext: false);
					}
					else
					{
						value = await scriptVariablePath.GetValueAsync(this).ConfigureAwait(continueOnCapturedContext: false);
					}
				}
				else
				{
					if (setter)
					{
						throw new ScriptRuntimeException(targetExpression.Span, "Unsupported target expression for assignment.");
					}
					value = await EvaluateAsync(targetExpression).ConfigureAwait(continueOnCapturedContext: false);
				}
			}
			catch (Exception ex) when (_getOrSetValueLevel == 1 && !(ex is ScriptRuntimeException))
			{
				throw new ScriptRuntimeException(targetExpression.Span, "Unexpected exception while accessing target expression: " + ex.Message, ex);
			}
			if (((_isFunctionCallDisabled && _getOrSetValueLevel > 1) || !_isFunctionCallDisabled) && ScriptFunctionCall.IsFunction(value))
			{
				value = await ScriptFunctionCall.CallAsync(this, targetExpression, value, _getOrSetValueLevel == 1, null).ConfigureAwait(continueOnCapturedContext: false);
			}
			return value;
		}

		public async ValueTask<object> GetValueAsync(ScriptExpression target)
		{
			ScriptNode previousNode = CurrentNode;
			_getOrSetValueLevel++;
			try
			{
				CurrentNode = target;
				return await GetOrSetValueAsync(target, null, setter: false).ConfigureAwait(continueOnCapturedContext: false);
			}
			finally
			{
				CurrentNode = previousNode;
				_getOrSetValueLevel--;
			}
		}

		public async ValueTask<string> RenderTemplateAsync(Template template, ScriptArray arguments, ScriptNode callerContext)
		{
			string result = null;
			EnterRecursive(callerContext);
			string previousIndent = CurrentIndent;
			CurrentIndent = null;
			PushOutput();
			PushLocal();
			try
			{
				SetValue(ScriptVariable.Arguments, arguments, asReadOnly: true, force: true);
				IEnumerable<ScriptNamedArgument> enumerable = (callerContext as ScriptFunctionCall)?.Arguments.OfType<ScriptNamedArgument>();
				if (enumerable != null)
				{
					foreach (ScriptNamedArgument item in enumerable)
					{
						string name = item.Name.Name;
						object value = await item.Value.EvaluateAsync(this).ConfigureAwait(continueOnCapturedContext: false);
						ScriptVariable variable = ScriptVariable.Create(name, ScriptVariableScope.Local);
						SetValue(variable, value, asReadOnly: false, force: true);
					}
				}
				if (previousIndent != null)
				{
					ResetPreviousNewLine();
				}
				result = await template.RenderAsync(this).ConfigureAwait(continueOnCapturedContext: false);
				if (previousIndent != null)
				{
					ResetPreviousNewLine();
				}
			}
			finally
			{
				PopLocal();
				PopOutput();
				CurrentIndent = previousIndent;
				ExitRecursive(callerContext);
			}
			return result;
		}

		public async ValueTask SetValueAsync(ScriptExpression target, object value)
		{
			if (target == null)
			{
				throw new ArgumentNullException("target");
			}
			_getOrSetValueLevel++;
			try
			{
				await GetOrSetValueAsync(target, value, setter: true).ConfigureAwait(continueOnCapturedContext: false);
			}
			finally
			{
				_getOrSetValueLevel--;
			}
		}

		public async ValueTask<TemplateContext> WriteAsync(string text, int startIndex, int count)
		{
			if (text != null)
			{
				if (CurrentIndent != null)
				{
					int index = startIndex;
					int indexEnd = startIndex + count;
					while (index < indexEnd)
					{
						int newLineIndex = text.IndexOf('\n', index);
						if (newLineIndex < 0 || newLineIndex >= indexEnd)
						{
							if (_previousTextWasNewLine)
							{
								await Output.WriteAsync(CurrentIndent, 0, CurrentIndent.Length, CancellationToken).ConfigureAwait(continueOnCapturedContext: false);
								_previousTextWasNewLine = false;
							}
							await Output.WriteAsync(text, index, indexEnd - index, CancellationToken).ConfigureAwait(continueOnCapturedContext: false);
							break;
						}
						int length = newLineIndex - index;
						if (_previousTextWasNewLine && (IndentOnEmptyLines || (length != 0 && (length != 1 || text[index] != '\r'))))
						{
							await Output.WriteAsync(CurrentIndent, 0, CurrentIndent.Length, CancellationToken).ConfigureAwait(continueOnCapturedContext: false);
							_previousTextWasNewLine = false;
						}
						await Output.WriteAsync(text, index, length + 1, CancellationToken).ConfigureAwait(continueOnCapturedContext: false);
						index = newLineIndex + 1;
						_previousTextWasNewLine = true;
					}
				}
				else
				{
					if (count > 0)
					{
						_previousTextWasNewLine = text[startIndex + count - 1] == '\n';
					}
					await Output.WriteAsync(text, startIndex, count, CancellationToken).ConfigureAwait(continueOnCapturedContext: false);
				}
			}
			return this;
		}

		public async ValueTask<TemplateContext> WriteAsync(string text)
		{
			if (text != null)
			{
				await WriteAsync(text, 0, text.Length).ConfigureAwait(continueOnCapturedContext: false);
			}
			return this;
		}

		public async ValueTask<TemplateContext> WriteAsync(ScriptStringSlice slice)
		{
			await WriteAsync(slice.FullText, slice.Index, slice.Length).ConfigureAwait(continueOnCapturedContext: false);
			return this;
		}

		public virtual async ValueTask<TemplateContext> WriteAsync(SourceSpan span, object textAsObject)
		{
			if (textAsObject != null)
			{
				string text = ObjectToString(textAsObject);
				await WriteAsync(text).ConfigureAwait(continueOnCapturedContext: false);
			}
			return this;
		}

		public async ValueTask<TemplateContext> WriteLineAsync()
		{
			await WriteAsync(NewLine).ConfigureAwait(continueOnCapturedContext: false);
			return this;
		}

		public TemplateContext()
			: this(null, null)
		{
		}

		public TemplateContext(ScriptObject builtin)
			: this(builtin, null)
		{
		}

		public TemplateContext(IEqualityComparer<string> keyComparer)
			: this(null, keyComparer)
		{
		}

		public TemplateContext(ScriptObject builtin, IEqualityComparer<string> keyComparer)
		{
			BuiltinObject = builtin ?? GetDefaultBuiltinObject();
			EnableOutput = true;
			EnableBreakAndContinueAsReturnOutsideLoop = false;
			EnableRelaxedTargetAccess = false;
			EnableRelaxedMemberAccess = true;
			EnableRelaxedFunctionAccess = false;
			EnableRelaxedIndexerAccess = true;
			AutoIndent = true;
			IndentOnEmptyLines = true;
			LoopLimit = 1000;
			RecursiveLimit = 100;
			LimitToString = 0;
			ObjectRecursionLimit = 0;
			MemberRenamer = StandardMemberRenamer.Default;
			RegexTimeOut = TimeSpan.FromSeconds(10.0);
			TemplateLoaderParserOptions = default(ParserOptions);
			TemplateLoaderLexerOptions = LexerOptions.Default;
			NewLine = Environment.NewLine;
			Language = ScriptLang.Default;
			_outputs = new FastStack<IScriptOutput>(4);
			_output = new StringBuilderOutput();
			_outputs.Push(_output);
			_globalContexts = new FastStack<VariableContext>(4);
			_availableGlobalContexts = new FastStack<VariableContext>(4);
			_availableLocalContexts = new FastStack<VariableContext>(4);
			_localContexts = new FastStack<VariableContext>(4);
			_availableStores = new FastStack<ScriptObject>(4);
			_cultures = new FastStack<CultureInfo>(4);
			_caseValues = new FastStack<object>(4);
			_sourceFiles = new FastStack<string>(4);
			_memberAccessors = new Dictionary<Type, IObjectAccessor>();
			_listAccessors = new Dictionary<Type, IListAccessor>();
			_loops = new FastStack<ScriptLoopStatementBase>(4);
			BlockDelegates = new FastStack<ScriptBlockStatement>(4);
			_availablePipeArguments = new FastStack<ScriptPipeArguments>(4);
			_pipeArguments = new FastStack<ScriptPipeArguments>(4);
			_availableScriptExpressionLists = new FastStack<List<ScriptExpression>>(4);
			_availableReflectionArguments = new object[65][];
			_keyComparer = keyComparer;
			for (int i = 0; i < _availableReflectionArguments.Length; i++)
			{
				_availableReflectionArguments[i] = new object[i];
			}
			_isFunctionCallDisabled = false;
			CachedTemplates = new Dictionary<string, Template>();
			Tags = new Dictionary<object, object>();
			PushGlobal(BuiltinObject);
		}

		public void CheckAbort()
		{
			RuntimeHelpers.EnsureSufficientExecutionStack();
			CancellationToken cancellationToken = CancellationToken;
			if (cancellationToken.IsCancellationRequested)
			{
				throw new ScriptAbortException(CurrentNode?.Span ?? default(SourceSpan), cancellationToken);
			}
		}

		public void PushCulture(CultureInfo culture)
		{
			if (culture == null)
			{
				throw new ArgumentNullException("culture");
			}
			_cultures.Push(culture);
		}

		public CultureInfo PopCulture()
		{
			if (_cultures.Count == 0)
			{
				throw new InvalidOperationException("Cannot PopCulture more than PushCulture");
			}
			return _cultures.Pop();
		}

		internal void PushPipeArguments()
		{
			ScriptPipeArguments scriptPipeArguments = ((_availablePipeArguments.Count > 0) ? _availablePipeArguments.Pop() : new ScriptPipeArguments(1));
			_pipeArguments.Push(scriptPipeArguments);
			_currentPipeArguments = scriptPipeArguments;
		}

		internal void ClearPipeArguments()
		{
			while (_pipeArguments.Count > 0)
			{
				PopPipeArguments();
			}
		}

		internal List<ScriptExpression> GetOrCreateListOfScriptExpressions(int capacity)
		{
			List<ScriptExpression> list = ((_availableScriptExpressionLists.Count > 0) ? _availableScriptExpressionLists.Pop() : new List<ScriptExpression>());
			if (capacity > list.Capacity)
			{
				list.Capacity = capacity;
			}
			return list;
		}

		internal void ReleaseListOfScriptExpressions(List<ScriptExpression> list)
		{
			_availableScriptExpressionLists.Push(list);
			list.Clear();
		}

		internal object[] GetOrCreateReflectionArguments(int length)
		{
			if (length < 0)
			{
				throw new ArgumentOutOfRangeException("length");
			}
			if (length >= _availableReflectionArguments.Length)
			{
				return new object[length];
			}
			object[] array = _availableReflectionArguments[length] ?? new object[length];
			if (length > 0)
			{
				_availableReflectionArguments[length] = (object[])array[0];
				array[0] = null;
			}
			return array;
		}

		internal void ReleaseReflectionArguments(object[] reflectionArguments)
		{
			if (reflectionArguments != null && reflectionArguments.Length < _availableReflectionArguments.Length)
			{
				Array.Clear(reflectionArguments, 0, reflectionArguments.Length);
				object[] array = _availableReflectionArguments[reflectionArguments.Length];
				_availableReflectionArguments[reflectionArguments.Length] = reflectionArguments;
				if (reflectionArguments.Length != 0)
				{
					reflectionArguments[0] = array;
				}
			}
		}

		internal void PopPipeArguments()
		{
			if (_pipeArguments.Count == 0)
			{
				throw new InvalidOperationException("Cannot PopPipeArguments more than PushPipeArguments");
			}
			ScriptPipeArguments scriptPipeArguments = _pipeArguments.Pop();
			scriptPipeArguments.Clear();
			_currentPipeArguments = ((_pipeArguments.Count > 0) ? _pipeArguments.Peek() : null);
			_availablePipeArguments.Push(scriptPipeArguments);
		}

		public void PushSourceFile(string sourceFile)
		{
			if (sourceFile == null)
			{
				throw new ArgumentNullException("sourceFile");
			}
			_sourceFiles.Push(sourceFile);
		}

		public string PopSourceFile()
		{
			if (_sourceFiles.Count == 0)
			{
				throw new InvalidOperationException("Cannot PopSourceFile more than PushSourceFile");
			}
			return _sourceFiles.Pop();
		}

		public object GetValue(ScriptExpression target)
		{
			ScriptNode currentNode = CurrentNode;
			_getOrSetValueLevel++;
			try
			{
				CurrentNode = target;
				return GetOrSetValue(target, null, setter: false);
			}
			finally
			{
				CurrentNode = currentNode;
				_getOrSetValueLevel--;
			}
		}

		public void SetValue(ScriptVariable variable, bool value)
		{
			SetValue(variable, value ? TrueObject : FalseObject);
		}

		public virtual void Import(SourceSpan span, object objectToImport)
		{
			if (!(objectToImport is ScriptObject))
			{
				throw new ScriptRuntimeException(span, "Unexpected value `" + GetTypeName(objectToImport) + "` for import. Expecting an plain script object.");
			}
			CurrentGlobal.Import(objectToImport);
		}

		public void SetValue(ScriptExpression target, object value)
		{
			if (target == null)
			{
				throw new ArgumentNullException("target");
			}
			_getOrSetValueLevel++;
			try
			{
				GetOrSetValue(target, value, setter: true);
			}
			finally
			{
				_getOrSetValueLevel--;
			}
		}

		public void PushOutput()
		{
			PushOutput(new StringBuilderOutput());
		}

		public void PushOutput(IScriptOutput output)
		{
			_output = output ?? throw new ArgumentNullException("output");
			_outputs.Push(_output);
		}

		public IScriptOutput PopOutput()
		{
			if (_outputs.Count == 1)
			{
				throw new InvalidOperationException("Unexpected PopOutput for top level writer");
			}
			IScriptOutput result = _outputs.Pop();
			_output = _outputs.Peek();
			return result;
		}

		public virtual TemplateContext Write(SourceSpan span, object textAsObject)
		{
			if (textAsObject != null)
			{
				string text = ObjectToString(textAsObject);
				Write(text);
			}
			return this;
		}

		public TemplateContext Write(string text)
		{
			if (text != null)
			{
				Write(text, 0, text.Length);
			}
			return this;
		}

		public TemplateContext WriteLine()
		{
			Write(NewLine);
			return this;
		}

		public TemplateContext Write(ScriptStringSlice slice)
		{
			Write(slice.FullText, slice.Index, slice.Length);
			return this;
		}

		public TemplateContext Write(string text, int startIndex, int count)
		{
			if (text != null)
			{
				if (CurrentIndent != null)
				{
					int num = startIndex;
					int num2 = startIndex + count;
					while (num < num2)
					{
						int num3 = text.IndexOf('\n', num);
						if (num3 < 0 || num3 >= num2)
						{
							if (_previousTextWasNewLine)
							{
								Output.Write(CurrentIndent, 0, CurrentIndent.Length);
								_previousTextWasNewLine = false;
							}
							Output.Write(text, num, num2 - num);
							break;
						}
						int num4 = num3 - num;
						if (_previousTextWasNewLine && (IndentOnEmptyLines || (num4 != 0 && (num4 != 1 || text[num] != '\r'))))
						{
							Output.Write(CurrentIndent, 0, CurrentIndent.Length);
							_previousTextWasNewLine = false;
						}
						Output.Write(text, num, num4 + 1);
						num = num3 + 1;
						_previousTextWasNewLine = true;
					}
				}
				else
				{
					if (count > 0)
					{
						_previousTextWasNewLine = text[startIndex + count - 1] == '\n';
					}
					Output.Write(text, startIndex, count);
				}
			}
			return this;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public object Evaluate(ScriptNode scriptNode)
		{
			return Evaluate(scriptNode, aliasReturnedFunction: false);
		}

		public virtual object Evaluate(ScriptNode scriptNode, bool aliasReturnedFunction)
		{
			if (scriptNode == null)
			{
				return null;
			}
			bool isFunctionCallDisabled = _isFunctionCallDisabled;
			int getOrSetValueLevel = _getOrSetValueLevel;
			ScriptNode currentNode = CurrentNode;
			try
			{
				CurrentNode = scriptNode;
				_getOrSetValueLevel = 0;
				_isFunctionCallDisabled = aliasReturnedFunction;
				return scriptNode.Evaluate(this);
			}
			catch (ScriptRuntimeException exception) when (RenderRuntimeException != null)
			{
				return RenderRuntimeException(exception);
			}
			catch (Exception ex) when (!(ex is ScriptRuntimeException))
			{
				ScriptRuntimeException ex2 = new ScriptRuntimeException(scriptNode.Span, ex.Message, ex);
				if (RenderRuntimeException != null)
				{
					return RenderRuntimeException(ex2);
				}
				throw ex2;
			}
			finally
			{
				CurrentNode = currentNode;
				_getOrSetValueLevel = getOrSetValueLevel;
				_isFunctionCallDisabled = isFunctionCallDisabled;
			}
		}

		public IObjectAccessor GetMemberAccessor(object target)
		{
			if (target == null)
			{
				return NullAccessor.Default;
			}
			Type type = target.GetType();
			if (!_memberAccessors.TryGetValue(type, out var value))
			{
				value = GetMemberAccessorImpl(target) ?? NullAccessor.Default;
				_memberAccessors.Add(type, value);
			}
			return value;
		}

		public virtual void Reset()
		{
			while (OutputCount > 1)
			{
				PopOutput();
			}
			((StringBuilderOutput)Output).Builder.Length = 0;
			while (GlobalCount > 1)
			{
				PopGlobal();
			}
			while (CultureCount > 0)
			{
				PopCulture();
			}
			while (SourceFileCount > 0)
			{
				PopSourceFile();
			}
		}

		protected virtual IObjectAccessor GetMemberAccessorImpl(object target)
		{
			Type type = target.GetType();
			if (target is IScriptObject)
			{
				return ScriptObjectAccessor.Default;
			}
			if (target is string)
			{
				return StringAccessor.Default;
			}
			if (type.IsPrimitiveOrDecimal())
			{
				return PrimitiveAccessor.Default;
			}
			if (!DictionaryAccessor.TryGet(target, out var accessor))
			{
				if (type.IsArray)
				{
					return ArrayAccessor.Default;
				}
				if (target is IList)
				{
					return ListAccessor.Default;
				}
				return new TypedObjectAccessor(type, _keyComparer, MemberFilter, MemberRenamer);
			}
			return accessor;
		}

		public static ScriptObject GetDefaultBuiltinObject()
		{
			return new BuiltinFunctions();
		}

		public void EnterRecursive(ScriptNode node)
		{
			try
			{
				RuntimeHelpers.EnsureSufficientExecutionStack();
			}
			catch (InsufficientExecutionStackException)
			{
				throw new ScriptRuntimeException(node.Span, "Exceeding recursive depth limit, near to stack overflow");
			}
			_callDepth++;
			if (RecursiveLimit != 0 && _callDepth > RecursiveLimit)
			{
				throw new ScriptRuntimeException(node.Span, $"Exceeding number of recursive depth limit `{RecursiveLimit}` for node: `{node}`");
			}
		}

		public void ExitRecursive(ScriptNode node)
		{
			_callDepth--;
			if (_callDepth < 0)
			{
				throw new ScriptRuntimeException(node.Span, $"unexpected ExitRecursive not matching EnterRecursive for `{node}`");
			}
		}

		internal void EnterFunction(ScriptNode caller)
		{
			EnterRecursive(caller);
		}

		internal void ExitFunction(ScriptNode caller)
		{
			ExitRecursive(caller);
		}

		internal void EnterLoop(ScriptLoopStatementBase loop)
		{
			if (loop == null)
			{
				throw new ArgumentNullException("loop");
			}
			_loops.Push(loop);
			PushVariableScope(VariableScope.Loop);
			OnEnterLoop(loop);
		}

		protected virtual void OnEnterLoop(ScriptLoopStatementBase loop)
		{
		}

		internal void ExitLoop(ScriptLoopStatementBase loop)
		{
			try
			{
				OnExitLoop(loop);
			}
			finally
			{
				PopVariableScope(VariableScope.Loop);
				_loops.Pop();
				if (!IsInLoop)
				{
					_loopStep = 0;
				}
			}
		}

		protected virtual void OnExitLoop(ScriptLoopStatementBase loop)
		{
		}

		internal bool StepLoop(ScriptLoopStatementBase loop, LoopType loopType = LoopType.Default)
		{
			_loopStep++;
			int num = ((loopType != LoopType.Queryable) ? LoopLimit : LoopLimitQueryable.GetValueOrDefault(LoopLimit));
			if (num != 0 && _loopStep > num)
			{
				throw new ScriptRuntimeException(_loops.Peek().Span, $"Exceeding number of iteration limit `{num}` for loop statement.");
			}
			return OnStepLoop(loop);
		}

		protected virtual bool OnStepLoop(ScriptLoopStatementBase loop)
		{
			return true;
		}

		internal void PushCase(object caseValue)
		{
			_caseValues.Push(caseValue);
		}

		internal object PeekCase()
		{
			return _caseValues.Peek();
		}

		internal object PopCase()
		{
			if (_caseValues.Count == 0)
			{
				throw new InvalidOperationException("Cannot PopCase more than PushCase");
			}
			return _caseValues.Pop();
		}

		private object GetOrSetValue(ScriptExpression targetExpression, object valueToSet, bool setter)
		{
			object obj = null;
			try
			{
				if (targetExpression is IScriptVariablePath scriptVariablePath)
				{
					if (setter)
					{
						scriptVariablePath.SetValue(this, valueToSet);
					}
					else
					{
						obj = scriptVariablePath.GetValue(this);
					}
				}
				else
				{
					if (setter)
					{
						throw new ScriptRuntimeException(targetExpression.Span, "Unsupported target expression for assignment.");
					}
					obj = Evaluate(targetExpression);
				}
			}
			catch (Exception ex) when (_getOrSetValueLevel == 1 && !(ex is ScriptRuntimeException))
			{
				throw new ScriptRuntimeException(targetExpression.Span, "Unexpected exception while accessing target expression: " + ex.Message, ex);
			}
			if (((_isFunctionCallDisabled && _getOrSetValueLevel > 1) || !_isFunctionCallDisabled) && ScriptFunctionCall.IsFunction(obj))
			{
				obj = ScriptFunctionCall.Call(this, targetExpression, obj, _getOrSetValueLevel == 1, null);
			}
			return obj;
		}

		public IListAccessor GetListAccessor(object target)
		{
			Type type = target.GetType();
			if (!_listAccessors.TryGetValue(type, out var value))
			{
				value = GetListAccessorImpl(target, type);
				_listAccessors.Add(type, value);
			}
			return value;
		}

		protected virtual IListAccessor GetListAccessorImpl(object target, Type type)
		{
			if (type.IsArray)
			{
				return ArrayAccessor.Default;
			}
			if (type == typeof(string))
			{
				return StringAccessor.Default;
			}
			if (type.IsPrimitiveOrDecimal())
			{
				return PrimitiveAccessor.Default;
			}
			if (target is IList)
			{
				return ListAccessor.Default;
			}
			return null;
		}

		public void ResetPreviousNewLine()
		{
			_previousTextWasNewLine = false;
		}

		public virtual string GetTemplatePathFromName(string templateName, ScriptNode callerContext)
		{
			if (string.IsNullOrEmpty(templateName))
			{
				throw new ScriptRuntimeException(callerContext.Span, "Include template name cannot be null or empty");
			}
			return ConvertTemplateNameToPath(templateName, callerContext);
		}

		protected string ConvertTemplateNameToPath(string templateName, ScriptNode callerContext)
		{
			if (TemplateLoader == null)
			{
				throw new ScriptRuntimeException(callerContext.Span, "Unable to include <" + templateName + ">. No TemplateLoader registered in TemplateContext.TemplateLoader");
			}
			string path;
			try
			{
				path = TemplateLoader.GetPath(this, callerContext.Span, templateName);
			}
			catch (Exception ex) when (!(ex is ScriptRuntimeException))
			{
				throw new ScriptRuntimeException(callerContext.Span, "Unexpected exception while getting the path for the include name `" + templateName + "`", ex);
			}
			if (path == null)
			{
				throw new ScriptRuntimeException(callerContext.Span, "Include template path is null for `" + templateName);
			}
			return path;
		}

		public Template GetOrCreateTemplate(string templatePath, ScriptNode callerContext)
		{
			if (!CachedTemplates.TryGetValue(templatePath, out var value))
			{
				value = CreateTemplate(templatePath, callerContext);
				CachedTemplates[templatePath] = value;
			}
			return value;
		}

		protected virtual Template CreateTemplate(string templatePath, ScriptNode callerContext)
		{
			string text;
			try
			{
				text = TemplateLoader.Load(this, callerContext.Span, templatePath);
			}
			catch (Exception ex) when (!(ex is ScriptRuntimeException))
			{
				throw new ScriptRuntimeException(callerContext.Span, "Unexpected exception while creating template from path `" + templatePath + "`", ex);
			}
			if (text == null)
			{
				throw new ScriptRuntimeException(callerContext.Span, "The result of including `" + templatePath + "` cannot be null");
			}
			Template template = Template.Parse(text, templatePath, TemplateLoaderParserOptions, TemplateLoaderLexerOptions);
			if (template.HasErrors)
			{
				throw new ScriptParserRuntimeException(callerContext.Span, "Error while parsing template `" + templatePath + "`", template.Messages);
			}
			CachedTemplates.Add(templatePath, template);
			return template;
		}

		public string RenderTemplate(Template template, ScriptArray arguments, ScriptNode callerContext)
		{
			string result = null;
			EnterRecursive(callerContext);
			string currentIndent = CurrentIndent;
			CurrentIndent = null;
			PushOutput();
			PushLocal();
			try
			{
				SetValue(ScriptVariable.Arguments, arguments, asReadOnly: true, force: true);
				IEnumerable<ScriptNamedArgument> enumerable = (callerContext as ScriptFunctionCall)?.Arguments.OfType<ScriptNamedArgument>();
				if (enumerable != null)
				{
					foreach (ScriptNamedArgument item in enumerable)
					{
						string name = item.Name.Name;
						object value = item.Value.Evaluate(this);
						ScriptVariable variable = ScriptVariable.Create(name, ScriptVariableScope.Local);
						SetValue(variable, value, asReadOnly: false, force: true);
					}
				}
				if (currentIndent != null)
				{
					ResetPreviousNewLine();
				}
				result = template.Render(this);
				if (currentIndent != null)
				{
					ResetPreviousNewLine();
				}
			}
			finally
			{
				PopLocal();
				PopOutput();
				CurrentIndent = currentIndent;
				ExitRecursive(callerContext);
			}
			return result;
		}

		public object GetFormat(Type formatType)
		{
			return CurrentCulture.GetFormat(formatType);
		}

		public virtual object IsEmpty(SourceSpan span, object against)
		{
			if (against == null)
			{
				return null;
			}
			if (against is IList)
			{
				return ((IList)against).Count == 0;
			}
			if (against is IEnumerable)
			{
				return !((IEnumerable)against).GetEnumerator().MoveNext();
			}
			if (against.GetType().IsPrimitiveOrDecimal())
			{
				return false;
			}
			return GetMemberAccessor(against).GetMemberCount(this, span, against) > 0;
		}

		public virtual IList ToList(SourceSpan span, object value)
		{
			if (value == null)
			{
				return null;
			}
			if (value is IList)
			{
				return (IList)value;
			}
			return new ScriptArray((value as IEnumerable) ?? throw new ScriptRuntimeException(span, "Unexpected list value. Expecting an array, list or iterator. Unable to convert to a list."));
		}

		public virtual string ObjectToString(object value, bool nested = false)
		{
			if (_objectToStringLevel == 0)
			{
				_currentToStringLength = 0;
			}
			try
			{
				_objectToStringLevel++;
				if (ObjectRecursionLimit != 0 && _objectToStringLevel > ObjectRecursionLimit)
				{
					throw new InvalidOperationException("Structure is too deeply nested or contains reference loops.");
				}
				string text = ObjectToStringImpl(value, nested);
				if (LimitToString > 0 && _objectToStringLevel == 1 && text != null && text.Length >= LimitToString)
				{
					return text + "...";
				}
				return text;
			}
			finally
			{
				_objectToStringLevel--;
			}
		}

		private string ObjectToStringImpl(object value, bool nested)
		{
			if (LimitToString > 0 && _currentToStringLength >= LimitToString)
			{
				return string.Empty;
			}
			if (value is string text)
			{
				if (LimitToString > 0 && _currentToStringLength + text.Length >= LimitToString)
				{
					int num = LimitToString - _currentToStringLength;
					if (num <= 0)
					{
						return string.Empty;
					}
					string text2 = text.Substring(0, num);
					if (!nested)
					{
						return text2;
					}
					return "\"" + StringFunctions.Escape(text2);
				}
				if (!nested)
				{
					return text;
				}
				return "\"" + StringFunctions.Escape(text) + "\"";
			}
			if (value == null || value == EmptyScriptObject.Default)
			{
				if (!nested)
				{
					return null;
				}
				return "null";
			}
			if (value is bool)
			{
				if (!(bool)value)
				{
					return "false";
				}
				return "true";
			}
			if (value is DateTime value2)
			{
				bool strictVariables = StrictVariables;
				try
				{
					StrictVariables = false;
					if (GetValue(DateTimeFunctions.DateVariable) is DateTimeFunctions dateTimeFunctions)
					{
						return dateTimeFunctions.ToString(value2, dateTimeFunctions.Format, CurrentCulture);
					}
				}
				finally
				{
					StrictVariables = strictVariables;
				}
			}
			if (value is IFormattable formattable)
			{
				return formattable.ToString(null, this);
			}
			if (value is IConvertible convertible)
			{
				return convertible.ToString(this);
			}
			if (value is IEnumerable enumerable)
			{
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.Append("[");
				_currentToStringLength++;
				bool flag = true;
				foreach (object item in enumerable)
				{
					if (!flag)
					{
						stringBuilder.Append(", ");
						_currentToStringLength += 2;
					}
					string text3 = ObjectToString(item, nested: true);
					stringBuilder.Append(text3);
					if (text3 != null)
					{
						_currentToStringLength += text3.Length;
					}
					if (LimitToString > 0 && _currentToStringLength >= LimitToString)
					{
						return stringBuilder.ToString();
					}
					flag = false;
				}
				stringBuilder.Append("]");
				_currentToStringLength++;
				return stringBuilder.ToString();
			}
			string fullName = value.GetType().FullName;
			if (fullName != null && fullName.StartsWith("System.Collections.Generic.KeyValuePair"))
			{
				ScriptObject scriptObject = new ScriptObject(2);
				scriptObject.Import(value, null, MemberRenamer);
				return ObjectToString(scriptObject, nested: true);
			}
			if (value is IScriptCustomFunction && !(value is ScriptFunction))
			{
				return "<function>";
			}
			return value.ToString();
		}

		public virtual bool ToBool(SourceSpan span, object value)
		{
			if (value == null || value == EmptyScriptObject.Default)
			{
				return false;
			}
			if (value is bool)
			{
				return (bool)value;
			}
			if (UseScientific)
			{
				Type type = value.GetType();
				if (type.IsPrimitive || type == typeof(decimal))
				{
					return Convert.ToBoolean(value);
				}
				if (value is BigInteger bigInteger)
				{
					return bigInteger != BigInteger.Zero;
				}
			}
			return true;
		}

		public virtual int ToInt(SourceSpan span, object value)
		{
			if (value == null)
			{
				return 0;
			}
			if (value is int)
			{
				return (int)value;
			}
			checked
			{
				try
				{
					if (value is BigInteger bigInteger)
					{
						return (int)bigInteger;
					}
					if (value is IScriptConvertibleTo scriptConvertibleTo && scriptConvertibleTo.TryConvertTo(this, span, typeof(int), out object value2))
					{
						return (int)value2;
					}
					if (value is uint num)
					{
						return (int)num;
					}
					if (value is ulong num2)
					{
						return (int)num2;
					}
					return Convert.ToInt32(value, CurrentCulture);
				}
				catch (Exception innerException)
				{
					throw new ScriptRuntimeException(span, "Unable to convert type `" + GetTypeName(value) + "` to int", innerException);
				}
			}
		}

		public virtual string GetTypeName(object value)
		{
			if (value == null)
			{
				return "null";
			}
			if (value is Type type)
			{
				return type.ScriptPrettyName();
			}
			if (value is IScriptCustomTypeInfo scriptCustomTypeInfo)
			{
				return scriptCustomTypeInfo.TypeName;
			}
			return value.GetType().ScriptPrettyName();
		}

		public T ToObject<T>(SourceSpan span, object value)
		{
			return (T)ToObject(span, value, typeof(T));
		}

		public virtual object ToObject(SourceSpan span, object value, Type destinationType)
		{
			if (destinationType == null)
			{
				throw new ArgumentNullException("destinationType");
			}
			(bool IsNullable, Type DestinationType) tuple = GetNullableInfo(destinationType);
			bool item = tuple.IsNullable;
			destinationType = tuple.DestinationType;
			Type type = value?.GetType();
			if (destinationType == type)
			{
				return value;
			}
			if (item && value == null)
			{
				return null;
			}
			if (destinationType == typeof(string))
			{
				return ObjectToString(value);
			}
			if (destinationType == typeof(int))
			{
				return ToInt(span, value);
			}
			if (destinationType == typeof(bool))
			{
				return ToBool(span, value);
			}
			if (value == null)
			{
				if (destinationType == typeof(double))
				{
					return 0.0;
				}
				if (destinationType == typeof(float))
				{
					return 0f;
				}
				if (destinationType == typeof(long))
				{
					return 0L;
				}
				if (destinationType == typeof(decimal))
				{
					return 0m;
				}
				if (destinationType == typeof(BigInteger))
				{
					return new BigInteger(0);
				}
				return null;
			}
			if (destinationType.IsEnum)
			{
				try
				{
					if (value is string value2)
					{
						return Enum.Parse(destinationType, value2);
					}
					return Enum.ToObject(destinationType, value);
				}
				catch (Exception innerException)
				{
					throw new ScriptRuntimeException(span, "Unable to convert type `" + GetTypeName(value) + "` to `" + GetTypeName(destinationType) + "`", innerException);
				}
			}
			if (value is IScriptConvertibleTo scriptConvertibleTo && scriptConvertibleTo.TryConvertTo(this, span, destinationType, out object value3))
			{
				return value3;
			}
			if (typeof(IScriptConvertibleFrom).IsAssignableFrom(destinationType))
			{
				IScriptConvertibleFrom scriptConvertibleFrom = (IScriptConvertibleFrom)Activator.CreateInstance(destinationType);
				if (scriptConvertibleFrom.TryConvertFrom(this, span, value))
				{
					return scriptConvertibleFrom;
				}
			}
			Type c = type;
			if (type.IsPrimitiveOrDecimal() && destinationType.IsPrimitiveOrDecimal())
			{
				try
				{
					if (destinationType == typeof(BigInteger))
					{
						if (type == typeof(char))
						{
							return new BigInteger((char)value);
						}
						if (type == typeof(bool))
						{
							return new BigInteger(((bool)value) ? 1 : 0);
						}
						if (type == typeof(float))
						{
							return new BigInteger((float)value);
						}
						if (type == typeof(double))
						{
							return new BigInteger((double)value);
						}
						if (type == typeof(int))
						{
							return new BigInteger((int)value);
						}
						if (type == typeof(uint))
						{
							return new BigInteger((uint)value);
						}
						if (type == typeof(long))
						{
							return new BigInteger((long)value);
						}
						if (type == typeof(ulong))
						{
							return new BigInteger((ulong)value);
						}
					}
					else if (type == typeof(BigInteger))
					{
						if (destinationType == typeof(char))
						{
							return (char)(int)(BigInteger)value;
						}
						if (destinationType == typeof(float))
						{
							return (float)(BigInteger)value;
						}
						if (destinationType == typeof(double))
						{
							return (double)(BigInteger)value;
						}
						if (destinationType == typeof(uint))
						{
							return (uint)(BigInteger)value;
						}
						if (destinationType == typeof(long))
						{
							return (long)(BigInteger)value;
						}
						if (destinationType == typeof(ulong))
						{
							return (ulong)(BigInteger)value;
						}
					}
					return Convert.ChangeType(value, destinationType, CurrentCulture);
				}
				catch (Exception innerException2)
				{
					throw new ScriptRuntimeException(span, "Unable to convert type `" + GetTypeName(value) + "` to `" + GetTypeName(destinationType) + "`", innerException2);
				}
			}
			if (destinationType == typeof(IList))
			{
				return ToList(span, value);
			}
			if (destinationType.IsAssignableFrom(c))
			{
				return value;
			}
			throw new ScriptRuntimeException(span, "Unable to convert type `" + GetTypeName(value) + "` to `" + GetTypeName(destinationType) + "`");
			static (bool IsNullable, Type DestinationType) GetNullableInfo(Type destinationType)
			{
				destinationType = destinationType ?? throw new ArgumentNullException("destinationType");
				Type underlyingType = Nullable.GetUnderlyingType(destinationType);
				if ((object)underlyingType != null)
				{
					return (true, underlyingType);
				}
				return (false, destinationType);
			}
		}

		public void PushGlobal(IScriptObject scriptObject)
		{
			PushGlobalOnly(scriptObject);
			PushLocal();
		}

		internal void PushGlobalOnly(IScriptObject scriptObject)
		{
			if (scriptObject == null)
			{
				throw new ArgumentNullException("scriptObject");
			}
			_globalContexts.Push(GetOrCreateGlobalContext(scriptObject));
		}

		private VariableContext GetOrCreateGlobalContext(IScriptObject globalObject)
		{
			if (_availableGlobalContexts.Count == 0)
			{
				return new VariableContext(globalObject);
			}
			VariableContext variableContext = _availableGlobalContexts.Pop();
			variableContext.LocalObject = globalObject;
			return variableContext;
		}

		internal IScriptObject PopGlobalOnly()
		{
			if (_globalContexts.Count == 1)
			{
				throw new InvalidOperationException("Unexpected PopGlobal() not matching a PushGlobal");
			}
			VariableContext variableContext = _globalContexts.Pop();
			IScriptObject localObject = variableContext.LocalObject;
			variableContext.LocalObject = null;
			_availableGlobalContexts.Push(variableContext);
			return localObject;
		}

		public IScriptObject PopGlobal()
		{
			IScriptObject result = PopGlobalOnly();
			PopLocal();
			return result;
		}

		public void PushLocal()
		{
			PushVariableScope(VariableScope.Local);
		}

		public void PopLocal()
		{
			PopVariableScope(VariableScope.Local);
		}

		public void SetValue(ScriptVariable variable, object value, bool asReadOnly = false)
		{
			if (variable == null)
			{
				throw new ArgumentNullException("variable");
			}
			if (!GetStoreForWrite(variable).TrySetValue(this, variable.Span, variable.Name, value, asReadOnly))
			{
				throw new ScriptRuntimeException(variable.Span, $"Cannot set value on the readonly variable `{variable}`");
			}
		}

		public void SetValue(ScriptVariable variable, object value, bool asReadOnly, bool force)
		{
			if (variable == null)
			{
				throw new ArgumentNullException("variable");
			}
			IScriptObject storeForWrite = GetStoreForWrite(variable);
			if (force)
			{
				storeForWrite.Remove(variable.Name);
				storeForWrite.TrySetValue(this, variable.Span, variable.Name, value, asReadOnly);
			}
			else if (!storeForWrite.TrySetValue(this, variable.Span, variable.Name, value, asReadOnly))
			{
				throw new ScriptRuntimeException(variable.Span, $"Cannot set value on the readonly variable `{variable}`");
			}
		}

		public void DeleteValue(ScriptVariable variable)
		{
			if (variable == null)
			{
				throw new ArgumentNullException("variable");
			}
			GetStoreForWrite(variable).Remove(variable.Name);
		}

		public void SetReadOnly(ScriptVariable variable, bool isReadOnly = true)
		{
			if (variable == null)
			{
				throw new ArgumentNullException("variable");
			}
			GetStoreForWrite(variable).SetReadOnly(variable.Name, isReadOnly);
		}

		public virtual void SetLoopVariable(ScriptVariable variable, object value)
		{
			if (variable == null)
			{
				throw new ArgumentNullException("variable");
			}
			VariableContext obj = ((variable.Scope == ScriptVariableScope.Global) ? _globalContexts.Peek() : _currentLocalContext);
			if (obj.Loops.Count == 0)
			{
				throw new InvalidOperationException("Cannot set a loop global variable without a loop variable store.");
			}
			if (!obj.Loops.Peek().TrySetValue(this, variable.Span, variable.Name, value, readOnly: false))
			{
				throw new ScriptRuntimeException(variable.Span, $"Cannot set value on the variable `{variable}`");
			}
		}

		private void PushLocalContext(ScriptObject locals = null)
		{
			VariableContext variableContext = ((_availableLocalContexts.Count > 0) ? _availableLocalContexts.Pop() : new VariableContext(null));
			variableContext.LocalObject = locals;
			_localContexts.Push(variableContext);
			_currentLocalContext = variableContext;
		}

		private ScriptObject PopLocalContext()
		{
			VariableContext variableContext = _localContexts.Pop();
			ScriptObject result = (ScriptObject)variableContext.LocalObject;
			variableContext.LocalObject = null;
			_availableLocalContexts.Push(variableContext);
			_currentLocalContext = _localContexts.Peek();
			return result;
		}

		public object GetValue(ScriptVariable variable)
		{
			if (variable == null)
			{
				throw new ArgumentNullException("variable");
			}
			IEnumerable<IScriptObject> storeForRead = GetStoreForRead(variable);
			object value = null;
			foreach (IScriptObject item in storeForRead)
			{
				if (item.TryGetValue(this, variable.Span, variable.Name, out value))
				{
					return value;
				}
			}
			bool found = false;
			if (TryGetVariable != null && TryGetVariable(this, variable.Span, variable, out value))
			{
				found = true;
			}
			CheckVariableFound(variable, found);
			return value;
		}

		public object GetValue(ScriptVariableGlobal variable)
		{
			if (variable == null)
			{
				throw new ArgumentNullException("variable");
			}
			object value = null;
			int count = _globalContexts.Count;
			VariableContext[] items = _globalContexts.Items;
			bool isInLoop = IsInLoop;
			for (int num = count - 1; num >= 0; num--)
			{
				VariableContext variableContext = items[num];
				if (isInLoop)
				{
					int count2 = variableContext.Loops.Count;
					if (count2 > 0)
					{
						ScriptObject[] items2 = variableContext.Loops.Items;
						for (int num2 = count2 - 1; num2 >= 0; num2--)
						{
							if (items2[num2].TryGetValue(this, variable.Span, variable.Name, out value))
							{
								return value;
							}
						}
					}
				}
				if (items[num].LocalObject.TryGetValue(this, variable.Span, variable.Name, out value))
				{
					return value;
				}
			}
			bool found = false;
			if (TryGetVariable != null && TryGetVariable(this, variable.Span, variable, out value))
			{
				found = true;
			}
			CheckVariableFound(variable, found);
			return value;
		}

		public ValueTask<object> GetValueAsync(ScriptVariableGlobal variable)
		{
			return new ValueTask<object>(GetValue(variable));
		}

		public ValueTask<object> GetValueAsync(ScriptVariable variable)
		{
			return new ValueTask<object>(GetValue(variable));
		}

		public ValueTask SetValueAsync(ScriptVariable variable, object value, bool asReadOnly = false)
		{
			SetValue(variable, value, asReadOnly);
			return default(ValueTask);
		}

		private IScriptObject GetStoreForWrite(ScriptVariable variable)
		{
			ScriptVariableScope scope = variable.Scope;
			IScriptObject scriptObject = null;
			switch (scope)
			{
			case ScriptVariableScope.Global:
			{
				string name = variable.Name;
				int num = _globalContexts.Count - 1;
				scriptObject = _globalContexts.Items[num].LocalObject;
				if (!scriptObject.CanWrite(name))
				{
					string arg = ((scriptObject == BuiltinObject) ? "builtin " : string.Empty);
					throw new ScriptRuntimeException(variable.Span, $"Cannot set the {arg}readonly variable `{variable}`");
				}
				break;
			}
			case ScriptVariableScope.Local:
				if (_currentLocalContext.LocalObject != null)
				{
					scriptObject = _currentLocalContext.LocalObject;
					break;
				}
				if (_globalContexts.Count > 0)
				{
					scriptObject = _globalContexts.Peek().LocalObject;
					break;
				}
				throw new ScriptRuntimeException(variable.Span, $"Invalid usage of the local variable `{variable}` in the current context");
			}
			return scriptObject;
		}

		[IteratorStateMachine(typeof(<GetStoreForRead>d__306))]
		private IEnumerable<IScriptObject> GetStoreForRead(ScriptVariable variable)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <GetStoreForRead>d__306(-2)
			{
				<>4__this = this,
				<>3__variable = variable
			};
		}

		private void CheckVariableFound(ScriptVariable variable, bool found)
		{
			if (StrictVariables && !found && variable != ScriptVariable.Arguments)
			{
				throw new ScriptRuntimeException(variable.Span, $"The variable or function `{variable}` was not found");
			}
		}

		private void PushVariableScope(VariableScope scope)
		{
			if (scope == VariableScope.Local)
			{
				ScriptObject locals = ((_availableStores.Count > 0) ? _availableStores.Pop() : new ScriptObject());
				PushLocalContext(locals);
				return;
			}
			ScriptObject item = ((_availableStores.Count > 0) ? _availableStores.Pop() : new ScriptObject());
			ScriptObject item2 = ((_availableStores.Count > 0) ? _availableStores.Pop() : new ScriptObject());
			_globalContexts.Peek().Loops.Push(item2);
			_currentLocalContext.Loops.Push(item);
		}

		private void PopVariableScope(VariableScope scope)
		{
			if (scope == VariableScope.Local)
			{
				ScriptObject scriptObject = PopLocalContext();
				scriptObject.Clear();
				_availableStores.Push(scriptObject);
				return;
			}
			if (_currentLocalContext.Loops.Count == 0)
			{
				throw new InvalidOperationException("Invalid number of matching push/pop VariableScope.");
			}
			ScriptObject scriptObject2 = _globalContexts.Peek().Loops.Pop();
			scriptObject2.Clear();
			_availableStores.Push(scriptObject2);
			ScriptObject scriptObject3 = _currentLocalContext.Loops.Pop();
			scriptObject3.Clear();
			_availableStores.Push(scriptObject3);
		}
	}
	public class ScriptPrinter
	{
		private readonly IScriptOutput _output;

		private readonly bool _isScriptOnly;

		private bool _isInCode;

		private bool _expectSpace;

		private bool _expectEndOfStatement;

		private bool _previousHasSpace;

		private bool _hasEndOfStatement;

		private bool _hasComma;

		private FastStack<bool> _isWhileLoop;

		public readonly ScriptPrinterOptions Options;

		public bool PreviousHasSpace => _previousHasSpace;

		public bool IsInWhileLoop
		{
			get
			{
				if (_isWhileLoop.Count > 0)
				{
					return _isWhileLoop.Peek();
				}
				return false;
			}
		}

		public ScriptPrinter(IScriptOutput output, ScriptPrinterOptions options = default(ScriptPrinterOptions))
		{
			_isWhileLoop = new FastStack<bool>(4);
			Options = options;
			if (options.Mode != 0 && options.Mode != ScriptMode.ScriptOnly)
			{
				throw new ArgumentException($"The rendering mode `{options.Mode}` is not supported. Only `ScriptMode.Default` or `ScriptMode.ScriptOnly` are currently supported");
			}
			_isScriptOnly = options.Mode == ScriptMode.ScriptOnly;
			_isInCode = _isScriptOnly || options.Mode == ScriptMode.FrontMatterOnly || options.Mode == ScriptMode.FrontMatterAndContent;
			_output = output;
			_hasEndOfStatement = true;
		}

		public ScriptPrinter Write(ScriptNode node)
		{
			if (node != null)
			{
				bool flag = false;
				if (node is ScriptLoopStatementBase)
				{
					_isWhileLoop.Push(node is ScriptWhileStatement);
					flag = true;
				}
				try
				{
					WriteBegin(node);
					if (node is IScriptTerminal)
					{
						_hasComma = false;
					}
					node.PrintTo(this);
					WriteEnd(node);
				}
				finally
				{
					if (flag)
					{
						_isWhileLoop.Pop();
					}
				}
			}
			return this;
		}

		public ScriptPrinter Write(string text)
		{
			_previousHasSpace = text.Length > 0 && char.IsWhiteSpace(text[text.Length - 1]);
			_output.Write(text);
			return this;
		}

		public ScriptPrinter Write(ScriptStringSlice slice)
		{
			_previousHasSpace = slice.Length > 0 && char.IsWhiteSpace(slice[slice.Length - 1]);
			_output.Write(slice);
			return this;
		}

		public ScriptPrinter ExpectEos()
		{
			if (!_hasEndOfStatement)
			{
				_expectEndOfStatement = true;
			}
			return this;
		}

		public ScriptPrinter ExpectSpace()
		{
			_expectSpace = true;
			return this;
		}

		public ScriptPrinter WriteListWithCommas<T>(IList<T> list) where T : ScriptNode
		{
			if (list == null)
			{
				return this;
			}
			for (int i = 0; i < list.Count; i++)
			{
				T node = list[i];
				if (i > 0 && !_hasComma)
				{
					Write(",");
					_hasComma = true;
				}
				Write(node);
			}
			return this;
		}

		public ScriptPrinter WriteEnterCode(int escape = 0)
		{
			Write("{");
			for (int i = 0; i < escape; i++)
			{
				Write("%");
			}
			Write("{");
			_expectEndOfStatement = false;
			_expectSpace = false;
			_hasEndOfStatement = true;
			_isInCode = true;
			return this;
		}

		public ScriptPrinter WriteExitCode(int escape = 0)
		{
			Write("}");
			for (int i = 0; i < escape; i++)
			{
				Write("%");
			}
			Write("}");
			_expectEndOfStatement = false;
			_expectSpace = false;
			_hasEndOfStatement = false;
			_isInCode = false;
			return this;
		}

		private void WriteBegin(ScriptNode node)
		{
			WriteTrivias(node, before: true);
			HandleEos(node);
			if (_hasEndOfStatement)
			{
				_hasEndOfStatement = false;
				_expectEndOfStatement = false;
			}
			if (node.CanHaveLeadingTrivia())
			{
				if (_expectSpace && !_previousHasSpace)
				{
					Write(" ");
				}
				_expectSpace = false;
			}
		}

		private void WriteEnd(ScriptNode node)
		{
			WriteTrivias(node, before: false);
			if (node is ScriptPage && _isInCode && !_isScriptOnly)
			{
				WriteExitCode();
			}
		}

		private static bool IsFrontMarker(ScriptNode node)
		{
			if (node is ScriptToken scriptToken)
			{
				return scriptToken.TokenType == TokenType.FrontMatterMarker;
			}
			return false;
		}

		private void HandleEos(ScriptNode node)
		{
			bool flag = IsFrontMarker(node);
			if ((node is ScriptStatement || flag) && !IsBlockOrPage(node) && _isInCode && _expectEndOfStatement)
			{
				if (!_hasEndOfStatement && !(node is ScriptEscapeStatement))
				{
					Write(flag ? "\n" : "; ");
				}
				_expectEndOfStatement = false;
				_hasEndOfStatement = false;
				_hasComma = false;
			}
		}

		private static bool IsBlockOrPage(ScriptNode node)
		{
			if (!(node is ScriptBlockStatement))
			{
				return node is ScriptPage;
			}
			return true;
		}

		private void WriteTrivias(ScriptNode node, bool before)
		{
			if (!(node is IScriptTerminal scriptTerminal))
			{
				return;
			}
			ScriptTrivias trivias = scriptTerminal.Trivias;
			if (trivias == null)
			{
				return;
			}
			foreach (ScriptTrivia item in before ? trivias.Before : trivias.After)
			{
				item.Write(this);
				if (item.Type == ScriptTriviaType.NewLine || item.Type == ScriptTriviaType.SemiColon)
				{
					_hasEndOfStatement = true;
					if (item.Type == ScriptTriviaType.SemiColon)
					{
						_hasComma = false;
					}
					if (_expectSpace)
					{
						_expectSpace = false;
					}
				}
				if (item.Type == ScriptTriviaType.Comma)
				{
					_hasComma = true;
				}
			}
		}
	}
	public struct ScriptPrinterOptions
	{
		public ScriptMode Mode;
	}
	public class LiquidTemplateContext : TemplateContext
	{
		public LiquidTemplateContext()
			: base(new LiquidBuiltinsFunctions())
		{
			base.Language = ScriptLang.Liquid;
			base.EnableBreakAndContinueAsReturnOutsideLoop = true;
			base.EnableRelaxedTargetAccess = true;
			base.TemplateLoaderLexerOptions = new LexerOptions
			{
				Lang = ScriptLang.Liquid
			};
			base.TemplateLoaderParserOptions = new ParserOptions
			{
				LiquidFunctionsToScriban = true
			};
			base.IsLiquid = true;
		}

		public override string GetTemplatePathFromName(string templateName, ScriptNode callerContext)
		{
			if (string.IsNullOrEmpty(templateName))
			{
				return null;
			}
			return ConvertTemplateNameToPath(templateName, callerContext);
		}
	}
}
namespace Scriban.Syntax
{
	internal class ScientificFunctionCallRewriter
	{
		[DebuggerDisplay("Count = {Count}, Current = {Index} : {Current}")]
		private class BinaryExpressionIterator : List<BinaryExpressionOrOperator>
		{
			public int Index { get; set; }

			public BinaryExpressionOrOperator Current
			{
				get
				{
					if (Index >= base.Count)
					{
						return default(BinaryExpressionOrOperator);
					}
					return base[Index];
				}
			}

			public bool HasCurrent => Index < base.Count;

			public bool HasNext => Index + 1 < base.Count;

			public bool MoveNext()
			{
				Index++;
				return HasCurrent;
			}

			public BinaryExpressionOrOperator PeekNext()
			{
				return base[Index + 1];
			}
		}

		[DebuggerDisplay("{ToDebuggerDisplay(),nq}")]
		private readonly struct BinaryExpressionOrOperator
		{
			public readonly ScriptExpression Expression;

			public readonly ScriptBinaryOperator Operator;

			public readonly ScriptToken OperatorToken;

			public readonly FunctionCallKind CallKind;

			public BinaryExpressionOrOperator(ScriptExpression expression, FunctionCallKind kind)
			{
				Expression = expression;
				Operator = ScriptBinaryOperator.None;
				OperatorToken = null;
				CallKind = kind;
			}

			public BinaryExpressionOrOperator(ScriptBinaryOperator @operator, ScriptToken operatorToken)
			{
				Expression = null;
				Operator = @operator;
				OperatorToken = operatorToken;
				CallKind = FunctionCallKind.None;
			}

			private string ToDebuggerDisplay()
			{
				object obj;
				if (Expression == null)
				{
					obj = OperatorToken?.ToString();
					if (obj == null)
					{
						return $"`{Operator.ToText()}` - CallKind = {CallKind}";
					}
				}
				else
				{
					obj = Expression.ToString();
				}
				return (string)obj;
			}
		}

		private enum FunctionCallKind
		{
			None,
			Regular,
			Expression
		}

		private const int ImplicitFunctionCallPrecedence = 101;

		private static async ValueTask FlattenBinaryExpressionsAsync(TemplateContext context, ScriptExpression expression, List<BinaryExpressionOrOperator> expressions)
		{
			while (expression is ScriptBinaryExpression binaryExpression)
			{
				ScriptExpression expression2 = (ScriptExpression)binaryExpression.Left.Clone();
				ScriptExpression right = (ScriptExpression)binaryExpression.Right.Clone();
				ScriptToken token = (ScriptToken)(binaryExpression.OperatorToken?.Clone());
				await FlattenBinaryExpressionsAsync(context, expression2, expressions).ConfigureAwait(continueOnCapturedContext: false);
				expressions.Add(new BinaryExpressionOrOperator(binaryExpression.Operator, token));
				expression = right;
			}
			ScriptExpression expression3 = expression;
			expressions.Add(new BinaryExpressionOrOperator(expression3, await GetFunctionCallKindAsync(context, expression).ConfigureAwait(continueOnCapturedContext: false)));
		}

		private static async ValueTask<FunctionCallKind> GetFunctionCallKindAsync(TemplateContext context, ScriptExpression expression)
		{
			bool restoreStrictVariables = context.StrictVariables;
			context.StrictVariables = false;
			object result = null;
			try
			{
				result = await context.EvaluateAsync(expression, aliasReturnedFunction: true).ConfigureAwait(continueOnCapturedContext: false);
			}
			catch (ScriptRuntimeException) when (context.IgnoreExceptionsWhileRewritingScientific)
			{
			}
			finally
			{
				context.StrictVariables = restoreStrictVariables;
			}
			if (result is IScriptCustomFunction scriptCustomFunction && ((scriptCustomFunction.RequiredParameterCount != 0) ? scriptCustomFunction.RequiredParameterCount : ((scriptCustomFunction.ParameterCount > 0) ? 1 : 0)) > 0)
			{
				return (!scriptCustomFunction.IsParameterType<ScriptExpression>(0)) ? FunctionCallKind.Regular : FunctionCallKind.Expression;
			}
			return FunctionCallKind.None;
		}

		public static async ValueTask<ScriptExpression> RewriteAsync(TemplateContext context, ScriptBinaryExpression binaryExpression)
		{
			if (!HasImplicitBinaryExpression(binaryExpression))
			{
				return binaryExpression;
			}
			BinaryExpressionIterator iterator = new BinaryExpressionIterator();
			await FlattenBinaryExpressionsAsync(context, binaryExpression, iterator).ConfigureAwait(continueOnCapturedContext: false);
			return ParseBinaryExpressionTree(iterator, 0, isExpectingExpression: false);
		}

		public static ScriptExpression Rewrite(TemplateContext context, ScriptBinaryExpression binaryExpression)
		{
			if (!HasImplicitBinaryExpression(binaryExpression))
			{
				return binaryExpression;
			}
			BinaryExpressionIterator binaryExpressionIterator = new BinaryExpressionIterator();
			FlattenBinaryExpressions(context, binaryExpression, binaryExpressionIterator);
			return ParseBinaryExpressionTree(binaryExpressionIterator, 0, isExpectingExpression: false);
		}

		private static bool HasImplicitBinaryExpression(ScriptExpression expression)
		{
			if (expression is ScriptBinaryExpression scriptBinaryExpression)
			{
				if (scriptBinaryExpression.OperatorToken == null && scriptBinaryExpression.Operator == ScriptBinaryOperator.Multiply)
				{
					return true;
				}
				if (!HasImplicitBinaryExpression(scriptBinaryExpression.Left))
				{
					return HasImplicitBinaryExpression(scriptBinaryExpression.Right);
				}
				return true;
			}
			return false;
		}

		private static void FlattenBinaryExpressions(TemplateContext context, ScriptExpression expression, List<BinaryExpressionOrOperator> expressions)
		{
			while (expression is ScriptBinaryExpression scriptBinaryExpression)
			{
				ScriptExpression expression2 = (ScriptExpression)scriptBinaryExpression.Left.Clone();
				ScriptExpression obj = (ScriptExpression)scriptBinaryExpression.Right.Clone();
				ScriptToken operatorToken = (ScriptToken)(scriptBinaryExpression.OperatorToken?.Clone());
				FlattenBinaryExpressions(context, expression2, expressions);
				expressions.Add(new BinaryExpressionOrOperator(scriptBinaryExpression.Operator, operatorToken));
				expression = obj;
			}
			expressions.Add(new BinaryExpressionOrOperator(expression, GetFunctionCallKind(context, expression)));
		}

		private static ScriptExpression ParseBinaryExpressionTree(BinaryExpressionIterator it, int precedence, bool isExpectingExpression)
		{
			ScriptExpression scriptExpression = null;
			while (it.HasCurrent)
			{
				BinaryExpressionOrOperator current = it.Current;
				ScriptExpression expression = current.Expression;
				if (expression == null)
				{
					int num = Parser.GetDefaultBinaryOperatorPrecedence(current.Operator);
					if (!isExpectingExpression && it.HasNext && it.PeekNext().CallKind != 0)
					{
						num = ((num < 101) ? num : 101);
					}
					if (num <= precedence)
					{
						break;
					}
					it.MoveNext();
					ScriptBinaryExpression scriptBinaryExpression = new ScriptBinaryExpression
					{
						Left = scriptExpression,
						Operator = current.Operator,
						OperatorToken = (current.OperatorToken ?? ScriptToken.Star()),
						Span = 
						{
							Start = scriptExpression.Span.Start
						}
					};
					scriptBinaryExpression.Right = ParseBinaryExpressionTree(it, num, isExpectingExpression);
					scriptBinaryExpression.Span.End = scriptBinaryExpression.Right.Span.End;
					scriptExpression = scriptBinaryExpression;
				}
				else if (!isExpectingExpression && current.CallKind != 0)
				{
					ScriptFunctionCall obj = new ScriptFunctionCall
					{
						Target = expression,
						ExplicitCall = true,
						Span = 
						{
							Start = expression.Span.Start
						}
					};
					if (!it.MoveNext())
					{
						throw new ScriptRuntimeException(expression.Span, "The function is expecting at least one argument");
					}
					if (it.Current.Expression == null && (it.Current.Operator != ScriptBinaryOperator.Multiply || it.Current.OperatorToken != null))
					{
						throw new ScriptRuntimeException(expression.Span, "The function expecting one argument cannot be followed by the operator " + (it.Current.OperatorToken?.ToString() ?? it.Current.Operator.ToText()));
					}
					if (!it.MoveNext())
					{
						throw new ScriptRuntimeException(expression.Span, "The function is expecting at least one argument");
					}
					ScriptExpression scriptExpression2 = ParseBinaryExpressionTree(it, 101, current.CallKind == FunctionCallKind.Expression);
					obj.Arguments.Add(scriptExpression2);
					obj.Span.End = scriptExpression2.Span.End;
					scriptExpression = obj;
				}
				else
				{
					scriptExpression = expression;
					it.MoveNext();
				}
			}
			return scriptExpression;
		}

		private static FunctionCallKind GetFunctionCallKind(TemplateContext context, ScriptExpression expression)
		{
			bool strictVariables = context.StrictVariables;
			context.StrictVariables = false;
			object obj = null;
			try
			{
				obj = context.Evaluate(expression, aliasReturnedFunction: true);
			}
			catch (ScriptRuntimeException) when (context.IgnoreExceptionsWhileRewritingScientific)
			{
			}
			finally
			{
				context.StrictVariables = strictVariables;
			}
			if (obj is IScriptCustomFunction scriptCustomFunction && ((scriptCustomFunction.RequiredParameterCount != 0) ? scriptCustomFunction.RequiredParameterCount : ((scriptCustomFunction.ParameterCount > 0) ? 1 : 0)) > 0)
			{
				if (!scriptCustomFunction.IsParameterType<ScriptExpression>(0))
				{
					return FunctionCallKind.Regular;
				}
				return FunctionCallKind.Expression;
			}
			return FunctionCallKind.None;
		}
	}
	[ScriptSyntax("array initializer", "[item1, item2,...]")]
	public class ScriptArrayInitializerExpression : ScriptExpression
	{
		private ScriptList<ScriptExpression> _values;

		private ScriptToken _openBracketToken;

		private ScriptToken _closeBracketToken;

		public override int ChildrenCount => 3;

		public ScriptToken OpenBracketToken
		{
			get
			{
				return _openBracketToken;
			}
			set
			{
				ParentToThis(ref _openBracketToken, value);
			}
		}

		public ScriptList<ScriptExpression> Values
		{
			get
			{
				return _values;
			}
			set
			{
				ParentToThis(ref _values, value);
			}
		}

		public ScriptToken CloseBracketToken
		{
			get
			{
				return _closeBracketToken;
			}
			set
			{
				ParentToThis(ref _closeBracketToken, value);
			}
		}

		public override async ValueTask<object> EvaluateAsync(TemplateContext context)
		{
			ScriptArray scriptArray = new ScriptArray();
			foreach (ScriptExpression value in Values)
			{
				scriptArray.Add(await context.EvaluateAsync(value).ConfigureAwait(continueOnCapturedContext: false));
			}
			return scriptArray;
		}

		protected override ScriptNode GetChildrenImpl(int index)
		{
			return index switch
			{
				0 => OpenBracketToken, 
				1 => Values, 
				2 => CloseBracketToken, 
				_ => null, 
			};
		}

		public override void Accept(ScriptVisitor visitor)
		{
			visitor.Visit(this);
		}

		public override TResult Accept<TResult>(ScriptVisitor<TResult> visitor)
		{
			return visitor.Visit(this);
		}

		public ScriptArrayInitializerExpression()
		{
			OpenBracketToken = ScriptToken.OpenBracket();
			Values = new ScriptList<ScriptExpression>();
			CloseBracketToken = ScriptToken.CloseBracket();
		}

		public override object Evaluate(TemplateContext context)
		{
			ScriptArray scriptArray = new ScriptArray();
			foreach (ScriptExpression value in Values)
			{
				object item = context.Evaluate(value);
				scriptArray.Add(item);
			}
			return scriptArray;
		}

		public override void PrintTo(ScriptPrinter printer)
		{
			printer.Write(OpenBracketToken);
			printer.WriteListWithCommas(Values);
			printer.Write(CloseBracketToken);
		}
	}
	[ScriptSyntax("assign expression", "<target_expression> = <value_expression>")]
	public class ScriptAssignExpression : ScriptExpression
	{
		private ScriptExpression _target;

		private ScriptToken _equalToken;

		private ScriptExpression _value;

		public override int ChildrenCount => 3;

		public ScriptExpression Target
		{
			get
			{
				return _target;
			}
			set
			{
				ParentToThis(ref _target, value);
			}
		}

		public ScriptToken EqualToken
		{
			get
			{
				return _equalToken;
			}
			set
			{
				ParentToThis(ref _equalToken, value);
			}
		}

		public ScriptExpression Value
		{
			get
			{
				return _value;
			}
			set
			{
				ParentToThis(ref _value, value);
			}
		}

		public override async ValueTask<object> EvaluateAsync(TemplateContext context)
		{
			object obj = ((EqualToken.TokenType != TokenType.Equal) ? (await GetValueToSetAsync(context).ConfigureAwait(continueOnCapturedContext: false)) : (await context.EvaluateAsync(Value).ConfigureAwait(continueOnCapturedContext: false)));
			object value = obj;
			await context.SetValueAsync(Target, value).ConfigureAwait(continueOnCapturedContext: false);
			return null;
		}

		private async ValueTask<object> GetValueToSetAsync(TemplateContext context)
		{
			object right = await context.EvaluateAsync(Value).ConfigureAwait(continueOnCapturedContext: false);
			object leftValue = await context.EvaluateAsync(Target).ConfigureAwait(continueOnCapturedContext: false);
			ScriptBinaryOperator op = EqualToken.TokenType switch
			{
				TokenType.PlusEqual => ScriptBinaryOperator.Add, 
				TokenType.MinusEqual => ScriptBinaryOperator.Subtract, 
				TokenType.AsteriskEqual => ScriptBinaryOperator.Multiply, 
				TokenType.DivideEqual => ScriptBinaryOperator.Divide, 
				TokenType.DoubleDivideEqual => ScriptBinaryOperator.DivideRound, 
				TokenType.PercentEqual => ScriptBinaryOperator.Modulus, 
				_ => throw new ScriptRuntimeException(context.CurrentSpan, $"Operator {EqualToken} is not a valid compound assignment operator"), 
			};
			return ScriptBinaryExpression.Evaluate(context, Span, op, leftValue, right);
		}

		protected override ScriptNode GetChildrenImpl(int index)
		{
			return index switch
			{
				0 => Target, 
				1 => EqualToken, 
				2 => Value, 
				_ => null, 
			};
		}

		public override void Accept(ScriptVisitor visitor)
		{
			visitor.Visit(this);
		}

		public override TResult Accept<TResult>(ScriptVisitor<TResult> visitor)
		{
			return visitor.Visit(this);
		}

		public ScriptAssignExpression()
		{
			EqualToken = ScriptToken.Equal();
		}

		public override object Evaluate(TemplateContext context)
		{
			object value = ((EqualToken.TokenType == TokenType.Equal) ? context.Evaluate(Value) : GetValueToSet(context));
			context.SetValue(Target, value);
			return null;
		}

		private object GetValueToSet(TemplateContext context)
		{
			object rightValue = context.Evaluate(Value);
			object leftValue = context.Evaluate(Target);
			ScriptBinaryOperator op = EqualToken.TokenType switch
			{
				TokenType.PlusEqual => ScriptBinaryOperator.Add, 
				TokenType.MinusEqual => ScriptBinaryOperator.Subtract, 
				TokenType.AsteriskEqual => ScriptBinaryOperator.Multiply, 
				TokenType.DivideEqual => ScriptBinaryOperator.Divide, 
				TokenType.DoubleDivideEqual => ScriptBinaryOperator.DivideRound, 
				TokenType.PercentEqual => ScriptBinaryOperator.Modulus, 
				_ => throw new ScriptRuntimeException(context.CurrentSpan, $"Operator {EqualToken} is not a valid compound assignment operator"), 
			};
			return ScriptBinaryExpression.Evaluate(context, Span, op, leftValue, rightValue);
		}

		public override bool CanHaveLeadingTrivia()
		{
			return false;
		}

		public override void PrintTo(ScriptPrinter printer)
		{
			printer.Write(Target);
			printer.Write(EqualToken);
			printer.Write(Value);
		}
	}
	[ScriptSyntax("binary expression", "<expression> operator <expression>")]
	public class ScriptBinaryExpression : ScriptExpression
	{
		[CompilerGenerated]
		private sealed class <RangeExclude>d__32 : IEnumerable<object>, IEnumerable, IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			private int <>l__initialThreadId;

			private long left;

			public long <>3__left;

			private long right;

			public long <>3__right;

			private long <i>5__2;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <RangeExclude>d__32(int <>1__state)
			{
				this.<>1__state = <>1__state;
				<>l__initialThreadId = Environment.CurrentManagedThreadId;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					if (left < right)
					{
						<i>5__2 = left;
						goto IL_0070;
					}
					<i>5__2 = left;
					goto IL_00c0;
				case 1:
					<>1__state = -1;
					<i>5__2++;
					goto IL_0070;
				case 2:
					{
						<>1__state = -1;
						<i>5__2--;
						goto IL_00c0;
					}
					IL_00c0:
					if (<i>5__2 > right)
					{
						<>2__current = FitToBestInteger(<i>5__2);
						<>1__state = 2;
						return true;
					}
					break;
					IL_0070:
					if (<i>5__2 < right)
					{
						<>2__current = FitToBestInteger(<i>5__2);
						<>1__state = 1;
						return true;
					}
					break;
				}
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}

			[DebuggerHidden]
			IEnumerator<object> IEnumerable<object>.GetEnumerator()
			{
				<RangeExclude>d__32 <RangeExclude>d__;
				if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
				{
					<>1__state = 0;
					<RangeExclude>d__ = this;
				}
				else
				{
					<RangeExclude>d__ = new <RangeExclude>d__32(0);
				}
				<RangeExclude>d__.left = <>3__left;
				<RangeExclude>d__.right = <>3__right;
				return <RangeExclude>d__;
			}

			[DebuggerHidden]
			IEnumerator IEnumerable.GetEnumerator()
			{
				return ((IEnumerable<object>)this).GetEnumerator();
			}
		}

		[CompilerGenerated]
		private sealed class <RangeExclude>d__34 : IEnumerable<object>, IEnumerable, IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			private int <>l__initialThreadId;

			private BigInteger left;

			public BigInteger <>3__left;

			private BigInteger right;

			public BigInteger <>3__right;

			private BigInteger <i>5__2;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <RangeExclude>d__34(int <>1__state)
			{
				this.<>1__state = <>1__state;
				<>l__initialThreadId = Environment.CurrentManagedThreadId;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					if (left < right)
					{
						<i>5__2 = left;
						goto IL_0077;
					}
					<i>5__2 = left;
					goto IL_00ce;
				case 1:
					<>1__state = -1;
					<i>5__2++;
					goto IL_0077;
				case 2:
					{
						<>1__state = -1;
						<i>5__2--;
						goto IL_00ce;
					}
					IL_00ce:
					if (<i>5__2 > right)
					{
						<>2__current = FitToBestInteger(<i>5__2);
						<>1__state = 2;
						return true;
					}
					break;
					IL_0077:
					if (<i>5__2 < right)
					{
						<>2__current = FitToBestInteger(<i>5__2);
						<>1__state = 1;
						return true;
					}
					break;
				}
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}

			[DebuggerHidden]
			IEnumerator<object> IEnumerable<object>.GetEnumerator()
			{
				<RangeExclude>d__34 <RangeExclude>d__;
				if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
				{
					<>1__state = 0;
					<RangeExclude>d__ = this;
				}
				else
				{
					<RangeExclude>d__ = new <RangeExclude>d__34(0);
				}
				<RangeExclude>d__.left = <>3__left;
				<RangeExclude>d__.right = <>3__right;
				return <RangeExclude>d__;
			}

			[DebuggerHidden]
			IEnumerator IEnumerable.GetEnumerator()
			{
				return ((IEnumerable<object>)this).GetEnumerator();
			}
		}

		[CompilerGenerated]
		private sealed class <RangeInclude>d__31 : IEnumerable<object>, IEnumerable, IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			private int <>l__initialThreadId;

			private long left;

			public long <>3__left;

			private long right;

			public long <>3__right;

			private long <i>5__2;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <RangeInclude>d__31(int <>1__state)
			{
				this.<>1__state = <>1__state;
				<>l__initialThreadId = Environment.CurrentManagedThreadId;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					if (left < right)
					{
						<i>5__2 = left;
						goto IL_0070;
					}
					<i>5__2 = left;
					goto IL_00c0;
				case 1:
					<>1__state = -1;
					<i>5__2++;
					goto IL_0070;
				case 2:
					{
						<>1__state = -1;
						<i>5__2--;
						goto IL_00c0;
					}
					IL_00c0:
					if (<i>5__2 >= right)
					{
						<>2__current = FitToBestInteger(<i>5__2);
						<>1__state = 2;
						return true;
					}
					break;
					IL_0070:
					if (<i>5__2 <= right)
					{
						<>2__current = FitToBestInteger(<i>5__2);
						<>1__state = 1;
						return true;
					}
					break;
				}
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}

			[DebuggerHidden]
			IEnumerator<object> IEnumerable<object>.GetEnumerator()
			{
				<RangeInclude>d__31 <RangeInclude>d__;
				if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
				{
					<>1__state = 0;
					<RangeInclude>d__ = this;
				}
				else
				{
					<RangeInclude>d__ = new <RangeInclude>d__31(0);
				}
				<RangeInclude>d__.left = <>3__left;
				<RangeInclude>d__.right = <>3__right;
				return <RangeInclude>d__;
			}

			[DebuggerHidden]
			IEnumerator IEnumerable.GetEnumerator()
			{
				return ((IEnumerable<object>)this).GetEnumerator();
			}
		}

		[CompilerGenerated]
		private sealed class <RangeInclude>d__33 : IEnumerable<object>, IEnumerable, IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			private int <>l__initialThreadId;

			private BigInteger left;

			public BigInteger <>3__left;

			private BigInteger right;

			public BigInteger <>3__right;

			private BigInteger <i>5__2;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <RangeInclude>d__33(int <>1__state)
			{
				this.<>1__state = <>1__state;
				<>l__initialThreadId = Environment.CurrentManagedThreadId;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					if (left < right)
					{
						<i>5__2 = left;
						goto IL_0077;
					}
					<i>5__2 = left;
					goto IL_00ce;
				case 1:
					<>1__state = -1;
					<i>5__2++;
					goto IL_0077;
				case 2:
					{
						<>1__state = -1;
						<i>5__2--;
						goto IL_00ce;
					}
					IL_00ce:
					if (<i>5__2 >= right

Mods/LabPresence.dll

Decompiled 2 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Security;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Text.Json;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using BoneLib;
using BoneLib.BoneMenu;
using BoneLib.Notifications;
using DiscordRPC;
using DiscordRPC.Events;
using DiscordRPC.Exceptions;
using DiscordRPC.Helper;
using DiscordRPC.IO;
using DiscordRPC.Logging;
using DiscordRPC.Message;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSLZ.Marrow;
using Il2CppSLZ.Marrow.Interaction;
using Il2CppSLZ.Marrow.Pool;
using Il2CppSLZ.Marrow.SceneStreaming;
using Il2CppSLZ.Marrow.Utilities;
using Il2CppSLZ.Marrow.Warehouse;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using Il2CppSystem.Reflection;
using LabFusion.Data;
using LabFusion.Entities;
using LabFusion.Network;
using LabFusion.Player;
using LabFusion.SDK.Gamemodes;
using LabFusion.SDK.Metadata;
using LabFusion.UI.Popups;
using LabFusion.Utilities;
using LabPresence;
using LabPresence.Config;
using LabPresence.Managers;
using LabPresence.Plugins;
using LabPresence.Plugins.Default;
using LabPresence.Utilities;
using MelonLoader;
using MelonLoader.Preferences;
using MelonLoader.Utils;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Scriban;
using Scriban.Parsing;
using Scriban.Runtime;
using Semver;
using Tomlet.Attributes;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: MelonInfo(typeof(Core), "LabPresence", "1.3.0", "HAHOOS", "https://thunderstore.io/c/bonelab/p/HAHOOS/LabPresence/")]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: MelonPriority(-1000)]
[assembly: MelonOptionalDependencies(new string[] { "LabFusion", "DiscordRPC", "Scriban" })]
[assembly: MelonPlatform(/*Could not decode attribute arguments.*/)]
[assembly: AssemblyTitle("Adds Discord Rich Presence support to BONELAB")]
[assembly: AssemblyDescription("Adds Discord Rich Presence support to BONELAB")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("HAHOOS")]
[assembly: AssemblyProduct("LabPresence")]
[assembly: AssemblyFileVersion("1.3.0")]
[assembly: AssemblyInformationalVersion("1.3.0")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyVersion("1.3.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace LabPresence
{
	public class Core : MelonMod
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static OnJoinEvent <>9__31_4;

			public static OnJoinRequestedEvent <>9__31_5;

			public static OnSpectateEvent <>9__31_6;

			public static Action <>9__31_7;

			public static Action <>9__31_8;

			public static Action <>9__31_9;

			public static Action <>9__31_10;

			public static Action<LevelCrate> <>9__31_11;

			public static Action<LevelCrate> <>9__31_12;

			public static Action<LevelCrate> <>9__31_13;

			public static Func<ScriptObject> <>9__35_0;

			internal void <OnInitializeMelon>b__31_4(object _, JoinMessage e)
			{
				Overwrites.OnJoin.Run(e);
			}

			internal void <OnInitializeMelon>b__31_5(object _, JoinRequestMessage e)
			{
				Overwrites.OnJoinRequested.Run(e);
			}

			internal void <OnInitializeMelon>b__31_6(object _, SpectateMessage e)
			{
				Overwrites.OnSpectate.Run(e);
			}

			internal void <OnInitializeMelon>b__31_7()
			{
				RichPresenceManager.TrySetRichPresence(Config.LevelLoaded, (ActivityType)0);
			}

			internal void <OnInitializeMelon>b__31_8()
			{
				RichPresenceManager.TrySetRichPresence(Config.LevelLoading, (ActivityType)0);
			}

			internal void <OnInitializeMelon>b__31_9()
			{
				RichPresenceManager.TrySetRichPresence(Config.AssetWarehouseLoaded, (ActivityType)0);
			}

			internal void <OnInitializeMelon>b__31_10()
			{
				RichPresenceManager.TrySetRichPresence(Config.PreGameStarted, (ActivityType)0);
			}

			internal void <OnInitializeMelon>b__31_11(LevelCrate _)
			{
				if (!FirstLevelLoad)
				{
					FirstLevelLoad = true;
					Thunderstore.BL_SendNotification();
				}
				LevelLaunch = DateTime.Now;
				ConfigureTimestamp(autoUpdate: true);
				Overwrites.OnLevelLoaded.Run();
			}

			internal void <OnInitializeMelon>b__31_12(LevelCrate _)
			{
				Overwrites.OnLevelLoading.Run();
			}

			internal void <OnInitializeMelon>b__31_13(LevelCrate _)
			{
				Overwrites.OnLevelUnloaded.Run();
			}

			internal ScriptObject <AddDefaultPlaceholders>b__35_0()
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_000b: Unknown result type (might be due to invalid IL or missing references)
				//IL_001c: Unknown result type (might be due to invalid IL or missing references)
				//IL_002d: Unknown result type (might be due to invalid IL or missing references)
				//IL_003f: Expected O, but got Unknown
				ScriptObject val = new ScriptObject((IEqualityComparer<string>)StringComparer.OrdinalIgnoreCase);
				val.Add("game", (object)new ScribanGame());
				val.Add("player", (object)new ScribanPlayer());
				val.Add("ammo", (object)new ScribanAmmo());
				return val;
			}
		}

		public const string Version = "1.3.0";

		private const string ClientID = "1338522973421965382";

		private static float _elapsedSecondsDateCheck = 0f;

		public static DiscordRpcClient Client { get; private set; }

		internal static Instance Logger { get; private set; }

		internal static MelonPreferences_ReflectiveCategory Category { get; private set; }

		internal static DefaultConfig Config
		{
			get
			{
				MelonPreferences_ReflectiveCategory category = Category;
				return (category != null) ? category.GetValue<DefaultConfig>() : null;
			}
		}

		public static DateTimeOffset GameLaunch { get; } = DateTimeOffset.Now;


		public static DateTimeOffset LevelLaunch { get; private set; } = DateTimeOffset.Now;


		public static Thunderstore Thunderstore { get; private set; }

		public static bool FirstLevelLoad { get; private set; }

		private static int LastDay { get; set; } = -1;


		public override void OnInitializeMelon()
		{
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Expected O, but got Unknown
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Expected O, but got Unknown
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Expected O, but got Unknown
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Expected O, but got Unknown
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0197: Expected O, but got Unknown
			//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Expected O, but got Unknown
			//IL_01db: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e6: Expected O, but got Unknown
			//IL_0205: Unknown result type (might be due to invalid IL or missing references)
			//IL_020a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0210: Expected O, but got Unknown
			if (HelperMethods.IsAndroid())
			{
				((MelonBase)this).LoggerInstance.Error("This mod is not supported as it is unlikely for it to actually work.");
				((MelonBase)this).Unregister("Unsupported platform", false);
				return;
			}
			Logger = ((MelonBase)this).LoggerInstance;
			((MelonBase)this).LoggerInstance.Msg("Creating preferences");
			DirectoryInfo directoryInfo = Directory.CreateDirectory(Path.Combine(MelonEnvironment.UserDataDirectory, "LabPresence"));
			Category = MelonPreferences.CreateCategory<DefaultConfig>("LabPresenceConfig", "Lab Presence Config");
			Category.SetFilePath(Path.Combine(directoryInfo.FullName, "default.cfg"), true, false);
			Category.SaveToFile(false);
			((MelonBase)this).LoggerInstance.Msg("Initializing Thunderstore");
			Thunderstore = new Thunderstore("LabPresence / 1.3.0 A BONELAB Mod");
			Thunderstore.BL_FetchPackage("LabPresence", "HAHOOS", "1.3.0", ((MelonBase)this).LoggerInstance);
			((MelonBase)this).LoggerInstance.Msg("Adding placeholders");
			AddDefaultPlaceholders();
			((MelonBase)this).LoggerInstance.Msg("Initializing...");
			Client = new DiscordRpcClient("1338522973421965382", -1, (ILogger)null, false, (INamedPipeClient)null)
			{
				Logger = (ILogger)(object)new Logger(((MelonBase)this).LoggerInstance, Config.RPCLogLevel, "RPC")
			};
			Client.OnReady += (OnReadyEvent)delegate(object _, ReadyMessage e)
			{
				((MelonBase)this).LoggerInstance.Msg("User @" + e.User.Username + " is ready");
				((MelonBase)this).LoggerInstance.Msg("Registering URI Scheme");
				RegisterURIScheme();
				Client.SynchronizeState();
			};
			Client.OnConnectionEstablished += (OnConnectionEstablishedEvent)delegate
			{
				((MelonBase)this).LoggerInstance.Msg("Successfully established connection");
			};
			Client.OnConnectionFailed += (OnConnectionFailedEvent)delegate(object _, ConnectionFailedMessage e)
			{
				((MelonBase)this).LoggerInstance.Error($"Failed to establish connection with pipe {e.FailedPipe}");
			};
			Client.OnError += (OnErrorEvent)delegate(object _, ErrorMessage e)
			{
				((MelonBase)this).LoggerInstance.Error("An unexpected error has occurred when sending a message, error: " + e.Message);
			};
			DiscordRpcClient client = Client;
			object obj = <>c.<>9__31_4;
			if (obj == null)
			{
				OnJoinEvent val = delegate(object _, JoinMessage e)
				{
					Overwrites.OnJoin.Run(e);
				};
				<>c.<>9__31_4 = val;
				obj = (object)val;
			}
			client.OnJoin += (OnJoinEvent)obj;
			DiscordRpcClient client2 = Client;
			object obj2 = <>c.<>9__31_5;
			if (obj2 == null)
			{
				OnJoinRequestedEvent val2 = delegate(object _, JoinRequestMessage e)
				{
					Overwrites.OnJoinRequested.Run(e);
				};
				<>c.<>9__31_5 = val2;
				obj2 = (object)val2;
			}
			client2.OnJoinRequested += (OnJoinRequestedEvent)obj2;
			DiscordRpcClient client3 = Client;
			object obj3 = <>c.<>9__31_6;
			if (obj3 == null)
			{
				OnSpectateEvent val3 = delegate(object _, SpectateMessage e)
				{
					Overwrites.OnSpectate.Run(e);
				};
				<>c.<>9__31_6 = val3;
				obj3 = (object)val3;
			}
			client3.OnSpectate += (OnSpectateEvent)obj3;
			Client.SkipIdenticalPresence = true;
			Client.SetSubscription((EventType)7);
			Client.Initialize();
			Overwrites.OnLevelLoaded.SetDefault(delegate
			{
				RichPresenceManager.TrySetRichPresence(Config.LevelLoaded, (ActivityType)0);
			});
			Overwrites.OnLevelLoading.SetDefault(delegate
			{
				RichPresenceManager.TrySetRichPresence(Config.LevelLoading, (ActivityType)0);
			});
			Overwrites.OnAssetWarehouseLoaded.SetDefault(delegate
			{
				RichPresenceManager.TrySetRichPresence(Config.AssetWarehouseLoaded, (ActivityType)0);
			});
			Overwrites.OnPreGame.SetDefault(delegate
			{
				RichPresenceManager.TrySetRichPresence(Config.PreGameStarted, (ActivityType)0);
			});
			try
			{
				if (Fusion.HasFusion)
				{
					PluginsManager.Register<FusionPlugin>();
				}
			}
			catch (Exception value)
			{
				Logger.Error($"An unexpected error has occurred while attempting to register the Fusion Plugin, exception:\n{value}");
			}
			LevelHooks.OnLevelLoaded = (Action<LevelCrate>)Delegate.Combine(LevelHooks.OnLevelLoaded, (Action<LevelCrate>)delegate
			{
				if (!FirstLevelLoad)
				{
					FirstLevelLoad = true;
					Thunderstore.BL_SendNotification();
				}
				LevelLaunch = DateTime.Now;
				ConfigureTimestamp(autoUpdate: true);
				Overwrites.OnLevelLoaded.Run();
			});
			LevelHooks.OnLevelLoading = (Action<LevelCrate>)Delegate.Combine(LevelHooks.OnLevelLoading, (Action<LevelCrate>)delegate
			{
				Overwrites.OnLevelLoading.Run();
			});
			LevelHooks.OnLevelUnloaded = (Action<LevelCrate>)Delegate.Combine(LevelHooks.OnLevelUnloaded, (Action<LevelCrate>)delegate
			{
				Overwrites.OnLevelUnloaded.Run();
			});
			AssetWarehouse.OnReady(Action.op_Implicit((Action)Overwrites.OnAssetWarehouseLoaded.Run));
			Overwrites.OnPreGame.Run();
			((MelonBase)this).LoggerInstance.Msg("Creating BoneMenu");
			MenuManager.Init();
			((MelonBase)this).LoggerInstance.Msg("Initialized.");
		}

		private void RegisterURIScheme()
		{
			try
			{
				Client.RegisterUriScheme((string)null, (string)null);
			}
			catch (Exception value)
			{
				((MelonBase)this).LoggerInstance.Error($"An unexpected error has occurred while registering URI scheme, exception:\n{value}");
			}
		}

		public static void ConfigureTimestamp(bool autoUpdate = false)
		{
			if (Config.TimeMode == TimeMode.CurrentTime)
			{
				RichPresenceManager.SetTimestampToCurrentTime(autoUpdate);
			}
			else if (Config.TimeMode == TimeMode.GameSession)
			{
				RichPresenceManager.SetTimestamp((ulong)GameLaunch.ToUnixTimeMilliseconds(), null, autoUpdate);
			}
			else if (Config.TimeMode == TimeMode.Level)
			{
				RichPresenceManager.SetTimestamp((ulong)LevelLaunch.ToUnixTimeMilliseconds(), null, autoUpdate);
			}
		}

		public static SpawnableCrate GetInHand(Handedness handType)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Invalid comparison between Unknown and I4
			Hand val = (((int)handType == 1) ? Player.LeftHand : Player.RightHand);
			object result;
			if (val == null)
			{
				result = null;
			}
			else
			{
				HandReciever attachedReceiver = val.AttachedReceiver;
				if (attachedReceiver == null)
				{
					result = null;
				}
				else
				{
					IGrippable host = attachedReceiver.Host;
					if (host == null)
					{
						result = null;
					}
					else
					{
						Grip grip = host.GetGrip();
						if (grip == null)
						{
							result = null;
						}
						else
						{
							MarrowEntity marrowEntity = grip._marrowEntity;
							if (marrowEntity == null)
							{
								result = null;
							}
							else
							{
								Poolee poolee = marrowEntity._poolee;
								result = ((poolee != null) ? poolee.SpawnableCrate : null);
							}
						}
					}
				}
			}
			return (SpawnableCrate)result;
		}

		private static void AddDefaultPlaceholders()
		{
			PlaceholderManager.RegisterPlaceholder("default", delegate
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_000b: Unknown result type (might be due to invalid IL or missing references)
				//IL_001c: Unknown result type (might be due to invalid IL or missing references)
				//IL_002d: Unknown result type (might be due to invalid IL or missing references)
				//IL_003f: Expected O, but got Unknown
				ScriptObject val = new ScriptObject((IEqualityComparer<string>)StringComparer.OrdinalIgnoreCase);
				val.Add("game", (object)new ScribanGame());
				val.Add("player", (object)new ScribanPlayer());
				val.Add("ammo", (object)new ScribanAmmo());
				return val;
			});
		}

		public static string CleanLevelName()
		{
			StreamSession session = SceneStreamer.Session;
			object obj;
			if (session == null)
			{
				obj = null;
			}
			else
			{
				LevelCrate level = session.Level;
				obj = ((level != null) ? ((Scannable)level).Title : null);
			}
			string text = (string)obj;
			if (text == null)
			{
				return "N/A";
			}
			if (Config.RemoveLevelNumbers)
			{
				text = RemoveBONELABLevelNumbers(text);
			}
			return text;
		}

		public static string RemoveUnityRichText(string text)
		{
			if (string.IsNullOrWhiteSpace(text))
			{
				return text;
			}
			return Regex.Replace(text, "<(.*?)>", string.Empty);
		}

		public static string RemoveBONELABLevelNumbers(string levelName)
		{
			return Regex.Replace(levelName, "[0-9][0-9] - ", string.Empty);
		}

		public override void OnUpdate()
		{
			((MelonBase)this).OnUpdate();
			Internal_OnUpdate();
		}

		private static void Internal_OnUpdate()
		{
			DiscordRpcClient client = Client;
			if (client != null && client.IsInitialized)
			{
				DiscordRpcClient client2 = Client;
				if (client2 != null)
				{
					client2.Invoke();
				}
			}
			RichPresenceManager.OnUpdate();
			Fps.OnUpdate();
			LevelHooks.OnUpdate();
			_elapsedSecondsDateCheck += Time.deltaTime;
			if (LastDay == -1)
			{
				LastDay = DateTime.Now.Day;
			}
			if (RichPresenceManager.CurrentConfig == null || !(_elapsedSecondsDateCheck >= 5f))
			{
				return;
			}
			_elapsedSecondsDateCheck = 0f;
			if (Config.TimeMode == TimeMode.CurrentTime)
			{
				DateTime now = DateTime.Now;
				if (now.Day != LastDay)
				{
					LastDay = now.Day;
					RichPresenceManager.SetTimestampToCurrentTime(autoUpdate: true);
				}
			}
		}

		public override void OnApplicationQuit()
		{
			DiscordRpcClient client = Client;
			if (client != null)
			{
				client.ClearPresence();
			}
			DiscordRpcClient client2 = Client;
			if (client2 != null)
			{
				client2.Dispose();
			}
		}
	}
	public class Logger : ILogger
	{
		public LogLevel Level { get; set; }

		public string Prefix { get; internal set; }

		private Instance LoggerInstance { get; }

		public Logger(Instance logger, string prefix)
		{
			LoggerInstance = logger;
			Prefix = prefix;
		}

		public Logger(Instance logger, LogLevel level, string prefix)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			LoggerInstance = logger;
			Level = level;
			Prefix = prefix;
		}

		public void Error(string message, params object[] args)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Invalid comparison between Unknown and I4
			if ((int)Level <= 4)
			{
				LoggerInstance.Error("[" + Prefix + "] [ERROR] " + message, args);
			}
		}

		public void Info(string message, params object[] args)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Invalid comparison between Unknown and I4
			if ((int)Level <= 2)
			{
				LoggerInstance.Msg("[" + Prefix + "] [INFO] " + message, args);
			}
		}

		public void Trace(string message, params object[] args)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Invalid comparison between Unknown and I4
			if ((int)Level <= 1)
			{
				LoggerInstance.Msg("[" + Prefix + "] [TRACE] " + message, args);
			}
		}

		public void Warning(string message, params object[] args)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Invalid comparison between Unknown and I4
			if ((int)Level <= 3)
			{
				LoggerInstance.Warning("[" + Prefix + "] [WARN] " + message, args);
			}
		}
	}
}
namespace LabPresence.Utilities
{
	public static class Fps
	{
		private static float updateTime;

		public static int FramesPerSecond { get; private set; }

		internal static int FramesRendered { get; private set; }

		internal static DateTime LastTime { get; private set; }

		internal static void OnUpdate()
		{
			FramesRendered++;
			updateTime += Time.deltaTime;
			if (updateTime >= 1f)
			{
				updateTime = 0f;
				FramesPerSecond = FramesRendered;
				FramesRendered = 0;
				LastTime = DateTime.Now;
			}
		}
	}
	public static class ImageConversion
	{
		private delegate IntPtr TextureOnlyDelegate(IntPtr tex);

		private delegate IntPtr TextureAndQualityDelegate(IntPtr tex, int quality);

		private delegate IntPtr TextureAndFlagDelegate(IntPtr tex, EXRFlags flags);

		private delegate bool LoadImageDelegate(IntPtr tex, IntPtr data, bool markNonReadable);

		private const string NullTextureError = "The texture cannot be null.";

		private static readonly TextureAndFlagDelegate EncodeToEXRDelegateField = IL2CPP.ResolveICall<TextureAndFlagDelegate>("UnityEngine.ImageConversion::EncodeToEXR");

		private static readonly TextureOnlyDelegate EncodeToTGADelegateField = IL2CPP.ResolveICall<TextureOnlyDelegate>("UnityEngine.ImageConversion::EncodeToTGA");

		private static readonly TextureOnlyDelegate EncodeToPNGDelegateField = IL2CPP.ResolveICall<TextureOnlyDelegate>("UnityEngine.ImageConversion::EncodeToPNG");

		private static readonly TextureAndQualityDelegate EncodeToJPGDelegateField = IL2CPP.ResolveICall<TextureAndQualityDelegate>("UnityEngine.ImageConversion::EncodeToJPG");

		private static readonly LoadImageDelegate LoadImageDelegateField = IL2CPP.ResolveICall<LoadImageDelegate>("UnityEngine.ImageConversion::LoadImage");

		public static Il2CppStructArray<byte> EncodeToTGA(this Texture2D tex)
		{
			if ((Object)(object)tex == (Object)null)
			{
				throw new ArgumentNullException("tex", "The texture cannot be null.");
			}
			if (EncodeToTGADelegateField == null)
			{
				throw new InvalidOperationException("The EncodeToTGADelegateField cannot be null.");
			}
			IntPtr intPtr = EncodeToTGADelegateField(IL2CPP.Il2CppObjectBaseToPtr((Il2CppObjectBase)(object)tex));
			if (intPtr != IntPtr.Zero)
			{
				return new Il2CppStructArray<byte>(intPtr);
			}
			return null;
		}

		public static Il2CppStructArray<byte> EncodeToPNG(this Texture2D tex)
		{
			if ((Object)(object)tex == (Object)null)
			{
				throw new ArgumentNullException("tex", "The texture cannot be null.");
			}
			if (EncodeToPNGDelegateField == null)
			{
				throw new InvalidOperationException("The EncodeToPNGDelegateField cannot be null.");
			}
			IntPtr intPtr = EncodeToPNGDelegateField(IL2CPP.Il2CppObjectBaseToPtr((Il2CppObjectBase)(object)tex));
			if (intPtr != IntPtr.Zero)
			{
				return new Il2CppStructArray<byte>(intPtr);
			}
			return null;
		}

		public static Il2CppStructArray<byte> EncodeToJPG(this Texture2D tex, int quality)
		{
			if ((Object)(object)tex == (Object)null)
			{
				throw new ArgumentNullException("tex", "The texture cannot be null.");
			}
			if (EncodeToJPGDelegateField == null)
			{
				throw new InvalidOperationException("The EncodeToJPGDelegateField cannot be null.");
			}
			IntPtr intPtr = EncodeToJPGDelegateField(IL2CPP.Il2CppObjectBaseToPtr((Il2CppObjectBase)(object)tex), quality);
			if (intPtr != IntPtr.Zero)
			{
				return new Il2CppStructArray<byte>(intPtr);
			}
			return null;
		}

		public static Il2CppStructArray<byte> EncodeToJPG(this Texture2D tex)
		{
			return tex.EncodeToJPG(75);
		}

		public static Il2CppStructArray<byte> EncodeToEXR(this Texture2D tex, EXRFlags flags)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)tex == (Object)null)
			{
				throw new ArgumentNullException("tex", "The texture cannot be null.");
			}
			if (EncodeToEXRDelegateField == null)
			{
				throw new InvalidOperationException("The EncodeToEXRDelegateField cannot be null.");
			}
			IntPtr intPtr = EncodeToEXRDelegateField(IL2CPP.Il2CppObjectBaseToPtr((Il2CppObjectBase)(object)tex), flags);
			if (intPtr != IntPtr.Zero)
			{
				return new Il2CppStructArray<byte>(intPtr);
			}
			return null;
		}

		public static Il2CppStructArray<byte> EncodeToEXR(this Texture2D tex)
		{
			return tex.EncodeToEXR((EXRFlags)0);
		}

		public static bool LoadImage(this Texture2D tex, Il2CppStructArray<byte> data, bool markNonReadable)
		{
			if ((Object)(object)tex == (Object)null)
			{
				throw new ArgumentNullException("tex", "The texture cannot be null.");
			}
			if (data == null)
			{
				throw new ArgumentNullException("data", "The data cannot be null.");
			}
			if (LoadImageDelegateField == null)
			{
				throw new InvalidOperationException("The LoadImageDelegateField cannot be null.");
			}
			return LoadImageDelegateField(IL2CPP.Il2CppObjectBaseToPtr((Il2CppObjectBase)(object)tex), IL2CPP.Il2CppObjectBaseToPtr((Il2CppObjectBase)(object)data), markNonReadable);
		}

		public static bool LoadImage(this Texture2D tex, Il2CppStructArray<byte> data)
		{
			return tex.LoadImage(data, markNonReadable: false);
		}

		public static Texture2D LoadTexture(string name, byte[] bytes)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Expected O, but got Unknown
			Texture2D val = new Texture2D(2, 2);
			val.LoadImage(Il2CppStructArray<byte>.op_Implicit(bytes), markNonReadable: false);
			((Object)val).name = name;
			((Object)val).hideFlags = (HideFlags)32;
			return val;
		}
	}
	public static class LevelHooks
	{
		public static LevelCrate CurrentLevel
		{
			get
			{
				StreamSession session = SceneStreamer.Session;
				return ((session != null) ? session.Level : null) ?? null;
			}
		}

		public static Action<LevelCrate> OnLevelLoaded { get; set; }

		public static Action<LevelCrate> OnLevelLoading { get; set; }

		public static Action<LevelCrate> OnLevelUnloaded { get; set; }

		internal static LastStatus LastStatus { get; private set; }

		internal static void OnUpdate()
		{
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Invalid comparison between Unknown and I4
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Invalid comparison between Unknown and I4
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Invalid comparison between Unknown and I4
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Invalid comparison between Unknown and I4
			if (!MarrowGame.IsInitialized || SceneStreamer.Session == null || (Object)(object)SceneStreamer.Session.Level == (Object)null)
			{
				return;
			}
			LastStatus lastStatus = LastStatus;
			if (lastStatus != null && lastStatus.UpToDate(SceneStreamer.Session.Level, SceneStreamer.Session.Status))
			{
				return;
			}
			try
			{
				if ((int)SceneStreamer.Session.Status == 2)
				{
					OnLevelLoaded?.Invoke(SceneStreamer.Session.Level);
				}
				else if ((int)SceneStreamer.Session.Status == 1)
				{
					OnLevelLoading?.Invoke(SceneStreamer.Session.Level);
				}
				if ((int)SceneStreamer.Session.Status != 2)
				{
					LastStatus lastStatus2 = LastStatus;
					if (lastStatus2 != null && (int)lastStatus2.Status == 2)
					{
						OnLevelUnloaded?.Invoke(LastStatus?.Level);
					}
				}
			}
			finally
			{
				LastStatus = new LastStatus(SceneStreamer.Session.Status, SceneStreamer.Session.Level);
			}
		}
	}
	internal class LastStatus
	{
		internal StreamStatus Status { get; set; }

		internal LevelCrate Level { get; set; }

		public LastStatus(StreamStatus status, LevelCrate level)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			Status = status;
			Level = level;
			base..ctor();
		}

		internal bool UpToDate(string barcode, StreamStatus status)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			LevelCrate level = Level;
			object obj;
			if (level == null)
			{
				obj = null;
			}
			else
			{
				Barcode barcode2 = ((Scannable)level).Barcode;
				obj = ((barcode2 != null) ? barcode2.ID : null);
			}
			return (string?)obj == barcode && Status == status;
		}

		internal bool UpToDate(LevelCrate level, StreamStatus status)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			LevelCrate level2 = Level;
			object obj;
			if (level2 == null)
			{
				obj = null;
			}
			else
			{
				Barcode barcode = ((Scannable)level2).Barcode;
				obj = ((barcode != null) ? barcode.ID : null);
			}
			object obj2;
			if (level == null)
			{
				obj2 = null;
			}
			else
			{
				Barcode barcode2 = ((Scannable)level).Barcode;
				obj2 = ((barcode2 != null) ? barcode2.ID : null);
			}
			return (string?)obj == (string?)obj2 && Status == status;
		}
	}
	public class ScribanCrate
	{
		public enum CrateType
		{
			Spawnable,
			Avatar,
			Level,
			VFX
		}

		public CrateType Type { get; }

		public string Barcode { get; }

		public string Title { get; }

		public string Description { get; }

		public bool Redacted { get; }

		public bool Unlockable { get; }

		public ScriptArray<string> Tags { get; }

		public ScriptArray<ScribanBoneTag> BoneTags { get; }

		public ScribanPallet Pallet { get; }

		public ScribanCrate(Crate crate, ScribanPallet pallet = null)
		{
			Title = ((Scannable)crate).Title;
			Description = ((Scannable)crate).Description;
			Redacted = ((Scannable)crate).Redacted;
			Barcode = ((Scannable)crate).Barcode.ID;
			Unlockable = ((Scannable)crate).Unlockable;
			if (crate.Tags == null)
			{
				Tags = new ScriptArray<string>();
			}
			else
			{
				ScriptArray<string> val = new ScriptArray<string>();
				Enumerator<string> enumerator = crate.Tags.GetEnumerator();
				while (enumerator.MoveNext())
				{
					string current = enumerator.Current;
					val.Add(current);
				}
				Tags = val;
			}
			Pallet = pallet ?? new ScribanPallet(crate.Pallet);
			if (crate.BoneTags == null || crate.BoneTags.Tags == null)
			{
				BoneTags = new ScriptArray<ScribanBoneTag>();
			}
			else
			{
				List<ScribanBoneTag> scribanBoneTags = new List<ScribanBoneTag>();
				crate.BoneTags.Tags.ForEach(Action<BoneTagReference>.op_Implicit((Action<BoneTagReference>)delegate(BoneTagReference c)
				{
					scribanBoneTags.Add(new ScribanBoneTag(((DataCardReference<BoneTag>)(object)c).DataCard, Pallet));
				}));
				ScriptArray<ScribanBoneTag> val2 = new ScriptArray<ScribanBoneTag>();
				foreach (ScribanBoneTag item in scribanBoneTags)
				{
					val2.Add(item);
				}
				BoneTags = val2;
			}
			if (((MemberInfo)((Object)crate).GetIl2CppType()).Name == "SpawnableCrate")
			{
				Type = CrateType.Spawnable;
				return;
			}
			if (((MemberInfo)((Object)crate).GetIl2CppType()).Name == "AvatarCrate")
			{
				Type = CrateType.Avatar;
				return;
			}
			if (((MemberInfo)((Object)crate).GetIl2CppType()).Name == "LevelCrate")
			{
				Type = CrateType.Level;
				return;
			}
			if (((MemberInfo)((Object)crate).GetIl2CppType()).Name == "VFXCrate")
			{
				Type = CrateType.VFX;
				return;
			}
			throw new ArgumentOutOfRangeException("Crate type " + ((MemberInfo)((Object)crate).GetIl2CppType()).Name + " is not supported.");
		}
	}
	public class ScribanPallet
	{
		public string Title { get; }

		public string Description { get; }

		public string Author { get; }

		public string Barcode { get; }

		public string[] Tags { get; }

		public bool Redacted { get; }

		public bool Unlockable { get; }

		public string Version { get; }

		public string SDKVersion { get; }

		public ScriptArray<ScribanCrate> Crates { get; }

		public ScriptArray<ScribanChangeLog> ChangeLogs { get; }

		public ScriptArray<ScribanDataCard> DataCards { get; }

		public string[] Dependencies { get; }

		public ScribanPallet(Pallet pallet)
		{
			Barcode = ((Scannable)pallet).Barcode.ID;
			Unlockable = ((Scannable)pallet).Unlockable;
			Redacted = ((Scannable)pallet).Redacted;
			Title = ((Scannable)pallet).Title;
			if (pallet.Tags == null)
			{
				Tags = Array.Empty<string>();
			}
			else
			{
				Tags = Il2CppArrayBase<string>.op_Implicit(pallet.Tags.ToArray());
			}
			Version = pallet.Version;
			if (pallet.Crates == null)
			{
				Crates = new ScriptArray<ScribanCrate>();
			}
			else
			{
				List<ScribanCrate> scribanCrates = new List<ScribanCrate>();
				pallet.Crates.ForEach(Action<Crate>.op_Implicit((Action<Crate>)delegate(Crate c)
				{
					scribanCrates.Add(new ScribanCrate(c, this));
				}));
				ScriptArray<ScribanCrate> val = new ScriptArray<ScribanCrate>();
				foreach (ScribanCrate item in scribanCrates)
				{
					val.Add(item);
				}
				Crates = val;
			}
			Author = pallet.Author;
			Description = ((Scannable)pallet).Description;
			SDKVersion = pallet.SDKVersion;
			if (pallet.ChangeLogs == null)
			{
				ChangeLogs = new ScriptArray<ScribanChangeLog>();
			}
			else
			{
				List<ScribanChangeLog> list = new List<ScribanChangeLog>();
				Enumerator<ChangeLog> enumerator2 = pallet.ChangeLogs.GetEnumerator();
				while (enumerator2.MoveNext())
				{
					ChangeLog current2 = enumerator2.Current;
					list.Add(new ScribanChangeLog(current2));
				}
				ScriptArray<ScribanChangeLog> val2 = new ScriptArray<ScribanChangeLog>();
				foreach (ScribanChangeLog item2 in list)
				{
					val2.Add(item2);
				}
				ChangeLogs = val2;
			}
			if (pallet.DataCards == null)
			{
				DataCards = new ScriptArray<ScribanDataCard>();
			}
			else
			{
				List<ScribanDataCard> scribanDataCards = new List<ScribanDataCard>();
				pallet.DataCards.ForEach(Action<DataCard>.op_Implicit((Action<DataCard>)delegate(DataCard c)
				{
					scribanDataCards.Add(new ScribanDataCard(c, this));
				}));
				ScriptArray<ScribanDataCard> val3 = new ScriptArray<ScribanDataCard>();
				foreach (ScribanDataCard item3 in scribanDataCards)
				{
					val3.Add(item3);
				}
				DataCards = val3;
			}
			if (pallet.PalletDependencies == null)
			{
				Dependencies = Array.Empty<string>();
				return;
			}
			List<string> dependencies = new List<string>();
			pallet.PalletDependencies.ForEach(Action<PalletReference>.op_Implicit((Action<PalletReference>)delegate(PalletReference p)
			{
				dependencies.Add(((ScannableReference)p).Barcode.ID);
			}));
			Dependencies = dependencies.ToArray();
		}
	}
	public class ScribanChangeLog
	{
		public string Title { get; } = changelog.title;


		public string Version { get; } = changelog.version;


		public string Text { get; } = changelog.text;


		public ScribanChangeLog(ChangeLog changelog)
		{
		}
	}
	public class ScribanDataCard
	{
		public string Title { get; } = ((Scannable)dataCard).Title;


		public string Description { get; } = ((Scannable)dataCard).Description;


		public string Barcode { get; } = ((Scannable)dataCard).Barcode.ID;


		public bool Redacted { get; } = ((Scannable)dataCard).Redacted;


		public bool Unlockable { get; } = ((Scannable)dataCard).Unlockable;


		public ScribanPallet Pallet { get; } = pallet ?? new ScribanPallet(dataCard.Pallet);


		public ScribanDataCard(DataCard dataCard, ScribanPallet pallet = null)
		{
		}
	}
	public class ScribanBoneTag
	{
		public string Title { get; } = ((Scannable)boneTag).Title;


		public string Description { get; } = ((Scannable)boneTag).Description;


		public string Barcode { get; } = ((Scannable)boneTag).Barcode.ID;


		public bool Redacted { get; } = ((Scannable)boneTag).Redacted;


		public bool Unlockable { get; } = ((Scannable)boneTag).Unlockable;


		public ScribanPallet Pallet { get; } = pallet ?? new ScribanPallet(((DataCard)boneTag).Pallet);


		public ScribanBoneTag(BoneTag boneTag, ScribanPallet pallet = null)
		{
		}
	}
	public class ScribanAmmo : ScriptObject
	{
		public static int Light => GetAmmo("light");

		public static int Medium => GetAmmo("medium");

		public static int Heavy => GetAmmo("heavy");

		public static int GetAmmo(string type)
		{
			AmmoInventory instance = AmmoInventory.Instance;
			return (instance != null) ? instance._groupCounts[type] : 0;
		}
	}
	public class ScribanPlayer : ScriptObject
	{
		public static ScribanCrate Avatar
		{
			get
			{
				RigManager rigManager = Player.RigManager;
				object result;
				if (!((Object)(object)((rigManager == null) ? null : ((CrateReferenceT<AvatarCrate>)(object)rigManager.AvatarCrate)?.Crate) != (Object)null))
				{
					result = null;
				}
				else
				{
					RigManager rigManager2 = Player.RigManager;
					result = new ScribanCrate((Crate)(object)((rigManager2 == null) ? null : ((CrateReferenceT<AvatarCrate>)(object)rigManager2.AvatarCrate)?.Crate));
				}
				return (ScribanCrate)result;
			}
		}

		public static ScribanCrate LeftHand => ((Object)(object)Core.GetInHand((Handedness)1) != (Object)null) ? new ScribanCrate((Crate)(object)Core.GetInHand((Handedness)1)) : null;

		public static ScribanCrate RightHand => ((Object)(object)Core.GetInHand((Handedness)2) != (Object)null) ? new ScribanCrate((Crate)(object)Core.GetInHand((Handedness)2)) : null;

		public static float Health
		{
			get
			{
				RigManager rigManager = Player.RigManager;
				float? obj;
				if (rigManager == null)
				{
					obj = null;
				}
				else
				{
					Health health = rigManager.health;
					obj = ((health != null) ? new float?(health.curr_Health) : null);
				}
				float? num = obj;
				return num.GetValueOrDefault();
			}
		}

		public static float MaxHealth
		{
			get
			{
				RigManager rigManager = Player.RigManager;
				float? obj;
				if (rigManager == null)
				{
					obj = null;
				}
				else
				{
					Health health = rigManager.health;
					obj = ((health != null) ? new float?(health.max_Health) : null);
				}
				float? num = obj;
				return num.GetValueOrDefault();
			}
		}

		public static float HealthPercentange => Health / MaxHealth * 100f;
	}
	public class ScribanGame : ScriptObject
	{
		public static ScribanCrate Level
		{
			get
			{
				StreamSession session = SceneStreamer.Session;
				object result;
				if (!((Object)(object)((session != null) ? session.Level : null) != (Object)null))
				{
					result = null;
				}
				else
				{
					StreamSession session2 = SceneStreamer.Session;
					result = new ScribanCrate((Crate)(object)((session2 != null) ? session2.Level : null));
				}
				return (ScribanCrate)result;
			}
		}

		public static string LevelName => Core.CleanLevelName();

		public static string MLVersion => AppDomain.CurrentDomain?.GetAssemblies()?.FirstOrDefault((Assembly x) => x.GetName().Name == "MelonLoader")?.GetName()?.Version?.ToString() ?? "N/A";

		public static int FPS => Fps.FramesPerSecond;

		public static string OperatingSystem => SystemInfo.operatingSystem;

		public static int ModsCount
		{
			get
			{
				int result = 0;
				if (AssetWarehouse.ready && AssetWarehouse.Instance != null)
				{
					result = AssetWarehouse.Instance.PalletCount() - AssetWarehouse.Instance.gamePallets.Count;
				}
				return result;
			}
		}

		public static int CodeModsCount => MelonTypeBase<MelonMod>.RegisteredMelons.Count;
	}
	public class ScribanUtils : ScriptObject
	{
		public static ScribanPallet GetPallet(string barcode)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Expected O, but got Unknown
			Pallet pallet = default(Pallet);
			if (AssetWarehouse.Instance.TryGetPallet(new Barcode(barcode), ref pallet))
			{
				return new ScribanPallet(pallet);
			}
			return null;
		}

		public static string CleanString(string str)
		{
			return Core.RemoveUnityRichText(str);
		}
	}
	public class Thunderstore
	{
		public readonly string UserAgent;

		private Package _fetchedPackage;

		private bool _isLatestVersion;

		private string _currentVersion;

		public bool IsV1Deprecated { get; set; }

		public Thunderstore(string userAgent)
		{
			UserAgent = userAgent;
		}

		public Thunderstore(string userAgent, bool isV1Deprecated)
			: this(userAgent)
		{
			IsV1Deprecated = isV1Deprecated;
		}

		public Thunderstore()
		{
			Assembly executingAssembly = Assembly.GetExecutingAssembly();
			if (executingAssembly != null)
			{
				AssemblyName name = executingAssembly.GetName();
				if (name != null)
				{
					UserAgent = $"{name.Name} / {name.Version} C# Application";
				}
			}
		}

		public Thunderstore(bool isV1Deprecated)
		{
			IsV1Deprecated = isV1Deprecated;
			Assembly executingAssembly = Assembly.GetExecutingAssembly();
			if (executingAssembly != null)
			{
				AssemblyName name = executingAssembly.GetName();
				if (name != null)
				{
					UserAgent = $"{name.Name} / {name.Version}";
				}
			}
		}

		public void BL_FetchPackage(string name, string author, string currentVersion, Instance logger = null)
		{
			if (_fetchedPackage != null)
			{
				return;
			}
			_currentVersion = currentVersion;
			try
			{
				_fetchedPackage = GetPackage(author, name);
				if (_fetchedPackage == null && logger != null)
				{
					logger.Warning("Could not find Thunderstore package for " + name);
				}
				if (string.IsNullOrWhiteSpace(_fetchedPackage.Latest?.Version) && logger != null)
				{
					logger.Warning("Latest version could not be found or the version is empty");
				}
				_isLatestVersion = _fetchedPackage.IsLatestVersion(currentVersion);
				if (!_isLatestVersion)
				{
					if (logger != null)
					{
						logger.Warning($"A new version of {name} is available: v{_fetchedPackage.Latest.Version} while the current is v{currentVersion}. It is recommended that you update");
					}
				}
				else if (SemVersion.Parse(currentVersion, false) == _fetchedPackage.Latest.SemanticVersion)
				{
					if (logger != null)
					{
						logger.Msg($"Latest version of {name} is installed! (v{currentVersion})");
					}
				}
				else if (logger != null)
				{
					logger.Msg($"Beta release of {name} is installed (v{_fetchedPackage.Latest.Version} is newest, v{currentVersion} is installed)");
				}
			}
			catch (ThunderstorePackageNotFoundException)
			{
				if (logger != null)
				{
					logger.Warning("Could not find Thunderstore package for " + name);
				}
			}
			catch (Exception ex2)
			{
				if (logger != null)
				{
					logger.Error("An unexpected error has occurred while trying to check if " + name + " is the latest version", ex2);
				}
			}
		}

		public void BL_CreateMenuLabel(Page page, bool createBlankSpace = true)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			if (_fetchedPackage != null)
			{
				if (createBlankSpace)
				{
					((Element)page.CreateFunction("", Color.white, (Action)null)).SetProperty((ElementProperties)1);
				}
				((Element)page.CreateFunction("Current Version: v" + _currentVersion + ((_isLatestVersion || _fetchedPackage == null) ? string.Empty : "<br><color=#00FF00>(Update available!)</color>"), Color.white, (Action)null)).SetProperty((ElementProperties)1);
			}
		}

		public void BL_SendNotification()
		{
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//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_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Expected O, but got Unknown
			if (_fetchedPackage != null && !_isLatestVersion)
			{
				NotificationText message = default(NotificationText);
				((NotificationText)(ref message))..ctor($"There is a new version of {_fetchedPackage.Name}. Go to Thunderstore and download the latest version which is <color=#00FF00>v{_fetchedPackage.Latest.Version}</color>", Color.white, true);
				Notifier.Send(new Notification
				{
					Title = NotificationText.op_Implicit("Update!"),
					Message = message,
					PopupLength = 5f,
					ShowTitleOnPopup = true,
					Type = (NotificationType)1
				});
			}
		}

		public Package GetPackage(string @namespace, string name, string version = null)
		{
			Package package = SendRequest<Package>($"https://thunderstore.io/api/experimental/package/{@namespace}/{name}/{version ?? string.Empty}");
			if (!IsV1Deprecated && package != null)
			{
				V1PackageMetrics packageMetrics = GetPackageMetrics(@namespace, name);
				if (packageMetrics != null)
				{
					package.TotalDownloads = packageMetrics.Downloads;
					package.RatingScore = packageMetrics.RatingScore;
				}
			}
			return package;
		}

		private static bool IsTaskGood<T>(Task<T> task) where T : class
		{
			return task != null && task.IsCompletedSuccessfully && task.Result != null;
		}

		public T SendRequest<T>(string url)
		{
			HttpClientHandler handler = new HttpClientHandler
			{
				ClientCertificateOptions = ClientCertificateOption.Manual,
				ServerCertificateCustomValidationCallback = (HttpRequestMessage _, X509Certificate2? _, X509Chain? _, SslPolicyErrors _) => true
			};
			HttpClient httpClient = new HttpClient(handler);
			httpClient.DefaultRequestHeaders.Add("User-Agent", UserAgent);
			httpClient.DefaultRequestHeaders.Add("Accept", "application/json");
			Task<HttpResponseMessage> async = httpClient.GetAsync(url);
			async.Wait();
			HttpResponseMessage httpResponseMessage = async?.Result;
			if (IsTaskGood(async))
			{
				if (!httpResponseMessage.IsSuccessStatusCode)
				{
					HandleHttpError(httpResponseMessage);
					return default(T);
				}
				Task<string> task = httpResponseMessage.Content.ReadAsStringAsync();
				task.Wait();
				string text = task?.Result;
				if (IsTaskGood(task))
				{
					return JsonConvert.DeserializeObject<T>(text);
				}
			}
			return default(T);
		}

		private static void HandleHttpError(HttpResponseMessage result)
		{
			if (IsThunderstoreError(result, out var details))
			{
				if (IsPackageNotFound(result, details))
				{
					throw new ThunderstorePackageNotFoundException("Thunderstore could not find the package");
				}
				throw new ThunderstoreErrorException("Thunderstore API has thrown an unexpected error!", result);
			}
			result.EnsureSuccessStatusCode();
		}

		public V1PackageMetrics GetPackageMetrics(string @namespace, string name)
		{
			if (IsV1Deprecated)
			{
				return null;
			}
			return SendRequest<V1PackageMetrics>($"https://thunderstore.io/api/v1/package-metrics/{@namespace}/{name}/");
		}

		public bool IsLatestVersion(string @namespace, string name, string currentVersion)
		{
			SemVersion currentVersion2 = default(SemVersion);
			if (SemVersion.TryParse(currentVersion, ref currentVersion2, false))
			{
				return IsLatestVersion(@namespace, name, currentVersion2);
			}
			return false;
		}

		public bool IsLatestVersion(string @namespace, string name, Version currentVersion)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Expected O, but got Unknown
			return IsLatestVersion(@namespace, name, new SemVersion(currentVersion));
		}

		public bool IsLatestVersion(string @namespace, string name, SemVersion currentVersion)
		{
			if (!IsV1Deprecated)
			{
				return GetPackageMetrics(@namespace, name)?.IsLatestVersion(currentVersion) ?? false;
			}
			return GetPackage(@namespace, name)?.IsLatestVersion(currentVersion) ?? false;
		}

		private static bool IsPackageNotFound(HttpResponseMessage response, string details = "")
		{
			if (response.StatusCode != HttpStatusCode.NotFound)
			{
				return false;
			}
			if (details != null && details.Length == 0)
			{
				details = GetDetails(response);
			}
			return string.Equals(details, "Not found.", StringComparison.OrdinalIgnoreCase);
		}

		private static bool IsThunderstoreError(HttpResponseMessage response, out string details)
		{
			details = GetDetails(response);
			return !string.IsNullOrWhiteSpace(details);
		}

		private static string GetDetails(HttpResponseMessage response)
		{
			if (response.IsSuccessStatusCode)
			{
				return null;
			}
			Task<string> task = response.Content.ReadAsStringAsync();
			task.Wait();
			string result = task.Result;
			if (string.IsNullOrWhiteSpace(result))
			{
				return null;
			}
			ThunderstoreErrorResponse thunderstoreErrorResponse;
			try
			{
				thunderstoreErrorResponse = JsonConvert.DeserializeObject<ThunderstoreErrorResponse>(result);
			}
			catch (JsonException)
			{
				return null;
			}
			if (!string.IsNullOrWhiteSpace(thunderstoreErrorResponse?.Details))
			{
				return thunderstoreErrorResponse.Details;
			}
			return null;
		}
	}
	public class Package
	{
		[JsonProperty("namespace")]
		public string Namespace { get; internal set; }

		[JsonProperty("name")]
		public string Name { get; internal set; }

		[JsonProperty("full_name")]
		public string FullName { get; internal set; }

		[JsonProperty("owner")]
		public string Owner { get; internal set; }

		[JsonProperty("package_url")]
		public string PackageURL { get; internal set; }

		[JsonProperty("date_created")]
		public DateTime CreatedAt { get; internal set; }

		[JsonProperty("date_updated")]
		public DateTime UpdatedAt { get; internal set; }

		[JsonProperty("rating_score")]
		public int RatingScore { get; internal set; }

		[JsonProperty("is_pinned")]
		public bool IsPinned { get; internal set; }

		[JsonProperty("is_deprecated")]
		public bool IsDeprecated { get; internal set; }

		[JsonProperty("total_downloads")]
		public int TotalDownloads { get; internal set; }

		[JsonProperty("latest")]
		public PackageVersion Latest { get; internal set; }

		[JsonProperty("community_listings")]
		public PackageListing[] CommunityListings { get; internal set; }

		public bool IsLatestVersion(string current)
		{
			if (string.IsNullOrWhiteSpace(current))
			{
				return false;
			}
			if (Latest == null || Latest.SemanticVersion == (SemVersion)null)
			{
				return false;
			}
			SemVersion val = default(SemVersion);
			if (SemVersion.TryParse(current, ref val, false))
			{
				return val >= Latest.SemanticVersion;
			}
			return false;
		}

		public bool IsLatestVersion(SemVersion current)
		{
			if (current == (SemVersion)null)
			{
				return false;
			}
			if (Latest == null || Latest.SemanticVersion == (SemVersion)null)
			{
				return false;
			}
			return current >= Latest.SemanticVersion;
		}

		public bool IsLatestVersion(Version current)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Expected O, but got Unknown
			if (current == null)
			{
				return false;
			}
			if (Latest == null || Latest.SemanticVersion == (SemVersion)null)
			{
				return false;
			}
			return new SemVersion(current) >= Latest.SemanticVersion;
		}
	}
	public class PackageVersion
	{
		[JsonProperty("namespace")]
		public string Namespace { get; internal set; }

		[JsonProperty("name")]
		public string Name { get; internal set; }

		[JsonProperty("version_number")]
		public string Version
		{
			get
			{
				return ((object)SemanticVersion).ToString();
			}
			internal set
			{
				SemanticVersion = SemVersion.Parse(value, false);
			}
		}

		[JsonIgnore]
		public SemVersion SemanticVersion { get; internal set; }

		[JsonProperty("full_name")]
		public string FullName { get; internal set; }

		[JsonProperty("description")]
		public string Description { get; internal set; }

		[JsonProperty("icon")]
		public string Icon { get; internal set; }

		[JsonProperty("dependencies")]
		public List<string> Dependencies { get; internal set; }

		[JsonProperty("download_url")]
		public string DownloadURL { get; internal set; }

		[JsonProperty("date_created")]
		public DateTime CreatedAt { get; internal set; }

		[JsonProperty("downloads")]
		public int Downloads { get; internal set; }

		[JsonProperty("website_url")]
		public string WebsiteURL { get; internal set; }

		[JsonProperty("is_active")]
		public bool IsActive { get; internal set; }
	}
	public class PackageListing
	{
		public enum ReviewStatus
		{
			UNREVIEWED,
			APPROVED,
			REJECTED
		}

		[JsonProperty("has_nsfw_content")]
		public bool HasNSFWContent { get; internal set; }

		[JsonProperty("categories")]
		public List<string> Categories { get; internal set; }

		[JsonProperty("community")]
		public string Community { get; internal set; }

		[JsonProperty("review_status")]
		public string ReviewStatusString
		{
			get
			{
				return ReviewStatusValue.ToString();
			}
			internal set
			{
				if (value == null)
				{
					throw new ArgumentNullException("value");
				}
				if (string.Equals(value, "unreviewed", StringComparison.OrdinalIgnoreCase))
				{
					ReviewStatusValue = ReviewStatus.UNREVIEWED;
				}
				else if (string.Equals(value, "approved", StringComparison.OrdinalIgnoreCase))
				{
					ReviewStatusValue = ReviewStatus.APPROVED;
				}
				else if (string.Equals(value, "rejected", StringComparison.OrdinalIgnoreCase))
				{
					ReviewStatusValue = ReviewStatus.REJECTED;
				}
			}
		}

		[JsonIgnore]
		public ReviewStatus ReviewStatusValue { get; internal set; }
	}
	public class V1PackageMetrics
	{
		[JsonProperty("downloads")]
		public int Downloads { get; internal set; }

		[JsonProperty("rating_score")]
		public int RatingScore { get; internal set; }

		[JsonProperty("latest_version")]
		public string LatestVersion
		{
			get
			{
				return ((object)LatestSemanticVersion).ToString();
			}
			internal set
			{
				LatestSemanticVersion = SemVersion.Parse(value, false);
			}
		}

		[JsonIgnore]
		public SemVersion LatestSemanticVersion { get; internal set; }

		public bool IsLatestVersion(string current)
		{
			if (string.IsNullOrWhiteSpace(current))
			{
				return false;
			}
			if (LatestSemanticVersion == (SemVersion)null)
			{
				return false;
			}
			SemVersion val = default(SemVersion);
			if (SemVersion.TryParse(current, ref val, false))
			{
				return val >= LatestSemanticVersion;
			}
			return false;
		}

		public bool IsLatestVersion(SemVersion current)
		{
			if (current == (SemVersion)null)
			{
				return false;
			}
			if (LatestSemanticVersion == (SemVersion)null)
			{
				return false;
			}
			return current >= LatestSemanticVersion;
		}

		public bool IsLatestVersion(Version current)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Expected O, but got Unknown
			if (current == null)
			{
				return false;
			}
			if (LatestSemanticVersion == (SemVersion)null)
			{
				return false;
			}
			return new SemVersion(current) >= LatestSemanticVersion;
		}
	}
	public class ThunderstoreErrorResponse
	{
		[JsonProperty("detail")]
		public string Details { get; internal set; }
	}
	public class ThunderstoreErrorException : Exception
	{
		public string Details { get; }

		public HttpStatusCode HttpStatusCode { get; }

		public ThunderstoreErrorException()
		{
		}

		public ThunderstoreErrorException(string message)
			: base(message)
		{
		}

		public ThunderstoreErrorException(string message, Exception innerException)
			: base(message, innerException)
		{
		}

		public ThunderstoreErrorException(string message, string details, HttpStatusCode httpStatusCode, Exception innerException)
			: base(message, innerException)
		{
			Details = details;
			HttpStatusCode = httpStatusCode;
		}

		public ThunderstoreErrorException(string message, HttpResponseMessage response)
			: base(message)
		{
			if (response.IsSuccessStatusCode)
			{
				return;
			}
			HttpStatusCode = response.StatusCode;
			Task<string> task = response.Content.ReadAsStringAsync();
			task.Wait();
			string result = task.Result;
			if (string.IsNullOrWhiteSpace(result))
			{
				Details = string.Empty;
				return;
			}
			ThunderstoreErrorResponse thunderstoreErrorResponse;
			try
			{
				thunderstoreErrorResponse = JsonConvert.DeserializeObject<ThunderstoreErrorResponse>(result);
			}
			catch (JsonException)
			{
				Details = string.Empty;
				return;
			}
			if (thunderstoreErrorResponse != null)
			{
				Details = thunderstoreErrorResponse.Details;
			}
		}
	}
	public class ThunderstorePackageNotFoundException : ThunderstoreErrorException
	{
		public string Namespace { get; }

		public string Name { get; }

		public string Version { get; }

		public ThunderstorePackageNotFoundException(string message, string @namespace, string name, string details, HttpStatusCode httpStatusCode, Exception innerException)
			: base(message, details, httpStatusCode, innerException)
		{
			Namespace = @namespace;
			Name = name;
		}

		public ThunderstorePackageNotFoundException(string message, string @namespace, string name, string version, string details, HttpStatusCode httpStatusCode, Exception innerException)
			: base(message, details, httpStatusCode, innerException)
		{
			Namespace = @namespace;
			Name = name;
			Version = version;
		}

		public ThunderstorePackageNotFoundException(string message, string @namespace, string name, HttpResponseMessage response)
			: base(message, response)
		{
			Namespace = @namespace;
			Name = name;
		}

		public ThunderstorePackageNotFoundException(string message, string @namespace, string name, string version, HttpResponseMessage response)
			: base(message, response)
		{
			Namespace = @namespace;
			Name = name;
			Version = version;
		}

		public ThunderstorePackageNotFoundException()
		{
		}

		public ThunderstorePackageNotFoundException(string message)
			: base(message)
		{
		}

		public ThunderstorePackageNotFoundException(string message, Exception innerException)
			: base(message, innerException)
		{
		}

		public ThunderstorePackageNotFoundException(string message, string details, HttpStatusCode httpStatusCode, Exception innerException)
			: base(message, details, httpStatusCode, innerException)
		{
		}

		public ThunderstorePackageNotFoundException(string message, HttpResponseMessage response)
			: base(message, response)
		{
		}
	}
}
namespace LabPresence.Plugins
{
	public static class Overwrites
	{
		public static OverwritesType OnLevelLoaded { get; } = new OverwritesType();


		public static OverwritesType OnLevelLoading { get; } = new OverwritesType();


		public static OverwritesType OnLevelUnloaded { get; } = new OverwritesType();


		public static OverwritesType OnAssetWarehouseLoaded { get; } = new OverwritesType();


		public static OverwritesType OnPreGame { get; } = new OverwritesType();


		public static OverwritesType<JoinMessage> OnJoin { get; } = new OverwritesType<JoinMessage>();


		public static OverwritesType<JoinRequestMessage> OnJoinRequested { get; } = new OverwritesType<JoinRequestMessage>();


		public static OverwritesType<SpectateMessage> OnSpectate { get; } = new OverwritesType<SpectateMessage>();

	}
	public class OverwritesType<T> where T : new()
	{
		private readonly List<Overwrite<T>> _Overwrites = new List<Overwrite<T>>();

		public IReadOnlyCollection<Overwrite<T>> Overwrites => _Overwrites.AsReadOnly();

		internal Action<T> Default { get; private set; }

		internal void SetDefault(Action<T> action)
		{
			Default = action;
		}

		public void RegisterOverwrite(Overwrite<T> overwrite)
		{
			if (IsRegistered(overwrite))
			{
				throw new ArgumentException("An overwrite with the same ID is already registered!");
			}
			_Overwrites.Add(overwrite);
		}

		public void RegisterOverwrite(Func<T, bool> callback, out Guid ID, int priority = 0)
		{
			Overwrite<T> overwrite = new Overwrite<T>(callback, priority);
			RegisterOverwrite(overwrite);
			ID = overwrite.ID;
		}

		public bool RemoveOverwrite(Guid ID)
		{
			return _Overwrites.RemoveAll((Overwrite<T> x) => x.ID == ID) > 0;
		}

		public bool RemoveOverwrite(Overwrite<T> overwrite)
		{
			return RemoveOverwrite(overwrite.ID);
		}

		public bool IsRegistered(Guid ID)
		{
			return Overwrites.Any((Overwrite<T> x) => x.ID == ID);
		}

		public bool IsRegistered(Overwrite<T> overwrite)
		{
			return IsRegistered(overwrite.ID);
		}

		public void Run(T arg)
		{
			if (_Overwrites.Count == 0)
			{
				Default?.Invoke(arg);
				return;
			}
			List<Overwrite<T>> list = Overwrites.OrderByDescending((Overwrite<T> x) => x.Priority).ToList();
			for (int i = 0; i < list.Count; i++)
			{
				if (list.Count == 0)
				{
					break;
				}
				Overwrite<T> overwrite = list[0];
				if (overwrite == null)
				{
					list.RemoveAt(0);
					continue;
				}
				Func<T, bool> callback = overwrite.Callback;
				if (callback == null || !callback(arg))
				{
					list.RemoveAt(0);
					continue;
				}
				return;
			}
			Default?.Invoke(arg);
		}
	}
	public class Overwrite<T> where T : new()
	{
		public int Priority { get; set; }

		public Guid ID { get; set; }

		public Func<T, bool> Callback { get; set; }

		public Overwrite(Guid id, Func<T, bool> callback, int priority = 0)
		{
			ID = id;
			Priority = priority;
			Callback = callback;
		}

		public Overwrite(Func<T, bool> callback, int priority = 0)
		{
			ID = Guid.NewGuid();
			Priority = priority;
			Callback = callback;
		}
	}
	public class OverwritesType
	{
		private readonly List<Overwrite> _Overwrites = new List<Overwrite>();

		public IReadOnlyCollection<Overwrite> Overwrites => _Overwrites.AsReadOnly();

		internal Action Default { get; private set; }

		internal void SetDefault(Action action)
		{
			Default = action;
		}

		public void RegisterOverwrite(Overwrite overwrite)
		{
			if (IsRegistered(overwrite))
			{
				throw new ArgumentException("An overwrite with the same ID is already registered!");
			}
			_Overwrites.Add(overwrite);
		}

		public void RegisterOverwrite(Func<bool> callback, out Guid ID, int priority = 0)
		{
			Overwrite overwrite = new Overwrite(callback, priority);
			RegisterOverwrite(overwrite);
			ID = overwrite.ID;
		}

		public bool RemoveOverwrite(Guid ID)
		{
			return _Overwrites.RemoveAll((Overwrite x) => x.ID == ID) > 0;
		}

		public bool RemoveOverwrite(Overwrite overwrite)
		{
			return RemoveOverwrite(overwrite.ID);
		}

		public bool IsRegistered(Guid ID)
		{
			return Overwrites.Any((Overwrite x) => x.ID == ID);
		}

		public bool IsRegistered(Overwrite overwrite)
		{
			return IsRegistered(overwrite.ID);
		}

		public void Run()
		{
			if (_Overwrites.Count == 0)
			{
				Default?.Invoke();
				return;
			}
			List<Overwrite> list = Overwrites.OrderByDescending((Overwrite x) => x.Priority).ToList();
			for (int i = 0; i < list.Count; i++)
			{
				if (list.Count == 0)
				{
					break;
				}
				Overwrite overwrite = list[0];
				if (overwrite == null)
				{
					list.RemoveAt(0);
					continue;
				}
				Func<bool> callback = overwrite.Callback;
				if (callback == null || !callback())
				{
					list.RemoveAt(0);
					continue;
				}
				return;
			}
			Default?.Invoke();
		}
	}
	public class Overwrite
	{
		public int Priority { get; set; }

		public Guid ID { get; set; }

		public Func<bool> Callback { get; set; }

		public Overwrite(Guid id, Func<bool> callback, int priority = 0)
		{
			ID = id;
			Priority = priority;
			Callback = callback;
		}

		public Overwrite(Func<bool> callback, int priority = 0)
		{
			ID = Guid.NewGuid();
			Priority = priority;
			Callback = callback;
		}
	}
	public interface IPlugin
	{
		string Name { get; }

		SemVersion Version { get; }

		string Author { get; }

		bool CreatesMenu => false;

		Color MenuColor => Color.white;

		Logger Logger { get; internal set; }

		Page MenuPage { get; internal set; }

		void Internal_Init();

		internal void Internal_PopulateMenu()
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: 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)
			if (MenuPage == null && CreatesMenu)
			{
				MenuPage = MenuManager.PluginsPage.CreatePage(Name, MenuColor, 0, true);
				((Element)MenuPage.CreateFunction($"Version: v{Version}", Color.white, (Action)null)).SetProperty((ElementProperties)1);
				((Element)MenuPage.CreateFunction("Author: " + Author, Color.white, (Action)null)).SetProperty((ElementProperties)1);
				((Element)MenuPage.CreateFunction(string.Empty, Color.white, (Action)null)).SetProperty((ElementProperties)1);
				PopulateMenu(MenuPage);
			}
		}

		void PopulateMenu(Page page)
		{
		}
	}
	public abstract class Plugin : IPlugin
	{
		public abstract string Name { get; }

		public abstract SemVersion Version { get; }

		public abstract string Author { get; }

		public virtual bool CreatesMenu => false;

		public virtual Color MenuColor => Color.white;

		public MelonPreferences_Category Category { get; private set; }

		public Logger Logger { get; set; }

		public Page MenuPage { get; set; }

		public void Internal_Init()
		{
			Logger = new Logger(Core.Logger, Name);
			Category = MelonPreferences.CreateCategory("LabPresence_" + Name + "_Config");
			Category.SetFilePath(Path.Combine(MelonEnvironment.UserDataDirectory, "LabPresence", Name.ToLower() + ".cfg"));
			Category.SaveToFile(false);
			Init();
		}

		public virtual void Init()
		{
		}

		public virtual void PopulateMenu(Page page)
		{
		}
	}
	public abstract class Plugin<ConfigT> : IPlugin where ConfigT : new()
	{
		public abstract string Name { get; }

		public abstract SemVersion Version { get; }

		public abstract string Author { get; }

		public Logger Logger { get; set; }

		public Page MenuPage { get; set; }

		public virtual bool CreatesMenu => false;

		public virtual Color MenuColor => Color.white;

		public MelonPreferences_ReflectiveCategory Category { get; private set; }

		public void Internal_Init()
		{
			Logger = new Logger(Core.Logger, Name);
			Category = MelonPreferences.CreateCategory<ConfigT>("LabPresence_" + Name + "_Config", (string)null);
			Category.SetFilePath(Path.Combine(MelonEnvironment.UserDataDirectory, "LabPresence", Name.ToLower() + ".cfg"), true, true);
			Category.SaveToFile(false);
			Init();
		}

		public virtual void Init()
		{
		}

		public virtual void PopulateMenu(Page page)
		{
		}

		public ConfigT GetConfig()
		{
			return Category.GetValue<ConfigT>();
		}
	}
	public static class PluginsManager
	{
		private static readonly List<IPlugin> _Plugins = new List<IPlugin>();

		public static IReadOnlyCollection<IPlugin> Plugins => _Plugins.AsReadOnly();

		public static void Register(Type plugin)
		{
			IPlugin pluginFromType = GetPluginFromType(plugin);
			if (IsRegistered(plugin))
			{
				throw new ArgumentException("A plugin with the same name is already registered!");
			}
			Core.Logger.Msg($"Plugin '{pluginFromType.Name}' v{pluginFromType.Version} by {pluginFromType.Author} has been registered!");
			_Plugins.Add(pluginFromType);
			pluginFromType.Internal_Init();
			if (MenuManager.IsInitialized)
			{
				pluginFromType.Internal_PopulateMenu();
			}
		}

		public static void Register<PluginT>() where PluginT : IPlugin
		{
			Register(typeof(PluginT));
		}

		public static void Unregister(string name)
		{
			List<IPlugin> list = new List<IPlugin>(_Plugins);
			list.ForEach(delegate(IPlugin x)
			{
				if (!(x.Name != name))
				{
					if (x.MenuPage != null)
					{
						Menu.DestroyPage(x.MenuPage);
					}
					_Plugins.Remove(x);
				}
			});
		}

		public static void Unregister(Type plugin)
		{
			Unregister(GetPluginFromType(plugin).Name);
		}

		public static void Unregister<PluginT>() where PluginT : IPlugin
		{
			Unregister(GetPluginFromType(typeof(PluginT)).Name);
		}

		public static bool IsRegistered(string name)
		{
			return Plugins.Any((IPlugin x) => x.Name == name);
		}

		public static bool IsRegistered(Type plugin)
		{
			return IsRegistered(GetPluginFromType(plugin).Name);
		}

		public static bool IsRegistered<PluginT>() where PluginT : IPlugin
		{
			return IsRegistered(GetPluginFromType(typeof(PluginT)).Name);
		}

		private static IPlugin GetPluginFromType(Type plugin)
		{
			if (!plugin.IsTypeOf<IPlugin>())
			{
				throw new ArgumentException("Type must be a sub class of IPlugin!", "plugin");
			}
			return (IPlugin)Activator.CreateInstance(plugin);
		}

		public static bool IsTypeOf<T>(this Type type)
		{
			return typeof(T).IsAssignableFrom(type);
		}
	}
}
namespace LabPresence.Plugins.Default
{
	internal class FusionPlugin : Plugin<FusionConfig>
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static ServerEvent <0>__OnDisconnect;
		}

		[CompilerGenerated]
		private sealed class <AfterLevelLoaded>d__24 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public Action callback;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <AfterLevelLoaded>d__24(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0045: Unknown result type (might be due to invalid IL or missing references)
				//IL_004b: Invalid comparison between Unknown and I4
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					break;
				case 1:
					<>1__state = -1;
					break;
				}
				StreamSession session = SceneStreamer.Session;
				if (session == null || (int)session.Status != 2)
				{
					<>2__current = null;
					<>1__state = 1;
					return true;
				}
				callback?.Invoke();
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		private float ElapsedSeconds = 0f;

		private bool turnedOff = false;

		public override string Name => "Fusion";

		public override SemVersion Version => new SemVersion(1, 0, 0, "", "");

		public override string Author => "HAHOOS";

		public override bool CreatesMenu => true;

		public override Color MenuColor => Color.cyan;

		internal static FusionPlugin Instance { get; set; }

		public override void Init()
		{
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Expected O, but got Unknown
			Instance = this;
			if (!Fusion.HasFusion)
			{
				base.Logger.Error("LabFusion is not installed, so FusionPlugin will not be set up!");
				return;
			}
			PlaceholderManager.RegisterPlaceholder("labfusion", delegate
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_000b: Unknown result type (might be due to invalid IL or missing references)
				//IL_001d: Expected O, but got Unknown
				ScriptObject val = new ScriptObject((IEqualityComparer<string>)StringComparer.OrdinalIgnoreCase);
				val.Add("fusion", (object)new ScribanFusion());
				return val;
			});
			Overwrites.OnLevelLoaded.RegisterOverwrite(OnLevelLoaded, out var ID, 100);
			Overwrites.OnLevelLoaded.RegisterOverwrite(OnLevelLoading, out ID, 100);
			Overwrites.OnJoin.RegisterOverwrite(Join, out ID, 100);
			Overwrites.OnJoinRequested.RegisterOverwrite(JoinRequested, out ID, 100);
			((MelonEventBase<LemonAction>)(object)MelonEvents.OnUpdate).Subscribe(new LemonAction(Update), 0, false);
			HasFusion();
		}

		public override void PopulateMenu(Page page)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			((Element)page.CreateBool("Override Time", Color.yellow, GetConfig().OverrideTimeToLobby, (Action<bool>)delegate(bool val)
			{
				GetConfig().OverrideTimeToLobby = val;
				base.Category.SaveToFile(false);
				Fusion.SetTimestamp(setLobbyLaunch: false);
			})).SetTooltip("If the time mode will be set to 'Level', when in a fusion lobby it will override the time to display how long you are in the lobby instead of the level");
			((Element)page.CreateBool("Show Join Request Pop Up", Color.cyan, GetConfig().ShowJoinRequestPopUp, (Action<bool>)delegate(bool val)
			{
				GetConfig().ShowJoinRequestPopUp = val;
				base.Category.SaveToFile(false);
			})).SetTooltip("If true, a notification will be shown when someone requests to join your server");
			((Element)page.CreateBool("Allow Players To Invite", Color.white, GetConfig().AllowPlayersToInvite, (Action<bool>)delegate(bool val)
			{
				GetConfig().AllowPlayersToInvite = val;
				base.Category.SaveToFile(false);
			})).SetTooltip("If true, when hosting a private server, players will be able to let others join the server through Discord");
			((Element)page.CreateBool("Show Custom Gamemode Tooltips", MenuManager.FromRGB(191, 255, 0), GetConfig().ShowCustomGamemodeToolTips, (Action<bool>)delegate(bool val)
			{
				GetConfig().ShowCustomGamemodeToolTips = val;
				base.Category.SaveToFile(false);
			})).SetTooltip("If true, gamemodes that support custom tooltips will display custom text on the small icon. Disabling this option will cause the tooltip to only show the name of the gamemode");
			((Element)page.CreateBool("Joins", Color.cyan, GetConfig().Joins, (Action<bool>)delegate(bool val)
			{
				GetConfig().Joins = val;
				base.Category.SaveToFile(false);
			})).SetTooltip("If true, the rich presence will allow discord users to join your server when available, otherwise if false, the join button will never be shown");
		}

		private void HasFusion()
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			Fusion.Init(base.Logger);
			object obj = <>O.<0>__OnDisconnect;
			if (obj == null)
			{
				ServerEvent val = OnDisconnect;
				<>O.<0>__OnDisconnect = val;
				obj = (object)val;
			}
			MultiplayerHooking.OnDisconnected += (ServerEvent)obj;
		}

		private static void OnDisconnect()
		{
			if (RichPresenceManager.OverrideTimestamp?.Origin == "fusion")
			{
				RichPresenceManager.ResetOverrideTimestamp();
			}
			Overwrites.OnLevelLoaded.Run();
		}

		private bool JoinRequested(JoinRequestMessage message)
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: 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: Expected O, but got Unknown
			try
			{
				base.Logger.Info("Join requested");
				MelonCoroutines.Start(AfterLevelLoaded(after));
			}
			catch (Exception value)
			{
				Notifier.Send(new Notification
				{
					Title = NotificationText.op_Implicit("Failure | LabPresence"),
					Message = NotificationText.op_Implicit("An unexpected error has occurred while handling join request, check the console or logs for more details"),
					Type = (NotificationType)2,
					PopupLength = 5f,
					ShowTitleOnPopup = true
				});
				base.Logger.Error($"An unexpected error has occurred while handling join request, exception:\n{value}");
				return false;
			}
			return true;
			void after()
			{
				Fusion.JoinRequest(message);
			}
		}

		private bool OnLevelLoaded()
		{
			if (Fusion.IsConnected)
			{
				RichPresenceManager.TrySetRichPresence(GetConfig().LevelLoaded, (ActivityType)0, GetParty(), GetSecrets());
			}
			return Fusion.IsConnected;
		}

		private bool OnLevelLoading()
		{
			if (Fusion.IsConnected)
			{
				RichPresenceManager.TrySetRichPresence(GetConfig().LevelLoading, (ActivityType)0, GetParty(), GetSecrets());
			}
			return Fusion.IsConnected;
		}

		private bool Join(JoinMessage e)
		{
			if (!Fusion.HasFusion)
			{
				return false;
			}
			try
			{
				base.Logger.Info("Received Join Request");
				string text = RichPresenceManager.Decrypt(e.Secret);
				string[] array = text.Split("|");
				if (array.Length <= 1)
				{
					throw new ArgumentException("Secret provided to join the lobby did not include all of the necessary info");
				}
				if (array.Length > 2)
				{
					throw new ArgumentException("Secret provided to join the lobby was invalid, the name of the network layer or code to the server may have contained the '|' character used to separate network layer & code, causing unexpected results");
				}
				string layer = array[0];
				string code = array[1];
				MelonCoroutines.Start(AfterLevelLoaded(join));
				void join()
				{
					//IL_003c: Unknown result type (might be due to invalid IL or missing references)
					//IL_0041: Unknown result type (might be due to invalid IL or missing references)
					//IL_0047: Unknown result type (might be due to invalid IL or missing references)
					//IL_004c: Unknown result type (might be due to invalid IL or missing references)
					//IL_0051: Unknown result type (might be due to invalid IL or missing references)
					//IL_0057: Unknown result type (might be due to invalid IL or missing references)
					//IL_005c: Unknown result type (might be due to invalid IL or missing references)
					//IL_0061: Unknown result type (might be due to invalid IL or missing references)
					//IL_006c: Unknown result type (might be due to invalid IL or missing references)
					//IL_0073: Unknown result type (might be due to invalid IL or missing references)
					//IL_0075: Unknown result type (might be due to invalid IL or missing references)
					//IL_007f: Expected O, but got Unknown
					base.Logger.Info("Attempting to join with the following code: " + code);
					if (code != Fusion.GetLobbyCode())
					{
						Notifier.Send(new Notification
						{
							Title = NotificationText.op_Implicit("LabPresence"),
							Message = NotificationText.op_Implicit("Attempting to join the target lobby, this might take a few seconds..."),
							PopupLength = 4f,
							ShowTitleOnPopup = true,
							Type = (NotificationType)0
						});
						if (Fusion.EnsureNetworkLayer(layer))
						{
							Fusion.JoinByCode(code);
						}
						else
						{
							Fusion.ErrorNotif("Failed to ensure network layer, check the console/logs for errors. If none are present, it's likely the user is playing on a network layer that you do not have.", 5f);
						}
					}
					else
					{
						base.Logger.Error("Player is already in the lobby");
						Fusion.ErrorNotif("Could not join, because you are already in the lobby!", 5f);
					}
				}
			}
			catch (Exception value)
			{
				Fusion.ErrorNotif("An unexpected error has occurred while trying to join the lobby, check the console or logs for more details", 5f);
				base.Logger.Error($"An unexpected error has occurred while trying to join the lobby, exception:\n{value}");
				return false;
			}
			return true;
		}

		private static Party GetParty()
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Expected O, but got Unknown
			if (!Fusion.IsConnected)
			{
				return null;
			}
			ulong lobbyID = Fusion.GetLobbyID();
			if (lobbyID == 0L || lobbyID.ToString().Length < 2)
			{
				return null;
			}
			return new Party
			{
				ID = Fusion.GetLobbyID().ToString(),
				Privacy = (PrivacySetting)((Fusion.GetPrivacy() == Fusion.ServerPrivacy.Public) ? 1 : 0),
				Max = Fusion.GetPlayerCount().max,
				Size = Fusion.GetPlayerCount().current
			};
		}

		private static Secrets GetSecrets()
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Invalid comparison between Unknown and I4
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Expected O, but got Unknown
			if (!Fusion.IsConnected)
			{
				return null;
			}
			if ((int)SceneStreamer.Session.Status == 1)
			{
				return null;
			}
			var (num, num2) = Fusion.GetPlayerCount();
			if (num >= num2)
			{
				return null;
			}
			switch (Fusion.GetPrivacy())
			{
			case Fusion.ServerPrivacy.Locked:
				return null;
			default:
				if (!Fusion.IsAllowedToInvite())
				{
					return null;
				}
				break;
			case Fusion.ServerPrivacy.Public:
			case Fusion.ServerPrivacy.Friends_Only:
				break;
			}
			string currentNetworkLayerTitle = Fusion.GetCurrentNetworkLayerTitle();
			if (string.IsNullOrWhiteSpace(currentNetworkLayerTitle))
			{
				return null;
			}
			string lobbyCode = Fusion.GetLobbyCode();
			if (string.IsNullOrWhiteSpace(lobbyCode))
			{
				return null;
			}
			string joinSecret = RichPresenceManager.Encrypt(currentNetworkLayerTitle + "|" + lobbyCode);
			return new Secrets
			{
				JoinSecret = joinSecret
			};
		}

		[IteratorStateMachine(typeof(<AfterLevelLoaded>d__24))]
		private static IEnumerator AfterLevelLoaded(Action callback)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <AfterLevelLoaded>d__24(0)
			{
				callback = callback
			};
		}

		private void Update()
		{
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Invalid comparison between Unknown and I4
			if (base.Category != null && GetConfig() != null)
			{
				Fusion.EnsureMetaDataSync();
			}
			ElapsedSeconds += Time.deltaTime;
			if (!(ElapsedSeconds >= 5f))
			{
				return;
			}
			ElapsedSeconds = 0f;
			if (Fusion.IsConnected)
			{
				StreamSession session = SceneStreamer.Session;
				if (session != null && (int)session.Status == 2)
				{
					RichPresenceManager.AutoUpdate = false;
					turnedOff = true;
					var (key, tooltip) = Fusion.GetGamemodeRPC();
					RichPresenceManager.TrySetRichPresence(RichPresenceManager.CurrentConfig, (ActivityType)0, GetParty(), GetSecrets(), null, new Asset(key, tooltip));
					return;
				}
			}
			if (!RichPresenceManager.AutoUpdate && turnedOff)
			{
				RichPresenceManager.AutoUpdate = true;
				turnedOff = false;
			}
		}
	}
	public static class Fusion
	{
		public enum ServerPrivacy
		{
			Unknown = -1,
			Public,
			Private,
			Friends_Only,
			Locked
		}

		[CompilerGenerated]
		private static class <>O
		{
			public static ServerEvent <0>__Update;

			public static ServerEvent <1>__OnLobby;

			public static Func<string> <2>__HideAndSeekTooltip;

			public static Func<string> <3>__DeathmatchTooltip;

			public static Func<string> <4>__TeamDeathmatchTooltip;

			public static Func<string> <5>__EntangledTooltip;

			public static Func<string> <6>__SmashBonesTooltip;

			public static Func<string> <7>__JuggernautTooltip;
		}

		private const string AllowKey = "LabPresence.AllowInvites";

		private static Logger Logger;

		internal static DateTimeOffset LobbyLaunch { get; set; }

		public static bool HasFusion => MelonBase.FindMelon("LabFusion", "Lakatrazz") != null;

		public static bool IsConnected
		{
			get
			{
				if (HasFusion)
				{
					return Internal_IsConnected();
				}
				return false;
			}
		}

		public static bool IsGamemodeStarted
		{
			get
			{
				if (!IsConnected)
				{
					return false;
				}
				return Internal_IsGamemodeStarted();
			}
		}

		private static bool Internal_IsGamemodeStarted()
		{
			return GamemodeManager.IsGamemodeStarted;
		}

		internal static bool Internal_IsConnected()
		{
			return NetworkInfo.HasServer;
		}

		public static string GetLobbyName()
		{
			if (!IsConnected)
			{
				return "N/A";
			}
			return Internal_GetLobbyName();
		}

		public static string GetPermissionLevel()
		{
			if (!IsConnected)
			{
				return "N/A";
			}
			return Internal_GetPermissionLevel();
		}

		private static string Internal_GetPermissionLevel()
		{
			return LocalPlayer.Metadata.PermissionLevel.GetValue();
		}

		internal static string Internal_GetLobbyName()
		{
			LobbyInfo lobbyInfo = LobbyInfoManager.LobbyInfo;
			string text = ((lobbyInfo != null) ? lobbyInfo.LobbyName : null);
			if (lobbyInfo == null)
			{
				return "N/A";
			}
			return string.IsNullOrWhiteSpace(text) ? (lobbyInfo.LobbyHostName + "'s lobby") : text;
		}

		public static string GetHost()
		{
			if (!IsConnected)
			{
				return "N/A";
			}
			return Internal_GetHost();
		}

		internal static string Internal_GetHost()
		{
			LobbyInfo lobbyInfo = LobbyInfoManager.LobbyInfo;
			string text = ((lobbyInfo != null) ? lobbyInfo.LobbyHostName : null);
			if (lobbyInfo == null)
			{
				return "N/A";
			}
			return string.IsNullOrWhiteSpace(text) ? "N/A" : text;
		}

		public static (int current, int max) GetPlayerCount()
		{
			if (!IsConnected)
			{
				return (-1, -1);
			}
			return Internal_GetPlayerCount();
		}

		private static (int current, int max) Internal_GetPlayerCount()
		{
			LobbyInfo lobbyInfo = LobbyInfoManager.LobbyInfo;
			if (lobbyInfo == null)
			{
				return (-1, -1);
			}
			int playerCount = lobbyInfo.PlayerCount;
			int maxPlayers = lobbyInfo.MaxPlayers;
			return (playerCount, maxPlayers);
		}

		public static ServerPrivacy GetPrivacy()
		{
			if (!IsConnected)
			{
				return ServerPrivacy.Unknown;
			}
			return Internal_GetPrivacy();
		}

		private static ServerPrivacy Internal_GetPrivacy()
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected I4, but got Unknown
			LobbyInfo lobbyInfo = LobbyInfoManager.LobbyInfo;
			if (lobbyInfo == null)
			{
				return ServerPrivacy.Unknown;
			}
			ServerPrivacy privacy = lobbyInfo.Privacy;
			return (ServerPrivacy)privacy;
		}

		public static ulong GetLobbyID()
		{
			if (!IsConnected)
			{
				return 0uL;
			}
			return Internal_GetLobbyID();
		}

		private static ulong Internal_GetLobbyID()
		{
			LobbyInfo lobbyInfo = LobbyInfoManager.LobbyInfo;
			if (lobbyInfo == null)
			{
				return 0uL;
			}
			return lobbyInfo.LobbyID;
		}

		public static string GetLobbyCode()
		{
			if (!IsConnected)
			{
				return string.Empty;
			}
			return Internal_GetLobbyCode();
		}

		private static string Internal_GetLobbyCode()
		{
			LobbyInfo lobbyInfo = LobbyInfoManager.LobbyInfo;
			if (lobbyInfo == null)
			{
				return string.Empty;
			}
			return lobbyInfo.LobbyCode;
		}

		public static (string username, string displayName) GetCurrentPlayer()
		{
			if (!IsConnected)
			{
				return (null, null);
			}
			return Internal_GetCurrentPlayer();
		}

		private static (string username, string displayName) Internal_GetCurrentPlayer()
		{
			string username = LocalPlayer.Username;
			string item = default(string);
			if (MetadataHelper.TryGetDisplayName(PlayerIDManager.LocalID, ref item))
			{
				item = username;
			}
			return (username, item);
		}

		public static string GetCurrentNetworkLayerTitle()
		{
			if (!IsConnected)
			{
				return null;
			}
			return Internal_GetCurrentNetworkLayerTitle();
		}

		private static string Internal_GetCurrentNetworkLayerTitle()
		{
			NetworkLayer layer = NetworkLayerManager.Layer;
			return (layer != null) ? layer.Title : null;
		}

		public static void EnsureMetaDataSync()
		{
			if (IsConnected)
			{
				Internal_EnsureMetadataSync();
			}
		}

		internal static void Internal_EnsureMetadataSync()
		{
			string value = default(string);
			bool result;
			if (!NetworkInfo.IsHost)
			{
				LocalPlayer.Metadata.Metadata.TryRemoveMetadata("LabPresence.AllowInvites");
			}
			else if (!LocalPlayer.Metadata.Metadata.TryGetMetadata("LabPresence.AllowInvites", ref value) || !bool.TryParse(value, out result) || result != FusionPlugin.Instance.GetConfig().AllowPlayersToInvite)
			{
				LocalPlayer.Metadata.Metadata.TrySetMetadata("LabPresence.AllowInvites", FusionPlugin.Instance.GetConfig().AllowPlayersToInvite.ToString());
			}
		}

		public static bool IsAllowedToInvite()
		{
			if (!IsConnected)
			{
				return false;
			}
			return Internal_IsAllowedToInvite();
		}

		private static bool Internal_IsAllowedToInvite()
		{
			if (!FusionPlugin.Instance.GetConfig().Joins)
			{
				return false;
			}
			if (NetworkInfo.IsHost)
			{
				return true;
			}
			if (PlayerIDManager.GetHostID() == null)
			{
				return true;
			}
			NetworkPlayer val = default(NetworkPlayer);
			if (!NetworkPlayerManager.TryGetPlayer(PlayerID.op_Implicit(PlayerIDManager.GetHostID()), ref val))
			{
				return true;
			}
			if (val == null)
			{
				return true;
			}
			PlayerID playerID = val.PlayerID;
			object value;
			if (playerID == null)
			{
				value = null;
			}
			else
			{
				PlayerMetadata metadata = playerID.Metadata;
				if (metadata == null)
				{
					value = null;
				}
				else
				{
					NetworkMetadata metadata2 = metadata.Metadata;
					value = ((metadata2 != null) ? metadata2.GetMetadata("LabPresence.AllowInvites") : null);
				}
			}
			if (string.IsNullOrWhiteSpace((string?)value))
			{
				return true;
			}
			PlayerID playerID2 = val.PlayerID;
			object obj;
			if (playerID2 == null)
			{
				obj = null;
			}
			else
			{
				PlayerMetadata metadata3 = playerID2.Metadata;
				if (metadata3 == null)
				{
					obj = null;
				}
				else
				{
					NetworkMetadata metadata4 = metadata3.Metadata;
					obj = ((metadata4 != null) ? metadata4.GetMetadata("LabPresence.AllowInvites") : null);
				}
			}
			return (string?)obj == bool.TrueString;
		}

		public static bool EnsureNetworkLayer(string title)
		{
			if (!HasFusion)
			{
				return false;
			}
			return Internal_EnsureNetworkLayer(title);
		}

		private static bool Internal_EnsureNetworkLayer(string title)
		{
			if (!NetworkLayer.LayerLookup.TryGetValue(title, out var value))
			{
				Logger.Error("Could find network layer '" + title + "'");
				return false;
			}
			try
			{
				if (NetworkLayerManager.LoggedIn && NetworkLayerManager.Layer == value)
				{
					return true;
				}
				if (NetworkLayerManager.LoggedIn)
				{
					NetworkLayerManager.LogOut();
				}
				NetworkLayerManager.LogIn(value);
			}
			catch (Exception value2)
			{
				Logger.Error($"An unexpected error has occurred while ensuring fusion is on the right network layer, exception:\n{value2}");
				return false;
			}
			return true;
		}

		public static void JoinByCode(string code)
		{
			if (HasFusion && !string.IsNullOrWhiteSpace(code))
			{
				Internal_JoinByCode(code);
			}
		}

		private static void Internal_JoinByCode(string code)
		{
			if (string.Equals(NetworkHelper.GetServerCode(), code, StringComparison.OrdinalIgnoreCase))
			{
				ErrorNotif("You are already in the lobby!");
				return;
			}
			if (NetworkLayerManager.Layer.Matchmaker != null)
			{
				NetworkLayerManager.Layer.Matchmaker.RequestLobbiesByCode(code, (Action<MatchmakerCallbackInfo>)delegate(MatchmakerCallbackInfo x)
				{
					//IL_0000: Unknown result type (might be due to invalid IL or missing references)
					AttemptJoin(x, code);
				});
				return;
			}
			if (IsConnected)
			{
				NetworkHelper.Disconnect("Joining another lobby");
			}
			NetworkHelper.JoinServerByCode(code);
		}

		private static void AttemptJoin(MatchmakerCallbackInfo x, string code)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Invalid comparison between Unknown and I4
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Invalid comparison between Unknown and I4
			LobbyInfo val = x.Lobbies.FirstOrDefault();
			LobbyInfo targetLobby = ((LobbyMetadataInfo)(ref val.Metadata)).LobbyInfo;
			if (targetLobby == null || targetLobby.LobbyCode == null)
			{
				Core.Logger.Error("The lobby was not found");
				ErrorNotif("The lobby you wanted to join was not found!");
				return;
			}
			if ((int)targetLobby.Privacy == 2)
			{
				PlayerList playerList = targetLobby.PlayerList;
				PlayerInfo val2 = ((playerList == null) ? null : playerList.Players?.FirstOrDefault((Func<PlayerInfo, bool>)((PlayerInfo x) => x.Username == targetLobby.LobbyHostName)));
				if (val2 == null)
				{
					Core.Logger.Warning("Could not find host, unable to verify if you can join the lobby (Privacy: Friends Only)");
				}
				else if (!NetworkLayerManager.Layer.IsFriend(val2.PlatformID))
				{
					Core.Logger.Error("The lobby is friends only and you are not friends with the host, cannot join");
					ErrorNotif("Cannot join the lobby, because it is friends only and you are not friends with the host!");
					return;
				}
			}
			if ((int)targetLobby.Privacy == 3)
			{
				Core.Logger.Error("The lobby is locked, cannot join");
				ErrorNotif("Cannot join the lobby, because it is locked");
				return;
			}
			if (IsConnected)
			{
				NetworkHelper.Disconnect("Joining another lobby");
			}
			NetworkHelper.JoinServerByCode(code);
		}

		internal static void ErrorNotif(string msg, float length = 3.5f)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Expected O, but got Unknown
			Notifier.Send(new Notification
			{
				Title = NotificationText.op_Implicit("Error | FLB"),
				Message = NotificationText.op_Implicit(msg),
				PopupLength = length,
				Type = (NotificationType)2
			});
		}

		internal static void JoinRequest(JoinRequestMessage message)
		{
			if (IsConnected && message != null)
			{
				Internal_JoinRequest(message);
			}
		}

		private static void Internal_JoinRequest(JoinRequestMessage message)
		{
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Expected O, but got Unknown
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: 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_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Expected O, but got Unknown
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			if (message != null)
			{
				FusionConfig config = FusionPlugin.Instance.GetConfig();
				if (config != null && config.ShowJoinRequestPopUp)
				{
					Texture2D customIcon = (Texture2D)(((object)RichPresenceManager.GetAvatar(message.User, (AvatarSize)512)) ?? ((object)new Texture2D(1, 1)));
					Notifier.Send(new Notification
					{
						Title = NotificationText.op_Implicit("Join Request"),
						Message = NotificationText.op_Implicit(message.User.DisplayName + " (@" + message.User.Username + ") wants to join you! Go to the LabFusion menu to accept or deny the request"),
						PopupLength = 5f,
						ShowTitleOnPopup = true,
						Type = (NotificationType)4,
						CustomIcon = customIcon
					});
				}
				Notifier.Send(new Notification
				{
					Title = NotificationText.op_Implicit("Join Request"),
					Message = NotificationText.op_Implicit(message.User.DisplayName + " (@" + message.User.Username + ") wants to join you!"),
					PopupLength = 5f,
					SaveToMenu = true,
					ShowPopup = false,
					Type = (NotificationType)0,
					OnAccepted = delegate
					{
						Core.Client.Respond(message, true);
					},
					OnDeclined = delegate
					{
						Core.Client.Respond(message, false);
					}
				});
			}
		}

		internal static void Init(Logger logger)
		{
			if (HasFusion)
			{
				Internal_Init(logger);
			}
		}

		private static void Internal_Init(Logger logger)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Expected O, but got Unknown
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Expected O, but got Unknown
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Expected O, but got Unknown
			Logger = logger;
			object obj = <>O.<0>__Update;