
简介面向冒险岛 WZ 修改零基础玩家的一份入门图文教程由尐静制作旨在帮助新手建立对 WZ 文件读写与修改的基本认识并走完从工具使用到补丁分享的完整入门流程。内容围绕魔法无敌、闹钟不缩头、蛋蛋无延迟、物品过滤、代码提取、辅助技能全屏化与无延迟、界面美化等常见修改方法展开配合 deMSwz、HR、Winpatch 等工具的操作图示并反复提示修改前备份 WZ 文件、避免与游戏同时运行等注意事项读者可据此独立完成小型修改并自行排查常见问题。包内共 1 个 doc 文件约 890KB以图文步骤排版为主篇幅精简便于对照操作。目前已有 4374 人学习适合刚接触 WZ 修改、希望先完整走通一遍基础流程再深入的学习者。1. 客户端资源包改坏三次之后WZ 修改到底在改什么我改坏第三个 mob.wz 之后才承认WZ 这类资源包不是压缩包而是一棵带类型的树.wz是大容器里面按8500001.img、0400.img这种节点切开节点下再挂 int、string、canvas 属性所谓“修改”其实是改树上某个叶子。这篇拆的是初级 WZ 修改的完整链路——批量刷属性、按节点删动作、做差分补丁工具是 deMSwz、HeRepacker下称 HR、Winpatch再配合 String.wz 反查代码。它适合已经能打开包、但一改就崩或改完没反应的人。所有操作只在自有客户端副本和离线环境里做线上客户端有资源校验别拿正式账号试。2. 先认清 WZ 的树形结构三件工具的分工与运行环境多数人第一次打开 mob.wz 会懵左边一长串数字命名的 img 节点右边一堆叫attack1、die1、info的属性看不出“文件”在哪。原因在于 WZ 不是归档格式是序列化的属性树工具做的事是解析这棵树、让你在树上增删改最后再序列化回去。搞清楚节点模型再动手能少踩掉一半的坑。2.1 img 节点、属性类型与 canvas一个.wz文件顶层通常是一批xxx.img节点编号即对象 id例如8500001.img对应某个 BOSS0400.img是某类物品的一个分卷。img 之下是属性树常见类型有 int4 字节有符号整型、short、string、float/double、vector坐标对、uol对另一节点的引用、sub子节点容器和 canvas内嵌一张 PNG附带 origin 坐标。类型决定你能怎么改。int 属性可以塞进一个大数编辑器按二进制写回string 属性你写一串数字进去客户端读的时候仍按字符串处理表现就是“改了但没反应”。canvas 属性没有“部分修改”这回事只能整张导出、改完、整张回填。我见过有人想调一个图标的不透明度直接在属性面板里找 alpha找了半天——那东西根本不在属性里在 PNG 像素里。还有一点容易忽略同名属性在不同 img 下可能类型不同。同样是攻击间隔类的键在某些怪上是 int在另一些怪上是 short。short 只有 2 字节写 2147483647 会直接截断表现是数值变成完全不相干的另一个数。所以批量改之前先抽三五个节点看看类型是否一致。2.2 三件工具各管一段活它们不是互相替代的关系硬要拿一个干全部的活结果一般是包被写坏。工具擅长不擅长依赖deMSwz打开大包、按属性名批量刷值、导出文本清单编辑图像、精细删节点独占文件客户端不能同时运行HeRepackerHR树形浏览、删节点、PNG 导出与回填、跨版本读包大批量按名刷值需要 .NET Framework 3.5Winpatch两个目录做差分、生成补丁包不理解 WZ 语义只认文件字节无特殊依赖deMSwz 的核心能力是“自定义值 Process All”你给一个键名和一个值它对包内所有同名节点统一写入。改 mob.wz 这种每个怪物 img 下都可能有同名键的包这是唯一现实的做法手点几千个节点不现实。HR 的核心能力是树操作删动作、删图标、导出 PNG 都靠它它的“读取模式”还决定了解析规则选错就是一堆乱码。Winpatch 完全不关心 WZ 是什么它只比较两个目录的文件差异所以它既能做出干净的补丁也能一步把你客户的整个目录清空——后面单独说。2.3 运行环境与备份纪律HR 依赖 .NET Framework 3.5这个运行时在较新的系统上默认不装属于“按需启用”的可选功能。直接双击报缺少运行时的用管理员权限开命令行启用# 以管理员身份运行启用 .NET Framework 3.5 可选功能 # /Online 表示从系统源获取/All 表示包含父功能 DISM /Online /Enable-Feature /FeatureName:NetFx3 /All # 启用后确认状态State 应为 Enabled DISM /Online /Get-FeatureInfo /FeatureName:NetFx3这里两个参数值得说/FeatureName:NetFx3是 3.5 的功能名别写成 NetFx4/All会把依赖的父功能一起带上漏了它有时会报 0x800f0906 之类的错误。启用完不需要重启但正在运行的客户端要关掉。备份纪律比工具重要。我自己的目录长这样mob.wz.orig是原始包mob.wz.wip是当前改到一半的工作副本mob.wz才是工具实际读写的文件。每完成一个独立改动比如只改了攻击间隔就把 wip 另存一份带时间戳的再继续下一步。这样任何一步翻车都能退回上一个可用状态而不是从原始包重来。# 改包前固定跑一遍的备份脚本 set -e SRC$1 # 传入要改的 wz 文件路径 TS$(date %Y%m%d_%H%M%S) cp -n $SRC $SRC.orig # -n 保证原始备份只写一次不会被后续覆盖 cp $SRC $SRC.$TS.wip # 每轮改动前留一个带时间戳的工作副本 ls -lh $SRC* # 确认备份落盘大小与源文件一致cp -n这个参数是关键原始备份只允许写一次避免手滑把已经改坏的包当成“原始包”再备份一遍那就彻底没有后悔药了。最后那行ls -lh不是多余动作——WZ 包动辄几十上百 MB磁盘满导致的半截文件在工具里打开时会报各种莫名其妙的解析错误先看一眼大小能省掉半小时排查。3. 批量属性注入用自定义键值把 mob.wz 的改动一次刷完mob.wz 是怪物数据包节点多、单节点属性杂适合用 deMSwz 的批量写入能力一次性处理。拿“攻击后的行为间隔”这类键举例它在大量怪物 img 下都存在逐个点开改不现实而批量写入只需要给键名和值剩下的交给工具遍历。3.1 批量写入靠的是“按名匹配”不是“按路径匹配”deMSwz 左下角有一个自定义值区域前面是键名输入框后面是数值输入框旁边一个勾选框再加一个 Process All 按钮。它的行为是遍历当前打开包内的所有节点凡是属性名与输入键名完全一致的把值写成你给的那个数。注意是完全一致——大小写敏感多一个空格都不算命中。这就带来两个前提。第一这个键在包里必须已经存在批量写入是覆盖不是新增键名写错的结果是零命中而工具不会报错进度条照样跑完。第二同名键的类型要一致前面说过 short 和 int 混用会截断。稳妥的做法是先在树上手动翻两三个节点确认键名拼写和类型再开批量。提示改之前先把客户端进程完全退出。deMSwz 打开包时会独占文件客户端在跑的情况下要么打开失败要么保存时写不进去最坏的情况是客户端正好在读这个文件两边一起把包写花。3.2 判断“包已经完整读入”的两个信号mob.wz 体积大打开要等。判断是否读完看的不是界面能不能点而是主窗口下方那行reading WZ的进度提示它消失并且没有弹出任何错误对话框才算完整载入。这两个条件缺一不可——有时候进度提示消失了但弹了一个解析警告你点了忽略继续操作后面保存出来的包在某个节点上是坏的而且坏的位置跟你改的地方可能毫无关系。载入过程中不要点任何按钮也不要切换窗口去干别的然后回来狂点。我遇到过在进度条没走完时点了下树节点工具直接卡死强杀进程后原包被占用锁住得重启资源管理器才能删。打不开的常见原因就三类文件被客户端或其他编辑器占用包的版本比工具新节点类型表里没有对应项文件本身已经是半截损坏状态就是上一节说的磁盘满或强杀进程留下的。第三类没法救只能从.orig备份恢复。3.3 Process All 到 Save to 的完整操作序列按这个顺序走中间不要跳步打开 deMSwz载入mob.wz等到reading WZ消失且无报错。把界面上所有默认勾选项全部取消。这一步最容易被跳过——默认勾选代表“处理全部属性”你只想改一个键它会把整棵树上能处理的属性都翻一遍慢而且会顺带重写一批你没打算动的节点。在自定义值的前框输入键名例如attackAfter严格保持大小写后框输入数值2147483647。勾上自定义值旁边的勾选框让工具只处理这一条。点Process All等进度条走完。进度条时长与包体积成正比中途不要点取消——取消后已经写入的部分不会回滚。点Save to..在弹出的保存对话框里选择覆盖原mob.wz。第 6 步的保存对话框里有一个容易看错的勾选项作用是“保存前备份原文件”之类。我一开始勾了它结果目录里多出一份旧包后续用 HR 读包时选错文件读了半天发现改动没生效。这个勾按需处理如果你已经在外面做了.orig备份这里就别再生成一份避免文件名混淆。保存完成后的第一件事不是开客户端验证而是重新用编辑器打开刚保存的包随便找几个目标节点看键值是不是真的变成了你写的数。批量写入零命中的情况界面上完全看不出来只有回读才能确认。这一步用脚本更快# 把 deMSwz 导出的属性文本清单做一次命中校验 # 清单格式假设为每行 路径|属性名|值导出时按这个格式整理 import sys, collections path, key, expect sys.argv[1], sys.argv[2], sys.argv[3] hits collections.Counter() with open(path, encodingutf-8, errorsignore) as f: for line in f: parts line.rstrip(\n).split(|) if len(parts) ! 3: continue node, name, value parts if name key: # 大小写严格相等不做 lower() hits[value] 1 total sum(hits.values()) print(f命中 {total} 处取值分布{dict(hits)}) if hits.get(expect, 0) ! total: # 有任何一个没写成目标值就判失败 print(存在未写入目标值的节点检查类型是否被截断) sys.exit(1)这段脚本只做一件事从导出的清单里按属性名精确匹配统计取值的分布。sys.exit(1)那行是给自己留的门禁——只要有节点的值不等于目标值说明该节点的属性类型不是 int比如 short 被截断需要单独处理。用Counter而不是简单计数是因为取值分布能直接告诉你“是全部没改成功”还是“改成功了但有几个被截断”这两种情况的排查方向完全不同。3.4 2147483647 这个数为什么不能随便加2147483647 是 32 位有符号整型的上限也就是 2³¹−1。客户端读这类属性时按有符号 int 解析超过这个数会绕回负数。写 2147483648 的结果是客户端读到一个很大的负数行为可能反向——本来是“无延迟”变成“卡到超时”。也有些字段客户端不直接当数值用而是做掩码或除法。这类字段写满值会触发完全不同的分支表现是游戏内表现异常但程序不崩。遇到这种情况把值退到百万级比如 1000000再试通常就够了。判定方法很简单同一个键分别写 2147483647 和 1000000看客户端表现是否一致。一致说明字段是纯数值比较不一致说明有位运算参与。注意不要图省事把值写成 -1。-1 在二进制上是全 1很多语言里确实代表“最大值”但客户端如果对这个字段做了 0的判断-1 会被直接跳过等于没改。4. 节点级删改闹钟缩头、起身动作与物品图标的三类删法批量写入解决“值”的问题删节点解决“行为”的问题。删对了是流程简化删错了是动画直接崩或者物品无法操作。这一章的四类操作用的都是 HR前提是先把读取模式选对。4.1 读取模式选错后面全是无用功HR 读包前要先选模式模式决定了节点命名规则和部分属性类型的解析方式。不同来源的客户端包节点命名和结构不完全一样选错模式的表现是包能打开节点树也能展开但导出的 PNG 花屏、部分属性显示成乱码、按名字搜索搜不到。判定方法不复杂打开包后先抽查一个你确认存在的节点比如某个 BOSS 的 img 是否在预期位置再随便展开一个 canvas 属性点一下预览。预览正常出图说明模式对了。出图是全黑或者花屏别急着怀疑包坏了先换模式重开。打开路径是File → Load选中目标包。加载完成后不要立刻改先在树上找到你要动的节点把完整路径记下来比如mob.wz → 8500001.img → attack1改的时候按路径走不按界面上的显示顺序走。4.2 删动作节点缩头动作和起身动作以某个 BOSS 的缩头行为为例路径是mob.wz → 8500001.img → attack1。展开attack1后能看到一串子节点这些子节点对应技能释放过程中的各个动作帧序列。要走“不缩头”的效果思路是把缩头开始之后的那些动作节点整体删掉让动作序列在缩头前就结束。关键点在这里子节点在界面上的排列顺序和节点名字里的数字大小不是一回事。你看到列表里第 21 项它的实际名字可能是24第 22 项可能是21。如果按“从第 21 行开始往下全选删除”操作删掉的是错位的节点结果是动作序列中间断了一截客户端表现是怪物卡在某个动作上不动或者直接不刷新。正确做法是逐个点开子节点看右侧属性面板里显示的真实节点名确认名字落在目标区间之后再删。删除操作是选中节点后Property → remove Property快捷键CtrlR。删完先File → Save另存成一个新文件名不要直接覆盖回游戏里验证过再决定要不要替换。起身动作的改法思路相同但更干脆找到对应怪物 img 下的die1节点整项删掉。die1对应的是死亡后逐帧站起的那段动画删掉后死亡状态直接跳到下一阶段。这里没有区间问题只有一个节点风险低得多适合拿来练手熟悉 HR 的删节点手感。4.3 物品图标过滤删 iconRaw不删整项物品相关的包是Item.wz。过滤某件物品的思路是让它不出现在正常的展示流程里做法是删掉它的图标资源节点。路径是Item.wz → 0400.img → 04000000 → iconRaw。0400.img是分卷04000000是具体物品的 id 节点iconRaw是这个物品的原始图标canvas 类型。删掉iconRaw客户端拿不到图标数据渲染为空。这里有个边界必须说清楚删iconRaw影响的是展示不是数据。物品本身的属性节点info、spec之类还在所以背包里原有的该物品仍然可以出售、可以存仓但所有依赖图标渲染的交互会失效——拖拽、丢弃、交换这类操作会失败因为客户端在拖拽时要画一个跟随鼠标的图标。想恢复就把iconRaw加回去别去动info。提示删之前把iconRaw用 HR 的导出功能存一份 PNG 到本地。后面想还原的时候新建一个同名 canvas 节点把这个 PNG 回填进去就行比从备份包里翻快得多。4.4 用 String.wz 反查代码前面所有操作都要先知道“代码”——怪物 id、物品 id、技能 id。这些 id 不是猜出来的String.wz就是那张对照表它按版本同步记录了 id 与名称的映射。做法是用 deMSwz 打开String.wz在树里按名称找目标双击对应项右侧会显示 id右键全选复制到记事本存档。我习惯按类别整理成几个文本文件比如怪物 id 一张表、物品 id 一张表后面改包时直接查表不用每次重开 String.wz——这个包也不小反复开关很浪费时间。包文件主要用途常改的节点mob.wz怪物数据与动作序列attack1 下的动作子节点、die1Item.wz物品定义与图标iconRawskill.wz技能等级数据各等级节点的数值与范围String.wzid 与名称对照只读用于反查Ui.wz界面图片资源canvas 节点下的 PNG4.5 技能节点职业码加序号还要看符号位技能相关的包是skill.wz节点 id 由两部分拼成职业代码 4 位技能序号。冒险家系职业代码是 3 位扩展职业是 4 位。战士线 100、法师线 200、弓手线 300、飞侠线 400、海盗线 500转职后在百位后追加序号比如 110 是战士一转分支、120 是另一分支、130 是第三分支再往后 111、121、131 是三转112、122、132 是四转。改范围类效果比如让某个技能的作用范围覆盖屏幕时要动的是技能等级节点下的范围属性通常是左上和右下两个坐标对。这两个值的符号是相反的一个改成正的大数另一个要改成负的大数才能把范围从一个点向两侧撑开。只改一边的结果是范围偏向一侧看起来像“半屏”。还有一个必须接受的现实技能是按 id 独立存储的改了 1121000 只影响那一个技能不会“全职业生效”。同一个效果在不同职业线上是不同 id得一个一个来。这也是为什么这类补丁很少有人做全量——工作量按职业数乘技能数增长。4.6 Ui.wzPNG 导出、修改、回填界面类资源全在Ui.wz本质上就是一堆 canvas 节点套着 PNG。改法三步选中 canvas 节点点导出按钮存成 PNG用图像工具改改颜色、调透明度都行不建议动整体尺寸保存时必须存成 PNG 格式文件名保持原样然后回填覆盖原节点最后保存包。透明度这类效果往往不止一个文件。比如底部状态栏的透明化除了主背景图还要处理状态栏背景那一张路径大致在StatusBar/base/backgrnd.png这一层只改一张会出现“背景透了但边条还是实心”的割裂感。改之前先把相关路径下的 canvas 全部导出一遍看看哪些是同一块区域的组成部分一次改完再回填。5. 五条踩坑记录从目录被删光到属性大小写翻车这些坑有一个共同点操作时界面都显示“成功”问题要到验证阶段才暴露。按现象、原因、解决三步记下来比记操作步骤有用。5.1 补丁装完客户目录里其他文件全没了现象生成的补丁在自己机器上测试正常发出去之后对方反馈“装完补丁整个客户端只剩补丁里那几个文件”。原因差分工具的逻辑是比对两个目录把“只在旧目录存在”的文件判定为需要删除。制作补丁时如果新旧目录里混进了无关文件或者排除规则没做全这些“只在一边存在”的文件就会被写进删除列表。更隐蔽的情况是新旧目录的层级不一致工具按相对路径比对路径对不上就当成“旧文件已不存在”。解决制作补丁前把要发布的文件单独复制到两个干净目录里一个旧版一个新版目录层级严格一致除此之外一个文件都不放。然后在工具里对每个文件路径逐个确认排除状态构造之前再核对一遍文件清单数量。这条我现在的习惯是补丁目录里的文件数必须等于改动文件数多一个都不构造。5.2 Process All 跑完了进游戏一点变化没有现象批量写入进度条正常走完保存也成功回读发现值没变或者只有一部分节点变了。原因两种情况。一是键名大小写或拼写不匹配工具按名精确匹配attackAfter写成AttackAfter就是零命中但界面不会提示。二是该节点的属性类型不是 int写进去的值被截断或拒绝。解决先用 3.2 节的脚本做一次命中统计看取值分布。全部未命中就是键名问题回树上抄一遍原始拼写部分未命中就是类型问题抽那几个节点单独看类型改用 HR 手工改。5.3 保存时报错或者保存出来的包打不开现象点保存后工具报写入失败或者保存成功但下次打开提示解析错误。原因客户端进程还在跑文件被占用或者保存过程中磁盘空间不足写了一半或者上一次异常退出留下了文件锁。解决改包全程关闭客户端。保存前看一眼目标分区剩余空间WZ 包保存时需要临时空间剩余空间小于包体积两倍就容易出问题。已经写坏的包不要试图修复直接从.orig恢复这也是为什么备份要用cp -n只写一次。5.4 改完数值游戏里的表现和预期完全相反现象想做出“无间隔”的效果结果变成了超长等待或者直接卡住。原因写入的值超过了字段类型的上限被截断成负数或者该字段在客户端里参与位运算满值触发了另一个分支。解决先确认字段类型是 int 还是 shortshort 上限只有 32767。确认是 int 之后把值退到百万级再测一次两次表现一致说明是纯数值比较不一致就换成保守值。5.5 按界面顺序删节点动画直接崩现象删完动作节点怪物在某个动作上定住不动或者整个技能放不出来。原因子节点在界面上的排列顺序不等于节点名的数字顺序。按行号区间删删掉的是错位的节点动作序列中间被挖空。解决删之前逐个点开子节点按属性面板显示的真实节点名确认范围删完先用另存的文件在离线环境验证一遍动作是否完整再覆盖正式包。这条没有捷径只能慢。6. 差分补丁制作与验证让改动只落在一个文件上回到 Winpatch。它不理解 WZ 语义只做字节级目录比对所以能不能做出干净的补丁全看你喂给它的目录有多干净。流程是开专家模式分别指定旧文件目录和新文件目录然后逐个文件确认排除状态——要发布的保留不发布的全部排除。每个文件路径下面都有排除按钮点一下加入排除列表旧目录和新目录两边都要做不能只做一边。补丁说明文本可以自己写构造前顺手填上改了什么方便对方核对。点构造补丁等生成完成。体积和正确性要一起看。一个只改了 mob.wz 里几十个字节的补丁体积应该接近压缩后该文件的增量如果生成出来比整个包还大说明差分粒度没对上多半是新旧目录里混进了未排除的大文件。反过来补丁只有几百字节也要警惕可能改动根本没被包含进去。验证我固定走三步。先比哈希把打完补丁的目录和手工改好的新目录各算一次逐个文件比对。# 对比两个目录下同名文件的哈希只输出不一致的项 # -r 递归-q 只输出差异缺文件也会列出 diff -rq old_dir new_dir # 对关键文件单独做哈希比对确认补丁落点正确 sha256sum new_dir/mob.wz patched_dir/mob.wzdiff -rq会把“只在一边存在”和“内容不同”都列出来前者往往就是 5.1 节那个坑的源头看到就说明目录没清干净。sha256sum那行用来确认补丁打完后的文件与手工改好的文件完全一致哈希对不上但功能正常的情况也存在比如补丁工具做了对齐填充这时候以功能验证为准。第二步在离线环境实际加载一次重点看改动点附近的行为别只看你改的那一处——删节点类操作容易连带影响相邻动作。第三步留退路补丁包里附一份反向补丁或者原始文件备份让对方能在装错时退回去。从那以后我每次构造补丁都强制走一遍“目录清点—哈希比对—离线加载”三道全过才发出去宁可多花十分钟也不愿意再收到一句“装完就没了”。希望帮到你。本文还有配套的精品资源点击获取