Decompiled source of RiskOfPain v1.0.0

OpenShock.Integrations.RiskOfRain2.dll

Decompiled 8 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using OpenShock.Integrations.LethalCompany.OpenShockApi.Models;
using OpenShock.Integrations.RiskOfRain2.Models;
using OpenShock.Integrations.RiskOfRain2.OpenShockApi;
using OpenShock.Integrations.RiskOfRain2.OpenShockApi.Models;
using OpenShock.Integrations.RiskOfRain2.Utils;
using R2API.Utils;
using RiskOfOptions;
using RiskOfOptions.OptionConfigs;
using RiskOfOptions.Options;
using RoR2;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Networking;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("OpenShock")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+355cc380d68835218893c9cf2267554a7cd2fc6c")]
[assembly: AssemblyProduct("OpenShock.Integrations.RiskOfRain2")]
[assembly: AssemblyTitle("OpenShock.Integrations.RiskOfRain2")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace OpenShock.Integrations.LethalCompany.OpenShockApi.Models
{
	public class ControlRequest
	{
		public IEnumerable<Control> Shocks { get; set; }

		public string? CustomName { get; set; }
	}
	public enum ControlType
	{
		Stop,
		Shock,
		Vibrate,
		Sound
	}
}
namespace OpenShock.Integrations.RiskOfRain2
{
	[BepInPlugin("OpenShock.Integrations.RiskOfRain2", "RiskOfPain", "1.0.0")]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class RiskOfPain : BaseUnityPlugin
	{
		private ConfigEntry<string> _openShockServer;

		private ConfigEntry<string> _openShockApiToken;

		private ConfigEntry<string> _shockers;

		private ConfigEntry<byte> _settingOnDeathIntensity;

		private ConfigEntry<ushort> _settingOnDeathDuration;

		private ConfigEntry<bool> _settingOnDamageEnabled;

		private ConfigEntry<ControlType> _settingOnDamageMode;

		private ConfigEntry<DamageBehaviour> _settingOnDamageBehaviour;

		private ConfigEntry<int> _settingOnDamageDuration;

		private ConfigEntry<int> _settingOnDamageIntensityLimit;

		private Timer _actionTimer;

		private readonly object _receivedDamageLock = new object();

		private float _receivedDamage;

		private CharacterBody? _localUserCharacterBody;

		private OpenShock.Integrations.RiskOfRain2.OpenShockApi.OpenShockApi? _openShockApiClient;

		private IList<Guid> _shockersList;

		public static RiskOfPain Instance { get; private set; }

		public static ManualLogSource ModLogger { get; private set; }

		private void SetupConfiguration()
		{
			_openShockServer = ((BaseUnityPlugin)this).Config.Bind<string>("OpenShock", "Server", "https://api.openshock.app", "The URL of the OpenShock backend");
			_openShockApiToken = ((BaseUnityPlugin)this).Config.Bind<string>("OpenShock", "ApiToken", "", "API token for authentication, can be found under API Tokens on the OpenShock dashboard (https://shocklink.net/#/dashboard/tokens)");
			_shockers = ((BaseUnityPlugin)this).Config.Bind<string>("Shockers", "Shockers", "comma,seperated,list,of,shocker,ids", "A list of shocker IDs to use within the mod. Comma seperated.");
			_settingOnDeathIntensity = ((BaseUnityPlugin)this).Config.Bind<byte>("OnDeath", "Intensity", (byte)25, "The intensity of the shocker when the player dies");
			_settingOnDeathDuration = ((BaseUnityPlugin)this).Config.Bind<ushort>("OnDeath", "Duration", (ushort)1000, "The duration of the shocker when the player dies");
			_settingOnDamageEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("OnDamage", "Enabled", true, "Enables on damage");
			_settingOnDamageMode = ((BaseUnityPlugin)this).Config.Bind<ControlType>("OnDamage", "Mode", ControlType.Shock, "The action that happens when you take damage");
			_settingOnDamageBehaviour = ((BaseUnityPlugin)this).Config.Bind<DamageBehaviour>("OnDamage", "Behaviour", DamageBehaviour.LowHp, "How the intensity is calculated. LowHp = Higher intensity the lower on HP you are; DamagePercentage = Intensity correlates to how much health you have lost of your max HP when damaged. DamageAbsolute = Intensity is equal to how much damage you recevied");
			_settingOnDamageDuration = ((BaseUnityPlugin)this).Config.Bind<int>("OnDamage", "Duration", 100, "The duration of the shocker when the player takes damage");
			_settingOnDamageIntensityLimit = ((BaseUnityPlugin)this).Config.Bind<int>("OnDamage", "IntensityLimit", 25, "Intensity limit for the shocker when the player takes damage");
		}

		private void RegisterConfigEvents()
		{
			_openShockServer.SettingChanged += UpdateApiClient;
			_openShockApiToken.SettingChanged += UpdateApiClient;
			_shockers.SettingChanged += ShockersOnSettingChanged;
		}

		private void UpdateApiClient(object sender, EventArgs e)
		{
			SetupApiClient();
		}

		private void ShockersOnSettingChanged(object sender, EventArgs e)
		{
			SetupShockers();
		}

		private void ActionTimerElapsed(object state)
		{
			try
			{
				OnDamageActionExecute();
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)ex);
			}
		}

		private void OnDamageActionExecute()
		{
			float receivedDamage;
			lock (_receivedDamageLock)
			{
				receivedDamage = _receivedDamage;
				_receivedDamage = 0f;
			}
			byte b = CalculateIntensity(receivedDamage);
			((BaseUnityPlugin)this).Logger.LogDebug((object)$"ActionTimerElapsed - Damage: {receivedDamage:0.00} Intensity: {b}");
			ControlShockersFnf(_settingOnDamageMode.Value, b, (ushort)_settingOnDamageDuration.Value);
		}

		private void ClientOnDamage(DamageDealtMessage damageMessage)
		{
			if (!((Object)(object)_localUserCharacterBody == (Object)null) && !((Object)(object)damageMessage.victim == (Object)null) && !((Object)(object)damageMessage.victim != (Object)(object)((Component)_localUserCharacterBody).gameObject))
			{
				((BaseUnityPlugin)this).Logger.LogDebug((object)$"Player received damage: {damageMessage.damage}");
				lock (_receivedDamageLock)
				{
					_receivedDamage += damageMessage.damage;
				}
				_actionTimer.Change(TimeSpan.FromMilliseconds(50.0), Timeout.InfiniteTimeSpan);
			}
		}

		private byte CalculateIntensity(float damage)
		{
			float fullCombinedHealth = _localUserCharacterBody.healthComponent.fullCombinedHealth;
			float health = _localUserCharacterBody.healthComponent.health;
			DamageBehaviour value = _settingOnDamageBehaviour.Value;
			float value3;
			if ((uint)value <= 1u)
			{
				float value2 = value switch
				{
					DamageBehaviour.LowHp => health / fullCombinedHealth, 
					DamageBehaviour.DamagePercent => damage / fullCombinedHealth, 
					_ => throw new Exception("This is unreachable."), 
				};
				value3 = MathUtils.Lerp(0f, _settingOnDamageIntensityLimit.Value, MathUtils.Saturate(value2));
			}
			else
			{
				value3 = Math.Clamp(damage, 0f, _settingOnDamageIntensityLimit.Value);
			}
			return Convert.ToByte(value3);
		}

		private void OnCharacterBodyStart(CharacterBody characterBody)
		{
			if (characterBody.isPlayerControlled)
			{
				NetworkUser val = Util.LookUpBodyNetworkUser(characterBody);
				if (!((Object)(object)val == (Object)null) && ((NetworkBehaviour)val).isLocalPlayer)
				{
					_localUserCharacterBody = characterBody;
					((BaseUnityPlugin)this).Logger.LogDebug((object)("Local user found. " + val.userName));
				}
			}
		}

		private void OnCharacterBodyDestroy(CharacterBody characterBody)
		{
			if (characterBody.isPlayerControlled && !((Object)(object)_localUserCharacterBody != (Object)(object)characterBody))
			{
				_localUserCharacterBody = null;
				((BaseUnityPlugin)this).Logger.LogDebug((object)"Local user destroyed");
			}
		}

		private void SetupApiClient()
		{
			if (!Uri.TryCreate(_openShockServer.Value, UriKind.Absolute, out Uri result))
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"Unable to parse OpenShock server URL. E.g. https://api.openshock.app");
			}
			else if (string.IsNullOrWhiteSpace(_openShockApiToken.Value))
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"API Token is not configured");
			}
			else
			{
				_openShockApiClient = new OpenShock.Integrations.RiskOfRain2.OpenShockApi.OpenShockApi(result, _openShockApiToken.Value);
			}
		}

		private void SetupShockers()
		{
			List<Guid> list = new List<Guid>();
			string[] array = _shockers.Value.Split(',');
			foreach (string text in array)
			{
				if (Guid.TryParse(text, out var result))
				{
					ManualLogSource logger = ((BaseUnityPlugin)this).Logger;
					Guid guid = result;
					logger.LogInfo((object)("Found shocker ID " + guid));
					list.Add(result);
				}
				else
				{
					((BaseUnityPlugin)this).Logger.LogError((object)("Failed to parse shocker ID " + text));
				}
			}
			_shockersList = list;
		}

		private async Task ControlShockers(ControlType controlType, byte intensity, ushort duration)
		{
			if (_openShockApiClient == null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"OpenShock server or token not configured");
				return;
			}
			((BaseUnityPlugin)this).Logger.LogDebug((object)"Sending control request");
			IEnumerable<Control> shocks = _shockersList.Select((Guid shocker) => new Control
			{
				Id = shocker,
				Duration = duration,
				Intensity = intensity,
				Type = controlType
			});
			await _openShockApiClient.Control(shocks);
			((BaseUnityPlugin)this).Logger.LogDebug((object)"Command sent");
		}

		private void ControlShockersFnf(ControlType controlType, byte intensity, ushort duration)
		{
			LucTask.Run(() => ControlShockers(controlType, intensity, duration), default(CancellationToken), "F:\\Dev\\Git\\OpenShock\\Integrations.RiskOfRain2\\Integrations.RiskOfRain2\\OpenShockLogic.cs", "ControlShockersFnf", 69);
		}

		private void SetupRiskOfOptionsMenu()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Expected O, but got Unknown
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Expected O, but got Unknown
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Expected O, but got Unknown
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Expected O, but got Unknown
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Expected O, but got Unknown
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Expected O, but got Unknown
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Expected O, but got Unknown
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Expected O, but got Unknown
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Expected O, but got Unknown
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: 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
			ModSettingsManager.AddOption((BaseOption)new StringInputFieldOption(_openShockServer));
			ModSettingsManager.AddOption((BaseOption)new StringInputFieldOption(_openShockApiToken, new InputFieldConfig
			{
				submitOn = (SubmitEnum)6
			}));
			ModSettingsManager.AddOption((BaseOption)new StringInputFieldOption(_shockers, new InputFieldConfig
			{
				submitOn = (SubmitEnum)6
			}));
			ModSettingsManager.AddOption((BaseOption)new GenericButtonOption("TestShockers", "OpenShock", "Will vibrate all configured shockers at 25% and 1s", "Test Shockers", (UnityAction)delegate
			{
				ControlShockersFnf(ControlType.Vibrate, 25, 1000);
			}));
			ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(_settingOnDamageEnabled));
			ModSettingsManager.AddOption((BaseOption)new ChoiceOption((ConfigEntryBase)(object)_settingOnDamageMode));
			ModSettingsManager.AddOption((BaseOption)new ChoiceOption((ConfigEntryBase)(object)_settingOnDamageBehaviour));
			ModSettingsManager.AddOption((BaseOption)new IntSliderOption(_settingOnDamageDuration, new IntSliderConfig
			{
				min = 300,
				max = 30000
			}));
			ModSettingsManager.AddOption((BaseOption)new IntSliderOption(_settingOnDamageIntensityLimit, new IntSliderConfig
			{
				min = 1,
				max = 100
			}));
		}

		private void Awake()
		{
			((BaseUnityPlugin)this).Logger.LogDebug((object)"RiskOfPain loading...");
			Instance = this;
			ModLogger = ((BaseUnityPlugin)this).Logger;
			_actionTimer = new Timer(ActionTimerElapsed, null, -1, -1);
			SetupConfiguration();
			RegisterConfigEvents();
			SetupApiClient();
			SetupShockers();
			SetupRiskOfOptionsMenu();
			((BaseUnityPlugin)this).Logger.LogDebug((object)"RiskOfPain loaded");
		}

		private void OnEnable()
		{
			CharacterBody.onBodyStartGlobal += OnCharacterBodyStart;
			CharacterBody.onBodyDestroyGlobal += OnCharacterBodyDestroy;
			GlobalEventManager.onClientDamageNotified += ClientOnDamage;
			((BaseUnityPlugin)this).Logger.LogDebug((object)"Events registered");
		}

		private void OnDisable()
		{
			CharacterBody.onBodyStartGlobal -= OnCharacterBodyStart;
			CharacterBody.onBodyDestroyGlobal -= OnCharacterBodyDestroy;
			GlobalEventManager.onClientDamageNotified -= ClientOnDamage;
			((BaseUnityPlugin)this).Logger.LogDebug((object)"Events unregistered");
		}
	}
	public static class LucTask
	{
		public static Task Run(Func<Task?> function, CancellationToken token = default(CancellationToken), [CallerFilePath] string file = "", [CallerMemberName] string member = "", [CallerLineNumber] int line = -1)
		{
			string file2 = file;
			string member2 = member;
			return Task.Run(function, token).ContinueWith(delegate(Task t)
			{
				if (t.IsFaulted)
				{
					int num = file2.LastIndexOf('\\');
					if (num == -1)
					{
						num = file2.LastIndexOf('/');
					}
					RiskOfPain.ModLogger.LogError((object)$"Error during task execution. {file2.Substring(num + 1, file2.Length - num - 1)}::{member2}:{line} {t.Exception}");
				}
			}, TaskContinuationOptions.OnlyOnFaulted);
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "OpenShock.Integrations.RiskOfRain2";

		public const string PLUGIN_NAME = "OpenShock.Integrations.RiskOfRain2";

		public const string PLUGIN_VERSION = "1.0.0";
	}
}
namespace OpenShock.Integrations.RiskOfRain2.Utils
{
	public class MathUtils
	{
		public static float Lerp(float min, float max, float t)
		{
			return min + (max - min) * t;
		}

		public static float Saturate(float value)
		{
			if (!(value < 0f))
			{
				if (!(value > 1f))
				{
					return value;
				}
				return 1f;
			}
			return 0f;
		}
	}
}
namespace OpenShock.Integrations.RiskOfRain2.OpenShockApi
{
	public class OpenShockApi
	{
		private static readonly ManualLogSource Logger = Logger.CreateLogSource("OpenShockApi");

		private readonly HttpClient _httpClient;

		public OpenShockApi(Uri server, string apiToken)
		{
			_httpClient = new HttpClient
			{
				BaseAddress = server
			};
			_httpClient.DefaultRequestHeaders.Add("User-Agent", "OpenShock.Integrations.RiskOfRain2/1.0.0");
			_httpClient.DefaultRequestHeaders.Add("OpenShockToken", apiToken);
		}

		public async Task Control(IEnumerable<Control> shocks)
		{
			Logger.LogInfo((object)"Sending control request to OpenShock API");
			HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "/2/shockers/control")
			{
				Content = new StringContent(JsonConvert.SerializeObject((object)new ControlRequest
				{
					Shocks = shocks,
					CustomName = "Integrations.RiskOfRain2"
				}), Encoding.UTF8, "application/json")
			};
			HttpResponseMessage httpResponseMessage = await _httpClient.SendAsync(request);
			if (!httpResponseMessage.IsSuccessStatusCode)
			{
				Logger.LogError((object)$"Failed to send control request to OpenShock API [{httpResponseMessage.StatusCode}]");
			}
		}
	}
}
namespace OpenShock.Integrations.RiskOfRain2.OpenShockApi.Models
{
	public class Control
	{
		public Guid Id { get; set; }

		public ControlType Type { get; set; }

		public byte Intensity { get; set; }

		public ushort Duration { get; set; }
	}
}
namespace OpenShock.Integrations.RiskOfRain2.Models
{
	public enum DamageBehaviour
	{
		LowHp,
		DamagePercent,
		DamageAbsolute
	}
}