using cfg.GuideCfg;
using Framework;
using Framework.Condition;
using Gameplay.Area;
using Gameplay.Level;
using Gameplay.Net;
using Gameplay.Skill;
using NLDPB;
using PhxhSDK;
using System;
using System.Collections.Generic;
using UnityEngine;
namespace Gameplay.Guide
{
///
/// 新手引导管理器
///
public class GuideManager : Singlenton, IInitable, IUpdatable
{
#region 兜底强制跳过引导机制
///
/// 2秒内点击n次,弹出强制跳过引导
///
private readonly Queue queueTime = new();
///
/// 强制跳过引导检测时间(秒)
///
private const double SKIP_GUIDE_CHECK_TIME = 2d;
#endregion
///
/// 新手引导配置字典,key:引导组,Value:引导步骤配置链表
///
private Dictionary> dicGuideCfg;
///
/// 当前的引导组
///
private GuideGroup curGroup;
///
/// 触发条件id
///
private int reactionID = ConditionReactor.INVALID_ALLOC_ID;
///
/// 当前完成的引导id,防止服务器没保存成功
///
private int curCompleteId = 0;
///
/// 特殊pv引导id
///
private int pvGuideID = 1000;
///
/// 是否引导中
///
public bool IsGuiding
{
get { return curGroup != null && curGroup.IsGuiding; }
}
///
/// 控制地板点击
///
public bool IsControlFloor = false;
///
/// 是否改名
///
public bool IsChangeName = true;
///
/// 指定地板索引
///
public int FloorIndex = -1;
///
/// 是否编队引导
///
public bool IsEditTeamGuide = false;
///
/// 使用技能成功
///
public bool IsUseSkillSuccess = true;
///
/// 是否播放过PV视频
///
public bool IsPlayPVVideo;
///
/// 是否响应任意点击
///
public bool IsEnableAnyClick = true;
public void Init()
{
InputManager.Instance.OnAnyClick += OnAnyClick;
EventManager.Instance.Register(EventManager.EventName.AllConfigLoad, InitData);
}
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);
}
public void Release()
{
EventManager.Instance.Unregister(EventManager.EventName.AllConfigLoad, InitData);
if (null != InputManager.Instance)
InputManager.Instance.OnAnyClick -= OnAnyClick;
}
///
/// 开始引导
///
public void BeginGuide(int completeStepId = 0)
{
#if GUIDE
try
{
if (IsGuiding)
return;
//if (ConditionReactor.INVALID_ALLOC_ID != reactionID)
//ConditionReactor.Instance.RemoveReaction(reactionID);
if (0 == completeStepId)
{
if (0 == curCompleteId)
curCompleteId = (int)Actor.Instance.Logic.GetCount((uint)LogicID.NewGuideProgress);
}
else
curCompleteId = completeStepId;
int groupId = GetGuideGroupId(curCompleteId);
if (0 == groupId)
return;
if (!dicGuideCfg.TryGetValue(groupId, out LinkedList linkCfg))
return;
curGroup = new GuideGroup(groupId, linkCfg);
if (curGroup.CurStep.Cfg.BeginCondition.Length <= 0)
{
OnBeginGuide(true, null, ConditionReactor.INVALID_ALLOC_ID);
return;
}
//reactionID = ConditionReactor.Instance.AddReaction(curGroup.CurStep.Cfg.BeginCondition, OnBeginGuide);
}
catch (Exception e)
{
DebugUtil.LogError($"引导启动异常:{e}");
}
#endif
}
///
/// 完成指定引导步骤
///
///
public void CompleteStep(GuideStepBase step)
{
if (null == curGroup)
return;
if (step != curGroup.CurStep)
{
DebugUtil.LogError("要完成的引导步骤不是当前步骤");
EndGuide(true);
return;
}
curCompleteId = curGroup.CurStep.Cfg.Id;
NetHelper.SaveGuideProgress((uint)curGroup.CurStep.Cfg.Id); // 完成引导步骤,保存服务器
DebugUtil.Log($"完成引导步骤,服务器保存引导id:{curGroup.CurStep.Cfg.Id}");
queueTime.Clear();
if (curGroup.IsComplete)
{
DebugUtil.Log($"完成引导组,组id:{curGroup.GroupId}");
int nextGroupId = curGroup.NextGroupId;
if (dicGuideCfg.TryGetValue(nextGroupId, out LinkedList linkCfg))
{
curGroup = new(nextGroupId, linkCfg, true);
curGroup.BeginGuide();
}
else
EndGuide(false);
}
else
{
if (curGroup.CurStep.Cfg.IsComplete)
DebugUtil.Log($"提前完成引导组,组id:{curGroup.GroupId}");
curGroup.BeginNextStep();
}
}
///
/// 回到指定步骤
///
///
public void ReturnStep(int stepId)
{
curGroup.EndGuide();
curGroup.BeginGuideById(stepId);
}
///
/// 结束引导
///
public void EndGuide(bool isReEnterMain)
{
if (IsGuiding)
curGroup.EndGuide();
RecoverState();
curGroup = null;
UIManager.Instance.CloseWindow(UINameConst.UI_Guide);
UIManager.Instance.CloseWindow(UINameConst.UI_GuideTip);
if (isReEnterMain)
{
if (LevelManager.Instance.IsInLevel)
LevelManager.Instance.TryExitLevel(false, null, true);
else
GameStateManager.Instance.ChangeState(new GameStateMainScene());
}
}
///
/// 跳过当前引导组
///
///
public void SkipCurGuideGroup()
{
if (null == curGroup)
return;
if (!dicGuideCfg.TryGetValue(curGroup.GroupId, out LinkedList linkedCfg))
{
DebugUtil.LogError("要完成的引导组不存在");
return;
}
curCompleteId = linkedCfg.Last.Value.Id;
NetHelper.SaveGuideProgress((uint)linkedCfg.Last.Value.Id); // 跳过引导步骤,保存服务器
DebugUtil.Log($"跳过引导组,服务器保存引导id:{linkedCfg.Last.Value.Id}");
EndGuide(false);
BeginGuide(linkedCfg.Last.Value.Id);
}
///
/// 跳过所有引导
///
public async void SkipAllGuide(bool isEditor = false)
{
DebugUtil.Log("跳过所有引导");
GuideConfig guideConfig = TableManager.Instance.Tables.GuideConfig;
DataGuideCfg cfg = guideConfig.DataList[^1];
curCompleteId = cfg.Id;
NetHelper.SaveGuideProgress((uint)cfg.Id);
if (!isEditor &&
!IsPlayPVVideo &&
null != curGroup &&
curGroup.CurStep.Cfg.Id <= pvGuideID) // 特殊处理 播放过pv视频则不播放,没播放过则播放
{
EndGuide(false);
await UI_PVAnimaPlayController.Open("Assets/Video/LevelIntro/LevelIntro_PV.mp4", () => { EndGuide(true); });
}
else
EndGuide(true);
}
///
/// 显示跳过所有引导提示
///
public void ShowSkipAllGuide()
{
UITipsManager.ShowConfirmTwo(CommonUtils.GetLocalizeText("Guide_SkipAllTitle"), // 脱离卡死
CommonUtils.GetLocalizeText("Guide_SkipAllContent"), // 是否强制跳过新手引导?(选择【跳过】便不再触发新手引导)
CommonUtils.GetLocalizeText("Skip"), // 跳过
CommonUtils.GetLocalizeText("Not"), // 否
() => { SkipAllGuide(); });
}
///
/// 判断引导步骤是否完成
///
///
public bool CheckComplete(int guideId)
{
if (0 == curCompleteId)
{
int curCompleteStepId = (int)Actor.Instance.Logic.GetCount((uint)LogicID.NewGuideProgress);
return curCompleteStepId >= guideId;
}
return curCompleteId >= guideId;
}
///
/// 初始化数据
///
private void InitData()
{
dicGuideCfg = new();
foreach (DataGuideCfg cfg in TableManager.Instance.Tables.GuideConfig.DataList)
{
if (dicGuideCfg.ContainsKey(cfg.GroupId) && !IsFirstStep(cfg))
continue;
DataGuideCfg addCfg = cfg; // 记录要添加进链表的引导步骤配置
int groudId = cfg.GroupId;
LinkedList linkCfg = new();
dicGuideCfg[groudId] = linkCfg;
while (null != addCfg && addCfg.GroupId == groudId)
{
linkCfg.AddLast(addCfg);
if (0 == addCfg.NextId)
addCfg = null;
else if (addCfg.Id >= addCfg.NextId)
throw new Exception($"{addCfg.Id}引导的下一步id配置错误,下一步id小于等于当前id可能导致死循环");
else
addCfg = TableManager.Instance.Tables.GuideConfig.Get(addCfg.NextId);
}
}
#region 检验每个引导组的步骤顺序是否正常
foreach (LinkedList linkCfg in dicGuideCfg.Values)
{
DataGuideCfg preCfg = null;
foreach (DataGuideCfg cfg in linkCfg)
{
if (null == preCfg)
{
preCfg = cfg;
continue;
}
if (preCfg.NextId != cfg.Id)
{
Debug.LogError($"新手引导配置出错,组id:{cfg.GroupId}, 当前步骤id:{preCfg.Id}, 实际下一步步骤id:{preCfg.NextId}, 当前下一步步骤id:{cfg.Id}");
return;
}
else
preCfg = cfg;
}
}
#endregion
}
///
/// 是否是引导组的第一步
///
///
private bool IsFirstStep(DataGuideCfg dataGuideCfg)
{
return dataGuideCfg.Id == dataGuideCfg.GroupId;
}
///
/// 获取应该引导的引导组id
///
///
private int GetGuideGroupId(int completeStepId)
{
GuideConfig guideConfig = TableManager.Instance.Tables.GuideConfig;
if (guideConfig.DataList.Count <= 0)
return 0;
if (completeStepId >= guideConfig.DataList[^1].Id) // 大于等于最后一步的id
return 0; // 跳过引导
DataGuideCfg completeCfg = null;
if (0 != completeStepId)
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);
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($"引导步骤{completeStepId}所在组{cfg.GroupId}的{cfg.Id}步骤完成,该组完成");
isGroupComplete = true;
break;
}
}
}
if (isGroupComplete) // 该组完成,取下一组
{
DataGuideCfg dataGuideCfg = guideConfig.Get(completeCfg.NextId);
while (null != dataGuideCfg)
{
if (dataGuideCfg.GroupId == completeCfg.GroupId)
{
dataGuideCfg = guideConfig.Get(dataGuideCfg.NextId);
continue;
}
return dataGuideCfg.GroupId;
}
return 0;
}
else
return completeCfg.GroupId; // 该组没有完成,重来
}
///
/// 设置引导状态
///
private void SetGuideState()
{
UIManager.Instance.IsEnableBack = false;
}
///
/// 还原状态
///
private void RecoverState()
{
UIManager.Instance.IsEnableBack = true;
ConditionReactor.Instance.RemoveReaction(reactionID);
reactionID = ConditionReactor.INVALID_ALLOC_ID;
}
///
/// 开始引导
///
private void OnBeginGuide(bool conditionResult, object callBackParam, int reactionID)
{
if (!conditionResult)
return;
//ConditionReactor.Instance.RemoveReaction(reactionID);
//this.reactionID = ConditionReactor.INVALID_ALLOC_ID;
if (IsGuiding)
return;
try
{
SetGuideState();
curGroup.BeginGuide();
}
catch (Exception e)
{
DebugUtil.LogError($"跳过引导,错误信息:{e}");
RecoverState();
}
}
///
/// 引导过程中的任意点击事件
///
private void OnAnyClick()
{
if (!IsGuiding)
return;
if (!IsEnableAnyClick)
return;
DateTime curTime = CommonUtils.GetCurTime(CommonUtils.E_TimeType.Local);
queueTime.Enqueue(curTime);
while (queueTime.TryPeek(out DateTime firstTime))
{
TimeSpan timeSpan = curTime - firstTime;
if (timeSpan.TotalSeconds < SKIP_GUIDE_CHECK_TIME)
break;
queueTime.Dequeue();
}
if (TableManager.Instance.Tables.GlobalConfig.SkipGuideClickCount <= queueTime.Count)
{
DebugUtil.Log($"{SKIP_GUIDE_CHECK_TIME}秒内连续点击{TableManager.Instance.Tables.GlobalConfig.SkipGuideClickCount}次,弹出强制跳过新手引导提示");
queueTime.Clear();
ShowSkipAllGuide();
}
else
DebugUtil.Log($"[引导]记录两秒内的点击次数{queueTime.Count}");
}
}
}