From 2aeac718ccbea89d383c47e01e10e1c6ca681cc6 Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 25 Nov 2015 20:33:13 -0500 Subject: [PATCH] workflow: Account for job postings correctly and fix existing issues Without removing postings correctly, it was possible to end up with multiple workers assigned to a job that workflow had suspended multiple times, which caused crashes if more than one worker was assigned to the same job by DF. This adds an additional command, fix-job-postings, that runs automatically when loading a world and fixes: - Multiple job postings that point to the same job - Job postings that point to a job where posting_index == -1 (i.e. jobs that should have no posting assigned) Fixes #741 --- library/LuaApi.cpp | 1 + library/include/modules/Job.h | 5 +++ library/modules/Job.cpp | 28 +++++++++++++++ library/xml | 2 +- plugins/workflow.cpp | 67 +++++++++++++++++++++++++++++++++-- 5 files changed, 100 insertions(+), 3 deletions(-) diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 62f274902..72267a5bf 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -1464,6 +1464,7 @@ static const LuaWrapper::FunctionReg dfhack_job_module[] = { WRAPM(Job,isSuitableMaterial), WRAPM(Job,getName), WRAPM(Job,linkIntoWorld), + WRAPM(Job,removePostings), WRAPN(is_equal, jobEqual), WRAPN(is_item_equal, jobItemEqual), { NULL, NULL } diff --git a/library/include/modules/Job.h b/library/include/modules/Job.h index 4b3950ebd..fbbed9ff3 100644 --- a/library/include/modules/Job.h +++ b/library/include/modules/Job.h @@ -72,6 +72,11 @@ namespace DFHack DFHACK_EXPORT bool linkIntoWorld(df::job *job, bool new_id = true); + // Flag this job's posting as "dead" and set its posting_index to -1 + // If remove_all is true, flag all postings pointing to this job + // Returns true if any postings were removed + DFHACK_EXPORT bool removePostings(df::job *job, bool remove_all = false); + // lists jobs with ids >= *id_var, and sets *id_var = *job_next_id; DFHACK_EXPORT bool listNewlyCreated(std::vector *pvec, int *id_var); diff --git a/library/modules/Job.cpp b/library/modules/Job.cpp index 1cfc0fa78..af2fcb4e8 100644 --- a/library/modules/Job.cpp +++ b/library/modules/Job.cpp @@ -377,6 +377,34 @@ bool DFHack::Job::linkIntoWorld(df::job *job, bool new_id) } } +bool DFHack::Job::removePostings(df::job *job, bool remove_all) +{ + using df::global::world; + CHECK_NULL_POINTER(job); + bool removed = false; + if (!remove_all) + { + if (job->posting_index >= 0 && job->posting_index < world->job_postings.size()) + { + world->job_postings[job->posting_index]->flags.bits.dead = true; + removed = true; + } + } + else + { + for (auto it = world->job_postings.begin(); it != world->job_postings.end(); ++it) + { + if ((**it).job == job) + { + (**it).flags.bits.dead = true; + removed = true; + } + } + } + job->posting_index = -1; + return removed; +} + bool DFHack::Job::listNewlyCreated(std::vector *pvec, int *id_var) { using df::global::world; diff --git a/library/xml b/library/xml index 378a580f7..bb950d99d 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 378a580f7e333607a64a301d598e3885954a5d9d +Subproject commit bb950d99da543f314f3dd9babf1446c8331ff99d diff --git a/plugins/workflow.cpp b/plugins/workflow.cpp index 113f4c89d..b2a2d11c4 100644 --- a/plugins/workflow.cpp +++ b/plugins/workflow.cpp @@ -59,10 +59,13 @@ REQUIRE_GLOBAL(job_next_id); /* Plugin registration */ static command_result workflow_cmd(color_ostream &out, vector & parameters); +static command_result fix_job_postings_cmd(color_ostream &out, vector ¶meters); static void init_state(color_ostream &out); static void cleanup_state(color_ostream &out); +static int fix_job_postings(color_ostream *out = NULL, bool dry_run = false); + DFhackCExport command_result plugin_init (color_ostream &out, std::vector &commands) { if (!world || !ui) @@ -142,6 +145,13 @@ DFhackCExport command_result plugin_init (color_ostream &out, std::vector ¶meters) +{ + bool dry = parameters.size(); + int fixed = fix_job_postings(&out, dry); + out << fixed << " job issue(s) " << (dry ? "detected but not fixed" : "fixed") << endl; + return CR_OK; +} + /****************************** * JOB STATE TRACKING STRUCTS * ******************************/ @@ -274,7 +295,7 @@ public: { if (world->frame_counter >= resume_time && actual_job->flags.bits.suspend) { - actual_job->unk_v4020_1 = -1; + Job::removePostings(actual_job, true); actual_job->flags.bits.suspend = false; } } @@ -287,7 +308,7 @@ public: if (!actual_job->flags.bits.suspend) { actual_job->flags.bits.suspend = true; - actual_job->unk_v4020_1 = -1; + Job::removePostings(actual_job, true); } } @@ -406,6 +427,41 @@ public: } }; +static int fix_job_postings (color_ostream *out, bool dry_run) +{ + int count = 0; + df::job_list_link *link = &world->job_list; + while (link) + { + df::job *job = link->item; + if (job) + { + bool needs_posting = (job->posting_index >= 0); + bool found_posting = false; + for (auto it = world->job_postings.begin(); it != world->job_postings.end(); ++it) + { + df::world::T_job_postings *posting = *it; + if (posting->job == job && !posting->flags.bits.dead) + { + if (!found_posting && needs_posting) + found_posting = true; + else + { + ++count; + if (*out) + *out << "Found extra job posting: Job " << job->id << ": " + << Job::getName(job) << endl; + if (!dry_run) + posting->flags.bits.dead = true; + } + } + } + } + link = link->next; + } + return count; +} + /****************************** * GLOBAL VARIABLES * ******************************/ @@ -1603,6 +1659,12 @@ static int getCountHistory(lua_State *L) return 1; } +static int fixJobPostings(lua_State *L) +{ + bool dry = lua_toboolean(L, 1); + lua_pushinteger(L, fix_job_postings(NULL, dry)); + return 1; +} DFHACK_PLUGIN_LUA_FUNCTIONS { DFHACK_LUA_FUNCTION(deleteConstraint), @@ -1614,6 +1676,7 @@ DFHACK_PLUGIN_LUA_COMMANDS { DFHACK_LUA_COMMAND(findConstraint), DFHACK_LUA_COMMAND(setConstraint), DFHACK_LUA_COMMAND(getCountHistory), + DFHACK_LUA_COMMAND(fixJobPostings), DFHACK_LUA_END };