Mangos代码阅读

Mangos代码阅读

2010-12-14 15:51:07|  分类: mangos研究|举报|字号 订阅

逻辑层: 类World实现了wow的World,所有的逻辑处理
  MaNGOS 下载,编译,配置和运行的基本步骤 下载和安装msysgit,用于代码管理我使用的是Git-1.6.5.1-preview20091022.exe 
  下载和安装tortoisegit,用于代码管理我使用的是TortoiseGit-1.3.2.0-32bit.msi 
  使用git://github.com/mangos/mangos.git,从github提取mangos代码 
  采用Git GUI工具的Clone Existing Repository,得到 mangos代码(我的是9560,安装UDB参考这) 
  使用git://github.com/scriptdev2/scriptdev2.git,从github提取scriptdev2代码 
  采用Git GUI工具的Clone Existing Repository,得到 scriptdev2代码. 
  编译mangos我用的是VC9,打开mangoswinmangosdVC90.sln进行构造,构造完成后,会得到mangosbinWin32_Debug文件夹 
  编译scriptdev2我用的是VC9,打开mangoswinscriptdev2VC90.sln进行构造,构造完成后,会得到scriptdev2binWin32_Debug文件夹也可参考 
  pandore 
  拷贝mangossrcmangosd目录下的mangosd.conf.dist.in为mangosbinWin32_Debugmangosd.conf 
  拷贝mangossrcrealmd目录下的realmd.conf.dist.in为mangosbinWin32_Debugrealmd.conf 
  从http://www.wowtaiwan.com.tw/下载和安装台服WOW,并升级到最新版本我使用的是台服WOW 3.3.2 build 11403 
  ,采用MaNGOS的工具ad从wow的MPQ中抽取map,得到的所有的map数据文件,文件命名规范为map_id(3位) tileY(2位) tileX(2位).map,如文件名为0002035.map,代表的是Azeroth(地图id为000,tile坐标为(35,20). 注:WOW客户端的Tile对应mangos中的grid,WOW客户端的Chunk对应mangos中的cell(1cell = 4 chunk) 
  按照常规流程(包括建立数据库和配置服务器)把服务器跑起来,使用account create zzh1234567 zzh1234567 创建一个账号,使用account set gmlevel zzh1234567 3设置为超级用户 
  配置好客户端后,运行WOW,顺利登陆,呵呵 
  通过安装UDB来丰富场景FULL DB 9560 : HERE,参考这,在我安装DB9560的时候,发现Mangos在LoadCreatureAddons的时候,加载creature template addons出错,Mangos只要求creature template addons有7个字段,而creature template addons有9个字段我现在只是简单地跳过LoadCreatureAddons的调用 
   
运行Mangos (运行Mangos一节过期,是以前我针对国服3.1.3版本进行的安装配置) ,采用MaNGOS的工具ad从wow的MPQ中抽取map,得到的所有的map数据文件,文件命名规范为map_id(3位) tileY(2位) tileX(2位).map,如文件名为0002035.map,代表的是Azeroth(地图id为000,tile坐标为(35,20). 注:WOW客户端的Tile对应mangos中的grid,WOW客户端的Chunk对应mangos中的cell(1cell = 4 chunk) 
  配置好客户端后,运行WOW,顺利登陆,呵呵 
   
Mangos代码阅读 
  Mangos有13个工程 
  使用了4个外部工具库,分别是: 跨平台的网络通讯框架The ADAPTIVE Communication Environment (ACE) 
  压缩库zlib 
  Socket通信库 C++ Sockets Library (使用在realmd工程中,和使用在Mangosd工程中的RASocket,负责处理Remote Administration其他地方没有使用到这个C++ Sockets Library )发现在C++ Sockets Library的TcpSocket::Open中存在一个问题,在n = connect(s, ad, ad);语句执行后,如果n=-1,C++ Sockets Library会检测是否ERR为WSAEWOULDBLOCK,否则表示成功,但在动态库中使用TcpSocket的时候,我发现n = connect(s, ad, ad);语句执行后,n=-1,ERR会为0,这个时候连接也是成功了,但TcpSocket::Open会当做不成功处理我发现这个问题,但没有时间去探究原因,也许并不是一个问题 
  C++的并行编程模板库Threading Building Blocks (tbb 和 tbbmalloc) 
  Mangos的实现分为:登录服务器(realmd)和世界服务器(mangosd+game)realmd和mangos共用了Mangos公共库(shared) 
  工程shared 
  提供了通用功能,包括了数据库的封装类,实现了对MySql的访问,同样,我们可以编写派生类来支持其他的数据库 
  工程script 
  提供了脚本接口,并实现了简单的几个脚本,封装为DLL,提供给game使用,具体可参考:MaNGOS脚本接口 
  通过使用不同的脚本DLL来替换share的这个DLL,可以让game具有更强的AIScriptDev2 就是一个这样的库ScriptDev2 is a replacement for the Script Library that comes with MaNGOS( http://www.getmangos.com ) written in C++ and is compatible with Windows and Linux. It provides scripts for NPCs, Boss events, and Items currently. Once ScriptDev2 is compiled it is automatically run by MaNGOS on server startup. 
  

工程mangosd 
  mangos是世界服务器的管理器,负责初始化工作和启动世界服务器各层的线程,这些工作主要是由类Master来实现具体是: 使用三个数据库对象WorldDatabase和CharacterDatabase和loginDatabase,初始化三大数据库:World Database和Character Database和login Database,并为每个数据库的访问都启动一个DB delay threads具体的数据库操作功能都是由Mangos公共库shared来提供 
  调用sWorld.SetInitialWorldSettings,对World进行初始化,包括加载所有的游戏数据和初始化各种更新定时器和邮件定时器,还有些其他的初始化工作类World的成员函数SetInitialWorldSettings调用成员函数LoadConfigSettings解析mangosd.conf,解析后内容放入uint32 m_configs[CONFIG_VALUE_COUNT]中 
  加载的游戏数据有: 
  DBC数据 
  Objects数据 
  Spells数据 
  Pooling数据 
  Game Event数据 
  loot数据 
  技能数据 
  所有其他的游戏数据,包括Waypoints和Trainers等等等 
  脚本数据 
  其他的初始化工作有: 
  初始化MapManager,启动Map System 
  初始化Battlegrounds,启动BattleGround System 
  初始化DailyQuestResetTime 
  初始化sGameEventMgr,Starting Game Event system 
  类Master启动WorldRunnable,开始游戏逻辑Heartbeat for the World,由Master创建,并设置线程为最高优先级 
  类Master启动CliRunnable:Command Line Interface handling thread,由Master创建CliRunnable运行时候会生成一个WorldDatabase线程,在接收到输入后会调用sWorld.QueueCliCommand把Cmd放入到World::cliCmdQueue中 
  mangosd的线程总共有(1+3+1+1+1+2 +1 =10)10个线程 主线程Master 
  2个网络线程ReactorRunnable(可配置数目)(网络层) 
  一个World线程(逻辑层) 
  三个DB线程(数据层) 
  一个CLI线程(输入层),运行时候会生成一个WorldDatabase线程 
  一个RA线程(管理层) 
  一个freeze catcher 线程(可选) 
  工程g3dlite:游戏逻辑层的底层库 
  工程framework:系统框架 
  工程realm 
  负责登陆和选择游戏服务器,进行负载均衡用到了C++ Sockets Library进行登录处理,采用select I/O模型实现了Wow, Mangos登录时的SRP6认证客户端作为它的client连接到realm server认证和选择了mangos server就断开 而mangos server和realm server则不进行连接,只是通过数据库交互数据:mangos server把自己的状态和拥有的角色数放入库中realm server会读取数据库中的这些信息来获知mangos server的状态 数据库realm的realmlist表保存了realm的列表 
  realm通过如下事件处理函数来负责登陆和选择游戏服务器 
  const AuthHandler table[] = 
  { 
  { AUTH_LOGON_CHALLENGE, STATUS_CONNECTED, &AuthSocket::_HandleLogonChallenge }, 
  { AUTH_LOGON_PROOF, STATUS_CONNECTED, &AuthSocket::_HandleLogonProof }, 
  { AUTH_RECONNECT_CHALLENGE, STATUS_CONNECTED, &AuthSocket::_HandleReconnectChallenge}, 
  { AUTH_RECONNECT_PROOF, STATUS_CONNECTED, &AuthSocket::_HandleReconnectProof }, 
  { REALM_LIST, STATUS_AUTHED, &AuthSocket::_HandleRealmList }, 
  { XFER_ACCEPT, STATUS_CONNECTED, &AuthSocket::_HandleXferAccept }, 
  { XFER_RESUME, STATUS_CONNECTED, &AuthSocket::_HandleXferResume }, 
  { XFER_CANCEL, STATUS_CONNECTED, &AuthSocket::_HandleXferCancel } 
  }; 登录处理: 
  user登录到realm server进行身份认证,并选择登录上哪个mangos serveruser登录到mangos server后,将不再和realm server交互 
  参考: Wow 服务器解析 
  工程game 
  game:是Mangos的核心代码,网络层和逻辑层代码(采用了ACE反应器(Reactor)模式) 
  网络层: WorldSocket :负责网络IO,而类WorldSession负责逻辑处理WorldSocket和WorldSession分别在独立的线程ReactorRunnable和WorldRunnable中运行,使用WorldSession中的消息队列_recvQueue来进行数据缓冲在WorldSocket接收到网咯输入后,会调用m_Session->QueuePacket (new_pct);把网络包放入WorldSession的_recvQueue所以,可以看到WorldSocket 是Mangos game的网络层,而WorldSession是逻辑处理层WorldSocketMgr是网络层的一个管理器,它负责指派WorldSocket归哪个ReactorRunnable管理(Mangos可创建多个ReactorRunnable,缺省是2个) 
  WorldSocketMgr(Manages all sockets connected to peers and network threads)管理所有的连接WorldSocketWorldSocketMgr的WorldSocketMgr::StartNetwork对8085(缺省)端口进行侦听逻辑处理的循环是在World::Update中循环处理包括: 
  刷新更新定时器 
  刷新游戏定时器和处理游戏关闭 
  处理日常任务 
  处理拍卖 
  刷新SessionsWorld::UpdateSessions会调用所有WorldSession的WorldSession::Update在WorldSession::Update中进行逻辑处理 
  处理天气 
  刷新uptime table 
  刷新Objects,包括maps,transport,creatures,,,, 
  刷新所有running battlegrounds 
  刷新SqlResultQueue, 逻辑层和数据层是通过Queue来进行异步操作的(用了AsyncPQuery和SqlResultQueue) 
  处理尸体移除 
  处理游戏事件 
  处理 Move all creatures with "delayed move" and remove and delete all objects with "delayed remove" 
  处理InstanceSaveManager的刷新 
  调用World::ProcessCliCommands,处理CLI从cliCmdQueue取得cmd进行解析执行所有有效的Cmd,都可以在ChatHandler::getCommandTable中找到 
  类WorldSession: 类WorldSession负责逻辑处理 
  void WorldSession::SendPacket(WorldPacket const* packet) 负责发包给客户端,直接发包,没有输出缓冲队列 
  在WorldSession::Update中进行逻辑处理World::UpdateSessions会调用所有WorldSession的WorldSession::Update 
  执行语句OpcodeHandler& opHandle = opcodeTable[packet->GetOpcode()];得到opHandle 
  根据得到的opHandle,执行(this->*opHandle.handler)(*packet); 
  WorldSession::HandlePlayerLogin处理玩家登陆游戏 
  构建Player 
  Player::LoadFromDB从数据库中加载玩家数据在Player::LoadFromDB中会调用SetMap(MapManager::Instance().CreateMap(GetMapId() , this));加载当前player所在的map 
  Player::SetPosition在Player运动的时候,改变位置,保存处理夸区 
  类Map实现了一个state machine,采用state pattern组织了Gid的4个state object:InvalidState;ActiveState;IdleState;RemovalState 
  game中的管理器有: ObjectMgr 
  mMangosStringLocaleMap 关联到mangos_string table 
  m_scriptNames 关联到tables: creature_template;gameobject_template;item_templat e;areatrigger_scripts;instance_template 
  mCreatureLocaleMap 关联到locales_creature table 
  mGameObjectLocaleMap关联到locales_gameobject table 
  mItemLocaleMap关联到locales_item table 
  mQuestLocaleMap –> locales_quest 
  mNpcTextLocaleMap –> locales_npc_text 
  mPageTextLocaleMap –> locales_page_text 
  mGossipMenuItemsLocaleMap –> locales_gossip_menu_option 
  mPointOfInterestLocaleMap –> locales_points_of_interest 
  … 
  对象类层次 
  对象的类层次如下,所有的Object都由ObjectMgr进行管理ObjectMgr以GUID方式,管理了characters,creature,item_instance,gameobject,auctionhouse,mail,item_text,corpse,arena_team,character_equipmentsets 
   
   
   
   
  

Player状态 
  /// Player state 
  enum SessionStatus 
  { 
  STATUS_AUTHED = 0, ///< Player authenticated (_player==NULL, m_playerRecentlyLogout = false or will be reset before handler call, m_GUID have garbage) 
  STATUS_LOGGEDIN, ///< Player in game (_player!=NULL, m_GUID == _player->GetGUID(), inWorld()) 
  STATUS_TRANSFER, ///< Player transferring to another map (_player!=NULL, m_GUID == _player->GetGUID(), !inWorld()) 
  STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT, ///< _player!= NULL or _player==NULL && m_playerRecentlyLogout, m_GUID store last _player guid) 
  STATUS_NEVER ///< Opcode not accepted from client (deprecated or server side only) 
  }; 
  生物状态 
  enum DeathState 
  { 
  ALIVE = 0, 
  JUST_DIED = 1, 
  CORPSE = 2, 
  DEAD = 3, 
  JUST_ALIVED = 4, 
  DEAD_FALLING= 5 
  }; 
  玩家登陆 
  服务器端在连接打开后,会发SMSG_AUTH_CHALLENGE到客户端客户端从服务器端发送回来的种子和 SRP6 数据中产生随机种子,生成 SHA1 字符串,用这些数据生成 CMSG_AUITH_SESSION 数据包,发送给服务端这个过程是没有经过加密的 
  
  客户端发送SMSG_AUTH_SESSION到服务器 
  服务器处理SMSG_AUTH_SESSION 
  服务器发送SMSG_AUTH_RESPONSE给客户端 
  服务器发送SMSG_ADDON_INFO给客户端 
  服务器发送SMSG_CLIENTCACHE_VERSION给客户端 
  服务器发送SMSG_TUTORIAL_FLAGS给客户端 
  packet结构 SMSG_AUTH_SESSION 是client packet有一个头部(ClientPktHeader),后面是数据块 
  SMSG_AUTH_RESPONSE 是server packet有一个头部(ServicePktHeader),后面是数据块 
  SMSG_AUTH_RESPONSE 的包组织 
  SMSG_AUTH_RESPONSE 的opcode是01EE,ByteBuffer大小为1 + 4 + 1 + 4 + 1=11一个SMSG_AUTH_RESPONSE 的数据如下: 在构造了SMSG_AUTH_RESPONSE packet后,WorldSocket::SendPacket会根据SMSG_AUTH_RESPONSE packet构造出一个ServerPktHeader,并对ServerPktHeader中的数据header进行加密发送加密采用m_Crypt.EncryptSend ((uint8*)header.header, header.getHeaderLength()); WorldSocket::handle_input_header会对从客户端接收来的数据进行解密,解密采用m_Crypt.DecryptRecv ((uint8*) m_Header.rd_ptr (), sizeof (ClientPktHeader)); 
  角色枚举 玩家登上服务器后,从客户端发送SMSG_CHAR_ENUM到服务器 
  在服务器端 
  根据{ "CMSG_CHAR_ENUM", STATUS_AUTHED, &WorldSession::HandleCharEnumOpcode },服务器会调用WorldSession::HandleCharEnumOpcode 
  WorldSession::HandleCharEnumOpcode会调用CharacterDatabase.AsyncPQuery,进行异步查询后,调用CharacterHandler::HandleCharEnumCallback 
  CharacterHandler::HandleCharEnumCallback会回头调用session->HandleCharEnum(result); 
  WorldSession::HandleCharEnum根据characters数据库的查询结果,调用Player::BuildEnumData,加载角色数据,构造SMSG_CHAR_ENUM返回包,然后发送回客户端 
  
  角色创建 
   
  角色的初始化装备在CharStartOutfit.dbc 
  角色的创建和选择的设置都在 ChrRaces.dbc 
  角色的创建属性都在Playercreateinfo,包括出生地和出生属性 
  playercreateinfo_item表是创建一个新人物时,人物默认带的所有Item的表 
  playercreateinfo_spell表是创建一个新人物时,人物默认带的所有Spell的表 
角色删除 
  

Mangos代码阅读,布布扣,bubuko.com

时间: 2024-11-13 06:52:47

Mangos代码阅读的相关文章

《代码阅读方法与实践》阅读笔记之二

时间过得真快,一转眼,10天就过去了,感觉上次写阅读笔记的场景仿佛还历历在目.<代码阅读方法与实践>这本书真的很难写笔记,本来我看这本书的名字还以为书里大概写的都是些代码阅读的简易方法,心想着这就好写笔记了,没想到竟然好多都是我们之前学过的东西,这倒让我有点无从下手了.大概像我们这些还没有太多经历的大学生,总是习惯于尽量避免自己的工作量,总是试图找到一些完成事情的捷径吧.总之,尽管我不想承认,但我自己心里很清楚,我就是这种人.下面开始言归正传,说说接下来的几章内容归纳. 这本书在前面已经分析了

代码阅读问题

---恢复内容开始--- 下面列举阅读代码过程中遇到的问题和相应的资料查询: 1.namespace的用途:http://www.kuqin.com/language/20080107/3532.html 2.enum 的用途:http://pcedu.pconline.com.cn/empolder/gj/c/0502/562347.html 3.SFML:http://www.sfml-dev.org/ 4.双冒号的用法:http://blog.csdn.net/zimingjushi/ar

代码阅读方法与实践(三)

我们分析的许多系统都遵循一种简单的“主程序和子例程”结构.常见的.重要的结构可以归类为少数迥然相异的构架类型:集中式储存库.数据流.面向对象或分层构架.这些构架类型常常结合成一个层次结构用来控制大型系统的复杂性.接下来我们将独立的分析每种构架类型,但是一个系统可以同时展示出多种不同的构架类型.以不同的方式检查同一个系统.分许系统的不同部分.或使用不同级别的分解,都有可能发现不同的架构类型. 集中式储存库的构架模型依赖于一个中心过程或数据结构,他在系统中担任控制或信息的集线器.即使不需要数据库提供

《代码阅读方法与实践》阅读笔记三

之前已经看完了<代码阅读方法与实践>的前六章,基本上也就是看得比较粗略,没有很精细的阅读,上节课听到老师说的“学术交流会”还是很紧张的,挺害怕被问到问题,结果回答不出来可怎么办啊,不仅丢人,分也送给别人了啊,这可怎么破啊.所以呢,我打算近期再看一遍,不管有没有用,算是给自己加点自信吧. 第七章,讲的是编程规范和约定,主要就是文件的命名及组织.缩进.编排.命名约定.编程实践.过程规范之类的,其实这一章也不用我做过多的介绍,因为大家应该都有听各科老师讲过好几遍了,道理大家都懂,但是大家除了在理论上

《代码阅读方法与实践之读书笔记之一》

阅读代码是程序员的基本技能,同时也是软件开发.维护.演进.审查和重用过程中不可或缺的组成部分.<代码阅读方法与实践之读书笔记之一>这本书围绕代码阅读,详细论述了相关的知识与技能.我希望通过仔细阅读并学习本书,可以快速地提高我的代码阅读的技能与技巧,进而从现有的优秀代码.算法.构架.设计中汲取营养,提高自身的开发与设计能力.此次读了此书的前四章,以下是我从中汲取到的宝贵养分: 从第一章<导论>一节中我体会到了我们要养成一个经常花时间阅读别人编写的高品质代码的习惯,因为阅读高品质的代码

图形化代码阅读工具——Scitools Understand

Scitools出品的Understand 2.0.用了很多年了,比Source Insight强大很多.以前的名字叫Understand for C/C++,Understand for Java,Understand for Ada,最近这几年合并成了一个产品. 最值得一提的是各种关系图的绘制,以及在这些图上的交互操作:Declaration Graphs / Hierarchy Graphs / Control Flow Graphs / Dependency Graphs / UML C

NRE代码阅读记录

本来是为了论证自己的观点,把安全标签打在RunningConfig里,就写了个代码分析,结果写着写着发现的确不应该是在RunningVM里.意外的发现看代码的时候这么写写还是挺不错的,也避免了看了后面的忘记前面的.这种底层的代码实在是很难理解,对我来说就像是小学生去算高数一样,也只能硬着头皮去看了. vmmng.cc对应的就是如下界面(回头放图上来,ubuntu下没有什么截图工具,总不能把整个屏幕放上来)然后"3"键可以新建tiny-core虚拟机,对应到代码里,也就是input_th

代码阅读分析工具Understand 2.0试用

Understand 2.0是一款源码阅读分析软件,功能强大.试用过一段时间后,感觉相当不错,确实能够大大提高代码阅读效率.因为Understand功能十分强大,本文不可能详尽地介绍它的全部功能,所以仅仅列举本人觉得比較重要或有特色的功能,以做抛砖引玉之举. Understand 2.0能够从http://www.scitools.com/下载到,安装后能够试用15天. 使用Understand阅读代码前,要先创建一个Project,然后把全部的源码文件增加到这个Project里.这里我创建了一

Xv6代码阅读报告之进程调度

Xv6代码阅读报告-Topic3 @肖剑楠 20111013223 Xv6代码阅读报告-Topic3 1. 序 2. 上下文切换 2.1 defs.h 2.2 swtch.S 3. 进程调度 4. 管道 5. 进程调度流程 6. Pipe实现概述 7. 阅读心得 1. 序 Xv6为了实现CPU多进程化需要解决一系列问题.1. 如何在进程间切换?2. 如何让这一切换变得透明?3. 需要锁机制来避免竞争.4. 内存.资源的自动释放. Xv6通过实现上下文切换(Context Switching),时