using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Pigeon.Movement; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("AlwaysFireWhileSprinting")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("AlwaysFireWhileSprinting")] [assembly: AssemblyTitle("AlwaysFireWhileSprinting")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [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; } } } [BepInPlugin("sparroh.alwaysfirewhilesprinting", "AlwaysFireWhileSprinting", "1.0.1")] [MycoMod(/*Could not decode attribute arguments.*/)] public class SparrohPlugin : BaseUnityPlugin { private struct OriginalFireConstraints { public ActionFireMode CanFireWhileSprinting; public ActionFireMode CanFireWhileSliding; } public const string PluginGUID = "sparroh.alwaysfirewhilesprinting"; public const string PluginName = "AlwaysFireWhileSprinting"; public const string PluginVersion = "1.0.1"; internal static ManualLogSource Logger; internal static ConfigEntry enableCanFireWhileSprinting; internal static ConfigEntry enableCanFireWhileSliding; internal static ConfigEntry enableSprintToFireFix; private static readonly FieldInfo gunDataField = AccessTools.Field(typeof(Gun), "gunData"); private static readonly Dictionary originalConstraints = new Dictionary(); private Harmony harmony; private FileSystemWatcher configWatcher; private static volatile bool pendingConstraintRefresh; private void Awake() { //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Expected O, but got Unknown //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Expected O, but got Unknown Logger = ((BaseUnityPlugin)this).Logger; enableCanFireWhileSprinting = ((BaseUnityPlugin)this).Config.Bind("General", "Can Fire While Sprinting", true, "Allows firing weapons while sprinting."); enableCanFireWhileSliding = ((BaseUnityPlugin)this).Config.Bind("General", "Can Fire While Sliding", true, "Allows firing weapons while sliding."); enableSprintToFireFix = ((BaseUnityPlugin)this).Config.Bind("General", "Sprint To Fire Fix", true, "Enables the Sprint-to-Fire fix that allows immediate firing while sprinting and proper sprint resume behavior."); enableCanFireWhileSprinting.SettingChanged += OnFireConstraintSettingChanged; enableCanFireWhileSliding.SettingChanged += OnFireConstraintSettingChanged; try { SetupFileWatcher(); } catch (Exception ex) { Logger.LogError((object)("Error setting up config file watcher: " + ex.Message)); } harmony = new Harmony("sparroh.alwaysfirewhilesprinting"); try { MethodInfo methodInfo = AccessTools.Method(typeof(Gun), "Setup", new Type[3] { typeof(Player), typeof(PlayerAnimation), typeof(IGear) }, (Type[])null); if (methodInfo == null) { Logger.LogError((object)"Could not find Gun.Setup method for patching."); } else { HarmonyMethod val = new HarmonyMethod(typeof(SparrohPlugin), "ModifyWeaponPrefix", (Type[])null); harmony.Patch((MethodBase)methodInfo, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } catch (Exception ex2) { Logger.LogError((object)("Error patching Gun.Setup: " + ex2.Message)); } try { harmony.PatchAll(typeof(SprintToFireFixPatches)); Logger.LogInfo((object)("SprintToFireFix patches applied (currently " + (enableSprintToFireFix.Value ? "enabled" : "disabled") + ")")); } catch (Exception ex3) { Logger.LogError((object)("Error applying SprintToFireFix patches: " + ex3.Message)); } Logger.LogInfo((object)"AlwaysFireWhileSprinting v1.0.1 loaded successfully."); } private void Update() { if (pendingConstraintRefresh) { pendingConstraintRefresh = false; ApplyFireConstraintsToAllGuns(); } } private void SetupFileWatcher() { configWatcher = new FileSystemWatcher(Paths.ConfigPath, "sparroh.alwaysfirewhilesprinting.cfg"); configWatcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.LastWrite; configWatcher.Changed += OnConfigFileChanged; configWatcher.Created += OnConfigFileChanged; configWatcher.Renamed += OnConfigFileChanged; configWatcher.EnableRaisingEvents = true; } private void OnConfigFileChanged(object sender, FileSystemEventArgs e) { try { ((BaseUnityPlugin)this).Config.Reload(); pendingConstraintRefresh = true; Logger.LogInfo((object)"Config reloaded from disk."); } catch (Exception ex) { Logger.LogError((object)("Error reloading config: " + ex.Message)); } } private static void OnFireConstraintSettingChanged(object sender, EventArgs e) { pendingConstraintRefresh = true; } public static void ModifyWeaponPrefix(Gun __instance, IGear prefab) { Gun val = (Gun)(object)((prefab is Gun) ? prefab : null); if (val != null) { ApplyFireConstraints(val); } } internal static void ApplyFireConstraintsToAllGuns() { try { Gun[] array = Object.FindObjectsOfType(); foreach (Gun val in array) { if ((Object)(object)val != (Object)null) { ApplyFireConstraints(val); } } Logger.LogInfo((object)$"Re-applied fire constraints to {array.Length} gun(s)."); } catch (Exception ex) { Logger.LogError((object)("Error re-applying fire constraints: " + ex.Message)); } } internal static void ApplyFireConstraints(Gun gun) { if ((Object)(object)gun == (Object)null) { return; } try { object obj = gunDataField?.GetValue(gun); if (obj != null) { ApplyFireConstraintsToGunDataObject(gun, obj); } else { ApplyFireConstraintsToGunData(gun, ref gun.GunData); } } catch (Exception ex) { Logger.LogError((object)("Error applying fire constraints: " + ex.Message)); } } private static void ApplyFireConstraintsToGunData(Gun gun, ref GunData gunData) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) int instanceID = ((Object)gun).GetInstanceID(); if (!originalConstraints.TryGetValue(instanceID, out var value)) { value = new OriginalFireConstraints { CanFireWhileSprinting = gunData.fireConstraints.canFireWhileSprinting, CanFireWhileSliding = gunData.fireConstraints.canFireWhileSliding }; originalConstraints[instanceID] = value; } gunData.fireConstraints.canFireWhileSprinting = (ActionFireMode)(enableCanFireWhileSprinting.Value ? 1 : ((int)value.CanFireWhileSprinting)); gunData.fireConstraints.canFireWhileSliding = (ActionFireMode)(enableCanFireWhileSliding.Value ? 1 : ((int)value.CanFireWhileSliding)); } private static void ApplyFireConstraintsToGunDataObject(Gun gun, object gunDataObj) { //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) FieldInfo field = gunDataObj.GetType().GetField("fireConstraints"); if (field == null) { return; } object value = field.GetValue(gunDataObj); if (value == null) { return; } Type type = value.GetType(); FieldInfo field2 = type.GetField("canFireWhileSprinting"); FieldInfo field3 = type.GetField("canFireWhileSliding"); if (!(field2 == null) && !(field3 == null)) { int instanceID = ((Object)gun).GetInstanceID(); if (!originalConstraints.TryGetValue(instanceID, out var value2)) { value2 = new OriginalFireConstraints { CanFireWhileSprinting = (ActionFireMode)field2.GetValue(value), CanFireWhileSliding = (ActionFireMode)field3.GetValue(value) }; originalConstraints[instanceID] = value2; } object value3 = (object)(ActionFireMode)(enableCanFireWhileSprinting.Value ? 1 : ((int)value2.CanFireWhileSprinting)); object value4 = (object)(ActionFireMode)(enableCanFireWhileSliding.Value ? 1 : ((int)value2.CanFireWhileSliding)); field2.SetValue(value, value3); field3.SetValue(value, value4); field.SetValue(gunDataObj, value); if (gunDataField != null && gunDataField.FieldType.IsValueType) { gunDataField.SetValue(gun, gunDataObj); } } } private void OnDestroy() { if (enableCanFireWhileSprinting != null) { enableCanFireWhileSprinting.SettingChanged -= OnFireConstraintSettingChanged; } if (enableCanFireWhileSliding != null) { enableCanFireWhileSliding.SettingChanged -= OnFireConstraintSettingChanged; } if (configWatcher != null) { configWatcher.EnableRaisingEvents = false; configWatcher.Changed -= OnConfigFileChanged; configWatcher.Created -= OnConfigFileChanged; configWatcher.Renamed -= OnConfigFileChanged; configWatcher.Dispose(); configWatcher = null; } Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } } } public class SprintToFireData : MonoBehaviour { public bool SprintingLockedBySprintToFire { get; set; } public bool PreviousFireInputHeld { get; set; } } public static class SprintToFireFixPatches { private static readonly FieldInfo playerField = AccessTools.Field(typeof(Gun), "player"); private static readonly FieldInfo gunDataField = AccessTools.Field(typeof(Gun), "gunData"); private static readonly FieldInfo isFireInputHeldField = AccessTools.Field(typeof(Gun), "isFireInputHeld"); private static readonly MethodInfo tryFireMethod = AccessTools.Method(typeof(Gun), "TryFire", (Type[])null, (Type[])null); private static readonly PropertyInfo canFireWithoutAmmoProperty = AccessTools.Property(typeof(Gun), "CanFireWithoutAmmo"); private static bool IsEnabled { get { if (SparrohPlugin.enableSprintToFireFix != null) { return SparrohPlugin.enableSprintToFireFix.Value; } return false; } } [HarmonyPatch(typeof(Gun), "CanFireDuringAnimationState")] [HarmonyPrefix] private static bool CanFireDuringAnimationStatePrefix(Gun __instance, ref bool __result) { if (!IsEnabled) { return true; } try { if ((bool)isFireInputHeldField.GetValue(__instance)) { __result = true; return false; } } catch (Exception ex) { SparrohPlugin.Logger.LogError((object)("Error in CanFireDuringAnimationState patch: " + ex.Message)); } return true; } [HarmonyPatch(typeof(Gun), "MinWalkingWeightToFire")] [HarmonyPrefix] private static bool MinWalkingWeightToFirePrefix(Gun __instance, ref float __result) { if (!IsEnabled) { return true; } try { if ((bool)isFireInputHeldField.GetValue(__instance)) { __result = 0f; return false; } } catch (Exception ex) { SparrohPlugin.Logger.LogError((object)("Error in MinWalkingWeightToFire patch: " + ex.Message)); } return true; } [HarmonyPatch(typeof(Gun), "Update")] [HarmonyPostfix] private static void UpdatePostfix(Gun __instance) { if (!IsEnabled) { return; } try { bool flag = (bool)isFireInputHeldField.GetValue(__instance); SprintToFireData sprintToFireData = ((Component)__instance).gameObject.GetComponent(); if ((Object)(object)sprintToFireData == (Object)null) { sprintToFireData = ((Component)__instance).gameObject.AddComponent(); } if (sprintToFireData.PreviousFireInputHeld && !flag && sprintToFireData.SprintingLockedBySprintToFire) { object? value = playerField.GetValue(__instance); Player val = (Player)((value is Player) ? value : null); if ((Object)(object)val != (Object)null) { val.SprintLocks = 0; sprintToFireData.SprintingLockedBySprintToFire = false; if (val.AutoSprint) { FieldInfo field = typeof(Player).GetField("wantsToSprint", BindingFlags.Instance | BindingFlags.NonPublic); if (field != null) { field.SetValue(val, true); } } } } sprintToFireData.PreviousFireInputHeld = flag; if (flag) { AccessTools.Property(typeof(Gun), "WantsToFire").SetValue(__instance, true); } } catch (Exception ex) { SparrohPlugin.Logger.LogError((object)("Error in Update postfix: " + ex.Message)); } } [HarmonyPatch(typeof(Gun), "HandleFiring")] [HarmonyPrefix] private static bool HandleFiringPrefix(Gun __instance) { if (!IsEnabled) { return true; } try { object? value = playerField.GetValue(__instance); Player val = (Player)((value is Player) ? value : null); if ((Object)(object)val == (Object)null) { return true; } object value2 = gunDataField.GetValue(__instance); if (value2 == null) { return true; } bool flag = (bool)isFireInputHeldField.GetValue(__instance); if (val.IsSprinting && flag) { object value3 = value2.GetType().GetField("chargeData").GetValue(value2); bool num = (bool)value3.GetType().GetProperty("CanFire").GetValue(value3); bool flag2 = (bool)canFireWithoutAmmoProperty.GetValue(__instance); if (num && ((double)__instance.RemainingAmmo >= 1.0 || flag2)) { object value4 = value2.GetType().GetField("fireConstraints").GetValue(value2); if ((int)value4.GetType().GetField("canFireWhileSprinting").GetValue(value4) != 1) { val.SprintLocks = 1; SprintToFireData component = ((Component)__instance).gameObject.GetComponent(); if ((Object)(object)component != (Object)null) { component.SprintingLockedBySprintToFire = true; } } tryFireMethod.Invoke(__instance, null); return false; } } } catch (Exception ex) { SparrohPlugin.Logger.LogError((object)("Error in SprintToFireFix patch: " + ex.Message)); SparrohPlugin.Logger.LogError((object)("Stack trace: " + ex.StackTrace)); } return true; } } namespace AlwaysFireWhileSprinting { public static class MyPluginInfo { public const string PLUGIN_GUID = "AlwaysFireWhileSprinting"; public const string PLUGIN_NAME = "AlwaysFireWhileSprinting"; public const string PLUGIN_VERSION = "1.0.0"; } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } }