5.1 创建角色
FairySystem.exe!Fairy::LogicModel::initModel
FairySystem.exe!Fairy::LogicModelManager::createLogicModel
FairySystem.exe!Fairy::LogicModelManager::createLogicModel
FairySystem.exe!Fairy::LogicModelObject::_createLogicModel
FairySystem.exe!Fairy::LogicModelObject::setLogicModelName
FairySystem.exe!Fairy::`anonymous namespace'::LogicModelNameCmd::doSet
FairySystem.exe!Fairy::PropertyInterface::setProperty
FairySystem.exe!wWinMain
6.1 Class view
class CEventSystem : public tEventSystem
class CActionItem : public tActionItem
- CActionItem
- CActionItem_ChangeSuit
- CActionItem_ChatMood
- CActionItem_Item
- CActionItem_LifeAbility
- CActionItem_MouseCmd_Exchange
- CActionItem_MouseCmd_Friend
- CActionItem_MouseCmd_Identify
- CActionItem_MouseCmd_Repair
- CActionItem_PetSkill
- CActionItem_Skill
名称 | 描述 | CActionItem_ChatMood | 操作管理器-聊天动作 | CActionItem_Item | 操作管理器-物品 | CActionItem_LifeAbility | 操作管理器-生活技能 | CActionItem_MouseCmd_Identify | 鉴定 | CActionItem_MouseCmd_Repair | 鼠标指令用于处理诸如鉴定,修理,加为好友等特殊鼠标状态 | CActionItem_PetSkill | 宠物技能 | CActionItem_Skill | 技能 | CActionItem_XinFa | 心法 |
6.2 事件定义
6.2.1 事件 ID总共 492 个事件,定义于文件 GameInterface\Include\Game\GIEventDefine.h
enum GAME_EVENT_ID
{
GE_APPLICATION_INITED, /// 游戏程序初始化
...
事件 ID 均以 GE_打头。
6.2.2 事件名
定义于文件game\Event\GMEventSystem.cpp。
EVENT_DEFINE g_GlobalEvent[] =
{
{ GE_APPLICATION_INITED, "APPLICATION_INITED", },
{ GE_ON_SCENE_TRANS, "ON_SCENE_TRANS", },
{ GE_ON_SERVER_TRANS, "ON_SERVER_TRANS", },
6.2.3 Event 结构
事件基本单元定义,此处重构为事件元 META_EVENT 更合适。
struct EVENT_DEFINE
{
typedef std::list< std::pair< FUNC_EVENT_HANDLE, UINT > > REGISTER_STRUCT;
GAME_EVENT_ID idEvent;
LPCTSTR szEvent;
BOOL delayProcess;
REGISTER_STRUCT listFuncNotify;
Event 结构包含了事件 ID、事件名、延迟处理标志、N 个处理过程。处理过程的定义如下:
typedef VOID (__stdcall* FUNC_EVENT_HANDLE)(const EVENT* pEvent, UINT dwOwnerData);
也即处理过程是返回值为空的,参数为 EVENT 和所有者 this(?未严格论证)指针的一个回调函数。
事件定义如下
struct EVENT
{
EVENT_DEFINE* pEventDef;
std::vector<STRING> vArg;
bool operator == (const EVENT& other);
};
事件包含了事件元、事件参数。
综上,事件、事件元、事件过程的关系为:事件是后者的组合。
6.2.4 事件初始化
搞了 2 个 map:
//通过事件名称检索表
std::map< STRING, EVENT_DEFINE* > m_mapEventIndex_AsName;
//通过事件ID检索表
std::map< GAME_EVENT_ID, EVENT_DEFINE* > m_mapEventIndex_AsID;
最终只是为了实现三角关系的勾结:事件 ID、事件名、事件元
6.3 注册事件
事件元是事件的中心,但是事件元不是天生的贵种,事件初始化虽然完成了所有事件的定义,也巩
固了三角关系,但是那只是一个空壳,没有事件处理过程,时间表什么也坐不了。注册事件这个方
法将时间表中的每一个事件元都绑定了一个处理过程。
// 注册事件处理函数
VOID CEventSystem::RegisterEventHandle(const STRING& nameEvent, FUNC_EVENT_HANDLE
funHandle, UINT uOwnerData)
{
EVENT_DEFINE* pEvent = m_mapEventIndex_AsName[nameEvent];
pEvent->listFuncNotify.push_back( std::make_pair(funHandle, uOwnerData) );
…
6.3.1 事件注册代码
一共 N 处事件注册
Client\UI_CEGUI\UIWindowMng.cpp
RegisterEventHandle( strEventName , _OnGameEvent , (DWORD)(DWORD_PTR)this )
Client\Game\Action\GMActionSystem.cpp
RegisterEventHandle("ON_SKILL_ACTIVE", _OnSkillActive)
Client\Game\DataPool\GMDataPool.cpp
RegisterEventHandle("UNIT_HP", _Skill_OnUpdatePlayerAttrib)
Client\Game\DataPool\GMDataPool.cpp
RegisterEventHandle("UNIT_MP", _Skill_OnUpdatePlayerAttrib)
Client\Game\DataPool\GMDataPool.cpp
RegisterEventHandle("UNIT_RAGE", _Skill_OnUpdatePlayerAttrib)
Client\Game\DataPool\GMDataPool.cpp
RegisterEventHandle("UNIT_EQUIP_WEAPON", _Skill_OnUpdatePlayerAttrib)
Client\Game\Engine\EngineInterface.cpp
RegisterEventHandle("VARIABLE_CHANGED", _OnVariableChangedEvent)
Client\Game\Interface\GMGameInterface.cpp
RegisterEventHandle("VARIABLE_CHANGED",
SCRIPT_SANDBOX::SystemSetup::_OnVariableChangedEvent)
Client\Game\Interface\GMInterface_Script_Talk.cpp
RegisterEventHandle("TIME_UPDATE", _SendTalkHelpMsg)
Client\Game\Interface\GMInterface_Script_Talk.cpp
RegisterEventHandle("VIEW_RESOLUTION_CHANGED", _HandleWindowSizeChange)
Client\Game\Sound\GMSoundSystem.cpp
RegisterEventHandle("VARIABLE_CHANGED", _OnVariableChangedEvent)
Client\Game\World\WorldManager.cpp
RegisterEventHandle("ON_SCENE_TRANS", _OnSceneTransEvent)
Client\Game\World\WorldManager.cpp
RegisterEventHandle("ON_SERVER_TRANS", _OnSceneTransEvent)
Client\Game\World\WorldManager.cpp
RegisterEventHandle("VARIABLE_CHANGED", _OnVariableChangedEvent)
INT CUIWindowItem::LUA_RegisterEvent(LuaPlus::LuaState* pState)
g_pEventSys->RegisterEventHandle( strEventName , _OnGameEvent ,
(DWORD)(DWORD_PTR)this );
VOID CActionSystem::Initial(VOID*)
// 注册关心的事件
// 技能开始使用
CEventSystem::GetMe()->RegisterEventHandle("ON_SKILL_ACTIVE", _OnSkillActive);
VOID CDataPool::Initial(VOID*)
CEventSystem::GetMe()->RegisterEventHandle("UNIT_HP", _Skill_OnUpdatePlayerAttrib);
CEventSystem::GetMe()->RegisterEventHandle("UNIT_MP", _Skill_OnUpdatePlayerAttrib);
CEventSystem::GetMe()->RegisterEventHandle("UNIT_RAGE",
_Skill_OnUpdatePlayerAttrib);
CEventSystem::GetMe()->RegisterEventHandle("UNIT_EQUIP_WEAPON",
_Skill_OnUpdatePlayerAttrib);
VOID CEngineInterface::Initial(VOID* pParam)
// 系统设置接口挂接变量控制系统
g_pEventSys->RegisterEventHandle("VARIABLE_CHANGED",_OnVariableChangedEvent);
CGameProcedure::s_pEventSystem->RegisterEventHandle("TIME_UPDATE",
VOID Talk::Initial()
// 注册时间事件回调函数
_SendTalkHelpMsg);
CGameProcedure::s_pEventSystem->RegisterEventHandle("VIEW_RESOLUTION_CHANGED",
_HandleWindowSizeChange);
VOID CSoundSystemFMod::Initial(VOID*)
// 挂接变量系统
CEventSystem::GetMe()->RegisterEventHandle("VARIABLE_CHANGED",
_OnVariableChangedEvent);
ON_SCENE_TRANS
VOID CWorldManager::Initial(VOID*)
// 注册事件处理
CEventSystem::GetMe()->RegisterEventHandle("ON_SCENE_TRANS", _OnSceneTransEvent);
CEventSystem::GetMe()->RegisterEventHandle("ON_SERVER_TRANS", _OnSceneTransEvent);
// 挂接变量系统
CEventSystem::GetMe()->RegisterEventHandle("VARIABLE_CHANGED",_OnVariableChangedEve
nt);
事件表
事件名称 | 处理函数 | 描述 | ON_SCENE_TRANS | CWorldManager::_OnSceneTransEvent | N/A | ON_SERVER_TRANS | CWorldManager::_OnSceneTransEvent | N/A | VARIABLE_CHANGED | CWorldManager::_OnVariableChangedEvent | 挂接变量系统 | VARIABLE_CHANGED | CSoundSystemFMod::_OnVariableChangedEvent | N/A | TIME_UPDATE | Talk::_SendTalkHelpMsg | 注册时间事件回调函数 | VIEW_RESOLUTION_CHANGED | Talk::_HandleWindowSizeChange | N/A | VARIABLE_CHANGED | SCRIPT_SANDBOX::SystemSetup::_OnVariableChangedEvent | 系统设置接口挂接变量控制系统 | VARIABLE_CHANGED | CEngineInterface::_OnVariableChangedEvent | 系统设置接口挂接变量控制系统 | UNIT_HP | CDataPool::_Skill_OnUpdatePlayerAttrib | N/A | UNIT_MP | CDataPool::_Skill_OnUpdatePlayerAttrib | N/A | UNIT_RAGE | CDataPool::_Skill_OnUpdatePlayerAttrib | N/A | UNIT_EQUIP_WEAPON | CDataPool::_Skill_OnUpdatePlayerAttrib | N/A | StrEventName | CUIWindowItem::_OnGameEvent | N/A |
6.3.2 扯淡
事件其实就是一个这样的结构
Struct Event
{
STRING name;
UINT id;
List handle;
}
绕来绕去,搞这么绕口,非常 c 的一种风格,难道是修修补补的产物?
6.3.3 事件队列
事件队列定义
//事件队列
std::list< EVENT > m_queueEvent;
//慢速处理队列, 每桢一个,防止过多的消息同时涌现
std::list< EVENT > m_delayQueueEvent;
UINT m_dwLastTickCount;
事件队列就是一个链表。定义了一个慢速处理队列。大概是为了实现和 ms 的 Send、Post 不同方式
发送消息一样的作用。
事件入队可以通过事件 ID 和事件名两种方式,当然最后都是填充 EVENT 结构并入队。
virtual VOID PushEvent(GAME_EVENT_ID id);
virtual VOID PushEvent(STRING& eventName);
事件名和事件 ID 根据三角勾结关系取到事件元,入队即可。
6.3.4 执行事件处理
在主循环里执行
VOID CEventSystem::ProcessAllEvent(VOID)
大致过程如下,处理延迟处理事件不提,和非延迟事件一样处理。
- 将重复事件合并
- 从事件中取到事件元
- 从事件元中取到事件过程链表
- 依次执行链表中的每个处理过程
- 将时间队列清空
6.4 事件源
Keyboard
Handle_AccelerateKey( event );
Handle_Combination_Key( event );
CEventSystem::GetMe()->PushEvent(GE_ACCELERATE_KEYSEND, "b");
Mouse
6.5 事件输入输出
产生事件
CEventSystem::GetMe()->PushEvent(GE_ACCELERATE_KEYSEND, "f");
6.6 事件回溯
以消息“GE_GAMELOGIN_OPEN_SELECT_SERVER”为例,打开 Analysis\event\武侠 2 窗口事件表.doc,找到消息
GAMELOGIN_OPEN_SELECT_SERVER | 21 | LoginSelectServer | SelectServer.layout.xml | SelectServer.lua | 然后打开 SelectServer.lua,在预加载的时候,注册了“GE_GAMELOGIN_OPEN_SELECT_SERVER”,
-- 注册 onLoad 事件
function LoginSelectServer_PreLoad()
-- 打开选择服务器界面
this:RegisterEvent("GAMELOGIN_OPEN_SELECT_SERVER");
-- 选择区域
this:RegisterEvent("GAMELOGIN_CLOSE_SELECT_SERVER");
-- 打开选择服务器界面
this:RegisterEvent("GAMELOGIN_SELECT_AREA");
-- 选择 login
this:RegisterEvent("GAMELOGIN_SELECT_LOGINSERVER");
-- 注册选择一个 login server 事件
this:RegisterEvent("GAMELOGIN_SELECT_LOGIN_SERVER");
-- 玩家进入场景
this:RegisterEvent("PLAYER_ENTERING_WORLD");
end
在消息响应的时候,在脚本的 function LoginSelectServer_OnEvent(event)中进行处理:
if( event == "GAMELOGIN_OPEN_SELECT_SERVER" ) then
this:Show();
return;
end
6.7 打开人物属性栏
GE_OPEN_CHARACTOR
e:\GameDev\projects\tlbb\source\wx2\wxsj2\trunk\Client\GameInterface\Include\Game\GIEventDefine.hL
line341 GE_OPEN_CHARACTOR, // 打开人物属性栏
e:\GameDev\projects\tlbb\source\wx2\wxsj2\trunk\Client\game\Event\GMEventSystem.cpp
line250 { GE_OPEN_CHARACTOR, "OPEN_CHARACTOR", },
e:\GameDev\projects\tlbb\source\wx2\wxsj2\trunk\Client\game\Interface\GMGameInterface_Script.cpp
line1374
INT Lua_OpenCharacter( LuaPlus::LuaState* state )
{
LuaStack args(state);
if( !args[ 1 ].IsInteger() ) return 0;
CEventSystem::GetMe()->PushEvent( GE_OPEN_CHARACTOR, args[ 1 ].GetInteger() );
return 0;
}
e:\GameDev\projects\tlbb\source\wx2\wxsj2\trunk\Client\game\Script\GMScriptSystm.cpp
objGlobal.Register( "OpenCharacter", SCRIPT_SANDBOX::Lua_OpenCharacter);
6.8 杂货商人交互分析
UI_CEGUI_d.dll!CUIWindowItem::_OnGameEvent
Game_d.exe!CEventSystem::_ProcessEvent
Game_d.exe!CEventSystem::ProcessAllEvent
Game_d.exe!CGameProcedure::ProcessGameEvent
Game_d.exe!CGameProcedure::MainLoop
Game_d.exe!_tMain_With_CPPException
Game_d.exe!WinMain
QUEST_EVENTLIST
{ GE_QUEST_EVENTLIST, "QUEST_EVENTLIST", },
|