From 1b1b4245c92b32371a4d3c15d69f65197a3aec47 Mon Sep 17 00:00:00 2001 From: myk002 Date: Fri, 21 May 2021 06:52:16 -0700 Subject: [PATCH 1/2] report output filenames when creating blueprints also refactor so we can get this data from gui/blueprint --- plugins/blueprint.cpp | 117 +++++++++++++++++++++++++++---------- plugins/lua/blueprint.lua | 14 ++--- test/plugins/blueprint.lua | 36 ++++++------ 3 files changed, 108 insertions(+), 59 deletions(-) diff --git a/plugins/blueprint.cpp b/plugins/blueprint.cpp index 2158f4086..9b00c8551 100644 --- a/plugins/blueprint.cpp +++ b/plugins/blueprint.cpp @@ -10,6 +10,7 @@ #include "Console.h" #include "DataDefs.h" +#include "DataFuncs.h" #include "DataIdentity.h" #include "LuaTools.h" #include "PluginManager.h" @@ -85,27 +86,27 @@ static const struct_field_info blueprint_options_fields[] = { }; struct_identity blueprint_options::_identity(sizeof(blueprint_options), &df::allocator_fn, NULL, "blueprint_options", NULL, blueprint_options_fields); -command_result blueprint(color_ostream &out, vector ¶meters); +command_result blueprint(color_ostream &, vector &); -DFhackCExport command_result plugin_init(color_ostream &out, vector &commands) +DFhackCExport command_result plugin_init(color_ostream &, vector &commands) { commands.push_back(PluginCommand("blueprint", "Record the structure of a live game map in a quickfort blueprint", blueprint, false)); return CR_OK; } -DFhackCExport command_result plugin_shutdown(color_ostream &out) +DFhackCExport command_result plugin_shutdown(color_ostream &) { return CR_OK; } -pair get_building_size(df::building* b) +static pair get_building_size(df::building* b) { return pair(b->x2 - b->x1 + 1, b->y2 - b->y1 + 1); } -char get_tile_dig(int32_t x, int32_t y, int32_t z) +static char get_tile_dig(int32_t x, int32_t y, int32_t z) { - df::tiletype *tt = Maps::getTileType(x, y , z); + df::tiletype *tt = Maps::getTileType(x, y, z); df::tiletype_shape ts = tileShape(tt ? *tt : tiletype::Void); switch (ts) { @@ -132,7 +133,7 @@ char get_tile_dig(int32_t x, int32_t y, int32_t z) } } -string get_tile_build(uint32_t x, uint32_t y, df::building* b) +static string get_tile_build(uint32_t x, uint32_t y, df::building* b) { if (! b) return " "; @@ -513,7 +514,7 @@ string get_tile_build(uint32_t x, uint32_t y, df::building* b) } } -string get_tile_place(uint32_t x, uint32_t y, df::building* b) +static string get_tile_place(uint32_t x, uint32_t y, df::building* b) { if (! b || b->getType() != building_type::Stockpile) return " "; @@ -579,24 +580,28 @@ string get_tile_place(uint32_t x, uint32_t y, df::building* b) return out.str(); } -string get_tile_query(df::building* b) +static string get_tile_query(df::building* b) { if (b && b->is_room) return "r+"; return " "; } -void init_stream(ofstream &out, string basename, string target) +// returns filename +static string init_stream(ofstream &out, string basename, string target) { std::ostringstream out_path; out_path << basename << "-" << target << ".csv"; - out.open(out_path.str(), ofstream::trunc); + string path = out_path.str(); + out.open(path, ofstream::trunc); out << "#" << target << endl; + return path; } -command_result do_transform(const DFCoord &start, const DFCoord &end, - const blueprint_options &options, - std::ostringstream &err) +static bool do_transform(const DFCoord &start, const DFCoord &end, + const blueprint_options &options, + vector &files, + std::ostringstream &err) { ofstream dig, build, place, query; @@ -609,24 +614,24 @@ command_result do_transform(const DFCoord &start, const DFCoord &end, if (!Filesystem::mkdir_recursive(parent_path)) { err << "could not create output directory: '" << parent_path << "'"; - return CR_FAILURE; + return false; } - if (options.auto_phase || options.query) + if (options.auto_phase || options.dig) { - init_stream(query, basename, "query"); + files.push_back(init_stream(dig, basename, "dig")); } - if (options.auto_phase || options.place) + if (options.auto_phase || options.build) { - init_stream(place, basename, "place"); + files.push_back(init_stream(build, basename, "build")); } - if (options.auto_phase || options.build) + if (options.auto_phase || options.place) { - init_stream(build, basename, "build"); + files.push_back(init_stream(place, basename, "place")); } - if (options.auto_phase || options.dig) + if (options.auto_phase || options.query) { - init_stream(dig, basename, "dig"); + files.push_back(init_stream(query, basename, "query")); } const int32_t z_inc = start.z < end.z ? 1 : -1; @@ -677,7 +682,7 @@ command_result do_transform(const DFCoord &start, const DFCoord &end, if (options.auto_phase || options.dig) dig.close(); - return CR_OK; + return true; } static bool get_options(blueprint_options &opts, @@ -720,7 +725,11 @@ static void print_help() } } -command_result blueprint(color_ostream &out, vector ¶meters) +// returns whether blueprint generation was successful. populates files with the +// names of the files that were generated +static bool do_blueprint(color_ostream &out, + const vector ¶meters, + vector &files) { CoreSuspender suspend; @@ -743,13 +752,13 @@ command_result blueprint(color_ostream &out, vector ¶meters) if (!get_options(options, parameters) || options.help) { print_help(); - return options.help ? CR_OK : CR_FAILURE; + return options.help; } if (!Maps::IsValid()) { out.printerr("Map is not available!\n"); - return CR_FAILURE; + return false; } // start coordinates can come from either the commandline or the map cursor @@ -760,14 +769,14 @@ command_result blueprint(color_ostream &out, vector ¶meters) { out.printerr("Can't get cursor coords! Make sure you specify the" " --cursor parameter or have an active cursor in DF.\n"); - return CR_FAILURE; + return false; } } if (!Maps::isValidTilePos(start)) { out.printerr("Invalid start position: %d,%d,%d\n", start.x, start.y, start.z); - return CR_FAILURE; + return false; } // end coords are one beyond the last processed coordinate. note that @@ -789,8 +798,52 @@ command_result blueprint(color_ostream &out, vector ¶meters) end.z = -1; std::ostringstream err; - command_result result = do_transform(start, end, options, err); - if (result != CR_OK) + if (!do_transform(start, end, options, files, err)) + { out.printerr("%s\n", err.str().c_str()); - return result; + return false; + } + return true; } + +// entrypoint when called from Lua. returns the names of the generated files +static int run(lua_State *L) +{ + int argc = lua_gettop(L); + vector argv; + + for (int i = 1; i <= argc; ++i) + { + const char *s = lua_tostring(L, i); + if (s == NULL) + luaL_error(L, "all parameters must be strings"); + argv.push_back(s); + } + + vector files; + if (do_blueprint(Core::getInstance().getConsole(), argv, files)) + { + Lua::PushVector(L, files); + return 1; + } + + return 0; +} + +command_result blueprint(color_ostream &out, vector ¶meters) +{ + vector files; + if (do_blueprint(Core::getInstance().getConsole(), parameters, files)) + { + out.print("Generated blueprint file(s):\n"); + for (string &fname : files) + out.print(" %s\n", fname.c_str()); + return CR_OK; + } + return CR_FAILURE; +} + +DFHACK_PLUGIN_LUA_COMMANDS { + DFHACK_LUA_COMMAND(run), + DFHACK_LUA_END +}; diff --git a/plugins/lua/blueprint.lua b/plugins/lua/blueprint.lua index e9b7ec667..628fb552c 100644 --- a/plugins/lua/blueprint.lua +++ b/plugins/lua/blueprint.lua @@ -138,10 +138,8 @@ function parse_commandline(opts, ...) parse_positionals(opts, positionals, depth and 4 or 3) end --- compatibility with old exported API. we route the request back through --- run_command so we have a unified path for parameter processing and invariant --- checking. -local function do_blueprint(start_pos, end_pos, name, phase) +-- compatibility with old exported API. +local function do_phase(start_pos, end_pos, name, phase) local width = math.abs(start_pos.x - end_pos.x) + 1 local height = math.abs(start_pos.y - end_pos.y) + 1 local depth = math.abs(start_pos.z - end_pos.z) + 1 @@ -153,13 +151,11 @@ local function do_blueprint(start_pos, end_pos, name, phase) local cursor = ('--cursor=%d,%d,%d'):format(x, y, z) - return dfhack.run_command('blueprint', - tostring(width), tostring(height), - tostring(depth), tostring(name), - phase, cursor) + run(tostring(width), tostring(height), tostring(depth), tostring(name), + phase, cursor) end for phase in pairs(valid_phases) do - _ENV[phase] = function(s, e, n) do_blueprint(s, e, n, phase) end + _ENV[phase] = function(s, e, n) do_phase(s, e, n, phase) end end return _ENV diff --git a/test/plugins/blueprint.lua b/test/plugins/blueprint.lua index e579a668f..ddb0c0bcd 100644 --- a/test/plugins/blueprint.lua +++ b/test/plugins/blueprint.lua @@ -121,44 +121,44 @@ function test.parse_commandline() 'zero depth') end -function test.do_blueprint_positive_dims() - local mock_run_command = mock.func() - mock.patch(dfhack, 'run_command', mock_run_command, +function test.do_phase_positive_dims() + local mock_run = mock.func() + mock.patch(b, 'run', mock_run, function() local spos = {x=10, y=20, z=30} local epos = {x=11, y=21, z=31} b.query(spos, epos, 'imaname') - expect.eq(1, mock_run_command.call_count) - expect.table_eq({'blueprint', '2', '2', '2', 'imaname', 'query', + expect.eq(1, mock_run.call_count) + expect.table_eq({'2', '2', '2', 'imaname', 'query', '--cursor=10,20,30'}, - mock_run_command.call_args[1]) + mock_run.call_args[1]) end) end -function test.do_blueprint_negative_dims() - local mock_run_command = mock.func() - mock.patch(dfhack, 'run_command', mock_run_command, +function test.do_phase_negative_dims() + local mock_run = mock.func() + mock.patch(b, 'run', mock_run, function() local spos = {x=11, y=21, z=31} local epos = {x=10, y=20, z=30} b.query(spos, epos, 'imaname') - expect.eq(1, mock_run_command.call_count) - expect.table_eq({'blueprint', '2', '2', '-2', 'imaname', 'query', + expect.eq(1, mock_run.call_count) + expect.table_eq({'2', '2', '-2', 'imaname', 'query', '--cursor=10,20,31'}, - mock_run_command.call_args[1]) + mock_run.call_args[1]) end) end -function test.do_blueprint_ensure_cursor_is_at_upper_left() - local mock_run_command = mock.func() - mock.patch(dfhack, 'run_command', mock_run_command, +function test.do_phase_ensure_cursor_is_at_upper_left() + local mock_run = mock.func() + mock.patch(b, 'run', mock_run, function() local spos = {x=11, y=20, z=30} local epos = {x=10, y=21, z=31} b.query(spos, epos, 'imaname') - expect.eq(1, mock_run_command.call_count) - expect.table_eq({'blueprint', '2', '2', '2', 'imaname', 'query', + expect.eq(1, mock_run.call_count) + expect.table_eq({'2', '2', '2', 'imaname', 'query', '--cursor=10,20,30'}, - mock_run_command.call_args[1]) + mock_run.call_args[1]) end) end From ce6a2d29740ca64f0ebfddb5070d93aac22c30e9 Mon Sep 17 00:00:00 2001 From: myk002 Date: Tue, 1 Jun 2021 02:16:48 -0700 Subject: [PATCH 2/2] used passed-in out param instead of the console --- plugins/blueprint.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/plugins/blueprint.cpp b/plugins/blueprint.cpp index 9b00c8551..19c0d2b97 100644 --- a/plugins/blueprint.cpp +++ b/plugins/blueprint.cpp @@ -685,11 +685,11 @@ static bool do_transform(const DFCoord &start, const DFCoord &end, return true; } -static bool get_options(blueprint_options &opts, +static bool get_options(color_ostream &out, + blueprint_options &opts, const vector ¶meters) { auto L = Lua::Core::State; - color_ostream_proxy out(Core::getInstance().getConsole()); Lua::StackUnwinder top(L); if (!lua_checkstack(L, parameters.size() + 2) || @@ -711,10 +711,9 @@ static bool get_options(blueprint_options &opts, return true; } -static void print_help() +static void print_help(color_ostream &out) { auto L = Lua::Core::State; - color_ostream_proxy out(Core::getInstance().getConsole()); Lua::StackUnwinder top(L); if (!lua_checkstack(L, 1) || @@ -749,9 +748,9 @@ static bool do_blueprint(color_ostream &out, } blueprint_options options; - if (!get_options(options, parameters) || options.help) + if (!get_options(out, options, parameters) || options.help) { - print_help(); + print_help(out); return options.help; } @@ -821,7 +820,10 @@ static int run(lua_State *L) } vector files; - if (do_blueprint(Core::getInstance().getConsole(), argv, files)) + color_ostream *out = Lua::GetOutput(L); + if (!out) + out = &Core::getInstance().getConsole(); + if (do_blueprint(*out, argv, files)) { Lua::PushVector(L, files); return 1; @@ -833,7 +835,7 @@ static int run(lua_State *L) command_result blueprint(color_ostream &out, vector ¶meters) { vector files; - if (do_blueprint(Core::getInstance().getConsole(), parameters, files)) + if (do_blueprint(out, parameters, files)) { out.print("Generated blueprint file(s):\n"); for (string &fname : files)