热血江湖助手 · 分析资料站← 报告总目录助手主页
分区:15_助手版本迭代说明源文件:角色配置同步_改动说明.md篇幅:17.6 KB收录:2026-10-19 17:10

角色配置 上传/下载 —— 改动说明

日期:2026-10-07 13:15<br>交付:D:/AI空间/rxjh/旧版本更新_修复后_v4.e(2,808,883 字节,md5 18ac3480c2a7b58193e671856b77d6d8)<br>编译源:D:/AI空间/rxjh/旧版本更新.代码

你原来的 旧版本更新_修复后.e(md5 fa40cdab…)一个字节都没动。
_v2.e(只修常量值)和这一版功能重复,可以删;_v3.e 有问题已删除。

一、需求

加一个「角色配置」文件上传下载,只上传下载当前角色的配置文件

二、【重要】v3 为什么把你界面搞坏了 —— 根因与修复

症状

编译 v3 后:你之前摆好的 上传脚本按钮 / 下载脚本按钮 不见了,新加的两个按钮也不在最上层。

根因:文本主本里的界面结构早就和你 .e 不一致了

反编译你的 旧版本更新_修复后.e 做真值对比,发现:

你的 .e旧的文本主本
上传脚本按钮索引 1,顶层控件(不属于任何分组框)索引 379,挂在 分组框2 下
下载脚本按钮索引 2,挂在 补给_分组框_死亡处理 下索引 380,挂在 分组框2 下
分组框2 的 Children不含这两个按钮末尾是 …, 358, 379, 380

易语言的层级规则:控件列表里越靠前 = 越靠上层。<br>旧主本把它们挂在 分组框2 的 Children 最末尾 = 最底层 → 被 超级列表框_喊话列表 盖住;<br>我的 v3 又把两个新按钮也追加在同样位置 → 同样被压在最底。<br>这就是"搞没了"和"不在最顶层"的同一个原因。

我之前的判断失误

上一次"对拍"我比的是 e2t(v2) vs e2t(v3)——两边都源自同一个过期主本,归一化噪声互相抵消,所以什么都没发现。<br>正确的比对对象应该是 e2t(你的 .e)。

修复做法:以你的 .e 为基准重建

  1. 反编译 旧版本更新_修复后.e 取真值(0 错误 / 0 警告)
  2. 用它整体替换文本主本的 窗口/MainDialogWnd.form.json
  3. 把 2 个新按钮插到索引 1、2(顶层控件、无父容器 = 最顶层),其余控件索引整体 +2,所有 Children 引用同步重映射
  4. 重新 t2e / e2t 对拍

对拍结果:你的 381 个控件在新 .e 里"未原样保留的个数 = 0"(名称/类型/坐标/宽高/可见性/禁用/扩展数据/父子关系全部一致)。

三、服务端(wwwroot/yxzh_script.asp)

新增维度参数 kind:

请求含义
?op=list&token=…列坐标脚本(老行为不变)
?op=list&token=…&kind=role&role=<角色名>列该角色的配置
?op=get&token=…&name=<文件名> / &kind=role&role=…下载
?op=put&token=…&name=<文件名> / &kind=role&role=…上传(POST body)

服务器落点(三者隔离):

C:\inetpub\wwwroot\坐标脚本\              ← 坐标脚本(原有)
C:\inetpub\wwwroot\坐标脚本\_bak\
C:\inetpub\wwwroot\角色配置\<角色名>\      ← ★ 新增
C:\inetpub\wwwroot\角色配置\_bak\          ← ★ 新增,留底名:<时间戳>_<角色名>_<原名>

安全护栏(新增 SafeRole())

角色名必须"纯名字":长度 1–20;禁 \ / : ? " < > |;禁 .(.. 穿越直接出局);<br>禁 空格 & % + #(会破坏 URL 查询串);禁 _ 开头(占住 _bak 内部目录)。<br>文件名继续只放行 .ini 且不含路径成分。DoPut 会分级补建目录(FSO 只能建一层)。

四、助手端

4.1 界面:2 个新按钮(在最顶层)

索引控件名标题LeftTop宽高归属
1上传角色配置按钮上传角色配置280447832顶层控件
2下载角色配置按钮下载角色配置361447832顶层控件
3上传脚本按钮上传脚本28087032顶层(你原来的,未动)
4下载脚本按钮下载脚本35987032你的归属关系未动

四个按钮排成 2×2。两个新按钮索引 1、2 = 整窗口最上面两层,不会被任何面板/分组框盖住。

4.2 代码:新增 4 个子程序

代码/窗口程序集_MainDialogWnd.form.e.txt 末尾纯追加(你的 752,720 字节原封不动,新文件 = 你的 + 10,130 字节):

.子程序 _上传角色配置按钮_被单击
.子程序 _下载角色配置按钮_被单击
.子程序 上传角色配置到服务器
.子程序 下载角色配置到本地

「只同步当前角色」怎么保证:全程只用

角色目录 = 角色配置目录 + “\” + 全局_人物名称     ' 当前角色名,读游戏内存得到

上传只枚举它下面的 *.ini,下载只写回同一目录,其余角色目录绝不触碰。<br>没取到角色名(没进游戏 / 没点「加载」)直接中止写日志,不会误写别的角色。

复用:常量 #脚本接口地址 / #脚本接口令牌、全局锁 脚本同步运行中(脚本同步与角色配置互斥)、<br>脚本上传线程 / 脚本下载线程、取同步时间戳()。<br>下载覆盖前的旧配置备份到 角色配置\<角色名>\_同步备份\<时间戳>\。<br>日志前缀 【角色同步】(区别于坐标脚本的 【脚本同步】)。

五、验证结果

项目结果
t2e0 错误 / 0 警告 → _tmp/out45.e
e2t0 错误 / 0 警告
你的控件是否保留未原样保留的个数 = 0(381 个全对)
分组框2 是否还挂脚本按钮否(与你的 .e 一致)
下载脚本按钮 的归属补给_分组框_死亡处理.Children = [4, 5, 86, 87, …](原 [2, 3, 84, 85, …],重映射后一致)
代码文件你的 752,720 字节逐字节相同,之后纯追加 10,130 字节
二进制常量http://139.196.21.118/yxzh_script.asp、yxzhApi2026Rxjh 各 1 次,全角引号 0 次
新子程序4 个全部反编译回读成功
服务端 HTTP坐标脚本 list 回归 21 文件;角色 put→get md5 一致;二次覆盖生成留底;10 条非法用例全拒

六、你需要做的

  1. F7 编译 旧版本更新_修复后_v4.e(t2e 0 错误 ≠ 能编译,这条没变)
  2. 编译后重启助手,确认四个按钮在顶部右侧、2×2 排列,且都在最上层
  3. 进游戏点一次「加载」把角色名读出来,再点新按钮
  4. 第一次给某个角色同步,先点「上传角色配置」(服务器上还没这角色的目录,直接点下载只会提示 ERR no base)

七、备份清单

旧版本更新.代码/窗口/MainDialogWnd.form.json.bak_按钮位置回写前_20261007_124140
旧版本更新.代码/窗口/MainDialogWnd.form.json.bak_加角色配置按钮前_20261007_130340
旧版本更新.代码/窗口/MainDialogWnd.form.json.bak_以你的e为基准重排前_20261007_131312   ← v3 前的旧结构
旧版本更新.代码/代码/窗口程序集_MainDialogWnd.form.e.txt.bak_加角色配置同步前_20261007_130450
旧版本更新.代码/常量.e.txt.bak_常量值修复前_20261007_124140
_tmp/e2t_user_now/          你的 .e 的反编译真值(诊断用,别删)
tools/yxzh_script.asp       服务端源码(GBK 落盘副本 tools/_yxzh_script.gbk.asp)
tools/_deploy_script_api_role.py   部署 + 验证脚本,可重复跑

八、教训(下次别再犯)

  1. 改这个工程前,先 e2t 用户当前 .e 取真值,把文本主本对齐过去,而不是相信主本里的旧结构。

用户会用 IDE 直接改界面,主本随时可能过期。

  1. e2t(v_a) vs e2t(v_b) 这种对拍有盲区——两边同源时噪声抵消,查不出结构性问题。

必须有一条链路是 e2t(用户当前 .e)。

  1. 易语言控件层级:列表里越靠前越在上层。往 Children 末尾追加 = 压到最底 = 看不见。

要让控件在最上层,就插到索引靠前的位置,并且不要挂进会被裁剪的容器。

  1. 窗口/MainDialogWnd.form.json 序列化参数固定为 indent=4 + CRLF + UTF-8 BOM,

否则和 e2txt 原始输出对不上(indent=2 会差 4 万+字节)。

  1. e2txt 目录名 e2txt 1.2 - 易代码文本,横杠两侧都有空格,少一个就 127。

附:两次编译错误修复 + 界面按你 IDE 状态重建(对应 _v6.e)

一、错误(10044) 行数组 = 分割文本 (...)

根因是声明写法,不是代码逻辑。

写法含义
.局部变量 X, 文本型, , "0"(第3字段空、第4字段 "0")真数组 ✅ 工程第 265 行一直是这种,从没报过错
.局部变量 X, 文本型, 数组(只有第3字段)标量 ❌ t2e 不报错但把数组属性丢掉

判据来源:反编译能编译的老工程 Mydll_202303211.e,里面的数组全是 , , "0" 形式。

全工程扫描 1167 处 , 数组 局部变量,真的按数组用的只有 4 行(其余 1163 处是历史冗余标注,变量本就是标量、代码也按标量用,不动):

顺带纠正一个此前的错误结论:e2t 反编译产物不能用来判断数组性(它会无差别给出 , 数组)。所以以前拿 e2t(v4) vs e2t(v5) 对拍根本查不出这个问题。

二、错误(10041) 结果 = 时间_取现行时间戳 (真)

根因:三个易模块都有同名公开子程序,参数个数各不相同,易语言解析到的是 0 参那一版。

模块参数
薏米模块_20232 个(生成10位 / 参数时间,均可空)
精易模块1 个(是否取十位时间戳,可空)
魔鬼作坊VIP模块 V8.00 个 ← 实际解析到这个

解析规则是从既有代码反推出来的:十到十六 在薏米是 2 参、魔鬼作坊是 1 参,而全工程既有 3 处调用全是 1 参 → 魔鬼作坊胜出,和这次报错完全吻合。

修复:改成 结果 = 时间_取现行时间戳 ()。三家参数都可空、默认都返回 13 位毫秒时间戳,不传参对三家都兼容,不赌解析结果。

这条规律以后要记住:本项目里 编码_URL编码、目录_创建、网页_访问、文件_枚举 都是多模块同名。
已核对:编码_URL编码(x, 真, 假)(3参) 与 网页_访问 在本次编译中已通过(报错行号在它们之后);
文件_枚举 当初就是踩到这个坑才换成核心库 寻找文件。

三、界面:按你 IDE 里最新保存的 _v4.e 重建

你 13:16 在 IDE 里把 v4 打开又挪了按钮并保存(文件从 2.8MB 变 7MB),我核对了差异:

上传脚本按钮       (203, 552)   W=70
下载脚本按钮       (282, 552)   W=70
上传角色配置按钮   (189, 600)   W=89
下载角色配置按钮   (281, 600)   W=100

v6 已按这个布局重建,校验结果:_v6.e 反编译出的 form.json 与你的 _v4.e 逐字段完全相同(True,383 个控件)。

你在 IDE 里保存后,常量.e.txt 会从 136 条变成 257 条 —— 多出的 121 条是模块常量被物化进来的
(标准 / 低 / AMF0 / 网页事件_* 等)。这是 IDE 的正常行为,不要把这些回写进文本主本,
否则模块常量会被重复定义。同理 全局变量 / 自定义类型 / 成员 上多出来的 , 数组 也是 e2txt 的渲染噪声。

四、本轮改动清单

代码/窗口程序集_MainDialogWnd.form.e.txt   4 行数组声明改为 , , "0";1 处 时间_取现行时间戳(真)→()
窗口/MainDialogWnd.form.json               整体换成你 _v4.e 反编译出的版本(= 你的最新界面)
旧版本更新_修复后.e         6,993,827 B  md5 fa40cdab…   ← 你的原文件,始终没动
旧版本更新_修复后_v4.e      7,005,673 B  md5 b50b21b4…   ← 你 IDE 保存的,含 10044 错误,别编译
旧版本更新_修复后_v6.e      2,809,205 B  md5 be0863c8…   ← ✅ 编译这个

_v5.e 已删除(含 10041 错误),避免误编译。

新增工具(可复用):

tools/yxzh_script.asp               服务端接口源码(UTF-8,部署时自动转 GBK 落盘)
tools/_deploy_fix_saferole.py       部署 + 全量验证(178 角色 / 往返 / 安全 / 回归)
tools/_audit_resolve.py             扫描多模块同名命令 + 从既有调用反推解析规则
tools/_audit_cmds.py                审计指定命令在各模块的定义与参数
tools/_scan_array_decl.py           扫描"声明是标量但代码按数组用"的变量
tools/_verify_v6.py                 交付前全面校验(界面对拍 / 常量 / 代码 / 二进制串)
tools/_what_user_changed.py         分析用户在 IDE 里改了什么
tools/_read_iislog.py               翻 IIS 访问日志,看客户端实际发出的 URL

五、【2026-10-07 13:55】修复 ERR bad role(服务端,无需重新编译)

症状

【角色同步】开始上传当前角色【江南雨替我说别】的配置到服务器…
【角色同步】上传失败:UserConfig.ini;服务器返回【ERR bad role】
【角色同步】上传失败:组队名单.ini;服务器返回【ERR bad role】
【角色同步】上传失败:购买物品列表.ini;服务器返回【ERR bad role】
【角色同步】上传结束:角色【江南雨替我说别】成功 0 个,失败 3 个

根因:VBScript 的 AscW 返回 16 位有符号整数,中文被误判成控制字符

SafeRole() 里我写了一条防控制字符的判断:

If AscW(ch) < 33 Then Exit Function        ' ← 错的就是这一行

AscW 在 VBScript 里返回的是 16 位有符号整数。码位 ≥ U+8000 的汉字会溢出成负数:

字符码位AscW 实际返回< 33 ?
江U+6C5F27743否 ✓ 通过
南U+535721335否 ✓ 通过
雨U+96E838632 → −26904是 ✗ 被拒
替U+66FF26367否 ✓ 通过
我U+621125105否 ✓ 通过
说U+8BF435828 → −29708是 ✗ 被拒
别U+522B21035否 ✓ 通过

所以「江南雨替我说别」整串被拒 → CurDir() 返回空 → ERR bad role。

约一半的汉字(码位 ≥ U+8000)都会中招 —— 实测 178 个角色里 89 个含这类字。

定位过程(为什么之前 10 条"非法用例"没抓住)

实际上它是被这个 bug 拒绝的 —— 假阳性掩盖了真 bug

  1. 部署诊断页把 SafeRole 逐字符逐条件回放 → 只有 雨 / 说 的 AscW(ch) < 33 为 True
  2. 翻 IIS 访问日志,客户端实际发出的是

role=%BD%AD%C4%CF%D3%EA%CC%E6%CE%D2%CB%B5%B1%F0(= 江南雨替我说别 的 GBK 编码,编码完全正确)

顺带确认:客户端 编码_URL编码 (名, 真, 假) 第 3 参「是否UTF8」= 假 → GBK;
服务端 @CodePage=936 能正确解码 GBK 百分号编码(诊断页实测 ASCW=6C5F 5357 96E8 66FF 6211 8BF4 522B)。
客户端一行都不用改。

修复

' ★ 这里【绝对不能用 AscW(ch) < 33】——
'   VBScript 的 AscW 返回的是 16 位【有符号】整数,码位 >= U+8000 的汉字
'   (雨 U+96E8 / 说 U+8BF4 / 星 U+661F ...)会溢出成负数,被误判成控制字符
If ch < " " Then Exit Function
If ch = Chr(127) Then Exit Function

VBScript 的比较运算符按码位逐字符比较,不受符号影响。SafeName() 也补了同样的两条。

顺手堵掉一个隐患:op=get 失败不再返回文本

客户端是把 op=get 的响应整体当文件内容落盘的。原来失败时返回 ERR no file 文本,<br>万一文件在 list 和 get 之间消失,就会把 ERR no file 写进本地 UserConfig.ini 造成污染。

改为返回 200 + 真空 body,原因放 X-Script-Err 响应头:<br>客户端会走到「下载失败(无数据)」分支,不会污染文件。

⚠️ 踩坑记录:一开始改成 Response.Status = "404" + 空 body,
结果 IIS 用自己的 HTML 错误页替换了 body,客户端会把整段 HTML 写进 .ini,比原来更糟。
必须保持 200,只让 body 为空。

验证结果(tools/_deploy_fix_saferole.py)

[1] 部署 yxzh_script.asp  utf-8 → gbk 7,6xx 字节,无 BOM
[2] 逐个验收 178 个真实角色名            → 被拒 0 个 ✅(其中 89 个含码位>=U+8000 的汉字)
[3] 角色【江南雨替我说别】往返            → 3/3 文件 md5 一致 ✅
[4] 服务器落盘目录名                     → wwwroot\角色配置\江南雨替我说别(中文名正确)✅
[5] 安全性回归(.. / _bak / a/../b / a\b / a:b / a b / 各类非法 name)→ 全部拒绝 ✅
[6] 坐标脚本 op=list 回归                → 21 个文件 ✅
[7] get 失败                             → 200 + body 为空 + X-Script-Err 头 ✅

留底命名实测:20261007_135620_江南雨替我说别_UserConfig.ini。

你接下来

这次是纯服务端修复,DLL 不用重新编译。 直接再点一次「上传角色配置」就行。

(服务器上现在已经有一个 wwwroot\角色配置\江南雨替我说别\ 目录,里面是刚才测试上传的 3 个文件,<br>内容和你本地逐字节相同,可以当第一次同步的正常结果留着。)

本页由 Markdown 报告自动转排;如需原始 md,可在原会话工作区取用。