Decompiled source of ReOpenShock v1.0.5

ReOpenShock.dll

Decompiled 3 weeks ago
using System;
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.Tasks;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using ReOpenShock.Patches;
using Sirenix.Serialization.Utilities;
using Sirenix.Utilities;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("ReOpenShock")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.5.0")]
[assembly: AssemblyInformationalVersion("1.0.5+b1f49121efd3625308aaa2fa11c6630d1abfc48c")]
[assembly: AssemblyProduct("Shocks you in R.E.P.O")]
[assembly: AssemblyTitle("ReOpenShock")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.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;
		}
	}
}
namespace ReOpenShock
{
	public static class ModConfig
	{
		private static class ConfigGroups
		{
			public static readonly string Connection = "Connection";

			public static readonly string General = "General";

			public static readonly string ShockEvents = "Shock Events";

			public static readonly string Misc = "Misc";
		}

		public static ConfigEntry<string> OpenShockAPIDomain;

		public static ConfigEntry<string> OpenShockAPIKey;

		public static ConfigEntry<bool> DeveloperMode;

		public static ConfigEntry<int> ShockStrength;

		public static ConfigEntry<float> ShockDuration;

		public static ConfigEntry<bool> ShockOnDeath;

		public static ConfigEntry<bool> ShockOnDamage;

		public static ConfigEntry<bool> ShockOnItemBreak;

		private static readonly ImmutableList<ConfigEntry<string>> RegenOsClientOnChange = new ImmutableList<ConfigEntry<string>>((IList<ConfigEntry<string>>)new List<ConfigEntry<string>>(2) { OpenShockAPIDomain, OpenShockAPIKey });

		public static void Init(ConfigFile config)
		{
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Expected O, but got Unknown
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Expected O, but got Unknown
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Expected O, but got Unknown
			OpenShockAPIDomain = config.Bind<string>(ConfigGroups.Connection, "OpenShock API", "https://api.openshock.app", "The OpenShock instance's API");
			OpenShockAPIKey = config.Bind<string>(ConfigGroups.Connection, "OpenShock API Key", "GO TO YOUR CONFIG FILE TO EDIT", "Go to your config file to edit!");
			DeveloperMode = config.Bind<bool>(ConfigGroups.Misc, "Developer Mode", false, new ConfigDescription("Beeps Only", (AcceptableValueBase)null, new object[1] { "HideFromREPOConfig" }));
			ShockStrength = config.Bind<int>(ConfigGroups.General, "Shock Strength", 20, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
			ShockDuration = config.Bind<float>(ConfigGroups.General, "Shock Duration", 0.3f, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.3f, 30f), Array.Empty<object>()));
			ShockOnDeath = config.Bind<bool>(ConfigGroups.ShockEvents, "Shock On Death", true, "Do you want to be shocked on death?");
			ShockOnDamage = config.Bind<bool>(ConfigGroups.ShockEvents, "Shock On Damage", true, "Shock on damage proportionate to how low you are");
			ShockOnItemBreak = config.Bind<bool>(ConfigGroups.ShockEvents, "Shock On Item Break", true, "Shocks you when an item breaks, proportionate to how much health the item had");
		}
	}
	internal static class ModGlobals
	{
		private static float _lastLevelMessage = Time.time;

		internal static GameObject? LastOffensiveObject = null;

		internal static float LastOffensiveGracePeriodTime = 0f;

		internal static readonly Dictionary<GameObject, float> RecentlyHeldObjects = new Dictionary<GameObject, float>();

		internal static bool IsAlive { get; set; } = true;


		internal static string CurrentLevel { get; set; } = "";


		internal static bool IsSafeLevel { get; set; } = true;


		internal static float LastHeldItemPickupTime { get; set; } = Time.time;


		internal static void UpdateLevel(string level)
		{
			CurrentLevel = level;
			EvaluateIsSafeLevel();
			if (!(_lastLevelMessage < 3f))
			{
				ReOpenShock.Instance.Logger.LogInfo((object)("Updating Level to " + level + " - Resetting Mod Global Variables"));
				_lastLevelMessage = Time.time;
			}
		}

		private static void EvaluateIsSafeLevel()
		{
			bool flag = false;
			if (!SemiFunc.IsMultiplayer())
			{
				flag = CurrentLevel == "Arena";
			}
			IsSafeLevel = CurrentLevel == "Shop" || CurrentLevel == "Lobby" || CurrentLevel == "Lobby Menu" || CurrentLevel == "" || flag;
		}

		internal static void Revive()
		{
			IsAlive = true;
			ReOpenShock.Instance.Logger.LogInfo((object)"Player has been revived.");
		}
	}
	public enum ControlType
	{
		Stop,
		Shock,
		Vibrate,
		Sound
	}
	public class ControlRequest
	{
		public IEnumerable<Control> Shocks { get; set; } = null;


		public string CustomName { get; set; }
	}
	public class Control
	{
		public string Id { get; set; }

		public ControlType Type { get; set; }

		public int Intensity { get; set; }

		public int Duration { get; set; }
	}
	public class DevicesRes
	{
		public string message { get; set; }

		public List<Hub> data { get; set; }
	}
	public class Hub
	{
		public string id { get; set; }

		public string name { get; set; }

		public DateTime createdOn { get; set; }

		public List<Shocker> shockers { get; set; }
	}
	public class Shocker
	{
		public string name { get; set; }

		public bool isPaused { get; set; }

		public DateTime createdOn { get; set; }

		public string id { get; set; }

		public int rfId { get; set; }

		public string model { get; set; }
	}
	public class OpenShockApi
	{
		private static readonly ManualLogSource Logger = Logger.CreateLogSource("OpenShockApi");

		private readonly HttpClient _httpClient;

		public ImmutableList<string> devices = new ImmutableList<string>((IList<string>)new List<string>());

		public OpenShockApi(string apiToken, Uri server)
		{
			HttpClientHandler handler = new HttpClientHandler();
			_httpClient = new HttpClient(handler)
			{
				BaseAddress = server
			};
			_httpClient.DefaultRequestHeaders.Add("User-Agent", "ReOpenShock/1.0.5");
			_httpClient.DefaultRequestHeaders.Add("OpenShockToken", apiToken);
		}

		public async Task Control(List<Control> shocks)
		{
			if (shocks.Count != 0)
			{
				Logger.LogInfo((object)"Sending control request to OpenShock API");
				HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Post, "/2/shockers/control")
				{
					Content = new StringContent(JsonConvert.SerializeObject((object)new ControlRequest
					{
						Shocks = shocks,
						CustomName = "Integrations.ReOpenShock"
					}), Encoding.UTF8, "application/json")
				};
				HttpResponseMessage response = await _httpClient.SendAsync(requestMessage);
				if (!response.IsSuccessStatusCode)
				{
					Logger.LogError((object)$"Failed to send control request to OpenShock API [{response.StatusCode}]");
				}
				else
				{
					Logger.LogInfo((object)"Successfully sent control request");
				}
			}
		}

		public async Task GetDevices()
		{
			if (ModConfig.OpenShockAPIKey.Value == (string)((ConfigEntryBase)ModConfig.OpenShockAPIKey).DefaultValue)
			{
				devices = new ImmutableList<string>((IList<string>)new List<string>());
				return;
			}
			Logger.LogInfo((object)"Sending get devices request to OpenShock API");
			HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Get, "/1/shockers/own");
			HttpResponseMessage response = await _httpClient.SendAsync(requestMessage);
			if (!response.IsSuccessStatusCode)
			{
				Logger.LogError((object)$"Failed to send get devices request to OpenShock API [{response.StatusCode}]");
				return;
			}
			DevicesRes resCl = JsonConvert.DeserializeObject<DevicesRes>(await response.Content.ReadAsStringAsync());
			List<string> shockerIds = new List<string>();
			foreach (Hub hub in resCl.data)
			{
				foreach (Shocker shocker in hub.shockers)
				{
					shockerIds.Add(shocker.id);
				}
			}
			devices = LinqExtensions.ToImmutableList<string>((IEnumerable<string>)shockerIds);
			Logger.LogInfo((object)$"Got {devices.Count} shockers");
		}
	}
	[BepInPlugin("gay.lilyy.ReOpenShock", "ReOpenShock", "1.0.5")]
	public class ReOpenShock : BaseUnityPlugin
	{
		public const string PluginGuid = "gay.lilyy.ReOpenShock";

		public const string PluginName = "ReOpenShock";

		public const string PluginVersion = "1.0.5";

		public static ReOpenShock Instance;

		private Harmony _harmony;

		internal OpenShockApi client;

		public ManualLogSource Logger;

		public async void Awake()
		{
			Instance = this;
			Logger = ((BaseUnityPlugin)this).Logger;
			ModConfig.Init(((BaseUnityPlugin)this).Config);
			Patch();
			Logger.LogInfo((object)"ReOpenShock patched!");
			await MakeClient();
		}

		public async Task MakeClient()
		{
			client = new OpenShockApi(ModConfig.OpenShockAPIKey.Value, new Uri(ModConfig.OpenShockAPIDomain.Value));
			await client.GetDevices();
		}

		private void Patch()
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Expected O, but got Unknown
			if (_harmony == null)
			{
				_harmony = new Harmony("gay.lilyy.ReOpenShock");
			}
			_harmony.PatchAll(typeof(PlayerPatches));
			_harmony.PatchAll(typeof(ValuablePatches));
			_harmony.PatchAll(typeof(ValuablePatches.PhysGrabObjectImpactDetectorPatch));
		}

		public async void ActionShockers(ControlType action, int strength)
		{
			List<Control> actions = new List<Control>();
			foreach (string device in Instance.client.devices)
			{
				actions.Add(new Control
				{
					Id = device,
					Duration = (int)(ModConfig.ShockDuration.Value * 1000f),
					Intensity = strength,
					Type = (ModConfig.DeveloperMode.Value ? ControlType.Sound : action)
				});
			}
			Logger.LogInfo((object)$"Actioning shockers at mode {action} at {strength}% for {ModConfig.ShockDuration}s");
			await Instance.client.Control(actions);
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "ReOpenShock";

		public const string PLUGIN_NAME = "Shocks you in R.E.P.O";

		public const string PLUGIN_VERSION = "1.0.5";
	}
}
namespace ReOpenShock.Patches
{
	public static class PlayerPatches
	{
		private static int _lastHealth;

		[HarmonyPostfix]
		[HarmonyPatch(typeof(PlayerAvatar), "PlayerDeathDone")]
		public static void PlayerDeathDone_PostFix(PlayerAvatar __instance)
		{
			ReOpenShock.Instance.Logger.LogInfo((object)(__instance.playerName + " died"));
			if (__instance.isLocal)
			{
				ReOpenShock.Instance.Logger.LogInfo((object)"Shocking!");
				Task.Run(delegate
				{
					ReOpenShock.Instance.ActionShockers(ModConfig.ShockOnDeath.Value ? ControlType.Shock : ControlType.Vibrate, ModConfig.ShockStrength.Value);
				});
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(PlayerHealth), "Hurt")]
		public static void PlayerHurt_Prefix(PlayerHealth __instance)
		{
			if (!((Component)__instance).GetComponent<PlayerAvatar>().isLocal || !ModConfig.ShockOnDamage.Value)
			{
				return;
			}
			if (_lastHealth < 0)
			{
				_lastHealth = __instance.health;
			}
			if (__instance.health < _lastHealth)
			{
				float num = (1f - (float)__instance.health / (float)__instance.maxHealth) * 100f;
				ReOpenShock.Instance.Logger.LogInfo((object)num);
				int shockValue = Mathf.RoundToInt(num);
				ReOpenShock.Instance.Logger.LogInfo((object)$"Health decreased: {_lastHealth} -> {__instance.health}, sending shock {shockValue}");
				Task.Run(delegate
				{
					ReOpenShock.Instance.ActionShockers(ControlType.Shock, shockValue);
				});
			}
			_lastHealth = __instance.health;
		}
	}
	public static class ValuablePatches
	{
		[HarmonyPatch(typeof(PhysGrabObjectImpactDetector))]
		public static class PhysGrabObjectImpactDetectorPatch
		{
			private static bool _lastHitEnemy;

			[HarmonyPrefix]
			[HarmonyPatch("OnCollisionStay")]
			private static void OnCollisionStay(ref Collision collision)
			{
				if (((Component)collision.transform).CompareTag("Enemy"))
				{
					_lastHitEnemy = true;
				}
				else
				{
					_lastHitEnemy = false;
				}
			}

			[HarmonyPostfix]
			[HarmonyPatch("BreakRPC")]
			private static void ItemImpactBreakRPC(float valueLost, ref bool _loseValue, int breakLevel, PhysGrabObjectImpactDetector __instance)
			{
				if (ModConfig.ShockOnItemBreak.Value && _loseValue)
				{
					ItemBreakPostfix(valueLost, __instance);
				}
			}

			private static void ItemBreakPostfix(float valueLost, PhysGrabObjectImpactDetector __instance)
			{
				if (!ModGlobals.IsAlive || ModGlobals.CurrentLevel == "Arena" || !__instance.isValuable)
				{
					return;
				}
				bool heldByLocalPlayer = __instance.physGrabObject.heldByLocalPlayer;
				if (heldByLocalPlayer)
				{
					if (!ModGlobals.RecentlyHeldObjects.ContainsKey(((Component)__instance).gameObject))
					{
						ModGlobals.RecentlyHeldObjects.Add(((Component)__instance).gameObject, Time.time);
						ReOpenShock.Instance.Logger.LogInfo((object)("Object " + ((Object)((Component)__instance).gameObject).name + " added to held objects."));
					}
					else
					{
						ModGlobals.RecentlyHeldObjects[((Component)__instance).gameObject] = Time.time;
					}
				}
				float dollarValueOriginal = __instance.valuableObject.dollarValueOriginal;
				ShockPlayerIfNecessary(((Component)__instance).gameObject, valueLost, dollarValueOriginal, heldByLocalPlayer);
			}

			private static void ShockPlayerIfNecessary(GameObject damagedObject, float valueLost, float originalValue, bool isHeldByLocalPlayer)
			{
				if (ModGlobals.RecentlyHeldObjects.ContainsKey(damagedObject))
				{
					float num = ModGlobals.RecentlyHeldObjects[damagedObject];
					if (isHeldByLocalPlayer && _lastHitEnemy)
					{
						ModGlobals.LastOffensiveGracePeriodTime = Time.time;
						ModGlobals.LastOffensiveObject = damagedObject;
						ReOpenShock.Instance.Logger.LogInfo((object)"[Damage Item Event] Enemy hit, aborting shock");
					}
					else if (_lastHitEnemy && Time.time - num <= 2f)
					{
						ModGlobals.LastOffensiveGracePeriodTime = Time.time;
						ModGlobals.LastOffensiveObject = damagedObject;
						ReOpenShock.Instance.Logger.LogInfo((object)"[Damage Item Event] Enemy hit in thrown grace period, aborting shock");
					}
					else if ((Object)(object)ModGlobals.LastOffensiveObject == (Object)(object)damagedObject && Time.time - ModGlobals.LastOffensiveGracePeriodTime <= 3f)
					{
						ReOpenShock.Instance.Logger.LogInfo((object)"[Damage Item Event] Recently used 'weapon' took damage, aborting shock");
					}
					else if (Time.time - num <= 4f)
					{
						ShockPlayer(valueLost, originalValue, ((Object)damagedObject).name);
					}
				}
			}

			private static void ShockPlayer(float valueLost, float originalValue, string objName)
			{
				int num = MapValue(valueLost, 0f, originalValue, 0f, ModConfig.ShockStrength.Value);
				ReOpenShock.Instance.Logger.LogInfo((object)$"[Damage Item Event] Played damaged {objName} for {valueLost} - Shocking for {num}%");
				ReOpenShock.Instance.ActionShockers(ControlType.Shock, num);
			}

			private static int MapValue(float value, float start1, float stop1, float start2, float stop2)
			{
				return (int)(start1 + (value - start1) * (stop2 - start2) / (stop1 - start1));
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(PhysGrabObject), "GrabEnded")]
		private static void GrabEndedPostFix(PhysGrabObject __instance)
		{
			if (__instance.isValuable && __instance.heldByLocalPlayer)
			{
				ModGlobals.LastHeldItemPickupTime = Time.time;
				ModGlobals.LastOffensiveGracePeriodTime = 0f;
				if (!ModGlobals.RecentlyHeldObjects.ContainsKey(((Component)__instance).gameObject))
				{
					ModGlobals.RecentlyHeldObjects.Add(((Component)__instance).gameObject, Time.time);
					ReOpenShock.Instance.Logger.LogInfo((object)("Added " + ((Object)((Component)__instance).gameObject).name + " to recently held"));
				}
				else
				{
					ModGlobals.RecentlyHeldObjects[((Component)__instance).gameObject] = Time.time;
					ReOpenShock.Instance.Logger.LogInfo((object)("Updated " + ((Object)((Component)__instance).gameObject).name + " in recently held"));
				}
			}
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}