]> git.lizzy.rs Git - minetest.git/blob - src/script/common/c_content.cpp
6203ea78c04005509431f780d0631eda05b89f52
[minetest.git] / src / script / common / c_content.cpp
1 /*
2 Minetest
3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 #include "common/c_content.h"
20 #include "common/c_converter.h"
21 #include "common/c_types.h"
22 #include "nodedef.h"
23 #include "object_properties.h"
24 #include "collision.h"
25 #include "cpp_api/s_node.h"
26 #include "lua_api/l_object.h"
27 #include "lua_api/l_item.h"
28 #include "common/c_internal.h"
29 #include "server.h"
30 #include "log.h"
31 #include "tool.h"
32 #include "porting.h"
33 #include "mapgen/mg_schematic.h"
34 #include "noise.h"
35 #include "server/player_sao.h"
36 #include "util/pointedthing.h"
37 #include "debug.h" // For FATAL_ERROR
38 #include <json/json.h>
39
40 struct EnumString es_TileAnimationType[] =
41 {
42         {TAT_NONE, "none"},
43         {TAT_VERTICAL_FRAMES, "vertical_frames"},
44         {TAT_SHEET_2D, "sheet_2d"},
45         {0, nullptr},
46 };
47
48 /******************************************************************************/
49 void read_item_definition(lua_State* L, int index,
50                 const ItemDefinition &default_def, ItemDefinition &def)
51 {
52         if (index < 0)
53                 index = lua_gettop(L) + 1 + index;
54
55         def.type = (ItemType)getenumfield(L, index, "type",
56                         es_ItemType, ITEM_NONE);
57         getstringfield(L, index, "name", def.name);
58         getstringfield(L, index, "description", def.description);
59         getstringfield(L, index, "short_description", def.short_description);
60         getstringfield(L, index, "inventory_image", def.inventory_image);
61         getstringfield(L, index, "inventory_overlay", def.inventory_overlay);
62         getstringfield(L, index, "wield_image", def.wield_image);
63         getstringfield(L, index, "wield_overlay", def.wield_overlay);
64         getstringfield(L, index, "palette", def.palette_image);
65
66         // Read item color.
67         lua_getfield(L, index, "color");
68         read_color(L, -1, &def.color);
69         lua_pop(L, 1);
70
71         lua_getfield(L, index, "wield_scale");
72         if(lua_istable(L, -1)){
73                 def.wield_scale = check_v3f(L, -1);
74         }
75         lua_pop(L, 1);
76
77         int stack_max = getintfield_default(L, index, "stack_max", def.stack_max);
78         def.stack_max = rangelim(stack_max, 1, U16_MAX);
79
80         lua_getfield(L, index, "on_use");
81         def.usable = lua_isfunction(L, -1);
82         lua_pop(L, 1);
83
84         getboolfield(L, index, "liquids_pointable", def.liquids_pointable);
85
86         lua_getfield(L, index, "tool_capabilities");
87         if(lua_istable(L, -1)){
88                 def.tool_capabilities = new ToolCapabilities(
89                                 read_tool_capabilities(L, -1));
90         }
91
92         // If name is "" (hand), ensure there are ToolCapabilities
93         // because it will be looked up there whenever any other item has
94         // no ToolCapabilities
95         if (def.name.empty() && def.tool_capabilities == NULL){
96                 def.tool_capabilities = new ToolCapabilities();
97         }
98
99         lua_getfield(L, index, "groups");
100         read_groups(L, -1, def.groups);
101         lua_pop(L, 1);
102
103         lua_getfield(L, index, "sounds");
104         if (!lua_isnil(L, -1)) {
105                 luaL_checktype(L, -1, LUA_TTABLE);
106                 lua_getfield(L, -1, "place");
107                 read_soundspec(L, -1, def.sound_place);
108                 lua_pop(L, 1);
109                 lua_getfield(L, -1, "place_failed");
110                 read_soundspec(L, -1, def.sound_place_failed);
111                 lua_pop(L, 1);
112         }
113         lua_pop(L, 1);
114
115         // No, this is not a mistake. Item sounds are in "sound", node sounds in "sounds".
116         lua_getfield(L, index, "sound");
117         if (!lua_isnil(L, -1)) {
118                 luaL_checktype(L, -1, LUA_TTABLE);
119                 lua_getfield(L, -1, "punch_use");
120                 read_soundspec(L, -1, def.sound_use);
121                 lua_pop(L, 1);
122                 lua_getfield(L, -1, "punch_use_air");
123                 read_soundspec(L, -1, def.sound_use_air);
124                 lua_pop(L, 1);
125         }
126         lua_pop(L, 1);
127
128         def.range = getfloatfield_default(L, index, "range", def.range);
129
130         // Client shall immediately place this node when player places the item.
131         // Server will update the precise end result a moment later.
132         // "" = no prediction
133         getstringfield(L, index, "node_placement_prediction",
134                         def.node_placement_prediction);
135
136         getintfield(L, index, "place_param2", def.place_param2);
137 }
138
139 /******************************************************************************/
140 void push_item_definition(lua_State *L, const ItemDefinition &i)
141 {
142         lua_newtable(L);
143         lua_pushstring(L, i.name.c_str());
144         lua_setfield(L, -2, "name");
145         lua_pushstring(L, i.description.c_str());
146         lua_setfield(L, -2, "description");
147 }
148
149 void push_item_definition_full(lua_State *L, const ItemDefinition &i)
150 {
151         std::string type(es_ItemType[(int)i.type].str);
152
153         lua_newtable(L);
154         lua_pushstring(L, i.name.c_str());
155         lua_setfield(L, -2, "name");
156         lua_pushstring(L, i.description.c_str());
157         lua_setfield(L, -2, "description");
158         if (!i.short_description.empty()) {
159                 lua_pushstring(L, i.short_description.c_str());
160                 lua_setfield(L, -2, "short_description");
161         }
162         lua_pushstring(L, type.c_str());
163         lua_setfield(L, -2, "type");
164         lua_pushstring(L, i.inventory_image.c_str());
165         lua_setfield(L, -2, "inventory_image");
166         lua_pushstring(L, i.inventory_overlay.c_str());
167         lua_setfield(L, -2, "inventory_overlay");
168         lua_pushstring(L, i.wield_image.c_str());
169         lua_setfield(L, -2, "wield_image");
170         lua_pushstring(L, i.wield_overlay.c_str());
171         lua_setfield(L, -2, "wield_overlay");
172         lua_pushstring(L, i.palette_image.c_str());
173         lua_setfield(L, -2, "palette_image");
174         push_ARGB8(L, i.color);
175         lua_setfield(L, -2, "color");
176         push_v3f(L, i.wield_scale);
177         lua_setfield(L, -2, "wield_scale");
178         lua_pushinteger(L, i.stack_max);
179         lua_setfield(L, -2, "stack_max");
180         lua_pushboolean(L, i.usable);
181         lua_setfield(L, -2, "usable");
182         lua_pushboolean(L, i.liquids_pointable);
183         lua_setfield(L, -2, "liquids_pointable");
184         if (i.tool_capabilities) {
185                 push_tool_capabilities(L, *i.tool_capabilities);
186                 lua_setfield(L, -2, "tool_capabilities");
187         }
188         push_groups(L, i.groups);
189         lua_setfield(L, -2, "groups");
190         push_soundspec(L, i.sound_place);
191         lua_setfield(L, -2, "sound_place");
192         push_soundspec(L, i.sound_place_failed);
193         lua_setfield(L, -2, "sound_place_failed");
194         lua_pushstring(L, i.node_placement_prediction.c_str());
195         lua_setfield(L, -2, "node_placement_prediction");
196 }
197
198 /******************************************************************************/
199 void read_object_properties(lua_State *L, int index,
200                 ServerActiveObject *sao, ObjectProperties *prop, IItemDefManager *idef)
201 {
202         if(index < 0)
203                 index = lua_gettop(L) + 1 + index;
204         if (lua_isnil(L, index))
205                 return;
206
207         luaL_checktype(L, -1, LUA_TTABLE);
208
209         int hp_max = 0;
210         if (getintfield(L, -1, "hp_max", hp_max)) {
211                 prop->hp_max = (u16)rangelim(hp_max, 0, U16_MAX);
212                 // hp_max = 0 is sometimes used as a hack to keep players dead, only validate for entities
213                 if (prop->hp_max == 0 && sao->getType() != ACTIVEOBJECT_TYPE_PLAYER)
214                         throw LuaError("The hp_max property may not be 0 for entities!");
215
216                 if (prop->hp_max < sao->getHP()) {
217                         PlayerHPChangeReason reason(PlayerHPChangeReason::SET_HP_MAX);
218                         sao->setHP(prop->hp_max, reason);
219                 }
220         }
221
222         if (getintfield(L, -1, "breath_max", prop->breath_max)) {
223                 if (sao->getType() == ACTIVEOBJECT_TYPE_PLAYER) {
224                         PlayerSAO *player = (PlayerSAO *)sao;
225                         if (prop->breath_max < player->getBreath())
226                                 player->setBreath(prop->breath_max);
227                 }
228         }
229         getboolfield(L, -1, "physical", prop->physical);
230         getboolfield(L, -1, "collide_with_objects", prop->collideWithObjects);
231
232         lua_getfield(L, -1, "collisionbox");
233         bool collisionbox_defined = lua_istable(L, -1);
234         if (collisionbox_defined)
235                 prop->collisionbox = read_aabb3f(L, -1, 1.0);
236         lua_pop(L, 1);
237
238         lua_getfield(L, -1, "selectionbox");
239         if (lua_istable(L, -1)) {
240                 getboolfield(L, -1, "rotate", prop->rotate_selectionbox);
241                 prop->selectionbox = read_aabb3f(L, -1, 1.0);
242         } else if (collisionbox_defined) {
243                 prop->selectionbox = prop->collisionbox;
244         }
245         lua_pop(L, 1);
246
247         getboolfield(L, -1, "pointable", prop->pointable);
248         getstringfield(L, -1, "visual", prop->visual);
249
250         getstringfield(L, -1, "mesh", prop->mesh);
251
252         lua_getfield(L, -1, "visual_size");
253         if (lua_istable(L, -1)) {
254                 // Backwards compatibility: Also accept { x = ?, y = ? }
255                 v2f scale_xy = read_v2f(L, -1);
256
257                 f32 scale_z = scale_xy.X;
258                 lua_getfield(L, -1, "z");
259                 if (lua_isnumber(L, -1))
260                         scale_z = lua_tonumber(L, -1);
261                 lua_pop(L, 1);
262
263                 prop->visual_size = v3f(scale_xy.X, scale_xy.Y, scale_z);
264         }
265         lua_pop(L, 1);
266
267         lua_getfield(L, -1, "textures");
268         if(lua_istable(L, -1)){
269                 prop->textures.clear();
270                 int table = lua_gettop(L);
271                 lua_pushnil(L);
272                 while(lua_next(L, table) != 0){
273                         // key at index -2 and value at index -1
274                         if(lua_isstring(L, -1))
275                                 prop->textures.emplace_back(lua_tostring(L, -1));
276                         else
277                                 prop->textures.emplace_back("");
278                         // removes value, keeps key for next iteration
279                         lua_pop(L, 1);
280                 }
281         }
282         lua_pop(L, 1);
283
284         lua_getfield(L, -1, "colors");
285         if (lua_istable(L, -1)) {
286                 int table = lua_gettop(L);
287                 prop->colors.clear();
288                 for (lua_pushnil(L); lua_next(L, table); lua_pop(L, 1)) {
289                         video::SColor color(255, 255, 255, 255);
290                         read_color(L, -1, &color);
291                         prop->colors.push_back(color);
292                 }
293         }
294         lua_pop(L, 1);
295
296         lua_getfield(L, -1, "spritediv");
297         if(lua_istable(L, -1))
298                 prop->spritediv = read_v2s16(L, -1);
299         lua_pop(L, 1);
300
301         lua_getfield(L, -1, "initial_sprite_basepos");
302         if(lua_istable(L, -1))
303                 prop->initial_sprite_basepos = read_v2s16(L, -1);
304         lua_pop(L, 1);
305
306         getboolfield(L, -1, "is_visible", prop->is_visible);
307         getboolfield(L, -1, "makes_footstep_sound", prop->makes_footstep_sound);
308         if (getfloatfield(L, -1, "stepheight", prop->stepheight))
309                 prop->stepheight *= BS;
310         getfloatfield(L, -1, "eye_height", prop->eye_height);
311
312         getfloatfield(L, -1, "automatic_rotate", prop->automatic_rotate);
313         lua_getfield(L, -1, "automatic_face_movement_dir");
314         if (lua_isnumber(L, -1)) {
315                 prop->automatic_face_movement_dir = true;
316                 prop->automatic_face_movement_dir_offset = luaL_checknumber(L, -1);
317         } else if (lua_isboolean(L, -1)) {
318                 prop->automatic_face_movement_dir = lua_toboolean(L, -1);
319                 prop->automatic_face_movement_dir_offset = 0.0;
320         }
321         lua_pop(L, 1);
322         getboolfield(L, -1, "backface_culling", prop->backface_culling);
323         getintfield(L, -1, "glow", prop->glow);
324
325         getstringfield(L, -1, "nametag", prop->nametag);
326         lua_getfield(L, -1, "nametag_color");
327         if (!lua_isnil(L, -1)) {
328                 video::SColor color = prop->nametag_color;
329                 if (read_color(L, -1, &color))
330                         prop->nametag_color = color;
331         }
332         lua_pop(L, 1);
333         lua_getfield(L, -1, "nametag_bgcolor");
334         if (!lua_isnil(L, -1)) {
335                 if (lua_toboolean(L, -1)) {
336                         video::SColor color;
337                         if (read_color(L, -1, &color))
338                                 prop->nametag_bgcolor = color;
339                 } else {
340                         prop->nametag_bgcolor = nullopt;
341                 }
342         }
343         lua_pop(L, 1);
344
345         lua_getfield(L, -1, "automatic_face_movement_max_rotation_per_sec");
346         if (lua_isnumber(L, -1)) {
347                 prop->automatic_face_movement_max_rotation_per_sec = luaL_checknumber(L, -1);
348         }
349         lua_pop(L, 1);
350
351         getstringfield(L, -1, "infotext", prop->infotext);
352         getboolfield(L, -1, "static_save", prop->static_save);
353
354         lua_getfield(L, -1, "wield_item");
355         if (!lua_isnil(L, -1))
356                 prop->wield_item = read_item(L, -1, idef).getItemString();
357         lua_pop(L, 1);
358
359         getfloatfield(L, -1, "zoom_fov", prop->zoom_fov);
360         getboolfield(L, -1, "use_texture_alpha", prop->use_texture_alpha);
361         getboolfield(L, -1, "shaded", prop->shaded);
362         getboolfield(L, -1, "show_on_minimap", prop->show_on_minimap);
363
364         getstringfield(L, -1, "damage_texture_modifier", prop->damage_texture_modifier);
365 }
366
367 /******************************************************************************/
368 void push_object_properties(lua_State *L, ObjectProperties *prop)
369 {
370         lua_newtable(L);
371         lua_pushnumber(L, prop->hp_max);
372         lua_setfield(L, -2, "hp_max");
373         lua_pushnumber(L, prop->breath_max);
374         lua_setfield(L, -2, "breath_max");
375         lua_pushboolean(L, prop->physical);
376         lua_setfield(L, -2, "physical");
377         lua_pushboolean(L, prop->collideWithObjects);
378         lua_setfield(L, -2, "collide_with_objects");
379         push_aabb3f(L, prop->collisionbox);
380         lua_setfield(L, -2, "collisionbox");
381         push_aabb3f(L, prop->selectionbox);
382         lua_pushboolean(L, prop->rotate_selectionbox);
383         lua_setfield(L, -2, "rotate");
384         lua_setfield(L, -2, "selectionbox");
385         lua_pushboolean(L, prop->pointable);
386         lua_setfield(L, -2, "pointable");
387         lua_pushlstring(L, prop->visual.c_str(), prop->visual.size());
388         lua_setfield(L, -2, "visual");
389         lua_pushlstring(L, prop->mesh.c_str(), prop->mesh.size());
390         lua_setfield(L, -2, "mesh");
391         push_v3f(L, prop->visual_size);
392         lua_setfield(L, -2, "visual_size");
393
394         lua_createtable(L, prop->textures.size(), 0);
395         u16 i = 1;
396         for (const std::string &texture : prop->textures) {
397                 lua_pushlstring(L, texture.c_str(), texture.size());
398                 lua_rawseti(L, -2, i++);
399         }
400         lua_setfield(L, -2, "textures");
401
402         lua_createtable(L, prop->colors.size(), 0);
403         i = 1;
404         for (const video::SColor &color : prop->colors) {
405                 push_ARGB8(L, color);
406                 lua_rawseti(L, -2, i++);
407         }
408         lua_setfield(L, -2, "colors");
409
410         push_v2s16(L, prop->spritediv);
411         lua_setfield(L, -2, "spritediv");
412         push_v2s16(L, prop->initial_sprite_basepos);
413         lua_setfield(L, -2, "initial_sprite_basepos");
414         lua_pushboolean(L, prop->is_visible);
415         lua_setfield(L, -2, "is_visible");
416         lua_pushboolean(L, prop->makes_footstep_sound);
417         lua_setfield(L, -2, "makes_footstep_sound");
418         lua_pushnumber(L, prop->stepheight / BS);
419         lua_setfield(L, -2, "stepheight");
420         lua_pushnumber(L, prop->eye_height);
421         lua_setfield(L, -2, "eye_height");
422         lua_pushnumber(L, prop->automatic_rotate);
423         lua_setfield(L, -2, "automatic_rotate");
424         if (prop->automatic_face_movement_dir)
425                 lua_pushnumber(L, prop->automatic_face_movement_dir_offset);
426         else
427                 lua_pushboolean(L, false);
428         lua_setfield(L, -2, "automatic_face_movement_dir");
429         lua_pushboolean(L, prop->backface_culling);
430         lua_setfield(L, -2, "backface_culling");
431         lua_pushnumber(L, prop->glow);
432         lua_setfield(L, -2, "glow");
433         lua_pushlstring(L, prop->nametag.c_str(), prop->nametag.size());
434         lua_setfield(L, -2, "nametag");
435         push_ARGB8(L, prop->nametag_color);
436         lua_setfield(L, -2, "nametag_color");
437         if (prop->nametag_bgcolor) {
438                 push_ARGB8(L, prop->nametag_bgcolor.value());
439                 lua_setfield(L, -2, "nametag_bgcolor");
440         } else {
441                 lua_pushboolean(L, false);
442                 lua_setfield(L, -2, "nametag_bgcolor");
443         }
444         lua_pushnumber(L, prop->automatic_face_movement_max_rotation_per_sec);
445         lua_setfield(L, -2, "automatic_face_movement_max_rotation_per_sec");
446         lua_pushlstring(L, prop->infotext.c_str(), prop->infotext.size());
447         lua_setfield(L, -2, "infotext");
448         lua_pushboolean(L, prop->static_save);
449         lua_setfield(L, -2, "static_save");
450         lua_pushlstring(L, prop->wield_item.c_str(), prop->wield_item.size());
451         lua_setfield(L, -2, "wield_item");
452         lua_pushnumber(L, prop->zoom_fov);
453         lua_setfield(L, -2, "zoom_fov");
454         lua_pushboolean(L, prop->use_texture_alpha);
455         lua_setfield(L, -2, "use_texture_alpha");
456         lua_pushboolean(L, prop->shaded);
457         lua_setfield(L, -2, "shaded");
458         lua_pushlstring(L, prop->damage_texture_modifier.c_str(), prop->damage_texture_modifier.size());
459         lua_setfield(L, -2, "damage_texture_modifier");
460         lua_pushboolean(L, prop->show_on_minimap);
461         lua_setfield(L, -2, "show_on_minimap");
462 }
463
464 /******************************************************************************/
465 TileDef read_tiledef(lua_State *L, int index, u8 drawtype)
466 {
467         if(index < 0)
468                 index = lua_gettop(L) + 1 + index;
469
470         TileDef tiledef;
471
472         bool default_tiling = true;
473         bool default_culling = true;
474         switch (drawtype) {
475                 case NDT_PLANTLIKE:
476                 case NDT_PLANTLIKE_ROOTED:
477                 case NDT_FIRELIKE:
478                         default_tiling = false;
479                         // "break" is omitted here intentionaly, as PLANTLIKE
480                         // FIRELIKE drawtype both should default to having
481                         // backface_culling to false.
482                 case NDT_MESH:
483                 case NDT_LIQUID:
484                         default_culling = false;
485                         break;
486                 default:
487                         break;
488         }
489
490         // key at index -2 and value at index
491         if(lua_isstring(L, index)){
492                 // "default_lava.png"
493                 tiledef.name = lua_tostring(L, index);
494                 tiledef.tileable_vertical = default_tiling;
495                 tiledef.tileable_horizontal = default_tiling;
496                 tiledef.backface_culling = default_culling;
497         }
498         else if(lua_istable(L, index))
499         {
500                 // name="default_lava.png"
501                 tiledef.name.clear();
502                 getstringfield(L, index, "name", tiledef.name);
503                 getstringfield(L, index, "image", tiledef.name); // MaterialSpec compat.
504                 tiledef.backface_culling = getboolfield_default(
505                         L, index, "backface_culling", default_culling);
506                 tiledef.tileable_horizontal = getboolfield_default(
507                         L, index, "tileable_horizontal", default_tiling);
508                 tiledef.tileable_vertical = getboolfield_default(
509                         L, index, "tileable_vertical", default_tiling);
510                 std::string align_style;
511                 if (getstringfield(L, index, "align_style", align_style)) {
512                         if (align_style == "user")
513                                 tiledef.align_style = ALIGN_STYLE_USER_DEFINED;
514                         else if (align_style == "world")
515                                 tiledef.align_style = ALIGN_STYLE_WORLD;
516                         else
517                                 tiledef.align_style = ALIGN_STYLE_NODE;
518                 }
519                 tiledef.scale = getintfield_default(L, index, "scale", 0);
520                 // color = ...
521                 lua_getfield(L, index, "color");
522                 tiledef.has_color = read_color(L, -1, &tiledef.color);
523                 lua_pop(L, 1);
524                 // animation = {}
525                 lua_getfield(L, index, "animation");
526                 tiledef.animation = read_animation_definition(L, -1);
527                 lua_pop(L, 1);
528         }
529
530         return tiledef;
531 }
532
533 /******************************************************************************/
534 void read_content_features(lua_State *L, ContentFeatures &f, int index)
535 {
536         if(index < 0)
537                 index = lua_gettop(L) + 1 + index;
538
539         /* Cache existence of some callbacks */
540         lua_getfield(L, index, "on_construct");
541         if(!lua_isnil(L, -1)) f.has_on_construct = true;
542         lua_pop(L, 1);
543         lua_getfield(L, index, "on_destruct");
544         if(!lua_isnil(L, -1)) f.has_on_destruct = true;
545         lua_pop(L, 1);
546         lua_getfield(L, index, "after_destruct");
547         if(!lua_isnil(L, -1)) f.has_after_destruct = true;
548         lua_pop(L, 1);
549
550         lua_getfield(L, index, "on_rightclick");
551         f.rightclickable = lua_isfunction(L, -1);
552         lua_pop(L, 1);
553
554         /* Name */
555         getstringfield(L, index, "name", f.name);
556
557         /* Groups */
558         lua_getfield(L, index, "groups");
559         read_groups(L, -1, f.groups);
560         lua_pop(L, 1);
561
562         /* Visual definition */
563
564         f.drawtype = (NodeDrawType)getenumfield(L, index, "drawtype",
565                         ScriptApiNode::es_DrawType,NDT_NORMAL);
566         getfloatfield(L, index, "visual_scale", f.visual_scale);
567
568         /* Meshnode model filename */
569         getstringfield(L, index, "mesh", f.mesh);
570
571         // tiles = {}
572         lua_getfield(L, index, "tiles");
573         if(lua_istable(L, -1)){
574                 int table = lua_gettop(L);
575                 lua_pushnil(L);
576                 int i = 0;
577                 while(lua_next(L, table) != 0){
578                         // Read tiledef from value
579                         f.tiledef[i] = read_tiledef(L, -1, f.drawtype);
580                         // removes value, keeps key for next iteration
581                         lua_pop(L, 1);
582                         i++;
583                         if(i==6){
584                                 lua_pop(L, 1);
585                                 break;
586                         }
587                 }
588                 // Copy last value to all remaining textures
589                 if(i >= 1){
590                         TileDef lasttile = f.tiledef[i-1];
591                         while(i < 6){
592                                 f.tiledef[i] = lasttile;
593                                 i++;
594                         }
595                 }
596         }
597         lua_pop(L, 1);
598
599         // overlay_tiles = {}
600         lua_getfield(L, index, "overlay_tiles");
601         if (lua_istable(L, -1)) {
602                 int table = lua_gettop(L);
603                 lua_pushnil(L);
604                 int i = 0;
605                 while (lua_next(L, table) != 0) {
606                         // Read tiledef from value
607                         f.tiledef_overlay[i] = read_tiledef(L, -1, f.drawtype);
608                         // removes value, keeps key for next iteration
609                         lua_pop(L, 1);
610                         i++;
611                         if (i == 6) {
612                                 lua_pop(L, 1);
613                                 break;
614                         }
615                 }
616                 // Copy last value to all remaining textures
617                 if (i >= 1) {
618                         TileDef lasttile = f.tiledef_overlay[i - 1];
619                         while (i < 6) {
620                                 f.tiledef_overlay[i] = lasttile;
621                                 i++;
622                         }
623                 }
624         }
625         lua_pop(L, 1);
626
627         // special_tiles = {}
628         lua_getfield(L, index, "special_tiles");
629         if(lua_istable(L, -1)){
630                 int table = lua_gettop(L);
631                 lua_pushnil(L);
632                 int i = 0;
633                 while(lua_next(L, table) != 0){
634                         // Read tiledef from value
635                         f.tiledef_special[i] = read_tiledef(L, -1, f.drawtype);
636                         // removes value, keeps key for next iteration
637                         lua_pop(L, 1);
638                         i++;
639                         if(i==CF_SPECIAL_COUNT){
640                                 lua_pop(L, 1);
641                                 break;
642                         }
643                 }
644         }
645         lua_pop(L, 1);
646
647         /* alpha & use_texture_alpha */
648         // This is a bit complicated due to compatibility
649
650         f.setDefaultAlphaMode();
651
652         warn_if_field_exists(L, index, "alpha",
653                 "Obsolete, only limited compatibility provided; "
654                 "replaced by \"use_texture_alpha\"");
655         if (getintfield_default(L, index, "alpha", 255) != 255)
656                 f.alpha = ALPHAMODE_BLEND;
657
658         lua_getfield(L, index, "use_texture_alpha");
659         if (lua_isboolean(L, -1)) {
660                 warn_if_field_exists(L, index, "use_texture_alpha",
661                         "Boolean values are deprecated; use the new choices");
662                 if (lua_toboolean(L, -1))
663                         f.alpha = (f.drawtype == NDT_NORMAL) ? ALPHAMODE_CLIP : ALPHAMODE_BLEND;
664         } else if (check_field_or_nil(L, -1, LUA_TSTRING, "use_texture_alpha")) {
665                 int result = f.alpha;
666                 string_to_enum(ScriptApiNode::es_TextureAlphaMode, result,
667                                 std::string(lua_tostring(L, -1)));
668                 f.alpha = static_cast<enum AlphaMode>(result);
669         }
670         lua_pop(L, 1);
671
672         /* Other stuff */
673
674         lua_getfield(L, index, "color");
675         read_color(L, -1, &f.color);
676         lua_pop(L, 1);
677
678         getstringfield(L, index, "palette", f.palette_name);
679
680         lua_getfield(L, index, "post_effect_color");
681         read_color(L, -1, &f.post_effect_color);
682         lua_pop(L, 1);
683
684         f.param_type = (ContentParamType)getenumfield(L, index, "paramtype",
685                         ScriptApiNode::es_ContentParamType, CPT_NONE);
686         f.param_type_2 = (ContentParamType2)getenumfield(L, index, "paramtype2",
687                         ScriptApiNode::es_ContentParamType2, CPT2_NONE);
688
689         if (!f.palette_name.empty() &&
690                         !(f.param_type_2 == CPT2_COLOR ||
691                         f.param_type_2 == CPT2_COLORED_FACEDIR ||
692                         f.param_type_2 == CPT2_COLORED_WALLMOUNTED ||
693                         f.param_type_2 == CPT2_COLORED_DEGROTATE ||
694                         f.param_type_2 == CPT2_COLORED_4DIR))
695                 warningstream << "Node " << f.name.c_str()
696                         << " has a palette, but not a suitable paramtype2." << std::endl;
697
698         // True for all ground-like things like stone and mud, false for eg. trees
699         getboolfield(L, index, "is_ground_content", f.is_ground_content);
700         f.light_propagates = (f.param_type == CPT_LIGHT);
701         getboolfield(L, index, "sunlight_propagates", f.sunlight_propagates);
702         // This is used for collision detection.
703         // Also for general solidness queries.
704         getboolfield(L, index, "walkable", f.walkable);
705         // Player can point to these
706         getboolfield(L, index, "pointable", f.pointable);
707         // Player can dig these
708         getboolfield(L, index, "diggable", f.diggable);
709         // Player can climb these
710         getboolfield(L, index, "climbable", f.climbable);
711         // Player can build on these
712         getboolfield(L, index, "buildable_to", f.buildable_to);
713         // Liquids flow into and replace node
714         getboolfield(L, index, "floodable", f.floodable);
715         // Whether the node is non-liquid, source liquid or flowing liquid
716         f.liquid_type = (LiquidType)getenumfield(L, index, "liquidtype",
717                         ScriptApiNode::es_LiquidType, LIQUID_NONE);
718         // If the content is liquid, this is the flowing version of the liquid.
719         getstringfield(L, index, "liquid_alternative_flowing",
720                         f.liquid_alternative_flowing);
721         // If the content is liquid, this is the source version of the liquid.
722         getstringfield(L, index, "liquid_alternative_source",
723                         f.liquid_alternative_source);
724         // Viscosity for fluid flow, ranging from 1 to 7, with
725         // 1 giving almost instantaneous propagation and 7 being
726         // the slowest possible
727         f.liquid_viscosity = getintfield_default(L, index,
728                         "liquid_viscosity", f.liquid_viscosity);
729         // If move_resistance is not set explicitly,
730         // move_resistance is equal to liquid_viscosity
731         f.move_resistance = f.liquid_viscosity;
732         f.liquid_range = getintfield_default(L, index,
733                         "liquid_range", f.liquid_range);
734         f.leveled = getintfield_default(L, index, "leveled", f.leveled);
735         f.leveled_max = getintfield_default(L, index,
736                         "leveled_max", f.leveled_max);
737
738         getboolfield(L, index, "liquid_renewable", f.liquid_renewable);
739         f.drowning = getintfield_default(L, index,
740                         "drowning", f.drowning);
741         // Amount of light the node emits
742         f.light_source = getintfield_default(L, index,
743                         "light_source", f.light_source);
744         if (f.light_source > LIGHT_MAX) {
745                 warningstream << "Node " << f.name.c_str()
746                         << " had greater light_source than " << LIGHT_MAX
747                         << ", it was reduced." << std::endl;
748                 f.light_source = LIGHT_MAX;
749         }
750         f.damage_per_second = getintfield_default(L, index,
751                         "damage_per_second", f.damage_per_second);
752
753         lua_getfield(L, index, "node_box");
754         if(lua_istable(L, -1))
755                 f.node_box = read_nodebox(L, -1);
756         lua_pop(L, 1);
757
758         lua_getfield(L, index, "connects_to");
759         if (lua_istable(L, -1)) {
760                 int table = lua_gettop(L);
761                 lua_pushnil(L);
762                 while (lua_next(L, table) != 0) {
763                         // Value at -1
764                         f.connects_to.emplace_back(lua_tostring(L, -1));
765                         lua_pop(L, 1);
766                 }
767         }
768         lua_pop(L, 1);
769
770         lua_getfield(L, index, "connect_sides");
771         if (lua_istable(L, -1)) {
772                 int table = lua_gettop(L);
773                 lua_pushnil(L);
774                 while (lua_next(L, table) != 0) {
775                         // Value at -1
776                         std::string side(lua_tostring(L, -1));
777                         // Note faces are flipped to make checking easier
778                         if (side == "top")
779                                 f.connect_sides |= 2;
780                         else if (side == "bottom")
781                                 f.connect_sides |= 1;
782                         else if (side == "front")
783                                 f.connect_sides |= 16;
784                         else if (side == "left")
785                                 f.connect_sides |= 32;
786                         else if (side == "back")
787                                 f.connect_sides |= 4;
788                         else if (side == "right")
789                                 f.connect_sides |= 8;
790                         else
791                                 warningstream << "Unknown value for \"connect_sides\": "
792                                         << side << std::endl;
793                         lua_pop(L, 1);
794                 }
795         }
796         lua_pop(L, 1);
797
798         lua_getfield(L, index, "selection_box");
799         if(lua_istable(L, -1))
800                 f.selection_box = read_nodebox(L, -1);
801         lua_pop(L, 1);
802
803         lua_getfield(L, index, "collision_box");
804         if(lua_istable(L, -1))
805                 f.collision_box = read_nodebox(L, -1);
806         lua_pop(L, 1);
807
808         f.waving = getintfield_default(L, index,
809                         "waving", f.waving);
810
811         // Set to true if paramtype used to be 'facedir_simple'
812         getboolfield(L, index, "legacy_facedir_simple", f.legacy_facedir_simple);
813         // Set to true if wall_mounted used to be set to true
814         getboolfield(L, index, "legacy_wallmounted", f.legacy_wallmounted);
815
816         // Sound table
817         lua_getfield(L, index, "sounds");
818         if(lua_istable(L, -1)){
819                 lua_getfield(L, -1, "footstep");
820                 read_soundspec(L, -1, f.sound_footstep);
821                 lua_pop(L, 1);
822                 lua_getfield(L, -1, "dig");
823                 read_soundspec(L, -1, f.sound_dig);
824                 lua_pop(L, 1);
825                 lua_getfield(L, -1, "dug");
826                 read_soundspec(L, -1, f.sound_dug);
827                 lua_pop(L, 1);
828         }
829         lua_pop(L, 1);
830
831         // Node immediately placed by client when node is dug
832         getstringfield(L, index, "node_dig_prediction",
833                 f.node_dig_prediction);
834
835         // How much the node slows down players, ranging from 1 to 7,
836         // the higher, the slower.
837         f.move_resistance = getintfield_default(L, index,
838                         "move_resistance", f.move_resistance);
839
840         // Whether e.g. players in this node will have liquid movement physics
841         lua_getfield(L, index, "liquid_move_physics");
842         if(lua_isboolean(L, -1)) {
843                 f.liquid_move_physics = lua_toboolean(L, -1);
844         } else if(lua_isnil(L, -1)) {
845                 f.liquid_move_physics = f.liquid_type != LIQUID_NONE;
846         } else {
847                 errorstream << "Field \"liquid_move_physics\": Invalid type!" << std::endl;
848         }
849         lua_pop(L, 1);
850 }
851
852 void push_content_features(lua_State *L, const ContentFeatures &c)
853 {
854         std::string paramtype(ScriptApiNode::es_ContentParamType[(int)c.param_type].str);
855         std::string paramtype2(ScriptApiNode::es_ContentParamType2[(int)c.param_type_2].str);
856         std::string drawtype(ScriptApiNode::es_DrawType[(int)c.drawtype].str);
857         std::string liquid_type(ScriptApiNode::es_LiquidType[(int)c.liquid_type].str);
858
859         /* Missing "tiles" because I don't see a usecase (at least not yet). */
860
861         lua_newtable(L);
862         lua_pushboolean(L, c.has_on_construct);
863         lua_setfield(L, -2, "has_on_construct");
864         lua_pushboolean(L, c.has_on_destruct);
865         lua_setfield(L, -2, "has_on_destruct");
866         lua_pushboolean(L, c.has_after_destruct);
867         lua_setfield(L, -2, "has_after_destruct");
868         lua_pushstring(L, c.name.c_str());
869         lua_setfield(L, -2, "name");
870         push_groups(L, c.groups);
871         lua_setfield(L, -2, "groups");
872         lua_pushstring(L, paramtype.c_str());
873         lua_setfield(L, -2, "paramtype");
874         lua_pushstring(L, paramtype2.c_str());
875         lua_setfield(L, -2, "paramtype2");
876         lua_pushstring(L, drawtype.c_str());
877         lua_setfield(L, -2, "drawtype");
878         if (!c.mesh.empty()) {
879                 lua_pushstring(L, c.mesh.c_str());
880                 lua_setfield(L, -2, "mesh");
881         }
882 #ifndef SERVER
883         push_ARGB8(L, c.minimap_color);       // I know this is not set-able w/ register_node,
884         lua_setfield(L, -2, "minimap_color"); // but the people need to know!
885 #endif
886         lua_pushnumber(L, c.visual_scale);
887         lua_setfield(L, -2, "visual_scale");
888         lua_pushnumber(L, c.alpha);
889         lua_setfield(L, -2, "alpha");
890         if (!c.palette_name.empty()) {
891                 push_ARGB8(L, c.color);
892                 lua_setfield(L, -2, "color");
893
894                 lua_pushstring(L, c.palette_name.c_str());
895                 lua_setfield(L, -2, "palette_name");
896
897                 push_palette(L, c.palette);
898                 lua_setfield(L, -2, "palette");
899         }
900         lua_pushnumber(L, c.waving);
901         lua_setfield(L, -2, "waving");
902         lua_pushnumber(L, c.connect_sides);
903         lua_setfield(L, -2, "connect_sides");
904
905         lua_createtable(L, c.connects_to.size(), 0);
906         u16 i = 1;
907         for (const std::string &it : c.connects_to) {
908                 lua_pushlstring(L, it.c_str(), it.size());
909                 lua_rawseti(L, -2, i++);
910         }
911         lua_setfield(L, -2, "connects_to");
912
913         push_ARGB8(L, c.post_effect_color);
914         lua_setfield(L, -2, "post_effect_color");
915         lua_pushnumber(L, c.leveled);
916         lua_setfield(L, -2, "leveled");
917         lua_pushnumber(L, c.leveled_max);
918         lua_setfield(L, -2, "leveled_max");
919         lua_pushboolean(L, c.sunlight_propagates);
920         lua_setfield(L, -2, "sunlight_propagates");
921         lua_pushnumber(L, c.light_source);
922         lua_setfield(L, -2, "light_source");
923         lua_pushboolean(L, c.is_ground_content);
924         lua_setfield(L, -2, "is_ground_content");
925         lua_pushboolean(L, c.walkable);
926         lua_setfield(L, -2, "walkable");
927         lua_pushboolean(L, c.pointable);
928         lua_setfield(L, -2, "pointable");
929         lua_pushboolean(L, c.diggable);
930         lua_setfield(L, -2, "diggable");
931         lua_pushboolean(L, c.climbable);
932         lua_setfield(L, -2, "climbable");
933         lua_pushboolean(L, c.buildable_to);
934         lua_setfield(L, -2, "buildable_to");
935         lua_pushboolean(L, c.rightclickable);
936         lua_setfield(L, -2, "rightclickable");
937         lua_pushnumber(L, c.damage_per_second);
938         lua_setfield(L, -2, "damage_per_second");
939         if (c.isLiquid()) {
940                 lua_pushstring(L, liquid_type.c_str());
941                 lua_setfield(L, -2, "liquid_type");
942                 lua_pushstring(L, c.liquid_alternative_flowing.c_str());
943                 lua_setfield(L, -2, "liquid_alternative_flowing");
944                 lua_pushstring(L, c.liquid_alternative_source.c_str());
945                 lua_setfield(L, -2, "liquid_alternative_source");
946                 lua_pushnumber(L, c.liquid_viscosity);
947                 lua_setfield(L, -2, "liquid_viscosity");
948                 lua_pushboolean(L, c.liquid_renewable);
949                 lua_setfield(L, -2, "liquid_renewable");
950                 lua_pushnumber(L, c.liquid_range);
951                 lua_setfield(L, -2, "liquid_range");
952         }
953         lua_pushnumber(L, c.drowning);
954         lua_setfield(L, -2, "drowning");
955         lua_pushboolean(L, c.floodable);
956         lua_setfield(L, -2, "floodable");
957         push_nodebox(L, c.node_box);
958         lua_setfield(L, -2, "node_box");
959         push_nodebox(L, c.selection_box);
960         lua_setfield(L, -2, "selection_box");
961         push_nodebox(L, c.collision_box);
962         lua_setfield(L, -2, "collision_box");
963         lua_newtable(L);
964         push_soundspec(L, c.sound_footstep);
965         lua_setfield(L, -2, "sound_footstep");
966         push_soundspec(L, c.sound_dig);
967         lua_setfield(L, -2, "sound_dig");
968         push_soundspec(L, c.sound_dug);
969         lua_setfield(L, -2, "sound_dug");
970         lua_setfield(L, -2, "sounds");
971         lua_pushboolean(L, c.legacy_facedir_simple);
972         lua_setfield(L, -2, "legacy_facedir_simple");
973         lua_pushboolean(L, c.legacy_wallmounted);
974         lua_setfield(L, -2, "legacy_wallmounted");
975         lua_pushstring(L, c.node_dig_prediction.c_str());
976         lua_setfield(L, -2, "node_dig_prediction");
977         lua_pushnumber(L, c.move_resistance);
978         lua_setfield(L, -2, "move_resistance");
979         lua_pushboolean(L, c.liquid_move_physics);
980         lua_setfield(L, -2, "liquid_move_physics");
981 }
982
983 /******************************************************************************/
984 void push_nodebox(lua_State *L, const NodeBox &box)
985 {
986         lua_newtable(L);
987         switch (box.type)
988         {
989                 case NODEBOX_REGULAR:
990                         lua_pushstring(L, "regular");
991                         lua_setfield(L, -2, "type");
992                         break;
993                 case NODEBOX_LEVELED:
994                 case NODEBOX_FIXED:
995                         lua_pushstring(L, "fixed");
996                         lua_setfield(L, -2, "type");
997                         push_box(L, box.fixed);
998                         lua_setfield(L, -2, "fixed");
999                         break;
1000                 case NODEBOX_WALLMOUNTED:
1001                         lua_pushstring(L, "wallmounted");
1002                         lua_setfield(L, -2, "type");
1003                         push_aabb3f(L, box.wall_top);
1004                         lua_setfield(L, -2, "wall_top");
1005                         push_aabb3f(L, box.wall_bottom);
1006                         lua_setfield(L, -2, "wall_bottom");
1007                         push_aabb3f(L, box.wall_side);
1008                         lua_setfield(L, -2, "wall_side");
1009                         break;
1010                 case NODEBOX_CONNECTED: {
1011                         lua_pushstring(L, "connected");
1012                         lua_setfield(L, -2, "type");
1013                         const auto &c = box.getConnected();
1014                         push_box(L, c.connect_top);
1015                         lua_setfield(L, -2, "connect_top");
1016                         push_box(L, c.connect_bottom);
1017                         lua_setfield(L, -2, "connect_bottom");
1018                         push_box(L, c.connect_front);
1019                         lua_setfield(L, -2, "connect_front");
1020                         push_box(L, c.connect_back);
1021                         lua_setfield(L, -2, "connect_back");
1022                         push_box(L, c.connect_left);
1023                         lua_setfield(L, -2, "connect_left");
1024                         push_box(L, c.connect_right);
1025                         lua_setfield(L, -2, "connect_right");
1026                         // half the boxes are missing here?
1027                         break;
1028                 }
1029                 default:
1030                         FATAL_ERROR("Invalid box.type");
1031                         break;
1032         }
1033 }
1034
1035 void push_box(lua_State *L, const std::vector<aabb3f> &box)
1036 {
1037         lua_createtable(L, box.size(), 0);
1038         u8 i = 1;
1039         for (const aabb3f &it : box) {
1040                 push_aabb3f(L, it);
1041                 lua_rawseti(L, -2, i++);
1042         }
1043 }
1044
1045 /******************************************************************************/
1046 void push_palette(lua_State *L, const std::vector<video::SColor> *palette)
1047 {
1048         lua_createtable(L, palette->size(), 0);
1049         int newTable = lua_gettop(L);
1050         int index = 1;
1051         std::vector<video::SColor>::const_iterator iter;
1052         for (iter = palette->begin(); iter != palette->end(); ++iter) {
1053                 push_ARGB8(L, (*iter));
1054                 lua_rawseti(L, newTable, index);
1055                 index++;
1056         }
1057 }
1058
1059 /******************************************************************************/
1060 void read_server_sound_params(lua_State *L, int index,
1061                 ServerPlayingSound &params)
1062 {
1063         if(index < 0)
1064                 index = lua_gettop(L) + 1 + index;
1065
1066         if(lua_istable(L, index)){
1067                 // Functional overlap: this may modify SimpleSoundSpec contents
1068                 getfloatfield(L, index, "fade", params.spec.fade);
1069                 getfloatfield(L, index, "pitch", params.spec.pitch);
1070                 getboolfield(L, index, "loop", params.spec.loop);
1071
1072                 getfloatfield(L, index, "gain", params.gain);
1073
1074                 // Handle positional information
1075                 getstringfield(L, index, "to_player", params.to_player);
1076                 lua_getfield(L, index, "pos");
1077                 if(!lua_isnil(L, -1)){
1078                         v3f p = read_v3f(L, -1)*BS;
1079                         params.pos = p;
1080                         params.type = SoundLocation::Position;
1081                 }
1082                 lua_pop(L, 1);
1083                 lua_getfield(L, index, "object");
1084                 if(!lua_isnil(L, -1)){
1085                         ObjectRef *ref = ModApiBase::checkObject<ObjectRef>(L, -1);
1086                         ServerActiveObject *sao = ObjectRef::getobject(ref);
1087                         if(sao){
1088                                 params.object = sao->getId();
1089                                 params.type = SoundLocation::Object;
1090                         }
1091                 }
1092                 lua_pop(L, 1);
1093                 params.max_hear_distance = BS*getfloatfield_default(L, index,
1094                                 "max_hear_distance", params.max_hear_distance/BS);
1095                 getstringfield(L, index, "exclude_player", params.exclude_player);
1096         }
1097 }
1098
1099 /******************************************************************************/
1100 void read_soundspec(lua_State *L, int index, SimpleSoundSpec &spec)
1101 {
1102         if(index < 0)
1103                 index = lua_gettop(L) + 1 + index;
1104         if (lua_isnil(L, index))
1105                 return;
1106
1107         if (lua_istable(L, index)) {
1108                 getstringfield(L, index, "name", spec.name);
1109                 getfloatfield(L, index, "gain", spec.gain);
1110                 getfloatfield(L, index, "fade", spec.fade);
1111                 getfloatfield(L, index, "pitch", spec.pitch);
1112         } else if (lua_isstring(L, index)) {
1113                 spec.name = lua_tostring(L, index);
1114         }
1115 }
1116
1117 void push_soundspec(lua_State *L, const SimpleSoundSpec &spec)
1118 {
1119         lua_createtable(L, 0, 3);
1120         lua_pushstring(L, spec.name.c_str());
1121         lua_setfield(L, -2, "name");
1122         lua_pushnumber(L, spec.gain);
1123         lua_setfield(L, -2, "gain");
1124         lua_pushnumber(L, spec.fade);
1125         lua_setfield(L, -2, "fade");
1126         lua_pushnumber(L, spec.pitch);
1127         lua_setfield(L, -2, "pitch");
1128 }
1129
1130 /******************************************************************************/
1131 NodeBox read_nodebox(lua_State *L, int index)
1132 {
1133         NodeBox nodebox;
1134         if (lua_isnil(L, -1))
1135                 return nodebox;
1136
1137         luaL_checktype(L, -1, LUA_TTABLE);
1138
1139         nodebox.type = (NodeBoxType)getenumfield(L, index, "type",
1140                         ScriptApiNode::es_NodeBoxType, NODEBOX_REGULAR);
1141
1142 #define NODEBOXREAD(n, s){ \
1143                 lua_getfield(L, index, (s)); \
1144                 if (lua_istable(L, -1)) \
1145                         (n) = read_aabb3f(L, -1, BS); \
1146                 lua_pop(L, 1); \
1147         }
1148
1149 #define NODEBOXREADVEC(n, s) \
1150         lua_getfield(L, index, (s)); \
1151         if (lua_istable(L, -1)) \
1152                 (n) = read_aabb3f_vector(L, -1, BS); \
1153         lua_pop(L, 1);
1154
1155         NODEBOXREADVEC(nodebox.fixed, "fixed");
1156         NODEBOXREAD(nodebox.wall_top, "wall_top");
1157         NODEBOXREAD(nodebox.wall_bottom, "wall_bottom");
1158         NODEBOXREAD(nodebox.wall_side, "wall_side");
1159
1160         if (nodebox.type == NODEBOX_CONNECTED) {
1161                 auto &c = nodebox.getConnected();
1162                 NODEBOXREADVEC(c.connect_top, "connect_top");
1163                 NODEBOXREADVEC(c.connect_bottom, "connect_bottom");
1164                 NODEBOXREADVEC(c.connect_front, "connect_front");
1165                 NODEBOXREADVEC(c.connect_left, "connect_left");
1166                 NODEBOXREADVEC(c.connect_back, "connect_back");
1167                 NODEBOXREADVEC(c.connect_right, "connect_right");
1168                 NODEBOXREADVEC(c.disconnected_top, "disconnected_top");
1169                 NODEBOXREADVEC(c.disconnected_bottom, "disconnected_bottom");
1170                 NODEBOXREADVEC(c.disconnected_front, "disconnected_front");
1171                 NODEBOXREADVEC(c.disconnected_left, "disconnected_left");
1172                 NODEBOXREADVEC(c.disconnected_back, "disconnected_back");
1173                 NODEBOXREADVEC(c.disconnected_right, "disconnected_right");
1174                 NODEBOXREADVEC(c.disconnected, "disconnected");
1175                 NODEBOXREADVEC(c.disconnected_sides, "disconnected_sides");
1176         }
1177
1178         return nodebox;
1179 }
1180
1181 /******************************************************************************/
1182 MapNode readnode(lua_State *L, int index)
1183 {
1184         lua_pushvalue(L, index);
1185         lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_READ_NODE);
1186         lua_insert(L, -2);
1187         lua_call(L, 1, 3);
1188         content_t content = lua_tointeger(L, -3);
1189         u8 param1 = lua_tointeger(L, -2);
1190         u8 param2 = lua_tointeger(L, -1);
1191         lua_pop(L, 3);
1192         return MapNode(content, param1, param2);
1193 }
1194
1195 /******************************************************************************/
1196 void pushnode(lua_State *L, const MapNode &n)
1197 {
1198         lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_PUSH_NODE);
1199         lua_pushinteger(L, n.getContent());
1200         lua_pushinteger(L, n.getParam1());
1201         lua_pushinteger(L, n.getParam2());
1202         lua_call(L, 3, 1);
1203 }
1204
1205 /******************************************************************************/
1206 void warn_if_field_exists(lua_State *L, int table,
1207                 const char *name, const std::string &message)
1208 {
1209         lua_getfield(L, table, name);
1210         if (!lua_isnil(L, -1)) {
1211                 warningstream << "Field \"" << name << "\": "
1212                                 << message << std::endl;
1213                 infostream << script_get_backtrace(L) << std::endl;
1214         }
1215         lua_pop(L, 1);
1216 }
1217
1218 /******************************************************************************/
1219 int getenumfield(lua_State *L, int table,
1220                 const char *fieldname, const EnumString *spec, int default_)
1221 {
1222         int result = default_;
1223         string_to_enum(spec, result,
1224                         getstringfield_default(L, table, fieldname, ""));
1225         return result;
1226 }
1227
1228 /******************************************************************************/
1229 bool string_to_enum(const EnumString *spec, int &result,
1230                 const std::string &str)
1231 {
1232         const EnumString *esp = spec;
1233         while(esp->str){
1234                 if (!strcmp(str.c_str(), esp->str)) {
1235                         result = esp->num;
1236                         return true;
1237                 }
1238                 esp++;
1239         }
1240         return false;
1241 }
1242
1243 /******************************************************************************/
1244 ItemStack read_item(lua_State* L, int index, IItemDefManager *idef)
1245 {
1246         if(index < 0)
1247                 index = lua_gettop(L) + 1 + index;
1248
1249         if (lua_isnil(L, index)) {
1250                 return ItemStack();
1251         }
1252
1253         if (lua_isuserdata(L, index)) {
1254                 // Convert from LuaItemStack
1255                 LuaItemStack *o = ModApiBase::checkObject<LuaItemStack>(L, index);
1256                 return o->getItem();
1257         }
1258
1259         if (lua_isstring(L, index)) {
1260                 // Convert from itemstring
1261                 std::string itemstring = lua_tostring(L, index);
1262                 try
1263                 {
1264                         ItemStack item;
1265                         item.deSerialize(itemstring, idef);
1266                         return item;
1267                 }
1268                 catch(SerializationError &e)
1269                 {
1270                         warningstream<<"unable to create item from itemstring"
1271                                         <<": "<<itemstring<<std::endl;
1272                         return ItemStack();
1273                 }
1274         }
1275         else if(lua_istable(L, index))
1276         {
1277                 // Convert from table
1278                 std::string name = getstringfield_default(L, index, "name", "");
1279                 int count = getintfield_default(L, index, "count", 1);
1280                 int wear = getintfield_default(L, index, "wear", 0);
1281
1282                 ItemStack istack(name, count, wear, idef);
1283
1284                 // BACKWARDS COMPATIBLITY
1285                 std::string value = getstringfield_default(L, index, "metadata", "");
1286                 istack.metadata.setString("", value);
1287
1288                 // Get meta
1289                 lua_getfield(L, index, "meta");
1290                 int fieldstable = lua_gettop(L);
1291                 if (lua_istable(L, fieldstable)) {
1292                         lua_pushnil(L);
1293                         while (lua_next(L, fieldstable) != 0) {
1294                                 // key at index -2 and value at index -1
1295                                 std::string key = lua_tostring(L, -2);
1296                                 size_t value_len;
1297                                 const char *value_cs = lua_tolstring(L, -1, &value_len);
1298                                 std::string value(value_cs, value_len);
1299                                 istack.metadata.setString(key, value);
1300                                 lua_pop(L, 1); // removes value, keeps key for next iteration
1301                         }
1302                 }
1303
1304                 return istack;
1305         } else {
1306                 throw LuaError("Expecting itemstack, itemstring, table or nil");
1307         }
1308 }
1309
1310 /******************************************************************************/
1311 void push_tool_capabilities(lua_State *L,
1312                 const ToolCapabilities &toolcap)
1313 {
1314         lua_newtable(L);
1315         setfloatfield(L, -1, "full_punch_interval", toolcap.full_punch_interval);
1316         setintfield(L, -1, "max_drop_level", toolcap.max_drop_level);
1317         setintfield(L, -1, "punch_attack_uses", toolcap.punch_attack_uses);
1318                 // Create groupcaps table
1319                 lua_newtable(L);
1320                 // For each groupcap
1321                 for (const auto &gc_it : toolcap.groupcaps) {
1322                         // Create groupcap table
1323                         lua_newtable(L);
1324                         const std::string &name = gc_it.first;
1325                         const ToolGroupCap &groupcap = gc_it.second;
1326                         // Create subtable "times"
1327                         lua_newtable(L);
1328                         for (auto time : groupcap.times) {
1329                                 lua_pushinteger(L, time.first);
1330                                 lua_pushnumber(L, time.second);
1331                                 lua_settable(L, -3);
1332                         }
1333                         // Set subtable "times"
1334                         lua_setfield(L, -2, "times");
1335                         // Set simple parameters
1336                         setintfield(L, -1, "maxlevel", groupcap.maxlevel);
1337                         setintfield(L, -1, "uses", groupcap.uses);
1338                         // Insert groupcap table into groupcaps table
1339                         lua_setfield(L, -2, name.c_str());
1340                 }
1341                 // Set groupcaps table
1342                 lua_setfield(L, -2, "groupcaps");
1343                 //Create damage_groups table
1344                 lua_newtable(L);
1345                 // For each damage group
1346                 for (const auto &damageGroup : toolcap.damageGroups) {
1347                         // Create damage group table
1348                         lua_pushinteger(L, damageGroup.second);
1349                         lua_setfield(L, -2, damageGroup.first.c_str());
1350                 }
1351                 lua_setfield(L, -2, "damage_groups");
1352 }
1353
1354 /******************************************************************************/
1355 void push_inventory_list(lua_State *L, const InventoryList &invlist)
1356 {
1357         push_items(L, invlist.getItems());
1358 }
1359
1360 /******************************************************************************/
1361 void push_inventory_lists(lua_State *L, const Inventory &inv)
1362 {
1363         const auto &lists = inv.getLists();
1364         lua_createtable(L, 0, lists.size());
1365         for(const InventoryList *list : lists) {
1366                 const std::string &name = list->getName();
1367                 lua_pushlstring(L, name.c_str(), name.size());
1368                 push_inventory_list(L, *list);
1369                 lua_rawset(L, -3);
1370         }
1371 }
1372
1373 /******************************************************************************/
1374 void read_inventory_list(lua_State *L, int tableindex,
1375                 Inventory *inv, const char *name, IGameDef *gdef, int forcesize)
1376 {
1377         if(tableindex < 0)
1378                 tableindex = lua_gettop(L) + 1 + tableindex;
1379
1380         // If nil, delete list
1381         if(lua_isnil(L, tableindex)){
1382                 inv->deleteList(name);
1383                 return;
1384         }
1385
1386         // Get Lua-specified items to insert into the list
1387         std::vector<ItemStack> items = read_items(L, tableindex, gdef);
1388         size_t listsize = (forcesize >= 0) ? forcesize : items.size();
1389
1390         // Create or resize/clear list
1391         InventoryList *invlist = inv->addList(name, listsize);
1392         if (!invlist) {
1393                 luaL_error(L, "inventory list: cannot create list named '%s'", name);
1394                 return;
1395         }
1396
1397         for (size_t i = 0; i < items.size(); ++i) {
1398                 if (i == listsize)
1399                         break; // Truncate provided list of items
1400                 invlist->changeItem(i, items[i]);
1401         }
1402 }
1403
1404 /******************************************************************************/
1405 struct TileAnimationParams read_animation_definition(lua_State *L, int index)
1406 {
1407         if(index < 0)
1408                 index = lua_gettop(L) + 1 + index;
1409
1410         struct TileAnimationParams anim;
1411         anim.type = TAT_NONE;
1412         if (!lua_istable(L, index))
1413                 return anim;
1414
1415         anim.type = (TileAnimationType)
1416                 getenumfield(L, index, "type", es_TileAnimationType,
1417                 TAT_NONE);
1418         if (anim.type == TAT_VERTICAL_FRAMES) {
1419                 // {type="vertical_frames", aspect_w=16, aspect_h=16, length=2.0}
1420                 anim.vertical_frames.aspect_w =
1421                         getintfield_default(L, index, "aspect_w", 16);
1422                 anim.vertical_frames.aspect_h =
1423                         getintfield_default(L, index, "aspect_h", 16);
1424                 anim.vertical_frames.length =
1425                         getfloatfield_default(L, index, "length", 1.0);
1426         } else if (anim.type == TAT_SHEET_2D) {
1427                 // {type="sheet_2d", frames_w=5, frames_h=3, frame_length=0.5}
1428                 getintfield(L, index, "frames_w",
1429                         anim.sheet_2d.frames_w);
1430                 getintfield(L, index, "frames_h",
1431                         anim.sheet_2d.frames_h);
1432                 getfloatfield(L, index, "frame_length",
1433                         anim.sheet_2d.frame_length);
1434         }
1435
1436         return anim;
1437 }
1438
1439 /******************************************************************************/
1440 ToolCapabilities read_tool_capabilities(
1441                 lua_State *L, int table)
1442 {
1443         ToolCapabilities toolcap;
1444         getfloatfield(L, table, "full_punch_interval", toolcap.full_punch_interval);
1445         getintfield(L, table, "max_drop_level", toolcap.max_drop_level);
1446         getintfield(L, table, "punch_attack_uses", toolcap.punch_attack_uses);
1447         lua_getfield(L, table, "groupcaps");
1448         if(lua_istable(L, -1)){
1449                 int table_groupcaps = lua_gettop(L);
1450                 lua_pushnil(L);
1451                 while(lua_next(L, table_groupcaps) != 0){
1452                         // key at index -2 and value at index -1
1453                         std::string groupname = luaL_checkstring(L, -2);
1454                         if(lua_istable(L, -1)){
1455                                 int table_groupcap = lua_gettop(L);
1456                                 // This will be created
1457                                 ToolGroupCap groupcap;
1458                                 // Read simple parameters
1459                                 getintfield(L, table_groupcap, "maxlevel", groupcap.maxlevel);
1460                                 getintfield(L, table_groupcap, "uses", groupcap.uses);
1461                                 // DEPRECATED: maxwear
1462                                 float maxwear = 0;
1463                                 if (getfloatfield(L, table_groupcap, "maxwear", maxwear)){
1464                                         if (maxwear != 0)
1465                                                 groupcap.uses = 1.0/maxwear;
1466                                         else
1467                                                 groupcap.uses = 0;
1468                                         warningstream << "Field \"maxwear\" is deprecated; "
1469                                                         << "replace with uses=1/maxwear" << std::endl;
1470                                         infostream << script_get_backtrace(L) << std::endl;
1471                                 }
1472                                 // Read "times" table
1473                                 lua_getfield(L, table_groupcap, "times");
1474                                 if(lua_istable(L, -1)){
1475                                         int table_times = lua_gettop(L);
1476                                         lua_pushnil(L);
1477                                         while(lua_next(L, table_times) != 0){
1478                                                 // key at index -2 and value at index -1
1479                                                 int rating = luaL_checkinteger(L, -2);
1480                                                 float time = luaL_checknumber(L, -1);
1481                                                 groupcap.times[rating] = time;
1482                                                 // removes value, keeps key for next iteration
1483                                                 lua_pop(L, 1);
1484                                         }
1485                                 }
1486                                 lua_pop(L, 1);
1487                                 // Insert groupcap into toolcap
1488                                 toolcap.groupcaps[groupname] = groupcap;
1489                         }
1490                         // removes value, keeps key for next iteration
1491                         lua_pop(L, 1);
1492                 }
1493         }
1494         lua_pop(L, 1);
1495
1496         lua_getfield(L, table, "damage_groups");
1497         if(lua_istable(L, -1)){
1498                 int table_damage_groups = lua_gettop(L);
1499                 lua_pushnil(L);
1500                 while(lua_next(L, table_damage_groups) != 0){
1501                         // key at index -2 and value at index -1
1502                         std::string groupname = luaL_checkstring(L, -2);
1503                         u16 value = luaL_checkinteger(L, -1);
1504                         toolcap.damageGroups[groupname] = value;
1505                         // removes value, keeps key for next iteration
1506                         lua_pop(L, 1);
1507                 }
1508         }
1509         lua_pop(L, 1);
1510         return toolcap;
1511 }
1512
1513 /******************************************************************************/
1514 void push_dig_params(lua_State *L,const DigParams &params)
1515 {
1516         lua_createtable(L, 0, 3);
1517         setboolfield(L, -1, "diggable", params.diggable);
1518         setfloatfield(L, -1, "time", params.time);
1519         setintfield(L, -1, "wear", params.wear);
1520 }
1521
1522 /******************************************************************************/
1523 void push_hit_params(lua_State *L,const HitParams &params)
1524 {
1525         lua_createtable(L, 0, 3);
1526         setintfield(L, -1, "hp", params.hp);
1527         setintfield(L, -1, "wear", params.wear);
1528 }
1529
1530 /******************************************************************************/
1531
1532 bool getflagsfield(lua_State *L, int table, const char *fieldname,
1533         FlagDesc *flagdesc, u32 *flags, u32 *flagmask)
1534 {
1535         lua_getfield(L, table, fieldname);
1536
1537         bool success = read_flags(L, -1, flagdesc, flags, flagmask);
1538
1539         lua_pop(L, 1);
1540
1541         return success;
1542 }
1543
1544 bool read_flags(lua_State *L, int index, FlagDesc *flagdesc,
1545         u32 *flags, u32 *flagmask)
1546 {
1547         if (lua_isstring(L, index)) {
1548                 std::string flagstr = lua_tostring(L, index);
1549                 *flags = readFlagString(flagstr, flagdesc, flagmask);
1550         } else if (lua_istable(L, index)) {
1551                 *flags = read_flags_table(L, index, flagdesc, flagmask);
1552         } else {
1553                 return false;
1554         }
1555
1556         return true;
1557 }
1558
1559 u32 read_flags_table(lua_State *L, int table, FlagDesc *flagdesc, u32 *flagmask)
1560 {
1561         u32 flags = 0, mask = 0;
1562         char fnamebuf[64] = "no";
1563
1564         for (int i = 0; flagdesc[i].name; i++) {
1565                 bool result;
1566
1567                 if (getboolfield(L, table, flagdesc[i].name, result)) {
1568                         mask |= flagdesc[i].flag;
1569                         if (result)
1570                                 flags |= flagdesc[i].flag;
1571                 }
1572
1573                 strlcpy(fnamebuf + 2, flagdesc[i].name, sizeof(fnamebuf) - 2);
1574                 if (getboolfield(L, table, fnamebuf, result))
1575                         mask |= flagdesc[i].flag;
1576         }
1577
1578         if (flagmask)
1579                 *flagmask = mask;
1580
1581         return flags;
1582 }
1583
1584 void push_flags_string(lua_State *L, FlagDesc *flagdesc, u32 flags, u32 flagmask)
1585 {
1586         std::string flagstring = writeFlagString(flags, flagdesc, flagmask);
1587         lua_pushlstring(L, flagstring.c_str(), flagstring.size());
1588 }
1589
1590 /******************************************************************************/
1591 /* Lua Stored data!                                                           */
1592 /******************************************************************************/
1593
1594 /******************************************************************************/
1595 void read_groups(lua_State *L, int index, ItemGroupList &result)
1596 {
1597         if (lua_isnil(L, index))
1598                 return;
1599
1600         luaL_checktype(L, index, LUA_TTABLE);
1601
1602         result.clear();
1603         lua_pushnil(L);
1604         if (index < 0)
1605                 index -= 1;
1606         while (lua_next(L, index) != 0) {
1607                 // key at index -2 and value at index -1
1608                 std::string name = luaL_checkstring(L, -2);
1609                 int rating = luaL_checkinteger(L, -1);
1610                 // zero rating indicates not in the group
1611                 if (rating != 0)
1612                         result[name] = rating;
1613                 // removes value, keeps key for next iteration
1614                 lua_pop(L, 1);
1615         }
1616 }
1617
1618 /******************************************************************************/
1619 void push_groups(lua_State *L, const ItemGroupList &groups)
1620 {
1621         lua_createtable(L, 0, groups.size());
1622         for (const auto &group : groups) {
1623                 lua_pushinteger(L, group.second);
1624                 lua_setfield(L, -2, group.first.c_str());
1625         }
1626 }
1627
1628 /******************************************************************************/
1629 void push_items(lua_State *L, const std::vector<ItemStack> &items)
1630 {
1631         lua_createtable(L, items.size(), 0);
1632         for (u32 i = 0; i != items.size(); i++) {
1633                 LuaItemStack::create(L, items[i]);
1634                 lua_rawseti(L, -2, i + 1);
1635         }
1636 }
1637
1638 /******************************************************************************/
1639 std::vector<ItemStack> read_items(lua_State *L, int index, IGameDef *gdef)
1640 {
1641         if(index < 0)
1642                 index = lua_gettop(L) + 1 + index;
1643
1644         std::vector<ItemStack> items;
1645         luaL_checktype(L, index, LUA_TTABLE);
1646         lua_pushnil(L);
1647         while (lua_next(L, index)) {
1648                 s32 key = luaL_checkinteger(L, -2);
1649                 if (key < 1) {
1650                         throw LuaError("Invalid inventory list index");
1651                 }
1652                 if (items.size() < (u32) key) {
1653                         items.resize(key);
1654                 }
1655                 items[key - 1] = read_item(L, -1, gdef->idef());
1656                 lua_pop(L, 1);
1657         }
1658         return items;
1659 }
1660
1661 /******************************************************************************/
1662 void luaentity_get(lua_State *L, u16 id)
1663 {
1664         // Get luaentities[i]
1665         lua_getglobal(L, "core");
1666         lua_getfield(L, -1, "luaentities");
1667         luaL_checktype(L, -1, LUA_TTABLE);
1668         lua_pushinteger(L, id);
1669         lua_gettable(L, -2);
1670         lua_remove(L, -2); // Remove luaentities
1671         lua_remove(L, -2); // Remove core
1672 }
1673
1674 /******************************************************************************/
1675 bool read_noiseparams(lua_State *L, int index, NoiseParams *np)
1676 {
1677         if (index < 0)
1678                 index = lua_gettop(L) + 1 + index;
1679
1680         if (!lua_istable(L, index))
1681                 return false;
1682
1683         getfloatfield(L, index, "offset",      np->offset);
1684         getfloatfield(L, index, "scale",       np->scale);
1685         getfloatfield(L, index, "persist",     np->persist);
1686         getfloatfield(L, index, "persistence", np->persist);
1687         getfloatfield(L, index, "lacunarity",  np->lacunarity);
1688         getintfield(L,   index, "seed",        np->seed);
1689         getintfield(L,   index, "octaves",     np->octaves);
1690
1691         u32 flags    = 0;
1692         u32 flagmask = 0;
1693         np->flags = getflagsfield(L, index, "flags", flagdesc_noiseparams,
1694                 &flags, &flagmask) ? flags : NOISE_FLAG_DEFAULTS;
1695
1696         lua_getfield(L, index, "spread");
1697         np->spread  = read_v3f(L, -1);
1698         lua_pop(L, 1);
1699
1700         return true;
1701 }
1702
1703 void push_noiseparams(lua_State *L, NoiseParams *np)
1704 {
1705         lua_newtable(L);
1706         setfloatfield(L, -1, "offset",      np->offset);
1707         setfloatfield(L, -1, "scale",       np->scale);
1708         setfloatfield(L, -1, "persist",     np->persist);
1709         setfloatfield(L, -1, "persistence", np->persist);
1710         setfloatfield(L, -1, "lacunarity",  np->lacunarity);
1711         setintfield(  L, -1, "seed",        np->seed);
1712         setintfield(  L, -1, "octaves",     np->octaves);
1713
1714         push_flags_string(L, flagdesc_noiseparams, np->flags,
1715                 np->flags);
1716         lua_setfield(L, -2, "flags");
1717
1718         push_v3f(L, np->spread);
1719         lua_setfield(L, -2, "spread");
1720 }
1721
1722 /******************************************************************************/
1723 // Returns depth of json value tree
1724 static int push_json_value_getdepth(const Json::Value &value)
1725 {
1726         if (!value.isArray() && !value.isObject())
1727                 return 1;
1728
1729         int maxdepth = 0;
1730         for (const auto &it : value) {
1731                 int elemdepth = push_json_value_getdepth(it);
1732                 if (elemdepth > maxdepth)
1733                         maxdepth = elemdepth;
1734         }
1735         return maxdepth + 1;
1736 }
1737 // Recursive function to convert JSON --> Lua table
1738 static bool push_json_value_helper(lua_State *L, const Json::Value &value,
1739                 int nullindex)
1740 {
1741         switch(value.type()) {
1742                 case Json::nullValue:
1743                 default:
1744                         lua_pushvalue(L, nullindex);
1745                         break;
1746                 case Json::intValue:
1747                         lua_pushinteger(L, value.asLargestInt());
1748                         break;
1749                 case Json::uintValue:
1750                         lua_pushinteger(L, value.asLargestUInt());
1751                         break;
1752                 case Json::realValue:
1753                         lua_pushnumber(L, value.asDouble());
1754                         break;
1755                 case Json::stringValue:
1756                         {
1757                                 const char *str = value.asCString();
1758                                 lua_pushstring(L, str ? str : "");
1759                         }
1760                         break;
1761                 case Json::booleanValue:
1762                         lua_pushboolean(L, value.asInt());
1763                         break;
1764                 case Json::arrayValue:
1765                         lua_createtable(L, value.size(), 0);
1766                         for (Json::Value::const_iterator it = value.begin();
1767                                         it != value.end(); ++it) {
1768                                 push_json_value_helper(L, *it, nullindex);
1769                                 lua_rawseti(L, -2, it.index() + 1);
1770                         }
1771                         break;
1772                 case Json::objectValue:
1773                         lua_createtable(L, 0, value.size());
1774                         for (Json::Value::const_iterator it = value.begin();
1775                                         it != value.end(); ++it) {
1776 #if !defined(JSONCPP_STRING) && (JSONCPP_VERSION_MAJOR < 1 || JSONCPP_VERSION_MINOR < 9)
1777                                 const char *str = it.memberName();
1778                                 lua_pushstring(L, str ? str : "");
1779 #else
1780                                 std::string str = it.name();
1781                                 lua_pushstring(L, str.c_str());
1782 #endif
1783                                 push_json_value_helper(L, *it, nullindex);
1784                                 lua_rawset(L, -3);
1785                         }
1786                         break;
1787         }
1788         return true;
1789 }
1790 // converts JSON --> Lua table; returns false if lua stack limit exceeded
1791 // nullindex: Lua stack index of value to use in place of JSON null
1792 bool push_json_value(lua_State *L, const Json::Value &value, int nullindex)
1793 {
1794         if(nullindex < 0)
1795                 nullindex = lua_gettop(L) + 1 + nullindex;
1796
1797         int depth = push_json_value_getdepth(value);
1798
1799         // The maximum number of Lua stack slots used at each recursion level
1800         // of push_json_value_helper is 2, so make sure there a depth * 2 slots
1801         if (lua_checkstack(L, depth * 2))
1802                 return push_json_value_helper(L, value, nullindex);
1803
1804         return false;
1805 }
1806
1807 // Converts Lua table --> JSON
1808 void read_json_value(lua_State *L, Json::Value &root, int index, u8 recursion)
1809 {
1810         if (recursion > 16) {
1811                 throw SerializationError("Maximum recursion depth exceeded");
1812         }
1813         int type = lua_type(L, index);
1814         if (type == LUA_TBOOLEAN) {
1815                 root = (bool) lua_toboolean(L, index);
1816         } else if (type == LUA_TNUMBER) {
1817                 root = lua_tonumber(L, index);
1818         } else if (type == LUA_TSTRING) {
1819                 size_t len;
1820                 const char *str = lua_tolstring(L, index, &len);
1821                 root = std::string(str, len);
1822         } else if (type == LUA_TTABLE) {
1823                 lua_pushnil(L);
1824                 while (lua_next(L, index)) {
1825                         // Key is at -2 and value is at -1
1826                         Json::Value value;
1827                         read_json_value(L, value, lua_gettop(L), recursion + 1);
1828
1829                         Json::ValueType roottype = root.type();
1830                         int keytype = lua_type(L, -1);
1831                         if (keytype == LUA_TNUMBER) {
1832                                 lua_Number key = lua_tonumber(L, -1);
1833                                 if (roottype != Json::nullValue && roottype != Json::arrayValue) {
1834                                         throw SerializationError("Can't mix array and object values in JSON");
1835                                 } else if (key < 1) {
1836                                         throw SerializationError("Can't use zero-based or negative indexes in JSON");
1837                                 } else if (floor(key) != key) {
1838                                         throw SerializationError("Can't use indexes with a fractional part in JSON");
1839                                 }
1840                                 root[(Json::ArrayIndex) key - 1] = value;
1841                         } else if (keytype == LUA_TSTRING) {
1842                                 if (roottype != Json::nullValue && roottype != Json::objectValue) {
1843                                         throw SerializationError("Can't mix array and object values in JSON");
1844                                 }
1845                                 root[lua_tostring(L, -1)] = value;
1846                         } else {
1847                                 throw SerializationError("Lua key to convert to JSON is not a string or number");
1848                         }
1849                 }
1850         } else if (type == LUA_TNIL) {
1851                 root = Json::nullValue;
1852         } else {
1853                 throw SerializationError("Can only store booleans, numbers, strings, objects, arrays, and null in JSON");
1854         }
1855         lua_pop(L, 1); // Pop value
1856 }
1857
1858 void push_pointed_thing(lua_State *L, const PointedThing &pointed, bool csm,
1859         bool hitpoint)
1860 {
1861         lua_newtable(L);
1862         if (pointed.type == POINTEDTHING_NODE) {
1863                 lua_pushstring(L, "node");
1864                 lua_setfield(L, -2, "type");
1865                 push_v3s16(L, pointed.node_undersurface);
1866                 lua_setfield(L, -2, "under");
1867                 push_v3s16(L, pointed.node_abovesurface);
1868                 lua_setfield(L, -2, "above");
1869         } else if (pointed.type == POINTEDTHING_OBJECT) {
1870                 lua_pushstring(L, "object");
1871                 lua_setfield(L, -2, "type");
1872
1873                 if (csm) {
1874                         lua_pushinteger(L, pointed.object_id);
1875                         lua_setfield(L, -2, "id");
1876                 } else {
1877                         push_objectRef(L, pointed.object_id);
1878                         lua_setfield(L, -2, "ref");
1879                 }
1880         } else {
1881                 lua_pushstring(L, "nothing");
1882                 lua_setfield(L, -2, "type");
1883         }
1884         if (hitpoint && (pointed.type != POINTEDTHING_NOTHING)) {
1885                 push_v3f(L, pointed.intersection_point / BS); // convert to node coords
1886                 lua_setfield(L, -2, "intersection_point");
1887                 push_v3f(L, pointed.intersection_normal);
1888                 lua_setfield(L, -2, "intersection_normal");
1889                 lua_pushinteger(L, pointed.box_id + 1); // change to Lua array index
1890                 lua_setfield(L, -2, "box_id");
1891         }
1892 }
1893
1894 void push_objectRef(lua_State *L, const u16 id)
1895 {
1896         // Get core.object_refs[i]
1897         lua_getglobal(L, "core");
1898         lua_getfield(L, -1, "object_refs");
1899         luaL_checktype(L, -1, LUA_TTABLE);
1900         lua_pushinteger(L, id);
1901         lua_gettable(L, -2);
1902         lua_remove(L, -2); // object_refs
1903         lua_remove(L, -2); // core
1904 }
1905
1906 void read_hud_element(lua_State *L, HudElement *elem)
1907 {
1908         elem->type = (HudElementType)getenumfield(L, 2, "hud_elem_type",
1909                                                                         es_HudElementType, HUD_ELEM_TEXT);
1910
1911         lua_getfield(L, 2, "position");
1912         elem->pos = lua_istable(L, -1) ? read_v2f(L, -1) : v2f();
1913         lua_pop(L, 1);
1914
1915         lua_getfield(L, 2, "scale");
1916         elem->scale = lua_istable(L, -1) ? read_v2f(L, -1) : v2f();
1917         lua_pop(L, 1);
1918
1919         lua_getfield(L, 2, "size");
1920         elem->size = lua_istable(L, -1) ? read_v2s32(L, -1) : v2s32();
1921         lua_pop(L, 1);
1922
1923         elem->name    = getstringfield_default(L, 2, "name", "");
1924         elem->text    = getstringfield_default(L, 2, "text", "");
1925         elem->number  = getintfield_default(L, 2, "number", 0);
1926         if (elem->type == HUD_ELEM_WAYPOINT)
1927                 // waypoints reuse the item field to store precision, item = precision + 1
1928                 elem->item = getintfield_default(L, 2, "precision", -1) + 1;
1929         else
1930                 elem->item = getintfield_default(L, 2, "item", 0);
1931         elem->dir     = getintfield_default(L, 2, "direction", 0);
1932         elem->z_index = MYMAX(S16_MIN, MYMIN(S16_MAX,
1933                         getintfield_default(L, 2, "z_index", 0)));
1934         elem->text2   = getstringfield_default(L, 2, "text2", "");
1935
1936         // Deprecated, only for compatibility's sake
1937         if (elem->dir == 0)
1938                 elem->dir = getintfield_default(L, 2, "dir", 0);
1939
1940         lua_getfield(L, 2, "alignment");
1941         elem->align = lua_istable(L, -1) ? read_v2f(L, -1) : v2f();
1942         lua_pop(L, 1);
1943
1944         lua_getfield(L, 2, "offset");
1945         elem->offset = lua_istable(L, -1) ? read_v2f(L, -1) : v2f();
1946         lua_pop(L, 1);
1947
1948         lua_getfield(L, 2, "world_pos");
1949         elem->world_pos = lua_istable(L, -1) ? read_v3f(L, -1) : v3f();
1950         lua_pop(L, 1);
1951
1952         elem->style = getintfield_default(L, 2, "style", 0);
1953
1954         /* check for known deprecated element usage */
1955         if ((elem->type  == HUD_ELEM_STATBAR) && (elem->size == v2s32()))
1956                 log_deprecated(L,"Deprecated usage of statbar without size!");
1957 }
1958
1959 void push_hud_element(lua_State *L, HudElement *elem)
1960 {
1961         lua_newtable(L);
1962
1963         lua_pushstring(L, es_HudElementType[(u8)elem->type].str);
1964         lua_setfield(L, -2, "type");
1965
1966         push_v2f(L, elem->pos);
1967         lua_setfield(L, -2, "position");
1968
1969         lua_pushstring(L, elem->name.c_str());
1970         lua_setfield(L, -2, "name");
1971
1972         push_v2f(L, elem->scale);
1973         lua_setfield(L, -2, "scale");
1974
1975         lua_pushstring(L, elem->text.c_str());
1976         lua_setfield(L, -2, "text");
1977
1978         lua_pushnumber(L, elem->number);
1979         lua_setfield(L, -2, "number");
1980
1981         if (elem->type == HUD_ELEM_WAYPOINT) {
1982                 // waypoints reuse the item field to store precision, precision = item - 1
1983                 lua_pushnumber(L, elem->item - 1);
1984                 lua_setfield(L, -2, "precision");
1985         }
1986         // push the item field for waypoints as well for backwards compatibility
1987         lua_pushnumber(L, elem->item);
1988         lua_setfield(L, -2, "item");
1989
1990         lua_pushnumber(L, elem->dir);
1991         lua_setfield(L, -2, "direction");
1992
1993         push_v2f(L, elem->offset);
1994         lua_setfield(L, -2, "offset");
1995
1996         push_v2f(L, elem->align);
1997         lua_setfield(L, -2, "alignment");
1998
1999         push_v2s32(L, elem->size);
2000         lua_setfield(L, -2, "size");
2001
2002         // Deprecated, only for compatibility's sake
2003         lua_pushnumber(L, elem->dir);
2004         lua_setfield(L, -2, "dir");
2005
2006         push_v3f(L, elem->world_pos);
2007         lua_setfield(L, -2, "world_pos");
2008
2009         lua_pushnumber(L, elem->z_index);
2010         lua_setfield(L, -2, "z_index");
2011
2012         lua_pushstring(L, elem->text2.c_str());
2013         lua_setfield(L, -2, "text2");
2014
2015         lua_pushinteger(L, elem->style);
2016         lua_setfield(L, -2, "style");
2017 }
2018
2019 bool read_hud_change(lua_State *L, HudElementStat &stat, HudElement *elem, void **value)
2020 {
2021         std::string statstr = lua_tostring(L, 3);
2022         {
2023                 int statint;
2024                 if (!string_to_enum(es_HudElementStat, statint, statstr)) {
2025                         script_log_unique(L, "Unknown HUD stat type: " + statstr, warningstream);
2026                         return false;
2027                 }
2028
2029                 stat = (HudElementStat)statint;
2030         }
2031
2032         switch (stat) {
2033                 case HUD_STAT_POS:
2034                         elem->pos = read_v2f(L, 4);
2035                         *value = &elem->pos;
2036                         break;
2037                 case HUD_STAT_NAME:
2038                         elem->name = luaL_checkstring(L, 4);
2039                         *value = &elem->name;
2040                         break;
2041                 case HUD_STAT_SCALE:
2042                         elem->scale = read_v2f(L, 4);
2043                         *value = &elem->scale;
2044                         break;
2045                 case HUD_STAT_TEXT:
2046                         elem->text = luaL_checkstring(L, 4);
2047                         *value = &elem->text;
2048                         break;
2049                 case HUD_STAT_NUMBER:
2050                         elem->number = luaL_checknumber(L, 4);
2051                         *value = &elem->number;
2052                         break;
2053                 case HUD_STAT_ITEM:
2054                         elem->item = luaL_checknumber(L, 4);
2055                         if (elem->type == HUD_ELEM_WAYPOINT && statstr == "precision")
2056                                 elem->item++;
2057                         *value = &elem->item;
2058                         break;
2059                 case HUD_STAT_DIR:
2060                         elem->dir = luaL_checknumber(L, 4);
2061                         *value = &elem->dir;
2062                         break;
2063                 case HUD_STAT_ALIGN:
2064                         elem->align = read_v2f(L, 4);
2065                         *value = &elem->align;
2066                         break;
2067                 case HUD_STAT_OFFSET:
2068                         elem->offset = read_v2f(L, 4);
2069                         *value = &elem->offset;
2070                         break;
2071                 case HUD_STAT_WORLD_POS:
2072                         elem->world_pos = read_v3f(L, 4);
2073                         *value = &elem->world_pos;
2074                         break;
2075                 case HUD_STAT_SIZE:
2076                         elem->size = read_v2s32(L, 4);
2077                         *value = &elem->size;
2078                         break;
2079                 case HUD_STAT_Z_INDEX:
2080                         elem->z_index = MYMAX(S16_MIN, MYMIN(S16_MAX, luaL_checknumber(L, 4)));
2081                         *value = &elem->z_index;
2082                         break;
2083                 case HUD_STAT_TEXT2:
2084                         elem->text2 = luaL_checkstring(L, 4);
2085                         *value = &elem->text2;
2086                         break;
2087                 case HUD_STAT_STYLE:
2088                         elem->style = luaL_checknumber(L, 4);
2089                         *value = &elem->style;
2090                         break;
2091         }
2092
2093         return true;
2094 }
2095
2096 /******************************************************************************/
2097
2098 // Indices must match values in `enum CollisionType` exactly!!
2099 static const char *collision_type_str[] = {
2100         "node",
2101         "object",
2102 };
2103
2104 // Indices must match values in `enum CollisionAxis` exactly!!
2105 static const char *collision_axis_str[] = {
2106         "x",
2107         "y",
2108         "z",
2109 };
2110
2111 void push_collision_move_result(lua_State *L, const collisionMoveResult &res)
2112 {
2113         lua_createtable(L, 0, 4);
2114
2115         setboolfield(L, -1, "touching_ground", res.touching_ground);
2116         setboolfield(L, -1, "collides", res.collides);
2117         setboolfield(L, -1, "standing_on_object", res.standing_on_object);
2118
2119         /* collisions */
2120         lua_createtable(L, res.collisions.size(), 0);
2121         int i = 1;
2122         for (const auto &c : res.collisions) {
2123                 lua_createtable(L, 0, 5);
2124
2125                 lua_pushstring(L, collision_type_str[c.type]);
2126                 lua_setfield(L, -2, "type");
2127
2128                 assert(c.axis != COLLISION_AXIS_NONE);
2129                 lua_pushstring(L, collision_axis_str[c.axis]);
2130                 lua_setfield(L, -2, "axis");
2131
2132                 if (c.type == COLLISION_NODE) {
2133                         push_v3s16(L, c.node_p);
2134                         lua_setfield(L, -2, "node_pos");
2135                 } else if (c.type == COLLISION_OBJECT) {
2136                         push_objectRef(L, c.object->getId());
2137                         lua_setfield(L, -2, "object");
2138                 }
2139
2140                 push_v3f(L, c.old_speed / BS);
2141                 lua_setfield(L, -2, "old_velocity");
2142
2143                 push_v3f(L, c.new_speed / BS);
2144                 lua_setfield(L, -2, "new_velocity");
2145
2146                 lua_rawseti(L, -2, i++);
2147         }
2148         lua_setfield(L, -2, "collisions");
2149         /**/
2150 }
2151
2152
2153 void push_mod_spec(lua_State *L, const ModSpec &spec, bool include_unsatisfied)
2154 {
2155         lua_newtable(L);
2156
2157         lua_pushstring(L, spec.name.c_str());
2158         lua_setfield(L, -2, "name");
2159
2160         lua_pushstring(L, spec.author.c_str());
2161         lua_setfield(L, -2, "author");
2162
2163         lua_pushinteger(L, spec.release);
2164         lua_setfield(L, -2, "release");
2165
2166         lua_pushstring(L, spec.desc.c_str());
2167         lua_setfield(L, -2, "description");
2168
2169         lua_pushstring(L, spec.path.c_str());
2170         lua_setfield(L, -2, "path");
2171
2172         lua_pushstring(L, spec.virtual_path.c_str());
2173         lua_setfield(L, -2, "virtual_path");
2174
2175         lua_newtable(L);
2176         int i = 1;
2177         for (const auto &dep : spec.unsatisfied_depends) {
2178                 lua_pushstring(L, dep.c_str());
2179                 lua_rawseti(L, -2, i++);
2180         }
2181         lua_setfield(L, -2, "unsatisfied_depends");
2182 }