diff options
Diffstat (limited to 'src/script')
27 files changed, 715 insertions, 206 deletions
diff --git a/src/script/common/c_content.cpp b/src/script/common/c_content.cpp index cb0253c32..accbb1a87 100644 --- a/src/script/common/c_content.cpp +++ b/src/script/common/c_content.cpp @@ -83,7 +83,7 @@ void read_item_definition(lua_State* L, int index, getboolfield(L, index, "liquids_pointable", def.liquids_pointable); warn_if_field_exists(L, index, "tool_digging_properties", - "Deprecated; use tool_capabilities"); + "Obsolete; use tool_capabilities"); lua_getfield(L, index, "tool_capabilities"); if(lua_istable(L, -1)){ @@ -208,8 +208,6 @@ void read_object_properties(lua_State *L, int index, getboolfield(L, -1, "physical", prop->physical); getboolfield(L, -1, "collide_with_objects", prop->collideWithObjects); - getfloatfield(L, -1, "weight", prop->weight); - lua_getfield(L, -1, "collisionbox"); bool collisionbox_defined = lua_istable(L, -1); if (collisionbox_defined) @@ -340,8 +338,6 @@ void push_object_properties(lua_State *L, ObjectProperties *prop) lua_setfield(L, -2, "physical"); lua_pushboolean(L, prop->collideWithObjects); lua_setfield(L, -2, "collide_with_objects"); - lua_pushnumber(L, prop->weight); - lua_setfield(L, -2, "weight"); push_aabb3f(L, prop->collisionbox); lua_setfield(L, -2, "collisionbox"); push_aabb3f(L, prop->selectionbox); @@ -643,19 +639,19 @@ ContentFeatures read_content_features(lua_State *L, int index) warningstream << "Node " << f.name.c_str() << " has a palette, but not a suitable paramtype2." << std::endl; - // Warn about some deprecated fields + // Warn about some obsolete fields warn_if_field_exists(L, index, "wall_mounted", - "Deprecated; use paramtype2 = 'wallmounted'"); + "Obsolete; use paramtype2 = 'wallmounted'"); warn_if_field_exists(L, index, "light_propagates", - "Deprecated; determined from paramtype"); + "Obsolete; determined from paramtype"); warn_if_field_exists(L, index, "dug_item", - "Deprecated; use 'drop' field"); + "Obsolete; use 'drop' field"); warn_if_field_exists(L, index, "extra_dug_item", - "Deprecated; use 'drop' field"); + "Obsolete; use 'drop' field"); warn_if_field_exists(L, index, "extra_dug_item_rarity", - "Deprecated; use 'drop' field"); + "Obsolete; use 'drop' field"); warn_if_field_exists(L, index, "metadata_name", - "Deprecated; use on_add and metadata callbacks"); + "Obsolete; use on_add and metadata callbacks"); // True for all ground-like things like stone and mud, false for eg. trees getboolfield(L, index, "is_ground_content", f.is_ground_content); @@ -1023,6 +1019,7 @@ void read_server_sound_params(lua_State *L, int index, params.max_hear_distance = BS*getfloatfield_default(L, index, "max_hear_distance", params.max_hear_distance/BS); getboolfield(L, index, "loop", params.loop); + getstringfield(L, index, "exclude_player", params.exclude_player); } } @@ -1851,11 +1848,13 @@ void read_hud_element(lua_State *L, HudElement *elem) elem->size = lua_istable(L, -1) ? read_v2s32(L, -1) : v2s32(); lua_pop(L, 1); - elem->name = getstringfield_default(L, 2, "name", ""); - elem->text = getstringfield_default(L, 2, "text", ""); - elem->number = getintfield_default(L, 2, "number", 0); - elem->item = getintfield_default(L, 2, "item", 0); - elem->dir = getintfield_default(L, 2, "direction", 0); + elem->name = getstringfield_default(L, 2, "name", ""); + elem->text = getstringfield_default(L, 2, "text", ""); + elem->number = getintfield_default(L, 2, "number", 0); + elem->item = getintfield_default(L, 2, "item", 0); + elem->dir = getintfield_default(L, 2, "direction", 0); + elem->z_index = MYMAX(S16_MIN, MYMIN(S16_MAX, + getintfield_default(L, 2, "z_index", 0))); // Deprecated, only for compatibility's sake if (elem->dir == 0) @@ -1921,6 +1920,9 @@ void push_hud_element(lua_State *L, HudElement *elem) push_v3f(L, elem->world_pos); lua_setfield(L, -2, "world_pos"); + + lua_pushnumber(L, elem->z_index); + lua_setfield(L, -2, "z_index"); } HudElementStat read_hud_change(lua_State *L, HudElement *elem, void **value) @@ -1978,6 +1980,10 @@ HudElementStat read_hud_change(lua_State *L, HudElement *elem, void **value) elem->size = read_v2s32(L, 4); *value = &elem->size; break; + case HUD_STAT_Z_INDEX: + elem->z_index = MYMAX(S16_MIN, MYMIN(S16_MAX, luaL_checknumber(L, 4))); + *value = &elem->z_index; + break; } return stat; } diff --git a/src/script/common/c_converter.cpp b/src/script/common/c_converter.cpp index b9d6f0494..3c2f75641 100644 --- a/src/script/common/c_converter.cpp +++ b/src/script/common/c_converter.cpp @@ -335,6 +335,28 @@ video::SColor read_ARGB8(lua_State *L, int index) return color; } +bool is_color_table(lua_State *L, int index) +{ + // Check whole table in case of missing ColorSpec keys: + // This check does not remove the checked value from the stack. + // Only update the value if we know we have a valid ColorSpec key pair. + if (!lua_istable(L, index)) + return false; + + bool is_color_table = false; + lua_getfield(L, index, "r"); + if (!is_color_table) + is_color_table = lua_isnumber(L, -1); + lua_getfield(L, index, "g"); + if (!is_color_table) + is_color_table = lua_isnumber(L, -1); + lua_getfield(L, index, "b"); + if (!is_color_table) + is_color_table = lua_isnumber(L, -1); + lua_pop(L, 3); // b, g, r values + return is_color_table; +} + aabb3f read_aabb3f(lua_State *L, int index, f32 scale) { aabb3f box; diff --git a/src/script/common/c_converter.h b/src/script/common/c_converter.h index f84494c8d..9620bf75a 100644 --- a/src/script/common/c_converter.h +++ b/src/script/common/c_converter.h @@ -110,6 +110,7 @@ v2s32 read_v2s32 (lua_State *L, int index); video::SColor read_ARGB8 (lua_State *L, int index); bool read_color (lua_State *L, int index, video::SColor *color); +bool is_color_table (lua_State *L, int index); aabb3f read_aabb3f (lua_State *L, int index, f32 scale); v3s16 read_v3s16 (lua_State *L, int index); diff --git a/src/script/common/c_internal.cpp b/src/script/common/c_internal.cpp index f792b6218..b19af9f82 100644 --- a/src/script/common/c_internal.cpp +++ b/src/script/common/c_internal.cpp @@ -47,7 +47,7 @@ int script_exception_wrapper(lua_State *L, lua_CFunction f) /* * Note that we can't get tracebacks for LUA_ERRMEM or LUA_ERRERR (without * hacking Lua internals). For LUA_ERRMEM, this is because memory errors will - * not execute the the error handler, and by the time lua_pcall returns the + * not execute the error handler, and by the time lua_pcall returns the * execution stack will have already been unwound. For LUA_ERRERR, there was * another error while trying to generate a backtrace from a LUA_ERRRUN. It is * presumed there is an error with the internal Lua state and thus not possible @@ -135,7 +135,27 @@ void script_run_callbacks_f(lua_State *L, int nargs, lua_remove(L, error_handler); } -void log_deprecated(lua_State *L, const std::string &message) +static void script_log(lua_State *L, const std::string &message, + std::ostream &log_to, bool do_error, int stack_depth) +{ + lua_Debug ar; + + log_to << message << " "; + if (lua_getstack(L, stack_depth, &ar)) { + FATAL_ERROR_IF(!lua_getinfo(L, "Sl", &ar), "lua_getinfo() failed"); + log_to << "(at " << ar.short_src << ":" << ar.currentline << ")"; + } else { + log_to << "(at ?:?)"; + } + log_to << std::endl; + + if (do_error) + script_error(L, LUA_ERRRUN, NULL, NULL); + else + infostream << script_get_backtrace(L) << std::endl; +} + +void log_deprecated(lua_State *L, const std::string &message, int stack_depth) { static bool configured = false; static bool do_log = false; @@ -152,24 +172,6 @@ void log_deprecated(lua_State *L, const std::string &message) } } - if (do_log) { - warningstream << message; - if (L) { // L can be NULL if we get called from scripting_game.cpp - lua_Debug ar; - - if (!lua_getstack(L, 2, &ar)) - FATAL_ERROR_IF(!lua_getstack(L, 1, &ar), "lua_getstack() failed"); - FATAL_ERROR_IF(!lua_getinfo(L, "Sl", &ar), "lua_getinfo() failed"); - warningstream << " (at " << ar.short_src << ":" << ar.currentline << ")"; - } - warningstream << std::endl; - - if (L) { - if (do_error) - script_error(L, LUA_ERRRUN, NULL, NULL); - else - infostream << script_get_backtrace(L) << std::endl; - } - } + if (do_log) + script_log(L, message, warningstream, do_error, stack_depth); } - diff --git a/src/script/common/c_internal.h b/src/script/common/c_internal.h index d2131d1ad..d8cf3fe76 100644 --- a/src/script/common/c_internal.h +++ b/src/script/common/c_internal.h @@ -103,4 +103,6 @@ int script_exception_wrapper(lua_State *L, lua_CFunction f); void script_error(lua_State *L, int pcall_result, const char *mod, const char *fxn); void script_run_callbacks_f(lua_State *L, int nargs, RunCallbacksMode mode, const char *fxn); -void log_deprecated(lua_State *L, const std::string &message); + +void log_deprecated(lua_State *L, const std::string &message, + int stack_depth=1); diff --git a/src/script/cpp_api/s_base.cpp b/src/script/cpp_api/s_base.cpp index caa335d76..ecb1ba39b 100644 --- a/src/script/cpp_api/s_base.cpp +++ b/src/script/cpp_api/s_base.cpp @@ -197,18 +197,22 @@ void ScriptApiBase::loadModFromMemory(const std::string &mod_name) { ModNameStorer mod_name_storer(getStack(), mod_name); - const std::string *init_filename = getClient()->getModFile(mod_name + ":init.lua"); - const std::string display_filename = mod_name + ":init.lua"; - if(init_filename == NULL) - throw ModError("Mod:\"" + mod_name + "\" lacks init.lua"); + sanity_check(m_type == ScriptingType::Client); - verbosestream << "Loading and running script " << display_filename << std::endl; + const std::string init_filename = mod_name + ":init.lua"; + const std::string chunk_name = "@" + init_filename; + + const std::string *contents = getClient()->getModFile(init_filename); + if (!contents) + throw ModError("Mod \"" + mod_name + "\" lacks init.lua"); + + verbosestream << "Loading and running script " << chunk_name << std::endl; lua_State *L = getStack(); int error_handler = PUSH_ERROR_HANDLER(L); - bool ok = ScriptApiSecurity::safeLoadFile(L, init_filename->c_str(), display_filename.c_str()); + bool ok = ScriptApiSecurity::safeLoadString(L, *contents, chunk_name.c_str()); if (ok) ok = !lua_pcall(L, 0, 0, error_handler); if (!ok) { @@ -329,6 +333,20 @@ void ScriptApiBase::setOriginFromTableRaw(int index, const char *fxn) #endif } +/* + * How ObjectRefs are handled in Lua: + * When an active object is created, an ObjectRef is created on the Lua side + * and stored in core.object_refs[id]. + * Methods that require an ObjectRef to a certain object retrieve it from that + * table instead of creating their own.(*) + * When an active object is removed, the existing ObjectRef is invalidated + * using ::set_null() and removed from the core.object_refs table. + * (*) An exception to this are NULL ObjectRefs and anonymous ObjectRefs + * for objects without ID. + * It's unclear what the latter are needed for and their use is problematic + * since we lose control over the ref and the contained pointer. + */ + void ScriptApiBase::addObjectReference(ServerActiveObject *cobj) { SCRIPTAPI_PRECHECKHEADER diff --git a/src/script/cpp_api/s_item.cpp b/src/script/cpp_api/s_item.cpp index cbdfcf1b1..24955cefc 100644 --- a/src/script/cpp_api/s_item.cpp +++ b/src/script/cpp_api/s_item.cpp @@ -115,7 +115,8 @@ bool ScriptApiItem::item_OnUse(ItemStack &item, return true; } -bool ScriptApiItem::item_OnSecondaryUse(ItemStack &item, ServerActiveObject *user) +bool ScriptApiItem::item_OnSecondaryUse(ItemStack &item, + ServerActiveObject *user, const PointedThing &pointed) { SCRIPTAPI_PRECHECKHEADER @@ -126,8 +127,6 @@ bool ScriptApiItem::item_OnSecondaryUse(ItemStack &item, ServerActiveObject *use LuaItemStack::create(L, item); objectrefGetOrCreate(L, user); - PointedThing pointed; - pointed.type = POINTEDTHING_NOTHING; pushPointedThing(pointed); PCALL_RES(lua_pcall(L, 3, 1, error_handler)); if (!lua_isnil(L, -1)) { diff --git a/src/script/cpp_api/s_item.h b/src/script/cpp_api/s_item.h index 6c7f286a9..25a3501f9 100644 --- a/src/script/cpp_api/s_item.h +++ b/src/script/cpp_api/s_item.h @@ -42,7 +42,7 @@ public: bool item_OnUse(ItemStack &item, ServerActiveObject *user, const PointedThing &pointed); bool item_OnSecondaryUse(ItemStack &item, - ServerActiveObject *user); + ServerActiveObject *user, const PointedThing &pointed); bool item_OnCraft(ItemStack &item, ServerActiveObject *user, const InventoryList *old_craft_grid, const InventoryLocation &craft_inv); bool item_CraftPredict(ItemStack &item, ServerActiveObject *user, @@ -51,7 +51,6 @@ public: protected: friend class LuaItemStack; friend class ModApiItemMod; - friend class LuaRaycast; bool getItemCallback(const char *name, const char *callbackname, const v3s16 *p = nullptr); /*! diff --git a/src/script/cpp_api/s_security.cpp b/src/script/cpp_api/s_security.cpp index b90b3aa2c..b5abcfb5d 100644 --- a/src/script/cpp_api/s_security.cpp +++ b/src/script/cpp_api/s_security.cpp @@ -372,14 +372,16 @@ bool ScriptApiSecurity::isSecure(lua_State *L) return secure; } - -#define CHECK_FILE_ERR(ret, fp) \ - if (ret) { \ - lua_pushfstring(L, "%s: %s", path, strerror(errno)); \ - if (fp) std::fclose(fp); \ - return false; \ +bool ScriptApiSecurity::safeLoadString(lua_State *L, const std::string &code, const char *chunk_name) +{ + if (code.size() > 0 && code[0] == LUA_SIGNATURE[0]) { + lua_pushliteral(L, "Bytecode prohibited when mod security is enabled."); + return false; } - + if (luaL_loadbuffer(L, code.data(), code.size(), chunk_name)) + return false; + return true; +} bool ScriptApiSecurity::safeLoadFile(lua_State *L, const char *path, const char *display_name) { @@ -406,68 +408,49 @@ bool ScriptApiSecurity::safeLoadFile(lua_State *L, const char *path, const char int c = std::getc(fp); if (c == '#') { // Skip the first line - while ((c = std::getc(fp)) != EOF && c != '\n'); - if (c == '\n') c = std::getc(fp); + while ((c = std::getc(fp)) != EOF && c != '\n') {} + if (c == '\n') + std::getc(fp); start = std::ftell(fp); } - if (c == LUA_SIGNATURE[0]) { - lua_pushliteral(L, "Bytecode prohibited when mod security is enabled."); - std::fclose(fp); - if (path) { - delete [] chunk_name; - } - return false; - } - // Read the file int ret = std::fseek(fp, 0, SEEK_END); if (ret) { lua_pushfstring(L, "%s: %s", path, strerror(errno)); - std::fclose(fp); if (path) { + std::fclose(fp); delete [] chunk_name; } return false; } size_t size = std::ftell(fp) - start; - char *code = new char[size]; + std::string code(size, '\0'); ret = std::fseek(fp, start, SEEK_SET); if (ret) { lua_pushfstring(L, "%s: %s", path, strerror(errno)); - std::fclose(fp); - delete [] code; if (path) { + std::fclose(fp); delete [] chunk_name; } return false; } - size_t num_read = std::fread(code, 1, size, fp); - if (path) { + size_t num_read = std::fread(&code[0], 1, size, fp); + if (path) std::fclose(fp); - } if (num_read != size) { lua_pushliteral(L, "Error reading file to load."); - delete [] code; - if (path) { + if (path) delete [] chunk_name; - } return false; } - if (luaL_loadbuffer(L, code, size, chunk_name)) { - delete [] code; - return false; - } - - delete [] code; - - if (path) { + bool result = safeLoadString(L, code, chunk_name); + if (path) delete [] chunk_name; - } - return true; + return result; } @@ -628,14 +611,9 @@ int ScriptApiSecurity::sl_g_load(lua_State *L) code += std::string(buf, len); lua_pop(L, 1); // Pop return value } - if (code[0] == LUA_SIGNATURE[0]) { + if (!safeLoadString(L, code, chunk_name)) { lua_pushnil(L); - lua_pushliteral(L, "Bytecode prohibited when mod security is enabled."); - return 2; - } - if (luaL_loadbuffer(L, code.data(), code.size(), chunk_name)) { - lua_pushnil(L); - lua_insert(L, lua_gettop(L) - 1); + lua_insert(L, -2); return 2; } return 1; @@ -649,16 +627,19 @@ int ScriptApiSecurity::sl_g_loadfile(lua_State *L) ScriptApiBase *script = (ScriptApiBase *) lua_touserdata(L, -1); lua_pop(L, 1); + // Client implementation if (script->getType() == ScriptingType::Client) { - std::string display_path = readParam<std::string>(L, 1); - const std::string *path = script->getClient()->getModFile(display_path); - if (!path) { - std::string error_msg = "Coudln't find script called:" + display_path; + std::string path = readParam<std::string>(L, 1); + const std::string *contents = script->getClient()->getModFile(path); + if (!contents) { + std::string error_msg = "Coudln't find script called: " + path; lua_pushnil(L); lua_pushstring(L, error_msg.c_str()); return 2; } - if (!safeLoadFile(L, path->c_str(), display_path.c_str())) { + + std::string chunk_name = "@" + path; + if (!safeLoadString(L, *contents, chunk_name.c_str())) { lua_pushnil(L); lua_insert(L, -2); return 2; @@ -666,6 +647,8 @@ int ScriptApiSecurity::sl_g_loadfile(lua_State *L) return 1; } #endif + + // Server implementation const char *path = NULL; if (lua_isstring(L, 1)) { path = lua_tostring(L, 1); @@ -694,15 +677,11 @@ int ScriptApiSecurity::sl_g_loadstring(lua_State *L) size_t size; const char *code = lua_tolstring(L, 1, &size); + std::string code_s(code, size); - if (size > 0 && code[0] == LUA_SIGNATURE[0]) { + if (!safeLoadString(L, code_s, chunk_name)) { lua_pushnil(L); - lua_pushliteral(L, "Bytecode prohibited when mod security is enabled."); - return 2; - } - if (luaL_loadbuffer(L, code, size, chunk_name)) { - lua_pushnil(L); - lua_insert(L, lua_gettop(L) - 1); + lua_insert(L, -2); return 2; } return 1; diff --git a/src/script/cpp_api/s_security.h b/src/script/cpp_api/s_security.h index c31aff26b..73e763548 100644 --- a/src/script/cpp_api/s_security.h +++ b/src/script/cpp_api/s_security.h @@ -50,6 +50,8 @@ public: void initializeSecurityClient(); // Checks if the Lua state has been secured static bool isSecure(lua_State *L); + // Loads a string as Lua code safely (doesn't allow bytecode). + static bool safeLoadString(lua_State *L, const std::string &code, const char *chunk_name); // Loads a file as Lua code safely (doesn't allow bytecode). static bool safeLoadFile(lua_State *L, const char *path, const char *display_name = NULL); // Checks if mods are allowed to read (and optionally write) to the path diff --git a/src/script/lua_api/l_camera.cpp b/src/script/lua_api/l_camera.cpp index 80071b3b8..9c1470284 100644 --- a/src/script/lua_api/l_camera.cpp +++ b/src/script/lua_api/l_camera.cpp @@ -108,11 +108,10 @@ int LuaCamera::l_get_pos(lua_State *L) int LuaCamera::l_get_offset(lua_State *L) { - Camera *camera = getobject(L, 1); - if (!camera) - return 0; + LocalPlayer *player = getClient(L)->getEnv().getLocalPlayer(); + sanity_check(player); - push_v3s16(L, camera->getOffset()); + push_v3f(L, player->getEyeOffset() / BS); return 1; } diff --git a/src/script/lua_api/l_client.cpp b/src/script/lua_api/l_client.cpp index 6345fc75f..fba182492 100644 --- a/src/script/lua_api/l_client.cpp +++ b/src/script/lua_api/l_client.cpp @@ -36,12 +36,47 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "util/string.h" #include "nodedef.h" +#define checkCSMRestrictionFlag(flag) \ + ( getClient(L)->checkCSMRestrictionFlag(CSMRestrictionFlags::flag) ) + +// Not the same as FlagDesc, which contains an `u32 flag` +struct CSMFlagDesc { + const char *name; + u64 flag; +}; + +/* + FIXME: This should eventually be moved somewhere else + It also needs to be kept in sync with the definition of CSMRestrictionFlags + in network/networkprotocol.h +*/ +const static CSMFlagDesc flagdesc_csm_restriction[] = { + {"load_client_mods", CSM_RF_LOAD_CLIENT_MODS}, + {"chat_messages", CSM_RF_CHAT_MESSAGES}, + {"read_itemdefs", CSM_RF_READ_ITEMDEFS}, + {"read_nodedefs", CSM_RF_READ_NODEDEFS}, + {"lookup_nodes", CSM_RF_LOOKUP_NODES}, + {"read_playerinfo", CSM_RF_READ_PLAYERINFO}, + {NULL, 0} +}; + +// get_current_modname() int ModApiClient::l_get_current_modname(lua_State *L) { lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME); return 1; } +// get_modpath(modname) +int ModApiClient::l_get_modpath(lua_State *L) +{ + std::string modname = readParam<std::string>(L, 1); + // Client mods use a virtual filesystem, see Client::scanModSubfolder() + std::string path = modname + ":"; + lua_pushstring(L, path.c_str()); + return 1; +} + // get_last_run_mod() int ModApiClient::l_get_last_run_mod(lua_State *L) { @@ -95,11 +130,8 @@ int ModApiClient::l_send_chat_message(lua_State *L) // If server disabled this API, discard - // clang-format off - if (getClient(L)->checkCSMRestrictionFlag( - CSMRestrictionFlags::CSM_RF_CHAT_MESSAGES)) + if (checkCSMRestrictionFlag(CSM_RF_CHAT_MESSAGES)) return 0; - // clang-format on std::string message = luaL_checkstring(L, 1); getClient(L)->sendChatMessage(utf8_to_wide(message)); @@ -116,12 +148,8 @@ int ModApiClient::l_clear_out_chat_queue(lua_State *L) // get_player_names() int ModApiClient::l_get_player_names(lua_State *L) { - // clang-format off - if (getClient(L)->checkCSMRestrictionFlag( - CSMRestrictionFlags::CSM_RF_READ_PLAYERINFO)) { + if (checkCSMRestrictionFlag(CSM_RF_READ_PLAYERINFO)) return 0; - } - // clang-format on const std::list<std::string> &plist = getClient(L)->getConnectedPlayerNames(); lua_createtable(L, plist.size(), 0); @@ -190,7 +218,7 @@ int ModApiClient::l_get_node_or_nil(lua_State *L) // Do it bool pos_ok; - MapNode n = getClient(L)->getNode(pos, &pos_ok); + MapNode n = getClient(L)->CSMGetNode(pos, &pos_ok); if (pos_ok) { // Return node pushnode(L, n, getClient(L)->ndef()); @@ -202,9 +230,18 @@ int ModApiClient::l_get_node_or_nil(lua_State *L) int ModApiClient::l_get_language(lua_State *L) { - char *locale = setlocale(LC_ALL, ""); +#ifdef _WIN32 + char *locale = setlocale(LC_ALL, NULL); +#else + char *locale = setlocale(LC_MESSAGES, NULL); +#endif + std::string lang = gettext("LANG_CODE"); + if (lang == "LANG_CODE") + lang = ""; + lua_pushstring(L, locale); - return 1; + lua_pushstring(L, lang.c_str()); + return 2; } int ModApiClient::l_get_wielded_item(lua_State *L) @@ -297,11 +334,8 @@ int ModApiClient::l_get_item_def(lua_State *L) IItemDefManager *idef = gdef->idef(); assert(idef); - // clang-format off - if (getClient(L)->checkCSMRestrictionFlag( - CSMRestrictionFlags::CSM_RF_READ_ITEMDEFS)) + if (checkCSMRestrictionFlag(CSM_RF_READ_ITEMDEFS)) return 0; - // clang-format on if (!lua_isstring(L, 1)) return 0; @@ -328,11 +362,8 @@ int ModApiClient::l_get_node_def(lua_State *L) if (!lua_isstring(L, 1)) return 0; - // clang-format off - if (getClient(L)->checkCSMRestrictionFlag( - CSMRestrictionFlags::CSM_RF_READ_NODEDEFS)) + if (checkCSMRestrictionFlag(CSM_RF_READ_NODEDEFS)) return 0; - // clang-format on std::string name = readParam<std::string>(L, 1); const ContentFeatures &cf = ndef->get(ndef->getId(name)); @@ -362,9 +393,23 @@ int ModApiClient::l_get_builtin_path(lua_State *L) return 1; } +// get_csm_restrictions() +int ModApiClient::l_get_csm_restrictions(lua_State *L) +{ + u64 flags = getClient(L)->getCSMRestrictionFlags(); + const CSMFlagDesc *flagdesc = flagdesc_csm_restriction; + + lua_newtable(L); + for (int i = 0; flagdesc[i].name; i++) { + setboolfield(L, -1, flagdesc[i].name, !!(flags & flagdesc[i].flag)); + } + return 1; +} + void ModApiClient::Initialize(lua_State *L, int top) { API_FCT(get_current_modname); + API_FCT(get_modpath); API_FCT(print); API_FCT(display_chat_message); API_FCT(send_chat_message); @@ -387,4 +432,5 @@ void ModApiClient::Initialize(lua_State *L, int top) API_FCT(get_privilege_list); API_FCT(get_builtin_path); API_FCT(get_language); + API_FCT(get_csm_restrictions); } diff --git a/src/script/lua_api/l_client.h b/src/script/lua_api/l_client.h index 0d3e6b106..6d1f70b1d 100644 --- a/src/script/lua_api/l_client.h +++ b/src/script/lua_api/l_client.h @@ -30,6 +30,9 @@ private: // get_current_modname() static int l_get_current_modname(lua_State *L); + // get_modpath(modname) + static int l_get_modpath(lua_State *L); + // print(text) static int l_print(lua_State *L); @@ -93,6 +96,9 @@ private: // get_builtin_path() static int l_get_builtin_path(lua_State *L); + // get_csm_restrictions() + static int l_get_csm_restrictions(lua_State *L); + public: static void Initialize(lua_State *L, int top); }; diff --git a/src/script/lua_api/l_env.cpp b/src/script/lua_api/l_env.cpp index a56b1cb0b..3169fa4cf 100644 --- a/src/script/lua_api/l_env.cpp +++ b/src/script/lua_api/l_env.cpp @@ -140,17 +140,20 @@ void LuaLBM::trigger(ServerEnvironment *env, v3s16 p, MapNode n) int LuaRaycast::l_next(lua_State *L) { MAP_LOCK_REQUIRED; - - ScriptApiItem *script = getScriptApi<ScriptApiItem>(L); GET_ENV_PTR; + bool csm = false; +#ifndef SERVER + csm = getClient(L) != nullptr; +#endif + LuaRaycast *o = checkobject(L, 1); PointedThing pointed; env->continueRaycast(&o->state, &pointed); if (pointed.type == POINTEDTHING_NOTHING) lua_pushnil(L); else - script->pushPointedThing(pointed, true); + push_pointed_thing(L, pointed, csm, true); return 1; } @@ -637,6 +640,31 @@ int ModApiEnvMod::l_add_item(lua_State *L) return 1; } +// get_connected_players() +int ModApiEnvMod::l_get_connected_players(lua_State *L) +{ + ServerEnvironment *env = (ServerEnvironment *) getEnv(L); + if (!env) { + log_deprecated(L, "Calling get_connected_players() at mod load time" + " is deprecated"); + lua_createtable(L, 0, 0); + return 1; + } + + lua_createtable(L, env->getPlayerCount(), 0); + u32 i = 0; + for (RemotePlayer *player : env->getPlayers()) { + if (player->getPeerId() == PEER_ID_INEXISTENT) + continue; + PlayerSAO *sao = player->getPlayerSAO(); + if (sao && !sao->isGone()) { + getScriptApiBase(L)->objectrefGetOrCreate(L, sao); + lua_rawseti(L, -2, ++i); + } + } + return 1; +} + // get_player_by_name(name) int ModApiEnvMod::l_get_player_by_name(lua_State *L) { @@ -644,16 +672,12 @@ int ModApiEnvMod::l_get_player_by_name(lua_State *L) // Do it const char *name = luaL_checkstring(L, 1); - RemotePlayer *player = dynamic_cast<RemotePlayer *>(env->getPlayer(name)); - if (player == NULL){ - lua_pushnil(L); - return 1; - } + RemotePlayer *player = env->getPlayer(name); + if (!player || player->getPeerId() == PEER_ID_INEXISTENT) + return 0; PlayerSAO *sao = player->getPlayerSAO(); - if(sao == NULL){ - lua_pushnil(L); - return 1; - } + if (!sao || sao->isGone()) + return 0; // Put player on stack getScriptApiBase(L)->objectrefGetOrCreate(L, sao); return 1; @@ -769,11 +793,8 @@ int ModApiEnvMod::l_find_node_near(lua_State *L) #ifndef SERVER // Client API limitations - if (getClient(L) && - getClient(L)->checkCSMRestrictionFlag( - CSMRestrictionFlags::CSM_RF_LOOKUP_NODES)) { - radius = std::max<int>(radius, getClient(L)->getCSMNodeRangeLimit()); - } + if (getClient(L)) + radius = getClient(L)->CSMClampRadius(pos, radius); #endif for (int d = start_radius; d <= radius; d++) { @@ -796,11 +817,20 @@ int ModApiEnvMod::l_find_nodes_in_area(lua_State *L) { GET_ENV_PTR; - const NodeDefManager *ndef = getServer(L)->ndef(); v3s16 minp = read_v3s16(L, 1); v3s16 maxp = read_v3s16(L, 2); sortBoxVerticies(minp, maxp); +#ifndef SERVER + const NodeDefManager *ndef = getClient(L) ? getClient(L)->ndef() : getServer(L)->ndef(); + if (getClient(L)) { + minp = getClient(L)->CSMClampPos(minp); + maxp = getClient(L)->CSMClampPos(maxp); + } +#else + const NodeDefManager *ndef = getServer(L)->ndef(); +#endif + v3s16 cube = maxp - minp + 1; // Volume limit equal to 8 default mapchunks, (80 * 2) ^ 3 = 4,096,000 if ((u64)cube.X * (u64)cube.Y * (u64)cube.Z > 4096000) { @@ -864,11 +894,20 @@ int ModApiEnvMod::l_find_nodes_in_area_under_air(lua_State *L) GET_ENV_PTR; - const NodeDefManager *ndef = getServer(L)->ndef(); v3s16 minp = read_v3s16(L, 1); v3s16 maxp = read_v3s16(L, 2); sortBoxVerticies(minp, maxp); +#ifndef SERVER + const NodeDefManager *ndef = getClient(L) ? getClient(L)->ndef() : getServer(L)->ndef(); + if (getClient(L)) { + minp = getClient(L)->CSMClampPos(minp); + maxp = getClient(L)->CSMClampPos(maxp); + } +#else + const NodeDefManager *ndef = getServer(L)->ndef(); +#endif + v3s16 cube = maxp - minp + 1; // Volume limit equal to 8 default mapchunks, (80 * 2) ^ 3 = 4,096,000 if ((u64)cube.X * (u64)cube.Y * (u64)cube.Z > 4096000) { @@ -1161,7 +1200,7 @@ int ModApiEnvMod::l_find_path(lua_State *L) unsigned int max_jump = luaL_checkint(L, 4); unsigned int max_drop = luaL_checkint(L, 5); PathAlgorithm algo = PA_PLAIN_NP; - if (!lua_isnil(L, 6)) { + if (!lua_isnoneornil(L, 6)) { std::string algorithm = luaL_checkstring(L,6); if (algorithm == "A*") @@ -1301,6 +1340,7 @@ void ModApiEnvMod::Initialize(lua_State *L, int top) API_FCT(find_nodes_with_meta); API_FCT(get_meta); API_FCT(get_node_timer); + API_FCT(get_connected_players); API_FCT(get_player_by_name); API_FCT(get_objects_inside_radius); API_FCT(set_timeofday); @@ -1329,9 +1369,14 @@ void ModApiEnvMod::Initialize(lua_State *L, int top) void ModApiEnvMod::InitializeClient(lua_State *L, int top) { + API_FCT(get_node_light); API_FCT(get_timeofday); - API_FCT(get_day_count); API_FCT(get_node_max_level); API_FCT(get_node_level); + API_FCT(find_nodes_with_meta); API_FCT(find_node_near); + API_FCT(find_nodes_in_area); + API_FCT(find_nodes_in_area_under_air); + API_FCT(line_of_sight); + API_FCT(raycast); } diff --git a/src/script/lua_api/l_env.h b/src/script/lua_api/l_env.h index 68a4eae50..ac2f8b588 100644 --- a/src/script/lua_api/l_env.h +++ b/src/script/lua_api/l_env.h @@ -101,6 +101,9 @@ private: // pos = {x=num, y=num, z=num} static int l_add_item(lua_State *L); + // get_connected_players() + static int l_get_connected_players(lua_State *L); + // get_player_by_name(name) static int l_get_player_by_name(lua_State *L); diff --git a/src/script/lua_api/l_item.cpp b/src/script/lua_api/l_item.cpp index f9708b560..0c174feca 100644 --- a/src/script/lua_api/l_item.cpp +++ b/src/script/lua_api/l_item.cpp @@ -414,7 +414,9 @@ ItemStack& LuaItemStack::getItem() int LuaItemStack::create_object(lua_State *L) { NO_MAP_LOCK_REQUIRED; - ItemStack item = read_item(L, 1, getGameDef(L)->idef()); + ItemStack item; + if (!lua_isnone(L, 1)) + item = read_item(L, 1, getGameDef(L)->idef()); LuaItemStack *o = new LuaItemStack(item); *(void **)(lua_newuserdata(L, sizeof(void *))) = o; luaL_getmetatable(L, className); @@ -610,9 +612,11 @@ int ModApiItemMod::l_get_content_id(lua_State *L) std::string name = luaL_checkstring(L, 1); const NodeDefManager *ndef = getGameDef(L)->getNodeDefManager(); - content_t c = ndef->getId(name); + content_t content_id; + if (!ndef->getId(name, content_id)) + throw LuaError("Unknown node: " + name); - lua_pushinteger(L, c); + lua_pushinteger(L, content_id); return 1; /* number of results */ } diff --git a/src/script/lua_api/l_localplayer.cpp b/src/script/lua_api/l_localplayer.cpp index 3e14e48e4..821b1cb66 100644 --- a/src/script/lua_api/l_localplayer.cpp +++ b/src/script/lua_api/l_localplayer.cpp @@ -78,7 +78,7 @@ int LuaLocalPlayer::l_is_attached(lua_State *L) { LocalPlayer *player = getobject(L, 1); - lua_pushboolean(L, player->isAttached); + lua_pushboolean(L, player->getParent() != nullptr); return 1; } @@ -157,7 +157,7 @@ int LuaLocalPlayer::l_get_override_pos(lua_State *L) { LocalPlayer *player = getobject(L, 1); - push_v3f(L, player->overridePosition); + push_v3f(L, player->getPosition()); return 1; } diff --git a/src/script/lua_api/l_mapgen.cpp b/src/script/lua_api/l_mapgen.cpp index 2e0cba8dd..cb0d6ac95 100644 --- a/src/script/lua_api/l_mapgen.cpp +++ b/src/script/lua_api/l_mapgen.cpp @@ -879,7 +879,7 @@ int ModApiMapgen::l_set_mapgen_params(lua_State *L) settingsmgr->setMapSetting("chunksize", readParam<std::string>(L, -1), true); warn_if_field_exists(L, 1, "flagmask", - "Deprecated: flags field now includes unset flags."); + "Obsolete: flags field now includes unset flags."); lua_getfield(L, 1, "flags"); if (lua_isstring(L, -1)) diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp index efdb345c9..23ed1ffe0 100644 --- a/src/script/lua_api/l_object.cpp +++ b/src/script/lua_api/l_object.cpp @@ -60,6 +60,8 @@ LuaEntitySAO* ObjectRef::getluaobject(ObjectRef *ref) return NULL; if (obj->getType() != ACTIVEOBJECT_TYPE_LUAENTITY) return NULL; + if (obj->isGone()) + return NULL; return (LuaEntitySAO*)obj; } @@ -70,6 +72,8 @@ PlayerSAO* ObjectRef::getplayersao(ObjectRef *ref) return NULL; if (obj->getType() != ACTIVEOBJECT_TYPE_PLAYER) return NULL; + if (obj->isGone()) + return NULL; return (PlayerSAO*)obj; } @@ -1059,6 +1063,9 @@ int ObjectRef::l_get_luaentity(lua_State *L) int ObjectRef::l_is_player_connected(lua_State *L) { NO_MAP_LOCK_REQUIRED; + // This method was once added for a bugfix, but never documented + log_deprecated(L, "is_player_connected is undocumented and " + "will be removed in a future release"); ObjectRef *ref = checkobject(L, 1); RemotePlayer *player = getplayer(ref); lua_pushboolean(L, (player != NULL && player->getPeerId() != PEER_ID_INEXISTENT)); @@ -1701,42 +1708,157 @@ int ObjectRef::l_hud_get_hotbar_selected_image(lua_State *L) return 1; } -// set_sky(self, bgcolor, type, list, clouds = true) +// set_sky(self, {base_color=, type=, textures=, clouds=, sky_colors={}}) int ObjectRef::l_set_sky(lua_State *L) { NO_MAP_LOCK_REQUIRED; ObjectRef *ref = checkobject(L, 1); RemotePlayer *player = getplayer(ref); - if (player == NULL) + if (!player) return 0; - video::SColor bgcolor(255,255,255,255); - read_color(L, 2, &bgcolor); + bool is_colorspec = is_color_table(L, 2); - std::string type = luaL_checkstring(L, 3); + SkyboxParams skybox_params = player->getSkyParams(); + if (lua_istable(L, 2) && !is_colorspec) { + lua_getfield(L, 2, "base_color"); + if (!lua_isnil(L, -1)) + read_color(L, -1, &skybox_params.bgcolor); + lua_pop(L, 1); - std::vector<std::string> params; - if (lua_istable(L, 4)) { - lua_pushnil(L); - while (lua_next(L, 4) != 0) { - // key at index -2 and value at index -1 - if (lua_isstring(L, -1)) - params.emplace_back(readParam<std::string>(L, -1)); - else - params.emplace_back(""); - // removes value, keeps key for next iteration + lua_getfield(L, 2, "type"); + if (!lua_isnil(L, -1)) + skybox_params.type = luaL_checkstring(L, -1); + lua_pop(L, 1); + + lua_getfield(L, 2, "textures"); + skybox_params.textures.clear(); + if (lua_istable(L, -1) && skybox_params.type == "skybox") { + lua_pushnil(L); + while (lua_next(L, -2) != 0) { + // Key is at index -2 and value at index -1 + skybox_params.textures.emplace_back(readParam<std::string>(L, -1)); + // Removes the value, but keeps the key for iteration + lua_pop(L, 1); + } + } + lua_pop(L, 1); + + /* + We want to avoid crashes, so we're checking even if we're not using them. + However, we want to ensure that the skybox can be set to nil when + using "regular" or "plain" skybox modes as textures aren't needed. + */ + + if (skybox_params.textures.size() != 6 && skybox_params.textures.size() > 0) + throw LuaError("Skybox expects 6 textures!"); + + skybox_params.clouds = getboolfield_default(L, 2, + "clouds", skybox_params.clouds); + + lua_getfield(L, 2, "sky_color"); + if (lua_istable(L, -1)) { + lua_getfield(L, -1, "day_sky"); + read_color(L, -1, &skybox_params.sky_color.day_sky); + lua_pop(L, 1); + + lua_getfield(L, -1, "day_horizon"); + read_color(L, -1, &skybox_params.sky_color.day_horizon); + lua_pop(L, 1); + + lua_getfield(L, -1, "dawn_sky"); + read_color(L, -1, &skybox_params.sky_color.dawn_sky); + lua_pop(L, 1); + + lua_getfield(L, -1, "dawn_horizon"); + read_color(L, -1, &skybox_params.sky_color.dawn_horizon); + lua_pop(L, 1); + + lua_getfield(L, -1, "night_sky"); + read_color(L, -1, &skybox_params.sky_color.night_sky); + lua_pop(L, 1); + + lua_getfield(L, -1, "night_horizon"); + read_color(L, -1, &skybox_params.sky_color.night_horizon); + lua_pop(L, 1); + + lua_getfield(L, -1, "indoors"); + read_color(L, -1, &skybox_params.sky_color.indoors); + lua_pop(L, 1); + + // Prevent flickering clouds at dawn/dusk: + skybox_params.sun_tint = video::SColor(255, 255, 255, 255); + lua_getfield(L, -1, "fog_sun_tint"); + read_color(L, -1, &skybox_params.sun_tint); + lua_pop(L, 1); + + skybox_params.moon_tint = video::SColor(255, 255, 255, 255); + lua_getfield(L, -1, "fog_moon_tint"); + read_color(L, -1, &skybox_params.moon_tint); + lua_pop(L, 1); + + lua_getfield(L, -1, "fog_tint_type"); + if (!lua_isnil(L, -1)) + skybox_params.tint_type = luaL_checkstring(L, -1); + lua_pop(L, 1); + + // Because we need to leave the "sky_color" table. lua_pop(L, 1); } - } + } else { + // Handle old set_sky calls, and log deprecated: + log_deprecated(L, "Deprecated call to set_sky, please check lua_api.txt"); + + // Fix sun, moon and stars showing when classic textured skyboxes are used + SunParams sun_params = player->getSunParams(); + MoonParams moon_params = player->getMoonParams(); + StarParams star_params = player->getStarParams(); + + // Prevent erroneous background colors + skybox_params.bgcolor = video::SColor(255, 255, 255, 255); + read_color(L, 2, &skybox_params.bgcolor); + + skybox_params.type = luaL_checkstring(L, 3); + + // Preserve old behaviour of the sun, moon and stars + // when using the old set_sky call. + if (skybox_params.type == "regular") { + sun_params.visible = true; + sun_params.sunrise_visible = true; + moon_params.visible = true; + star_params.visible = true; + } else { + sun_params.visible = false; + sun_params.sunrise_visible = false; + moon_params.visible = false; + star_params.visible = false; + } - if (type == "skybox" && params.size() != 6) - throw LuaError("skybox expects 6 textures"); + skybox_params.textures.clear(); + if (lua_istable(L, 4)) { + lua_pushnil(L); + while (lua_next(L, 4) != 0) { + // Key at index -2, and value at index -1 + if (lua_isstring(L, -1)) + skybox_params.textures.emplace_back(readParam<std::string>(L, -1)); + else + skybox_params.textures.emplace_back(""); + // Remove the value, keep the key for the next iteration + lua_pop(L, 1); + } + } + if (skybox_params.type == "skybox" && skybox_params.textures.size() != 6) + throw LuaError("Skybox expects 6 textures."); - bool clouds = true; - if (lua_isboolean(L, 5)) - clouds = readParam<bool>(L, 5); + skybox_params.clouds = true; + if (lua_isboolean(L, 5)) + skybox_params.clouds = readParam<bool>(L, 5); - getServer(L)->setSky(player, bgcolor, type, params, clouds); + getServer(L)->setSun(player, sun_params); + getServer(L)->setMoon(player, moon_params); + getServer(L)->setStars(player, star_params); + } + getServer(L)->setSky(player, skybox_params); lua_pushboolean(L, true); return 1; } @@ -1747,28 +1869,226 @@ int ObjectRef::l_get_sky(lua_State *L) NO_MAP_LOCK_REQUIRED; ObjectRef *ref = checkobject(L, 1); RemotePlayer *player = getplayer(ref); - if (player == NULL) + + if (!player) return 0; - video::SColor bgcolor(255, 255, 255, 255); - std::string type; - std::vector<std::string> params; - bool clouds; + SkyboxParams skybox_params; + skybox_params = player->getSkyParams(); - player->getSky(&bgcolor, &type, ¶ms, &clouds); - type = type.empty() ? "regular" : type; + push_ARGB8(L, skybox_params.bgcolor); + lua_pushlstring(L, skybox_params.type.c_str(), skybox_params.type.size()); - push_ARGB8(L, bgcolor); - lua_pushlstring(L, type.c_str(), type.size()); lua_newtable(L); s16 i = 1; - for (const std::string ¶m : params) { - lua_pushlstring(L, param.c_str(), param.size()); + for (const std::string& texture : skybox_params.textures) { + lua_pushlstring(L, texture.c_str(), texture.size()); lua_rawseti(L, -2, i++); } - lua_pushboolean(L, clouds); + lua_pushboolean(L, skybox_params.clouds); return 4; } +// get_sky_color(self) +int ObjectRef::l_get_sky_color(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + RemotePlayer *player = getplayer(ref); + + if (!player) + return 0; + + const SkyboxParams& skybox_params = player->getSkyParams(); + + lua_newtable(L); + if (skybox_params.type == "regular") { + push_ARGB8(L, skybox_params.sky_color.day_sky); + lua_setfield(L, -2, "day_sky"); + push_ARGB8(L, skybox_params.sky_color.day_horizon); + lua_setfield(L, -2, "day_horizon"); + push_ARGB8(L, skybox_params.sky_color.dawn_sky); + lua_setfield(L, -2, "dawn_sky"); + push_ARGB8(L, skybox_params.sky_color.dawn_horizon); + lua_setfield(L, -2, "dawn_horizon"); + push_ARGB8(L, skybox_params.sky_color.night_sky); + lua_setfield(L, -2, "night_sky"); + push_ARGB8(L, skybox_params.sky_color.night_horizon); + lua_setfield(L, -2, "night_horizon"); + push_ARGB8(L, skybox_params.sky_color.indoors); + lua_setfield(L, -2, "indoors"); + } + push_ARGB8(L, skybox_params.sun_tint); + lua_setfield(L, -2, "sun_tint"); + push_ARGB8(L, skybox_params.moon_tint); + lua_setfield(L, -2, "moon_tint"); + lua_pushstring(L, skybox_params.tint_type.c_str()); + lua_setfield(L, -2, "tint_type"); + return 1; +} + +// set_sun(self, {visible, texture=, tonemap=, sunrise=, rotation=, scale=}) +int ObjectRef::l_set_sun(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + RemotePlayer *player = getplayer(ref); + if (!player) + return 0; + + if (!lua_istable(L, 2)) + return 0; + + SunParams sun_params = player->getSunParams(); + + sun_params.visible = getboolfield_default(L, 2, + "visible", sun_params.visible); + sun_params.texture = getstringfield_default(L, 2, + "texture", sun_params.texture); + sun_params.tonemap = getstringfield_default(L, 2, + "tonemap", sun_params.tonemap); + sun_params.sunrise = getstringfield_default(L, 2, + "sunrise", sun_params.sunrise); + sun_params.sunrise_visible = getboolfield_default(L, 2, + "sunrise_visible", sun_params.sunrise_visible); + sun_params.scale = getfloatfield_default(L, 2, + "scale", sun_params.scale); + + getServer(L)->setSun(player, sun_params); + lua_pushboolean(L, true); + return 1; +} + +//get_sun(self) +int ObjectRef::l_get_sun(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + RemotePlayer *player = getplayer(ref); + if (!player) + return 0; + const SunParams &sun_params = player->getSunParams(); + + lua_newtable(L); + lua_pushboolean(L, sun_params.visible); + lua_setfield(L, -2, "visible"); + lua_pushstring(L, sun_params.texture.c_str()); + lua_setfield(L, -2, "texture"); + lua_pushstring(L, sun_params.tonemap.c_str()); + lua_setfield(L, -2, "tonemap"); + lua_pushstring(L, sun_params.sunrise.c_str()); + lua_setfield(L, -2, "sunrise"); + lua_pushboolean(L, sun_params.sunrise_visible); + lua_setfield(L, -2, "sunrise_visible"); + lua_pushnumber(L, sun_params.scale); + lua_setfield(L, -2, "scale"); + + return 1; +} + +// set_moon(self, {visible, texture=, tonemap=, sunrise=, rotation=, scale=}) +int ObjectRef::l_set_moon(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + RemotePlayer *player = getplayer(ref); + if (!player) + return 0; + if (!lua_istable(L, 2)) + return 0; + + MoonParams moon_params = player->getMoonParams(); + + moon_params.visible = getboolfield_default(L, 2, + "visible", moon_params.visible); + moon_params.texture = getstringfield_default(L, 2, + "texture", moon_params.texture); + moon_params.tonemap = getstringfield_default(L, 2, + "tonemap", moon_params.tonemap); + moon_params.scale = getfloatfield_default(L, 2, + "scale", moon_params.scale); + + getServer(L)->setMoon(player, moon_params); + lua_pushboolean(L, true); + return 1; +} + +// get_moon(self) +int ObjectRef::l_get_moon(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + RemotePlayer *player = getplayer(ref); + if (!player) + return 0; + const MoonParams &moon_params = player->getMoonParams(); + + lua_newtable(L); + lua_pushboolean(L, moon_params.visible); + lua_setfield(L, -2, "visible"); + lua_pushstring(L, moon_params.texture.c_str()); + lua_setfield(L, -2, "texture"); + lua_pushstring(L, moon_params.tonemap.c_str()); + lua_setfield(L, -2, "tonemap"); + lua_pushnumber(L, moon_params.scale); + lua_setfield(L, -2, "scale"); + + return 1; +} + +// set_stars(self, {visible, count=, starcolor=, rotation=, scale=}) +int ObjectRef::l_set_stars(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + RemotePlayer *player = getplayer(ref); + if (!player) + return 0; + if (!lua_istable(L, 2)) + return 0; + + StarParams star_params = player->getStarParams(); + + star_params.visible = getboolfield_default(L, 2, + "visible", star_params.visible); + star_params.count = getintfield_default(L, 2, + "count", star_params.count); + + lua_getfield(L, 2, "star_color"); + if (!lua_isnil(L, -1)) + read_color(L, -1, &star_params.starcolor); + lua_pop(L, 1); + + star_params.scale = getfloatfield_default(L, 2, + "scale", star_params.scale); + + getServer(L)->setStars(player, star_params); + lua_pushboolean(L, true); + return 1; +} + +// get_stars(self) +int ObjectRef::l_get_stars(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + RemotePlayer *player = getplayer(ref); + if (!player) + return 0; + const StarParams &star_params = player->getStarParams(); + + lua_newtable(L); + lua_pushboolean(L, star_params.visible); + lua_setfield(L, -2, "visible"); + lua_pushnumber(L, star_params.count); + lua_setfield(L, -2, "count"); + push_ARGB8(L, star_params.starcolor); + lua_setfield(L, -2, "star_color"); + lua_pushnumber(L, star_params.scale); + lua_setfield(L, -2, "scale"); + + return 1; +} + // set_clouds(self, {density=, color=, ambient=, height=, thickness=, speed=}) int ObjectRef::l_set_clouds(lua_State *L) { @@ -2025,6 +2345,13 @@ luaL_Reg ObjectRef::methods[] = { luamethod(ObjectRef, hud_get_hotbar_selected_image), luamethod(ObjectRef, set_sky), luamethod(ObjectRef, get_sky), + luamethod(ObjectRef, get_sky_color), + luamethod(ObjectRef, set_sun), + luamethod(ObjectRef, get_sun), + luamethod(ObjectRef, set_moon), + luamethod(ObjectRef, get_moon), + luamethod(ObjectRef, set_stars), + luamethod(ObjectRef, get_stars), luamethod(ObjectRef, set_clouds), luamethod(ObjectRef, get_clouds), luamethod(ObjectRef, override_day_night_ratio), diff --git a/src/script/lua_api/l_object.h b/src/script/lua_api/l_object.h index e817e1d33..a75c59fd9 100644 --- a/src/script/lua_api/l_object.h +++ b/src/script/lua_api/l_object.h @@ -324,12 +324,33 @@ private: // hud_get_hotbar_selected_image(self) static int l_hud_get_hotbar_selected_image(lua_State *L); - // set_sky(self, bgcolor, type, list, clouds = true) + // set_sky({base_color=, type=, textures=, clouds=, sky_colors={}}) static int l_set_sky(lua_State *L); // get_sky(self) static int l_get_sky(lua_State *L); + // get_sky_color(self) + static int l_get_sky_color(lua_State* L); + + // set_sun(self, {visible, texture=, tonemap=, sunrise=, rotation=, scale=}) + static int l_set_sun(lua_State *L); + + // get_sun(self) + static int l_get_sun(lua_State *L); + + // set_moon(self, {visible, texture=, tonemap=, rotation, scale=}) + static int l_set_moon(lua_State *L); + + // get_moon(self) + static int l_get_moon(lua_State *L); + + // set_stars(self, {visible, count=, starcolor=, rotation, scale=}) + static int l_set_stars(lua_State *L); + + // get_stars(self) + static int l_get_stars(lua_State *L); + // set_clouds(self, {density=, color=, ambient=, height=, thickness=, speed=}) static int l_set_clouds(lua_State *L); diff --git a/src/script/lua_api/l_server.cpp b/src/script/lua_api/l_server.cpp index 7c083e652..00e849cdf 100644 --- a/src/script/lua_api/l_server.cpp +++ b/src/script/lua_api/l_server.cpp @@ -429,7 +429,7 @@ int ModApiServer::l_get_worldpath(lua_State *L) return 1; } -// sound_play(spec, parameters) +// sound_play(spec, parameters, [ephemeral]) int ModApiServer::l_sound_play(lua_State *L) { NO_MAP_LOCK_REQUIRED; @@ -437,8 +437,14 @@ int ModApiServer::l_sound_play(lua_State *L) read_soundspec(L, 1, spec); ServerSoundParams params; read_server_sound_params(L, 2, params); - s32 handle = getServer(L)->playSound(spec, params); - lua_pushinteger(L, handle); + bool ephemeral = lua_gettop(L) > 2 && readParam<bool>(L, 3); + if (ephemeral) { + getServer(L)->playSound(spec, params, true); + lua_pushnil(L); + } else { + s32 handle = getServer(L)->playSound(spec, params); + lua_pushinteger(L, handle); + } return 1; } @@ -446,7 +452,7 @@ int ModApiServer::l_sound_play(lua_State *L) int ModApiServer::l_sound_stop(lua_State *L) { NO_MAP_LOCK_REQUIRED; - int handle = luaL_checkinteger(L, 1); + s32 handle = luaL_checkinteger(L, 1); getServer(L)->stopSound(handle); return 0; } diff --git a/src/script/lua_api/l_settings.cpp b/src/script/lua_api/l_settings.cpp index cc2c73789..33eb02392 100644 --- a/src/script/lua_api/l_settings.cpp +++ b/src/script/lua_api/l_settings.cpp @@ -20,6 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "lua_api/l_settings.h" #include "lua_api/l_internal.h" #include "cpp_api/s_security.h" +#include "util/string.h" // FlagDesc #include "settings.h" #include "noise.h" #include "log.h" @@ -128,6 +129,29 @@ int LuaSettings::l_get_np_group(lua_State *L) return 1; } +int LuaSettings::l_get_flags(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + LuaSettings *o = checkobject(L, 1); + std::string key = std::string(luaL_checkstring(L, 2)); + + u32 flags = 0; + auto flagdesc = o->m_settings->getFlagDescFallback(key); + if (o->m_settings->getFlagStrNoEx(key, flags, flagdesc)) { + lua_newtable(L); + int table = lua_gettop(L); + for (size_t i = 0; flagdesc[i].name; ++i) { + lua_pushboolean(L, flags & flagdesc[i].flag); + lua_setfield(L, table, flagdesc[i].name); + } + lua_pushvalue(L, table); + } else { + lua_pushnil(L); + } + + return 1; +} + // set(self, key, value) int LuaSettings::l_set(lua_State* L) { @@ -305,6 +329,7 @@ const luaL_Reg LuaSettings::methods[] = { luamethod(LuaSettings, get), luamethod(LuaSettings, get_bool), luamethod(LuaSettings, get_np_group), + luamethod(LuaSettings, get_flags), luamethod(LuaSettings, set), luamethod(LuaSettings, set_bool), luamethod(LuaSettings, set_np_group), diff --git a/src/script/lua_api/l_settings.h b/src/script/lua_api/l_settings.h index dcf39a89e..67d7b342b 100644 --- a/src/script/lua_api/l_settings.h +++ b/src/script/lua_api/l_settings.h @@ -42,6 +42,9 @@ private: // get_np_group(self, key) -> noiseparam static int l_get_np_group(lua_State *L); + // get_flags(self, key) -> key/value table + static int l_get_flags(lua_State *L); + // set(self, key, value) static int l_set(lua_State *L); diff --git a/src/script/lua_api/l_util.cpp b/src/script/lua_api/l_util.cpp index a58c3a196..ae3e5df3d 100644 --- a/src/script/lua_api/l_util.cpp +++ b/src/script/lua_api/l_util.cpp @@ -59,7 +59,7 @@ int ModApiUtil::l_log(lua_State *L) std::string name = luaL_checkstring(L, 1); text = luaL_checkstring(L, 2); if (name == "deprecated") { - log_deprecated(L, text); + log_deprecated(L, text, 2); return 0; } level = Logger::stringToLevel(name); diff --git a/src/script/scripting_client.cpp b/src/script/scripting_client.cpp index c3e0ca373..1288b1df7 100644 --- a/src/script/scripting_client.cpp +++ b/src/script/scripting_client.cpp @@ -69,6 +69,7 @@ void ClientScripting::InitializeModApi(lua_State *L, int top) { LuaItemStack::Register(L); ItemStackMetaRef::Register(L); + LuaRaycast::Register(L); StorageRef::Register(L); LuaMinimap::Register(L); NodeMetaRef::RegisterClient(L); diff --git a/src/script/scripting_server.cpp b/src/script/scripting_server.cpp index 2204c6884..cbf229640 100644 --- a/src/script/scripting_server.cpp +++ b/src/script/scripting_server.cpp @@ -121,8 +121,3 @@ void ServerScripting::InitializeModApi(lua_State *L, int top) ModApiStorage::Initialize(L, top); ModApiChannels::Initialize(L, top); } - -void log_deprecated(const std::string &message) -{ - log_deprecated(NULL, message); -} diff --git a/src/script/scripting_server.h b/src/script/scripting_server.h index 88cea143c..bf06ab197 100644 --- a/src/script/scripting_server.h +++ b/src/script/scripting_server.h @@ -51,5 +51,3 @@ public: private: void InitializeModApi(lua_State *L, int top); }; - -void log_deprecated(const std::string &message); |