一 武侠的event是个比较强的系统,个人感觉也是做的比较好的,结合lua使用起来很不错
二 实现
1 定义结构
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;
};
struct EVENT
{
EVENT_DEFINE* pEventDef;
std::vector<STRING> vArg;
bool operator == (const EVENT& other)
{
if(other.pEventDef != pEventDef)
return false;
if(other.vArg.size() != vArg.size())
return false;
for(register size_t i=0; i<vArg.size(); i++)
{
if(vArg[i] != other.vArg[i])
return false;
}
return true;
}
};
{
typedef std::list< std::pair< FUNC_EVENT_HANDLE, UINT > > REGISTER_STRUCT;
GAME_EVENT_ID idEvent;
LPCTSTR szEvent;
BOOL delayProcess;
REGISTER_STRUCT listFuncNotify;
};
struct EVENT
{
EVENT_DEFINE* pEventDef;
std::vector<STRING> vArg;
bool operator == (const EVENT& other)
{
if(other.pEventDef != pEventDef)
return false;
if(other.vArg.size() != vArg.size())
return false;
for(register size_t i=0; i<vArg.size(); i++)
{
if(vArg[i] != other.vArg[i])
return false;
}
return true;
}
};
变量
//通过事件名称检索表
std::map< STRING, EVENT_DEFINE* > m_mapEventIndex_AsName;
//通过事件ID检索表
std::map< GAME_EVENT_ID, EVENT_DEFINE* > m_mapEventIndex_AsID;
保存了所有注册的事件,可以通过ID和Name索引
//事件队列
std::list< EVENT > m_queueEvent;
//慢速处理队列, 每桢一个,防止过多的消息同时涌现
std::list< EVENT > m_delayQueueEvent;
保存了当前需要处理的事件
2 lua注册接口
INT CUIWindowItem::LUA_RegisterEvent(LuaPlus::LuaState* pState)
{
LuaStack args(pState);
if(!(args[2].IsString()))
return 0;
if(m_bLayoutLoaded)
{
KLThrow("%s Must register event in \"***PreLoad\" Function ", m_strWindowName.c_str());
}
STRING strEventName = args[2].GetString();
g_pEventSys->RegisterEventHandle(strEventName, _OnGameEvent, (DWORD)(DWORD_PTR)this);
return 0;
}
{
LuaStack args(pState);
if(!(args[2].IsString()))
return 0;
if(m_bLayoutLoaded)
{
KLThrow("%s Must register event in \"***PreLoad\" Function ", m_strWindowName.c_str());
}
STRING strEventName = args[2].GetString();
g_pEventSys->RegisterEventHandle(strEventName, _OnGameEvent, (DWORD)(DWORD_PTR)this);
return 0;
}
// 注册事件处理函数
VOID CEventSystem::RegisterEventHandle(const STRING& nameEvent, FUNC_EVENT_HANDLE funHandle, UINT uOwnerData)
{
if(!funHandle)
return;
EVENT_DEFINE* pEvent = m_mapEventIndex_AsName[nameEvent];
if(!pEvent)
return;
pEvent->listFuncNotify.push_back( std::make_pair(funHandle, uOwnerData) );
}
VOID CEventSystem::RegisterEventHandle(const STRING& nameEvent, FUNC_EVENT_HANDLE funHandle, UINT uOwnerData)
{
if(!funHandle)
return;
EVENT_DEFINE* pEvent = m_mapEventIndex_AsName[nameEvent];
if(!pEvent)
return;
pEvent->listFuncNotify.push_back( std::make_pair(funHandle, uOwnerData) );
}
3 添加处理事件
VOID CEventSystem::PushEvent(STRING& eventName, LPCTSTR szArg0, LPCTSTR szArg1, INT iArg2, INT iArg3)
{
if(m_mapEventIndex_AsName.find(eventName) == m_mapEventIndex_AsName.end()) return;
EVENT event;
event.pEventDef=m_mapEventIndex_AsName[eventName];
event.vArg.push_back(szArg0);
event.vArg.push_back(szArg1);
CHAR szTemp[32];
_snprintf(szTemp, 32, "%d", iArg2);
event.vArg.push_back(szTemp);
_snprintf(szTemp, 32, "%d", iArg3);
event.vArg.push_back(szTemp);
_PushEvent(event);
}
{
if(m_mapEventIndex_AsName.find(eventName) == m_mapEventIndex_AsName.end()) return;
EVENT event;
event.pEventDef=m_mapEventIndex_AsName[eventName];
event.vArg.push_back(szArg0);
event.vArg.push_back(szArg1);
CHAR szTemp[32];
_snprintf(szTemp, 32, "%d", iArg2);
event.vArg.push_back(szTemp);
_snprintf(szTemp, 32, "%d", iArg3);
event.vArg.push_back(szTemp);
_PushEvent(event);
}
void CEventSystem::_PushEvent(const EVENT& event)
{
if(!event.pEventDef)
return;
// 如果是慢速处理的事件
if(event.pEventDef->delayProcess)
{
m_delayQueueEvent.push_back(event);
}
else
{
m_queueEvent.push_back(event);
}
}
{
if(!event.pEventDef)
return;
// 如果是慢速处理的事件
if(event.pEventDef->delayProcess)
{
m_delayQueueEvent.push_back(event);
}
else
{
m_queueEvent.push_back(event);
}
}
// 距离发生改变,产生事件
std::vector< STRING > vParam;
CHAR szTemp[MAX_PATH];
_snprintf(szTemp, MAX_PATH, "%d", pObject->GetID());
vParam.push_back(szTemp);
vParam.push_back("distance");
_snprintf(szTemp, MAX_PATH, "%.3f", fDistance);
vParam.push_back(szTemp);
CEventSystem::GetMe()->PushEvent(GE_OBJECT_CARED_EVENT, vParam);
std::vector< STRING > vParam;
CHAR szTemp[MAX_PATH];
_snprintf(szTemp, MAX_PATH, "%d", pObject->GetID());
vParam.push_back(szTemp);
vParam.push_back("distance");
_snprintf(szTemp, MAX_PATH, "%.3f", fDistance);
vParam.push_back(szTemp);
CEventSystem::GetMe()->PushEvent(GE_OBJECT_CARED_EVENT, vParam);
4 执行事件
VOID CEventSystem::ProcessAllEvent(VOID)
{
// 处理慢速队列
if(!(m_delayQueueEvent.empty()))
{
const UINT WORK_STEP = 2;
UINT nTickCountNow = CGameProcedure::s_pTimeSystem->GetTickCount();
UINT nTickCountStep = CGameProcedure::s_pTimeSystem->CalSubTime(m_dwLastTickCount, nTickCountNow);
if(nTickCountStep >= WORK_STEP)
{
m_dwLastTickCount = nTickCountNow;
const EVENT& event = *(m_delayQueueEvent.begin());
_ProcessEvent(event);
m_delayQueueEvent.erase(m_delayQueueEvent.begin());
}
}
register std::list< EVENT >::iterator it;
for(it=m_queueEvent.begin(); it!=m_queueEvent.end(); it++)
{
const EVENT& event = *it;
// 检测是否有同样的Event已经被处理
bool bMultiPushed = false;
for(register std::list< EVENT >::iterator itPrev=m_queueEvent.begin(); itPrev !=it; itPrev++)
{
if(*itPrev == *it)
{
bMultiPushed = true;
break;
}
}
if(bMultiPushed)
continue;
_ProcessEvent(event);
}
m_queueEvent.clear();
}
void CEventSystem::_ProcessEvent(const EVENT& event)
{
// 查找事件定义
EVENT_DEFINE* pEventDef = event.pEventDef;
if(!pEventDef)
return;
// 调用处理函数
if(!(pEventDef->listFuncNotify.empty()))
{
EVENT_DEFINE::REGISTER_STRUCT::iterator it;
for(it=pEventDef->listFuncNotify.begin(); it!=pEventDef->listFuncNotify.end(); it++)
{
if((*it).first)
((*it).first)(&event, (*it).second);
}
}
}
{
// 处理慢速队列
if(!(m_delayQueueEvent.empty()))
{
const UINT WORK_STEP = 2;
UINT nTickCountNow = CGameProcedure::s_pTimeSystem->GetTickCount();
UINT nTickCountStep = CGameProcedure::s_pTimeSystem->CalSubTime(m_dwLastTickCount, nTickCountNow);
if(nTickCountStep >= WORK_STEP)
{
m_dwLastTickCount = nTickCountNow;
const EVENT& event = *(m_delayQueueEvent.begin());
_ProcessEvent(event);
m_delayQueueEvent.erase(m_delayQueueEvent.begin());
}
}
register std::list< EVENT >::iterator it;
for(it=m_queueEvent.begin(); it!=m_queueEvent.end(); it++)
{
const EVENT& event = *it;
// 检测是否有同样的Event已经被处理
bool bMultiPushed = false;
for(register std::list< EVENT >::iterator itPrev=m_queueEvent.begin(); itPrev !=it; itPrev++)
{
if(*itPrev == *it)
{
bMultiPushed = true;
break;
}
}
if(bMultiPushed)
continue;
_ProcessEvent(event);
}
m_queueEvent.clear();
}
void CEventSystem::_ProcessEvent(const EVENT& event)
{
// 查找事件定义
EVENT_DEFINE* pEventDef = event.pEventDef;
if(!pEventDef)
return;
// 调用处理函数
if(!(pEventDef->listFuncNotify.empty()))
{
EVENT_DEFINE::REGISTER_STRUCT::iterator it;
for(it=pEventDef->listFuncNotify.begin(); it!=pEventDef->listFuncNotify.end(); it++)
{
if((*it).first)
((*it).first)(&event, (*it).second);
}
}
}
另外有一个回调函数,执行具体的lua调用
VOID WINAPI CUIWindowItem::_OnGameEvent(const EVENT* pEvent, UINT dwOwnerData)
{
KLAssert(pEvent);
//--------------------------------------------------------
// 分发
CUIWindowItem* pWinItem = (CUIWindowItem*)(DWORD_PTR)(dwOwnerData);
if(!pWinItem)
return;
// 加载
if(!(pWinItem->m_bLayoutLoaded))
{
pWinItem->LoadWindow();
}
//--------------------------------------------------------
// 参数
for(INT i=0; i<(INT)pEvent->vArg.size(); i++)
{
CHAR szTemp[MAX_PATH];
_snprintf(szTemp, MAX_PATH, "arg%d", i);
g_pScriptSys->GetLuaState()->GetGlobals().SetString(szTemp, pEvent->vArg[i].c_str());
}
//--------------------------------------------------------
// 调用脚本
CHAR szFunctionName[MAX_PATH];
_snprintf(szFunctionName, MAX_PATH, "%s_OnEvent", pWinItem->m_strWindowName.c_str());
CHAR szFunctionParam[MAX_PATH];
_snprintf(szFunctionParam, MAX_PATH, "\"%s\"", pEvent->pEventDef->szEvent);
pWinItem->m_pScriptEnv->DoFunction(szFunctionName, szFunctionParam);
}
{
KLAssert(pEvent);
//--------------------------------------------------------
// 分发
CUIWindowItem* pWinItem = (CUIWindowItem*)(DWORD_PTR)(dwOwnerData);
if(!pWinItem)
return;
// 加载
if(!(pWinItem->m_bLayoutLoaded))
{
pWinItem->LoadWindow();
}
//--------------------------------------------------------
// 参数
for(INT i=0; i<(INT)pEvent->vArg.size(); i++)
{
CHAR szTemp[MAX_PATH];
_snprintf(szTemp, MAX_PATH, "arg%d", i);
g_pScriptSys->GetLuaState()->GetGlobals().SetString(szTemp, pEvent->vArg[i].c_str());
}
//--------------------------------------------------------
// 调用脚本
CHAR szFunctionName[MAX_PATH];
_snprintf(szFunctionName, MAX_PATH, "%s_OnEvent", pWinItem->m_strWindowName.c_str());
CHAR szFunctionParam[MAX_PATH];
_snprintf(szFunctionParam, MAX_PATH, "\"%s\"", pEvent->pEventDef->szEvent);
pWinItem->m_pScriptEnv->DoFunction(szFunctionName, szFunctionParam);
}