Previous topicNext topic
 Gameofmir Help
Help > 游戏引擎功能系统 > 功能操作命令 >
HTTP / JSON 脚本扩展

HTTP / JSON 脚本扩展手册

M2 引擎 · NPC 脚本异步 HTTP 请求与 JSON 解析命令   HttpGetEx HttpPostEx
目录
  1. HTTP 请求命令
  2. JSON 条件命令
  3. JSON 动作命令
  4. 路径语法
  5. 综合示例
  6. 使用场景
  7. 注意事项

一、HTTP 请求命令

1. HttpGetEx #ACT

HttpGetEx <URL> @Label VarName
参数说明
URL完整的 http:// 或 https:// 地址
@Label请求完成后跳转的 NPC 脚本标签
VarName接收响应文本的字符串变量,如 S100
; 示例:查询服务器公告
[@查询公告]
#ACT
HttpGetEx http://api.mygame.com/notice/today @公告返回 S20
BREAK

[@公告返回]
#SAY
今日公告:\
<$STR(S20)>

2. HttpPostEx #ACT

HttpPostEx <URL> <Body> form|json|text @Label VarName
参数说明
URL完整地址
Body请求体内容
类型form / json / text
@Label完成后跳转标签
VarName接收响应文本的字符串变量
类型Content-Type说明
formapplication/x-www-form-urlencoded; charset=utf-8k=v&k2=v2 拆分并 URL 编码
jsonapplication/json; charset=utf-8正文自动转 UTF-8
texttext/plain; charset=utf-8正文自动转 UTF-8
 

; 示例:表单方式上报签到
[@每日签到]
#ACT
HttpPostEx http://api.mygame.com/sign account=<$USERNAME>&role=<$USERNAME> form @签到返回 S21
BREAK

[@签到返回]
#SAY
签到结果:\
<$STR(S21)>
; 示例:JSON 提交领奖请求,解析返回
[@领取奖励]
#ACT
HttpPostEx http://api.mygame.com/reward/claim {"role":"<$USERNAME>","id":1001} json @领奖返回 S22
BREAK

[@领奖返回]
#ACT
; 假设返回 {"code":0,"msg":"ok","gold":5000}
JsonGetNodeValue S22 code M1 -1
JsonGetNodeValue S22 msg  S23 未知
JsonGetNodeValue S22 gold M2 0
#SAY
结果:<$STR(S23)>\
金币+<$STR(M2)>
; 示例:上报玩家反馈(纯文本正文可以包含空格)
[@提交反馈]
#ACT
HttpPostEx http://api.mygame.com/feedback 玩家 <$USERNAME> 反馈:游戏体验良好 text @反馈返回 S24
BREAK

[@反馈返回]
#SAY
服务器回执:\
<$STR(S24)>
执行结果:请求在后台线程异步执行;无论成功或失败,响应文本都会写入 VarName,随后自动跳转 @Label

二、JSON 条件命令 #IF

下列示例均假设 S30 = {"role":{"name":"剑圣","level":55,"bag":[1001,1002,1003],"vip":{"grade":3},"title":null}}

1. CheckJsonNodeExists

CheckJsonNodeExists <Json> <Path>

节点存在即为真(值为 null 也算存在)。

#IF
CheckJsonNodeExists S30 role.name
#ACT
SENDMSG 6 role.name 存在

2. CheckJsonNodeIsArray

CheckJsonNodeIsArray <Json> <Path>

节点存在且为数组时为真。

#IF
CheckJsonNodeIsArray S30 role.bag
#ACT
SENDMSG 6 role.bag 是数组

3. CheckJsonNodeIsObject

CheckJsonNodeIsObject <Json> <Path>

节点存在且为对象(字典)时为真。

#IF
CheckJsonNodeIsObject S30 role.vip
#ACT
SENDMSG 6 role.vip 是对象

4. CheckJsonNodeIsNull

CheckJsonNodeIsNull <Json> <Path>

节点存在且值为 null 时为真。

#IF
CheckJsonNodeIsNull S30 role.title
#ACT
SENDMSG 6 role.title 是 null

三、JSON 动作命令 #ACT

1. JsonGetNodeValue

JsonGetNodeValue <Json> <Path> VarOut [Default]
#ACT
JsonGetNodeValue S30 role.name S31 未知
SENDMSG 6 名字:<$STR(S31)>     ; 名字:剑圣

JsonGetNodeValue S30 role.job S31 战士
SENDMSG 6 职业:<$STR(S31)>     ; 职业:战士 (节点不存在用默认值)

2. JsonGetNodeArrLen

JsonGetNodeArrLen <Json> <Path> VarOut [Default]
#ACT
JsonGetNodeArrLen S30 role.bag  M10 0
SENDMSG 6 背包物品数:<$STR(M10)>   ; 3

JsonGetNodeArrLen S30 role.mail M11 0
SENDMSG 6 邮件数:<$STR(M11)>      ; 0 (节点不存在用默认值)

四、路径语法

使用 . 表示层级、[N] 表示数组下标,区分大小写。

路径取值
role.name剑圣
role.level55
role.bag数组本身
role.bag[0]1001
role.vip.grade3
role.title空串 (null)

五、综合示例:遍历数组

#IF
#ACT
Mov S30 {"role":{"name":"剑圣","level":55,"bag":[1001,1002,1003],"vip":{"grade":3},"title":null}}

#IF
CheckJsonNodeExists S30 role.name
CheckJsonNodeIsArray S30 role.bag
#ACT
JsonGetNodeValue  S30 role.name S31 未知
JsonGetNodeArrLen S30 role.bag  M10 0
SENDMSG 6 名字:<$STR(S31)>
SENDMSG 6 背包物品数:<$STR(M10)>

Mov M11 0
While M11 < M10
    ; 拼接路径:role.bag[M11]
    Mov S32 role.bag[<$STR(M11)>]
    JsonGetNodeValue S30 S32 S33 0
    SENDMSG 6 <$STR(S32)>:<$STR(S33)>
    Inc M11 1
EndWhile

; 输出:
; 名字:剑圣
; 背包物品数:3
; role.bag[0]:1001
; role.bag[1]:1002
; role.bag[2]:1003

#ELSEACT
SENDMSG 6 条件不满足

六、使用场景

场景 1 · GM 后台充值到账

玩家充值后,GM 系统通过 HTTP 通知游戏服务器给玩家加元宝。

; NPC 对话里发起查询:有没有未到账订单
[@查询订单]
#ACT
HttpGetEx http://api.mygame.com/pay/query?account=<$USERNAME> @订单处理 S40
BREAK

[@订单处理]
#ACT
; 返回 {"code":0,"order":"N2026041901","gold":6800,"status":1}
JsonGetNodeValue S40 code   M20 -1
#IF
Equal M20 0
CheckJsonNodeExists S40 order
#ACT
JsonGetNodeValue S40 order S41 0
JsonGetNodeValue S40 gold  M21 0
GAMEGOLD +  <$STR(M21)>
SENDMSG 6 订单 <$STR(S41)> 已到账:元宝+<$STR(M21)>
#ELSEACT
SENDMSG 6 暂无未到账订单

场景 2 · 防沉迷 / 实名校验

调用第三方实名接口,只有通过的账号才能进入主城。

[@实名校验]
#ACT
HttpPostEx http://api.mygame.com/idcard {"account":"<$USERNAME>"} json @校验返回 S50
BREAK

[@校验返回]
#ACT
JsonGetNodeValue S50 pass M30 0
#IF
Equal M30 1
#ACT
MAPMOVE 0 333 333
SENDMSG 6 实名通过,欢迎进入游戏
#ELSEACT
SENDMSG 6 尚未实名,请到官网完成实名认证
KICK

场景 3 · 跨服排行榜拉取

NPC 展示中心服下发的 TOP3 战力榜。

[@查战力榜]
#ACT
HttpGetEx http://api.mygame.com/rank/power?top=3 @榜单返回 S60
BREAK

[@榜单返回]
#ACT
; 返回 {"list":[{"name":"剑圣","p":99999},{"name":"法神","p":88888},{"name":"道尊","p":77777}]}
#IF
CheckJsonNodeIsArray S60 list
#ACT
JsonGetNodeArrLen S60 list M40 0

JsonGetNodeValue S60 list[0].name S61 -
JsonGetNodeValue S60 list[0].p    M41 0
JsonGetNodeValue S60 list[1].name S62 -
JsonGetNodeValue S60 list[1].p    M42 0
JsonGetNodeValue S60 list[2].name S63 -
JsonGetNodeValue S60 list[2].p    M43 0

#SAY
【战力榜 TOP3】\
1. <$STR(S61)>  <$STR(M41)>\
2. <$STR(S62)>  <$STR(M42)>\
3. <$STR(S63)>  <$STR(M43)>
#ELSEACT
SENDMSG 6 榜单数据异常

场景 4 · 在线领取微信/QQ 群激活码

玩家提交群号绑定后,服务器校验并下发激活码。



[@领激活码]
#ACT
HttpPostEx http://api.mygame.com/gift/code account=<$USERNAME>&channel=wechat form @激活返回 S70
BREAK

[@激活返回]
#ACT
JsonGetNodeValue S70 code M50 -1
#IF
Equal M50 0
CheckJsonNodeExists S70 giftCode
#ACT
JsonGetNodeValue S70 giftCode S71 0
#SAY
你的激活码:\
<$STR(S71)>\
(请尽快使用,24 小时内有效)
#ELSEACT
JsonGetNodeValue S70 msg S72 领取失败
SENDMSG 6 <$STR(S72)>

场景 5 · 数据上报(无需处理返回)

关键事件上报到日志服务器,不关心返回内容。

; 玩家首次击杀 BOSS 时上报
[@击杀祖玛教主]
#ACT
HttpPostEx http://log.mygame.com/event {"type":"bosskill","boss":"祖玛教主","role":"<$USERNAME>","lv":<$LEVEL>} json @忽略 S80
; 继续后续逻辑
GAMEGOLD +  100000
SENDMSG 6 祖玛教主已击杀!奖励已发放

[@忽略]
; 不做任何处理
BREAK

场景 6 · 动态活动配置

从后台拉取今日活动开关与倍率,写入全局变量,供经验或掉落脚本读取。

[@活动启动]
#ACT
HttpGetEx http://api.mygame.com/activity/today @活动解析 S90
BREAK

[@活动解析]
#ACT
; 返回 {"double_exp":1,"rate":2,"end":"2026-04-30"}
JsonGetNodeValue S90 double_exp M60 0
JsonGetNodeValue S90 rate       M61 1
JsonGetNodeValue S90 end        S91 -

#IF
Equal M60 1
#ACT
Mov G500 1
Mov G501 <$STR(M61)>
SENDMSG 2 全服经验<$STR(M61)>倍活动开启,截止 <$STR(S91)>
#ELSEACT
Mov G500 0
Mov G501 1

场景 7 · 模拟 Webhook 通知

攻沙成功后,把战报推送到运营群机器人。

[@沙巴克战报]
#ACT
; webhook 常见 JSON 结构
HttpPostEx http://qbot.mygame.com/hook {"text":"<$GUILDNAME> 攻占了沙巴克!"} json @回执 S99
BREAK

[@回执]
SENDMSG 2 战报已推送

场景 8 · 网页后台控制指挥官假人

让一只在线的「指挥官假人」按固定节奏轮询后台:它可以批量拉起其他假人,也可以启动、停止或切换自身挂机脚本。DUMMYSTARTDUMMYSTOP 和挂机配置命令只作用于当前假人,不是全服广播命令。

涉及命令
DUMMYLOGON 假人批量上线 · DUMMYSTART / DUMMYSTOP 开始/停止当前假人挂机 · SETDUMMYCONFIGFILENAME + LOADDUMMYCONFIGFILE 切换当前假人脚本 · CHECKDUMMYCOUNT 查询假人数。

Web 端返回 JSON 示例:

{
  "ts": 202604190830,
  "cmds": [
    {"op":"login", "map":"0",   "x":333, "y":333, "count":20},
    {"op":"start"},
    {"op":"stop"},
    {"op":"cfg",   "file":"zuma.cfg"}
  ]
}

假人脚本:指挥官定时轮询

; ─────────────────────────────────────
; 入口:指挥官假人每 60 秒执行一次
; ─────────────────────────────────────
[@Main]
#IF
; 冷却检测(60 秒一次,防止刷爆后台)
CheckTimer Dummy_Tick 60
#ACT
BREAK
#ELSEACT
GOTO @拉指令

[@拉指令]
#ACT
SetTimer Dummy_Tick
; 带上服务器 ID,便于后台分服下发
HttpGetEx http://api.mygame.com/dummy/cmds?sid=1 @处理指令 S100
BREAK

; ─────────────────────────────────────
; 解析返回:循环取出每条指令并执行
; ─────────────────────────────────────
[@处理指令]
#IF
CheckJsonNodeIsArray S100 cmds
#ACT
JsonGetNodeArrLen S100 cmds M70 0
Mov M71 0
Goto @循环

[@循环]
#IF
Small M71 M70
#ACT
; 拼 cmds[M71].op 路径
Mov S101 cmds[<$STR(M71)>].op
JsonGetNodeValue S100 S101 S102 -

#IF
Equal <$STR(S102)> login
#ACT
GOTO @执行登录
#ELSEACT

#IF
Equal <$STR(S102)> start
#ACT
DUMMYSTART
#ELSEACT

#IF
Equal <$STR(S102)> stop
#ACT
DUMMYSTOP
#ELSEACT

#IF
Equal <$STR(S102)> cfg
#ACT
GOTO @执行换脚本
#ELSEACT

Inc M71 1
GOTO @循环

; ─────────────────────────────────────
; 子操作
; ─────────────────────────────────────
[@执行登录]
#ACT
Mov S110 cmds[<$STR(M71)>].map
Mov S111 cmds[<$STR(M71)>].x
Mov S112 cmds[<$STR(M71)>].y
Mov S113 cmds[<$STR(M71)>].count
JsonGetNodeValue S100 S110 S114 0
JsonGetNodeValue S100 S111 M80  333
JsonGetNodeValue S100 S112 M81  333
JsonGetNodeValue S100 S113 M82  10
; 批量登录假人: 地图 X Y 数量 是否随机
DUMMYLOGON <$STR(S114)> <$STR(M80)> <$STR(M81)> <$STR(M82)> 1
SENDMSG 2 [后台] 已拉起假人 <$STR(M82)> 只
Inc M71 1
GOTO @循环

[@执行换脚本]
#ACT
Mov S110 cmds[<$STR(M71)>].file
JsonGetNodeValue S100 S110 S114 default.cfg
SETDUMMYCONFIGFILENAME <$STR(S114)>
LOADDUMMYCONFIGFILE
SENDMSG 2 [后台] 假人脚本已切换到 <$STR(S114)>
Inc M71 1
GOTO @循环

配套:假人侧定期心跳上报

让假人每 5 分钟把自身状态回报给后台,便于面板显示。

[@DummyHeartbeat]
#IF
IsDummy
#ACT
GOTO @DummyHeartbeatTimer
#ELSEACT
BREAK

[@DummyHeartbeatTimer]
#IF
CheckTimer Dummy_HB 300
#ACT
BREAK
#ELSEACT
SetTimer Dummy_HB
Mov S120 {"name":"<$USERNAME>","map":"<$MAPNAME>","lv":<$LEVEL>,"hp":<$HP>,"online":1}
HttpPostEx http://api.mygame.com/dummy/report <$STR(S120)> json @心跳完毕 S121
BREAK

[@心跳完毕]
BREAK
安全建议
① 后台接口建议加 token 签名校验,避免被伪造请求;
② 单次返回的指令数量建议限制(如 ≤ 20 条);
③ 轮询频率不要太高,建议 ≥ 30 秒。

七、注意事项

异步模型:HTTP 命令下发后脚本立即继续执行,真正的返回处理必须写在同一 NPC 的 @Label 里。
编码:form 类型请使用 k=v&k2=v2 写法,键和值会按 UTF-8 自动 URL 编码,已有的合法 %HH 转义会保留;json/text 正文统一转为 UTF-8。响应是合法 UTF-8 时自动解码,否则按系统 ANSI 编码兼容处理。
POST 正文:正文可以包含空格,命令会从行尾识别 form|json|text @Label VarName;类型只能是这三种之一。也可以先把正文写入字符串变量,再用 <$STR(S变量)> 提交。
大小写:JSON 路径键名严格区分大小写,必须与原始数据完全一致。
错误触发:① JSON 整体解析失败;② JSON 路径格式非法;③ 对非数组节点使用 JsonGetNodeArrLen。节点不存在或数组下标越界不会报错,会写入默认值。
HTTP 结果:网络失败时返回变量会收到错误文本;HTTP 错误状态仍返回服务器正文。单次响应最多读取 15 MB,HTTPS 会正常校验证书。
玩家保护:异步返回时引擎会校验玩家与原 NPC;玩家已下线、角色指针已复用或 NPC 已删除/替换时,不会写入变量也不会跳转。