Files
Endfield-Data/LuaScripts/UI/Panels/ChallengeDungeon/ChallengeDungeonCtrl.lua
2025-12-02 20:37:18 +07:00

750 lines
24 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 uiCtrl = require_ex('UI/Panels/Base/UICtrl')
local PANEL_ID = PanelId.ChallengeDungeon
local PHASE_ID = PhaseId.ChallengeDungeon
ChallengeDungeonCtrl = HL.Class('ChallengeDungeonCtrl', uiCtrl.UICtrl)
local activitySystem = GameInstance.player.activitySystem
local dungeonManager = GameInstance.dungeonManager
local DungeonStateEnum = {
Lock = 0,
Unlock = 1,
Complete = 2,
PerfectComplete = 3,
}
ChallengeDungeonCtrl.s_messages = HL.StaticField(HL.Table) << {
[MessageConst.ON_SUB_GAME_UNLOCK] = '_OnSubGameUnlock',
[MessageConst.ON_ACTIVITY_GAME_ENTRANCE_UNLOCK] = '_OnSeriesUnlock',
[MessageConst.ON_SYSTEM_DISPLAY_SIZE_CHANGED] = '_OnDisplaySizeChanged',
}
ChallengeDungeonCtrl.m_info = HL.Field(HL.Table)
ChallengeDungeonCtrl.m_getTabCellFunc = HL.Field(HL.Function)
ChallengeDungeonCtrl.m_getDungeonCellFunc = HL.Field(HL.Function)
ChallengeDungeonCtrl.m_batchMarkListCache = HL.Field(HL.Forward("UIListCache"))
ChallengeDungeonCtrl.m_updateTimeCor = HL.Field(HL.Thread)
ChallengeDungeonCtrl.m_readRedDotDungeonTempList = HL.Field(HL.Table)
ChallengeDungeonCtrl.m_viewedDungeonIds = HL.Field(HL.Table)
ChallengeDungeonCtrl.m_curRedDotDungeonIds = HL.Field(HL.Table)
ChallengeDungeonCtrl.OnCreate = HL.Override(HL.Any) << function(self, arg)
self:_InitUI()
self:_InitData(arg)
self:_UpdateData()
self:_RefreshAllUI()
end
ChallengeDungeonCtrl.OnClose = HL.Override() << function(self)
self.m_updateTimeCor = self:_ClearCoroutine(self.m_updateTimeCor)
local seriesInfo = self.m_info.seriesInfos[self.m_info.curSelectSeriesIndex]
if ActivityUtils.isNewGameEntranceSeries(seriesInfo.seriesId) then
ActivityUtils.setFalseNewGameEntranceSeries(seriesInfo.seriesId)
end
self:_TryClearReadDungeon()
end
ChallengeDungeonCtrl._InitData = HL.Method(HL.Any) << function(self, arg)
local activityId = ""
if type(arg) == "string" then
activityId = arg
else
activityId = arg.activityId
end
self.m_info = {
activityId = activityId,
curSelectSeriesIndex = 1,
seriesInfos = {},
}
self.m_readRedDotDungeonTempList = {}
self:_InitSeriesInfo()
end
ChallengeDungeonCtrl._InitSeriesInfo = HL.Method() << function(self)
local _, seriesCfg = Tables.activityGameEntranceSeriesTable:TryGetValue(self.m_info.activityId)
for seriesId, seriesSingleCfg in pairs(seriesCfg.seriesMap) do
local seriesInfo = {
seriesId = seriesId,
seriesName = seriesSingleCfg.name,
sortId = seriesSingleCfg.sortId,
allDungeonInfos = {
},
dungeonBatchInfos = {
},
totalDungeonCount = 0,
achievementId = seriesSingleCfg.achieveId,
isUnlock = false,
openTime = "",
perfectCompleteCount = 0,
hasBatchIsLock = false,
lockBatchIndex = 0,
}
table.insert(self.m_info.seriesInfos, seriesInfo)
self:_InitAllDungeonInfo(seriesInfo)
self:_InitDungeonBatchInfo(seriesInfo)
end
table.sort(self.m_info.seriesInfos, Utils.genSortFunction({ "sortId" }, true))
end
ChallengeDungeonCtrl._InitAllDungeonInfo = HL.Method(HL.Table) << function(self, seriesInfo)
local seriesId = seriesInfo.seriesId
local _, activityGameCfg = Tables.activityGameEntranceGameTable:TryGetValue(seriesId)
for _, gameCfg in pairs(activityGameCfg.gameList) do
local dungeonId = gameCfg.gameId
local _, dungeonCfg = Tables.dungeonTable:TryGetValue(dungeonId)
if dungeonCfg then
local rewardInfos = {}
local _, firstRewardCfg = Tables.rewardTable:TryGetValue(dungeonCfg.firstPassRewardId)
if firstRewardCfg then
for _, item in pairs(firstRewardCfg.itemBundles) do
local itemCfg = Tables.itemTable[item.id]
local rewardInfo = {
id = item.id,
count = item.count,
isFirst = true,
gainedSortId = 0,
typeSortId = 1,
raritySort = -itemCfg.rarity,
sortId1 = -itemCfg.sortId1,
sortId2 = itemCfg.sortId2,
}
table.insert(rewardInfos, rewardInfo)
end
end
local _, extraRewardCfg = Tables.rewardTable:TryGetValue(dungeonCfg.extraRewardId)
if extraRewardCfg then
for _, item in pairs(extraRewardCfg.itemBundles) do
local itemCfg = Tables.itemTable[item.id]
local rewardInfo = {
id = item.id,
count = item.count,
isFirst = false,
gainedSortId = 0,
typeSortId = 2,
raritySort = -itemCfg.rarity,
sortId1 = -itemCfg.sortId1,
sortId2 = itemCfg.sortId2,
}
table.insert(rewardInfos, rewardInfo)
end
end
local dungeonInfo = {
dungeonId = dungeonId,
sceneId = dungeonCfg.sceneId,
dungeonName = dungeonCfg.dungeonName,
timeOffset = gameCfg.timeOffset,
rewardInfos = rewardInfos,
hasFirstReward = firstRewardCfg ~= nil,
hasExtraReward = extraRewardCfg ~= nil,
dungeonState = DungeonStateEnum.Lock,
unlockTime = 0,
collectChestNum = 0,
maxChestNum = 0,
sortId = gameCfg.sortId,
}
table.insert(seriesInfo.allDungeonInfos, dungeonInfo)
else
logger.error(string.format("解密活动对应副本不存在系列id%s副本id%s", seriesId, dungeonId))
end
end
seriesInfo.totalDungeonCount = #seriesInfo.allDungeonInfos
table.sort(seriesInfo.allDungeonInfos, Utils.genSortFunction({ "sortId" }, true))
end
ChallengeDungeonCtrl._InitDungeonBatchInfo = HL.Method(HL.Table) << function(self, seriesInfo)
local curBatchTimeOffset = -1
local dungeonBatchInfo
local allPreBatchDungeonCount = 0
for _, dungeonInfo in pairs(seriesInfo.allDungeonInfos) do
if curBatchTimeOffset ~= dungeonInfo.timeOffset then
curBatchTimeOffset = dungeonInfo.timeOffset
if dungeonBatchInfo ~= nil then
allPreBatchDungeonCount = allPreBatchDungeonCount + #dungeonBatchInfo.dungeonInfos
end
dungeonBatchInfo = {
timeOffset = curBatchTimeOffset,
allPreBatchDungeonCount = allPreBatchDungeonCount,
dungeonInfos = {},
unlockTime = dungeonInfo.unlockTime,
}
table.insert(seriesInfo.dungeonBatchInfos, dungeonBatchInfo)
end
table.insert(dungeonBatchInfo.dungeonInfos, dungeonInfo)
end
end
ChallengeDungeonCtrl._UpdateData = HL.Method() << function(self)
for _, seriesInfo in pairs(self.m_info.seriesInfos) do
self:_UpdateSeriesInfo(seriesInfo)
end
end
ChallengeDungeonCtrl._UpdateSeriesInfo = HL.Method(HL.Table) << function(self, seriesInfo)
local seriesId = seriesInfo.seriesId
local activityData = activitySystem:GetActivity(self.m_info.activityId)
if activityData == nil then
logger.error("ActivityData为空ActivityId" .. self.m_info.activityId)
return
end
local hasData, seriesData = activityData.seriesDataMap:TryGetValue(seriesId)
if not hasData then
logger.error("副本活动数据缺失系列id" .. seriesId)
return
end
seriesInfo.isUnlock = activitySystem:IsGameEntranceSeriesUnlock(seriesId)
seriesInfo.openTime = seriesData.OpenTime
self:_UpdateAllDungeonInfo(seriesInfo)
self:_UpdateDungeonBatchInfo(seriesInfo)
end
ChallengeDungeonCtrl._UpdateAllDungeonInfo = HL.Method(HL.Table) << function(self, seriesInfo)
seriesInfo.perfectCompleteCount = 0
local rewardSortKeys = UIConst.COMMON_ITEM_SORT_KEYS
table.insert(rewardSortKeys, 1, "typeSortId")
table.insert(rewardSortKeys, 1, "gainedSortId")
for _, dungeonInfo in pairs(seriesInfo.allDungeonInfos) do
local dungeonId = dungeonInfo.dungeonId
local curTime = DateTimeUtils.GetCurrentTimestampBySeconds()
dungeonInfo.unlockTime = seriesInfo.openTime + dungeonInfo.timeOffset * Const.SEC_PER_HOUR
local isUnlock = dungeonManager:IsDungeonUnlocked(dungeonId) and curTime >= dungeonInfo.unlockTime
local isComplete = dungeonManager:IsDungeonPassed(dungeonId)
dungeonInfo.collectChestNum, dungeonInfo.maxChestNum = DungeonUtils.getDungeonChestCount(dungeonInfo.sceneId)
local isGetFirstReward = not dungeonInfo.hasFirstReward or dungeonManager:IsDungeonFirstPassRewardGained(dungeonId)
local isGetExtraReward = not dungeonInfo.hasExtraReward or dungeonManager:IsDungeonExtraRewardGained(dungeonId)
local isGetAllChest = (dungeonInfo.maxChestNum < 1 or dungeonInfo.collectChestNum >= dungeonInfo.maxChestNum)
local isPerfectComplete = isComplete and isGetFirstReward and isGetExtraReward and isGetAllChest
if isUnlock then
if isComplete then
if isPerfectComplete then
dungeonInfo.dungeonState = DungeonStateEnum.PerfectComplete
seriesInfo.perfectCompleteCount = seriesInfo.perfectCompleteCount + 1
else
dungeonInfo.dungeonState = DungeonStateEnum.Complete
end
else
dungeonInfo.dungeonState = DungeonStateEnum.Unlock
end
else
dungeonInfo.dungeonState = DungeonStateEnum.Lock
end
for _, rewardInfo in pairs(dungeonInfo.rewardInfos) do
if rewardInfo.isFirst then
rewardInfo.isGet = isGetFirstReward
rewardInfo.gainedSortId = isGetFirstReward and 1 or 0
else
rewardInfo.isGet = isGetExtraReward
rewardInfo.gainedSortId = isGetExtraReward and 1 or 0
end
end
table.sort(dungeonInfo.rewardInfos, Utils.genSortFunction(rewardSortKeys, true))
end
end
ChallengeDungeonCtrl._UpdateDungeonBatchInfo = HL.Method(HL.Table) << function(self, seriesInfo)
local firstLockIndex = -1
local batchCount = #seriesInfo.dungeonBatchInfos
for index = 1, batchCount do
local dungeonBatchInfo = seriesInfo.dungeonBatchInfos[index]
local isLock = dungeonBatchInfo.dungeonInfos[1].dungeonState == DungeonStateEnum.Lock
if isLock then
firstLockIndex = index
break
end
end
seriesInfo.hasBatchIsLock = firstLockIndex > 0
seriesInfo.lockBatchIndex = firstLockIndex
end
ChallengeDungeonCtrl._InitUI = HL.Method() << function(self)
self.view.commonTopTitlePanel.btnClose.onClick:AddListener(function()
PhaseManager:PopPhase(PHASE_ID)
end)
self.view.controllerHintPlaceholder:InitControllerHintPlaceholder({ self.view.inputGroup.groupId })
self.m_getTabCellFunc = UIUtils.genCachedCellFunction(self.view.tabList)
self.view.tabList.onUpdateCell:AddListener(function(obj, csIndex)
local cell = self.m_getTabCellFunc(obj)
self:_RefreshTabCell(cell, LuaIndex(csIndex))
end)
self.m_getDungeonCellFunc = UIUtils.genCachedCellFunction(self.view.dungeonList)
self.view.dungeonList.onUpdateCell:AddListener(function(obj, csIndex)
local cell = self.m_getDungeonCellFunc(obj)
self:_RefreshDungeonCell(cell, LuaIndex(csIndex))
end)
self.m_batchMarkListCache = UIUtils.genCellCache(self.view.overviewNode.batchMark)
local preActionId = self.view.keyHintLeft.actionId
local nextActionId = self.view.keyHintRight.actionId
self:BindInputPlayerAction(preActionId, function()
local count = #self.m_info.seriesInfos
local newIndex = (self.m_info.curSelectSeriesIndex + count - 2) % count + 1
if newIndex ~= self.m_info.curSelectSeriesIndex then
self:_OnChangeSeriesTab(newIndex)
self.view.tabList:ScrollToIndex(CSIndex(newIndex))
end
end)
self:BindInputPlayerAction(nextActionId, function()
local count = #self.m_info.seriesInfos
local newIndex = self.m_info.curSelectSeriesIndex % count + 1
if newIndex ~= self.m_info.curSelectSeriesIndex then
self:_OnChangeSeriesTab(newIndex)
self.view.tabList:ScrollToIndex(CSIndex(newIndex))
end
end)
end
ChallengeDungeonCtrl._RefreshAllUI = HL.Method() << function(self)
self.view.tabList:UpdateCount(math.max(#self.m_info.seriesInfos, 2))
self:_RefreshContentUI(self.m_info.curSelectSeriesIndex)
end
ChallengeDungeonCtrl._RefreshContentUI = HL.Method(HL.Number) << function(self, seriesIndex)
self.m_info.curSelectSeriesIndex = seriesIndex
local seriesInfo = self.m_info.seriesInfos[seriesIndex]
local progress = seriesInfo.perfectCompleteCount / seriesInfo.totalDungeonCount
local overviewNode = self.view.overviewNode
overviewNode.seriesNameTxt.text = seriesInfo.seriesName
overviewNode.progressBar.fillAmount = progress
overviewNode.curProgTxt.text = seriesInfo.perfectCompleteCount
overviewNode.maxProgTxt.text = seriesInfo.totalDungeonCount
local batchCount = #seriesInfo.dungeonBatchInfos
self.m_batchMarkListCache:Refresh(batchCount, function(cell, luaIndex)
local rotation = cell.transform.localEulerAngles
local dungeonBatchInfo = seriesInfo.dungeonBatchInfos[luaIndex]
rotation.z = dungeonBatchInfo.allPreBatchDungeonCount / seriesInfo.totalDungeonCount * -360
cell.transform.localEulerAngles = rotation
end)
overviewNode.dungeonMedal:InitCommonMedalNode(seriesInfo.achievementId)
self.m_curRedDotDungeonIds = {}
for _, dungeonInfo in pairs(seriesInfo.allDungeonInfos) do
if RedDotManager:GetRedDotState("AdventureDungeonCell", { dungeonInfo.dungeonId }) then
table.insert(self.m_curRedDotDungeonIds, dungeonInfo.dungeonId)
end
end
self.m_updateTimeCor = self:_ClearCoroutine(self.m_updateTimeCor)
if seriesInfo.isUnlock then
self.view.mainStateCtrl:SetState("Unlock")
local count = 0
if seriesInfo.hasBatchIsLock then
local dungeonBatchInfo = seriesInfo.dungeonBatchInfos[seriesInfo.lockBatchIndex]
count = dungeonBatchInfo.allPreBatchDungeonCount + 1
else
count = seriesInfo.totalDungeonCount
end
self.m_viewedDungeonIds = {}
self.view.dungeonList:UpdateCount(count, true)
local obj = self.view.dungeonList:Get(0)
local firstCell = self.m_getDungeonCellFunc(obj)
if firstCell then
InputManagerInst.controllerNaviManager:SetTarget(firstCell.naviDecorator)
end
else
self.view.mainStateCtrl:SetState("Lock")
end
self.m_updateTimeCor = self:_ClearCoroutine(self.m_updateTimeCor)
self.view.keyHintContent.gameObject:SetActive(#self.m_info.seriesInfos > 1)
end
ChallengeDungeonCtrl._RefreshTabCell = HL.Method(HL.Any, HL.Number) << function(self, cell, luaIndex)
if luaIndex > #self.m_info.seriesInfos then
cell.stateCtrl:SetState("Empty")
cell.btn.enabled = false
cell.redDot:Stop()
return
end
local seriesInfo = self.m_info.seriesInfos[luaIndex]
cell.btn.enabled = true
cell.nameTxt.text = seriesInfo.seriesName
if seriesInfo.isUnlock then
cell.stateCtrl:SetState("Unlock")
if seriesInfo.perfectCompleteCount >= seriesInfo.totalDungeonCount then
cell.stateCtrl:SetState("AllComplete")
end
else
cell.stateCtrl:SetState("Lock")
end
cell.btn.onClick:RemoveAllListeners()
cell.btn.onClick:AddListener(function()
self:_OnChangeSeriesTab(luaIndex)
end)
cell.stateCtrl:SetState(self.m_info.curSelectSeriesIndex ~= luaIndex and "UnSelect" or "Select")
cell.redDot:InitRedDot("ActivityNormalChallengeSeries", seriesInfo.seriesId)
end
ChallengeDungeonCtrl._RefreshDungeonCell = HL.Method(HL.Any, HL.Number) << function(self, cell, luaIndex)
local seriesInfo = self.m_info.seriesInfos[self.m_info.curSelectSeriesIndex]
local dungeonInfo = seriesInfo.allDungeonInfos[luaIndex]
local dungeonId = dungeonInfo.dungeonId
local isUnread = GameInstance.player.subGameSys:IsGameUnread(dungeonId)
if dungeonInfo.dungeonState == DungeonStateEnum.Lock then
cell.stateController:SetState("Lock")
self.m_updateTimeCor = self:_ClearCoroutine(self.m_updateTimeCor)
self.m_updateTimeCor = self:_StartCoroutine(function()
while true do
local curTime = DateTimeUtils.GetCurrentTimestampBySeconds()
if curTime <= dungeonInfo.unlockTime then
local leftTime = dungeonInfo.unlockTime - curTime
cell.unlockTimeTxt.text = UIUtils.getLeftTime(leftTime)
else
self.m_updateTimeCor = self:_ClearCoroutine(self.m_updateTimeCor)
self:_UpdateData()
self:_RefreshAllUI()
end
coroutine.wait(1)
end
end)
else
cell.stateController:SetState("Unlock")
cell.titleTxt.text = dungeonInfo.dungeonName
cell.gameObject.name = dungeonId
if dungeonInfo.dungeonState == DungeonStateEnum.PerfectComplete then
cell.stateController:SetState("PerfectComplete")
elseif dungeonInfo.dungeonState == DungeonStateEnum.Complete then
cell.stateController:SetState("Complete")
else
cell.stateController:SetState("UnComplete")
end
if cell.getRewardCellFunc == nil then
cell.getRewardCellFunc = UIUtils.genCellCache(cell.rewardCell)
end
cell.getRewardCellFunc:Refresh(#dungeonInfo.rewardInfos, function(rewardCell, rewardLuaIndex)
local rewardInfo = dungeonInfo.rewardInfos[rewardLuaIndex]
rewardCell:InitItem(rewardInfo, function()
UIUtils.showItemSideTips(rewardCell)
end)
rewardCell:SetExtraInfo({ isSideTips = DeviceInfo.usingController })
if DeviceInfo.usingController then
rewardCell:SetEnableHoverTips(false)
else
rewardCell:SetEnableHoverTips(true)
end
rewardCell.view.rewardedCover.gameObject:SetActive(rewardInfo.isGet)
rewardCell.view.extraTagStateCtrl.gameObject:SetActive(not rewardInfo.isGet)
if not rewardInfo.isGet then
if rewardInfo.isFirst then
rewardCell.view.extraTagStateCtrl:SetState("First")
else
rewardCell.view.extraTagStateCtrl:SetState("Extra")
end
end
end)
local firstCell = cell.getRewardCellFunc:Get(1)
cell.keyHintContent:SetParent(firstCell.view.transform)
cell.keyHintContent.anchoredPosition = Vector2(-74, 0)
cell.rewardListNaviGroup.onIsFocusedChange:RemoveAllListeners()
cell.rewardListNaviGroup.onIsFocusedChange:AddListener(function(isFocused)
if not isFocused then
Notify(MessageConst.HIDE_ITEM_TIPS)
end
end)
if dungeonInfo.maxChestNum > 0 then
cell.chestNumNode.gameObject:SetActive(true)
cell.chestNumTxt.text = dungeonInfo.collectChestNum .. "/" .. dungeonInfo.maxChestNum
else
cell.chestNumNode.gameObject:SetActive(false)
end
cell.gotoBtn.onClick:RemoveAllListeners()
cell.gotoBtn.onClick:AddListener(function()
local enterDungeonCallback = function(enterDungeonId)
LuaSystemManager.uiRestoreSystem:AddRequest(enterDungeonId, function()
PhaseManager:OpenPhaseFast(PhaseId.ChallengeDungeon, self.m_info.activityId)
end)
end
Notify(MessageConst.ON_OPEN_DUNGEON_ENTRY_PANEL, { dungeonId, enterDungeonCallback })
if isUnread then
GameInstance.player.subGameSys:SendSubGameListRead({ dungeonId })
end
end)
end
cell.redDot:InitRedDot("AdventureDungeonCell", { dungeonId })
if isUnread then
table.insert(self.m_readRedDotDungeonTempList, dungeonId)
end
self.m_viewedDungeonIds[dungeonId] = true
self:_RefreshBottomRedDot()
cell.animationWrapper:Play("challengedungeoncell_in")
end
ChallengeDungeonCtrl._RefreshBottomRedDot = HL.Method() << function(self)
if self.m_curRedDotDungeonIds == nil or self.m_viewedDungeonIds == nil then
self.view.listOutsideRedDot.gameObject:SetActive(false)
return
end
for _, id in pairs(self.m_curRedDotDungeonIds) do
if self.m_viewedDungeonIds[id] == nil then
self.view.listOutsideRedDot.gameObject:SetActive(true)
return
end
end
self.view.listOutsideRedDot.gameObject:SetActive(false)
end
ChallengeDungeonCtrl._OnSubGameUnlock = HL.Method(HL.Any) << function(self, arg)
local dungeonId = unpack(arg)
if DungeonUtils.isDungeonChallenge(dungeonId) then
self:_UpdateData()
self:_RefreshAllUI()
end
end
ChallengeDungeonCtrl._OnSeriesUnlock = HL.Method(HL.Any) << function(self, arg)
local seriesId = unpack(arg)
for _, seriesInfo in pairs(self.m_info.seriesInfos) do
if seriesInfo.seriesId == seriesId then
self:_UpdateData()
self:_RefreshAllUI()
break
end
end
end
ChallengeDungeonCtrl._OnChangeSeriesTab = HL.Method(HL.Number) << function(self, luaIndex)
local oldIndex = self.m_info.curSelectSeriesIndex
if oldIndex ~= luaIndex then
local oldObj = self.view.tabList:Get(CSIndex(oldIndex))
local oldCell = self.m_getTabCellFunc(oldObj)
if oldCell then
oldCell.animationWrapper:Play("challengedungeonselected_out")
end
local newObj = self.view.tabList:Get(CSIndex(luaIndex))
local newCell = self.m_getTabCellFunc(newObj)
if newCell then
newCell.animationWrapper:Play("challengedungeonselected_in")
end
self:_RefreshContentUI(luaIndex)
self.view.dungeonNodeAniWrapper:Play("challengedungeonlist_change")
self:_TryClearReadDungeon()
local seriesInfo = self.m_info.seriesInfos[luaIndex]
if ActivityUtils.isNewGameEntranceSeries(seriesInfo.seriesId) then
ActivityUtils.setFalseNewGameEntranceSeries(seriesInfo.seriesId)
end
end
end
ChallengeDungeonCtrl._TryClearReadDungeon = HL.Method() << function(self)
if #self.m_readRedDotDungeonTempList > 0 then
GameInstance.player.subGameSys:SendSubGameListRead(self.m_readRedDotDungeonTempList)
end
self.m_readRedDotDungeonTempList = {}
end
ChallengeDungeonCtrl._OnDisplaySizeChanged = HL.Method() << function(self)
self:_RefreshAllUI()
end
HL.Commit(ChallengeDungeonCtrl)