294 lines
8.5 KiB
C#
294 lines
8.5 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using AibisDream.Kit;
|
|
using AibisDream.SaveSystem;
|
|
using UnityEngine;
|
|
using UnityEngine.Events;
|
|
using AibisDream.Framework;
|
|
using Yarn.Unity;
|
|
|
|
namespace AibisDream
|
|
{
|
|
public class DialogController : Singleton<DialogController>
|
|
{
|
|
private DialogueRunner _dialogueRunner;
|
|
|
|
public DialogueRunner DialogueRunner => _dialogueRunner;
|
|
|
|
[SerializeField] private LineAdvanceInput lineAdvanceInput;
|
|
|
|
private string _currentNodeName;
|
|
private string[] _currentNodeTags;
|
|
|
|
private void Start()
|
|
{
|
|
_dialogueRunner = GetComponentInChildren<DialogueRunner>();
|
|
_dialogueRunner.onDialogueStart ??= new UnityEvent();
|
|
_dialogueRunner.onDialogueComplete ??= new UnityEvent();
|
|
_dialogueRunner.onNodeStart ??= new UnityEventString();
|
|
_dialogueRunner.onNodeComplete ??= new UnityEventString();
|
|
|
|
_dialogueRunner.onDialogueStart.AddListener(() =>
|
|
{
|
|
EnumEventSystem.Global.Send(InteractionEventEnum.DialogStart);
|
|
});
|
|
|
|
_dialogueRunner.onDialogueComplete.AddListener(() =>
|
|
{
|
|
EnumEventSystem.Global.Send(InteractionEventEnum.DialogEnd);
|
|
ClearCurrentNodeContext();
|
|
});
|
|
|
|
_dialogueRunner.onNodeStart.AddListener(OnNodeStart);
|
|
_dialogueRunner.onNodeComplete.AddListener(OnNodeComplete);
|
|
}
|
|
|
|
private void OnEnable()
|
|
{
|
|
SingleCastEventSystem.Global.Register<DialogEventEnum, string>(DialogEventEnum.StartNode, StartDialogNode);
|
|
|
|
EnumEventSystem.Global.Register(GameLoopEnum.GameStart, ResetAdvanceMode);
|
|
EnumEventSystem.Global.Register(GameLoopEnum.GameQuit, ResetAdvanceMode);
|
|
|
|
EnumEventSystem.Global.Register(DialogEventEnum.OptionShow, OnOptionShow);
|
|
EnumEventSystem.Global.Register<DialogEventEnum, LineInfo>(DialogEventEnum.OptionSelected, OnOptionSelected);
|
|
}
|
|
|
|
private void OnDisable()
|
|
{
|
|
SingleCastEventSystem.Global.Unregister(DialogEventEnum.StartNode);
|
|
|
|
EnumEventSystem.Global.UnRegister(GameLoopEnum.GameStart, ResetAdvanceMode);
|
|
EnumEventSystem.Global.UnRegister(GameLoopEnum.GameQuit, ResetAdvanceMode);
|
|
|
|
EnumEventSystem.Global.UnRegister(DialogEventEnum.OptionShow, OnOptionShow);
|
|
EnumEventSystem.Global.UnRegister<DialogEventEnum, LineInfo>(DialogEventEnum.OptionSelected, OnOptionSelected);
|
|
}
|
|
|
|
private void ResetAdvanceMode()
|
|
{
|
|
advanceMode.Value = new AdvanceMode
|
|
{
|
|
isAuto = false,
|
|
isQuick = false
|
|
};
|
|
|
|
isInOption = false;
|
|
lineSyncToken = null;
|
|
|
|
Time.timeScale = 1f;
|
|
}
|
|
|
|
#region Yarn控制
|
|
|
|
/// <summary>
|
|
/// 开启对话
|
|
/// </summary>
|
|
/// <param name="yarnProject">Yarn组</param>
|
|
public void StartDialog(YarnProject yarnProject)
|
|
{
|
|
_dialogueRunner.SetProject(yarnProject);
|
|
_ = _dialogueRunner.StartDialogue("Start");
|
|
}
|
|
|
|
public void StopDialog()
|
|
{
|
|
_ = _dialogueRunner.Stop();
|
|
YarnVariableStorage.Instance.Clear();
|
|
DialogUIManager.Instance.HideDialog();
|
|
}
|
|
|
|
public void LoadDialog(YarnProject yarnProject)
|
|
{
|
|
_dialogueRunner.SetProject(yarnProject);
|
|
_ = _dialogueRunner.StartDialogue("Center");
|
|
}
|
|
|
|
public void StartDialogNode(string nodeName)
|
|
{
|
|
// 检查对话是否正在运行
|
|
if (_dialogueRunner.IsDialogueRunning)
|
|
{
|
|
Debug.LogWarning($"对话正在运行中,无法启动新节点: {nodeName}");
|
|
return;
|
|
}
|
|
|
|
if (CheckIfNodeExistInCurrentYarnProject(nodeName))
|
|
{
|
|
_ = _dialogueRunner.StartDialogue(nodeName);
|
|
}
|
|
else
|
|
{
|
|
Debug.LogWarning($"节点 {nodeName} 不存在!");
|
|
}
|
|
}
|
|
|
|
private bool CheckIfNodeExistInCurrentYarnProject(string nodeName)
|
|
{
|
|
var currentProject = _dialogueRunner.YarnProject;
|
|
if (currentProject == null)
|
|
{
|
|
Debug.LogWarning("当前没有可用的 YarnProject,无法检查节点");
|
|
return false;
|
|
}
|
|
|
|
string[] nodeNames = currentProject.NodeNames;
|
|
if (Array.Exists(nodeNames, item => item == nodeName))
|
|
{
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
Debug.Log($"节点 {nodeName} 不存在!");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
/// <summary>
|
|
/// 返回当前正在执行的节点名与节点 tags;尚未启动 / 异常时返回 (null, 空数组)。
|
|
/// </summary>
|
|
public (string nodeName, IReadOnlyList<string> tags) GetCurrentNodeContext()
|
|
{
|
|
if (string.IsNullOrEmpty(_currentNodeName))
|
|
{
|
|
return (null, Array.Empty<string>());
|
|
}
|
|
|
|
return (_currentNodeName, _currentNodeTags ?? Array.Empty<string>());
|
|
}
|
|
|
|
private void OnNodeStart(string nodeName)
|
|
{
|
|
UpdateCurrentNodeContext(nodeName);
|
|
|
|
if (!SavePointEvaluator.CanAutoSave(out _))
|
|
{
|
|
return;
|
|
}
|
|
|
|
StartCoroutine(SaveRestoreOrchestrator.AutoSaveRoutine(nodeName));
|
|
}
|
|
|
|
private void OnNodeComplete(string nodeName)
|
|
{
|
|
ClearCurrentNodeContext();
|
|
}
|
|
|
|
private void UpdateCurrentNodeContext(string nodeName)
|
|
{
|
|
if (_dialogueRunner == null || _dialogueRunner.Dialogue == null)
|
|
{
|
|
ClearCurrentNodeContext();
|
|
return;
|
|
}
|
|
|
|
_currentNodeName = nodeName;
|
|
|
|
var tagsHeader = _dialogueRunner.Dialogue.GetHeaderValue(nodeName, "tags");
|
|
_currentNodeTags = string.IsNullOrWhiteSpace(tagsHeader)
|
|
? Array.Empty<string>()
|
|
: tagsHeader.Split(Array.Empty<char>(), StringSplitOptions.RemoveEmptyEntries);
|
|
}
|
|
|
|
private void ClearCurrentNodeContext()
|
|
{
|
|
_currentNodeName = null;
|
|
_currentNodeTags = null;
|
|
}
|
|
|
|
#region 推进方式修改
|
|
|
|
public BindProperty<AdvanceMode> advanceMode = new(new AdvanceMode());
|
|
|
|
public void SwitchAutoMode()
|
|
{
|
|
var mode = advanceMode.Value;
|
|
mode.isAuto = !mode.isAuto;
|
|
advanceMode.Value = mode;
|
|
}
|
|
|
|
public void SwitchQuickMode()
|
|
{
|
|
var mode = advanceMode.Value;
|
|
mode.isQuick = !mode.isQuick;
|
|
advanceMode.Value = mode;
|
|
|
|
Time.timeScale = advanceMode.Value.CurrentMode == AdvanceModeEnum.Quick ? 8f : 1f;
|
|
}
|
|
|
|
#endregion
|
|
|
|
private LineSyncToken _lineSyncToken;
|
|
public LineSyncToken lineSyncToken
|
|
{
|
|
get => _lineSyncToken;
|
|
set
|
|
{
|
|
_lineSyncToken = value;
|
|
lineAdvanceInput?.RunLine(value);
|
|
}
|
|
}
|
|
|
|
public bool isInOption;
|
|
|
|
public LineSyncState GetDialogState()
|
|
{
|
|
if (lineSyncToken != null && lineSyncToken.state != LineSyncState.Advanced)
|
|
{
|
|
return lineSyncToken.state;
|
|
}
|
|
else if (isInOption)
|
|
{
|
|
return LineSyncState.InOption;
|
|
}
|
|
else
|
|
{
|
|
return LineSyncState.Default;
|
|
}
|
|
}
|
|
|
|
private void OnOptionShow()
|
|
{
|
|
isInOption = true;
|
|
}
|
|
|
|
private void OnOptionSelected(LineInfo lineInfo)
|
|
{
|
|
isInOption = false;
|
|
}
|
|
}
|
|
|
|
public struct AdvanceMode
|
|
{
|
|
public bool isAuto;
|
|
public bool isQuick;
|
|
|
|
public AdvanceModeEnum CurrentMode
|
|
{
|
|
get
|
|
{
|
|
if (isQuick)
|
|
{
|
|
return AdvanceModeEnum.Quick;
|
|
}
|
|
else if (isAuto)
|
|
{
|
|
return AdvanceModeEnum.Auto;
|
|
}
|
|
else
|
|
{
|
|
return AdvanceModeEnum.Default;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public enum AdvanceModeEnum
|
|
{
|
|
Default,
|
|
Auto,
|
|
Quick
|
|
}
|
|
} |