VC++6.0传奇2.0源码拆解:MMORPG多进程架构与编译调试实战链路

来源: 作者: 点击:
一、源码工程整体形态
传奇2.0服务端源码在 VC++6.0 下是多 Workspace 多 Project 结构,每个可执行体独立成工程,共享 MirServer 目录约定。核心工程清单:
- LoginGate.dsp → LoginGate.exe(登录网关)
• LoginSrv.dsp → LoginSrv.exe(ID验证服务)

• DBServer.dsp → DBServer.exe(角色/数据持久层)

- SelGate.dsp / Gate30.dsp → 角色选择网关
• RunGate.dsp → RunGate.exe(游戏运行网关)

• M2Server.dsp → M2Server.exe(GameSvr 主逻辑)

- LogDataSrv.dsp → 物品/操作日志服务

工程间不静态链接游戏逻辑,靠 TCP 命名管道/共享内存 做进程间通信,这是早期 Windows MMORPG 典型“网关+逻辑+数据”三层分离架构。

二、各模块源码职责与调用链
1. LoginGate(LoginGate.cpp → WinMain → MainWndProc)
窗口消息驱动,WSAAsyncSelect 绑定 _IDM_CLIENTSOCK_MSG;本地监听 7000 收客户端,远端连 LoginSrv 5000。OnClientSockMsg 里按 FD_CONNECT/FD_READ/FD_CLOSE 分发,启 ThreadFuncForMsg 线程用 IOCP 投递数据包。职责仅加解密转发,不做账号判定。

2. LoginSrv(LogSrv 目录)
读 ID.DB / ID.DB.idx(BDE/Paradox 格式),校验账号密码、封禁、在线数;通过后回包 LoginGate 告知客户端该去哪个 SelGate/DBServer 地址端口。!AddrTable.txt / !ServerInfo.txt 控制 IP 映射。

3. DBServer(DBSrv200 / DBServer 工程)
核心数据守护进程。FDB 目录存人物自定义格式库(Hum.DB 类),Mud2\DB 下挂 StdItems.DB / Monster.DB / Magic.DB 由 BDE HeroDB 别名暴露。GameSvr 要存读角色时发命名管道/Socket 请求,DBSvr 落盘后回 ACK,避免 M2 直接碰 DB 拖慢主循环。

4. SelGate / Gate30
角色选择期中间件,透传角色列表、创建/删除请求到 DBServer,验证完把玩家交给 RunGate。

5. RunGate
多实例(7200/7300…),面向已进游戏玩家。收 M2 下发的坐标/血量/背包变更,转发玩家移动/施法/交易封包给 M2。网关层可横向加实例分摊连接,M2 单进程跑地图与战斗。

6. M2Server(Mir200 主工程,代码量最大)
包含:
• Map 加载:读 Mir200\Map\*.map,二维 Cell 数组存可走/阻挡/物件层

• 怪物 AI:状态机(Idle/Patrol/Chase/Attack/Return),MonGen.txt 驱动刷新

- 战斗计算:DC/AC/MAC/命中/暴击公式,技能分支查 Magic.DB
• 物品系统:StdItems.txt 与 StdItems.DB 双源,GIVE/TAKE 改内存→通知 DBSvr 落盘

- 脚本解析器:Envir\Market_Def、QuestDiary、QFunction-0.txt 文本指令解释执行
• 沙巴克/行会/排行榜:Castle\SabukW.txt、GuildBase\Guilds 运行时维护

三、网络模型与线程结构
源码中可见两套并存:
• 早期分支:WSAAsyncSelect + 窗口消息(LoginGate 典型写法,单线程可撑千连)

• 主服务分支:IOCP 完成端口(CheckAvailableIOCP 判断 NT/2000 后启用),M2/RunGate 用工作线程池收发包,逻辑帧在主线程 Timer 里跑

封包头含会话ID、序号、指令字(CM_LOGIN / CM_ATTACK / CM_DROPITEM…),M2 里大 switch 分发到 HandleXxx 函数。

四、VC++6.0 编译环境硬性条件
- 宿主系统:Windows 2000 / XP 32位实机或虚拟机(Win10+ 装 VC6 需兼容模式且易注册表报错)
• 运行库:VC++6.0 原版 + SP6 + Visual Assist X(老版 10.x)+ BDE Administrator(Borland 共享组件)

- 数据库支撑:DBC2000 装完在 BDE Administrator 建 STANDARD Alias 改名 HeroDB,PATH 指 D:\MirServer\Mud2\DB,Ctrl+S 保存,否则 DBServer 起不来
- 路径规矩:D:\MirServer 纯英文无空格,源码工程放 D:\MirServer\Src 或平行目录,避免长路径中文导致 rc/dsp 加载失败

五、编译顺序与常见报错
1. 打开 MirServer.dsw(或逐工程 Open Workspace)
2. Build 顺序建议:先编译公共库(如有 Share/Common.dsp)→ LoginGate → LoginSrv → DBServer → SelGate → RunGate → M2Server
3. 典型报错:
• cannot open include file 'winsock2.h' → Platform SDK 缺失,VC6 原盘补装或拷 Include/Lib

• unresolved external symbol __imp__WSAStartup@8 → Link 里没加 ws2_32.lib

- BDE 相关 Variant/BDE.hpp 找不到 → 没装 Borland BDE Shared,重装 DBC2000 选 Typical
• error LNK2001 Debug/M2Server.exe : unreachable code → 老代码开了 /Ox 优化与 debug 混用,关优化选 Disable Optimization

- 断点打不中 → 必须在 Debug 配置 Rebuild All,Release 去调试信息

六、调试实战做法
• 单进程调试:VC6 → Build Start Debug → Go,把 LoginGate 设为 Active Project,命令行参数留空,断点打在 MainWndProc 的 WM_COMMAND 分支看登录包流转

- 多进程联调:依次启动 DBServer→LoginSrv→LoginGate→SelGate→M2Server→RunGate,M2 挂 VC6 调试器,客户端用配套登录器连 127.0.0.1:7000;想跟战斗逻辑就在 M2 的 HandleAttack 入口下断,配合 OutputDebugString 打玩家坐标/目标ID 到 DebugView
- 数据校验:改 StdItems.DB 某件装备 DC 后,DBServer 不重启只重读会不一致,调试时直接重启 DBSvr;M2 里 HumanItem 结构下断看内存布局(常用 TItemStd 结构:wIdx, bDura, bDuraMax, bShape, wLooks…)
- 地图阻挡排查:MapCell 结构下断,打印 (x,y) 的 bFlag 位,确认服务端和客户端 .map 版本一致

七、源码阅读切入点建议(按价值排序)
1. LoginGate.cpp → 理解封包转发与 IOCP 雏形
2. M2Server 的 MapUnit / MapMgr → 地图格子与寻路基底
3. MonsterAI / MonsterInfo → Race 状态机与 Monster.DB 字段映射
4. FightSystem / CalcPhysDamage → 早期数值公式朴素逻辑
5. ScriptEngine → #if/#act/#say 文本指令分词与执行(MerChant/QuestDiary 底层)
6. DBServer 的 HumDB 读写 → 自定义格式角色存档字段偏移

八、启动时序与进程依赖(源码外运行时约束)
DBServer(起 HeroDB 连接)→ LoginSrv(连 DBServer)→ LoginGate(连 LoginSrv)→ SelGate(连 LoginSrv/DBServer)→ M2Server(读 Envir、Mir200\Map、Castle,监听 RunGate 回连)→ RunGate(连 M2 指定端口)
任意前置没起,后续进程报“连接失败”而非崩溃,排错按这条链倒推。

九、老代码特征与改造注意
• 大量全局变量(g_xMapMgr、g_HumanList、g_MonList)无命名空间,多线程改需加临界区

- 字符串多用 char[]/AnsiString,直接接 UTF-8 客户端必乱码,脚本文件必须 ANSI
• 无现代日志框架,靠 Log\ 目录写文本 + OutputDebugString

- 想加新指令:在 CM_xxx 枚举加值 → M2 的 Dispatch 表注册 Handle → 客户端封包对齐,缺一环就断连

VC++6.0 下的传奇2.0源码本质是一套“网关分流 + 逻辑集中 + 数据隔离”的 MMORPG 基线架构,编译跑通的关键不在代码多复杂,而在 BDE/HeroDB、VC6 SP6、纯英文路径、进程启动顺序这四件事同时对齐;读懂 LoginGate 的 IOCP 转发再进 M2 的战斗与脚本内核,整条链路就清楚了。