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"
23 #include "object_properties.h"
24 #include "cpp_api/s_node.h"
25 #include "lua_api/l_object.h"
26 #include "lua_api/l_item.h"
27 #include "common/c_internal.h"
31 #include "serverobject.h"
33 #include "mg_schematic.h"
35 #include "util/pointedthing.h"
36 #include "debug.h" // For FATAL_ERROR
37 #include <json/json.h>
39 struct EnumString es_TileAnimationType[] =
42 {TAT_VERTICAL_FRAMES, "vertical_frames"},
43 {TAT_SHEET_2D, "sheet_2d"},
47 /******************************************************************************/
48 void read_item_definition(lua_State* L, int index,
49 const ItemDefinition &default_def, ItemDefinition &def)
52 index = lua_gettop(L) + 1 + index;
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, "inventory_overlay", def.inventory_overlay);
60 getstringfield(L, index, "wield_image", def.wield_image);
61 getstringfield(L, index, "wield_overlay", def.wield_overlay);
62 getstringfield(L, index, "palette", def.palette_image);
65 lua_getfield(L, index, "color");
66 read_color(L, -1, &def.color);
69 lua_getfield(L, index, "wield_scale");
70 if(lua_istable(L, -1)){
71 def.wield_scale = check_v3f(L, -1);
75 int stack_max = getintfield_default(L, index, "stack_max", def.stack_max);
76 def.stack_max = rangelim(stack_max, 1, U16_MAX);
78 lua_getfield(L, index, "on_use");
79 def.usable = lua_isfunction(L, -1);
82 getboolfield(L, index, "liquids_pointable", def.liquids_pointable);
84 warn_if_field_exists(L, index, "tool_digging_properties",
85 "Deprecated; use tool_capabilities");
87 lua_getfield(L, index, "tool_capabilities");
88 if(lua_istable(L, -1)){
89 def.tool_capabilities = new ToolCapabilities(
90 read_tool_capabilities(L, -1));
93 // If name is "" (hand), ensure there are ToolCapabilities
94 // because it will be looked up there whenever any other item has
95 // no ToolCapabilities
96 if (def.name.empty() && def.tool_capabilities == NULL){
97 def.tool_capabilities = new ToolCapabilities();
100 lua_getfield(L, index, "groups");
101 read_groups(L, -1, def.groups);
104 lua_getfield(L, index, "sounds");
105 if(lua_istable(L, -1)){
106 lua_getfield(L, -1, "place");
107 read_soundspec(L, -1, def.sound_place);
109 lua_getfield(L, -1, "place_failed");
110 read_soundspec(L, -1, def.sound_place_failed);
115 def.range = getfloatfield_default(L, index, "range", def.range);
117 // Client shall immediately place this node when player places the item.
118 // Server will update the precise end result a moment later.
119 // "" = no prediction
120 getstringfield(L, index, "node_placement_prediction",
121 def.node_placement_prediction);
124 /******************************************************************************/
125 void push_item_definition(lua_State *L, const ItemDefinition &i)
128 lua_pushstring(L, i.name.c_str());
129 lua_setfield(L, -2, "name");
130 lua_pushstring(L, i.description.c_str());
131 lua_setfield(L, -2, "description");
134 void push_item_definition_full(lua_State *L, const ItemDefinition &i)
136 std::string type(es_ItemType[(int)i.type].str);
139 lua_pushstring(L, i.name.c_str());
140 lua_setfield(L, -2, "name");
141 lua_pushstring(L, i.description.c_str());
142 lua_setfield(L, -2, "description");
143 lua_pushstring(L, type.c_str());
144 lua_setfield(L, -2, "type");
145 lua_pushstring(L, i.inventory_image.c_str());
146 lua_setfield(L, -2, "inventory_image");
147 lua_pushstring(L, i.inventory_overlay.c_str());
148 lua_setfield(L, -2, "inventory_overlay");
149 lua_pushstring(L, i.wield_image.c_str());
150 lua_setfield(L, -2, "wield_image");
151 lua_pushstring(L, i.wield_overlay.c_str());
152 lua_setfield(L, -2, "wield_overlay");
153 lua_pushstring(L, i.palette_image.c_str());
154 lua_setfield(L, -2, "palette_image");
155 push_ARGB8(L, i.color);
156 lua_setfield(L, -2, "color");
157 push_v3f(L, i.wield_scale);
158 lua_setfield(L, -2, "wield_scale");
159 lua_pushinteger(L, i.stack_max);
160 lua_setfield(L, -2, "stack_max");
161 lua_pushboolean(L, i.usable);
162 lua_setfield(L, -2, "usable");
163 lua_pushboolean(L, i.liquids_pointable);
164 lua_setfield(L, -2, "liquids_pointable");
165 if (i.type == ITEM_TOOL) {
166 push_tool_capabilities(L, ToolCapabilities(
167 i.tool_capabilities->full_punch_interval,
168 i.tool_capabilities->max_drop_level,
169 i.tool_capabilities->groupcaps,
170 i.tool_capabilities->damageGroups));
171 lua_setfield(L, -2, "tool_capabilities");
173 push_groups(L, i.groups);
174 lua_setfield(L, -2, "groups");
175 push_soundspec(L, i.sound_place);
176 lua_setfield(L, -2, "sound_place");
177 push_soundspec(L, i.sound_place_failed);
178 lua_setfield(L, -2, "sound_place_failed");
179 lua_pushstring(L, i.node_placement_prediction.c_str());
180 lua_setfield(L, -2, "node_placement_prediction");
183 /******************************************************************************/
184 void read_object_properties(lua_State *L, int index,
185 ObjectProperties *prop, IItemDefManager *idef)
188 index = lua_gettop(L) + 1 + index;
189 if(!lua_istable(L, index))
193 if (getintfield(L, -1, "hp_max", hp_max))
194 prop->hp_max = (s16)rangelim(hp_max, 0, S16_MAX);
196 getboolfield(L, -1, "physical", prop->physical);
197 getboolfield(L, -1, "collide_with_objects", prop->collideWithObjects);
199 getfloatfield(L, -1, "weight", prop->weight);
201 lua_getfield(L, -1, "collisionbox");
202 if(lua_istable(L, -1))
203 prop->collisionbox = read_aabb3f(L, -1, 1.0);
206 lua_getfield(L, -1, "selectionbox");
207 if (lua_istable(L, -1))
208 prop->selectionbox = read_aabb3f(L, -1, 1.0);
210 prop->selectionbox = prop->collisionbox;
212 getboolfield(L, -1, "pointable", prop->pointable);
213 getstringfield(L, -1, "visual", prop->visual);
215 getstringfield(L, -1, "mesh", prop->mesh);
217 lua_getfield(L, -1, "visual_size");
218 if(lua_istable(L, -1))
219 prop->visual_size = read_v2f(L, -1);
222 lua_getfield(L, -1, "textures");
223 if(lua_istable(L, -1)){
224 prop->textures.clear();
225 int table = lua_gettop(L);
227 while(lua_next(L, table) != 0){
228 // key at index -2 and value at index -1
229 if(lua_isstring(L, -1))
230 prop->textures.emplace_back(lua_tostring(L, -1));
232 prop->textures.emplace_back("");
233 // removes value, keeps key for next iteration
239 lua_getfield(L, -1, "colors");
240 if (lua_istable(L, -1)) {
241 int table = lua_gettop(L);
242 prop->colors.clear();
243 for (lua_pushnil(L); lua_next(L, table); lua_pop(L, 1)) {
244 video::SColor color(255, 255, 255, 255);
245 read_color(L, -1, &color);
246 prop->colors.push_back(color);
251 lua_getfield(L, -1, "spritediv");
252 if(lua_istable(L, -1))
253 prop->spritediv = read_v2s16(L, -1);
256 lua_getfield(L, -1, "initial_sprite_basepos");
257 if(lua_istable(L, -1))
258 prop->initial_sprite_basepos = read_v2s16(L, -1);
261 getboolfield(L, -1, "is_visible", prop->is_visible);
262 getboolfield(L, -1, "makes_footstep_sound", prop->makes_footstep_sound);
263 if (getfloatfield(L, -1, "stepheight", prop->stepheight))
264 prop->stepheight *= BS;
265 getboolfield(L, -1, "can_zoom", prop->can_zoom);
267 getfloatfield(L, -1, "automatic_rotate", prop->automatic_rotate);
268 lua_getfield(L, -1, "automatic_face_movement_dir");
269 if (lua_isnumber(L, -1)) {
270 prop->automatic_face_movement_dir = true;
271 prop->automatic_face_movement_dir_offset = luaL_checknumber(L, -1);
272 } else if (lua_isboolean(L, -1)) {
273 prop->automatic_face_movement_dir = lua_toboolean(L, -1);
274 prop->automatic_face_movement_dir_offset = 0.0;
277 getboolfield(L, -1, "backface_culling", prop->backface_culling);
279 getstringfield(L, -1, "nametag", prop->nametag);
280 lua_getfield(L, -1, "nametag_color");
281 if (!lua_isnil(L, -1)) {
282 video::SColor color = prop->nametag_color;
283 if (read_color(L, -1, &color))
284 prop->nametag_color = color;
288 lua_getfield(L, -1, "automatic_face_movement_max_rotation_per_sec");
289 if (lua_isnumber(L, -1)) {
290 prop->automatic_face_movement_max_rotation_per_sec = luaL_checknumber(L, -1);
293 getstringfield(L, -1, "infotext", prop->infotext);
294 lua_getfield(L, -1, "wield_item");
295 if (!lua_isnil(L, -1))
296 prop->wield_item = read_item(L, -1, idef).getItemString();
300 /******************************************************************************/
301 void push_object_properties(lua_State *L, ObjectProperties *prop)
304 lua_pushnumber(L, prop->hp_max);
305 lua_setfield(L, -2, "hp_max");
306 lua_pushboolean(L, prop->physical);
307 lua_setfield(L, -2, "physical");
308 lua_pushboolean(L, prop->collideWithObjects);
309 lua_setfield(L, -2, "collide_with_objects");
310 lua_pushnumber(L, prop->weight);
311 lua_setfield(L, -2, "weight");
312 push_aabb3f(L, prop->collisionbox);
313 lua_setfield(L, -2, "collisionbox");
314 push_aabb3f(L, prop->selectionbox);
315 lua_setfield(L, -2, "selectionbox");
316 lua_pushboolean(L, prop->pointable);
317 lua_setfield(L, -2, "pointable");
318 lua_pushlstring(L, prop->visual.c_str(), prop->visual.size());
319 lua_setfield(L, -2, "visual");
320 lua_pushlstring(L, prop->mesh.c_str(), prop->mesh.size());
321 lua_setfield(L, -2, "mesh");
322 push_v2f(L, prop->visual_size);
323 lua_setfield(L, -2, "visual_size");
327 for (const std::string &texture : prop->textures) {
328 lua_pushlstring(L, texture.c_str(), texture.size());
329 lua_rawseti(L, -2, i);
331 lua_setfield(L, -2, "textures");
335 for (const video::SColor &color : prop->colors) {
336 push_ARGB8(L, color);
337 lua_rawseti(L, -2, i);
339 lua_setfield(L, -2, "colors");
341 push_v2s16(L, prop->spritediv);
342 lua_setfield(L, -2, "spritediv");
343 push_v2s16(L, prop->initial_sprite_basepos);
344 lua_setfield(L, -2, "initial_sprite_basepos");
345 lua_pushboolean(L, prop->is_visible);
346 lua_setfield(L, -2, "is_visible");
347 lua_pushboolean(L, prop->makes_footstep_sound);
348 lua_setfield(L, -2, "makes_footstep_sound");
349 lua_pushnumber(L, prop->stepheight / BS);
350 lua_setfield(L, -2, "stepheight");
351 lua_pushboolean(L, prop->can_zoom);
352 lua_setfield(L, -2, "can_zoom");
354 lua_pushnumber(L, prop->automatic_rotate);
355 lua_setfield(L, -2, "automatic_rotate");
356 if (prop->automatic_face_movement_dir)
357 lua_pushnumber(L, prop->automatic_face_movement_dir_offset);
359 lua_pushboolean(L, false);
360 lua_setfield(L, -2, "automatic_face_movement_dir");
361 lua_pushboolean(L, prop->backface_culling);
362 lua_setfield(L, -2, "backface_culling");
363 lua_pushlstring(L, prop->nametag.c_str(), prop->nametag.size());
364 lua_setfield(L, -2, "nametag");
365 push_ARGB8(L, prop->nametag_color);
366 lua_setfield(L, -2, "nametag_color");
367 lua_pushnumber(L, prop->automatic_face_movement_max_rotation_per_sec);
368 lua_setfield(L, -2, "automatic_face_movement_max_rotation_per_sec");
369 lua_pushlstring(L, prop->infotext.c_str(), prop->infotext.size());
370 lua_setfield(L, -2, "infotext");
371 lua_pushlstring(L, prop->wield_item.c_str(), prop->wield_item.size());
372 lua_setfield(L, -2, "wield_item");
375 /******************************************************************************/
376 TileDef read_tiledef(lua_State *L, int index, u8 drawtype)
379 index = lua_gettop(L) + 1 + index;
383 bool default_tiling = true;
384 bool default_culling = true;
387 case NDT_PLANTLIKE_ROOTED:
389 default_tiling = false;
390 // "break" is omitted here intentionaly, as PLANTLIKE
391 // FIRELIKE drawtype both should default to having
392 // backface_culling to false.
395 default_culling = false;
401 // key at index -2 and value at index
402 if(lua_isstring(L, index)){
403 // "default_lava.png"
404 tiledef.name = lua_tostring(L, index);
405 tiledef.tileable_vertical = default_tiling;
406 tiledef.tileable_horizontal = default_tiling;
407 tiledef.backface_culling = default_culling;
409 else if(lua_istable(L, index))
411 // name="default_lava.png"
413 getstringfield(L, index, "name", tiledef.name);
414 getstringfield(L, index, "image", tiledef.name); // MaterialSpec compat.
415 tiledef.backface_culling = getboolfield_default(
416 L, index, "backface_culling", default_culling);
417 tiledef.tileable_horizontal = getboolfield_default(
418 L, index, "tileable_horizontal", default_tiling);
419 tiledef.tileable_vertical = getboolfield_default(
420 L, index, "tileable_vertical", default_tiling);
422 lua_getfield(L, index, "color");
423 tiledef.has_color = read_color(L, -1, &tiledef.color);
426 lua_getfield(L, index, "animation");
427 tiledef.animation = read_animation_definition(L, -1);
434 /******************************************************************************/
435 ContentFeatures read_content_features(lua_State *L, int index)
438 index = lua_gettop(L) + 1 + index;
442 /* Cache existence of some callbacks */
443 lua_getfield(L, index, "on_construct");
444 if(!lua_isnil(L, -1)) f.has_on_construct = true;
446 lua_getfield(L, index, "on_destruct");
447 if(!lua_isnil(L, -1)) f.has_on_destruct = true;
449 lua_getfield(L, index, "after_destruct");
450 if(!lua_isnil(L, -1)) f.has_after_destruct = true;
453 lua_getfield(L, index, "on_rightclick");
454 f.rightclickable = lua_isfunction(L, -1);
458 getstringfield(L, index, "name", f.name);
461 lua_getfield(L, index, "groups");
462 read_groups(L, -1, f.groups);
465 /* Visual definition */
467 f.drawtype = (NodeDrawType)getenumfield(L, index, "drawtype",
468 ScriptApiNode::es_DrawType,NDT_NORMAL);
469 getfloatfield(L, index, "visual_scale", f.visual_scale);
471 /* Meshnode model filename */
472 getstringfield(L, index, "mesh", f.mesh);
475 lua_getfield(L, index, "tiles");
476 // If nil, try the deprecated name "tile_images" instead
477 if(lua_isnil(L, -1)){
479 warn_if_field_exists(L, index, "tile_images",
480 "Deprecated; new name is \"tiles\".");
481 lua_getfield(L, index, "tile_images");
483 if(lua_istable(L, -1)){
484 int table = lua_gettop(L);
487 while(lua_next(L, table) != 0){
488 // Read tiledef from value
489 f.tiledef[i] = read_tiledef(L, -1, f.drawtype);
490 // removes value, keeps key for next iteration
498 // Copy last value to all remaining textures
500 TileDef lasttile = f.tiledef[i-1];
502 f.tiledef[i] = lasttile;
509 // overlay_tiles = {}
510 lua_getfield(L, index, "overlay_tiles");
511 if (lua_istable(L, -1)) {
512 int table = lua_gettop(L);
515 while (lua_next(L, table) != 0) {
516 // Read tiledef from value
517 f.tiledef_overlay[i] = read_tiledef(L, -1, f.drawtype);
518 // removes value, keeps key for next iteration
526 // Copy last value to all remaining textures
528 TileDef lasttile = f.tiledef_overlay[i - 1];
530 f.tiledef_overlay[i] = lasttile;
537 // special_tiles = {}
538 lua_getfield(L, index, "special_tiles");
539 // If nil, try the deprecated name "special_materials" instead
540 if(lua_isnil(L, -1)){
542 warn_if_field_exists(L, index, "special_materials",
543 "Deprecated; new name is \"special_tiles\".");
544 lua_getfield(L, index, "special_materials");
546 if(lua_istable(L, -1)){
547 int table = lua_gettop(L);
550 while(lua_next(L, table) != 0){
551 // Read tiledef from value
552 f.tiledef_special[i] = read_tiledef(L, -1, f.drawtype);
553 // removes value, keeps key for next iteration
556 if(i==CF_SPECIAL_COUNT){
564 f.alpha = getintfield_default(L, index, "alpha", 255);
566 bool usealpha = getboolfield_default(L, index,
567 "use_texture_alpha", false);
572 lua_getfield(L, index, "color");
573 read_color(L, -1, &f.color);
576 getstringfield(L, index, "palette", f.palette_name);
580 lua_getfield(L, index, "post_effect_color");
581 read_color(L, -1, &f.post_effect_color);
584 f.param_type = (ContentParamType)getenumfield(L, index, "paramtype",
585 ScriptApiNode::es_ContentParamType, CPT_NONE);
586 f.param_type_2 = (ContentParamType2)getenumfield(L, index, "paramtype2",
587 ScriptApiNode::es_ContentParamType2, CPT2_NONE);
589 if (!f.palette_name.empty() &&
590 !(f.param_type_2 == CPT2_COLOR ||
591 f.param_type_2 == CPT2_COLORED_FACEDIR ||
592 f.param_type_2 == CPT2_COLORED_WALLMOUNTED))
593 warningstream << "Node " << f.name.c_str()
594 << " has a palette, but not a suitable paramtype2." << std::endl;
596 // Warn about some deprecated fields
597 warn_if_field_exists(L, index, "wall_mounted",
598 "Deprecated; use paramtype2 = 'wallmounted'");
599 warn_if_field_exists(L, index, "light_propagates",
600 "Deprecated; determined from paramtype");
601 warn_if_field_exists(L, index, "dug_item",
602 "Deprecated; use 'drop' field");
603 warn_if_field_exists(L, index, "extra_dug_item",
604 "Deprecated; use 'drop' field");
605 warn_if_field_exists(L, index, "extra_dug_item_rarity",
606 "Deprecated; use 'drop' field");
607 warn_if_field_exists(L, index, "metadata_name",
608 "Deprecated; use on_add and metadata callbacks");
610 // True for all ground-like things like stone and mud, false for eg. trees
611 getboolfield(L, index, "is_ground_content", f.is_ground_content);
612 f.light_propagates = (f.param_type == CPT_LIGHT);
613 getboolfield(L, index, "sunlight_propagates", f.sunlight_propagates);
614 // This is used for collision detection.
615 // Also for general solidness queries.
616 getboolfield(L, index, "walkable", f.walkable);
617 // Player can point to these
618 getboolfield(L, index, "pointable", f.pointable);
619 // Player can dig these
620 getboolfield(L, index, "diggable", f.diggable);
621 // Player can climb these
622 getboolfield(L, index, "climbable", f.climbable);
623 // Player can build on these
624 getboolfield(L, index, "buildable_to", f.buildable_to);
625 // Liquids flow into and replace node
626 getboolfield(L, index, "floodable", f.floodable);
627 // Whether the node is non-liquid, source liquid or flowing liquid
628 f.liquid_type = (LiquidType)getenumfield(L, index, "liquidtype",
629 ScriptApiNode::es_LiquidType, LIQUID_NONE);
630 // If the content is liquid, this is the flowing version of the liquid.
631 getstringfield(L, index, "liquid_alternative_flowing",
632 f.liquid_alternative_flowing);
633 // If the content is liquid, this is the source version of the liquid.
634 getstringfield(L, index, "liquid_alternative_source",
635 f.liquid_alternative_source);
636 // Viscosity for fluid flow, ranging from 1 to 7, with
637 // 1 giving almost instantaneous propagation and 7 being
638 // the slowest possible
639 f.liquid_viscosity = getintfield_default(L, index,
640 "liquid_viscosity", f.liquid_viscosity);
641 f.liquid_range = getintfield_default(L, index,
642 "liquid_range", f.liquid_range);
643 f.leveled = getintfield_default(L, index, "leveled", f.leveled);
645 getboolfield(L, index, "liquid_renewable", f.liquid_renewable);
646 f.drowning = getintfield_default(L, index,
647 "drowning", f.drowning);
648 // Amount of light the node emits
649 f.light_source = getintfield_default(L, index,
650 "light_source", f.light_source);
651 if (f.light_source > LIGHT_MAX) {
652 warningstream << "Node " << f.name.c_str()
653 << " had greater light_source than " << LIGHT_MAX
654 << ", it was reduced." << std::endl;
655 f.light_source = LIGHT_MAX;
657 f.damage_per_second = getintfield_default(L, index,
658 "damage_per_second", f.damage_per_second);
660 lua_getfield(L, index, "node_box");
661 if(lua_istable(L, -1))
662 f.node_box = read_nodebox(L, -1);
665 lua_getfield(L, index, "connects_to");
666 if (lua_istable(L, -1)) {
667 int table = lua_gettop(L);
669 while (lua_next(L, table) != 0) {
671 f.connects_to.emplace_back(lua_tostring(L, -1));
677 lua_getfield(L, index, "connect_sides");
678 if (lua_istable(L, -1)) {
679 int table = lua_gettop(L);
681 while (lua_next(L, table) != 0) {
683 std::string side(lua_tostring(L, -1));
684 // Note faces are flipped to make checking easier
686 f.connect_sides |= 2;
687 else if (side == "bottom")
688 f.connect_sides |= 1;
689 else if (side == "front")
690 f.connect_sides |= 16;
691 else if (side == "left")
692 f.connect_sides |= 32;
693 else if (side == "back")
694 f.connect_sides |= 4;
695 else if (side == "right")
696 f.connect_sides |= 8;
698 warningstream << "Unknown value for \"connect_sides\": "
699 << side << std::endl;
705 lua_getfield(L, index, "selection_box");
706 if(lua_istable(L, -1))
707 f.selection_box = read_nodebox(L, -1);
710 lua_getfield(L, index, "collision_box");
711 if(lua_istable(L, -1))
712 f.collision_box = read_nodebox(L, -1);
715 f.waving = getintfield_default(L, index,
718 // Set to true if paramtype used to be 'facedir_simple'
719 getboolfield(L, index, "legacy_facedir_simple", f.legacy_facedir_simple);
720 // Set to true if wall_mounted used to be set to true
721 getboolfield(L, index, "legacy_wallmounted", f.legacy_wallmounted);
724 lua_getfield(L, index, "sounds");
725 if(lua_istable(L, -1)){
726 lua_getfield(L, -1, "footstep");
727 read_soundspec(L, -1, f.sound_footstep);
729 lua_getfield(L, -1, "dig");
730 read_soundspec(L, -1, f.sound_dig);
732 lua_getfield(L, -1, "dug");
733 read_soundspec(L, -1, f.sound_dug);
741 void push_content_features(lua_State *L, const ContentFeatures &c)
743 std::string paramtype(ScriptApiNode::es_ContentParamType[(int)c.param_type].str);
744 std::string paramtype2(ScriptApiNode::es_ContentParamType2[(int)c.param_type_2].str);
745 std::string drawtype(ScriptApiNode::es_DrawType[(int)c.drawtype].str);
746 std::string liquid_type(ScriptApiNode::es_LiquidType[(int)c.liquid_type].str);
748 /* Missing "tiles" because I don't see a usecase (at least not yet). */
751 lua_pushboolean(L, c.has_on_construct);
752 lua_setfield(L, -2, "has_on_construct");
753 lua_pushboolean(L, c.has_on_destruct);
754 lua_setfield(L, -2, "has_on_destruct");
755 lua_pushboolean(L, c.has_after_destruct);
756 lua_setfield(L, -2, "has_after_destruct");
757 lua_pushstring(L, c.name.c_str());
758 lua_setfield(L, -2, "name");
759 push_groups(L, c.groups);
760 lua_setfield(L, -2, "groups");
761 lua_pushstring(L, paramtype.c_str());
762 lua_setfield(L, -2, "paramtype");
763 lua_pushstring(L, paramtype2.c_str());
764 lua_setfield(L, -2, "paramtype2");
765 lua_pushstring(L, drawtype.c_str());
766 lua_setfield(L, -2, "drawtype");
767 if (!c.mesh.empty()) {
768 lua_pushstring(L, c.mesh.c_str());
769 lua_setfield(L, -2, "mesh");
772 push_ARGB8(L, c.minimap_color); // I know this is not set-able w/ register_node,
773 lua_setfield(L, -2, "minimap_color"); // but the people need to know!
775 lua_pushnumber(L, c.visual_scale);
776 lua_setfield(L, -2, "visual_scale");
777 lua_pushnumber(L, c.alpha);
778 lua_setfield(L, -2, "alpha");
779 if (!c.palette_name.empty()) {
780 push_ARGB8(L, c.color);
781 lua_setfield(L, -2, "color");
783 lua_pushstring(L, c.palette_name.c_str());
784 lua_setfield(L, -2, "palette_name");
786 push_palette(L, c.palette);
787 lua_setfield(L, -2, "palette");
789 lua_pushnumber(L, c.waving);
790 lua_setfield(L, -2, "waving");
791 lua_pushnumber(L, c.connect_sides);
792 lua_setfield(L, -2, "connect_sides");
796 for (const std::string &it : c.connects_to) {
797 lua_pushlstring(L, it.c_str(), it.size());
798 lua_rawseti(L, -2, i);
800 lua_setfield(L, -2, "connects_to");
802 push_ARGB8(L, c.post_effect_color);
803 lua_setfield(L, -2, "post_effect_color");
804 lua_pushnumber(L, c.leveled);
805 lua_setfield(L, -2, "leveled");
806 lua_pushboolean(L, c.sunlight_propagates);
807 lua_setfield(L, -2, "sunlight_propagates");
808 lua_pushnumber(L, c.light_source);
809 lua_setfield(L, -2, "light_source");
810 lua_pushboolean(L, c.is_ground_content);
811 lua_setfield(L, -2, "is_ground_content");
812 lua_pushboolean(L, c.walkable);
813 lua_setfield(L, -2, "walkable");
814 lua_pushboolean(L, c.pointable);
815 lua_setfield(L, -2, "pointable");
816 lua_pushboolean(L, c.diggable);
817 lua_setfield(L, -2, "diggable");
818 lua_pushboolean(L, c.climbable);
819 lua_setfield(L, -2, "climbable");
820 lua_pushboolean(L, c.buildable_to);
821 lua_setfield(L, -2, "buildable_to");
822 lua_pushboolean(L, c.rightclickable);
823 lua_setfield(L, -2, "rightclickable");
824 lua_pushnumber(L, c.damage_per_second);
825 lua_setfield(L, -2, "damage_per_second");
827 lua_pushstring(L, liquid_type.c_str());
828 lua_setfield(L, -2, "liquid_type");
829 lua_pushstring(L, c.liquid_alternative_flowing.c_str());
830 lua_setfield(L, -2, "liquid_alternative_flowing");
831 lua_pushstring(L, c.liquid_alternative_source.c_str());
832 lua_setfield(L, -2, "liquid_alternative_source");
833 lua_pushnumber(L, c.liquid_viscosity);
834 lua_setfield(L, -2, "liquid_viscosity");
835 lua_pushboolean(L, c.liquid_renewable);
836 lua_setfield(L, -2, "liquid_renewable");
837 lua_pushnumber(L, c.liquid_range);
838 lua_setfield(L, -2, "liquid_range");
840 lua_pushnumber(L, c.drowning);
841 lua_setfield(L, -2, "drowning");
842 lua_pushboolean(L, c.floodable);
843 lua_setfield(L, -2, "floodable");
844 push_nodebox(L, c.node_box);
845 lua_setfield(L, -2, "node_box");
846 push_nodebox(L, c.selection_box);
847 lua_setfield(L, -2, "selection_box");
848 push_nodebox(L, c.collision_box);
849 lua_setfield(L, -2, "collision_box");
851 push_soundspec(L, c.sound_footstep);
852 lua_setfield(L, -2, "sound_footstep");
853 push_soundspec(L, c.sound_dig);
854 lua_setfield(L, -2, "sound_dig");
855 push_soundspec(L, c.sound_dug);
856 lua_setfield(L, -2, "sound_dug");
857 lua_setfield(L, -2, "sounds");
858 lua_pushboolean(L, c.legacy_facedir_simple);
859 lua_setfield(L, -2, "legacy_facedir_simple");
860 lua_pushboolean(L, c.legacy_wallmounted);
861 lua_setfield(L, -2, "legacy_wallmounted");
864 /******************************************************************************/
865 void push_nodebox(lua_State *L, const NodeBox &box)
870 case NODEBOX_REGULAR:
871 lua_pushstring(L, "regular");
872 lua_setfield(L, -2, "type");
874 case NODEBOX_LEVELED:
876 lua_pushstring(L, "fixed");
877 lua_setfield(L, -2, "type");
878 push_box(L, box.fixed);
879 lua_setfield(L, -2, "fixed");
881 case NODEBOX_WALLMOUNTED:
882 lua_pushstring(L, "wallmounted");
883 lua_setfield(L, -2, "type");
884 push_aabb3f(L, box.wall_top);
885 lua_setfield(L, -2, "wall_top");
886 push_aabb3f(L, box.wall_bottom);
887 lua_setfield(L, -2, "wall_bottom");
888 push_aabb3f(L, box.wall_side);
889 lua_setfield(L, -2, "wall_side");
891 case NODEBOX_CONNECTED:
892 lua_pushstring(L, "connected");
893 lua_setfield(L, -2, "type");
894 push_box(L, box.connect_top);
895 lua_setfield(L, -2, "connect_top");
896 push_box(L, box.connect_bottom);
897 lua_setfield(L, -2, "connect_bottom");
898 push_box(L, box.connect_front);
899 lua_setfield(L, -2, "connect_front");
900 push_box(L, box.connect_back);
901 lua_setfield(L, -2, "connect_back");
902 push_box(L, box.connect_left);
903 lua_setfield(L, -2, "connect_left");
904 push_box(L, box.connect_right);
905 lua_setfield(L, -2, "connect_right");
908 FATAL_ERROR("Invalid box.type");
913 void push_box(lua_State *L, const std::vector<aabb3f> &box)
917 for (const aabb3f &it : box) {
919 lua_rawseti(L, -2, i);
923 /******************************************************************************/
924 void push_palette(lua_State *L, const std::vector<video::SColor> *palette)
926 lua_createtable(L, palette->size(), 0);
927 int newTable = lua_gettop(L);
929 std::vector<video::SColor>::const_iterator iter;
930 for (iter = palette->begin(); iter != palette->end(); ++iter) {
931 push_ARGB8(L, (*iter));
932 lua_rawseti(L, newTable, index);
937 /******************************************************************************/
938 void read_server_sound_params(lua_State *L, int index,
939 ServerSoundParams ¶ms)
942 index = lua_gettop(L) + 1 + index;
944 params = ServerSoundParams();
945 if(lua_istable(L, index)){
946 getfloatfield(L, index, "gain", params.gain);
947 getstringfield(L, index, "to_player", params.to_player);
948 getfloatfield(L, index, "fade", params.fade);
949 getfloatfield(L, index, "pitch", params.pitch);
950 lua_getfield(L, index, "pos");
951 if(!lua_isnil(L, -1)){
952 v3f p = read_v3f(L, -1)*BS;
954 params.type = ServerSoundParams::SSP_POSITIONAL;
957 lua_getfield(L, index, "object");
958 if(!lua_isnil(L, -1)){
959 ObjectRef *ref = ObjectRef::checkobject(L, -1);
960 ServerActiveObject *sao = ObjectRef::getobject(ref);
962 params.object = sao->getId();
963 params.type = ServerSoundParams::SSP_OBJECT;
967 params.max_hear_distance = BS*getfloatfield_default(L, index,
968 "max_hear_distance", params.max_hear_distance/BS);
969 getboolfield(L, index, "loop", params.loop);
973 /******************************************************************************/
974 void read_soundspec(lua_State *L, int index, SimpleSoundSpec &spec)
977 index = lua_gettop(L) + 1 + index;
978 if(lua_isnil(L, index)){
979 } else if(lua_istable(L, index)){
980 getstringfield(L, index, "name", spec.name);
981 getfloatfield(L, index, "gain", spec.gain);
982 getfloatfield(L, index, "fade", spec.fade);
983 getfloatfield(L, index, "pitch", spec.pitch);
984 } else if(lua_isstring(L, index)){
985 spec.name = lua_tostring(L, index);
989 void push_soundspec(lua_State *L, const SimpleSoundSpec &spec)
992 lua_pushstring(L, spec.name.c_str());
993 lua_setfield(L, -2, "name");
994 lua_pushnumber(L, spec.gain);
995 lua_setfield(L, -2, "gain");
996 lua_pushnumber(L, spec.fade);
997 lua_setfield(L, -2, "fade");
998 lua_pushnumber(L, spec.pitch);
999 lua_setfield(L, -2, "pitch");
1002 /******************************************************************************/
1003 NodeBox read_nodebox(lua_State *L, int index)
1006 if(lua_istable(L, -1)){
1007 nodebox.type = (NodeBoxType)getenumfield(L, index, "type",
1008 ScriptApiNode::es_NodeBoxType, NODEBOX_REGULAR);
1010 #define NODEBOXREAD(n, s){ \
1011 lua_getfield(L, index, (s)); \
1012 if (lua_istable(L, -1)) \
1013 (n) = read_aabb3f(L, -1, BS); \
1017 #define NODEBOXREADVEC(n, s) \
1018 lua_getfield(L, index, (s)); \
1019 if (lua_istable(L, -1)) \
1020 (n) = read_aabb3f_vector(L, -1, BS); \
1023 NODEBOXREADVEC(nodebox.fixed, "fixed");
1024 NODEBOXREAD(nodebox.wall_top, "wall_top");
1025 NODEBOXREAD(nodebox.wall_bottom, "wall_bottom");
1026 NODEBOXREAD(nodebox.wall_side, "wall_side");
1027 NODEBOXREADVEC(nodebox.connect_top, "connect_top");
1028 NODEBOXREADVEC(nodebox.connect_bottom, "connect_bottom");
1029 NODEBOXREADVEC(nodebox.connect_front, "connect_front");
1030 NODEBOXREADVEC(nodebox.connect_left, "connect_left");
1031 NODEBOXREADVEC(nodebox.connect_back, "connect_back");
1032 NODEBOXREADVEC(nodebox.connect_right, "connect_right");
1037 /******************************************************************************/
1038 MapNode readnode(lua_State *L, int index, INodeDefManager *ndef)
1040 lua_getfield(L, index, "name");
1041 if (!lua_isstring(L, -1))
1042 throw LuaError("Node name is not set or is not a string!");
1043 const char *name = lua_tostring(L, -1);
1047 lua_getfield(L, index, "param1");
1048 if (!lua_isnil(L, -1))
1049 param1 = lua_tonumber(L, -1);
1053 lua_getfield(L, index, "param2");
1054 if (!lua_isnil(L, -1))
1055 param2 = lua_tonumber(L, -1);
1058 return {ndef, name, param1, param2};
1061 /******************************************************************************/
1062 void pushnode(lua_State *L, const MapNode &n, INodeDefManager *ndef)
1065 lua_pushstring(L, ndef->get(n).name.c_str());
1066 lua_setfield(L, -2, "name");
1067 lua_pushnumber(L, n.getParam1());
1068 lua_setfield(L, -2, "param1");
1069 lua_pushnumber(L, n.getParam2());
1070 lua_setfield(L, -2, "param2");
1073 /******************************************************************************/
1074 void warn_if_field_exists(lua_State *L, int table,
1075 const char *name, const std::string &message)
1077 lua_getfield(L, table, name);
1078 if (!lua_isnil(L, -1)) {
1079 warningstream << "Field \"" << name << "\": "
1080 << message << std::endl;
1081 infostream << script_get_backtrace(L) << std::endl;
1086 /******************************************************************************/
1087 int getenumfield(lua_State *L, int table,
1088 const char *fieldname, const EnumString *spec, int default_)
1090 int result = default_;
1091 string_to_enum(spec, result,
1092 getstringfield_default(L, table, fieldname, ""));
1096 /******************************************************************************/
1097 bool string_to_enum(const EnumString *spec, int &result,
1098 const std::string &str)
1100 const EnumString *esp = spec;
1102 if(str == std::string(esp->str)){
1111 /******************************************************************************/
1112 ItemStack read_item(lua_State* L, int index, IItemDefManager *idef)
1115 index = lua_gettop(L) + 1 + index;
1117 if (lua_isnil(L, index)) {
1121 if (lua_isuserdata(L, index)) {
1122 // Convert from LuaItemStack
1123 LuaItemStack *o = LuaItemStack::checkobject(L, index);
1124 return o->getItem();
1127 if (lua_isstring(L, index)) {
1128 // Convert from itemstring
1129 std::string itemstring = lua_tostring(L, index);
1133 item.deSerialize(itemstring, idef);
1136 catch(SerializationError &e)
1138 warningstream<<"unable to create item from itemstring"
1139 <<": "<<itemstring<<std::endl;
1143 else if(lua_istable(L, index))
1145 // Convert from table
1146 std::string name = getstringfield_default(L, index, "name", "");
1147 int count = getintfield_default(L, index, "count", 1);
1148 int wear = getintfield_default(L, index, "wear", 0);
1150 ItemStack istack(name, count, wear, idef);
1152 // BACKWARDS COMPATIBLITY
1153 std::string value = getstringfield_default(L, index, "metadata", "");
1154 istack.metadata.setString("", value);
1157 lua_getfield(L, index, "meta");
1158 int fieldstable = lua_gettop(L);
1159 if (lua_istable(L, fieldstable)) {
1161 while (lua_next(L, fieldstable) != 0) {
1162 // key at index -2 and value at index -1
1163 std::string key = lua_tostring(L, -2);
1165 const char *value_cs = lua_tolstring(L, -1, &value_len);
1166 std::string value(value_cs, value_len);
1167 istack.metadata.setString(key, value);
1168 lua_pop(L, 1); // removes value, keeps key for next iteration
1174 throw LuaError("Expecting itemstack, itemstring, table or nil");
1178 /******************************************************************************/
1179 void push_tool_capabilities(lua_State *L,
1180 const ToolCapabilities &toolcap)
1183 setfloatfield(L, -1, "full_punch_interval", toolcap.full_punch_interval);
1184 setintfield(L, -1, "max_drop_level", toolcap.max_drop_level);
1185 // Create groupcaps table
1187 // For each groupcap
1188 for (const auto &gc_it : toolcap.groupcaps) {
1189 // Create groupcap table
1191 const std::string &name = gc_it.first;
1192 const ToolGroupCap &groupcap = gc_it.second;
1193 // Create subtable "times"
1195 for (auto time : groupcap.times) {
1196 lua_pushinteger(L, time.first);
1197 lua_pushnumber(L, time.second);
1198 lua_settable(L, -3);
1200 // Set subtable "times"
1201 lua_setfield(L, -2, "times");
1202 // Set simple parameters
1203 setintfield(L, -1, "maxlevel", groupcap.maxlevel);
1204 setintfield(L, -1, "uses", groupcap.uses);
1205 // Insert groupcap table into groupcaps table
1206 lua_setfield(L, -2, name.c_str());
1208 // Set groupcaps table
1209 lua_setfield(L, -2, "groupcaps");
1210 //Create damage_groups table
1212 // For each damage group
1213 for (const auto &damageGroup : toolcap.damageGroups) {
1214 // Create damage group table
1215 lua_pushinteger(L, damageGroup.second);
1216 lua_setfield(L, -2, damageGroup.first.c_str());
1218 lua_setfield(L, -2, "damage_groups");
1221 /******************************************************************************/
1222 void push_inventory_list(lua_State *L, Inventory *inv, const char *name)
1224 InventoryList *invlist = inv->getList(name);
1225 if(invlist == NULL){
1229 std::vector<ItemStack> items;
1230 for(u32 i=0; i<invlist->getSize(); i++)
1231 items.push_back(invlist->getItem(i));
1232 push_items(L, items);
1235 /******************************************************************************/
1236 void read_inventory_list(lua_State *L, int tableindex,
1237 Inventory *inv, const char *name, Server* srv, int forcesize)
1240 tableindex = lua_gettop(L) + 1 + tableindex;
1241 // If nil, delete list
1242 if(lua_isnil(L, tableindex)){
1243 inv->deleteList(name);
1246 // Otherwise set list
1247 std::vector<ItemStack> items = read_items(L, tableindex,srv);
1248 int listsize = (forcesize != -1) ? forcesize : items.size();
1249 InventoryList *invlist = inv->addList(name, listsize);
1251 for(std::vector<ItemStack>::const_iterator
1252 i = items.begin(); i != items.end(); ++i){
1253 if(forcesize != -1 && index == forcesize)
1255 invlist->changeItem(index, *i);
1258 while(forcesize != -1 && index < forcesize){
1259 invlist->deleteItem(index);
1264 /******************************************************************************/
1265 struct TileAnimationParams read_animation_definition(lua_State *L, int index)
1268 index = lua_gettop(L) + 1 + index;
1270 struct TileAnimationParams anim;
1271 anim.type = TAT_NONE;
1272 if (!lua_istable(L, index))
1275 anim.type = (TileAnimationType)
1276 getenumfield(L, index, "type", es_TileAnimationType,
1278 if (anim.type == TAT_VERTICAL_FRAMES) {
1279 // {type="vertical_frames", aspect_w=16, aspect_h=16, length=2.0}
1280 anim.vertical_frames.aspect_w =
1281 getintfield_default(L, index, "aspect_w", 16);
1282 anim.vertical_frames.aspect_h =
1283 getintfield_default(L, index, "aspect_h", 16);
1284 anim.vertical_frames.length =
1285 getfloatfield_default(L, index, "length", 1.0);
1286 } else if (anim.type == TAT_SHEET_2D) {
1287 // {type="sheet_2d", frames_w=5, frames_h=3, frame_length=0.5}
1288 getintfield(L, index, "frames_w",
1289 anim.sheet_2d.frames_w);
1290 getintfield(L, index, "frames_h",
1291 anim.sheet_2d.frames_h);
1292 getfloatfield(L, index, "frame_length",
1293 anim.sheet_2d.frame_length);
1299 /******************************************************************************/
1300 ToolCapabilities read_tool_capabilities(
1301 lua_State *L, int table)
1303 ToolCapabilities toolcap;
1304 getfloatfield(L, table, "full_punch_interval", toolcap.full_punch_interval);
1305 getintfield(L, table, "max_drop_level", toolcap.max_drop_level);
1306 lua_getfield(L, table, "groupcaps");
1307 if(lua_istable(L, -1)){
1308 int table_groupcaps = lua_gettop(L);
1310 while(lua_next(L, table_groupcaps) != 0){
1311 // key at index -2 and value at index -1
1312 std::string groupname = luaL_checkstring(L, -2);
1313 if(lua_istable(L, -1)){
1314 int table_groupcap = lua_gettop(L);
1315 // This will be created
1316 ToolGroupCap groupcap;
1317 // Read simple parameters
1318 getintfield(L, table_groupcap, "maxlevel", groupcap.maxlevel);
1319 getintfield(L, table_groupcap, "uses", groupcap.uses);
1320 // DEPRECATED: maxwear
1322 if (getfloatfield(L, table_groupcap, "maxwear", maxwear)){
1324 groupcap.uses = 1.0/maxwear;
1327 warningstream << "Field \"maxwear\" is deprecated; "
1328 << "replace with uses=1/maxwear" << std::endl;
1329 infostream << script_get_backtrace(L) << std::endl;
1331 // Read "times" table
1332 lua_getfield(L, table_groupcap, "times");
1333 if(lua_istable(L, -1)){
1334 int table_times = lua_gettop(L);
1336 while(lua_next(L, table_times) != 0){
1337 // key at index -2 and value at index -1
1338 int rating = luaL_checkinteger(L, -2);
1339 float time = luaL_checknumber(L, -1);
1340 groupcap.times[rating] = time;
1341 // removes value, keeps key for next iteration
1346 // Insert groupcap into toolcap
1347 toolcap.groupcaps[groupname] = groupcap;
1349 // removes value, keeps key for next iteration
1355 lua_getfield(L, table, "damage_groups");
1356 if(lua_istable(L, -1)){
1357 int table_damage_groups = lua_gettop(L);
1359 while(lua_next(L, table_damage_groups) != 0){
1360 // key at index -2 and value at index -1
1361 std::string groupname = luaL_checkstring(L, -2);
1362 u16 value = luaL_checkinteger(L, -1);
1363 toolcap.damageGroups[groupname] = value;
1364 // removes value, keeps key for next iteration
1372 /******************************************************************************/
1373 void push_dig_params(lua_State *L,const DigParams ¶ms)
1376 setboolfield(L, -1, "diggable", params.diggable);
1377 setfloatfield(L, -1, "time", params.time);
1378 setintfield(L, -1, "wear", params.wear);
1381 /******************************************************************************/
1382 void push_hit_params(lua_State *L,const HitParams ¶ms)
1385 setintfield(L, -1, "hp", params.hp);
1386 setintfield(L, -1, "wear", params.wear);
1389 /******************************************************************************/
1391 bool getflagsfield(lua_State *L, int table, const char *fieldname,
1392 FlagDesc *flagdesc, u32 *flags, u32 *flagmask)
1394 lua_getfield(L, table, fieldname);
1396 bool success = read_flags(L, -1, flagdesc, flags, flagmask);
1403 bool read_flags(lua_State *L, int index, FlagDesc *flagdesc,
1404 u32 *flags, u32 *flagmask)
1406 if (lua_isstring(L, index)) {
1407 std::string flagstr = lua_tostring(L, index);
1408 *flags = readFlagString(flagstr, flagdesc, flagmask);
1409 } else if (lua_istable(L, index)) {
1410 *flags = read_flags_table(L, index, flagdesc, flagmask);
1418 u32 read_flags_table(lua_State *L, int table, FlagDesc *flagdesc, u32 *flagmask)
1420 u32 flags = 0, mask = 0;
1421 char fnamebuf[64] = "no";
1423 for (int i = 0; flagdesc[i].name; i++) {
1426 if (getboolfield(L, table, flagdesc[i].name, result)) {
1427 mask |= flagdesc[i].flag;
1429 flags |= flagdesc[i].flag;
1432 strlcpy(fnamebuf + 2, flagdesc[i].name, sizeof(fnamebuf) - 2);
1433 if (getboolfield(L, table, fnamebuf, result))
1434 mask |= flagdesc[i].flag;
1443 void push_flags_string(lua_State *L, FlagDesc *flagdesc, u32 flags, u32 flagmask)
1445 std::string flagstring = writeFlagString(flags, flagdesc, flagmask);
1446 lua_pushlstring(L, flagstring.c_str(), flagstring.size());
1449 /******************************************************************************/
1450 /* Lua Stored data! */
1451 /******************************************************************************/
1453 /******************************************************************************/
1454 void read_groups(lua_State *L, int index, ItemGroupList &result)
1456 if (!lua_istable(L,index))
1462 while(lua_next(L, index) != 0){
1463 // key at index -2 and value at index -1
1464 std::string name = luaL_checkstring(L, -2);
1465 int rating = luaL_checkinteger(L, -1);
1466 result[name] = rating;
1467 // removes value, keeps key for next iteration
1472 /******************************************************************************/
1473 void push_groups(lua_State *L, const ItemGroupList &groups)
1476 for (const auto &group : groups) {
1477 lua_pushnumber(L, group.second);
1478 lua_setfield(L, -2, group.first.c_str());
1482 /******************************************************************************/
1483 void push_items(lua_State *L, const std::vector<ItemStack> &items)
1485 lua_createtable(L, items.size(), 0);
1486 for (u32 i = 0; i != items.size(); i++) {
1487 LuaItemStack::create(L, items[i]);
1488 lua_rawseti(L, -2, i + 1);
1492 /******************************************************************************/
1493 std::vector<ItemStack> read_items(lua_State *L, int index, Server *srv)
1496 index = lua_gettop(L) + 1 + index;
1498 std::vector<ItemStack> items;
1499 luaL_checktype(L, index, LUA_TTABLE);
1501 while (lua_next(L, index)) {
1502 s32 key = luaL_checkinteger(L, -2);
1504 throw LuaError("Invalid inventory list index");
1506 if (items.size() < (u32) key) {
1509 items[key - 1] = read_item(L, -1, srv->idef());
1515 /******************************************************************************/
1516 void luaentity_get(lua_State *L, u16 id)
1518 // Get luaentities[i]
1519 lua_getglobal(L, "core");
1520 lua_getfield(L, -1, "luaentities");
1521 luaL_checktype(L, -1, LUA_TTABLE);
1522 lua_pushnumber(L, id);
1523 lua_gettable(L, -2);
1524 lua_remove(L, -2); // Remove luaentities
1525 lua_remove(L, -2); // Remove core
1528 /******************************************************************************/
1529 bool read_noiseparams(lua_State *L, int index, NoiseParams *np)
1532 index = lua_gettop(L) + 1 + index;
1534 if (!lua_istable(L, index))
1537 getfloatfield(L, index, "offset", np->offset);
1538 getfloatfield(L, index, "scale", np->scale);
1539 getfloatfield(L, index, "persist", np->persist);
1540 getfloatfield(L, index, "persistence", np->persist);
1541 getfloatfield(L, index, "lacunarity", np->lacunarity);
1542 getintfield(L, index, "seed", np->seed);
1543 getintfield(L, index, "octaves", np->octaves);
1547 np->flags = getflagsfield(L, index, "flags", flagdesc_noiseparams,
1548 &flags, &flagmask) ? flags : NOISE_FLAG_DEFAULTS;
1550 lua_getfield(L, index, "spread");
1551 np->spread = read_v3f(L, -1);
1557 void push_noiseparams(lua_State *L, NoiseParams *np)
1560 lua_pushnumber(L, np->offset);
1561 lua_setfield(L, -2, "offset");
1562 lua_pushnumber(L, np->scale);
1563 lua_setfield(L, -2, "scale");
1564 lua_pushnumber(L, np->persist);
1565 lua_setfield(L, -2, "persistence");
1566 lua_pushnumber(L, np->lacunarity);
1567 lua_setfield(L, -2, "lacunarity");
1568 lua_pushnumber(L, np->seed);
1569 lua_setfield(L, -2, "seed");
1570 lua_pushnumber(L, np->octaves);
1571 lua_setfield(L, -2, "octaves");
1573 push_flags_string(L, flagdesc_noiseparams, np->flags,
1575 lua_setfield(L, -2, "flags");
1577 push_v3f(L, np->spread);
1578 lua_setfield(L, -2, "spread");
1581 /******************************************************************************/
1582 // Returns depth of json value tree
1583 static int push_json_value_getdepth(const Json::Value &value)
1585 if (!value.isArray() && !value.isObject())
1589 for (const auto &it : value) {
1590 int elemdepth = push_json_value_getdepth(it);
1591 if (elemdepth > maxdepth)
1592 maxdepth = elemdepth;
1594 return maxdepth + 1;
1596 // Recursive function to convert JSON --> Lua table
1597 static bool push_json_value_helper(lua_State *L, const Json::Value &value,
1600 switch(value.type()) {
1601 case Json::nullValue:
1603 lua_pushvalue(L, nullindex);
1605 case Json::intValue:
1606 lua_pushinteger(L, value.asInt());
1608 case Json::uintValue:
1609 lua_pushinteger(L, value.asUInt());
1611 case Json::realValue:
1612 lua_pushnumber(L, value.asDouble());
1614 case Json::stringValue:
1616 const char *str = value.asCString();
1617 lua_pushstring(L, str ? str : "");
1620 case Json::booleanValue:
1621 lua_pushboolean(L, value.asInt());
1623 case Json::arrayValue:
1625 for (Json::Value::const_iterator it = value.begin();
1626 it != value.end(); ++it) {
1627 push_json_value_helper(L, *it, nullindex);
1628 lua_rawseti(L, -2, it.index() + 1);
1631 case Json::objectValue:
1633 for (Json::Value::const_iterator it = value.begin();
1634 it != value.end(); ++it) {
1635 #ifndef JSONCPP_STRING
1636 const char *str = it.memberName();
1637 lua_pushstring(L, str ? str : "");
1639 std::string str = it.name();
1640 lua_pushstring(L, str.c_str());
1642 push_json_value_helper(L, *it, nullindex);
1649 // converts JSON --> Lua table; returns false if lua stack limit exceeded
1650 // nullindex: Lua stack index of value to use in place of JSON null
1651 bool push_json_value(lua_State *L, const Json::Value &value, int nullindex)
1654 nullindex = lua_gettop(L) + 1 + nullindex;
1656 int depth = push_json_value_getdepth(value);
1658 // The maximum number of Lua stack slots used at each recursion level
1659 // of push_json_value_helper is 2, so make sure there a depth * 2 slots
1660 if (lua_checkstack(L, depth * 2))
1661 return push_json_value_helper(L, value, nullindex);
1666 // Converts Lua table --> JSON
1667 void read_json_value(lua_State *L, Json::Value &root, int index, u8 recursion)
1669 if (recursion > 16) {
1670 throw SerializationError("Maximum recursion depth exceeded");
1672 int type = lua_type(L, index);
1673 if (type == LUA_TBOOLEAN) {
1674 root = (bool) lua_toboolean(L, index);
1675 } else if (type == LUA_TNUMBER) {
1676 root = lua_tonumber(L, index);
1677 } else if (type == LUA_TSTRING) {
1679 const char *str = lua_tolstring(L, index, &len);
1680 root = std::string(str, len);
1681 } else if (type == LUA_TTABLE) {
1683 while (lua_next(L, index)) {
1684 // Key is at -2 and value is at -1
1686 read_json_value(L, value, lua_gettop(L), recursion + 1);
1688 Json::ValueType roottype = root.type();
1689 int keytype = lua_type(L, -1);
1690 if (keytype == LUA_TNUMBER) {
1691 lua_Number key = lua_tonumber(L, -1);
1692 if (roottype != Json::nullValue && roottype != Json::arrayValue) {
1693 throw SerializationError("Can't mix array and object values in JSON");
1694 } else if (key < 1) {
1695 throw SerializationError("Can't use zero-based or negative indexes in JSON");
1696 } else if (floor(key) != key) {
1697 throw SerializationError("Can't use indexes with a fractional part in JSON");
1699 root[(Json::ArrayIndex) key - 1] = value;
1700 } else if (keytype == LUA_TSTRING) {
1701 if (roottype != Json::nullValue && roottype != Json::objectValue) {
1702 throw SerializationError("Can't mix array and object values in JSON");
1704 root[lua_tostring(L, -1)] = value;
1706 throw SerializationError("Lua key to convert to JSON is not a string or number");
1709 } else if (type == LUA_TNIL) {
1710 root = Json::nullValue;
1712 throw SerializationError("Can only store booleans, numbers, strings, objects, arrays, and null in JSON");
1714 lua_pop(L, 1); // Pop value
1717 void push_pointed_thing(lua_State *L, const PointedThing &pointed, bool csm)
1720 if (pointed.type == POINTEDTHING_NODE) {
1721 lua_pushstring(L, "node");
1722 lua_setfield(L, -2, "type");
1723 push_v3s16(L, pointed.node_undersurface);
1724 lua_setfield(L, -2, "under");
1725 push_v3s16(L, pointed.node_abovesurface);
1726 lua_setfield(L, -2, "above");
1727 } else if (pointed.type == POINTEDTHING_OBJECT) {
1728 lua_pushstring(L, "object");
1729 lua_setfield(L, -2, "type");
1732 lua_pushinteger(L, pointed.object_id);
1733 lua_setfield(L, -2, "id");
1735 push_objectRef(L, pointed.object_id);
1736 lua_setfield(L, -2, "ref");
1739 lua_pushstring(L, "nothing");
1740 lua_setfield(L, -2, "type");
1744 void push_objectRef(lua_State *L, const u16 id)
1746 // Get core.object_refs[i]
1747 lua_getglobal(L, "core");
1748 lua_getfield(L, -1, "object_refs");
1749 luaL_checktype(L, -1, LUA_TTABLE);
1750 lua_pushnumber(L, id);
1751 lua_gettable(L, -2);
1752 lua_remove(L, -2); // object_refs
1753 lua_remove(L, -2); // core