aboutsummaryrefslogtreecommitdiff
path: root/src/script/lua_api
diff options
context:
space:
mode:
Diffstat (limited to 'src/script/lua_api')
-rw-r--r--src/script/lua_api/l_areastore.cpp49
-rw-r--r--src/script/lua_api/l_client.cpp26
-rw-r--r--src/script/lua_api/l_craft.cpp32
-rw-r--r--src/script/lua_api/l_craft.h1
-rw-r--r--src/script/lua_api/l_env.cpp11
-rw-r--r--src/script/lua_api/l_env.h2
-rw-r--r--src/script/lua_api/l_internal.h2
-rw-r--r--src/script/lua_api/l_inventory.cpp23
-rw-r--r--src/script/lua_api/l_item.cpp56
-rw-r--r--src/script/lua_api/l_item.h18
-rw-r--r--src/script/lua_api/l_mainmenu.cpp142
-rw-r--r--src/script/lua_api/l_mainmenu.h4
-rw-r--r--src/script/lua_api/l_nodemeta.cpp27
-rw-r--r--src/script/lua_api/l_nodemeta.h6
-rw-r--r--src/script/lua_api/l_noise.cpp67
-rw-r--r--src/script/lua_api/l_noise.h17
-rw-r--r--src/script/lua_api/l_object.cpp214
-rw-r--r--src/script/lua_api/l_object.h12
-rw-r--r--src/script/lua_api/l_particleparams.h282
-rw-r--r--src/script/lua_api/l_particles.cpp214
-rw-r--r--src/script/lua_api/l_particles_local.cpp114
-rw-r--r--src/script/lua_api/l_server.cpp131
-rw-r--r--src/script/lua_api/l_server.h10
-rw-r--r--src/script/lua_api/l_settings.cpp21
-rw-r--r--src/script/lua_api/l_sound.cpp4
-rw-r--r--src/script/lua_api/l_storage.cpp8
-rw-r--r--src/script/lua_api/l_util.cpp22
-rw-r--r--src/script/lua_api/l_util.h5
-rw-r--r--src/script/lua_api/l_vmanip.cpp51
-rw-r--r--src/script/lua_api/l_vmanip.h5
30 files changed, 1228 insertions, 348 deletions
diff --git a/src/script/lua_api/l_areastore.cpp b/src/script/lua_api/l_areastore.cpp
index 45724e604..ec2656c4a 100644
--- a/src/script/lua_api/l_areastore.cpp
+++ b/src/script/lua_api/l_areastore.cpp
@@ -27,26 +27,26 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "filesys.h"
#include <fstream>
-static inline void get_data_and_border_flags(lua_State *L, u8 start_i,
- bool *borders, bool *data)
+static inline void get_data_and_corner_flags(lua_State *L, u8 start_i,
+ bool *corners, bool *data)
{
if (!lua_isboolean(L, start_i))
return;
- *borders = lua_toboolean(L, start_i);
+ *corners = lua_toboolean(L, start_i);
if (!lua_isboolean(L, start_i + 1))
return;
*data = lua_toboolean(L, start_i + 1);
}
static void push_area(lua_State *L, const Area *a,
- bool include_borders, bool include_data)
+ bool include_corners, bool include_data)
{
- if (!include_borders && !include_data) {
+ if (!include_corners && !include_data) {
lua_pushboolean(L, true);
return;
}
lua_newtable(L);
- if (include_borders) {
+ if (include_corners) {
push_v3s16(L, a->minedge);
lua_setfield(L, -2, "min");
push_v3s16(L, a->maxedge);
@@ -59,13 +59,13 @@ static void push_area(lua_State *L, const Area *a,
}
static inline void push_areas(lua_State *L, const std::vector<Area *> &areas,
- bool borders, bool data)
+ bool corners, bool data)
{
lua_newtable(L);
size_t cnt = areas.size();
for (size_t i = 0; i < cnt; i++) {
lua_pushnumber(L, areas[i]->id);
- push_area(L, areas[i], borders, data);
+ push_area(L, areas[i], corners, data);
lua_settable(L, -3);
}
}
@@ -94,7 +94,7 @@ int LuaAreaStore::gc_object(lua_State *L)
return 0;
}
-// get_area(id, include_borders, include_data)
+// get_area(id, include_corners, include_data)
int LuaAreaStore::l_get_area(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
@@ -104,9 +104,9 @@ int LuaAreaStore::l_get_area(lua_State *L)
u32 id = luaL_checknumber(L, 2);
- bool include_borders = true;
+ bool include_corners = true;
bool include_data = false;
- get_data_and_border_flags(L, 3, &include_borders, &include_data);
+ get_data_and_corner_flags(L, 3, &include_corners, &include_data);
const Area *res;
@@ -114,12 +114,12 @@ int LuaAreaStore::l_get_area(lua_State *L)
if (!res)
return 0;
- push_area(L, res, include_borders, include_data);
+ push_area(L, res, include_corners, include_data);
return 1;
}
-// get_areas_for_pos(pos, include_borders, include_data)
+// get_areas_for_pos(pos, include_corners, include_data)
int LuaAreaStore::l_get_areas_for_pos(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
@@ -129,19 +129,19 @@ int LuaAreaStore::l_get_areas_for_pos(lua_State *L)
v3s16 pos = check_v3s16(L, 2);
- bool include_borders = true;
+ bool include_corners = true;
bool include_data = false;
- get_data_and_border_flags(L, 3, &include_borders, &include_data);
+ get_data_and_corner_flags(L, 3, &include_corners, &include_data);
std::vector<Area *> res;
ast->getAreasForPos(&res, pos);
- push_areas(L, res, include_borders, include_data);
+ push_areas(L, res, include_corners, include_data);
return 1;
}
-// get_areas_in_area(edge1, edge2, accept_overlap, include_borders, include_data)
+// get_areas_in_area(corner1, corner2, accept_overlap, include_corners, include_data)
int LuaAreaStore::l_get_areas_in_area(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
@@ -149,25 +149,26 @@ int LuaAreaStore::l_get_areas_in_area(lua_State *L)
LuaAreaStore *o = checkobject(L, 1);
AreaStore *ast = o->as;
- v3s16 minedge = check_v3s16(L, 2);
- v3s16 maxedge = check_v3s16(L, 3);
+ v3s16 minp = check_v3s16(L, 2);
+ v3s16 maxp = check_v3s16(L, 3);
+ sortBoxVerticies(minp, maxp);
- bool include_borders = true;
+ bool include_corners = true;
bool include_data = false;
bool accept_overlap = false;
if (lua_isboolean(L, 4)) {
accept_overlap = readParam<bool>(L, 4);
- get_data_and_border_flags(L, 5, &include_borders, &include_data);
+ get_data_and_corner_flags(L, 5, &include_corners, &include_data);
}
std::vector<Area *> res;
- ast->getAreasInArea(&res, minedge, maxedge, accept_overlap);
- push_areas(L, res, include_borders, include_data);
+ ast->getAreasInArea(&res, minp, maxp, accept_overlap);
+ push_areas(L, res, include_corners, include_data);
return 1;
}
-// insert_area(edge1, edge2, data, id)
+// insert_area(corner1, corner2, data, id)
int LuaAreaStore::l_insert_area(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
diff --git a/src/script/lua_api/l_client.cpp b/src/script/lua_api/l_client.cpp
index aaced7cd0..05ac53cbb 100644
--- a/src/script/lua_api/l_client.cpp
+++ b/src/script/lua_api/l_client.cpp
@@ -268,30 +268,32 @@ int ModApiClient::l_sound_play(lua_State *L)
SimpleSoundSpec spec;
read_soundspec(L, 1, spec);
+ SoundLocation type = SoundLocation::Local;
float gain = 1.0f;
- float pitch = 1.0f;
- bool looped = false;
- s32 handle;
+ v3f position;
if (lua_istable(L, 2)) {
getfloatfield(L, 2, "gain", gain);
- getfloatfield(L, 2, "pitch", pitch);
- getboolfield(L, 2, "loop", looped);
+ getfloatfield(L, 2, "pitch", spec.pitch);
+ getboolfield(L, 2, "loop", spec.loop);
lua_getfield(L, 2, "pos");
if (!lua_isnil(L, -1)) {
- v3f pos = read_v3f(L, -1) * BS;
+ position = read_v3f(L, -1) * BS;
+ type = SoundLocation::Position;
lua_pop(L, 1);
- handle = sound->playSoundAt(
- spec.name, looped, gain * spec.gain, pos, pitch);
- lua_pushinteger(L, handle);
- return 1;
}
}
- handle = sound->playSound(spec.name, looped, gain * spec.gain, spec.fade, pitch);
- lua_pushinteger(L, handle);
+ spec.gain *= gain;
+ s32 handle;
+ if (type == SoundLocation::Local)
+ handle = sound->playSound(spec);
+ else
+ handle = sound->playSoundAt(spec, position);
+
+ lua_pushinteger(L, handle);
return 1;
}
diff --git a/src/script/lua_api/l_craft.cpp b/src/script/lua_api/l_craft.cpp
index 18622ee00..137b210be 100644
--- a/src/script/lua_api/l_craft.cpp
+++ b/src/script/lua_api/l_craft.cpp
@@ -371,8 +371,9 @@ int ModApiCraft::l_clear_craft(lua_State *L)
int ModApiCraft::l_get_craft_result(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
+ IGameDef *gdef = getGameDef(L);
- int input_i = 1;
+ const int input_i = 1;
std::string method_s = getstringfield_default(L, input_i, "method", "normal");
enum CraftMethod method = (CraftMethod)getenumfield(L, input_i, "method",
es_CraftMethod, CRAFT_METHOD_NORMAL);
@@ -382,10 +383,9 @@ int ModApiCraft::l_get_craft_result(lua_State *L)
width = luaL_checkinteger(L, -1);
lua_pop(L, 1);
lua_getfield(L, input_i, "items");
- std::vector<ItemStack> items = read_items(L, -1,getServer(L));
+ std::vector<ItemStack> items = read_items(L, -1, gdef);
lua_pop(L, 1); // items
- IGameDef *gdef = getServer(L);
ICraftDefManager *cdef = gdef->cdef();
CraftInput input(method, width, items);
CraftOutput output;
@@ -465,13 +465,13 @@ static void push_craft_recipes(lua_State *L, IGameDef *gdef,
const std::vector<CraftDefinition*> &recipes,
const CraftOutput &output)
{
- lua_createtable(L, recipes.size(), 0);
-
if (recipes.empty()) {
lua_pushnil(L);
return;
}
+ lua_createtable(L, recipes.size(), 0);
+
std::vector<CraftDefinition*>::const_iterator it = recipes.begin();
for (unsigned i = 0; it != recipes.end(); ++it) {
lua_newtable(L);
@@ -487,10 +487,9 @@ int ModApiCraft::l_get_craft_recipe(lua_State *L)
NO_MAP_LOCK_REQUIRED;
std::string item = luaL_checkstring(L, 1);
- Server *server = getServer(L);
+ IGameDef *gdef = getGameDef(L);
CraftOutput output(item, 0);
- std::vector<CraftDefinition*> recipes = server->cdef()
- ->getCraftRecipes(output, server, 1);
+ auto recipes = gdef->cdef()->getCraftRecipes(output, gdef, 1);
lua_createtable(L, 1, 0);
@@ -500,7 +499,7 @@ int ModApiCraft::l_get_craft_recipe(lua_State *L)
setintfield(L, -1, "width", 0);
return 1;
}
- push_craft_recipe(L, server, recipes[0], output);
+ push_craft_recipe(L, gdef, recipes[0], output);
return 1;
}
@@ -510,12 +509,11 @@ int ModApiCraft::l_get_all_craft_recipes(lua_State *L)
NO_MAP_LOCK_REQUIRED;
std::string item = luaL_checkstring(L, 1);
- Server *server = getServer(L);
+ IGameDef *gdef = getGameDef(L);
CraftOutput output(item, 0);
- std::vector<CraftDefinition*> recipes = server->cdef()
- ->getCraftRecipes(output, server);
+ auto recipes = gdef->cdef()->getCraftRecipes(output, gdef);
- push_craft_recipes(L, server, recipes, output);
+ push_craft_recipes(L, gdef, recipes, output);
return 1;
}
@@ -527,3 +525,11 @@ void ModApiCraft::Initialize(lua_State *L, int top)
API_FCT(register_craft);
API_FCT(clear_craft);
}
+
+void ModApiCraft::InitializeAsync(lua_State *L, int top)
+{
+ // all read-only functions
+ API_FCT(get_all_craft_recipes);
+ API_FCT(get_craft_recipe);
+ API_FCT(get_craft_result);
+}
diff --git a/src/script/lua_api/l_craft.h b/src/script/lua_api/l_craft.h
index 9002b23ef..5234af56f 100644
--- a/src/script/lua_api/l_craft.h
+++ b/src/script/lua_api/l_craft.h
@@ -45,4 +45,5 @@ private:
public:
static void Initialize(lua_State *L, int top);
+ static void InitializeAsync(lua_State *L, int top);
};
diff --git a/src/script/lua_api/l_env.cpp b/src/script/lua_api/l_env.cpp
index 18ee3a521..b26c89e7d 100644
--- a/src/script/lua_api/l_env.cpp
+++ b/src/script/lua_api/l_env.cpp
@@ -640,7 +640,7 @@ int ModApiEnvMod::l_add_entity(lua_State *L)
v3f pos = checkFloatPos(L, 1);
const char *name = luaL_checkstring(L, 2);
- const char *staticdata = luaL_optstring(L, 3, "");
+ std::string staticdata = readParam<std::string>(L, 3, "");
ServerActiveObject *obj = new LuaEntitySAO(env, pos, name, staticdata);
int objectid = env->addActiveObject(obj);
@@ -757,7 +757,7 @@ int ModApiEnvMod::l_get_objects_in_area(lua_State *L)
{
GET_ENV_PTR;
ScriptApiBase *script = getScriptApiBase(L);
-
+
v3f minp = read_v3f(L, 1) * BS;
v3f maxp = read_v3f(L, 2) * BS;
aabb3f box(minp, maxp);
@@ -1219,7 +1219,8 @@ int ModApiEnvMod::l_emerge_area(lua_State *L)
sortBoxVerticies(bpmin, bpmax);
size_t num_blocks = VoxelArea(bpmin, bpmax).getVolume();
- assert(num_blocks != 0);
+ if (num_blocks == 0)
+ return 0;
if (lua_isfunction(L, 3)) {
callback = LuaEmergeAreaCallback;
@@ -1386,7 +1387,7 @@ int ModApiEnvMod::l_transforming_liquid_add(lua_State *L)
GET_ENV_PTR;
v3s16 p0 = read_v3s16(L, 1);
- env->getMap().transforming_liquid_add(p0);
+ env->getServerMap().transforming_liquid_add(p0);
return 1;
}
@@ -1409,7 +1410,7 @@ int ModApiEnvMod::l_compare_block_status(lua_State *L)
v3s16 nodepos = check_v3s16(L, 1);
std::string condition_s = luaL_checkstring(L, 2);
auto status = env->getBlockStatus(getNodeBlockPos(nodepos));
-
+
int condition_i = -1;
if (!string_to_enum(es_BlockStatusType, condition_i, condition_s))
return 0; // Unsupported
diff --git a/src/script/lua_api/l_env.h b/src/script/lua_api/l_env.h
index 67c76faae..a7d406d2a 100644
--- a/src/script/lua_api/l_env.h
+++ b/src/script/lua_api/l_env.h
@@ -114,7 +114,7 @@ private:
// get_objects_inside_radius(pos, radius)
static int l_get_objects_inside_radius(lua_State *L);
-
+
// get_objects_in_area(pos, minp, maxp)
static int l_get_objects_in_area(lua_State *L);
diff --git a/src/script/lua_api/l_internal.h b/src/script/lua_api/l_internal.h
index 672e535ca..de73ff42a 100644
--- a/src/script/lua_api/l_internal.h
+++ b/src/script/lua_api/l_internal.h
@@ -69,7 +69,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
// Retrieve Environment pointer as `env` (no map lock)
#define GET_PLAIN_ENV_PTR_NO_MAP_LOCK \
- Environment *env = (Environment *)getEnv(L); \
+ Environment *env = getEnv(L); \
if (env == NULL) \
return 0
diff --git a/src/script/lua_api/l_inventory.cpp b/src/script/lua_api/l_inventory.cpp
index b0a4ee194..175047e58 100644
--- a/src/script/lua_api/l_inventory.cpp
+++ b/src/script/lua_api/l_inventory.cpp
@@ -214,11 +214,16 @@ int InvRef::l_get_list(lua_State *L)
InvRef *ref = checkobject(L, 1);
const char *listname = luaL_checkstring(L, 2);
Inventory *inv = getinv(L, ref);
- if(inv){
- push_inventory_list(L, inv, listname);
- } else {
+ if (!inv) {
lua_pushnil(L);
+ return 1;
}
+ InventoryList *invlist = inv->getList(listname);
+ if (!invlist) {
+ lua_pushnil(L);
+ return 1;
+ }
+ push_inventory_list(L, *invlist);
return 1;
}
@@ -242,7 +247,7 @@ int InvRef::l_set_list(lua_State *L)
return 0;
}
-// get_lists(self) -> list of InventoryLists
+// get_lists(self) -> table that maps listnames to InventoryLists
int InvRef::l_get_lists(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
@@ -251,15 +256,7 @@ int InvRef::l_get_lists(lua_State *L)
if (!inv) {
return 0;
}
- std::vector<const InventoryList*> lists = inv->getLists();
- std::vector<const InventoryList*>::iterator iter = lists.begin();
- lua_createtable(L, 0, lists.size());
- for (; iter != lists.end(); iter++) {
- const char* name = (*iter)->getName().c_str();
- lua_pushstring(L, name);
- push_inventory_list(L, inv, name);
- lua_rawset(L, -3);
- }
+ push_inventory_lists(L, *inv);
return 1;
}
diff --git a/src/script/lua_api/l_item.cpp b/src/script/lua_api/l_item.cpp
index 794d8a6e5..13d046d00 100644
--- a/src/script/lua_api/l_item.cpp
+++ b/src/script/lua_api/l_item.cpp
@@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "lua_api/l_internal.h"
#include "common/c_converter.h"
#include "common/c_content.h"
+#include "common/c_packer.h"
#include "itemdef.h"
#include "nodedef.h"
#include "server.h"
@@ -342,7 +343,7 @@ int LuaItemStack::l_get_tool_capabilities(lua_State *L)
}
// add_wear(self, amount) -> true/false
-// The range for "amount" is [0,65535]. Wear is only added if the item
+// The range for "amount" is [0,65536]. Wear is only added if the item
// is a tool. Adding wear might destroy the item.
// Returns true if the item is (or was) a tool.
int LuaItemStack::l_add_wear(lua_State *L)
@@ -356,6 +357,25 @@ int LuaItemStack::l_add_wear(lua_State *L)
return 1;
}
+// add_wear_by_uses(self, max_uses) -> true/false
+// The range for "max_uses" is [0,65536].
+// Adds wear to the item in such a way that, if
+// only this function is called to add wear, the item
+// will be destroyed exactly after `max_uses` times of calling it.
+// No-op if `max_uses` is 0 or item is not a tool.
+// Returns true if the item is (or was) a tool.
+int LuaItemStack::l_add_wear_by_uses(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+ LuaItemStack *o = checkobject(L, 1);
+ ItemStack &item = o->m_stack;
+ u32 max_uses = readParam<int>(L, 2);
+ u32 add_wear = calculateResultWear(max_uses, item.wear);
+ bool result = item.addWear(add_wear, getGameDef(L)->idef());
+ lua_pushboolean(L, result);
+ return 1;
+}
+
// add_item(self, itemstack or itemstring or table or nil) -> itemstack
// Returns leftover item stack
int LuaItemStack::l_add_item(lua_State *L)
@@ -441,6 +461,7 @@ int LuaItemStack::create_object(lua_State *L)
lua_setmetatable(L, -2);
return 1;
}
+
// Not callable from Lua
int LuaItemStack::create(lua_State *L, const ItemStack &item)
{
@@ -457,6 +478,20 @@ LuaItemStack *LuaItemStack::checkobject(lua_State *L, int narg)
return *(LuaItemStack **)luaL_checkudata(L, narg, className);
}
+void *LuaItemStack::packIn(lua_State *L, int idx)
+{
+ LuaItemStack *o = checkobject(L, idx);
+ return new ItemStack(o->getItem());
+}
+
+void LuaItemStack::packOut(lua_State *L, void *ptr)
+{
+ ItemStack *stack = reinterpret_cast<ItemStack*>(ptr);
+ if (L)
+ create(L, *stack);
+ delete stack;
+}
+
void LuaItemStack::Register(lua_State *L)
{
lua_newtable(L);
@@ -488,6 +523,8 @@ void LuaItemStack::Register(lua_State *L)
// Can be created from Lua (ItemStack(itemstack or itemstring or table or nil))
lua_register(L, className, create_object);
+
+ script_register_packer(L, className, packIn, packOut);
}
const char LuaItemStack::className[] = "ItemStack";
@@ -514,6 +551,7 @@ const luaL_Reg LuaItemStack::methods[] = {
luamethod(LuaItemStack, get_definition),
luamethod(LuaItemStack, get_tool_capabilities),
luamethod(LuaItemStack, add_wear),
+ luamethod(LuaItemStack, add_wear_by_uses),
luamethod(LuaItemStack, add_item),
luamethod(LuaItemStack, item_fits),
luamethod(LuaItemStack, take_item),
@@ -576,6 +614,9 @@ int ModApiItemMod::l_register_item_raw(lua_State *L)
// be done
if (f.name == "ignore")
return 0;
+ // This would break everything
+ if (f.name.empty())
+ throw LuaError("Cannot register node with empty name");
content_t id = ndef->set(f.name, f);
@@ -632,8 +673,8 @@ int ModApiItemMod::l_get_content_id(lua_State *L)
NO_MAP_LOCK_REQUIRED;
std::string name = luaL_checkstring(L, 1);
- const IItemDefManager *idef = getGameDef(L)->getItemDefManager();
- const NodeDefManager *ndef = getGameDef(L)->getNodeDefManager();
+ const IItemDefManager *idef = getGameDef(L)->idef();
+ const NodeDefManager *ndef = getGameDef(L)->ndef();
// If this is called at mod load time, NodeDefManager isn't aware of
// aliases yet, so we need to handle them manually
@@ -658,7 +699,7 @@ int ModApiItemMod::l_get_name_from_content_id(lua_State *L)
NO_MAP_LOCK_REQUIRED;
content_t c = luaL_checkint(L, 1);
- const NodeDefManager *ndef = getGameDef(L)->getNodeDefManager();
+ const NodeDefManager *ndef = getGameDef(L)->ndef();
const char *name = ndef->get(c).name.c_str();
lua_pushstring(L, name);
@@ -673,3 +714,10 @@ void ModApiItemMod::Initialize(lua_State *L, int top)
API_FCT(get_content_id);
API_FCT(get_name_from_content_id);
}
+
+void ModApiItemMod::InitializeAsync(lua_State *L, int top)
+{
+ // all read-only functions
+ API_FCT(get_content_id);
+ API_FCT(get_name_from_content_id);
+}
diff --git a/src/script/lua_api/l_item.h b/src/script/lua_api/l_item.h
index 16878c101..a392555d2 100644
--- a/src/script/lua_api/l_item.h
+++ b/src/script/lua_api/l_item.h
@@ -108,11 +108,20 @@ private:
static int l_get_tool_capabilities(lua_State *L);
// add_wear(self, amount) -> true/false
- // The range for "amount" is [0,65535]. Wear is only added if the item
+ // The range for "amount" is [0,65536]. Wear is only added if the item
// is a tool. Adding wear might destroy the item.
// Returns true if the item is (or was) a tool.
static int l_add_wear(lua_State *L);
+ // add_wear_by_uses(self, max_uses) -> true/false
+ // The range for "max_uses" is [0,65536].
+ // Adds wear to the item in such a way that, if
+ // only this function is called to add wear, the item
+ // will be destroyed exactly after `max_uses` times of calling it.
+ // No-op if `max_uses` is 0 or item is not a tool.
+ // Returns true if the item is (or was) a tool.
+ static int l_add_wear_by_uses(lua_State *L);
+
// add_item(self, itemstack or itemstring or table or nil) -> itemstack
// Returns leftover item stack
static int l_add_item(lua_State *L);
@@ -141,8 +150,11 @@ public:
// Not callable from Lua
static int create(lua_State *L, const ItemStack &item);
static LuaItemStack* checkobject(lua_State *L, int narg);
- static void Register(lua_State *L);
+ static void *packIn(lua_State *L, int idx);
+ static void packOut(lua_State *L, void *ptr);
+
+ static void Register(lua_State *L);
};
class ModApiItemMod : public ModApiBase {
@@ -152,6 +164,8 @@ private:
static int l_register_alias_raw(lua_State *L);
static int l_get_content_id(lua_State *L);
static int l_get_name_from_content_id(lua_State *L);
+
public:
static void Initialize(lua_State *L, int top);
+ static void InitializeAsync(lua_State *L, int top);
};
diff --git a/src/script/lua_api/l_mainmenu.cpp b/src/script/lua_api/l_mainmenu.cpp
index 736ad022f..cf4a057e1 100644
--- a/src/script/lua_api/l_mainmenu.cpp
+++ b/src/script/lua_api/l_mainmenu.cpp
@@ -38,7 +38,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "client/client.h"
#include "client/renderingengine.h"
#include "network/networkprotocol.h"
-
+#include "content/mod_configuration.h"
/******************************************************************************/
std::string ModApiMainMenu::getTextData(lua_State *L, std::string name)
@@ -139,6 +139,14 @@ int ModApiMainMenu::l_start(lua_State *L)
data->password = getTextData(L,"password");
data->address = getTextData(L,"address");
data->port = getTextData(L,"port");
+
+ const auto val = getTextData(L, "allow_login_or_register");
+ if (val == "login")
+ data->allow_login_or_register = ELoginRegister::Login;
+ else if (val == "register")
+ data->allow_login_or_register = ELoginRegister::Register;
+ else
+ data->allow_login_or_register = ELoginRegister::Any;
}
data->serverdescription = getTextData(L,"serverdescription");
data->servername = getTextData(L,"servername");
@@ -304,7 +312,11 @@ int ModApiMainMenu::l_get_games(lua_State *L)
lua_settable(L, top_lvl2);
lua_pushstring(L, "name");
- lua_pushstring(L, game.name.c_str());
+ lua_pushstring(L, game.title.c_str());
+ lua_settable(L, top_lvl2);
+
+ lua_pushstring(L, "title");
+ lua_pushstring(L, game.title.c_str());
lua_settable(L, top_lvl2);
lua_pushstring(L, "author");
@@ -323,9 +335,9 @@ int ModApiMainMenu::l_get_games(lua_State *L)
lua_newtable(L);
int table2 = lua_gettop(L);
int internal_index = 1;
- for (const std::string &addon_mods_path : game.addon_mods_paths) {
+ for (const auto &addon_mods_path : game.addon_mods_paths) {
lua_pushnumber(L, internal_index);
- lua_pushstring(L, addon_mods_path.c_str());
+ lua_pushstring(L, addon_mods_path.second.c_str());
lua_settable(L, table2);
internal_index++;
}
@@ -356,6 +368,11 @@ int ModApiMainMenu::l_get_content_info(lua_State *L)
lua_pushstring(L, spec.author.c_str());
lua_setfield(L, -2, "author");
+ if (!spec.title.empty()) {
+ lua_pushstring(L, spec.title.c_str());
+ lua_setfield(L, -2, "title");
+ }
+
lua_pushinteger(L, spec.release);
lua_setfield(L, -2, "release");
@@ -393,6 +410,100 @@ int ModApiMainMenu::l_get_content_info(lua_State *L)
}
/******************************************************************************/
+int ModApiMainMenu::l_check_mod_configuration(lua_State *L)
+{
+ std::string worldpath = luaL_checkstring(L, 1);
+
+ ModConfiguration modmgr;
+
+ // Add all game mods
+ SubgameSpec gamespec = findWorldSubgame(worldpath);
+ modmgr.addGameMods(gamespec);
+ modmgr.addModsInPath(worldpath + DIR_DELIM + "worldmods", "worldmods");
+
+ // Add user-configured mods
+ std::vector<ModSpec> modSpecs;
+
+ luaL_checktype(L, 2, LUA_TTABLE);
+
+ lua_pushnil(L);
+ while (lua_next(L, 2)) {
+ // Ignore non-string keys
+ if (lua_type(L, -2) != LUA_TSTRING) {
+ throw LuaError(
+ "Unexpected non-string key in table passed to "
+ "core.check_mod_configuration");
+ }
+
+ std::string modpath = luaL_checkstring(L, -1);
+ lua_pop(L, 1);
+ std::string virtual_path = lua_tostring(L, -1);
+
+ modSpecs.emplace_back();
+ ModSpec &spec = modSpecs.back();
+ spec.name = fs::GetFilenameFromPath(modpath.c_str());
+ spec.path = modpath;
+ spec.virtual_path = virtual_path;
+ if (!parseModContents(spec)) {
+ throw LuaError("Not a mod!");
+ }
+ }
+
+ modmgr.addMods(modSpecs);
+ try {
+ modmgr.checkConflictsAndDeps();
+ } catch (const ModError &err) {
+ errorstream << err.what() << std::endl;
+
+ lua_newtable(L);
+
+ lua_pushboolean(L, false);
+ lua_setfield(L, -2, "is_consistent");
+
+ lua_newtable(L);
+ lua_setfield(L, -2, "unsatisfied_mods");
+
+ lua_newtable(L);
+ lua_setfield(L, -2, "satisfied_mods");
+
+ lua_pushstring(L, err.what());
+ lua_setfield(L, -2, "error_message");
+ return 1;
+ }
+
+
+ lua_newtable(L);
+
+ lua_pushboolean(L, modmgr.isConsistent());
+ lua_setfield(L, -2, "is_consistent");
+
+ lua_newtable(L);
+ int top = lua_gettop(L);
+ unsigned int index = 1;
+ for (const auto &spec : modmgr.getUnsatisfiedMods()) {
+ lua_pushnumber(L, index);
+ push_mod_spec(L, spec, true);
+ lua_settable(L, top);
+ index++;
+ }
+
+ lua_setfield(L, -2, "unsatisfied_mods");
+
+ lua_newtable(L);
+ top = lua_gettop(L);
+ index = 1;
+ for (const auto &spec : modmgr.getMods()) {
+ lua_pushnumber(L, index);
+ push_mod_spec(L, spec, false);
+ lua_settable(L, top);
+ index++;
+ }
+ lua_setfield(L, -2, "satisfied_mods");
+
+ return 1;
+}
+
+/******************************************************************************/
int ModApiMainMenu::l_show_keys_menu(lua_State *L)
{
GUIEngine* engine = getGuiEngine(L);
@@ -533,14 +644,14 @@ int ModApiMainMenu::l_get_modpath(lua_State *L)
/******************************************************************************/
int ModApiMainMenu::l_get_modpaths(lua_State *L)
{
- int index = 1;
lua_newtable(L);
+
ModApiMainMenu::l_get_modpath(L);
- lua_rawseti(L, -2, index);
+ lua_setfield(L, -2, "mods");
+
for (const std::string &component : getEnvModPaths()) {
- index++;
lua_pushstring(L, component.c_str());
- lua_rawseti(L, -2, index);
+ lua_setfield(L, -2, fs::AbsolutePath(component).c_str());
}
return 1;
}
@@ -860,6 +971,19 @@ int ModApiMainMenu::l_open_dir(lua_State *L)
}
/******************************************************************************/
+int ModApiMainMenu::l_share_file(lua_State *L)
+{
+#ifdef __ANDROID__
+ std::string path = luaL_checkstring(L, 1);
+ porting::shareFileAndroid(path);
+ lua_pushboolean(L, true);
+#else
+ lua_pushboolean(L, false);
+#endif
+ return 1;
+}
+
+/******************************************************************************/
int ModApiMainMenu::l_do_async_callback(lua_State *L)
{
MainMenuScripting *script = getScriptApi<MainMenuScripting>(L);
@@ -891,6 +1015,7 @@ void ModApiMainMenu::Initialize(lua_State *L, int top)
API_FCT(get_worlds);
API_FCT(get_games);
API_FCT(get_content_info);
+ API_FCT(check_mod_configuration);
API_FCT(start);
API_FCT(close);
API_FCT(show_keys_menu);
@@ -924,6 +1049,7 @@ void ModApiMainMenu::Initialize(lua_State *L, int top)
API_FCT(get_max_supp_proto);
API_FCT(open_url);
API_FCT(open_dir);
+ API_FCT(share_file);
API_FCT(do_async_callback);
}
diff --git a/src/script/lua_api/l_mainmenu.h b/src/script/lua_api/l_mainmenu.h
index 781185425..9dc40c7f4 100644
--- a/src/script/lua_api/l_mainmenu.h
+++ b/src/script/lua_api/l_mainmenu.h
@@ -82,6 +82,8 @@ private:
static int l_get_content_info(lua_State *L);
+ static int l_check_mod_configuration(lua_State *L);
+
//gui
static int l_show_keys_menu(lua_State *L);
@@ -152,6 +154,8 @@ private:
static int l_open_dir(lua_State *L);
+ static int l_share_file(lua_State *L);
+
// async
static int l_do_async_callback(lua_State *L);
diff --git a/src/script/lua_api/l_nodemeta.cpp b/src/script/lua_api/l_nodemeta.cpp
index 34760157d..bdc4844c0 100644
--- a/src/script/lua_api/l_nodemeta.cpp
+++ b/src/script/lua_api/l_nodemeta.cpp
@@ -40,7 +40,7 @@ NodeMetaRef* NodeMetaRef::checkobject(lua_State *L, int narg)
Metadata* NodeMetaRef::getmeta(bool auto_create)
{
if (m_is_local)
- return m_meta;
+ return m_local_meta;
NodeMetadata *meta = m_env->getMap().getNodeMetadata(m_p);
if (meta == NULL && auto_create) {
@@ -62,9 +62,14 @@ void NodeMetaRef::clearMeta()
void NodeMetaRef::reportMetadataChange(const std::string *name)
{
SANITY_CHECK(!m_is_local);
- // NOTE: This same code is in rollback_interface.cpp
// Inform other things that the metadata has changed
- NodeMetadata *meta = dynamic_cast<NodeMetadata*>(m_meta);
+ NodeMetadata *meta = dynamic_cast<NodeMetadata*>(getmeta(false));
+
+ // If the metadata is now empty, get rid of it
+ if (meta && meta->empty()) {
+ clearMeta();
+ meta = nullptr;
+ }
MapEditEvent event;
event.type = MEET_BLOCK_NODE_METADATA_CHANGED;
@@ -127,18 +132,14 @@ void NodeMetaRef::handleToTable(lua_State *L, Metadata *_meta)
// fields
MetaDataRef::handleToTable(L, _meta);
- NodeMetadata *meta = (NodeMetadata*) _meta;
+ NodeMetadata *meta = (NodeMetadata *) _meta;
// inventory
- lua_newtable(L);
Inventory *inv = meta->getInventory();
if (inv) {
- std::vector<const InventoryList *> lists = inv->getLists();
- for(std::vector<const InventoryList *>::const_iterator
- i = lists.begin(); i != lists.end(); ++i) {
- push_inventory_list(L, inv, (*i)->getName().c_str());
- lua_setfield(L, -2, (*i)->getName().c_str());
- }
+ push_inventory_lists(L, *inv);
+ } else {
+ lua_newtable(L);
}
lua_setfield(L, -2, "inventory");
}
@@ -178,8 +179,8 @@ NodeMetaRef::NodeMetaRef(v3s16 p, ServerEnvironment *env):
}
NodeMetaRef::NodeMetaRef(Metadata *meta):
- m_meta(meta),
- m_is_local(true)
+ m_is_local(true),
+ m_local_meta(meta)
{
}
diff --git a/src/script/lua_api/l_nodemeta.h b/src/script/lua_api/l_nodemeta.h
index fdc1766ed..265ece3d0 100644
--- a/src/script/lua_api/l_nodemeta.h
+++ b/src/script/lua_api/l_nodemeta.h
@@ -33,10 +33,12 @@ class NodeMetadata;
class NodeMetaRef : public MetaDataRef {
private:
+ bool m_is_local = false;
+ // Set for server metadata
v3s16 m_p;
ServerEnvironment *m_env = nullptr;
- Metadata *m_meta = nullptr;
- bool m_is_local = false;
+ // Set for client metadata
+ Metadata *m_local_meta = nullptr;
static const char className[];
static const luaL_Reg methodsServer[];
diff --git a/src/script/lua_api/l_noise.cpp b/src/script/lua_api/l_noise.cpp
index f43ba837a..5561eaebf 100644
--- a/src/script/lua_api/l_noise.cpp
+++ b/src/script/lua_api/l_noise.cpp
@@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "lua_api/l_internal.h"
#include "common/c_converter.h"
#include "common/c_content.h"
+#include "common/c_packer.h"
#include "log.h"
#include "porting.h"
#include "util/numeric.h"
@@ -30,7 +31,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
LuaPerlinNoise
*/
-LuaPerlinNoise::LuaPerlinNoise(NoiseParams *params) :
+LuaPerlinNoise::LuaPerlinNoise(const NoiseParams *params) :
np(*params)
{
}
@@ -101,6 +102,25 @@ LuaPerlinNoise *LuaPerlinNoise::checkobject(lua_State *L, int narg)
}
+void *LuaPerlinNoise::packIn(lua_State *L, int idx)
+{
+ LuaPerlinNoise *o = checkobject(L, idx);
+ return new NoiseParams(o->np);
+}
+
+void LuaPerlinNoise::packOut(lua_State *L, void *ptr)
+{
+ NoiseParams *np = reinterpret_cast<NoiseParams*>(ptr);
+ if (L) {
+ LuaPerlinNoise *o = new LuaPerlinNoise(np);
+ *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
+ luaL_getmetatable(L, className);
+ lua_setmetatable(L, -2);
+ }
+ delete np;
+}
+
+
void LuaPerlinNoise::Register(lua_State *L)
{
lua_newtable(L);
@@ -126,6 +146,8 @@ void LuaPerlinNoise::Register(lua_State *L)
lua_pop(L, 1);
lua_register(L, className, create_object);
+
+ script_register_packer(L, className, packIn, packOut);
}
@@ -141,12 +163,10 @@ luaL_Reg LuaPerlinNoise::methods[] = {
LuaPerlinNoiseMap
*/
-LuaPerlinNoiseMap::LuaPerlinNoiseMap(NoiseParams *params, s32 seed, v3s16 size)
+LuaPerlinNoiseMap::LuaPerlinNoiseMap(const NoiseParams *np, s32 seed, v3s16 size)
{
- m_is3d = size.Z > 1;
- np = *params;
try {
- noise = new Noise(&np, seed, size.X, size.Y, size.Z);
+ noise = new Noise(np, seed, size.X, size.Y, size.Z);
} catch (InvalidNoiseParamsException &e) {
throw LuaError(e.what());
}
@@ -217,7 +237,7 @@ int LuaPerlinNoiseMap::l_get_3d_map(lua_State *L)
LuaPerlinNoiseMap *o = checkobject(L, 1);
v3f p = check_v3f(L, 2);
- if (!o->m_is3d)
+ if (!o->is3D())
return 0;
Noise *n = o->noise;
@@ -248,7 +268,7 @@ int LuaPerlinNoiseMap::l_get_3d_map_flat(lua_State *L)
v3f p = check_v3f(L, 2);
bool use_buffer = lua_istable(L, 3);
- if (!o->m_is3d)
+ if (!o->is3D())
return 0;
Noise *n = o->noise;
@@ -289,7 +309,7 @@ int LuaPerlinNoiseMap::l_calc_3d_map(lua_State *L)
LuaPerlinNoiseMap *o = checkobject(L, 1);
v3f p = check_v3f(L, 2);
- if (!o->m_is3d)
+ if (!o->is3D())
return 0;
Noise *n = o->noise;
@@ -359,6 +379,35 @@ LuaPerlinNoiseMap *LuaPerlinNoiseMap::checkobject(lua_State *L, int narg)
}
+struct NoiseMapParams {
+ NoiseParams np;
+ s32 seed;
+ v3s16 size;
+};
+
+void *LuaPerlinNoiseMap::packIn(lua_State *L, int idx)
+{
+ LuaPerlinNoiseMap *o = checkobject(L, idx);
+ NoiseMapParams *ret = new NoiseMapParams();
+ ret->np = o->noise->np;
+ ret->seed = o->noise->seed;
+ ret->size = v3s16(o->noise->sx, o->noise->sy, o->noise->sz);
+ return ret;
+}
+
+void LuaPerlinNoiseMap::packOut(lua_State *L, void *ptr)
+{
+ NoiseMapParams *p = reinterpret_cast<NoiseMapParams*>(ptr);
+ if (L) {
+ LuaPerlinNoiseMap *o = new LuaPerlinNoiseMap(&p->np, p->seed, p->size);
+ *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
+ luaL_getmetatable(L, className);
+ lua_setmetatable(L, -2);
+ }
+ delete p;
+}
+
+
void LuaPerlinNoiseMap::Register(lua_State *L)
{
lua_newtable(L);
@@ -384,6 +433,8 @@ void LuaPerlinNoiseMap::Register(lua_State *L)
lua_pop(L, 1);
lua_register(L, className, create_object);
+
+ script_register_packer(L, className, packIn, packOut);
}
diff --git a/src/script/lua_api/l_noise.h b/src/script/lua_api/l_noise.h
index 9f50dfd3f..5d34a479b 100644
--- a/src/script/lua_api/l_noise.h
+++ b/src/script/lua_api/l_noise.h
@@ -30,6 +30,7 @@ class LuaPerlinNoise : public ModApiBase
{
private:
NoiseParams np;
+
static const char className[];
static luaL_Reg methods[];
@@ -42,7 +43,7 @@ private:
static int l_get_3d(lua_State *L);
public:
- LuaPerlinNoise(NoiseParams *params);
+ LuaPerlinNoise(const NoiseParams *params);
~LuaPerlinNoise() = default;
// LuaPerlinNoise(seed, octaves, persistence, scale)
@@ -51,6 +52,9 @@ public:
static LuaPerlinNoise *checkobject(lua_State *L, int narg);
+ static void *packIn(lua_State *L, int idx);
+ static void packOut(lua_State *L, void *ptr);
+
static void Register(lua_State *L);
};
@@ -59,9 +63,8 @@ public:
*/
class LuaPerlinNoiseMap : public ModApiBase
{
- NoiseParams np;
Noise *noise;
- bool m_is3d;
+
static const char className[];
static luaL_Reg methods[];
@@ -80,16 +83,20 @@ class LuaPerlinNoiseMap : public ModApiBase
static int l_get_map_slice(lua_State *L);
public:
- LuaPerlinNoiseMap(NoiseParams *np, s32 seed, v3s16 size);
-
+ LuaPerlinNoiseMap(const NoiseParams *np, s32 seed, v3s16 size);
~LuaPerlinNoiseMap();
+ inline bool is3D() const { return noise->sz > 1; }
+
// LuaPerlinNoiseMap(np, size)
// Creates an LuaPerlinNoiseMap and leaves it on top of stack
static int create_object(lua_State *L);
static LuaPerlinNoiseMap *checkobject(lua_State *L, int narg);
+ static void *packIn(lua_State *L, int idx);
+ static void packOut(lua_State *L, void *ptr);
+
static void Register(lua_State *L);
};
diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp
index 407b48db0..6bd07a4c1 100644
--- a/src/script/lua_api/l_object.cpp
+++ b/src/script/lua_api/l_object.cpp
@@ -420,8 +420,7 @@ int ObjectRef::l_set_local_animation(lua_State *L)
float frame_speed = readParam<float>(L, 6, 30.0f);
getServer(L)->setLocalPlayerAnimations(player, frames, frame_speed);
- lua_pushboolean(L, true);
- return 1;
+ return 0;
}
// get_local_animation(self)
@@ -464,8 +463,7 @@ int ObjectRef::l_set_eye_offset(lua_State *L)
offset_third.Y = rangelim(offset_third.Y,-10,15); //1.5*BS
getServer(L)->setPlayerEyeOffset(player, offset_first, offset_third);
- lua_pushboolean(L, true);
- return 1;
+ return 0;
}
// get_eye_offset(self)
@@ -737,8 +735,7 @@ int ObjectRef::l_set_nametag_attributes(lua_State *L)
prop->validate();
sao->notifyObjectPropertiesModified();
- lua_pushboolean(L, true);
- return 1;
+ return 0;
}
// get_nametag_attributes(self)
@@ -1116,7 +1113,7 @@ int ObjectRef::l_set_look_vertical(lua_State *L)
float pitch = readParam<float>(L, 2) * core::RADTODEG;
playersao->setLookPitchAndSend(pitch);
- return 1;
+ return 0;
}
// set_look_horizontal(self, radians)
@@ -1131,7 +1128,7 @@ int ObjectRef::l_set_look_horizontal(lua_State *L)
float yaw = readParam<float>(L, 2) * core::RADTODEG;
playersao->setPlayerYawAndSend(yaw);
- return 1;
+ return 0;
}
// DEPRECATED
@@ -1151,7 +1148,7 @@ int ObjectRef::l_set_look_pitch(lua_State *L)
float pitch = readParam<float>(L, 2) * core::RADTODEG;
playersao->setLookPitchAndSend(pitch);
- return 1;
+ return 0;
}
// DEPRECATED
@@ -1171,7 +1168,7 @@ int ObjectRef::l_set_look_yaw(lua_State *L)
float yaw = readParam<float>(L, 2) * core::RADTODEG;
playersao->setPlayerYawAndSend(yaw);
- return 1;
+ return 0;
}
// set_fov(self, degrees, is_multiplier, transition_time)
@@ -1310,8 +1307,7 @@ int ObjectRef::l_set_inventory_formspec(lua_State *L)
player->inventory_formspec = formspec;
getServer(L)->reportInventoryFormspecModified(player->getName());
- lua_pushboolean(L, true);
- return 1;
+ return 0;
}
// get_inventory_formspec(self) -> formspec
@@ -1342,8 +1338,7 @@ int ObjectRef::l_set_formspec_prepend(lua_State *L)
player->formspec_prepend = formspec;
getServer(L)->reportFormspecPrependModified(player->getName());
- lua_pushboolean(L, true);
- return 1;
+ return 0;
}
// get_formspec_prepend(self)
@@ -1603,8 +1598,7 @@ int ObjectRef::l_hud_set_flags(lua_State *L)
if (!getServer(L)->hudSetFlags(player, flags, mask))
return 0;
- lua_pushboolean(L, true);
- return 1;
+ return 0;
}
// hud_get_flags(self)
@@ -1617,20 +1611,11 @@ int ObjectRef::l_hud_get_flags(lua_State *L)
return 0;
lua_newtable(L);
- lua_pushboolean(L, player->hud_flags & HUD_FLAG_HOTBAR_VISIBLE);
- lua_setfield(L, -2, "hotbar");
- lua_pushboolean(L, player->hud_flags & HUD_FLAG_HEALTHBAR_VISIBLE);
- lua_setfield(L, -2, "healthbar");
- lua_pushboolean(L, player->hud_flags & HUD_FLAG_CROSSHAIR_VISIBLE);
- lua_setfield(L, -2, "crosshair");
- lua_pushboolean(L, player->hud_flags & HUD_FLAG_WIELDITEM_VISIBLE);
- lua_setfield(L, -2, "wielditem");
- lua_pushboolean(L, player->hud_flags & HUD_FLAG_BREATHBAR_VISIBLE);
- lua_setfield(L, -2, "breathbar");
- lua_pushboolean(L, player->hud_flags & HUD_FLAG_MINIMAP_VISIBLE);
- lua_setfield(L, -2, "minimap");
- lua_pushboolean(L, player->hud_flags & HUD_FLAG_MINIMAP_RADAR_VISIBLE);
- lua_setfield(L, -2, "minimap_radar");
+ const EnumString *esp = es_HudBuiltinElement;
+ for (int i = 0; esp[i].str; i++) {
+ lua_pushboolean(L, (player->hud_flags & esp[i].num) != 0);
+ lua_setfield(L, -2, esp[i].str);
+ }
return 1;
}
@@ -1870,11 +1855,37 @@ int ObjectRef::l_set_sky(lua_State *L)
}
getServer(L)->setSky(player, sky_params);
- lua_pushboolean(L, true);
- return 1;
+ return 0;
}
-// get_sky(self)
+static void push_sky_color(lua_State *L, const SkyboxParams &params)
+{
+ lua_newtable(L);
+ if (params.type == "regular") {
+ push_ARGB8(L, params.sky_color.day_sky);
+ lua_setfield(L, -2, "day_sky");
+ push_ARGB8(L, params.sky_color.day_horizon);
+ lua_setfield(L, -2, "day_horizon");
+ push_ARGB8(L, params.sky_color.dawn_sky);
+ lua_setfield(L, -2, "dawn_sky");
+ push_ARGB8(L, params.sky_color.dawn_horizon);
+ lua_setfield(L, -2, "dawn_horizon");
+ push_ARGB8(L, params.sky_color.night_sky);
+ lua_setfield(L, -2, "night_sky");
+ push_ARGB8(L, params.sky_color.night_horizon);
+ lua_setfield(L, -2, "night_horizon");
+ push_ARGB8(L, params.sky_color.indoors);
+ lua_setfield(L, -2, "indoors");
+ }
+ push_ARGB8(L, params.fog_sun_tint);
+ lua_setfield(L, -2, "fog_sun_tint");
+ push_ARGB8(L, params.fog_moon_tint);
+ lua_setfield(L, -2, "fog_moon_tint");
+ lua_pushstring(L, params.fog_tint_type.c_str());
+ lua_setfield(L, -2, "fog_tint_type");
+}
+
+// get_sky(self, as_table)
int ObjectRef::l_get_sky(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
@@ -1883,10 +1894,30 @@ int ObjectRef::l_get_sky(lua_State *L)
if (player == nullptr)
return 0;
- SkyboxParams skybox_params = player->getSkyParams();
+ const SkyboxParams &skybox_params = player->getSkyParams();
+ // handle the deprecated version
+ if (!readParam<bool>(L, 2, false)) {
+ log_deprecated(L, "Deprecated call to get_sky, please check lua_api.txt");
+
+ push_ARGB8(L, skybox_params.bgcolor);
+ lua_pushlstring(L, skybox_params.type.c_str(), skybox_params.type.size());
+
+ lua_newtable(L);
+ s16 i = 1;
+ for (const std::string &texture : skybox_params.textures) {
+ lua_pushlstring(L, texture.c_str(), texture.size());
+ lua_rawseti(L, -2, i++);
+ }
+ lua_pushboolean(L, skybox_params.clouds);
+ return 4;
+ }
+
+ lua_newtable(L);
push_ARGB8(L, skybox_params.bgcolor);
+ lua_setfield(L, -2, "base_color");
lua_pushlstring(L, skybox_params.type.c_str(), skybox_params.type.size());
+ lua_setfield(L, -2, "type");
lua_newtable(L);
s16 i = 1;
@@ -1894,44 +1925,30 @@ int ObjectRef::l_get_sky(lua_State *L)
lua_pushlstring(L, texture.c_str(), texture.size());
lua_rawseti(L, -2, i++);
}
+ lua_setfield(L, -2, "textures");
lua_pushboolean(L, skybox_params.clouds);
- return 4;
+ lua_setfield(L, -2, "clouds");
+
+ push_sky_color(L, skybox_params);
+ lua_setfield(L, -2, "sky_color");
+ return 1;
}
+// DEPRECATED
// get_sky_color(self)
int ObjectRef::l_get_sky_color(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
+
+ log_deprecated(L, "Deprecated call to get_sky_color, use get_sky instead");
+
ObjectRef *ref = checkobject(L, 1);
RemotePlayer *player = getplayer(ref);
if (player == nullptr)
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.fog_sun_tint);
- lua_setfield(L, -2, "fog_sun_tint");
- push_ARGB8(L, skybox_params.fog_moon_tint);
- lua_setfield(L, -2, "fog_moon_tint");
- lua_pushstring(L, skybox_params.fog_tint_type.c_str());
- lua_setfield(L, -2, "fog_tint_type");
+ push_sky_color(L, skybox_params);
return 1;
}
@@ -1960,8 +1977,7 @@ int ObjectRef::l_set_sun(lua_State *L)
}
getServer(L)->setSun(player, sun_params);
- lua_pushboolean(L, true);
- return 1;
+ return 0;
}
//get_sun(self)
@@ -2014,8 +2030,7 @@ int ObjectRef::l_set_moon(lua_State *L)
}
getServer(L)->setMoon(player, moon_params);
- lua_pushboolean(L, true);
- return 1;
+ return 0;
}
// get_moon(self)
@@ -2069,9 +2084,11 @@ int ObjectRef::l_set_stars(lua_State *L)
"scale", star_params.scale);
}
+ star_params.day_opacity = getfloatfield_default(L, 2,
+ "day_opacity", star_params.day_opacity);
+
getServer(L)->setStars(player, star_params);
- lua_pushboolean(L, true);
- return 1;
+ return 0;
}
// get_stars(self)
@@ -2094,6 +2111,8 @@ int ObjectRef::l_get_stars(lua_State *L)
lua_setfield(L, -2, "star_color");
lua_pushnumber(L, star_params.scale);
lua_setfield(L, -2, "scale");
+ lua_pushnumber(L, star_params.day_opacity);
+ lua_setfield(L, -2, "day_opacity");
return 1;
}
@@ -2138,8 +2157,7 @@ int ObjectRef::l_set_clouds(lua_State *L)
}
getServer(L)->setClouds(player, cloud_params);
- lua_pushboolean(L, true);
- return 1;
+ return 0;
}
int ObjectRef::l_get_clouds(lua_State *L)
@@ -2193,8 +2211,7 @@ int ObjectRef::l_override_day_night_ratio(lua_State *L)
}
getServer(L)->overrideDayNightRatio(player, do_override, ratio);
- lua_pushboolean(L, true);
- return 1;
+ return 0;
}
// get_day_night_ratio(self)
@@ -2271,6 +2288,61 @@ int ObjectRef::l_set_minimap_modes(lua_State *L)
return 0;
}
+// set_lighting(self, lighting)
+int ObjectRef::l_set_lighting(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+ ObjectRef *ref = checkobject(L, 1);
+ RemotePlayer *player = getplayer(ref);
+ if (player == nullptr)
+ return 0;
+
+ luaL_checktype(L, 2, LUA_TTABLE);
+ Lighting lighting = player->getLighting();
+ lua_getfield(L, 2, "shadows");
+ if (lua_istable(L, -1)) {
+ lighting.shadow_intensity = getfloatfield_default(L, -1, "intensity", lighting.shadow_intensity);
+ }
+ lua_pop(L, -1);
+
+ getServer(L)->setLighting(player, lighting);
+ return 0;
+}
+
+// get_lighting(self)
+int ObjectRef::l_get_lighting(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+ ObjectRef *ref = checkobject(L, 1);
+ RemotePlayer *player = getplayer(ref);
+ if (player == nullptr)
+ return 0;
+
+ const Lighting &lighting = player->getLighting();
+
+ lua_newtable(L); // result
+ lua_newtable(L); // "shadows"
+ lua_pushnumber(L, lighting.shadow_intensity);
+ lua_setfield(L, -2, "intensity");
+ lua_setfield(L, -2, "shadows");
+ return 1;
+}
+
+// respawn(self)
+int ObjectRef::l_respawn(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+ ObjectRef *ref = checkobject(L, 1);
+ RemotePlayer *player = getplayer(ref);
+ if (player == nullptr)
+ return 0;
+
+ getServer(L)->RespawnPlayer(player->getPeerId());
+ lua_pushboolean(L, true);
+ return 1;
+}
+
+
ObjectRef::ObjectRef(ServerActiveObject *object):
m_object(object)
{}
@@ -2424,5 +2496,9 @@ luaL_Reg ObjectRef::methods[] = {
luamethod(ObjectRef, get_eye_offset),
luamethod(ObjectRef, send_mapblock),
luamethod(ObjectRef, set_minimap_modes),
+ luamethod(ObjectRef, set_lighting),
+ luamethod(ObjectRef, get_lighting),
+ luamethod(ObjectRef, respawn),
+
{0,0}
};
diff --git a/src/script/lua_api/l_object.h b/src/script/lua_api/l_object.h
index db3a3a7cf..b36bab492 100644
--- a/src/script/lua_api/l_object.h
+++ b/src/script/lua_api/l_object.h
@@ -316,9 +316,10 @@ private:
// set_sky(self, sky_parameters)
static int l_set_sky(lua_State *L);
- // get_sky(self)
+ // get_sky(self, as_table)
static int l_get_sky(lua_State *L);
+ // DEPRECATED
// get_sky_color(self)
static int l_get_sky_color(lua_State* L);
@@ -375,4 +376,13 @@ private:
// set_minimap_modes(self, modes, wanted_mode)
static int l_set_minimap_modes(lua_State *L);
+
+ // set_lighting(self, lighting)
+ static int l_set_lighting(lua_State *L);
+
+ // get_lighting(self)
+ static int l_get_lighting(lua_State *L);
+
+ // respawn(self)
+ static int l_respawn(lua_State *L);
};
diff --git a/src/script/lua_api/l_particleparams.h b/src/script/lua_api/l_particleparams.h
new file mode 100644
index 000000000..03f11c07f
--- /dev/null
+++ b/src/script/lua_api/l_particleparams.h
@@ -0,0 +1,282 @@
+/*
+Minetest
+Copyright (C) 2021 velartrill, Lexi Hale <lexi@hale.su>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#pragma once
+#include "lua_api/l_particles.h"
+#include "lua_api/l_object.h"
+#include "lua_api/l_internal.h"
+#include "common/c_converter.h"
+#include "common/c_content.h"
+#include "server.h"
+#include "particles.h"
+
+namespace LuaParticleParams
+{
+ using namespace ParticleParamTypes;
+
+ template<typename T>
+ inline void readNumericLuaValue(lua_State* L, T& ret)
+ {
+ if (lua_isnil(L,-1))
+ return;
+
+ if (std::is_integral<T>())
+ ret = lua_tointeger(L, -1);
+ else
+ ret = lua_tonumber(L, -1);
+ }
+
+ template <typename T, size_t N>
+ inline void readNumericLuaValue(lua_State* L, Parameter<T,N>& ret)
+ {
+ readNumericLuaValue<T>(L, ret.val);
+ }
+
+ // these are unfortunately necessary as C++ intentionally disallows function template
+ // specialization and there's no way to make template overloads reliably resolve correctly
+ inline void readLuaValue(lua_State* L, f32Parameter& ret) { readNumericLuaValue(L, ret); }
+ inline void readLuaValue(lua_State* L, f32& ret) { readNumericLuaValue(L, ret); }
+ inline void readLuaValue(lua_State* L, u16& ret) { readNumericLuaValue(L, ret); }
+ inline void readLuaValue(lua_State* L, u8& ret) { readNumericLuaValue(L, ret); }
+
+ inline void readLuaValue(lua_State* L, v3fParameter& ret)
+ {
+ if (lua_isnil(L, -1))
+ return;
+
+ if (lua_isnumber(L, -1)) { // shortcut for uniform vectors
+ auto n = lua_tonumber(L, -1);
+ ret = v3fParameter(n,n,n);
+ } else {
+ ret = (v3fParameter)check_v3f(L, -1);
+ }
+ }
+
+ inline void readLuaValue(lua_State* L, v2fParameter& ret)
+ {
+ if (lua_isnil(L, -1))
+ return;
+
+ if (lua_isnumber(L, -1)) { // shortcut for uniform vectors
+ auto n = lua_tonumber(L, -1);
+ ret = v2fParameter(n,n);
+ } else {
+ ret = (v2fParameter)check_v2f(L, -1);
+ }
+ }
+
+ inline void readLuaValue(lua_State* L, TweenStyle& ret)
+ {
+ if (lua_isnil(L, -1))
+ return;
+
+ static const EnumString opts[] = {
+ {(int)TweenStyle::fwd, "fwd"},
+ {(int)TweenStyle::rev, "rev"},
+ {(int)TweenStyle::pulse, "pulse"},
+ {(int)TweenStyle::flicker, "flicker"},
+ {0, nullptr},
+ };
+
+ luaL_checktype(L, -1, LUA_TSTRING);
+ int v = (int)TweenStyle::fwd;
+ if (!string_to_enum(opts, v, lua_tostring(L, -1))) {
+ throw LuaError("tween style must be one of ('fwd', 'rev', 'pulse', 'flicker')");
+ }
+ ret = (TweenStyle)v;
+ }
+
+ inline void readLuaValue(lua_State* L, AttractorKind& ret)
+ {
+ if (lua_isnil(L, -1))
+ return;
+
+ static const EnumString opts[] = {
+ {(int)AttractorKind::none, "none"},
+ {(int)AttractorKind::point, "point"},
+ {(int)AttractorKind::line, "line"},
+ {(int)AttractorKind::plane, "plane"},
+ {0, nullptr},
+ };
+
+ luaL_checktype(L, -1, LUA_TSTRING);
+ int v = (int)AttractorKind::none;
+ if (!string_to_enum(opts, v, lua_tostring(L, -1))) {
+ throw LuaError("attractor kind must be one of ('none', 'point', 'line', 'plane')");
+ }
+ ret = (AttractorKind)v;
+ }
+
+ inline void readLuaValue(lua_State* L, BlendMode& ret)
+ {
+ if (lua_isnil(L, -1))
+ return;
+
+ static const EnumString opts[] = {
+ {(int)BlendMode::alpha, "alpha"},
+ {(int)BlendMode::add, "add"},
+ {(int)BlendMode::sub, "sub"},
+ {(int)BlendMode::screen, "screen"},
+ {0, nullptr},
+ };
+
+ luaL_checktype(L, -1, LUA_TSTRING);
+ int v = (int)BlendMode::alpha;
+ if (!string_to_enum(opts, v, lua_tostring(L, -1))) {
+ throw LuaError("blend mode must be one of ('alpha', 'add', 'sub', 'screen')");
+ }
+ ret = (BlendMode)v;
+ }
+
+ template <typename T> void
+ readLuaValue(lua_State* L, RangedParameter<T>& field)
+ {
+ if (lua_isnil(L,-1))
+ return;
+ if (!lua_istable(L,-1)) // is this is just a literal value?
+ goto set_uniform;
+
+ lua_getfield(L, -1, "min");
+ // handle convenience syntax for non-range values
+ if (lua_isnil(L,-1)) {
+ lua_pop(L, 1);
+ goto set_uniform;
+ }
+ readLuaValue(L,field.min);
+ lua_pop(L, 1);
+
+ lua_getfield(L, -1, "max");
+ readLuaValue(L,field.max);
+ lua_pop(L, 1);
+
+ lua_getfield(L, -1, "bias");
+ if (!lua_isnil(L,-1))
+ readLuaValue(L,field.bias);
+ lua_pop(L, 1);
+ return;
+
+ set_uniform:
+ readLuaValue(L, field.min);
+ readLuaValue(L, field.max);
+ }
+
+ template <typename T> void
+ readLegacyValue(lua_State* L, const char* name, T& field) {}
+
+ template <typename T> void
+ readLegacyValue(lua_State* L, const char* name, RangedParameter<T>& field)
+ {
+ int tbl = lua_gettop(L);
+ lua_pushliteral(L, "min");
+ lua_pushstring(L, name);
+ lua_concat(L, 2);
+ lua_gettable(L, tbl);
+ if (!lua_isnil(L, -1)) {
+ readLuaValue(L, field.min);
+ }
+ lua_settop(L, tbl);
+
+ lua_pushliteral(L, "max");
+ lua_pushstring(L, name);
+ lua_concat(L, 2);
+ lua_gettable(L, tbl);
+ if (!lua_isnil(L, -1)) {
+ readLuaValue(L, field.max);
+ }
+ lua_settop(L, tbl);
+ }
+
+ template <typename T> void
+ readTweenTable(lua_State* L, const char* name, TweenedParameter<T>& field)
+ {
+ int tbl = lua_gettop(L);
+
+ lua_pushstring(L, name);
+ lua_pushliteral(L, "_tween");
+ lua_concat(L, 2);
+ lua_gettable(L, tbl);
+ if(lua_istable(L, -1)) {
+ int tween = lua_gettop(L);
+ // get the starting value
+ lua_pushinteger(L, 1), lua_gettable(L, tween);
+ readLuaValue(L, field.start);
+ lua_pop(L, 1);
+
+ // get the final value -- use len instead of 2 so that this
+ // gracefully degrades if keyframe support is later added
+ lua_pushinteger(L, (lua_Integer)lua_objlen(L, -1)), lua_gettable(L, tween);
+ readLuaValue(L, field.end);
+ lua_pop(L, 1);
+
+ // get the effect settings
+ lua_getfield(L, -1, "style");
+ if (!lua_isnil(L,-1))
+ readLuaValue(L, field.style);
+ lua_pop(L, 1);
+
+ lua_getfield(L, -1, "reps");
+ if (!lua_isnil(L,-1))
+ readLuaValue(L, field.reps);
+ lua_pop(L, 1);
+
+ lua_getfield(L, -1, "start");
+ if (!lua_isnil(L,-1))
+ readLuaValue(L, field.beginning);
+ lua_pop(L, 1);
+
+ goto done;
+ } else {
+ lua_pop(L,1);
+ }
+ // the table is not present; check for nonanimated values
+
+ lua_getfield(L, tbl, name);
+ if(!lua_isnil(L, -1)) {
+ readLuaValue(L, field.start);
+ lua_settop(L, tbl);
+ goto set_uniform;
+ } else {
+ lua_pop(L,1);
+ }
+
+ // the goto did not trigger, so this table is not present either
+ // check for pre-5.6.0 legacy values
+ readLegacyValue(L, name, field.start);
+
+ set_uniform:
+ field.end = field.start;
+ done:
+ lua_settop(L, tbl); // clean up after ourselves
+ }
+
+ inline u16 readAttachmentID(lua_State* L, const char* name)
+ {
+ u16 id = 0;
+ lua_getfield(L, -1, name);
+ if (!lua_isnil(L, -1)) {
+ ObjectRef *ref = ObjectRef::checkobject(L, -1);
+ if (auto obj = ObjectRef::getobject(ref))
+ id = obj->getId();
+ }
+ lua_pop(L, 1);
+ return id;
+ }
+
+ void readTexValue(lua_State* L, ServerParticleTexture& tex);
+}
diff --git a/src/script/lua_api/l_particles.cpp b/src/script/lua_api/l_particles.cpp
index a51c4fe20..586c7dc73 100644
--- a/src/script/lua_api/l_particles.cpp
+++ b/src/script/lua_api/l_particles.cpp
@@ -20,30 +20,50 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "lua_api/l_particles.h"
#include "lua_api/l_object.h"
#include "lua_api/l_internal.h"
+#include "lua_api/l_particleparams.h"
#include "common/c_converter.h"
#include "common/c_content.h"
#include "server.h"
#include "particles.h"
-// add_particle({pos=, velocity=, acceleration=, expirationtime=,
-// size=, collisiondetection=, collision_removal=, object_collision=,
-// vertical=, texture=, player=})
-// pos/velocity/acceleration = {x=num, y=num, z=num}
-// expirationtime = num (seconds)
-// size = num
-// collisiondetection = bool
-// collision_removal = bool
-// object_collision = bool
-// vertical = bool
-// texture = e.g."default_wood.png"
-// animation = TileAnimation definition
-// glow = num
+void LuaParticleParams::readTexValue(lua_State* L, ServerParticleTexture& tex)
+{
+ StackUnroller unroll(L);
+
+ tex.animated = false;
+ if (lua_isstring(L, -1)) {
+ tex.string = lua_tostring(L, -1);
+ return;
+ }
+
+ luaL_checktype(L, -1, LUA_TTABLE);
+ lua_getfield(L, -1, "name");
+ tex.string = luaL_checkstring(L, -1);
+ lua_pop(L, 1);
+
+ lua_getfield(L, -1, "animation");
+ if (! lua_isnil(L, -1)) {
+ tex.animated = true;
+ tex.animation = read_animation_definition(L, -1);
+ }
+ lua_pop(L, 1);
+
+ lua_getfield(L, -1, "blend");
+ LuaParticleParams::readLuaValue(L, tex.blendmode);
+ lua_pop(L, 1);
+
+ LuaParticleParams::readTweenTable(L, "alpha", tex.alpha);
+ LuaParticleParams::readTweenTable(L, "scale", tex.scale);
+
+}
+
+// add_particle({...})
int ModApiParticles::l_add_particle(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
// Get parameters
- struct ParticleParameters p;
+ ParticleParameters p;
std::string playername;
if (lua_gettop(L) > 1) // deprecated
@@ -56,7 +76,7 @@ int ModApiParticles::l_add_particle(lua_State *L)
p.expirationtime = luaL_checknumber(L, 4);
p.size = luaL_checknumber(L, 5);
p.collisiondetection = readParam<bool>(L, 6);
- p.texture = luaL_checkstring(L, 7);
+ p.texture.string = luaL_checkstring(L, 7);
if (lua_gettop(L) == 8) // only spawn for a single player
playername = luaL_checkstring(L, 8);
}
@@ -108,7 +128,12 @@ int ModApiParticles::l_add_particle(lua_State *L)
p.animation = read_animation_definition(L, -1);
lua_pop(L, 1);
- p.texture = getstringfield_default(L, 1, "texture", p.texture);
+ lua_getfield(L, 1, "texture");
+ if (!lua_isnil(L, -1)) {
+ LuaParticleParams::readTexValue(L, p.texture);
+ }
+ lua_pop(L, 1);
+
p.glow = getintfield_default(L, 1, "glow", p.glow);
lua_getfield(L, 1, "node");
@@ -119,34 +144,26 @@ int ModApiParticles::l_add_particle(lua_State *L)
p.node_tile = getintfield_default(L, 1, "node_tile", p.node_tile);
playername = getstringfield_default(L, 1, "playername", "");
+
+ lua_getfield(L, 1, "drag");
+ if (lua_istable(L, -1))
+ p.drag = check_v3f(L, -1);
+ lua_pop(L, 1);
+
+ lua_getfield(L, 1, "jitter");
+ LuaParticleParams::readLuaValue(L, p.jitter);
+ lua_pop(L, 1);
+
+ lua_getfield(L, 1, "bounce");
+ LuaParticleParams::readLuaValue(L, p.bounce);
+ lua_pop(L, 1);
}
getServer(L)->spawnParticle(playername, p);
return 1;
}
-// add_particlespawner({amount=, time=,
-// minpos=, maxpos=,
-// minvel=, maxvel=,
-// minacc=, maxacc=,
-// minexptime=, maxexptime=,
-// minsize=, maxsize=,
-// collisiondetection=,
-// collision_removal=,
-// object_collision=,
-// vertical=,
-// texture=,
-// player=})
-// minpos/maxpos/minvel/maxvel/minacc/maxacc = {x=num, y=num, z=num}
-// minexptime/maxexptime = num (seconds)
-// minsize/maxsize = num
-// collisiondetection = bool
-// collision_removal = bool
-// object_collision = bool
-// vertical = bool
-// texture = e.g."default_wood.png"
-// animation = TileAnimation definition
-// glow = num
+// add_particlespawner({...})
int ModApiParticles::l_add_particlespawner(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
@@ -156,24 +173,31 @@ int ModApiParticles::l_add_particlespawner(lua_State *L)
ServerActiveObject *attached = NULL;
std::string playername;
+ using namespace ParticleParamTypes;
if (lua_gettop(L) > 1) //deprecated
{
log_deprecated(L, "Deprecated add_particlespawner call with "
"individual parameters instead of definition");
p.amount = luaL_checknumber(L, 1);
p.time = luaL_checknumber(L, 2);
- p.minpos = check_v3f(L, 3);
- p.maxpos = check_v3f(L, 4);
- p.minvel = check_v3f(L, 5);
- p.maxvel = check_v3f(L, 6);
- p.minacc = check_v3f(L, 7);
- p.maxacc = check_v3f(L, 8);
- p.minexptime = luaL_checknumber(L, 9);
- p.maxexptime = luaL_checknumber(L, 10);
- p.minsize = luaL_checknumber(L, 11);
- p.maxsize = luaL_checknumber(L, 12);
+ auto minpos = check_v3f(L, 3);
+ auto maxpos = check_v3f(L, 4);
+ auto minvel = check_v3f(L, 5);
+ auto maxvel = check_v3f(L, 6);
+ auto minacc = check_v3f(L, 7);
+ auto maxacc = check_v3f(L, 8);
+ auto minexptime = luaL_checknumber(L, 9);
+ auto maxexptime = luaL_checknumber(L, 10);
+ auto minsize = luaL_checknumber(L, 11);
+ auto maxsize = luaL_checknumber(L, 12);
+ p.pos = v3fRange(minpos, maxpos);
+ p.vel = v3fRange(minvel, maxvel);
+ p.acc = v3fRange(minacc, maxacc);
+ p.exptime = f32Range(minexptime, maxexptime);
+ p.size = f32Range(minsize, maxsize);
+
p.collisiondetection = readParam<bool>(L, 13);
- p.texture = luaL_checkstring(L, 14);
+ p.texture.string = luaL_checkstring(L, 14);
if (lua_gettop(L) == 15) // only spawn for a single player
playername = luaL_checkstring(L, 15);
}
@@ -182,40 +206,46 @@ int ModApiParticles::l_add_particlespawner(lua_State *L)
p.amount = getintfield_default(L, 1, "amount", p.amount);
p.time = getfloatfield_default(L, 1, "time", p.time);
- lua_getfield(L, 1, "minpos");
- if (lua_istable(L, -1))
- p.minpos = check_v3f(L, -1);
- lua_pop(L, 1);
-
- lua_getfield(L, 1, "maxpos");
- if (lua_istable(L, -1))
- p.maxpos = check_v3f(L, -1);
- lua_pop(L, 1);
-
- lua_getfield(L, 1, "minvel");
- if (lua_istable(L, -1))
- p.minvel = check_v3f(L, -1);
- lua_pop(L, 1);
-
- lua_getfield(L, 1, "maxvel");
- if (lua_istable(L, -1))
- p.maxvel = check_v3f(L, -1);
- lua_pop(L, 1);
-
- lua_getfield(L, 1, "minacc");
- if (lua_istable(L, -1))
- p.minacc = check_v3f(L, -1);
- lua_pop(L, 1);
-
- lua_getfield(L, 1, "maxacc");
- if (lua_istable(L, -1))
- p.maxacc = check_v3f(L, -1);
- lua_pop(L, 1);
+ // set default values
+ p.exptime = 1;
+ p.size = 1;
+
+ // read spawner parameters from the table
+ LuaParticleParams::readTweenTable(L, "pos", p.pos);
+ LuaParticleParams::readTweenTable(L, "vel", p.vel);
+ LuaParticleParams::readTweenTable(L, "acc", p.acc);
+ LuaParticleParams::readTweenTable(L, "size", p.size);
+ LuaParticleParams::readTweenTable(L, "exptime", p.exptime);
+ LuaParticleParams::readTweenTable(L, "drag", p.drag);
+ LuaParticleParams::readTweenTable(L, "jitter", p.jitter);
+ LuaParticleParams::readTweenTable(L, "bounce", p.bounce);
+ lua_getfield(L, 1, "attract");
+ if (!lua_isnil(L, -1)) {
+ luaL_checktype(L, -1, LUA_TTABLE);
+ lua_getfield(L, -1, "kind");
+ LuaParticleParams::readLuaValue(L, p.attractor_kind);
+ lua_pop(L,1);
+
+ lua_getfield(L, -1, "die_on_contact");
+ if (!lua_isnil(L, -1))
+ p.attractor_kill = readParam<bool>(L, -1);
+ lua_pop(L,1);
+
+ if (p.attractor_kind != AttractorKind::none) {
+ LuaParticleParams::readTweenTable(L, "strength", p.attract);
+ LuaParticleParams::readTweenTable(L, "origin", p.attractor_origin);
+ p.attractor_attachment = LuaParticleParams::readAttachmentID(L, "origin_attached");
+ if (p.attractor_kind != AttractorKind::point) {
+ LuaParticleParams::readTweenTable(L, "direction", p.attractor_direction);
+ p.attractor_direction_attachment = LuaParticleParams::readAttachmentID(L, "direction_attached");
+ }
+ }
+ } else {
+ p.attractor_kind = AttractorKind::none;
+ }
+ lua_pop(L,1);
+ LuaParticleParams::readTweenTable(L, "radius", p.radius);
- p.minexptime = getfloatfield_default(L, 1, "minexptime", p.minexptime);
- p.maxexptime = getfloatfield_default(L, 1, "maxexptime", p.maxexptime);
- p.minsize = getfloatfield_default(L, 1, "minsize", p.minsize);
- p.maxsize = getfloatfield_default(L, 1, "maxsize", p.maxsize);
p.collisiondetection = getboolfield_default(L, 1,
"collisiondetection", p.collisiondetection);
p.collision_removal = getboolfield_default(L, 1,
@@ -234,11 +264,29 @@ int ModApiParticles::l_add_particlespawner(lua_State *L)
attached = ObjectRef::getobject(ref);
}
+ lua_getfield(L, 1, "texture");
+ if (!lua_isnil(L, -1)) {
+ LuaParticleParams::readTexValue(L, p.texture);
+ }
+ lua_pop(L, 1);
+
p.vertical = getboolfield_default(L, 1, "vertical", p.vertical);
- p.texture = getstringfield_default(L, 1, "texture", p.texture);
playername = getstringfield_default(L, 1, "playername", "");
p.glow = getintfield_default(L, 1, "glow", p.glow);
+ lua_getfield(L, 1, "texpool");
+ if (lua_istable(L, -1)) {
+ size_t tl = lua_objlen(L, -1);
+ p.texpool.reserve(tl);
+ for (size_t i = 0; i < tl; ++i) {
+ lua_pushinteger(L, i+1), lua_gettable(L, -2);
+ p.texpool.emplace_back();
+ LuaParticleParams::readTexValue(L, p.texpool.back());
+ lua_pop(L,1);
+ }
+ }
+ lua_pop(L, 1);
+
lua_getfield(L, 1, "node");
if (lua_istable(L, -1))
p.node = readnode(L, -1, getGameDef(L)->ndef());
diff --git a/src/script/lua_api/l_particles_local.cpp b/src/script/lua_api/l_particles_local.cpp
index cc68b13a5..62cbab8e9 100644
--- a/src/script/lua_api/l_particles_local.cpp
+++ b/src/script/lua_api/l_particles_local.cpp
@@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "common/c_converter.h"
#include "lua_api/l_internal.h"
#include "lua_api/l_object.h"
+#include "lua_api/l_particleparams.h"
#include "client/particles.h"
#include "client/client.h"
#include "client/clientevent.h"
@@ -49,6 +50,19 @@ int ModApiParticlesLocal::l_add_particle(lua_State *L)
p.acc = check_v3f(L, -1);
lua_pop(L, 1);
+ lua_getfield(L, 1, "drag");
+ if (lua_istable(L, -1))
+ p.drag = check_v3f(L, -1);
+ lua_pop(L, 1);
+
+ lua_getfield(L, 1, "jitter");
+ LuaParticleParams::readLuaValue(L, p.jitter);
+ lua_pop(L, 1);
+
+ lua_getfield(L, 1, "bounce");
+ LuaParticleParams::readLuaValue(L, p.bounce);
+ lua_pop(L, 1);
+
p.expirationtime = getfloatfield_default(L, 1, "expirationtime",
p.expirationtime);
p.size = getfloatfield_default(L, 1, "size", p.size);
@@ -64,7 +78,11 @@ int ModApiParticlesLocal::l_add_particle(lua_State *L)
p.animation = read_animation_definition(L, -1);
lua_pop(L, 1);
- p.texture = getstringfield_default(L, 1, "texture", p.texture);
+ lua_getfield(L, 1, "texture");
+ if (!lua_isnil(L, -1)) {
+ LuaParticleParams::readTexValue(L,p.texture);
+ }
+ lua_pop(L, 1);
p.glow = getintfield_default(L, 1, "glow", p.glow);
lua_getfield(L, 1, "node");
@@ -88,44 +106,50 @@ int ModApiParticlesLocal::l_add_particlespawner(lua_State *L)
// Get parameters
ParticleSpawnerParameters p;
-
p.amount = getintfield_default(L, 1, "amount", p.amount);
p.time = getfloatfield_default(L, 1, "time", p.time);
- lua_getfield(L, 1, "minpos");
- if (lua_istable(L, -1))
- p.minpos = check_v3f(L, -1);
- lua_pop(L, 1);
-
- lua_getfield(L, 1, "maxpos");
- if (lua_istable(L, -1))
- p.maxpos = check_v3f(L, -1);
- lua_pop(L, 1);
-
- lua_getfield(L, 1, "minvel");
- if (lua_istable(L, -1))
- p.minvel = check_v3f(L, -1);
- lua_pop(L, 1);
-
- lua_getfield(L, 1, "maxvel");
- if (lua_istable(L, -1))
- p.maxvel = check_v3f(L, -1);
- lua_pop(L, 1);
-
- lua_getfield(L, 1, "minacc");
- if (lua_istable(L, -1))
- p.minacc = check_v3f(L, -1);
- lua_pop(L, 1);
+ // set default values
+ p.exptime = 1;
+ p.size = 1;
+
+ // read spawner parameters from the table
+ using namespace ParticleParamTypes;
+ LuaParticleParams::readTweenTable(L, "pos", p.pos);
+ LuaParticleParams::readTweenTable(L, "vel", p.vel);
+ LuaParticleParams::readTweenTable(L, "acc", p.acc);
+ LuaParticleParams::readTweenTable(L, "size", p.size);
+ LuaParticleParams::readTweenTable(L, "exptime", p.exptime);
+ LuaParticleParams::readTweenTable(L, "drag", p.drag);
+ LuaParticleParams::readTweenTable(L, "jitter", p.jitter);
+ LuaParticleParams::readTweenTable(L, "bounce", p.bounce);
+ lua_getfield(L, 1, "attract");
+ if (!lua_isnil(L, -1)) {
+ luaL_checktype(L, -1, LUA_TTABLE);
+ lua_getfield(L, -1, "kind");
+ LuaParticleParams::readLuaValue(L, p.attractor_kind);
+ lua_pop(L,1);
+
+ lua_getfield(L, -1, "die_on_contact");
+ if (!lua_isnil(L, -1))
+ p.attractor_kill = readParam<bool>(L, -1);
+ lua_pop(L,1);
+
+ if (p.attractor_kind != AttractorKind::none) {
+ LuaParticleParams::readTweenTable(L, "strength", p.attract);
+ LuaParticleParams::readTweenTable(L, "origin", p.attractor_origin);
+ p.attractor_attachment = LuaParticleParams::readAttachmentID(L, "origin_attached");
+ if (p.attractor_kind != AttractorKind::point) {
+ LuaParticleParams::readTweenTable(L, "direction", p.attractor_direction);
+ p.attractor_direction_attachment = LuaParticleParams::readAttachmentID(L, "direction_attached");
+ }
+ }
+ } else {
+ p.attractor_kind = AttractorKind::none;
+ }
+ lua_pop(L,1);
+ LuaParticleParams::readTweenTable(L, "radius", p.radius);
- lua_getfield(L, 1, "maxacc");
- if (lua_istable(L, -1))
- p.maxacc = check_v3f(L, -1);
- lua_pop(L, 1);
-
- p.minexptime = getfloatfield_default(L, 1, "minexptime", p.minexptime);
- p.maxexptime = getfloatfield_default(L, 1, "maxexptime", p.maxexptime);
- p.minsize = getfloatfield_default(L, 1, "minsize", p.minsize);
- p.maxsize = getfloatfield_default(L, 1, "maxsize", p.maxsize);
p.collisiondetection = getboolfield_default(L, 1,
"collisiondetection", p.collisiondetection);
p.collision_removal = getboolfield_default(L, 1,
@@ -137,10 +161,28 @@ int ModApiParticlesLocal::l_add_particlespawner(lua_State *L)
p.animation = read_animation_definition(L, -1);
lua_pop(L, 1);
+ lua_getfield(L, 1, "texture");
+ if (!lua_isnil(L, -1)) {
+ LuaParticleParams::readTexValue(L, p.texture);
+ }
+ lua_pop(L, 1);
+
p.vertical = getboolfield_default(L, 1, "vertical", p.vertical);
- p.texture = getstringfield_default(L, 1, "texture", p.texture);
p.glow = getintfield_default(L, 1, "glow", p.glow);
+ lua_getfield(L, 1, "texpool");
+ if (lua_istable(L, -1)) {
+ size_t tl = lua_objlen(L, -1);
+ p.texpool.reserve(tl);
+ for (size_t i = 0; i < tl; ++i) {
+ lua_pushinteger(L, i+1), lua_gettable(L, -2);
+ p.texpool.emplace_back();
+ LuaParticleParams::readTexValue(L, p.texpool.back());
+ lua_pop(L,1);
+ }
+ }
+ lua_pop(L, 1);
+
lua_getfield(L, 1, "node");
if (lua_istable(L, -1))
p.node = readnode(L, -1, getGameDef(L)->ndef());
diff --git a/src/script/lua_api/l_server.cpp b/src/script/lua_api/l_server.cpp
index 88ab5e16b..a5daae346 100644
--- a/src/script/lua_api/l_server.cpp
+++ b/src/script/lua_api/l_server.cpp
@@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "lua_api/l_internal.h"
#include "common/c_converter.h"
#include "common/c_content.h"
+#include "common/c_packer.h"
#include "cpp_api/s_base.h"
#include "cpp_api/s_security.h"
#include "scripting_server.h"
@@ -61,11 +62,8 @@ int ModApiServer::l_get_server_uptime(lua_State *L)
int ModApiServer::l_get_server_max_lag(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
- ServerEnvironment *s_env = dynamic_cast<ServerEnvironment *>(getEnv(L));
- if (!s_env)
- lua_pushnil(L);
- else
- lua_pushnumber(L, s_env->getMaxLagEstimate());
+ GET_ENV_PTR;
+ lua_pushnumber(L, env->getMaxLagEstimate());
return 1;
}
@@ -325,12 +323,15 @@ int ModApiServer::l_disconnect_player(lua_State *L)
else
message.append("Disconnected.");
- RemotePlayer *player = dynamic_cast<ServerEnvironment *>(getEnv(L))->getPlayer(name);
- if (player == NULL) {
+ Server *server = getServer(L);
+
+ RemotePlayer *player = server->getEnv().getPlayer(name);
+ if (!player) {
lua_pushboolean(L, false); // No such player
return 1;
}
- getServer(L)->DenyAccess_Legacy(player->getPeerId(), utf8_to_wide(message));
+
+ server->DenyAccess(player->getPeerId(), SERVER_ACCESSDENIED_CUSTOM_STRING, message);
lua_pushboolean(L, true);
return 1;
}
@@ -392,12 +393,11 @@ int ModApiServer::l_get_modpath(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
std::string modname = luaL_checkstring(L, 1);
- const ModSpec *mod = getServer(L)->getModSpec(modname);
- if (!mod) {
+ const ModSpec *mod = getGameDef(L)->getModSpec(modname);
+ if (!mod)
lua_pushnil(L);
- return 1;
- }
- lua_pushstring(L, mod->path.c_str());
+ else
+ lua_pushstring(L, mod->path.c_str());
return 1;
}
@@ -409,13 +409,14 @@ int ModApiServer::l_get_modnames(lua_State *L)
// Get a list of mods
std::vector<std::string> modlist;
- getServer(L)->getModNames(modlist);
+ for (auto &it : getGameDef(L)->getMods())
+ modlist.emplace_back(it.name);
std::sort(modlist.begin(), modlist.end());
// Package them up for Lua
lua_createtable(L, modlist.size(), 0);
- std::vector<std::string>::iterator iter = modlist.begin();
+ auto iter = modlist.begin();
for (u16 i = 0; iter != modlist.end(); ++iter) {
lua_pushstring(L, iter->c_str());
lua_rawseti(L, -2, ++i);
@@ -427,8 +428,8 @@ int ModApiServer::l_get_modnames(lua_State *L)
int ModApiServer::l_get_worldpath(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
- std::string worldpath = getServer(L)->getWorldPath();
- lua_pushstring(L, worldpath.c_str());
+ const Server *srv = getServer(L);
+ lua_pushstring(L, srv->getWorldPath().c_str());
return 1;
}
@@ -436,16 +437,15 @@ int ModApiServer::l_get_worldpath(lua_State *L)
int ModApiServer::l_sound_play(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
- SimpleSoundSpec spec;
- read_soundspec(L, 1, spec);
- ServerSoundParams params;
+ ServerPlayingSound params;
+ read_soundspec(L, 1, params.spec);
read_server_sound_params(L, 2, params);
bool ephemeral = lua_gettop(L) > 2 && readParam<bool>(L, 3);
if (ephemeral) {
- getServer(L)->playSound(spec, params, true);
+ getServer(L)->playSound(params, true);
lua_pushnil(L);
} else {
- s32 handle = getServer(L)->playSound(spec, params);
+ s32 handle = getServer(L)->playSound(params);
lua_pushinteger(L, handle);
}
return 1;
@@ -510,7 +510,8 @@ int ModApiServer::l_dynamic_add_media(lua_State *L)
int ModApiServer::l_is_singleplayer(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
- lua_pushboolean(L, getServer(L)->isSingleplayer());
+ const Server *srv = getServer(L);
+ lua_pushboolean(L, srv->isSingleplayer());
return 1;
}
@@ -525,6 +526,76 @@ int ModApiServer::l_notify_authentication_modified(lua_State *L)
return 0;
}
+// do_async_callback(func, params, mod_origin)
+int ModApiServer::l_do_async_callback(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+ ServerScripting *script = getScriptApi<ServerScripting>(L);
+
+ luaL_checktype(L, 1, LUA_TFUNCTION);
+ luaL_checktype(L, 2, LUA_TTABLE);
+ luaL_checktype(L, 3, LUA_TSTRING);
+
+ call_string_dump(L, 1);
+ size_t func_length;
+ const char *serialized_func_raw = lua_tolstring(L, -1, &func_length);
+
+ PackedValue *param = script_pack(L, 2);
+
+ std::string mod_origin = readParam<std::string>(L, 3);
+
+ u32 jobId = script->queueAsync(
+ std::string(serialized_func_raw, func_length),
+ param, mod_origin);
+
+ lua_settop(L, 0);
+ lua_pushinteger(L, jobId);
+ return 1;
+}
+
+// register_async_dofile(path)
+int ModApiServer::l_register_async_dofile(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+
+ std::string path = readParam<std::string>(L, 1);
+ CHECK_SECURE_PATH(L, path.c_str(), false);
+
+ // Find currently running mod name (only at init time)
+ lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
+ if (!lua_isstring(L, -1))
+ return 0;
+ std::string modname = readParam<std::string>(L, -1);
+
+ getServer(L)->m_async_init_files.emplace_back(modname, path);
+ lua_pushboolean(L, true);
+ return 1;
+}
+
+// serialize_roundtrip(value)
+// Meant for unit testing the packer from Lua
+int ModApiServer::l_serialize_roundtrip(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+
+ int top = lua_gettop(L);
+ auto *pv = script_pack(L, 1);
+ if (top != lua_gettop(L))
+ throw LuaError("stack values leaked");
+
+#ifndef NDEBUG
+ script_dump_packed(pv);
+#endif
+
+ top = lua_gettop(L);
+ script_unpack(L, pv);
+ delete pv;
+ if (top + 1 != lua_gettop(L))
+ throw LuaError("stack values leaked");
+
+ return 1;
+}
+
void ModApiServer::Initialize(lua_State *L, int top)
{
API_FCT(request_shutdown);
@@ -558,4 +629,18 @@ void ModApiServer::Initialize(lua_State *L, int top)
API_FCT(remove_player);
API_FCT(unban_player_or_ip);
API_FCT(notify_authentication_modified);
+
+ API_FCT(do_async_callback);
+ API_FCT(register_async_dofile);
+ API_FCT(serialize_roundtrip);
+}
+
+void ModApiServer::InitializeAsync(lua_State *L, int top)
+{
+ API_FCT(get_worldpath);
+ API_FCT(is_singleplayer);
+
+ API_FCT(get_current_modname);
+ API_FCT(get_modpath);
+ API_FCT(get_modnames);
}
diff --git a/src/script/lua_api/l_server.h b/src/script/lua_api/l_server.h
index f05c0b7c9..a4f38c34e 100644
--- a/src/script/lua_api/l_server.h
+++ b/src/script/lua_api/l_server.h
@@ -106,6 +106,16 @@ private:
// notify_authentication_modified(name)
static int l_notify_authentication_modified(lua_State *L);
+ // do_async_callback(func, params, mod_origin)
+ static int l_do_async_callback(lua_State *L);
+
+ // register_async_dofile(path)
+ static int l_register_async_dofile(lua_State *L);
+
+ // serialize_roundtrip(obj)
+ static int l_serialize_roundtrip(lua_State *L);
+
public:
static void Initialize(lua_State *L, int top);
+ static void InitializeAsync(lua_State *L, int top);
};
diff --git a/src/script/lua_api/l_settings.cpp b/src/script/lua_api/l_settings.cpp
index 14398dda2..3f3fda56e 100644
--- a/src/script/lua_api/l_settings.cpp
+++ b/src/script/lua_api/l_settings.cpp
@@ -27,9 +27,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "log.h"
-/* This protects:
- * 'secure.*' settings from being set
- * some mapgen settings from being set
+/* This protects the following from being set:
+ * 'secure.*' settings
+ * some security-relevant settings
+ * (better solution pending)
+ * some mapgen settings
* (not security-criticial, just to avoid messing up user configs)
*/
#define CHECK_SETTING_SECURITY(L, name) \
@@ -41,7 +43,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
static inline int checkSettingSecurity(lua_State* L, const std::string &name)
{
if (ScriptApiSecurity::isSecure(L) && name.compare(0, 7, "secure.") == 0)
- throw LuaError("Attempt to set secure setting.");
+ throw LuaError("Attempted to set secure setting.");
bool is_mainmenu = false;
#ifndef SERVER
@@ -54,6 +56,17 @@ static inline int checkSettingSecurity(lua_State* L, const std::string &name)
return -1;
}
+ const char *disallowed[] = {
+ "main_menu_script", "shader_path", "texture_path", "screenshot_path",
+ "serverlist_file", "serverlist_url", "map-dir", "contentdb_url",
+ };
+ if (!is_mainmenu) {
+ for (const char *name2 : disallowed) {
+ if (name == name2)
+ throw LuaError("Attempted to set disallowed setting.");
+ }
+ }
+
return 0;
}
diff --git a/src/script/lua_api/l_sound.cpp b/src/script/lua_api/l_sound.cpp
index b86eda53e..934b4a07e 100644
--- a/src/script/lua_api/l_sound.cpp
+++ b/src/script/lua_api/l_sound.cpp
@@ -28,9 +28,9 @@ int ModApiSound::l_sound_play(lua_State *L)
{
SimpleSoundSpec spec;
read_soundspec(L, 1, spec);
- bool looped = readParam<bool>(L, 2);
+ spec.loop = readParam<bool>(L, 2);
- s32 handle = getGuiEngine(L)->playSound(spec, looped);
+ s32 handle = getGuiEngine(L)->playSound(spec);
lua_pushinteger(L, handle);
diff --git a/src/script/lua_api/l_storage.cpp b/src/script/lua_api/l_storage.cpp
index b8f4347a8..b6c53e353 100644
--- a/src/script/lua_api/l_storage.cpp
+++ b/src/script/lua_api/l_storage.cpp
@@ -25,12 +25,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
int ModApiStorage::l_get_mod_storage(lua_State *L)
{
- lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
- if (!lua_isstring(L, -1)) {
- return 0;
- }
-
- std::string mod_name = readParam<std::string>(L, -1);
+ // Note that this is wrapped in Lua, see builtin/common/mod_storage.lua
+ std::string mod_name = readParam<std::string>(L, 1);
ModMetadata *store = nullptr;
diff --git a/src/script/lua_api/l_util.cpp b/src/script/lua_api/l_util.cpp
index b04f26fda..f602aed99 100644
--- a/src/script/lua_api/l_util.cpp
+++ b/src/script/lua_api/l_util.cpp
@@ -159,6 +159,17 @@ int ModApiUtil::l_write_json(lua_State *L)
return 1;
}
+// get_tool_wear_after_use(uses[, initial_wear])
+int ModApiUtil::l_get_tool_wear_after_use(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+ u32 uses = readParam<int>(L, 1);
+ u16 initial_wear = readParam<int>(L, 2, 0);
+ u16 wear = calculateResultWear(uses, initial_wear);
+ lua_pushnumber(L, wear);
+ return 1;
+}
+
// get_dig_params(groups, tool_capabilities[, wear])
int ModApiUtil::l_get_dig_params(lua_State *L)
{
@@ -469,6 +480,8 @@ int ModApiUtil::l_get_version(lua_State *L)
lua_setfield(L, table, "hash");
}
+ lua_pushboolean(L, DEVELOPMENT_BUILD);
+ lua_setfield(L, table, "is_dev");
return 1;
}
@@ -586,6 +599,7 @@ void ModApiUtil::Initialize(lua_State *L, int top)
API_FCT(parse_json);
API_FCT(write_json);
+ API_FCT(get_tool_wear_after_use);
API_FCT(get_dig_params);
API_FCT(get_hit_params);
@@ -647,6 +661,9 @@ void ModApiUtil::InitializeClient(lua_State *L, int top)
API_FCT(sha1);
API_FCT(colorspec_to_colorstring);
API_FCT(colorspec_to_bytes);
+
+ LuaSettings::create(L, g_settings, g_settings_path);
+ lua_setfield(L, top, "settings");
}
void ModApiUtil::InitializeAsync(lua_State *L, int top)
@@ -671,6 +688,9 @@ void ModApiUtil::InitializeAsync(lua_State *L, int top)
API_FCT(cpdir);
API_FCT(mvdir);
API_FCT(get_dir_list);
+ API_FCT(safe_file_write);
+
+ API_FCT(request_insecure_environment);
API_FCT(encode_base64);
API_FCT(decode_base64);
@@ -680,6 +700,8 @@ void ModApiUtil::InitializeAsync(lua_State *L, int top)
API_FCT(colorspec_to_colorstring);
API_FCT(colorspec_to_bytes);
+ API_FCT(encode_png);
+
API_FCT(get_last_run_mod);
API_FCT(set_last_run_mod);
diff --git a/src/script/lua_api/l_util.h b/src/script/lua_api/l_util.h
index fcf8a1057..ec86c6632 100644
--- a/src/script/lua_api/l_util.h
+++ b/src/script/lua_api/l_util.h
@@ -50,6 +50,9 @@ private:
// write_json(data[, styled])
static int l_write_json(lua_State *L);
+ // get_tool_wear_after_use(uses[, initial_wear])
+ static int l_get_tool_wear_after_use(lua_State *L);
+
// get_dig_params(groups, tool_capabilities[, wear])
static int l_get_dig_params(lua_State *L);
@@ -129,6 +132,4 @@ public:
static void Initialize(lua_State *L, int top);
static void InitializeAsync(lua_State *L, int top);
static void InitializeClient(lua_State *L, int top);
-
- static void InitializeAsync(AsyncEngine &engine);
};
diff --git a/src/script/lua_api/l_vmanip.cpp b/src/script/lua_api/l_vmanip.cpp
index e040e545b..6187a47db 100644
--- a/src/script/lua_api/l_vmanip.cpp
+++ b/src/script/lua_api/l_vmanip.cpp
@@ -17,11 +17,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-
+#include <map>
#include "lua_api/l_vmanip.h"
#include "lua_api/l_internal.h"
#include "common/c_content.h"
#include "common/c_converter.h"
+#include "common/c_packer.h"
#include "emerge.h"
#include "environment.h"
#include "map.h"
@@ -45,6 +46,8 @@ int LuaVoxelManip::l_read_from_map(lua_State *L)
LuaVoxelManip *o = checkobject(L, 1);
MMVManip *vm = o->vm;
+ if (vm->isOrphan())
+ return 0;
v3s16 bp1 = getNodeBlockPos(check_v3s16(L, 2));
v3s16 bp2 = getNodeBlockPos(check_v3s16(L, 3));
@@ -112,23 +115,23 @@ int LuaVoxelManip::l_write_to_map(lua_State *L)
LuaVoxelManip *o = checkobject(L, 1);
bool update_light = !lua_isboolean(L, 2) || readParam<bool>(L, 2);
+
GET_ENV_PTR;
ServerMap *map = &(env->getServerMap());
+
+ std::map<v3s16, MapBlock*> modified_blocks;
if (o->is_mapgen_vm || !update_light) {
- o->vm->blitBackAll(&(o->modified_blocks));
+ o->vm->blitBackAll(&modified_blocks);
} else {
- voxalgo::blit_back_with_light(map, o->vm,
- &(o->modified_blocks));
+ voxalgo::blit_back_with_light(map, o->vm, &modified_blocks);
}
MapEditEvent event;
event.type = MEET_OTHER;
- for (const auto &modified_block : o->modified_blocks)
- event.modified_blocks.insert(modified_block.first);
-
+ for (const auto &it : modified_blocks)
+ event.modified_blocks.insert(it.first);
map->dispatchEvent(event);
- o->modified_blocks.clear();
return 0;
}
@@ -166,7 +169,7 @@ int LuaVoxelManip::l_update_liquids(lua_State *L)
LuaVoxelManip *o = checkobject(L, 1);
- Map *map = &(env->getMap());
+ ServerMap *map = &(env->getServerMap());
const NodeDefManager *ndef = getServer(L)->getNodeDefManager();
MMVManip *vm = o->vm;
@@ -429,6 +432,34 @@ LuaVoxelManip *LuaVoxelManip::checkobject(lua_State *L, int narg)
return *(LuaVoxelManip **)ud; // unbox pointer
}
+void *LuaVoxelManip::packIn(lua_State *L, int idx)
+{
+ LuaVoxelManip *o = checkobject(L, idx);
+
+ if (o->is_mapgen_vm)
+ throw LuaError("nope");
+ return o->vm->clone();
+}
+
+void LuaVoxelManip::packOut(lua_State *L, void *ptr)
+{
+ MMVManip *vm = reinterpret_cast<MMVManip*>(ptr);
+ if (!L) {
+ delete vm;
+ return;
+ }
+
+ // Associate vmanip with map if the Lua env has one
+ Environment *env = getEnv(L);
+ if (env)
+ vm->reparent(&(env->getMap()));
+
+ LuaVoxelManip *o = new LuaVoxelManip(vm, false);
+ *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
+ luaL_getmetatable(L, className);
+ lua_setmetatable(L, -2);
+}
+
void LuaVoxelManip::Register(lua_State *L)
{
lua_newtable(L);
@@ -455,6 +486,8 @@ void LuaVoxelManip::Register(lua_State *L)
// Can be created from Lua (VoxelManip())
lua_register(L, className, create_object);
+
+ script_register_packer(L, className, packIn, packOut);
}
const char LuaVoxelManip::className[] = "VoxelManip";
diff --git a/src/script/lua_api/l_vmanip.h b/src/script/lua_api/l_vmanip.h
index 15ab9eef8..005133335 100644
--- a/src/script/lua_api/l_vmanip.h
+++ b/src/script/lua_api/l_vmanip.h
@@ -19,7 +19,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#pragma once
-#include <map>
#include "irr_v3d.h"
#include "lua_api/l_base.h"
@@ -33,7 +32,6 @@ class MMVManip;
class LuaVoxelManip : public ModApiBase
{
private:
- std::map<v3s16, MapBlock *> modified_blocks;
bool is_mapgen_vm = false;
static const char className[];
@@ -77,5 +75,8 @@ public:
static LuaVoxelManip *checkobject(lua_State *L, int narg);
+ static void *packIn(lua_State *L, int idx);
+ static void packOut(lua_State *L, void *ptr);
+
static void Register(lua_State *L);
};