一句话告诉 AI “把《仙逆》做成魔兽 RPG 地图”,它真的给我导出了一个 .w3x 文件。
我的朋友,80、90 后的你,凌晨两点的网吧,还记得吗?
2006年,网吧包夜5块钱。
你坐在一台积满烟灰的CRT显示器前,屏幕上是魔兽争霸3的世界编辑器。你小心翼翼地放下一个步兵,设置一个触发器——“当单位死亡时,显示文字:你输了”。那是你第一次体会到“创造世界”的快感。

那个年代,DOTA还叫“远古遗迹保卫战”,RPG地图才是魔兽争霸的灵魂。《守卫剑阁》、《仙之侠道》、《真三国无双》……每一张RPG地图背后,都是某个少年在世界编辑器里熬了无数个通宵。

20年后的今天,那些少年已经秃了头、还了房贷、送娃上了补习班。但有些东西,刻在DNA里,删不掉。
如果我告诉你,现在只需要对 AI 说一句话,就能生成一张可以在魔兽争霸3里玩的 RPG 地图,你信吗?

一个疯狂的想法开始了
事情的起因很简单。某天晚上我重温《仙逆》,看到王林从一个山村废柴少年一步步逆天改命,我脑子里突然蹦出一个想法:
这剧情,天然就是一个RPG地图啊!
山村起步 → 拜入宗门 → 野外刷怪 → 最终Boss对决,这不就是《守卫剑阁》的结构吗?
但问题来了——我已经不是20年前那个能在世界编辑器里泡一整夜的少年了。光是回忆那些 rawcode(hfoo 是步兵、Hpal 是圣骑士……)就够我头疼的。
于是我决定让 AI 来做这件事。 既然我们已经有了具备 MCP 能力的智能体,还能让它写图文文章,那为什么不能用它来做魔兽争霸 RPG 地图呢?搜索一番,发现没有现成的 MCP 服务器能实现这个功能,那不好意思,我就开始造这个轮子了。
我们不是让 AI “生成一段描述”或者“画一张概念图”这种隔靴搔痒的事,而是——让 AI 直接输出一个 .w3x 文件,可以丢进魔兽争霸3里直接玩的那种。
技术方案拆解:MCP + wc3maptranslator + MPQ
先说结论,整个架构长这样:
你说一句话 → Claude → MCP Tools → wc3maptranslator → .w3x 地图文件
项目结构是这个样子的:

第一层:MCP —— 让 AI 拥有“操作世界编辑器”的能力
MCP(Model Context Protocol)是 Anthropic 提出的开放协议,一句话解释:给 AI 装外挂。
传统的 AI 对话只能输出文字。但通过 MCP,你可以给 AI 注册一组“工具”,AI 在对话中可以主动调用这些工具来完成实际操作。
我给 AI 注册了 12 个工具,模拟了世界编辑器的核心功能:
| 工具 |
做什么 |
对应世界编辑器的... |
create_map |
创建地图 |
文件 → 新建地图 |
place_unit |
放单位 |
在地图上拖放一个单位 |
place_doodad |
放装饰物 |
放一棵树、一块石头 |
set_terrain |
刷地形 |
用地形笔刷涂地面 |
add_trigger |
加触发器 |
触发器编辑器 |
add_quest |
加任务 |
F9 任务日志 |
add_dialogue |
加对话 |
电影模式对话 |
set_player_config |
设玩家 |
玩家属性设置 |
export_map |
导出地图 |
文件 → 另存为 .w3x |
用 Python FastMCP 实现,核心代码非常简洁:
from fastmcp import FastMCP
mcp = FastMCP("wc3-map-builder")
@mcp.tool()
def create_map(name: str, terrain_type: str = "Lordaeron_Summer",
size: str = "medium", description: str = "") -> dict:
"""Initialize a new map, resetting all previous state."""
w, h = SIZE_PRESETS[size]
_state.reset(name, terrain_type, w, h)
return {"status": "ok", "message": f"Map '{name}' created ({w}x{h})"}
@mcp.tool()
def place_unit(unit_id: str, x: float, y: float,
player: int = 0, name: str = "", hero_level: int = 0) -> dict:
"""Place a unit on the map at world coordinates."""
unit = UnitPlacement(type=unit_id, position=[x, y, 0], player=player,
name=name, hero_level=hero_level)
_state.add_unit(unit)
return {"status": "ok", "message": f"Placed {unit_id} at ({x}, {y})"}
AI 看到这些工具的描述后,就知道怎么“操作”了。你只需要说“放一个圣骑士在地图中央”,AI 会自动调用 place_unit(unit_id="Hpal", x=0, y=0, hero_level=1)。
第二层:状态管理 —— 一份 Pydantic 模型就是一张地图
所有工具操作的都是同一个内存中的 MapState 对象。这个对象用 Pydantic 模型定义,结构非常清晰:
class MapState:
info: MapInfo # 地图名、尺寸、地形类型
units: list[Unit] # 所有单位
doodads: list[Doodad] # 所有装饰物
triggers: list[Trigger] # 所有触发器
quests: list[Quest] # 任务
dialogues: list[Dlg] # 对话
players: list[Player] # 玩家配置
AI 每次调用工具,就是在往这个对象里加东西。就像你在世界编辑器里一步步搭建地图一样。
第三层:导出管线 —— 从 JSON 到 .w3x 的全自动流水线
这是最硬核的部分。.w3x 文件本质上是一个 MPQ 压缩包,里面装着一堆二进制文件:
.w3x (MPQ Archive)
├── war3map.w3e ← 地形数据(每个格子的地面类型、高度)
├── war3mapUnits.doo ← 预放置单位(坐标、类型、玩家归属)
├── war3map.doo ← 装饰物
├── war3map.w3i ← 地图信息(名称、玩家、队伍)
├── war3map.j ← JASS 脚本(触发器逻辑)
└── war3map.wts ← 字符串表
导出流程分三步走:
Step 1:MapState → JSON
把 Pydantic 模型转成 wc3maptranslator 能读的 JSON 格式。这一步纯 Python。
Step 2:JSON → 二进制文件
用 Node.js 的 wc3maptranslator 库把 JSON 转成 WC3 能识别的二进制格式。这个库是社区大佬的杰作,它知道 war3map.w3e 的每一个字节该怎么排列。
Step 3:二进制文件 → MPQ → .w3x
最后,我用纯 Python 实现了一个 MPQ v1 打包器。没有用任何 C 扩展,纯手搓:
MPQ_MAGIC = b"MPQ\x1a"
HM3W_MAGIC = b"HM3W"
def build_w3x(files: dict[str, bytes], output_path: str) -> Path:
# 1. 写 512 字节 HM3W 头
# 2. 写 MPQ 头(magic + 偏移量表)
# 3. 写文件数据
# 4. 写哈希表(文件名 → 块索引)
# 5. 写块表(偏移 + 大小 + 标志)
...
MPQ 格式是暴雪在1996年发明的压缩包格式,用了一套独特的哈希算法来做文件索引。为了让 WC3 能正确读取,我得精确实现它的 Hash Table 和 Block Table 结构——包括那个经典的 seed = (seed * 125 + 3) % 0x2AAAAB 哈希种子算法。
第四层:JASS 代码生成 —— 触发器的灵魂
RPG 地图没有触发器就是一具空壳。当 AI 调用 add_trigger 时,系统会在导出时自动生成 JASS 脚本:
function Trig_MapInit_Opening_Actions takes nothing returns nothing
call DisplayTimedTextToForce(GetPlayersAll(), 10.00,
"赵国,一个偏远的小山村。少年王林资质平庸,却心怀修仙之梦...")
endfunction
function Trig_BossKill_TengHuaYuan_Conditions takes nothing returns boolean
if not (GetUnitName(GetDyingUnit()) == "藤化远") then
return false
endif
return true
endfunction
对话系统也是自动生成的,用 |cffffcc00 颜色代码高亮角色名:
function PlayDialogue_Final_Battle takes nothing returns nothing
call DisplayTimedTextToForce(GetPlayersAll(), 3.00,
"|cffffcc00藤化远:|r 王林!交出天运珠,饶你不死!")
call TriggerSleepAction(3.00)
call DisplayTimedTextToForce(GetPlayersAll(), 4.00,
"|cffffcc00王林:|r 我命由我不由天。要珠子?先问过我手中的剑!")
...
endfunction
实战:一句话生成《仙逆》RPG 地图
说了这么多技术,来看实际效果。
我对 AI 说:
“基于仙逆小说的剧情,创建一个魔兽争霸 RPG 地图”

AI 的操作序列:
1. create_map(“仙逆-王林修仙录”, terrain=“Ashenvale”, size=“large”)
2. set_player_config × 4 → 王林(玩家) / 恒岳派(友方AI) / 邪修(敌方) / 天运宗(Boss)
3. place_unit × 18 → 英雄、NPC、小怪、Boss 全部到位
4. set_terrain × 3 → 山村(泥土) / 宗门(石砖) / 禁地(高台)
5. place_doodad × 7 → 树木、岩石点缀场景
6. add_trigger × 2 → 开场剧情 + Boss 击杀判定
7. add_quest × 3 → 三章主线任务
8. add_dialogue × 3 → 告别 / 收徒 / 最终对决
9. export_map → 输出 仙逆-王林修仙录.w3x (11KB)
整个过程不到 30 秒。
最终产出的地图包含:
- 第一章:拜入恒岳派 —— 王林告别父亲,从赵国山村出发
- 第二章:天运珠之秘 —— 击败邪修妖兽,获取天运珠碎片
- 第三章:逆天对决 —— 闯入天运宗禁地,击杀 Boss 藤化远
对话都是小说味儿的:
王林之父:林儿,你真的要去修仙吗?那可是九死一生的路啊...
王林:父亲,孩儿心意已决。总有一天,我会让王家扬名天下!
藤化远:王林!交出天运珠,饶你不死!
王林:我命由我不由天。要珠子?先问过我手中的剑!

为什么是 MCP 而不是直接让 AI 生成代码?
你可能会问:为什么不直接让 AI 生成一个完整的 .j 文件或者地图数据?
因为 MCP 的工具调用模式天然适合“渐进式构建”。
想想你在世界编辑器里做图的过程:你不会先在脑子里规划好每个单位的精确坐标,然后一次性写完。你是边做边调的——先放几个单位看看位置对不对,再加个触发器测试一下逻辑。
MCP 工具就是给 AI 提供了同样的“边做边调”的能力。AI 可以先 create_map,然后 place_unit 放几个单位,随时 get_map_status 看看当前状态,觉得不对还能继续调整。
更重要的是,工具的粒度决定了 AI 的可靠性。让 AI 一次性输出一个完整的二进制文件格式?那基本是天方夜谭。但让 AI 调用 place_unit(unit_id=“Hpal”, x=100, y=200) 这样的工具?那它几乎不会出错。
更多玩法与拓展
这套架构不限于小说改编。你可以:
- “做一张 2v2 对战地图,双方各有一个主基地和三条兵线” → AI 自动布局
- “参考守卫剑阁的玩法,做一个三国题材的防守图” → AI 理解游戏机制后设计关卡
- “把我的 DND 跑团剧本转成 WC3 地图” → 任务、对话、触发器全自动
甚至可以做得更极致:把地图编辑器本身部署成一个远程服务(MCP 支持 HTTP 模式),让完全不懂技术的人通过 AI 对话来做地图。
# 一行命令启动远程服务
python -m src.server --http --port 8000
# 或者 Docker 一键部署
docker run -p 8000:8000 wc3-mcp
这个项目本身就是一个有趣的 开源实战案例,将传统游戏地图制作与现代 AI 能力桥接了起来。
写在最后:从网吧少年到代码造梦
这个项目的技术含量其实不高。Python + Node.js + 一点点对 MPQ 格式的逆向理解,总共也就几百行代码。
但它击中了我内心某个柔软的地方。
20年前,我们在网吧里用世界编辑器造梦。那是一个没有 AI、没有 GitHub Copilot、连 Stack Overflow 都还没上线的年代。你想做一个 RPG 地图,唯一的办法就是翻遍论坛帖子、啃晦涩的 JASS 文档、然后一行一行地写触发器。
现在,你只需要告诉 AI 一个故事,它就能帮你把梦造出来。
技术在进步,但造梦的冲动从未改变。那个凌晨两点还在网吧里调触发器的少年,他只是换了一种方式,继续在创造世界。在这个 云栈社区 里,以及更多类似的开发者聚集地,这种创造精神仍在延续。
项目地址:https://github.com/coder-brzhang/war3-mapedit-mcp
如果你也是那个网吧少年,欢迎 Star。