diff --git a/docs/plugins/stockpiles.rst b/docs/plugins/stockpiles.rst index bfc378ed0..01cd3159b 100644 --- a/docs/plugins/stockpiles.rst +++ b/docs/plugins/stockpiles.rst @@ -5,32 +5,20 @@ stockpiles .. dfhack-tool:: :summary: Import and export stockpile settings. - :tags: untested fort design productivity stockpiles + :tags: fort design productivity stockpiles :no-command: -.. dfhack-command:: copystock - :summary: Copies the configuration of the selected stockpile. - .. dfhack-command:: savestock :summary: Exports the configuration of the selected stockpile. .. dfhack-command:: loadstock - :summary: Imports the configuration of the selected stockpile. + :summary: Imports configuration for the selected stockpile. -When the plugin is enabled, the :kbd:`q` menu of each stockpile will have an -option for saving or loading the stockpile settings. See `gui/stockpiles` for -an in-game interface. +Select a stockpile in the UI first to use these commands. Usage ----- -``enable stockpiles`` - Add a hotkey that you can hit to easily save and load settings from - stockpiles selected in :kbd:`q` mode. -``copystock`` - Copies the parameters of the currently highlighted stockpile to the custom - stockpile settings and switches to custom stockpile placement mode, - effectively allowing you to copy/paste stockpiles easily. ``savestock `` Saves the currently highlighted stockpile's settings to a file in your Dwarf Fortress folder. This file can be used to copy settings between game @@ -45,9 +33,9 @@ etc. are not saved as they are different in every world. Examples -------- -``savestock food_settings.dfstock`` - Export the stockpile settings for the stockpile currently selected in - :kbd:`q` mode to a file named ``food_settings.dfstock``. -``loadstock food_settings.dfstock`` - Set the selected stockpile settings to those saved in the - ``food_settings.dfstock`` file. +``savestock food`` + Export the stockpile settings for the currently selected stockpile to a + file named ``food.dfstock``. +``loadstock food`` + Set the selected stockpile settings to those saved in the ``food.dfstock`` + file. diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 82722f16a..d87b41978 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -156,7 +156,7 @@ dfhack_plugin(showmood showmood.cpp) #dfhack_plugin(steam-engine steam-engine.cpp) #add_subdirectory(spectate) #dfhack_plugin(stockflow stockflow.cpp LINK_LIBRARIES lua) -#add_subdirectory(stockpiles) +add_subdirectory(stockpiles) #dfhack_plugin(stocks stocks.cpp) dfhack_plugin(strangemood strangemood.cpp) dfhack_plugin(tailor tailor.cpp LINK_LIBRARIES lua) diff --git a/plugins/stockpiles/StockpileSerializer.cpp b/plugins/stockpiles/StockpileSerializer.cpp index cf3bfa349..c413613f6 100644 --- a/plugins/stockpiles/StockpileSerializer.cpp +++ b/plugins/stockpiles/StockpileSerializer.cpp @@ -474,7 +474,6 @@ void StockpileSerializer::write_general() mBuffer.set_max_wheelbarrows ( mPile->max_wheelbarrows ); mBuffer.set_max_barrels ( mPile->max_barrels ); mBuffer.set_use_links_only ( mPile->use_links_only ); - mBuffer.set_unknown1 ( mPile->settings.unk1 ); mBuffer.set_allow_inorganic ( mPile->settings.allow_inorganic ); mBuffer.set_allow_organic ( mPile->settings.allow_organic ); mBuffer.set_corpses ( mPile->settings.flags.bits.corpses ); @@ -490,8 +489,6 @@ void StockpileSerializer::read_general() mPile->max_barrels = mBuffer.max_barrels(); if ( mBuffer.has_use_links_only() ) mPile->use_links_only = mBuffer.use_links_only(); - if ( mBuffer.has_unknown1() ) - mPile->settings.unk1 = mBuffer.unknown1(); if ( mBuffer.has_allow_inorganic() ) mPile->settings.allow_inorganic = mBuffer.allow_inorganic(); if ( mBuffer.has_allow_organic() ) diff --git a/plugins/stockpiles/proto/stockpiles.proto b/plugins/stockpiles/proto/stockpiles.proto index 992989efd..90c95b93f 100644 --- a/plugins/stockpiles/proto/stockpiles.proto +++ b/plugins/stockpiles/proto/stockpiles.proto @@ -136,7 +136,7 @@ message StockpileSettings { optional AnimalsSet animals = 1; optional FoodSet food = 2; optional FurnitureSet furniture = 3; - optional int32 unknown1 = 4; + optional int32 unknown1 = 4 [deprecated=true]; optional RefuseSet refuse = 5; optional StoneSet stone = 6; optional OreSet ore = 7; diff --git a/plugins/stockpiles/stockpiles.cpp b/plugins/stockpiles/stockpiles.cpp index 4b61ff175..4a2bdc33c 100644 --- a/plugins/stockpiles/stockpiles.cpp +++ b/plugins/stockpiles/stockpiles.cpp @@ -1,82 +1,32 @@ -#include "Core.h" -#include "Console.h" -#include "Export.h" #include "PluginManager.h" - -#include "DataFuncs.h" -#include "LuaTools.h" -#include "modules/Filesystem.h" - -#include "../uicommon.h" - #include "StockpileUtils.h" #include "StockpileSerializer.h" - #include "modules/Filesystem.h" #include "modules/Gui.h" -#include "modules/Filesystem.h" - -#include "df/world.h" -#include "df/world_data.h" - -#include "DataDefs.h" -#include "df/plotinfost.h" -#include "df/building_stockpilest.h" -#include "df/stockpile_settings.h" -#include "df/global_objects.h" -#include "df/viewscreen_dwarfmodest.h" - -// stl -#include -#include using std::vector; using std::string; -using std::endl; -using namespace DFHack; -using namespace df::enums; -using namespace google::protobuf; -using namespace dfstockpiles; - -DFHACK_PLUGIN ( "stockpiles" ); -REQUIRE_GLOBAL(gps); -REQUIRE_GLOBAL(world); -REQUIRE_GLOBAL(plotinfo); -REQUIRE_GLOBAL(selection_rect); -using df::building_stockpilest; -using std::placeholders::_1; +using namespace DFHack; -static command_result copystock ( color_ostream &out, vector & parameters ); -static bool copystock_guard ( df::viewscreen *top ); +DFHACK_PLUGIN("stockpiles"); static command_result savestock ( color_ostream &out, vector & parameters ); -static bool savestock_guard ( df::viewscreen *top ); - static command_result loadstock ( color_ostream &out, vector & parameters ); -static bool loadstock_guard ( df::viewscreen *top ); DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands ) { - if ( world && plotinfo ) - { - commands.push_back(PluginCommand( - "copystock", - "Copy stockpile under cursor.", - copystock, - copystock_guard)); - commands.push_back(PluginCommand( - "savestock", - "Save the active stockpile's settings to a file.", - savestock, - savestock_guard)); - commands.push_back(PluginCommand( - "loadstock", - "Load and apply stockpile settings from a file.", - loadstock, - loadstock_guard)); - } + commands.push_back(PluginCommand( + "savestock", + "Save the active stockpile's settings to a file.", + savestock, + Gui::any_stockpile_hotkey)); + commands.push_back(PluginCommand( + "loadstock", + "Load and apply stockpile settings from a file.", + loadstock, + Gui::any_stockpile_hotkey)); return CR_OK; } @@ -86,111 +36,10 @@ DFhackCExport command_result plugin_shutdown ( color_ostream &out ) return CR_OK; } -DFhackCExport command_result plugin_onstatechange ( color_ostream &out, state_change_event event ) -{ - switch ( event ) - { - case SC_MAP_LOADED: - break; - default: - break; - } - - return CR_OK; -} - -static bool copystock_guard ( df::viewscreen *top ) -{ - using namespace ui_sidebar_mode; - - if ( !Gui::dwarfmode_hotkey ( top ) ) - return false; - - switch ( plotinfo->main.mode ) - { - case Stockpiles: - return true; - case BuildingItems: - case QueryBuilding: - return !!virtual_cast ( world->selected_building ); - default: - return false; - } -} - -static command_result copystock ( color_ostream &out, vector & parameters ) -{ - // HOTKEY COMMAND: CORE ALREADY SUSPENDED - - // For convenience: when used in the stockpiles mode, switch to 'q' - if ( plotinfo->main.mode == ui_sidebar_mode::Stockpiles ) - { - world->selected_building = NULL; // just in case it contains some kind of garbage - plotinfo->main.mode = ui_sidebar_mode::QueryBuilding; - selection_rect->start_x = -30000; - - out << "Switched back to query building." << endl; - return CR_OK; - } - - building_stockpilest *sp = virtual_cast ( world->selected_building ); - if ( !sp ) - { - out.printerr ( "Selected building isn't a stockpile.\n" ); - return CR_WRONG_USAGE; - } - - plotinfo->stockpile.custom_settings = sp->settings; - plotinfo->main.mode = ui_sidebar_mode::Stockpiles; - world->selected_stockpile_type = stockpile_category::Custom; - - out << "Stockpile options copied." << endl; - return CR_OK; -} - - -static bool savestock_guard ( df::viewscreen *top ) -{ - using namespace ui_sidebar_mode; - - if ( !Gui::dwarfmode_hotkey ( top ) ) - return false; - - switch ( plotinfo->main.mode ) - { - case Stockpiles: - return true; - case BuildingItems: - case QueryBuilding: - return !!virtual_cast ( world->selected_building ); - default: - return false; - } -} - -static bool loadstock_guard ( df::viewscreen *top ) -{ - using namespace ui_sidebar_mode; - - if ( !Gui::dwarfmode_hotkey ( top ) ) - return false; - - switch ( plotinfo->main.mode ) - { - case Stockpiles: - return true; - case BuildingItems: - case QueryBuilding: - return !!virtual_cast ( world->selected_building ); - default: - return false; - } -} - // exporting static command_result savestock ( color_ostream &out, vector & parameters ) { - building_stockpilest *sp = virtual_cast ( world->selected_building ); + df::building_stockpilest *sp = Gui::getSelectedStockpile(out, true); if ( !sp ) { out.printerr ( "Selected building isn't a stockpile.\n" ); @@ -247,7 +96,7 @@ static command_result savestock ( color_ostream &out, vector & paramete // importing static command_result loadstock ( color_ostream &out, vector & parameters ) { - building_stockpilest *sp = virtual_cast ( world->selected_building ); + df::building_stockpilest *sp = Gui::getSelectedStockpile(out, true); if ( !sp ) { out.printerr ( "Selected building isn't a stockpile.\n" ); @@ -302,227 +151,3 @@ static command_result loadstock ( color_ostream &out, vector & paramete } return CR_OK; } - -/** - * calls the lua function manage_settings() to kickoff the GUI - */ -bool manage_settings ( building_stockpilest *sp ) -{ - auto L = Lua::Core::State; - color_ostream_proxy out ( Core::getInstance().getConsole() ); - - CoreSuspendClaimer suspend; - Lua::StackUnwinder top ( L ); - - if ( !lua_checkstack ( L, 2 ) ) - return false; - - if ( !Lua::PushModulePublic ( out, L, "plugins.stockpiles", "manage_settings" ) ) - return false; - - Lua::Push ( L, sp ); - - if ( !Lua::SafeCall ( out, L, 1, 2 ) ) - return false; - - return true; -} - -bool show_message_box ( const std::string & title, const std::string & msg, bool is_error = false ) -{ - auto L = Lua::Core::State; - color_ostream_proxy out ( Core::getInstance().getConsole() ); - - CoreSuspendClaimer suspend; - Lua::StackUnwinder top ( L ); - - if ( !lua_checkstack ( L, 4 ) ) - return false; - - if ( !Lua::PushModulePublic ( out, L, "plugins.stockpiles", "show_message_box" ) ) - return false; - - Lua::Push ( L, title ); - Lua::Push ( L, msg ); - Lua::Push ( L, is_error ); - - if ( !Lua::SafeCall ( out, L, 3, 0 ) ) - return false; - - return true; -} - -struct stockpiles_import_hook : public df::viewscreen_dwarfmodest -{ - typedef df::viewscreen_dwarfmodest interpose_base; - - bool handleInput ( set *input ) - { - if ( Gui::inRenameBuilding() ) - return false; - - df::building_stockpilest *sp = get_selected_stockpile(); - if ( !sp ) - return false; - - if ( input->count ( interface_key::CUSTOM_L ) ) - { - manage_settings ( sp ); - return true; - } - - return false; - } - - DEFINE_VMETHOD_INTERPOSE ( void, feed, ( set *input ) ) - { - if ( !handleInput ( input ) ) - INTERPOSE_NEXT ( feed ) ( input ); - } - - DEFINE_VMETHOD_INTERPOSE ( void, render, () ) - { - INTERPOSE_NEXT ( render ) (); - - df::building_stockpilest *sp = get_selected_stockpile(); - if ( !sp ) - return; - - auto dims = Gui::getDwarfmodeViewDims(); - int left_margin = dims.menu_x1 + 1; - int x = left_margin; - int y = dims.y2 - 3; // below autodump, automelt, autotrade, stocks; above stockflow - OutputHotkeyString ( x, y, "Load/Save Settings", "l", true, left_margin, COLOR_WHITE, COLOR_LIGHTRED ); - } -}; - -IMPLEMENT_VMETHOD_INTERPOSE ( stockpiles_import_hook, feed ); -IMPLEMENT_VMETHOD_INTERPOSE ( stockpiles_import_hook, render ); - -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 ( stockpiles_import_hook, feed ).apply ( enable ) || - !INTERPOSE_HOOK ( stockpiles_import_hook, render ).apply ( enable ) - ) - return CR_FAILURE; - - is_enabled = enable; - } - - return CR_OK; -} - -static std::vector list_dir ( const std::string &path, bool recursive = false ) -{ -// color_ostream_proxy out ( Core::getInstance().getConsole() ); - std::vector files; - std::stack dirs; - dirs.push(path); -// out << "list_dir start" << endl; - while (!dirs.empty() ) { - const std::string current = dirs.top(); -// out << "\t walking " << current << endl; - dirs.pop(); - std::vector entries; - const int res = DFHack::getdir(current, entries); - if ( res != 0 ) - continue; - for ( std::vector::iterator it = entries.begin() ; it != entries.end(); ++it ) - { - if ( (*it).empty() || (*it)[0] == '.' ) continue; - // shitty cross platform c++ we've got to construct the actual path manually - std::ostringstream child_path_s; - child_path_s << current << "/" << *it; - const std::string child = child_path_s.str(); - if ( recursive && Filesystem::isdir ( child ) ) - { -// out << "\t\tgot child dir: " << child << endl; - dirs.push ( child ); - } - else if ( Filesystem::isfile ( child ) ) - { - const std::string rel_path ( child.substr ( std::string ( "./"+path).length()-1 ) ); -// out << "\t\t adding file: " << child << " as " << rel_path << endl; - files.push_back ( rel_path ); - } - } - } -// out << "listdir_stop" << endl; - return files; -} - -static std::vector clean_dfstock_list ( const std::string &path ) -{ - if ( !Filesystem::exists ( path ) ) - { - return std::vector(); - } - std::vector files ( list_dir ( path, true) ); - files.erase ( std::remove_if ( files.begin(), files.end(), [] ( const std::string &f ) - { - return !is_dfstockfile ( f ); - } ), files.end() ); - std::transform ( files.begin(), files.end(), files.begin(), [] ( const std::string &f ) - { - return f.substr ( 0, f.find_last_of ( "." ) ); - } ); - std::sort ( files.begin(),files.end(), CompareNoCase ); - return files; -} - -static int stockpiles_list_settings ( lua_State *L ) -{ - auto path = luaL_checkstring ( L, 1 ); - if ( Filesystem::exists ( path ) && !Filesystem::isdir ( path ) ) - { - lua_pushfstring ( L, "stocksettings path invalid: %s", path ); - lua_error ( L ); - return 0; - } - std::vector files = clean_dfstock_list ( path ); - Lua::PushVector ( L, files, true ); - return 1; -} - -const std::string err_title = "Stockpile Settings Error"; -const std::string err_help = "Does the folder exist?\nCheck the console for more information."; - -static void stockpiles_load ( color_ostream &out, std::string filename ) -{ - std::vector params; - params.push_back ( filename ); - command_result r = loadstock ( out, params ); - if ( r != CR_OK ) - show_message_box ( err_title, "Couldn't load. " + err_help, true ); -} - - -static void stockpiles_save ( color_ostream &out, std::string filename ) -{ - std::vector params; - params.push_back ( filename ); - command_result r = savestock ( out, params ); - if ( r != CR_OK ) - show_message_box ( err_title, "Couldn't save. " + err_help, true ); -} - -DFHACK_PLUGIN_LUA_FUNCTIONS -{ - DFHACK_LUA_FUNCTION ( stockpiles_load ), - DFHACK_LUA_FUNCTION ( stockpiles_save ), - DFHACK_LUA_END -}; - -DFHACK_PLUGIN_LUA_COMMANDS -{ - DFHACK_LUA_COMMAND ( stockpiles_list_settings ), - DFHACK_LUA_END -};