Skip to content

Commit 2af9583

Browse files
committed
Move CEventNotifier class to xrCore and slightly refactoring it
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.
1 parent 1980ecb commit 2af9583

File tree

10 files changed

+182
-166
lines changed

10 files changed

+182
-166
lines changed

src/utils/xrSE_Factory/ai_space.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
////////////////////////////////////////////////////////////////////////////
88

99
#pragma once
10+
#include "xrCore/Events/Notifier.h"
1011

1112
class CScriptEngine;
1213

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

2829
IC CScriptEngine& script_engine() const;
30+
31+
enum EEventID
32+
{
33+
EVENT_SCRIPT_ENGINE_STARTED,
34+
EVENT_SCRIPT_ENGINE_RESET,
35+
EVENT_COUNT,
36+
};
37+
CEventNotifierCallback::CID Subscribe(CEventNotifierCallback* cb, EEventID event_id) { return 0; }
38+
bool Unsubscribe(CEventNotifierCallback::CID cid, EEventID event_id) { return true; }
2939
};
3040

3141
IC CAI_Space& ai();

src/xrCore/Events/Notifier.h

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
#pragma once
2+
3+
#include "xrCommon/xr_smart_pointers.h"
4+
#include "xrCommon/xr_vector.h"
5+
#include "xrCommon/xr_array.h"
6+
#include "xrCore/Threading/Lock.hpp"
7+
#include "xrCore/Threading/ScopeLock.hpp"
8+
9+
class CEventNotifierCallback
10+
{
11+
public:
12+
using CID = size_t;
13+
static const CID INVALID_CID = std::numeric_limits<CID>::max();
14+
15+
virtual void ProcessEvent() = 0;
16+
virtual ~CEventNotifierCallback(){};
17+
};
18+
19+
template <unsigned int CNT>
20+
class CEventNotifier
21+
{
22+
private:
23+
class CCallbackStorage
24+
{
25+
class CCallbackWrapper
26+
{
27+
public:
28+
xr_unique_ptr<CEventNotifierCallback> callback;
29+
bool destroying = false;
30+
bool executing = false;
31+
32+
CCallbackWrapper(CEventNotifierCallback* cb) : callback(cb){};
33+
bool operator==(const CEventNotifierCallback* cb) { return cb == callback.get(); }
34+
void Reset()
35+
{
36+
callback.reset(nullptr);
37+
destroying = false;
38+
executing = false;
39+
}
40+
};
41+
xr_vector<CCallbackWrapper> m_callbacks;
42+
Lock m_lock;
43+
44+
public:
45+
CEventNotifierCallback::CID RegisterCallback(CEventNotifierCallback* cb)
46+
{
47+
ScopeLock lock(&m_lock);
48+
auto it = std::find(m_callbacks.begin(), m_callbacks.end(), nullptr);
49+
return (it == m_callbacks.end()) ? (m_callbacks.emplace_back(cb), m_callbacks.size() - 1) :
50+
(it->callback.reset(cb), std::distance(m_callbacks.begin(), it));
51+
}
52+
53+
bool UnregisterCallback(CEventNotifierCallback::CID cid)
54+
{
55+
bool result = false;
56+
ScopeLock lock(&m_lock);
57+
if (cid < m_callbacks.size() && m_callbacks[cid].callback != nullptr)
58+
{
59+
if (!m_callbacks[cid].destroying)
60+
{
61+
result = true;
62+
m_callbacks[cid].destroying = true;
63+
}
64+
65+
if (!m_callbacks[cid].executing)
66+
{
67+
m_callbacks[cid].Reset();
68+
}
69+
}
70+
return result;
71+
}
72+
73+
void ExecuteCallbacks()
74+
{
75+
ScopeLock lock(&m_lock);
76+
for (CEventNotifierCallback::CID i = 0; i < m_callbacks.size(); ++i)
77+
{
78+
auto& cb = m_callbacks[i];
79+
if (cb.callback != nullptr && !cb.destroying)
80+
{
81+
cb.executing = true;
82+
cb.callback->ProcessEvent();
83+
cb.executing = false;
84+
85+
if (cb.destroying)
86+
{
87+
UnregisterCallback(i);
88+
}
89+
}
90+
}
91+
}
92+
};
93+
94+
xr_array<CCallbackStorage, CNT> m_callbacks;
95+
96+
public:
97+
CEventNotifierCallback::CID RegisterCallback(CEventNotifierCallback* cb, unsigned int event_id)
98+
{
99+
R_ASSERT(event_id < CNT);
100+
return m_callbacks[event_id].RegisterCallback(cb);
101+
}
102+
103+
bool UnregisterCallback(CEventNotifierCallback::CID cid, unsigned int event_id)
104+
{
105+
R_ASSERT(event_id < CNT);
106+
return m_callbacks[event_id].UnregisterCallback(cid);
107+
}
108+
109+
void FireEvent(unsigned int event_id)
110+
{
111+
R_ASSERT(event_id < CNT);
112+
m_callbacks[event_id].ExecuteCallbacks();
113+
}
114+
};

src/xrCore/xrCore.vcxproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,7 @@ call .GitInfo.cmd</Command>
364364
</ClInclude>
365365
<ClInclude Include="Debug\MiniDump.h" />
366366
<ClInclude Include="dump_string.h" />
367+
<ClInclude Include="Events\Notifier.h" />
367368
<ClInclude Include="fastdelegate.h" />
368369
<CustomBuild Include="FileSystem.h" />
369370
<ClInclude Include="FileCRC32.h" />

src/xrCore/xrCore.vcxproj.filters

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,9 @@
115115
<Filter Include="xrDelegate">
116116
<UniqueIdentifier>{b54073c2-213d-456f-b88d-8eeb0dd440b0}</UniqueIdentifier>
117117
</Filter>
118+
<Filter Include="Events">
119+
<UniqueIdentifier>{f17d865f-a3fd-41ac-b217-d7d34ed591f5}</UniqueIdentifier>
120+
</Filter>
118121
</ItemGroup>
119122
<ItemGroup>
120123
<ClCompile Include="FTimer.cpp">
@@ -686,6 +689,9 @@
686689
<ClInclude Include="FileCRC32.h">
687690
<Filter>FS</Filter>
688691
</ClInclude>
692+
<ClInclude Include="Events\Notifier.h">
693+
<Filter>Events</Filter>
694+
</ClInclude>
689695
<ClInclude Include="xrDelegate\xrDelegate.h">
690696
<Filter>xrDelegate</Filter>
691697
</ClInclude>

src/xrGame/MainMenu.cpp

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -67,19 +67,16 @@ CMainMenu* MainMenu() { return (CMainMenu*)g_pGamePersistent->m_pMainMenu; };
6767

6868
CMainMenu::CMainMenu()
6969
{
70-
class CResetEventCb : public CAI_Space::CEventCallback
70+
class CResetEventCb : public CEventNotifierCallback
7171
{
7272
CMainMenu* m_mainmenu;
7373

7474
public:
7575
CResetEventCb(CMainMenu* mm) : m_mainmenu(mm) {}
76-
void ProcessEvent() override
77-
{
78-
m_mainmenu->DestroyInternal(true);
79-
}
76+
void ProcessEvent() override { m_mainmenu->DestroyInternal(true); }
8077
};
8178

82-
m_script_reset_event_cid = ai().Subscribe(new CResetEventCb(this), CAI_Space::CNotifier::EVENT_SCRIPT_ENGINE_RESET);
79+
m_script_reset_event_cid = ai().Subscribe(new CResetEventCb(this), CAI_Space::EVENT_SCRIPT_ENGINE_RESET);
8380

8481
m_Flags.zero();
8582
m_startDialog = NULL;
@@ -171,7 +168,7 @@ CMainMenu::~CMainMenu()
171168
xr_delete(m_demo_info_loader);
172169
delete_data(m_pMB_ErrDlgs);
173170

174-
ai().Unsubscribe(m_script_reset_event_cid, CAI_Space::CNotifier::EVENT_SCRIPT_ENGINE_RESET);
171+
ai().Unsubscribe(m_script_reset_event_cid, CAI_Space::EVENT_SCRIPT_ENGINE_RESET);
175172
}
176173

177174
void CMainMenu::ReadTextureInfo()

src/xrGame/MainMenu.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ class CMainMenu : public IMainMenu,
198198

199199
demo_info const* GetDemoInfo(LPCSTR file_name);
200200

201-
CAI_Space::CEventCallback::CID m_script_reset_event_cid;
201+
CEventNotifierCallback::CID m_script_reset_event_cid;
202202
};
203203

204204
extern CMainMenu* MainMenu();

src/xrGame/ai_space.cpp

Lines changed: 12 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -22,82 +22,6 @@
2222
#include "moving_objects.h"
2323
#include "doors_manager.h"
2424

25-
//----------------------- Event processing-----------------------
26-
27-
CAI_Space::CEventCallback::CID CAI_Space::CEventCallbackStorage::RegisterCallback(CEventCallback* cb)
28-
{
29-
m_lock.lock();
30-
31-
size_t i, cb_count = m_callbacks.size();
32-
33-
for (i = 0; i < cb_count; ++i)
34-
{
35-
if (!m_callbacks[i])
36-
{
37-
break;
38-
}
39-
}
40-
41-
if (i == cb_count)
42-
{
43-
m_callbacks.resize(cb_count + 1);
44-
}
45-
46-
m_callbacks[i].reset(cb);
47-
48-
m_lock.unlock();
49-
return i;
50-
}
51-
bool CAI_Space::CEventCallbackStorage::UnregisterCallback(CEventCallback::CID cid)
52-
{
53-
bool result = false;
54-
m_lock.lock();
55-
56-
if (cid < m_callbacks.size() && m_callbacks[cid])
57-
{
58-
m_callbacks[cid].reset(nullptr);
59-
result = true;
60-
}
61-
62-
m_lock.unlock();
63-
return result;
64-
}
65-
66-
void CAI_Space::CEventCallbackStorage::ExecuteCallbacks()
67-
{
68-
m_lock.lock();
69-
70-
for (auto& cb : m_callbacks)
71-
{
72-
if (cb)
73-
{
74-
cb->ProcessEvent();
75-
}
76-
}
77-
78-
m_lock.unlock();
79-
}
80-
81-
CAI_Space::CEventCallback::CID CAI_Space::CNotifier::RegisterCallback(CEventCallback* cb, EEventID event_id)
82-
{
83-
R_ASSERT(event_id < EVENT_COUNT);
84-
return m_callbacks[event_id].RegisterCallback(cb);
85-
}
86-
87-
bool CAI_Space::CNotifier::UnregisterCallback(CEventCallback::CID cid, EEventID event_id)
88-
{
89-
R_ASSERT(event_id < EVENT_COUNT);
90-
return m_callbacks[event_id].UnregisterCallback(cid);
91-
}
92-
93-
void CAI_Space::CNotifier::FireEvent(EEventID event_id)
94-
{
95-
R_ASSERT(event_id < EVENT_COUNT);
96-
m_callbacks[event_id].ExecuteCallbacks();
97-
}
98-
99-
//----------------------- Main CAI_Space stuff-----------------------
100-
10125
static CAI_Space g_ai_space;
10226

10327
CAI_Space& CAI_Space::GetInstance()
@@ -132,7 +56,11 @@ void CAI_Space::init()
13256

13357
CAI_Space::~CAI_Space()
13458
{
135-
m_events_notifier.FireEvent(CNotifier::EVENT_SCRIPT_ENGINE_RESET);
59+
if (GEnv.ScriptEngine != nullptr)
60+
{
61+
m_events_notifier.FireEvent(EVENT_SCRIPT_ENGINE_RESET);
62+
}
63+
13664
unload();
13765
xr_delete(GEnv.ScriptEngine); // XXX: wrapped into try..catch(...) in vanilla source
13866
}
@@ -211,15 +139,18 @@ void CAI_Space::RestartScriptEngine()
211139
{
212140
if (GEnv.ScriptEngine != nullptr)
213141
{
214-
m_events_notifier.FireEvent(CNotifier::EVENT_SCRIPT_ENGINE_RESET);
142+
m_events_notifier.FireEvent(EVENT_SCRIPT_ENGINE_RESET);
215143
}
216144

217145
SetupScriptEngine();
218146
#ifdef DEBUG
219147
get_moving_objects().clear();
220148
#endif // DEBUG
221149

222-
m_events_notifier.FireEvent(CNotifier::EVENT_SCRIPT_ENGINE_STARTED);
150+
if (GEnv.ScriptEngine != nullptr)
151+
{
152+
m_events_notifier.FireEvent(EVENT_SCRIPT_ENGINE_STARTED);
153+
}
223154
}
224155

225156
void CAI_Space::load(LPCSTR level_name)
@@ -266,12 +197,12 @@ void CAI_Space::set_alife(CALifeSimulator* alife_simulator)
266197
SetGameGraph(nullptr);
267198
}
268199

269-
CAI_Space::CEventCallback::CID CAI_Space::Subscribe(CEventCallback* cb, CNotifier::EEventID event_id)
200+
CEventNotifierCallback::CID CAI_Space::Subscribe(CEventNotifierCallback* cb, EEventID event_id)
270201
{
271202
return m_events_notifier.RegisterCallback(cb, event_id);
272203
}
273204

274-
bool CAI_Space::Unsubscribe(CAI_Space::CEventCallback::CID cid, CNotifier::EEventID event_id)
205+
bool CAI_Space::Unsubscribe(CEventNotifierCallback::CID cid, EEventID event_id)
275206
{
276207
return m_events_notifier.UnregisterCallback(cid, event_id);
277208
}

0 commit comments

Comments
 (0)