Decompiled source of FullAuto v1.3.0

BepInEx/plugins/FullAutoMod.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.InputSystem.Utilities;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[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.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("MycopunkModder")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("Makes all semi-auto weapons fully automatic")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0.0")]
[assembly: AssemblyProduct("FullAutoMod")]
[assembly: AssemblyTitle("FullAutoMod")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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 FullAutoMod
{
	[BepInPlugin("fullautomod.mycopunk", "FullAutoMod", "1.0.0.0")]
	[BepInProcess("Mycopunk.exe")]
	[MycoMod(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		private enum FireMode
		{
			Default,
			ForceFullAuto
		}

		[HarmonyPatch]
		private class PatchGunUpdate
		{
			private static MethodBase TargetMethod()
			{
				return _gunUpdate;
			}

			[HarmonyPrefix]
			private static void Prefix(object __instance)
			{
				if (!_resolved || __instance == null)
				{
					return;
				}
				int hashCode = __instance.GetHashCode();
				if (!_gunFireModes.TryGetValue(hashCode, out var value) || value != FireMode.ForceFullAuto || !_fireActionHooked || _fireAction == null)
				{
					return;
				}
				bool flag;
				try
				{
					flag = _fireAction.IsPressed();
				}
				catch
				{
					_fireActionHooked = false;
					_fireAction = null;
					return;
				}
				if (!flag)
				{
					return;
				}
				object obj2;
				try
				{
					obj2 = _gunPlayer?.GetValue(__instance, null);
				}
				catch
				{
					return;
				}
				if (obj2 == null)
				{
					return;
				}
				bool flag2;
				try
				{
					flag2 = (bool)_gunActive.GetValue(__instance, null);
				}
				catch
				{
					return;
				}
				if (!flag2)
				{
					return;
				}
				float num;
				bool flag3;
				try
				{
					num = (float)_gunRemainingAmmo.GetValue(__instance, null);
					flag3 = (bool)_gunCanFireWithoutAmmo.GetValue(__instance, null);
				}
				catch
				{
					return;
				}
				if (!(num <= 0f) || flag3)
				{
					bool flag4;
					try
					{
						flag4 = (bool)_gunReloading.GetValue(__instance, null);
					}
					catch
					{
						return;
					}
					if (!flag4)
					{
						_gunIsFireInputHeld.SetValue(__instance, true);
					}
				}
			}
		}

		public const string PluginGUID = "fullautomod.mycopunk";

		public const string PluginName = "FullAutoMod";

		public const string PluginVersion = "1.0.0.0";

		internal static ManualLogSource Logger;

		private static ConfigEntry<string> _toggleKeyConfig;

		private static ConfigEntry<int> _popupYOffsetConfig;

		private static Type _gunType;

		private static MethodInfo _gunUpdate;

		private static FieldInfo _gunIsFireInputHeld;

		private static PropertyInfo _gunRemainingAmmo;

		private static PropertyInfo _gunCanFireWithoutAmmo;

		private static PropertyInfo _gunReloading;

		private static PropertyInfo _gunPlayer;

		private static PropertyInfo _gunActive;

		private static bool _resolved;

		private static InputAction _fireAction;

		private static bool _fireActionHooked;

		private static readonly Dictionary<int, FireMode> _gunFireModes = new Dictionary<int, FireMode>();

		private static object _cachedGun;

		private static float _lastGunQuery;

		private const float GUN_CACHE = 0.25f;

		private static bool _toggleKeyDown;

		private static bool _toggleKeyWasDown;

		private static float _toggleHoldTime;

		private const float TOGGLE_HOLD_THRESHOLD = 1f;

		private static bool _toggleExecutedAsHold;

		private static string _cachedKeyName = "";

		private static Key _cachedInputSystemKey;

		private static bool _toggleKeyParseWarned;

		private static GameObject _popupCanvas;

		private static Text _popupText;

		private static CanvasGroup _popupGroup;

		private static RectTransform _popupBgRect;

		private static float _popupShowTime;

		private const float POPUP_AUTO_FADE = 0.5f;

		private static bool _popupReady;

		private static FileSystemWatcher _configWatcher;

		private static volatile bool _pendingConfigReload;

		private static Key ParseKeyName(string name)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: 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_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrEmpty(name))
			{
				return (Key)10;
			}
			if (Enum.TryParse<Key>(name, ignoreCase: true, out Key result))
			{
				return result;
			}
			return (Key)10;
		}

		private static Key GetCurrentToggleKey()
		{
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: 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_0088: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				string value = _toggleKeyConfig.Value;
				if (value != _cachedKeyName)
				{
					_cachedKeyName = value;
					_cachedInputSystemKey = ParseKeyName(value);
					Logger.LogDebug((object)$"ToggleKey re-parsed: \"{value}\" → {_cachedInputSystemKey}");
				}
				return _cachedInputSystemKey;
			}
			catch
			{
				if (!_toggleKeyParseWarned)
				{
					_toggleKeyParseWarned = true;
					ManualLogSource logger = Logger;
					if (logger != null)
					{
						logger.LogWarning((object)"Failed to read ToggleKey from config; falling back to Backslash");
					}
				}
				return (Key)10;
			}
		}

		private void Awake()
		{
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Expected O, but got Unknown
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			Logger = ((BaseUnityPlugin)this).Logger;
			Logger.LogInfo((object)"Full Auto Mod loading...");
			_toggleKeyConfig = ((BaseUnityPlugin)this).Config.Bind<string>("General", "ToggleKey", "Backslash", "Key to toggle fire mode per weapon.\nUse standard key names (Backslash, I, F10, Space, etc.).\nQuick press (< 1s): toggle fire mode on release.\nHold (>= 1s): preview current mode popup.");
			_popupYOffsetConfig = ((BaseUnityPlugin)this).Config.Bind<int>("UI", "PopupYOffset", 60, new ConfigDescription("Vertical offset of the fire mode popup (positive = below crosshair)", (AcceptableValueBase)(object)new AcceptableValueRange<int>(-200, 200), Array.Empty<object>()));
			((BaseUnityPlugin)this).Config.Save();
			_toggleKeyConfig.SettingChanged += delegate
			{
				_cachedKeyName = "";
				Logger.LogInfo((object)"ToggleKey config changed — applying immediately.");
			};
			_popupYOffsetConfig.SettingChanged += delegate
			{
				UpdatePopupPosition();
				Logger.LogDebug((object)"PopupYOffset config changed — repositioning.");
			};
			_cachedKeyName = _toggleKeyConfig.Value;
			_cachedInputSystemKey = ParseKeyName(_cachedKeyName);
			try
			{
				_configWatcher = new FileSystemWatcher(Paths.ConfigPath, "fullautomod.mycopunk.cfg")
				{
					NotifyFilter = (NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.LastWrite),
					EnableRaisingEvents = true
				};
				_configWatcher.Changed += OnConfigFileChanged;
				_configWatcher.Created += OnConfigFileChanged;
				_configWatcher.Renamed += OnConfigFileChanged;
				Logger.LogInfo((object)"Config file watcher started.");
			}
			catch (Exception ex)
			{
				Logger.LogWarning((object)("Could not start config file watcher: " + ex.Message));
			}
			ResolveGunType();
			if (_resolved)
			{
				Harmony.CreateAndPatchAll(typeof(PatchGunUpdate), (string)null);
			}
			SceneManager.sceneLoaded += OnSceneLoaded;
			CreatePopupUI();
			Logger.LogInfo((object)"Full Auto Mod initialized.");
			Logger.LogInfo((object)("Toggle key: \"" + _cachedKeyName + "\" (live config, no restart needed)"));
		}

		private void OnConfigFileChanged(object sender, FileSystemEventArgs e)
		{
			_pendingConfigReload = true;
		}

		private void OnDestroy()
		{
			if (_configWatcher != null)
			{
				_configWatcher.EnableRaisingEvents = false;
				_configWatcher.Changed -= OnConfigFileChanged;
				_configWatcher.Created -= OnConfigFileChanged;
				_configWatcher.Renamed -= OnConfigFileChanged;
				_configWatcher.Dispose();
				_configWatcher = null;
			}
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			_fireActionHooked = false;
			_fireAction = null;
			_cachedGun = null;
			_gunFireModes.Clear();
		}

		private void Update()
		{
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Invalid comparison between Unknown and I4
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			if (_pendingConfigReload)
			{
				_pendingConfigReload = false;
				try
				{
					((BaseUnityPlugin)this).Config.Reload();
					Logger.LogInfo((object)"Config reloaded from disk.");
				}
				catch (Exception ex)
				{
					Logger.LogError((object)("Error reloading config: " + ex.Message));
				}
			}
			if (!_resolved)
			{
				ResolveGunType();
				return;
			}
			if (!_fireActionHooked)
			{
				HookFireAction();
			}
			bool flag = false;
			if (Keyboard.current != null)
			{
				Key currentToggleKey = GetCurrentToggleKey();
				if ((int)currentToggleKey > 0)
				{
					KeyControl val = Keyboard.current[currentToggleKey];
					if (val != null)
					{
						flag = ((ButtonControl)val).isPressed;
					}
				}
			}
			if (flag && !_toggleKeyWasDown)
			{
				_toggleHoldTime = 0f;
				_toggleExecutedAsHold = false;
			}
			if (flag)
			{
				_toggleHoldTime += Time.unscaledDeltaTime;
				if (_toggleHoldTime >= 1f && !_toggleExecutedAsHold)
				{
					_toggleExecutedAsHold = true;
					object obj = FindHeldGun();
					if (obj != null)
					{
						ShowPopup(GetCurrentModeLabel(obj), keepOpen: true);
					}
				}
			}
			if (!flag && _toggleKeyWasDown)
			{
				if (_toggleHoldTime < 1f)
				{
					OnTogglePressed();
				}
				else if (_toggleExecutedAsHold)
				{
					HidePopup();
				}
				_toggleHoldTime = 0f;
				_toggleExecutedAsHold = false;
			}
			_toggleKeyDown = flag;
			_toggleKeyWasDown = flag;
			if (_popupReady && (Object)(object)_popupGroup != (Object)null && _popupGroup.alpha > 0f && !_toggleKeyDown)
			{
				float num = Time.unscaledTime - _popupShowTime;
				if (num > 1f)
				{
					_popupGroup.alpha = 0f;
					_popupCanvas.SetActive(false);
				}
				else if (num > 0.5f)
				{
					float num2 = (num - 0.5f) / 0.5f;
					_popupGroup.alpha = 1f - num2;
				}
			}
		}

		private string GetCurrentModeLabel(object gun)
		{
			int hashCode = gun.GetHashCode();
			FireMode fireMode = FireMode.Default;
			if (_gunFireModes.TryGetValue(hashCode, out var value))
			{
				fireMode = value;
			}
			if (fireMode == FireMode.ForceFullAuto)
			{
				return "Full-Auto (Override)";
			}
			return GetDefaultModeLabel(gun);
		}

		private void OnTogglePressed()
		{
			object obj = FindHeldGun();
			if (obj != null)
			{
				int hashCode = obj.GetHashCode();
				FireMode fireMode = FireMode.Default;
				if (_gunFireModes.TryGetValue(hashCode, out var value))
				{
					fireMode = value;
				}
				if (fireMode == FireMode.Default)
				{
					_gunFireModes[hashCode] = FireMode.ForceFullAuto;
					ShowPopup("Full-Auto (Override)", keepOpen: false);
				}
				else
				{
					_gunFireModes.Remove(hashCode);
					ShowPopup(GetDefaultModeLabel(obj), keepOpen: false);
				}
			}
		}

		private static string GetDefaultModeLabel(object gun)
		{
			return "Default";
		}

		private void CreatePopupUI()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Expected O, but got Unknown
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Expected O, but got Unknown
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_0202: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				_popupCanvas = new GameObject("FAM_PopupCanvas");
				Object.DontDestroyOnLoad((Object)(object)_popupCanvas);
				Canvas val = _popupCanvas.AddComponent<Canvas>();
				val.renderMode = (RenderMode)0;
				val.sortingOrder = 31000;
				CanvasScaler val2 = _popupCanvas.AddComponent<CanvasScaler>();
				val2.uiScaleMode = (ScaleMode)1;
				val2.referenceResolution = new Vector2(1920f, 1080f);
				val2.screenMatchMode = (ScreenMatchMode)0;
				val2.matchWidthOrHeight = 0.5f;
				_popupGroup = _popupCanvas.AddComponent<CanvasGroup>();
				_popupGroup.alpha = 0f;
				GameObject val3 = new GameObject("PopupBG");
				val3.transform.SetParent(_popupCanvas.transform, false);
				_popupBgRect = val3.AddComponent<RectTransform>();
				_popupBgRect.anchorMin = new Vector2(0.5f, 0.5f);
				_popupBgRect.anchorMax = new Vector2(0.5f, 0.5f);
				_popupBgRect.pivot = new Vector2(0.5f, 0.5f);
				_popupBgRect.sizeDelta = new Vector2(260f, 34f);
				UpdatePopupPosition();
				Image val4 = val3.AddComponent<Image>();
				((Graphic)val4).color = new Color(0.015f, 0.015f, 0.018f, 0.82f);
				GameObject val5 = new GameObject("PopupText");
				val5.transform.SetParent(val3.transform, false);
				RectTransform val6 = val5.AddComponent<RectTransform>();
				val6.anchorMin = Vector2.zero;
				val6.anchorMax = Vector2.one;
				val6.offsetMin = Vector2.zero;
				val6.offsetMax = Vector2.zero;
				_popupText = val5.AddComponent<Text>();
				_popupText.font = Resources.GetBuiltinResource<Font>("Arial.ttf");
				_popupText.fontSize = 18;
				_popupText.fontStyle = (FontStyle)1;
				_popupText.alignment = (TextAnchor)4;
				((Graphic)_popupText).color = Color.white;
				_popupText.text = "";
				_popupCanvas.SetActive(false);
				_popupReady = true;
			}
			catch (Exception ex)
			{
				Logger.LogError((object)("CreatePopupUI: " + ex.Message));
			}
		}

		private void UpdatePopupPosition()
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_popupBgRect != (Object)null)
			{
				float num = ((_popupYOffsetConfig != null) ? _popupYOffsetConfig.Value : 60);
				_popupBgRect.anchoredPosition = new Vector2(0f, 0f - num);
			}
		}

		private void ShowPopup(string text, bool keepOpen)
		{
			if (_popupReady && !((Object)(object)_popupText == (Object)null) && !((Object)(object)_popupGroup == (Object)null))
			{
				UpdatePopupPosition();
				_popupText.text = text;
				_popupGroup.alpha = 1f;
				_popupCanvas.SetActive(true);
				if (!keepOpen)
				{
					_popupShowTime = Time.unscaledTime;
				}
			}
		}

		private void HidePopup()
		{
			if (_popupReady && !((Object)(object)_popupGroup == (Object)null))
			{
				_popupGroup.alpha = 0f;
				_popupCanvas.SetActive(false);
			}
		}

		private static object FindHeldGun()
		{
			float unscaledTime = Time.unscaledTime;
			if (_cachedGun != null && unscaledTime - _lastGunQuery < 0.25f)
			{
				return _cachedGun;
			}
			_lastGunQuery = unscaledTime;
			_cachedGun = null;
			Type type = Type.GetType("Pigeon.Movement.Player, Assembly-CSharp");
			if (type == null)
			{
				return null;
			}
			PropertyInfo property = type.GetProperty("LocalPlayer", BindingFlags.Static | BindingFlags.Public);
			if (property == null)
			{
				return null;
			}
			object value = property.GetValue(null, null);
			if (value == null)
			{
				return null;
			}
			Object[] array = Resources.FindObjectsOfTypeAll(_gunType);
			Object[] array2 = array;
			foreach (object obj in array2)
			{
				if (obj == null)
				{
					continue;
				}
				try
				{
					object obj2 = _gunPlayer?.GetValue(obj, null);
					bool flag = (bool)(_gunActive?.GetValue(obj, null) ?? ((object)false));
					if (obj2 == value && flag)
					{
						_cachedGun = obj;
						return obj;
					}
				}
				catch
				{
				}
			}
			return null;
		}

		private void ResolveGunType()
		{
			try
			{
				Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
				foreach (Assembly assembly in assemblies)
				{
					if (assembly.GetName().Name != "Assembly-CSharp")
					{
						continue;
					}
					_gunType = assembly.GetType("Gun");
					if (_gunType == null)
					{
						Logger.LogWarning((object)"Gun not found");
						break;
					}
					Logger.LogInfo((object)("Gun: " + _gunType.FullName));
					BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
					_gunUpdate = _gunType.GetMethod("Update", bindingAttr);
					_gunIsFireInputHeld = _gunType.GetField("isFireInputHeld", bindingAttr);
					_gunRemainingAmmo = _gunType.GetProperty("RemainingAmmo", bindingAttr);
					_gunCanFireWithoutAmmo = _gunType.GetProperty("CanFireWithoutAmmo", bindingAttr);
					_gunReloading = _gunType.GetProperty("Reloading", bindingAttr);
					_gunPlayer = _gunType.GetProperty("Player", bindingAttr);
					_gunActive = _gunType.GetProperty("Active", bindingAttr);
					if (_gunUpdate == null || _gunIsFireInputHeld == null)
					{
						Logger.LogError((object)"Missing critical members");
					}
					else
					{
						_resolved = true;
					}
					break;
				}
			}
			catch (Exception ex)
			{
				Logger.LogError((object)("Init: " + ex.Message));
			}
		}

		private void HookFireAction()
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				InputActionAsset[] array = Resources.FindObjectsOfTypeAll<InputActionAsset>();
				InputActionAsset[] array2 = array;
				foreach (InputActionAsset val in array2)
				{
					Enumerator<InputActionMap> enumerator = val.actionMaps.GetEnumerator();
					try
					{
						while (enumerator.MoveNext())
						{
							InputActionMap current = enumerator.Current;
							if (_fireAction == null)
							{
								_fireAction = current.FindAction("Fire", false);
								if (_fireAction != null)
								{
									_fireAction.Enable();
								}
							}
						}
					}
					finally
					{
						((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
					}
				}
				if (_fireAction != null)
				{
					_fireActionHooked = true;
				}
			}
			catch (Exception ex)
			{
				Logger.LogWarning((object)("HookFire: " + ex.Message));
			}
		}
	}
}