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<bool> enableCanFireWhileSprinting;
internal static ConfigEntry<bool> enableCanFireWhileSliding;
internal static ConfigEntry<bool> enableSprintToFireFix;
private static readonly FieldInfo gunDataField = AccessTools.Field(typeof(Gun), "gunData");
private static readonly Dictionary<int, OriginalFireConstraints> originalConstraints = new Dictionary<int, OriginalFireConstraints>();
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<bool>("General", "Can Fire While Sprinting", true, "Allows firing weapons while sprinting.");
enableCanFireWhileSliding = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Can Fire While Sliding", true, "Allows firing weapons while sliding.");
enableSprintToFireFix = ((BaseUnityPlugin)this).Config.Bind<bool>("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<Gun>();
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<SprintToFireData>();
if ((Object)(object)sprintToFireData == (Object)null)
{
sprintToFireData = ((Component)__instance).gameObject.AddComponent<SprintToFireData>();
}
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<SprintToFireData>();
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)
{
}
}
}