mangos0.9代码分析(一)

最近下到了一份mangos0.9版本的源码,打算用心读一读,也算是学习学习。

当然这也是本人第一次接触游戏服务器源码,估计会遇到很多很多的问题,这篇文章也是本人的第一篇博客,来csdn那么多年了,终于打算开始写点东西了,接下来的一段时间,想自己研究研究这份代码,随手写点东西也算是做了笔记了。

        mangos不是一个魔兽私服模拟器,它是一个开源的自由软件项目,是用c++和C#编程语言,实现的一个支持大型多人在线角色扮演游戏服务器的程序框架,在这个框架下,它理论上应该支持任何客户端的网络游戏,由于现在很多人使用魔兽世界来对它进行测试,所以针对魔兽世界的脚本和数据库文件比较完善,很多人就利用这个开源项目来实现魔兽私服。mangos的技术细节上是这样的,核心部分是个和特定游戏没有关系的核心框架程序,主要是进行进程调度,创造世界,建立心跳机制,处理网络接入等。数据库也是使用的开源数据库软件MySQL,编译器使用的是GCC。至于游戏内容数据库,游戏人物,时间,世界脚本,都是由这个核心程序所支持的扩展脚本来实现,所以有一些独立出来的项目专门模拟魔兽世界来开发支持mangos的核心程序。现在mangos的核心程序已经放到著名的协同开发网站sourceforge上开发了,使用的版本控制工具是subversion,(目前已经迁移到GIT)。大家都可以到github下载最新的源代码程序。(该段转自百度百科)

     我下载的mangos0.9版本在csdn资源中就有,源代码在mangos/src目录中,该目录中包括6个文件夹,和makefile.in 和makefile.am文件,这两个文件不用说的,产生makefile文件用的。 关键在所包含的六个文件夹  bindings   framework  game  mangosd  realmd  shared 。

其中bindings文件夹中包含脚本文件,应该是对脚本进行绑定的。

framework文件夹中包括一些游戏框架,其中包括网络框架,游戏系统框架,工具,平台等内容。

game文件夹中应该是游戏的文件,包括世界系统,战斗系统,游戏事件,游戏场景等的实现。

mangosd文件夹中是mangosd的主程序,包括程序的入口等。

realmd 文件夹中是游戏区域信息,包括RealmList等内容。

shared文件夹中 应该是公用的函数和库,database的内容包含在其中。

以上内容只是自己的摸索,不保准的,呵呵。

另外分析一下整体结构:

mangos使用了4个外部工具库,分别是:

       跨平台的网络通讯框架The ADAPTIVE Communication Environment (ACE)
  压缩库zlib
  Socket通信库 C++ Sockets Library  和  C++的并行编程模板库Threading Building Blocks (tbb 和 tbbmalloc)


mangos可以分为以下几个工程模块:

      工程mangosd 

      mangos是世界服务器的管理器,负责初始化工作和启动世界服务器各层的线程,这些工作主要是由类Master来实现。

      类Master执行包括连接数据库,载入世界模型,启动世界更新线程,启动命令行线程,启动RA线程等操作。

      mangosd共有13个线程:

       一个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的列表。

      工程game
  game:是Mangos的核心代码,网络层和逻辑层代码(采用了ACE反应器(Reactor)模式)    

     mangos的执行模型如下:   

一、线程分布:
1、主线程 main---- Master::Run() ,主要功能:初始化world、创建子线程、回收资源
2、WorldRunnable -------GS主线程
3、CliRunnable -----后台调试线程
4、RARunnable -------事件处理和分发线程
5、MaNGOSsoapRunnable---协议
6、FreezeDetectorRunnable
7、线程池  Master::Run----WorldSocketMgr::StartNetwork---WorldSocketMgr::StartReactiveIO ---ReactorRunnable

二、事件分发和处理
WorldRunnable::run---World:update----World:UpdateSessions---WorldSession::Update(一个socket内所有事件)---各种各样的handler

基本框架:ACE的Reactor机制(ACE_TP_Reactor)

三、WorldRunnable 主要功能
WorldRunnable ----World 定时器任务+网络事件(session中的)+异步IO回调+任务系统调度+cli

 

     以上部分内容参考网络上一些资料  
     

按照逻辑,先从mangosd开始读起, 因为目前我也不是很清楚这份代码的架构,也处于摸索阶段,先从main开始入手,也算是摸着石头过河了。

// 此处略去了版权声明,开源软件尊重版权
#include "Common.h"
#include "Database/DatabaseEnv.h"
#include "Config/ConfigEnv.h"
#include "Log.h"
#include "Master.h"
#include "SystemConfig.h"

// 用于系统的判断,用于兼容Windows系统,mangosd原本是linux下的开源软件
#ifdef WIN32
#include "ServiceWin32.h"
char serviceName[] = "mangosd";
char serviceLongName[] = "MaNGOS world service";
char serviceDescription[] = "Massive Network Game Object Server";
/*
 * -1 - not in service mode
 *  0 - stopped
 *  1 - running
 *  2 - paused
 */
int m_ServiceStatus = -1;
#endif

//选择数据库的宏定义,一般选择MySql数据库 ,其中DatabaseMySql类定义在shared文件夹中,数据库类作为公共文件
#ifdef DO_POSTGRESQL
DatabasePostgre WorldDatabase;                              ///< Accessor to the world database
DatabasePostgre CharacterDatabase;                          ///< Accessor to the character database
DatabasePostgre loginDatabase;                              ///< Accessor to the realm/login database
#else
DatabaseMysql WorldDatabase;                                ///< Accessor to the world database
DatabaseMysql CharacterDatabase;                            ///< Accessor to the character database
DatabaseMysql loginDatabase;                                ///< Accessor to the realm/login database
#endif

uint32 realmID;                                             /// 使用一个全局变量记录游戏区域的id,因为游戏区id唯一性,一旦选择应该保持全局不变

/// 从终端输出一些版本Server运行信息
void usage(const char *prog)
{
    sLog.outString("Usage: \n %s []\n"
        "    -c config_file           use config_file as configuration file\n\r"
        #ifdef WIN32
        "    Running as service functions:\n\r"
        "    --service                run as service\n\r"
        "    -s install               install service\n\r"
        "    -s uninstall             uninstall service\n\r"
        #endif
        ,prog);
}

/// 主函数,登录mangos的入口
extern int main(int argc, char **argv)
{
// 创建一个mangos内存管理 并对该内存管理类进行初始化 
// 该内存管理类模版在framework文件中的policies中进行声明,使用MaNGOS命名空间,负责什么以后再看了。。。
    MaNGOS::Singleton::Instance();
	
///读取Mangosd的配置文件 其中 宏_MANGOSD_CONFIG为"mangosd.conf" 该配置文件就在mangosd文件夹中
    char const* cfg_file = _MANGOSD_CONFIG;
    int c=1;
//下面执行的是一些附带命令,在启动时作为附带命令来指定文件和输出相关信息 ( 附带命令是随便解释的呵呵  )
    while( c < argc )
    {
        if( strcmp(argv[c],"-c") == 0)
        {   // "-c"应该是配置文件的命令,后面附带配置文件
            if( ++c >= argc )
            {   
				// 后文不带参数,报错
                sLog.outError("Runtime-Error: -c option requires an input argument");
                usage(argv[0]);
                return 1;
            }
            else
                cfg_file = argv[c];  // 配置文件
        }
// 以下宏定义范围内为Windows下的文件配置信息也是用来配置configure文件的, 此处略过
        #ifdef WIN32
        
        //Services//
        
        if( strcmp(argv[c],"-s") == 0)
        {
            if( ++c >= argc )
            {
                sLog.outError("Runtime-Error: -s option requires an input argument");
                usage(argv[0]);
                return 1;
            }
            if( strcmp(argv[c],"install") == 0)
            {
                if (WinServiceInstall())
                    sLog.outString("Installing service");
                return 1;
            }
            else if( strcmp(argv[c],"uninstall") == 0)
            {
                if(WinServiceUninstall())
                    sLog.outString("Uninstalling service");
                return 1;
            }
            else
            {
                sLog.outError("Runtime-Error: unsupported option %s",argv[c]);
                usage(argv[0]);
                return 1;
            }
        }
        if( strcmp(argv[c],"--service") == 0)
        {
            WinServiceRun();
        }
        
        #endif
        ++c;
    }

   // 读取配置文件出错  
    if (!sConfig.SetSource(cfg_file))
    {
        sLog.outError("Could not find configuration file %s.", cfg_file);
        return 1;
    }
   // 成功读取配置文件,输出信息
    sLog.outString("Using configuration file %s.", cfg_file);

  // 其实服务器主程序应该是在这里运行的,这个sMaster对象这样定义着 
  // #define sMaster MaNGOS::Singleton::Instance() 
  // 其实还是作为Singleton的模版传进去进行初始化后得到的,这里的Singleton是不是设计模式中的单例模式呢??我也不清    // 楚 呵呵
  // 而模版类MaNGOS::Singleton 自我感觉应该是非常关键的一点,以后会详细分析其实现和设计
    sMaster.Run();  // 运行Master对象 ,至此,Mangos开始运行。
    return 0;
}

其实 mangos中的main()多是一些配置文件信息,进行数据库,内存管理,配置文件的初始化等工作,然后执行sMaster开始真正运行系统。

下一次顺着这条路 从sMaster开始接着向下分析。

实验室关门了。。

 

 
 

你可能感兴趣的:(游戏服务器学习,mangos)