Wow世界中的地图有两种:场景地图和副本地图.
场景地图只有一个实体,一般比较大。如东部王国、卡里姆多和外域分别是一个整张的地图(各个地图间传送的港口也是单独的地图)。
副本地图是同样的地图场景,但却有多个不同的实体。比如各种副本和战场,都属于副本地图。
InstanceMgr:将负责整个世界的地图创建和保持。每个地图(以及每个副本)将以MapMgr的形式创建,MapMgr主要负责地图中玩家和npc怪物的逻辑管理和运算。世界地图的MapMgr放在m_singleMaps中,副本的MapMgr则在每个Instance:: m_mapMgr中(也就是说每个副本都会有一个MapMgr,但是当没有副本存在时也不会有副本的MapMgr。而世界地图则固定有一个MapMgr)。 Map中的_terrain则加载了地图文件中的地形信息,包括水体深度和地面高度信息等。而Map也将主要负责地图信息和地形信息的管理。下面分别描述:
注:如上图,MapMgr派生自CThread,也就是说每个地图和副本都会有一个线程。这样使不同的地图的运算分离,也能充分利用多cpu的性能,但是当用户量大的时候可能会产生大量的线程,不太确定这种方法的优劣。不过如果线程在可以承受的范围内的话,这样也可以避免一个玩家操作卡时导致整个服务器都卡的情况,至多也就是当前地图副本的玩家卡。
MapMgr:
MapMgr派生自CThread和CellHandler<MapCell>,在创建时会加入到线程池中运行,当终止线程时,MapMgr会删除自己释放内存。父类CellHandler是个模板类,把地图分为多个单元格MapCell,将地图上的npc和玩家划分为多个小子集分别处理.当当前单元格和相邻的单元个都没有玩家的时候,会将单元格设置一个
延迟unload事件:
sEventMgr.AddEvent(_mapmgr, &MapMgr::UnloadCell,(uint32)_x,(uint32)_y,MAKE_CELL_EVENT(_x,_y),sWorld.map_unload_time * 1000,1,0);
在一定时间后如果还没有玩家进入就unload该单元格以及其中的npc,以节省资源。
MapMgr则在Do函数(实际上是运行在run()函数执行线程中)中循环调用_PerformObjectDuties()函数,以间隔时间刷新该地图中所有对象(npc,宠物,玩家,gameObject,session等)的状态和逻辑运算。
Map:
成员TerrainMgr同样将地图的地形分为单元格(成员CellInformation),实现了地形的动态加载和卸载(这个与MapCell的加载和卸载是一起的,但是没有设置延时,是立即释放的。当玩家在两个格子间频繁切换时会影响性能。)
Map本身则负责了怪物刷新点(spawns)的载入和维护管理。
InstanceMgr:
InstanceMgr初始化时将为每一个地图创建一个Map,为每一个非副本地图创建一个MapMgr:
void InstanceMgr::_CreateMap(uint32 mapid)
{
if( mapid >= NUM_MAPS )
return;
MapInfo * inf;
inf = WorldMapInfoStorage.LookupEntry(mapid);
if(inf==NULL)
return;
if(m_maps[mapid]!=NULL)
return;
//初始化一个map,并将指针放入数组
m_maps[mapid] = new Map(mapid, inf);
if(inf->type == INSTANCE_NULL)
{
//如果不是副本地图则创建世界地图副本(实际的实现是为其创建一个MapMgr并放入线程池执行)
_CreateInstance(mapid, GenerateInstanceID());
}
}
副本的MapMgr将在创建副本对象时动态创建,
//跟创建世界地图副本的函数是不同的两个重载函数
MapMgr * InstanceMgr::_CreateInstance(Instance * in)
{
in->m_mapMgr = new MapMgr(m_maps[in->m_mapId], in->m_mapId, in->m_instanceId);
in->m_mapMgr->pInstance = in;
in->m_mapMgr->iInstanceMode = in->m_difficulty;
in->m_mapMgr->InactiveMoveTime = 60+UNIXTIME;
ThreadPool.ExecuteTask(in->m_mapMgr);
return in->m_mapMgr;
}
Instance的创建在InstanceMgr::GetInstance(Object* obj)时动态创建,当instance绑定到一个MapMgr以后,就以MapMgr的形式单独运行,直到_DeleteInstance时,将设置MapMgr终止线程。