Decompiled source of ProjectileTweaks v1.3.0

ProjectileTweaks.dll

Decompiled 2 weeks ago
using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Managers;
using Jotunn.Utils;
using ProjectileTweaks.Configs;
using ProjectileTweaks.Extensions;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("ProjectileTweaks")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ProjectileTweaks")]
[assembly: AssemblyCopyright("Copyright ©  2023")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("e3243d22-4307-4008-ba36-9f326008cde5")]
[assembly: AssemblyFileVersion("1.3.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.3.0.0")]
[module: UnverifiableCode]
namespace ProjectileTweaks
{
	[BepInPlugin("Searica.Valheim.ProjectileTweaks", "ProjectileTweaks", "1.3.0")]
	[BepInDependency("com.jotunn.jotunn", "2.19.3")]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	internal class ProjectileTweaks : BaseUnityPlugin
	{
		public const string Author = "Searica";

		public const string PluginName = "ProjectileTweaks";

		public const string PluginGUID = "Searica.Valheim.ProjectileTweaks";

		public const string PluginVersion = "1.3.0";

		private const string BombSection = "BombTweaks";

		private const string BowSection = "BowTweaks";

		private const string XbowSection = "CrossbowTweaks";

		private const string SpearSection = "SpearTweaks";

		private const string StaffSection = "StaffTweaks";

		private const string ZoomSection = "Zoom";

		private static bool ShouldSaveConfig;

		internal static ConfigEntry<float> BowSpreadMult { get; private set; }

		internal static ConfigEntry<float> BowVelocityMult { get; private set; }

		internal static ConfigEntry<float> BowLaunchAngle { get; private set; }

		internal static ConfigEntry<float> BowVerticalOffset { get; private set; }

		internal static ConfigEntry<float> BowHorizontalOffset { get; private set; }

		internal static ConfigEntry<float> BowDrawSpeed { get; private set; }

		internal static ConfigEntry<float> BombSpreadMult { get; private set; }

		internal static ConfigEntry<float> BombVelocityMult { get; private set; }

		internal static ConfigEntry<float> BombLaunchAngle { get; private set; }

		internal static ConfigEntry<float> BombVerticalOffset { get; private set; }

		internal static ConfigEntry<float> BombHorizontalOffset { get; private set; }

		internal static ConfigEntry<float> XbowSpreadMult { get; private set; }

		internal static ConfigEntry<float> XbowVelocityMult { get; private set; }

		internal static ConfigEntry<float> XbowLaunchAngle { get; private set; }

		internal static ConfigEntry<float> XbowVerticalOffset { get; private set; }

		internal static ConfigEntry<float> XbowHorizontalOffset { get; private set; }

		internal static ConfigEntry<float> XBowReloadSpeed { get; private set; }

		internal static ConfigEntry<float> SpearSpreadMult { get; private set; }

		internal static ConfigEntry<float> SpearVelocityMult { get; private set; }

		internal static ConfigEntry<float> SpearLaunchAngle { get; private set; }

		internal static ConfigEntry<float> SpearVerticalOffset { get; private set; }

		internal static ConfigEntry<float> SpearHorizontalOffset { get; private set; }

		internal static ConfigEntry<float> StaffSpreadMult { get; private set; }

		internal static ConfigEntry<float> StaffVelocityMult { get; private set; }

		internal static ConfigEntry<float> StaffLaunchAngle { get; private set; }

		internal static ConfigEntry<float> StaffVerticalOffset { get; private set; }

		internal static ConfigEntry<float> StaffHorizontalOffset { get; private set; }

		internal static ConfigEntry<bool> EnableBowZoom { get; private set; }

		internal static ConfigEntry<bool> EnableXbowZoom { get; private set; }

		internal static ConfigEntry<KeyCode> ZoomKey { get; private set; }

		internal static ConfigEntry<KeyCode> CancelDrawKey { get; private set; }

		internal static ConfigEntry<float> StayInZoomTime { get; private set; }

		internal static ConfigEntry<float> TimeToZoomIn { get; private set; }

		internal static ConfigEntry<float> ZoomFactor { get; private set; }

		internal static ConfigEntry<bool> AutoBowZoom { get; private set; }

		internal static bool IsZoomEnabled
		{
			get
			{
				if (!EnableBowZoom.Value)
				{
					return EnableXbowZoom.Value;
				}
				return true;
			}
		}

		public void Awake()
		{
			Log.Init(((BaseUnityPlugin)this).Logger);
			ConfigManager.Init("Searica.Valheim.ProjectileTweaks", ((BaseUnityPlugin)this).Config);
			Initialize();
			ConfigManager.Save();
			Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), "Searica.Valheim.ProjectileTweaks");
			Game.isModded = true;
			ConfigManager.SetupWatcher();
			SynchronizationManager.OnConfigurationWindowClosed += delegate
			{
				UpdateConfigFile();
			};
			SynchronizationManager.OnConfigurationSynchronized += delegate
			{
				UpdateConfigFile();
			};
		}

		public void OnDestroy()
		{
			ConfigManager.Save();
		}

		private void Initialize()
		{
			BowDrawSpeed = ConfigManager.BindConfig("BowTweaks", ConfigManager.SetStringPriority("Draw Speed Multiplier", 4), 1f, "Multiplier for draw speed of bows. Set to 2 to draw bows twice as fast. Does not affect Vanilla scaling with skill level.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 2f));
			BowDrawSpeed.SettingChanged += UpdateSettings;
			BowSpreadMult = ConfigManager.BindConfig("BowTweaks", ConfigManager.SetStringPriority("Spread Multiplier", 3), 1f, "Multiplies the min and max projectile spread, so if you set it to zero your arrows will have zero spread.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f));
			BowSpreadMult.SettingChanged += UpdateSettings;
			BowVelocityMult = ConfigManager.BindConfig("BowTweaks", ConfigManager.SetStringPriority("Velocity Multiplier", 2), 1f, "Multiplies velocity of arrows.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 2f));
			BowVelocityMult.SettingChanged += UpdateSettings;
			BowLaunchAngle = ConfigManager.BindConfig("BowTweaks", ConfigManager.SetStringPriority("Launch Angle", 1), -1f, "Changes the launch angle for arrows. Vanilla default for bows is 0. Negative values angle upwards, and positive values angle downwards.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-5f, 5f));
			BowLaunchAngle.SettingChanged += UpdateSettings;
			BowHorizontalOffset = ConfigManager.BindConfig("BowTweaks", "Horizontal Offset", 0.2f, "Offsets the location that arrows are launched from when firing them. Positive shifts it to your characters right. Negative shifts it to your characters left.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-0.75f, 0.75f));
			BowHorizontalOffset.SettingChanged += UpdateSettings;
			BowVerticalOffset = ConfigManager.BindConfig("BowTweaks", "Vertical Offset", 0.2f, "Offsets the location that arrows are launched from when firing them. Positive shifts it upwards. Negative shifts it downwards.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-0.75f, 0.75f));
			BowVerticalOffset.SettingChanged += UpdateSettings;
			BombSpreadMult = ConfigManager.BindConfig("BombTweaks", ConfigManager.SetStringPriority("Spread Multiplier", 3), 1f, "Multiplies the min and max projectile spread, so if you set it to zero your bombs will have zero spread.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f));
			BombSpreadMult.SettingChanged += UpdateSettings;
			BombVelocityMult = ConfigManager.BindConfig("BombTweaks", ConfigManager.SetStringPriority("Velocity Multiplier", 2), 1f, "Multiplies velocity of bombs.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 2f));
			BombVelocityMult.SettingChanged += UpdateSettings;
			BombLaunchAngle = ConfigManager.BindConfig("BombTweaks", ConfigManager.SetStringPriority("Launch Angle", 1), -1f, "Changes the launch angle for bombs. Vanilla default for bombs is 0. Negative values angle upwards, and positive values angle downwards.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-5f, 5f));
			BombLaunchAngle.SettingChanged += UpdateSettings;
			BombHorizontalOffset = ConfigManager.BindConfig("BombTweaks", "Horizontal Offset", 0f, "Offsets the location that bombs are thrown from when firing them. Positive shifts it to your characters right. Negative shifts it to your characters left.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-0.75f, 0.75f));
			BombHorizontalOffset.SettingChanged += UpdateSettings;
			BombVerticalOffset = ConfigManager.BindConfig("BombTweaks", "Vertical Offset", 0.5f, "Offsets the location that bombs are launched from when firing them. Positive shifts it upwards. Negative shifts it downwards.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-0.75f, 0.75f));
			BombVerticalOffset.SettingChanged += UpdateSettings;
			XBowReloadSpeed = ConfigManager.BindConfig("CrossbowTweaks", ConfigManager.SetStringPriority("Reload Speed Multiplier", 4), 1f, "Multiplier for reload speed of crossbows. Set to 2 to reload twice as fast. Does not affect Vanilla scaling with skill level.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 2f));
			XBowReloadSpeed.SettingChanged += UpdateSettings;
			XbowSpreadMult = ConfigManager.BindConfig("CrossbowTweaks", ConfigManager.SetStringPriority("Spread Multiplier", 3), 1f, "Multiplies the min and max projectile spread, so if you set it to zero your bolts will have zero spread.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f));
			XbowSpreadMult.SettingChanged += UpdateSettings;
			XbowVelocityMult = ConfigManager.BindConfig("CrossbowTweaks", ConfigManager.SetStringPriority("Velocity Multiplier", 2), 1f, "Multiplies velocity of bolts.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 2f));
			XbowVelocityMult.SettingChanged += UpdateSettings;
			XbowLaunchAngle = ConfigManager.BindConfig("CrossbowTweaks", ConfigManager.SetStringPriority("Launch Angle", 1), -1f, "Changes the launch angle for bolts. Vanilla default for crossbows is -1. Negative values angle upwards, and positive values angle downwards.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-5f, 5f));
			XbowLaunchAngle.SettingChanged += UpdateSettings;
			XbowHorizontalOffset = ConfigManager.BindConfig("CrossbowTweaks", "Horizontal Offset", 0f, "Offsets the location that bolts are launched from when firing them. Positive shifts it to your characters right. Negative shifts it to your characters left.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-0.75f, 0.75f));
			XbowHorizontalOffset.SettingChanged += UpdateSettings;
			XbowVerticalOffset = ConfigManager.BindConfig("CrossbowTweaks", "Vertical Offset", 0f, "Offsets the location that bolts are launched from when firing them. Positive shifts it upwards. Negative shifts it downwards.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-0.75f, 0.75f));
			XbowVerticalOffset.SettingChanged += UpdateSettings;
			SpearSpreadMult = ConfigManager.BindConfig("SpearTweaks", ConfigManager.SetStringPriority("Spread Multiplier", 3), 1f, "Multiplies the min and max projectile spread, so if you set it to zero your spear throws will have zero spread.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f));
			SpearSpreadMult.SettingChanged += UpdateSettings;
			SpearVelocityMult = ConfigManager.BindConfig("SpearTweaks", ConfigManager.SetStringPriority("Velocity Multiplier", 2), 1f, "Multiplies velocity of thrown spears.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 2f));
			SpearVelocityMult.SettingChanged += UpdateSettings;
			SpearLaunchAngle = ConfigManager.BindConfig("SpearTweaks", "Launch Angle", -1f, "Changes the launch angle for thrown spears. Vanilla default for spears is 0. Negative values angle upwards, and positive values angle downwards.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-5f, 5f));
			SpearLaunchAngle.SettingChanged += UpdateSettings;
			SpearHorizontalOffset = ConfigManager.BindConfig("SpearTweaks", "Horizontal Offset", 0.1f, "Offsets the location that thrown spears are launched from when throwing them. Positive shifts it to your characters right. Negative shifts it to your characters left.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-0.75f, 0.75f));
			SpearHorizontalOffset.SettingChanged += UpdateSettings;
			SpearVerticalOffset = ConfigManager.BindConfig("SpearTweaks", "Vertical Offset", 0.5f, "Offsets the location that thrown spears are launched from when throwing them. Positive shifts it upwards. Negative shifts it downwards.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-0.75f, 0.75f));
			SpearVelocityMult.SettingChanged += UpdateSettings;
			StaffSpreadMult = ConfigManager.BindConfig("StaffTweaks", ConfigManager.SetStringPriority("Spread Multiplier", 3), 1f, "Multiplies the min and max projectile spread, so if you set it to zero there will be zero spread.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f));
			StaffSpreadMult.SettingChanged += UpdateSettings;
			StaffVelocityMult = ConfigManager.BindConfig("StaffTweaks", ConfigManager.SetStringPriority("Velocity Multiplier", 2), 1f, "Multiplies velocity of projectiles.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 2f));
			StaffVelocityMult.SettingChanged += UpdateSettings;
			StaffHorizontalOffset = ConfigManager.BindConfig("StaffTweaks", "Horizontal Offset", 0f, "Offsets the location that projectiles are launched from when firing them. Positive shifts it to your characters right. Negative shifts it to your characters left.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-0.75f, 0.75f));
			StaffHorizontalOffset.SettingChanged += UpdateSettings;
			StaffVerticalOffset = ConfigManager.BindConfig("StaffTweaks", "Vertical Offset", 0.3f, "Offsets the location that projectiles are launched from when firing them. Positive shifts it upwards. Negative shifts it downwards.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-0.75f, 0.75f));
			StaffVerticalOffset.SettingChanged += UpdateSettings;
			EnableBowZoom = ConfigManager.BindConfig("Zoom", ConfigManager.SetStringPriority("Bow Zoom", 3), value: true, "Set to true/enabled to allow zooming while using a bow.");
			EnableBowZoom.SettingChanged += UpdateSettings;
			EnableXbowZoom = ConfigManager.BindConfig("Zoom", ConfigManager.SetStringPriority("Crossbow Zoom", 3), value: true, "Set to true/enabled to allow zooming while using a crossbow.");
			EnableXbowZoom.SettingChanged += UpdateSettings;
			ZoomKey = ConfigManager.BindConfig<KeyCode>("Zoom", ConfigManager.SetStringPriority("Zoom Key", 2), (KeyCode)324, "Set the key used to zoom in while using a bow or crossbow.", null, synced: false);
			ZoomKey.SettingChanged += UpdateSettings;
			CancelDrawKey = ConfigManager.BindConfig<KeyCode>("Zoom", ConfigManager.SetStringPriority("Cancel Draw Key", 1), (KeyCode)101, "Set the key used to cancel drawing your bow.", null, synced: false);
			CancelDrawKey.SettingChanged += UpdateSettings;
			TimeToZoomIn = ConfigManager.BindConfig("Zoom", "Time to Zoom in", 1f, "Time that it takes to zoom in all the way. '1' is default and recommended.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.2f, 2f), synced: false);
			TimeToZoomIn.SettingChanged += UpdateSettings;
			StayInZoomTime = ConfigManager.BindConfig("Zoom", "Stay In-Zoom Time", 2f, "Set the maximum time the camera will stay zoomed in while holding the zoom key after firing a projectile.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 4f), synced: false);
			StayInZoomTime.SettingChanged += UpdateSettings;
			ZoomFactor = ConfigManager.BindConfig("Zoom", "Zoom Factor", 2f, "Set how much too zoom in relative to current camera view.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 4f), synced: false);
			ZoomFactor.SettingChanged += UpdateSettings;
			AutoBowZoom = ConfigManager.BindConfig("Zoom", "Auto Bow Zoom", value: false, "Set to true/enabled to make bows automatically zoom in as they are drawn.", null, synced: false);
			AutoBowZoom.SettingChanged += UpdateSettings;
		}

		private static void UpdateConfigFile()
		{
			if (ShouldSaveConfig)
			{
				ConfigManager.Save();
				ShouldSaveConfig = false;
			}
		}

		private static void UpdateSettings(object obj, EventArgs e)
		{
			ShouldSaveConfig |= !ShouldSaveConfig;
		}
	}
	internal enum LogLevel
	{
		Low,
		Medium,
		High
	}
	internal static class Log
	{
		private const BindingFlags AllBindings = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.GetProperty | BindingFlags.SetProperty;

		private static ManualLogSource logSource;

		internal static ConfigEntry<LogLevel> Verbosity { get; private set; }

		internal static LogLevel VerbosityLevel => Verbosity.Value;

		internal static bool IsVerbosityLow => Verbosity.Value >= LogLevel.Low;

		internal static bool IsVerbosityMedium => Verbosity.Value >= LogLevel.Medium;

		internal static bool IsVerbosityHigh => Verbosity.Value >= LogLevel.High;

		internal static void Init(ManualLogSource logSource)
		{
			Log.logSource = logSource;
		}

		internal static void LogDebug(object data)
		{
			logSource.LogDebug(data);
		}

		internal static void LogError(object data)
		{
			logSource.LogError(data);
		}

		internal static void LogFatal(object data)
		{
			logSource.LogFatal(data);
		}

		internal static void LogMessage(object data)
		{
			logSource.LogMessage(data);
		}

		internal static void LogWarning(object data)
		{
			logSource.LogWarning(data);
		}

		internal static void LogInfo(object data, LogLevel level = LogLevel.Low)
		{
			if (Verbosity == null || VerbosityLevel >= level)
			{
				logSource.LogInfo(data);
			}
		}

		internal static void LogGameObject(GameObject prefab, bool includeChildren = false)
		{
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Expected O, but got Unknown
			LogInfo("***** " + ((Object)prefab).name + " *****");
			Component[] components = prefab.GetComponents<Component>();
			for (int i = 0; i < components.Length; i++)
			{
				LogComponent(components[i]);
			}
			if (!includeChildren)
			{
				return;
			}
			LogInfo("***** " + ((Object)prefab).name + " (children) *****");
			foreach (Transform item in prefab.transform)
			{
				Transform val = item;
				LogInfo(" - " + ((Object)((Component)val).gameObject).name);
				components = ((Component)val).gameObject.GetComponents<Component>();
				for (int i = 0; i < components.Length; i++)
				{
					LogComponent(components[i]);
				}
			}
		}

		internal static void LogComponent(Component compo)
		{
			LogInfo("--- " + ((object)compo).GetType().Name + ": " + ((Object)compo).name + " ---");
			PropertyInfo[] properties = ((object)compo).GetType().GetProperties(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.GetProperty | BindingFlags.SetProperty);
			foreach (PropertyInfo propertyInfo in properties)
			{
				LogInfo($" - {propertyInfo.Name} = {propertyInfo.GetValue(compo)}");
			}
			FieldInfo[] fields = ((object)compo).GetType().GetFields(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.GetProperty | BindingFlags.SetProperty);
			foreach (FieldInfo fieldInfo in fields)
			{
				LogInfo($" - {fieldInfo.Name} = {fieldInfo.GetValue(compo)}");
			}
		}
	}
	[HarmonyPatch]
	internal static class ZoomManager
	{
		internal enum ZoomState
		{
			Fixed,
			ZoomingIn,
			ZoomingOut
		}

		private static ZoomState CurrentZoomState;

		private static float ZoomInTimer;

		private static float ZoomOutTimer;

		private static float ZoomOutDelayTimer;

		private static float BaseFov;

		private static float LastZoomFov;

		private static float NewZoomFov;

		private const float DiffTol = 0.1f;

		private const float PercTol = 0.01f;

		private const float ZoomOutDuration = 1f;

		[HarmonyPrefix]
		[HarmonyPatch(typeof(GameCamera), "UpdateCamera")]
		[HarmonyPriority(0)]
		public static void UpdateCameraPrefix(GameCamera __instance)
		{
			if (ProjectileTweaks.IsZoomEnabled && (CurrentZoomState == ZoomState.ZoomingOut || CurrentZoomState == ZoomState.ZoomingIn))
			{
				__instance.m_fov = NewZoomFov;
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Player), "SetControls")]
		private static void SetControlsPrefix(Player __instance, ref bool attackHold, ref bool blockHold)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			if (ProjectileTweaks.IsZoomEnabled)
			{
				if (attackHold)
				{
					blockHold = Input.GetKey(ProjectileTweaks.CancelDrawKey.Value);
				}
				else if (CurrentZoomState == ZoomState.ZoomingIn && HasZoomableItem(__instance))
				{
					blockHold = false;
				}
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(GameCamera), "GetCameraPosition")]
		[HarmonyPriority(100)]
		private static void GetCameraPositionPostfix(GameCamera __instance)
		{
			if ((Object)(object)__instance != (Object)null && ProjectileTweaks.IsZoomEnabled && CurrentZoomState == ZoomState.Fixed && Mathf.Abs(__instance.m_fov - BaseFov) > 0.1f)
			{
				BaseFov = __instance.m_fov;
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Hud), "UpdateCrosshair")]
		[HarmonyPriority(0)]
		private static void UpdateCrosshairPostfix(Player player, float bowDrawPercentage)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			if (!ProjectileTweaks.IsZoomEnabled || BaseFov == 0f)
			{
				return;
			}
			if (!HasZoomableItem(player))
			{
				ZoomOut();
				return;
			}
			bool key = Input.GetKey(ProjectileTweaks.ZoomKey.Value);
			bool num = (key || ProjectileTweaks.AutoBowZoom.Value) && bowDrawPercentage > 0.01f;
			bool flag = key && ((Humanoid)player).IsWeaponLoaded();
			if (num || flag)
			{
				ZoomIn();
			}
			else if (key && bowDrawPercentage <= 0.01f)
			{
				ProcessZoomOutDelay();
			}
			else
			{
				ZoomOut();
			}
		}

		internal static void ZoomIn()
		{
			ZoomInTimer += Time.deltaTime;
			CurrentZoomState = ZoomState.ZoomingIn;
			float num = Mathf.InverseLerp(0.05f, ProjectileTweaks.TimeToZoomIn.Value, ZoomInTimer);
			LastZoomFov = Mathf.Lerp(BaseFov, BaseFov / ProjectileTweaks.ZoomFactor.Value, num);
			GameCamera.instance.m_fov = LastZoomFov;
			NewZoomFov = LastZoomFov;
		}

		public static void ZoomOut()
		{
			if (CurrentZoomState != 0)
			{
				if (CurrentZoomState == ZoomState.ZoomingIn)
				{
					CurrentZoomState = ZoomState.ZoomingOut;
					ZoomOutTimer = 0f;
					ZoomInTimer = 0f;
				}
				else
				{
					ZoomOutTimer += Time.deltaTime;
					if (ZoomOutTimer > 1f)
					{
						GameCamera.instance.m_fov = BaseFov;
						CurrentZoomState = ZoomState.Fixed;
						ZoomOutDelayTimer = 0f;
						return;
					}
				}
				float num = Mathf.InverseLerp(0f, 0.3f, ZoomOutTimer);
				NewZoomFov = Mathf.Lerp(LastZoomFov, BaseFov, num);
				GameCamera.instance.m_fov = NewZoomFov;
			}
			else if (Mathf.Abs(GameCamera.instance.m_fov - BaseFov) >= 0.1f)
			{
				GameCamera.instance.m_fov = BaseFov;
			}
		}

		internal static void ProcessZoomOutDelay()
		{
			ZoomOutDelayTimer += Time.deltaTime;
			if (ZoomOutDelayTimer > ProjectileTweaks.StayInZoomTime.Value)
			{
				ZoomOut();
			}
		}

		internal static bool HasZoomableItem(Player player)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Invalid comparison between Unknown and I4
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Invalid comparison between Unknown and I4
			ItemData currentWeapon = ((Humanoid)player).GetCurrentWeapon();
			if (currentWeapon != null)
			{
				SkillType skillType = currentWeapon.m_shared.m_skillType;
				bool num = ProjectileTweaks.EnableBowZoom.Value && (int)skillType == 8;
				bool flag = ProjectileTweaks.EnableXbowZoom.Value && (int)skillType == 14;
				return num || flag;
			}
			return false;
		}
	}
}
namespace ProjectileTweaks.Patches
{
	[HarmonyPatch(typeof(Attack))]
	internal static class AttackPatch
	{
		private static float m_projectileVel;

		private static float m_projectileVelMin;

		private static float m_projectileAccuracy;

		private static float m_projectileAccuracyMin;

		[HarmonyPostfix]
		[HarmonyBefore(new string[] { "blacks7ar.BowPlugin" })]
		[HarmonyPriority(700)]
		[HarmonyPatch("Start")]
		internal static void AttackStartPrefix(Attack __instance)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Invalid comparison between Unknown and I4
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Invalid comparison between Unknown and I4
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Invalid comparison between Unknown and I4
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Invalid comparison between Unknown and I4
			ItemData playerWeapon = GetPlayerWeapon(__instance);
			if (playerWeapon != null)
			{
				SkillType skillType = playerWeapon.m_shared.m_skillType;
				if ((int)skillType == 8)
				{
					SetVelocity(__instance, ProjectileTweaks.BowVelocityMult);
					SetSpread(__instance, ProjectileTweaks.BowSpreadMult);
					SetLaunchAngle(__instance, ProjectileTweaks.BowLaunchAngle);
				}
				else if ((int)skillType == 14)
				{
					SetVelocity(__instance, ProjectileTweaks.XbowVelocityMult);
					SetSpread(__instance, ProjectileTweaks.XbowSpreadMult);
					SetLaunchAngle(__instance, ProjectileTweaks.XbowLaunchAngle);
				}
				else if ((int)skillType == 5)
				{
					SetVelocity(__instance, ProjectileTweaks.SpearVelocityMult);
					SetSpread(__instance, ProjectileTweaks.SpearSpreadMult);
					SetLaunchAngle(__instance, ProjectileTweaks.SpearLaunchAngle);
				}
				else if ((int)skillType == 9)
				{
					SetVelocity(__instance, ProjectileTweaks.StaffVelocityMult);
					SetSpread(__instance, ProjectileTweaks.StaffSpreadMult);
				}
				else if (IsBomb(playerWeapon))
				{
					SetVelocity(__instance, ProjectileTweaks.BombVelocityMult);
					SetSpread(__instance, ProjectileTweaks.BombSpreadMult);
					SetLaunchAngle(__instance, ProjectileTweaks.BombLaunchAngle);
				}
			}
		}

		private static void SetVelocity(Attack attack, ConfigEntry<float> velocityMultiplier)
		{
			m_projectileVel = attack.m_projectileVel;
			m_projectileVelMin = attack.m_projectileVelMin;
			velocityMultiplier.SettingChanged += delegate
			{
				attack.m_projectileVel = m_projectileVel * velocityMultiplier.Value;
				attack.m_projectileVelMin = m_projectileVelMin * velocityMultiplier.Value;
			};
			Attack obj = attack;
			obj.m_projectileVel *= velocityMultiplier.Value;
			Attack obj2 = attack;
			obj2.m_projectileVelMin *= velocityMultiplier.Value;
		}

		private static void SetSpread(Attack attack, ConfigEntry<float> spreadConfig)
		{
			m_projectileAccuracy = attack.m_projectileAccuracy;
			m_projectileAccuracyMin = attack.m_projectileAccuracyMin;
			spreadConfig.SettingChanged += delegate
			{
				attack.m_projectileAccuracy = m_projectileAccuracy * spreadConfig.Value;
				attack.m_projectileAccuracyMin = m_projectileAccuracyMin * spreadConfig.Value;
			};
			Attack obj = attack;
			obj.m_projectileAccuracy *= spreadConfig.Value;
			Attack obj2 = attack;
			obj2.m_projectileAccuracyMin *= spreadConfig.Value;
		}

		private static void SetLaunchAngle(Attack attack, ConfigEntry<float> angleConfig)
		{
			angleConfig.SettingChanged += delegate
			{
				attack.m_launchAngle = angleConfig.Value;
			};
			attack.m_launchAngle = angleConfig.Value;
		}

		[HarmonyPostfix]
		[HarmonyPatch("GetProjectileSpawnPoint")]
		private static void GetProjectileSpawnPointPostfix(Attack __instance, ref Vector3 spawnPoint, ref Vector3 aimDir)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Invalid comparison between Unknown and I4
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Invalid comparison between Unknown and I4
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Invalid comparison between Unknown and I4
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Invalid comparison between Unknown and I4
			ItemData playerWeapon = GetPlayerWeapon(__instance);
			if (playerWeapon != null)
			{
				SkillType skillType = playerWeapon.m_shared.m_skillType;
				if ((int)skillType == 8)
				{
					ApplyOffset(ref spawnPoint, ref aimDir, ProjectileTweaks.BowVerticalOffset.Value, ProjectileTweaks.BowHorizontalOffset.Value);
				}
				else if ((int)skillType == 14)
				{
					ApplyOffset(ref spawnPoint, ref aimDir, ProjectileTweaks.XbowVerticalOffset.Value, ProjectileTweaks.XbowHorizontalOffset.Value);
				}
				else if ((int)skillType == 5)
				{
					ApplyOffset(ref spawnPoint, ref aimDir, ProjectileTweaks.SpearVerticalOffset.Value, ProjectileTweaks.SpearHorizontalOffset.Value);
				}
				else if ((int)skillType == 9)
				{
					ApplyOffset(ref spawnPoint, ref aimDir, ProjectileTweaks.StaffVerticalOffset.Value, ProjectileTweaks.StaffHorizontalOffset.Value);
				}
				else if (IsBomb(playerWeapon))
				{
					ApplyOffset(ref spawnPoint, ref aimDir, ProjectileTweaks.BombVerticalOffset.Value, ProjectileTweaks.BombHorizontalOffset.Value);
				}
			}
		}

		private static void ApplyOffset(ref Vector3 spawnPoint, ref Vector3 aimDir, float vertOffset, float horzOffset)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: 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)
			Vector3 val = new Vector3(aimDir.z, 0f, 0f - aimDir.x);
			Vector3 normalized = ((Vector3)(ref val)).normalized;
			normalized *= horzOffset;
			spawnPoint += normalized;
			spawnPoint += new Vector3(0f, vertOffset, 0f);
		}

		private static ItemData GetPlayerWeapon(Attack attack)
		{
			if (attack != null)
			{
				Humanoid character = attack.m_character;
				Player val = (Player)(object)((character is Player) ? character : null);
				if (val != null && (((Character)val).m_name == "Human" || (Object)(object)val == (Object)(object)Player.m_localPlayer))
				{
					return ((Humanoid)val).GetCurrentWeapon();
				}
			}
			return null;
		}

		private static bool IsBomb(ItemData item)
		{
			return item.m_shared.m_attack.m_attackAnimation == "throw_bomb";
		}
	}
	[HarmonyPatch(typeof(Humanoid))]
	internal static class HumanoidPatch
	{
		[HarmonyPrefix]
		[HarmonyPriority(0)]
		[HarmonyPatch("GetAttackDrawPercentage")]
		private static void GetAttackDrawPercentagePrefix(Humanoid __instance, out float __state)
		{
			if (Object.op_Implicit((Object)(object)__instance) && (Object)(object)((__instance is Player) ? __instance : null) == (Object)(object)Player.m_localPlayer)
			{
				ItemData currentWeapon = __instance.GetCurrentWeapon();
				if (currentWeapon != null && currentWeapon.m_shared.m_attack.m_bowDraw)
				{
					__state = currentWeapon.m_shared.m_attack.m_drawDurationMin;
					currentWeapon.m_shared.m_attack.m_drawDurationMin = __state * (1f / ProjectileTweaks.BowDrawSpeed.Value);
					return;
				}
			}
			__state = -1f;
		}

		[HarmonyPostfix]
		[HarmonyPriority(800)]
		[HarmonyPatch("GetAttackDrawPercentage")]
		private static void GetAttackDrawPercentagePostfix(Humanoid __instance, ref float __state)
		{
			if (__state != -1f)
			{
				ItemData currentWeapon = __instance.GetCurrentWeapon();
				if (currentWeapon != null && currentWeapon.m_shared.m_attack.m_bowDraw)
				{
					currentWeapon.m_shared.m_attack.m_drawDurationMin = __state;
				}
			}
		}
	}
	[HarmonyPatch(typeof(ItemData))]
	internal static class ItemDataPatch
	{
		[HarmonyPrefix]
		[HarmonyPriority(0)]
		[HarmonyPatch("GetWeaponLoadingTime")]
		public static void GetWeaponLoadingTimePrefix(ItemData __instance, out float __state)
		{
			if (__instance.m_shared.m_attack.m_requiresReload)
			{
				__state = __instance.m_shared.m_attack.m_reloadTime;
				Attack attack = __instance.m_shared.m_attack;
				attack.m_reloadTime *= 1f / ProjectileTweaks.XBowReloadSpeed.Value;
			}
			else
			{
				__state = -1f;
			}
		}

		[HarmonyPostfix]
		[HarmonyPriority(800)]
		[HarmonyPatch("GetWeaponLoadingTime")]
		public static void GetWeaponLoadingTimePostfix(ItemData __instance, ref float __state)
		{
			if (__instance.m_shared.m_attack.m_requiresReload && __state != -1f)
			{
				__instance.m_shared.m_attack.m_reloadTime = __state;
			}
		}
	}
}
namespace ProjectileTweaks.Extensions
{
	internal static class EventExtensions
	{
		public static void SafeInvoke(this Action events)
		{
			if (events == null)
			{
				return;
			}
			Delegate[] invocationList = events.GetInvocationList();
			for (int i = 0; i < invocationList.Length; i++)
			{
				Action action = (Action)invocationList[i];
				try
				{
					action();
				}
				catch (Exception ex)
				{
					Log.LogWarning($"Exception thrown at event {new StackFrame(1).GetMethod().Name} in {action.Method.DeclaringType.Name}.{action.Method.Name}:\n{ex}");
				}
			}
		}

		public static void SafeInvoke<TArg1>(this Action<TArg1> events, TArg1 arg1)
		{
			if (events == null)
			{
				return;
			}
			Delegate[] invocationList = events.GetInvocationList();
			for (int i = 0; i < invocationList.Length; i++)
			{
				Action<TArg1> action = (Action<TArg1>)invocationList[i];
				try
				{
					action(arg1);
				}
				catch (Exception ex)
				{
					Log.LogWarning($"Exception thrown at event {new StackFrame(1).GetMethod().Name} in {action.Method.DeclaringType.Name}.{action.Method.Name}:\n{ex}");
				}
			}
		}

		public static void SafeInvoke<TArg1, TArg2>(this Action<TArg1, TArg2> events, TArg1 arg1, TArg2 arg2)
		{
			if (events == null)
			{
				return;
			}
			Delegate[] invocationList = events.GetInvocationList();
			for (int i = 0; i < invocationList.Length; i++)
			{
				Action<TArg1, TArg2> action = (Action<TArg1, TArg2>)invocationList[i];
				try
				{
					action(arg1, arg2);
				}
				catch (Exception ex)
				{
					Log.LogWarning($"Exception thrown at event {new StackFrame(1).GetMethod().Name} in {action.Method.DeclaringType.Name}.{action.Method.Name}:\n{ex}");
				}
			}
		}

		public static void SafeInvoke<TEventArg>(this EventHandler<TEventArg> events, object sender, TEventArg arg1)
		{
			if (events == null)
			{
				return;
			}
			Delegate[] invocationList = events.GetInvocationList();
			for (int i = 0; i < invocationList.Length; i++)
			{
				EventHandler<TEventArg> eventHandler = (EventHandler<TEventArg>)invocationList[i];
				try
				{
					eventHandler(sender, arg1);
				}
				catch (Exception ex)
				{
					Log.LogWarning($"Exception thrown at event {new StackFrame(1).GetMethod().Name} in {eventHandler.Method.DeclaringType.Name}.{eventHandler.Method.Name}:\n{ex}");
				}
			}
		}
	}
}
namespace ProjectileTweaks.Configs
{
	internal static class ConfigManager
	{
		private static string ConfigFileName;

		private static string ConfigFileFullPath;

		private static ConfigFile configFile;

		private static BaseUnityPlugin ConfigurationManager;

		private const string ConfigManagerGUID = "com.bepis.bepinex.configurationmanager";

		private static readonly ConfigurationManagerAttributes AdminConfig = new ConfigurationManagerAttributes
		{
			IsAdminOnly = true
		};

		private static readonly ConfigurationManagerAttributes ClientConfig = new ConfigurationManagerAttributes
		{
			IsAdminOnly = false
		};

		private const char ZWS = '\u200b';

		internal static event Action OnConfigWindowClosed;

		internal static event Action OnConfigFileReloaded;

		private static void InvokeOnConfigWindowClosed()
		{
			ConfigManager.OnConfigWindowClosed?.SafeInvoke();
		}

		private static void InvokeOnConfigFileReloaded()
		{
			ConfigManager.OnConfigFileReloaded?.SafeInvoke();
		}

		internal static ConfigEntry<T> BindConfig<T>(string section, string name, T value, string description, AcceptableValueBase acceptVals = null, bool synced = true)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			string extendedDescription = GetExtendedDescription(description, synced);
			return configFile.Bind<T>(section, name, value, new ConfigDescription(extendedDescription, acceptVals, new object[1] { synced ? AdminConfig : ClientConfig }));
		}

		internal static string SetStringPriority(string sectionName, int priority)
		{
			if (priority == 0)
			{
				return sectionName;
			}
			return new string('\u200b', priority) + sectionName;
		}

		internal static string GetExtendedDescription(string description, bool synchronizedSetting)
		{
			return description + (synchronizedSetting ? " [Synced with Server]" : " [Not Synced with Server]");
		}

		internal static void Init(string GUID, ConfigFile config, bool saveOnConfigSet = false)
		{
			configFile = config;
			configFile.SaveOnConfigSet = saveOnConfigSet;
			ConfigFileName = GUID + ".cfg";
			ConfigFileFullPath = Path.Combine(Paths.ConfigPath, ConfigFileName);
		}

		internal static bool DisableSaveOnConfigSet()
		{
			bool saveOnConfigSet = configFile.SaveOnConfigSet;
			configFile.SaveOnConfigSet = false;
			return saveOnConfigSet;
		}

		internal static void SaveOnConfigSet(bool value)
		{
			configFile.SaveOnConfigSet = value;
		}

		internal static void Save()
		{
			configFile.Save();
		}

		internal static void SetupWatcher()
		{
			FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(Paths.ConfigPath, ConfigFileName);
			fileSystemWatcher.Changed += ReloadConfigFile;
			fileSystemWatcher.Created += ReloadConfigFile;
			fileSystemWatcher.Renamed += ReloadConfigFile;
			fileSystemWatcher.IncludeSubdirectories = true;
			fileSystemWatcher.SynchronizingObject = ThreadingHelper.SynchronizingObject;
			fileSystemWatcher.EnableRaisingEvents = true;
		}

		private static void ReloadConfigFile(object sender, FileSystemEventArgs e)
		{
			if (!File.Exists(ConfigFileFullPath))
			{
				return;
			}
			try
			{
				Log.LogInfo("Reloading config file");
				bool value = DisableSaveOnConfigSet();
				configFile.Reload();
				SaveOnConfigSet(value);
				InvokeOnConfigFileReloaded();
			}
			catch
			{
				Log.LogError("There was an issue loading your " + ConfigFileName);
				Log.LogError("Please check your config entries for spelling and format!");
			}
		}

		internal static void CheckForConfigManager()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Invalid comparison between Unknown and I4
			if ((int)SystemInfo.graphicsDeviceType != 4 && Chainloader.PluginInfos.TryGetValue("com.bepis.bepinex.configurationmanager", out var value) && Object.op_Implicit((Object)(object)value.Instance))
			{
				ConfigurationManager = value.Instance;
				Log.LogDebug("Configuration manager found, hooking DisplayingWindowChanged");
				EventInfo @event = ((object)ConfigurationManager).GetType().GetEvent("DisplayingWindowChanged");
				if (@event != null)
				{
					Action<object, object> action = OnConfigManagerDisplayingWindowChanged;
					Delegate handler = Delegate.CreateDelegate(@event.EventHandlerType, action.Target, action.Method);
					@event.AddEventHandler(ConfigurationManager, handler);
				}
			}
		}

		private static void OnConfigManagerDisplayingWindowChanged(object sender, object e)
		{
			if (!(bool)((object)ConfigurationManager).GetType().GetProperty("DisplayingWindow").GetValue(ConfigurationManager, null))
			{
				InvokeOnConfigWindowClosed();
			}
		}
	}
}