summaryrefslogtreecommitdiff
path: root/src/script
diff options
context:
space:
mode:
Diffstat (limited to 'src/script')
-rw-r--r--src/script/common/c_content.cpp47
-rw-r--r--src/script/common/c_content.h2
-rw-r--r--src/script/common/c_converter.cpp4
-rw-r--r--src/script/common/c_converter.h2
-rw-r--r--src/script/common/helper.cpp5
-rw-r--r--src/script/cpp_api/s_base.cpp11
-rw-r--r--src/script/cpp_api/s_entity.cpp6
-rw-r--r--src/script/cpp_api/s_entity.h2
-rw-r--r--src/script/cpp_api/s_env.cpp8
-rw-r--r--src/script/cpp_api/s_node.cpp2
-rw-r--r--src/script/cpp_api/s_nodemeta.cpp12
-rw-r--r--src/script/cpp_api/s_security.cpp3
-rw-r--r--src/script/cpp_api/s_server.cpp22
-rw-r--r--src/script/cpp_api/s_server.h12
-rw-r--r--src/script/lua_api/l_areastore.cpp1
-rw-r--r--src/script/lua_api/l_camera.cpp21
-rw-r--r--src/script/lua_api/l_client.cpp16
-rw-r--r--src/script/lua_api/l_craft.cpp10
-rw-r--r--src/script/lua_api/l_env.cpp32
-rw-r--r--src/script/lua_api/l_http.cpp15
-rw-r--r--src/script/lua_api/l_item.cpp11
-rw-r--r--src/script/lua_api/l_item.h3
-rw-r--r--src/script/lua_api/l_localplayer.cpp22
-rw-r--r--src/script/lua_api/l_mainmenu.cpp28
-rw-r--r--src/script/lua_api/l_mainmenu.h4
-rw-r--r--src/script/lua_api/l_mapgen.cpp89
-rw-r--r--src/script/lua_api/l_mapgen.h3
-rw-r--r--src/script/lua_api/l_nodemeta.cpp2
-rw-r--r--src/script/lua_api/l_object.cpp125
-rw-r--r--src/script/lua_api/l_object.h11
-rw-r--r--src/script/lua_api/l_server.cpp4
-rw-r--r--src/script/lua_api/l_vmanip.cpp2
-rw-r--r--src/script/scripting_client.cpp5
33 files changed, 427 insertions, 115 deletions
diff --git a/src/script/common/c_content.cpp b/src/script/common/c_content.cpp
index 793485e25..cb0253c32 100644
--- a/src/script/common/c_content.cpp
+++ b/src/script/common/c_content.cpp
@@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "common/c_types.h"
#include "nodedef.h"
#include "object_properties.h"
+#include "content_sao.h"
#include "cpp_api/s_node.h"
#include "lua_api/l_object.h"
#include "lua_api/l_item.h"
@@ -163,11 +164,7 @@ void push_item_definition_full(lua_State *L, const ItemDefinition &i)
lua_pushboolean(L, i.liquids_pointable);
lua_setfield(L, -2, "liquids_pointable");
if (i.type == ITEM_TOOL) {
- push_tool_capabilities(L, ToolCapabilities(
- i.tool_capabilities->full_punch_interval,
- i.tool_capabilities->max_drop_level,
- i.tool_capabilities->groupcaps,
- i.tool_capabilities->damageGroups));
+ push_tool_capabilities(L, *i.tool_capabilities);
lua_setfield(L, -2, "tool_capabilities");
}
push_groups(L, i.groups);
@@ -182,7 +179,7 @@ void push_item_definition_full(lua_State *L, const ItemDefinition &i)
/******************************************************************************/
void read_object_properties(lua_State *L, int index,
- ObjectProperties *prop, IItemDefManager *idef)
+ ServerActiveObject *sao, ObjectProperties *prop, IItemDefManager *idef)
{
if(index < 0)
index = lua_gettop(L) + 1 + index;
@@ -190,10 +187,24 @@ void read_object_properties(lua_State *L, int index,
return;
int hp_max = 0;
- if (getintfield(L, -1, "hp_max", hp_max))
+ if (getintfield(L, -1, "hp_max", hp_max)) {
prop->hp_max = (u16)rangelim(hp_max, 0, U16_MAX);
- getintfield(L, -1, "breath_max", prop->breath_max);
+ if (prop->hp_max < sao->getHP()) {
+ PlayerHPChangeReason reason(PlayerHPChangeReason::SET_HP);
+ sao->setHP(prop->hp_max, reason);
+ if (sao->getType() == ACTIVEOBJECT_TYPE_PLAYER)
+ sao->getEnv()->getGameDef()->SendPlayerHPOrDie((PlayerSAO *)sao, reason);
+ }
+ }
+
+ if (getintfield(L, -1, "breath_max", prop->breath_max)) {
+ if (sao->getType() == ACTIVEOBJECT_TYPE_PLAYER) {
+ PlayerSAO *player = (PlayerSAO *)sao;
+ if (prop->breath_max < player->getBreath())
+ player->setBreath(prop->breath_max);
+ }
+ }
getboolfield(L, -1, "physical", prop->physical);
getboolfield(L, -1, "collide_with_objects", prop->collideWithObjects);
@@ -1093,7 +1104,7 @@ MapNode readnode(lua_State *L, int index, const NodeDefManager *ndef)
lua_getfield(L, index, "name");
if (!lua_isstring(L, -1))
throw LuaError("Node name is not set or is not a string!");
- const char *name = lua_tostring(L, -1);
+ std::string name = lua_tostring(L, -1);
lua_pop(L, 1);
u8 param1 = 0;
@@ -1108,7 +1119,11 @@ MapNode readnode(lua_State *L, int index, const NodeDefManager *ndef)
param2 = lua_tonumber(L, -1);
lua_pop(L, 1);
- return {ndef, name, param1, param2};
+ content_t id = CONTENT_IGNORE;
+ if (!ndef->getId(name, id))
+ throw LuaError("\"" + name + "\" is not a registered node!");
+
+ return {id, param1, param2};
}
/******************************************************************************/
@@ -1234,7 +1249,8 @@ void push_tool_capabilities(lua_State *L,
{
lua_newtable(L);
setfloatfield(L, -1, "full_punch_interval", toolcap.full_punch_interval);
- setintfield(L, -1, "max_drop_level", toolcap.max_drop_level);
+ setintfield(L, -1, "max_drop_level", toolcap.max_drop_level);
+ setintfield(L, -1, "punch_attack_uses", toolcap.punch_attack_uses);
// Create groupcaps table
lua_newtable(L);
// For each groupcap
@@ -1356,6 +1372,7 @@ ToolCapabilities read_tool_capabilities(
ToolCapabilities toolcap;
getfloatfield(L, table, "full_punch_interval", toolcap.full_punch_interval);
getintfield(L, table, "max_drop_level", toolcap.max_drop_level);
+ getintfield(L, table, "punch_attack_uses", toolcap.punch_attack_uses);
lua_getfield(L, table, "groupcaps");
if(lua_istable(L, -1)){
int table_groupcaps = lua_gettop(L);
@@ -1510,13 +1527,15 @@ void read_groups(lua_State *L, int index, ItemGroupList &result)
return;
result.clear();
lua_pushnil(L);
- if(index < 0)
+ if (index < 0)
index -= 1;
- while(lua_next(L, index) != 0){
+ while (lua_next(L, index) != 0) {
// key at index -2 and value at index -1
std::string name = luaL_checkstring(L, -2);
int rating = luaL_checkinteger(L, -1);
- result[name] = rating;
+ // zero rating indicates not in the group
+ if (rating != 0)
+ result[name] = rating;
// removes value, keeps key for next iteration
lua_pop(L, 1);
}
diff --git a/src/script/common/c_content.h b/src/script/common/c_content.h
index f3a653682..9e755682f 100644
--- a/src/script/common/c_content.h
+++ b/src/script/common/c_content.h
@@ -62,6 +62,7 @@ struct HitParams;
struct EnumString;
struct NoiseParams;
class Schematic;
+class ServerActiveObject;
ContentFeatures read_content_features (lua_State *L, int index);
@@ -107,6 +108,7 @@ void push_item_definition_full (lua_State *L,
const ItemDefinition &i);
void read_object_properties (lua_State *L, int index,
+ ServerActiveObject *sao,
ObjectProperties *prop,
IItemDefManager *idef);
void push_object_properties (lua_State *L,
diff --git a/src/script/common/c_converter.cpp b/src/script/common/c_converter.cpp
index dfd3f5cea..b9d6f0494 100644
--- a/src/script/common/c_converter.cpp
+++ b/src/script/common/c_converter.cpp
@@ -540,9 +540,9 @@ v3s16 getv3s16field_default(lua_State *L, int table,
}
void setstringfield(lua_State *L, int table,
- const char *fieldname, const char *value)
+ const char *fieldname, const std::string &value)
{
- lua_pushstring(L, value);
+ lua_pushlstring(L, value.c_str(), value.length());
if(table < 0)
table -= 1;
lua_setfield(L, table, fieldname);
diff --git a/src/script/common/c_converter.h b/src/script/common/c_converter.h
index 87bc35ac6..f84494c8d 100644
--- a/src/script/common/c_converter.h
+++ b/src/script/common/c_converter.h
@@ -91,7 +91,7 @@ std::string checkstringfield(lua_State *L, int table,
const char *fieldname);
void setstringfield(lua_State *L, int table,
- const char *fieldname, const char *value);
+ const char *fieldname, const std::string &value);
void setintfield(lua_State *L, int table,
const char *fieldname, int value);
void setfloatfield(lua_State *L, int table,
diff --git a/src/script/common/helper.cpp b/src/script/common/helper.cpp
index 59bde57ab..f53a2b7e8 100644
--- a/src/script/common/helper.cpp
+++ b/src/script/common/helper.cpp
@@ -107,9 +107,10 @@ template <> v2f LuaHelper::readParam(lua_State *L, int index)
template <> std::string LuaHelper::readParam(lua_State *L, int index)
{
+ size_t length;
std::string result;
- const char *str = luaL_checkstring(L, index);
- result.append(str);
+ const char *str = luaL_checklstring(L, index, &length);
+ result.assign(str, length);
return result;
}
diff --git a/src/script/cpp_api/s_base.cpp b/src/script/cpp_api/s_base.cpp
index a8ed902dd..caa335d76 100644
--- a/src/script/cpp_api/s_base.cpp
+++ b/src/script/cpp_api/s_base.cpp
@@ -232,6 +232,13 @@ void ScriptApiBase::loadModFromMemory(const std::string &mod_name)
void ScriptApiBase::runCallbacksRaw(int nargs,
RunCallbacksMode mode, const char *fxn)
{
+#ifndef SERVER
+ // Hard fail for bad guarded callbacks
+ // Only run callbacks when the scripting enviroment is loaded
+ FATAL_ERROR_IF(m_type == ScriptingType::Client &&
+ !getClient()->modsLoaded(), fxn);
+#endif
+
#ifdef SCRIPTAPI_LOCK_DEBUG
assert(m_lock_recursion_count > 0);
#endif
@@ -404,6 +411,10 @@ void ScriptApiBase::pushPlayerHPChangeReason(lua_State *L, const PlayerHPChangeR
objectrefGetOrCreate(L, reason.object);
lua_setfield(L, -2, "object");
}
+ if (!reason.node.empty()) {
+ lua_pushstring(L, reason.node.c_str());
+ lua_setfield(L, -2, "node");
+ }
}
Server* ScriptApiBase::getServer()
diff --git a/src/script/cpp_api/s_entity.cpp b/src/script/cpp_api/s_entity.cpp
index 8af9f9bf6..26c7e8cd4 100644
--- a/src/script/cpp_api/s_entity.cpp
+++ b/src/script/cpp_api/s_entity.cpp
@@ -157,7 +157,7 @@ std::string ScriptApiEntity::luaentity_GetStaticdata(u16 id)
}
void ScriptApiEntity::luaentity_GetProperties(u16 id,
- ObjectProperties *prop)
+ ServerActiveObject *self, ObjectProperties *prop)
{
SCRIPTAPI_PRECHECKHEADER
@@ -170,11 +170,11 @@ void ScriptApiEntity::luaentity_GetProperties(u16 id,
prop->hp_max = 10;
// Deprecated: read object properties directly
- read_object_properties(L, -1, prop, getServer()->idef());
+ read_object_properties(L, -1, self, prop, getServer()->idef());
// Read initial_properties
lua_getfield(L, -1, "initial_properties");
- read_object_properties(L, -1, prop, getServer()->idef());
+ read_object_properties(L, -1, self, prop, getServer()->idef());
lua_pop(L, 1);
}
diff --git a/src/script/cpp_api/s_entity.h b/src/script/cpp_api/s_entity.h
index 966c2745e..cc08c46e8 100644
--- a/src/script/cpp_api/s_entity.h
+++ b/src/script/cpp_api/s_entity.h
@@ -35,7 +35,7 @@ public:
void luaentity_Remove(u16 id);
std::string luaentity_GetStaticdata(u16 id);
void luaentity_GetProperties(u16 id,
- ObjectProperties *prop);
+ ServerActiveObject *self, ObjectProperties *prop);
void luaentity_Step(u16 id, float dtime);
bool luaentity_Punch(u16 id,
ServerActiveObject *puncher, float time_from_last_punch,
diff --git a/src/script/cpp_api/s_env.cpp b/src/script/cpp_api/s_env.cpp
index f8cef98b7..ab3b5fe46 100644
--- a/src/script/cpp_api/s_env.cpp
+++ b/src/script/cpp_api/s_env.cpp
@@ -151,6 +151,10 @@ void ScriptApiEnv::initializeEnvironment(ServerEnvironment *env)
bool simple_catch_up = true;
getboolfield(L, current_abm, "catch_up", simple_catch_up);
+ lua_getfield(L, current_abm, "action");
+ luaL_checktype(L, current_abm + 1, LUA_TFUNCTION);
+ lua_pop(L, 1);
+
LuaABM *abm = new LuaABM(L, id, trigger_contents, required_neighbors,
trigger_interval, trigger_chance, simple_catch_up);
@@ -200,6 +204,10 @@ void ScriptApiEnv::initializeEnvironment(ServerEnvironment *env)
bool run_at_every_load = getboolfield_default(L, current_lbm,
"run_at_every_load", false);
+ lua_getfield(L, current_lbm, "action");
+ luaL_checktype(L, current_lbm + 1, LUA_TFUNCTION);
+ lua_pop(L, 1);
+
LuaLBM *lbm = new LuaLBM(L, id, trigger_contents, name,
run_at_every_load);
diff --git a/src/script/cpp_api/s_node.cpp b/src/script/cpp_api/s_node.cpp
index 719f53a6b..d93a4c3ad 100644
--- a/src/script/cpp_api/s_node.cpp
+++ b/src/script/cpp_api/s_node.cpp
@@ -246,7 +246,7 @@ void ScriptApiNode::node_on_receive_fields(v3s16 p,
const NodeDefManager *ndef = getServer()->ndef();
// If node doesn't exist, we don't know what callback to call
- MapNode node = getEnv()->getMap().getNodeNoEx(p);
+ MapNode node = getEnv()->getMap().getNode(p);
if (node.getContent() == CONTENT_IGNORE)
return;
diff --git a/src/script/cpp_api/s_nodemeta.cpp b/src/script/cpp_api/s_nodemeta.cpp
index b49bb8170..c081e9fc4 100644
--- a/src/script/cpp_api/s_nodemeta.cpp
+++ b/src/script/cpp_api/s_nodemeta.cpp
@@ -38,7 +38,7 @@ int ScriptApiNodemeta::nodemeta_inventory_AllowMove(
const NodeDefManager *ndef = getServer()->ndef();
// If node doesn't exist, we don't know what callback to call
- MapNode node = getEnv()->getMap().getNodeNoEx(ma.to_inv.p);
+ MapNode node = getEnv()->getMap().getNode(ma.to_inv.p);
if (node.getContent() == CONTENT_IGNORE)
return 0;
@@ -76,7 +76,7 @@ int ScriptApiNodemeta::nodemeta_inventory_AllowPut(
const NodeDefManager *ndef = getServer()->ndef();
// If node doesn't exist, we don't know what callback to call
- MapNode node = getEnv()->getMap().getNodeNoEx(ma.to_inv.p);
+ MapNode node = getEnv()->getMap().getNode(ma.to_inv.p);
if (node.getContent() == CONTENT_IGNORE)
return 0;
@@ -112,7 +112,7 @@ int ScriptApiNodemeta::nodemeta_inventory_AllowTake(
const NodeDefManager *ndef = getServer()->ndef();
// If node doesn't exist, we don't know what callback to call
- MapNode node = getEnv()->getMap().getNodeNoEx(ma.from_inv.p);
+ MapNode node = getEnv()->getMap().getNode(ma.from_inv.p);
if (node.getContent() == CONTENT_IGNORE)
return 0;
@@ -148,7 +148,7 @@ void ScriptApiNodemeta::nodemeta_inventory_OnMove(
const NodeDefManager *ndef = getServer()->ndef();
// If node doesn't exist, we don't know what callback to call
- MapNode node = getEnv()->getMap().getNodeNoEx(ma.from_inv.p);
+ MapNode node = getEnv()->getMap().getNode(ma.from_inv.p);
if (node.getContent() == CONTENT_IGNORE)
return;
@@ -181,7 +181,7 @@ void ScriptApiNodemeta::nodemeta_inventory_OnPut(
const NodeDefManager *ndef = getServer()->ndef();
// If node doesn't exist, we don't know what callback to call
- MapNode node = getEnv()->getMap().getNodeNoEx(ma.to_inv.p);
+ MapNode node = getEnv()->getMap().getNode(ma.to_inv.p);
if (node.getContent() == CONTENT_IGNORE)
return;
@@ -212,7 +212,7 @@ void ScriptApiNodemeta::nodemeta_inventory_OnTake(
const NodeDefManager *ndef = getServer()->ndef();
// If node doesn't exist, we don't know what callback to call
- MapNode node = getEnv()->getMap().getNodeNoEx(ma.from_inv.p);
+ MapNode node = getEnv()->getMap().getNode(ma.from_inv.p);
if (node.getContent() == CONTENT_IGNORE)
return;
diff --git a/src/script/cpp_api/s_security.cpp b/src/script/cpp_api/s_security.cpp
index e9067a54c..b90b3aa2c 100644
--- a/src/script/cpp_api/s_security.cpp
+++ b/src/script/cpp_api/s_security.cpp
@@ -113,7 +113,6 @@ void ScriptApiSecurity::initializeSecurity()
"setupvalue",
"setmetatable",
"upvalueid",
- "upvaluejoin",
"sethook",
"debug",
"setlocal",
@@ -244,6 +243,7 @@ void ScriptApiSecurity::initializeSecurityClient()
"rawset",
"select",
"setfenv",
+ // getmetatable can be used to escape the sandbox
"setmetatable",
"tonumber",
"tostring",
@@ -265,6 +265,7 @@ void ScriptApiSecurity::initializeSecurityClient()
};
static const char *debug_whitelist[] = {
"getinfo",
+ "traceback"
};
#if USE_LUAJIT
diff --git a/src/script/cpp_api/s_server.cpp b/src/script/cpp_api/s_server.cpp
index 3b461a2a3..1ce2f9d45 100644
--- a/src/script/cpp_api/s_server.cpp
+++ b/src/script/cpp_api/s_server.cpp
@@ -168,3 +168,25 @@ void ScriptApiServer::on_shutdown()
runCallbacks(0, RUN_CALLBACKS_MODE_FIRST);
}
+std::string ScriptApiServer::formatChatMessage(const std::string &name,
+ const std::string &message)
+{
+ SCRIPTAPI_PRECHECKHEADER
+
+ // Push function onto stack
+ lua_getglobal(L, "core");
+ lua_getfield(L, -1, "format_chat_message");
+
+ // Push arguments onto stack
+ lua_pushstring(L, name.c_str());
+ lua_pushstring(L, message.c_str());
+
+ // Actually call the function
+ lua_call(L, 2, 1);
+
+ // Fetch return value
+ std::string ret = lua_tostring(L, -1);
+ lua_pop(L, 1);
+
+ return ret;
+}
diff --git a/src/script/cpp_api/s_server.h b/src/script/cpp_api/s_server.h
index 769939d3f..a4cede84d 100644
--- a/src/script/cpp_api/s_server.h
+++ b/src/script/cpp_api/s_server.h
@@ -36,14 +36,18 @@ public:
// Calls on_shutdown handlers
void on_shutdown();
+ // Calls core.format_chat_message
+ std::string formatChatMessage(const std::string &name,
+ const std::string &message);
+
/* auth */
bool getAuth(const std::string &playername,
- std::string *dst_password,
- std::set<std::string> *dst_privs);
+ std::string *dst_password,
+ std::set<std::string> *dst_privs);
void createAuth(const std::string &playername,
- const std::string &password);
+ const std::string &password);
bool setPassword(const std::string &playername,
- const std::string &password);
+ const std::string &password);
private:
void getAuthHandler();
void readPrivileges(int index, std::set<std::string> &result);
diff --git a/src/script/lua_api/l_areastore.cpp b/src/script/lua_api/l_areastore.cpp
index d53d74aa8..908c766b0 100644
--- a/src/script/lua_api/l_areastore.cpp
+++ b/src/script/lua_api/l_areastore.cpp
@@ -185,6 +185,7 @@ int LuaAreaStore::l_insert_area(lua_State *L)
if (lua_isnumber(L, 5))
a.id = lua_tonumber(L, 5);
+ // Insert & assign a new ID if necessary
if (!ast->insertArea(&a))
return 0;
diff --git a/src/script/lua_api/l_camera.cpp b/src/script/lua_api/l_camera.cpp
index 462006777..80071b3b8 100644
--- a/src/script/lua_api/l_camera.cpp
+++ b/src/script/lua_api/l_camera.cpp
@@ -31,19 +31,24 @@ LuaCamera::LuaCamera(Camera *m) : m_camera(m)
void LuaCamera::create(lua_State *L, Camera *m)
{
+ lua_getglobal(L, "core");
+ luaL_checktype(L, -1, LUA_TTABLE);
+ int objectstable = lua_gettop(L);
+ lua_getfield(L, -1, "camera");
+
+ // Duplication check
+ if (lua_type(L, -1) == LUA_TUSERDATA) {
+ lua_pop(L, 1);
+ return;
+ }
+
LuaCamera *o = new LuaCamera(m);
*(void **)(lua_newuserdata(L, sizeof(void *))) = o;
luaL_getmetatable(L, className);
lua_setmetatable(L, -2);
- int camera_object = lua_gettop(L);
-
- lua_getglobal(L, "core");
- luaL_checktype(L, -1, LUA_TTABLE);
- int coretable = lua_gettop(L);
-
- lua_pushvalue(L, camera_object);
- lua_setfield(L, coretable, "camera");
+ lua_pushvalue(L, lua_gettop(L));
+ lua_setfield(L, objectstable, "camera");
}
int LuaCamera::l_set_camera_mode(lua_State *L)
diff --git a/src/script/lua_api/l_client.cpp b/src/script/lua_api/l_client.cpp
index 6d9d832b7..6345fc75f 100644
--- a/src/script/lua_api/l_client.cpp
+++ b/src/script/lua_api/l_client.cpp
@@ -210,17 +210,13 @@ int ModApiClient::l_get_language(lua_State *L)
int ModApiClient::l_get_wielded_item(lua_State *L)
{
Client *client = getClient(L);
+ LocalPlayer *player = client->getEnv().getLocalPlayer();
+ if (!player)
+ return 0;
- Inventory local_inventory(client->idef());
- client->getLocalInventory(local_inventory);
-
- InventoryList *mlist = local_inventory.getList("main");
-
- if (mlist && client->getPlayerItem() < mlist->getSize()) {
- LuaItemStack::create(L, mlist->getItem(client->getPlayerItem()));
- } else {
- LuaItemStack::create(L, ItemStack());
- }
+ ItemStack selected_item;
+ player->getWieldedItem(&selected_item, nullptr);
+ LuaItemStack::create(L, selected_item);
return 1;
}
diff --git a/src/script/lua_api/l_craft.cpp b/src/script/lua_api/l_craft.cpp
index 0899b945e..18622ee00 100644
--- a/src/script/lua_api/l_craft.cpp
+++ b/src/script/lua_api/l_craft.cpp
@@ -294,7 +294,7 @@ int ModApiCraft::l_clear_craft(lua_State *L)
std::string type = getstringfield_default(L, table, "type", "shaped");
CraftOutput c_output(output, 0);
if (!output.empty()) {
- if (craftdef->clearCraftRecipesByOutput(c_output, getServer(L))) {
+ if (craftdef->clearCraftsByOutput(c_output, getServer(L))) {
lua_pushboolean(L, true);
return 1;
}
@@ -351,7 +351,13 @@ int ModApiCraft::l_clear_craft(lua_State *L)
throw LuaError("Unknown crafting definition type: \"" + type + "\"");
}
- if (!craftdef->clearCraftRecipesByInput(method, width, recipe, getServer(L))) {
+ std::vector<ItemStack> items;
+ items.reserve(recipe.size());
+ for (const auto &item : recipe)
+ items.emplace_back(item, 1, 0, getServer(L)->idef());
+ CraftInput input(method, width, items);
+
+ if (!craftdef->clearCraftsByInput(input, getServer(L))) {
warningstream << "No craft recipe matches input" << std::endl;
lua_pushboolean(L, false);
return 1;
diff --git a/src/script/lua_api/l_env.cpp b/src/script/lua_api/l_env.cpp
index 711bd3fdd..a56b1cb0b 100644
--- a/src/script/lua_api/l_env.cpp
+++ b/src/script/lua_api/l_env.cpp
@@ -350,7 +350,7 @@ int ModApiEnvMod::l_get_node(lua_State *L)
// pos
v3s16 pos = read_v3s16(L, 1);
// Do it
- MapNode n = env->getMap().getNodeNoEx(pos);
+ MapNode n = env->getMap().getNode(pos);
// Return node
pushnode(L, n, env->getGameDef()->ndef());
return 1;
@@ -366,7 +366,7 @@ int ModApiEnvMod::l_get_node_or_nil(lua_State *L)
v3s16 pos = read_v3s16(L, 1);
// Do it
bool pos_ok;
- MapNode n = env->getMap().getNodeNoEx(pos, &pos_ok);
+ MapNode n = env->getMap().getNode(pos, &pos_ok);
if (pos_ok) {
// Return node
pushnode(L, n, env->getGameDef()->ndef());
@@ -392,7 +392,7 @@ int ModApiEnvMod::l_get_node_light(lua_State *L)
u32 dnr = time_to_daynight_ratio(time_of_day, true);
bool is_position_ok;
- MapNode n = env->getMap().getNodeNoEx(pos, &is_position_ok);
+ MapNode n = env->getMap().getNode(pos, &is_position_ok);
if (is_position_ok) {
const NodeDefManager *ndef = env->getGameDef()->ndef();
lua_pushinteger(L, n.getLightBlend(dnr, ndef));
@@ -417,7 +417,7 @@ int ModApiEnvMod::l_place_node(lua_State *L)
MapNode n = readnode(L, 2, ndef);
// Don't attempt to load non-loaded area as of now
- MapNode n_old = env->getMap().getNodeNoEx(pos);
+ MapNode n_old = env->getMap().getNode(pos);
if(n_old.getContent() == CONTENT_IGNORE){
lua_pushboolean(L, false);
return 1;
@@ -446,7 +446,7 @@ int ModApiEnvMod::l_dig_node(lua_State *L)
v3s16 pos = read_v3s16(L, 1);
// Don't attempt to load non-loaded area as of now
- MapNode n = env->getMap().getNodeNoEx(pos);
+ MapNode n = env->getMap().getNode(pos);
if(n.getContent() == CONTENT_IGNORE){
lua_pushboolean(L, false);
return 1;
@@ -469,7 +469,7 @@ int ModApiEnvMod::l_punch_node(lua_State *L)
v3s16 pos = read_v3s16(L, 1);
// Don't attempt to load non-loaded area as of now
- MapNode n = env->getMap().getNodeNoEx(pos);
+ MapNode n = env->getMap().getNode(pos);
if(n.getContent() == CONTENT_IGNORE){
lua_pushboolean(L, false);
return 1;
@@ -491,7 +491,7 @@ int ModApiEnvMod::l_get_node_max_level(lua_State *L)
}
v3s16 pos = read_v3s16(L, 1);
- MapNode n = env->getMap().getNodeNoEx(pos);
+ MapNode n = env->getMap().getNode(pos);
lua_pushnumber(L, n.getMaxLevel(env->getGameDef()->ndef()));
return 1;
}
@@ -506,7 +506,7 @@ int ModApiEnvMod::l_get_node_level(lua_State *L)
}
v3s16 pos = read_v3s16(L, 1);
- MapNode n = env->getMap().getNodeNoEx(pos);
+ MapNode n = env->getMap().getNode(pos);
lua_pushnumber(L, n.getLevel(env->getGameDef()->ndef()));
return 1;
}
@@ -522,7 +522,7 @@ int ModApiEnvMod::l_set_node_level(lua_State *L)
u8 level = 1;
if(lua_isnumber(L, 2))
level = lua_tonumber(L, 2);
- MapNode n = env->getMap().getNodeNoEx(pos);
+ MapNode n = env->getMap().getNode(pos);
lua_pushnumber(L, n.setLevel(env->getGameDef()->ndef(), level));
env->setNode(pos, n);
return 1;
@@ -539,7 +539,7 @@ int ModApiEnvMod::l_add_node_level(lua_State *L)
u8 level = 1;
if(lua_isnumber(L, 2))
level = lua_tonumber(L, 2);
- MapNode n = env->getMap().getNodeNoEx(pos);
+ MapNode n = env->getMap().getNode(pos);
lua_pushnumber(L, n.addLevel(env->getGameDef()->ndef(), level));
env->setNode(pos, n);
return 1;
@@ -780,7 +780,7 @@ int ModApiEnvMod::l_find_node_near(lua_State *L)
std::vector<v3s16> list = FacePositionCache::getFacePositions(d);
for (const v3s16 &i : list) {
v3s16 p = pos + i;
- content_t c = env->getMap().getNodeNoEx(p).getContent();
+ content_t c = env->getMap().getNode(p).getContent();
if (CONTAINS(filter, c)) {
push_v3s16(L, p);
return 1;
@@ -832,7 +832,7 @@ int ModApiEnvMod::l_find_nodes_in_area(lua_State *L)
for (s16 y = minp.Y; y <= maxp.Y; y++)
for (s16 z = minp.Z; z <= maxp.Z; z++) {
v3s16 p(x, y, z);
- content_t c = env->getMap().getNodeNoEx(p).getContent();
+ content_t c = env->getMap().getNode(p).getContent();
std::vector<content_t>::iterator it = std::find(filter.begin(), filter.end(), c);
if (it != filter.end()) {
@@ -898,10 +898,10 @@ int ModApiEnvMod::l_find_nodes_in_area_under_air(lua_State *L)
for (s16 z = minp.Z; z <= maxp.Z; z++) {
s16 y = minp.Y;
v3s16 p(x, y, z);
- content_t c = env->getMap().getNodeNoEx(p).getContent();
+ content_t c = env->getMap().getNode(p).getContent();
for (; y <= maxp.Y; y++) {
v3s16 psurf(x, y + 1, z);
- content_t csurf = env->getMap().getNodeNoEx(psurf).getContent();
+ content_t csurf = env->getMap().getNode(psurf).getContent();
if (c != CONTENT_AIR && csurf == CONTENT_AIR &&
CONTAINS(filter, c)) {
push_v3s16(L, v3s16(x, y, z));
@@ -1035,7 +1035,7 @@ int ModApiEnvMod::l_fix_light(lua_State *L)
for (auto &modified_block : modified_blocks)
event.modified_blocks.insert(modified_block.first);
- map.dispatchEvent(&event);
+ map.dispatchEvent(event);
}
lua_pushboolean(L, success);
@@ -1144,7 +1144,7 @@ int ModApiEnvMod::l_delete_area(lua_State *L)
}
}
- map.dispatchEvent(&event);
+ map.dispatchEvent(event);
lua_pushboolean(L, success);
return 1;
}
diff --git a/src/script/lua_api/l_http.cpp b/src/script/lua_api/l_http.cpp
index ac261cd60..2ff651cb5 100644
--- a/src/script/lua_api/l_http.cpp
+++ b/src/script/lua_api/l_http.cpp
@@ -53,9 +53,8 @@ void ModApiHttp::read_http_fetch_request(lua_State *L, HTTPFetchRequest &req)
lua_getfield(L, 1, "post_data");
if (lua_istable(L, 2)) {
lua_pushnil(L);
- while (lua_next(L, 2) != 0)
- {
- req.post_fields[luaL_checkstring(L, -2)] = luaL_checkstring(L, -1);
+ while (lua_next(L, 2) != 0) {
+ req.post_fields[readParam<std::string>(L, -2)] = readParam<std::string>(L, -1);
lua_pop(L, 1);
}
} else if (lua_isstring(L, 2)) {
@@ -66,10 +65,8 @@ void ModApiHttp::read_http_fetch_request(lua_State *L, HTTPFetchRequest &req)
lua_getfield(L, 1, "extra_headers");
if (lua_istable(L, 2)) {
lua_pushnil(L);
- while (lua_next(L, 2) != 0)
- {
- const char *header = luaL_checkstring(L, -1);
- req.extra_headers.emplace_back(header);
+ while (lua_next(L, 2) != 0) {
+ req.extra_headers.emplace_back(readParam<std::string>(L, -1));
lua_pop(L, 1);
}
}
@@ -83,7 +80,7 @@ void ModApiHttp::push_http_fetch_result(lua_State *L, HTTPFetchResult &res, bool
setboolfield(L, -1, "timeout", res.timeout);
setboolfield(L, -1, "completed", completed);
setintfield(L, -1, "code", res.response_code);
- setstringfield(L, -1, "data", res.data.c_str());
+ setstringfield(L, -1, "data", res.data);
}
// http_api.fetch_async(HTTPRequest definition)
@@ -94,7 +91,7 @@ int ModApiHttp::l_http_fetch_async(lua_State *L)
HTTPFetchRequest req;
read_http_fetch_request(L, req);
- actionstream << "Mod performs HTTP request with URL " << req.url << std::endl;
+ infostream << "Mod performs HTTP request with URL " << req.url << std::endl;
httpfetch_async(req);
// Convert handle to hex string since lua can't handle 64-bit integers
diff --git a/src/script/lua_api/l_item.cpp b/src/script/lua_api/l_item.cpp
index e41d23fd1..f9708b560 100644
--- a/src/script/lua_api/l_item.cpp
+++ b/src/script/lua_api/l_item.cpp
@@ -175,6 +175,16 @@ int LuaItemStack::l_set_metadata(lua_State *L)
return 1;
}
+// get_description(self)
+int LuaItemStack::l_get_description(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+ LuaItemStack *o = checkobject(L, 1);
+ std::string desc = o->m_stack.getDescription(getGameDef(L)->idef());
+ lua_pushstring(L, desc.c_str());
+ return 1;
+}
+
// clear(self) -> true
int LuaItemStack::l_clear(lua_State *L)
{
@@ -470,6 +480,7 @@ const luaL_Reg LuaItemStack::methods[] = {
luamethod(LuaItemStack, get_meta),
luamethod(LuaItemStack, get_metadata),
luamethod(LuaItemStack, set_metadata),
+ luamethod(LuaItemStack, get_description),
luamethod(LuaItemStack, clear),
luamethod(LuaItemStack, replace),
luamethod(LuaItemStack, to_string),
diff --git a/src/script/lua_api/l_item.h b/src/script/lua_api/l_item.h
index 5ff715b2a..6fab58045 100644
--- a/src/script/lua_api/l_item.h
+++ b/src/script/lua_api/l_item.h
@@ -66,6 +66,9 @@ private:
// set_metadata(self, string)
static int l_set_metadata(lua_State *L);
+ // get_description(self)
+ static int l_get_description(lua_State *L);
+
// clear(self) -> true
static int l_clear(lua_State *L);
diff --git a/src/script/lua_api/l_localplayer.cpp b/src/script/lua_api/l_localplayer.cpp
index 7444d0e88..3e14e48e4 100644
--- a/src/script/lua_api/l_localplayer.cpp
+++ b/src/script/lua_api/l_localplayer.cpp
@@ -30,20 +30,24 @@ LuaLocalPlayer::LuaLocalPlayer(LocalPlayer *m) : m_localplayer(m)
void LuaLocalPlayer::create(lua_State *L, LocalPlayer *m)
{
+ lua_getglobal(L, "core");
+ luaL_checktype(L, -1, LUA_TTABLE);
+ int objectstable = lua_gettop(L);
+ lua_getfield(L, -1, "localplayer");
+
+ // Duplication check
+ if (lua_type(L, -1) == LUA_TUSERDATA) {
+ lua_pop(L, 1);
+ return;
+ }
+
LuaLocalPlayer *o = new LuaLocalPlayer(m);
*(void **)(lua_newuserdata(L, sizeof(void *))) = o;
luaL_getmetatable(L, className);
lua_setmetatable(L, -2);
- // Keep localplayer object stack id
- int localplayer_object = lua_gettop(L);
-
- lua_getglobal(L, "core");
- luaL_checktype(L, -1, LUA_TTABLE);
- int coretable = lua_gettop(L);
-
- lua_pushvalue(L, localplayer_object);
- lua_setfield(L, coretable, "localplayer");
+ lua_pushvalue(L, lua_gettop(L));
+ lua_setfield(L, objectstable, "localplayer");
}
int LuaLocalPlayer::l_get_velocity(lua_State *L)
diff --git a/src/script/lua_api/l_mainmenu.cpp b/src/script/lua_api/l_mainmenu.cpp
index 2557f448a..76db7ed13 100644
--- a/src/script/lua_api/l_mainmenu.cpp
+++ b/src/script/lua_api/l_mainmenu.cpp
@@ -107,6 +107,21 @@ int ModApiMainMenu::l_update_formspec(lua_State *L)
}
/******************************************************************************/
+int ModApiMainMenu::l_set_formspec_prepend(lua_State *L)
+{
+ GUIEngine *engine = getGuiEngine(L);
+ sanity_check(engine != NULL);
+
+ if (engine->m_startgame)
+ return 0;
+
+ std::string formspec(luaL_checkstring(L, 1));
+ engine->setFormspecPrepend(formspec);
+
+ return 0;
+}
+
+/******************************************************************************/
int ModApiMainMenu::l_start(lua_State *L)
{
GUIEngine* engine = getGuiEngine(L);
@@ -867,6 +882,16 @@ bool ModApiMainMenu::mayModifyPath(const std::string &path)
return false;
}
+
+/******************************************************************************/
+int ModApiMainMenu::l_may_modify_path(lua_State *L)
+{
+ const char *target = luaL_checkstring(L, 1);
+ std::string absolute_destination = fs::RemoveRelativePathComponents(target);
+ lua_pushboolean(L, ModApiMainMenu::mayModifyPath(absolute_destination));
+ return 1;
+}
+
/******************************************************************************/
int ModApiMainMenu::l_show_path_select_dialog(lua_State *L)
{
@@ -1031,6 +1056,7 @@ int ModApiMainMenu::l_do_async_callback(lua_State *L)
void ModApiMainMenu::Initialize(lua_State *L, int top)
{
API_FCT(update_formspec);
+ API_FCT(set_formspec_prepend);
API_FCT(set_clouds);
API_FCT(get_textlist_index);
API_FCT(get_table_index);
@@ -1057,6 +1083,7 @@ void ModApiMainMenu::Initialize(lua_State *L, int top)
API_FCT(delete_dir);
API_FCT(copy_dir);
API_FCT(extract_zip);
+ API_FCT(may_modify_path);
API_FCT(get_mainmenu_path);
API_FCT(show_path_select_dialog);
API_FCT(download_file);
@@ -1086,6 +1113,7 @@ void ModApiMainMenu::InitializeAsync(lua_State *L, int top)
API_FCT(delete_dir);
API_FCT(copy_dir);
//API_FCT(extract_zip); //TODO remove dependency to GuiEngine
+ API_FCT(may_modify_path);
API_FCT(download_file);
//API_FCT(gettext); (gettext lib isn't threadsafe)
}
diff --git a/src/script/lua_api/l_mainmenu.h b/src/script/lua_api/l_mainmenu.h
index 4a664359a..b2ca49320 100644
--- a/src/script/lua_api/l_mainmenu.h
+++ b/src/script/lua_api/l_mainmenu.h
@@ -104,6 +104,8 @@ private:
static int l_update_formspec(lua_State *L);
+ static int l_set_formspec_prepend(lua_State *L);
+
static int l_get_screen_info(lua_State *L);
//filesystem
@@ -130,6 +132,8 @@ private:
static int l_extract_zip(lua_State *L);
+ static int l_may_modify_path(lua_State *L);
+
static int l_download_file(lua_State *L);
static int l_get_video_drivers(lua_State *L);
diff --git a/src/script/lua_api/l_mapgen.cpp b/src/script/lua_api/l_mapgen.cpp
index 92ed4377e..2e0cba8dd 100644
--- a/src/script/lua_api/l_mapgen.cpp
+++ b/src/script/lua_api/l_mapgen.cpp
@@ -405,7 +405,16 @@ Biome *read_biome_def(lua_State *L, int index, const NodeDefManager *ndef)
nn.push_back(getstringfield_default(L, index, "node_river_water", ""));
nn.push_back(getstringfield_default(L, index, "node_riverbed", ""));
nn.push_back(getstringfield_default(L, index, "node_dust", ""));
- nn.push_back(getstringfield_default(L, index, "node_cave_liquid", ""));
+
+ size_t nnames = getstringlistfield(L, index, "node_cave_liquid", &nn);
+ // If no cave liquids defined, set list to "ignore" to trigger old hardcoded
+ // cave liquid behaviour.
+ if (nnames == 0) {
+ nn.emplace_back("ignore");
+ nnames = 1;
+ }
+ b->m_nnlistsizes.push_back(nnames);
+
nn.push_back(getstringfield_default(L, index, "node_dungeon", ""));
nn.push_back(getstringfield_default(L, index, "node_dungeon_alt", ""));
nn.push_back(getstringfield_default(L, index, "node_dungeon_stair", ""));
@@ -1745,6 +1754,83 @@ int ModApiMapgen::l_serialize_schematic(lua_State *L)
return 1;
}
+// read_schematic(schematic, options={...})
+int ModApiMapgen::l_read_schematic(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+
+ SchematicManager *schemmgr = getServer(L)->getEmergeManager()->schemmgr;
+
+ //// Read options
+ std::string write_yslice = getstringfield_default(L, 2, "write_yslice_prob", "all");
+
+ //// Get schematic
+ bool was_loaded = false;
+ Schematic *schem = (Schematic *)get_objdef(L, 1, schemmgr);
+ if (!schem) {
+ schem = load_schematic(L, 1, NULL, NULL);
+ was_loaded = true;
+ }
+ if (!schem) {
+ errorstream << "read_schematic: failed to get schematic" << std::endl;
+ return 0;
+ }
+ lua_pop(L, 2);
+
+ //// Create the Lua table
+ u32 numnodes = schem->size.X * schem->size.Y * schem->size.Z;
+ const std::vector<std::string> &names = schem->m_nodenames;
+
+ lua_createtable(L, 0, (write_yslice == "none") ? 2 : 3);
+
+ // Create the size field
+ push_v3s16(L, schem->size);
+ lua_setfield(L, 1, "size");
+
+ // Create the yslice_prob field
+ if (write_yslice != "none") {
+ lua_createtable(L, schem->size.Y, 0);
+ for (u16 y = 0; y != schem->size.Y; ++y) {
+ u8 probability = schem->slice_probs[y] & MTSCHEM_PROB_MASK;
+ if (probability < MTSCHEM_PROB_ALWAYS || write_yslice != "low") {
+ lua_createtable(L, 0, 2);
+ lua_pushinteger(L, y);
+ lua_setfield(L, 3, "ypos");
+ lua_pushinteger(L, probability * 2);
+ lua_setfield(L, 3, "prob");
+ lua_rawseti(L, 2, y + 1);
+ }
+ }
+ lua_setfield(L, 1, "yslice_prob");
+ }
+
+ // Create the data field
+ lua_createtable(L, numnodes, 0); // data table
+ for (u32 i = 0; i < numnodes; ++i) {
+ MapNode node = schem->schemdata[i];
+ u8 probability = node.param1 & MTSCHEM_PROB_MASK;
+ bool force_place = node.param1 & MTSCHEM_FORCE_PLACE;
+ lua_createtable(L, 0, force_place ? 4 : 3);
+ lua_pushstring(L, names[schem->schemdata[i].getContent()].c_str());
+ lua_setfield(L, 3, "name");
+ lua_pushinteger(L, probability * 2);
+ lua_setfield(L, 3, "prob");
+ lua_pushinteger(L, node.param2);
+ lua_setfield(L, 3, "param2");
+ if (force_place) {
+ lua_pushboolean(L, 1);
+ lua_setfield(L, 3, "force_place");
+ }
+ lua_rawseti(L, 2, i + 1);
+ }
+ lua_setfield(L, 1, "data");
+
+ if (was_loaded)
+ delete schem;
+
+ return 1;
+}
+
void ModApiMapgen::Initialize(lua_State *L, int top)
{
@@ -1784,4 +1870,5 @@ void ModApiMapgen::Initialize(lua_State *L, int top)
API_FCT(place_schematic);
API_FCT(place_schematic_on_vmanip);
API_FCT(serialize_schematic);
+ API_FCT(read_schematic);
}
diff --git a/src/script/lua_api/l_mapgen.h b/src/script/lua_api/l_mapgen.h
index 1339791f3..4a6a9ccf4 100644
--- a/src/script/lua_api/l_mapgen.h
+++ b/src/script/lua_api/l_mapgen.h
@@ -131,6 +131,9 @@ private:
// serialize_schematic(schematic, format, options={...})
static int l_serialize_schematic(lua_State *L);
+ // read_schematic(schematic, options={...})
+ static int l_read_schematic(lua_State *L);
+
public:
static void Initialize(lua_State *L, int top);
diff --git a/src/script/lua_api/l_nodemeta.cpp b/src/script/lua_api/l_nodemeta.cpp
index 22fc61782..229ce73db 100644
--- a/src/script/lua_api/l_nodemeta.cpp
+++ b/src/script/lua_api/l_nodemeta.cpp
@@ -68,7 +68,7 @@ void NodeMetaRef::reportMetadataChange(const std::string *name)
event.type = MEET_BLOCK_NODE_METADATA_CHANGED;
event.p = m_p;
event.is_private_change = name && meta && meta->isPrivate(*name);
- m_env->getMap().dispatchEvent(&event);
+ m_env->getMap().dispatchEvent(event);
}
// Exported functions
diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp
index b3ed39c7c..efdb345c9 100644
--- a/src/script/lua_api/l_object.cpp
+++ b/src/script/lua_api/l_object.cpp
@@ -170,8 +170,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();
@@ -187,12 +187,14 @@ int ObjectRef::l_punch(lua_State *L)
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, PlayerHPChangeReason(PlayerHPChangeReason::PLAYER_PUNCH, puncher));
+ getServer(L)->SendPlayerHPOrDie((PlayerSAO *)co,
+ PlayerHPChangeReason(PlayerHPChangeReason::PLAYER_PUNCH, puncher));
}
// If the puncher is a player, and its HP changed
@@ -201,7 +203,7 @@ int ObjectRef::l_punch(lua_State *L)
getServer(L)->SendPlayerHPOrDie((PlayerSAO *)puncher,
PlayerHPChangeReason(PlayerHPChangeReason::PLAYER_PUNCH, co));
}
- return 0;
+ return 1;
}
// right_click(self, clicker); clicker = an another ObjectRef
@@ -307,8 +309,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;
}
@@ -319,8 +322,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;
}
@@ -331,13 +335,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;
}
@@ -352,7 +358,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;
@@ -583,6 +589,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)
{
@@ -731,17 +755,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()) {
- PlayerHPChangeReason reason(PlayerHPChangeReason::SET_HP);
- co->setHP(prop->hp_max, reason);
- if (co->getType() == ACTIVEOBJECT_TYPE_PLAYER)
- getServer(L)->SendPlayerHPOrDie((PlayerSAO *)co, reason);
- }
+
+ read_object_properties(L, 2, co, prop, getServer(L)->idef());
co->notifyObjectPropertiesModified();
return 0;
}
@@ -1074,6 +1095,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)
{
@@ -1210,6 +1252,37 @@ int ObjectRef::l_set_look_yaw(lua_State *L)
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<f32>(luaL_checknumber(L, 2)), readParam<bool>(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)
{
@@ -1239,6 +1312,9 @@ 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)
@@ -1257,6 +1333,9 @@ 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)
@@ -1907,6 +1986,7 @@ 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),
@@ -1916,6 +1996,8 @@ 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),
@@ -1951,5 +2033,6 @@ 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}
};
diff --git a/src/script/lua_api/l_object.h b/src/script/lua_api/l_object.h
index c7d963d87..e817e1d33 100644
--- a/src/script/lua_api/l_object.h
+++ b/src/script/lua_api/l_object.h
@@ -212,6 +212,12 @@ private:
// get_player_velocity(self)
static int l_get_player_velocity(lua_State *L);
+ // add_player_velocity(self, {x=num, y=num, z=num})
+ static int l_add_player_velocity(lua_State *L);
+
+ // get_fov(self)
+ static int l_get_fov(lua_State *L);
+
// get_look_dir(self)
static int l_get_look_dir(lua_State *L);
@@ -229,6 +235,9 @@ private:
// get_look_yaw2(self)
static int l_get_look_horizontal(lua_State *L);
+ // set_fov(self, degrees, is_multiplier)
+ static int l_set_fov(lua_State *L);
+
// set_look_vertical(self, radians)
static int l_set_look_vertical(lua_State *L);
@@ -351,4 +360,6 @@ private:
// get_nametag_attributes(self)
static int l_get_nametag_attributes(lua_State *L);
+ // send_mapblock(pos)
+ static int l_send_mapblock(lua_State *L);
};
diff --git a/src/script/lua_api/l_server.cpp b/src/script/lua_api/l_server.cpp
index 6017a5475..7c083e652 100644
--- a/src/script/lua_api/l_server.cpp
+++ b/src/script/lua_api/l_server.cpp
@@ -233,6 +233,10 @@ int ModApiServer::l_get_player_information(lua_State *L)
lua_pushnumber(L, prot_vers);
lua_settable(L, table);
+ lua_pushstring(L, "formspec_version");
+ lua_pushnumber(L, player->formspec_version);
+ lua_settable(L, table);
+
#ifndef NDEBUG
lua_pushstring(L,"serialization_version");
lua_pushnumber(L, ser_vers);
diff --git a/src/script/lua_api/l_vmanip.cpp b/src/script/lua_api/l_vmanip.cpp
index c92983bd3..fd73d21d1 100644
--- a/src/script/lua_api/l_vmanip.cpp
+++ b/src/script/lua_api/l_vmanip.cpp
@@ -126,7 +126,7 @@ int LuaVoxelManip::l_write_to_map(lua_State *L)
for (const auto &modified_block : o->modified_blocks)
event.modified_blocks.insert(modified_block.first);
- map->dispatchEvent(&event);
+ map->dispatchEvent(event);
o->modified_blocks.clear();
return 0;
diff --git a/src/script/scripting_client.cpp b/src/script/scripting_client.cpp
index 86e5f2874..c3e0ca373 100644
--- a/src/script/scripting_client.cpp
+++ b/src/script/scripting_client.cpp
@@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "lua_api/l_client.h"
#include "lua_api/l_env.h"
#include "lua_api/l_item.h"
+#include "lua_api/l_itemstackmeta.h"
#include "lua_api/l_minimap.h"
#include "lua_api/l_modchannels.h"
#include "lua_api/l_particles_local.h"
@@ -67,6 +68,7 @@ ClientScripting::ClientScripting(Client *client):
void ClientScripting::InitializeModApi(lua_State *L, int top)
{
LuaItemStack::Register(L);
+ ItemStackMetaRef::Register(L);
StorageRef::Register(L);
LuaMinimap::Register(L);
NodeMetaRef::RegisterClient(L);
@@ -84,8 +86,7 @@ void ClientScripting::InitializeModApi(lua_State *L, int top)
void ClientScripting::on_client_ready(LocalPlayer *localplayer)
{
- lua_State *L = getStack();
- LuaLocalPlayer::create(L, localplayer);
+ LuaLocalPlayer::create(getStack(), localplayer);
}
void ClientScripting::on_camera_ready(Camera *camera)