Decompiled source of H3Status v0.5.1

plugins/H3Status.dll

Decompiled 3 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Net;
using System.Net.Security;
using System.Net.Sockets;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security;
using System.Security.Authentication;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using FistVR;
using Fleck2;
using Fleck2.Handlers;
using Fleck2.Interfaces;
using H3Status.Model;
using H3Status.Patches;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using Valve.Newtonsoft.Json;
using Valve.Newtonsoft.Json.Converters;
using Valve.Newtonsoft.Json.Serialization;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: AssemblyCompany("H3Status")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.5.1.0")]
[assembly: AssemblyInformationalVersion("0.5.1+6a5e0dc5f46c295da8d6b5979e4a299739236a95")]
[assembly: AssemblyProduct("H3Status")]
[assembly: AssemblyTitle("H3Status")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.5.1.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class IsReadOnlyAttribute : Attribute
	{
	}
	[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;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace xyz.bacur.plugins
{
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "H3Status";

		public const string PLUGIN_NAME = "H3Status";

		public const string PLUGIN_VERSION = "0.5.1";
	}
}
namespace Fleck2
{
	public static class Fleck2Extensions
	{
		public delegate void Action();

		public delegate void Action<in T>(T t);

		public delegate void Action<in T, in TU>(T t, TU u);

		public delegate void Action<in T, in TU, in TV>(T t, TU u, TV v);

		public delegate TResult Func<out TResult>();

		public delegate TResult Func<in T, out TResult>(T t);

		public delegate TResult Func<in T, in TU, out TResult>(T t, TU u);

		public delegate TResult Func<in T, in TU, in TV, out TResult>(T t, TU u, TV v);

		public static T[] ToArray<T>(this IEnumerable<T> enumerable)
		{
			return enumerable.ToList().ToArray();
		}

		public static List<T> ToList<T>(this IEnumerable<T> enumerable)
		{
			List<T> list = new List<T>();
			foreach (T item in enumerable)
			{
				list.Add(item);
			}
			return list;
		}

		public static IEnumerable<T> Skip<T>(this IEnumerable<T> enumerable, int count)
		{
			foreach (T item in enumerable)
			{
				if (count-- <= 0)
				{
					yield return item;
				}
			}
		}

		public static byte[] Skip(this byte[] array, int count)
		{
			byte[] array2 = new byte[array.Length - count];
			int num = 0;
			for (int i = 0; i < array.Length; i++)
			{
				if (count-- <= 0)
				{
					array2[num] = array[i];
					num++;
				}
			}
			return array2;
		}

		public static IEnumerable<T> Take<T>(this IEnumerable<T> enumerable, int count)
		{
			foreach (T item in enumerable)
			{
				if (count-- > 0)
				{
					yield return item;
					continue;
				}
				yield break;
			}
		}

		public static IEnumerable<T> Skip<T>(this T[] enumerable, int count)
		{
			foreach (T val in enumerable)
			{
				if (count-- > 0)
				{
					yield return val;
					continue;
				}
				break;
			}
		}

		public static IEnumerable<T> Take<T>(this T[] enumerable, int count)
		{
			foreach (T val in enumerable)
			{
				if (count-- > 0)
				{
					yield return val;
					continue;
				}
				break;
			}
		}

		public static IEnumerable<TResult> Select<TSource, TResult>(this IEnumerable<TSource> enumerable, Converter<TSource, TResult> selector)
		{
			foreach (TResult item in enumerable.ToList().ConvertAll(selector))
			{
				yield return item;
			}
		}
	}
	public enum LogLevel
	{
		None,
		Debug,
		Info,
		Warn,
		Error
	}
	public class FleckLog
	{
		public static LogLevel Level = LogLevel.Info;

		public static Fleck2Extensions.Action<LogLevel, string, Exception> LogAction = delegate(LogLevel level, string message, Exception ex)
		{
			if (Level != LogLevel.None && level >= Level)
			{
				Console.WriteLine("{0} [{1}] {2} {3}", DateTime.Now, level, message, ex);
			}
		};

		public static void Warn(string message, Exception ex = null)
		{
			LogAction(LogLevel.Warn, message, ex);
		}

		public static void Error(string message, Exception ex = null)
		{
			LogAction(LogLevel.Error, message, ex);
		}

		public static void Debug(string message, Exception ex = null)
		{
			LogAction(LogLevel.Debug, message, ex);
		}

		public static void Info(string message, Exception ex = null)
		{
			LogAction(LogLevel.Info, message, ex);
		}
	}
	public enum FrameType : byte
	{
		Continuation = 0,
		Text = 1,
		Binary = 2,
		Close = 8,
		Ping = 9,
		Pong = 10
	}
	public class HandlerFactory
	{
		public static IHandler BuildHandler(WebSocketHttpRequest request, Action<string> onMessage, Fleck2Extensions.Action onClose, Action<byte[]> onBinary)
		{
			switch (GetVersion(request))
			{
			case "76":
				return Draft76Handler.Create(request, onMessage);
			case "7":
			case "8":
			case "13":
				return Hybi13Handler.Create(request, onMessage, onClose, onBinary);
			default:
				throw new WebSocketException(1003);
			}
		}

		public static string GetVersion(WebSocketHttpRequest request)
		{
			if (request.Headers.TryGetValue("Sec-WebSocket-Version", out var value))
			{
				return value;
			}
			if (request.Headers.TryGetValue("Sec-WebSocket-Draft", out value))
			{
				return value;
			}
			if (request.Headers.ContainsKey("Sec-WebSocket-Key1"))
			{
				return "76";
			}
			return "75";
		}
	}
	public class HandshakeException : Exception
	{
		public HandshakeException()
		{
		}

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

		public HandshakeException(string message, Exception innerException)
			: base(message, innerException)
		{
		}
	}
	public static class IntExtensions
	{
		public static byte[] ToBigEndianBytes<T>(this int source)
		{
			Type typeFromHandle = typeof(T);
			byte[] bytes;
			if ((object)typeFromHandle == typeof(ushort))
			{
				bytes = BitConverter.GetBytes((ushort)source);
			}
			else if ((object)typeFromHandle == typeof(ulong))
			{
				bytes = BitConverter.GetBytes((ulong)source);
			}
			else
			{
				if ((object)typeFromHandle != typeof(int))
				{
					throw new InvalidCastException("Cannot be cast to T");
				}
				bytes = BitConverter.GetBytes(source);
			}
			if (BitConverter.IsLittleEndian)
			{
				Array.Reverse((Array)bytes);
			}
			return bytes;
		}

		public static int ToLittleEndianInt(this byte[] source)
		{
			if (BitConverter.IsLittleEndian)
			{
				Array.Reverse((Array)source);
			}
			if (source.Length == 2)
			{
				return BitConverter.ToUInt16(source, 0);
			}
			if (source.Length == 8)
			{
				return (int)BitConverter.ToUInt64(source, 0);
			}
			throw new ArgumentException("Unsupported Size");
		}
	}
	public class ReadState
	{
		public List<byte> Data { get; private set; }

		public FrameType? FrameType { get; set; }

		public ReadState()
		{
			Data = new List<byte>();
		}

		public void Clear()
		{
			Data.Clear();
			FrameType = null;
		}
	}
	public class RequestParser
	{
		private const string Pattern = "^(?<method>[^\\s]+)\\s(?<path>[^\\s]+)\\sHTTP\\/1\\.1\\r\\n((?<field_name>[^:\\r\\n]+):\\s(?<field_value>[^\\r\\n]+)\\r\\n)+\\r\\n(?<body>.+)?";

		private static readonly Regex Regex = new Regex("^(?<method>[^\\s]+)\\s(?<path>[^\\s]+)\\sHTTP\\/1\\.1\\r\\n((?<field_name>[^:\\r\\n]+):\\s(?<field_value>[^\\r\\n]+)\\r\\n)+\\r\\n(?<body>.+)?", RegexOptions.IgnoreCase);

		public static WebSocketHttpRequest Parse(byte[] bytes)
		{
			return Parse(bytes, "ws");
		}

		public static WebSocketHttpRequest Parse(byte[] bytes, string scheme)
		{
			string input = Encoding.UTF8.GetString(bytes);
			Match match = Regex.Match(input);
			if (!match.Success)
			{
				return null;
			}
			WebSocketHttpRequest webSocketHttpRequest = new WebSocketHttpRequest
			{
				Method = match.Groups["method"].Value,
				Path = match.Groups["path"].Value,
				Body = match.Groups["body"].Value,
				Bytes = bytes,
				Scheme = scheme
			};
			CaptureCollection captures = match.Groups["field_name"].Captures;
			CaptureCollection captures2 = match.Groups["field_value"].Captures;
			for (int i = 0; i < captures.Count; i++)
			{
				string key = captures[i].ToString();
				string value = captures2[i].ToString();
				webSocketHttpRequest.Headers[key] = value;
			}
			return webSocketHttpRequest;
		}
	}
	public class SocketCancellationToken : ICancellationToken
	{
		private readonly object _syncLock = new object();

		public readonly Guid Token;

		private bool _isCancellationRequested;

		public bool IsCancellationRequested
		{
			get
			{
				Monitor.Enter(_syncLock);
				try
				{
					return _isCancellationRequested;
				}
				finally
				{
					Monitor.Exit(_syncLock);
				}
			}
			private set
			{
				Monitor.Enter(_syncLock);
				try
				{
					_isCancellationRequested = value;
				}
				finally
				{
					Monitor.Exit(_syncLock);
				}
			}
		}

		public void ThrowIfCancellationRequested()
		{
			if (IsCancellationRequested)
			{
				throw new SocketCancellationTokenException(this);
			}
		}

		public void Cancel()
		{
			IsCancellationRequested = true;
		}
	}
	public class SocketCancellationTokenException : Exception
	{
		public SocketCancellationToken Token { get; private set; }

		public SocketCancellationTokenException(SocketCancellationToken token)
		{
			Token = token;
		}
	}
	public class SocketFactory
	{
		public SocketCancellationToken Token { get; private set; }

		public SocketFactory(SocketCancellationToken token)
		{
			Token = token;
		}

		public void HandleAsync<TResult>(Fleck2Extensions.Func<AsyncCallback, object, IAsyncResult> beginMethod, Fleck2Extensions.Func<IAsyncResult, TResult> endMethod, Action<SocketResult> resultCallback)
		{
			DoAsyncTask(delegate
			{
				beginMethod(delegate(IAsyncResult result)
				{
					DoAsyncTask(delegate
					{
						resultCallback(new SocketResult(endMethod(result)));
					}, resultCallback);
				}, null);
			}, resultCallback);
		}

		public void HandleAsync(Fleck2Extensions.Func<AsyncCallback, object, IAsyncResult> beginMethod, Fleck2Extensions.Func<IAsyncResult, ICancellationToken, ISocket> endMethod, Action<SocketResult> resultCallback)
		{
			DoAsyncTask(delegate
			{
				beginMethod(delegate(IAsyncResult result)
				{
					DoAsyncTask(delegate
					{
						resultCallback(new SocketResult(endMethod(result, Token)));
					}, resultCallback);
				}, null);
			}, resultCallback);
		}

		public void HandleAsyncVoid<T>(Fleck2Extensions.Func<AsyncCallback, object, T> beginMethod, Fleck2Extensions.Action<T> endMethod, Action<SocketResult> resultCallback)
		{
			DoAsyncTask(delegate
			{
				beginMethod(delegate(IAsyncResult result)
				{
					DoAsyncTask(delegate
					{
						endMethod((T)result);
						resultCallback(new SocketResult(true));
					}, resultCallback);
				}, null);
			}, resultCallback);
		}

		private static void DoAsyncTask(Fleck2Extensions.Action unitOfWork, Action<SocketResult> resultCallback)
		{
			ThreadPool.QueueUserWorkItem(delegate
			{
				try
				{
					unitOfWork();
				}
				catch (SocketCancellationTokenException)
				{
				}
				catch (Exception result)
				{
					resultCallback(new SocketResult(result));
				}
			});
		}
	}
	public class SocketResult
	{
		private readonly object _result;

		public SocketResult(object result)
		{
			_result = result;
		}

		public SocketResult Success<TResult>(Fleck2Extensions.Action<TResult> callback)
		{
			if (!(_result is Exception))
			{
				callback((TResult)_result);
			}
			return this;
		}

		public SocketResult Error<TResult>(Fleck2Extensions.Action<TResult> callback)
		{
			if (_result is Exception)
			{
				callback((TResult)_result);
			}
			return this;
		}

		public SocketResult Success(Fleck2Extensions.Action callback)
		{
			if (!(_result is Exception))
			{
				callback();
			}
			return this;
		}

		public TResult AsValue<TResult>()
		{
			return (TResult)_result;
		}
	}
	public class SocketWrapper : ISocket
	{
		private readonly Socket _socket;

		private Stream _stream;

		private readonly SocketCancellationToken _socketCancellationToken;

		private readonly SocketFactory _socketFactory;

		public string RemoteIpAddress
		{
			get
			{
				if (!(_socket.RemoteEndPoint is IPEndPoint iPEndPoint))
				{
					return null;
				}
				return iPEndPoint.Address.ToString();
			}
		}

		public int RemotePort
		{
			get
			{
				if (!(_socket.RemoteEndPoint is IPEndPoint iPEndPoint))
				{
					return -1;
				}
				return iPEndPoint.Port;
			}
		}

		public bool Connected => _socket.Connected;

		public Stream Stream => _stream;

		public bool NoDelay
		{
			get
			{
				return _socket.NoDelay;
			}
			set
			{
				_socket.NoDelay = value;
			}
		}

		public SocketWrapper(Socket socket)
		{
			_socketCancellationToken = new SocketCancellationToken();
			_socketFactory = new SocketFactory(_socketCancellationToken);
			_socket = socket;
			if (_socket.Connected)
			{
				_stream = new NetworkStream(_socket);
			}
		}

		public void Authenticate(X509Certificate2 certificate, Fleck2Extensions.Action callback, Fleck2Extensions.Action<Exception> error)
		{
			SslStream ssl = new SslStream(_stream, leaveInnerStreamOpen: false);
			_stream = ssl;
			Fleck2Extensions.Func<AsyncCallback, object, IAsyncResult> beginMethod = (AsyncCallback cb, object s) => ssl.BeginAuthenticateAsServer(certificate, clientCertificateRequired: false, SslProtocols.Tls, checkCertificateRevocation: false, cb, s);
			_socketFactory.HandleAsyncVoid(beginMethod, ssl.EndAuthenticateAsServer, delegate(SocketResult result)
			{
				result.Success(callback);
				result.Error(error);
			});
		}

		public void Listen(int backlog)
		{
			_socket.Listen(backlog);
		}

		public void Bind(EndPoint endPoint)
		{
			_socket.Bind(endPoint);
		}

		public void Receive(byte[] buffer, Fleck2Extensions.Action<int> callback, Fleck2Extensions.Action<Exception> error, int offset = 0)
		{
			Fleck2Extensions.Func<AsyncCallback, object, IAsyncResult> beginMethod = (AsyncCallback cb, object data) => _stream.BeginRead(buffer, offset, buffer.Length, cb, data);
			_socketFactory.HandleAsync(beginMethod, _stream.EndRead, delegate(SocketResult result)
			{
				result.Success(callback);
				result.Error(error);
			});
		}

		public void Accept(Fleck2Extensions.Action<ISocket> callback, Fleck2Extensions.Action<Exception> error)
		{
			Fleck2Extensions.Func<IAsyncResult, ICancellationToken, ISocket> endMethod = delegate(IAsyncResult result, ICancellationToken token)
			{
				token.ThrowIfCancellationRequested();
				return new SocketWrapper(_socket.EndAccept(result));
			};
			_socketFactory.HandleAsync(_socket.BeginAccept, endMethod, delegate(SocketResult result)
			{
				result.Success(callback);
				result.Error(error);
			});
		}

		public void Dispose()
		{
			_socketCancellationToken.Cancel();
			if (_stream != null)
			{
				_stream.Dispose();
			}
			if (_socket != null)
			{
				_socket.Close();
			}
		}

		public void Close()
		{
			_socketCancellationToken.Cancel();
			if (_stream != null)
			{
				_stream.Close();
			}
			if (_socket != null)
			{
				_socket.Close();
			}
		}

		public int EndSend(IAsyncResult asyncResult)
		{
			_stream.EndWrite(asyncResult);
			return 0;
		}

		public void Send(byte[] buffer, Fleck2Extensions.Action callback, Fleck2Extensions.Action<Exception> error)
		{
			Fleck2Extensions.Func<AsyncCallback, object, IAsyncResult> beginMethod = (AsyncCallback cb, object s) => _stream.BeginWrite(buffer, 0, buffer.Length, cb, s);
			_socketFactory.HandleAsyncVoid(beginMethod, _stream.EndWrite, delegate(SocketResult result)
			{
				result.Success(callback);
				result.Error(error);
			});
		}
	}
	public class WebSocketConnection : IWebSocketConnection
	{
		private readonly Action<IWebSocketConnection> _initialize;

		private readonly Fleck2Extensions.Func<WebSocketHttpRequest, IHandler> _handlerFactory;

		private readonly Fleck2Extensions.Func<byte[], WebSocketHttpRequest> _parseRequest;

		private bool _closed;

		private const int ReadSize = 4096;

		public ISocket Socket { get; set; }

		public IHandler Handler { get; set; }

		public Fleck2Extensions.Action OnOpen { get; set; }

		public Fleck2Extensions.Action OnClose { get; set; }

		public Action<string> OnMessage { get; set; }

		public Action<byte[]> OnBinary { get; set; }

		public Action<Exception> OnError { get; set; }

		public IWebSocketConnectionInfo ConnectionInfo { get; private set; }

		public WebSocketConnection(ISocket socket, Action<IWebSocketConnection> initialize, Fleck2Extensions.Func<byte[], WebSocketHttpRequest> parseRequest, Fleck2Extensions.Func<WebSocketHttpRequest, IHandler> handlerFactory)
		{
			Socket = socket;
			OnOpen = delegate
			{
			};
			OnClose = delegate
			{
			};
			OnMessage = delegate
			{
			};
			OnBinary = delegate
			{
			};
			OnError = delegate
			{
			};
			_initialize = initialize;
			_handlerFactory = handlerFactory;
			_parseRequest = parseRequest;
		}

		public void Send(string message)
		{
			if (Handler == null)
			{
				throw new InvalidOperationException("Cannot send before handshake");
			}
			if (_closed || !Socket.Connected)
			{
				FleckLog.Warn("Data sent after close. Ignoring.");
				return;
			}
			byte[] bytes = Handler.FrameText(message);
			SendBytes(bytes);
		}

		public void Send(byte[] message)
		{
			if (Handler == null)
			{
				throw new InvalidOperationException("Cannot send before handshake");
			}
			if (_closed || !Socket.Connected)
			{
				FleckLog.Warn("Data sent after close. Ignoring.");
				return;
			}
			byte[] bytes = Handler.FrameBinary(message);
			SendBytes(bytes);
		}

		public void StartReceiving()
		{
			List<byte> data = new List<byte>(4096);
			byte[] buffer = new byte[4096];
			Read(data, buffer);
		}

		public void Close()
		{
			Close(1000);
		}

		public void Close(int code)
		{
			if (Handler == null)
			{
				CloseSocket();
				return;
			}
			byte[] array = Handler.FrameClose(code);
			if (array.Length == 0)
			{
				CloseSocket();
			}
			else
			{
				SendBytes(array, CloseSocket);
			}
		}

		public void CreateHandler(IEnumerable<byte> data)
		{
			WebSocketHttpRequest webSocketHttpRequest = _parseRequest(data.ToArray());
			if (webSocketHttpRequest != null)
			{
				Handler = _handlerFactory(webSocketHttpRequest);
				if (Handler != null)
				{
					ConnectionInfo = WebSocketConnectionInfo.Create(webSocketHttpRequest, Socket.RemoteIpAddress, Socket.RemotePort);
					_initialize(this);
					byte[] bytes = Handler.CreateHandshake();
					SendBytes(bytes, OnOpen);
				}
			}
		}

		private void Read(List<byte> data, byte[] buffer)
		{
			if (_closed || !Socket.Connected)
			{
				return;
			}
			Socket.Receive(buffer, delegate(int r)
			{
				if (r <= 0)
				{
					FleckLog.Debug("0 bytes read. Closing.");
					CloseSocket();
				}
				else
				{
					FleckLog.Debug(r + " bytes read");
					byte[] array = buffer.Take(r).ToArray();
					if (Handler != null)
					{
						Handler.Receive(array);
					}
					else
					{
						data.AddRange(array);
						CreateHandler(data);
					}
					Read(data, buffer);
				}
			}, HandleReadError);
		}

		private void HandleReadError(Exception e)
		{
			if (e is ObjectDisposedException)
			{
				FleckLog.Debug("Swallowing ObjectDisposedException", e);
				return;
			}
			OnError(e);
			if (e is HandshakeException)
			{
				FleckLog.Debug("Error while reading", e);
			}
			else if (e is WebSocketException)
			{
				FleckLog.Debug("Error while reading", e);
				Close(((WebSocketException)e).StatusCode);
			}
			else if (e is IOException)
			{
				FleckLog.Debug("Error while reading", e);
				Close(1006);
			}
			else
			{
				FleckLog.Error("Application Error", e);
				Close(1011);
			}
		}

		private void SendBytes(byte[] bytes, Fleck2Extensions.Action callback = null)
		{
			Socket.Send(bytes, delegate
			{
				FleckLog.Debug("Sent " + bytes.Length + " bytes");
				if (callback != null)
				{
					callback();
				}
			}, delegate(Exception e)
			{
				if (e is IOException)
				{
					FleckLog.Debug("Failed to send. Disconnecting.", e);
				}
				else
				{
					FleckLog.Info("Failed to send. Disconnecting.", e);
				}
				CloseSocket();
			});
		}

		private void CloseSocket()
		{
			OnClose();
			_closed = true;
			Socket.Close();
			Socket.Dispose();
		}
	}
	public class WebSocketConnectionInfo : IWebSocketConnectionInfo
	{
		private const string CookiePattern = "((;\\s)*(?<cookie_name>[^=]+)=(?<cookie_value>[^\\;]+))+";

		private static readonly Regex CookieRegex = new Regex("((;\\s)*(?<cookie_name>[^=]+)=(?<cookie_value>[^\\;]+))+");

		public string SubProtocol { get; private set; }

		public string Origin { get; private set; }

		public string Host { get; private set; }

		public string Path { get; private set; }

		public string ClientIpAddress { get; set; }

		public int ClientPort { get; set; }

		public Guid Id { get; set; }

		public IDictionary<string, string> Cookies { get; private set; }

		public static WebSocketConnectionInfo Create(WebSocketHttpRequest request, string clientIp, int clientPort)
		{
			WebSocketConnectionInfo webSocketConnectionInfo = new WebSocketConnectionInfo
			{
				Origin = (request["Origin"] ?? request["Sec-WebSocket-Origin"]),
				Host = request["Host"],
				SubProtocol = request["Sec-WebSocket-Protocol"],
				Path = request.Path,
				ClientIpAddress = clientIp,
				ClientPort = clientPort
			};
			string text = request["Cookie"];
			if (text != null)
			{
				Match match = CookieRegex.Match(text);
				CaptureCollection captures = match.Groups["cookie_name"].Captures;
				CaptureCollection captures2 = match.Groups["cookie_value"].Captures;
				for (int i = 0; i < captures.Count; i++)
				{
					string key = captures[i].ToString();
					string value = captures2[i].ToString();
					webSocketConnectionInfo.Cookies[key] = value;
				}
			}
			return webSocketConnectionInfo;
		}

		private WebSocketConnectionInfo()
		{
			Cookies = new Dictionary<string, string>();
			Id = Guid.NewGuid();
		}
	}
	public class WebSocketException : Exception
	{
		public ushort StatusCode { get; private set; }

		public WebSocketException(ushort statusCode)
		{
			StatusCode = statusCode;
		}

		public WebSocketException(ushort statusCode, string message)
			: base(message)
		{
			StatusCode = statusCode;
		}

		public WebSocketException(ushort statusCode, string message, Exception innerException)
			: base(message, innerException)
		{
			StatusCode = statusCode;
		}
	}
	public class WebSocketHttpRequest
	{
		private readonly IDictionary<string, string> _headers = new Dictionary<string, string>();

		public string Method { get; set; }

		public string Path { get; set; }

		public string Body { get; set; }

		public string Scheme { get; set; }

		public byte[] Bytes { get; set; }

		public string this[string name]
		{
			get
			{
				if (!_headers.TryGetValue(name, out var value))
				{
					return null;
				}
				return value;
			}
		}

		public IDictionary<string, string> Headers => _headers;
	}
	public class WebSocketServer : IWebSocketServer, IDisposable
	{
		private readonly string _scheme;

		private Action<IWebSocketConnection> _config;

		public ISocket ListenerSocket { get; set; }

		public string Location { get; private set; }

		public int Port { get; private set; }

		public X509Certificate2 Certificate { get; set; }

		public bool IsSecure
		{
			get
			{
				if (_scheme == "wss")
				{
					return Certificate != null;
				}
				return false;
			}
		}

		public WebSocketServer(string location)
			: this(8181, location)
		{
		}

		public WebSocketServer(int port, string location)
		{
			Uri uri = new Uri(location);
			Port = ((uri.Port > 0) ? uri.Port : port);
			Location = location;
			_scheme = uri.Scheme;
			Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
			ListenerSocket = new SocketWrapper(socket);
		}

		public void Dispose()
		{
			ListenerSocket.Dispose();
		}

		public void Start(Action<IWebSocketConnection> config)
		{
			IPEndPoint ipLocal = new IPEndPoint(IPAddress.Any, Port);
			ListenerSocket.Bind(ipLocal);
			ListenerSocket.Listen(100);
			FleckLog.Info("Server started at " + Location);
			if (_scheme == "wss" && Certificate == null)
			{
				FleckLog.Error("Scheme cannot be 'wss' without a Certificate");
				return;
			}
			ListenForClients();
			_config = config;
		}

		private void ListenForClients()
		{
			ListenerSocket.Accept(OnClientConnect, delegate(Exception e)
			{
				FleckLog.Error("Listener socket is closed", e);
			});
		}

		private void OnClientConnect(ISocket clientSocket)
		{
			FleckLog.Debug($"Client connected from {clientSocket.RemoteIpAddress}:{clientSocket.RemotePort.ToString(CultureInfo.InvariantCulture)}");
			ListenForClients();
			WebSocketConnection connection = null;
			connection = new WebSocketConnection(clientSocket, _config, (byte[] bytes) => RequestParser.Parse(bytes, _scheme), (WebSocketHttpRequest r) => HandlerFactory.BuildHandler(r, delegate(string s)
			{
				connection.OnMessage(s);
			}, connection.Close, delegate(byte[] b)
			{
				connection.OnBinary(b);
			}));
			if (IsSecure)
			{
				FleckLog.Debug("Authenticating Secure Connection");
				clientSocket.Authenticate(Certificate, connection.StartReceiving, delegate(Exception e)
				{
					FleckLog.Warn("Failed to Authenticate", e);
				});
			}
			else
			{
				connection.StartReceiving();
			}
		}
	}
	public static class WebSocketStatusCodes
	{
		public const ushort NormalClosure = 1000;

		public const ushort GoingAway = 1001;

		public const ushort ProtocolError = 1002;

		public const ushort UnsupportedDataType = 1003;

		public const ushort NoStatusReceived = 1005;

		public const ushort AbnormalClosure = 1006;

		public const ushort InvalidFramePayloadData = 1007;

		public const ushort PolicyViolation = 1008;

		public const ushort MessageTooBig = 1009;

		public const ushort MandatoryExt = 1010;

		public const ushort InternalServerError = 1011;

		public const ushort TlsHandshake = 1015;

		public const ushort ApplicationError = 3000;

		public static ushort[] ValidCloseCodes = new ushort[9] { 1000, 1001, 1002, 1003, 1007, 1008, 1009, 1010, 1011 };

		public static bool Contains(ushort code)
		{
			for (int i = 0; i < ValidCloseCodes.Length; i++)
			{
				if (ValidCloseCodes[i] == code)
				{
					return true;
				}
			}
			return false;
		}
	}
}
namespace Fleck2.Interfaces
{
	public interface ICancellationToken
	{
		void ThrowIfCancellationRequested();
	}
	public interface IHandler
	{
		byte[] CreateHandshake();

		void Receive(IEnumerable<byte> data);

		byte[] FrameText(string text);

		byte[] FrameBinary(byte[] bytes);

		byte[] FrameClose(int code);
	}
	public interface ISocket
	{
		bool Connected { get; }

		string RemoteIpAddress { get; }

		int RemotePort { get; }

		Stream Stream { get; }

		bool NoDelay { get; set; }

		void Accept(Fleck2Extensions.Action<ISocket> callback, Fleck2Extensions.Action<Exception> error);

		void Send(byte[] buffer, Fleck2Extensions.Action callback, Fleck2Extensions.Action<Exception> error);

		void Receive(byte[] buffer, Fleck2Extensions.Action<int> callback, Fleck2Extensions.Action<Exception> error, int offset = 0);

		void Authenticate(X509Certificate2 certificate, Fleck2Extensions.Action callback, Fleck2Extensions.Action<Exception> error);

		void Dispose();

		void Close();

		void Bind(EndPoint ipLocal);

		void Listen(int backlog);
	}
	public interface IWebSocketConnection
	{
		Fleck2Extensions.Action OnOpen { get; set; }

		Fleck2Extensions.Action OnClose { get; set; }

		Action<string> OnMessage { get; set; }

		Action<byte[]> OnBinary { get; set; }

		Action<Exception> OnError { get; set; }

		IWebSocketConnectionInfo ConnectionInfo { get; }

		void Send(string message);

		void Send(byte[] message);

		void Close();
	}
	public interface IWebSocketConnectionInfo
	{
		string SubProtocol { get; }

		string Origin { get; }

		string Host { get; }

		string Path { get; }

		string ClientIpAddress { get; }

		int ClientPort { get; }

		IDictionary<string, string> Cookies { get; }

		Guid Id { get; }
	}
	public interface IWebSocketServer : IDisposable
	{
		void Start(Action<IWebSocketConnection> config);
	}
}
namespace Fleck2.Handlers
{
	public class ComposableHandler : IHandler
	{
		public Fleck2Extensions.Func<byte[]> Handshake = () => new byte[0];

		public Fleck2Extensions.Func<string, byte[]> TextFrame = (string x) => new byte[0];

		public Fleck2Extensions.Func<byte[], byte[]> BinaryFrame = (byte[] x) => new byte[0];

		public Action<List<byte>> ReceiveData = delegate
		{
		};

		public Fleck2Extensions.Func<int, byte[]> CloseFrame = (int i) => new byte[0];

		private readonly List<byte> _data = new List<byte>();

		public byte[] CreateHandshake()
		{
			return Handshake();
		}

		public void Receive(IEnumerable<byte> data)
		{
			_data.AddRange(data);
			ReceiveData(_data);
		}

		public byte[] FrameText(string text)
		{
			return TextFrame(text);
		}

		public byte[] FrameBinary(byte[] bytes)
		{
			return BinaryFrame(bytes);
		}

		public byte[] FrameClose(int code)
		{
			return CloseFrame(code);
		}
	}
	public static class Draft76Handler
	{
		private const byte End = byte.MaxValue;

		private const byte Start = 0;

		private const int MaxSize = 5242880;

		public static IHandler Create(WebSocketHttpRequest request, Action<string> onMessage)
		{
			return new ComposableHandler
			{
				TextFrame = FrameText,
				Handshake = () => Handshake(request),
				ReceiveData = delegate(List<byte> data)
				{
					ReceiveData(onMessage, data);
				}
			};
		}

		public static void ReceiveData(Action<string> onMessage, List<byte> data)
		{
			while (data.Count > 0)
			{
				if (data[0] != 0)
				{
					throw new WebSocketException(1007);
				}
				int num = data.IndexOf(byte.MaxValue);
				if (num < 0)
				{
					break;
				}
				if (num > 5242880)
				{
					throw new WebSocketException(1009);
				}
				byte[] bytes = data.Skip(1).Take(num - 1).ToArray();
				data.RemoveRange(0, num + 1);
				string obj = Encoding.UTF8.GetString(bytes);
				onMessage(obj);
			}
		}

		public static byte[] FrameText(string data)
		{
			byte[] bytes = Encoding.UTF8.GetBytes(data);
			byte[] array = new byte[bytes.Length + 2];
			array[0] = 0;
			array[^1] = byte.MaxValue;
			Array.Copy(bytes, 0, array, 1, bytes.Length);
			return array;
		}

		public static byte[] Handshake(WebSocketHttpRequest request)
		{
			FleckLog.Debug("Building Draft76 Response");
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append("HTTP/1.1 101 WebSocket Protocol Handshake\r\n");
			stringBuilder.Append("Upgrade: WebSocket\r\n");
			stringBuilder.Append("Connection: Upgrade\r\n");
			stringBuilder.AppendFormat("Sec-WebSocket-Origin: {0}\r\n", request["Origin"]);
			stringBuilder.AppendFormat("Sec-WebSocket-Location: {0}://{1}{2}\r\n", request.Scheme, request["Host"], request.Path);
			if (request.Headers.ContainsKey("Sec-WebSocket-Protocol"))
			{
				stringBuilder.AppendFormat("Sec-WebSocket-Protocol: {0}\r\n", request["Sec-WebSocket-Protocol"]);
			}
			stringBuilder.Append("\r\n");
			string key = request["Sec-WebSocket-Key1"];
			string key2 = request["Sec-WebSocket-Key2"];
			ArraySegment<byte> challenge = new ArraySegment<byte>(request.Bytes, request.Bytes.Length - 8, 8);
			byte[] array = CalculateAnswerBytes(key, key2, challenge);
			byte[] array2 = Encoding.ASCII.GetBytes(stringBuilder.ToString());
			int num = array2.Length;
			Array.Resize(ref array2, num + array.Length);
			Array.Copy(array, 0, array2, num, array.Length);
			return array2;
		}

		public static byte[] CalculateAnswerBytes(string key1, string key2, ArraySegment<byte> challenge)
		{
			byte[] sourceArray = ParseKey(key1);
			byte[] sourceArray2 = ParseKey(key2);
			byte[] array = new byte[16];
			Array.Copy(sourceArray, 0, array, 0, 4);
			Array.Copy(sourceArray2, 0, array, 4, 4);
			Array.Copy(challenge.Array, challenge.Offset, array, 8, 8);
			return MD5.Create().ComputeHash(array);
		}

		private static byte[] ParseKey(string key)
		{
			int num = 0;
			StringBuilder stringBuilder = new StringBuilder();
			for (int i = 0; i < key.Length; i++)
			{
				if (char.IsWhiteSpace(key[i]))
				{
					num++;
				}
				if (char.IsDigit(key[i]))
				{
					stringBuilder.Append(key[i]);
				}
			}
			byte[] bytes = BitConverter.GetBytes((int)(long.Parse(stringBuilder.ToString()) / num));
			if (BitConverter.IsLittleEndian)
			{
				Array.Reverse((Array)bytes);
			}
			return bytes;
		}
	}
	public static class Hybi13Handler
	{
		private const string WebSocketResponseGuid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";

		public static IHandler Create(WebSocketHttpRequest request, Action<string> onMessage, Fleck2Extensions.Action onClose, Action<byte[]> onBinary)
		{
			ReadState readState = new ReadState();
			return new ComposableHandler
			{
				Handshake = () => BuildHandshake(request),
				TextFrame = (string data) => FrameData(Encoding.UTF8.GetBytes(data), FrameType.Text),
				BinaryFrame = (byte[] data) => FrameData(data, FrameType.Binary),
				CloseFrame = (int i) => FrameData(i.ToBigEndianBytes<ushort>(), FrameType.Close),
				ReceiveData = delegate(List<byte> bytes)
				{
					ReceiveData(bytes, readState, delegate(FrameType op, byte[] data)
					{
						ProcessFrame(op, data, onMessage, onClose, onBinary);
					});
				}
			};
		}

		public static byte[] FrameData(byte[] payload, FrameType frameType)
		{
			MemoryStream memoryStream = new MemoryStream();
			byte value = (byte)(frameType + 128);
			memoryStream.WriteByte(value);
			if (payload.Length > 65535)
			{
				memoryStream.WriteByte(127);
				byte[] array = payload.Length.ToBigEndianBytes<ushort>();
				memoryStream.Write(array, 0, array.Length);
			}
			else if (payload.Length > 125)
			{
				memoryStream.WriteByte(126);
				byte[] array2 = payload.Length.ToBigEndianBytes<ushort>();
				memoryStream.Write(array2, 0, array2.Length);
			}
			else
			{
				memoryStream.WriteByte((byte)payload.Length);
			}
			memoryStream.Write(payload, 0, payload.Length);
			return memoryStream.ToArray();
		}

		public static void ReceiveData(List<byte> data, ReadState readState, Fleck2Extensions.Action<FrameType, byte[]> processFrame)
		{
			while (data.Count >= 2)
			{
				bool flag = (data[0] & 0x80) != 0;
				int num = data[0] & 0x70;
				FrameType frameType = (FrameType)(data[0] & 0xF);
				bool num2 = (data[1] & 0x80) != 0;
				int num3 = data[1] & 0x7F;
				if (!num2 || !Enum.IsDefined(typeof(FrameType), frameType) || num != 0 || (frameType == FrameType.Continuation && !readState.FrameType.HasValue))
				{
					throw new WebSocketException(1002);
				}
				int num4 = 2;
				int num5;
				switch (num3)
				{
				case 127:
					if (data.Count < num4 + 8)
					{
						return;
					}
					num5 = data.Skip(num4).Take(8).ToArray()
						.ToLittleEndianInt();
					num4 += 8;
					break;
				case 126:
					if (data.Count < num4 + 2)
					{
						return;
					}
					num5 = data.Skip(num4).Take(2).ToArray()
						.ToLittleEndianInt();
					num4 += 2;
					break;
				default:
					num5 = num3;
					break;
				}
				if (data.Count < num4 + 4)
				{
					break;
				}
				List<byte> maskBytes = data.Skip(num4).Take(4).ToList();
				num4 += 4;
				if (data.Count < num4 + num5)
				{
					break;
				}
				int i = 0;
				IEnumerable<byte> collection = from value in data.Skip(num4).Take(num5)
					select (byte)(value ^ maskBytes[i++ % 4]);
				readState.Data.AddRange(collection);
				data.RemoveRange(0, num4 + num5);
				if (frameType != FrameType.Continuation)
				{
					readState.FrameType = frameType;
				}
				if (flag && readState.FrameType.HasValue)
				{
					byte[] u = readState.Data.ToArray();
					FrameType? frameType2 = readState.FrameType;
					readState.Clear();
					processFrame(frameType2.Value, u);
				}
			}
		}

		public static void ProcessFrame(FrameType frameType, byte[] data, Action<string> onMessage, Fleck2Extensions.Action onClose, Action<byte[]> onBinary)
		{
			switch (frameType)
			{
			case FrameType.Close:
				if (data.Length == 1 || data.Length > 125)
				{
					throw new WebSocketException(1002);
				}
				if (data.Length >= 2)
				{
					ushort num = (ushort)data.Take(2).ToArray().ToLittleEndianInt();
					if (!WebSocketStatusCodes.Contains(num) && (num < 3000 || num > 4999))
					{
						throw new WebSocketException(1002);
					}
				}
				if (data.Length > 2)
				{
					ReadUtf8PayloadData(data.Skip(2));
				}
				onClose();
				break;
			case FrameType.Binary:
				onBinary(data);
				break;
			case FrameType.Text:
				onMessage(ReadUtf8PayloadData(data));
				break;
			default:
				FleckLog.Debug("Received unhandled " + frameType);
				break;
			}
		}

		public static byte[] BuildHandshake(WebSocketHttpRequest request)
		{
			FleckLog.Debug("Building Hybi-14 Response");
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append("HTTP/1.1 101 Switching Protocols\r\n");
			stringBuilder.Append("Upgrade: websocket\r\n");
			stringBuilder.Append("Connection: Upgrade\r\n");
			string arg = CreateResponseKey(request["Sec-WebSocket-Key"]);
			stringBuilder.AppendFormat("Sec-WebSocket-Accept: {0}\r\n", arg);
			stringBuilder.Append("\r\n");
			return Encoding.ASCII.GetBytes(stringBuilder.ToString());
		}

		public static string CreateResponseKey(string requestKey)
		{
			string s = requestKey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
			return Convert.ToBase64String(SHA1.Create().ComputeHash(Encoding.ASCII.GetBytes(s)));
		}

		private static string ReadUtf8PayloadData(byte[] bytes)
		{
			UTF8Encoding uTF8Encoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true);
			try
			{
				return uTF8Encoding.GetString(bytes);
			}
			catch (ArgumentException)
			{
				throw new WebSocketException(1007);
			}
		}
	}
}
namespace H3Status
{
	internal static class Config
	{
		public static ConfigEntry<bool> ServerEnabled;

		public static ConfigEntry<int> ServerPort;

		public static ConfigEntry<bool> LogScoreEvents;

		public static ConfigEntry<bool> SceneEvent;

		public static ConfigEntry<bool> AmmoEvent;

		public static ConfigEntry<bool> HealthEvent;

		public static ConfigEntry<bool> BuffEvent;

		public static ConfigEntry<bool> TNHLevelEvent;

		public static ConfigEntry<bool> TNHPhaseEvent;

		public static ConfigEntry<bool> TNHHoldPhaseEvent;

		public static ConfigEntry<bool> TNHScoreEvent;

		public static ConfigEntry<bool> TNHEncryptionDestroyed;

		public static ConfigEntry<bool> TNHTokenEvent;

		private static ConfigFile _configFile;

		private static ConfigEntry<T> Bind<T>(this ConfigFile config, string section, string key, T defaultValue, Action<T> callback)
		{
			ConfigEntry<T> entry = config.Bind<T>(section, key, defaultValue, (ConfigDescription)null);
			entry.SettingChanged += delegate
			{
				callback(entry.Value);
			};
			return entry;
		}

		public static void Init(ConfigFile config)
		{
			_configFile = config;
			string text = "1. General";
			string text2 = "2. Event Types";
			ServerEnabled = config.Bind(text, "Server Enabled", defaultValue: true, OnServerEnabledChanged);
			ServerPort = config.Bind(text, "Server Port", 9504, OnServerPortChanged);
			LogScoreEvents = config.Bind<bool>(text, "Log Score Events", false, (ConfigDescription)null);
			SceneEvent = config.Bind<bool>(text2, "Scene Changed", true, (ConfigDescription)null);
			AmmoEvent = config.Bind<bool>(text2, "Score Changed", true, (ConfigDescription)null);
			HealthEvent = config.Bind<bool>(text2, "Health Changed", true, (ConfigDescription)null);
			BuffEvent = config.Bind<bool>(text2, "Powerup Activated", true, (ConfigDescription)null);
			TNHLevelEvent = config.Bind<bool>(text2, "T&H Level Started", true, (ConfigDescription)null);
			TNHPhaseEvent = config.Bind<bool>(text2, "T&H Phase Changed", true, (ConfigDescription)null);
			TNHHoldPhaseEvent = config.Bind<bool>(text2, "T&H Hold Phase Changed", true, (ConfigDescription)null);
			TNHScoreEvent = config.Bind<bool>(text2, "T&H Score Changed", true, (ConfigDescription)null);
			TNHEncryptionDestroyed = config.Bind<bool>(text2, "T&H Encryption Destroyed", true, (ConfigDescription)null);
			TNHTokenEvent = config.Bind<bool>(text2, "T&H Tokens Changed", true, (ConfigDescription)null);
		}

		private static void OnServerEnabledChanged(bool enabled)
		{
			if (enabled)
			{
				Plugin.Start();
			}
			else
			{
				Plugin.Stop();
			}
		}

		private static void OnServerPortChanged(int port)
		{
			Server.Stop();
			Server.Start(port);
		}
	}
	[BepInProcess("h3vr.exe")]
	[BepInPlugin("xyz.bacur.plugins.h3status", "H3Status", "0.5.1")]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "xyz.bacur.plugins.h3status";

		public const string Name = "H3Status";

		public const string Version = "0.5.1";

		internal static ManualLogSource Logger;

		internal static Harmony Patcher;

		protected void Awake()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Expected O, but got Unknown
			Logger = ((BaseUnityPlugin)this).Logger;
			Patcher = new Harmony("xyz.bacur.plugins.h3status");
			Config.Init(((BaseUnityPlugin)this).Config);
			if (!Config.ServerEnabled.Value)
			{
				Logger.LogWarning((object)"Server disabled in config");
			}
			else
			{
				Start();
			}
		}

		protected void OnDestroy()
		{
			Stop();
		}

		internal static void Start()
		{
			Server.Start(Config.ServerPort.Value);
			Harmony patcher = Patcher;
			if (patcher != null)
			{
				patcher.PatchAll(typeof(SceneHandler));
			}
			Harmony patcher2 = Patcher;
			if (patcher2 != null)
			{
				patcher2.PatchAll(typeof(TNHScoreHandler));
			}
			Harmony patcher3 = Patcher;
			if (patcher3 != null)
			{
				patcher3.PatchAll(typeof(TNHPhaseHandler));
			}
			Harmony patcher4 = Patcher;
			if (patcher4 != null)
			{
				patcher4.PatchAll(typeof(PlayerHealthHandler));
			}
			Harmony patcher5 = Patcher;
			if (patcher5 != null)
			{
				patcher5.PatchAll(typeof(WeaponAmmoHandler));
			}
		}

		internal static void Stop()
		{
			Server.Stop();
			Harmony patcher = Patcher;
			if (patcher != null)
			{
				patcher.UnpatchSelf();
			}
		}
	}
	internal static class Server
	{
		private static WebSocketServer _server;

		private static readonly List<IWebSocketConnection> _instances = new List<IWebSocketConnection>();

		private static readonly JsonSerializerSettings _jsonSettings = new JsonSerializerSettings
		{
			ContractResolver = (IContractResolver)new CamelCasePropertyNamesContractResolver(),
			Converters = new List<JsonConverter>(1) { (JsonConverter)new StringEnumConverter(false) }
		};

		public static void Start(int port)
		{
			if (_server != null)
			{
				return;
			}
			FleckLog.Level = LogLevel.Warn;
			_server = new WebSocketServer($"ws://0.0.0.0:{port}");
			_server.Start(delegate(IWebSocketConnection instance)
			{
				instance.OnOpen = delegate
				{
					_instances.Add(instance);
					instance.Send(JsonConvert.SerializeObject((object)new Event
					{
						Type = EventType.Hello,
						Status = VersionHandler.GetVersionInfo()
					}, _jsonSettings));
				};
				instance.OnClose = delegate
				{
					_instances.Remove(instance);
				};
			});
			Plugin.Logger.LogInfo((object)$"Server started on port {port}");
		}

		public static void Stop()
		{
			if (_server == null)
			{
				return;
			}
			Plugin.Logger.LogInfo((object)"Server shutting down");
			foreach (IWebSocketConnection instance in _instances)
			{
				instance.Close();
			}
			_server.Dispose();
			_server = null;
		}

		public static void SendMessage(Event evt)
		{
			string message = JsonConvert.SerializeObject((object)evt, _jsonSettings);
			foreach (IWebSocketConnection instance in _instances)
			{
				instance.Send(message);
			}
		}
	}
}
namespace H3Status.Utils
{
	internal static class AmmoReader
	{
		public static void GetAmmo(string path)
		{
			//IL_0077: 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_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			Plugin.Logger.LogInfo((object)"WRITING FILE");
			StreamWriter streamWriter = new StreamWriter(path, append: false);
			try
			{
				ManagerSingleton<AM>.Instance.GenerateFireArmRoundDictionaries();
			}
			catch
			{
				Plugin.Logger.LogInfo((object)"TypeDict already generated");
			}
			foreach (KeyValuePair<FireArmRoundType, Dictionary<FireArmRoundClass, DisplayDataClass>> item in ManagerSingleton<AM>.Instance.TypeDic)
			{
				foreach (KeyValuePair<FireArmRoundClass, DisplayDataClass> item2 in item.Value)
				{
					string text = ((object)item.Key/*cast due to .constrained prefix*/).ToString() + "," + ((object)item2.Key/*cast due to .constrained prefix*/).ToString() + "," + ((Object)item2.Value.Mesh).name;
					Plugin.Logger.LogInfo((object)text);
					streamWriter.WriteLine(text);
				}
			}
			streamWriter.Flush();
			streamWriter.Close();
			Plugin.Logger.LogInfo((object)"DONE");
		}

		public unsafe static void GetShells(string path)
		{
			//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_0034: 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)
			Plugin.Logger.LogInfo((object)"WRITING FILE");
			StreamWriter streamWriter = new StreamWriter(path, append: false);
			foreach (FireArmRoundType type in ManagerSingleton<AM>.Instance.TypeList)
			{
				FVRFireArmRound component = ((AnvilAsset)AM.GetRoundSelfPrefab(type, AM.GetDefaultRoundClass(type))).GetGameObject().GetComponent<FVRFireArmRound>();
				if ((Object)(object)component != (Object)null)
				{
					component.Fire();
					if ((Object)(object)component != (Object)null && (Object)(object)component.FiredRenderer != (Object)null)
					{
						string text = ((object)(*(FireArmRoundType*)(&type))/*cast due to .constrained prefix*/).ToString() + "," + ((Object)((Component)component.FiredRenderer).gameObject.GetComponent<MeshFilter>().sharedMesh).name;
						Plugin.Logger.LogInfo((object)text);
						streamWriter.WriteLine(text);
					}
				}
			}
			streamWriter.Flush();
			streamWriter.Close();
			Plugin.Logger.LogInfo((object)"DONE");
		}
	}
	internal static class WeaponReader
	{
		public static void GetWeapons(string path, ItemSpawnerV2 spawner)
		{
			//IL_0131: 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_01d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0200: Unknown result type (might be due to invalid IL or missing references)
			//IL_0225: Unknown result type (might be due to invalid IL or missing references)
			//IL_022a: Unknown result type (might be due to invalid IL or missing references)
			//IL_024f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0254: Unknown result type (might be due to invalid IL or missing references)
			//IL_027b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0280: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0304: Unknown result type (might be due to invalid IL or missing references)
			//IL_032b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0330: Unknown result type (might be due to invalid IL or missing references)
			List<FVRObject> list = ManagerSingleton<IM>.Instance.odicTagCategory[(ObjectCategory)1];
			int count = list.Count;
			for (int i = 0; i < list.Count; i++)
			{
				bool flag = false;
				FVRObject val = list[i];
				if (val.OSple && val.SpawnedFromId != null && !(val.SpawnedFromId == string.Empty) && IM.HasSpawnedID(val.SpawnedFromId) && IM.GetSpawnerID(val.SpawnedFromId).IsDisplayedInMainEntry)
				{
					flag = true;
				}
				if (!flag)
				{
					list.RemoveAt(i--);
				}
			}
			Plugin.Logger.LogInfo((object)$"Found {list.Count} guns ({count - list.Count} excluded)");
			Plugin.Logger.LogInfo((object)"WRITING FILES");
			List<string> list2 = new List<string> { "Cube", "Sphere", "Capsule", "Quad" };
			foreach (FVRObject item in list)
			{
				string itemID = IM.GetSpawnerID(item.SpawnedFromId).ItemID;
				Plugin.Logger.LogInfo((object)itemID);
				GameObject val2 = Object.Instantiate<GameObject>(((AnvilAsset)item).GetGameObject(), Vector3.zero, Quaternion.identity);
				val2.SetActive(false);
				StreamWriter streamWriter = new StreamWriter(path + "/" + itemID + ".csv", append: false);
				MeshFilter[] componentsInChildren = val2.GetComponentsInChildren<MeshFilter>(false);
				foreach (MeshFilter val3 in componentsInChildren)
				{
					if ((Object)(object)val3.sharedMesh != (Object)null)
					{
						string name = ((Object)val3.sharedMesh).name;
						if (!list2.Contains(name))
						{
							string value = ((Object)val3.sharedMesh).name + "," + ((Component)val3).transform.position.x.ToString("F6") + "," + ((Component)val3).transform.position.y.ToString("F6") + "," + ((Component)val3).transform.position.z.ToString("F6") + "," + ((Component)val3).transform.rotation.x.ToString("F6") + "," + ((Component)val3).transform.rotation.y.ToString("F6") + "," + ((Component)val3).transform.rotation.z.ToString("F6") + "," + ((Component)val3).transform.localScale.x.ToString("F6") + "," + ((Component)val3).transform.localScale.y.ToString("F6") + "," + ((Component)val3).transform.localScale.z.ToString("F6");
							streamWriter.WriteLine(value);
						}
					}
				}
				Object.Destroy((Object)(object)val2);
				streamWriter.Flush();
				streamWriter.Close();
			}
			Plugin.Logger.LogInfo((object)"DONE");
		}
	}
}
namespace H3Status.Patches
{
	internal static class VersionHandler
	{
		private static VersionStatus versionStatus;

		public static VersionStatus GetVersionInfo()
		{
			versionStatus.Version = "0.5.1";
			versionStatus.GameVersion = $"{GM.Version_UpdateNumber}.{GM.Version_AlphaNumber}.{GM.Version_PatchNumber}";
			return versionStatus;
		}
	}
	[HarmonyPatch]
	internal static class SceneHandler
	{
		public static string activeScene = string.Empty;

		private static SceneStatus sceneStatus = default(SceneStatus);

		[HarmonyPostfix]
		[HarmonyPatch(typeof(SteamVR_LoadLevel), "Begin")]
		private static void SceneEvent(string levelName)
		{
			if (Config.SceneEvent.Value)
			{
				activeScene = levelName;
				sceneStatus = new SceneStatus
				{
					Name = levelName
				};
				Server.SendMessage(new Event
				{
					Type = EventType.SceneEvent,
					Status = sceneStatus
				});
			}
		}
	}
	[HarmonyPatch]
	internal static class TNHPhaseHandler
	{
		private static readonly string[] holdNamesInstitution = new string[20]
		{
			"HUB", "LIBRARY", "GARDEN", "ATRIUM", "LOBBY", "HEDRONS", "TURBINE", "HYDRO", "SPILLWAY", "RODS",
			"STORAGE", "APRROACH", "CROSSOVER", "PIPEWORKS", "VOID", "CONCOURSE", "BUNKER", "INCLINATOR", "ABYSS", "SUBSTATION"
		};

		private static readonly string[] supplyNamesInstitution = new string[16]
		{
			"ARRAY", "STUDIO", "SUITE", "LOFT", "PENTHOUSE", "GREENWALL", "FENESTRA", "JUDGEMENT", "PRESIDIO", "DISSONANCE",
			"CLERESTORY", "HELIX", "FACILITY", "STACKS", "ALTAR", "PUMP"
		};

		private static bool isInitialized = false;

		private static TNHLevelStatus levelStatus = default(TNHLevelStatus);

		private static TNHPhaseStatus phaseStatus = default(TNHPhaseStatus);

		private static TNHHoldPhaseStatus holdPhaseStatus = default(TNHHoldPhaseStatus);

		[HarmonyPrefix]
		[HarmonyPatch(typeof(TNH_Manager), "DelayedInit")]
		private static void TNHLevelEventPre(TNH_Manager __instance)
		{
			isInitialized = __instance.m_hasInit;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(TNH_Manager), "DelayedInit")]
		private static void TNHLevelEventPost(TNH_Manager __instance)
		{
			//IL_0070: 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_008a: 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_00a4: Unknown result type (might be due to invalid IL or missing references)
			if (Config.TNHLevelEvent.Value && !isInitialized && __instance.m_hasInit)
			{
				levelStatus = new TNHLevelStatus
				{
					Seed = __instance.HoldSequenceSeed,
					EquipmentSeed = __instance.equipmentSeed,
					LevelName = __instance.LevelName,
					CharacterName = __instance.C.DisplayName,
					ScoreMultiplier = TNHScoreHandler.GetMultiplier(),
					AiDifficulty = __instance.AI_Difficulty,
					RadarMode = __instance.RadarMode,
					TargetMode = __instance.TargetMode,
					HealthMode = __instance.HealthMode,
					EquipmentMode = __instance.EquipmentMode
				};
				Server.SendMessage(new Event
				{
					Type = EventType.TNHLevelEvent,
					Status = levelStatus
				});
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(TNH_Manager), "SetPhase")]
		private static void TNHPhaseEvent(TNH_Phase p, TNH_Manager __instance)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			if (!Config.TNHPhaseEvent.Value)
			{
				return;
			}
			phaseStatus = new TNHPhaseStatus
			{
				Phase = p,
				Level = __instance.m_level,
				Count = __instance.m_maxLevels,
				Seed = __instance.m_holdSequenceSeed,
				Hold = __instance.m_curHoldIndex,
				Supply = new List<int>(),
				HoldName = null,
				SupplyNames = null
			};
			foreach (int activeSupplyPointIndicy in __instance.m_activeSupplyPointIndicies)
			{
				phaseStatus.Supply.Add(activeSupplyPointIndicy);
			}
			if (SceneHandler.activeScene == "Institution")
			{
				phaseStatus.HoldName = holdNamesInstitution[__instance.m_curHoldIndex];
				phaseStatus.SupplyNames = new List<string>();
				foreach (int activeSupplyPointIndicy2 in __instance.m_activeSupplyPointIndicies)
				{
					phaseStatus.SupplyNames.Add(supplyNamesInstitution[activeSupplyPointIndicy2]);
				}
			}
			Server.SendMessage(new Event
			{
				Type = EventType.TNHPhaseEvent,
				Status = phaseStatus
			});
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(TNH_HoldPoint), "BeginAnalyzing")]
		[HarmonyPatch(typeof(TNH_HoldPoint), "IdentifyEncryption")]
		[HarmonyPatch(typeof(TNH_HoldPoint), "CompletePhase")]
		private static void TNHHoldPhaseEvent(TNH_HoldPoint __instance)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			if (Config.TNHHoldPhaseEvent.Value)
			{
				holdPhaseStatus = new TNHHoldPhaseStatus
				{
					Phase = __instance.m_state,
					Level = __instance.m_phaseIndex,
					Count = __instance.H.Phases.Count,
					EncryptionType = __instance.m_curPhase.Encryption,
					EncryptionCount = __instance.m_numTargsToSpawn,
					EncryptionTime = 120f
				};
				Server.SendMessage(new Event
				{
					Type = EventType.TNHHoldPhaseEvent,
					Status = holdPhaseStatus
				});
			}
		}
	}
	[HarmonyPatch]
	internal static class TNHScoreHandler
	{
		private static TNHScoreStatus scoreStatus = default(TNHScoreStatus);

		private static TNHTokenStatus tokenStatus = default(TNHTokenStatus);

		private static readonly int[] eventMultiplier = new int[15]
		{
			12000, 12, 1, 12, 300, 100, 100, 100, 100, 1,
			250, 12, 1, 1, 250
		};

		private static readonly bool[] eventIsCounted = new bool[15]
		{
			true, true, false, true, true, true, true, false, false, false,
			false, true, false, false, false
		};

		private static int GetEventScore(ScoringEvent ev, int num)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			return num * eventMultiplier[ev];
		}

		private static int GetTotalScore()
		{
			int num = 0;
			int multiplier = GetMultiplier();
			for (int i = 0; i <= 14; i++)
			{
				if (eventIsCounted[i])
				{
					num += GetEventScore((ScoringEvent)i, GM.TNH_Manager.Nums[i]);
				}
			}
			return num * multiplier;
		}

		internal static int GetMultiplier()
		{
			//IL_0007: 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_001f: Invalid comparison between Unknown and I4
			//IL_002a: 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_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Invalid comparison between Unknown and I4
			int num = 1;
			if ((int)GM.TNHOptions.TargetModeSetting == 0)
			{
				num += 3;
			}
			else if ((int)GM.TNHOptions.TargetModeSetting == 1)
			{
				num += 2;
			}
			if ((int)GM.TNHOptions.AIDifficultyModifier == 0)
			{
				num += 3;
			}
			if ((int)GM.TNHOptions.RadarModeModifier == 0)
			{
				num += 2;
			}
			else if ((int)GM.TNHOptions.RadarModeModifier != 1)
			{
				num += 3;
			}
			return num;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(TNH_Manager), "IncrementScoringStat")]
		private static void TNHScoreEvent(ScoringEvent ev, int num, TNH_Manager __instance)
		{
			//IL_0005: 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_0031: 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)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			if (eventIsCounted[ev])
			{
				if (Config.LogScoreEvents.Value)
				{
					Plugin.Logger.LogMessage((object)$"{ev}: {GetEventScore(ev, num) * GetMultiplier()} ({GetEventScore(ev, num)}x{GetMultiplier()})");
				}
				if (Config.TNHScoreEvent.Value)
				{
					scoreStatus = new TNHScoreStatus
					{
						Type = ev,
						Value = GetEventScore(ev, num),
						Mult = GetMultiplier(),
						Score = GetTotalScore()
					};
					Server.SendMessage(new Event
					{
						Type = EventType.TNHScoreEvent,
						Status = scoreStatus
					});
				}
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(TNH_HoldPoint), "TargetDestroyed")]
		private static void TNHEncryptionDestroyed()
		{
			if (Config.TNHEncryptionDestroyed.Value)
			{
				Server.SendMessage(new Event
				{
					Type = EventType.TNHEncryptionDestroyed
				});
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(TNH_Manager), "AddTokens")]
		private static void TNHTokenEventAdd(int i, TNH_Manager __instance)
		{
			if (Config.TNHTokenEvent.Value)
			{
				tokenStatus = new TNHTokenStatus
				{
					Change = i,
					Tokens = __instance.m_numTokens
				};
				Server.SendMessage(new Event
				{
					Type = EventType.TNHTokenEvent,
					Status = tokenStatus
				});
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(TNH_Manager), "SubtractTokens")]
		private static void TNHTokenEventSubtract(int i, TNH_Manager __instance)
		{
			if (Config.TNHTokenEvent.Value)
			{
				tokenStatus = new TNHTokenStatus
				{
					Change = -i,
					Tokens = __instance.m_numTokens
				};
				Server.SendMessage(new Event
				{
					Type = EventType.TNHTokenEvent,
					Status = tokenStatus
				});
			}
		}
	}
	[HarmonyPatch]
	internal static class PlayerHealthHandler
	{
		private static HealthStatus healthStatus;

		private static BuffStatus buffStatus;

		[HarmonyPostfix]
		[HarmonyPatch(typeof(FVRPlayerBody), "RegisterPlayerHit")]
		private static void HealthEventHit(float DamagePoints, bool FromSelf, int iff, FVRPlayerBody __instance)
		{
			if (Config.HealthEvent.Value)
			{
				healthStatus = new HealthStatus
				{
					Change = -(int)DamagePoints,
					Health = (int)__instance.Health,
					MaxHealth = (int)__instance.m_startingHealth
				};
				Server.SendMessage(new Event
				{
					Type = EventType.HealthEvent,
					Status = healthStatus
				});
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(FVRPlayerBody), "HarmPercent")]
		private static void HealthEventHarm(float f, FVRPlayerBody __instance)
		{
			if (Config.HealthEvent.Value)
			{
				healthStatus = new HealthStatus
				{
					Change = -(int)(__instance.m_startingHealth * f),
					Health = (int)__instance.Health,
					MaxHealth = (int)__instance.m_startingHealth
				};
				Server.SendMessage(new Event
				{
					Type = EventType.HealthEvent,
					Status = healthStatus
				});
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(FVRPlayerBody), "Init")]
		private static void HealthEventInit(FVRPlayerBody __instance)
		{
			if (Config.HealthEvent.Value)
			{
				healthStatus = new HealthStatus
				{
					Change = 0f,
					Health = (int)__instance.Health,
					MaxHealth = (int)__instance.m_startingHealth
				};
				Server.SendMessage(new Event
				{
					Type = EventType.HealthEvent,
					Status = healthStatus
				});
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(FVRPlayerBody), "SetHealthThreshold")]
		private static void HealthEventUpdate(float h, FVRPlayerBody __instance)
		{
			if (Config.HealthEvent.Value)
			{
				healthStatus = new HealthStatus
				{
					Change = (int)(h - __instance.Health),
					Health = (int)h,
					MaxHealth = (int)h
				};
				Server.SendMessage(new Event
				{
					Type = EventType.HealthEvent,
					Status = healthStatus
				});
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(FVRPlayerBody), "HealPercent")]
		private static void HealthEventHeal(float f, FVRPlayerBody __instance)
		{
			if (Config.HealthEvent.Value)
			{
				healthStatus = new HealthStatus
				{
					Change = (int)(__instance.m_startingHealth * f),
					Health = (int)__instance.Health,
					MaxHealth = (int)__instance.m_startingHealth
				};
				Server.SendMessage(new Event
				{
					Type = EventType.HealthEvent,
					Status = healthStatus
				});
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(FVRPlayerBody), "ActivatePower")]
		private static void BuffEvent(PowerupType type, PowerUpIntensity intensity, PowerUpDuration d, bool isPuke, bool isInverted, float DurationOverride = -1f)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Expected I4, but got Unknown
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			if (Config.BuffEvent.Value)
			{
				float duration = 1f;
				switch ((int)d)
				{
				case 0:
					duration = 30f;
					break;
				case 1:
					duration = 20f;
					break;
				case 2:
					duration = 10f;
					break;
				case 3:
					duration = 2f;
					break;
				case 4:
					duration = 40f;
					break;
				}
				if (DurationOverride > 0f)
				{
					duration = DurationOverride;
				}
				buffStatus = new BuffStatus
				{
					Type = type,
					Duration = duration,
					Inverted = isInverted
				};
				Server.SendMessage(new Event
				{
					Type = EventType.BuffEvent,
					Status = buffStatus
				});
			}
		}
	}
	[HarmonyPatch]
	internal static class WeaponAmmoHandler
	{
		private static bool isUpdatePending;

		private static AmmoStatus ammoStatus;

		[HarmonyPrefix]
		[HarmonyPatch(typeof(FVRFireArm), "FVRFixedUpdate")]
		private static void HandlePendingEvent()
		{
			if (Config.AmmoEvent.Value && isUpdatePending)
			{
				isUpdatePending = false;
				Server.SendMessage(new Event
				{
					Type = EventType.AmmoEvent,
					Status = ammoStatus
				});
			}
		}

		private static void UpdateAmmoCount(FVRFireArm fireArm)
		{
			//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_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_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cb: 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_00f7: Unknown result type (might be due to invalid IL or missing references)
			//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)
			if ((Object)(object)fireArm == (Object)null || (Object)(object)((FVRInteractiveObject)fireArm).m_hand == (Object)null)
			{
				return;
			}
			string weapon = string.Empty;
			int hand = (((FVRInteractiveObject)fireArm).m_hand.IsThisTheRightHand ? 1 : 0);
			FireArmRoundType roundType = fireArm.RoundType;
			FireArmRoundClass roundClass = (FireArmRoundClass)0;
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			try
			{
				roundClass = AM.GetDefaultRoundClass(fireArm.RoundType);
			}
			catch
			{
			}
			if ((Object)(object)((FVRPhysicalObject)fireArm).ObjectWrapper != (Object)null)
			{
				weapon = ((!IM.HasSpawnedID(((FVRPhysicalObject)fireArm).ObjectWrapper.ItemID)) ? ((FVRPhysicalObject)fireArm).ObjectWrapper.DisplayName : IM.GetSpawnerID(((FVRPhysicalObject)fireArm).ObjectWrapper.ItemID).DisplayName);
			}
			if ((Object)(object)fireArm.Magazine != (Object)null)
			{
				num3 += fireArm.Magazine.m_capacity;
				num += fireArm.Magazine.m_numRounds;
				if (fireArm.Magazine.LoadedRounds != null)
				{
					for (int i = 0; i < fireArm.Magazine.LoadedRounds.Length; i++)
					{
						if (fireArm.Magazine.LoadedRounds[i] != null)
						{
							roundClass = fireArm.Magazine.LoadedRounds[i].LR_Class;
						}
					}
				}
			}
			if ((Object)(object)fireArm.BeltDD != (Object)null)
			{
				num += fireArm.BeltDD.m_roundsOnBelt;
			}
			if (fireArm.FChambers != null)
			{
				num3 += fireArm.FChambers.Count;
				foreach (FVRFireArmChamber fChamber in fireArm.FChambers)
				{
					if (!((Object)(object)fChamber.m_round == (Object)null))
					{
						if (fChamber.IsSpent)
						{
							num2++;
							continue;
						}
						roundClass = fChamber.m_round.RoundClass;
						num++;
					}
				}
			}
			ammoStatus = new AmmoStatus
			{
				Weapon = weapon,
				Hand = hand,
				RoundType = roundType,
				RoundClass = roundClass,
				Current = num,
				Spent = num2,
				Capacity = num3
			};
			isUpdatePending = true;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(FVRFireArmMagazine), "AddRound", new Type[]
		{
			typeof(FireArmRoundClass),
			typeof(bool),
			typeof(bool)
		})]
		[HarmonyPatch(typeof(FVRFireArmMagazine), "AddRound", new Type[]
		{
			typeof(FVRFireArmRound),
			typeof(bool),
			typeof(bool),
			typeof(bool)
		})]
		private static void AmmoEventMagazine(FVRFireArmMagazine __instance)
		{
			if (Config.AmmoEvent.Value)
			{
				UpdateAmmoCount(__instance.FireArm);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(FVRFireArm), "LoadMag")]
		[HarmonyPatch(typeof(FVRFireArm), "EjectMag")]
		private static void AmmoEventFireArm(FVRFireArm __instance)
		{
			if (Config.AmmoEvent.Value)
			{
				UpdateAmmoCount(__instance);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(FVRFireArmChamber), "UpdateProxyDisplay")]
		private static void AmmoEventChamber(FVRFireArmChamber __instance)
		{
			if (!Config.AmmoEvent.Value)
			{
				return;
			}
			if ((Object)(object)__instance.Firearm != (Object)null)
			{
				UpdateAmmoCount(__instance.Firearm);
				return;
			}
			Transform parent = ((Component)__instance).transform.parent;
			FVRFireArm val = ((parent != null) ? ((Component)parent).gameObject.GetComponent<FVRFireArm>() : null);
			if ((Object)(object)val != (Object)null)
			{
				UpdateAmmoCount(val);
			}
		}
	}
}
namespace H3Status.Model
{
	internal struct Event
	{
		public EventType Type { get; set; }

		public object? Status { get; set; }
	}
	[JsonConverter(typeof(StringEnumConverter), new object[] { true })]
	internal enum EventType
	{
		Hello,
		SceneEvent,
		AmmoEvent,
		HealthEvent,
		BuffEvent,
		TNHLevelEvent,
		TNHPhaseEvent,
		TNHHoldPhaseEvent,
		TNHScoreEvent,
		TNHEncryptionDestroyed,
		TNHTokenEvent
	}
	internal struct VersionStatus
	{
		public string Version { get; set; }

		public string GameVersion { get; set; }
	}
	internal struct SceneStatus
	{
		public string Name { get; set; }
	}
	internal struct AmmoStatus
	{
		public string Weapon { get; set; }

		public FireArmRoundType RoundType { get; set; }

		public FireArmRoundClass RoundClass { get; set; }

		public int Hand { get; set; }

		public int Current { get; set; }

		public int Spent { get; set; }

		public int Capacity { get; set; }
	}
	internal struct HealthStatus
	{
		public float Change { get; set; }

		public float Health { get; set; }

		public float MaxHealth { get; set; }
	}
	internal struct BuffStatus
	{
		public PowerupType Type { get; set; }

		public float Duration { get; set; }

		public bool Inverted { get; set; }
	}
	internal struct TNHLevelStatus
	{
		public int Seed { get; set; }

		public int EquipmentSeed { get; set; }

		public string LevelName { get; set; }

		public string CharacterName { get; set; }

		public int ScoreMultiplier { get; set; }

		public TNHModifier_AIDifficulty AiDifficulty { get; set; }

		public TNHModifier_RadarMode RadarMode { get; set; }

		public TNHSetting_TargetMode TargetMode { get; set; }

		public TNHSetting_HealthMode HealthMode { get; set; }

		public TNHSetting_EquipmentMode EquipmentMode { get; set; }
	}
	internal struct TNHPhaseStatus
	{
		public TNH_Phase Phase { get; set; }

		public int Level { get; set; }

		public int Count { get; set; }

		public int Seed { get; set; }

		public int Hold { get; set; }

		public List<int> Supply { get; set; }

		public string? HoldName { get; set; }

		public List<string>? SupplyNames { get; set; }
	}
	internal struct TNHHoldPhaseStatus
	{
		public HoldState Phase { get; set; }

		public int Level { get; set; }

		public int Count { get; set; }

		public TNH_EncryptionType EncryptionType { get; set; }

		public int EncryptionCount { get; set; }

		public float EncryptionTime { get; set; }
	}
	internal struct TNHScoreStatus
	{
		public ScoringEvent Type { get; set; }

		public int Value { get; set; }

		public int Mult { get; set; }

		public int Score { get; set; }
	}
	internal struct TNHTokenStatus
	{
		public int Change { get; set; }

		public int Tokens { get; set; }
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
	[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
	public class ExtensionAttribute : Attribute
	{
	}
}