CHUAN2 DEV ENGINE
996 正版授权研发中心 · 360 授权合作教学中心 · 抖音传奇直播合作授权 · 快手推广运营商授权
OFFICIAL LICENSED ACADEMY 查验官方授权证书 →
// 威海旷世互娱教学基地 · 技术文章
进阶实战游戏功能996引擎

Lua+rawset:绕过__newindex的安全写入本质

2026-09-29 18:24 作者:996 技术组 996引擎Lua教程传奇脚本进阶实战游戏功能996引擎

【语法算法】

rawset 的安全写入本质就这一行:

lua
rawset(t, key, value)

rawset 绕过 __newindex 元方法直接写入表——rawset 的全部语义就这一行。可这一行的前后各有一个坑:前面是"表设了 __newindex 后普通赋值不走 rawset",后面是"rawset 里调 rawset 会死循环"。今天拆开。

一、拦截、绕过、安全三段

rawset 的三段。拦截:表的元表设了 __newindex 后所有新键赋值都走 __newindex 函数——普通赋值被拦截——rawset 绕过拦截直接写入——绕过的是元方法不是表本身。绕过:rawset(t, k, v) 不查元表直接写——即使元表有 __newindex 也不触发——绕过后写入的值不会经过 __newindex 的转换逻辑——rawset 的语义就是"无视拦截直接写入"。安全:rawset 是 C 级函数——没有函数调用开销——比普通赋值还快——但 rawset 不做类型检查——写入什么类型就是什么类型——调用方负责保证类型正确。三段连起来:rawset 玩的是"绕过抽象层直接写底层"——调试和性能分析时 rawset 比 # 更诚实。

mermaid
graph TD
    A["t.newKey = value"] --> B{"t有__newindex?"}
    B -->|是| C["调用__newindex(t, k, v)"]
    C --> D["拦截或转换"]
    B -->|否| E["直接写入"]
    A --> F["rawset(t, k, v)"]
    F --> G["绕过__newindex直接写入"]

二、rawset 的正确写法

lua
local proxy = setmetatable({}, {
    __newindex = function(t, k, v)
        if type(v) == "string" then
            rawset(t, k, v:upper())            -- 绕过__newindex写入转换后的值
        else
            SL:ShowError("只接受字符串")
        end
    end
})

proxy.name = "hello"
print(proxy.name)  -- HELLO

proxy.age = 42
-- 报错: 只接受字符串

rawset 在 __newindex 函数里写入转换后的值——绕过元方法避免无限递归——如果用普通赋值就会再次触发 __newindex——无限递归直到栈溢出。

三、rawset 的纪律与 rawget 的配对

rawset 的纪律是"不在 __newindex 里调 rawset 写入未转换的值"——__newindex 的职责是拦截和转换——转换完成后用 rawset 写入——如果 rawset 写入的值还会触发 __newindex,就形成了无限循环。和 rawget 的配对也值得记:rawget 绕过 __index 直读、rawset 绕过 __newindex 直写——raw 家族的读写操作对称配对——调试时用 raw 家族逐层排查,就能定位问题出在哪一层元方法。最后一条纪律:rawset 不触发 __newindex 但也不触发 __close——to-be-closed 变量用 rawset 赋值不会触发清理——to-be-closed 变量的赋值必须走普通赋值路径。

作者履历与出处

本文由 996 技术组基于 996 引擎官方知识库与浮生梦老师课程体系整理。团队长期从事传奇类引擎 Lua 后端逻辑、客户端界面与商业版本交付,内容以官方知识库与真实项目为出处,按版本持续修订。

← 返回文章地图返回研学路径

幂尔框架 · 实战干货 · 接口调用

LATEST ARTICLES

全站技术干货持续更新:996 引擎 / Lua 实战帖,语法、参数与示例一篇讲透。进入文章地图 · 查看全部 →

进阶实战游戏功能

连枝血纹:打这一只,那一只陪着疼

【游戏功能】 var ld2=Math.max(1,Math.round(d 0.25)) ——先拆这一行。连枝转移的账就在…

2026-10-01 21:55 996 技术组
进阶实战游戏功能

让先礼纹:让它一招,下一刀翻倍

【游戏功能】 前阵子的投诉出得冤:玩家开着让先纹被怪的头一招打掉了半管血,找到客服问"让先让了个寂寞"。翻流水发现机制没算错…

2026-10-01 21:55 996 技术组
进阶实战游戏功能

秋后账纹:笔笔记着,收摊一笔清算

【游戏功能】 上一版留了条只在连打两场时冒头的隐蔽报错:秋后纹第二次开的清算比第一次翻倍——头一场十二笔账清完没清零,第二场…

2026-10-01 21:55 996 技术组
进阶实战游戏功能

悔刀仙纹:砍出去的刀能收回,重砍更重

【游戏功能】 先抛一个坑:砍出去的刀,能收回来吗?刀光落了地、数字蹦出来、血条掉了——按理说木已成舟。可玩家心里都有过那一拍…

2026-10-01 21:55 996 技术组
进阶实战游戏功能

头刀卯纹:新怪头一刀,先点先得加倍

【游戏功能】 var fresh=(tg===M)?fr.a:fr.b ——先拆这一行。两只怪,两本"点没点过卯"的小账,出…

2026-10-01 21:55 996 技术组
进阶实战游戏功能

憋劲蛮纹:落空三刀不白落,憋成一刀重的

【游戏功能】 上个月一场差评事故:一个闪避堆得高的怪成了玩家的噩梦——十刀落空七刀,打得着的两三刀又不痛不痒,玩家在频道里骂…

2026-10-01 21:55 996 技术组