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