游戏服务器之分线处理处理的是游戏服务器在多场景服务器和每个场景服务器下分多场景对象的情况下的角色跳线和进入分线场景的应用的处理。
设计上:
(1)配置分线信息到静态表,服务器启动时加载并创建场景对象。
(2)每生产一个场景对象(包括分线的场景对象)就注册到社会关系服务器。
(3)进入场景或者跳线时,则查询场景服务器中的分线信息,然后选择在当前服务器下切换场景对象还是切换场景服务器。
1、场景配置处理
场景id是由服务器id和地图id哈希组成的。
地图id配置规则,含分线的地图id命名为NewMapID(由地图id(mapID)和分线号组成),否则没有分线的地图就只是使用地图id(mapID)。
每个NewMapID只能配到一个serverId下。然后根据地图id和分线号就可以找到应该是要切到哪个服务器(是要跨场景进程还是就是在本进程里面换换地图)。
地图id规则上:line 节点下,NewMapID由(500+mapID*10+分线号)组成,新增分线要按这种格式,分线数量要为双数.
格式上:line 节点下,mapID为需要分线的基础ID , 在下一层节点 NewMapID 为映射的分线地图ID .
<line mapID="1" >
<info serverId="21" NewMapID="511"/>
<info serverId="22" NewMapID="512"/>
<info serverId="21" NewMapID="513"/>
<info serverId="22" NewMapID="514"/>
<info serverId="21" NewMapID="515"/>
<info serverId="22" NewMapID="516"/>
</line>
<line mapID="2" >
<info serverId="21" NewMapID="521"/>
<info serverId="22" NewMapID="522"/>
<info serverId="21" NewMapID="523"/>
<info serverId="22" NewMapID="524"/>
</line>
<line mapID="3" >
<info serverId="21" NewMapID="531"/>
<info serverId="22" NewMapID="532"/>
<info serverId="21" NewMapID="533"/>
<info serverId="22" NewMapID="534"/>
</line>
<line mapID="4" >
<info serverId="21" NewMapID="541"/>
<info serverId="22" NewMapID="542"/>
</line>
2、分线信息应用
在服务器启动时,根据分线信息容器创建场景对象。每创建一个场景服务器(或者副本服务器)的一个场景对象,会注册场景对象(地图id、服务器id、场景名称、场景对象类型)到社会关系服务器,以便作为角色切换场景服务器的参考。
在请求跳线时,根据基础地图id、线号和分线信息(容器)可查询到是否是分线场景以及其场景id 。再根据场景id判断是否是在当前场景服务器,而选择是否需要切换服务器或者在当前服务器下切换场景。
至于在当前场景进程的切换场景,主要是
1、更新当前场景状态(如特殊场景有buff)
2、更新屏索引
3、更新角色坐标
4、同步刷新社会关系服务器用户场景
5、同步网关屏索引
6、重新加载玩家个人信息给队友
7、特殊的副本就需要进行特殊的限制(如不能摆摊交易、不能组队、设置pk模式)等
8、如果是普通场景发送分线信息
至于需要切换场景进程的切换场景,除了以上的一些步骤还要的步骤是角色的存档和读档(可优化成直接转移角色内存数据到另一个场景服务器)。
(在另一篇文章游戏服务器之跨场景进程有一些分析:http://blog.youkuaiyun.com/chenjiayi_yun/article/details/18416543)
(2) 跳转场景应用
场景id规则:(使每个服务器的场景id都不一样)
//场景id哈希(顺便提一下,除了网络字节序是大端顺序,程序逻辑环境一般是小端顺序,也就是数据的高位字节存放在地址的高位 低位字节存放在地址低位,在这里就是serverid在高位也就是高地址,就算这样不怎么影响哈希结果,但对有些特殊的需要排序的情景下还是要注意下哈希的顺序)
inline uint32 sceneid_hash(const uint16& serverid, const uint16 &mapid)//mapid包括分线的新地图id和不分线的地图id
{
return (serverid<< 16) + mapid;
}
客户端发来切线的请求。调用角色的换线函数,查找需求场景。
场景进程的场景管理器(g_scene_mgr),根据地图的id和分线的号可以获取需求的场景(这些在配置文件里面配置),如果该场景和在本场景进程中可以找得到,
则只是需要在本进程中切换下场景,否则就需要跨场景服务器了。
bool scene_player::changeLineByNum( uint8 lineNum )
{
debug_log("[%s,%u]请求切线",this->name,this->id);
if(this->getEntryState() == SceneObject_Death)//限制切换场景时的角色状态
{
scene_chat::send_sys(this,"角色死亡不能切线");
return false;
}
if (lastChangeLineTime + 10 > main_logic_thread::currentTime.sec())//限制切线频率
{
g_player_mgr.sendTipsToUser(this->id,TIPS_TYPE_CENTER,"切线过于频繁,请稍候再试");
return false;
}
lastChangeLineTime = main_logic_thread::currentTime.sec();
uint32 sceneid = g_scene_mgr.getSceneIdByLineNum(this->scene->map->id,lineNum);
if (sceneid && sceneid != this->scene->id)
{
Scene *pScene = g_scene_mgr.get_scene_by_id(sceneid);
if (pScene)//本服务器内切换场景
{
nPos intoPos = this->getPos();
return changeScene(pScene, intoPos);
}
else//切换场景服务器切换场景
{
return changeServer(sceneid,this->getPos().x,this->getPos().y);
}
}
return false;
}
至此,游戏服务器之分线处理大致上说完了。