Decompiled source of RumbleRain v0.4.2

plugins/RumbleRain/RumbleRain.dll

Decompiled 5 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Threading;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Buttplug.Client;
using Buttplug.Client.Connectors.WebsocketConnector;
using Buttplug.Core;
using Costura;
using R2API.Utils;
using RiskOfOptions;
using RiskOfOptions.OptionConfigs;
using RiskOfOptions.Options;
using RoR2;
using UnityEngine;
using UnityEngine.Events;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")]
[assembly: AssemblyCompany("RumbleRain")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("RumbleRain")]
[assembly: AssemblyTitle("RumbleRain")]
[assembly: AssemblyVersion("1.0.0.0")]
internal class <Module>
{
	static <Module>()
	{
		AssemblyLoader.Attach();
	}
}
namespace RumbleRain
{
	internal static class ConfigManager
	{
		internal static ConfigFile VibrationConfigFile { get; set; }

		internal static ConfigEntry<string> ServerUri { get; set; }

		internal static ConfigEntry<float> PollingRateSeconds { get; set; }

		internal static ConfigEntry<bool> IsRewardingEnabled { get; set; }

		internal static ConfigEntry<bool> IsPunishingEnabled { get; set; }

		internal static ConfigEntry<bool> IsMinionRewardingEnabled { get; set; }

		internal static ConfigEntry<bool> IsMinionPunishingEnabled { get; set; }

		internal static ConfigEntry<float> DamageDealtBaseVibrationIntensity { get; set; }

		internal static ConfigEntry<float> DamageReceivedBaseVibrationIntensity { get; set; }

		internal static ConfigEntry<float> MaximumVibrationIntensity { get; set; }

		internal static ConfigEntry<float> BaseVibrationDurationSeconds { get; set; }

		internal static ConfigEntry<float> MaximumVibrationDurationSeconds { get; set; }

		internal static ConfigEntry<VibrationInfoProvider.VibrationBehavior> VibrationBehavior { get; set; }

		internal static ConfigEntry<bool> AllowExcessDamage { get; set; }

		internal static ConfigEntry<KeyboardShortcut> ToggleVibrationKeybind { get; set; }

		static ConfigManager()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Expected O, but got Unknown
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Expected O, but got Unknown
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Expected O, but got Unknown
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Expected O, but got Unknown
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Expected O, but got Unknown
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Expected O, but got Unknown
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Expected O, but got Unknown
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Expected O, but got Unknown
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Expected O, but got Unknown
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Expected O, but got Unknown
			//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Expected O, but got Unknown
			//IL_01db: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e5: Expected O, but got Unknown
			//IL_01ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_020a: Unknown result type (might be due to invalid IL or missing references)
			//IL_021a: Expected O, but got Unknown
			//IL_0215: Unknown result type (might be due to invalid IL or missing references)
			//IL_021f: Expected O, but got Unknown
			//IL_024c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0256: Expected O, but got Unknown
			//IL_0260: Unknown result type (might be due to invalid IL or missing references)
			//IL_0265: Unknown result type (might be due to invalid IL or missing references)
			//IL_0270: Unknown result type (might be due to invalid IL or missing references)
			//IL_027b: Unknown result type (might be due to invalid IL or missing references)
			//IL_028b: Expected O, but got Unknown
			//IL_0286: Unknown result type (might be due to invalid IL or missing references)
			//IL_0290: Expected O, but got Unknown
			//IL_02bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c7: Expected O, but got Unknown
			//IL_02d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fc: 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_0340: Unknown result type (might be due to invalid IL or missing references)
			//IL_034a: Expected O, but got Unknown
			//IL_0354: Unknown result type (might be due to invalid IL or missing references)
			//IL_0359: Unknown result type (might be due to invalid IL or missing references)
			//IL_0364: Unknown result type (might be due to invalid IL or missing references)
			//IL_0381: Unknown result type (might be due to invalid IL or missing references)
			//IL_0391: Expected O, but got Unknown
			//IL_038c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0396: Expected O, but got Unknown
			//IL_03c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03cd: Expected O, but got Unknown
			//IL_03d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0402: Expected O, but got Unknown
			//IL_03fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0407: Expected O, but got Unknown
			//IL_0445: Unknown result type (might be due to invalid IL or missing references)
			//IL_044f: Expected O, but got Unknown
			//IL_0473: Unknown result type (might be due to invalid IL or missing references)
			//IL_047d: Expected O, but got Unknown
			//IL_04a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_04bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c5: Expected O, but got Unknown
			VibrationConfigFile = new ConfigFile(Paths.ConfigPath + "\\RumbleRain.cfg", true);
			ModSettingsManager.SetModDescription("Vibrates BPio-capable devices in response to in-game damage events.");
			ServerUri = VibrationConfigFile.Bind<string>("Devices", "Server Uri", "ws://localhost:12345", "URI of the Intiface server.");
			ModSettingsManager.AddOption((BaseOption)new StringInputFieldOption(ServerUri, true));
			PollingRateSeconds = VibrationConfigFile.Bind<float>("Devices", "Polling Rate Seconds", 0.2f, new ConfigDescription("How often to update vibrations.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 3f), Array.Empty<object>()));
			ModSettingsManager.AddOption((BaseOption)new StepSliderOption(PollingRateSeconds, new StepSliderConfig
			{
				min = 0.1f,
				max = 3f,
				increment = 0.1f
			}));
			ModSettingsManager.AddOption((BaseOption)new GenericButtonOption("Connect Devices", "Devices", "Attempts to connect to the Intiface server.", "Connect", (UnityAction)delegate
			{
				RumbleRain.DeviceManager.ConnectDevices();
			}));
			IsRewardingEnabled = VibrationConfigFile.Bind<bool>("Activated By", "Dealing Damage", false, "Receive vibrations when dealing damage.");
			ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(IsRewardingEnabled));
			IsPunishingEnabled = VibrationConfigFile.Bind<bool>("Activated By", "Receiving Damage", true, "Receive vibrations when receiving damage.");
			ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(IsPunishingEnabled));
			IsMinionRewardingEnabled = VibrationConfigFile.Bind<bool>("Activated By", "Minions Dealing Damage", false, "Receive vibrations when your minions (drones, turrets, etc.) deal damage.");
			ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(IsMinionRewardingEnabled));
			IsMinionPunishingEnabled = VibrationConfigFile.Bind<bool>("Activated By", "Minions Receiving Damage", false, "Receive vibrations when your minions (drones, turrets, etc.) receive damage.");
			ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(IsMinionPunishingEnabled));
			DamageDealtBaseVibrationIntensity = VibrationConfigFile.Bind<float>("Vibration Values", "Damage Dealt Base Vibration Intensity", 0.05f, new ConfigDescription("Base vibration intensity percentage for vibrations generated by dealing damage. Multiplied by (damageDealt / maxHealthOfDamagedEntity).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			ModSettingsManager.AddOption((BaseOption)new StepSliderOption(DamageDealtBaseVibrationIntensity, new StepSliderConfig
			{
				min = 0f,
				max = 1f,
				increment = 0.01f
			}));
			DamageReceivedBaseVibrationIntensity = VibrationConfigFile.Bind<float>("Vibration Values", "Damage Received Base Vibration Intensity", 1f, new ConfigDescription("Base vibration intensity percentage for vibrations generated by receiving damage. Multiplied by (damageDealt / maxHealthOfDamagedEntity).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			ModSettingsManager.AddOption((BaseOption)new StepSliderOption(DamageReceivedBaseVibrationIntensity, new StepSliderConfig
			{
				min = 0f,
				max = 1f,
				increment = 0.01f
			}));
			MaximumVibrationIntensity = VibrationConfigFile.Bind<float>("Vibration Values", "Maximum Vibration Intensity", 1f, new ConfigDescription("Max percentage of total vibration intensity expressed as a decimal.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			ModSettingsManager.AddOption((BaseOption)new StepSliderOption(MaximumVibrationIntensity, new StepSliderConfig
			{
				min = 0f,
				max = 1f,
				increment = 0.01f
			}));
			MaximumVibrationDurationSeconds = VibrationConfigFile.Bind<float>("Vibration Values", "Maximum Vibration Duration Seconds", 20f, new ConfigDescription("The longest amount of seconds vibrations will last for assuming no new vibrations are generated.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, (float)TimeSpan.FromMinutes(5.0).TotalSeconds), Array.Empty<object>()));
			ModSettingsManager.AddOption((BaseOption)new StepSliderOption(MaximumVibrationDurationSeconds, new StepSliderConfig
			{
				min = 0f,
				max = (float)TimeSpan.FromMinutes(5.0).TotalSeconds,
				increment = 0.5f
			}));
			BaseVibrationDurationSeconds = VibrationConfigFile.Bind<float>("Vibration Values", "Base Vibration Duration Seconds", 5f, new ConfigDescription("The base vibration duration in seconds to add when damage is dealt or received. Multiplied by (damageDealt / maxHealthOfDamagedEntity).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>()));
			ModSettingsManager.AddOption((BaseOption)new StepSliderOption(BaseVibrationDurationSeconds, new StepSliderConfig
			{
				min = 0f,
				max = 100f,
				increment = 0.5f
			}));
			VibrationBehavior = VibrationConfigFile.Bind<VibrationInfoProvider.VibrationBehavior>("Vibration Behavior", "Vibration Behavior", VibrationInfoProvider.VibrationBehavior.AdditiveWithLinearDecay, "How vibrations should handle new information and evolve over time.");
			VibrationBehavior.SettingChanged += delegate
			{
				RumbleRain.DeviceManager.InfoProvider = VibrationInfoProvider.From(VibrationBehavior.Value);
			};
			ModSettingsManager.AddOption((BaseOption)new ChoiceOption((ConfigEntryBase)(object)VibrationBehavior));
			AllowExcessDamage = VibrationConfigFile.Bind<bool>("Vibration Behavior", "Allow For Excess Damage", false, "Allow for excess damage dealt over an entity's max combined health to affect vibrations.");
			ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(AllowExcessDamage));
			ConfigFile vibrationConfigFile = VibrationConfigFile;
			KeyCode[] array = new KeyCode[3];
			RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/);
			ToggleVibrationKeybind = vibrationConfigFile.Bind<KeyboardShortcut>("Keybinds", "Toggle Devices", new KeyboardShortcut((KeyCode)306, (KeyCode[])(object)array), "This keybind will toggle devices to be active or not. See the Properties section at https://docs.unity3d.com/ScriptReference/KeyCode.html for expected values.");
			ModSettingsManager.AddOption((BaseOption)new KeyBindOption(ToggleVibrationKeybind));
		}
	}
	internal class DeviceManager
	{
		private enum DeviceState
		{
			Active,
			Inactive,
			Paused
		}

		private DeviceState _state;

		private VibrationInfoProvider _infoProvider;

		private DeviceState State
		{
			get
			{
				return _state;
			}
			set
			{
				_state = value;
			}
		}

		private ButtplugClient ButtplugClient { get; set; }

		private List<ButtplugClientDevice> ConnectedDevices { get; set; }

		internal VibrationInfoProvider InfoProvider
		{
			get
			{
				return _infoProvider;
			}
			set
			{
				StopConnectedDevices();
				_infoProvider = value;
			}
		}

		public DeviceManager(VibrationInfoProvider vibrationInfoProvider, string clientName)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected O, but got Unknown
			State = DeviceState.Inactive;
			ConnectedDevices = new List<ButtplugClientDevice>();
			ButtplugClient = new ButtplugClient(clientName);
			Log.Info("BP client created for " + clientName);
			ButtplugClient.DeviceAdded += HandleDeviceAdded;
			ButtplugClient.DeviceRemoved += HandleDeviceRemoved;
			InfoProvider = vibrationInfoProvider;
		}

		public async void ConnectDevices()
		{
			if (ButtplugClient.Connected)
			{
				return;
			}
			try
			{
				Log.Info("Attempting to connect to Intiface server at \"" + ConfigManager.ServerUri.Value + "\"");
				await ButtplugClient.ConnectAsync((IButtplugClientConnector)new ButtplugWebsocketConnector(new Uri(ConfigManager.ServerUri.Value)), default(CancellationToken));
				Log.Info("Connection successful. Beginning scan for devices");
				await ButtplugClient.StartScanningAsync(default(CancellationToken));
			}
			catch (ButtplugException)
			{
				Log.Error("Attempt to connect to devices failed. Ensure Intiface is running and attempt to reconnect from the 'Devices' section in the mod's in-game settings.");
			}
		}

		internal IEnumerator PollVibrations()
		{
			Log.Info($"Beginning polling every {ConfigManager.PollingRateSeconds.Value} seconds");
			while (true)
			{
				float secondsToWaitFor = ConfigManager.PollingRateSeconds.Value;
				yield return (object)new WaitForSeconds(secondsToWaitFor);
				if (ButtplugClient.Connected && State == DeviceState.Active)
				{
					if (InfoProvider.Info.IsImpotent() && State == DeviceState.Active)
					{
						StopConnectedDevices();
						continue;
					}
					InfoProvider.UpdateVibrationInfo(TimeSpan.FromSeconds(secondsToWaitFor));
					VibrateConnectedDevices(InfoProvider.Info.Intensity);
				}
			}
		}

		internal void SendVibrationInfo(VibrationInfo vibrationInfo)
		{
			if (State != DeviceState.Paused)
			{
				InfoProvider.Input(vibrationInfo);
				VibrateConnectedDevices(InfoProvider.Info.Intensity);
			}
		}

		private void VibrateConnectedDevices(double intensity)
		{
			State = DeviceState.Active;
			ConnectedDevices.ForEach(async delegate(ButtplugClientDevice device)
			{
				await device.VibrateAsync(intensity);
			});
		}

		private void StopConnectedDevices(DeviceState newState = DeviceState.Inactive)
		{
			if (newState == DeviceState.Active)
			{
				throw new ArgumentException(string.Format("{0}={1} is invalid. Expecting {2} or {3}.", "newState", newState, DeviceState.Inactive, DeviceState.Active));
			}
			State = newState;
			ConnectedDevices.ForEach(async delegate(ButtplugClientDevice device)
			{
				await device.Stop();
			});
		}

		internal void ToggleConnectedDevices()
		{
			switch (State)
			{
			case DeviceState.Active:
			case DeviceState.Inactive:
				StopConnectedDevices(DeviceState.Paused);
				break;
			case DeviceState.Paused:
				VibrateConnectedDevices(InfoProvider.Info.Intensity);
				break;
			}
		}

		internal void CleanUp()
		{
			StopConnectedDevices();
			InfoProvider.Reset();
		}

		private void HandleDeviceAdded(object sender, DeviceAddedEventArgs args)
		{
			if (!IsVibratableDevice(args.Device))
			{
				Log.Info(args.Device.Name + " was detected but ignored due to it not being vibratable.");
				return;
			}
			Log.Info(args.Device.Name + " connected to client " + ButtplugClient.Name);
			ConnectedDevices.Add(args.Device);
		}

		private void HandleDeviceRemoved(object sender, DeviceRemovedEventArgs args)
		{
			if (IsVibratableDevice(args.Device))
			{
				Log.Info(args.Device.Name + " disconnected from client " + ButtplugClient.Name);
				ConnectedDevices.Remove(args.Device);
			}
		}

		private bool IsVibratableDevice(ButtplugClientDevice device)
		{
			return device.VibrateAttributes.Count > 0;
		}
	}
	internal static class Log
	{
		private static ManualLogSource Logger { get; set; }

		internal static void Init(ManualLogSource logger)
		{
			Logger = logger;
		}

		[Conditional("DEBUG")]
		internal static void Debug(object data)
		{
			Logger.LogDebug(data);
		}

		internal static void Info(object data)
		{
			Logger.LogInfo(data);
		}

		internal static void Message(object data)
		{
			Logger.LogMessage(data);
		}

		internal static void Warning(object data)
		{
			Logger.LogWarning(data);
		}

		internal static void Error(object data)
		{
			Logger.LogError(data);
		}

		internal static void Fatal(object data)
		{
			Logger.LogFatal(data);
		}
	}
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("quasikyo.RumbleRain", "RumbleRain", "0.4.2")]
	public class RumbleRain : BaseUnityPlugin
	{
		public const string PluginGUID = "quasikyo.RumbleRain";

		public const string PluginAuthor = "quasikyo";

		public const string PluginName = "RumbleRain";

		public const string PluginVersion = "0.4.2";

		internal static DeviceManager DeviceManager { get; private set; }

		public void Awake()
		{
			Log.Init(((BaseUnityPlugin)this).Logger);
			Log.Info("Performing setup for $RumbleRain");
			DeviceManager = new DeviceManager(VibrationInfoProvider.From(ConfigManager.VibrationBehavior.Value), "RumbleRain");
			DeviceManager.ConnectDevices();
			Run.onRunStartGlobal += delegate
			{
				((MonoBehaviour)this).StartCoroutine(DeviceManager.PollVibrations());
			};
			Run.onRunDestroyGlobal += delegate
			{
				((MonoBehaviour)this).StopAllCoroutines();
				DeviceManager.CleanUp();
			};
			GlobalEventManager.onClientDamageNotified += VibrateDevicesOnDamage;
		}

		public void Update()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			KeyboardShortcut value = ConfigManager.ToggleVibrationKeybind.Value;
			if (((KeyboardShortcut)(ref value)).IsDown())
			{
				DeviceManager.ToggleConnectedDevices();
			}
		}

		private void VibrateDevicesOnDamage(DamageDealtMessage damageMessage)
		{
			CharacterMaster cachedMaster = LocalUserManager.GetFirstLocalUser().cachedMaster;
			CharacterBody body = cachedMaster.GetBody();
			GameObject victim = damageMessage.victim;
			CharacterBody val = ((victim != null) ? victim.GetComponent<CharacterBody>() : null);
			GameObject attacker = damageMessage.attacker;
			CharacterBody val2 = ((attacker != null) ? attacker.GetComponent<CharacterBody>() : null);
			if (!((Object)(object)val == (Object)null))
			{
				float fullCombinedHealth = val.healthComponent.fullCombinedHealth;
				float num = damageMessage.damage / fullCombinedHealth;
				if (!ConfigManager.AllowExcessDamage.Value)
				{
					num = Math.Min(num, 1f);
				}
				bool flag = (Object)(object)body == (Object)(object)val2;
				bool num2 = (Object)(object)body == (Object)(object)val;
				object obj;
				if (val2 == null)
				{
					obj = null;
				}
				else
				{
					CharacterMaster master = val2.master;
					obj = ((master != null) ? master.minionOwnership.ownerMaster : null);
				}
				bool flag2 = (Object)obj == (Object)(object)cachedMaster;
				CharacterMaster master2 = val.master;
				bool flag3 = (Object)(object)((master2 != null) ? master2.minionOwnership.ownerMaster : null) == (Object)(object)cachedMaster;
				VibrationInfo vibrationInfo = new VibrationInfo(TimeSpan.FromSeconds((double)ConfigManager.BaseVibrationDurationSeconds.Value * (double)num));
				if ((flag && ConfigManager.IsRewardingEnabled.Value) || (flag2 && ConfigManager.IsMinionRewardingEnabled.Value))
				{
					vibrationInfo.Intensity = ConfigManager.DamageDealtBaseVibrationIntensity.Value * num;
					DeviceManager.SendVibrationInfo(vibrationInfo);
				}
				if ((num2 && ConfigManager.IsPunishingEnabled.Value) || (flag3 && ConfigManager.IsMinionPunishingEnabled.Value))
				{
					vibrationInfo.Intensity = ConfigManager.DamageReceivedBaseVibrationIntensity.Value * num;
					DeviceManager.SendVibrationInfo(vibrationInfo);
				}
			}
		}
	}
	internal class VibrationInfo
	{
		private double _intensity;

		private TimeSpan _duration;

		private double _intensitySnapshot;

		private TimeSpan _durationSnapshot;

		protected internal double Intensity
		{
			get
			{
				return _intensity;
			}
			set
			{
				_intensity = Clamp(value, 0.0, ConfigManager.MaximumVibrationIntensity.Value);
			}
		}

		protected internal TimeSpan Duration
		{
			get
			{
				return _duration;
			}
			set
			{
				_duration = Clamp(value, TimeSpan.Zero, TimeSpan.FromSeconds(ConfigManager.MaximumVibrationDurationSeconds.Value));
			}
		}

		protected internal double IntensitySnapshot
		{
			get
			{
				return _intensitySnapshot;
			}
			set
			{
				_intensitySnapshot = Clamp(value, 0.0, ConfigManager.MaximumVibrationIntensity.Value);
			}
		}

		protected internal TimeSpan DurationSnapshot
		{
			get
			{
				return _durationSnapshot;
			}
			set
			{
				_durationSnapshot = Clamp(value, TimeSpan.Zero, TimeSpan.FromSeconds(ConfigManager.MaximumVibrationDurationSeconds.Value));
			}
		}

		internal VibrationInfo()
			: this(0.0, TimeSpan.Zero)
		{
		}

		internal VibrationInfo(double intensity)
			: this(intensity, TimeSpan.Zero)
		{
		}

		internal VibrationInfo(TimeSpan duration)
			: this(0.0, duration)
		{
		}

		internal VibrationInfo(double intensity, TimeSpan duration)
		{
			Intensity = intensity;
			Duration = duration;
			SnapshotValues();
		}

		private T Clamp<T>(T value, T inclusiveMinimum, T inclusiveMaximum) where T : IComparable<T>
		{
			if (value.CompareTo(inclusiveMinimum) < 0)
			{
				return inclusiveMinimum;
			}
			if (value.CompareTo(inclusiveMaximum) > 0)
			{
				return inclusiveMaximum;
			}
			return value;
		}

		public static VibrationInfo operator +(VibrationInfo a, VibrationInfo b)
		{
			return new VibrationInfo(a.Intensity + b.Intensity, a.Duration + b.Duration);
		}

		protected internal void SnapshotValues()
		{
			IntensitySnapshot = Intensity;
			DurationSnapshot = Duration;
		}

		protected internal bool IsImpotent()
		{
			if (!(Intensity <= 0.0))
			{
				return Duration <= TimeSpan.Zero;
			}
			return true;
		}

		public override string ToString()
		{
			return $"{base.ToString()}(intensity={Intensity}, duration={Duration.TotalSeconds} seconds)";
		}
	}
	internal abstract class VibrationInfoProvider
	{
		internal enum VibrationBehavior
		{
			AdditiveWithLinearDecay,
			AdditiveWithExponentialDecay
		}

		protected internal VibrationInfo Info { get; set; }

		protected internal VibrationInfoProvider()
		{
			Info = new VibrationInfo();
		}

		protected internal static VibrationInfoProvider From(VibrationBehavior vibrationBehavior)
		{
			return vibrationBehavior switch
			{
				VibrationBehavior.AdditiveWithLinearDecay => new AdditiveInfoProviderWithLinearDecay(), 
				VibrationBehavior.AdditiveWithExponentialDecay => new AdditiveInfoProvierWithExponentialDecay(), 
				_ => throw new ArgumentException($"{vibrationBehavior} is not a valid behavior."), 
			};
		}

		protected internal abstract void Input(VibrationInfo newVibrationInfo);

		protected internal abstract void UpdateVibrationInfo(TimeSpan timeSinceLastUpdate);

		protected internal virtual void Reset()
		{
			Info = new VibrationInfo();
		}
	}
	internal class AdditiveInfoProviderWithLinearDecay : VibrationInfoProvider
	{
		protected internal override void Input(VibrationInfo newVibrationInfo)
		{
			base.Info += newVibrationInfo;
			base.Info.SnapshotValues();
		}

		protected internal override void UpdateVibrationInfo(TimeSpan timeSinceLastUpdate)
		{
			base.Info.Duration -= timeSinceLastUpdate;
			double num = base.Info.Duration.TotalSeconds / base.Info.DurationSnapshot.TotalSeconds;
			base.Info.Intensity = base.Info.IntensitySnapshot * num;
		}
	}
	internal class AdditiveInfoProvierWithExponentialDecay : VibrationInfoProvider
	{
		protected internal override void Input(VibrationInfo newVibrationInfo)
		{
			base.Info += newVibrationInfo;
			base.Info.SnapshotValues();
		}

		protected internal override void UpdateVibrationInfo(TimeSpan timeSinceLastUpdate)
		{
			base.Info.Duration -= timeSinceLastUpdate;
			double num = base.Info.Duration.TotalSeconds / base.Info.DurationSnapshot.TotalSeconds;
			base.Info.Intensity *= num;
		}
	}
}
namespace Costura
{
	[CompilerGenerated]
	internal static class AssemblyLoader
	{
		private static object nullCacheLock = new object();

		private static Dictionary<string, bool> nullCache = new Dictionary<string, bool>();

		private static Dictionary<string, string> assemblyNames = new Dictionary<string, string>();

		private static Dictionary<string, string> symbolNames = new Dictionary<string, string>();

		private static int isAttached;

		private static string CultureToString(CultureInfo culture)
		{
			if (culture == null)
			{
				return "";
			}
			return culture.Name;
		}

		private static Assembly ReadExistingAssembly(AssemblyName name)
		{
			AppDomain currentDomain = AppDomain.CurrentDomain;
			Assembly[] assemblies = currentDomain.GetAssemblies();
			Assembly[] array = assemblies;
			foreach (Assembly assembly in array)
			{
				AssemblyName name2 = assembly.GetName();
				if (string.Equals(name2.Name, name.Name, StringComparison.InvariantCultureIgnoreCase) && string.Equals(CultureToString(name2.CultureInfo), CultureToString(name.CultureInfo), StringComparison.InvariantCultureIgnoreCase))
				{
					return assembly;
				}
			}
			return null;
		}

		private static void CopyTo(Stream source, Stream destination)
		{
			byte[] array = new byte[81920];
			int count;
			while ((count = source.Read(array, 0, array.Length)) != 0)
			{
				destination.Write(array, 0, count);
			}
		}

		private static Stream LoadStream(string fullName)
		{
			Assembly executingAssembly = Assembly.GetExecutingAssembly();
			if (fullName.EndsWith(".compressed"))
			{
				using (Stream stream = executingAssembly.GetManifestResourceStream(fullName))
				{
					using DeflateStream source = new DeflateStream(stream, CompressionMode.Decompress);
					MemoryStream memoryStream = new MemoryStream();
					CopyTo(source, memoryStream);
					memoryStream.Position = 0L;
					return memoryStream;
				}
			}
			return executingAssembly.GetManifestResourceStream(fullName);
		}

		private static Stream LoadStream(Dictionary<string, string> resourceNames, string name)
		{
			if (resourceNames.TryGetValue(name, out var value))
			{
				return LoadStream(value);
			}
			return null;
		}

		private static byte[] ReadStream(Stream stream)
		{
			byte[] array = new byte[stream.Length];
			stream.Read(array, 0, array.Length);
			return array;
		}

		private static Assembly ReadFromEmbeddedResources(Dictionary<string, string> assemblyNames, Dictionary<string, string> symbolNames, AssemblyName requestedAssemblyName)
		{
			string text = requestedAssemblyName.Name.ToLowerInvariant();
			if (requestedAssemblyName.CultureInfo != null && !string.IsNullOrEmpty(requestedAssemblyName.CultureInfo.Name))
			{
				text = requestedAssemblyName.CultureInfo.Name + "." + text;
			}
			byte[] rawAssembly;
			using (Stream stream = LoadStream(assemblyNames, text))
			{
				if (stream == null)
				{
					return null;
				}
				rawAssembly = ReadStream(stream);
			}
			using (Stream stream2 = LoadStream(symbolNames, text))
			{
				if (stream2 != null)
				{
					byte[] rawSymbolStore = ReadStream(stream2);
					return Assembly.Load(rawAssembly, rawSymbolStore);
				}
			}
			return Assembly.Load(rawAssembly);
		}

		public static Assembly ResolveAssembly(object sender, ResolveEventArgs e)
		{
			lock (nullCacheLock)
			{
				if (nullCache.ContainsKey(e.Name))
				{
					return null;
				}
			}
			AssemblyName assemblyName = new AssemblyName(e.Name);
			Assembly assembly = ReadExistingAssembly(assemblyName);
			if ((object)assembly != null)
			{
				return assembly;
			}
			assembly = ReadFromEmbeddedResources(assemblyNames, symbolNames, assemblyName);
			if ((object)assembly == null)
			{
				lock (nullCacheLock)
				{
					nullCache[e.Name] = true;
				}
				if ((assemblyName.Flags & AssemblyNameFlags.Retargetable) != 0)
				{
					assembly = Assembly.Load(assemblyName);
				}
			}
			return assembly;
		}

		static AssemblyLoader()
		{
			assemblyNames.Add("buttplug.client.connectors.websocketconnector", "costura.buttplug.client.connectors.websocketconnector.dll.compressed");
			assemblyNames.Add("buttplug", "costura.buttplug.dll.compressed");
			assemblyNames.Add("deniszykov.websocketlistener", "costura.deniszykov.websocketlistener.dll.compressed");
			assemblyNames.Add("system.appcontext", "costura.system.appcontext.dll.compressed");
			assemblyNames.Add("system.collections.concurrent", "costura.system.collections.concurrent.dll.compressed");
			assemblyNames.Add("system.collections", "costura.system.collections.dll.compressed");
			assemblyNames.Add("system.collections.nongeneric", "costura.system.collections.nongeneric.dll.compressed");
			assemblyNames.Add("system.collections.specialized", "costura.system.collections.specialized.dll.compressed");
			assemblyNames.Add("system.componentmodel.composition", "costura.system.componentmodel.composition.dll.compressed");
			assemblyNames.Add("system.componentmodel", "costura.system.componentmodel.dll.compressed");
			assemblyNames.Add("system.componentmodel.eventbasedasync", "costura.system.componentmodel.eventbasedasync.dll.compressed");
			assemblyNames.Add("system.componentmodel.primitives", "costura.system.componentmodel.primitives.dll.compressed");
			assemblyNames.Add("system.componentmodel.typeconverter", "costura.system.componentmodel.typeconverter.dll.compressed");
			assemblyNames.Add("system.console", "costura.system.console.dll.compressed");
			assemblyNames.Add("system.core", "costura.system.core.dll.compressed");
			assemblyNames.Add("system.data.common", "costura.system.data.common.dll.compressed");
			assemblyNames.Add("system.data", "costura.system.data.dll.compressed");
			assemblyNames.Add("system.diagnostics.contracts", "costura.system.diagnostics.contracts.dll.compressed");
			assemblyNames.Add("system.diagnostics.debug", "costura.system.diagnostics.debug.dll.compressed");
			assemblyNames.Add("system.diagnostics.fileversioninfo", "costura.system.diagnostics.fileversioninfo.dll.compressed");
			assemblyNames.Add("system.diagnostics.process", "costura.system.diagnostics.process.dll.compressed");
			assemblyNames.Add("system.diagnostics.stacktrace", "costura.system.diagnostics.stacktrace.dll.compressed");
			assemblyNames.Add("system.diagnostics.textwritertracelistener", "costura.system.diagnostics.textwritertracelistener.dll.compressed");
			assemblyNames.Add("system.diagnostics.tools", "costura.system.diagnostics.tools.dll.compressed");
			assemblyNames.Add("system.diagnostics.tracesource", "costura.system.diagnostics.tracesource.dll.compressed");
			assemblyNames.Add("system.diagnostics.tracing", "costura.system.diagnostics.tracing.dll.compressed");
			assemblyNames.Add("system.drawing", "costura.system.drawing.dll.compressed");
			assemblyNames.Add("system.drawing.primitives", "costura.system.drawing.primitives.dll.compressed");
			assemblyNames.Add("system.dynamic.runtime", "costura.system.dynamic.runtime.dll.compressed");
			assemblyNames.Add("system.globalization.calendars", "costura.system.globalization.calendars.dll.compressed");
			assemblyNames.Add("system.globalization", "costura.system.globalization.dll.compressed");
			assemblyNames.Add("system.globalization.extensions", "costura.system.globalization.extensions.dll.compressed");
			assemblyNames.Add("system.io.compression", "costura.system.io.compression.dll.compressed");
			assemblyNames.Add("system.io.compression.filesystem", "costura.system.io.compression.filesystem.dll.compressed");
			assemblyNames.Add("system.io.compression.zipfile", "costura.system.io.compression.zipfile.dll.compressed");
			assemblyNames.Add("system.io", "costura.system.io.dll.compressed");
			assemblyNames.Add("system.io.filesystem", "costura.system.io.filesystem.dll.compressed");
			assemblyNames.Add("system.io.filesystem.driveinfo", "costura.system.io.filesystem.driveinfo.dll.compressed");
			assemblyNames.Add("system.io.filesystem.primitives", "costura.system.io.filesystem.primitives.dll.compressed");
			assemblyNames.Add("system.io.filesystem.watcher", "costura.system.io.filesystem.watcher.dll.compressed");
			assemblyNames.Add("system.io.isolatedstorage", "costura.system.io.isolatedstorage.dll.compressed");
			assemblyNames.Add("system.io.memorymappedfiles", "costura.system.io.memorymappedfiles.dll.compressed");
			assemblyNames.Add("system.io.pipes", "costura.system.io.pipes.dll.compressed");
			assemblyNames.Add("system.io.unmanagedmemorystream", "costura.system.io.unmanagedmemorystream.dll.compressed");
			assemblyNames.Add("system.linq", "costura.system.linq.dll.compressed");
			assemblyNames.Add("system.linq.expressions", "costura.system.linq.expressions.dll.compressed");
			assemblyNames.Add("system.linq.parallel", "costura.system.linq.parallel.dll.compressed");
			assemblyNames.Add("system.linq.queryable", "costura.system.linq.queryable.dll.compressed");
			assemblyNames.Add("system.net", "costura.system.net.dll.compressed");
			assemblyNames.Add("system.net.http", "costura.system.net.http.dll.compressed");
			assemblyNames.Add("system.net.nameresolution", "costura.system.net.nameresolution.dll.compressed");
			assemblyNames.Add("system.net.networkinformation", "costura.system.net.networkinformation.dll.compressed");
			assemblyNames.Add("system.net.ping", "costura.system.net.ping.dll.compressed");
			assemblyNames.Add("system.net.primitives", "costura.system.net.primitives.dll.compressed");
			assemblyNames.Add("system.net.requests", "costura.system.net.requests.dll.compressed");
			assemblyNames.Add("system.net.security", "costura.system.net.security.dll.compressed");
			assemblyNames.Add("system.net.sockets", "costura.system.net.sockets.dll.compressed");
			assemblyNames.Add("system.net.webheadercollection", "costura.system.net.webheadercollection.dll.compressed");
			assemblyNames.Add("system.net.websockets.client", "costura.system.net.websockets.client.dll.compressed");
			assemblyNames.Add("system.net.websockets", "costura.system.net.websockets.dll.compressed");
			assemblyNames.Add("system.numerics", "costura.system.numerics.dll.compressed");
			assemblyNames.Add("system.objectmodel", "costura.system.objectmodel.dll.compressed");
			assemblyNames.Add("system.reflection", "costura.system.reflection.dll.compressed");
			assemblyNames.Add("system.reflection.emit", "costura.system.reflection.emit.dll.compressed");
			assemblyNames.Add("system.reflection.emit.ilgeneration", "costura.system.reflection.emit.ilgeneration.dll.compressed");
			assemblyNames.Add("system.reflection.emit.lightweight", "costura.system.reflection.emit.lightweight.dll.compressed");
			assemblyNames.Add("system.reflection.extensions", "costura.system.reflection.extensions.dll.compressed");
			assemblyNames.Add("system.reflection.primitives", "costura.system.reflection.primitives.dll.compressed");
			assemblyNames.Add("system.reflection.typeextensions", "costura.system.reflection.typeextensions.dll.compressed");
			assemblyNames.Add("system.resources.reader", "costura.system.resources.reader.dll.compressed");
			assemblyNames.Add("system.resources.resourcemanager", "costura.system.resources.resourcemanager.dll.compressed");
			assemblyNames.Add("system.resources.writer", "costura.system.resources.writer.dll.compressed");
			assemblyNames.Add("system.runtime.compilerservices.unsafe", "costura.system.runtime.compilerservices.unsafe.dll.compressed");
			assemblyNames.Add("system.runtime.compilerservices.visualc", "costura.system.runtime.compilerservices.visualc.dll.compressed");
			assemblyNames.Add("system.runtime", "costura.system.runtime.dll.compressed");
			assemblyNames.Add("system.runtime.extensions", "costura.system.runtime.extensions.dll.compressed");
			assemblyNames.Add("system.runtime.handles", "costura.system.runtime.handles.dll.compressed");
			assemblyNames.Add("system.runtime.interopservices", "costura.system.runtime.interopservices.dll.compressed");
			assemblyNames.Add("system.runtime.interopservices.runtimeinformation", "costura.system.runtime.interopservices.runtimeinformation.dll.compressed");
			assemblyNames.Add("system.runtime.numerics", "costura.system.runtime.numerics.dll.compressed");
			assemblyNames.Add("system.runtime.serialization", "costura.system.runtime.serialization.dll.compressed");
			assemblyNames.Add("system.runtime.serialization.formatters", "costura.system.runtime.serialization.formatters.dll.compressed");
			assemblyNames.Add("system.runtime.serialization.json", "costura.system.runtime.serialization.json.dll.compressed");
			assemblyNames.Add("system.runtime.serialization.primitives", "costura.system.runtime.serialization.primitives.dll.compressed");
			assemblyNames.Add("system.runtime.serialization.xml", "costura.system.runtime.serialization.xml.dll.compressed");
			assemblyNames.Add("system.security.claims", "costura.system.security.claims.dll.compressed");
			assemblyNames.Add("system.security.cryptography.algorithms", "costura.system.security.cryptography.algorithms.dll.compressed");
			assemblyNames.Add("system.security.cryptography.csp", "costura.system.security.cryptography.csp.dll.compressed");
			assemblyNames.Add("system.security.cryptography.encoding", "costura.system.security.cryptography.encoding.dll.compressed");
			assemblyNames.Add("system.security.cryptography.primitives", "costura.system.security.cryptography.primitives.dll.compressed");
			assemblyNames.Add("system.security.cryptography.x509certificates", "costura.system.security.cryptography.x509certificates.dll.compressed");
			assemblyNames.Add("system.security.principal", "costura.system.security.principal.dll.compressed");
			assemblyNames.Add("system.security.securestring", "costura.system.security.securestring.dll.compressed");
			assemblyNames.Add("system.servicemodel.web", "costura.system.servicemodel.web.dll.compressed");
			assemblyNames.Add("system.text.encoding", "costura.system.text.encoding.dll.compressed");
			assemblyNames.Add("system.text.encoding.extensions", "costura.system.text.encoding.extensions.dll.compressed");
			assemblyNames.Add("system.text.regularexpressions", "costura.system.text.regularexpressions.dll.compressed");
			assemblyNames.Add("system.threading.channels", "costura.system.threading.channels.dll.compressed");
			assemblyNames.Add("system.threading", "costura.system.threading.dll.compressed");
			assemblyNames.Add("system.threading.overlapped", "costura.system.threading.overlapped.dll.compressed");
			assemblyNames.Add("system.threading.tasks", "costura.system.threading.tasks.dll.compressed");
			assemblyNames.Add("system.threading.tasks.extensions", "costura.system.threading.tasks.extensions.dll.compressed");
			assemblyNames.Add("system.threading.tasks.parallel", "costura.system.threading.tasks.parallel.dll.compressed");
			assemblyNames.Add("system.threading.thread", "costura.system.threading.thread.dll.compressed");
			assemblyNames.Add("system.threading.threadpool", "costura.system.threading.threadpool.dll.compressed");
			assemblyNames.Add("system.threading.timer", "costura.system.threading.timer.dll.compressed");
			assemblyNames.Add("system.transactions", "costura.system.transactions.dll.compressed");
			assemblyNames.Add("system.valuetuple", "costura.system.valuetuple.dll.compressed");
			assemblyNames.Add("system.web", "costura.system.web.dll.compressed");
			assemblyNames.Add("system.windows", "costura.system.windows.dll.compressed");
			assemblyNames.Add("system.xml", "costura.system.xml.dll.compressed");
			assemblyNames.Add("system.xml.linq", "costura.system.xml.linq.dll.compressed");
			assemblyNames.Add("system.xml.readerwriter", "costura.system.xml.readerwriter.dll.compressed");
			assemblyNames.Add("system.xml.serialization", "costura.system.xml.serialization.dll.compressed");
			assemblyNames.Add("system.xml.xdocument", "costura.system.xml.xdocument.dll.compressed");
			assemblyNames.Add("system.xml.xmldocument", "costura.system.xml.xmldocument.dll.compressed");
			assemblyNames.Add("system.xml.xmlserializer", "costura.system.xml.xmlserializer.dll.compressed");
			assemblyNames.Add("system.xml.xpath", "costura.system.xml.xpath.dll.compressed");
			assemblyNames.Add("system.xml.xpath.xdocument", "costura.system.xml.xpath.xdocument.dll.compressed");
		}

		public static void Attach()
		{
			if (Interlocked.Exchange(ref isAttached, 1) == 1)
			{
				return;
			}
			AppDomain currentDomain = AppDomain.CurrentDomain;
			currentDomain.AssemblyResolve += delegate(object sender, ResolveEventArgs e)
			{
				lock (nullCacheLock)
				{
					if (nullCache.ContainsKey(e.Name))
					{
						return null;
					}
				}
				AssemblyName assemblyName = new AssemblyName(e.Name);
				Assembly assembly = ReadExistingAssembly(assemblyName);
				if ((object)assembly != null)
				{
					return assembly;
				}
				assembly = ReadFromEmbeddedResources(assemblyNames, symbolNames, assemblyName);
				if ((object)assembly == null)
				{
					lock (nullCacheLock)
					{
						nullCache[e.Name] = true;
					}
					if ((assemblyName.Flags & AssemblyNameFlags.Retargetable) != 0)
					{
						assembly = Assembly.Load(assemblyName);
					}
				}
				return assembly;
			};
		}
	}
}
internal class RumbleRain_ProcessedByFody
{
	internal const string FodyVersion = "6.8.0.0";

	internal const string Costura = "5.7.0";
}