using cfg.GuideCfg; using Framework; using Framework.Condition; using Gameplay.Level; using Gameplay.Net; using Gameplay.SubSystems; using NLDPB; using PhxhSDK; using System; using System.Collections.Generic; namespace Gameplay.Guide { /// /// 新手引导管理器 /// public sealed class GuideManager : Singlenton, IInitable, IUpdatable { #region 兜底强制跳过引导机制 /// /// 2秒内点击n次,弹出强制跳过引导 /// private readonly Queue queueTime = new(); /// /// 强制跳过引导检测时间(秒) /// private const double SKIP_GUIDE_CHECK_TIME = 2d; #endregion /// /// 未完成的引导步骤,注册的开始条件记录在这,key:reactionId,value:引导步骤配置 /// private Dictionary dicReaction; /// /// 完成的引导步骤id /// private HashSet setCompleteId; /// /// 当前的引导步骤 /// private GuideStepBase curStep; /// /// 完成的引导组id /// private int completeGroupId; /// /// 是否初始化引导 /// private bool isInitGuide; /// /// 是否引导中 /// public bool IsGuiding { get { return null != curStep && curStep.IsGuiding; } } #region 引导特殊控制参数 /// /// 控制地板点击 /// public bool IsControlFloor = false; /// /// 指定地板索引 /// public int FloorIndex = -1; /// /// 使用技能成功 /// public bool IsUseSkillSuccess = true; /// /// 是否响应任意点击 /// public bool IsEnableAnyClick = true; #endregion public void Init() { isInitGuide = false; InputManager.Instance.OnAnyClick += OnAnyClick; } 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() { if (null != InputManager.Instance) InputManager.Instance.OnAnyClick -= OnAnyClick; isInitGuide = false; } /// /// 初始化引导 /// public void InitGuide() { #if GUIDE if (isInitGuide) return; dicReaction = new(); setCompleteId = new(); completeGroupId = 0;// (int)Actor.Instance.Logic.GetCount((uint)LogicID.NewGuideProgress); // 服务器所在新手引导组id foreach (DataGuideCfg cfg in TableManager.Instance.Tables.GuideConfig.DataList) { if (IsCompleted(cfg.GroupId)) // 已完成跳过 continue; dicReaction[ConditionReactor.Instance.AddReaction(cfg.BeginCondition, OnBeginGuideByCondition)] = cfg; } isInitGuide = true; #endif } /// /// 完成指定引导步骤 /// /// public void CompleteStep() { if (null == curStep) { EndGuide(true); return; } setCompleteId.Add(curStep.Cfg.Id); if (curStep.Cfg.IsFinalStep) { setCompleteId.Clear(); completeGroupId &= curStep.Cfg.GroupId; // 按位存 NetHelper.SaveGuideProgress(LogicID.NewGuideProgress, completeGroupId); // 完成引导步骤,保存服务器 DebugUtil.Log($"完成引导id:{curStep.Cfg.Id},服务器保存引导组id:{curStep.Cfg.GroupId},服务器实际保存id:{completeGroupId}"); } queueTime.Clear(); curStep = null; EventManager.Instance.Send(EventManager.EventName.Guide_Progress_Change); } /// /// 结束引导 /// public void EndGuide(bool isReEnterMain) { if (IsGuiding) curStep.EndGuide(); RecoverState(); curStep = null; UIManager.Instance.CloseWindow(UINameConst.UI_Guide); UIManager.Instance.CloseWindow(UINameConst.UI_GuideTip); 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()); } } /// /// 跳过当前引导组 /// /// public void SkipCurGuideGroup() {/* if (null == curGroup) return; if (!dicGuideCfg.TryGetValue(curGroup.GroupId, out List listCfg)) { DebugUtil.LogError("要完成的引导组不存在"); return; } NetHelper.SaveGuideProgress(LogicID.NewGuideProgress, listCfg[^1].Id); // 跳过引导步骤,保存服务器 DebugUtil.Log($"跳过引导组,服务器保存引导id:{listCfg[^1].Id}"); EndGuide(false);*/ } /// /// 跳过所有引导 /// public void SkipAllGuide() { DebugUtil.Log("跳过所有引导"); GuideConfig guideConfig = TableManager.Instance.Tables.GuideConfig; DataGuideCfg cfg = guideConfig.DataList[^1]; NetHelper.SaveGuideProgress(LogicID.NewGuideProgress, cfg.Id); EndGuide(true); } /// /// 显示跳过所有引导提示 /// public void ShowSkipAllGuide() { UITipsManager.ShowConfirmTwo(CommonUtils.GetLocalizeText("Guide_SkipAllTitle"), // 脱离卡死 CommonUtils.GetLocalizeText("Guide_SkipAllContent"), // 是否强制跳过新手引导?(选择【跳过】便不再触发新手引导) CommonUtils.GetLocalizeText("Skip"), // 跳过 CommonUtils.GetLocalizeText("Not"), // 否 () => { SkipAllGuide(); }); } /// /// 判断引导步骤是否完成 /// /// public bool IsStepComplete(int guideId) { DataGuideCfg cfg = TableManager.Instance.Tables.GuideConfig.Get(guideId); if (null == cfg) return false; if (IsCompleted(cfg.GroupId)) return true; return setCompleteId.Contains(guideId); } #region 私有方法 /// /// 引导组是否完成 /// /// /// private bool IsCompleted(int groupId) { return 1 == (completeGroupId & groupId); } /// /// 设置引导状态 /// private void SetGuideState() { UIManager.Instance.IsEnableBack = false; } /// /// 还原状态 /// private void RecoverState() { UIManager.Instance.IsEnableBack = true; } /// /// 引导过程中的任意点击事件 /// private void OnAnyClick() { if (!IsGuiding) return; if (!IsEnableAnyClick) return; if (LoadingManager.Instance.IsRuning) 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(); } } #endregion /// /// 创建引导步骤 /// private GuideStepBase CreateGuideStep(DataGuideCfg cfg) { switch (cfg.GuideType) { case E_GuideType.ClickFloor: return ClickFloorGuide.Create(cfg); case E_GuideType.ClickRole: return ClickCharacterGuide.Create(cfg); default: { throw new Exception($"新手引导,未处理类型:{cfg.GuideType}"); } } } /// /// 通过条件触发开始引导 /// private void OnBeginGuideByCondition(bool conditionResult, object callBackParam, int reactionID) { if (!conditionResult) return; if (!dicReaction.TryGetValue(reactionID, out DataGuideCfg guideCfg)) return; ConditionReactor.Instance.RemoveReaction(reactionID); dicReaction.Remove(reactionID); try { SetGuideState(); curStep = CreateGuideStep(guideCfg); curStep.StartGuide(); } catch (Exception e) { DebugUtil.LogError($"跳过引导,错误信息:{e}"); RecoverState(); } } } }