当前位置 : 145z游戏站 | 热血传奇 | 技术教程 | 

传奇NPC脚本非法字符过滤实战:@@InPutString输入拦截与CheckStrLen/FilterList全链路

热度:
@@InPutString指令触发后客户端弹文本输入框,玩家录入内容写入S变量(S0–S99),后续脚本通过<$STR(SX)>读取。这条链路没有任何内置转义,玩家输入|、/、\、<、>、$、@、脚本关键字、系统命令字符串,都会原样进入变量。如果服务端逻辑用该变量拼接数据库查询、写TXT记录、做EQUAL/CHECKLEVELEX之外的字符串比对,脏数据直接穿透。过滤必须在“回车确认后、业务逻辑前”这一段完成,不能依赖客户端弹窗自身的限制。

一、引擎级过滤列表(第一道闸)

Hero引擎路径:M2Server→查看→列表信息→其他设置→字符过滤,或编辑Mir200\Envir\GuildRankNameFilter.txt(部分版本读此文件)。添加每行一个敏感词或非法字符序列,玩家录入命中后不进入回调段,直接跳转[@IsInFilterList](3K引擎跳[@MsgFilter])。

配置示例(GuildRankNameFilter.txt):

@
@@
~
..
\
/
<
>
|
$
script
call
goto
exec


回调处理:
[@IsInFilterList]
#SAY
你输入的内容包含非法字符,请重新输入!\
<返回/@Main>


3K引擎对应:
[@MsgFilter]
#SAY
输入内容命中过滤列表,请重新输入!\
<返回/@Main>


注意:过滤列表是全局生效的,不仅拦@@InPutString,行会名称创建、角色改名、聊天频道也会走同一张表。往里加@、$、<、>、|这些脚本语法符号是最低限度的防护。

二、回调段内变量判空与长度校验(第二道闸)

Hero引擎@@InPutStringX回调段名为[@CallInPutStringX],3K为[@InPutStringX]。进入回调后第一件事是判空和长度,用CheckStrLen指令:
[@CallInPutString10]
#IF
CheckStrLen<$STR(S10)>1
#ACT
MESSAGEBOX输入不能为空!
GOTO@Main
#IF
CheckStrLen<$STR(S10)>16
#ACT
MESSAGEBOX输入长度不能超过16个字符!
GOTO@Main
#ELSE
#ACT
;通过校验,进入业务逻辑
GOTO@ProcessInput


CheckStrLen语法:CheckStrLen<字符串>长度值,不带比较符时判定“大于等于该长度”;部分引擎支持CheckStrLen<字符串><5表示小于5。实际写法以引擎版本为准,保守做法是用两次CheckStrLen分别卡下限和上限。

三、字符级逐字扫描(第三道闸)

引擎过滤列表只能做子串匹配,不能做白名单。如果需要严格限制“只允许中文+字母+数字”,用脚本逐字符遍历S变量,配合CheckContainsStr或EQUAL比对ASCII范围。由于传奇脚本没有正则,只能用笨办法——把输入拆成单字符逐一比对:
[@ProcessInput]
;假设S10已通过长度校验
;用MOVS11=首字符,循环判断是否在白名单内
;以下为逻辑示意,实际引擎需借助自定义变量+跳转实现

#IF
CheckContainsStr<$STR(S10)>@
#ACT
MESSAGEBOX包含非法字符@!
GOTO@Main
#IF
CheckContainsStr<$STR(S10)><
#ACT
MESSAGEBOX包含非法字符<!
GOTO@Main
#IF
CheckContainsStr<$STR(S10)>>
#ACT
MESSAGEBOX包含非法字符>!
GOTO@Main
#IF
CheckContainsStr<$STR(S10)>|
#ACT
MESSAGEBOX包含非法字符|!
GOTO@Main
#IF
CheckContainsStr<$STR(S10)>$
#ACT
MESSAGEBOX包含非法字符$!
GOTO@Main
#IF
CheckContainsStr<$STR(S10)>\
#ACT
MESSAGEBOX包含非法字符\!
GOTO@Main
#IF
CheckContainsStr<$STR(S10)>/
#ACT
MESSAGEBOX包含非法字符/!
GOTO@Main
#ELSE
#ACT
GOTO@SaveToDB


CheckContainsStr用法:CheckContainsStr<源字符串>子串,命中返回真。逐条写虽然冗长,但覆盖完全,且每条都能给出精确错误提示。

四、数据库写入前的二次校验

如果输入内容最终要写TXT或入库(如角色改名、行会公告、自定义称号),在WRITETEXT/WRITELINE之前再加一道EQUAL比对,防止空串或纯空格:
[@SaveToDB]
#IF
EQUALS10
#ACT
MESSAGEBOX内容为空,拒绝写入!
GOTO@Main
#ELSE
#ACT
WRITETEXT..\Envir\UserData\Titles.txt<$STR(S10)>
SENDMSG6称号[<$STR(S10)>]已记录!
CLOSE


五、不同引擎的回调差异速查

项目Hero引擎3K引擎

触发指令@@InPutStringX@@InPutStringX

回调段名[@CallInPutStringX][@InPutStringX]

过滤命中段[@IsInFilterList][@MsgFilter]

变量范围S0–S99(部分支持扩展)S0–S99

判空方式CheckStrLen<$STR(SX)>1EQUALSX或CheckStrLen

过滤列表位置列表信息→其他设置/GuildRankNameFilter.txt插件消息过滤列表

六、完整三层过滤示例(Hero引擎,角色自定义称号)
[@Main]
请为角色设定一个称号:<输入称号/@InputTitle>\

[@InputTitle]
@@InPutString20请输入称号(1-10字,仅限中文/字母/数字):

[@CallInPutString20]
;第一层:引擎过滤列表已自动拦截,命中走[@IsInFilterList]
#IF
CheckStrLen<$STR(S20)>1
#ACT
MESSAGEBOX称号不能为空!
GOTO@Main
#IF
CheckStrLen<$STR(S20)>11
#ACT
MESSAGEBOX称号不能超过10个字符!
GOTO@Main
#IF
CheckContainsStr<$STR(S20)>@
#ACT
MESSAGEBOX称号不能包含@符号!
GOTO@Main
#IF
CheckContainsStr<$STR(S20)><
#ACT
MESSAGEBOX称号不能包含<符号!
GOTO@Main
#IF
CheckContainsStr<$STR(S20)>>
#ACT
MESSAGEBOX称号不能包含>符号!
GOTO@Main
#IF
CheckContainsStr<$STR(S20)>|
#ACT
MESSAGEBOX称号不能包含|符号!
GOTO@Main
#IF
CheckContainsStr<$STR(S20)>$
#ACT
MESSAGEBOX称号不能包含$符号!
GOTO@Main
#IF
CheckContainsStr<$STR(S20)>\
#ACT
MESSAGEBOX称号不能包含\符号!
GOTO@Main
#IF
CheckContainsStr<$STR(S20)>/
#ACT
MESSAGEBOX称号不能包含/符号!
GOTO@Main
#ELSE
#ACT
WRITETEXT..\Envir\UserData\Title_<$USERNAME>.txt<$STR(S20)>
SENDMSG6称号[<$STR(S20)>]设定成功!
CLOSE

[@IsInFilterList]
#SAY
输入的称号包含系统保留字符,请更换内容!\
<重新输入/@Main>


七、常见故障排查

•输入后脚本无响应:检查回调段名是否按引擎写对(Hero漏Call、3K多Call都会死)

•过滤列表加了词但不生效:确认M2是否执行了“重新加载列表信息”或重启;GuildRankNameFilter.txt改完需重载

•CheckContainsStr不识别中文:部分老版本引擎只支持单字节字符匹配,中文需用CheckStrLen间接限制长度+过滤列表兜底

•变量读出来是空:确认@@InPutStringX的X与回调段里读的SX编号一致,别写成@@InPutString20却在[@CallInPutString20]里读S10

•过滤列表误杀正常输入:逐条排查,把常用标点(如空格、下划线)从过滤文件中移除,改用脚本层CheckContainsStr精确拦截

@@InPutString的过滤不是单一指令能解决的,必须三层叠加:引擎过滤列表拦语法符号和敏感词→回调段CheckStrLen卡长度和判空→CheckContainsStr逐字符白名单/黑名单扫描→写入前EQUAL最终确认。少任何一层,输入链路都存在被脏数据击穿的可能。
[顶部]