五个月,一个人,把一款 2003 年的韩国网游客户端重写了一遍

ShiningLore Online 是一款 2003 年上线的韩国 MMORPG(大型多人在线角色扮演游戏),早就停运了,原版客户端的可执行文件里是一万七千多个函数。五个月之后,它在我的手机上跑起来了——一个人写的。这种体量的客户端工程,按正常配置是一个团队的活。
一个人,五个月,182,024 行
2026 年 3 月 11 日,仓库有了第一个提交;8 月 3 日是最近一次。中间跨度 4 个月 23 天,口语上说「五个月」是准的。
这五个月里仓库积累了 1,913 个提交,作者 1 人。提交数本身不说明任何事——加上「作者 1 人」才是一句话:这种体量的客户端,正常配置是一个团队。当前版本号还停在 0.0.3,这事远没到完成。
代码按区域拆开是这样:
| 区域 | 文件数 | 行数 |
|---|---|---|
客户端 client/ |
434 | 89,788 |
基础库 libs/ |
115 | 22,067 |
共享层 shared/ |
58 | 12,999 |
命令行工具 tools/ |
10 | 6,397 |
服务端 server/ |
22 | 3,074 |
测试 tests/ |
188 | 47,699 |
| 合计 | 827 | 182,024 |
不含测试的代码是 134,325 行——这就是「把客户端重写了一遍」的实际重量。server/ 那 3,074 行是另一个故事,后面单独说。
仓库里另有 180 篇 Markdown 文档,合计 102,948 行。文档和代码(不含测试)的比例大约 0.77 : 1——写给 AI 看的文档,行数快赶上代码了。这事这篇只点到为止,怎么写文档是后面的事。
把 145 天的总量摊到每一天,平均值是这样:每天 13.2 个提交,每天 1,255 行代码(含测试),每天 710 行文档。但这只是总量除以天数,不是每天真写了这么多——有的周几乎一行代码没动,整周都在读二进制。报这个平均,只是让人对规模有个感觉,不是描述任何一天的真实节奏。
五个月里走到了哪
最初的几周是另一种节奏。W11 项目启动,构建环境就绪,开始啃资源包格式;W12 资源提取完成,3D 资产格式完整解析;W13 模型查看器、地图查看器、客户端骨架、服务器原型同步推进。这段时间没什么能玩的,全是把原版的数据格式摸清楚、把工具链搭起来。
然后是三个能看见游戏长出来的节点:
- W14:登录流程跑通,角色选择画面完成。这是「能登录」。
- W17:加密通道打通,点一下鼠标角色就在地图上走起来,相机角度也贴齐原版。这是「能进世界」。
- W24:战斗整套跑通。这是「能打架」。
W14 到 W17 之间,还隔着一场逆向马拉松(W15)——一口气修掉了三个搁了很久的严重 bug——和一次渲染架构的大重构(W16),后者让客户端和工具开始共用同一套底层。
从「能登录」到「能打架」,中间隔了十周。这十周里大部分力气没花在写代码上,花在读懂原版到底约定了什么。下面是这十周里的几个画面。
W20 之前,服务端发来的「实体出现」包已经能解开——实体的 ID、坐标都老老实实存进了哈希表,但屏幕一直是空的。数据在,人不在。这一周给每个实体装上一个占位人形(就是先用一个简单的人形替身把实体顶上去,样子还不对,但至少看得见人了),人才真的在地图上站出来。最有意思的不是人站出来了,是这套同步跟原版客户端双向互通:原版那边看得见自研客户端的玩家,自研客户端这边也看得见原版的玩家。两个相隔二十多年的客户端,就这么站在同一张地图上。
W21,别人看你走路终于不抽了,NPC 也有了属于自己的脸。
W22 一周里往前走了三步:进场时朝向站对了,走路会自己绕开挡路的东西,头顶第一次长出了血条。但这一周真正卡人的是另一件事——别人身上的装备。场景里其他玩家一直穿着职业默认的那套衣服,跟他们实际穿的对不上,折腾了一整夜。理清之后发现是两层问题叠在一起:服务端不会主动下发别人的真实装备,得等客户端先发一个「我在这」的位置心跳包,它才肯把那身装备广播回来,而自研客户端一直没发这个包;补上心跳之后又发现,自己额外发的另一个请求包,会把这个广播挤掉。两层都改对,别人身上的头、胸、手、腿、脚、武器六个部位才第一次拼齐。
这事是个好例子:卡住的地方不在代码,在「原版到底约定了什么」——代码怎么写都行,原版当年怎么约定的,只能一点一点从二进制里挖。
W23,地图上第一次有了怪物——会站、会走,鼠标移上去弹出名字和血条。到这儿,世界才算真有了生气。
然后是 W24。前面攒下的一切在这一周汇到一起:打怪、战死、复活、升级,一条线走通——从「能登录」算起的第十周,终于到了「能打架」。同一个周末,顺手把游戏搬上了 Android 和 iOS。
后面的事没那么戏剧化,但正是它们把游戏撑了起来:W25 回头细调还原度,原版 HUD、掉落物、选人信息栏;W26 有了天气——下雨下雪、天会黑,背包能开,手机端能显示中文;W27 NPC 能开口说话,商人能买东西,安卓装上直接玩,窗口模式稳 60 帧;W28 商店和背包能真上手——买卖、拖拽、换装、用道具;W29 任务日志和仓库两扇窗口能打开;W30 底部四扇聊天窗口一口气立起来,新手村的屋子能推门进;W31 整套声音系统并入主线,仓库真的能存能取。
Android 移植从 2026 年 6 月 12 日动手,到 W31 已经打包成一个自包含的手机应用,装上直接玩。最终覆盖 Windows / macOS / Linux / Android / iOS 五个平台。
声音并入主线那天,测试是 174/174 全绿。仓库里除了单元测试,还跑着一批架构守卫脚本——检查分层、检查文件体积上限、检查模块边界。它们不是摆设,挂在构建流程里,违反就过不了构建。一个人做项目,最怕架构在不知不觉里烂掉,这些脚本就是把规矩钉死在构建流程里,替我盯着。

原版。标准分辨率就是 800×600,勉强能撑到 1024×768,再往上就不行了。

复刻版,同一张地图、同一个位置。分辨率能一路开到 4K,画面比例也不再锁死在 4:3——视野宽了一圈,原版里挤在画面边缘、只露出一角的东西,现在能看全。用的还是原版那一套资源,换掉的是渲染它的管线。
还原度做到一定地步,标准就变了
复刻做到后面,开始在原版里找到它自己的 bug。
挑一条最有画面感的:下雨的时候,地上那圈雨点涟漪,原版把它画在了地平面以下——玩家永远看不见。这不是猜的,是拿原版实跑二十多秒、把几千个雨点的数据一个一个记下来对着查,才确认出来的。一个 2003 年就埋在里面的 bug,在我这儿才第一次被看见。
这件事的意义不在于抓原版的错,在于:还原度做到某个程度之后,标准就不再是「看起来对」,而是「跟原版逐帧一致」。 做到这一步,对不对已经不完全由眼睛说了算,得拿原版实跑的数据一行行去对。连原版画错的地方,都得先忠实复刻一遍,再谈要不要修。
为什么一个人能做成
回到开头那个问题:一个人怎么做成这种体量的事?
先看原版有多大:开头说的那一万七千多个函数,装在一个大约 6 MB 的可执行文件里;服务端那边还有 7 个服务进程——网关、游戏世界、角色存档、行会、小游戏、日志、消息。这种体量的二进制,一个人纯靠手挖,根本读不完。
这种工程结构上为什么需要一个团队?因为里面塞了好几个各自成方向的东西:渲染、网络协议、资源格式、UI、音频,每一块单拎出来都够一个人啃一阵。一个人要全接住,瓶颈不在写——写不过来可以靠 AI 提速——在读懂原版把每一块定成了什么样。
而这个项目真正的难点,恰恰不在「写」,在 「读」 ——把 2003 年那批工程师做过的每一个决定(数据怎么排、协议怎么分层、状态机怎么跳)从原版客户端的二进制里挖出来,理解清楚,再用现代 C++ 写一遍。
一段二十年前的反编译结果摆在那里,人得一行一行去猜它在干什么;模型能很快给出一个像样的解释,剩下的事是我去验证它对不对——这正是它在这个项目里最值钱的能力。
这就是为什么一个人能做成结构上需要一个团队的事:重活是读,不是写;而读,正是大模型最强的地方。
服务端那一侧,必须说清楚
标题写的是「客户端」,不是「客户端和服务端都复刻完了」。这两件事差得很远。
事实是:客户端现在连的是原版的服务器。 战斗、刷怪、掉落,目前全部依赖原版服务器在跑。读者不要误以为现在已经有一个能独立运行的私服。
自研服务端只是起步:网关完成度大约 5%,游戏世界服务端刚开张——只独立实现了室内房间的门链,跟官方服务器做到了字节级对齐。服务端集群的逆向分析已经完成,但实现基本没开始,server/ 目录目前就 3,074 行。
这不是失败,是排序——客户端先,服务端后。客户端那一半才是真正吃力的部分,要读二进制、要对还原度;服务端是另一摊,留着后做。但「重写了一款完整的 MMORPG」这种话不能说,那不是事实。
顺手把还没做完的事也列出来,省得读者误会得太乐观:
- 「创建角色」只有窗口界面,还不能真捏人,也创建不了角色。
- 技能窗能开、能把技能拖到快捷环、绑定能存到服务器,但施放还没接。
- 玩家之间的面对面交易没做;好友和行会的真实收发也没做。
- 跨区传送门还没实测。
- 自研服务端还停在起步:网关约 5%,游戏世界服务端刚开张。
- Android 还差内存优化、屏幕刘海避让、触屏体验打磨。
这些不是小尾巴,有几条是核心玩法。把它们摆出来,不是示弱,是想说清楚现在到底做到了哪、没做到哪——一个项目的可信度,往往就差在这些说不说上。
AI 做了什么,我做了什么
AI 在这个项目里干的活:读二十年前的二进制并解释它在干什么;按我写的规范产出实现;大规模重构;写测试;写文档。
我干的活:定规范和架构;判断 AI 给的结论对不对;用实机数据裁决分歧;决定做什么、不做什么。
有一件事必须现在就摆出来,它是整个系列的基调:AI 给出的结论有相当一部分是错的,而且错得还很像真的。 这个项目里最贵的部分,不是让 AI 写代码,是建立一套能持续发现 AI 判断错误的机制。
后面九篇里,有三篇专门讲我和 AI 一起判断错了的事。
实机录像,点封面播放。播放器加载不出来的话,可以直接看 B 站原片。
后面还有九篇。挑几个值得等的:
- 为什么逆向工程这件事特别适合交给 AI。
- 我怎么给 AI 立规矩,让它别每次都重犯同一个错。
- 一个人怎么做代码评审——让三个不同的模型互相拆台。
- 还有三篇「判断错了」的实录。
方法比结果更有意思。能登录、能进世界、能打架、能听见声音——这些都只是起点,真正值得讲的,是怎么一步步走到这儿的。
项目每周的进展记在 sl.tommylau.com,那边是写给玩家看的,只讲游戏里能看见的变化;这个系列写给开发者,讲的是背后怎么做出来的。