summaryrefslogtreecommitdiff
path: root/plugins/workflow.cpp
diff options
context:
space:
mode:
authorAlexander Gavrilov2012-01-09 17:29:28 +0400
committerAlexander Gavrilov2012-01-09 17:29:28 +0400
commit3e147fe9024c656ab4929630ba9292b18df86203 (patch)
treea285c4600273c5b40d7c3d4eaa67c79d70b56fd7 /plugins/workflow.cpp
parent50386f66a3651ec08086257aa37f3e8d532fcffa (diff)
downloaddfhack-3e147fe9024c656ab4929630ba9292b18df86203.tar.gz
dfhack-3e147fe9024c656ab4929630ba9292b18df86203.tar.bz2
dfhack-3e147fe9024c656ab4929630ba9292b18df86203.tar.xz
Modify the workflow plugin to protect all repeat jobs when enabled.
Diffstat (limited to 'plugins/workflow.cpp')
-rw-r--r--plugins/workflow.cpp341
1 files changed, 143 insertions, 198 deletions
diff --git a/plugins/workflow.cpp b/plugins/workflow.cpp
index 0a1319d2..32ca50a8 100644
--- a/plugins/workflow.cpp
+++ b/plugins/workflow.cpp
@@ -36,7 +36,7 @@ using df::global::job_next_id;
/* Plugin registration */
-static command_result protect_job(Core *c, vector <string> & parameters);
+static command_result workflow_cmd(Core *c, vector <string> & parameters);
static void init_state(Core *c);
static void cleanup_state(Core *c);
@@ -55,14 +55,17 @@ DFhackCExport command_result plugin_init (Core *c, std::vector <PluginCommand> &
if (ui_workshop_job_cursor && job_next_id) {
commands.push_back(
PluginCommand(
- "protect-job", "Manage protection of workshop jobs from removal.",
- protect_job, false,
- " protect-job list\n"
- " List protected jobs. If a workshop is selected, filters by it.\n"
- " protect-job add [all]\n"
- " Protect the selected job, or any repeat jobs (possibly in the workshop).\n"
- " protect-job remove [all]\n"
- " Unprotect the selected job, or any repeat jobs (possibly in the workshop).\n"
+ "workflow", "Manage control of repeat jobs.",
+ workflow_cmd, false,
+ " workflow enable\n"
+ " workflow disable\n"
+ " Enable or disable the plugin.\n"
+ " workflow list-jobs\n"
+ " List workflow-controlled jobs (if in a workshop, filtered by it).\n"
+ "Function:\n"
+ " When the plugin is enabled, it protects all repeat jobs from removal.\n"
+ " If they do disappear due to any cause, they are immediately re-added\n"
+ " to their workshop and suspended.\n"
)
);
}
@@ -130,20 +133,35 @@ struct ProtectedJob {
}
};
-PersistentDataItem config;
-static std::vector<PersistentDataItem> protected_cfg;
+/*******************************/
+
+static bool enabled = false;
+static PersistentDataItem config;
+
+enum ConfigFlags {
+ CF_ENABLED = 1
+};
typedef std::map<int, ProtectedJob*> TKnownJobs;
static TKnownJobs known_jobs;
static std::vector<ProtectedJob*> pending_recover;
+/*******************************/
+
static ProtectedJob *get_known(int id)
{
TKnownJobs::iterator it = known_jobs.find(id);
return (it != known_jobs.end()) ? it->second : NULL;
}
+static bool isSupportedJob(df::job *job)
+{
+ return job->misc_links.empty() &&
+ !job->job_items.empty() &&
+ getJobHolder(job);
+}
+
static void enumLiveJobs(std::map<int, df::job*> &rv)
{
df::job_list_link *p = world->job_list.next;
@@ -151,129 +169,74 @@ static void enumLiveJobs(std::map<int, df::job*> &rv)
rv[p->item->id] = p->item;
}
-static void cleanup_state(Core *)
-{
- config = PersistentDataItem();
- protected_cfg.clear();
+/*******************************/
+static void stop_protect(Core *c)
+{
pending_recover.clear();
+ if (!known_jobs.empty())
+ c->con.print("Unprotecting %d jobs.\n", known_jobs.size());
+
for (TKnownJobs::iterator it = known_jobs.begin(); it != known_jobs.end(); ++it)
delete it->second;
known_jobs.clear();
}
-static void init_state(Core *c)
+static void cleanup_state(Core *c)
{
- config = c->getWorld()->GetPersistentData("workflow/config");
- c->getWorld()->GetPersistentData(&protected_cfg, "workflow/protected-jobs");
-
- std::map<int, df::job*> jobs;
- enumLiveJobs(jobs);
+ config = PersistentDataItem();
- for (unsigned i = 0; i < protected_cfg.size(); i++)
- {
- PersistentDataItem &item = protected_cfg[i];
- for (int j = 0; j < PersistentDataItem::NumInts; j++)
- {
- int id = item.ival(j);
- if (id <= 0)
- continue;
+ stop_protect(c);
+}
- if (get_known(id)) // duplicate
- {
- item.ival(j) = -1;
- continue;
- }
+static bool check_lost_jobs(Core *c);
- df::job *job = jobs[id];
- if (!job)
- {
- c->con.printerr("Protected job lost: %d\n", id);
- item.ival(j) = -1;
- continue;
- }
+static void start_protect(Core *c)
+{
+ check_lost_jobs(c);
- if (!job->misc_links.empty() || job->job_items.empty())
- {
- c->con.printerr("Protected job unsupported: %d (%s)\n",
- id, ENUM_KEY_STR(job_type, job->job_type));
- item.ival(j) = -1;
- continue;
- }
+ if (!known_jobs.empty())
+ c->con.print("Protecting %d jobs.\n", known_jobs.size());
+}
- ProtectedJob *pj = new ProtectedJob(job);
- if (!pj->holder)
- {
- c->con.printerr("Protected job not in building: %d (%s)\n",
- id, ENUM_KEY_STR(job_type, job->job_type));
- delete pj;
- item.ival(j) = -1;
- continue;
- }
+static void init_state(Core *c)
+{
+ config = c->getWorld()->GetPersistentData("workflow/config");
- known_jobs[id] = pj;
+ enabled = config.isValid() && config.ival(0) != -1 &&
+ (config.ival(0) & CF_ENABLED);
- if (!job->flags.bits.repeat) {
- c->con.printerr("Protected job not repeating: %d\n", id);
- job->flags.bits.repeat = true;
- }
- }
- }
+ if (!enabled)
+ return;
- if (!known_jobs.empty())
- c->con.print("Protecting %d jobs.\n", known_jobs.size());
+ start_protect(c);
}
-static int *find_protected_id_slot(Core *c, int key)
+static void enable_plugin(Core *c)
{
- for (unsigned i = 0; i < protected_cfg.size(); i++)
+ if (!config.isValid())
{
- PersistentDataItem &item = protected_cfg[i];
- for (int j = 0; j < PersistentDataItem::NumInts; j++)
- {
- if (item.ival(j) == key)
- return &item.ival(j);
- }
+ config = c->getWorld()->AddPersistentData("workflow/config");
+ config.ival(0) = 0;
}
- if (key == -1) {
- protected_cfg.push_back(c->getWorld()->AddPersistentData("workflow/protected-jobs"));
- PersistentDataItem &item = protected_cfg.back();
- return &item.ival(0);
- }
+ config.ival(0) |= CF_ENABLED;
+ enabled = true;
+ c->con << "Enabling the plugin." << endl;
- return NULL;
+ start_protect(c);
}
+/*******************************/
+
static void forget_job(Core *c, ProtectedJob *pj)
{
known_jobs.erase(pj->id);
-
- if (int *p = find_protected_id_slot(c, pj->id))
- *p = -1;
-
delete pj;
}
-static void remember_job(Core *c, df::job *job)
-{
- if (get_known(job->id))
- return;
-
- if (!job->misc_links.empty() || job->job_items.empty())
- {
- c->con.printerr("Unsupported job type: %d (%s)\n",
- job->id, ENUM_KEY_STR(job_type, job->job_type));
- return;
- }
-
- known_jobs[job->id] = new ProtectedJob(job);
-
- *find_protected_id_slot(c, -1) = job->id;
-}
-
static bool recover_job(Core *c, ProtectedJob *pj)
{
// Check that the building exists
@@ -305,37 +268,22 @@ static bool recover_job(Core *c, ProtectedJob *pj)
return false;
}
- // Find the position in the job list
- df::job_list_link *ins_pos = &world->job_list;
- while (ins_pos->next && ins_pos->next->item->id < pj->id)
- ins_pos = ins_pos->next;
+ // Create and link in the actual job structure
+ df::job *recovered = cloneJobStruct(pj->job_copy);
+
+ recovered->flags.bits.repeat = true;
+ recovered->flags.bits.suspend = true;
- if (ins_pos->next && ins_pos->next->item->id == pj->id)
+ if (!linkJobIntoWorld(recovered, false)) // reuse same id
{
+ deleteJobStruct(recovered);
+
c->con.printerr("Inconsistency: job %d (%s) already in list.",
pj->id, ENUM_KEY_STR(job_type, pj->job_copy->job_type));
pj->live = true;
return true;
}
- // Create the actual job structure
- df::job *recovered = cloneJobStruct(pj->job_copy);
-
- recovered->flags.bits.repeat = true;
- recovered->flags.bits.suspend = true;
-
- // Link the job into the global list
- df::job_list_link *link = new df::job_list_link();
- recovered->list_link = link;
-
- link->item = recovered;
- link->next = ins_pos->next;
- if (ins_pos->next)
- ins_pos->next->prev = link;
- link->prev = ins_pos;
- ins_pos->next = link;
-
- // Add to building jobs
pj->holder->jobs.push_back(recovered);
// Done
@@ -343,7 +291,7 @@ static bool recover_job(Core *c, ProtectedJob *pj)
return true;
}
-static void check_lost_jobs(Core *c)
+static bool check_lost_jobs(Core *c)
{
static int check = 1;
check++;
@@ -351,15 +299,27 @@ static void check_lost_jobs(Core *c)
df::job_list_link *p = world->job_list.next;
for (; p; p = p->next)
{
- ProtectedJob *pj = get_known(p->item->id);
- if (!pj)
- continue;
- pj->check_idx = check;
+ df::job *job = p->item;
- // force repeat
- p->item->flags.bits.repeat = true;
+ ProtectedJob *pj = get_known(job->id);
+ if (pj)
+ {
+ if (!job->flags.bits.repeat)
+ forget_job(c, pj);
+ else
+ pj->check_idx = check;
+ }
+ else if (job->flags.bits.repeat && isSupportedJob(job))
+ {
+ pj = new ProtectedJob(job);
+ assert(pj->holder);
+ known_jobs[pj->id] = pj;
+ pj->check_idx = check;
+ }
}
+ bool any_lost = false;
+
for (TKnownJobs::const_iterator it = known_jobs.begin(); it != known_jobs.end(); ++it)
{
if (it->second->check_idx == check || !it->second->live)
@@ -367,7 +327,10 @@ static void check_lost_jobs(Core *c)
it->second->live = false;
pending_recover.push_back(it->second);
+ any_lost = true;
}
+
+ return any_lost;
}
static void update_job_data(Core *c)
@@ -382,21 +345,30 @@ static void update_job_data(Core *c)
}
}
+static void recover_jobs(Core *c)
+{
+ for (int i = pending_recover.size()-1; i >= 0; i--)
+ if (recover_job(c, pending_recover[i]))
+ vector_erase_at(pending_recover, i);
+}
+
DFhackCExport command_result plugin_onupdate(Core* c)
{
- if (known_jobs.empty())
+ if (!enabled)
return CR_OK;
static unsigned cnt = 0;
cnt++;
- if ((cnt % 10) == 0)
+ bool force_recover = false;
+ if ((cnt % 5) == 0)
{
- for (int i = pending_recover.size()-1; i >= 0; i--)
- if (recover_job(c, pending_recover[i]))
- vector_erase_at(pending_recover, i);
+ force_recover = check_lost_jobs(c);
+ }
- check_lost_jobs(c);
+ if (force_recover || (cnt % 50) == 0)
+ {
+ recover_jobs(c);
}
if ((cnt % 500) == 0)
@@ -405,10 +377,12 @@ DFhackCExport command_result plugin_onupdate(Core* c)
return CR_OK;
}
-static command_result protect_job(Core *c, vector <string> & parameters)
+static command_result workflow_cmd(Core *c, vector <string> & parameters)
{
CoreSuspender suspend(c);
+ update_job_data(c);
+
if (parameters.empty())
return CR_WRONG_USAGE;
@@ -424,10 +398,38 @@ static command_result protect_job(Core *c, vector <string> & parameters)
std::map<int, df::job*> jobs;
enumLiveJobs(jobs);
- update_job_data(c);
std::string cmd = parameters[0];
- if (cmd == "list")
+
+ if (cmd == "enable")
+ {
+ if (enabled)
+ {
+ c->con << "The plugin is already enabled." << endl;
+ return CR_OK;
+ }
+
+ enable_plugin(c);
+ return CR_OK;
+ }
+ else if (cmd == "disable")
+ {
+ if (!enabled)
+ {
+ c->con << "The plugin is already disabled." << endl;
+ return CR_OK;
+ }
+
+ enabled = false;
+ config.ival(0) &= ~CF_ENABLED;
+ stop_protect(c);
+ return CR_OK;
+ }
+
+ if (!enabled)
+ c->con << "Note: the plugin is not enabled." << endl;
+
+ if (cmd == "list-jobs")
{
if (workshop)
{
@@ -457,65 +459,8 @@ static command_result protect_job(Core *c, vector <string> & parameters)
printJobDetails(c, pending_recover[i]->job_copy);
}
}
- }
- else if (cmd == "add" || cmd == "remove")
- {
- bool add = (cmd == "add");
- bool all = (parameters.size() >= 2 && parameters[1] == "all");
- if (parameters.size() >= 2 && !all)
- return CR_WRONG_USAGE;
-
- if (workshop && all)
- {
- for (unsigned i = 0; i < workshop->jobs.size(); i++)
- {
- df::job *job = workshop->jobs[i];
- if (add)
- {
- if (!job->flags.bits.repeat)
- continue;
- remember_job(c, job);
- }
- else
- {
- if (ProtectedJob *pj = get_known(job->id))
- forget_job(c, pj);
- }
- }
- }
- else if (workshop)
- {
- if (!job) {
- c->con.printerr("No job is selected in the current building.\n");
- return CR_FAILURE;
- }
-
- if (add)
- remember_job(c, job);
- else if (ProtectedJob *pj = get_known(job->id))
- forget_job(c, pj);
- }
- else
- {
- if (!all) {
- c->con.printerr("Please either select a job, or specify 'all'.\n");
- return CR_WRONG_USAGE;
- }
- if (add)
- {
- for (std::map<int,df::job*>::iterator it = jobs.begin(); it != jobs.end(); it++)
- if (it->second->flags.bits.repeat)
- remember_job(c, it->second);
- }
- else
- {
- pending_recover.clear();
-
- while (!known_jobs.empty())
- forget_job(c, known_jobs.begin()->second);
- }
- }
+ return CR_OK;
}
else
return CR_WRONG_USAGE;