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.Math;
using Pigeon.Movement;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Interactions;
[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("SalvoMacro")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("SalvoMacro")]
[assembly: AssemblyTitle("SalvoMacro")]
[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.salvomacro", "SalvoMacro", "1.2.0")]
[MycoMod(/*Could not decode attribute arguments.*/)]
public class SparrohPlugin : BaseUnityPlugin
{
public enum ActivationMode
{
None,
Toggle,
Always
}
public const string PluginGUID = "sparroh.salvomacro";
public const string PluginName = "SalvoMacro";
public const string PluginVersion = "1.2.0";
internal static ManualLogSource Logger;
public static ConfigEntry<ActivationMode> salvoMode;
public static ConfigEntry<bool> useZeroLockRelease;
public static ConfigEntry<bool> suppressSalvoModelAlways;
private FileSystemWatcher configWatcher;
private volatile bool configReloadPending;
private int lastConfigChangeTick;
private const int ConfigReloadDebounceMs = 250;
internal static SparrohPlugin Instance { get; private set; }
private void Awake()
{
//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
Instance = this;
Logger = ((BaseUnityPlugin)this).Logger;
salvoMode = ((BaseUnityPlugin)this).Config.Bind<ActivationMode>("General", "SalvoActivationMode", ActivationMode.Toggle, "None: default manual firing. Toggle: Slot3 toggles auto-fire on/off. Always: auto-fire whenever charged.");
useZeroLockRelease = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "UseZeroLockRelease", true, "When true (recommended), auto-fire uses vanilla zero-lock release (crosshair point + spread). When false, instantly fills target locks via FindSalvoTarget before firing.");
suppressSalvoModelAlways = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "SuppressSalvoModelAlways", false, "Always hide the 3D salvo launcher model to save screen space (including manual aim). Auto-fire never shows the model regardless.");
salvoMode.SettingChanged += delegate
{
WingsuitPatches.ResetToggle();
};
try
{
WingsuitPatches.InitializeAccess();
new Harmony("sparroh.salvomacro").PatchAll(typeof(WingsuitPatches));
Logger.LogInfo((object)"SalvoMacro v1.2.0 loaded");
}
catch (Exception ex)
{
Logger.LogError((object)("Failed to patch methods: " + ex));
}
SetupConfigWatcher();
}
private void Update()
{
if (!configReloadPending || Environment.TickCount - lastConfigChangeTick < 250)
{
return;
}
configReloadPending = false;
try
{
((BaseUnityPlugin)this).Config.Reload();
WingsuitPatches.ResetToggle();
Logger.LogInfo((object)"Config reloaded.");
}
catch (Exception ex)
{
Logger.LogError((object)("Failed to reload config: " + ex.Message));
}
}
private void SetupConfigWatcher()
{
try
{
string configFilePath = ((BaseUnityPlugin)this).Config.ConfigFilePath;
string directoryName = Path.GetDirectoryName(configFilePath);
string fileName = Path.GetFileName(configFilePath);
if (string.IsNullOrEmpty(directoryName) || string.IsNullOrEmpty(fileName))
{
Logger.LogWarning((object)"Could not set up config hot-reload: invalid config path.");
return;
}
configWatcher = new FileSystemWatcher(directoryName, fileName)
{
NotifyFilter = (NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.LastWrite),
EnableRaisingEvents = true
};
configWatcher.Changed += OnConfigFileChanged;
configWatcher.Created += OnConfigFileChanged;
configWatcher.Renamed += OnConfigFileRenamed;
}
catch (Exception ex)
{
Logger.LogError((object)("Failed to set up config file watcher: " + ex.Message));
}
}
private void OnConfigFileChanged(object sender, FileSystemEventArgs e)
{
lastConfigChangeTick = Environment.TickCount;
configReloadPending = true;
}
private void OnConfigFileRenamed(object sender, RenamedEventArgs e)
{
string fileName = Path.GetFileName(((BaseUnityPlugin)this).Config.ConfigFilePath);
if (string.Equals(e.Name, fileName, StringComparison.OrdinalIgnoreCase) || string.Equals(e.OldName, fileName, StringComparison.OrdinalIgnoreCase))
{
lastConfigChangeTick = Environment.TickCount;
configReloadPending = true;
}
}
private void OnDestroy()
{
if (configWatcher != null)
{
configWatcher.EnableRaisingEvents = false;
configWatcher.Changed -= OnConfigFileChanged;
configWatcher.Created -= OnConfigFileChanged;
configWatcher.Renamed -= OnConfigFileRenamed;
configWatcher.Dispose();
configWatcher = null;
}
}
}
[HarmonyPatch(typeof(Wingsuit))]
public static class WingsuitPatches
{
public static bool salvoAutoEnabled;
private static FieldInfo isSalvoActiveField;
private static FieldInfo salvoLockOrFireTimeField;
private static FieldInfo salvoModelField;
private static FieldInfo salvoAnimationTimeField;
private static PropertyInfo maxSalvoLocksProperty;
private static MethodInfo addExtraHealingRocketMethod;
private static MethodInfo findSalvoTargetMethod;
private static bool accessReady;
public static void InitializeAccess()
{
isSalvoActiveField = AccessTools.Field(typeof(Wingsuit), "isSalvoActive");
salvoLockOrFireTimeField = AccessTools.Field(typeof(Wingsuit), "salvoLockOrFireTime");
salvoModelField = AccessTools.Field(typeof(Wingsuit), "salvoModel");
salvoAnimationTimeField = AccessTools.Field(typeof(Wingsuit), "salvoAnimationTime");
maxSalvoLocksProperty = AccessTools.Property(typeof(Wingsuit), "MaxSalvoLocks");
addExtraHealingRocketMethod = AccessTools.Method(typeof(Wingsuit), "AddExtraHealingRocket", (Type[])null, (Type[])null);
findSalvoTargetMethod = AccessTools.Method(typeof(Wingsuit), "FindSalvoTarget", (Type[])null, (Type[])null);
accessReady = isSalvoActiveField != null && salvoLockOrFireTimeField != null && maxSalvoLocksProperty != null;
if (!accessReady)
{
SparrohPlugin.Logger.LogError((object)"Failed to resolve one or more Wingsuit members for SalvoMacro.");
}
}
public static void ResetToggle()
{
salvoAutoEnabled = false;
}
private static bool IsAutoFireActive()
{
return SparrohPlugin.salvoMode.Value switch
{
SparrohPlugin.ActivationMode.Always => true,
SparrohPlugin.ActivationMode.Toggle => salvoAutoEnabled,
_ => false,
};
}
[HarmonyPatch("OnSalvoPressed")]
[HarmonyPrefix]
private static bool OnSalvoPressedPrefix(CallbackContext context)
{
if (SparrohPlugin.salvoMode.Value != SparrohPlugin.ActivationMode.Toggle)
{
return true;
}
if (((CallbackContext)(ref context)).interaction is TapInteraction)
{
return true;
}
salvoAutoEnabled = !salvoAutoEnabled;
SparrohPlugin.Logger.LogDebug((object)("Salvo auto-fire " + (salvoAutoEnabled ? "enabled" : "disabled")));
return false;
}
[HarmonyPatch("FixedUpdate")]
[HarmonyPostfix]
private static void FixedUpdatePostfix(Wingsuit __instance)
{
if (!accessReady || !((NetworkBehaviour)__instance).IsOwner || !IsAutoFireActive())
{
return;
}
try
{
TryAutoFire(__instance);
}
catch (Exception ex)
{
SparrohPlugin.Logger.LogError((object)("Error in salvo auto-fire: " + ex));
}
}
[HarmonyPatch("Update")]
[HarmonyPostfix]
private static void UpdatePostfix(Wingsuit __instance)
{
if (!SparrohPlugin.suppressSalvoModelAlways.Value || !((NetworkBehaviour)__instance).IsOwner)
{
return;
}
try
{
SuppressSalvoModel(__instance);
}
catch (Exception ex)
{
SparrohPlugin.Logger.LogError((object)("Error suppressing salvo model: " + ex.Message));
}
}
[HarmonyPatch("OnSalvoPressed")]
[HarmonyPostfix]
private static void OnSalvoPressedPostfix(Wingsuit __instance)
{
if (!SparrohPlugin.suppressSalvoModelAlways.Value || !((NetworkBehaviour)__instance).IsOwner)
{
return;
}
try
{
SuppressSalvoModel(__instance);
}
catch (Exception ex)
{
SparrohPlugin.Logger.LogError((object)("Error suppressing salvo model on press: " + ex.Message));
}
}
private static void SuppressSalvoModel(Wingsuit wingsuit)
{
if (!(salvoModelField == null))
{
object? value = salvoModelField.GetValue(wingsuit);
Transform val = (Transform)((value is Transform) ? value : null);
if ((Object)(object)val != (Object)null && ((Component)val).gameObject.activeSelf)
{
((Component)val).gameObject.SetActive(false);
}
if (salvoAnimationTimeField != null)
{
salvoAnimationTimeField.SetValue(wingsuit, 0f);
}
}
}
private static void TryAutoFire(Wingsuit wingsuit)
{
//IL_00be: Unknown result type (might be due to invalid IL or missing references)
if ((bool)isSalvoActiveField.GetValue(wingsuit))
{
return;
}
List<ITarget> salvoLocks = wingsuit.SalvoLocks;
List<Vector3> salvoLockPositions = wingsuit.SalvoLockPositions;
if (salvoLocks == null || salvoLockPositions == null || salvoLocks.Count > 0)
{
return;
}
Cooldown rocketSalvoCooldown = wingsuit.RocketSalvoCooldown;
if (rocketSalvoCooldown == null || !((CooldownData)(ref rocketSalvoCooldown.data)).IsCharged)
{
return;
}
int num = (int)maxSalvoLocksProperty.GetValue(wingsuit);
if (num > 0)
{
ref WingsuitData data = ref wingsuit.Data;
salvoLocks.Clear();
salvoLockPositions.Clear();
salvoLockOrFireTimeField.SetValue(wingsuit, -99f);
if (SparrohPlugin.useZeroLockRelease.Value)
{
BuildZeroLockRelease(wingsuit, salvoLocks, salvoLockPositions, num, ref data);
}
else
{
BuildInstantTargetLocks(wingsuit, salvoLocks, num);
}
if (salvoLocks.Count == 0)
{
BuildZeroLockRelease(wingsuit, salvoLocks, salvoLockPositions, num, ref data);
}
if (UpgradeFlagsExtensions.IsEnabled(wingsuit.UpgradeFlags, (WingsuitUpgradeFlags)16) && addExtraHealingRocketMethod != null)
{
addExtraHealingRocketMethod.Invoke(wingsuit, null);
}
((CooldownData)(ref rocketSalvoCooldown.data)).UseCharge();
if (data.fuelAddedOnSalvoFire > 0f)
{
float num2 = Mathf.LerpUnclamped(1f, 0.13f, Mathf.InverseLerp(2f, 20f, (float)rocketSalvoCooldown.MaxCharges));
wingsuit.AddCharge(data.fuelAddedOnSalvoFire * num2);
}
}
}
private static void BuildZeroLockRelease(Wingsuit wingsuit, List<ITarget> locks, List<Vector3> lockPositions, int maxLocks, ref WingsuitData data)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_003f: Unknown result type (might be due to invalid IL or missing references)
//IL_0044: Unknown result type (might be due to invalid IL or missing references)
//IL_0049: 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)
//IL_002b: Unknown result type (might be due to invalid IL or missing references)
//IL_0056: 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_006d: Unknown result type (might be due to invalid IL or missing references)
//IL_0072: Unknown result type (might be due to invalid IL or missing references)
RaycastHit val2 = default(RaycastHit);
Vector3 val = ((!IBullet.RaycastForBullet(PlayerLook.Position, PlayerLook.Forward, data.maxSalvoLockDistance, 10241, 0f, ref val2)) ? (PlayerLook.Position + PlayerLook.Forward * data.maxSalvoLockDistance) : ((RaycastHit)(ref val2)).point);
for (int i = 0; i < maxLocks; i++)
{
locks.Add(null);
lockPositions.Add(val + ((Random)(ref data.salvoSpread.spreadRandom)).InsideUnitSphere() * 4f);
}
}
private static void BuildInstantTargetLocks(Wingsuit wingsuit, List<ITarget> locks, int maxLocks)
{
//IL_0055: 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)
if (findSalvoTargetMethod == null)
{
return;
}
for (int i = 0; i < maxLocks; i++)
{
if (!(bool)findSalvoTargetMethod.Invoke(wingsuit, null))
{
break;
}
salvoLockOrFireTimeField.SetValue(wingsuit, -99f);
}
if (locks.Count > 0 && locks.Count < maxLocks && !UpgradeFlagsExtensions.IsEnabled(wingsuit.UpgradeFlags, (WingsuitUpgradeFlags)8))
{
List<Vector3> salvoLockPositions = wingsuit.SalvoLockPositions;
int index = locks.Count - 1;
for (int j = locks.Count; j < maxLocks; j++)
{
locks.Add(locks[index]);
salvoLockPositions.Add(salvoLockPositions[index]);
}
}
}
}
namespace SalvoMacro
{
public static class MyPluginInfo
{
public const string PLUGIN_GUID = "SalvoMacro";
public const string PLUGIN_NAME = "SalvoMacro";
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)
{
}
}
}