diff --git a/src/logic/scripting/lua/libcore.cpp b/src/logic/scripting/lua/libcore.cpp index dcfc93e7..86b4e9f6 100644 --- a/src/logic/scripting/lua/libcore.cpp +++ b/src/logic/scripting/lua/libcore.cpp @@ -47,7 +47,7 @@ static int l_reopen_world(lua_State*) { static int l_close_world(lua_State* L) { if (scripting::controller == nullptr) { - luaL_error(L, "no world open"); + throw std::runtime_error("no world open"); } bool save_world = lua_toboolean(L, 1); if (save_world) { @@ -69,12 +69,15 @@ static int l_delete_world(lua_State* L) { static int l_reconfig_packs(lua_State* L) { if (!lua_istable(L, 1)) { - luaL_error(L, "strings array expected as the first argument"); + throw std::runtime_error("strings array expected as the first argument"); } if (!lua_istable(L, 2)) { - luaL_error(L, "strings array expected as the second argument"); + throw std::runtime_error("strings array expected as the second argument"); } std::vector addPacks; + if (!lua_istable(L, 1)) { + throw std::runtime_error("an array expected as argument 1"); + } int addLen = lua_objlen(L, 1); for (int i = 0; i < addLen; i++) { lua_rawgeti(L, 1, i+1); @@ -83,6 +86,9 @@ static int l_reconfig_packs(lua_State* L) { } std::vector remPacks; + if (!lua_istable(L, 2)) { + throw std::runtime_error("an array expected as argument 2"); + } int remLen = lua_objlen(L, 2); for (int i = 0; i < remLen; i++) { lua_rawgeti(L, 2, i+1); @@ -147,8 +153,7 @@ static int l_get_setting_info(lua_State* L) { return 1; } lua_pop(L, 1); - luaL_error(L, "unsupported setting type"); - return 0; + throw std::runtime_error("unsupported setting type"); } static int l_quit(lua_State*) { diff --git a/src/logic/scripting/lua/libfile.cpp b/src/logic/scripting/lua/libfile.cpp index 67023891..9c6ebe97 100644 --- a/src/logic/scripting/lua/libfile.cpp +++ b/src/logic/scripting/lua/libfile.cpp @@ -4,19 +4,15 @@ #include "../../../engine.hpp" #include "../../../files/files.hpp" #include "../../../files/engine_paths.hpp" +#include "../../../util/stringutil.hpp" #include #include namespace fs = std::filesystem; -static fs::path resolve_path(lua_State* L, const std::string& path) { - try { - return scripting::engine->getPaths()->resolve(path); - } catch (const files_access_error& err) { - luaL_error(L, err.what()); - abort(); // unreachable - } +static fs::path resolve_path(lua_State*, const std::string& path) { + return scripting::engine->getPaths()->resolve(path); } static int l_file_find(lua_State* L) { @@ -37,7 +33,7 @@ static int l_file_read(lua_State* L) { lua_pushstring(L, files::read_string(path).c_str()); return 1; } - return luaL_error(L, "file does not exists '%s'", path.u8string().c_str()); + throw std::runtime_error("file does not exists "+util::quote(path.u8string())); } static int l_file_write(lua_State* L) { @@ -103,27 +99,22 @@ static int l_file_read_bytes(lua_State* L) { } return 1; } - return luaL_error(L, "file does not exists '%s'", path.u8string().c_str()); + throw std::runtime_error("file does not exists "+util::quote(path.u8string())); } static int read_bytes_from_table(lua_State* L, int tableIndex, std::vector& bytes) { if(!lua_istable(L, tableIndex)) { - return luaL_error(L, "table expected"); + throw std::runtime_error("table expected"); } else { lua_pushnil(L); - while(lua_next(L, tableIndex - 1) != 0) { const int byte = lua_tointeger(L, -1); - if(byte < 0 || byte > 255) { - return luaL_error(L, "invalid byte '%i'", byte); + throw std::runtime_error("invalid byte '"+std::to_string(byte)+"'"); } - - bytes.push_back(byte); - + bytes.push_back(byte); lua_pop(L, 1); } - return 1; } } @@ -132,7 +123,7 @@ static int l_file_write_bytes(lua_State* L) { int pathIndex = 1; if(!lua_isstring(L, pathIndex)) { - return luaL_error(L, "string expected"); + throw std::runtime_error("string expected"); } fs::path path = resolve_path(L, lua_tostring(L, pathIndex)); diff --git a/src/logic/scripting/lua/libgui.cpp b/src/logic/scripting/lua/libgui.cpp index b224c138..84973805 100644 --- a/src/logic/scripting/lua/libgui.cpp +++ b/src/logic/scripting/lua/libgui.cpp @@ -34,14 +34,14 @@ struct DocumentNode { using namespace scripting; -static DocumentNode getDocumentNode(lua_State* L, const std::string& name, const std::string& nodeName) { +static DocumentNode getDocumentNode(lua_State*, const std::string& name, const std::string& nodeName) { auto doc = engine->getAssets()->getLayout(name); if (doc == nullptr) { - luaL_error(L, "document '%s' not found", name.c_str()); + throw std::runtime_error("document '"+name+"' not found"); } auto node = doc->get(nodeName); if (node == nullptr) { - luaL_error(L, "document '%s' has no element with id '%s'", name.c_str(), nodeName.c_str()); + throw std::runtime_error("document '"+name+"' has no element with id '"+nodeName+"'"); } return {doc, node}; } @@ -79,7 +79,7 @@ static int l_container_add(lua_State* L) { node->add(subnode); UINode::getIndices(subnode, docnode.document->getMapWriteable()); } catch (const std::exception& err) { - luaL_error(L, err.what()); + throw std::runtime_error(err.what()); } return 0; } @@ -418,7 +418,7 @@ static int l_gui_get_env(lua_State* L) { auto name = lua_tostring(L, 1); auto doc = scripting::engine->getAssets()->getLayout(name); if (doc == nullptr) { - luaL_error(L, "document '%s' not found", name); + throw std::runtime_error("document '"+std::string(name)+"' not found"); } lua_getglobal(L, lua::LuaState::envName(*doc->getEnvironment()).c_str()); return 1; @@ -439,7 +439,7 @@ static int l_gui_reindex(lua_State* L) { auto name = lua_tostring(L, 1); auto doc = scripting::engine->getAssets()->getLayout(name); if (doc == nullptr) { - luaL_error(L, "document '%s' not found", name); + throw std::runtime_error("document '"+std::string(name)+"' not found"); } doc->rebuildIndices(); return 0; diff --git a/src/logic/scripting/lua/libhud.cpp b/src/logic/scripting/lua/libhud.cpp index 270980e0..9c03a9b8 100644 --- a/src/logic/scripting/lua/libhud.cpp +++ b/src/logic/scripting/lua/libhud.cpp @@ -10,6 +10,7 @@ #include "../../../graphics/ui/elements/InventoryView.hpp" #include "../../../items/Inventories.hpp" #include "../../../logic/BlocksController.hpp" +#include "../../../util/stringutil.hpp" #include "../../../voxels/Block.hpp" #include "../../../voxels/Chunks.hpp" #include "../../../voxels/voxel.hpp" @@ -45,17 +46,18 @@ static int l_hud_open_block(lua_State* L) { voxel* vox = scripting::level->chunks->get(x, y, z); if (vox == nullptr) { - luaL_error(L, "block does not exists at %d %d %d", x, y, z); + throw std::runtime_error("block does not exists at "+ + std::to_string(x) + " " + std::to_string(y) + " " + std::to_string(z) + ); } auto def = scripting::content->getIndices()->getBlockDef(vox->id); auto assets = scripting::engine->getAssets(); auto layout = assets->getLayout(def->uiLayout); if (layout == nullptr) { - luaL_error(L, "block '%s' has no ui layout", def->name.c_str()); + throw std::runtime_error("block '"+def->name+"' has no ui layout"); } auto id = scripting::blocks->createBlockInventory(x, y, z); - scripting::hud->openInventory( glm::ivec3(x, y, z), layout, scripting::level->inventories->get(id), playerInventory ); @@ -72,7 +74,7 @@ static int l_hud_show_overlay(lua_State* L) { auto assets = scripting::engine->getAssets(); auto layout = assets->getLayout(name); if (layout == nullptr) { - luaL_error(L, "there is no ui layout '%s'", name); + throw std::runtime_error("there is no ui layout "+util::quote(name)); } scripting::hud->showOverlay(layout, playerInventory); return 0; @@ -82,7 +84,7 @@ static UiDocument* require_layout(lua_State* L, const char* name) { auto assets = scripting::engine->getAssets(); auto layout = assets->getLayout(name); if (layout == nullptr) { - luaL_error(L, "layout '%s' is not found", name); + throw std::runtime_error("layout '"+std::string(name)+"' is not found"); } return layout; } diff --git a/src/logic/scripting/lua/libinput.cpp b/src/logic/scripting/lua/libinput.cpp index 56977498..f654dc47 100644 --- a/src/logic/scripting/lua/libinput.cpp +++ b/src/logic/scripting/lua/libinput.cpp @@ -5,6 +5,7 @@ #include "../../../window/input.hpp" #include "../../../window/Events.hpp" +#include "../../../util/stringutil.hpp" #include "../../../frontend/screens/Screen.hpp" #include "../../../frontend/hud.hpp" #include "../../../engine.hpp" @@ -26,7 +27,7 @@ static int l_add_callback(lua_State* L) { auto bindname = lua_tostring(L, 1); const auto& bind = Events::bindings.find(bindname); if (bind == Events::bindings.end()) { - luaL_error(L, "unknown binding %q", bindname); + throw std::runtime_error("unknown binding "+util::quote(bindname)); } state->pushvalue(2); runnable callback = state->createRunnable(); diff --git a/src/logic/scripting/lua/libinventory.cpp b/src/logic/scripting/lua/libinventory.cpp index 6fe9ced7..067c7943 100644 --- a/src/logic/scripting/lua/libinventory.cpp +++ b/src/logic/scripting/lua/libinventory.cpp @@ -8,22 +8,40 @@ #include "../../../items/Inventories.hpp" #include "../../../logic/BlocksController.hpp" -static void validate_itemid(lua_State* L, itemid_t id) { +static void validate_itemid(itemid_t id) { if (id >= scripting::indices->countItemDefs()) { - luaL_error(L, "invalid item id"); + throw std::runtime_error("invalid item id"); + } +} + +static std::shared_ptr get_inventory(int64_t id) { + auto inv = scripting::level->inventories->get(id); + if (inv == nullptr) { + throw std::runtime_error("inventory not found: "+std::to_string(id)); + } + return inv; +} + +static std::shared_ptr get_inventory(int64_t id, int arg) { + auto inv = scripting::level->inventories->get(id); + if (inv == nullptr) { + throw std::runtime_error("inventory not found: "+std::to_string(id)+ + " argument "+std::to_string(arg)); + } + return inv; +} + +static void validate_slotid(int slotid, Inventory* inv) { + if (slotid < 0 || uint64_t(slotid) >= inv->size()) { + throw std::runtime_error("slot index is out of range [0..inventory.size(invid)]"); } } static int l_inventory_get(lua_State* L) { lua::luaint invid = lua_tointeger(L, 1); lua::luaint slotid = lua_tointeger(L, 2); - auto inv = scripting::level->inventories->get(invid); - if (inv == nullptr) { - luaL_error(L, "inventory does not exists in runtime: %d", invid); - } - if (slotid < 0 || uint64_t(slotid) >= inv->size()) { - luaL_error(L, "slot index is out of range [0, inventory.size(invid)]"); - } + auto inv = get_inventory(invid); + validate_slotid(slotid, inv.get()); const ItemStack& item = inv->getSlot(slotid); lua_pushinteger(L, item.getItemId()); lua_pushinteger(L, item.getCount()); @@ -35,15 +53,11 @@ static int l_inventory_set(lua_State* L) { lua::luaint slotid = lua_tointeger(L, 2); lua::luaint itemid = lua_tointeger(L, 3); lua::luaint count = lua_tointeger(L, 4); - validate_itemid(L, itemid); + validate_itemid(itemid); - auto inv = scripting::level->inventories->get(invid); - if (inv == nullptr) { - luaL_error(L, "inventory does not exists in runtime: %d", invid); - } - if (slotid < 0 || uint64_t(slotid) >= inv->size()) { - luaL_error(L, "slot index is out of range [0, inventory.size(invid)]"); - } + auto inv = get_inventory(invid); + + validate_slotid(slotid, inv.get()); ItemStack& item = inv->getSlot(slotid); item.set(ItemStack(itemid, count)); return 0; @@ -51,10 +65,7 @@ static int l_inventory_set(lua_State* L) { static int l_inventory_size(lua_State* L) { lua::luaint invid = lua_tointeger(L, 1); - auto inv = scripting::level->inventories->get(invid); - if (inv == nullptr) { - luaL_error(L, "inventory does not exists in runtime: %d", invid); - } + auto inv = get_inventory(invid); lua_pushinteger(L, inv->size()); return 1; } @@ -63,12 +74,9 @@ static int l_inventory_add(lua_State* L) { lua::luaint invid = lua_tointeger(L, 1); lua::luaint itemid = lua_tointeger(L, 2); lua::luaint count = lua_tointeger(L, 3); - validate_itemid(L, itemid); + validate_itemid(itemid); - auto inv = scripting::level->inventories->get(invid); - if (inv == nullptr) { - luaL_error(L, "inventory does not exists in runtime: %d", invid); - } + auto inv = get_inventory(invid); ItemStack item(itemid, count); inv->move(item, scripting::indices); lua_pushinteger(L, item.getCount()); @@ -115,17 +123,12 @@ static int l_inventory_clone(lua_State* L) { static int l_inventory_move(lua_State* L) { lua::luaint invAid = lua_tointeger(L, 1); lua::luaint slotAid = lua_tointeger(L, 2); - auto invA = scripting::level->inventories->get(invAid); - if (invA == nullptr) { - luaL_error(L, "inventory A does not exists in runtime: %d", invAid); - } + auto invA = get_inventory(invAid, 1); + validate_slotid(slotAid, invA.get()); lua::luaint invBid = lua_tointeger(L, 3); lua::luaint slotBid = lua_isnil(L, 4) ? -1 : lua_tointeger(L, 4); - auto invB = scripting::level->inventories->get(invBid); - if (invB == nullptr) { - luaL_error(L, "inventory B does not exists in runtime: %d", invBid); - } + auto invB = get_inventory(invBid, 3); auto& slot = invA->getSlot(slotAid); if (slotBid == -1) { invB->move(slot, scripting::content->getIndices()); diff --git a/src/logic/scripting/lua/libjson.cpp b/src/logic/scripting/lua/libjson.cpp index bce8b1b6..2c72a75e 100644 --- a/src/logic/scripting/lua/libjson.cpp +++ b/src/logic/scripting/lua/libjson.cpp @@ -18,8 +18,7 @@ static int l_json_stringify(lua_State* L) { lua_pushstring(L, string.c_str()); return 1; } else { - luaL_error(L, "table expected"); - return 0; + throw std::runtime_error("table expected"); } } diff --git a/src/logic/scripting/lua/lua_util.hpp b/src/logic/scripting/lua/lua_util.hpp index 33176c95..4d9e37bf 100644 --- a/src/logic/scripting/lua/lua_util.hpp +++ b/src/logic/scripting/lua/lua_util.hpp @@ -11,6 +11,8 @@ #endif #include +#include + namespace lua { inline int pushivec3(lua_State* L, luaint x, luaint y, luaint z) { lua_pushinteger(L, x); @@ -94,6 +96,9 @@ namespace lua { inline glm::vec2 tovec2(lua_State* L, int idx) { lua_pushvalue(L, idx); + if (!lua_istable(L, idx) || lua_objlen(L, idx) < 2) { + throw std::runtime_error("value must be an array of two numbers"); + } lua_rawgeti(L, -1, 1); lua::luanumber x = lua_tonumber(L, -1); lua_pop(L, 1); lua_rawgeti(L, -1, 2); @@ -104,8 +109,8 @@ namespace lua { inline glm::vec4 tocolor(lua_State* L, int idx) { lua_pushvalue(L, idx); - if (!lua_istable(L, -1)) { - luaL_error(L, "RGBA array required"); + if (!lua_istable(L, -1) || lua_objlen(L, idx) < 4) { + throw std::runtime_error("RGBA array required"); } lua_rawgeti(L, -1, 1); lua::luanumber r = lua_tonumber(L, -1); lua_pop(L, 1); diff --git a/src/util/stringutil.hpp b/src/util/stringutil.hpp index 3270c92e..ebfd6664 100644 --- a/src/util/stringutil.hpp +++ b/src/util/stringutil.hpp @@ -5,6 +5,7 @@ #include #include +#include namespace util { /// @brief Function used for string serialization in text formats