The BepInEx console will not appear when launching like it does for other games on Thunderstore. This is normal (and helps prevent crashes during startup). You can turn it back on in your BepInEx.cfg file.
Decompiled source of PeakShock v0.1.5
plugins/addzeey.PeakShock.dll
Decompiled 5 days agousing System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Net.Http; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Threading; using System.Threading.Tasks; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using UnityEngine; [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("addzeey.PeakShock")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.1.5.0")] [assembly: AssemblyInformationalVersion("0.1.5+7124d3ac273467a88dba3e808a05475cae2aa94f")] [assembly: AssemblyProduct("addzeey.PeakShock")] [assembly: AssemblyTitle("PeakShock")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.1.5.0")] [module: UnverifiableCode] [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; } } } public interface IShockController { void EnqueueShock(int intensity, int duration, string? code = null); } namespace BepInEx { [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] [Conditional("CodeGeneration")] internal sealed class BepInAutoPluginAttribute : Attribute { public BepInAutoPluginAttribute(string? id = null, string? name = null, string? version = null) { } } } namespace BepInEx.Preloader.Core.Patching { [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] [Conditional("CodeGeneration")] internal sealed class PatcherAutoPluginAttribute : Attribute { public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null) { } } } namespace PeakShock { internal class ShockRequestQueue : IDisposable { private ConcurrentQueue<Func<Task>> _taskQueue; private SemaphoreSlim _signal; private CancellationTokenSource _cts; private Task _worker; private readonly object _lock = new object(); private bool _disposed; public ShockRequestQueue() { Start(); } public void Enqueue(Func<Task> task) { if (_disposed) { throw new ObjectDisposedException("ShockRequestQueue"); } _taskQueue.Enqueue(task); _signal.Release(); } public void Enqueue<T>(Func<T, Task> task, T args) { Func<T, Task> task2 = task; T args2 = args; if (_disposed) { throw new ObjectDisposedException("ShockRequestQueue"); } _taskQueue.Enqueue(() => task2(args2)); _signal.Release(); } public void Start() { _taskQueue = new ConcurrentQueue<Func<Task>>(); _signal = new SemaphoreSlim(0); _cts = new CancellationTokenSource(); _worker = Task.Run((Func<Task?>)ProcessQueueAsync); } private async Task ProcessQueueAsync() { while (!_cts.Token.IsCancellationRequested) { await _signal.WaitAsync(_cts.Token); if (_taskQueue.TryDequeue(out Func<Task> result)) { try { await result(); } catch (Exception ex) { Plugin.Log.LogError((object)ex.ToString()); } } } } public async Task StopAsync() { if (_disposed) { return; } _cts.Cancel(); _signal.Release(); try { await _worker; } catch (Exception ex) { Plugin.Log.LogError((object)ex.ToString()); } } public async Task ResetAsync() { lock (_lock) { if (!_worker.IsCompleted) { StopAsync().Wait(); } Start(); } } public void Dispose() { if (!_disposed) { StopAsync().Wait(); _cts.Dispose(); _signal.Dispose(); _disposed = true; } } } public class OpenShockController : IShockController { private readonly ShockRequestQueue _queue = new ShockRequestQueue(); private readonly string _apiUrl; private readonly string _deviceId; private readonly string _apiKey; private readonly HttpClient _client = new HttpClient(); private DateTime _lastShockTime = DateTime.MinValue; private TimeSpan ShockCooldown => TimeSpan.FromSeconds(1.0 + (double)Math.Max(0f, Plugin.ShockCooldownSeconds.Value)); public OpenShockController() { _apiUrl = Plugin.OpenShockApiUrl.Value; _deviceId = Plugin.OpenShockDeviceId.Value; _apiKey = Plugin.OpenShockApiKey.Value; } public void EnqueueShock(int intensity, int duration, string? code = null) { string code2 = code; DateTime utcNow = DateTime.UtcNow; if (utcNow - _lastShockTime < ShockCooldown) { Plugin.Log.LogInfo((object)"[PeakShock] OpenShock shock skipped due to cooldown."); return; } _lastShockTime = utcNow; _queue.Enqueue(() => TriggerShockInternal(intensity, duration, code2)); } private async Task TriggerShockInternal(int intensity, int duration, string? code) { int num = Math.Clamp(duration * 1000, 300, 65535); if (string.IsNullOrEmpty(_apiUrl) || string.IsNullOrEmpty(_apiKey)) { Plugin.Log.LogWarning((object)$"[PeakShock] Would send OpenShock (intensity={intensity}, duration={num}), but OpenShock credentials are not set."); return; } string text = ((!string.IsNullOrEmpty(code)) ? code : _deviceId); if (string.IsNullOrEmpty(text)) { Plugin.Log.LogWarning((object)"[PeakShock] No deviceId or share code provided for OpenShock."); return; } Plugin.Log.LogInfo((object)$"[PeakShock] Sending OpenShock: id={text}, intensity={intensity}, duration={num}"); var anon = new { Shocks = new[] { new { Id = text, Type = 1, Intensity = intensity, Duration = num } }, CustomName = "Integrations.PeakShock" }; string content = JsonConvert.SerializeObject((object)anon); StringContent content2 = new StringContent(content, Encoding.UTF8, "application/json"); HttpRequestMessage httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, _apiUrl + "/2/shockers/control") { Content = content2 }; httpRequestMessage.Headers.Add("OpenShockToken", _apiKey); httpRequestMessage.Headers.Add("User-Agent", "PeakShock/" + Plugin.Version); try { HttpResponseMessage response = await _client.SendAsync(httpRequestMessage); if (!response.IsSuccessStatusCode) { string arg = await response.Content.ReadAsStringAsync(); Plugin.Log.LogError((object)$"OpenShock API error: {response.StatusCode} {arg}"); } } catch (Exception arg2) { Plugin.Log.LogError((object)$"OpenShock API exception: {arg2}"); } } } public class PiShockController : IShockController { private readonly HttpClient _client = new HttpClient(); private readonly ShockRequestQueue _queue = new ShockRequestQueue(); private DateTime _lastShockTime = DateTime.MinValue; private TimeSpan ShockCooldown => TimeSpan.FromSeconds(1f + Math.Max(0f, Plugin.ShockCooldownSeconds.Value)); public void TriggerShock(int intensity, int duration = 1, string? shareCode = null) { DateTime utcNow = DateTime.UtcNow; if (utcNow - _lastShockTime < ShockCooldown) { Plugin.Log.LogInfo((object)"[PeakShock] Shock skipped due to cooldown."); return; } _lastShockTime = utcNow; string code = shareCode ?? Plugin.PiShockShareCode.Value; Plugin.Log.LogInfo((object)$"[PeakShock] Enqueue shock: intensity={intensity}, duration={duration}, code={code}"); _queue.Enqueue(() => TriggerShockInternal(intensity, duration, code)); } public void EnqueueShock(int intensity, int duration, string? code = null) { TriggerShock(intensity, duration, code); } private async Task TriggerShockInternal(int intensity, int duration, string code) { string value = Plugin.PiShockUserName.Value; string value2 = Plugin.PiShockAPIKey.Value; if (string.IsNullOrEmpty(value) || string.IsNullOrEmpty(value2) || string.IsNullOrEmpty(code)) { Plugin.Log.LogWarning((object)$"[PeakShock] Would send shock (intensity={intensity}, duration={duration}, code={code}), but PiShock credentials are not set."); return; } Plugin.Log.LogInfo((object)$"[PeakShock] Sending shock: intensity={intensity}, duration={duration}, code={code}"); string content = JsonConvert.SerializeObject((object)new { Username = value, APIKey = value2, Code = code, Intensity = intensity, Duration = duration, Op = 0 }); StringContent content2 = new StringContent(content, Encoding.UTF8, "application/json"); try { Plugin.Log.LogInfo((object)$"[PeakShock] Sending request to PiShock API: {value}, Intensity={intensity}, Duration={duration}"); HttpResponseMessage httpResponseMessage = await _client.PostAsync("https://do.pishock.com/api/apioperate/", content2); if (!httpResponseMessage.IsSuccessStatusCode) { Plugin.Log.LogError((object)$"PiShock API error: {httpResponseMessage.StatusCode}"); } } catch (Exception arg) { Plugin.Log.LogError((object)$"PiShock API exception: {arg}"); } } } [BepInPlugin("addzeey.PeakShock", "PeakShock", "0.1.5")] public class Plugin : BaseUnityPlugin { public enum ShockProvider { PiShock, OpenShock } public const string PluginVersion = "0.1.5"; private Harmony? _harmony; public const string Id = "addzeey.PeakShock"; internal static ManualLogSource Log { get; private set; } internal static ConfigFile CFG { get; private set; } internal static PiShockController PiShockController { get; private set; } internal static ConfigEntry<string> PiShockUserName { get; private set; } internal static ConfigEntry<string> PiShockAPIKey { get; private set; } internal static ConfigEntry<string> PiShockShareCode { get; private set; } internal static ConfigEntry<int> MinShock { get; private set; } internal static ConfigEntry<int> MaxShock { get; private set; } internal static ConfigEntry<int> DeathShock { get; private set; } internal static ConfigEntry<int> DeathDuration { get; private set; } internal static ConfigEntry<bool> EnableInjuryShock { get; private set; } internal static ConfigEntry<bool> EnablePoisonShock { get; private set; } internal static ConfigEntry<bool> EnableColdShock { get; private set; } internal static ConfigEntry<bool> EnableHotShock { get; private set; } internal static ConfigEntry<float> ShockCooldownSeconds { get; private set; } internal static ConfigEntry<ShockProvider> ShockProviderType { get; private set; } internal static ConfigEntry<string> OpenShockApiUrl { get; private set; } internal static ConfigEntry<string> OpenShockDeviceId { get; private set; } internal static ConfigEntry<string> OpenShockApiKey { get; private set; } internal static IShockController ShockController { get; private set; } public static string Name => "PeakShock"; public static string Version => "0.1.5"; private void Awake() { //IL_0328: Unknown result type (might be due to invalid IL or missing references) //IL_0332: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; CFG = ((BaseUnityPlugin)this).Config; PiShockUserName = CFG.Bind<string>("PiShock", "UserName", "", "Your PiShock username"); PiShockAPIKey = CFG.Bind<string>("PiShock", "APIKey", "", "Your PiShock API Key"); PiShockShareCode = CFG.Bind<string>("PiShock", "ShareCode", "", "Your PiShock ShareCode"); MinShock = CFG.Bind<int>("Shock", "MinShock", 10, "Minimum shock intensity (1-100)"); MaxShock = CFG.Bind<int>("Shock", "MaxShock", 100, "Maximum shock intensity (1-100)"); DeathShock = CFG.Bind<int>("Shock", "DeathShock", 80, "Shock intensity on death (1-100)"); DeathDuration = CFG.Bind<int>("Shock", "DeathDuration", 2, "Shock duration on death (seconds)"); EnableInjuryShock = CFG.Bind<bool>("ShockTypes", "EnableInjuryShock", true, "Enable shock for Injury damage"); EnablePoisonShock = CFG.Bind<bool>("ShockTypes", "EnablePoisonShock", false, "Enable shock for Poison damage"); EnableColdShock = CFG.Bind<bool>("ShockTypes", "EnableColdShock", false, "Enable shock for Cold damage"); EnableHotShock = CFG.Bind<bool>("ShockTypes", "EnableHotShock", false, "Enable shock for Hot/Fire damage"); ShockCooldownSeconds = CFG.Bind<float>("Shock", "ShockCooldownSeconds", 2f, "Minimum seconds between shocks (prevents shock spam)"); ShockProviderType = CFG.Bind<ShockProvider>("Shock", "Provider", ShockProvider.PiShock, "Choose PiShock or OpenShock"); OpenShockApiUrl = CFG.Bind<string>("OpenShock", "ApiUrl", "https://api.openshock.app", "OpenShock API URL"); OpenShockDeviceId = CFG.Bind<string>("OpenShock", "DeviceId", "", "OpenShock Device ID"); OpenShockApiKey = CFG.Bind<string>("OpenShock", "ApiKey", "", "OpenShock API Key"); Log.LogInfo((object)$"[PeakShock] Config:\nMinShock={MinShock.Value}\nMaxShock={MaxShock.Value}\nDeathShock={DeathShock.Value}\nDeathDuration={DeathDuration.Value}\nEnableInjuryShock={EnableInjuryShock.Value}\nEnablePoisonShock={EnablePoisonShock.Value}\nEnableColdShock={EnableColdShock.Value}\nEnableHotShock={EnableHotShock.Value}\nShockCooldownSeconds={ShockCooldownSeconds.Value}"); if (ShockProviderType.Value == ShockProvider.PiShock) { ShockController = new PiShockController(); Log.LogInfo((object)"[PeakShock] Initialized PiShockController"); } else { ShockController = new OpenShockController(); Log.LogInfo((object)"[PeakShock] Initialized OpenShockController"); } _harmony = new Harmony("com.yourname.PeakShock"); _harmony.PatchAll(Assembly.GetExecutingAssembly()); Log.LogInfo((object)("Plugin " + Name + " is loaded!")); } } } namespace PeakShock.PeakShock.Patches { [HarmonyPatch(typeof(Character), "RPCA_Die")] public class CharacterDeathPatch { [HarmonyPostfix] public static void Postfix(Character __instance) { if (__instance.IsLocal) { int intensity = Plugin.DeathShock.Value; int duration = Plugin.DeathDuration.Value; Plugin.Log.LogInfo((object)$"[PeakShock] Player died. Triggering death shock: {intensity}% for {duration}s"); Task.Run(delegate { Plugin.ShockController.EnqueueShock(intensity, duration); }); } } } [HarmonyPatch(typeof(CharacterAfflictions), "AddStatus")] public class CharacterAfflictions_AddStatus_Patch { private static readonly Dictionary<STATUSTYPE, bool> ShockTypeEnabled = new Dictionary<STATUSTYPE, bool> { { (STATUSTYPE)1, false }, { (STATUSTYPE)0, Plugin.EnableInjuryShock.Value }, { (STATUSTYPE)3, Plugin.EnablePoisonShock.Value }, { (STATUSTYPE)2, Plugin.EnableColdShock.Value }, { (STATUSTYPE)8, Plugin.EnableHotShock.Value } }; [HarmonyPostfix] public static void Postfix(CharacterAfflictions __instance, STATUSTYPE statusType, float amount, bool fromRPC) { //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Invalid comparison between I4 and Unknown //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) if (!__instance.character.IsLocal || (Object)(object)__instance.character != (Object)(object)Character.localCharacter || amount <= 0f) { return; } if (__instance.character.data.dead || __instance.character.data.fullyPassedOut || __instance.character.data.passedOut) { Plugin.Log.LogInfo((object)$"[PeakShock] Ignored status effect shock ({statusType}) because player is dead or passed out."); return; } int value = Plugin.MinShock.Value; int value2 = Plugin.MaxShock.Value; float num = 0f; if (amount < 0.01f) { num += amount; if (num > 0.01f) { Plugin.Log.LogInfo((object)$"[PeakShock] Accumulated damage {num} exceeds threshold, triggering shock."); int intensity = Mathf.Clamp(Mathf.RoundToInt(num * (float)value2), value, value2); Task.Run(delegate { Plugin.ShockController.EnqueueShock(intensity, 1); }); num = 0f; } } else { if (1 == (int)statusType) { return; } if (!ShockTypeEnabled.TryGetValue(statusType, out var value3) || !value3) { Plugin.Log.LogInfo((object)$"[PeakShock] Ignored status effect shock for {statusType} because it is disabled."); return; } int intensity2 = Mathf.Clamp(Mathf.RoundToInt(amount * (float)value2), value, value2); Plugin.Log.LogInfo((object)$"[PeakShock] Status effect {statusType} damage: {amount}, shock: {intensity2}%"); Task.Run(delegate { Plugin.ShockController.EnqueueShock(intensity2, 1); }); } } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } }