[CSM] Add event on_place_node API lua (#5548)
[oweals/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 "cpp_api/s_node.h"
25 #include "lua_api/l_object.h"
26 #include "lua_api/l_item.h"
27 #include "common/c_internal.h"
28 #include "server.h"
29 #include "log.h"
30 #include "tool.h"
31 #include "serverobject.h"
32 #include "porting.h"
33 #include "mg_schematic.h"
34 #include "noise.h"
35 #include "util/pointedthing.h"
36 #include <json/json.h>
37
38 struct EnumString es_TileAnimationType[] =
39 {
40         {TAT_NONE, "none"},
41         {TAT_VERTICAL_FRAMES, "vertical_frames"},
42         {TAT_SHEET_2D, "sheet_2d"},
43         {0, NULL},
44 };
45
46 /******************************************************************************/
47 void read_item_definition(lua_State* L, int index,
48                 const ItemDefinition &default_def, ItemDefinition &def)
49 {
50         if (index < 0)
51                 index = lua_gettop(L) + 1 + index;
52
53         def.type = (ItemType)getenumfield(L, index, "type",
54                         es_ItemType, ITEM_NONE);
55         getstringfield(L, index, "name", def.name);
56         getstringfield(L, index, "description", def.description);
57         getstringfield(L, index, "inventory_image", def.inventory_image);
58         getstringfield(L, index, "wield_image", def.wield_image);
59         getstringfield(L, index, "palette", def.palette_image);
60
61         // Read item color.
62         lua_getfield(L, index, "color");
63         read_color(L, -1, &def.color);
64         lua_pop(L, 1);
65
66         lua_getfield(L, index, "wield_scale");
67         if(lua_istable(L, -1)){
68                 def.wield_scale = check_v3f(L, -1);
69         }
70         lua_pop(L, 1);
71
72         int stack_max = getintfield_default(L, index, "stack_max", def.stack_max);
73         def.stack_max = rangelim(stack_max, 1, U16_MAX);
74
75         lua_getfield(L, index, "on_use");
76         def.usable = lua_isfunction(L, -1);
77         lua_pop(L, 1);
78
79         getboolfield(L, index, "liquids_pointable", def.liquids_pointable);
80
81         warn_if_field_exists(L, index, "tool_digging_properties",
82                         "Deprecated; use tool_capabilities");
83
84         lua_getfield(L, index, "tool_capabilities");
85         if(lua_istable(L, -1)){
86                 def.tool_capabilities = new ToolCapabilities(
87                                 read_tool_capabilities(L, -1));
88         }
89
90         // If name is "" (hand), ensure there are ToolCapabilities
91         // because it will be looked up there whenever any other item has
92         // no ToolCapabilities
93         if(def.name == "" && def.tool_capabilities == NULL){
94                 def.tool_capabilities = new ToolCapabilities();
95         }
96
97         lua_getfield(L, index, "groups");
98         read_groups(L, -1, def.groups);
99         lua_pop(L, 1);
100
101         lua_getfield(L, index, "sounds");
102         if(lua_istable(L, -1)){
103                 lua_getfield(L, -1, "place");
104                 read_soundspec(L, -1, def.sound_place);
105                 lua_pop(L, 1);
106                 lua_getfield(L, -1, "place_failed");
107                 read_soundspec(L, -1, def.sound_place_failed);
108                 lua_pop(L, 1);
109         }
110         lua_pop(L, 1);
111
112         def.range = getfloatfield_default(L, index, "range", def.range);
113
114         // Client shall immediately place this node when player places the item.
115         // Server will update the precise end result a moment later.
116         // "" = no prediction
117         getstringfield(L, index, "node_placement_prediction",
118                         def.node_placement_prediction);
119 }
120
121 /******************************************************************************/
122 void push_item_definition(lua_State *L, const ItemDefinition &i)
123 {
124         lua_newtable(L);
125         lua_pushstring(L, i.name.c_str());
126         lua_setfield(L, -2, "name");
127         lua_pushstring(L, i.description.c_str());
128         lua_setfield(L, -2, "description");
129 }
130
131 /******************************************************************************/
132 void read_object_properties(lua_State *L, int index,
133                 ObjectProperties *prop, IItemDefManager *idef)
134 {
135         if(index < 0)
136                 index = lua_gettop(L) + 1 + index;
137         if(!lua_istable(L, index))
138                 return;
139
140         prop->hp_max = getintfield_default(L, -1, "hp_max", 10);
141
142         getboolfield(L, -1, "physical", prop->physical);
143         getboolfield(L, -1, "collide_with_objects", prop->collideWithObjects);
144
145         getfloatfield(L, -1, "weight", prop->weight);
146
147         lua_getfield(L, -1, "collisionbox");
148         if(lua_istable(L, -1))
149                 prop->collisionbox = read_aabb3f(L, -1, 1.0);
150         lua_pop(L, 1);
151
152         getstringfield(L, -1, "visual", prop->visual);
153
154         getstringfield(L, -1, "mesh", prop->mesh);
155
156         lua_getfield(L, -1, "visual_size");
157         if(lua_istable(L, -1))
158                 prop->visual_size = read_v2f(L, -1);
159         lua_pop(L, 1);
160
161         lua_getfield(L, -1, "textures");
162         if(lua_istable(L, -1)){
163                 prop->textures.clear();
164                 int table = lua_gettop(L);
165                 lua_pushnil(L);
166                 while(lua_next(L, table) != 0){
167                         // key at index -2 and value at index -1
168                         if(lua_isstring(L, -1))
169                                 prop->textures.push_back(lua_tostring(L, -1));
170                         else
171                                 prop->textures.push_back("");
172                         // removes value, keeps key for next iteration
173                         lua_pop(L, 1);
174                 }
175         }
176         lua_pop(L, 1);
177
178         lua_getfield(L, -1, "colors");
179         if (lua_istable(L, -1)) {
180                 int table = lua_gettop(L);
181                 prop->colors.clear();
182                 for (lua_pushnil(L); lua_next(L, table); lua_pop(L, 1)) {
183                         video::SColor color(255, 255, 255, 255);
184                         read_color(L, -1, &color);
185                         prop->colors.push_back(color);
186                 }
187         }
188         lua_pop(L, 1);
189
190         lua_getfield(L, -1, "spritediv");
191         if(lua_istable(L, -1))
192                 prop->spritediv = read_v2s16(L, -1);
193         lua_pop(L, 1);
194
195         lua_getfield(L, -1, "initial_sprite_basepos");
196         if(lua_istable(L, -1))
197                 prop->initial_sprite_basepos = read_v2s16(L, -1);
198         lua_pop(L, 1);
199
200         getboolfield(L, -1, "is_visible", prop->is_visible);
201         getboolfield(L, -1, "makes_footstep_sound", prop->makes_footstep_sound);
202         getfloatfield(L, -1, "automatic_rotate", prop->automatic_rotate);
203         if (getfloatfield(L, -1, "stepheight", prop->stepheight))
204                 prop->stepheight *= BS;
205         lua_getfield(L, -1, "automatic_face_movement_dir");
206         if (lua_isnumber(L, -1)) {
207                 prop->automatic_face_movement_dir = true;
208                 prop->automatic_face_movement_dir_offset = luaL_checknumber(L, -1);
209         } else if (lua_isboolean(L, -1)) {
210                 prop->automatic_face_movement_dir = lua_toboolean(L, -1);
211                 prop->automatic_face_movement_dir_offset = 0.0;
212         }
213         lua_pop(L, 1);
214         getboolfield(L, -1, "backface_culling", prop->backface_culling);
215
216         getstringfield(L, -1, "nametag", prop->nametag);
217         lua_getfield(L, -1, "nametag_color");
218         if (!lua_isnil(L, -1)) {
219                 video::SColor color = prop->nametag_color;
220                 if (read_color(L, -1, &color))
221                         prop->nametag_color = color;
222         }
223         lua_pop(L, 1);
224
225         lua_getfield(L, -1, "automatic_face_movement_max_rotation_per_sec");
226         if (lua_isnumber(L, -1)) {
227                 prop->automatic_face_movement_max_rotation_per_sec = luaL_checknumber(L, -1);
228         }
229         lua_pop(L, 1);
230         getstringfield(L, -1, "infotext", prop->infotext);
231         lua_getfield(L, -1, "wield_item");
232         if (!lua_isnil(L, -1))
233                 prop->wield_item = read_item(L, -1, idef).getItemString();
234         lua_pop(L, 1);
235 }
236
237 /******************************************************************************/
238 void push_object_properties(lua_State *L, ObjectProperties *prop)
239 {
240         lua_newtable(L);
241         lua_pushnumber(L, prop->hp_max);
242         lua_setfield(L, -2, "hp_max");
243         lua_pushboolean(L, prop->physical);
244         lua_setfield(L, -2, "physical");
245         lua_pushboolean(L, prop->collideWithObjects);
246         lua_setfield(L, -2, "collide_with_objects");
247         lua_pushnumber(L, prop->weight);
248         lua_setfield(L, -2, "weight");
249         push_aabb3f(L, prop->collisionbox);
250         lua_setfield(L, -2, "collisionbox");
251         lua_pushlstring(L, prop->visual.c_str(), prop->visual.size());
252         lua_setfield(L, -2, "visual");
253         lua_pushlstring(L, prop->mesh.c_str(), prop->mesh.size());
254         lua_setfield(L, -2, "mesh");
255         push_v2f(L, prop->visual_size);
256         lua_setfield(L, -2, "visual_size");
257
258         lua_newtable(L);
259         u16 i = 1;
260         for (std::vector<std::string>::iterator it = prop->textures.begin();
261                         it != prop->textures.end(); ++it) {
262                 lua_pushlstring(L, it->c_str(), it->size());
263                 lua_rawseti(L, -2, i);
264         }
265         lua_setfield(L, -2, "textures");
266
267         lua_newtable(L);
268         i = 1;
269         for (std::vector<video::SColor>::iterator it = prop->colors.begin();
270                         it != prop->colors.end(); ++it) {
271                 push_ARGB8(L, *it);
272                 lua_rawseti(L, -2, i);
273         }
274         lua_setfield(L, -2, "colors");
275
276         push_v2s16(L, prop->spritediv);
277         lua_setfield(L, -2, "spritediv");
278         push_v2s16(L, prop->initial_sprite_basepos);
279         lua_setfield(L, -2, "initial_sprite_basepos");
280         lua_pushboolean(L, prop->is_visible);
281         lua_setfield(L, -2, "is_visible");
282         lua_pushboolean(L, prop->makes_footstep_sound);
283         lua_setfield(L, -2, "makes_footstep_sound");
284         lua_pushnumber(L, prop->automatic_rotate);
285         lua_setfield(L, -2, "automatic_rotate");
286         lua_pushnumber(L, prop->stepheight / BS);
287         lua_setfield(L, -2, "stepheight");
288         if (prop->automatic_face_movement_dir)
289                 lua_pushnumber(L, prop->automatic_face_movement_dir_offset);
290         else
291                 lua_pushboolean(L, false);
292         lua_setfield(L, -2, "automatic_face_movement_dir");
293         lua_pushboolean(L, prop->backface_culling);
294         lua_setfield(L, -2, "backface_culling");
295         lua_pushlstring(L, prop->nametag.c_str(), prop->nametag.size());
296         lua_setfield(L, -2, "nametag");
297         push_ARGB8(L, prop->nametag_color);
298         lua_setfield(L, -2, "nametag_color");
299         lua_pushnumber(L, prop->automatic_face_movement_max_rotation_per_sec);
300         lua_setfield(L, -2, "automatic_face_movement_max_rotation_per_sec");
301         lua_pushlstring(L, prop->infotext.c_str(), prop->infotext.size());
302         lua_setfield(L, -2, "infotext");
303         lua_pushlstring(L, prop->wield_item.c_str(), prop->wield_item.size());
304         lua_setfield(L, -2, "wield_item");
305 }
306
307 /******************************************************************************/
308 TileDef read_tiledef(lua_State *L, int index, u8 drawtype)
309 {
310         if(index < 0)
311                 index = lua_gettop(L) + 1 + index;
312
313         TileDef tiledef;
314
315         bool default_tiling = true;
316         bool default_culling = true;
317         switch (drawtype) {
318                 case NDT_PLANTLIKE:
319                 case NDT_FIRELIKE:
320                         default_tiling = false;
321                         // "break" is omitted here intentionaly, as PLANTLIKE
322                         // FIRELIKE drawtype both should default to having
323                         // backface_culling to false.
324                 case NDT_MESH:
325                 case NDT_LIQUID:
326                         default_culling = false;
327                         break;
328                 default:
329                         break;
330         }
331
332         // key at index -2 and value at index
333         if(lua_isstring(L, index)){
334                 // "default_lava.png"
335                 tiledef.name = lua_tostring(L, index);
336                 tiledef.tileable_vertical = default_tiling;
337                 tiledef.tileable_horizontal = default_tiling;
338                 tiledef.backface_culling = default_culling;
339         }
340         else if(lua_istable(L, index))
341         {
342                 // name="default_lava.png"
343                 tiledef.name = "";
344                 getstringfield(L, index, "name", tiledef.name);
345                 getstringfield(L, index, "image", tiledef.name); // MaterialSpec compat.
346                 tiledef.backface_culling = getboolfield_default(
347                         L, index, "backface_culling", default_culling);
348                 tiledef.tileable_horizontal = getboolfield_default(
349                         L, index, "tileable_horizontal", default_tiling);
350                 tiledef.tileable_vertical = getboolfield_default(
351                         L, index, "tileable_vertical", default_tiling);
352                 // color = ...
353                 lua_getfield(L, index, "color");
354                 tiledef.has_color = read_color(L, -1, &tiledef.color);
355                 lua_pop(L, 1);
356                 // animation = {}
357                 lua_getfield(L, index, "animation");
358                 tiledef.animation = read_animation_definition(L, -1);
359                 lua_pop(L, 1);
360         }
361
362         return tiledef;
363 }
364
365 /******************************************************************************/
366 ContentFeatures read_content_features(lua_State *L, int index)
367 {
368         if(index < 0)
369                 index = lua_gettop(L) + 1 + index;
370
371         ContentFeatures f;
372
373         /* Cache existence of some callbacks */
374         lua_getfield(L, index, "on_construct");
375         if(!lua_isnil(L, -1)) f.has_on_construct = true;
376         lua_pop(L, 1);
377         lua_getfield(L, index, "on_destruct");
378         if(!lua_isnil(L, -1)) f.has_on_destruct = true;
379         lua_pop(L, 1);
380         lua_getfield(L, index, "after_destruct");
381         if(!lua_isnil(L, -1)) f.has_after_destruct = true;
382         lua_pop(L, 1);
383
384         lua_getfield(L, index, "on_rightclick");
385         f.rightclickable = lua_isfunction(L, -1);
386         lua_pop(L, 1);
387
388         /* Name */
389         getstringfield(L, index, "name", f.name);
390
391         /* Groups */
392         lua_getfield(L, index, "groups");
393         read_groups(L, -1, f.groups);
394         lua_pop(L, 1);
395
396         /* Visual definition */
397
398         f.drawtype = (NodeDrawType)getenumfield(L, index, "drawtype",
399                         ScriptApiNode::es_DrawType,NDT_NORMAL);
400         getfloatfield(L, index, "visual_scale", f.visual_scale);
401
402         /* Meshnode model filename */
403         getstringfield(L, index, "mesh", f.mesh);
404
405         // tiles = {}
406         lua_getfield(L, index, "tiles");
407         // If nil, try the deprecated name "tile_images" instead
408         if(lua_isnil(L, -1)){
409                 lua_pop(L, 1);
410                 warn_if_field_exists(L, index, "tile_images",
411                                 "Deprecated; new name is \"tiles\".");
412                 lua_getfield(L, index, "tile_images");
413         }
414         if(lua_istable(L, -1)){
415                 int table = lua_gettop(L);
416                 lua_pushnil(L);
417                 int i = 0;
418                 while(lua_next(L, table) != 0){
419                         // Read tiledef from value
420                         f.tiledef[i] = read_tiledef(L, -1, f.drawtype);
421                         // removes value, keeps key for next iteration
422                         lua_pop(L, 1);
423                         i++;
424                         if(i==6){
425                                 lua_pop(L, 1);
426                                 break;
427                         }
428                 }
429                 // Copy last value to all remaining textures
430                 if(i >= 1){
431                         TileDef lasttile = f.tiledef[i-1];
432                         while(i < 6){
433                                 f.tiledef[i] = lasttile;
434                                 i++;
435                         }
436                 }
437         }
438         lua_pop(L, 1);
439
440         // overlay_tiles = {}
441         lua_getfield(L, index, "overlay_tiles");
442         if (lua_istable(L, -1)) {
443                 int table = lua_gettop(L);
444                 lua_pushnil(L);
445                 int i = 0;
446                 while (lua_next(L, table) != 0) {
447                         // Read tiledef from value
448                         f.tiledef_overlay[i] = read_tiledef(L, -1, f.drawtype);
449                         // removes value, keeps key for next iteration
450                         lua_pop(L, 1);
451                         i++;
452                         if (i == 6) {
453                                 lua_pop(L, 1);
454                                 break;
455                         }
456                 }
457                 // Copy last value to all remaining textures
458                 if (i >= 1) {
459                         TileDef lasttile = f.tiledef_overlay[i - 1];
460                         while (i < 6) {
461                                 f.tiledef_overlay[i] = lasttile;
462                                 i++;
463                         }
464                 }
465         }
466         lua_pop(L, 1);
467
468         // special_tiles = {}
469         lua_getfield(L, index, "special_tiles");
470         // If nil, try the deprecated name "special_materials" instead
471         if(lua_isnil(L, -1)){
472                 lua_pop(L, 1);
473                 warn_if_field_exists(L, index, "special_materials",
474                                 "Deprecated; new name is \"special_tiles\".");
475                 lua_getfield(L, index, "special_materials");
476         }
477         if(lua_istable(L, -1)){
478                 int table = lua_gettop(L);
479                 lua_pushnil(L);
480                 int i = 0;
481                 while(lua_next(L, table) != 0){
482                         // Read tiledef from value
483                         f.tiledef_special[i] = read_tiledef(L, -1, f.drawtype);
484                         // removes value, keeps key for next iteration
485                         lua_pop(L, 1);
486                         i++;
487                         if(i==CF_SPECIAL_COUNT){
488                                 lua_pop(L, 1);
489                                 break;
490                         }
491                 }
492         }
493         lua_pop(L, 1);
494
495         f.alpha = getintfield_default(L, index, "alpha", 255);
496
497         bool usealpha = getboolfield_default(L, index,
498                         "use_texture_alpha", false);
499         if (usealpha)
500                 f.alpha = 0;
501
502         // Read node color.
503         lua_getfield(L, index, "color");
504         read_color(L, -1, &f.color);
505         lua_pop(L, 1);
506
507         getstringfield(L, index, "palette", f.palette_name);
508
509         /* Other stuff */
510
511         lua_getfield(L, index, "post_effect_color");
512         read_color(L, -1, &f.post_effect_color);
513         lua_pop(L, 1);
514
515         f.param_type = (ContentParamType)getenumfield(L, index, "paramtype",
516                         ScriptApiNode::es_ContentParamType, CPT_NONE);
517         f.param_type_2 = (ContentParamType2)getenumfield(L, index, "paramtype2",
518                         ScriptApiNode::es_ContentParamType2, CPT2_NONE);
519
520         if (f.palette_name != "" &&
521                         !(f.param_type_2 == CPT2_COLOR ||
522                         f.param_type_2 == CPT2_COLORED_FACEDIR ||
523                         f.param_type_2 == CPT2_COLORED_WALLMOUNTED))
524                 warningstream << "Node " << f.name.c_str()
525                         << " has a palette, but not a suitable paramtype2." << std::endl;
526
527         // Warn about some deprecated fields
528         warn_if_field_exists(L, index, "wall_mounted",
529                         "Deprecated; use paramtype2 = 'wallmounted'");
530         warn_if_field_exists(L, index, "light_propagates",
531                         "Deprecated; determined from paramtype");
532         warn_if_field_exists(L, index, "dug_item",
533                         "Deprecated; use 'drop' field");
534         warn_if_field_exists(L, index, "extra_dug_item",
535                         "Deprecated; use 'drop' field");
536         warn_if_field_exists(L, index, "extra_dug_item_rarity",
537                         "Deprecated; use 'drop' field");
538         warn_if_field_exists(L, index, "metadata_name",
539                         "Deprecated; use on_add and metadata callbacks");
540
541         // True for all ground-like things like stone and mud, false for eg. trees
542         getboolfield(L, index, "is_ground_content", f.is_ground_content);
543         f.light_propagates = (f.param_type == CPT_LIGHT);
544         getboolfield(L, index, "sunlight_propagates", f.sunlight_propagates);
545         // This is used for collision detection.
546         // Also for general solidness queries.
547         getboolfield(L, index, "walkable", f.walkable);
548         // Player can point to these
549         getboolfield(L, index, "pointable", f.pointable);
550         // Player can dig these
551         getboolfield(L, index, "diggable", f.diggable);
552         // Player can climb these
553         getboolfield(L, index, "climbable", f.climbable);
554         // Player can build on these
555         getboolfield(L, index, "buildable_to", f.buildable_to);
556         // Liquids flow into and replace node
557         getboolfield(L, index, "floodable", f.floodable);
558         // Whether the node is non-liquid, source liquid or flowing liquid
559         f.liquid_type = (LiquidType)getenumfield(L, index, "liquidtype",
560                         ScriptApiNode::es_LiquidType, LIQUID_NONE);
561         // If the content is liquid, this is the flowing version of the liquid.
562         getstringfield(L, index, "liquid_alternative_flowing",
563                         f.liquid_alternative_flowing);
564         // If the content is liquid, this is the source version of the liquid.
565         getstringfield(L, index, "liquid_alternative_source",
566                         f.liquid_alternative_source);
567         // Viscosity for fluid flow, ranging from 1 to 7, with
568         // 1 giving almost instantaneous propagation and 7 being
569         // the slowest possible
570         f.liquid_viscosity = getintfield_default(L, index,
571                         "liquid_viscosity", f.liquid_viscosity);
572         f.liquid_range = getintfield_default(L, index,
573                         "liquid_range", f.liquid_range);
574         f.leveled = getintfield_default(L, index, "leveled", f.leveled);
575
576         getboolfield(L, index, "liquid_renewable", f.liquid_renewable);
577         f.drowning = getintfield_default(L, index,
578                         "drowning", f.drowning);
579         // Amount of light the node emits
580         f.light_source = getintfield_default(L, index,
581                         "light_source", f.light_source);
582         if (f.light_source > LIGHT_MAX) {
583                 warningstream << "Node " << f.name.c_str()
584                         << " had greater light_source than " << LIGHT_MAX
585                         << ", it was reduced." << std::endl;
586                 f.light_source = LIGHT_MAX;
587         }
588         f.damage_per_second = getintfield_default(L, index,
589                         "damage_per_second", f.damage_per_second);
590
591         lua_getfield(L, index, "node_box");
592         if(lua_istable(L, -1))
593                 f.node_box = read_nodebox(L, -1);
594         lua_pop(L, 1);
595
596         lua_getfield(L, index, "connects_to");
597         if (lua_istable(L, -1)) {
598                 int table = lua_gettop(L);
599                 lua_pushnil(L);
600                 while (lua_next(L, table) != 0) {
601                         // Value at -1
602                         f.connects_to.push_back(lua_tostring(L, -1));
603                         lua_pop(L, 1);
604                 }
605         }
606         lua_pop(L, 1);
607
608         lua_getfield(L, index, "connect_sides");
609         if (lua_istable(L, -1)) {
610                 int table = lua_gettop(L);
611                 lua_pushnil(L);
612                 while (lua_next(L, table) != 0) {
613                         // Value at -1
614                         std::string side(lua_tostring(L, -1));
615                         // Note faces are flipped to make checking easier
616                         if (side == "top")
617                                 f.connect_sides |= 2;
618                         else if (side == "bottom")
619                                 f.connect_sides |= 1;
620                         else if (side == "front")
621                                 f.connect_sides |= 16;
622                         else if (side == "left")
623                                 f.connect_sides |= 32;
624                         else if (side == "back")
625                                 f.connect_sides |= 4;
626                         else if (side == "right")
627                                 f.connect_sides |= 8;
628                         else
629                                 warningstream << "Unknown value for \"connect_sides\": "
630                                         << side << std::endl;
631                         lua_pop(L, 1);
632                 }
633         }
634         lua_pop(L, 1);
635
636         lua_getfield(L, index, "selection_box");
637         if(lua_istable(L, -1))
638                 f.selection_box = read_nodebox(L, -1);
639         lua_pop(L, 1);
640
641         lua_getfield(L, index, "collision_box");
642         if(lua_istable(L, -1))
643                 f.collision_box = read_nodebox(L, -1);
644         lua_pop(L, 1);
645
646         f.waving = getintfield_default(L, index,
647                         "waving", f.waving);
648
649         // Set to true if paramtype used to be 'facedir_simple'
650         getboolfield(L, index, "legacy_facedir_simple", f.legacy_facedir_simple);
651         // Set to true if wall_mounted used to be set to true
652         getboolfield(L, index, "legacy_wallmounted", f.legacy_wallmounted);
653
654         // Sound table
655         lua_getfield(L, index, "sounds");
656         if(lua_istable(L, -1)){
657                 lua_getfield(L, -1, "footstep");
658                 read_soundspec(L, -1, f.sound_footstep);
659                 lua_pop(L, 1);
660                 lua_getfield(L, -1, "dig");
661                 read_soundspec(L, -1, f.sound_dig);
662                 lua_pop(L, 1);
663                 lua_getfield(L, -1, "dug");
664                 read_soundspec(L, -1, f.sound_dug);
665                 lua_pop(L, 1);
666         }
667         lua_pop(L, 1);
668
669         return f;
670 }
671
672 /******************************************************************************/
673 void read_server_sound_params(lua_State *L, int index,
674                 ServerSoundParams &params)
675 {
676         if(index < 0)
677                 index = lua_gettop(L) + 1 + index;
678         // Clear
679         params = ServerSoundParams();
680         if(lua_istable(L, index)){
681                 getfloatfield(L, index, "gain", params.gain);
682                 getstringfield(L, index, "to_player", params.to_player);
683                 lua_getfield(L, index, "pos");
684                 if(!lua_isnil(L, -1)){
685                         v3f p = read_v3f(L, -1)*BS;
686                         params.pos = p;
687                         params.type = ServerSoundParams::SSP_POSITIONAL;
688                 }
689                 lua_pop(L, 1);
690                 lua_getfield(L, index, "object");
691                 if(!lua_isnil(L, -1)){
692                         ObjectRef *ref = ObjectRef::checkobject(L, -1);
693                         ServerActiveObject *sao = ObjectRef::getobject(ref);
694                         if(sao){
695                                 params.object = sao->getId();
696                                 params.type = ServerSoundParams::SSP_OBJECT;
697                         }
698                 }
699                 lua_pop(L, 1);
700                 params.max_hear_distance = BS*getfloatfield_default(L, index,
701                                 "max_hear_distance", params.max_hear_distance/BS);
702                 getboolfield(L, index, "loop", params.loop);
703         }
704 }
705
706 /******************************************************************************/
707 void read_soundspec(lua_State *L, int index, SimpleSoundSpec &spec)
708 {
709         if(index < 0)
710                 index = lua_gettop(L) + 1 + index;
711         if(lua_isnil(L, index)){
712         } else if(lua_istable(L, index)){
713                 getstringfield(L, index, "name", spec.name);
714                 getfloatfield(L, index, "gain", spec.gain);
715         } else if(lua_isstring(L, index)){
716                 spec.name = lua_tostring(L, index);
717         }
718 }
719
720 /******************************************************************************/
721 NodeBox read_nodebox(lua_State *L, int index)
722 {
723         NodeBox nodebox;
724         if(lua_istable(L, -1)){
725                 nodebox.type = (NodeBoxType)getenumfield(L, index, "type",
726                                 ScriptApiNode::es_NodeBoxType, NODEBOX_REGULAR);
727
728 #define NODEBOXREAD(n, s) \
729         do { \
730                 lua_getfield(L, index, (s)); \
731                 if (lua_istable(L, -1)) \
732                         (n) = read_aabb3f(L, -1, BS); \
733                 lua_pop(L, 1); \
734         } while (0)
735
736 #define NODEBOXREADVEC(n, s) \
737         do { \
738                 lua_getfield(L, index, (s)); \
739                 if (lua_istable(L, -1)) \
740                         (n) = read_aabb3f_vector(L, -1, BS); \
741                 lua_pop(L, 1); \
742         } while (0)
743                 NODEBOXREADVEC(nodebox.fixed, "fixed");
744                 NODEBOXREAD(nodebox.wall_top, "wall_top");
745                 NODEBOXREAD(nodebox.wall_bottom, "wall_bottom");
746                 NODEBOXREAD(nodebox.wall_side, "wall_side");
747                 NODEBOXREADVEC(nodebox.connect_top, "connect_top");
748                 NODEBOXREADVEC(nodebox.connect_bottom, "connect_bottom");
749                 NODEBOXREADVEC(nodebox.connect_front, "connect_front");
750                 NODEBOXREADVEC(nodebox.connect_left, "connect_left");
751                 NODEBOXREADVEC(nodebox.connect_back, "connect_back");
752                 NODEBOXREADVEC(nodebox.connect_right, "connect_right");
753         }
754         return nodebox;
755 }
756
757 /******************************************************************************/
758 MapNode readnode(lua_State *L, int index, INodeDefManager *ndef)
759 {
760         lua_getfield(L, index, "name");
761         if (!lua_isstring(L, -1))
762                 throw LuaError("Node name is not set or is not a string!");
763         const char *name = lua_tostring(L, -1);
764         lua_pop(L, 1);
765
766         u8 param1 = 0;
767         lua_getfield(L, index, "param1");
768         if (!lua_isnil(L, -1))
769                 param1 = lua_tonumber(L, -1);
770         lua_pop(L, 1);
771
772         u8 param2 = 0;
773         lua_getfield(L, index, "param2");
774         if (!lua_isnil(L, -1))
775                 param2 = lua_tonumber(L, -1);
776         lua_pop(L, 1);
777
778         return MapNode(ndef, name, param1, param2);
779 }
780
781 /******************************************************************************/
782 void pushnode(lua_State *L, const MapNode &n, INodeDefManager *ndef)
783 {
784         lua_newtable(L);
785         lua_pushstring(L, ndef->get(n).name.c_str());
786         lua_setfield(L, -2, "name");
787         lua_pushnumber(L, n.getParam1());
788         lua_setfield(L, -2, "param1");
789         lua_pushnumber(L, n.getParam2());
790         lua_setfield(L, -2, "param2");
791 }
792
793 /******************************************************************************/
794 void warn_if_field_exists(lua_State *L, int table,
795                 const char *name, const std::string &message)
796 {
797         lua_getfield(L, table, name);
798         if (!lua_isnil(L, -1)) {
799                 warningstream << "Field \"" << name << "\": "
800                                 << message << std::endl;
801                 infostream << script_get_backtrace(L) << std::endl;
802         }
803         lua_pop(L, 1);
804 }
805
806 /******************************************************************************/
807 int getenumfield(lua_State *L, int table,
808                 const char *fieldname, const EnumString *spec, int default_)
809 {
810         int result = default_;
811         string_to_enum(spec, result,
812                         getstringfield_default(L, table, fieldname, ""));
813         return result;
814 }
815
816 /******************************************************************************/
817 bool string_to_enum(const EnumString *spec, int &result,
818                 const std::string &str)
819 {
820         const EnumString *esp = spec;
821         while(esp->str){
822                 if(str == std::string(esp->str)){
823                         result = esp->num;
824                         return true;
825                 }
826                 esp++;
827         }
828         return false;
829 }
830
831 /******************************************************************************/
832 ItemStack read_item(lua_State* L, int index, IItemDefManager *idef)
833 {
834         if(index < 0)
835                 index = lua_gettop(L) + 1 + index;
836
837         if(lua_isnil(L, index))
838         {
839                 return ItemStack();
840         }
841         else if(lua_isuserdata(L, index))
842         {
843                 // Convert from LuaItemStack
844                 LuaItemStack *o = LuaItemStack::checkobject(L, index);
845                 return o->getItem();
846         }
847         else if(lua_isstring(L, index))
848         {
849                 // Convert from itemstring
850                 std::string itemstring = lua_tostring(L, index);
851                 try
852                 {
853                         ItemStack item;
854                         item.deSerialize(itemstring, idef);
855                         return item;
856                 }
857                 catch(SerializationError &e)
858                 {
859                         warningstream<<"unable to create item from itemstring"
860                                         <<": "<<itemstring<<std::endl;
861                         return ItemStack();
862                 }
863         }
864         else if(lua_istable(L, index))
865         {
866                 // Convert from table
867                 std::string name = getstringfield_default(L, index, "name", "");
868                 int count = getintfield_default(L, index, "count", 1);
869                 int wear = getintfield_default(L, index, "wear", 0);
870
871                 ItemStack istack(name, count, wear, idef);
872
873                 // BACKWARDS COMPATIBLITY
874                 std::string value = getstringfield_default(L, index, "metadata", "");
875                 istack.metadata.setString("", value);
876
877                 // Get meta
878                 lua_getfield(L, index, "meta");
879                 int fieldstable = lua_gettop(L);
880                 if (lua_istable(L, fieldstable)) {
881                         lua_pushnil(L);
882                         while (lua_next(L, fieldstable) != 0) {
883                                 // key at index -2 and value at index -1
884                                 std::string key = lua_tostring(L, -2);
885                                 size_t value_len;
886                                 const char *value_cs = lua_tolstring(L, -1, &value_len);
887                                 std::string value(value_cs, value_len);
888                                 istack.metadata.setString(key, value);
889                                 lua_pop(L, 1); // removes value, keeps key for next iteration
890                         }
891                 }
892
893                 return istack;
894         } else {
895                 throw LuaError("Expecting itemstack, itemstring, table or nil");
896         }
897 }
898
899 /******************************************************************************/
900 void push_tool_capabilities(lua_State *L,
901                 const ToolCapabilities &toolcap)
902 {
903         lua_newtable(L);
904         setfloatfield(L, -1, "full_punch_interval", toolcap.full_punch_interval);
905                 setintfield(L, -1, "max_drop_level", toolcap.max_drop_level);
906                 // Create groupcaps table
907                 lua_newtable(L);
908                 // For each groupcap
909                 for (ToolGCMap::const_iterator i = toolcap.groupcaps.begin();
910                         i != toolcap.groupcaps.end(); ++i) {
911                         // Create groupcap table
912                         lua_newtable(L);
913                         const std::string &name = i->first;
914                         const ToolGroupCap &groupcap = i->second;
915                         // Create subtable "times"
916                         lua_newtable(L);
917                         for (UNORDERED_MAP<int, float>::const_iterator
918                                         i = groupcap.times.begin(); i != groupcap.times.end(); ++i) {
919                                 lua_pushinteger(L, i->first);
920                                 lua_pushnumber(L, i->second);
921                                 lua_settable(L, -3);
922                         }
923                         // Set subtable "times"
924                         lua_setfield(L, -2, "times");
925                         // Set simple parameters
926                         setintfield(L, -1, "maxlevel", groupcap.maxlevel);
927                         setintfield(L, -1, "uses", groupcap.uses);
928                         // Insert groupcap table into groupcaps table
929                         lua_setfield(L, -2, name.c_str());
930                 }
931                 // Set groupcaps table
932                 lua_setfield(L, -2, "groupcaps");
933                 //Create damage_groups table
934                 lua_newtable(L);
935                 // For each damage group
936                 for (DamageGroup::const_iterator i = toolcap.damageGroups.begin();
937                         i != toolcap.damageGroups.end(); ++i) {
938                         // Create damage group table
939                         lua_pushinteger(L, i->second);
940                         lua_setfield(L, -2, i->first.c_str());
941                 }
942                 lua_setfield(L, -2, "damage_groups");
943 }
944
945 /******************************************************************************/
946 void push_inventory_list(lua_State *L, Inventory *inv, const char *name)
947 {
948         InventoryList *invlist = inv->getList(name);
949         if(invlist == NULL){
950                 lua_pushnil(L);
951                 return;
952         }
953         std::vector<ItemStack> items;
954         for(u32 i=0; i<invlist->getSize(); i++)
955                 items.push_back(invlist->getItem(i));
956         push_items(L, items);
957 }
958
959 /******************************************************************************/
960 void read_inventory_list(lua_State *L, int tableindex,
961                 Inventory *inv, const char *name, Server* srv, int forcesize)
962 {
963         if(tableindex < 0)
964                 tableindex = lua_gettop(L) + 1 + tableindex;
965         // If nil, delete list
966         if(lua_isnil(L, tableindex)){
967                 inv->deleteList(name);
968                 return;
969         }
970         // Otherwise set list
971         std::vector<ItemStack> items = read_items(L, tableindex,srv);
972         int listsize = (forcesize != -1) ? forcesize : items.size();
973         InventoryList *invlist = inv->addList(name, listsize);
974         int index = 0;
975         for(std::vector<ItemStack>::const_iterator
976                         i = items.begin(); i != items.end(); ++i){
977                 if(forcesize != -1 && index == forcesize)
978                         break;
979                 invlist->changeItem(index, *i);
980                 index++;
981         }
982         while(forcesize != -1 && index < forcesize){
983                 invlist->deleteItem(index);
984                 index++;
985         }
986 }
987
988 /******************************************************************************/
989 struct TileAnimationParams read_animation_definition(lua_State *L, int index)
990 {
991         if(index < 0)
992                 index = lua_gettop(L) + 1 + index;
993
994         struct TileAnimationParams anim;
995         anim.type = TAT_NONE;
996         if (!lua_istable(L, index))
997                 return anim;
998
999         anim.type = (TileAnimationType)
1000                 getenumfield(L, index, "type", es_TileAnimationType,
1001                 TAT_NONE);
1002         if (anim.type == TAT_VERTICAL_FRAMES) {
1003                 // {type="vertical_frames", aspect_w=16, aspect_h=16, length=2.0}
1004                 anim.vertical_frames.aspect_w =
1005                         getintfield_default(L, index, "aspect_w", 16);
1006                 anim.vertical_frames.aspect_h =
1007                         getintfield_default(L, index, "aspect_h", 16);
1008                 anim.vertical_frames.length =
1009                         getfloatfield_default(L, index, "length", 1.0);
1010         } else if (anim.type == TAT_SHEET_2D) {
1011                 // {type="sheet_2d", frames_w=5, frames_h=3, frame_length=0.5}
1012                 getintfield(L, index, "frames_w",
1013                         anim.sheet_2d.frames_w);
1014                 getintfield(L, index, "frames_h",
1015                         anim.sheet_2d.frames_h);
1016                 getfloatfield(L, index, "frame_length",
1017                         anim.sheet_2d.frame_length);
1018         }
1019
1020         return anim;
1021 }
1022
1023 /******************************************************************************/
1024 ToolCapabilities read_tool_capabilities(
1025                 lua_State *L, int table)
1026 {
1027         ToolCapabilities toolcap;
1028         getfloatfield(L, table, "full_punch_interval", toolcap.full_punch_interval);
1029         getintfield(L, table, "max_drop_level", toolcap.max_drop_level);
1030         lua_getfield(L, table, "groupcaps");
1031         if(lua_istable(L, -1)){
1032                 int table_groupcaps = lua_gettop(L);
1033                 lua_pushnil(L);
1034                 while(lua_next(L, table_groupcaps) != 0){
1035                         // key at index -2 and value at index -1
1036                         std::string groupname = luaL_checkstring(L, -2);
1037                         if(lua_istable(L, -1)){
1038                                 int table_groupcap = lua_gettop(L);
1039                                 // This will be created
1040                                 ToolGroupCap groupcap;
1041                                 // Read simple parameters
1042                                 getintfield(L, table_groupcap, "maxlevel", groupcap.maxlevel);
1043                                 getintfield(L, table_groupcap, "uses", groupcap.uses);
1044                                 // DEPRECATED: maxwear
1045                                 float maxwear = 0;
1046                                 if (getfloatfield(L, table_groupcap, "maxwear", maxwear)){
1047                                         if (maxwear != 0)
1048                                                 groupcap.uses = 1.0/maxwear;
1049                                         else
1050                                                 groupcap.uses = 0;
1051                                         warningstream << "Field \"maxwear\" is deprecated; "
1052                                                         << "replace with uses=1/maxwear" << std::endl;
1053                                         infostream << script_get_backtrace(L) << std::endl;
1054                                 }
1055                                 // Read "times" table
1056                                 lua_getfield(L, table_groupcap, "times");
1057                                 if(lua_istable(L, -1)){
1058                                         int table_times = lua_gettop(L);
1059                                         lua_pushnil(L);
1060                                         while(lua_next(L, table_times) != 0){
1061                                                 // key at index -2 and value at index -1
1062                                                 int rating = luaL_checkinteger(L, -2);
1063                                                 float time = luaL_checknumber(L, -1);
1064                                                 groupcap.times[rating] = time;
1065                                                 // removes value, keeps key for next iteration
1066                                                 lua_pop(L, 1);
1067                                         }
1068                                 }
1069                                 lua_pop(L, 1);
1070                                 // Insert groupcap into toolcap
1071                                 toolcap.groupcaps[groupname] = groupcap;
1072                         }
1073                         // removes value, keeps key for next iteration
1074                         lua_pop(L, 1);
1075                 }
1076         }
1077         lua_pop(L, 1);
1078
1079         lua_getfield(L, table, "damage_groups");
1080         if(lua_istable(L, -1)){
1081                 int table_damage_groups = lua_gettop(L);
1082                 lua_pushnil(L);
1083                 while(lua_next(L, table_damage_groups) != 0){
1084                         // key at index -2 and value at index -1
1085                         std::string groupname = luaL_checkstring(L, -2);
1086                         u16 value = luaL_checkinteger(L, -1);
1087                         toolcap.damageGroups[groupname] = value;
1088                         // removes value, keeps key for next iteration
1089                         lua_pop(L, 1);
1090                 }
1091         }
1092         lua_pop(L, 1);
1093         return toolcap;
1094 }
1095
1096 /******************************************************************************/
1097 void push_dig_params(lua_State *L,const DigParams &params)
1098 {
1099         lua_newtable(L);
1100         setboolfield(L, -1, "diggable", params.diggable);
1101         setfloatfield(L, -1, "time", params.time);
1102         setintfield(L, -1, "wear", params.wear);
1103 }
1104
1105 /******************************************************************************/
1106 void push_hit_params(lua_State *L,const HitParams &params)
1107 {
1108         lua_newtable(L);
1109         setintfield(L, -1, "hp", params.hp);
1110         setintfield(L, -1, "wear", params.wear);
1111 }
1112
1113 /******************************************************************************/
1114
1115 bool getflagsfield(lua_State *L, int table, const char *fieldname,
1116         FlagDesc *flagdesc, u32 *flags, u32 *flagmask)
1117 {
1118         lua_getfield(L, table, fieldname);
1119
1120         bool success = read_flags(L, -1, flagdesc, flags, flagmask);
1121
1122         lua_pop(L, 1);
1123
1124         return success;
1125 }
1126
1127 bool read_flags(lua_State *L, int index, FlagDesc *flagdesc,
1128         u32 *flags, u32 *flagmask)
1129 {
1130         if (lua_isstring(L, index)) {
1131                 std::string flagstr = lua_tostring(L, index);
1132                 *flags = readFlagString(flagstr, flagdesc, flagmask);
1133         } else if (lua_istable(L, index)) {
1134                 *flags = read_flags_table(L, index, flagdesc, flagmask);
1135         } else {
1136                 return false;
1137         }
1138
1139         return true;
1140 }
1141
1142 u32 read_flags_table(lua_State *L, int table, FlagDesc *flagdesc, u32 *flagmask)
1143 {
1144         u32 flags = 0, mask = 0;
1145         char fnamebuf[64] = "no";
1146
1147         for (int i = 0; flagdesc[i].name; i++) {
1148                 bool result;
1149
1150                 if (getboolfield(L, table, flagdesc[i].name, result)) {
1151                         mask |= flagdesc[i].flag;
1152                         if (result)
1153                                 flags |= flagdesc[i].flag;
1154                 }
1155
1156                 strlcpy(fnamebuf + 2, flagdesc[i].name, sizeof(fnamebuf) - 2);
1157                 if (getboolfield(L, table, fnamebuf, result))
1158                         mask |= flagdesc[i].flag;
1159         }
1160
1161         if (flagmask)
1162                 *flagmask = mask;
1163
1164         return flags;
1165 }
1166
1167 void push_flags_string(lua_State *L, FlagDesc *flagdesc, u32 flags, u32 flagmask)
1168 {
1169         std::string flagstring = writeFlagString(flags, flagdesc, flagmask);
1170         lua_pushlstring(L, flagstring.c_str(), flagstring.size());
1171 }
1172
1173 /******************************************************************************/
1174 /* Lua Stored data!                                                           */
1175 /******************************************************************************/
1176
1177 /******************************************************************************/
1178 void read_groups(lua_State *L, int index, ItemGroupList &result)
1179 {
1180         if (!lua_istable(L,index))
1181                 return;
1182         result.clear();
1183         lua_pushnil(L);
1184         if(index < 0)
1185                 index -= 1;
1186         while(lua_next(L, index) != 0){
1187                 // key at index -2 and value at index -1
1188                 std::string name = luaL_checkstring(L, -2);
1189                 int rating = luaL_checkinteger(L, -1);
1190                 result[name] = rating;
1191                 // removes value, keeps key for next iteration
1192                 lua_pop(L, 1);
1193         }
1194 }
1195
1196 /******************************************************************************/
1197 void push_groups(lua_State *L, const ItemGroupList &groups)
1198 {
1199         lua_newtable(L);
1200         for (ItemGroupList::const_iterator it = groups.begin(); it != groups.end(); ++it) {
1201                 lua_pushnumber(L, it->second);
1202                 lua_setfield(L, -2, it->first.c_str());
1203         }
1204 }
1205
1206 /******************************************************************************/
1207 void push_items(lua_State *L, const std::vector<ItemStack> &items)
1208 {
1209         lua_createtable(L, items.size(), 0);
1210         for (u32 i = 0; i != items.size(); i++) {
1211                 LuaItemStack::create(L, items[i]);
1212                 lua_rawseti(L, -2, i + 1);
1213         }
1214 }
1215
1216 /******************************************************************************/
1217 std::vector<ItemStack> read_items(lua_State *L, int index, Server *srv)
1218 {
1219         if(index < 0)
1220                 index = lua_gettop(L) + 1 + index;
1221
1222         std::vector<ItemStack> items;
1223         luaL_checktype(L, index, LUA_TTABLE);
1224         lua_pushnil(L);
1225         while (lua_next(L, index)) {
1226                 s32 key = luaL_checkinteger(L, -2);
1227                 if (key < 1) {
1228                         throw LuaError("Invalid inventory list index");
1229                 }
1230                 if (items.size() < (u32) key) {
1231                         items.resize(key);
1232                 }
1233                 items[key - 1] = read_item(L, -1, srv->idef());
1234                 lua_pop(L, 1);
1235         }
1236         return items;
1237 }
1238
1239 /******************************************************************************/
1240 void luaentity_get(lua_State *L, u16 id)
1241 {
1242         // Get luaentities[i]
1243         lua_getglobal(L, "core");
1244         lua_getfield(L, -1, "luaentities");
1245         luaL_checktype(L, -1, LUA_TTABLE);
1246         lua_pushnumber(L, id);
1247         lua_gettable(L, -2);
1248         lua_remove(L, -2); // Remove luaentities
1249         lua_remove(L, -2); // Remove core
1250 }
1251
1252 /******************************************************************************/
1253 bool read_noiseparams(lua_State *L, int index, NoiseParams *np)
1254 {
1255         if (index < 0)
1256                 index = lua_gettop(L) + 1 + index;
1257
1258         if (!lua_istable(L, index))
1259                 return false;
1260
1261         getfloatfield(L, index, "offset",      np->offset);
1262         getfloatfield(L, index, "scale",       np->scale);
1263         getfloatfield(L, index, "persist",     np->persist);
1264         getfloatfield(L, index, "persistence", np->persist);
1265         getfloatfield(L, index, "lacunarity",  np->lacunarity);
1266         getintfield(L,   index, "seed",        np->seed);
1267         getintfield(L,   index, "octaves",     np->octaves);
1268
1269         u32 flags    = 0;
1270         u32 flagmask = 0;
1271         np->flags = getflagsfield(L, index, "flags", flagdesc_noiseparams,
1272                 &flags, &flagmask) ? flags : NOISE_FLAG_DEFAULTS;
1273
1274         lua_getfield(L, index, "spread");
1275         np->spread  = read_v3f(L, -1);
1276         lua_pop(L, 1);
1277
1278         return true;
1279 }
1280
1281 void push_noiseparams(lua_State *L, NoiseParams *np)
1282 {
1283         lua_newtable(L);
1284         lua_pushnumber(L, np->offset);
1285         lua_setfield(L, -2, "offset");
1286         lua_pushnumber(L, np->scale);
1287         lua_setfield(L, -2, "scale");
1288         lua_pushnumber(L, np->persist);
1289         lua_setfield(L, -2, "persistence");
1290         lua_pushnumber(L, np->lacunarity);
1291         lua_setfield(L, -2, "lacunarity");
1292         lua_pushnumber(L, np->seed);
1293         lua_setfield(L, -2, "seed");
1294         lua_pushnumber(L, np->octaves);
1295         lua_setfield(L, -2, "octaves");
1296
1297         push_flags_string(L, flagdesc_noiseparams, np->flags,
1298                 np->flags);
1299         lua_setfield(L, -2, "flags");
1300
1301         push_v3f(L, np->spread);
1302         lua_setfield(L, -2, "spread");
1303 }
1304
1305 /******************************************************************************/
1306 // Returns depth of json value tree
1307 static int push_json_value_getdepth(const Json::Value &value)
1308 {
1309         if (!value.isArray() && !value.isObject())
1310                 return 1;
1311
1312         int maxdepth = 0;
1313         for (Json::Value::const_iterator it = value.begin();
1314                         it != value.end(); ++it) {
1315                 int elemdepth = push_json_value_getdepth(*it);
1316                 if (elemdepth > maxdepth)
1317                         maxdepth = elemdepth;
1318         }
1319         return maxdepth + 1;
1320 }
1321 // Recursive function to convert JSON --> Lua table
1322 static bool push_json_value_helper(lua_State *L, const Json::Value &value,
1323                 int nullindex)
1324 {
1325         switch(value.type()) {
1326                 case Json::nullValue:
1327                 default:
1328                         lua_pushvalue(L, nullindex);
1329                         break;
1330                 case Json::intValue:
1331                         lua_pushinteger(L, value.asInt());
1332                         break;
1333                 case Json::uintValue:
1334                         lua_pushinteger(L, value.asUInt());
1335                         break;
1336                 case Json::realValue:
1337                         lua_pushnumber(L, value.asDouble());
1338                         break;
1339                 case Json::stringValue:
1340                         {
1341                                 const char *str = value.asCString();
1342                                 lua_pushstring(L, str ? str : "");
1343                         }
1344                         break;
1345                 case Json::booleanValue:
1346                         lua_pushboolean(L, value.asInt());
1347                         break;
1348                 case Json::arrayValue:
1349                         lua_newtable(L);
1350                         for (Json::Value::const_iterator it = value.begin();
1351                                         it != value.end(); ++it) {
1352                                 push_json_value_helper(L, *it, nullindex);
1353                                 lua_rawseti(L, -2, it.index() + 1);
1354                         }
1355                         break;
1356                 case Json::objectValue:
1357                         lua_newtable(L);
1358                         for (Json::Value::const_iterator it = value.begin();
1359                                         it != value.end(); ++it) {
1360 #ifndef JSONCPP_STRING
1361                                 const char *str = it.memberName();
1362                                 lua_pushstring(L, str ? str : "");
1363 #else
1364                                 std::string str = it.name();
1365                                 lua_pushstring(L, str.c_str());
1366 #endif
1367                                 push_json_value_helper(L, *it, nullindex);
1368                                 lua_rawset(L, -3);
1369                         }
1370                         break;
1371         }
1372         return true;
1373 }
1374 // converts JSON --> Lua table; returns false if lua stack limit exceeded
1375 // nullindex: Lua stack index of value to use in place of JSON null
1376 bool push_json_value(lua_State *L, const Json::Value &value, int nullindex)
1377 {
1378         if(nullindex < 0)
1379                 nullindex = lua_gettop(L) + 1 + nullindex;
1380
1381         int depth = push_json_value_getdepth(value);
1382
1383         // The maximum number of Lua stack slots used at each recursion level
1384         // of push_json_value_helper is 2, so make sure there a depth * 2 slots
1385         if (lua_checkstack(L, depth * 2))
1386                 return push_json_value_helper(L, value, nullindex);
1387         else
1388                 return false;
1389 }
1390
1391 // Converts Lua table --> JSON
1392 void read_json_value(lua_State *L, Json::Value &root, int index, u8 recursion)
1393 {
1394         if (recursion > 16) {
1395                 throw SerializationError("Maximum recursion depth exceeded");
1396         }
1397         int type = lua_type(L, index);
1398         if (type == LUA_TBOOLEAN) {
1399                 root = (bool) lua_toboolean(L, index);
1400         } else if (type == LUA_TNUMBER) {
1401                 root = lua_tonumber(L, index);
1402         } else if (type == LUA_TSTRING) {
1403                 size_t len;
1404                 const char *str = lua_tolstring(L, index, &len);
1405                 root = std::string(str, len);
1406         } else if (type == LUA_TTABLE) {
1407                 lua_pushnil(L);
1408                 while (lua_next(L, index)) {
1409                         // Key is at -2 and value is at -1
1410                         Json::Value value;
1411                         read_json_value(L, value, lua_gettop(L), recursion + 1);
1412
1413                         Json::ValueType roottype = root.type();
1414                         int keytype = lua_type(L, -1);
1415                         if (keytype == LUA_TNUMBER) {
1416                                 lua_Number key = lua_tonumber(L, -1);
1417                                 if (roottype != Json::nullValue && roottype != Json::arrayValue) {
1418                                         throw SerializationError("Can't mix array and object values in JSON");
1419                                 } else if (key < 1) {
1420                                         throw SerializationError("Can't use zero-based or negative indexes in JSON");
1421                                 } else if (floor(key) != key) {
1422                                         throw SerializationError("Can't use indexes with a fractional part in JSON");
1423                                 }
1424                                 root[(Json::ArrayIndex) key - 1] = value;
1425                         } else if (keytype == LUA_TSTRING) {
1426                                 if (roottype != Json::nullValue && roottype != Json::objectValue) {
1427                                         throw SerializationError("Can't mix array and object values in JSON");
1428                                 }
1429                                 root[lua_tostring(L, -1)] = value;
1430                         } else {
1431                                 throw SerializationError("Lua key to convert to JSON is not a string or number");
1432                         }
1433                 }
1434         } else if (type == LUA_TNIL) {
1435                 root = Json::nullValue;
1436         } else {
1437                 throw SerializationError("Can only store booleans, numbers, strings, objects, arrays, and null in JSON");
1438         }
1439         lua_pop(L, 1); // Pop value
1440 }
1441
1442 void push_pointed_thing(lua_State *L, const PointedThing &pointed)
1443 {
1444         lua_newtable(L);
1445         if (pointed.type == POINTEDTHING_NODE) {
1446                 lua_pushstring(L, "node");
1447                 lua_setfield(L, -2, "type");
1448                 push_v3s16(L, pointed.node_undersurface);
1449                 lua_setfield(L, -2, "under");
1450                 push_v3s16(L, pointed.node_abovesurface);
1451                 lua_setfield(L, -2, "above");
1452         } else if (pointed.type == POINTEDTHING_OBJECT) {
1453                 lua_pushstring(L, "object");
1454                 lua_setfield(L, -2, "type");
1455                 push_objectRef(L, pointed.object_id);
1456                 lua_setfield(L, -2, "ref");
1457         } else {
1458                 lua_pushstring(L, "nothing");
1459                 lua_setfield(L, -2, "type");
1460         }
1461 }
1462
1463 void push_objectRef(lua_State *L, const u16 id)
1464 {
1465         // Get core.object_refs[i]
1466         lua_getglobal(L, "core");
1467         lua_getfield(L, -1, "object_refs");
1468         luaL_checktype(L, -1, LUA_TTABLE);
1469         lua_pushnumber(L, id);
1470         lua_gettable(L, -2);
1471         lua_remove(L, -2); // object_refs
1472         lua_remove(L, -2); // core
1473 }