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

334 lines
11 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>
/// 台词播放记录数据
/// </summary>
private class DialoguePlayData
{
/// <summary>
/// 台词对应次数字典
/// </summary>
public Dictionary<int, int> DicCount;
/// <summary>
/// 上一次日期
/// </summary>
public DateTime LastTime;
public DialoguePlayData()
{
DicCount = new();
}
public void SetNewTime(DateTime dateTime)
{
LastTime = dateTime;
DicCount.Clear();
}
}
/// <summary>
/// 台词播放记录数据key
/// </summary>
private const string DIALOGUE_PLAY_DATA = "Dialogue_play_data";
/// <summary>
/// 台词配置数据key角色id, value台词配置数据
/// </summary>
private Dictionary<int, List<DataDialogueCfg>> dicDialogueData;
/// <summary>
/// 角色台词对应的权重字典key角色idvalue: subKey台词idsubValue台词权重
/// </summary>
private Dictionary<int, Dictionary<int, float>> dicDialogueWeight;
/// <summary>
/// 台词播放记录数据
/// </summary>
private DialoguePlayData dialoguePlayData;
/// <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();
dialoguePlayData = StorageMgr.Instance.GetStorage<DialoguePlayData>(DIALOGUE_PLAY_DATA);
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>
/// <param name="callback"></param>
/// <returns></returns>
public async UniTask<Audio> PlayDiaogue(int roleId, E_DialogueType dialogueType, Action<string> callback = null)
{
#region 校验
if (!isInit)
{
DebugUtil.LogError("数据未初始化");
return null;
}
#endregion
#region 每日重置次数,后续应该通过跨天事件触发
DateTime curTime = CommonUtils.GetCurTime(CommonUtils.E_TimeType.Server);
if (curTime.Hour > TableManager.Instance.Tables.GlobalConfig.DailyChangeHour && // 超过5点
curTime.Day != dialoguePlayData.LastTime.Day) // 不是同一天
{
dialoguePlayData.SetNewTime(curTime);
}
#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 (cfg.DayPlayCount > 0 && // 0表示无限次
dialoguePlayData.DicCount.TryGetValue(cfg.DialogueId, out int count) &&
count >= cfg.DayPlayCount) // 超过播放次数
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
#region 记录播放次数
if (playCfg.DayPlayCount > 0)
{
dialoguePlayData.DicCount.TryGetValue(playCfg.DialogueId, out int count);
dialoguePlayData.DicCount[playCfg.DialogueId] = count + 1;
}
#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:
{
DateTime kanbanbanBirth = new(2024, 4, 29); // 测试玩家生日
return CommonUtils.IsBirth(kanbanbanBirth);
}
case E_DialogueType.KanbanbanBirthday:
{
DateTime kanbanbanBirth = new(2024, 4, 29); // 测试看板娘生日
return CommonUtils.IsBirth(kanbanbanBirth);
}
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;
}
}