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

764 lines
22 KiB
Lua

local uiCtrl = require_ex('UI/Panels/Base/UICtrl')
local PANEL_ID = PanelId.FacSquirter
local SoilState = {
None = 0,
Spraying = 1,
Paused = 2,
Invalid = 3,
Completed = 4,
Waiting = 5,
NotInStep = 6,
}
local OutState = {
None = "None",
Idle = "Idle",
Spraying = "Spraying",
Stopped = "Stopped",
}
local SMART_ALERT_FUNCTION_NAME_LIST = {
"_CheckAlertNoPowerCondition",
"_CheckAlertNoPowerWithDiffuserCondition",
"_CheckAlertNoPowerWithoutDiffuserCondition",
"_CheckAlertCanBeOpenedCondition",
"_CheckAlertLiquidTypeCannotDumpedCondition",
"_CheckAlertDiffTypeLiquidCannotSprayedCondition",
}
FacSquirterCtrl = HL.Class('FacSquirterCtrl', uiCtrl.UICtrl)
local SOIL_CELL_PROGRESS_TWEEN_DURATION = 0.25
local SQUIRTER_SPRITES_FOLDER_PATH = "Factory/Squirter"
local INVALID_ITEM_TEXT_ID = "ui_fac_squirter_different_liquid"
local INVALID_SOIL_NODES_TEXT_ID = "ui_fac_squirter_no_target_info"
FacSquirterCtrl.m_buildingInfo = HL.Field(CS.Beyond.Gameplay.RemoteFactory.BuildingUIInfo_FluidSpray)
FacSquirterCtrl.m_updateThread = HL.Field(HL.Thread)
FacSquirterCtrl.m_soilNodeDataList = HL.Field(HL.Table)
FacSquirterCtrl.m_needUpdateSoilNodes = HL.Field(HL.Boolean) << false
FacSquirterCtrl.m_soilCellConfig = HL.Field(HL.Table)
FacSquirterCtrl.m_validLiquidIds = HL.Field(HL.Table)
FacSquirterCtrl.m_soilCellTweenList = HL.Field(HL.Table)
FacSquirterCtrl.m_soilCells = HL.Field(HL.Forward('UIListCache'))
FacSquirterCtrl.m_outState = HL.Field(HL.String) << ""
FacSquirterCtrl.s_messages = HL.StaticField(HL.Table) << {
}
FacSquirterCtrl.OnCreate = HL.Override(HL.Any) << function(self, arg)
self.m_buildingInfo = arg.uiInfo
self.view.inventoryArea:InitInventoryArea({
customOnUpdateCell = function(cell, itemBundle)
self:_RefreshInventoryItemCell(cell, itemBundle)
end,
customSetActionMenuArgs = function(actionMenuArgs)
actionMenuArgs.cacheRepo = self.view.facCacheRepository
end,
onStateChange = function()
self:_RefreshNaviGroupSwitcherInfos()
end,
isFluidOnlyMachine = true,
})
self.view.facCacheRepository:InitFacCacheRepository({
cache = self.m_buildingInfo.sprayCache,
isInCache = true,
isFluidCache = true,
cacheIndex = 1,
slotCount = 1,
})
self.view.facCachePipe:InitFacCachePipe(self.m_buildingInfo, {
useSinglePipe = true,
})
self.view.buildingCommon:InitBuildingCommon(self.m_buildingInfo, {
smartAlertFuncNameList = SMART_ALERT_FUNCTION_NAME_LIST,
targetCtrlInstance = self
})
GameInstance.remoteFactoryManager:RegisterInterestedUnitId(self.m_buildingInfo.nodeId)
self:_UpdateSmartAlertCache()
self:_InitSquirterStaticData()
self:_InitSquirterBasicContent()
self:_InitSquirterSoilCellColorConfig()
self:_InitSquirterSoilNodes()
self:_InitSquirterUpdateThread()
self:_InitFacMachineCrafterController()
self.view.facCacheRepository.view.repoNaviGroup:NaviToThisGroup()
end
FacSquirterCtrl.OnClose = HL.Override() << function(self)
self.view.buildingCommon:ClearSmartAlertUpdate()
GameInstance.remoteFactoryManager:UnregisterInterestedUnitId(self.m_buildingInfo.nodeId)
if self.m_soilCellTweenList ~= nil then
for _, tween in pairs(self.m_soilCellTweenList) do
if tween ~= nil then
tween:Kill(false)
end
end
end
end
FacSquirterCtrl._InitSquirterUpdateThread = HL.Method() << function(self)
self:_UpdateAndRefreshOutState()
self.m_updateThread = self:_StartCoroutine(function()
while true do
self:_RefreshSquirterSpeed()
self:_UpdateAndRefreshOutState()
self:_UpdateAndRefreshSquirterAllSoilNodesState()
coroutine.step()
end
end)
end
FacSquirterCtrl._InitSquirterStaticData = HL.Method() << function(self)
self.m_validLiquidIds = {}
local success, tableData = Tables.factoryFluidSprayTable:TryGetValue(self.m_buildingInfo.buildingId)
if not success then
return
end
for index = 0, tableData.validItemIds.Count - 1 do
self.m_validLiquidIds[tableData.validItemIds[index]] = true
end
end
FacSquirterCtrl._InitSquirterBasicContent = HL.Method() << function(self)
local success, tableData = Tables.factoryFluidSprayTable:TryGetValue(self.m_buildingInfo.buildingId)
if not success then
return
end
self.view.speedNode.maxSpeedText.text = string.format("%d", tableData.maximumSuply)
self:_RefreshSquirterSpeed()
end
FacSquirterCtrl._RefreshSquirterSpeed = HL.Method() << function(self)
local speed = self.m_buildingInfo.fluidSpray.lastRoundSprayCount
self.view.speedNode.currSpeedText.text = string.format("%d", speed)
self.view.speedNode.currSpeedText.color = speed > 0 and self.view.config.NORMAL_COLOR or self.view.config.STOPPED_COLOR
end
FacSquirterCtrl._IsCurrentCacheItemValid = HL.Method().Return(HL.Boolean) << function(self)
local cacheItemId = ""
for id, _ in cs_pairs(self.m_buildingInfo.sprayCache.items) do
if not string.isEmpty(id) then
cacheItemId = id
break
end
end
return string.isEmpty(cacheItemId) or self.m_validLiquidIds[cacheItemId] == true
end
FacSquirterCtrl._UpdateAndRefreshOutState = HL.Method() << function(self)
local state = OutState.None
local isValidSoilNodes = #self.m_soilNodeDataList > 0
local isValidItem = self:_IsCurrentCacheItemValid()
if not isValidItem or not isValidSoilNodes then
state = OutState.Stopped
else
local speed = self.m_buildingInfo.fluidSpray.lastRoundSprayCount
state = speed > 0 and OutState.Spraying or OutState.Idle
end
if state == self.m_outState then
return
end
self.view.outNode.stateController:SetState(state)
local isStopped = state == OutState.Stopped
if isStopped then
local text = ""
if not isValidSoilNodes then
text = Language[INVALID_SOIL_NODES_TEXT_ID]
else
local cacheItemId = ""
for id, _ in cs_pairs(self.m_buildingInfo.sprayCache.items) do
if not string.isEmpty(id) then
cacheItemId = id
break
end
end
local canBeDischarge = FactoryUtils.getLiquidCanBeDischarge(cacheItemId)
if not canBeDischarge then
text = string.format(Language.LUA_LIQUID_CANT_DISCHARGE_IN_SQUIRTER, UIUtils.getItemName(cacheItemId))
else
text = Language[INVALID_ITEM_TEXT_ID]
end
end
self.view.tipsTextNode.tipsText.text = text
end
UIUtils.PlayAnimationAndToggleActive(self.view.tipsTextNode.animationWrapper, isStopped)
UIUtils.PlayAnimationAndToggleActive(self.view.outNode.blockedAnim, isStopped)
self.m_outState = state
end
FacSquirterCtrl._InitSquirterSoilCellColorConfig = HL.Method() << function(self)
self.m_soilCellConfig = {
[SoilState.Spraying] = {
iconId = "icon_squirter_play",
iconColor = self.view.config.NORMAL_COLOR,
progressColor = self.view.config.NORMAL_COLOR,
stateText = Language["ui_fac_squirter_soil_spraying"],
},
[SoilState.Paused] = {
iconId = "icon_squirter_pause",
iconColor = self.view.config.PAUSED_COLOR,
progressColor = self.view.config.PAUSED_COLOR,
stateText = Language["ui_fac_squirter_soil_pause"],
},
[SoilState.Invalid] = {
iconId = "icon_squirter_error",
iconColor = self.view.config.INVALID_COLOR,
progressColor = self.view.config.INVALID_COLOR,
stateText = Language["ui_fac_squirter_soil_different"],
},
[SoilState.Completed] = {
iconId = "icon_squirter_select",
iconColor = self.view.config.COMPLETE_COLOR,
progressColor = self.view.config.NORMAL_COLOR,
stateText = Language["ui_fac_squirter_soil_complete"],
},
[SoilState.Waiting] = {
iconId = "icon_squirter_omit",
iconColor = self.view.config.PAUSED_COLOR,
progressColor = self.view.config.PAUSED_COLOR,
stateText = Language["ui_fac_squirter_soil_waiting"],
hideProgress = true,
},
[SoilState.NotInStep] = {
iconId = "icon_squirter_omit",
iconColor = self.view.config.PAUSED_COLOR,
progressColor = self.view.config.PAUSED_COLOR,
stateText = Language["ui_fac_squirter_soil_step_invalid"],
hideProgress = true,
},
}
end
FacSquirterCtrl._InitSquirterSoilNodes = HL.Method() << function(self)
local soilNodes = self.m_buildingInfo:GetProcessingSoilNodes()
self.m_soilNodeDataList = {}
self.m_soilCellTweenList = {}
for _, soilNode in cs_pairs(soilNodes) do
local nodeHandler = FactoryUtils.getBuildingNodeHandler(soilNode)
if nodeHandler ~= nil then
local soilComponent = nodeHandler:GetComponentInPosition(GEnums.FCComponentPos.Soil:GetHashCode())
if soilComponent ~= nil and soilComponent.soil ~= nil then
table.insert(self.m_soilNodeDataList, {
nodeHandler = nodeHandler,
soilComponent = soilComponent.soil,
state = SoilState.None,
})
end
end
end
if #self.m_soilNodeDataList == 0 then
self.view.targetNode.emptyNode.gameObject:SetActiveIfNecessary(true)
self.view.targetNode.soilList.gameObject:SetActiveIfNecessary(false)
self.m_needUpdateSoilNodes = false
return
end
self.m_soilCells = UIUtils.genCellCache(self.view.targetNode.soilCell)
self.m_soilCells:Refresh(#self.m_soilNodeDataList, function(cell, index)
self:_RefreshSquirterSoilNodeBasicContent(cell, index)
self:_UpdateAndRefreshSquirterSoilNodeState(cell, index, true)
end)
self.view.targetNode.emptyNode.gameObject:SetActiveIfNecessary(false)
self.view.targetNode.soilList.gameObject:SetActiveIfNecessary(true)
self.m_needUpdateSoilNodes = true
end
FacSquirterCtrl._RefreshSquirterSoilNodeBasicContent = HL.Method(HL.Any, HL.Number) << function(self, cell, index)
if cell == nil then
return
end
local data = self.m_soilNodeDataList[index]
if data == nil then
return
end
local success, facBuildingData = Tables.factoryBuildingTable:TryGetValue(data.nodeHandler.templateId)
if not success then
return
end
cell.titleNode.text.text = facBuildingData.name
end
FacSquirterCtrl._UpdateAndRefreshSquirterAllSoilNodesState = HL.Method() << function(self)
if not self.m_needUpdateSoilNodes then
return
end
local cellCount = self.m_soilCells:GetCount()
for index = 1, cellCount do
local cell = self.m_soilCells:GetItem(index)
self:_UpdateAndRefreshSquirterSoilNodeState(cell, index, false)
end
end
FacSquirterCtrl._UpdateAndRefreshSquirterSoilNodeState = HL.Method(HL.Any, HL.Number, HL.Boolean) << function(self, cell, index, firstRefresh)
if cell == nil then
return
end
local data = self.m_soilNodeDataList[index]
if data == nil then
return
end
local success, stepsData = Tables.plantingDataTable:TryGetValue(data.nodeHandler.templateId)
if not success then
return
end
local state = SoilState.None
local step = data.soilComponent.stepCursor
local stepData = stepsData.plantingSteps[step]
local stepType = stepData.plantingStepType
local currProgress, totalProgress = data.soilComponent.waterGot, -1
if stepType ~= GEnums.PlantingStepType.Water then
if step == 0 then
state = SoilState.NotInStep
else
local lastStepType = stepsData.plantingSteps[step - 1].plantingStepType
local isCompleted = lastStepType == GEnums.PlantingStepType.Water
state = isCompleted and SoilState.Completed or SoilState.NotInStep
if isCompleted then
currProgress = totalProgress
end
end
else
local valueIntList = stepData.plantingStepParameter.valueIntList
totalProgress = valueIntList[valueIntList.Count - 1]
if currProgress == totalProgress then
state = SoilState.Completed
else
if not self:_IsCurrentCacheItemValid() then
state = SoilState.Invalid
else
if currProgress <= 0 then
state = SoilState.Waiting
else
local currSpeed = self.m_buildingInfo.fluidSpray.lastRoundSprayCount
state = currSpeed > 0 and SoilState.Spraying or SoilState.Paused
end
end
end
end
if state == data.state and not firstRefresh and state ~= SoilState.Spraying then
return
end
local config = self.m_soilCellConfig[state]
if config == nil then
return
end
cell.stateNode.icon:LoadSprite(SQUIRTER_SPRITES_FOLDER_PATH, config.iconId)
cell.stateNode.icon.color = config.iconColor
cell.progressNode.progressBar.color = config.progressColor
cell.stateNode.text.text = config.stateText
if not config.hideProgress then
local targetAmount = currProgress / totalProgress
if firstRefresh then
cell.progressNode.progressBar.fillAmount = targetAmount
else
if self.m_soilCellTweenList[index] ~= nil then
self.m_soilCellTweenList[index]:Kill(false)
end
self.m_soilCellTweenList[index] = DOTween.To(function()
return cell.progressNode.progressBar.fillAmount
end, function(amount)
cell.progressNode.progressBar.fillAmount = amount
end, targetAmount, SOIL_CELL_PROGRESS_TWEEN_DURATION)
end
cell.progressNode.content.gameObject:SetActiveIfNecessary(true)
else
cell.progressNode.content.gameObject:SetActiveIfNecessary(false)
end
if firstRefresh then
if state == SoilState.Invalid then
self:_RefreshSquirterSoilNodeAnimState(cell, state)
end
else
if data.state ~= state then
self:_RefreshSquirterSoilNodeAnimState(cell, state)
end
end
data.state = state
end
FacSquirterCtrl._RefreshSquirterSoilNodeAnimState = HL.Method(HL.Any, HL.Number) << function(self, cell, state)
local animName = "facsquirtersoil_change"
if state == SoilState.Invalid then
animName = "facsquirtersoil_loop"
elseif state == SoilState.Completed then
animName = "facsquirtersoil_done"
end
if cell.stateAnim.curStateName == animName then
return
end
cell.stateAnim:PlayWithTween(animName)
end
FacSquirterCtrl._RefreshInventoryItemCell = HL.Method(HL.Userdata, HL.Any) << function(self, cell, itemBundle)
if cell == nil or itemBundle == nil then
return
end
local itemId = itemBundle.id
local isEmptyBottle = Tables.emptyBottleTable:ContainsKey(itemId)
local isFullBottle = Tables.fullBottleTable:ContainsKey(itemId)
local isBottle = isEmptyBottle or isFullBottle
local isEmpty = string.isEmpty(itemBundle.id)
cell.view.forbiddenMask.gameObject:SetActiveIfNecessary(not isBottle and not isEmpty)
cell.view.dragItem.enabled = isBottle
cell.view.dropItem.enabled = isBottle or isEmpty
end
FacSquirterCtrl.m_naviGroupSwitcher = HL.Field(HL.Forward('NaviGroupSwitcher'))
FacSquirterCtrl._InitFacMachineCrafterController = HL.Method() << function(self)
local NaviGroupSwitcher = require_ex("Common/Utils/UI/NaviGroupSwitcher").NaviGroupSwitcher
self.m_naviGroupSwitcher = NaviGroupSwitcher(self.view.inputGroup.groupId, nil, true)
self:_RefreshNaviGroupSwitcherInfos()
end
FacSquirterCtrl._RefreshNaviGroupSwitcherInfos = HL.Method() << function(self)
if self.m_naviGroupSwitcher == nil then
return
end
local naviGroupInfos = {
{
naviGroup = self.view.facCacheRepository.view.repoNaviGroup,
text = Language.LUA_INV_NAVI_SWITCH_TO_MACHINE
}
}
self.view.inventoryArea:AddNaviGroupSwitchInfo(naviGroupInfos)
self.m_naviGroupSwitcher:ChangeGroupInfos(naviGroupInfos)
end
FacSquirterCtrl.m_smartAlertTargetTransformCache = HL.Field(HL.Table)
FacSquirterCtrl._UpdateSmartAlertCache = HL.Method() << function(self)
self.m_smartAlertTargetTransformCache = {}
self.m_smartAlertTargetTransformCache.state = self.view.buildingCommon.view.stateNode.transform
local list = self.view.facCacheRepository:GetRepositorySlotList()
if list[1] ~= nil then
self.m_smartAlertTargetTransformCache.fluidCache = list[1].transform
end
end
FacSquirterCtrl._CheckAlertCanBeOpenedCondition = HL.Method(HL.Userdata).Return(HL.Boolean, HL.Opt(HL.Table)) << function(self, state)
if self.view.buildingCommon.smartAlertChangeCachePauseUpdate or state ~= GEnums.FacBuildingState.Closed then
return false
end
local node = self.m_buildingInfo.nodeHandler
if node and node.power and node.power.powerCost then
local curCost = node.power.powerCost
local powerInfo = FactoryUtils.getCurRegionPowerInfo()
local powerCost = powerInfo.powerCost
local powerGen = powerInfo.powerGen
if powerCost + curCost <= powerGen then
local checkOpen = DeviceInfo.usingController and
self:GetSortingOrder() >= UIManager:CurBlockKeyboardEventPanelOrder()
local alertInfo = {
condition = GEnums.FacSmartAlertType.CanBeOpened,
targetTransform = self.m_smartAlertTargetTransformCache.state,
defaultOpen = checkOpen
}
return true, alertInfo
end
end
return false
end
FacSquirterCtrl._CheckAlertNoPowerWithoutDiffuserCondition = HL.Method(HL.Userdata).Return(HL.Boolean, HL.Opt(HL.Table)) << function(self, state)
if self.view.buildingCommon.smartAlertChangeCachePauseUpdate or state ~= GEnums.FacBuildingState.NotInPowerNet then
return false
end
if self.m_buildingInfo.inPowerRangeDiffusers.Count <= 0 then
local checkOpen = DeviceInfo.usingController and
self:GetSortingOrder() >= UIManager:CurBlockKeyboardEventPanelOrder()
local alertInfo = {
condition = GEnums.FacSmartAlertType.NoPowerWithoutDiffuser,
targetTransform = self.m_smartAlertTargetTransformCache.state,
defaultOpen = checkOpen
}
return true, alertInfo
end
return false
end
FacSquirterCtrl._CheckAlertNoPowerWithDiffuserCondition = HL.Method(HL.Userdata).Return(HL.Boolean, HL.Opt(HL.Table)) << function(self, state)
if self.view.buildingCommon.smartAlertChangeCachePauseUpdate or state ~= GEnums.FacBuildingState.NotInPowerNet then
return false
end
if self.m_buildingInfo.inPowerRangeDiffusers.Count > 0 then
local checkOpen = DeviceInfo.usingController and
self:GetSortingOrder() >= UIManager:CurBlockKeyboardEventPanelOrder()
local alertInfo = {
condition = GEnums.FacSmartAlertType.NoPowerWithDiffuser,
targetTransform = self.m_smartAlertTargetTransformCache.state,
defaultOpen = checkOpen
}
return true, alertInfo
end
return false
end
FacSquirterCtrl._CheckAlertNoPowerCondition = HL.Method(HL.Userdata).Return(HL.Boolean, HL.Opt(HL.Table)) << function(self, state)
if self.view.buildingCommon.smartAlertChangeCachePauseUpdate or state ~= GEnums.FacBuildingState.NoPower then
return false
end
local checkOpen = DeviceInfo.usingController and
self:GetSortingOrder() >= UIManager:CurBlockKeyboardEventPanelOrder()
local alertInfo = {
condition = GEnums.FacSmartAlertType.NoPower,
targetTransform = self.m_smartAlertTargetTransformCache.state,
defaultOpen = checkOpen
}
return true, alertInfo
end
FacSquirterCtrl._CheckAlertLiquidTypeCannotDumpedCondition = HL.Method(HL.Userdata).Return(HL.Boolean, HL.Opt(HL.Table)) << function(self, state)
if self.view.buildingCommon.smartAlertChangeCachePauseUpdate or state ~= GEnums.FacBuildingState.Idle then
return false
end
local cacheItemId = ""
for id, _ in cs_pairs(self.m_buildingInfo.sprayCache.items) do
if not string.isEmpty(id) then
cacheItemId = id
break
end
end
if not string.isEmpty(cacheItemId) and not FactoryUtils.getLiquidCanBeDischarge(cacheItemId) then
local checkOpen = DeviceInfo.usingController and
self.view.facCacheRepository.view.repoNaviGroup.IsTopLayer and
self:GetSortingOrder() >= UIManager:CurBlockKeyboardEventPanelOrder()
local alertInfo = {
condition = GEnums.FacSmartAlertType.LiquidTypeCannotDumped,
targetTransform = self.m_smartAlertTargetTransformCache.fluidCache,
args = {},
checkRefresh = cacheItemId,
defaultOpen = checkOpen
}
table.insert(alertInfo.args, UIUtils.getItemName(cacheItemId))
table.insert(alertInfo.args, UIUtils.getItemName(cacheItemId))
return true, alertInfo
end
return false
end
FacSquirterCtrl._CheckAlertDiffTypeLiquidCannotSprayedCondition = HL.Method(HL.Userdata).Return(HL.Boolean, HL.Opt(HL.Table)) << function(self, state)
if self.view.buildingCommon.smartAlertChangeCachePauseUpdate or state ~= GEnums.FacBuildingState.Idle then
return false
end
local cacheItemId = ""
for id, _ in cs_pairs(self.m_buildingInfo.sprayCache.items) do
if not string.isEmpty(id) then
cacheItemId = id
break
end
end
if not string.isEmpty(cacheItemId) and not self.m_validLiquidIds[cacheItemId] then
local checkOpen = DeviceInfo.usingController and
self.view.facCacheRepository.view.repoNaviGroup.IsTopLayer and
self:GetSortingOrder() >= UIManager:CurBlockKeyboardEventPanelOrder()
local alertInfo = {
condition = GEnums.FacSmartAlertType.DiffTypeLiquidCannotSprayed,
targetTransform = self.m_smartAlertTargetTransformCache.fluidCache,
args = {},
checkRefresh = cacheItemId,
defaultOpen = checkOpen
}
table.insert(alertInfo.args, UIUtils.getItemName(cacheItemId))
return true, alertInfo
end
return false
end
HL.Commit(FacSquirterCtrl)