Decompiled source of BLOODLINK v0.114.0

BepInEx/plugins/LiteNetLib.dll

Decompiled 13 hours ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading;
using LiteNetLib.Layers;
using LiteNetLib.Utils;
using Microsoft.CodeAnalysis;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Ruslan Pyrch")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright 2026 Ruslan Pyrch")]
[assembly: AssemblyDescription("Lite reliable UDP library for .NET, Mono, and .NET Core")]
[assembly: AssemblyFileVersion("2.1.4")]
[assembly: AssemblyInformationalVersion("1.0.0+4d3de1e93abaead30199bf572f4a3363f854e14b")]
[assembly: AssemblyProduct("LiteNetLib")]
[assembly: AssemblyTitle("LiteNetLib")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/RevenantX/LiteNetLib")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("2.1.4.0")]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class IsUnmanagedAttribute : Attribute
	{
	}
}
namespace LiteNetLib
{
	internal abstract class BaseChannel
	{
		protected readonly LiteNetPeer Peer;

		protected readonly Queue<NetPacket> OutgoingQueue = new Queue<NetPacket>(64);

		private int _isAddedToPeerChannelSendQueue;

		public int PacketsInQueue => OutgoingQueue.Count;

		protected BaseChannel(LiteNetPeer peer)
		{
			Peer = peer;
		}

		public void AddToQueue(NetPacket packet)
		{
			lock (OutgoingQueue)
			{
				OutgoingQueue.Enqueue(packet);
			}
			AddToPeerChannelSendQueue();
		}

		protected void AddToPeerChannelSendQueue()
		{
			if (Interlocked.CompareExchange(ref _isAddedToPeerChannelSendQueue, 1, 0) == 0)
			{
				Peer.AddToReliableChannelSendQueue(this);
			}
		}

		public bool SendAndCheckQueue()
		{
			bool num = SendNextPackets();
			if (!num)
			{
				Interlocked.Exchange(ref _isAddedToPeerChannelSendQueue, 0);
			}
			return num;
		}

		public abstract bool SendNextPackets();

		public abstract bool ProcessPacket(NetPacket packet);
	}
	internal enum ConnectionRequestResult
	{
		None,
		Accept,
		Reject,
		RejectForce
	}
	public class LiteConnectionRequest
	{
		private readonly LiteNetManager _listener;

		private int _used;

		internal NetConnectRequestPacket InternalPacket;

		public readonly IPEndPoint RemoteEndPoint;

		public NetDataReader Data => InternalPacket.Data;

		internal ConnectionRequestResult Result { get; private set; }

		internal void UpdateRequest(NetConnectRequestPacket connectRequest)
		{
			if (connectRequest.ConnectionTime >= InternalPacket.ConnectionTime && (connectRequest.ConnectionTime != InternalPacket.ConnectionTime || connectRequest.ConnectionNumber != InternalPacket.ConnectionNumber))
			{
				InternalPacket = connectRequest;
			}
		}

		private bool TryActivate()
		{
			return Interlocked.CompareExchange(ref _used, 1, 0) == 0;
		}

		internal LiteConnectionRequest(IPEndPoint remoteEndPoint, NetConnectRequestPacket requestPacket, LiteNetManager listener)
		{
			InternalPacket = requestPacket;
			RemoteEndPoint = remoteEndPoint;
			_listener = listener;
		}

		public LiteNetPeer AcceptIfKey(string key)
		{
			if (!TryActivate())
			{
				return null;
			}
			try
			{
				if (Data.GetString() == key)
				{
					Result = ConnectionRequestResult.Accept;
				}
			}
			catch
			{
				NetDebug.WriteError("[AC] Invalid incoming data");
			}
			if (Result == ConnectionRequestResult.Accept)
			{
				return _listener.OnConnectionSolved(this, null, 0, 0);
			}
			Result = ConnectionRequestResult.Reject;
			_listener.OnConnectionSolved(this, null, 0, 0);
			return null;
		}

		public LiteNetPeer Accept()
		{
			if (!TryActivate())
			{
				return null;
			}
			Result = ConnectionRequestResult.Accept;
			return _listener.OnConnectionSolved(this, null, 0, 0);
		}

		public void Reject(byte[] rejectData, int start, int length, bool force)
		{
			if (TryActivate())
			{
				Result = (force ? ConnectionRequestResult.RejectForce : ConnectionRequestResult.Reject);
				_listener.OnConnectionSolved(this, rejectData, start, length);
			}
		}

		public void Reject(byte[] rejectData, int start, int length)
		{
			Reject(rejectData, start, length, force: false);
		}

		public void RejectForce(byte[] rejectData, int start, int length)
		{
			Reject(rejectData, start, length, force: true);
		}

		public void RejectForce()
		{
			Reject(null, 0, 0, force: true);
		}

		public void RejectForce(byte[] rejectData)
		{
			Reject(rejectData, 0, rejectData.Length, force: true);
		}

		public void RejectForce(NetDataWriter rejectData)
		{
			Reject(rejectData.Data, 0, rejectData.Length, force: true);
		}

		public void Reject()
		{
			Reject(null, 0, 0, force: false);
		}

		public void Reject(byte[] rejectData)
		{
			Reject(rejectData, 0, rejectData.Length, force: false);
		}

		public void Reject(NetDataWriter rejectData)
		{
			Reject(rejectData.Data, 0, rejectData.Length, force: false);
		}
	}
	public class ConnectionRequest : LiteConnectionRequest
	{
		internal ConnectionRequest(IPEndPoint remoteEndPoint, NetConnectRequestPacket requestPacket, LiteNetManager listener)
			: base(remoteEndPoint, requestPacket, listener)
		{
		}

		public new NetPeer AcceptIfKey(string key)
		{
			return (NetPeer)base.AcceptIfKey(key);
		}

		public new NetPeer Accept()
		{
			return (NetPeer)base.Accept();
		}
	}
	public enum UnconnectedMessageType
	{
		BasicMessage,
		Broadcast
	}
	public enum DisconnectReason
	{
		ConnectionFailed,
		Timeout,
		HostUnreachable,
		NetworkUnreachable,
		RemoteConnectionClose,
		DisconnectPeerCalled,
		ConnectionRejected,
		InvalidProtocol,
		UnknownHost,
		Reconnect,
		PeerToPeerConnection,
		PeerNotFound
	}
	public struct DisconnectInfo
	{
		public DisconnectReason Reason;

		public SocketError SocketErrorCode;

		public NetPacketReader AdditionalData;
	}
	public interface INetEventListener
	{
		void OnPeerConnected(NetPeer peer);

		void OnPeerDisconnected(NetPeer peer, DisconnectInfo disconnectInfo);

		void OnNetworkError(IPEndPoint endPoint, SocketError socketError);

		void OnNetworkReceive(NetPeer peer, NetPacketReader reader, byte channelNumber, DeliveryMethod deliveryMethod);

		void OnNetworkReceiveUnconnected(IPEndPoint remoteEndPoint, NetPacketReader reader, UnconnectedMessageType messageType);

		void OnNetworkLatencyUpdate(NetPeer peer, int latency);

		void OnConnectionRequest(ConnectionRequest request);

		void OnMessageDelivered(NetPeer peer, object userData)
		{
		}

		void OnNtpResponse(NtpPacket packet)
		{
		}

		void OnPeerAddressChanged(NetPeer peer, IPEndPoint previousAddress)
		{
		}
	}
	public interface ILiteNetEventListener
	{
		void OnPeerConnected(LiteNetPeer peer);

		void OnPeerDisconnected(LiteNetPeer peer, DisconnectInfo disconnectInfo);

		void OnNetworkError(IPEndPoint endPoint, SocketError socketError)
		{
		}

		void OnNetworkReceive(LiteNetPeer peer, NetPacketReader reader, DeliveryMethod deliveryMethod);

		void OnNetworkReceiveUnconnected(IPEndPoint remoteEndPoint, NetPacketReader reader, UnconnectedMessageType messageType)
		{
		}

		void OnNetworkLatencyUpdate(LiteNetPeer peer, int latency)
		{
		}

		void OnConnectionRequest(LiteConnectionRequest request);

		void OnPeerAddressChanged(LiteNetPeer peer, IPEndPoint previousAddress)
		{
		}

		void OnMessageDelivered(LiteNetPeer peer, object userData)
		{
		}
	}
	public class EventBasedNetListener : INetEventListener
	{
		public delegate void OnPeerConnected(NetPeer peer);

		public delegate void OnPeerDisconnected(NetPeer peer, DisconnectInfo disconnectInfo);

		public delegate void OnNetworkError(IPEndPoint endPoint, SocketError socketError);

		public delegate void OnNetworkReceive(NetPeer peer, NetPacketReader reader, byte channel, DeliveryMethod deliveryMethod);

		public delegate void OnNetworkReceiveUnconnected(IPEndPoint remoteEndPoint, NetPacketReader reader, UnconnectedMessageType messageType);

		public delegate void OnNetworkLatencyUpdate(NetPeer peer, int latency);

		public delegate void OnConnectionRequest(ConnectionRequest request);

		public delegate void OnDeliveryEvent(NetPeer peer, object userData);

		public delegate void OnNtpResponseEvent(NtpPacket packet);

		public delegate void OnPeerAddressChangedEvent(NetPeer peer, IPEndPoint previousAddress);

		public event OnPeerConnected PeerConnectedEvent;

		public event OnPeerDisconnected PeerDisconnectedEvent;

		public event OnNetworkError NetworkErrorEvent;

		public event OnNetworkReceive NetworkReceiveEvent;

		public event OnNetworkReceiveUnconnected NetworkReceiveUnconnectedEvent;

		public event OnNetworkLatencyUpdate NetworkLatencyUpdateEvent;

		public event OnConnectionRequest ConnectionRequestEvent;

		public event OnDeliveryEvent DeliveryEvent;

		public event OnNtpResponseEvent NtpResponseEvent;

		public event OnPeerAddressChangedEvent PeerAddressChangedEvent;

		public void ClearPeerConnectedEvent()
		{
			this.PeerConnectedEvent = null;
		}

		public void ClearPeerDisconnectedEvent()
		{
			this.PeerDisconnectedEvent = null;
		}

		public void ClearNetworkErrorEvent()
		{
			this.NetworkErrorEvent = null;
		}

		public void ClearNetworkReceiveEvent()
		{
			this.NetworkReceiveEvent = null;
		}

		public void ClearNetworkReceiveUnconnectedEvent()
		{
			this.NetworkReceiveUnconnectedEvent = null;
		}

		public void ClearNetworkLatencyUpdateEvent()
		{
			this.NetworkLatencyUpdateEvent = null;
		}

		public void ClearConnectionRequestEvent()
		{
			this.ConnectionRequestEvent = null;
		}

		public void ClearDeliveryEvent()
		{
			this.DeliveryEvent = null;
		}

		public void ClearNtpResponseEvent()
		{
			this.NtpResponseEvent = null;
		}

		public void ClearPeerAddressChangedEvent()
		{
			this.PeerAddressChangedEvent = null;
		}

		void INetEventListener.OnPeerConnected(NetPeer peer)
		{
			this.PeerConnectedEvent?.Invoke(peer);
		}

		void INetEventListener.OnPeerDisconnected(NetPeer peer, DisconnectInfo disconnectInfo)
		{
			this.PeerDisconnectedEvent?.Invoke(peer, disconnectInfo);
		}

		void INetEventListener.OnNetworkError(IPEndPoint endPoint, SocketError socketErrorCode)
		{
			this.NetworkErrorEvent?.Invoke(endPoint, socketErrorCode);
		}

		void INetEventListener.OnNetworkReceive(NetPeer peer, NetPacketReader reader, byte channelNumber, DeliveryMethod deliveryMethod)
		{
			this.NetworkReceiveEvent?.Invoke(peer, reader, channelNumber, deliveryMethod);
		}

		void INetEventListener.OnNetworkReceiveUnconnected(IPEndPoint remoteEndPoint, NetPacketReader reader, UnconnectedMessageType messageType)
		{
			this.NetworkReceiveUnconnectedEvent?.Invoke(remoteEndPoint, reader, messageType);
		}

		void INetEventListener.OnNetworkLatencyUpdate(NetPeer peer, int latency)
		{
			this.NetworkLatencyUpdateEvent?.Invoke(peer, latency);
		}

		void INetEventListener.OnConnectionRequest(ConnectionRequest request)
		{
			this.ConnectionRequestEvent?.Invoke(request);
		}

		void INetEventListener.OnMessageDelivered(NetPeer peer, object userData)
		{
			this.DeliveryEvent?.Invoke(peer, userData);
		}

		void INetEventListener.OnNtpResponse(NtpPacket packet)
		{
			this.NtpResponseEvent?.Invoke(packet);
		}

		void INetEventListener.OnPeerAddressChanged(NetPeer peer, IPEndPoint previousAddress)
		{
			this.PeerAddressChangedEvent?.Invoke(peer, previousAddress);
		}
	}
	public class EventBasedLiteNetListener : ILiteNetEventListener
	{
		public delegate void OnPeerConnected(LiteNetPeer peer);

		public delegate void OnPeerDisconnected(LiteNetPeer peer, DisconnectInfo disconnectInfo);

		public delegate void OnNetworkError(IPEndPoint endPoint, SocketError socketError);

		public delegate void OnNetworkReceive(LiteNetPeer peer, NetPacketReader reader, DeliveryMethod deliveryMethod);

		public delegate void OnNetworkReceiveUnconnected(IPEndPoint remoteEndPoint, NetPacketReader reader, UnconnectedMessageType messageType);

		public delegate void OnNetworkLatencyUpdate(LiteNetPeer peer, int latency);

		public delegate void OnConnectionRequest(LiteConnectionRequest request);

		public delegate void OnDeliveryEvent(LiteNetPeer peer, object userData);

		public delegate void OnPeerAddressChangedEvent(LiteNetPeer peer, IPEndPoint previousAddress);

		public event OnPeerConnected PeerConnectedEvent;

		public event OnPeerDisconnected PeerDisconnectedEvent;

		public event OnNetworkError NetworkErrorEvent;

		public event OnNetworkReceive NetworkReceiveEvent;

		public event OnNetworkReceiveUnconnected NetworkReceiveUnconnectedEvent;

		public event OnNetworkLatencyUpdate NetworkLatencyUpdateEvent;

		public event OnConnectionRequest ConnectionRequestEvent;

		public event OnDeliveryEvent DeliveryEvent;

		public event OnPeerAddressChangedEvent PeerAddressChangedEvent;

		public void ClearPeerConnectedEvent()
		{
			this.PeerConnectedEvent = null;
		}

		public void ClearPeerDisconnectedEvent()
		{
			this.PeerDisconnectedEvent = null;
		}

		public void ClearNetworkErrorEvent()
		{
			this.NetworkErrorEvent = null;
		}

		public void ClearNetworkReceiveEvent()
		{
			this.NetworkReceiveEvent = null;
		}

		public void ClearNetworkReceiveUnconnectedEvent()
		{
			this.NetworkReceiveUnconnectedEvent = null;
		}

		public void ClearNetworkLatencyUpdateEvent()
		{
			this.NetworkLatencyUpdateEvent = null;
		}

		public void ClearConnectionRequestEvent()
		{
			this.ConnectionRequestEvent = null;
		}

		public void ClearDeliveryEvent()
		{
			this.DeliveryEvent = null;
		}

		public void ClearPeerAddressChangedEvent()
		{
			this.PeerAddressChangedEvent = null;
		}

		void ILiteNetEventListener.OnPeerConnected(LiteNetPeer peer)
		{
			this.PeerConnectedEvent?.Invoke(peer);
		}

		void ILiteNetEventListener.OnPeerDisconnected(LiteNetPeer peer, DisconnectInfo disconnectInfo)
		{
			this.PeerDisconnectedEvent?.Invoke(peer, disconnectInfo);
		}

		void ILiteNetEventListener.OnNetworkError(IPEndPoint endPoint, SocketError socketErrorCode)
		{
			this.NetworkErrorEvent?.Invoke(endPoint, socketErrorCode);
		}

		void ILiteNetEventListener.OnNetworkReceive(LiteNetPeer peer, NetPacketReader reader, DeliveryMethod deliveryMethod)
		{
			this.NetworkReceiveEvent?.Invoke(peer, reader, deliveryMethod);
		}

		void ILiteNetEventListener.OnNetworkReceiveUnconnected(IPEndPoint remoteEndPoint, NetPacketReader reader, UnconnectedMessageType messageType)
		{
			this.NetworkReceiveUnconnectedEvent?.Invoke(remoteEndPoint, reader, messageType);
		}

		void ILiteNetEventListener.OnNetworkLatencyUpdate(LiteNetPeer peer, int latency)
		{
			this.NetworkLatencyUpdateEvent?.Invoke(peer, latency);
		}

		void ILiteNetEventListener.OnConnectionRequest(LiteConnectionRequest request)
		{
			this.ConnectionRequestEvent?.Invoke(request);
		}

		void ILiteNetEventListener.OnMessageDelivered(LiteNetPeer peer, object userData)
		{
			this.DeliveryEvent?.Invoke(peer, userData);
		}

		void ILiteNetEventListener.OnPeerAddressChanged(LiteNetPeer peer, IPEndPoint previousAddress)
		{
			this.PeerAddressChangedEvent?.Invoke(peer, previousAddress);
		}
	}
	public sealed class NetConnectRequestPacket
	{
		public const int HeaderSize = 18;

		public readonly long ConnectionTime;

		public byte ConnectionNumber;

		public readonly byte[] TargetAddress;

		public readonly NetDataReader Data;

		public readonly int PeerId;

		private NetConnectRequestPacket(long connectionTime, byte connectionNumber, int localId, byte[] targetAddress, NetDataReader data)
		{
			ConnectionTime = connectionTime;
			ConnectionNumber = connectionNumber;
			TargetAddress = targetAddress;
			Data = data;
			PeerId = localId;
		}

		internal static int GetProtocolId(NetPacket packet)
		{
			return BitConverter.ToInt32(packet.RawData, 1);
		}

		internal static NetConnectRequestPacket FromData(NetPacket packet)
		{
			if (packet.ConnectionNumber >= 4)
			{
				return null;
			}
			long connectionTime = BitConverter.ToInt64(packet.RawData, 5);
			int localId = BitConverter.ToInt32(packet.RawData, 13);
			int num = packet.RawData[17];
			if (num != 16 && num != 28)
			{
				return null;
			}
			byte[] array = new byte[num];
			Buffer.BlockCopy(packet.RawData, 18, array, 0, num);
			NetDataReader netDataReader = new NetDataReader(null, 0, 0);
			if (packet.Size > 18 + num)
			{
				netDataReader.SetSource(packet.RawData, 18 + num, packet.Size);
			}
			return new NetConnectRequestPacket(connectionTime, packet.ConnectionNumber, localId, array, netDataReader);
		}

		internal static NetPacket Make(ReadOnlySpan<byte> connectData, SocketAddress addressBytes, long connectTime, int localId)
		{
			NetPacket netPacket = new NetPacket(PacketProperty.ConnectRequest, connectData.Length + addressBytes.Size);
			FastBitConverter.GetBytes(netPacket.RawData, 1, 13);
			FastBitConverter.GetBytes(netPacket.RawData, 5, connectTime);
			FastBitConverter.GetBytes(netPacket.RawData, 13, localId);
			netPacket.RawData[17] = (byte)addressBytes.Size;
			for (int i = 0; i < addressBytes.Size; i++)
			{
				netPacket.RawData[18 + i] = addressBytes[i];
			}
			connectData.CopyTo(netPacket.RawData.AsSpan(18 + addressBytes.Size));
			return netPacket;
		}
	}
	internal sealed class NetConnectAcceptPacket
	{
		public const int Size = 15;

		public readonly long ConnectionTime;

		public readonly byte ConnectionNumber;

		public readonly int PeerId;

		public readonly bool PeerNetworkChanged;

		private NetConnectAcceptPacket(long connectionTime, byte connectionNumber, int peerId, bool peerNetworkChanged)
		{
			ConnectionTime = connectionTime;
			ConnectionNumber = connectionNumber;
			PeerId = peerId;
			PeerNetworkChanged = peerNetworkChanged;
		}

		public static NetConnectAcceptPacket FromData(NetPacket packet)
		{
			if (packet.Size != 15)
			{
				return null;
			}
			long connectionTime = BitConverter.ToInt64(packet.RawData, 1);
			byte b = packet.RawData[9];
			if (b >= 4)
			{
				return null;
			}
			byte b2 = packet.RawData[10];
			if (b2 > 1)
			{
				return null;
			}
			int num = BitConverter.ToInt32(packet.RawData, 11);
			if (num < 0)
			{
				return null;
			}
			return new NetConnectAcceptPacket(connectionTime, b, num, b2 == 1);
		}

		public static NetPacket Make(long connectTime, byte connectNum, int localPeerId)
		{
			NetPacket netPacket = new NetPacket(PacketProperty.ConnectAccept, 0);
			FastBitConverter.GetBytes(netPacket.RawData, 1, connectTime);
			netPacket.RawData[9] = connectNum;
			FastBitConverter.GetBytes(netPacket.RawData, 11, localPeerId);
			return netPacket;
		}

		public static NetPacket MakeNetworkChanged(LiteNetPeer peer)
		{
			NetPacket netPacket = new NetPacket(PacketProperty.PeerNotFound, 14);
			FastBitConverter.GetBytes(netPacket.RawData, 1, peer.ConnectTime);
			netPacket.RawData[9] = peer.ConnectionNum;
			netPacket.RawData[10] = 1;
			FastBitConverter.GetBytes(netPacket.RawData, 11, peer.RemoteId);
			return netPacket;
		}
	}
	public class LiteNetManager : IEnumerable<LiteNetPeer>, IEnumerable
	{
		public struct NetPeerEnumerator<T> : IEnumerator<T>, IEnumerator, IDisposable where T : LiteNetPeer
		{
			private readonly T _initialPeer;

			private T _p;

			public T Current => _p;

			object IEnumerator.Current => _p;

			public NetPeerEnumerator(T p)
			{
				_initialPeer = p;
				_p = null;
			}

			public void Dispose()
			{
			}

			public bool MoveNext()
			{
				_p = ((_p == null) ? _initialPeer : ((T)_p.NextPeer));
				return _p != null;
			}

			public void Reset()
			{
				throw new NotSupportedException();
			}
		}

		private struct Slot
		{
			internal int HashCode;

			internal int Next;

			internal LiteNetPeer Value;
		}

		private readonly Random _randomGenerator = new Random();

		private const int MinLatencyThreshold = 5;

		private Thread _logicThread;

		private bool _manualMode;

		private readonly AutoResetEvent _updateTriggerEvent = new AutoResetEvent(initialState: true);

		private NetEvent _pendingEventHead;

		private NetEvent _pendingEventTail;

		private NetEvent _netEventPoolHead;

		private readonly ILiteNetEventListener _netEventListener;

		private readonly Dictionary<IPEndPoint, LiteConnectionRequest> _requestsDict = new Dictionary<IPEndPoint, LiteConnectionRequest>();

		private long _connectedPeersCount;

		private readonly PacketLayerBase _extraPacketLayer;

		private int _lastPeerId;

		private ConcurrentQueue<int> _peerIds = new ConcurrentQueue<int>();

		private readonly object _eventLock = new object();

		private volatile bool _isRunning;

		private bool _dropPacket;

		public bool UnconnectedMessagesEnabled;

		public bool NatPunchEnabled;

		public int UpdateTime = 15;

		public int PingInterval = 1000;

		public int DisconnectTimeout = 5000;

		public bool SimulatePacketLoss;

		public bool SimulateLatency;

		public int SimulationPacketLossChance = 10;

		public int SimulationMinLatency = 30;

		public int SimulationMaxLatency = 100;

		public bool UnsyncedEvents;

		public bool UnsyncedReceiveEvent;

		public bool UnsyncedDeliveryEvent;

		public bool BroadcastReceiveEnabled;

		public int ReconnectDelay = 500;

		public int MaxConnectAttempts = 10;

		public bool ReuseAddress;

		public bool DontRoute;

		public readonly NetStatistics Statistics = new NetStatistics();

		public bool EnableStatistics;

		public ushort MaxFragmentsCount = ushort.MaxValue;

		private readonly Lazy<NatPunchModule> _natPunchModule;

		public bool AutoRecycle;

		public bool IPv6Enabled = true;

		public int MtuOverride;

		public bool MtuDiscovery;

		public bool UseNativeSockets;

		public bool DisconnectOnUnreachable;

		public bool AllowPeerAddressChange;

		public int MaxPacketPerManualReceive = 256;

		private const int MaxPrimeArrayLength = 2147483587;

		private const int HashPrime = 101;

		private const int Lower31BitMask = int.MaxValue;

		private static readonly int[] Primes;

		private int[] _buckets;

		private Slot[] _slots;

		private int _count;

		private int _lastIndex;

		private int _freeList = -1;

		private LiteNetPeer[] _peersArray = new LiteNetPeer[32];

		protected readonly ReaderWriterLockSlim _peersLock = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion);

		protected volatile LiteNetPeer _headPeer;

		private NetPacket _poolHead;

		private int _poolCount;

		private readonly object _poolLock = new object();

		public int PacketPoolSize = 1000;

		protected Socket _udpSocketv4;

		private Socket _udpSocketv6;

		private Thread _receiveThread;

		private IPEndPoint _bufferEndPointv4;

		private IPEndPoint _bufferEndPointv6;

		private const int SioUdpConnreset = -1744830452;

		private static readonly IPAddress MulticastAddressV6;

		public static readonly bool IPv6Support;

		internal bool NotConnected;

		public int ReceivePollingTime = 50000;

		public NatPunchModule NatPunchModule => _natPunchModule.Value;

		public bool IsRunning => _isRunning;

		public int LocalPort { get; private set; }

		public LiteNetPeer FirstPeer => _headPeer;

		public int ConnectedPeersCount => (int)Interlocked.Read(ref _connectedPeersCount);

		public int ExtraPacketSizeForLayer => _extraPacketLayer?.ExtraPacketSizeForLayer ?? 0;

		public int PoolCount => _poolCount;

		public short Ttl
		{
			get
			{
				return _udpSocketv4.Ttl;
			}
			internal set
			{
				_udpSocketv4.Ttl = value;
			}
		}

		public LiteNetManager(ILiteNetEventListener listener, PacketLayerBase extraPacketLayer = null)
		{
			_netEventListener = listener;
			_natPunchModule = new Lazy<NatPunchModule>(() => new NatPunchModule(this));
			_extraPacketLayer = extraPacketLayer;
		}

		internal void ConnectionLatencyUpdated(LiteNetPeer fromPeer, int latency)
		{
			CreateEvent(NetEvent.EType.ConnectionLatencyUpdated, fromPeer, null, SocketError.Success, latency, DisconnectReason.ConnectionFailed, null, DeliveryMethod.Unreliable, 0);
		}

		internal void MessageDelivered(LiteNetPeer fromPeer, object userData)
		{
			CreateEvent(NetEvent.EType.MessageDelivered, fromPeer, null, SocketError.Success, 0, DisconnectReason.ConnectionFailed, null, DeliveryMethod.Unreliable, 0, null, userData);
		}

		internal void DisconnectPeerForce(LiteNetPeer peer, DisconnectReason reason, SocketError socketErrorCode, NetPacket eventData)
		{
			DisconnectPeer(peer, reason, socketErrorCode, force: true, null, 0, 0, eventData);
		}

		private void DisconnectPeer(LiteNetPeer peer, DisconnectReason reason, SocketError socketErrorCode, bool force, byte[] data, int start, int count, NetPacket eventData)
		{
			switch (peer.Shutdown(data, start, count, force))
			{
			case ShutdownResult.None:
				return;
			case ShutdownResult.WasConnected:
				Interlocked.Decrement(ref _connectedPeersCount);
				break;
			}
			CreateEvent(NetEvent.EType.Disconnect, peer, null, socketErrorCode, 0, reason, null, DeliveryMethod.Unreliable, 0, eventData);
		}

		private void CreateEvent(NetEvent.EType type, LiteNetPeer peer = null, IPEndPoint remoteEndPoint = null, SocketError errorCode = SocketError.Success, int latency = 0, DisconnectReason disconnectReason = DisconnectReason.ConnectionFailed, LiteConnectionRequest connectionRequest = null, DeliveryMethod deliveryMethod = DeliveryMethod.Unreliable, byte channelNumber = 0, NetPacket readerSource = null, object userData = null)
		{
			bool flag = UnsyncedEvents;
			switch (type)
			{
			case NetEvent.EType.Connect:
				Interlocked.Increment(ref _connectedPeersCount);
				break;
			case NetEvent.EType.MessageDelivered:
				flag = UnsyncedDeliveryEvent;
				break;
			}
			NetEvent netEvent;
			lock (_eventLock)
			{
				netEvent = _netEventPoolHead;
				if (netEvent == null)
				{
					netEvent = new NetEvent(this);
				}
				else
				{
					_netEventPoolHead = netEvent.Next;
				}
			}
			netEvent.Next = null;
			netEvent.Type = type;
			netEvent.DataReader.SetSource(readerSource, readerSource?.HeaderSize ?? 0);
			netEvent.Peer = peer;
			netEvent.RemoteEndPoint = remoteEndPoint;
			netEvent.Latency = latency;
			netEvent.ErrorCode = errorCode;
			netEvent.DisconnectReason = disconnectReason;
			netEvent.ConnectionRequest = connectionRequest;
			netEvent.DeliveryMethod = deliveryMethod;
			netEvent.ChannelNumber = channelNumber;
			netEvent.UserData = userData;
			if (flag || _manualMode)
			{
				ProcessEvent(netEvent);
				return;
			}
			lock (_eventLock)
			{
				if (_pendingEventTail == null)
				{
					_pendingEventHead = netEvent;
				}
				else
				{
					_pendingEventTail.Next = netEvent;
				}
				_pendingEventTail = netEvent;
			}
		}

		protected virtual void ProcessEvent(NetEvent evt)
		{
			bool isNull = evt.DataReader.IsNull;
			switch (evt.Type)
			{
			case NetEvent.EType.Connect:
				_netEventListener.OnPeerConnected(evt.Peer);
				break;
			case NetEvent.EType.Disconnect:
			{
				DisconnectInfo disconnectInfo = default(DisconnectInfo);
				disconnectInfo.Reason = evt.DisconnectReason;
				disconnectInfo.AdditionalData = evt.DataReader;
				disconnectInfo.SocketErrorCode = evt.ErrorCode;
				DisconnectInfo disconnectInfo2 = disconnectInfo;
				_netEventListener.OnPeerDisconnected(evt.Peer, disconnectInfo2);
				break;
			}
			case NetEvent.EType.Receive:
				_netEventListener.OnNetworkReceive(evt.Peer, evt.DataReader, evt.DeliveryMethod);
				break;
			case NetEvent.EType.ReceiveUnconnected:
				_netEventListener.OnNetworkReceiveUnconnected(evt.RemoteEndPoint, evt.DataReader, UnconnectedMessageType.BasicMessage);
				break;
			case NetEvent.EType.Broadcast:
				_netEventListener.OnNetworkReceiveUnconnected(evt.RemoteEndPoint, evt.DataReader, UnconnectedMessageType.Broadcast);
				break;
			case NetEvent.EType.Error:
				_netEventListener.OnNetworkError(evt.RemoteEndPoint, evt.ErrorCode);
				break;
			case NetEvent.EType.ConnectionLatencyUpdated:
				_netEventListener.OnNetworkLatencyUpdate(evt.Peer, evt.Latency);
				break;
			case NetEvent.EType.ConnectionRequest:
				_netEventListener.OnConnectionRequest(evt.ConnectionRequest);
				break;
			case NetEvent.EType.MessageDelivered:
				_netEventListener.OnMessageDelivered(evt.Peer, evt.UserData);
				break;
			case NetEvent.EType.PeerAddressChanged:
			{
				_peersLock.EnterUpgradeableReadLock();
				IPEndPoint iPEndPoint = null;
				if (ContainsPeer(evt.Peer))
				{
					_peersLock.EnterWriteLock();
					RemovePeerFromSet(evt.Peer);
					iPEndPoint = new IPEndPoint(evt.Peer.Address, evt.Peer.Port);
					evt.Peer.FinishEndPointChange(evt.RemoteEndPoint);
					AddPeerToSet(evt.Peer);
					_peersLock.ExitWriteLock();
				}
				_peersLock.ExitUpgradeableReadLock();
				if (iPEndPoint != null)
				{
					_netEventListener.OnPeerAddressChanged(evt.Peer, iPEndPoint);
				}
				break;
			}
			}
			if (isNull)
			{
				RecycleEvent(evt);
			}
			else if (AutoRecycle)
			{
				evt.DataReader.RecycleInternal();
			}
		}

		internal void RecycleEvent(NetEvent evt)
		{
			evt.Peer = null;
			evt.ErrorCode = SocketError.Success;
			evt.RemoteEndPoint = null;
			evt.ConnectionRequest = null;
			lock (_eventLock)
			{
				evt.Next = _netEventPoolHead;
				_netEventPoolHead = evt;
			}
		}

		protected virtual void ProcessNtpRequests(float elapsedMilliseconds)
		{
		}

		private void UpdateLogic()
		{
			List<LiteNetPeer> list = new List<LiteNetPeer>();
			Stopwatch stopwatch = new Stopwatch();
			stopwatch.Start();
			while (_isRunning)
			{
				try
				{
					float num = (float)((double)stopwatch.ElapsedTicks / (double)Stopwatch.Frequency * 1000.0);
					num = ((num <= 0f) ? 0.001f : num);
					stopwatch.Restart();
					for (LiteNetPeer liteNetPeer = _headPeer; liteNetPeer != null; liteNetPeer = liteNetPeer.NextPeer)
					{
						if (liteNetPeer.ConnectionState == ConnectionState.Disconnected && liteNetPeer.TimeSinceLastPacket > (float)DisconnectTimeout)
						{
							list.Add(liteNetPeer);
						}
						else
						{
							liteNetPeer.Update(num);
						}
					}
					if (list.Count > 0)
					{
						_peersLock.EnterWriteLock();
						for (int i = 0; i < list.Count; i++)
						{
							RemovePeer(list[i], enableWriteLock: false);
						}
						_peersLock.ExitWriteLock();
						list.Clear();
					}
					ProcessNtpRequests(num);
					int num2 = UpdateTime - (int)stopwatch.ElapsedMilliseconds;
					if (num2 > 0)
					{
						_updateTriggerEvent.WaitOne(num2);
					}
				}
				catch (ThreadAbortException)
				{
					return;
				}
				catch (Exception ex2)
				{
					NetDebug.WriteError("[NM] LogicThread error: " + ex2);
				}
			}
			stopwatch.Stop();
		}

		[Conditional("DEBUG")]
		[Conditional("SIMULATE_NETWORK")]
		private void ProcessDelayedPackets()
		{
			_ = SimulateLatency;
		}

		public void ManualUpdate(float elapsedMilliseconds)
		{
			if (!_manualMode)
			{
				return;
			}
			for (LiteNetPeer liteNetPeer = _headPeer; liteNetPeer != null; liteNetPeer = liteNetPeer.NextPeer)
			{
				if (liteNetPeer.ConnectionState == ConnectionState.Disconnected && liteNetPeer.TimeSinceLastPacket > (float)DisconnectTimeout)
				{
					RemovePeer(liteNetPeer, enableWriteLock: false);
				}
				else
				{
					liteNetPeer.Update(elapsedMilliseconds);
				}
			}
			ProcessNtpRequests(elapsedMilliseconds);
		}

		protected virtual LiteNetPeer CreateOutgoingPeer(IPEndPoint remoteEndPoint, int id, byte connectNum, ReadOnlySpan<byte> connectData)
		{
			return new LiteNetPeer(this, remoteEndPoint, id, connectNum, connectData);
		}

		protected virtual LiteNetPeer CreateIncomingPeer(LiteConnectionRequest request, int id)
		{
			return new LiteNetPeer(this, request, id);
		}

		protected virtual LiteNetPeer CreateRejectPeer(IPEndPoint remoteEndPoint, int id)
		{
			return new LiteNetPeer(this, remoteEndPoint, id);
		}

		protected virtual LiteConnectionRequest CreateConnectionRequest(IPEndPoint remoteEndPoint, NetConnectRequestPacket requestPacket)
		{
			return new LiteConnectionRequest(remoteEndPoint, requestPacket, this);
		}

		internal LiteNetPeer OnConnectionSolved(LiteConnectionRequest request, byte[] rejectData, int start, int length)
		{
			LiteNetPeer actualValue = null;
			if (request.Result == ConnectionRequestResult.RejectForce)
			{
				if (rejectData != null && length > 0)
				{
					NetPacket netPacket = PoolGetWithProperty(PacketProperty.Disconnect, length);
					netPacket.ConnectionNumber = request.InternalPacket.ConnectionNumber;
					FastBitConverter.GetBytes(netPacket.RawData, 1, request.InternalPacket.ConnectionTime);
					if (netPacket.Size >= NetConstants.PossibleMtu[0])
					{
						NetDebug.WriteError("[Peer] Disconnect additional data size more than MTU!");
					}
					else
					{
						Buffer.BlockCopy(rejectData, start, netPacket.RawData, 9, length);
					}
					SendRawAndRecycle(netPacket, request.RemoteEndPoint);
				}
				lock (_requestsDict)
				{
					_requestsDict.Remove(request.RemoteEndPoint);
				}
			}
			else
			{
				lock (_requestsDict)
				{
					if (!TryGetPeer(request.RemoteEndPoint, out actualValue))
					{
						if (request.Result == ConnectionRequestResult.Reject)
						{
							actualValue = CreateRejectPeer(request.RemoteEndPoint, GetNextPeerId());
							actualValue.Reject(request.InternalPacket, rejectData, start, length);
							AddPeer(actualValue);
						}
						else
						{
							actualValue = CreateIncomingPeer(request, GetNextPeerId());
							AddPeer(actualValue);
							CreateEvent(NetEvent.EType.Connect, actualValue, null, SocketError.Success, 0, DisconnectReason.ConnectionFailed, null, DeliveryMethod.Unreliable, 0);
						}
					}
					_requestsDict.Remove(request.RemoteEndPoint);
				}
			}
			return actualValue;
		}

		private int GetNextPeerId()
		{
			if (!_peerIds.TryDequeue(out var result))
			{
				return _lastPeerId++;
			}
			return result;
		}

		private void ProcessConnectRequest(IPEndPoint remoteEndPoint, LiteNetPeer netPeer, NetConnectRequestPacket connRequest)
		{
			if (netPeer != null)
			{
				ConnectRequestResult connectRequestResult = netPeer.ProcessConnectRequest(connRequest);
				switch (connectRequestResult)
				{
				default:
					return;
				case ConnectRequestResult.Reconnection:
					DisconnectPeerForce(netPeer, DisconnectReason.Reconnect, SocketError.Success, null);
					RemovePeer(netPeer, enableWriteLock: true);
					break;
				case ConnectRequestResult.NewConnection:
					RemovePeer(netPeer, enableWriteLock: true);
					break;
				case ConnectRequestResult.P2PLose:
					DisconnectPeerForce(netPeer, DisconnectReason.PeerToPeerConnection, SocketError.Success, null);
					RemovePeer(netPeer, enableWriteLock: true);
					break;
				}
				if (connectRequestResult != ConnectRequestResult.P2PLose)
				{
					connRequest.ConnectionNumber = (byte)((netPeer.ConnectionNum + 1) % 4);
				}
			}
			LiteConnectionRequest value;
			lock (_requestsDict)
			{
				if (_requestsDict.TryGetValue(remoteEndPoint, out value))
				{
					value.UpdateRequest(connRequest);
					return;
				}
				value = CreateConnectionRequest(remoteEndPoint, connRequest);
				_requestsDict.Add(remoteEndPoint, value);
			}
			CreateEvent(NetEvent.EType.ConnectionRequest, null, null, SocketError.Success, 0, DisconnectReason.ConnectionFailed, value, DeliveryMethod.Unreliable, 0);
		}

		private void OnMessageReceived(NetPacket packet, IPEndPoint remoteEndPoint)
		{
			if (packet.Size == 0)
			{
				PoolRecycle(packet);
				return;
			}
			_dropPacket = false;
			if (!_dropPacket)
			{
				HandleMessageReceived(packet, remoteEndPoint);
			}
		}

		[Conditional("DEBUG")]
		[Conditional("SIMULATE_NETWORK")]
		private void HandleSimulateLatency(NetPacket packet, IPEndPoint remoteEndPoint)
		{
			_ = SimulateLatency;
		}

		[Conditional("DEBUG")]
		[Conditional("SIMULATE_NETWORK")]
		private void HandleSimulatePacketLoss()
		{
			if (SimulatePacketLoss && _randomGenerator.NextDouble() * 100.0 < (double)SimulationPacketLossChance)
			{
				_dropPacket = true;
			}
		}

		internal virtual bool CustomMessageHandle(NetPacket packet, IPEndPoint remoteEndPoint)
		{
			return false;
		}

		private void HandleMessageReceived(NetPacket packet, IPEndPoint remoteEndPoint)
		{
			int size = packet.Size;
			if (EnableStatistics)
			{
				Statistics.IncrementPacketsReceived();
				Statistics.AddBytesReceived(size);
			}
			if (CustomMessageHandle(packet, remoteEndPoint))
			{
				return;
			}
			if (_extraPacketLayer != null)
			{
				_extraPacketLayer.ProcessInboundPacket(ref remoteEndPoint, ref packet.RawData, ref packet.Size);
				if (packet.Size == 0)
				{
					return;
				}
			}
			if (!packet.Verify())
			{
				NetDebug.WriteError("[NM] DataReceived: bad!");
				PoolRecycle(packet);
				return;
			}
			switch (packet.Property)
			{
			case PacketProperty.ConnectRequest:
				if (NetConnectRequestPacket.GetProtocolId(packet) != 13)
				{
					SendRawAndRecycle(PoolGetWithProperty(PacketProperty.InvalidProtocol), remoteEndPoint);
					return;
				}
				break;
			case PacketProperty.Broadcast:
				if (BroadcastReceiveEnabled)
				{
					CreateEvent(NetEvent.EType.Broadcast, null, remoteEndPoint, SocketError.Success, 0, DisconnectReason.ConnectionFailed, null, DeliveryMethod.Unreliable, 0, packet);
				}
				return;
			case PacketProperty.UnconnectedMessage:
				if (UnconnectedMessagesEnabled)
				{
					CreateEvent(NetEvent.EType.ReceiveUnconnected, null, remoteEndPoint, SocketError.Success, 0, DisconnectReason.ConnectionFailed, null, DeliveryMethod.Unreliable, 0, packet);
				}
				return;
			case PacketProperty.NatMessage:
				if (NatPunchEnabled)
				{
					NatPunchModule.ProcessMessage(remoteEndPoint, packet);
				}
				return;
			}
			LiteNetPeer actualValue = remoteEndPoint as LiteNetPeer;
			bool flag = actualValue != null || TryGetPeer(remoteEndPoint, out actualValue);
			if (flag && EnableStatistics)
			{
				actualValue.Statistics.IncrementPacketsReceived();
				actualValue.Statistics.AddBytesReceived(size);
			}
			switch (packet.Property)
			{
			case PacketProperty.ConnectRequest:
			{
				NetConnectRequestPacket netConnectRequestPacket = NetConnectRequestPacket.FromData(packet);
				if (netConnectRequestPacket != null)
				{
					ProcessConnectRequest(remoteEndPoint, actualValue, netConnectRequestPacket);
				}
				break;
			}
			case PacketProperty.PeerNotFound:
				if (flag)
				{
					if (actualValue.ConnectionState == ConnectionState.Connected)
					{
						if (packet.Size == 1)
						{
							actualValue.ResetMtu();
							SendRaw(NetConnectAcceptPacket.MakeNetworkChanged(actualValue), remoteEndPoint);
						}
						else if (packet.Size == 2 && packet.RawData[1] == 1)
						{
							DisconnectPeerForce(actualValue, DisconnectReason.PeerNotFound, SocketError.Success, null);
						}
					}
				}
				else
				{
					if (packet.Size <= 1)
					{
						break;
					}
					bool flag2 = false;
					if (AllowPeerAddressChange)
					{
						NetConnectAcceptPacket netConnectAcceptPacket = NetConnectAcceptPacket.FromData(packet);
						if (netConnectAcceptPacket != null && netConnectAcceptPacket.PeerNetworkChanged && netConnectAcceptPacket.PeerId < _peersArray.Length)
						{
							_peersLock.EnterUpgradeableReadLock();
							LiteNetPeer liteNetPeer = _peersArray[netConnectAcceptPacket.PeerId];
							_peersLock.ExitUpgradeableReadLock();
							if (liteNetPeer != null && liteNetPeer.ConnectTime == netConnectAcceptPacket.ConnectionTime && liteNetPeer.ConnectionNum == netConnectAcceptPacket.ConnectionNumber)
							{
								if (liteNetPeer.ConnectionState == ConnectionState.Connected)
								{
									liteNetPeer.InitiateEndPointChange();
									CreateEvent(NetEvent.EType.PeerAddressChanged, liteNetPeer, remoteEndPoint, SocketError.Success, 0, DisconnectReason.ConnectionFailed, null, DeliveryMethod.Unreliable, 0);
								}
								flag2 = true;
							}
						}
					}
					PoolRecycle(packet);
					if (!flag2)
					{
						NetPacket netPacket = PoolGetWithProperty(PacketProperty.PeerNotFound, 1);
						netPacket.RawData[1] = 1;
						SendRawAndRecycle(netPacket, remoteEndPoint);
					}
				}
				break;
			case PacketProperty.InvalidProtocol:
				if (flag && actualValue.ConnectionState == ConnectionState.Outgoing)
				{
					DisconnectPeerForce(actualValue, DisconnectReason.InvalidProtocol, SocketError.Success, null);
				}
				break;
			case PacketProperty.Disconnect:
				if (flag)
				{
					DisconnectResult disconnectResult = actualValue.ProcessDisconnect(packet);
					if (disconnectResult == DisconnectResult.None)
					{
						PoolRecycle(packet);
						break;
					}
					DisconnectPeerForce(actualValue, (disconnectResult == DisconnectResult.Disconnect) ? DisconnectReason.RemoteConnectionClose : DisconnectReason.ConnectionRejected, SocketError.Success, packet);
				}
				else
				{
					PoolRecycle(packet);
				}
				SendRawAndRecycle(PoolGetWithProperty(PacketProperty.ShutdownOk), remoteEndPoint);
				break;
			case PacketProperty.ConnectAccept:
				if (flag)
				{
					NetConnectAcceptPacket netConnectAcceptPacket2 = NetConnectAcceptPacket.FromData(packet);
					if (netConnectAcceptPacket2 != null && actualValue.ProcessConnectAccept(netConnectAcceptPacket2))
					{
						CreateEvent(NetEvent.EType.Connect, actualValue, null, SocketError.Success, 0, DisconnectReason.ConnectionFailed, null, DeliveryMethod.Unreliable, 0);
					}
				}
				break;
			default:
				if (flag)
				{
					actualValue.ProcessPacket(packet);
				}
				else
				{
					SendRawAndRecycle(PoolGetWithProperty(PacketProperty.PeerNotFound), remoteEndPoint);
				}
				break;
			}
		}

		internal void CreateReceiveEvent(NetPacket packet, DeliveryMethod method, byte channelNumber, int headerSize, LiteNetPeer fromPeer)
		{
			if (UnsyncedEvents || UnsyncedReceiveEvent || _manualMode)
			{
				NetEvent netEvent;
				lock (_eventLock)
				{
					netEvent = _netEventPoolHead;
					if (netEvent == null)
					{
						netEvent = new NetEvent(this);
					}
					else
					{
						_netEventPoolHead = netEvent.Next;
					}
				}
				netEvent.Next = null;
				netEvent.Type = NetEvent.EType.Receive;
				netEvent.DataReader.SetSource(packet, headerSize);
				netEvent.Peer = fromPeer;
				netEvent.DeliveryMethod = method;
				netEvent.ChannelNumber = channelNumber;
				ProcessEvent(netEvent);
				return;
			}
			lock (_eventLock)
			{
				NetEvent netEvent = _netEventPoolHead;
				if (netEvent == null)
				{
					netEvent = new NetEvent(this);
				}
				else
				{
					_netEventPoolHead = netEvent.Next;
				}
				netEvent.Next = null;
				netEvent.Type = NetEvent.EType.Receive;
				netEvent.DataReader.SetSource(packet, headerSize);
				netEvent.Peer = fromPeer;
				netEvent.DeliveryMethod = method;
				netEvent.ChannelNumber = channelNumber;
				if (_pendingEventTail == null)
				{
					_pendingEventHead = netEvent;
				}
				else
				{
					_pendingEventTail.Next = netEvent;
				}
				_pendingEventTail = netEvent;
			}
		}

		public void SendToAll(NetDataWriter writer, DeliveryMethod options)
		{
			SendToAll(writer.Data, 0, writer.Length, options);
		}

		public void SendToAll(byte[] data, DeliveryMethod options)
		{
			SendToAll(data, 0, data.Length, options);
		}

		public void SendToAll(byte[] data, int start, int length, DeliveryMethod options)
		{
			try
			{
				_peersLock.EnterReadLock();
				for (LiteNetPeer liteNetPeer = _headPeer; liteNetPeer != null; liteNetPeer = liteNetPeer.NextPeer)
				{
					liteNetPeer.Send(data, start, length, options);
				}
			}
			finally
			{
				_peersLock.ExitReadLock();
			}
		}

		public void SendToAll(NetDataWriter writer, DeliveryMethod options, LiteNetPeer excludePeer)
		{
			SendToAll(writer.Data, 0, writer.Length, options, excludePeer);
		}

		public void SendToAll(byte[] data, DeliveryMethod options, LiteNetPeer excludePeer)
		{
			SendToAll(data, 0, data.Length, options, excludePeer);
		}

		public void SendToAll(byte[] data, int start, int length, DeliveryMethod options, LiteNetPeer excludePeer)
		{
			try
			{
				_peersLock.EnterReadLock();
				for (LiteNetPeer liteNetPeer = _headPeer; liteNetPeer != null; liteNetPeer = liteNetPeer.NextPeer)
				{
					if (liteNetPeer != excludePeer)
					{
						liteNetPeer.Send(data, start, length, options);
					}
				}
			}
			finally
			{
				_peersLock.ExitReadLock();
			}
		}

		public void SendToAll(ReadOnlySpan<byte> data, DeliveryMethod options)
		{
			SendToAll(data, options, null);
		}

		public void SendToAll(ReadOnlySpan<byte> data, DeliveryMethod options, LiteNetPeer excludePeer)
		{
			try
			{
				_peersLock.EnterReadLock();
				for (LiteNetPeer liteNetPeer = _headPeer; liteNetPeer != null; liteNetPeer = liteNetPeer.NextPeer)
				{
					if (liteNetPeer != excludePeer)
					{
						liteNetPeer.Send(data, options);
					}
				}
			}
			finally
			{
				_peersLock.ExitReadLock();
			}
		}

		public bool SendUnconnectedMessage(ReadOnlySpan<byte> message, IPEndPoint remoteEndPoint)
		{
			int headerSize = NetPacket.GetHeaderSize(PacketProperty.UnconnectedMessage);
			NetPacket netPacket = PoolGetPacket(message.Length + headerSize);
			netPacket.Property = PacketProperty.UnconnectedMessage;
			message.CopyTo(new Span<byte>(netPacket.RawData, headerSize, message.Length));
			return SendRawAndRecycle(netPacket, remoteEndPoint) > 0;
		}

		public bool Start()
		{
			return Start(0);
		}

		public bool Start(IPAddress addressIPv4, IPAddress addressIPv6, int port)
		{
			return Start(addressIPv4, addressIPv6, port, manualMode: false);
		}

		public bool Start(string addressIPv4, string addressIPv6, int port)
		{
			IPAddress addressIPv7 = NetUtils.ResolveAddress(addressIPv4);
			IPAddress addressIPv8 = NetUtils.ResolveAddress(addressIPv6);
			return Start(addressIPv7, addressIPv8, port);
		}

		public bool Start(int port)
		{
			return Start(IPAddress.Any, IPAddress.IPv6Any, port);
		}

		public bool StartInManualMode(IPAddress addressIPv4, IPAddress addressIPv6, int port)
		{
			return Start(addressIPv4, addressIPv6, port, manualMode: true);
		}

		public bool StartInManualMode(string addressIPv4, string addressIPv6, int port)
		{
			IPAddress addressIPv7 = NetUtils.ResolveAddress(addressIPv4);
			IPAddress addressIPv8 = NetUtils.ResolveAddress(addressIPv6);
			return StartInManualMode(addressIPv7, addressIPv8, port);
		}

		public bool StartInManualMode(int port)
		{
			return StartInManualMode(IPAddress.Any, IPAddress.IPv6Any, port);
		}

		public bool SendUnconnectedMessage(byte[] message, IPEndPoint remoteEndPoint)
		{
			return SendUnconnectedMessage(message, 0, message.Length, remoteEndPoint);
		}

		public bool SendUnconnectedMessage(NetDataWriter writer, string address, int port)
		{
			return SendUnconnectedMessage(writer.Data, 0, writer.Length, NetUtils.MakeEndPoint(address, port));
		}

		public bool SendUnconnectedMessage(NetDataWriter writer, IPEndPoint remoteEndPoint)
		{
			return SendUnconnectedMessage(writer.Data, 0, writer.Length, remoteEndPoint);
		}

		public bool SendUnconnectedMessage(byte[] message, int start, int length, IPEndPoint remoteEndPoint)
		{
			NetPacket packet = PoolGetWithData(PacketProperty.UnconnectedMessage, message, start, length);
			return SendRawAndRecycle(packet, remoteEndPoint) > 0;
		}

		public void TriggerUpdate()
		{
			_updateTriggerEvent.Set();
		}

		public void PollEvents()
		{
			if (_manualMode)
			{
				if (_udpSocketv4 != null)
				{
					ManualReceive(_udpSocketv4, _bufferEndPointv4);
				}
				if (_udpSocketv6 != null && _udpSocketv6 != _udpSocketv4)
				{
					ManualReceive(_udpSocketv6, _bufferEndPointv6);
				}
			}
			else if (!UnsyncedEvents)
			{
				NetEvent netEvent;
				lock (_eventLock)
				{
					netEvent = _pendingEventHead;
					_pendingEventHead = null;
					_pendingEventTail = null;
				}
				while (netEvent != null)
				{
					NetEvent next = netEvent.Next;
					ProcessEvent(netEvent);
					netEvent = next;
				}
			}
		}

		public LiteNetPeer Connect(string address, int port, string key)
		{
			return Connect(address, port, NetDataWriter.FromString(key));
		}

		public LiteNetPeer Connect(string address, int port, NetDataWriter connectionData)
		{
			IPEndPoint target;
			try
			{
				target = NetUtils.MakeEndPoint(address, port);
			}
			catch
			{
				CreateEvent(NetEvent.EType.Disconnect, null, null, SocketError.Success, 0, DisconnectReason.UnknownHost, null, DeliveryMethod.Unreliable, 0);
				return null;
			}
			return Connect(target, connectionData);
		}

		public LiteNetPeer Connect(IPEndPoint target, string key)
		{
			return Connect(target, NetDataWriter.FromString(key));
		}

		public LiteNetPeer Connect(IPEndPoint target, NetDataWriter connectionData)
		{
			if (!_isRunning)
			{
				throw new InvalidOperationException("Client is not running");
			}
			lock (_requestsDict)
			{
				if (_requestsDict.ContainsKey(target))
				{
					return null;
				}
				byte connectNum = 0;
				if (TryGetPeer(target, out var actualValue))
				{
					ConnectionState connectionState = actualValue.ConnectionState;
					if (connectionState == ConnectionState.Outgoing || connectionState == ConnectionState.Connected)
					{
						return actualValue;
					}
					connectNum = (byte)((actualValue.ConnectionNum + 1) % 4);
					RemovePeer(actualValue, enableWriteLock: true);
				}
				actualValue = CreateOutgoingPeer(target, GetNextPeerId(), connectNum, connectionData.AsReadOnlySpan());
				AddPeer(actualValue);
				return actualValue;
			}
		}

		public LiteNetPeer Connect(IPEndPoint target, ReadOnlySpan<byte> connectionData)
		{
			if (!_isRunning)
			{
				throw new InvalidOperationException("Client is not running");
			}
			lock (_requestsDict)
			{
				if (_requestsDict.ContainsKey(target))
				{
					return null;
				}
				byte connectNum = 0;
				if (TryGetPeer(target, out var actualValue))
				{
					ConnectionState connectionState = actualValue.ConnectionState;
					if (connectionState == ConnectionState.Outgoing || connectionState == ConnectionState.Connected)
					{
						return actualValue;
					}
					connectNum = (byte)((actualValue.ConnectionNum + 1) % 4);
					RemovePeer(actualValue, enableWriteLock: true);
				}
				actualValue = CreateOutgoingPeer(target, GetNextPeerId(), connectNum, connectionData);
				AddPeer(actualValue);
				return actualValue;
			}
		}

		public void Stop()
		{
			Stop(sendDisconnectMessages: true);
		}

		public void Stop(bool sendDisconnectMessages)
		{
			if (_isRunning)
			{
				bool simulateLatency = SimulateLatency;
				SimulateLatency = false;
				for (LiteNetPeer liteNetPeer = _headPeer; liteNetPeer != null; liteNetPeer = liteNetPeer.NextPeer)
				{
					liteNetPeer.Shutdown(null, 0, 0, !sendDisconnectMessages);
				}
				CloseSocket();
				SimulateLatency = simulateLatency;
				_updateTriggerEvent.Set();
				if (!_manualMode)
				{
					_logicThread.Join();
					_logicThread = null;
				}
				ClearPeerSet();
				_peerIds = new ConcurrentQueue<int>();
				_lastPeerId = 0;
				_connectedPeersCount = 0L;
				_pendingEventHead = null;
				_pendingEventTail = null;
			}
		}

		public int GetPeersCount(ConnectionState peerState)
		{
			int num = 0;
			_peersLock.EnterReadLock();
			for (LiteNetPeer liteNetPeer = _headPeer; liteNetPeer != null; liteNetPeer = liteNetPeer.NextPeer)
			{
				if ((liteNetPeer.ConnectionState & peerState) != 0)
				{
					num++;
				}
			}
			_peersLock.ExitReadLock();
			return num;
		}

		public void GetPeers(List<LiteNetPeer> peers, ConnectionState peerState)
		{
			peers.Clear();
			_peersLock.EnterReadLock();
			for (LiteNetPeer liteNetPeer = _headPeer; liteNetPeer != null; liteNetPeer = liteNetPeer.NextPeer)
			{
				if ((liteNetPeer.ConnectionState & peerState) != 0)
				{
					peers.Add(liteNetPeer);
				}
			}
			_peersLock.ExitReadLock();
		}

		public void GetConnectedPeers(List<LiteNetPeer> peers)
		{
			GetPeers(peers, ConnectionState.Connected);
		}

		public void DisconnectAll()
		{
			DisconnectAll(null, 0, 0);
		}

		public void DisconnectAll(byte[] data, int start, int count)
		{
			_peersLock.EnterReadLock();
			for (LiteNetPeer liteNetPeer = _headPeer; liteNetPeer != null; liteNetPeer = liteNetPeer.NextPeer)
			{
				DisconnectPeer(liteNetPeer, DisconnectReason.DisconnectPeerCalled, SocketError.Success, force: false, data, start, count, null);
			}
			_peersLock.ExitReadLock();
		}

		public void DisconnectPeerForce(LiteNetPeer peer)
		{
			DisconnectPeerForce(peer, DisconnectReason.DisconnectPeerCalled, SocketError.Success, null);
		}

		public void DisconnectPeer(LiteNetPeer peer)
		{
			DisconnectPeer(peer, null, 0, 0);
		}

		public void DisconnectPeer(LiteNetPeer peer, byte[] data)
		{
			DisconnectPeer(peer, data, 0, data.Length);
		}

		public void DisconnectPeer(LiteNetPeer peer, NetDataWriter writer)
		{
			DisconnectPeer(peer, writer.Data, 0, writer.Length);
		}

		public void DisconnectPeer(LiteNetPeer peer, byte[] data, int start, int count)
		{
			DisconnectPeer(peer, DisconnectReason.DisconnectPeerCalled, SocketError.Success, force: false, data, start, count, null);
		}

		public NetPeerEnumerator<LiteNetPeer> GetEnumerator()
		{
			return new NetPeerEnumerator<LiteNetPeer>(_headPeer);
		}

		IEnumerator<LiteNetPeer> IEnumerable<LiteNetPeer>.GetEnumerator()
		{
			return new NetPeerEnumerator<LiteNetPeer>(_headPeer);
		}

		IEnumerator IEnumerable.GetEnumerator()
		{
			return new NetPeerEnumerator<LiteNetPeer>(_headPeer);
		}

		private static int HashSetGetPrime(int min)
		{
			int[] primes = Primes;
			foreach (int num in primes)
			{
				if (num >= min)
				{
					return num;
				}
			}
			for (int j = min | 1; j < int.MaxValue; j += 2)
			{
				if (IsPrime(j) && (j - 1) % 101 != 0)
				{
					return j;
				}
			}
			return min;
			static bool IsPrime(int candidate)
			{
				if (((uint)candidate & (true ? 1u : 0u)) != 0)
				{
					int num2 = (int)Math.Sqrt(candidate);
					for (int k = 3; k <= num2; k += 2)
					{
						if (candidate % k == 0)
						{
							return false;
						}
					}
					return true;
				}
				return candidate == 2;
			}
		}

		private void ClearPeerSet()
		{
			_peersLock.EnterWriteLock();
			_headPeer = null;
			if (_lastIndex > 0)
			{
				Array.Clear(_slots, 0, _lastIndex);
				Array.Clear(_buckets, 0, _buckets.Length);
				_lastIndex = 0;
				_count = 0;
				_freeList = -1;
			}
			_peersArray = new LiteNetPeer[32];
			_peersLock.ExitWriteLock();
		}

		protected bool ContainsPeer(LiteNetPeer item)
		{
			if (item == null)
			{
				NetDebug.WriteError($"Contains peer null: {item}");
				return false;
			}
			if (_buckets != null)
			{
				int num = item.GetHashCode() & 0x7FFFFFFF;
				for (int num2 = _buckets[num % _buckets.Length] - 1; num2 >= 0; num2 = _slots[num2].Next)
				{
					if (_slots[num2].HashCode == num && _slots[num2].Value.Equals(item))
					{
						return true;
					}
				}
			}
			return false;
		}

		public LiteNetPeer GetPeerById(int id)
		{
			if (id < 0 || id >= _peersArray.Length)
			{
				return null;
			}
			return _peersArray[id];
		}

		public bool TryGetPeerById(int id, out LiteNetPeer peer)
		{
			peer = GetPeerById(id);
			return peer != null;
		}

		private void AddPeer(LiteNetPeer peer)
		{
			if (peer == null)
			{
				NetDebug.WriteError($"Add peer null: {peer}");
				return;
			}
			_peersLock.EnterWriteLock();
			if (_headPeer != null)
			{
				peer.NextPeer = _headPeer;
				_headPeer.PrevPeer = peer;
			}
			_headPeer = peer;
			AddPeerToSet(peer);
			if (peer.Id >= _peersArray.Length)
			{
				int num = _peersArray.Length * 2;
				while (peer.Id >= num)
				{
					num *= 2;
				}
				Array.Resize(ref _peersArray, num);
			}
			_peersArray[peer.Id] = peer;
			_peersLock.ExitWriteLock();
		}

		private void RemovePeer(LiteNetPeer peer, bool enableWriteLock)
		{
			if (enableWriteLock)
			{
				_peersLock.EnterWriteLock();
			}
			if (!RemovePeerFromSet(peer))
			{
				if (enableWriteLock)
				{
					_peersLock.ExitWriteLock();
				}
				return;
			}
			if (peer == _headPeer)
			{
				_headPeer = peer.NextPeer;
			}
			if (peer.PrevPeer != null)
			{
				peer.PrevPeer.NextPeer = peer.NextPeer;
			}
			if (peer.NextPeer != null)
			{
				peer.NextPeer.PrevPeer = peer.PrevPeer;
			}
			peer.PrevPeer = null;
			_peersArray[peer.Id] = null;
			_peerIds.Enqueue(peer.Id);
			if (enableWriteLock)
			{
				_peersLock.ExitWriteLock();
			}
		}

		protected bool RemovePeerFromSet(LiteNetPeer peer)
		{
			if (_buckets == null || peer == null)
			{
				return false;
			}
			int num = peer.GetHashCode() & 0x7FFFFFFF;
			int num2 = num % _buckets.Length;
			int num3 = -1;
			for (int num4 = _buckets[num2] - 1; num4 >= 0; num4 = _slots[num4].Next)
			{
				if (_slots[num4].HashCode == num && _slots[num4].Value.Equals(peer))
				{
					if (num3 < 0)
					{
						_buckets[num2] = _slots[num4].Next + 1;
					}
					else
					{
						_slots[num3].Next = _slots[num4].Next;
					}
					_slots[num4].HashCode = -1;
					_slots[num4].Value = null;
					_slots[num4].Next = _freeList;
					_count--;
					if (_count == 0)
					{
						_lastIndex = 0;
						_freeList = -1;
					}
					else
					{
						_freeList = num4;
					}
					return true;
				}
				num3 = num4;
			}
			return false;
		}

		private bool TryGetPeer(IPEndPoint endPoint, out LiteNetPeer actualValue)
		{
			if (_buckets != null)
			{
				int num = endPoint.GetHashCode() & 0x7FFFFFFF;
				_peersLock.EnterReadLock();
				for (int num2 = _buckets[num % _buckets.Length] - 1; num2 >= 0; num2 = _slots[num2].Next)
				{
					if (_slots[num2].HashCode == num && _slots[num2].Value.Equals(endPoint))
					{
						actualValue = _slots[num2].Value;
						_peersLock.ExitReadLock();
						return true;
					}
				}
				_peersLock.ExitReadLock();
			}
			actualValue = null;
			return false;
		}

		private bool TryGetPeer(SocketAddress saddr, out LiteNetPeer actualValue)
		{
			if (_buckets != null)
			{
				int num = saddr.GetHashCode() & 0x7FFFFFFF;
				_peersLock.EnterReadLock();
				for (int num2 = _buckets[num % _buckets.Length] - 1; num2 >= 0; num2 = _slots[num2].Next)
				{
					if (_slots[num2].HashCode == num && _slots[num2].Value.Serialize().Equals(saddr))
					{
						actualValue = _slots[num2].Value;
						_peersLock.ExitReadLock();
						return true;
					}
				}
				_peersLock.ExitReadLock();
			}
			actualValue = null;
			return false;
		}

		protected bool AddPeerToSet(LiteNetPeer value)
		{
			if (_buckets == null)
			{
				int num = HashSetGetPrime(0);
				_buckets = new int[num];
				_slots = new Slot[num];
			}
			int num2 = value.GetHashCode() & 0x7FFFFFFF;
			int num3 = num2 % _buckets.Length;
			for (int num4 = _buckets[num2 % _buckets.Length] - 1; num4 >= 0; num4 = _slots[num4].Next)
			{
				if (_slots[num4].HashCode == num2 && _slots[num4].Value.Equals(value))
				{
					return false;
				}
			}
			int num5;
			if (_freeList >= 0)
			{
				num5 = _freeList;
				_freeList = _slots[num5].Next;
			}
			else
			{
				if (_lastIndex == _slots.Length)
				{
					int num6 = 2 * _count;
					num6 = (((uint)num6 > 2147483587u && 2147483587 > _count) ? 2147483587 : HashSetGetPrime(num6));
					Slot[] array = new Slot[num6];
					Array.Copy(_slots, 0, array, 0, _lastIndex);
					_buckets = new int[num6];
					for (int i = 0; i < _lastIndex; i++)
					{
						int num7 = array[i].HashCode % num6;
						array[i].Next = _buckets[num7] - 1;
						_buckets[num7] = i + 1;
					}
					_slots = array;
					num3 = num2 % _buckets.Length;
				}
				num5 = _lastIndex;
				_lastIndex++;
			}
			_slots[num5].HashCode = num2;
			_slots[num5].Value = value;
			_slots[num5].Next = _buckets[num3] - 1;
			_buckets[num3] = num5 + 1;
			_count++;
			return true;
		}

		private NetPacket PoolGetWithData(PacketProperty property, byte[] data, int start, int length)
		{
			int headerSize = NetPacket.GetHeaderSize(property);
			NetPacket netPacket = PoolGetPacket(length + headerSize);
			netPacket.Property = property;
			Buffer.BlockCopy(data, start, netPacket.RawData, headerSize, length);
			return netPacket;
		}

		private NetPacket PoolGetWithProperty(PacketProperty property, int size)
		{
			NetPacket netPacket = PoolGetPacket(size + NetPacket.GetHeaderSize(property));
			netPacket.Property = property;
			return netPacket;
		}

		private NetPacket PoolGetWithProperty(PacketProperty property)
		{
			NetPacket netPacket = PoolGetPacket(NetPacket.GetHeaderSize(property));
			netPacket.Property = property;
			return netPacket;
		}

		internal NetPacket PoolGetPacket(int size)
		{
			if (size > NetConstants.MaxPacketSize)
			{
				return new NetPacket(size);
			}
			NetPacket poolHead;
			lock (_poolLock)
			{
				poolHead = _poolHead;
				if (poolHead == null)
				{
					return new NetPacket(size);
				}
				_poolHead = _poolHead.Next;
				_poolCount--;
			}
			poolHead.Size = size;
			if (poolHead.RawData.Length < size)
			{
				poolHead.RawData = new byte[size];
			}
			return poolHead;
		}

		internal void PoolRecycle(NetPacket packet)
		{
			if (packet.RawData.Length > NetConstants.MaxPacketSize || _poolCount >= PacketPoolSize)
			{
				return;
			}
			packet.RawData[0] = 0;
			lock (_poolLock)
			{
				packet.Next = _poolHead;
				_poolHead = packet;
				_poolCount++;
			}
		}

		static LiteNetManager()
		{
			Primes = new int[72]
			{
				3, 7, 11, 17, 23, 29, 37, 47, 59, 71,
				89, 107, 131, 163, 197, 239, 293, 353, 431, 521,
				631, 761, 919, 1103, 1327, 1597, 1931, 2333, 2801, 3371,
				4049, 4861, 5839, 7013, 8419, 10103, 12143, 14591, 17519, 21023,
				25229, 30293, 36353, 43627, 52361, 62851, 75431, 90523, 108631, 130363,
				156437, 187751, 225307, 270371, 324449, 389357, 467237, 560689, 672827, 807403,
				968897, 1162687, 1395263, 1674319, 2009191, 2411033, 2893249, 3471899, 4166287, 4999559,
				5999471, 7199369
			};
			MulticastAddressV6 = IPAddress.Parse("ff02::1");
			IPv6Support = Socket.OSSupportsIPv6;
		}

		private bool ProcessError(SocketException ex)
		{
			switch (ex.SocketErrorCode)
			{
			case SocketError.NotConnected:
				NotConnected = true;
				return true;
			case SocketError.OperationAborted:
			case SocketError.Interrupted:
			case SocketError.NotSocket:
				return true;
			default:
				NetDebug.WriteError($"[R]Error code: {(int)ex.SocketErrorCode} - {ex}");
				CreateEvent(NetEvent.EType.Error, null, null, ex.SocketErrorCode, 0, DisconnectReason.ConnectionFailed, null, DeliveryMethod.Unreliable, 0);
				break;
			case SocketError.WouldBlock:
			case SocketError.MessageSize:
			case SocketError.NetworkReset:
			case SocketError.ConnectionReset:
			case SocketError.TimedOut:
				break;
			}
			return false;
		}

		private void ManualReceive(Socket socket, EndPoint bufferEndPoint)
		{
			try
			{
				int num = MaxPacketPerManualReceive;
				while (socket.Available > 0 && (num > 0 || MaxPacketPerManualReceive == 0) && ReceiveFrom(socket, ref bufferEndPoint) > 0)
				{
					num--;
				}
			}
			catch (SocketException ex)
			{
				ProcessError(ex);
			}
			catch (ObjectDisposedException)
			{
			}
			catch (Exception ex3)
			{
				NetDebug.WriteError("[NM] SocketReceiveThread error: " + ex3);
			}
		}

		private void NativeReceiveLogic()
		{
			IntPtr handle = _udpSocketv4.Handle;
			IntPtr s2 = _udpSocketv6?.Handle ?? IntPtr.Zero;
			byte[] address2 = new byte[16];
			byte[] address3 = new byte[28];
			IPEndPoint tempEndPoint = new IPEndPoint(IPAddress.Any, 0);
			List<Socket> list = new List<Socket>(2);
			Socket udpSocketv = _udpSocketv4;
			Socket udpSocketv2 = _udpSocketv6;
			NetPacket packet = PoolGetPacket(NetConstants.MaxPacketSize);
			while (_isRunning)
			{
				try
				{
					if (udpSocketv2 == null)
					{
						if (!NativeReceiveFrom(handle, address2))
						{
							break;
						}
						continue;
					}
					bool flag = false;
					if (udpSocketv.Available != 0 || list.Contains(udpSocketv))
					{
						if (!NativeReceiveFrom(handle, address2))
						{
							break;
						}
						flag = true;
					}
					if (udpSocketv2.Available != 0 || list.Contains(udpSocketv2))
					{
						if (!NativeReceiveFrom(s2, address3))
						{
							break;
						}
						flag = true;
					}
					list.Clear();
					if (!flag)
					{
						list.Add(udpSocketv);
						list.Add(udpSocketv2);
						Socket.Select(list, null, null, ReceivePollingTime);
					}
				}
				catch (SocketException ex)
				{
					if (ProcessError(ex))
					{
						break;
					}
				}
				catch (ObjectDisposedException)
				{
					break;
				}
				catch (ThreadAbortException)
				{
					break;
				}
				catch (Exception ex4)
				{
					NetDebug.WriteError("[NM] SocketReceiveThread error: " + ex4);
				}
			}
			bool NativeReceiveFrom(IntPtr s, byte[] address)
			{
				int socketAddressSize = address.Length;
				packet.Size = NativeSocket.RecvFrom(s, packet.RawData, NetConstants.MaxPacketSize, address, ref socketAddressSize);
				if (packet.Size == 0)
				{
					return true;
				}
				if (packet.Size == -1)
				{
					return !ProcessError(new SocketException((int)NativeSocket.GetSocketError()));
				}
				short num = (short)((address[1] << 8) | address[0]);
				tempEndPoint.Port = (ushort)((address[2] << 8) | address[3]);
				if ((NativeSocket.UnixMode && num == 10) || (!NativeSocket.UnixMode && num == 23))
				{
					uint num2 = (uint)((address[27] << 24) + (address[26] << 16) + (address[25] << 8) + address[24]);
					tempEndPoint.Address = new IPAddress(new ReadOnlySpan<byte>(address, 8, 16), num2);
				}
				else
				{
					long newAddress = (uint)((address[4] & 0xFF) | ((address[5] << 8) & 0xFF00) | ((address[6] << 16) & 0xFF0000) | (address[7] << 24));
					tempEndPoint.Address = new IPAddress(newAddress);
				}
				if (TryGetPeer(tempEndPoint, out var actualValue))
				{
					OnMessageReceived(packet, actualValue);
				}
				else
				{
					OnMessageReceived(packet, tempEndPoint);
					tempEndPoint = new IPEndPoint(IPAddress.Any, 0);
				}
				packet = PoolGetPacket(NetConstants.MaxPacketSize);
				return true;
			}
		}

		private int ReceiveFrom(Socket s, ref EndPoint bufferEndPoint)
		{
			NetPacket netPacket = PoolGetPacket(NetConstants.MaxPacketSize);
			netPacket.Size = s.ReceiveFrom(netPacket.RawData, 0, NetConstants.MaxPacketSize, SocketFlags.None, ref bufferEndPoint);
			OnMessageReceived(netPacket, (IPEndPoint)bufferEndPoint);
			return netPacket.Size;
		}

		private void ReceiveLogic()
		{
			EndPoint bufferEndPoint = new IPEndPoint(IPAddress.Any, 0);
			EndPoint bufferEndPoint2 = new IPEndPoint(IPAddress.IPv6Any, 0);
			List<Socket> list = new List<Socket>(2);
			Socket udpSocketv = _udpSocketv4;
			Socket udpSocketv2 = _udpSocketv6;
			while (_isRunning)
			{
				try
				{
					if (udpSocketv2 == null)
					{
						if (udpSocketv.Available != 0 || udpSocketv.Poll(ReceivePollingTime, SelectMode.SelectRead))
						{
							ReceiveFrom(udpSocketv, ref bufferEndPoint);
						}
						continue;
					}
					bool flag = false;
					if (udpSocketv.Available != 0 || list.Contains(udpSocketv))
					{
						ReceiveFrom(udpSocketv, ref bufferEndPoint);
						flag = true;
					}
					if (udpSocketv2.Available != 0 || list.Contains(udpSocketv2))
					{
						ReceiveFrom(udpSocketv2, ref bufferEndPoint2);
						flag = true;
					}
					list.Clear();
					if (!flag)
					{
						list.Add(udpSocketv);
						list.Add(udpSocketv2);
						Socket.Select(list, null, null, ReceivePollingTime);
					}
				}
				catch (SocketException ex)
				{
					if (ProcessError(ex))
					{
						break;
					}
				}
				catch (ObjectDisposedException)
				{
					break;
				}
				catch (ThreadAbortException)
				{
					break;
				}
				catch (Exception ex4)
				{
					NetDebug.WriteError("[NM] SocketReceiveThread error: " + ex4);
				}
			}
		}

		public bool Start(IPAddress addressIPv4, IPAddress addressIPv6, int port, bool manualMode)
		{
			if (IsRunning && !NotConnected)
			{
				return false;
			}
			NotConnected = false;
			_manualMode = manualMode;
			UseNativeSockets = UseNativeSockets && NativeSocket.IsSupported;
			_udpSocketv4 = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
			if (!BindSocket(_udpSocketv4, new IPEndPoint(addressIPv4, port)))
			{
				return false;
			}
			LocalPort = ((IPEndPoint)_udpSocketv4.LocalEndPoint).Port;
			_isRunning = true;
			if (_manualMode)
			{
				_bufferEndPointv4 = new IPEndPoint(IPAddress.Any, 0);
			}
			if (IPv6Support && IPv6Enabled)
			{
				_udpSocketv6 = new Socket(AddressFamily.InterNetworkV6, SocketType.Dgram, ProtocolType.Udp);
				if (BindSocket(_udpSocketv6, new IPEndPoint(addressIPv6, LocalPort)))
				{
					if (_manualMode)
					{
						_bufferEndPointv6 = new IPEndPoint(IPAddress.IPv6Any, 0);
					}
				}
				else
				{
					_udpSocketv6 = null;
				}
			}
			if (!manualMode)
			{
				ThreadStart start = ReceiveLogic;
				if (UseNativeSockets)
				{
					start = NativeReceiveLogic;
				}
				_receiveThread = new Thread(start)
				{
					Name = $"ReceiveThread({LocalPort})",
					IsBackground = true
				};
				_receiveThread.Start();
				if (_logicThread == null)
				{
					_logicThread = new Thread(UpdateLogic)
					{
						Name = "LogicThread",
						IsBackground = true
					};
					_logicThread.Start();
				}
			}
			return true;
		}

		private bool BindSocket(Socket socket, IPEndPoint ep)
		{
			socket.ReceiveTimeout = 500;
			socket.SendTimeout = 500;
			socket.ReceiveBufferSize = 1048576;
			socket.SendBufferSize = 1048576;
			socket.Blocking = true;
			if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
			{
				try
				{
					socket.IOControl(-1744830452, new byte[1], null);
				}
				catch
				{
				}
			}
			try
			{
				socket.ExclusiveAddressUse = !ReuseAddress;
				socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, ReuseAddress);
				socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontRoute, DontRoute);
			}
			catch
			{
			}
			if (ep.AddressFamily == AddressFamily.InterNetwork)
			{
				Ttl = 255;
				try
				{
					socket.EnableBroadcast = true;
				}
				catch (SocketException ex)
				{
					NetDebug.WriteError($"[B]Broadcast error: {ex.SocketErrorCode}");
				}
				if (!RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
				{
					try
					{
						socket.DontFragment = true;
					}
					catch (SocketException ex2)
					{
						NetDebug.WriteError($"[B]DontFragment error: {ex2.SocketErrorCode}");
					}
				}
			}
			try
			{
				socket.Bind(ep);
				if (ep.AddressFamily == AddressFamily.InterNetworkV6)
				{
					try
					{
						socket.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.AddMembership, new IPv6MulticastOption(MulticastAddressV6));
					}
					catch (Exception)
					{
					}
				}
			}
			catch (SocketException ex4)
			{
				switch (ex4.SocketErrorCode)
				{
				case SocketError.AddressAlreadyInUse:
					if (socket.AddressFamily == AddressFamily.InterNetworkV6)
					{
						try
						{
							socket.DualMode = false;
							socket.Bind(ep);
						}
						catch (SocketException ex5)
						{
							NetDebug.WriteError($"[B]Bind exception: {ex5}, errorCode: {ex5.SocketErrorCode}");
							return false;
						}
						return true;
					}
					break;
				case SocketError.AddressFamilyNotSupported:
					return true;
				}
				NetDebug.WriteError($"[B]Bind exception: {ex4}, errorCode: {ex4.SocketErrorCode}");
				return false;
			}
			return true;
		}

		internal int SendRawAndRecycle(NetPacket packet, IPEndPoint remoteEndPoint)
		{
			int result = SendRaw(packet.RawData, 0, packet.Size, remoteEndPoint);
			PoolRecycle(packet);
			return result;
		}

		internal int SendRaw(NetPacket packet, IPEndPoint remoteEndPoint)
		{
			return SendRaw(packet.RawData, 0, packet.Size, remoteEndPoint);
		}

		internal int SendRaw(byte[] message, int start, int length, IPEndPoint remoteEndPoint)
		{
			if (!_isRunning)
			{
				return 0;
			}
			NetPacket netPacket = null;
			if (_extraPacketLayer != null)
			{
				netPacket = PoolGetPacket(length + _extraPacketLayer.ExtraPacketSizeForLayer);
				Buffer.BlockCopy(message, start, netPacket.RawData, 0, length);
				start = 0;
				_extraPacketLayer.ProcessOutBoundPacket(ref remoteEndPoint, ref netPacket.RawData, ref start, ref length);
				message = netPacket.RawData;
			}
			int result = SendRawCore(message, start, length, remoteEndPoint);
			if (netPacket != null)
			{
				PoolRecycle(netPacket);
			}
			return result;
		}

		internal unsafe int SendRawCore(byte[] message, int start, int length, IPEndPoint remoteEndPoint)
		{
			if (!_isRunning)
			{
				return 0;
			}
			Socket socket = _udpSocketv4;
			if (remoteEndPoint.AddressFamily == AddressFamily.InterNetworkV6 && IPv6Support)
			{
				socket = _udpSocketv6;
				if (socket == null)
				{
					return 0;
				}
			}
			int num;
			try
			{
				if (UseNativeSockets && remoteEndPoint is LiteNetPeer liteNetPeer)
				{
					fixed (byte* pinnedBuffer = &message[start])
					{
						num = NativeSocket.SendTo(socket.Handle, pinnedBuffer, length, liteNetPeer.NativeAddress, liteNetPeer.NativeAddress.Length);
					}
					if (num == -1)
					{
						throw NativeSocket.GetSocketException();
					}
				}
				else
				{
					num = socket.SendTo(message, start, length, SocketFlags.None, remoteEndPoint);
				}
			}
			catch (SocketException ex)
			{
				switch (ex.SocketErrorCode)
				{
				case SocketError.Interrupted:
				case SocketError.NoBufferSpaceAvailable:
					return 0;
				case SocketError.MessageSize:
					return 0;
				case SocketError.NetworkUnreachable:
				case SocketError.HostUnreachable:
					if (DisconnectOnUnreachable && remoteEndPoint is LiteNetPeer peer)
					{
						DisconnectPeerForce(peer, (ex.SocketErrorCode == SocketError.HostUnreachable) ? DisconnectReason.HostUnreachable : DisconnectReason.NetworkUnreachable, ex.SocketErrorCode, null);
					}
					CreateEvent(NetEvent.EType.Error, null, remoteEndPoint, ex.SocketErrorCode, 0, DisconnectReason.ConnectionFailed, null, DeliveryMethod.Unreliable, 0);
					return -1;
				case SocketError.Shutdown:
					CreateEvent(NetEvent.EType.Error, null, remoteEndPoint, ex.SocketErrorCode, 0, DisconnectReason.ConnectionFailed, null, DeliveryMethod.Unreliable, 0);
					return -1;
				default:
					NetDebug.WriteError($"[S] {ex}");
					return -1;
				}
			}
			catch (Exception arg)
			{
				NetDebug.WriteError($"[S] {arg}");
				return 0;
			}
			if (num <= 0)
			{
				return 0;
			}
			if (EnableStatistics)
			{
				Statistics.IncrementPacketsSent();
				Statistics.AddBytesSent(length);
			}
			return num;
		}

		public bool SendBroadcast(NetDataWriter writer, int port)
		{
			return SendBroadcast(writer.Data, 0, writer.Length, port);
		}

		public bool SendBroadcast(byte[] data, int port)
		{
			return SendBroadcast(data, 0, data.Length, port);
		}

		public bool SendBroadcast(byte[] data, int start, int length, int port)
		{
			if (!IsRunning)
			{
				return false;
			}
			NetPacket netPacket;
			if (_extraPacketLayer != null)
			{
				int headerSize = NetPacket.GetHeaderSize(PacketProperty.Broadcast);
				netPacket = PoolGetPacket(headerSize + length + _extraPacketLayer.ExtraPacketSizeForLayer);
				netPacket.Property = PacketProperty.Broadcast;
				Buffer.BlockCopy(data, start, netPacket.RawData, headerSize, length);
				int offset = 0;
				int length2 = length + headerSize;
				IPEndPoint endPoint = null;
				_extraPacketLayer.ProcessOutBoundPacket(ref endPoint, ref netPacket.RawData, ref offset, ref length2);
			}
			else
			{
				netPacket = PoolGetWithData(PacketProperty.Broadcast, data, start, length);
			}
			bool flag = false;
			bool flag2 = false;
			try
			{
				flag = _udpSocketv4.SendTo(netPacket.RawData, 0, netPacket.Size, SocketFlags.None, new IPEndPoint(IPAddress.Broadcast, port)) > 0;
				if (_udpSocketv6 != null)
				{
					flag2 = _udpSocketv6.SendTo(netPacket.RawData, 0, netPacket.Size, SocketFlags.None, new IPEndPoint(MulticastAddressV6, port)) > 0;
				}
			}
			catch (SocketException ex)
			{
				if (ex.SocketErrorCode == SocketError.HostUnreachable)
				{
					return flag;
				}
				NetDebug.WriteError($"[S][MCAST] {ex}");
				return flag;
			}
			catch (Exception arg)
			{
				NetDebug.WriteError($"[S][MCAST] {arg}");
				return flag;
			}
			finally
			{
				PoolRecycle(netPacket);
			}
			return flag || flag2;
		}

		private void CloseSocket()
		{
			_isRunning = false;
			if (_receiveThread != null && _receiveThread != Thread.CurrentThread)
			{
				_receiveThread.Join();
			}
			_receiveThread = null;
			_udpSocketv4?.Close();
			_udpSocketv6?.Close();
			_udpSocketv4 = null;
			_udpSocketv6 = null;
		}
	}
	[Flags]
	public enum ConnectionState : byte
	{
		Outgoing = 2,
		Connected = 4,
		ShutdownRequested = 8,
		Disconnected = 0x10,
		EndPointChange = 0x20,
		Any = 0x2E
	}
	internal enum ConnectRequestResult
	{
		None,
		P2PLose,
		Reconnection,
		NewConnection
	}
	internal enum DisconnectResult
	{
		None,
		Reject,
		Disconnect
	}
	internal enum ShutdownResult
	{
		None,
		Success,
		WasConnected
	}
	public class LiteNetPeer : IPEndPoint
	{
		private sealed class IncomingFragments
		{
			public readonly NetPacket[] Fragments;

			public readonly ushort TotalFragments;

			public readonly byte ChannelId;

			public int ReceivedCount;

			public int TotalSize;

			public IncomingFragments(ushort totalFragments, byte channelId)
			{
				TotalFragments = totalFragments;
				ChannelId = channelId;
				Fragments = new NetPacket[totalFragments];
			}

			public void RecycleAll(LiteNetManager netManager)
			{
				for (int i = 0; i < Fragments.Length; i++)
				{
					NetPacket netPacket = Fragments[i];
					if (netPacket != null)
					{
						netManager.PoolRecycle(netPacket);
						Fragments[i] = null;
					}
				}
			}
		}

		private int _rtt;

		private int _avgRtt;

		private int _rttCount;

		private float _resendDelay = 27f;

		private float _pingSendTimer;

		private float _rttResetTimer;

		private readonly Stopwatch _pingTimer = new Stopwatch();

		private float _timeSinceLastPacket;

		private long _remoteDelta;

		private readonly object _shutdownLock = new object();

		internal volatile LiteNetPeer NextPeer;

		internal LiteNetPeer PrevPeer;

		private NetPacket[] _unreliableSecondQueue;

		private NetPacket[] _unreliableChannel;

		private int _unreliablePendingCount;

		private readonly object _unreliableChannelLock = new object();

		private int _mtu;

		private int _mtuIdx;

		private bool _finishMtu;

		private float _mtuCheckTimer;

		private int _mtuCheckAttempts;

		private const int MtuCheckDelay = 1000;

		private const int MaxMtuCheckAttempts = 4;

		private readonly object _mtuMutex = new object();

		private int _fragmentId;

		private readonly Dictionary<ushort, IncomingFragments> _holdedFragments;

		private readonly Dictionary<ushort, ushort> _deliveredFragments;

		private readonly NetPacket _mergeData;

		private int _mergePos;

		private int _mergeCount;

		private int _connectAttempts;

		private float _connectTimer;

		private long _connectTime;

		private byte _connectNum;

		private ConnectionState _connectionState;

		private NetPacket _shutdownPacket;

		private const int ShutdownDelay = 300;

		private float _shutdownTimer;

		private readonly NetPacket _pingPacket;

		private readonly NetPacket _pongPacket;

		private readonly NetPacket _connectRequestPacket;

		private readonly NetPacket _connectAcceptPacket;

		public readonly LiteNetManager NetManager;

		public readonly int Id;

		public float ResendFixedDelay = 25f;

		public float ResendRttMultiplier = 2.1f;

		public object Tag;

		public readonly NetStatistics Statistics;

		private SocketAddress _cachedSocketAddr;

		private int _cachedHashCode;

		private ReliableChannel _reliableChannel;

		private ReliableChannel _reliableUnorderedChannel;

		private SequencedChannel _sequencedChannel;

		internal byte[] NativeAddress;

		internal byte ConnectionNum
		{
			get
			{
				return _connectNum;
			}
			private set
			{
				_connectNum = value;
				_mergeData.ConnectionNumber = value;
				_pingPacket.ConnectionNumber = value;
				_pongPacket.ConnectionNumber = value;
			}
		}

		public ConnectionState ConnectionState => _connectionState;

		internal long ConnectTime => _connectTime;

		public int RemoteId { get; private set; }

		public int Ping => _avgRtt / 2;

		public int RoundTripTime => _avgRtt;

		public int Mtu => _mtu;

		public long RemoteTimeDelta => _remoteDelta;

		public DateTime RemoteUtcTime => new DateTime(DateTime.UtcNow.Ticks + _remoteDelta);

		public float TimeSinceLastPacket => _timeSinceLastPacket;

		internal float ResendDelay => _resendDelay;

		protected virtual int ChannelsCount => 1;

		public override SocketAddress Serialize()
		{
			return _cachedSocketAddr;
		}

		public override int GetHashCode()
		{
			return _cachedHashCode;
		}

		internal LiteNetPeer(LiteNetManager netManager, IPEndPoint remoteEndPoint, int id)
			: base(remoteEndPoint.Address, remoteEndPoint.Port)
		{
			Id = id;
			Statistics = new NetStatistics();
			NetManager = netManager;
			_cachedSocketAddr = base.Serialize();
			if (NetManager.UseNativeSockets)
			{
				NativeAddress = new byte[_cachedSocketAddr.Size];
				for (int i = 0; i < _cachedSocketAddr.Size; i++)
				{
					NativeAddress[i] = _cachedSocketAddr[i];
				}
			}
			_cachedHashCode = base.GetHashCode();
			ResetMtu();
			_connectionState = ConnectionState.Connected;
			_mergeData = new NetPacket(PacketProperty.Merged, NetConstants.MaxPacketSize);
			_pongPacket = new NetPacket(PacketProperty.Pong, 0);
			_pingPacket = new NetPacket(PacketProperty.Ping, 0)
			{
				Sequence = 1
			};
			_unreliableSecondQueue = new NetPacket[8];
			_unreliableChannel = new NetPacket[8];
			_holdedFragments = new Dictionary<ushort, IncomingFragments>();
			_deliveredFragments = new Dictionary<ushort, ushort>();
		}

		internal void InitiateEndPointChange()
		{
			ResetMtu();
			_connectionState = ConnectionState.EndPointChange;
		}

		internal void FinishEndPointChange(IPEndPoint newEndPoint)
		{
			if (_connectionState != ConnectionState.EndPointChange)
			{
				return;
			}
			_connectionState = ConnectionState.Connected;
			base.Address = newEndPoint.Address;
			base.Port = newEndPoint.Port;
			_cachedSocketAddr = base.Serialize();
			if (NetManager.UseNativeSockets)
			{
				NativeAddress = new byte[_cachedSocketAddr.Size];
				for (int i = 0; i < _cachedSocketAddr.Size; i++)
				{
					NativeAddress[i] = _cachedSocketAddr[i];
				}
			}
			_cachedHashCode = base.GetHashCode();
		}

		internal void ResetMtu()
		{
			_finishMtu = !NetManager.MtuDiscovery;
			if (NetManager.MtuOverride > 0)
			{
				OverrideMtu(NetManager.MtuOverride);
			}
			else
			{
				SetMtu(0);
			}
		}

		private void SetMtu(int mtuIdx)
		{
			_mtuIdx = mtuIdx;
			_mtu = NetConstants.PossibleMtu[mtuIdx] - NetManager.ExtraPacketSizeForLayer;
		}

		private void OverrideMtu(int mtuValue)
		{
			_mtu = mtuValue;
			_finishMtu = true;
		}

		public int GetPacketsCountInReliableQueue(bool ordered)
		{
			return (ordered ? _reliableChannel : _reliableUnorderedChannel)?.PacketsInQueue ?? 0;
		}

		public PooledPacket CreatePacketFromPool(DeliveryMethod deliveryMethod)
		{
			int mtu = _mtu;
			NetPacket netPacket = NetManager.PoolGetPacket(mtu);
			if (deliveryMethod == DeliveryMethod.Unreliable)
			{
				netPacket.Property = PacketProperty.Unreliable;
				return new PooledPacket(netPacket, mtu, 0);
			}
			netPacket.Property = PacketProperty.Channeled;
			return new PooledPacket(netPacket, mtu, (byte)deliveryMethod);
		}

		public void SendPooledPacket(PooledPacket packet, int userDataSize)
		{
			if (_connectionState != ConnectionState.Connected)
			{
				return;
			}
			packet._packet.Size = packet.UserDataOffset + userDataSize;
			if (packet._packet.Property == PacketProperty.Channeled)
			{
				CreateChannel(packet._channelNumber).AddToQueue(packet._packet);
				return;
			}
			lock (_unreliableChannelLock)
			{
				if (_unreliablePendingCount == _unreliableChannel.Length)
				{
					Array.Resize(ref _unreliableChannel, _unreliablePendingCount * 2);
				}
				_unreliableChannel[_unreliablePendingCount++] = packet._packet;
			}
		}

		internal virtual BaseChannel CreateChannel(byte channelNumber)
		{
			switch ((DeliveryMethod)channelNumber)
			{
			case DeliveryMethod.ReliableOrdered:
			case DeliveryMethod.ReliableSequenced:
				return _reliableChannel ?? (_reliableChannel = new ReliableChannel(this, ordered: true, 2));
			case DeliveryMethod.ReliableUnordered:
				return _reliableUnorderedChannel ?? (_reliableUnorderedChannel = new ReliableChannel(this, ordered: false, channelNumber));
			case DeliveryMethod.Sequenced:
				return _sequencedChannel ?? (_sequencedChannel = new SequencedChannel(this, reliable: true, channelNumber));
			default:
				throw new Exception("Invalid channel type");
			}
		}

		internal LiteNetPeer(LiteNetManager netManager, IPEndPoint remoteEndPoint, int id, byte connectNum, ReadOnlySpan<byte> connectData)
			: this(netManager, remoteEndPoint, id)
		{
			_connectTime = DateTime.UtcNow.Ticks;
			_connectionState = ConnectionState.Outgoing;
			ConnectionNum = connectNum;
			_connectRequestPacket = NetConnectRequestPacket.Make(connectData, remoteEndPoint.Serialize(), _connectTime, id);
			_connectRequestPacket.ConnectionNumber = connectNum;
			NetManager.SendRaw(_connectRequestPacket, this);
		}

		internal LiteNetPeer(LiteNetManager netManager, LiteConnectionRequest request, int id)
			: this(netManager, request.RemoteEndPoint, id)
		{
			_connectTime = request.InternalPacket.ConnectionTime;
			ConnectionNum = request.InternalPacket.ConnectionNumber;
			RemoteId = request.InternalPacket.PeerId;
			_connectAcceptPacket = NetConnectAcceptPacket.Make(_connectTime, ConnectionNum, id);
			_connectionState = ConnectionState.Connected;
			NetManager.SendRaw(_connectAcceptPacket, this);
		}

		internal void Reject(NetConnectRequestPacket requestData, byte[] data, int start, int length)
		{
			_connectTime = requestData.ConnectionTime;
			_connectNum = requestData.ConnectionNumber;
			Shutdown(data, start, length, force: false);
		}

		internal bool ProcessConnectAccept(NetConnectAcceptPacket packet)
		{
			if (_connectionState != ConnectionState.Outgoing)
			{
				return false;
			}
			if (packet.ConnectionTime != _connectTime)
			{
				return false;
			}
			ConnectionNum = packet.ConnectionNumber;
			RemoteId = packet.PeerId;
			Interlocked.Exchange(ref _timeSinceLastPacket, 0f);
			_connectionState = ConnectionState.Connected;
			return true;
		}

		public int GetMaxSinglePacketSize(DeliveryMethod options)
		{
			return _mtu - NetPacket.GetHeaderSize((options != DeliveryMethod.Unreliable) ? PacketProperty.Channeled : PacketProperty.Unreliable);
		}

		public void SendWithDeliveryEvent(byte[] data, DeliveryMethod deliveryMethod, object userData)
		{
			if (deliveryMethod != DeliveryMethod.ReliableOrdered && deliveryMethod != 0)
			{
				throw new ArgumentException("Delivery event will work only for ReliableOrdered/Unordered packets");
			}
			SendInternal(new ReadOnlySpan<byte>(data, 0, data.Length), 0, deliveryMethod, userData);
		}

		public void SendWithDeliveryEvent(byte[] data, int start, int length, DeliveryMethod deliveryMethod, object userData)
		{
			if (deliveryMethod != DeliveryMethod.ReliableOrdered && deliveryMethod != 0)
			{
				throw new ArgumentException("Delivery event will work only for ReliableOrdered/Unordered packets");
			}
			SendInternal(new ReadOnlySpan<byte>(data, start, length), 0, deliveryMethod, userData);
		}

		public void SendWithDeliveryEvent(NetDataWriter dataWriter, DeliveryMethod deliveryMethod, object userData)
		{
			if (deliveryMethod != DeliveryMethod.ReliableOrdered && deliveryMethod != 0)
			{
				throw new ArgumentException("Delivery event will work only for ReliableOrdered/Unordered packets");
			}
			SendInternal(dataWriter.AsReadOnlySpan(), 0, deliveryMethod, userData);
		}

		public void Send(byte[] data, DeliveryMethod deliveryMethod)
		{
			SendInternal(new ReadOnlySpan<byte>(data, 0, data.Length), 0, deliveryMethod, null);
		}

		public void Send(NetDataWriter dataWriter, DeliveryMethod deliveryMethod)
		{
			SendInternal(dataWriter.AsReadOnlySpan(), 0, deliveryMethod, null);
		}

		public void Send(byte[] data, int start, int length, DeliveryMethod options)
		{
			SendInternal(new ReadOnlySpan<byte>(data, start, length), 0, options, null);
		}

		public void SendWithDeliveryEvent(ReadOnlySpan<byte> data, DeliveryMethod deliveryMethod, object userData)
		{
			if (deliveryMethod != DeliveryMethod.ReliableOrdered && deliveryMethod != 0)
			{
				throw new ArgumentException("Delivery event will work only for ReliableOrdered/Unordered packets");
			}
			SendInternal(data, 0, deliveryMethod, userData);
		}

		public void Send(ReadOnlySpan<byte> data, DeliveryMethod deliveryMethod)
		{
			SendInternal(data, 0, deliveryMethod, null);
		}

		protected void SendInternal(ReadOnlySpan<byte> data, byte channelNumber, DeliveryMethod deliveryMethod, object userData)
		{
			if (_connectionState != ConnectionState.Connected || channelNumber >= ChannelsCount)
			{
				return;
			}
			BaseChannel baseChannel = null;
			PacketProperty property;
			if (deliveryMethod == DeliveryMethod.Unreliable)
			{
				property = PacketProperty.Unreliable;
			}
			else
			{
				property = PacketProperty.Channeled;
				baseChannel = CreateChannel((byte)((uint)(channelNumber * 4) + (uint)deliveryMethod));
			}
			int headerSize = NetPacket.GetHeaderSize(property);
			int mtu = _mtu;
			int num = data.Length;
			if (num + headerSize > mtu)
			{
				if (deliveryMethod != DeliveryMethod.ReliableOrdered && deliveryMethod != 0)
				{
					throw new TooBigPacketException("Unreliable or ReliableSequenced packet size exceeded maximum of " + (mtu - headerSize) + " bytes, Check allowed size by GetMaxSinglePacketSize()");
				}
				int num2 = mtu - headerSize - 6;
				int num3 = num / num2 + ((num % num2 != 0) ? 1 : 0);
				if (num3 > NetManager.MaxFragmentsCount)
				{
					throw new TooBigPacketException("Data was split in " + num3 + " fragments, which exceeds " + NetManager.MaxFragmentsCount);
				}
				ushort fragmentId = (ushort)Interlocked.Increment(ref _fragmentId);
				for (ushort num4 = 0; num4 < num3; num4++)
				{
					int num5 = ((num > num2) ? num2 : num);
					NetPacket netPacket = NetManager.PoolGetPacket(headerSize + num5 + 6);
					netPacket.Property = property;
					netPacket.UserData = userData;
					netPacket.FragmentId = fragmentId;
					netPacket.FragmentPart = num4;
					netPacket.FragmentsTotal = (ushort)num3;
					netPacket.MarkFragmented();
					data.Slice(num4 * num2, num5).CopyTo(new Span<byte>(netPacket.RawData, 10, num5));
					baseChannel.AddToQueue(netPacket);
					num -= num5;
				}
				return;
			}
			NetPacket netPacket2 = NetManager.PoolGetPacket(headerSize + num);
			netPacket2.Property = property;
			data.CopyTo(new Span<byte>(netPacket2.RawData, headerSize, num));
			netPacket2.UserData = userData;
			if (baseChannel == null)
			{
				lock (_unreliableChannelLock)
				{
					if (_unreliablePendingCount == _unreliableChannel.Length)
					{
						Array.Resize(ref _unreliableChannel, _unreliablePendingCount * 2);
					}
					_unreliableChannel[_unreliablePendingCount++] = netPacket2;
					return;
				}
			}
			baseChannel.AddToQueue(netPacket2);
		}

		public void Disconnect(byte[] data)
		{
			NetManager.DisconnectPeer(this, data);
		}

		public void Disconnect(NetDataWriter writer)
		{
			NetManager.DisconnectPeer(this, writer);
		}

		public void Disconnect(byte[] data, int start, int count)
		{
			NetManager.DisconnectPeer(this, data, start, count);
		}

		public void Disconnect()
		{
			NetManager.DisconnectPeer(this);
		}

		internal DisconnectResult ProcessDisconnect(NetPacket packet)
		{
			if ((_connectionState == ConnectionState.Connected || _connectionState == ConnectionState.Outgoing) && packet.Size >= 9 && BitConverter.ToInt64(packet.RawData, 1) == _connectTime && packet.ConnectionNumber == _connectNum)
			{
				if (_connectionState != ConnectionState.Connected)
				{
					return DisconnectResult.Reject;
				}
				return DisconnectResult.Disconnect;
			}
			return DisconnectResult.None;
		}

		internal virtual void AddToReliableChannelSendQueue(BaseChannel channel)
		{
		}

		internal ShutdownResult Shutdown(byte[] data, int start, int length, bool force)
		{
			lock (_shutdownLock)
			{
				if (_connectionState == ConnectionState.Disconnected || _connectionState == ConnectionState.ShutdownRequested)
				{
					return ShutdownResult.None;
				}
				ShutdownResult result = ((_connectionState != ConnectionState.Connected) ? ShutdownResult.Success : ShutdownResult.WasConnected);
				if (force)
				{
					_connectionState = ConnectionState.Disconnected;
					return result;
				}
				Interlocked.Exchange(ref _timeSinceLastPacket, 0f);
				_shutdownPacket = new NetPacket(PacketProperty.Disconnect, length)
				{
					ConnectionNumber = _connectNum
				};
				FastBitConverter.GetBytes(_shutdownPacket.RawData, 1, _connectTime);
				if (_shutdownPacket.Size >= _mtu)
				{
					NetDebug.WriteError("[Peer] Disconnect additional data size more than MTU - 8!");
				}
				else if (data != null && length > 0)
				{
					Buffer.BlockCopy(data, start, _shutdownPacket.RawData, 9, length);
				}
				_connectionState = ConnectionState.ShutdownRequested;
				NetManager.SendRaw(_shutdownPacket, this);
				return result;
			}
		}

		private void UpdateRoundTripTime(int roundTripTime)
		{
			_rtt += roundTripTime;
			_rttCount++;
			_avgRtt = _rtt / _rttCount;
			_resendDelay = ResendFixedDelay + (float)_avgRtt * ResendRttMultiplier;
		}

		internal void AddReliablePacket(DeliveryMethod method, NetPacket p)
		{
			ushort packetFragId;
			IncomingFragments incomingFragments;
			NetPacket resultingPacket;
			if (p.IsFragmented)
			{
				if (p.FragmentsTotal == 0 || p.FragmentsTotal > NetManager.MaxFragmentsCount)
				{
					NetManager.PoolRecycle(p);
					NetDebug.WriteError($"Invalid FragmentsTotal: {p.FragmentsTotal}");
					return;
				}
				if (p.FragmentPart >= p.FragmentsTotal)
				{
					NetManager.PoolRecycle(p);
					NetDebug.WriteError($"FragmentPart {p.FragmentPart} >= FragmentsTotal {p.FragmentsTotal}");
					return;
				}
				packetFragId = p.FragmentId;
				byte channelId = p.ChannelId;
				if (!_holdedFragments.TryGetValue(packetFragId, out incomingFragments))
				{
					if (_holdedFragments.Count >= 32 * ChannelsCount * 2)
					{
						NetManager.PoolRecycle(p);
						return;
					}
					incomingFragments = new IncomingFragments(p.FragmentsTotal, p.ChannelId);
					_holdedFragments.Add(packetFragId, incomingFragments);
				}
				else if (p.FragmentsTotal != incomingFragments.TotalFragments || p.ChannelId != incomingFragments.ChannelId)
				{
					NetManager.PoolRecycle(p);
					NetDebug.WriteError("Fragment metadata mismatch");
					return;
				}
				NetPacket[] fragments = incomingFragments.Fragments;
				if (fragments[p.FragmentPart] != null)
				{
					NetManager.PoolRecycle(p);
					NetDebug.WriteError("Invalid fragment packet");
					return;
				}
				fragments[p.FragmentPart] = p;
				incomingFragments.ReceivedCount++;
				incomingFragments.TotalSize += p.Size - 10;
				if (incomingFragments.ReceivedCount != incomingFragments.TotalFragments)
				{
					return;
				}
				resultingPacket = NetManager.PoolGetPacket(incomingFragments.TotalSize);
				int num = 0;
				for (ushort num2 = 0; num2 < incomingFragments.TotalFragments; num2++)
				{
					NetPacket netPacket = fragments[num2];
					if (netPacket == null)
					{
						AbortReassembly($"Fragment {num2} missing during reassembly");
						return;
					}
					if (netPacket.Size > netPacket.RawData.Length)
					{
						AbortReassembly($"Fragment error size: {netPacket.Size} > fragment.RawData.Length: {netPacket.RawData.Length}");
						return;
					}
					int num3 = netPacket.Size - 10;
					if (num + num3 > resultingPacket.RawData.Length)
					{
						AbortReassembly($"Fragment error pos: {num + num3} >= resultPacketSize: {resultingPacket.RawData.Length}");
						return;
					}
					Buffer.BlockCopy(netPacket.RawData, 10, resultingPacket.RawData, num, num3);
					num += num3;
					NetManager.PoolRecycle(netPacket);
					fragments[num2] = null;
				}
				_holdedFragments.Remove(packetFragId);
				NetManager.CreateReceiveEvent(resultingPacket, method, (byte)(channelId / 4), 0, this);
			}
			else
			{
				NetManager.CreateReceiveEvent(p, method, (byte)(p.ChannelId / 4), 4, this);
			}
			void AbortReassembly(string error)
			{
				_holdedFragments.Remove(packetFragId);
				incomingFragments.RecycleAll(NetManager);
				NetManager.PoolRecycle(resultingPacket);
				NetDebug.WriteError(error);
			}
		}

		private void ProcessMtuPacket(NetPacket packet)
		{
			if (packet.Size < NetConstants.PossibleMtu[0])
			{
				return;
			}
			int num = BitConverter.ToInt32(packet.RawData, 1);
			int num2 = BitConverter.ToInt32(packet.RawData, packet.Size - 4);
			if (num != packet.Size || num != num2 || num > NetConstants.MaxPacketSize)
			{
				NetDebug.WriteError($"[MTU] Broken packet. RMTU {num}, EMTU {num2}, PSIZE {packet.Size}");
			}
			else if (packet.Property == PacketProperty.MtuCheck)
			{
				_mtuCheckAttempts = 0;
				packet.Property = PacketProperty.MtuOk;
				NetManager.SendRawAndRecycle(packet, this);
			}
			else if (num > _mtu && !_finishMtu && num == NetConstants.PossibleMtu[_mtuIdx + 1] - NetManager.ExtraPacketSizeForLayer)
			{
				lock (_mtuMutex)
				{
					SetMtu(_mtuIdx + 1);
				}
				if (_mtuIdx == NetConstants.PossibleMtu.Length - 1)
				{
					_finishMtu = true;
				}
				NetManager.PoolRecycle(packet);
			}
		}

		private void UpdateMtuLogic(float deltaTime)
		{
			if (_finishMtu)
			{
				return;
			}
			_mtuCheckTimer += deltaTime;
			if (_mtuCheckTimer < 1000f)
			{
				return;
			}
			_mtuCheckTimer = 0f;
			_mtuCheckAttempts++;
			if (_mtuCheckAttempts >= 4)
			{
				_finishMtu = true;
				return;
			}
			lock (_mtuMutex)
			{
				if (_mtuIdx < NetConstants.PossibleMtu.Length - 1)
				{
					int num = NetConstants.PossibleMtu[_mtuIdx + 1] - NetManager.ExtraPacketSizeForLayer;
					NetPacket netPacket = NetManager.PoolGetPacket(num);
					netPacket.Property = PacketProperty.MtuCheck;
					FastBitConverter.GetBytes(netPacket.RawData, 1, num);
					FastBitConverter.GetBytes(netPacket.RawData, netPacket.Size - 4, num);
					if (NetManager.SendRawAndRecycle(netPacket, this) <= 0)
					{
						_finishMtu = true;
					}
				}
			}
		}

		internal ConnectRequestResult ProcessConnectRequest(NetConnectRequestPacket connRequest)
		{
			switch (_connectionState)
			{
			case ConnectionState.Outgoing:
			{
				if (connRequest.ConnectionTime < _connectTime)
				{
					return ConnectRequestResult.P2PLose;
				}
				if (connRequest.ConnectionTime != _connectTime)
				{
					break;
				}
				byte[] targetAddress = connRequest.TargetAddress;
				for (int num = _cachedSocketAddr.Size - 1; num >= 0; num--)
				{
					byte b = _cachedSocketAddr[num];
					if (b != targetAddress[num] && b < targetAddress[num])
					{
						return ConnectRequestResult.P2PLose;
					}
				}
				break;
			}
			case ConnectionState.Connected:
				if (connRequest.ConnectionTime == _connectTime)
				{
					NetManager.SendRaw(_connectAcceptPacket, this);
				}
				else if (connRequest.ConnectionTime > _connectTime)
				{
					return ConnectRequestResult.Reconnection;
				}
				break;
			case ConnectionState.ShutdownRequested:
			case ConnectionState.Disconnected:
				if (connRequest.ConnectionTime >= _connectTime)
				{
					return ConnectRequestResult.NewConnection;
				}
				break;
			}
			return ConnectRequestResult.None;
		}

		internal virtual void ProcessChanneled(NetPacket packet)
		{
			if (packet.ChannelId >= 4 || packet.ChannelId == 3)
			{
				NetManager.PoolRecycle(packet);
			}
			else if (!CreateChannel(packet.ChannelId).ProcessPacket(packet))
			{
				NetManager.PoolRecycle(packet);
			}
		}

		internal void ProcessPacket(NetPacket packet)
		{
			if (_connectionState == ConnectionState.Outgoing || _connectionState == ConnectionState.Disconnected)
			{
				NetManager.PoolRecycle(packet);
				return;
			}
			if (packet.Property == PacketProperty.ShutdownOk)
			{
				if (_connectionState == ConnectionState.ShutdownRequested)
				{
					_connectionState = ConnectionState.Disconnected;
				}
				NetManager.PoolRecycle(packet);
				return;
			}
			if (packet.ConnectionNumber != _connectNum)
			{
				NetManager.PoolRecycle(packet);
				return;
			}
			Interlocked.Exchange(ref _timeSinceLastPacket, 0f);
			switch (packet.Property)
			{
			case PacketProperty.Merged:
			{
				int num2 = 1;
				while (num2 < packet.Size)
				{
					ushort num3 = BitConverter.ToUInt16(packet.RawData, num2);
					if (num3 == 0)
					{
						break;
					}
					num2 += 2;
					if (packet.Size - num2 < num3)
					{
						break;
					}
					NetPacket netPacket = NetManager.PoolGetPacket(num3);
					Buffer.BlockCopy(packet.RawData, num2, netPacket.RawData, 0, num3);
					netPacket.Size = num3;
					if (!netPacket.Verify())
					{
						break;
					}
					num2 += num3;
					ProcessPacket(netPacket);
				}
				NetManager.PoolRecycle(packet);
				break;
			}
			case PacketProperty.Ping:
				if (NetUtils.RelativeSequenceNumber(packet.Sequence, _pongPacket.Sequence) > 0)
				{
					FastBitConverter.GetBytes(_pongPacket.RawData, 3, DateTime.UtcNow.Ticks);
					_pongPacket.Sequence = packet.Sequence;
					NetManager.SendRaw(_pongPacket, this);
				}
				NetManager.PoolRecycle(packet);
				break;
			case PacketProperty.Pong:
				if (packet.Sequence == _pingPacket.Sequence)
				{
					_pingTimer.Stop();
					int num = (int)_pingTimer.ElapsedMilliseconds;
					_remoteDelta = BitConverter.ToInt64(packet.RawData, 3) + (long)num * 10000L / 2 - DateTime.UtcNow.Ticks;
					UpdateRoundTripT

BepInEx/plugins/ULTRAKILL.Bloodlink.dll

Decompiled 13 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using LiteNetLib;
using LiteNetLib.Layers;
using LiteNetLib.Utils;
using ULTRAKILL.Bloodlink.Combat;
using ULTRAKILL.Bloodlink.Core;
using ULTRAKILL.Bloodlink.Enemies;
using ULTRAKILL.Bloodlink.Levels;
using ULTRAKILL.Bloodlink.Networking;
using ULTRAKILL.Bloodlink.Players;
using ULTRAKILL.Bloodlink.UI;
using ULTRAKILL.Enemy;
using ULTRAKILL.Portal;
using Unity.Collections;
using Unity.Jobs;
using Unity.Mathematics;
using Unity.Networking.Transport;
using Unity.Networking.Transport.Relay;
using Unity.Networking.Transport.Utilities;
using Unity.Services.Authentication;
using Unity.Services.Core;
using Unity.Services.Core.Internal;
using Unity.Services.Qos;
using Unity.Services.Relay;
using Unity.Services.Relay.Models;
using Unity.Services.Relay.Scheduler;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Authentication")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Internal")]
[assembly: IgnoresAccessChecksTo("Unity.Services.QoS")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Relay")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("ULTRAKILL.Bloodlink")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("ULTRAKILL.Bloodlink")]
[assembly: AssemblyTitle("ULTRAKILL.Bloodlink")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace ULTRAKILL.Bloodlink.UI
{
	[HarmonyPatch(typeof(MainMenuAgony), "Start")]
	internal static class MainMenuMultiplayerButtonPatch
	{
		private static void Postfix(MainMenuAgony __instance)
		{
			if ((Object)(object)((Component)__instance).GetComponent<MainMenuMultiplayerButton>() == (Object)null)
			{
				((Component)__instance).gameObject.AddComponent<MainMenuMultiplayerButton>();
				BloodlinkPlugin.Instance?.LogMainMenuInjected();
			}
		}
	}
	internal sealed class MainMenuMultiplayerButton : MonoBehaviour
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static UnityAction <>9__5_0;

			internal void <Start>b__5_0()
			{
				BloodlinkPlugin.Instance?.OpenMultiplayerPanel();
			}
		}

		private GameObject canvasObject;

		internal static bool UiPresent { get; private set; }

		private void Start()
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Expected O, but got Unknown
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Expected O, but got Unknown
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_021a: Unknown result type (might be due to invalid IL or missing references)
			//IL_023a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0246: Unknown result type (might be due to invalid IL or missing references)
			//IL_0266: Unknown result type (might be due to invalid IL or missing references)
			//IL_0288: Unknown result type (might be due to invalid IL or missing references)
			//IL_02aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_02be: Unknown result type (might be due to invalid IL or missing references)
			//IL_0316: Unknown result type (might be due to invalid IL or missing references)
			//IL_031b: Unknown result type (might be due to invalid IL or missing references)
			//IL_032d: Unknown result type (might be due to invalid IL or missing references)
			//IL_033e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0353: Unknown result type (might be due to invalid IL or missing references)
			//IL_0368: Unknown result type (might be due to invalid IL or missing references)
			//IL_0373: Unknown result type (might be due to invalid IL or missing references)
			//IL_0387: Unknown result type (might be due to invalid IL or missing references)
			//IL_0391: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_03de: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_0416: Unknown result type (might be due to invalid IL or missing references)
			//IL_0425: Unknown result type (might be due to invalid IL or missing references)
			//IL_0443: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ec: Expected O, but got Unknown
			canvasObject = new GameObject("Bloodlink Multiplayer Menu Button", new Type[4]
			{
				typeof(RectTransform),
				typeof(Canvas),
				typeof(CanvasScaler),
				typeof(GraphicRaycaster)
			});
			MainMenuAgony component = ((Component)this).GetComponent<MainMenuAgony>();
			GameObject val = (((Object)(object)component != (Object)null) ? component.mainMenu : null);
			canvasObject.transform.SetParent(((Object)(object)val != (Object)null) ? val.transform : ((Component)this).transform, false);
			Canvas component2 = canvasObject.GetComponent<Canvas>();
			component2.renderMode = (RenderMode)0;
			component2.sortingOrder = 1000;
			component2.overrideSorting = true;
			CanvasScaler component3 = canvasObject.GetComponent<CanvasScaler>();
			component3.uiScaleMode = (ScaleMode)1;
			component3.referenceResolution = new Vector2(1920f, 1080f);
			component3.matchWidthOrHeight = 0.5f;
			GameObject val2 = new GameObject("Multiplayer", new Type[3]
			{
				typeof(RectTransform),
				typeof(Image),
				typeof(Button)
			});
			val2.transform.SetParent(canvasObject.transform, false);
			RectTransform component4 = val2.GetComponent<RectTransform>();
			component4.anchorMin = new Vector2(0f, 0f);
			component4.anchorMax = new Vector2(0f, 0f);
			component4.pivot = new Vector2(0f, 0f);
			component4.anchoredPosition = new Vector2(56f, 48f);
			component4.sizeDelta = new Vector2(300f, 74f);
			Image component5 = val2.GetComponent<Image>();
			((Graphic)component5).color = new Color(0.12f, 0.035f, 0.045f, 0.98f);
			Button component6 = val2.GetComponent<Button>();
			((Selectable)component6).targetGraphic = (Graphic)(object)component5;
			Navigation navigation = default(Navigation);
			((Navigation)(ref navigation)).mode = (Mode)0;
			((Selectable)component6).navigation = navigation;
			((Selectable)component6).transition = (Transition)1;
			ColorBlock colors = default(ColorBlock);
			((ColorBlock)(ref colors)).normalColor = Color.white;
			((ColorBlock)(ref colors)).highlightedColor = new Color(1f, 0.76f, 0.76f, 1f);
			((ColorBlock)(ref colors)).pressedColor = new Color(0.78f, 0.52f, 0.52f, 1f);
			((ColorBlock)(ref colors)).selectedColor = Color.white;
			((ColorBlock)(ref colors)).disabledColor = new Color(0.45f, 0.45f, 0.45f, 0.6f);
			((ColorBlock)(ref colors)).colorMultiplier = 1f;
			((ColorBlock)(ref colors)).fadeDuration = 0.08f;
			((Selectable)component6).colors = colors;
			Outline obj = val2.AddComponent<Outline>();
			((Shadow)obj).effectColor = new Color(0.42f, 0.025f, 0.04f, 0.95f);
			((Shadow)obj).effectDistance = new Vector2(1.5f, -1.5f);
			ButtonClickedEvent onClick = component6.onClick;
			object obj2 = <>c.<>9__5_0;
			if (obj2 == null)
			{
				UnityAction val3 = delegate
				{
					BloodlinkPlugin.Instance?.OpenMultiplayerPanel();
				};
				<>c.<>9__5_0 = val3;
				obj2 = (object)val3;
			}
			((UnityEvent)onClick).AddListener((UnityAction)obj2);
			GameObject val4 = new GameObject("Accent", new Type[2]
			{
				typeof(RectTransform),
				typeof(Image)
			});
			val4.transform.SetParent(val2.transform, false);
			RectTransform component7 = val4.GetComponent<RectTransform>();
			component7.anchorMin = new Vector2(0f, 0f);
			component7.anchorMax = new Vector2(0f, 1f);
			component7.pivot = new Vector2(0f, 0.5f);
			component7.anchoredPosition = Vector2.zero;
			component7.sizeDelta = new Vector2(5f, 0f);
			((Graphic)val4.GetComponent<Image>()).color = new Color(0.9f, 0.045f, 0.065f, 1f);
			((Graphic)val4.GetComponent<Image>()).raycastTarget = false;
			CreateLabel(val2.transform, "Title", "MULTIPLAYER", 25, (FontStyle)1, (TextAnchor)6, new Vector2(28f, 0.45f), new Vector2(-12f, -8f));
			((Graphic)CreateLabel(val2.transform, "Subtitle", "HOST   /   JOIN   /   CO-OP", 12, (FontStyle)1, (TextAnchor)0, new Vector2(28f, 8f), new Vector2(-12f, -42f))).color = new Color(0.84f, 0.72f, 0.72f, 1f);
			UiPresent = true;
		}

		private static Text CreateLabel(Transform parent, string objectName, string value, int fontSize, FontStyle fontStyle, TextAnchor alignment, Vector2 offsetMin, Vector2 offsetMax)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: 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_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: 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_00b2: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(objectName, new Type[2]
			{
				typeof(RectTransform),
				typeof(Text)
			});
			val.transform.SetParent(parent, false);
			RectTransform component = val.GetComponent<RectTransform>();
			component.anchorMin = Vector2.zero;
			component.anchorMax = Vector2.one;
			component.offsetMin = offsetMin;
			component.offsetMax = offsetMax;
			Text component2 = val.GetComponent<Text>();
			component2.font = Resources.GetBuiltinResource<Font>("Arial.ttf");
			if ((Object)(object)component2.font == (Object)null)
			{
				component2.font = Font.CreateDynamicFontFromOSFont("Arial", fontSize);
			}
			component2.text = value;
			component2.fontSize = fontSize;
			component2.fontStyle = fontStyle;
			component2.alignment = alignment;
			((Graphic)component2).color = Color.white;
			((Graphic)component2).raycastTarget = false;
			return component2;
		}

		private void OnEnable()
		{
			if ((Object)(object)canvasObject != (Object)null)
			{
				UiPresent = true;
			}
		}

		private void OnDisable()
		{
			UiPresent = false;
		}

		private void OnDestroy()
		{
			UiPresent = false;
			if ((Object)(object)canvasObject != (Object)null)
			{
				Object.Destroy((Object)(object)canvasObject);
			}
		}
	}
	internal sealed class MuseumChessPanel : MonoBehaviour
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static UnityAction <>9__8_0;

			internal void <TryCreate>b__8_0()
			{
				MuseumChessSession.Promotion = (byte)(MuseumChessSession.Promotion % 4 + 1);
			}
		}

		private Button versus;

		private Button promotion;

		private Button bot;

		private Text versusText;

		private Text promotionText;

		private GameObject container;

		private float nextSearch;

		private void Update()
		{
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)versus == (Object)null)
			{
				if (!(Time.unscaledTime < nextSearch))
				{
					nextSearch = Time.unscaledTime + 1f;
					TryCreate();
				}
			}
			else
			{
				BloodlinkPlugin instance = BloodlinkPlugin.Instance;
				((Selectable)versus).interactable = (Object)(object)instance != (Object)null && instance.IsConnected && instance.Network.Players.Count >= 2;
				versusText.text = "VS PLAYER" + (MuseumChessSession.Active ? ("\n" + MuseumChessSession.Status) : "\nHOST: WHITE / GUEST: BLACK");
				((Selectable)bot).interactable = !MuseumChessSession.Active || ((Object)(object)instance != (Object)null && instance.IsHost);
				promotionText.text = "PROMOTION: " + ((object)(PieceType)MuseumChessSession.Promotion/*cast due to .constrained prefix*/).ToString().ToUpperInvariant();
			}
		}

		private void TryCreate()
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Expected O, but got Unknown
			//IL_013f: 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_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0230: Unknown result type (might be due to invalid IL or missing references)
			//IL_0235: Unknown result type (might be due to invalid IL or missing references)
			//IL_0272: Unknown result type (might be due to invalid IL or missing references)
			//IL_027c: Expected O, but got Unknown
			//IL_02a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ac: Expected O, but got Unknown
			//IL_02e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ee: Expected O, but got Unknown
			ChessManager component = ((Component)this).GetComponent<ChessManager>();
			Button val = null;
			Button[] array = Resources.FindObjectsOfTypeAll<Button>();
			foreach (Button val2 in array)
			{
				if ((Object)(object)val2 == (Object)null || ((Component)val2).gameObject.scene != ((Component)this).gameObject.scene || (Object)(object)((Component)((Component)val2).transform).GetComponentInParent<Canvas>() == (Object)null)
				{
					continue;
				}
				for (int j = 0; j < ((UnityEventBase)val2.onClick).GetPersistentEventCount(); j++)
				{
					if (((UnityEventBase)val2.onClick).GetPersistentTarget(j) == (Object)(object)component)
					{
						val = val2;
						break;
					}
				}
				if ((Object)(object)val != (Object)null)
				{
					break;
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			RectTransform component2 = ((Component)val).GetComponent<RectTransform>();
			container = new GameObject("Bloodlink Chess Multiplayer", new Type[3]
			{
				typeof(RectTransform),
				typeof(VerticalLayoutGroup),
				typeof(LayoutElement)
			});
			container.transform.SetParent(((Component)val).transform.parent, false);
			container.transform.SetSiblingIndex(((Component)val).transform.GetSiblingIndex() + 1);
			RectTransform component3 = container.GetComponent<RectTransform>();
			component3.anchorMin = component2.anchorMin;
			component3.anchorMax = component2.anchorMax;
			component3.pivot = component2.pivot;
			Rect rect = component2.rect;
			float num = Mathf.Max(38f, ((Rect)(ref rect)).height);
			rect = component2.rect;
			component3.sizeDelta = new Vector2(Mathf.Max(260f, ((Rect)(ref rect)).width), num * 3f + 12f);
			component3.anchoredPosition = component2.anchoredPosition + Vector2.down * (num + 8f);
			VerticalLayoutGroup component4 = container.GetComponent<VerticalLayoutGroup>();
			((HorizontalOrVerticalLayoutGroup)component4).spacing = 6f;
			bool childControlWidth = (((HorizontalOrVerticalLayoutGroup)component4).childControlHeight = true);
			((HorizontalOrVerticalLayoutGroup)component4).childControlWidth = childControlWidth;
			((HorizontalOrVerticalLayoutGroup)component4).childForceExpandWidth = true;
			((HorizontalOrVerticalLayoutGroup)component4).childForceExpandHeight = false;
			container.GetComponent<LayoutElement>().preferredHeight = num * 3f + 12f;
			LayoutElement component5 = container.GetComponent<LayoutElement>();
			rect = component2.rect;
			component5.preferredWidth = Mathf.Max(260f, ((Rect)(ref rect)).width);
			versus = CreateButton("VS PLAYER", num, out versusText);
			((UnityEvent)versus.onClick).AddListener(new UnityAction(MuseumChessSession.RequestStart));
			bot = CreateButton("VS BOT", num, out var _);
			((UnityEvent)bot.onClick).AddListener(new UnityAction(MuseumChessSession.StartBotGame));
			promotion = CreateButton("PROMOTION: QUEEN", num, out promotionText);
			ButtonClickedEvent onClick = promotion.onClick;
			object obj = <>c.<>9__8_0;
			if (obj == null)
			{
				UnityAction val3 = delegate
				{
					MuseumChessSession.Promotion = (byte)(MuseumChessSession.Promotion % 4 + 1);
				};
				<>c.<>9__8_0 = val3;
				obj = (object)val3;
			}
			((UnityEvent)onClick).AddListener((UnityAction)obj);
		}

		private Button CreateButton(string label, float height, out Text text)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Expected O, but got Unknown
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Expected O, but got Unknown
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(label, new Type[4]
			{
				typeof(RectTransform),
				typeof(Image),
				typeof(Button),
				typeof(LayoutElement)
			});
			val.transform.SetParent(container.transform, false);
			((Graphic)val.GetComponent<Image>()).color = new Color(0.18f, 0.025f, 0.025f, 0.98f);
			val.GetComponent<LayoutElement>().preferredHeight = height;
			Button component = val.GetComponent<Button>();
			((Selectable)component).targetGraphic = (Graphic)(object)val.GetComponent<Image>();
			GameObject val2 = new GameObject("Label", new Type[2]
			{
				typeof(RectTransform),
				typeof(Text)
			});
			val2.transform.SetParent(val.transform, false);
			RectTransform component2 = val2.GetComponent<RectTransform>();
			component2.anchorMin = Vector2.zero;
			component2.anchorMax = Vector2.one;
			component2.offsetMin = new Vector2(6f, 2f);
			component2.offsetMax = new Vector2(-6f, -2f);
			text = val2.GetComponent<Text>();
			text.font = Resources.GetBuiltinResource<Font>("Arial.ttf");
			text.text = label;
			text.fontSize = 17;
			text.fontStyle = (FontStyle)1;
			text.alignment = (TextAnchor)4;
			((Graphic)text).color = Color.white;
			((Graphic)text).raycastTarget = false;
			return component;
		}

		private void OnDestroy()
		{
			if ((Object)(object)container != (Object)null)
			{
				Object.Destroy((Object)(object)container);
			}
		}
	}
}
namespace ULTRAKILL.Bloodlink.Players
{
	internal sealed class CosmeticProjectileFlight : MonoBehaviour
	{
		private Vector3 velocity;

		private Vector3 gravity;

		private Vector3 angularVelocity;

		private float remaining = 5f;

		public void Initialize(Vector3 initialVelocity, Vector3 gravityAcceleration, Vector3 initialAngularVelocity, float lifetime = 5f)
		{
			//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)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			velocity = initialVelocity;
			gravity = gravityAcceleration;
			angularVelocity = initialAngularVelocity;
			remaining = Mathf.Clamp(lifetime, 0.1f, 10f);
		}

		private void Update()
		{
			//IL_0017: 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_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//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_0056: 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_0066: Unknown result type (might be due to invalid IL or missing references)
			float num = Mathf.Min(Time.unscaledDeltaTime, 0.05f);
			Transform transform = ((Component)this).transform;
			transform.position += velocity * num;
			velocity += gravity * num;
			((Component)this).transform.Rotate(angularVelocity * 57.29578f * num, (Space)0);
			remaining -= num;
			if (remaining <= 0f)
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
			}
		}
	}
	public sealed class RemotePlayerVisual : MonoBehaviour
	{
		private struct TimedSnapshot
		{
			public PlayerSnapshot State;

			public float ReceivedAt;
		}

		private readonly List<TimedSnapshot> buffer = new List<TimedSnapshot>(8);

		private readonly List<Animator> animators = new List<Animator>();

		private readonly Dictionary<Animator, HashSet<int>> animatorParameterHashes = new Dictionary<Animator, HashSet<int>>();

		private readonly List<GameObject> remoteCoinInstances = new List<GameObject>();

		private readonly List<GameObject> remoteNailInstances = new List<GameObject>();

		private readonly List<GameObject> remoteRocketInstances = new List<GameObject>();

		private Renderer[] visualRenderers;

		private MaterialPropertyBlock[] appearanceBlocks;

		private uint lastPrimaryColor = uint.MaxValue;

		private uint lastSecondaryColor = uint.MaxValue;

		private uint lastLightColor = uint.MaxValue;

		private byte lastGlowIntensity;

		private GameObject[] baseWeapons;

		private GameObject[] alternateWeapons;

		private Transform modelRoot;

		private Transform remoteHead;

		private Transform remoteRightArm;

		private Transform remoteChest;

		private Quaternion modelBaseLocalRotation = Quaternion.identity;

		private float landingLayerWeight;

		private TextMesh nameplate;

		private TextMesh nameplateShadow;

		private uint lastReceivedTick;

		private bool hasReceivedSnapshot;

		private Transform recoilingWeapon;

		private Vector3 weaponRestPosition;

		private Quaternion weaponRestRotation;

		private float recoilUntil;

		private int lastDeadState = -1;

		private float nextAnimatorDiagnosticAt;

		private byte lastWeaponSlot = byte.MaxValue;

		private byte lastWeaponVariation = byte.MaxValue;

		private bool hasWeaponState;

		private bool lastWeaponAlternate;

		private Vector3 sampledPlanarVelocity;

		private bool hasRenderedPosition;

		public uint PlayerId { get; private set; }

		internal bool HasRenderableModel
		{
			get
			{
				if (visualRenderers == null || visualRenderers.Length == 0)
				{
					return false;
				}
				for (int i = 0; i < visualRenderers.Length; i++)
				{
					Renderer val = visualRenderers[i];
					if (!((Object)(object)val == (Object)null) && val.enabled && ((Component)val).gameObject.activeInHierarchy)
					{
						SkinnedMeshRenderer val2 = (SkinnedMeshRenderer)(object)((val is SkinnedMeshRenderer) ? val : null);
						if ((Object)(object)val2 != (Object)null && (Object)(object)val2.sharedMesh != (Object)null)
						{
							return true;
						}
						MeshFilter component = ((Component)val).GetComponent<MeshFilter>();
						if ((Object)(object)component != (Object)null && (Object)(object)component.sharedMesh != (Object)null)
						{
							return true;
						}
					}
				}
				return false;
			}
		}

		public static RemotePlayerVisual Create(PlayerAnimations template, uint playerId, string playerName)
		{
			return Create(template, null, playerId, playerName);
		}

		public static RemotePlayerVisual Create(PlayerAnimations template, Transform sourcePlayerRoot, uint playerId, string playerName)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: 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_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0276: Unknown result type (might be due to invalid IL or missing references)
			//IL_027c: Expected O, but got Unknown
			//IL_04e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_04e9: Expected O, but got Unknown
			//IL_0512: Unknown result type (might be due to invalid IL or missing references)
			//IL_0599: Unknown result type (might be due to invalid IL or missing references)
			//IL_05e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_05e9: Expected O, but got Unknown
			//IL_0612: Unknown result type (might be due to invalid IL or missing references)
			//IL_069d: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("Bloodlink Remote Player " + playerId);
			RemotePlayerVisual remotePlayerVisual = val.AddComponent<RemotePlayerVisual>();
			remotePlayerVisual.PlayerId = playerId;
			GameObject val2 = new GameObject("Remote V1 Runtime Model");
			val2.transform.SetParent(val.transform, false);
			val2.SetActive(false);
			GameObject val3 = Object.Instantiate<GameObject>(((Component)template).gameObject, val2.transform, false);
			((Object)val3).name = "Remote V1 Rig";
			val3.transform.localPosition = (((Object)(object)sourcePlayerRoot != (Object)null) ? sourcePlayerRoot.InverseTransformPoint(((Component)template).transform.position) : ((Component)template).transform.localPosition);
			val3.transform.localRotation = Quaternion.identity;
			val3.transform.localScale = GetRelativeScale(((Component)template).transform, sourcePlayerRoot);
			Behaviour[] componentsInChildren = val3.GetComponentsInChildren<Behaviour>(true);
			foreach (Behaviour val4 in componentsInChildren)
			{
				Animator val5 = (Animator)(object)((val4 is Animator) ? val4 : null);
				if ((Object)(object)val5 != (Object)null)
				{
					((Behaviour)val5).enabled = true;
					val5.applyRootMotion = false;
					val5.cullingMode = (AnimatorCullingMode)0;
					val5.updateMode = (AnimatorUpdateMode)2;
					if (!remotePlayerVisual.animators.Contains(val5))
					{
						remotePlayerVisual.animators.Add(val5);
					}
				}
				else
				{
					val4.enabled = false;
				}
			}
			Collider[] componentsInChildren2 = val3.GetComponentsInChildren<Collider>(true);
			for (int i = 0; i < componentsInChildren2.Length; i++)
			{
				componentsInChildren2[i].enabled = false;
			}
			Rigidbody[] componentsInChildren3 = val3.GetComponentsInChildren<Rigidbody>(true);
			foreach (Rigidbody obj in componentsInChildren3)
			{
				obj.isKinematic = true;
				obj.useGravity = false;
			}
			Camera[] componentsInChildren4 = val3.GetComponentsInChildren<Camera>(true);
			for (int i = 0; i < componentsInChildren4.Length; i++)
			{
				((Behaviour)componentsInChildren4[i]).enabled = false;
			}
			AudioSource[] componentsInChildren5 = val3.GetComponentsInChildren<AudioSource>(true);
			foreach (AudioSource obj2 in componentsInChildren5)
			{
				obj2.Stop();
				((Behaviour)obj2).enabled = false;
			}
			remotePlayerVisual.modelRoot = val3.transform;
			remotePlayerVisual.modelBaseLocalRotation = Quaternion.identity;
			Renderer[] componentsInChildren6 = val2.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer obj3 in componentsInChildren6)
			{
				obj3.enabled = true;
				((Component)obj3).gameObject.layer = 0;
				SkinnedMeshRenderer val6 = (SkinnedMeshRenderer)(object)((obj3 is SkinnedMeshRenderer) ? obj3 : null);
				if ((Object)(object)val6 != (Object)null)
				{
					val6.updateWhenOffscreen = true;
				}
			}
			remotePlayerVisual.visualRenderers = val2.GetComponentsInChildren<Renderer>(true);
			remotePlayerVisual.appearanceBlocks = (MaterialPropertyBlock[])(object)new MaterialPropertyBlock[remotePlayerVisual.visualRenderers.Length];
			for (int j = 0; j < remotePlayerVisual.appearanceBlocks.Length; j++)
			{
				remotePlayerVisual.appearanceBlocks[j] = new MaterialPropertyBlock();
			}
			remotePlayerVisual.baseWeapons = RemapWeapons(template.weapons, ((Component)template).transform, val3.transform);
			remotePlayerVisual.alternateWeapons = RemapWeapons(template.altweapons, ((Component)template).transform, val3.transform);
			PlayerAnimations component = val3.GetComponent<PlayerAnimations>();
			remotePlayerVisual.remoteHead = (((Object)(object)component != (Object)null) ? component.head : null);
			remotePlayerVisual.remoteRightArm = (((Object)(object)component != (Object)null) ? component.rightArm : null);
			remotePlayerVisual.remoteChest = (((Object)(object)component != (Object)null) ? component.chest : null);
			MonoBehaviour[] componentsInChildren7 = val3.GetComponentsInChildren<MonoBehaviour>(true);
			for (int i = 0; i < componentsInChildren7.Length; i++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren7[i]);
			}
			val2.SetActive(true);
			val3.SetActive(true);
			foreach (Animator animator in remotePlayerVisual.animators)
			{
				animator.Rebind();
				((Behaviour)animator).enabled = true;
				animator.applyRootMotion = false;
				animator.speed = 1f;
				animator.updateMode = (AnimatorUpdateMode)2;
				animator.cullingMode = (AnimatorCullingMode)0;
				animator.Update(0f);
				remotePlayerVisual.CacheAnimatorParameters(animator);
			}
			BloodlinkPlugin instance = BloodlinkPlugin.Instance;
			if ((Object)(object)instance != (Object)null)
			{
				foreach (Animator animator2 in remotePlayerVisual.animators)
				{
					RuntimeAnimatorController runtimeAnimatorController = animator2.runtimeAnimatorController;
					instance.LogRemoteAnimatorDiagnostics("Remote V1 animator initialized for player " + playerId + ": controller=" + (((Object)(object)runtimeAnimatorController != (Object)null) ? ((Object)runtimeAnimatorController).name : "<none>") + ", avatar=" + (((Object)(object)animator2.avatar != (Object)null) ? ((Object)animator2.avatar).name : "<none>") + ", parameters=" + GetAnimatorParameterSummary(animator2) + ", enabled=" + ((Behaviour)animator2).isActiveAndEnabled + ".");
				}
			}
			GameObject val7 = new GameObject("Remote Player Name", new Type[1] { typeof(TextMesh) });
			val7.transform.SetParent(val.transform, false);
			val7.transform.localPosition = new Vector3(0f, 2.1f, 0f);
			remotePlayerVisual.nameplate = val7.GetComponent<TextMesh>();
			remotePlayerVisual.nameplate.text = playerName ?? ("Player " + playerId);
			remotePlayerVisual.nameplate.fontSize = 64;
			remotePlayerVisual.nameplate.characterSize = 0.075f;
			remotePlayerVisual.nameplate.anchor = (TextAnchor)4;
			remotePlayerVisual.nameplate.alignment = (TextAlignment)1;
			remotePlayerVisual.nameplate.color = new Color(1f, 0.87f, 0.82f, 1f);
			remotePlayerVisual.nameplate.font = Resources.GetBuiltinResource<Font>("Arial.ttf");
			((Renderer)((Component)remotePlayerVisual.nameplate).GetComponent<MeshRenderer>()).sortingOrder = 100;
			GameObject val8 = new GameObject("Remote Player Name Shadow", new Type[1] { typeof(TextMesh) });
			val8.transform.SetParent(val.transform, false);
			val8.transform.localPosition = new Vector3(0f, 2.1f, 0.005f);
			remotePlayerVisual.nameplateShadow = val8.GetComponent<TextMesh>();
			remotePlayerVisual.nameplateShadow.font = remotePlayerVisual.nameplate.font;
			remotePlayerVisual.nameplateShadow.fontSize = remotePlayerVisual.nameplate.fontSize;
			remotePlayerVisual.nameplateShadow.characterSize = remotePlayerVisual.nameplate.characterSize;
			remotePlayerVisual.nameplateShadow.anchor = (TextAnchor)4;
			remotePlayerVisual.nameplateShadow.alignment = (TextAlignment)1;
			remotePlayerVisual.nameplateShadow.color = new Color(0f, 0f, 0f, 0.92f);
			((Renderer)((Component)remotePlayerVisual.nameplateShadow).GetComponent<MeshRenderer>()).sortingOrder = 99;
			remotePlayerVisual.nameplateShadow.text = remotePlayerVisual.nameplate.text;
			return remotePlayerVisual;
		}

		private static Vector3 GetRelativeScale(Transform source, Transform sourceRoot)
		{
			//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_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: 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_0057: 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_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)sourceRoot == (Object)null)
			{
				return source.localScale;
			}
			Vector3 lossyScale = source.lossyScale;
			Vector3 lossyScale2 = sourceRoot.lossyScale;
			return new Vector3((Mathf.Abs(lossyScale2.x) > 0.0001f) ? (lossyScale.x / lossyScale2.x) : lossyScale.x, (Mathf.Abs(lossyScale2.y) > 0.0001f) ? (lossyScale.y / lossyScale2.y) : lossyScale.y, (Mathf.Abs(lossyScale2.z) > 0.0001f) ? (lossyScale.z / lossyScale2.z) : lossyScale.z);
		}

		private static Transform RemapTransform(Transform source, Transform sourceRoot, Transform cloneRoot)
		{
			if ((Object)(object)source == (Object)null)
			{
				return null;
			}
			string relativePath = GetRelativePath(source, sourceRoot);
			if (!string.IsNullOrEmpty(relativePath))
			{
				return cloneRoot.Find(relativePath);
			}
			return null;
		}

		private static GameObject[] RemapWeapons(GameObject[] source, Transform sourceRoot, Transform cloneRoot)
		{
			if (source == null)
			{
				return Array.Empty<GameObject>();
			}
			GameObject[] array = (GameObject[])(object)new GameObject[source.Length];
			for (int i = 0; i < source.Length; i++)
			{
				if (!((Object)(object)source[i] == (Object)null))
				{
					string relativePath = GetRelativePath(source[i].transform, sourceRoot);
					Transform val = (string.IsNullOrEmpty(relativePath) ? null : cloneRoot.Find(relativePath));
					array[i] = (((Object)(object)val != (Object)null) ? ((Component)val).gameObject : null);
				}
			}
			return array;
		}

		private static string GetRelativePath(Transform target, Transform root)
		{
			List<string> list = new List<string>();
			Transform val = target;
			while ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)root)
			{
				list.Insert(0, ((Object)val).name);
				val = val.parent;
			}
			if (!((Object)(object)val == (Object)(object)root))
			{
				return string.Empty;
			}
			return string.Join("/", list.ToArray());
		}

		public void Push(PlayerSnapshot state)
		{
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: 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: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: 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_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			if (state == null)
			{
				return;
			}
			if (!hasReceivedSnapshot || state.Tick != lastReceivedTick)
			{
				if (buffer.Count > 0)
				{
					TimedSnapshot timedSnapshot = buffer[buffer.Count - 1];
					float num = Time.unscaledTime - timedSnapshot.ReceivedAt;
					if (num > 0.005f && num < 0.5f)
					{
						Vector3 val = Vector3.ProjectOnPlane((state.Position - timedSnapshot.State.Position) / num, Vector3.up);
						if (((Vector3)(ref val)).sqrMagnitude < 67600f)
						{
							sampledPlanarVelocity = val;
						}
					}
				}
				buffer.Add(new TimedSnapshot
				{
					State = state,
					ReceivedAt = Time.unscaledTime
				});
				lastReceivedTick = state.Tick;
				hasReceivedSnapshot = true;
				while (buffer.Count > 12)
				{
					buffer.RemoveAt(0);
				}
			}
			if ((Object)(object)nameplate != (Object)null)
			{
				bool flag = (state.MovementFlags & 4) != 0;
				nameplate.text = (flag ? ((state.PlayerName ?? ("Player " + PlayerId)) + "\nDEAD") : ((state.PlayerName ?? ("Player " + PlayerId)) + "\n" + state.Health + " HP"));
				if ((Object)(object)nameplateShadow != (Object)null)
				{
					nameplateShadow.text = nameplate.text;
				}
				nameplate.color = (flag ? new Color(0.72f, 0.72f, 0.72f, 1f) : new Color(1f, 0.87f, 0.82f, 1f));
			}
			if ((state.MovementFlags & 4) != 0)
			{
				SetWeapon(0, 0);
			}
			else
			{
				SetWeapon(state.WeaponSlot, state.WeaponVariation, state.WeaponAlternate);
			}
			ApplyAppearance(state.PrimaryColor, state.SecondaryColor, state.LightColor, state.GlowIntensity);
		}

		private void LateUpdate()
		{
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			UpdateWeaponRecoil();
			UpdateAnimationLayers();
			if (buffer.Count == 0)
			{
				return;
			}
			float num = Time.unscaledTime - 0.1f;
			TimedSnapshot timedSnapshot = buffer[0];
			TimedSnapshot timedSnapshot2 = buffer[buffer.Count - 1];
			if (num <= timedSnapshot.ReceivedAt)
			{
				Apply(timedSnapshot.State.Position, timedSnapshot.State.Rotation);
				Animate(timedSnapshot.State);
				return;
			}
			for (int i = 1; i < buffer.Count; i++)
			{
				TimedSnapshot timedSnapshot3 = buffer[i];
				if (num <= timedSnapshot3.ReceivedAt)
				{
					TimedSnapshot timedSnapshot4 = buffer[i - 1];
					float num2 = Mathf.Max(0.001f, timedSnapshot3.ReceivedAt - timedSnapshot4.ReceivedAt);
					float num3 = Mathf.Clamp01((num - timedSnapshot4.ReceivedAt) / num2);
					Apply(Vector3.Lerp(timedSnapshot4.State.Position, timedSnapshot3.State.Position, num3), Quaternion.Slerp(timedSnapshot4.State.Rotation, timedSnapshot3.State.Rotation, num3));
					Animate(timedSnapshot3.State);
					return;
				}
			}
			float num4 = Mathf.Clamp(num - timedSnapshot2.ReceivedAt, 0f, 0.1f);
			Apply(timedSnapshot2.State.Position + timedSnapshot2.State.Velocity * num4, timedSnapshot2.State.Rotation);
			Animate(timedSnapshot2.State);
		}

		public void PlayWeaponFire(byte slot, byte variation, byte fireKind, Quaternion aimRotation, bool weaponAlternate = false)
		{
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: 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_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: 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)
			SetWeapon(slot, variation, weaponAlternate);
			int num = ((slot > 0) ? (slot - 1) : 255);
			GameObject[] array = (lastWeaponAlternate ? alternateWeapons : baseWeapons);
			if (num >= array.Length || (Object)(object)array[num] == (Object)null)
			{
				return;
			}
			Transform transform = array[num].transform;
			PlayMuzzleFlash(((Component)transform).gameObject, slot, fireKind, aimRotation);
			foreach (Animator animator in animators)
			{
				SetFloatIfPresent(animator, "ShootSpeed", 1f);
				SetTriggerIfPresent(animator, (slot == 5 && fireKind == 9) ? "Spray" : "Shoot");
			}
			if ((Object)(object)recoilingWeapon != (Object)(object)transform)
			{
				RestoreWeaponRecoil();
				recoilingWeapon = transform;
				weaponRestPosition = transform.localPosition;
				weaponRestRotation = transform.localRotation;
			}
			recoilUntil = Time.unscaledTime + 0.075f;
			transform.localPosition = weaponRestPosition + Vector3.back * 0.055f;
			transform.localRotation = weaponRestRotation * Quaternion.Euler(-5f, 0f, 0f);
		}

		public void PlayPlayerAnimation(PlayerAnimationEvent animation)
		{
			if (animation == null)
			{
				return;
			}
			foreach (Animator animator in animators)
			{
				if (animation.Action == PlayerAnimationAction.Punch)
				{
					SetFloatIfPresent(animator, "PunchSpeed", animation.Speed);
					SetTriggerIfPresent(animator, "Punch");
				}
				else if (animation.Action == PlayerAnimationAction.CoinToss)
				{
					SetTriggerIfPresent(animator, "CoinToss");
				}
				else if (animation.Action == PlayerAnimationAction.Parry)
				{
					SetTriggerIfPresent(animator, "Parry");
				}
				else if (animation.Action == PlayerAnimationAction.Jump)
				{
					SetTriggerIfPresent(animator, "Jump");
				}
				else if (animation.Action == PlayerAnimationAction.Land)
				{
					landingLayerWeight = Mathf.Clamp01(animation.Speed);
					if (animator.layerCount > 1)
					{
						animator.SetLayerWeight(1, landingLayerWeight);
					}
				}
			}
		}

		public void PlayCoinProjectile(CoinProjectileEvent coin)
		{
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			if (coin == null || coin.OwnerPlayerId != PlayerId)
			{
				return;
			}
			GameObject[] array = (lastWeaponAlternate ? alternateWeapons : baseWeapons);
			if (array == null || array.Length == 0 || (Object)(object)array[0] == (Object)null)
			{
				return;
			}
			GameObject val = null;
			Revolver componentInChildren = array[0].GetComponentInChildren<Revolver>(true);
			if ((Object)(object)componentInChildren != (Object)null)
			{
				val = componentInChildren.coin;
			}
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			PlayPrefabOneShots(val, coin.Position);
			for (int num = remoteCoinInstances.Count - 1; num >= 0; num--)
			{
				if ((Object)(object)remoteCoinInstances[num] == (Object)null)
				{
					remoteCoinInstances.RemoveAt(num);
				}
			}
			while (remoteCoinInstances.Count >= 8)
			{
				if ((Object)(object)remoteCoinInstances[0] != (Object)null)
				{
					Object.Destroy((Object)(object)remoteCoinInstances[0]);
				}
				remoteCoinInstances.RemoveAt(0);
			}
			GameObject val2 = InstantiateCosmeticProjectile(val, coin.Position, coin.Rotation, coin.Velocity, coin.Gravity, coin.AngularVelocity, 5f, "Bloodlink Remote Coin " + PlayerId);
			if (!((Object)(object)val2 == (Object)null))
			{
				remoteCoinInstances.Add(val2);
			}
		}

		public void PlayNailProjectile(NailProjectileEvent projectile)
		{
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			if (projectile == null || projectile.OwnerPlayerId != PlayerId)
			{
				return;
			}
			GameObject[] array = (lastWeaponAlternate ? alternateWeapons : baseWeapons);
			if (array == null || array.Length <= 2 || (Object)(object)array[2] == (Object)null)
			{
				return;
			}
			Nailgun componentInChildren = array[2].GetComponentInChildren<Nailgun>(true);
			if ((Object)(object)componentInChildren == (Object)null)
			{
				return;
			}
			GameObject val = ((projectile.VisualKind == 1 || projectile.VisualKind == 3) ? componentInChildren.heatedNail : componentInChildren.nail);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			for (int num = remoteNailInstances.Count - 1; num >= 0; num--)
			{
				if ((Object)(object)remoteNailInstances[num] == (Object)null)
				{
					remoteNailInstances.RemoveAt(num);
				}
			}
			while (remoteNailInstances.Count >= 40)
			{
				if ((Object)(object)remoteNailInstances[0] != (Object)null)
				{
					Object.Destroy((Object)(object)remoteNailInstances[0]);
				}
				remoteNailInstances.RemoveAt(0);
			}
			GameObject val2 = InstantiateCosmeticProjectile(val, projectile.Position, projectile.Rotation, projectile.Velocity, projectile.Gravity, projectile.AngularVelocity, 3f, "Bloodlink Remote Nail Projectile " + PlayerId);
			if (!((Object)(object)val2 == (Object)null))
			{
				remoteNailInstances.Add(val2);
			}
		}

		public void PlayRocketProjectile(RocketProjectileEvent projectile)
		{
			//IL_0135: 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_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			if (projectile == null || projectile.OwnerPlayerId != PlayerId)
			{
				return;
			}
			GameObject[] array = (lastWeaponAlternate ? alternateWeapons : baseWeapons);
			if (array == null || array.Length <= 4 || (Object)(object)array[4] == (Object)null)
			{
				return;
			}
			RocketLauncher componentInChildren = array[4].GetComponentInChildren<RocketLauncher>(true);
			if ((Object)(object)componentInChildren == (Object)null)
			{
				return;
			}
			GameObject val = ((projectile.VisualKind == 1) ? (((Object)(object)componentInChildren.cannonBall != (Object)null) ? ((Component)componentInChildren.cannonBall).gameObject : null) : ((projectile.VisualKind != 2) ? componentInChildren.rocket : (((Object)(object)componentInChildren.napalmProjectile != (Object)null) ? ((Component)componentInChildren.napalmProjectile).gameObject : null)));
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			for (int num = remoteRocketInstances.Count - 1; num >= 0; num--)
			{
				if ((Object)(object)remoteRocketInstances[num] == (Object)null)
				{
					remoteRocketInstances.RemoveAt(num);
				}
			}
			while (remoteRocketInstances.Count >= 12)
			{
				if ((Object)(object)remoteRocketInstances[0] != (Object)null)
				{
					Object.Destroy((Object)(object)remoteRocketInstances[0]);
				}
				remoteRocketInstances.RemoveAt(0);
			}
			GameObject val2 = InstantiateCosmeticProjectile(val, projectile.Position, projectile.Rotation, projectile.Velocity, projectile.Gravity, projectile.AngularVelocity, 4f, "Bloodlink Remote Rocket Projectile " + PlayerId);
			if (!((Object)(object)val2 == (Object)null))
			{
				remoteRocketInstances.Add(val2);
			}
		}

		private static GameObject InstantiateCosmeticProjectile(GameObject prefab, Vector3 position, Quaternion rotation, Vector3 velocity, Vector3 gravity, Vector3 angularVelocity, float lifetime, string objectName)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: 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_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)prefab == (Object)null)
			{
				return null;
			}
			GameObject val = new GameObject("Bloodlink Inactive Projectile Guard");
			val.SetActive(false);
			GameObject val2 = Object.Instantiate<GameObject>(prefab, position, rotation, val.transform);
			if ((Object)(object)val2 == (Object)null)
			{
				Object.Destroy((Object)(object)val);
				return null;
			}
			((Object)val2).name = objectName;
			val2.SetActive(false);
			Behaviour[] componentsInChildren = val2.GetComponentsInChildren<Behaviour>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				componentsInChildren[i].enabled = false;
			}
			Collider[] componentsInChildren2 = val2.GetComponentsInChildren<Collider>(true);
			for (int i = 0; i < componentsInChildren2.Length; i++)
			{
				componentsInChildren2[i].enabled = false;
			}
			Rigidbody[] componentsInChildren3 = val2.GetComponentsInChildren<Rigidbody>(true);
			foreach (Rigidbody obj in componentsInChildren3)
			{
				obj.isKinematic = true;
				obj.useGravity = false;
				obj.velocity = Vector3.zero;
				obj.angularVelocity = Vector3.zero;
			}
			AudioSource[] componentsInChildren4 = val2.GetComponentsInChildren<AudioSource>(true);
			foreach (AudioSource obj2 in componentsInChildren4)
			{
				obj2.Stop();
				((Behaviour)obj2).enabled = false;
			}
			Renderer[] componentsInChildren5 = val2.GetComponentsInChildren<Renderer>(true);
			for (int i = 0; i < componentsInChildren5.Length; i++)
			{
				componentsInChildren5[i].enabled = true;
			}
			val2.AddComponent<CosmeticProjectileFlight>().Initialize(velocity, gravity, angularVelocity, lifetime);
			val2.transform.SetParent((Transform)null, true);
			Object.Destroy((Object)(object)val);
			val2.SetActive(true);
			return val2;
		}

		private static void PlayMuzzleFlash(GameObject weapon, byte slot, byte fireKind, Quaternion aimRotation)
		{
			//IL_02a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0335: Expected O, but got Unknown
			if ((Object)(object)weapon == (Object)null)
			{
				return;
			}
			GameObject val = null;
			Transform val2 = null;
			switch (slot)
			{
			case 1:
			{
				Revolver componentInChildren4 = weapon.GetComponentInChildren<Revolver>(true);
				if ((Object)(object)componentInChildren4 != (Object)null && (Object)(object)componentInChildren4.gunBarrel != (Object)null)
				{
					val2 = componentInChildren4.gunBarrel.transform;
				}
				break;
			}
			case 2:
			{
				Shotgun componentInChildren5 = weapon.GetComponentInChildren<Shotgun>(true);
				if ((Object)(object)componentInChildren5 != (Object)null)
				{
					val = componentInChildren5.muzzleFlash;
					if (componentInChildren5.shootPoints != null && componentInChildren5.shootPoints.Length != 0)
					{
						val2 = componentInChildren5.shootPoints[0];
					}
				}
				break;
			}
			case 3:
			{
				Nailgun componentInChildren2 = weapon.GetComponentInChildren<Nailgun>(true);
				if (!((Object)(object)componentInChildren2 != (Object)null))
				{
					break;
				}
				val = ((fireKind == 7) ? componentInChildren2.muzzleFlash2 : componentInChildren2.muzzleFlash);
				if (componentInChildren2.shootPoints != null && componentInChildren2.shootPoints.Length != 0)
				{
					int num = Mathf.Clamp(componentInChildren2.barrelNum, 0, componentInChildren2.shootPoints.Length - 1);
					if ((Object)(object)componentInChildren2.shootPoints[num] != (Object)null)
					{
						val2 = componentInChildren2.shootPoints[num].transform;
					}
				}
				break;
			}
			case 4:
			{
				Railcannon componentInChildren3 = weapon.GetComponentInChildren<Railcannon>(true);
				if ((Object)(object)componentInChildren3 != (Object)null)
				{
					val2 = componentInChildren3.shootPoint;
				}
				break;
			}
			case 5:
			{
				RocketLauncher componentInChildren = weapon.GetComponentInChildren<RocketLauncher>(true);
				if (!((Object)(object)componentInChildren != (Object)null))
				{
					break;
				}
				val = componentInChildren.muzzleFlash;
				val2 = componentInChildren.shootPoint;
				if (fireKind != 9)
				{
					break;
				}
				ParticleSystem napalmMuzzleFlashParticles = componentInChildren.napalmMuzzleFlashParticles;
				if ((Object)(object)napalmMuzzleFlashParticles != (Object)null)
				{
					if ((Object)(object)val2 == (Object)null)
					{
						val2 = ((Component)napalmMuzzleFlashParticles).transform;
					}
					((Component)napalmMuzzleFlashParticles).transform.SetPositionAndRotation(val2.position, aimRotation);
					napalmMuzzleFlashParticles.Play(true);
					return;
				}
				break;
			}
			}
			if ((Object)(object)val2 == (Object)null)
			{
				val2 = weapon.transform;
			}
			if ((Object)(object)val != (Object)null)
			{
				PlayPrefabOneShots(val, val2.position);
				GameObject val3 = Object.Instantiate<GameObject>(val, val2.position, aimRotation);
				AudioSource[] componentsInChildren = val3.GetComponentsInChildren<AudioSource>(true);
				foreach (AudioSource obj in componentsInChildren)
				{
					obj.Stop();
					((Behaviour)obj).enabled = false;
				}
				Collider[] componentsInChildren2 = val3.GetComponentsInChildren<Collider>(true);
				for (int i = 0; i < componentsInChildren2.Length; i++)
				{
					componentsInChildren2[i].enabled = false;
				}
				Rigidbody[] componentsInChildren3 = val3.GetComponentsInChildren<Rigidbody>(true);
				foreach (Rigidbody obj2 in componentsInChildren3)
				{
					obj2.isKinematic = true;
					obj2.useGravity = false;
				}
				ParticleSystem[] componentsInChildren4 = val3.GetComponentsInChildren<ParticleSystem>(true);
				for (int i = 0; i < componentsInChildren4.Length; i++)
				{
					componentsInChildren4[i].Play(true);
				}
				Object.Destroy((Object)(object)val3, 1.25f);
			}
			else
			{
				GameObject val4 = new GameObject("Bloodlink Remote Muzzle Flash");
				val4.transform.SetPositionAndRotation(val2.position, aimRotation);
				Light obj3 = val4.AddComponent<Light>();
				obj3.type = (LightType)2;
				obj3.color = ((slot == 4) ? new Color(0.2f, 0.8f, 1f) : new Color(1f, 0.32f, 0.08f));
				obj3.intensity = ((slot == 4) ? 5f : 2.5f);
				obj3.range = ((slot == 4) ? 5f : 2.25f);
				Object.Destroy((Object)val4, 0.08f);
			}
		}

		private static void PlayPrefabOneShots(GameObject prefab, Vector3 position)
		{
			//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_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Expected O, but got Unknown
			if ((Object)(object)prefab == (Object)null)
			{
				return;
			}
			AudioSource[] componentsInChildren = prefab.GetComponentsInChildren<AudioSource>(true);
			int num = 0;
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				if (num >= 4)
				{
					break;
				}
				AudioSource val = componentsInChildren[i];
				if (!((Object)(object)val == (Object)null) && !((Object)(object)val.clip == (Object)null) && !val.loop)
				{
					GameObject val2 = new GameObject("Bloodlink spatial sound");
					val2.transform.position = position;
					AudioSource val3 = val2.AddComponent<AudioSource>();
					val3.clip = val.clip;
					val3.volume = Mathf.Clamp01(val.volume);
					val3.pitch = Mathf.Clamp(val.pitch, 0.25f, 3f);
					val3.spatialBlend = 1f;
					val3.minDistance = Mathf.Max(0.1f, val.minDistance);
					val3.maxDistance = Mathf.Max(val3.minDistance + 0.1f, Mathf.Min(80f, val.maxDistance));
					val3.rolloffMode = val.rolloffMode;
					val3.dopplerLevel = 0f;
					val3.Play();
					Object.Destroy((Object)val2, Mathf.Max(0.25f, val.clip.length / Mathf.Max(0.25f, Mathf.Abs(val3.pitch)) + 0.2f));
					num++;
				}
			}
		}

		private void UpdateWeaponRecoil()
		{
			//IL_0042: 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_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: 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_0084: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)recoilingWeapon == (Object)null))
			{
				if (Time.unscaledTime >= recoilUntil)
				{
					RestoreWeaponRecoil();
					return;
				}
				float num = Mathf.Clamp01((recoilUntil - Time.unscaledTime) / 0.075f);
				recoilingWeapon.localPosition = weaponRestPosition + Vector3.back * (0.055f * num);
				recoilingWeapon.localRotation = weaponRestRotation * Quaternion.Euler(-5f * num, 0f, 0f);
			}
		}

		private void RestoreWeaponRecoil()
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)recoilingWeapon != (Object)null)
			{
				recoilingWeapon.localPosition = weaponRestPosition;
				recoilingWeapon.localRotation = weaponRestRotation;
			}
			recoilingWeapon = null;
			recoilUntil = 0f;
		}

		private void Apply(Vector3 position, Quaternion rotation)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: 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_0015: 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_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: 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_009d: 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_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: 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_00e2: Unknown result type (might be due to invalid IL or missing references)
			float y = ((Quaternion)(ref rotation)).eulerAngles.y;
			if (hasRenderedPosition)
			{
				Vector3 val = position - ((Component)this).transform.position;
				if (((Vector3)(ref val)).sqrMagnitude < 400f)
				{
					position = Vector3.Lerp(((Component)this).transform.position, position, PlayerPositionCorrectionPolicy.RemoteBlend(Time.unscaledDeltaTime));
				}
			}
			hasRenderedPosition = true;
			((Component)this).transform.SetPositionAndRotation(position, Quaternion.Euler(0f, y, 0f));
			Camera main = Camera.main;
			if ((Object)(object)main != (Object)null && (Object)(object)nameplate != (Object)null)
			{
				Quaternion rotation2 = Quaternion.LookRotation(((Component)nameplate).transform.position - ((Component)main).transform.position);
				((Component)nameplate).transform.rotation = rotation2;
				if ((Object)(object)nameplateShadow != (Object)null)
				{
					((Component)nameplateShadow).transform.rotation = rotation2;
				}
			}
		}

		private void Animate(PlayerSnapshot state)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//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_001e: 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_004d: 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_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0445: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0294: Unknown result type (might be due to invalid IL or missing references)
			//IL_0299: Unknown result type (might be due to invalid IL or missing references)
			if (animators.Count == 0)
			{
				return;
			}
			Vector3 val = Vector3.ProjectOnPlane(state.Velocity, Vector3.up);
			if (((Vector3)(ref val)).sqrMagnitude < 0.25f && ((Vector3)(ref sampledPlanarVelocity)).sqrMagnitude > 0.25f)
			{
				val = sampledPlanarVelocity;
			}
			Vector3 val2 = ((Component)this).transform.InverseTransformDirection(val) / 15f;
			bool flag = (state.MovementFlags & 1) != 0;
			bool flag2 = (state.MovementFlags & 2) != 0;
			bool flag3 = (state.MovementFlags & 8) != 0;
			bool flag4 = state.WeaponSlot >= 3;
			bool flag5 = (state.MovementFlags & 4) != 0 && state.Health == 0;
			if (lastDeadState != (flag5 ? 1 : 0))
			{
				lastDeadState = (flag5 ? 1 : 0);
				foreach (Animator animator in animators)
				{
					SetBoolIfPresent(animator, "Dead", flag5);
					SetBoolIfPresent(animator, "IsDead", flag5);
					if (flag5)
					{
						SetTriggerIfPresent(animator, "Death");
						SetTriggerIfPresent(animator, "Die");
					}
				}
				if (!flag5)
				{
					SetWeapon(state.WeaponSlot, state.WeaponVariation, state.WeaponAlternate);
				}
			}
			foreach (Animator animator2 in animators)
			{
				SetBoolIfPresent(animator2, "Dodging", flag && !flag2);
				SetBoolIfPresent(animator2, "Sliding", flag2);
				SetBoolIfPresent(animator2, "InAir", !flag3);
				SetBoolIfPresent(animator2, "BigWeapon", flag4);
				SetFloatIfPresent(animator2, "VelX", flag5 ? 0f : val2.x);
				SetFloatIfPresent(animator2, "VelY", flag5 ? 0f : val2.z);
			}
			if (Time.unscaledTime >= nextAnimatorDiagnosticAt)
			{
				nextAnimatorDiagnosticAt = Time.unscaledTime + 5f;
				BloodlinkPlugin instance = BloodlinkPlugin.Instance;
				if ((Object)(object)instance != (Object)null)
				{
					foreach (Animator animator3 in animators)
					{
						if (!((Object)(object)animator3 == (Object)null) && animator3.isInitialized && !((Object)(object)animator3.runtimeAnimatorController == (Object)null) && animator3.layerCount != 0)
						{
							AnimatorStateInfo currentAnimatorStateInfo = animator3.GetCurrentAnimatorStateInfo(0);
							instance.LogRemoteAnimatorDiagnostics("Remote V1 animation state player " + PlayerId + ": state=" + ((AnimatorStateInfo)(ref currentAnimatorStateInfo)).fullPathHash + ", time=" + ((AnimatorStateInfo)(ref currentAnimatorStateInfo)).normalizedTime.ToString("F2") + ", SnapshotVel=" + ((Vector3)(ref state.Velocity)).ToString("F2") + ", LocalVel=" + ((Vector3)(ref val2)).ToString("F2") + ", Flags=" + state.MovementFlags + ", Dead=" + flag5 + ", VelX=" + animator3.GetFloat("VelX").ToString("F2") + ", VelY=" + animator3.GetFloat("VelY").ToString("F2") + ", InAir=" + animator3.GetBool("InAir") + ", Sliding=" + animator3.GetBool("Sliding") + ", Dodging=" + animator3.GetBool("Dodging") + ".");
						}
					}
				}
			}
			UpdateModelFacing(state, flag2);
			ApplyRemoteAim(state.ViewRotation, flag4);
		}

		private void UpdateModelFacing(PlayerSnapshot state, bool sliding)
		{
			//IL_001a: 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_002f: Unknown result type (might be due to invalid IL or missing references)
			//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_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//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_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: 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_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: 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_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)modelRoot == (Object)null))
			{
				Quaternion val = Quaternion.Euler(0f, ((Component)this).transform.eulerAngles.y, 0f) * modelBaseLocalRotation;
				Vector3 val2 = Vector3.ProjectOnPlane(state.Velocity, Vector3.up);
				if (sliding && ((Vector3)(ref val2)).sqrMagnitude > 1f)
				{
					val = Quaternion.LookRotation(((Vector3)(ref val2)).normalized, Vector3.up) * modelBaseLocalRotation;
				}
				modelRoot.rotation = Quaternion.Slerp(modelRoot.rotation, val, 1f - Mathf.Exp(-12f * Time.unscaledDeltaTime));
			}
		}

		private void UpdateAnimationLayers()
		{
			if (landingLayerWeight <= 0f)
			{
				return;
			}
			landingLayerWeight = Mathf.MoveTowards(landingLayerWeight, 0f, Time.unscaledDeltaTime * 3f);
			foreach (Animator animator in animators)
			{
				if ((Object)(object)animator != (Object)null && animator.layerCount > 1)
				{
					animator.SetLayerWeight(1, landingLayerWeight);
				}
			}
		}

		private void ApplyRemoteAim(Quaternion viewRotation, bool bigWeapon)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: 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_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)remoteHead != (Object)null)
			{
				remoteHead.rotation = viewRotation;
			}
			if ((Object)(object)remoteChest != (Object)null)
			{
				float num = ((Quaternion)(ref viewRotation)).eulerAngles.x;
				if (num > 180f)
				{
					num -= 360f;
				}
				remoteChest.localRotation = Quaternion.Euler(num * 0.35f, 0f, 0f);
			}
			if (!((Object)(object)remoteRightArm == (Object)null))
			{
				if (!bigWeapon)
				{
					AimRemoteArm(remoteRightArm, viewRotation);
				}
				if (remoteRightArm.childCount > 0)
				{
					AimRemoteArm(remoteRightArm.GetChild(0), viewRotation);
				}
			}
		}

		private static void AimRemoteArm(Transform arm, Quaternion viewRotation)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)arm == (Object)null))
			{
				arm.rotation = viewRotation;
				arm.Rotate(Vector3.right, 90f, (Space)1);
				arm.Rotate(Vector3.up, 180f, (Space)1);
			}
		}

		private void SetWeapon(byte slot, byte variation, bool? alternate = null)
		{
			bool flag = alternate ?? lastWeaponAlternate;
			if (hasWeaponState && lastWeaponSlot == slot && lastWeaponVariation == variation && lastWeaponAlternate == flag)
			{
				return;
			}
			bool flag2 = hasWeaponState;
			hasWeaponState = true;
			lastWeaponSlot = slot;
			lastWeaponVariation = variation;
			lastWeaponAlternate = flag;
			int num = ((slot > 0) ? (slot - 1) : 255);
			for (int i = 0; i < baseWeapons.Length; i++)
			{
				if ((Object)(object)baseWeapons[i] != (Object)null)
				{
					baseWeapons[i].SetActive(i == num && !flag);
				}
			}
			for (int j = 0; j < alternateWeapons.Length; j++)
			{
				if ((Object)(object)alternateWeapons[j] != (Object)null)
				{
					alternateWeapons[j].SetActive(j == num && flag);
				}
			}
			if (!flag2)
			{
				return;
			}
			foreach (Animator animator in animators)
			{
				SetTriggerIfPresent(animator, "ChangeWeapon");
			}
		}

		private void ApplyAppearance(uint primary, uint secondary, uint light, byte glow)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: 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_0052: 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_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			if (primary == lastPrimaryColor && secondary == lastSecondaryColor && light == lastLightColor && glow == lastGlowIntensity)
			{
				return;
			}
			lastPrimaryColor = primary;
			lastSecondaryColor = secondary;
			lastLightColor = light;
			lastGlowIntensity = glow;
			Color val = PlayerAppearanceColor.Unpack(primary);
			Color val2 = PlayerAppearanceColor.Unpack(secondary);
			Color val3 = PlayerAppearanceColor.Unpack(light);
			Color val4 = val3 * ((float)(int)glow / 255f);
			int num = Shader.PropertyToID("_Color");
			int num2 = Shader.PropertyToID("_BaseColor");
			int num3 = Shader.PropertyToID("_EmissionColor");
			for (int i = 0; i < visualRenderers.Length; i++)
			{
				Renderer val5 = visualRenderers[i];
				if (!((Object)(object)val5 == (Object)null))
				{
					string text = (((Object)(object)val5.sharedMaterial != (Object)null) ? ((Object)val5.sharedMaterial).name : string.Empty);
					string hint = (((Object)((Component)val5).gameObject).name + " " + text).ToLowerInvariant();
					Color val6 = (IsLightDetail(hint) ? val3 : (IsSecondaryDetail(hint) ? val2 : val));
					MaterialPropertyBlock val7 = appearanceBlocks[i];
					val5.GetPropertyBlock(val7);
					val7.SetColor(num, val6);
					val7.SetColor(num2, val6);
					val7.SetColor(num3, val4);
					val5.SetPropertyBlock(val7);
				}
			}
		}

		private static bool IsLightDetail(string hint)
		{
			if (!hint.Contains("eye") && !hint.Contains("light") && !hint.Contains("glow") && !hint.Contains("emiss"))
			{
				return hint.Contains("led");
			}
			return true;
		}

		private static bool IsSecondaryDetail(string hint)
		{
			if (!hint.Contains("secondary") && !hint.Contains("accent") && !hint.Contains("trim") && !hint.Contains("panel"))
			{
				return hint.Contains("joint");
			}
			return true;
		}

		private void SetBoolIfPresent(Animator animator, string name, bool value)
		{
			if (HasParameter(animator, name, (AnimatorControllerParameterType)4))
			{
				animator.SetBool(name, value);
			}
		}

		private void SetFloatIfPresent(Animator animator, string name, float value)
		{
			if (HasParameter(animator, name, (AnimatorControllerParameterType)1))
			{
				animator.SetFloat(name, value);
			}
		}

		private void SetTriggerIfPresent(Animator animator, string name)
		{
			if (HasParameter(animator, name, (AnimatorControllerParameterType)9))
			{
				animator.SetTrigger(name);
			}
		}

		private void CacheAnimatorParameters(Animator animator)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)animator == (Object)null))
			{
				HashSet<int> hashSet = new HashSet<int>();
				AnimatorControllerParameter[] parameters = animator.parameters;
				foreach (AnimatorControllerParameter val in parameters)
				{
					hashSet.Add(ParameterKey(val.nameHash, val.type));
				}
				animatorParameterHashes[animator] = hashSet;
			}
		}

		private static string GetAnimatorParameterSummary(Animator animator)
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)animator == (Object)null)
			{
				return "<no animator>";
			}
			AnimatorControllerParameter[] parameters = animator.parameters;
			StringBuilder stringBuilder = new StringBuilder(parameters.Length * 16);
			for (int i = 0; i < parameters.Length; i++)
			{
				if (i != 0)
				{
					stringBuilder.Append(", ");
				}
				stringBuilder.Append(parameters[i].name).Append(':').Append(parameters[i].type);
			}
			return stringBuilder.ToString();
		}

		private bool HasParameter(Animator animator, string name, AnimatorControllerParameterType type)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)animator == (Object)null)
			{
				return false;
			}
			if (!animatorParameterHashes.TryGetValue(animator, out var value) || value.Count == 0)
			{
				CacheAnimatorParameters(animator);
			}
			if (animatorParameterHashes.TryGetValue(animator, out value))
			{
				return value.Contains(ParameterKey(Animator.StringToHash(name), type));
			}
			return false;
		}

		private static int ParameterKey(int nameHash, AnimatorControllerParameterType type)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Expected I4, but got Unknown
			return (nameHash * 397) ^ type;
		}
	}
	internal sealed class SpectatorController
	{
		private bool wasDead;

		private float deathStartedAt;

		private uint followedPlayerId;

		private readonly List<PlayerSnapshot> livingPlayers = new List<PlayerSnapshot>(4);

		private CameraController detachedCameraController;

		private Transform detachedCamera;

		private Transform originalCameraParent;

		private Vector3 originalCameraLocalPosition;

		private Quaternion originalCameraLocalRotation;

		private bool originalControllerEnabled;

		private bool cameraDetached;

		private Rigidbody frozenBody;

		private bool bodyWasKinematic;

		private bool bodyUsedGravity;

		private Vector3 cameraVelocity;

		private bool respawnRequested;

		public bool IsActive { get; private set; }

		public bool ShowHud { get; private set; }

		public string Status { get; private set; } = "Spectator";

		public bool ConsumeRespawnRequest()
		{
			if (!respawnRequested)
			{
				return false;
			}
			respawnRequested = false;
			return true;
		}

		public void PrepareForRespawn()
		{
			RestoreCamera();
			wasDead = false;
			bool isActive = (ShowHud = false);
			IsActive = isActive;
			followedPlayerId = 0u;
			respawnRequested = false;
		}

		public void Update(NewMovement localPlayer, NetworkService network)
		{
			//IL_01f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)localPlayer == (Object)null || network == null || !network.IsConnected || !localPlayer.dead)
			{
				RestoreCamera();
				wasDead = false;
				IsActive = false;
				ShowHud = false;
				followedPlayerId = 0u;
				respawnRequested = false;
				return;
			}
			if (!wasDead)
			{
				wasDead = true;
				deathStartedAt = Time.unscaledTime;
			}
			if (Time.unscaledTime - deathStartedAt < 2.1f)
			{
				ShowHud = false;
				Status = "ELIMINATED  /  spectator starts after the death sequence";
				return;
			}
			ShowHud = true;
			if (Input.GetKeyDown((KeyCode)114))
			{
				respawnRequested = true;
			}
			if ((Object)(object)localPlayer.deathSequence != (Object)null && ((Component)localPlayer.deathSequence).gameObject.activeSelf)
			{
				((Component)localPlayer.deathSequence).gameObject.SetActive(false);
			}
			livingPlayers.Clear();
			foreach (PlayerSnapshot value in network.Players.Values)
			{
				if (value.PlayerId != network.LocalPlayerId && (value.MovementFlags & 4) == 0 && network.HasFreshPlayerSnapshot(value.PlayerId, 3f))
				{
					livingPlayers.Add(value);
				}
			}
			livingPlayers.Sort(ComparePlayerIds);
			if (livingPlayers.Count == 0)
			{
				IsActive = false;
				Status = "WAITING  /  no fresh living teammate snapshot";
				return;
			}
			int num = livingPlayers.FindIndex((PlayerSnapshot player) => player.PlayerId == followedPlayerId);
			if (num < 0)
			{
				num = 0;
			}
			if (Input.GetKeyDown((KeyCode)93))
			{
				num = (num + 1) % livingPlayers.Count;
			}
			else if (Input.GetKeyDown((KeyCode)91))
			{
				num = (num + livingPlayers.Count - 1) % livingPlayers.Count;
			}
			PlayerSnapshot playerSnapshot = livingPlayers[num];
			if (followedPlayerId != playerSnapshot.PlayerId)
			{
				cameraVelocity = Vector3.zero;
			}
			followedPlayerId = playerSnapshot.PlayerId;
			IsActive = true;
			Status = "SPECTATING  /  " + playerSnapshot.PlayerName + "  /  [ and ] switch  /  R respawn  /  " + playerSnapshot.Health + " HP";
			CameraController cc = localPlayer.cc;
			if (!((Object)(object)cc == (Object)null) && !((Object)(object)cc.cam == (Object)null))
			{
				DetachCamera(cc);
			}
		}

		private static int ComparePlayerIds(PlayerSnapshot left, PlayerSnapshot right)
		{
			return left.PlayerId.CompareTo(right.PlayerId);
		}

		public void LateUpdate(NewMovement localPlayer, NetworkService network)
		{
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_0210: Unknown result type (might be due to invalid IL or missing references)
			//IL_0215: Unknown result type (might be due to invalid IL or missing references)
			//IL_0217: Unknown result type (might be due to invalid IL or missing references)
			//IL_021b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0220: Unknown result type (might be due to invalid IL or missing references)
			//IL_0236: Unknown result type (might be due to invalid IL or missing references)
			//IL_0241: Unknown result type (might be due to invalid IL or missing references)
			if (!ShowHud || !IsActive || (Object)(object)localPlayer == (Object)null || network == null || !network.IsConnected || !localPlayer.dead)
			{
				return;
			}
			PlayerSnapshot playerSnapshot = null;
			foreach (PlayerSnapshot value in network.Players.Values)
			{
				if (value.PlayerId == followedPlayerId && (value.MovementFlags & 4) == 0 && network.HasFreshPlayerSnapshot(value.PlayerId, 3f))
				{
					playerSnapshot = value;
					break;
				}
			}
			if (playerSnapshot == null || (Object)(object)localPlayer.cc == (Object)null || (Object)(object)localPlayer.cc.cam == (Object)null)
			{
				return;
			}
			Transform transform = ((Component)localPlayer.cc.cam).transform;
			if (!cameraDetached)
			{
				DetachCamera(localPlayer.cc);
			}
			Vector3 position = playerSnapshot.Position;
			if ((Object)(object)BloodlinkPlugin.Instance != (Object)null)
			{
				BloodlinkPlugin.Instance.TryGetSpectatorPose(playerSnapshot.PlayerId, out position);
			}
			float num = Mathf.Min(Time.unscaledDeltaTime, 0.05f);
			Quaternion val = Quaternion.Slerp(transform.rotation, playerSnapshot.ViewRotation, 1f - Mathf.Exp(-10f * num));
			Vector3 val2 = position + Vector3.up * 0.65f;
			Vector3 val3 = -(val * Vector3.forward);
			float num2 = 3.25f;
			RaycastHit[] array = Physics.SphereCastAll(val2, 0.18f, val3, num2, -5, (QueryTriggerInteraction)1);
			for (int i = 0; i < array.Length; i++)
			{
				RaycastHit val4 = array[i];
				if (!((Object)(object)((RaycastHit)(ref val4)).collider == (Object)null) && !((Object)(object)((Component)((RaycastHit)(ref val4)).collider).GetComponentInParent<NewMovement>() != (Object)null) && !((Object)(object)((Component)((RaycastHit)(ref val4)).collider).GetComponentInParent<RemotePlayerVisual>() != (Object)null) && !((Object)(object)((Component)((RaycastHit)(ref val4)).collider).GetComponentInParent<EnemyIdentifier>() != (Object)null))
				{
					num2 = Mathf.Min(num2, Mathf.Max(0.25f, ((RaycastHit)(ref val4)).distance - 0.15f));
				}
			}
			transform.position = Vector3.SmoothDamp(transform.position, val2 + val3 * num2, ref cameraVelocity, 0.13f, 120f, num);
			transform.rotation = val;
		}

		private void DetachCamera(CameraController controller)
		{
			//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_006d: 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_0122: 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_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			if (cameraDetached || (Object)(object)controller == (Object)null || (Object)(object)controller.cam == (Object)null)
			{
				return;
			}
			detachedCameraController = controller;
			originalControllerEnabled = ((Behaviour)controller).enabled;
			detachedCamera = ((Component)controller.cam).transform;
			originalCameraParent = detachedCamera.parent;
			originalCameraLocalPosition = detachedCamera.localPosition;
			originalCameraLocalRotation = detachedCamera.localRotation;
			((Behaviour)controller).enabled = false;
			NewMovement val = ((Component)controller).GetComponentInParent<NewMovement>();
			if ((Object)(object)val == (Object)null)
			{
				val = MonoSingleton<NewMovement>.Instance;
			}
			if ((Object)(object)val != (Object)null && (Object)(object)val.rb != (Object)null)
			{
				frozenBody = val.rb;
				bodyWasKinematic = frozenBody.isKinematic;
				bodyUsedGravity = frozenBody.useGravity;
				if (!frozenBody.isKinematic)
				{
					frozenBody.velocity = Vector3.zero;
					frozenBody.angularVelocity = Vector3.zero;
				}
				frozenBody.isKinematic = true;
				frozenBody.useGravity = false;
			}
			cameraVelocity = Vector3.zero;
			detachedCamera.SetParent((Transform)null, true);
			cameraDetached = true;
		}

		private void RestoreCamera()
		{
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: 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)
			if ((Object)(object)frozenBody != (Object)null)
			{
				frozenBody.isKinematic = bodyWasKinematic;
				frozenBody.useGravity = bodyUsedGravity;
				frozenBody = null;
			}
			if (cameraDetached)
			{
				if ((Object)(object)detachedCamera != (Object)null)
				{
					detachedCamera.SetParent(originalCameraParent, false);
					detachedCamera.localPosition = originalCameraLocalPosition;
					detachedCamera.localRotation = originalCameraLocalRotation;
				}
				if ((Object)(object)detachedCameraController != (Object)null)
				{
					((Behaviour)detachedCameraController).enabled = originalControllerEnabled;
				}
				detachedCameraController = null;
				detachedCamera = null;
				originalCameraParent = null;
				cameraDetached = false;
				cameraVelocity = Vector3.zero;
			}
		}
	}
	internal sealed class V1AppearancePreview : IDisposable
	{
		private const int PreviewLayer = 29;

		private readonly RemotePlayerVisual visual;

		private readonly Transform modelRoot;

		private readonly Camera camera;

		private readonly RenderTexture texture;

		private readonly Light keyLight;

		private float yaw;

		private float distance = 4.1f;

		private uint tick;

		public bool AutoRotate = true;

		public Texture Texture => (Texture)(object)texture;

		public bool IsAvailable
		{
			get
			{
				if ((Object)(object)visual != (Object)null && (Object)(object)modelRoot != (Object)null)
				{
					return (Object)(object)camera != (Object)null;
				}
				return false;
			}
		}

		public void Rotate(float amount)
		{
			yaw = Mathf.Repeat(yaw + amount, 360f);
			AutoRotate = false;
		}

		public void Zoom(float amount)
		{
			distance = Mathf.Clamp(distance + amount, 2.5f, 6f);
		}

		public void ResetView()
		{
			yaw = 0f;
			distance = 4.1f;
			AutoRotate = true;
		}

		public void PlayAction(PlayerAnimationAction action)
		{
			visual?.PlayPlayerAnimation(new PlayerAnimationEvent
			{
				Action = action,
				Speed = 1f
			});
		}

		private V1AppearancePreview(RemotePlayerVisual visual, Transform modelRoot, Camera camera, RenderTexture texture, Light keyLight)
		{
			this.visual = visual;
			this.modelRoot = modelRoot;
			this.camera = camera;
			this.texture = texture;
			this.keyLight = keyLight;
		}

		public static V1AppearancePreview Create(PlayerAnimations template)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: 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_00ea: 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_0140: 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_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Expected O, but got Unknown
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01df: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)template == (Object)null)
			{
				return null;
			}
			RemotePlayerVisual remotePlayerVisual = RemotePlayerVisual.Create(template, uint.MaxValue, "APPEARANCE PREVIEW");
			((Object)remotePlayerVisual).name = "Bloodlink V1 Appearance Preview";
			((Component)remotePlayerVisual).transform.position = new Vector3(50000f, 50000f, 50000f);
			Transform val = ((Component)remotePlayerVisual).transform.Find("Remote V1 Runtime Model");
			if ((Object)(object)val == (Object)null)
			{
				Object.Destroy((Object)(object)((Component)remotePlayerVisual).gameObject);
				return null;
			}
			TextMesh[] componentsInChildren = ((Component)remotePlayerVisual).GetComponentsInChildren<TextMesh>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				((Component)componentsInChildren[i]).gameObject.SetActive(false);
			}
			SetLayerRecursively(((Component)remotePlayerVisual).transform, 29);
			GameObject val2 = new GameObject("Bloodlink Appearance Preview Camera")
			{
				hideFlags = (HideFlags)61
			};
			SetLayerRecursively(val2.transform, 29);
			Camera val3 = val2.AddComponent<Camera>();
			((Behaviour)val3).enabled = false;
			val3.clearFlags = (CameraClearFlags)2;
			val3.backgroundColor = new Color(0.075f, 0.025f, 0.03f, 1f);
			val3.cullingMask = 536870912;
			val3.fieldOfView = 34f;
			val3.nearClipPlane = 0.05f;
			val3.farClipPlane = 40f;
			val3.allowHDR = false;
			val3.allowMSAA = true;
			RenderTexture val4 = new RenderTexture(384, 384, 16, (RenderTextureFormat)0)
			{
				name = "Bloodlink V1 Appearance Preview",
				antiAliasing = 2,
				hideFlags = (HideFlags)61
			};
			val4.Create();
			val3.targetTexture = val4;
			GameObject val5 = new GameObject("Bloodlink Appearance Preview Light")
			{
				hideFlags = (HideFlags)61
			};
			SetLayerRecursively(val5.transform, 29);
			Light val6 = val5.AddComponent<Light>();
			val6.type = (LightType)1;
			val6.color = new Color(1f, 0.78f, 0.72f);
			val6.intensity = 1.15f;
			val6.cullingMask = 536870912;
			val5.transform.rotation = Quaternion.Euler(28f, -32f, 0f);
			return new V1AppearancePreview(remotePlayerVisual, val, val3, val4, val6);
		}

		public void Render(uint primary, uint secondary, uint lights, byte glow, byte weaponSlot, byte weaponVariation)
		{
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: 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_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: 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_00c4: 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_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: 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_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)visual == (Object)null) && !((Object)(object)modelRoot == (Object)null) && !((Object)(object)camera == (Object)null))
			{
				if (AutoRotate)
				{
					yaw = Mathf.Repeat(yaw + Time.unscaledDeltaTime * 18f, 360f);
				}
				modelRoot.localRotation = Quaternion.Euler(0f, yaw, 0f);
				visual.Push(new PlayerSnapshot
				{
					PlayerId = uint.MaxValue,
					PlayerName = string.Empty,
					Position = ((Component)visual).transform.position,
					Rotation = ((Component)visual).transform.rotation,
					ViewRotation = Quaternion.identity,
					WeaponSlot = (byte)Mathf.Clamp((int)weaponSlot, 1, 5),
					WeaponVariation = weaponVariation,
					PrimaryColor = primary,
					SecondaryColor = secondary,
					LightColor = lights,
					GlowIntensity = glow,
					MovementFlags = 8,
					Tick = ++tick
				});
				Vector3 val = modelRoot.position + Vector3.up * 1f;
				((Component)camera).transform.position = val + new Vector3(0f, 0.16f, distance);
				((Component)camera).transform.rotation = Quaternion.LookRotation(val - ((Component)camera).transform.position, Vector3.up);
				camera.Render();
			}
		}

		public void Dispose()
		{
			if ((Object)(object)camera != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)camera).gameObject);
			}
			if ((Object)(object)keyLight != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)keyLight).gameObject);
			}
			if ((Object)(object)texture != (Object)null)
			{
				texture.Release();
				Object.Destroy((Object)(object)tex

BepInEx/plugins/Unity.Networking.Transport.dll

Decompiled 13 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading;
using AOT;
using Microsoft.CodeAnalysis;
using Unity.Baselib.LowLevel;
using Unity.Burst;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Jobs;
using Unity.Mathematics;
using Unity.Networking.Transport.Error;
using Unity.Networking.Transport.Protocols;
using Unity.Networking.Transport.Relay;
using Unity.Networking.Transport.Utilities;
using Unity.Networking.Transport.Utilities.LowLevel.Unsafe;
using Unity.Services.Relay.Models;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: InternalsVisibleTo("Unity.Networking.Transport.EditorTests")]
[assembly: InternalsVisibleTo("Unity.Networking.Transport.RuntimeTests")]
[assembly: InternalsVisibleTo("Unity.Networking.Transport.PlayTests.Performance")]
[assembly: InternalsVisibleTo("Unity.InternalAPINetworkingBridge.001")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Unity.Networking.Transport")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("Unity.Networking.Transport")]
[assembly: AssemblyTitle("Unity.Networking.Transport")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class IsUnmanagedAttribute : Attribute
	{
	}
}
namespace Unity.Networking.Transport
{
	internal static class Base64
	{
		private unsafe static int FromBase64_Decode_UTF16(byte* startInputPtr, int inputLength, byte* startDestPtr, int destLength)
		{
			if (inputLength == 0)
			{
				return 0;
			}
			if (inputLength % 4 != 0)
			{
				Debug.LogError((object)"Base64 string's length must be multiple of 4");
				return -1;
			}
			if (destLength < inputLength / 4 * 3 - 2)
			{
				Debug.LogError((object)"Dest array is too small");
				return -1;
			}
			byte* ptr = startDestPtr;
			int num = inputLength / 4;
			byte* ptr2 = stackalloc byte[256];
			UnsafeUtility.MemSet((void*)ptr2, byte.MaxValue, 256L);
			for (byte b = 0; b < "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".Length; b++)
			{
				ptr2[(int)"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[b]] = b;
			}
			ptr2[61] = 0;
			for (int i = 0; i < num - 1; i++)
			{
				byte b2 = ptr2[(int)(*startInputPtr)];
				byte b3 = ptr2[(int)startInputPtr[2]];
				byte b4 = ptr2[(int)startInputPtr[4]];
				byte b5 = ptr2[(int)startInputPtr[6]];
				if (b2 == byte.MaxValue || b3 == byte.MaxValue || b4 == byte.MaxValue || b5 == byte.MaxValue)
				{
					Debug.LogError((object)"Invalid Base64 symbol");
					return -1;
				}
				*(startDestPtr++) = (byte)((b2 << 2) | (b3 >> 4));
				*(startDestPtr++) = (byte)((b3 << 4) | (b4 >> 2));
				*(startDestPtr++) = (byte)((b4 << 6) | b5);
				startInputPtr += 8;
			}
			byte b6 = startInputPtr[4];
			byte b7 = startInputPtr[6];
			byte b8 = ptr2[(int)(*startInputPtr)];
			byte b9 = ptr2[(int)startInputPtr[2]];
			byte b10 = ptr2[(int)b6];
			byte b11 = ptr2[(int)b7];
			if (b8 == byte.MaxValue || b9 == byte.MaxValue || b10 == byte.MaxValue || b11 == byte.MaxValue)
			{
				Debug.LogError((object)"Invalid Base64 symbol");
				return -1;
			}
			*(startDestPtr++) = (byte)((b8 << 2) | (b9 >> 4));
			if (b6 != 61)
			{
				if (b7 == 61)
				{
					if (destLength < inputLength / 4 * 3 - 1)
					{
						Debug.LogError((object)"Dest array is too small");
						return -1;
					}
					*(startDestPtr++) = (byte)((b9 << 4) | (b10 >> 2));
				}
				else
				{
					if (destLength < inputLength / 4 * 3)
					{
						Debug.LogError((object)"Dest array is too small");
						return -1;
					}
					*(startDestPtr++) = (byte)((b9 << 4) | (b10 >> 2));
					*(startDestPtr++) = (byte)((b10 << 6) | b11);
				}
			}
			return (int)(startDestPtr - ptr);
		}

		public unsafe static int FromBase64String(string base64, byte* dest, int destMaxLength)
		{
			int result;
			fixed (char* startInputPtr = base64)
			{
				result = FromBase64_Decode_UTF16((byte*)startInputPtr, base64.Length, dest, destMaxLength);
			}
			return result;
		}
	}
	internal struct UnsafeBaselibNetworkArray : IDisposable
	{
		[NativeDisableUnsafePtrRestriction]
		private UnsafePtrList<Baselib_RegisteredNetwork_Buffer> m_BufferPool;

		public unsafe UnsafeBaselibNetworkArray(int capacity, int typeSize)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: 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_006b: 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_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: 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_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			long num = typeSize;
			num = capacity * typeSize;
			int num2 = capacity;
			num2 = 1;
			m_BufferPool = new UnsafePtrList<Baselib_RegisteredNetwork_Buffer>(num2, AllocatorHandle.op_Implicit((Allocator)4), (NativeArrayOptions)0);
			Baselib_Memory_PageSizeInfo* ptr = (Baselib_Memory_PageSizeInfo*)stackalloc Baselib_Memory_PageSizeInfo[1];
			Binding.Baselib_Memory_GetPageSizeInfo(ptr);
			ulong defaultPageSize = ((Baselib_Memory_PageSizeInfo)ptr).defaultPageSize;
			for (int i = 0; i < num2; i++)
			{
				ulong num3 = 1uL;
				if ((ulong)num > defaultPageSize)
				{
					num3 = (ulong)math.ceil((double)num / (double)defaultPageSize);
				}
				Baselib_RegisteredNetwork_Buffer* ptr2 = (Baselib_RegisteredNetwork_Buffer*)UnsafeUtility.Malloc((long)UnsafeUtility.SizeOf<Baselib_RegisteredNetwork_Buffer>(), UnsafeUtility.AlignOf<Baselib_RegisteredNetwork_Buffer>(), (Allocator)4);
				Baselib_ErrorState val = default(Baselib_ErrorState);
				Baselib_Memory_PageAllocation val2 = Binding.Baselib_Memory_AllocatePages(((Baselib_Memory_PageSizeInfo)ptr).defaultPageSize, num3, 1uL, (Baselib_Memory_PageState)4, &val);
				if ((int)val.code != 0)
				{
					break;
				}
				UnsafeUtility.MemSet((void*)val2.ptr, (byte)0, (long)(val2.pageCount * val2.pageSize));
				Unsafe.Write(ptr2, Binding.Baselib_RegisteredNetwork_Buffer_Register(val2, &val));
				if ((int)val.code != 0)
				{
					Binding.Baselib_Memory_ReleasePages(val2, &val);
					Unsafe.Write(ptr2, default(Baselib_RegisteredNetwork_Buffer));
				}
				m_BufferPool.Add((void*)ptr2);
			}
		}

		public unsafe void Dispose()
		{
			//IL_0002: 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_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			Baselib_ErrorState val = default(Baselib_ErrorState);
			for (int i = 0; i < m_BufferPool.Length; i++)
			{
				Baselib_RegisteredNetwork_Buffer* intPtr = m_BufferPool[i];
				Baselib_Memory_PageAllocation allocation = ((Baselib_RegisteredNetwork_Buffer)intPtr).allocation;
				Binding.Baselib_RegisteredNetwork_Buffer_Deregister(*intPtr);
				Binding.Baselib_Memory_ReleasePages(allocation, &val);
				UnsafeUtility.Free((void*)intPtr, (Allocator)4);
			}
		}

		public unsafe Baselib_RegisteredNetwork_BufferSlice AtIndexAsSlice(int index, uint elementSize)
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			uint num = 0u;
			Baselib_RegisteredNetwork_Buffer* ptr = null;
			ptr = m_BufferPool[0];
			num = elementSize * (uint)index;
			IntPtr data = (IntPtr)((byte*)(void*)((Baselib_Memory_PageAllocation)(&((Baselib_RegisteredNetwork_Buffer)ptr).allocation)).ptr + num);
			Baselib_RegisteredNetwork_BufferSlice result = default(Baselib_RegisteredNetwork_BufferSlice);
			result.id = ((Baselib_RegisteredNetwork_Buffer)ptr).id;
			result.data = data;
			result.offset = num;
			result.size = elementSize;
			return result;
		}
	}
	public static class BaselibNetworkParameterExtensions
	{
		internal const int k_defaultRxQueueSize = 64;

		internal const int k_defaultTxQueueSize = 64;

		internal const uint k_defaultMaximumPayloadSize = 2000u;

		public static ref NetworkSettings WithBaselibNetworkInterfaceParameters(this ref NetworkSettings settings, int receiveQueueCapacity = 64, int sendQueueCapacity = 64, uint maximumPayloadSize = 2000u)
		{
			BaselibNetworkParameter parameter = new BaselibNetworkParameter
			{
				receiveQueueCapacity = receiveQueueCapacity,
				sendQueueCapacity = sendQueueCapacity,
				maximumPayloadSize = maximumPayloadSize
			};
			settings.AddRawParameterStruct(ref parameter);
			return ref settings;
		}

		public static BaselibNetworkParameter GetBaselibNetworkInterfaceParameters(this ref NetworkSettings settings)
		{
			if (!settings.TryGet<BaselibNetworkParameter>(out var parameter))
			{
				parameter.receiveQueueCapacity = 64;
				parameter.sendQueueCapacity = 64;
				parameter.maximumPayloadSize = 2000u;
			}
			return parameter;
		}
	}
	public struct BaselibNetworkParameter : INetworkParameter
	{
		public int receiveQueueCapacity;

		public int sendQueueCapacity;

		public uint maximumPayloadSize;

		public bool Validate()
		{
			bool result = true;
			if (receiveQueueCapacity <= 0)
			{
				result = false;
				Debug.LogError((object)string.Format("{0} value ({1}) must be greater than 0", "receiveQueueCapacity", receiveQueueCapacity));
			}
			if (sendQueueCapacity <= 0)
			{
				result = false;
				Debug.LogError((object)string.Format("{0} value ({1}) must be greater than 0", "sendQueueCapacity", sendQueueCapacity));
			}
			if (maximumPayloadSize == 0)
			{
				result = false;
				Debug.LogError((object)string.Format("{0} value ({1}) must be greater than 0", "maximumPayloadSize", maximumPayloadSize));
			}
			return result;
		}
	}
	[BurstCompile]
	public struct BaselibNetworkInterface : INetworkInterface, IDisposable
	{
		internal struct Payloads : IDisposable
		{
			public UnsafeAtomicFreeList m_Handles;

			public UnsafeBaselibNetworkArray m_PayloadArray;

			public UnsafeBaselibNetworkArray m_EndpointArray;

			private uint m_PayloadSize;

			public int InUse => m_Handles.InUse;

			public int Capacity => m_Handles.Capacity;

			public bool IsCreated => m_Handles.IsCreated;

			public Payloads(int capacity, uint maxPayloadSize)
			{
				m_PayloadSize = maxPayloadSize;
				m_Handles = new UnsafeAtomicFreeList(capacity, (Allocator)4);
				m_PayloadArray = new UnsafeBaselibNetworkArray(capacity, (int)maxPayloadSize);
				m_EndpointArray = new UnsafeBaselibNetworkArray(capacity, 28);
			}

			public void Dispose()
			{
				m_Handles.Dispose();
				m_PayloadArray.Dispose();
				m_EndpointArray.Dispose();
			}

			public Baselib_RegisteredNetwork_Request GetRequestFromHandle(int handle)
			{
				//IL_0002: Unknown result type (might be due to invalid IL or missing references)
				//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_0025: Unknown result type (might be due to invalid IL or missing references)
				//IL_0036: Unknown result type (might be due to invalid IL or missing references)
				//IL_003b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0040: 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_0046: Unknown result type (might be due to invalid IL or missing references)
				return new Baselib_RegisteredNetwork_Request
				{
					payload = m_PayloadArray.AtIndexAsSlice(handle, m_PayloadSize),
					remoteEndpoint = new Baselib_RegisteredNetwork_Endpoint
					{
						slice = m_EndpointArray.AtIndexAsSlice(handle, 28u)
					}
				};
			}

			public int AcquireHandle()
			{
				return m_Handles.Pop();
			}

			public void ReleaseHandle(int handle)
			{
				m_Handles.Push(handle);
			}
		}

		internal enum SocketStatus
		{
			SocketNormal,
			SocketNeedsRecreate,
			SocketFailed
		}

		internal struct BaselibData
		{
			public Baselib_RegisteredNetwork_Socket_UDP m_Socket;

			public SocketStatus m_SocketStatus;

			public Payloads m_PayloadsTx;

			public NetworkInterfaceEndPoint m_LocalEndpoint;

			public long m_LastUpdateTime;

			public long m_LastSocketRecreateTime;

			public uint m_NumSocketRecreate;
		}

		[BurstCompile]
		private struct FlushSendJob : IJob
		{
			public Payloads Tx;

			[NativeDisableContainerSafetyRestriction]
			public NativeArray<BaselibData> Baselib;

			public unsafe void Execute()
			{
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0026: Unknown result type (might be due to invalid IL or missing references)
				//IL_002e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0033: Unknown result type (might be due to invalid IL or missing references)
				//IL_0035: Unknown result type (might be due to invalid IL or missing references)
				//IL_0036: Unknown result type (might be due to invalid IL or missing references)
				//IL_0063: Unknown result type (might be due to invalid IL or missing references)
				//IL_0066: Invalid comparison between Unknown and I4
				//IL_0042: 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)
				//IL_0058: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
				//IL_0095: Unknown result type (might be due to invalid IL or missing references)
				//IL_0096: Unknown result type (might be due to invalid IL or missing references)
				//IL_009e: Unknown result type (might be due to invalid IL or missing references)
				Baselib_RegisteredNetwork_CompletionResult* ptr = (Baselib_RegisteredNetwork_CompletionResult*)stackalloc Baselib_RegisteredNetwork_CompletionResult[64];
				Baselib_ErrorState val = default(Baselib_ErrorState);
				for (int i = 0; i < Tx.Capacity; i++)
				{
					Baselib_RegisteredNetwork_ProcessStatus val2 = Binding.Baselib_RegisteredNetwork_Socket_UDP_ProcessSend(Baselib[0].m_Socket, &val);
					if ((int)val.code != 0)
					{
						Debug.LogError((object)$"Error on baselib processing send ({val.code})");
						MarkSocketAsNeedingRecreate(Baselib);
						return;
					}
					if ((int)val2 != 1)
					{
						break;
					}
				}
				int num = 0;
				long num2 = (long)Tx.Capacity / 64L + 1;
				while ((num = (int)Binding.Baselib_RegisteredNetwork_Socket_UDP_DequeueSend(Baselib[0].m_Socket, ptr, 64u, &val)) > 0)
				{
					if ((int)val.code != 0)
					{
						MarkSocketAsNeedingRecreate(Baselib);
						break;
					}
					for (int j = 0; j < num; j++)
					{
						Tx.ReleaseHandle((int)((Baselib_RegisteredNetwork_CompletionResult)((byte*)ptr + (nint)j * (nint)Unsafe.SizeOf<Baselib_RegisteredNetwork_CompletionResult>())).requestUserdata - 1);
					}
					if (num2-- < 0)
					{
						break;
					}
				}
			}
		}

		[BurstCompile]
		private struct ReceiveJob : IJob
		{
			public NetworkPacketReceiver Receiver;

			public Payloads Rx;

			[NativeDisableContainerSafetyRestriction]
			public NativeArray<BaselibData> Baselib;

			public unsafe void Execute()
			{
				//IL_0002: Unknown result type (might be due to invalid IL or missing references)
				//IL_0042: 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: Invalid comparison between Unknown and I4
				//IL_0086: 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_0099: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
				//IL_0118: Unknown result type (might be due to invalid IL or missing references)
				//IL_011d: Unknown result type (might be due to invalid IL or missing references)
				//IL_011f: 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_0126: Unknown result type (might be due to invalid IL or missing references)
				//IL_012b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0137: Unknown result type (might be due to invalid IL or missing references)
				//IL_0150: Unknown result type (might be due to invalid IL or missing references)
				//IL_015c: Unknown result type (might be due to invalid IL or missing references)
				//IL_016f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0171: Unknown result type (might be due to invalid IL or missing references)
				//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
				//IL_01f4: Unknown result type (might be due to invalid IL or missing references)
				//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
				Baselib_ErrorState val = default(Baselib_ErrorState);
				BaselibData baselibData = Baselib[0];
				baselibData.m_LastUpdateTime = Receiver.LastUpdateTime;
				Baselib[0] = baselibData;
				int num = 0;
				while ((int)Binding.Baselib_RegisteredNetwork_Socket_UDP_ProcessRecv(Baselib[0].m_Socket, &val) == 1 && num++ < Rx.Capacity)
				{
				}
				Baselib_RegisteredNetwork_CompletionResult* ptr = (Baselib_RegisteredNetwork_CompletionResult*)stackalloc Baselib_RegisteredNetwork_CompletionResult[64];
				int num2 = 0;
				int num3 = 0;
				int num4 = 0;
				do
				{
					num4 = (int)Binding.Baselib_RegisteredNetwork_Socket_UDP_DequeueRecv(Baselib[0].m_Socket, ptr, 64u, &val);
					if ((int)val.code != 0)
					{
						Receiver.ReceiveErrorCode = -10;
						return;
					}
					num2 += num4;
					for (int i = 0; i < num4; i++)
					{
						if ((int)((Baselib_RegisteredNetwork_CompletionResult)((byte*)ptr + (nint)i * (nint)Unsafe.SizeOf<Baselib_RegisteredNetwork_CompletionResult>())).status == 0)
						{
							num3++;
							continue;
						}
						int bytesTransferred = (int)((Baselib_RegisteredNetwork_CompletionResult)((byte*)ptr + (nint)i * (nint)Unsafe.SizeOf<Baselib_RegisteredNetwork_CompletionResult>())).bytesTransferred;
						if (bytesTransferred > 0)
						{
							int handle = (int)((Baselib_RegisteredNetwork_CompletionResult)((byte*)ptr + (nint)i * (nint)Unsafe.SizeOf<Baselib_RegisteredNetwork_CompletionResult>())).requestUserdata - 1;
							Baselib_RegisteredNetwork_Request requestFromHandle = Rx.GetRequestFromHandle(handle);
							Baselib_RegisteredNetwork_BufferSlice slice = requestFromHandle.remoteEndpoint.slice;
							NetworkInterfaceEndPoint address = new NetworkInterfaceEndPoint
							{
								dataLength = (int)slice.size
							};
							UnsafeUtility.MemCpy((void*)address.data, (void*)slice.data, (long)(int)slice.size);
							Receiver.AppendPacket(requestFromHandle.payload.data, ref address, bytesTransferred);
							Rx.ReleaseHandle(handle);
						}
					}
				}
				while ((long)num4 == 64);
				if (num2 > 0 && num3 == num2)
				{
					MarkSocketAsNeedingRecreate(Baselib);
				}
				int num5 = ScheduleAllReceives(Baselib[0].m_Socket, ref Rx);
				if (num5 < 0)
				{
					Receiver.ReceiveErrorCode = num5;
					MarkSocketAsNeedingRecreate(Baselib);
				}
			}
		}

		public static BaselibNetworkParameter DefaultParameters = new BaselibNetworkParameter
		{
			receiveQueueCapacity = 64,
			sendQueueCapacity = 64,
			maximumPayloadSize = 2000u
		};

		private BaselibNetworkParameter configuration;

		private const int k_defaultRxQueueSize = 64;

		private const int k_defaultTxQueueSize = 64;

		private const int k_defaultMaximumPayloadSize = 2000;

		private const uint k_MaxNumSocketRecreate = 1000u;

		private const uint k_RequestsBatchSize = 64u;

		[ReadOnly]
		internal NativeArray<BaselibData> m_Baselib;

		[NativeDisableContainerSafetyRestriction]
		private Payloads m_PayloadsRx;

		[NativeDisableContainerSafetyRestriction]
		private Payloads m_PayloadsTx;

		private UnsafeBaselibNetworkArray m_LocalAndTempEndpoint;

		private static TransportFunctionPointer<NetworkSendInterface.BeginSendMessageDelegate> BeginSendMessageFunctionPointer = new TransportFunctionPointer<NetworkSendInterface.BeginSendMessageDelegate>((NetworkSendInterface.BeginSendMessageDelegate)BeginSendMessage);

		private static TransportFunctionPointer<NetworkSendInterface.EndSendMessageDelegate> EndSendMessageFunctionPointer = new TransportFunctionPointer<NetworkSendInterface.EndSendMessageDelegate>((NetworkSendInterface.EndSendMessageDelegate)EndSendMessage);

		private static TransportFunctionPointer<NetworkSendInterface.AbortSendMessageDelegate> AbortSendMessageFunctionPointer = new TransportFunctionPointer<NetworkSendInterface.AbortSendMessageDelegate>((NetworkSendInterface.AbortSendMessageDelegate)AbortSendMessage);

		public NetworkInterfaceEndPoint LocalEndPoint => m_Baselib[0].m_LocalEndpoint;

		public bool IsCreated => m_Baselib.IsCreated;

		public int CreateInterfaceEndPoint(NetworkEndPoint address, out NetworkInterfaceEndPoint endpoint)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			return CreateInterfaceEndPoint(address.rawNetworkAddress, out endpoint);
		}

		private unsafe int CreateInterfaceEndPoint(Baselib_NetworkAddress address, out NetworkInterfaceEndPoint endpoint)
		{
			//IL_0009: 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_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: 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_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: 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_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Expected I4, but got Unknown
			Baselib_RegisteredNetwork_BufferSlice val = m_LocalAndTempEndpoint.AtIndexAsSlice(0, 28u);
			Baselib_ErrorState val2 = default(Baselib_ErrorState);
			endpoint = default(NetworkInterfaceEndPoint);
			Baselib_RegisteredNetwork_Endpoint val3 = Binding.Baselib_RegisteredNetwork_Endpoint_Create(&address, val, &val2);
			if ((int)val2.code != 0)
			{
				return (int)val2.code;
			}
			endpoint.dataLength = (int)val3.slice.size;
			fixed (byte* data = endpoint.data)
			{
				void* ptr = data;
				UnsafeUtility.MemCpy(ptr, (void*)val3.slice.data, (long)endpoint.dataLength);
			}
			return 0;
		}

		private unsafe NetworkInterfaceEndPoint GetLocalEndPoint(Baselib_RegisteredNetwork_Socket_UDP socket)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: 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_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			Baselib_ErrorState val = default(Baselib_ErrorState);
			Baselib_NetworkAddress address = default(Baselib_NetworkAddress);
			Binding.Baselib_RegisteredNetwork_Socket_UDP_GetNetworkAddress(socket, &address, &val);
			NetworkInterfaceEndPoint endpoint = default(NetworkInterfaceEndPoint);
			if ((int)val.code != 0)
			{
				return endpoint;
			}
			CreateInterfaceEndPoint(address, out endpoint);
			return endpoint;
		}

		public unsafe NetworkEndPoint GetGenericEndPoint(NetworkInterfaceEndPoint endpoint)
		{
			//IL_000a: 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_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: 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_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: 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_0074: Unknown result type (might be due to invalid IL or missing references)
			NetworkEndPoint result = default(NetworkEndPoint);
			Baselib_ErrorState val = default(Baselib_ErrorState);
			Baselib_RegisteredNetwork_BufferSlice slice = m_LocalAndTempEndpoint.AtIndexAsSlice(0, 28u);
			Baselib_RegisteredNetwork_Endpoint val2 = default(Baselib_RegisteredNetwork_Endpoint);
			val2.slice = slice;
			val2.slice.size = (uint)endpoint.dataLength;
			UnsafeUtility.MemCpy((void*)val2.slice.data, (void*)endpoint.data, (long)endpoint.dataLength);
			Binding.Baselib_RegisteredNetwork_Endpoint_GetNetworkAddress(val2, &result.rawNetworkAddress, &val);
			if ((int)val.code != 0)
			{
				return default(NetworkEndPoint);
			}
			return result;
		}

		public int Initialize(NetworkSettings settings)
		{
			//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)
			configuration = settings.GetBaselibNetworkInterfaceParameters();
			m_Baselib = new NativeArray<BaselibData>(1, (Allocator)4, (NativeArrayOptions)1);
			BaselibData baselibData = default(BaselibData);
			m_PayloadsTx = new Payloads(configuration.sendQueueCapacity, configuration.maximumPayloadSize);
			m_PayloadsRx = new Payloads(configuration.receiveQueueCapacity, configuration.maximumPayloadSize);
			m_LocalAndTempEndpoint = new UnsafeBaselibNetworkArray(2, 28);
			baselibData.m_PayloadsTx = m_PayloadsTx;
			m_Baselib[0] = baselibData;
			return 0;
		}

		public void Dispose()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			if (m_Baselib[0].m_Socket.handle != IntPtr.Zero)
			{
				Binding.Baselib_RegisteredNetwork_Socket_UDP_Close(m_Baselib[0].m_Socket);
			}
			m_LocalAndTempEndpoint.Dispose();
			if (m_PayloadsTx.IsCreated)
			{
				m_PayloadsTx.Dispose();
			}
			if (m_PayloadsRx.IsCreated)
			{
				m_PayloadsRx.Dispose();
			}
			m_Baselib.Dispose();
		}

		private static void MarkSocketAsNeedingRecreate(NativeArray<BaselibData> baselib)
		{
			BaselibData baselibData = baselib[0];
			baselibData.m_SocketStatus = SocketStatus.SocketNeedsRecreate;
			baselib[0] = baselibData;
		}

		private void RecreateSocket(long updateTime)
		{
			BaselibData baselibData = m_Baselib[0];
			if (baselibData.m_LastSocketRecreateTime == baselibData.m_LastUpdateTime || baselibData.m_NumSocketRecreate >= 1000)
			{
				Debug.LogError((object)"Unrecoverable socket failure. An unknown condition is preventing the application from reliably creating sockets.");
				baselibData.m_SocketStatus = SocketStatus.SocketFailed;
				m_Baselib[0] = baselibData;
				return;
			}
			Debug.LogWarning((object)"Socket error encountered; attempting recovery by creating a new one.");
			Bind(baselibData.m_LocalEndpoint);
			baselibData = m_Baselib[0];
			baselibData.m_LastSocketRecreateTime = updateTime;
			baselibData.m_NumSocketRecreate++;
			m_Baselib[0] = baselibData;
		}

		public JobHandle ScheduleReceive(NetworkPacketReceiver receiver, JobHandle dep)
		{
			//IL_004b: 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_006b: 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_003e: Unknown result type (might be due to invalid IL or missing references)
			if (m_Baselib[0].m_SocketStatus == SocketStatus.SocketNeedsRecreate)
			{
				RecreateSocket(receiver.LastUpdateTime);
			}
			if (m_Baselib[0].m_SocketStatus == SocketStatus.SocketFailed)
			{
				receiver.ReceiveErrorCode = -10;
				return dep;
			}
			return IJobExtensions.Schedule<ReceiveJob>(new ReceiveJob
			{
				Baselib = m_Baselib,
				Rx = m_PayloadsRx,
				Receiver = receiver
			}, dep);
		}

		public JobHandle ScheduleSend(NativeQueue<QueuedSendMessage> sendQueue, JobHandle dep)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: 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_0013: Unknown result type (might be due to invalid IL or missing references)
			if (m_Baselib[0].m_SocketStatus != SocketStatus.SocketNormal)
			{
				return dep;
			}
			return IJobExtensions.Schedule<FlushSendJob>(new FlushSendJob
			{
				Baselib = m_Baselib,
				Tx = m_PayloadsTx
			}, dep);
		}

		public unsafe int Bind(NetworkInterfaceEndPoint endpoint)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: 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_0042: 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_004b: 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_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Invalid comparison between Unknown and I4
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Invalid comparison between Unknown and I4
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unsupported input type for neg.
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Expected I4, but got Unknown
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			BaselibData baselibData = m_Baselib[0];
			Baselib_RegisteredNetwork_BufferSlice val = m_LocalAndTempEndpoint.AtIndexAsSlice(0, 28u);
			UnsafeUtility.MemCpy((void*)val.data, (void*)endpoint.data, (long)endpoint.dataLength);
			Baselib_ErrorState val2 = default(Baselib_ErrorState);
			Baselib_RegisteredNetwork_Endpoint val3 = default(Baselib_RegisteredNetwork_Endpoint);
			val3.slice = val;
			Baselib_NetworkAddress address = default(Baselib_NetworkAddress);
			Binding.Baselib_RegisteredNetwork_Endpoint_GetNetworkAddress(val3, &address, &val2);
			bool flag = WouldBindFailWithoutAddressReuse(address);
			Baselib_RegisteredNetwork_Socket_UDP socket = checked(Binding.Baselib_RegisteredNetwork_Socket_UDP_Create(&address, (Baselib_NetworkAddress_AddressReuse)1, (uint)configuration.sendQueueCapacity, (uint)configuration.receiveQueueCapacity, &val2));
			if ((int)val2.code != 0)
			{
				if ((int)val2.code == 67108865)
				{
					Debug.LogError((object)"Failed to bind the socket because address is already in use. It is likely that another process is already listening on the same port.");
				}
				if ((int)val2.code != -1)
				{
					return 0 - val2.code;
				}
				return -10;
			}
			if (m_Baselib[0].m_Socket.handle != IntPtr.Zero)
			{
				Binding.Baselib_RegisteredNetwork_Socket_UDP_Close(m_Baselib[0].m_Socket);
				m_PayloadsRx.Dispose();
				m_PayloadsRx = new Payloads(configuration.receiveQueueCapacity, configuration.maximumPayloadSize);
			}
			int num = ScheduleAllReceives(socket, ref m_PayloadsRx);
			if (num < 0)
			{
				return num;
			}
			if (baselibData.m_SocketStatus != SocketStatus.SocketNeedsRecreate && flag)
			{
				ushort port = GetGenericEndPoint(endpoint).Port;
				Debug.LogWarning((object)($"Port {port} is likely already in use by another application. " + "Socket was still created, but expect erroneous behavior. This condition will become a failure starting in version 2.0 of Unity Transport."));
			}
			baselibData.m_Socket = socket;
			baselibData.m_SocketStatus = SocketStatus.SocketNormal;
			baselibData.m_LocalEndpoint = GetLocalEndPoint(socket);
			m_Baselib[0] = baselibData;
			return 0;
		}

		private unsafe bool WouldBindFailWithoutAddressReuse(Baselib_NetworkAddress address)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//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)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Invalid comparison between Unknown and I4
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			Baselib_ErrorState val = default(Baselib_ErrorState);
			Baselib_RegisteredNetwork_Socket_UDP val2 = checked(Binding.Baselib_RegisteredNetwork_Socket_UDP_Create(&address, (Baselib_NetworkAddress_AddressReuse)0, (uint)configuration.sendQueueCapacity, (uint)configuration.receiveQueueCapacity, &val));
			if ((int)val.code == 0)
			{
				Binding.Baselib_RegisteredNetwork_Socket_UDP_Close(val2);
			}
			return (int)val.code == 67108865;
		}

		public int Listen()
		{
			return 0;
		}

		public unsafe NetworkSendInterface CreateSendInterface()
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			return new NetworkSendInterface
			{
				BeginSendMessage = BeginSendMessageFunctionPointer,
				EndSendMessage = EndSendMessageFunctionPointer,
				AbortSendMessage = AbortSendMessageFunctionPointer,
				UserData = (IntPtr)NativeArrayUnsafeUtility.GetUnsafePtr<BaselibData>(m_Baselib)
			};
		}

		[BurstCompile(DisableDirectCall = true)]
		[MonoPInvokeCallback(typeof(NetworkSendInterface.BeginSendMessageDelegate))]
		private unsafe static int BeginSendMessage(out NetworkInterfaceSendHandle handle, IntPtr userData, int requiredPayloadSize)
		{
			//IL_0028: 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_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: 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_005b: 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_006c: Unknown result type (might be due to invalid IL or missing references)
			BaselibData* ptr = (BaselibData*)(void*)userData;
			handle = default(NetworkInterfaceSendHandle);
			int num = ptr->m_PayloadsTx.AcquireHandle();
			if (num < 0)
			{
				return -5;
			}
			Baselib_RegisteredNetwork_Request requestFromHandle = ptr->m_PayloadsTx.GetRequestFromHandle(num);
			if ((int)requestFromHandle.payload.size < requiredPayloadSize)
			{
				ptr->m_PayloadsTx.ReleaseHandle(num);
				return -4;
			}
			handle.id = num;
			handle.size = 0;
			handle.data = requestFromHandle.payload.data;
			handle.capacity = (int)requestFromHandle.payload.size;
			return 0;
		}

		[BurstCompile(DisableDirectCall = true)]
		[MonoPInvokeCallback(typeof(NetworkSendInterface.EndSendMessageDelegate))]
		private unsafe static int EndSendMessage(ref NetworkInterfaceSendHandle handle, ref NetworkInterfaceEndPoint address, IntPtr userData, ref NetworkSendQueueHandle sendQueueHandle)
		{
			//IL_0015: 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_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: 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_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			BaselibData* ptr = (BaselibData*)(void*)userData;
			int id = handle.id;
			Baselib_RegisteredNetwork_Request requestFromHandle = ptr->m_PayloadsTx.GetRequestFromHandle(id);
			requestFromHandle.requestUserdata = (IntPtr)(id + 1);
			requestFromHandle.payload.size = (uint)handle.size;
			NetworkInterfaceEndPoint networkInterfaceEndPoint = address;
			UnsafeUtility.MemCpy((void*)requestFromHandle.remoteEndpoint.slice.data, (void*)networkInterfaceEndPoint.data, (long)address.dataLength);
			Baselib_RegisteredNetwork_Request* ptr2 = &requestFromHandle;
			Baselib_ErrorState val = default(Baselib_ErrorState);
			int num = (int)Binding.Baselib_RegisteredNetwork_Socket_UDP_ScheduleSend(ptr->m_Socket, ptr2, 1u, &val);
			if ((int)val.code != 0 || (long)num != 1)
			{
				ptr->m_PayloadsTx.ReleaseHandle(id);
				return -5;
			}
			return handle.size;
		}

		[BurstCompile(DisableDirectCall = true)]
		[MonoPInvokeCallback(typeof(NetworkSendInterface.AbortSendMessageDelegate))]
		private unsafe static void AbortSendMessage(ref NetworkInterfaceSendHandle handle, IntPtr userData)
		{
			BaselibData* ptr = (BaselibData*)(void*)userData;
			int id = handle.id;
			ptr->m_PayloadsTx.ReleaseHandle(id);
		}

		private unsafe static int ScheduleAllReceives(Baselib_RegisteredNetwork_Socket_UDP socket, ref Payloads PayloadsRx)
		{
			//IL_0002: 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_007e: 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_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Invalid comparison between Unknown and I4
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unsupported input type for neg.
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Expected I4, but got Unknown
			Baselib_ErrorState val = default(Baselib_ErrorState);
			Baselib_RegisteredNetwork_Request* ptr = (Baselib_RegisteredNetwork_Request*)stackalloc Baselib_RegisteredNetwork_Request[64];
			int num = 0;
			do
			{
				for (num = 0; (long)num < 64L; num++)
				{
					if (PayloadsRx.InUse >= PayloadsRx.Capacity)
					{
						break;
					}
					int num2 = PayloadsRx.AcquireHandle();
					Unsafe.Write((byte*)ptr + (nint)num * (nint)Unsafe.SizeOf<Baselib_RegisteredNetwork_Request>(), PayloadsRx.GetRequestFromHandle(num2));
					((Baselib_RegisteredNetwork_Request)((byte*)ptr + (nint)num * (nint)Unsafe.SizeOf<Baselib_RegisteredNetwork_Request>())).requestUserdata = (IntPtr)num2 + 1;
				}
				if (num <= 0)
				{
					continue;
				}
				Binding.Baselib_RegisteredNetwork_Socket_UDP_ScheduleRecv(socket, ptr, (uint)num, &val);
				if ((int)val.code != 0)
				{
					if ((int)val.code != -1)
					{
						return 0 - val.code;
					}
					return -10;
				}
			}
			while ((long)num == 64);
			return 0;
		}

		private bool ValidateParameters(BaselibNetworkParameter param)
		{
			if (param.receiveQueueCapacity <= 0)
			{
				return false;
			}
			if (param.sendQueueCapacity <= 0)
			{
				return false;
			}
			return true;
		}

		private bool TryExtractParameters(out BaselibNetworkParameter config, params INetworkParameter[] param)
		{
			for (int i = 0; i < param.Length; i++)
			{
				if (param[i] is BaselibNetworkParameter && ValidateParameters((BaselibNetworkParameter)(object)param[i]))
				{
					config = (BaselibNetworkParameter)(object)param[i];
					return true;
				}
			}
			config = default(BaselibNetworkParameter);
			return false;
		}
	}
	[StructLayout(LayoutKind.Explicit)]
	internal struct UIntFloat
	{
		[FieldOffset(0)]
		public float floatValue;

		[FieldOffset(0)]
		public uint intValue;

		[FieldOffset(0)]
		public double doubleValue;

		[FieldOffset(0)]
		public ulong longValue;
	}
	public struct DataStreamWriter
	{
		private struct StreamData
		{
			public unsafe byte* buffer;

			public int length;

			public int capacity;

			public ulong bitBuffer;

			public int bitIndex;

			public int failedWrites;
		}

		[NativeDisableUnsafePtrRestriction]
		private StreamData m_Data;

		internal IntPtr m_SendHandleData;

		public unsafe static bool IsLittleEndian
		{
			get
			{
				uint num = 1u;
				byte* ptr = (byte*)(&num);
				return *ptr == 1;
			}
		}

		public unsafe bool IsCreated => m_Data.buffer != null;

		public bool HasFailedWrites => m_Data.failedWrites > 0;

		public int Capacity => m_Data.capacity;

		public int Length
		{
			get
			{
				SyncBitData();
				return m_Data.length + (m_Data.bitIndex + 7 >> 3);
			}
		}

		public int LengthInBits
		{
			get
			{
				SyncBitData();
				return m_Data.length * 8 + m_Data.bitIndex;
			}
		}

		public DataStreamWriter(int length, Allocator allocator)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			Initialize(out this, new NativeArray<byte>(length, allocator, (NativeArrayOptions)1));
		}

		public DataStreamWriter(NativeArray<byte> data)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			Initialize(out this, data);
		}

		public unsafe DataStreamWriter(byte* data, int length)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			NativeArray<byte> data2 = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray<byte>((void*)data, length, (Allocator)0);
			Initialize(out this, data2);
		}

		public unsafe NativeArray<byte> AsNativeArray()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			return NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray<byte>((void*)m_Data.buffer, Length, (Allocator)0);
		}

		private unsafe static void Initialize(out DataStreamWriter self, NativeArray<byte> data)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			self.m_SendHandleData = IntPtr.Zero;
			self.m_Data.capacity = data.Length;
			self.m_Data.length = 0;
			self.m_Data.buffer = (byte*)NativeArrayUnsafeUtility.GetUnsafePtr<byte>(data);
			self.m_Data.bitBuffer = 0uL;
			self.m_Data.bitIndex = 0;
			self.m_Data.failedWrites = 0;
		}

		private static short ByteSwap(short val)
		{
			return (short)(((val & 0xFF) << 8) | ((val >> 8) & 0xFF));
		}

		private static int ByteSwap(int val)
		{
			return ((val & 0xFF) << 24) | ((val & 0xFF00) << 8) | ((val >> 8) & 0xFF00) | ((val >> 24) & 0xFF);
		}

		private unsafe void SyncBitData()
		{
			int num = m_Data.bitIndex;
			if (num > 0)
			{
				ulong num2 = m_Data.bitBuffer;
				int num3 = 0;
				while (num > 0)
				{
					m_Data.buffer[m_Data.length + num3] = (byte)num2;
					num -= 8;
					num2 >>= 8;
					num3++;
				}
			}
		}

		public unsafe void Flush()
		{
			while (m_Data.bitIndex > 0)
			{
				m_Data.buffer[m_Data.length++] = (byte)m_Data.bitBuffer;
				m_Data.bitIndex -= 8;
				m_Data.bitBuffer >>= 8;
			}
			m_Data.bitIndex = 0;
		}

		public unsafe bool WriteBytes(byte* data, int bytes)
		{
			if (m_Data.length + (m_Data.bitIndex + 7 >> 3) + bytes > m_Data.capacity)
			{
				m_Data.failedWrites++;
				return false;
			}
			Flush();
			UnsafeUtility.MemCpy((void*)(m_Data.buffer + m_Data.length), (void*)data, (long)bytes);
			m_Data.length += bytes;
			return true;
		}

		public unsafe bool WriteByte(byte value)
		{
			return WriteBytes(&value, 1);
		}

		public unsafe bool WriteBytes(NativeArray<byte> value)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			return WriteBytes((byte*)NativeArrayUnsafeUtility.GetUnsafeReadOnlyPtr<byte>(value), value.Length);
		}

		public unsafe bool WriteShort(short value)
		{
			return WriteBytes((byte*)(&value), 2);
		}

		public unsafe bool WriteUShort(ushort value)
		{
			return WriteBytes((byte*)(&value), 2);
		}

		public unsafe bool WriteInt(int value)
		{
			return WriteBytes((byte*)(&value), 4);
		}

		public unsafe bool WriteUInt(uint value)
		{
			return WriteBytes((byte*)(&value), 4);
		}

		public unsafe bool WriteLong(long value)
		{
			return WriteBytes((byte*)(&value), 8);
		}

		public unsafe bool WriteULong(ulong value)
		{
			return WriteBytes((byte*)(&value), 8);
		}

		public unsafe bool WriteShortNetworkByteOrder(short value)
		{
			short num = (IsLittleEndian ? ByteSwap(value) : value);
			return WriteBytes((byte*)(&num), 2);
		}

		public bool WriteUShortNetworkByteOrder(ushort value)
		{
			return WriteShortNetworkByteOrder((short)value);
		}

		public unsafe bool WriteIntNetworkByteOrder(int value)
		{
			int num = (IsLittleEndian ? ByteSwap(value) : value);
			return WriteBytes((byte*)(&num), 4);
		}

		public bool WriteUIntNetworkByteOrder(uint value)
		{
			return WriteIntNetworkByteOrder((int)value);
		}

		public bool WriteFloat(float value)
		{
			UIntFloat uIntFloat = new UIntFloat
			{
				floatValue = value
			};
			return WriteInt((int)uIntFloat.intValue);
		}

		private unsafe void FlushBits()
		{
			while (m_Data.bitIndex >= 8)
			{
				m_Data.buffer[m_Data.length++] = (byte)m_Data.bitBuffer;
				m_Data.bitIndex -= 8;
				m_Data.bitBuffer >>= 8;
			}
		}

		private void WriteRawBitsInternal(uint value, int numbits)
		{
			m_Data.bitBuffer |= (ulong)value << m_Data.bitIndex;
			m_Data.bitIndex += numbits;
		}

		public bool WriteRawBits(uint value, int numbits)
		{
			if (m_Data.length + (m_Data.bitIndex + numbits + 7 >> 3) > m_Data.capacity)
			{
				m_Data.failedWrites++;
				return false;
			}
			WriteRawBitsInternal(value, numbits);
			FlushBits();
			return true;
		}

		public unsafe bool WritePackedUInt(uint value, NetworkCompressionModel model)
		{
			int num = model.CalculateBucket(value);
			uint num2 = model.bucketOffsets[num];
			int num3 = model.bucketSizes[num];
			ushort num4 = model.encodeTable[num];
			if (m_Data.length + (m_Data.bitIndex + (num4 & 0xFF) + num3 + 7 >> 3) > m_Data.capacity)
			{
				m_Data.failedWrites++;
				return false;
			}
			WriteRawBitsInternal((uint)(num4 >> 8), num4 & 0xFF);
			WriteRawBitsInternal(value - num2, num3);
			FlushBits();
			return true;
		}

		public bool WritePackedULong(ulong value, NetworkCompressionModel model)
		{
			return WritePackedUInt((uint)(value >> 32), model) & WritePackedUInt((uint)(value & 0xFFFFFFFFu), model);
		}

		public bool WritePackedInt(int value, NetworkCompressionModel model)
		{
			uint value2 = (uint)((value >> 31) ^ (value << 1));
			return WritePackedUInt(value2, model);
		}

		public bool WritePackedLong(long value, NetworkCompressionModel model)
		{
			ulong value2 = (ulong)((value >> 63) ^ (value << 1));
			return WritePackedULong(value2, model);
		}

		public bool WritePackedFloat(float value, NetworkCompressionModel model)
		{
			return WritePackedFloatDelta(value, 0f, model);
		}

		public bool WritePackedUIntDelta(uint value, uint baseline, NetworkCompressionModel model)
		{
			int value2 = (int)(baseline - value);
			return WritePackedInt(value2, model);
		}

		public bool WritePackedIntDelta(int value, int baseline, NetworkCompressionModel model)
		{
			int value2 = baseline - value;
			return WritePackedInt(value2, model);
		}

		public bool WritePackedLongDelta(long value, long baseline, NetworkCompressionModel model)
		{
			long value2 = baseline - value;
			return WritePackedLong(value2, model);
		}

		public bool WritePackedULongDelta(ulong value, ulong baseline, NetworkCompressionModel model)
		{
			long value2 = (long)(baseline - value);
			return WritePackedLong(value2, model);
		}

		public bool WritePackedFloatDelta(float value, float baseline, NetworkCompressionModel model)
		{
			int num = 0;
			if (value != baseline)
			{
				num = 32;
			}
			if (m_Data.length + (m_Data.bitIndex + 1 + num + 7 >> 3) > m_Data.capacity)
			{
				m_Data.failedWrites++;
				return false;
			}
			if (num == 0)
			{
				WriteRawBitsInternal(0u, 1);
			}
			else
			{
				WriteRawBitsInternal(1u, 1);
				UIntFloat uIntFloat = new UIntFloat
				{
					floatValue = value
				};
				WriteRawBitsInternal(uIntFloat.intValue, num);
			}
			FlushBits();
			return true;
		}

		public unsafe bool WriteFixedString32(FixedString32Bytes str)
		{
			int bytes = (int)str + 2;
			byte* data = (byte*)(&str);
			return WriteBytes(data, bytes);
		}

		public unsafe bool WriteFixedString64(FixedString64Bytes str)
		{
			int bytes = (int)str + 2;
			byte* data = (byte*)(&str);
			return WriteBytes(data, bytes);
		}

		public unsafe bool WriteFixedString128(FixedString128Bytes str)
		{
			int bytes = (int)str + 2;
			byte* data = (byte*)(&str);
			return WriteBytes(data, bytes);
		}

		public unsafe bool WriteFixedString512(FixedString512Bytes str)
		{
			int bytes = (int)str + 2;
			byte* data = (byte*)(&str);
			return WriteBytes(data, bytes);
		}

		public unsafe bool WriteFixedString4096(FixedString4096Bytes str)
		{
			int bytes = (int)str + 2;
			byte* data = (byte*)(&str);
			return WriteBytes(data, bytes);
		}

		public unsafe bool WritePackedFixedString32Delta(FixedString32Bytes str, FixedString32Bytes baseline, NetworkCompressionModel model)
		{
			ushort length = (ushort)str;
			byte* data = (byte*)(&str) + 2;
			return WritePackedFixedStringDelta(data, length, (byte*)(&baseline) + 2, (uint)baseline, model);
		}

		public unsafe bool WritePackedFixedString64Delta(FixedString64Bytes str, FixedString64Bytes baseline, NetworkCompressionModel model)
		{
			ushort length = (ushort)str;
			byte* data = (byte*)(&str) + 2;
			return WritePackedFixedStringDelta(data, length, (byte*)(&baseline) + 2, (uint)baseline, model);
		}

		public unsafe bool WritePackedFixedString128Delta(FixedString128Bytes str, FixedString128Bytes baseline, NetworkCompressionModel model)
		{
			ushort length = (ushort)str;
			byte* data = (byte*)(&str) + 2;
			return WritePackedFixedStringDelta(data, length, (byte*)(&baseline) + 2, (uint)baseline, model);
		}

		public unsafe bool WritePackedFixedString512Delta(FixedString512Bytes str, FixedString512Bytes baseline, NetworkCompressionModel model)
		{
			ushort length = (ushort)str;
			byte* data = (byte*)(&str) + 2;
			return WritePackedFixedStringDelta(data, length, (byte*)(&baseline) + 2, (uint)baseline, model);
		}

		public unsafe bool WritePackedFixedString4096Delta(FixedString4096Bytes str, FixedString4096Bytes baseline, NetworkCompressionModel model)
		{
			ushort length = (ushort)str;
			byte* data = (byte*)(&str) + 2;
			return WritePackedFixedStringDelta(data, length, (byte*)(&baseline) + 2, (uint)baseline, model);
		}

		private unsafe bool WritePackedFixedStringDelta(byte* data, uint length, byte* baseData, uint baseLength, NetworkCompressionModel model)
		{
			StreamData data2 = m_Data;
			if (!WritePackedUIntDelta(length, baseLength, model))
			{
				return false;
			}
			bool flag = false;
			if (length <= baseLength)
			{
				for (uint num = 0u; num < length; num++)
				{
					flag |= !WritePackedUIntDelta(data[num], baseData[num], model);
				}
			}
			else
			{
				for (uint num2 = 0u; num2 < baseLength; num2++)
				{
					flag |= !WritePackedUIntDelta(data[num2], baseData[num2], model);
				}
				for (uint num3 = baseLength; num3 < length; num3++)
				{
					flag |= !WritePackedUInt(data[num3], model);
				}
			}
			if (flag)
			{
				m_Data = data2;
				m_Data.failedWrites++;
			}
			return !flag;
		}

		public void Clear()
		{
			m_Data.length = 0;
			m_Data.bitIndex = 0;
			m_Data.bitBuffer = 0uL;
			m_Data.failedWrites = 0;
		}

		[Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
		private void CheckRead()
		{
		}

		[Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
		private void CheckWrite()
		{
		}

		[Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
		private static void CheckAllocator(Allocator allocator)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			if ((int)allocator != 2)
			{
				throw new InvalidOperationException("DataStreamWriters can only be created with temp memory");
			}
		}

		[Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
		private static void CheckBits(uint value, int numbits)
		{
			if (numbits < 0 || numbits > 32)
			{
				throw new ArgumentOutOfRangeException("Invalid number of bits");
			}
			if ((ulong)value >= (ulong)(1L << numbits))
			{
				throw new ArgumentOutOfRangeException("Value does not fit in the specified number of bits");
			}
		}
	}
	public struct DataStreamReader
	{
		private struct Context
		{
			public int m_ReadByteIndex;

			public int m_BitIndex;

			public ulong m_BitBuffer;

			public int m_FailedReads;
		}

		[NativeDisableUnsafePtrRestriction]
		private unsafe byte* m_bufferPtr;

		private Context m_Context;

		private int m_Length;

		public bool IsLittleEndian => DataStreamWriter.IsLittleEndian;

		public bool HasFailedReads => m_Context.m_FailedReads > 0;

		public int Length => m_Length;

		public unsafe bool IsCreated => m_bufferPtr != null;

		public DataStreamReader(NativeArray<byte> array)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			Initialize(out this, array);
		}

		public unsafe DataStreamReader(byte* data, int length)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			NativeArray<byte> array = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray<byte>((void*)data, length, (Allocator)0);
			Initialize(out this, array);
		}

		private unsafe static void Initialize(out DataStreamReader self, NativeArray<byte> array)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			self.m_bufferPtr = (byte*)NativeArrayUnsafeUtility.GetUnsafeReadOnlyPtr<byte>(array);
			self.m_Length = array.Length;
			self.m_Context = default(Context);
		}

		private static short ByteSwap(short val)
		{
			return (short)(((val & 0xFF) << 8) | ((val >> 8) & 0xFF));
		}

		private static int ByteSwap(int val)
		{
			return ((val & 0xFF) << 24) | ((val & 0xFF00) << 8) | ((val >> 8) & 0xFF00) | ((val >> 24) & 0xFF);
		}

		public unsafe void ReadBytes(byte* data, int length)
		{
			if (GetBytesRead() + length > m_Length)
			{
				m_Context.m_FailedReads++;
				UnsafeUtility.MemClear((void*)data, (long)length);
				return;
			}
			m_Context.m_ReadByteIndex -= m_Context.m_BitIndex >> 3;
			m_Context.m_BitIndex = 0;
			m_Context.m_BitBuffer = 0uL;
			UnsafeUtility.MemCpy((void*)data, (void*)(m_bufferPtr + m_Context.m_ReadByteIndex), (long)length);
			m_Context.m_ReadByteIndex += length;
		}

		public unsafe void ReadBytes(NativeArray<byte> array)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			ReadBytes((byte*)NativeArrayUnsafeUtility.GetUnsafePtr<byte>(array), array.Length);
		}

		public int GetBytesRead()
		{
			return m_Context.m_ReadByteIndex - (m_Context.m_BitIndex >> 3);
		}

		public int GetBitsRead()
		{
			return (m_Context.m_ReadByteIndex << 3) - m_Context.m_BitIndex;
		}

		public void SeekSet(int pos)
		{
			if (pos > m_Length)
			{
				m_Context.m_FailedReads++;
				return;
			}
			m_Context.m_ReadByteIndex = pos;
			m_Context.m_BitIndex = 0;
			m_Context.m_BitBuffer = 0uL;
		}

		public unsafe byte ReadByte()
		{
			byte result = default(byte);
			ReadBytes(&result, 1);
			return result;
		}

		public unsafe short ReadShort()
		{
			short result = default(short);
			ReadBytes((byte*)(&result), 2);
			return result;
		}

		public unsafe ushort ReadUShort()
		{
			ushort result = default(ushort);
			ReadBytes((byte*)(&result), 2);
			return result;
		}

		public unsafe int ReadInt()
		{
			int result = default(int);
			ReadBytes((byte*)(&result), 4);
			return result;
		}

		public unsafe uint ReadUInt()
		{
			uint result = default(uint);
			ReadBytes((byte*)(&result), 4);
			return result;
		}

		public unsafe long ReadLong()
		{
			long result = default(long);
			ReadBytes((byte*)(&result), 8);
			return result;
		}

		public unsafe ulong ReadULong()
		{
			ulong result = default(ulong);
			ReadBytes((byte*)(&result), 8);
			return result;
		}

		public unsafe short ReadShortNetworkByteOrder()
		{
			short num = default(short);
			ReadBytes((byte*)(&num), 2);
			if (!IsLittleEndian)
			{
				return num;
			}
			return ByteSwap(num);
		}

		public ushort ReadUShortNetworkByteOrder()
		{
			return (ushort)ReadShortNetworkByteOrder();
		}

		public unsafe int ReadIntNetworkByteOrder()
		{
			int num = default(int);
			ReadBytes((byte*)(&num), 4);
			if (!IsLittleEndian)
			{
				return num;
			}
			return ByteSwap(num);
		}

		public uint ReadUIntNetworkByteOrder()
		{
			return (uint)ReadIntNetworkByteOrder();
		}

		public float ReadFloat()
		{
			UIntFloat uIntFloat = new UIntFloat
			{
				intValue = (uint)ReadInt()
			};
			return uIntFloat.floatValue;
		}

		public unsafe uint ReadPackedUInt(NetworkCompressionModel model)
		{
			FillBitBuffer();
			uint num = 63u;
			uint num2 = (uint)(int)m_Context.m_BitBuffer & num;
			ushort num3 = model.decodeTable[(int)num2];
			int num4 = num3 >> 8;
			int num5 = num3 & 0xFF;
			if (m_Context.m_BitIndex < num5)
			{
				m_Context.m_FailedReads++;
				return 0u;
			}
			m_Context.m_BitBuffer >>= num5;
			m_Context.m_BitIndex -= num5;
			uint num6 = model.bucketOffsets[num4];
			int numbits = model.bucketSizes[num4];
			return ReadRawBitsInternal(numbits) + num6;
		}

		private unsafe void FillBitBuffer()
		{
			while (m_Context.m_BitIndex <= 56 && m_Context.m_ReadByteIndex < m_Length)
			{
				m_Context.m_BitBuffer |= (ulong)m_bufferPtr[m_Context.m_ReadByteIndex++] << m_Context.m_BitIndex;
				m_Context.m_BitIndex += 8;
			}
		}

		private uint ReadRawBitsInternal(int numbits)
		{
			if (m_Context.m_BitIndex < numbits)
			{
				m_Context.m_FailedReads++;
				return 0u;
			}
			int result = (int)((long)m_Context.m_BitBuffer & ((1L << numbits) - 1));
			m_Context.m_BitBuffer >>= numbits;
			m_Context.m_BitIndex -= numbits;
			return (uint)result;
		}

		public uint ReadRawBits(int numbits)
		{
			FillBitBuffer();
			return ReadRawBitsInternal(numbits);
		}

		public ulong ReadPackedULong(NetworkCompressionModel model)
		{
			return ((ulong)ReadPackedUInt(model) << 32) | ReadPackedUInt(model);
		}

		public int ReadPackedInt(NetworkCompressionModel model)
		{
			uint num = ReadPackedUInt(model);
			return (int)((num >> 1) ^ (0 - (num & 1)));
		}

		public long ReadPackedLong(NetworkCompressionModel model)
		{
			ulong num = ReadPackedULong(model);
			return (long)((num >> 1) ^ (0L - (num & 1)));
		}

		public float ReadPackedFloat(NetworkCompressionModel model)
		{
			return ReadPackedFloatDelta(0f, model);
		}

		public int ReadPackedIntDelta(int baseline, NetworkCompressionModel model)
		{
			int num = ReadPackedInt(model);
			return baseline - num;
		}

		public uint ReadPackedUIntDelta(uint baseline, NetworkCompressionModel model)
		{
			uint num = (uint)ReadPackedInt(model);
			return baseline - num;
		}

		public long ReadPackedLongDelta(long baseline, NetworkCompressionModel model)
		{
			long num = ReadPackedLong(model);
			return baseline - num;
		}

		public ulong ReadPackedULongDelta(ulong baseline, NetworkCompressionModel model)
		{
			ulong num = (ulong)ReadPackedLong(model);
			return baseline - num;
		}

		public float ReadPackedFloatDelta(float baseline, NetworkCompressionModel model)
		{
			FillBitBuffer();
			if (ReadRawBitsInternal(1) == 0)
			{
				return baseline;
			}
			int numbits = 32;
			return new UIntFloat
			{
				intValue = ReadRawBitsInternal(numbits)
			}.floatValue;
		}

		public unsafe FixedString32Bytes ReadFixedString32()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			FixedString32Bytes result = default(FixedString32Bytes);
			byte* data = (byte*)(&result) + 2;
			result = (FixedString32Bytes)ReadFixedString(data, ((FixedString32Bytes)(ref result)).Capacity);
			return result;
		}

		public unsafe FixedString64Bytes ReadFixedString64()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			FixedString64Bytes result = default(FixedString64Bytes);
			byte* data = (byte*)(&result) + 2;
			result = (FixedString64Bytes)ReadFixedString(data, ((FixedString64Bytes)(ref result)).Capacity);
			return result;
		}

		public unsafe FixedString128Bytes ReadFixedString128()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			FixedString128Bytes result = default(FixedString128Bytes);
			byte* data = (byte*)(&result) + 2;
			result = (FixedString128Bytes)ReadFixedString(data, ((FixedString128Bytes)(ref result)).Capacity);
			return result;
		}

		public unsafe FixedString512Bytes ReadFixedString512()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			FixedString512Bytes result = default(FixedString512Bytes);
			byte* data = (byte*)(&result) + 2;
			result = (FixedString512Bytes)ReadFixedString(data, ((FixedString512Bytes)(ref result)).Capacity);
			return result;
		}

		public unsafe FixedString4096Bytes ReadFixedString4096()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			FixedString4096Bytes result = default(FixedString4096Bytes);
			byte* data = (byte*)(&result) + 2;
			result = (FixedString4096Bytes)ReadFixedString(data, ((FixedString4096Bytes)(ref result)).Capacity);
			return result;
		}

		public unsafe ushort ReadFixedString(byte* data, int maxLength)
		{
			ushort num = ReadUShort();
			if (num > maxLength)
			{
				return 0;
			}
			ReadBytes(data, num);
			return num;
		}

		public unsafe FixedString32Bytes ReadPackedFixedString32Delta(FixedString32Bytes baseline, NetworkCompressionModel model)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			FixedString32Bytes result = default(FixedString32Bytes);
			byte* data = (byte*)(&result) + 2;
			result = (FixedString32Bytes)ReadPackedFixedStringDelta(data, ((FixedString32Bytes)(ref result)).Capacity, (byte*)(&baseline) + 2, (ushort)baseline, model);
			return result;
		}

		public unsafe FixedString64Bytes ReadPackedFixedString64Delta(FixedString64Bytes baseline, NetworkCompressionModel model)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			FixedString64Bytes result = default(FixedString64Bytes);
			byte* data = (byte*)(&result) + 2;
			result = (FixedString64Bytes)ReadPackedFixedStringDelta(data, ((FixedString64Bytes)(ref result)).Capacity, (byte*)(&baseline) + 2, (ushort)baseline, model);
			return result;
		}

		public unsafe FixedString128Bytes ReadPackedFixedString128Delta(FixedString128Bytes baseline, NetworkCompressionModel model)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			FixedString128Bytes result = default(FixedString128Bytes);
			byte* data = (byte*)(&result) + 2;
			result = (FixedString128Bytes)ReadPackedFixedStringDelta(data, ((FixedString128Bytes)(ref result)).Capacity, (byte*)(&baseline) + 2, (ushort)baseline, model);
			return result;
		}

		public unsafe FixedString512Bytes ReadPackedFixedString512Delta(FixedString512Bytes baseline, NetworkCompressionModel model)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			FixedString512Bytes result = default(FixedString512Bytes);
			byte* data = (byte*)(&result) + 2;
			result = (FixedString512Bytes)ReadPackedFixedStringDelta(data, ((FixedString512Bytes)(ref result)).Capacity, (byte*)(&baseline) + 2, (ushort)baseline, model);
			return result;
		}

		public unsafe FixedString4096Bytes ReadPackedFixedString4096Delta(FixedString4096Bytes baseline, NetworkCompressionModel model)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			FixedString4096Bytes result = default(FixedString4096Bytes);
			byte* data = (byte*)(&result) + 2;
			result = (FixedString4096Bytes)ReadPackedFixedStringDelta(data, ((FixedString4096Bytes)(ref result)).Capacity, (byte*)(&baseline) + 2, (ushort)baseline, model);
			return result;
		}

		public unsafe ushort ReadPackedFixedStringDelta(byte* data, int maxLength, byte* baseData, ushort baseLength, NetworkCompressionModel model)
		{
			uint num = ReadPackedUIntDelta(baseLength, model);
			if (num > (uint)maxLength)
			{
				return 0;
			}
			if (num <= baseLength)
			{
				for (int i = 0; i < num; i++)
				{
					data[i] = (byte)ReadPackedUIntDelta(baseData[i], model);
				}
			}
			else
			{
				for (int j = 0; j < baseLength; j++)
				{
					data[j] = (byte)ReadPackedUIntDelta(baseData[j], model);
				}
				for (int k = baseLength; k < num; k++)
				{
					data[k] = (byte)ReadPackedUInt(model);
				}
			}
			return (ushort)num;
		}

		[Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
		private void CheckRead()
		{
		}

		[Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
		private static void CheckBits(int numbits)
		{
			if (numbits < 0 || numbits > 32)
			{
				throw new ArgumentOutOfRangeException("Invalid number of bits");
			}
		}
	}
	internal static class HMACSHA256
	{
		public unsafe static void ComputeHash(byte* keyValue, int keyArrayLength, byte* messageBytes, int messageLength, byte* result)
		{
			byte* ptr = stackalloc byte[32];
			SHA256.SHA256State sHA256State = SHA256.SHA256State.Create();
			if (keyArrayLength > 64)
			{
				sHA256State.Update(keyValue, keyArrayLength);
				sHA256State.Final(ptr);
				keyValue = ptr;
				keyArrayLength = 32;
			}
			byte* ptr2 = stackalloc byte[64];
			for (int i = 0; i < keyArrayLength; i++)
			{
				ptr2[i] = (byte)(0x36 ^ keyValue[i]);
			}
			for (int j = keyArrayLength; j < 64; j++)
			{
				ptr2[j] = 54;
			}
			sHA256State = SHA256.SHA256State.Create();
			sHA256State.Update(ptr2, 64);
			sHA256State.Update(messageBytes, messageLength);
			sHA256State.Final(result);
			for (int k = 0; k < keyArrayLength; k++)
			{
				ptr2[k] = (byte)(0x5C ^ keyValue[k]);
			}
			for (int l = keyArrayLength; l < 64; l++)
			{
				ptr2[l] = 92;
			}
			sHA256State = SHA256.SHA256State.Create();
			sHA256State.Update(ptr2, 64);
			sHA256State.Update(result, 32);
			sHA256State.Final(result);
		}
	}
	public struct NetworkPacketReceiver
	{
		[Flags]
		public enum AppendPacketMode
		{
			None = 0,
			NoCopyNeeded = 1
		}

		internal NetworkDriver m_Driver;

		public long LastUpdateTime => m_Driver.LastUpdateTime;

		public int ReceiveErrorCode
		{
			set
			{
				m_Driver.ReceiveErrorCode = value;
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public IntPtr AllocateMemory(ref int dataLen)
		{
			return m_Driver.AllocateMemory(ref dataLen);
		}

		public unsafe bool AppendPacket(IntPtr data, ref NetworkInterfaceEndPoint address, int dataLen, AppendPacketMode mode = AppendPacketMode.None)
		{
			if ((mode & AppendPacketMode.NoCopyNeeded) != AppendPacketMode.None)
			{
				m_Driver.AppendPacket(data, ref address, dataLen);
				return true;
			}
			int dataLen2 = dataLen;
			IntPtr intPtr = m_Driver.AllocateMemory(ref dataLen2);
			if (intPtr == IntPtr.Zero || dataLen2 < dataLen)
			{
				OutOfMemoryError();
				return false;
			}
			UnsafeUtility.MemCpy(intPtr.ToPointer(), data.ToPointer(), (long)dataLen);
			m_Driver.AppendPacket(intPtr, ref address, dataLen);
			return true;
		}

		public bool IsAddressUsed(NetworkInterfaceEndPoint address)
		{
			return m_Driver.IsAddressUsed(address);
		}

		private void OutOfMemoryError()
		{
			ReceiveErrorCode = 10040;
		}
	}
	[Flags]
	public enum SendHandleFlags
	{
		AllocatedByDriver = 1
	}
	public struct NetworkInterfaceSendHandle
	{
		public IntPtr data;

		public int capacity;

		public int size;

		public int id;

		public SendHandleFlags flags;
	}
	public struct NetworkSendQueueHandle
	{
		private IntPtr handle;

		internal unsafe static NetworkSendQueueHandle ToTempHandle(ParallelWriter<QueuedSendMessage> sendQueue)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			void* ptr = UnsafeUtility.Malloc((long)UnsafeUtility.SizeOf<ParallelWriter<QueuedSendMessage>>(), UnsafeUtility.AlignOf<ParallelWriter<QueuedSendMessage>>(), (Allocator)2);
			UnsafeUtility.WriteArrayElement<ParallelWriter<QueuedSendMessage>>(ptr, 0, sendQueue);
			return new NetworkSendQueueHandle
			{
				handle = (IntPtr)ptr
			};
		}

		public unsafe ParallelWriter<QueuedSendMessage> FromHandle()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			return UnsafeUtility.ReadArrayElement<ParallelWriter<QueuedSendMessage>>((void*)handle, 0);
		}
	}
	public struct NetworkSendInterface
	{
		[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
		public delegate int BeginSendMessageDelegate(out NetworkInterfaceSendHandle handle, IntPtr userData, int requiredPayloadSize);

		[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
		public delegate int EndSendMessageDelegate(ref NetworkInterfaceSendHandle handle, ref NetworkInterfaceEndPoint address, IntPtr userData, ref NetworkSendQueueHandle sendQueue);

		[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
		public delegate void AbortSendMessageDelegate(ref NetworkInterfaceSendHandle handle, IntPtr userData);

		public TransportFunctionPointer<BeginSendMessageDelegate> BeginSendMessage;

		public TransportFunctionPointer<EndSendMessageDelegate> EndSendMessage;

		public TransportFunctionPointer<AbortSendMessageDelegate> AbortSendMessage;

		[NativeDisableUnsafePtrRestriction]
		public IntPtr UserData;
	}
	public interface INetworkInterface : IDisposable
	{
		NetworkInterfaceEndPoint LocalEndPoint { get; }

		int Initialize(NetworkSettings settings);

		JobHandle ScheduleReceive(NetworkPacketReceiver receiver, JobHandle dep);

		JobHandle ScheduleSend(NativeQueue<QueuedSendMessage> sendQueue, JobHandle dep);

		int Bind(NetworkInterfaceEndPoint endpoint);

		int Listen();

		NetworkSendInterface CreateSendInterface();

		int CreateInterfaceEndPoint(NetworkEndPoint address, out NetworkInterfaceEndPoint endpoint);

		NetworkEndPoint GetGenericEndPoint(NetworkInterfaceEndPoint endpoint);
	}
	internal struct IPCManager
	{
		[StructLayout(LayoutKind.Explicit)]
		internal struct IPCData
		{
			[FieldOffset(0)]
			public int from;

			[FieldOffset(4)]
			public int length;

			[FieldOffset(8)]
			public unsafe fixed byte data[1400];
		}

		public static IPCManager Instance;

		private NativeMultiQueue<IPCData> m_IPCQueue;

		private NativeHashMap<ushort, int> m_IPCChannels;

		internal static JobHandle ManagerAccessHandle;

		private int m_RefCount;

		public bool IsCreated => m_IPCQueue.IsCreated;

		public void AddRef()
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			if (m_RefCount == 0)
			{
				m_IPCQueue = new NativeMultiQueue<IPCData>(128);
				m_IPCChannels = new NativeHashMap<ushort, int>(64, AllocatorHandle.op_Implicit((Allocator)4));
			}
			m_RefCount++;
		}

		public void Release()
		{
			m_RefCount--;
			if (m_RefCount == 0)
			{
				((JobHandle)(ref ManagerAccessHandle)).Complete();
				m_IPCQueue.Dispose();
				m_IPCChannels.Dispose();
			}
		}

		internal unsafe void Update(NetworkInterfaceEndPoint local, NativeQueue<QueuedSendMessage> queue)
		{
			QueuedSendMessage queuedSendMessage = default(QueuedSendMessage);
			while (queue.TryDequeue(ref queuedSendMessage))
			{
				IPCData value = default(IPCData);
				UnsafeUtility.MemCpy((void*)value.data, (void*)queuedSendMessage.Data, (long)queuedSendMessage.DataLength);
				value.length = queuedSendMessage.DataLength;
				value.from = *(int*)local.data;
				m_IPCQueue.Enqueue(*(int*)queuedSendMessage.Dest.data, value);
			}
		}

		public unsafe NetworkInterfaceEndPoint CreateEndPoint(ushort port)
		{
			((JobHandle)(ref ManagerAccessHandle)).Complete();
			int num = 0;
			if (port == 0)
			{
				int num2 = default(int);
				while (num == 0)
				{
					port = RandomHelpers.GetRandomUShort();
					if (!m_IPCChannels.TryGetValue(port, ref num2))
					{
						num = m_IPCChannels.Count + 1;
						m_IPCChannels.TryAdd(port, num);
					}
				}
			}
			else if (!m_IPCChannels.TryGetValue(port, ref num))
			{
				num = m_IPCChannels.Count + 1;
				m_IPCChannels.TryAdd(port, num);
			}
			NetworkInterfaceEndPoint result = new NetworkInterfaceEndPoint
			{
				dataLength = 4
			};
			*(int*)result.data = num;
			return result;
		}

		public unsafe bool GetEndPointPort(NetworkInterfaceEndPoint ep, out ushort port)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			((JobHandle)(ref ManagerAccessHandle)).Complete();
			int num = *(int*)ep.data;
			NativeArray<int> valueArray = m_IPCChannels.GetValueArray(AllocatorHandle.op_Implicit((Allocator)2));
			NativeArray<ushort> keyArray = m_IPCChannels.GetKeyArray(AllocatorHandle.op_Implicit((Allocator)2));
			port = 0;
			for (int i = 0; i < m_IPCChannels.Count; i++)
			{
				if (valueArray[i] == num)
				{
					port = keyArray[i];
					return true;
				}
			}
			return false;
		}

		public unsafe int PeekNext(NetworkInterfaceEndPoint local, void* slice, out int length, out NetworkInterfaceEndPoint from)
		{
			((JobHandle)(ref ManagerAccessHandle)).Complete();
			from = default(NetworkInterfaceEndPoint);
			length = 0;
			if (m_IPCQueue.Peek(*(int*)local.data, out var value))
			{
				UnsafeUtility.MemCpy(slice, (void*)value.data, (long)value.length);
				length = value.length;
			}
			GetEndPointByHandle(value.from, out from);
			return length;
		}

		public unsafe int ReceiveMessageEx(NetworkInterfaceEndPoint local, void* payloadData, int payloadLen, ref NetworkInterfaceEndPoint remote)
		{
			if (!m_IPCQueue.Peek(*(int*)local.data, out var value))
			{
				return 0;
			}
			GetEndPointByHandle(value.from, out remote);
			int num = Math.Min(payloadLen, value.length);
			UnsafeUtility.MemCpy(payloadData, (void*)value.data, (long)num);
			if (num < value.length)
			{
				return -10040;
			}
			m_IPCQueue.Dequeue(*(int*)local.data, out value);
			return num;
		}

		private unsafe void GetEndPointByHandle(int handle, out NetworkInterfaceEndPoint endpoint)
		{
			NetworkInterfaceEndPoint networkInterfaceEndPoint = new NetworkInterfaceEndPoint
			{
				dataLength = 4
			};
			*(int*)networkInterfaceEndPoint.data = handle;
			endpoint = networkInterfaceEndPoint;
		}
	}
	[BurstCompile]
	public struct IPCNetworkInterface : INetworkInterface, IDisposable
	{
		[BurstCompile]
		private struct SendUpdate : IJob
		{
			public IPCManager ipcManager;

			public NativeQueue<QueuedSendMessage> ipcQueue;

			[ReadOnly]
			public NativeArray<NetworkInterfaceEndPoint> localEndPoint;

			public void Execute()
			{
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				ipcManager.Update(localEndPoint[0], ipcQueue);
			}
		}

		[BurstCompile]
		private struct ReceiveJob : IJob
		{
			public NetworkPacketReceiver receiver;

			public IPCManager ipcManager;

			public NetworkInterfaceEndPoint localEndPoint;

			public unsafe void Execute()
			{
				receiver.ReceiveErrorCode = 0;
				IntPtr intPtr;
				NetworkInterfaceEndPoint address;
				int num;
				do
				{
					int dataLen = 1400;
					intPtr = receiver.AllocateMemory(ref dataLen);
					if (intPtr == IntPtr.Zero)
					{
						break;
					}
					address = default(NetworkInterfaceEndPoint);
					num = NativeReceive(intPtr.ToPointer(), dataLen, ref address);
					if (num <= 0)
					{
						if (num != 0)
						{
							receiver.ReceiveErrorCode = -num;
						}
						break;
					}
				}
				while (receiver.AppendPacket(intPtr, ref address, num, NetworkPacketReceiver.AppendPacketMode.NoCopyNeeded));
			}

			private unsafe int NativeReceive(void* data, int length, ref NetworkInterfaceEndPoint address)
			{
				return ipcManager.ReceiveMessageEx(localEndPoint, data, length, ref address);
			}
		}

		[ReadOnly]
		private NativeArray<NetworkInterfaceEndPoint> m_LocalEndPoint;

		private static TransportFunctionPointer<NetworkSendInterface.BeginSendMessageDelegate> BeginSendMessageFunctionPointer = new TransportFunctionPointer<NetworkSendInterface.BeginSendMessageDelegate>((NetworkSendInterface.BeginSendMessageDelegate)BeginSendMessage);

		private static TransportFunctionPointer<NetworkSendInterface.EndSendMessageDelegate> EndSendMessageFunctionPointer = new TransportFunctionPointer<NetworkSendInterface.EndSendMessageDelegate>((NetworkSendInterface.EndSendMessageDelegate)EndSendMessage);

		private static TransportFunctionPointer<NetworkSendInterface.AbortSendMessageDelegate> AbortSendMessageFunctionPointer = new TransportFunctionPointer<NetworkSendInterface.AbortSendMessageDelegate>((NetworkSendInterface.AbortSendMessageDelegate)AbortSendMessage);

		public NetworkInterfaceEndPoint LocalEndPoint => m_LocalEndPoint[0];

		public int CreateInterfaceEndPoint(NetworkEndPoint address, out NetworkInterfaceEndPoint endpoint)
		{
			if (!address.IsLoopback && !address.IsAny)
			{
				endpoint = default(NetworkInterfaceEndPoint);
				return -9;
			}
			endpoint = IPCManager.Instance.CreateEndPoint(address.Port);
			return 0;
		}

		public NetworkEndPoint GetGenericEndPoint(NetworkInterfaceEndPoint endpoint)
		{
			if (!IPCManager.Instance.GetEndPointPort(endpoint, out var port))
			{
				return default(NetworkEndPoint);
			}
			return NetworkEndPoint.LoopbackIpv4.WithPort(port);
		}

		public int Initialize(NetworkSettings settings)
		{
			//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)
			IPCManager.Instance.AddRef();
			m_LocalEndPoint = new NativeArray<NetworkInterfaceEndPoint>(1, (Allocator)4, (NativeArrayOptions)1);
			NetworkInterfaceEndPoint endpoint = default(NetworkInterfaceEndPoint);
			int num = 0;
			if ((num = CreateInterfaceEndPoint(NetworkEndPoint.LoopbackIpv4, out endpoint)) != 0)
			{
				return num;
			}
			m_LocalEndPoint[0] = endpoint;
			return 0;
		}

		public void Dispose()
		{
			m_LocalEndPoint.Dispose();
			IPCManager.Instance.Release();
		}

		public JobHandle ScheduleReceive(NetworkPacketReceiver receiver, JobHandle dep)
		{
			//IL_002a: 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_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: 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_0042: Unknown result type (might be due to invalid IL or missing references)
			dep = IJobExtensions.Schedule<ReceiveJob>(new ReceiveJob
			{
				receiver = receiver,
				ipcManager = IPCManager.Instance,
				localEndPoint = LocalEndPoint
			}, JobHandle.CombineDependencies(dep, IPCManager.ManagerAccessHandle));
			IPCManager.ManagerAccessHandle = dep;
			return dep;
		}

		public JobHandle ScheduleSend(NativeQueue<QueuedSendMessage> sendQueue, JobHandle dep)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: 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_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: 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_0042: Unknown result type (might be due to invalid IL or missing references)
			dep = IJobExtensions.Schedule<SendUpdate>(new SendUpdate
			{
				ipcManager = IPCManager.Instance,
				ipcQueue = sendQueue,
				localEndPoint = m_LocalEndPoint
			}, JobHandle.CombineDependencies(dep, IPCManager.ManagerAccessHandle));
			IPCManager.ManagerAccessHandle = dep;
			return dep;
		}

		public int Bind(NetworkInterfaceEndPoint endpoint)
		{
			m_LocalEndPoint[0] = endpoint;
			return 0;
		}

		public int Listen()
		{
			return 0;
		}

		public NetworkSendInterface CreateSendInterface()
		{
			return new NetworkSendInterface
			{
				BeginSendMessage = BeginSendMessageFunctionPointer,
				EndSendMessage = EndSendMessageFunctionPointer,
				AbortSendMessage = AbortSendMessageFunctionPointer
			};
		}

		[BurstCompile(DisableDirectCall = true)]
		[MonoPInvokeCallback(typeof(NetworkSendInterface.BeginSendMessageDelegate))]
		private unsafe static int BeginSendMessage(out NetworkInterfaceSendHandle handle, IntPtr userData, int requiredPayloadSize)
		{
			handle.id = 0;
			handle.size = 0;
			handle.capacity = requiredPayloadSize;
			handle.data = (IntPtr)UnsafeUtility.Malloc((long)handle.capacity, 8, (Allocator)2);
			handle.flags = (SendHandleFlags)0;
			return 0;
		}

		[BurstCompile(DisableDirectCall = true)]
		[MonoPInvokeCallback(typeof(NetworkSendInterface.EndSendMessageDelegate))]
		private unsafe static int EndSendMessage(ref NetworkInterfaceSendHandle handle, ref NetworkInterfaceEndPoint address, IntPtr userData, ref NetworkSendQueueHandle sendQueueHandle)
		{
			//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)
			ParallelWriter<QueuedSendMessage> val = sendQueueHandle.FromHandle();
			QueuedSendMessage queuedSendMessage = new QueuedSendMessage
			{
				Dest = address,
				DataLength = handle.size
			};
			UnsafeUtility.MemCpy((void*)queuedSendMessage.Data, (void*)handle.data, (long)handle.size);
			val.Enqueue(queuedSendMessage);
			return handle.size;
		}

		[BurstCompile(DisableDirectCall = true)]
		[MonoPInvokeCallback(typeof(NetworkSendInterface.AbortSendMessageDelegate))]
		private static void AbortSendMessage(ref NetworkInterfaceSendHandle handle, IntPtr userData)
		{
		}
	}
	public struct NetworkCompressionModel : IDisposable
	{
		internal static readonly byte[] k_BucketSizes = new byte[16]
		{
			0, 0, 1, 2, 3, 4, 6, 8, 10, 12,
			15, 18, 21, 24, 27, 32
		};

		internal static readonly uint[] k_BucketOffsets = new uint[16]
		{
			0u, 1u, 2u, 4u, 8u, 16u, 32u, 96u, 352u, 1376u,
			5472u, 38240u, 300384u, 2397536u, 19174752u, 153392480u
		};

		internal static readonly int[] k_FirstBucketCandidate = new int[33]
		{
			15, 15, 15, 15, 14, 14, 14, 13, 13, 13,
			12, 12, 12, 11, 11, 11, 10, 10, 10, 9,
			9, 8, 8, 7, 7, 6, 5, 4, 3, 2,
			1, 1, 0
		};

		internal static readonly byte[] k_DefaultModelData = new byte[19]
		{
			16, 2, 3, 3, 3, 4, 4, 4, 5, 5,
			5, 6, 6, 6, 6, 6, 6, 0, 0
		};

		internal const int k_AlphabetSize = 16;

		internal const int k_MaxHuffmanSymbolLength = 6;

		internal const int k_MaxContexts = 1;

		internal unsafe fixed ushort encodeTable[16];

		internal unsafe fixed ushort decodeTable[64];

		internal unsafe fixed byte bucketSizes[16];

		internal unsafe fixed uint bucketOffsets[16];

		public void Dispose()
		{
		}

		public unsafe NetworkCompressionModel(Allocator allocator)
		{
			for (int i = 0; i < 16; i++)
			{
				bucketSizes[i] = k_BucketSizes[i];
				bucketOffsets[i] = k_BucketOffsets[i];
			}
			byte[] array = k_DefaultModelData;
			int num = 1;
			byte[,] array2 = new byte[num, 16];
			int num2 = 0;
			_ = array[num2++];
			for (int j = 0; j < 16; j++)
			{
				byte b = array[num2++];
				for (int k = 0; k < num; k++)
				{
					array2[k, j] = b;
				}
			}
			int num3 = array[num2] | (array[num2 + 1] << 8);
			num2 += 2;
			for (int l = 0; l < num3; l++)
			{
				int num4 = array[num2] | (array[num2 + 1] << 8);
				num2 += 2;
				_ = array[num2++];
				for (int m = 0; m < 16; m++)
				{
					byte b2 = array[num2++];
					array2[num4, m] = b2;
				}
			}
			byte[] array3 = new byte[16];
			ushort[] array4 = new ushort[64];
			byte[] array5 = new byte[16];
			for (int n = 0; n < num; n++)
			{
				for (int num5 = 0; num5 < 16; num5++)
				{
					array3[num5] = array2[n, num5];
				}
				GenerateHuffmanCodes(array5, 0, array3, 0, 16, 6);
				GenerateHuffmanDecodeTable(array4, 0, array3, array5, 16, 6);
				for (int num6 = 0; num6 < 16; num6++)
				{
					encodeTable[n * 16 + num6] = (ushort)((array5[num6] << 8) | array2[n, num6]);
				}
				for (int num7 = 0; num7 < 64; num7++)
				{
					decodeTable[n * 64 + num7] = array4[num7];
				}
			}
		}

		private static void GenerateHuffmanCodes(byte[] symboLCodes, int symbolCodesOffset, byte[] symbolLengths, int symbolLengthsOffset, int alphabetSize, int maxCodeLength)
		{
			byte[] array = new byte[maxCodeLength + 1];
			byte[,] array2 = new byte[maxCodeLength + 1, alphabetSize];
			for (int i = 0; i < alphabetSize; i++)
			{
				int num = symbolLengths[i + symbolLengthsOffset];
				array2[num, array[num]++] = (byte)i;
			}
			uint num2 = 0u;
			for (int j = 1; j <= maxCodeLength; j++)
			{
				int num3 = array[j];
				for (int k = 0; k < num3; k++)
				{
					int num4 = array2[j, k];
					symboLCodes[num4 + symbolCodesOffset] = (byte)ReverseBits(num2++, j);
				}
				num2 <<= 1;
			}
		}

		private static uint ReverseBits(uint value, int num_bits)
		{
			value = ((value & 0x55555555) << 1) | ((value & 0xAAAAAAAAu) >> 1);
			value = ((value & 0x33333333) << 2) | ((value & 0xCCCCCCCCu) >> 2);
			value = ((value & 0xF0F0F0F) << 4) | ((value & 0xF0F0F0F0u) >> 4);
			value = ((value & 0xFF00FF) << 8) | ((value & 0xFF00FF00u) >> 8);
			value = (value << 16) | (value >> 16);
			return value >> 32 - num_bits;
		}

		private static void GenerateHuffmanDecodeTable(ushort[] decodeTable, int decodeTableOffset, byte[] symbolLengths, byte[] symbolCodes, int alphabetSize, int maxCodeLength)
		{
			uint num = (uint)(1 << maxCodeLength);
			for (int i = 0; i < alphabetSize; i++)
			{
				int num2 = symbolLengths[i];
				if (num2 > 0)
				{
					uint num3 = symbolCodes[i];
					uint num4 = (uint)(1 << num2);
					do
					{
						decodeTable[decodeTableOffset + num3] = (ushort)((i << 8) | num2);
						num3 += num4;
					}
					while (num3 < num);
				}
			}
		}

		public unsafe int CalculateBucket(uint value)
		{
			int num = k_FirstBucketCandidate[math.lzcnt(value)];
			if (num + 1 < 16 && value >= bucketOffsets[num + 1])
			{
				num++;
			}
			return num;
		}
	}
	public struct NetworkConnection : IEquatable<NetworkConnection>
	{
		public enum State
		{
			Disconnected,
			Connecting,
			Connected
		}

		internal int m_NetworkId;

		internal int m_NetworkVersion;

		public bool IsCreated => m_NetworkVersion != 0;

		public int InternalId => m_NetworkId;

		public int Disconnect(NetworkDriver driver)
		{
			return driver.Disconnect(this);
		}

		public NetworkEvent.Type PopEvent(NetworkDriver driver, out DataStreamReader stream)
		{
			return driver.PopEventForConnection(this, out stream);
		}

		public NetworkEvent.Type PopEvent(NetworkDriver driver, out DataStreamReader stream, out NetworkPipeline pipeline)
		{
			return driver.PopEventForConnection(this, out stream, out pipeline);
		}

		public int Close(NetworkDriver driver)
		{
			if (m_NetworkId >= 0)
			{
				return driver.Disconnect(this);
			}
			return -1;
		}

		public State GetState(NetworkDriver driver)
		{
			return driver.GetConnectionState(this);
		}

		public static bool operator ==(NetworkConnection lhs, NetworkConnection rhs)
		{
			if (lhs.m_NetworkId == rhs.m_NetworkId)
			{
				return lhs.m_NetworkVersion == rhs.m_NetworkVersion;
			}
			return false;
		}

		public static bool operator !=(NetworkConnection lhs, NetworkConnection rhs)
		{
			if (lhs.m_NetworkId == rhs.m_NetworkId)
			{
				return lhs.m_NetworkVersion != rhs.m_NetworkVersion;
			}
			return true;
		}

		public override bool Equals(object o)
		{
			return this == (NetworkConnection)o;
		}

		public bool Equals(NetworkConnection o)
		{
			return this == o;
		}

		public override int GetHashCode()
		{
			return (m_NetworkId << 8) ^ m_NetworkVersion;
		}
	}
	public struct QueuedSendMessage
	{
		public unsafe fixed byte Data[1400];

		public NetworkInterfaceEndPoint Dest;

		public int DataLength;
	}
	public struct NetworkDriver : IDisposable
	{
		public struct Concurrent
		{
			private struct PendingSend
			{
				public NetworkPipeline Pipeline;

				public NetworkConnection Connection;

				public NetworkInterfaceSendHandle SendHandle;

				public int headerSize;
			}

			internal NetworkSendInterface m_NetworkSendInterface;

			internal NetworkProtocol m_NetworkProtocolInterface;

			internal NetworkEventQueue.Concurrent m_EventQueue;

			internal NativeArray<byte> m_DisconnectReasons;

			[ReadOnly]
			internal NativeList<Connection> m_ConnectionList;

			[ReadOnly]
			internal NativeList<byte> m_DataStream;

			internal NetworkPipelineProcessor.Concurrent m_PipelineProcessor;

			internal UdpCHeader.HeaderFlags m_DefaultHeaderFlags;

			internal ParallelWriter<QueuedSendMessage> m_ConcurrentParallelSendQueue;

			public NetworkEvent.Type PopEventForConnection(NetworkConnection connectionId, out DataStreamReader reader)
			{
				NetworkPipeline pipeline;
				return PopEventForConnection(connectionId, out reader, out pipeline);
			}

			public NetworkEvent.Type PopEventForConnection(NetworkConnection connectionId, out DataStreamReader reader, out NetworkPipeline pipeline)
			{
				//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a9: 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_00b4: Unknown result type (might be due to invalid IL or missing references)
				//IL_008e: Unknown result type (might be due to invalid IL or missing references)
				pipeline = default(NetworkPipeline);
				reader = default(DataStreamReader);
				if (connectionId.m_NetworkId < 0 || connectionId.m_NetworkId >= m_ConnectionList.Length || m_ConnectionList[connectionId.m_NetworkId].Version != connectionId.m_NetworkVersion)
				{
					return NetworkEvent.Type.Empty;
				}
				int offset;
				int size;
				int pipelineId;
				NetworkEvent.Type num = m_EventQueue.PopEventForConnection(connectionId.m_NetworkId, out offset, out size, out pipelineId);
				pipeline = new NetworkPipeline
				{
					Id = pipelineId
				};
				if (num == NetworkEvent.Type.Disconnect && offset < 0)
				{
					reader = new DataStreamReader(m_DisconnectReasons.GetSubArray(math.abs(offset), 1));
					return num;
				}
				if (size > 0)
				{
					reader = new DataStreamReader(NativeList<byte>.op_Implicit(m_DataStream).GetSubArray(offset, size));
				}
				return num;
			}

			public int MaxHeaderSize(NetworkPipeline pipe)
			{
				int num = m_NetworkProtocolInterface.PaddingSize;
				if (pipe.Id > 0)
				{
					num += m_PipelineProcessor.SendHeaderCapacity(pipe) + 1;
				}
				return num;
			}

			internal int MaxProtocolHeaderSize()
			{
				return m_NetworkProtocolInterface.PaddingSize;
			}

			public int BeginSend(NetworkConnection id, out DataStreamWriter writer, int requiredPayloadSize = 0)
			{
				return BeginSend(NetworkPipeline.Null, id, out writer, requiredPayloadSize);
			}

			public unsafe int BeginSend(NetworkPipeline pipe, NetworkConnection id, out DataStreamWriter writer, int requiredPayloadSize = 0)
			{
				//IL_0184: Unknown result type (might be due to invalid IL or missing references)
				//IL_0189: Unknown result type (might be due to invalid IL or missing references)
				//IL_018c: Unknown result type (might be due to invalid IL or missing references)
				writer = default(DataStreamWriter);
				if (id.m_NetworkId < 0 || id.m_NetworkId >= m_ConnectionList.Length)
				{
					return -1;
				}
				Connection connection = m_ConnectionList[id.m_NetworkId];
				if (connection.Version != id.m_NetworkVersion)
				{
					return -2;
				}
				if (connection.State != NetworkConnection.State.Connected)
				{
					return -3;
				}
				int num = ((pipe.Id > 0) ? (m_PipelineProcessor.SendHeaderCapacity(pipe) + 1) : 0);
				int num2 = m_PipelineProcessor.PayloadCapacity(pipe);
				int payloadOffset;
				int num3 = m_NetworkProtocolInterface.ComputePacketOverhead.Ptr.Invoke(ref connection, out payloadOffset);
				int num4 = ((num2 == 0) ? (1400 - num3 - num) : num2);
				int num5 = ((num2 == 0) ? 1400 : (num2 + num3 + num));
				if (num4 < requiredPayloadSize)
				{
					return -4;
				}
				if (requiredPayloadSize > 0 && num4 > requiredPayloadSize)
				{
					int num6 = num4 - requiredPayloadSize;
					num4 -= num6;
					num5 -= num6;
				}
				NetworkInterfaceSendHandle handle = default(NetworkInterfaceSendHandle);
				if (num5 > 1400)
				{
					handle.data = (IntPtr)UnsafeUtility.Malloc((long)num5, 8, (Allocator)2);
					handle.capacity = num5;
					handle.id = 0;
					handle.size = 0;
					handle.flags = SendHandleFlags.AllocatedByDriver;
				}
				else
				{
					int num7 = m_NetworkSendInterface.BeginSendMessage.Ptr.Invoke(out handle, m_NetworkSendInterface.UserData, num5);
					if (num7 != 0)
					{
						return num7;
					}
				}
				if (handle.capacity < num5)
				{
					return -4;
				}
				NativeArray<byte> data = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray<byte>((void*)((byte*)(void*)handle.data + payloadOffset + num), num4, (Allocator)0);
				writer = new DataStreamWriter(data);
				writer.m_SendHandleData = (IntPtr)UnsafeUtility.Malloc((long)UnsafeUtility.SizeOf<PendingSend>(), UnsafeUtility.AlignOf<PendingSend>(), (Allocator)2);
				*(PendingSend*)(void*)writer.m_SendHandleData = new PendingSend
				{
					Pipeline = pipe,
					Connection = id,
					SendHandle = handle,
					headerSize = payloadOffset
				};
				return 0;
			}

			public unsafe int EndSend(DataStreamWriter writer)
			{
				PendingSend* ptr = (PendingSend*)(void*)writer.m_SendHandleData;
				if (ptr == null || ptr->Connection == default(NetworkConnection))
				{
					return -8;
				}
				if (m_ConnectionList[ptr->Connection.m_NetworkId].Version != ptr->Connection.m_NetworkVersion)
				{
					return -2;
				}
				if (writer.HasFailedWrites)
				{
					AbortSend(writer);
					return -4;
				}
				PendingSend pendingSend = *(PendingSend*)(void*)writer.m_SendHandleData;
				ptr->Connection = default(NetworkConnection);
				pendingSend.SendHandle.size = pendingSend.headerSize + writer.Length;
				int num = 0;
				if (pendingSend.Pipeline.Id > 0)
				{
					pendingSend.SendHandle.size += m_PipelineProcessor.SendHeaderCapacity(pendingSend.Pipeline) + 1;
					UdpCHeader.HeaderFlags defaultHeaderFlags = m_DefaultHeaderFlags;
					m_DefaultHeaderFlags = UdpCHeader.HeaderFlags.HasPipeline;
					num = m_PipelineProcessor.Send(this, pendingSend.Pipeline, pendingSend.Connection, pendingSend.SendHandle, pendingSend.headerSize);
					m_DefaultHeaderFlags = defaultHeaderFlags;
				}
				else
				{
					num = CompleteSend(pendingSend.Connection, pendingSend.SendHandle, (m_DefaultHeaderFlags & UdpCHeader.HeaderFlags.HasPipeline) != 0);
				}
				if (num <= 0)
				{
					return num;
				}
				return writer.Length;
			}

			public unsafe void AbortSend(DataStreamWriter writer)
			{
				PendingSend* ptr = (PendingSend*)(void*)writer.m_SendHandleData;
				if (ptr == null || ptr->Connection == default(NetworkConnection))
				{
					Debug.LogError((object)"AbortSend without matching BeginSend");
					return;
				}
				PendingSend pendingSend = *(PendingSend*)(void*)writer.m_SendHandleData;
				ptr->Connection = default(NetworkConnection);
				AbortSend(pendingSend.SendHandle);
			}

			internal unsafe int CompleteSend(NetworkConnection sendConnect

BepInEx/plugins/Unity.Services.Authentication.dll

Decompiled 13 hours ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
using Unity.Services.Authentication.Generated;
using Unity.Services.Authentication.Internal;
using Unity.Services.Authentication.Shared;
using Unity.Services.Core;
using Unity.Services.Core.Configuration.Internal;
using Unity.Services.Core.Environments.Internal;
using Unity.Services.Core.Internal;
using Unity.Services.Core.Scheduler.Internal;
using Unity.Services.Core.Telemetry.Internal;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.Scripting;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AlwaysLinkAssembly]
[assembly: InternalsVisibleTo("Unity.Services.Authentication.Editor")]
[assembly: InternalsVisibleTo("Unity.Services.Authentication.Internal1")]
[assembly: InternalsVisibleTo("Unity.Services.Authentication.Internal2")]
[assembly: InternalsVisibleTo("Unity.Services.Authentication.Internal3")]
[assembly: InternalsVisibleTo("Unity.Services.Authentication.Internal4")]
[assembly: InternalsVisibleTo("Unity.Services.Authentication.Unity")]
[assembly: InternalsVisibleTo("Unity.Services.Authentication.Tests")]
[assembly: InternalsVisibleTo("Unity.Services.Authentication.EditorTests")]
[assembly: InternalsVisibleTo("Unity.Services.Authentication.TestUtils")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Unity.Services.Authentication")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("Unity.Services.Authentication")]
[assembly: AssemblyTitle("Unity.Services.Authentication")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace Unity.Services.Authentication
{
	public static class AuthenticationService
	{
		private static IAuthenticationService s_Instance;

		public static IAuthenticationService Instance
		{
			get
			{
				//IL_000c: Unknown result type (might be due to invalid IL or missing references)
				if (s_Instance == null)
				{
					throw new ServicesInitializationException("Singleton is not initialized. Please call UnityServices.InitializeAsync() to initialize.");
				}
				return s_Instance;
			}
			internal set
			{
				s_Instance = value;
			}
		}
	}
	internal class AuthenticationServiceInternal : IAuthenticationService
	{
		private const string k_ProfileRegex = "^[a-zA-Z0-9_-]{1,30}$";

		private const string k_IdProviderNameRegex = "^oidc-[a-z0-9-_\\.]{1,15}$";

		private const string k_SteamIdentityRegex = "^[a-zA-Z0-9]{5,30}$";

		private readonly IProfile m_Profile;

		private readonly IJwtDecoder m_JwtDecoder;

		private readonly IAuthenticationCache m_Cache;

		private readonly IActionScheduler m_Scheduler;

		private readonly IAuthenticationMetrics m_Metrics;

		public bool IsSignedIn
		{
			get
			{
				if (State != AuthenticationState.Authorized && State != AuthenticationState.Refreshing)
				{
					return State == AuthenticationState.Expired;
				}
				return true;
			}
		}

		public bool IsAuthorized
		{
			get
			{
				if (State != AuthenticationState.Authorized)
				{
					return State == AuthenticationState.Refreshing;
				}
				return true;
			}
		}

		public bool IsExpired => State == AuthenticationState.Expired;

		public bool SessionTokenExists => !string.IsNullOrEmpty(SessionTokenComponent.SessionToken);

		public string Profile => m_Profile.Current;

		public string AccessToken => AccessTokenComponent.AccessToken;

		public string PlayerId => PlayerIdComponent.PlayerId;

		public string PlayerName => PlayerNameComponent.PlayerName;

		public PlayerInfo PlayerInfo { get; internal set; }

		internal long? ExpirationActionId { get; set; }

		internal long? RefreshActionId { get; set; }

		internal AccessTokenComponent AccessTokenComponent { get; }

		internal EnvironmentIdComponent EnvironmentIdComponent { get; }

		internal PlayerIdComponent PlayerIdComponent { get; }

		internal PlayerNameComponent PlayerNameComponent { get; }

		internal SessionTokenComponent SessionTokenComponent { get; }

		internal AuthenticationState State { get; set; }

		internal IAuthenticationSettings Settings { get; }

		internal IAuthenticationNetworkClient NetworkClient { get; set; }

		internal IPlayerNamesApi PlayerNamesApi { get; set; }

		internal IAuthenticationExceptionHandler ExceptionHandler { get; set; }

		public event Action<RequestFailedException> SignInFailed;

		public event Action SignedIn;

		public event Action SignedOut;

		public event Action Expired;

		public event Action<RequestFailedException> UpdatePasswordFailed;

		internal event Action<AuthenticationState, AuthenticationState> StateChanged;

		internal AuthenticationServiceInternal(IAuthenticationSettings settings, IAuthenticationNetworkClient networkClient, IPlayerNamesApi playerNamesApi, IProfile profile, IJwtDecoder jwtDecoder, IAuthenticationCache cache, IActionScheduler scheduler, IAuthenticationMetrics metrics, AccessTokenComponent accessToken, EnvironmentIdComponent environmentId, PlayerIdComponent playerId, PlayerNameComponent playerName, SessionTokenComponent sessionToken)
		{
			Settings = settings;
			NetworkClient = networkClient;
			PlayerNamesApi = playerNamesApi;
			m_Profile = profile;
			m_JwtDecoder = jwtDecoder;
			m_Cache = cache;
			m_Scheduler = scheduler;
			m_Metrics = metrics;
			ExceptionHandler = new AuthenticationExceptionHandler(m_Metrics);
			AccessTokenComponent = accessToken;
			EnvironmentIdComponent = environmentId;
			PlayerIdComponent = playerId;
			PlayerNameComponent = playerName;
			SessionTokenComponent = sessionToken;
			State = AuthenticationState.SignedOut;
			MigrateCache();
			PlayerIdComponent.PlayerIdChanged += OnPlayerIdChanged;
			Expired += delegate
			{
				m_Metrics.SendExpiredSessionMetric();
			};
		}

		private void OnPlayerIdChanged(string playerId)
		{
			PlayerNameComponent.Clear();
		}

		public Task SignInAnonymouslyAsync(SignInOptions options = null)
		{
			if (State == AuthenticationState.SignedOut || State == AuthenticationState.Expired)
			{
				if (SessionTokenExists)
				{
					string sessionToken = SessionTokenComponent.SessionToken;
					if (string.IsNullOrEmpty(sessionToken))
					{
						SessionTokenComponent.Clear();
						RequestFailedException exception = ExceptionHandler.BuildClientSessionTokenNotExistsException();
						SendSignInFailedEvent(exception, forceSignOut: true);
						return Task.FromException((Exception)(object)exception);
					}
					return HandleSignInRequestAsync(() => NetworkClient.SignInWithSessionTokenAsync(sessionToken));
				}
				if (options == null || options.CreateAccount)
				{
					return HandleSignInRequestAsync(NetworkClient.SignInAnonymouslyAsync);
				}
				SessionTokenComponent.Clear();
				RequestFailedException exception2 = ExceptionHandler.BuildClientSessionTokenNotExistsException();
				SendSignInFailedEvent(exception2, forceSignOut: true);
				return Task.FromException((Exception)(object)exception2);
			}
			RequestFailedException exception3 = ExceptionHandler.BuildClientInvalidStateException(State);
			SendSignInFailedEvent(exception3, forceSignOut: false);
			return Task.FromException((Exception)(object)exception3);
		}

		public Task SignInWithAppleAsync(string idToken, SignInOptions options = null)
		{
			return SignInWithExternalTokenAsync("apple.com", new SignInWithExternalTokenRequest
			{
				IdProvider = "apple.com",
				Token = idToken,
				SignInOnly = (options != null && !options.CreateAccount)
			});
		}

		public Task LinkWithAppleAsync(string idToken, LinkOptions options = null)
		{
			return LinkWithExternalTokenAsync("apple.com", new LinkWithExternalTokenRequest
			{
				IdProvider = "apple.com",
				Token = idToken,
				ForceLink = (options?.ForceLink ?? false)
			});
		}

		public Task UnlinkAppleAsync()
		{
			return UnlinkExternalTokenAsync("apple.com");
		}

		public Task SignInWithAppleGameCenterAsync(string signature, string teamPlayerId, string publicKeyURL, string salt, ulong timestamp, SignInOptions options = null)
		{
			return SignInWithExternalTokenAsync("apple-game-center", new SignInWithAppleGameCenterRequest
			{
				IdProvider = "apple-game-center",
				Token = signature,
				AppleGameCenterConfig = new AppleGameCenterConfig
				{
					TeamPlayerId = teamPlayerId,
					PublicKeyURL = publicKeyURL,
					Salt = salt,
					Timestamp = timestamp
				},
				SignInOnly = (options != null && !options.CreateAccount)
			});
		}

		public Task LinkWithAppleGameCenterAsync(string signature, string teamPlayerId, string publicKeyURL, string salt, ulong timestamp, LinkOptions options = null)
		{
			return LinkWithExternalTokenAsync("apple-game-center", new LinkWithAppleGameCenterRequest
			{
				IdProvider = "apple-game-center",
				Token = signature,
				AppleGameCenterConfig = new AppleGameCenterConfig
				{
					TeamPlayerId = teamPlayerId,
					PublicKeyURL = publicKeyURL,
					Salt = salt,
					Timestamp = timestamp
				},
				ForceLink = (options?.ForceLink ?? false)
			});
		}

		public Task UnlinkAppleGameCenterAsync()
		{
			return UnlinkExternalTokenAsync("apple-game-center");
		}

		public Task SignInWithGoogleAsync(string idToken, SignInOptions options = null)
		{
			return SignInWithExternalTokenAsync("google.com", new SignInWithExternalTokenRequest
			{
				IdProvider = "google.com",
				Token = idToken,
				SignInOnly = (options != null && !options.CreateAccount)
			});
		}

		public Task LinkWithGoogleAsync(string idToken, LinkOptions options = null)
		{
			return LinkWithExternalTokenAsync("google.com", new LinkWithExternalTokenRequest
			{
				IdProvider = "google.com",
				Token = idToken,
				ForceLink = (options?.ForceLink ?? false)
			});
		}

		public Task UnlinkGoogleAsync()
		{
			return UnlinkExternalTokenAsync("google.com");
		}

		public Task SignInWithGooglePlayGamesAsync(string authCode, SignInOptions options = null)
		{
			return SignInWithExternalTokenAsync("google-play-games", new SignInWithExternalTokenRequest
			{
				IdProvider = "google-play-games",
				Token = authCode,
				SignInOnly = (options != null && !options.CreateAccount)
			});
		}

		public Task LinkWithGooglePlayGamesAsync(string authCode, LinkOptions options = null)
		{
			return LinkWithExternalTokenAsync("google-play-games", new LinkWithExternalTokenRequest
			{
				IdProvider = "google-play-games",
				Token = authCode,
				ForceLink = (options?.ForceLink ?? false)
			});
		}

		public Task UnlinkGooglePlayGamesAsync()
		{
			return UnlinkExternalTokenAsync("google-play-games");
		}

		public Task SignInWithFacebookAsync(string accessToken, SignInOptions options = null)
		{
			return SignInWithExternalTokenAsync("facebook.com", new SignInWithExternalTokenRequest
			{
				IdProvider = "facebook.com",
				Token = accessToken,
				SignInOnly = (options != null && !options.CreateAccount)
			});
		}

		public Task LinkWithFacebookAsync(string accessToken, LinkOptions options = null)
		{
			return LinkWithExternalTokenAsync("facebook.com", new LinkWithExternalTokenRequest
			{
				IdProvider = "facebook.com",
				Token = accessToken,
				ForceLink = (options?.ForceLink ?? false)
			});
		}

		public Task UnlinkFacebookAsync()
		{
			return UnlinkExternalTokenAsync("facebook.com");
		}

		[Obsolete("This method is deprecated as of version 2.7.1. Please use the SignInWithSteamAsync method with the 'identity' parameter for better security.")]
		public Task SignInWithSteamAsync(string sessionTicket, SignInOptions options = null)
		{
			return SignInWithExternalTokenAsync("steampowered.com", new SignInWithSteamRequest
			{
				IdProvider = "steampowered.com",
				Token = sessionTicket,
				SignInOnly = (options != null && !options.CreateAccount)
			});
		}

		[Obsolete("This method is deprecated as of version 2.7.1. Please use the LinkWithSteamAsync method with the 'identity' parameter for better security.")]
		public Task LinkWithSteamAsync(string sessionTicket, LinkOptions options = null)
		{
			return LinkWithExternalTokenAsync("steampowered.com", new LinkWithSteamRequest
			{
				IdProvider = "steampowered.com",
				Token = sessionTicket,
				ForceLink = (options?.ForceLink ?? false)
			});
		}

		public Task SignInWithSteamAsync(string sessionTicket, string identity, SignInOptions options = null)
		{
			ValidateSteamIdentity(identity);
			return SignInWithExternalTokenAsync("steampowered.com", new SignInWithSteamRequest
			{
				IdProvider = "steampowered.com",
				Token = sessionTicket,
				SteamConfig = new SteamConfig
				{
					identity = identity
				},
				SignInOnly = (options != null && !options.CreateAccount)
			});
		}

		public Task LinkWithSteamAsync(string sessionTicket, string identity, LinkOptions options = null)
		{
			ValidateSteamIdentity(identity);
			return LinkWithExternalTokenAsync("steampowered.com", new LinkWithSteamRequest
			{
				IdProvider = "steampowered.com",
				Token = sessionTicket,
				SteamConfig = new SteamConfig
				{
					identity = identity
				},
				ForceLink = (options?.ForceLink ?? false)
			});
		}

		private void ValidateSteamIdentity(string identity)
		{
			if (string.IsNullOrEmpty(identity))
			{
				throw ExceptionHandler.BuildUnknownException("Identity cannot be null or empty.");
			}
			if (!Regex.IsMatch(identity, "^[a-zA-Z0-9]{5,30}$"))
			{
				throw ExceptionHandler.BuildUnknownException("The provided identity must only contain alphanumeric characters and be between 5 and 30 characters in length.");
			}
		}

		public Task UnlinkSteamAsync()
		{
			return UnlinkExternalTokenAsync("steampowered.com");
		}

		public Task SignInWithOculusAsync(string nonce, string userId, SignInOptions options = null)
		{
			return SignInWithExternalTokenAsync("oculus", new SignInWithOculusRequest
			{
				IdProvider = "oculus",
				Token = nonce,
				OculusConfig = new OculusConfig
				{
					UserId = userId
				},
				SignInOnly = (options != null && !options.CreateAccount)
			});
		}

		public Task LinkWithOculusAsync(string nonce, string userId, LinkOptions options = null)
		{
			return LinkWithExternalTokenAsync("oculus", new LinkWithOculusRequest
			{
				IdProvider = "oculus",
				Token = nonce,
				OculusConfig = new OculusConfig
				{
					UserId = userId
				},
				ForceLink = (options?.ForceLink ?? false)
			});
		}

		public Task UnlinkOculusAsync()
		{
			return UnlinkExternalTokenAsync("oculus");
		}

		public Task SignInWithOpenIdConnectAsync(string idProviderName, string idToken, SignInOptions options = null)
		{
			if (!ValidateOpenIdConnectIdProviderName(idProviderName))
			{
				throw ExceptionHandler.BuildInvalidIdProviderNameException();
			}
			return SignInWithExternalTokenAsync(idProviderName, new SignInWithExternalTokenRequest
			{
				IdProvider = idProviderName,
				Token = idToken,
				SignInOnly = (options != null && !options.CreateAccount)
			});
		}

		public Task LinkWithOpenIdConnectAsync(string idProviderName, string idToken, LinkOptions options = null)
		{
			if (!ValidateOpenIdConnectIdProviderName(idProviderName))
			{
				throw ExceptionHandler.BuildInvalidIdProviderNameException();
			}
			return LinkWithExternalTokenAsync(idProviderName, new LinkWithExternalTokenRequest
			{
				IdProvider = idProviderName,
				Token = idToken,
				ForceLink = (options?.ForceLink ?? false)
			});
		}

		public Task UnlinkOpenIdConnectAsync(string idProviderName)
		{
			if (!ValidateOpenIdConnectIdProviderName(idProviderName))
			{
				throw ExceptionHandler.BuildInvalidIdProviderNameException();
			}
			return UnlinkExternalTokenAsync(idProviderName);
		}

		public Task SignInWithUsernamePasswordAsync(string username, string password)
		{
			return SignInWithUsernamePasswordRequestAsync(BuildUsernamePasswordRequest(username, password));
		}

		public Task SignUpWithUsernamePasswordAsync(string username, string password)
		{
			return SignUpWithUsernamePasswordRequestAsync(BuildUsernamePasswordRequest(username, password));
		}

		public Task AddUsernamePasswordAsync(string username, string password)
		{
			return AddUsernamePasswordRequestAsync(BuildUsernamePasswordRequest(username, password));
		}

		public Task UpdatePasswordAsync(string currentPassword, string newPassword)
		{
			if (string.IsNullOrEmpty(currentPassword) || string.IsNullOrEmpty(newPassword))
			{
				throw ExceptionHandler.BuildInvalidCredentialsException();
			}
			return UpdatePasswordRequestAsync(new UpdatePasswordRequest
			{
				Password = currentPassword,
				NewPassword = newPassword
			});
		}

		public Task SignInWithUnityAsync(string token, SignInOptions options = null)
		{
			return SignInWithExternalTokenAsync("unity", new SignInWithExternalTokenRequest
			{
				IdProvider = "unity",
				Token = token,
				SignInOnly = (options != null && !options.CreateAccount)
			});
		}

		public Task LinkWithUnityAsync(string token, LinkOptions options = null)
		{
			return LinkWithExternalTokenAsync("unity", new LinkWithExternalTokenRequest
			{
				IdProvider = "unity",
				Token = token,
				ForceLink = (options?.ForceLink ?? false)
			});
		}

		public Task UnlinkUnityAsync()
		{
			return UnlinkExternalTokenAsync("unity");
		}

		public async Task DeleteAccountAsync()
		{
			if (IsAuthorized)
			{
				try
				{
					await NetworkClient.DeleteAccountAsync(PlayerId);
					SignOut(clearCredentials: true);
					return;
				}
				catch (WebRequestException exception)
				{
					throw ExceptionHandler.ConvertException(exception);
				}
			}
			throw ExceptionHandler.BuildClientInvalidStateException(State);
		}

		public void SignOut(bool clearCredentials = false)
		{
			AccessTokenComponent.Clear();
			PlayerInfo = null;
			if (clearCredentials)
			{
				SessionTokenComponent.Clear();
				PlayerIdComponent.Clear();
				PlayerNameComponent.Clear();
			}
			CancelScheduledRefresh();
			CancelScheduledExpiration();
			ChangeState(AuthenticationState.SignedOut);
		}

		public void SwitchProfile(string profile)
		{
			if (State == AuthenticationState.SignedOut)
			{
				if (!string.IsNullOrEmpty(profile) && Regex.Match(profile, "^[a-zA-Z0-9_-]{1,30}$").Success)
				{
					m_Profile.Current = profile;
					return;
				}
				throw ExceptionHandler.BuildClientInvalidProfileException();
			}
			throw ExceptionHandler.BuildClientInvalidStateException(State);
		}

		public void ClearSessionToken()
		{
			if (State == AuthenticationState.SignedOut)
			{
				SessionTokenComponent.Clear();
				return;
			}
			throw ExceptionHandler.BuildClientInvalidStateException(State);
		}

		public async Task<PlayerInfo> GetPlayerInfoAsync()
		{
			if (IsAuthorized)
			{
				try
				{
					PlayerInfo = new PlayerInfo(await NetworkClient.GetPlayerInfoAsync(PlayerId));
					return PlayerInfo;
				}
				catch (WebRequestException exception)
				{
					throw ExceptionHandler.ConvertException(exception);
				}
			}
			throw ExceptionHandler.BuildClientInvalidStateException(State);
		}

		public async Task<string> GetPlayerNameAsync()
		{
			if (IsAuthorized)
			{
				try
				{
					PlayerNamesApi.Configuration.AccessToken = AccessTokenComponent.AccessToken;
					Player data = (await PlayerNamesApi.GetNameAsync(PlayerId)).Data;
					PlayerNameComponent.PlayerName = data.Name;
					return data.Name;
				}
				catch (ApiException ex)
				{
					if (ex.Response.StatusCode == 404)
					{
						PlayerNameComponent.Clear();
						return null;
					}
					throw ExceptionHandler.ConvertException(ex);
				}
				catch (Exception ex2)
				{
					throw ExceptionHandler.BuildUnknownException(ex2.Message);
				}
			}
			throw ExceptionHandler.BuildClientInvalidStateException(State);
		}

		public async Task<string> UpdatePlayerNameAsync(string playerName)
		{
			if (IsAuthorized)
			{
				if (string.IsNullOrWhiteSpace(playerName) || playerName.Any(char.IsWhiteSpace))
				{
					throw ExceptionHandler.BuildInvalidPlayerNameException();
				}
				try
				{
					PlayerNamesApi.Configuration.AccessToken = AccessTokenComponent.AccessToken;
					string text = (await PlayerNamesApi.UpdateNameAsync(PlayerId, new UpdateNameRequest(playerName))).Data?.Name;
					if (string.IsNullOrWhiteSpace(text))
					{
						throw ExceptionHandler.BuildUnknownException("Invalid player name response");
					}
					PlayerNameComponent.PlayerName = text;
					return text;
				}
				catch (ApiException exception)
				{
					throw ExceptionHandler.ConvertException(exception);
				}
				catch (Exception ex)
				{
					throw ExceptionHandler.BuildUnknownException(ex.Message);
				}
			}
			throw ExceptionHandler.BuildClientInvalidStateException(State);
		}

		internal Task SignInWithExternalTokenAsync(string idProvider, SignInWithExternalTokenRequest request, bool enableRefresh = true)
		{
			if (State == AuthenticationState.SignedOut || State == AuthenticationState.Expired)
			{
				return HandleSignInRequestAsync(() => NetworkClient.SignInWithExternalTokenAsync(idProvider, request), enableRefresh);
			}
			RequestFailedException exception = ExceptionHandler.BuildClientInvalidStateException(State);
			SendSignInFailedEvent(exception, forceSignOut: false);
			return Task.FromException((Exception)(object)exception);
		}

		internal async Task LinkWithExternalTokenAsync(string idProvider, LinkWithExternalTokenRequest request)
		{
			if (IsAuthorized)
			{
				try
				{
					LinkResponse linkResponse = await NetworkClient.LinkWithExternalTokenAsync(idProvider, request);
					PlayerInfo?.AddExternalIdentity(linkResponse.User?.ExternalIds?.FirstOrDefault((ExternalIdentity x) => x.ProviderId == request.IdProvider));
					return;
				}
				catch (WebRequestException exception)
				{
					throw ExceptionHandler.ConvertException(exception);
				}
			}
			throw ExceptionHandler.BuildClientInvalidStateException(State);
		}

		internal async Task UnlinkExternalTokenAsync(string idProvider)
		{
			if (IsAuthorized)
			{
				string text = PlayerInfo?.GetIdentityId(idProvider);
				if (text == null)
				{
					throw ExceptionHandler.BuildClientUnlinkExternalIdNotFoundException();
				}
				try
				{
					await NetworkClient.UnlinkExternalTokenAsync(idProvider, new UnlinkRequest
					{
						IdProvider = idProvider,
						ExternalId = text
					});
					PlayerInfo.RemoveIdentity(idProvider);
					return;
				}
				catch (WebRequestException exception)
				{
					throw ExceptionHandler.ConvertException(exception);
				}
			}
			throw ExceptionHandler.BuildClientInvalidStateException(State);
		}

		internal Task SignInWithUsernamePasswordRequestAsync(UsernamePasswordRequest request, bool enableRefresh = true)
		{
			if (State == AuthenticationState.SignedOut || State == AuthenticationState.Expired)
			{
				return HandleSignInRequestAsync(() => NetworkClient.SignInWithUsernamePasswordAsync(request), enableRefresh);
			}
			RequestFailedException exception = ExceptionHandler.BuildClientInvalidStateException(State);
			SendSignInFailedEvent(exception, forceSignOut: false);
			return Task.FromException((Exception)(object)exception);
		}

		internal Task SignUpWithUsernamePasswordRequestAsync(UsernamePasswordRequest request, bool enableRefresh = true)
		{
			if (State == AuthenticationState.SignedOut || State == AuthenticationState.Expired)
			{
				return HandleSignInRequestAsync(() => NetworkClient.SignUpWithUsernamePasswordAsync(request), enableRefresh);
			}
			RequestFailedException exception = ExceptionHandler.BuildClientInvalidStateException(State);
			SendSignInFailedEvent(exception, forceSignOut: false);
			return Task.FromException((Exception)(object)exception);
		}

		internal async Task AddUsernamePasswordRequestAsync(UsernamePasswordRequest request)
		{
			if (IsAuthorized)
			{
				try
				{
					SignInResponse signInResponse = await NetworkClient.AddUsernamePasswordAsync(request);
					PlayerInfo.Username = signInResponse.User?.Username;
					return;
				}
				catch (WebRequestException exception)
				{
					throw ExceptionHandler.ConvertException(exception);
				}
				catch (Exception ex)
				{
					throw ExceptionHandler.BuildUnknownException(ex.Message);
				}
			}
			throw ExceptionHandler.BuildClientInvalidStateException(State);
		}

		internal Task UpdatePasswordRequestAsync(UpdatePasswordRequest request, bool enableRefresh = true)
		{
			if (IsAuthorized)
			{
				return HandleUpdatePasswordRequestAsync(() => NetworkClient.UpdatePasswordAsync(request), enableRefresh);
			}
			return Task.FromException((Exception)(object)ExceptionHandler.BuildClientInvalidStateException(State));
		}

		internal Task RefreshAccessTokenAsync()
		{
			if (IsSignedIn)
			{
				if (State == AuthenticationState.Expired)
				{
					return Task.CompletedTask;
				}
				string sessionToken = SessionTokenComponent.SessionToken;
				if (string.IsNullOrEmpty(sessionToken))
				{
					return Task.CompletedTask;
				}
				return StartRefreshAsync(sessionToken);
			}
			return Task.CompletedTask;
		}

		internal async Task HandleSignInRequestAsync(Func<Task<SignInResponse>> signInRequest, bool enableRefresh = true)
		{
			try
			{
				ChangeState(AuthenticationState.SigningIn);
				CompleteSignIn(await signInRequest(), enableRefresh);
			}
			catch (RequestFailedException ex)
			{
				RequestFailedException exception = ex;
				SendSignInFailedEvent(exception, forceSignOut: true);
				throw;
			}
			catch (WebRequestException exception2)
			{
				RequestFailedException ex2 = ExceptionHandler.ConvertException(exception2);
				if (ex2.ErrorCode == AuthenticationErrorCodes.InvalidSessionToken)
				{
					SessionTokenComponent.Clear();
					Logger.Log("The session token is invalid and has been cleared. The associated account is no longer accessible through this login method.");
				}
				SendSignInFailedEvent(ex2, forceSignOut: true);
				throw ex2;
			}
		}

		internal async Task HandleUpdatePasswordRequestAsync(Func<Task<SignInResponse>> updatePasswordRequest, bool enableRefresh = true)
		{
			try
			{
				CompleteSignIn(await updatePasswordRequest(), enableRefresh);
			}
			catch (RequestFailedException ex)
			{
				RequestFailedException exception = ex;
				SendUpdatePasswordFailedEvent(exception, forceSignOut: false);
				throw;
			}
			catch (WebRequestException exception2)
			{
				RequestFailedException ex2 = ExceptionHandler.ConvertException(exception2);
				if (ex2.ErrorCode == AuthenticationErrorCodes.InvalidSessionToken)
				{
					SessionTokenComponent.Clear();
					Logger.Log("The session token is invalid and has been cleared. The associated account is no longer accessible through this login method.");
				}
				SendUpdatePasswordFailedEvent(ex2, forceSignOut: false);
				throw ex2;
			}
		}

		internal async Task StartRefreshAsync(string sessionToken)
		{
			ChangeState(AuthenticationState.Refreshing);
			try
			{
				CompleteSignIn(await NetworkClient.SignInWithSessionTokenAsync(sessionToken));
			}
			catch (RequestFailedException)
			{
				Logger.LogWarning("The access token is not valid. Retry and refresh again.");
				if (State != AuthenticationState.Expired)
				{
					Expire();
				}
			}
			catch (WebRequestException)
			{
				if (State == AuthenticationState.Refreshing)
				{
					Logger.LogWarning("Failed to refresh access token due to network error or internal server error, will retry later.");
					ChangeState(AuthenticationState.Authorized);
					ScheduleRefresh(Settings.RefreshAttemptFrequency);
				}
			}
		}

		internal void CompleteSignIn(SignInResponse response, bool enableRefresh = true)
		{
			try
			{
				AccessToken accessToken = m_JwtDecoder.Decode<AccessToken>(response.IdToken);
				if (accessToken == null)
				{
					throw AuthenticationException.Create(51, "Failed to decode and verify access token.");
				}
				AccessTokenComponent.AccessToken = response.IdToken;
				if (accessToken.Audience != null)
				{
					EnvironmentIdComponent.EnvironmentId = accessToken.Audience.FirstOrDefault((string s) => s.StartsWith("envId:"))?.Substring(6);
				}
				PlayerInfo = ((response.User != null) ? new PlayerInfo(response.User) : new PlayerInfo(response.UserId));
				PlayerIdComponent.PlayerId = response.UserId;
				SessionTokenComponent.SessionToken = response.SessionToken;
				int num = response.ExpiresIn - Settings.AccessTokenRefreshBuffer;
				int num2 = response.ExpiresIn - Settings.AccessTokenExpiryBuffer;
				AccessTokenComponent.ExpiryTime = DateTime.UtcNow.AddSeconds(num2);
				if (enableRefresh)
				{
					ScheduleRefresh(num);
				}
				ScheduleExpiration(num2);
				ChangeState(AuthenticationState.Authorized);
			}
			catch (AuthenticationException)
			{
				throw;
			}
			catch (Exception innerException)
			{
				throw AuthenticationException.Create(0, "Unknown error completing sign-in.", innerException);
			}
		}

		internal void ScheduleRefresh(double delay)
		{
			CancelScheduledRefresh();
			DateTime value = DateTime.UtcNow.AddSeconds(delay);
			DateTime? expiryTime = AccessTokenComponent.ExpiryTime;
			if (value < expiryTime)
			{
				RefreshActionId = m_Scheduler.ScheduleAction((Action)ExecuteScheduledRefresh, delay);
			}
		}

		internal void ScheduleExpiration(double delay)
		{
			CancelScheduledExpiration();
			ExpirationActionId = m_Scheduler.ScheduleAction((Action)ExecuteScheduledExpiration, delay);
		}

		internal void ExecuteScheduledRefresh()
		{
			RefreshActionId = null;
			RefreshAccessTokenAsync();
		}

		internal void ExecuteScheduledExpiration()
		{
			ExpirationActionId = null;
			Expire();
		}

		internal void CancelScheduledRefresh()
		{
			if (RefreshActionId.HasValue)
			{
				m_Scheduler.CancelAction(RefreshActionId.Value);
				RefreshActionId = null;
			}
		}

		internal void CancelScheduledExpiration()
		{
			if (ExpirationActionId.HasValue)
			{
				m_Scheduler.CancelAction(ExpirationActionId.Value);
				ExpirationActionId = null;
			}
		}

		internal void Expire()
		{
			AccessTokenComponent.Clear();
			CancelScheduledRefresh();
			CancelScheduledExpiration();
			ChangeState(AuthenticationState.Expired);
		}

		internal void MigrateCache()
		{
			try
			{
				SessionTokenComponent.Migrate();
			}
			catch (Exception exception)
			{
				Logger.LogException(exception);
			}
		}

		private void ChangeState(AuthenticationState newState)
		{
			if (State != newState)
			{
				AuthenticationState state = State;
				State = newState;
				HandleStateChanged(state, newState);
			}
		}

		private void HandleStateChanged(AuthenticationState oldState, AuthenticationState newState)
		{
			this.StateChanged?.Invoke(oldState, newState);
			switch (newState)
			{
			case AuthenticationState.Authorized:
				if (oldState != AuthenticationState.Refreshing)
				{
					this.SignedIn?.Invoke();
				}
				break;
			case AuthenticationState.SignedOut:
				if (oldState != AuthenticationState.SigningIn)
				{
					this.SignedOut?.Invoke();
				}
				break;
			case AuthenticationState.Expired:
				this.Expired?.Invoke();
				break;
			case AuthenticationState.SigningIn:
			case AuthenticationState.Refreshing:
				break;
			}
		}

		private void SendSignInFailedEvent(RequestFailedException exception, bool forceSignOut)
		{
			this.SignInFailed?.Invoke(exception);
			if (forceSignOut)
			{
				SignOut();
			}
		}

		private void SendUpdatePasswordFailedEvent(RequestFailedException exception, bool forceSignOut)
		{
			this.UpdatePasswordFailed?.Invoke(exception);
			if (forceSignOut)
			{
				SignOut();
			}
		}

		private bool ValidateOpenIdConnectIdProviderName(string idProviderName)
		{
			if (!string.IsNullOrEmpty(idProviderName))
			{
				return Regex.Match(idProviderName, "^oidc-[a-z0-9-_\\.]{1,15}$").Success;
			}
			return false;
		}

		private UsernamePasswordRequest BuildUsernamePasswordRequest(string username, string password)
		{
			if (!ValidateCredentials(username, password))
			{
				throw ExceptionHandler.BuildInvalidCredentialsException();
			}
			return new UsernamePasswordRequest
			{
				Username = username,
				Password = password
			};
		}

		private bool ValidateCredentials(string username, string password)
		{
			if (!string.IsNullOrEmpty(username))
			{
				return !string.IsNullOrEmpty(password);
			}
			return false;
		}
	}
	internal enum AuthenticationState
	{
		SignedOut,
		SigningIn,
		Authorized,
		Refreshing,
		Expired
	}
	public static class AuthenticationExtensions
	{
		internal const string ProfileKey = "com.unity.services.authentication.profile";

		private const string k_ProfileRegex = "^[a-zA-Z0-9_-]{1,30}$";

		public static InitializationOptions SetProfile(this InitializationOptions options, string profile)
		{
			if (string.IsNullOrEmpty(profile) || !Regex.Match(profile, "^[a-zA-Z0-9_-]{1,30}$").Success)
			{
				throw AuthenticationException.Create(AuthenticationErrorCodes.ClientInvalidProfile, "Invalid profile name. The profile may only contain alphanumeric values, '-', '_', and must be no longer than 30 characters.");
			}
			return options.SetOption("com.unity.services.authentication.profile", profile);
		}
	}
	internal class AuthenticationPackageInitializer : IInitializablePackage
	{
		private const string k_CloudEnvironmentKey = "com.unity.services.core.cloud-environment";

		private const string k_StagingEnvironment = "staging";

		public Task Initialize(CoreRegistry registry)
		{
			AuthenticationSettings settings = new AuthenticationSettings();
			IActionScheduler serviceComponent = registry.GetServiceComponent<IActionScheduler>();
			IEnvironments serviceComponent2 = registry.GetServiceComponent<IEnvironments>();
			ICloudProjectId serviceComponent3 = registry.GetServiceComponent<ICloudProjectId>();
			IProjectConfiguration serviceComponent4 = registry.GetServiceComponent<IProjectConfiguration>();
			ProfileComponent profile = new ProfileComponent(serviceComponent4.GetString("com.unity.services.authentication.profile", "default"));
			AuthenticationMetrics metrics = new AuthenticationMetrics(registry.GetServiceComponent<IMetricsFactory>());
			JwtDecoder jwtDecoder = new JwtDecoder();
			AuthenticationCache cache = new AuthenticationCache(serviceComponent3, profile);
			AccessTokenComponent accessToken = new AccessTokenComponent();
			EnvironmentIdComponent environmentId = new EnvironmentIdComponent();
			PlayerIdComponent playerId = new PlayerIdComponent(cache);
			PlayerNameComponent playerName = new PlayerNameComponent(cache);
			SessionTokenComponent sessionToken = new SessionTokenComponent(cache);
			NetworkConfiguration configuration = new NetworkConfiguration();
			NetworkHandler networkHandler = new NetworkHandler(configuration);
			string playerAuthHost = GetPlayerAuthHost(serviceComponent4);
			PlayerNamesApi playerNamesApi = new PlayerNamesApi(new AuthenticationApiClient(configuration), new ApiConfiguration
			{
				BasePath = GetPlayerNamesHost(serviceComponent4)
			});
			AuthenticationNetworkClient networkClient = new AuthenticationNetworkClient(playerAuthHost, serviceComponent3, serviceComponent2, networkHandler, accessToken);
			AuthenticationServiceInternal authenticationServiceInternal = (AuthenticationServiceInternal)(AuthenticationService.Instance = new AuthenticationServiceInternal(settings, networkClient, playerNamesApi, profile, jwtDecoder, cache, serviceComponent, metrics, accessToken, environmentId, playerId, playerName, sessionToken));
			registry.RegisterServiceComponent<IAccessToken>((IAccessToken)(object)authenticationServiceInternal.AccessTokenComponent);
			registry.RegisterServiceComponent<IEnvironmentId>((IEnvironmentId)(object)authenticationServiceInternal.EnvironmentIdComponent);
			registry.RegisterServiceComponent<IPlayerId>((IPlayerId)(object)authenticationServiceInternal.PlayerIdComponent);
			return Task.CompletedTask;
		}

		[RuntimeInitializeOnLoadMethod(/*Could not decode attribute arguments.*/)]
		private static void Register()
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: 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_001f: 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_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: 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_004a: Unknown result type (might be due to invalid IL or missing references)
			CoreRegistration val = CoreRegistry.Instance.RegisterPackage<AuthenticationPackageInitializer>(new AuthenticationPackageInitializer());
			val = ((CoreRegistration)(ref val)).DependsOn<IEnvironments>();
			val = ((CoreRegistration)(ref val)).DependsOn<IActionScheduler>();
			val = ((CoreRegistration)(ref val)).DependsOn<ICloudProjectId>();
			val = ((CoreRegistration)(ref val)).DependsOn<IProjectConfiguration>();
			val = ((CoreRegistration)(ref val)).DependsOn<IMetricsFactory>();
			val = ((CoreRegistration)(ref val)).ProvidesComponent<IPlayerId>();
			val = ((CoreRegistration)(ref val)).ProvidesComponent<IAccessToken>();
			((CoreRegistration)(ref val)).ProvidesComponent<IEnvironmentId>();
		}

		private string GetPlayerAuthHost(IProjectConfiguration projectConfiguration)
		{
			if (((projectConfiguration != null) ? projectConfiguration.GetString("com.unity.services.core.cloud-environment", (string)null) : null) == "staging")
			{
				return "https://player-auth-stg.services.api.unity.com";
			}
			return "https://player-auth.services.api.unity.com";
		}

		private string GetPlayerNamesHost(IProjectConfiguration projectConfiguration)
		{
			if (((projectConfiguration != null) ? projectConfiguration.GetString("com.unity.services.core.cloud-environment", (string)null) : null) == "staging")
			{
				return "https://social-stg.services.api.unity.com/v1";
			}
			return "https://social.services.api.unity.com/v1";
		}
	}
	public static class AuthenticationErrorCodes
	{
		public static readonly int MinValue = 10000;

		public static readonly int ClientInvalidUserState = 10000;

		public static readonly int ClientNoActiveSession = 10001;

		public static readonly int InvalidParameters = 10002;

		public static readonly int AccountAlreadyLinked = 10003;

		public static readonly int AccountLinkLimitExceeded = 10004;

		public static readonly int ClientUnlinkExternalIdNotFound = 10005;

		public static readonly int ClientInvalidProfile = 10006;

		public static readonly int InvalidSessionToken = 10007;
	}
	public sealed class AuthenticationException : RequestFailedException
	{
		private AuthenticationException(int errorCode, string message, Exception innerException = null)
			: base(errorCode, message, innerException)
		{
		}

		public static RequestFailedException Create(int errorCode, string message, Exception innerException = null)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			if (errorCode < AuthenticationErrorCodes.MinValue)
			{
				return new RequestFailedException(errorCode, message, innerException);
			}
			return (RequestFailedException)(object)new AuthenticationException(errorCode, message, innerException);
		}
	}
	internal class AuthenticationExceptionHandler : IAuthenticationExceptionHandler
	{
		private IAuthenticationMetrics Metrics { get; }

		public AuthenticationExceptionHandler(IAuthenticationMetrics metrics)
		{
			Metrics = metrics;
		}

		public RequestFailedException BuildClientInvalidStateException(AuthenticationState state)
		{
			string message = string.Empty;
			switch (state)
			{
			case AuthenticationState.SignedOut:
				message = "Invalid state for this operation. The player is signed out.";
				break;
			case AuthenticationState.SigningIn:
				message = "Invalid state for this operation. The player is already signing in.";
				break;
			case AuthenticationState.Authorized:
			case AuthenticationState.Refreshing:
				message = "Invalid state for this operation. The player is already signed in.";
				break;
			case AuthenticationState.Expired:
				message = "Invalid state for this operation. The player session has expired.";
				break;
			}
			Metrics.SendClientInvalidStateExceptionMetric();
			return AuthenticationException.Create(AuthenticationErrorCodes.ClientInvalidUserState, message);
		}

		public RequestFailedException BuildClientInvalidProfileException()
		{
			return AuthenticationException.Create(AuthenticationErrorCodes.ClientInvalidProfile, "Invalid profile name. The profile may only contain alphanumeric values, '-', '_', and must be no longer than 30 characters.");
		}

		public RequestFailedException BuildClientUnlinkExternalIdNotFoundException()
		{
			Metrics.SendUnlinkExternalIdNotFoundExceptionMetric();
			return AuthenticationException.Create(AuthenticationErrorCodes.ClientUnlinkExternalIdNotFound, "No external id was found to unlink from the provider. Use GetPlayerInfoAsync to load the linked external ids.");
		}

		public RequestFailedException BuildClientSessionTokenNotExistsException()
		{
			Metrics.SendClientSessionTokenNotExistsExceptionMetric();
			return AuthenticationException.Create(AuthenticationErrorCodes.ClientNoActiveSession, "There is no cached session token.");
		}

		public RequestFailedException BuildUnknownException(string error)
		{
			return AuthenticationException.Create(0, error);
		}

		public RequestFailedException BuildInvalidIdProviderNameException()
		{
			return AuthenticationException.Create(AuthenticationErrorCodes.InvalidParameters, "Invalid IdProviderName. The Id Provider name should start with 'oidc-' and have between 6 and 20 characters (including 'oidc-')");
		}

		public RequestFailedException BuildInvalidPlayerNameException()
		{
			return AuthenticationException.Create(AuthenticationErrorCodes.InvalidParameters, "Invalid Player Name. Player names cannot be empty or contain spaces.");
		}

		public RequestFailedException BuildInvalidCredentialsException()
		{
			return AuthenticationException.Create(AuthenticationErrorCodes.InvalidParameters, "Username and/or Password are not in the correct format");
		}

		public RequestFailedException ConvertException(WebRequestException exception)
		{
			//IL_00be: Expected O, but got Unknown
			StringBuilder stringBuilder = new StringBuilder();
			string value = $"Request failed: {exception.ResponseCode}, {exception.Message}";
			stringBuilder.Append(value);
			if (exception.ResponseHeaders != null && exception.ResponseHeaders.TryGetValue("x-request-id", out var value2))
			{
				stringBuilder.Append(", request-id: " + value2);
			}
			Logger.Log(stringBuilder.ToString());
			if (exception.NetworkError)
			{
				Metrics.SendNetworkErrorMetric();
				return AuthenticationException.Create(1, "Network Error: " + exception.Message, exception);
			}
			try
			{
				AuthenticationErrorResponse authenticationErrorResponse = IsolatedJsonConvert.DeserializeObject<AuthenticationErrorResponse>(exception.Message, SerializerSettings.DefaultSerializerSettings);
				return AuthenticationException.Create(MapErrorCodes(authenticationErrorResponse.Title), authenticationErrorResponse.Detail, exception);
			}
			catch (JsonException ex)
			{
				JsonException innerException = ex;
				return AuthenticationException.Create(0, "Failed to deserialize server response.", (Exception)(object)innerException);
			}
			catch (Exception)
			{
				return AuthenticationException.Create(0, "Unknown error deserializing server response. ", exception);
			}
		}

		public RequestFailedException ConvertException(ApiException exception)
		{
			return (RequestFailedException)(exception?.Type switch
			{
				ApiExceptionType.InvalidParameters => AuthenticationException.Create(AuthenticationErrorCodes.InvalidParameters, exception.Message), 
				ApiExceptionType.Deserialization => AuthenticationException.Create(0, exception.Message), 
				ApiExceptionType.Network => CreateNetworkException(exception), 
				ApiExceptionType.Http => CreateHttpException(exception), 
				_ => CreateUnknownException(exception), 
			});
		}

		private static RequestFailedException CreateNetworkException(ApiException exception)
		{
			return (RequestFailedException)(exception?.Response?.StatusCode switch
			{
				503 => AuthenticationException.Create(3, exception.Message), 
				504 => AuthenticationException.Create(2, exception.Message), 
				_ => AuthenticationException.Create(1, exception.Message), 
			});
		}

		private static RequestFailedException CreateHttpException(ApiException exception)
		{
			return (RequestFailedException)(exception?.Response?.StatusCode switch
			{
				400 => AuthenticationException.Create(55, exception.Message), 
				401 => AuthenticationException.Create(51, exception.Message), 
				403 => AuthenticationException.Create(53, exception.Message), 
				404 => AuthenticationException.Create(54, exception.Message), 
				408 => AuthenticationException.Create(2, exception.Message), 
				429 => AuthenticationException.Create(50, exception.Message), 
				_ => AuthenticationException.Create(55, exception.Message), 
			});
		}

		private static RequestFailedException CreateUnknownException(Exception exception)
		{
			return AuthenticationException.Create(0, "Unknown Error: " + exception.Message);
		}

		private int MapErrorCodes(string serverErrorTitle)
		{
			return serverErrorTitle switch
			{
				"ENTITY_EXISTS" => AuthenticationErrorCodes.AccountAlreadyLinked, 
				"LINKED_ACCOUNT_LIMIT_EXCEEDED" => AuthenticationErrorCodes.AccountLinkLimitExceeded, 
				"INVALID_PARAMETERS" => AuthenticationErrorCodes.InvalidParameters, 
				"INVALID_SESSION_TOKEN" => AuthenticationErrorCodes.InvalidSessionToken, 
				"PERMISSION_DENIED" => AuthenticationErrorCodes.InvalidParameters, 
				"UNAUTHORIZED_REQUEST" => 51, 
				_ => 0, 
			};
		}
	}
	internal interface IAuthenticationExceptionHandler
	{
		RequestFailedException BuildClientInvalidStateException(AuthenticationState state);

		RequestFailedException BuildClientInvalidProfileException();

		RequestFailedException BuildClientUnlinkExternalIdNotFoundException();

		RequestFailedException BuildClientSessionTokenNotExistsException();

		RequestFailedException BuildUnknownException(string error);

		RequestFailedException BuildInvalidIdProviderNameException();

		RequestFailedException BuildInvalidPlayerNameException();

		RequestFailedException BuildInvalidCredentialsException();

		RequestFailedException ConvertException(WebRequestException exception);

		RequestFailedException ConvertException(ApiException exception);
	}
	public interface IAuthenticationService
	{
		bool IsSignedIn { get; }

		bool IsAuthorized { get; }

		bool IsExpired { get; }

		string AccessToken { get; }

		string PlayerId { get; }

		string PlayerName { get; }

		string Profile { get; }

		bool SessionTokenExists { get; }

		PlayerInfo PlayerInfo { get; }

		event Action SignedIn;

		event Action SignedOut;

		event Action Expired;

		event Action<RequestFailedException> SignInFailed;

		Task SignInAnonymouslyAsync(SignInOptions options = null);

		Task SignInWithAppleAsync(string idToken, SignInOptions options = null);

		Task LinkWithAppleAsync(string idToken, LinkOptions options = null);

		Task UnlinkAppleAsync();

		Task SignInWithAppleGameCenterAsync(string signature, string teamPlayerId, string publicKeyURL, string salt, ulong timestamp, SignInOptions options = null);

		Task LinkWithAppleGameCenterAsync(string signature, string teamPlayerId, string publicKeyURL, string salt, ulong timestamp, LinkOptions options = null);

		Task UnlinkAppleGameCenterAsync();

		Task SignInWithGoogleAsync(string idToken, SignInOptions options = null);

		Task LinkWithGoogleAsync(string idToken, LinkOptions options = null);

		Task UnlinkGoogleAsync();

		Task SignInWithGooglePlayGamesAsync(string authCode, SignInOptions options = null);

		Task LinkWithGooglePlayGamesAsync(string authCode, LinkOptions options = null);

		Task UnlinkGooglePlayGamesAsync();

		Task SignInWithFacebookAsync(string accessToken, SignInOptions options = null);

		Task LinkWithFacebookAsync(string accessToken, LinkOptions options = null);

		Task UnlinkFacebookAsync();

		Task SignInWithSteamAsync(string sessionTicket, string identity, SignInOptions options = null);

		[Obsolete("This method is deprecated as of version 2.7.1. Please use the SignInWithSteamAsync method with the 'identity' parameter for better security.")]
		Task SignInWithSteamAsync(string sessionTicket, SignInOptions options = null);

		Task LinkWithSteamAsync(string sessionTicket, string identity, LinkOptions options = null);

		[Obsolete("This method is deprecated as of version 2.7.1. Please use the LinkWithSteamAsync method with the 'identity' parameter for better security.")]
		Task LinkWithSteamAsync(string sessionTicket, LinkOptions options = null);

		Task UnlinkSteamAsync();

		Task SignInWithOculusAsync(string nonce, string userId, SignInOptions options = null);

		Task LinkWithOculusAsync(string nonce, string userId, LinkOptions options = null);

		Task UnlinkOculusAsync();

		Task SignInWithOpenIdConnectAsync(string idProviderName, string idToken, SignInOptions options = null);

		Task LinkWithOpenIdConnectAsync(string idProviderName, string idToken, LinkOptions options = null);

		Task UnlinkOpenIdConnectAsync(string idProviderName);

		Task SignInWithUnityAsync(string token, SignInOptions options = null);

		Task LinkWithUnityAsync(string token, LinkOptions options = null);

		Task UnlinkUnityAsync();

		Task SignInWithUsernamePasswordAsync(string username, string password);

		Task SignUpWithUsernamePasswordAsync(string username, string password);

		Task AddUsernamePasswordAsync(string username, string password);

		Task UpdatePasswordAsync(string currentPassword, string newPassword);

		Task DeleteAccountAsync();

		Task<PlayerInfo> GetPlayerInfoAsync();

		Task<string> GetPlayerNameAsync();

		Task<string> UpdatePlayerNameAsync(string name);

		void SignOut(bool clearCredentials = false);

		void SwitchProfile(string profile);

		void ClearSessionToken();
	}
	internal class AuthenticationMetrics : IAuthenticationMetrics
	{
		private const string k_PackageName = "com.unity.services.authentication";

		private const string k_NetworkErrorKey = "network_error_event";

		private const string k_ExpiredSessionKey = "expired_session_event";

		private const string k_ClientInvalidStateExceptionKey = "client_invalid_state_exception_event";

		private const string k_UnlinkExternalIdNotFoundExceptionKey = "unlink_external_id_not_found_exception_event";

		private const string k_ClientSessionTokenNotExistsExceptionKey = "client_session_token_not_exists_exception_event";

		private readonly IMetrics m_Metrics;

		internal AuthenticationMetrics(IMetricsFactory metricsFactory)
		{
			m_Metrics = metricsFactory.Create("com.unity.services.authentication");
		}

		public void SendNetworkErrorMetric()
		{
			m_Metrics.SendSumMetric("network_error_event", 1.0, (IDictionary<string, string>)null);
		}

		public void SendExpiredSessionMetric()
		{
			m_Metrics.SendSumMetric("expired_session_event", 1.0, (IDictionary<string, string>)null);
		}

		public void SendClientInvalidStateExceptionMetric()
		{
			m_Metrics.SendSumMetric("client_invalid_state_exception_event", 1.0, (IDictionary<string, string>)null);
		}

		public void SendUnlinkExternalIdNotFoundExceptionMetric()
		{
			m_Metrics.SendSumMetric("unlink_external_id_not_found_exception_event", 1.0, (IDictionary<string, string>)null);
		}

		public void SendClientSessionTokenNotExistsExceptionMetric()
		{
			m_Metrics.SendSumMetric("client_session_token_not_exists_exception_event", 1.0, (IDictionary<string, string>)null);
		}
	}
	internal interface IAuthenticationMetrics
	{
		void SendNetworkErrorMetric();

		void SendExpiredSessionMetric();

		void SendClientInvalidStateExceptionMetric();

		void SendUnlinkExternalIdNotFoundExceptionMetric();

		void SendClientSessionTokenNotExistsExceptionMetric();
	}
	internal class AccessTokenComponent : IAccessToken, IServiceComponent
	{
		public string AccessToken { get; internal set; }

		public DateTime? ExpiryTime { get; internal set; }

		internal AccessTokenComponent()
		{
		}

		internal void Clear()
		{
			AccessToken = null;
			ExpiryTime = null;
		}
	}
	internal class EnvironmentIdComponent : IEnvironmentId, IServiceComponent
	{
		public string EnvironmentId { get; internal set; }

		internal EnvironmentIdComponent()
		{
		}
	}
	internal class PlayerIdComponent : IPlayerId, IServiceComponent
	{
		private const string k_CacheKey = "player_id";

		private readonly IAuthenticationCache m_Cache;

		public string PlayerId
		{
			get
			{
				return GetPlayerId();
			}
			internal set
			{
				SetPlayerId(value);
			}
		}

		public event Action<string> PlayerIdChanged;

		internal PlayerIdComponent(IAuthenticationCache cache)
		{
			m_Cache = cache;
		}

		internal void Clear()
		{
			m_Cache.DeleteKey("player_id");
		}

		private string GetPlayerId()
		{
			return m_Cache.GetString("player_id");
		}

		private void SetPlayerId(string playerId)
		{
			if (PlayerId != playerId)
			{
				m_Cache.SetString("player_id", playerId);
				this.PlayerIdChanged?.Invoke(playerId);
			}
		}
	}
	internal class PlayerNameComponent : IPlayerName
	{
		private const string k_CacheKey = "player_name";

		private readonly IAuthenticationCache m_Cache;

		public string PlayerName
		{
			get
			{
				return GetPlayerName();
			}
			internal set
			{
				SetPlayerName(value);
			}
		}

		public event Action<string> PlayerNameChanged;

		internal PlayerNameComponent(IAuthenticationCache cache)
		{
			m_Cache = cache;
		}

		internal void Clear()
		{
			m_Cache.DeleteKey("player_name");
		}

		private string GetPlayerName()
		{
			return m_Cache.GetString("player_name");
		}

		private void SetPlayerName(string playerName)
		{
			if (PlayerName != playerName)
			{
				m_Cache.SetString("player_name", playerName);
				this.PlayerNameChanged?.Invoke(playerName);
			}
		}
	}
	internal interface IProfile
	{
		string Current { get; set; }

		event Action<ProfileEventArgs> ProfileChange;
	}
	internal class ProfileComponent : IProfile
	{
		private string _current;

		public string Current
		{
			get
			{
				return _current;
			}
			set
			{
				SetProfile(value);
			}
		}

		public event Action<ProfileEventArgs> ProfileChange;

		internal ProfileComponent(string profile)
		{
			SetProfile(profile);
		}

		public void SetProfile(string profile)
		{
			_current = profile;
			this.ProfileChange?.Invoke(new ProfileEventArgs(_current));
		}
	}
	internal class ProfileEventArgs : EventArgs
	{
		public string Profile { get; }

		public ProfileEventArgs(string profile)
		{
			Profile = profile;
		}
	}
	internal class SessionTokenComponent
	{
		private const string k_CacheKey = "session_token";

		private readonly IAuthenticationCache m_Cache;

		internal string SessionToken
		{
			get
			{
				return GetSessionToken();
			}
			set
			{
				SetSessionToken(value);
			}
		}

		internal SessionTokenComponent(IAuthenticationCache cache)
		{
			m_Cache = cache;
		}

		internal void Clear()
		{
			m_Cache.DeleteKey("session_token");
		}

		internal void Migrate()
		{
			m_Cache.Migrate("session_token");
		}

		private string GetSessionToken()
		{
			return m_Cache.GetString("session_token");
		}

		private void SetSessionToken(string sessionToken)
		{
			m_Cache.SetString("session_token", sessionToken);
		}
	}
	public sealed class Identity
	{
		public string TypeId;

		public string UserId;

		internal Identity(ExternalIdentity externalIdentity)
		{
			if (externalIdentity != null)
			{
				TypeId = externalIdentity.ProviderId;
				UserId = externalIdentity.ExternalId;
			}
		}
	}
	public sealed class LinkOptions
	{
		public bool ForceLink { get; set; }
	}
	public sealed class PlayerInfo
	{
		private const string k_OpenIdConnectPrefix = "oidc-";

		private const string k_IdProviderNameRegex = "^oidc-[a-z0-9-_\\.]{1,15}$";

		public string Id { get; }

		public DateTime? CreatedAt { get; }

		public List<Identity> Identities { get; }

		[CanBeNull]
		public string Username { get; internal set; }

		[CanBeNull]
		public DateTime? LastPasswordUpdate { get; internal set; }

		internal PlayerInfo(string playerId)
		{
			Id = playerId;
			Identities = new List<Identity>();
		}

		internal PlayerInfo(PlayerInfoResponse response)
			: this(response.Id, response.CreatedAt, response.ExternalIds, response.UsernamePassword?.Username, response.UsernamePassword?.PasswordUpdatedAt)
		{
		}

		internal PlayerInfo(User user)
			: this(user.Id, user.CreatedAt, user.ExternalIds, user.UsernameInfo?.Username ?? user.Username, user.UsernameInfo?.PasswordUpdatedAt)
		{
		}

		internal PlayerInfo(string playerId, string createdAt, List<ExternalIdentity> externalIdentities, string username, string lastPasswordUpdate)
		{
			Id = playerId;
			Identities = new List<Identity>();
			if (double.TryParse(createdAt, out var result))
			{
				CreatedAt = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(result);
			}
			if (externalIdentities != null)
			{
				foreach (ExternalIdentity externalIdentity in externalIdentities)
				{
					Identities.Add(new Identity(externalIdentity));
				}
			}
			Username = username;
			if (double.TryParse(lastPasswordUpdate, out var result2))
			{
				LastPasswordUpdate = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(result2);
			}
		}

		public string GetFacebookId()
		{
			return GetIdentityId("facebook.com");
		}

		public string GetSteamId()
		{
			return GetIdentityId("steampowered.com");
		}

		public string GetGoogleId()
		{
			return GetIdentityId("google.com");
		}

		public string GetGooglePlayGamesId()
		{
			return GetIdentityId("google-play-games");
		}

		public string GetAppleId()
		{
			return GetIdentityId("apple.com");
		}

		public string GetAppleGameCenterId()
		{
			return GetIdentityId("apple-game-center");
		}

		public string GetOculusId()
		{
			return GetIdentityId("oculus");
		}

		public string GetOpenIdConnectId(string idProviderName)
		{
			if (!ValidateOpenIdConnectIdProviderName(idProviderName))
			{
				return null;
			}
			return GetIdentityId(idProviderName);
		}

		public string GetUnityId()
		{
			return GetIdentityId("unity");
		}

		public List<Identity> GetOpenIdConnectIdProviders()
		{
			return Identities?.FindAll((Identity id) => id.TypeId.StartsWith("oidc-"));
		}

		internal string GetIdentityId(string typeId)
		{
			return Identities?.FirstOrDefault((Identity x) => x.TypeId == typeId)?.UserId;
		}

		internal void AddExternalIdentity(ExternalIdentity externalId)
		{
			if (externalId != null)
			{
				Identities.Add(new Identity(externalId));
			}
		}

		internal void RemoveIdentity(string typeId)
		{
			Identities?.RemoveAll((Identity x) => x.TypeId == typeId);
		}

		private bool ValidateOpenIdConnectIdProviderName(string idProviderName)
		{
			if (!string.IsNullOrEmpty(idProviderName))
			{
				return Regex.Match(idProviderName, "^oidc-[a-z0-9-_\\.]{1,15}$").Success;
			}
			return false;
		}
	}
	[Serializable]
	internal class AppleGameCenterConfig
	{
		[JsonProperty("teamPlayerId")]
		public string TeamPlayerId;

		[JsonProperty("publicKeyUrl")]
		public string PublicKeyURL;

		[JsonProperty("salt")]
		public string Salt;

		[JsonProperty("timestamp")]
		public ulong Timestamp;

		[Preserve]
		internal AppleGameCenterConfig()
		{
		}
	}
	[Serializable]
	internal class LinkWithAppleGameCenterRequest : LinkWithExternalTokenRequest
	{
		[JsonProperty("appleGameCenterConfig")]
		public AppleGameCenterConfig AppleGameCenterConfig;

		[Preserve]
		internal LinkWithAppleGameCenterRequest()
		{
		}
	}
	[Serializable]
	internal class SignInWithAppleGameCenterRequest : SignInWithExternalTokenRequest
	{
		[JsonProperty("appleGameCenterConfig")]
		public AppleGameCenterConfig AppleGameCenterConfig;

		[Preserve]
		internal SignInWithAppleGameCenterRequest()
		{
		}
	}
	[Serializable]
	internal class LinkWithExternalTokenRequest
	{
		[JsonProperty("idProvider")]
		public string IdProvider;

		[JsonProperty("token")]
		public string Token;

		[JsonProperty("forceLink")]
		public bool ForceLink;

		[Preserve]
		internal LinkWithExternalTokenRequest()
		{
		}
	}
	internal class LinkWithSteamRequest : LinkWithExternalTokenRequest
	{
		[JsonProperty("steamConfig")]
		public SteamConfig SteamConfig;

		[Preserve]
		internal LinkWithSteamRequest()
		{
		}
	}
	[Serializable]
	internal class OculusConfig
	{
		[JsonProperty("userId")]
		public string UserId;

		[Preserve]
		internal OculusConfig()
		{
		}
	}
	[Serializable]
	internal class LinkWithOculusRequest : LinkWithExternalTokenRequest
	{
		[JsonProperty("oculusConfig")]
		public OculusConfig OculusConfig;

		[Preserve]
		internal LinkWithOculusRequest()
		{
		}
	}
	[Serializable]
	internal class SignInWithOculusRequest : SignInWithExternalTokenRequest
	{
		[JsonProperty("oculusConfig")]
		public OculusConfig OculusConfig;

		[Preserve]
		internal SignInWithOculusRequest()
		{
		}
	}
	[Serializable]
	internal class SessionTokenRequest
	{
		[JsonProperty("sessionToken")]
		public string SessionToken;

		[Preserve]
		public SessionTokenRequest()
		{
		}
	}
	[Serializable]
	internal class SignInWithExternalTokenRequest
	{
		[JsonProperty("idProvider")]
		public string IdProvider;

		[JsonProperty("token")]
		public string Token;

		[JsonProperty("signInOnly")]
		public bool SignInOnly;

		[Preserve]
		internal SignInWithExternalTokenRequest()
		{
		}
	}
	[Serializable]
	internal class SignInWithSteamRequest : SignInWithExternalTokenRequest
	{
		[JsonProperty("steamConfig")]
		public SteamConfig SteamConfig;

		[Preserve]
		internal SignInWithSteamRequest()
		{
		}
	}
	internal class SteamConfig
	{
		[JsonProperty("identity")]
		public string identity;

		[Preserve]
		internal SteamConfig()
		{
		}
	}
	[Serializable]
	internal class UnlinkRequest
	{
		[JsonProperty("idProvider")]
		public string IdProvider;

		[JsonProperty("externalId")]
		public string ExternalId;

		[Preserve]
		internal UnlinkRequest()
		{
		}
	}
	[Serializable]
	internal class UpdatePasswordRequest
	{
		[JsonProperty("password")]
		public string Password;

		[JsonProperty("newPassword")]
		public string NewPassword;

		[Preserve]
		internal UpdatePasswordRequest()
		{
		}
	}
	[Serializable]
	internal class UsernamePasswordRequest
	{
		[JsonProperty("username")]
		public string Username;

		[JsonProperty("password")]
		public string Password;

		[Preserve]
		internal UsernamePasswordRequest()
		{
		}
	}
	[Serializable]
	internal class AuthenticationErrorResponse
	{
		[JsonProperty("title")]
		public string Title;

		[JsonProperty("detail")]
		public string Detail;

		[JsonProperty("status")]
		public int Status;

		[Preserve]
		public AuthenticationErrorResponse()
		{
		}
	}
	[Serializable]
	internal class ExternalIdentity
	{
		[JsonProperty("providerId")]
		public string ProviderId;

		[JsonProperty("externalId")]
		public string ExternalId;

		[Preserve]
		public ExternalIdentity()
		{
		}
	}
	[Serializable]
	internal class LinkResponse
	{
		[JsonProperty("user")]
		public User User;

		[Preserve]
		public LinkResponse()
		{
		}
	}
	[Serializable]
	internal class PlayerInfoResponse
	{
		[JsonProperty("id")]
		public string Id;

		[JsonProperty("createdAt")]
		public string CreatedAt;

		[JsonProperty("externalIds")]
		public List<ExternalIdentity> ExternalIds;

		[JsonProperty("username")]
		[CanBeNull]
		public string Username;

		[JsonProperty("usernamepassword")]
		[CanBeNull]
		public UsernameInfo UsernamePassword;

		[Preserve]
		public PlayerInfoResponse()
		{
		}
	}
	[Serializable]
	internal class SignInResponse
	{
		[JsonProperty("userId")]
		public string UserId;

		[JsonProperty("idToken")]
		public string IdToken;

		[JsonProperty("sessionToken")]
		public string SessionToken;

		[JsonProperty("expiresIn")]
		public int ExpiresIn;

		[JsonProperty("user")]
		public User User;

		[Preserve]
		public SignInResponse()
		{
		}
	}
	[Serializable]
	internal class UnlinkResponse
	{
		[JsonProperty("user")]
		public User User;

		[Preserve]
		public UnlinkResponse()
		{
		}
	}
	[Serializable]
	internal class User
	{
		[JsonProperty("id")]
		public string Id;

		[JsonProperty("createdAt")]
		public string CreatedAt;

		[JsonProperty("externalIds")]
		public List<ExternalIdentity> ExternalIds;

		[JsonProperty("username")]
		[CanBeNull]
		public string Username;

		[JsonProperty("UsernameInfo")]
		[CanBeNull]
		public UsernameInfo UsernameInfo;

		[Preserve]
		public User()
		{
		}
	}
	internal class UsernameInfo
	{
		[JsonProperty("username")]
		public string Username;

		[JsonProperty("createdAt")]
		public string CreatedAt;

		[JsonProperty("lastLoginAt")]
		public string LastLoginAt;

		[JsonProperty("passwordUpdatedAt")]
		public string PasswordUpdatedAt;

		[Preserve]
		public UsernameInfo()
		{
		}
	}
	internal class AccessToken : BaseJwt
	{
		[JsonProperty("aud")]
		public string[] Audience;

		[JsonProperty("client_id")]
		public string ClientId;

		[JsonProperty("ext")]
		public AccessTokenExtraClaims Extra;

		[JsonProperty("iss")]
		public string Issuer;

		[JsonProperty("jti")]
		public string JwtId;

		[JsonProperty("project_id")]
		public string ProjectId;

		[JsonProperty("scp")]
		public string[] Scope;

		[JsonProperty("sub")]
		public string Subject;

		[Preserve]
		public AccessToken()
		{
		}
	}
	internal class AccessTokenExtraClaims
	{
		[Preserve]
		public AccessTokenExtraClaims()
		{
		}
	}
	internal class BaseJwt
	{
		[JsonProperty("exp")]
		public int ExpirationTimeUnix;

		[JsonProperty("iat")]
		public int IssuedAtTimeUnix;

		[JsonProperty("nbf")]
		public int NotBeforeTimeUnix;

		[JsonIgnore]
		public DateTime? ExpirationTime => ConvertTimestamp(ExpirationTimeUnix);

		[JsonIgnore]
		public DateTime? IssuedAtTime => ConvertTimestamp(IssuedAtTimeUnix);

		[JsonIgnore]
		public DateTime? NotBeforeTime => ConvertTimestamp(NotBeforeTimeUnix);

		[Preserve]
		public BaseJwt()
		{
		}

		protected DateTime? ConvertTimestamp(int timestamp)
		{
			if (timestamp != 0)
			{
				return DateTimeOffset.FromUnixTimeSeconds(timestamp).DateTime;
			}
			return null;
		}
	}
	internal class AuthenticationSettings : IAuthenticationSettings
	{
		private const int k_AccessTokenRefreshBuffer = 300;

		private const int k_AccessTokenExpiryBuffer = 15;

		private const int k_RefreshAttemptFrequency = 30;

		public int AccessTokenRefreshBuffer { get; internal set; }

		public int AccessTokenExpiryBuffer { get; internal set; }

		public int RefreshAttemptFrequency { get; internal set; }

		internal AuthenticationSettings()
		{
			AccessTokenRefreshBuffer = 300;
			AccessTokenExpiryBuffer = 15;
			RefreshAttemptFrequency = 30;
		}

		internal void Reset()
		{
			AccessTokenRefreshBuffer = 300;
			AccessTokenExpiryBuffer = 15;
			RefreshAttemptFrequency = 30;
		}
	}
	internal interface IAuthenticationSettings
	{
		int AccessTokenRefreshBuffer { get; }

		int AccessTokenExpiryBuffer { get; }

		int RefreshAttemptFrequency { get; }
	}
	internal interface INetworkConfiguration
	{
		int Retries { get; }

		int Timeout { get; }
	}
	internal class NetworkConfiguration : INetworkConfiguration
	{
		private const int k_DefaultRetries = 2;

		private const int k_DefaultTimeout = 10;

		public int Retries { get; set; } = 2;

		public int Timeout { get; set; } = 10;
	}
	public sealed class SignInOptions
	{
		public bool CreateAccount { get; set; }
	}
	internal class AuthenticationApiClient : IApiClient
	{
		private INetworkConfiguration Configuration { get; }

		public AuthenticationApiClient(INetworkConfiguration configuration)
		{
			Configuration = configuration;
		}

		public Task<ApiResponse> GetAsync(string path, ApiRequestOptions options, IApiConfiguration configuration, CancellationToken cancellationToken = default(CancellationToken))
		{
			return SendAsync(path, WebRequestVerb.Get, options, configuration, cancellationToken);
		}

		public Task<ApiResponse<T>> GetAsync<T>(string path, ApiRequestOptions options, IApiConfiguration configuration, CancellationToken cancellationToken = default(CancellationToken))
		{
			return SendAsync<T>(path, WebRequestVerb.Get, options, configuration, cancellationToken);
		}

		public Task<ApiResponse> PostAsync(string path, ApiRequestOptions options, IApiConfiguration configuration, CancellationToken cancellationToken = default(CancellationToken))
		{
			return SendAsync(path, WebRequestVerb.Post, options, configuration, cancellationToken);
		}

		public Task<ApiResponse<T>> PostAsync<T>(string path, ApiRequestOptions options, IApiConfiguration configuration, CancellationToken cancellationToken = default(CancellationToken))
		{
			return SendAsync<T>(path, WebRequestVerb.Post, options, configuration, cancellationToken);
		}

		public Task<ApiResponse> PutAsync(string path, ApiRequestOptions options, IApiConfiguration configuration, CancellationToken cancellationToken = default(CancellationToken))
		{
			return SendAsync(path, WebRequestVerb.Put, options, configuration, cancellationToken);
		}

		public Task<ApiResponse<T>> PutAsync<T>(string path, ApiRequestOptions options, IApiConfiguration configuration, CancellationToken cancellationToken = default(CancellationToken))
		{
			return SendAsync<T>(path, WebRequestVerb.Put, options, configuration, cancellationToken);
		}

		public Task<ApiResponse> DeleteAsync(string path, ApiRequestOptions options, IApiConfiguration configuration, CancellationToken cancellationToken = default(CancellationToken))
		{
			return SendAsync(path, WebRequestVerb.Delete, options, configuration, cancellationToken);
		}

		public Task<ApiResponse<T>> DeleteAsync<T>(string path, ApiRequestOptions options, IApiConfiguration configuration, CancellationToken cancellationToken = default(CancellationToken))
		{
			return SendAsync<T>(path, WebRequestVerb.Delete, options, configuration, cancellationToken);
		}

		public Task<ApiResponse> HeadAsync(string path, ApiRequestOptions options, IApiConfiguration configuration, CancellationToken cancellationToken = default(CancellationToken))
		{
			return SendAsync(path, WebRequestVerb.Head, options, configuration, cancellationToken);
		}

		public Task<ApiResponse<T>> HeadAsync<T>(string path, ApiRequestOptions options, IApiConfiguration configuration, CancellationToken cancellationToken = default(CancellationToken))
		{
			return SendAsync<T>(path, WebRequestVerb.Head, options, configuration, cancellationToken);
		}

		public Task<ApiResponse> OptionsAsync(string path, ApiRequestOptions options, IApiConfiguration configuration, CancellationToken cancellationToken = default(CancellationToken))
		{
			return SendAsync(path, WebRequestVerb.Options, options, configuration, cancellationToken);
		}

		public Task<ApiResponse<T>> OptionsAsync<T>(string path, ApiRequestOptions options, IApiConfiguration configuration, CancellationToken cancellationToken = default(CancellationToken))
		{
			return SendAsync<T>(path, WebRequestVerb.Options, options, configuration, cancellationToken);
		}

		public Task<ApiResponse> PatchAsync(string path, ApiRequestOptions options, IApiConfiguration configuration, CancellationToken cancellationToken = default(CancellationToken))
		{
			return SendAsync(path, WebRequestVerb.Patch, options, configuration, cancellationToken);
		}

		public Task<ApiResponse<T>> PatchAsync<T>(string path, ApiRequestOptions options, IApiConfiguration configuration, CancellationToken cancellationToken = default(CancellationToken))
		{
			return SendAsync<T>(path, WebRequestVerb.Patch, options, configuration, cancellationToken);
		}

		private async Task<ApiResponse> SendAsync(string path, WebRequestVerb method, ApiRequestOptions options, IApiConfiguration configuration, CancellationToken cancellationToken = default(CancellationToken))
		{
			int attempts = 0;
			bool flag;
			do
			{
				try
				{
					UnityWebRequest request = BuildWebRequest(path, method, options, configuration);
					try
					{
						return await request.SendWebRequestAsync();
					}
					finally
					{
						((IDisposable)request)?.Dispose();
					}
				}
				catch (ApiException ex)
				{
					flag = ex.Type == ApiExceptionType.Network;
					attempts++;
					if (attempts >= Configuration.Retries || !flag)
					{
						throw;
					}
				}
			}
			while (flag);
			return null;
		}

		private async Task<ApiResponse<T>> SendAsync<T>(string path, WebRequestVerb method, ApiRequestOptions options, IApiConfiguration configuration, CancellationToken cancellationToken = default(CancellationToken))
		{
			int attempts = 0;
			bool flag;
			do
			{
				try
				{
					UnityWebRequest request = BuildWebRequest(path, method, options, configuration);
					try
					{
						return await request.SendWebRequestAsync<T>(cancellationToken);
					}
					finally
					{
						((IDisposable)request)?.Dispose();
					}
				}
				catch (ApiException ex)
				{
					flag = ex.Type == ApiExceptionType.Network;
					if (attempts >= Configuration.Retries || !flag)
					{
						throw;
					}
					attempts++;
				}
			}
			while (flag);
			return null;
		}

		internal UnityWebRequest BuildWebRequest(string path, WebRequestVerb method, ApiRequestOptions options, IApiConfiguration configuration)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Expected O, but got Unknown
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Expected O, but got Unknown
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Expected O, but got Unknown
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Expected O, but got Unknown
			ApiRequestPathBuilder apiRequestPathBuilder = new ApiRequestPathBuilder(configuration.BasePath, path);
			apiRequestPathBuilder.AddPathParameters(options.PathParameters);
			apiRequestPathBuilder.AddQueryParameters(options.QueryParameters);
			UnityWebRequest val = new UnityWebRequest(apiRequestPathBuilder.GetFullUri(), method.ToString());
			if (configuration.UserAgent != null)
			{
				val.SetRequestHeader("User-Agent", configuration.UserAgent);
			}
			if (configuration.DefaultHeaders != null)
			{
				foreach (KeyValuePair<string, string> defaultHeader in configuration.DefaultHeaders)
				{
					val.SetRequestHeader(defaultHeader.Key, defaultHeader.Value);
				}
			}
			if (options.HeaderParameters != null)
			{
				foreach (KeyValuePair<string, IList<string>> headerParameter in options.HeaderParameters)
				{
					foreach (string item in headerParameter.Value)
					{
						val.SetRequestHeader(headerParameter.Key, item);
					}
				}
			}
			val.timeout = configuration.Timeout;
			if (options.Data != null)
			{
				JsonSerializerSettings settings = new JsonSerializerSettings
				{
					ReferenceLoopHandling = (ReferenceLoopHandling)1
				};
				string s = IsolatedJsonConvert.SerializeObject(options.Data, settings);
				val.uploadHandler = (UploadHandler)new UploadHandlerRaw(Encoding.UTF8.GetBytes(s));
			}
			val.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
			return val;
		}
	}
	internal class AuthenticationNetworkClient : IAuthenticationNetworkClient
	{
		private const string k_AnonymousUrlStem = "/v1/authentication/anonymous";

		private const string k_SessionTokenUrlStem = "/v1/authentication/session-token";

		private const string k_ExternalTokenUrlStem = "/v1/authentication/external-token";

		private const string k_LinkExternalTokenUrlStem = "/v1/authentication/link";

		private const string k_UnlinkExternalTokenUrlStem = "/v1/authentication/unlink";

		private const string k_UsersUrlStem = "/v1/users";

		private const string k_UsernamePasswordSignInUrlStem = "/v1/authentication/usernamepassword/sign-in";

		private const string k_UsernamePasswordSignUpUrlStem = "/v1/authentication/usernamepassword/sign-up";

		private const string k_UpdatePasswordUrlStem = "/v1/authentication/usernamepassword/update-password";

		private readonly string m_AnonymousUrl;

		private readonly string m_SessionTokenUrl;

		private readonly string m_ExternalTokenUrl;

		private readonly string m_LinkExternalTokenUrl;

		private readonly string m_UnlinkExternalTokenUrl;

		private readonly string m_UsersUrl;

		private readonly string m_UsernamePasswordSignInUrl;

		private readonly string m_UsernamePasswordSignUpUrl;

		private readonly string m_UpdatePasswordUrl;

		private readonly Dictionary<string, string> m_CommonHeaders;

		internal AccessTokenComponent AccessTokenComponent { get; }

		internal ICloudProjectId CloudProjectIdComponent { get; }

		internal IEnvironments EnvironmentComponent { get; }

		internal INetworkHandler NetworkHandler { get; }

		private string AccessToken => AccessTokenComponent.AccessToken;

		private string EnvironmentName => EnvironmentComponent.Current;

		internal AuthenticationNetworkClient(string host, ICloudProjectId cloudProjectId, IEnvironments environment, INetworkHandler networkHandler, AccessTokenComponent accessToken)
		{
			AccessTokenComponent = accessToken;
			CloudProjectIdComponent = cloudProjectId;
			EnvironmentComponent = environment;
			NetworkHandler = networkHandler;
			m_AnonymousUrl = host + "/v1/authentication/anonymous";
			m_SessionTokenUrl = host + "/v1/authentication/session-token";
			m_ExternalTokenUrl = host + "/v1/authentication/external-token";
			m_LinkExternalTokenUrl = host + "/v1/authentication/link";
			m_UnlinkExternalTokenUrl = host + "/v1/authentication/unlink";
			m_UsersUrl = host + "/v1/users";
			m_UsernamePasswordSignInUrl = host + "/v1/authentication/usernamepassword/sign-in";
			m_UsernamePasswordSignUpUrl = host + "/v1/authentication/usernamepassword/sign-up";
			m_UpdatePasswordUrl = host + "/v1/authentication/usernamepassword/update-password";
			m_CommonHeaders = new Dictionary<string, string>
			{
				["ProjectId"] = CloudProjectIdComponent.GetCloudProjectId(),
				["Error-Version"] = "v1"
			};
		}

		public Task<SignInResponse> SignInAnonymouslyAsync()
		{
			return NetworkHandler.PostAsync<SignInResponse>(m_AnonymousUrl, WithEnvironment(GetCommonHeaders()));
		}

		public Task<SignInResponse> SignInWithSessionTokenAsync(string token)
		{
			return NetworkHandler.PostAsync<SignInResponse>(m_SessionTokenUrl, new SessionTokenRequest
			{
				SessionToken = token
			}, WithEnvironment(GetCommonHeaders()));
		}

		public Task<SignInResponse> SignInWithExternalTokenAsync(string idProvider, SignInWithExternalTokenRequest externalToken)
		{
			string url = m_ExternalTokenUrl + "/" + idProvider;
			return NetworkHandler.PostAsync<SignInResponse>(url, externalToken, WithEnvironment(GetCommonHeaders()));
		}

		public Task<LinkResponse> LinkWithExternalTokenAsync(string idProvider, LinkWithExternalTokenRequest externalToken)
		{
			string url = m_LinkExternalTokenUrl + "/" + idProvider;
			return NetworkHandler.PostAsync<LinkResponse>(url, externalToken, WithEnvironment(WithAccessToken(GetCommonHeaders())));
		}

		public Task<UnlinkResponse> UnlinkExternalTokenAsync(string idProvider, UnlinkRequest request)
		{
			string url = m_UnlinkExternalTokenUrl + "/" + idProvider;
			return NetworkHandler.PostAsync<UnlinkResponse>(url, request, WithEnvironment(WithAccessToken(GetCommonHeaders())));
		}

		public Task<PlayerInfoResponse> GetPlayerInfoAsync(string playerId)
		{
			return NetworkHandler.GetAsync<PlayerInfoResponse>(CreateUserRequestUrl(playerId), WithAccessToken(GetCommonHeaders()));
		}

		public Task DeleteAccountAsync(string playerId)
		{
			return NetworkHandler.DeleteAsync(CreateUserRequestUrl(playerId), WithEnvironment(WithAccessToken(GetCommonHeaders())));
		}

		public Task<SignInResponse> SignInWithUsernamePasswordAsync(UsernamePasswordRequest credentials)
		{
			return NetworkHandler.PostAsync<SignInResponse>(m_UsernamePasswordSignInUrl, credentials, WithEnvironment(GetCommonHeaders()));
		}

		public Task<SignInResponse> SignUpWithUsernamePasswordAsync(UsernamePasswordRequest credentials)
		{
			return NetworkHandler.PostAsync<SignInResponse>(m_UsernamePasswordSignUpUrl, credentials, WithEnvironment(GetCommonHeaders()));
		}

		public Task<SignInResponse> AddUsernamePasswordAsync(UsernamePasswordRequest credentials)
		{
			return NetworkHandler.PostAsync<SignInResponse>(m_UsernamePasswordSignUpUrl, credentials, WithEnvironment(WithAccessToken(GetCommonHeaders())));
		}

		public Task<SignInResponse> UpdatePasswordAsync(UpdatePasswordRequest credentials)
		{
			return NetworkHandler.PostAsync<SignInResponse>(m_UpdatePasswordUrl, credentials, WithEnvironment(WithAccessToken(GetCommonHeaders())));
		}

		private string CreateUserRequestUrl(string user)
		{
			return m_UsersUrl + "/" + user;
		}

		private Dictionary<string, string> WithAccessToken(Dictionary<string, string> headers)
		{
			headers["Authorization"] = "Bearer " + AccessToken;
			return headers;
		}

		private Dictionary<string, string> WithEnvironment(Dictionary<string, string> headers)
		{
			string environmentName = EnvironmentName;
			if (!string.IsNullOrEmpty(environmentName))
			{
				headers["UnityEnvironment"] = environmentName;
			}
			return headers;
		}

		private Dictionary<string, string> GetCommonHeaders()
		{
			return new Dictionary<string, string>(m_CommonHeaders);
		}
	}
	internal static class AuthenticationWebRequestUtils
	{
		public static Task<ApiResponse> SendWebRequestAsync(this UnityWebRequest request)
		{
			TaskCompletionSource<ApiResponse> tcs = new TaskCompletionSource<ApiResponse>();
			UnityWebRequestAsyncOperation val = request.SendWebRequest();
			if (((AsyncOperation)val).isDone)
			{
				ProcessResponse(tcs, request);
			}
			else
			{
				((AsyncOperation)val).completed += delegate
				{
					ProcessResponse(tcs, request);
				};
			}
			return tcs.Task;
		}

		public static Task<ApiResponse<T>> SendWebRequestAsync<T>(this UnityWebRequest request, CancellationToken cancellationToken)
		{
			TaskCompletionSource<ApiResponse<T>> tcs = new TaskCompletionSource<ApiResponse<T>>();
			cancellationToken.Register(delegate
			{
				tcs.SetCanceled();
			});
			UnityWebRequestAsyncOperation val = request.SendWebRequest();
			if (((AsyncOperation)val).isDone)
			{
				ProcessResponse(tcs, request);
			}
			else
			{
				((AsyncOperation)val).completed += delegate
				{
					ProcessResponse(tcs, request);
				};
			}
			return tcs.Task;
		}

		private static void ProcessResponse(TaskCompletionSource<ApiResponse> tcs, UnityWebRequest request)
		{
			ApiResponse obj = new ApiResponse
			{
				StatusCode = (int)request.responseCode,
				ErrorText = request.error
			};
			DownloadHandler downloadHandler = request.downloadHandler;
			obj.RawContent = ((downloadHandler != null) ? downloadHandler.text : null);
			ApiResponse apiResponse = obj;
			string error = request.error;
			DownloadHandler downloadHandler2 = request.downloadHandler;
			string message = error + "\n" + ((downloadHandler2 != null) ? downloadHandler2.text : null);
			if (IsNetworkError(request))
			{
				tcs.SetException(new ApiException(ApiExceptionType.Network, message, apiResponse));
			}
			else if (IsHttpError(request))
			{
				tcs.SetException(new ApiException(ApiExceptionType.Http, message, apiResponse));
			}
			else
			{
				tcs.SetResult(apiResponse);
			}
		}

		private static void ProcessResponse<T>(TaskCompletionSource<ApiResponse<T>> tcs, UnityWebRequest request)
		{
			ApiResponse<T> obj = new ApiResponse<T>
			{
				StatusCode = (int)request.responseCode,
				ErrorText = request.error
			};
			DownloadHandler downloadHandler = request.downloadHandler;
			obj.RawContent = ((downloadHandler != null) ? downloadHandler.text : null);
			ApiResponse<T> apiResponse = obj;
			string error = request.error;
			DownloadHandler downloadHandler2 = request.downloadHandler;
			string message = error + "\n" + ((downloadHandler2 != null) ? downloadHandler2.text : null);
			if (IsNetworkError(request))
			{
				tcs.SetException(new ApiException(ApiExceptionType.Network, message, apiResponse));
				return;
			}
			if (IsHttpError(request))
			{
				tcs.SetException(new ApiException(ApiExceptionType.Http, message, apiResponse));
				return;
			}
			try
			{
				DownloadHandler downloadHandler3 = request.downloadHandler;
				if (!string.IsNullOrEmpty((downloadHandler3 != null) ? downloadHandler3.text : null))
				{
					DownloadHandler downloadHandler4 = request.downloadHandler;
					apiResponse.Data = IsolatedJsonConvert.DeserializeObject<T>((downloadHandler4 != null) ? downloadHandler4.text : null, SerializerSettings.DefaultSerializerSettings);
				}
			}
			catch (Exception)
			{
				tcs.SetException(new ApiException(ApiExceptionType.Deserialization, $"Deserialization of type '{typeof(T)}' failed.", apiResponse));
				return;
			}
			tcs.SetResult(apiResponse);
		}

		public static bool IsNetworkError(UnityWebRequest request)
		{
			return request.responseCode >= 500;
		}

		public static bool IsHttpError(UnityWebRequest request)
		{
			if (request.responseCode >= 400)
			{
				return request.responseCode < 500;
			}
			return false;
		}
	}
	internal static class HttpUtilities
	{
		public static IDictionary<string, string> ParseQueryString(string queryString)
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			string[] array = queryString.Split('?', '&');
			foreach (string text in array)
			{
				int num = text.IndexOf('=');
				if (num >= 0)
				{
					string key = UnescapeUrlString(text.Substring(0, num));
					string value = UnescapeUrlString(text.Substring(num + 1));
					dictionary[key] = value;
				}
			}
			return dictionary;
		}

		public static string EncodeQueryString(IDictionary<string, string> queryParams)
		{
			StringBuilder stringBuilder = new StringBuilder();
			bool flag = true;
			foreach (KeyValuePair<string, string> queryParam in queryParams)
			{
				if (!flag)
				{
					stringBuilder.Append('&');
				}
				else
				{
					flag = false;
				}
				stringBuilder.Append(EscapeUrlString(queryParam.Key)).Append('=').Append(EscapeUrlString(queryParam.Value));
			}
			return stringBuilder.ToString();
		}

		private static string EscapeUrlString(string rawString)
		{
			return Uri.EscapeDataString(rawString);
		}

		private static string UnescapeUrlString(string urlString)
		{
			return Uri.UnescapeDataString(urlString);
		}
	}
	internal interface IAuthenticationNetworkClient
	{
		Task<SignInResponse> SignInAnonymouslyAsync();

		Task<SignInResponse> SignInWithSessionTokenAsync(string token);

		Task<SignInResponse> SignInWithExternalTokenAsync(string idProvider, SignInWithExternalTokenRequest externalToken);

		Task<LinkResponse> LinkWithExternalTokenAsync(string idProvider, LinkWithExternalTokenRequest externalToken);

		Task<UnlinkResponse> UnlinkExternalTokenAsync(string idProvider, UnlinkRequest request);

		Task<PlayerInfoResponse> GetPlayerInfoAsync(string playerId);

		Task DeleteAccountAsync(string playerId);

		Task<SignInResponse> SignInWithUsernamePasswordAsync(UsernamePasswordRequest credentials);

		Task<SignInResponse> SignUpWithUsernamePasswordAsync(UsernamePasswordRequest credentials);

		Task<SignInResponse> AddUsernamePasswordAsync(UsernamePasswordRequest credentials);

		Task<SignInResponse> UpdatePasswordAsync(UpdatePasswordRequest credentials);
	}
	internal interface INetworkHandler
	{
		Task<T> GetAsync<T>(string url, IDictionary<string, string> headers = null);

		Task<T> PostAsync<T>(string url, IDictionary<string, string> headers = null);

		Task<T> PostAsync<T>(string url, object payload, IDictionary<string, string> headers = null);

		Task<T> PutAsync<T>(string url, object payload, IDictionary<string, string> headers = null);

		Task DeleteAsync(string url, IDictionary<string, string> headers = null);

		Task<T> DeleteAsync<T>(string url, IDictionary<string, string> headers = null);
	}
	internal class NetworkHandler : INetworkHandler
	{
		public static class ContentType
		{
			public const string Json = "application/json";
		}

		private INetworkConfiguration Configuration { get; }

		public NetworkHandler(INetworkConfiguration configuration)
		{
			Configuration = configuration;
		}

		public Task<T> GetAsync<T>(string url, IDictionary<string, string> headers = null)
		{
			return new WebRequest(Configuration, WebRequestVerb.Get, url, headers, null, "application/json").SendAsync<T>();
		}

		public Task<T> PostAsync<T>(string url, IDictionary<string, string> headers = null)
		{
			return new WebRequest(Configuration, WebRequestVerb.Post, url, headers, null, "application/json").SendAsync<T>();
		}

		public Task<T> PostAsync<T>(string url, object payload, IDictionary<string, string> headers = null)
		{
			string payload2 = ((payload != null) ? IsolatedJsonConvert.SerializeObject(payload, SerializerSettings.DefaultSerializerSettings) : null);
			return new WebRequest(Configuration, WebRequestVerb.Post, url, headers, payload2, "application/json").SendAsync<T>();
		}

		public Task<T> PutAsync<T>(string url, object payload, IDictionary<string, string> headers = null)
		{
			string payload2 = ((payload != null) ? IsolatedJsonConvert.SerializeObject(payload, SerializerSettings.DefaultSerializerSettings) : null);
			return new WebRequest(Configuration, WebRequestVerb.Put, url, headers, payload2, "application/json").SendAsync<T>();
		}

		public Task DeleteAsync(string url, IDictionary<string, string> headers = null)
		{
			return new WebRequest(Configuration, WebRequestVerb.Delete, url, headers, null, "application/json").SendAsync();
		}

		public Task<T> DeleteAsync<T>(string url, IDictionary<string, string> headers = null)
		{
			return new WebRequest(Configuration, WebRequestVerb.Delete, url, headers, null, "application/json").SendAsync<T>();
		}
	}
	internal class WebRequest
	{
		private readonly WebRequestVerb m_Verb;

		private readonly string m_Url;

		private readonly IDictionary<string, string> m_Headers;

		private readonly string m_Payload;

		private readonly string m_PayloadContentType;

		private readonly JsonSerializerSettings m_JsonSerializerSettings = new JsonSerializerSettings
		{
			NullValueHandling = (NullValueHandling)1
		};

		internal INetworkConfiguration Configuration { get; }

		internal int Retries { get; private set; }

		internal WebRequest(INetworkConfiguration configuration, WebRequestVerb verb, string url, IDictionary<string, string> headers, string payload, string payloadContentType)
		{
			//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_0012: Expected O, but got Unknown
			Configuration = configuration;
			m_Verb = verb;
			m_Url = url;
			m_Headers = headers;
			m_Payload = payload;
			m_PayloadContentType = payloadContentType;
		}

		internal Task SendAsync()
		{
			return SendAttemptAsync(new TaskCompletionSource<string>());
		}

		internal async Task<T> SendAsync<T>()
		{
			string value = await SendAttemptAsync(new TaskCompletionSource<string>());
			if (string.IsNullOrEmpty(value))
			{
				return default(T);
			}
			try
			{
				return IsolatedJsonConvert.DeserializeObject<T>(value, m_JsonSerializerSettings);
			}
			catch (Exception ex)
			{
				string text = "Failed to deserialize object!";
				Logger.Log(text + " " + ex.Message);
				throw new WebRequestException(isNetworkError: false, isServerError: false, isDeserializationError: true, 0L, text);
			}
		}

		private Task<string> SendAttemptAsync(TaskCompletionSource<string> tcs)
		{
			try
			{
				UnityWebRequest request = Build();
				((AsyncOperation)request.SendWebRequest()).completed += delegate
				{
					WebRequest webRequest = this;
					TaskCompletionSource<string> tcs2 = tcs;
					long responseCode = request.responseCode;
					bool isNetworkError = RequestHasNetworkError(request);
					bool isServerError = RequestHasServerError(request);
					string error = request.error;
					DownloadHandler downloadHandler = request.downloadHandler;
					webRequest.RequestCompleted(tcs2, responseCode, isNetworkError, isServerError, error, (downloadHandler != null) ? downloadHandler.text : null, request.GetResponseHeaders());
					request.Dispose();
				};
			}
			catch (Exception exception)
			{
				tcs.SetException(exception);
			}
			return tcs.Task;
		}

		internal UnityWebRequest Build()
		{
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Expected O, but got Unknown
			//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_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Expected O, but got Unknown
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Expected O, but got Unknown
			//IL_0088: Expected O, but got Unknown
			//IL_00c1: 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_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Expected O, but got Unknown
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Expected O, but got Unknown
			//IL_00ed: Expected O, but got Unknown
			UnityWebRequest val;
			switch (m_Verb)
			{
			case WebRequestVerb.Post:
				val = (UnityWebRequest)((!string.IsNullOrEmpty(m_Payload)) ? ((object)new UnityWebRequest(m_Url, "POST")
				{
					uploadHandler = (UploadHandler)new UploadHandlerRaw(Encoding.UTF8.GetBytes(m_Payload)),
					downloadHandler = (DownloadHandler)new DownloadHandlerBuffer()
				}) : ((object)UnityWebRequest.Post(m_Url, string.Empty)));
				break;
			case WebRequestVerb.Get:
				val = UnityWebRequest.Get(m_Url);
				break;
			case WebRequestVerb.Put:
				if (string.IsNullOrEmpty(m_Payload))
				{
					throw new ArgumentException("PUT payload cannot be empty.");
				}
				val = new UnityWebRequest(m_Url, "PUT")
				{
					uploadHandler = (UploadHandler)new UploadHandlerRaw(Encoding.UTF8.GetBytes(m_Payload)),
					downloadHandler = (DownloadHandler)new DownloadHandlerBuffer()
				};
				break;
			case WebRequestVerb.Delete:
				val = UnityWebRequest.Delete(m_Url);
				val.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
				break;
			default:
				throw new ArgumentException("Unknown verb " + m_Verb);
			}
			if (!string.IsNullOrEmpty(m_PayloadContentType))
			{
				val.SetRequestHeader("Content-Type", m_PayloadContentType);
			}
			if (m_Headers != null)
			{
				foreach (KeyValuePair<string, string> header in m_Headers)
				{
					val.SetRequestHeader(header.Key, header.Value);
				}
			}
			val.timeout = Configuration.Timeout;
			return val;
		}

		internal void RequestCompleted(TaskCompletionSource<string> tcs, long responseCode, bool isNetworkError, bool isServerError, string errorText, string bodyText, IDictionary<string, string> headers)
		{
			if (isNetworkError && Retries < Configuration.Retries)
			{
				Logger.LogWarning("Network error detected, retrying...");
				Retries++;
				SendAttemptAsync(tcs);
			}
			else if (isNetworkError || isServerError)
			{
				string text = ((isServerError && !string.IsNullOrEmpty(bodyText)) ? bodyText : errorText);
				WebRequestException exception = new WebRequestException(isNetworkError, isServerError, isDeserializationError: false, responseCode, text, headers);
				tcs.SetException(exception);
				Logger.LogWarning("Request completed with error: " + text);
			}
			else
			{
				tcs.SetResult(bodyText);
			}
		}

		private bool RequestHasServerError(UnityWebRequest request)
		{
			return request.responseCode >= 400;
		}

		private bool RequestHasNetworkError(UnityWebRequest request)
		{
			if (request.isNetworkError)
			{
				return request.error != "Redirect limit exceeded";
			}
			return false;
		}
	}
	internal class WebRequestException : Exception
	{
		public bool NetworkError { get; private set; }

		public bool DeserializationError { get; private set; }

		public bool ServerError { get; private set; }

		public long ResponseCode { get; private set; }

		public IDictionary<string, string> ResponseHeaders { get; private set; }

		internal WebRequestException(bool isNetworkError, bool isServerError, bool isDeserializationError, long responseCode, string errorMessage, IDictionary<string, string> responseHeaders = null)
			: base(errorMessage)
		{
			NetworkError = isNetworkError;
			ServerError = isServerError;
			DeserializationError = isDeserializationError;
			ResponseCode = responseCode;
			ResponseHeaders = responseHeaders;
		}
	}
	internal enum WebRequestVerb
	{
		Delete,
		Get,
		Head,
		Options,
		Patch,
		Post,
		Put
	}
	internal class AuthenticationCache : IAuthenticationCache, ICache
	{
		private ICloudProjectId m_CloudProjectId;

		private IProfile m_Profile;

		public string CloudProjectId => m_CloudProjectId.GetCloudProjectId();

		public string Profile => m_Profile.Current;

		private string Prefix => CloudProjectId + "." + Profile + ".unity.services.authentication.";

		private string OldPrefix => "unity.services.authentication.";

		public AuthenticationCache(ICloudProjectId cloudProjectId, IProfile profile)
		{
			m_CloudProjectId = cloudProjectId;
			m_Profile = profile;
		}

		public bool HasKey(string key)
		{
			return PlayerPrefs.HasKey(GetKey(key));
		}

		public void DeleteKey(string key)
		{
			PlayerPrefs.DeleteKey(GetKey(key));
		}

		[CanBeNull]
		public string GetString(string key)
		{
			if (!HasKey(key))
			{
				return null;
			}
			return PlayerPrefs.GetString(GetKey(key));
		}

		public void SetString(string key, string value)
		{
			PlayerPrefs.SetString(GetKey(key), value);
			PlayerPrefs.Save();
		}

		public void Migrate(string key)
		{
			string oldKey = GetOldKey(key);
			if (PlayerPrefs.HasKey(oldKey))
			{
				PlayerPrefs.SetString(GetKey(key), PlayerPrefs.GetString(oldKey));
				PlayerPrefs.DeleteKey(oldKey);
			}
		}

		internal string GetKey(string key)
		{
			return Prefix + key;
		}

		internal string GetOldKey(string key)
		{
			return OldPrefix + key;
		}
	}
	internal interface IAuthenticationCache : ICache
	{
		string Profile { get; }

		string CloudProjectId { get; }

		void Migrate(string key);
	}
	internal interface ICache
	{
		bool HasKey(string key);

		void DeleteKey(string key);

		void SetString(string key, string value);

		string GetString(string key);
	}
	internal static class IdProviderKeys
	{
		internal const string Apple = "apple.com";

		internal const string Facebook = "facebook.com";

		internal const string AppleGameCenter = "apple-game-center";

		internal const string Google = "google.com";

		internal const string GooglePlayGames = "google-play-games";

		internal const string Oculus = "oculus";

		internal const string OpenIDConnect = "oidc-";

		internal const string Steam = "steampowered.com";

		internal const string UsernamePassword = "usernamepassword";

		internal const string Unity = "unity";
	}
	internal static class IsolatedJsonConvert
	{
		[DebuggerStepThrough]
		public static string SerializeObject(object value)
		{
			return SerializeObject(value, (Type)null, (JsonSerializerSettings)null);
		}

		[DebuggerStepThrough]
		public static string SerializeObject(object value, Formatting formatting)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			return SerializeObject(value, formatting, (JsonSerializerSettings)null);
		}

		[DebuggerStepThrough]
		public static string SerializeObject(object value, params JsonConverter[] converters)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected O, but got Unknown
			JsonSerializerSettings val = ((converters != null && converters.Length != 0) ? new JsonSerializerSettings
			{
				Converters = converters
			} : ((JsonSerializerSettings)null));
			JsonSerializerSettings settings = val;
			return SerializeObject(value, (Type)null, settings);
		}

		[DebuggerStepThrough]
		public static string SerializeObject(object value, Formatting formatting, p

BepInEx/plugins/Unity.Services.QoS.dll

Decompiled 13 hours 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.Net.Sockets;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using Newtonsoft.Json.Utilities;
using Unity.Collections;
using Unity.Jobs;
using Unity.Networking.QoS;
using Unity.Services.Authentication.Internal;
using Unity.Services.Core.Configuration.Internal;
using Unity.Services.Core.Internal;
using Unity.Services.Core.Telemetry.Internal;
using Unity.Services.Qos;
using Unity.Services.Qos.Apis.QosDiscovery;
using Unity.Services.Qos.Http;
using Unity.Services.Qos.Internal;
using Unity.Services.Qos.Models;
using Unity.Services.Qos.QosDiscovery;
using Unity.Services.Qos.Runner;
using Unity.Services.Qos.Scheduler;
using Unity.Services.Qos.V2;
using Unity.Services.Qos.V2.Apis.QosDiscovery;
using Unity.Services.Qos.V2.Http;
using Unity.Services.Qos.V2.Models;
using Unity.Services.Qos.V2.QosDiscovery;
using Unity.Services.Qos.V2.Scheduler;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.Scripting;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AlwaysLinkAssembly]
[assembly: InternalsVisibleTo("Unity.Services.Qos.Tests")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Unity.Services.QoS")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("Unity.Services.QoS")]
[assembly: AssemblyTitle("Unity.Services.QoS")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
}
namespace Unity.Networking.QoS
{
	internal struct InternalQosResult
	{
		internal const uint InvalidLatencyValue = uint.MaxValue;

		internal const float InvalidPacketLossValue = float.MaxValue;

		internal uint RequestsSent;

		internal uint ResponsesReceived;

		internal uint InvalidRequests;

		internal uint InvalidResponses;

		internal uint DuplicateResponses;

		internal FcType FcType;

		internal byte FcUnits;

		internal uint AggregateLatencyMs;

		internal uint AverageLatencyMs
		{
			get
			{
				if (ResponsesReceived == 0)
				{
					return uint.MaxValue;
				}
				return AggregateLatencyMs / ResponsesReceived;
			}
		}

		internal float PacketLoss
		{
			get
			{
				if (RequestsSent != 0 && ResponsesReceived <= RequestsSent)
				{
					return 1f - (float)ResponsesReceived / (float)RequestsSent;
				}
				return float.MaxValue;
			}
		}

		internal void AddAggregateLatency(uint amountMs)
		{
			AggregateLatencyMs += amountMs;
		}
	}
	internal struct QosJob : IQosJob, IJob
	{
		private struct InternalQosServer
		{
			public readonly NetworkEndPoint RemoteEndpoint;

			public readonly DateTime BackoffUntilUtc;

			public readonly int Idx;

			private int m_FirstIdx;

			private ushort m_RequestIdentifier;

			public int FirstIdx
			{
				get
				{
					return m_FirstIdx;
				}
				set
				{
					m_FirstIdx = value;
				}
			}

			public ushort RequestIdentifier
			{
				get
				{
					return m_RequestIdentifier;
				}
				set
				{
					m_RequestIdentifier = value;
				}
			}

			public bool Duplicate => m_FirstIdx != Idx;

			public string Address => RemoteEndpoint.Address;

			public InternalQosServer(NetworkEndPoint remote, DateTime backoffUntilUtc, int idx)
			{
				RemoteEndpoint = remote;
				BackoffUntilUtc = backoffUntilUtc;
				Idx = idx;
				m_FirstIdx = idx;
				m_RequestIdentifier = 0;
			}
		}

		public NativeArray<InternalQosResult> QosResults { get; }

		internal QosJob(IList<UcgQosServer> qosServers, string title)
		{
			this = default(QosJob);
			throw new NotImplementedException();
		}

		public void Execute()
		{
			throw new NotImplementedException();
		}

		public JobHandle Schedule<T>(JobHandle dependsOn = default(JobHandle)) where T : struct, IJob
		{
			throw new NotImplementedException();
		}

		public void Dispose()
		{
			throw new NotImplementedException();
		}
	}
	internal enum NetworkFamily
	{
		Invalid = 0,
		Ipv4 = 2,
		Ipv6 = 23
	}
	internal struct NetworkEndPoint
	{
		internal string Address
		{
			get
			{
				throw new NotImplementedException();
			}
		}
	}
	internal static class QosHelper
	{
		private const ulong WSAEWOULDBLOCK = 10035uL;

		private const ulong WSAETIMEDOUT = 10060uL;

		private const ulong EAGAIN_EWOULDBLOCK_1 = 11uL;

		private const ulong EAGAIN_EWOULDBLOCK_2 = 35uL;

		internal static bool WouldBlock(ulong errorcode)
		{
			if (errorcode != 10035 && errorcode != 10060 && errorcode != 11)
			{
				return errorcode == 35;
			}
			return true;
		}

		internal static bool ExpiredUtc(DateTime timeUtc)
		{
			return DateTime.UtcNow > timeUtc;
		}

		internal static string Since(DateTime dt)
		{
			return $"{(DateTime.UtcNow - dt).TotalMilliseconds:F0}ms";
		}
	}
	internal class QosRequest
	{
		private const int MinPacketLen = 15;

		private const int MaxPacketLen = 1500;

		private const byte RequestMagic = 89;

		private const int ConstructedPacketLen = 14;

		private byte m_Magic = 89;

		private byte m_VerAndFlow;

		private byte m_TitleLen;

		private byte[] m_Title;

		private byte m_Sequence;

		private ushort m_Identifier;

		private ulong m_Timestamp;

		private ushort m_PacketLength = 14;

		internal byte Magic => m_Magic;

		internal byte Version => (byte)((m_VerAndFlow >> 4) & 0xF);

		internal byte FlowControl => (byte)(m_VerAndFlow & 0xF);

		internal byte[] Title
		{
			get
			{
				return m_Title;
			}
			set
			{
				if (15 + value.Length > 1500)
				{
					throw new ArgumentException($"Encoded title would make the QosPacket have size {15 + value.Length}. Max size is {1500}.");
				}
				m_Title = value;
				m_TitleLen = (byte)(m_Title.Length + 1);
				m_PacketLength = (ushort)(14 + m_Title.Length);
			}
		}

		internal byte Sequence
		{
			get
			{
				return m_Sequence;
			}
			set
			{
				m_Sequence = value;
			}
		}

		internal ushort Identifier
		{
			get
			{
				return m_Identifier;
			}
			set
			{
				m_Identifier = value;
			}
		}

		internal ulong Timestamp
		{
			get
			{
				return m_Timestamp;
			}
			set
			{
				m_Timestamp = value;
			}
		}

		internal int Length => m_PacketLength;

		internal (uint, int) Send(IntPtr socketHandle, NetworkEndPoint endPoint, DateTime expireTimeUtc)
		{
			throw new NotImplementedException();
		}
	}
	internal enum FcType
	{
		None,
		Throttle,
		Ban
	}
	internal class QosResponse
	{
		private const int MinPacketLen = 13;

		private const int MaxPacketLen = 1500;

		private const byte ResponseMagic = 149;

		private const byte ResponseVersion = 0;

		private byte m_Magic;

		private byte m_VerAndFlow;

		private byte m_Sequence;

		private ushort m_Identifier;

		private ulong m_Timestamp;

		private int m_LatencyMs;

		private ushort m_PacketLength;

		internal byte Magic => m_Magic;

		internal byte Version => (byte)((m_VerAndFlow >> 4) & 0xF);

		internal byte FlowControl => (byte)(m_VerAndFlow & 0xF);

		internal byte Sequence => m_Sequence;

		internal ushort Identifier => m_Identifier;

		internal ulong Timestamp => m_Timestamp;

		internal ushort Length => m_PacketLength;

		internal int LatencyMs => m_LatencyMs;

		internal (int received, int errorCode) Recv(IntPtr socketHandle, bool wait, DateTime expireTimeUtc, ref NetworkEndPoint endPoint)
		{
			throw new NotImplementedException();
		}

		internal void Deserialize(IntPtr msgData)
		{
			throw new NotImplementedException();
		}

		internal bool Verify(uint maxSequence, ref string error)
		{
			if (Length < 13)
			{
				error = $"response is too small got {Length} bytes min expected {13} bytes";
				return false;
			}
			if (Magic != 149)
			{
				error = $"response contains an invalid signature 0x{Magic:X} expected 0x{(byte)149:X}";
				return false;
			}
			if (Version != 0)
			{
				error = $"response contains an invalid version {Version} expected {(byte)0}";
				return false;
			}
			if (Sequence > maxSequence)
			{
				error = $"response contains an invalid sequence {Sequence} max expected {maxSequence}";
				return false;
			}
			return true;
		}

		internal (FcType type, byte units) ParseFlowControl()
		{
			if (FlowControl == 0)
			{
				return (type: FcType.None, units: 0);
			}
			int num = (((FlowControl & 8) == 0) ? 1 : 2);
			byte b = (byte)(FlowControl & 7);
			if (num == 2)
			{
				b++;
			}
			return (type: (FcType)num, units: b);
		}
	}
	[Serializable]
	internal struct UcgQosServer
	{
		internal string regionid;

		internal string ipv4;

		internal string ipv6;

		internal ushort port;

		[NonSerialized]
		[HideInInspector]
		internal DateTime BackoffUntilUtc;

		public override string ToString()
		{
			if (!string.IsNullOrEmpty(ipv6))
			{
				return $"[{ipv6}]:{port}, {regionid}, {BackoffUntilUtc}";
			}
			if (!string.IsNullOrEmpty(ipv4))
			{
				return $"{ipv4}:{port}, {regionid}, {BackoffUntilUtc}";
			}
			return "";
		}
	}
}
namespace Unity.Services.Core
{
	public static class UnityServicesExtensions
	{
		public static IQosService GetQosService(this IUnityServices unityServices)
		{
			return unityServices.GetService<IQosService>();
		}
	}
}
namespace Unity.Services.Qos
{
	internal class Configuration
	{
		public string BasePath;

		public int? RequestTimeout;

		public int? NumberOfRetries;

		public IDictionary<string, string> Headers;

		public Configuration(string basePath, int? requestTimeout, int? numRetries, IDictionary<string, string> headers)
		{
			BasePath = basePath;
			RequestTimeout = requestTimeout;
			NumberOfRetries = numRetries;
			if (headers == null)
			{
				Headers = headers;
			}
			else
			{
				Headers = new Dictionary<string, string>(headers);
			}
		}

		public static Configuration MergeConfigurations(Configuration a, Configuration b)
		{
			if (a == null || b == null)
			{
				return a ?? b;
			}
			Configuration configuration = new Configuration(a.BasePath, a.RequestTimeout, a.NumberOfRetries, a.Headers);
			if (configuration.BasePath == null)
			{
				configuration.BasePath = b.BasePath;
			}
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			if (b.Headers != null)
			{
				foreach (KeyValuePair<string, string> header in b.Headers)
				{
					dictionary[header.Key] = header.Value;
				}
			}
			if (configuration.Headers != null)
			{
				foreach (KeyValuePair<string, string> header2 in configuration.Headers)
				{
					dictionary[header2.Key] = header2.Value;
				}
			}
			configuration.Headers = dictionary;
			configuration.RequestTimeout = configuration.RequestTimeout ?? b.RequestTimeout;
			configuration.NumberOfRetries = configuration.NumberOfRetries ?? b.NumberOfRetries;
			return configuration;
		}
	}
	internal class QosResults : IQosResults, IServiceComponent
	{
		private WrappedQosService _qosService;

		internal QosResults(WrappedQosService qosService)
		{
			_qosService = qosService;
		}

		public Task<IList<QosResult>> GetSortedQosResultsAsync(string service, IList<string> regions)
		{
			return _qosService.GetSortedInternalQosResultsAsync(service, regions);
		}
	}
	internal class Response
	{
		public Dictionary<string, string> Headers { get; }

		public long Status { get; set; }

		public Response(Unity.Services.Qos.Http.HttpClientResponse httpResponse)
		{
			Headers = httpResponse.Headers;
			Status = httpResponse.StatusCode;
		}
	}
	internal class Response<T> : Response
	{
		public T Result { get; }

		public Response(Unity.Services.Qos.Http.HttpClientResponse httpResponse, T result)
			: base(httpResponse)
		{
			Result = result;
		}
	}
	internal class QosPackageInitializer : IInitializablePackageV2, IInitializablePackage
	{
		private const string k_CloudEnvironmentKey = "com.unity.services.core.cloud-environment";

		private const string k_PackageName = "com.unity.services.qos";

		private const string k_StagingEnvironment = "staging";

		[RuntimeInitializeOnLoadMethod(/*Could not decode attribute arguments.*/)]
		internal static void InitializeOnLoad()
		{
			new QosPackageInitializer().Register(CorePackageRegistry.Instance);
		}

		public void Register(CorePackageRegistry registry)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: 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_001f: 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_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			CoreRegistration val = registry.Register<QosPackageInitializer>(this);
			val = ((CoreRegistration)(ref val)).DependsOn<IAccessToken>();
			val = ((CoreRegistration)(ref val)).DependsOn<IMetricsFactory>();
			val = ((CoreRegistration)(ref val)).DependsOn<IProjectConfiguration>();
			val = ((CoreRegistration)(ref val)).ProvidesComponent<IQosResults>();
			((CoreRegistration)(ref val)).ProvidesComponent<IQosServiceComponent>();
		}

		internal void Register(CoreRegistry registry)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: 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_001f: 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_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			CoreRegistration val = registry.RegisterPackage<QosPackageInitializer>(this);
			val = ((CoreRegistration)(ref val)).DependsOn<IAccessToken>();
			val = ((CoreRegistration)(ref val)).DependsOn<IMetricsFactory>();
			val = ((CoreRegistration)(ref val)).DependsOn<IProjectConfiguration>();
			val = ((CoreRegistration)(ref val)).ProvidesComponent<IQosResults>();
			((CoreRegistration)(ref val)).ProvidesComponent<IQosServiceComponent>();
		}

		public Task Initialize(CoreRegistry registry)
		{
			QosService.Instance = InitializeService(registry);
			return Task.CompletedTask;
		}

		public Task InitializeInstanceAsync(CoreRegistry registry)
		{
			InitializeService(registry);
			return Task.CompletedTask;
		}

		private IQosService InitializeService(CoreRegistry registry)
		{
			IProjectConfiguration serviceComponent = registry.GetServiceComponent<IProjectConfiguration>();
			IAccessToken serviceComponent2 = registry.GetServiceComponent<IAccessToken>();
			IMetrics metrics = registry.GetServiceComponent<IMetricsFactory>().Create("com.unity.services.qos");
			Unity.Services.Qos.Http.HttpClient httpClient = new Unity.Services.Qos.Http.HttpClient();
			InternalQosDiscoveryService internalQosDiscoveryService = new InternalQosDiscoveryService(GetHost(serviceComponent), httpClient, serviceComponent2);
			Unity.Services.Qos.V2.Http.HttpClient httpClient2 = new Unity.Services.Qos.V2.Http.HttpClient();
			Unity.Services.Qos.V2.Configuration configuration = new Unity.Services.Qos.V2.Configuration(GetHost(serviceComponent), 10, 4, null);
			WrappedQosService wrappedQosService = new WrappedQosService(qosDiscoveryApiClientV2: new Unity.Services.Qos.V2.Apis.QosDiscovery.QosDiscoveryApiClient(httpClient2, serviceComponent2, configuration), qosDiscoveryApiClient: internalQosDiscoveryService.QosDiscoveryApi, qosRunner: new BaselibQosRunner(), accessToken: serviceComponent2, metrics: metrics);
			registry.RegisterService<IQosService>((IQosService)wrappedQosService);
			registry.RegisterServiceComponent<IQosResults>((IQosResults)(object)new QosResults(wrappedQosService));
			registry.RegisterServiceComponent<IQosServiceComponent>((IQosServiceComponent)new QosServiceComponent(wrappedQosService));
			return wrappedQosService;
		}

		private string GetHost(IProjectConfiguration projectConfiguration)
		{
			if (((projectConfiguration != null) ? projectConfiguration.GetString("com.unity.services.core.cloud-environment", (string)null) : null) == "staging")
			{
				return "https://qos-discovery-stg.services.api.unity.com";
			}
			return "https://qos-discovery.services.api.unity.com";
		}
	}
	internal class InternalQosDiscoveryService
	{
		private const int RequestTimeout = 10;

		private const int NumRetries = 4;

		public Unity.Services.Qos.Apis.QosDiscovery.IQosDiscoveryApiClient QosDiscoveryApi { get; set; }

		public Configuration Configuration { get; set; }

		internal InternalQosDiscoveryService(string host, Unity.Services.Qos.Http.HttpClient httpClient, IAccessToken accessToken = null)
		{
			Configuration = new Configuration(host, 10, 4, null);
			QosDiscoveryApi = new Unity.Services.Qos.Apis.QosDiscovery.QosDiscoveryApiClient(httpClient, accessToken, Configuration);
		}
	}
	public static class QosService
	{
		public static IQosService Instance { get; internal set; }
	}
	public interface IQosService
	{
		Task<IList<IQosResult>> GetSortedQosResultsAsync(string service, IList<string> regions);

		Task<IList<IQosAnnotatedResult>> GetSortedRelayQosResultsAsync(IList<string> regions);

		Task<IList<IQosAnnotatedResult>> GetSortedMultiplayQosResultsAsync(IList<string> fleet);

		Task<IList<Unity.Services.Qos.V2.Models.QosServer>> GetAllServersAsync();

		Task<IList<(Unity.Services.Qos.V2.Models.QosServer, IQosMeasurements)>> GetQosResultsAsync(IList<Unity.Services.Qos.V2.Models.QosServer> servers);
	}
	public interface IQosMeasurements
	{
		int AverageLatencyMs { get; }

		float PacketLossPercent { get; }
	}
	public interface IQosResult
	{
		string Region { get; }

		int AverageLatencyMs { get; }

		float PacketLossPercent { get; }
	}
	public interface IQosAnnotatedResult : IQosResult
	{
		Dictionary<string, List<string>> Annotations { get; }
	}
	public interface IQosServiceComponent : IServiceComponent
	{
		IQosService Service { get; }
	}
	internal class QosServiceComponent : IQosServiceComponent, IServiceComponent
	{
		public IQosService Service { get; }

		internal QosServiceComponent(IQosService qos)
		{
			Service = qos;
		}
	}
	internal class WrappedQosService : IQosService
	{
		private const string ResultLatencyMetricName = "qos_result_latency_ms";

		private const string ResultPacketLossMetricName = "qos_result_packet_loss";

		private const string MetricServiceNameLabelName = "qos_service_name";

		private const string MetricServiceRegionLabelName = "qos_service_region";

		private const string MetricClientCountryLabelName = "qos_client_country";

		private const string MetricClientRegionLabelName = "qos_client_region";

		private const string MetricClientBestResultLabelName = "qos_best_result";

		private const string MetricClientBestResultLabelTrueValue = "true";

		private Unity.Services.Qos.Apis.QosDiscovery.IQosDiscoveryApiClient _qosDiscoveryApiClient;

		private Unity.Services.Qos.V2.Apis.QosDiscovery.IQosDiscoveryApiClient _qosDiscoveryApiClientV2;

		private IQosRunner _qosRunner;

		private IAccessToken _accessToken;

		private IMetrics _metrics;

		private string _latestCountryForTelemetry;

		private string _latestRegionForTelemetry;

		private string _getAllServersEtag = "";

		private IList<Unity.Services.Qos.V2.Models.QosServer> _getAllServersCached;

		internal WrappedQosService(Unity.Services.Qos.Apis.QosDiscovery.IQosDiscoveryApiClient qosDiscoveryApiClient, Unity.Services.Qos.V2.Apis.QosDiscovery.IQosDiscoveryApiClient qosDiscoveryApiClientV2, IQosRunner qosRunner, IAccessToken accessToken, IMetrics metrics)
		{
			_qosDiscoveryApiClient = qosDiscoveryApiClient;
			_qosDiscoveryApiClientV2 = qosDiscoveryApiClientV2;
			_qosRunner = qosRunner;
			_accessToken = accessToken;
			_metrics = metrics;
		}

		public async Task<IList<IQosResult>> GetSortedQosResultsAsync(string service, IList<string> regions)
		{
			return (await GetSortedInternalQosResultsAsync(service, regions)).Select(MapToPublicQosResult).ToList();
		}

		internal async Task<IList<QosResult>> GetSortedInternalQosResultsAsync(string service, IList<string> regions)
		{
			throw new UnsupportedEditorVersionException("QoS SDK does not support this version of Unity, please upgrade to 2020.3.34f1+, 2021.3.2f1+, 2022.2.0a10+, or newer.");
		}

		private List<QosResult> SortResults(IList<QosResult> results)
		{
			return (from q in results
				orderby q.AverageLatencyMs, q.PacketLossPercent
				select q).ToList();
		}

		public async Task<IList<IQosAnnotatedResult>> GetSortedRelayQosResultsAsync(IList<string> regions)
		{
			return await GetSortedInternalServiceQosResultsAsync("relay", regions, null);
		}

		public async Task<IList<IQosAnnotatedResult>> GetSortedMultiplayQosResultsAsync(IList<string> fleet)
		{
			return await GetSortedInternalServiceQosResultsAsync("multiplay", null, fleet);
		}

		public async Task<IList<Unity.Services.Qos.V2.Models.QosServer>> GetAllServersAsync()
		{
			GetAllServersRequest request = new GetAllServersRequest();
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			if (!string.IsNullOrEmpty(_getAllServersEtag))
			{
				dictionary.Add("If-None-Match", _getAllServersEtag);
			}
			Unity.Services.Qos.V2.Configuration operationConfiguration = new Unity.Services.Qos.V2.Configuration(null, null, null, dictionary);
			try
			{
				Unity.Services.Qos.V2.Response<Unity.Services.Qos.V2.Models.QosServersResponseBody> response = await _qosDiscoveryApiClientV2.GetAllServersAsync(request, operationConfiguration);
				response.Headers.TryGetValue("ETag", out _getAllServersEtag);
				_getAllServersCached = response.Result.Data.Servers;
				response.Headers.TryGetValue("X-Client-Country", out _latestCountryForTelemetry);
				response.Headers.TryGetValue("X-Client-Region", out _latestRegionForTelemetry);
			}
			catch (Unity.Services.Qos.V2.Http.HttpException ex)
			{
				if (304 == ex.Response.StatusCode)
				{
					return _getAllServersCached;
				}
				throw;
			}
			return _getAllServersCached;
		}

		public async Task<IList<(Unity.Services.Qos.V2.Models.QosServer, IQosMeasurements)>> GetQosResultsAsync(IList<Unity.Services.Qos.V2.Models.QosServer> servers)
		{
			List<(Unity.Services.Qos.V2.Models.QosServer, IQosMeasurements)> list = await _qosRunner.MeasureQosV2Async(servers);
			SendResultsMetricsV2(list);
			return list;
		}

		private void SendResultsMetricsV2(IReadOnlyCollection<(Unity.Services.Qos.V2.Models.QosServer, IQosMeasurements)> qosResults)
		{
			SendResultsMetricsV2ForService(qosResults, (Unity.Services.Qos.V2.Models.QosServer qs) => qs.Annotations.RelayRegionId, "relay");
			SendResultsMetricsV2ForService(qosResults, (Unity.Services.Qos.V2.Models.QosServer qs) => qs.Annotations.MultiplayRegionId, "multiplay");
		}

		private void SendResultsMetricsV2ForService(IReadOnlyCollection<(Unity.Services.Qos.V2.Models.QosServer, IQosMeasurements)> allResults, Func<Unity.Services.Qos.V2.Models.QosServer, List<string>> regionGetter, string service)
		{
			List<(Unity.Services.Qos.V2.Models.QosServer, IQosMeasurements)> list = (from t in allResults
				where regionGetter(t.Item1) != null && regionGetter(t.Item1).Count > 0
				orderby t.Item2.AverageLatencyMs, t.Item2.PacketLossPercent
				select t).ToList();
			for (int num = 0; num < list.Count; num++)
			{
				(Unity.Services.Qos.V2.Models.QosServer, IQosMeasurements) tuple = list[num];
				SendResultMetrics(service, _latestCountryForTelemetry, _latestRegionForTelemetry, regionGetter(tuple.Item1)[0], tuple.Item2.AverageLatencyMs, tuple.Item2.PacketLossPercent, num == 0);
			}
		}

		internal async Task<IList<IQosAnnotatedResult>> GetSortedInternalServiceQosResultsAsync(string service, IList<string> regions, IList<string> fleet)
		{
			throw new UnsupportedEditorVersionException("QoS SDK does not support this version of Unity, please upgrade to 2020.3.34f1+, 2021.3.2f1+, 2022.2.0a10+, or newer.");
		}

		private List<IQosAnnotatedResult> SortServiceResults(IList<QosAnnotatedResult> results)
		{
			return (from q in (from q in results
					where q.AverageLatencyMs != int.MaxValue && (double)q.PacketLossPercent >= 0.0 && (double)q.PacketLossPercent < 1.0
					group q by q.Region).Select((Func<IGrouping<string, QosAnnotatedResult>, IQosAnnotatedResult>)((IGrouping<string, QosAnnotatedResult> q) => new QosResult(q.Key, (int)Math.Round(q.Select((QosAnnotatedResult x) => x.AverageLatencyMs).Average()), q.Select((QosAnnotatedResult x) => x.PacketLossPercent).Average(), q.Select((QosAnnotatedResult x) => x.Annotations).First()))).ToList()
				orderby q.AverageLatencyMs, q.PacketLossPercent
				select q).ToList();
		}

		private void SendResultsMetrics(IList<QosResult> sortedResults, string service, Response discoveryResponse)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			discoveryResponse.Headers.TryGetValue("X-Client-Country", out var value);
			discoveryResponse.Headers.TryGetValue("X-Client-Region", out var value2);
			for (int i = 0; i < sortedResults.Count; i++)
			{
				QosResult val = sortedResults[i];
				SendResultMetrics(service, value, value2, val.Region, val.AverageLatencyMs, val.PacketLossPercent, i == 0);
			}
		}

		private void SendResultsMetrics(IList<IQosResult> sortedResults, string service, Response discoveryResponse)
		{
			discoveryResponse.Headers.TryGetValue("X-Client-Country", out var value);
			discoveryResponse.Headers.TryGetValue("X-Client-Region", out var value2);
			for (int i = 0; i < sortedResults.Count; i++)
			{
				IQosResult qosResult = sortedResults[i];
				SendResultMetrics(service, value, value2, qosResult.Region, qosResult.AverageLatencyMs, qosResult.PacketLossPercent, i == 0);
			}
		}

		private void SendResultMetrics(string service, string clientCountry, string clientRegion, string region, int averageLatencyMs, float packetLossPercent, bool isBest)
		{
			IDictionary<string, string> dictionary = new Dictionary<string, string>();
			dictionary.Add("qos_service_name", service);
			dictionary.Add("qos_service_region", region);
			if (!string.IsNullOrEmpty(clientCountry))
			{
				dictionary.Add("qos_client_country", clientCountry);
			}
			if (!string.IsNullOrEmpty(clientRegion))
			{
				dictionary.Add("qos_client_region", clientRegion);
			}
			if (isBest)
			{
				dictionary.Add("qos_best_result", "true");
			}
			_metrics.SendHistogramMetric("qos_result_latency_ms", (double)averageLatencyMs, dictionary);
			_metrics.SendHistogramMetric("qos_result_packet_loss", (double)packetLossPercent, dictionary);
		}

		private IQosResult MapToPublicQosResult(QosResult internalQosResult)
		{
			//IL_0000: 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)
			return new QosResult(internalQosResult.Region, internalQosResult.AverageLatencyMs, internalQosResult.PacketLossPercent);
		}
	}
	internal class QosResult : IQosAnnotatedResult, IQosResult
	{
		public string Region { get; }

		public int AverageLatencyMs { get; }

		public float PacketLossPercent { get; }

		public Dictionary<string, List<string>> Annotations { get; }

		public QosResult(string region, int averageLatencyMs, float packetLossPercent, Dictionary<string, List<string>> annotations = null)
		{
			Region = region;
			AverageLatencyMs = averageLatencyMs;
			PacketLossPercent = packetLossPercent;
			Annotations = annotations ?? new Dictionary<string, List<string>>();
		}
	}
	internal class UnsupportedEditorVersionException : Exception
	{
		public UnsupportedEditorVersionException()
		{
		}

		public UnsupportedEditorVersionException(string message)
			: base(message)
		{
		}
	}
}
namespace Unity.Services.Qos.V2
{
	internal class Configuration
	{
		public string BasePath;

		public int? RequestTimeout;

		public int? NumberOfRetries;

		public IDictionary<string, string> Headers;

		public Configuration(string basePath, int? requestTimeout, int? numRetries, IDictionary<string, string> headers)
		{
			BasePath = basePath;
			RequestTimeout = requestTimeout;
			NumberOfRetries = numRetries;
			if (headers == null)
			{
				Headers = new Dictionary<string, string>();
			}
			else
			{
				Headers = new Dictionary<string, string>(headers);
			}
		}

		public static Configuration MergeConfigurations(Configuration a, Configuration b)
		{
			if (a == null || b == null)
			{
				return a ?? b;
			}
			Configuration configuration = new Configuration(a.BasePath, a.RequestTimeout, a.NumberOfRetries, a.Headers);
			if (configuration.BasePath == null)
			{
				configuration.BasePath = b.BasePath;
			}
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			if (b.Headers != null)
			{
				foreach (KeyValuePair<string, string> header in b.Headers)
				{
					dictionary[header.Key] = header.Value;
				}
			}
			if (configuration.Headers != null)
			{
				foreach (KeyValuePair<string, string> header2 in configuration.Headers)
				{
					dictionary[header2.Key] = header2.Value;
				}
			}
			configuration.Headers = dictionary;
			configuration.RequestTimeout = configuration.RequestTimeout ?? b.RequestTimeout;
			configuration.NumberOfRetries = configuration.NumberOfRetries ?? b.NumberOfRetries;
			return configuration;
		}
	}
	internal class Response
	{
		public Dictionary<string, string> Headers { get; }

		public long Status { get; set; }

		public Response(Unity.Services.Qos.V2.Http.HttpClientResponse httpResponse)
		{
			Headers = httpResponse.Headers;
			Status = httpResponse.StatusCode;
		}
	}
	internal class Response<T> : Response
	{
		public T Result { get; }

		public Response(Unity.Services.Qos.V2.Http.HttpClientResponse httpResponse, T result)
			: base(httpResponse)
		{
			Result = result;
		}
	}
}
namespace Unity.Services.Qos.V2.Scheduler
{
	internal static class EngineStateHelper
	{
		public static bool IsPlaying;

		[RuntimeInitializeOnLoadMethod(/*Could not decode attribute arguments.*/)]
		public static void Init()
		{
			IsPlaying = Application.isPlaying;
		}
	}
	internal static class ThreadHelper
	{
		private static SynchronizationContext _unitySynchronizationContext;

		private static TaskScheduler _taskScheduler;

		private static int _mainThreadId;

		public static SynchronizationContext SynchronizationContext => _unitySynchronizationContext;

		public static TaskScheduler TaskScheduler => _taskScheduler;

		public static int MainThreadId => _mainThreadId;

		[RuntimeInitializeOnLoadMethod(/*Could not decode attribute arguments.*/)]
		public static void Init()
		{
			_unitySynchronizationContext = SynchronizationContext.Current;
			_taskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
			_mainThreadId = Thread.CurrentThread.ManagedThreadId;
		}
	}
}
namespace Unity.Services.Qos.V2.Models
{
	[Preserve]
	[DataContract(Name = "ErrorResponseBody")]
	internal class ErrorResponseBody
	{
		[Preserve]
		[DataMember(Name = "type", IsRequired = true, EmitDefaultValue = true)]
		public string Type { get; }

		[Preserve]
		[DataMember(Name = "title", IsRequired = true, EmitDefaultValue = true)]
		public string Title { get; }

		[Preserve]
		[DataMember(Name = "status", IsRequired = true, EmitDefaultValue = true)]
		public int Status { get; }

		[Preserve]
		[DataMember(Name = "code", IsRequired = true, EmitDefaultValue = true)]
		public int Code { get; }

		[Preserve]
		[DataMember(Name = "detail", IsRequired = true, EmitDefaultValue = true)]
		public string Detail { get; }

		[Preserve]
		[DataMember(Name = "instance", EmitDefaultValue = false)]
		public string Instance { get; }

		[Preserve]
		[DataMember(Name = "details", EmitDefaultValue = false)]
		public List<Unity.Services.Qos.V2.Http.IDeserializable> Details { get; }

		[Preserve]
		public ErrorResponseBody(string type, string title, int status, int code, string detail, string instance = null, List<object> details = null)
		{
			Type = type;
			Title = title;
			Status = status;
			Code = code;
			Detail = detail;
			Instance = instance;
			Details = Unity.Services.Qos.V2.Http.JsonObject.GetNewJsonObjectResponse(details);
		}

		internal string SerializeAsPathParam()
		{
			string text = "";
			if (Type != null)
			{
				text = text + "type," + Type + ",";
			}
			if (Title != null)
			{
				text = text + "title," + Title + ",";
			}
			text = text + "status," + Status + ",";
			text = text + "code," + Code + ",";
			if (Detail != null)
			{
				text = text + "detail," + Detail + ",";
			}
			if (Instance != null)
			{
				text = text + "instance," + Instance + ",";
			}
			if (Details != null)
			{
				text = text + "details," + Details.ToString();
			}
			return text;
		}

		internal Dictionary<string, string> GetAsQueryParam()
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			if (Type != null)
			{
				string value = Type.ToString();
				dictionary.Add("type", value);
			}
			if (Title != null)
			{
				string value2 = Title.ToString();
				dictionary.Add("title", value2);
			}
			string value3 = Status.ToString();
			dictionary.Add("status", value3);
			string value4 = Code.ToString();
			dictionary.Add("code", value4);
			if (Detail != null)
			{
				string value5 = Detail.ToString();
				dictionary.Add("detail", value5);
			}
			if (Instance != null)
			{
				string value6 = Instance.ToString();
				dictionary.Add("instance", value6);
			}
			if (Details != null)
			{
				string value7 = Details.ToString();
				dictionary.Add("details", value7);
			}
			return dictionary;
		}
	}
	internal interface IOneOf
	{
		Type Type { get; }

		object Value { get; }
	}
	[Preserve]
	[DataContract(Name = "QosServer")]
	public class QosServer
	{
		[Preserve]
		[DataMember(Name = "endpoints", IsRequired = true, EmitDefaultValue = true)]
		public List<string> Endpoints { get; }

		[Preserve]
		[DataMember(Name = "annotations", IsRequired = true, EmitDefaultValue = true)]
		public QosServerAnnotations Annotations { get; }

		[Preserve]
		public QosServer(List<string> endpoints, QosServerAnnotations annotations)
		{
			Endpoints = endpoints;
			Annotations = annotations;
		}

		internal string SerializeAsPathParam()
		{
			string text = "";
			if (Endpoints != null)
			{
				text = text + "endpoints," + Endpoints.ToString() + ",";
			}
			if (Annotations != null)
			{
				text = text + "annotations," + Annotations.ToString();
			}
			return text;
		}

		internal Dictionary<string, string> GetAsQueryParam()
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			if (Endpoints != null)
			{
				string value = Endpoints.ToString();
				dictionary.Add("endpoints", value);
			}
			return dictionary;
		}
	}
	[Preserve]
	[DataContract(Name = "QosServerAnnotations")]
	public class QosServerAnnotations
	{
		[Preserve]
		[DataMember(Name = "projectId", EmitDefaultValue = false)]
		public List<string> ProjectId { get; }

		[Preserve]
		[DataMember(Name = "environmentId", EmitDefaultValue = false)]
		public List<string> EnvironmentId { get; }

		[Preserve]
		[DataMember(Name = "relayRegionId", EmitDefaultValue = false)]
		public List<string> RelayRegionId { get; }

		[Preserve]
		[DataMember(Name = "multiplayRegionId", EmitDefaultValue = false)]
		public List<string> MultiplayRegionId { get; }

		[Preserve]
		[DataMember(Name = "multiplayFleetId", EmitDefaultValue = false)]
		public List<string> MultiplayFleetId { get; }

		[Preserve]
		[DataMember(Name = "matchmakerQueueName", EmitDefaultValue = false)]
		public List<string> MatchmakerQueueName { get; }

		[Preserve]
		[DataMember(Name = "matchmakerPoolId", EmitDefaultValue = false)]
		public List<string> MatchmakerPoolId { get; }

		[Preserve]
		public QosServerAnnotations(List<string> projectId = null, List<string> environmentId = null, List<string> relayRegionId = null, List<string> multiplayRegionId = null, List<string> multiplayFleetId = null, List<string> matchmakerQueueName = null, List<string> matchmakerPoolId = null)
		{
			ProjectId = projectId;
			EnvironmentId = environmentId;
			RelayRegionId = relayRegionId;
			MultiplayRegionId = multiplayRegionId;
			MultiplayFleetId = multiplayFleetId;
			MatchmakerQueueName = matchmakerQueueName;
			MatchmakerPoolId = matchmakerPoolId;
		}

		internal string SerializeAsPathParam()
		{
			string text = "";
			if (ProjectId != null)
			{
				text = text + "projectId," + ProjectId.ToString() + ",";
			}
			if (EnvironmentId != null)
			{
				text = text + "environmentId," + EnvironmentId.ToString() + ",";
			}
			if (RelayRegionId != null)
			{
				text = text + "relayRegionId," + RelayRegionId.ToString() + ",";
			}
			if (MultiplayRegionId != null)
			{
				text = text + "multiplayRegionId," + MultiplayRegionId.ToString() + ",";
			}
			if (MultiplayFleetId != null)
			{
				text = text + "multiplayFleetId," + MultiplayFleetId.ToString() + ",";
			}
			if (MatchmakerQueueName != null)
			{
				text = text + "matchmakerQueueName," + MatchmakerQueueName.ToString() + ",";
			}
			if (MatchmakerPoolId != null)
			{
				text = text + "matchmakerPoolId," + MatchmakerPoolId.ToString();
			}
			return text;
		}

		internal Dictionary<string, string> GetAsQueryParam()
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			if (ProjectId != null)
			{
				string value = ProjectId.ToString();
				dictionary.Add("projectId", value);
			}
			if (EnvironmentId != null)
			{
				string value2 = EnvironmentId.ToString();
				dictionary.Add("environmentId", value2);
			}
			if (RelayRegionId != null)
			{
				string value3 = RelayRegionId.ToString();
				dictionary.Add("relayRegionId", value3);
			}
			if (MultiplayRegionId != null)
			{
				string value4 = MultiplayRegionId.ToString();
				dictionary.Add("multiplayRegionId", value4);
			}
			if (MultiplayFleetId != null)
			{
				string value5 = MultiplayFleetId.ToString();
				dictionary.Add("multiplayFleetId", value5);
			}
			if (MatchmakerQueueName != null)
			{
				string value6 = MatchmakerQueueName.ToString();
				dictionary.Add("matchmakerQueueName", value6);
			}
			if (MatchmakerPoolId != null)
			{
				string value7 = MatchmakerPoolId.ToString();
				dictionary.Add("matchmakerPoolId", value7);
			}
			return dictionary;
		}
	}
	[Preserve]
	[DataContract(Name = "QosServersList")]
	internal class QosServersList
	{
		[Preserve]
		[DataMember(Name = "servers", IsRequired = true, EmitDefaultValue = true)]
		public List<QosServer> Servers { get; }

		[Preserve]
		public QosServersList(List<QosServer> servers)
		{
			Servers = servers;
		}

		internal string SerializeAsPathParam()
		{
			string text = "";
			if (Servers != null)
			{
				text = text + "servers," + Servers.ToString();
			}
			return text;
		}

		internal Dictionary<string, string> GetAsQueryParam()
		{
			return new Dictionary<string, string>();
		}
	}
	[Preserve]
	[DataContract(Name = "QosServersResponseBody")]
	internal class QosServersResponseBody
	{
		[Preserve]
		[DataMember(Name = "data", IsRequired = true, EmitDefaultValue = true)]
		public QosServersList Data { get; }

		[Preserve]
		public QosServersResponseBody(QosServersList data)
		{
			Data = data;
		}

		internal string SerializeAsPathParam()
		{
			string text = "";
			if (Data != null)
			{
				text = text + "data," + Data.ToString();
			}
			return text;
		}

		internal Dictionary<string, string> GetAsQueryParam()
		{
			return new Dictionary<string, string>();
		}
	}
}
namespace Unity.Services.Qos.V2.Http
{
	internal abstract class BaseApiClient
	{
		protected readonly IHttpClient HttpClient;

		public BaseApiClient(IHttpClient httpClient)
		{
			HttpClient = httpClient ?? new HttpClient();
		}
	}
	[Serializable]
	internal class DeserializationException : Exception
	{
		public DeserializationException()
		{
		}

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

		private DeserializationException(string message, Exception inner)
			: base(message, inner)
		{
		}
	}
	internal enum MissingMemberHandling
	{
		Error,
		Ignore
	}
	internal class DeserializationSettings
	{
		public MissingMemberHandling MissingMemberHandling;
	}
	internal class HttpClient : IHttpClient
	{
		public async Task<HttpClientResponse> MakeRequestAsync(string method, string url, byte[] body, Dictionary<string, string> headers, int requestTimeout)
		{
			return await CreateWebRequestAsync(method.ToUpper(), url, body, headers, requestTimeout);
		}

		public async Task<HttpClientResponse> MakeRequestAsync(string method, string url, List<IMultipartFormSection> body, Dictionary<string, string> headers, int requestTimeout, string boundary = null)
		{
			return await CreateWebRequestAsync(method.ToUpper(), url, body, headers, requestTimeout, boundary);
		}

		private async Task<HttpClientResponse> CreateWebRequestAsync(string method, string url, byte[] body, IDictionary<string, string> headers, int requestTimeout)
		{
			return await CreateHttpClientResponse(method, url, body, headers, requestTimeout);
		}

		private async Task<HttpClientResponse> CreateHttpClientResponse(string method, string url, byte[] body, IDictionary<string, string> headers, int requestTimeout)
		{
			return await (await Task.Factory.StartNew(async delegate
			{
				UnityWebRequest request = new UnityWebRequest(url, method);
				try
				{
					foreach (KeyValuePair<string, string> header in headers)
					{
						request.SetRequestHeader(header.Key, header.Value);
					}
					request.timeout = requestTimeout;
					if (body != null && (method == "POST" || method == "PUT" || method == "PATCH"))
					{
						request.uploadHandler = (UploadHandler)new UploadHandlerRaw(body);
					}
					request.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
					return await SendWebRequest(request);
				}
				finally
				{
					((IDisposable)request)?.Dispose();
				}
			}, CancellationToken.None, TaskCreationOptions.None, Unity.Services.Qos.V2.Scheduler.ThreadHelper.TaskScheduler));
		}

		private async Task<HttpClientResponse> CreateWebRequestAsync(string method, string url, List<IMultipartFormSection> body, IDictionary<string, string> headers, int requestTimeout, string boundary = null)
		{
			return await (await Task.Factory.StartNew(async delegate
			{
				byte[] boundary2 = (string.IsNullOrEmpty(boundary) ? UnityWebRequest.GenerateBoundary() : Encoding.Default.GetBytes(boundary));
				UnityWebRequest val = new UnityWebRequest(url, method);
				foreach (KeyValuePair<string, string> header in headers)
				{
					val.SetRequestHeader(header.Key, header.Value);
				}
				val.timeout = requestTimeout;
				val = SetupMultipartRequest(val, body, boundary2);
				val.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
				return await SendWebRequest(val);
			}, CancellationToken.None, TaskCreationOptions.None, Unity.Services.Qos.V2.Scheduler.ThreadHelper.TaskScheduler));
		}

		private static UnityWebRequest SetupMultipartRequest(UnityWebRequest request, List<IMultipartFormSection> multipartFormSections, byte[] boundary)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			byte[] array = null;
			if (multipartFormSections != null && multipartFormSections.Count != 0)
			{
				array = UnityWebRequest.SerializeFormSections(multipartFormSections, boundary);
			}
			UploadHandler val = (UploadHandler)new UploadHandlerRaw(array);
			val.contentType = "multipart/form-data; boundary=" + Encoding.UTF8.GetString(boundary, 0, boundary.Length);
			request.uploadHandler = val;
			request.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
			return request;
		}

		private UnityWebRequestAsyncOperation SendWebRequest(UnityWebRequest request)
		{
			return request.SendWebRequest();
		}
	}
	internal class HttpClientResponse
	{
		public Dictionary<string, string> Headers { get; }

		public long StatusCode { get; }

		public bool IsHttpError { get; }

		public bool IsNetworkError { get; }

		public byte[] Data { get; }

		public string ErrorMessage { get; }

		public HttpClientResponse(Dictionary<string, string> headers, long statusCode, bool isHttpError, bool isNetworkError, byte[] data, string errorMessage)
		{
			Headers = headers;
			StatusCode = statusCode;
			IsHttpError = isHttpError;
			IsNetworkError = isNetworkError;
			Data = data;
			ErrorMessage = errorMessage;
		}
	}
	[Serializable]
	[Preserve]
	internal class HttpException : Exception
	{
		[Preserve]
		public HttpClientResponse Response;

		[Preserve]
		public HttpException()
		{
		}

		[Preserve]
		public HttpException(string message)
			: base(message)
		{
		}

		[Preserve]
		public HttpException(string message, Exception inner)
			: base(message, inner)
		{
		}

		[Preserve]
		public HttpException(HttpClientResponse response)
			: base($"({response.StatusCode}) {response.ErrorMessage}")
		{
			Response = response;
		}
	}
	[Serializable]
	[Preserve]
	internal class HttpException<T> : HttpException
	{
		[Preserve]
		public T ActualError;

		[Preserve]
		public HttpException()
		{
		}

		[Preserve]
		public HttpException(string message)
			: base(message)
		{
		}

		[Preserve]
		public HttpException(string message, Exception inner)
			: base(message, inner)
		{
		}

		[Preserve]
		public HttpException(HttpClientResponse response, T actualError)
			: base(response)
		{
			ActualError = actualError;
		}
	}
	[Preserve]
	[JsonConverter(typeof(JsonObjectConverter))]
	internal interface IDeserializable
	{
		string GetAsString();

		T GetAs<T>(DeserializationSettings deserializationSettings = null);
	}
	internal interface IHttpClient
	{
		Task<HttpClientResponse> MakeRequestAsync(string method, string url, byte[] body, Dictionary<string, string> headers, int requestTimeout);

		Task<HttpClientResponse> MakeRequestAsync(string method, string url, List<IMultipartFormSection> body, Dictionary<string, string> headers, int requestTimeout, string boundary = null);
	}
	internal static class IsolatedJsonConvert
	{
		[DebuggerStepThrough]
		public static string SerializeObject(object value)
		{
			return SerializeObject(value, null, null);
		}

		[DebuggerStepThrough]
		public static string SerializeObject(object value, JsonSerializerSettings settings)
		{
			return SerializeObject(value, null, settings);
		}

		[DebuggerStepThrough]
		public static string SerializeObject(object value, Type type, JsonSerializerSettings settings)
		{
			JsonSerializer jsonSerializer = JsonSerializer.Create(settings);
			return SerializeObjectInternal(value, type, jsonSerializer);
		}

		private static string SerializeObjectInternal(object value, Type type, JsonSerializer jsonSerializer)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			StringWriter stringWriter = new StringWriter(new StringBuilder(256), CultureInfo.InvariantCulture);
			JsonTextWriter val = new JsonTextWriter((TextWriter)stringWriter);
			try
			{
				((JsonWriter)val).Formatting = jsonSerializer.Formatting;
				jsonSerializer.Serialize((JsonWriter)(object)val, value, type);
			}
			finally
			{
				((IDisposable)val)?.Dispose();
			}
			return stringWriter.ToString();
		}

		[DebuggerStepThrough]
		public static object DeserializeObject(string value, Type type)
		{
			return DeserializeObject(value, type, null);
		}

		[DebuggerStepThrough]
		public static T DeserializeObject<T>(string value, JsonSerializerSettings settings)
		{
			return (T)DeserializeObject(value, typeof(T), settings);
		}

		public static object DeserializeObject(string value, Type type, JsonSerializerSettings settings)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Expected O, but got Unknown
			JsonSerializer val = JsonSerializer.Create(settings);
			JsonTextReader val2 = new JsonTextReader((TextReader)new StringReader(value));
			try
			{
				return val.Deserialize((JsonReader)(object)val2, type);
			}
			finally
			{
				((IDisposable)val2)?.Dispose();
			}
		}
	}
	internal static class JsonHelpers
	{
		[RuntimeInitializeOnLoadMethod(/*Could not decode attribute arguments.*/)]
		internal static void RegisterTypesForAOT()
		{
			AotHelper.EnsureType<StringEnumConverter>();
			AotHelper.EnsureType<JsonObjectConverter>();
		}

		internal static bool TryParseJson<T>(this string @this, out T result)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: 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_0033: Expected O, but got Unknown
			bool success = true;
			JsonSerializerSettings settings = new JsonSerializerSettings
			{
				Error = delegate(object sender, ErrorEventArgs args)
				{
					success = false;
					args.ErrorContext.Handled = true;
				},
				MissingMemberHandling = (MissingMemberHandling)0,
				ReferenceLoopHandling = (ReferenceLoopHandling)1
			};
			result = IsolatedJsonConvert.DeserializeObject<T>(@this, settings);
			return success;
		}
	}
	[Preserve]
	[JsonConverter(typeof(JsonObjectConverter))]
	internal class JsonObject : IDeserializable
	{
		[Preserve]
		internal object obj;

		[Preserve]
		internal JsonObject(object obj)
		{
			this.obj = obj;
		}

		public string GetAsString()
		{
			try
			{
				if (obj == null)
				{
					return "";
				}
				if (obj.GetType() == typeof(string))
				{
					return obj.ToString();
				}
				return IsolatedJsonConvert.SerializeObject(obj);
			}
			catch (Exception)
			{
				throw new InvalidOperationException("Failed to convert JsonObject to string.");
			}
		}

		public T GetAs<T>(DeserializationSettings deserializationSettings = null)
		{
			//IL_003d: Expected O, but got Unknown
			//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_0024: Expected O, but got Unknown
			deserializationSettings = deserializationSettings ?? new DeserializationSettings();
			JsonSerializerSettings settings = new JsonSerializerSettings
			{
				MissingMemberHandling = (MissingMemberHandling)(deserializationSettings.MissingMemberHandling == MissingMemberHandling.Error)
			};
			try
			{
				return IsolatedJsonConvert.DeserializeObject<T>(IsolatedJsonConvert.SerializeObject(obj), settings);
			}
			catch (JsonSerializationException ex)
			{
				throw new DeserializationException(((Exception)ex).Message);
			}
			catch (Exception)
			{
				throw new DeserializationException("Unable to deserialize object.");
			}
		}

		public T GetAs<T>()
		{
			return GetAs<T>(null);
		}

		internal static IDeserializable GetNewJsonObjectResponse(object o)
		{
			return new JsonObject(o);
		}

		internal static List<IDeserializable> GetNewJsonObjectResponse(List<object> o)
		{
			return o?.Select((Func<object, IDeserializable>)((object v) => new JsonObject(v))).ToList();
		}

		internal static List<List<IDeserializable>> GetNewJsonObjectResponse(List<List<object>> o)
		{
			return o?.Select((List<object> l) => ((IEnumerable<object>)l).Select((Func<object, IDeserializable>)((object v) => (v != null) ? new JsonObject(v) : null)).ToList()).ToList();
		}

		internal static Dictionary<string, IDeserializable> GetNewJsonObjectResponse(Dictionary<string, object> o)
		{
			return o?.ToDictionary((Func<KeyValuePair<string, object>, string>)((KeyValuePair<string, object> kv) => kv.Key), (Func<KeyValuePair<string, object>, IDeserializable>)((KeyValuePair<string, object> kv) => new JsonObject(kv.Value)));
		}

		internal static Dictionary<string, List<IDeserializable>> GetNewJsonObjectResponse(Dictionary<string, List<object>> o)
		{
			return o?.ToDictionary((KeyValuePair<string, List<object>> kv) => kv.Key, (KeyValuePair<string, List<object>> kv) => GetNewJsonObjectResponse(kv.Value));
		}
	}
	[Preserve]
	internal class JsonObjectConverter : JsonConverter
	{
		public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
		{
			JsonObject jsonObject = (JsonObject)value;
			if (jsonObject.obj == null)
			{
				writer.WriteNull();
			}
			else
			{
				JToken.FromObject(jsonObject.obj, serializer).WriteTo(writer, Array.Empty<JsonConverter>());
			}
		}

		public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Invalid comparison between Unknown and I4
			if ((int)reader.TokenType != 11)
			{
				if (reader.Value != null)
				{
					return new JsonObject(reader.Value);
				}
				try
				{
					return new JsonObject(JObject.Load(reader));
				}
				catch (JsonReaderException)
				{
					return new JsonObject(JArray.Load(reader));
				}
			}
			return new JsonObject(null);
		}

		public override bool CanConvert(Type objectType)
		{
			throw new NotImplementedException();
		}
	}
	[Preserve]
	internal class JsonObjectCollectionConverter : JsonConverter
	{
		public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
		{
			object obj = value;
			Type type = value.GetType();
			if (type == typeof(Dictionary<string, IDeserializable>))
			{
				obj = (Dictionary<string, IDeserializable>)value;
			}
			else if (type == typeof(List<IDeserializable>))
			{
				obj = (List<IDeserializable>)value;
			}
			else if (type == typeof(List<List<IDeserializable>>))
			{
				obj = (List<List<IDeserializable>>)value;
			}
			if (obj == null)
			{
				writer.WriteNull();
			}
			else
			{
				JToken.FromObject(obj).WriteTo(writer, Array.Empty<JsonConverter>());
			}
		}

		public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Invalid comparison between Unknown and I4
			if ((int)reader.TokenType != 11)
			{
				List<object> obj = (List<object>)reader.Value;
				List<JsonObject> list = new List<JsonObject>();
				{
					foreach (object item in obj)
					{
						list.Add(new JsonObject(item));
					}
					return list;
				}
			}
			return null;
		}

		public override bool CanConvert(Type objectType)
		{
			throw new NotImplementedException();
		}
	}
	[Serializable]
	internal class ResponseDeserializationException : Exception
	{
		public HttpClientResponse response;

		public ResponseDeserializationException()
		{
		}

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

		private ResponseDeserializationException(Exception inner, string message)
			: base(message, inner)
		{
		}

		public ResponseDeserializationException(HttpClientResponse httpClientResponse)
			: base("Unable to Deserialize Http Client Response")
		{
			response = httpClientResponse;
		}

		public ResponseDeserializationException(HttpClientResponse httpClientResponse, string message)
			: base(message)
		{
			response = httpClientResponse;
		}

		public ResponseDeserializationException(HttpClientResponse httpClientResponse, Exception inner, string message)
			: base(message, inner)
		{
			response = httpClientResponse;
		}
	}
	internal static class ResponseHandler
	{
		private static List<IDeserializable> DeserializeListOfJsonObjects(List<object> objectList)
		{
			List<IDeserializable> list = new List<IDeserializable>();
			foreach (object @object in objectList)
			{
				list.Add(new JsonObject(@object));
			}
			return list;
		}

		public static T TryDeserializeResponse<T>(HttpClientResponse response)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: 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_0014: Expected O, but got Unknown
			JsonSerializerSettings settings = new JsonSerializerSettings
			{
				MissingMemberHandling = (MissingMemberHandling)0,
				ReferenceLoopHandling = (ReferenceLoopHandling)1
			};
			try
			{
				return IsolatedJsonConvert.DeserializeObject<T>(GetDeserializedJson(response.Data), settings);
			}
			catch (Exception ex)
			{
				throw new ResponseDeserializationException(response, ex, ex.Message);
			}
		}

		public static object TryDeserializeResponse(HttpClientResponse response, Type type)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: 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_0014: Expected O, but got Unknown
			JsonSerializerSettings settings = new JsonSerializerSettings
			{
				MissingMemberHandling = (MissingMemberHandling)0,
				ReferenceLoopHandling = (ReferenceLoopHandling)1
			};
			try
			{
				return IsolatedJsonConvert.DeserializeObject(GetDeserializedJson(response.Data), type, settings);
			}
			catch (Exception ex)
			{
				throw new ResponseDeserializationException(response, ex, ex.Message);
			}
		}

		private static string GetDeserializedJson(byte[] data)
		{
			if (data != null)
			{
				return Encoding.UTF8.GetString(data);
			}
			return null;
		}

		public static void HandleAsyncResponse(HttpClientResponse response, Dictionary<string, Type> statusCodeToTypeMap)
		{
			if (statusCodeToTypeMap.ContainsKey(response.StatusCode.ToString()))
			{
				Type type = statusCodeToTypeMap[response.StatusCode.ToString()];
				if ((type != null && response.IsHttpError) || response.IsNetworkError)
				{
					if (typeof(Unity.Services.Qos.V2.Models.IOneOf).IsAssignableFrom(type))
					{
						throw CreateOneOfException(response, type);
					}
					throw CreateHttpException(response, type);
				}
				return;
			}
			throw new HttpException(response);
		}

		private static HttpException CreateOneOfException(HttpClientResponse response, Type responseType)
		{
			try
			{
				object obj = TryDeserializeResponse(response, responseType);
				return CreateHttpException(response, ((Unity.Services.Qos.V2.Models.IOneOf)obj).Type);
			}
			catch (ArgumentException ex)
			{
				throw new ResponseDeserializationException(response, ex, ex.Message);
			}
			catch (MissingFieldException inner)
			{
				throw new ResponseDeserializationException(response, inner, "Discriminator field not found in the parsed json response.");
			}
			catch (ResponseDeserializationException ex2)
			{
				if (ex2.InnerException.GetType() == typeof(MissingFieldException))
				{
					throw new ResponseDeserializationException(response, ex2.InnerException, "Discriminator field not found in the parsed json response.");
				}
				if (ex2.response == null)
				{
					throw new ResponseDeserializationException(response, ex2.Message);
				}
				throw;
			}
			catch (Exception ex3)
			{
				throw new ResponseDeserializationException(response, ex3, ex3.Message);
			}
		}

		private static HttpException CreateHttpException(HttpClientResponse response, Type responseType)
		{
			Type type = typeof(HttpException<>).MakeGenericType(responseType);
			try
			{
				if (responseType == typeof(Stream))
				{
					object obj = ((response.Data == null) ? new MemoryStream() : new MemoryStream(response.Data));
					return (HttpException)Activator.CreateInstance(type, response, obj);
				}
				object obj2 = TryDeserializeResponse(response, responseType);
				return (HttpException)Activator.CreateInstance(type, response, obj2);
			}
			catch (ArgumentException ex)
			{
				throw new ResponseDeserializationException(response, ex, ex.Message);
			}
			catch (MissingFieldException inner)
			{
				throw new ResponseDeserializationException(response, inner, "Discriminator field not found in the parsed json response.");
			}
			catch (ResponseDeserializationException ex2)
			{
				if (ex2.response == null)
				{
					throw new ResponseDeserializationException(response, ex2.Message);
				}
				throw;
			}
			catch (Exception ex3)
			{
				throw new ResponseDeserializationException(response, ex3, ex3.Message);
			}
		}

		public static T HandleAsyncResponse<T>(HttpClientResponse response, Dictionary<string, Type> statusCodeToTypeMap) where T : class
		{
			HandleAsyncResponse(response, statusCodeToTypeMap);
			try
			{
				if (statusCodeToTypeMap[response.StatusCode.ToString()] == typeof(string))
				{
					return ((response.Data == null) ? null : Encoding.UTF8.GetString(response.Data)) as T;
				}
				if (statusCodeToTypeMap[response.StatusCode.ToString()] == typeof(Stream))
				{
					return ((response.Data == null) ? new MemoryStream() : new MemoryStream(response.Data)) as T;
				}
				return TryDeserializeResponse<T>(response);
			}
			catch (ArgumentException ex)
			{
				throw new ResponseDeserializationException(response, ex.Message);
			}
			catch (MissingFieldException inner)
			{
				throw new ResponseDeserializationException(response, inner, "Discriminator field not found in the parsed json response.");
			}
			catch (ResponseDeserializationException ex2)
			{
				if (ex2.response == null)
				{
					throw new ResponseDeserializationException(response, ex2.Message);
				}
				throw;
			}
			catch (Exception ex3)
			{
				throw new ResponseDeserializationException(response, ex3, ex3.Message);
			}
		}
	}
	internal static class UnityWebRequestHelpers
	{
		public static TaskAwaiter<HttpClientResponse> GetAwaiter(this UnityWebRequestAsyncOperation asyncOp)
		{
			TaskCompletionSource<HttpClientResponse> tcs = new TaskCompletionSource<HttpClientResponse>();
			((AsyncOperation)asyncOp).completed += delegate(AsyncOperation obj)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_000b: Expected O, but got Unknown
				HttpClientResponse result = CreateHttpClientResponse((UnityWebRequestAsyncOperation)obj);
				tcs.SetResult(result);
			};
			return tcs.Task.GetAwaiter();
		}

		internal static HttpClientResponse CreateHttpClientResponse(UnityWebRequestAsyncOperation unityResponse)
		{
			UnityWebRequest webRequest = unityResponse.webRequest;
			return new HttpClientResponse(webRequest.GetResponseHeaders(), webRequest.responseCode, webRequest.isHttpError, webRequest.isNetworkError, webRequest.downloadHandler.data, webRequest.error);
		}
	}
}
namespace Unity.Services.Qos.V2.Helpers
{
	internal static class AsyncOpRetry
	{
		public static AsyncOpRetry<T> FromCreateAsync<T>(Func<int, T> op)
		{
			return AsyncOpRetry<T>.FromCreateAsync(op);
		}
	}
	internal class AsyncOpRetry<T>
	{
		private uint MaxRetries { get; set; } = 4u;

		private float JitterMagnitude { get; set; } = 1f;

		private float DelayScale { get; set; } = 1f;

		private float MaxDelayTime { get; set; } = 8f;

		private Func<int, T> CreateOperation { get; set; }

		private Func<T, bool> RetryCondition { get; set; }

		private Action<T> OnComplete { get; set; }

		private AsyncOpRetry(Func<int, T> createAsyncOp)
		{
			CreateOperation = createAsyncOp;
		}

		private static float AddJitter(float number, float magnitude)
		{
			return number + Random.value * magnitude;
		}

		private static float Pow2(float exponent, float scale)
		{
			return (float)(Math.Pow(2.0, exponent) * (double)scale);
		}

		private static float CalculateDelay(int attemptNumber, float maxDelayTime, float delayScale, float jitterMagnitude)
		{
			return Math.Min(AddJitter(Pow2(attemptNumber, delayScale), jitterMagnitude), maxDelayTime);
		}

		public static AsyncOpRetry<T> FromCreateAsync(Func<int, T> op)
		{
			return new AsyncOpRetry<T>(op);
		}

		public AsyncOpRetry<T> WithRetryCondition(Func<T, bool> shouldRetry)
		{
			RetryCondition = shouldRetry;
			return this;
		}

		public AsyncOpRetry<T> WhenComplete(Action<T> onComplete)
		{
			OnComplete = onComplete;
			return this;
		}

		public IEnumerator Run()
		{
			T asyncOp = default(T);
			int attempt = 0;
			while (attempt <= MaxRetries)
			{
				asyncOp = CreateOperation(attempt + 1);
				yield return asyncOp;
				Func<T, bool> retryCondition = RetryCondition;
				if (retryCondition != null && !retryCondition(asyncOp))
				{
					break;
				}
				float num = CalculateDelay(attempt, MaxDelayTime, DelayScale, JitterMagnitude);
				yield return (object)new WaitForSecondsRealtime(num);
				int num2 = attempt + 1;
				attempt = num2;
			}
			OnComplete?.Invoke(asyncOp);
		}
	}
}
namespace Unity.Services.Qos.V2.ErrorMitigation
{
	internal interface IRetryPolicyProvider
	{
		IRetryPolicy<T> ForOperation<T>(Func<int, Task<T>> operation);

		IRetryPolicy<T> ForOperation<T>(Func<Task<T>> operation);
	}
	internal interface IRetryPolicy<T>
	{
		IRetryPolicy<T> WithJitterMagnitude(float magnitude);

		IRetryPolicy<T> WithDelayScale(float scale);

		IRetryPolicy<T> WithMaxDelayTime(float time);

		IRetryPolicy<T> WithRetryCondition(Func<T, Task<bool>> shouldRetry);

		IRetryPolicy<T> UptoMaximumRetries(uint amount);

		IRetryPolicy<T> HandleException<TException>() where TException : Exception;

		IRetryPolicy<T> HandleException<TException>(Func<TException, bool> condition) where TException : Exception;

		Task<T> RunAsync(RetryPolicyConfig retryPolicyConfig = null);
	}
	internal class RetryPolicyProvider : IRetryPolicyProvider
	{
		public IRetryPolicy<T> ForOperation<T>(Func<int, Task<T>> operation)
		{
			return RetryPolicy<T>.ForOperation(operation);
		}

		public IRetryPolicy<T> ForOperation<T>(Func<Task<T>> operation)
		{
			return RetryPolicy<T>.ForOperation(operation);
		}
	}
	internal class RetryPolicy<T> : IRetryPolicy<T>
	{
		private RetryPolicyConfig _retryPolicyConfig = new RetryPolicyConfig();

		private Func<int, Task<T>> CreateOperation { get; set; }

		private Func<T, Task<bool>> RetryCondition { get; set; }

		private RetryPolicy(Func<int, Task<T>> createAsyncOp)
		{
			CreateOperation = createAsyncOp;
		}

		private RetryPolicy(Func<Task<T>> createAsyncOp)
		{
			CreateOperation = (int _) => createAsyncOp();
		}

		private static float AddJitter(float number, float magnitude)
		{
			return number + Random.value * magnitude;
		}

		private static float Pow2(float exponent, float scale)
		{
			return (float)(Math.Pow(2.0, exponent) * (double)scale);
		}

		private static float CalculateDelay(int attemptNumber, float maxDelayTime, float delayScale, float jitterMagnitude)
		{
			return Math.Min(AddJitter(Pow2(attemptNumber, delayScale), jitterMagnitude), maxDelayTime);
		}

		public IRetryPolicy<T> WithJitterMagnitude(float magnitude)
		{
			_retryPolicyConfig.JitterMagnitude = magnitude;
			return this;
		}

		public IRetryPolicy<T> WithDelayScale(float scale)
		{
			_retryPolicyConfig.DelayScale = scale;
			return this;
		}

		public IRetryPolicy<T> WithMaxDelayTime(float time)
		{
			_retryPolicyConfig.MaxDelayTime = time;
			return this;
		}

		public static RetryPolicy<T> ForOperation(Func<int, Task<T>> operation)
		{
			return new RetryPolicy<T>(operation);
		}

		public static RetryPolicy<T> ForOperation(Func<Task<T>> operation)
		{
			return new RetryPolicy<T>(operation);
		}

		public IRetryPolicy<T> WithRetryCondition(Func<T, Task<bool>> shouldRetry)
		{
			RetryCondition = shouldRetry;
			return this;
		}

		public IRetryPolicy<T> UptoMaximumRetries(uint amount)
		{
			_retryPolicyConfig.MaxRetries = amount;
			return this;
		}

		public IRetryPolicy<T> HandleException<TException>() where TException : Exception
		{
			_retryPolicyConfig.HandleException<TException>();
			return this;
		}

		public IRetryPolicy<T> HandleException<TException>(Func<TException, bool> condition) where TException : Exception
		{
			_retryPolicyConfig.HandleException(condition);
			return this;
		}

		public async Task<T> RunAsync(RetryPolicyConfig retryPolicyConfig = null)
		{
			T opResult = default(T);
			if (retryPolicyConfig == null)
			{
				retryPolicyConfig = _retryPolicyConfig;
			}
			int attempt = 0;
			while (attempt <= retryPolicyConfig.MaxRetries)
			{
				try
				{
					opResult = await CreateOperation(attempt + 1);
				}
				catch (Exception e)
				{
					if (!retryPolicyConfig.IsHandledException(e))
					{
						throw;
					}
				}
				if (RetryCondition != null && opResult != null)
				{
					if (!(await RetryCondition(opResult)))
					{
						break;
					}
				}
				else if (opResult != null)
				{
					break;
				}
				await Task.Delay((int)(CalculateDelay(attempt, retryPolicyConfig.MaxDelayTime, retryPolicyConfig.DelayScale, retryPolicyConfig.JitterMagnitude) * 1000f));
				int num = attempt + 1;
				attempt = num;
			}
			return opResult;
		}
	}
	internal delegate Exception ExceptionPredicate(Exception ex);
	internal class RetryPolicyConfig
	{
		private float _jitterMagnitude = 1f;

		private float _delayScale = 1f;

		private float _maxDelayTime = 8f;

		private List<ExceptionPredicate> _exceptionsToHandle = new List<ExceptionPredicate>();

		public uint MaxRetries { get; set; } = 4u;

		public float JitterMagnitude
		{
			get
			{
				return _jitterMagnitude;
			}
			set
			{
				_jitterMagnitude = Mathf.Clamp(value, 0.001f, 1f);
			}
		}

		public float DelayScale
		{
			get
			{
				return _delayScale;
			}
			set
			{
				_delayScale = Mathf.Clamp(value, 0.05f, 1f);
			}
		}

		public float MaxDelayTime
		{
			get
			{
				return _maxDelayTime;
			}
			set
			{
				_maxDelayTime = Mathf.Clamp(value, 0.1f, 60f);
			}
		}

		public void HandleException<TException>() where TException : Exception
		{
			_exceptionsToHandle.Add((Exception exception) => (!(exception is TException)) ? null : exception);
		}

		public void HandleException<TException>(Func<TException, bool> condition) where TException : Exception
		{
			_exceptionsToHandle.Add((Exception exception) => (!(exception is TException arg) || !condition(arg)) ? null : exception);
		}

		public bool IsHandledException(Exception e)
		{
			if (_exceptionsToHandle != null)
			{
				foreach (ExceptionPredicate item in _exceptionsToHandle)
				{
					if (item(e) == e)
					{
						return true;
					}
				}
			}
			return false;
		}
	}
	internal class StatusCodePolicyConfig
	{
		private IDictionary<long, bool> _statusCodesToHandleDict = new Dictionary<long, bool>
		{
			{ 408L, true },
			{ 429L, true },
			{ 502L, true },
			{ 503L, true },
			{ 504L, true }
		};

		public void HandleStatusCode(long code)
		{
			if (_statusCodesToHandleDict.ContainsKey(code))
			{
				_statusCodesToHandleDict[code] = true;
			}
			else
			{
				_statusCodesToHandleDict.Add(new KeyValuePair<long, bool>(code, value: true));
			}
		}

		public void DontHandleStatusCode(long code)
		{
			if (_statusCodesToHandleDict.ContainsKey(code))
			{
				_statusCodesToHandleDict[code] = false;
			}
			else
			{
				_statusCodesToHandleDict.Add(new KeyValuePair<long, bool>(code, value: false));
			}
		}

		public void Clear()
		{
			_statusCodesToHandleDict.Clear();
		}

		public bool IsHandledStatusCode(long code)
		{
			return _statusCodesToHandleDict.Contains(new KeyValuePair<long, bool>(code, value: true));
		}
	}
}
namespace Unity.Services.Qos.V2.QosDiscovery
{
	internal static class JsonSerialization
	{
		public static byte[] Serialize<T>(T obj)
		{
			return Encoding.UTF8.GetBytes(SerializeToString(obj));
		}

		public static string SerializeToString<T>(T obj)
		{
			//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_0017: Expected O, but got Unknown
			return IsolatedJsonConvert.SerializeObject(obj, new JsonSerializerSettings
			{
				ReferenceLoopHandling = (ReferenceLoopHandling)1
			});
		}
	}
	[Preserve]
	internal class QosDiscoveryApiBaseRequest
	{
		private static readonly Regex JsonRegex = new Regex("application\\/json(;\\s)?((charset=utf8|q=[0-1]\\.\\d)(\\s)?)*");

		[Preserve]
		public List<string> AddParamsToQueryParams(List<string> queryParams, string key, string value)
		{
			key = UnityWebRequest.EscapeURL(key);
			value = UnityWebRequest.EscapeURL(value);
			queryParams.Add(key + "=" + value);
			return queryParams;
		}

		[Preserve]
		public List<string> AddParamsToQueryParams(List<string> queryParams, string key, List<string> values, string style, bool explode)
		{
			if (explode)
			{
				foreach (string value in values)
				{
					string text = UnityWebRequest.EscapeURL(value);
					queryParams.Add(UnityWebRequest.EscapeURL(key) + "=" + text);
				}
			}
			else
			{
				string text2 = UnityWebRequest.EscapeURL(key) + "=";
				foreach (string value2 in values)
				{
					text2 = text2 + UnityWebRequest.EscapeURL(value2) + ",";
				}
				text2 = text2.Remove(text2.Length - 1);
				queryParams.Add(text2);
			}
			return queryParams;
		}

		[Preserve]
		public List<string> AddParamsToQueryParams(List<string> queryParams, Dictionary<string, string> modelVars)
		{
			foreach (string key in modelVars.Keys)
			{
				string text = UnityWebRequest.EscapeURL(modelVars[key]);
				queryParams.Add(UnityWebRequest.EscapeURL(key) + "=" + text);
			}
			return queryParams;
		}

		[Preserve]
		public List<string> AddParamsToQueryParams<T>(List<string> queryParams, string key, T value)
		{
			if (queryParams == null)
			{
				queryParams = new List<string>();
			}
			key = UnityWebRequest.EscapeURL(key);
			string text = UnityWebRequest.EscapeURL(value.ToString());
			queryParams.Add(key + "=" + text);
			return queryParams;
		}

		[Preserve]
		public string GetPathParamString(List<string> pathParam)
		{
			string text = "";
			foreach (string item in pathParam)
			{
				text = text + UnityWebRequest.EscapeURL(item) + ",";
			}
			return text.Remove(text.Length - 1);
		}

		public byte[] ConstructBody(Stream stream)
		{
			if (stream != null)
			{
				using (MemoryStream memoryStream = new MemoryStream())
				{
					stream.CopyTo(memoryStream);
					return memoryStream.ToArray();
				}
			}
			return null;
		}

		public byte[] ConstructBody(string s)
		{
			return Encoding.UTF8.GetBytes(s);
		}

		public byte[] ConstructBody(object o)
		{
			return JsonSerialization.Serialize(o);
		}

		public string GenerateAcceptHeader(string[] accepts)
		{
			if (accepts.Length == 0)
			{
				return null;
			}
			for (int i = 0; i < accepts.Length; i++)
			{
				if (string.Equals(accepts[i], "application/json", StringComparison.OrdinalIgnoreCase))
				{
					return "application/json";
				}
			}
			return string.Join(", ", accepts);
		}

		public string GenerateContentTypeHeader(string[] contentTypes)
		{
			if (contentTypes.Length == 0)
			{
				return null;
			}
			for (int i = 0; i < contentTypes.Length; i++)
			{
				if (!string.IsNullOrWhiteSpace(contentTypes[i]) && JsonRegex.IsMatch(contentTypes[i]))
				{
					return contentTypes[i];
				}
			}
			return contentTypes[0];
		}

		public IMultipartFormSection GenerateMultipartFormFileSection(string paramName, FileStream stream, string contentType)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			return (IMultipartFormSection)new MultipartFormFileSection(paramName, ConstructBody(stream), GetFileName(stream.Name), contentType);
		}

		public IMultipartFormSection GenerateMultipartFormFileSection(string paramName, Stream stream, string contentType)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			return (IMultipartFormSection)new MultipartFormFileSection(paramName, ConstructBody(stream), Guid.NewGuid().ToString(), contentType);
		}

		private string GetFileName(string filePath)
		{
			return Path.GetFileName(filePath);
		}
	}
	[Preserve]
	internal class GetAllServersRequest : QosDiscoveryApiBaseRequest
	{
		private string PathAndQueryParams;

		[Preserve]
		public Guid XRequestId { get; }

		[Preserve]
		public string XUser { get; }

		[Preserve]
		public string XUserType { get; }

		[Preserve]
		public GetAllServersRequest(Guid xRequestId = default(Guid), string xUser = null, string xUserType = null)
		{
			XRequestId = xRequestId;
			XUser = xUser;
			XUserType = xUserType;
			PathAndQueryParams = "/v2alpha1/servers";
		}

		public string ConstructUrl(string requestBasePath)
		{
			return requestBasePath + PathAndQueryParams;
		}

		public byte[] ConstructBody()
		{
			return null;
		}

		public Dictionary<string, string> ConstructHeaders(IAccessToken accessToken, Configuration operationConfiguration = null)
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			if (!string.IsNullOrEmpty(accessToken.AccessToken))
			{
				dictionary.Add("authorization", "Bearer " + accessToken.AccessToken);
			}
			dictionary.Add("Unity-Client-Version", Application.unityVersion);
			dictionary.Add("Unity-Client-Mode", Unity.Services.Qos.V2.Scheduler.EngineStateHelper.IsPlaying ? "play" : "edit");
			string[] contentTypes = new string[0];
			string[] accepts = new string[2] { "application/json", "application/problem+json" };
			string value = GenerateAcceptHeader(accepts);
			if (!string.IsNullOrEmpty(value))
			{
				dictionary.Add("Accept", value);
			}
			string text = "GET";
			string value2 = GenerateContentTypeHeader(contentTypes);
			if (!string.IsNullOrEmpty(value2))
			{
				dictionary.Add("Content-Type", value2);
			}
			else if (text == "POST" || text == "PATCH")
			{
				dictionary.Add("Content-Type", "application/json");
			}
			if (!XRequestId.Equals(default(Guid)))
			{
				dictionary.Add("X-Request-Id", XRequestId.ToString());
			}
			if (!string.IsNullOrEmpty(XUser))
			{
				dictionary.Add("X-User", XUser);
			}
			if (!string.IsNullOrEmpty(XUserType))
			{
				dictionary.Add("X-User-Type", XUserType);
			}
			if (operationConfiguration != null && operationConfiguration.Headers != null)
			{
				foreach (KeyValuePair<string, string> header in operationConfiguration.Headers)
				{
					dictionary[header.Key] = header.Value;
				}
			}
			return dictionary;
		}
	}
}
namespace Unity.Services.Qos.V2.Apis.QosDiscovery
{
	internal interface IQosDiscoveryApiClient
	{
		Task<Response<Unity.Services.Qos.V2.Models.QosServersResponseBody>> GetAllServersAsync(GetAllServersRequest request, Configuration operationConfiguration = null);
	}
	internal class QosDiscoveryApiClient : Unity.Services.Qos.V2.Http.BaseApiClient, IQosDiscoveryApiClient
	{
		private IAccessToken _accessToken;

		private const int _baseTimeout = 10;

		private Configuration _configuration;

		public Configuration Configuration
		{
			get
			{
				Configuration b = new Configuration("http://localhost", 10, 4, null);
				return Configuration.MergeConfigurations(_configuration, b);
			}
			set
			{
				_configuration = value;
			}
		}

		public QosDiscoveryApiClient(Unity.Services.Qos.V2.Http.IHttpClient httpClient, IAccessToken accessToken, Configuration configuration = null)
			: base(httpClient)
		{
			_configuration = configuration;
			_accessToken = accessToken;
		}

		public async Task<Response<Unity.Services.Qos.V2.Models.QosServersResponseBody>> GetAllServersAsync(GetAllServersRequest request, Configuration operationConfiguration = null)
		{
			Dictionary<string, Type> statusCodeToTypeMap = new Dictionary<string, Type>
			{
				{
					"200",
					typeof(Unity.Services.Qos.V2.Models.QosServersResponseBody)
				},
				{
					"400",
					typeof(Unity.Services.Qos.V2.Models.ErrorResponseBody)
				},
				{
					"401",
					typeof(Unity.Services.Qos.V2.Models.ErrorResponseBody)
				},
				{
					"403",
					typeof(Unity.Services.Qos.V2.Models.ErrorResponseBody)
				},
				{
					"429",
					typeof(Unity.Services.Qos.V2.Models.ErrorResponseBody)
				},
				{
					"500",
					typeof(Unity.Services.Qos.V2.Models.ErrorResponseBody)
				},
				{
					"503",
					typeof(Unity.Services.Qos.V2.Models.ErrorResponseBody)
				}
			};
			Configuration configuration = Configuration.MergeConfigurations(operationConfiguration, Configuration);
			Unity.Services.Qos.V2.Http.HttpClientResponse obj = await HttpClient.MakeRequestAsync("GET", request.ConstructUrl(configuration.BasePath), request.ConstructBody(), request.ConstructHeaders(_accessToken, configuration), configuration.RequestTimeout ?? 10);
			Unity.Services.Qos.V2.Models.QosServersResponseBody result = Unity.Services.Qos.V2.Http.ResponseHandler.HandleAsyncResponse<Unity.Services.Qos.V2.Models.QosServersResponseBody>(obj, statusCodeToTypeMap);
			return new Response<Unity.Services.Qos.V2.Models.QosServersResponseBody>(obj, result);
		}
	}
}
namespace Unity.Services.Qos.Scheduler
{
	internal static class EngineStateHelper
	{
		public static bool IsPlaying;

		[RuntimeInitializeOnLoadMethod(/*Could not decode attribute arguments.*/)]
		public static void Init()
		{
			IsPlaying = Application.isPlaying;
		}
	}
	internal static class ThreadHelper
	{
		private static SynchronizationContext _unitySynchronizationContext;

		private static TaskScheduler _taskScheduler;

		private static int _mainThreadId;

		public static SynchronizationContext SynchronizationContext => _unitySynchronizationContext;

		public static TaskScheduler TaskScheduler => _taskScheduler;

		public static int MainThreadId => _mainThreadId;

		[RuntimeInitializeOnLoadMethod(/*Could not decode attribute arguments.*/)]
		public static void Init()
		{
			_unitySynchronizationContext = SynchronizationContext.Current;
			_taskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
			_mainThreadId = Thread.CurrentThread.ManagedThreadId;
		}
	}
}
namespace Unity.Services.Qos.Runner
{
	internal delegate IQosJob QosJobProvider(IList<UcgQosServer> servers, string title);
	internal delegate Task<IPAddress[]> DnsResolver(string host);
	internal class BaselibQosRunner : IQosRunner
	{
		internal struct QosMeasurementImpl : IQosMeasurements
		{
			public int AverageLatencyMs { get; }

			public float PacketLossPercent { get; }

			public QosMeasurementImpl(int averageLatencyMs, float packetLossPercent)
			{
				AverageLatencyMs = averageLatencyMs;
				PacketLossPercent = packetLossPercent;
			}
		}

		private QosJobProvider _qosJobProvider = (IList<UcgQosServer> servers, string title) => new QosJob(servers, title);

		private DnsResolver _dnsResolver = Dns.GetHostAddressesAsync;

		public BaselibQosRunner(QosJobProvider qosJobProvider = null, DnsResolver dnsResolver = null)
		{
			if (qosJobProvider != null)
			{
				_qosJobProvider = qosJobProvider;
			}
			if (dnsResolver != null)
			{
				_dnsResolver = dnsResolver;
			}
		}

		public async Task<List<QosResult>> MeasureQosAsync(IList<Unity.Services.Qos.Models.QosServer> servers)
		{
			List<UcgQosServer> convertedServers = (from s in await Task.WhenAll(servers.Select(ToUcgFormat))
				where s.HasValue
				select s.Value).ToList();
			List<QosResult> results = new List<QosResult>();
			IQosJob qosJob = await RunQosJob(convertedServers);
			if (servers.Count() == ((IEnumerable<InternalQosResult>)(object)qosJob.QosResults).Count())
			{
				results = ParseResults((IEnumerable<InternalQosResult>)(object)qosJob.QosResults, servers);
			}
			qosJob.Dispose();
			qosJob.QosResults.Dispose();
			return results;
		}

		public async Task<List<QosAnnotatedResult>> MeasureQosAsync(IList<QosServiceServer> servers)
		{
			List<UcgQosServer> convertedServers = (from s in await Task.WhenAll(servers.Select(ToUcgFormat))
				where s.HasValue
				select s.Value).ToList();
			List<QosAnnotatedResult> results = new List<QosAnnotatedResult>();
			IQosJob qosJob = await RunQosJob(convertedServers);
			if (servers.Count() == ((IEnumerable<InternalQosResult>)(object)qosJob.QosResults).Count())
			{
				results = ParseResults((IEnumerable<InternalQosResult>)(object)qosJob.QosResults, servers);
			}
			qosJob.Dispose();
			qosJob.QosResults.Dispose();
			return results;
		}

		public async Task<List<(Unity.Services.Qos.V2.Models.QosServer, IQosMeasurements)>> MeasureQosV2Async(IList<Unity.Services.Qos.V2.Models.QosServer> servers)
		{
			List<Unity.Services.Qos.Models.QosServer> servers2 = servers.ToList().ConvertAll((Unity.Services.Qos.V2.Models.QosServer q) => new Unity.Services.Qos.Models.QosServer(q.Endpoints, "unused"));
			List<QosResult> list = await MeasureQosAsync(servers2);
			List<(Unity.Services.Qos.V2.Models.QosServer, IQosMeasurements)> list2 = new List<(Unity.Services.Qos.V2.Models.QosServer, IQosMeasurements)>(list.Count);
			if (list.Count == 0 || list.Count != servers.Count)
			{
				return list2;
			}
			List<QosMeasurementImpl> list3 = list.ConvertAll((QosResult qr) => new QosMeasurementImpl(qr.AverageLatencyMs, qr.PacketLossPercent));
			for (int num = 0; num < servers.Count; num++)
			{
				list2.Add((servers[num], list3[num]));
			}
			return list2;
		}

		private async Task<IQosJob> RunQosJob(List<UcgQosServer> convertedServers)
		{
			string title = "QoS request";
			IQosJob job = _qosJobProvider(convertedServers, title);
			JobHandle handle = job.Schedule<QosJob>(default(JobHandle));
			while (!((JobHandle)(ref handle)).IsCompleted)
			{
				await Task.Yield();
			}
			((JobHandle)(ref handle)).Complete();
			return job;
		}

		private async Task<UcgQosServer?> ToUcgFormat(Unity.Services.Qos.Models.QosServer server)
		{
			string serverEndpoint = server.Endpoints[0];
			string region = server.Region;
			return await ToUcgFormat(serverEndpoint, region);
		}

		private async Task<UcgQosServer?> ToUcgFormat(QosServiceServer server)
		{
			string serverEndpoint = server.Endpoints[0];
			string region = server.Region;
			return await ToUcgFormat(serverEndpoint, region);
		}

		private async Task<UcgQosServer?> ToUcgFormat(string serverEndpoint, string serverRegion)
		{
			if (!Uri.TryCreate("udp://" + serverEndpoint, UriKind.Absolute, out Uri uri))
			{
				Debug.LogError((object)("Could not create address from endpoint: '" + serverEndpoint + "'"));
				return null;
			}
			if (uri.Port == -1)
			{
				Debug.LogError((object)("Missing or invalid port in endpoint: '" + serverEndpoint + "'"));
				return null;
			}
			IPAddress[] array = await _dnsResolver(uri.Host);
			if (array.Length == 0)
			{
				Debug.LogError((object)("No addresses could be resolved for host " + uri.Host));
				return null;
			}
			IPAddress iPAddress = array[0];
			UcgQosServer value = new UcgQosServer
			{
				regionid = serverRegion,
				ipv6 = null,
				port = Convert.ToUInt16(uri.Port),
				BackoffUntilUtc = default(DateTime)
			};
			if (iPAddress.AddressFamily == AddressFamily.InterNetwork)
			{
				value.ipv4 = iPAddress.ToString();
			}
			else if (iPAddress.AddressFamily == AddressFamily.InterNetworkV6)
			{
				value.ipv6 = iPAddress.ToString();
			}
			return value;
		}

		private static List<QosResult> ParseResults(IEnumerable<InternalQosResult> ucgResults, IEnumerable<Unity.Services.Qos.Models.QosServer> servers)
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			List<QosResult> list = new List<QosResult>();
			using IEnumerator<Unity.Services.Qos.Models.QosServer> enumerator = servers.GetEnumerator();
			foreach (InternalQosResult ucgResult in ucgResults)
			{
				enumerator.MoveNext();
				if (enumerator.Current == null)
				{
					break;
				}
				int averageLatencyMs = (int)((ucgResult.AverageLatencyMs > int.MaxValue) ? int.MaxValue : ucgResult.AverageLatencyMs);
				list.Add(new QosResult
				{
					Region = enumerator.Current.Region,
					AverageLatencyMs = averageLatencyMs,
					PacketLossPercent = ucgResult.PacketLoss
				});
			}
			return list;
		}

		private static List<QosAnnotatedResult> ParseResults(IEnumerable<InternalQosResult> ucgResults, IEnumerable<QosServiceServer> servers)
		{
			List<QosAnnotatedResult> list = new List<QosAnnotatedResult>();
			using IEnumerator<QosServiceServer> enumerator = servers.GetEnumerator();
			foreach (InternalQosResult ucgResult in ucgResults)
			{
				enumerator.MoveNext();
				if (enumerator.Current == null)
				{
					break;
				}
				int averageLatencyMs = (int)((ucgResult.AverageLatencyMs > int.MaxValue) ? int.MaxValue : ucgResult.AverageLatencyMs);
				list.Add(new QosAnnotatedResult
				{
					Region = enumerator.Current.Region,
					AverageLatencyMs = averageLatencyMs,
					PacketLossPercent = ucgResult.PacketLoss,
					Annotations = enumerator.Current.Annotations
				});
			}
			return list;
		}
	}
	internal interface IQosJob : IJob
	{
		NativeArray<InternalQosResult> QosResults { get; }

		JobHandle Schedule<T>(JobHandle dependsOn = default(JobHandle)) where T : struct, IJob;

		void Dispose();
	}
	internal interface IQosRunner
	{
		Task<List<QosResult>> MeasureQosAsync(IList<Unity.Services.Qos.Models.QosServer> servers);

		Task<List<QosAnnotatedResult>> MeasureQosAsync(IList<QosServiceServer> servers);

		Task<List<(Unity.Services.Qos.V2.Models.QosServer, IQosMeasurements)>> MeasureQosV2Async(IList<Unity.Services.Qos.V2.Models.QosServer> servers);
	}
	public struct QosAnnotatedResult
	{
		public string Region;

		public int AverageLatencyMs;

		public float PacketLossPercent;

		public Dictionary<string, List<string>> Annotations;
	}
}
namespace Unity.Services.Qos.Models
{
	[Preserve]
	[DataContract(Name = "ErrorResponseBody")]
	internal class ErrorResponseBody
	{
		[Preserve]
		[DataMember(Name = "type", IsRequired = true, EmitDefaultValue = true)]
		public string Type { get; }

		[Preserve]
		[DataMember(Name = "title", IsRequired = true, EmitDefaultValue = true)]
		public string Title { get; }

		[Preserve]
		[DataMember(Name = "status", IsRequired = true, EmitDefaultValue = true)]
		public int Status { get; }

		[Preserve]
		[DataMember(Name = "code", IsRequired = true, EmitDefaultValue = true)]
		public int Code { get; }

		[Preserve]
		[DataMember(Name = "detail", IsRequired = true, EmitDefaultValue = true)]
		public string Detail { get; }

		[Preserve]
		[DataMember(Name = "instance", EmitDefaultValue = false)]
		public string Instance { get; }

		[Preserve]
		[DataMember(Name = "details", EmitDefaultValue = false)]
		public List<Unity.Services.Qos.Http.IDeserializable> Details { get; }

		[Preserve]
		public ErrorResponseBody(string type, string title, int status, int code, string detail, string instance = null, List<object> details = null)
		{
			Type = type;
			Title = title;
			Status = status;
			Code = code;
			Detail = detail;
			Instance = instance;
			Details = Unity.Services.Qos.Http.JsonObject.GetNewJsonObjectResponse(details);
		}

		internal string SerializeAsPathParam()
		{
			string text = "";
			if (Type != null)
			{
				text = text + "type," + Type + ",";
			}
			if (Title != null)
			{
				text = text + "title," + Title + ",";
			}
			text = text + "status," + Status + ",";
			text = text + "code," + Code + ",";
			if (Detail != null)
			{
				text = text + "detail," + Detail + ",";
			}
			if (Instance != null)
			{
				text = text + "instance," + Instance + ",";
			}
			if (Details != null)
			{
				text = text + "details," + Details.ToString();
			}
			return text;
		}

		internal Dictionary<string, string> GetAsQueryParam()
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			if (Type != null)
			{
				string value = Type.ToString();
				dictionary.Add("type", value);
			}
			if (Title != null)
			{
				string value2 = Title.ToString();
				dictionary.Add("title", value2);
			}
			string value3 = Status.ToString();
			dictionary.Add("status", value3);
			string value4 = Code.ToString();
			dictionary.Add("code", value4);
			if (Detail != null)
			{
				string value5 = Detail.ToString();
				dictionary.Add("detail", value5);
			}
			if (Instance != null)
			{
				string value6 = Instance.ToString();
				dictionary.Add("instance", value6);
			}
			if (Details != null)
			{
				string value7 = Details.ToString();
				dictionary.Add("details", value7);
			}
			return dictionary;
		}
	}
	[Preserve]
	[DataContract(Name = "KeyValuePair")]
	internal class KeyValuePair
	{
		[Preserve]
		[DataMember(Name = "key", IsRequired = true, EmitDefaultValue = true)]
		public string Key { get; }

		[Preserve]
		[DataMember(Name = "value", IsRequired = true, EmitDefaultValue = true)]
		public string Value { get; }

		[Preserve]
		public KeyValuePair(string key, string value)
		{
			Key = key;
			Value = value;
		}
	}
	internal interface IOneOf
	{
		Type Type { get; }

		object Value { get; }
	}
	[Preserve]
	[DataContract(Name = "QosServer")]
	internal class QosServer
	{
		[Preserve]
		[DataMember(Name = "endpoints", IsRequired = true, EmitDefaultValue = true)]
		public List<string> Endpoints { get; }

		[Preserve]
		[DataMember(Name = "region", IsRequired = true, EmitDefaultValue = true)]
		public string Region { get; }

		[Preserve]
		[DataMember(Name = "services", EmitDefaultValue = false)]
		public List<string> Services { get; }

		[Preserve]
		public QosServer(List<string> endpoints, string region, List<string> services = null)
		{
			Endpoints = endpoints;
			Region = region;
			Services = services;
		}

		internal string SerializeAsPathParam()
		{
			string text = "";
			if (Endpoints != null)
			{
				text = text + "endpoints," + Endpoints.ToString() + ",";
			}
			if (Region != null)
			{
				text = text + "region," + Region + ",";
			}
			if (Services != null)
			{
				text = text + "services," + Services.ToString();
			}
			return text;
		}

		internal Dictionary<string, string> GetAsQueryParam()
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			if (Endpoints != null)
			{
				string value = Endpoints.ToString();
				dictionary.Add("endpoints", value);
			}
			if (Region != null)
			{
				string value2 = Region.ToString();
				dictionary.Add("region", value2);
			}
			if (Services != null)
			{
				string value3 = Services.ToString();
				dictionary.Add("services", value3);
			}
			return dictionary;
		}
	}
	[Preserve]
	[DataContract(Name = "QosServersList")]
	internal class QosServersList
	{
		[Preserve]
		[DataMember(Name = "servers", IsRequired = true, EmitDefaultValue = true)]
		public List<QosServer> Servers { get; }

		[Preserve]
		public QosServersList(List<QosServer> servers)
		{
			Servers = servers;
		}

		internal string SerializeAsPathParam()
		{
			string text = "";
			if (Servers != null)
			{
				text = text + "servers," + Servers.ToString();
			}
			return text;
		}

		internal Dictionary<string, string> GetAsQueryParam()
		{
			return new Dictionary<string, string>();
		}
	}
	[Preserve]
	[DataContract(Name = "QosServersResponseBody")]
	internal class QosServersResponseBody
	{
		[Preserve]
		[DataMember(Name = "data", IsRequired = true, EmitDefaultValue = true)]
		public QosServersList Data { get; }

		[Preserve]
		public QosServersResponseBody(QosServersList data)
		{
			Data = data;
		}

		internal string SerializeAsPathParam()
		{
			string text = "";
			if (Data != null)
			{
				text = text + "data," + Data.ToString();
			}
			return text;
		}

		internal Dictionary<string, string> GetAsQueryParam()
		{
			return new Dictionary<string, string>();
		}
	}
	[Preserve]
	[DataContract(Name = "QosServiceServer")]
	internal class QosServiceServer
	{
		[Preserve]
		[DataMember(Name = "endpoints", IsRequired = true, EmitDefaultValue = true)]
		public List<string> Endpoints { get; }

		[Preserve]
		[DataMember(Name = "region", IsRequired = true, EmitDefaultValue = true)]
		public string Region { get; }

		[Preserve]
		[DataMember(Name = "annotations", EmitDefaultValue = false)]
		public Dictionary<string, List<string>> Annotations { get; }

		[Preserve]
		public QosServiceServer(List<string> endpoints, string region, Dictionary<string, List<string>> annotations = null)
		{
			Endpoints = endpoints;
			Region = region;
			Annotations = annotations;
		}

		internal string SerializeAsPathParam()
		{
			string text = "";
			if (Endpoints != null)
			{
				text = text + "endpoints," + Endpoints.ToString() + ",";
			}
			if (Region != null)
			{
				text = text + "region," + Region + ",";
			}
			if (Annotations != null)
			{
				text = text + "annotations," + Annotations.ToString();
			}
			return text;
		}

		internal Dictionary<string, string> GetAsQueryParam()
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			if (Endpoints != null)
			{
				string value = Endpoints.ToString();
				dictionary.Add("endpoints", value);
			}
			if (Region != null)
			{
				string value2 = Region.ToString();
				dictionary.Add("region", value2);
			}
			if (Annotations != null)
			{
				string value3 = Annotations.ToString();
				dictionary.Add("annotations", value3);
			}
			return dictionary;
		}
	}
	[Preserve]
	[DataContract(Name = "QosServiceServersList")]
	internal class QosServiceServersList
	{
		[Preserve]
		[DataMember(Name = "servers", IsRequired = true, EmitDefaultValue = true)]
		public List<QosServiceServer> Servers { get; }

		[Preserve]
		public QosServiceServersList(List<QosServiceServer> servers)
		{
			Servers = servers;
		}

		internal string SerializeAsPathParam()
		{
			string text = "";
			if (Servers != null)
			{
				text = text + "servers," + Servers.ToString();
			}
			return text;
		}

		internal Dictionary<string, string> GetAsQueryParam()
		{
			return new Dictionary<string, string>();
		}
	}
	[Preserve]
	[DataContract(Name = "QosServiceServersResponseBody")]
	internal class QosServiceServersResponseBody
	{
		[Preserve]
		[DataMember(Name = "data", IsRequired = true, EmitDefaultValue = true)]
		public QosServiceServersList Data { get; }

		[Preserve]
		public QosServiceServersResponseBody(QosServiceServersList data)
		{
			Data = data;
		}

		internal string SerializeAsPathParam()
		{
			string text = "";
			if (Data != null)
			{
				text = text + "data," + Data.ToString();
			}
			return text;
		}

		internal Dictionary<string, string> GetAsQueryParam()
		{
			return new Dictionary<string, string>();
		}
	}
}
namespace Unity.Services.Qos.Http
{
	internal abstract class BaseApiClient
	{
		protected readonly IHttpClient HttpClient;

		public BaseApiClient(IHttpClient httpClient)
		{
			HttpClient = httpClient ?? new HttpClient();
		}
	}
	[Serializable]
	internal class DeserializationException : Exception
	{
		public DeserializationException()
		{
		}

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

		private DeserializationException(string message, Exception inner)
			: base(message, inner)
		{
		}
	}
	internal enum MissingMemberHandling
	{
		Error,
		Ignore
	}
	internal class DeserializationSettings
	{
		public MissingMemberHandling MissingMemberHandling;
	}
	internal class HttpClient : IHttpClient
	{
		public async Task<HttpClientResponse> MakeRequestAsync(string method, string url, byte[] body, Dictionary<string, string> headers, int requestTimeout)
		{
			return await CreateWebRequestAsync(method.ToUpper(), url, body, headers, requestTimeout);
		}

		public async Task<HttpClientResponse> MakeRequestAsync(string method, string url, List<IMultipartFormSection> body, Dictionary<string, string> headers, int requestTimeout, string boundary = null)
		{
			return await CreateWebRequestAsync(method.ToUpper(), url, body, headers, requestTimeout, boundary);
		}

		private async Task<HttpClientResponse> CreateWebRequestAsync(string method, string url, byte[] body, IDictiona

BepInEx/plugins/Unity.Services.Relay.dll

Decompiled 13 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using Newtonsoft.Json.Utilities;
using Unity.Services.Authentication.Internal;
using Unity.Services.Core;
using Unity.Services.Core.Configuration.Internal;
using Unity.Services.Core.Internal;
using Unity.Services.Qos.Internal;
using Unity.Services.Relay.Apis.RelayAllocations;
using Unity.Services.Relay.Http;
using Unity.Services.Relay.Models;
using Unity.Services.Relay.RelayAllocations;
using Unity.Services.Relay.Scheduler;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.Scripting;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: InternalsVisibleTo("Unity.Services.Relay.Tests")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Unity.Services.Relay")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("Unity.Services.Relay")]
[assembly: AssemblyTitle("Unity.Services.Relay")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
}
namespace Unity.Services.Relay
{
	internal class Configuration
	{
		public string BasePath;

		public int? RequestTimeout;

		public int? NumberOfRetries;

		public IDictionary<string, string> Headers;

		public Configuration(string basePath, int? requestTimeout, int? numRetries, IDictionary<string, string> headers)
		{
			BasePath = basePath;
			RequestTimeout = requestTimeout;
			NumberOfRetries = numRetries;
			if (headers == null)
			{
				Headers = headers;
			}
			else
			{
				Headers = new Dictionary<string, string>(headers);
			}
		}

		public static Configuration MergeConfigurations(Configuration a, Configuration b)
		{
			if (a == null || b == null)
			{
				return a ?? b;
			}
			Configuration configuration = new Configuration(a.BasePath, a.RequestTimeout, a.NumberOfRetries, a.Headers);
			if (configuration.BasePath == null)
			{
				configuration.BasePath = b.BasePath;
			}
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			if (b.Headers != null)
			{
				foreach (KeyValuePair<string, string> header in b.Headers)
				{
					dictionary[header.Key] = header.Value;
				}
			}
			if (configuration.Headers != null)
			{
				foreach (KeyValuePair<string, string> header2 in configuration.Headers)
				{
					dictionary[header2.Key] = header2.Value;
				}
			}
			configuration.Headers = dictionary;
			configuration.RequestTimeout = configuration.RequestTimeout ?? b.RequestTimeout;
			configuration.NumberOfRetries = configuration.NumberOfRetries ?? b.NumberOfRetries;
			return configuration;
		}
	}
	internal class Response
	{
		public Dictionary<string, string> Headers { get; }

		public long Status { get; set; }

		public Response(HttpClientResponse httpResponse)
		{
			Headers = httpResponse.Headers;
			Status = httpResponse.StatusCode;
		}
	}
	internal class Response<T> : Response
	{
		public T Result { get; }

		public Response(HttpClientResponse httpResponse, T result)
			: base(httpResponse)
		{
			Result = result;
		}
	}
	internal class RelayServiceProvider : IInitializablePackage
	{
		[RuntimeInitializeOnLoadMethod(/*Could not decode attribute arguments.*/)]
		private static void Register()
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: 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_0022: Unknown result type (might be due to invalid IL or missing references)
			CoreRegistration val = CoreRegistry.Instance.RegisterPackage<RelayServiceProvider>(new RelayServiceProvider());
			((CoreRegistration)(ref val)).DependsOn<IAccessToken>();
			((CoreRegistration)(ref val)).DependsOn<IProjectConfiguration>();
			((CoreRegistration)(ref val)).DependsOn<IQosResults>();
		}

		public Task Initialize(CoreRegistry registry)
		{
			HttpClient httpClient = new HttpClient();
			IAccessToken serviceComponent = registry.GetServiceComponent<IAccessToken>();
			IProjectConfiguration serviceComponent2 = registry.GetServiceComponent<IProjectConfiguration>();
			IQosResults serviceComponent3 = registry.GetServiceComponent<IQosResults>();
			if (serviceComponent != null)
			{
				RelayServiceSdk.Instance = new InternalRelayService(httpClient, serviceComponent2, serviceComponent, serviceComponent3);
			}
			return Task.CompletedTask;
		}
	}
	internal class InternalRelayService : IRelayServiceSdk
	{
		private const string k_CloudEnvironmentKey = "com.unity.services.core.cloud-environment";

		private const string k_StagingEnvironment = "staging";

		public IRelayAllocationsApiClient AllocationsApi { get; set; }

		public Configuration Configuration { get; set; }

		public IAccessToken AccessToken { get; set; }

		public IQosResults QosResults { get; set; }

		public InternalRelayService(HttpClient httpClient, IProjectConfiguration projectConfiguration = null, IAccessToken accessToken = null, IQosResults qosResults = null)
		{
			AllocationsApi = new RelayAllocationsApiClient(httpClient, accessToken);
			Configuration = new Configuration(GetHost(projectConfiguration), 10, 4, null);
			AccessToken = accessToken;
			QosResults = qosResults;
		}

		private string GetHost(IProjectConfiguration projectConfiguration)
		{
			if (((projectConfiguration != null) ? projectConfiguration.GetString("com.unity.services.core.cloud-environment", (string)null) : null) == "staging")
			{
				return "https://relay-allocations-stg.services.api.unity.com";
			}
			return "https://relay-allocations.services.api.unity.com";
		}
	}
	internal static class RelayServiceSdk
	{
		public static IRelayServiceSdk Instance { get; internal set; }
	}
	internal interface IRelayServiceSdk
	{
		IRelayAllocationsApiClient AllocationsApi { get; set; }

		Configuration Configuration { get; set; }

		IAccessToken AccessToken { get; set; }

		IQosResults QosResults { get; set; }
	}
	internal static class ApiErrorExtender
	{
		public static RelayExceptionReason GetExceptionReason(this ErrorResponseBody error)
		{
			RelayExceptionReason result = RelayExceptionReason.Unknown;
			if (error.Code != 15000)
			{
				if (Enum.IsDefined(typeof(RelayExceptionReason), error.Code))
				{
					result = (RelayExceptionReason)error.Code;
				}
			}
			else if (Enum.IsDefined(typeof(RelayExceptionReason), error.Status))
			{
				result = (RelayExceptionReason)error.Status;
			}
			return result;
		}

		public static RelayExceptionReason GetExceptionReason(this HttpClientResponse error)
		{
			RelayExceptionReason result = RelayExceptionReason.Unknown;
			if (error.IsHttpError)
			{
				int num = (int)error.StatusCode + 15000;
				if (Enum.IsDefined(typeof(RelayExceptionReason), num))
				{
					result = (RelayExceptionReason)num;
				}
			}
			else if (error.IsNetworkError)
			{
				result = RelayExceptionReason.NetworkError;
			}
			return result;
		}

		public static string GetExceptionMessage(this ErrorResponseBody error)
		{
			string text = error.Title + ": " + error.Detail;
			foreach (Unity.Services.Relay.Models.KeyValuePair item in error.Details ?? new List<Unity.Services.Relay.Models.KeyValuePair>())
			{
				text = text + "\n" + item.Key + ": " + item.Value;
			}
			return text;
		}
	}
	public enum RelayExceptionReason
	{
		Min = 15000,
		NoError = 15000,
		InvalidRequest = 15001,
		InactiveProject = 15006,
		RegionNotFound = 15007,
		AllocationNotFound = 15008,
		JoinCodeNotFound = 15009,
		NoSuitableRelay = 15010,
		InvalidArgument = 15400,
		Unauthorized = 15401,
		PaymentRequired = 15402,
		Forbidden = 15403,
		EntityNotFound = 15404,
		MethodNotAllowed = 15405,
		NotAcceptable = 15406,
		ProxyAuthenticationRequired = 15407,
		RequestTimeOut = 15408,
		Conflict = 15409,
		Gone = 15410,
		LengthRequired = 15411,
		PreconditionFailed = 15412,
		RequestEntityTooLarge = 15413,
		RequestUriTooLong = 15414,
		UnsupportedMediaType = 15415,
		RangeNotSatisfiable = 15416,
		ExpectationFailed = 15417,
		Teapot = 15418,
		Misdirected = 15421,
		UnprocessableTransaction = 15422,
		Locked = 15423,
		FailedDependency = 15424,
		TooEarly = 15425,
		UpgradeRequired = 15426,
		PreconditionRequired = 15428,
		RateLimited = 15429,
		RequestHeaderFieldsTooLarge = 15431,
		UnavailableForLegalReasons = 15451,
		InternalServerError = 15500,
		NotImplemented = 15501,
		BadGateway = 15502,
		ServiceUnavailable = 15503,
		GatewayTimeout = 15504,
		HttpVersionNotSupported = 15505,
		VariantAlsoNegotiates = 15506,
		InsufficientStorage = 15507,
		LoopDetected = 15508,
		NotExtended = 15510,
		NetworkAuthenticationRequired = 15511,
		NetworkError = 15998,
		Unknown = 15999,
		Max = 15999
	}
	public class RelayServiceException : RequestFailedException
	{
		public RelayExceptionReason Reason { get; private set; }

		public ErrorResponseBody ApiError => (((Exception)this).InnerException as HttpException<ErrorResponseBody>)?.ActualError;

		public RelayServiceException(RelayExceptionReason reason, string message, Exception innerException)
			: base((int)reason, message, innerException)
		{
			Reason = reason;
		}

		public RelayServiceException(RelayExceptionReason reason, string message)
			: base((int)reason, message)
		{
			Reason = reason;
		}

		public RelayServiceException(long errorCode, string message)
			: base((int)errorCode, message)
		{
			if (Enum.IsDefined(typeof(RelayExceptionReason), errorCode))
			{
				Reason = (RelayExceptionReason)errorCode;
			}
			else
			{
				Reason = RelayExceptionReason.Unknown;
			}
		}

		public RelayServiceException(Exception innerException)
			: base(15999, "Unknown Relay Service Exception", innerException)
		{
		}
	}
	public interface IRelayService
	{
		Task<Allocation> CreateAllocationAsync(int maxConnections, string region = null);

		Task<string> GetJoinCodeAsync(Guid allocationId);

		Task<JoinAllocation> JoinAllocationAsync(string joinCode);

		Task<List<Region>> ListRegionsAsync();
	}
	public interface IRelayServiceSDK : IRelayService
	{
	}
	public interface IRelayServiceSDKConfiguration
	{
		void SetAllocationsServiceBasePath(string basePath);
	}
	public static class RelayService
	{
		private static IRelayService service;

		public static IRelayService Instance
		{
			get
			{
				if (service != null)
				{
					return service;
				}
				service = new WrappedRelayService(RelayServiceSdk.Instance ?? throw new InvalidOperationException("Attempting to call Relay Services requires initializing Core Registry. Call 'UnityServices.InitializeAsync' first!"));
				return service;
			}
		}
	}
	public static class Relay
	{
		public static IRelayServiceSDK Instance => (IRelayServiceSDK)RelayService.Instance;
	}
	internal class WrappedRelayService : IRelayService, IRelayServiceSDK, IRelayServiceSDKConfiguration
	{
		private const string QosRelayServiceName = "relay";

		internal IRelayServiceSdk m_RelayService { get; set; }

		internal WrappedRelayService(IRelayServiceSdk relayService)
		{
			m_RelayService = relayService;
		}

		public async Task<Allocation> CreateAllocationAsync(int maxConnections, string region = null)
		{
			EnsureSignedIn();
			if (maxConnections <= 0)
			{
				throw new ArgumentException("Maximum number of connections for an allocation must be greater than 0!");
			}
			if (m_RelayService.QosResults == null)
			{
				throw new Exception("Qos component should not be null, check that is is properly initialized.");
			}
			if (string.IsNullOrEmpty(region))
			{
				try
				{
					List<string> list = (await ListRegionsAsync()).Select((Region r) => r.Id).ToList();
					IList<QosResult> list2 = await m_RelayService.QosResults.GetSortedQosResultsAsync("relay", (IList<string>)list);
					if (list2.Any())
					{
						region = list2[0].Region;
						Debug.Log((object)("best region is " + region));
					}
				}
				catch (Exception ex)
				{
					Debug.LogWarning((object)("Could not do Qos region selection. Will use default." + Environment.NewLine + "QoS failed due to [" + ex.GetType().Name + "]. Reason: " + ex.Message));
				}
			}
			try
			{
				return (await m_RelayService.AllocationsApi.CreateAllocationAsync(new CreateAllocationRequest(new AllocationRequest(maxConnections, region)), m_RelayService.Configuration)).Result.Data.Allocation;
			}
			catch (HttpException<ErrorResponseBody> ex2)
			{
				throw new RelayServiceException(ex2.ActualError.GetExceptionReason(), ex2.ActualError.GetExceptionMessage(), ex2);
			}
			catch (HttpException ex3)
			{
				if (ex3.Response.IsHttpError)
				{
					throw new RelayServiceException(ex3.Response.GetExceptionReason(), ex3.Response.ErrorMessage, ex3);
				}
				if (ex3.Response.IsNetworkError)
				{
					throw new RelayServiceException(RelayExceptionReason.NetworkError, ex3.Response.ErrorMessage);
				}
				throw new RequestFailedException(15999, "Something went wrong.", (Exception)ex3);
			}
		}

		public async Task<string> GetJoinCodeAsync(Guid allocationId)
		{
			EnsureSignedIn();
			if (allocationId == Guid.Empty)
			{
				throw new ArgumentNullException("AllocationId cannot be null or empty!");
			}
			try
			{
				return (await m_RelayService.AllocationsApi.CreateJoincodeAsync(new CreateJoincodeRequest(new JoinCodeRequest(allocationId)), m_RelayService.Configuration)).Result.Data.JoinCode;
			}
			catch (HttpException<ErrorResponseBody> ex)
			{
				throw new RelayServiceException(ex.ActualError.GetExceptionReason(), ex.ActualError.GetExceptionMessage(), ex);
			}
			catch (HttpException ex2)
			{
				if (ex2.Response.IsHttpError)
				{
					throw new RelayServiceException(ex2.Response.GetExceptionReason(), ex2.Response.ErrorMessage, ex2);
				}
				if (ex2.Response.IsNetworkError)
				{
					throw new RelayServiceException(RelayExceptionReason.NetworkError, ex2.Response.ErrorMessage);
				}
				throw new RequestFailedException(15999, "Something went wrong.", (Exception)ex2);
			}
		}

		public async Task<JoinAllocation> JoinAllocationAsync(string joinCode)
		{
			EnsureSignedIn();
			if (string.IsNullOrWhiteSpace(joinCode))
			{
				throw new ArgumentNullException("JoinCode must be non-null, non-empty, and cannot contain only whitespace!");
			}
			try
			{
				return (await m_RelayService.AllocationsApi.JoinRelayAsync(new JoinRelayRequest(new JoinRequest(joinCode)), m_RelayService.Configuration)).Result.Data.Allocation;
			}
			catch (HttpException<ErrorResponseBody> ex)
			{
				throw new RelayServiceException(ex.ActualError.GetExceptionReason(), ex.ActualError.GetExceptionMessage(), ex);
			}
			catch (HttpException ex2)
			{
				if (ex2.Response.IsHttpError)
				{
					throw new RelayServiceException(ex2.Response.GetExceptionReason(), ex2.Response.ErrorMessage, ex2);
				}
				if (ex2.Response.IsNetworkError)
				{
					throw new RelayServiceException(RelayExceptionReason.NetworkError, ex2.Response.ErrorMessage);
				}
				throw new RequestFailedException(15999, "Something went wrong.", (Exception)ex2);
			}
		}

		public async Task<List<Region>> ListRegionsAsync()
		{
			EnsureSignedIn();
			try
			{
				return (await m_RelayService.AllocationsApi.ListRegionsAsync(new ListRegionsRequest(), m_RelayService.Configuration)).Result.Data.Regions;
			}
			catch (HttpException<ErrorResponseBody> ex)
			{
				throw new RelayServiceException(ex.ActualError.GetExceptionReason(), ex.ActualError.GetExceptionMessage(), ex);
			}
			catch (HttpException ex2)
			{
				if (ex2.Response.IsHttpError)
				{
					throw new RelayServiceException(ex2.Response.GetExceptionReason(), ex2.Response.ErrorMessage, ex2);
				}
				if (ex2.Response.IsNetworkError)
				{
					throw new RelayServiceException(RelayExceptionReason.NetworkError, ex2.Response.ErrorMessage);
				}
				throw new RequestFailedException(15999, "Something went wrong.", (Exception)ex2);
			}
		}

		public void SetAllocationsServiceBasePath(string allocationsBasePath)
		{
			m_RelayService.Configuration.BasePath = allocationsBasePath;
		}

		private void EnsureSignedIn()
		{
			if (m_RelayService.AccessToken.AccessToken == null)
			{
				throw new RelayServiceException(RelayExceptionReason.Unauthorized, "You are not signed in to the Authentication Service. Please sign in.");
			}
		}
	}
}
namespace Unity.Services.Relay.Scheduler
{
	internal static class EngineStateHelper
	{
		public static bool IsPlaying;

		[RuntimeInitializeOnLoadMethod(/*Could not decode attribute arguments.*/)]
		public static void Init()
		{
			IsPlaying = Application.isPlaying;
		}
	}
	public static class GameObjectFactory
	{
		public static GameObject CreateCoreSdkGameObject()
		{
			//IL_0024: 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_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected O, but got Unknown
			//IL_0037: Expected O, but got Unknown
			Random random = new Random();
			GameObject val = new GameObject("_SdkCore-" + random.Next(0, int.MaxValue));
			val.AddComponent<TaskSchedulerThreaded>();
			Object.DontDestroyOnLoad((Object)val);
			return val;
		}
	}
	public abstract class TaskScheduler : MonoBehaviour
	{
		public abstract void ScheduleBackgroundTask(Action task);

		public abstract bool IsMainThread();

		public abstract void ScheduleMainThreadTask(Action task);

		public void ScheduleOrExecuteOnMain(Action action)
		{
			if (IsMainThread())
			{
				action?.Invoke();
			}
			else
			{
				ScheduleMainThreadTask(action);
			}
		}
	}
	public sealed class TaskSchedulerThreaded : TaskScheduler
	{
		private Queue<Action> m_mainThreadTaskQueue = new Queue<Action>();

		private object m_lock = new object();

		private Thread m_mainThread;

		private void Start()
		{
			m_mainThread = Thread.CurrentThread;
		}

		public override bool IsMainThread()
		{
			return m_mainThread == Thread.CurrentThread;
		}

		public override void ScheduleBackgroundTask(Action task)
		{
			ThreadPool.QueueUserWorkItem(delegate
			{
				task();
			});
		}

		public override void ScheduleMainThreadTask(Action task)
		{
			lock (m_lock)
			{
				m_mainThreadTaskQueue.Enqueue(task);
			}
		}

		private void Update()
		{
			Queue<Action> queue = null;
			lock (m_lock)
			{
				queue = new Queue<Action>(m_mainThreadTaskQueue);
				m_mainThreadTaskQueue.Clear();
			}
			foreach (Action item in queue)
			{
				item();
			}
		}
	}
	public sealed class TaskSchedulerWebGL : TaskScheduler
	{
		private Queue<Action> m_mainThreadTaskQueue = new Queue<Action>();

		public override void ScheduleBackgroundTask(Action task)
		{
			ScheduleMainThreadTask(task);
		}

		public override bool IsMainThread()
		{
			return false;
		}

		public override void ScheduleMainThreadTask(Action task)
		{
			m_mainThreadTaskQueue.Enqueue(task);
		}

		private void Update()
		{
			((m_mainThreadTaskQueue.Count > 0) ? m_mainThreadTaskQueue.Dequeue() : null)?.Invoke();
		}
	}
	internal static class ThreadHelper
	{
		private static SynchronizationContext _unitySynchronizationContext;

		private static System.Threading.Tasks.TaskScheduler _taskScheduler;

		private static int _mainThreadId;

		public static SynchronizationContext SynchronizationContext => _unitySynchronizationContext;

		public static System.Threading.Tasks.TaskScheduler TaskScheduler => _taskScheduler;

		public static int MainThreadId => _mainThreadId;

		[RuntimeInitializeOnLoadMethod(/*Could not decode attribute arguments.*/)]
		public static void Init()
		{
			_unitySynchronizationContext = SynchronizationContext.Current;
			_taskScheduler = System.Threading.Tasks.TaskScheduler.FromCurrentSynchronizationContext();
			_mainThreadId = Thread.CurrentThread.ManagedThreadId;
		}
	}
}
namespace Unity.Services.Relay.Models
{
	[Preserve]
	[DataContract(Name = "AllocateResponseBody")]
	public class AllocateResponseBody
	{
		[Preserve]
		[DataMember(Name = "meta", IsRequired = true, EmitDefaultValue = true)]
		public ResponseMeta Meta { get; }

		[Preserve]
		[DataMember(Name = "links", EmitDefaultValue = false)]
		public ResponseLinks Links { get; }

		[Preserve]
		[DataMember(Name = "data", IsRequired = true, EmitDefaultValue = true)]
		public AllocationData Data { get; }

		[Preserve]
		public AllocateResponseBody(ResponseMeta meta, AllocationData data, ResponseLinks links = null)
		{
			Meta = meta;
			Links = links;
			Data = data;
		}

		internal string SerializeAsPathParam()
		{
			string text = "";
			if (Meta != null)
			{
				text = text + "meta," + Meta.ToString() + ",";
			}
			if (Links != null)
			{
				text = text + "links," + Links.ToString() + ",";
			}
			if (Data != null)
			{
				text = text + "data," + Data.ToString();
			}
			return text;
		}

		internal Dictionary<string, string> GetAsQueryParam()
		{
			return new Dictionary<string, string>();
		}
	}
	[Preserve]
	[DataContract(Name = "Allocation")]
	public class Allocation
	{
		[Preserve]
		[DataMember(Name = "allocationId", IsRequired = true, EmitDefaultValue = true)]
		public Guid AllocationId { get; }

		[Preserve]
		[DataMember(Name = "serverEndpoints", IsRequired = true, EmitDefaultValue = true)]
		public List<RelayServerEndpoint> ServerEndpoints { get; }

		[Preserve]
		[DataMember(Name = "relayServer", IsRequired = true, EmitDefaultValue = true)]
		public RelayServer RelayServer { get; }

		[Preserve]
		[DataMember(Name = "key", IsRequired = true, EmitDefaultValue = true)]
		public byte[] Key { get; }

		[Preserve]
		[DataMember(Name = "connectionData", IsRequired = true, EmitDefaultValue = true)]
		public byte[] ConnectionData { get; }

		[Preserve]
		[DataMember(Name = "allocationIdBytes", IsRequired = true, EmitDefaultValue = true)]
		public byte[] AllocationIdBytes { get; }

		[Preserve]
		[DataMember(Name = "region", IsRequired = true, EmitDefaultValue = true)]
		public string Region { get; }

		[Preserve]
		public Allocation(Guid allocationId, List<RelayServerEndpoint> serverEndpoints, RelayServer relayServer, byte[] key, byte[] connectionData, byte[] allocationIdBytes, string region)
		{
			AllocationId = allocationId;
			ServerEndpoints = serverEndpoints;
			RelayServer = relayServer;
			Key = key;
			ConnectionData = connectionData;
			AllocationIdBytes = allocationIdBytes;
			Region = region;
		}

		internal string SerializeAsPathParam()
		{
			string text = "";
			_ = AllocationId;
			text = text + "allocationId," + AllocationId.ToString() + ",";
			if (ServerEndpoints != null)
			{
				text = text + "serverEndpoints," + ServerEndpoints.ToString() + ",";
			}
			if (RelayServer != null)
			{
				text = text + "relayServer," + RelayServer.ToString() + ",";
			}
			if (Key != null)
			{
				text = text + "key," + Key.ToString() + ",";
			}
			if (ConnectionData != null)
			{
				text = text + "connectionData," + ConnectionData.ToString() + ",";
			}
			if (AllocationIdBytes != null)
			{
				text = text + "allocationIdBytes," + AllocationIdBytes.ToString() + ",";
			}
			if (Region != null)
			{
				text = text + "region," + Region;
			}
			return text;
		}

		internal Dictionary<string, string> GetAsQueryParam()
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			_ = AllocationId;
			string value = AllocationId.ToString();
			dictionary.Add("allocationId", value);
			if (Key != null)
			{
				string value2 = Key.ToString();
				dictionary.Add("key", value2);
			}
			if (ConnectionData != null)
			{
				string value3 = ConnectionData.ToString();
				dictionary.Add("connectionData", value3);
			}
			if (AllocationIdBytes != null)
			{
				string value4 = AllocationIdBytes.ToString();
				dictionary.Add("allocationIdBytes", value4);
			}
			if (Region != null)
			{
				string value5 = Region.ToString();
				dictionary.Add("region", value5);
			}
			return dictionary;
		}
	}
	[Preserve]
	[DataContract(Name = "AllocationData")]
	public class AllocationData
	{
		[Preserve]
		[DataMember(Name = "allocation", IsRequired = true, EmitDefaultValue = true)]
		public Allocation Allocation { get; }

		[Preserve]
		public AllocationData(Allocation allocation)
		{
			Allocation = allocation;
		}

		internal string SerializeAsPathParam()
		{
			string text = "";
			if (Allocation != null)
			{
				text = text + "allocation," + Allocation.ToString();
			}
			return text;
		}

		internal Dictionary<string, string> GetAsQueryParam()
		{
			return new Dictionary<string, string>();
		}
	}
	[Preserve]
	[DataContract(Name = "AllocationRequest")]
	public class AllocationRequest
	{
		[Preserve]
		[DataMember(Name = "maxConnections", IsRequired = true, EmitDefaultValue = true)]
		public int MaxConnections { get; }

		[Preserve]
		[DataMember(Name = "region", EmitDefaultValue = false)]
		public string Region { get; }

		[Preserve]
		public AllocationRequest(int maxConnections, string region = null)
		{
			MaxConnections = maxConnections;
			Region = region;
		}

		internal string SerializeAsPathParam()
		{
			string text = "";
			text = text + "maxConnections," + MaxConnections + ",";
			if (Region != null)
			{
				text = text + "region," + Region;
			}
			return text;
		}

		internal Dictionary<string, string> GetAsQueryParam()
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			string value = MaxConnections.ToString();
			dictionary.Add("maxConnections", value);
			if (Region != null)
			{
				string value2 = Region.ToString();
				dictionary.Add("region", value2);
			}
			return dictionary;
		}
	}
	[Preserve]
	[DataContract(Name = "ErrorResponseBody")]
	public class ErrorResponseBody
	{
		[Preserve]
		[DataMember(Name = "status", IsRequired = true, EmitDefaultValue = true)]
		public int Status { get; }

		[Preserve]
		[DataMember(Name = "detail", IsRequired = true, EmitDefaultValue = true)]
		public string Detail { get; }

		[Preserve]
		[DataMember(Name = "title", IsRequired = true, EmitDefaultValue = true)]
		public string Title { get; }

		[Preserve]
		[DataMember(Name = "details", EmitDefaultValue = false)]
		public List<KeyValuePair> Details { get; }

		[Preserve]
		[DataMember(Name = "type", IsRequired = true, EmitDefaultValue = true)]
		public string Type { get; }

		[Preserve]
		[DataMember(Name = "code", IsRequired = true, EmitDefaultValue = true)]
		public int Code { get; }

		[Preserve]
		public ErrorResponseBody(int status, string detail, string title, string type, int code, List<KeyValuePair> details = null)
		{
			Status = status;
			Detail = detail;
			Title = title;
			Details = details;
			Type = type;
			Code = code;
		}

		internal string SerializeAsPathParam()
		{
			string text = "";
			text = text + "status," + Status + ",";
			if (Detail != null)
			{
				text = text + "detail," + Detail + ",";
			}
			if (Title != null)
			{
				text = text + "title," + Title + ",";
			}
			if (Details != null)
			{
				text = text + "details," + Details.ToString() + ",";
			}
			if (Type != null)
			{
				text = text + "type," + Type + ",";
			}
			return text + "code," + Code;
		}

		internal Dictionary<string, string> GetAsQueryParam()
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			string value = Status.ToString();
			dictionary.Add("status", value);
			if (Detail != null)
			{
				string value2 = Detail.ToString();
				dictionary.Add("detail", value2);
			}
			if (Title != null)
			{
				string value3 = Title.ToString();
				dictionary.Add("title", value3);
			}
			if (Type != null)
			{
				string value4 = Type.ToString();
				dictionary.Add("type", value4);
			}
			string value5 = Code.ToString();
			dictionary.Add("code", value5);
			return dictionary;
		}
	}
	[Preserve]
	[DataContract(Name = "JoinAllocation")]
	public class JoinAllocation
	{
		[Preserve]
		[DataMember(Name = "allocationId", IsRequired = true, EmitDefaultValue = true)]
		public Guid AllocationId { get; }

		[Preserve]
		[DataMember(Name = "serverEndpoints", IsRequired = true, EmitDefaultValue = true)]
		public List<RelayServerEndpoint> ServerEndpoints { get; }

		[Preserve]
		[DataMember(Name = "relayServer", IsRequired = true, EmitDefaultValue = true)]
		public RelayServer RelayServer { get; }

		[Preserve]
		[DataMember(Name = "key", IsRequired = true, EmitDefaultValue = true)]
		public byte[] Key { get; }

		[Preserve]
		[DataMember(Name = "connectionData", IsRequired = true, EmitDefaultValue = true)]
		public byte[] ConnectionData { get; }

		[Preserve]
		[DataMember(Name = "allocationIdBytes", IsRequired = true, EmitDefaultValue = true)]
		public byte[] AllocationIdBytes { get; }

		[Preserve]
		[DataMember(Name = "region", IsRequired = true, EmitDefaultValue = true)]
		public string Region { get; }

		[Preserve]
		[DataMember(Name = "hostConnectionData", IsRequired = true, EmitDefaultValue = true)]
		public byte[] HostConnectionData { get; }

		[Preserve]
		public JoinAllocation(Guid allocationId, List<RelayServerEndpoint> serverEndpoints, RelayServer relayServer, byte[] key, byte[] connectionData, byte[] allocationIdBytes, string region, byte[] hostConnectionData)
		{
			AllocationId = allocationId;
			ServerEndpoints = serverEndpoints;
			RelayServer = relayServer;
			Key = key;
			ConnectionData = connectionData;
			AllocationIdBytes = allocationIdBytes;
			Region = region;
			HostConnectionData = hostConnectionData;
		}

		internal string SerializeAsPathParam()
		{
			string text = "";
			_ = AllocationId;
			text = text + "allocationId," + AllocationId.ToString() + ",";
			if (ServerEndpoints != null)
			{
				text = text + "serverEndpoints," + ServerEndpoints.ToString() + ",";
			}
			if (RelayServer != null)
			{
				text = text + "relayServer," + RelayServer.ToString() + ",";
			}
			if (Key != null)
			{
				text = text + "key," + Key.ToString() + ",";
			}
			if (ConnectionData != null)
			{
				text = text + "connectionData," + ConnectionData.ToString() + ",";
			}
			if (AllocationIdBytes != null)
			{
				text = text + "allocationIdBytes," + AllocationIdBytes.ToString() + ",";
			}
			if (Region != null)
			{
				text = text + "region," + Region + ",";
			}
			if (HostConnectionData != null)
			{
				text = text + "hostConnectionData," + HostConnectionData.ToString();
			}
			return text;
		}

		internal Dictionary<string, string> GetAsQueryParam()
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			_ = AllocationId;
			string value = AllocationId.ToString();
			dictionary.Add("allocationId", value);
			if (Key != null)
			{
				string value2 = Key.ToString();
				dictionary.Add("key", value2);
			}
			if (ConnectionData != null)
			{
				string value3 = ConnectionData.ToString();
				dictionary.Add("connectionData", value3);
			}
			if (AllocationIdBytes != null)
			{
				string value4 = AllocationIdBytes.ToString();
				dictionary.Add("allocationIdBytes", value4);
			}
			if (Region != null)
			{
				string value5 = Region.ToString();
				dictionary.Add("region", value5);
			}
			if (HostConnectionData != null)
			{
				string value6 = HostConnectionData.ToString();
				dictionary.Add("hostConnectionData", value6);
			}
			return dictionary;
		}
	}
	[Preserve]
	[DataContract(Name = "JoinAllocation_allOf")]
	public class JoinAllocationAllOf
	{
		[Preserve]
		[DataMember(Name = "hostConnectionData", IsRequired = true, EmitDefaultValue = true)]
		public byte[] HostConnectionData { get; }

		[Preserve]
		public JoinAllocationAllOf(byte[] hostConnectionData)
		{
			HostConnectionData = hostConnectionData;
		}

		internal string SerializeAsPathParam()
		{
			string text = "";
			if (HostConnectionData != null)
			{
				text = text + "hostConnectionData," + HostConnectionData.ToString();
			}
			return text;
		}

		internal Dictionary<string, string> GetAsQueryParam()
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			if (HostConnectionData != null)
			{
				string value = HostConnectionData.ToString();
				dictionary.Add("hostConnectionData", value);
			}
			return dictionary;
		}
	}
	[Preserve]
	[DataContract(Name = "JoinCodeData")]
	public class JoinCodeData
	{
		[Preserve]
		[DataMember(Name = "joinCode", IsRequired = true, EmitDefaultValue = true)]
		public string JoinCode { get; }

		[Preserve]
		public JoinCodeData(string joinCode)
		{
			JoinCode = joinCode;
		}

		internal string SerializeAsPathParam()
		{
			string text = "";
			if (JoinCode != null)
			{
				text = text + "joinCode," + JoinCode;
			}
			return text;
		}

		internal Dictionary<string, string> GetAsQueryParam()
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			if (JoinCode != null)
			{
				string value = JoinCode.ToString();
				dictionary.Add("joinCode", value);
			}
			return dictionary;
		}
	}
	[Preserve]
	[DataContract(Name = "JoinCodeRequest")]
	public class JoinCodeRequest
	{
		[Preserve]
		[DataMember(Name = "allocationId", IsRequired = true, EmitDefaultValue = true)]
		public Guid AllocationId { get; }

		[Preserve]
		public JoinCodeRequest(Guid allocationId)
		{
			AllocationId = allocationId;
		}

		internal string SerializeAsPathParam()
		{
			string text = "";
			_ = AllocationId;
			return text + "allocationId," + AllocationId;
		}

		internal Dictionary<string, string> GetAsQueryParam()
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			_ = AllocationId;
			string value = AllocationId.ToString();
			dictionary.Add("allocationId", value);
			return dictionary;
		}
	}
	[Preserve]
	[DataContract(Name = "JoinCodeResponseBody")]
	public class JoinCodeResponseBody
	{
		[Preserve]
		[DataMember(Name = "meta", IsRequired = true, EmitDefaultValue = true)]
		public ResponseMeta Meta { get; }

		[Preserve]
		[DataMember(Name = "links", IsRequired = true, EmitDefaultValue = true)]
		public ResponseLinks Links { get; }

		[Preserve]
		[DataMember(Name = "data", IsRequired = true, EmitDefaultValue = true)]
		public JoinCodeData Data { get; }

		[Preserve]
		public JoinCodeResponseBody(ResponseMeta meta, ResponseLinks links, JoinCodeData data)
		{
			Meta = meta;
			Links = links;
			Data = data;
		}

		internal string SerializeAsPathParam()
		{
			string text = "";
			if (Meta != null)
			{
				text = text + "meta," + Meta.ToString() + ",";
			}
			if (Links != null)
			{
				text = text + "links," + Links.ToString() + ",";
			}
			if (Data != null)
			{
				text = text + "data," + Data.ToString();
			}
			return text;
		}

		internal Dictionary<string, string> GetAsQueryParam()
		{
			return new Dictionary<string, string>();
		}
	}
	[Preserve]
	[DataContract(Name = "JoinData")]
	public class JoinData
	{
		[Preserve]
		[DataMember(Name = "allocation", IsRequired = true, EmitDefaultValue = true)]
		public JoinAllocation Allocation { get; }

		[Preserve]
		public JoinData(JoinAllocation allocation)
		{
			Allocation = allocation;
		}

		internal string SerializeAsPathParam()
		{
			string text = "";
			if (Allocation != null)
			{
				text = text + "allocation," + Allocation.ToString();
			}
			return text;
		}

		internal Dictionary<string, string> GetAsQueryParam()
		{
			return new Dictionary<string, string>();
		}
	}
	[Preserve]
	[DataContract(Name = "JoinRequest")]
	public class JoinRequest
	{
		[Preserve]
		[DataMember(Name = "joinCode", IsRequired = true, EmitDefaultValue = true)]
		public string JoinCode { get; }

		[Preserve]
		public JoinRequest(string joinCode)
		{
			JoinCode = joinCode;
		}

		internal string SerializeAsPathParam()
		{
			string text = "";
			if (JoinCode != null)
			{
				text = text + "joinCode," + JoinCode;
			}
			return text;
		}

		internal Dictionary<string, string> GetAsQueryParam()
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			if (JoinCode != null)
			{
				string value = JoinCode.ToString();
				dictionary.Add("joinCode", value);
			}
			return dictionary;
		}
	}
	[Preserve]
	[DataContract(Name = "JoinResponseBody")]
	public class JoinResponseBody
	{
		[Preserve]
		[DataMember(Name = "meta", IsRequired = true, EmitDefaultValue = true)]
		public ResponseMeta Meta { get; }

		[Preserve]
		[DataMember(Name = "data", IsRequired = true, EmitDefaultValue = true)]
		public JoinData Data { get; }

		[Preserve]
		public JoinResponseBody(ResponseMeta meta, JoinData data)
		{
			Meta = meta;
			Data = data;
		}

		internal string SerializeAsPathParam()
		{
			string text = "";
			if (Meta != null)
			{
				text = text + "meta," + Meta.ToString() + ",";
			}
			if (Data != null)
			{
				text = text + "data," + Data.ToString();
			}
			return text;
		}

		internal Dictionary<string, string> GetAsQueryParam()
		{
			return new Dictionary<string, string>();
		}
	}
	[Preserve]
	[DataContract(Name = "KeyValuePair")]
	public class KeyValuePair
	{
		[Preserve]
		[DataMember(Name = "key", IsRequired = true, EmitDefaultValue = true)]
		public string Key { get; }

		[Preserve]
		[DataMember(Name = "value", IsRequired = true, EmitDefaultValue = true)]
		public string Value { get; }

		[Preserve]
		public KeyValuePair(string key, string value)
		{
			Key = key;
			Value = value;
		}

		internal string SerializeAsPathParam()
		{
			string text = "";
			if (Key != null)
			{
				text = text + "key," + Key + ",";
			}
			if (Value != null)
			{
				text = text + "value," + Value;
			}
			return text;
		}

		internal Dictionary<string, string> GetAsQueryParam()
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			if (Key != null)
			{
				string value = Key.ToString();
				dictionary.Add("key", value);
			}
			if (Value != null)
			{
				string value2 = Value.ToString();
				dictionary.Add("value", value2);
			}
			return dictionary;
		}
	}
	[Preserve]
	[DataContract(Name = "Region")]
	public class Region
	{
		[Preserve]
		[DataMember(Name = "id", IsRequired = true, EmitDefaultValue = true)]
		public string Id { get; }

		[Preserve]
		[DataMember(Name = "description", IsRequired = true, EmitDefaultValue = true)]
		public string Description { get; }

		[Preserve]
		public Region(string id, string description)
		{
			Id = id;
			Description = description;
		}

		internal string SerializeAsPathParam()
		{
			string text = "";
			if (Id != null)
			{
				text = text + "id," + Id + ",";
			}
			if (Description != null)
			{
				text = text + "description," + Description;
			}
			return text;
		}

		internal Dictionary<string, string> GetAsQueryParam()
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			if (Id != null)
			{
				string value = Id.ToString();
				dictionary.Add("id", value);
			}
			if (Description != null)
			{
				string value2 = Description.ToString();
				dictionary.Add("description", value2);
			}
			return dictionary;
		}
	}
	[Preserve]
	[DataContract(Name = "RegionsData")]
	public class RegionsData
	{
		[Preserve]
		[DataMember(Name = "regions", IsRequired = true, EmitDefaultValue = true)]
		public List<Region> Regions { get; }

		[Preserve]
		public RegionsData(List<Region> regions)
		{
			Regions = regions;
		}

		internal string SerializeAsPathParam()
		{
			string text = "";
			if (Regions != null)
			{
				text = text + "regions," + Regions.ToString();
			}
			return text;
		}

		internal Dictionary<string, string> GetAsQueryParam()
		{
			return new Dictionary<string, string>();
		}
	}
	[Preserve]
	[DataContract(Name = "RegionsResponseBody")]
	public class RegionsResponseBody
	{
		[Preserve]
		[DataMember(Name = "data", IsRequired = true, EmitDefaultValue = true)]
		public RegionsData Data { get; }

		[Preserve]
		public RegionsResponseBody(RegionsData data)
		{
			Data = data;
		}

		internal string SerializeAsPathParam()
		{
			string text = "";
			if (Data != null)
			{
				text = text + "data," + Data.ToString();
			}
			return text;
		}

		internal Dictionary<string, string> GetAsQueryParam()
		{
			return new Dictionary<string, string>();
		}
	}
	public interface IOneOf
	{
		Type Type { get; }

		object Value { get; }
	}
	[Preserve]
	[DataContract(Name = "RelayServer")]
	public class RelayServer
	{
		[Preserve]
		[DataMember(Name = "ipV4", IsRequired = true, EmitDefaultValue = true)]
		public string IpV4 { get; }

		[Preserve]
		[DataMember(Name = "port", IsRequired = true, EmitDefaultValue = true)]
		public int Port { get; }

		[Preserve]
		public RelayServer(string ipV4, int port)
		{
			IpV4 = ipV4;
			Port = port;
		}

		internal string SerializeAsPathParam()
		{
			string text = "";
			if (IpV4 != null)
			{
				text = text + "ipV4," + IpV4 + ",";
			}
			return text + "port," + Port;
		}

		internal Dictionary<string, string> GetAsQueryParam()
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			if (IpV4 != null)
			{
				string value = IpV4.ToString();
				dictionary.Add("ipV4", value);
			}
			string value2 = Port.ToString();
			dictionary.Add("port", value2);
			return dictionary;
		}
	}
	[Preserve]
	[DataContract(Name = "RelayServerEndpoint")]
	public class RelayServerEndpoint
	{
		[Preserve]
		[JsonConverter(typeof(StringEnumConverter))]
		public enum NetworkOptions
		{
			[EnumMember(Value = "udp")]
			Udp = 1,
			[EnumMember(Value = "tcp")]
			Tcp
		}

		public const string ConnectionTypeUdp = "udp";

		public const string ConnectionTypeDtls = "dtls";

		public const string ConnectionTypeWss = "wss";

		[Preserve]
		[DataMember(Name = "connectionType", IsRequired = true, EmitDefaultValue = true)]
		public string ConnectionType { get; }

		[Preserve]
		[JsonConverter(typeof(StringEnumConverter))]
		[DataMember(Name = "network", IsRequired = true, EmitDefaultValue = true)]
		public NetworkOptions Network { get; }

		[Preserve]
		[DataMember(Name = "reliable", IsRequired = true, EmitDefaultValue = true)]
		public bool Reliable { get; }

		[Preserve]
		[DataMember(Name = "secure", IsRequired = true, EmitDefaultValue = true)]
		public bool Secure { get; }

		[Preserve]
		[DataMember(Name = "host", IsRequired = true, EmitDefaultValue = true)]
		public string Host { get; }

		[Preserve]
		[DataMember(Name = "port", IsRequired = true, EmitDefaultValue = true)]
		public int Port { get; }

		[Preserve]
		public RelayServerEndpoint(string connectionType, NetworkOptions network, bool reliable, bool secure, string host, int port)
		{
			ConnectionType = connectionType;
			Network = network;
			Reliable = reliable;
			Secure = secure;
			Host = host;
			Port = port;
		}

		internal string SerializeAsPathParam()
		{
			string text = "";
			if (ConnectionType != null)
			{
				text = text + "connectionType," + ConnectionType + ",";
			}
			text = text + "network," + Network.ToString() + ",";
			text = text + "reliable," + Reliable + ",";
			text = text + "secure," + Secure + ",";
			if (Host != null)
			{
				text = text + "host," + Host + ",";
			}
			return text + "port," + Port;
		}

		internal Dictionary<string, string> GetAsQueryParam()
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			if (ConnectionType != null)
			{
				string value = ConnectionType.ToString();
				dictionary.Add("connectionType", value);
			}
			string value2 = Network.ToString();
			dictionary.Add("network", value2);
			string value3 = Reliable.ToString();
			dictionary.Add("reliable", value3);
			string value4 = Secure.ToString();
			dictionary.Add("secure", value4);
			if (Host != null)
			{
				string value5 = Host.ToString();
				dictionary.Add("host", value5);
			}
			string value6 = Port.ToString();
			dictionary.Add("port", value6);
			return dictionary;
		}
	}
	[Preserve]
	[DataContract(Name = "ResponseLinks")]
	public class ResponseLinks
	{
		[Preserve]
		[DataMember(Name = "next", EmitDefaultValue = false)]
		public string Next { get; }

		[Preserve]
		public ResponseLinks(string next = null)
		{
			Next = next;
		}

		internal string SerializeAsPathParam()
		{
			string text = "";
			if (Next != null)
			{
				text = text + "next," + Next;
			}
			return text;
		}

		internal Dictionary<string, string> GetAsQueryParam()
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			if (Next != null)
			{
				string value = Next.ToString();
				dictionary.Add("next", value);
			}
			return dictionary;
		}
	}
	[Preserve]
	[DataContract(Name = "ResponseMeta")]
	public class ResponseMeta
	{
		[Preserve]
		[DataMember(Name = "requestId", IsRequired = true, EmitDefaultValue = true)]
		public string RequestId { get; }

		[Preserve]
		[DataMember(Name = "status", IsRequired = true, EmitDefaultValue = true)]
		public int Status { get; }

		[Preserve]
		public ResponseMeta(string requestId, int status)
		{
			RequestId = requestId;
			Status = status;
		}

		internal string SerializeAsPathParam()
		{
			string text = "";
			if (RequestId != null)
			{
				text = text + "requestId," + RequestId + ",";
			}
			return text + "status," + Status;
		}

		internal Dictionary<string, string> GetAsQueryParam()
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			if (RequestId != null)
			{
				string value = RequestId.ToString();
				dictionary.Add("requestId", value);
			}
			string value2 = Status.ToString();
			dictionary.Add("status", value2);
			return dictionary;
		}
	}
}
namespace Unity.Services.Relay.Http
{
	internal abstract class BaseApiClient
	{
		protected readonly IHttpClient HttpClient;

		public BaseApiClient(IHttpClient httpClient)
		{
			HttpClient = httpClient ?? new HttpClient();
		}
	}
	[Serializable]
	internal class DeserializationException : Exception
	{
		public DeserializationException()
		{
		}

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

		private DeserializationException(string message, Exception inner)
			: base(message, inner)
		{
		}
	}
	public enum MissingMemberHandling
	{
		Error,
		Ignore
	}
	public class DeserializationSettings
	{
		public MissingMemberHandling MissingMemberHandling;
	}
	internal class HttpClient : IHttpClient
	{
		public async Task<HttpClientResponse> MakeRequestAsync(string method, string url, byte[] body, Dictionary<string, string> headers, int requestTimeout)
		{
			return await CreateWebRequestAsync(method.ToUpper(), url, body, headers, requestTimeout);
		}

		public async Task<HttpClientResponse> MakeRequestAsync(string method, string url, List<IMultipartFormSection> body, Dictionary<string, string> headers, int requestTimeout, string boundary = null)
		{
			return await CreateWebRequestAsync(method.ToUpper(), url, body, headers, requestTimeout, boundary);
		}

		private async Task<HttpClientResponse> CreateWebRequestAsync(string method, string url, byte[] body, IDictionary<string, string> headers, int requestTimeout)
		{
			return await CreateHttpClientResponse(method, url, body, headers, requestTimeout);
		}

		private async Task<HttpClientResponse> CreateHttpClientResponse(string method, string url, byte[] body, IDictionary<string, string> headers, int requestTimeout)
		{
			return await (await Task.Factory.StartNew(async delegate
			{
				UnityWebRequest request = new UnityWebRequest(url, method);
				try
				{
					foreach (KeyValuePair<string, string> header in headers)
					{
						request.SetRequestHeader(header.Key, header.Value);
					}
					request.timeout = requestTimeout;
					if (body != null && (method == "POST" || method == "PUT" || method == "PATCH"))
					{
						request.uploadHandler = (UploadHandler)new UploadHandlerRaw(body);
					}
					request.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
					return await SendWebRequest(request);
				}
				finally
				{
					((IDisposable)request)?.Dispose();
				}
			}, CancellationToken.None, TaskCreationOptions.None, ThreadHelper.TaskScheduler));
		}

		private async Task<HttpClientResponse> CreateWebRequestAsync(string method, string url, List<IMultipartFormSection> body, IDictionary<string, string> headers, int requestTimeout, string boundary = null)
		{
			return await (await Task.Factory.StartNew(async delegate
			{
				byte[] boundary2 = (string.IsNullOrEmpty(boundary) ? UnityWebRequest.GenerateBoundary() : Encoding.Default.GetBytes(boundary));
				UnityWebRequest val = new UnityWebRequest(url, method);
				foreach (KeyValuePair<string, string> header in headers)
				{
					val.SetRequestHeader(header.Key, header.Value);
				}
				val.timeout = requestTimeout;
				val = SetupMultipartRequest(val, body, boundary2);
				val.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
				return await SendWebRequest(val);
			}, CancellationToken.None, TaskCreationOptions.None, ThreadHelper.TaskScheduler));
		}

		private static UnityWebRequest SetupMultipartRequest(UnityWebRequest request, List<IMultipartFormSection> multipartFormSections, byte[] boundary)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			byte[] array = null;
			if (multipartFormSections != null && multipartFormSections.Count != 0)
			{
				array = UnityWebRequest.SerializeFormSections(multipartFormSections, boundary);
			}
			UploadHandler val = (UploadHandler)new UploadHandlerRaw(array);
			val.contentType = "multipart/form-data; boundary=" + Encoding.UTF8.GetString(boundary, 0, boundary.Length);
			request.uploadHandler = val;
			request.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
			return request;
		}

		private UnityWebRequestAsyncOperation SendWebRequest(UnityWebRequest request)
		{
			return request.SendWebRequest();
		}
	}
	internal class HttpClientResponse
	{
		public Dictionary<string, string> Headers { get; }

		public long StatusCode { get; }

		public bool IsHttpError { get; }

		public bool IsNetworkError { get; }

		public byte[] Data { get; }

		public string ErrorMessage { get; }

		public HttpClientResponse(Dictionary<string, string> headers, long statusCode, bool isHttpError, bool isNetworkError, byte[] data, string errorMessage)
		{
			Headers = headers;
			StatusCode = statusCode;
			IsHttpError = isHttpError;
			IsNetworkError = isNetworkError;
			Data = data;
			ErrorMessage = errorMessage;
		}
	}
	[Serializable]
	[Preserve]
	internal class HttpException : Exception
	{
		[Preserve]
		public HttpClientResponse Response;

		[Preserve]
		public HttpException()
		{
		}

		[Preserve]
		public HttpException(string message)
			: base(message)
		{
		}

		[Preserve]
		public HttpException(string message, Exception inner)
			: base(message, inner)
		{
		}

		[Preserve]
		public HttpException(HttpClientResponse response)
			: base($"({response.StatusCode}) {response.ErrorMessage}")
		{
			Response = response;
		}
	}
	[Serializable]
	[Preserve]
	internal class HttpException<T> : HttpException
	{
		[Preserve]
		public T ActualError;

		[Preserve]
		public HttpException()
		{
		}

		[Preserve]
		public HttpException(string message)
			: base(message)
		{
		}

		[Preserve]
		public HttpException(string message, Exception inner)
			: base(message, inner)
		{
		}

		[Preserve]
		public HttpException(HttpClientResponse response, T actualError)
			: base(response)
		{
			ActualError = actualError;
		}
	}
	[Preserve]
	[JsonConverter(typeof(JsonObjectConverter))]
	internal interface IDeserializable
	{
		string GetAsString();

		T GetAs<T>(DeserializationSettings deserializationSettings = null);
	}
	internal interface IHttpClient
	{
		Task<HttpClientResponse> MakeRequestAsync(string method, string url, byte[] body, Dictionary<string, string> headers, int requestTimeout);

		Task<HttpClientResponse> MakeRequestAsync(string method, string url, List<IMultipartFormSection> body, Dictionary<string, string> headers, int requestTimeout, string boundary = null);
	}
	internal static class JsonHelpers
	{
		[RuntimeInitializeOnLoadMethod(/*Could not decode attribute arguments.*/)]
		internal static void RegisterTypesForAOT()
		{
			AotHelper.EnsureType<StringEnumConverter>();
			AotHelper.EnsureType<JsonObjectConverter>();
		}

		internal static bool TryParseJson<T>(this string @this, out T result)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: 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_0033: Expected O, but got Unknown
			bool success = true;
			JsonSerializerSettings val = new JsonSerializerSettings
			{
				Error = delegate(object sender, ErrorEventArgs args)
				{
					success = false;
					args.ErrorContext.Handled = true;
				},
				MissingMemberHandling = (MissingMemberHandling)0,
				ReferenceLoopHandling = (ReferenceLoopHandling)1
			};
			result = JsonConvert.DeserializeObject<T>(@this, val);
			return success;
		}
	}
	[Preserve]
	[JsonConverter(typeof(JsonObjectConverter))]
	internal class JsonObject : IDeserializable
	{
		[Preserve]
		internal object obj;

		[Preserve]
		internal JsonObject(object obj)
		{
			this.obj = obj;
		}

		public string GetAsString()
		{
			try
			{
				if (obj == null)
				{
					return "";
				}
				if (obj.GetType() == typeof(string))
				{
					return obj.ToString();
				}
				return JsonConvert.SerializeObject(obj);
			}
			catch (Exception)
			{
				throw new InvalidOperationException("Failed to convert JsonObject to string.");
			}
		}

		public T GetAs<T>(DeserializationSettings deserializationSettings = null)
		{
			//IL_0065: Expected O, but got Unknown
			//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_0024: Expected O, but got Unknown
			deserializationSettings = deserializationSettings ?? new DeserializationSettings();
			JsonSerializerSettings val = new JsonSerializerSettings
			{
				MissingMemberHandling = (MissingMemberHandling)(deserializationSettings.MissingMemberHandling == MissingMemberHandling.Error)
			};
			try
			{
				T val2 = JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(obj), val);
				List<string> list = ValidateObject(val2);
				if (list.Count > 0)
				{
					throw new DeserializationException(string.Join("\n", list));
				}
				return val2;
			}
			catch (DeserializationException)
			{
				throw;
			}
			catch (JsonSerializationException ex2)
			{
				throw new DeserializationException(((Exception)ex2).Message);
			}
			catch (Exception)
			{
				throw new DeserializationException("Unable to deserialize object.");
			}
		}

		public T GetAs<T>()
		{
			return GetAs<T>(null);
		}

		public static IDeserializable GetNewJsonObjectResponse(object o)
		{
			return new JsonObject(o);
		}

		public static List<IDeserializable> GetNewJsonObjectResponse(List<object> o)
		{
			return o?.Select((Func<object, IDeserializable>)((object v) => new JsonObject(v))).ToList();
		}

		public static List<List<IDeserializable>> GetNewJsonObjectResponse(List<List<object>> o)
		{
			return o?.Select((List<object> l) => ((IEnumerable<object>)l).Select((Func<object, IDeserializable>)((object v) => (v != null) ? new JsonObject(v) : null)).ToList()).ToList();
		}

		public static Dictionary<string, IDeserializable> GetNewJsonObjectResponse(Dictionary<string, object> o)
		{
			return o?.ToDictionary((Func<KeyValuePair<string, object>, string>)((KeyValuePair<string, object> kv) => kv.Key), (Func<KeyValuePair<string, object>, IDeserializable>)((KeyValuePair<string, object> kv) => new JsonObject(kv.Value)));
		}

		public static Dictionary<string, List<IDeserializable>> GetNewJsonObjectResponse(Dictionary<string, List<object>> o)
		{
			return o?.ToDictionary((KeyValuePair<string, List<object>> kv) => kv.Key, (KeyValuePair<string, List<object>> kv) => GetNewJsonObjectResponse(kv.Value));
		}

		private List<string> ValidateObject<T>(T objectToCheck, List<string> errors = null)
		{
			if (errors == null)
			{
				errors = new List<string>();
			}
			if (objectToCheck != null)
			{
				if (typeof(IEnumerable).IsAssignableFrom(typeof(T)))
				{
					foreach (object item in (IEnumerable)(object)objectToCheck)
					{
						ValidateFieldInfos(item, errors);
						ValidatePropertyInfos(item, errors);
					}
				}
				else
				{
					ValidateFieldInfos(objectToCheck, errors);
					ValidatePropertyInfos(objectToCheck, errors);
				}
			}
			return errors;
		}

		private void ValidatePropertyInfos<T>(T objectToCheck, List<string> errors)
		{
			PropertyInfo[] properties = objectToCheck.GetType().GetProperties();
			foreach (PropertyInfo propertyInfo in properties)
			{
				if (propertyInfo.GetIndexParameters().Length != 0)
				{
					for (int j = 0; j < propertyInfo.GetIndexParameters().Length; j++)
					{
						object value = propertyInfo.GetValue(objectToCheck, new object[1] { j });
						string name = propertyInfo.Name;
						string name2 = objectToCheck.GetType().Name;
						ValidateValue(value, name2, "Property", name, errors);
					}
				}
				else
				{
					object value2 = propertyInfo.GetValue(objectToCheck);
					string name3 = propertyInfo.Name;
					string name4 = objectToCheck.GetType().Name;
					ValidateValue(value2, name4, "Property", name3, errors);
				}
			}
		}

		private void ValidateFieldInfos<T>(T objectToCheck, List<string> errors)
		{
			FieldInfo[] fields = objectToCheck.GetType().GetFields();
			foreach (FieldInfo obj in fields)
			{
				object value = obj.GetValue(objectToCheck);
				string name = obj.Name;
				string name2 = objectToCheck.GetType().Name;
				ValidateValue(value, name2, "Field", name, errors);
			}
		}

		private void ValidateValue(object value, string objectName, string memberType, string memberName, List<string> errors)
		{
			if (!(value is ValueType) && !(value is string))
			{
				if (value is JObject)
				{
					errors.Add(memberType + ": \"" + memberName + "\" on Type: \"" + objectName + "\" must not be of type `object` or `dynamic`");
				}
				else
				{
					ValidateObject(value, errors);
				}
			}
		}
	}
	[Preserve]
	internal class JsonObjectConverter : JsonConverter
	{
		public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
		{
			JsonObject jsonObject = (JsonObject)value;
			if (jsonObject.obj == null)
			{
				writer.WriteNull();
			}
			else
			{
				JToken.FromObject(jsonObject.obj).WriteTo(writer, Array.Empty<JsonConverter>());
			}
		}

		public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Invalid comparison between Unknown and I4
			if ((int)reader.TokenType != 11)
			{
				if (reader.Value != null)
				{
					return new JsonObject(reader.Value);
				}
				try
				{
					return new JsonObject(JObject.Load(reader));
				}
				catch (JsonReaderException)
				{
					return new JsonObject(JArray.Load(reader));
				}
			}
			return new JsonObject(null);
		}

		public override bool CanConvert(Type objectType)
		{
			throw new NotImplementedException();
		}
	}
	[Preserve]
	internal class JsonObjectCollectionConverter : JsonConverter
	{
		public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
		{
			object obj = value;
			Type type = value.GetType();
			if (type == typeof(Dictionary<string, IDeserializable>))
			{
				obj = (Dictionary<string, IDeserializable>)value;
			}
			else if (type == typeof(List<IDeserializable>))
			{
				obj = (List<IDeserializable>)value;
			}
			else if (type == typeof(List<List<IDeserializable>>))
			{
				obj = (List<List<IDeserializable>>)value;
			}
			if (obj == null)
			{
				writer.WriteNull();
			}
			else
			{
				JToken.FromObject(obj).WriteTo(writer, Array.Empty<JsonConverter>());
			}
		}

		public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Invalid comparison between Unknown and I4
			if ((int)reader.TokenType != 11)
			{
				List<object> obj = (List<object>)reader.Value;
				List<JsonObject> list = new List<JsonObject>();
				{
					foreach (object item in obj)
					{
						list.Add(new JsonObject(item));
					}
					return list;
				}
			}
			return null;
		}

		public override bool CanConvert(Type objectType)
		{
			throw new NotImplementedException();
		}
	}
	[Serializable]
	internal class ResponseDeserializationException : Exception
	{
		public HttpClientResponse response;

		public ResponseDeserializationException()
		{
		}

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

		private ResponseDeserializationException(Exception inner, string message)
			: base(message, inner)
		{
		}

		public ResponseDeserializationException(HttpClientResponse httpClientResponse)
			: base("Unable to Deserialize Http Client Response")
		{
			response = httpClientResponse;
		}

		public ResponseDeserializationException(HttpClientResponse httpClientResponse, string message)
			: base(message)
		{
			response = httpClientResponse;
		}

		public ResponseDeserializationException(HttpClientResponse httpClientResponse, Exception inner, string message)
			: base(message, inner)
		{
			response = httpClientResponse;
		}
	}
	internal static class ResponseHandler
	{
		private static List<IDeserializable> DeserializeListOfJsonObjects(List<object> objectList)
		{
			List<IDeserializable> list = new List<IDeserializable>();
			foreach (object @object in objectList)
			{
				list.Add(new JsonObject(@object));
			}
			return list;
		}

		public static T TryDeserializeResponse<T>(HttpClientResponse response)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: 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_0014: Expected O, but got Unknown
			JsonSerializerSettings val = new JsonSerializerSettings
			{
				MissingMemberHandling = (MissingMemberHandling)0,
				ReferenceLoopHandling = (ReferenceLoopHandling)1
			};
			try
			{
				return JsonConvert.DeserializeObject<T>(GetDeserializedJson(response.Data), val);
			}
			catch (Exception ex)
			{
				throw new ResponseDeserializationException(response, ex, ex.Message);
			}
		}

		public static object TryDeserializeResponse(HttpClientResponse response, Type type)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: 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_0014: Expected O, but got Unknown
			JsonSerializerSettings val = new JsonSerializerSettings
			{
				MissingMemberHandling = (MissingMemberHandling)0,
				ReferenceLoopHandling = (ReferenceLoopHandling)1
			};
			try
			{
				return JsonConvert.DeserializeObject(GetDeserializedJson(response.Data), type, val);
			}
			catch (Exception ex)
			{
				throw new ResponseDeserializationException(response, ex, ex.Message);
			}
		}

		private static string GetDeserializedJson(byte[] data)
		{
			return Encoding.UTF8.GetString(data);
		}

		public static void HandleAsyncResponse(HttpClientResponse response, Dictionary<string, Type> statusCodeToTypeMap)
		{
			if (statusCodeToTypeMap.ContainsKey(response.StatusCode.ToString()))
			{
				Type type = statusCodeToTypeMap[response.StatusCode.ToString()];
				if ((type != null && response.IsHttpError) || response.IsNetworkError)
				{
					if (typeof(IOneOf).IsAssignableFrom(type))
					{
						throw CreateOneOfException(response, type);
					}
					throw CreateHttpException(response, type);
				}
				return;
			}
			throw new HttpException(response);
		}

		private static HttpException CreateOneOfException(HttpClientResponse response, Type responseType)
		{
			try
			{
				object obj = TryDeserializeResponse(response, responseType);
				return CreateHttpException(response, ((IOneOf)obj).Type);
			}
			catch (ArgumentException ex)
			{
				throw new ResponseDeserializationException(response, ex, ex.Message);
			}
			catch (MissingFieldException inner)
			{
				throw new ResponseDeserializationException(response, inner, "Discriminator field not found in the parsed json response.");
			}
			catch (ResponseDeserializationException ex2)
			{
				if (ex2.InnerException.GetType() == typeof(MissingFieldException))
				{
					throw new ResponseDeserializationException(response, ex2.InnerException, "Discriminator field not found in the parsed json response.");
				}
				if (ex2.response == null)
				{
					throw new ResponseDeserializationException(response, ex2.Message);
				}
				throw;
			}
			catch (Exception ex3)
			{
				throw new ResponseDeserializationException(response, ex3, ex3.Message);
			}
		}

		private static HttpException CreateHttpException(HttpClientResponse response, Type responseType)
		{
			Type type = typeof(HttpException<>).MakeGenericType(responseType);
			try
			{
				if (responseType == typeof(Stream))
				{
					object obj = ((response.Data == null) ? new MemoryStream() : new MemoryStream(response.Data));
					return (HttpException)Activator.CreateInstance(type, response, obj);
				}
				object obj2 = TryDeserializeResponse(response, responseType);
				return (HttpException)Activator.CreateInstance(type, response, obj2);
			}
			catch (ArgumentException ex)
			{
				throw new ResponseDeserializationException(response, ex, ex.Message);
			}
			catch (MissingFieldException inner)
			{
				throw new ResponseDeserializationException(response, inner, "Discriminator field not found in the parsed json response.");
			}
			catch (ResponseDeserializationException ex2)
			{
				if (ex2.response == null)
				{
					throw new ResponseDeserializationException(response, ex2.Message);
				}
				throw;
			}
			catch (Exception ex3)
			{
				throw new ResponseDeserializationException(response, ex3, ex3.Message);
			}
		}

		public static T HandleAsyncResponse<T>(HttpClientResponse response, Dictionary<string, Type> statusCodeToTypeMap) where T : class
		{
			HandleAsyncResponse(response, statusCodeToTypeMap);
			try
			{
				if (statusCodeToTypeMap[response.StatusCode.ToString()] == typeof(Stream))
				{
					return ((response.Data == null) ? new MemoryStream() : new MemoryStream(response.Data)) as T;
				}
				return TryDeserializeResponse<T>(response);
			}
			catch (ArgumentException ex)
			{
				throw new ResponseDeserializationException(response, ex.Message);
			}
			catch (MissingFieldException inner)
			{
				throw new ResponseDeserializationException(response, inner, "Discriminator field not found in the parsed json response.");
			}
			catch (ResponseDeserializationException ex2)
			{
				if (ex2.response == null)
				{
					throw new ResponseDeserializationException(response, ex2.Message);
				}
				throw;
			}
			catch (Exception ex3)
			{
				throw new ResponseDeserializationException(response, ex3, ex3.Message);
			}
		}
	}
	internal static class UnityWebRequestHelpers
	{
		public static TaskAwaiter<HttpClientResponse> GetAwaiter(this UnityWebRequestAsyncOperation asyncOp)
		{
			TaskCompletionSource<HttpClientResponse> tcs = new TaskCompletionSource<HttpClientResponse>();
			((AsyncOperation)asyncOp).completed += delegate(AsyncOperation obj)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_000b: Expected O, but got Unknown
				HttpClientResponse result = CreateHttpClientResponse((UnityWebRequestAsyncOperation)obj);
				tcs.SetResult(result);
			};
			return tcs.Task.GetAwaiter();
		}

		internal static HttpClientResponse CreateHttpClientResponse(UnityWebRequestAsyncOperation unityResponse)
		{
			UnityWebRequest webRequest = unityResponse.webRequest;
			return new HttpClientResponse(webRequest.GetResponseHeaders(), webRequest.responseCode, webRequest.isHttpError, webRequest.isNetworkError, webRequest.downloadHandler.data, webRequest.error);
		}
	}
}
namespace Unity.Services.Relay.Helpers
{
	internal static class AsyncOpRetry
	{
		public static AsyncOpRetry<T> FromCreateAsync<T>(Func<int, T> op)
		{
			return AsyncOpRetry<T>.FromCreateAsync(op);
		}
	}
	internal class AsyncOpRetry<T>
	{
		private uint MaxRetries { get; set; } = 4u;

		private float JitterMagnitude { get; set; } = 1f;

		private float DelayScale { get; set; } = 1f;

		private float MaxDelayTime { get; set; } = 8f;

		private Func<int, T> CreateOperation { get; set; }

		private Func<T, bool> RetryCondition { get; set; }

		private Action<T> OnComplete { get; set; }

		private AsyncOpRetry(Func<int, T> createAsyncOp)
		{
			CreateOperation = createAsyncOp;
		}

		private static float AddJitter(float number, float magnitude)
		{
			return number + Random.value * magnitude;
		}

		private static float Pow2(float exponent, float scale)
		{
			return (float)(Math.Pow(2.0, exponent) * (double)scale);
		}

		private static float CalculateDelay(int attemptNumber, float maxDelayTime, float delayScale, float jitterMagnitude)
		{
			return Math.Min(AddJitter(Pow2(attemptNumber, delayScale), jitterMagnitude), maxDelayTime);
		}

		public static AsyncOpRetry<T> FromCreateAsync(Func<int, T> op)
		{
			return new AsyncOpRetry<T>(op);
		}

		public AsyncOpRetry<T> WithRetryCondition(Func<T, bool> shouldRetry)
		{
			RetryCondition = shouldRetry;
			return this;
		}

		public AsyncOpRetry<T> WhenComplete(Action<T> onComplete)
		{
			OnComplete = onComplete;
			return this;
		}

		public IEnumerator Run()
		{
			T asyncOp = default(T);
			int attempt = 0;
			while (attempt <= MaxRetries)
			{
				asyncOp = CreateOperation(attempt + 1);
				yield return asyncOp;
				Func<T, bool> retryCondition = RetryCondition;
				if (retryCondition != null && !retryCondition(asyncOp))
				{
					break;
				}
				float num = CalculateDelay(attempt, MaxDelayTime, DelayScale, JitterMagnitude);
				yield return (object)new WaitForSecondsRealtime(num);
				int num2 = attempt + 1;
				attempt = num2;
			}
			OnComplete?.Invoke(asyncOp);
		}
	}
}
namespace Unity.Services.Relay.ErrorMitigation
{
	internal interface IRetryPolicyProvider
	{
		IRetryPolicy<T> ForOperation<T>(Func<int, Task<T>> operation);

		IRetryPolicy<T> ForOperation<T>(Func<Task<T>> operation);
	}
	internal interface IRetryPolicy<T>
	{
		IRetryPolicy<T> WithJitterMagnitude(float magnitude);

		IRetryPolicy<T> WithDelayScale(float scale);

		IRetryPolicy<T> WithMaxDelayTime(float time);

		IRetryPolicy<T> WithRetryCondition(Func<T, Task<bool>> shouldRetry);

		IRetryPolicy<T> UptoMaximumRetries(uint amount);

		IRetryPolicy<T> HandleException<TException>() where TException : Exception;

		IRetryPolicy<T> HandleException<TException>(Func<TException, bool> condition) where TException : Exception;

		Task<T> RunAsync(RetryPolicyConfig retryPolicyConfig = null);
	}
	internal class RetryPolicyProvider : IRetryPolicyProvider
	{
		public IRetryPolicy<T> ForOperation<T>(Func<int, Task<T>> operation)
		{
			return RetryPolicy<T>.ForOperation(operation);
		}

		public IRetryPolicy<T> ForOperation<T>(Func<Task<T>> operation)
		{
			return RetryPolicy<T>.ForOperation(operation);
		}
	}
	internal class RetryPolicy<T> : IRetryPolicy<T>
	{
		private RetryPolicyConfig _retryPolicyConfig = new RetryPolicyConfig();

		private Func<int, Task<T>> CreateOperation { get; set; }

		private Func<T, Task<bool>> RetryCondition { get; set; }

		private RetryPolicy(Func<int, Task<T>> createAsyncOp)
		{
			CreateOperation = createAsyncOp;
		}

		private RetryPolicy(Func<Task<T>> createAsyncOp)
		{
			CreateOperation = (int _) => createAsyncOp();
		}

		private static float AddJitter(float number, float magnitude)
		{
			return number + Random.value * magnitude;
		}

		private static float Pow2(float exponent, float scale)
		{
			return (float)(Math.Pow(2.0, exponent) * (double)scale);
		}

		private static float CalculateDelay(int attemptNumber, float maxDelayTime, float delayScale, float jitterMagnitude)
		{
			return Math.Min(AddJitter(Pow2(attemptNumber, delayScale), jitterMagnitude), maxDelayTime);
		}

		public IRetryPolicy<T> WithJitterMagnitude(float magnitude)
		{
			_retryPolicyConfig.JitterMagnitude = magnitude;
			return this;
		}

		public IRetryPolicy<T> WithDelayScale(float scale)
		{
			_retryPolicyConfig.DelayScale = scale;
			return this;
		}

		public IRetryPolicy<T> WithMaxDelayTime(float time)
		{
			_retryPolicyConfig.MaxDelayTime = time;
			return this;
		}

		public static RetryPolicy<T> ForOperation(Func<int, Task<T>> operation)
		{
			return new RetryPolicy<T>(operation);
		}

		public static RetryPolicy<T> ForOperation(Func<Task<T>> operation)
		{
			return new RetryPolicy<T>(operation);
		}

		public IRetryPolicy<T> WithRetryCondition(Func<T, Task<bool>> shouldRetry)
		{
			RetryCondition = shouldRetry;
			return this;
		}

		public IRetryPolicy<T> UptoMaximumRetries(uint amount)
		{
			_retryPolicyConfig.MaxRetries = amount;
			return this;
		}

		public IRetryPolicy<T> HandleException<TException>() where TException : Exception
		{
			_retryPolicyConfig.HandleException<TException>();
			return this;
		}

		public IRetryPolicy<T> HandleException<TException>(Func<TException, bool> condition) where TException : Exception
		{
			_retryPolicyConfig.HandleException(condition);
			return this;
		}

		public async Task<T> RunAsync(RetryPolicyConfig retryPolicyConfig = null)
		{
			T opResult = default(T);
			if (retryPolicyConfig == null)
			{
				retryPolicyConfig = _retryPolicyConfig;
			}
			int attempt = 0;
			while (attempt <= retryPolicyConfig.MaxRetries)
			{
				try
				{
					opResult = await CreateOperation(attempt + 1);
				}
				catch (Exception e)
				{
					if (!retryPolicyConfig.IsHandledException(e))
					{
						throw;
					}
				}
				if (RetryCondition != null && opResult != null)
				{
					if (!(await RetryCondition(opResult)))
					{
						break;
					}
				}
				else if (opResult != null)
				{
					break;
				}
				await Task.Delay((int)(CalculateDelay(attempt, retryPolicyConfig.MaxDelayTime, retryPolicyConfig.DelayScale, retryPolicyConfig.JitterMagnitude) * 1000f));
				int num = attempt + 1;
				attempt = num;
			}
			return opResult;
		}
	}
	internal delegate Exception ExceptionPredicate(Exception ex);
	internal class RetryPolicyConfig
	{
		private float _jitterMagnitude = 1f;

		private float _delayScale = 1f;

		private float _maxDelayTime = 8f;

		private List<ExceptionPredicate> _exceptionsToHandle = new List<ExceptionPredicate>();

		public uint MaxRetries { get; set; } = 4u;

		public float JitterMagnitude
		{
			get
			{
				return _jitterMagnitude;
			}
			set
			{
				_jitterMagnitude = Mathf.Clamp(value, 0.001f, 1f);
			}
		}

		public float DelayScale
		{
			get
			{
				return _delayScale;
			}
			set
			{
				_delayScale = Mathf.Clamp(value, 0.05f, 1f);
			}
		}

		public float MaxDelayTime
		{
			get
			{
				return _maxDelayTime;
			}
			set
			{
				_maxDelayTime = Mathf.Clamp(value, 0.1f, 60f);
			}
		}

		public void HandleException<TException>() where TException : Exception
		{
			_exceptionsToHandle.Add((Exception exception) => (!(exception is TException)) ? null : exception);
		}

		public void HandleException<TException>(Func<TException, bool> condition) where TException : Exception
		{
			_exceptionsToHandle.Add((Exception exception) => (!(exception is TException arg) || !condition(arg)) ? null : exception);
		}

		public bool IsHandledException(Exception e)
		{
			if (_exceptionsToHandle != null)
			{
				foreach (ExceptionPredicate item in _exceptionsToHandle)
				{
					if (item(e) == e)
					{
						return true;
					}
				}
			}
			return false;
		}
	}
	internal class StatusCodePolicyConfig
	{
		private IDictionary<long, bool> _statusCodesToHandleDict = new Dictionary<long, bool>
		{
			{ 408L, true },
			{ 429L, true },
			{ 502L, true },
			{ 503L, true },
			{ 504L, true }
		};

		public void HandleStatusCode(long code)
		{
			if (_statusCodesToHandleDict.ContainsKey(code))
			{
				_statusCodesToHandleDict[code] = true;
			}
			else
			{
				_statusCodesToHandleDict.Add(new KeyValuePair<long, bool>(code, value: true));
			}
		}

		public void DontHandleStatusCode(long code)
		{
			if (_statusCodesToHandleDict.ContainsKey(code))
			{
				_statusCodesToHandleDict[code] = false;
			}
			else
			{
				_statusCodesToHandleDict.Add(new KeyValuePair<long, bool>(code, value: false));
			}
		}

		public void Clear()
		{
			_statusCodesToHandleDict.Clear();
		}

		public bool IsHandledStatusCode(long code)
		{
			return _statusCodesToHandleDict.Contains(new KeyValuePair<long, bool>(code, value: true));
		}
	}
}
namespace Unity.Services.Relay.RelayAllocations
{
	internal static class JsonSerialization
	{
		public static byte[] Serialize<T>(T obj)
		{
			return Encoding.UTF8.GetBytes(SerializeToString(obj));
		}

		public static string SerializeToString<T>(T obj)
		{
			//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_0017: Expected O, but got Unknown
			return JsonConvert.SerializeObject((object)obj, new JsonSerializerSettings
			{
				ReferenceLoopHandling = (ReferenceLoopHandling)1
			});
		}
	}
	[Preserve]
	internal class RelayAllocationsApiBaseRequest
	{
		private static readonly Regex JsonRegex = new Regex("application\\/json(;\\s)?((charset=utf8|q=[0-1]\\.\\d)(\\s)?)*");

		[Preserve]
		public List<string> AddParamsToQueryParams(List<string> queryParams, string key, string value)
		{
			key = UnityWebRequest.EscapeURL(key);
			value = UnityWebRequest.EscapeURL(value);
			queryParams.Add(key + "=" + value);
			return queryParams;
		}

		[Preserve]
		public List<string> AddParamsToQueryParams(List<string> queryParams, string key, List<string> values, string style, bool explode)
		{
			if (explode)
			{
				foreach (string value in values)
				{
					string text = UnityWebRequest.EscapeURL(value);
					queryParams.Add(UnityWebRequest.EscapeURL(key) + "=" + text);
				}
			}
			else
			{
				string text2 = UnityWebRequest.EscapeURL(key) + "=";
				foreach (string value2 in values)
				{
					text2 = text2 + UnityWebRequest.EscapeURL(value2) + ",";
				}
				text2 = text2.Remove(text2.Length - 1);
				queryParams.Add(text2);
			}
			return queryParams;
		}

		[Preserve]
		public List<string> AddParamsToQueryParams(List<string> queryParams, Dictionary<string, string> modelVars)
		{
			foreach (string key in modelVars.Keys)
			{
				string text = UnityWebRequest.EscapeURL(modelVars[key]);
				queryParams.Add(UnityWebRequest.EscapeURL(key) + "=" + text);
			}
			return queryParams;
		}

		[Preserve]
		public List<string> AddParamsToQueryParams<T>(List<string> queryParams, string key, T value)
		{
			if (queryParams == null)
			{
				queryParams = new List<string>();
			}
			key = UnityWebRequest.EscapeURL(key);
			string text = UnityWebRequest.EscapeURL(value.ToString());
			queryParams.Add(key + "=" + text);
			return queryParams;
		}

		[Preserve]
		public string GetPathParamString(List<string> pathParam)
		{
			string text = "";
			foreach (string item in pathParam)
			{
				text = text + UnityWebRequest.EscapeURL(item) + ",";
			}
			return text.Remove(text.Length - 1);
		}

		public byte[] ConstructBody(Stream stream)
		{
			if (stream != null)
			{
				using (MemoryStream memoryStream = new MemoryStream())
				{
					stream.CopyTo(memoryStream);
					return memoryStream.ToArray();
				}
			}
			return null;
		}

		public byte[] ConstructBody(string s)
		{
			return Encoding.UTF8.GetBytes(s);
		}

		public byte[] ConstructBody(object o)
		{
			return JsonSerialization.Serialize(o);
		}

		public string GenerateAcceptHeader(string[] accepts)
		{
			if (accepts.Length == 0)
			{
				return null;
			}
			for (int i = 0; i < accepts.Length; i++)
			{
				if (string.Equals(accepts[i], "application/json", StringComparison.OrdinalIgnoreCase))
				{
					return "application/json";
				}
			}
			return string.Join(", ", accepts);
		}

		public string GenerateContentTypeHeader(string[] contentTypes)
		{
			if (contentTypes.Length == 0)
			{
				return null;
			}
			for (int i = 0; i < contentTypes.Length; i++)
			{
				if (!string.IsNullOrWhiteSpace(contentTypes[i]) && JsonRegex.IsMatch(contentTypes[i]))
				{
					return contentTypes[i];
				}
			}
			return contentTypes[0];
		}

		public IMultipartFormSection GenerateMultipartFormFileSection(string paramName, FileStream stream, string contentType)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			return (IMultipartFormSection)new MultipartFormFileSection(paramName, ConstructBody(stream), GetFileName(stream.Name), contentType);
		}

		public IMultipartFormSection GenerateMultipartFormFileSection(string paramName, Stream stream, string contentType)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			return (IMultipartFormSection)new MultipartFormFileSection(paramName, ConstructBody(stream), Guid.NewGuid().ToString(), contentType);
		}

		private string GetFileName(string filePath)
		{
			return Path.GetFileName(filePath);
		}
	}
	[Preserve]
	internal class CreateAllocationRequest : RelayAllocationsApiBaseRequest
	{
		private string PathAndQueryParams;

		[Preserve]
		public AllocationRequest AllocationRequest { get; }

		[Preserve]
		public CreateAllocationRequest(AllocationRequest allocationRequest)
		{
			AllocationRequest = allocationRequest;
			PathAndQueryParams = "/v1/allocate";
		}

		public string ConstructUrl(string requestBasePath)
		{
			return requestBasePath + PathAndQueryParams;
		}

		public byte[] ConstructBody()
		{
			return ConstructBody(AllocationRequest);
		}

		public Dictionary<string, string> ConstructHeaders(IAccessToken accessToken, Configuration operationConfiguration = null)
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			if (!string.IsNullOrEmpty(accessToken.AccessToken))
			{
				dictionary.Add("authorization", "Bearer " + accessToken.AccessToken);
			}
			dictionary.Add("Unity-Client-Version", Application.unityVersion);
			dictionary.Add("Unity-Client-Mode", EngineStateHelper.IsPlaying ? "play" : "edit");
			string[] contentTypes = new string[1] { "application/json" };
			string[] accepts = new string[2] { "application/json", "application/problem+json" };
			string value = GenerateAcceptHeader(accepts);
			if (!string.IsNullOrEmpty(value))
			{
				dictionary.Add("Accept", value);
			}
			string text = "POST";
			string value2 = GenerateContentTypeHeader(contentTypes);
			if (!string.IsNullOrEmpty(value2))
			{
				dictionary.Add("Content-Type", value2);
			}
			else if (text == "POST" || text == "PATCH")
			{
				dictionary.Add("Content-Type", "application/json");
			}
			if (operationConfiguration != null && operationConfiguration.Headers != null)
			{
				foreach (KeyValuePair<string, string> header in operationConfiguration.Headers)
				{
					dictionary[header.Key] = header.Value;
				}
			}
			return dictionary;
		}
	}
	[Preserve]
	internal class CreateJoincodeRequest : RelayAllocationsApiBaseRequest
	{
		private string PathAndQueryParams;

		[Preserve]
		public JoinCodeRequest JoinCodeRequest { get; }

		[Preserve]
		public CreateJoincodeRequest(JoinCodeRequest joinCodeRequest)
		{
			JoinCodeRequest = joinCodeRequest;
			PathAndQueryParams = "/v1/joincode";
		}

		public string ConstructUrl(string requestBasePath)
		{
			return requestBasePath + PathAndQueryParams;
		}

		public byte[] ConstructBody()
		{
			return ConstructBody(JoinCodeRequest);
		}

		public Dictionary<string, string> ConstructHeaders(IAccessToken accessToken, Configuration operationConfiguration = null)
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			if (!string.IsNullOrEmpty(accessToken.AccessToken))
			{
				dictionary.Add("authorization", "Bearer " + accessToken.AccessToken);
			}
			dictionary.Add("Unity-Client-Version", Application.unityVersion);
			dictionary.Add("Unity-Client-Mode", EngineStateHelper.IsPlaying ? "play" : "edit");
			string[] contentTypes = new string[1] { "application/json" };
			string[] accepts = new string[2] { "application/json", "application/problem+json" };
			string value = GenerateAcceptHeader(accepts);
			if (!string.IsNullOrEmpty(value))
			{
				dictionary.Add("Accept", value);
			}
			string text = "POST";
			string value2 = GenerateContentTypeHeader(contentTypes);
			if (!string.IsNullOrEmpty(value2))
			{
				dictionary.Add("Content-Type", value2);
			}
			else if (text == "POST" || text == "PATCH")
			{
				dictionary.Add("Content-Type", "application/json");
			}
			if (operationConfiguration != null && operationConfiguration.Headers != null)
			{
				foreach (KeyValuePair<string, string> header in operationConfiguration.Headers)
				{
					dictionary[header.Key] = header.Value;
				}
			}
			return dictionary;
		}
	}
	[Preserve]
	internal class JoinRelayRequest : RelayAllocationsApiBaseRequest
	{
		private string PathAndQueryParams;

		[Preserve]
		public JoinRequest JoinRequest { get; }

		[Preserve]
		public JoinRelayRequest(JoinRequest joinRequest)
		{
			JoinRequest = joinRequest;
			PathAndQueryParams = "/v1/join";
		}

		public string ConstructUrl(string requestBasePath)
		{
			return requestBasePath + PathAndQueryParams;
		}

		public byte[] ConstructBody()
		{
			return ConstructBody(JoinRequest);
		}

		public Dictionary<string, string> ConstructHeaders(IAccessToken accessToken, Configuration operationConfiguration = null)
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			if (!string.IsNullOrEmpty(accessToken.AccessToken))
			{
				dictionary.Add("authorization", "Bearer " + accessToken.AccessToken);
			}
			dictionary.Add("Unity-Client-Version", Application.unityVersion);
			dictionary.Add("Unity-Client-Mode", EngineStateHelper.IsPlaying ? "play" : "edit");
			string[] contentTypes = new string[1] { "application/json" };
			string[] accepts = new string[2] { "application/json", "application/problem+json" };
			string value = GenerateAcceptHeader(accepts);
			if (!string.IsNullOrEmpty(value))
			{
				dictionary.Add("Accept", value);
			}
			string text = "POST";
			string value2 = GenerateContentTypeHeader(contentTypes);
			if (!string.IsNullOrEmpty(value2))
			{
				dictionary.Add("Content-Type", value2);
			}
			else if (text == "POST" || text == "PATCH")
			{
				dictionary.Add("Content-Type", "application/json");
			}
			if (operationConfiguration != null && operationConfiguration.Headers != null)
			{
				foreach (KeyValuePair<string, string> header in operationConfiguration.Headers)
				{
					dictionary[header.Key] = header.Value;
				}
			}
			return dictionary;
		}
	}
	[Preserve]
	internal class ListRegionsRequest : RelayAllocationsApiBaseRequest
	{
		private string PathAndQueryParams;

		[Preserve]
		public ListRegionsRequest()
		{
			PathAndQueryParams = "/v1/regions";
		}

		public string ConstructUrl(string requestBasePath)
		{
			return requestBasePath + PathAndQueryParams;
		}

		public byte[] ConstructBody()
		{
			return null;
		}

		public Dictionary<string, string> ConstructHeaders(IAccessToken accessToken, Configuration operationConfiguration = null)
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			if (!string.IsNullOrEmpty(accessToken.AccessToken))
			{
				dictionary.Add("authorization", "Bearer " + accessToken.AccessToken);
			}
			dictionary.Add("Unity-Client-Version", Application.unityVersion);
			dictionary.Add("Unity-Client-Mode", EngineStateHelper.IsPlaying ? "play" : "edit");
			string[] contentTypes = new string[0];
			string[] accepts = new string[2] { "application/json", "application/problem+json" };
			string value = GenerateAcceptHeader(accepts);
			if (!string.IsNullOrEmpty(value))
			{
				dictionary.Add("Accept", value);
			}
			string text = "GET";
			string value2 = GenerateContentTypeHeader(contentTypes);
			if (!string.IsNullOrEmpty(value2))
			{
				dictionary.Add("Content-Type", value2);
			}
			else if (text == "POST" || text == "PATCH")
			{
				dictionary.Add("Content-Type", "application/json");
			}
			if (operationConfiguration != null && operationConfiguration.Headers != null)
			{
				foreach (KeyValuePair<string, string> header in operationConfiguration.Headers)
				{
					dictionary[header.Key] = header.Value;
				}
			}
			return dictionary;
		}
	}
}
namespace Unity.Services.Relay.Apis.RelayAllocations
{
	internal interface IRelayAllocationsApiClient
	{
		Task<Response<AllocateResponseBody>> CreateAllocationAsync(CreateAllocationRequest request, Configuration operationConfiguration = null);

		Task<Response<JoinCodeResponseBody>> CreateJoincodeAsync(CreateJoincodeRequest request, Configuration operationConfiguration = null);

		Task<Response<JoinResponseBody>> JoinRelayAsync(JoinRelayRequest request, Configuration operationConfiguration = null);

		Task<Response<RegionsResponseBody>> ListRegionsAsync(ListRegionsRequest request, Configuration operationConfiguration = null);
	}
	internal class RelayAllocationsApiClient : BaseApiClient, IRelayAllocationsApiClient
	{
		private IAccessToken _accessToken;

		private const int _baseTimeout = 10;

		private Configuration _configuration;

		public Configuration Configuration
		{
			get
			{
				Configuration b = new Configuration("https://relay-allocations.services.api.unity.com", 10, 4, null);
				return Configuration.MergeConfigurations(_configuration, b);
			}
			set
			{
				_configuration = value;
			}
		}

		public RelayAllocationsApiClient(IHttpClient httpClient, IAccessToken accessToken, Configuration configuration = null)
			: base(httpClient)
		{
			_configuration = configuration;
			_accessToken = accessToken;
		}

		public async Task<Response<AllocateResponseBody>> CreateAllocationAsync(CreateAllocationRequest request, Configuration operationConfiguration = null)
		{
			Dictionary<string, Type> statusCodeToTypeMap = new Dictionary<string, Type>
			{
				{
					"201",
					typeof(AllocateResponseBody)
				},
				{
					"400",
					typeof(ErrorResponseBody)
				},
				{
					"401",
					typeof(ErrorResponseBody)
				},
				{
					"403",
					typeof(ErrorResponseBody)
				},
				{
					"429",
					typeof(ErrorResponseBody)
				},
				{
					"500",
					typeof(ErrorResponseBody)
				},
				{
					"503",
					typeof(ErrorResponseBody)
				}
			};
			Configuration configuration = Configuration.MergeConfigurations(operationConfiguration, Configuration);
			HttpClientResponse obj = await HttpClient.MakeRequestAsync("POST", request.ConstructUrl(configuration.BasePath), request.ConstructBody(), request.ConstructHeaders(_accessToken, configuration), configuration.RequestTimeout ?? 10);
			AllocateResponseBody result = ResponseHandler.HandleAsyncResponse<AllocateResponseBody>(obj, statusCodeToTypeMap);
			return new Response<AllocateResponseBody>(obj, result);
		}

		public async Task<Response<JoinCodeResponseBody>> CreateJoincodeAsync(CreateJoincodeRequest request, Configuration operationConfiguration = null)
		{
			Dictionary<string, Type> statusCodeToTypeMap = new Dictionary<string, Type>
			{
				{
					"200",
					typeof(JoinCodeResponseBody)
				},
				{
					"201",
					typeof(JoinCodeResponseBody)
				},
				{
					"400",
					typeof(ErrorResponseBody)
				},
				{
					"401",
					typeof(ErrorResponseBody)
				},
				{
					"403",
					typeof(ErrorResponseBody)
				},
				{
					"404",
					typeof(ErrorResponseBody)
				},
				{
					"429",
					typeof(ErrorResponseBody)
				},
				{
					"500",
					typeof(ErrorResponseBody)
				}
			};
			Configuration configuration = Configuration.MergeConfigurations(operationConfiguration, Configuration);
			HttpClientResponse obj = await HttpClient.MakeRequestAsync("POST", request.ConstructUrl(configuration.BasePath), request.ConstructBody(), request.ConstructHeaders(_accessToken, configuration), configuration.RequestTimeout ?? 10);
			JoinCodeResponseBody result = ResponseHandler.HandleAsyncResponse<JoinCodeResponseBody>(obj, statusCodeToTypeMap);
			return new Response<JoinCodeResponseBody>(obj, result);
		}

		public async Task<Response<JoinResponseBody>> JoinRelayAsync(JoinRelayRequest request, Configuration operationConfiguration = null)
		{
			Dictionary<string, Type> statusCodeToTypeMap = new Dictionary<string, Type>
			{
				{
					"200",
					typeof(JoinResponseBody)
				},
				{
					"400",
					typeof(ErrorResponseBody)
				},
				{
					"401",
					typeof(ErrorResponseBody)
				},
				{
					"403",
					typeof(ErrorResponseBody)
				},
				{
					"404",
					typeof(ErrorResponseBody)
				},
				{
					"429",
					typeof(ErrorResponseBody)
				},
				{
					"500",
					typeof(ErrorResponseBody)
				}
			};
			Configuration configuration = Configuration.MergeConfigurations(operationConfiguration, Configuration);
			HttpClientResponse obj = await HttpClient.MakeRequestAsync("POST", request.ConstructUrl(configuration.BasePath), request.ConstructBody(), request.ConstructHeaders(_accessToken, configuration), configuration.RequestTimeout ?? 10);
			JoinResponseBody result = ResponseHandler.HandleAsyncResponse<JoinResponseBody>(obj, statusCodeToTypeMap);
			return new Response<JoinResponseBody>(obj, result);
		}

		public async Task<Response<RegionsResponseBody>> ListRegionsAsync(ListRegionsRequest request, Configuration operationConfiguration = null)
		{
			Dictionary<string, Type> statusCodeToTypeMap = new Dictionary<string, Type>
			{
				{
					"200",
					typeof(RegionsResponseBody)
				},
				{
					"400",
					typeof(ErrorResponseBody)
				},
				{
					"401",
					typeof(ErrorResponseBody)
				},
				{
					"403",
					typeof(ErrorResponseBody)
				},
				{
					"429",
					typeof(ErrorResponseBody)
				},
				{
					"500",
					typeof(ErrorResponseBody)
				}
			};
			Configuration configuration = Configuration.MergeConfigurations(operationConfiguration, Configuration);
			HttpClientResponse obj = await HttpClient.MakeRequestAsync("GET", request.ConstructUrl(configuration.BasePath), request.ConstructBody(), request.ConstructHeaders(_accessToken, configuration), configuration.RequestTimeout ?? 10);
			RegionsResponseBody result = ResponseHandler.HandleAsyncResponse<RegionsResponseBody>(obj, statusCodeToTypeMap);
			return new Response<RegionsResponseBody>(obj, result);
		}
	}
}