From 53346328e8cc12dc2bb800534aefcb4eabb15502 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Fri, 30 Dec 2011 18:12:15 +0400 Subject: [PATCH] Notify plugins about game being loaded or unloaded. As a test, make seadwatch deactivate on these events. --- library/Core.cpp | 19 +++++++++++++++++++ library/PluginManager.cpp | 24 ++++++++++++++++++++++++ library/include/dfhack/Core.h | 3 +++ library/include/dfhack/PluginManager.h | 8 ++++++++ plugins/seedwatch.cpp | 24 +++++++++++++++++++++++- 5 files changed, 77 insertions(+), 1 deletion(-) diff --git a/library/Core.cpp b/library/Core.cpp index 04b885fa7..41d3b5bd9 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -51,6 +51,9 @@ using namespace DFHack; #include "dfhack/SDL_fakes/events.h" +#include "dfhack/df/world.h" +#include "dfhack/df/world_data.h" + #include #include #include @@ -439,6 +442,7 @@ Core::Core() HotkeyMutex = 0; HotkeyCond = 0; misc_data_mutex=0; + last_world_data_ptr = NULL; }; void Core::fatal (std::string output, bool deactivate) @@ -631,8 +635,23 @@ int Core::Update() if(errorstate) return -1; + // detect if the game was loaded or unloaded in the meantime + void *new_wdata = NULL; + if (df::global::world) { + df::world_data *wdata = df::global::world->world_data; + // when the game is unloaded, world_data isn't deleted, but its contents are + if (wdata && !wdata->sites.empty()) + new_wdata = wdata; + } + + if (new_wdata != last_world_data_ptr) { + last_world_data_ptr = new_wdata; + plug_mgr->OnStateChange(new_wdata ? SC_GAME_LOADED : SC_GAME_UNLOADED); + } + // notify all the plugins that a game tick is finished plug_mgr->OnUpdate(); + // wake waiting tools // do not allow more tools to join in while we process stuff here StackMutex->lock(); diff --git a/library/PluginManager.cpp b/library/PluginManager.cpp index d37c3fbf0..997b8e59f 100644 --- a/library/PluginManager.cpp +++ b/library/PluginManager.cpp @@ -135,6 +135,7 @@ Plugin::Plugin(Core * core, const std::string & filepath, const std::string & _f plugin_shutdown = 0; plugin_status = 0; plugin_onupdate = 0; + plugin_onstatechange = 0; state = PS_UNLOADED; access = new RefLock(); } @@ -192,6 +193,7 @@ bool Plugin::load() plugin_status = (command_result (*)(Core *, std::string &)) LookupPlugin(plug, "plugin_status"); plugin_onupdate = (command_result (*)(Core *)) LookupPlugin(plug, "plugin_onupdate"); plugin_shutdown = (command_result (*)(Core *)) LookupPlugin(plug, "plugin_shutdown"); + plugin_onstatechange = (command_result (*)(Core *, state_change_event)) LookupPlugin(plug, "plugin_onstatechange"); //name = _PlugName(); plugin_lib = plug; if(plugin_init(&c,commands) == CR_OK) @@ -299,6 +301,19 @@ command_result Plugin::on_update() return cr; } +command_result Plugin::on_state_change(state_change_event event) +{ + Core & c = Core::getInstance(); + command_result cr = CR_NOT_IMPLEMENTED; + access->lock_add(); + if(state == PS_LOADED && plugin_onstatechange) + { + cr = plugin_onstatechange(&c, event); + } + access->lock_sub(); + return cr; +} + Plugin::plugin_state Plugin::getState() const { return state; @@ -370,6 +385,15 @@ void PluginManager::OnUpdate( void ) all_plugins[i]->on_update(); } } + +void PluginManager::OnStateChange( state_change_event event ) +{ + for(int i = 0; i < all_plugins.size(); i++) + { + all_plugins[i]->on_state_change(event); + } +} + // FIXME: doesn't check name collisions! void PluginManager::registerCommands( Plugin * p ) { diff --git a/library/include/dfhack/Core.h b/library/include/dfhack/Core.h index 64eae5d3e..e91dae390 100644 --- a/library/include/dfhack/Core.h +++ b/library/include/dfhack/Core.h @@ -134,6 +134,8 @@ namespace DFHack /// returns a named pointer. void *GetData(std::string key); + bool isWorldLoaded() { return (last_world_data_ptr != NULL); } + DFHack::Process * p; DFHack::VersionInfo * vinfo; DFHack::Console con; @@ -184,6 +186,7 @@ namespace DFHack bool hotkey_set; tthread::mutex * HotkeyMutex; tthread::condition_variable * HotkeyCond; + void *last_world_data_ptr; // for state change tracking // Very important! bool started; diff --git a/library/include/dfhack/PluginManager.h b/library/include/dfhack/PluginManager.h index fef1aea50..0ac84f219 100644 --- a/library/include/dfhack/PluginManager.h +++ b/library/include/dfhack/PluginManager.h @@ -46,6 +46,11 @@ namespace DFHack CR_FAILURE = 0, CR_OK = 1 }; + enum state_change_event + { + SC_GAME_LOADED, + SC_GAME_UNLOADED + }; struct PluginCommand { /// create a command with a name, description, function pointer to its code @@ -87,6 +92,7 @@ namespace DFHack Plugin(DFHack::Core* core, const std::string& filepath, const std::string& filename, PluginManager * pm); ~Plugin(); command_result on_update(); + command_result on_state_change(state_change_event event); public: bool load(); bool unload(); @@ -117,6 +123,7 @@ namespace DFHack command_result (*plugin_status)(Core *, std::string &); command_result (*plugin_shutdown)(Core *); command_result (*plugin_onupdate)(Core *); + command_result (*plugin_onstatechange)(Core *, state_change_event); }; class DFHACK_EXPORT PluginManager { @@ -126,6 +133,7 @@ namespace DFHack PluginManager(Core * core); ~PluginManager(); void OnUpdate( void ); + void OnStateChange( state_change_event event ); void registerCommands( Plugin * p ); void unregisterCommands( Plugin * p ); // PUBLIC METHODS diff --git a/plugins/seedwatch.cpp b/plugins/seedwatch.cpp index 418398e3d..90175470c 100755 --- a/plugins/seedwatch.cpp +++ b/plugins/seedwatch.cpp @@ -288,10 +288,32 @@ DFhackCExport DFHack::command_result plugin_init(DFHack::Core* pCore, std::vecto return DFHack::CR_OK; } +DFhackCExport DFHack::command_result plugin_onstatechange(DFHack::Core* pCore, DFHack::state_change_event event) +{ + switch (event) { + case DFHack::SC_GAME_LOADED: + case DFHack::SC_GAME_UNLOADED: + if (running) + pCore->con.printerr("seedwatch deactivated due to game load/unload\n"); + running = false; + break; + default: + break; + } + + return DFHack::CR_OK; +} + DFhackCExport DFHack::command_result plugin_onupdate(DFHack::Core* pCore) { - if(running) + if (running) { + // reduce processing rate + static int counter = 0; + if (++counter < 500) + return DFHack::CR_OK; + counter = 0; + DFHack::Core& core = *pCore; DFHack::World *w = core.getWorld(); DFHack::t_gamemodes gm;