Decompiled source of AlwaysPracticeMakesPerfect v1.0.0

BepInEx/plugins/AlwaysPracticeMakesPerfect.dll

Decompiled 2 days 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 Animancer;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Pigeon.Math;
using Pigeon.Movement;
using TMPro;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Sparroh")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.1.0.0")]
[assembly: AssemblyInformationalVersion("1.1.0")]
[assembly: AssemblyProduct("AlwaysPracticeMakesPerfect")]
[assembly: AssemblyTitle("AlwaysPracticeMakesPerfect")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.1.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;
		}
	}
}
public static class ConfigManager
{
	private const float DebounceSeconds = 0.25f;

	private const float DefaultWindowDuration = 0.45f;

	private const float DefaultReloadSpeedMultiplier = 2.5f;

	private static ConfigFile config;

	private static ManualLogSource logger;

	private static FileSystemWatcher configWatcher;

	private static volatile bool reloadPending;

	private static float lastReloadTime;

	public static ConfigEntry<bool> EnablePracticeMakesPerfect { get; private set; }

	public static ConfigEntry<float> WindowDuration { get; private set; }

	public static ConfigEntry<float> ReloadSpeedMultiplier { get; private set; }

	public static void Initialize(ConfigFile configFile, ManualLogSource log)
	{
		config = configFile;
		logger = log;
		EnablePracticeMakesPerfect = config.Bind<bool>("General", "Enable Practice Makes Perfect", true, "Enables the Practice Makes Perfect reload timing mini-game on all weapons.");
		WindowDuration = config.Bind<float>("General", "Window Duration", 0.45f, "Width of the timing window during reload (seconds of animation time). Vanilla upgrade uses a short window.");
		ReloadSpeedMultiplier = config.Bind<float>("General", "Reload Speed Multiplier", 2.5f, "Reload animation speed multiplier applied when you press Fire inside the timing window.");
		try
		{
			SetupFileWatcher();
		}
		catch (Exception ex)
		{
			logger.LogError((object)("Error setting up config file watcher: " + ex.Message));
		}
	}

	public static void Tick()
	{
		if (!reloadPending || Time.unscaledTime - lastReloadTime < 0.25f)
		{
			return;
		}
		reloadPending = false;
		lastReloadTime = Time.unscaledTime;
		try
		{
			config.Reload();
			logger.LogInfo((object)($"Config reloaded. Enable={EnablePracticeMakesPerfect.Value}, " + $"Window={WindowDuration.Value}, Speed={ReloadSpeedMultiplier.Value}"));
		}
		catch (Exception ex)
		{
			logger.LogError((object)("Error reloading config: " + ex.Message));
		}
	}

	public static void Dispose()
	{
		if (configWatcher != null)
		{
			configWatcher.EnableRaisingEvents = false;
			configWatcher.Changed -= OnConfigFileChanged;
			configWatcher.Created -= OnConfigFileChanged;
			configWatcher.Renamed -= OnConfigFileChanged;
			configWatcher.Dispose();
			configWatcher = null;
		}
	}

	private static void SetupFileWatcher()
	{
		configWatcher = new FileSystemWatcher(Paths.ConfigPath, "sparroh.alwayspracticemakesperfect.cfg");
		configWatcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.LastWrite;
		configWatcher.Changed += OnConfigFileChanged;
		configWatcher.Created += OnConfigFileChanged;
		configWatcher.Renamed += OnConfigFileChanged;
		configWatcher.EnableRaisingEvents = true;
	}

	private static void OnConfigFileChanged(object sender, FileSystemEventArgs e)
	{
		reloadPending = true;
	}
}
internal static class InstaReloadPatches
{
	private enum FeedbackKind
	{
		None,
		Success,
		Miss
	}

	private sealed class GenericInstaReloadState
	{
		public Gun Gun;

		public float WindowCenterNormalized;

		public bool Active;

		public bool Succeeded;

		public int LastTickFrame;
	}

	private static class ListPool<T>
	{
		private static readonly Stack<List<T>> pool = new Stack<List<T>>();

		public static List<T> Get()
		{
			if (pool.Count <= 0)
			{
				return new List<T>(8);
			}
			return pool.Pop();
		}

		public static void Release(List<T> list)
		{
			list.Clear();
			pool.Push(list);
		}
	}

	private static readonly FieldInfo animatorField = AccessTools.Field(typeof(Gun), "animator");

	private static readonly FieldInfo reloadAnimationField = AccessTools.Field(typeof(Gun), "reloadAnimation");

	private static readonly FieldInfo hudField = AccessTools.Field(typeof(Gun), "hud");

	private static readonly FieldInfo instaReloadTimeField = AccessTools.Field(typeof(FastReloadShotgun), "instaReloadTime");

	private static readonly Dictionary<int, GenericInstaReloadState> genericStates = new Dictionary<int, GenericInstaReloadState>();

	private static GameObject sharedBarRoot;

	private static RectTransform trackRt;

	private static RectTransform sweetSpotRt;

	private static Image sweetSpotImage;

	private static RectTransform cursorRt;

	private static Image cursorImage;

	private static TextMeshProUGUI promptLabel;

	private static bool barVisible;

	private static float feedbackUntil;

	private static FeedbackKind feedbackKind;

	private static float lfProgress01;

	private static float lfSweetMin01;

	private static float lfSweetMax01;

	private static bool lfInWindow;

	private static bool lfBarArmed;

	private static bool loggedMissingAnimator;

	private static bool loggedFirstState;

	private static bool loggedFirstTick;

	private static bool loggedFirstWindow;

	private const float BarWidth = 280f;

	private const float BarHeight = 14f;

	private const float CursorWidth = 3f;

	private const float AnchorY = 0.3f;

	private static readonly Color TrackColor = new Color(0.05f, 0.07f, 0.1f, 0.72f);

	private static readonly Color SweetSpotIdle = new Color(0.98f, 0.82f, 0.35f, 0.45f);

	private static readonly Color SweetSpotActive = new Color(0.98f, 0.82f, 0.35f, 0.92f);

	private static readonly Color SweetSpotSuccess = new Color(0.2f, 0.9f, 0.45f, 0.95f);

	private static readonly Color SweetSpotMiss = new Color(0.95f, 0.3f, 0.35f, 0.9f);

	private static readonly Color CursorIdle = new Color(0.95f, 0.96f, 0.98f, 0.95f);

	private static readonly Color CursorActive = new Color(1f, 0.92f, 0.35f, 1f);

	private static readonly Color PromptColor = new Color(1f, 0.92f, 0.35f, 1f);

	internal static void Cleanup()
	{
		HideBar();
		genericStates.Clear();
		if ((Object)(object)sharedBarRoot != (Object)null)
		{
			Object.Destroy((Object)(object)sharedBarRoot);
			sharedBarRoot = null;
			trackRt = null;
			sweetSpotRt = null;
			sweetSpotImage = null;
			cursorRt = null;
			cursorImage = null;
			promptLabel = null;
		}
	}

	internal static void TickTrackedGuns()
	{
		if (!ConfigManager.EnablePracticeMakesPerfect.Value)
		{
			if (genericStates.Count > 0)
			{
				genericStates.Clear();
				HideBar();
			}
			return;
		}
		TickFeedbackExpiry();
		if (genericStates.Count == 0)
		{
			return;
		}
		List<int> list = ListPool<int>.Get();
		list.AddRange(genericStates.Keys);
		for (int i = 0; i < list.Count; i++)
		{
			int key = list[i];
			if (genericStates.TryGetValue(key, out var value) && value.Active && value.LastTickFrame != Time.frameCount)
			{
				Gun gun = value.Gun;
				if ((Object)(object)gun == (Object)null)
				{
					genericStates.Remove(key);
				}
				else
				{
					TickGun(gun);
				}
			}
		}
		ListPool<int>.Release(list);
	}

	private static void TickFeedbackExpiry()
	{
		if (feedbackKind != FeedbackKind.None && !(Time.unscaledTime < feedbackUntil))
		{
			feedbackKind = FeedbackKind.None;
			HideBar();
		}
	}

	[HarmonyPatch(typeof(FastReloadShotgun), "OnUpgradesEnabled")]
	[HarmonyPostfix]
	private static void FastReloadShotgun_OnUpgradesEnabled_Postfix(FastReloadShotgun __instance)
	{
		if (ConfigManager.EnablePracticeMakesPerfect.Value && !((Object)(object)__instance == (Object)null) && ((NetworkBehaviour)__instance).IsOwner)
		{
			ref LeadFlingerData data = ref __instance.Data;
			if (!(data.instaReloadDuration > 0f))
			{
				data.instaReloadDuration = Mathf.Max(0.01f, ConfigManager.WindowDuration.Value);
				data.instaReloadSpeed = Mathf.Max(1f, ConfigManager.ReloadSpeedMultiplier.Value);
				((Gun)__instance).SetUpgradeFlag_Owner((GearUpgradeFlags)268435456, true);
			}
		}
	}

	[HarmonyPatch(typeof(FastReloadShotgun), "OnReload")]
	[HarmonyPostfix]
	private static void FastReloadShotgun_OnReload_Postfix(FastReloadShotgun __instance)
	{
		if (ConfigManager.EnablePracticeMakesPerfect.Value && !((Object)(object)__instance == (Object)null) && ((NetworkBehaviour)__instance).IsOwner)
		{
			ref LeadFlingerData data = ref __instance.Data;
			if (data.instaReloadDuration <= 0f)
			{
				data.instaReloadDuration = Mathf.Max(0.01f, ConfigManager.WindowDuration.Value);
				data.instaReloadSpeed = Mathf.Max(1f, ConfigManager.ReloadSpeedMultiplier.Value);
			}
			if (!(instaReloadTimeField == null) && !((float)instaReloadTimeField.GetValue(__instance) > 0f))
			{
				float instaReloadDuration = data.instaReloadDuration;
				float num = ((Random)(ref Random.shared)).NextFloat(instaReloadDuration * 0.7f, 0.7f);
				instaReloadTimeField.SetValue(__instance, num);
			}
		}
	}

	[HarmonyPatch(typeof(FastReloadShotgun), "OnActiveUpdate")]
	[HarmonyPrefix]
	private static void FastReloadShotgun_OnActiveUpdate_Prefix(FastReloadShotgun __instance)
	{
		//IL_0181: Unknown result type (might be due to invalid IL or missing references)
		//IL_0186: Unknown result type (might be due to invalid IL or missing references)
		lfBarArmed = false;
		if ((Object)(object)__instance == (Object)null || !((NetworkBehaviour)__instance).IsOwner || !ConfigManager.EnablePracticeMakesPerfect.Value)
		{
			return;
		}
		ref LeadFlingerData data = ref __instance.Data;
		if (data.instaReloadDuration <= 0f || instaReloadTimeField == null || !((Gun)__instance).Reloading || !((Gun)__instance).Active)
		{
			return;
		}
		float num = (float)instaReloadTimeField.GetValue(__instance);
		if (num <= 0f)
		{
			return;
		}
		object? obj = animatorField?.GetValue(__instance);
		PlayerAnimation val = (PlayerAnimation)((obj is PlayerAnimation) ? obj : null);
		if ((Object)(object)val == (Object)null)
		{
			return;
		}
		AnimancerState currentState = val.CurrentState;
		if (currentState == null)
		{
			return;
		}
		object obj2 = reloadAnimationField?.GetValue(__instance);
		if ((obj2 != null && object.Equals(currentState.Key, obj2)) || !(currentState.NormalizedTime <= 0f) || !(currentState.Time <= 0f))
		{
			float num2 = currentState.Duration;
			if (num2 <= 0.001f)
			{
				num2 = Mathf.Max(currentState.Length, 0.01f);
			}
			float time = currentState.Time;
			float num3 = data.instaReloadDuration * 0.5f;
			float num4 = num2 * num;
			lfProgress01 = Mathf.Clamp01(time / num2);
			lfSweetMin01 = Mathf.Clamp01((num4 - num3) / num2);
			lfSweetMax01 = Mathf.Clamp01((num4 + num3) / num2);
			lfInWindow = time >= num4 - num3 && time <= num4 + num3;
			lfBarArmed = true;
			bool flag = false;
			try
			{
				PlayerActions player = PlayerInput.Controls.Player;
				flag = ((PlayerActions)(ref player)).Fire.WasPressedThisFrame();
			}
			catch
			{
			}
			if (flag)
			{
				FlashFeedback(lfInWindow ? FeedbackKind.Success : FeedbackKind.Miss);
			}
		}
	}

	[HarmonyPatch(typeof(FastReloadShotgun), "OnActiveUpdate")]
	[HarmonyPostfix]
	private static void FastReloadShotgun_OnActiveUpdate_Postfix(FastReloadShotgun __instance)
	{
		if ((Object)(object)__instance == (Object)null || !((NetworkBehaviour)__instance).IsOwner)
		{
			return;
		}
		SuppressVanillaPopup(__instance);
		if (!ConfigManager.EnablePracticeMakesPerfect.Value)
		{
			if (barVisible && feedbackKind == FeedbackKind.None)
			{
				HideBar();
			}
		}
		else if (feedbackKind != FeedbackKind.None)
		{
			UpdateBarVisual(lfProgress01, lfSweetMin01, lfSweetMax01, lfInWindow);
		}
		else if (!lfBarArmed)
		{
			if (barVisible)
			{
				HideBar();
			}
		}
		else
		{
			UpdateBarVisual(lfProgress01, lfSweetMin01, lfSweetMax01, lfInWindow);
		}
	}

	private static void SuppressVanillaPopup(FastReloadShotgun gun)
	{
		if (!ConfigManager.EnablePracticeMakesPerfect.Value)
		{
			return;
		}
		try
		{
			object? obj = hudField?.GetValue(gun);
			FastShotgunHUD val = (FastShotgunHUD)((obj is FastShotgunHUD) ? obj : null);
			if ((Object)(object)val?.InstaReloadPopup != (Object)null && val.InstaReloadPopup.activeSelf)
			{
				val.InstaReloadPopup.SetActive(false);
			}
		}
		catch
		{
		}
	}

	[HarmonyPatch(typeof(Gun), "ForceStartReload")]
	[HarmonyPostfix]
	private static void Gun_ForceStartReload_Postfix(Gun __instance)
	{
		if (ConfigManager.EnablePracticeMakesPerfect.Value && !((Object)(object)__instance == (Object)null) && ((NetworkBehaviour)__instance).IsOwner && !(__instance is FastReloadShotgun) && __instance.Reloading)
		{
			float num = Mathf.Max(0.01f, ConfigManager.WindowDuration.Value);
			float num2 = ((Random)(ref Random.shared)).NextFloat(num * 0.7f, 0.7f);
			int instanceID = ((Object)__instance).GetInstanceID();
			genericStates[instanceID] = new GenericInstaReloadState
			{
				Gun = __instance,
				WindowCenterNormalized = num2,
				Active = true,
				Succeeded = false,
				LastTickFrame = -1
			};
			feedbackKind = FeedbackKind.None;
			if (!loggedFirstState)
			{
				loggedFirstState = true;
				SparrohPlugin.Logger.LogInfo((object)("[PMPA] Generic insta-reload armed for " + ((object)__instance).GetType().Name + " " + $"(center={num2:F3}, window={num:F3})."));
			}
		}
	}

	[HarmonyPatch(typeof(Gun), "Update")]
	[HarmonyPostfix]
	private static void Gun_Update_Postfix(Gun __instance)
	{
		if (!((Object)(object)__instance == (Object)null) && ((NetworkBehaviour)__instance).IsOwner && !(__instance is FastReloadShotgun) && __instance.Active)
		{
			TickGun(__instance);
		}
	}

	[HarmonyPatch(typeof(Gun), "Disable")]
	[HarmonyPostfix]
	private static void Gun_Disable_Postfix(Gun __instance)
	{
		if (!((Object)(object)__instance == (Object)null))
		{
			genericStates.Remove(((Object)__instance).GetInstanceID());
			if (feedbackKind == FeedbackKind.None)
			{
				HideBar();
			}
		}
	}

	[HarmonyPatch(typeof(Gun), "OnDestroy")]
	[HarmonyPrefix]
	private static void Gun_OnDestroy_Prefix(Gun __instance)
	{
		if (!((Object)(object)__instance == (Object)null))
		{
			genericStates.Remove(((Object)__instance).GetInstanceID());
			if (feedbackKind == FeedbackKind.None)
			{
				HideBar();
			}
		}
	}

	private static void TickGun(Gun gun)
	{
		//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)gun == (Object)null || gun is FastReloadShotgun)
		{
			return;
		}
		int instanceID = ((Object)gun).GetInstanceID();
		if (!ConfigManager.EnablePracticeMakesPerfect.Value)
		{
			if (genericStates.Remove(instanceID))
			{
				HideBar();
			}
		}
		else
		{
			if (!genericStates.TryGetValue(instanceID, out var value) || !value.Active || value.LastTickFrame == Time.frameCount)
			{
				return;
			}
			value.LastTickFrame = Time.frameCount;
			if (!loggedFirstTick)
			{
				loggedFirstTick = true;
				SparrohPlugin.Logger.LogInfo((object)("[PMPA] First generic tick on " + ((object)gun).GetType().Name + "."));
			}
			if (!gun.Reloading || !gun.Active)
			{
				genericStates.Remove(instanceID);
				if (feedbackKind == FeedbackKind.None)
				{
					HideBar();
				}
				return;
			}
			if (value.Succeeded)
			{
				if (feedbackKind == FeedbackKind.None)
				{
					HideBar();
				}
				return;
			}
			object? obj = animatorField?.GetValue(gun);
			PlayerAnimation val = (PlayerAnimation)((obj is PlayerAnimation) ? obj : null);
			if ((Object)(object)val == (Object)null)
			{
				if (!loggedMissingAnimator)
				{
					loggedMissingAnimator = true;
					SparrohPlugin.Logger.LogWarning((object)"[PMPA] Could not access Gun.animator.");
				}
				return;
			}
			AnimancerState currentState = val.CurrentState;
			if (currentState == null)
			{
				if (feedbackKind == FeedbackKind.None)
				{
					HideBar();
				}
				return;
			}
			object obj2 = reloadAnimationField?.GetValue(gun);
			if ((obj2 == null || !object.Equals(currentState.Key, obj2)) && currentState.NormalizedTime <= 0f && currentState.Time <= 0f)
			{
				if (feedbackKind == FeedbackKind.None)
				{
					HideBar();
				}
				return;
			}
			float num = Mathf.Max(0.01f, ConfigManager.WindowDuration.Value) * 0.5f;
			float num2 = currentState.Duration;
			if (num2 <= 0.001f)
			{
				num2 = Mathf.Max(currentState.Length, 0.01f);
			}
			float time = currentState.Time;
			float num3 = num2 * value.WindowCenterNormalized;
			bool flag = time >= num3 - num && time <= num3 + num;
			bool flag2 = false;
			try
			{
				PlayerActions player = PlayerInput.Controls.Player;
				flag2 = ((PlayerActions)(ref player)).Fire.WasPressedThisFrame();
			}
			catch
			{
			}
			float progress = Mathf.Clamp01(time / num2);
			float sweetMin = Mathf.Clamp01((num3 - num) / num2);
			float sweetMax = Mathf.Clamp01((num3 + num) / num2);
			if (flag)
			{
				if (!loggedFirstWindow)
				{
					loggedFirstWindow = true;
					SparrohPlugin.Logger.LogInfo((object)("[PMPA] Timing window open on " + ((object)gun).GetType().Name + " " + $"(t={time:F3}, center={num3:F3}, half={num:F3})."));
				}
				if (flag2)
				{
					value.Succeeded = true;
					value.Active = false;
					((AnimancerNode)currentState).Speed = ((AnimancerNode)currentState).Speed * Mathf.Max(1f, ConfigManager.ReloadSpeedMultiplier.Value);
					FlashFeedback(FeedbackKind.Success);
					TryTriggerReloadEffect(gun);
					SparrohPlugin.Logger.LogInfo((object)$"[PMPA] Success on {((object)gun).GetType().Name}; speed now {((AnimancerNode)currentState).Speed:F2}.");
				}
			}
			else if (flag2)
			{
				value.Active = false;
				genericStates.Remove(instanceID);
				FlashFeedback(FeedbackKind.Miss);
			}
			_ = feedbackKind;
			UpdateBarVisual(progress, sweetMin, sweetMax, flag);
		}
	}

	private static void EnsureBar()
	{
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		//IL_001d: Expected O, but got Unknown
		//IL_005e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0082: Unknown result type (might be due to invalid IL or missing references)
		//IL_0088: Expected O, but got Unknown
		//IL_00af: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
		//IL_0102: Expected O, but got Unknown
		//IL_012e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0147: Unknown result type (might be due to invalid IL or missing references)
		//IL_0160: Unknown result type (might be due to invalid IL or missing references)
		//IL_0179: Unknown result type (might be due to invalid IL or missing references)
		//IL_018a: Unknown result type (might be due to invalid IL or missing references)
		//IL_019f: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
		//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
		//IL_0206: Unknown result type (might be due to invalid IL or missing references)
		//IL_0230: Unknown result type (might be due to invalid IL or missing references)
		//IL_0245: Unknown result type (might be due to invalid IL or missing references)
		//IL_024a: Unknown result type (might be due to invalid IL or missing references)
		//IL_025c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0276: Unknown result type (might be due to invalid IL or missing references)
		//IL_028f: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b7: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d0: Unknown result type (might be due to invalid IL or missing references)
		//IL_02e9: Unknown result type (might be due to invalid IL or missing references)
		//IL_0303: Unknown result type (might be due to invalid IL or missing references)
		//IL_0308: Unknown result type (might be due to invalid IL or missing references)
		//IL_031a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0334: Unknown result type (might be due to invalid IL or missing references)
		//IL_034d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0366: Unknown result type (might be due to invalid IL or missing references)
		//IL_037f: Unknown result type (might be due to invalid IL or missing references)
		//IL_038e: Unknown result type (might be due to invalid IL or missing references)
		//IL_03a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_03c1: Unknown result type (might be due to invalid IL or missing references)
		//IL_03c6: Unknown result type (might be due to invalid IL or missing references)
		//IL_03d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_03e9: Unknown result type (might be due to invalid IL or missing references)
		//IL_03fe: Unknown result type (might be due to invalid IL or missing references)
		//IL_0413: Unknown result type (might be due to invalid IL or missing references)
		//IL_0428: Unknown result type (might be due to invalid IL or missing references)
		//IL_043c: Unknown result type (might be due to invalid IL or missing references)
		//IL_048d: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)sharedBarRoot != (Object)null))
		{
			sharedBarRoot = new GameObject("AlwaysPracticeMakesPerfect_ReloadBar");
			Object.DontDestroyOnLoad((Object)(object)sharedBarRoot);
			Canvas obj = sharedBarRoot.AddComponent<Canvas>();
			obj.renderMode = (RenderMode)0;
			obj.sortingOrder = 9000;
			CanvasScaler obj2 = sharedBarRoot.AddComponent<CanvasScaler>();
			obj2.uiScaleMode = (ScaleMode)1;
			obj2.referenceResolution = new Vector2(1920f, 1080f);
			obj2.matchWidthOrHeight = 0.5f;
			sharedBarRoot.AddComponent<GraphicRaycaster>();
			GameObject val = new GameObject("Container");
			val.transform.SetParent(sharedBarRoot.transform, false);
			RectTransform obj3 = val.AddComponent<RectTransform>();
			obj3.anchorMin = new Vector2(0.5f, 0.3f);
			obj3.anchorMax = new Vector2(0.5f, 0.3f);
			obj3.pivot = new Vector2(0.5f, 0.5f);
			obj3.sizeDelta = new Vector2(304f, 54f);
			GameObject val2 = new GameObject("Track");
			val2.transform.SetParent(val.transform, false);
			trackRt = val2.AddComponent<RectTransform>();
			trackRt.anchorMin = new Vector2(0.5f, 0.5f);
			trackRt.anchorMax = new Vector2(0.5f, 0.5f);
			trackRt.pivot = new Vector2(0.5f, 0.5f);
			trackRt.sizeDelta = new Vector2(280f, 14f);
			Image obj4 = val2.AddComponent<Image>();
			((Graphic)obj4).color = TrackColor;
			((Graphic)obj4).raycastTarget = false;
			GameObject val3 = new GameObject("Outline");
			val3.transform.SetParent(val.transform, false);
			RectTransform obj5 = val3.AddComponent<RectTransform>();
			obj5.anchorMin = new Vector2(0.5f, 0.5f);
			obj5.anchorMax = new Vector2(0.5f, 0.5f);
			obj5.pivot = new Vector2(0.5f, 0.5f);
			obj5.sizeDelta = new Vector2(284f, 18f);
			((Transform)obj5).SetSiblingIndex(0);
			Image obj6 = val3.AddComponent<Image>();
			((Graphic)obj6).color = new Color(0.25f, 0.4f, 0.5f, 0.55f);
			((Graphic)obj6).raycastTarget = false;
			GameObject val4 = new GameObject("SweetSpot");
			val4.transform.SetParent(val2.transform, false);
			sweetSpotRt = val4.AddComponent<RectTransform>();
			sweetSpotRt.anchorMin = new Vector2(0f, 0f);
			sweetSpotRt.anchorMax = new Vector2(0f, 1f);
			sweetSpotRt.pivot = new Vector2(0f, 0.5f);
			sweetSpotRt.anchoredPosition = Vector2.zero;
			sweetSpotRt.sizeDelta = new Vector2(20f, 0f);
			sweetSpotImage = val4.AddComponent<Image>();
			((Graphic)sweetSpotImage).color = SweetSpotIdle;
			((Graphic)sweetSpotImage).raycastTarget = false;
			GameObject val5 = new GameObject("Cursor");
			val5.transform.SetParent(val2.transform, false);
			cursorRt = val5.AddComponent<RectTransform>();
			cursorRt.anchorMin = new Vector2(0f, 0.5f);
			cursorRt.anchorMax = new Vector2(0f, 0.5f);
			cursorRt.pivot = new Vector2(0.5f, 0.5f);
			cursorRt.sizeDelta = new Vector2(3f, 24f);
			cursorRt.anchoredPosition = Vector2.zero;
			cursorImage = val5.AddComponent<Image>();
			((Graphic)cursorImage).color = CursorIdle;
			((Graphic)cursorImage).raycastTarget = false;
			GameObject val6 = new GameObject("Prompt");
			val6.transform.SetParent(val.transform, false);
			RectTransform obj7 = val6.AddComponent<RectTransform>();
			obj7.anchorMin = new Vector2(0.5f, 0.5f);
			obj7.anchorMax = new Vector2(0.5f, 0.5f);
			obj7.pivot = new Vector2(0.5f, 0f);
			obj7.anchoredPosition = new Vector2(0f, 13f);
			obj7.sizeDelta = new Vector2(280f, 28f);
			promptLabel = val6.AddComponent<TextMeshProUGUI>();
			((TMP_Text)promptLabel).text = "FIRE";
			((TMP_Text)promptLabel).alignment = (TextAlignmentOptions)514;
			((TMP_Text)promptLabel).fontSize = 22f;
			((TMP_Text)promptLabel).fontStyle = (FontStyles)1;
			((Graphic)promptLabel).color = PromptColor;
			((Graphic)promptLabel).raycastTarget = false;
			if ((Object)(object)TMP_Settings.defaultFontAsset != (Object)null)
			{
				((TMP_Text)promptLabel).font = TMP_Settings.defaultFontAsset;
			}
			((Component)promptLabel).gameObject.SetActive(false);
			sharedBarRoot.SetActive(false);
			barVisible = false;
		}
	}

	private static void UpdateBarVisual(float progress01, float sweetMin01, float sweetMax01, bool inWindow)
	{
		//IL_0050: Unknown result type (might be due to invalid IL or missing references)
		//IL_0065: Unknown result type (might be due to invalid IL or missing references)
		//IL_0080: Unknown result type (might be due to invalid IL or missing references)
		//IL_0097: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
		//IL_0100: Unknown result type (might be due to invalid IL or missing references)
		//IL_010f: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
		//IL_017f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0184: Unknown result type (might be due to invalid IL or missing references)
		//IL_0196: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
		//IL_013d: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
		EnsureBar();
		progress01 = Mathf.Clamp01(progress01);
		sweetMin01 = Mathf.Clamp01(sweetMin01);
		sweetMax01 = Mathf.Clamp01(Mathf.Max(sweetMax01, sweetMin01 + 0.01f));
		float num = sweetMin01 * 280f;
		float num2 = Mathf.Max(4f, (sweetMax01 - sweetMin01) * 280f);
		sweetSpotRt.anchoredPosition = new Vector2(num, 0f);
		sweetSpotRt.sizeDelta = new Vector2(num2, 0f);
		cursorRt.anchoredPosition = new Vector2(progress01 * 280f, 0f);
		if (feedbackKind == FeedbackKind.Success)
		{
			((Graphic)sweetSpotImage).color = SweetSpotSuccess;
			((Graphic)cursorImage).color = SweetSpotSuccess;
			if ((Object)(object)promptLabel != (Object)null)
			{
				((TMP_Text)promptLabel).text = "NICE";
				((Graphic)promptLabel).color = SweetSpotSuccess;
				((Component)promptLabel).gameObject.SetActive(true);
			}
		}
		else if (feedbackKind == FeedbackKind.Miss)
		{
			((Graphic)sweetSpotImage).color = SweetSpotMiss;
			((Graphic)cursorImage).color = SweetSpotMiss;
			if ((Object)(object)promptLabel != (Object)null)
			{
				((TMP_Text)promptLabel).text = "MISS";
				((Graphic)promptLabel).color = SweetSpotMiss;
				((Component)promptLabel).gameObject.SetActive(true);
			}
		}
		else if (inWindow)
		{
			float num3 = 0.85f + 0.15f * Mathf.Sin(Time.unscaledTime * 14f);
			Color sweetSpotActive = SweetSpotActive;
			sweetSpotActive.a *= num3;
			((Graphic)sweetSpotImage).color = sweetSpotActive;
			((Graphic)cursorImage).color = CursorActive;
			if ((Object)(object)promptLabel != (Object)null)
			{
				((TMP_Text)promptLabel).text = "FIRE";
				((Graphic)promptLabel).color = PromptColor;
				((Component)promptLabel).gameObject.SetActive(true);
			}
		}
		else
		{
			((Graphic)sweetSpotImage).color = SweetSpotIdle;
			((Graphic)cursorImage).color = CursorIdle;
			if ((Object)(object)promptLabel != (Object)null)
			{
				((Component)promptLabel).gameObject.SetActive(false);
			}
		}
		if (!sharedBarRoot.activeSelf)
		{
			sharedBarRoot.SetActive(true);
		}
		barVisible = true;
	}

	private static void FlashFeedback(FeedbackKind kind)
	{
		feedbackKind = kind;
		feedbackUntil = Time.unscaledTime + 0.35f;
	}

	private static void HideBar()
	{
		feedbackKind = FeedbackKind.None;
		if ((Object)(object)sharedBarRoot != (Object)null && sharedBarRoot.activeSelf)
		{
			sharedBarRoot.SetActive(false);
		}
		barVisible = false;
	}

	private static void TryTriggerReloadEffect(Gun gun)
	{
		try
		{
			(AccessTools.Method(((object)gun).GetType(), "TriggerEffectReload", (Type[])null, (Type[])null) ?? AccessTools.Method(typeof(Gun), "TriggerEffectReload", (Type[])null, (Type[])null))?.Invoke(gun, null);
		}
		catch
		{
		}
	}
}
[BepInPlugin("sparroh.alwayspracticemakesperfect", "AlwaysPracticeMakesPerfect", "1.1.0")]
[MycoMod(/*Could not decode attribute arguments.*/)]
public class SparrohPlugin : BaseUnityPlugin
{
	public const string PluginGUID = "sparroh.alwayspracticemakesperfect";

	public const string PluginName = "AlwaysPracticeMakesPerfect";

	public const string PluginVersion = "1.1.0";

	internal static ManualLogSource Logger;

	private Harmony harmony;

	private void Awake()
	{
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_002b: Expected O, but got Unknown
		Logger = ((BaseUnityPlugin)this).Logger;
		ConfigManager.Initialize(((BaseUnityPlugin)this).Config, Logger);
		harmony = new Harmony("sparroh.alwayspracticemakesperfect");
		try
		{
			harmony.PatchAll(typeof(InstaReloadPatches));
			Logger.LogInfo((object)"Harmony patches applied.");
		}
		catch (Exception ex)
		{
			Logger.LogError((object)("Error applying patches: " + ex.Message));
		}
		Logger.LogInfo((object)"AlwaysPracticeMakesPerfect v1.1.0 loaded successfully.");
	}

	private void Update()
	{
		ConfigManager.Tick();
		try
		{
			InstaReloadPatches.TickTrackedGuns();
		}
		catch (Exception ex)
		{
			Logger.LogError((object)("Error in insta-reload tick: " + ex.Message));
		}
	}

	private void OnDestroy()
	{
		InstaReloadPatches.Cleanup();
		ConfigManager.Dispose();
		Harmony obj = harmony;
		if (obj != null)
		{
			obj.UnpatchSelf();
		}
	}
}
namespace AlwaysPracticeMakesPerfect
{
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "AlwaysPracticeMakesPerfect";

		public const string PLUGIN_NAME = "AlwaysPracticeMakesPerfect";

		public const string PLUGIN_VERSION = "1.1.0";
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}