diff --git a/LUA_API.rst b/LUA_API.rst index e2d336f7e..3b2847a58 100644 --- a/LUA_API.rst +++ b/LUA_API.rst @@ -779,9 +779,9 @@ Maps module Returns a map block object for given x,y,z in local block coordinates. -* ``dfhack.maps.getTileBlock(coords)`` +* ``dfhack.maps.getTileBlock(coords)``, or ``getTileBlock(x,y,z)`` - Returns a map block object for given df::coord in local tile coordinates. + Returns a map block object for given df::coord or x,y,z in local tile coordinates. * ``dfhack.maps.getRegionBiome(region_coord2d)`` diff --git a/Lua API.html b/Lua API.html index ebfbe80ed..c7c2041db 100644 --- a/Lua API.html +++ b/Lua API.html @@ -1005,8 +1005,8 @@ Returns false in case of error.

  • dfhack.maps.getBlock(x,y,z)

    Returns a map block object for given x,y,z in local block coordinates.

  • -
  • dfhack.maps.getTileBlock(coords)

    -

    Returns a map block object for given df::coord in local tile coordinates.

    +
  • dfhack.maps.getTileBlock(coords), or getTileBlock(x,y,z)

    +

    Returns a map block object for given df::coord or x,y,z in local tile coordinates.

  • dfhack.maps.getRegionBiome(region_coord2d)

    Returns the biome info struct for the given global map region.

    @@ -1129,7 +1129,7 @@ from the size of the building.

  • dfhack.constructions.designateNew(pos,type,item_type,mat_index)

    Designates a new construction at given position. If there already is a planned but not completed construction there, changes its type. -Returns true or false if obstructed. +Returns true, or false if obstructed. Note that designated constructions are technically buildings.

  • diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 0d0647183..05a71d610 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -520,8 +520,7 @@ static int dfhack_matinfo_matches(lua_State *state) else if (lua_istable(state, 2)) { df::dfhack_material_category tmp; - if (!Lua::AssignDFObject(*Lua::GetOutput(state), state, &tmp, 2, false)) - lua_error(state); + Lua::CheckDFObject(state, &tmp, 2, false); lua_pushboolean(state, info.matches(tmp)); } else @@ -714,7 +713,6 @@ static const luaL_Reg dfhack_items_funcs[] = { static const LuaWrapper::FunctionReg dfhack_maps_module[] = { WRAPN(getBlock, (df::map_block* (*)(int32_t,int32_t,int32_t))Maps::getBlock), - WRAPN(getTileBlock, (df::map_block* (*)(df::coord))Maps::getTileBlock), WRAPM(Maps, getRegionBiome), WRAPM(Maps, getGlobalInitFeature), WRAPM(Maps, getLocalInitFeature), @@ -722,7 +720,27 @@ static const LuaWrapper::FunctionReg dfhack_maps_module[] = { { NULL, NULL } }; +static int maps_getTileBlock(lua_State *L) +{ + df::map_block *block; + if (lua_gettop(L) == 1) + { + df::coord pos; + Lua::CheckDFObject(L, &pos, 1); + block = Maps::getTileBlock(pos); + } + else + { + block = Maps::getTileBlock( + luaL_checkint(L, 1), luaL_checkint(L, 2), luaL_checkint(L, 3) + ); + } + Lua::PushDFObject(L, block); + return 1; +} + static const luaL_Reg dfhack_maps_funcs[] = { + { "getTileBlock", maps_getTileBlock }, { NULL, NULL } }; diff --git a/library/LuaTools.cpp b/library/LuaTools.cpp index 253af099c..85e93fbba 100644 --- a/library/LuaTools.cpp +++ b/library/LuaTools.cpp @@ -84,7 +84,7 @@ void *DFHack::Lua::GetDFObject(lua_State *state, type_identity *type, int val_in return get_object_internal(state, type, val_index, exact_type, false); } -void *DFHack::Lua::CheckDFObject(lua_State *state, type_identity *type, int val_index, bool exact_type) +static void check_valid_ptr_index(lua_State *state, int val_index) { if (lua_type(state, val_index) == LUA_TNONE) { @@ -93,23 +93,47 @@ void *DFHack::Lua::CheckDFObject(lua_State *state, type_identity *type, int val_ else luaL_error(state, "at index %d: pointer expected", val_index); } +} - if (lua_isnil(state, val_index)) - return NULL; +static void dfhack_printerr(lua_State *S, const std::string &str); - void *rv = get_object_internal(state, type, val_index, exact_type, false); +static void signal_typeid_error(color_ostream *out, lua_State *state, + type_identity *type, const char *msg, + int val_index, bool perr, bool signal) +{ + std::string error = stl_sprintf(msg, type->getFullName().c_str()); - if (!rv) + if (signal) { - std::string error = "invalid pointer type"; - if (type) - error += "; expected: " + type->getFullName(); - if (val_index > 0) luaL_argerror(state, val_index, error.c_str()); else luaL_error(state, "at index %d: %s", val_index, error.c_str()); } + else if (perr) + { + if (out) + out->printerr("%s", error.c_str()); + else + dfhack_printerr(state, error); + } + else + lua_pushstring(state, error.c_str()); +} + + +void *DFHack::Lua::CheckDFObject(lua_State *state, type_identity *type, int val_index, bool exact_type) +{ + check_valid_ptr_index(state, val_index); + + if (lua_isnil(state, val_index)) + return NULL; + + void *rv = get_object_internal(state, type, val_index, exact_type, false); + + if (!rv) + signal_typeid_error(NULL, state, type, "invalid pointer type; expected: %s", + val_index, false, true); return rv; } @@ -343,7 +367,7 @@ static void error_tostring(lua_State *L, bool keep_old = false) } } -static void report_error(lua_State *L, color_ostream *out = NULL) +static void report_error(lua_State *L, color_ostream *out = NULL, bool pop = false) { error_tostring(L, true); @@ -355,7 +379,7 @@ static void report_error(lua_State *L, color_ostream *out = NULL) else dfhack_printerr(L, msg); - lua_pop(L, 1); + lua_pop(L, pop?2:1); } static bool convert_to_exception(lua_State *L, int slevel, lua_State *thread = NULL) @@ -544,10 +568,7 @@ bool DFHack::Lua::SafeCall(color_ostream &out, lua_State *L, int nargs, int nres bool ok = lua_pcall(L, nargs, nres, base) == LUA_OK; if (!ok && perr) - { - report_error(L, &out); - lua_pop(L, 1); - } + report_error(L, &out, true); lua_remove(L, base); set_dfhack_output(L, cur_out); @@ -658,10 +679,7 @@ int DFHack::Lua::SafeResume(color_ostream &out, lua_State *from, lua_State *thre int rv = resume_helper(from, thread, nargs, nres); if (!Lua::IsSuccess(rv) && perr) - { - report_error(from, &out); - lua_pop(from, 1); - } + report_error(from, &out, true); set_dfhack_output(from, cur_out); @@ -746,14 +764,64 @@ bool DFHack::Lua::Require(color_ostream &out, lua_State *state, return true; } +static bool doAssignDFObject(color_ostream *out, lua_State *state, + type_identity *type, void *target, int val_index, + bool exact, bool perr, bool signal) +{ + if (signal) + check_valid_ptr_index(state, val_index); + + if (lua_istable(state, val_index)) + { + val_index = lua_absindex(state, val_index); + lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_ASSIGN_NAME); + Lua::PushDFObject(state, type, target); + lua_pushvalue(state, val_index); + + if (signal) + { + lua_call(state, 2, 0); + return true; + } + else + return Lua::SafeCall(*out, state, 2, 0, perr); + } + else if (!lua_isuserdata(state, val_index)) + { + signal_typeid_error(out, state, type, "pointer to %s expected", + val_index, perr, signal); + return false; + } + else + { + void *in_ptr = Lua::GetDFObject(state, type, val_index, exact); + if (!in_ptr) + { + signal_typeid_error(out, state, type, "incompatible pointer type: %s expected", + val_index, perr, signal); + return false; + } + if (!type->copy(target, in_ptr)) + { + signal_typeid_error(out, state, type, "no copy support for %s", + val_index, perr, signal); + return false; + } + return true; + } +} + bool DFHack::Lua::AssignDFObject(color_ostream &out, lua_State *state, - type_identity *type, void *target, int val_index, bool perr) + type_identity *type, void *target, int val_index, + bool exact_type, bool perr) { - val_index = lua_absindex(state, val_index); - lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_ASSIGN_NAME); - PushDFObject(state, type, target); - lua_pushvalue(state, val_index); - return Lua::SafeCall(out, state, 2, 0, perr); + return doAssignDFObject(&out, state, type, target, val_index, exact_type, perr, false); +} + +void DFHack::Lua::CheckDFObject(lua_State *state, type_identity *type, + void *target, int val_index, bool exact_type) +{ + doAssignDFObject(NULL, state, type, target, val_index, exact_type, false, true); } bool DFHack::Lua::SafeCallString(color_ostream &out, lua_State *state, const std::string &code, @@ -773,10 +841,7 @@ bool DFHack::Lua::SafeCallString(color_ostream &out, lua_State *state, const std if (luaL_loadbuffer(state, code.data(), code.size(), debug_tag) != LUA_OK) { if (perr) - { - report_error(state, &out); - lua_pop(state, 1); - } + report_error(state, &out, true); return false; } @@ -1113,10 +1178,7 @@ static void do_invoke_event(lua_State *L, int argbase, int num_args, int errorfu lua_pushvalue(L, argbase+i); if (lua_pcall(L, num_args, 0, errorfun) != LUA_OK) - { - report_error(L); - lua_pop(L, 1); - } + report_error(L, NULL, true); } static void dfhack_event_invoke(lua_State *L, int base, bool from_c) diff --git a/library/include/LuaTools.h b/library/include/LuaTools.h index 1ca79d331..a6e538d2a 100644 --- a/library/include/LuaTools.h +++ b/library/include/LuaTools.h @@ -109,7 +109,15 @@ namespace DFHack {namespace Lua { * Return behavior is of SafeCall below. */ DFHACK_EXPORT bool AssignDFObject(color_ostream &out, lua_State *state, - type_identity *type, void *target, int val_index, bool perr = true); + type_identity *type, void *target, int val_index, + bool exact_type = false, bool perr = true); + + /** + * Assign the value at val_index to the target of given identity using df.assign(). + * Otherwise throws an error. + */ + DFHACK_EXPORT void CheckDFObject(lua_State *state, type_identity *type, + void *target, int val_index, bool exact_type = false); /** * Push the pointer onto the stack as a wrapped DF object of a specific type. @@ -139,8 +147,19 @@ namespace DFHack {namespace Lua { * Assign the value at val_index to the target using df.assign(). */ template - bool AssignDFObject(color_ostream &out, lua_State *state, T *target, int val_index, bool perr = true) { - return AssignDFObject(out, state, df::identity_traits::get(), target, val_index, perr); + bool AssignDFObject(color_ostream &out, lua_State *state, T *target, + int val_index, bool exact_type = false, bool perr = true) { + return AssignDFObject(out, state, df::identity_traits::get(), + target, val_index, exact_type, perr); + } + + /** + * Assign the value at val_index to the target using df.assign(). + * Throws in case of an error. + */ + template + void CheckDFObject(lua_State *state, T *target, int val_index, bool exact_type = false) { + CheckDFObject(state, df::identity_traits::get(), target, val_index, exact_type); } /**