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

develop
Robert Heinrich 2012-03-28 11:56:59 +02:00
commit 4646033741
7 changed files with 235 additions and 16 deletions

@ -972,6 +972,7 @@ int Core::UnicodeAwareSym(const SDL::KeyboardEvent& ke)
{
// Assume keyboard layouts don't change the order of numbers:
if( '0' <= ke.ksym.sym && ke.ksym.sym <= '9') return ke.ksym.sym;
if(SDL::K_F1 <= ke.ksym.sym && ke.ksym.sym <= SDL::K_F12) return ke.ksym.sym;
int unicode = ke.ksym.unicode;

@ -65,9 +65,22 @@ void constructed_identity::lua_read(lua_State *state, int fname_idx, void *ptr)
push_object_internal(state, this, ptr);
}
static void invoke_assign(lua_State *state, type_identity *id, void *ptr, int val_index)
{
lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_ASSIGN_NAME);
push_object_internal(state, id, ptr);
lua_pushvalue(state, val_index);
lua_call(state, 2, 0);
}
void constructed_identity::lua_write(lua_State *state, int fname_idx, void *ptr, int val_index)
{
field_error(state, fname_idx, "complex object", "write");
if (lua_istable(state, val_index))
{
invoke_assign(state, this, ptr, val_index);
}
else
field_error(state, fname_idx, "complex object", "write");
}
void enum_identity::lua_read(lua_State *state, int fname_idx, void *ptr)
@ -150,6 +163,58 @@ void df::pointer_identity::lua_read(lua_State *state, int fname_idx, void *ptr)
lua_read(state, fname_idx, ptr, target);
}
static void autovivify_ptr(lua_State *state, int fname_idx, void **pptr,
type_identity *target, int val_index)
{
lua_getfield(state, val_index, "new");
// false or nil => bail out
if (!lua_toboolean(state, -1))
field_error(state, fname_idx, "null and autovivify not requested", "write");
// not 'true' => call df.new()
if (!lua_isboolean(state, -1))
{
int top = lua_gettop(state);
// Verify new points to a reasonable type of object
type_identity *suggested = get_object_identity(state, top, "autovivify", true, true);
if (!is_type_compatible(state, target, 0, suggested, top+1, false))
field_error(state, fname_idx, "incompatible suggested autovivify type", "write");
lua_pop(state, 1);
// Invoke df.new()
lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_NEW_NAME);
lua_swap(state);
lua_call(state, 1, 1);
// Retrieve the pointer
void *nval = get_object_internal(state, target, top, false);
// shouldn't happen: this means suggested type is compatible,
// but its new() result isn't for some reason.
if (!nval)
field_error(state, fname_idx, "inconsistent autovivify type", "write");
*pptr = nval;
}
// otherwise use the target type
else
{
if (!target)
field_error(state, fname_idx, "trying to autovivify void*", "write");
*pptr = target->allocate();
if (!*pptr)
field_error(state, fname_idx, "could not allocate in autovivify", "write");
}
lua_pop(state, 1);
}
void df::pointer_identity::lua_write(lua_State *state, int fname_idx, void *ptr,
type_identity *target, int val_index)
{
@ -157,6 +222,13 @@ void df::pointer_identity::lua_write(lua_State *state, int fname_idx, void *ptr,
if (lua_isnil(state, val_index))
*pptr = NULL;
else if (lua_istable(state, val_index))
{
if (!*pptr)
autovivify_ptr(state, fname_idx, pptr, target, val_index);
invoke_assign(state, target, *pptr, val_index);
}
else
{
void *nval = get_object_internal(state, target, val_index, false);
@ -435,10 +507,15 @@ static void write_field(lua_State *state, const struct_field_info *field, void *
case struct_field_info::POINTER:
df::pointer_identity::lua_write(state, 2, ptr, field->type, value_idx);
return;
case struct_field_info::STATIC_ARRAY:
case struct_field_info::STL_VECTOR_PTR:
field_error(state, 2, "complex object", "write");
lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_ASSIGN_NAME);
read_field(state, field, ptr);
lua_pushvalue(state, value_idx);
lua_call(state, 2, 0);
return;
case struct_field_info::END:
return;

@ -255,8 +255,8 @@ static void fetch_container_details(lua_State *state, int meta, type_identity **
/**
* Check if type1 and type2 are compatible, possibly using additional metatable data.
*/
static bool is_type_compatible(lua_State *state, type_identity *type1, int meta1,
type_identity *type2, int meta2, bool exact_equal)
bool LuaWrapper::is_type_compatible(lua_State *state, type_identity *type1, int meta1,
type_identity *type2, int meta2, bool exact_equal)
{
if (type1 == type2)
return true;
@ -417,9 +417,9 @@ static bool is_valid_metatable(lua_State *state, int objidx, int metaidx)
/**
* Given a DF object reference or type, safely retrieve its identity pointer.
*/
static type_identity *get_object_identity(lua_State *state, int objidx,
const char *ctx, bool allow_type = false,
bool keep_metatable = false)
type_identity *LuaWrapper::get_object_identity(lua_State *state, int objidx,
const char *ctx, bool allow_type,
bool keep_metatable)
{
if (!lua_getmetatable(state, objidx))
luaL_error(state, "Invalid object in %s", ctx);
@ -608,6 +608,43 @@ static int meta_new(lua_State *state)
return 1;
}
static void invoke_resize(lua_State *state, int table, lua_Integer size)
{
lua_getfield(state, table, "resize");
lua_pushvalue(state, table);
lua_pushinteger(state, size);
lua_call(state, 2, 0);
}
static void copy_table(lua_State *state, int dest, int src, int skipbase)
{
// stack: (skipbase) skipkey skipkey |
int top = lua_gettop(state);
lua_pushnil(state);
while (lua_next(state, src))
{
for (int i = skipbase+1; i <= top; i++)
{
if (lua_rawequal(state, -2, i))
{
lua_pop(state, 1);
goto next_outer;
}
}
{
lua_pushvalue(state, -2);
lua_swap(state);
lua_settable(state, dest);
}
next_outer:;
}
}
/**
* Method: assign data between objects.
*/
@ -618,11 +655,105 @@ static int meta_assign(lua_State *state)
if (argc != 2)
luaL_error(state, "Usage: target:assign(src) or df.assign(target,src)");
type_identity *id1, *id2;
check_type_compatible(state, 1, 2, &id1, &id2, "df.assign()", false, false);
if (!lua_istable(state, 2))
{
type_identity *id1, *id2;
check_type_compatible(state, 1, 2, &id1, &id2, "df.assign()", false, false);
if (!id1->copy(get_object_ref(state, 1), get_object_ref(state, 2)))
luaL_error(state, "No copy support for %s", id1->getFullName().c_str());
}
else
{
type_identity *id = get_object_identity(state, 1, "df.assign()", false);
int base = lua_gettop(state);
// x:assign{ assign = foo } => x:assign(foo)
bool has_assign = false;
lua_pushstring(state, "assign");
lua_dup(state);
lua_rawget(state, 2);
if (!lua_isnil(state,-1))
{
has_assign = true;
lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_ASSIGN_NAME);
lua_pushvalue(state, 1);
lua_pushvalue(state, base+2);
lua_call(state, 2, 0);
}
lua_pop(state, 1);
// new is used by autovivification and should be skipped
lua_pushstring(state, "new");
if (id->isContainer())
{
// check resize field
lua_pushstring(state, "resize");
lua_dup(state);
lua_rawget(state, 2);
if (lua_isnil(state,-1) && !has_assign)
{
/*
* no assign && nil or missing resize field => 1-based lua array
*/
int size = lua_objlen(state, 2);
lua_pop(state, 1);
invoke_resize(state, 1, size);
for (int i = 1; i <= size; i++)
{
lua_pushinteger(state, i-1);
lua_rawgeti(state, 2, i);
lua_settable(state, 1);
}
}
else
{
if (lua_isboolean(state, -1) || lua_isnil(state, -1))
{
// resize=false => just assign
// resize=true => find the largest index
if (lua_toboolean(state, -1))
{
lua_Integer size = 0;
lua_pushnil(state);
while (lua_next(state, 2))
{
lua_pop(state, 1);
if (lua_isnumber(state,-1))
size = std::max(size, lua_tointeger(state,-1)+1);
}
invoke_resize(state, 1, size);
}
}
else
{
// otherwise, must be an explicit number
if (!lua_isnumber(state,-1))
luaL_error(state, "Invalid container.resize value in df.assign()");
invoke_resize(state, 1, lua_tointeger(state, -1));
}
lua_pop(state, 1);
copy_table(state, 1, 2, base);
}
}
else
{
if (!id1->copy(get_object_ref(state, 1), get_object_ref(state, 2)))
luaL_error(state, "No copy support for %s", id1->getFullName().c_str());
copy_table(state, 1, 2, base);
}
}
return 0;
}

@ -149,6 +149,13 @@ namespace DFHack { namespace LuaWrapper {
*/
uint8_t *get_object_addr(lua_State *state, int obj, int field, const char *mode);
bool is_type_compatible(lua_State *state, type_identity *type1, int meta1,
type_identity *type2, int meta2, bool exact_equal);
type_identity *get_object_identity(lua_State *state, int objidx,
const char *ctx, bool allow_type = false,
bool keep_metatable = false);
void LookupInTable(lua_State *state, void *id, const char *tname);
void SaveInTable(lua_State *state, void *node, const char *tname);
void SaveTypeInfo(lua_State *state, void *node);

@ -1 +1 @@
Subproject commit b41c666c6be6fe18906a98dababdc4ff681b8382
Subproject commit 8bb7f923b1d124610db7e30aeb3be8f4cb9bd021

@ -96,7 +96,8 @@ const luaL_Reg lua_vinfo_func[]=
VI_FUNC(setAddress),
VI_FUNC(getAddress),
VI_FUNC(setOS),
VI_FUNC(getOS)
VI_FUNC(getOS),
{NULL,NULL}
};
#undef VI_FUNC
void lua::RegisterVersionInfo(lua::state &st)

@ -802,7 +802,6 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out )
}
// Idle dwarves come first, then we sort from least-skilled to most-skilled.
std::sort(hauler_ids.begin(), hauler_ids.end(), [&dwarf_info] (int i, int j) -> bool
{
if (dwarf_info[i].state == IDLE && dwarf_info[j].state != IDLE)
@ -812,6 +811,11 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out )
return dwarf_info[i].mastery_penalty > dwarf_info[j].mastery_penalty;
});
// don't set any haulers if everyone is off drinking or something
if (hauler_ids.size() == 0) {
num_haulers = 0;
}
FOR_ENUM_ITEMS(unit_labor, labor)
{
if (labor == df::enums::unit_labor::NONE)
@ -831,7 +835,6 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out )
assert(dwarf >= 0);
assert(dwarf < n_dwarfs);
dwarfs[dwarf]->status.labors[labor] = true;
dwarf_info[dwarf].assigned_jobs++;
}
@ -848,7 +851,6 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out )
dwarfs[dwarf]->status.labors[labor] = false;
}
}
return CR_OK;
}