GS初始化

开启GameServer模式
init函数,现在看看这个大函数干什么的
//这个init也是GameServerUI里面调的,这个线程其实就做了一些初始化的工作,其实这里面没有什么主不主线程,都是在一个进程里面的
void __stdcall GameServer::init()
{
    ///设置最大连接数,现在还不知这个到底干啥的
    Share::SetMaxGcNumb(12000); //指定本GS支持的最大数量

    ///log日志,现在服务器写日志,在服务器报错的时候可以查看日志,还有报错时生成dump文件,然后上传ftp服务器,到时可以调试这个dump文件也可以知道在哪里报错
    // Log记录,全局单例,支持多线程。
    m_spLog = NEWSP(Log);
    std::string strLogDir = safe::wcstombs(Plug::GetCurrentPath()) + "Log";
    m_spLog->Init(strLogDir.c_str());
    SetPlug("Log", m_spLog.get());

    ///这个usbdog现在我不知道干啥的
    I_USBDog* pDog = NEW(USBDog);
    msg_assertex(pDog,"usb dog 创建失败!");
    std::string str = (char*)Plug::GetApp()->m_app_shared;
    if(str != "USBDog")
        return ;

    ///主要是一些配置文件的拷贝,只要模板然后拷贝一份你可以配置
    std::wstring wstrCurPath = Plug::GetCurrentPath();
    CheckFileAndCopy(wstrCurPath + L"option.xml", wstrCurPath + L"option模板.xml");
    CheckFileAndCopy(wstrCurPath + L"DBline.xml", wstrCurPath + L"DBline模板.xml");
    CheckFileAndCopy(wstrCurPath + L"centerOption.xml", wstrCurPath + L"centerOption模板.xml");

    ///在程序中开启控制打印,看变量的值
//#define ALLOC_CONSOLE
#ifdef ALLOC_CONSOLE
    AllocConsole();                        // 开辟控制台 释放:FreeConsole();
    SetConsoleTitle(L"Debug Output");      // 设置控制台窗口标题
    freopen("CONOUT$","w",stdout);         // 重定向输出
    printf("hello!\n");
#endif

    ////为进程指定CPU
    //SetProcessAffinityMask(GetCurrentProcess(), 1L);

    ///连接中心服务器,天龙里面是世界服务器,我们这个可以说没啥用,天龙那个是架构的一部分,没咋看天龙那个世界服务器
    /*连接centerServer*/
    m_spCenterTcpLink = NEWSP(CenterTcpLink);
    std::shared_ptr<I_SaveOption> spSaveOpt = NEWSP(SaveOption);
    spSaveOpt->openFile((Plug::GetCurrentPath() + L"centerOption.xml").c_str());
    std::string strIP = safe::wcstombs(spSaveOpt->getStr(L"root.ip"));
    int nPort = spSaveOpt->getInt(L"root.port");
    int nIP = ntohl(inet_addr(strIP.c_str()));
    if (!m_spCenterTcpLink->Connect(nIP, nPort))
    {
        MessageBox(NULL, L"centerServer连接失败!", L"Error!", MB_ICONERROR);
        ::TerminateProcess(::GetCurrentProcess(), 0);
    }

    //获取GameServer端口号
    spSaveOpt->openFile((Plug::GetCurrentPath() + L"option.xml").c_str());
    m_nPort = spSaveOpt->getInt(L"root.port");

    /*    初始化数据库    */
    m_spAsynDBC = NEWSP(asynDBCenter);///主要是mongo数据库的指针和加载任务等级信息,用于创建角色使用

    spSaveOpt->openFile((Plug::GetCurrentPath() + L"DBline.xml").c_str());
    std::string strDBIP =  safe::wcstombs(spSaveOpt->getStr(L"root.ip"));
    std::string strAcountDBName = safe::wcstombs(spSaveOpt->getStr(L"root.AccountDBName"));
    std::string strActorDBName = safe::wcstombs(spSaveOpt->getStr(L"root.ActorDBName"));

    ///这个主要是数据库字段数组的初始化,这个数组的值就是对应到数据库里面的字段的,后面数据库的存取都用到这个数组,类似下面的形式
    {//其中是根绝数组直接定位的
        m_pConfigName[eAccountTable_INC] = "T_INC";
        m_pConfigName[eAccountTable_User] = "T_UserInfo";
        m_pConfigName[eServerTable_INC] = "T_INC";
        m_pConfigName[eServerTable_Actor] = "T_ActorInfo";
        m_pConfigName[eServerTable_Guild] = "T_GuildInfo";
        m_pConfigName[eServerTable_Prop] = "T_PropInfo";
    }
    if(!m_spAsynDBC->Init(true))
    {
        MessageBoxA(GetTopWindow(NULL), "数据库初始化失败!", "Error!", MB_ICONERROR);
        ::TerminateProcess(GetCurrentProcess(), 0);
    }
    ///这个登录过程主要是连接mongo和认证,然后就是保证一些表的存在,数据库现在主要分为账号数据库和角色数据库,这里用suerperamdmin登录,其他数据库也能使用了
    if(!m_spAsynDBC->Login(strDBIP.c_str(), 27017, ShuiHu::eServerDB_AoShiQianXiong, "SuperAdmin", "123456"))
    {
        MessageBoxA(GetTopWindow(NULL), "数据库连接失败!", "Error!", MB_ICONERROR);
        ::TerminateProcess(GetCurrentProcess(), 0);
    }
    ///在ui上显示数据库线程id方便压测的
    OnThreadId(m_spAsynDBC->GetThrID(), L"数据库");

    ///对于长时间没有收到心跳包的客户端会被放入队列中,到时会释放,其实这个没咋看
    I_TimerFactory* pTimeFactory = NEW(TimerFactory);
    SetPlug("TimerFactory", pTimeFactory);
    m_FreeQueueTimer.reset(pTimeFactory->createTimer());
    m_FreeQueueTimer->regTimer(std::bind(&GameServer::FreeQueueTimer, this));
    m_FreeQueueTimer->setInterval(30 * 1000);//(30 * 1000);
    m_FreeQueueTimer->start();

    ///定时保存帮会信息,1min
    m_SaveGuildInfoTimer.reset(pTimeFactory->createTimer());
    m_SaveGuildInfoTimer->regTimer(std::bind(&DBSaveTiming::OnSaveGuildInfo, &m_DBSaveTiming));
    m_SaveGuildInfoTimer->setInterval(1 * 60 * 1000);

    ///定时保存道具信息,从道具管理器里面读取,然后保存到数据库,是整个服务器的道具定时存储
    m_SavePropInfoTimer.reset(pTimeFactory->createTimer());
    m_SavePropInfoTimer->regTimer(std::bind(&DBSaveTiming::OnSavePropInfo, &m_DBSaveTiming));
    m_SavePropInfoTimer->setInterval(1 * 60 * 1000);

    ///添加DataLayer单例好像gamemap里面也会用到,最后被废弃了,随后看看
    m_spDataLayer = NEWSP(DataLayer);
    add_singleton("DataLayer", m_spDataLayer.get());
    //m_spDataLayer = NEWSP(GatwayData);

    ///网络初始化,就是双向的共享内存的初始化
    if(!m_spDataLayer->Init())
    {
        Plug::PlugMessageBox(L"初始化网络失败!");
        ::TerminateProcess(::GetCurrentProcess(), 0);
    }

    ShareInit(m_spDataLayer.get());
    m_DBSaveTiming.SetAsynDBCPtr(m_spAsynDBC);
    m_DBSaveTiming.SetPropMgrPtr(m_spPropManager);
    m_DBSaveTiming.SetGuildOptPtr(m_spGuildOpt);
    //获取帮会信息
    m_fnGetGuildInfo = std::bind(&GameServer::ProcessGetGuildInfo, this, ph::_1, ph::_2);
    m_spAsynDBC->GetGuildInfos(&m_fnGetGuildInfo);
    //道具信息
    m_funGetUserProp = std::bind(&GameServer::ProcessGetPropInfo, this, ph::_1, ph::_2);
    m_spAsynDBC->GetPropInfos(&m_funGetUserProp);

    m_LiveMgr.m_fnTimeOutDisconnect = std::bind(&GameServer::TimeOutDisconnect, this, ph::_1);
    m_LiveMgr.Init(GetMaxGcNumb());

    m_vecChannel.resize(GetMaxGcNumb());
    m_spThread.reset(new std::thread(std::bind(&GameServer::ProcessThread, this)));//创建一个线程,就是常说的GS线程,其实很多工作都是在这个线程里面做的
    OnThreadId(m_spThread->get_id(), L"GS线程");
}
//可以看出主线程
void Share::ShareInit(I_DataLayer* data_layer)//share是管理所有地图信息的,非常重要
{
    // 加载xls表
    if(!LoadnBodyId())
        Plug::PlugMessageBox("加载nBodyID表失败啊!");//三种职业,两种性别,nbodyid大概就代表地图资源
    if(!LoadLevelInfo())
        Plug::PlugMessageBox("加载角色等级信息失败!");//三种职业,71个等级的等级信息
    if(!LoadMapData())
        Plug::PlugMessageBox("加载地图数据失败!");//现在就有7张地图

    /*地图数量*/

    for(auto itMap : m_mapDataTable)
    {
        auto& pMap = m_mapMap[itMap.first] = NEW(Map);//m_mapMap是地图id对应一个地图指针信息
        pMap->Init(GetMaxGcNumb(), itMap.second.map_path.c_str());//地图的初始化
        pMap->m_fnGetLevelInfo = std::bind(&Share::TGetLevelInfo, this, ph::_1, ph::_2, ph::_3);

        pMap->m_nMapId = itMap.first;
        std::wstring name = L"地图";
        name += boost::lexical_cast<std::wstring>(pMap->m_nMapId);
        OnThreadId(pMap->GetThreadId(), name); //获取线程ID
    }

    m_pDataLayer = data_layer;
    //初始化 跨地图操作模块
    InitAcrossMapOpt();
    InitAcrossManager();
}

void Map::Init(int max_gc_numb,  const char* res_path)
{
    m_pLog = GetPlug(Log);//全局log单例
    msg_assert(m_pLog);

    m_vecPlayerChannel.resize(max_gc_numb);//m_vecPlayerChannel代表了一个地图上的所有玩家

    InitTimer();//map里面各种定时器的初始化
    InitOpt();//主要是地图内的一些操作,帮会,组队,关系,交易,npc交互,将这给些给分开有利于模块的独立
    InitMapInfoXml(res_path);//主要是地图的加载,块的划分,格子,2d人物通知都是用的格子,听说3d用的九宫格,只是听说
    InitPropXml();//道具信息的读取
    InitOrnamemtal();//这个不知干啥的
    InitMonsterTypeInfoTable();//怪物信息记载
    InitRegions();//区域的加载(安全区,战斗区)
    InitSkillLevelInfoTable();//技能等级信息
    InitMonsterDropRuleTable();//怪物掉落
    InitPlayerDropRuleTable();//人物掉落
    InitPetArrributeTable();//宠物属性
    InitSkillRestrictInfoTable();//限制技能读取

    InitSkillScript();//技能脚本
    InitMission();//任务
    InitMgr();//管理加载

    Start();//map线程启动
}
时间: 2024-08-03 13:53:40

GS初始化的相关文章

共享内存初始化

现在就来看看共享内存的初始化(过程是非常复杂的,也看了好多次) 1.内存池(其实这个也是放到共享内存里面) { 其中包括小,中,大三种模式,就以小举个例子 1.是否初始化m_镜像,表示2是否初始化, 2.托管内存队列:就是把shareDataEx类型的对象填充到托管的内存队列中 3.内存池:针对内存池分配的内存,这个应该和托管的队列是有联系的 } 进程锁:boost进程锁 共享内存:真正交互的是这个内存,到时细看下,这个和内存池是怎么交互的 m_a2b--->GS->NET(名字叫"

GS LiveMgr心跳管理类

struct LiveMgr { private: int m_nCount; ///< 管理数量 std::vector<int> m_vecChannels; ///< 所有channel std::shared_ptr<I_Timer> m_spTimer; ///< 定时器 public: std::function<void(int channel)> m_fnTimeOutDisconnect; void Init(int nMaxGcNu

linux内核设计的艺术-开始执行main函数

为了执行linux内的C语言main函数,上一篇讲到了,为了从汇编语言环境跳转到C语言环境下执行,将CPU工作模式从16位转变到32位模式(C语言是32位的),并且重新建立了GDT与IDT,但是此时GDT和IDT中并没有内容,所以不能进行内存寻址与中断,接下来就是初始化GDT和IDT了. 进入32位模式后,寄存器也将变为32位寄存器,下面的汇编语法和之前的intel汇编有些不同,为AT&T汇编,至于差别不在赘述. Head.S startup_32: //重设段寄存器内容 movl $0x10,

GS(道具,帮会)定时存储

//最近数据库存储做了重大改变,数据库内部的回头再说,先看看GS这边的 1.现在感觉数据库的状态将请求包放入命令队列中,以前是全部放进去,这样让其他的数据库操作不会随着数据库定时器而变慢,GS线程去驱动,一分钟不太可能还存不完 2.差异更新,GS只获取更改了的记录,这样不用每次都把全部的记录都放进去,这个过程是数据库改观不少 外面搞个mgr,内部使用可以重用的模板类,感觉是比之前封装的要好,但复杂度也上去了 m_spSaveOptMgr.reset(new SaveOptMgr(m_spAsyn

服务器打开共享内存的初始化

服务器共享内存以及客户端打开服务器获得通知过程 打开GS就会进行共享内存的初始化,过程很复杂,看了很多次,今天看的时候终于了解了大概了 bool DataLayer::init() { int pid = GetCurrentProcessId(); auto path = Plug::GetCurrentPath(); path += L"pid.txt"; auto file = _wfopen(path.c_str(), L"wb"); char buf[10

GS与MS之间通信

GS与MS之间通信 注意GS与MS是两个线程,现在是每个map一个线程,他们之间是内部协议进行通信的,那既然是两个线程那如何通信呢,看了net进程通信这个就比较简单了 举个例子 m_pMap->Gs2MsData(gs2ms_add_player, m_nChannelId, (void*)&rActorEx, sizeof(rActorEx));//发送玩家上线包 void Map::Gs2MsData(int cmd, int channel_id, void* data, int le

GS发包到MS

GS发包到MS(GS,MS包交互过程) 例:人物上线 首先看看其实如何确定是哪张地图的 数据库首先只保存一个mapid 在share初始化的时候已经初始化了所有map,并保存了map的指针信息,其key就是mapid if(rActorEx.GetMapID() <= 0) rActorEx.SetMapID(1009); int mapID = rActorEx.GetMapID(); rActorEx.m_nBodyID = m_pShare->TGetnBodyId(rActorEx.G

Linux内核源代码情景分析-系统初始化

我们跳过boot,setup,直接来到head代码,内核映像的起点是stext,也是_stext,引导和解压缩以后的整个映像放在内存从0x100000即1MB开始的区间.CPU执行内核映像的入口startup_32就在内核映像开头的地方,因此其物理地址也是0x100000. 然而,在正常运行时整个内核映像都应该在系统空间中,系统空间的虚拟地址与物理地址间有个固定的位移,这就是0xC0000000,即3GB.所以,在连接内核映像时已经在所有的符号地址加了一个偏移量0xC0000000,这样star

OD: Windows Security Techniques &amp; GS Bypassing via C++ Virtual Function

Windows 安全机制 漏洞的万源之本在于冯诺依曼设计的计算机模型没有将代码和数据进行区分——病毒.加壳脱壳.shellcode.跨站脚本攻击.SQL注入等都是因为计算机把数据和代码混淆这一天然缺陷而造成的. Windows XP SP2 之前的系统致力于系统稳定性,忽略安全性:之后的 Windows 系统系统加入了独特的安全性设计: 1. GS 编译技术:函数返回地址之前加入了 Security Cookie,返回之前首先检测 cookie 是否正确,栈溢出难度增加. 2. 增加了对 S.E