NLDClient-yudde/ProjectNLD/Assets/Code/Scripts/Gameplay/Guide/GuideManager.cs

567 lines
18 KiB
C#
Raw Normal View History

2024-05-22 16:31:29 +08:00
using cfg.GuideCfg;
2024-05-22 15:41:05 +08:00
using Framework;
2024-10-11 15:46:57 +08:00
using Framework.Condition;
using Gameplay.Area;
using Gameplay.Level;
2024-06-05 14:04:26 +08:00
using Gameplay.Net;
using Gameplay.Skill;
using Gameplay.SubSystems;
2024-06-05 14:04:26 +08:00
using NLDPB;
2024-05-22 15:41:05 +08:00
using PhxhSDK;
2024-06-28 17:34:50 +08:00
using System;
2024-05-22 15:41:05 +08:00
using System.Collections.Generic;
2024-05-29 16:36:30 +08:00
namespace Gameplay.Guide
2024-05-22 15:41:05 +08:00
{
2024-05-22 16:31:29 +08:00
/// <summary>
2024-05-29 16:36:30 +08:00
/// 新手引导管理器
2024-05-22 16:31:29 +08:00
/// </summary>
public class GuideManager : Singlenton<GuideManager>, IInitable, IUpdatable
2024-05-24 19:11:19 +08:00
{
2024-12-04 14:27:43 +08:00
/// <summary>
/// 引导组第一步的id
/// </summary>
private const int GUIDE_GROUP_FIRST_STEP_ID = 1;
/// <summary>
/// 是否初始化数据成功
/// </summary>
private bool isInitDataSuccess;
/// <summary>
/// 特殊pv引导id
/// </summary>
private const int PV_GUIDE_ID = 1000;
#region 兜底强制跳过引导机制
/// <summary>
2024-10-12 13:34:27 +08:00
/// 2秒内点击n次弹出强制跳过引导
/// </summary>
2024-10-12 12:54:52 +08:00
private readonly Queue<DateTime> queueTime = new();
/// <summary>
/// 强制跳过引导检测时间(秒)
/// </summary>
private const double SKIP_GUIDE_CHECK_TIME = 2d;
#endregion
2024-10-11 15:46:57 +08:00
/// <summary>
2024-12-04 14:27:43 +08:00
/// 新手引导配置字典key引导组Value引导组引导步骤列表
2024-10-11 15:46:57 +08:00
/// </summary>
2024-12-04 14:27:43 +08:00
private Dictionary<int, List<DataGuideCfg>> dicGuideCfg;
2024-10-11 15:46:57 +08:00
/// <summary>
2024-12-04 14:27:43 +08:00
/// 未完成的引导组,注册的开始条件记录在这,key:reactionId,value:引导组id
2024-10-11 15:46:57 +08:00
/// </summary>
2024-12-04 14:27:43 +08:00
private Dictionary<int, int> dicReaction;
2024-10-18 18:13:23 +08:00
/// <summary>
2024-12-04 14:27:43 +08:00
/// 当前的引导组
/// </summary>
2024-12-04 14:27:43 +08:00
private GuideGroup curGroup;
2024-05-29 16:36:30 +08:00
/// <summary>
/// 是否引导中
/// </summary>
public bool IsGuiding
2024-05-24 19:11:19 +08:00
{
2024-05-29 16:36:30 +08:00
get { return curGroup != null && curGroup.IsGuiding; }
2024-05-24 19:11:19 +08:00
}
#region 引导特殊控制参数
2024-07-03 14:07:54 +08:00
/// <summary>
/// 控制地板点击
/// </summary>
2024-07-04 16:06:01 +08:00
public bool IsControlFloor = false;
2024-07-01 13:08:37 +08:00
/// <summary>
2024-07-03 19:15:36 +08:00
/// 是否改名
/// </summary>
public bool IsChangeName = true;
/// <summary>
2024-07-01 13:08:37 +08:00
/// 指定地板索引
/// </summary>
public int FloorIndex = -1;
2024-07-04 13:48:56 +08:00
/// <summary>
/// 是否编队引导
/// </summary>
public bool IsEditTeamGuide = false;
/// <summary>
/// 使用技能成功
/// </summary>
public bool IsUseSkillSuccess = true;
2024-10-18 18:13:23 +08:00
/// <summary>
/// 是否播放过PV视频
/// </summary>
public bool IsPlayPVVideo;
/// <summary>
/// 是否响应任意点击
/// </summary>
public bool IsEnableAnyClick = true;
#endregion
2024-07-01 13:08:37 +08:00
public int CurGuideStepId
{
get
{
if (IsGuiding)
return curGroup.CurStep.Cfg.Id;
return 0;
}
}
2024-05-29 16:36:30 +08:00
public void Init()
2024-05-24 19:11:19 +08:00
{
2024-12-04 14:27:43 +08:00
isInitDataSuccess = false;
InputManager.Instance.OnAnyClick += OnAnyClick;
2024-05-29 16:36:30 +08:00
EventManager.Instance.Register(EventManager.EventName.AllConfigLoad, InitData);
}
2024-05-29 13:04:51 +08:00
public void Update(float deltaTime)
{
if (!Instance.IsGuiding)
return;
if (!LevelManager.Instance.IsInLevel)
return;
if (null == LevelManager.Instance.CurrentLevel)
return;
if (!LevelManager.Instance.CurrentLevel.isInBattle)
return;
if (!LevelManager.Instance.CurrentLevel.IsPause())
return;
AreaManager.instance.LogicUpdate(deltaTime);
SkillManager.instance.playerSkillManager.LogicUpdate(deltaTime);
}
2024-05-29 16:36:30 +08:00
public void Release()
{
EventManager.Instance.Unregister(EventManager.EventName.AllConfigLoad, InitData);
if (null != InputManager.Instance)
InputManager.Instance.OnAnyClick -= OnAnyClick;
2024-05-24 19:11:19 +08:00
}
2024-05-29 16:36:30 +08:00
/// <summary>
2024-12-04 14:27:43 +08:00
/// 启动引导
2024-05-29 16:36:30 +08:00
/// </summary>
2024-12-04 14:27:43 +08:00
public void StartGuide()
2024-05-24 19:11:19 +08:00
{
2024-06-05 13:13:11 +08:00
#if GUIDE
2024-12-04 14:27:43 +08:00
if (!isInitDataSuccess)
2024-10-17 12:33:34 +08:00
{
2024-12-04 14:27:43 +08:00
DebugUtil.LogError("启动引导失败,数据没有初始化成功");
return;
}
2024-10-11 19:22:18 +08:00
2024-12-04 14:27:43 +08:00
foreach (KeyValuePair<int, List<DataGuideCfg>> kv in dicGuideCfg)
{
if (CheckGuideGroupComplete(kv.Key)) // 已经完成的引导跳过
continue;
2024-10-11 18:21:20 +08:00
2024-12-04 14:27:43 +08:00
if (kv.Value.Count <= 0)
{
DebugUtil.LogError($"引导组id:{kv.Key}没有引导步骤数据");
continue;
}
2024-12-04 14:27:43 +08:00
DataGuideCfg cfg = kv.Value[0];
if (!IsFirstStep(cfg))
{
DebugUtil.LogError($"引导组id:{kv.Key}的第一个引导数据不是起始步骤引导id{cfg.Id}");
continue;
}
2024-10-17 12:33:34 +08:00
2024-12-04 14:27:43 +08:00
if (null == dicReaction)
dicReaction = new();
2024-10-10 13:59:48 +08:00
2024-12-04 14:27:43 +08:00
dicReaction[ConditionReactor.Instance.AddReaction(cfg.BeginCondition, OnBeginGuideByCondition)] = cfg.GroupId;
2024-10-11 17:17:54 +08:00
}
2024-06-05 13:13:11 +08:00
#endif
2024-05-24 19:11:19 +08:00
}
2024-05-24 15:07:50 +08:00
2024-05-29 16:36:30 +08:00
/// <summary>
/// 完成指定引导步骤
/// </summary>
/// <param name="step"></param>
public void CompleteStep(GuideStepBase step)
{
if (null == curGroup)
return;
2024-05-29 13:04:51 +08:00
2024-05-29 16:36:30 +08:00
if (step != curGroup.CurStep)
{
DebugUtil.LogError("要完成的引导步骤不是当前步骤");
EndGuide(true);
2024-05-29 13:04:51 +08:00
2024-05-29 16:36:30 +08:00
return;
}
2024-05-29 13:04:51 +08:00
NetHelper.SaveGuideProgress((uint)curGroup.CurStep.Cfg.Id); // 完成引导步骤,保存服务器
2024-09-29 14:38:21 +08:00
DebugUtil.Log($"<color=#00FA9A>完成引导步骤服务器保存引导id:{curGroup.CurStep.Cfg.Id}</color>");
2024-10-12 17:13:17 +08:00
queueTime.Clear();
2024-05-29 16:36:30 +08:00
if (curGroup.IsComplete)
{
DebugUtil.Log($"<color=#00FA9A>完成引导组组id:{curGroup.GroupId}</color>");
2024-05-29 16:36:30 +08:00
int nextGroupId = curGroup.NextGroupId;
2024-12-04 14:27:43 +08:00
if (dicGuideCfg.TryGetValue(nextGroupId, out List<DataGuideCfg> listCfg))
2024-05-29 16:36:30 +08:00
{
2024-12-04 14:27:43 +08:00
curGroup = new(nextGroupId, listCfg, true);
2024-05-29 16:36:30 +08:00
curGroup.BeginGuide();
}
else
EndGuide(false);
}
else
{
if (curGroup.CurStep.Cfg.IsComplete)
DebugUtil.Log($"<color=#00FA9A>提前完成引导组组id:{curGroup.GroupId}</color>");
2024-05-29 16:36:30 +08:00
curGroup.BeginNextStep();
}
2024-05-29 16:36:30 +08:00
}
2024-05-22 16:31:29 +08:00
2024-05-29 16:36:30 +08:00
/// <summary>
/// 结束引导
/// </summary>
2024-06-06 14:41:02 +08:00
public void EndGuide(bool isReEnterMain)
2024-05-22 16:31:29 +08:00
{
2024-05-29 16:36:30 +08:00
if (IsGuiding)
curGroup.EndGuide();
2024-05-22 16:31:29 +08:00
RecoverState();
2024-05-29 16:36:30 +08:00
curGroup = null;
UIManager.Instance.CloseWindow(UINameConst.UI_Guide);
UIManager.Instance.CloseWindow(UINameConst.UI_GuideTip);
2024-05-22 15:41:05 +08:00
2024-05-29 16:36:30 +08:00
if (isReEnterMain)
{
if (LevelManager.Instance.IsInLevel)
{
LevelManager.Instance.ExitLevelChangeMainFunc = () =>
{
GameStateManager.Instance.ChangeState(new GameStateMainScene());
return false;
};
LevelManager.Instance.TryExitLevel(false, null, true);
}
else
GameStateManager.Instance.ChangeState(new GameStateMainScene());
}
2024-05-22 16:31:29 +08:00
}
/// <summary>
2024-10-11 15:46:57 +08:00
/// 跳过当前引导组
/// </summary>
/// <param name="isReEnterMain"></param>
2024-10-11 15:46:57 +08:00
public void SkipCurGuideGroup()
{
2024-10-11 15:46:57 +08:00
if (null == curGroup)
return;
2024-12-04 14:27:43 +08:00
if (!dicGuideCfg.TryGetValue(curGroup.GroupId, out List<DataGuideCfg> listCfg))
2024-10-11 15:46:57 +08:00
{
DebugUtil.LogError("要完成的引导组不存在");
return;
}
2024-12-04 14:27:43 +08:00
NetHelper.SaveGuideProgress((uint)listCfg[^1].Id); // 跳过引导步骤,保存服务器
DebugUtil.Log($"<color=#00FA9A>跳过引导组服务器保存引导id:{listCfg[^1].Id}</color>");
2024-10-11 17:17:54 +08:00
EndGuide(false);
2024-12-04 14:27:43 +08:00
StartGuide();
}
2024-10-12 12:46:58 +08:00
/// <summary>
/// 跳过所有引导
/// </summary>
public async void SkipAllGuide(bool isEditor = false)
2024-10-12 12:46:58 +08:00
{
DebugUtil.Log("跳过所有引导");
GuideConfig guideConfig = TableManager.Instance.Tables.GuideConfig;
DataGuideCfg cfg = guideConfig.DataList[^1];
NetHelper.SaveGuideProgress((uint)cfg.Id);
if (!isEditor &&
!IsPlayPVVideo &&
2024-10-18 18:13:23 +08:00
null != curGroup &&
curGroup.CurStep.Cfg.Id <= PV_GUIDE_ID) // 特殊处理 播放过pv视频则不播放没播放过则播放
2024-10-18 18:13:23 +08:00
{
EndGuide(false);
if (LevelManager.Instance.IsInLevel)
{
LevelManager.Instance.ExitLevelChangeMainFunc = () =>
{
GameStateManager.Instance.ChangeState(new GameStateMainScene());
return false;
};
if (!LevelManager.Instance.CurrLevel.IsStory)
LevelManager.Instance.TryExitLevel(false, null, true);
}
await UI_PVAnimaPlayController.Open("Assets/Video/LevelIntro/LevelIntro_PV.mp4", () =>
{
if (!LevelManager.Instance.IsInLevel)
{
GameStateManager.Instance.ChangeState(new GameStateMainScene());
return;
}
if (LevelManager.Instance.CurrLevel.IsStory)
LevelManager.Instance.TryExitLevel(false, null, true);
else
LevelManager.Instance.ExitLevelDirectly();
});
2024-10-18 18:13:23 +08:00
}
else
EndGuide(true);
2024-10-12 12:46:58 +08:00
}
/// <summary>
/// 显示跳过所有引导提示
/// </summary>
public void ShowSkipAllGuide()
{
2024-10-12 13:34:27 +08:00
UITipsManager.ShowConfirmTwo(CommonUtils.GetLocalizeText("Guide_SkipAllTitle"), // 脱离卡死
CommonUtils.GetLocalizeText("Guide_SkipAllContent"), // 是否强制跳过新手引导?(选择【跳过】便不再触发新手引导)
CommonUtils.GetLocalizeText("Skip"), // 跳过
CommonUtils.GetLocalizeText("Not"), // 否
() => { SkipAllGuide(); });
2024-10-12 12:46:58 +08:00
}
2024-10-14 12:20:28 +08:00
/// <summary>
/// 判断引导步骤是否完成
/// </summary>
/// <returns></returns>
public bool CheckComplete(int guideId)
{
2024-12-04 14:27:43 +08:00
int curCompleteStepId = (int)Actor.Instance.Logic.GetCount((uint)LogicID.NewGuideProgress);
2024-10-14 12:20:28 +08:00
2024-12-04 14:27:43 +08:00
return curCompleteStepId >= guideId;
2024-10-14 12:20:28 +08:00
}
2024-12-04 14:27:43 +08:00
#region 私有方法
2024-05-29 16:36:30 +08:00
/// <summary>
/// 初始化数据
/// </summary>
private void InitData()
2024-12-04 14:27:43 +08:00
{
2024-05-29 16:36:30 +08:00
dicGuideCfg = new();
foreach (DataGuideCfg cfg in TableManager.Instance.Tables.GuideConfig.DataList)
2024-05-22 16:31:29 +08:00
{
2024-12-04 14:27:43 +08:00
if (!dicGuideCfg.TryGetValue(cfg.GroupId, out List<DataGuideCfg> listCfg))
2024-05-29 16:36:30 +08:00
{
2024-12-04 14:27:43 +08:00
listCfg = new List<DataGuideCfg>();
dicGuideCfg[cfg.GroupId] = listCfg;
2024-05-22 16:31:29 +08:00
}
2024-12-04 14:27:43 +08:00
if(cfg.NextId<=cfg.Id)
throw new Exception($"引导组id:{cfg.GroupId},的{cfg.Id}引导的下一步id配置错误,下一步id小于等于当前id会导致死循环");
listCfg.Add(cfg);
2024-05-29 16:36:30 +08:00
}
2024-05-22 16:31:29 +08:00
2024-05-29 16:36:30 +08:00
#region 检验每个引导组的步骤顺序是否正常
2024-12-04 14:27:43 +08:00
foreach (List<DataGuideCfg> listCfg in dicGuideCfg.Values)
2024-05-29 16:36:30 +08:00
{
DataGuideCfg preCfg = null;
2024-12-04 14:27:43 +08:00
foreach (DataGuideCfg cfg in listCfg)
2024-05-22 16:31:29 +08:00
{
2024-05-29 16:36:30 +08:00
if (null == preCfg)
{
preCfg = cfg;
continue;
}
if (preCfg.NextId != cfg.Id)
2024-12-04 14:27:43 +08:00
throw new Exception($"新手引导配置出错组id:{preCfg.GroupId}, 步骤id:{preCfg.Id}的下一步步骤id{preCfg.NextId},当前配置是{cfg.Id}");
2024-05-29 16:36:30 +08:00
else
preCfg = cfg;
2024-05-22 16:31:29 +08:00
}
}
2024-05-29 16:36:30 +08:00
#endregion
2024-12-04 14:27:43 +08:00
isInitDataSuccess = true;
}
/// <summary>
/// 检查引导组是否完成
/// </summary>
/// <returns></returns>
private bool CheckGuideGroupComplete(int guideGroupId)
{
// 通过服务器数据判断该组引导是否完成
return false;
2024-05-22 16:31:29 +08:00
}
2024-05-29 16:36:30 +08:00
/// <summary>
/// 是否是引导组的第一步
/// </summary>
/// <returns></returns>
private bool IsFirstStep(DataGuideCfg dataGuideCfg)
{
2024-12-04 14:27:43 +08:00
return GUIDE_GROUP_FIRST_STEP_ID == dataGuideCfg.Id;
2024-05-29 16:36:30 +08:00
}
/// <summary>
/// 获取应该引导的引导组id
/// </summary>
/// <returns></returns>
private int GetGuideGroupId(int completeStepId)
{
2024-12-04 13:22:49 +08:00
return 0;
/*
2024-08-02 15:55:10 +08:00
GuideConfig guideConfig = TableManager.Instance.Tables.GuideConfig;
if (guideConfig.DataList.Count <= 0)
return 0;
if (completeStepId >= guideConfig.DataList[^1].Id) // 大于等于最后一步的id
2024-08-01 15:39:44 +08:00
return 0; // 跳过引导
2024-10-22 15:18:46 +08:00
DataGuideCfg completeCfg = null;
if (0 != completeStepId && 1 != completeStepId)
2024-10-22 15:18:46 +08:00
completeCfg = guideConfig.Get(completeStepId); // 已经完成的引导步骤配置
if (null == completeCfg) // 没有获取到不是存在的配置id可能修改过id
{
foreach (DataGuideCfg guideCfg in TableManager.Instance.Tables.GuideConfig.DataList)
{
if (guideCfg.Id >= completeStepId)
{
completeCfg = guideCfg;
break;
}
}
}
bool isGroupComplete = false; // 当前步骤所在引导组是否完成
DataGuideCfg nextCfg = guideConfig.Get(completeCfg.NextId);
2024-08-01 14:49:39 +08:00
if (null == nextCfg)
return 0; // 没有下一步了
else if (nextCfg.GroupId != completeCfg.GroupId) // 该步骤是该组最后一步,表示整组完成
isGroupComplete = true;
else
{
foreach (DataGuideCfg cfg in TableManager.Instance.Tables.GuideConfig.DataList)
{
if (cfg.GroupId != completeCfg.GroupId)
continue;
if (cfg.IsComplete && cfg.Id <= completeCfg.Id)
{
DebugUtil.Log($"<color=#00FA9A>引导步骤{completeStepId}所在组{cfg.GroupId}的{cfg.Id}步骤完成,该组完成</color>");
isGroupComplete = true;
break;
}
}
}
if (isGroupComplete) // 该组完成,取下一组
{
DataGuideCfg dataGuideCfg = guideConfig.Get(completeCfg.NextId);
while (null != dataGuideCfg)
{
if (dataGuideCfg.GroupId == completeCfg.GroupId)
{
if (0 == dataGuideCfg.NextId) // 下一组id为0表示最后一组
return 0;
dataGuideCfg = guideConfig.Get(dataGuideCfg.NextId);
continue;
}
return dataGuideCfg.GroupId;
}
return 0;
}
else
2024-08-01 14:49:39 +08:00
return completeCfg.GroupId; // 该组没有完成,重来
2024-12-04 13:22:49 +08:00
*/
}
/// <summary>
/// 设置引导状态
/// </summary>
private void SetGuideState()
{
UIManager.Instance.IsEnableBack = false;
}
/// <summary>
/// 还原状态
/// </summary>
private void RecoverState()
{
UIManager.Instance.IsEnableBack = true;
}
2024-10-11 15:46:57 +08:00
/// <summary>
2024-12-04 14:27:43 +08:00
/// 通过条件触发开始引导
2024-10-11 15:46:57 +08:00
/// </summary>
2024-12-04 14:27:43 +08:00
private void OnBeginGuideByCondition(bool conditionResult, object callBackParam, int reactionID)
2024-10-11 15:46:57 +08:00
{
if (!conditionResult)
return;
2024-12-04 14:27:43 +08:00
if (!dicReaction.TryGetValue(reactionID, out int guideGroupId))
2024-10-11 15:46:57 +08:00
return;
2024-12-04 14:27:43 +08:00
ConditionReactor.Instance.RemoveReaction(reactionID);
dicReaction.Remove(reactionID);
2024-10-11 15:46:57 +08:00
try
{
2024-12-04 14:27:43 +08:00
if (!dicGuideCfg.TryGetValue(guideGroupId, out List<DataGuideCfg> listCfg))
return;
curGroup = new GuideGroup(guideGroupId, listCfg);
2024-10-11 15:46:57 +08:00
SetGuideState();
curGroup.BeginGuide();
}
catch (Exception e)
{
DebugUtil.LogError($"跳过引导,错误信息:{e}");
RecoverState();
}
}
/// <summary>
/// 引导过程中的任意点击事件
/// </summary>
private void OnAnyClick()
{
if (!IsGuiding)
return;
2024-10-18 18:13:23 +08:00
if (!IsEnableAnyClick)
return;
if (LoadingManager.Instance.IsRuning)
return;
DateTime curTime = CommonUtils.GetCurTime(CommonUtils.E_TimeType.Local);
queueTime.Enqueue(curTime);
2024-10-12 17:13:17 +08:00
while (queueTime.TryPeek(out DateTime firstTime))
{
TimeSpan timeSpan = curTime - firstTime;
if (timeSpan.TotalSeconds < SKIP_GUIDE_CHECK_TIME)
break;
queueTime.Dequeue();
2024-10-12 17:13:17 +08:00
}
2024-10-12 12:53:49 +08:00
if (TableManager.Instance.Tables.GlobalConfig.SkipGuideClickCount <= queueTime.Count)
{
2024-10-12 12:53:49 +08:00
DebugUtil.Log($"{SKIP_GUIDE_CHECK_TIME}秒内连续点击{TableManager.Instance.Tables.GlobalConfig.SkipGuideClickCount}次,弹出强制跳过新手引导提示");
queueTime.Clear();
2024-10-12 12:46:58 +08:00
ShowSkipAllGuide();
}
}
2024-12-04 14:27:43 +08:00
#endregion
2024-05-22 15:41:05 +08:00
}
2024-05-24 19:11:19 +08:00
}