Decompiled source of AutoReloadPlus v1.1.3

AutoReloadPlus.dll

Decompiled 2 months ago
using System;
using System.Collections;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using Agents;
using AutoReloadPlus.Utils;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using BepInEx.Unity.IL2CPP.Utils.Collections;
using GTFO.API.Utilities;
using GameData;
using Gear;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppSystem;
using Microsoft.CodeAnalysis;
using Player;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("AutoReloadPlus")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+fb2f9fac3e22790e0fa2f8c0dc5db0939c61c1c7")]
[assembly: AssemblyProduct("AutoReloadPlus")]
[assembly: AssemblyTitle("AutoReloadPlus")]
[assembly: AssemblyVersion("1.0.0.0")]
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;
		}
	}
}
namespace AutoReloadPlus
{
	internal static class AutoReloadPatch
	{
		private static BulletWeaponArchetype? _cachedArchetype;

		private static IInteractable? _cachedInteract;

		private static Interact_Timed? _cachedInteractTimed;

		private static Coroutine? _autoReloadRoutine;

		private static bool _haltAutoReloads;

		private static int _emptyClicks;

		private static float _heldEmptyTimer;

		private static float _emptyTimer;

		private static float _emptyShotTimer;

		private static bool ShouldTriggerReload()
		{
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Invalid comparison between Unknown and I4
			if (_cachedArchetype == null || !((PlayerInventoryBase)((Weapon)_cachedArchetype.m_weapon).m_inventory).CanReloadCurrent())
			{
				return false;
			}
			if (Configuration.autoReloadAimingInstant && (PlayerLocomotion.AimToggleLock || InputMapper.GetButton.Invoke((InputAction)7, (eFocusState)4)))
			{
				return true;
			}
			if (_emptyClicks >= Configuration.clicksToReload && CanCountClicks())
			{
				return true;
			}
			if (_haltAutoReloads)
			{
				return false;
			}
			if (CanTimeAutoReloads())
			{
				if ((int)_cachedArchetype.m_archetypeData.FireMode == 2)
				{
					if (Configuration.autoReloadDelayHoldAuto >= 0f && _heldEmptyTimer >= Configuration.autoReloadDelayHoldAuto)
					{
						return true;
					}
					if (Configuration.autoReloadDelayAuto >= 0f && _emptyTimer >= Configuration.autoReloadDelayAuto)
					{
						return true;
					}
				}
				else if (Configuration.autoReloadDelaySemi >= 0f && _emptyTimer >= Configuration.autoReloadDelaySemi)
				{
					return true;
				}
			}
			return false;
		}

		private static bool CanCountClicks()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Invalid comparison between Unknown and I4
			if (_cachedArchetype == null)
			{
				return false;
			}
			if ((int)_cachedArchetype.m_archetypeData.FireMode == 2)
			{
				if (!Configuration.autoReloadBypassDelayAuto)
				{
					if (Clock.Time > _cachedArchetype.m_nextBurstTimer)
					{
						return Clock.Time > _emptyShotTimer;
					}
					return false;
				}
				return true;
			}
			if (!Configuration.clicksBypassDelay)
			{
				return Clock.Time > _cachedArchetype.m_nextBurstTimer;
			}
			return true;
		}

		private static bool CanTimeAutoReloads()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Invalid comparison between Unknown and I4
			if (_cachedArchetype == null)
			{
				return false;
			}
			if ((int)_cachedArchetype.m_archetypeData.FireMode == 2)
			{
				if (!Configuration.autoReloadBypassDelayAuto)
				{
					if (Clock.Time > _cachedArchetype.m_nextBurstTimer)
					{
						return Clock.Time > _emptyShotTimer;
					}
					return false;
				}
				return true;
			}
			if (!Configuration.autoReloadBypassDelaySemi)
			{
				return Clock.Time > _cachedArchetype.m_nextBurstTimer;
			}
			return true;
		}

		private static void Reset()
		{
			_haltAutoReloads = false;
			_heldEmptyTimer = 0f;
			_emptyTimer = 0f;
			_emptyClicks = 0;
			_emptyShotTimer = 0f;
		}

		[HarmonyPatch(typeof(BulletWeaponArchetype), "OnWield")]
		[HarmonyWrapSafe]
		[HarmonyPostfix]
		private static void StartUpdateRoutine(BulletWeaponArchetype __instance)
		{
			if (!((Object)(object)__instance.m_owner == (Object)null) && ((Agent)__instance.m_owner).IsLocallyOwned)
			{
				_cachedArchetype = __instance;
				if (_autoReloadRoutine != null)
				{
					ARPLogger.Warning("OnWield called, but a coroutine still exists.");
					Reset();
				}
				else
				{
					_autoReloadRoutine = CoroutineManager.StartCoroutine(CollectionExtensions.WrapToIl2Cpp(UpdateAutoReload()), (Action)null);
				}
			}
		}

		[HarmonyPatch(typeof(BulletWeaponArchetype), "OnUnWield")]
		[HarmonyWrapSafe]
		[HarmonyPostfix]
		private static void StopUpdateRoutine(BulletWeaponArchetype __instance)
		{
			if (!((Object)(object)__instance.m_owner == (Object)null) && ((Agent)__instance.m_owner).IsLocallyOwned)
			{
				_cachedArchetype = null;
				if (_autoReloadRoutine != null)
				{
					CoroutineManager.StopCoroutine(_autoReloadRoutine);
				}
				_autoReloadRoutine = null;
			}
		}

		private static IEnumerator UpdateAutoReload()
		{
			float lastUpdateTime = Clock.Time;
			bool clickSoundTriggered = false;
			_heldEmptyTimer = 0f;
			_emptyTimer = 0f;
			_emptyClicks = 0;
			_emptyShotTimer = 0f;
			uint archID = ((GameDataBlockBase<ArchetypeDataBlock>)(object)_cachedArchetype.m_archetypeData).persistentID;
			while (true)
			{
				yield return null;
				float num = Clock.Time - lastUpdateTime;
				lastUpdateTime = Clock.Time;
				if (_cachedArchetype == null || (Object)(object)_cachedArchetype.m_weapon == (Object)null)
				{
					break;
				}
				if (archID != ((ItemEquippable)_cachedArchetype.m_weapon).ArchetypeID)
				{
					_cachedArchetype = _cachedArchetype.m_weapon.m_archeType;
					archID = ((ItemEquippable)_cachedArchetype.m_weapon).ArchetypeID;
				}
				if (((ItemEquippable)_cachedArchetype.m_weapon).IsReloading)
				{
					Reset();
				}
				else
				{
					if (_cachedArchetype.m_clip > 0f)
					{
						continue;
					}
					if (_emptyShotTimer == 0f)
					{
						_emptyShotTimer = _cachedArchetype.m_nextShotTimer;
					}
					if (_cachedArchetype.m_owner.Locomotion.IsRunning)
					{
						_haltAutoReloads |= Configuration.sprintHaltsReload;
						_heldEmptyTimer = 0f;
						_emptyTimer = 0f;
						continue;
					}
					if (_cachedArchetype.m_owner.Interaction.m_bestSelectedInteract != _cachedInteract)
					{
						_cachedInteract = _cachedArchetype.m_owner.Interaction.m_bestSelectedInteract;
						_cachedInteractTimed = ((Il2CppObjectBase)_cachedInteract).TryCast<Interact_Timed>();
					}
					if ((Object)(object)_cachedInteractTimed != (Object)null && _cachedInteractTimed.TimerIsActive)
					{
						_haltAutoReloads |= Configuration.interactHaltsReload;
						_heldEmptyTimer = 0f;
						_emptyTimer = 0f;
						continue;
					}
					if (((ItemEquippable)_cachedArchetype.m_weapon).FireButtonPressed && CanCountClicks())
					{
						if ((clickSoundTriggered || !_cachedArchetype.m_clickTriggered) && _emptyClicks <= Configuration.clicksToReload)
						{
							_cachedArchetype.m_weapon.TriggerAudio(((ItemEquippable)_cachedArchetype.m_weapon).AudioData.eventClick);
						}
						clickSoundTriggered = _cachedArchetype.m_clickTriggered;
						_emptyClicks++;
					}
					if (!_haltAutoReloads && CanTimeAutoReloads())
					{
						_emptyTimer += num;
						if (((ItemEquippable)_cachedArchetype.m_weapon).FireButton || (InputMapper.HasGamepad && InputMapper.GetAxisKeyMouseGamepad((InputAction)47, _cachedArchetype.m_owner.InputFilter) > 0f))
						{
							_heldEmptyTimer += num;
						}
					}
					if (ShouldTriggerReload())
					{
						((PlayerInventoryBase)((Weapon)_cachedArchetype.m_weapon).m_inventory).TriggerReload();
						clickSoundTriggered = false;
					}
				}
			}
			ARPLogger.Log("AutoReload coroutine has no cached archetype (OnUnWield was not called). Culling coroutine.");
			_autoReloadRoutine = null;
			Reset();
		}
	}
	internal static class Configuration
	{
		public static int clicksToReload = 1;

		public static bool clicksBypassDelay = true;

		public static bool autoReloadAimingInstant = false;

		public static bool sprintHaltsReload = false;

		public static bool interactHaltsReload = false;

		public static float autoReloadDelayHoldAuto = -1f;

		public static float autoReloadDelayAuto = 2f;

		public static bool autoReloadBypassDelayAuto = true;

		public static float autoReloadDelaySemi = 2f;

		public static bool autoReloadBypassDelaySemi = true;

		private static ConfigFile configFile;

		internal static void Init()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Expected O, but got Unknown
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Expected O, but got Unknown
			configFile = new ConfigFile(Path.Combine(Paths.ConfigPath, "AutoReloadPlus.cfg"), true);
			BindAll(configFile);
			LiveEdit.CreateListener(Paths.ConfigPath, "AutoReloadPlus.cfg", false).FileChanged += new LiveEditEventHandler(OnFileChanged);
		}

		private static void OnFileChanged(LiveEditEventArgs _)
		{
			configFile.Reload();
			string text = "Base Settings";
			clicksToReload = (int)configFile[text, "Clicks to Reload"].BoxedValue;
			clicksBypassDelay = (bool)configFile[text, "Clicks Bypass Cooldown"].BoxedValue;
			autoReloadAimingInstant = (bool)configFile[text, "Aim Triggers Auto Reload"].BoxedValue;
			sprintHaltsReload = (bool)configFile[text, "Sprint Halts Auto Reload"].BoxedValue;
			interactHaltsReload = (bool)configFile[text, "Interact Halts Auto Reload"].BoxedValue;
			text = "Full-Auto Weapons";
			autoReloadDelayHoldAuto = (float)configFile[text, "Held Auto Reload Delay"].BoxedValue;
			autoReloadDelayAuto = (float)configFile[text, "Auto Reload Delay"].BoxedValue;
			autoReloadBypassDelayAuto = (bool)configFile[text, "Auto Reloads Bypass Cooldown"].BoxedValue;
			text = "Semi-Auto/Burst Weapons";
			autoReloadDelaySemi = (float)configFile[text, "Auto Reload Delay"].BoxedValue;
			autoReloadBypassDelaySemi = (bool)configFile[text, "Auto Reload Bypasses Cooldown"].BoxedValue;
		}

		private static void BindAll(ConfigFile config)
		{
			string text = "Base Settings";
			clicksToReload = config.Bind<int>(text, "Clicks to Reload", clicksToReload, "The number of clicks required to trigger a reload while out of ammo.\nThe vanilla Auto Reload feature requires two clicks. Consider disabling it if setting this value above two.\nA value of 0 or less will reload immediately.").Value;
			clicksBypassDelay = config.Bind<bool>(text, "Clicks Bypass Cooldown", clicksBypassDelay, "Clicking will count towards a reload without waiting for shot cooldown.\nThe vanilla Auto Reload feature waits for this cooldown, although it can be bypassed by reloading manually.").Value;
			autoReloadAimingInstant = config.Bind<bool>(text, "Aim Triggers Auto Reload", autoReloadAimingInstant, "Aiming down sights will instantly trigger a reload when out of ammo.").Value;
			sprintHaltsReload = config.Bind<bool>(text, "Sprint Halts Auto Reload", sprintHaltsReload, "If a sprint is performed while out of ammo, Auto Reload Delays will halt until the next reload.\nIf disabled, Auto Reload Delays will reset their timers and continue after the sprint has ended.").Value;
			interactHaltsReload = config.Bind<bool>(text, "Interact Halts Auto Reload", sprintHaltsReload, "If an interact is attempted while out of ammo, Auto Reload Delays will halt until the next reload.\nIf disabled, Auto Reload Delays will reset their timers and continue after the interact attempt has ended.").Value;
			text = "Full-Auto Weapons";
			autoReloadDelayHoldAuto = config.Bind<float>(text, "Held Auto Reload Delay", autoReloadDelayHoldAuto, "Time in seconds before an automatic reload occurs when out of ammo and holding down the trigger.\nSetting to a value less than 0 disables this.").Value;
			autoReloadDelayAuto = config.Bind<float>(text, "Auto Reload Delay", autoReloadDelayAuto, "Time in seconds before an automatic reload occurs when out of ammo.\nSetting to a value less than 0 disables this.").Value;
			autoReloadBypassDelayAuto = config.Bind<bool>(text, "Auto Reloads Bypass Cooldown", autoReloadBypassDelayAuto, "Auto Reload Delays will bypass shot cooldown, starting their timers the moment the last shot is fired.").Value;
			text = "Semi-Auto/Burst Weapons";
			autoReloadDelaySemi = config.Bind<float>(text, "Auto Reload Delay", autoReloadDelaySemi, "Time in seconds before an automatic reload occurs when out of ammo.\nSetting to a value less than 0 disables this.").Value;
			autoReloadBypassDelaySemi = config.Bind<bool>(text, "Auto Reload Bypasses Cooldown", autoReloadBypassDelaySemi, "Auto Reload Delay will bypass shot cooldown, starting its timer the moment the last shot is fired.").Value;
		}
	}
	[BepInPlugin("Dinorush.AutoReloadPlus", "AutoReloadPlus", "1.1.3")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	internal sealed class EntryPoint : BasePlugin
	{
		public const string MODNAME = "AutoReloadPlus";

		public override void Load()
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			ARPLogger.Log("Loading AutoReloadPlus");
			Configuration.Init();
			new Harmony("AutoReloadPlus").PatchAll(typeof(AutoReloadPatch));
			ARPLogger.Log("Loaded AutoReloadPlus");
		}
	}
}
namespace AutoReloadPlus.Utils
{
	internal static class ARPLogger
	{
		private static ManualLogSource logger = Logger.CreateLogSource("AutoReloadPlus");

		public static void Log(string format, params object[] args)
		{
			Log(string.Format(format, args));
		}

		public static void Log(string str)
		{
			if (logger != null)
			{
				logger.Log((LogLevel)8, (object)str);
			}
		}

		public static void Warning(string format, params object[] args)
		{
			Warning(string.Format(format, args));
		}

		public static void Warning(string str)
		{
			if (logger != null)
			{
				logger.Log((LogLevel)4, (object)str);
			}
		}

		public static void Error(string format, params object[] args)
		{
			Error(string.Format(format, args));
		}

		public static void Error(string str)
		{
			if (logger != null)
			{
				logger.Log((LogLevel)2, (object)str);
			}
		}

		public static void Debug(string format, params object[] args)
		{
			Debug(string.Format(format, args));
		}

		public static void Debug(string str)
		{
			if (logger != null)
			{
				logger.Log((LogLevel)32, (object)str);
			}
		}
	}
}