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``
Writes all blueprints into a single file. This is the standard format for
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``
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,
color_ostream &out,
blueprint_options opts, // copy because we can't const
const string &phase) {
const string &phase,
int32_t ordinal) {
auto L = Lua::Core::State;
Lua::StackUnwinder top(L);
if (!lua_checkstack(L, 3) ||
if (!lua_checkstack(L, 4) ||
!Lua::PushModulePublic(
out, L, "plugins.blueprint", "get_filename")) {
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, 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");
return false;
}
@ -1228,9 +1230,9 @@ static bool write_blueprint(color_ostream &out,
std::map<string, ofstream*> &output_files,
const blueprint_options &opts,
const blueprint_processor &processor,
bool pretty) {
bool pretty, int32_t ordinal) {
string fname;
if (!get_filename(fname, out, opts, processor.phase))
if (!get_filename(fname, out, opts, processor.phase, ordinal))
return false;
if (!output_files.count(fname))
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,
std::map<string, ofstream*> &output_files,
const blueprint_options &opts,
const std::vector<string> & meta_phases) {
const std::vector<string> & meta_phases,
int32_t ordinal) {
string fname;
get_filename(fname, out, opts, meta_phases.front());
get_filename(fname, out, opts, meta_phases.front(), ordinal);
ofstream &ofile = *output_files[fname];
ofile << "#meta label(";
@ -1285,7 +1288,7 @@ static void add_processor(vector<blueprint_processor> &processors,
static bool do_transform(color_ostream &out,
const df::coord &start, const df::coord &end,
blueprint_options &opts,
blueprint_options opts, // copy so we can munge it
vector<string> &filenames) {
// empty map instances to pass to emplace() below
static const bp_area EMPTY_AREA;
@ -1368,16 +1371,26 @@ static bool do_transform(color_ostream &out,
if (meta_phases.size() <= 1)
opts.nometa = true;
bool in_meta = false;
int32_t ordinal = 0;
std::map<string, ofstream*> output_files;
for (blueprint_processor &processor : processors) {
if (processor.mapdata.empty() && !processor.force_create)
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;
}
if (!opts.nometa) {
write_meta_blueprint(out, output_files, opts, meta_phases);
}
if (in_meta)
write_meta_blueprint(out, output_files, opts, meta_phases, ordinal);
for (auto &it : output_files) {
filenames.push_back(it.first);

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

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

@ -101,7 +101,7 @@ function test.parse_gui_commandline()
opts = {}
b.parse_gui_commandline(opts, {'--splitby', 'phase'})
expect.table_eq({auto_phase=true, format='minimal', split_strategy='phase',
name='blueprint'},
name='blueprint', nometa=true},
opts)
expect.error_match('unknown split_strategy',
@ -241,16 +241,16 @@ end
function test.get_filename()
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'}
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'}
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'}
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()
b.get_filename({name='', split_strategy='none'})

@ -244,7 +244,7 @@ end
local function run_blueprint(basename, spec, pos)
local args = {tostring(spec.width), tostring(spec.height),
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)
if playback_start_arg then
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('o')})
view:onInput({_STRING=string.byte('o')})
send_keys('SELECT')
view:onInput({SELECT=true})
-- rotate the dump direction to the south
send_keys('CUSTOM_D')
view:onRender()