Autolabor: track labors actually being used (to avoid "gone fishing" bug); fix several wrong labor map entries; add several special cases for hauling (still not all there yet); add debug warning if job deduction appears wrong; flail about mightily trying to resolve heap corruption on unload

develop
Kelly Martin 2012-12-08 02:42:22 -06:00
parent 42670f0233
commit e7d3fbe97b
1 changed files with 98 additions and 50 deletions

@ -60,6 +60,7 @@
#include <df/units_other_id.h> #include <df/units_other_id.h>
#include <df/ui.h> #include <df/ui.h>
#include <df/training_assignment.h> #include <df/training_assignment.h>
#include <df/general_ref_contains_itemst.h>
#include <MiscUtils.h> #include <MiscUtils.h>
@ -482,6 +483,8 @@ struct dwarf_info_t
int high_skill; int high_skill;
df::unit_labor using_labor;
dwarf_info_t(df::unit* dw) : dwarf(dw), clear_all(0), has_axe(0), has_pick(0), has_crossbow(0), state(OTHER), high_skill(0) dwarf_info_t(df::unit* dw) : dwarf(dw), clear_all(0), has_axe(0), has_pick(0), has_crossbow(0), state(OTHER), high_skill(0)
{ {
} }
@ -521,9 +524,9 @@ struct dwarf_info_t
static df::unit_labor hauling_labor_map[] = static df::unit_labor hauling_labor_map[] =
{ {
df::unit_labor::HAUL_ITEM, /* BAR */ df::unit_labor::HAUL_ITEM, /* BAR */
df::unit_labor::HAUL_ITEM, /* SMALLGEM */ df::unit_labor::HAUL_STONE, /* SMALLGEM */
df::unit_labor::HAUL_ITEM, /* BLOCKS */ df::unit_labor::HAUL_ITEM, /* BLOCKS */
df::unit_labor::HAUL_ITEM, /* ROUGH */ df::unit_labor::HAUL_STONE, /* ROUGH */
df::unit_labor::HAUL_STONE, /* BOULDER */ df::unit_labor::HAUL_STONE, /* BOULDER */
df::unit_labor::HAUL_WOOD, /* WOOD */ df::unit_labor::HAUL_WOOD, /* WOOD */
df::unit_labor::HAUL_FURNITURE, /* DOOR */ df::unit_labor::HAUL_FURNITURE, /* DOOR */
@ -543,7 +546,7 @@ static df::unit_labor hauling_labor_map[] =
df::unit_labor::HAUL_FURNITURE, /* TABLE */ df::unit_labor::HAUL_FURNITURE, /* TABLE */
df::unit_labor::HAUL_FURNITURE, /* COFFIN */ df::unit_labor::HAUL_FURNITURE, /* COFFIN */
df::unit_labor::HAUL_FURNITURE, /* STATUE */ df::unit_labor::HAUL_FURNITURE, /* STATUE */
df::unit_labor::HAUL_BODY, /* CORPSE */ df::unit_labor::HAUL_REFUSE, /* CORPSE */
df::unit_labor::HAUL_ITEM, /* WEAPON */ df::unit_labor::HAUL_ITEM, /* WEAPON */
df::unit_labor::HAUL_ITEM, /* ARMOR */ df::unit_labor::HAUL_ITEM, /* ARMOR */
df::unit_labor::HAUL_ITEM, /* SHOES */ df::unit_labor::HAUL_ITEM, /* SHOES */
@ -565,7 +568,7 @@ static df::unit_labor hauling_labor_map[] =
df::unit_labor::HAUL_ITEM, /* BRACELET */ df::unit_labor::HAUL_ITEM, /* BRACELET */
df::unit_labor::HAUL_ITEM, /* GEM */ df::unit_labor::HAUL_ITEM, /* GEM */
df::unit_labor::HAUL_FURNITURE, /* ANVIL */ df::unit_labor::HAUL_FURNITURE, /* ANVIL */
df::unit_labor::HAUL_BODY, /* CORPSEPIECE */ df::unit_labor::HAUL_REFUSE, /* CORPSEPIECE */
df::unit_labor::HAUL_REFUSE, /* REMAINS */ df::unit_labor::HAUL_REFUSE, /* REMAINS */
df::unit_labor::HAUL_FOOD, /* MEAT */ df::unit_labor::HAUL_FOOD, /* MEAT */
df::unit_labor::HAUL_FOOD, /* FISH */ df::unit_labor::HAUL_FOOD, /* FISH */
@ -707,8 +710,31 @@ private:
public: public:
df::unit_labor get_labor(df::job* j) df::unit_labor get_labor(df::job* j)
{ {
df::item* item = j->items[0]->item; if (j->job_type == df::job_type::StoreItemInStockpile && j->item_subtype != -1)
return hauling_labor_map[item->getType()]; return (df::unit_labor) j->item_subtype;
df::item* item;
// if (j->job_type == df::job_type::StoreItemInBarrel)
// item = j->items[1]->item;
// else
item = j->items[0]->item;
if (item->flags.bits.container && item->getType() != df::item_type::BIN)
{
for (auto a = item->general_refs.begin(); a != item->general_refs.end(); a++)
{
if ((*a)->getType() == df::general_ref_type::CONTAINS_ITEM)
{
int item_id = ((df::general_ref_contains_itemst *) (*a))->item_id;
item = binsearch_in_vector(world->items.all, item_id);
break;
}
}
}
df::unit_labor l = hauling_labor_map[item->getType()];
if (l == df::unit_labor::HAUL_REFUSE && item->flags.bits.dead_dwarf)
l = df::unit_labor::HAUL_BODY;
return l;
} }
jlfunc_hauling() {}; jlfunc_hauling() {};
}; };
@ -931,29 +957,45 @@ private:
return jlf; return jlf;
} }
private: private:
jlfunc *jlf_hauling, *jlf_make_furniture, *jlf_make_object, *jlf_make_armor, *jlf_make_weapon; std::map<df::job_type,jlfunc*> job_to_labor_table;
jlfunc *job_to_labor_table[ENUM_LAST_ITEM(job_type)+1];
public: public:
~JobLaborMapper() ~JobLaborMapper()
{ {
std::set<jlfunc*> log;
for (auto i = jlf_cache.begin(); i != jlf_cache.end(); i++) for (auto i = jlf_cache.begin(); i != jlf_cache.end(); i++)
{
if (!log.count(i->second))
{
log.insert(i->second);
delete i->second; delete i->second;
}
i->second = 0;
}
FOR_ENUM_ITEMS (job_type, j)
{
if (j < 0)
continue;
delete jlf_hauling; jlfunc* p = job_to_labor_table[j];
delete jlf_make_furniture; if (!log.count(p))
delete jlf_make_object; {
delete jlf_make_armor; log.insert(p);
delete jlf_make_weapon; delete p;
}
job_to_labor_table[j] = 0;
}
} }
JobLaborMapper() JobLaborMapper()
{ {
jlf_hauling = new jlfunc_hauling(); jlfunc* jlf_hauling = new jlfunc_hauling();
jlf_make_furniture = new jlfunc_make(df::unit_labor::FORGE_FURNITURE); jlfunc* jlf_make_furniture = new jlfunc_make(df::unit_labor::FORGE_FURNITURE);
jlf_make_object = new jlfunc_make(df::unit_labor::METAL_CRAFT); jlfunc* jlf_make_object = new jlfunc_make(df::unit_labor::METAL_CRAFT);
jlf_make_armor = new jlfunc_make(df::unit_labor::FORGE_ARMOR); jlfunc* jlf_make_armor = new jlfunc_make(df::unit_labor::FORGE_ARMOR);
jlf_make_weapon = new jlfunc_make(df::unit_labor::FORGE_WEAPON); jlfunc* jlf_make_weapon = new jlfunc_make(df::unit_labor::FORGE_WEAPON);
jlfunc* jlf_no_labor = jlf_const(df::unit_labor::NONE); jlfunc* jlf_no_labor = jlf_const(df::unit_labor::NONE);
@ -979,7 +1021,7 @@ public:
job_to_labor_table[df::job_type::FillWaterskin] = jlf_no_labor; job_to_labor_table[df::job_type::FillWaterskin] = jlf_no_labor;
job_to_labor_table[df::job_type::FillWaterskin2] = jlf_no_labor; job_to_labor_table[df::job_type::FillWaterskin2] = jlf_no_labor;
job_to_labor_table[df::job_type::Sleep] = jlf_no_labor; job_to_labor_table[df::job_type::Sleep] = jlf_no_labor;
job_to_labor_table[df::job_type::CollectSand] = jlf_const(df::unit_labor::GLASSMAKER); job_to_labor_table[df::job_type::CollectSand] = jlf_const(df::unit_labor::HAUL_ITEM);
job_to_labor_table[df::job_type::Fish] = jlf_const(df::unit_labor::FISH); job_to_labor_table[df::job_type::Fish] = jlf_const(df::unit_labor::FISH);
job_to_labor_table[df::job_type::Hunt] = jlf_const(df::unit_labor::HUNT); job_to_labor_table[df::job_type::Hunt] = jlf_const(df::unit_labor::HUNT);
job_to_labor_table[df::job_type::HuntVermin] = jlf_no_labor; job_to_labor_table[df::job_type::HuntVermin] = jlf_no_labor;
@ -1002,7 +1044,7 @@ public:
job_to_labor_table[df::job_type::StoreWeapon] = jlf_hauling; job_to_labor_table[df::job_type::StoreWeapon] = jlf_hauling;
job_to_labor_table[df::job_type::StoreArmor] = jlf_hauling; job_to_labor_table[df::job_type::StoreArmor] = jlf_hauling;
job_to_labor_table[df::job_type::StoreItemInBarrel] = jlf_hauling; job_to_labor_table[df::job_type::StoreItemInBarrel] = jlf_hauling;
job_to_labor_table[df::job_type::StoreItemInBin] = jlf_hauling; job_to_labor_table[df::job_type::StoreItemInBin] = jlf_const(df::unit_labor::HAUL_ITEM);
job_to_labor_table[df::job_type::SeekArtifact] = jlf_no_labor; job_to_labor_table[df::job_type::SeekArtifact] = jlf_no_labor;
job_to_labor_table[df::job_type::SeekInfant] = jlf_no_labor; job_to_labor_table[df::job_type::SeekInfant] = jlf_no_labor;
job_to_labor_table[df::job_type::AttendParty] = jlf_no_labor; job_to_labor_table[df::job_type::AttendParty] = jlf_no_labor;
@ -1205,15 +1247,8 @@ public:
return df::unit_labor::NONE; return df::unit_labor::NONE;
} }
df::job_skill skill;
df::unit_labor labor;
skill = ENUM_ATTR(job_type, skill, j->job_type);
if (skill != df::job_skill::NONE)
labor = ENUM_ATTR(job_skill, labor, skill);
else
labor = ENUM_ATTR(job_type, labor, j->job_type);
if (labor == df::unit_labor::NONE) df::unit_labor labor;
labor = job_to_labor_table[j->job_type]->get_labor(j); labor = job_to_labor_table[j->job_type]->get_labor(j);
return labor; return labor;
@ -1222,7 +1257,7 @@ public:
/* End of labor deducer */ /* End of labor deducer */
static JobLaborMapper* labor_mapper; static JobLaborMapper* labor_mapper = 0;
static bool isOptionEnabled(unsigned flag) static bool isOptionEnabled(unsigned flag)
{ {
@ -1243,11 +1278,6 @@ static void setOptionEnabled(ConfigFlags flag, bool on)
static void cleanup_state() static void cleanup_state()
{ {
labor_infos.clear(); labor_infos.clear();
if (labor_mapper)
{
delete labor_mapper;
labor_mapper = 0;
}
} }
static void reset_labor(df::unit_labor labor) static void reset_labor(df::unit_labor labor)
@ -1298,11 +1328,6 @@ static void init_state()
reset_labor((df::unit_labor) i); reset_labor((df::unit_labor) i);
} }
generate_labor_to_skill_map();
if (!labor_mapper)
labor_mapper = new JobLaborMapper();
} }
static df::job_skill labor_to_skill[ENUM_LAST_ITEM(unit_labor) + 1]; static df::job_skill labor_to_skill[ENUM_LAST_ITEM(unit_labor) + 1];
@ -1382,6 +1407,10 @@ DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <Plug
" while it is enabled.\n" " while it is enabled.\n"
)); ));
generate_labor_to_skill_map();
labor_mapper = new JobLaborMapper();
init_state(); init_state();
return CR_OK; return CR_OK;
@ -1391,6 +1420,8 @@ DFhackCExport command_result plugin_shutdown ( color_ostream &out )
{ {
cleanup_state(); cleanup_state();
delete labor_mapper;
return CR_OK; return CR_OK;
} }
@ -1400,13 +1431,15 @@ class AutoLaborManager {
public: public:
AutoLaborManager(color_ostream& o) : out(o) AutoLaborManager(color_ostream& o) : out(o)
{ {
dwarf_info.clear();
} }
~AutoLaborManager() ~AutoLaborManager()
{ {
for (std::vector<dwarf_info_t*>::iterator i = dwarf_info.begin(); for (auto d = dwarf_info.begin(); d != dwarf_info.end(); d++)
i != dwarf_info.end(); i++) {
delete (*i); delete (*d);
}
} }
dwarf_info_t* add_dwarf(df::unit* u) dwarf_info_t* add_dwarf(df::unit* u)
@ -1704,7 +1737,7 @@ private:
} }
else else
{ {
int job = dwarf->dwarf->job.current_job->job_type; df::job_type job = dwarf->dwarf->job.current_job->job_type;
if (job >= 0 && job < ARRAY_COUNT(dwarf_states)) if (job >= 0 && job < ARRAY_COUNT(dwarf_states))
state = dwarf_states[job]; state = dwarf_states[job];
else else
@ -1712,6 +1745,20 @@ private:
out.print("Dwarf \"%s\" has unknown job %i\n", dwarf->dwarf->name.first_name.c_str(), job); out.print("Dwarf \"%s\" has unknown job %i\n", dwarf->dwarf->name.first_name.c_str(), job);
state = OTHER; state = OTHER;
} }
if (state == BUSY)
{
df::unit_labor labor = labor_mapper->find_job_labor(dwarf->dwarf->job.current_job);
if (labor != df::unit_labor::NONE)
{
labor_needed[labor]--;
if (!dwarf->dwarf->status.labors[labor])
{
out.print("AUTOLABOR: dwarf %s (id %d) is doing job %s(%d) but is not enabled for labor %s(%d).\n",
dwarf->dwarf->name.first_name.c_str(), dwarf->dwarf->id,
ENUM_KEY_STR(job_type, job).c_str(), job, ENUM_KEY_STR(unit_labor, labor).c_str(), labor);
}
}
}
} }
dwarf->state = state; dwarf->state = state;
@ -1753,6 +1800,9 @@ private:
FOR_ENUM_ITEMS (unit_labor, labor) FOR_ENUM_ITEMS (unit_labor, labor)
{ {
if (labor == df::unit_labor::NONE)
continue;
df::job_skill skill = labor_to_skill[labor]; df::job_skill skill = labor_to_skill[labor];
if (skill != df::job_skill::NONE) if (skill != df::job_skill::NONE)
{ {
@ -1804,7 +1854,7 @@ private:
} }
} }
if ((state == IDLE || state == BUSY) && !dwarf->clear_all) if ((state == IDLE) && !dwarf->clear_all)
available_dwarfs.push_back(dwarf); available_dwarfs.push_back(dwarf);
} }
@ -1815,6 +1865,8 @@ private:
public: public:
void process() void process()
{ {
dwarf_info.clear();
dig_count = tree_count = plant_count = detail_count = pick_count = axe_count = 0; dig_count = tree_count = plant_count = detail_count = pick_count = axe_count = 0;
cnt_recover_wounded = cnt_diagnosis = cnt_immobilize = cnt_dressing = cnt_cleaning = cnt_surgery = cnt_suture = cnt_recover_wounded = cnt_diagnosis = cnt_immobilize = cnt_dressing = cnt_cleaning = cnt_surgery = cnt_suture =
cnt_setting = cnt_traction = cnt_crutch = 0; cnt_setting = cnt_traction = cnt_crutch = 0;
@ -1904,7 +1956,6 @@ public:
// note: this doesn't test to see if the trainer is actually needed, and thus will overallocate trainers. bleah. // note: this doesn't test to see if the trainer is actually needed, and thus will overallocate trainers. bleah.
} }
if (print_debug) if (print_debug)
{ {
for (auto i = labor_needed.begin(); i != labor_needed.end(); i++) for (auto i = labor_needed.begin(); i != labor_needed.end(); i++)
@ -2079,12 +2130,9 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out )
step_count = 0; step_count = 0;
debug_stream = &out; debug_stream = &out;
AutoLaborManager alm(out); AutoLaborManager alm(out);
alm.process(); alm.process();
return CR_OK; return CR_OK;
} }