local UIWidgetBase = require_ex('Common/Core/UIWidgetBase') local LuaNodeCache = require_ex('Common/Utils/LuaNodeCache') local CommonCache = require_ex('Common/Utils/CommonCache') BlueprintPreview = HL.Class('BlueprintPreview', UIWidgetBase) local uiSizePerUnit = 128 BlueprintPreview.m_csBP = HL.Field(CS.Beyond.Gameplay.RemoteFactory.RemoteFactoryBlueprint) BlueprintPreview.m_nodeCellCache = HL.Field(LuaNodeCache) BlueprintPreview.m_conveyorCellCache = HL.Field(LuaNodeCache) BlueprintPreview.m_showingCellDic = HL.Field(HL.Table) BlueprintPreview.m_previewHelper = HL.Field(CS.Beyond.UI.BlueprintPreviewHelper) BlueprintPreview.m_canEdit = HL.Field(HL.Boolean) << false BlueprintPreview.m_updateId = HL.Field(HL.Number) << -1 BlueprintPreview.m_nextTargetId = HL.Field(HL.Number) << 1 BlueprintPreview.m_id2Cell = HL.Field(HL.Table) BlueprintPreview.m_bpAbnormalIconHelper = HL.Field(HL.Table) BlueprintPreview.mouseShow = HL.Field(HL.Boolean) << true local NodeType = { Building = 1, Logistic = 2, Belt = 3, Pipe = 4, } local Face2Vector2 = { [0] = Vector2(0, 1), [1] = Vector2(1, 0), [2] = Vector2(0, -1), [3] = Vector2(-1, 0), } local Face2RotZForConveyor = { [0] = 90, [1] = 0, [2] = -90, [3] = 180, } local Face2RotZForBuilding = { [0] = 360, [1] = 270, [2] = 180, [3] = 90, } BlueprintPreview._OnFirstTimeInit = HL.Override() << function(self) self.m_nodeCellCache = LuaNodeCache(self.view.nodeCell, self.view.content) self.m_conveyorCellCache = LuaNodeCache(self.view.conveyorCell, self.view.content) self.m_previewHelper = CS.Beyond.UI.BlueprintPreviewHelper() self.view.maskBtn.onClick:AddListener(function() self:_OnClick() end) self:_InitChangeIconNode() local secondCellObj = CSUtils.CreateObject(self.view.hoverTipsCell.gameObject, self.view.hoverTipsNode) secondCellObj.name = "HoverTipsCell2" secondCellObj.transform:SetAsLastSibling() self.view.hoverTipsCell2 = Utils.wrapLuaNode(secondCellObj) end BlueprintPreview.m_widthScale = HL.Field(HL.Number) << 1 BlueprintPreview.m_heightScale = HL.Field(HL.Number) << 1 BlueprintPreview.InitBlueprintPreview = HL.Method(CS.Beyond.Gameplay.RemoteFactory.RemoteFactoryBlueprint, HL.Boolean, HL.Opt(HL.Table)) << function(self, csBP, canEdit, bpAbnormalIconHelper) self:_FirstTimeInit() self:_HideChangeIconNode(true) if self.m_showingCellDic then for cell, info in pairs(self.m_showingCellDic) do if info.type == NodeType.Building or info.type == NodeType.Logistic then self.m_nodeCellCache:Cache(cell) elseif info.type == NodeType.Belt or info.type == NodeType.Pipe then self.m_conveyorCellCache:Cache(cell) end end end self.m_csBP = csBP self.m_showingCellDic = {} self.m_changedIcons = {} self.m_canEdit = canEdit self.m_bpAbnormalIconHelper = bpAbnormalIconHelper self:_CancelHover() local range = self.m_csBP.sourceRect local bpUISize = Vector2(range.width, range.height) * uiSizePerUnit self.view.content.transform.sizeDelta = bpUISize local viewSize = self.view.scrollRect.transform.rect.size - Vector2(100, 100) local widthRatio = viewSize.x / bpUISize.x local heightRatio = viewSize.y / bpUISize.y local scaleValue = math.min(widthRatio, heightRatio, 1) scaleValue = math.max(scaleValue, self.view.config.MIN_SCALE) self.m_widthScale = scaleValue/widthRatio - 1 self.m_heightScale = scaleValue/heightRatio - 1 self.view.content.transform.localScale = Vector3(scaleValue, scaleValue, 1) local curMaxShowingCount = self.view.scrollRect.transform.rect.size / (uiSizePerUnit * scaleValue) local bgWidth, bgHeight if curMaxShowingCount.x > range.width then bgWidth = math.ceil(curMaxShowingCount.x) bgWidth = bgWidth + (bgWidth + range.width) % 2 else bgWidth = range.width + 2 end if curMaxShowingCount.y > range.height then bgHeight = math.ceil(curMaxShowingCount.y) bgHeight = bgHeight + (bgHeight + range.height) % 2 else bgHeight = range.height + 2 end self.view.gridImg.transform.sizeDelta = Vector2(bgWidth, bgHeight) * uiSizePerUnit self.view.gridImg.transform:SetAsFirstSibling() self.m_previewHelper:SetSize(range.width, range.height) self.m_nextTargetId = 1 self.m_id2Cell = {} for _, entry in pairs(self.m_csBP.buildingNodes) do self:_GenPreviewBuilding(entry) end for _, entry in pairs(self.m_csBP.conveyorNodes) do self:_GenPreviewConveyor(entry) end self.view.hoverHint.transform:SetAsLastSibling() if DeviceInfo.usingController then self.view.controllerMouse.gameObject:SetActive(true) else self.view.controllerMouse.gameObject:SetActive(false) end if DeviceInfo.usingController then InputManagerInst:SetCustomControllerMouse(self.view.controllerMouse.transform, self:GetUICtrl().uiCamera) self.view.changeIconNode.selectableNaviGroup.onIsFocusedChange:AddListener(function(isTarget) if not isTarget then self:_HideChangeIconNode() end end) self.view.controllerMouse.anchoredPosition = Vector2(self.view.scrollRectRectTransform.rect.size.x * 1/2, self.view.scrollRectRectTransform.rect.size.y * 1/2) end end BlueprintPreview._GenPreviewBuilding = HL.Method(CS.Beyond.Gameplay.RemoteFactory.BlueprintBuildingEntry) << function(self, entry) local cell = self.m_nodeCellCache:Get() local info = { id = self:_GetNextTargetId(), entry = entry, } self.m_showingCellDic[cell] = info self.m_id2Cell[info.id] = cell local templateId = entry.templateId local isBuilding, bData = Tables.factoryBuildingTable:TryGetValue(templateId) info.type = isBuilding and NodeType.Building or NodeType.Logistic if self.m_canEdit then local _, iconData = Tables.factoryBlueprintMachineIconTable:TryGetValue(templateId) if iconData then info.canChangeIcon = iconData.canModify else info.canChangeIcon = false end else info.canChangeIcon = false end cell.selectedNode.gameObject:SetActive(false) local spatial = entry.spatial local gridSize = Vector2(isBuilding and bData.range.width or 1, isBuilding and bData.range.depth or 1) local swapSize = spatial.face == 1 or spatial.face == 3 local swappedGridSize = swapSize and Vector2(gridSize.y, gridSize.x) or gridSize local nodeUISize = gridSize * uiSizePerUnit cell.transform.sizeDelta = swappedGridSize * uiSizePerUnit local pos = entry.worldSpatial.worldPosition cell.transform.anchoredPosition = Vector2(pos.x, pos.z) * uiSizePerUnit cell.bg.transform.sizeDelta = nodeUISize cell.bg.transform.localEulerAngles = Vector3(0, 0, Face2RotZForBuilding[spatial.face]) local minX = lume.round(pos.x - swappedGridSize.x / 2) local minY = lume.round(pos.z - swappedGridSize.y / 2) self.m_previewHelper:BatchAddGridValue(minX, minY, swappedGridSize.x, swappedGridSize.y, info.id) local bgPath, isDefaultBuilding if isBuilding then local spBGInfo = FacConst.BLUEPRINT_PREVIEW_SP_BUILDING_BG[bData.type] isDefaultBuilding = spBGInfo == nil bgPath = spBGInfo and spBGInfo[1] or FacConst.BLUEPRINT_PREVIEW_BUILDING_DEFAULT_BG else bgPath = string.format(FacConst.BLUEPRINT_PREVIEW_LOGISTIC_BG, templateId) end cell.bg:LoadSpriteWithOutFormat(bgPath) self:_PrepareCellImgCache(cell) if isDefaultBuilding then self:_GenDefaultBuildingBG(entry, cell, bData) else cell.waistDeco.gameObject:SetActive(false) cell.machineBG.gameObject:SetActive(false) end if not isBuilding then local _, isLiquid = FactoryUtils.getLogisticData(templateId) if isLiquid then info.isHighLayer = true else cell.transform:SetAsFirstSibling() end end self:_UpdateTargetIcon(info.id) end BlueprintPreview._SetEdgeImgs = HL.Method(HL.Table, HL.Table, HL.String, HL.String) << function(self, edgeImgs, info, format, formatAlter) local count = info.count if count > 0 then local size = info.size if count == size then edgeImgs[info.edgeFace] = string.format(format, count) else edgeImgs[info.edgeFace] = string.format(formatAlter, size, count) end end end BlueprintPreview._GenDefaultBuildingBG = HL.Method(CS.Beyond.Gameplay.RemoteFactory.BlueprintBuildingEntry, HL.Table, HL.Any) << function(self, entry, cell, bData) local isBigBuilding = bData.range.width >= 3 and bData.range.depth >= 3 and (bData.range.width * bData.range.depth >= 9) local edgeImgs = {} local inPorts = self:_GenDefaultBuildingPort(bData.inputPorts, true, bData.range.width, bData.range.depth) local outPorts = self:_GenDefaultBuildingPort(bData.outputPorts, false, bData.range.width, bData.range.depth) self:_SetEdgeImgs(edgeImgs, inPorts.belt, FacConst.BLUEPRINT_PREVIEW_BELT_PORT_IN, FacConst.BLUEPRINT_PREVIEW_BELT_PORT_IN_ALTER) self:_SetEdgeImgs(edgeImgs, outPorts.belt, FacConst.BLUEPRINT_PREVIEW_BELT_PORT_OUT, FacConst.BLUEPRINT_PREVIEW_BELT_PORT_OUT_ALTER) local formulaMode = entry:GetFormulaMode() if not formulaMode or formulaMode == FacConst.FAC_FORMULA_MODE_MAP.LIQUID then self:_SetEdgeImgs(edgeImgs, inPorts.pipe, FacConst.BLUEPRINT_PREVIEW_PIPE_PORT_IN, FacConst.BLUEPRINT_PREVIEW_PIPE_PORT_IN_ALTER) self:_SetEdgeImgs(edgeImgs, outPorts.pipe, FacConst.BLUEPRINT_PREVIEW_PIPE_PORT_OUT, FacConst.BLUEPRINT_PREVIEW_PIPE_PORT_OUT_ALTER) end local needWaist = true for face = 0, 3 do local imgPath = edgeImgs[face] local img if not imgPath then if face == 0 or face == 2 then img = cell.m_imgCache:Get() img:LoadSpriteWithOutFormat(isBigBuilding and FacConst.BLUEPRINT_PREVIEW_BUILDING_DEFAULT_EDGE_BIG or FacConst.BLUEPRINT_PREVIEW_BUILDING_DEFAULT_EDGE_SMALL) img.transform.sizeDelta = Vector2(bData.range.width * uiSizePerUnit, isBigBuilding and 140 or 40) img.type = CS.UnityEngine.UI.Image.Type.Sliced end else img = cell.m_imgCache:Get() img:LoadSpriteWithOutFormat(imgPath) img:SetNativeSizeIgnoreRefScale() img.type = CS.UnityEngine.UI.Image.Type.Simple end if img then if face == 0 then img.transform.anchoredPosition = Vector2(bData.range.width / 2, bData.range.depth) * uiSizePerUnit img.transform.localEulerAngles = Vector3(0, 0, 0) elseif face == 1 then img.transform.anchoredPosition = Vector2(bData.range.width, bData.range.depth / 2) * uiSizePerUnit img.transform.localEulerAngles = Vector3(0, 0, 270) needWaist = false elseif face == 2 then img.transform.anchoredPosition = Vector2(bData.range.width / 2, 0) * uiSizePerUnit img.transform.localEulerAngles = Vector3(0, 0, 180) elseif face == 3 then img.transform.anchoredPosition = Vector2(0, bData.range.depth / 2) * uiSizePerUnit img.transform.localEulerAngles = Vector3(0, 0, 90) needWaist = false end table.insert(cell.m_showingImgs, img) end end cell.waistDeco.gameObject:SetActive(needWaist) if isBigBuilding then cell.machineBG:LoadSprite(UIConst.UI_SPRITE_FAC_BUILDING_PANEL_ICON_BIG, bData.iconOnPanel) cell.machineBG.transform.localEulerAngles = Vector3(0, 0, -cell.bg.transform.localEulerAngles.z) cell.machineBG.gameObject:SetActive(true) else cell.machineBG.gameObject:SetActive(false) end end BlueprintPreview._GenDefaultBuildingPort = HL.Method(HL.Any, HL.Boolean, HL.Number, HL.Number).Return(HL.Table) << function(self, portsData, isInput, width, depth) local ports = { belt = { count = 0, edgeFace = -1, minPos = math.maxinteger, maxPos = math.mininteger }, pipe = { count = 0, edgeFace = -1, minPos = math.maxinteger, maxPos = math.mininteger }, } for _, v in pairs(portsData) do local info = v.isPipe and ports.pipe or ports.belt info.count = info.count + 1 local portPosIsOnX = (v.trans.rotation.y / 90) % 2 == 0 local portPos = portPosIsOnX and v.trans.position.x or v.trans.position.z info.minPos = math.min(portPos, info.minPos) info.maxPos = math.max(portPos, info.maxPos) info.edgeFace = (v.trans.rotation.y / 90 + (isInput and 2 or 0)) % 4 end for _, info in pairs(ports) do if info.count > 0 then info.size = info.maxPos - info.minPos + 1 local buildingSize = info.edgeFace % 2 == 0 and width or depth if (buildingSize - info.size) % 2 == 1 then info.size = info.size + 1 end end end return ports end BlueprintPreview._GenPreviewConveyor = HL.Method(CS.Beyond.Gameplay.RemoteFactory.BlueprintConveyorEntry) << function(self, entry) local cell = self.m_conveyorCellCache:Get() local info = { id = self:_GetNextTargetId(), entry = entry, canChangeIcon = false, } self.m_showingCellDic[cell] = info self.m_id2Cell[info.id] = cell local templateId = entry.templateId local isBelt = templateId == FacConst.BELT_ID info.type = isBelt and NodeType.Belt or NodeType.Pipe info.segInfos = self:_GetConveyorSegmentInfos(entry) info.isHighLayer = not isBelt if isBelt then cell.transform:SetAsFirstSibling() end local imgs = isBelt and FacConst.BLUEPRINT_PREVIEW_BELT_IMGS or FacConst.BLUEPRINT_PREVIEW_PIPE_IMGS self:_PrepareCellImgCache(cell) for k, v in ipairs(info.segInfos) do local img = cell.m_imgCache:Get() if UNITY_EDITOR then img.gameObject.name = "Seg_" .. k end table.insert(cell.m_showingImgs, img) if v.length then img:LoadSpriteWithOutFormat(imgs.normal) local centerGridPos = v.startPoint + Vector2(0.5, 0.5) + (v.length - 1) / 2 * Face2Vector2[v.startFace] img.transform.anchoredPosition = centerGridPos * uiSizePerUnit img.transform.sizeDelta = Vector2(v.length, 1) * uiSizePerUnit img.transform.localEulerAngles = Vector3(0, 0, Face2RotZForConveyor[v.startFace]) local endPoint = v.startPoint + (v.length - 1) * Face2Vector2[v.startFace] local minX = math.min(v.startPoint.x, endPoint.x) local minY = math.min(v.startPoint.y, endPoint.y) local sizeX = math.abs(v.startPoint.x - endPoint.x) + 1 local sizeY = math.abs(v.startPoint.y - endPoint.y) + 1 self.m_previewHelper:BatchAddGridValue(minX, minY, sizeX, sizeY, info.id) else local imgInfo = FacConst.BLUEPRINT_PREVIEW_CORNER_DIC[v.startFace][v.endFace] img:LoadSpriteWithOutFormat(imgInfo[1] and imgs.corner1 or imgs.corner2) local centerGridPos = v.startPoint + Vector2(0.5, 0.5) img.transform.anchoredPosition = centerGridPos * uiSizePerUnit img.transform.sizeDelta = Vector2(uiSizePerUnit, uiSizePerUnit) img.transform.localEulerAngles = Vector3(0, 0, imgInfo[2]) self.m_previewHelper:AddGridValue(v.startPoint.x, v.startPoint.y, info.id) end end end BlueprintPreview._GetConveyorSegmentInfos = HL.Method(CS.Beyond.Gameplay.RemoteFactory.BlueprintConveyorEntry).Return(HL.Table) << function(self, entry) local spatialInfo = entry.spatial local gridPath = spatialInfo.gridPath local segInfos = {} local curStartPoint = Vector2(gridPath.startPoint.x, gridPath.startPoint.y) local curStartFace = spatialInfo.startFace for _, vector in pairs(gridPath.segments) do local length = vector.length if vector.face ~= curStartFace then local cornerInfo = { startPoint = curStartPoint, startFace = curStartFace, endFace = vector.face, } curStartFace = cornerInfo.endFace curStartPoint = curStartPoint + Face2Vector2[cornerInfo.endFace] table.insert(segInfos, cornerInfo) length = length - 1 end if length > 0 then local straightInfo = { startPoint = curStartPoint, startFace = curStartFace, length = length, } table.insert(segInfos, straightInfo) curStartPoint = curStartPoint + straightInfo.length * Face2Vector2[curStartFace] end end return segInfos end BlueprintPreview.m_iconCells = HL.Field(HL.Forward('UIListCache')) BlueprintPreview.m_changedIcons = HL.Field(HL.Table) BlueprintPreview.m_curIconIndex = HL.Field(HL.Number) << -1 BlueprintPreview.m_iconInfos = HL.Field(HL.Table) BlueprintPreview.m_curChangeIconTargetId = HL.Field(HL.Number) << -1 BlueprintPreview._InitChangeIconNode = HL.Method() << function(self) local node = self.view.changeIconNode self.m_iconCells = UIUtils.genCellCache(node.iconCell) node.autoCloseArea.onTriggerAutoClose:AddListener(function() self:_HideChangeIconNode() end) end BlueprintPreview._ShowChangeIconNode = HL.Method(HL.Number) << function(self, targetId) if self.m_curChangeIconTargetId == targetId then self:_HideChangeIconNode() return end local node = self.view.changeIconNode node.gameObject:SetActive(true) node.animationWrapper:ClearTween(false) node.animationWrapper:PlayInAnimation() self.m_curChangeIconTargetId = targetId local cell = self.m_id2Cell[targetId] local info = self.m_showingCellDic[cell] local templateId = info.entry.templateId local bData = Tables.factoryBuildingTable[templateId] node.titleTxt.text = string.format(Language.LUA_FAC_BLUEPRINT_CHANGE_MACHINE_ICON_TITLE, bData.name) local iconMap = { [""] = { itemId = "", icon = bData.iconOnPanel, sortId1 = math.maxinteger, }, } local _, curItemId = self:_GetTargetIconInfo(targetId) if not string.isEmpty(curItemId) then local itemData = Tables.itemTable[curItemId] iconMap[curItemId] = { itemId = curItemId, icon = itemData.iconId, sortId1 = itemData.sortId1, sortId2 = itemData.sortId2, rarity = itemData.rarity, } end local _, formulaCpt = info.entry.info:TryGetValue(GEnums.FCComponentPos.FormulaMan) local currentMode if formulaCpt and not string.isEmpty(formulaCpt.currentMode) then currentMode = formulaCpt.currentMode end local craftInfos = FactoryUtils.getBuildingCrafts(templateId, nil, nil, currentMode) for _, cInfo in ipairs(craftInfos) do if cInfo.outcomes then for _, v in ipairs(cInfo.outcomes) do local itemId = v.id if not iconMap[itemId] then local itemData = Tables.itemTable[itemId] iconMap[itemId] = { itemId = itemId, icon = itemData.iconId, sortId1 = itemData.sortId1, sortId2 = itemData.sortId2, rarity = itemData.rarity, } end end end end self.m_iconInfos = {} for _, v in pairs(iconMap) do table.insert(self.m_iconInfos, v) end table.sort(self.m_iconInfos, Utils.genSortFunction({ "sortId1", "sortId2", "itemId" })) local selectedCell = nil self.m_iconCells:Refresh(#self.m_iconInfos, function(iconCell, index) local iconInfo = self.m_iconInfos[index] if string.isEmpty(iconInfo.itemId) then iconCell.icon:InitItemIcon("item_gold") iconCell.icon.view.icon:LoadSprite(UIConst.UI_SPRITE_FAC_BUILDING_PANEL_ICON, iconInfo.icon) iconCell.rarityLine.gameObject:SetActive(false) iconCell.rarityLight.gameObject:SetActive(false) else iconCell.icon:InitItemIcon(iconInfo.itemId) iconCell.rarityLine.gameObject:SetActive(true) iconCell.rarityLight.gameObject:SetActive(true) local color = UIUtils.getItemRarityColor(iconInfo.rarity) iconCell.rarityLine.color = color iconCell.rarityLight.color = color end iconCell.button.onClick:RemoveAllListeners() iconCell.button.onClick:AddListener(function() self:_OnClickIcon(index) end) local isSelected = iconInfo.itemId == curItemId if isSelected then self.m_curIconIndex = index selectedCell = iconCell end iconCell.stateController:SetState(isSelected and "Selected" or "Normal") end) cell.selectedNode.gameObject:SetActive(true) local panelCtrl = self:GetUICtrl() UIUtils.updateTipsPosition(self.view.changeIconNode.transform, cell.transform, panelCtrl.view.transform, panelCtrl.uiCamera, UIConst.UI_TIPS_POS_TYPE.RightTop, { top = self.view.config.CHANGE_ICON_NODE_PADDING_VER.x, bottom = self.view.config.CHANGE_ICON_NODE_PADDING_VER.y, left = self.view.config.CHANGE_ICON_NODE_PADDING_HOR.x, right = self.view.config.CHANGE_ICON_NODE_PADDING_HOR.y, }) node.autoCloseArea.tmpSafeArea = cell.transform if DeviceInfo.usingController then node.selectableNaviGroup:ManuallyFocus() if selectedCell then self.mouseShow = false self.view.leftBottomNode.gameObject:SetActive(false) self:_CancelHover() UIUtils.setAsNaviTarget(selectedCell.button) end end end BlueprintPreview._OnClickIcon = HL.Method(HL.Number) << function(self, index) if index == self.m_curIconIndex then return end local oldCell = self.m_iconCells:Get(self.m_curIconIndex) oldCell.stateController:SetState("Normal") self.m_curIconIndex = index local newCell = self.m_iconCells:Get(self.m_curIconIndex) newCell.stateController:SetState("Selected") self.m_changedIcons[self.m_curChangeIconTargetId] = self.m_iconInfos[index].itemId self:_UpdateTargetIcon(self.m_curChangeIconTargetId) end BlueprintPreview._HideChangeIconNode = HL.Method(HL.Opt(HL.Boolean)) << function(self, skipAni) local node = self.view.changeIconNode if not skipAni then if node.animationWrapper.curState == CS.Beyond.UI.UIConst.AnimationState.Out then return end end if skipAni then node.animationWrapper:ClearTween(false) node.gameObject:SetActive(false) else UIUtils.PlayAnimationAndToggleActive(node.animationWrapper, false) end self.mouseShow = true self.view.leftBottomNode.gameObject:SetActive(true) if self.m_curChangeIconTargetId > 0 then local cell = self.m_id2Cell[self.m_curChangeIconTargetId] self.m_curChangeIconTargetId = -1 cell.selectedNode.gameObject:SetActive(false) end end BlueprintPreview._GetTargetIconInfo = HL.Method(HL.Number).Return(HL.Opt(HL.String, HL.String, HL.Number)) << function(self, targetId) local itemId = self.m_changedIcons[targetId] local cell = self.m_id2Cell[targetId] local info = self.m_showingCellDic[cell] if not itemId then itemId = info.entry.productIcon end if string.isEmpty(itemId) then if info.type == NodeType.Building then local data = Tables.factoryBuildingTable[info.entry.templateId] return data.iconOnPanel, "" end return end local itemData = Tables.itemTable[itemId] return itemData.iconId, itemId, itemData.rarity end BlueprintPreview._UpdateTargetIcon = HL.Method(HL.Number) << function(self, targetId) local cell = self.m_id2Cell[targetId] local info = self.m_showingCellDic[cell] local icon, itemId, rarity = self:_GetTargetIconInfo(targetId) local node = cell.iconNode node.machineIcon.gameObject:SetActive(false) node.emptyNode.gameObject:SetActive(false) node.itemNode.gameObject:SetActive(false) if icon == nil then node.emptyNode.gameObject:SetActive(true) elseif string.isEmpty(itemId) then node.machineIcon.gameObject:SetActive(true) node.machineIcon:LoadSprite(UIConst.UI_SPRITE_FAC_BUILDING_PANEL_ICON, icon) else node.itemNode.gameObject:SetActive(true) node.itemIcon:InitItemIcon(itemId) local color = UIUtils.getItemRarityColor(rarity) node.rarityIcon.color = color local isAbnormal if Utils.isInBlackbox() then isAbnormal = false else isAbnormal = self.m_bpAbnormalIconHelper and self.m_bpAbnormalIconHelper.IsAbnormal(info.entry.templateId, itemId) end node.abnormalNode.gameObject:SetActive(isAbnormal) end node.changeHint.gameObject:SetActive(info.canChangeIcon) end BlueprintPreview.ApplyIconChanges = HL.Method() << function(self) for targetId, itemId in pairs(self.m_changedIcons) do local cell = self.m_id2Cell[targetId] local info = self.m_showingCellDic[cell] info.entry.productIcon = itemId end end BlueprintPreview.GetChangedIcons = HL.Method().Return(HL.Opt(HL.Table)) << function(self) if not self:HasIconChanged() then return end local dic = {} for targetId, newIcon in pairs(self.m_changedIcons) do local cell = self.m_id2Cell[targetId] local info = self.m_showingCellDic[cell] dic[info.entry.nodeId] = newIcon end return dic end BlueprintPreview.HasIconChanged = HL.Method().Return(HL.Boolean) << function(self) return next(self.m_changedIcons) ~= nil end BlueprintPreview.m_curHoverTargetId = HL.Field(HL.Any) BlueprintPreview.m_curHoverTargetId2 = HL.Field(HL.Any) BlueprintPreview._UpdateHoverPos = HL.Method() << function(self) if not DeviceInfo.usingController and not self.view.maskBtnArea.pointerInArea then if self.m_curHoverTargetId then self:_CancelHover() end return end if DeviceInfo.usingController then if not self.mouseShow then self.view.controllerMouse.gameObject:SetActive(false) return end self.view.controllerMouse.gameObject:SetActive(true) local stickValue = InputManagerInst:GetGamepadStickValue(true) local moveDelta = stickValue * self.view.config.CONTROLLER_MOVE_SPEED * Time.deltaTime local targetPosition = self.view.controllerMouse.anchoredPosition + moveDelta local targetNormalizedPosition = self.view.scrollRect.normalizedPosition if targetPosition.x <= self.view.config.CONTROLLER_PADDING and self.m_widthScale > 0 then targetNormalizedPosition.x = lume.clamp(self.view.scrollRect.normalizedPosition.x - self.view.config.CONTROLLER_ROLL_SPEED * Time.deltaTime / self.m_widthScale,0,1) elseif targetPosition.x >= self.view.scrollRectRectTransform.rect.size.x - self.view.config.CONTROLLER_PADDING and self.m_widthScale > 0 then targetNormalizedPosition.x = lume.clamp(self.view.scrollRect.normalizedPosition.x + self.view.config.CONTROLLER_ROLL_SPEED * Time.deltaTime / self.m_widthScale,0,1) end if targetPosition.y <= self.view.config.CONTROLLER_PADDING and self.m_heightScale > 0 then targetNormalizedPosition.y = lume.clamp(self.view.scrollRect.normalizedPosition.y - self.view.config.CONTROLLER_ROLL_SPEED * Time.deltaTime / self.m_heightScale,0,1) elseif targetPosition.y >= self.view.scrollRectRectTransform.rect.size.y - self.view.config.CONTROLLER_PADDING and self.m_heightScale > 0 then targetNormalizedPosition.y = lume.clamp(self.view.scrollRect.normalizedPosition.y + self.view.config.CONTROLLER_ROLL_SPEED * Time.deltaTime / self.m_heightScale,0,1) end self.view.scrollRect.normalizedPosition = targetNormalizedPosition if stickValue ~= Vector2.zero then targetPosition.x = lume.clamp(targetPosition.x,self.view.config.CONTROLLER_PADDING,self.view.scrollRectRectTransform.rect.size.x - self.view.config.CONTROLLER_PADDING) targetPosition.y = lume.clamp(targetPosition.y,self.view.config.CONTROLLER_PADDING,self.view.scrollRectRectTransform.rect.size.y - self.view.config.CONTROLLER_PADDING) self.view.controllerMouse.anchoredPosition = targetPosition end end local mousePos = InputManager.mousePosition:XY() local rect = CSUtils.RectTransformToScreenRect(self.view.content.transform, self:GetUICtrl().uiCamera) local relativePos = mousePos - rect.min local gridScreenSize = rect.width / self.m_csBP.sourceRect.width local gridPos = relativePos / gridScreenSize gridPos = Vector2(math.floor(gridPos.x), math.floor(gridPos.y)) local id1, id2 = self.m_previewHelper:GetGridValue(gridPos.x, gridPos.y) if id1 == 0 then if self.m_curHoverTargetId then self:_CancelHover() end self.view.controllerEditBtn.interactable = false return end local cell1 = self.m_id2Cell[id1] local info1 = self.m_showingCellDic[cell1] local isConveyor = info1.type == NodeType.Belt or info1.type == NodeType.Pipe if not isConveyor and id1 == self.m_curHoverTargetId and id2 == self.m_curHoverTargetId2 then return end self.view.controllerEditBtn.interactable = info1.canChangeIcon self.m_curHoverTargetId = id1 if id2 == 0 then self.m_curHoverTargetId2 = nil else local cell2 = self.m_id2Cell[id2] local info2 = self.m_showingCellDic[cell2] if info2.isHighLayer then self.m_curHoverTargetId = id2 self.m_curHoverTargetId2 = id1 isConveyor = info2.type == NodeType.Belt or info2.type == NodeType.Pipe cell1, info1 = cell2, info2 else self.m_curHoverTargetId2 = id2 end end self:_UpdateHoverTips() self.view.hoverHint.gameObject:SetActive(true) self.view.hoverTipsNode.gameObject:SetActive(true) if isConveyor then self.view.hoverHint.transform.sizeDelta = Vector2(uiSizePerUnit, uiSizePerUnit) self.view.hoverHint.transform.anchoredPosition = Vector2(math.floor(gridPos.x) + 0.5, math.floor(gridPos.y) + 0.5) * uiSizePerUnit else self.view.hoverHint.transform.sizeDelta = cell1.transform.sizeDelta self.view.hoverHint.transform.anchoredPosition = cell1.transform.anchoredPosition end end BlueprintPreview._CancelHover = HL.Method() << function(self) self.m_curHoverTargetId = nil self.m_curHoverTargetId2 = nil self.view.hoverHint.gameObject:SetActive(false) self.view.hoverTipsNode.gameObject:SetActive(false) end BlueprintPreview._OnClick = HL.Method() << function(self) if not self.m_canEdit then return end self:_UpdateHoverPos() if self.m_curHoverTargetId then local info = self.m_showingCellDic[self.m_id2Cell[self.m_curHoverTargetId]] if not info.canChangeIcon then return end self:_ShowChangeIconNode(self.m_curHoverTargetId) end if self.m_curHoverTargetId2 then end end BlueprintPreview._UpdateHoverTips = HL.Method() << function(self) self:_UpdateSingleHoverTips(self.view.hoverTipsCell, self.m_curHoverTargetId) self:_UpdateSingleHoverTips(self.view.hoverTipsCell2, self.m_curHoverTargetId2) end BlueprintPreview._UpdateSingleHoverTips = HL.Method(HL.Table, HL.Any) << function(self, cell, targetId) if not targetId then cell.m_curTargetId = nil cell.gameObject.gameObject:SetActive(false) return end local oriActive = cell.gameObject.activeInHierarchy cell.gameObject.gameObject:SetActive(true) if cell.m_curTargetId == targetId then if not oriActive then AudioAdapter.PostEvent("Au_UI_Popup_CommonHoverTipPanel_Open") end return end cell.m_curTargetId = targetId AudioAdapter.PostEvent("Au_UI_Popup_CommonHoverTipPanel_Open") local nodeCell = self.m_id2Cell[targetId] local info = self.m_showingCellDic[nodeCell] local templateId = info.entry.templateId local icon, name, itemId if info.type == NodeType.Building then local data = Tables.factoryBuildingTable[templateId] icon = data.iconOnPanel name = data.name itemId = FactoryUtils.getBuildingItemId(templateId) elseif info.type == NodeType.Logistic then local data = FactoryUtils.getLogisticData(templateId) icon = data.iconOnPanel name = data.name itemId = data.itemId elseif info.type == NodeType.Belt then local data = Tables.factoryGridBeltTable[templateId] icon = data.beltData.iconOnPanel name = data.beltData.name itemId = data.beltData.itemId elseif info.type == NodeType.Pipe then local data = Tables.factoryLiquidPipeTable[templateId] icon = data.pipeData.iconOnPanel name = data.pipeData.name itemId = data.pipeData.itemId end cell.icon:LoadSprite(UIConst.UI_SPRITE_FAC_BUILDING_PANEL_ICON, icon) cell.nameTxt.text = name local itemData = Tables.itemTable[itemId] cell.rarityLine.color = UIUtils.getItemRarityColor(itemData.rarity) end BlueprintPreview._OnEnable = HL.Override() << function(self) if self.m_updateId < 0 then self.m_updateId = LuaUpdate:Add("TailTick", function() self:_UpdateHoverPos() end) end end BlueprintPreview._OnDisable = HL.Override() << function(self) if self.m_updateId then self.m_updateId = LuaUpdate:Remove(self.m_updateId) end end BlueprintPreview._OnDestroy = HL.Override() << function(self) if self.m_updateId then self.m_updateId = LuaUpdate:Remove(self.m_updateId) end end BlueprintPreview._GetNextTargetId = HL.Method().Return(HL.Number) << function(self) local id = self.m_nextTargetId self.m_nextTargetId = self.m_nextTargetId + 1 return id end BlueprintPreview._PrepareCellImgCache = HL.Method(HL.Any) << function(self, cell) if not cell.m_imgCache then cell.m_imgCache = CommonCache(function() local obj = CSUtils.CreateObject(cell.image.gameObject, cell.image.transform.parent) return obj.gameObject:GetComponent("UIImage") end, function(img) img.gameObject:SetActive(true) end, function(img) img.gameObject:SetActive(false) end) cell.m_imgCache:Cache(cell.image) cell.m_showingImgs = {} else for _, img in ipairs(cell.m_showingImgs) do cell.m_imgCache:Cache(img) end cell.m_showingImgs = {} end end HL.Commit(BlueprintPreview) return BlueprintPreview