diff --git a/src/xrGame/MainMenu.cpp b/src/xrGame/MainMenu.cpp index f26caab0a51..f1a0fb7258d 100644 --- a/src/xrGame/MainMenu.cpp +++ b/src/xrGame/MainMenu.cpp @@ -67,6 +67,20 @@ CMainMenu* MainMenu() { return (CMainMenu*)g_pGamePersistent->m_pMainMenu; }; CMainMenu::CMainMenu() { + class CResetEventCb : public CAI_Space::CEventCallback + { + CMainMenu* m_mainmenu; + + public: + CResetEventCb(CMainMenu* mm) : m_mainmenu(mm) {} + 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_Flags.zero(); m_startDialog = NULL; m_screenshotFrame = u32(-1); @@ -156,6 +170,8 @@ 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); } void CMainMenu::ReadTextureInfo() diff --git a/src/xrGame/MainMenu.h b/src/xrGame/MainMenu.h index 22e1fb07583..152d53d9a08 100644 --- a/src/xrGame/MainMenu.h +++ b/src/xrGame/MainMenu.h @@ -15,6 +15,7 @@ class demo_info_loader; #include "xrUICore/Callbacks/UIWndCallback.h" #include "xrUICore/ui_base.h" #include "DemoInfo.h" +#include "ai_space.h" namespace gamespy_gp { @@ -196,6 +197,8 @@ class CMainMenu : public IMainMenu, LPCSTR GetCDKeyFromRegistry(); demo_info const* GetDemoInfo(LPCSTR file_name); + + CAI_Space::CEventCallback::CID m_script_reset_event_cid; }; extern CMainMenu* MainMenu(); diff --git a/src/xrGame/ai_space.cpp b/src/xrGame/ai_space.cpp index 0c6913c122f..176bc659924 100644 --- a/src/xrGame/ai_space.cpp +++ b/src/xrGame/ai_space.cpp @@ -22,6 +22,82 @@ #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() @@ -48,7 +124,7 @@ void CAI_Space::init() VERIFY(!GEnv.ScriptEngine); GEnv.ScriptEngine = new CScriptEngine(); - SetupScriptEngine(); + RestartScriptEngine(); } m_inited = true; @@ -56,6 +132,7 @@ void CAI_Space::init() CAI_Space::~CAI_Space() { + m_events_notifier.FireEvent(CNotifier::EVENT_SCRIPT_ENGINE_RESET); unload(); xr_delete(GEnv.ScriptEngine); // XXX: wrapped into try..catch(...) in vanilla source } @@ -130,6 +207,21 @@ void CAI_Space::SetupScriptEngine() LoadCommonScripts(); } +void CAI_Space::RestartScriptEngine() +{ + if (GEnv.ScriptEngine != nullptr) + { + m_events_notifier.FireEvent(CNotifier::EVENT_SCRIPT_ENGINE_RESET); + } + + SetupScriptEngine(); +#ifdef DEBUG + get_moving_objects().clear(); +#endif // DEBUG + + m_events_notifier.FireEvent(CNotifier::EVENT_SCRIPT_ENGINE_STARTED); +} + void CAI_Space::load(LPCSTR level_name) { VERIFY(m_game_graph); @@ -173,3 +265,13 @@ void CAI_Space::set_alife(CALifeSimulator* alife_simulator) return; SetGameGraph(nullptr); } + +CAI_Space::CEventCallback::CID CAI_Space::Subscribe(CEventCallback* cb, CNotifier::EEventID event_id) +{ + return m_events_notifier.RegisterCallback(cb, event_id); +} + +bool CAI_Space::Unsubscribe(CAI_Space::CEventCallback::CID cid, CNotifier::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 19214dc121f..27f90fbf7f8 100644 --- a/src/xrGame/ai_space.h +++ b/src/xrGame/ai_space.h @@ -9,8 +9,10 @@ #pragma once #include "xrAICore/AISpaceBase.hpp" +#include "xrCommon/xr_array.h" #include +#include class CGameGraph; class CGameLevelCrossTable; @@ -30,6 +32,47 @@ class manager; class CAI_Space : public AISpaceBase { +public: + class CEventCallback + { + public: + using CID = size_t; + static const CID INVALID_CID = std::numeric_limits::max(); + + virtual void ProcessEvent() = 0; + virtual ~CEventCallback(){}; + }; + + class CEventCallbackStorage + { + xr_vector> m_callbacks; + std::mutex m_lock; + + public: + CEventCallback::CID RegisterCallback(CEventCallback* cb); + bool UnregisterCallback(CEventCallback::CID cid); + void ExecuteCallbacks(); + }; + + class CNotifier + { + public: + enum EEventID + { + EVENT_SCRIPT_ENGINE_STARTED, + EVENT_SCRIPT_ENGINE_RESET, + EVENT_COUNT, + }; + + private: + xr_array m_callbacks; + + public: + CEventCallback::CID RegisterCallback(CEventCallback* cb, EEventID event_id); + bool UnregisterCallback(CEventCallback::CID cid, EEventID event_id); + void FireEvent(EEventID event_id); + }; + private: friend class CALifeSimulator; friend class CALifeGraphRegistry; @@ -39,6 +82,7 @@ class CAI_Space : public AISpaceBase private: bool m_inited = false; + CNotifier m_events_notifier; std::unique_ptr m_ef_storage; std::unique_ptr m_cover_manager; @@ -54,6 +98,7 @@ class CAI_Space : public AISpaceBase void set_alife(CALifeSimulator* alife_simulator); void LoadCommonScripts(); void RegisterScriptClasses(); + void SetupScriptEngine(); public: CAI_Space() = default; @@ -62,7 +107,10 @@ class CAI_Space : public AISpaceBase virtual ~CAI_Space(); static CAI_Space& GetInstance(); - void SetupScriptEngine(); + CEventCallback::CID Subscribe(CEventCallback* cb, CNotifier::EEventID event_id); + bool Unsubscribe(CEventCallback::CID cid, CNotifier::EEventID event_id); + void RestartScriptEngine(); + IC CEF_Storage& ef_storage() const; IC const CALifeSimulator& alife() const; diff --git a/src/xrGame/alife_simulator.cpp b/src/xrGame/alife_simulator.cpp index fcce0fe5c0f..44561c39408 100644 --- a/src/xrGame/alife_simulator.cpp +++ b/src/xrGame/alife_simulator.cpp @@ -23,7 +23,6 @@ LPCSTR alife_section = "alife"; -extern void destroy_lua_wpn_params(); CALifeSimulator::CALifeSimulator(IPureServer* server, shared_str* command_line) : CALifeUpdateManager(server, alife_section), CALifeInteractionManager(server, alife_section), @@ -32,13 +31,7 @@ CALifeSimulator::CALifeSimulator(IPureServer* server, shared_str* command_line) // XXX: why do we need to reinitialize script engine? if (!strstr(Core.Params, "-keep_lua")) { - destroy_lua_wpn_params(); - MainMenu()->DestroyInternal(true); - xr_delete(g_object_factory); - ai().SetupScriptEngine(); -#ifdef DEBUG - ai().get_moving_objects().clear(); -#endif // DEBUG + ai().RestartScriptEngine(); } ai().set_alife(this); diff --git a/src/xrGame/ui/UIWpnParams.cpp b/src/xrGame/ui/UIWpnParams.cpp index e8e40cabbd5..54cac7f9b49 100644 --- a/src/xrGame/ui/UIWpnParams.cpp +++ b/src/xrGame/ui/UIWpnParams.cpp @@ -3,7 +3,6 @@ #include "UIXmlInit.h" #include "Level.h" #include "game_base_space.h" -#include "ai_space.h" #include "xrScriptEngine/script_engine.hpp" #include "inventory_item_object.h" #include "UIInventoryUtilities.h" @@ -21,6 +20,22 @@ struct SLuaWpnParams ~SLuaWpnParams(); }; +static SLuaWpnParams* g_lua_wpn_params = nullptr; + +static CAI_Space::CEventCallback::CID g_wpn_params_cb_cid = CAI_Space::CEventCallback::INVALID_CID; + +class CResetEventCb : public CAI_Space::CEventCallback +{ +public: + void ProcessEvent() override + { + if (g_lua_wpn_params) + { + xr_delete(g_lua_wpn_params); + } + } +}; + SLuaWpnParams::SLuaWpnParams() { bool functor_exists; @@ -34,16 +49,14 @@ SLuaWpnParams::SLuaWpnParams() VERIFY(functor_exists); functor_exists = GEnv.ScriptEngine->functor("ui_wpn_params.GetAccuracy", m_functorAccuracy); VERIFY(functor_exists); + + if (g_wpn_params_cb_cid == CAI_Space::CEventCallback::INVALID_CID) + { + g_wpn_params_cb_cid = ai().Subscribe(new CResetEventCb(), CAI_Space::CNotifier::EVENT_SCRIPT_ENGINE_RESET); + } } SLuaWpnParams::~SLuaWpnParams() {} -SLuaWpnParams* g_lua_wpn_params = NULL; - -void destroy_lua_wpn_params() -{ - if (g_lua_wpn_params) - xr_delete(g_lua_wpn_params); -} // ===================================================================== diff --git a/src/xrGame/xrgame_dll_detach.cpp b/src/xrGame/xrgame_dll_detach.cpp index 9928f75e1b3..07a16946959 100644 --- a/src/xrGame/xrgame_dll_detach.cpp +++ b/src/xrGame/xrgame_dll_detach.cpp @@ -58,11 +58,9 @@ void init_game_globals() extern CUIXml* g_uiSpotXml; extern CUIXml* pWpnScopeXml; -extern void destroy_lua_wpn_params(); void clean_game_globals() { - destroy_lua_wpn_params(); // destroy object factory xr_delete(g_object_factory); // destroy monster squad global var diff --git a/src/xrServerEntities/object_factory.h b/src/xrServerEntities/object_factory.h index e0c216a4a3d..ff063fe76fc 100644 --- a/src/xrServerEntities/object_factory.h +++ b/src/xrServerEntities/object_factory.h @@ -6,9 +6,6 @@ // Description : Object factory //////////////////////////////////////////////////////////////////////////// -#ifndef object_factoryH -#define object_factoryH - #pragma once #include "object_item_abstract.h" @@ -91,4 +88,3 @@ extern CObjectFactory* g_object_factory; IC const CObjectFactory& object_factory(); #include "object_factory_inline.h" -#endif diff --git a/src/xrServerEntities/object_factory_inline.h b/src/xrServerEntities/object_factory_inline.h index fcc9a75fdc4..b51828c7bdd 100644 --- a/src/xrServerEntities/object_factory_inline.h +++ b/src/xrServerEntities/object_factory_inline.h @@ -7,8 +7,6 @@ //////////////////////////////////////////////////////////////////////////// #pragma once -#ifndef object_factory_inlineH -#define object_factory_inlineH #include IC const CObjectFactory& object_factory() @@ -17,6 +15,27 @@ IC const CObjectFactory& object_factory() { g_object_factory = new CObjectFactory(); g_object_factory->init(); + + class CResetEventCb : public CAI_Space::CEventCallback + { + CAI_Space::CEventCallback::CID m_cid; + + public: + CResetEventCb() {} + void SetCid(CAI_Space::CEventCallback::CID cid) { m_cid = cid; } + void ProcessEvent() override + { + xr_delete(g_object_factory); + } + }; + + static CAI_Space::CEventCallback::CID cid = CAI_Space::CEventCallback::INVALID_CID; + if (cid == CAI_Space::CEventCallback::INVALID_CID) + { + CResetEventCb* e = new CResetEventCb(); + cid = ai().Subscribe(e, CAI_Space::CNotifier::EVENT_SCRIPT_ENGINE_RESET); + e->SetCid(cid); + } } return (*g_object_factory); } @@ -125,5 +144,3 @@ IC void CObjectFactory::actualize() const m_actual = true; std::sort(m_clsids.begin(), m_clsids.end(), CObjectItemPredicate()); } - -#endif