1 /*
2 script/lua_api/l_mapgen.cpp
3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4 */
5 
6 /*
7 This file is part of Freeminer.
8 
9 Freeminer is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 Freeminer  is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with Freeminer.  If not, see <http://www.gnu.org/licenses/>.
21 */
22 
23 #include "lua_api/l_mapgen.h"
24 #include "lua_api/l_internal.h"
25 #include "lua_api/l_vmanip.h"
26 #include "common/c_converter.h"
27 #include "common/c_content.h"
28 #include "util/serialize.h"
29 #include "server.h"
30 #include "environment.h"
31 #include "emerge.h"
32 #include "mg_biome.h"
33 #include "mg_ore.h"
34 #include "mg_decoration.h"
35 #include "mg_schematic.h"
36 #include "mapgen_v7.h"
37 #include "settings.h"
38 #include "main.h"
39 #include "log.h"
40 
41 
42 struct EnumString ModApiMapgen::es_BiomeTerrainType[] =
43 {
44 	{BIOME_TYPE_NORMAL, "normal"},
45 	{BIOME_TYPE_LIQUID, "liquid"},
46 	{BIOME_TYPE_NETHER, "nether"},
47 	{BIOME_TYPE_AETHER, "aether"},
48 	{BIOME_TYPE_FLAT,   "flat"},
49 	{0, NULL},
50 };
51 
52 struct EnumString ModApiMapgen::es_DecorationType[] =
53 {
54 	{DECO_SIMPLE,    "simple"},
55 	{DECO_SCHEMATIC, "schematic"},
56 	{DECO_LSYSTEM,   "lsystem"},
57 	{0, NULL},
58 };
59 
60 struct EnumString ModApiMapgen::es_MapgenObject[] =
61 {
62 	{MGOBJ_VMANIP,    "voxelmanip"},
63 	{MGOBJ_HEIGHTMAP, "heightmap"},
64 	{MGOBJ_BIOMEMAP,  "biomemap"},
65 	{MGOBJ_HEATMAP,   "heatmap"},
66 	{MGOBJ_HUMIDMAP,  "humiditymap"},
67 	{MGOBJ_GENNOTIFY, "gennotify"},
68 	{0, NULL},
69 };
70 
71 struct EnumString ModApiMapgen::es_OreType[] =
72 {
73 	{ORE_SCATTER,  "scatter"},
74 	{ORE_SHEET,    "sheet"},
75 	{ORE_CLAYLIKE, "claylike"},
76 	{0, NULL},
77 };
78 
79 struct EnumString ModApiMapgen::es_Rotation[] =
80 {
81 	{ROTATE_0,    "0"},
82 	{ROTATE_90,   "90"},
83 	{ROTATE_180,  "180"},
84 	{ROTATE_270,  "270"},
85 	{ROTATE_RAND, "random"},
86 	{0, NULL},
87 };
88 
89 
read_schematic_replacements(lua_State * L,std::map<std::string,std::string> & replace_names,int index)90 static void read_schematic_replacements(lua_State *L,
91 	std::map<std::string, std::string> &replace_names, int index)
92 {
93 	lua_pushnil(L);
94 	while (lua_next(L, index)) {
95 		std::string replace_from;
96 		std::string replace_to;
97 
98 		if (lua_istable(L, -1)) { // Old {{"x", "y"}, ...} format
99 			lua_rawgeti(L, -1, 1);
100 			replace_from = lua_tostring(L, -1);
101 			lua_pop(L, 1);
102 
103 			lua_rawgeti(L, -1, 2);
104 			replace_to = lua_tostring(L, -1);
105 			lua_pop(L, 1);
106 		} else { // New {x = "y", ...} format
107 			replace_from = lua_tostring(L, -2);
108 			replace_to = lua_tostring(L, -1);
109 		}
110 
111 		replace_names[replace_from] = replace_to;
112 		lua_pop(L, 1);
113 	}
114 }
115 
116 
117 // get_mapgen_object(objectname)
118 // returns the requested object used during map generation
l_get_mapgen_object(lua_State * L)119 int ModApiMapgen::l_get_mapgen_object(lua_State *L)
120 {
121 	const char *mgobjstr = lua_tostring(L, 1);
122 
123 	int mgobjint;
124 	if (!string_to_enum(es_MapgenObject, mgobjint, mgobjstr ? mgobjstr : ""))
125 		return 0;
126 
127 	enum MapgenObject mgobj = (MapgenObject)mgobjint;
128 
129 	EmergeManager *emerge = getServer(L)->getEmergeManager();
130 	Mapgen *mg = emerge->getCurrentMapgen();
131 	if (!mg)
132 		return 0;
133 
134 	size_t maplen = mg->csize.X * mg->csize.Z;
135 
136 	switch (mgobj) {
137 		case MGOBJ_VMANIP: {
138 			ManualMapVoxelManipulator *vm = mg->vm;
139 
140 			// VoxelManip object
141 			LuaVoxelManip *o = new LuaVoxelManip(vm, true);
142 			*(void **)(lua_newuserdata(L, sizeof(void *))) = o;
143 			luaL_getmetatable(L, "VoxelManip");
144 			lua_setmetatable(L, -2);
145 
146 			// emerged min pos
147 			push_v3s16(L, vm->m_area.MinEdge);
148 
149 			// emerged max pos
150 			push_v3s16(L, vm->m_area.MaxEdge);
151 
152 			return 3;
153 		}
154 		case MGOBJ_HEIGHTMAP: {
155 			if (!mg->heightmap)
156 				return 0;
157 
158 			lua_newtable(L);
159 			for (size_t i = 0; i != maplen; i++) {
160 				lua_pushinteger(L, mg->heightmap[i]);
161 				lua_rawseti(L, -2, i + 1);
162 			}
163 
164 			return 1;
165 		}
166 		case MGOBJ_BIOMEMAP: {
167 			if (!mg->biomemap)
168 				return 0;
169 
170 			lua_newtable(L);
171 			for (size_t i = 0; i != maplen; i++) {
172 				lua_pushinteger(L, mg->biomemap[i]);
173 				lua_rawseti(L, -2, i + 1);
174 			}
175 
176 			return 1;
177 		}
178 		case MGOBJ_HEATMAP: { // Mapgen V7 specific objects
179 		case MGOBJ_HUMIDMAP:
180 			if (strcmp(emerge->params.mg_name.c_str(), "v7"))
181 				return 0;
182 
183 			MapgenV7 *mgv7 = (MapgenV7 *)mg;
184 
185 			float *arr = (mgobj == MGOBJ_HEATMAP) ?
186 				mgv7->noise_heat->result : mgv7->noise_humidity->result;
187 			if (!arr)
188 				return 0;
189 
190 			lua_newtable(L);
191 			for (size_t i = 0; i != maplen; i++) {
192 				lua_pushnumber(L, arr[i]);
193 				lua_rawseti(L, -2, i + 1);
194 			}
195 
196 			return 1;
197 		}
198 		case MGOBJ_GENNOTIFY: {
199 			lua_newtable(L);
200 			for (int i = 0; flagdesc_gennotify[i].name; i++) {
201 				if (!(emerge->gennotify & flagdesc_gennotify[i].flag))
202 					continue;
203 
204 				std::vector<v3s16> *posvec = mg->gen_notifications[i];
205 				if (!posvec)
206 					return 0;
207 
208 				lua_newtable(L);
209 				for (unsigned int j = 0; j != posvec->size(); j++) {
210 					push_v3s16(L, (*posvec)[j]);
211 					lua_rawseti(L, -2, j + 1);
212 				}
213 				lua_setfield(L, -2, flagdesc_gennotify[i].name);
214 
215 				posvec->clear();
216 			}
217 
218 			return 1;
219 		}
220 	}
221 
222 	return 0;
223 }
224 
225 // set_mapgen_params(params)
226 // set mapgen parameters
l_set_mapgen_params(lua_State * L)227 int ModApiMapgen::l_set_mapgen_params(lua_State *L)
228 {
229 	if (!lua_istable(L, 1))
230 		return 0;
231 
232 	EmergeManager *emerge = getServer(L)->getEmergeManager();
233 	assert(emerge);
234 
235 	std::string flagstr;
236 	u32 flags = 0, flagmask = 0;
237 
238 	lua_getfield(L, 1, "mgname");
239 	if (lua_isstring(L, -1)) {
240 		emerge->params.mg_name = std::string(lua_tostring(L, -1));
241 		delete emerge->params.sparams;
242 		emerge->params.sparams = NULL;
243 	}
244 
245 	lua_getfield(L, 1, "seed");
246 	if (lua_isnumber(L, -1))
247 		emerge->params.seed = lua_tointeger(L, -1);
248 
249 	lua_getfield(L, 1, "water_level");
250 	if (lua_isnumber(L, -1))
251 		emerge->params.water_level = lua_tointeger(L, -1);
252 
253 	lua_getfield(L, 1, "flagmask");
254 	if (lua_isstring(L, -1)) {
255 		flagstr = lua_tostring(L, -1);
256 		emerge->params.flags &= ~readFlagString(flagstr, flagdesc_mapgen, NULL);
257 		errorstream << "set_mapgen_params(): flagmask field is deprecated, "
258 			"see lua_api.txt" << std::endl;
259 	}
260 
261 	if (getflagsfield(L, 1, "flags", flagdesc_mapgen, &flags, &flagmask)) {
262 		emerge->params.flags &= ~flagmask;
263 		emerge->params.flags |= flags;
264 	}
265 
266 	return 0;
267 }
268 
269 // set_noiseparam_defaults({np1={noise params}, ...})
270 // set default values for noise parameters if not present in global settings
l_set_noiseparam_defaults(lua_State * L)271 int ModApiMapgen::l_set_noiseparam_defaults(lua_State *L)
272 {
273 	NoiseParams np;
274 	std::string val, name;
275 
276 	if (!lua_istable(L, 1))
277 		return 0;
278 
279 	lua_pushnil(L);
280 	while (lua_next(L, 1)) {
281 		if (read_noiseparams_nc(L, -1, &np)) {
282 			if (!serializeStructToString(&val, NOISEPARAMS_FMT_STR, &np))
283 				continue;
284 			if (!lua_isstring(L, -2))
285 				continue;
286 
287 			name = lua_tostring(L, -2);
288 			g_settings->setDefault(name, val);
289 		}
290 		lua_pop(L, 1);
291 	}
292 
293 	return 0;
294 }
295 
296 // set_gen_notify(string)
l_set_gen_notify(lua_State * L)297 int ModApiMapgen::l_set_gen_notify(lua_State *L)
298 {
299 	u32 flags = 0, flagmask = 0;
300 
301 	if (read_flags(L, 1, flagdesc_gennotify, &flags, &flagmask)) {
302 		EmergeManager *emerge = getServer(L)->getEmergeManager();
303 		emerge->gennotify = flags;
304 	}
305 
306 	return 0;
307 }
308 
309 // register_biome({lots of stuff})
l_register_biome(lua_State * L)310 int ModApiMapgen::l_register_biome(lua_State *L)
311 {
312 	int index = 1;
313 	luaL_checktype(L, index, LUA_TTABLE);
314 
315 	NodeResolver *resolver = getServer(L)->getNodeDefManager()->getResolver();
316 	BiomeManager *bmgr     = getServer(L)->getEmergeManager()->biomemgr;
317 
318 	enum BiomeType biometype = (BiomeType)getenumfield(L, index, "type",
319 		es_BiomeTerrainType, BIOME_TYPE_NORMAL);
320 	Biome *b = bmgr->create(biometype);
321 
322 	b->name           = getstringfield_default(L, index, "name", "");
323 	b->depth_top      = getintfield_default(L, index, "depth_top",    1);
324 	b->depth_filler   = getintfield_default(L, index, "depth_filler", 3);
325 	b->height_min     = getintfield_default(L, index, "height_min",   0);
326 	b->height_max     = getintfield_default(L, index, "height_max",   0);
327 	b->heat_point     = getfloatfield_default(L, index, "heat_point",     0.);
328 	b->humidity_point = getfloatfield_default(L, index, "humidity_point", 0.);
329 	b->flags          = 0; //reserved
330 
331 	u32 id = bmgr->add(b);
332 	if (id == (u32)-1) {
333 		delete b;
334 		return 0;
335 	}
336 
337 	// Pend node resolutions only if insertion succeeded
338 	resolver->addNode(getstringfield_default(L, index, "node_top", ""),
339 		 "mapgen_dirt_with_grass", CONTENT_AIR, &b->c_top);
340 	resolver->addNode(getstringfield_default(L, index, "node_filler", ""),
341 		"mapgen_dirt", CONTENT_AIR, &b->c_filler);
342 	resolver->addNode(getstringfield_default(L, index, "node_water", ""),
343 		"mapgen_water_source", CONTENT_AIR, &b->c_water);
344 	resolver->addNode(getstringfield_default(L, index, "node_dust", ""),
345 		"air", CONTENT_IGNORE, &b->c_dust);
346 	resolver->addNode(getstringfield_default(L, index, "node_dust_water", ""),
347 		"mapgen_water_source", CONTENT_IGNORE, &b->c_dust_water);
348 
349 	resolver->addNode(getstringfield_default(L, index, "node_top_cold", ""),
350 		 "mapgen_dirt_with_snow", b->c_top, &b->c_top_cold);
351 	resolver->addNode(getstringfield_default(L, index, "node_ice", ""),
352 		"mapgen_ice", b->c_water, &b->c_ice);
353 
354 	verbosestream << "register_biome: " << b->name << std::endl;
355 
356 	lua_pushinteger(L, id);
357 	return 1;
358 }
359 
360 // register_decoration({lots of stuff})
l_register_decoration(lua_State * L)361 int ModApiMapgen::l_register_decoration(lua_State *L)
362 {
363 	int index = 1;
364 	luaL_checktype(L, index, LUA_TTABLE);
365 
366 	INodeDefManager *ndef      = getServer(L)->getNodeDefManager();
367 	NodeResolver *resolver     = getServer(L)->getNodeDefManager()->getResolver();
368 	DecorationManager *decomgr = getServer(L)->getEmergeManager()->decomgr;
369 	BiomeManager *biomemgr     = getServer(L)->getEmergeManager()->biomemgr;
370 
371 	enum DecorationType decotype = (DecorationType)getenumfield(L, index,
372 				"deco_type", es_DecorationType, -1);
373 
374 	Decoration *deco = decomgr->create(decotype);
375 	if (!deco) {
376 		errorstream << "register_decoration: decoration placement type "
377 			<< decotype << " not implemented";
378 		return 0;
379 	}
380 
381 	deco->name       = getstringfield_default(L, index, "name", "");
382 	deco->fill_ratio = getfloatfield_default(L, index, "fill_ratio", 0.02);
383 	deco->sidelen    = getintfield_default(L, index, "sidelen", 8);
384 	if (deco->sidelen <= 0) {
385 		errorstream << "register_decoration: sidelen must be "
386 			"greater than 0" << std::endl;
387 		delete deco;
388 		return 0;
389 	}
390 
391 	//// Get node name(s) to place decoration on
392 	std::vector<const char *> place_on_names;
393 	getstringlistfield(L, index, "place_on", place_on_names);
394 	for (size_t i = 0; i != place_on_names.size(); i++)
395 		resolver->addNodeList(place_on_names[i], &deco->c_place_on);
396 
397 	//// Get NoiseParams to define how decoration is placed
398 	lua_getfield(L, index, "noise_params");
399 	deco->np = read_noiseparams(L, -1);
400 	lua_pop(L, 1);
401 
402 	//// Get biomes associated with this decoration (if any)
403 	std::vector<const char *> biome_list;
404 	getstringlistfield(L, index, "biomes", biome_list);
405 	for (size_t i = 0; i != biome_list.size(); i++) {
406 		Biome *b = (Biome *)biomemgr->getByName(biome_list[i]);
407 		if (!b)
408 			continue;
409 
410 		deco->biomes.insert(b->id);
411 	}
412 
413 	//// Handle decoration type-specific parameters
414 	bool success = false;
415 	switch (decotype) {
416 		case DECO_SIMPLE:
417 			success = regDecoSimple(L, resolver, (DecoSimple *)deco);
418 			break;
419 		case DECO_SCHEMATIC:
420 			success = regDecoSchematic(L, ndef, (DecoSchematic *)deco);
421 			break;
422 		case DECO_LSYSTEM:
423 			break;
424 	}
425 
426 	if (!success) {
427 		delete deco;
428 		return 0;
429 	}
430 
431 	u32 id = decomgr->add(deco);
432 	if (id == (u32)-1) {
433 		delete deco;
434 		return 0;
435 	}
436 
437 	lua_pushinteger(L, id);
438 	return 1;
439 }
440 
regDecoSimple(lua_State * L,NodeResolver * resolver,DecoSimple * deco)441 bool ModApiMapgen::regDecoSimple(lua_State *L,
442 		NodeResolver *resolver, DecoSimple *deco)
443 {
444 	int index = 1;
445 
446 	deco->deco_height     = getintfield_default(L, index, "height", 1);
447 	deco->deco_height_max = getintfield_default(L, index, "height_max", 0);
448 	deco->nspawnby        = getintfield_default(L, index, "num_spawn_by", -1);
449 
450 	if (deco->deco_height <= 0) {
451 		errorstream << "register_decoration: simple decoration height"
452 			" must be greater than 0" << std::endl;
453 		return false;
454 	}
455 
456 	std::vector<const char *> deco_names;
457 	getstringlistfield(L, index, "decoration", deco_names);
458 	if (deco_names.size() == 0) {
459 		errorstream << "register_decoration: no decoration nodes "
460 			"defined" << std::endl;
461 		return false;
462 	}
463 
464 	std::vector<const char *> spawnby_names;
465 	getstringlistfield(L, index, "spawn_by", spawnby_names);
466 	if (deco->nspawnby != -1 && spawnby_names.size() == 0) {
467 		errorstream << "register_decoration: no spawn_by nodes defined,"
468 			" but num_spawn_by specified" << std::endl;
469 		return false;
470 	}
471 
472 	for (size_t i = 0; i != deco_names.size(); i++)
473 		resolver->addNodeList(deco_names[i], &deco->c_decos);
474 	for (size_t i = 0; i != spawnby_names.size(); i++)
475 		resolver->addNodeList(spawnby_names[i], &deco->c_spawnby);
476 
477 	return true;
478 }
479 
regDecoSchematic(lua_State * L,INodeDefManager * ndef,DecoSchematic * deco)480 bool ModApiMapgen::regDecoSchematic(lua_State *L, INodeDefManager *ndef,
481 	DecoSchematic *deco)
482 {
483 	int index = 1;
484 
485 	deco->flags = 0;
486 	getflagsfield(L, index, "flags", flagdesc_deco_schematic, &deco->flags, NULL);
487 
488 	deco->rotation = (Rotation)getenumfield(L, index, "rotation",
489 		es_Rotation, ROTATE_0);
490 
491 	std::map<std::string, std::string> replace_names;
492 	lua_getfield(L, index, "replacements");
493 	if (lua_istable(L, -1))
494 		read_schematic_replacements(L, replace_names, lua_gettop(L));
495 	lua_pop(L, 1);
496 
497 	Schematic *schem = new Schematic;
498 	lua_getfield(L, index, "schematic");
499 	if (!get_schematic(L, -1, schem, ndef, replace_names)) {
500 		lua_pop(L, 1);
501 		delete schem;
502 		return false;
503 	}
504 	lua_pop(L, 1);
505 
506 	deco->schematic = schem;
507 
508 	return true;
509 }
510 
511 // register_ore({lots of stuff})
l_register_ore(lua_State * L)512 int ModApiMapgen::l_register_ore(lua_State *L)
513 {
514 	int index = 1;
515 	luaL_checktype(L, index, LUA_TTABLE);
516 
517 	NodeResolver *resolver = getServer(L)->getNodeDefManager()->getResolver();
518 	OreManager *oremgr     = getServer(L)->getEmergeManager()->oremgr;
519 
520 	enum OreType oretype = (OreType)getenumfield(L, index,
521 				"ore_type", es_OreType, ORE_SCATTER);
522 	Ore *ore = oremgr->create(oretype);
523 	if (!ore) {
524 		errorstream << "register_ore: ore_type " << oretype << " not implemented";
525 		return 0;
526 	}
527 
528 	ore->name           = getstringfield_default(L, index, "name", "");
529 	ore->ore_param2     = (u8)getintfield_default(L, index, "ore_param2", 0);
530 	ore->clust_scarcity = getintfield_default(L, index, "clust_scarcity", 1);
531 	ore->clust_num_ores = getintfield_default(L, index, "clust_num_ores", 1);
532 	ore->clust_size     = getintfield_default(L, index, "clust_size", 0);
533 	ore->height_min     = getintfield_default(L, index, "height_min", 0);
534 	ore->height_max     = getintfield_default(L, index, "height_max", 0);
535 	ore->nthresh        = getfloatfield_default(L, index, "noise_threshhold", 0);
536 	ore->noise          = NULL;
537 	ore->flags          = 0;
538 
539 	if (ore->clust_scarcity <= 0 || ore->clust_num_ores <= 0) {
540 		errorstream << "register_ore: clust_scarcity and clust_num_ores"
541 			"must be greater than 0" << std::endl;
542 		delete ore;
543 		return 0;
544 	}
545 
546 	getflagsfield(L, index, "flags", flagdesc_ore, &ore->flags, NULL);
547 
548 	lua_getfield(L, index, "noise_params");
549 	ore->np = read_noiseparams(L, -1);
550 	lua_pop(L, 1);
551 
552 	u32 id = oremgr->add(ore);
553 	if (id == (u32)-1) {
554 		delete ore;
555 		return 0;
556 	}
557 
558 	std::vector<const char *> wherein_names;
559 	getstringlistfield(L, index, "wherein", wherein_names);
560 	for (size_t i = 0; i != wherein_names.size(); i++)
561 		resolver->addNodeList(wherein_names[i], &ore->c_wherein);
562 
563 	resolver->addNode(getstringfield_default(L, index, "ore", ""),
564 		"", CONTENT_AIR, &ore->c_ore);
565 
566 	lua_pushinteger(L, id);
567 	return 1;
568 }
569 
570 // create_schematic(p1, p2, probability_list, filename)
l_create_schematic(lua_State * L)571 int ModApiMapgen::l_create_schematic(lua_State *L)
572 {
573 	Schematic schem;
574 
575 	Map *map = &(getEnv(L)->getMap());
576 	INodeDefManager *ndef = getServer(L)->getNodeDefManager();
577 
578 	v3s16 p1 = read_v3s16(L, 1);
579 	v3s16 p2 = read_v3s16(L, 2);
580 	sortBoxVerticies(p1, p2);
581 
582 	std::vector<std::pair<v3s16, u8> > prob_list;
583 	if (lua_istable(L, 3)) {
584 		lua_pushnil(L);
585 		while (lua_next(L, 3)) {
586 			if (lua_istable(L, -1)) {
587 				lua_getfield(L, -1, "pos");
588 				v3s16 pos = read_v3s16(L, -1);
589 				lua_pop(L, 1);
590 
591 				u8 prob = getintfield_default(L, -1, "prob", MTSCHEM_PROB_ALWAYS);
592 				prob_list.push_back(std::make_pair(pos, prob));
593 			}
594 
595 			lua_pop(L, 1);
596 		}
597 	}
598 
599 	std::vector<std::pair<s16, u8> > slice_prob_list;
600 	if (lua_istable(L, 5)) {
601 		lua_pushnil(L);
602 		while (lua_next(L, 5)) {
603 			if (lua_istable(L, -1)) {
604 				s16 ypos = getintfield_default(L, -1, "ypos", 0);
605 				u8 prob  = getintfield_default(L, -1, "prob", MTSCHEM_PROB_ALWAYS);
606 				slice_prob_list.push_back(std::make_pair(ypos, prob));
607 			}
608 
609 			lua_pop(L, 1);
610 		}
611 	}
612 
613 	const char *filename = luaL_checkstring(L, 4);
614 
615 	if (!schem.getSchematicFromMap(map, p1, p2)) {
616 		errorstream << "create_schematic: failed to get schematic "
617 			"from map" << std::endl;
618 		return 0;
619 	}
620 
621 	schem.applyProbabilities(p1, &prob_list, &slice_prob_list);
622 
623 	schem.saveSchematicToFile(filename, ndef);
624 	actionstream << "create_schematic: saved schematic file '"
625 		<< filename << "'." << std::endl;
626 
627 	return 1;
628 }
629 
630 // place_schematic(p, schematic, rotation, replacement)
l_place_schematic(lua_State * L)631 int ModApiMapgen::l_place_schematic(lua_State *L)
632 {
633 	Schematic schem;
634 
635 	Map *map = &(getEnv(L)->getMap());
636 	INodeDefManager *ndef = getServer(L)->getNodeDefManager();
637 
638 	//// Read position
639 	v3s16 p = read_v3s16(L, 1);
640 
641 	//// Read rotation
642 	int rot = ROTATE_0;
643 	if (lua_isstring(L, 3))
644 		string_to_enum(es_Rotation, rot, std::string(lua_tostring(L, 3)));
645 
646 	//// Read force placement
647 	bool force_placement = true;
648 	if (lua_isboolean(L, 5))
649 		force_placement = lua_toboolean(L, 5);
650 
651 	//// Read node replacements
652 	std::map<std::string, std::string> replace_names;
653 	if (lua_istable(L, 4))
654 		read_schematic_replacements(L, replace_names, 4);
655 
656 	//// Read schematic
657 	if (!get_schematic(L, 2, &schem, ndef, replace_names)) {
658 		errorstream << "place_schematic: failed to get schematic" << std::endl;
659 		return 0;
660 	}
661 
662 	schem.placeStructure(map, p, 0, (Rotation)rot, force_placement, ndef);
663 
664 	return 1;
665 }
666 
Initialize(lua_State * L,int top)667 void ModApiMapgen::Initialize(lua_State *L, int top)
668 {
669 	API_FCT(get_mapgen_object);
670 
671 	API_FCT(set_mapgen_params);
672 	API_FCT(set_noiseparam_defaults);
673 	API_FCT(set_gen_notify);
674 
675 	API_FCT(register_biome);
676 	API_FCT(register_decoration);
677 	API_FCT(register_ore);
678 
679 	API_FCT(create_schematic);
680 	API_FCT(place_schematic);
681 }
682