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
}
}