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"
34 #include "json/json.h"
36 struct EnumString es_TileAnimationType[] =
39 {TAT_VERTICAL_FRAMES, "vertical_frames"},
43 /******************************************************************************/
44 ItemDefinition read_item_definition(lua_State* L,int index,
45 ItemDefinition default_def)
48 index = lua_gettop(L) + 1 + index;
50 // Read the item definition
51 ItemDefinition def = default_def;
53 def.type = (ItemType)getenumfield(L, index, "type",
54 es_ItemType, ITEM_NONE);
55 getstringfield(L, index, "name", def.name);
56 getstringfield(L, index, "description", def.description);
57 getstringfield(L, index, "inventory_image", def.inventory_image);
58 getstringfield(L, index, "wield_image", def.wield_image);
60 lua_getfield(L, index, "wield_scale");
61 if(lua_istable(L, -1)){
62 def.wield_scale = check_v3f(L, -1);
66 def.stack_max = getintfield_default(L, index, "stack_max", def.stack_max);
67 if(def.stack_max == 0)
70 lua_getfield(L, index, "on_use");
71 def.usable = lua_isfunction(L, -1);
74 getboolfield(L, index, "liquids_pointable", def.liquids_pointable);
76 warn_if_field_exists(L, index, "tool_digging_properties",
77 "deprecated: use tool_capabilities");
79 lua_getfield(L, index, "tool_capabilities");
80 if(lua_istable(L, -1)){
81 def.tool_capabilities = new ToolCapabilities(
82 read_tool_capabilities(L, -1));
85 // If name is "" (hand), ensure there are ToolCapabilities
86 // because it will be looked up there whenever any other item has
87 // no ToolCapabilities
88 if(def.name == "" && def.tool_capabilities == NULL){
89 def.tool_capabilities = new ToolCapabilities();
92 lua_getfield(L, index, "groups");
93 read_groups(L, -1, def.groups);
96 lua_getfield(L, index, "sounds");
97 if(lua_istable(L, -1)){
98 lua_getfield(L, -1, "place");
99 read_soundspec(L, -1, def.sound_place);
104 def.range = getfloatfield_default(L, index, "range", def.range);
106 // Client shall immediately place this node when player places the item.
107 // Server will update the precise end result a moment later.
108 // "" = no prediction
109 getstringfield(L, index, "node_placement_prediction",
110 def.node_placement_prediction);
115 /******************************************************************************/
116 void read_object_properties(lua_State *L, int index,
117 ObjectProperties *prop)
120 index = lua_gettop(L) + 1 + index;
121 if(!lua_istable(L, index))
124 prop->hp_max = getintfield_default(L, -1, "hp_max", 10);
126 getboolfield(L, -1, "physical", prop->physical);
127 getboolfield(L, -1, "collide_with_objects", prop->collideWithObjects);
129 getfloatfield(L, -1, "weight", prop->weight);
131 lua_getfield(L, -1, "collisionbox");
132 if(lua_istable(L, -1))
133 prop->collisionbox = read_aabb3f(L, -1, 1.0);
136 getstringfield(L, -1, "visual", prop->visual);
138 getstringfield(L, -1, "mesh", prop->mesh);
140 lua_getfield(L, -1, "visual_size");
141 if(lua_istable(L, -1))
142 prop->visual_size = read_v2f(L, -1);
145 lua_getfield(L, -1, "textures");
146 if(lua_istable(L, -1)){
147 prop->textures.clear();
148 int table = lua_gettop(L);
150 while(lua_next(L, table) != 0){
151 // key at index -2 and value at index -1
152 if(lua_isstring(L, -1))
153 prop->textures.push_back(lua_tostring(L, -1));
155 prop->textures.push_back("");
156 // removes value, keeps key for next iteration
162 lua_getfield(L, -1, "colors");
163 if(lua_istable(L, -1)){
164 prop->colors.clear();
165 int table = lua_gettop(L);
167 while(lua_next(L, table) != 0){
168 // key at index -2 and value at index -1
169 if(lua_isstring(L, -1))
170 prop->colors.push_back(readARGB8(L, -1));
172 prop->colors.push_back(video::SColor(255, 255, 255, 255));
173 // removes value, keeps key for next iteration
179 lua_getfield(L, -1, "spritediv");
180 if(lua_istable(L, -1))
181 prop->spritediv = read_v2s16(L, -1);
184 lua_getfield(L, -1, "initial_sprite_basepos");
185 if(lua_istable(L, -1))
186 prop->initial_sprite_basepos = read_v2s16(L, -1);
189 getboolfield(L, -1, "is_visible", prop->is_visible);
190 getboolfield(L, -1, "makes_footstep_sound", prop->makes_footstep_sound);
191 getfloatfield(L, -1, "automatic_rotate", prop->automatic_rotate);
192 getfloatfield(L, -1, "stepheight", prop->stepheight);
193 prop->stepheight*=BS;
194 lua_getfield(L, -1, "automatic_face_movement_dir");
195 if (lua_isnumber(L, -1)) {
196 prop->automatic_face_movement_dir = true;
197 prop->automatic_face_movement_dir_offset = luaL_checknumber(L, -1);
198 } else if (lua_isboolean(L, -1)) {
199 prop->automatic_face_movement_dir = lua_toboolean(L, -1);
200 prop->automatic_face_movement_dir_offset = 0.0;
205 /******************************************************************************/
206 TileDef read_tiledef(lua_State *L, int index)
209 index = lua_gettop(L) + 1 + index;
213 // key at index -2 and value at index
214 if(lua_isstring(L, index)){
215 // "default_lava.png"
216 tiledef.name = lua_tostring(L, index);
218 else if(lua_istable(L, index))
220 // {name="default_lava.png", animation={}}
222 getstringfield(L, index, "name", tiledef.name);
223 getstringfield(L, index, "image", tiledef.name); // MaterialSpec compat.
224 tiledef.backface_culling = getboolfield_default(
225 L, index, "backface_culling", true);
227 lua_getfield(L, index, "animation");
228 if(lua_istable(L, -1)){
229 // {type="vertical_frames", aspect_w=16, aspect_h=16, length=2.0}
230 tiledef.animation.type = (TileAnimationType)
231 getenumfield(L, -1, "type", es_TileAnimationType,
233 tiledef.animation.aspect_w =
234 getintfield_default(L, -1, "aspect_w", 16);
235 tiledef.animation.aspect_h =
236 getintfield_default(L, -1, "aspect_h", 16);
237 tiledef.animation.length =
238 getfloatfield_default(L, -1, "length", 1.0);
246 /******************************************************************************/
247 ContentFeatures read_content_features(lua_State *L, int index)
250 index = lua_gettop(L) + 1 + index;
254 /* Cache existence of some callbacks */
255 lua_getfield(L, index, "on_construct");
256 if(!lua_isnil(L, -1)) f.has_on_construct = true;
258 lua_getfield(L, index, "on_destruct");
259 if(!lua_isnil(L, -1)) f.has_on_destruct = true;
261 lua_getfield(L, index, "after_destruct");
262 if(!lua_isnil(L, -1)) f.has_after_destruct = true;
265 lua_getfield(L, index, "on_rightclick");
266 f.rightclickable = lua_isfunction(L, -1);
270 getstringfield(L, index, "name", f.name);
273 lua_getfield(L, index, "groups");
274 read_groups(L, -1, f.groups);
277 /* Visual definition */
279 f.drawtype = (NodeDrawType)getenumfield(L, index, "drawtype",
280 ScriptApiNode::es_DrawType,NDT_NORMAL);
281 getfloatfield(L, index, "visual_scale", f.visual_scale);
284 lua_getfield(L, index, "tiles");
285 // If nil, try the deprecated name "tile_images" instead
286 if(lua_isnil(L, -1)){
288 warn_if_field_exists(L, index, "tile_images",
289 "Deprecated; new name is \"tiles\".");
290 lua_getfield(L, index, "tile_images");
292 if(lua_istable(L, -1)){
293 int table = lua_gettop(L);
296 while(lua_next(L, table) != 0){
297 // Read tiledef from value
298 f.tiledef[i] = read_tiledef(L, -1);
299 // removes value, keeps key for next iteration
307 // Copy last value to all remaining textures
309 TileDef lasttile = f.tiledef[i-1];
311 f.tiledef[i] = lasttile;
318 // special_tiles = {}
319 lua_getfield(L, index, "special_tiles");
320 // If nil, try the deprecated name "special_materials" instead
321 if(lua_isnil(L, -1)){
323 warn_if_field_exists(L, index, "special_materials",
324 "Deprecated; new name is \"special_tiles\".");
325 lua_getfield(L, index, "special_materials");
327 if(lua_istable(L, -1)){
328 int table = lua_gettop(L);
331 while(lua_next(L, table) != 0){
332 // Read tiledef from value
333 f.tiledef_special[i] = read_tiledef(L, -1);
334 // removes value, keeps key for next iteration
337 if(i==CF_SPECIAL_COUNT){
345 f.alpha = getintfield_default(L, index, "alpha", 255);
347 bool usealpha = getboolfield_default(L, index,
348 "use_texture_alpha", false);
354 lua_getfield(L, index, "post_effect_color");
355 if(!lua_isnil(L, -1))
356 f.post_effect_color = readARGB8(L, -1);
359 f.param_type = (ContentParamType)getenumfield(L, index, "paramtype",
360 ScriptApiNode::es_ContentParamType, CPT_NONE);
361 f.param_type_2 = (ContentParamType2)getenumfield(L, index, "paramtype2",
362 ScriptApiNode::es_ContentParamType2, CPT2_NONE);
364 // Warn about some deprecated fields
365 warn_if_field_exists(L, index, "wall_mounted",
366 "deprecated: use paramtype2 = 'wallmounted'");
367 warn_if_field_exists(L, index, "light_propagates",
368 "deprecated: determined from paramtype");
369 warn_if_field_exists(L, index, "dug_item",
370 "deprecated: use 'drop' field");
371 warn_if_field_exists(L, index, "extra_dug_item",
372 "deprecated: use 'drop' field");
373 warn_if_field_exists(L, index, "extra_dug_item_rarity",
374 "deprecated: use 'drop' field");
375 warn_if_field_exists(L, index, "metadata_name",
376 "deprecated: use on_add and metadata callbacks");
378 // True for all ground-like things like stone and mud, false for eg. trees
379 getboolfield(L, index, "is_ground_content", f.is_ground_content);
380 f.light_propagates = (f.param_type == CPT_LIGHT);
381 getboolfield(L, index, "sunlight_propagates", f.sunlight_propagates);
382 // This is used for collision detection.
383 // Also for general solidness queries.
384 getboolfield(L, index, "walkable", f.walkable);
385 // Player can point to these
386 getboolfield(L, index, "pointable", f.pointable);
387 // Player can dig these
388 getboolfield(L, index, "diggable", f.diggable);
389 // Player can climb these
390 getboolfield(L, index, "climbable", f.climbable);
391 // Player can build on these
392 getboolfield(L, index, "buildable_to", f.buildable_to);
393 // Whether the node is non-liquid, source liquid or flowing liquid
394 f.liquid_type = (LiquidType)getenumfield(L, index, "liquidtype",
395 ScriptApiNode::es_LiquidType, LIQUID_NONE);
396 // If the content is liquid, this is the flowing version of the liquid.
397 getstringfield(L, index, "liquid_alternative_flowing",
398 f.liquid_alternative_flowing);
399 // If the content is liquid, this is the source version of the liquid.
400 getstringfield(L, index, "liquid_alternative_source",
401 f.liquid_alternative_source);
402 // Viscosity for fluid flow, ranging from 1 to 7, with
403 // 1 giving almost instantaneous propagation and 7 being
404 // the slowest possible
405 f.liquid_viscosity = getintfield_default(L, index,
406 "liquid_viscosity", f.liquid_viscosity);
407 f.liquid_range = getintfield_default(L, index,
408 "liquid_range", f.liquid_range);
409 f.leveled = getintfield_default(L, index, "leveled", f.leveled);
411 getboolfield(L, index, "liquid_renewable", f.liquid_renewable);
412 getstringfield(L, index, "freezemelt", f.freezemelt);
413 f.drowning = getintfield_default(L, index,
414 "drowning", f.drowning);
415 // Amount of light the node emits
416 f.light_source = getintfield_default(L, index,
417 "light_source", f.light_source);
418 f.damage_per_second = getintfield_default(L, index,
419 "damage_per_second", f.damage_per_second);
421 lua_getfield(L, index, "node_box");
422 if(lua_istable(L, -1))
423 f.node_box = read_nodebox(L, -1);
426 lua_getfield(L, index, "selection_box");
427 if(lua_istable(L, -1))
428 f.selection_box = read_nodebox(L, -1);
431 f.waving = getintfield_default(L, index,
434 // Set to true if paramtype used to be 'facedir_simple'
435 getboolfield(L, index, "legacy_facedir_simple", f.legacy_facedir_simple);
436 // Set to true if wall_mounted used to be set to true
437 getboolfield(L, index, "legacy_wallmounted", f.legacy_wallmounted);
440 lua_getfield(L, index, "sounds");
441 if(lua_istable(L, -1)){
442 lua_getfield(L, -1, "footstep");
443 read_soundspec(L, -1, f.sound_footstep);
445 lua_getfield(L, -1, "dig");
446 read_soundspec(L, -1, f.sound_dig);
448 lua_getfield(L, -1, "dug");
449 read_soundspec(L, -1, f.sound_dug);
457 /******************************************************************************/
458 void read_server_sound_params(lua_State *L, int index,
459 ServerSoundParams ¶ms)
462 index = lua_gettop(L) + 1 + index;
464 params = ServerSoundParams();
465 if(lua_istable(L, index)){
466 getfloatfield(L, index, "gain", params.gain);
467 getstringfield(L, index, "to_player", params.to_player);
468 lua_getfield(L, index, "pos");
469 if(!lua_isnil(L, -1)){
470 v3f p = read_v3f(L, -1)*BS;
472 params.type = ServerSoundParams::SSP_POSITIONAL;
475 lua_getfield(L, index, "object");
476 if(!lua_isnil(L, -1)){
477 ObjectRef *ref = ObjectRef::checkobject(L, -1);
478 ServerActiveObject *sao = ObjectRef::getobject(ref);
480 params.object = sao->getId();
481 params.type = ServerSoundParams::SSP_OBJECT;
485 params.max_hear_distance = BS*getfloatfield_default(L, index,
486 "max_hear_distance", params.max_hear_distance/BS);
487 getboolfield(L, index, "loop", params.loop);
491 /******************************************************************************/
492 void read_soundspec(lua_State *L, int index, SimpleSoundSpec &spec)
495 index = lua_gettop(L) + 1 + index;
496 if(lua_isnil(L, index)){
497 } else if(lua_istable(L, index)){
498 getstringfield(L, index, "name", spec.name);
499 getfloatfield(L, index, "gain", spec.gain);
500 } else if(lua_isstring(L, index)){
501 spec.name = lua_tostring(L, index);
505 /******************************************************************************/
506 NodeBox read_nodebox(lua_State *L, int index)
509 if(lua_istable(L, -1)){
510 nodebox.type = (NodeBoxType)getenumfield(L, index, "type",
511 ScriptApiNode::es_NodeBoxType, NODEBOX_REGULAR);
513 lua_getfield(L, index, "fixed");
514 if(lua_istable(L, -1))
515 nodebox.fixed = read_aabb3f_vector(L, -1, BS);
518 lua_getfield(L, index, "wall_top");
519 if(lua_istable(L, -1))
520 nodebox.wall_top = read_aabb3f(L, -1, BS);
523 lua_getfield(L, index, "wall_bottom");
524 if(lua_istable(L, -1))
525 nodebox.wall_bottom = read_aabb3f(L, -1, BS);
528 lua_getfield(L, index, "wall_side");
529 if(lua_istable(L, -1))
530 nodebox.wall_side = read_aabb3f(L, -1, BS);
536 /******************************************************************************/
537 MapNode readnode(lua_State *L, int index, INodeDefManager *ndef)
539 lua_getfield(L, index, "name");
540 const char *name = luaL_checkstring(L, -1);
543 lua_getfield(L, index, "param1");
547 param1 = lua_tonumber(L, -1);
550 lua_getfield(L, index, "param2");
554 param2 = lua_tonumber(L, -1);
556 return MapNode(ndef, name, param1, param2);
559 /******************************************************************************/
560 void pushnode(lua_State *L, const MapNode &n, INodeDefManager *ndef)
563 lua_pushstring(L, ndef->get(n).name.c_str());
564 lua_setfield(L, -2, "name");
565 lua_pushnumber(L, n.getParam1());
566 lua_setfield(L, -2, "param1");
567 lua_pushnumber(L, n.getParam2());
568 lua_setfield(L, -2, "param2");
571 /******************************************************************************/
572 void warn_if_field_exists(lua_State *L, int table,
573 const char *fieldname, const std::string &message)
575 lua_getfield(L, table, fieldname);
576 if(!lua_isnil(L, -1)){
577 //TODO find way to access backtrace fct from here
578 // infostream<<script_get_backtrace(L)<<std::endl;
579 infostream<<"WARNING: field \""<<fieldname<<"\": "
580 <<message<<std::endl;
585 /******************************************************************************/
586 int getenumfield(lua_State *L, int table,
587 const char *fieldname, const EnumString *spec, int default_)
589 int result = default_;
590 string_to_enum(spec, result,
591 getstringfield_default(L, table, fieldname, ""));
595 /******************************************************************************/
596 bool string_to_enum(const EnumString *spec, int &result,
597 const std::string &str)
599 const EnumString *esp = spec;
601 if(str == std::string(esp->str)){
610 /******************************************************************************/
611 ItemStack read_item(lua_State* L, int index,Server* srv)
614 index = lua_gettop(L) + 1 + index;
616 if(lua_isnil(L, index))
620 else if(lua_isuserdata(L, index))
622 // Convert from LuaItemStack
623 LuaItemStack *o = LuaItemStack::checkobject(L, index);
626 else if(lua_isstring(L, index))
628 // Convert from itemstring
629 std::string itemstring = lua_tostring(L, index);
630 IItemDefManager *idef = srv->idef();
634 item.deSerialize(itemstring, idef);
637 catch(SerializationError &e)
639 infostream<<"WARNING: unable to create item from itemstring"
640 <<": "<<itemstring<<std::endl;
644 else if(lua_istable(L, index))
646 // Convert from table
647 IItemDefManager *idef = srv->idef();
648 std::string name = getstringfield_default(L, index, "name", "");
649 int count = getintfield_default(L, index, "count", 1);
650 int wear = getintfield_default(L, index, "wear", 0);
651 std::string metadata = getstringfield_default(L, index, "metadata", "");
652 return ItemStack(name, count, wear, metadata, idef);
656 throw LuaError(NULL, "Expecting itemstack, itemstring, table or nil");
660 /******************************************************************************/
661 void push_tool_capabilities(lua_State *L,
662 const ToolCapabilities &toolcap)
665 setfloatfield(L, -1, "full_punch_interval", toolcap.full_punch_interval);
666 setintfield(L, -1, "max_drop_level", toolcap.max_drop_level);
667 // Create groupcaps table
670 for(std::map<std::string, ToolGroupCap>::const_iterator
671 i = toolcap.groupcaps.begin(); i != toolcap.groupcaps.end(); i++){
672 // Create groupcap table
674 const std::string &name = i->first;
675 const ToolGroupCap &groupcap = i->second;
676 // Create subtable "times"
678 for(std::map<int, float>::const_iterator
679 i = groupcap.times.begin(); i != groupcap.times.end(); i++){
680 int rating = i->first;
681 float time = i->second;
682 lua_pushinteger(L, rating);
683 lua_pushnumber(L, time);
686 // Set subtable "times"
687 lua_setfield(L, -2, "times");
688 // Set simple parameters
689 setintfield(L, -1, "maxlevel", groupcap.maxlevel);
690 setintfield(L, -1, "uses", groupcap.uses);
691 // Insert groupcap table into groupcaps table
692 lua_setfield(L, -2, name.c_str());
694 // Set groupcaps table
695 lua_setfield(L, -2, "groupcaps");
696 //Create damage_groups table
698 // For each damage group
699 for(std::map<std::string, s16>::const_iterator
700 i = toolcap.damageGroups.begin(); i != toolcap.damageGroups.end(); i++){
701 // Create damage group table
702 lua_pushinteger(L, i->second);
703 lua_setfield(L, -2, i->first.c_str());
705 lua_setfield(L, -2, "damage_groups");
708 /******************************************************************************/
709 void push_inventory_list(lua_State *L, Inventory *inv, const char *name)
711 InventoryList *invlist = inv->getList(name);
716 std::vector<ItemStack> items;
717 for(u32 i=0; i<invlist->getSize(); i++)
718 items.push_back(invlist->getItem(i));
719 push_items(L, items);
722 /******************************************************************************/
723 void read_inventory_list(lua_State *L, int tableindex,
724 Inventory *inv, const char *name, Server* srv, int forcesize)
727 tableindex = lua_gettop(L) + 1 + tableindex;
728 // If nil, delete list
729 if(lua_isnil(L, tableindex)){
730 inv->deleteList(name);
733 // Otherwise set list
734 std::vector<ItemStack> items = read_items(L, tableindex,srv);
735 int listsize = (forcesize != -1) ? forcesize : items.size();
736 InventoryList *invlist = inv->addList(name, listsize);
738 for(std::vector<ItemStack>::const_iterator
739 i = items.begin(); i != items.end(); i++){
740 if(forcesize != -1 && index == forcesize)
742 invlist->changeItem(index, *i);
745 while(forcesize != -1 && index < forcesize){
746 invlist->deleteItem(index);
751 /******************************************************************************/
752 ToolCapabilities read_tool_capabilities(
753 lua_State *L, int table)
755 ToolCapabilities toolcap;
756 getfloatfield(L, table, "full_punch_interval", toolcap.full_punch_interval);
757 getintfield(L, table, "max_drop_level", toolcap.max_drop_level);
758 lua_getfield(L, table, "groupcaps");
759 if(lua_istable(L, -1)){
760 int table_groupcaps = lua_gettop(L);
762 while(lua_next(L, table_groupcaps) != 0){
763 // key at index -2 and value at index -1
764 std::string groupname = luaL_checkstring(L, -2);
765 if(lua_istable(L, -1)){
766 int table_groupcap = lua_gettop(L);
767 // This will be created
768 ToolGroupCap groupcap;
769 // Read simple parameters
770 getintfield(L, table_groupcap, "maxlevel", groupcap.maxlevel);
771 getintfield(L, table_groupcap, "uses", groupcap.uses);
772 // DEPRECATED: maxwear
774 if(getfloatfield(L, table_groupcap, "maxwear", maxwear)){
776 groupcap.uses = 1.0/maxwear;
779 infostream<<script_get_backtrace(L)<<std::endl;
780 infostream<<"WARNING: field \"maxwear\" is deprecated; "
781 <<"should replace with uses=1/maxwear"<<std::endl;
783 // Read "times" table
784 lua_getfield(L, table_groupcap, "times");
785 if(lua_istable(L, -1)){
786 int table_times = lua_gettop(L);
788 while(lua_next(L, table_times) != 0){
789 // key at index -2 and value at index -1
790 int rating = luaL_checkinteger(L, -2);
791 float time = luaL_checknumber(L, -1);
792 groupcap.times[rating] = time;
793 // removes value, keeps key for next iteration
798 // Insert groupcap into toolcap
799 toolcap.groupcaps[groupname] = groupcap;
801 // removes value, keeps key for next iteration
807 lua_getfield(L, table, "damage_groups");
808 if(lua_istable(L, -1)){
809 int table_damage_groups = lua_gettop(L);
811 while(lua_next(L, table_damage_groups) != 0){
812 // key at index -2 and value at index -1
813 std::string groupname = luaL_checkstring(L, -2);
814 u16 value = luaL_checkinteger(L, -1);
815 toolcap.damageGroups[groupname] = value;
816 // removes value, keeps key for next iteration
824 /******************************************************************************/
825 void push_dig_params(lua_State *L,const DigParams ¶ms)
828 setboolfield(L, -1, "diggable", params.diggable);
829 setfloatfield(L, -1, "time", params.time);
830 setintfield(L, -1, "wear", params.wear);
833 /******************************************************************************/
834 void push_hit_params(lua_State *L,const HitParams ¶ms)
837 setintfield(L, -1, "hp", params.hp);
838 setintfield(L, -1, "wear", params.wear);
841 /******************************************************************************/
842 u32 getflagsfield(lua_State *L, int table, const char *fieldname,
843 FlagDesc *flagdesc, u32 *flagmask)
847 lua_getfield(L, table, fieldname);
849 if (lua_isstring(L, -1)) {
850 std::string flagstr = lua_tostring(L, -1);
851 flags = readFlagString(flagstr, flagdesc, flagmask);
852 } else if (lua_istable(L, -1)) {
853 flags = read_flags_table(L, -1, flagdesc, flagmask);
861 u32 read_flags_table(lua_State *L, int table, FlagDesc *flagdesc, u32 *flagmask)
863 u32 flags = 0, mask = 0;
864 char fnamebuf[64] = "no";
866 for (int i = 0; flagdesc[i].name; i++) {
869 if (getboolfield(L, table, flagdesc[i].name, result)) {
870 mask |= flagdesc[i].flag;
872 flags |= flagdesc[i].flag;
875 strlcpy(fnamebuf + 2, flagdesc[i].name, sizeof(fnamebuf) - 2);
876 if (getboolfield(L, table, fnamebuf, result))
877 mask |= flagdesc[i].flag;
886 /******************************************************************************/
887 /* Lua Stored data! */
888 /******************************************************************************/
890 /******************************************************************************/
891 void read_groups(lua_State *L, int index,
892 std::map<std::string, int> &result)
894 if (!lua_istable(L,index))
900 while(lua_next(L, index) != 0){
901 // key at index -2 and value at index -1
902 std::string name = luaL_checkstring(L, -2);
903 int rating = luaL_checkinteger(L, -1);
904 result[name] = rating;
905 // removes value, keeps key for next iteration
910 /******************************************************************************/
911 void push_items(lua_State *L, const std::vector<ItemStack> &items)
913 // Create and fill table
914 lua_createtable(L, items.size(), 0);
915 std::vector<ItemStack>::const_iterator iter = items.begin();
916 for (u32 i = 0; iter != items.end(); iter++) {
917 LuaItemStack::create(L, *iter);
918 lua_rawseti(L, -2, ++i);
922 /******************************************************************************/
923 std::vector<ItemStack> read_items(lua_State *L, int index, Server *srv)
926 index = lua_gettop(L) + 1 + index;
928 std::vector<ItemStack> items;
929 luaL_checktype(L, index, LUA_TTABLE);
931 while (lua_next(L, index)) {
932 s32 key = luaL_checkinteger(L, -2);
934 throw LuaError(NULL, "Invalid inventory list index");
936 if (items.size() < (u32) key) {
939 items[key - 1] = read_item(L, -1, srv);
945 /******************************************************************************/
946 void luaentity_get(lua_State *L, u16 id)
948 // Get minetest.luaentities[i]
949 lua_getglobal(L, "minetest");
950 lua_getfield(L, -1, "luaentities");
951 luaL_checktype(L, -1, LUA_TTABLE);
952 lua_pushnumber(L, id);
954 lua_remove(L, -2); // luaentities
955 lua_remove(L, -2); // minetest
958 /******************************************************************************/
959 NoiseParams *read_noiseparams(lua_State *L, int index)
962 index = lua_gettop(L) + 1 + index;
964 if (!lua_istable(L, index))
967 NoiseParams *np = new NoiseParams;
969 np->offset = getfloatfield_default(L, index, "offset", 0.0);
970 np->scale = getfloatfield_default(L, index, "scale", 0.0);
971 lua_getfield(L, index, "spread");
972 np->spread = read_v3f(L, -1);
974 np->seed = getintfield_default(L, index, "seed", 0);
975 np->octaves = getintfield_default(L, index, "octaves", 0);
976 np->persist = getfloatfield_default(L, index, "persist", 0.0);
981 /******************************************************************************/
982 bool read_schematic(lua_State *L, int index, DecoSchematic *dschem, Server *server) {
984 index = lua_gettop(L) + 1 + index;
986 INodeDefManager *ndef = server->getNodeDefManager();
988 if (lua_istable(L, index)) {
989 lua_getfield(L, index, "size");
990 v3s16 size = read_v3s16(L, -1);
993 int numnodes = size.X * size.Y * size.Z;
994 MapNode *schemdata = new MapNode[numnodes];
997 // Get schematic data
998 lua_getfield(L, index, "data");
999 luaL_checktype(L, -1, LUA_TTABLE);
1002 while (lua_next(L, -2)) {
1004 // same as readnode, except param1 default is MTSCHEM_PROB_CONST
1005 lua_getfield(L, -1, "name");
1006 const char *name = luaL_checkstring(L, -1);
1010 lua_getfield(L, -1, "param1");
1011 param1 = !lua_isnil(L, -1) ? lua_tonumber(L, -1) : MTSCHEM_PROB_ALWAYS;
1015 lua_getfield(L, -1, "param2");
1016 param2 = !lua_isnil(L, -1) ? lua_tonumber(L, -1) : 0;
1019 schemdata[i] = MapNode(ndef, name, param1, param2);
1026 if (i != numnodes) {
1027 errorstream << "read_schematic: incorrect number of "
1028 "nodes provided in raw schematic data (got " << i <<
1029 ", expected " << numnodes << ")." << std::endl;
1033 u8 *sliceprobs = new u8[size.Y];
1034 for (i = 0; i != size.Y; i++)
1035 sliceprobs[i] = MTSCHEM_PROB_ALWAYS;
1037 // Get Y-slice probability values (if present)
1038 lua_getfield(L, index, "yslice_prob");
1039 if (lua_istable(L, -1)) {
1041 while (lua_next(L, -2)) {
1042 if (getintfield(L, -1, "ypos", i) && i >= 0 && i < size.Y) {
1043 sliceprobs[i] = getintfield_default(L, -1,
1044 "prob", MTSCHEM_PROB_ALWAYS);
1050 dschem->size = size;
1051 dschem->schematic = schemdata;
1052 dschem->slice_probs = sliceprobs;
1054 } else if (lua_isstring(L, index)) {
1055 dschem->filename = std::string(lua_tostring(L, index));
1057 errorstream << "read_schematic: missing schematic "
1058 "filename or raw schematic data" << std::endl;
1065 /******************************************************************************/
1066 // Returns depth of json value tree
1067 static int push_json_value_getdepth(const Json::Value &value)
1069 if (!value.isArray() && !value.isObject())
1073 for (Json::Value::const_iterator it = value.begin();
1074 it != value.end(); ++it) {
1075 int elemdepth = push_json_value_getdepth(*it);
1076 if (elemdepth > maxdepth)
1077 maxdepth = elemdepth;
1079 return maxdepth + 1;
1081 // Recursive function to convert JSON --> Lua table
1082 static bool push_json_value_helper(lua_State *L, const Json::Value &value,
1085 switch(value.type()) {
1086 case Json::nullValue:
1088 lua_pushvalue(L, nullindex);
1090 case Json::intValue:
1091 lua_pushinteger(L, value.asInt());
1093 case Json::uintValue:
1094 lua_pushinteger(L, value.asUInt());
1096 case Json::realValue:
1097 lua_pushnumber(L, value.asDouble());
1099 case Json::stringValue:
1101 const char *str = value.asCString();
1102 lua_pushstring(L, str ? str : "");
1105 case Json::booleanValue:
1106 lua_pushboolean(L, value.asInt());
1108 case Json::arrayValue:
1110 for (Json::Value::const_iterator it = value.begin();
1111 it != value.end(); ++it) {
1112 push_json_value_helper(L, *it, nullindex);
1113 lua_rawseti(L, -2, it.index() + 1);
1116 case Json::objectValue:
1118 for (Json::Value::const_iterator it = value.begin();
1119 it != value.end(); ++it) {
1120 const char *str = it.memberName();
1121 lua_pushstring(L, str ? str : "");
1122 push_json_value_helper(L, *it, nullindex);
1129 // converts JSON --> Lua table; returns false if lua stack limit exceeded
1130 // nullindex: Lua stack index of value to use in place of JSON null
1131 bool push_json_value(lua_State *L, const Json::Value &value, int nullindex)
1134 nullindex = lua_gettop(L) + 1 + nullindex;
1136 int depth = push_json_value_getdepth(value);
1138 // The maximum number of Lua stack slots used at each recursion level
1139 // of push_json_value_helper is 2, so make sure there a depth * 2 slots
1140 if (lua_checkstack(L, depth * 2))
1141 return push_json_value_helper(L, value, nullindex);
1146 // Converts Lua table --> JSON
1147 void read_json_value(lua_State *L, Json::Value &root, int index, u8 recursion)
1149 if (recursion > 16) {
1150 throw SerializationError("Maximum recursion depth exceeded");
1152 int type = lua_type(L, index);
1153 if (type == LUA_TBOOLEAN) {
1154 root = (bool) lua_toboolean(L, index);
1155 } else if (type == LUA_TNUMBER) {
1156 root = lua_tonumber(L, index);
1157 } else if (type == LUA_TSTRING) {
1159 const char *str = lua_tolstring(L, index, &len);
1160 root = std::string(str, len);
1161 } else if (type == LUA_TTABLE) {
1163 while (lua_next(L, index)) {
1164 // Key is at -2 and value is at -1
1166 read_json_value(L, value, lua_gettop(L), recursion + 1);
1168 Json::ValueType roottype = root.type();
1169 int keytype = lua_type(L, -1);
1170 if (keytype == LUA_TNUMBER) {
1171 lua_Number key = lua_tonumber(L, -1);
1172 if (roottype != Json::nullValue && roottype != Json::arrayValue) {
1173 throw SerializationError("Can't mix array and object values in JSON");
1174 } else if (key < 1) {
1175 throw SerializationError("Can't use zero-based or negative indexes in JSON");
1176 } else if (floor(key) != key) {
1177 throw SerializationError("Can't use indexes with a fractional part in JSON");
1179 root[(Json::ArrayIndex) key - 1] = value;
1180 } else if (keytype == LUA_TSTRING) {
1181 if (roottype != Json::nullValue && roottype != Json::objectValue) {
1182 throw SerializationError("Can't mix array and object values in JSON");
1184 root[lua_tostring(L, -1)] = value;
1186 throw SerializationError("Lua key to convert to JSON is not a string or number");
1189 } else if (type == LUA_TNIL) {
1190 root = Json::nullValue;
1192 throw SerializationError("Can only store booleans, numbers, strings, objects, arrays, and null in JSON");
1194 lua_pop(L, 1); // Pop value