Decompiled source of Luckyrun v0.2.2

LuckyShotSpeedrun.dll

Decompiled a day ago
using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using OpenShot.Core;
using OpenShot.Events;
using OpenShot.UI;
using UnityEngine;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("LuckyShotSpeedrun")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("LuckyShot Speedrun Timer Mod")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyInformationalVersion("0.1.0")]
[assembly: AssemblyProduct("LuckyShotSpeedrun")]
[assembly: AssemblyTitle("LuckyShotSpeedrun")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.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;
		}
	}
}
namespace LuckyShotSpeedrun
{
	[BepInPlugin("com.liam.luckyshot.speedrun", "LuckyShotSpeedrun", "0.1.0")]
	public class Plugin : BaseUnityPlugin
	{
		[Serializable]
		public class Settings
		{
			public bool AutoStart = true;

			public bool StartOnFirstShot = true;

			public bool StartOnSceneLoad;

			public bool StartOnSpawnerStart;

			public bool PauseOnMenu = true;

			public bool ShowAlways;

			public string Category = "Any%";

			public bool EndRunOnFail = true;

			public int LowShotThreshold = 5;

			public string Seed = "";
		}

		[Serializable]
		public class RunResult
		{
			public bool Success;

			public double Time;

			public int Shots;

			public int Hits;

			public string Category;

			public string Timestamp;
		}

		public static ManualLogSource Logger;

		public static Settings settings;

		public static Stopwatch sw = new Stopwatch();

		public static bool running = false;

		public static bool paused = false;

		public static int Shots = 0;

		public static int Hits = 0;

		public static float lastShotTime = 0f;

		public static bool pendingShot = false;

		public static float hitWindow = 0.5f;

		public static bool runFailed = false;

		public static readonly string[] CategoriesList = new string[9] { "Any%", "Any% (No-Buy)", "100%", "One-Magazine", "First-Target", "No-Miss", "Low-Shot", "Glitchless", "Set-Seed" };

		private Harmony harmony;

		private void Awake()
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Expected O, but got Unknown
			//IL_015b: 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_0166: Expected O, but got Unknown
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Expected O, but got Unknown
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Expected O, but got Unknown
			Logger = ((BaseUnityPlugin)this).Logger;
			Logger.LogInfo((object)"LuckyShotSpeedrun loaded");
			settings = SaveAPI.GetData<Settings>("LuckyShotSpeedrun.Settings") ?? new Settings();
			GameEvents.OnShotFired += new CancelableEvent(OnShotFired);
			GameEvents.OnSceneLoaded += OnSceneLoaded;
			GameEvents.OnTargetSpawnerStarted += OnTargetSpawnerStarted;
			GameEvents.OnWeaponReloaded += OnWeaponReloaded_Event;
			GameEvents.OnShopTryBuy += OnShopTryBuy_Event;
			try
			{
				harmony = new Harmony("com.liam.luckyshot.speedrun.harmony");
				Type type = AccessTools.TypeByName("Target");
				if (type != null)
				{
					MethodInfo methodInfo = AccessTools.Method(type, "OnDisable", (Type[])null, (Type[])null);
					if (methodInfo != null)
					{
						HarmonyMethod val = new HarmonyMethod(typeof(Plugin).GetMethod("Target_OnDisable_Postfix", BindingFlags.Static | BindingFlags.NonPublic))
						{
							priority = 400
						};
						harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
						Logger.LogInfo((object)"Patched Target.OnDisable for hit detection");
					}
					else
					{
						Logger.LogWarning((object)"Target.OnDisable method not found");
					}
				}
				else
				{
					Logger.LogWarning((object)"Target type not found - hit detection disabled");
				}
			}
			catch (Exception ex)
			{
				Logger.LogError((object)("Failed to apply Target patch: " + ex.Message + "\n" + ex.StackTrace));
			}
			GameObject val2 = new GameObject("LuckyShotSpeedrun_Timer");
			Object.DontDestroyOnLoad((Object)val2);
			val2.AddComponent<TimerDisplay>();
		}

		private void OnDestroy()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			GameEvents.OnShotFired -= new CancelableEvent(OnShotFired);
			GameEvents.OnSceneLoaded -= OnSceneLoaded;
			GameEvents.OnTargetSpawnerStarted -= OnTargetSpawnerStarted;
			GameEvents.OnWeaponReloaded -= OnWeaponReloaded_Event;
			GameEvents.OnShopTryBuy -= OnShopTryBuy_Event;
			try
			{
				Harmony obj = harmony;
				if (obj != null)
				{
					obj.UnpatchSelf();
				}
			}
			catch
			{
			}
			SaveAPI.SetData<Settings>("LuckyShotSpeedrun.Settings", settings);
		}

		private void OnShotFired(ref bool cancel)
		{
			try
			{
				if (settings.AutoStart && settings.StartOnFirstShot && !running)
				{
					StartTimer();
				}
				Shots++;
				pendingShot = true;
				lastShotTime = Time.realtimeSinceStartup;
			}
			catch (Exception ex)
			{
				Logger.LogError((object)("Error in OnShotFired: " + ex.Message));
			}
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			try
			{
				if (settings.AutoStart && settings.StartOnSceneLoad)
				{
					ResetTimer();
					StartTimer();
				}
			}
			catch (Exception ex)
			{
				Logger.LogError((object)("Error in OnSceneLoaded: " + ex.Message));
			}
		}

		private void OnTargetSpawnerStarted(object obj)
		{
			try
			{
				if (settings.AutoStart && settings.StartOnSpawnerStart && !running)
				{
					StartTimer();
				}
			}
			catch (Exception ex)
			{
				Logger.LogError((object)("Error in OnTargetSpawnerStarted: " + ex.Message));
			}
		}

		public static void StartTimer()
		{
			if (!running)
			{
				sw.Start();
				running = true;
				paused = false;
				Logger.LogInfo((object)"Speedrun timer started");
			}
		}

		public static void StopTimer()
		{
			if (running)
			{
				sw.Stop();
				running = false;
				paused = false;
				Logger.LogInfo((object)"Speedrun timer stopped");
			}
		}

		public static void PauseTimer()
		{
			if (running)
			{
				sw.Stop();
				paused = true;
				Logger.LogInfo((object)"Speedrun timer paused");
			}
		}

		public static void ResumeTimer()
		{
			if (paused)
			{
				sw.Start();
				paused = false;
				Logger.LogInfo((object)"Speedrun timer resumed");
			}
		}

		public static void ResetTimer()
		{
			sw.Reset();
			running = false;
			paused = false;
			runFailed = false;
			Shots = 0;
			Hits = 0;
			pendingShot = false;
			Logger.LogInfo((object)"Speedrun timer reset");
		}

		private static void Target_OnDisable_Postfix(object __instance)
		{
			try
			{
				Hits++;
				pendingShot = false;
				Logger.LogInfo((object)$"Target disabled - hits={Hits}");
				if (running && settings != null && settings.Category == "First-Target")
				{
					EndRun(success: true);
				}
			}
			catch (Exception ex)
			{
				Logger.LogError((object)("Error in Target_OnDisable_Postfix: " + ex.Message));
			}
		}

		private void OnWeaponReloaded_Event(object weapon, int amount, ref bool cancel)
		{
			try
			{
				if (running && settings != null && settings.Category == "One-Magazine")
				{
					Logger.LogInfo((object)"Blocking reload due to One-Magazine mode");
					cancel = true;
				}
			}
			catch (Exception ex)
			{
				Logger.LogError((object)("Error in OnWeaponReloaded_Event: " + ex.Message));
			}
		}

		private void OnShopTryBuy_Event(int cost, ref bool cancel)
		{
			try
			{
				if (running && settings != null && settings.Category == "Any% (No-Buy)")
				{
					Logger.LogInfo((object)"Blocking purchase due to No-Buy mode");
					cancel = true;
				}
			}
			catch (Exception ex)
			{
				Logger.LogError((object)("Error in OnShopTryBuy_Event: " + ex.Message));
			}
		}

		public static void CheckPendingShotTimeout()
		{
			if (running && pendingShot && Time.realtimeSinceStartup - lastShotTime > hitWindow)
			{
				pendingShot = false;
				Logger.LogInfo((object)"Miss detected");
				if (settings != null && settings.Category == "No-Miss")
				{
					EndRun(success: false);
				}
			}
		}

		public static void EndRun(bool success)
		{
			if (running || paused)
			{
				sw.Stop();
				running = false;
				paused = false;
				runFailed = !success;
				Logger.LogInfo((object)string.Format("Run {0} - Time: {1} Shots:{2} Hits:{3}", success ? "completed" : "failed", TimerDisplay.FormatTime(sw.Elapsed.TotalSeconds), Shots, Hits));
				RunResult runResult = new RunResult
				{
					Success = success,
					Time = sw.Elapsed.TotalSeconds,
					Shots = Shots,
					Hits = Hits,
					Category = (settings?.Category ?? ""),
					Timestamp = DateTime.UtcNow.ToString("o")
				};
				SaveAPI.SetData<RunResult>("LuckyShotSpeedrun.LastRun", runResult);
			}
		}

		[OpenShotMenuTab("Speedrun Timer")]
		public static void DrawMenu()
		{
			UIHelper.DrawHeader("LuckyShot Speedrun Timer");
			if (settings == null)
			{
				settings = new Settings();
			}
			bool flag = UIHelper.DrawSettings((object)settings);
			UIHelper.DrawLabel("Category:");
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			string[] categoriesList = CategoriesList;
			foreach (string text in categoriesList)
			{
				if (text == settings.Category)
				{
					if (GUILayout.Button(text, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) }))
					{
						settings.Category = text;
						flag = true;
					}
				}
				else if (GUILayout.Button(text, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) }))
				{
					settings.Category = text;
					flag = true;
				}
			}
			GUILayout.EndHorizontal();
			UIHelper.DrawLabel("Time: " + TimerDisplay.FormatTime(sw.Elapsed.TotalSeconds));
			UIHelper.DrawLabel($"Shots: {Shots}, Hits: {Hits}");
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			if (!running && !paused)
			{
				if (UIHelper.DrawButton("Start"))
				{
					ResetTimer();
					StartTimer();
				}
			}
			else if (running)
			{
				if (UIHelper.DrawButton("Pause"))
				{
					PauseTimer();
				}
			}
			else if (paused && UIHelper.DrawButton("Resume"))
			{
				ResumeTimer();
			}
			if (UIHelper.DrawButton("Stop"))
			{
				EndRun(success: true);
			}
			if (UIHelper.DrawButton("Reset"))
			{
				ResetTimer();
			}
			GUILayout.EndHorizontal();
			if (settings.Category == "Set-Seed")
			{
				UIHelper.DrawLabel("Seed (for run submission):");
				string text2 = GUILayout.TextField(settings.Seed ?? "", Array.Empty<GUILayoutOption>());
				if (text2 != settings.Seed)
				{
					settings.Seed = text2;
					flag = true;
				}
			}
			if (flag)
			{
				SaveAPI.SetData<Settings>("LuckyShotSpeedrun.Settings", settings);
			}
		}
	}
	public class TimerDisplay : MonoBehaviour
	{
		private GUIStyle labelStyle;

		private void OnGUI()
		{
			//IL_005b: 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_0040: Expected O, but got Unknown
			if (!Plugin.running)
			{
				Plugin.Settings settings = Plugin.settings;
				if (settings == null || !settings.ShowAlways)
				{
					return;
				}
			}
			if (labelStyle == null)
			{
				labelStyle = new GUIStyle(GUI.skin.label)
				{
					fontSize = 24
				};
			}
			GUI.Label(new Rect((float)(Screen.width - 300), 20f, 280f, 60f), FormatTime(Plugin.sw.Elapsed.TotalSeconds), labelStyle);
			Plugin.Settings settings2 = Plugin.settings;
			if (settings2 != null && settings2.PauseOnMenu && Input.GetKeyDown((KeyCode)282))
			{
				if (Plugin.running)
				{
					Plugin.PauseTimer();
				}
				else if (Plugin.paused)
				{
					Plugin.ResumeTimer();
				}
			}
			Plugin.CheckPendingShotTimeout();
		}

		public static string FormatTime(double seconds)
		{
			return $"{(int)seconds / 60:D2}:{(int)seconds % 60:D2}";
		}
	}
	public class PluginInfo
	{
		public const string PLUGIN_GUID = "com.liam.luckyshot.speedrun";

		public const string PLUGIN_NAME = "LuckyShotSpeedrun";

		public const string PLUGIN_VERSION = "0.1.0";
	}
}