From e2334387a905f0dc5f75a25150a50605749b0225 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 15 Jul 2020 16:57:14 -0700 Subject: [PATCH] blueprint: write blueprints to blueprints/ subdir to enable writing to a subdir that may not exist, blueprint now automatically creates folder trees. E.g. ``blueprint 30 30 1 rooms/dining dig`` will create the file ``blueprints/rooms/dining-dig.csv``). Previously it would fail if the ``blueprints/rooms/`` directory didn't already exist. --- docs/Authors.rst | 1 + docs/changelog.txt | 2 + plugins/CMakeLists.txt | 3 +- plugins/blueprint.cpp | 87 ++++++++++++++++++++++++++++++------------ 4 files changed, 67 insertions(+), 26 deletions(-) diff --git a/docs/Authors.rst b/docs/Authors.rst index 6701b67a0..3c2777a7d 100644 --- a/docs/Authors.rst +++ b/docs/Authors.rst @@ -100,6 +100,7 @@ Milo Christiansen milochristiansen MithrilTuxedo MithrilTuxedo mizipzor mizipzor moversti moversti +Myk Taylor myk002 napagokc napagokc Neil Little nmlittle Nick Rart nickrart comestible diff --git a/docs/changelog.txt b/docs/changelog.txt index dfda78c0b..e43abd188 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -41,6 +41,8 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: - `RemoteFortressReader`: fixed a couple crashes that could result from decoding invalid enum items (``site_realization_building_type`` and ``improvement_type``) ## Misc Improvements +- `blueprint`: now writes blueprints to the ``blueprints/`` subfolder instead of the df root folder +- `blueprint`: now automatically creates folder trees when organizing blueprints into subfolders (e.g. ``blueprint 30 30 1 rooms/dining dig`` will create the file ``blueprints/rooms/dining-dig.csv``); previously it would fail if the ``blueprints/rooms/`` directory didn't already exist - `confirm`: added a confirmation dialog for convicting dwarves of crimes ## Ruby diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 678b7eec2..3dc461ee9 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -93,7 +93,8 @@ if(BUILD_SUPPORTED) dfhack_plugin(automaterial automaterial.cpp) dfhack_plugin(automelt automelt.cpp) dfhack_plugin(autotrade autotrade.cpp) - dfhack_plugin(blueprint blueprint.cpp LINK_LIBRARIES lua) + # stdc++fs required for std::experimental::filesystem; once we move to c++17 this can be removed since it's in the STL there + dfhack_plugin(blueprint blueprint.cpp LINK_LIBRARIES lua stdc++fs) dfhack_plugin(burrows burrows.cpp LINK_LIBRARIES lua) dfhack_plugin(building-hacks building-hacks.cpp LINK_LIBRARIES lua) dfhack_plugin(buildingplan buildingplan.cpp LINK_LIBRARIES buildingplan-lib) diff --git a/plugins/blueprint.cpp b/plugins/blueprint.cpp index 9742b16e7..d7ce19334 100644 --- a/plugins/blueprint.cpp +++ b/plugins/blueprint.cpp @@ -3,6 +3,8 @@ //Translates a region of tiles specified by the cursor and arguments/prompts into a series of blueprint files suitable for digfort/buildingplan/quickfort #include +#include // This is just in c++17, but we're currently compiling with c++11 +#include #include #include @@ -33,6 +35,8 @@ using std::pair; using namespace DFHack; using namespace df::enums; +namespace filesystem = std::experimental::filesystem; + DFHACK_PLUGIN("blueprint"); enum phase {DIG=1, BUILD=2, PLACE=4, QUERY=8}; @@ -62,9 +66,10 @@ command_result help(color_ostream &out) << " defaults to generating all blueprints" << endl << endl << "blueprint translates a portion of your fortress into blueprints suitable for" << endl - << " digfort/fortplan/quickfort. Blueprints are created in the DF folder with names" << endl - << " following a \"name-phase.csv\" pattern. Translation starts at the current" << endl - << " cursor location and includes all tiles in the range specified." << endl; + << " digfort/fortplan/quickfort. Blueprints are created in the \"blueprints\"" << endl + << " subdirectory of the DF folder with names following a \"name-phase.csv\" pattern." << endl + << " Translation starts at the current cursor location and includes all tiles in the" << endl + << " range specified." << endl; return CR_OK; } @@ -557,32 +562,52 @@ string get_tile_query(df::building* b) return " "; } -command_result do_transform(DFCoord start, DFCoord end, string name, uint32_t phases) +void init_stream(ofstream &out, filesystem::path basename, std::string target) +{ + filesystem::path out_path(basename); + out_path += "-"; + out_path += target; + out_path += ".csv"; + out.open(out_path, ofstream::trunc); + out << "#" << target << endl; +} + +command_result do_transform(DFCoord start, DFCoord end, string name, uint32_t phases, std::ostringstream &err) { ofstream dig, build, place, query; + + filesystem::path basename = "blueprints"; + basename /= name; + basename.make_preferred(); + + // create output directory if it doesn't already exist + std::error_code ec; + if (!filesystem::create_directories(basename.parent_path(), ec) && ec) + { + err << "could not create output directory: " << basename.parent_path() + << " (" << ec.message() << ")"; + return CR_FAILURE; + } + if (phases & QUERY) { //query = ofstream((name + "-query.csv").c_str(), ofstream::trunc); - query.open(name+"-query.csv", ofstream::trunc); - query << "#query" << endl; + init_stream(query, basename, "query"); } if (phases & PLACE) { //place = ofstream(name + "-place.csv", ofstream::trunc); - place.open(name+"-place.csv", ofstream::trunc); - place << "#place" << endl; + init_stream(place, basename, "place"); } if (phases & BUILD) { //build = ofstream(name + "-build.csv", ofstream::trunc); - build.open(name+"-build.csv", ofstream::trunc); - build << "#build" << endl; + init_stream(build, basename, "build"); } if (phases & DIG) { //dig = ofstream(name + "-dig.csv", ofstream::trunc); - dig.open(name+"-dig.csv", ofstream::trunc); - dig << "#dig" << endl; + init_stream(dig, basename, "dig"); } if (start.x > end.x) { @@ -675,18 +700,27 @@ command_result blueprint(color_ostream &out, vector ¶meters) } DFCoord start (x, y, z); DFCoord end (x + stoi(parameters[0]), y + stoi(parameters[1]), z + stoi(parameters[2])); - if (parameters.size() == 4) - return do_transform(start, end, parameters[3], DIG | BUILD | PLACE | QUERY); uint32_t option = 0; - if (cmd_option_exists(parameters, "dig")) - option |= DIG; - if (cmd_option_exists(parameters, "build")) - option |= BUILD; - if (cmd_option_exists(parameters, "place")) - option |= PLACE; - if (cmd_option_exists(parameters, "query")) - option |= QUERY; - return do_transform(start, end, parameters[3], option); + if (parameters.size() == 4) + { + option = DIG | BUILD | PLACE | QUERY; + } + else + { + if (cmd_option_exists(parameters, "dig")) + option |= DIG; + if (cmd_option_exists(parameters, "build")) + option |= BUILD; + if (cmd_option_exists(parameters, "place")) + option |= PLACE; + if (cmd_option_exists(parameters, "query")) + option |= QUERY; + } + std::ostringstream err; + DFHack::command_result result = do_transform(start, end, parameters[3], option, err); + if (result != CR_OK) + out.printerr("%s\n", err.str().c_str()); + return result; } static int create(lua_State *L, uint32_t options) { @@ -701,9 +735,12 @@ static int create(lua_State *L, uint32_t options) { luaL_argerror(L, 2, "invalid end position"); string filename(lua_tostring(L, 3)); - lua_pushboolean(L, do_transform(start, end, filename, options)); + std::ostringstream err; + DFHack::command_result result = do_transform(start, end, filename, options, err); + if (result != CR_OK) + luaL_error(L, "%s", err.str().c_str()); + lua_pushboolean(L, result); return 1; - } static int dig(lua_State *L) {