找回密码
 register
搜索
查看: 41|回复: 0

洱海月 珍兽锁定功能修复笔记

[复制链接]
  • 打卡等级:本地老炮
  • 打卡总天数:533
  • 打卡月天数:22
  • 打卡总奖励:530
  • 最近打卡:2026-06-24 01:45:59
Waylee 发表于 2026-4-2 09:07 | 显示全部楼层 |阅读模式 | Google Chrome | Windows 10

马上注册,查看网站隐藏内容!!

您需要 登录 才可以下载或查看,没有账号?register

×

1. 规则

当前代码的行为如下:

  1. 随身珍兽可以锁定、发起解锁、显示解锁中。
  2. 珍兽银行里的珍兽只显示锁状态,不直接发起锁/解锁。
  3. 锁/解锁请求只处理随身珍兽,银行里的珍兽要先取回随身再解锁。
  4. 锁定珍兽可以存入仓库,也可以从仓库取出。
  5. 珍兽进仓、仓库互换只拦交易中的珍兽,不拦锁定状态。
  6. 锁定珍兽仍然不能交易、不能摆摊、不能上架。

2. 先看客户端入口

服务端规则按客户端现有入口来定。

2.1 锁/解锁入口只在随身珍兽列表

文件:客户端/Interface/ItemCoffer/ItemCoffer.lua

function ItemCoffer_Lock_Clicked()
    if( g_nTheTabIndex == 2 )  then
        local nPetIndex = ItemCoffer_PetList:GetFirstSelectItem();
        if(nPetIndex == -1)  then
            PlayerPackage:Lock("lock", "pet", -1);
        else
            PlayerPackage:Lock("lock", "pet", g_PetIndex[nPetIndex]);
        end
    end
end

function ItemCoffer_Unlock_Clicked()
    if( g_nTheTabIndex == 2 )  then
        local nPetIndex = ItemCoffer_PetList:GetFirstSelectItem();
        if(nPetIndex == -1)  then
            PlayerPackage:Lock("unlock", "pet", -1);
        else
            PlayerPackage:Lock("unlock", "pet", g_PetIndex[nPetIndex]);
        end
    end
end

这里传的是随身珍兽索引,不是银行索引。

2.2 银行界面只有显示,没有锁/解锁入口

文件:客户端/Interface/PetBankMain/PetBankMain.lua

if (PlayerPackage:IsPetLock(i-1,1) == 1)  then
    local nUnlockElapsedTime = PlayerPackage:GetPUnlockElapsedTime_Pet(i-1 ,1);
end
function PetBankMain_Refuse_Click()
    Pet:SavePetIntoBank_PetBank(PETBANK_CURRENT_SELECT,0); -- 银行到背包
end

这里就能把服务端规则定下来:

  • 银行界面会显示锁状态。
  • 银行界面没有 OpenLockFrame / Lock("unlock","pet", ...)
  • 所以服务端不能把“银行里的锁定珍兽禁止取出”做成硬规则,否则会卡死。

3. 第一步:补 CGAskLockObj.PET

文件:/home/ubuntu/Game2/services/scene/scenecore.lua

原来的问题是 char_ask_lock_obj() 只处理 ITEMPET 请求直接失败。

主要改法如下:
***付费内容***

这里保持两个限制:

  • 只允许“随身珍兽”进锁/解锁请求。
  • 不要在这里支持银行珍兽,否则会和客户端真实入口冲突。

4. 第二步:在 human.lua 建一套珍兽解锁状态管理

文件:/home/ubuntu/Game2/services/scene/obj/human.lua

4.1 新增常量

***付费内容***

4.2 新增心跳刷新

if self:has_pending_pet_unlock() then
    if self.pet_unlock_refresh_tick > delta_time then
        self.pet_unlock_refresh_tick = self.pet_unlock_refresh_tick - delta_time
    else
        self.pet_unlock_refresh_tick = PET_LOCK_REFRESH_INTERVAL_MS
        self:refresh_locked_pet_unlock_state(true)
    end
else
    self.pet_unlock_refresh_tick = 0
end

4.3 新增解锁时间表

function human:get_pet_unlock_time_map()
    self.game_flag = self.game_flag or {}
    local unlock_map = self.game_flag[PET_LOCK_UNLOCK_TIME_KEY]
    if type(unlock_map) ~= "table" then
        unlock_map = {}
        self.game_flag[PET_LOCK_UNLOCK_TIME_KEY] = unlock_map
    end
    return unlock_map
end

function human:is_pet_unlocking_by_guid(guid)
    local unlock_time = self:get_pet_unlock_time_by_guid(guid)
    return unlock_time > os.time()
end

function human:set_pet_unlock_time_by_guid(guid, unlock_time)
    local unlock_map = self:get_pet_unlock_time_map()
    unlock_map[make_pet_lock_guid_key(guid)] = math.max(0, math.floor(tonumber(unlock_time) or 0))
end

function human:clear_pet_unlock_time_by_guid(guid)
    local unlock_map = self:get_pet_unlock_time_map()
    unlock_map[make_pet_lock_guid_key(guid)] = nil
end

5. 第三步:统一封装珍兽锁字段发包

Game.exe 用到的就是珍兽详情包里的这两个字段:

  • unknow_5:锁状态位
  • unknow_10:解锁中的时间编码

这两个字段统一放进 human:sync_pet_lock_packet_fields()

文件:/home/ubuntu/Game2/services/scene/obj/human.lua

***付费内容***

这里不要再回到旧写法:

  • unknow_52/3,不要再写死成 2
  • unknow_10 不是固定 0,解锁中时要编码。
  • 编码公式在 get_pet_unlock_packet_value_by_guid() 里统一处理。

6. 第四步:所有珍兽详情包都必须走统一锁字段

6.1 pet_detail.lua

文件:/home/ubuntu/Game2/lualib/pet_detail.lua

function pet_detail:calculate_pet_detail_attrib(msg)
    ...
    msg:set_unknow_2(-1)
    msg:set_titles(self:get_titles())
    msg:set_current_title(self:get_current_title())
    local owner = self:get_owner()
    if owner and owner.sync_pet_lock_packet_fields then
        owner:sync_pet_lock_packet_fields(self, msg)
    else
        msg:set_unknow_5(self:is_lock() and 3 or 2)
        msg:set_unknow_10(0)
    end
    msg:set_unknow_11(5399)
    msg:set_unknow_13(0)
end

6.2 pet_attrib.lua

文件:/home/ubuntu/Game2/lualib/db/pet_attrib.lua

if creator and creator.sync_pet_lock_packet_fields then
    creator:sync_pet_lock_packet_fields(pet, refresh_detail_attrib)
else
    refresh_detail_attrib:set_unknow_5(pet.is_lock and pet:is_lock() and 3 or 2)
    refresh_detail_attrib:set_unknow_10(0)
end

这里保持一个做法:

  • 不允许再写死 set_unknow_5(2)
  • 不允许再写死 set_unknow_10(0)

7. 第五步:补珍兽银行刷新包

银行界面不是单个 GCDetailAttrib_Pet,而是整包 GCPetBankListUPData

文件:/home/ubuntu/Game2/services/scene/obj/human.lua

function human:send_pet_bank_list_update()
    local scene = self:get_scene()
    local pet_bank_container = self:get_pet_bank_container()
    if not scene or not pet_bank_container then
        return
    end

    local pet_list = {}
    for i = 0, pet_bank_container:get_size() - 1 do
        local pet = pet_bank_container:get_item(i)
        if pet then
            local msg_detail = packet_def.GCDetailAttrib_Pet.new()
            pet:calculate_pet_detail_attrib(msg_detail)
            msg_detail.unknow_6 = 0
            local pet_buffer = msg_detail:bos()
            pet_list[i + 1] = pet_buffer
        end
    end

    local msg = packet_def.GCPetBankListUPData.new()
    msg.pet_list = pet_list
    scene:send2client(self, msg)
end

然后在仓库增删换后统一调用:

文件:/home/ubuntu/Game2/services/scene/scenecore.lua

human:send_pet_bank_list_update()

8. 第六步:珍兽银行的业务规则按客户端入口来

文件:/home/ubuntu/Game2/services/scene/scenecore.lua

char_pet_bank_add_pet() 改成下面这套逻辑:

function scenecore:char_pet_bank_add_pet(who, bap)
    local human = self.objs[who]
    if not human then return end
    human:refresh_locked_item_unlock_state(false)
    human:refresh_locked_pet_unlock_state(false)

    local pet_bag_container = human:get_pet_bag_container()
    local pet_bank_container = human:get_pet_bank_container()
    local function check_pet_not_in_exchange(pet, tips)
        if not pet then
            return false
        end
        if self:is_pet_in_exchange(pet) then
            human:notify_tips(tips or "交易中的珍兽无法进行此操作")
            return false
        end
        return true
    end 
    if bap.type == 0 then
        -- 银行 -> 背包:允许取出锁定珍兽
    elseif bap.type == 1 then
        -- 背包 -> 银行:允许锁定珍兽存入,只拦交易状态
        local pet = pet_bag_container:get_pet_by_guid(bap.pet_guid_from)
        if not check_pet_not_in_exchange(pet, "交易中的珍兽无法存入仓库") then
            return
        end
    elseif bap.type == 2 then
        -- 背包 <-> 银行:只拦背包侧交易状态,不拦锁定状态
        local pet_from = pet_bag_container:get_item(from)
        if not check_pet_not_in_exchange(pet_from, "交易中的珍兽无法与仓库互换") then
            return
        end
    end

    human:send_pet_bank_list_update()
end

这里容易踩坑:

  • 银行里的锁定珍兽必须允许取出。
  • 锁定珍兽必须允许存仓,否则锁状态跨容器会断在半路。
  • 背包 -> 银行、背包 <-> 银行只拦交易中的珍兽,不拦锁定状态。
  • 客户端没有“直接解锁银行珍兽”的入口,解锁还是回到随身界面做。

9. 第七步:存档恢复,不然重登丢锁状态

文件:/home/ubuntu/Game2/lualib/pet_detail.lua

9.1 加载时恢复

***付费内容***

9.2 保存时写回

function pet_detail:copy_raw_data()
    return {
        skills = self.skill_list,
        titles = self.titles,
        lv1_attrib = self.db:get_lv1_attrib(),
        attrib = self.db:get_db_save_attrib(),
        equips = self:get_equip_container():get_save_data(),
        locked = self.locked == true,
        cool_down_times = self.cool_down_times
    }
end

10. 第八步:交易/摆摊等入口补刷新

文件:/home/ubuntu/Game2/lualib/human_item_logic.lua

function human_item_logic:is_pet_can_exchange(human, contaner, bag_index, locked_tips)
    human:refresh_locked_pet_unlock_state(false)
    local pet = contaner and contaner:get_item(bag_index)
    if not pet then
        return false
    end
    if pet.is_lock and pet:is_lock() then
        human:notify_tips(locked_tips or "该珍兽已在交易或摆摊中")
        return false
    end
    return true
end

原因:

  • 有些入口不走 check_pet_operable()
  • 必须先刷新解锁状态,再判断 is_lock()

11. 第九步:银行容器也要绑定 owner

文件:/home/ubuntu/Game2/services/scene/obj/human.lua

self.pet_bank_container:init(pet_bank_bag_size, data.pet_bank_list,define.CONTAINER_INDEX.HUMAN_PET_BANK,self)

不传 self 的话,银行里的 pet_detail:get_owner() 拿不到 human,发包时就拿不到统一锁状态。


12. 收尾检查

代码改完后,至少把下面几项过一遍:

  1. char_ask_lock_obj() 已支持 OBJ_TYPE.PET
  2. 锁/解锁请求只处理随身珍兽,不处理银行珍兽。
  3. human.lua 里有 pet_lock_unlock_time 时间表和心跳刷新。
  4. pet_detail.lua / pet_attrib.lua 不再写死 unknow_5=2unknow_10=0
  5. GCPetBankListUPDatacalculate_pet_detail_attrib(),而不是旧的固定字段。
  6. 银行锁定珍兽允许取出到随身。
  7. 锁定珍兽允许存仓,仓库互换不拦锁定状态。
  8. 交易、摆摊、上架仍会拦锁定珍兽。
  9. pet_detail:copy_raw_data() 已保存 locked

13. 检查记录

先跑语法检查:

luac -p /home/ubuntu/Game2/services/scene/obj/human.lua
luac -p /home/ubuntu/Game2/services/scene/scenecore.lua
luac -p /home/ubuntu/Game2/lualib/db/pet_attrib.lua
luac -p /home/ubuntu/Game2/lualib/pet_detail.lua
luac -p /home/ubuntu/Game2/lualib/human_item_logic.lua

联机把下面几项点过:

  • 珍兽锁定正常。
  • 珍兽解锁正常。
  • 银行显示锁状态正常。
  • 锁定珍兽可存入银行。
  • 银行锁定珍兽可取出。
  • 锁定珍兽不能交易、摆摊、上架。
付费看帖
剩余 30% 内容需要支付 66.00 金币 后可完整阅读
支持付费阅读,激励作者创作更好的作品。
您需要登录后才可以回帖 登录 | register

本版积分规则

QQ|雪舞知识库 ( 浙ICP备15015590号-1 | 萌ICP备20232229号|浙公网安备33048102000118号 )|天天打卡

GMT+8, 2026-6-24 05:47 , Processed in 0.062107 second(s), 26 queries .

Powered by Discuz! X5.0

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表