服务端主要由三大块组成,数据库、服务端逻辑、脚本。数据库用的MySQL,这里不是很关键暂且不说。脚本有自己的脚本引擎,简单的任务、战斗等都可以通过数据库配置相应条目来完成,复杂的战斗AI等在脚本库中由C++直接写成,这个脚本库是要被编译为机器代码的,执行效率相当高效,例如巫妖王的战斗比较复杂就用C++写,其它简单的就配置在数据库中由脚本引擎来驱动执行。AZ服务端是一个多线程、逻辑单线程的服务端。每个线程内部都采用循环结构,主线程启动后将创建多个工作线程,主要包括负责游戏世界运作的核心线程,具有处理用户请求,执行定时器的能力。其它几个工作线程还有网络Io,该线程启动后其内部将使用线程池进行网络Io操作,不间断地接收数据包,并存储到相关玩家的消息队列中,由世界线程进行处理,其它几个工作线程先不讨论,看mangos的源代码.务端启动后这些线程将永不停息地工作。世界线程是服务器的核心,负责处理所有玩家操作请求,定时器、AI等。以下是世界线程启动后执行的代码:
/// Heartbeat for the Worldvoid WorldRunnable::run()
///- Init new SQL thread for the world database
WorldDatabase.ThreadStart(); // let thread do safe mySQL requests (one connection call enough) sWorld.InitResultQueue();
uint32 realCurrTime = 0;
uint32 realPrevTime = WorldTimer::tick();
uint32 prevSleepTime = 0; // used for balanced full tick time length near WORLD_SLEEP_CONST
///- While we have not World::m_stopEvent, update the world
展开全文
while (!World::IsStopped())
++World::m_worldLoopCounter;
realCurrTime = WorldTimer::getMSTime();
uint32 diff = WorldTimer::tick();
sWorld.Update(diff);
realPrevTime = realCurrTime;
// diff (D0) include time of previous sleep (d0) + tick time (t0)
// we want that next d1 + t1 == WORLD_SLEEP_CONST
// we can't know next t1 and then can use (t0 + d1) == WORLD_SLEEP_CONST requirement
// d1 = WORLD_SLEEP_CONST - t0 = WORLD_SLEEP_CONST - (D0 - d0) = WORLD_SLEEP_CONST + d0 - D0
if (diff <= WORLD_SLEEP_CONST + prevSleepTime)
prevSleepTime = WORLD_SLEEP_CONST + prevSleepTime - diff;
ACE_Based::Thread::Sleep(prevSleepTime);
else
prevSleepTime = 0;
#ifdef WIN32
if (m_ServiceStatus == 0) World::StopNow(SHUTDOWN_EXIT_CODE);
while (m_ServiceStatus == 2) Sleep(1000);#endif
sWorld.CleanupsBeforeStop();
sWorldSocketMgr->StopNetwork();
MapManager::Instance().UnloadAll(); // unload all grids (including locked in memory)
///- End the database thread
WorldDatabase.ThreadEnd(); // free mySQL thread resources
这里先作一下说明,这是世界线程的根循环结构,在while(!World::IsStopped())内部只有一个核心函数调用,其他都是一些控制更新时间之类的代码,不用太关注:
sWorld.Update(diff);
sWorld是单一实例的World对象,它代表了整个游戏世界,和多数MMORPG一样,启动后进入根循环,在运行内部一直调用更新整个游戏世界的Update函数,服务端不停的Update游戏世界,每次Update能在100毫秒内完成,则客户端会感到非常流畅。在根循环退出后,清理服务器相关资源,线程结束被回收。
到这里仅仅需要关注一个函数了,就是World的Update方法内部到底在干什么?
void World::Update(uint32 diff)
///- Update the different timers
for (int i = 0; i < WUPDATE_COUNT; ++i)
if (m_timers[i].GetCurrent() >= 0)
m_timers[i].Update(diff);
else
m_timers[i].SetCurrent(0);
///- Update the game time and check for shutdown time _UpdateGameTime();
///-Update mass mailer tasks if any sMassMailMgr.Update();
/// Handle daily quests reset time
if (m_gameTime > m_NextDailyQuestReset)
ResetDailyQuests();
/// Handle weekly quests reset time
if (m_gameTime > m_NextWeeklyQuestReset)
ResetWeeklyQuests();
/// Handle monthly quests reset time
if (m_gameTime > m_NextMonthlyQuestReset)
ResetMonthlyQuests();
/// Handle monthly quests reset time
if (m_gameTime > m_NextCurrencyReset)
ResetCurrencyWeekCounts();
/// <ul><li> Handle auctions when the timer has passed
if (m_timers[WUPDATE_AUCTIONS].Passed())
m_timers[WUPDATE_AUCTIONS].Reset();
///- Update mails (return old mails with item, or delete them)
//(tested... works on win)
if (++mail_timer > mail_timer_expires)
mail_timer = 0;
sObjectMgr.ReturnOrDeleteOldMails(true);
///- Handle expired auctions sAuctionMgr.Update();
/// <li> Handle AHBot operations
if (m_timers[WUPDATE_AHBOT].Passed())
sAuctionBot.Update();
m_timers[WUPDATE_AHBOT].Reset();
/// <li> Handle session updat
姓名:
年龄:
电话: