Decompiled source of Boss VS Intro v1.0.0

BossVSIntro.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("BossVSIntro")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("Boss VS Intro")]
[assembly: AssemblyTitle("BossVSIntro")]
[assembly: AssemblyVersion("1.0.0.0")]
[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 BossVSIntro
{
	[BepInPlugin("com.scout.bossvsintro", "Boss VS Intro", "1.2.0")]
	public class BossVSIntroPlugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.scout.bossvsintro";

		public const string PluginName = "Boss VS Intro";

		public const string PluginVersion = "1.2.0";

		internal static BossVSIntroPlugin Instance;

		internal static ManualLogSource Log;

		internal static string ImagesRoot;

		internal static string SoundsRoot;

		internal static string PluginDir;

		private void Awake()
		{
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			PluginDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
			ImagesRoot = Path.Combine(PluginDir, "Images");
			SoundsRoot = Path.Combine(PluginDir, "Sounds");
			new Harmony("com.scout.bossvsintro").PatchAll();
			Log.LogInfo((object)"Boss VS Intro v1.2.0 loaded.");
			BossVSIntroPatch.BeginPreloadSounds();
		}
	}
	internal static class VSConfig
	{
		public static float introCooldown = 5f;

		public static float slideInDuration = 0.45f;

		public static float vsPopDuration = 0.35f;

		public static float vsStartScale = 3.5f;

		public static float vsHeightFraction = 0.35f;

		public static float shakeDuration = 0.4f;

		public static float shakeAmplitude = 38f;

		public static float holdDuration = 1f;

		public static float slideOutDuration = 0.4f;

		public static float centerGap = -1920f;

		public static string triggerSoundFile = "Trigger.wav";

		public static float soundVolume = 1f;

		public static float vsDelay = 1f;

		public static string playerFileName = "Player.png";

		public static string vsFileName = "VS.png";

		public static string bossFolderName = "Bosses";

		public static string bossFallbackName = "Default.png";
	}
	public class VSRunner : MonoBehaviour
	{
	}
	[HarmonyPatch(typeof(BossHealthBarTemplate))]
	public class BossVSIntroPatch
	{
		private static bool introPlaying;

		private static float lastIntroTime = -9999f;

		private static Canvas introCanvas;

		private static AudioSource introAudio;

		private static readonly Dictionary<string, Sprite> spriteCache = new Dictionary<string, Sprite>();

		private static AudioClip triggerClip;

		private static MonoBehaviour runner;

		private static MonoBehaviour Runner
		{
			get
			{
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				//IL_001c: Expected O, but got Unknown
				if ((Object)(object)runner == (Object)null)
				{
					GameObject val = new GameObject("BossVSIntroRunner");
					Object.DontDestroyOnLoad((Object)(object)val);
					runner = (MonoBehaviour)(object)val.AddComponent<VSRunner>();
				}
				return runner;
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch("Initialize", new Type[]
		{
			typeof(BossHealthBar),
			typeof(SliderLayer[])
		})]
		private static void InitializePostfix(BossHealthBarTemplate __instance, BossHealthBar bossBar, SliderLayer[] colorLayers)
		{
			BossVSIntroPlugin.Log.LogInfo((object)("[VS] Initialize fired for: " + bossBar?.bossName));
			if (!((Object)(object)__instance == (Object)null) && !((Object)(object)bossBar == (Object)null) && !string.IsNullOrEmpty(bossBar.bossName))
			{
				if (introPlaying)
				{
					BossVSIntroPlugin.Log.LogWarning((object)"[VS] Bailed: introPlaying is STUCK true — last splash never finished.");
					return;
				}
				if (Time.unscaledTime - lastIntroTime < VSConfig.introCooldown)
				{
					BossVSIntroPlugin.Log.LogWarning((object)$"[VS] Bailed: on cooldown ({Time.unscaledTime - lastIntroTime:F1}s since last < {VSConfig.introCooldown}s).");
					return;
				}
				BossVSIntroPlugin.Log.LogInfo((object)"[VS] All guards passed — starting splash coroutine.");
				Runner.StartCoroutine(PlayVSIntro(bossBar.bossName));
			}
		}

		public static void BeginPreloadSounds()
		{
			Runner.StartCoroutine(PreloadSounds());
		}

		private static IEnumerator PreloadSounds()
		{
			yield return LoadClip(Path.Combine(BossVSIntroPlugin.SoundsRoot, VSConfig.triggerSoundFile), delegate(AudioClip c)
			{
				triggerClip = c;
			});
		}

		private static IEnumerator LoadClip(string fullPath, Action<AudioClip> onLoaded)
		{
			if (!File.Exists(fullPath))
			{
				BossVSIntroPlugin.Log.LogWarning((object)("Sound not found (splash will be silent for this one): " + fullPath));
				onLoaded(null);
				yield break;
			}
			AudioType type = GuessAudioType(fullPath);
			UnityWebRequest req = UnityWebRequestMultimedia.GetAudioClip("file://" + fullPath, type);
			try
			{
				yield return req.SendWebRequest();
				if ((int)req.result != 1)
				{
					BossVSIntroPlugin.Log.LogError((object)("Failed to load sound '" + fullPath + "': " + req.error));
					onLoaded(null);
					yield break;
				}
				onLoaded(DownloadHandlerAudioClip.GetContent(req));
			}
			finally
			{
				((IDisposable)req)?.Dispose();
			}
		}

		private static AudioType GuessAudioType(string path)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			string text = Path.GetExtension(path).ToLowerInvariant();
			string text2 = text;
			if (!(text2 == ".ogg"))
			{
				if (text2 == ".mp3")
				{
					return (AudioType)13;
				}
				return (AudioType)20;
			}
			return (AudioType)14;
		}

		private static void PlaySound(AudioClip clip)
		{
			if (!((Object)(object)clip == (Object)null) && !((Object)(object)introAudio == (Object)null))
			{
				introAudio.PlayOneShot(clip, VSConfig.soundVolume);
			}
		}

		private static string Sanitize(string name)
		{
			StringBuilder stringBuilder = new StringBuilder();
			string text = name.ToUpperInvariant();
			foreach (char c in text)
			{
				if (char.IsLetterOrDigit(c))
				{
					stringBuilder.Append(c);
				}
				else if (c == ' ' || c == '-' || c == '_')
				{
					stringBuilder.Append('_');
				}
			}
			return stringBuilder.ToString();
		}

		private static Sprite LoadSprite(string fullPath)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Expected O, but got Unknown
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			if (spriteCache.TryGetValue(fullPath, out var value))
			{
				return value;
			}
			if (!File.Exists(fullPath))
			{
				return null;
			}
			try
			{
				byte[] array = File.ReadAllBytes(fullPath);
				Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
				ImageConversion.LoadImage(val, array);
				((Texture)val).filterMode = (FilterMode)1;
				((Texture)val).wrapMode = (TextureWrapMode)1;
				Sprite val2 = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f);
				spriteCache[fullPath] = val2;
				return val2;
			}
			catch (Exception ex)
			{
				BossVSIntroPlugin.Log.LogError((object)("Failed to load image '" + fullPath + "': " + ex.Message));
				return null;
			}
		}

		private static Canvas GetOrCreateCanvas()
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Expected O, but got Unknown
			if ((Object)(object)introCanvas != (Object)null)
			{
				return introCanvas;
			}
			GameObject val = new GameObject("BossVSIntroCanvas");
			Object.DontDestroyOnLoad((Object)(object)val);
			introCanvas = val.AddComponent<Canvas>();
			introCanvas.renderMode = (RenderMode)0;
			introCanvas.sortingOrder = 32767;
			CanvasScaler val2 = val.AddComponent<CanvasScaler>();
			val2.uiScaleMode = (ScaleMode)0;
			val2.scaleFactor = 1f;
			val.AddComponent<GraphicRaycaster>();
			introAudio = val.AddComponent<AudioSource>();
			introAudio.playOnAwake = false;
			introAudio.spatialBlend = 0f;
			introAudio.ignoreListenerPause = true;
			return introCanvas;
		}

		private static Image MakeImage(Transform parent, Sprite sprite, string name, float targetHeight)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Expected O, but got Unknown
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name);
			val.transform.SetParent(parent, false);
			Image val2 = val.AddComponent<Image>();
			val2.sprite = sprite;
			((Graphic)val2).raycastTarget = false;
			val2.preserveAspect = true;
			RectTransform rectTransform = ((Graphic)val2).rectTransform;
			rectTransform.anchorMin = new Vector2(0.5f, 0.5f);
			rectTransform.anchorMax = new Vector2(0.5f, 0.5f);
			rectTransform.pivot = new Vector2(0.5f, 0.5f);
			float num = (float)((Texture)sprite.texture).width / (float)((Texture)sprite.texture).height;
			rectTransform.sizeDelta = new Vector2(targetHeight * num, targetHeight);
			rectTransform.anchoredPosition = Vector2.zero;
			((Transform)rectTransform).localScale = Vector3.one;
			return val2;
		}

		private static float EaseOutCubic(float x)
		{
			return 1f - Mathf.Pow(1f - x, 3f);
		}

		private static float EaseInCubic(float x)
		{
			return x * x * x;
		}

		private static IEnumerator PlayVSIntro(string bossName)
		{
			introPlaying = true;
			string playerPath = Path.Combine(BossVSIntroPlugin.ImagesRoot, VSConfig.playerFileName);
			string vsPath = Path.Combine(BossVSIntroPlugin.ImagesRoot, VSConfig.vsFileName);
			string bossPath = Path.Combine(path3: Sanitize(bossName) + ".png", path1: BossVSIntroPlugin.ImagesRoot, path2: VSConfig.bossFolderName);
			string bossFallback = Path.Combine(BossVSIntroPlugin.ImagesRoot, VSConfig.bossFolderName, VSConfig.bossFallbackName);
			Sprite playerSprite = LoadSprite(playerPath);
			Sprite vsSprite = LoadSprite(vsPath);
			Sprite bossSprite = LoadSprite(bossPath) ?? LoadSprite(bossFallback);
			if ((Object)(object)playerSprite == (Object)null)
			{
				BossVSIntroPlugin.Log.LogWarning((object)("Missing player image: " + playerPath));
			}
			if ((Object)(object)vsSprite == (Object)null)
			{
				BossVSIntroPlugin.Log.LogWarning((object)("Missing VS image: " + vsPath));
			}
			if ((Object)(object)bossSprite == (Object)null)
			{
				BossVSIntroPlugin.Log.LogWarning((object)("Missing boss image (and no Default.png): " + bossPath));
			}
			if ((Object)(object)playerSprite == (Object)null || (Object)(object)vsSprite == (Object)null || (Object)(object)bossSprite == (Object)null)
			{
				introPlaying = false;
				yield break;
			}
			lastIntroTime = Time.unscaledTime;
			float previousTimeScale = Time.timeScale;
			Time.timeScale = 0f;
			Image playerImg = null;
			Image bossImg = null;
			Image vsImg = null;
			IEnumerator anim = AnimateCard(playerSprite, bossSprite, vsSprite, delegate(Image img)
			{
				playerImg = img;
			}, delegate(Image img)
			{
				bossImg = img;
			}, delegate(Image img)
			{
				vsImg = img;
			});
			while (true)
			{
				object current;
				try
				{
					if (!anim.MoveNext())
					{
						break;
					}
					current = anim.Current;
					goto IL_0295;
				}
				catch (Exception ex)
				{
					Exception e = ex;
					BossVSIntroPlugin.Log.LogError((object)$"[VS] Splash threw, bailing safely: {e}");
				}
				break;
				IL_0295:
				yield return current;
			}
			if ((Object)(object)playerImg != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)playerImg).gameObject);
			}
			if ((Object)(object)bossImg != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)bossImg).gameObject);
			}
			if ((Object)(object)vsImg != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)vsImg).gameObject);
			}
			Time.timeScale = previousTimeScale;
			introPlaying = false;
		}

		private static IEnumerator AnimateCard(Sprite playerSprite, Sprite bossSprite, Sprite vsSprite, Action<Image> outPlayer, Action<Image> outBoss, Action<Image> outVs)
		{
			Canvas canvas = GetOrCreateCanvas();
			PlaySound(triggerClip);
			float screenW = Screen.width;
			float screenH = Screen.height;
			Image playerImg = MakeImage(((Component)canvas).transform, playerSprite, "VS_Player", screenH);
			Image bossImg = MakeImage(((Component)canvas).transform, bossSprite, "VS_Boss", screenH);
			Image vsImg = MakeImage(((Component)canvas).transform, vsSprite, "VS_Badge", screenH * VSConfig.vsHeightFraction);
			outPlayer(playerImg);
			outBoss(bossImg);
			outVs(vsImg);
			RectTransform playerRT = ((Graphic)playerImg).rectTransform;
			RectTransform bossRT = ((Graphic)bossImg).rectTransform;
			RectTransform vsRT = ((Graphic)vsImg).rectTransform;
			float halfGap = VSConfig.centerGap * 0.5f;
			float playerHalfW = playerRT.sizeDelta.x * 0.5f;
			float bossHalfW = bossRT.sizeDelta.x * 0.5f;
			Vector2 playerStart = new Vector2(0f - screenW, 0f);
			Vector2 bossStart = new Vector2(screenW, 0f);
			Vector2 playerEnd = new Vector2(0f - (playerHalfW + halfGap), 0f);
			Vector2 bossEnd = new Vector2(bossHalfW + halfGap, 0f);
			playerRT.anchoredPosition = playerStart;
			bossRT.anchoredPosition = bossStart;
			vsRT.anchoredPosition = Vector2.zero;
			((Transform)playerRT).SetAsLastSibling();
			((Transform)bossRT).SetAsLastSibling();
			((Transform)vsRT).SetAsLastSibling();
			((Component)vsImg).gameObject.SetActive(false);
			float t = 0f;
			while (t < VSConfig.slideInDuration)
			{
				t += Time.unscaledDeltaTime;
				float k = EaseOutCubic(Mathf.Clamp01(t / VSConfig.slideInDuration));
				playerRT.anchoredPosition = Vector2.LerpUnclamped(playerStart, playerEnd, k);
				bossRT.anchoredPosition = Vector2.LerpUnclamped(bossStart, bossEnd, k);
				yield return null;
			}
			playerRT.anchoredPosition = playerEnd;
			bossRT.anchoredPosition = bossEnd;
			t = 0f;
			while (t < VSConfig.vsDelay)
			{
				t += Time.unscaledDeltaTime;
				yield return null;
			}
			((Component)vsImg).gameObject.SetActive(true);
			float impactDuration = Mathf.Max(VSConfig.vsPopDuration, VSConfig.shakeDuration);
			t = 0f;
			while (t < impactDuration)
			{
				t += Time.unscaledDeltaTime;
				float kv = EaseOutCubic(Mathf.Clamp01(t / VSConfig.vsPopDuration));
				((Transform)vsRT).localScale = Vector3.one * Mathf.LerpUnclamped(VSConfig.vsStartScale, 1f, kv);
				float decay = 1f - Mathf.Clamp01(t / VSConfig.shakeDuration);
				float amp = VSConfig.shakeAmplitude * decay;
				playerRT.anchoredPosition = playerEnd + new Vector2(Random.Range(0f - amp, amp), Random.Range(0f - amp, amp));
				bossRT.anchoredPosition = bossEnd + new Vector2(Random.Range(0f - amp, amp), Random.Range(0f - amp, amp));
				yield return null;
			}
			((Transform)vsRT).localScale = Vector3.one;
			playerRT.anchoredPosition = playerEnd;
			bossRT.anchoredPosition = bossEnd;
			t = 0f;
			while (t < VSConfig.holdDuration)
			{
				t += Time.unscaledDeltaTime;
				yield return null;
			}
			Vector2 vsUpEnd = new Vector2(0f, screenH);
			t = 0f;
			while (t < VSConfig.slideOutDuration)
			{
				t += Time.unscaledDeltaTime;
				float k2 = EaseInCubic(Mathf.Clamp01(t / VSConfig.slideOutDuration));
				playerRT.anchoredPosition = Vector2.LerpUnclamped(playerEnd, playerStart, k2);
				bossRT.anchoredPosition = Vector2.LerpUnclamped(bossEnd, bossStart, k2);
				vsRT.anchoredPosition = Vector2.LerpUnclamped(Vector2.zero, vsUpEnd, k2);
				yield return null;
			}
		}
	}
}