Files
Endfield-Data/LuaScripts/LuaSystem/MainHudActionQueueSystem.lua
2025-12-02 20:37:18 +07:00

882 lines
23 KiB
Lua

local LuaSystemBase = require_ex('LuaSystem/LuaSystemBase')
MainHudActionQueueSystem = HL.Class('MainHudActionQueueSystem', LuaSystemBase.LuaSystemBase)
MainHudActionQueueSystem._InitConfigs = HL.Method() << function(self)
self.configs = {
Cinematic = {
order = CS.Beyond.MainHudActionQueueConsts.CINEMATIC_ORDER_FIRST,
needWait = true,
isCinematic = true,
dropWhenChangeScene = true,
},
DashBarUpgrade = {
order = 0,
needWait = true,
ignoreCinematicInterrupt = true,
checkGuideOnStart = true,
},
CashShopOrderSettle = {
order = 1,
needWait = true,
finishWhenInterrupt = true,
checkGuideOnStart = true,
},
MonthlyPassPopup = {
order = 1,
needWait = true,
finishWhenInterrupt = true,
checkGuideOnStart = true,
},
FacTechPointGained = {
order = 1,
needWait = true,
finishWhenInterrupt = true,
preloadPanelId = PanelId.FacTechPointGainedToast,
},
ChapterPanelWithoutMissionHud =
{
order = CS.Beyond.MainHudActionQueueConsts.BLOCKER_ORDER,
needWait = true,
finishWhenInterrupt = true,
dropWhenChangeScene = true,
},
MissionHudCompleteBlocker = {
order = CS.Beyond.MainHudActionQueueConsts.BLOCKER_ORDER,
needWait = true,
finishWhenInterrupt = false,
dropWhenChangeScene = true,
},
CenterRewards = {
order = 2,
needWait = true,
preloadPanelId = PanelId.RewardsPopupCenter,
},
EquipFormulaRewardPopup = {
order = 2,
needWait = true,
finishWhenInterrupt = true,
preloadPanelId = PanelId.EquipFormulaRewardPopup,
},
WorldLevelPreview = {
order = 2.1,
needWait = true,
finishWhenInterrupt = true,
dropWhenChangeScene = true,
checkGuideOnStart = true,
},
SettlementToast = {
order = 2.5,
needWait = true,
finishWhenInterrupt = true,
},
ImportantReward = {
order = 3,
needWait = true,
ignoreCinematicInterrupt = true,
preloadPanelId = PanelId.ImportantRewardPopup,
checkGuideOnStart = true,
},
AdventureLevelUp = {
order = 4,
needWait = true,
finishWhenInterrupt = false,
preloadPanelId = PanelId.AdventureLevelUp,
checkGuideOnStart = true,
},
AfterLevelUpSNS = {
order = 4.1,
needWait = true,
dropWhenChangeScene = true,
},
PuzzlePickup = {
order = 6,
needWait = true,
finishWhenInterrupt = true,
preloadPanelId = PanelId.PuzzlePickupToast,
},
EndingToast = {
order = 6,
needWait = true,
finishWhenInterrupt = true,
},
MissionHudResumeInfo = {
order = 7,
needWait = false,
},
CommonPOIUpgradeToast = {
order = 8,
needWait = true,
finishWhenInterrupt = true,
preloadPanelId = PanelId.CommonPOIUpgradeToast,
},
DomainDepotDeliverToast = {
order = 9,
needWait = true,
finishWhenInterrupt = true,
preloadPanelId = PanelId.DomainDepotDeliverToast,
},
DomainUpgrade = {
order = 10,
needWait = true,
finishWhenInterrupt = true,
preloadPanelId = PanelId.DomainUpgrade,
},
MapRegionToast = {
order = 98,
needWait = true,
finishWhenInterrupt = true,
dropWhenChangeScene = true,
preloadPanelId = PanelId.MapRegionToast,
},
SpaceshipHudTips = {
order = 99,
needWait = true,
dropWhenChangeScene = true,
},
SNSNormalNotice = {
order = 100,
needWait = false,
dropWhenChangeScene = true,
},
GetItemToast = {
order = 100,
needWait = false,
},
FirstGotItem = {
order = 100,
needWait = false,
},
UnlockPRTS = {
order = 100,
needWait = false,
},
DomainUpgradeToast = {
order = 100,
needWait = false,
},
WeeklyRaidEnter = {
order = 100,
needWait = true,
finishWhenInterrupt = false,
dropWhenChangeScene = true,
},
}
for k, v in pairs(self.configs) do
v.name = k
end
end
MainHudActionQueueSystem.m_pendingRequests = HL.Field(HL.Table)
MainHudActionQueueSystem.configs = HL.Field(HL.Table)
MainHudActionQueueSystem.m_nextRequestId = HL.Field(HL.Number) << 1
MainHudActionQueueSystem.m_isShowing = HL.Field(HL.Boolean) << false
MainHudActionQueueSystem.m_tryStartActionCor = HL.Field(HL.Thread)
MainHudActionQueueSystem.m_curShowingActionOrder = HL.Field(HL.Number) << math.mininteger
MainHudActionQueueSystem.MainHudActionQueueSystem = HL.Constructor() << function(self)
self:_InitConfigs()
self.m_pendingRequests = {}
self.m_playIgnoreMainHudActionTypes = {}
self:RegisterMessage(MessageConst.ON_ONE_MAIN_HUD_ACTION_FINISHED, function(arg)
local name
if type(arg) == "table" then
name = unpack(arg)
else
name = arg
end
self:OnOneMainHudActionFinish(name)
end)
self:RegisterMessage(MessageConst.ON_IN_MAIN_HUD_CHANGED, function(arg)
local inMainHud = unpack(arg)
if inMainHud then
self:_TryAddStartActionCor()
else
if next(self.m_playIgnoreMainHudActionTypes) then
local nextRequestIndex = self:_GetNextRequestIndex(false)
if nextRequestIndex then
if nextRequestIndex == 1 then
if self.m_isShowing then
return
else
self:_TryStartAction()
return
end
else
self:Interrupt()
self:_TryStartAction()
return
end
end
end
self:Interrupt()
end
end)
self:RegisterMessage(MessageConst.ON_PHASE_LEVEL_DESTROYED, function(arg)
self:Interrupt(true)
self:_DropRequestWhenChangeScene()
end)
self:RegisterMessage(MessageConst.ON_GUIDE_STOPPED, function(arg)
local isForce = unpack(arg)
if isForce then
self:_TryAddStartActionCor()
end
end)
self:RegisterMessage(MessageConst.ON_ONE_COMMON_TASK_REQUEST_FINISH, function()
self:_TryAddStartActionCor()
end)
self:RegisterMessage(MessageConst.INTERRUPT_MAIN_HUD_ACTION_ON_COMMON_BLEND_IN, function()
self:Interrupt()
end)
self:RegisterMessage(MessageConst.ON_COMMON_BLEND_OUT, function()
self:_TryAddStartActionCor()
end)
self:RegisterMessage(MessageConst.COMMON_START_BLOCK_MAIN_HUD_ACTION_QUEUE, function()
self:Interrupt()
end)
self:RegisterMessage(MessageConst.COMMON_END_BLOCK_MAIN_HUD_ACTION_QUEUE, function()
self:_TryAddStartActionCor()
end)
self:RegisterMessage(MessageConst.ON_LEAVE_TOWER_DEFENSE_DEFENDING_PHASE, function()
self:Interrupt()
end)
self:RegisterMessage(MessageConst.ON_TOWER_DEFENSE_LEVEL_REWARDS_FINISHED, function()
self:_TryAddStartActionCor()
end)
self:RegisterMessage(MessageConst.MAIN_HUD_ACTION_QUEUE_TOGGLE_IGNORE_MAIN_HUD_CS, function(args)
local actionType, active = unpack(args)
self:ToggleActionPlayIgnoreMainHud(actionType, active)
end)
self:RegisterMessage(MessageConst.PRE_LEVEL_START, function()
if Utils.isInBlackbox() then
self:ManuallyDropAllRequests()
end
end)
self:RegisterMessage(MessageConst.ON_CONFIRM_CHANGE_INPUT_DEVICE_TYPE, function()
self:Interrupt()
end)
self:RegisterMessage(MessageConst.ON_SWITCH_LANGUAGE, function()
self:Interrupt()
end)
end
MainHudActionQueueSystem.AddRequest = HL.Method(HL.String, HL.Function, HL.Opt(HL.Function, HL.Boolean, HL.Function)) << function(self, type, action, getOrder, startImmediately, onDrop)
logger.important(CS.Beyond.EnableLogType.MainHudActionQueue, "MainHudActionQueueSystem.AddRequest", type, startImmediately)
local requestId = self.m_nextRequestId
self.m_nextRequestId = self.m_nextRequestId + 1
local cfg = self.configs[type]
local request = {
id = requestId,
type = type,
action = action,
getOrder = getOrder,
onDrop = onDrop,
cfg = cfg,
}
setmetatable(request, { __index = cfg })
table.insert(self.m_pendingRequests, request)
if request.isCinematic then
Notify(MessageConst.FAC_BUILD_EXIT_CUR_MODE, true)
Notify(MessageConst.FAC_EXIT_DESTROY_MODE, true)
LuaSystemManager.factory:ToggleTopView(false, true)
if GameWorld.worldInfo.inMainHud or self.m_playIgnoreMainHudActionTypes[type] then
local curRequest = self.m_pendingRequests[1]
if curRequest and not curRequest.isCinematic and not curRequest.ignoreCinematicInterrupt then
if self.m_isShowing then
self:Interrupt()
curRequest.order = nil
local nextRequestIndex = self:_GetNextRequestIndex(true)
self:_MoveRequestToTop(nextRequestIndex)
self:_StartFirstAction()
return
else
curRequest.order = nil
end
end
end
end
self:_SortRequest(true)
request.startImmediately = startImmediately
if startImmediately then
if self.m_isShowing or self.m_pendingRequests[1] ~= request then
logger.warn("MainHudActionQueueSystem.AddRequest", type, "startImmediately 失败:当前正在播放", request.type)
else
self:_TryStartAction()
return
end
end
self:_TryAddStartActionCor()
end
MainHudActionQueueSystem._SortRequest = HL.Method(HL.Boolean) << function(self, forceSort)
local needSort = forceSort
for k, request in ipairs(self.m_pendingRequests) do
if request.getOrder and (not self.m_isShowing or k > 1) then
needSort = true
request.order = request.getOrder()
end
end
if not needSort then
return
end
table.sort(self.m_pendingRequests, Utils.genSortFunction({ "order", "id" }, true))
logger.important(CS.Beyond.EnableLogType.MainHudActionQueue, "MainHudActionQueueSystem._SortRequest")
end
MainHudActionQueueSystem.IsShowing = HL.Method().Return(HL.Boolean) << function(self)
return self.m_isShowing
end
MainHudActionQueueSystem.GetCurQueueFirstRequest = HL.Method().Return(HL.Opt(HL.Table)) << function(self)
return self.m_pendingRequests[1]
end
MainHudActionQueueSystem.GetCurQueueFirstRequestType = HL.Method().Return(HL.Opt(HL.String)) << function(self)
local request = self.m_pendingRequests[1]
if request then
return request.type
end
end
MainHudActionQueueSystem._TryAddStartActionCor = HL.Method() << function(self)
if self.m_isShowing or self.m_pendingRequests[1] == nil then
logger.important(CS.Beyond.EnableLogType.MainHudActionQueue, "MainHudActionQueueSystem._TryAddStartActionCor Skipped")
return
end
if self.m_tryStartActionCor then
logger.important(CS.Beyond.EnableLogType.MainHudActionQueue, "MainHudActionQueueSystem._TryAddStartActionCor Duplicated")
return
end
if self.m_lastFinishShowingFrameCount == Time.frameCount then
logger.important(CS.Beyond.EnableLogType.MainHudActionQueue, "MainHudActionQueueSystem._TryAddStartActionCor 当帧刚结束,所以直接开始,确保播放之间是无缝的")
self:_TryStartAction()
elseif self.m_pendingRequests[1].startImmediately then
logger.important(CS.Beyond.EnableLogType.MainHudActionQueue, "MainHudActionQueueSystem._TryAddStartActionCor startImmediately")
self:_TryStartAction()
else
logger.important(CS.Beyond.EnableLogType.MainHudActionQueue, "MainHudActionQueueSystem._TryAddStartActionCor Succ")
self.m_tryStartActionCor = self:_StartCoroutine(function()
coroutine.step()
coroutine.step()
self:_TryStartAction()
end)
end
end
MainHudActionQueueSystem._TryStartAction = HL.Method() << function(self)
logger.important(CS.Beyond.EnableLogType.MainHudActionQueue, "MainHudActionQueueSystem._TryStartAction")
self.m_tryStartActionCor = self:_ClearCoroutine(self.m_tryStartActionCor)
if GameInstance.player.guide.isInForceGuide and not Utils.isInBlackbox() then
return
end
local nextRequestIndex = self:_GetNextRequestIndex(false)
if not nextRequestIndex then
return
end
if GameInstance.player.inventory.isProcessingRewardToastData then
return
end
if UIManager:IsShow(PanelId.MissionCompletePop) then
return
end
if LuaSystemManager.commonTaskTrackSystem:HasRequest() then
return
end
if Utils.isInSettlementDefense() then
return
end
self:_MoveRequestToTop(nextRequestIndex)
self:_StartFirstAction()
end
MainHudActionQueueSystem.m_curPreloadId = HL.Field(HL.Any)
MainHudActionQueueSystem.m_nextPreloadId = HL.Field(HL.Number) << 1
MainHudActionQueueSystem._StartFirstAction = HL.Method() << function(self)
self.m_isShowing = true
local request = self.m_pendingRequests[1]
request.order = self.m_curShowingActionOrder
local cfg = self.configs[request.type]
if cfg.checkGuideOnStart and GameInstance.player.guide.isInForceGuide and not Utils.isInBlackbox() then
logger.important(CS.Beyond.EnableLogType.MainHudActionQueue, "MainHudActionQueueSystem._StartFirstAction Failed Because Of Guide", request.type, request)
self:Interrupt(false, true)
return
else
logger.important(CS.Beyond.EnableLogType.MainHudActionQueue, "MainHudActionQueueSystem._StartFirstAction", request.type, request)
end
local isResume = request.haveBeenInterrupted
if request.preloadPanelId then
local pId = self.m_nextPreloadId
self.m_nextPreloadId = self.m_nextPreloadId + 1
self.m_curPreloadId = pId
UIManager:PreloadPanelAsset(request.preloadPanelId, "MainHudActionQueue", function()
if self.m_curPreloadId == pId then
request.action(isResume)
if not cfg.needWait then
self:OnOneMainHudActionFinish(request.type)
end
end
end)
else
self.m_curPreloadId = nil
request.action(isResume)
if not cfg.needWait then
self:OnOneMainHudActionFinish(request.type)
end
end
end
MainHudActionQueueSystem._CheckAllMainHudActionFinish = HL.Method() << function(self)
if self.m_pendingRequests[1] ~= nil then
return
end
Notify(MessageConst.ALL_MAIN_HUD_ACTION_FINISH)
end
MainHudActionQueueSystem.m_lastFinishShowingFrameCount = HL.Field(HL.Number) << -1
MainHudActionQueueSystem.OnOneMainHudActionFinish = HL.Method(HL.String) << function(self, type)
logger.important(CS.Beyond.EnableLogType.MainHudActionQueue, "MainHudActionQueueSystem.OnOneMainHudActionFinish", type)
if not self.m_isShowing then
logger.error("OnOneMainHudActionFinish: 当前不在播放中", type)
return
end
local request = self.m_pendingRequests[1]
if request.type ~= type then
logger.error("OnOneMainHudActionFinish: 并不是正在播放的类型", type, request)
return
end
table.remove(self.m_pendingRequests, 1)
if self.m_pendingRequests[1] then
local nextRequestIndex = self:_GetNextRequestIndex(false)
if nextRequestIndex then
self:_MoveRequestToTop(nextRequestIndex)
self:_StartFirstAction()
return
end
end
self.m_isShowing = false
self.m_lastFinishShowingFrameCount = Time.frameCount
logger.important(CS.Beyond.EnableLogType.MainHudActionQueue, "MainHudActionQueueSystem showing finished")
self:_CheckAllMainHudActionFinish()
CS.Beyond.Gameplay.Conditions.OnMainHudActionFinished.Trigger(false)
end
MainHudActionQueueSystem.Interrupt = HL.Method(HL.Opt(HL.Boolean, HL.Boolean)) << function(self, includeCinematic, forceNotFinish)
if not includeCinematic then
if not self.m_isShowing and self.m_tryStartActionCor == nil then
return
end
local request = self.m_pendingRequests[1]
if request and request.isCinematic then
return
end
end
self.m_tryStartActionCor = self:_ClearCoroutine(self.m_tryStartActionCor)
if not self.m_isShowing then
return
end
local request = self.m_pendingRequests[1]
logger.important(CS.Beyond.EnableLogType.MainHudActionQueue, "MainHudActionQueueSystem.Interrupt", includeCinematic, request.type)
self.m_curPreloadId = nil
self.m_isShowing = false
Notify(MessageConst.INTERRUPT_MAIN_HUD_ACTION_QUEUE)
if request.finishWhenInterrupt and not forceNotFinish then
table.remove(self.m_pendingRequests, 1)
self:_CheckAllMainHudActionFinish()
else
request.haveBeenInterrupted = true
end
CS.Beyond.Gameplay.Conditions.OnMainHudActionFinished.Trigger(true)
end
MainHudActionQueueSystem._DropRequestWhenChangeScene = HL.Method() << function(self)
local newRequests = {}
for _, request in ipairs(self.m_pendingRequests) do
if not request.dropWhenChangeScene then
table.insert(newRequests, request)
else
logger.important(CS.Beyond.EnableLogType.MainHudActionQueue, "MainHudActionQueueSystem._DropRequestWhenChangeScene", request.name)
if request.onDrop then
request.onDrop()
end
end
end
self.m_pendingRequests = newRequests
end
MainHudActionQueueSystem.RemoveActionsOfType = HL.Method(HL.String) << function(self, actionType)
logger.important(CS.Beyond.EnableLogType.MainHudActionQueue, "MainHudActionQueueSystem.RemoveActionsOfType", actionType)
local needRestart = false
local requestCnt = #self.m_pendingRequests
if requestCnt == 0 then
return
end
if self.m_isShowing then
local currentAction = self.m_pendingRequests[1]
if currentAction.type == actionType then
if currentAction.finishWhenInterrupt then
requestCnt = requestCnt - 1
end
self:Interrupt()
needRestart = true
end
end
local reservedCnt = 0
local newPendingRequests = {}
for i = 1, requestCnt do
local request = self.m_pendingRequests[i]
if request.type == actionType then
if request.onDrop then
request.onDrop()
end
else
reservedCnt = reservedCnt + 1
newPendingRequests[reservedCnt] = request
end
end
self.m_pendingRequests = newPendingRequests
if reservedCnt == 0 then
self:Interrupt()
elseif needRestart then
self:_TryStartAction()
end
end
MainHudActionQueueSystem.HasRequest = HL.Method(HL.String).Return(HL.Boolean) << function(self, actionType)
for _, request in ipairs(self.m_pendingRequests) do
if request.type == actionType then
return true
end
end
return false
end
MainHudActionQueueSystem.m_playIgnoreMainHudActionTypes = HL.Field(HL.Table)
MainHudActionQueueSystem.ToggleActionPlayIgnoreMainHud = HL.Method(HL.String, HL.Boolean) << function(self, actionType, ignoreMainHud)
local curIsActive = self.m_playIgnoreMainHudActionTypes[actionType] == true
if curIsActive == ignoreMainHud then
return
end
logger.important(CS.Beyond.EnableLogType.MainHudActionQueue, "MainHudActionQueueSystem.ToggleActionPlayIgnoreMainHud", actionType, ignoreMainHud)
if ignoreMainHud then
self.m_playIgnoreMainHudActionTypes[actionType] = true
else
self.m_playIgnoreMainHudActionTypes[actionType] = nil
end
if ignoreMainHud and not self.m_isShowing and self.m_pendingRequests[1] then
self:_TryStartAction()
end
end
MainHudActionQueueSystem._GetNextRequestIndex = HL.Method(HL.Boolean).Return(HL.Opt(HL.Number)) << function(self, forceSort)
self:_SortRequest(forceSort)
if GameWorld.worldInfo.inMainHud and not CameraManager:IsCommonTempControllerActive() then
return 1
else
if next(self.m_playIgnoreMainHudActionTypes) then
for k, v in ipairs(self.m_pendingRequests) do
if self.m_playIgnoreMainHudActionTypes[v.type] then
return k
end
end
end
end
end
MainHudActionQueueSystem._MoveRequestToTop = HL.Method(HL.Opt(HL.Number)) << function(self, index)
if index and index ~= 1 then
local request = self.m_pendingRequests[index]
for k = index, 2, -1 do
self.m_pendingRequests[k] = self.m_pendingRequests[k - 1]
end
self.m_pendingRequests[1] = request
end
end
MainHudActionQueueSystem.ManuallyDropAllRequests = HL.Method() << function(self)
if self:IsShowing() then
logger.error("MainHudActionQueueSystem.ManuallyDropAllRequests FAIL because: IsShowing")
return
end
for _, request in ipairs(self.m_pendingRequests) do
logger.important(CS.Beyond.EnableLogType.MainHudActionQueue, "MainHudActionQueueSystem.ManuallyDropAllRequests", request.name)
if request.onDrop then
request.onDrop()
end
end
self.m_pendingRequests = {}
end
HL.Commit(MainHudActionQueueSystem)
return MainHudActionQueueSystem