Files
2026-01-31 21:42:01 +07:00

1440 lines
43 KiB
Lua
Raw Permalink 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 GuideStepType = CS.Beyond.Gameplay.GuideStepType
local HintType = CS.Beyond.Gameplay.GuideUIHighlightInfo.HintType
local TextStyle = CS.Beyond.Gameplay.GuideTextInfo.Style
local InfoAtFirstHighlightStyle = {
Force = "Force",
Weak = "Weak",
FullScreenForce = "FullScreenForce",
}
local uiCtrl = require_ex('UI/Panels/Base/UICtrl')
local PANEL_ID = PanelId.Guide
GuideCtrl = HL.Class('GuideCtrl', uiCtrl.UICtrl)
GuideCtrl.s_messages = HL.StaticField(HL.Table) << {
[MessageConst.HIDE_GUIDE_STEP] = 'HideGuideStep',
[MessageConst.CLEAR_GUIDE_STEP] = '_ClearStep',
[MessageConst.ON_COMPLETE_GUIDE_GROUP] = 'OnCompleteGuide',
[MessageConst.ON_INTERRUPT_GUIDE] = 'OnInterruptGuide',
[MessageConst.ON_UI_PANEL_START_OPEN] = 'OnPanelOpened',
[MessageConst.ON_UI_PANEL_SHOW] = 'OnPanelOpened',
[MessageConst.ON_UI_PANEL_CLOSED] = 'OnPanelClosed',
[MessageConst.ON_UI_PANEL_HIDE] = 'OnPanelClosed',
[MessageConst.ON_UI_PHASE_OPENED] = 'OnPhaseOpened',
[MessageConst.ON_UI_PHASE_EXITED] = 'OnPhaseExited',
[MessageConst.ON_CONTROLLER_TYPE_CHANGED] = '_OnControllerTypeChanged',
}
local HIGHLIGHT_DIALOG_ARROW_MIDDLE_RANG = 0.4
local USE_LEFT_HAND_WIDTH_RATIO = 0.06
local RIGHT_ARROW_MODIFIED_OFFSET = -9
GuideCtrl.m_curStepInfo = HL.Field(CS.Beyond.Gameplay.GuideStepInfo)
GuideCtrl.m_isCurForceStep = HL.Field(HL.Boolean) << false
GuideCtrl.m_waitClickUIHighlight = HL.Field(HL.Boolean) << false
GuideCtrl.m_stepStartTime = HL.Field(HL.Number) << -1
GuideCtrl.m_curUIHighlightInfos = HL.Field(HL.Table)
GuideCtrl.m_uiHighlightCells = HL.Field(HL.Forward('UIListCache'))
GuideCtrl.m_firstHighlightUICell = HL.Field(HL.Table)
GuideCtrl.m_dialogNodeMap = HL.Field(HL.Table)
GuideCtrl.m_highlightDialogPadding = HL.Field(HL.Table)
GuideCtrl.m_hasFinishCondition = HL.Field(HL.Boolean) << false
GuideCtrl.m_guideStepInterval = HL.Field(HL.Number) << 0
GuideCtrl.OnCreate = HL.Override(HL.Any) << function(self, arg)
self.view.fullScreenBtn.onClick:AddListener(function()
self:_TryGotoNextStep(true)
end)
UIUtils.bindInputPlayerAction("guide_click", function()
if not DeviceInfo.usingTouch then
self:_TryGotoNextStep(true)
end
end, self.view.fullScreenBtn.groupId)
self.m_uiHighlightCells = UIUtils.genCellCache(self.view.uiHighlightCell)
self.m_dialogNodeMap = {
[TextStyle.BigLeftTop] = self.view.bigLeftTopDialogNode,
[TextStyle.BigLeftBottom] = self.view.bigLeftBottomDialogNode,
[TextStyle.TitleMiddleTop] = self.view.titleMiddleTopNode,
[TextStyle.InfoAtFirstUIHighlight] = self.view.infoAtFirstUIHighlightDialogNode,
}
self.m_highlightDialogPadding = {
top = self.view.config.UI_HIGHLIGHT_DIALOG_PADDING_TOP,
bottom = self.view.config.UI_HIGHLIGHT_DIALOG_PADDING_BOTTOM,
left = self.view.config.UI_HIGHLIGHT_DIALOG_PADDING_LEFT,
right = self.view.config.UI_HIGHLIGHT_DIALOG_PADDING_RIGHT,
}
self:_HideAllOnCreate()
self:_InitDialogControllerHint()
end
GuideCtrl.OnShow = HL.Override() << function(self)
self:_AddTick()
end
GuideCtrl.OnHide = HL.Override() << function(self)
self:_Clear()
end
GuideCtrl.OnClose = HL.Override() << function(self)
self:_Clear()
end
GuideCtrl._HideAllOnCreate = HL.Method() << function(self)
self.view.helperNode.gameObject:SetActive(false)
for _, node in pairs(self.m_dialogNodeMap) do
node.gameObject:SetActive(false)
end
end
GuideCtrl.m_lateTickKey = HL.Field(HL.Number) << -1
GuideCtrl._AddTick = HL.Method() << function(self)
if self.m_lateTickKey > 0 then
return
end
self.m_lateTickKey = LuaUpdate:Add("LateTick", function(deltaTime)
self:_LateTick()
end)
end
GuideCtrl._Clear = HL.Method() << function(self)
LuaUpdate:Remove(self.m_lateTickKey)
self.m_lateTickKey = -1
self.m_curHideMediaTime = -1
Notify(MessageConst.TOGGLE_LEVEL_CAMERA_MOVE, { "guide", true })
CoroutineManager:ClearAllCoroutine(self)
CS.Beyond.UI.UIActionKeyHint.s_stopCheckBindingEnabledForGuide = false
CS.Beyond.UI.UIAutoCloseArea.s_stopCheckShouldClose = false
end
GuideCtrl._LateTick = HL.Method() << function(self)
if self.m_curUIHighlightInfos then
local isForce = self.m_curStepInfo.type ~= GuideStepType.Weak
for _, v in ipairs(self.m_curUIHighlightInfos) do
if IsNull(v.targetTrans) or v.targetTrans.gameObject.name ~= v.oriName then
if NotNull(v.targetTrans) then
v.targetTrans = v.targetTrans.parent:Find(v.oriName)
end
if IsNull(v.targetTrans) then
if v.is3DUI then
v.targetTrans = GameObject.Find(v.path)
else
v.targetTrans = UIManager.uiRoot.transform:Find(v.path) or UIManager.worldUIRoot.transform:Find(v.path)
end
end
if NotNull(v.targetTrans) then
local button, toggle, dropdown, keyHint = self:_GetClickTarget(v.targetTrans)
v.button = button
v.cell.button:ClearTarget()
v.cell.button.targetButton = button
v.cell.button.targetToggle = toggle
v.cell.button.targetDropdown = dropdown
v.cell.button.targetKeyHintActionId = keyHint and keyHint:GetActionId() or nil
v.cell.button:CopyTargetBinding()
end
end
if NotNull(v.targetTrans) then
local rect = UIUtils.getUIRectOfRectTransform(v.targetTrans, v.is3DUI and CameraManager.mainCamera or self.uiCamera)
self:_SyncUIHighlightTargetRect(v.cell, rect, v.needMask, v.isCircle)
if not isForce then
local isActive = UIUtils.isUIGOActive(v.targetTrans.gameObject) and (not v.button or (v.ignoreBindingEnabled or v.button.groupEnabled))
if v.cell.gameObject.activeSelf ~= isActive then
v.cell.gameObject:SetActive(isActive)
if isActive then
v.cell.animationWrapper:Play(v.isCircle and "guideuihighlight_loop02" or "guideuihighlight_loop01")
end
if isActive then
GameInstance.player.guide:ResumeWeakGuideAutoFinishStepTimer()
else
GameInstance.player.guide:PauseWeakGuideAutoFinishStepTimer()
end
end
end
else
if not isForce and v.cell.gameObject.activeSelf ~= false then
v.cell.gameObject:SetActive(false)
GameInstance.player.guide:ResumeWeakGuideAutoFinishStepTimer()
end
end
end
self:_SyncInfoAtFirstUIHighlight(self.m_curUIHighlightInfos[1])
end
if self.m_needRefreshTrackPoint then
self:_RefreshHelperTrackPointDistance()
end
end
GuideCtrl.ShowGuideStep = HL.StaticMethod(HL.Table) << function(args)
local stepInfo, hasFinishCondition = unpack(args)
local self = UIManager:AutoOpen(PANEL_ID)
self:_ClearStep()
if stepInfo.type == GuideStepType.Weak and self:_StopShowWeakGuideIfNeed(stepInfo.uiHighlightInfos) then
return
end
self.m_curStepInfo = stepInfo
self.m_stepStartTime = Time.unscaledTime
self.m_hasFinishCondition = hasFinishCondition or false
self.view.emptyMask.gameObject:SetActiveIfNecessary(false)
self.view.main.gameObject:SetActiveIfNecessary(true)
local isForce = stepInfo.type ~= GuideStepType.Weak
self.m_isCurForceStep = isForce
self:_RefreshUIHighlight(stepInfo.uiHighlightInfos, isForce)
self:_RefreshDialog(stepInfo.textInfos)
self:_RefreshDialogControllerHint(stepInfo, hasFinishCondition == true)
local isMedia = self:_RefreshMedia(stepInfo.mediaInfos)
local isHelper = self:_RefreshHelper()
local needBlockInput = false
local needFullScreenBtn = false
local hasHighlightInfo = stepInfo.uiHighlightInfos.Count > 0
if isForce then
if hasHighlightInfo or not string.isEmpty(stepInfo.enableActionId) or not hasFinishCondition then
needBlockInput = true
end
if not hasFinishCondition and not self.m_waitClickUIHighlight then
needFullScreenBtn = true
end
end
Notify(MessageConst.TOGGLE_LEVEL_CAMERA_MOVE, { "guide", not needBlockInput })
local stopCheckBinding = needBlockInput and not isMedia and not isHelper
CS.Beyond.UI.UIActionKeyHint.s_stopCheckBindingEnabledForGuide = stopCheckBinding
CS.Beyond.UI.UIAutoCloseArea.s_stopCheckShouldClose = needBlockInput
self:ChangeCurPanelBlockSetting(needBlockInput)
local showFullScreenBtn = needFullScreenBtn and not isMedia
self.view.fullScreenBtn.gameObject:SetActive(showFullScreenBtn)
if showFullScreenBtn then
self.m_guideStepInterval = stepInfo.stepInterval
end
if self.m_hasInfoAtUI then
self:_RefreshInfoAtFirstUIHighlightStyle(needFullScreenBtn, isForce)
end
self:_RefreshDialogHintNode(needFullScreenBtn)
self.view.maskImg.gameObject:SetActive(needFullScreenBtn and not self.view.uiHighlightNode.gameObject.activeSelf)
self:_AddTick()
if DeviceInfo.usingController then
if stepInfo.hideControllerHintBar then
UIManager:HideWithKey(PanelId.ControllerHint, "Guide")
end
end
end
GuideCtrl.HideGuideStep = HL.Method(HL.Opt(HL.Any)) << function(self, args)
args = args or {}
local groupInfo, isClientInterrupt = unpack(args)
CS.Beyond.UI.UIActionKeyHint.s_stopCheckBindingEnabledForGuide = false
CS.Beyond.UI.UIAutoCloseArea.s_stopCheckShouldClose = false
Notify(MessageConst.HIDE_GUIDE_MEDIA)
if not self:IsShow(true) then
return
end
self:ChangeCurPanelBlockSetting(false)
self:_Clear()
local groupId = GameInstance.player.guide.curGuideGroupId
if not isClientInterrupt and self.view.dialogNode.gameObject.activeInHierarchy then
for _, node in pairs(self.m_dialogNodeMap) do
if node.animationWrapper.curState == CS.Beyond.UI.UIConst.AnimationState.Out then
return
end
end
local isFirst = true
local animPlay = false
for t, dialogNode in pairs(self.m_dialogNodeMap) do
if dialogNode.gameObject.activeInHierarchy then
if t == TextStyle.InfoAtFirstUIHighlight then
local innerIsFirst = isFirst
animPlay = true
dialogNode.animationWrapper:Play(dialogNode.outAniName, function()
dialogNode.animationWrapper.curState = CS.Beyond.UI.UIConst.AnimationState.Stop
self:_TryHideGuidePanel(groupId)
end, CS.Beyond.UI.UIConst.AnimationState.Out)
else
if isFirst then
animPlay = true
dialogNode.animationWrapper:PlayOutAnimation(function()
self:_TryHideGuidePanel(groupId)
end)
else
animPlay = true
dialogNode.animationWrapper:PlayOutAnimation()
end
end
isFirst = false
end
end
if not animPlay then
self:_TryHideGuidePanel(groupId)
end
else
self:_TryHideGuidePanel(groupId)
end
self.view.uiHighlightNode.gameObject:SetActiveIfNecessary(false)
end
GuideCtrl.ShowGuideEmptyMask = HL.StaticMethod() << function()
local self = UIManager:AutoOpen(PANEL_ID)
self.view.main.gameObject:SetActiveIfNecessary(false)
self:_RefreshEmptyMaskState(true)
end
GuideCtrl.OnPanelOpened = HL.Method(HL.String) << function(self, panelName)
self:_RefreshHelperVisibleStateByPanelOrPhaseState(panelName, true, true)
end
GuideCtrl.OnPanelClosed = HL.Method(HL.String) << function(self, panelName)
self:_RefreshHelperVisibleStateByPanelOrPhaseState(panelName, false, true)
end
GuideCtrl.OnPhaseOpened = HL.Method(HL.String) << function(self, phaseName)
self:_RefreshHelperVisibleStateByPanelOrPhaseState(phaseName, true, false)
end
GuideCtrl.OnPhaseExited = HL.Method(HL.String) << function(self, phaseName)
self:_RefreshHelperVisibleStateByPanelOrPhaseState(phaseName, false, false)
end
GuideCtrl.OnInterruptGuide = HL.Method() << function(self)
self:Hide()
end
GuideCtrl.OnCompleteGuide = HL.Method(HL.Any) << function(self, args)
local groupId, clearPendingGroup = unpack(args)
if clearPendingGroup then
self:_RefreshEmptyMaskState(false)
self:Hide()
end
end
GuideCtrl._RefreshEmptyMaskState = HL.Method(HL.Boolean) << function(self, needShow)
self.view.emptyMask.gameObject:SetActiveIfNecessary(needShow)
CS.Beyond.UI.UIActionKeyHint.s_stopCheckBindingEnabledForGuide = needShow
CS.Beyond.UI.UIAutoCloseArea.s_stopCheckShouldClose = needShow
self:ChangeCurPanelBlockSetting(needShow)
end
GuideCtrl._StopShowWeakGuideIfNeed = HL.Method(HL.Userdata).Return(HL.Boolean) << function(self, highlightInfos)
if highlightInfos == nil or highlightInfos.Count == 0 then
return false
end
for index = 0, highlightInfos.Count - 1 do
local info = highlightInfos[index]
local path = info.path
local trans = self:_GetHighlightTarget(path)
if not NotNull(trans) then
GameInstance.player.guide:OnWeakGuideFindHighlightFailedOnInit()
return true
end
end
return false
end
GuideCtrl._OnClickFakeButton = HL.Method() << function(self)
if self.m_waitClickUIHighlight and not self.m_hasFinishCondition then
self.m_waitClickUIHighlight = false
self:_TryGotoNextStep(false)
end
end
GuideCtrl._TryGotoNextStep = HL.Method(HL.Boolean) << function(self, checkInterval)
if not self.m_curStepInfo then
return
end
if self.m_waitClickUIHighlight then
return
end
if checkInterval and Time.unscaledTime < self.m_stepStartTime + self.m_guideStepInterval then
return
end
GameInstance.player.guide:OnGuideStepUIClicked()
end
GuideCtrl._ClearStep = HL.Method() << function(self)
self.m_waitClickUIHighlight = false
self.m_curUIHighlightInfos = nil
self.m_firstHighlightUICell = nil
self.m_curStepInfo = nil
self.m_guideStepInterval = UIConst.GUIDE_STEP_MIN_INTERVAL
self.m_uiHighlightCells:Update(function(cell)
cell.button:ClearTarget()
end)
UIManager:ShowWithKey(PanelId.ControllerHint, "Guide")
Notify(MessageConst.REFRESH_CONTROLLER_HINT_CONTENT_IMMEDIATELY)
end
GuideCtrl.m_hasInfoAtUI = HL.Field(HL.Boolean) << false
GuideCtrl._RefreshDialog = HL.Method(HL.Userdata) << function(self, textInfos)
if not textInfos or textInfos.Count == 0 then
for _, node in pairs(self.m_dialogNodeMap) do
node.animationWrapper:ClearTween()
end
self.view.dialogNode.gameObject:SetActiveIfNecessary(false)
return
end
self.view.dialogNode.gameObject:SetActiveIfNecessary(true)
self.view.infoAtFirstUIHighlightDialogNode.gameObject:SetActive(false)
self.view.bigLeftTopDialogNode.gameObject:SetActive(false)
self.view.bigLeftBottomDialogNode.gameObject:SetActive(false)
self.view.titleMiddleTopNode.gameObject:SetActive(false)
self.m_hasInfoAtUI = false
for _, info in pairs(textInfos) do
local node = self.m_dialogNodeMap[info.style]
node.gameObject:SetActive(true)
local text = Utils.getGuideText(info.txtId)
local result = InputManager.ParseTextActionId(text)
node.content:SetAndResolveTextStyle(result)
LayoutRebuilder.ForceRebuildLayoutImmediate(node.rectTransform)
if info.style == TextStyle.InfoAtFirstUIHighlight then
self.m_hasInfoAtUI = true
self:_SyncInfoAtFirstUIHighlight(self.m_curUIHighlightInfos[1])
else
node.animationWrapper:PlayInAnimation()
end
end
end
GuideCtrl._RefreshDialogHintNode = HL.Method(HL.Boolean) << function(self, needFullScreenBtn)
for _, dialogNode in pairs(self.m_dialogNodeMap) do
dialogNode.hintNode.gameObject:SetActiveIfNecessary(needFullScreenBtn and not DeviceInfo.usingController)
end
end
GuideCtrl._SyncInfoAtFirstUIHighlight = HL.Method(HL.Table) << function(self, info)
if not info or not self.m_hasInfoAtUI then
return
end
if IsNull(info.targetTrans) then
return
end
local node = self.view.infoAtFirstUIHighlightDialogNode
local hasArrow = self.view.infoAtFirstUIHighlightDialogNode.forceArrow.gameObject.activeInHierarchy
UIUtils.updateTipsPosition(node.rectTransform,
info.targetTrans,
self.view.rectTransform, self.uiCamera,
UIConst.UI_TIPS_POS_TYPE.GuideTips,
self.m_highlightDialogPadding,
hasArrow and self.view.config.DIALOG_NODE_ARROW_OFFSET_X or 0
)
self:_SyncUIHighlightDialogArrowState(info.targetTrans)
local isForce = self.m_curStepInfo.type ~= GuideStepType.Weak
if not isForce then
local isActive = UIUtils.isUIGOActive(info.targetTrans.gameObject) and (not info.button or (info.ignoreBindingEnabled or info.button.groupEnabled))
if node.gameObject.activeSelf ~= isActive then
node.gameObject:SetActive(isActive)
end
end
end
GuideCtrl._RefreshInfoAtFirstUIHighlightStyle = HL.Method(HL.Boolean, HL.Boolean) << function(self, needFullScreenBtn, isForce)
local dialogNode = self.view.infoAtFirstUIHighlightDialogNode
local state = ""
if isForce then
state = needFullScreenBtn and InfoAtFirstHighlightStyle.FullScreenForce or InfoAtFirstHighlightStyle.Force
else
state = InfoAtFirstHighlightStyle.Weak
end
dialogNode.stateController:SetState(state)
local hasArrow = dialogNode.forceArrow.gameObject.activeSelf
local isRight = dialogNode.right
if not hasArrow then
if isForce then
dialogNode.animationWrapper:Play(isRight and "hightdialogcoverright_in" or "hightdialogcoverleft_in")
dialogNode.outAniName = "hightdialogcover_out"
else
dialogNode.animationWrapper:Play(isRight and "hightdialognlowright_in" or "hightdialognlowleft_in")
dialogNode.outAniName = "hightdialognlow_out"
end
else
if isRight then
dialogNode.animationWrapper:Play("hightdialogarrowright_in", function()
dialogNode.animationWrapper:Play("hightdialogarrowright_loop")
end)
dialogNode.outAniName = "hightdialogarrowright_out"
else
dialogNode.animationWrapper:Play("hightdialogarrowleft_in", function()
dialogNode.animationWrapper:Play("hightdialogarrowleft_loop")
end)
dialogNode.outAniName = "hightdialogarrowleft_out"
end
end
end
GuideCtrl._SyncUIHighlightDialogArrowState = HL.Method(HL.Userdata) << function(self, highlightRectTransform)
if highlightRectTransform == nil then
return
end
local dialogNode = self.view.infoAtFirstUIHighlightDialogNode
local dialogScreenRect = UIUtils.getTransformScreenRect(dialogNode.rectTransform, self.uiCamera)
local highlightScreenRect = UIUtils.getTransformScreenRect(highlightRectTransform, self.uiCamera)
local dialogScreenRectHeight = highlightScreenRect.height
local middleRangeOffset = dialogScreenRectHeight * HIGHLIGHT_DIALOG_ARROW_MIDDLE_RANG
local right = highlightScreenRect.center.x > dialogScreenRect.center.x
dialogNode.right = right
if not dialogNode.forceArrow.gameObject.activeInHierarchy then
return
end
local up = highlightScreenRect.center.y < dialogScreenRect.center.y
local middle = highlightScreenRect.center.y >= dialogScreenRect.center.y - middleRangeOffset and
highlightScreenRect.center.y <= dialogScreenRect.center.y + middleRangeOffset
local arrowX, arrowY
if middle then
arrowY = 0
else
local halfHeight = dialogNode.rectTransform.rect.height / 2 + self.view.config.UI_HIGHLIGHT_DIALOG_ARROW_OFFSET_Y
arrowY = up and halfHeight or -halfHeight
end
local halfWidth = dialogNode.rectTransform.rect.width / 2 + self.view.config.UI_HIGHLIGHT_DIALOG_ARROW_OFFSET_X
arrowX = right and halfWidth or -halfWidth
if right then
arrowX = arrowX + RIGHT_ARROW_MODIFIED_OFFSET
end
dialogNode.forceArrow.anchoredPosition = Vector2(arrowX, arrowY)
dialogNode.forceArrow.localScale = Vector3(right and -1 or 1, 1, 1)
end
GuideCtrl._TryHideGuidePanel = HL.Method(HL.String) << function(self, lastGroupId)
local curGroupId = GameInstance.player.guide.curGuideGroupId
local pendingGroupId = GameInstance.player.guide.pendingGuideGroupId
local nextGroupId = string.isEmpty(curGroupId) and pendingGroupId or curGroupId
if not string.isEmpty(nextGroupId) and lastGroupId ~= curGroupId then
return
end
self:Hide()
end
GuideCtrl.m_curHideMediaTime = HL.Field(HL.Number) << -1
local FORCE_HIDE_MEDIA_TIMER_DURATION = 3
GuideCtrl._RefreshMedia = HL.Method(HL.Userdata).Return(HL.Boolean) << function(self, mediaInfos)
local count = mediaInfos.Count
if not mediaInfos or count == 0 then
Notify(MessageConst.HIDE_GUIDE_MEDIA)
return false
end
self.m_curHideMediaTime = -1
Notify(MessageConst.SHOW_GUIDE_MEDIA, {
mediaInfos = mediaInfos,
onComplete = function()
if self:_ForceHideMediaIfNeed() then
return
end
self:_TryGotoNextStep(false)
end
})
return true
end
GuideCtrl._ForceHideMediaIfNeed = HL.Method().Return(HL.Boolean) << function(self)
if self.m_curStepInfo ~= nil then
self.m_curHideMediaTime = Time.time
return false
end
if self.m_curHideMediaTime > 0 and Time.time - self.m_curHideMediaTime > FORCE_HIDE_MEDIA_TIMER_DURATION then
self:HideGuideStep()
self.m_curHideMediaTime = -1
logger.error(ELogChannel.Guide, "图文引导", GameInstance.player.guide.curGuideGroupId, "未正常关闭")
return true
end
return false
end
GuideCtrl.m_needRefreshTrackPoint = HL.Field(HL.Boolean) << false
GuideCtrl.m_curTrackPointKey = HL.Field(HL.String) << ""
GuideCtrl.m_helperCoverVisible = HL.Field(HL.Boolean) << false
GuideCtrl._RefreshHelper = HL.Method().Return(HL.Boolean) << function(self)
if self.m_curStepInfo.type ~= GuideStepType.ForceHelper then
self.view.helperNode.animationWrapper:PlayOutAnimation(function()
self.view.helperNode.gameObject:SetActiveIfNecessary(false)
end)
return false
end
local helperNode = self.view.helperNode
local helperInfo = self.m_curStepInfo.helperInfo
local contentText = Utils.getGuideText(helperInfo.contentTextId)
helperNode.content:SetAndResolveTextStyle(InputManager.ParseTextActionId(contentText))
local useCustomImage = not string.isEmpty(helperInfo.helperImagePath)
if useCustomImage then
helperNode.customHelperImage:LoadSprite(UIConst.UI_SPRITE_GUIDE, helperInfo.helperImagePath)
end
helperNode.defaultHelperImage.gameObject:SetActiveIfNecessary(not useCustomImage)
helperNode.customHelperImage.gameObject:SetActiveIfNecessary(useCustomImage)
self.m_needRefreshTrackPoint = not string.isEmpty(helperInfo.trackingPointKey)
self.m_curTrackPointKey = helperInfo.trackingPointKey
helperNode.targetNode.gameObject:SetActiveIfNecessary(self.m_needRefreshTrackPoint)
helperNode.switchButton.onClick:RemoveAllListeners()
helperNode.switchButton.onClick:AddListener(function()
self:_RefreshHelperCoverVisibleState(not self.m_helperCoverVisible)
end)
self:_RefreshHelperCoverVisibleState(true)
helperNode.controlNode.gameObject:SetActiveIfNecessary(true)
helperNode.gameObject:SetActiveIfNecessary(true)
helperNode.animationWrapper:PlayInAnimation()
if self.m_needRefreshTrackPoint then
self:_RefreshHelperTrackPointDistance()
end
return true
end
GuideCtrl._RefreshHelperTrackPointDistance = HL.Method() << function(self)
if string.isEmpty(self.m_curTrackPointKey) then
return
end
local distance = GameInstance.player.commonTrackingSystem:GetDistanceByTrackingPointKey(self.m_curTrackPointKey)
if distance > 0 then
self.view.helperNode.targetNode.distanceText.text = string.format("%d", math.floor(distance))
self.view.helperNode.targetNode.gameObject:SetActive(true)
else
self.view.helperNode.targetNode.gameObject:SetActive(false)
end
end
GuideCtrl._RefreshHelperCoverVisibleState = HL.Method(HL.Boolean) << function(self, isVisible)
if isVisible then
self.view.helperNode.cover:PlayInAnimation()
else
self.view.helperNode.cover:PlayOutAnimation()
end
self.view.helperNode.switchIcon.localScale = Vector3(isVisible and 1 or -1, 1, 1)
self.m_helperCoverVisible = isVisible
end
GuideCtrl._RefreshHelperVisibleStateByPanelOrPhaseState = HL.Method(HL.String, HL.Boolean, HL.Boolean) << function(self, name, isOpened, isPanel)
if not self:IsShow() or not self.view.helperNode.gameObject.activeSelf then
return
end
local invisibleList = isPanel and
Tables.globalConst.guideHelperInvisiblePanelList or
Tables.globalConst.guideHelperInvisiblePhaseList
local isInvisible = false
for _, invisibleName in pairs(invisibleList) do
if invisibleName == name then
isInvisible = isOpened
if not isInvisible then
self.view.helperNode.animationWrapper:PlayInAnimation()
self.view.helperNode.controlNode.gameObject:SetActiveIfNecessary(true)
else
self.view.helperNode.animationWrapper:PlayOutAnimation(function()
self.view.helperNode.controlNode.gameObject:SetActiveIfNecessary(false)
end)
end
break
end
end
end
GuideCtrl._RefreshUIHighlight = HL.Method(HL.Userdata, HL.Boolean) << function(self, highlightInfos, needMask)
if not highlightInfos or highlightInfos.Count == 0 then
self.view.uiHighlightNode.gameObject:SetActiveIfNecessary(false)
return
end
self.view.uiHighlightNode.gameObject:SetActiveIfNecessary(true)
Notify(MessageConst.REFRESH_CONTROLLER_HINT_CONTENT_IMMEDIATELY)
self.m_curUIHighlightInfos = {}
local showDrag = false
self.view.dragHint.hand:DOKill()
self.m_uiHighlightCells:Refresh(highlightInfos.Count, function(cell, index)
local info = highlightInfos[CSIndex(index)]
self:_HighlightUITarget(cell, info, needMask)
if index == 1 then
self.m_firstHighlightUICell = cell
end
if info.hintType == HintType.DragFrom or info.hintType == HintType.DragTo then
showDrag = true
end
end)
self.view.dragHint.gameObject:SetActiveIfNecessary(showDrag)
if showDrag then
self.view.dragHint.hand.anchoredPosition = Vector2.zero
self.view.dragHint.hand:DOMove(self.view.dragHint.toPosition, 1.3, false):SetEase(CS.DG.Tweening.Ease.OutFlash):SetLoops(-1, CS.DG.Tweening.LoopType.Restart)
end
end
GuideCtrl._HighlightUITarget = HL.Method(HL.Table, CS.Beyond.Gameplay.GuideUIHighlightInfo, HL.Boolean)
<< function(self, cell, info, needMask)
local path = info.path
local trans, is3DUI = self:_GetHighlightTarget(path)
if not trans then
logger.error(ELogChannel.Guide, "引导", GameInstance.player.guide.curGuideGroupId, "UI路径不对", path)
if BEYOND_DEBUG then
Notify(MessageConst.SHOW_TOAST, string.format("引导的UI路径不对 %s\n详情看Log", path))
self:_ShowCompleteGuidePopup()
end
return
end
if string.startWith(path, "ItemTipsPanel") then
Notify(MessageConst.TOGGLE_ITEM_TIPS_AUTO_CLOSE, false)
end
trans = trans:GetComponent("RectTransform")
needMask = needMask and info.needBlackMask
local isCircle = info.shape == CS.Beyond.Gameplay.GuideUIHighlightInfo.Shape.Circle
if isCircle then
cell.simpleStateController:SetState(needMask and "Circle" or "CircleNoMask")
else
cell.simpleStateController:SetState("Rect")
cell.forceFrame.gameObject:SetActive(self.m_isCurForceStep)
cell.weakFrame.gameObject:SetActive(not self.m_isCurForceStep)
end
cell.animationWrapper:PlayInAnimation(function()
cell.animationWrapper:Play(isCircle and "guideuihighlight_loop02" or "guideuihighlight_loop01")
end)
local targetRect = UIUtils.getUIRectOfRectTransform(trans, is3DUI and CameraManager.mainCamera or self.uiCamera)
self:_SyncUIHighlightTargetRect(cell, targetRect, needMask, isCircle)
local uiInfo = {
cell = cell,
targetTrans = trans,
oriName = trans.gameObject.name,
is3DUI = is3DUI,
path = info.path,
isCircle = isCircle,
needMask = needMask,
ignoreBindingEnabled = info.ignoreBindingEnabled,
}
table.insert(self.m_curUIHighlightInfos, uiInfo)
cell.gameObject:SetActive(true)
local needClick, needClickHint = false, false
local button, toggle, dropdown, keyHint = self:_GetClickTarget(trans)
uiInfo.button = button
if info.hintType == HintType.Click and info.useClickHint then
needClickHint = button ~= nil or toggle ~= nil or dropdown ~= nil or keyHint ~= nil
end
cell.clickHint.gameObject:SetActive(needClickHint)
if self.m_isCurForceStep then
if info.hintType == HintType.Click then
if button or toggle or dropdown or keyHint then
needClick = true
self.m_waitClickUIHighlight = true
cell.button.targetButton = button
cell.button.targetToggle = toggle
cell.button.targetDropdown = dropdown
cell.button.targetKeyHintActionId = keyHint and keyHint:GetActionId() or nil
cell.button.onClick = function()
self:_OnClickFakeButton()
end
cell.button:CopyTargetBinding()
else
logger.error(ELogChannel.Guide, "引导", GameInstance.player.guide.curGuideGroupId, "该路径下没有可点击对象", info.path)
end
elseif info.hintType == HintType.DragFrom then
self.view.dragHint.rectTransform.anchoredPosition = cell.rectTransform.anchoredPosition
if button then
cell.button.targetButton = button
cell.button:ForceToggleTargetBinding(true, true)
end
elseif info.hintType == HintType.DragTo then
self.view.dragHint.toPosition = cell.rectTransform.position
local vector = cell.rectTransform.anchoredPosition - self.view.dragHint.rectTransform.anchoredPosition
local line = self.view.dragHint.line
line.sizeDelta = Vector2(line.sizeDelta.x, vector.magnitude)
line.localEulerAngles = Vector3(0, 0, Vector2.SignedAngle(Vector2.down, vector))
if button or toggle or dropdown then
cell.button.targetButton = button
cell.button.targetToggle = toggle
cell.button.targetDropdown = dropdown
cell.button:ForceToggleTargetBinding(true, true)
end
end
end
cell.button.gameObject:SetActive(needClick)
if DeviceInfo.usingController and info.autoNaviToThisTarget then
local selectable = button or toggle or dropdown
if selectable then
InputManagerInst.controllerNaviManager:SetTarget(selectable)
else
logger.error(ELogChannel.Guide, "引导", GameInstance.player.guide.curGuideGroupId, "找不到 Selectable无法自动手柄Navi", path)
end
end
end
GuideCtrl._GetHighlightTarget = HL.Method(HL.String).Return(HL.Userdata, HL.Boolean) << function(self, path)
local trans = UIManager.uiRoot.transform:Find(path)
local is3DUI = false
if not trans then
trans = UIManager.worldUIRoot.transform:Find(path)
if not trans then
trans = GameObject.Find(path)
is3DUI = true
end
end
return trans, is3DUI
end
GuideCtrl._GetClickTarget = HL.Method(Transform).Return(HL.Opt(HL.Any, HL.Any, HL.Any, HL.Any)) << function(self, trans)
local targets = {}
local targetTypes = {
typeof(CS.Beyond.UI.UIButton),
typeof(CS.Beyond.UI.UIToggle),
typeof(CS.Beyond.UI.UIDropdown),
typeof(CS.Beyond.UI.UIActionKeyHint),
}
for k, t in ipairs(targetTypes) do
local target = trans:GetComponent(t)
if target then
targets[k] = target
return targets[1], targets[2], targets[3], targets[4]
end
end
for k, t in ipairs(targetTypes) do
local target = trans:GetComponentInChildren(t)
if target then
targets[k] = target
return targets[1], targets[2], targets[3], targets[4]
end
end
for k, t in ipairs(targetTypes) do
local target = trans:GetComponentInParent(t)
if target then
targets[k] = target
return targets[1], targets[2], targets[3], targets[4]
end
end
end
GuideCtrl._SyncUIHighlightTargetRect = HL.Method(HL.Table, Unity.Rect, HL.Boolean, HL.Boolean) << function(self, cell, targetRect, needMask, isCircle)
if DeviceInfo.usingController then
local extraSize = self.view.config.CONTROLLER_HIGHLIGHT_EXTRA_SIZE
targetRect = UIUtils.addRectSizeKeepCenter(targetRect, extraSize.x, extraSize.y)
end
local rectTrans = cell.rectTransform
rectTrans.anchoredPosition = Vector2(targetRect.center.x, -targetRect.center.y)
if isCircle then
local size = math.max(targetRect.size.x, targetRect.size.y)
rectTrans.sizeDelta = Vector2(size, size)
else
rectTrans.sizeDelta = targetRect.size
end
if cell.clickHint.gameObject.activeSelf then
local clickHintRect = UIUtils.getTransformScreenRect(rectTrans, self.uiCamera)
local ratio = (Screen.width - clickHintRect.center.x) / Screen.width
local handOutOfScreen = ratio <= USE_LEFT_HAND_WIDTH_RATIO
cell.clickHintRightHand.gameObject:SetActive(not handOutOfScreen)
cell.clickHintLeftHand.gameObject:SetActive(handOutOfScreen)
end
cell.maskNode.gameObject:SetActiveIfNecessary(needMask)
if not needMask then
return
end
local width = UIManager.uiCanvasRect.rect.size.x
local height = UIManager.uiCanvasRect.rect.size.y
local xOffset = width / 2 - targetRect.center.x
cell.up.anchoredPosition = Vector2(xOffset, 0)
cell.down.anchoredPosition = Vector2(xOffset, 0)
cell.up.sizeDelta = Vector2(width, targetRect.y)
cell.down.sizeDelta = Vector2(width, height - targetRect.yMax)
cell.left.sizeDelta = Vector2(targetRect.x, targetRect.height)
cell.right.sizeDelta = Vector2(width - targetRect.xMax, targetRect.height)
local otherCell = self.m_firstHighlightUICell
if otherCell and otherCell ~= cell then
local selfRect = {
xMin = rectTrans.anchoredPosition.x - rectTrans.sizeDelta.x / 2,
xMax = rectTrans.anchoredPosition.x + rectTrans.sizeDelta.x / 2,
yMin = rectTrans.anchoredPosition.y - rectTrans.sizeDelta.y / 2,
yMax = rectTrans.anchoredPosition.y + rectTrans.sizeDelta.y / 2,
}
local otherRect = {
xMin = otherCell.rectTransform.anchoredPosition.x - otherCell.rectTransform.sizeDelta.x / 2,
xMax = otherCell.rectTransform.anchoredPosition.x + otherCell.rectTransform.sizeDelta.x / 2,
yMin = otherCell.rectTransform.anchoredPosition.y - otherCell.rectTransform.sizeDelta.y / 2,
yMax = otherCell.rectTransform.anchoredPosition.y + otherCell.rectTransform.sizeDelta.y / 2,
}
if otherRect.yMin >= selfRect.yMax then
self:_AdjustVerticalTargetMasks(otherCell, cell, otherRect.yMin - selfRect.yMax)
elseif selfRect.yMin > otherRect.yMax then
self:_AdjustVerticalTargetMasks(cell, otherCell, selfRect.yMin - otherRect.yMax)
elseif otherRect.xMin >= selfRect.xMax then
self:_AdjustHorizontalTargetMasks(otherCell, cell, otherRect.xMin - selfRect.xMax)
elseif selfRect.xMin > otherRect.xMax then
self:_AdjustHorizontalTargetMasks(cell, otherCell, selfRect.xMin - otherRect.xMax)
else
end
end
end
GuideCtrl._AdjustVerticalTargetMasks = HL.Method(HL.Table, HL.Table, HL.Number) << function(self, upCell, downCell, height)
upCell.down.sizeDelta = Vector2(upCell.down.sizeDelta.x, height)
downCell.up.sizeDelta = Vector2.zero
end
GuideCtrl._AdjustHorizontalTargetMasks = HL.Method(HL.Table, HL.Table, HL.Number)
<< function(self, rightCell, leftCell, uiWidth)
local width = UIManager.uiCanvasRect.rect.size.x
local halfRightItemWidth = rightCell.rectTransform.sizeDelta.x / 2
local rightHorMaskWidth = width - rightCell.rectTransform.anchoredPosition.x + uiWidth + halfRightItemWidth
local rightHorOffsetX = rightHorMaskWidth / 2 - uiWidth - halfRightItemWidth
rightCell.up.sizeDelta = Vector2(rightHorMaskWidth, rightCell.up.sizeDelta.y)
rightCell.up.anchoredPosition = Vector2(rightHorOffsetX, 0)
rightCell.down.sizeDelta = Vector2(rightHorMaskWidth, rightCell.down.sizeDelta.y)
rightCell.down.anchoredPosition = Vector2(rightHorOffsetX, 0)
rightCell.left.sizeDelta = Vector2(uiWidth, rightCell.left.sizeDelta.y)
local leftItemWidth = leftCell.rectTransform.sizeDelta.x
local leftHorMaskWidth = leftCell.rectTransform.anchoredPosition.x + leftItemWidth
local leftHorOffsetX = leftHorMaskWidth / 2 - leftCell.rectTransform.anchoredPosition.x - leftItemWidth / 2
leftCell.up.sizeDelta = Vector2(leftHorMaskWidth, leftCell.up.sizeDelta.y)
leftCell.up.anchoredPosition = Vector2(leftHorOffsetX, 0)
leftCell.down.sizeDelta = Vector2(leftHorMaskWidth, leftCell.down.sizeDelta.y)
leftCell.down.anchoredPosition = Vector2(leftHorOffsetX, 0)
leftCell.right.sizeDelta = Vector2.zero
end
GuideCtrl._SetHighlightTargetMask = HL.Method(HL.Table, HL.Boolean) << function(self, cell, enable)
cell.upImage.raycastTarget = enable
cell.downImage.raycastTarget = enable
cell.leftImage.raycastTarget = enable
cell.rightImage.raycastTarget = enable
end
GuideCtrl.m_controllerHintTextList = HL.Field(HL.Table)
GuideCtrl.m_controllerHintNodeList = HL.Field(HL.Table)
GuideCtrl._ConvertTextInfosStyle = HL.Method(HL.Userdata, HL.Userdata) << function(self, textInfos, uiHighlightInfos)
if not textInfos or textInfos.Count == 0 then
return
end
if not uiHighlightInfos or uiHighlightInfos.Count == 0 then
return
end
local firstHighlight = uiHighlightInfos[0]
if firstHighlight == nil then
return
end
local highlightPath = firstHighlight.path
if string.isEmpty(highlightPath) then
return
end
for _, info in pairs(textInfos) do
info.style = TextStyle.InfoAtFirstUIHighlight
end
end
GuideCtrl._InitDialogControllerHint = HL.Method() << function(self)
if not DeviceInfo.usingController then
return
end
self.m_controllerHintTextList = {
self.view.bigLeftBottomDialogNode.controllerHintText,
self.view.bigLeftTopDialogNode.controllerHintText,
self.view.titleMiddleTopNode.controllerHintText,
self.view.infoAtFirstUIHighlightDialogNode.controllerHintText,
}
self.m_controllerHintNodeList = {
self.view.bigLeftBottomDialogNode.controllerHintNode,
self.view.bigLeftTopDialogNode.controllerHintNode,
self.view.titleMiddleTopNode.controllerHintNode,
self.view.infoAtFirstUIHighlightDialogNode.controllerHintNode,
}
self:_RefreshControllerHintText()
self:_RefreshDialogControllerHintNodeList(false)
end
GuideCtrl._RefreshControllerHintText = HL.Method() << function(self)
if self.m_controllerHintTextList == nil then
return
end
for _, hintText in ipairs(self.m_controllerHintTextList) do
if hintText ~= nil then
local result = InputManager.ParseTextActionId(Language["ui_common_next_step"])
hintText:SetAndResolveTextStyle(result)
end
end
end
GuideCtrl._OnControllerTypeChanged = HL.Method(HL.Any) << function(self, args)
self:_RefreshControllerHintText()
end
GuideCtrl._RefreshDialogControllerHintNodeList = HL.Method(HL.Boolean) << function(self, active)
if not DeviceInfo.usingController then
return
end
if self.m_controllerHintNodeList == nil then
return
end
for _, hintNode in ipairs(self.m_controllerHintNodeList) do
if hintNode ~= nil then
hintNode.gameObject:SetActiveIfNecessary(active)
end
end
end
GuideCtrl._RefreshDialogControllerHint = HL.Method(HL.Userdata, HL.Boolean) << function(self, stepInfo, hasFinishCondition)
self:_RefreshDialogControllerHintNodeList(false)
if not DeviceInfo.usingController then
return
end
if stepInfo == nil or stepInfo.type == GuideStepType.Weak or not string.isEmpty(stepInfo.enableActionId) or hasFinishCondition then
return
end
local highlightInfos = stepInfo.uiHighlightInfos
if highlightInfos ~= nil and highlightInfos.Count > 0 then
local firstHighlightHintInfo = highlightInfos[0]
if firstHighlightHintInfo == nil or firstHighlightHintInfo.hintType ~= HintType.None then
return
end
end
self:_RefreshDialogControllerHintNodeList(true)
end
if BEYOND_DEBUG then
GuideCtrl._ShowCompleteGuidePopup = HL.Method() << function(self)
local offset = 5
local guideSortingOrder = self:GetSortingOrder()
local lastSortingOrder
Notify(MessageConst.SHOW_POP_UP, {
content = "引导状态异常,是否直接跳过该引导",
freezeWorld = true,
hideBlur = true,
onConfirm = function()
GameInstance.player.guide:CompleteCurGuideGroupForDebug()
local _, popupCtrl = UIManager:IsOpen(PanelId.CommonPopUp)
popupCtrl:SetSortingOrder(lastSortingOrder, false)
end,
onCancel = function()
local _, popupCtrl = UIManager:IsOpen(PanelId.CommonPopUp)
popupCtrl:SetSortingOrder(lastSortingOrder, false)
end,
})
local _, popupCtrl = UIManager:IsOpen(PanelId.CommonPopUp)
lastSortingOrder = popupCtrl:GetSortingOrder()
popupCtrl:SetSortingOrder(guideSortingOrder + offset, false)
end
end
HL.Commit(GuideCtrl)