Some mods may be broken due to the recent Alloyed Collective update.
Decompiled source of RiskOfPain v1.1.0
OpenShock.Integrations.RiskOfRain2.dll
Decompiled 3 weeks agousing 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.1.0")] [assembly: AssemblyInformationalVersion("1.0.0+3412324020c2e4123365d6d29e14b8862e59542a")] [assembly: AssemblyProduct("OpenShock.Integrations.RiskOfRain2")] [assembly: AssemblyTitle("OpenShock.Integrations.RiskOfRain2")] [assembly: AssemblyVersion("1.1.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<bool> _settingOnDeathEnabled; private ConfigEntry<ControlType> _settingOnDeathBehaviour; private ConfigEntry<int> _settingOnDeathIntensity; private ConfigEntry<int> _settingOnDeathDuration; private ConfigEntry<bool> _settingOnDamageEnabled; private ConfigEntry<ControlType> _settingOnDamageMode; private ConfigEntry<DamageBehaviour> _settingOnDamageBehaviour; private ConfigEntry<int> _settingOnDamageDuration; private ConfigEntry<int> _settingOnDamageIntensityLimit; private ConfigEntry<bool> _settingEnableVerboseLogging; private Timer _actionTimer; private readonly object _receivedDamageLock = new object(); private float _receivedDamage; private double _lastDeathTime = -1.0; 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() { _settingEnableVerboseLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("OpenShock", "EnableVerboseLogging", false, "Enables verbose logging for debugging purposes"); _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."); _settingOnDeathEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("OnDeath", "Enabled", true, "Enables on death"); _settingOnDeathBehaviour = ((BaseUnityPlugin)this).Config.Bind<ControlType>("OnDeath", "Behaviour", ControlType.Shock, "The action that happens when the player dies"); _settingOnDeathIntensity = ((BaseUnityPlugin)this).Config.Bind<int>("OnDeath", "Intensity", 25, "The intensity of the shocker when the player dies"); _settingOnDeathDuration = ((BaseUnityPlugin)this).Config.Bind<int>("OnDeath", "Duration", 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", 300, "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; } if (Time.realtimeSinceStartupAsDouble - _lastDeathTime < 1.0) { if (_settingEnableVerboseLogging.Value) { ((BaseUnityPlugin)this).Logger.LogDebug((object)"Not sending damage feedback due to recent death"); } return; } byte b = CalculateIntensity(receivedDamage); if (_settingEnableVerboseLogging.Value) { ((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)) { if (_settingEnableVerboseLogging.Value) { ((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; if (_settingEnableVerboseLogging.Value) { ((BaseUnityPlugin)this).Logger.LogDebug((object)$"Calculating Intensity - MaxHp: {fullCombinedHealth:0.00} CurrentHp: {health:0.00} Damage: {damage:0.00} Behaviour: {value}"); } float num2; if ((uint)value <= 1u) { float num = value switch { DamageBehaviour.LowHp => 1f - health / fullCombinedHealth, DamageBehaviour.DamagePercent => damage / fullCombinedHealth, _ => throw new Exception("This is unreachable."), }; num2 = MathUtils.Lerp(0f, _settingOnDamageIntensityLimit.Value, MathUtils.Saturate(num)); if (_settingEnableVerboseLogging.Value) { ((BaseUnityPlugin)this).Logger.LogDebug((object)$"Calculated Intensity - CurrentHp: {health:0.00} / {fullCombinedHealth:0.00} Damage: {damage:0.00} Scaled: {num:0.0000} Intensity: {num2:0.00}"); } } else { num2 = Math.Clamp(damage, 0f, _settingOnDamageIntensityLimit.Value); } byte b = Convert.ToByte(num2); if (_settingEnableVerboseLogging.Value) { ((BaseUnityPlugin)this).Logger.LogDebug((object)$"Final Intensity Byte: {b}"); } return b; } private void OnCharacterDeath(DamageReport damageReport) { if (!((Object)(object)_localUserCharacterBody == (Object)null) && !((Object)(object)damageReport.victimBody == (Object)null) && !((Object)(object)damageReport.victimBody != (Object)(object)_localUserCharacterBody)) { ((BaseUnityPlugin)this).Logger.LogDebug((object)"Player has died"); if (!_settingOnDeathEnabled.Value) { ((BaseUnityPlugin)this).Logger.LogDebug((object)"OnDeath is disabled, skipping"); return; } _lastDeathTime = Time.realtimeSinceStartupAsDouble; ControlShockersFnf(_settingOnDeathBehaviour.Value, (byte)_settingOnDeathIntensity.Value, (ushort)_settingOnDeathDuration.Value); } } 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; } if (_settingEnableVerboseLogging.Value) { ((BaseUnityPlugin)this).Logger.LogDebug((object)$"Sending control request - Type: {controlType} Intensity: {intensity} Duration: {duration}ms"); } IEnumerable<Control> shocks = _shockersList.Select((Guid shocker) => new Control { Id = shocker, Duration = duration, Intensity = intensity, Type = controlType }); await _openShockApiClient.Control(shocks); if (_settingEnableVerboseLogging.Value) { ((BaseUnityPlugin)this).Logger.LogDebug((object)"Command sent"); } } private void ControlShockersFnf(ControlType controlType, byte intensity, ushort duration) { LucTask.Run(() => ControlShockers(controlType, intensity, duration), default(CancellationToken), "/home/runner/work/Integrations.RiskOfRain2/Integrations.RiskOfRain2/Integrations.RiskOfRain2/OpenShockLogic.cs", "ControlShockersFnf", 71); } 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_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Expected O, but got Unknown //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_007d: 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_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Expected O, but got Unknown //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Expected O, but got Unknown //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: 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 //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Expected O, but got Unknown //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Expected O, but got Unknown //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Expected O, but got Unknown //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Expected O, but got Unknown //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Expected O, but got Unknown //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Expected O, but got Unknown //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_0170: 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 CheckBoxOption(_settingEnableVerboseLogging)); 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(_settingOnDeathEnabled)); ModSettingsManager.AddOption((BaseOption)new ChoiceOption((ConfigEntryBase)(object)_settingOnDeathBehaviour)); ModSettingsManager.AddOption((BaseOption)new IntSliderOption(_settingOnDeathIntensity, new IntSliderConfig { min = 1, max = 100 })); ModSettingsManager.AddOption((BaseOption)new IntSliderOption(_settingOnDeathDuration, new IntSliderConfig { min = 300, max = 30000 })); 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; GlobalEventManager.onCharacterDeathGlobal += OnCharacterDeath; ((BaseUnityPlugin)this).Logger.LogDebug((object)"Events registered"); } private void OnDisable() { CharacterBody.onBodyStartGlobal -= OnCharacterBodyStart; CharacterBody.onBodyDestroyGlobal -= OnCharacterBodyDestroy; GlobalEventManager.onClientDamageNotified -= ClientOnDamage; GlobalEventManager.onCharacterDeathGlobal -= OnCharacterDeath; ((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 } }