Decompiled source of CutsceneSkip v0.1.7

CutsceneSkip.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Threading;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Cysharp.Threading.Tasks;
using Dialogue;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using NineSolsAPI;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[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("CutsceneSkip")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("A Nine Sols mod that enables skipping any cutscene or dialogue (that won't break the game).")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+f2ef21ec8b14004ebe0e3cc19e8b497315bd320b")]
[assembly: AssemblyProduct("CutsceneSkip")]
[assembly: AssemblyTitle("CutsceneSkip")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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 CutsceneSkip
{
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("CutsceneSkip", "CutsceneSkip", "1.0.0")]
	public class CutsceneSkip : BaseUnityPlugin
	{
		private static ConfigEntry<KeyboardShortcut> skipKeybind = null;

		private Harmony harmony;

		public static (A2_SG4_Logic?, string) activeA2SG4 = (null, "");

		public static (A4_S5_Logic?, string) activeA4S5 = (null, "");

		public static string dialogueSkipNotificationId = "";

		public static (SimpleCutsceneManager?, string) activeCutscene = (null, "");

		public static (VideoPlayAction?, string) activeVideo = (null, "");

		public static string KuafuEndingChoiceCutsceneGOPath = "AG_S2/Room/NPCs/SimpleCutSceneFSM_結尾/FSM Animator/LogicRoot/[CutScene]";

		public static string SkipKeybindText()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			KeyboardShortcut value = skipKeybind.Value;
			return ((KeyboardShortcut)(ref value)).Serialize();
		}

		private void Awake()
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			Log.Init(((BaseUnityPlugin)this).Logger);
			RCGLifeCycle.DontDestroyForever(((Component)this).gameObject);
			harmony = Harmony.CreateAndPatchAll(typeof(CutsceneSkip).Assembly, (string)null);
			skipKeybind = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("", "Skip Keybind", new KeyboardShortcut((KeyCode)107, (KeyCode[])(object)new KeyCode[1] { (KeyCode)306 }), "The keyboard shortcut to actually skip cutscenes and dialogue.");
			KeybindManager.Add((MonoBehaviour)(object)this, (Action)SkipActiveCutsceneOrDialogue, (Func<KeyboardShortcut>)(() => skipKeybind.Value));
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Plugin CutsceneSkip is loaded!");
			Notifications.Awake();
		}

		public static bool KuafuEndingChoiceCutsceneActive()
		{
			if ((Object)(object)activeCutscene.Item1 == (Object)null)
			{
				return false;
			}
			GameObject val = GameObject.Find(KuafuEndingChoiceCutsceneGOPath);
			return (Object)(object)((Component)activeCutscene.Item1).gameObject == (Object)(object)val;
		}

		private void SkipActiveCutsceneOrDialogue()
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			if (KuafuEndingChoiceCutsceneActive())
			{
				Log.Info("Not allowing the player to skip anything because we're in the Kuafu ending choice conversation, where even dialogue skipping softlocks.");
				return;
			}
			GameObject obj = GameObject.Find("GameCore(Clone)/RCG LifeCycle/UIManager/GameplayUICamera/Always Canvas/DialoguePlayer(KeepThisEnable)");
			DialoguePlayer val = ((obj != null) ? obj.GetComponent<DialoguePlayer>() : null);
			if ((Object)(object)activeA2SG4.Item1 != (Object)null)
			{
				A2_SG4_Logic item = activeA2SG4.Item1;
				if ((Object)(object)val != (Object)null)
				{
					AnimatorStateInfo currentAnimatorStateInfo = val.phoneUI.phoneRingAnimator.GetCurrentAnimatorStateInfo(0);
					if (((AnimatorStateInfo)(ref currentAnimatorStateInfo)).IsName("Webcam_Show"))
					{
						Log.Info("Found A2_SG4_Logic a.k.a. Heng Power Reservoir flashback, but doing nothing because the phone UI is currently ringing. If we skip now that ringing will go on forever.");
						return;
					}
				}
				bool num = AccessTools.FieldRefAccess<A2_SG4_Logic, bool>("_done").Invoke(item);
				if (num)
				{
					Log.Info("A2_SG4_Logic's _done flag is already set. Player must have skipped too early. Resetting _done flag back to false.");
					AccessTools.FieldRefAccess<A2_SG4_Logic, bool>("_done").Invoke(item) = false;
					if (AccessTools.FieldRefAccess<SceneConnectionPoint, bool>("touchedChangeSceneTrigger").Invoke(item.connectionToS2))
					{
						Log.Info("A2_SG4_Logic::connectionToS2's touchedChangeSceneTrigger flag is also already set. Also resetting that touchedChangeSceneTrigger flag back to false.");
						AccessTools.FieldRefAccess<SceneConnectionPoint, bool>("touchedChangeSceneTrigger").Invoke(item.connectionToS2) = false;
					}
					if (AccessTools.FieldRefAccess<SceneConnectionPoint, bool>("touchedChangeSceneTrigger").Invoke(item.connectionToS3))
					{
						Log.Info("A2_SG4_Logic::connectionToS3's touchedChangeSceneTrigger flag is also already set. Also resetting that touchedChangeSceneTrigger flag back to false.");
						AccessTools.FieldRefAccess<SceneConnectionPoint, bool>("touchedChangeSceneTrigger").Invoke(item.connectionToS3) = false;
					}
				}
				Log.Info("Found A2_SG4_Logic a.k.a. Heng Power Reservoir flashback, calling A2_SG4_Logic.TrySkip() as a special case");
				item.TrySkip();
				Notifications.CancelNotification(activeA2SG4.Item2);
				if (num)
				{
					activeA2SG4.Item1 = null;
				}
			}
			else if ((Object)(object)activeA4S5.Item1 != (Object)null)
			{
				A4_S5_Logic item2 = activeA4S5.Item1;
				if (item2.BossKilled.CurrentValue)
				{
					Log.Info("Found A4_S5_Logic a.k.a. Sky Rending Claw fight. Claw already killed. Applying special case logic to skip post-fight scene.");
					item2.FinishCutscene.TrySkip();
				}
				else
				{
					if (((Component)item2.GianMechClawMonsterBase).gameObject.activeSelf)
					{
						Log.Info("Found A4_S5_Logic a.k.a. Sky Rending Claw fight. Claw not yet killed. But claw is already active, so trying to skip this now would just softlock. Doing nothing.");
						return;
					}
					if (AccessTools.FieldRefAccess<BubbleDialogueController, int>("index").Invoke(item2.BeforeMangaBubble) >= item2.BeforeMangaBubble.nodes.Count && !AccessTools.FieldRefAccess<SimpleCutsceneManager, bool>("isMangaPauseing").Invoke(item2.StartCutscene))
					{
						Log.Info("Found A4_S5_Logic a.k.a. Sky Rending Claw fight. Appears to be in a manga transition animation, which in this scene would cause the fight to start without the screen activating so you can see it. Doing nothing for now; try again when the manga is done animating and waiting for input.");
						return;
					}
					Log.Info("Found A4_S5_Logic a.k.a. Sky Rending Claw fight. Claw not yet killed. Applying special case logic to skip pre-fight scenes.");
					GameObject.Find("A4_S5/A4_S5_Logic(DisableMeForBossDesign)/CUTSCENE_START/MangaView_OriginalPrefab/MANGACanvas").SetActive(false);
					item2.BeforeMangaBubble.TrySkip();
					item2.BubbleDialogue.TrySkip();
					item2.TrySkip();
				}
				Notifications.CancelNotification(activeA4S5.Item2);
			}
			else if ((Object)(object)val != (Object)null && (Object)(object)AccessTools.FieldRefAccess<DialoguePlayer, DialogueGraph>("playingDialogueGraph").Invoke(val) != (Object)null)
			{
				Log.Info("calling DialoguePlayer.playingDialogueGraph.TrySkip()");
				val.TrySkip();
				if (dialogueSkipNotificationId != "")
				{
					Notifications.CancelNotification(dialogueSkipNotificationId);
					dialogueSkipNotificationId = "";
				}
			}
			else if ((Object)(object)activeCutscene.Item1 != (Object)null)
			{
				SimpleCutsceneManager item3 = activeCutscene.Item1;
				Log.Info("calling TrySkip() on " + ((Object)item3).name);
				AccessTools.Method(typeof(SimpleCutsceneManager), "TrySkip", (Type[])null, (Type[])null).Invoke(item3, Array.Empty<object>());
				if (AccessTools.FieldRefAccess<SimpleCutsceneManager, bool>("isMangaPauseing").Invoke(item3))
				{
					Log.Info("also calling Resume() since it was 'manga paused'");
					AccessTools.Method(typeof(SimpleCutsceneManager), "Resume", (Type[])null, (Type[])null).Invoke(item3, Array.Empty<object>());
				}
				Notifications.CancelNotification(activeCutscene.Item2);
				activeCutscene = (null, "");
			}
			else if ((Object)(object)activeVideo.Item1 != (Object)null)
			{
				VideoPlayAction item4 = activeVideo.Item1;
				Log.Info("calling TrySkip() on " + ((Object)item4).name);
				AccessTools.Method(typeof(VideoPlayAction), "TrySkip", (Type[])null, (Type[])null).Invoke(item4, Array.Empty<object>());
				Notifications.CancelNotification(activeVideo.Item2);
				activeVideo = (null, "");
			}
		}

		private void Update()
		{
			Notifications.Update();
		}

		private void OnDestroy()
		{
			harmony.UnpatchSelf();
			Notifications.OnDestroy();
		}
	}
	internal static class Log
	{
		private static ManualLogSource? logSource;

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

		internal static void Debug(object data)
		{
			ManualLogSource? obj = logSource;
			if (obj != null)
			{
				obj.LogDebug(data);
			}
		}

		internal static void Error(object data)
		{
			ManualLogSource? obj = logSource;
			if (obj != null)
			{
				obj.LogError(data);
			}
		}

		internal static void Fatal(object data)
		{
			ManualLogSource? obj = logSource;
			if (obj != null)
			{
				obj.LogFatal(data);
			}
		}

		internal static void Info(object data)
		{
			ManualLogSource? obj = logSource;
			if (obj != null)
			{
				obj.LogInfo(data);
			}
		}

		internal static void Message(object data)
		{
			ManualLogSource? obj = logSource;
			if (obj != null)
			{
				obj.LogMessage(data);
			}
		}

		internal static void Warning(object data)
		{
			ManualLogSource? obj = logSource;
			if (obj != null)
			{
				obj.LogWarning(data);
			}
		}
	}
	internal class Notifications
	{
		private struct Notification
		{
			public string id;

			public DateTimeOffset timestamp;

			public string displayText;
		}

		private static Canvas CanvasComponent = null;

		private static TextMeshProUGUI TextComponent = null;

		private static bool isDirty = false;

		private static List<Notification> notificationStack = new List<Notification>();

		private static readonly TimeSpan expiry = TimeSpan.FromSeconds(10.0);

		public static void Awake()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("NineSolsAPI-FullscreenCanvas");
			RCGLifeCycle.DontDestroyForever(val);
			CanvasComponent = val.AddComponent<Canvas>();
			CanvasComponent.renderMode = (RenderMode)0;
			TextComponent = val.AddComponent<TextMeshProUGUI>();
			((TMP_Text)TextComponent).alignment = (TextAlignmentOptions)1028;
			((TMP_Text)TextComponent).fontSize = 20f;
			((Graphic)TextComponent).color = Color.white;
		}

		public static void Update()
		{
			UpdateText();
		}

		public static void OnDestroy()
		{
			Object.Destroy((Object)(object)((Component)CanvasComponent).gameObject);
		}

		public static void UpdateText()
		{
			DateTimeOffset now = DateTimeOffset.UtcNow;
			int num = notificationStack.RemoveAll((Notification notification) => now - notification.timestamp > expiry);
			isDirty |= num > 0;
			if (isDirty)
			{
				((TMP_Text)TextComponent).text = string.Join('\n', notificationStack.Select((Notification n) => n.displayText));
				isDirty = false;
			}
		}

		public static string AddNotification(string displayText)
		{
			Log.Info("Notifications.AddNotification(" + displayText + ")");
			string text = Guid.NewGuid().ToString("N");
			notificationStack.Add(new Notification
			{
				id = text,
				timestamp = DateTimeOffset.UtcNow,
				displayText = displayText
			});
			isDirty = true;
			return text;
		}

		public static void CancelNotification(string id)
		{
			string id2 = id;
			Log.Info("Notifications.CancelNotification(" + id2 + ")");
			if (id2 != null && id2 != "")
			{
				int num = notificationStack.RemoveAll((Notification x) => x.id == id2);
				isDirty |= num > 0;
			}
		}
	}
	[HarmonyPatch]
	public class Patches
	{
		private static List<string> skipDenylist = new List<string>
		{
			"A1_S2_GameLevel/Room/Prefab/Gameplay2_Alina/Simple Binding Tool/SimpleCutSceneFSM_關門戰開頭演出/FSM Animator/LogicRoot/[CutScene]", "GameLevel/Room/Prefab/村民避難所_階段 FSM Object/FSM Animator/View/村民避難所ControlRoom/Phase3(二次入侵)/General FSM A0_S10 二次入侵/FSM Animator/LogicRoot/[CutScene] 戰鬥前", "A2_S1/Room/Prefab/EnterPyramid_Acting/[CutScene]ActivePyramidAndEnter", "A3_S1/Room/Prefab/妹妹回憶_SimpleCutSceneFSM Variant/FSM Animator/LogicRoot/[CutScene]", "A4_S4/ZGunAndDoor/Shield Giant Bot Control Provider Variant_Cutscene/Hack Control Monster FSM/FSM Animator/LogicRoot/Cutscene/LogicRoot/[CutScene]", "A5_S5/Room/SimpleCutSceneFSM_JieChuan and Jee/FSM Animator/LogicRoot/[CutScene]", "AG_S2/Room/NPCs/議會演出相關Binding/ShanShan 軒軒分身 FSM/FSM Animator/CutScene/[CutScene] 食譜_團圓飯/FSM Animator/LogicRoot/[CutScene]", "GameLevel/Room/Prefab/EventBinder/General Boss Fight FSM Object Variant/FSM Animator/[CutScene] 易公死亡", "A3_S5_BossGouMang_GameLevel/Room/Simple Binding Tool/BossGouMangLogic/[CutScene]/[CutScene]Goumang_Explosion_Drop/[Timeline]Goumang_Explosion_Drop", "A5_S2/Room/SimpleCutSceneFSM_A5妹妹回憶/FSM Animator/LogicRoot/[CutScene]",
			"GameLevel/Room1/SimpleCutSceneFSM/FSM Animator/LogicRoot/[CutScene]", "AG_S2/Room/Prefab/ControlRoom FSM Binding Tool/NPC_AICore_Base/NPC_AICore_Base_FSM/FSM Animator/LogicRoot/[CutScene]AI核心解鎖", "AG_S2/Room/NPCs/議會演出相關Binding/ShanShan 軒軒分身 FSM/FSM Animator/CutScene/收到文物演出/[CutsceneFSM] 軒軒收到古唱片/FSM Animator/LogicRoot/[CutScene]", "GameLevel/Room1/SimpleCutSceneFSM_EnterVilliage/FSM Animator/LogicRoot/[CutScene]", "A4_S3/Room/Prefab/CutScene_ChangeScene_FSM Variant/FSM Animator/LogicRoot/[CutScene]EnterScene", "A11_S2/CutScene_ChangeScene_FSM Variant/FSM Animator/LogicRoot/[CutScene]EnterScene", "AG_GoHome/Room/Prefab/SimpleCutSceneFSM_搭公車/FSM Animator/LogicRoot/[CutScene]", "A1_S1_GameLevel/Room/A1_S1_Tutorial_Logic/[CutScene]AfterTutorial_AI_Call/[Timeline]", "A4_S3/Room/Prefab/ElementRoom/ElementDoor FSM/ElementDoor FSM/FSM Animator/LogicRoot/[CutScene]Eenter_A4SG4", "A7_S1/Room/Prefab/A7_S1_三階段FSM/FSM Animator/Phase2_A7Entry/花入口 FSM Object/FSM Animator/LogicRoot/[CutScene] 進入演出",
			"A2_S5_ BossHorseman_GameLevel/Room/Simple Binding Tool/Boss_SpearHorse_Logic/[CutScene]SpearHorse_End", "A0_S6/Room/Prefab/SimpleCutSceneFSM_道長死亡/FSM Animator/LogicRoot/Cutscene_TaoChangPart2", "A4_S5/A4_S5_Logic(DisableMeForBossDesign)/CUTSCENE_START", "A4_S5/A4_S5_Logic(DisableMeForBossDesign)/CUTSENE_EMERGENCY", "A4_S5/A4_S5_Logic(DisableMeForBossDesign)/CUTSCENE_Finish", "A11_S2/Room/Prefab/EventBinder/OldBoy FSM Object/FSM Animator/LogicRoot/[CutScene]OldBoyFighting/[Timeline]", "A2_Stage_Remake/Room/Prefab/FallingTeleportTrickBackgroundProvider/A7_HotSpring/溫泉場景Setting FSM Object/FSM Animator/View/SPA/PinkSkin/Pink/SimpleCutSceneFSM_八仙無限murmur/FSM Animator/LogicRoot/[CutScene]", "A2_Stage_Remake/Room/Prefab/FallingTeleportTrickBackgroundProvider/A7_HotSpring/溫泉場景Setting FSM Object/FSM Animator/View/SPA/PinkSkin/Pink_Odd/SimpleCutSceneFSM_八仙無限murmur/FSM Animator/LogicRoot/[CutScene]", "A7_ButterflyTest/Room/Prefab/FallingTeleportTrickBackgroundProvider/A7_HotSpring/溫泉場景Setting FSM Object/FSM Animator/View/SPA/PinkSkin/Pink_Odd/SimpleCutSceneFSM_八仙無限murmur/FSM Animator/LogicRoot/[CutScene]"
		};

		private static List<string> skipDelaylist = new List<string> { "A2_SG4/Room/妹妹回憶_SimpleCutSceneFSM/FSM Animator/LogicRoot/[CutScene]", "VR_TaoChang/Room/SimpleCutSceneFSM_易公後妹妹回憶/FSM Animator/LogicRoot/[CutScene]", "GameLevel/Room/Prefab/EventBinder/General Boss Fight FSM Object Variant/FSM Animator/[CutScene] 一進", "GameLevel/Room/Prefab/EventBinder/General Boss Fight FSM Object Variant/FSM Animator/[CutScene] 二進", "P2_R22_Savepoint_GameLevel/EventBinder/General Boss Fight FSM Object Variant/FSM Animator/[CutScene]FirstTimeContact/[Timeline]", "P2_R22_Savepoint_GameLevel/EventBinder/General Boss Fight FSM Object Variant/FSM Animator/[CutScene]SecondTimeContact/[Timeline]" };

		private static HashSet<string> skippableVideos = new HashSet<string> { "GameLevel/Room/Prefab/SimpleCutSceneFSM_結局_大爆炸/--[States]/FSM/[State] PlayCutSceneEnd/[Action] VideoPlayAction", "A7_S6_Memory_Butterfly_CutScene_GameLevel/A7_S6_Cutscene FSM/--[States]/FSM/[State] PlayingVideo/[Action] VideoPlayAction" };

		public static string GetFullPath(GameObject go)
		{
			Transform val = go.transform;
			List<string> list = new List<string>();
			while ((Object)(object)val != (Object)null)
			{
				list.Add(((Object)val).name);
				val = val.parent;
			}
			list.Reverse();
			return string.Join("/", list);
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(SimpleCutsceneManager), "PlayAnimation")]
		private static void SimpleCutsceneManager_PlayAnimation(SimpleCutsceneManager __instance)
		{
			string fullPath = GetFullPath(((Component)__instance).gameObject);
			if (skipDelaylist.Contains(fullPath))
			{
				return;
			}
			Log.Info("SimpleCutsceneManager_PlayAnimation " + fullPath);
			if (skipDenylist.Contains(fullPath))
			{
				Log.Info("not allowing skip for cutscene " + fullPath + " because it's on the skip denylist");
				return;
			}
			if (((Object)__instance).name.EndsWith("[TimeLine]CrateEnter_L") || ((Object)__instance).name.EndsWith("[TimeLine]CrateEnter_R"))
			{
				Log.Info("not allowing skip for " + fullPath + " because all crate exit 'cutscenes' I've tested instantly softlock when skipped");
				return;
			}
			if (((Object)__instance).name == "[CutScene]調閱報告")
			{
				Log.Info("not allowing skip for " + fullPath + " because all \"[CutScene]調閱報告\" / Eigong lab report cutscenes risk softlocking when skipped");
				return;
			}
			string item = "";
			if ((Object)(object)((Component)__instance).gameObject == (Object)(object)GameObject.Find(CutsceneSkip.KuafuEndingChoiceCutsceneGOPath))
			{
				Log.Info("Not prompting player to skip this cutscene because it's in the Kuafu ending choice conversation, where even dialogue skipping softlocks.");
			}
			else if (((Object)__instance).name.EndsWith("_EnterScene"))
			{
				Log.Info("skipping notification for " + ((Object)__instance).name + " because transition 'cutscenes' are typically over before the player can even see the toast");
			}
			else
			{
				item = Notifications.AddNotification("Press " + CutsceneSkip.SkipKeybindText() + " to Skip This Cutscene");
			}
			CutsceneSkip.activeCutscene = (__instance, item);
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(SimpleCutsceneManager), "PlayAnimation")]
		private static async void SimpleCutsceneManager_PlayAnimation_Postfix(SimpleCutsceneManager __instance)
		{
			string goPath = GetFullPath(((Component)__instance).gameObject);
			if (skipDelaylist.Contains(goPath))
			{
				await UniTask.DelayFrame(100, (PlayerLoopTiming)8, default(CancellationToken));
				Log.Info("SimpleCutsceneManager_PlayAnimation acting on " + goPath + " with delay (i.e. Postfix patch + 100 frame wait) to avoid softlocking");
				string item = Notifications.AddNotification("Press " + CutsceneSkip.SkipKeybindText() + " to Skip This Cutscene");
				CutsceneSkip.activeCutscene = (__instance, item);
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(SimpleCutsceneManager), "End")]
		private static void SimpleCutsceneManager_End(SimpleCutsceneManager __instance)
		{
			Log.Info("SimpleCutsceneManager_End " + ((Object)__instance).name);
			if ((Object)(object)CutsceneSkip.activeCutscene.Item1 == (Object)(object)__instance)
			{
				CutsceneSkip.activeCutscene = (null, "");
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(DialoguePlayer), "StartDialogue")]
		private static void DialoguePlayer_StartDialogue(DialoguePlayer __instance)
		{
			if (CutsceneSkip.KuafuEndingChoiceCutsceneActive())
			{
				Log.Info("Not prompting player to skip this dialogue because it's in the Kuafu ending choice conversation, where even dialogue skipping softlocks.");
				return;
			}
			Log.Info("DialoguePlayer_StartDialogue " + ((Object)__instance).name);
			CutsceneSkip.dialogueSkipNotificationId = Notifications.AddNotification("Press " + CutsceneSkip.SkipKeybindText() + " to Skip This Dialogue");
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(VideoPlayAction), "OnStateEnterImplement")]
		private static void VideoPlayAction_OnStateEnterImplement(VideoPlayAction __instance)
		{
			string fullPath = GetFullPath(((Component)__instance).gameObject);
			Log.Debug("VideoPlayAction_OnStateEnterImplement " + fullPath);
			if (skippableVideos.Contains(fullPath))
			{
				string item = Notifications.AddNotification("Press " + CutsceneSkip.SkipKeybindText() + " to Skip This Video");
				CutsceneSkip.activeVideo = (__instance, item);
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(VideoPlayAction), "VideoClipDone")]
		private static void VideoPlayAction_VideoClipDone(VideoPlayAction __instance)
		{
			Log.Debug("VideoPlayAction_VideoClipDone " + ((Object)__instance).name);
			if ((Object)(object)CutsceneSkip.activeVideo.Item1 == (Object)(object)__instance)
			{
				CutsceneSkip.activeVideo = (null, "");
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(A2_SG4_Logic), "EnterLevelStart")]
		private static void A2_SG4_Logic_EnterLevelStart(A2_SG4_Logic __instance)
		{
			Log.Info("A2_SG4_Logic_EnterLevelStart / Heng Power Reservoir flashback");
			string item = Notifications.AddNotification("Press " + CutsceneSkip.SkipKeybindText() + " to Skip This Heng Flashback");
			CutsceneSkip.activeA2SG4 = (__instance, item);
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(A2_SG4_Logic), "OnLevelDestroy")]
		private static void A2_SG4_Logic_OnLevelDestroy(A2_SG4_Logic __instance)
		{
			Log.Info("A2_SG4_Logic_OnLevelDestroy / Heng Power Reservoir flashback");
			if ((Object)(object)CutsceneSkip.activeA2SG4.Item1 == (Object)(object)__instance)
			{
				Notifications.CancelNotification(CutsceneSkip.activeA2SG4.Item2);
				CutsceneSkip.activeA2SG4 = (null, "");
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(A4_S5_Logic), "EnterLevelStart")]
		private static async void A4_S5_Logic_EnterLevelStart(A4_S5_Logic __instance)
		{
			Log.Info("A4_S5_Logic_EnterLevelStart / Sky Rending Claw Pre-Fight Scenes");
			await UniTask.DelayFrame(100, (PlayerLoopTiming)8, default(CancellationToken));
			string item = Notifications.AddNotification("Press " + CutsceneSkip.SkipKeybindText() + " to Skip Pre-Claw Fight Cutscenes");
			CutsceneSkip.activeA4S5 = (__instance, item);
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(A4_S5_Logic), "FooGameComplete")]
		private static void A4_S5_Logic_FooGameComplete(A4_S5_Logic __instance)
		{
			Log.Info("A4_S5_Logic_FooGameComplete / Sky Rending Claw Post-Fight Scenes");
			if ((Object)(object)CutsceneSkip.activeA4S5.Item1 != (Object)null)
			{
				Notifications.CancelNotification(CutsceneSkip.activeA4S5.Item2);
			}
			string item = Notifications.AddNotification("Press " + CutsceneSkip.SkipKeybindText() + " to Skip Post-Claw Fight Cutscene");
			CutsceneSkip.activeA4S5 = (__instance, item);
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "CutsceneSkip";

		public const string PLUGIN_NAME = "CutsceneSkip";

		public const string PLUGIN_VERSION = "1.0.0";
	}
}