VC++6.0传奇2.0源码架构拆解:服务端网关分层客户端WindHorn编译调试全实录

来源: 作者: 点击:
传奇2.0(Legend of Mir 2)VC++6.0源码是一套典型的多进程分布式MMORPG服务端 + Win32/DirectDraw客户端架构,核心思想是“连接层网关化、逻辑层集中化、数据层持久化”。整套源码在VC6里以 .dsw 工作区组织,包含 LoginGate、SelGate、GameGate、LoginSrv、DBSvr、GameSvr(M2Server)、AdminCmd 等服务端工程,以及 WindHorn、Mir2Ex 等客户端工程 。下面按“整体架构→服务端模块→客户端模块→协议与数据结构→编译环境→启动联调→调试实战→常见编译错误”顺序直拆。

一、整体MMORPG架构分层
数据层:HeroDB(BDE/DBC)、SQL Server(.mdf/.ldf)、Access(.mdb),存账号、角色、物品、技能、行会
服务层:LoginSrv(账号校验)、DBSvr(角色读写持久化)、GameSvr/M2Server(地图、战斗、AI、脚本、广播)
网关层:LoginGate(7000 客户端鉴权入口)、SelGate(7100 角色选择转发)、GameGate(游戏会话代理与消息路由)
客户端层:WindHorn(窗口/DX渲染/音效)、Mir2Ex(登录/选角/游戏逻辑状态机),通过TCP连 LoginGate→SelGate→GameGate

消息前缀约定(Def/Protocol.h):
CM_* 客户端→服务端(CM_LOGIN、CM_WALK、CM_HIT、CM_SPELL、CM_SAY)
SM_* 服务端→客户端(SM_WALK、SM_HIT、SM_ABILITY)
GM_* 网关内部(GM_OPEN、GM_CLOSE、GM_DATA)
DB_/DBR_ 数据库层(DB_LOADHUMANRCD、DB_SAVEHUMANRCD)
RM_* 内部广播引用(RM_WALK、RM_HIT)

二、服务端核心模块源码解析
1. LoginGate(登录网关)
入口 LoginGate.cpp → WinMain → CheckAvailableIOCP(检测NT/2000 IOCP) → InitInstance(WSAStartup) → MainWndProc
本地监听 7000 收客户端,远端连 LoginSrv 5000;用 WSAAsyncSelect + 窗口消息 _IDM_CLIENTSOCK_MSG 处理 FD_CONNECT/FD_READ/FD_CLOSE,线程里用 IOCP 把 LoginSrv 回包转发客户端
只做中转,不验密码,不落数据。

2. SelGate(角色选择网关)
结构与 LoginGate 同构,端口 7100,下游连 DBSvr;负责建角、删角、角色列表、进服授权,转发 CM_QUERYCHR / CM_NEWCHR

3. GameGate(游戏网关)
会话代理,维持客户端Socket与GameSvr内部UserInfo映射;收到客户端 CM_WALK/CM_HIT 直接转发 GameSvr,收到 GameSvr 的 SM_/RM_ 压进对应用户发送缓冲,在IOCP工作线程发回客户端;GM_DATA 类网关本地处理,不分发

4. LoginSrv(账号服务)
等价 AccountServer:验号、选服、建号、防多登;配置 Logsrv.ini(监听端口、DB连接串、允许GameSrv IP列表)

5. DBSvr(数据库持久化)
核心文件 ProcessDBMsg.cpp、ServerCommSockMsg.cpp、GateCommSockMsg.cpp
处理 DB_LOADHUMANRCD / DB_SAVEHUMANRCD / DB_ADDUSER 等;_THUMANRCD(角色存档结构)、_TUSERITEMRCD(物品升级属性)、_THUMANMAGICRCD(技能数据)序列化进库
配置 DBSvr.ini(SQL/Access连接串、Gate通信端口)

6. GameSvr / M2Server(逻辑主程)
核心类:CPlayerObject(移动/战斗/背包/魔法)、CUserInfo(会话与持久化中间层)、CCharObject(怪物/NPC基类)
目录 Mir200\Envir:MapInfo.txt、MonGen.txt、QuestDiary、Market_Def、Npc_Def、ItemDB、MagicDB、Guild 等全部热读
主循环 Operate() 处理 CM_WALK→SM_WALK→RM_WALK 附近广播;战斗结算、爆率、脚本引擎、行会、攻城、交易均在次进程

7. AdminCmd
M2控制台GM工具,发 GM 指令、踢人、改属性、重载脚本

三、客户端模块源码解析(WindHorn + Mir2Ex)
全局对象:
CWHDXGraphicWindow g_xMainWnd(主窗口+DX初始化)
CLoginProcess g_xLoginProc / CCharacterProcess g_xChrSelProc / CGameProcess g_xGameProc(三态机)
继承链:CWHApp → CWHWindow → CWHDXGraphicWindow;CWHDefProcess → CLoginProcess/CCharacterProcess/CGameProcess
WinMain 流程:注册窗口 → DirectDrawEnumerateEx 枚举设备 → CreateDXG() 建 DirectDraw 对象、独占全屏、设显示模式 → CSound.InitMirSound → 消息循环按 g_bProcState 分发到对应 Process 的 DefMainWndProc
玩家点地图移动:CGameProcess::OnLButtonDown → 寻路 → g_xClientSocket.SendPacket(CM_WALK) → 等 SM_WALK/RM_WALK 回包 → 本地插值渲染
资源读取:.wil/.wzx(精灵)、.map(地图)、.wav(音效)、Data\ 补丁,客户端 Mir2.ini 配 LoginIP/LoginPort

四、关键数据结构与协议
Def/Protocol.h:全部 CM/SM/GM/DB/RM 宏与包体结构
_THUMANRCD:char name[14]、level、exp、hp/mp、map、x/y、背包指针、技能数组
_TUSERITEMRCD:makeidx、dura、count、attr[](攻魔道、幸运、孔位、镶嵌)
_ENCODE/EnDecode.cpp:早期简单异或/移位加解密客户端↔网关包

五、VC++6.0编译环境准备
系统:Win2000/XP/Win7 32位最稳;Win10/11需关内核隔离、兼容模式管理员跑VC6
必备库:
• Platform SDK / Old Windows SDK(含 winsock2、winmm)

• DirectX SDK(June 2010 或更早 DX8/9 SDK,含 ddraw.h / ddraw.lib / dinput.lib)

• BDE Administrator + DBC2000(HeroDB 用)

VC6 目录配置:Tools→Options→Directories 加 SDK Include/Lib 置顶

六、编译顺序与工程依赖
打开 LegendOfMir2_Server.dsw
Project→Dependencies 顺序:
公共库(Def/DynamicArray/List/Queue/EnDecode) → DBSvr → LoginSrv → GameSvr(M2Server) → Gate(Login/Sel/Game) → AdminCmd
客户端工作区:先编 WindHorn(生成图形/输入/音效库)→ Mir2Ex(主程序)
配置改点:
• LoginSrv.ini / Logsrv.ini:DB连接串、监听端口、允许GameSvr IP

• GameSvr 启动参数:ServerID、地图路径 Mir200\Map、Envir 路径、DBSvr IP:Port

• 单机多 GameSvr 需独立目录+不同 ServerID+不同端口

七、启动联调顺序
1. 起数据库(SQL Server / Access 引擎 / HeroDB BDE)
2. DBSvr.exe(看“DB Connected”)
3. LoginSrv.exe(账号服务就绪)
4. LoginGate.exe(7000)、SelGate.exe(7100)、GameGate.exe(游戏网关)
5. M2Server.exe / GameSvr.exe(加载 MapInfo/MonGen/QuestDiary,日志“启动成功 在线0”)
6. 客户端改 Mir2.ini → LoginIP=127.0.0.1 LoginPort=7000 → 进游戏建角

八、调试实战(VC6原生调试器)
Project Settings→C/C++→Debug Info = Program Database (/Zi);Link→Debug = Generate debug info
断点落点:
• 网络层:GameGate MainWndProc、OnClientSockMsg

• 逻辑层:CPlayerObject::Operate、ObjectPlayer.cpp 战斗结算

- 数据层:DBSvr ProcessDBMsg.cpp DB_LOADHUMANRCD
Watch 看 g_xMainWnd、g_bProcState、CUserInfo 指针;Memory 窗口看 _THUMANRCD 原始字节
崩溃无提示:WinMain 外包 __try/__except(EXCEPTION_EXECUTE_HANDLER) 写 minidump;Entry-point 设 WinMainCRTStartup
协议联调:客户端发 CM_WALK,VC6断 GameSvr Operate(),看 SM_WALK 是否广播给同屏 RM_* 玩家

九、高频编译错误速查
LNK2001 _DirectDrawCreate@12 未解析 → Link→Object/library modules 加 ddraw.lib;或源码 #pragma comment(lib,"ddraw.lib")
LNK2001 _WSAStartup / recv 未解析 → 加 ws2_32.lib
C2065 'LPDIRECTDRAWSURFACE7' 未声明 → 缺 ddraw.h,SDK Include 路径未挂
结构体对齐告警/读包错位 → Project→C/C++→Code Generation→Struct member alignment = 1 Byte;或头文件 #pragma pack(1)
C4786 模板名截断 → C/C++→Advanced→Disable Language Extensions
COleDispatchDriver / MFC 类找不到 → 工程未开 MFC 支持或没链 mfcs42/lib;纯SDK工程别混用 MFC 头
C2440 long→HANDLE → 显式 HANDLE h = NULL 初始化
/GX 异常开启导致 recv 崩溃 → 关 /GX,VC6 SEH 在旧系统不稳

十、源码研读入口推荐
服务端:Def/Protocol.h(协议全貌)→ DBSvr/ProcessDBMsg.cpp(持久化)→ GameSvr/ObjectPlayer.cpp(角色逻辑)→ LoginGate/MainWndProc.cpp(网关IOCP)
客户端:LoginGate.cpp WinMain → CWHDXGraphicWindow::CreateDXG → CGameProcess::OnLButtonDown → g_xClientSocket 发包链

整套源码本质是“前端DX渲染 + 多网关分流 + 中心逻辑服 + 独立DB代理”的经典老派MMO实现,VC6编译关键不在代码而在 SDK路径/库链接/结构体对齐/IOCP模型四件事同时对齐,调试主线跟住 CM_/SM_/DB_* 三段消息流即可贯通全栈。