http://hi.baidu.com/zyy503950958/home
下载和安装msysgit,用于代码管理。我使用的是Git-1.6.5.1-preview20091022.exe。
14. 如果要用PerfHUB来调试,可以二进制打开wow.exe,把其中的53 52 6A 01 6A 00 50 8B 41 40改成53 52 6A 02 6A 01 50 8B 41 40后另存。具体可以参考用PerfHUD来调试商业游戏。改完后,托exe到PerfHUB的图标上就ok了。
运行Mangos (运行Mangos一节过期,是以前我针对国服3.1.3版本进行的安装配置)
|
Mangos代码阅读 Mangos有13个工程。 使用了4个外部工具库,分别是:
Mangos的实现分为:登录服务器(realmd)和世界服务器(mangosd+game)。realmd和mangos共用了Mangos公共库(shared)。 工程shared 提供了通用功能,包括了数据库的封装类,实现了对MySql的访问,同样,我们可以编写派生类来支持其他的数据库。 工程script 提供了脚本接口,并实现了简单的几个脚本,封装为DLL,提供给game使用,具体可参考:MaNGOS脚本接口。 通过使用不同的脚本DLL来替换Mangos中的AI实现,可以让game具有更强的AI。ScriptDev2 就是一个这样的库。ScriptDev2 is a replacement for the Script Library that comes with MaNGOS( http://www.getmangos.com ) written in C++ and is compatible with Windows and Linux. It provides scripts for NPCs, Boss events, and Items currently. Once ScriptDev2 is compiled it is automatically run by MaNGOS on server startup. 工程mangosd mangos是世界服务器的管理器,负责初始化工作和启动世界服务器各层的线程,这些工作主要是由类Master来实现。具体是:
mangosd的线程总共有(1+3+1+1+1+2 +1 =10)10个线程。
工程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的状态。
登录处理: user登录到realm server进行身份认证,并选择登录上哪个mangos server。user登录到mangos server后,将不再和realm server交互。 参考: Wow 服务器解析 |
工程game
game:是Mangos的核心代码,网络层和逻辑层代码(采用了ACE反应器(Reactor)模式)
网络层:
逻辑层:
game中的定时器有:
/// Timers for different object refresh rates
enum WorldTimers
{
WUPDATE_OBJECTS = 0, // 间隔为0
WUPDATE_SESSIONS = 1, // 间隔为0
WUPDATE_AUCTIONS = 2,// 间隔为60秒
WUPDATE_WEATHERS = 3,// 间隔为1秒
WUPDATE_UPTIME = 4,
WUPDATE_CORPSES = 5,
WUPDATE_EVENTS = 6,
WUPDATE_COUNT = 7
};
game中的管理器有:
对象类层次
对象的类层次如下,所有的Object都由ObjectMgr进行管理。ObjectMgr以GUID方式,管理了characters,creature,item_instance,gameobject,auctionhouse,mail,item_text,corpse,arena_team,character_equipmentsets。
// indexes of BattlemasterList.dbc
enum BattleGroundTypeId
{
BATTLEGROUND_TYPE_NONE = 0,
BATTLEGROUND_AV = 1,
BATTLEGROUND_WS = 2,
BATTLEGROUND_AB = 3,
BATTLEGROUND_NA = 4,
BATTLEGROUND_BE = 5,
BATTLEGROUND_AA = 6,
BATTLEGROUND_EY = 7,
BATTLEGROUND_RL = 8,
BATTLEGROUND_SA = 9,
BATTLEGROUND_DS = 10,
BATTLEGROUND_RV = 11,
BATTLEGROUND_IC = 30,
BATTLEGROUND_ABG = 32
};
战场代码名字解释
AB - Arathi Basin ALX
AV - Alterac Valley AS
Ey - Eye of the Storm FB
BE - Blade Edge arena 刀锋山竞技场
AA - dunno :]
RL - Ruins of Lordareon arena 洛丹伦废墟竞技场
NA - Nagrand Arena 纳格兰竞技场
Player状态
/// Player state
enum SessionStatus
{
STATUS_AUTHED = 0, ///< Player authenticated (_player==NULL, m_playerRecentlyLogout = false or will be reset before handler call, m_GUID have garbage)
STATUS_LOGGEDIN, ///< Player in game (_player!=NULL, m_GUID == _player->GetGUID(), inWorld())
STATUS_TRANSFER, ///< Player transferring to another map (_player!=NULL, m_GUID == _player->GetGUID(), !inWorld())
STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT, ///< _player!= NULL or _player==NULL && m_playerRecentlyLogout, m_GUID store last _player guid)
STATUS_NEVER ///< Opcode not accepted from client (deprecated or server side only)
};
生物状态
enum DeathState
{
ALIVE = 0,
JUST_DIED = 1,
CORPSE = 2,
DEAD = 3,
JUST_ALIVED = 4,
DEAD_FALLING= 5
};
玩家登陆
服务器端在连接打开后,会发SMSG_AUTH_CHALLENGE到客户端。客户端从服务器端发送回来的种子和 SRP6 数据中产生随机种子,生成 SHA1 字符串,用这些数据生成 CMSG_AUITH_SESSION 数据包,发送给服务端。这个过程是没有经过加密的。
packet结构
SMSG_AUTH_SESSION 是client packet有一个头部(ClientPktHeader),后面是数据块。
SMSG_AUTH_RESPONSE 是server packet有一个头部(ServicePktHeader),后面是数据块。
SMSG_AUTH_RESPONSE 的包组织
SMSG_AUTH_RESPONSE 的opcode是01EE,ByteBuffer大小为1 + 4 + 1 + 4 + 1=11。一个SMSG_AUTH_RESPONSE 的数据如下:
在构造了SMSG_AUTH_RESPONSE packet后,WorldSocket::SendPacket会根据SMSG_AUTH_RESPONSE packet构造出一个ServerPktHeader,并对ServerPktHeader中的数据header进行加密发送。加密采用m_Crypt.EncryptSend ((uint8*)header.header, header.getHeaderLength());
ServerPktHeader |
WorldSocket::handle_input_header会对从客户端接收来的数据进行解密,解密采用m_Crypt.DecryptRecv ((uint8*) m_Header.rd_ptr (), sizeof (ClientPktHeader));
角色枚举
角色创建 角色的初始化装备在CharStartOutfit.dbc 角色的创建和选择的设置都在 ChrRaces.dbc 角色的创建属性都在Playercreateinfo,包括出生地和出生属性。 playercreateinfo_item表是创建一个新人物时,人物默认带的所有Item的表 playercreateinfo_spell表是创建一个新人物时,人物默认带的所有Spell的表 角色删除 角色进入游戏 发出的消息有: SMSG_SET_PROFICIENCY SMSG_CRITERIA_UPDATE MSG_DUGEON_DIFFICULTY SMSG_LOGIN_VERIFY_WORLD SMSG_ACCOUNT_DATA_TIMES SMSG_FEATURE_SYSTEM_STATUS SMSG_MOTD SMSG_LEARNED_DANCE_MOVES SMSG_BIND_POINT_UPDATE SMSG_TALENTS_INFO SMSG_INSTANCE_DIFFICULTY SMSG_INITIAL_SPELLS SMSG_UNLEARN_SPELLS SMSG_ACTION_BUTTONS SMSG_ACTION_FACTIONS SMSG_INIT_WORLD_STATES SMSG_EQUIPMENT_SET_LIST SMSG_ALL_ACHIEVEMENT_DATA SMSG_LOGIN_SETTIMESPEED SMSG_TRIGGER_CINEMA SMSG_COMPRESSED_UPDATE_OBJECT: 会发送Monster数据 SMSG_MONSTER_MOVE:会发送Monster的移动数据 SMSG_INIT_WORLD_STATES SMSG_WEATHER SMSG_TIME_SYNC_REQUEST SMSG_WEATHER SMSG_SPELL_GO SMSG_AURA_UPDATE_ALL SMSG_UPDATE_ACCOUNT_COMPLETE SMSG_PLYAED_TIME SMSG_NAME_QUERY_RESPONSE SMSG_RAID_INSTANCE_INFO SMSG_QUERY_TIME_RESPONSE SMSG_GMTICKET_GETTICKET SMSG_QUERY_TIME_RESPONSE SMSG_QUERY_NEXT_MAIL_TIME SMSG_CALENDAR_SEND_NUM_PENDING SMSG_WORLD_STATE_UI_TIMER_UPDATE SMSG_STANDSTATE_UPDATE // 多个 SMSG_CHANNEL_NOTIFY // 多个 SMSG_USERLIST_ADD // 多个
看上面的Mangos的Call Stack,可以明白角色进入游戏场景时,Mangos是如何处理的。具体如下: WorldSession::HandlePlayerLogin:
Map::Add(Player *player) 非常重要。可以知道Mangos是如何按Cell加载地图数据,包括地图上的物品,生物的。WOW客户端会把一些Cell数据缓冲到World of Warcraft\Cache\WDB中。 Map::Add(Player *player) bool Map::Add(Player *player) // update player state for other player and visa-versa SendInitSelf(player); // 把Player信息(transport,EquipmentSlots信息,BankBagSlots信息,KeyRingSlots信息和CurrencyTokenSlots等)以SMSG_UPDATE_OBJECT发送到客户端 UpdatePlayerVisibility(player,cell,p); AddNotifier(player,cell,p); 函数LoadMapAndVMap:按GRID加载map & vmap。 类ObjectGridLoader:按GRID加载Grid上的Objects。在ObjectGridLoader::LoadN中,会生成GridLoader 看CellObjectGuids结构 struct CellObjectGuids 可以知道在一个cell中管理了该cell中的所有creatures和gameobjects和corpses。ObjectMgr中的MapObjectGuids mMapObjectGuids就是按照Cell管理所有的所有creatures和gameobjects和corpses。 在ObjectMgr中的mMapObjectGuids结构是: void Map::SendInitSelf( Player * player ) UpdateData data; // attach to player data current transport data // build data for self presence in world at own client (one time for map) // build other passengers at transport also (they always visible and marked as visible and will not send at visibility update at add to map WorldPacket packet; void Map::UpdateObjectsVisibilityFor( Player* player, Cell cell, CellPair cellpair ) cell.data.Part.reserved = ALL_DISTRICT; // send data void Creature::SendMonsterMoveWithSpeedToCurrentDestination(Player* player) void Unit::SendMonsterMoveWithSpeed(float x, float y, float z, uint32 transitTime, Player* player) 怪物的移动 SMSG_MONSTER_MOVE InstanceMap:Dungeon Instance Maps BattleGroundMap:Battleground Instance Maps
一个Map的Grid有4个状态,分别是:
Map::Update |
WDB文件 (参考:http://www.sourcepeek.com/wiki/WDB_Files)
参考:
|