Add automatic drybucket and melting to workflow.

develop
Alexander Gavrilov 2012-01-12 20:07:53 +04:00
parent 9a86087db5
commit 53e9a1659b
2 changed files with 162 additions and 47 deletions

@ -1 +1 @@
Subproject commit 9799fc70b8389ddc0e73805f528dbd7b223653e5 Subproject commit 91b6531e1a66e98f7c0ae7f81b5496ccde584b73

@ -24,6 +24,7 @@
#include <df/tool_uses.h> #include <df/tool_uses.h>
#include <df/general_ref.h> #include <df/general_ref.h>
#include <df/general_ref_unit_workerst.h> #include <df/general_ref_unit_workerst.h>
#include <df/general_ref_unit_holderst.h>
#include <df/general_ref_building_holderst.h> #include <df/general_ref_building_holderst.h>
#include <df/general_ref_contains_itemst.h> #include <df/general_ref_contains_itemst.h>
#include <df/general_ref_contains_unitst.h> #include <df/general_ref_contains_unitst.h>
@ -33,6 +34,7 @@
#include <df/reaction_product_itemst.h> #include <df/reaction_product_itemst.h>
#include <df/plant_raw.h> #include <df/plant_raw.h>
#include <df/inorganic_raw.h> #include <df/inorganic_raw.h>
#include <df/builtin_mats.h>
using std::vector; using std::vector;
using std::string; using std::string;
@ -68,9 +70,12 @@ DFhackCExport command_result plugin_init (Core *c, std::vector <PluginCommand> &
PluginCommand( PluginCommand(
"workflow", "Manage control of repeat jobs.", "workflow", "Manage control of repeat jobs.",
workflow_cmd, false, workflow_cmd, false,
" workflow enable\n" " workflow enable [option...]\n"
" workflow disable\n" " workflow disable [option...]\n"
" Enable or disable the plugin.\n" " If no options are specified, enables or disables the plugin.\n"
" Otherwise, enables or disables any of the following options:\n"
" - drybuckets: Automatically empty abandoned water buckets.\n"
" - auto-melt: Resume melt jobs when there are objects to melt.\n"
" workflow jobs\n" " workflow jobs\n"
" List workflow-controlled jobs (if in a workshop, filtered by it).\n" " List workflow-controlled jobs (if in a workshop, filtered by it).\n"
" workflow list\n" " workflow list\n"
@ -241,23 +246,21 @@ public:
void set_resumed(bool resume) void set_resumed(bool resume)
{ {
want_resumed = resume;
if (resume) if (resume)
{ {
if (world->frame_counter >= resume_time) if (world->frame_counter >= resume_time)
actual_job->flags.bits.suspend = false; actual_job->flags.bits.suspend = false;
} }
else else
{
if (isActuallyResumed())
{ {
resume_time = 0; resume_time = 0;
if (isActuallyResumed())
resume_delay = DAY_TICKS; resume_delay = DAY_TICKS;
}
actual_job->flags.bits.suspend = true; actual_job->flags.bits.suspend = true;
} }
want_resumed = resume;
} }
}; };
@ -326,7 +329,9 @@ static int last_tick_frame_count = 0;
static int last_frame_count = 0; static int last_frame_count = 0;
enum ConfigFlags { enum ConfigFlags {
CF_ENABLED = 1 CF_ENABLED = 1,
CF_DRYBUCKETS = 2,
CF_AUTOMELT = 4
}; };
typedef std::map<int, ProtectedJob*> TKnownJobs; typedef std::map<int, ProtectedJob*> TKnownJobs;
@ -335,6 +340,8 @@ static TKnownJobs known_jobs;
static std::vector<ProtectedJob*> pending_recover; static std::vector<ProtectedJob*> pending_recover;
static std::vector<ItemConstraint*> constraints; static std::vector<ItemConstraint*> constraints;
static int meltable_count = 0;
/****************************** /******************************
* MISC FUNCTIONS * * MISC FUNCTIONS *
******************************/ ******************************/
@ -361,6 +368,22 @@ static void enumLiveJobs(std::map<int, df::job*> &rv)
rv[p->item->id] = p->item; rv[p->item->id] = p->item;
} }
static bool isOptionEnabled(unsigned flag)
{
return config.isValid() && (config.ival(0) & flag) != 0;
}
static void setOptionEnabled(ConfigFlags flag, bool on)
{
if (!config.isValid())
return;
if (on)
config.ival(0) |= flag;
else
config.ival(0) &= ~flag;
}
/****************************** /******************************
* STATE INITIALIZATION * * STATE INITIALIZATION *
******************************/ ******************************/
@ -403,9 +426,10 @@ static void start_protect(Core *c)
static void init_state(Core *c) static void init_state(Core *c)
{ {
config = c->getWorld()->GetPersistentData("workflow/config"); config = c->getWorld()->GetPersistentData("workflow/config");
if (config.isValid() && config.ival(0) == -1)
config.ival(0) = 0;
enabled = config.isValid() && config.ival(0) != -1 && enabled = isOptionEnabled(CF_ENABLED);
(config.ival(0) & CF_ENABLED);
// Parse constraints // Parse constraints
std::vector<PersistentDataItem> items; std::vector<PersistentDataItem> items;
@ -436,7 +460,7 @@ static void enable_plugin(Core *c)
config.ival(0) = 0; config.ival(0) = 0;
} }
config.ival(0) |= CF_ENABLED; setOptionEnabled(CF_ENABLED, true);
enabled = true; enabled = true;
c->con << "Enabling the plugin." << endl; c->con << "Enabling the plugin." << endl;
@ -929,16 +953,46 @@ static void map_job_constraints(Core *c)
* ITEM-CONSTRAINT MAPPING * * ITEM-CONSTRAINT MAPPING *
******************************/ ******************************/
static bool itemNotEmpty(df::item *item) static void dryBucket(df::item *item)
{
for (unsigned i = 0; i < item->itemrefs.size(); i++)
{
df::general_ref *ref = item->itemrefs[i];
if (strict_virtual_cast<df::general_ref_contains_itemst>(ref))
{
df::item *obj = ref->getItem();
if (obj &&
obj->getType() == item_type::LIQUID_MISC &&
obj->getMaterial() == builtin_mats::WATER)
{
obj->flags.bits.garbage_colect = true;
obj->flags.bits.hidden = true;
}
}
}
}
static bool itemBusy(df::item *item)
{ {
for (unsigned i = 0; i < item->itemrefs.size(); i++) for (unsigned i = 0; i < item->itemrefs.size(); i++)
{ {
df::general_ref *ref = item->itemrefs[i]; df::general_ref *ref = item->itemrefs[i];
if (strict_virtual_cast<df::general_ref_contains_itemst>(ref)) if (strict_virtual_cast<df::general_ref_contains_itemst>(ref))
{
df::item *obj = ref->getItem();
if (obj && !obj->flags.bits.garbage_colect)
return true;
}
else if (strict_virtual_cast<df::general_ref_contains_unitst>(ref))
return true; return true;
if (strict_virtual_cast<df::general_ref_contains_unitst>(ref)) else if (strict_virtual_cast<df::general_ref_unit_holderst>(ref))
{
if (!item->flags.bits.in_job)
return true; return true;
} }
}
return false; return false;
} }
@ -966,6 +1020,8 @@ static void map_job_items(Core *c)
constraints[i]->item_inuse = 0; constraints[i]->item_inuse = 0;
} }
meltable_count = 0;
// Precompute a bitmask with the bad flags // Precompute a bitmask with the bad flags
df::item_flags bad_flags; df::item_flags bad_flags;
bad_flags.whole = 0; bad_flags.whole = 0;
@ -976,6 +1032,8 @@ static void map_job_items(Core *c)
F(in_building); F(construction); F(artifact1); F(in_building); F(construction); F(artifact1);
#undef F #undef F
bool dry_buckets = isOptionEnabled(CF_DRYBUCKETS);
std::vector<df::item*> &items = world->items.other[items_other_id::ANY_FREE]; std::vector<df::item*> &items = world->items.other[items_other_id::ANY_FREE];
for (unsigned i = 0; i < items.size(); i++) for (unsigned i = 0; i < items.size(); i++)
@ -984,14 +1042,20 @@ static void map_job_items(Core *c)
if (item->flags.whole & bad_flags.whole) if (item->flags.whole & bad_flags.whole)
continue; continue;
if (itemInRealJob(item))
continue;
df::item_type itype = item->getType(); df::item_type itype = item->getType();
int16_t isubtype = item->getSubtype(); int16_t isubtype = item->getSubtype();
int16_t imattype = item->getActualMaterial(); int16_t imattype = item->getActualMaterial();
int32_t imatindex = item->getActualMaterialIndex(); int32_t imatindex = item->getActualMaterialIndex();
// Special handling
if (dry_buckets && itype == item_type::BUCKET && !item->flags.bits.in_job)
dryBucket(item);
if (item->flags.bits.melt && !item->flags.bits.owned && !itemBusy(item))
meltable_count++;
// Match to constraints
TMaterialCache::key_type matkey(imattype, imatindex); TMaterialCache::key_type matkey(imattype, imatindex);
for (unsigned i = 0; i < constraints.size(); i++) for (unsigned i = 0; i < constraints.size(); i++)
@ -1019,7 +1083,8 @@ static void map_job_items(Core *c)
if (item->flags.bits.owned || if (item->flags.bits.owned ||
item->isAssignedToStockpile() || item->isAssignedToStockpile() ||
itemNotEmpty(item)) itemInRealJob(item) ||
itemBusy(item))
{ {
cv->item_inuse++; cv->item_inuse++;
} }
@ -1041,12 +1106,37 @@ static void map_job_items(Core *c)
static std::string shortJobDescription(df::job *job); static std::string shortJobDescription(df::job *job);
static void setJobResumed(Core *c, ProtectedJob *pj, bool goal)
{
bool current = pj->isResumed();
pj->set_resumed(goal);
if (goal != current)
{
c->con.print("%s %s%s\n",
(goal ? "Resuming" : "Suspending"),
shortJobDescription(pj->actual_job).c_str(),
(!goal || pj->isActuallyResumed() ? "" : " (delayed)"));
}
}
static void update_jobs_by_constraints(Core *c) static void update_jobs_by_constraints(Core *c)
{ {
for (TKnownJobs::const_iterator it = known_jobs.begin(); it != known_jobs.end(); ++it) for (TKnownJobs::const_iterator it = known_jobs.begin(); it != known_jobs.end(); ++it)
{ {
ProtectedJob *pj = it->second; ProtectedJob *pj = it->second;
if (!pj->isLive() || pj->constraints.empty()) if (!pj->isLive())
continue;
if (pj->actual_job->job_type == job_type::MeltMetalObject &&
isOptionEnabled(CF_AUTOMELT))
{
setJobResumed(c, pj, meltable_count > 0);
continue;
}
if (pj->constraints.empty())
continue; continue;
int resume_weight = -1; int resume_weight = -1;
@ -1060,29 +1150,21 @@ static void update_jobs_by_constraints(Core *c)
suspend_weight = std::max(suspend_weight, pj->constraints[i]->weight); suspend_weight = std::max(suspend_weight, pj->constraints[i]->weight);
} }
bool current = pj->isResumed(); bool goal = pj->isResumed();
bool goal = current;
if (resume_weight >= 0 && resume_weight >= suspend_weight) if (resume_weight >= 0 && resume_weight >= suspend_weight)
goal = true; goal = true;
else if (suspend_weight >= 0 && suspend_weight >= resume_weight) else if (suspend_weight >= 0 && suspend_weight >= resume_weight)
goal = false; goal = false;
pj->set_resumed(goal); setJobResumed(c, pj, goal);
if (goal != current)
{
c->con.print("%s %s%s\n",
(goal ? "Resuming" : "Suspending"),
shortJobDescription(pj->actual_job).c_str(),
(!goal || pj->isActuallyResumed() ? "" : " (delayed)"));
}
} }
} }
static void process_constraints(Core *c) static void process_constraints(Core *c)
{ {
if (constraints.empty()) if (constraints.empty() &&
!isOptionEnabled(CF_DRYBUCKETS | CF_AUTOMELT))
return; return;
map_job_constraints(c); map_job_constraints(c);
@ -1203,7 +1285,22 @@ static void print_job(Core *c, ProtectedJob *pj)
if (!pj) if (!pj)
return; return;
printJobDetails(c, pj->isLive() ? pj->actual_job : pj->job_copy); df::job *job = pj->isLive() ? pj->actual_job : pj->job_copy;
printJobDetails(c, job);
if (job->job_type == job_type::MeltMetalObject &&
isOptionEnabled(CF_AUTOMELT))
{
if (meltable_count <= 0)
c->con.color(Console::COLOR_CYAN);
else if (pj->want_resumed && !pj->isActuallyResumed())
c->con.color(Console::COLOR_YELLOW);
else
c->con.color(Console::COLOR_GREEN);
c->con << " Meltable: " << meltable_count << " objects." << endl;
c->con.reset_color();
}
for (int i = 0; i < pj->constraints.size(); i++) for (int i = 0; i < pj->constraints.size(); i++)
print_constraint(c, pj->constraints[i], true, " "); print_constraint(c, pj->constraints[i], true, " ");
@ -1233,28 +1330,46 @@ static command_result workflow_cmd(Core *c, vector <string> & parameters)
std::string cmd = parameters.empty() ? "list" : parameters[0]; std::string cmd = parameters.empty() ? "list" : parameters[0];
if (cmd == "enable") if (cmd == "enable" || cmd == "disable")
{
bool enable = (cmd == "enable");
if (enable && !enabled)
{
enable_plugin(c);
}
else if (!enable && parameters.size() == 1)
{ {
if (enabled) if (enabled)
{ {
c->con << "The plugin is already enabled." << endl; enabled = false;
return CR_OK; setOptionEnabled(CF_ENABLED, false);
stop_protect(c);
} }
enable_plugin(c); c->con << "The plugin is disabled." << endl;
return CR_OK; return CR_OK;
} }
else if (cmd == "disable")
{ for (unsigned i = 1; i < parameters.size(); i++)
if (!enabled)
{ {
c->con << "The plugin is already disabled." << endl; if (parameters[i] == "drybuckets")
return CR_OK; setOptionEnabled(CF_DRYBUCKETS, enable);
else if (parameters[i] == "auto-melt")
setOptionEnabled(CF_AUTOMELT, enable);
else
return CR_WRONG_USAGE;
} }
enabled = false; if (enabled)
config.ival(0) &= ~CF_ENABLED; c->con << "The plugin is enabled." << endl;
stop_protect(c); else
c->con << "The plugin is disabled." << endl;
if (isOptionEnabled(CF_DRYBUCKETS))
c->con << "Option drybuckets is enabled." << endl;
if (isOptionEnabled(CF_AUTOMELT))
c->con << "Option auto-melt is enabled." << endl;
return CR_OK; return CR_OK;
} }
else if (cmd == "count" || cmd == "amount") else if (cmd == "count" || cmd == "amount")