Merge branch 'master' of git://github.com/angavrilov/dfhack

develop
Robert Heinrich 2012-04-10 10:18:38 +02:00
commit 7d0cfb7e80
9 changed files with 182 additions and 55 deletions

@ -68,6 +68,11 @@ All typed objects have the following built-in features:
and values. Fields are enumerated in memory order. Methods and
lua wrapper properties are not included in the iteration.
**WARNING**: a few of the data structures (like ui_look_list)
contain unions with pointers to different types with vtables.
Using pairs on such structs is an almost sure way to crash with
an access violation.
* ``ref._kind``
Returns one of: ``primitive``, ``struct``, ``container``,
@ -629,10 +634,18 @@ Job module
Prints info about the job.
* ``dfhack.job.getJobHolder(job)``
* ``dfhack.job.printItemDetails(jobitem,idx)``
Prints info about the job item.
* ``dfhack.job.getHolder(job)``
Returns the building holding the job.
* ``dfhack.job.getWorker(job)``
Returns the unit performing the job.
* ``dfhack.job.is_equal(job1,job2)``
Compares important fields in the job and nested item structures.
@ -641,6 +654,12 @@ Job module
Compares important fields in the job item structures.
* ``dfhack.job.listNewlyCreated(first_id)``
Returns the current value of ``df.global.job_next_id``, and
if there are any jobs with ``first_id <= id < job_next_id``,
a lua list containing them.
Units module
------------

@ -395,6 +395,10 @@ Every structured field access produces a new userdata instance.</p>
<p>Returns an iterator for the sequence of actual C++ field names
and values. Fields are enumerated in memory order. Methods and
lua wrapper properties are not included in the iteration.</p>
<p><strong>WARNING</strong>: a few of the data structures (like ui_look_list)
contain unions with pointers to different types with vtables.
Using pairs on such structs is an almost sure way to crash with
an access violation.</p>
</li>
<li><p class="first"><tt class="docutils literal">ref._kind</tt></p>
<p>Returns one of: <tt class="docutils literal">primitive</tt>, <tt class="docutils literal">struct</tt>, <tt class="docutils literal">container</tt>,
@ -869,15 +873,26 @@ The is_bright boolean actually seems to invert the brightness.</p>
<li><p class="first"><tt class="docutils literal">dfhack.job.printJobDetails(job)</tt></p>
<p>Prints info about the job.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.job.getJobHolder(job)</tt></p>
<li><p class="first"><tt class="docutils literal">dfhack.job.printItemDetails(jobitem,idx)</tt></p>
<p>Prints info about the job item.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.job.getHolder(job)</tt></p>
<p>Returns the building holding the job.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.job.getWorker(job)</tt></p>
<p>Returns the unit performing the job.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.job.is_equal(job1,job2)</tt></p>
<p>Compares important fields in the job and nested item structures.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.job.is_item_equal(job_item1,job_item2)</tt></p>
<p>Compares important fields in the job item structures.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.job.listNewlyCreated(first_id)</tt></p>
<p>Returns the current value of <tt class="docutils literal">df.global.job_next_id</tt>, and
if there are any jobs with <tt class="docutils literal">first_id &lt;= id &lt; job_next_id</tt>,
a lua list containing them.</p>
</li>
</ul>
</div>
<div class="section" id="units-module">

@ -893,26 +893,31 @@ int Core::Update()
if (new_wdata != last_world_data_ptr)
{
// we check for map change too
bool mapchange = new_mapdata != last_local_map_ptr;
bool had_map = isMapLoaded();
last_world_data_ptr = new_wdata;
last_local_map_ptr = new_mapdata;
getWorld()->ClearPersistentCache();
// and if the world is going away, we report the map change first
if(!new_wdata && mapchange)
plug_mgr->OnStateChange(out, new_mapdata ? SC_MAP_LOADED : SC_MAP_UNLOADED);
if(had_map)
plug_mgr->OnStateChange(out, SC_MAP_UNLOADED);
// and if the world is appearing, we report map change after that
plug_mgr->OnStateChange(out, new_wdata ? SC_WORLD_LOADED : SC_WORLD_UNLOADED);
if(new_wdata && mapchange)
plug_mgr->OnStateChange(out, new_mapdata ? SC_MAP_LOADED : SC_MAP_UNLOADED);
if(isMapLoaded())
plug_mgr->OnStateChange(out, SC_MAP_LOADED);
}
// otherwise just check for map change...
else if (new_mapdata != last_local_map_ptr)
{
bool had_map = isMapLoaded();
last_local_map_ptr = new_mapdata;
getWorld()->ClearPersistentCache();
plug_mgr->OnStateChange(out, new_mapdata ? SC_MAP_LOADED : SC_MAP_UNLOADED);
if (isMapLoaded() != had_map)
{
getWorld()->ClearPersistentCache();
plug_mgr->OnStateChange(out, new_mapdata ? SC_MAP_LOADED : SC_MAP_UNLOADED);
}
}
// detect if the viewscreen changed

@ -517,10 +517,13 @@ static void OpenMatinfo(lua_State *state)
* Wrappers for C++ API *
************************/
static void OpenModule(lua_State *state, const char *mname, const LuaWrapper::FunctionReg *reg)
static void OpenModule(lua_State *state, const char *mname,
const LuaWrapper::FunctionReg *reg, const luaL_Reg *reg2 = NULL)
{
luaL_getsubtable(state, lua_gettop(state), mname);
LuaWrapper::SetFunctionWrappers(state, reg);
if (reg2)
luaL_setfuncs(state, reg2, 0);
lua_pop(state, 1);
}
@ -547,14 +550,46 @@ static bool jobEqual(df::job *job1, df::job *job2) { return *job1 == *job2; }
static bool jobItemEqual(df::job_item *job1, df::job_item *job2) { return *job1 == *job2; }
static const LuaWrapper::FunctionReg dfhack_job_module[] = {
WRAP(cloneJobStruct),
WRAP(printJobDetails),
WRAP(getJobHolder),
WRAPM(Job,cloneJobStruct),
WRAPM(Job,printItemDetails),
WRAPM(Job,printJobDetails),
WRAPM(Job,getHolder),
WRAPM(Job,getWorker),
WRAPN(is_equal, jobEqual),
WRAPN(is_item_equal, jobItemEqual),
{ NULL, NULL }
};
static int job_listNewlyCreated(lua_State *state)
{
int nxid = luaL_checkint(state, 1);
lua_settop(state, 1);
std::vector<df::job*> pvec;
if (Job::listNewlyCreated(&pvec, &nxid))
{
lua_pushinteger(state, nxid);
lua_newtable(state);
for (size_t i = 0; i < pvec.size(); i++)
{
Lua::PushDFObject(state, pvec[i]);
lua_rawseti(state, -2, i+1);
}
return 2;
}
else
return 1;
}
static const luaL_Reg dfhack_job_funcs[] = {
{ "listNewlyCreated", job_listNewlyCreated },
{ NULL, NULL }
};
static const LuaWrapper::FunctionReg dfhack_units_module[] = {
WRAPM(Units, setNickname),
WRAPM(Units, getVisibleName),
@ -576,6 +611,6 @@ void OpenDFHackApi(lua_State *state)
LuaWrapper::SetFunctionWrappers(state, dfhack_module);
OpenModule(state, "gui", dfhack_gui_module);
OpenModule(state, "job", dfhack_job_module);
OpenModule(state, "job", dfhack_job_module, dfhack_job_funcs);
OpenModule(state, "units", dfhack_units_module);
}

@ -1072,10 +1072,10 @@ void LuaWrapper::SetFunctionWrappers(lua_State *state, const FunctionReg *reg)
/**
* Add fields in the array to the UPVAL_FIELDTABLE candidates on the stack.
*/
static void IndexFields(lua_State *state, int base, struct_identity *pstruct)
static void IndexFields(lua_State *state, int base, struct_identity *pstruct, bool globals)
{
if (pstruct->getParent())
IndexFields(state, base, pstruct->getParent());
IndexFields(state, base, pstruct->getParent(), globals);
auto fields = pstruct->getFields();
if (!fields)
@ -1105,7 +1105,10 @@ static void IndexFields(lua_State *state, int base, struct_identity *pstruct)
break;
default:
AssociateId(state, base+3, ++cnt, name.c_str());
// Do not add invalid globals to the enumeration order
if (!globals || *(void**)fields[i].offset)
AssociateId(state, base+3, ++cnt, name.c_str());
lua_pushlightuserdata(state, (void*)&fields[i]);
lua_setfield(state, base+2, name.c_str());
break;
@ -1143,7 +1146,7 @@ void LuaWrapper::IndexStatics(lua_State *state, int meta_idx, int ftable_idx, st
* Make a struct-style object metatable.
*/
static void MakeFieldMetatable(lua_State *state, struct_identity *pstruct,
lua_CFunction reader, lua_CFunction writer)
lua_CFunction reader, lua_CFunction writer, bool globals = false)
{
int base = lua_gettop(state);
@ -1152,7 +1155,7 @@ static void MakeFieldMetatable(lua_State *state, struct_identity *pstruct,
// Index the fields
lua_newtable(state);
IndexFields(state, base, pstruct);
IndexFields(state, base, pstruct, globals);
// Add the iteration metamethods
PushStructMethod(state, base+1, base+3, meta_struct_next);
@ -1304,7 +1307,7 @@ void struct_identity::build_metatable(lua_State *state)
void global_identity::build_metatable(lua_State *state)
{
MakeFieldMetatable(state, this, meta_global_index, meta_global_newindex);
MakeFieldMetatable(state, this, meta_global_index, meta_global_newindex, true);
}
/**

@ -36,24 +36,32 @@ namespace df
struct job_item;
struct job_item_filter;
struct building;
struct unit;
}
namespace DFHack
{
// Duplicate the job structure. It is not linked into any DF lists.
DFHACK_EXPORT df::job *cloneJobStruct(df::job *job);
namespace Job {
// Duplicate the job structure. It is not linked into any DF lists.
DFHACK_EXPORT df::job *cloneJobStruct(df::job *job);
// Delete a cloned structure.
DFHACK_EXPORT void deleteJobStruct(df::job *job);
// Delete a cloned structure.
DFHACK_EXPORT void deleteJobStruct(df::job *job);
DFHACK_EXPORT bool operator== (const df::job_item &a, const df::job_item &b);
DFHACK_EXPORT bool operator== (const df::job &a, const df::job &b);
DFHACK_EXPORT void printItemDetails(color_ostream &out, df::job_item *item, int idx);
DFHACK_EXPORT void printJobDetails(color_ostream &out, df::job *job);
DFHACK_EXPORT df::building *getHolder(df::job *job);
DFHACK_EXPORT df::unit *getWorker(df::job *job);
DFHACK_EXPORT void printJobDetails(color_ostream &out, df::job *job);
DFHACK_EXPORT bool linkIntoWorld(df::job *job, bool new_id = true);
DFHACK_EXPORT df::building *getJobHolder(df::job *job);
// lists jobs with ids >= *id_var, and sets *id_var = *job_next_id;
DFHACK_EXPORT bool listNewlyCreated(std::vector<df::job*> *pvec, int *id_var);
}
DFHACK_EXPORT bool linkJobIntoWorld(df::job *job, bool new_id = true);
DFHACK_EXPORT bool operator== (const df::job_item &a, const df::job_item &b);
DFHACK_EXPORT bool operator== (const df::job &a, const df::job &b);
}
#endif

@ -53,7 +53,7 @@ using namespace std;
using namespace DFHack;
using namespace df::enums;
df::job *DFHack::cloneJobStruct(df::job *job)
df::job *DFHack::Job::cloneJobStruct(df::job *job)
{
CHECK_NULL_POINTER(job);
@ -87,7 +87,7 @@ df::job *DFHack::cloneJobStruct(df::job *job)
return pnew;
}
void DFHack::deleteJobStruct(df::job *job)
void DFHack::Job::deleteJobStruct(df::job *job)
{
if (!job)
return;
@ -148,7 +148,7 @@ bool DFHack::operator== (const df::job &a, const df::job &b)
return true;
}
static void print_job_item_details(color_ostream &out, df::job *job, unsigned idx, df::job_item *item)
void DFHack::Job::printItemDetails(color_ostream &out, df::job_item *item, int idx)
{
CHECK_NULL_POINTER(item);
@ -184,7 +184,7 @@ static void print_job_item_details(color_ostream &out, df::job *job, unsigned id
out << " tool use: " << ENUM_KEY_STR(tool_uses, item->has_tool_use) << endl;
}
void DFHack::printJobDetails(color_ostream &out, df::job *job)
void DFHack::Job::printJobDetails(color_ostream &out, df::job *job)
{
CHECK_NULL_POINTER(job);
@ -224,10 +224,10 @@ void DFHack::printJobDetails(color_ostream &out, df::job *job)
out << " reaction: " << job->reaction_name << endl;
for (size_t i = 0; i < job->job_items.size(); i++)
print_job_item_details(out, job, i, job->job_items[i]);
printItemDetails(out, job->job_items[i], i);
}
df::building *DFHack::getJobHolder(df::job *job)
df::building *DFHack::Job::getHolder(df::job *job)
{
CHECK_NULL_POINTER(job);
@ -241,7 +241,21 @@ df::building *DFHack::getJobHolder(df::job *job)
return NULL;
}
bool DFHack::linkJobIntoWorld(df::job *job, bool new_id)
df::unit *DFHack::Job::getWorker(df::job *job)
{
CHECK_NULL_POINTER(job);
for (size_t i = 0; i < job->references.size(); i++)
{
VIRTUAL_CAST_VAR(ref, df::general_ref_unit_workerst, job->references[i]);
if (ref)
return ref->getUnit();
}
return NULL;
}
bool DFHack::Job::linkIntoWorld(df::job *job, bool new_id)
{
using df::global::world;
using df::global::job_next_id;
@ -269,3 +283,31 @@ bool DFHack::linkJobIntoWorld(df::job *job, bool new_id)
return true;
}
}
bool DFHack::Job::listNewlyCreated(std::vector<df::job*> *pvec, int *id_var)
{
using df::global::world;
using df::global::job_next_id;
pvec->clear();
if (!job_next_id || *job_next_id <= *id_var)
return false;
int old_id = *id_var;
int cur_id = *job_next_id;
*id_var = cur_id;
pvec->reserve(std::min(20,cur_id - old_id));
df::job_list_link *link = world->job_list.next;
for (; link; link = link->next)
{
int id = link->item->id;
if (id >= old_id)
pvec->push_back(link->item);
}
return true;
}

@ -289,9 +289,9 @@ static command_result job_duplicate(color_ostream &out, vector <string> & parame
}
// Actually clone
df::job *pnew = cloneJobStruct(job);
df::job *pnew = Job::cloneJobStruct(job);
linkJobIntoWorld(pnew);
Job::linkIntoWorld(pnew);
vector_insert_at(building->jobs, ++*ui_workshop_job_cursor, pnew);
return CR_OK;
@ -325,14 +325,14 @@ static command_result job_cmd(color_ostream &out, vector <string> & parameters)
return CR_WRONG_USAGE;
if (cmd == "query") {
printJobDetails(out, job);
Job::printJobDetails(out, job);
} else {
if (!Gui::workshop_job_hotkey(Core::getTopViewscreen()))
return CR_WRONG_USAGE;
df::building *selected = world->selected_building;
for (size_t i = 0; i < selected->jobs.size(); i++)
printJobDetails(out, selected->jobs[i]);
Job::printJobDetails(out, selected->jobs[i]);
}
}
else if (cmd == "item-material")
@ -355,7 +355,7 @@ static command_result job_cmd(color_ostream &out, vector <string> & parameters)
if (minfo.isValid() && !iinfo.matches(*item, &minfo)) {
out.printerr("Material does not match the requirements.\n");
printJobDetails(out, job);
Job::printJobDetails(out, job);
return CR_FAILURE;
}
@ -376,7 +376,7 @@ static command_result job_cmd(color_ostream &out, vector <string> & parameters)
out.printerr("WARNING: Due to a probable bug, creature & plant material subtype\n"
" is ignored unless the item type is also specified.\n");
printJobDetails(out, job);
Job::printJobDetails(out, job);
return CR_OK;
}
else if (cmd == "item-type")
@ -399,7 +399,7 @@ static command_result job_cmd(color_ostream &out, vector <string> & parameters)
if (iinfo.isValid() && !iinfo.matches(*item, &minfo)) {
out.printerr("Item type does not match the requirements.\n");
printJobDetails(out, job);
Job::printJobDetails(out, job);
return CR_FAILURE;
}
@ -407,7 +407,7 @@ static command_result job_cmd(color_ostream &out, vector <string> & parameters)
item->item_subtype = iinfo.subtype;
out << "Job item updated." << endl;
printJobDetails(out, job);
Job::printJobDetails(out, job);
return CR_OK;
}
else

@ -184,9 +184,9 @@ public:
ProtectedJob(df::job *job) : id(job->id)
{
tick_idx = cur_tick_idx;
holder = getJobHolder(job);
holder = Job::getHolder(job);
building_id = holder ? holder->id : -1;
job_copy = cloneJobStruct(job);
job_copy = Job::cloneJobStruct(job);
actual_job = job;
reaction_id = -1;
@ -196,7 +196,7 @@ public:
~ProtectedJob()
{
deleteJobStruct(job_copy);
Job::deleteJobStruct(job_copy);
}
bool isActuallyResumed() {
@ -214,8 +214,8 @@ public:
return;
reaction_id = -1;
deleteJobStruct(job_copy);
job_copy = cloneJobStruct(job);
Job::deleteJobStruct(job_copy);
job_copy = Job::cloneJobStruct(job);
}
void tick_job(df::job *job, int ticks)
@ -365,7 +365,7 @@ static ProtectedJob *get_known(int id)
static bool isSupportedJob(df::job *job)
{
return job->misc_links.empty() &&
getJobHolder(job) &&
Job::getHolder(job) &&
(!job->job_items.empty() ||
job->job_type == job_type::CollectClay ||
job->job_type == job_type::CollectSand);
@ -526,11 +526,11 @@ static bool recover_job(color_ostream &out, ProtectedJob *pj)
}
// Create and link in the actual job structure
df::job *recovered = cloneJobStruct(pj->job_copy);
df::job *recovered = Job::cloneJobStruct(pj->job_copy);
if (!linkJobIntoWorld(recovered, false)) // reuse same id
if (!Job::linkIntoWorld(recovered, false)) // reuse same id
{
deleteJobStruct(recovered);
Job::deleteJobStruct(recovered);
out.printerr("Inconsistency: job %d (%s) already in list.\n",
pj->id, ENUM_KEY_STR(job_type, pj->job_copy->job_type).c_str());
@ -1435,7 +1435,7 @@ static void print_job(color_ostream &out, ProtectedJob *pj)
df::job *job = pj->isLive() ? pj->actual_job : pj->job_copy;
printJobDetails(out, job);
Job::printJobDetails(out, job);
if (job->job_type == job_type::MeltMetalObject &&
isOptionEnabled(CF_AUTOMELT))
@ -1560,7 +1560,7 @@ static command_result workflow_cmd(color_ostream &out, vector <string> & paramet
pending = true;
}
printJobDetails(out, pending_recover[i]->job_copy);
Job::printJobDetails(out, pending_recover[i]->job_copy);
}
}