support "group" file split strategy for blueprint

develop
myk002 2022-10-14 11:58:43 -07:00
parent c238b7c651
commit b1bf80e585
No known key found for this signature in database
GPG Key ID: 8A39CA0FA0C16E78
37 changed files with 58 additions and 29 deletions

@ -0,0 +1,6 @@
#query label(query)
,,{givename name="foo dumper"}
,,{givename name="foo"}
Can't render this file because it contains an unexpected character in line 5 and column 18.

@ -146,5 +146,10 @@ The ``--splitby`` flag can take any of the following values:
``none`` ``none``
Writes all blueprints into a single file. This is the standard format for Writes all blueprints into a single file. This is the standard format for
quickfort fortress blueprint bundles and is the default. quickfort fortress blueprint bundles and is the default.
``group``
Creates one file per group of blueprints that can be played back at the same
time (without have to unpause the game and let dwarves fulfill jobs between
blueprint runs).
``phase`` ``phase``
Creates a separate file for each phase. Creates a separate file for each phase. Implies ``--nometa`` since meta
blueprints can't combine blueprints that are in separate files.

@ -1095,11 +1095,12 @@ static bool create_output_dir(color_ostream &out,
static bool get_filename(string &fname, static bool get_filename(string &fname,
color_ostream &out, color_ostream &out,
blueprint_options opts, // copy because we can't const blueprint_options opts, // copy because we can't const
const string &phase) { const string &phase,
int32_t ordinal) {
auto L = Lua::Core::State; auto L = Lua::Core::State;
Lua::StackUnwinder top(L); Lua::StackUnwinder top(L);
if (!lua_checkstack(L, 3) || if (!lua_checkstack(L, 4) ||
!Lua::PushModulePublic( !Lua::PushModulePublic(
out, L, "plugins.blueprint", "get_filename")) { out, L, "plugins.blueprint", "get_filename")) {
out.printerr("Failed to load blueprint Lua code\n"); out.printerr("Failed to load blueprint Lua code\n");
@ -1108,8 +1109,9 @@ static bool get_filename(string &fname,
Lua::Push(L, &opts); Lua::Push(L, &opts);
Lua::Push(L, phase); Lua::Push(L, phase);
Lua::Push(L, ordinal);
if (!Lua::SafeCall(out, L, 2, 1)) { if (!Lua::SafeCall(out, L, 3, 1)) {
out.printerr("Failed Lua call to get_filename\n"); out.printerr("Failed Lua call to get_filename\n");
return false; return false;
} }
@ -1228,9 +1230,9 @@ static bool write_blueprint(color_ostream &out,
std::map<string, ofstream*> &output_files, std::map<string, ofstream*> &output_files,
const blueprint_options &opts, const blueprint_options &opts,
const blueprint_processor &processor, const blueprint_processor &processor,
bool pretty) { bool pretty, int32_t ordinal) {
string fname; string fname;
if (!get_filename(fname, out, opts, processor.phase)) if (!get_filename(fname, out, opts, processor.phase, ordinal))
return false; return false;
if (!output_files.count(fname)) if (!output_files.count(fname))
output_files[fname] = new ofstream(fname, ofstream::trunc); output_files[fname] = new ofstream(fname, ofstream::trunc);
@ -1249,9 +1251,10 @@ static bool write_blueprint(color_ostream &out,
static void write_meta_blueprint(color_ostream &out, static void write_meta_blueprint(color_ostream &out,
std::map<string, ofstream*> &output_files, std::map<string, ofstream*> &output_files,
const blueprint_options &opts, const blueprint_options &opts,
const std::vector<string> & meta_phases) { const std::vector<string> & meta_phases,
int32_t ordinal) {
string fname; string fname;
get_filename(fname, out, opts, meta_phases.front()); get_filename(fname, out, opts, meta_phases.front(), ordinal);
ofstream &ofile = *output_files[fname]; ofstream &ofile = *output_files[fname];
ofile << "#meta label("; ofile << "#meta label(";
@ -1285,7 +1288,7 @@ static void add_processor(vector<blueprint_processor> &processors,
static bool do_transform(color_ostream &out, static bool do_transform(color_ostream &out,
const df::coord &start, const df::coord &end, const df::coord &start, const df::coord &end,
blueprint_options &opts, blueprint_options opts, // copy so we can munge it
vector<string> &filenames) { vector<string> &filenames) {
// empty map instances to pass to emplace() below // empty map instances to pass to emplace() below
static const bp_area EMPTY_AREA; static const bp_area EMPTY_AREA;
@ -1368,16 +1371,26 @@ static bool do_transform(color_ostream &out,
if (meta_phases.size() <= 1) if (meta_phases.size() <= 1)
opts.nometa = true; opts.nometa = true;
bool in_meta = false;
int32_t ordinal = 0;
std::map<string, ofstream*> output_files; std::map<string, ofstream*> output_files;
for (blueprint_processor &processor : processors) { for (blueprint_processor &processor : processors) {
if (processor.mapdata.empty() && !processor.force_create) if (processor.mapdata.empty() && !processor.force_create)
continue; continue;
if (!write_blueprint(out, output_files, opts, processor, pretty)) bool meta_phase = is_meta_phase(out, opts, processor.phase);
if (!in_meta)
++ordinal;
if (in_meta && !meta_phase) {
write_meta_blueprint(out, output_files, opts, meta_phases, ordinal);
++ordinal;
}
in_meta = meta_phase;
if (!write_blueprint(out, output_files, opts, processor, pretty,
ordinal))
break; break;
} }
if (!opts.nometa) { if (in_meta)
write_meta_blueprint(out, output_files, opts, meta_phases); write_meta_blueprint(out, output_files, opts, meta_phases, ordinal);
}
for (auto &it : output_files) { for (auto &it : output_files) {
filenames.push_back(it.first); filenames.push_back(it.first);

@ -31,6 +31,7 @@ valid_formats = utils.invert(valid_formats_list)
local valid_split_strategies_list = { local valid_split_strategies_list = {
'none', 'none',
'group',
'phase', 'phase',
} }
valid_split_strategies = utils.invert(valid_split_strategies_list) valid_split_strategies = utils.invert(valid_split_strategies_list)
@ -143,6 +144,10 @@ local function process_args(opts, args)
return return
end end
if opts.split_strategy == 'phase' then
opts.nometa = true
end
return positionals return positionals
end end
@ -200,7 +205,7 @@ function is_meta_phase(opts, phase)
end end
-- returns the name of the output file for the given context -- returns the name of the output file for the given context
function get_filename(opts, phase) function get_filename(opts, phase, ordinal)
local fullname = 'blueprints/' .. opts.name local fullname = 'blueprints/' .. opts.name
local _,_,basename = fullname:find('/([^/]+)/?$') local _,_,basename = fullname:find('/([^/]+)/?$')
if not basename then if not basename then
@ -210,14 +215,13 @@ function get_filename(opts, phase)
if fullname:endswith('/') then if fullname:endswith('/') then
fullname = fullname .. basename fullname = fullname .. basename
end end
if opts.split_strategy == 'phase' then if opts.split_strategy == 'none' then
if is_meta_phase(opts, phase) then return ('%s.csv'):format(fullname)
phase = 'meta' end
end if is_meta_phase(opts, phase) then
return ('%s-%s.csv'):format(fullname, phase) phase = 'meta'
end end
-- no splitting return ('%s-%d-%s.csv'):format(fullname, ordinal, phase)
return ('%s.csv'):format(fullname)
end end
-- compatibility with old exported API. -- compatibility with old exported API.

@ -1 +1 @@
Subproject commit 6f0d7ea22edcd68a1716d843e3ff439a75f23c35 Subproject commit 0be5cc0eaf625029ef26392224db5c3d2822a63d

@ -101,7 +101,7 @@ function test.parse_gui_commandline()
opts = {} opts = {}
b.parse_gui_commandline(opts, {'--splitby', 'phase'}) b.parse_gui_commandline(opts, {'--splitby', 'phase'})
expect.table_eq({auto_phase=true, format='minimal', split_strategy='phase', expect.table_eq({auto_phase=true, format='minimal', split_strategy='phase',
name='blueprint'}, name='blueprint', nometa=true},
opts) opts)
expect.error_match('unknown split_strategy', expect.error_match('unknown split_strategy',
@ -241,16 +241,16 @@ end
function test.get_filename() function test.get_filename()
local opts = {name='a', split_strategy='none'} local opts = {name='a', split_strategy='none'}
expect.eq('blueprints/a.csv', b.get_filename(opts, 'dig')) expect.eq('blueprints/a.csv', b.get_filename(opts, 'dig', 1))
opts = {name='a/', split_strategy='none'} opts = {name='a/', split_strategy='none'}
expect.eq('blueprints/a/a.csv', b.get_filename(opts, 'dig')) expect.eq('blueprints/a/a.csv', b.get_filename(opts, 'dig', 1))
opts = {name='a', split_strategy='phase'} opts = {name='a', split_strategy='phase'}
expect.eq('blueprints/a-dig.csv', b.get_filename(opts, 'dig')) expect.eq('blueprints/a-1-dig.csv', b.get_filename(opts, 'dig', 1))
opts = {name='a/', split_strategy='phase'} opts = {name='a/', split_strategy='phase'}
expect.eq('blueprints/a/a-dig.csv', b.get_filename(opts, 'dig')) expect.eq('blueprints/a/a-5-dig.csv', b.get_filename(opts, 'dig', 5))
expect.error_match('could not parse basename', function() expect.error_match('could not parse basename', function()
b.get_filename({name='', split_strategy='none'}) b.get_filename({name='', split_strategy='none'})

@ -244,7 +244,7 @@ end
local function run_blueprint(basename, spec, pos) local function run_blueprint(basename, spec, pos)
local args = {tostring(spec.width), tostring(spec.height), local args = {tostring(spec.width), tostring(spec.height),
tostring(-spec.depth), output_dir..basename, tostring(-spec.depth), output_dir..basename,
get_cursor_arg(pos), '-tphase', '--nometa'} get_cursor_arg(pos), '-tphase'}
local playback_start_arg = get_playback_start_arg(spec.start) local playback_start_arg = get_playback_start_arg(spec.start)
if playback_start_arg then if playback_start_arg then
table.insert(args, playback_start_arg) table.insert(args, playback_start_arg)
@ -444,7 +444,7 @@ function extra_fns.gui_quantum(pos)
view:onInput({_STRING=string.byte('f')}) view:onInput({_STRING=string.byte('f')})
view:onInput({_STRING=string.byte('o')}) view:onInput({_STRING=string.byte('o')})
view:onInput({_STRING=string.byte('o')}) view:onInput({_STRING=string.byte('o')})
send_keys('SELECT') view:onInput({SELECT=true})
-- rotate the dump direction to the south -- rotate the dump direction to the south
send_keys('CUSTOM_D') send_keys('CUSTOM_D')
view:onRender() view:onRender()