Notify plugins about game being loaded or unloaded.

As a test, make seadwatch deactivate on these events.
develop
Alexander Gavrilov 2011-12-30 18:12:15 +04:00
parent 298e2fe92d
commit 53346328e8
5 changed files with 77 additions and 1 deletions

@ -51,6 +51,9 @@ using namespace DFHack;
#include "dfhack/SDL_fakes/events.h" #include "dfhack/SDL_fakes/events.h"
#include "dfhack/df/world.h"
#include "dfhack/df/world_data.h"
#include <stdio.h> #include <stdio.h>
#include <iomanip> #include <iomanip>
#include <stdlib.h> #include <stdlib.h>
@ -439,6 +442,7 @@ Core::Core()
HotkeyMutex = 0; HotkeyMutex = 0;
HotkeyCond = 0; HotkeyCond = 0;
misc_data_mutex=0; misc_data_mutex=0;
last_world_data_ptr = NULL;
}; };
void Core::fatal (std::string output, bool deactivate) void Core::fatal (std::string output, bool deactivate)
@ -631,8 +635,23 @@ int Core::Update()
if(errorstate) if(errorstate)
return -1; 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 // notify all the plugins that a game tick is finished
plug_mgr->OnUpdate(); plug_mgr->OnUpdate();
// wake waiting tools // wake waiting tools
// do not allow more tools to join in while we process stuff here // do not allow more tools to join in while we process stuff here
StackMutex->lock(); StackMutex->lock();

@ -135,6 +135,7 @@ Plugin::Plugin(Core * core, const std::string & filepath, const std::string & _f
plugin_shutdown = 0; plugin_shutdown = 0;
plugin_status = 0; plugin_status = 0;
plugin_onupdate = 0; plugin_onupdate = 0;
plugin_onstatechange = 0;
state = PS_UNLOADED; state = PS_UNLOADED;
access = new RefLock(); access = new RefLock();
} }
@ -192,6 +193,7 @@ bool Plugin::load()
plugin_status = (command_result (*)(Core *, std::string &)) LookupPlugin(plug, "plugin_status"); plugin_status = (command_result (*)(Core *, std::string &)) LookupPlugin(plug, "plugin_status");
plugin_onupdate = (command_result (*)(Core *)) LookupPlugin(plug, "plugin_onupdate"); plugin_onupdate = (command_result (*)(Core *)) LookupPlugin(plug, "plugin_onupdate");
plugin_shutdown = (command_result (*)(Core *)) LookupPlugin(plug, "plugin_shutdown"); plugin_shutdown = (command_result (*)(Core *)) LookupPlugin(plug, "plugin_shutdown");
plugin_onstatechange = (command_result (*)(Core *, state_change_event)) LookupPlugin(plug, "plugin_onstatechange");
//name = _PlugName(); //name = _PlugName();
plugin_lib = plug; plugin_lib = plug;
if(plugin_init(&c,commands) == CR_OK) if(plugin_init(&c,commands) == CR_OK)
@ -299,6 +301,19 @@ command_result Plugin::on_update()
return cr; 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 Plugin::plugin_state Plugin::getState() const
{ {
return state; return state;
@ -370,6 +385,15 @@ void PluginManager::OnUpdate( void )
all_plugins[i]->on_update(); 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! // FIXME: doesn't check name collisions!
void PluginManager::registerCommands( Plugin * p ) void PluginManager::registerCommands( Plugin * p )
{ {

@ -134,6 +134,8 @@ namespace DFHack
/// returns a named pointer. /// returns a named pointer.
void *GetData(std::string key); void *GetData(std::string key);
bool isWorldLoaded() { return (last_world_data_ptr != NULL); }
DFHack::Process * p; DFHack::Process * p;
DFHack::VersionInfo * vinfo; DFHack::VersionInfo * vinfo;
DFHack::Console con; DFHack::Console con;
@ -184,6 +186,7 @@ namespace DFHack
bool hotkey_set; bool hotkey_set;
tthread::mutex * HotkeyMutex; tthread::mutex * HotkeyMutex;
tthread::condition_variable * HotkeyCond; tthread::condition_variable * HotkeyCond;
void *last_world_data_ptr; // for state change tracking
// Very important! // Very important!
bool started; bool started;

@ -46,6 +46,11 @@ namespace DFHack
CR_FAILURE = 0, CR_FAILURE = 0,
CR_OK = 1 CR_OK = 1
}; };
enum state_change_event
{
SC_GAME_LOADED,
SC_GAME_UNLOADED
};
struct PluginCommand struct PluginCommand
{ {
/// create a command with a name, description, function pointer to its code /// 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(DFHack::Core* core, const std::string& filepath, const std::string& filename, PluginManager * pm);
~Plugin(); ~Plugin();
command_result on_update(); command_result on_update();
command_result on_state_change(state_change_event event);
public: public:
bool load(); bool load();
bool unload(); bool unload();
@ -117,6 +123,7 @@ namespace DFHack
command_result (*plugin_status)(Core *, std::string &); command_result (*plugin_status)(Core *, std::string &);
command_result (*plugin_shutdown)(Core *); command_result (*plugin_shutdown)(Core *);
command_result (*plugin_onupdate)(Core *); command_result (*plugin_onupdate)(Core *);
command_result (*plugin_onstatechange)(Core *, state_change_event);
}; };
class DFHACK_EXPORT PluginManager class DFHACK_EXPORT PluginManager
{ {
@ -126,6 +133,7 @@ namespace DFHack
PluginManager(Core * core); PluginManager(Core * core);
~PluginManager(); ~PluginManager();
void OnUpdate( void ); void OnUpdate( void );
void OnStateChange( state_change_event event );
void registerCommands( Plugin * p ); void registerCommands( Plugin * p );
void unregisterCommands( Plugin * p ); void unregisterCommands( Plugin * p );
// PUBLIC METHODS // PUBLIC METHODS

@ -288,10 +288,32 @@ DFhackCExport DFHack::command_result plugin_init(DFHack::Core* pCore, std::vecto
return DFHack::CR_OK; 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) 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::Core& core = *pCore;
DFHack::World *w = core.getWorld(); DFHack::World *w = core.getWorld();
DFHack::t_gamemodes gm; DFHack::t_gamemodes gm;