LCOV - code coverage report
Current view: top level - src/script/common - c_content.cpp (source / functions) Hit Total Coverage
Test: report Lines: 8 763 1.0 %
Date: 2015-07-11 18:23:49 Functions: 3 37 8.1 %

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

Generated by: LCOV version 1.11