GM 指令:修改玩家属性

必须严格做权限、日志、风控分层 ,不能直接裸改属性值;属性不是简单赋值,要走 AttrMgr 的标准化接口,不然会破坏属性缓存、Buff、装备、套装的联动计算。

1、两种修改模式(区分开)

  1. 临时属性(增益,下线消失 / 时效,Buff形式) 走 BuffMgr,适合GM临时给无敌、攻速、倍攻这种,不改动角色基础档案。
  2. 永久基础属性(存库,永久生效) 修改角色基础面板(基础攻击、血量、防御等),属于高危操作,权限必须最高、强制落地日志。

❌ 禁止做法:

ini 复制代码
-- 错误!直接改attr表,会导致属性快照、Buff叠加全部错乱
player.attr.atk = 9999

2、永久属性GM指令示例(attr_set)

lua 复制代码
--[[
指令:/attr_set 角色名 属性key 值
示例:/attr_set 张三 base_atk 1000
权限:3(最高权限,运营后台专用,禁止普通GM)
依赖:AttrMgr、PlayerMgr、LogMgr
]]
GMMgr:RegisterCmd({
    cmd = "attr_set",
    perm = 3,
    desc = "修改玩家基础永久属性:/attr_set 角色名 attr_key value",
    handler = function(gm_player, target_name, attr_key, val_str)
        if not target_name or not attr_key or not val_str then
            return {ret = -1, msg = "参数错误,用法:/attr_set 角色名 属性名 数值"}
        end
        local val = tonumber(val_str)
        if not val then
            return {ret = -2, msg = "属性值必须是数字"}
        end
        local target = PlayerMgr:GetPlayerByName(target_name)
        if not target then
            return {ret = -3, msg = "目标玩家不在线"}
        end

        -- 走属性管理器接口,内部自动重算总属性、同步客户端
        local ok, err = AttrMgr:SetBaseAttr(target, attr_key, val)
        if not ok then
            return {ret = -4, msg = err}
        end

        AttrMgr:SyncAttr(target)
        LogMgr:LogGm(gm_player.uid, "attr_set",
            string.format("name:%s,key:%s,val:%d", target_name, attr_key, val),
            "GM修改玩家永久基础属性")
        return {ret = 0, msg = "属性修改成功"}
    end
})

配套 AttrMgr 内部接口示意:

lua 复制代码
function AttrMgr:SetBaseAttr(player, key, value)
    -- 可以在这里加白名单:只允许修改配置里开放的基础属性,拦截total_*总属性
    local white_list = {base_hp=true,base_atk=true,base_def=true,base_mp=true}
    if not white_list[key] then
        return false, "不允许修改该属性"
    end
    player.base_attr[key] = value
    self:RecalcAttr(player) -- 重新计算:基础+装备+buff → 总属性
    return true
end

3、临时属性(无敌/倍攻这类,推荐用Buff方案)

ini 复制代码
-- /add_buff 角色名 buffid 秒数
GMMgr:RegisterCmd({
    cmd = "add_buff",
    perm = 3,
    desc = "给玩家添加临时Buff属性",
    handler = function(gm_player, target_name, buffid_str, time_str)
        local buff_id = tonumber(buffid_str)
        local time = tonumber(time_str) or 60
        local target = PlayerMgr:GetPlayerByName(target_name)
        if not target then
            return {ret = -1, msg = "目标不在线"}
        end
        BuffMgr:AddBuff(target, buff_id, time)
        LogMgr:LogGm(gm_player.uid, "add_buff", target_name..","..buff_id, "GM添加Buff临时属性")
        return {ret = 0, msg = "Buff添加成功"}
    end
})

4、风控红线(重点)

  1. 白名单限制 :只能修改 base_* 基础属性,禁止直接修改 total_hp / total_atk 这类最终总属性;总属性是计算结果,不能直接赋值。
  2. 权限隔离:改永久属性的指令权限 perm=3,和刷物品、沙巴克同等级,普通测试GM不给这个权限。
  3. 日志必须完整:操作人、目标、属性key、旧值、新值,最好存独立gm_operate流水表,可审计回滚。
  4. 可选增加二次确认:后台使用时,高危指令增加确认弹窗,避免手滑输错数值。
  5. 离线玩家兼容扩展:如果需要修改离线角色基础属性,要走DB加载角色数据,修改base_attr字段入库,上线时重新计算属性。

5、对比小结

  • 临时效果(无敌、倍数、限时加成)👉 用 add_buff
  • 永久基础面板调整(调基础攻防)👉 用 attr_set,走AttrMgr、严格白名单审计
  • 绝对禁止:直接修改最终总属性

如果你需要,我可以一并写查询玩家属性指令 / 回滚属性指令。

相关推荐
胡写代码1 小时前
删掉的数据还占着唯一键:逻辑删除 + 唯一索引的四次取舍
spring boot·后端
IT_陈寒1 小时前
React的useEffect依赖数组把我坑惨了
前端·人工智能·后端
用户8356290780511 小时前
Python 调整 Excel 工作表显示设置
后端·python
ServBay2 小时前
API Key 泄露如何在 10 分钟内止血?AI 密钥管理必备
后端·ai编程
代码丰2 小时前
大 JSON 放进 Redis 之后,如何用 Stream 解耦耗时任务?
redis·后端·系统架构
武子康3 小时前
手机加语音配件,断开连接后谁来保住这段话?
人工智能·后端·agent
captain3764 小时前
Spring MVC(4)-响应
java·spring boot·后端
武子康4 小时前
Cosmos Curator 总览:从一条样本的组成,选对数据处理入口
人工智能·后端·agent
北冥you鱼5 小时前
Go 语言 CRUD 实战:从接口设计到真实业务场景
开发语言·后端·golang