Skip to content

Commit

Permalink
Move CEventNotifier class to xrCore and slightly refactoring it
Browse files Browse the repository at this point in the history
This class can be useful in the other places of the engine. After the refactoring the callback is allowed to unsubscribe himself frm ProcessEvent - it won't cause immediate deleting the callback's instance. Callback will be deleted only after ProcessEvent is completed.
  • Loading branch information
FreeZoneMods committed Nov 3, 2018
1 parent 1980ecb commit 2af9583
Show file tree
Hide file tree
Showing 10 changed files with 182 additions and 166 deletions.
10 changes: 10 additions & 0 deletions src/utils/xrSE_Factory/ai_space.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
////////////////////////////////////////////////////////////////////////////

#pragma once
#include "xrCore/Events/Notifier.h"

class CScriptEngine;

Expand All @@ -26,6 +27,15 @@ class CAI_Space
static CAI_Space& GetInstance();

IC CScriptEngine& script_engine() const;

enum EEventID
{
EVENT_SCRIPT_ENGINE_STARTED,
EVENT_SCRIPT_ENGINE_RESET,
EVENT_COUNT,
};
CEventNotifierCallback::CID Subscribe(CEventNotifierCallback* cb, EEventID event_id) { return 0; }
bool Unsubscribe(CEventNotifierCallback::CID cid, EEventID event_id) { return true; }
};

IC CAI_Space& ai();
Expand Down
114 changes: 114 additions & 0 deletions src/xrCore/Events/Notifier.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
#pragma once

#include "xrCommon/xr_smart_pointers.h"
#include "xrCommon/xr_vector.h"
#include "xrCommon/xr_array.h"
#include "xrCore/Threading/Lock.hpp"
#include "xrCore/Threading/ScopeLock.hpp"

class CEventNotifierCallback
{
public:
using CID = size_t;
static const CID INVALID_CID = std::numeric_limits<CID>::max();

virtual void ProcessEvent() = 0;
virtual ~CEventNotifierCallback(){};
};

template <unsigned int CNT>
class CEventNotifier
{
private:
class CCallbackStorage
{
class CCallbackWrapper
{
public:
xr_unique_ptr<CEventNotifierCallback> callback;
bool destroying = false;
bool executing = false;

CCallbackWrapper(CEventNotifierCallback* cb) : callback(cb){};
bool operator==(const CEventNotifierCallback* cb) { return cb == callback.get(); }
void Reset()
{
callback.reset(nullptr);
destroying = false;
executing = false;
}
};
xr_vector<CCallbackWrapper> m_callbacks;
Lock m_lock;

public:
CEventNotifierCallback::CID RegisterCallback(CEventNotifierCallback* cb)
{
ScopeLock lock(&m_lock);
auto it = std::find(m_callbacks.begin(), m_callbacks.end(), nullptr);
return (it == m_callbacks.end()) ? (m_callbacks.emplace_back(cb), m_callbacks.size() - 1) :
(it->callback.reset(cb), std::distance(m_callbacks.begin(), it));
}

bool UnregisterCallback(CEventNotifierCallback::CID cid)
{
bool result = false;
ScopeLock lock(&m_lock);
if (cid < m_callbacks.size() && m_callbacks[cid].callback != nullptr)
{
if (!m_callbacks[cid].destroying)
{
result = true;
m_callbacks[cid].destroying = true;
}

if (!m_callbacks[cid].executing)
{
m_callbacks[cid].Reset();
}
}
return result;
}

void ExecuteCallbacks()
{
ScopeLock lock(&m_lock);
for (CEventNotifierCallback::CID i = 0; i < m_callbacks.size(); ++i)
{
auto& cb = m_callbacks[i];
if (cb.callback != nullptr && !cb.destroying)
{
cb.executing = true;
cb.callback->ProcessEvent();
cb.executing = false;

if (cb.destroying)
{
UnregisterCallback(i);
}
}
}
}
};

xr_array<CCallbackStorage, CNT> m_callbacks;

public:
CEventNotifierCallback::CID RegisterCallback(CEventNotifierCallback* cb, unsigned int event_id)
{
R_ASSERT(event_id < CNT);
return m_callbacks[event_id].RegisterCallback(cb);
}

bool UnregisterCallback(CEventNotifierCallback::CID cid, unsigned int event_id)
{
R_ASSERT(event_id < CNT);
return m_callbacks[event_id].UnregisterCallback(cid);
}

void FireEvent(unsigned int event_id)
{
R_ASSERT(event_id < CNT);
m_callbacks[event_id].ExecuteCallbacks();
}
};
1 change: 1 addition & 0 deletions src/xrCore/xrCore.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,7 @@ call .GitInfo.cmd</Command>
</ClInclude>
<ClInclude Include="Debug\MiniDump.h" />
<ClInclude Include="dump_string.h" />
<ClInclude Include="Events\Notifier.h" />
<ClInclude Include="fastdelegate.h" />
<CustomBuild Include="FileSystem.h" />
<ClInclude Include="FileCRC32.h" />
Expand Down
6 changes: 6 additions & 0 deletions src/xrCore/xrCore.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,9 @@
<Filter Include="xrDelegate">
<UniqueIdentifier>{b54073c2-213d-456f-b88d-8eeb0dd440b0}</UniqueIdentifier>
</Filter>
<Filter Include="Events">
<UniqueIdentifier>{f17d865f-a3fd-41ac-b217-d7d34ed591f5}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="FTimer.cpp">
Expand Down Expand Up @@ -686,6 +689,9 @@
<ClInclude Include="FileCRC32.h">
<Filter>FS</Filter>
</ClInclude>
<ClInclude Include="Events\Notifier.h">
<Filter>Events</Filter>
</ClInclude>
<ClInclude Include="xrDelegate\xrDelegate.h">
<Filter>xrDelegate</Filter>
</ClInclude>
Expand Down
11 changes: 4 additions & 7 deletions src/xrGame/MainMenu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,19 +67,16 @@ CMainMenu* MainMenu() { return (CMainMenu*)g_pGamePersistent->m_pMainMenu; };

CMainMenu::CMainMenu()
{
class CResetEventCb : public CAI_Space::CEventCallback
class CResetEventCb : public CEventNotifierCallback
{
CMainMenu* m_mainmenu;

public:
CResetEventCb(CMainMenu* mm) : m_mainmenu(mm) {}
void ProcessEvent() override
{
m_mainmenu->DestroyInternal(true);
}
void ProcessEvent() override { m_mainmenu->DestroyInternal(true); }
};

m_script_reset_event_cid = ai().Subscribe(new CResetEventCb(this), CAI_Space::CNotifier::EVENT_SCRIPT_ENGINE_RESET);
m_script_reset_event_cid = ai().Subscribe(new CResetEventCb(this), CAI_Space::EVENT_SCRIPT_ENGINE_RESET);

m_Flags.zero();
m_startDialog = NULL;
Expand Down Expand Up @@ -171,7 +168,7 @@ CMainMenu::~CMainMenu()
xr_delete(m_demo_info_loader);
delete_data(m_pMB_ErrDlgs);

ai().Unsubscribe(m_script_reset_event_cid, CAI_Space::CNotifier::EVENT_SCRIPT_ENGINE_RESET);
ai().Unsubscribe(m_script_reset_event_cid, CAI_Space::EVENT_SCRIPT_ENGINE_RESET);
}

void CMainMenu::ReadTextureInfo()
Expand Down
2 changes: 1 addition & 1 deletion src/xrGame/MainMenu.h
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ class CMainMenu : public IMainMenu,

demo_info const* GetDemoInfo(LPCSTR file_name);

CAI_Space::CEventCallback::CID m_script_reset_event_cid;
CEventNotifierCallback::CID m_script_reset_event_cid;
};

extern CMainMenu* MainMenu();
93 changes: 12 additions & 81 deletions src/xrGame/ai_space.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,82 +22,6 @@
#include "moving_objects.h"
#include "doors_manager.h"

//----------------------- Event processing-----------------------

CAI_Space::CEventCallback::CID CAI_Space::CEventCallbackStorage::RegisterCallback(CEventCallback* cb)
{
m_lock.lock();

size_t i, cb_count = m_callbacks.size();

for (i = 0; i < cb_count; ++i)
{
if (!m_callbacks[i])
{
break;
}
}

if (i == cb_count)
{
m_callbacks.resize(cb_count + 1);
}

m_callbacks[i].reset(cb);

m_lock.unlock();
return i;
}
bool CAI_Space::CEventCallbackStorage::UnregisterCallback(CEventCallback::CID cid)
{
bool result = false;
m_lock.lock();

if (cid < m_callbacks.size() && m_callbacks[cid])
{
m_callbacks[cid].reset(nullptr);
result = true;
}

m_lock.unlock();
return result;
}

void CAI_Space::CEventCallbackStorage::ExecuteCallbacks()
{
m_lock.lock();

for (auto& cb : m_callbacks)
{
if (cb)
{
cb->ProcessEvent();
}
}

m_lock.unlock();
}

CAI_Space::CEventCallback::CID CAI_Space::CNotifier::RegisterCallback(CEventCallback* cb, EEventID event_id)
{
R_ASSERT(event_id < EVENT_COUNT);
return m_callbacks[event_id].RegisterCallback(cb);
}

bool CAI_Space::CNotifier::UnregisterCallback(CEventCallback::CID cid, EEventID event_id)
{
R_ASSERT(event_id < EVENT_COUNT);
return m_callbacks[event_id].UnregisterCallback(cid);
}

void CAI_Space::CNotifier::FireEvent(EEventID event_id)
{
R_ASSERT(event_id < EVENT_COUNT);
m_callbacks[event_id].ExecuteCallbacks();
}

//----------------------- Main CAI_Space stuff-----------------------

static CAI_Space g_ai_space;

CAI_Space& CAI_Space::GetInstance()
Expand Down Expand Up @@ -132,7 +56,11 @@ void CAI_Space::init()

CAI_Space::~CAI_Space()
{
m_events_notifier.FireEvent(CNotifier::EVENT_SCRIPT_ENGINE_RESET);
if (GEnv.ScriptEngine != nullptr)
{
m_events_notifier.FireEvent(EVENT_SCRIPT_ENGINE_RESET);
}

unload();
xr_delete(GEnv.ScriptEngine); // XXX: wrapped into try..catch(...) in vanilla source
}
Expand Down Expand Up @@ -211,15 +139,18 @@ void CAI_Space::RestartScriptEngine()
{
if (GEnv.ScriptEngine != nullptr)
{
m_events_notifier.FireEvent(CNotifier::EVENT_SCRIPT_ENGINE_RESET);
m_events_notifier.FireEvent(EVENT_SCRIPT_ENGINE_RESET);
}

SetupScriptEngine();
#ifdef DEBUG
get_moving_objects().clear();
#endif // DEBUG

m_events_notifier.FireEvent(CNotifier::EVENT_SCRIPT_ENGINE_STARTED);
if (GEnv.ScriptEngine != nullptr)
{
m_events_notifier.FireEvent(EVENT_SCRIPT_ENGINE_STARTED);
}
}

void CAI_Space::load(LPCSTR level_name)
Expand Down Expand Up @@ -266,12 +197,12 @@ void CAI_Space::set_alife(CALifeSimulator* alife_simulator)
SetGameGraph(nullptr);
}

CAI_Space::CEventCallback::CID CAI_Space::Subscribe(CEventCallback* cb, CNotifier::EEventID event_id)
CEventNotifierCallback::CID CAI_Space::Subscribe(CEventNotifierCallback* cb, EEventID event_id)
{
return m_events_notifier.RegisterCallback(cb, event_id);
}

bool CAI_Space::Unsubscribe(CAI_Space::CEventCallback::CID cid, CNotifier::EEventID event_id)
bool CAI_Space::Unsubscribe(CEventNotifierCallback::CID cid, EEventID event_id)
{
return m_events_notifier.UnregisterCallback(cid, event_id);
}
Loading

0 comments on commit 2af9583

Please sign in to comment.