/// <summary> /// 系统向前进一个状态 /// 她只有在对话推进和选择项出现时才被触发 /// </summary> public static void SteadyForward(bool fromWheel, SceneAction saPtr, MusicianDescriptor mdescriptor, BacklogHolder backlogHolder) { lock (typeof(RollbackManager)) { // 回滚后返回,移栈并演绎 if (fromWheel && RollbackManager.IsRollingBack) { // 取上一状态 var recentStep = RollbackManager.backwardStack.Last(); RollbackManager.backwardStack.RemoveLast(); RollbackManager.forwardStack.AddLast(recentStep); // 重演绎 RollbackManager.GotoSteadyState(recentStep); } // 非回滚状态时才重新构造 else if (fromWheel == false) { // 处理回顾 if (saPtr.Type == SActionType.act_dialog) { backlogHolder.AddLog(saPtr.Tag); } // 构造当前状态的拷贝 var vm = Director.RunMana.CallStack.Fork() as StackMachine; vm.SetMachineName(String.Format("Yuri!Forked?{0}?{1}", DateTime.Now.Ticks, rand.Next(0, int.MaxValue))); RollbackableSnapshot ssp = new RollbackableSnapshot() { TimeStamp = DateTime.Now, IsBranchingRefer = Director.GetInstance().GetMainRender().IsBranching, MusicRef = ForkableState.DeepCopyBySerialization(mdescriptor), BacklogRef = ForkableState.DeepCopyBySerialization(backlogHolder), ReactionRef = saPtr, VMRef = vm, globalDao = SymbolTable.GetInstance().GlobalCtxDao.Fork() as GlobalContextDAO, sceneDao = SymbolTable.GetInstance().SceneCtxDao.Fork() as SceneContextDAO, ScreenStateRef = ScreenManager.GetInstance().Fork() as ScreenManager, SemaphoreDict = ForkableState.DeepCopyBySerialization(Director.RunMana.SemaphoreBindings), EnableRClickRef = Director.RunMana.EnableRClick, PerformingChapterRef = Director.RunMana.PerformingChapter }; // 如果栈中容量溢出就剔掉最早进入的那个 if (RollbackManager.forwardStack.Count >= GlobalConfigContext.MaxRollbackStep) { RollbackManager.forwardStack.RemoveFirst(); } // 入栈 RollbackManager.forwardStack.AddLast(ssp); } } }
/// <summary> /// 将系统跳转到指定的稳定状态 /// </summary> /// <param name="ssp">要演绎的状态包装</param> public static void GotoSteadyState(RollbackableSnapshot ssp) { // 停止消息循环 Director.PauseUpdateContext(); // 结束全部动画 SpriteAnimation.ClearAnimateWaitingDict(); // 检查是否需要回滚当前的并行处理和信号绑定 bool needRepara = false; if (ssp.VMRef.ESP.BindingSceneName != Director.RunMana.CallStack.SAVEP.BindingSceneName) { Director.RunMana.PauseParallel(); needRepara = true; } // 退到SSP所描述的状态 SymbolTable.GetInstance().SetDAO(ssp.sceneDao.Fork() as SceneContextDAO, ssp.globalDao.Fork() as GlobalContextDAO); ScreenManager.ResetSynObject(ssp.ScreenStateRef.Fork() as ScreenManager); Director.RunMana.ResetCallstackObject(ssp.VMRef.Fork() as StackMachine); Director.RunMana.Backlogs = ForkableState.DeepCopyBySerialization(ssp.BacklogRef); Director.RunMana.Musics = ForkableState.DeepCopyBySerialization(ssp.MusicRef); Director.RunMana.DashingPureSa = ssp.ReactionRef.Clone(true); Director.RunMana.SemaphoreBindings = ForkableState.DeepCopyBySerialization(ssp.SemaphoreDict); Director.RunMana.EnableRClick = ssp.EnableRClickRef; Director.RunMana.PerformingChapter = ssp.PerformingChapterRef; Director.ScrMana = ScreenManager.GetInstance(); // 刷新主渲染器上的堆栈绑定 Director.GetInstance().RefreshMainRenderVMReference(); Director.GetInstance().GetMainRender().IsBranching = ssp.IsBranchingRefer; // 重绘整个画面 ViewManager.GetInstance().ReDraw(true); // 恢复音效 UpdateRender render = Director.GetInstance().GetMainRender(); if (GlobalConfigContext.UseBassEngine) { MusicianBass.GetInstance().RePerform(Director.RunMana.Musics); } else { Musician.GetInstance().RePerform(Director.RunMana.Musics); } // 清空字符串缓冲 render.dialogPreStr = String.Empty; render.pendingDialogQueue.Clear(); // 关闭自动播放 Director.RunMana.IsAutoplaying = false; // 弹空全部等待,复现保存最后一个动作 Director.RunMana.ExitUserWait(); Interrupt reactionNtr = new Interrupt() { Type = InterruptType.LoadReaction, Detail = "Reaction for rollback", InterruptSA = ssp.ReactionRef, InterruptFuncSign = String.Empty, ReturnTarget = null, PureInterrupt = true }; // 提交中断到主调用堆栈 Director.RunMana.CallStack.Submit(reactionNtr); // 重启并行处理和信号系统 if (needRepara) { var sc = ResourceManager.GetInstance().GetScene(ssp.VMRef.EBP.BindingSceneName); Director.RunMana.ConstructParallelForRollingBack(sc); Director.RunMana.BackTraceParallel(); Director.RunMana.LastSceneName = sc.Scenario; SemaphoreDispatcher.ReBinding(sc, Director.RunMana.SemaphoreBindings); } // 重启消息循环 Director.ResumeUpdateContext(); }