diff options
Diffstat (limited to 'src/script/lua_api')
-rw-r--r-- | src/script/lua_api/l_camera.cpp | 7 | ||||
-rw-r--r-- | src/script/lua_api/l_client.cpp | 86 | ||||
-rw-r--r-- | src/script/lua_api/l_client.h | 6 | ||||
-rw-r--r-- | src/script/lua_api/l_env.cpp | 87 | ||||
-rw-r--r-- | src/script/lua_api/l_env.h | 3 | ||||
-rw-r--r-- | src/script/lua_api/l_item.cpp | 10 | ||||
-rw-r--r-- | src/script/lua_api/l_localplayer.cpp | 4 | ||||
-rw-r--r-- | src/script/lua_api/l_mapgen.cpp | 2 | ||||
-rw-r--r-- | src/script/lua_api/l_object.cpp | 395 | ||||
-rw-r--r-- | src/script/lua_api/l_object.h | 23 | ||||
-rw-r--r-- | src/script/lua_api/l_server.cpp | 14 | ||||
-rw-r--r-- | src/script/lua_api/l_settings.cpp | 25 | ||||
-rw-r--r-- | src/script/lua_api/l_settings.h | 3 | ||||
-rw-r--r-- | src/script/lua_api/l_util.cpp | 2 |
14 files changed, 576 insertions, 91 deletions
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); |