-- 角色面板 装备
PlayerEquip = {}

PlayerEquip._ui = nil

-- 13 斗笠位置比较特殊 属于和头盔位置同部位
-- 要斗笠和头盔分开 需要设置Panel_pos13为显示 
PlayerEquip.showModelCapAndHelmet = false -- 斗笠和头盔分开情况下  模型是否显示 斗笠头盔
PlayerEquip.posSetting = {}
PlayerEquip._hideNodePos = {}
PlayerEquip.RoleType = {
    Self = 1 -- 自己
}

-- 剑甲分离出格子 需要对应相应装备位置
PlayerEquip.realUIPos = {
    [GUIDefine.EquipPosUI.Equip_Type_Dress] = 1000, 
    [GUIDefine.EquipPosUI.Equip_Type_Weapon] = 1001,
}

PlayerEquip.fictionalUIPos = {
    [1000] = GUIDefine.EquipPosUI.Equip_Type_Dress,
    [1001] = GUIDefine.EquipPosUI.Equip_Type_Weapon, 
}

function PlayerEquip.main(data)
    PlayerEquip.posSetting = {
        0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 16, --1000, 1001 如有分离装备 需要添加
    }
    local parent = GUI:Attach_Parent()
    GUI:LoadExport(parent, "player/player_equip_node_win32")

    PlayerEquip._ui = GUI:ui_delegate(parent)
    if not PlayerEquip._ui then
        return false
    end
    PlayerEquip._parent = parent

    PlayerEquip._samePosDiff = {}

    -- 初始化装备槽
    PlayerEquip.InitEquipCells()
    -- 角色性别
    PlayerEquip.playerSex = SL:GetMetaValue("SEX")
    -- 发型
    PlayerEquip.playerHairID = SL:GetMetaValue("HAIR")
    -- 职业
    PlayerEquip.playerJob = SL:GetMetaValue("JOB")

    -- 首饰盒
    local ringBoxShow = SL:GetMetaValue("SERVER_OPTION", SW_KEY_SNDAITEMBOX) == 1 -- 首饰盒功能是否开启
    GUI:setVisible(PlayerEquip._ui.Best_ringBox, ringBoxShow)
    GUI:addOnClickEvent(PlayerEquip._ui.Best_ringBox,function()
        -- 请求玩家首饰盒状态
        SL:RequestOpenPlayerBestRings()
        
        -- 设置0.3秒的点击延迟
        -- 1. 防止玩家快速重复点击导致多次发送请求
        -- 2. 避免在服务器响应前重复触发打开操作
        -- 3. 提供更好的交互体验,给予适当的操作间隔
        GUI:delayTouchEnabled(PlayerEquip._ui.Best_ringBox, 0.3)
    end)

    --刷新首饰盒状态
    PlayerEquip.RefreshPlayerBestRingsOpenState()
    PlayerEquip.RefreshBestRingBox()
    ----------------------
    --刷新行会信息
    PlayerEquip.RefreshGuildInfo()
    ----------------------
    PlayerEquip.RegisterEvent()
end

-- 初始化需要隐藏的装备节点位置
-- 遍历指定位置列表,记录当前不可见的装备节点
function PlayerEquip.InitHideNodePos()
    -- 清空隐藏节点记录表
    PlayerEquip._hideNodePos = {}
    
    -- 定义需要检查的装备位置列表
    -- 包含所有可能需要隐藏的装备槽位置
    -- 2-12: 常规装备位置
    -- 13,14,15: 特殊装备位置 
    -- 55: 面巾位置
    local posList = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 55}
    
    -- 遍历所有位置
    for _, i in ipairs(posList) do
        -- 检查对应位置的节点是否存在
        if PlayerEquip._ui[string.format("Node_%s", i)] then
            -- 获取节点当前的可见性状态
            local visible = GUI:getVisible(PlayerEquip._ui[string.format("Node_%s", i)])
            -- 如果节点当前不可见,将其记录到隐藏节点表中
            if not visible then
                PlayerEquip._hideNodePos[i] = true
            end
        end
    end
end

-- 初始化相同位置装备的差异化显示
-- 主要处理斗笠(13号位置)和面巾(55号位置)与头盔的显示逻辑
-- @param isAfterF10Load - 是否在F10加载后调用
function PlayerEquip.InitSamePosDiff(isAfterF10Load)
    -- 获取13号位置(斗笠)面板的可见性状态
    PlayerEquip._pos13Visible = GUI:getVisible(PlayerEquip._ui.Panel_pos13)
    
    -- 如果斗笠面板可见,需要特殊处理
    if PlayerEquip._pos13Visible then
        -- 将斗笠(13)和面巾(55)位置添加到装备位置列表
        table.insert(PlayerEquip.posSetting, 13)
        table.insert(PlayerEquip.posSetting, 55)
        -- 记录需要特殊处理的装备位置
        -- 4号位置为头盔,13号位置为斗笠
        -- 这两个位置的装备会相互影响显示
        PlayerEquip._samePosDiff = {
            [4] = 4,   -- 头盔位置
            [13] = 13  -- 斗笠位置
        }
    end
    
    -- 根据斗笠面板的可见性来设置面巾相关UI元素的显示状态
    GUI:setVisible(PlayerEquip._ui.Panel_pos55, PlayerEquip._pos13Visible)
    GUI:setVisible(PlayerEquip._ui.Node_55, PlayerEquip._pos13Visible)
    
    -- 如果是F10加载后的调用,需要初始化装备事件、UI和更新角色模型
    if isAfterF10Load then
        PlayerEquip.InitEquipEvent()    -- 初始化装备相关事件
        PlayerEquip.InitEquipUI()       -- 初始化装备UI显示
        PlayerEquip.UpdatePlayerView(nil, true)  -- 更新角色模型显示
    end
end

-- 初始化所有装备格子的事件处理
-- 为每个装备位置添加拖拽、点击等交互事件
function PlayerEquip.InitEquipEvent()
    -- 获取所有需要初始化事件的装备位置列表
    local posSetting = PlayerEquip.posSetting
    
    -- 遍历每个装备位置
    for _, pos in ipairs(posSetting) do
        -- 获取对应位置的装备面板UI节点
        local equipPanel = PlayerEquip._ui["Panel_pos" .. pos]
        -- 为该装备面板初始化移动、点击等事件处理
        PlayerEquip.InitPanelMoveEvent(equipPanel, pos)
    end
end

function PlayerEquip.InitPanelMoveEvent(equipPanel, pos)

    -- 根据装备位置获取装备数据
    -- @param equipPos - 装备位置索引
    -- @param equipList - 是否获取装备列表(用于处理可叠加装备)
    -- @return equipItems - 装备数据或装备列表
    local function GetEquipDataByPos(equipPos, equipList)
        -- 默认为移动状态开始
        local beginOnMoving = true
        -- 如果是特殊处理位置(如头盔和斗笠),不获取列表且不处理移动状态
        if PlayerEquip._samePosDiff[equipPos] then
            equipList = false
            beginOnMoving = false
        end

        -- 初始化返回值
        local equipItems = nil  -- 装备列表
        local posData = nil     -- 单个装备数据
        
        -- 根据equipList参数决定获取方式
        if equipList then
            -- 获取该位置的装备列表数据(用于可叠加装备,如头盔可以叠加斗笠)
            equipItems = SL:GetMetaValue("EQUIP_DATA_LIST", equipPos)
        else
            -- 获取该位置的单个装备数据
            posData = SL:GetMetaValue("EQUIP_DATA", equipPos, beginOnMoving) 
        end

        -- 处理返回数据格式
        if not equipItems and posData then
            if not beginOnMoving then
                -- 非移动状态:将单个装备数据转换为列表格式
                equipItems = {}
                table.insert(equipItems, posData)
            else
                -- 移动状态:直接使用装备数据
                equipItems = posData
            end
        end
        
        -- 返回处理后的装备数据
--         "equipItems" = {
                -- 1 = {
                -- "AddValues" = {
                -- }
                -- "Color"          = 249
                -- "Desc"           = "<ID=1|-#0#0&0><ID=2|TXT:<[单件属性]:/FCOLOR=154>#0#0&0><ID=3|TXT:<生命值 + 18%/FCOLOR=223>#0#0&0><ID=4|TXT:<攻魔道 + 6%/FCOLOR=223>#0#0&0>"
                -- "Dura"           = 50000
                -- "DuraMax"        = 50000
                -- "ExAbil" = {
                --     "abil" = *MAX NESTING*
                --     "abilex" = ""
                --     "name"   = ""
                -- }
                -- "ExtendInfo" = {
                --     "ItmSrc" = *MAX NESTING*
                -- }
                -- "Index"          = 50148
                -- "Looks"          = 1587
                -- "MakeIndex"      = 23367
                -- "Name"           = "仙魔俱灭+6"
                -- "Need"           = 0
                -- "NeedLevel"      = 1
                -- "NeedLevelParam" = 24
                -- "OverLap"        = 1
                -- "Shape"          = 11
                -- "StdMode"        = 16
                -- "Values" = {
                -- }
                -- "Weight"         = 1
                -- "Where"          = 13
                -- "attribute"      = "3#3#7|3#4#7|3#5#7|3#6#7|3#7#7|3#8#7|3#9#7|3#10#7|3#11#7|3#12#7|3#21#6"
                -- "bEffect"        = ""
                -- "sEffect"        = ""
        return equipItems
    end

    -- 检查同位置装备的当前选择状态
    -- 主要用于处理头盔和斗笠这类可以叠加的装备位置
    -- @param equipPos - 装备位置索引
    -- @return number - 返回实际的装备位置
    local function checkSamePosCurSelect(equipPos)
        -- 如果不是特殊处理的装备位置(如头盔和斗笠)
        if not PlayerEquip._samePosDiff[equipPos] then
            -- 获取该位置的装备数据
            local itemData = SL:GetMetaValue("EQUIP_DATA", equipPos, true)
            -- 如果装备数据存在且有Where属性(实际装备位置),返回实际位置
            if itemData and itemData.Where then
                return itemData.Where
            end
        end
        -- 如果是特殊处理位置或没有找到实际位置,返回原始位置
        return equipPos
    end

    -- 获取装备的实际位置
    -- 如果存在虚拟位置映射(剑甲分离系统),则使用映射后的实际位置
    -- 否则使用原始位置
    -- @param pos - 装备在UI上的位置索引(可能是虚拟位置,如1000表示衣服专用格子)
    -- @return equipPos - 装备的实际系统位置(如GUIDefine.EquipPosUI.Equip_Type_Dress表示衣服位置)
    local equipPos = PlayerEquip.fictionalUIPos and PlayerEquip.fictionalUIPos[pos] or pos
    
    -- 刷新装备移动状态的回调函数
    -- @param _ - 未使用的参数
    -- @param bool - true表示开始移动,false表示结束移动
    local function refreshMoveState(_, bool)
        -- 保存当前处理的装备位置
        local setPos = equipPos
        
        -- 检查是否可以显示装备图标或是特殊处理位置
        if GUIFunction:CheckCanShowEquipItem(setPos) or PlayerEquip._samePosDiff[setPos] then
            -- 获取装备图标节点
            local itemNode = PlayerEquip._ui["Node_" .. setPos]
            if PlayerEquip._hideNodePos[setPos] then
                -- 如果是需要隐藏的位置,强制隐藏
                GUI:setVisible(itemNode, false)
            else
                -- 根据移动状态切换显示/隐藏
                GUI:setVisible(itemNode, not bool)
            end
        else
            -- 处理装备模型的显示/隐藏
            local noEquip = nil
            if bool then
                -- 特殊处理头盔位置
                if setPos == GUIDefine.EquipPosUI.Equip_Type_Helmet then
                    setPos = checkSamePosCurSelect(GUIDefine.EquipPosUI.Equip_Type_Helmet)
                end
                -- 根据装备类型设置对应部位的隐藏标记
                noEquip = {}
                if setPos == GUIDefine.EquipPosUI.Equip_Type_Dress then
                    noEquip.NoCloth = true        -- 衣服
                elseif setPos == GUIDefine.EquipPosUI.Equip_Type_Weapon then
                    noEquip.NoWeapon = true       -- 武器
                elseif setPos == GUIDefine.EquipPosUI.Equip_Type_Helmet then
                    noEquip.NoHead = true         -- 头盔
                elseif setPos == GUIDefine.EquipPosUI.Equip_Type_Cap then
                    noEquip.NoCap = true          -- 斗笠
                elseif setPos == GUIDefine.EquipPosUI.Equip_Type_Shield then
                    noEquip.NoShield = true       -- 盾牌
                elseif setPos == GUIDefine.EquipPosUI.Equip_Type_Veil then
                    noEquip.NoVeil = true         -- 面巾
                end
            end
            -- 更新角色模型显示
            PlayerEquip.UpdatePlayerView(noEquip)
        end

        -- 处理剑甲分离系统的UI显示逻辑
        -- 当装备位置存在对应的专用格子时(如武器、衣服的专用格子)
        if PlayerEquip.realUIPos and PlayerEquip.realUIPos[setPos] then 
            if bool then 
                -- 开始移动装备时,隐藏专用格子中的装备图标
                PlayerEquip.HideEquipItemsUI(setPos)
            else 
                -- 结束移动时,显示专用格子中的装备图标
                PlayerEquip.ShowEquipItemsUI(setPos)
            end 
        end

        if bool then
            PlayerEquip._moveItemData = SL:GetMetaValue("EQUIP_DATA", equipPos)
        else
            PlayerEquip._moveItemData = nil
        end
    end

    local function endMoveCallBack()
        PlayerEquip._moveItemData = nil
    end

    -- 双击装备格子的回调函数
    -- 用于处理装备的卸下操作
    local function doubleCallBack()
        -- 如果装备正在移动中,不处理双击事件
        if PlayerEquip._moveItemData then
            return
        end
        
        -- 判断是否需要获取装备列表
        -- 默认不获取列表
        local isList = false
        -- 如果不是特殊处理位置(头盔和斗笠的叠加位置)
        if not PlayerEquip._samePosDiff[equipPos] then
            -- 判断是否为头盔位置(普通头盔或超级头盔)
            -- 因为头盔位置可以叠加多个装备(头盔、斗笠、面巾等)
            -- 所以需要获取装备列表而不是单个装备数据
            isList = equipPos == GUIDefine.EquipPosUI.Equip_Type_Helmet or equipPos == GUIDefine.EquipPosUI.Equip_Type_Super_Helmet
        end
        
        -- 获取装备数据
        local itemData = SL:GetMetaValue("EQUIP_DATA", equipPos, isList)
        -- 如果有装备,则执行卸下操作
        if itemData then
            SL:TakeOffPlayerEquip(itemData)
        end
    end

    -- 鼠标滚动
    local function scrollCallBack(data)
        SL:onLUAEvent(LUA_EVENT_ITEMTIPS_MOUSE_SCROLL, data)
    end

    -- 获取装备面板的尺寸信息
    local panelSize = GUI:getContentSize(equipPanel)
    
    -- 创建可移动的装备控件
    -- @param equipPanel - 父节点面板
    -- @param "move_equip_"..pos - 控件唯一标识符
    -- @param panelSize.width/2, panelSize.height/2 - 控件在父节点中的位置(居中)
    -- @param panelSize.width, panelSize.height - 控件的宽高
    -- @param ITEMFROMUI_ENUM.PALYER_EQUIP - 标识该控件来自玩家装备界面
    local equipWidget = GUI:MoveWidget_Create(equipPanel, "move_equip_" .. pos, panelSize.width / 2 , panelSize.height / 2, panelSize.width, panelSize.height, SL:GetMetaValue("ITEMFROMUI_ENUM").PALYER_EQUIP, {
        equipPos = equipPos,                                                  -- 装备实际位置
        equipList = not PlayerEquip._samePosDiff[equipPos] and true or false, -- 是否需要获取装备列表(处理头盔等可叠加装备)
        beginMoveCB = refreshMoveState,   -- 开始移动回调
        cancelMoveCB = refreshMoveState,  -- 取消移动回调
        endMoveCB = endMoveCallBack,      -- 结束移动回调
        pcDoubleCB = doubleCallBack,      -- 双击回调(用于卸下装备)
        mouseScrollCB = scrollCallBack,    -- 鼠标滚轮回调(用于装备提示界面)
    })

    -- 延迟显示计时器,用于控制装备提示的显示时机
    local enterDelayTimer = nil

    -- 清理延迟显示计时器
    -- 当鼠标移出装备格子或需要取消延迟显示时调用
    local function CleanupTimer()
        -- 如果存在计时器
        if enterDelayTimer then
            -- 停止装备面板上的所有动作(包括延迟显示)
            GUI:stopAllActions(equipPanel)
            -- 重置计时器
            enterDelayTimer = nil
        end
    end

    -- 鼠标移动到装备格子上的回调函数
    -- 用于显示装备的详细信息提示
    local function mouseMoveCallBack()
        -- 获取当前装备位置的装备数据列表
        -- 因为某些位置(如头盔)可能有多个装备叠加
        local itemData = GetEquipDataByPos(equipPos, true)
        -- 如果没有装备数据或装备正在移动中,不显示提示
        if not itemData or PlayerEquip._moveItemData then
            return
        end
        
        -- 获取装备格子在屏幕上的绝对坐标
        local panelPos = GUI:getWorldPosition(equipPanel)
        
        -- 构造提示数据
        local data = {}
        data.itemData = itemData[#itemData]       -- 最上层装备数据
        data.itemData2 = itemData[#itemData - 1]  -- 第二层装备数据
        data.itemData3 = itemData[#itemData - 2]  -- 第三层装备数据
        data.pos = panelPos                       -- 提示框显示位置
        data.lookPlayer = false                   -- 是否查看其他玩家装备
        data.from = SL:GetMetaValue("ITEMFROMUI_ENUM").PALYER_EQUIP  -- 提示来源为玩家装备栏
        
        -- 显示装备提示框
        SL:OpenItemTips(data)
        -- 清理延迟显示计时器
        CleanupTimer()
    end

    -- 鼠标进入装备格子的回调函数
    -- 用于延迟显示装备提示信息,避免鼠标快速划过时频繁触发
    local function onEnterFunc()
        -- 如果已经存在延迟计时器,不重复创建
        if enterDelayTimer then
            return
        end
        -- 创建一个50毫秒的延迟计时器
        -- 当计时器触发时,调用mouseMoveCallBack显示装备提示
        enterDelayTimer = SL:scheduleOnce(equipPanel, function()
            mouseMoveCallBack()
        end, 0.05)
    end

    local function onLeaveFunc()
        SL:CloseItemTips()
        CleanupTimer()
    end

    -- 为装备格子添加鼠标移入移出事件
    -- @param equipPanel - 装备格子的UI面板
    -- @param onEnterFunc - 鼠标移入回调,显示装备详细信息提示
    -- @param onLeaveFunc - 鼠标移出回调,关闭装备提示并清理计时器
    -- @param checkIsVisible - 是否检查面板可见性,只有在面板可见时才触发事件
    GUI:addMouseMoveEvent(equipPanel, {
        onEnterFunc = onEnterFunc,     -- 鼠标移入时延迟显示装备提示
        onLeaveFunc = onLeaveFunc,     -- 鼠标移出时关闭提示并清理计时器
        checkIsVisible = true          -- 启用可见性检查
    })
end

-- 初始化装备UI显示
-- 遍历所有装备位置,创建和更新装备图标
function PlayerEquip.InitEquipUI()
    -- 获取所有装备位置的数据映射表 获取装备位对应MakeIndex数据
    local equipDataByPos = SL:GetMetaValue("EQUIP_POS_DATAS")  
    
    -- "equipDataByPos" = {
    --     0 = 22163
    --     1 = 22164
    --     3 = 22166
    --     4 = 22165
    --     5 = 22167
    --     6 = 22168
    --     7 = 22169
    --     8 = 22170
    -- }
    
    
    -- 遍历每个装备位置及其数据
    for pos, data in pairs(equipDataByPos) do
        -- 获取对应位置的装备面板
        local equipPanel = PlayerEquip._ui["Panel_pos" .. pos]
        
        -- 检查装备面板是否存在,且该位置是可显示装备或需要特殊处理的位置
        if equipPanel and (GUIFunction:CheckCanShowEquipItem(pos) or PlayerEquip._samePosDiff[pos]) then
            -- 根据装备唯一标识获取装备详细数据
            local item = SL:GetMetaValue("EQUIP_DATA_BY_MAKEINDEX", data)
            if item then 
                -- 获取装备图标节点
                local itemNode = PlayerEquip._ui["Node_"..pos]
                -- 清除节点上的所有子节点
                GUI:removeAllChildren(itemNode)
                -- 创建新的装备图标
                PlayerEquip.CreateEquipItem(itemNode, item, pos)
            end
        end
        -- 显示剑甲分离系统相关的装备图标
        PlayerEquip.ShowEquipItemsUI(pos)
    end
end

-- 创建装备图标项
-- @param parent - 父节点,装备图标的容器节点
-- @param data - 装备数据,包含装备的基本信息和属性
-- @param uiPos - 装备在UI上的位置索引
function PlayerEquip.CreateEquipItem(parent, data, uiPos)
    -- 检查装备位置是否需要显示内观特效
    -- @param uiPos - 装备在UI上的位置索引
    -- @return boolean - true表示显示特效,false表示不显示
    local function checkPos(uiPos)
        -- 检查是否存在虚拟位置映射且当前位置在映射表中
        if PlayerEquip.fictionalUIPos and PlayerEquip.fictionalUIPos[uiPos] then 
            -- 获取实际的装备类型
            local pos = PlayerEquip.fictionalUIPos[uiPos]
            -- 如果是衣服或武器的专用格子,不显示内观特效
            if pos == GUIDefine.EquipPosUI.Equip_Type_Dress or pos == GUIDefine.EquipPosUI.Equip_Type_Weapon then
                return false
            end
        end
        -- 其他位置显示内观特效
        return true
    end

    -- 构造装备显示信息
    local info = {}
    info.itemData = data                -- 装备数据
    info.index = data.Index             -- 装备索引
    info.noMouseTips = true             -- 禁用鼠标提示(因为使用了自定义提示)
    info.showModelEffect = checkPos(uiPos)  -- 是否显示内观特效
    info.from = SL:GetMetaValue("ITEMFROMUI_ENUM").PALYER_EQUIP  -- 标识来源为玩家装备栏
    
    -- 创建装备图标并设置锚点为中心点
    local item = GUI:ItemShow_Create(parent, "item_" .. uiPos, 0, 0, info)
    GUI:setAnchorPoint(item, 0.5, 0.5)
end

-- 初始化装备格子
-- 处理额外装备位置和剑甲分离的显示逻辑
function PlayerEquip.InitEquipCells()
    -- 获取当前玩家ID
    local uid = SL:GetMetaValue("USER_ID")
    -- 请求服务器获取该玩家的珍宝信息
    SL:RequestLookZhenBao(uid)

    -- 获取额外装备位置的配置
    -- SW_KEY_EQUIP_EXTRA_POS: 服务器配置键值
    -- 返回值: 0-不显示额外装备位置, 1-显示额外装备位置
    local equipPosSet = SL:GetMetaValue("SERVER_OPTION", SW_KEY_EQUIP_EXTRA_POS) or 0
    local showExtra = equipPosSet == 1

    -- 处理额外装备位置(14号和15号位置) 军鼓和马牌
    if showExtra then
        -- 如果开启额外装备位置,将1415号位置添加到装备位置列表
        table.insert(PlayerEquip.posSetting, 14)
        table.insert(PlayerEquip.posSetting, 15)
    else
        -- 如果未开启额外装备位置,隐藏相关UI元素
        -- Panel_pos: 装备格子的容器面板
        -- Node: 装备图标节点
        GUI:setVisible(PlayerEquip._ui.Panel_pos14, false)
        GUI:setVisible(PlayerEquip._ui.Panel_pos15, false)
        GUI:setVisible(PlayerEquip._ui.Node_14, false)
        GUI:setVisible(PlayerEquip._ui.Node_15, false)
    end

    -- 处理剑甲分离配置
    -- DivideWeaponAndClothes: 1-开启剑甲分离, 0-关闭剑甲分离
    if SL:GetMetaValue("GAME_DATA", "DivideWeaponAndClothes") == 1 then 
        -- 如果开启剑甲分离,显示专用装备格子(10001001号位置)
        -- 1000: 衣服专用格子
        -- 1001: 武器专用格子
        GUI:setVisible(PlayerEquip._ui.Panel_pos1000, true)
        GUI:setVisible(PlayerEquip._ui.Panel_pos1001, true)
        GUI:setVisible(PlayerEquip._ui.Node_1000, true)
        GUI:setVisible(PlayerEquip._ui.Node_1001, true)
        -- 将专用格子添加到装备位置列表
        table.insert(PlayerEquip.posSetting, 1000)
        table.insert(PlayerEquip.posSetting, 1001)
    end 
end

-- 刷新玩家行会信息显示
-- 包括行会名称和职位,并根据玩家状态设置对应的文字颜色
function PlayerEquip.RefreshGuildInfo()
    -- 获取行会信息文本控件
    local textGuildInfo = PlayerEquip._ui.Text_guildinfo
    
    -- 获取玩家当前的行会数据
    -- guildData包含行会名称(guildName)和玩家职位等级(rank)
    local guildData = SL:GetMetaValue("GUILD_INFO")
    
    -- 获取行会名称
    local myGuildName = guildData.guildName
    -- 根据职位等级获取对应的职位名称
    local myJobName = SL:GetMetaValue("GUILD_OFFICIAL", guildData.rank)
    
    -- 如果没有行会名称,说明玩家未加入行会,直接返回
    if not myGuildName then
        return
    end
    
    -- 如果职位名称为空,设置为空字符串避免显示nil
    myJobName = myJobName or ""

    -- 组合行会信息显示文本:行会名称 + 空格 + 职位名称
    local guildInfo = myGuildName .. " " .. myJobName
    -- 设置文本内容
    GUI:Text_setString(textGuildInfo, guildInfo)

    -- 获取玩家名字颜色ID
    -- 不同身份/状态的玩家可能有不同的文字颜色
    local color = SL:GetMetaValue("USER_NAME_COLOR")
    -- 如果有特殊颜色设置(color > 0),将文字设置为对应的十六进制颜色值
    if color and color > 0 then
        GUI:Text_setTextColor(textGuildInfo, SL:GetHexColorByStyleId(color))
    end
end

-- 刷新玩家首饰盒开启状态
-- @param data - 首饰盒状态数据,包含isOpen标记
function PlayerEquip.RefreshPlayerBestRingsOpenState(data)
    -- 获取当前玩家的首饰盒激活状态
    local activeState = SL:GetMetaValue("BEST_RING_OPENSTATE", PlayerEquip.RoleType.Self)
    -- 根据激活状态设置首饰盒按钮的灰化效果
    if activeState then
        GUI:Image_setGrey(PlayerEquip._ui.Image_box, false)  -- 激活状态,显示正常图标
    else
        GUI:Image_setGrey(PlayerEquip._ui.Image_box, true)   -- 未激活状态,显示灰化图标
    end
    
    -- 鼠标移动到首饰盒按钮上的回调函数
    -- @param touchPos - 鼠标触摸位置
    local function mouseMoveCallBack(touchPos)
        -- 如果首饰盒按钮不可见,直接返回
        if not GUI:getVisible(PlayerEquip._ui.Best_ringBox) then 
            return
        end
        -- 获取首饰盒的自定义名称,默认为"首饰盒"
        local bestRingsName = SL:GetMetaValue("SERVER_OPTION", "SndaItemBoxName") or "首饰盒"
        -- 检查鼠标是否在按钮有效区域内且名称不为空
        if SL:CheckNodeCanCallBack(PlayerEquip._ui.Best_ringBox, touchPos) and bestRingsName ~= "" then
            -- 根据激活状态设置不同的提示文本
            local tips = nil
            local activeState = SL:GetMetaValue("BEST_RING_OPENSTATE", PlayerEquip.RoleType.Self)
            if activeState then
                tips = string.format("点击打开%s", bestRingsName)
            else
                tips = string.format("%s未开启", bestRingsName)
            end
            -- 计算提示框显示位置
            local worldPos = GUI:getWorldPosition(PlayerEquip._ui.Best_ringBox)
            worldPos.x = GUI:getContentSize(PlayerEquip._ui.Best_ringBox).width/2 + worldPos.x
            -- 显示世界坐标提示框
            GUI:ShowWorldTips(tips, worldPos, GUI:p(0.5, 1))
        end
    end

    -- 鼠标离开首饰盒按钮的回调函数
    local function leaveItem()
        -- 隐藏提示框
        GUI:HideWorldTips()
    end

    -- 为首饰盒按钮添加鼠标移入移出事件
    GUI:addMouseMoveEvent(PlayerEquip._ui.Best_ringBox,
        {
            onEnterFunc = mouseMoveCallBack,  -- 鼠标移入回调
            onLeaveFunc = leaveItem           -- 鼠标移出回调
        }
    )
    
    -- 如果传入数据中包含打开标记且首饰盒已激活
    -- 则打开首饰盒界面
    if data and data.isOpen then
        if activeState then
            SL:OpenBestRingBoxUI(PlayerEquip.RoleType.Self, { param = {} })
        end
    end
end

-- 刷新首饰盒按钮的显示状态
-- 根据首饰盒界面的打开状态切换按钮贴图,并更新按钮的激活状态
function PlayerEquip.RefreshBestRingBox()
    -- 延迟0.1秒执行刷新操作
    -- 这样可以确保其他相关状态已经更新完成
    SL:scheduleOnce(PlayerEquip._ui.Best_ringBox,function()
        -- 默认使用未打开状态的贴图
        local texture = "btn_jewelry_1_1.png"
        -- 检查首饰盒界面是否已经打开
        if SL:GetMetaValue("BEST_RING_WIN_ISOPEN", PlayerEquip.RoleType.Self) then
            -- 如果已打开,使用打开状态的贴图
            texture = "btn_jewelry_1_0.png"
        end
        -- 加载对应状态的按钮贴图
        -- 贴图路径: SLDefine.PATH_RES_PRIVATE/player_best_rings_ui/player_best_rings_ui_win32/
        GUI:Image_loadTexture(PlayerEquip._ui.Image_box, SLDefine.PATH_RES_PRIVATE .. "player_best_rings_ui/player_best_rings_ui_win32/" .. texture)
        
        -- 设置图片不随内容自适应大小
        GUI:setIgnoreContentAdaptWithSize(PlayerEquip._ui.Image_box, true)
        
        -- 刷新首饰盒的开启状态(灰化/激活)
        PlayerEquip.RefreshPlayerBestRingsOpenState()
    end,0.1)
end

-- 获取装备在UI上的实际显示位置
-- 用于处理特殊装备(斗笠、面巾等)与头盔共用显示位置的情况
-- @param pos - 装备的原始位置索引
-- @return pos - 转换后的UI显示位置
function PlayerEquip.GetShowUIPosByItemWhere(pos)
    -- 获取装备位置类型配置
    local typeConfig = GUIDefine.EquipPosUI
    -- 如果是普通斗笠或面巾,显示在普通头盔位置
    if pos == typeConfig.Equip_Type_Cap or pos == typeConfig.Equip_Type_Veil then
        pos = typeConfig.Equip_Type_Helmet
    -- 如果是超级斗笠或超级面巾,显示在超级头盔位置
    elseif pos == typeConfig.Equip_Type_Super_Cap or pos == typeConfig.Equip_Type_Super_Veil then
        pos = typeConfig.Equip_Type_Super_Helmet
    end
    return pos
end

-- 更新装备UI显示
-- @param data - 装备更新数据,包含操作类型(opera)、装备唯一标识(MakeIndex)和装备位置(Where)
function PlayerEquip.UpdateEquipUI(data)
    -- 检查数据有效性
    -- Check if data is nil or empty table
    -- next(data) returns nil if table is empty
    if not data or not next(data) then
        return
    end
    
    -- 获取操作类型、装备唯一标识和位置
    local operatorType = data.opera  -- 1:增加 2:删除 3:修改
    local MakeIndex = data.MakeIndex -- 装备唯一标识
    local pos = data.Where           -- 装备位置

    -- 处理特殊装备位置映射
    -- 如果不是特殊处理位置(头盔斗笠)且不是面巾(55号位置)或斗笠面板不可见
    -- 则获取实际的UI显示位置
    if not PlayerEquip._samePosDiff[pos] then
        if not PlayerEquip._pos13Visible or pos ~= 55 then --面巾不处理
            pos = PlayerEquip.GetShowUIPosByItemWhere(pos)
        end
    end

    -- 获取装备面板UI节点
    local equipPanel = PlayerEquip._ui["Panel_pos" .. pos]
    if not equipPanel then
        return
    end

    -- 检查该位置是否需要显示装备图标
    local isShowItem = false 
    if GUIFunction:CheckCanShowEquipItem(pos) or PlayerEquip._samePosDiff[pos] then
        isShowItem = true
    end

    -- 重置移动中的装备数据
    PlayerEquip._moveItemData = nil

    -- 根据操作类型处理UI更新
    if operatorType == 1 then -- 增加装备
        if isShowItem then
            -- 获取装备图标节点
            local itemNode = PlayerEquip._ui["Node_" .. pos]
            -- 根据隐藏节点配置设置可见性
            if not PlayerEquip._hideNodePos[pos] then
                GUI:setVisible(itemNode, true)
            else
                GUI:setVisible(itemNode, false)
            end
            -- 清除旧的装备图标
            GUI:removeAllChildren(itemNode)
            -- 获取新装备数据并创建图标
            local item = SL:GetMetaValue("EQUIP_DATA_BY_MAKEINDEX", MakeIndex)
            PlayerEquip.CreateEquipItem(itemNode, item, pos)
            -- 如果是特殊处理位置且需要显示头盔斗笠
            -- 则更新角色模型和装备显示
            if PlayerEquip._samePosDiff[pos] and PlayerEquip.showModelCapAndHelmet then 
                PlayerEquip.UpdatePlayerView()
                PlayerEquip.ShowEquipItemsUI(pos)
            end
        else
            -- 仅更新角色模型和装备显示
            PlayerEquip.UpdatePlayerView()
            PlayerEquip.ShowEquipItemsUI(pos)
        end
    elseif operatorType == 2 then -- 删除装备
        if isShowItem then
            -- 清除装备图标
            local itemNode = PlayerEquip._ui["Node_" .. pos]
            GUI:removeAllChildren(itemNode)
            -- 特殊处理位置的额外更新
            if PlayerEquip._samePosDiff[pos] and PlayerEquip.showModelCapAndHelmet then 
                PlayerEquip.UpdatePlayerView()
                PlayerEquip.HideEquipItemsUI(pos)
            end
        else
            -- 仅更新角色模型和隐藏装备
            PlayerEquip.UpdatePlayerView()
            PlayerEquip.HideEquipItemsUI(pos)
        end
    elseif operatorType == 3 then -- 修改装备
        -- 只处理外观更新
        if not data.isChangeLook then
            return
        end

        if isShowItem then
            -- 更新装备图标
            local itemNode = PlayerEquip._ui["Node_" .. pos]
            GUI:removeAllChildren(itemNode)
            local item = SL:GetMetaValue("EQUIP_DATA_BY_MAKEINDEX", MakeIndex)
            PlayerEquip.CreateEquipItem(itemNode, item, pos)
            -- 特殊处理位置需要更新角色模型
            if PlayerEquip._samePosDiff[pos] and PlayerEquip.showModelCapAndHelmet then 
                PlayerEquip.UpdatePlayerView()
            end
        else
            -- 仅更新角色模型
            PlayerEquip.UpdatePlayerView()
        end
    end
end

-- 更新角色模型显示
-- @param noEquipType - 指定不显示的装备类型,如 {NoCloth=true} 表示不显示衣服
-- @param init - 是否为初始化调用,用于处理装备移动状态
function PlayerEquip.UpdatePlayerView(noEquipType, init)
    -- 清除角色模型节点的所有子节点,准备重新创建模型
    GUI:removeAllChildren(PlayerEquip._ui.Node_playerModel)
    -- 获取所有装备位置的数据映射表
    local equipDataByPos = SL:GetMetaValue("EQUIP_POS_DATAS")
    -- 获取装备位置类型配置
    local equipTypeConfig = GUIDefine.EquipPosUI

    -- 初始化不显示装备类型的表,如果未传入则使用空表
    noEquipType = noEquipType or {}

    -- 控制是否显示裸模,默认显示
    local showNakedMold = true --装备进行判断是否显示裸模  默认显示
    -- 控制是否显示头盔,用于处理斗笠与头盔的显示冲突
    local showHelmet = false

    -- 获取外观文件名和类型
    -- @param looks - 外观ID
    -- @return fileName - 格式化的文件名(6位数字)
    -- @return type - 外观类型(向下取整)
    local function getFileName(looks)
        -- 将外观ID格式化为6位数字的文件名
        local fileName = string.format("%06d", looks % 10000)
        -- 返回文件名和外观类型
        return fileName, math.floor(looks / 10000)
    end

    -- 获取装备的外观和特效数据
    -- @param equipType - 装备类型
    -- @param need - 是否强制需要该装备的外观
    -- @return show - 包含外观ID和特效ID的表
    local function GetLooks(equipType, need)
        -- 初始化返回数据结构
        local show = {
            look = nil,    -- 外观ID
            effect = nil   -- 特效ID
        }
        
        -- 处理时装类型(ID > 10000)
        if equipType > 10000 then
            local fashionShow = {}
            return fashionShow
        end

        -- 如果不是强制需要且该位置有装备数据
        if not need and equipType and equipDataByPos[equipType] then
            -- 获取装备唯一标识
            local MakeIndex = equipDataByPos[equipType]
            -- 如果是初始化且装备正在移动中,不显示该装备
            if init and PlayerEquip._moveItemData and MakeIndex == PlayerEquip._moveItemData.MakeIndex then
                return show
            end
            -- 获取装备详细数据
            local equipData = SL:GetMetaValue("EQUIP_DATA_BY_MAKEINDEX", MakeIndex) or {}

            -- 处理衣服的特殊显示逻辑
            if equipType == equipTypeConfig.Equip_Type_Dress then
                -- 如果衣服有荣誉出售标记(shonourSell=1),不显示裸模
                if showNakedMold and equipData and equipData.shonourSell and tonumber(equipData.shonourSell) == 1 then
                    showNakedMold = false
                end
            end

            -- 设置外观ID
            if equipData and equipData.Looks then
                show.look = equipData.Looks
            end

            -- 设置特效ID
            if equipData and equipData.sEffect then
                show.effect = equipData.sEffect
            end

            -- 处理斗笠的特殊显示逻辑
            -- 如果是斗笠且没有动画,则显示头盔
            if equipType == equipTypeConfig.Equip_Type_Cap and equipData.AniCount == 0 then
                showHelmet = true
            end

            -- 处理特殊位置(如头盔斗笠)的显示逻辑
            -- 如果是特殊处理位置且不显示头盔斗笠,返回空外观
            if PlayerEquip._samePosDiff[equipType] and not PlayerEquip.showModelCapAndHelmet then
                return {
                    look = nil,
                    effect = nil
                }
            end

            return show
        end
        return show
    end

    -- 获取角色当前发型ID
    local hairID        = SL:GetMetaValue("HAIR")
    -- 获取各部位装备的外观和特效数据
    local clothShow     = GetLooks(equipTypeConfig.Equip_Type_Dress, noEquipType.NoCloth)    -- 衣服
    local weaponShow    = GetLooks(equipTypeConfig.Equip_Type_Weapon, noEquipType.NoWeapon)  -- 武器
    local headShow      = GetLooks(equipTypeConfig.Equip_Type_Helmet, noEquipType.NoHead)    -- 头盔
    local capShow       = GetLooks(equipTypeConfig.Equip_Type_Cap, noEquipType.NoCap)        -- 斗笠
    local shieldShow    = GetLooks(equipTypeConfig.Equip_Type_Shield, noEquipType.NoShield)  -- 盾牌
    local veilShow      = GetLooks(equipTypeConfig.Equip_Type_Veil, noEquipType.NoVeil)      -- 面巾
    local tDressShow    = GetLooks(10004)  -- 时装衣服
    local tWeaponShow   = GetLooks(10005)  -- 时装武器
       -- 获取角色的法阵配置
    local embattle      = SL:GetMetaValue("EMBATTLE")

    -- 构造角色模型显示所需的数据
    local modelData = {
        clothID         = clothShow.look,        -- 衣服外观ID
        clothEffectID   = clothShow.effect,      -- 衣服特效ID
        weaponID        = weaponShow.look,       -- 武器外观ID
        weaponEffectID  = weaponShow.effect,     -- 武器特效ID
        headID          = headShow.look,         -- 头盔外观ID
        headEffectID    = headShow.effect,       -- 头盔特效ID
        hairID          = hairID,                -- 发型ID
        capID           = capShow.look,          -- 斗笠外观ID
        capEffectID     = capShow.effect,        -- 斗笠特效ID
        veilID          = veilShow.look,         -- 面巾外观ID
        veilEffectID    = veilShow.effect,       -- 面巾特效ID
        shieldID        = shieldShow.look,       -- 盾牌外观ID
        shieldEffectID  = shieldShow.effect,     -- 盾牌特效ID
        tDressID        = tDressShow.look,       -- 时装衣服外观ID
        tDressEffectID  = tDressShow.effect,     -- 时装衣服特效ID
        tWeaponID       = tWeaponShow.look,      -- 时装武器外观ID
        tWeaponEffectID = tWeaponShow.effect,    -- 时装武器特效ID
        embattlesID     = embattle,              -- 法阵ID
        notShowMold     = not showNakedMold,     -- 是否不显示裸模(由衣服的荣誉出售标记决定)
        notShowHair     = not showNakedMold,     -- 是否不显示头发(与裸模显示状态保持一致)
    }

    -- 获取角色性别和职业信息
    local sex = SL:GetMetaValue("SEX")          -- 性别
    local job = SL:GetMetaValue("JOB")          -- 职业
    -- 创建角色模型UI
    -- @param PlayerEquip._ui.Node_playerModel - 模型的父节点
    -- @param "model" - 模型的名称
    -- @param 0, 0 - 模型在父节点中的位置坐标
    -- @param sex - 角色性别
    -- @param modelData - 模型显示数据(包含所有装备外观和特效)
    -- @param nil - 预留参数
    -- @param true - 是否显示模型
    -- @param job - 角色职业
    -- @param {showHelmet = showHelmet} - 额外参数,控制头盔显示
    local uiModel = GUI:UIModel_Create(PlayerEquip._ui.Node_playerModel, "model", 0, 0, sex, modelData, nil, true, job, {showHelmet = showHelmet})
    -- 设置模型的锚点为中心点,使其在父节点中居中显示
    GUI:setAnchorPoint(uiModel, 0.5, 0.5)
end

-- 显示装备物品的UI
-- 主要用于处理剑甲分离系统中专用装备格子的显示
-- @param pos - 装备位置索引(如武器位置、衣服位置等)
function PlayerEquip.ShowEquipItemsUI(pos)
    -- 检查位置参数是否有效
    if not pos then 
        return 
    end 

    -- 检查是否存在位置映射表且当前位置有对应的映射
    -- realUIPos: 装备位置到UI位置的映射表(如武器位置映射到1001号专用格子)
    if not PlayerEquip.realUIPos or not PlayerEquip.realUIPos[pos] then 
        return 
    end 

    -- 获取该位置的装备数据
    -- EQUIP_DATA: 存储所有装备位置的数据表
    local data = SL:GetMetaValue("EQUIP_DATA", pos)
    -- 如果该位置没有装备,直接返回
    if not data then 
        return 
    end 

    -- 获取装备在UI上的实际显示位置
    -- 如武器位置(1)映射到专用格子位置(1001)
    local UIPos = PlayerEquip.realUIPos[pos]

    -- 获取装备面板节点
    -- Panel_pos: 装备格子的容器面板
    local itemPanel = PlayerEquip._ui["Panel_pos" .. UIPos]
    -- 检查面板是否可见
    local bShow = GUI:getVisible(itemPanel)
    -- 如果面板不可见,不进行显示操作
    if not bShow then 
        return 
    end 

    -- 获取装备图标节点
    -- Node_: 用于显示装备图标的节点
    local itemNode = PlayerEquip._ui["Node_" .. UIPos]
    -- 检查节点是否存在
    if not itemNode then   
        return 
    end 

    -- 显示装备图标节点
    GUI:setVisible(itemNode, true)
    -- 清除节点上的所有子节点(移除旧的装备图标)
    GUI:removeAllChildren(itemNode)

    -- 创建新的装备图标
    -- CreateEquipItem: 根据装备数据创建对应的图标显示
    PlayerEquip.CreateEquipItem(itemNode, data, UIPos)
end

function PlayerEquip.HideEquipItemsUI(pos)
    if not pos then 
        return 
    end 

    if not PlayerEquip.realUIPos or not PlayerEquip.realUIPos[pos] then 
        return 
    end 

    local UIPos = PlayerEquip.realUIPos[pos] 

    local itemPanel = PlayerEquip._ui["Panel_pos" .. UIPos]
    local bShow = GUI:getVisible(itemPanel)
    if not bShow then 
        return 
    end 

    local itemNode = PlayerEquip._ui["Node_"..UIPos]
    if not itemNode then   
        return 
    end 

    GUI:setVisible(itemNode, false)
    GUI:removeAllChildren(itemNode)
end

function PlayerEquip.OnOpenOrCloseWin(data)
    if data == "PlayerBestRingGUI" then
        PlayerEquip.RefreshBestRingBox()
    end
end

--[[    
    界面关闭回调
]]
function PlayerEquip.CloseCallback()
    PlayerEquip.UnRegisterEvent()
end

function PlayerEquip.RegisterEvent()
    --刷新行会信息
    SL:RegisterLUAEvent(LUA_EVENT_PLAYER_GUILD_INFO_CHANGE, "PlayerEquip", PlayerEquip.RefreshGuildInfo)
    -- 刷新装备信息
    SL:RegisterLUAEvent(LUA_EVENT_PLAYER_EQUIP_CHANGE, "PlayerEquip", PlayerEquip.UpdateEquipUI)
    -- 刷新法阵
    SL:RegisterLUAEvent(LUA_EVENT_PLAYER_EMBATTLE_CHANGE, "PlayerEquip", PlayerEquip.UpdatePlayerView)
    -- 刷新性别
    SL:RegisterLUAEvent(LUA_EVENT_PLAYER_SEX_CHANGE, "PlayerEquip", PlayerEquip.UpdatePlayerView)
    -- 打开/关闭界面
    SL:RegisterLUAEvent(LUA_EVENT_OPENWIN, "PlayerEquip", PlayerEquip.OnOpenOrCloseWin)
    SL:RegisterLUAEvent(LUA_EVENT_CLOSEWIN, "PlayerEquip", PlayerEquip.OnOpenOrCloseWin)
    -- 首饰盒状态改变
    SL:RegisterLUAEvent(LUA_EVENT_BESTRINGBOX_STATE, "PlayerEquip", PlayerEquip.RefreshPlayerBestRingsOpenState)
end

function PlayerEquip.UnRegisterEvent()
    SL:UnRegisterLUAEvent(LUA_EVENT_PLAYER_GUILD_INFO_CHANGE, "PlayerEquip")
    SL:UnRegisterLUAEvent(LUA_EVENT_PLAYER_EQUIP_CHANGE, "PlayerEquip")
    SL:UnRegisterLUAEvent(LUA_EVENT_PLAYER_EMBATTLE_CHANGE, "PlayerEquip")
    SL:UnRegisterLUAEvent(LUA_EVENT_PLAYER_SEX_CHANGE, "PlayerEquip")
    SL:UnRegisterLUAEvent(LUA_EVENT_OPENWIN, "PlayerEquip")
    SL:UnRegisterLUAEvent(LUA_EVENT_CLOSEWIN, "PlayerEquip")
    SL:UnRegisterLUAEvent(LUA_EVENT_BESTRINGBOX_STATE, "PlayerEquip")
end
    撰写回复...