3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
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.
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.
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.
19 #include "common/c_content.h"
20 #include "common/c_converter.h"
21 #include "common/c_types.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"
32 #include "serverobject.h"
35 #include "json/json.h"
37 struct EnumString es_TileAnimationType[] =
40 {TAT_VERTICAL_FRAMES, "vertical_frames"},
44 /******************************************************************************/
45 ItemDefinition read_item_definition(lua_State* L,int index,
46 ItemDefinition default_def)
49 index = lua_gettop(L) + 1 + index;
51 // Read the item definition
52 ItemDefinition def = default_def;
54 def.type = (ItemType)getenumfield(L, index, "type",
55 es_ItemType, ITEM_NONE);
56 getstringfield(L, index, "name", def.name);
57 getstringfield(L, index, "description", def.description);
58 getstringfield(L, index, "inventory_image", def.inventory_image);
59 getstringfield(L, index, "wield_image", def.wield_image);
61 lua_getfield(L, index, "wield_scale");
62 if(lua_istable(L, -1)){
63 def.wield_scale = check_v3f(L, -1);
67 def.stack_max = getintfield_default(L, index, "stack_max", def.stack_max);
68 if(def.stack_max == 0)
71 lua_getfield(L, index, "on_use");
72 def.usable = lua_isfunction(L, -1);
75 getboolfield(L, index, "liquids_pointable", def.liquids_pointable);
77 warn_if_field_exists(L, index, "tool_digging_properties",
78 "deprecated: use tool_capabilities");
80 lua_getfield(L, index, "tool_capabilities");
81 if(lua_istable(L, -1)){
82 def.tool_capabilities = new ToolCapabilities(
83 read_tool_capabilities(L, -1));
86 // If name is "" (hand), ensure there are ToolCapabilities
87 // because it will be looked up there whenever any other item has
88 // no ToolCapabilities
89 if(def.name == "" && def.tool_capabilities == NULL){
90 def.tool_capabilities = new ToolCapabilities();
93 lua_getfield(L, index, "groups");
94 read_groups(L, -1, def.groups);
97 lua_getfield(L, index, "sounds");
98 if(lua_istable(L, -1)){
99 lua_getfield(L, -1, "place");
100 read_soundspec(L, -1, def.sound_place);
105 def.range = getfloatfield_default(L, index, "range", def.range);
107 // Client shall immediately place this node when player places the item.
108 // Server will update the precise end result a moment later.
109 // "" = no prediction
110 getstringfield(L, index, "node_placement_prediction",
111 def.node_placement_prediction);
116 /******************************************************************************/
117 void read_object_properties(lua_State *L, int index,
118 ObjectProperties *prop)
121 index = lua_gettop(L) + 1 + index;
122 if(!lua_istable(L, index))
125 prop->hp_max = getintfield_default(L, -1, "hp_max", 10);
127 getboolfield(L, -1, "physical", prop->physical);
128 getboolfield(L, -1, "collide_with_objects", prop->collideWithObjects);
130 getfloatfield(L, -1, "weight", prop->weight);
132 lua_getfield(L, -1, "collisionbox");
133 if(lua_istable(L, -1))
134 prop->collisionbox = read_aabb3f(L, -1, 1.0);
137 getstringfield(L, -1, "visual", prop->visual);
139 getstringfield(L, -1, "mesh", prop->mesh);
141 lua_getfield(L, -1, "visual_size");
142 if(lua_istable(L, -1))
143 prop->visual_size = read_v2f(L, -1);
146 lua_getfield(L, -1, "textures");
147 if(lua_istable(L, -1)){
148 prop->textures.clear();
149 int table = lua_gettop(L);
151 while(lua_next(L, table) != 0){
152 // key at index -2 and value at index -1
153 if(lua_isstring(L, -1))
154 prop->textures.push_back(lua_tostring(L, -1));
156 prop->textures.push_back("");
157 // removes value, keeps key for next iteration
163 lua_getfield(L, -1, "colors");
164 if(lua_istable(L, -1)){
165 prop->colors.clear();
166 int table = lua_gettop(L);
168 while(lua_next(L, table) != 0){
169 // key at index -2 and value at index -1
170 if(lua_isstring(L, -1))
171 prop->colors.push_back(readARGB8(L, -1));
173 prop->colors.push_back(video::SColor(255, 255, 255, 255));
174 // removes value, keeps key for next iteration
180 lua_getfield(L, -1, "spritediv");
181 if(lua_istable(L, -1))
182 prop->spritediv = read_v2s16(L, -1);
185 lua_getfield(L, -1, "initial_sprite_basepos");
186 if(lua_istable(L, -1))
187 prop->initial_sprite_basepos = read_v2s16(L, -1);
190 getboolfield(L, -1, "is_visible", prop->is_visible);
191 getboolfield(L, -1, "makes_footstep_sound", prop->makes_footstep_sound);
192 getfloatfield(L, -1, "automatic_rotate", prop->automatic_rotate);
193 getfloatfield(L, -1, "stepheight", prop->stepheight);
194 prop->stepheight*=BS;
195 lua_getfield(L, -1, "automatic_face_movement_dir");
196 if (lua_isnumber(L, -1)) {
197 prop->automatic_face_movement_dir = true;
198 prop->automatic_face_movement_dir_offset = luaL_checknumber(L, -1);
199 } else if (lua_isboolean(L, -1)) {
200 prop->automatic_face_movement_dir = lua_toboolean(L, -1);
201 prop->automatic_face_movement_dir_offset = 0.0;
206 /******************************************************************************/
207 TileDef read_tiledef(lua_State *L, int index)
210 index = lua_gettop(L) + 1 + index;
214 // key at index -2 and value at index
215 if(lua_isstring(L, index)){
216 // "default_lava.png"
217 tiledef.name = lua_tostring(L, index);
219 else if(lua_istable(L, index))
221 // {name="default_lava.png", animation={}}
223 getstringfield(L, index, "name", tiledef.name);
224 getstringfield(L, index, "image", tiledef.name); // MaterialSpec compat.
225 tiledef.backface_culling = getboolfield_default(
226 L, index, "backface_culling", true);
228 lua_getfield(L, index, "animation");
229 if(lua_istable(L, -1)){
230 // {type="vertical_frames", aspect_w=16, aspect_h=16, length=2.0}
231 tiledef.animation.type = (TileAnimationType)
232 getenumfield(L, -1, "type", es_TileAnimationType,
234 tiledef.animation.aspect_w =
235 getintfield_default(L, -1, "aspect_w", 16);
236 tiledef.animation.aspect_h =
237 getintfield_default(L, -1, "aspect_h", 16);
238 tiledef.animation.length =
239 getfloatfield_default(L, -1, "length", 1.0);
247 /******************************************************************************/
248 ContentFeatures read_content_features(lua_State *L, int index)
251 index = lua_gettop(L) + 1 + index;
255 /* Cache existence of some callbacks */
256 lua_getfield(L, index, "on_construct");
257 if(!lua_isnil(L, -1)) f.has_on_construct = true;
259 lua_getfield(L, index, "on_destruct");
260 if(!lua_isnil(L, -1)) f.has_on_destruct = true;
262 lua_getfield(L, index, "after_destruct");
263 if(!lua_isnil(L, -1)) f.has_after_destruct = true;
266 lua_getfield(L, index, "on_rightclick");
267 f.rightclickable = lua_isfunction(L, -1);
271 getstringfield(L, index, "name", f.name);
274 lua_getfield(L, index, "groups");
275 read_groups(L, -1, f.groups);
278 /* Visual definition */
280 f.drawtype = (NodeDrawType)getenumfield(L, index, "drawtype",
281 ScriptApiNode::es_DrawType,NDT_NORMAL);
282 getfloatfield(L, index, "visual_scale", f.visual_scale);
285 lua_getfield(L, index, "tiles");
286 // If nil, try the deprecated name "tile_images" instead
287 if(lua_isnil(L, -1)){
289 warn_if_field_exists(L, index, "tile_images",
290 "Deprecated; new name is \"tiles\".");
291 lua_getfield(L, index, "tile_images");
293 if(lua_istable(L, -1)){
294 int table = lua_gettop(L);
297 while(lua_next(L, table) != 0){
298 // Read tiledef from value
299 f.tiledef[i] = read_tiledef(L, -1);
300 // removes value, keeps key for next iteration
308 // Copy last value to all remaining textures
310 TileDef lasttile = f.tiledef[i-1];
312 f.tiledef[i] = lasttile;
319 // special_tiles = {}
320 lua_getfield(L, index, "special_tiles");
321 // If nil, try the deprecated name "special_materials" instead
322 if(lua_isnil(L, -1)){
324 warn_if_field_exists(L, index, "special_materials",
325 "Deprecated; new name is \"special_tiles\".");
326 lua_getfield(L, index, "special_materials");
328 if(lua_istable(L, -1)){
329 int table = lua_gettop(L);
332 while(lua_next(L, table) != 0){
333 // Read tiledef from value
334 f.tiledef_special[i] = read_tiledef(L, -1);
335 // removes value, keeps key for next iteration
338 if(i==CF_SPECIAL_COUNT){
346 f.alpha = getintfield_default(L, index, "alpha", 255);
348 bool usealpha = getboolfield_default(L, index,
349 "use_texture_alpha", false);
355 lua_getfield(L, index, "post_effect_color");
356 if(!lua_isnil(L, -1))
357 f.post_effect_color = readARGB8(L, -1);
360 f.param_type = (ContentParamType)getenumfield(L, index, "paramtype",
361 ScriptApiNode::es_ContentParamType, CPT_NONE);
362 f.param_type_2 = (ContentParamType2)getenumfield(L, index, "paramtype2",
363 ScriptApiNode::es_ContentParamType2, CPT2_NONE);
365 // Warn about some deprecated fields
366 warn_if_field_exists(L, index, "wall_mounted",
367 "deprecated: use paramtype2 = 'wallmounted'");
368 warn_if_field_exists(L, index, "light_propagates",
369 "deprecated: determined from paramtype");
370 warn_if_field_exists(L, index, "dug_item",
371 "deprecated: use 'drop' field");
372 warn_if_field_exists(L, index, "extra_dug_item",
373 "deprecated: use 'drop' field");
374 warn_if_field_exists(L, index, "extra_dug_item_rarity",
375 "deprecated: use 'drop' field");
376 warn_if_field_exists(L, index, "metadata_name",
377 "deprecated: use on_add and metadata callbacks");
379 // True for all ground-like things like stone and mud, false for eg. trees
380 getboolfield(L, index, "is_ground_content", f.is_ground_content);
381 f.light_propagates = (f.param_type == CPT_LIGHT);
382 getboolfield(L, index, "sunlight_propagates", f.sunlight_propagates);
383 // This is used for collision detection.
384 // Also for general solidness queries.
385 getboolfield(L, index, "walkable", f.walkable);
386 // Player can point to these
387 getboolfield(L, index, "pointable", f.pointable);
388 // Player can dig these
389 getboolfield(L, index, "diggable", f.diggable);
390 // Player can climb these
391 getboolfield(L, index, "climbable", f.climbable);
392 // Player can build on these
393 getboolfield(L, index, "buildable_to", f.buildable_to);
394 // Whether the node is non-liquid, source liquid or flowing liquid
395 f.liquid_type = (LiquidType)getenumfield(L, index, "liquidtype",
396 ScriptApiNode::es_LiquidType, LIQUID_NONE);
397 // If the content is liquid, this is the flowing version of the liquid.
398 getstringfield(L, index, "liquid_alternative_flowing",
399 f.liquid_alternative_flowing);
400 // If the content is liquid, this is the source version of the liquid.
401 getstringfield(L, index, "liquid_alternative_source",
402 f.liquid_alternative_source);
403 // Viscosity for fluid flow, ranging from 1 to 7, with
404 // 1 giving almost instantaneous propagation and 7 being
405 // the slowest possible
406 f.liquid_viscosity = getintfield_default(L, index,
407 "liquid_viscosity", f.liquid_viscosity);
408 f.liquid_range = getintfield_default(L, index,
409 "liquid_range", f.liquid_range);
410 f.leveled = getintfield_default(L, index, "leveled", f.leveled);
412 getboolfield(L, index, "liquid_renewable", f.liquid_renewable);
413 getstringfield(L, index, "freezemelt", f.freezemelt);
414 f.drowning = getintfield_default(L, index,
415 "drowning", f.drowning);
416 // Amount of light the node emits
417 f.light_source = getintfield_default(L, index,
418 "light_source", f.light_source);
419 f.damage_per_second = getintfield_default(L, index,
420 "damage_per_second", f.damage_per_second);
422 lua_getfield(L, index, "node_box");
423 if(lua_istable(L, -1))
424 f.node_box = read_nodebox(L, -1);
427 lua_getfield(L, index, "selection_box");
428 if(lua_istable(L, -1))
429 f.selection_box = read_nodebox(L, -1);
432 f.waving = getintfield_default(L, index,
435 // Set to true if paramtype used to be 'facedir_simple'
436 getboolfield(L, index, "legacy_facedir_simple", f.legacy_facedir_simple);
437 // Set to true if wall_mounted used to be set to true
438 getboolfield(L, index, "legacy_wallmounted", f.legacy_wallmounted);
441 lua_getfield(L, index, "sounds");
442 if(lua_istable(L, -1)){
443 lua_getfield(L, -1, "footstep");
444 read_soundspec(L, -1, f.sound_footstep);
446 lua_getfield(L, -1, "dig");
447 read_soundspec(L, -1, f.sound_dig);
449 lua_getfield(L, -1, "dug");
450 read_soundspec(L, -1, f.sound_dug);
458 /******************************************************************************/
459 void read_server_sound_params(lua_State *L, int index,
460 ServerSoundParams ¶ms)
463 index = lua_gettop(L) + 1 + index;
465 params = ServerSoundParams();
466 if(lua_istable(L, index)){
467 getfloatfield(L, index, "gain", params.gain);
468 getstringfield(L, index, "to_player", params.to_player);
469 lua_getfield(L, index, "pos");
470 if(!lua_isnil(L, -1)){
471 v3f p = read_v3f(L, -1)*BS;
473 params.type = ServerSoundParams::SSP_POSITIONAL;
476 lua_getfield(L, index, "object");
477 if(!lua_isnil(L, -1)){
478 ObjectRef *ref = ObjectRef::checkobject(L, -1);
479 ServerActiveObject *sao = ObjectRef::getobject(ref);
481 params.object = sao->getId();
482 params.type = ServerSoundParams::SSP_OBJECT;
486 params.max_hear_distance = BS*getfloatfield_default(L, index,
487 "max_hear_distance", params.max_hear_distance/BS);
488 getboolfield(L, index, "loop", params.loop);
492 /******************************************************************************/
493 void read_soundspec(lua_State *L, int index, SimpleSoundSpec &spec)
496 index = lua_gettop(L) + 1 + index;
497 if(lua_isnil(L, index)){
498 } else if(lua_istable(L, index)){
499 getstringfield(L, index, "name", spec.name);
500 getfloatfield(L, index, "gain", spec.gain);
501 } else if(lua_isstring(L, index)){
502 spec.name = lua_tostring(L, index);
506 /******************************************************************************/
507 NodeBox read_nodebox(lua_State *L, int index)
510 if(lua_istable(L, -1)){
511 nodebox.type = (NodeBoxType)getenumfield(L, index, "type",
512 ScriptApiNode::es_NodeBoxType, NODEBOX_REGULAR);
514 lua_getfield(L, index, "fixed");
515 if(lua_istable(L, -1))
516 nodebox.fixed = read_aabb3f_vector(L, -1, BS);
519 lua_getfield(L, index, "wall_top");
520 if(lua_istable(L, -1))
521 nodebox.wall_top = read_aabb3f(L, -1, BS);
524 lua_getfield(L, index, "wall_bottom");
525 if(lua_istable(L, -1))
526 nodebox.wall_bottom = read_aabb3f(L, -1, BS);
529 lua_getfield(L, index, "wall_side");
530 if(lua_istable(L, -1))
531 nodebox.wall_side = read_aabb3f(L, -1, BS);
537 /******************************************************************************/
538 MapNode readnode(lua_State *L, int index, INodeDefManager *ndef)
540 lua_getfield(L, index, "name");
541 const char *name = luaL_checkstring(L, -1);
544 lua_getfield(L, index, "param1");
548 param1 = lua_tonumber(L, -1);
551 lua_getfield(L, index, "param2");
555 param2 = lua_tonumber(L, -1);
557 return MapNode(ndef, name, param1, param2);
560 /******************************************************************************/
561 void pushnode(lua_State *L, const MapNode &n, INodeDefManager *ndef)
564 lua_pushstring(L, ndef->get(n).name.c_str());
565 lua_setfield(L, -2, "name");
566 lua_pushnumber(L, n.getParam1());
567 lua_setfield(L, -2, "param1");
568 lua_pushnumber(L, n.getParam2());
569 lua_setfield(L, -2, "param2");
572 /******************************************************************************/
573 void warn_if_field_exists(lua_State *L, int table,
574 const char *fieldname, const std::string &message)
576 lua_getfield(L, table, fieldname);
577 if(!lua_isnil(L, -1)){
578 //TODO find way to access backtrace fct from here
579 // infostream<<script_get_backtrace(L)<<std::endl;
580 infostream<<"WARNING: field \""<<fieldname<<"\": "
581 <<message<<std::endl;
586 /******************************************************************************/
587 int getenumfield(lua_State *L, int table,
588 const char *fieldname, const EnumString *spec, int default_)
590 int result = default_;
591 string_to_enum(spec, result,
592 getstringfield_default(L, table, fieldname, ""));
596 /******************************************************************************/
597 bool string_to_enum(const EnumString *spec, int &result,
598 const std::string &str)
600 const EnumString *esp = spec;
602 if(str == std::string(esp->str)){
611 /******************************************************************************/
612 ItemStack read_item(lua_State* L, int index,Server* srv)
615 index = lua_gettop(L) + 1 + index;
617 if(lua_isnil(L, index))
621 else if(lua_isuserdata(L, index))
623 // Convert from LuaItemStack
624 LuaItemStack *o = LuaItemStack::checkobject(L, index);
627 else if(lua_isstring(L, index))
629 // Convert from itemstring
630 std::string itemstring = lua_tostring(L, index);
631 IItemDefManager *idef = srv->idef();
635 item.deSerialize(itemstring, idef);
638 catch(SerializationError &e)
640 infostream<<"WARNING: unable to create item from itemstring"
641 <<": "<<itemstring<<std::endl;
645 else if(lua_istable(L, index))
647 // Convert from table
648 IItemDefManager *idef = srv->idef();
649 std::string name = getstringfield_default(L, index, "name", "");
650 int count = getintfield_default(L, index, "count", 1);
651 int wear = getintfield_default(L, index, "wear", 0);
652 std::string metadata = getstringfield_default(L, index, "metadata", "");
653 return ItemStack(name, count, wear, metadata, idef);
657 throw LuaError(NULL, "Expecting itemstack, itemstring, table or nil");
661 /******************************************************************************/
662 void push_tool_capabilities(lua_State *L,
663 const ToolCapabilities &toolcap)
666 setfloatfield(L, -1, "full_punch_interval", toolcap.full_punch_interval);
667 setintfield(L, -1, "max_drop_level", toolcap.max_drop_level);
668 // Create groupcaps table
671 for(std::map<std::string, ToolGroupCap>::const_iterator
672 i = toolcap.groupcaps.begin(); i != toolcap.groupcaps.end(); i++){
673 // Create groupcap table
675 const std::string &name = i->first;
676 const ToolGroupCap &groupcap = i->second;
677 // Create subtable "times"
679 for(std::map<int, float>::const_iterator
680 i = groupcap.times.begin(); i != groupcap.times.end(); i++){
681 int rating = i->first;
682 float time = i->second;
683 lua_pushinteger(L, rating);
684 lua_pushnumber(L, time);
687 // Set subtable "times"
688 lua_setfield(L, -2, "times");
689 // Set simple parameters
690 setintfield(L, -1, "maxlevel", groupcap.maxlevel);
691 setintfield(L, -1, "uses", groupcap.uses);
692 // Insert groupcap table into groupcaps table
693 lua_setfield(L, -2, name.c_str());
695 // Set groupcaps table
696 lua_setfield(L, -2, "groupcaps");
697 //Create damage_groups table
699 // For each damage group
700 for(std::map<std::string, s16>::const_iterator
701 i = toolcap.damageGroups.begin(); i != toolcap.damageGroups.end(); i++){
702 // Create damage group table
703 lua_pushinteger(L, i->second);
704 lua_setfield(L, -2, i->first.c_str());
706 lua_setfield(L, -2, "damage_groups");
709 /******************************************************************************/
710 void push_inventory_list(lua_State *L, Inventory *inv, const char *name)
712 InventoryList *invlist = inv->getList(name);
717 std::vector<ItemStack> items;
718 for(u32 i=0; i<invlist->getSize(); i++)
719 items.push_back(invlist->getItem(i));
720 push_items(L, items);
723 /******************************************************************************/
724 void read_inventory_list(lua_State *L, int tableindex,
725 Inventory *inv, const char *name, Server* srv, int forcesize)
728 tableindex = lua_gettop(L) + 1 + tableindex;
729 // If nil, delete list
730 if(lua_isnil(L, tableindex)){
731 inv->deleteList(name);
734 // Otherwise set list
735 std::vector<ItemStack> items = read_items(L, tableindex,srv);
736 int listsize = (forcesize != -1) ? forcesize : items.size();
737 InventoryList *invlist = inv->addList(name, listsize);
739 for(std::vector<ItemStack>::const_iterator
740 i = items.begin(); i != items.end(); i++){
741 if(forcesize != -1 && index == forcesize)
743 invlist->changeItem(index, *i);
746 while(forcesize != -1 && index < forcesize){
747 invlist->deleteItem(index);
752 /******************************************************************************/
753 ToolCapabilities read_tool_capabilities(
754 lua_State *L, int table)
756 ToolCapabilities toolcap;
757 getfloatfield(L, table, "full_punch_interval", toolcap.full_punch_interval);
758 getintfield(L, table, "max_drop_level", toolcap.max_drop_level);
759 lua_getfield(L, table, "groupcaps");
760 if(lua_istable(L, -1)){
761 int table_groupcaps = lua_gettop(L);
763 while(lua_next(L, table_groupcaps) != 0){
764 // key at index -2 and value at index -1
765 std::string groupname = luaL_checkstring(L, -2);
766 if(lua_istable(L, -1)){
767 int table_groupcap = lua_gettop(L);
768 // This will be created
769 ToolGroupCap groupcap;
770 // Read simple parameters
771 getintfield(L, table_groupcap, "maxlevel", groupcap.maxlevel);
772 getintfield(L, table_groupcap, "uses", groupcap.uses);
773 // DEPRECATED: maxwear
775 if(getfloatfield(L, table_groupcap, "maxwear", maxwear)){
777 groupcap.uses = 1.0/maxwear;
780 infostream<<script_get_backtrace(L)<<std::endl;
781 infostream<<"WARNING: field \"maxwear\" is deprecated; "
782 <<"should replace with uses=1/maxwear"<<std::endl;
784 // Read "times" table
785 lua_getfield(L, table_groupcap, "times");
786 if(lua_istable(L, -1)){
787 int table_times = lua_gettop(L);
789 while(lua_next(L, table_times) != 0){
790 // key at index -2 and value at index -1
791 int rating = luaL_checkinteger(L, -2);
792 float time = luaL_checknumber(L, -1);
793 groupcap.times[rating] = time;
794 // removes value, keeps key for next iteration
799 // Insert groupcap into toolcap
800 toolcap.groupcaps[groupname] = groupcap;
802 // removes value, keeps key for next iteration
808 lua_getfield(L, table, "damage_groups");
809 if(lua_istable(L, -1)){
810 int table_damage_groups = lua_gettop(L);
812 while(lua_next(L, table_damage_groups) != 0){
813 // key at index -2 and value at index -1
814 std::string groupname = luaL_checkstring(L, -2);
815 u16 value = luaL_checkinteger(L, -1);
816 toolcap.damageGroups[groupname] = value;
817 // removes value, keeps key for next iteration
825 /******************************************************************************/
826 void push_dig_params(lua_State *L,const DigParams ¶ms)
829 setboolfield(L, -1, "diggable", params.diggable);
830 setfloatfield(L, -1, "time", params.time);
831 setintfield(L, -1, "wear", params.wear);
834 /******************************************************************************/
835 void push_hit_params(lua_State *L,const HitParams ¶ms)
838 setintfield(L, -1, "hp", params.hp);
839 setintfield(L, -1, "wear", params.wear);
842 /******************************************************************************/
843 u32 getflagsfield(lua_State *L, int table, const char *fieldname,
844 FlagDesc *flagdesc, u32 *flagmask)
848 lua_getfield(L, table, fieldname);
850 if (lua_isstring(L, -1)) {
851 std::string flagstr = lua_tostring(L, -1);
852 flags = readFlagString(flagstr, flagdesc, flagmask);
853 } else if (lua_istable(L, -1)) {
854 flags = read_flags_table(L, -1, flagdesc, flagmask);
862 u32 read_flags_table(lua_State *L, int table, FlagDesc *flagdesc, u32 *flagmask)
864 u32 flags = 0, mask = 0;
865 char fnamebuf[64] = "no";
867 for (int i = 0; flagdesc[i].name; i++) {
870 if (getboolfield(L, table, flagdesc[i].name, result)) {
871 mask |= flagdesc[i].flag;
873 flags |= flagdesc[i].flag;
876 strlcpy(fnamebuf + 2, flagdesc[i].name, sizeof(fnamebuf) - 2);
877 if (getboolfield(L, table, fnamebuf, result))
878 mask |= flagdesc[i].flag;
887 /******************************************************************************/
888 /* Lua Stored data! */
889 /******************************************************************************/
891 /******************************************************************************/
892 void read_groups(lua_State *L, int index,
893 std::map<std::string, int> &result)
895 if (!lua_istable(L,index))
901 while(lua_next(L, index) != 0){
902 // key at index -2 and value at index -1
903 std::string name = luaL_checkstring(L, -2);
904 int rating = luaL_checkinteger(L, -1);
905 result[name] = rating;
906 // removes value, keeps key for next iteration
911 /******************************************************************************/
912 void push_items(lua_State *L, const std::vector<ItemStack> &items)
914 // Create and fill table
915 lua_createtable(L, items.size(), 0);
916 std::vector<ItemStack>::const_iterator iter = items.begin();
917 for (u32 i = 0; iter != items.end(); iter++) {
918 LuaItemStack::create(L, *iter);
919 lua_rawseti(L, -2, ++i);
923 /******************************************************************************/
924 std::vector<ItemStack> read_items(lua_State *L, int index, Server *srv)
927 index = lua_gettop(L) + 1 + index;
929 std::vector<ItemStack> items;
930 luaL_checktype(L, index, LUA_TTABLE);
932 while (lua_next(L, index)) {
933 s32 key = luaL_checkinteger(L, -2);
935 throw LuaError(NULL, "Invalid inventory list index");
937 if (items.size() < (u32) key) {
940 items[key - 1] = read_item(L, -1, srv);
946 /******************************************************************************/
947 void luaentity_get(lua_State *L, u16 id)
949 // Get minetest.luaentities[i]
950 lua_getglobal(L, "minetest");
951 lua_getfield(L, -1, "luaentities");
952 luaL_checktype(L, -1, LUA_TTABLE);
953 lua_pushnumber(L, id);
955 lua_remove(L, -2); // luaentities
956 lua_remove(L, -2); // minetest
959 /******************************************************************************/
960 NoiseParams *read_noiseparams(lua_State *L, int index)
963 index = lua_gettop(L) + 1 + index;
965 if (!lua_istable(L, index))
968 NoiseParams *np = new NoiseParams;
970 np->offset = getfloatfield_default(L, index, "offset", 0.0);
971 np->scale = getfloatfield_default(L, index, "scale", 0.0);
972 lua_getfield(L, index, "spread");
973 np->spread = read_v3f(L, -1);
975 np->seed = getintfield_default(L, index, "seed", 0);
976 np->octaves = getintfield_default(L, index, "octaves", 0);
977 np->persist = getfloatfield_default(L, index, "persist", 0.0);
982 /******************************************************************************/
983 bool read_schematic(lua_State *L, int index, DecoSchematic *dschem, Server *server) {
985 index = lua_gettop(L) + 1 + index;
987 INodeDefManager *ndef = server->getNodeDefManager();
989 if (lua_istable(L, index)) {
990 lua_getfield(L, index, "size");
991 v3s16 size = read_v3s16(L, -1);
994 int numnodes = size.X * size.Y * size.Z;
995 MapNode *schemdata = new MapNode[numnodes];
998 // Get schematic data
999 lua_getfield(L, index, "data");
1000 luaL_checktype(L, -1, LUA_TTABLE);
1003 while (lua_next(L, -2)) {
1005 // same as readnode, except param1 default is MTSCHEM_PROB_CONST
1006 lua_getfield(L, -1, "name");
1007 const char *name = luaL_checkstring(L, -1);
1011 lua_getfield(L, -1, "param1");
1012 param1 = !lua_isnil(L, -1) ? lua_tonumber(L, -1) : MTSCHEM_PROB_ALWAYS;
1016 lua_getfield(L, -1, "param2");
1017 param2 = !lua_isnil(L, -1) ? lua_tonumber(L, -1) : 0;
1020 schemdata[i] = MapNode(ndef, name, param1, param2);
1027 if (i != numnodes) {
1028 errorstream << "read_schematic: incorrect number of "
1029 "nodes provided in raw schematic data (got " << i <<
1030 ", expected " << numnodes << ")." << std::endl;
1034 u8 *sliceprobs = new u8[size.Y];
1035 for (i = 0; i != size.Y; i++)
1036 sliceprobs[i] = MTSCHEM_PROB_ALWAYS;
1038 // Get Y-slice probability values (if present)
1039 lua_getfield(L, index, "yslice_prob");
1040 if (lua_istable(L, -1)) {
1042 while (lua_next(L, -2)) {
1043 if (getintfield(L, -1, "ypos", i) && i >= 0 && i < size.Y) {
1044 sliceprobs[i] = getintfield_default(L, -1,
1045 "prob", MTSCHEM_PROB_ALWAYS);
1051 dschem->size = size;
1052 dschem->schematic = schemdata;
1053 dschem->slice_probs = sliceprobs;
1055 } else if (lua_isstring(L, index)) {
1056 dschem->filename = std::string(lua_tostring(L, index));
1058 errorstream << "read_schematic: missing schematic "
1059 "filename or raw schematic data" << std::endl;
1066 /******************************************************************************/
1067 // Returns depth of json value tree
1068 static int push_json_value_getdepth(const Json::Value &value)
1070 if (!value.isArray() && !value.isObject())
1074 for (Json::Value::const_iterator it = value.begin();
1075 it != value.end(); ++it) {
1076 int elemdepth = push_json_value_getdepth(*it);
1077 if (elemdepth > maxdepth)
1078 maxdepth = elemdepth;
1080 return maxdepth + 1;
1082 // Recursive function to convert JSON --> Lua table
1083 static bool push_json_value_helper(lua_State *L, const Json::Value &value,
1086 switch(value.type()) {
1087 case Json::nullValue:
1089 lua_pushvalue(L, nullindex);
1091 case Json::intValue:
1092 lua_pushinteger(L, value.asInt());
1094 case Json::uintValue:
1095 lua_pushinteger(L, value.asUInt());
1097 case Json::realValue:
1098 lua_pushnumber(L, value.asDouble());
1100 case Json::stringValue:
1102 const char *str = value.asCString();
1103 lua_pushstring(L, str ? str : "");
1106 case Json::booleanValue:
1107 lua_pushboolean(L, value.asInt());
1109 case Json::arrayValue:
1111 for (Json::Value::const_iterator it = value.begin();
1112 it != value.end(); ++it) {
1113 push_json_value_helper(L, *it, nullindex);
1114 lua_rawseti(L, -2, it.index() + 1);
1117 case Json::objectValue:
1119 for (Json::Value::const_iterator it = value.begin();
1120 it != value.end(); ++it) {
1121 const char *str = it.memberName();
1122 lua_pushstring(L, str ? str : "");
1123 push_json_value_helper(L, *it, nullindex);
1130 // converts JSON --> Lua table; returns false if lua stack limit exceeded
1131 // nullindex: Lua stack index of value to use in place of JSON null
1132 bool push_json_value(lua_State *L, const Json::Value &value, int nullindex)
1135 nullindex = lua_gettop(L) + 1 + nullindex;
1137 int depth = push_json_value_getdepth(value);
1139 // The maximum number of Lua stack slots used at each recursion level
1140 // of push_json_value_helper is 2, so make sure there a depth * 2 slots
1141 if (lua_checkstack(L, depth * 2))
1142 return push_json_value_helper(L, value, nullindex);
1147 // Converts Lua table --> JSON
1148 void read_json_value(lua_State *L, Json::Value &root, int index, u8 recursion)
1150 if (recursion > 16) {
1151 throw SerializationError("Maximum recursion depth exceeded");
1153 int type = lua_type(L, index);
1154 if (type == LUA_TBOOLEAN) {
1155 root = (bool) lua_toboolean(L, index);
1156 } else if (type == LUA_TNUMBER) {
1157 root = lua_tonumber(L, index);
1158 } else if (type == LUA_TSTRING) {
1160 const char *str = lua_tolstring(L, index, &len);
1161 root = std::string(str, len);
1162 } else if (type == LUA_TTABLE) {
1164 while (lua_next(L, index)) {
1165 // Key is at -2 and value is at -1
1167 read_json_value(L, value, lua_gettop(L), recursion + 1);
1169 Json::ValueType roottype = root.type();
1170 int keytype = lua_type(L, -1);
1171 if (keytype == LUA_TNUMBER) {
1172 lua_Number key = lua_tonumber(L, -1);
1173 if (roottype != Json::nullValue && roottype != Json::arrayValue) {
1174 throw SerializationError("Can't mix array and object values in JSON");
1175 } else if (key < 1) {
1176 throw SerializationError("Can't use zero-based or negative indexes in JSON");
1177 } else if (floor(key) != key) {
1178 throw SerializationError("Can't use indexes with a fractional part in JSON");
1180 root[(Json::ArrayIndex) key - 1] = value;
1181 } else if (keytype == LUA_TSTRING) {
1182 if (roottype != Json::nullValue && roottype != Json::objectValue) {
1183 throw SerializationError("Can't mix array and object values in JSON");
1185 root[lua_tostring(L, -1)] = value;
1187 throw SerializationError("Lua key to convert to JSON is not a string or number");
1190 } else if (type == LUA_TNIL) {
1191 root = Json::nullValue;
1193 throw SerializationError("Can only store booleans, numbers, strings, objects, arrays, and null in JSON");
1195 lua_pop(L, 1); // Pop value