Files
beyond/Assets/Scripts/Cutscene/CutScene.cs
2024-11-20 15:21:28 +01:00

658 lines
21 KiB
C#

using Invector.vCamera;
using PixelCrushers.DialogueSystem;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using PixelCrushers.QuestMachine;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Playables;
using Sirenix.OdinInspector;
using QuestState = PixelCrushers.QuestMachine.QuestState;
using PixelCrushers;
namespace Beyond
{
[Serializable]
public class CutsceneSaveData
{
public bool wasPlayed;
}
[RequireComponent(typeof(PlayableDirector))]
public class CutScene : Saver
{
public static Action<bool> CutSceneEnable;
[Header("Conditions"), Tooltip("Leave it empty if you want this to play every time")]
public Condition m_condition;
[Header("Start Cutscene")] public GameObject[] toEnableOnStart;
public GameObject[] toDisableOnStart;
public UnityEvent m_onStartEvent;
[Header("End Cutscene")] public GameObject[] toEnableOnEnd;
public GameObject[] toDisableOnEnd;
public UnityEvent m_onEndEvent;
[Space]
[Tooltip("Depricated! don't use. Left to make sure some settings won't be lost (before copping)")]
public FadeSettings fadeSettings;
public bool m_completeCurrentQuest = false;
private float m_fadeTime = 1f;
public TeleportObject teleport;
public bool playOnStart = false;
//public bool playOnce = true;
public bool playMultipleTimes = false;
[TitleGroup("Skip Fade")]
public bool skipFadeOutIn = false;
[TitleGroup("Skip Fade")]
public bool skipFadeIn = false;
private bool timelineStarted;
private PlayableDirector m_playableDirector;
private Camera[] cameras;
private bool timeLineStoped;
private PlayState timeLineState = PlayState.Paused;
[Header("Debug"), SerializeField, Min(0.001f)]
private float m_speed = 1f;
private AudioListener[] audioListeners;
private CutSceneLerpCamera lerpCamera;
private StandardBarkUI m_barkUI;
private Camera playerCamera;
private bool cancelAlphaWait;
private Coroutine cancelAlpha;
private bool followTarget;
private Camera lastUseCamera;
private float cutSceneTimer;
private float nearestStopTime;
private CutSceneDialogueBreakpoint currentDialogueBreakpoint;
private int currentDialogueBreakpointIndex = 0;
private bool wasPlayed;
private bool wasLoaded;
public bool WasPlayed
{
set { wasPlayed = value; }
get { return wasPlayed; }
}
[SerializeField] private CutsceneLevelLoader m_cutsceneLevelLoader = new CutsceneLevelLoader();
[Space]
[Header("Breakpoints")]
[SerializeField]
private List<CutSceneBreakpoint> cutSceneBreakpoints = new List<CutSceneBreakpoint>();
[SerializeField]
private List<CutSceneDialogueBreakpoint> cutSceneDialogueBreakpoints = new List<CutSceneDialogueBreakpoint>();
private bool CanStart
{
get
{
if (wasPlayed && !playMultipleTimes)
return false;
return m_condition.IsTrue(Player.Instance.transform);
}
}
public bool TimelineStarted
{
get => timelineStarted;
set => timelineStarted = value;
}
public override void Awake()
{
base.Awake();
//fadeSettings.CreateInverseEndFadeCurve();
m_playableDirector = GetComponent<PlayableDirector>();
m_playableDirector.playOnAwake = false;
cameras = GetComponentsInChildren<Camera>(true);
audioListeners = GetComponentsInChildren<AudioListener>(true);
SetActiveCameras(false);
SetActiveAudioListener(false);
var tpCam = FindObjectOfType<vThirdPersonCamera>();
if (tpCam)
playerCamera = tpCam.GetComponent<Camera>();
wasPlayed = false;
}
private IEnumerator Start()
{
//lil hack to prevent starting cutscenes while loading, person to blame -> Seba
//yield return new WaitForSeconds(0.1f);
yield return null;
yield return null;
m_barkUI = GameObject.FindObjectOfType<StandardBarkUI>();
if (CanStart)
{
if (playOnStart)
PlayTimeline();
}
/*
else
{
this.gameObject.SetActive(false);
}
*/
}
public override void OnEnable()
{
base.OnEnable();
m_playableDirector.played += OnPlayed;
m_playableDirector.stopped += OnStoped;
m_playableDirector.paused += OnPaused;
cutSceneDialogueBreakpoints = cutSceneDialogueBreakpoints.OrderBy(x => x.PauseTime).ToList();
currentDialogueBreakpoint = GetCutsceneDialogueBreakpoint(currentDialogueBreakpointIndex);
}
public override void OnDisable()
{
base.OnDisable();
m_playableDirector.played -= OnPlayed;
m_playableDirector.stopped -= OnStoped;
m_playableDirector.paused -= OnPaused;
}
public override void OnDestroy()
{
base.OnDestroy();
m_playableDirector.played -= OnPlayed;
m_playableDirector.stopped -= OnStoped;
m_playableDirector.paused -= OnPaused;
StopAllCoroutines();
}
private void OnPaused()
{
if (m_playableDirector.state == PlayState.Playing)
{
m_playableDirector.Pause();
}
else
{
m_playableDirector.Play();
}
}
private void OnSkip()
{
//StopCoroutine(cancelAlpha);
//StopAllCoroutines();
//StartCoroutine(OnExitDelay());
OnStoped(m_playableDirector);
}
private void OnPaused(PlayableDirector director)
{
if (timelineStarted == false)
{
PlayTimeline();
}
}
private void SetActive(GameObject[] list, bool isActive)
{
var length = list.Length;
for (int i = 0; i < length; i++)
{
if (list[i] != null)
{
list[i].gameObject.SetActive(isActive);
}
}
}
private CutSceneDialogueBreakpoint GetCutsceneDialogueBreakpoint(int index)
{
return cutSceneDialogueBreakpoints.Count <= 0 || index >= cutSceneDialogueBreakpoints.Count
? null
: cutSceneDialogueBreakpoints[index];
}
private CutSceneBreakpoint GetCutsceneBreakpoint(int index)
{
return cutSceneBreakpoints.Count <= 0 || index >= cutSceneDialogueBreakpoints.Count
? null
: cutSceneBreakpoints[index];
}
private void OnPlayed(PlayableDirector director)
{
if (timelineStarted == false)
{
director.Pause();
}
}
private void Update()
{
if (timelineStarted)
{
if (currentDialogueBreakpoint == null)
{
return;
}
if (m_playableDirector.time >= currentDialogueBreakpoint.PauseTime)
{
m_playableDirector.Pause();
DialogueManager.instance.StartConversation(currentDialogueBreakpoint.DialogueTitle);
currentDialogueBreakpointIndex++;
currentDialogueBreakpoint = GetCutsceneDialogueBreakpoint(currentDialogueBreakpointIndex);
}
}
}
private void LateUpdate()
{
if (lerpCamera != null || timelineStarted == false || timeLineStoped == true) return;
if (playerCamera && followTarget)
{
var length = cameras.Length;
for (int i = 0; i < length; i++)
{
if (cameras[i].gameObject.activeInHierarchy)
{
lastUseCamera = cameras[i];
playerCamera.transform.position = cameras[i].transform.position;
playerCamera.transform.rotation = cameras[i].transform.rotation;
break;
}
}
//No active cutscene camera! Keep old transform.
if (lastUseCamera)
{
playerCamera.transform.position = lastUseCamera.transform.position;
playerCamera.transform.rotation = lastUseCamera.transform.rotation;
}
}
}
private void OnStoped(PlayableDirector director)
{
//FadeCanvasGroup.Instance.FadeIn(1f);
if (!timeLineStoped)
{
timeLineStoped = true;
timeLineState = PlayState.Paused;
timelineStarted = false;
director.Stop();
director.timeUpdateMode = DirectorUpdateMode.Manual;
director.time = director.duration;
director.Evaluate();
if (lerpCamera == null)
{
teleport.Teleport(vThirdPersonCamera.instance.transform);
vThirdPersonCamera.instance.ResetAngle();
vThirdPersonCamera.instance.ResetTarget();
}
try
{
m_onEndEvent?.Invoke();
}
catch (Exception e)
{
Debug.LogError("CutScene: error on OnStopped, while executing event. Message: " + e.Message);
}
SetActive(toEnableOnEnd, true);
SetActive(toDisableOnEnd, false);
SkipCanvas.Instance.m_OnSkip -= OnSkip;
SkipCanvas.Instance.m_OnPause -= OnPaused;
SkipCanvas.Instance.gameObject.SetActive(false);
}
Player.Instance.ResetAnimator();
if (lerpCamera == null)
{
//after player is enabled on set active, so everything works just fine
EnableInputAndUI();
}
var dc = Player.Instance.GetComponent<bDrawHideMeleeWeapons>();
if (dc != null)
{
dc.HideWeapons(true);
}
if (m_cutsceneLevelLoader.Enabled)
{
m_cutsceneLevelLoader.LoadLevel();
}
StopAllCoroutines();
//FadeCanvasGroup.Instance.FadeIn(1f);
}
/*
private void OnStoped(PlayableDirector director)
{
StopAllCoroutines();
StartCoroutine(OnStopedCoroutine(director));
}
private IEnumerator OnStopedCoroutine(PlayableDirector director)
{
if (!timeLineStoped)
{
director.time = director.duration;
//give one frame to move director to the end
yield return null;
director.Stop();
if (lerpCamera == null)
{
EnableInputAndUI();
}
timeLineStoped = true;
timeLineState = PlayState.Paused;
timelineStarted = false;
if (lerpCamera == null)
{
teleport.Teleport(vThirdPersonCamera.instance.transform);
}
m_onEndEvent?.Invoke();
SetActive(toEnableOnEnd, true);
SetActive(toDisableOnEnd, false);
SkipCanvas.Instance.m_OnSkip -= OnSkip;
SkipCanvas.Instance.m_OnPause -= OnPaused;
SkipCanvas.Instance.gameObject.SetActive(false);
}
var dc = Player.Instance.GetComponent<bDrawHideMeleeWeapons>();
if (dc != null)
{
dc.HideWeapons(true);
}
yield return null;
}
*/
private IEnumerator OnPlayDelay()
{
wasPlayed = true;
Player.Instance.PlayerInput.SetLockAllInput(true);
if (lerpCamera == null && FadeCanvasGroup.Instance != null)
{
if (playOnStart || skipFadeIn)
{
FadeCanvasGroup.Instance.FadeIn(m_fadeTime);
//yield return new WaitForSeconds(m_fadeTime);
followTarget = true;
}
else
{
FadeCanvasGroup.Instance.FadeOutIn(m_fadeTime);
yield return new WaitForSeconds(m_fadeTime);
followTarget = true;
//yield return new WaitForSeconds(m_fadeTime * 0.5f);
}
///FadeCanvasGroup.InvokeFade(fadeSettings.Startfade, fadeSettings.speed * m_speed);
//
/*
FadeCanvasGroup.Instance.FadeOutIn(m_fadeTime);
cancelAlpha = StartCoroutine(CancelAlphaWait());
yield return new WaitUntil(() => Alpha1());
yield return new WaitForSeconds(m_fadeTime * 0.5f);
followTarget = true;
yield return new WaitForSeconds(m_fadeTime * 0.5f);
yield return new WaitUntil(() => Alpha0());
if (cancelAlpha != null)
{
StopCoroutine(cancelAlpha);
}
*/
}
else
{
yield return null;
}
HideUI.InvokeSetActiveUI(false);
SkipCanvas.Instance.gameObject.SetActive(true);
SkipCanvas.Instance.m_OnSkip += OnSkip;
SkipCanvas.Instance.m_OnPause += OnPaused;
if (m_playableDirector && timeLineState != PlayState.Playing)
{
timeLineState = PlayState.Playing;
m_playableDirector.initialTime = 0f;
m_playableDirector.Play();
m_playableDirector.playableGraph.GetRootPlayable(0).SetSpeed(m_speed);
CutSceneEnable?.Invoke(true);
m_onStartEvent?.Invoke();
SetActive(toEnableOnStart, true);
SetActive(toDisableOnStart, false);
timeLineStoped = false;
StartCoroutine(OnExitDelay());
}
yield return null;
}
private IEnumerator OnExitDelay()
{
//var waitTime = (float)m_playableDirector.playableAsset.duration - (fadeSettings.GetInverseEndFadeCurveValue(1f) / fadeSettings.speed);
var waitTime =
(float)m_playableDirector.playableAsset.duration - m_fadeTime -
.2f; // * 0.5f; //0.5, b robimy fade in/out
while (m_playableDirector.time /*+ Time.deltaTime * 2f*/ <
waitTime) // hak, chcę być o jedną 2 klatkę do przodu.
{
yield return null;
}
if (lerpCamera == null)
{
if (!skipFadeOutIn)// && m_cutsceneLevelLoader.Enabled == false)
{
FadeCanvasGroup.Instance.FadeOutIn(m_fadeTime);
}
}
//cancelAlpha = StartCoroutine(CancelAlphaWait());
//yield return new WaitUntil(() => Alpha1());
//yield return new WaitUntil(() => Alpha0());
//yield return new WaitForSeconds(m_fadeTime * 0.5f);
// if (m_cutsceneLevelLoader.Enabled)
// {
// FadeCanvasGroup.Instance.FadeOut(m_fadeTime);
// yield return new WaitForSeconds(m_fadeTime);
// m_cutsceneLevelLoader.LoadLevel();
// yield break;
// }
yield return new WaitForSeconds(m_fadeTime);
followTarget = false;
//if (cancelAlpha != null)
//{
// StopCoroutine(cancelAlpha);
//}
OnStoped(m_playableDirector);
yield return null;
}
private IEnumerator CancelAlphaWait()
{
cancelAlphaWait = false;
float maxWaitTime = m_fadeTime;
//if (curve != null && curve.keys.Length > 0)
//{
//maxWaitTime = curve.keys[curve.length - 1].time / fadeSettings.speed;
//}
yield return new WaitForSeconds(maxWaitTime);
Debug.Log("Fade timeout, cancel wait");
cancelAlphaWait = true;
cancelAlpha = null;
}
private bool Alpha1()
{
return FadeCanvasGroup.Instance.canvasGroup.alpha >= 1f || cancelAlphaWait;
}
private bool Alpha0()
{
return FadeCanvasGroup.Instance.canvasGroup.alpha < 1f || cancelAlphaWait;
}
public void EnableInputAndUI()
{
HideUI.InvokeSetActiveUI(true);
CutSceneEnable?.Invoke(false);
Player.Instance.PlayerInput.SetLockAllInput(false);
Debug.Log("Disabled cutscene");
}
public void ResumeCutScene()
{
m_playableDirector.Resume();
}
[Button]
private void CompleteQuest()
{
var journal = QuestMachine.GetQuestJournal();
Quest currentQuest = null;
for (int i = 0; i < journal.questList.Count; i++)
{
var quest = journal.questList[i];
if (!quest.isTrackable || quest.GetState() == QuestState.Successful)
{
continue;
}
currentQuest = quest;
break;
}
if (currentQuest)
{
for (int i = 0; i < currentQuest.nodeList.Count; i++)
{
if (currentQuest.nodeList[i].GetState() == QuestNodeState.True)
{
continue;
}
if (currentQuest.nodeList[i].GetState() == QuestNodeState.Active)
{
currentQuest.nodeList[i].SetState(QuestNodeState.True);
journal.OnQuestNodeStateChanged(currentQuest.nodeList[i]);
}
}
//journal.();
}
}
[Button]
public void PlayTimeline()
{
if (CanStart)
{
timelineStarted = true;
lastUseCamera = null;
lerpCamera = GetComponent<CutSceneLerpCamera>();
if (lerpCamera != null && !lerpCamera.enabled)
{
lerpCamera = null;
}
if (m_completeCurrentQuest)
{
CompleteQuest();
}
StartCoroutine(OnPlayDelay());
}
}
private void SetActiveCameras(bool isActive)
{
foreach (var item in cameras)
{
item.enabled = isActive;
}
}
private void SetActiveAudioListener(bool isActive)
{
foreach (var item in audioListeners)
{
item.enabled = isActive;
}
}
private void OnValidate()
{
m_playableDirector = GetComponent<PlayableDirector>();
m_playableDirector.playOnAwake = false;
}
public override string RecordData()
{
CutsceneSaveData data = new();
data.wasPlayed = WasPlayed;
return SaveSystem.Serialize(data);
}
public override void ApplyData(string s)
{
var sd = SaveSystem.Deserialize<CutsceneSaveData>(s);
if (sd != null)
{
WasPlayed = sd.wasPlayed;
}
if (wasPlayed)
{
gameObject.SetActive(false);
}
}
}
[System.Serializable]
public class CutSceneBreakpoint
{
public float PauseTime;
public float Duration;
public UnityEvent OnPauseStart;
public UnityEvent OnPauseEnd;
}
[System.Serializable]
public class CutSceneDialogueBreakpoint
{
public float PauseTime;
public string DialogueTitle;
[Tooltip("if 0 pause will be stay until player pick choice")]
public float TimeForAutomaticChoice;
}
}