PGRData/Script/matrix/xmanager/XMovieManager.lua
2024-09-01 22:49:41 +02:00

586 lines
No EOL
20 KiB
Lua
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

local tonumber = tonumber
local tostring = tostring
local mathFloor = math.floor
local tableInsert = table.insert
local tableRemove = table.remove
local next = next
local CSMovieXMovieManagerInstance = CS.Movie.XMovieManager.Instance
local UI_MOVIE = "UiMovie"
local RESOLUTION_RATIO = CS.XResolutionManager.OriginWidth / CS.XResolutionManager.OriginHeight / CS.XUiManager.DefaultScreenRatio
local TIMELINE_SECONDS_TRANS = 1 / 60
local DEFAULT_SPEED = 1
local DisableFunction = false --功能屏蔽标记(调试模式时使用)
local CurrentAction = nil;
local ActionClass = {
[101] = require("XMovieActions/XMovieActionBgSwitch"), --背景切换
[102] = require("XMovieActions/XMovieActionTheme"), --章节主题
[103] = require("XMovieActions/XMovieActionBgScale"), --背景缩放位置调整
[104] = require("XMovieActions/XMovieActionBgMoveAnimation"), --背景位移动画
[105] = require("XMovieActions/XMovieActionSpineAnim"), --Spine动画加载
[106] = require("XMovieActions/XMovieActionPlaySpineAnim"), --Spine动画播放
[107] = require("XMovieActions/XMovieActionLeftTitleAppear"), --左边标题出现
[108] = require("XMovieActions/XMovieActionLeftTitleDisappear"), --左边标题消失
[201] = require("XMovieActions/XMovieActionActorAppear"), --演员出现
[202] = require("XMovieActions/XMovieActionActorDisappear"), --演员消失
[203] = require("XMovieActions/XMovieActionActorShift"), --演员位移
[204] = require("XMovieActions/XMovieActionActorChangeFace"), --演员表情
[205] = require("XMovieActions/XMovieActionActorAlphaChange"), --演员背景
[211] = require("XMovieActions/XMovieActionSpineActorAppear"), --spine演员出现
[212] = require("XMovieActions/XMovieActionSpineActorDisappear"), --spine演员消失
[213] = require("XMovieActions/XMovieActionSpineActorShift"), --spine演员位移
[214] = require("XMovieActions/XMovieActionSpineActorChangeAnim"), --spine演员切换动画
[215] = require("XMovieActions/XMovieActionSpineActorAnimationPlay"), --spine演员预置的UI动画播放
[301] = require("XMovieActions/XMovieActionDialog"), --普通对话
[302] = require("XMovieActions/XMovieActionSelection"), --选择分支对话
[303] = require("XMovieActions/XMovieActionDelaySkip"), --延迟跳转
[304] = require("XMovieActions/XMovieActionFullScreenDialog"), --全屏字幕
[305] = require("XMovieActions/XMovieActionYieldResume"), --挂起/恢复
[306] = require("XMovieActions/XMovieActionRoleMask"), --上下遮罩动画
[307] = require("XMovieActions/XMovieActionCenterTips"), --居中提示文本
[401] = require("XMovieActions/XMovieActionSoundPlay"), --BGM/CV/音效 播放
[402] = require("XMovieActions/XMovieActionAudioInterrupt"), --BGM/CV/音效 打断
[501] = require("XMovieActions/XMovieActionEffectPlay"), --特效播放
[502] = require("XMovieActions/XMovieActionAnimationPlay"), --UI动画播放
[503] = require("XMovieActions/XMovieActionVideoPlay"), --视频播放
[504] = require("XMovieActions/XMovieActionSetGray"), --灰度设置
[505] = require("XMovieActions/XMovieActionUnLoad"), --动效卸载
[506] = require("XMovieActions/XMovieActionPrefabAnimation"), --预制体动画
[507] = require("XMovieActions/XMovieActionInsertTipAppear"), --中间插入横幅
[508] = require("XMovieActions/XMovieActionInsertTipDisappear"), --中间横幅消失
[509] = require("XMovieActions/XMovieActionShowInsertPanel"), --显示两边插入分屏
[510] = require("XMovieActions/XMovieActionHideInsertPanel"), --隐藏插入分屏
[601] = require("XMovieActions/XMovieActionStaff"), --staff职员表
--3D剧情相关
[701] = require("XMovieActions/XMovieActionSceneLoad"), --场景加载
[702] = require("XMovieActions/XMovieActionCameraLoad"), --摄像头加载
[703] = require("XMovieActions/XMovieActionCameraPlay"), --播放相机动画
[704] = require("XMovieActions/XMovieActionActorLoad"), --角色模型加载
[705] = require("XMovieActions/XMovieActionModelMove"), --角色移动
[706] = require("XMovieActions/XMovieActionSetActorTransform"), --设置角色位置
[707] = require("XMovieActions/XMovieActionModelAnimationPlay"), --角色动画播放
[708] = require("XMovieActions/XMovieActionDialog3D"), --3D剧情对话框
[709] = require("XMovieActions/XMovieActionTimelineLoad"), --Timeline动画预制体加载
[710] = require("XMovieActions/XMovieActionTimelinePlay"), --Timeline动画播放
[711] = require("XMovieActions/XMovieActionPlayCV"), --播放角色语音
[712] = require("XMovieActions/XMovieActionSwitchMixMode"), --切换2D与3D混合模式
[713] = require("XMovieActions/XMovieActionSetBg"), --设置混合模式背景图片
}
--可以通过上一页返回到的节点
local MovieBackFilter = {
[301] = true, --普通对话
}
XMovieManagerCreator = function()
local AllMovieActions = {}
local ActionIdToIndexDics = {}
local CurPlayingMovieId
local CurPlayingActionIndex
local AutoPlay
local WaitToPlayList = {}
local DelaySelectionDic = {}
local ReviewDialogList = {}
local EndCallBack
local IsPlaying
local IsYield
local IsPause = false
local YieldCallBack
local MovieBackStack = XStack.New()
local Speed = 1 -- 自动播放的倍速
local function InitMovieActions(movieId)
local movieActions = {}
local actionIdToIndexDic = {}
local findEnd = false
local movieCfg = XMovieConfigs.GetMovieCfg(movieId)
for index, actionData in ipairs(movieCfg) do
local actionClass = ActionClass[actionData.Type]
if not actionClass then
XLog.Error("XMovieManager.InitMovieActions 配置节点类型错误找不到对应的节点Type: " .. actionData.Type)
return
end
tableInsert(movieActions, actionClass.New(actionData))
actionIdToIndexDic[actionData.ActionId] = index
if actionData.IsEnd ~= 0 then
findEnd = true
end
end
if not findEnd then
XLog.Error("XMovieManager.InitMovieActions error:没有配置结束标记IsEnd, movieId: ", movieId)
return
end
AllMovieActions[movieId] = movieActions
ActionIdToIndexDics[movieId] = actionIdToIndexDic
return movieActions
end
local function GetMovieActions(movieId)
if not AllMovieActions[movieId] then
InitMovieActions(movieId)
end
if not AllMovieActions[movieId] then
XLog.Error("XMovieManager GetMovieActions error:actions not exsit, movieId is: ", movieId)
return
end
return AllMovieActions[movieId]
end
local function GetActionIndexById(movieId, actionId)
local dic = ActionIdToIndexDics[movieId]
if not dic then
XLog.Error("XMovieManager GetActionIndexById error:dic not exsit, movieId is: " .. movieId .. ", actionId is: " .. actionId)
return
end
local index = dic[actionId]
if not index then
XLog.Error("XMovieManager GetActionIndexById error:index not exsit, actionId is: " .. actionId)
end
return index
end
local function ReleaseAll(isRelease)
if (not CS.XFight.IsRunning) and isRelease then
CsXUiManager.Instance:ReleaseAll(CsXUiType.Normal)
end
end
local function OnPlayBegin(movieId, hideSkipBtn,isRelease)
CurPlayingMovieId = movieId
CurPlayingActionIndex = 1
WaitToPlayList = GetMovieActions(movieId)
ReviewDialogList = {}
MovieBackStack:Clear()
IsPlaying = true
IsPause = false
CsXGameEventManager.Instance:Notify(XEventId.EVENT_MOVIE_BEGIN, movieId)
XEventManager.DispatchEvent(XEventId.EVENT_MOVIE_BEGIN, movieId)
if XLuaUiManager.IsUiShow(UI_MOVIE) then return end
ReleaseAll(isRelease)
XLuaUiManager.Open(UI_MOVIE, hideSkipBtn)
end
local function OnPlayEnd()
if not CurPlayingMovieId then return end
local dict = {}
dict["story_id"] = CurPlayingMovieId
dict["role_level"] = XPlayer.GetLevel()
CS.XRecord.Record(dict, "200002", "StorylineEnd")
if not CS.XFight.IsRunning then
CsXUiManager.Instance:RevertAll()
end
CurPlayingMovieId = nil
CurPlayingActionIndex = nil
AutoPlay = nil
ReviewDialogList = {}
DelaySelectionDic = {}
WaitToPlayList = {}
IsPlaying = nil
IsYield = nil
IsPause = false
YieldCallBack = nil
MovieBackStack:Clear()
CsXGameEventManager.Instance:Notify(XEventId.EVENT_MOVIE_END)
XEventManager.DispatchEvent(XEventId.EVENT_MOVIE_END)
if CurrentAction then
CurrentAction:OnDestroy()
end
if XLuaUiManager.IsUiShow(UI_MOVIE) then
XLuaUiManager.Close(UI_MOVIE)
end
end
--剧情UI完全关闭所有节点清理行为结束
local function AfterUiClosed()
if EndCallBack then
local endCb = EndCallBack --可能会嵌套播放,避免新剧情打开时回调被错误清掉
EndCallBack = nil
-- 剧情过程中强制下线
if not XLoginManager.IsLogin() then
return
end
endCb()
end
end
local function DoAction(ignoreLock)
if not CurPlayingActionIndex or not next(WaitToPlayList) then
OnPlayEnd()
return
end
if IsYield then
return
end
if IsPause then
return
end
local action = WaitToPlayList[CurPlayingActionIndex]
if not ignoreLock and action:IsWaiting() then
return
end
if action:Destroy() then
if action:IsEnding() then
OnPlayEnd()
return
end
MovieBackStack:Push(CurPlayingActionIndex)
local indexChanged
local selectedActionId = action:GetSelectedActionId()
if selectedActionId ~= 0 then
CurPlayingActionIndex = GetActionIndexById(CurPlayingMovieId, selectedActionId)
indexChanged = true
end
local delaySelectedActionId = action:GetDelaySelectActionId()
if delaySelectedActionId ~= 0 then
CurPlayingActionIndex = GetActionIndexById(CurPlayingMovieId, delaySelectedActionId)
indexChanged = true
end
local resumeActionId = action:GetResumeActionId()
if resumeActionId ~= 0 then
CurPlayingActionIndex = GetActionIndexById(CurPlayingMovieId, resumeActionId)
indexChanged = true
end
if not indexChanged then
local nextActionId = action:GetNextActionId()
if nextActionId ~= 0 then
CurPlayingActionIndex = GetActionIndexById(CurPlayingMovieId, nextActionId)
indexChanged = true
end
end
if not indexChanged then
CurPlayingActionIndex = CurPlayingActionIndex + 1
end
action = WaitToPlayList[CurPlayingActionIndex]
CurrentAction = action
action:OnReset()
if not action then
OnPlayEnd()
return
end
end
action:ChangeStatus()
end
---@class XMovieManager
local XMovieManager = {}
function XMovieManager.Init()
XEventManager.AddEventListener(XEventId.EVENT_MOVIE_BREAK_BLOCK, DoAction)
XEventManager.AddEventListener(XEventId.EVENT_MOVIE_UI_CLOSED, AfterUiClosed)
DisableFunction = XMovieManager.CheckFuncDisable()
end
local function PlayOldMovie(movieId, cb)
if not CSMovieXMovieManagerInstance:CheckMovieExist(movieId) then return end
CSMovieXMovieManagerInstance:PlayById(movieId, function()
if cb then cb() end
end)
end
local function PlayNewMovie(movieId, cb, yieldCb, hideSkipBtn, isRelease)
EndCallBack = cb
YieldCallBack = yieldCb
OnPlayBegin(movieId, hideSkipBtn,isRelease)
end
function XMovieManager.PlayMovie(movieId, cb, yieldCb, hideSkipBtn,isRelease)
if isRelease == nil then
isRelease = true
end
if DisableFunction or XUiManager.IsHideFunc then
XLog.Warning(string.format("已跳过剧情%s", movieId))
if not DisableFunction then
ReleaseAll(isRelease)
end
if cb then cb() end
return
end
local dict = {}
dict["story_id"] = movieId
dict["role_level"] = XPlayer.GetLevel()
CS.XRecord.Record(dict, "200001", "StorylineStart")
movieId = tostring(movieId)
if XMovieConfigs.CheckMovieConfigExist(movieId) then
PlayNewMovie(movieId, cb, yieldCb, hideSkipBtn, isRelease)
else
PlayOldMovie(movieId, cb)
end
end
function XMovieManager.StopMovie()
if not XMovieManager.IsPlayingMovie() then return end
if not XLuaUiManager.IsUiShow(UI_MOVIE) then return end
OnPlayEnd()
end
function XMovieManager.BackToLastAction()
local curAction = WaitToPlayList[CurPlayingActionIndex]
local lastId = MovieBackStack:Peek()
if lastId ~= CurPlayingActionIndex then
curAction:OnUndo()
curAction:OnReset()
end
if MovieBackStack:Count() == 0 then
CurPlayingActionIndex = 1
end
while (MovieBackStack:Count() ~= 0) do
local currIndex = MovieBackStack:Pop()
local action = WaitToPlayList[currIndex]
action:OnUndo()
action:OnReset()
if MovieBackFilter[action:GetType()] then
CurPlayingActionIndex = currIndex
break
end
if MovieBackStack:Count() == 0 then
CurPlayingActionIndex = 1
break
end
end
XEventManager.DispatchEvent(XEventId.EVENT_MOVIE_BREAK_BLOCK)
end
local function IsPlayingNewMovie()
return IsPlaying
end
local function IsPlayingOldMovie()
return CSMovieXMovieManagerInstance:IsPlayingMovie()
end
function XMovieManager.IsPlayingMovie()
return IsPlayingNewMovie() or IsPlayingOldMovie()
end
function XMovieManager.IsMovieYield()
if not XMovieManager.IsPlayingMovie() then return false end
return IsYield or false
end
function XMovieManager.YiledMovie()
if not YieldCallBack then return end --没有恢复回调时不允许挂起
IsYield = true
YieldCallBack()
YieldCallBack = nil
end
function XMovieManager.IsMoviePause()
if not XMovieManager.IsPlayingMovie() then return false end
return IsPause or false
end
function XMovieManager.SetMoviePause(isPause)
IsPause = isPause
end
function XMovieManager.SwitchMovieState()
IsPause = not IsPause
local action = WaitToPlayList[CurPlayingActionIndex]
if (not IsPause) and action:CanContinue() then
DoAction()
end
end
function XMovieManager.ResumeMovie(index)
if not IsPlayingNewMovie() then
if IsPlayingOldMovie() then
XLog.Error("XMovieManager.ResumeMovie Error: 老版剧情不支持挂起恢复操作")
return
end
XLog.Error("XMovieManager.ResumeMovie Error: 当前没有播放中的剧情")
return
end
local action = WaitToPlayList[CurPlayingActionIndex]
if not IsYield or not action.ResumeAtIndex then
XLog.Error("XMovieManager.ResumeMovie Error: 当前没有挂起中的剧情, action: ", action)
return
end
IsYield = nil
action:ResumeAtIndex(index)
DoAction()
end
function XMovieManager.PushInReviewDialogList(roleName, dialogContent,cueId)
roleName = roleName and roleName ~= "" and roleName .. ": " or ""
if not string.IsNilOrEmpty(roleName) then
dialogContent = dialogContent or "" -- and dialogContent ~= "" and '"' .. dialogContent .. '"' or ""
end
local data = {
RoleName = roleName,
Content = dialogContent,
CueId = cueId
}
tableInsert(ReviewDialogList, data)
end
function XMovieManager.RemoveFromReviewDialogList()
if ReviewDialogList and #ReviewDialogList > 0 then
tableRemove(ReviewDialogList)
end
end
function XMovieManager.DelaySelectAction(key, actionId)
DelaySelectionDic[key] = actionId
end
function XMovieManager.GetDelaySelectActionId(key)
local actionId = DelaySelectionDic[key]
if actionId then
DelaySelectionDic[key] = nil
else
actionId = 0
end
return actionId
end
function XMovieManager.SwitchAutoPlay()
AutoPlay = not AutoPlay
local action = WaitToPlayList[CurPlayingActionIndex]
if action then
XEventManager.DispatchEvent(XEventId.EVENT_MOVIE_AUTO_PLAY, AutoPlay)
end
-- 打点
local dict = {}
dict["story_id"] = CurPlayingMovieId
dict["role_level"] = XPlayer.GetLevel()
dict["speed"] = Speed
if AutoPlay then
CS.XRecord.Record(dict, "200011", "StoryAutoplayStart")
else
CS.XRecord.Record(dict, "200012", "StoryAutoplayEnd")
end
end
function XMovieManager.IsAutoPlay()
return AutoPlay
end
function XMovieManager.GetReviewDialogList()
return ReviewDialogList
end
function XMovieManager.ReplacePlayerName(str)
return XUiHelper.ReplaceWithPlayerName(str, XMovieConfigs.PLAYER_NAME_REPLACEMENT)
end
function XMovieManager.Fit(width)
return width * RESOLUTION_RATIO
end
function XMovieManager.ParamToNumber(param)
return param and param ~= "" and tonumber(param) or 0
end
function XMovieManager.TransTimeLineSeconds(time)
time = time or 0
local interger = mathFloor(time)
local decimal = time - interger
return interger + TIMELINE_SECONDS_TRANS * decimal
end
function XMovieManager.ReloadMovies()
if not XMain.IsDebug then return end
AllMovieActions = {}
ActionIdToIndexDics = {}
XMovieConfigs.DeleteMovieCfgs()
end
function XMovieManager.GetMovieDescription()
return XMovieConfigs.GetMovieSkipSkipDesc(CurPlayingMovieId)
end
function XMovieManager.GetCurPlayingMovieId()
return CurPlayingMovieId
end
--检测功能开关
function XMovieManager.CheckFuncDisable()
return XMain.IsDebug and XSaveTool.GetData(XPrefs.StoryTrigger)
end
function XMovieManager.ChangeFuncDisable(state)
DisableFunction = state
XSaveTool.SaveData(XPrefs.StoryTrigger, DisableFunction)
end
-- 设置倍速
function XMovieManager.SetSpeed(speed)
Speed = speed
-- 打点
local dict = {}
dict["story_id"] = CurPlayingMovieId
dict["role_level"] = XPlayer.GetLevel()
dict["speed"] = Speed
CS.XRecord.Record(dict, "200013", "StoryAutoplayChangeSpeed")
end
-- 获取倍速
function XMovieManager.GetSpeed()
if AutoPlay then
return Speed
else
return DEFAULT_SPEED
end
end
-- 重置速度
function XMovieManager.RestSpeed()
Speed = DEFAULT_SPEED
end
-- 当前是否加速
function XMovieManager.IsSpeedUp()
return Speed ~= DEFAULT_SPEED
end
XMovieManager.Init()
return XMovieManager
end