X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fscript%2Flua_api%2Fl_object.cpp;h=23ed1ffe005f81fed662fe3be849fb937574df89;hb=a87805a9445f280ca71da322c4b32cf357744511;hp=f72a81d322a28d1864d9e10ed88bcf765e8d406b;hpb=c7c03ad7a60b77040d0dfc360a79f065e0c2c971;p=dragonfireclient.git diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp index f72a81d32..23ed1ffe0 100644 --- a/src/script/lua_api/l_object.cpp +++ b/src/script/lua_api/l_object.cpp @@ -18,9 +18,11 @@ with this program; if not, write to the Free Software Foundation, Inc., */ #include "lua_api/l_object.h" +#include #include "lua_api/l_internal.h" #include "lua_api/l_inventory.h" #include "lua_api/l_item.h" +#include "lua_api/l_playermeta.h" #include "common/c_converter.h" #include "common/c_content.h" #include "log.h" @@ -58,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; } @@ -68,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; } @@ -101,12 +107,8 @@ int ObjectRef::l_remove(lua_State *L) if (co->getType() == ACTIVEOBJECT_TYPE_PLAYER) return 0; - const std::unordered_set &child_ids = co->getAttachmentChildIds(); - for (int child_id : child_ids) { - // Child can be NULL if it was deleted earlier - if (ServerActiveObject *child = env->getActiveObject(child_id)) - child->setAttachment(0, "", v3f(0, 0, 0), v3f(0, 0, 0)); - } + co->clearChildAttachments(); + co->clearParentAttachment(); verbosestream << "ObjectRef::l_remove(): id=" << co->getId() << std::endl; co->m_pending_removal = true; @@ -158,7 +160,7 @@ int ObjectRef::l_move_to(lua_State *L) // pos v3f pos = checkFloatPos(L, 2); // continuous - bool continuous = lua_toboolean(L, 3); + bool continuous = readParam(L, 3); // Do it co->moveTo(pos, continuous); return 0; @@ -172,8 +174,8 @@ int ObjectRef::l_punch(lua_State *L) ObjectRef *puncher_ref = checkobject(L, 2); ServerActiveObject *co = getobject(ref); ServerActiveObject *puncher = getobject(puncher_ref); - if (co == NULL) return 0; - if (puncher == NULL) return 0; + if (!co || !puncher) + return 0; v3f dir; if (lua_type(L, 5) != LUA_TTABLE) dir = co->getBasePosition() - puncher->getBasePosition(); @@ -185,24 +187,27 @@ int ObjectRef::l_punch(lua_State *L) ToolCapabilities toolcap = read_tool_capabilities(L, 4); dir.normalize(); - s16 src_original_hp = co->getHP(); - s16 dst_origin_hp = puncher->getHP(); + u16 src_original_hp = co->getHP(); + u16 dst_origin_hp = puncher->getHP(); // Do it - co->punch(dir, &toolcap, puncher, time_from_last_punch); + u16 wear = co->punch(dir, &toolcap, puncher, time_from_last_punch); + lua_pushnumber(L, wear); // If the punched is a player, and its HP changed if (src_original_hp != co->getHP() && co->getType() == ACTIVEOBJECT_TYPE_PLAYER) { - getServer(L)->SendPlayerHPOrDie((PlayerSAO *)co); + getServer(L)->SendPlayerHPOrDie((PlayerSAO *)co, + PlayerHPChangeReason(PlayerHPChangeReason::PLAYER_PUNCH, puncher)); } // If the puncher is a player, and its HP changed if (dst_origin_hp != puncher->getHP() && puncher->getType() == ACTIVEOBJECT_TYPE_PLAYER) { - getServer(L)->SendPlayerHPOrDie((PlayerSAO *)puncher); + getServer(L)->SendPlayerHPOrDie((PlayerSAO *)puncher, + PlayerHPChangeReason(PlayerHPChangeReason::PLAYER_PUNCH, co)); } - return 0; + return 1; } // right_click(self, clicker); clicker = an another ObjectRef @@ -226,17 +231,40 @@ int ObjectRef::l_right_click(lua_State *L) int ObjectRef::l_set_hp(lua_State *L) { NO_MAP_LOCK_REQUIRED; + + // Get Object ObjectRef *ref = checkobject(L, 1); luaL_checknumber(L, 2); ServerActiveObject *co = getobject(ref); - if (co == NULL) return 0; + if (co == NULL) + return 0; + + // Get HP int hp = lua_tonumber(L, 2); - /*infostream<<"ObjectRef::l_set_hp(): id="<getId() - <<" hp="<(L, -1))) { + errorstream << "Bad type given!" << std::endl; + } + lua_pop(L, 1); + + reason.lua_reference = luaL_ref(L, LUA_REGISTRYINDEX); + } + // Do it - co->setHP(hp); + co->setHP(hp, reason); if (co->getType() == ACTIVEOBJECT_TYPE_PLAYER) - getServer(L)->SendPlayerHPOrDie((PlayerSAO *)co); + getServer(L)->SendPlayerHPOrDie((PlayerSAO *)co, reason); + + if (reason.hasLuaReference()) + luaL_unref(L, LUA_REGISTRYINDEX, reason.lua_reference); // Return return 0; @@ -285,8 +313,9 @@ int ObjectRef::l_get_wield_list(lua_State *L) NO_MAP_LOCK_REQUIRED; ObjectRef *ref = checkobject(L, 1); ServerActiveObject *co = getobject(ref); - if (co == NULL) return 0; - // Do it + if (!co) + return 0; + lua_pushstring(L, co->getWieldList().c_str()); return 1; } @@ -297,8 +326,9 @@ int ObjectRef::l_get_wield_index(lua_State *L) NO_MAP_LOCK_REQUIRED; ObjectRef *ref = checkobject(L, 1); ServerActiveObject *co = getobject(ref); - if (co == NULL) return 0; - // Do it + if (!co) + return 0; + lua_pushinteger(L, co->getWieldIndex() + 1); return 1; } @@ -309,13 +339,15 @@ int ObjectRef::l_get_wielded_item(lua_State *L) NO_MAP_LOCK_REQUIRED; ObjectRef *ref = checkobject(L, 1); ServerActiveObject *co = getobject(ref); - if (co == NULL) { + if (!co) { // Empty ItemStack LuaItemStack::create(L, ItemStack()); return 1; } - // Do it - LuaItemStack::create(L, co->getWieldedItem()); + + ItemStack selected_item; + co->getWieldedItem(&selected_item, nullptr); + LuaItemStack::create(L, selected_item); return 1; } @@ -330,7 +362,7 @@ int ObjectRef::l_set_wielded_item(lua_State *L) ItemStack item = read_item(L, 2, getServer(L)->idef()); bool success = co->setWieldedItem(item); if (success && co->getType() == ACTIVEOBJECT_TYPE_PLAYER) { - getServer(L)->SendInventory(((PlayerSAO*)co)); + getServer(L)->SendInventory((PlayerSAO *)co, true); } lua_pushboolean(L, success); return 1; @@ -439,7 +471,7 @@ int ObjectRef::l_set_animation(lua_State *L) // Do it v2f frames = v2f(1, 1); if (!lua_isnil(L, 2)) - frames = read_v2f(L, 2); + frames = readParam(L, 2); float frame_speed = 15; if (!lua_isnil(L, 3)) frame_speed = lua_tonumber(L, 3); @@ -448,7 +480,7 @@ int ObjectRef::l_set_animation(lua_State *L) frame_blend = lua_tonumber(L, 4); bool frame_loop = true; if (lua_isboolean(L, 5)) - frame_loop = lua_toboolean(L, 5); + frame_loop = readParam(L, 5); co->setAnimation(frames, frame_speed, frame_blend, frame_loop); return 0; } @@ -561,6 +593,24 @@ int ObjectRef::l_get_eye_offset(lua_State *L) return 2; } +// send_mapblock(self, pos) +int ObjectRef::l_send_mapblock(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + + RemotePlayer *player = getplayer(ref); + if (!player) + return 0; + v3s16 p = read_v3s16(L, 2); + + session_t peer_id = player->getPeerId(); + bool r = getServer(L)->SendBlock(peer_id, p); + + lua_pushboolean(L, r); + return 1; +} + // set_animation_frame_speed(self, frame_speed) int ObjectRef::l_set_animation_frame_speed(lua_State *L) { @@ -591,7 +641,7 @@ int ObjectRef::l_set_bone_position(lua_State *L) // Do it std::string bone; if (!lua_isnil(L, 2)) - bone = lua_tostring(L, 2); + bone = readParam(L, 2); v3f position = v3f(0, 0, 0); if (!lua_isnil(L, 3)) position = check_v3f(L, 3); @@ -613,7 +663,7 @@ int ObjectRef::l_get_bone_position(lua_State *L) // Do it std::string bone; if (!lua_isnil(L, 2)) - bone = lua_tostring(L, 2); + bone = readParam(L, 2); v3f position = v3f(0, 0, 0); v3f rotation = v3f(0, 0, 0); @@ -650,7 +700,7 @@ int ObjectRef::l_set_attach(lua_State *L) bone = ""; if (!lua_isnil(L, 3)) - bone = lua_tostring(L, 3); + bone = readParam(L, 3); position = v3f(0, 0, 0); if (!lua_isnil(L, 4)) position = read_v3f(L, 4); @@ -699,21 +749,7 @@ int ObjectRef::l_set_detach(lua_State *L) if (co == NULL) return 0; - int parent_id = 0; - std::string bone; - v3f position; - v3f rotation; - co->getAttachment(&parent_id, &bone, &position, &rotation); - ServerActiveObject *parent = NULL; - if (parent_id) { - parent = env->getActiveObject(parent_id); - co->setAttachment(0, "", position, rotation); - } else { - co->setAttachment(0, "", v3f(0, 0, 0), v3f(0, 0, 0)); - } - // Do it - if (parent != NULL) - parent->removeAttachmentChild(co->getId()); + co->clearParentAttachment(); return 0; } @@ -723,16 +759,14 @@ int ObjectRef::l_set_properties(lua_State *L) NO_MAP_LOCK_REQUIRED; ObjectRef *ref = checkobject(L, 1); ServerActiveObject *co = getobject(ref); - if (co == NULL) return 0; + if (!co) + return 0; + ObjectProperties *prop = co->accessObjectProperties(); if (!prop) return 0; - read_object_properties(L, 2, prop, getServer(L)->idef()); - if (prop->hp_max < co->getHP()) { - co->setHP(prop->hp_max); - if (co->getType() == ACTIVEOBJECT_TYPE_PLAYER) - getServer(L)->SendPlayerHPOrDie((PlayerSAO *)co); - } + + read_object_properties(L, 2, co, prop, getServer(L)->idef()); co->notifyObjectPropertiesModified(); return 0; } @@ -829,6 +863,20 @@ int ObjectRef::l_set_velocity(lua_State *L) return 0; } +// add_velocity(self, {x=num, y=num, z=num}) +int ObjectRef::l_add_velocity(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + LuaEntitySAO *co = getluaobject(ref); + if (!co) + return 0; + v3f pos = checkFloatPos(L, 2); + // Do it + co->addVelocity(pos); + return 0; +} + // get_velocity(self) int ObjectRef::l_get_velocity(lua_State *L) { @@ -869,16 +917,51 @@ int ObjectRef::l_get_acceleration(lua_State *L) return 1; } +// set_rotation(self, {x=num, y=num, z=num}) +// Each 'num' is in radians +int ObjectRef::l_set_rotation(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + LuaEntitySAO *co = getluaobject(ref); + if (!co) + return 0; + + v3f rotation = check_v3f(L, 2) * core::RADTODEG; + co->setRotation(rotation); + return 0; +} + +// get_rotation(self) +// returns: {x=num, y=num, z=num} +// Each 'num' is in radians +int ObjectRef::l_get_rotation(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + LuaEntitySAO *co = getluaobject(ref); + if (!co) + return 0; + + lua_newtable(L); + v3f rotation = co->getRotation() * core::DEGTORAD; + push_v3f(L, rotation); + return 1; +} + // set_yaw(self, radians) int ObjectRef::l_set_yaw(lua_State *L) { NO_MAP_LOCK_REQUIRED; ObjectRef *ref = checkobject(L, 1); LuaEntitySAO *co = getluaobject(ref); + if (co == NULL) return 0; - float yaw = luaL_checknumber(L, 2) * core::RADTODEG; - // Do it - co->setYaw(yaw); + if (isNaN(L, 2)) + throw LuaError("ObjectRef::set_yaw: NaN value is not allowed."); + + float yaw = readParam(L, 2) * core::RADTODEG; + co->setRotation(v3f(0, yaw, 0)); return 0; } @@ -888,9 +971,10 @@ int ObjectRef::l_get_yaw(lua_State *L) NO_MAP_LOCK_REQUIRED; ObjectRef *ref = checkobject(L, 1); LuaEntitySAO *co = getluaobject(ref); - if (co == NULL) return 0; - // Do it - float yaw = co->getYaw() * core::DEGTORAD; + if (!co) + return 0; + + float yaw = co->getRotation().Y * core::DEGTORAD; lua_pushnumber(L, yaw); return 1; } @@ -932,7 +1016,7 @@ int ObjectRef::l_set_sprite(lua_State *L) // Do it v2s16 p(0,0); if (!lua_isnil(L, 2)) - p = read_v2s16(L, 2); + p = readParam(L, 2); int num_frames = 1; if (!lua_isnil(L, 3)) num_frames = lua_tonumber(L, 3); @@ -941,7 +1025,7 @@ int ObjectRef::l_set_sprite(lua_State *L) framelength = lua_tonumber(L, 4); bool select_horiz_by_yawpitch = false; if (!lua_isnil(L, 5)) - select_horiz_by_yawpitch = lua_toboolean(L, 5); + select_horiz_by_yawpitch = readParam(L, 5); co->setSprite(p, num_frames, framelength, select_horiz_by_yawpitch); return 0; } @@ -979,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)); @@ -1015,6 +1102,27 @@ int ObjectRef::l_get_player_velocity(lua_State *L) return 1; } +// add_player_velocity(self, {x=num, y=num, z=num}) +int ObjectRef::l_add_player_velocity(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + v3f vel = checkFloatPos(L, 2); + + RemotePlayer *player = getplayer(ref); + PlayerSAO *co = getplayersao(ref); + if (!player || !co) + return 0; + + session_t peer_id = player->getPeerId(); + if (peer_id == PEER_ID_INEXISTENT) + return 0; + // Do it + co->setMaxSpeedOverride(vel); + getServer(L)->SendPlayerSpeed(peer_id, vel); + return 0; +} + // get_look_dir(self) int ObjectRef::l_get_look_dir(lua_State *L) { @@ -1023,9 +1131,10 @@ int ObjectRef::l_get_look_dir(lua_State *L) PlayerSAO* co = getplayersao(ref); if (co == NULL) return 0; // Do it - float pitch = co->getRadPitchDep(); + float pitch = co->getRadLookPitchDep(); float yaw = co->getRadYawDep(); - v3f v(cos(pitch)*cos(yaw), sin(pitch), cos(pitch)*sin(yaw)); + v3f v(std::cos(pitch) * std::cos(yaw), std::sin(pitch), std::cos(pitch) * + std::sin(yaw)); push_v3f(L, v); return 1; } @@ -1043,7 +1152,7 @@ int ObjectRef::l_get_look_pitch(lua_State *L) PlayerSAO* co = getplayersao(ref); if (co == NULL) return 0; // Do it - lua_pushnumber(L, co->getRadPitchDep()); + lua_pushnumber(L, co->getRadLookPitchDep()); return 1; } @@ -1072,7 +1181,7 @@ int ObjectRef::l_get_look_vertical(lua_State *L) PlayerSAO* co = getplayersao(ref); if (co == NULL) return 0; // Do it - lua_pushnumber(L, co->getRadPitch()); + lua_pushnumber(L, co->getRadLookPitch()); return 1; } @@ -1084,7 +1193,7 @@ int ObjectRef::l_get_look_horizontal(lua_State *L) PlayerSAO* co = getplayersao(ref); if (co == NULL) return 0; // Do it - lua_pushnumber(L, co->getRadYaw()); + lua_pushnumber(L, co->getRadRotation().Y); return 1; } @@ -1095,9 +1204,9 @@ int ObjectRef::l_set_look_vertical(lua_State *L) ObjectRef *ref = checkobject(L, 1); PlayerSAO* co = getplayersao(ref); if (co == NULL) return 0; - float pitch = luaL_checknumber(L, 2) * core::RADTODEG; + float pitch = readParam(L, 2) * core::RADTODEG; // Do it - co->setPitchAndSend(pitch); + co->setLookPitchAndSend(pitch); return 1; } @@ -1108,9 +1217,9 @@ int ObjectRef::l_set_look_horizontal(lua_State *L) ObjectRef *ref = checkobject(L, 1); PlayerSAO* co = getplayersao(ref); if (co == NULL) return 0; - float yaw = luaL_checknumber(L, 2) * core::RADTODEG; + float yaw = readParam(L, 2) * core::RADTODEG; // Do it - co->setYawAndSend(yaw); + co->setPlayerYawAndSend(yaw); return 1; } @@ -1126,9 +1235,9 @@ int ObjectRef::l_set_look_pitch(lua_State *L) ObjectRef *ref = checkobject(L, 1); PlayerSAO* co = getplayersao(ref); if (co == NULL) return 0; - float pitch = luaL_checknumber(L, 2) * core::RADTODEG; + float pitch = readParam(L, 2) * core::RADTODEG; // Do it - co->setPitchAndSend(pitch); + co->setLookPitchAndSend(pitch); return 1; } @@ -1144,12 +1253,43 @@ int ObjectRef::l_set_look_yaw(lua_State *L) ObjectRef *ref = checkobject(L, 1); PlayerSAO* co = getplayersao(ref); if (co == NULL) return 0; - float yaw = luaL_checknumber(L, 2) * core::RADTODEG; + float yaw = readParam(L, 2) * core::RADTODEG; // Do it - co->setYawAndSend(yaw); + co->setPlayerYawAndSend(yaw); return 1; } +// set_fov(self, degrees[, is_multiplier]) +int ObjectRef::l_set_fov(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + RemotePlayer *player = getplayer(ref); + if (!player) + return 0; + + player->setFov({ static_cast(luaL_checknumber(L, 2)), readParam(L, 3) }); + getServer(L)->SendPlayerFov(player->getPeerId()); + + return 0; +} + +// get_fov(self) +int ObjectRef::l_get_fov(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + RemotePlayer *player = getplayer(ref); + if (!player) + return 0; + + PlayerFovSpec fov_spec = player->getFov(); + lua_pushnumber(L, fov_spec.fov); + lua_pushboolean(L, fov_spec.is_multiplier); + + return 2; +} + // set_breath(self, breath) int ObjectRef::l_set_breath(lua_State *L) { @@ -1179,18 +1319,20 @@ int ObjectRef::l_get_breath(lua_State *L) // set_attribute(self, attribute, value) int ObjectRef::l_set_attribute(lua_State *L) { + log_deprecated(L, + "Deprecated call to set_attribute, use MetaDataRef methods instead."); + ObjectRef *ref = checkobject(L, 1); PlayerSAO* co = getplayersao(ref); - if (co == NULL) { + if (co == NULL) return 0; - } std::string attr = luaL_checkstring(L, 2); if (lua_isnil(L, 3)) { - co->removeExtendedAttribute(attr); + co->getMeta().removeString(attr); } else { std::string value = luaL_checkstring(L, 3); - co->setExtendedAttribute(attr, value); + co->getMeta().setString(attr, value); } return 1; } @@ -1198,16 +1340,18 @@ int ObjectRef::l_set_attribute(lua_State *L) // get_attribute(self, attribute) int ObjectRef::l_get_attribute(lua_State *L) { + log_deprecated(L, + "Deprecated call to get_attribute, use MetaDataRef methods instead."); + ObjectRef *ref = checkobject(L, 1); PlayerSAO* co = getplayersao(ref); - if (co == NULL) { + if (co == NULL) return 0; - } std::string attr = luaL_checkstring(L, 2); std::string value; - if (co->getExtendedAttribute(attr, &value)) { + if (co->getMeta().getStringToRef(attr, value)) { lua_pushstring(L, value.c_str()); return 1; } @@ -1216,6 +1360,19 @@ int ObjectRef::l_get_attribute(lua_State *L) } +// get_meta(self, attribute) +int ObjectRef::l_get_meta(lua_State *L) +{ + ObjectRef *ref = checkobject(L, 1); + PlayerSAO *co = getplayersao(ref); + if (co == NULL) + return 0; + + PlayerMetaRef::create(L, &co->getMeta()); + return 1; +} + + // set_inventory_formspec(self, formspec) int ObjectRef::l_set_inventory_formspec(lua_State *L) { @@ -1244,6 +1401,37 @@ int ObjectRef::l_get_inventory_formspec(lua_State *L) return 1; } +// set_formspec_prepend(self, formspec) +int ObjectRef::l_set_formspec_prepend(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + RemotePlayer *player = getplayer(ref); + if (player == NULL) + return 0; + + std::string formspec = luaL_checkstring(L, 2); + + player->formspec_prepend = formspec; + getServer(L)->reportFormspecPrependModified(player->getName()); + lua_pushboolean(L, true); + return 1; +} + +// get_formspec_prepend(self) -> formspec +int ObjectRef::l_get_formspec_prepend(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + RemotePlayer *player = getplayer(ref); + if (player == NULL) + return 0; + + std::string formspec = player->formspec_prepend; + lua_pushlstring(L, formspec.c_str(), formspec.size()); + return 1; +} + // get_player_control(self) int ObjectRef::l_get_player_control(lua_State *L) { @@ -1471,7 +1659,7 @@ int ObjectRef::l_hud_set_hotbar_image(lua_State *L) if (player == NULL) return 0; - std::string name = lua_tostring(L, 2); + std::string name = readParam(L, 2); getServer(L)->hudSetHotbarImage(player, name); return 1; @@ -1500,7 +1688,7 @@ int ObjectRef::l_hud_set_hotbar_selected_image(lua_State *L) if (player == NULL) return 0; - std::string name = lua_tostring(L, 2); + std::string name = readParam(L, 2); getServer(L)->hudSetHotbarSelectedImage(player, name); return 1; @@ -1520,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); + + 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); + + 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(L, -1)); + // Removes the value, but keeps the key for iteration + lua_pop(L, 1); + } + } + lua_pop(L, 1); - std::string type = luaL_checkstring(L, 3); + /* + 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. + */ - std::vector 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(lua_tostring(L, -1)); - else - params.emplace_back(""); - // removes value, keeps key for next iteration + 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(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 = lua_toboolean(L, 5); + skybox_params.clouds = true; + if (lua_isboolean(L, 5)) + skybox_params.clouds = readParam(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; } @@ -1566,29 +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 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()); - lua_rawseti(L, -2, i); - i++; + 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) { @@ -1674,7 +2174,7 @@ int ObjectRef::l_override_day_night_ratio(lua_State *L) float ratio = 0.0f; if (!lua_isnil(L, 2)) { do_override = true; - ratio = luaL_checknumber(L, 2); + ratio = readParam(L, 2); } if (!getServer(L)->overrideDayNightRatio(player, do_override, ratio)) @@ -1749,6 +2249,7 @@ void ObjectRef::Register(lua_State *L) lua_pop(L, 1); // drop metatable + markAliasDeprecated(methods); luaL_openlib(L, 0, methods, 0); // fill methodtable lua_pop(L, 1); // drop methodtable @@ -1757,7 +2258,7 @@ void ObjectRef::Register(lua_State *L) } const char ObjectRef::className[] = "ObjectRef"; -const luaL_Reg ObjectRef::methods[] = { +luaL_Reg ObjectRef::methods[] = { // ServerActiveObject luamethod(ObjectRef, remove), luamethod_aliased(ObjectRef, get_pos, getpos), @@ -1788,11 +2289,14 @@ const luaL_Reg ObjectRef::methods[] = { luamethod(ObjectRef, get_nametag_attributes), // LuaEntitySAO-only luamethod_aliased(ObjectRef, set_velocity, setvelocity), + luamethod(ObjectRef, add_velocity), luamethod_aliased(ObjectRef, get_velocity, getvelocity), luamethod_aliased(ObjectRef, set_acceleration, setacceleration), luamethod_aliased(ObjectRef, get_acceleration, getacceleration), luamethod_aliased(ObjectRef, set_yaw, setyaw), luamethod_aliased(ObjectRef, get_yaw, getyaw), + luamethod(ObjectRef, set_rotation), + luamethod(ObjectRef, get_rotation), luamethod_aliased(ObjectRef, set_texture_mod, settexturemod), luamethod_aliased(ObjectRef, set_sprite, setsprite), luamethod(ObjectRef, get_entity_name), @@ -1802,6 +2306,7 @@ const luaL_Reg ObjectRef::methods[] = { luamethod(ObjectRef, is_player_connected), luamethod(ObjectRef, get_player_name), luamethod(ObjectRef, get_player_velocity), + luamethod(ObjectRef, add_player_velocity), luamethod(ObjectRef, get_look_dir), luamethod(ObjectRef, get_look_pitch), luamethod(ObjectRef, get_look_yaw), @@ -1811,12 +2316,17 @@ const luaL_Reg ObjectRef::methods[] = { luamethod(ObjectRef, set_look_vertical), luamethod(ObjectRef, set_look_yaw), luamethod(ObjectRef, set_look_pitch), + luamethod(ObjectRef, get_fov), + luamethod(ObjectRef, set_fov), luamethod(ObjectRef, get_breath), luamethod(ObjectRef, set_breath), luamethod(ObjectRef, get_attribute), luamethod(ObjectRef, set_attribute), + luamethod(ObjectRef, get_meta), luamethod(ObjectRef, set_inventory_formspec), luamethod(ObjectRef, get_inventory_formspec), + luamethod(ObjectRef, set_formspec_prepend), + luamethod(ObjectRef, get_formspec_prepend), luamethod(ObjectRef, get_player_control), luamethod(ObjectRef, get_player_control_bits), luamethod(ObjectRef, set_physics_override), @@ -1835,6 +2345,13 @@ const 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), @@ -1843,5 +2360,6 @@ const luaL_Reg ObjectRef::methods[] = { luamethod(ObjectRef, get_local_animation), luamethod(ObjectRef, set_eye_offset), luamethod(ObjectRef, get_eye_offset), + luamethod(ObjectRef, send_mapblock), {0,0} };