Decompiled source of AlwaysSprint v1.4.0

BepInEx/plugins/AlwaysSprintMod.dll

Decompiled 4 hours ago
using System;
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 Microsoft.CodeAnalysis;
using Pigeon.Movement;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Utilities;
using UnityEngine.SceneManagement;

[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("Always sprint by default - inverts the sprint input action")]
[assembly: AssemblyFileVersion("1.3.0.0")]
[assembly: AssemblyInformationalVersion("1.3.0.0")]
[assembly: AssemblyProduct("AlwaysSprintMod")]
[assembly: AssemblyTitle("AlwaysSprintMod")]
[assembly: AssemblyVersion("1.3.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 AlwaysSprintMod
{
	[BepInPlugin("coruscnium.alwayssprint", "AlwaysSprint", "1.4.0.0")]
	[BepInProcess("Mycopunk.exe")]
	[MycoMod(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		internal static ManualLogSource Logger;

		private static FieldInfo _isTryingToSprintField;

		private static FieldInfo _wantsToSprintField;

		private static bool _fieldsResolved;

		private static InputAction _sprintAction;

		private static InputAction _fireAction;

		private static bool _actionHooked;

		private static bool _walkToggled;

		private static bool _lastSprintButtonState;

		private static FieldInfo _gunDataField;

		private static FieldInfo _fireConstraintsField;

		private static FieldInfo _canFireWhileSprintingField;

		private static FieldInfo _gunOwnerField;

		private static object _canPerformDuringValue;

		private static bool _gunReflectionResolved;

		private static ConfigEntry<float> _reSprintDelayMsConfig;

		private static bool _wasFiring;

		private static float _fireStoppedTime;

		private static FileSystemWatcher _configWatcher;

		private static volatile bool _pendingConfigReload;

		private void Awake()
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Expected O, but got Unknown
			Logger = ((BaseUnityPlugin)this).Logger;
			Logger.LogInfo((object)"AlwaysSprintMod loading...");
			_reSprintDelayMsConfig = ((BaseUnityPlugin)this).Config.Bind<float>("SprintSuppression", "ReSprintDelayMs", 300f, new ConfigDescription("Delay (ms) after releasing the fire button before sprint resumes.\nSet to 0 for instant re-sprint (v1.3 behavior).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1000f), Array.Empty<object>()));
			((BaseUnityPlugin)this).Config.Save();
			_reSprintDelayMsConfig.SettingChanged += delegate
			{
				Logger.LogDebug((object)"ReSprintDelayMs config changed — applying immediately.");
			};
			try
			{
				_configWatcher = new FileSystemWatcher(Paths.ConfigPath, "coruscnium.alwayssprint.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));
			}
			ResolveFields();
			ResolveGunReflection();
			SceneManager.sceneLoaded += OnSceneLoaded;
			Logger.LogInfo((object)"AlwaysSprintMod initialized.");
		}

		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)
		{
			_actionHooked = false;
			_sprintAction = null;
			_fireAction = null;
			_walkToggled = false;
			_lastSprintButtonState = false;
			_wasFiring = false;
			_fireStoppedTime = 0f;
		}

		private void Update()
		{
			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 (!_fieldsResolved)
			{
				ResolveFields();
				return;
			}
			if (!_actionHooked)
			{
				TryHookActions();
			}
			Player localPlayer = Player.LocalPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return;
			}
			if (_sprintAction != null)
			{
				bool flag = false;
				try
				{
					flag = _sprintAction.IsPressed();
				}
				catch
				{
					_sprintAction = null;
					return;
				}
				if (flag && !_lastSprintButtonState)
				{
					_walkToggled = !_walkToggled;
				}
				_lastSprintButtonState = flag;
			}
			bool flag2 = _fireAction != null && _fireAction.IsPressed();
			if (!flag2 && _wasFiring)
			{
				_fireStoppedTime = Time.unscaledTime;
			}
			bool flag3;
			if (CheckCanFireWhileSprinting())
			{
				flag3 = !_walkToggled;
			}
			else if (flag2)
			{
				flag3 = false;
			}
			else
			{
				float num = _reSprintDelayMsConfig.Value / 1000f;
				flag3 = !(Time.unscaledTime - _fireStoppedTime < num) && !_walkToggled;
			}
			if (_isTryingToSprintField != null)
			{
				_isTryingToSprintField.SetValue(localPlayer, flag3);
			}
			if (_wantsToSprintField != null)
			{
				_wantsToSprintField.SetValue(localPlayer, flag3);
			}
			_wasFiring = flag2;
		}

		private bool CheckCanFireWhileSprinting()
		{
			if (!_gunReflectionResolved || _gunDataField == null)
			{
				return false;
			}
			try
			{
				Player localPlayer = Player.LocalPlayer;
				if ((Object)(object)localPlayer == (Object)null)
				{
					return false;
				}
				Gun[] array = Object.FindObjectsOfType<Gun>();
				Gun[] array2 = array;
				foreach (Gun val in array2)
				{
					if ((Object)(object)val == (Object)null)
					{
						continue;
					}
					if (_gunOwnerField != null)
					{
						object value = _gunOwnerField.GetValue(val);
						Player val2 = (Player)((value is Player) ? value : null);
						if (val2 != null && (Object)(object)val2 != (Object)(object)localPlayer)
						{
							continue;
						}
					}
					object value2 = _gunDataField.GetValue(val);
					if (value2 == null)
					{
						continue;
					}
					object value3 = _fireConstraintsField.GetValue(value2);
					if (value3 != null)
					{
						object value4 = _canFireWhileSprintingField.GetValue(value3);
						if (value4 != null && value4.Equals(_canPerformDuringValue))
						{
							return true;
						}
					}
				}
			}
			catch (Exception ex)
			{
				Logger.LogWarning((object)("CheckCanFireWhileSprinting error: " + ex.Message));
			}
			return false;
		}

		private void ResolveFields()
		{
			Type typeFromHandle = typeof(Player);
			_isTryingToSprintField = typeFromHandle.GetField("isTryingToSprint", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			_wantsToSprintField = typeFromHandle.GetField("wantsToSprint", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			Logger.LogInfo((object)$"AlwaysSprintMod - isTryingToSprint: {_isTryingToSprintField != null}");
			Logger.LogInfo((object)$"AlwaysSprintMod - wantsToSprint: {_wantsToSprintField != null}");
			_fieldsResolved = _isTryingToSprintField != null && _wantsToSprintField != null;
			if (_fieldsResolved)
			{
				Logger.LogInfo((object)"AlwaysSprintMod - fields resolved successfully.");
			}
			else
			{
				Logger.LogWarning((object)"AlwaysSprintMod - failed to resolve one or more sprint fields!");
			}
		}

		private void ResolveGunReflection()
		{
			try
			{
				Type typeFromHandle = typeof(Gun);
				_gunDataField = typeFromHandle.GetField("gunData", BindingFlags.Instance | BindingFlags.NonPublic);
				if (_gunDataField == null)
				{
					Logger.LogWarning((object)"AlwaysSprintMod - gunData field not found on Gun.");
					return;
				}
				Type fieldType = _gunDataField.FieldType;
				_fireConstraintsField = fieldType.GetField("fireConstraints", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (_fireConstraintsField == null)
				{
					Logger.LogWarning((object)"AlwaysSprintMod - fireConstraints field not found on GunData.");
					return;
				}
				Type fieldType2 = _fireConstraintsField.FieldType;
				_canFireWhileSprintingField = fieldType2.GetField("canFireWhileSprinting", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (_canFireWhileSprintingField == null)
				{
					Logger.LogWarning((object)"AlwaysSprintMod - canFireWhileSprinting field not found on FireConstraints.");
					return;
				}
				Type fieldType3 = _canFireWhileSprintingField.FieldType;
				if (fieldType3.IsEnum)
				{
					_canPerformDuringValue = Enum.Parse(fieldType3, "CanPerformDuring");
					_gunOwnerField = typeFromHandle.GetField("_owner", BindingFlags.Instance | BindingFlags.NonPublic) ?? typeFromHandle.GetField("owner", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? typeFromHandle.GetField("player", BindingFlags.Instance | BindingFlags.NonPublic) ?? typeFromHandle.GetField("_player", BindingFlags.Instance | BindingFlags.NonPublic) ?? typeFromHandle.GetField("m_Owner", BindingFlags.Instance | BindingFlags.NonPublic);
					if (_gunOwnerField != null && _gunOwnerField.FieldType != typeof(Player))
					{
						Logger.LogWarning((object)("AlwaysSprintMod - gun owner field '" + _gunOwnerField.Name + "' is not Player type (got " + _gunOwnerField.FieldType.Name + "), will check all guns."));
						_gunOwnerField = null;
					}
					_gunReflectionResolved = true;
					Logger.LogInfo((object)("AlwaysSprintMod - gun fire-constraint reflection resolved. Owner field: " + ((_gunOwnerField != null) ? _gunOwnerField.Name : "none (checks all guns)")));
				}
				else
				{
					Logger.LogWarning((object)"AlwaysSprintMod - canFireWhileSprinting is not an enum type.");
				}
			}
			catch (Exception ex)
			{
				Logger.LogWarning((object)("AlwaysSprintMod - error resolving gun reflection: " + ex.Message));
				_gunReflectionResolved = false;
			}
		}

		private void TryHookActions()
		{
			//IL_0019: 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_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: 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 (_sprintAction == null)
							{
								_sprintAction = current.FindAction("Sprint", false);
								if (_sprintAction != null)
								{
									_sprintAction.Enable();
									Logger.LogInfo((object)("Hooked Sprint from '" + ((Object)val).name + "/" + current.name + "'"));
								}
							}
							if (_fireAction == null)
							{
								_fireAction = current.FindAction("Fire", false);
								if (_fireAction != null)
								{
									_fireAction.Enable();
									Logger.LogInfo((object)("Hooked Fire from '" + ((Object)val).name + "/" + current.name + "'"));
								}
							}
						}
					}
					finally
					{
						((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
					}
				}
				if (_sprintAction != null && _fireAction != null)
				{
					_actionHooked = true;
				}
			}
			catch (Exception ex)
			{
				Logger.LogWarning((object)("Error hooking actions: " + ex.Message));
			}
		}
	}
}