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