]> git.lizzy.rs Git - minetest.git/blob - src/script/common/c_content.cpp
4be6457d8eb3f6536eed8188806a9b9f7cf897bd
[minetest.git] / src / script / common / c_content.cpp
1 /*
2 Minetest
3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 #include "common/c_content.h"
20 #include "common/c_converter.h"
21 #include "common/c_types.h"
22 #include "nodedef.h"
23 #include "object_properties.h"
24 #include "collision.h"
25 #include "cpp_api/s_node.h"
26 #include "lua_api/l_object.h"
27 #include "lua_api/l_item.h"
28 #include "common/c_internal.h"
29 #include "server.h"
30 #include "log.h"
31 #include "tool.h"
32 #include "porting.h"
33 #include "mapgen/mg_schematic.h"
34 #include "noise.h"
35 #include "server/player_sao.h"
36 #include "util/pointedthing.h"
37 #include "debug.h" // For FATAL_ERROR
38 #include <json/json.h>
39
40 struct EnumString es_TileAnimationType[] =
41 {
42         {TAT_NONE, "none"},
43         {TAT_VERTICAL_FRAMES, "vertical_frames"},
44         {TAT_SHEET_2D, "sheet_2d"},
45         {0, nullptr},
46 };
47
48 /******************************************************************************/
49 void read_item_definition(lua_State* L, int index,
50                 const ItemDefinition &default_def, ItemDefinition &def)
51 {
52         if (index < 0)
53                 index = lua_gettop(L) + 1 + index;
54
55         def.type = (ItemType)getenumfield(L, index, "type",
56                         es_ItemType, ITEM_NONE);
57         getstringfield(L, index, "name", def.name);
58         getstringfield(L, index, "description", def.description);
59         getstringfield(L, index, "short_description", def.short_description);
60         getstringfield(L, index, "inventory_image", def.inventory_image);
61         getstringfield(L, index, "inventory_overlay", def.inventory_overlay);
62         getstringfield(L, index, "wield_image", def.wield_image);
63         getstringfield(L, index, "wield_overlay", def.wield_overlay);
64         getstringfield(L, index, "palette", def.palette_image);
65
66         // Read item color.
67         lua_getfield(L, index, "color");
68         read_color(L, -1, &def.color);
69         lua_pop(L, 1);
70
71         lua_getfield(L, index, "wield_scale");
72         if(lua_istable(L, -1)){
73                 def.wield_scale = check_v3f(L, -1);
74         }
75         lua_pop(L, 1);
76
77         int stack_max = getintfield_default(L, index, "stack_max", def.stack_max);
78         def.stack_max = rangelim(stack_max, 1, U16_MAX);
79
80         lua_getfield(L, index, "on_use");
81         def.usable = lua_isfunction(L, -1);
82         lua_pop(L, 1);
83
84         getboolfield(L, index, "liquids_pointable", def.liquids_pointable);
85
86         lua_getfield(L, index, "tool_capabilities");
87         if(lua_istable(L, -1)){
88                 def.tool_capabilities = new ToolCapabilities(
89                                 read_tool_capabilities(L, -1));
90         }
91
92         // If name is "" (hand), ensure there are ToolCapabilities
93         // because it will be looked up there whenever any other item has
94         // no ToolCapabilities
95         if (def.name.empty() && def.tool_capabilities == NULL){
96                 def.tool_capabilities = new ToolCapabilities();
97         }
98
99         lua_getfield(L, index, "groups");
100         read_groups(L, -1, def.groups);
101         lua_pop(L, 1);
102
103         lua_getfield(L, index, "sounds");
104         if (!lua_isnil(L, -1)) {
105                 luaL_checktype(L, -1, LUA_TTABLE);
106                 lua_getfield(L, -1, "place");
107                 read_soundspec(L, -1, def.sound_place);
108                 lua_pop(L, 1);
109                 lua_getfield(L, -1, "place_failed");
110                 read_soundspec(L, -1, def.sound_place_failed);
111                 lua_pop(L, 1);
112         }
113         lua_pop(L, 1);
114
115         // No, this is not a mistake. Item sounds are in "sound", node sounds in "sounds".
116         lua_getfield(L, index, "sound");
117         if (!lua_isnil(L, -1)) {
118                 luaL_checktype(L, -1, LUA_TTABLE);
119                 lua_getfield(L, -1, "punch_use");
120                 read_soundspec(L, -1, def.sound_use);
121                 lua_pop(L, 1);
122                 lua_getfield(L, -1, "punch_use_air");
123                 read_soundspec(L, -1, def.sound_use_air);
124                 lua_pop(L, 1);
125         }
126         lua_pop(L, 1);
127
128         def.range = getfloatfield_default(L, index, "range", def.range);
129
130         // Client shall immediately place this node when player places the item.
131         // Server will update the precise end result a moment later.
132         // "" = no prediction
133         getstringfield(L, index, "node_placement_prediction",
134                         def.node_placement_prediction);
135
136         getintfield(L, index, "place_param2", def.place_param2);
137 }
138
139 /******************************************************************************/
140 void push_item_definition(lua_State *L, const ItemDefinition &i)
141 {
142         lua_newtable(L);
143         lua_pushstring(L, i.name.c_str());
144         lua_setfield(L, -2, "name");
145         lua_pushstring(L, i.description.c_str());
146         lua_setfield(L, -2, "description");
147 }
148
149 void push_item_definition_full(lua_State *L, const ItemDefinition &i)
150 {
151         std::string type(es_ItemType[(int)i.type].str);
152
153         lua_newtable(L);
154         lua_pushstring(L, i.name.c_str());
155         lua_setfield(L, -2, "name");
156         lua_pushstring(L, i.description.c_str());
157         lua_setfield(L, -2, "description");
158         if (!i.short_description.empty()) {
159                 lua_pushstring(L, i.short_description.c_str());
160                 lua_setfield(L, -2, "short_description");
161         }
162         lua_pushstring(L, type.c_str());
163         lua_setfield(L, -2, "type");
164         lua_pushstring(L, i.inventory_image.c_str());
165         lua_setfield(L, -2, "inventory_image");
166         lua_pushstring(L, i.inventory_overlay.c_str());
167         lua_setfield(L, -2, "inventory_overlay");
168         lua_pushstring(L, i.wield_image.c_str());
169         lua_setfield(L, -2, "wield_image");
170         lua_pushstring(L, i.wield_overlay.c_str());
171         lua_setfield(L, -2, "wield_overlay");
172         lua_pushstring(L, i.palette_image.c_str());
173         lua_setfield(L, -2, "palette_image");
174         push_ARGB8(L, i.color);
175         lua_setfield(L, -2, "color");
176         push_v3f(L, i.wield_scale);
177         lua_setfield(L, -2, "wield_scale");
178         lua_pushinteger(L, i.stack_max);
179         lua_setfield(L, -2, "stack_max");
180         lua_pushboolean(L, i.usable);
181         lua_setfield(L, -2, "usable");
182         lua_pushboolean(L, i.liquids_pointable);
183         lua_setfield(L, -2, "liquids_pointable");
184         if (i.tool_capabilities) {
185                 push_tool_capabilities(L, *i.tool_capabilities);
186                 lua_setfield(L, -2, "tool_capabilities");
187         }
188         push_groups(L, i.groups);
189         lua_setfield(L, -2, "groups");
190         push_soundspec(L, i.sound_place);
191         lua_setfield(L, -2, "sound_place");
192         push_soundspec(L, i.sound_place_failed);
193         lua_setfield(L, -2, "sound_place_failed");
194         lua_pushstring(L, i.node_placement_prediction.c_str());
195         lua_setfield(L, -2, "node_placement_prediction");
196 }
197
198 /******************************************************************************/
199 void read_object_properties(lua_State *L, int index,
200                 ServerActiveObject *sao, ObjectProperties *prop, IItemDefManager *idef)
201 {
202         if(index < 0)
203                 index = lua_gettop(L) + 1 + index;
204         if (lua_isnil(L, index))
205                 return;
206
207         luaL_checktype(L, -1, LUA_TTABLE);
208
209         int hp_max = 0;
210         if (getintfield(L, -1, "hp_max", hp_max)) {
211                 prop->hp_max = (u16)rangelim(hp_max, 0, U16_MAX);
212                 // hp_max = 0 is sometimes used as a hack to keep players dead, only validate for entities
213                 if (prop->hp_max == 0 && sao->getType() != ACTIVEOBJECT_TYPE_PLAYER)
214                         throw LuaError("The hp_max property may not be 0 for entities!");
215
216                 if (prop->hp_max < sao->getHP()) {
217                         PlayerHPChangeReason reason(PlayerHPChangeReason::SET_HP_MAX);
218                         sao->setHP(prop->hp_max, reason);
219                 }
220         }
221
222         if (getintfield(L, -1, "breath_max", prop->breath_max)) {
223                 if (sao->getType() == ACTIVEOBJECT_TYPE_PLAYER) {
224                         PlayerSAO *player = (PlayerSAO *)sao;
225                         if (prop->breath_max < player->getBreath())
226                                 player->setBreath(prop->breath_max);
227                 }
228         }
229         getboolfield(L, -1, "physical", prop->physical);
230         getboolfield(L, -1, "collide_with_objects", prop->collideWithObjects);
231
232         lua_getfield(L, -1, "collisionbox");
233         bool collisionbox_defined = lua_istable(L, -1);
234         if (collisionbox_defined)
235                 prop->collisionbox = read_aabb3f(L, -1, 1.0);
236         lua_pop(L, 1);
237
238         lua_getfield(L, -1, "selectionbox");
239         if (lua_istable(L, -1)) {
240                 getboolfield(L, -1, "rotate", prop->rotate_selectionbox);
241                 prop->selectionbox = read_aabb3f(L, -1, 1.0);
242         } else if (collisionbox_defined) {
243                 prop->selectionbox = prop->collisionbox;
244         }
245         lua_pop(L, 1);
246
247         getboolfield(L, -1, "pointable", prop->pointable);
248         getstringfield(L, -1, "visual", prop->visual);
249
250         getstringfield(L, -1, "mesh", prop->mesh);
251
252         lua_getfield(L, -1, "visual_size");
253         if (lua_istable(L, -1)) {
254                 // Backwards compatibility: Also accept { x = ?, y = ? }
255                 v2f scale_xy = read_v2f(L, -1);
256
257                 f32 scale_z = scale_xy.X;
258                 lua_getfield(L, -1, "z");
259                 if (lua_isnumber(L, -1))
260                         scale_z = lua_tonumber(L, -1);
261                 lua_pop(L, 1);
262
263                 prop->visual_size = v3f(scale_xy.X, scale_xy.Y, scale_z);
264         }
265         lua_pop(L, 1);
266
267         lua_getfield(L, -1, "textures");
268         if(lua_istable(L, -1)){
269                 prop->textures.clear();
270                 int table = lua_gettop(L);
271                 lua_pushnil(L);
272                 while(lua_next(L, table) != 0){
273                         // key at index -2 and value at index -1
274                         if(lua_isstring(L, -1))
275                                 prop->textures.emplace_back(lua_tostring(L, -1));
276                         else
277                                 prop->textures.emplace_back("");
278                         // removes value, keeps key for next iteration
279                         lua_pop(L, 1);
280                 }
281         }
282         lua_pop(L, 1);
283
284         lua_getfield(L, -1, "colors");
285         if (lua_istable(L, -1)) {
286                 int table = lua_gettop(L);
287                 prop->colors.clear();
288                 for (lua_pushnil(L); lua_next(L, table); lua_pop(L, 1)) {
289                         video::SColor color(255, 255, 255, 255);
290                         read_color(L, -1, &color);
291                         prop->colors.push_back(color);
292                 }
293         }
294         lua_pop(L, 1);
295
296         lua_getfield(L, -1, "spritediv");
297         if(lua_istable(L, -1))
298                 prop->spritediv = read_v2s16(L, -1);
299         lua_pop(L, 1);
300
301         lua_getfield(L, -1, "initial_sprite_basepos");
302         if(lua_istable(L, -1))
303                 prop->initial_sprite_basepos = read_v2s16(L, -1);
304         lua_pop(L, 1);
305
306         getboolfield(L, -1, "is_visible", prop->is_visible);
307         getboolfield(L, -1, "makes_footstep_sound", prop->makes_footstep_sound);
308         if (getfloatfield(L, -1, "stepheight", prop->stepheight))
309                 prop->stepheight *= BS;
310         getfloatfield(L, -1, "eye_height", prop->eye_height);
311
312         getfloatfield(L, -1, "automatic_rotate", prop->automatic_rotate);
313         lua_getfield(L, -1, "automatic_face_movement_dir");
314         if (lua_isnumber(L, -1)) {
315                 prop->automatic_face_movement_dir = true;
316                 prop->automatic_face_movement_dir_offset = luaL_checknumber(L, -1);
317         } else if (lua_isboolean(L, -1)) {
318                 prop->automatic_face_movement_dir = lua_toboolean(L, -1);
319                 prop->automatic_face_movement_dir_offset = 0.0;
320         }
321         lua_pop(L, 1);
322         getboolfield(L, -1, "backface_culling", prop->backface_culling);
323         getintfield(L, -1, "glow", prop->glow);
324
325         getstringfield(L, -1, "nametag", prop->nametag);
326         lua_getfield(L, -1, "nametag_color");
327         if (!lua_isnil(L, -1)) {
328                 video::SColor color = prop->nametag_color;
329                 if (read_color(L, -1, &color))
330                         prop->nametag_color = color;
331         }
332         lua_pop(L, 1);
333         lua_getfield(L, -1, "nametag_bgcolor");
334         if (!lua_isnil(L, -1)) {
335                 if (lua_toboolean(L, -1)) {
336                         video::SColor color;
337                         if (read_color(L, -1, &color))
338                                 prop->nametag_bgcolor = color;
339                 } else {
340                         prop->nametag_bgcolor = nullopt;
341                 }
342         }
343         lua_pop(L, 1);
344
345         lua_getfield(L, -1, "automatic_face_movement_max_rotation_per_sec");
346         if (lua_isnumber(L, -1)) {
347                 prop->automatic_face_movement_max_rotation_per_sec = luaL_checknumber(L, -1);
348         }
349         lua_pop(L, 1);
350
351         getstringfield(L, -1, "infotext", prop->infotext);
352         getboolfield(L, -1, "static_save", prop->static_save);
353
354         lua_getfield(L, -1, "wield_item");
355         if (!lua_isnil(L, -1))
356                 prop->wield_item = read_item(L, -1, idef).getItemString();
357         lua_pop(L, 1);
358
359         getfloatfield(L, -1, "zoom_fov", prop->zoom_fov);
360         getboolfield(L, -1, "use_texture_alpha", prop->use_texture_alpha);
361         getboolfield(L, -1, "shaded", prop->shaded);
362         getboolfield(L, -1, "show_on_minimap", prop->show_on_minimap);
363
364         getstringfield(L, -1, "damage_texture_modifier", prop->damage_texture_modifier);
365 }
366
367 /******************************************************************************/
368 void push_object_properties(lua_State *L, ObjectProperties *prop)
369 {
370         lua_newtable(L);
371         lua_pushnumber(L, prop->hp_max);
372         lua_setfield(L, -2, "hp_max");
373         lua_pushnumber(L, prop->breath_max);
374         lua_setfield(L, -2, "breath_max");
375         lua_pushboolean(L, prop->physical);
376         lua_setfield(L, -2, "physical");
377         lua_pushboolean(L, prop->collideWithObjects);
378         lua_setfield(L, -2, "collide_with_objects");
379         push_aabb3f(L, prop->collisionbox);
380         lua_setfield(L, -2, "collisionbox");
381         push_aabb3f(L, prop->selectionbox);
382         lua_pushboolean(L, prop->rotate_selectionbox);
383         lua_setfield(L, -2, "rotate");
384         lua_setfield(L, -2, "selectionbox");
385         lua_pushboolean(L, prop->pointable);
386         lua_setfield(L, -2, "pointable");
387         lua_pushlstring(L, prop->visual.c_str(), prop->visual.size());
388         lua_setfield(L, -2, "visual");
389         lua_pushlstring(L, prop->mesh.c_str(), prop->mesh.size());
390         lua_setfield(L, -2, "mesh");
391         push_v3f(L, prop->visual_size);
392         lua_setfield(L, -2, "visual_size");
393
394         lua_createtable(L, prop->textures.size(), 0);
395         u16 i = 1;
396         for (const std::string &texture : prop->textures) {
397                 lua_pushlstring(L, texture.c_str(), texture.size());
398                 lua_rawseti(L, -2, i++);
399         }
400         lua_setfield(L, -2, "textures");
401
402         lua_createtable(L, prop->colors.size(), 0);
403         i = 1;
404         for (const video::SColor &color : prop->colors) {
405                 push_ARGB8(L, color);
406                 lua_rawseti(L, -2, i++);
407         }
408         lua_setfield(L, -2, "colors");
409
410         push_v2s16(L, prop->spritediv);
411         lua_setfield(L, -2, "spritediv");
412         push_v2s16(L, prop->initial_sprite_basepos);
413         lua_setfield(L, -2, "initial_sprite_basepos");
414         lua_pushboolean(L, prop->is_visible);
415         lua_setfield(L, -2, "is_visible");
416         lua_pushboolean(L, prop->makes_footstep_sound);
417         lua_setfield(L, -2, "makes_footstep_sound");
418         lua_pushnumber(L, prop->stepheight / BS);
419         lua_setfield(L, -2, "stepheight");
420         lua_pushnumber(L, prop->eye_height);
421         lua_setfield(L, -2, "eye_height");
422         lua_pushnumber(L, prop->automatic_rotate);
423         lua_setfield(L, -2, "automatic_rotate");
424         if (prop->automatic_face_movement_dir)
425                 lua_pushnumber(L, prop->automatic_face_movement_dir_offset);
426         else
427                 lua_pushboolean(L, false);
428         lua_setfield(L, -2, "automatic_face_movement_dir");
429         lua_pushboolean(L, prop->backface_culling);
430         lua_setfield(L, -2, "backface_culling");
431         lua_pushnumber(L, prop->glow);
432         lua_setfield(L, -2, "glow");
433         lua_pushlstring(L, prop->nametag.c_str(), prop->nametag.size());
434         lua_setfield(L, -2, "nametag");
435         push_ARGB8(L, prop->nametag_color);
436         lua_setfield(L, -2, "nametag_color");
437         if (prop->nametag_bgcolor) {
438                 push_ARGB8(L, prop->nametag_bgcolor.value());
439                 lua_setfield(L, -2, "nametag_bgcolor");
440         } else {
441                 lua_pushboolean(L, false);
442                 lua_setfield(L, -2, "nametag_bgcolor");
443         }
444         lua_pushnumber(L, prop->automatic_face_movement_max_rotation_per_sec);
445         lua_setfield(L, -2, "automatic_face_movement_max_rotation_per_sec");
446         lua_pushlstring(L, prop->infotext.c_str(), prop->infotext.size());
447         lua_setfield(L, -2, "infotext");
448         lua_pushboolean(L, prop->static_save);
449         lua_setfield(L, -2, "static_save");
450         lua_pushlstring(L, prop->wield_item.c_str(), prop->wield_item.size());
451         lua_setfield(L, -2, "wield_item");
452         lua_pushnumber(L, prop->zoom_fov);
453         lua_setfield(L, -2, "zoom_fov");
454         lua_pushboolean(L, prop->use_texture_alpha);
455         lua_setfield(L, -2, "use_texture_alpha");
456         lua_pushboolean(L, prop->shaded);
457         lua_setfield(L, -2, "shaded");
458         lua_pushlstring(L, prop->damage_texture_modifier.c_str(), prop->damage_texture_modifier.size());
459         lua_setfield(L, -2, "damage_texture_modifier");
460         lua_pushboolean(L, prop->show_on_minimap);
461         lua_setfield(L, -2, "show_on_minimap");
462 }
463
464 /******************************************************************************/
465 TileDef read_tiledef(lua_State *L, int index, u8 drawtype, bool special)
466 {
467         if(index < 0)
468                 index = lua_gettop(L) + 1 + index;
469
470         TileDef tiledef;
471
472         bool default_tiling = true;
473         bool default_culling = true;
474         switch (drawtype) {
475                 case NDT_PLANTLIKE:
476                 case NDT_FIRELIKE:
477                         default_tiling = false;
478                         // "break" is omitted here intentionaly, as PLANTLIKE
479                         // FIRELIKE drawtype both should default to having
480                         // backface_culling to false.
481                 case NDT_MESH:
482                 case NDT_LIQUID:
483                         default_culling = false;
484                         break;
485                 case NDT_PLANTLIKE_ROOTED:
486                         default_tiling = !special;
487                         default_culling = !special;
488                         break;
489                 default:
490                         break;
491         }
492
493         // key at index -2 and value at index
494         if(lua_isstring(L, index)){
495                 // "default_lava.png"
496                 tiledef.name = lua_tostring(L, index);
497                 tiledef.tileable_vertical = default_tiling;
498                 tiledef.tileable_horizontal = default_tiling;
499                 tiledef.backface_culling = default_culling;
500         }
501         else if(lua_istable(L, index))
502         {
503                 // name="default_lava.png"
504                 tiledef.name.clear();
505                 getstringfield(L, index, "name", tiledef.name);
506                 getstringfield(L, index, "image", tiledef.name); // MaterialSpec compat.
507                 tiledef.backface_culling = getboolfield_default(
508                         L, index, "backface_culling", default_culling);
509                 tiledef.tileable_horizontal = getboolfield_default(
510                         L, index, "tileable_horizontal", default_tiling);
511                 tiledef.tileable_vertical = getboolfield_default(
512                         L, index, "tileable_vertical", default_tiling);
513                 std::string align_style;
514                 if (getstringfield(L, index, "align_style", align_style)) {
515                         if (align_style == "user")
516                                 tiledef.align_style = ALIGN_STYLE_USER_DEFINED;
517                         else if (align_style == "world")
518                                 tiledef.align_style = ALIGN_STYLE_WORLD;
519                         else
520                                 tiledef.align_style = ALIGN_STYLE_NODE;
521                 }
522                 tiledef.scale = getintfield_default(L, index, "scale", 0);
523                 // color = ...
524                 lua_getfield(L, index, "color");
525                 tiledef.has_color = read_color(L, -1, &tiledef.color);
526                 lua_pop(L, 1);
527                 // animation = {}
528                 lua_getfield(L, index, "animation");
529                 tiledef.animation = read_animation_definition(L, -1);
530                 lua_pop(L, 1);
531         }
532
533         return tiledef;
534 }
535
536 /******************************************************************************/
537 void read_content_features(lua_State *L, ContentFeatures &f, int index)
538 {
539         if(index < 0)
540                 index = lua_gettop(L) + 1 + index;
541
542         /* Cache existence of some callbacks */
543         lua_getfield(L, index, "on_construct");
544         if(!lua_isnil(L, -1)) f.has_on_construct = true;
545         lua_pop(L, 1);
546         lua_getfield(L, index, "on_destruct");
547         if(!lua_isnil(L, -1)) f.has_on_destruct = true;
548         lua_pop(L, 1);
549         lua_getfield(L, index, "after_destruct");
550         if(!lua_isnil(L, -1)) f.has_after_destruct = true;
551         lua_pop(L, 1);
552
553         lua_getfield(L, index, "on_rightclick");
554         f.rightclickable = lua_isfunction(L, -1);
555         lua_pop(L, 1);
556
557         /* Name */
558         getstringfield(L, index, "name", f.name);
559
560         /* Groups */
561         lua_getfield(L, index, "groups");
562         read_groups(L, -1, f.groups);
563         lua_pop(L, 1);
564
565         /* Visual definition */
566
567         f.drawtype = (NodeDrawType)getenumfield(L, index, "drawtype",
568                         ScriptApiNode::es_DrawType,NDT_NORMAL);
569         getfloatfield(L, index, "visual_scale", f.visual_scale);
570
571         /* Meshnode model filename */
572         getstringfield(L, index, "mesh", f.mesh);
573
574         // tiles = {}
575         lua_getfield(L, index, "tiles");
576         if(lua_istable(L, -1)){
577                 int table = lua_gettop(L);
578                 lua_pushnil(L);
579                 int i = 0;
580                 while(lua_next(L, table) != 0){
581                         // Read tiledef from value
582                         f.tiledef[i] = read_tiledef(L, -1, f.drawtype, false);
583                         // removes value, keeps key for next iteration
584                         lua_pop(L, 1);
585                         i++;
586                         if(i==6){
587                                 lua_pop(L, 1);
588                                 break;
589                         }
590                 }
591                 // Copy last value to all remaining textures
592                 if(i >= 1){
593                         TileDef lasttile = f.tiledef[i-1];
594                         while(i < 6){
595                                 f.tiledef[i] = lasttile;
596                                 i++;
597                         }
598                 }
599         }
600         lua_pop(L, 1);
601
602         // overlay_tiles = {}
603         lua_getfield(L, index, "overlay_tiles");
604         if (lua_istable(L, -1)) {
605                 int table = lua_gettop(L);
606                 lua_pushnil(L);
607                 int i = 0;
608                 while (lua_next(L, table) != 0) {
609                         // Read tiledef from value
610                         f.tiledef_overlay[i] = read_tiledef(L, -1, f.drawtype, false);
611                         // removes value, keeps key for next iteration
612                         lua_pop(L, 1);
613                         i++;
614                         if (i == 6) {
615                                 lua_pop(L, 1);
616                                 break;
617                         }
618                 }
619                 // Copy last value to all remaining textures
620                 if (i >= 1) {
621                         TileDef lasttile = f.tiledef_overlay[i - 1];
622                         while (i < 6) {
623                                 f.tiledef_overlay[i] = lasttile;
624                                 i++;
625                         }
626                 }
627         }
628         lua_pop(L, 1);
629
630         // special_tiles = {}
631         lua_getfield(L, index, "special_tiles");
632         if(lua_istable(L, -1)){
633                 int table = lua_gettop(L);
634                 lua_pushnil(L);
635                 int i = 0;
636                 while(lua_next(L, table) != 0){
637                         // Read tiledef from value
638                         f.tiledef_special[i] = read_tiledef(L, -1, f.drawtype, true);
639                         // removes value, keeps key for next iteration
640                         lua_pop(L, 1);
641                         i++;
642                         if(i==CF_SPECIAL_COUNT){
643                                 lua_pop(L, 1);
644                                 break;
645                         }
646                 }
647         }
648         lua_pop(L, 1);
649
650         /* alpha & use_texture_alpha */
651         // This is a bit complicated due to compatibility
652
653         f.setDefaultAlphaMode();
654
655         warn_if_field_exists(L, index, "alpha",
656                 "Obsolete, only limited compatibility provided; "
657                 "replaced by \"use_texture_alpha\"");
658         if (getintfield_default(L, index, "alpha", 255) != 255)
659                 f.alpha = ALPHAMODE_BLEND;
660
661         lua_getfield(L, index, "use_texture_alpha");
662         if (lua_isboolean(L, -1)) {
663                 warn_if_field_exists(L, index, "use_texture_alpha",
664                         "Boolean values are deprecated; use the new choices");
665                 if (lua_toboolean(L, -1))
666                         f.alpha = (f.drawtype == NDT_NORMAL) ? ALPHAMODE_CLIP : ALPHAMODE_BLEND;
667         } else if (check_field_or_nil(L, -1, LUA_TSTRING, "use_texture_alpha")) {
668                 int result = f.alpha;
669                 string_to_enum(ScriptApiNode::es_TextureAlphaMode, result,
670                                 std::string(lua_tostring(L, -1)));
671                 f.alpha = static_cast<enum AlphaMode>(result);
672         }
673         lua_pop(L, 1);
674
675         /* Other stuff */
676
677         lua_getfield(L, index, "color");
678         read_color(L, -1, &f.color);
679         lua_pop(L, 1);
680
681         getstringfield(L, index, "palette", f.palette_name);
682
683         lua_getfield(L, index, "post_effect_color");
684         read_color(L, -1, &f.post_effect_color);
685         lua_pop(L, 1);
686
687         f.param_type = (ContentParamType)getenumfield(L, index, "paramtype",
688                         ScriptApiNode::es_ContentParamType, CPT_NONE);
689         f.param_type_2 = (ContentParamType2)getenumfield(L, index, "paramtype2",
690                         ScriptApiNode::es_ContentParamType2, CPT2_NONE);
691
692         if (!f.palette_name.empty() &&
693                         !(f.param_type_2 == CPT2_COLOR ||
694                         f.param_type_2 == CPT2_COLORED_FACEDIR ||
695                         f.param_type_2 == CPT2_COLORED_WALLMOUNTED ||
696                         f.param_type_2 == CPT2_COLORED_DEGROTATE ||
697                         f.param_type_2 == CPT2_COLORED_4DIR))
698                 warningstream << "Node " << f.name.c_str()
699                         << " has a palette, but not a suitable paramtype2." << std::endl;
700
701         // True for all ground-like things like stone and mud, false for eg. trees
702         getboolfield(L, index, "is_ground_content", f.is_ground_content);
703         f.light_propagates = (f.param_type == CPT_LIGHT);
704         getboolfield(L, index, "sunlight_propagates", f.sunlight_propagates);
705         // This is used for collision detection.
706         // Also for general solidness queries.
707         getboolfield(L, index, "walkable", f.walkable);
708         // Player can point to these
709         getboolfield(L, index, "pointable", f.pointable);
710         // Player can dig these
711         getboolfield(L, index, "diggable", f.diggable);
712         // Player can climb these
713         getboolfield(L, index, "climbable", f.climbable);
714         // Player can build on these
715         getboolfield(L, index, "buildable_to", f.buildable_to);
716         // Liquids flow into and replace node
717         getboolfield(L, index, "floodable", f.floodable);
718         // Whether the node is non-liquid, source liquid or flowing liquid
719         f.liquid_type = (LiquidType)getenumfield(L, index, "liquidtype",
720                         ScriptApiNode::es_LiquidType, LIQUID_NONE);
721         // If the content is liquid, this is the flowing version of the liquid.
722         getstringfield(L, index, "liquid_alternative_flowing",
723                         f.liquid_alternative_flowing);
724         // If the content is liquid, this is the source version of the liquid.
725         getstringfield(L, index, "liquid_alternative_source",
726                         f.liquid_alternative_source);
727         // Viscosity for fluid flow, ranging from 1 to 7, with
728         // 1 giving almost instantaneous propagation and 7 being
729         // the slowest possible
730         f.liquid_viscosity = getintfield_default(L, index,
731                         "liquid_viscosity", f.liquid_viscosity);
732         // If move_resistance is not set explicitly,
733         // move_resistance is equal to liquid_viscosity
734         f.move_resistance = f.liquid_viscosity;
735         f.liquid_range = getintfield_default(L, index,
736                         "liquid_range", f.liquid_range);
737         f.leveled = getintfield_default(L, index, "leveled", f.leveled);
738         f.leveled_max = getintfield_default(L, index,
739                         "leveled_max", f.leveled_max);
740
741         getboolfield(L, index, "liquid_renewable", f.liquid_renewable);
742         f.drowning = getintfield_default(L, index,
743                         "drowning", f.drowning);
744         // Amount of light the node emits
745         f.light_source = getintfield_default(L, index,
746                         "light_source", f.light_source);
747         if (f.light_source > LIGHT_MAX) {
748                 warningstream << "Node " << f.name.c_str()
749                         << " had greater light_source than " << LIGHT_MAX
750                         << ", it was reduced." << std::endl;
751                 f.light_source = LIGHT_MAX;
752         }
753         f.damage_per_second = getintfield_default(L, index,
754                         "damage_per_second", f.damage_per_second);
755
756         lua_getfield(L, index, "node_box");
757         if(lua_istable(L, -1))
758                 f.node_box = read_nodebox(L, -1);
759         lua_pop(L, 1);
760
761         lua_getfield(L, index, "connects_to");
762         if (lua_istable(L, -1)) {
763                 int table = lua_gettop(L);
764                 lua_pushnil(L);
765                 while (lua_next(L, table) != 0) {
766                         // Value at -1
767                         f.connects_to.emplace_back(lua_tostring(L, -1));
768                         lua_pop(L, 1);
769                 }
770         }
771         lua_pop(L, 1);
772
773         lua_getfield(L, index, "connect_sides");
774         if (lua_istable(L, -1)) {
775                 int table = lua_gettop(L);
776                 lua_pushnil(L);
777                 while (lua_next(L, table) != 0) {
778                         // Value at -1
779                         std::string side(lua_tostring(L, -1));
780                         // Note faces are flipped to make checking easier
781                         if (side == "top")
782                                 f.connect_sides |= 2;
783                         else if (side == "bottom")
784                                 f.connect_sides |= 1;
785                         else if (side == "front")
786                                 f.connect_sides |= 16;
787                         else if (side == "left")
788                                 f.connect_sides |= 32;
789                         else if (side == "back")
790                                 f.connect_sides |= 4;
791                         else if (side == "right")
792                                 f.connect_sides |= 8;
793                         else
794                                 warningstream << "Unknown value for \"connect_sides\": "
795                                         << side << std::endl;
796                         lua_pop(L, 1);
797                 }
798         }
799         lua_pop(L, 1);
800
801         lua_getfield(L, index, "selection_box");
802         if(lua_istable(L, -1))
803                 f.selection_box = read_nodebox(L, -1);
804         lua_pop(L, 1);
805
806         lua_getfield(L, index, "collision_box");
807         if(lua_istable(L, -1))
808                 f.collision_box = read_nodebox(L, -1);
809         lua_pop(L, 1);
810
811         f.waving = getintfield_default(L, index,
812                         "waving", f.waving);
813
814         // Set to true if paramtype used to be 'facedir_simple'
815         getboolfield(L, index, "legacy_facedir_simple", f.legacy_facedir_simple);
816         // Set to true if wall_mounted used to be set to true
817         getboolfield(L, index, "legacy_wallmounted", f.legacy_wallmounted);
818
819         // Sound table
820         lua_getfield(L, index, "sounds");
821         if(lua_istable(L, -1)){
822                 lua_getfield(L, -1, "footstep");
823                 read_soundspec(L, -1, f.sound_footstep);
824                 lua_pop(L, 1);
825                 lua_getfield(L, -1, "dig");
826                 read_soundspec(L, -1, f.sound_dig);
827                 lua_pop(L, 1);
828                 lua_getfield(L, -1, "dug");
829                 read_soundspec(L, -1, f.sound_dug);
830                 lua_pop(L, 1);
831         }
832         lua_pop(L, 1);
833
834         // Node immediately placed by client when node is dug
835         getstringfield(L, index, "node_dig_prediction",
836                 f.node_dig_prediction);
837
838         // How much the node slows down players, ranging from 1 to 7,
839         // the higher, the slower.
840         f.move_resistance = getintfield_default(L, index,
841                         "move_resistance", f.move_resistance);
842
843         // Whether e.g. players in this node will have liquid movement physics
844         lua_getfield(L, index, "liquid_move_physics");
845         if(lua_isboolean(L, -1)) {
846                 f.liquid_move_physics = lua_toboolean(L, -1);
847         } else if(lua_isnil(L, -1)) {
848                 f.liquid_move_physics = f.liquid_type != LIQUID_NONE;
849         } else {
850                 errorstream << "Field \"liquid_move_physics\": Invalid type!" << std::endl;
851         }
852         lua_pop(L, 1);
853 }
854
855 void push_content_features(lua_State *L, const ContentFeatures &c)
856 {
857         std::string paramtype(ScriptApiNode::es_ContentParamType[(int)c.param_type].str);
858         std::string paramtype2(ScriptApiNode::es_ContentParamType2[(int)c.param_type_2].str);
859         std::string drawtype(ScriptApiNode::es_DrawType[(int)c.drawtype].str);
860         std::string liquid_type(ScriptApiNode::es_LiquidType[(int)c.liquid_type].str);
861
862         /* Missing "tiles" because I don't see a usecase (at least not yet). */
863
864         lua_newtable(L);
865         lua_pushboolean(L, c.has_on_construct);
866         lua_setfield(L, -2, "has_on_construct");
867         lua_pushboolean(L, c.has_on_destruct);
868         lua_setfield(L, -2, "has_on_destruct");
869         lua_pushboolean(L, c.has_after_destruct);
870         lua_setfield(L, -2, "has_after_destruct");
871         lua_pushstring(L, c.name.c_str());
872         lua_setfield(L, -2, "name");
873         push_groups(L, c.groups);
874         lua_setfield(L, -2, "groups");
875         lua_pushstring(L, paramtype.c_str());
876         lua_setfield(L, -2, "paramtype");
877         lua_pushstring(L, paramtype2.c_str());
878         lua_setfield(L, -2, "paramtype2");
879         lua_pushstring(L, drawtype.c_str());
880         lua_setfield(L, -2, "drawtype");
881         if (!c.mesh.empty()) {
882                 lua_pushstring(L, c.mesh.c_str());
883                 lua_setfield(L, -2, "mesh");
884         }
885 #ifndef SERVER
886         push_ARGB8(L, c.minimap_color);       // I know this is not set-able w/ register_node,
887         lua_setfield(L, -2, "minimap_color"); // but the people need to know!
888 #endif
889         lua_pushnumber(L, c.visual_scale);
890         lua_setfield(L, -2, "visual_scale");
891         lua_pushnumber(L, c.alpha);
892         lua_setfield(L, -2, "alpha");
893         if (!c.palette_name.empty()) {
894                 push_ARGB8(L, c.color);
895                 lua_setfield(L, -2, "color");
896
897                 lua_pushstring(L, c.palette_name.c_str());
898                 lua_setfield(L, -2, "palette_name");
899
900                 push_palette(L, c.palette);
901                 lua_setfield(L, -2, "palette");
902         }
903         lua_pushnumber(L, c.waving);
904         lua_setfield(L, -2, "waving");
905         lua_pushnumber(L, c.connect_sides);
906         lua_setfield(L, -2, "connect_sides");
907
908         lua_createtable(L, c.connects_to.size(), 0);
909         u16 i = 1;
910         for (const std::string &it : c.connects_to) {
911                 lua_pushlstring(L, it.c_str(), it.size());
912                 lua_rawseti(L, -2, i++);
913         }
914         lua_setfield(L, -2, "connects_to");
915
916         push_ARGB8(L, c.post_effect_color);
917         lua_setfield(L, -2, "post_effect_color");
918         lua_pushnumber(L, c.leveled);
919         lua_setfield(L, -2, "leveled");
920         lua_pushnumber(L, c.leveled_max);
921         lua_setfield(L, -2, "leveled_max");
922         lua_pushboolean(L, c.sunlight_propagates);
923         lua_setfield(L, -2, "sunlight_propagates");
924         lua_pushnumber(L, c.light_source);
925         lua_setfield(L, -2, "light_source");
926         lua_pushboolean(L, c.is_ground_content);
927         lua_setfield(L, -2, "is_ground_content");
928         lua_pushboolean(L, c.walkable);
929         lua_setfield(L, -2, "walkable");
930         lua_pushboolean(L, c.pointable);
931         lua_setfield(L, -2, "pointable");
932         lua_pushboolean(L, c.diggable);
933         lua_setfield(L, -2, "diggable");
934         lua_pushboolean(L, c.climbable);
935         lua_setfield(L, -2, "climbable");
936         lua_pushboolean(L, c.buildable_to);
937         lua_setfield(L, -2, "buildable_to");
938         lua_pushboolean(L, c.rightclickable);
939         lua_setfield(L, -2, "rightclickable");
940         lua_pushnumber(L, c.damage_per_second);
941         lua_setfield(L, -2, "damage_per_second");
942         if (c.isLiquid()) {
943                 lua_pushstring(L, liquid_type.c_str());
944                 lua_setfield(L, -2, "liquid_type");
945                 lua_pushstring(L, c.liquid_alternative_flowing.c_str());
946                 lua_setfield(L, -2, "liquid_alternative_flowing");
947                 lua_pushstring(L, c.liquid_alternative_source.c_str());
948                 lua_setfield(L, -2, "liquid_alternative_source");
949                 lua_pushnumber(L, c.liquid_viscosity);
950                 lua_setfield(L, -2, "liquid_viscosity");
951                 lua_pushboolean(L, c.liquid_renewable);
952                 lua_setfield(L, -2, "liquid_renewable");
953                 lua_pushnumber(L, c.liquid_range);
954                 lua_setfield(L, -2, "liquid_range");
955         }
956         lua_pushnumber(L, c.drowning);
957         lua_setfield(L, -2, "drowning");
958         lua_pushboolean(L, c.floodable);
959         lua_setfield(L, -2, "floodable");
960         push_nodebox(L, c.node_box);
961         lua_setfield(L, -2, "node_box");
962         push_nodebox(L, c.selection_box);
963         lua_setfield(L, -2, "selection_box");
964         push_nodebox(L, c.collision_box);
965         lua_setfield(L, -2, "collision_box");
966         lua_newtable(L);
967         push_soundspec(L, c.sound_footstep);
968         lua_setfield(L, -2, "sound_footstep");
969         push_soundspec(L, c.sound_dig);
970         lua_setfield(L, -2, "sound_dig");
971         push_soundspec(L, c.sound_dug);
972         lua_setfield(L, -2, "sound_dug");
973         lua_setfield(L, -2, "sounds");
974         lua_pushboolean(L, c.legacy_facedir_simple);
975         lua_setfield(L, -2, "legacy_facedir_simple");
976         lua_pushboolean(L, c.legacy_wallmounted);
977         lua_setfield(L, -2, "legacy_wallmounted");
978         lua_pushstring(L, c.node_dig_prediction.c_str());
979         lua_setfield(L, -2, "node_dig_prediction");
980         lua_pushnumber(L, c.move_resistance);
981         lua_setfield(L, -2, "move_resistance");
982         lua_pushboolean(L, c.liquid_move_physics);
983         lua_setfield(L, -2, "liquid_move_physics");
984 }
985
986 /******************************************************************************/
987 void push_nodebox(lua_State *L, const NodeBox &box)
988 {
989         lua_newtable(L);
990         switch (box.type)
991         {
992                 case NODEBOX_REGULAR:
993                         lua_pushstring(L, "regular");
994                         lua_setfield(L, -2, "type");
995                         break;
996                 case NODEBOX_LEVELED:
997                 case NODEBOX_FIXED:
998                         lua_pushstring(L, "fixed");
999                         lua_setfield(L, -2, "type");
1000                         push_box(L, box.fixed);
1001                         lua_setfield(L, -2, "fixed");
1002                         break;
1003                 case NODEBOX_WALLMOUNTED:
1004                         lua_pushstring(L, "wallmounted");
1005                         lua_setfield(L, -2, "type");
1006                         push_aabb3f(L, box.wall_top);
1007                         lua_setfield(L, -2, "wall_top");
1008                         push_aabb3f(L, box.wall_bottom);
1009                         lua_setfield(L, -2, "wall_bottom");
1010                         push_aabb3f(L, box.wall_side);
1011                         lua_setfield(L, -2, "wall_side");
1012                         break;
1013                 case NODEBOX_CONNECTED: {
1014                         lua_pushstring(L, "connected");
1015                         lua_setfield(L, -2, "type");
1016                         const auto &c = box.getConnected();
1017                         push_box(L, c.connect_top);
1018                         lua_setfield(L, -2, "connect_top");
1019                         push_box(L, c.connect_bottom);
1020                         lua_setfield(L, -2, "connect_bottom");
1021                         push_box(L, c.connect_front);
1022                         lua_setfield(L, -2, "connect_front");
1023                         push_box(L, c.connect_back);
1024                         lua_setfield(L, -2, "connect_back");
1025                         push_box(L, c.connect_left);
1026                         lua_setfield(L, -2, "connect_left");
1027                         push_box(L, c.connect_right);
1028                         lua_setfield(L, -2, "connect_right");
1029                         // half the boxes are missing here?
1030                         break;
1031                 }
1032                 default:
1033                         FATAL_ERROR("Invalid box.type");
1034                         break;
1035         }
1036 }
1037
1038 void push_box(lua_State *L, const std::vector<aabb3f> &box)
1039 {
1040         lua_createtable(L, box.size(), 0);
1041         u8 i = 1;
1042         for (const aabb3f &it : box) {
1043                 push_aabb3f(L, it);
1044                 lua_rawseti(L, -2, i++);
1045         }
1046 }
1047
1048 /******************************************************************************/
1049 void push_palette(lua_State *L, const std::vector<video::SColor> *palette)
1050 {
1051         lua_createtable(L, palette->size(), 0);
1052         int newTable = lua_gettop(L);
1053         int index = 1;
1054         std::vector<video::SColor>::const_iterator iter;
1055         for (iter = palette->begin(); iter != palette->end(); ++iter) {
1056                 push_ARGB8(L, (*iter));
1057                 lua_rawseti(L, newTable, index);
1058                 index++;
1059         }
1060 }
1061
1062 /******************************************************************************/
1063 void read_server_sound_params(lua_State *L, int index,
1064                 ServerPlayingSound &params)
1065 {
1066         if(index < 0)
1067                 index = lua_gettop(L) + 1 + index;
1068
1069         if(lua_istable(L, index)){
1070                 // Functional overlap: this may modify SimpleSoundSpec contents
1071                 getfloatfield(L, index, "fade", params.spec.fade);
1072                 getfloatfield(L, index, "pitch", params.spec.pitch);
1073                 getboolfield(L, index, "loop", params.spec.loop);
1074
1075                 getfloatfield(L, index, "gain", params.gain);
1076
1077                 // Handle positional information
1078                 getstringfield(L, index, "to_player", params.to_player);
1079                 lua_getfield(L, index, "pos");
1080                 if(!lua_isnil(L, -1)){
1081                         v3f p = read_v3f(L, -1)*BS;
1082                         params.pos = p;
1083                         params.type = SoundLocation::Position;
1084                 }
1085                 lua_pop(L, 1);
1086                 lua_getfield(L, index, "object");
1087                 if(!lua_isnil(L, -1)){
1088                         ObjectRef *ref = ModApiBase::checkObject<ObjectRef>(L, -1);
1089                         ServerActiveObject *sao = ObjectRef::getobject(ref);
1090                         if(sao){
1091                                 params.object = sao->getId();
1092                                 params.type = SoundLocation::Object;
1093                         }
1094                 }
1095                 lua_pop(L, 1);
1096                 params.max_hear_distance = BS*getfloatfield_default(L, index,
1097                                 "max_hear_distance", params.max_hear_distance/BS);
1098                 getstringfield(L, index, "exclude_player", params.exclude_player);
1099         }
1100 }
1101
1102 /******************************************************************************/
1103 void read_soundspec(lua_State *L, int index, SimpleSoundSpec &spec)
1104 {
1105         if(index < 0)
1106                 index = lua_gettop(L) + 1 + index;
1107         if (lua_isnil(L, index))
1108                 return;
1109
1110         if (lua_istable(L, index)) {
1111                 getstringfield(L, index, "name", spec.name);
1112                 getfloatfield(L, index, "gain", spec.gain);
1113                 getfloatfield(L, index, "fade", spec.fade);
1114                 getfloatfield(L, index, "pitch", spec.pitch);
1115         } else if (lua_isstring(L, index)) {
1116                 spec.name = lua_tostring(L, index);
1117         }
1118 }
1119
1120 void push_soundspec(lua_State *L, const SimpleSoundSpec &spec)
1121 {
1122         lua_createtable(L, 0, 3);
1123         lua_pushstring(L, spec.name.c_str());
1124         lua_setfield(L, -2, "name");
1125         lua_pushnumber(L, spec.gain);
1126         lua_setfield(L, -2, "gain");
1127         lua_pushnumber(L, spec.fade);
1128         lua_setfield(L, -2, "fade");
1129         lua_pushnumber(L, spec.pitch);
1130         lua_setfield(L, -2, "pitch");
1131 }
1132
1133 /******************************************************************************/
1134 NodeBox read_nodebox(lua_State *L, int index)
1135 {
1136         NodeBox nodebox;
1137         if (lua_isnil(L, -1))
1138                 return nodebox;
1139
1140         luaL_checktype(L, -1, LUA_TTABLE);
1141
1142         nodebox.type = (NodeBoxType)getenumfield(L, index, "type",
1143                         ScriptApiNode::es_NodeBoxType, NODEBOX_REGULAR);
1144
1145 #define NODEBOXREAD(n, s){ \
1146                 lua_getfield(L, index, (s)); \
1147                 if (lua_istable(L, -1)) \
1148                         (n) = read_aabb3f(L, -1, BS); \
1149                 lua_pop(L, 1); \
1150         }
1151
1152 #define NODEBOXREADVEC(n, s) \
1153         lua_getfield(L, index, (s)); \
1154         if (lua_istable(L, -1)) \
1155                 (n) = read_aabb3f_vector(L, -1, BS); \
1156         lua_pop(L, 1);
1157
1158         NODEBOXREADVEC(nodebox.fixed, "fixed");
1159         NODEBOXREAD(nodebox.wall_top, "wall_top");
1160         NODEBOXREAD(nodebox.wall_bottom, "wall_bottom");
1161         NODEBOXREAD(nodebox.wall_side, "wall_side");
1162
1163         if (nodebox.type == NODEBOX_CONNECTED) {
1164                 auto &c = nodebox.getConnected();
1165                 NODEBOXREADVEC(c.connect_top, "connect_top");
1166                 NODEBOXREADVEC(c.connect_bottom, "connect_bottom");
1167                 NODEBOXREADVEC(c.connect_front, "connect_front");
1168                 NODEBOXREADVEC(c.connect_left, "connect_left");
1169                 NODEBOXREADVEC(c.connect_back, "connect_back");
1170                 NODEBOXREADVEC(c.connect_right, "connect_right");
1171                 NODEBOXREADVEC(c.disconnected_top, "disconnected_top");
1172                 NODEBOXREADVEC(c.disconnected_bottom, "disconnected_bottom");
1173                 NODEBOXREADVEC(c.disconnected_front, "disconnected_front");
1174                 NODEBOXREADVEC(c.disconnected_left, "disconnected_left");
1175                 NODEBOXREADVEC(c.disconnected_back, "disconnected_back");
1176                 NODEBOXREADVEC(c.disconnected_right, "disconnected_right");
1177                 NODEBOXREADVEC(c.disconnected, "disconnected");
1178                 NODEBOXREADVEC(c.disconnected_sides, "disconnected_sides");
1179         }
1180
1181         return nodebox;
1182 }
1183
1184 /******************************************************************************/
1185 MapNode readnode(lua_State *L, int index)
1186 {
1187         lua_pushvalue(L, index);
1188         lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_READ_NODE);
1189         lua_insert(L, -2);
1190         lua_call(L, 1, 3);
1191         content_t content = lua_tointeger(L, -3);
1192         u8 param1 = lua_tointeger(L, -2);
1193         u8 param2 = lua_tointeger(L, -1);
1194         lua_pop(L, 3);
1195         return MapNode(content, param1, param2);
1196 }
1197
1198 /******************************************************************************/
1199 void pushnode(lua_State *L, const MapNode &n)
1200 {
1201         lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_PUSH_NODE);
1202         lua_pushinteger(L, n.getContent());
1203         lua_pushinteger(L, n.getParam1());
1204         lua_pushinteger(L, n.getParam2());
1205         lua_call(L, 3, 1);
1206 }
1207
1208 /******************************************************************************/
1209 void warn_if_field_exists(lua_State *L, int table,
1210                 const char *name, const std::string &message)
1211 {
1212         lua_getfield(L, table, name);
1213         if (!lua_isnil(L, -1)) {
1214                 warningstream << "Field \"" << name << "\": "
1215                                 << message << std::endl;
1216                 infostream << script_get_backtrace(L) << std::endl;
1217         }
1218         lua_pop(L, 1);
1219 }
1220
1221 /******************************************************************************/
1222 int getenumfield(lua_State *L, int table,
1223                 const char *fieldname, const EnumString *spec, int default_)
1224 {
1225         int result = default_;
1226         string_to_enum(spec, result,
1227                         getstringfield_default(L, table, fieldname, ""));
1228         return result;
1229 }
1230
1231 /******************************************************************************/
1232 bool string_to_enum(const EnumString *spec, int &result,
1233                 const std::string &str)
1234 {
1235         const EnumString *esp = spec;
1236         while(esp->str){
1237                 if (!strcmp(str.c_str(), esp->str)) {
1238                         result = esp->num;
1239                         return true;
1240                 }
1241                 esp++;
1242         }
1243         return false;
1244 }
1245
1246 /******************************************************************************/
1247 ItemStack read_item(lua_State* L, int index, IItemDefManager *idef)
1248 {
1249         if(index < 0)
1250                 index = lua_gettop(L) + 1 + index;
1251
1252         if (lua_isnil(L, index)) {
1253                 return ItemStack();
1254         }
1255
1256         if (lua_isuserdata(L, index)) {
1257                 // Convert from LuaItemStack
1258                 LuaItemStack *o = ModApiBase::checkObject<LuaItemStack>(L, index);
1259                 return o->getItem();
1260         }
1261
1262         if (lua_isstring(L, index)) {
1263                 // Convert from itemstring
1264                 std::string itemstring = lua_tostring(L, index);
1265                 try
1266                 {
1267                         ItemStack item;
1268                         item.deSerialize(itemstring, idef);
1269                         return item;
1270                 }
1271                 catch(SerializationError &e)
1272                 {
1273                         warningstream<<"unable to create item from itemstring"
1274                                         <<": "<<itemstring<<std::endl;
1275                         return ItemStack();
1276                 }
1277         }
1278         else if(lua_istable(L, index))
1279         {
1280                 // Convert from table
1281                 std::string name = getstringfield_default(L, index, "name", "");
1282                 int count = getintfield_default(L, index, "count", 1);
1283                 int wear = getintfield_default(L, index, "wear", 0);
1284
1285                 ItemStack istack(name, count, wear, idef);
1286
1287                 // BACKWARDS COMPATIBLITY
1288                 std::string value = getstringfield_default(L, index, "metadata", "");
1289                 istack.metadata.setString("", value);
1290
1291                 // Get meta
1292                 lua_getfield(L, index, "meta");
1293                 int fieldstable = lua_gettop(L);
1294                 if (lua_istable(L, fieldstable)) {
1295                         lua_pushnil(L);
1296                         while (lua_next(L, fieldstable) != 0) {
1297                                 // key at index -2 and value at index -1
1298                                 std::string key = lua_tostring(L, -2);
1299                                 size_t value_len;
1300                                 const char *value_cs = lua_tolstring(L, -1, &value_len);
1301                                 std::string value(value_cs, value_len);
1302                                 istack.metadata.setString(key, value);
1303                                 lua_pop(L, 1); // removes value, keeps key for next iteration
1304                         }
1305                 }
1306
1307                 return istack;
1308         } else {
1309                 throw LuaError("Expecting itemstack, itemstring, table or nil");
1310         }
1311 }
1312
1313 /******************************************************************************/
1314 void push_tool_capabilities(lua_State *L,
1315                 const ToolCapabilities &toolcap)
1316 {
1317         lua_newtable(L);
1318         setfloatfield(L, -1, "full_punch_interval", toolcap.full_punch_interval);
1319         setintfield(L, -1, "max_drop_level", toolcap.max_drop_level);
1320         setintfield(L, -1, "punch_attack_uses", toolcap.punch_attack_uses);
1321                 // Create groupcaps table
1322                 lua_newtable(L);
1323                 // For each groupcap
1324                 for (const auto &gc_it : toolcap.groupcaps) {
1325                         // Create groupcap table
1326                         lua_newtable(L);
1327                         const std::string &name = gc_it.first;
1328                         const ToolGroupCap &groupcap = gc_it.second;
1329                         // Create subtable "times"
1330                         lua_newtable(L);
1331                         for (auto time : groupcap.times) {
1332                                 lua_pushinteger(L, time.first);
1333                                 lua_pushnumber(L, time.second);
1334                                 lua_settable(L, -3);
1335                         }
1336                         // Set subtable "times"
1337                         lua_setfield(L, -2, "times");
1338                         // Set simple parameters
1339                         setintfield(L, -1, "maxlevel", groupcap.maxlevel);
1340                         setintfield(L, -1, "uses", groupcap.uses);
1341                         // Insert groupcap table into groupcaps table
1342                         lua_setfield(L, -2, name.c_str());
1343                 }
1344                 // Set groupcaps table
1345                 lua_setfield(L, -2, "groupcaps");
1346                 //Create damage_groups table
1347                 lua_newtable(L);
1348                 // For each damage group
1349                 for (const auto &damageGroup : toolcap.damageGroups) {
1350                         // Create damage group table
1351                         lua_pushinteger(L, damageGroup.second);
1352                         lua_setfield(L, -2, damageGroup.first.c_str());
1353                 }
1354                 lua_setfield(L, -2, "damage_groups");
1355 }
1356
1357 /******************************************************************************/
1358 void push_inventory_list(lua_State *L, const InventoryList &invlist)
1359 {
1360         push_items(L, invlist.getItems());
1361 }
1362
1363 /******************************************************************************/
1364 void push_inventory_lists(lua_State *L, const Inventory &inv)
1365 {
1366         const auto &lists = inv.getLists();
1367         lua_createtable(L, 0, lists.size());
1368         for(const InventoryList *list : lists) {
1369                 const std::string &name = list->getName();
1370                 lua_pushlstring(L, name.c_str(), name.size());
1371                 push_inventory_list(L, *list);
1372                 lua_rawset(L, -3);
1373         }
1374 }
1375
1376 /******************************************************************************/
1377 void read_inventory_list(lua_State *L, int tableindex,
1378                 Inventory *inv, const char *name, IGameDef *gdef, int forcesize)
1379 {
1380         if(tableindex < 0)
1381                 tableindex = lua_gettop(L) + 1 + tableindex;
1382
1383         // If nil, delete list
1384         if(lua_isnil(L, tableindex)){
1385                 inv->deleteList(name);
1386                 return;
1387         }
1388
1389         // Get Lua-specified items to insert into the list
1390         std::vector<ItemStack> items = read_items(L, tableindex, gdef);
1391         size_t listsize = (forcesize >= 0) ? forcesize : items.size();
1392
1393         // Create or resize/clear list
1394         InventoryList *invlist = inv->addList(name, listsize);
1395         if (!invlist) {
1396                 luaL_error(L, "inventory list: cannot create list named '%s'", name);
1397                 return;
1398         }
1399
1400         for (size_t i = 0; i < items.size(); ++i) {
1401                 if (i == listsize)
1402                         break; // Truncate provided list of items
1403                 invlist->changeItem(i, items[i]);
1404         }
1405 }
1406
1407 /******************************************************************************/
1408 struct TileAnimationParams read_animation_definition(lua_State *L, int index)
1409 {
1410         if(index < 0)
1411                 index = lua_gettop(L) + 1 + index;
1412
1413         struct TileAnimationParams anim;
1414         anim.type = TAT_NONE;
1415         if (!lua_istable(L, index))
1416                 return anim;
1417
1418         anim.type = (TileAnimationType)
1419                 getenumfield(L, index, "type", es_TileAnimationType,
1420                 TAT_NONE);
1421         if (anim.type == TAT_VERTICAL_FRAMES) {
1422                 // {type="vertical_frames", aspect_w=16, aspect_h=16, length=2.0}
1423                 anim.vertical_frames.aspect_w =
1424                         getintfield_default(L, index, "aspect_w", 16);
1425                 anim.vertical_frames.aspect_h =
1426                         getintfield_default(L, index, "aspect_h", 16);
1427                 anim.vertical_frames.length =
1428                         getfloatfield_default(L, index, "length", 1.0);
1429         } else if (anim.type == TAT_SHEET_2D) {
1430                 // {type="sheet_2d", frames_w=5, frames_h=3, frame_length=0.5}
1431                 getintfield(L, index, "frames_w",
1432                         anim.sheet_2d.frames_w);
1433                 getintfield(L, index, "frames_h",
1434                         anim.sheet_2d.frames_h);
1435                 getfloatfield(L, index, "frame_length",
1436                         anim.sheet_2d.frame_length);
1437         }
1438
1439         return anim;
1440 }
1441
1442 /******************************************************************************/
1443 ToolCapabilities read_tool_capabilities(
1444                 lua_State *L, int table)
1445 {
1446         ToolCapabilities toolcap;
1447         getfloatfield(L, table, "full_punch_interval", toolcap.full_punch_interval);
1448         getintfield(L, table, "max_drop_level", toolcap.max_drop_level);
1449         getintfield(L, table, "punch_attack_uses", toolcap.punch_attack_uses);
1450         lua_getfield(L, table, "groupcaps");
1451         if(lua_istable(L, -1)){
1452                 int table_groupcaps = lua_gettop(L);
1453                 lua_pushnil(L);
1454                 while(lua_next(L, table_groupcaps) != 0){
1455                         // key at index -2 and value at index -1
1456                         std::string groupname = luaL_checkstring(L, -2);
1457                         if(lua_istable(L, -1)){
1458                                 int table_groupcap = lua_gettop(L);
1459                                 // This will be created
1460                                 ToolGroupCap groupcap;
1461                                 // Read simple parameters
1462                                 getintfield(L, table_groupcap, "maxlevel", groupcap.maxlevel);
1463                                 getintfield(L, table_groupcap, "uses", groupcap.uses);
1464                                 // DEPRECATED: maxwear
1465                                 float maxwear = 0;
1466                                 if (getfloatfield(L, table_groupcap, "maxwear", maxwear)){
1467                                         if (maxwear != 0)
1468                                                 groupcap.uses = 1.0/maxwear;
1469                                         else
1470                                                 groupcap.uses = 0;
1471                                         warningstream << "Field \"maxwear\" is deprecated; "
1472                                                         << "replace with uses=1/maxwear" << std::endl;
1473                                         infostream << script_get_backtrace(L) << std::endl;
1474                                 }
1475                                 // Read "times" table
1476                                 lua_getfield(L, table_groupcap, "times");
1477                                 if(lua_istable(L, -1)){
1478                                         int table_times = lua_gettop(L);
1479                                         lua_pushnil(L);
1480                                         while(lua_next(L, table_times) != 0){
1481                                                 // key at index -2 and value at index -1
1482                                                 int rating = luaL_checkinteger(L, -2);
1483                                                 float time = luaL_checknumber(L, -1);
1484                                                 groupcap.times[rating] = time;
1485                                                 // removes value, keeps key for next iteration
1486                                                 lua_pop(L, 1);
1487                                         }
1488                                 }
1489                                 lua_pop(L, 1);
1490                                 // Insert groupcap into toolcap
1491                                 toolcap.groupcaps[groupname] = groupcap;
1492                         }
1493                         // removes value, keeps key for next iteration
1494                         lua_pop(L, 1);
1495                 }
1496         }
1497         lua_pop(L, 1);
1498
1499         lua_getfield(L, table, "damage_groups");
1500         if(lua_istable(L, -1)){
1501                 int table_damage_groups = lua_gettop(L);
1502                 lua_pushnil(L);
1503                 while(lua_next(L, table_damage_groups) != 0){
1504                         // key at index -2 and value at index -1
1505                         std::string groupname = luaL_checkstring(L, -2);
1506                         u16 value = luaL_checkinteger(L, -1);
1507                         toolcap.damageGroups[groupname] = value;
1508                         // removes value, keeps key for next iteration
1509                         lua_pop(L, 1);
1510                 }
1511         }
1512         lua_pop(L, 1);
1513         return toolcap;
1514 }
1515
1516 /******************************************************************************/
1517 void push_dig_params(lua_State *L,const DigParams &params)
1518 {
1519         lua_createtable(L, 0, 3);
1520         setboolfield(L, -1, "diggable", params.diggable);
1521         setfloatfield(L, -1, "time", params.time);
1522         setintfield(L, -1, "wear", params.wear);
1523 }
1524
1525 /******************************************************************************/
1526 void push_hit_params(lua_State *L,const HitParams &params)
1527 {
1528         lua_createtable(L, 0, 3);
1529         setintfield(L, -1, "hp", params.hp);
1530         setintfield(L, -1, "wear", params.wear);
1531 }
1532
1533 /******************************************************************************/
1534
1535 bool getflagsfield(lua_State *L, int table, const char *fieldname,
1536         FlagDesc *flagdesc, u32 *flags, u32 *flagmask)
1537 {
1538         lua_getfield(L, table, fieldname);
1539
1540         bool success = read_flags(L, -1, flagdesc, flags, flagmask);
1541
1542         lua_pop(L, 1);
1543
1544         return success;
1545 }
1546
1547 bool read_flags(lua_State *L, int index, FlagDesc *flagdesc,
1548         u32 *flags, u32 *flagmask)
1549 {
1550         if (lua_isstring(L, index)) {
1551                 std::string flagstr = lua_tostring(L, index);
1552                 *flags = readFlagString(flagstr, flagdesc, flagmask);
1553         } else if (lua_istable(L, index)) {
1554                 *flags = read_flags_table(L, index, flagdesc, flagmask);
1555         } else {
1556                 return false;
1557         }
1558
1559         return true;
1560 }
1561
1562 u32 read_flags_table(lua_State *L, int table, FlagDesc *flagdesc, u32 *flagmask)
1563 {
1564         u32 flags = 0, mask = 0;
1565         char fnamebuf[64] = "no";
1566
1567         for (int i = 0; flagdesc[i].name; i++) {
1568                 bool result;
1569
1570                 if (getboolfield(L, table, flagdesc[i].name, result)) {
1571                         mask |= flagdesc[i].flag;
1572                         if (result)
1573                                 flags |= flagdesc[i].flag;
1574                 }
1575
1576                 strlcpy(fnamebuf + 2, flagdesc[i].name, sizeof(fnamebuf) - 2);
1577                 if (getboolfield(L, table, fnamebuf, result))
1578                         mask |= flagdesc[i].flag;
1579         }
1580
1581         if (flagmask)
1582                 *flagmask = mask;
1583
1584         return flags;
1585 }
1586
1587 void push_flags_string(lua_State *L, FlagDesc *flagdesc, u32 flags, u32 flagmask)
1588 {
1589         std::string flagstring = writeFlagString(flags, flagdesc, flagmask);
1590         lua_pushlstring(L, flagstring.c_str(), flagstring.size());
1591 }
1592
1593 /******************************************************************************/
1594 /* Lua Stored data!                                                           */
1595 /******************************************************************************/
1596
1597 /******************************************************************************/
1598 void read_groups(lua_State *L, int index, ItemGroupList &result)
1599 {
1600         if (lua_isnil(L, index))
1601                 return;
1602
1603         luaL_checktype(L, index, LUA_TTABLE);
1604
1605         result.clear();
1606         lua_pushnil(L);
1607         if (index < 0)
1608                 index -= 1;
1609         while (lua_next(L, index) != 0) {
1610                 // key at index -2 and value at index -1
1611                 std::string name = luaL_checkstring(L, -2);
1612                 int rating = luaL_checkinteger(L, -1);
1613                 // zero rating indicates not in the group
1614                 if (rating != 0)
1615                         result[name] = rating;
1616                 // removes value, keeps key for next iteration
1617                 lua_pop(L, 1);
1618         }
1619 }
1620
1621 /******************************************************************************/
1622 void push_groups(lua_State *L, const ItemGroupList &groups)
1623 {
1624         lua_createtable(L, 0, groups.size());
1625         for (const auto &group : groups) {
1626                 lua_pushinteger(L, group.second);
1627                 lua_setfield(L, -2, group.first.c_str());
1628         }
1629 }
1630
1631 /******************************************************************************/
1632 void push_items(lua_State *L, const std::vector<ItemStack> &items)
1633 {
1634         lua_createtable(L, items.size(), 0);
1635         for (u32 i = 0; i != items.size(); i++) {
1636                 LuaItemStack::create(L, items[i]);
1637                 lua_rawseti(L, -2, i + 1);
1638         }
1639 }
1640
1641 /******************************************************************************/
1642 std::vector<ItemStack> read_items(lua_State *L, int index, IGameDef *gdef)
1643 {
1644         if(index < 0)
1645                 index = lua_gettop(L) + 1 + index;
1646
1647         std::vector<ItemStack> items;
1648         luaL_checktype(L, index, LUA_TTABLE);
1649         lua_pushnil(L);
1650         while (lua_next(L, index)) {
1651                 s32 key = luaL_checkinteger(L, -2);
1652                 if (key < 1) {
1653                         throw LuaError("Invalid inventory list index");
1654                 }
1655                 if (items.size() < (u32) key) {
1656                         items.resize(key);
1657                 }
1658                 items[key - 1] = read_item(L, -1, gdef->idef());
1659                 lua_pop(L, 1);
1660         }
1661         return items;
1662 }
1663
1664 /******************************************************************************/
1665 void luaentity_get(lua_State *L, u16 id)
1666 {
1667         // Get luaentities[i]
1668         lua_getglobal(L, "core");
1669         lua_getfield(L, -1, "luaentities");
1670         luaL_checktype(L, -1, LUA_TTABLE);
1671         lua_pushinteger(L, id);
1672         lua_gettable(L, -2);
1673         lua_remove(L, -2); // Remove luaentities
1674         lua_remove(L, -2); // Remove core
1675 }
1676
1677 /******************************************************************************/
1678 bool read_noiseparams(lua_State *L, int index, NoiseParams *np)
1679 {
1680         if (index < 0)
1681                 index = lua_gettop(L) + 1 + index;
1682
1683         if (!lua_istable(L, index))
1684                 return false;
1685
1686         getfloatfield(L, index, "offset",      np->offset);
1687         getfloatfield(L, index, "scale",       np->scale);
1688         getfloatfield(L, index, "persist",     np->persist);
1689         getfloatfield(L, index, "persistence", np->persist);
1690         getfloatfield(L, index, "lacunarity",  np->lacunarity);
1691         getintfield(L,   index, "seed",        np->seed);
1692         getintfield(L,   index, "octaves",     np->octaves);
1693
1694         u32 flags    = 0;
1695         u32 flagmask = 0;
1696         np->flags = getflagsfield(L, index, "flags", flagdesc_noiseparams,
1697                 &flags, &flagmask) ? flags : NOISE_FLAG_DEFAULTS;
1698
1699         lua_getfield(L, index, "spread");
1700         np->spread  = read_v3f(L, -1);
1701         lua_pop(L, 1);
1702
1703         return true;
1704 }
1705
1706 void push_noiseparams(lua_State *L, NoiseParams *np)
1707 {
1708         lua_newtable(L);
1709         setfloatfield(L, -1, "offset",      np->offset);
1710         setfloatfield(L, -1, "scale",       np->scale);
1711         setfloatfield(L, -1, "persist",     np->persist);
1712         setfloatfield(L, -1, "persistence", np->persist);
1713         setfloatfield(L, -1, "lacunarity",  np->lacunarity);
1714         setintfield(  L, -1, "seed",        np->seed);
1715         setintfield(  L, -1, "octaves",     np->octaves);
1716
1717         push_flags_string(L, flagdesc_noiseparams, np->flags,
1718                 np->flags);
1719         lua_setfield(L, -2, "flags");
1720
1721         push_v3f(L, np->spread);
1722         lua_setfield(L, -2, "spread");
1723 }
1724
1725 /******************************************************************************/
1726 // Returns depth of json value tree
1727 static int push_json_value_getdepth(const Json::Value &value)
1728 {
1729         if (!value.isArray() && !value.isObject())
1730                 return 1;
1731
1732         int maxdepth = 0;
1733         for (const auto &it : value) {
1734                 int elemdepth = push_json_value_getdepth(it);
1735                 if (elemdepth > maxdepth)
1736                         maxdepth = elemdepth;
1737         }
1738         return maxdepth + 1;
1739 }
1740 // Recursive function to convert JSON --> Lua table
1741 static bool push_json_value_helper(lua_State *L, const Json::Value &value,
1742                 int nullindex)
1743 {
1744         switch(value.type()) {
1745                 case Json::nullValue:
1746                 default:
1747                         lua_pushvalue(L, nullindex);
1748                         break;
1749                 case Json::intValue:
1750                         lua_pushinteger(L, value.asLargestInt());
1751                         break;
1752                 case Json::uintValue:
1753                         lua_pushinteger(L, value.asLargestUInt());
1754                         break;
1755                 case Json::realValue:
1756                         lua_pushnumber(L, value.asDouble());
1757                         break;
1758                 case Json::stringValue:
1759                         {
1760                                 const char *str = value.asCString();
1761                                 lua_pushstring(L, str ? str : "");
1762                         }
1763                         break;
1764                 case Json::booleanValue:
1765                         lua_pushboolean(L, value.asInt());
1766                         break;
1767                 case Json::arrayValue:
1768                         lua_createtable(L, value.size(), 0);
1769                         for (Json::Value::const_iterator it = value.begin();
1770                                         it != value.end(); ++it) {
1771                                 push_json_value_helper(L, *it, nullindex);
1772                                 lua_rawseti(L, -2, it.index() + 1);
1773                         }
1774                         break;
1775                 case Json::objectValue:
1776                         lua_createtable(L, 0, value.size());
1777                         for (Json::Value::const_iterator it = value.begin();
1778                                         it != value.end(); ++it) {
1779 #if !defined(JSONCPP_STRING) && (JSONCPP_VERSION_MAJOR < 1 || JSONCPP_VERSION_MINOR < 9)
1780                                 const char *str = it.memberName();
1781                                 lua_pushstring(L, str ? str : "");
1782 #else
1783                                 std::string str = it.name();
1784                                 lua_pushstring(L, str.c_str());
1785 #endif
1786                                 push_json_value_helper(L, *it, nullindex);
1787                                 lua_rawset(L, -3);
1788                         }
1789                         break;
1790         }
1791         return true;
1792 }
1793 // converts JSON --> Lua table; returns false if lua stack limit exceeded
1794 // nullindex: Lua stack index of value to use in place of JSON null
1795 bool push_json_value(lua_State *L, const Json::Value &value, int nullindex)
1796 {
1797         if(nullindex < 0)
1798                 nullindex = lua_gettop(L) + 1 + nullindex;
1799
1800         int depth = push_json_value_getdepth(value);
1801
1802         // The maximum number of Lua stack slots used at each recursion level
1803         // of push_json_value_helper is 2, so make sure there a depth * 2 slots
1804         if (lua_checkstack(L, depth * 2))
1805                 return push_json_value_helper(L, value, nullindex);
1806
1807         return false;
1808 }
1809
1810 // Converts Lua table --> JSON
1811 void read_json_value(lua_State *L, Json::Value &root, int index, u8 recursion)
1812 {
1813         if (recursion > 16) {
1814                 throw SerializationError("Maximum recursion depth exceeded");
1815         }
1816         int type = lua_type(L, index);
1817         if (type == LUA_TBOOLEAN) {
1818                 root = (bool) lua_toboolean(L, index);
1819         } else if (type == LUA_TNUMBER) {
1820                 root = lua_tonumber(L, index);
1821         } else if (type == LUA_TSTRING) {
1822                 size_t len;
1823                 const char *str = lua_tolstring(L, index, &len);
1824                 root = std::string(str, len);
1825         } else if (type == LUA_TTABLE) {
1826                 lua_pushnil(L);
1827                 while (lua_next(L, index)) {
1828                         // Key is at -2 and value is at -1
1829                         Json::Value value;
1830                         read_json_value(L, value, lua_gettop(L), recursion + 1);
1831
1832                         Json::ValueType roottype = root.type();
1833                         int keytype = lua_type(L, -1);
1834                         if (keytype == LUA_TNUMBER) {
1835                                 lua_Number key = lua_tonumber(L, -1);
1836                                 if (roottype != Json::nullValue && roottype != Json::arrayValue) {
1837                                         throw SerializationError("Can't mix array and object values in JSON");
1838                                 } else if (key < 1) {
1839                                         throw SerializationError("Can't use zero-based or negative indexes in JSON");
1840                                 } else if (floor(key) != key) {
1841                                         throw SerializationError("Can't use indexes with a fractional part in JSON");
1842                                 }
1843                                 root[(Json::ArrayIndex) key - 1] = value;
1844                         } else if (keytype == LUA_TSTRING) {
1845                                 if (roottype != Json::nullValue && roottype != Json::objectValue) {
1846                                         throw SerializationError("Can't mix array and object values in JSON");
1847                                 }
1848                                 root[lua_tostring(L, -1)] = value;
1849                         } else {
1850                                 throw SerializationError("Lua key to convert to JSON is not a string or number");
1851                         }
1852                 }
1853         } else if (type == LUA_TNIL) {
1854                 root = Json::nullValue;
1855         } else {
1856                 throw SerializationError("Can only store booleans, numbers, strings, objects, arrays, and null in JSON");
1857         }
1858         lua_pop(L, 1); // Pop value
1859 }
1860
1861 void push_pointed_thing(lua_State *L, const PointedThing &pointed, bool csm,
1862         bool hitpoint)
1863 {
1864         lua_newtable(L);
1865         if (pointed.type == POINTEDTHING_NODE) {
1866                 lua_pushstring(L, "node");
1867                 lua_setfield(L, -2, "type");
1868                 push_v3s16(L, pointed.node_undersurface);
1869                 lua_setfield(L, -2, "under");
1870                 push_v3s16(L, pointed.node_abovesurface);
1871                 lua_setfield(L, -2, "above");
1872         } else if (pointed.type == POINTEDTHING_OBJECT) {
1873                 lua_pushstring(L, "object");
1874                 lua_setfield(L, -2, "type");
1875
1876                 if (csm) {
1877                         lua_pushinteger(L, pointed.object_id);
1878                         lua_setfield(L, -2, "id");
1879                 } else {
1880                         push_objectRef(L, pointed.object_id);
1881                         lua_setfield(L, -2, "ref");
1882                 }
1883         } else {
1884                 lua_pushstring(L, "nothing");
1885                 lua_setfield(L, -2, "type");
1886         }
1887         if (hitpoint && (pointed.type != POINTEDTHING_NOTHING)) {
1888                 push_v3f(L, pointed.intersection_point / BS); // convert to node coords
1889                 lua_setfield(L, -2, "intersection_point");
1890                 push_v3f(L, pointed.intersection_normal);
1891                 lua_setfield(L, -2, "intersection_normal");
1892                 lua_pushinteger(L, pointed.box_id + 1); // change to Lua array index
1893                 lua_setfield(L, -2, "box_id");
1894         }
1895 }
1896
1897 void push_objectRef(lua_State *L, const u16 id)
1898 {
1899         // Get core.object_refs[i]
1900         lua_getglobal(L, "core");
1901         lua_getfield(L, -1, "object_refs");
1902         luaL_checktype(L, -1, LUA_TTABLE);
1903         lua_pushinteger(L, id);
1904         lua_gettable(L, -2);
1905         lua_remove(L, -2); // object_refs
1906         lua_remove(L, -2); // core
1907 }
1908
1909 void read_hud_element(lua_State *L, HudElement *elem)
1910 {
1911         elem->type = (HudElementType)getenumfield(L, 2, "hud_elem_type",
1912                                                                         es_HudElementType, HUD_ELEM_TEXT);
1913
1914         lua_getfield(L, 2, "position");
1915         elem->pos = lua_istable(L, -1) ? read_v2f(L, -1) : v2f();
1916         lua_pop(L, 1);
1917
1918         lua_getfield(L, 2, "scale");
1919         elem->scale = lua_istable(L, -1) ? read_v2f(L, -1) : v2f();
1920         lua_pop(L, 1);
1921
1922         lua_getfield(L, 2, "size");
1923         elem->size = lua_istable(L, -1) ? read_v2s32(L, -1) : v2s32();
1924         lua_pop(L, 1);
1925
1926         elem->name    = getstringfield_default(L, 2, "name", "");
1927         elem->text    = getstringfield_default(L, 2, "text", "");
1928         elem->number  = getintfield_default(L, 2, "number", 0);
1929         if (elem->type == HUD_ELEM_WAYPOINT)
1930                 // waypoints reuse the item field to store precision, item = precision + 1
1931                 elem->item = getintfield_default(L, 2, "precision", -1) + 1;
1932         else
1933                 elem->item = getintfield_default(L, 2, "item", 0);
1934         elem->dir     = getintfield_default(L, 2, "direction", 0);
1935         elem->z_index = MYMAX(S16_MIN, MYMIN(S16_MAX,
1936                         getintfield_default(L, 2, "z_index", 0)));
1937         elem->text2   = getstringfield_default(L, 2, "text2", "");
1938
1939         // Deprecated, only for compatibility's sake
1940         if (elem->dir == 0)
1941                 elem->dir = getintfield_default(L, 2, "dir", 0);
1942
1943         lua_getfield(L, 2, "alignment");
1944         elem->align = lua_istable(L, -1) ? read_v2f(L, -1) : v2f();
1945         lua_pop(L, 1);
1946
1947         lua_getfield(L, 2, "offset");
1948         elem->offset = lua_istable(L, -1) ? read_v2f(L, -1) : v2f();
1949         lua_pop(L, 1);
1950
1951         lua_getfield(L, 2, "world_pos");
1952         elem->world_pos = lua_istable(L, -1) ? read_v3f(L, -1) : v3f();
1953         lua_pop(L, 1);
1954
1955         elem->style = getintfield_default(L, 2, "style", 0);
1956
1957         /* check for known deprecated element usage */
1958         if ((elem->type  == HUD_ELEM_STATBAR) && (elem->size == v2s32()))
1959                 log_deprecated(L,"Deprecated usage of statbar without size!");
1960 }
1961
1962 void push_hud_element(lua_State *L, HudElement *elem)
1963 {
1964         lua_newtable(L);
1965
1966         lua_pushstring(L, es_HudElementType[(u8)elem->type].str);
1967         lua_setfield(L, -2, "type");
1968
1969         push_v2f(L, elem->pos);
1970         lua_setfield(L, -2, "position");
1971
1972         lua_pushstring(L, elem->name.c_str());
1973         lua_setfield(L, -2, "name");
1974
1975         push_v2f(L, elem->scale);
1976         lua_setfield(L, -2, "scale");
1977
1978         lua_pushstring(L, elem->text.c_str());
1979         lua_setfield(L, -2, "text");
1980
1981         lua_pushnumber(L, elem->number);
1982         lua_setfield(L, -2, "number");
1983
1984         if (elem->type == HUD_ELEM_WAYPOINT) {
1985                 // waypoints reuse the item field to store precision, precision = item - 1
1986                 lua_pushnumber(L, elem->item - 1);
1987                 lua_setfield(L, -2, "precision");
1988         }
1989         // push the item field for waypoints as well for backwards compatibility
1990         lua_pushnumber(L, elem->item);
1991         lua_setfield(L, -2, "item");
1992
1993         lua_pushnumber(L, elem->dir);
1994         lua_setfield(L, -2, "direction");
1995
1996         push_v2f(L, elem->offset);
1997         lua_setfield(L, -2, "offset");
1998
1999         push_v2f(L, elem->align);
2000         lua_setfield(L, -2, "alignment");
2001
2002         push_v2s32(L, elem->size);
2003         lua_setfield(L, -2, "size");
2004
2005         // Deprecated, only for compatibility's sake
2006         lua_pushnumber(L, elem->dir);
2007         lua_setfield(L, -2, "dir");
2008
2009         push_v3f(L, elem->world_pos);
2010         lua_setfield(L, -2, "world_pos");
2011
2012         lua_pushnumber(L, elem->z_index);
2013         lua_setfield(L, -2, "z_index");
2014
2015         lua_pushstring(L, elem->text2.c_str());
2016         lua_setfield(L, -2, "text2");
2017
2018         lua_pushinteger(L, elem->style);
2019         lua_setfield(L, -2, "style");
2020 }
2021
2022 bool read_hud_change(lua_State *L, HudElementStat &stat, HudElement *elem, void **value)
2023 {
2024         std::string statstr = lua_tostring(L, 3);
2025         {
2026                 int statint;
2027                 if (!string_to_enum(es_HudElementStat, statint, statstr)) {
2028                         script_log_unique(L, "Unknown HUD stat type: " + statstr, warningstream);
2029                         return false;
2030                 }
2031
2032                 stat = (HudElementStat)statint;
2033         }
2034
2035         switch (stat) {
2036                 case HUD_STAT_POS:
2037                         elem->pos = read_v2f(L, 4);
2038                         *value = &elem->pos;
2039                         break;
2040                 case HUD_STAT_NAME:
2041                         elem->name = luaL_checkstring(L, 4);
2042                         *value = &elem->name;
2043                         break;
2044                 case HUD_STAT_SCALE:
2045                         elem->scale = read_v2f(L, 4);
2046                         *value = &elem->scale;
2047                         break;
2048                 case HUD_STAT_TEXT:
2049                         elem->text = luaL_checkstring(L, 4);
2050                         *value = &elem->text;
2051                         break;
2052                 case HUD_STAT_NUMBER:
2053                         elem->number = luaL_checknumber(L, 4);
2054                         *value = &elem->number;
2055                         break;
2056                 case HUD_STAT_ITEM:
2057                         elem->item = luaL_checknumber(L, 4);
2058                         if (elem->type == HUD_ELEM_WAYPOINT && statstr == "precision")
2059                                 elem->item++;
2060                         *value = &elem->item;
2061                         break;
2062                 case HUD_STAT_DIR:
2063                         elem->dir = luaL_checknumber(L, 4);
2064                         *value = &elem->dir;
2065                         break;
2066                 case HUD_STAT_ALIGN:
2067                         elem->align = read_v2f(L, 4);
2068                         *value = &elem->align;
2069                         break;
2070                 case HUD_STAT_OFFSET:
2071                         elem->offset = read_v2f(L, 4);
2072                         *value = &elem->offset;
2073                         break;
2074                 case HUD_STAT_WORLD_POS:
2075                         elem->world_pos = read_v3f(L, 4);
2076                         *value = &elem->world_pos;
2077                         break;
2078                 case HUD_STAT_SIZE:
2079                         elem->size = read_v2s32(L, 4);
2080                         *value = &elem->size;
2081                         break;
2082                 case HUD_STAT_Z_INDEX:
2083                         elem->z_index = MYMAX(S16_MIN, MYMIN(S16_MAX, luaL_checknumber(L, 4)));
2084                         *value = &elem->z_index;
2085                         break;
2086                 case HUD_STAT_TEXT2:
2087                         elem->text2 = luaL_checkstring(L, 4);
2088                         *value = &elem->text2;
2089                         break;
2090                 case HUD_STAT_STYLE:
2091                         elem->style = luaL_checknumber(L, 4);
2092                         *value = &elem->style;
2093                         break;
2094         }
2095
2096         return true;
2097 }
2098
2099 /******************************************************************************/
2100
2101 // Indices must match values in `enum CollisionType` exactly!!
2102 static const char *collision_type_str[] = {
2103         "node",
2104         "object",
2105 };
2106
2107 // Indices must match values in `enum CollisionAxis` exactly!!
2108 static const char *collision_axis_str[] = {
2109         "x",
2110         "y",
2111         "z",
2112 };
2113
2114 void push_collision_move_result(lua_State *L, const collisionMoveResult &res)
2115 {
2116         lua_createtable(L, 0, 4);
2117
2118         setboolfield(L, -1, "touching_ground", res.touching_ground);
2119         setboolfield(L, -1, "collides", res.collides);
2120         setboolfield(L, -1, "standing_on_object", res.standing_on_object);
2121
2122         /* collisions */
2123         lua_createtable(L, res.collisions.size(), 0);
2124         int i = 1;
2125         for (const auto &c : res.collisions) {
2126                 lua_createtable(L, 0, 5);
2127
2128                 lua_pushstring(L, collision_type_str[c.type]);
2129                 lua_setfield(L, -2, "type");
2130
2131                 assert(c.axis != COLLISION_AXIS_NONE);
2132                 lua_pushstring(L, collision_axis_str[c.axis]);
2133                 lua_setfield(L, -2, "axis");
2134
2135                 if (c.type == COLLISION_NODE) {
2136                         push_v3s16(L, c.node_p);
2137                         lua_setfield(L, -2, "node_pos");
2138                 } else if (c.type == COLLISION_OBJECT) {
2139                         push_objectRef(L, c.object->getId());
2140                         lua_setfield(L, -2, "object");
2141                 }
2142
2143                 push_v3f(L, c.old_speed / BS);
2144                 lua_setfield(L, -2, "old_velocity");
2145
2146                 push_v3f(L, c.new_speed / BS);
2147                 lua_setfield(L, -2, "new_velocity");
2148
2149                 lua_rawseti(L, -2, i++);
2150         }
2151         lua_setfield(L, -2, "collisions");
2152         /**/
2153 }
2154
2155
2156 void push_mod_spec(lua_State *L, const ModSpec &spec, bool include_unsatisfied)
2157 {
2158         lua_newtable(L);
2159
2160         lua_pushstring(L, spec.name.c_str());
2161         lua_setfield(L, -2, "name");
2162
2163         lua_pushstring(L, spec.author.c_str());
2164         lua_setfield(L, -2, "author");
2165
2166         lua_pushinteger(L, spec.release);
2167         lua_setfield(L, -2, "release");
2168
2169         lua_pushstring(L, spec.desc.c_str());
2170         lua_setfield(L, -2, "description");
2171
2172         lua_pushstring(L, spec.path.c_str());
2173         lua_setfield(L, -2, "path");
2174
2175         lua_pushstring(L, spec.virtual_path.c_str());
2176         lua_setfield(L, -2, "virtual_path");
2177
2178         lua_newtable(L);
2179         int i = 1;
2180         for (const auto &dep : spec.unsatisfied_depends) {
2181                 lua_pushstring(L, dep.c_str());
2182                 lua_rawseti(L, -2, i++);
2183         }
2184         lua_setfield(L, -2, "unsatisfied_depends");
2185 }