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