一、进程级架构与职责划分
LegendofMir(Mir2)服务端不是单体程序,而是多进程协同系统,源码按组件拆工程:
-DBSvr(DBServer.exe):角色数据持久层,处理GetHumanRcd/SaveHumanRcd/MakeNewItem,数据落Mud2\DBSrv200\FDB\Hum.DB或HeroDB(DBC2000),内部端口6000/7300,不对外暴露
-LoginSrv(LoginSrv.exe):账号认证,读IDDB\ID.DB,分配游戏服入口,端口5500
•LoginGate(LoginGate.exe):客户端第一入口,监听7000,WSAAsyncSelect+线程转发,只做加解密与路由
-SelGate(SelGate.exe):角色选择期网关,端口7100/7101,从DBSvr拉角色列表
•RunGate/GameGate(RunGate.exe):游戏运行期操作枢纽,监听7200/7300等,转发移动/攻击/交易封包给M2
-M2Server(GameSvr/Mir200\M2Server.exe):世界模拟核心,地图/怪物/NPC/战斗/脚本全在这
•LogServer(LogDataServer.exe):行为日志落地,端口10000
进程间通信用TCP命名管道+自定义封包(Def/Protocol.h定义CM_/SM_/DB_/DBR_指令字),网关层屏蔽客户端直连M2,逻辑层与网络层物理分离。
二、标准启动顺序与依赖链(源码级视角)
初始化顺序错一位就全红:
1.DBServer先起→连HeroDB/打开FDB,建监听套接字,等LoginSrv/M2来取数据
2.LoginSrv起→读ID.DB,连DBSvr校验通道,开5500
3.LoginGate→绑7000,连LoginSrv5000/5500,等客户端
4.SelGate→绑7100,连LoginSrv+DBSvr
5.RunGate(可多实例7200/7300/7400…)→绑端口,等M2回连注册
6.M2Server最后起→读!Setup.txt、Envir、Map、MonGen、MerChant,初始化完成发“Gate0Opened/服务器启动完成”,回连各RunGate建立会话
M2若先于DBSvr起,角色加载阶段直接报“Cannotopendatabase”或卡在等待DBR_HUMAN_REC回应;RunGate先起则M2启动时报“Gateconnectionfailed”。
三、M2Server内部初始化流程(InitServer主线)
WinMain→读命令行/!Setup.txt→初始化全局管理器:
1.日志系统InitLog→Mir200\Log\建当日文件
2.加载配置LoadConfig(!Setup.txt/!ServerInfo.txt/!AddrTable.txt)→ServerName、IP、端口、经验倍率、爆率、存盘间隔入全局变量
3.数据库通道InitDBSvrSock→连DBServer内部端口,发DB_HELLO握手
4.地图系统InitMap→读Envir\MapInfo.txt,逐个加载Map\*.map到CMapMgr,解析格子阻挡/物件/区域触发
5.数据表加载LoadStdItems/LoadMonsterDB/LoadMagicDB→读StdItems.txt+StdItems.DB、Monster.txt+Monster.DB、Magic.txt+Magic.DB进内存哈希表
6.刷怪配置LoadMonGen→解析MonGen.txt,建定时器,按坐标/数量/间隔注册刷新点
7.NPC/机器人加载LoadMerChant→解析Envir\MerChant.txt,按“脚本名地图号XY…”绑定Market_Def\脚本名-地图号.txt;LoadRobot→Robot.txt+Robot_def\
8.脚本引擎InitScriptEngine→预编译QuestDiary/QFunction/QManage标签树,语法错打行号
9.沙巴克/行会/排行榜InitCastle/InitGuild/InitTop→读Castle\SabukW.txt、GuildBase\Guilds、顶榜文件
10.网络层InitGateSocks→等RunGate回连,建CGateInfo会话表;起主循环Timer(通常100-200ms逻辑帧)
11.控制台输出“服务器启动完成”,接受玩家接入
四、多线程架构与分工
老版VC++6/DELPHI源码线程模型:
•主线程:Windows消息循环+逻辑帧Timer(UpdateWorld:移动、战斗、AI、掉落、脚本触发)
-网络线程(LoginGate/RunGate):WSAAsyncSelect或IOCP完成端口(CheckAvailableIOCP判断NT/2000后启用),收包入队列→主线程按帧消费;发包反向推送
-DBSvr工作线程:ProcessDBMsg循环,从套接字读DB_消息→查/写Hum.DB→回DBR_,每条角色存档带GUID锁防并发覆盖
•M2怪物AI线程(部分版本/OpenMir2):MobThread调度,按OperateTime差分更新,无锁链表遍历;老版多在主帧里串行跑
-定时线程:存盘线程(默认10-30min写FDB/SQL)、刷怪线程、机器人触发线程(Robot_defSEC/MIN/HOUR)
•日志线程:LogServer独立进程,M2发UDP/TCP日志包,异步落盘不阻塞主帧
同步原语:全局对象表(g_HumanList/g_MonList/g_ItemList)用临界区/Monitor保护;DB回写用读写锁;网关会话CGateInfo用Interlocked计数。
五、封包流转示例(登录到进图)
客户端→LoginGate:7000(CM_IDLOGIN)→LoginSrv验ID.DB→DBSvr取角色列表→SelGate展示→选角色进服→RunGate:7200(CM_LOGIN带角色名)→M2发DB_LOADHUMAN→DBSvr回DBR_HUMAN_REC(_THUMANRCD:属性/装备/_TUSERITEMRCD/技能_THUMANMAGICRCD)→M2构CPlayerObject入世界→下发SM_LOGINOK+地图数据→客户端进比奇
实时操作:玩家按方向键→RunGate→CM_WALK→M2校验地图阻挡/速度/负重→更新CPlayerObject坐标→广播SM_GOODWALK给视野内会话→RunGate下发客户端
六、核心数据结构(源码可见)
•CPlayerObject:移动/战斗/背包/魔法/状态机主体(ObjectPlayer.cpp)
•CCharObject:怪/人/NPC公共基类,含地图坐标、视野、仇恨表
-_THUMANRCD/_TUSERITEMRCD/_THUMANMAGICRCD:DB持久化结构,GUID唯一标识物品
•CGateInfo:网关会话,含SendBuf/RecvBuf/ConnState
-CMapCell:地图格子,bFlag位标记可走/阻挡/传送/安全区
七、现代重构版(OpenMir2/.NET/C#)差异点
架构同构但实现升级:DBSvr改EFCore+MySQL(mir2_db.sql建表),网关仍分离可水平扩RunGate实例;主循环用ChannelMessageHandler消息队列替代裸switch;锁细化到AccountLock/LoadLock,加对象池、环形任务队列、增量存档;启动顺序仍严守DBSvr→LoginSrv→Gate→GameSvr。
八、初始化失败硬排查点
•M2起不来:HeroDB别名PATH错、Envir\MapInfo.txt地图号无对应.map、MerChant.txt字段错位、脚本UTF-8乱码、端口被占(netstat-ano查7000/7200)
-卡在加载角色:DBSvr没起或!AddrTable.txt没放行M2IP
•进图黑屏:Map\*.map与MapInfo.txt不一致、Objects.wil/Tiles.wil缺帧
-网关连不上:Config.ini里ListenAddr/IP/Port与M2!Setup.txt不一致
LegendofMir服务端初始化本质是一条“数据层先行→网关暴露端口→逻辑层最后拉起世界”的硬依赖链;多线程不在M2内卷并发,而是把网络、持久化、日志、定时全拆到独立进程/线程,主帧只跑世界模拟,这是它能撑百人在线且不炸的核心原因。
LegendofMir(Mir2)服务端不是单体程序,而是多进程协同系统,源码按组件拆工程:
-DBSvr(DBServer.exe):角色数据持久层,处理GetHumanRcd/SaveHumanRcd/MakeNewItem,数据落Mud2\DBSrv200\FDB\Hum.DB或HeroDB(DBC2000),内部端口6000/7300,不对外暴露
-LoginSrv(LoginSrv.exe):账号认证,读IDDB\ID.DB,分配游戏服入口,端口5500
•LoginGate(LoginGate.exe):客户端第一入口,监听7000,WSAAsyncSelect+线程转发,只做加解密与路由
-SelGate(SelGate.exe):角色选择期网关,端口7100/7101,从DBSvr拉角色列表
•RunGate/GameGate(RunGate.exe):游戏运行期操作枢纽,监听7200/7300等,转发移动/攻击/交易封包给M2
-M2Server(GameSvr/Mir200\M2Server.exe):世界模拟核心,地图/怪物/NPC/战斗/脚本全在这
•LogServer(LogDataServer.exe):行为日志落地,端口10000
进程间通信用TCP命名管道+自定义封包(Def/Protocol.h定义CM_/SM_/DB_/DBR_指令字),网关层屏蔽客户端直连M2,逻辑层与网络层物理分离。
二、标准启动顺序与依赖链(源码级视角)
初始化顺序错一位就全红:
1.DBServer先起→连HeroDB/打开FDB,建监听套接字,等LoginSrv/M2来取数据
2.LoginSrv起→读ID.DB,连DBSvr校验通道,开5500
3.LoginGate→绑7000,连LoginSrv5000/5500,等客户端
4.SelGate→绑7100,连LoginSrv+DBSvr
5.RunGate(可多实例7200/7300/7400…)→绑端口,等M2回连注册
6.M2Server最后起→读!Setup.txt、Envir、Map、MonGen、MerChant,初始化完成发“Gate0Opened/服务器启动完成”,回连各RunGate建立会话
M2若先于DBSvr起,角色加载阶段直接报“Cannotopendatabase”或卡在等待DBR_HUMAN_REC回应;RunGate先起则M2启动时报“Gateconnectionfailed”。
三、M2Server内部初始化流程(InitServer主线)
WinMain→读命令行/!Setup.txt→初始化全局管理器:
1.日志系统InitLog→Mir200\Log\建当日文件
2.加载配置LoadConfig(!Setup.txt/!ServerInfo.txt/!AddrTable.txt)→ServerName、IP、端口、经验倍率、爆率、存盘间隔入全局变量
3.数据库通道InitDBSvrSock→连DBServer内部端口,发DB_HELLO握手
4.地图系统InitMap→读Envir\MapInfo.txt,逐个加载Map\*.map到CMapMgr,解析格子阻挡/物件/区域触发
5.数据表加载LoadStdItems/LoadMonsterDB/LoadMagicDB→读StdItems.txt+StdItems.DB、Monster.txt+Monster.DB、Magic.txt+Magic.DB进内存哈希表
6.刷怪配置LoadMonGen→解析MonGen.txt,建定时器,按坐标/数量/间隔注册刷新点
7.NPC/机器人加载LoadMerChant→解析Envir\MerChant.txt,按“脚本名地图号XY…”绑定Market_Def\脚本名-地图号.txt;LoadRobot→Robot.txt+Robot_def\
8.脚本引擎InitScriptEngine→预编译QuestDiary/QFunction/QManage标签树,语法错打行号
9.沙巴克/行会/排行榜InitCastle/InitGuild/InitTop→读Castle\SabukW.txt、GuildBase\Guilds、顶榜文件
10.网络层InitGateSocks→等RunGate回连,建CGateInfo会话表;起主循环Timer(通常100-200ms逻辑帧)
11.控制台输出“服务器启动完成”,接受玩家接入
四、多线程架构与分工
老版VC++6/DELPHI源码线程模型:
•主线程:Windows消息循环+逻辑帧Timer(UpdateWorld:移动、战斗、AI、掉落、脚本触发)
-网络线程(LoginGate/RunGate):WSAAsyncSelect或IOCP完成端口(CheckAvailableIOCP判断NT/2000后启用),收包入队列→主线程按帧消费;发包反向推送
-DBSvr工作线程:ProcessDBMsg循环,从套接字读DB_消息→查/写Hum.DB→回DBR_,每条角色存档带GUID锁防并发覆盖
•M2怪物AI线程(部分版本/OpenMir2):MobThread调度,按OperateTime差分更新,无锁链表遍历;老版多在主帧里串行跑
-定时线程:存盘线程(默认10-30min写FDB/SQL)、刷怪线程、机器人触发线程(Robot_defSEC/MIN/HOUR)
•日志线程:LogServer独立进程,M2发UDP/TCP日志包,异步落盘不阻塞主帧
同步原语:全局对象表(g_HumanList/g_MonList/g_ItemList)用临界区/Monitor保护;DB回写用读写锁;网关会话CGateInfo用Interlocked计数。
五、封包流转示例(登录到进图)
客户端→LoginGate:7000(CM_IDLOGIN)→LoginSrv验ID.DB→DBSvr取角色列表→SelGate展示→选角色进服→RunGate:7200(CM_LOGIN带角色名)→M2发DB_LOADHUMAN→DBSvr回DBR_HUMAN_REC(_THUMANRCD:属性/装备/_TUSERITEMRCD/技能_THUMANMAGICRCD)→M2构CPlayerObject入世界→下发SM_LOGINOK+地图数据→客户端进比奇
实时操作:玩家按方向键→RunGate→CM_WALK→M2校验地图阻挡/速度/负重→更新CPlayerObject坐标→广播SM_GOODWALK给视野内会话→RunGate下发客户端
六、核心数据结构(源码可见)
•CPlayerObject:移动/战斗/背包/魔法/状态机主体(ObjectPlayer.cpp)
•CCharObject:怪/人/NPC公共基类,含地图坐标、视野、仇恨表
-_THUMANRCD/_TUSERITEMRCD/_THUMANMAGICRCD:DB持久化结构,GUID唯一标识物品
•CGateInfo:网关会话,含SendBuf/RecvBuf/ConnState
-CMapCell:地图格子,bFlag位标记可走/阻挡/传送/安全区
七、现代重构版(OpenMir2/.NET/C#)差异点
架构同构但实现升级:DBSvr改EFCore+MySQL(mir2_db.sql建表),网关仍分离可水平扩RunGate实例;主循环用ChannelMessageHandler消息队列替代裸switch;锁细化到AccountLock/LoadLock,加对象池、环形任务队列、增量存档;启动顺序仍严守DBSvr→LoginSrv→Gate→GameSvr。
八、初始化失败硬排查点
•M2起不来:HeroDB别名PATH错、Envir\MapInfo.txt地图号无对应.map、MerChant.txt字段错位、脚本UTF-8乱码、端口被占(netstat-ano查7000/7200)
-卡在加载角色:DBSvr没起或!AddrTable.txt没放行M2IP
•进图黑屏:Map\*.map与MapInfo.txt不一致、Objects.wil/Tiles.wil缺帧
-网关连不上:Config.ini里ListenAddr/IP/Port与M2!Setup.txt不一致
LegendofMir服务端初始化本质是一条“数据层先行→网关暴露端口→逻辑层最后拉起世界”的硬依赖链;多线程不在M2内卷并发,而是把网络、持久化、日志、定时全拆到独立进程/线程,主帧只跑世界模拟,这是它能撑百人在线且不炸的核心原因。

