Decompiled source of RoundsShock v1.0.1

plugins/RoundsShock.dll

Decompiled 3 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net;
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 BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using RoundsShock.Server;
using UnityEngine;
using UnityEngine.Networking;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("RoundsShock")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+ce793567f712328b16a8a899c7f4462a0204027f")]
[assembly: AssemblyProduct("RoundsShock")]
[assembly: AssemblyTitle("RoundsShock")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.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 RoundsShock
{
	public struct ModConfig
	{
		public string username;

		public string apiKey;

		public string code;

		public int hitIntensity;

		public int hitDuration;

		public int deathIntensity;

		public int deathDuration;

		public bool ConfigPlausable()
		{
			return !string.IsNullOrEmpty(username) && !string.IsNullOrEmpty(apiKey) && !string.IsNullOrEmpty(code);
		}

		public void SaveToPlayerPrefs()
		{
			PlayerPrefs.SetString("shocker_pishock_username", username);
			PlayerPrefs.SetString("shocker_pishock_apikey", apiKey);
			PlayerPrefs.SetString("shocker_pishock_code", code);
			PlayerPrefs.SetInt("shocker_hit_intensity", hitIntensity);
			PlayerPrefs.SetInt("shocker_hit_duration", hitDuration);
			PlayerPrefs.SetInt("shocker_death_intensity", deathIntensity);
			PlayerPrefs.SetInt("shocker_death_duration", deathDuration);
			PlayerPrefs.Save();
		}

		public static ModConfig LoadFromPlayerPrefs()
		{
			ModConfig result = default(ModConfig);
			result.username = PlayerPrefs.GetString("shocker_pishock_username");
			result.apiKey = PlayerPrefs.GetString("shocker_pishock_apikey");
			result.code = PlayerPrefs.GetString("shocker_pishock_code");
			result.hitIntensity = PlayerPrefs.GetInt("shocker_hit_intensity", 20);
			result.hitDuration = PlayerPrefs.GetInt("shocker_hit_duration", 1);
			result.deathIntensity = PlayerPrefs.GetInt("shocker_death_intensity", 30);
			result.deathDuration = PlayerPrefs.GetInt("shocker_death_duration", 1);
			return result;
		}
	}
	public sealed class PiShock
	{
		public static readonly PiShock Self = new PiShock();

		private const string API_URL = "https://do.pishock.com/api/apioperate/";

		public void Hit(float delay = 0f)
		{
			ExecuteWithDelay(delay, delegate
			{
				SendOperation(0, Plugin.ModConfig.hitIntensity, Plugin.ModConfig.hitDuration);
			});
		}

		public void Death(float delay = 0f)
		{
			ExecuteWithDelay(delay, delegate
			{
				SendOperation(0, Plugin.ModConfig.deathIntensity, Plugin.ModConfig.deathDuration);
			});
		}

		public void Defuse(float delay = 0f)
		{
			ExecuteWithDelay(delay, delegate
			{
				SendOperation(1, 100, 500);
			});
		}

		public void Test(float delay = 0f)
		{
			ExecuteWithDelay(delay, delegate
			{
				SendOperation(1, 20, 1);
				SendOperation(2, 50, 1);
			});
		}

		public void SendOperation(int op, int intensity, int duration)
		{
			if (!Plugin.ModConfig.ConfigPlausable())
			{
				Plugin.Logger.LogWarning((object)"Shock requested, but the config is not plausable");
			}
			else
			{
				((MonoBehaviour)Plugin.Instance).StartCoroutine(Coroutine());
			}
			IEnumerator Coroutine()
			{
				string jsonBody = null;
				try
				{
					jsonBody = $" {{\r\n    \"Username\": \"{Plugin.ModConfig.username}\",\r\n    \"Apikey\": \"{Plugin.ModConfig.apiKey}\",\r\n    \"Code\": \"{Plugin.ModConfig.code}\",\r\n    \"Name\": \"RoundsShock\",\r\n    \"Op\": \"{op}\",\r\n    \"Intensity\": \"{intensity}\",\r\n    \"Duration\": \"{duration}\"\r\n}}\r\n";
				}
				catch (Exception ex2)
				{
					Exception ex = ex2;
					Plugin.Logger.LogError((object)$"Failed to convert dictionary into json, {ex}");
				}
				if (jsonBody == null)
				{
					yield return 0;
				}
				UnityWebRequest request = new UnityWebRequest("https://do.pishock.com/api/apioperate/", "POST");
				byte[] bodyRaw = Encoding.UTF8.GetBytes(jsonBody);
				request.uploadHandler = (UploadHandler)new UploadHandlerRaw(bodyRaw);
				request.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
				request.SetRequestHeader("Content-Type", "application/json");
				Plugin.Logger.LogFatal((object)$"Sending PiShock operation: {op} {intensity} {duration}");
				yield return request.SendWebRequest();
				Plugin.Logger.LogFatal((object)(request.responseCode + " " + request.downloadHandler.text));
			}
		}

		private static void ExecuteWithDelay(float delay, Action action)
		{
			Action action2 = action;
			((MonoBehaviour)Plugin.Instance).StartCoroutine(Coroutine());
			IEnumerator Coroutine()
			{
				yield return (object)new WaitForSeconds(delay);
				action2();
			}
		}
	}
	[HarmonyPatch]
	public static class PlayerDamageHandler
	{
		private static readonly FieldInfo? _playerField;

		private static FieldInfo? GetField(string name, Type type)
		{
			BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
			FieldInfo fieldInfo = typeof(HealthHandler).GetField(name, bindingAttr);
			if (fieldInfo == null)
			{
				Plugin.Logger.LogError((object)("Failed to find field \"" + name + "\" on HealthHandler"));
				return null;
			}
			if (fieldInfo.FieldType != type)
			{
				Plugin.Logger.LogError((object)$"Field \"{name}\" on HealthHandler was not of type \"{type}\"");
				fieldInfo = null;
			}
			return fieldInfo;
		}

		static PlayerDamageHandler()
		{
			_playerField = GetField("player", typeof(Player));
			PrintAll();
		}

		private static void PrintAll()
		{
			Type typeFromHandle = typeof(HealthHandler);
			Plugin.Logger.LogInfo((object)$"Printing everything on {typeFromHandle}");
			BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
			FieldInfo[] fields = typeFromHandle.GetFields(bindingAttr);
			foreach (FieldInfo fieldInfo in fields)
			{
				Plugin.Logger.LogInfo((object)$"{fieldInfo.Name}, {fieldInfo.FieldType}");
			}
			PropertyInfo[] properties = typeFromHandle.GetProperties(bindingAttr);
			foreach (PropertyInfo propertyInfo in properties)
			{
				Plugin.Logger.LogInfo((object)$"{propertyInfo.Name}, {propertyInfo.PropertyType}");
			}
		}

		[HarmonyPatch(typeof(HealthHandler), "DoDamage")]
		[HarmonyPrefix]
		private static void OnDamage(HealthHandler __instance, Vector2 damage)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			if (!(_playerField == null))
			{
				Plugin.Logger.LogError((object)"Damage detected");
				Player val = (Player)_playerField.GetValue(__instance);
				if ((Object)(object)val == (Object)null)
				{
					Plugin.Logger.LogError((object)"Player field returned null when doing damage handling");
				}
				else if (val.data.view.IsMine)
				{
					PiShock.Self.Hit();
				}
			}
		}
	}
	[HarmonyPatch]
	public static class PlayerDeathHandler
	{
		[HarmonyPatch(typeof(PlayerManager), "PlayerDied")]
		[HarmonyPrefix]
		private static void OnDeath(PlayerManager __instance, Player player)
		{
			bool isMine = player.data.view.IsMine;
			Plugin.Logger.LogInfo((object)$"Death detected. Me: {isMine}");
			if (isMine)
			{
				PiShock.Self.Death();
			}
		}
	}
	[BepInPlugin("RoundsShock-guid", "RoundsShock", "1.0.0")]
	[HarmonyPatch]
	public sealed class Plugin : BaseUnityPlugin
	{
		public static Plugin Instance { get; private set; }

		public static ManualLogSource Logger { get; } = Logger.CreateLogSource("RoundsShock");


		public static ModConfig ModConfig { get; set; }

		private void Awake()
		{
			Instance = this;
			((Component)this).gameObject.AddComponent<ConfigServer>();
			ModConfig = ModConfig.LoadFromPlayerPrefs();
			Logger.LogError((object)"Rounds shock loaded");
			Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), (string)null);
		}
	}
}
namespace RoundsShock.Server
{
	public static class BodyParser
	{
		public static Dictionary<string, string> ParseUrlEncoded(HttpListenerRequest request)
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			string text = new StreamReader(request.InputStream).ReadToEnd();
			Plugin.Logger.LogMessage((object)text);
			string[] array = text.Split(new char[1] { '&' });
			string[] array2 = array;
			foreach (string text2 in array2)
			{
				string[] array3 = text2.Split(new char[1] { '=' });
				dictionary.Add(array3[0], array3[1]);
			}
			return dictionary;
		}
	}
	public sealed class ConfigServer : MonoBehaviour
	{
		private readonly string? _configHtml;

		private readonly string? _testHtml;

		private Thread? _thread;

		private bool CanRun => _configHtml != null && _testHtml != null;

		private string? LoadString(string path)
		{
			try
			{
				Stream manifestResourceStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(path);
				if (manifestResourceStream == null)
				{
					Plugin.Logger.LogFatal((object)("Resource stream not found for path " + path));
					return null;
				}
				StreamReader streamReader = new StreamReader(manifestResourceStream);
				return streamReader.ReadToEnd();
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogFatal((object)("Server Failed to Load stream " + path + ": " + ex.Message));
				return null;
			}
		}

		private ConfigServer()
		{
			_configHtml = LoadString("RoundsShock.Server.Resources.config.html");
			_testHtml = LoadString("RoundsShock.Server.Resources.test.html");
		}

		private void Awake()
		{
			if (CanRun)
			{
				_thread = new Thread(RunWebServer);
				_thread.Start();
			}
			else
			{
				Plugin.Logger.LogFatal((object)"Due to a failure loading HTML the config server will not start");
			}
		}

		private void OnDestroy()
		{
			if (CanRun)
			{
				_thread.Abort();
			}
		}

		private void RunWebServer()
		{
			string text = "http://localhost:6969/";
			HttpListener httpListener = new HttpListener();
			httpListener.Prefixes.Add(text);
			httpListener.Start();
			Application.OpenURL(text);
			while (true)
			{
				HttpListenerContext context = httpListener.GetContext();
				HttpListenerRequest request = context.Request;
				HttpListenerResponse response = context.Response;
				try
				{
					Plugin.Logger.LogWarning((object)(request.HttpMethod + " " + request.Url.AbsolutePath));
					if (request.Url.AbsolutePath.Contains("simpletest") && request.HttpMethod == "GET")
					{
						PiShock.Self.Test();
						response.Redirect("/");
					}
					else if (request.Url.AbsolutePath.Contains("testpls") && request.HttpMethod == "POST")
					{
						Dictionary<string, string> dictionary = BodyParser.ParseUrlEncoded(request);
						PiShock.Self.SendOperation(int.Parse(dictionary["operation"]), int.Parse(dictionary["intensity"]), int.Parse(dictionary["duration"]));
						response.StatusCode = 200;
					}
					else if (request.Url.AbsolutePath.Contains("test") && request.HttpMethod == "GET")
					{
						response.StatusCode = 200;
						response.ContentType = "text/html";
						response.ContentEncoding = Encoding.UTF8;
						byte[] bytes = Encoding.UTF8.GetBytes(_testHtml);
						response.ContentLength64 = bytes.Length;
						response.OutputStream.Write(bytes, 0, bytes.Length);
						response.OutputStream.Close();
					}
					else if (request.Url.AbsolutePath.Contains("save") && request.HttpMethod == "POST")
					{
						Dictionary<string, string> dictionary2 = BodyParser.ParseUrlEncoded(request);
						ModConfig modConfig = default(ModConfig);
						modConfig.username = dictionary2["username"];
						modConfig.apiKey = dictionary2["apiKey"];
						modConfig.code = dictionary2["code"];
						modConfig.hitIntensity = int.Parse(dictionary2["hitIntensity"]);
						modConfig.hitDuration = int.Parse(dictionary2["hitDuration"]);
						modConfig.deathIntensity = int.Parse(dictionary2["deathIntensity"]);
						modConfig.deathDuration = int.Parse(dictionary2["deathDuration"]);
						ModConfig modConfig2 = modConfig;
						modConfig2.SaveToPlayerPrefs();
						Plugin.ModConfig = modConfig2;
						response.Redirect("/");
					}
					else if (request.Url.AbsolutePath == "/" && request.HttpMethod == "GET")
					{
						ModConfig modConfig3 = Plugin.ModConfig;
						string s = _configHtml.Replace("{{username}}", modConfig3.username).Replace("{{apiKey}}", modConfig3.apiKey).Replace("{{code}}", modConfig3.code)
							.Replace("{{hitIntensity}}", modConfig3.hitIntensity.ToString())
							.Replace("{{hitDuration}}", modConfig3.hitDuration.ToString())
							.Replace("{{deathIntensity}}", modConfig3.deathIntensity.ToString())
							.Replace("{{deathDuration}}", modConfig3.deathDuration.ToString());
						response.StatusCode = 200;
						response.ContentType = "text/html";
						response.ContentEncoding = Encoding.UTF8;
						byte[] bytes2 = Encoding.UTF8.GetBytes(s);
						response.ContentLength64 = bytes2.Length;
						response.OutputStream.Write(bytes2, 0, bytes2.Length);
						response.OutputStream.Close();
					}
				}
				catch (Exception ex)
				{
					Plugin.Logger.LogError((object)ex);
					response.StatusCode = 500;
				}
				response.Close();
			}
		}
	}
}