背景

今天有玩家反馈,某个技能的状态buff有概率会出现2个图标,并且状态层数不一样

开始排查问题

  1. 策划是不是又把资源图标配置错了?
    • 最近没有配置新状态buff
  2. 前端代码排查后发现后端发来的状态数据为
    status_list = {{status_id = 2, stacks = 5},{status_id = 2, stacks = 1}}
    
    • 按理说,玩家身上的状态列表status_list,相同status_id只会保存一个数据
  3. 排查后端去重代码
    • 后端 附加状态的 简易混淆 lua 代码
      local apply_id_list = {} -- 带附加的状态列表
      apply_id_list[2] = {}
      
      local status_id, new_status
      -- 遍历所有要附加的状态
      for k, v in pairs(apply_id_list) do
          status_id = k
          v.status_id = status_id
          new_status = true
          -- 遍历玩家身上当前的状态
          for i, info in ipairs(target_status) do 
              -- 如果玩家有这个状态了,就不是新状态
              if info.status_id == status_id then
                  new_status = nil
                  break
              else
                  print("error--- ", info.status_id == status_id, info.status_id, status_id, for_i)
                  assert(not (info.status_id == status_id))
              end
          end
          if new_status then
              -- 如果这是一个新状态,就放入
              target_status[#target_status + 1] = v
          end
      end
      
    • 可以从简易代码看出,状态在附加的时候,是有判断玩家是否已经拥有当前状态的
  4. 换一个思考方向,存放的target_status是个table,会不会是因为table的传递引用问题导致的?
    • 如果 table 没有重新拷贝,那么可能其他地方对这个table数据修改,也会导致target_status中的内容也被修改
    • 直接将 等待附加的状态复制成一个新table放入 target_status 中,发现问题依旧
  5. 没有思路,尝试更换附加另外一个状态
    • !!! bug不会复现了 !!!
  6. 再次换回status_id = 2 的状态
    • !!! bug又出现了 !!!
  7. 开始怀疑,难道这个status_id = 2 的状态有什么特别?
    • 排查一遍状态脚本,并没有什么问题
  8. 在代码判断前,打印状态id数据
    -- 遍历玩家身上当前的状态
    for i, info in ipairs(target_status) do 
        -- 打印状态数据
        print(info.status_id, "==", status_id)
        -- 如果玩家有这个状态了,就不是新状态
        if info.status_id == status_id then
            new_status = nil
            break
        end
    end
    
    • !!! bug消失了 !!!
  9. 这就遇到玄学了,难道还加个打印就能改bug?
    • 难道是量子编程? 观测者效应,打印参数,还能改变数据
  10. 重复几次打印数据,与去除打印数据
      1. 打印数据, !!! bug消失 !!!
      1. 去除打印, !!! bug复现 !!!
  11. 觉得有些可怕
    • 一下子不懂 lua 代码了
  12. 尝试在判断状态id是否相等的地方增加else,增加断言数据
        for i, info in ipairs(target_status) do 
        -- 如果玩家有这个状态了,就不是新状态
        if info.status_id == status_id then
            new_status = nil
            break
        else
            print("error--- ", info.status_id == status_id, info.status_id, status_id, for_i)
            assert(not (info.status_id == status_id))
        end
    
    • !!! 断言报错了 !!!
    • 断言发现 状态id 确实相等,可能如果相等不应该能走入else部分
  13. 开始准备从我们的源代码中提取最小可复现的用例
    • 我们的项目使用 c++ 和 lua, 并且有好几千个lua文件,提取过程十分缓慢
  14. 提取用例,提交报告
    • 第二天作者说修复了
  15. 编译最新版的 LuaJIT
    • 还是会出现 bug, 出现的概率变成非常低
  16. 继续缩减最小可复现的用例
    • 继续提交可复现的用例
  17. 又过了一周,作者又提交了新的bug修复
    • 说遗漏了我编译 LuaJIT 的参数
  18. 一波三折的bug终于修复了

相关链接

发表评论