Decompiled source of PeakIntiface v0.4.2

BepInEx\plugins\PeakIntiface\Buttplug.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.WebSockets;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Buttplug.Core;
using Buttplug.Core.Messages;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: InternalsVisibleTo("Buttplug.Test")]
[assembly: InternalsVisibleTo("Buttplug.Client.Test")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Nonpolynomial Labs, LLC")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright Nonpolynomial Labs, LLC")]
[assembly: AssemblyDescription("Buttplug Sex Toy Control Library. Contains Core (messages, errors, etc), Client, and Websocket Connector components")]
[assembly: AssemblyFileVersion("5.0.1.0")]
[assembly: AssemblyInformationalVersion("5.0.1+08b292884fa1a73f5cdd64cfa4aa956a2b22d14b")]
[assembly: AssemblyProduct("Buttplug")]
[assembly: AssemblyTitle("Buttplug")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/buttplugio/buttplug-csharp")]
[assembly: AssemblyVersion("5.0.1.0")]
namespace Buttplug.Core
{
	public static class ButtplugConsts
	{
		public const uint SystemMsgId = 0u;

		public const uint DefaultMsgId = 1u;

		public const uint MaxId = uint.MaxValue;

		public const uint ProtocolVersionMajor = 4u;

		public const uint ProtocolVersionMinor = 0u;

		public const uint CurrentSpecVersion = 4u;
	}
	public class ButtplugDeviceException : ButtplugException
	{
		public ButtplugDeviceException(string message, uint id = 0u, Exception inner = null)
			: base(message, Error.ErrorClass.ERROR_DEVICE, id, inner)
		{
		}
	}
	public class ButtplugException : Exception
	{
		public Error ButtplugErrorMessage { get; }

		public static ButtplugException FromError(Error msg)
		{
			return msg.ErrorCode switch
			{
				Error.ErrorClass.ERROR_DEVICE => new ButtplugDeviceException(msg.ErrorMessage, msg.Id), 
				Error.ErrorClass.ERROR_INIT => new ButtplugHandshakeException(msg.ErrorMessage, msg.Id), 
				Error.ErrorClass.ERROR_MSG => new ButtplugMessageException(msg.ErrorMessage, msg.Id), 
				Error.ErrorClass.ERROR_PING => new ButtplugPingException(msg.ErrorMessage, msg.Id), 
				Error.ErrorClass.ERROR_UNKNOWN => new ButtplugException(msg.ErrorMessage, msg.Id), 
				_ => new ButtplugException(msg.ErrorMessage, msg.Id), 
			};
		}

		public ButtplugException(string message, uint id = 0u, Exception inner = null)
			: this(message, Error.ErrorClass.ERROR_UNKNOWN, id, inner)
		{
		}

		public ButtplugException(string message, Error.ErrorClass err = Error.ErrorClass.ERROR_UNKNOWN, uint id = 0u, Exception inner = null)
			: base(message, inner)
		{
			ButtplugErrorMessage = new Error(message, err, id);
		}
	}
	public class ButtplugExceptionEventArgs : EventArgs
	{
		public ButtplugException Exception { get; }

		public ButtplugExceptionEventArgs(ButtplugException ex)
		{
			Exception = ex;
		}
	}
	public class ButtplugHandshakeException : ButtplugException
	{
		public ButtplugHandshakeException(string message, uint id = 0u, Exception inner = null)
			: base(message, Error.ErrorClass.ERROR_INIT, id, inner)
		{
		}
	}
	public class ButtplugJsonMessageParser
	{
		private readonly Dictionary<string, Type> _messageTypes;

		private readonly JsonSerializer _serializer;

		public ButtplugJsonMessageParser()
		{
			//IL_0007: 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_0018: Expected O, but got Unknown
			_serializer = new JsonSerializer
			{
				MissingMemberHandling = (MissingMemberHandling)0
			};
			_messageTypes = new Dictionary<string, Type>();
			foreach (Type allMessageType in ButtplugUtils.GetAllMessageTypes())
			{
				_messageTypes.Add(allMessageType.Name, allMessageType);
			}
			if (!_messageTypes.Any())
			{
				throw new ButtplugMessageException("No message types available.");
			}
		}

		public IEnumerable<ButtplugMessage> Deserialize(string jsonMsg)
		{
			//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_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Expected O, but got Unknown
			//IL_0031: Expected O, but got Unknown
			//IL_005b: Expected O, but got Unknown
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			JsonTextReader val = new JsonTextReader((TextReader)new StringReader(jsonMsg))
			{
				CloseInput = false,
				SupportMultipleContent = true
			};
			List<ButtplugMessage> list = new List<ButtplugMessage>();
			while (true)
			{
				try
				{
					if (!((JsonReader)val).Read())
					{
						return list;
					}
				}
				catch (JsonReaderException ex)
				{
					JsonReaderException ex2 = ex;
					throw new ButtplugMessageException("Not valid JSON: " + jsonMsg + " - " + ((Exception)(object)ex2).Message);
				}
				JArray val2;
				try
				{
					val2 = JArray.Load((JsonReader)(object)val);
				}
				catch (JsonReaderException ex3)
				{
					JsonReaderException ex4 = ex3;
					throw new ButtplugMessageException("Not valid JSON: " + jsonMsg + " - " + ((Exception)(object)ex4).Message);
				}
				foreach (JObject item in ((JToken)val2).Children<JObject>())
				{
					string name = item.Properties().First().Name;
					if (!_messageTypes.ContainsKey(name))
					{
						throw new ButtplugMessageException(name + " is not a valid message class");
					}
					list.Add(DeserializeAs(item, _messageTypes[name]));
				}
			}
		}

		private ButtplugMessage DeserializeAs(JObject obj, Type msgType)
		{
			//IL_00c0: Expected O, but got Unknown
			if (!msgType.IsSubclassOf(typeof(ButtplugMessage)))
			{
				throw new ButtplugMessageException("Type " + msgType.Name + " is not a subclass of ButtplugMessage");
			}
			if (msgType.Namespace != "Buttplug.Core.Messages")
			{
				throw new ButtplugMessageException("Type " + msgType.Name + " (" + msgType.Namespace + ") is not in the namespace of Buttplug.Core.Messages");
			}
			string name = ButtplugMessage.GetName(msgType);
			try
			{
				return (ButtplugMessage)((JToken)Extensions.Value<JObject>((IEnumerable<JToken>)obj[name])).ToObject(msgType, _serializer);
			}
			catch (InvalidCastException ex)
			{
				throw new ButtplugMessageException($"Could not create message for JSON {obj}: {ex.Message}");
			}
			catch (JsonSerializationException ex2)
			{
				JsonSerializationException ex3 = ex2;
				throw new ButtplugMessageException($"Could not create message for JSON {obj}: {((Exception)(object)ex3).Message}");
			}
		}

		public string Serialize(ButtplugMessage msg)
		{
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			if (msg.GetType().Namespace != "Buttplug.Core.Messages")
			{
				throw new ButtplugMessageException("Type " + msg.GetType().Name + " (" + msg.GetType().Namespace + ") is not in the namespace of Buttplug.Core.Messages");
			}
			JObject val = ButtplugMessageToJObject(msg);
			if (val == null)
			{
				throw new ButtplugMessageException("Message cannot be converted to JSON.", msg.Id);
			}
			JArray val2 = new JArray();
			val2.Add((JToken)(object)val);
			return ((JToken)val2).ToString((Formatting)0, Array.Empty<JsonConverter>());
		}

		public string Serialize(IEnumerable<ButtplugMessage> msgs)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			JArray val = new JArray();
			foreach (ButtplugMessage msg in msgs)
			{
				JObject val2 = ButtplugMessageToJObject(msg);
				if (val2 != null)
				{
					val.Add((JToken)(object)val2);
				}
			}
			if (!((IEnumerable<JToken>)val).Any())
			{
				throw new ButtplugMessageException("No messages serialized.");
			}
			return ((JToken)val).ToString((Formatting)0, Array.Empty<JsonConverter>());
		}

		private JObject ButtplugMessageToJObject(ButtplugMessage msg)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			return new JObject((object)new JProperty(msg.Name, (object)JObject.FromObject((object)msg)));
		}
	}
	public class ButtplugMessageException : ButtplugException
	{
		public ButtplugMessageException(string message, uint id = 0u, Exception inner = null)
			: base(message, Error.ErrorClass.ERROR_MSG, id, inner)
		{
		}
	}
	public class ButtplugPingException : ButtplugException
	{
		public ButtplugPingException(string message, uint id = 0u, Exception inner = null)
			: base(message, Error.ErrorClass.ERROR_PING, id, inner)
		{
		}
	}
	public static class ButtplugUtils
	{
		public static IEnumerable<Type> GetAllMessageTypes()
		{
			IEnumerable<Type> enumerable;
			try
			{
				enumerable = Assembly.GetAssembly(typeof(ButtplugMessage))?.GetTypes();
			}
			catch (ReflectionTypeLoadException ex)
			{
				enumerable = ex.Types;
			}
			return (enumerable ?? throw new InvalidOperationException()).Where((Type type) => type != null && type.IsClass && type.IsSubclassOf(typeof(ButtplugMessage)) && type != typeof(ButtplugDeviceMessage));
		}

		[DebuggerStepThrough]
		public static void ArgumentNotNull(object argument, string argumentName)
		{
			if (argument == null)
			{
				throw new ArgumentNullException(argumentName);
			}
		}

		public static Type GetMessageType(string messageName)
		{
			return Type.GetType("Buttplug.Core.Messages." + messageName);
		}
	}
}
namespace Buttplug.Core.Messages
{
	public class ButtplugDeviceMessage : ButtplugMessage
	{
		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public uint DeviceIndex { get; set; }

		public ButtplugDeviceMessage(uint id = 1u, uint deviceIndex = uint.MaxValue)
			: base(id)
		{
			DeviceIndex = deviceIndex;
		}
	}
	public abstract class ButtplugMessage
	{
		private static readonly Dictionary<Type, ButtplugMessageMetadata> _metadataCache = new Dictionary<Type, ButtplugMessageMetadata>();

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

		[JsonIgnore]
		public string Name => GetName(GetType());

		protected ButtplugMessage(uint id)
		{
			Id = id;
		}

		private static T GetMessageAttribute<T>(Type msgType, Func<ButtplugMessageMetadata, T> func)
		{
			ButtplugUtils.ArgumentNotNull(msgType, "msgType");
			ButtplugUtils.ArgumentNotNull(func, "func");
			if (!msgType.IsSubclassOf(typeof(ButtplugMessage)))
			{
				throw new ArgumentException("Argument " + msgType.Name + " must be a subclass of ButtplugMessage");
			}
			if (_metadataCache.ContainsKey(msgType))
			{
				return func(_metadataCache[msgType]);
			}
			Attribute[] customAttributes = Attribute.GetCustomAttributes(msgType);
			for (int i = 0; i < customAttributes.Length; i++)
			{
				if (customAttributes[i] is ButtplugMessageMetadata buttplugMessageMetadata)
				{
					_metadataCache[msgType] = buttplugMessageMetadata;
					return func(buttplugMessageMetadata);
				}
			}
			throw new ArgumentException($"Type {msgType} does not have ButtplugMessageMetadata Attributes");
		}

		public static string GetName(Type msgType)
		{
			return GetMessageAttribute(msgType, (ButtplugMessageMetadata md) => md.Name);
		}
	}
	public interface IButtplugMessageOutgoingOnly
	{
	}
	[AttributeUsage(AttributeTargets.Class)]
	public class ButtplugMessageMetadata : Attribute
	{
		public string Name { get; }

		public ButtplugMessageMetadata(string name)
		{
			Name = name;
		}
	}
	public interface IButtplugDeviceInfoMessage
	{
		string DeviceName { get; }

		uint DeviceIndex { get; }

		string DeviceDisplayName { get; }

		uint DeviceMessageTimingGap { get; }

		Dictionary<string, DeviceFeature> DeviceFeatures { get; }
	}
	public class MessageReceivedEventArgs : EventArgs
	{
		public ButtplugMessage Message { get; }

		public MessageReceivedEventArgs(ButtplugMessage message)
		{
			Message = message;
		}
	}
	[JsonConverter(typeof(StringEnumConverter))]
	public enum OutputType
	{
		[EnumMember(Value = "Unknown")]
		Unknown,
		[EnumMember(Value = "Vibrate")]
		Vibrate,
		[EnumMember(Value = "Oscillate")]
		Oscillate,
		[EnumMember(Value = "Rotate")]
		Rotate,
		[EnumMember(Value = "Position")]
		Position,
		[EnumMember(Value = "HwPositionWithDuration")]
		HwPositionWithDuration,
		[EnumMember(Value = "Led")]
		Led,
		[EnumMember(Value = "Temperature")]
		Temperature,
		[EnumMember(Value = "Constrict")]
		Constrict,
		[EnumMember(Value = "Spray")]
		Spray
	}
	[JsonConverter(typeof(StringEnumConverter))]
	public enum InputType
	{
		[EnumMember(Value = "Unknown")]
		Unknown,
		[EnumMember(Value = "Battery")]
		Battery,
		[EnumMember(Value = "RSSI")]
		RSSI,
		[EnumMember(Value = "Button")]
		Button,
		[EnumMember(Value = "Pressure")]
		Pressure,
		[EnumMember(Value = "Depth")]
		Depth,
		[EnumMember(Value = "Position")]
		Position
	}
	[JsonConverter(typeof(StringEnumConverter))]
	public enum InputCommandType
	{
		[EnumMember(Value = "Read")]
		Read,
		[EnumMember(Value = "Subscribe")]
		Subscribe,
		[EnumMember(Value = "Unsubscribe")]
		Unsubscribe
	}
	[ButtplugMessageMetadata("Ok")]
	public class Ok : ButtplugMessage, IButtplugMessageOutgoingOnly
	{
		public Ok(uint id)
			: base(id)
		{
		}
	}
	[ButtplugMessageMetadata("Error")]
	public class Error : ButtplugMessage, IButtplugMessageOutgoingOnly
	{
		public enum ErrorClass
		{
			ERROR_UNKNOWN,
			ERROR_INIT,
			ERROR_PING,
			ERROR_MSG,
			ERROR_DEVICE
		}

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public ErrorClass ErrorCode;

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public string ErrorMessage;

		public Error(string errorMessage, ErrorClass errorCode, uint id)
			: base(id)
		{
			ErrorMessage = errorMessage;
			ErrorCode = errorCode;
		}
	}
	public class DeviceFeatureOutput
	{
		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public int[] Value;

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public int[] Duration;
	}
	public class DeviceFeatureInput
	{
		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public int[][] Value;

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public InputCommandType[] Command;
	}
	public class DeviceFeature
	{
		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public string FeatureDescription;

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public uint FeatureIndex;

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public Dictionary<string, DeviceFeatureOutput> Output;

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public Dictionary<string, DeviceFeatureInput> Input;

		public bool HasOutput(OutputType type)
		{
			if (Output != null)
			{
				return Output.ContainsKey(type.ToString());
			}
			return false;
		}

		public bool HasInput(InputType type)
		{
			if (Input != null)
			{
				return Input.ContainsKey(type.ToString());
			}
			return false;
		}

		public DeviceFeatureOutput GetOutput(OutputType type)
		{
			if (Output == null || !Output.ContainsKey(type.ToString()))
			{
				return null;
			}
			return Output[type.ToString()];
		}

		public DeviceFeatureInput GetInput(InputType type)
		{
			if (Input == null || !Input.ContainsKey(type.ToString()))
			{
				return null;
			}
			return Input[type.ToString()];
		}
	}
	public class DeviceInfo : IButtplugDeviceInfoMessage
	{
		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public string DeviceName;

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public uint DeviceIndex;

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public string DeviceDisplayName;

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public uint DeviceMessageTimingGap;

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public Dictionary<string, DeviceFeature> DeviceFeatures;

		string IButtplugDeviceInfoMessage.DeviceName => DeviceName;

		uint IButtplugDeviceInfoMessage.DeviceIndex => DeviceIndex;

		string IButtplugDeviceInfoMessage.DeviceDisplayName => DeviceDisplayName;

		uint IButtplugDeviceInfoMessage.DeviceMessageTimingGap => DeviceMessageTimingGap;

		Dictionary<string, DeviceFeature> IButtplugDeviceInfoMessage.DeviceFeatures => DeviceFeatures;

		public DeviceFeature GetFeature(uint index)
		{
			string key = index.ToString();
			if (DeviceFeatures != null && DeviceFeatures.ContainsKey(key))
			{
				return DeviceFeatures[key];
			}
			return null;
		}

		public IEnumerable<DeviceFeature> GetAllFeatures()
		{
			if (DeviceFeatures == null)
			{
				return Enumerable.Empty<DeviceFeature>();
			}
			return DeviceFeatures.Values;
		}

		public IEnumerable<DeviceFeature> GetFeaturesWithOutput(OutputType type)
		{
			return from f in GetAllFeatures()
				where f.HasOutput(type)
				select f;
		}

		public IEnumerable<DeviceFeature> GetFeaturesWithInput(InputType type)
		{
			return from f in GetAllFeatures()
				where f.HasInput(type)
				select f;
		}
	}
	public class DeviceListConverter : JsonConverter<DeviceList>
	{
		public override DeviceList ReadJson(JsonReader reader, Type objectType, DeviceList existingValue, bool hasExistingValue, JsonSerializer serializer)
		{
			JObject val = JObject.Load(reader);
			DeviceList deviceList = new DeviceList();
			if (val["Id"] != null)
			{
				deviceList.Id = Extensions.Value<uint>((IEnumerable<JToken>)val["Id"]);
			}
			deviceList.Devices = new Dictionary<uint, DeviceInfo>();
			if (val["Devices"] != null)
			{
				JToken obj = val["Devices"];
				JObject val2 = (JObject)(object)((obj is JObject) ? obj : null);
				if (val2 != null)
				{
					foreach (JProperty item in val2.Properties())
					{
						DeviceInfo value = item.Value.ToObject<DeviceInfo>(serializer);
						deviceList.Devices[uint.Parse(item.Name)] = value;
					}
				}
			}
			return deviceList;
		}

		public override void WriteJson(JsonWriter writer, DeviceList value, JsonSerializer serializer)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			JObject val = new JObject();
			val["Id"] = JToken.op_Implicit(value.Id);
			JObject val2 = new JObject();
			if (value.Devices != null)
			{
				foreach (KeyValuePair<uint, DeviceInfo> device in value.Devices)
				{
					((JToken)val2)[(object)device.Key] = (JToken)(object)JObject.FromObject((object)device.Value, serializer);
				}
			}
			val["Devices"] = (JToken)(object)val2;
			((JToken)val).WriteTo(writer, Array.Empty<JsonConverter>());
		}
	}
	[ButtplugMessageMetadata("DeviceList")]
	[JsonConverter(typeof(DeviceListConverter))]
	public class DeviceList : ButtplugMessage, IButtplugMessageOutgoingOnly
	{
		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public Dictionary<uint, DeviceInfo> Devices;

		public DeviceList(Dictionary<uint, DeviceInfo> devices, uint id)
			: base(id)
		{
			Devices = devices ?? new Dictionary<uint, DeviceInfo>();
		}

		internal DeviceList()
			: base(0u)
		{
			Devices = new Dictionary<uint, DeviceInfo>();
		}

		public IEnumerable<DeviceInfo> GetAllDevices()
		{
			IEnumerable<DeviceInfo> enumerable = Devices?.Values;
			return enumerable ?? Enumerable.Empty<DeviceInfo>();
		}

		public DeviceInfo GetDevice(uint index)
		{
			if (Devices != null && Devices.ContainsKey(index))
			{
				return Devices[index];
			}
			return null;
		}
	}
	[ButtplugMessageMetadata("RequestDeviceList")]
	public class RequestDeviceList : ButtplugMessage
	{
		public RequestDeviceList(uint id = 1u)
			: base(id)
		{
		}
	}
	[ButtplugMessageMetadata("StartScanning")]
	public class StartScanning : ButtplugMessage
	{
		public StartScanning(uint id = 1u)
			: base(id)
		{
		}
	}
	[ButtplugMessageMetadata("StopScanning")]
	public class StopScanning : ButtplugMessage
	{
		public StopScanning(uint id = 1u)
			: base(id)
		{
		}
	}
	[ButtplugMessageMetadata("ScanningFinished")]
	public class ScanningFinished : ButtplugMessage, IButtplugMessageOutgoingOnly
	{
		public ScanningFinished()
			: base(0u)
		{
		}
	}
	[ButtplugMessageMetadata("RequestServerInfo")]
	public class RequestServerInfo : ButtplugMessage
	{
		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public string ClientName;

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public uint ProtocolVersionMajor;

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public uint ProtocolVersionMinor;

		public RequestServerInfo(string clientName, uint id = 1u, uint protocolVersionMajor = 4u, uint protocolVersionMinor = 0u)
			: base(id)
		{
			ClientName = clientName;
			ProtocolVersionMajor = protocolVersionMajor;
			ProtocolVersionMinor = protocolVersionMinor;
		}
	}
	[ButtplugMessageMetadata("ServerInfo")]
	public class ServerInfo : ButtplugMessage, IButtplugMessageOutgoingOnly
	{
		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public uint ProtocolVersionMajor;

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public uint ProtocolVersionMinor;

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public uint MaxPingTime;

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public string ServerName;

		[JsonIgnore]
		public uint MessageVersion => ProtocolVersionMajor;

		public ServerInfo(string serverName, uint protocolVersionMajor, uint protocolVersionMinor, uint maxPingTime, uint id = 1u)
			: base(id)
		{
			ServerName = serverName;
			ProtocolVersionMajor = protocolVersionMajor;
			ProtocolVersionMinor = protocolVersionMinor;
			MaxPingTime = maxPingTime;
		}
	}
	[ButtplugMessageMetadata("Ping")]
	public class Ping : ButtplugMessage
	{
		public Ping(uint id = 1u)
			: base(id)
		{
		}
	}
	[ButtplugMessageMetadata("StopCmd")]
	public class StopCmd : ButtplugMessage
	{
		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public uint? DeviceIndex;

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public uint? FeatureIndex;

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public bool? Inputs;

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public bool? Outputs;

		public StopCmd(uint id = 1u, uint? deviceIndex = null, uint? featureIndex = null, bool? inputs = null, bool? outputs = null)
			: base(id)
		{
			DeviceIndex = deviceIndex;
			FeatureIndex = featureIndex;
			Inputs = inputs;
			Outputs = outputs;
		}
	}
	[ButtplugMessageMetadata("StopDeviceCmd")]
	public class StopDeviceCmd : ButtplugDeviceMessage
	{
		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public bool? Inputs;

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public bool? Outputs;

		public StopDeviceCmd(uint deviceIndex = uint.MaxValue, uint id = 1u, bool? inputs = null, bool? outputs = null)
			: base(id, deviceIndex)
		{
			Inputs = inputs;
			Outputs = outputs;
		}
	}
	[ButtplugMessageMetadata("StopAllDevices")]
	public class StopAllDevices : ButtplugMessage
	{
		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public bool? Inputs;

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public bool? Outputs;

		public StopAllDevices(uint id = 1u, bool? inputs = null, bool? outputs = null)
			: base(id)
		{
			Inputs = inputs;
			Outputs = outputs;
		}
	}
	public class OutputCommandValue
	{
		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public int Value;

		public OutputCommandValue()
		{
		}

		public OutputCommandValue(int value)
		{
			Value = value;
		}
	}
	public class OutputCommandValueWithDuration
	{
		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public int Value;

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public uint Duration;

		public OutputCommandValueWithDuration()
		{
		}

		public OutputCommandValueWithDuration(int value, uint duration)
		{
			Value = value;
			Duration = duration;
		}
	}
	public class OutputCmdConverter : JsonConverter<OutputCmd>
	{
		public override OutputCmd ReadJson(JsonReader reader, Type objectType, OutputCmd existingValue, bool hasExistingValue, JsonSerializer serializer)
		{
			JObject val = JObject.Load(reader);
			OutputCmd outputCmd = new OutputCmd();
			if (val["Id"] != null)
			{
				outputCmd.Id = Extensions.Value<uint>((IEnumerable<JToken>)val["Id"]);
			}
			if (val["DeviceIndex"] != null)
			{
				outputCmd.DeviceIndex = Extensions.Value<uint>((IEnumerable<JToken>)val["DeviceIndex"]);
			}
			if (val["FeatureIndex"] != null)
			{
				outputCmd.FeatureIndex = Extensions.Value<uint>((IEnumerable<JToken>)val["FeatureIndex"]);
			}
			outputCmd.Command = new Dictionary<string, object>();
			if (val["Command"] != null)
			{
				JToken obj = val["Command"];
				JObject val2 = (JObject)(object)((obj is JObject) ? obj : null);
				if (val2 != null)
				{
					foreach (JProperty item in val2.Properties())
					{
						if (item.Name == "HwPositionWithDuration")
						{
							outputCmd.Command[item.Name] = item.Value.ToObject<OutputCommandValueWithDuration>(serializer);
						}
						else
						{
							outputCmd.Command[item.Name] = item.Value.ToObject<OutputCommandValue>(serializer);
						}
					}
				}
			}
			return outputCmd;
		}

		public override void WriteJson(JsonWriter writer, OutputCmd value, JsonSerializer serializer)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			JObject val = new JObject();
			val["Id"] = JToken.op_Implicit(value.Id);
			val["DeviceIndex"] = JToken.op_Implicit(value.DeviceIndex);
			val["FeatureIndex"] = JToken.op_Implicit(value.FeatureIndex);
			JObject val2 = new JObject();
			if (value.Command != null)
			{
				foreach (KeyValuePair<string, object> item in value.Command)
				{
					val2[item.Key] = (JToken)(object)JObject.FromObject(item.Value, serializer);
				}
			}
			val["Command"] = (JToken)(object)val2;
			((JToken)val).WriteTo(writer, Array.Empty<JsonConverter>());
		}
	}
	[ButtplugMessageMetadata("OutputCmd")]
	[JsonConverter(typeof(OutputCmdConverter))]
	public class OutputCmd : ButtplugDeviceMessage
	{
		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public uint FeatureIndex;

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public Dictionary<string, object> Command;

		public OutputCmd()
		{
			Command = new Dictionary<string, object>();
		}

		public OutputCmd(uint deviceIndex, uint featureIndex, uint id = 1u)
			: base(id, deviceIndex)
		{
			FeatureIndex = featureIndex;
			Command = new Dictionary<string, object>();
		}

		public static OutputCmd Create(uint deviceIndex, uint featureIndex, OutputType outputType, int value, uint id = 1u)
		{
			return new OutputCmd(deviceIndex, featureIndex, id)
			{
				Command = { [outputType.ToString()] = new OutputCommandValue(value) }
			};
		}

		public static OutputCmd CreatePositionWithDuration(uint deviceIndex, uint featureIndex, int position, uint duration, uint id = 1u)
		{
			return new OutputCmd(deviceIndex, featureIndex, id)
			{
				Command = { [OutputType.HwPositionWithDuration.ToString()] = new OutputCommandValueWithDuration(position, duration) }
			};
		}

		public OutputCmd WithValue(OutputType outputType, int value)
		{
			Command[outputType.ToString()] = new OutputCommandValue(value);
			return this;
		}

		public OutputCmd WithPositionAndDuration(int position, uint duration)
		{
			Command[OutputType.HwPositionWithDuration.ToString()] = new OutputCommandValueWithDuration(position, duration);
			return this;
		}
	}
	[ButtplugMessageMetadata("InputCmd")]
	public class InputCmd : ButtplugDeviceMessage
	{
		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public uint FeatureIndex;

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public InputType Type;

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public InputCommandType Command;

		public InputCmd()
		{
		}

		public InputCmd(uint deviceIndex, uint featureIndex, InputType type, InputCommandType command, uint id = 1u)
			: base(id, deviceIndex)
		{
			FeatureIndex = featureIndex;
			Type = type;
			Command = command;
		}

		public static InputCmd Read(uint deviceIndex, uint featureIndex, InputType type, uint id = 1u)
		{
			return new InputCmd(deviceIndex, featureIndex, type, InputCommandType.Read, id);
		}

		public static InputCmd Subscribe(uint deviceIndex, uint featureIndex, InputType type, uint id = 1u)
		{
			return new InputCmd(deviceIndex, featureIndex, type, InputCommandType.Subscribe, id);
		}

		public static InputCmd Unsubscribe(uint deviceIndex, uint featureIndex, InputType type, uint id = 1u)
		{
			return new InputCmd(deviceIndex, featureIndex, type, InputCommandType.Unsubscribe, id);
		}
	}
	public class InputReadingValue
	{
		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public double Value;

		public InputReadingValue()
		{
		}

		public InputReadingValue(double value)
		{
			Value = value;
		}
	}
	public class InputReadingConverter : JsonConverter<InputReading>
	{
		public override InputReading ReadJson(JsonReader reader, Type objectType, InputReading existingValue, bool hasExistingValue, JsonSerializer serializer)
		{
			JObject val = JObject.Load(reader);
			InputReading inputReading = new InputReading();
			if (val["Id"] != null)
			{
				inputReading.Id = Extensions.Value<uint>((IEnumerable<JToken>)val["Id"]);
			}
			if (val["DeviceIndex"] != null)
			{
				inputReading.DeviceIndex = Extensions.Value<uint>((IEnumerable<JToken>)val["DeviceIndex"]);
			}
			if (val["FeatureIndex"] != null)
			{
				inputReading.FeatureIndex = Extensions.Value<uint>((IEnumerable<JToken>)val["FeatureIndex"]);
			}
			inputReading.Reading = new Dictionary<string, InputReadingValue>();
			if (val["Reading"] != null)
			{
				JToken obj = val["Reading"];
				JObject val2 = (JObject)(object)((obj is JObject) ? obj : null);
				if (val2 != null)
				{
					foreach (JProperty item in val2.Properties())
					{
						inputReading.Reading[item.Name] = item.Value.ToObject<InputReadingValue>(serializer);
					}
				}
			}
			return inputReading;
		}

		public override void WriteJson(JsonWriter writer, InputReading value, JsonSerializer serializer)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			JObject val = new JObject();
			val["Id"] = JToken.op_Implicit(value.Id);
			val["DeviceIndex"] = JToken.op_Implicit(value.DeviceIndex);
			val["FeatureIndex"] = JToken.op_Implicit(value.FeatureIndex);
			JObject val2 = new JObject();
			if (value.Reading != null)
			{
				foreach (KeyValuePair<string, InputReadingValue> item in value.Reading)
				{
					val2[item.Key] = (JToken)(object)JObject.FromObject((object)item.Value, serializer);
				}
			}
			val["Reading"] = (JToken)(object)val2;
			((JToken)val).WriteTo(writer, Array.Empty<JsonConverter>());
		}
	}
	[ButtplugMessageMetadata("InputReading")]
	[JsonConverter(typeof(InputReadingConverter))]
	public class InputReading : ButtplugDeviceMessage, IButtplugMessageOutgoingOnly
	{
		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public uint FeatureIndex;

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public Dictionary<string, InputReadingValue> Reading;

		public double? BatteryLevel => GetValue(InputType.Battery);

		public double? RSSILevel => GetValue(InputType.RSSI);

		public InputReading()
			: base(0u)
		{
			Reading = new Dictionary<string, InputReadingValue>();
		}

		public InputReading(uint deviceIndex, uint featureIndex, uint id = 0u)
			: base(id, deviceIndex)
		{
			FeatureIndex = featureIndex;
			Reading = new Dictionary<string, InputReadingValue>();
		}

		public double? GetValue(InputType type)
		{
			string key = type.ToString();
			if (Reading != null && Reading.ContainsKey(key))
			{
				return Reading[key].Value;
			}
			return null;
		}
	}
}
namespace Buttplug.Client
{
	public class ButtplugClient : IDisposable, IAsyncDisposable
	{
		protected Timer _pingTimer;

		internal ButtplugClientMessageHandler _handler;

		private readonly ConcurrentDictionary<uint, ButtplugClientDevice> _devices = new ConcurrentDictionary<uint, ButtplugClientDevice>();

		private IButtplugClientConnector _connector;

		private int _serverDisconnectRaised;

		public string Name { get; }

		public ButtplugClientDevice[] Devices => _devices.Values.ToArray();

		public bool Connected => _connector?.Connected ?? false;

		public event EventHandler<DeviceAddedEventArgs> DeviceAdded;

		public event EventHandler<DeviceRemovedEventArgs> DeviceRemoved;

		public event EventHandler<ButtplugExceptionEventArgs> ErrorReceived;

		public event EventHandler ScanningFinished;

		public event EventHandler PingTimeout;

		public event EventHandler ServerDisconnect;

		public event EventHandler<InputReadingEventArgs> InputReadingReceived;

		public ButtplugClient(string clientName)
		{
			Name = clientName;
		}

		public async Task ConnectAsync(IButtplugClientConnector connector, CancellationToken token = default(CancellationToken))
		{
			if (Connected)
			{
				throw new ButtplugHandshakeException("Client already connected to a server.");
			}
			ButtplugUtils.ArgumentNotNull(connector, "connector");
			_connector = connector;
			_serverDisconnectRaised = 0;
			_connector.Disconnected += ConnectorDisconnectedHandler;
			_connector.InvalidMessageReceived += ConnectorErrorHandler;
			_connector.MessageReceived += MessageReceivedHandler;
			_devices.Clear();
			_handler = new ButtplugClientMessageHandler(connector);
			await _connector.ConnectAsync(token).ConfigureAwait(continueOnCapturedContext: false);
			ButtplugMessage res = await _handler.SendMessageAsync(new RequestServerInfo(Name), token).ConfigureAwait(continueOnCapturedContext: false);
			if (!(res is ServerInfo si))
			{
				if (res is Error e)
				{
					await DisconnectAsync().ConfigureAwait(continueOnCapturedContext: false);
					throw ButtplugException.FromError(e);
				}
				await DisconnectAsync().ConfigureAwait(continueOnCapturedContext: false);
				throw new ButtplugHandshakeException("Unrecognized message " + res.Name + " during handshake", res.Id);
			}
			if (si.MaxPingTime != 0)
			{
				_pingTimer?.Dispose();
				_pingTimer = new Timer(OnPingTimer, null, 0, Convert.ToInt32(Math.Round((double)si.MaxPingTime / 2.0, 0)));
			}
			if (si.ProtocolVersionMajor < 4)
			{
				await DisconnectAsync().ConfigureAwait(continueOnCapturedContext: false);
				throw new ButtplugHandshakeException($"Buttplug Server's protocol version ({si.ProtocolVersionMajor}.{si.ProtocolVersionMinor}) is less than the client's ({4u}.{0u}). A newer server is required.", res.Id);
			}
			try
			{
				await RequestDeviceListAsync(token).ConfigureAwait(continueOnCapturedContext: false);
			}
			catch
			{
				await DisconnectAsync().ConfigureAwait(continueOnCapturedContext: false);
				throw;
			}
		}

		public async Task DisconnectAsync()
		{
			if (Connected)
			{
				_connector.MessageReceived -= MessageReceivedHandler;
				_connector.InvalidMessageReceived -= ConnectorErrorHandler;
				await _connector.DisconnectAsync().ConfigureAwait(continueOnCapturedContext: false);
				_connector.Disconnected -= ConnectorDisconnectedHandler;
				SignalServerDisconnect(this, EventArgs.Empty);
			}
		}

		private async Task RequestDeviceListAsync(CancellationToken token = default(CancellationToken))
		{
			ButtplugMessage buttplugMessage = await _handler.SendMessageAsync(new RequestDeviceList(), token).ConfigureAwait(continueOnCapturedContext: false);
			if (buttplugMessage is DeviceList list)
			{
				ProcessDeviceList(list);
				return;
			}
			if (buttplugMessage is Error msg)
			{
				throw ButtplugException.FromError(msg);
			}
			throw new ButtplugMessageException("Received unknown response to DeviceList query");
		}

		private void ProcessDeviceList(DeviceList list)
		{
			HashSet<uint> incomingDeviceIndices = new HashSet<uint>();
			foreach (DeviceInfo allDevice in list.GetAllDevices())
			{
				incomingDeviceIndices.Add(allDevice.DeviceIndex);
				if (!_devices.ContainsKey(allDevice.DeviceIndex))
				{
					ButtplugClientDevice buttplugClientDevice = new ButtplugClientDevice(_handler, allDevice);
					_devices[allDevice.DeviceIndex] = buttplugClientDevice;
					this.DeviceAdded?.Invoke(this, new DeviceAddedEventArgs(buttplugClientDevice));
				}
			}
			foreach (uint item in _devices.Keys.Where((uint idx) => !incomingDeviceIndices.Contains(idx)).ToList())
			{
				if (_devices.TryRemove(item, out var value))
				{
					this.DeviceRemoved?.Invoke(this, new DeviceRemovedEventArgs(value));
				}
			}
		}

		public async Task StartScanningAsync(CancellationToken token = default(CancellationToken))
		{
			EnsureConnected();
			await _handler.SendMessageExpectOk(new StartScanning(), token).ConfigureAwait(continueOnCapturedContext: false);
		}

		public async Task StopScanningAsync(CancellationToken token = default(CancellationToken))
		{
			EnsureConnected();
			await _handler.SendMessageExpectOk(new StopScanning(), token).ConfigureAwait(continueOnCapturedContext: false);
		}

		public async Task StopAllDevicesAsync(CancellationToken token = default(CancellationToken))
		{
			EnsureConnected();
			await _handler.SendMessageExpectOk(new StopCmd(), token).ConfigureAwait(continueOnCapturedContext: false);
		}

		private void EnsureConnected()
		{
			if (!Connected)
			{
				throw new ButtplugClientConnectorException("Client not connected.");
			}
		}

		private void ConnectorErrorHandler(object sender, ButtplugExceptionEventArgs exception)
		{
			this.ErrorReceived?.Invoke(this, exception);
		}

		private void ConnectorDisconnectedHandler(object sender, EventArgs eventArgs)
		{
			SignalServerDisconnect(sender, eventArgs);
		}

		private void SignalServerDisconnect(object sender, EventArgs eventArgs)
		{
			if (Interlocked.Exchange(ref _serverDisconnectRaised, 1) == 0)
			{
				this.ServerDisconnect?.Invoke(sender, eventArgs);
			}
		}

		private async void MessageReceivedHandler(object sender, MessageReceivedEventArgs args)
		{
			ButtplugMessage message = args.Message;
			if (!(message is DeviceList list))
			{
				if (!(message is ScanningFinished))
				{
					if (!(message is InputReading reading))
					{
						if (message is Error error)
						{
							this.ErrorReceived?.Invoke(this, new ButtplugExceptionEventArgs(ButtplugException.FromError(error)));
							if (error.ErrorCode == Error.ErrorClass.ERROR_PING)
							{
								this.PingTimeout?.Invoke(this, EventArgs.Empty);
								await DisconnectAsync().ConfigureAwait(continueOnCapturedContext: false);
							}
						}
						else
						{
							this.ErrorReceived?.Invoke(this, new ButtplugExceptionEventArgs(new ButtplugMessageException($"Got unhandled message: {message}", message.Id)));
						}
					}
					else
					{
						this.InputReadingReceived?.Invoke(this, new InputReadingEventArgs(reading));
					}
				}
				else
				{
					try
					{
						await RequestDeviceListAsync().ConfigureAwait(continueOnCapturedContext: false);
					}
					catch (Exception ex)
					{
						this.ErrorReceived?.Invoke(this, new ButtplugExceptionEventArgs(new ButtplugMessageException("Failed to get device list after scanning: " + ex.Message)));
					}
					this.ScanningFinished?.Invoke(this, EventArgs.Empty);
				}
			}
			else
			{
				ProcessDeviceList(list);
			}
		}

		private async void OnPingTimer(object state)
		{
			try
			{
				await _handler.SendMessageExpectOk(new Ping()).ConfigureAwait(continueOnCapturedContext: false);
			}
			catch (Exception inner)
			{
				this.ErrorReceived?.Invoke(this, new ButtplugExceptionEventArgs(new ButtplugPingException("Exception thrown during ping update", 0u, inner)));
				await DisconnectAsync().ConfigureAwait(continueOnCapturedContext: false);
			}
		}

		protected virtual void Dispose(bool disposing)
		{
			_pingTimer?.Dispose();
			DisconnectAsync().GetAwaiter().GetResult();
		}

		public void Dispose()
		{
			Dispose(disposing: true);
			GC.SuppressFinalize(this);
		}

		public async ValueTask DisposeAsync()
		{
			_pingTimer?.Dispose();
			await DisconnectAsync().ConfigureAwait(continueOnCapturedContext: false);
			GC.SuppressFinalize(this);
		}
	}
	public class DeviceAddedEventArgs : EventArgs
	{
		public ButtplugClientDevice Device { get; }

		public DeviceAddedEventArgs(ButtplugClientDevice device)
		{
			Device = device;
		}
	}
	public class DeviceRemovedEventArgs : EventArgs
	{
		public ButtplugClientDevice Device { get; }

		public DeviceRemovedEventArgs(ButtplugClientDevice device)
		{
			Device = device;
		}
	}
	public class InputReadingEventArgs : EventArgs
	{
		public InputReading Reading { get; }

		public uint DeviceIndex => Reading.DeviceIndex;

		public uint FeatureIndex => Reading.FeatureIndex;

		public InputReadingEventArgs(InputReading reading)
		{
			Reading = reading;
		}
	}
	public class ButtplugClientConnectorException : ButtplugException
	{
		public ButtplugClientConnectorException(string message, Exception inner = null)
			: base(message, Error.ErrorClass.ERROR_UNKNOWN, 0u, inner)
		{
		}
	}
	public class ButtplugClientDevice
	{
		private readonly Dictionary<uint, ButtplugClientDeviceFeature> _features;

		private readonly ButtplugClientMessageHandler _handler;

		public uint Index { get; }

		public string Name { get; }

		public string DisplayName { get; }

		public uint MessageTimingGap { get; }

		public IReadOnlyDictionary<uint, ButtplugClientDeviceFeature> Features => _features;

		internal ButtplugClientDevice(ButtplugClientMessageHandler handler, IButtplugDeviceInfoMessage devInfo)
			: this(handler, devInfo.DeviceIndex, devInfo.DeviceName, devInfo.DeviceFeatures, devInfo.DeviceDisplayName, devInfo.DeviceMessageTimingGap)
		{
			ButtplugUtils.ArgumentNotNull(devInfo, "devInfo");
		}

		internal ButtplugClientDevice(ButtplugClientMessageHandler handler, uint index, string name, Dictionary<string, DeviceFeature> deviceFeatures, string displayName, uint messageTimingGap)
		{
			ButtplugUtils.ArgumentNotNull(handler, "handler");
			_handler = handler;
			Index = index;
			Name = name;
			DisplayName = displayName;
			MessageTimingGap = messageTimingGap;
			_features = new Dictionary<uint, ButtplugClientDeviceFeature>();
			if (deviceFeatures == null)
			{
				return;
			}
			foreach (KeyValuePair<string, DeviceFeature> deviceFeature in deviceFeatures)
			{
				if (uint.TryParse(deviceFeature.Key, out var result))
				{
					_features[result] = new ButtplugClientDeviceFeature(this, deviceFeature.Value, _handler);
				}
			}
		}

		public IEnumerable<ButtplugClientDeviceFeature> GetFeaturesWithOutput(OutputType outputType)
		{
			return _features.Values.Where((ButtplugClientDeviceFeature f) => f.HasOutput(outputType));
		}

		public IEnumerable<ButtplugClientDeviceFeature> GetFeaturesWithInput(InputType inputType)
		{
			return _features.Values.Where((ButtplugClientDeviceFeature f) => f.HasInput(inputType));
		}

		public ButtplugClientDeviceFeature GetFeature(uint featureIndex)
		{
			if (!_features.TryGetValue(featureIndex, out var value))
			{
				return null;
			}
			return value;
		}

		public bool HasOutput(OutputType outputType)
		{
			return _features.Values.Any((ButtplugClientDeviceFeature f) => f.HasOutput(outputType));
		}

		public bool HasInput(InputType inputType)
		{
			return _features.Values.Any((ButtplugClientDeviceFeature f) => f.HasInput(inputType));
		}

		public async Task RunOutputAsync(DeviceOutputCommand command, CancellationToken token = default(CancellationToken))
		{
			List<ButtplugClientDeviceFeature> source = GetFeaturesWithOutput(command.OutputType).ToList();
			if (!source.Any())
			{
				throw new ButtplugDeviceException($"Device {Name} has no features with output type {command.OutputType}");
			}
			await Task.WhenAll(source.Select((ButtplugClientDeviceFeature f) => f.RunOutputAsync(command, token))).ConfigureAwait(continueOnCapturedContext: false);
		}

		public async Task RunOutputAsync(uint featureIndex, DeviceOutputCommand command, CancellationToken token = default(CancellationToken))
		{
			await (GetFeature(featureIndex) ?? throw new ButtplugDeviceException($"Device {Name} does not have feature index {featureIndex}")).RunOutputAsync(command, token).ConfigureAwait(continueOnCapturedContext: false);
		}

		public async Task<InputReading> RunInputAsync(DeviceInputCommand command, CancellationToken token = default(CancellationToken))
		{
			List<ButtplugClientDeviceFeature> source = GetFeaturesWithInput(command.InputType).ToList();
			if (!source.Any())
			{
				throw new ButtplugDeviceException($"Device {Name} has no features with input type {command.InputType}");
			}
			return await source.First().RunInputAsync(command, token).ConfigureAwait(continueOnCapturedContext: false);
		}

		public async Task<InputReading> RunInputAsync(uint featureIndex, DeviceInputCommand command, CancellationToken token = default(CancellationToken))
		{
			return await (GetFeature(featureIndex) ?? throw new ButtplugDeviceException($"Device {Name} does not have feature index {featureIndex}")).RunInputAsync(command, token).ConfigureAwait(continueOnCapturedContext: false);
		}

		public async Task<double> BatteryAsync(TimeSpan? timeout = null, CancellationToken token = default(CancellationToken))
		{
			CancellationTokenSource linkedCts = null;
			try
			{
				CancellationToken token2 = token;
				if (timeout.HasValue)
				{
					linkedCts = CancellationTokenSource.CreateLinkedTokenSource(new CancellationToken[1] { token });
					linkedCts.CancelAfter(timeout.Value);
					token2 = linkedCts.Token;
				}
				double? num = (await RunInputAsync(DeviceInput.Battery.Read(), token2).ConfigureAwait(continueOnCapturedContext: false))?.GetValue(InputType.Battery);
				if (!num.HasValue)
				{
					throw new ButtplugMessageException("Battery reading from device '" + Name + "' did not contain a battery value.");
				}
				return num.Value / 100.0;
			}
			finally
			{
				linkedCts?.Dispose();
			}
		}

		public async Task StopAsync(CancellationToken token = default(CancellationToken))
		{
			await _handler.SendMessageExpectOk(new StopCmd(1u, Index), token).ConfigureAwait(continueOnCapturedContext: false);
		}
	}
	public class PercentOrSteps
	{
		private readonly double? _percent;

		private readonly int? _steps;

		public double? Percent => _percent;

		public int? Steps => _steps;

		private PercentOrSteps(double? percent, int? steps)
		{
			_percent = percent;
			_steps = steps;
		}

		public static PercentOrSteps FromSteps(int steps)
		{
			return new PercentOrSteps(null, steps);
		}

		public static PercentOrSteps FromPercent(double percent, double minPercent = 0.0, double maxPercent = 1.0)
		{
			if (percent < minPercent || percent > maxPercent)
			{
				throw new ButtplugDeviceException($"Percent value {percent} is not in the range {minPercent} <= x <= {maxPercent}");
			}
			return new PercentOrSteps(percent, null);
		}

		public int ToStepValue(int maxSteps)
		{
			if (_steps.HasValue)
			{
				return _steps.Value;
			}
			return (int)Math.Ceiling(_percent.Value * (double)maxSteps);
		}
	}
	public class DeviceOutputCommand
	{
		public OutputType OutputType { get; }

		public PercentOrSteps Value { get; }

		public uint? Duration { get; }

		public DeviceOutputCommand(OutputType outputType, PercentOrSteps value, uint? duration = null)
		{
			OutputType = outputType;
			Value = value;
			Duration = duration;
		}
	}
	public class DeviceOutputValueBuilder
	{
		private readonly OutputType _outputType;

		internal DeviceOutputValueBuilder(OutputType outputType)
		{
			_outputType = outputType;
		}

		public DeviceOutputCommand Steps(int steps)
		{
			return new DeviceOutputCommand(_outputType, PercentOrSteps.FromSteps(steps));
		}

		public DeviceOutputCommand Percent(double percent)
		{
			double minPercent = ((_outputType == OutputType.Rotate) ? (-1.0) : 0.0);
			return new DeviceOutputCommand(_outputType, PercentOrSteps.FromPercent(percent, minPercent));
		}
	}
	public class DeviceOutputPositionWithDurationBuilder
	{
		internal DeviceOutputPositionWithDurationBuilder()
		{
		}

		public DeviceOutputCommand Steps(int steps, uint durationMs)
		{
			return new DeviceOutputCommand(OutputType.HwPositionWithDuration, PercentOrSteps.FromSteps(steps), durationMs);
		}

		public DeviceOutputCommand Percent(double percent, uint durationMs)
		{
			return new DeviceOutputCommand(OutputType.HwPositionWithDuration, PercentOrSteps.FromPercent(percent), durationMs);
		}
	}
	public static class DeviceOutput
	{
		public static DeviceOutputValueBuilder Vibrate => new DeviceOutputValueBuilder(OutputType.Vibrate);

		public static DeviceOutputValueBuilder Rotate => new DeviceOutputValueBuilder(OutputType.Rotate);

		public static DeviceOutputValueBuilder Oscillate => new DeviceOutputValueBuilder(OutputType.Oscillate);

		public static DeviceOutputValueBuilder Constrict => new DeviceOutputValueBuilder(OutputType.Constrict);

		public static DeviceOutputValueBuilder Temperature => new DeviceOutputValueBuilder(OutputType.Temperature);

		public static DeviceOutputValueBuilder Led => new DeviceOutputValueBuilder(OutputType.Led);

		public static DeviceOutputValueBuilder Spray => new DeviceOutputValueBuilder(OutputType.Spray);

		public static DeviceOutputValueBuilder Position => new DeviceOutputValueBuilder(OutputType.Position);

		public static DeviceOutputPositionWithDurationBuilder PositionWithDuration => new DeviceOutputPositionWithDurationBuilder();
	}
	public class DeviceInputCommand
	{
		public InputType InputType { get; }

		public InputCommandType CommandType { get; }

		public DeviceInputCommand(InputType inputType, InputCommandType commandType)
		{
			InputType = inputType;
			CommandType = commandType;
		}
	}
	public class DeviceInputBuilder
	{
		private readonly InputType _inputType;

		internal DeviceInputBuilder(InputType inputType)
		{
			_inputType = inputType;
		}

		public DeviceInputCommand Read()
		{
			return new DeviceInputCommand(_inputType, InputCommandType.Read);
		}

		public DeviceInputCommand Subscribe()
		{
			return new DeviceInputCommand(_inputType, InputCommandType.Subscribe);
		}

		public DeviceInputCommand Unsubscribe()
		{
			return new DeviceInputCommand(_inputType, InputCommandType.Unsubscribe);
		}
	}
	public static class DeviceInput
	{
		public static DeviceInputBuilder Battery => new DeviceInputBuilder(InputType.Battery);

		public static DeviceInputBuilder RSSI => new DeviceInputBuilder(InputType.RSSI);

		public static DeviceInputBuilder Button => new DeviceInputBuilder(InputType.Button);

		public static DeviceInputBuilder Pressure => new DeviceInputBuilder(InputType.Pressure);

		public static DeviceInputBuilder Depth => new DeviceInputBuilder(InputType.Depth);

		public static DeviceInputBuilder Position => new DeviceInputBuilder(InputType.Position);
	}
	public class ButtplugClientDeviceFeature
	{
		private readonly ButtplugClientMessageHandler _handler;

		public ButtplugClientDevice Device { get; }

		public uint FeatureIndex { get; }

		public string FeatureDescription { get; }

		public DeviceFeature FeatureDefinition { get; }

		internal ButtplugClientDeviceFeature(ButtplugClientDevice device, DeviceFeature feature, ButtplugClientMessageHandler handler)
		{
			Device = device;
			FeatureIndex = feature.FeatureIndex;
			FeatureDescription = feature.FeatureDescription;
			FeatureDefinition = feature;
			_handler = handler;
		}

		public bool HasOutput(OutputType outputType)
		{
			return FeatureDefinition.HasOutput(outputType);
		}

		public bool HasInput(InputType inputType)
		{
			return FeatureDefinition.HasInput(inputType);
		}

		public bool TryGetOutputRange(OutputType outputType, out int min, out int max)
		{
			DeviceFeatureOutput output = FeatureDefinition.GetOutput(outputType);
			if (output?.Value != null && output.Value.Length >= 2)
			{
				min = output.Value[0];
				max = output.Value[1];
				return true;
			}
			min = 0;
			max = 0;
			return false;
		}

		public async Task RunOutputAsync(DeviceOutputCommand command, CancellationToken token = default(CancellationToken))
		{
			if (!HasOutput(command.OutputType))
			{
				IEnumerable<string> enumerable = FeatureDefinition.Output?.Keys;
				IEnumerable<string> enumerable2 = enumerable ?? Enumerable.Empty<string>();
				string text = (enumerable2.Any() ? string.Join(", ", enumerable2) : "none");
				throw new ButtplugDeviceException($"Feature {FeatureIndex} ({FeatureDescription}) on device '{Device.Name}' does not support output type '{command.OutputType}'. " + "Supported outputs: " + text + ".");
			}
			DeviceFeatureOutput output = FeatureDefinition.GetOutput(command.OutputType);
			int maxSteps = 100;
			if (output?.Value != null && output.Value.Length >= 2)
			{
				maxSteps = output.Value[1];
			}
			int num = command.Value.ToStepValue(maxSteps);
			OutputCmd msg;
			if (command.OutputType == OutputType.HwPositionWithDuration)
			{
				if (!command.Duration.HasValue)
				{
					throw new ButtplugDeviceException($"HwPositionWithDuration command for feature {FeatureIndex} ({FeatureDescription}) on device '{Device.Name}' requires a duration value. " + "Use DeviceOutput.PositionWithDuration.Percent(position, durationMs) or DeviceOutput.PositionWithDuration.Steps(steps, durationMs).");
				}
				msg = OutputCmd.CreatePositionWithDuration(Device.Index, FeatureIndex, num, command.Duration.Value);
			}
			else
			{
				msg = OutputCmd.Create(Device.Index, FeatureIndex, command.OutputType, num);
			}
			await _handler.SendMessageExpectOk(msg, token).ConfigureAwait(continueOnCapturedContext: false);
		}

		public async Task<InputReading> RunInputAsync(DeviceInputCommand command, CancellationToken token = default(CancellationToken))
		{
			if (!HasInput(command.InputType))
			{
				IEnumerable<string> enumerable = FeatureDefinition.Input?.Keys;
				IEnumerable<string> enumerable2 = enumerable ?? Enumerable.Empty<string>();
				string text = (enumerable2.Any() ? string.Join(", ", enumerable2) : "none");
				throw new ButtplugDeviceException($"Feature {FeatureIndex} ({FeatureDescription}) on device '{Device.Name}' does not support input type '{command.InputType}'. " + "Supported inputs: " + text + ".");
			}
			InputCmd msg = new InputCmd(Device.Index, FeatureIndex, command.InputType, command.CommandType);
			if (command.CommandType == InputCommandType.Read)
			{
				ButtplugMessage buttplugMessage = await _handler.SendMessageAsync(msg, token).ConfigureAwait(continueOnCapturedContext: false);
				if (!(buttplugMessage is InputReading result))
				{
					if (buttplugMessage is Error msg2)
					{
						throw ButtplugException.FromError(msg2);
					}
					throw new ButtplugMessageException("Message type " + buttplugMessage.Name + " not handled by RunInputAsync", buttplugMessage.Id);
				}
				return result;
			}
			await _handler.SendMessageExpectOk(msg, token).ConfigureAwait(continueOnCapturedContext: false);
			return null;
		}
	}
	public static class ButtplugClientExtensions
	{
		public static Task ConnectAsync(this ButtplugClient client, string uri, CancellationToken token = default(CancellationToken))
		{
			return client.ConnectAsync(new Uri(uri), token);
		}

		public static Task ConnectAsync(this ButtplugClient client, Uri uri, CancellationToken token = default(CancellationToken))
		{
			return client.ConnectAsync(new ButtplugWebsocketConnector(uri), token);
		}

		public static ButtplugClientDevice GetDevice(this ButtplugClient client, uint index)
		{
			return client.Devices.FirstOrDefault((ButtplugClientDevice d) => d.Index == index);
		}

		public static IEnumerable<ButtplugClientDevice> GetDevicesWithOutput(this ButtplugClient client, OutputType outputType)
		{
			return client.Devices.Where((ButtplugClientDevice d) => d.HasOutput(outputType));
		}

		public static IEnumerable<ButtplugClientDevice> GetDevicesWithInput(this ButtplugClient client, InputType inputType)
		{
			return client.Devices.Where((ButtplugClientDevice d) => d.HasInput(inputType));
		}
	}
	internal class ButtplugClientMessageHandler
	{
		private IButtplugClientConnector _connector;

		internal ButtplugClientMessageHandler(IButtplugClientConnector connector)
		{
			_connector = connector;
		}

		public async Task<ButtplugMessage> SendMessageAsync(ButtplugMessage msg, CancellationToken token = default(CancellationToken))
		{
			if (!_connector.Connected)
			{
				throw new ButtplugClientConnectorException("Client not connected.");
			}
			return await _connector.SendAsync(msg, token).ConfigureAwait(continueOnCapturedContext: false);
		}

		public async Task SendMessageExpectOk(ButtplugMessage msg, CancellationToken token = default(CancellationToken))
		{
			ButtplugMessage buttplugMessage = await SendMessageAsync(msg, token).ConfigureAwait(continueOnCapturedContext: false);
			if (!(buttplugMessage is Ok))
			{
				if (buttplugMessage is Error msg2)
				{
					throw ButtplugException.FromError(msg2);
				}
				throw new ButtplugMessageException("Message type " + msg.Name + " not handled by SendMessageExpectOk", msg.Id);
			}
		}
	}
	public class ButtplugConnectorJSONParser
	{
		private readonly ButtplugJsonMessageParser _parser = new ButtplugJsonMessageParser();

		public string Serialize(ButtplugMessage msg)
		{
			return _parser.Serialize(msg);
		}

		public string Serialize(ButtplugMessage[] msgs)
		{
			return _parser.Serialize(msgs);
		}

		public IEnumerable<ButtplugMessage> Deserialize(string msg)
		{
			return _parser.Deserialize(msg);
		}
	}
	public class ButtplugConnectorMessageSorter : IDisposable
	{
		private class WaitingMessage : IDisposable
		{
			public TaskCompletionSource<ButtplugMessage> Promise { get; }

			public CancellationTokenRegistration Cancellation { get; set; }

			public WaitingMessage(TaskCompletionSource<ButtplugMessage> promise)
			{
				Promise = promise;
			}

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

		private int _counter;

		private readonly ConcurrentDictionary<uint, WaitingMessage> _waitingMsgs = new ConcurrentDictionary<uint, WaitingMessage>();

		public uint NextMsgId => Convert.ToUInt32(Interlocked.Increment(ref _counter));

		public Task<ButtplugMessage> PrepareMessage(ButtplugMessage msg, CancellationToken token = default(CancellationToken))
		{
			msg.Id = NextMsgId;
			WaitingMessage waitingMessage = new WaitingMessage(new TaskCompletionSource<ButtplugMessage>());
			_waitingMsgs.TryAdd(msg.Id, waitingMessage);
			if (token.CanBeCanceled)
			{
				waitingMessage.Cancellation = token.Register(delegate
				{
					if (_waitingMsgs.TryRemove(msg.Id, out var value))
					{
						value.Promise.TrySetCanceled();
					}
				});
			}
			return waitingMessage.Promise.Task;
		}

		public void CheckMessage(ButtplugMessage msg)
		{
			if (msg.Id == 0)
			{
				throw new ButtplugMessageException("Cannot sort message with System ID", msg.Id);
			}
			if (!_waitingMsgs.TryRemove(msg.Id, out var value))
			{
				throw new ButtplugMessageException("Message with non-matching ID received.", msg.Id);
			}
			value.Dispose();
			if (msg is Error msg2)
			{
				value.Promise.SetException(ButtplugException.FromError(msg2));
			}
			else
			{
				value.Promise.SetResult(msg);
			}
		}

		protected virtual void Dispose(bool disposing)
		{
			foreach (KeyValuePair<uint, WaitingMessage> waitingMsg in _waitingMsgs)
			{
				if (_waitingMsgs.TryRemove(waitingMsg.Key, out var value))
				{
					value.Dispose();
					value.Promise.TrySetException(new Exception("Sorter has been destroyed with live tasks still in queue."));
				}
			}
		}

		public void Dispose()
		{
			Dispose(disposing: true);
			GC.SuppressFinalize(this);
		}
	}
	public class ReturnMessage
	{
		public readonly string Message;

		public readonly Task<ButtplugMessage> Promise;

		public ReturnMessage(string message, Task<ButtplugMessage> promise)
		{
			Message = message;
			Promise = promise;
		}
	}
	public class ButtplugRemoteJSONConnector : IDisposable
	{
		private readonly ButtplugConnectorJSONParser _jsonSerializer = new ButtplugConnectorJSONParser();

		private readonly ButtplugConnectorMessageSorter _msgSorter = new ButtplugConnectorMessageSorter();

		public event EventHandler<MessageReceivedEventArgs> MessageReceived;

		public event EventHandler<ButtplugExceptionEventArgs> InvalidMessageReceived;

		public ReturnMessage PrepareMessage(ButtplugMessage msg, CancellationToken token = default(CancellationToken))
		{
			Task<ButtplugMessage> promise = _msgSorter.PrepareMessage(msg, token);
			return new ReturnMessage(_jsonSerializer.Serialize(msg), promise);
		}

		protected void ReceiveMessages(string jSONMsg)
		{
			IEnumerable<ButtplugMessage> enumerable;
			try
			{
				enumerable = _jsonSerializer.Deserialize(jSONMsg);
			}
			catch (ButtplugMessageException ex)
			{
				this.InvalidMessageReceived?.Invoke(this, new ButtplugExceptionEventArgs(ex));
				return;
			}
			foreach (ButtplugMessage item in enumerable)
			{
				if (item.Id == 0)
				{
					this.MessageReceived?.Invoke(this, new MessageReceivedEventArgs(item));
					continue;
				}
				try
				{
					_msgSorter.CheckMessage(item);
				}
				catch (ButtplugMessageException ex2)
				{
					this.InvalidMessageReceived?.Invoke(this, new ButtplugExceptionEventArgs(ex2));
				}
			}
		}

		protected virtual void Dispose(bool disposing)
		{
			_msgSorter.Dispose();
		}

		public void Dispose()
		{
			Dispose(disposing: true);
			GC.SuppressFinalize(this);
		}
	}
	public class ButtplugWebsocketConnector : ButtplugRemoteJSONConnector, IButtplugClientConnector
	{
		private ClientWebSocket _wsClient;

		private readonly SynchronizationContext _owningDispatcher = SynchronizationContext.Current ?? new SynchronizationContext();

		private readonly Uri _uri;

		private Task _readTask;

		private CancellationTokenSource _readLoopCancellationToken;

		public bool Connected
		{
			get
			{
				ClientWebSocket wsClient = _wsClient;
				if (wsClient == null)
				{
					return false;
				}
				return wsClient.State == WebSocketState.Open;
			}
		}

		public event EventHandler Disconnected;

		public ButtplugWebsocketConnector(Uri uri)
		{
			_uri = uri;
		}

		public async Task ConnectAsync(CancellationToken token = default(CancellationToken))
		{
			if (_wsClient != null)
			{
				throw new ButtplugHandshakeException("Websocket connector is already connected.");
			}
			try
			{
				_wsClient = new ClientWebSocket();
				await _wsClient.ConnectAsync(_uri, token).ConfigureAwait(continueOnCapturedContext: false);
			}
			catch (Exception inner)
			{
				throw new ButtplugClientConnectorException("Websocket Connection Exception! See Inner Exception", inner);
			}
			_readLoopCancellationToken?.Dispose();
			_readLoopCancellationToken = new CancellationTokenSource();
			_readTask = Task.Run(async delegate
			{
				await RunClientLoop(_readLoopCancellationToken.Token).ConfigureAwait(continueOnCapturedContext: false);
			});
		}

		public async Task DisconnectAsync(CancellationToken token = default(CancellationToken))
		{
			_readLoopCancellationToken?.Cancel();
			if (_wsClient != null && (_wsClient.State == WebSocketState.Connecting || _wsClient.State == WebSocketState.Open))
			{
				await _wsClient.CloseAsync(WebSocketCloseStatus.NormalClosure, null, CancellationToken.None).ConfigureAwait(continueOnCapturedContext: false);
			}
			_wsClient?.Dispose();
			_wsClient = null;
			if (_readTask != null)
			{
				await _readTask.ConfigureAwait(continueOnCapturedContext: false);
			}
			_readLoopCancellationToken?.Dispose();
			_readLoopCancellationToken = null;
		}

		public async Task<ButtplugMessage> SendAsync(ButtplugMessage msg, CancellationToken cancellationToken)
		{
			if (_wsClient == null)
			{
				throw new ButtplugException("Cannot send messages while disconnected", Error.ErrorClass.ERROR_MSG);
			}
			ReturnMessage returnMsg = PrepareMessage(msg, cancellationToken);
			await _wsClient.SendAsync(new ArraySegment<byte>(Encoding.UTF8.GetBytes(returnMsg.Message)), WebSocketMessageType.Text, endOfMessage: true, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
			return await returnMsg.Promise.ConfigureAwait(continueOnCapturedContext: false);
		}

		private async Task RunClientLoop(CancellationToken token)
		{
			try
			{
				new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: false);
				byte[] buff = new byte[2048];
				while (Connected && !token.IsCancellationRequested)
				{
					WebSocketReceiveResult webSocketReceiveResult = await _wsClient.ReceiveAsync(new ArraySegment<byte>(buff), token).ConfigureAwait(continueOnCapturedContext: false);
					if (webSocketReceiveResult.MessageType == WebSocketMessageType.Text)
					{
						string jSONMsg = Encoding.Default.GetString(buff, 0, webSocketReceiveResult.Count);
						ReceiveMessages(jSONMsg);
					}
				}
			}
			catch (Exception)
			{
			}
			finally
			{
				if (_wsClient != null)
				{
					_wsClient.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", CancellationToken.None).Dispose();
					_wsClient = null;
				}
				_owningDispatcher.Send(delegate
				{
					Dispose();
				}, null);
				_owningDispatcher.Send(delegate
				{
					this.Disconnected?.Invoke(this, EventArgs.Empty);
				}, null);
			}
		}
	}
	public interface IButtplugClientConnector
	{
		bool Connected { get; }

		event EventHandler<MessageReceivedEventArgs> MessageReceived;

		event EventHandler<ButtplugExceptionEventArgs> InvalidMessageReceived;

		event EventHandler Disconnected;

		Task ConnectAsync(CancellationToken token = default(CancellationToken));

		Task DisconnectAsync(CancellationToken token = default(CancellationToken));

		Task<ButtplugMessage> SendAsync(ButtplugMessage msg, CancellationToken token = default(CancellationToken));
	}
}

BepInEx\plugins\PeakIntiface\PeakIntiface.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Threading;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Buttplug.Client;
using Buttplug.Core.Messages;
using PeakIntiface.Buttplug;
using PeakIntiface.Toy;
using PeakIntiface.Triggers;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("PeakIntiface")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+0b15eeb7ef8e55e8e05ba857bf82664946ae5b27")]
[assembly: AssemblyProduct("PeakIntiface")]
[assembly: AssemblyTitle("PeakIntiface")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace PeakIntiface
{
	internal class ConfigManager
	{
		private readonly ConfigFile config;

		public static ConfigEntry<bool> Enabled;

		public static ConfigEntry<string> ServerIP;

		public static ConfigEntry<int> ServerPort;

		public static ConfigEntry<float> MaximumIntensity;

		public static ConfigEntry<float> MaximumRotate;

		public static ConfigEntry<float> MaximumConstrict;

		public static ConfigEntry<bool> EmergencyStopEnabled;

		public static ConfigEntry<KeyCode> EmergencyStopKey;

		public static ConfigEntry<float> ConstantVibration;

		public static ConfigEntry<bool> UseCarried;

		public static ConfigEntry<bool> UseSpectate;

		public static ConfigEntry<bool> InjuryTriggerEnabled;

		public static ConfigEntry<float> InjuryTriggerMaximumIntensity;

		public static ConfigEntry<float> InjuryTriggerMinimumIntensity;

		public static ConfigEntry<float> InjuryTriggerDuration;

		public static ConfigEntry<bool> ColdTriggerEnabled;

		public static ConfigEntry<float> ColdTriggerMaximumIntensity;

		public static ConfigEntry<float> ColdTriggerMinimumIntensity;

		public static ConfigEntry<float> ColdTriggerDuration;

		public static ConfigEntry<bool> PoisonTriggerEnabled;

		public static ConfigEntry<float> PoisonTriggerMaximumIntensity;

		public static ConfigEntry<float> PoisonTriggerMinimumIntensity;

		public static ConfigEntry<float> PoisonTriggerDuration;

		public static ConfigEntry<bool> CurseTriggerEnabled;

		public static ConfigEntry<float> CurseTriggerMaximumIntensity;

		public static ConfigEntry<float> CurseTriggerMinimumIntensity;

		public static ConfigEntry<float> CurseTriggerDuration;

		public static ConfigEntry<bool> DrowsyTriggerEnabled;

		public static ConfigEntry<float> DrowsyTriggerMaximumIntensity;

		public static ConfigEntry<float> DrowsyTriggerMinimumIntensity;

		public static ConfigEntry<float> DrowsyTriggerDuration;

		public static ConfigEntry<bool> HotTriggerEnabled;

		public static ConfigEntry<float> HotTriggerMaximumIntensity;

		public static ConfigEntry<float> HotTriggerMinimumIntensity;

		public static ConfigEntry<float> HotTriggerDuration;

		public static ConfigEntry<bool> ThornsTriggerEnabled;

		public static ConfigEntry<float> ThornsTriggerMaximumIntensity;

		public static ConfigEntry<float> ThornsTriggerMinimumIntensity;

		public static ConfigEntry<float> ThornsTriggerDuration;

		public static ConfigEntry<bool> SporesTriggerEnabled;

		public static ConfigEntry<float> SporesTriggerMaximumIntensity;

		public static ConfigEntry<float> SporesTriggerMinimumIntensity;

		public static ConfigEntry<float> SporesTriggerDuration;

		public static ConfigEntry<bool> WebTriggerEnabled;

		public static ConfigEntry<float> WebTriggerMaximumIntensity;

		public static ConfigEntry<float> WebTriggerMinimumIntensity;

		public static ConfigEntry<float> WebTriggerDuration;

		public static ConfigEntry<bool> ArrowTriggerEnabled;

		public static ConfigEntry<float> ArrowTriggerMaximumIntensity;

		public static ConfigEntry<float> ArrowTriggerMinimumIntensity;

		public static ConfigEntry<float> ArrowTriggerDuration;

		public static ConfigEntry<bool> PetrifyTriggerEnabled;

		public static ConfigEntry<float> PetrifyTriggerMaximumIntensity;

		public static ConfigEntry<float> PetrifyTriggerMinimumIntensity;

		public static ConfigEntry<float> PetrifyTriggerDuration;

		public static ConfigEntry<bool> DeadEnabled;

		public static ConfigEntry<float> DeadIntensity;

		public static ConfigEntry<float> DeadTime;

		public static ConfigEntry<bool> PassedOutEnabled;

		public static ConfigEntry<float> PassedOutIntensity;

		public static ConfigEntry<float> PassedOutTime;

		public static ConfigEntry<bool> RagdollEnabled;

		public static ConfigEntry<float> RagdollIntensity;

		public static ConfigEntry<float> RagdollTime;

		public ConfigManager(ConfigFile config)
		{
			this.config = config;
			LoadConfig();
		}

		private void LoadConfig()
		{
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Expected O, but got Unknown
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Expected O, but got Unknown
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Expected O, but got Unknown
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Expected O, but got Unknown
			//IL_01df: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fa: Expected O, but got Unknown
			//IL_01fa: Expected O, but got Unknown
			//IL_020f: 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_022a: Expected O, but got Unknown
			//IL_022a: Expected O, but got Unknown
			//IL_027d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0287: Expected O, but got Unknown
			//IL_02ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c4: Expected O, but got Unknown
			//IL_02f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0301: Expected O, but got Unknown
			//IL_0354: Unknown result type (might be due to invalid IL or missing references)
			//IL_035e: Expected O, but got Unknown
			//IL_0391: Unknown result type (might be due to invalid IL or missing references)
			//IL_039b: Expected O, but got Unknown
			//IL_03ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d8: Expected O, but got Unknown
			//IL_042b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0435: Expected O, but got Unknown
			//IL_0468: Unknown result type (might be due to invalid IL or missing references)
			//IL_0472: Expected O, but got Unknown
			//IL_04a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_04af: Expected O, but got Unknown
			//IL_0502: Unknown result type (might be due to invalid IL or missing references)
			//IL_050c: Expected O, but got Unknown
			//IL_053f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0549: Expected O, but got Unknown
			//IL_057c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0586: Expected O, but got Unknown
			//IL_05d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_05e3: Expected O, but got Unknown
			//IL_0616: Unknown result type (might be due to invalid IL or missing references)
			//IL_0620: Expected O, but got Unknown
			//IL_0653: Unknown result type (might be due to invalid IL or missing references)
			//IL_065d: Expected O, but got Unknown
			//IL_06b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_06ba: Expected O, but got Unknown
			//IL_06ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_06f7: Expected O, but got Unknown
			//IL_072a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0734: Expected O, but got Unknown
			//IL_0787: Unknown result type (might be due to invalid IL or missing references)
			//IL_0791: Expected O, but got Unknown
			//IL_07c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_07ce: Expected O, but got Unknown
			//IL_0801: Unknown result type (might be due to invalid IL or missing references)
			//IL_080b: Expected O, but got Unknown
			//IL_085e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0868: Expected O, but got Unknown
			//IL_089b: Unknown result type (might be due to invalid IL or missing references)
			//IL_08a5: Expected O, but got Unknown
			//IL_08d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_08e2: Expected O, but got Unknown
			//IL_0935: Unknown result type (might be due to invalid IL or missing references)
			//IL_093f: Expected O, but got Unknown
			//IL_0972: Unknown result type (might be due to invalid IL or missing references)
			//IL_097c: Expected O, but got Unknown
			//IL_09af: Unknown result type (might be due to invalid IL or missing references)
			//IL_09b9: Expected O, but got Unknown
			//IL_0a0c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a16: Expected O, but got Unknown
			//IL_0a49: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a53: Expected O, but got Unknown
			//IL_0a86: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a90: Expected O, but got Unknown
			//IL_0ae3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0aed: Expected O, but got Unknown
			//IL_0b20: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b2a: Expected O, but got Unknown
			//IL_0b5d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b67: Expected O, but got Unknown
			//IL_0b7c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b8d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b97: Expected O, but got Unknown
			//IL_0b97: Expected O, but got Unknown
			//IL_0bac: Unknown result type (might be due to invalid IL or missing references)
			//IL_0bcf: Unknown result type (might be due to invalid IL or missing references)
			//IL_0bd9: Expected O, but got Unknown
			//IL_0bd9: Expected O, but got Unknown
			//IL_0bee: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c11: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c1b: Expected O, but got Unknown
			//IL_0c1b: Expected O, but got Unknown
			//IL_0c30: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c41: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c4b: Expected O, but got Unknown
			//IL_0c4b: Expected O, but got Unknown
			//IL_0c60: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c83: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c8d: Expected O, but got Unknown
			//IL_0c8d: Expected O, but got Unknown
			//IL_0ca2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0cc5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ccf: Expected O, but got Unknown
			//IL_0ccf: Expected O, but got Unknown
			//IL_0ce4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0cf5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0cff: Expected O, but got Unknown
			//IL_0cff: Expected O, but got Unknown
			//IL_0d14: Unknown result type (might be due to invalid IL or missing references)
			//IL_0d37: Unknown result type (might be due to invalid IL or missing references)
			//IL_0d41: Expected O, but got Unknown
			//IL_0d41: Expected O, but got Unknown
			//IL_0d56: Unknown result type (might be due to invalid IL or missing references)
			//IL_0d79: Unknown result type (might be due to invalid IL or missing references)
			//IL_0d83: Expected O, but got Unknown
			//IL_0d83: Expected O, but got Unknown
			Enabled = config.Bind<bool>("General", "Enabled", true, "Enable or Disable toy control");
			Enabled.SettingChanged += EnabledSettingChanged;
			MaximumIntensity = config.Bind<float>("General", "Maximum Intensity", 0.7f, new ConfigDescription("Maximumtoy intensity from 0.0 to 1.0", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 1f), Array.Empty<object>()));
			MaximumRotate = config.Bind<float>("General", "Maximum Rotate", 0.3f, new ConfigDescription("Maximum toy rotate intensity from 0.0 to 1.0", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 1f), Array.Empty<object>()));
			MaximumConstrict = config.Bind<float>("General", "Maximum Constrict", 0.3f, new ConfigDescription("Maximum toy constrict intensity from 0.0 to 1.0", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 1f), Array.Empty<object>()));
			ServerIP = config.Bind<string>("General", "Server IP", "127.0.0.1", "IP address of the Intiface Server");
			ServerPort = config.Bind<int>("General", "Server Port", 12345, "Port of the Intiface Server");
			EmergencyStopEnabled = config.Bind<bool>("General", "Emergency Stop Enabled", true, "Enable or Disable Emergency Stop");
			EmergencyStopKey = config.Bind<KeyCode>("General", "Emergency Stop Key", (KeyCode)291, "Key to trigger Emergency Stop");
			ConstantVibration = config.Bind<float>("General", "Constant Vibration", 0f, new ConfigDescription("Constant vibration intensity from 0.0 to 1.0", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			ConstantVibration.SettingChanged += ConstantVibrationSettingChanged;
			UseCarried = config.Bind<bool>(new ConfigDefinition("Player State", "Use Carried"), true, new ConfigDescription("Use the player who is carring you for triggers", (AcceptableValueBase)null, Array.Empty<object>()));
			UseSpectate = config.Bind<bool>(new ConfigDefinition("Player State", "Use Spectate"), true, new ConfigDescription("Use the player who you are Spectating for triggers", (AcceptableValueBase)null, Array.Empty<object>()));
			InjuryTriggerEnabled = config.Bind<bool>("Triggers", "Injury Trigger Enabled", true, "Enable or Disable Injury Trigger");
			InjuryTriggerMaximumIntensity = config.Bind<float>("Triggers", "Injury Trigger Maximum Intensity", 0.5f, new ConfigDescription("Maximum intensity for Injury Trigger from 0.0 to 1.0", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 1f), Array.Empty<object>()));
			InjuryTriggerMinimumIntensity = config.Bind<float>("Triggers", "Injury Trigger Minimum Intensity", 0.1f, new ConfigDescription("Minimum intensity for Injury Trigger from 0.0 to 1.0", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 1f), Array.Empty<object>()));
			InjuryTriggerDuration = config.Bind<float>("Triggers", "Injury Trigger Duration", 5000f, new ConfigDescription("Duration for Injury Trigger in milliseconds", (AcceptableValueBase)(object)new AcceptableValueRange<float>(100f, 10000f), Array.Empty<object>()));
			ColdTriggerEnabled = config.Bind<bool>("Triggers", "Cold Trigger Enabled", true, "Enable or Disable Cold Trigger");
			ColdTriggerMaximumIntensity = config.Bind<float>("Triggers", "Cold Trigger Maximum Intensity", 0.5f, new ConfigDescription("Maximum intensity for Cold Trigger from 0.0 to 1.0", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 1f), Array.Empty<object>()));
			ColdTriggerMinimumIntensity = config.Bind<float>("Triggers", "Cold Trigger Minimum Intensity", 0.1f, new ConfigDescription("Minimum intensity for Cold Trigger from 0.0 to 1.0", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 1f), Array.Empty<object>()));
			ColdTriggerDuration = config.Bind<float>("Triggers", "Cold Trigger Duration", 1000f, new ConfigDescription("Duration for Cold Trigger in milliseconds", (AcceptableValueBase)(object)new AcceptableValueRange<float>(100f, 10000f), Array.Empty<object>()));
			PoisonTriggerEnabled = config.Bind<bool>("Triggers", "Poison Trigger Enabled", true, "Enable or Disable Poison Trigger");
			PoisonTriggerMaximumIntensity = config.Bind<float>("Triggers", "Poison Trigger Maximum Intensity", 0.5f, new ConfigDescription("Maximum intensity for Poison Trigger from 0.0 to 1.0", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 1f), Array.Empty<object>()));
			PoisonTriggerMinimumIntensity = config.Bind<float>("Triggers", "Poison Trigger Minimum Intensity", 0.1f, new ConfigDescription("Minimum intensity for Poison Trigger from 0.0 to 1.0", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 1f), Array.Empty<object>()));
			PoisonTriggerDuration = config.Bind<float>("Triggers", "Poison Trigger Duration", 3000f, new ConfigDescription("Duration for Poison Trigger in milliseconds", (AcceptableValueBase)(object)new AcceptableValueRange<float>(100f, 10000f), Array.Empty<object>()));
			CurseTriggerEnabled = config.Bind<bool>("Triggers", "Curse Trigger Enabled", true, "Enable or Disable Curse Trigger");
			CurseTriggerMaximumIntensity = config.Bind<float>("Triggers", "Curse Trigger Maximum Intensity", 0.5f, new ConfigDescription("Maximum intensity for Curse Trigger from 0.0 to 1.0", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 1f), Array.Empty<object>()));
			CurseTriggerMinimumIntensity = config.Bind<float>("Triggers", "Curse Trigger Minimum Intensity", 0.1f, new ConfigDescription("Minimum intensity for Curse Trigger from 0.0 to 1.0", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 1f), Array.Empty<object>()));
			CurseTriggerDuration = config.Bind<float>("Triggers", "Curse Trigger Duration", 5000f, new ConfigDescription("Duration for Curse Trigger in milliseconds", (AcceptableValueBase)(object)new AcceptableValueRange<float>(100f, 10000f), Array.Empty<object>()));
			DrowsyTriggerEnabled = config.Bind<bool>("Triggers", "Drowsy Trigger Enabled", true, "Enable or Disable Drowsy Trigger");
			DrowsyTriggerMaximumIntensity = config.Bind<float>("Triggers", "Drowsy Trigger Maximum Intensity", 0.5f, new ConfigDescription("Maximum intensity for Drowsy Trigger from 0.0 to 1.0", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 1f), Array.Empty<object>()));
			DrowsyTriggerMinimumIntensity = config.Bind<float>("Triggers", "Drowsy Trigger Minimum Intensity", 0.1f, new ConfigDescription("Minimum intensity for Drowsy Trigger from 0.0 to 1.0", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 1f), Array.Empty<object>()));
			DrowsyTriggerDuration = config.Bind<float>("Triggers", "Drowsy Trigger Duration", 1000f, new ConfigDescription("Duration for Drowsy Trigger in milliseconds", (AcceptableValueBase)(object)new AcceptableValueRange<float>(100f, 10000f), Array.Empty<object>()));
			HotTriggerEnabled = config.Bind<bool>("Triggers", "Hot Trigger Enabled", true, "Enable or Disable Hot Trigger");
			HotTriggerMaximumIntensity = config.Bind<float>("Triggers", "Hot Trigger Maximum Intensity", 0.5f, new ConfigDescription("Maximum intensity for Hot Trigger from 0.0 to 1.0", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 1f), Array.Empty<object>()));
			HotTriggerMinimumIntensity = config.Bind<float>("Triggers", "Hot Trigger Minimum Intensity", 0.1f, new ConfigDescription("Minimum intensity for Hot Trigger from 0.0 to 1.0", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 1f), Array.Empty<object>()));
			HotTriggerDuration = config.Bind<float>("Triggers", "Hot Trigger Duration", 1000f, new ConfigDescription("Duration for Hot Trigger in milliseconds", (AcceptableValueBase)(object)new AcceptableValueRange<float>(100f, 10000f), Array.Empty<object>()));
			ThornsTriggerEnabled = config.Bind<bool>("Triggers", "Thorns Trigger Enabled", true, "Enable or Disable Thorns Trigger");
			ThornsTriggerMaximumIntensity = config.Bind<float>("Triggers", "Thorns Trigger Maximum Intensity", 0.5f, new ConfigDescription("Maximum intensity for Thorns Trigger from 0.0 to 1.0", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 1f), Array.Empty<object>()));
			ThornsTriggerMinimumIntensity = config.Bind<float>("Triggers", "Thorns Trigger Minimum Intensity", 0.1f, new ConfigDescription("Minimum intensity for Thorns Trigger from 0.0 to 1.0", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 1f), Array.Empty<object>()));
			ThornsTriggerDuration = config.Bind<float>("Triggers", "Thorns Trigger Duration", 3000f, new ConfigDescription("Duration for Thorns Trigger in milliseconds", (AcceptableValueBase)(object)new AcceptableValueRange<float>(100f, 10000f), Array.Empty<object>()));
			SporesTriggerEnabled = config.Bind<bool>("Triggers", "Spores Trigger Enabled", true, "Enable or Disable Spores Trigger");
			SporesTriggerMaximumIntensity = config.Bind<float>("Triggers", "Spores Trigger Maximum Intensity", 0.5f, new ConfigDescription("Maximum intensity for Spores Trigger from 0.0 to 1.0", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 1f), Array.Empty<object>()));
			SporesTriggerMinimumIntensity = config.Bind<float>("Triggers", "Spores Trigger Minimum Intensity", 0.1f, new ConfigDescription("Minimum intensity for Spores Trigger from 0.0 to 1.0", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 1f), Array.Empty<object>()));
			SporesTriggerDuration = config.Bind<float>("Triggers", "Spores Trigger Duration", 5000f, new ConfigDescription("Duration for Spores Trigger in milliseconds", (AcceptableValueBase)(object)new AcceptableValueRange<float>(100f, 10000f), Array.Empty<object>()));
			WebTriggerEnabled = config.Bind<bool>("Triggers", "Web Trigger Enabled", true, "Enable or Disable Web Trigger");
			WebTriggerMaximumIntensity = config.Bind<float>("Triggers", "Web Trigger Maximum Intensity", 0.5f, new ConfigDescription("Maximum intensity for Web Trigger from 0.0 to 1.0", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 1f), Array.Empty<object>()));
			WebTriggerMinimumIntensity = config.Bind<float>("Triggers", "Web Trigger Minimum Intensity", 0.1f, new ConfigDescription("Minimum intensity for Web Trigger from 0.0 to 1.0", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 1f), Array.Empty<object>()));
			WebTriggerDuration = config.Bind<float>("Triggers", "Web Trigger Duration", 2000f, new ConfigDescription("Duration for Web Trigger in milliseconds", (AcceptableValueBase)(object)new AcceptableValueRange<float>(100f, 10000f), Array.Empty<object>()));
			ArrowTriggerEnabled = config.Bind<bool>("Triggers", "Arrow Trigger Enabled", true, "Enable or Disable Arrow Trigger");
			ArrowTriggerMaximumIntensity = config.Bind<float>("Triggers", "Arrow Trigger Maximum Intensity", 0.5f, new ConfigDescription("Maximum intensity for Arrow Trigger from 0.0 to 1.0", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 1f), Array.Empty<object>()));
			ArrowTriggerMinimumIntensity = config.Bind<float>("Triggers", "Arrow Trigger Minimum Intensity", 0.1f, new ConfigDescription("Minimum intensity for Arrow Trigger from 0.0 to 1.0", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 1f), Array.Empty<object>()));
			ArrowTriggerDuration = config.Bind<float>("Triggers", "Arrow Trigger Duration", 5000f, new ConfigDescription("Duration for Arrow Trigger in milliseconds", (AcceptableValueBase)(object)new AcceptableValueRange<float>(100f, 10000f), Array.Empty<object>()));
			PetrifyTriggerEnabled = config.Bind<bool>("Triggers", "Petrify Trigger Enabled", true, "Enable or Disable Petrify Trigger");
			PetrifyTriggerMaximumIntensity = config.Bind<float>("Triggers", "Petrify Trigger Maximum Intensity", 0.5f, new ConfigDescription("Maximum intensity for Petrify Trigger from 0.0 to 1.0", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 1f), Array.Empty<object>()));
			PetrifyTriggerMinimumIntensity = config.Bind<float>("Triggers", "Petrify Trigger Minimum Intensity", 0.1f, new ConfigDescription("Minimum intensity for Petrify Trigger from 0.0 to 1.0", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 1f), Array.Empty<object>()));
			PetrifyTriggerDuration = config.Bind<float>("Triggers", "Petrify Trigger Duration", 5000f, new ConfigDescription("Duration for Petrify Trigger in milliseconds", (AcceptableValueBase)(object)new AcceptableValueRange<float>(100f, 10000f), Array.Empty<object>()));
			DeadEnabled = config.Bind<bool>(new ConfigDefinition("Player State", "Dead Enabled"), true, new ConfigDescription("Enabled on death to trigger toy.", (AcceptableValueBase)null, Array.Empty<object>()));
			DeadIntensity = config.Bind<float>(new ConfigDefinition("Player State", "Dead Intensity"), 1f, new ConfigDescription("How strong the toy should go when you die.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 1f), Array.Empty<object>()));
			DeadTime = config.Bind<float>(new ConfigDefinition("Player State", "Dead Time"), 5000f, new ConfigDescription("How strong the toy should go when you die.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(100f, 10000f), Array.Empty<object>()));
			PassedOutEnabled = config.Bind<bool>(new ConfigDefinition("Player State", "Passed Out Enabled"), true, new ConfigDescription("Enabled on passing out to trigger toy.", (AcceptableValueBase)null, Array.Empty<object>()));
			PassedOutIntensity = config.Bind<float>(new ConfigDefinition("Player State", "Passed Out Intensity"), 1f, new ConfigDescription("How strong the toy should go when you pass out.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 1f), Array.Empty<object>()));
			PassedOutTime = config.Bind<float>(new ConfigDefinition("Player State", "Passed Out Time"), 5000f, new ConfigDescription("How long the toy should go when you pass out.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(100f, 10000f), Array.Empty<object>()));
			RagdollEnabled = config.Bind<bool>(new ConfigDefinition("Player State", "Ragdoll Enabled"), true, new ConfigDescription("Enabled on ragdoll to trigger toy.", (AcceptableValueBase)null, Array.Empty<object>()));
			RagdollIntensity = config.Bind<float>(new ConfigDefinition("Player State", "Ragdoll Intensity"), 1f, new ConfigDescription("How strong the toy should go when you ragdoll.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 1f), Array.Empty<object>()));
			RagdollTime = config.Bind<float>(new ConfigDefinition("Player State", "Ragdoll Time"), 5000f, new ConfigDescription("How long the toy should go when you ragdoll.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(100f, 10000f), Array.Empty<object>()));
		}

		private void ConstantVibrationSettingChanged(object sender, EventArgs e)
		{
			if (ConstantVibration.Value < 0.01f)
			{
				Plugin.ToyController?.StopVibrationAsync();
			}
		}

		private void EnabledSettingChanged(object sender, EventArgs e)
		{
			if (Plugin.ButtplugManager != null)
			{
				if (Enabled.Value)
				{
					Plugin.ButtplugManager.StartReconnecting();
				}
				else
				{
					Plugin.ButtplugManager.DisconnectAsync();
				}
			}
		}
	}
	[BepInPlugin("momo.peakintiface", "PEAK Intiface", "0.4.2")]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "momo.peakintiface";

		public const string PluginName = "PEAK Intiface";

		public const string PluginVersion = "0.4.2";

		public static ButtplugManager ButtplugManager;

		public static ToyController ToyController;

		public static StaminaTrigger StaminaTrigger;

		public static StatustEffectTrigger StatustEffectTrigger;

		public static CharacterStateTrigger CharacterStateTrigger;

		private void Awake()
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)"PEAK Intiface v0.4.2 loading...");
			new ConfigManager(((BaseUnityPlugin)this).Config);
			ButtplugManager = new ButtplugManager(((BaseUnityPlugin)this).Logger);
			if (ConfigManager.Enabled.Value)
			{
				ButtplugManager.StartReconnecting();
			}
			ToyController = new ToyController(ButtplugManager, ((BaseUnityPlugin)this).Logger);
			StaminaTrigger = new StaminaTrigger(((BaseUnityPlugin)this).Logger);
			StatustEffectTrigger = new StatustEffectTrigger(((BaseUnityPlugin)this).Logger);
			CharacterStateTrigger = new CharacterStateTrigger(((BaseUnityPlugin)this).Logger);
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"Intiface Address: {ConfigManager.ServerIP.Value}:{ConfigManager.ServerPort.Value}");
			((BaseUnityPlugin)this).Logger.LogInfo((object)"PEAK Intiface Loaded!");
		}

		private void Update()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			if (ConfigManager.EmergencyStopEnabled.Value && Input.GetKeyDown(ConfigManager.EmergencyStopKey.Value))
			{
				ToyController?.StopVibrationAsync();
				ConfigManager.Enabled.Value = false;
			}
			else if (ConfigManager.Enabled.Value && ToyController != null && ButtplugManager.IsConnected)
			{
				StaminaTrigger?.Update();
				StatustEffectTrigger?.Update();
				CharacterStateTrigger?.Update();
			}
		}

		private void OnApplicationQuit()
		{
			if (ButtplugManager == null)
			{
				return;
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)"PEAK is closing. Shutting down Intiface...");
			try
			{
				Task task = ButtplugManager.DisconnectAsync();
				if (!task.Wait(2000))
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)"Intiface shutdown timed out. Allowing PEAK to close.");
				}
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Error during Intiface shutdown: " + ex.Message));
			}
		}
	}
}
namespace PeakIntiface.Triggers
{
	public class CharacterStateTrigger
	{
		private readonly ManualLogSource logger;

		private bool alreadyDead = false;

		private bool alreadyPassedOut = false;

		private bool alreadyRagdoll = false;

		private readonly Dictionary<string, CancellationTokenSource> timedVibration = new Dictionary<string, CancellationTokenSource>();

		public CharacterStateTrigger(ManualLogSource logger)
		{
			this.logger = logger;
		}

		public void Update()
		{
			Character localCharacter = Character.localCharacter;
			if (!((Object)(object)localCharacter == (Object)null) && !((Object)(object)localCharacter.data == (Object)null))
			{
				bool dead = localCharacter.data.dead;
				bool flag = localCharacter.data.passedOut || localCharacter.data.fullyPassedOut;
				bool flag2 = localCharacter.data.fallSeconds > 0f;
				if (dead && !alreadyDead && ConfigManager.DeadEnabled.Value)
				{
					OnDeath();
				}
				if (flag && !alreadyPassedOut && ConfigManager.PassedOutEnabled.Value)
				{
					OnPassOut();
				}
				if (flag2 && !alreadyRagdoll && ConfigManager.RagdollEnabled.Value)
				{
					OnRagdoll();
				}
				alreadyDead = dead;
				alreadyPassedOut = flag;
				alreadyRagdoll = flag2;
			}
		}

		private void OnDeath()
		{
			StartTimedVibration("Death", ConfigManager.DeadIntensity.Value, ConfigManager.DeadTime.Value);
		}

		private void OnPassOut()
		{
			StartTimedVibration("PassOut", ConfigManager.PassedOutIntensity.Value, ConfigManager.PassedOutTime.Value);
		}

		private void OnRagdoll()
		{
			StartTimedVibration("Ragdoll", ConfigManager.RagdollIntensity.Value, ConfigManager.RagdollTime.Value);
		}

		private async Task StartTimedVibration(string VibrationSource, double intensity, float durationMilliseconds)
		{
			if (timedVibration.TryGetValue(VibrationSource, out var oldTimer))
			{
				oldTimer.Cancel();
				oldTimer.Dispose();
			}
			CancellationTokenSource timer = new CancellationTokenSource();
			timedVibration[VibrationSource] = timer;
			string source = "CharacterState-" + VibrationSource;
			TriggerUtils.SetVibration(source, intensity);
			try
			{
				await Task.Delay((int)durationMilliseconds, timer.Token);
			}
			catch (Exception)
			{
				return;
			}
			TriggerUtils.SetVibration(source, 0.0);
			timer.Dispose();
			timedVibration.Remove(VibrationSource);
		}
	}
	public class StaminaTrigger
	{
		private readonly ManualLogSource logger;

		public StaminaTrigger(ManualLogSource logger)
		{
			this.logger = logger;
		}

		public void Update()
		{
			if (Plugin.ToyController != null)
			{
				Character characterForStats = TriggerUtils.GetCharacterForStats();
				if ((Object)(object)characterForStats == (Object)null)
				{
					TriggerUtils.SetVibration("movement", 0.0);
					return;
				}
				float currentStamina = characterForStats.data.currentStamina;
				float maxStamina = characterForStats.GetMaxStamina();
				float num = ((maxStamina > 0f) ? (currentStamina / maxStamina) : 0f);
				TriggerUtils.SetVibration("movement", 1f - num);
			}
		}
	}
	public class StatustEffectTrigger
	{
		private readonly ManualLogSource logger;

		private Character subscribedCharacter = null;

		private readonly Dictionary<STATUSTYPE, CancellationTokenSource> afflictionIntensities = new Dictionary<STATUSTYPE, CancellationTokenSource>();

		public StatustEffectTrigger(ManualLogSource logger)
		{
			this.logger = logger;
		}

		internal void Update()
		{
			Character characterForStats = TriggerUtils.GetCharacterForStats();
			if (!((Object)(object)characterForStats == (Object)null) && !((Object)(object)subscribedCharacter == (Object)(object)characterForStats))
			{
				if ((Object)(object)subscribedCharacter != (Object)null)
				{
					CharacterAfflictions afflictions = subscribedCharacter.refs.afflictions;
					afflictions.OnAddedIncrementalStatus = (Action<STATUSTYPE, float>)Delegate.Remove(afflictions.OnAddedIncrementalStatus, new Action<STATUSTYPE, float>(OnAfflictionAdded));
				}
				subscribedCharacter = characterForStats;
				CharacterAfflictions afflictions2 = subscribedCharacter.refs.afflictions;
				afflictions2.OnAddedIncrementalStatus = (Action<STATUSTYPE, float>)Delegate.Combine(afflictions2.OnAddedIncrementalStatus, new Action<STATUSTYPE, float>(OnAfflictionAdded));
				logger.LogInfo((object)"Subscribed to status effects.");
			}
		}

		private void OnAfflictionAdded(STATUSTYPE sTATUSTYPE, float amount)
		{
			//IL_0011: 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_002a: 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_002e: 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_006f: Expected I4, but got Unknown
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: 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_0244: Unknown result type (might be due to invalid IL or missing references)
			//IL_0293: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0337: Unknown result type (might be due to invalid IL or missing references)
			//IL_0389: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d2: Unknown result type (might be due to invalid IL or missing references)
			float num = subscribedCharacter.refs.afflictions.GetCurrentStatus(sTATUSTYPE);
			if (num <= 0f)
			{
				num = amount;
			}
			switch ((int)sTATUSTYPE)
			{
			case 0:
				if (ConfigManager.InjuryTriggerEnabled.Value)
				{
					double intensity6 = TriggerUtils.CalculateIntensity(num, ConfigManager.InjuryTriggerMaximumIntensity.Value, ConfigManager.InjuryTriggerMinimumIntensity.Value, 2f);
					HandleAfflictionIntensity(sTATUSTYPE, intensity6, ConfigManager.InjuryTriggerDuration.Value);
				}
				break;
			case 2:
				if (ConfigManager.ColdTriggerEnabled.Value)
				{
					double intensity10 = TriggerUtils.CalculateIntensity(num, ConfigManager.ColdTriggerMaximumIntensity.Value, ConfigManager.ColdTriggerMinimumIntensity.Value, 2f);
					HandleAfflictionIntensity(sTATUSTYPE, intensity10, ConfigManager.ColdTriggerDuration.Value);
				}
				break;
			case 3:
				if (ConfigManager.PoisonTriggerEnabled.Value)
				{
					double intensity2 = TriggerUtils.CalculateIntensity(num, ConfigManager.PoisonTriggerMaximumIntensity.Value, ConfigManager.PoisonTriggerMinimumIntensity.Value, 2f);
					HandleAfflictionIntensity(sTATUSTYPE, intensity2, ConfigManager.PoisonTriggerDuration.Value);
				}
				break;
			case 5:
				if (ConfigManager.CurseTriggerEnabled.Value)
				{
					double intensity8 = TriggerUtils.CalculateIntensity(num, ConfigManager.CurseTriggerMaximumIntensity.Value, ConfigManager.CurseTriggerMinimumIntensity.Value, 2f);
					HandleAfflictionIntensity(sTATUSTYPE, intensity8, ConfigManager.CurseTriggerDuration.Value);
				}
				break;
			case 6:
				if (ConfigManager.DrowsyTriggerEnabled.Value)
				{
					double intensity4 = TriggerUtils.CalculateIntensity(num, ConfigManager.DrowsyTriggerMaximumIntensity.Value, ConfigManager.DrowsyTriggerMinimumIntensity.Value, 2f);
					HandleAfflictionIntensity(sTATUSTYPE, intensity4, ConfigManager.DrowsyTriggerDuration.Value);
				}
				break;
			case 8:
				if (ConfigManager.HotTriggerEnabled.Value)
				{
					double intensity11 = TriggerUtils.CalculateIntensity(num, ConfigManager.HotTriggerMaximumIntensity.Value, ConfigManager.HotTriggerMinimumIntensity.Value, 2f);
					HandleAfflictionIntensity(sTATUSTYPE, intensity11, ConfigManager.HotTriggerDuration.Value);
				}
				break;
			case 9:
				if (!ConfigManager.ThornsTriggerEnabled.Value)
				{
					double intensity9 = TriggerUtils.CalculateIntensity(num, ConfigManager.ThornsTriggerMaximumIntensity.Value, ConfigManager.ThornsTriggerMinimumIntensity.Value, 2f);
					HandleAfflictionIntensity(sTATUSTYPE, intensity9, ConfigManager.ThornsTriggerDuration.Value);
				}
				break;
			case 10:
				if (ConfigManager.SporesTriggerEnabled.Value)
				{
					double intensity7 = TriggerUtils.CalculateIntensity(num, ConfigManager.SporesTriggerMaximumIntensity.Value, ConfigManager.SporesTriggerMinimumIntensity.Value, 2f);
					HandleAfflictionIntensity(sTATUSTYPE, intensity7, ConfigManager.SporesTriggerDuration.Value);
				}
				break;
			case 11:
				if (ConfigManager.WebTriggerEnabled.Value)
				{
					double intensity5 = TriggerUtils.CalculateIntensity(num, ConfigManager.WebTriggerMaximumIntensity.Value, ConfigManager.WebTriggerMinimumIntensity.Value, 2f);
					HandleAfflictionIntensity(sTATUSTYPE, intensity5, ConfigManager.WebTriggerDuration.Value);
				}
				break;
			case 12:
				if (ConfigManager.ArrowTriggerEnabled.Value)
				{
					double intensity3 = TriggerUtils.CalculateIntensity(num, ConfigManager.ArrowTriggerMaximumIntensity.Value, ConfigManager.ArrowTriggerMinimumIntensity.Value, 2f);
					HandleAfflictionIntensity(sTATUSTYPE, intensity3, ConfigManager.ArrowTriggerDuration.Value);
				}
				break;
			case 13:
				if (!ConfigManager.PetrifyTriggerEnabled.Value)
				{
					double intensity = TriggerUtils.CalculateIntensity(num, ConfigManager.PetrifyTriggerMaximumIntensity.Value, ConfigManager.PetrifyTriggerMinimumIntensity.Value, 2f);
					HandleAfflictionIntensity(sTATUSTYPE, intensity, ConfigManager.PetrifyTriggerDuration.Value);
				}
				break;
			case 1:
			case 4:
			case 7:
				break;
			}
		}

		private async Task HandleAfflictionIntensity(STATUSTYPE sTATUSTYPE, double intensity, float durationMilliseconds)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			if (afflictionIntensities.TryGetValue(sTATUSTYPE, out var oldTimer))
			{
				oldTimer.Cancel();
				oldTimer.Dispose();
			}
			CancellationTokenSource timer = new CancellationTokenSource();
			afflictionIntensities[sTATUSTYPE] = timer;
			string source = $"StatustEffectTrigger-{sTATUSTYPE}";
			TriggerUtils.SetVibration(source, intensity);
			try
			{
				await Task.Delay((int)durationMilliseconds, timer.Token);
			}
			catch (Exception)
			{
				return;
			}
			TriggerUtils.SetVibration(source, 0.0);
			timer.Dispose();
			afflictionIntensities.Remove(sTATUSTYPE);
		}
	}
	internal static class TriggerUtils
	{
		public static double CalculateIntensity(float intensity, float maximum, float minimum, float multiplier = 1f)
		{
			return minimum + intensity * multiplier * (maximum - minimum);
		}

		public static void SetVibration(string source, double intensity)
		{
			Plugin.ToyController.SetSourceIntensity(source, intensity);
		}

		public static Character GetCharacterForStats()
		{
			Character val = Character.localCharacter;
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			if ((Object)(object)val.data == (Object)null)
			{
				return null;
			}
			if (ConfigManager.UseCarried.Value && val.data.isCarried && (Object)(object)val.data.carrier != (Object)null)
			{
				val = val.data.carrier;
			}
			else if (ConfigManager.UseSpectate.Value && val.data.dead)
			{
				val = Character.observedCharacter;
			}
			return val;
		}
	}
}
namespace PeakIntiface.Toy
{
	public class ToyController
	{
		private readonly ManualLogSource logger;

		private readonly ButtplugManager buttplugManager;

		private readonly Dictionary<string, double> sourceIntensities = new Dictionary<string, double>();

		public ToyController(ButtplugManager buttplugManager, ManualLogSource logger)
		{
			logger.LogInfo((object)"ToyController initialized.");
			this.logger = logger;
			this.buttplugManager = buttplugManager;
		}

		public void SetSourceIntensity(string source, double intensity)
		{
			sourceIntensities[source] = intensity;
			UpdateVibrationAsync();
		}

		private async void UpdateVibrationAsync()
		{
			if (!buttplugManager.IsConnected)
			{
				return;
			}
			double highestIntensity = ConfigManager.ConstantVibration.Value;
			string highestSource = "ConstantVibration";
			foreach (KeyValuePair<string, double> sourceIntensity in sourceIntensities)
			{
				if (sourceIntensity.Value > highestIntensity)
				{
					highestIntensity = sourceIntensity.Value;
					highestSource = sourceIntensity.Key;
				}
			}
			logger.LogInfo((object)$"Highest intensity source: {highestSource} with intensity: {highestIntensity}");
			if (highestIntensity < 0.009999999776482582)
			{
				await StopVibrationAsync();
				return;
			}
			ButtplugClientDevice[] devices = buttplugManager.Client.Devices;
			foreach (ButtplugClientDevice device in devices)
			{
				if (device.HasOutput((OutputType)1))
				{
					try
					{
						double clampedVibrateIntensity = Math.Max(0.0, Math.Min(highestIntensity, ConfigManager.MaximumIntensity.Value));
						await device.RunOutputAsync(DeviceOutput.Vibrate.Percent(clampedVibrateIntensity), default(CancellationToken));
					}
					catch (Exception ex)
					{
						Exception ex2 = ex;
						logger.LogWarning((object)("Could not control " + device.Name + ": " + ex2.Message));
					}
				}
				if (device.HasOutput((OutputType)3) && highestSource != "ConstantVibration")
				{
					try
					{
						double clampedRotateIntensity = Math.Max(0.0, Math.Min(highestIntensity, ConfigManager.MaximumRotate.Value));
						double rotationIntensity = clampedRotateIntensity * (double)((!(Random.value < 0.5f)) ? 1 : (-1));
						await device.RunOutputAsync(DeviceOutput.Rotate.Percent(rotationIntensity), default(CancellationToken));
					}
					catch (Exception ex)
					{
						Exception ex3 = ex;
						logger.LogWarning((object)("Could not control " + device.Name + ": " + ex3.Message));
					}
				}
				if (device.HasOutput((OutputType)8))
				{
					try
					{
						double clampedConstrictIntensity = Math.Max(0.0, Math.Min(highestIntensity, ConfigManager.MaximumConstrict.Value));
						await device.RunOutputAsync(DeviceOutput.Constrict.Percent(clampedConstrictIntensity), default(CancellationToken));
					}
					catch (Exception ex)
					{
						Exception ex4 = ex;
						logger.LogWarning((object)("Could not control " + device.Name + ": " + ex4.Message));
					}
				}
			}
		}

		public async Task StopVibrationAsync()
		{
			if (!buttplugManager.IsConnected)
			{
				return;
			}
			sourceIntensities.Clear();
			try
			{
				await buttplugManager.Client.StopAllDevicesAsync(default(CancellationToken));
			}
			catch (Exception ex)
			{
				logger.LogWarning((object)("Could not stop devices: " + ex.Message));
			}
		}
	}
}
namespace PeakIntiface.Buttplug
{
	public class ButtplugManager
	{
		private readonly ManualLogSource logger;

		private ButtplugClient client;

		private bool reconnecting = false;

		public bool IsConnected => client != null && client.Connected;

		public ButtplugClient Client => client;

		public ButtplugManager(ManualLogSource logger)
		{
			this.logger = logger;
		}

		public async Task StartReconnecting()
		{
			if (reconnecting)
			{
				return;
			}
			reconnecting = true;
			while (reconnecting)
			{
				if (!IsConnected)
				{
					logger.LogInfo((object)"Retrying reconnecting");
					await ConnectAsync(ConfigManager.ServerIP.Value, ConfigManager.ServerPort.Value);
				}
				await Task.Delay(5000);
			}
		}

		private async Task ConnectAsync(string ip, int port)
		{
			if (IsConnected)
			{
				return;
			}
			string address = $"ws://{ip}:{port}";
			logger.LogInfo((object)("Connecting to " + address + "..."));
			try
			{
				client = new ButtplugClient("PEAK Intiface");
				client.DeviceAdded += OnDeviceAdded;
				client.DeviceRemoved += OnDeviceRemoved;
				ButtplugWebsocketConnector connector = new ButtplugWebsocketConnector(new Uri(address));
				await client.ConnectAsync((IButtplugClientConnector)(object)connector, default(CancellationToken));
				logger.LogInfo((object)"Connected to Intiface!");
				await client.StartScanningAsync(default(CancellationToken));
			}
			catch
			{
				logger.LogError((object)"Could not connect to Intiface");
				client = null;
			}
		}

		public async Task DisconnectAsync()
		{
			reconnecting = false;
			if (!IsConnected)
			{
				return;
			}
			try
			{
				try
				{
					await client.StopScanningAsync(default(CancellationToken)).ConfigureAwait(continueOnCapturedContext: false);
				}
				catch
				{
				}
				try
				{
					await client.StopAllDevicesAsync(default(CancellationToken)).ConfigureAwait(continueOnCapturedContext: false);
				}
				catch
				{
				}
				await client.DisconnectAsync().ConfigureAwait(continueOnCapturedContext: false);
				logger.LogInfo((object)"Disconnected from Intiface.");
			}
			catch (Exception ex)
			{
				Exception ex2 = ex;
				logger.LogWarning((object)$"Error disconnecting from Intiface: {ex2}");
			}
			finally
			{
				client = null;
			}
		}

		private void OnDeviceAdded(object sender, DeviceAddedEventArgs args)
		{
			logger.LogInfo((object)("Device connected: " + args.Device.Name));
		}

		private void OnDeviceRemoved(object sender, DeviceRemovedEventArgs args)
		{
			logger.LogInfo((object)("Device disconnected: " + args.Device.Name));
		}
	}
}