Decompiled source of UltraShock v0.0.1

plugins/jakobbbb.UltraShock.dll

Decompiled 12 hours ago
using System;
using System.Collections.Concurrent;
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 ShockController;
using UnityEngine;
using UnityEngine.SceneManagement;

[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("UltraShock")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.0.1.0")]
[assembly: AssemblyInformationalVersion("0.0.1+ab8bcb5dbf1baa9dd238cf14558753e175d5104b")]
[assembly: AssemblyProduct("UltraShock")]
[assembly: AssemblyTitle("UltraShock")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.1.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;
		}
	}
}
namespace ShockController
{
	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;

		private ManualLogSource _logger;

		public ShockRequestQueue(ManualLogSource logger)
		{
			_logger = logger;
			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)
		{
			if (_disposed)
			{
				throw new ObjectDisposedException("ShockRequestQueue");
			}
			_taskQueue.Enqueue(() => task(args));
			_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 var result))
				{
					try
					{
						await result();
					}
					catch (Exception ex)
					{
						_logger.LogError((object)ex.ToString());
					}
				}
			}
		}

		public async Task StopAsync()
		{
			if (_disposed)
			{
				return;
			}
			_cts.Cancel();
			_signal.Release();
			try
			{
				await _worker;
			}
			catch (Exception ex)
			{
				_logger.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 interface IShockController
	{
		void EnqueueShock(int intensity, int duration_ms, string? code = null);
	}
	public class OpenShockController : IShockController
	{
		private readonly ShockRequestQueue _queue;

		private readonly string _apiUrl;

		private readonly string _deviceId;

		private readonly string _apiKey;

		private readonly float _cooldownSeconds;

		private readonly ManualLogSource _logger;

		private readonly HttpClient _client = new HttpClient();

		private DateTime _lastShockTime = DateTime.MinValue;

		private TimeSpan ShockCooldown => TimeSpan.FromSeconds(0.1 + (double)Math.Max(0f, _cooldownSeconds));

		public OpenShockController(string apiUrl, string deviceId, string apiKey, float cooldownSeconds, ManualLogSource logger)
		{
			_apiUrl = apiUrl;
			_deviceId = deviceId;
			_apiKey = apiKey;
			_cooldownSeconds = cooldownSeconds;
			_logger = logger;
			_queue = new ShockRequestQueue(logger);
		}

		public void EnqueueShock(int intensity, int duration_ms, string? code = null)
		{
			string code2 = code;
			DateTime utcNow = DateTime.UtcNow;
			if (utcNow - _lastShockTime < ShockCooldown)
			{
				_logger.LogInfo((object)"OpenShock shock skipped due to cooldown.");
				return;
			}
			_lastShockTime = utcNow;
			_queue.Enqueue(() => TriggerShockInternal(intensity, duration_ms, code2));
		}

		private async Task TriggerShockInternal(int intensity, int duration_ms, string? code)
		{
			duration_ms = Math.Clamp(duration_ms, 300, 65535);
			if (string.IsNullOrEmpty(_apiUrl) || string.IsNullOrEmpty(_apiKey))
			{
				_logger.LogWarning((object)$"Would send OpenShock (intensity={intensity}, duration_ms={duration_ms}), but OpenShock credentials are not set.");
				return;
			}
			string text = ((!string.IsNullOrEmpty(code)) ? code : _deviceId);
			if (string.IsNullOrEmpty(text))
			{
				_logger.LogWarning((object)"No deviceId or share code provided for OpenShock.");
				return;
			}
			_logger.LogInfo((object)$"Sending OpenShock: id={text}, intensity={intensity}, duration_ms={duration_ms}");
			StringContent content = new StringContent(JsonConvert.SerializeObject((object)new
			{
				Shocks = new[]
				{
					new
					{
						Id = text,
						Type = 1,
						Intensity = intensity,
						Duration = duration_ms
					}
				},
				CustomName = "Integrations.UltraShock"
			}), Encoding.UTF8, "application/json");
			HttpRequestMessage httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, _apiUrl + "/2/shockers/control")
			{
				Content = content
			};
			httpRequestMessage.Headers.Add("OpenShockToken", _apiKey);
			httpRequestMessage.Headers.Add("User-Agent", "UnityShock");
			try
			{
				HttpResponseMessage response = await _client.SendAsync(httpRequestMessage);
				if (!response.IsSuccessStatusCode)
				{
					string arg = await response.Content.ReadAsStringAsync();
					_logger.LogError((object)$"OpenShock API error: {response.StatusCode} {arg}");
				}
			}
			catch (Exception arg2)
			{
				_logger.LogError((object)$"OpenShock API exception: {arg2}");
			}
		}
	}
	public class PiShockController : IShockController
	{
		private readonly HttpClient _client = new HttpClient();

		private readonly ShockRequestQueue _queue;

		private readonly ManualLogSource _logger;

		private readonly string _userName;

		private readonly string _shareCode;

		private readonly string _apiKey;

		private readonly float _cooldownSeconds;

		private DateTime _lastShockTime = DateTime.MinValue;

		private TimeSpan ShockCooldown => TimeSpan.FromSeconds(0.1 + (double)Math.Max(0f, _cooldownSeconds));

		public PiShockController(string userName, string shareCode, string apiKey, float cooldownSeconds, ManualLogSource logger)
		{
			_userName = userName;
			_shareCode = shareCode;
			_apiKey = apiKey;
			_cooldownSeconds = cooldownSeconds;
			_logger = logger;
			_queue = new ShockRequestQueue(logger);
		}

		public void TriggerShock(int intensity, int duration_ms = 1, string? shareCode = null)
		{
			DateTime utcNow = DateTime.UtcNow;
			if (utcNow - _lastShockTime < ShockCooldown)
			{
				_logger.LogInfo((object)"Shock skipped due to cooldown.");
				return;
			}
			_lastShockTime = utcNow;
			string code = shareCode ?? _shareCode;
			_logger.LogInfo((object)$"Enqueue shock: intensity={intensity}, duration={duration_ms}, code={code}");
			_queue.Enqueue(() => TriggerShockInternal(intensity, duration_ms, code));
		}

		public void EnqueueShock(int intensity, int duration_ms, string? code = null)
		{
			TriggerShock(intensity, duration_ms, code);
		}

		private async Task TriggerShockInternal(int intensity, int duration, string code)
		{
			string userName = _userName;
			string apiKey = _apiKey;
			duration /= 1000;
			if (string.IsNullOrEmpty(userName) || string.IsNullOrEmpty(apiKey) || string.IsNullOrEmpty(code))
			{
				_logger.LogWarning((object)$"Would send shock (intensity={intensity}, duration={duration}, code={code}), but PiShock credentials are not set.");
				return;
			}
			_logger.LogInfo((object)$"Sending shock: intensity={intensity}, duration_sec={duration}, code={code}");
			StringContent content = new StringContent(JsonConvert.SerializeObject((object)new
			{
				Username = userName,
				APIKey = apiKey,
				Code = code,
				Intensity = intensity,
				Duration = duration,
				Op = 0
			}), Encoding.UTF8, "application/json");
			try
			{
				_logger.LogInfo((object)$"Sending request to PiShock API: {userName}, Intensity={intensity}, Duration={duration}");
				HttpResponseMessage httpResponseMessage = await _client.PostAsync("https://do.pishock.com/api/apioperate/", content);
				if (!httpResponseMessage.IsSuccessStatusCode)
				{
					_logger.LogError((object)$"PiShock API error: {httpResponseMessage.StatusCode}");
				}
			}
			catch (Exception arg)
			{
				_logger.LogError((object)$"PiShock API exception: {arg}");
			}
		}
	}
	public class ShockConfig
	{
		public enum ShockProvider
		{
			OpenShock,
			PiShock
		}

		public ConfigFile f { get; private set; }

		public ConfigEntry<float> ShockCooldownSeconds { get; private set; }

		public ConfigEntry<ShockProvider> ShockProviderType { get; private set; }

		public ConfigEntry<string> OpenShockApiUrl { get; private set; }

		public ConfigEntry<string> OpenShockDeviceId { get; private set; }

		public ConfigEntry<string> OpenShockApiKey { get; private set; }

		public ConfigEntry<string> PiShockUserName { get; private set; }

		public ConfigEntry<string> PiShockAPIKey { get; private set; }

		public ConfigEntry<string> PiShockShareCode { get; private set; }

		public ShockConfig(ConfigFile f)
		{
			ShockCooldownSeconds = f.Bind<float>("Shock", "ShockCooldownSeconds", 2f, "Minimum seconds between shocks (prevents shock spam)");
			ShockProviderType = f.Bind<ShockProvider>("Shock", "Provider", ShockProvider.OpenShock, "Choose PiShock or OpenShock");
			OpenShockApiUrl = f.Bind<string>("OpenShock", "ApiUrl", "https://api.openshock.app", "OpenShock API URL");
			OpenShockDeviceId = f.Bind<string>("OpenShock", "DeviceId", "", "OpenShock Device ID");
			OpenShockApiKey = f.Bind<string>("OpenShock", "ApiKey", "", "OpenShock API Key");
			PiShockUserName = f.Bind<string>("PiShock", "UserName", "", "Your PiShock username");
			PiShockAPIKey = f.Bind<string>("PiShock", "APIKey", "", "Your PiShock API Key");
			PiShockShareCode = f.Bind<string>("PiShock", "ShareCode", "", "Your PiShock ShareCode");
		}
	}
}
namespace UltraShock
{
	[HarmonyPatch(typeof(NewMovement), "GetHurt")]
	public class HurtPatch
	{
		private static void Postfix(int damage, bool invincible, float scoreLossMultiplier, bool explosion, bool instablack, float hardDamageMultiplier, bool ignoreInvincibility)
		{
			UltraShockPlugin.Logger.LogInfo((object)("Damage" + damage + "!"));
			float num = (float)UltraShockPlugin.ShockScale.Value / 100f;
			UltraShockPlugin.Shocker.EnqueueShock(Mathf.RoundToInt((float)damage * num), 500);
		}
	}
	internal class PluginInfo
	{
		public const string PLUGIN_GUID = "jakobbbb.UltraShock";

		public const string PLUGIN_NAME = "UltraShock";

		public const string PLUGIN_VERSION = "0.0.1";
	}
	[BepInPlugin("jakobbbb.UltraShock", "UltraShock", "0.0.1")]
	public class UltraShockPlugin : BaseUnityPlugin
	{
		public static ManualLogSource Logger;

		public static UltraShockPlugin Instance;

		internal ShockConfig _shockConf;

		public static IShockController Shocker;

		public static ConfigEntry<int> ShockScale { get; private set; }

		private void Awake()
		{
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Expected O, but got Unknown
			Instance = this;
			Object.DontDestroyOnLoad((Object)(object)this);
			Logger = ((BaseUnityPlugin)this).Logger;
			Logger.LogInfo((object)"Plugin jakobbbb.UltraShock is loaded :3");
			SceneManager.sceneLoaded += delegate
			{
				Logger.LogInfo((object)"Scene loaded!");
			};
			Harmony.CreateAndPatchAll(typeof(HurtPatch), (string)null);
			ConfigFile val = new ConfigFile("BepInEx/config/jakobbbb.UltraShock.cfg", true);
			ShockScale = val.Bind<int>("Shock", "ShockScale", 50, "How much to scale shock intensity (0-100)");
			_shockConf = new ShockConfig(val);
			ShockConfig.ShockProvider value = _shockConf.ShockProviderType.Value;
			Logger.LogInfo((object)$"Shock provider is: {value}");
			switch (value)
			{
			case ShockConfig.ShockProvider.OpenShock:
				Shocker = new OpenShockController(_shockConf.OpenShockApiUrl.Value, _shockConf.OpenShockDeviceId.Value, _shockConf.OpenShockApiKey.Value, _shockConf.ShockCooldownSeconds.Value, Logger);
				break;
			case ShockConfig.ShockProvider.PiShock:
				Shocker = new PiShockController(_shockConf.PiShockUserName.Value, _shockConf.PiShockShareCode.Value, _shockConf.PiShockAPIKey.Value, _shockConf.ShockCooldownSeconds.Value, Logger);
				break;
			}
		}

		private void OnEnable()
		{
			Logger.LogInfo((object)"Enabled");
		}

		private void OnDisable()
		{
			Logger.LogInfo((object)"Disabled");
		}

		private void Update()
		{
			Logger.LogError((object)"OWO");
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "UltraShock";

		public const string PLUGIN_NAME = "UltraShock";

		public const string PLUGIN_VERSION = "0.0.1";
	}
}