Decompiled source of SpeedrunCutsceneSkip v0.0.1

SpeedrunCutsceneSkip.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
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 UnityEngine;

[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("SpeedrunCutsceneSkip")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("A Nine Sols mod that auto-skips a handful of cutscenes for speedrunners.")]
[assembly: AssemblyFileVersion("0.0.1.0")]
[assembly: AssemblyInformationalVersion("0.0.1+7e0202213de13ce1eca0f524b642a209b8fba038")]
[assembly: AssemblyProduct("SpeedrunCutsceneSkip")]
[assembly: AssemblyTitle("SpeedrunCutsceneSkip")]
[assembly: AssemblyVersion("0.0.1.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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]
	[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]
	[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 SpeedrunCutsceneSkip
{
	[HarmonyPatch]
	internal class CentralHallPhone
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(SimpleCutsceneManager), "PlayAnimation")]
		private static async void SimpleCutsceneManager_PlayAnimation_Postfix(SimpleCutsceneManager __instance)
		{
			if (SpeedrunCutsceneSkip.Instance.SkipSetting.Value && ((Object)((Component)__instance).transform.parent.parent.parent).name == "SimpleCutSceneFSM_Tree intro" && FullPath.GetFullPath(((Component)__instance).gameObject) == "AG_S1/Room/SimpleCutSceneFSM_Tree intro/FSM Animator/LogicRoot/[CutScene]")
			{
				Log.Info("SpeedrunCutsceneSkip waiting 1.6 seconds before skipping the Warehouse Heng call");
				await UniTask.Delay(1667, false, (PlayerLoopTiming)8, default(CancellationToken));
				Log.Info("SpeedrunCutsceneSkip skipping the Senate Hall call");
				__instance.TrySkip();
				SpeedrunCutsceneSkip.AddSkippedTimeToLivesplit(27.917f);
			}
		}
	}
	internal static class CutsceneTimingConstants
	{
		public const float CentralHallPhone = 27.917f;

		public const float PavillionNymphIntro_RuyiActivation = 37.283f;

		public const float PavillionNymphIntro_ShuanshuanDialogue = 18.683f;

		public const float PowerReservoirHengCall = 41.076f;

		public const float WarehouseHengCall = 71.131f;

		public const float YanlaoBoundlessRepositoryEntrance = 26.621f;

		public const float YanlaoBossIntro = 47.1f;

		public const float PrisonTortureScene = 126.754f;

		public const float LadyEtherealPostBoss = 134.713f;

		public const float EDSanctumHengCall = 63.517f;

		public const float EigongSoulscape = 236.528f;
	}
	[HarmonyPatch]
	internal class EDSanctumHengCall
	{
		private static SimpleCutsceneManager? activeSanctumCall;

		[HarmonyPostfix]
		[HarmonyPatch(typeof(SimpleCutsceneManager), "PlayAnimation")]
		private static async void SimpleCutsceneManager_PlayAnimation_Postfix(SimpleCutsceneManager __instance)
		{
			if (SpeedrunCutsceneSkip.Instance.SkipSetting.Value && ((Object)((Component)__instance).transform.parent.parent.parent).name == "SimpleCutSceneFSM_A9_S3妹妹回憶" && FullPath.GetFullPath(((Component)__instance).gameObject) == "A9_S3/Room/SimpleCutSceneFSM_A9_S3妹妹回憶/FSM Animator/LogicRoot/[CutScene]")
			{
				Log.Info("SpeedrunCutsceneSkip waiting for dialogue to start before skipping the ED Sanctum Heng call");
				activeSanctumCall = __instance;
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(DialoguePlayer), "StartDialogue")]
		private static async void DialoguePlayer_StartDialogue(DialoguePlayer __instance, DialogueGraph dialogueGraph, Action callback, bool withBackground)
		{
			if (SpeedrunCutsceneSkip.Instance.SkipSetting.Value && (Object)(object)activeSanctumCall != (Object)null)
			{
				Log.Info("SpeedrunCutsceneSkip waiting 1.6 seconds before skipping the ED Sanctum Heng call");
				await UniTask.Delay(1667, false, (PlayerLoopTiming)8, default(CancellationToken));
				Log.Info("SpeedrunCutsceneSkip skipping the ED Sanctum Heng call");
				__instance.TrySkip();
				activeSanctumCall.TrySkip();
				activeSanctumCall = null;
				SpeedrunCutsceneSkip.AddSkippedTimeToLivesplit(63.517f);
			}
		}
	}
	[HarmonyPatch]
	internal class EigongSoulscape
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(SimpleCutsceneManager), "PlayAnimation")]
		private static async void SimpleCutsceneManager_PlayAnimation_Postfix(SimpleCutsceneManager __instance)
		{
			if (SpeedrunCutsceneSkip.Instance.SkipSetting.Value)
			{
				string fullPath = FullPath.GetFullPath(((Component)__instance).gameObject);
				Log.Info("SpeedrunCutsceneSkip eigong check " + ((Object)__instance).name + " - " + fullPath);
				if (((Object)((Component)__instance).transform.parent.parent.parent).name == "SimpleCutSceneFSM_易公陷阱" && FullPath.GetFullPath(((Component)__instance).gameObject) == "VR_TaoChang/Room/Prefab/Simple Binding Tool/SimpleCutSceneFSM_易公陷阱/FSM Animator/LogicRoot/[CutScene]")
				{
					Log.Info("SpeedrunCutsceneSkip waiting 1.6 seconds before skipping the Eigong first dialogue in her soulscape");
					await UniTask.Delay(1667, false, (PlayerLoopTiming)8, default(CancellationToken));
					Log.Info("SpeedrunCutsceneSkip skipping the Eigong confrontation inside her soulscape");
					__instance.TrySkip();
				}
				if (((Object)((Component)__instance).transform.parent.parent.parent).name == "SimpleCutSceneFSM_易公後妹妹回憶" && FullPath.GetFullPath(((Component)__instance).gameObject) == "VR_TaoChang/Room/SimpleCutSceneFSM_易公後妹妹回憶/FSM Animator/LogicRoot/[CutScene]")
				{
					Log.Info("SpeedrunCutsceneSkip waiting 1.6 seconds before skipping the Heng flashback inside of Eigong's soulscape");
					await UniTask.Delay(1667, false, (PlayerLoopTiming)8, default(CancellationToken));
					Log.Info("SpeedrunCutsceneSkip skipping the Heng flashback inside of Eigong's soulscape");
					__instance.TrySkip();
				}
				if (((Object)((Component)__instance).transform.parent.parent.parent).name == "[CutScene]BackFromSleeppod" && FullPath.GetFullPath(((Component)__instance).gameObject) == "A11_S2/Room/敘事相關/Sleeppod  FSM_易公/[CutScene]BackFromSleeppod/FSM Animator/LogicRoot/[CutScene]")
				{
					Log.Info("SpeedrunCutsceneSkip skipping the wakeup cutscene after Eigong's soulscape");
					__instance.TrySkip();
					SpeedrunCutsceneSkip.AddSkippedTimeToLivesplit(236.528f);
				}
			}
		}
	}
	internal class FullPath
	{
		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);
		}
	}
	[HarmonyPatch]
	internal class LadyEtherealPostBoss
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(SimpleCutsceneManager), "PlayAnimation")]
		private static async void SimpleCutsceneManager_PlayAnimation_Postfix(SimpleCutsceneManager __instance)
		{
			if (SpeedrunCutsceneSkip.Instance.SkipSetting.Value)
			{
				if (((Object)((Component)__instance).transform.parent.parent.parent).name == "SimpleCutSceneFSM (離開幻境)" && FullPath.GetFullPath(((Component)__instance).gameObject) == "P2_R22_Savepoint_GameLevel/EventBinder/SimpleCutSceneFSM (離開幻境)/FSM Animator/LogicRoot/[CutScene]")
				{
					Log.Info("SpeedrunCutsceneSkip skipping Lady Ethereal's post-fight cutscene");
					__instance.TrySkip();
				}
				if (((Object)((Component)__instance).transform.parent.parent.parent).name == "A7_S6_Cutscene FSM" && FullPath.GetFullPath(((Component)__instance).gameObject) == "A7_S6_Memory_Butterfly_CutScene_GameLevel/A7_S6_Cutscene FSM/FSM Animator/LogicRoot/[CutScene]")
				{
					Log.Info("SpeedrunCutsceneSkip skipping the Azure Flyer flashback cutscene");
					__instance.TrySkip();
				}
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(VideoPlayAction), "OnStateEnterImplement")]
		private static async void VideoPlayAction_OnStateEnterImplement(VideoPlayAction __instance)
		{
			if (SpeedrunCutsceneSkip.Instance.SkipSetting.Value && ((Object)__instance).name == "[Action] VideoPlayAction" && FullPath.GetFullPath(((Component)__instance).gameObject) == "A7_S6_Memory_Butterfly_CutScene_GameLevel/A7_S6_Cutscene FSM/--[States]/FSM/[State] PlayingVideo/[Action] VideoPlayAction")
			{
				Log.Info("SpeedrunCutsceneSkip waiting 1.6 seconds before skipping the post-Lady Ethereal Heng flashback video");
				await UniTask.Delay(1667, false, (PlayerLoopTiming)8, default(CancellationToken));
				Log.Info("SpeedrunCutsceneSkip skipping the post-Lady Ethereal Heng flashback video");
				AccessTools.Method(typeof(VideoPlayAction), "TrySkip", (Type[])null, (Type[])null).Invoke(__instance, Array.Empty<object>());
				SpeedrunCutsceneSkip.AddSkippedTimeToLivesplit(134.713f);
			}
		}
	}
	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);
			}
		}
	}
	[HarmonyPatch]
	internal class PavillionNymphIntro
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(SimpleCutsceneManager), "PlayAnimation")]
		private static async void SimpleCutsceneManager_PlayAnimation_Postfix(SimpleCutsceneManager __instance)
		{
			if (SpeedrunCutsceneSkip.Instance.SkipSetting.Value)
			{
				if (((Object)((Component)__instance).transform.parent.parent.parent.parent).name == "NPC_AICore_FSM" && FullPath.GetFullPath(((Component)__instance).gameObject) == "AG_S2/Room/Prefab/ControlRoom FSM Binding Tool/NPC_AICore_Base/NPC_AICore_Base_FSM/FSM Animator/LogicRoot/NPC_AICore_FSM/General FSM Object/Animator(FSM)/LogicRoot/[CutScene]初次對話演出")
				{
					Log.Info("SpeedrunCutsceneSkip waiting 1.6 seconds before skipping the Ruyi activation cutscene");
					await UniTask.Delay(1667, false, (PlayerLoopTiming)8, default(CancellationToken));
					Log.Info("SpeedrunCutsceneSkip skipping the Ruyi restore sequence");
					__instance.TrySkip();
					SpeedrunCutsceneSkip.AddSkippedTimeToLivesplit(37.283f);
				}
				if (((Object)((Component)__instance).transform.parent.parent.parent).name == "SimpleCutSceneFSM_軒軒到基地演出" && FullPath.GetFullPath(((Component)__instance).gameObject) == "AG_S2/Room/NPCs/議會演出相關Binding/SimpleCutSceneFSM_軒軒到基地演出/FSM Animator/LogicRoot/[CutScene]")
				{
					Log.Info("SpeedrunCutsceneSkip waiting 1.6 seconds before skipping the Shuanshuan intro dialogue");
					await UniTask.Delay(1667, false, (PlayerLoopTiming)8, default(CancellationToken));
					Log.Info("SpeedrunCutsceneSkip skipping the Shuanshuan dialogue");
					__instance.TrySkip();
					SpeedrunCutsceneSkip.AddSkippedTimeToLivesplit(18.683f);
				}
			}
		}
	}
	[HarmonyPatch]
	internal class PowerReservoirHengCall
	{
		[HarmonyPrefix]
		[HarmonyPatch(typeof(A2_SG4_Logic), "EnterLevelStart")]
		private static async void A2_SG4_Logic_EnterLevelStart(A2_SG4_Logic __instance)
		{
			if (SpeedrunCutsceneSkip.Instance.SkipSetting.Value)
			{
				Log.Info("SpeedrunCutsceneSkip skipping the Power Reservoir (Center) Heng call");
				await UniTask.Delay(250, false, (PlayerLoopTiming)8, default(CancellationToken));
				__instance.TrySkip();
				SpeedrunCutsceneSkip.AddSkippedTimeToLivesplit(41.076f);
			}
		}
	}
	internal struct SimpleCutsceneSkipData
	{
		public int delayTime;

		public float livesplitAddedTime;
	}
	internal static class SimpleCutsceneSkipDataTable
	{
		public static readonly Dictionary<string, SimpleCutsceneSkipData> Table = new Dictionary<string, SimpleCutsceneSkipData>
		{
			{
				"A4_S5/Room/TaoChangSniper_SimpleCutSceneFSM/FSM Animator/LogicRoot/[CutScene]",
				new SimpleCutsceneSkipData
				{
					delayTime = 1667,
					livesplitAddedTime = 26.621f
				}
			},
			{
				"A5_S2/Room/SimpleCutSceneFSM_A5妹妹回憶/FSM Animator/LogicRoot/[CutScene]",
				new SimpleCutsceneSkipData
				{
					delayTime = 250,
					livesplitAddedTime = 0f
				}
			},
			{
				"A5_S2/Room/SimpleCutSceneFSM_A5妹妹回憶/FSM Animator/LogicRoot/[CutScene] Second",
				new SimpleCutsceneSkipData
				{
					delayTime = 0,
					livesplitAddedTime = 0f
				}
			},
			{
				"A5_S2/Room/SimpleCutSceneFSM_A5妹妹回憶/FSM Animator/LogicRoot/[CutScene] Third",
				new SimpleCutsceneSkipData
				{
					delayTime = 0,
					livesplitAddedTime = 126.754f
				}
			}
		};
	}
	[HarmonyPatch]
	internal class SimpleCutsceneSkip
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(SimpleCutsceneManager), "PlayAnimation")]
		private static async void SimpleCutsceneManager_PlayAnimation_Postfix(SimpleCutsceneManager __instance)
		{
			if (!SpeedrunCutsceneSkip.Instance.SkipSetting.Value)
			{
				return;
			}
			string goPath = FullPath.GetFullPath(((Component)__instance).gameObject);
			if (SimpleCutsceneSkipDataTable.Table.ContainsKey(goPath))
			{
				int delayTime = SimpleCutsceneSkipDataTable.Table[goPath].delayTime;
				if (delayTime > 0)
				{
					Log.Info($"SpeedrunCutsceneSkip waiting {delayTime}ms before skipping cutscene: {goPath}");
					await UniTask.Delay(delayTime, false, (PlayerLoopTiming)8, default(CancellationToken));
				}
				Log.Info("SpeedrunCutsceneSkip skipping cutscene: " + goPath);
				__instance.TrySkip();
				SpeedrunCutsceneSkip.AddSkippedTimeToLivesplit(SimpleCutsceneSkipDataTable.Table[goPath].livesplitAddedTime);
			}
		}
	}
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("SpeedrunCutsceneSkip", "SpeedrunCutsceneSkip", "0.0.1")]
	public class SpeedrunCutsceneSkip : BaseUnityPlugin
	{
		public ConfigEntry<bool> SkipSetting;

		public static SpeedrunCutsceneSkip Instance;

		private Harmony harmony;

		private int LivesplitHook_SkippedCutscenesCount;

		private float LivesplitHook_TimeToAdd;

		private void Awake()
		{
			Log.Init(((BaseUnityPlugin)this).Logger);
			RCGLifeCycle.DontDestroyForever(((Component)this).gameObject);
			Instance = this;
			harmony = Harmony.CreateAndPatchAll(typeof(SpeedrunCutsceneSkip).Assembly, (string)null);
			SkipSetting = ((BaseUnityPlugin)this).Config.Bind<bool>("", "Skip Certain Cutscenes", true, "Turn this off and this mod will no longer do anything.");
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Plugin SpeedrunCutsceneSkip is loaded!");
		}

		private void OnDestroy()
		{
			harmony.UnpatchSelf();
		}

		public static void AddSkippedTimeToLivesplit(float time)
		{
			Instance.LivesplitHook_TimeToAdd = time;
			Instance.LivesplitHook_SkippedCutscenesCount++;
		}
	}
	[HarmonyPatch]
	internal class WarehouseHengCall
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(SimpleCutsceneManager), "PlayAnimation")]
		private static async void SimpleCutsceneManager_PlayAnimation_Postfix(SimpleCutsceneManager __instance)
		{
			if (SpeedrunCutsceneSkip.Instance.SkipSetting.Value && ((Object)((Component)__instance).transform.parent.parent.parent).name == "妹妹回憶_SimpleCutSceneFSM" && FullPath.GetFullPath(((Component)__instance).gameObject) == "A2_SG4/Room/妹妹回憶_SimpleCutSceneFSM/FSM Animator/LogicRoot/[CutScene]")
			{
				Log.Info("SpeedrunCutsceneSkip waiting 1.6 seconds before skipping the Warehouse Heng call");
				await UniTask.Delay(1667, false, (PlayerLoopTiming)8, default(CancellationToken));
				Log.Info("SpeedrunCutsceneSkip skipping the Warehouse Heng call");
				__instance.TrySkip();
				SpeedrunCutsceneSkip.AddSkippedTimeToLivesplit(71.131f);
			}
		}
	}
	[HarmonyPatch]
	internal class YanlaoPreFight
	{
		[HarmonyPrefix]
		[HarmonyPatch(typeof(A4_S5_Logic), "EnterLevelStart")]
		private static async void A4_S5_Logic_Start(A4_S5_Logic __instance)
		{
			if (SpeedrunCutsceneSkip.Instance.SkipSetting.Value && !__instance.FirstTimeAnimationPlayed.CurrentValue)
			{
				await UniTask.Delay(1000, false, (PlayerLoopTiming)8, default(CancellationToken));
				Log.Info("SpeedrunCutsceneSkip skipping the Yanlao Pre-Fight Scene");
				__instance.BeforeMangaBubble.TrySkip();
				__instance.StartCutscene.TrySkip();
				__instance.BubbleDialogue.TrySkip();
				__instance.MechClawGamePlay.gameObject.SetActive(true);
				((Component)__instance.GianMechClawMonsterBase).gameObject.SetActive(true);
				__instance.SwapClaw();
				((ICutScene)__instance.StartCutsceneEmergency).PlayCutscene((Action)delegate
				{
					AccessTools.Method(typeof(A4_S5_Logic), "StartFight", new Type[0], (Type[])null).Invoke(__instance, new object[0]);
				}, 1f, true, 0f);
				SpeedrunCutsceneSkip.AddSkippedTimeToLivesplit(47.1f);
			}
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "SpeedrunCutsceneSkip";

		public const string PLUGIN_NAME = "SpeedrunCutsceneSkip";

		public const string PLUGIN_VERSION = "0.0.1";
	}
}