NLDClient-yudde/ProjectNLD/Assets/Code/Scripts/Gameplay/Dialogue/DialogueManager.cs

267 lines
8.5 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using cfg.DialogueCfg;
using Cysharp.Threading.Tasks;
using Framework;
using Gameplay;
using PhxhSDK;
using System;
using System.Collections.Generic;
using System.Linq;
using Random = UnityEngine.Random;
/// <summary>
/// 台词管理器
/// </summary>
public class DialogueManager : Singlenton<DialogueManager>, IInitable
{
/// <summary>
/// 台词配置数据,key:角色id, value:台词配置数据
/// </summary>
private Dictionary<int, List<DataDialogueCfg>> dicDialogueData;
/// <summary>
/// 角色台词对应的权重字典,key:角色id,value: subKey:台词id,subValue:台词权重
/// </summary>
private Dictionary<int, Dictionary<int, float>> dicDialogueWeight;
/// <summary>
/// 是否初始化
/// </summary>
private bool isInit;
#region 临时数据
/// <summary>
/// 符合条件的台词数据
/// </summary>
private readonly List<DataDialogueCfg> listDialogueData = new();
private readonly List<float> listDialogueWeight = new();
#endregion
public void Init()
{
isInit = false;
dicDialogueData = new();
dicDialogueWeight = new();
EventManager.Instance.Register(EventManager.EventName.AllConfigLoad, InitData);
}
public void Release()
{
EventManager.Instance.Unregister(EventManager.EventName.AllConfigLoad, InitData);
isInit = false;
dicDialogueData.Clear();
dicDialogueData = null;
}
/// <summary>
/// 播放台词
/// </summary>
/// <param name="roleId"></param>
/// <param name="dialogueType"></param>
public async UniTask<Audio> PlayDiaogue(int roleId, E_DialogueType dialogueType, Action<string> callback = null)
{
#region 校验
if (!isInit)
{
DebugUtil.LogError("数据未初始化");
return null;
}
#endregion
#region 获取需要播放的台词,根据优先级,台词类型,条件
if (!dicDialogueData.TryGetValue(roleId, out List<DataDialogueCfg> listCfg))
{
DebugUtil.LogError("没有该角色的台词数据");
return null;
}
listDialogueData.Clear();
int minPriority = int.MaxValue; // 值越小优先级越高
foreach (DataDialogueCfg cfg in listCfg)
{
if (cfg.Priority > minPriority) // 优先级不足,排除
continue;
if (!cfg.DialogueType.Contains(dialogueType)) // 不是所需类型,排除
continue;
if (!IsCheckValid(roleId, cfg)) // 条件不满足,排除
continue;
if (cfg.Priority < minPriority)
{
minPriority = cfg.Priority;
listDialogueData.Clear();
}
listDialogueData.Add(cfg);
}
#endregion
if (listDialogueData.Count <= 0)
{
DebugUtil.LogError("没有满足条件要播放的台词");
return null;
}
#region 根据权重随机台词
DataDialogueCfg playCfg;
listDialogueWeight.Clear();
if (dicDialogueWeight.TryGetValue(roleId, out Dictionary<int, float> dicWeight))
{
foreach (DataDialogueCfg cfg in listDialogueData)
{
if (dicWeight.TryGetValue(cfg.DialogueId, out float weight))
listDialogueWeight.Add(weight);
else
listDialogueWeight.Add(1f);
}
playCfg = listDialogueData[RandomIndexByWeight()];
}
else
playCfg = listDialogueData[Random.Range(0, listDialogueData.Count)];
#endregion
#region 设置其他的权重
if (dicWeight != null)
{
foreach (DataDialogueCfg cfg in listDialogueData)
{
if (dicWeight.TryGetValue(cfg.DialogueId, out float weight) && weight <= 0f)
dicWeight[cfg.DialogueId] = 0.3f; // TODO 需要全局配置
else
dicWeight[cfg.DialogueId] = 1f;
}
dicWeight[playCfg.DialogueId] = 0f; // 当前使用的权重置为0
}
#endregion
DebugUtil.Log($"播放台词{playCfg.DialogueId}, 优先级{playCfg.Priority}"); // 测试Log
int audioId = await AudioManager.Instance.PlayAudio(playCfg.Voice);
callback?.Invoke(CommonUtils.GetLocalizeText(playCfg.TextLocal));
return AudioManager.Instance.GetAudioByID(AudioType.SOUND, audioId);
}
/// <summary>
/// 检查台词是否有效
/// </summary>
/// <returns></returns>
private bool IsCheckValid(int roleId, DataDialogueCfg dataDialogueCfg)
{
foreach (E_DialogueType dialogueType in dataDialogueCfg.DialogueType)
{
if (!IsCheckValidByOne(roleId, dialogueType))
return false;
}
return true;
}
/// <summary>
/// 检查个单个条件是否有效
/// </summary>
/// <param name="roleId"></param>
/// <param name="dataDialogueCfg"></param>
/// <returns></returns>
private bool IsCheckValidByOne(int roleId, E_DialogueType dialogueType)
{
switch (dialogueType)
{
case E_DialogueType.Morning: // 上午
{
DateTime dateTime = CommonUtils.GetCurTime(CommonUtils.E_TimeType.Server);
return dateTime.Hour >= 6 && dateTime.Hour < 16;
}
case E_DialogueType.Afternoon:
{
DateTime dateTime = CommonUtils.GetCurTime(CommonUtils.E_TimeType.Server);
return dateTime.Hour >= 16 && dateTime.Hour < 21;
}
case E_DialogueType.Evening:
{
DateTime dateTime = CommonUtils.GetCurTime(CommonUtils.E_TimeType.Server);
return dateTime.Hour >= 21 && dateTime.Hour < 23;
}
case E_DialogueType.Midnight:
{
DateTime dateTime = CommonUtils.GetCurTime(CommonUtils.E_TimeType.Server);
return dateTime.Hour < 6 || dateTime.Hour >= 23;
}
case E_DialogueType.PlayerBirthday:
case E_DialogueType.KanbanbanBirthday:
case E_DialogueType.Fetters:
{
DebugUtil.LogWarning("记录一下,等待处理");
return false; // Todo
}
case E_DialogueType.Awaken:
{
CharacterDataInfo characterDataInfo = CharacterDataInfoManager.Instance.GetCharacterInfo((uint)roleId);
if (characterDataInfo == null)
{
DebugUtil.LogError("未获取到角色");
return false;
}
return characterDataInfo.IsMaxAwake(); // 是否满觉醒
}
default: // 其余条件默认满足
return true;
}
}
/// <summary>
/// 根据权重随机一个索引
/// </summary>
/// <returns></returns>
private int RandomIndexByWeight()
{
float totalWeight = listDialogueWeight.Sum();
float randomWeight = Random.Range(0, 1f) * totalWeight;
totalWeight = 0f;
for (int i = 0; i < listDialogueWeight.Count; ++i)
{
totalWeight += listDialogueWeight[i];
if (randomWeight <= totalWeight)
return i;
}
return 0;
}
/// <summary>
/// 初始化数据
/// </summary>
private void InitData()
{
if (isInit)
return;
foreach (DataDialogueCfg data in TableManager.Instance.Tables.DialogueConfig.DataList)
{
#region 构造台词数据字典
if (!dicDialogueData.TryGetValue(data.Id, out List<DataDialogueCfg> listCfg))
{
listCfg = new List<DataDialogueCfg>();
dicDialogueData[data.Id] = listCfg;
}
listCfg.Add(data);
#endregion
#region 构造台词权重字典
if (!dicDialogueWeight.TryGetValue(data.Id, out Dictionary<int, float> dicWeight))
{
dicWeight = new Dictionary<int, float>();
dicDialogueWeight[data.Id] = dicWeight;
}
dicWeight[data.DialogueId] = 1f; // 所有台词初始权重为1f
#endregion
}
isInit = true;
}
}