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";
}
}