diff --git a/Readme.rst b/Readme.rst index 42ef41da3..d6ffcde23 100644 --- a/Readme.rst +++ b/Readme.rst @@ -209,6 +209,25 @@ or is a prefix ending at a '/' boundary would be considered for execution, i.e. for context ``foo/bar/baz``, possible matches are any of ``@foo/bar/baz``, ``@foo/bar``, ``@foo`` or none. +Enabling plugins +================ + +Many plugins can be in a distinct enabled or disabled state. Some of +them activate and deactivate automatically depending on the contents +of the world raws. Others store their state in world data. However a +number of them have to be enabled globally, and the init file is the +right place to do it. + +Most of such plugins support the built-in ``enable`` and ``disable`` +commands. Calling them at any time without arguments prints a list +of enabled and disabled plugins, and shows whether that can be changed +through the same commands. + +To enable or disable plugins that support this, use their names as +arguments for the command:: + + enable manipulator search + ======== Commands diff --git a/dfhack.init-example b/dfhack.init-example index b07603cc5..05fd020bc 100644 --- a/dfhack.init-example +++ b/dfhack.init-example @@ -150,8 +150,24 @@ tweak military-training # prevent crash if bees die in a hive with ungathered products by insta-gathering them tweak hive-crash -# enable autoSyndrome -autoSyndrome enable +########################### +# Globally acting plugins # +########################### + +# Dwarf Manipulator (simple in-game Dwarf Therapist replacement) +enable manipulator + +# Search tool in various screens (by falconne) +enable search + +# Improved build material selection interface (by falconne) +enable automaterial + +# Other interface improvement tools +#enable dwarfmonitor mousequery autotrade buildingplan resume zone + +# Auto Syndrome +#autoSyndrome enable ########### # Scripts # diff --git a/library/Core.cpp b/library/Core.cpp index 2b118e2ae..b8a5f4808 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -544,6 +544,56 @@ command_result Core::runCommand(color_ostream &con, const std::string &first, ve } } } + else if( first == "enable" || first == "disable" ) + { + CoreSuspender suspend; + bool enable = (first == "enable"); + + if(parts.size()) + { + command_result res = CR_OK; + + for (size_t i = 0; i < parts.size(); i++) + { + Plugin * plug = plug_mgr->getPluginByName(parts[i]); + + if(!plug) + { + res = CR_NOT_FOUND; + con.printerr("No such plugin: %s\n", parts[i].c_str()); + } + else if (!plug->can_set_enabled()) + { + res = CR_NOT_IMPLEMENTED; + con.printerr("Cannot %s plugin: %s\n", first.c_str(), parts[i].c_str()); + } + else + { + res = plug->set_enabled(con, enable); + + if (res != CR_OK || plug->is_enabled() != enable) + con.printerr("Could not %s plugin: %s\n", first.c_str(), parts[i].c_str()); + } + } + + return res; + } + else + { + for(size_t i = 0; i < plug_mgr->size();i++) + { + Plugin * plug = (plug_mgr->operator[](i)); + if (!plug->can_be_enabled()) continue; + + con.print( + "%20s\t%-3s%s\n", + (plug->getName()+":").c_str(), + plug->is_enabled() ? "on" : "off", + plug->can_set_enabled() ? "" : " (controlled elsewhere)" + ); + } + } + } else if(first == "ls" || first == "dir") { bool all = false; @@ -584,6 +634,7 @@ command_result Core::runCommand(color_ostream &con, const std::string &first, ve " load PLUGIN|all - Load a plugin by name or load all possible plugins.\n" " unload PLUGIN|all - Unload a plugin or all loaded plugins.\n" " reload PLUGIN|all - Reload a plugin or all loaded plugins.\n" + " enable/disable PLUGIN - Enable or disable a plugin if supported.\n" "\n" "plugins:\n" ); diff --git a/library/PluginManager.cpp b/library/PluginManager.cpp index d5636109b..3ef4910cb 100644 --- a/library/PluginManager.cpp +++ b/library/PluginManager.cpp @@ -172,6 +172,8 @@ Plugin::Plugin(Core * core, const std::string & filepath, const std::string & _f plugin_onupdate = 0; plugin_onstatechange = 0; plugin_rpcconnect = 0; + plugin_enable = 0; + plugin_is_enabled = 0; state = PS_UNLOADED; access = new RefLock(); } @@ -245,6 +247,8 @@ bool Plugin::load(color_ostream &con) plugin_shutdown = (command_result (*)(color_ostream &)) LookupPlugin(plug, "plugin_shutdown"); plugin_onstatechange = (command_result (*)(color_ostream &, state_change_event)) LookupPlugin(plug, "plugin_onstatechange"); plugin_rpcconnect = (RPCService* (*)(color_ostream &)) LookupPlugin(plug, "plugin_rpcconnect"); + plugin_enable = (command_result (*)(color_ostream &,bool)) LookupPlugin(plug, "plugin_enable"); + plugin_is_enabled = (bool*) LookupPlugin(plug, "plugin_is_enabled"); plugin_eval_ruby = (command_result (*)(color_ostream &, const char*)) LookupPlugin(plug, "plugin_eval_ruby"); index_lua(plug); this->name = *plug_name; @@ -254,11 +258,15 @@ bool Plugin::load(color_ostream &con) { state = PS_LOADED; parent->registerCommands(this); + if ((plugin_onupdate || plugin_enable) && !plugin_is_enabled) + con.printerr("Plugin %s has no enabled var!\n", name.c_str()); return true; } else { con.printerr("Plugin %s has failed to initialize properly.\n", filename.c_str()); + plugin_is_enabled = 0; + plugin_onupdate = 0; reset_lua(); ClosePlugin(plugin_lib); state = PS_BROKEN; @@ -294,6 +302,8 @@ bool Plugin::unload(color_ostream &con) if(plugin_shutdown) cr = plugin_shutdown(con); // cleanup... + plugin_is_enabled = 0; + plugin_onupdate = 0; reset_lua(); parent->unregisterCommands(this); commands.clear(); @@ -408,6 +418,12 @@ bool Plugin::can_invoke_hotkey(const std::string & command, df::viewscreen *top command_result Plugin::on_update(color_ostream &out) { + // Check things that are implicitly protected by the suspend lock + if (!plugin_onupdate) + return CR_NOT_IMPLEMENTED; + if (plugin_is_enabled && !*plugin_is_enabled) + return CR_OK; + // Grab mutex and call the thing command_result cr = CR_NOT_IMPLEMENTED; access->lock_add(); if(state == PS_LOADED && plugin_onupdate) @@ -419,6 +435,21 @@ command_result Plugin::on_update(color_ostream &out) return cr; } +command_result Plugin::set_enabled(color_ostream &out, bool enable) +{ + command_result cr = CR_NOT_IMPLEMENTED; + access->lock_add(); + if(state == PS_LOADED && plugin_is_enabled && plugin_enable) + { + cr = plugin_enable(out, enable); + + if (cr == CR_OK && enable != is_enabled()) + cr = CR_FAILURE; + } + access->lock_sub(); + return cr; +} + command_result Plugin::on_state_change(color_ostream &out, state_change_event event) { command_result cr = CR_NOT_IMPLEMENTED; @@ -524,6 +555,37 @@ void Plugin::reset_lua() } } +int Plugin::lua_is_enabled(lua_State *state) +{ + auto obj = (Plugin*)lua_touserdata(state, lua_upvalueindex(1)); + + RefAutoinc lock(obj->access); + if (obj->state == PS_LOADED && obj->plugin_is_enabled) + lua_pushboolean(state, obj->is_enabled()); + else + lua_pushnil(state); + + return 1; +} + +int Plugin::lua_set_enabled(lua_State *state) +{ + lua_settop(state, 1); + bool val = lua_toboolean(state, 1); + + auto obj = (Plugin*)lua_touserdata(state, lua_upvalueindex(1)); + RefAutoinc lock(obj->access); + + color_ostream *out = Lua::GetOutput(state); + + if (obj->state == PS_LOADED && obj->plugin_enable) + lua_pushboolean(state, obj->set_enabled(*out, val) == CR_OK); + else + luaL_error(state, "plugin %s unloaded, cannot enable or disable", obj->name.c_str()); + + return 1; +} + int Plugin::lua_cmd_wrapper(lua_State *state) { auto cmd = (LuaCommand*)lua_touserdata(state, lua_upvalueindex(1)); @@ -561,6 +623,19 @@ void Plugin::open_lua(lua_State *state, int table) RefAutolock lock(access); + if (plugin_is_enabled) + { + lua_pushlightuserdata(state, this); + lua_pushcclosure(state, lua_is_enabled, 1); + lua_setfield(state, table, "isEnabled"); + } + if (plugin_enable) + { + lua_pushlightuserdata(state, this); + lua_pushcclosure(state, lua_set_enabled, 1); + lua_setfield(state, table, "setEnabled"); + } + for (auto it = lua_commands.begin(); it != lua_commands.end(); ++it) { lua_pushlightuserdata(state, it->second); diff --git a/library/include/PluginManager.h b/library/include/PluginManager.h index 46a46f2df..506ca33c0 100644 --- a/library/include/PluginManager.h +++ b/library/include/PluginManager.h @@ -144,6 +144,11 @@ namespace DFHack bool unload(color_ostream &out); bool reload(color_ostream &out); + bool can_be_enabled() { return plugin_is_enabled != 0; } + bool is_enabled() { return plugin_is_enabled && *plugin_is_enabled; } + bool can_set_enabled() { return plugin_is_enabled != 0 && plugin_enable; } + command_result set_enabled(color_ostream &out, bool enable); + command_result invoke(color_ostream &out, const std::string & command, std::vector & parameters); bool can_invoke_hotkey(const std::string & command, df::viewscreen *top ); plugin_state getState () const; @@ -184,17 +189,22 @@ namespace DFHack static int lua_fun_wrapper(lua_State *state); void push_function(lua_State *state, LuaFunction *fn); + static int lua_is_enabled(lua_State *state); + static int lua_set_enabled(lua_State *state); + struct LuaEvent; std::map lua_events; void index_lua(DFLibrary *lib); void reset_lua(); + bool *plugin_is_enabled; command_result (*plugin_init)(color_ostream &, std::vector &); command_result (*plugin_status)(color_ostream &, std::string &); command_result (*plugin_shutdown)(color_ostream &); command_result (*plugin_onupdate)(color_ostream &); command_result (*plugin_onstatechange)(color_ostream &, state_change_event); + command_result (*plugin_enable)(color_ostream &, bool); RPCService* (*plugin_rpcconnect)(color_ostream &); command_result (*plugin_eval_ruby)(color_ostream &, const char*); }; @@ -250,6 +260,10 @@ namespace DFHack DFhackDataExport const char * name = plugin_name;\ DFhackDataExport Plugin *plugin_self = NULL; +#define DFHACK_PLUGIN_IS_ENABLED(varname) \ + DFhackDataExport bool plugin_is_enabled = false; \ + bool &varname = plugin_is_enabled; + #define DFHACK_PLUGIN_LUA_COMMANDS \ DFhackCExport const DFHack::CommandReg plugin_lua_commands[] = #define DFHACK_PLUGIN_LUA_FUNCTIONS \ diff --git a/plugins/add-spatter.cpp b/plugins/add-spatter.cpp index f7a611ec8..b915845fb 100644 --- a/plugins/add-spatter.cpp +++ b/plugins/add-spatter.cpp @@ -48,6 +48,7 @@ using df::global::ui; typedef df::reaction_product_item_improvementst improvement_product; DFHACK_PLUGIN("add-spatter"); +DFHACK_PLUGIN_IS_ENABLED(is_enabled); struct ReagentSource { int idx; @@ -390,6 +391,7 @@ static bool find_reactions(color_ostream &out) static void enable_hooks(bool enable) { + is_enabled = enable; INTERPOSE_HOOK(item_hook, isImprovable).apply(enable); INTERPOSE_HOOK(product_hook, produce).apply(enable); } diff --git a/plugins/advtools.cpp b/plugins/advtools.cpp index 5ceea69c8..ad50dbe5d 100644 --- a/plugins/advtools.cpp +++ b/plugins/advtools.cpp @@ -99,7 +99,7 @@ DFhackCExport command_result plugin_shutdown ( color_ostream &out ) df::nemesis_record *getPlayerNemesis(color_ostream &out, bool restore_swap); -static bool in_transient_swap = false; +DFHACK_PLUGIN_IS_ENABLED(in_transient_swap); DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_change_event event) { diff --git a/plugins/autoSyndrome.cpp b/plugins/autoSyndrome.cpp index 43b0b47fb..244e759f8 100644 --- a/plugins/autoSyndrome.cpp +++ b/plugins/autoSyndrome.cpp @@ -98,7 +98,7 @@ reaction_duck Next, start a new fort in a new world, build a duck workshop, then have someone become a duck. */ -bool enabled = false; +DFHACK_PLUGIN_IS_ENABLED(enabled); DFHACK_PLUGIN("autoSyndrome"); @@ -139,37 +139,45 @@ DFhackCExport command_result plugin_shutdown(color_ostream& out) { return CR_OK; }*/ +DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) +{ + if (enabled == enable) + return CR_OK; + + enabled = enable; + + Plugin* me = Core::getInstance().getPluginManager()->getPluginByName("autoSyndrome"); + if ( enabled ) { + EventManager::EventHandler handle(processJob, 5); + EventManager::registerListener(EventManager::EventType::JOB_COMPLETED, handle, me); + } else { + EventManager::unregisterAll(me); + } + + return CR_OK; +} + command_result autoSyndrome(color_ostream& out, vector& parameters) { if ( parameters.size() > 1 ) return CR_WRONG_USAGE; - bool wasEnabled = enabled; + bool enable = false; if ( parameters.size() == 1 ) { if ( parameters[0] == "enable" ) { - enabled = true; + enable = true; } else if ( parameters[0] == "disable" ) { - enabled = false; + enable = false; } else { int32_t a = atoi(parameters[0].c_str()); if ( a < 0 || a > 1 ) return CR_WRONG_USAGE; - enabled = (bool)a; + enable = (bool)a; } } - out.print("autoSyndrome is %s\n", enabled ? "enabled" : "disabled"); - if ( enabled == wasEnabled ) - return CR_OK; - - Plugin* me = Core::getInstance().getPluginManager()->getPluginByName("autoSyndrome"); - if ( enabled ) { - EventManager::EventHandler handle(processJob, 5); - EventManager::registerListener(EventManager::EventType::JOB_COMPLETED, handle, me); - } else { - EventManager::unregisterAll(me); - } - return CR_OK; + out.print("autoSyndrome is %s\n", enable ? "enabled" : "disabled"); + return plugin_enable(out, enable); } bool maybeApply(color_ostream& out, df::syndrome* syndrome, int32_t workerId, df::unit* unit) { diff --git a/plugins/autolabor.cpp b/plugins/autolabor.cpp index b1293055f..738dc7c66 100644 --- a/plugins/autolabor.cpp +++ b/plugins/autolabor.cpp @@ -76,7 +76,7 @@ using df::global::world; * (mining, hunting, and woodcutting) need to be handled carefully to minimize churn. */ -static int enable_autolabor = 0; +DFHACK_PLUGIN_IS_ENABLED(enable_autolabor); static bool print_debug = 0; @@ -535,6 +535,7 @@ static void setOptionEnabled(ConfigFlags flag, bool on) static void cleanup_state() { + enable_autolabor = false; labor_infos.clear(); } @@ -1297,6 +1298,27 @@ void print_labor (df::unit_labor labor, color_ostream &out) } } +DFhackCExport command_result plugin_enable ( color_ostream &out, bool enable ) +{ + if (!Core::getInstance().isWorldLoaded()) { + out.printerr("World is not loaded: please load a game first.\n"); + return CR_FAILURE; + } + + if (enable && !enable_autolabor) + { + enable_plugin(out); + } + else if(!enable && enable_autolabor) + { + enable_autolabor = false; + setOptionEnabled(CF_ENABLED, false); + + out << "Autolabor is disabled." << endl; + } + + return CR_OK; +} command_result autolabor (color_ostream &out, std::vector & parameters) { @@ -1312,19 +1334,8 @@ command_result autolabor (color_ostream &out, std::vector & parame parameters[0] == "1" || parameters[0] == "disable")) { bool enable = (parameters[0] == "1" || parameters[0] == "enable"); - if (enable && !enable_autolabor) - { - enable_plugin(out); - } - else if(!enable && enable_autolabor) - { - enable_autolabor = false; - setOptionEnabled(CF_ENABLED, false); - out << "The plugin is disabled." << endl; - } - - return CR_OK; + return plugin_enable(out, enable); } else if (parameters.size() == 2 && parameters[0] == "haulpct") { diff --git a/plugins/automaterial.cpp b/plugins/automaterial.cpp index 16b258a02..848d02bc2 100644 --- a/plugins/automaterial.cpp +++ b/plugins/automaterial.cpp @@ -1179,11 +1179,27 @@ color_ostream_proxy console_out(Core::getInstance().getConsole()); IMPLEMENT_VMETHOD_INTERPOSE(jobutils_hook, feed); IMPLEMENT_VMETHOD_INTERPOSE(jobutils_hook, render); -DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) +DFHACK_PLUGIN_IS_ENABLED(is_enabled); + +DFhackCExport command_result plugin_enable ( color_ostream &out, bool enable) { - if (!gps || !INTERPOSE_HOOK(jobutils_hook, feed).apply() || !INTERPOSE_HOOK(jobutils_hook, render).apply()) - out.printerr("Could not insert jobutils hooks!\n"); + if (!gps) + return CR_FAILURE; + + if (enable != is_enabled) + { + if (!INTERPOSE_HOOK(jobutils_hook, feed).apply(enable) || + !INTERPOSE_HOOK(jobutils_hook, render).apply(enable)) + return CR_FAILURE; + + is_enabled = enable; + } + return CR_OK; +} + +DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) +{ hotkeys[construction_type::Wall] = df::interface_key::HOTKEY_BUILDING_CONSTRUCTION_WALL; hotkeys[construction_type::Floor] = df::interface_key::HOTKEY_BUILDING_CONSTRUCTION_FLOOR; hotkeys[construction_type::Ramp] = df::interface_key::HOTKEY_BUILDING_CONSTRUCTION_RAMP; diff --git a/plugins/autotrade.cpp b/plugins/autotrade.cpp index 62f7c05c0..2d3cf0ed2 100644 --- a/plugins/autotrade.cpp +++ b/plugins/autotrade.cpp @@ -583,7 +583,6 @@ static command_result autotrade_cmd(color_ostream &out, vector & parame return CR_OK; } - DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_change_event event) { switch (event) @@ -600,11 +599,30 @@ DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_chan return CR_OK; } -DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) +DFHACK_PLUGIN_IS_ENABLED(is_enabled); + +DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) { - if (!gps || !INTERPOSE_HOOK(trade_hook, feed).apply() || !INTERPOSE_HOOK(trade_hook, render).apply()) - out.printerr("Could not insert autotrade hooks!\n"); + if (!gps) + return CR_FAILURE; + + if (enable != is_enabled) + { + depot_info.reset(); + monitor.reset(); + + if (!INTERPOSE_HOOK(trade_hook, feed).apply(enable) || + !INTERPOSE_HOOK(trade_hook, render).apply(enable)) + return CR_FAILURE; + is_enabled = enable; + } + + return CR_OK; +} + +DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) +{ commands.push_back( PluginCommand( "autotrade", "Automatically send items in marked stockpiles to trade depot, when trading is possible.", diff --git a/plugins/buildingplan.cpp b/plugins/buildingplan.cpp index 810314bc1..70a324423 100644 --- a/plugins/buildingplan.cpp +++ b/plugins/buildingplan.cpp @@ -1153,12 +1153,29 @@ static command_result buildingplan_cmd(color_ostream &out, vector & par return CR_OK; } +DFHACK_PLUGIN_IS_ENABLED(is_enabled); -DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) +DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) { - if (!gps || !INTERPOSE_HOOK(buildingplan_hook, feed).apply() || !INTERPOSE_HOOK(buildingplan_hook, render).apply()) - out.printerr("Could not insert buildingplan hooks!\n"); + if (!gps) + return CR_FAILURE; + + if (enable != is_enabled) + { + planner.reset(out); + + if (!INTERPOSE_HOOK(buildingplan_hook, feed).apply(enable) || + !INTERPOSE_HOOK(buildingplan_hook, render).apply(enable)) + return CR_FAILURE; + + is_enabled = enable; + } + + return CR_OK; +} +DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) +{ commands.push_back( PluginCommand( "buildingplan", "Place furniture before it's built", diff --git a/plugins/burrows.cpp b/plugins/burrows.cpp index edcc01ecf..32a76ba0c 100644 --- a/plugins/burrows.cpp +++ b/plugins/burrows.cpp @@ -221,7 +221,8 @@ static void detect_digging(color_ostream &out) } } -static bool active = false; +DFHACK_PLUGIN_IS_ENABLED(active); + static bool auto_grow = false; static std::vector grow_burrows; diff --git a/plugins/devel/autolabor2.cpp b/plugins/devel/autolabor2.cpp index e41ba541b..621f41be0 100644 --- a/plugins/devel/autolabor2.cpp +++ b/plugins/devel/autolabor2.cpp @@ -76,7 +76,7 @@ using df::global::world; #define ARRAY_COUNT(array) (sizeof(array)/sizeof((array)[0])) -static int enable_autolabor = 0; +DFHACK_PLUGIN_IS_ENABLED(enable_autolabor); static bool print_debug = 0; @@ -1375,6 +1375,7 @@ static void setOptionEnabled(ConfigFlags flag, bool on) static void cleanup_state() { + enable_autolabor = false; labor_infos.clear(); } @@ -2384,6 +2385,27 @@ df::unit_labor lookup_labor_by_name (std::string& name) return labor; } +DFhackCExport command_result plugin_enable ( color_ostream &out, bool enable ) +{ + if (!Core::getInstance().isWorldLoaded()) { + out.printerr("World is not loaded: please load a game first.\n"); + return CR_FAILURE; + } + + if (enable && !enable_autolabor) + { + enable_plugin(out); + } + else if(!enable && enable_autolabor) + { + enable_autolabor = false; + setOptionEnabled(CF_ENABLED, false); + + out << "Autolabor is disabled." << endl; + } + + return CR_OK; +} command_result autolabor (color_ostream &out, std::vector & parameters) { @@ -2398,19 +2420,7 @@ command_result autolabor (color_ostream &out, std::vector & parame (parameters[0] == "enable" || parameters[0] == "disable")) { bool enable = (parameters[0] == "enable"); - if (enable && !enable_autolabor) - { - enable_plugin(out); - } - else if(!enable && enable_autolabor) - { - enable_autolabor = false; - setOptionEnabled(CF_ENABLED, false); - - out << "The plugin is disabled." << endl; - } - - return CR_OK; + return plugin_enable(out, enable); } else if (parameters.size() == 3 && (parameters[0] == "max" || parameters[0] == "priority")) diff --git a/plugins/devel/kittens.cpp b/plugins/devel/kittens.cpp index b610d4742..df0f3b947 100644 --- a/plugins/devel/kittens.cpp +++ b/plugins/devel/kittens.cpp @@ -16,6 +16,8 @@ using std::vector; using std::string; using namespace DFHack; +DFHACK_PLUGIN_IS_ENABLED(is_enabled); + //FIXME: possible race conditions with calling kittens from the IO thread and shutdown from Core. bool shutdown_flag = false; bool final_flag = true; @@ -141,6 +143,7 @@ command_result trackmenu (color_ostream &out, vector & parameters) if(df::global::ui) { trackmenu_flg = true; + is_enabled = true; last_menu = df::global::ui->main.mode; out.print("Menu: %d\n",last_menu); return CR_OK; @@ -155,6 +158,7 @@ command_result trackmenu (color_ostream &out, vector & parameters) command_result trackpos (color_ostream &out, vector & parameters) { trackpos_flg = !trackpos_flg; + is_enabled = true; return CR_OK; } @@ -214,6 +218,7 @@ command_result ktimer (color_ostream &out, vector & parameters) // harmless potential data race here... timeLast = timeend; timering = true; + is_enabled = true; return CR_OK; } diff --git a/plugins/devel/memview.cpp b/plugins/devel/memview.cpp index a43e6a7bf..6a4baa295 100644 --- a/plugins/devel/memview.cpp +++ b/plugins/devel/memview.cpp @@ -15,6 +15,8 @@ using namespace DFHack; uint64_t timeLast=0; static tthread::mutex* mymutex=0; +DFHACK_PLUGIN_IS_ENABLED(is_enabled); + struct memory_data { void * addr; @@ -96,6 +98,7 @@ void Deinit() { if(memdata.state==STATE_ON) { + is_enabled = false; memdata.state=STATE_OFF; delete [] memdata.buf; delete [] memdata.lbuf; @@ -140,6 +143,7 @@ command_result memview (color_ostream &out, vector & parameters) { Deinit(); memdata.state=STATE_OFF; + is_enabled = false; mymutex->unlock(); return CR_OK; } @@ -156,6 +160,7 @@ command_result memview (color_ostream &out, vector & parameters) mymutex->unlock(); return CR_OK; } + is_enabled = true; memdata.state=STATE_ON; } if(parameters.size()>1) diff --git a/plugins/devel/nestboxes.cpp b/plugins/devel/nestboxes.cpp index 8c51b57ae..f4f423515 100644 --- a/plugins/devel/nestboxes.cpp +++ b/plugins/devel/nestboxes.cpp @@ -31,7 +31,7 @@ static command_result nestboxes(color_ostream &out, vector & parameters DFHACK_PLUGIN("nestboxes"); -static bool enabled = false; +DFHACK_PLUGIN_IS_ENABLED(enabled); static void eggscan(color_ostream &out) { @@ -97,6 +97,12 @@ DFhackCExport command_result plugin_onupdate(color_ostream &out) return CR_OK; } +DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) +{ + enabled = enable; + return CR_OK; +} + static command_result nestboxes(color_ostream &out, vector & parameters) { CoreSuspender suspend; diff --git a/plugins/devel/vshook.cpp b/plugins/devel/vshook.cpp index ceec2d08d..025bb2b1d 100644 --- a/plugins/devel/vshook.cpp +++ b/plugins/devel/vshook.cpp @@ -23,6 +23,8 @@ using df::global::gps; DFHACK_PLUGIN("vshook"); +DFHACK_PLUGIN_IS_ENABLED(is_enabled); + struct title_hook : df::viewscreen_titlest { typedef df::viewscreen_titlest interpose_base; @@ -37,17 +39,30 @@ struct title_hook : df::viewscreen_titlest { IMPLEMENT_VMETHOD_INTERPOSE(title_hook, render); -DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) +DFhackCExport command_result plugin_enable ( color_ostream &out, bool enable) { - if (gps) + if (!gps) + return CR_FAILURE; + + if (enable != is_enabled) { - if (!INTERPOSE_HOOK(title_hook, render).apply()) - out.printerr("Could not interpose viewscreen_titlest::render\n"); + if (!INTERPOSE_HOOK(title_hook, render).apply(enable)) + return CR_FAILURE; + + is_enabled = enable; } return CR_OK; } +DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) +{ + // DON'T DO THIS IN NON-EXAMPLE PLUGINS + plugin_enable(out, true); + + return CR_OK; +} + DFhackCExport command_result plugin_shutdown ( color_ostream &out ) { INTERPOSE_HOOK(title_hook, render).remove(); diff --git a/plugins/dwarfmonitor.cpp b/plugins/dwarfmonitor.cpp index 6ff62253a..883f0a002 100644 --- a/plugins/dwarfmonitor.cpp +++ b/plugins/dwarfmonitor.cpp @@ -1179,11 +1179,15 @@ IMPLEMENT_VMETHOD_INTERPOSE(dwarf_monitor_hook, feed); IMPLEMENT_VMETHOD_INTERPOSE(dwarf_monitor_hook, render); DFHACK_PLUGIN("dwarfmonitor"); +DFHACK_PLUGIN_IS_ENABLED(is_enabled); static bool set_monitoring_mode(const string &mode, const bool &state) { bool mode_recognized = false; + if (!is_enabled) + return false; + if (mode == "work" || mode == "all") { mode_recognized = true; @@ -1201,6 +1205,24 @@ static bool set_monitoring_mode(const string &mode, const bool &state) return mode_recognized; } +DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) +{ + if (!gps) + return CR_FAILURE; + + if (is_enabled != enable) + { + if (!INTERPOSE_HOOK(dwarf_monitor_hook, feed).apply(enable) || + !INTERPOSE_HOOK(dwarf_monitor_hook, render).apply(enable)) + return CR_FAILURE; + + reset(); + is_enabled = enable; + } + + return CR_OK; +} + static command_result dwarfmonitor_cmd(color_ostream &out, vector & parameters) { bool show_help = false; @@ -1222,6 +1244,9 @@ static command_result dwarfmonitor_cmd(color_ostream &out, vector & par } else if ((cmd == 'e' || cmd == 'E') && !mode.empty()) { + if (!is_enabled) + plugin_enable(out, true); + if (set_monitoring_mode(mode, true)) { out << "Monitoring enabled: " << mode << endl; @@ -1257,9 +1282,6 @@ static command_result dwarfmonitor_cmd(color_ostream &out, vector & par DFhackCExport command_result plugin_init(color_ostream &out, std::vector &commands) { - if (!gps || !INTERPOSE_HOOK(dwarf_monitor_hook, feed).apply() || !INTERPOSE_HOOK(dwarf_monitor_hook, render).apply()) - out.printerr("Could not insert dwarfmonitor hooks!\n"); - activity_labels[JOB_IDLE] = "Idle"; activity_labels[JOB_MILITARY] = "Military Duty"; activity_labels[JOB_LEISURE] = "Leisure"; diff --git a/plugins/fastdwarf.cpp b/plugins/fastdwarf.cpp index 6292fc85e..2f7d674eb 100644 --- a/plugins/fastdwarf.cpp +++ b/plugins/fastdwarf.cpp @@ -19,6 +19,8 @@ using df::global::world; // dfhack interface DFHACK_PLUGIN("fastdwarf"); +DFHACK_PLUGIN_IS_ENABLED(active); + static bool enable_fastdwarf = false; static bool enable_teledwarf = false; @@ -152,6 +154,8 @@ static command_result fastdwarf (color_ostream &out, vector & parameter return CR_WRONG_USAGE; } + active = enable_fastdwarf || enable_teledwarf; + out.print("Current state: fast = %d, teleport = %d.\n", (df::global::debug_turbospeed && *df::global::debug_turbospeed) ? 2 : (enable_fastdwarf ? 1 : 0), enable_teledwarf ? 1 : 0); @@ -159,6 +163,17 @@ static command_result fastdwarf (color_ostream &out, vector & parameter return CR_OK; } +DFhackCExport command_result plugin_enable ( color_ostream &out, bool enable ) +{ + if (active != enable) + { + active = enable_fastdwarf = enable; + enable_teledwarf = false; + } + + return CR_OK; +} + DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) { commands.push_back(PluginCommand("fastdwarf", diff --git a/plugins/fix-armory.cpp b/plugins/fix-armory.cpp index 5a4821b4b..a217c1a04 100644 --- a/plugins/fix-armory.cpp +++ b/plugins/fix-armory.cpp @@ -698,7 +698,7 @@ static void try_store_ammo(df::squad *squad) } } -static bool is_enabled = false; +DFHACK_PLUGIN_IS_ENABLED(is_enabled); DFhackCExport command_result plugin_onupdate(color_ostream &out, state_change_event event) { @@ -810,6 +810,21 @@ DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_chan return CR_OK; } +DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) +{ + if (!Core::getInstance().isWorldLoaded()) { + out.printerr("World is not loaded: please load a game first.\n"); + return CR_FAILURE; + } + + if (enable) + enable_plugin(out); + else + disable_plugin(out); + + return CR_OK; +} + static command_result fix_armory(color_ostream &out, vector ¶meters) { CoreSuspender suspend; @@ -820,13 +835,9 @@ static command_result fix_armory(color_ostream &out, vector ¶meters string cmd = parameters[0]; if (cmd == "enable") - { - enable_plugin(out); - } + return plugin_enable(out, true); else if (cmd == "disable") - { - disable_plugin(out); - } + return plugin_enable(out, false); else return CR_WRONG_USAGE; diff --git a/plugins/follow.cpp b/plugins/follow.cpp index 5c14780a3..56a7cf3b2 100644 --- a/plugins/follow.cpp +++ b/plugins/follow.cpp @@ -24,6 +24,7 @@ int32_t prevX, prevY, prevZ; uint8_t prevMenuWidth; DFHACK_PLUGIN("follow"); +DFHACK_PLUGIN_IS_ENABLED(is_enabled); DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) { @@ -53,6 +54,7 @@ DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_chan followedUnit = 0; prevX=prevY=prevZ = -1; prevMenuWidth = 0; + is_enabled = false; break; default: break; @@ -97,6 +99,7 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out ) } else if((prevX != x || prevY != y || prevZ != z) && prevMenuWidth == menu_width) //User has manually moved the window, stop following the unit { + is_enabled = false; followedUnit = 0; prevX=prevY=prevZ = -1; prevMenuWidth = 0; @@ -146,6 +149,7 @@ command_result follow (color_ostream &out, std::vector & parameter followedUnit = Gui::getSelectedUnit(out); if (followedUnit) { + is_enabled = true; std::ostringstream ss; ss << "Unpause to begin following " << df::global::world->raws.creatures.all[followedUnit->race]->name[0]; if (followedUnit->name.has_name) ss << " " << followedUnit->name.first_name; @@ -153,5 +157,6 @@ command_result follow (color_ostream &out, std::vector & parameter out.print(ss.str().c_str()); } else followedUnit = 0; + is_enabled = (followedUnit != NULL); return CR_OK; } diff --git a/plugins/infiniteSky.cpp b/plugins/infiniteSky.cpp index 8750e5435..6405a5cf0 100644 --- a/plugins/infiniteSky.cpp +++ b/plugins/infiniteSky.cpp @@ -71,7 +71,7 @@ DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_chan */ static size_t constructionSize = 0; -static bool enabled = false; +DFHACK_PLUGIN_IS_ENABLED(enabled); void doInfiniteSky(color_ostream& out, int32_t howMany); DFhackCExport command_result plugin_onupdate ( color_ostream &out ) @@ -155,6 +155,12 @@ void doInfiniteSky(color_ostream& out, int32_t howMany) { } +DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) +{ + enabled = enable; + return CR_OK; +} + command_result infiniteSky (color_ostream &out, std::vector & parameters) { if ( parameters.size() > 1 ) diff --git a/plugins/manipulator.cpp b/plugins/manipulator.cpp index 88dc61726..57f134447 100644 --- a/plugins/manipulator.cpp +++ b/plugins/manipulator.cpp @@ -1209,10 +1209,27 @@ IMPLEMENT_VMETHOD_INTERPOSE(unitlist_hook, render); DFHACK_PLUGIN("manipulator"); +DFHACK_PLUGIN_IS_ENABLED(is_enabled); + +DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) +{ + if (!gps) + return CR_FAILURE; + + if (enable != is_enabled) + { + if (!INTERPOSE_HOOK(unitlist_hook, feed).apply(enable) || + !INTERPOSE_HOOK(unitlist_hook, render).apply(enable)) + return CR_FAILURE; + + is_enabled = enable; + } + + return CR_OK; +} + DFhackCExport command_result plugin_init ( color_ostream &out, vector &commands) { - if (!gps || !INTERPOSE_HOOK(unitlist_hook, feed).apply() || !INTERPOSE_HOOK(unitlist_hook, render).apply()) - out.printerr("Could not insert Dwarf Manipulator hooks!\n"); return CR_OK; } diff --git a/plugins/misery.cpp b/plugins/misery.cpp index a0c0a2390..cc69115db 100644 --- a/plugins/misery.cpp +++ b/plugins/misery.cpp @@ -15,6 +15,8 @@ using namespace std; using namespace DFHack; +DFHACK_PLUGIN_IS_ENABLED(is_enabled); + static int factor = 1; static map processedThoughtCountTable; @@ -38,6 +40,7 @@ DFhackCExport command_result plugin_onupdate(color_ostream& out) { if ( wasLoaded ) { //we just unloaded the game: clear all data factor = 1; + is_enabled = false; processedThoughtCountTable.clear(); fakeThoughts.clear(); wasLoaded = false; @@ -138,6 +141,17 @@ DFhackCExport command_result plugin_init(color_ostream& out, vector& parameters) { if ( !df::global::world || !df::global::world->map.block_index ) { out.printerr("misery can only be enabled in fortress mode with a fully-loaded game.\n"); @@ -153,15 +167,18 @@ command_result misery(color_ostream &out, vector& parameters) { return CR_WRONG_USAGE; } factor = 1; + is_enabled = false; return CR_OK; } else if ( parameters[0] == "enable" ) { + is_enabled = true; factor = 2; if ( parameters.size() == 2 ) { - factor = atoi(parameters[1].c_str()); - if ( factor < 1 ) { + int a = atoi(parameters[1].c_str()); + if ( a <= 1 ) { out.printerr("Second argument must be a positive integer.\n"); return CR_WRONG_USAGE; } + factor = a; } } else if ( parameters[0] == "clear" ) { for ( size_t a = 0; a < fakeThoughts.size(); a++ ) { @@ -176,6 +193,7 @@ command_result misery(color_ostream &out, vector& parameters) { return CR_WRONG_USAGE; } factor = a; + is_enabled = factor > 1; } return CR_OK; diff --git a/plugins/mode.cpp b/plugins/mode.cpp index d18cf7529..66fb488a6 100644 --- a/plugins/mode.cpp +++ b/plugins/mode.cpp @@ -33,12 +33,6 @@ DFhackCExport command_result plugin_shutdown ( color_ostream &out ) return CR_OK; } -DFhackCExport command_result plugin_onupdate ( color_ostream &out ) -{ - // add tracking here - return CR_OK; -} - void printCurrentModes(t_gamemodes gm, Console & con) { con << "Current game type:\t" << gm.g_type << " ("; diff --git a/plugins/mousequery.cpp b/plugins/mousequery.cpp index dfb89f6f4..97e703752 100644 --- a/plugins/mousequery.cpp +++ b/plugins/mousequery.cpp @@ -239,12 +239,28 @@ struct mousequery_hook : public df::viewscreen_dwarfmodest IMPLEMENT_VMETHOD_INTERPOSE(mousequery_hook, feed); DFHACK_PLUGIN("mousequery"); +DFHACK_PLUGIN_IS_ENABLED(is_enabled); -DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) +DFhackCExport command_result plugin_enable ( color_ostream &out, bool enable) { - if (!gps || !INTERPOSE_HOOK(mousequery_hook, feed).apply()) - out.printerr("Could not insert mousequery hooks!\n"); + if (!gps) + return CR_FAILURE; + + if (is_enabled != enable) + { + last_x = last_y = last_z = -1; + + if (!INTERPOSE_HOOK(mousequery_hook, feed).apply(enable)) + return CR_FAILURE; + + is_enabled = enable; + } + + return CR_OK; +} +DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) +{ last_x = last_y = last_z = -1; return CR_OK; diff --git a/plugins/power-meter.cpp b/plugins/power-meter.cpp index efda2c590..0f8135eed 100644 --- a/plugins/power-meter.cpp +++ b/plugins/power-meter.cpp @@ -160,7 +160,7 @@ IMPLEMENT_VMETHOD_INTERPOSE(trap_hook, getName); IMPLEMENT_VMETHOD_INTERPOSE(trap_hook, updateAction); IMPLEMENT_VMETHOD_INTERPOSE(trap_hook, drawBuilding); -static bool enabled = false; +DFHACK_PLUGIN_IS_ENABLED(enabled); static void enable_hooks(bool enable) { diff --git a/plugins/rename.cpp b/plugins/rename.cpp index bffb33111..fdebad1d3 100644 --- a/plugins/rename.cpp +++ b/plugins/rename.cpp @@ -55,6 +55,7 @@ DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_chan static command_result rename(color_ostream &out, vector & parameters); DFHACK_PLUGIN("rename"); +DFHACK_PLUGIN_IS_ENABLED(is_enabled); DFhackCExport command_result plugin_init (color_ostream &out, std::vector &commands) { @@ -174,6 +175,9 @@ KNOWN_BUILDINGS static bool enable_building_rename(char code, bool enable) { + if (enable) + is_enabled = true; + if (code == 'Z') INTERPOSE_HOOK(dwarf_render_zone_hook, render).apply(enable); @@ -189,6 +193,7 @@ KNOWN_BUILDINGS static void disable_building_rename() { + is_enabled = false; INTERPOSE_HOOK(dwarf_render_zone_hook, render).remove(); #define BUILDING(code, cname, tag) \ diff --git a/plugins/resume.cpp b/plugins/resume.cpp index e697a133f..9d37baac7 100644 --- a/plugins/resume.cpp +++ b/plugins/resume.cpp @@ -107,7 +107,7 @@ struct SuspendedBuilding } }; -static bool enabled = false; +DFHACK_PLUGIN_IS_ENABLED(enabled); static bool buildings_scanned = false; static vector suspended_buildings, resumed_buildings; @@ -234,6 +234,23 @@ struct resume_hook : public df::viewscreen_dwarfmodest IMPLEMENT_VMETHOD_INTERPOSE(resume_hook, render); +DFhackCExport command_result plugin_enable ( color_ostream &out, bool enable) +{ + if (!gps) + return CR_FAILURE; + + if (enabled != enable) + { + clear_scanned(); + + if (!INTERPOSE_HOOK(resume_hook, render).apply(enable)) + return CR_FAILURE; + + enabled = enable; + } + + return CR_OK; +} static command_result resume_cmd(color_ostream &out, vector & parameters) { @@ -251,12 +268,12 @@ static command_result resume_cmd(color_ostream &out, vector & parameter } else if (cmd == 's') { - enabled = true; + plugin_enable(out, true); out << "Overlay enabled" << endl; } else if (cmd == 'h') { - enabled = false; + plugin_enable(out, false); out << "Overlay disabled" << endl; } else if (cmd == 'a') @@ -275,12 +292,8 @@ static command_result resume_cmd(color_ostream &out, vector & parameter return CR_OK; } - DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) { - if (!gps || !INTERPOSE_HOOK(resume_hook, render).apply()) - out.printerr("Could not insert resume hooks!\n"); - commands.push_back( PluginCommand( "resume", "A plugin to help display and resume suspended constructions conveniently", diff --git a/plugins/reveal.cpp b/plugins/reveal.cpp index 8db7c9112..2c51295a8 100644 --- a/plugins/reveal.cpp +++ b/plugins/reveal.cpp @@ -85,6 +85,8 @@ DFhackCExport command_result plugin_init ( color_ostream &out, vector & parameters) nopause_state = 0; else nopause_state = 1; + is_active = nopause_state || (revealed == REVEALED); out.print("nopause %sactivated.\n", (nopause_state ? "" : "de")); } else @@ -237,6 +240,7 @@ command_result reveal(color_ostream &out, vector & params) else revealed = DEMON_REVEALED; } + is_active = nopause_state || (revealed == REVEALED); con.print("Map revealed.\n"); if(!no_hell) con.print("Unpausing can unleash the forces of hell, so it has been temporarily disabled.\n"); @@ -296,6 +300,7 @@ command_result unreveal(color_ostream &out, vector & params) // give back memory. hidesaved.clear(); revealed = NOT_REVEALED; + is_active = nopause_state || (revealed == REVEALED); con.print("Map hidden!\n"); return CR_OK; } @@ -490,6 +495,7 @@ command_result revforget(color_ostream &out, vector & params) // give back memory. hidesaved.clear(); revealed = NOT_REVEALED; + is_active = nopause_state || (revealed == REVEALED); con.print("Reveal data forgotten!\n"); return CR_OK; } diff --git a/plugins/search.cpp b/plugins/search.cpp index 541fc9506..bb903b408 100644 --- a/plugins/search.cpp +++ b/plugins/search.cpp @@ -1609,6 +1609,7 @@ IMPLEMENT_HOOKS(df::viewscreen_dwarfmodest, burrow_search); DFHACK_PLUGIN("search"); +DFHACK_PLUGIN_IS_ENABLED(is_enabled); #define SEARCH_HOOKS \ HOOK_ACTION(unitlist_search_hook) \ @@ -1624,15 +1625,28 @@ DFHACK_PLUGIN("search"); HOOK_ACTION(burrow_search_hook) \ HOOK_ACTION(stockpile_search_hook) -DFhackCExport command_result plugin_init ( color_ostream &out, vector &commands) +DFhackCExport command_result plugin_enable ( color_ostream &out, bool enable) { + if (!gps || !gview) + return CR_FAILURE; + + if (is_enabled != enable) + { #define HOOK_ACTION(hook) \ - !INTERPOSE_HOOK(hook, feed).apply() || \ - !INTERPOSE_HOOK(hook, render).apply() || + !INTERPOSE_HOOK(hook, feed).apply(enable) || \ + !INTERPOSE_HOOK(hook, render).apply(enable) || + + if (SEARCH_HOOKS 0) + return CR_FAILURE; + + is_enabled = enable; + } - if (!gps || !gview || SEARCH_HOOKS 0) - out.printerr("Could not insert Search hooks!\n"); + return CR_OK; +} +DFhackCExport command_result plugin_init ( color_ostream &out, vector &commands) +{ #undef HOOK_ACTION const string a[] = {"Meager Quarters", "Modest Quarters", "Quarters", "Decent Quarters", "Fine Quarters", "Great Bedroom", "Grand Bedroom", "Royal Bedroom"}; diff --git a/plugins/seedwatch.cpp b/plugins/seedwatch.cpp index ae87e4381..19fa9b154 100755 --- a/plugins/seedwatch.cpp +++ b/plugins/seedwatch.cpp @@ -22,7 +22,7 @@ using namespace df::enums; using df::global::world; const int buffer = 20; // seed number buffer - 20 is reasonable -bool running = false; // whether seedwatch is counting the seeds or not +DFHACK_PLUGIN_IS_ENABLED(running); // whether seedwatch is counting the seeds or not // abbreviations for the standard plants map abbreviations; @@ -96,6 +96,12 @@ string searchAbbreviations(string in) } }; +DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) +{ + running = enable; + return CR_OK; +} + command_result df_seedwatch(color_ostream &out, vector& parameters) { CoreSuspender suspend; diff --git a/plugins/siege-engine.cpp b/plugins/siege-engine.cpp index 4b2060e99..2d6f5fcdd 100644 --- a/plugins/siege-engine.cpp +++ b/plugins/siege-engine.cpp @@ -1766,7 +1766,7 @@ DFHACK_PLUGIN_LUA_COMMANDS { DFHACK_LUA_END }; -static bool is_enabled = false; +DFHACK_PLUGIN_IS_ENABLED(is_enabled); static void enable_hooks(bool enable) { @@ -1809,6 +1809,25 @@ static void clear_caches(color_ostream &out) } } +DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) +{ + if (gamemode && *gamemode != game_mode::DWARF) + return CR_FAILURE; + + if (enable != is_enabled) + { + if (enable) + enable_plugin(); + else + { + World::DeletePersistentData(World::GetPersistentData("siege-engine/enabled")); + enable_hooks(false); + } + } + + return CR_OK; +} + DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_change_event event) { switch (event) { diff --git a/plugins/steam-engine.cpp b/plugins/steam-engine.cpp index 01d1dbd58..e3cd9b529 100644 --- a/plugins/steam-engine.cpp +++ b/plugins/steam-engine.cpp @@ -950,8 +950,12 @@ static bool find_engines(color_ostream &out) return !engines.empty(); } +DFHACK_PLUGIN_IS_ENABLED(is_enabled); + static void enable_hooks(bool enable) { + is_enabled = enable; + INTERPOSE_HOOK(liquid_hook, getItemDescription).apply(enable); INTERPOSE_HOOK(liquid_hook, adjustTemperature).apply(enable); INTERPOSE_HOOK(liquid_hook, checkTemperatureDamage).apply(enable); diff --git a/plugins/workflow.cpp b/plugins/workflow.cpp index b70fd8b0c..810cc46fe 100644 --- a/plugins/workflow.cpp +++ b/plugins/workflow.cpp @@ -402,7 +402,8 @@ public: * GLOBAL VARIABLES * ******************************/ -static bool enabled = false; +DFHACK_PLUGIN_IS_ENABLED(enabled); + static PersistentDataItem config; static int last_tick_frame_count = 0; @@ -1387,10 +1388,13 @@ static void update_data_structures(color_ostream &out) * LUA API * *************/ -static bool isEnabled() { return enabled; } - -static void setEnabled(color_ostream &out, bool enable) +DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) { + if (!Core::getInstance().isWorldLoaded()) { + out.printerr("World is not loaded: please load a game first.\n"); + return CR_FAILURE; + } + if (enable && !enabled) { enable_plugin(out); @@ -1401,6 +1405,8 @@ static void setEnabled(color_ostream &out, bool enable) setOptionEnabled(CF_ENABLED, false); stop_protect(out); } + + return CR_OK; } static void push_count_history(lua_State *L, ItemConstraint *icv) @@ -1591,8 +1597,6 @@ static int getCountHistory(lua_State *L) DFHACK_PLUGIN_LUA_FUNCTIONS { - DFHACK_LUA_FUNCTION(isEnabled), - DFHACK_LUA_FUNCTION(setEnabled), DFHACK_LUA_FUNCTION(deleteConstraint), DFHACK_LUA_END }; @@ -1767,10 +1771,10 @@ static command_result workflow_cmd(color_ostream &out, vector & paramet { bool enable = (cmd == "enable"); if (enable) - setEnabled(out, true); + plugin_enable(out, true); else if (parameters.size() == 1) { - setEnabled(out, false); + plugin_enable(out, false); out << "The plugin is disabled." << endl; return CR_OK; @@ -1805,7 +1809,10 @@ static command_result workflow_cmd(color_ostream &out, vector & paramet } if (!enabled) - out << "Note: the plugin is not enabled." << endl; + { + out.printerr("Error: the plugin is not enabled.\n"); + return CR_WRONG_USAGE; + } if (cmd == "jobs") { diff --git a/plugins/zone.cpp b/plugins/zone.cpp index 5649da252..0271cb75f 100644 --- a/plugins/zone.cpp +++ b/plugins/zone.cpp @@ -88,6 +88,10 @@ command_result df_autobutcher(color_ostream &out, vector & parameters); DFHACK_PLUGIN("zone"); +DFHACK_PLUGIN_IS_ENABLED(is_enabled); + +DFhackCExport command_result plugin_enable ( color_ostream &out, bool enable); + const string zone_help = "Allows easier management of pens/pastures, pits and cages.\n" "Options:\n" @@ -3015,6 +3019,7 @@ command_result df_autobutcher(color_ostream &out, vector & parameters) } else if (p == "start") { + plugin_enable(out, true); enable_autobutcher = true; start_autobutcher(out); return autoButcher(out, verbose); @@ -3485,6 +3490,7 @@ command_result autoButcher( color_ostream &out, bool verbose = false ) command_result start_autobutcher(color_ostream &out) { + plugin_enable(out, true); enable_autobutcher = true; if (!config_autobutcher.isValid()) @@ -3545,6 +3551,7 @@ command_result init_autobutcher(color_ostream &out) if(!enable_autobutcher) return CR_OK; + plugin_enable(out, true); // read watchlist from save std::vector items; @@ -3579,6 +3586,7 @@ command_result cleanup_autobutcher(color_ostream &out) command_result start_autonestbox(color_ostream &out) { + plugin_enable(out, true); enable_autonestbox = true; if (!config_autonestbox.isValid()) @@ -3620,6 +3628,8 @@ command_result init_autonestbox(color_ostream &out) sleep_autonestbox = config_autonestbox.ival(1); } } + if (enable_autonestbox) + plugin_enable(out, true); return CR_OK; } @@ -3856,6 +3866,9 @@ static void autobutcher_setEnabled(color_ostream &out, bool enable) config_autobutcher.ival(0) = enable_autobutcher; out << "Autobutcher stopped." << endl; } + + if (enable) + plugin_enable(out, true); } static void autowatch_setEnabled(color_ostream &out, bool enable) @@ -4455,12 +4468,25 @@ IMPLEMENT_VMETHOD_INTERPOSE(zone_hook, feed); IMPLEMENT_VMETHOD_INTERPOSE(zone_hook, render); //END zone filters +DFhackCExport command_result plugin_enable ( color_ostream &out, bool enable) +{ + if (!gps) + return CR_FAILURE; + + if (enable != is_enabled) + { + if (!INTERPOSE_HOOK(zone_hook, feed).apply(enable) || + !INTERPOSE_HOOK(zone_hook, render).apply(enable)) + return CR_FAILURE; + + is_enabled = enable; + } + + return CR_OK; +} DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) { - if (!gps || !INTERPOSE_HOOK(zone_hook, feed).apply() || !INTERPOSE_HOOK(zone_hook, render).apply()) - out.printerr("Could not insert jobutils hooks!\n"); - commands.push_back(PluginCommand( "zone", "manage activity zones.", df_zone, false,