Decompiled source of SalvoMacro v1.2.0

BepInEx/plugins/SalvoMacro.dll

Decompiled 2 weeks ago
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)
		{
		}
	}
}