From 83a67af5314afa723f401b5cda43c4f1864528a1 Mon Sep 17 00:00:00 2001 From: Sin! Date: Wed, 7 Nov 2018 20:38:46 +1000 Subject: [PATCH] Change subscriptions logic for CAI_Space It's better to create callbacks in the same place where deletion happens. So, let's make template functions to automatically create callbacks and subscribe it. --- src/utils/xrSE_Factory/ai_space.h | 8 +++- src/xrCore/Events/Notifier.h | 47 ++++++++++++++++++++ src/xrGame/MainMenu.cpp | 6 +-- src/xrGame/ai_space.cpp | 5 --- src/xrGame/ai_space.h | 7 ++- src/xrGame/ui/UIWpnParams.cpp | 10 ++--- src/xrServerEntities/object_factory_inline.h | 9 ++-- 7 files changed, 71 insertions(+), 21 deletions(-) diff --git a/src/utils/xrSE_Factory/ai_space.h b/src/utils/xrSE_Factory/ai_space.h index b574216b1f9..446218f8137 100644 --- a/src/utils/xrSE_Factory/ai_space.h +++ b/src/utils/xrSE_Factory/ai_space.h @@ -34,7 +34,13 @@ class CAI_Space EVENT_SCRIPT_ENGINE_RESET, EVENT_COUNT, }; - CEventNotifierCallback::CID Subscribe(CEventNotifierCallback* cb, EEventID event_id) { return 0; } + + template + CEventNotifierCallback::CID Subscribe(EEventID event_id, Args&&... args) + { + return 0; + } + bool Unsubscribe(CEventNotifierCallback::CID cid, EEventID event_id) { return true; } }; diff --git a/src/xrCore/Events/Notifier.h b/src/xrCore/Events/Notifier.h index bb19310dde0..071edfb9b8c 100644 --- a/src/xrCore/Events/Notifier.h +++ b/src/xrCore/Events/Notifier.h @@ -16,6 +16,16 @@ class CEventNotifierCallback virtual ~CEventNotifierCallback(){}; }; +class CEventNotifierCallbackWithCid : public CEventNotifierCallback +{ +private: + const CID m_cid; + +public: + CEventNotifierCallbackWithCid(CID cid) : m_cid(cid), CEventNotifierCallback(){}; + CID GetCid() const { return m_cid; } +}; + template class CEventNotifier { @@ -41,6 +51,14 @@ class CEventNotifier xr_vector m_callbacks; Lock m_lock; + CEventNotifierCallback::CID FindFreeCid() + { + ScopeLock lock(&m_lock); + auto it = std::find(m_callbacks.begin(), m_callbacks.end(), nullptr); + return (it == m_callbacks.end()) ? CEventNotifierCallback::INVALID_CID : + std::distance(m_callbacks.begin(), it); + } + public: CEventNotifierCallback::CID RegisterCallback(CEventNotifierCallback* cb) { @@ -50,6 +68,28 @@ class CEventNotifier (it->callback.reset(cb), std::distance(m_callbacks.begin(), it)); } + template + CEventNotifierCallback::CID CreateRegisteredCallback(Args&&... args) + { + static_assert(std::is_base_of::value); + + ScopeLock lock(&m_lock); + + auto cid = FindFreeCid(); + CB* cb = new CB((cid == CEventNotifierCallback::INVALID_CID) ? m_callbacks.size() : cid, args...); + + if (cid == CEventNotifierCallback::INVALID_CID) + { + m_callbacks.emplace_back(cb); + } + else + { + m_callbacks[cid].callback.reset(cb); + } + + return cb->GetCid(); + } + bool UnregisterCallback(CEventNotifierCallback::CID cid) { bool result = false; @@ -100,6 +140,13 @@ class CEventNotifier return m_callbacks[event_id].RegisterCallback(cb); } + template + CEventNotifierCallback::CID CreateRegisteredCallback(unsigned int event_id, Args&&... args) + { + R_ASSERT(event_id < CNT); + return m_callbacks[event_id].CreateRegisteredCallback(args...); + } + bool UnregisterCallback(CEventNotifierCallback::CID cid, unsigned int event_id) { R_ASSERT(event_id < CNT); diff --git a/src/xrGame/MainMenu.cpp b/src/xrGame/MainMenu.cpp index aed1ac73308..fd7cf3b99c2 100644 --- a/src/xrGame/MainMenu.cpp +++ b/src/xrGame/MainMenu.cpp @@ -67,16 +67,16 @@ CMainMenu* MainMenu() { return (CMainMenu*)g_pGamePersistent->m_pMainMenu; }; CMainMenu::CMainMenu() { - class CResetEventCb : public CEventNotifierCallback + class CResetEventCb : public CEventNotifierCallbackWithCid { CMainMenu* m_mainmenu; public: - CResetEventCb(CMainMenu* mm) : m_mainmenu(mm) {} + CResetEventCb(CID cid, CMainMenu* mm) : m_mainmenu(mm), CEventNotifierCallbackWithCid(cid) {} void ProcessEvent() override { m_mainmenu->DestroyInternal(true); } }; - m_script_reset_event_cid = ai().Subscribe(new CResetEventCb(this), CAI_Space::EVENT_SCRIPT_ENGINE_RESET); + m_script_reset_event_cid = ai().Subscribe(CAI_Space::EVENT_SCRIPT_ENGINE_RESET, this); m_Flags.zero(); m_startDialog = NULL; diff --git a/src/xrGame/ai_space.cpp b/src/xrGame/ai_space.cpp index 99b6643f55f..67aef49e380 100644 --- a/src/xrGame/ai_space.cpp +++ b/src/xrGame/ai_space.cpp @@ -197,11 +197,6 @@ void CAI_Space::set_alife(CALifeSimulator* alife_simulator) SetGameGraph(nullptr); } -CEventNotifierCallback::CID CAI_Space::Subscribe(CEventNotifierCallback* cb, EEventID event_id) -{ - return m_events_notifier.RegisterCallback(cb, event_id); -} - bool CAI_Space::Unsubscribe(CEventNotifierCallback::CID cid, EEventID event_id) { return m_events_notifier.UnregisterCallback(cid, event_id); diff --git a/src/xrGame/ai_space.h b/src/xrGame/ai_space.h index 0ddda746547..8cb537a5a4b 100644 --- a/src/xrGame/ai_space.h +++ b/src/xrGame/ai_space.h @@ -73,7 +73,12 @@ class CAI_Space : public AISpaceBase virtual ~CAI_Space(); static CAI_Space& GetInstance(); - CEventNotifierCallback::CID Subscribe(CEventNotifierCallback* cb, EEventID event_id); + template + CEventNotifierCallback::CID Subscribe(EEventID event_id, Args&&... args) + { + return m_events_notifier.CreateRegisteredCallback(event_id, args...); + } + bool Unsubscribe(CEventNotifierCallback::CID cid, EEventID event_id); void RestartScriptEngine(); diff --git a/src/xrGame/ui/UIWpnParams.cpp b/src/xrGame/ui/UIWpnParams.cpp index 58076cae221..45b9eaa2e7d 100644 --- a/src/xrGame/ui/UIWpnParams.cpp +++ b/src/xrGame/ui/UIWpnParams.cpp @@ -108,21 +108,19 @@ void CUIWpnParams::SetInfo(CInventoryItem* slot_wpn, CInventoryItem& cur_wpn) { if (!g_lua_wpn_params) { - class CResetEventCb : public CEventNotifierCallback + class CResetEventCb : public CEventNotifierCallbackWithCid { public: - CID m_cid = INVALID_CID; - + CResetEventCb(CID cid) : CEventNotifierCallbackWithCid(cid) {} void ProcessEvent() override { xr_delete(g_lua_wpn_params); - ai().Unsubscribe(m_cid, CAI_Space::EVENT_SCRIPT_ENGINE_RESET); + ai().Unsubscribe(GetCid(), CAI_Space::EVENT_SCRIPT_ENGINE_RESET); } }; g_lua_wpn_params = new SLuaWpnParams(); - auto cb = new CResetEventCb(); - cb->m_cid = ai().Subscribe(cb, CAI_Space::EVENT_SCRIPT_ENGINE_RESET); + ai().Subscribe(CAI_Space::EVENT_SCRIPT_ENGINE_RESET); } LPCSTR cur_section = cur_wpn.object().cNameSect().c_str(); diff --git a/src/xrServerEntities/object_factory_inline.h b/src/xrServerEntities/object_factory_inline.h index 3dcc44e7184..9a89c6f6a05 100644 --- a/src/xrServerEntities/object_factory_inline.h +++ b/src/xrServerEntities/object_factory_inline.h @@ -18,20 +18,19 @@ IC const CObjectFactory& object_factory() g_object_factory = new CObjectFactory(); g_object_factory->init(); - class CResetEventCb : public CEventNotifierCallback + class CResetEventCb : public CEventNotifierCallbackWithCid { public: - CID m_cid; + CResetEventCb(CID cid) : CEventNotifierCallbackWithCid(cid) {} void ProcessEvent() override { xr_delete(g_object_factory); - ai().Unsubscribe(m_cid, CAI_Space::EVENT_SCRIPT_ENGINE_RESET); + ai().Unsubscribe(GetCid(), CAI_Space::EVENT_SCRIPT_ENGINE_RESET); } }; - CResetEventCb* e = new CResetEventCb(); - e->m_cid = ai().Subscribe(e, CAI_Space::EVENT_SCRIPT_ENGINE_RESET); + ai().Subscribe(CAI_Space::EVENT_SCRIPT_ENGINE_RESET); } return (*g_object_factory); }