找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

3659

积分

0

好友

475

主题
发表于 昨天 08:02 | 查看: 5| 回复: 0

一句话告诉 AI “把《仙逆》做成魔兽 RPG 地图”,它真的给我导出了一个 .w3x 文件。

我的朋友,80、90 后的你,凌晨两点的网吧,还记得吗?

2006年,网吧包夜5块钱。

你坐在一台积满烟灰的CRT显示器前,屏幕上是魔兽争霸3的世界编辑器。你小心翼翼地放下一个步兵,设置一个触发器——“当单位死亡时,显示文字:你输了”。那是你第一次体会到“创造世界”的快感。

《魔兽争霸III》游戏界面截图

那个年代,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 地图”

地图创建成功的JSON日志

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。




上一篇:Claude Code 三阶段工作法:如何借助AI高效完成编码任务
下一篇:三种PEFT方法对比:LoRA、QLoRA与DoRA的原理与如何选择
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-2-25 10:45 , Processed in 0.573579 second(s), 42 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表