留言板、行会招募语、邮件标题这类字段会被玩家自由填写,并写入角色变量或转发给持久层。拼接式的写法一旦遇到单引号、注释符,就会把预期外的内容带进存储过程,轻则字段错乱,重则整表被改。思路是在 Lua 层做一道白名单闸门:长度、危险符号两道关卡全部通过才放行,任何一道不过都记计数并拒绝写入。
校验函数保持纯粹:只做判断,不做任何写入,方便在多个入口复用。规则宁可从严,命中即拦截,误杀再逐步放开。示例代码如下:
-- 输入校验:空串、超长、危险符号三类拦截
local BAD_PATTERN = "[;'\"]|/%*|%-%-"
local function checkInput(text, maxLen)
if type(text) ~= "string" or #text == 0 then
return false, "EMPTY"
end
if #text > maxLen then
return false, "TOOLONG"
end
if string.find(text, BAD_PATTERN) then
return false, "RISK"
end
return true, ""
end
招募语发布入口调用校验,通过后直接写入变量;被拦截的记录同时累计次数,同一角色反复触发就冻结发布资格,由值班通过管理命令查询计数后跟进。示例代码如下:
-- 招募语发布:先校验再写入
local player = class(actor)
local ok, reason = checkInput(recruitText, 60)
if not ok then
local cnt = tonumber(getplayvar(player, "HUMAN", "InputRisk") or 0) + 1
setplayvar(player, "HUMAN", "InputRisk", cnt, true)
sendmsg(player, 1, 0, "内容含有受限字符(" .. reason .. "),请调整后再发布。")
return
end
setplayvar(player, "HUMAN", "RecruitText", recruitText, true)
sendmsg(player, 1, 0, "招募语已更新。")
构造六组输入做回归:空串、超长串、含单引号、含注释符、纯正常中文、混合表情符号,前四组必须被拦截且计数递增,后两组正常入库。上线后每日巡检输入拦截计数排行,某个号的计数在短时间内快速上升,大概率是脚本在批量探测,先冻结发布入口再人工核查,避免更多字段被污染。
有次只校验了发布入口,忽略了改名入口,特殊符号借改名字段进了行会展示页,页面渲染直接错乱。教训是校验必须收口成一个公共模块,所有接收玩家输入的入口调用同一份实现,禁止各写各的。规则变更时还要灰度观察:先把拦截改为只记日志不拒绝,观察三天确认无误杀,再切换为硬拦截,玩家侧几乎无感知,出问题也能秒级回退。
表情符号按字节计算长度会超出预期,长度上限按字节数放宽一档,同时限制字符个数,两条约束同时生效才能既拦超长又不误伤正常输入。
全站技术干货持续更新:996 引擎 / Lua 实战帖,语法、参数与示例一篇讲透。进入文章地图 · 查看全部 →
实战应用:用在哪里 装备回收商 NPC 每天按评分收购玩家的装备,裁决之杖、骨玉权杖按攻击、持久加权打分,榜上只要前五名。数…
实战应用:用在哪里 沙巴克攻城是全服行会战的最高舞台:攻方砸开城门、抢占皇宫,守方依托城墙与复活点反打。规则设计的关键是节奏…
实战应用:用在哪里 影分身玩法给法师职业补上生存短板:危急时刻召唤四个影分身分担仇恨,敌人需要在六格范围内分辨真身,猜错就浪…
实战应用:用在哪里 组队邀请、行会宣战这类关键信令丢了没有兜底,玩家只能反复手点,高峰期体验很差。重试机制给信令加确认回执:…
实战应用:用在哪里 新资料片上线首日预约量常是日常十倍,一口气全开会让数据库与登录网关同时过载。滚动开区把开区动作排成队列:…
实战应用:用在哪里 百人同屏的沙巴克外围战场,每个玩家每秒跑动会触发数次位置更新,全部即时下发时广播量随人数平方增长,网关先…