Schematic decorations: Add 'place_offset_y' placement parameter
[oweals/minetest.git] / src / script / lua_api / l_mapgen.cpp
1 /*
2 Minetest
3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "lua_api/l_mapgen.h"
21 #include "lua_api/l_internal.h"
22 #include "lua_api/l_vmanip.h"
23 #include "common/c_converter.h"
24 #include "common/c_content.h"
25 #include "cpp_api/s_security.h"
26 #include "util/serialize.h"
27 #include "server.h"
28 #include "environment.h"
29 #include "emerge.h"
30 #include "mg_biome.h"
31 #include "mg_ore.h"
32 #include "mg_decoration.h"
33 #include "mg_schematic.h"
34 #include "mapgen_v5.h"
35 #include "mapgen_v7.h"
36 #include "filesys.h"
37 #include "settings.h"
38 #include "log.h"
39
40 struct EnumString ModApiMapgen::es_BiomeTerrainType[] =
41 {
42         {BIOMETYPE_NORMAL, "normal"},
43         {BIOMETYPE_LIQUID, "liquid"},
44         {BIOMETYPE_NETHER, "nether"},
45         {BIOMETYPE_AETHER, "aether"},
46         {BIOMETYPE_FLAT,   "flat"},
47         {0, NULL},
48 };
49
50 struct EnumString ModApiMapgen::es_DecorationType[] =
51 {
52         {DECO_SIMPLE,    "simple"},
53         {DECO_SCHEMATIC, "schematic"},
54         {DECO_LSYSTEM,   "lsystem"},
55         {0, NULL},
56 };
57
58 struct EnumString ModApiMapgen::es_MapgenObject[] =
59 {
60         {MGOBJ_VMANIP,    "voxelmanip"},
61         {MGOBJ_HEIGHTMAP, "heightmap"},
62         {MGOBJ_BIOMEMAP,  "biomemap"},
63         {MGOBJ_HEATMAP,   "heatmap"},
64         {MGOBJ_HUMIDMAP,  "humiditymap"},
65         {MGOBJ_GENNOTIFY, "gennotify"},
66         {0, NULL},
67 };
68
69 struct EnumString ModApiMapgen::es_OreType[] =
70 {
71         {ORE_SCATTER, "scatter"},
72         {ORE_SHEET,   "sheet"},
73         {ORE_PUFF,    "puff"},
74         {ORE_BLOB,    "blob"},
75         {ORE_VEIN,    "vein"},
76         {ORE_STRATUM, "stratum"},
77         {0, NULL},
78 };
79
80 struct EnumString ModApiMapgen::es_Rotation[] =
81 {
82         {ROTATE_0,    "0"},
83         {ROTATE_90,   "90"},
84         {ROTATE_180,  "180"},
85         {ROTATE_270,  "270"},
86         {ROTATE_RAND, "random"},
87         {0, NULL},
88 };
89
90 struct EnumString ModApiMapgen::es_SchematicFormatType[] =
91 {
92         {SCHEM_FMT_HANDLE, "handle"},
93         {SCHEM_FMT_MTS,    "mts"},
94         {SCHEM_FMT_LUA,    "lua"},
95         {0, NULL},
96 };
97
98 ObjDef *get_objdef(lua_State *L, int index, ObjDefManager *objmgr);
99
100 Biome *get_or_load_biome(lua_State *L, int index,
101         BiomeManager *biomemgr);
102 Biome *read_biome_def(lua_State *L, int index, INodeDefManager *ndef);
103 size_t get_biome_list(lua_State *L, int index,
104         BiomeManager *biomemgr, std::unordered_set<u8> *biome_id_list);
105
106 Schematic *get_or_load_schematic(lua_State *L, int index,
107         SchematicManager *schemmgr, StringMap *replace_names);
108 Schematic *load_schematic(lua_State *L, int index, INodeDefManager *ndef,
109         StringMap *replace_names);
110 Schematic *load_schematic_from_def(lua_State *L, int index,
111         INodeDefManager *ndef, StringMap *replace_names);
112 bool read_schematic_def(lua_State *L, int index,
113         Schematic *schem, std::vector<std::string> *names);
114
115 bool read_deco_simple(lua_State *L, DecoSimple *deco);
116 bool read_deco_schematic(lua_State *L, SchematicManager *schemmgr, DecoSchematic *deco);
117
118
119 ///////////////////////////////////////////////////////////////////////////////
120
121 ObjDef *get_objdef(lua_State *L, int index, ObjDefManager *objmgr)
122 {
123         if (index < 0)
124                 index = lua_gettop(L) + 1 + index;
125
126         // If a number, assume this is a handle to an object def
127         if (lua_isnumber(L, index))
128                 return objmgr->get(lua_tointeger(L, index));
129
130         // If a string, assume a name is given instead
131         if (lua_isstring(L, index))
132                 return objmgr->getByName(lua_tostring(L, index));
133
134         return NULL;
135 }
136
137 ///////////////////////////////////////////////////////////////////////////////
138
139 Schematic *get_or_load_schematic(lua_State *L, int index,
140         SchematicManager *schemmgr, StringMap *replace_names)
141 {
142         if (index < 0)
143                 index = lua_gettop(L) + 1 + index;
144
145         Schematic *schem = (Schematic *)get_objdef(L, index, schemmgr);
146         if (schem)
147                 return schem;
148
149         schem = load_schematic(L, index, schemmgr->getNodeDef(),
150                 replace_names);
151         if (!schem)
152                 return NULL;
153
154         if (schemmgr->add(schem) == OBJDEF_INVALID_HANDLE) {
155                 delete schem;
156                 return NULL;
157         }
158
159         return schem;
160 }
161
162
163 Schematic *load_schematic(lua_State *L, int index, INodeDefManager *ndef,
164         StringMap *replace_names)
165 {
166         if (index < 0)
167                 index = lua_gettop(L) + 1 + index;
168
169         Schematic *schem = NULL;
170
171         if (lua_istable(L, index)) {
172                 schem = load_schematic_from_def(L, index, ndef,
173                         replace_names);
174                 if (!schem) {
175                         delete schem;
176                         return NULL;
177                 }
178         } else if (lua_isnumber(L, index)) {
179                 return NULL;
180         } else if (lua_isstring(L, index)) {
181                 schem = SchematicManager::create(SCHEMATIC_NORMAL);
182
183                 std::string filepath = lua_tostring(L, index);
184                 if (!fs::IsPathAbsolute(filepath))
185                         filepath = ModApiBase::getCurrentModPath(L) + DIR_DELIM + filepath;
186
187                 if (!schem->loadSchematicFromFile(filepath, ndef,
188                                 replace_names)) {
189                         delete schem;
190                         return NULL;
191                 }
192         }
193
194         return schem;
195 }
196
197
198 Schematic *load_schematic_from_def(lua_State *L, int index,
199         INodeDefManager *ndef, StringMap *replace_names)
200 {
201         Schematic *schem = SchematicManager::create(SCHEMATIC_NORMAL);
202
203         if (!read_schematic_def(L, index, schem, &schem->m_nodenames)) {
204                 delete schem;
205                 return NULL;
206         }
207
208         size_t num_nodes = schem->m_nodenames.size();
209
210         schem->m_nnlistsizes.push_back(num_nodes);
211
212         if (replace_names) {
213                 for (size_t i = 0; i != num_nodes; i++) {
214                         StringMap::iterator it = replace_names->find(schem->m_nodenames[i]);
215                         if (it != replace_names->end())
216                                 schem->m_nodenames[i] = it->second;
217                 }
218         }
219
220         if (ndef)
221                 ndef->pendNodeResolve(schem);
222
223         return schem;
224 }
225
226
227 bool read_schematic_def(lua_State *L, int index,
228         Schematic *schem, std::vector<std::string> *names)
229 {
230         if (!lua_istable(L, index))
231                 return false;
232
233         //// Get schematic size
234         lua_getfield(L, index, "size");
235         v3s16 size = check_v3s16(L, -1);
236         lua_pop(L, 1);
237
238         schem->size = size;
239
240         //// Get schematic data
241         lua_getfield(L, index, "data");
242         luaL_checktype(L, -1, LUA_TTABLE);
243
244         u32 numnodes = size.X * size.Y * size.Z;
245         schem->schemdata = new MapNode[numnodes];
246
247         size_t names_base = names->size();
248         std::unordered_map<std::string, content_t> name_id_map;
249
250         u32 i = 0;
251         for (lua_pushnil(L); lua_next(L, -2); i++, lua_pop(L, 1)) {
252                 if (i >= numnodes)
253                         continue;
254
255                 //// Read name
256                 std::string name;
257                 if (!getstringfield(L, -1, "name", name))
258                         throw LuaError("Schematic data definition with missing name field");
259
260                 //// Read param1/prob
261                 u8 param1;
262                 if (!getintfield(L, -1, "param1", param1) &&
263                         !getintfield(L, -1, "prob", param1))
264                         param1 = MTSCHEM_PROB_ALWAYS_OLD;
265
266                 //// Read param2
267                 u8 param2 = getintfield_default(L, -1, "param2", 0);
268
269                 //// Find or add new nodename-to-ID mapping
270                 std::unordered_map<std::string, content_t>::iterator it = name_id_map.find(name);
271                 content_t name_index;
272                 if (it != name_id_map.end()) {
273                         name_index = it->second;
274                 } else {
275                         name_index = names->size() - names_base;
276                         name_id_map[name] = name_index;
277                         names->push_back(name);
278                 }
279
280                 //// Perform probability/force_place fixup on param1
281                 param1 >>= 1;
282                 if (getboolfield_default(L, -1, "force_place", false))
283                         param1 |= MTSCHEM_FORCE_PLACE;
284
285                 //// Actually set the node in the schematic
286                 schem->schemdata[i] = MapNode(name_index, param1, param2);
287         }
288
289         if (i != numnodes) {
290                 errorstream << "read_schematic_def: incorrect number of "
291                         "nodes provided in raw schematic data (got " << i <<
292                         ", expected " << numnodes << ")." << std::endl;
293                 return false;
294         }
295
296         //// Get Y-slice probability values (if present)
297         schem->slice_probs = new u8[size.Y];
298         for (i = 0; i != (u32) size.Y; i++)
299                 schem->slice_probs[i] = MTSCHEM_PROB_ALWAYS;
300
301         lua_getfield(L, index, "yslice_prob");
302         if (lua_istable(L, -1)) {
303                 for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) {
304                         u16 ypos;
305                         if (!getintfield(L, -1, "ypos", ypos) || (ypos >= size.Y) ||
306                                 !getintfield(L, -1, "prob", schem->slice_probs[ypos]))
307                                 continue;
308
309                         schem->slice_probs[ypos] >>= 1;
310                 }
311         }
312
313         return true;
314 }
315
316
317 void read_schematic_replacements(lua_State *L, int index, StringMap *replace_names)
318 {
319         if (index < 0)
320                 index = lua_gettop(L) + 1 + index;
321
322         lua_pushnil(L);
323         while (lua_next(L, index)) {
324                 std::string replace_from;
325                 std::string replace_to;
326
327                 if (lua_istable(L, -1)) { // Old {{"x", "y"}, ...} format
328                         lua_rawgeti(L, -1, 1);
329                         if (!lua_isstring(L, -1))
330                                 throw LuaError("schematics: replace_from field is not a string");
331                         replace_from = lua_tostring(L, -1);
332                         lua_pop(L, 1);
333
334                         lua_rawgeti(L, -1, 2);
335                         if (!lua_isstring(L, -1))
336                                 throw LuaError("schematics: replace_to field is not a string");
337                         replace_to = lua_tostring(L, -1);
338                         lua_pop(L, 1);
339                 } else { // New {x = "y", ...} format
340                         if (!lua_isstring(L, -2))
341                                 throw LuaError("schematics: replace_from field is not a string");
342                         replace_from = lua_tostring(L, -2);
343                         if (!lua_isstring(L, -1))
344                                 throw LuaError("schematics: replace_to field is not a string");
345                         replace_to = lua_tostring(L, -1);
346                 }
347
348                 replace_names->insert(std::make_pair(replace_from, replace_to));
349                 lua_pop(L, 1);
350         }
351 }
352
353 ///////////////////////////////////////////////////////////////////////////////
354
355 Biome *get_or_load_biome(lua_State *L, int index, BiomeManager *biomemgr)
356 {
357         if (index < 0)
358                 index = lua_gettop(L) + 1 + index;
359
360         Biome *biome = (Biome *)get_objdef(L, index, biomemgr);
361         if (biome)
362                 return biome;
363
364         biome = read_biome_def(L, index, biomemgr->getNodeDef());
365         if (!biome)
366                 return NULL;
367
368         if (biomemgr->add(biome) == OBJDEF_INVALID_HANDLE) {
369                 delete biome;
370                 return NULL;
371         }
372
373         return biome;
374 }
375
376
377 Biome *read_biome_def(lua_State *L, int index, INodeDefManager *ndef)
378 {
379         if (!lua_istable(L, index))
380                 return NULL;
381
382         BiomeType biometype = (BiomeType)getenumfield(L, index, "type",
383                 ModApiMapgen::es_BiomeTerrainType, BIOMETYPE_NORMAL);
384         Biome *b = BiomeManager::create(biometype);
385
386         b->name            = getstringfield_default(L, index, "name", "");
387         b->depth_top       = getintfield_default(L,    index, "depth_top",       0);
388         b->depth_filler    = getintfield_default(L,    index, "depth_filler",    -31000);
389         b->depth_water_top = getintfield_default(L,    index, "depth_water_top", 0);
390         b->depth_riverbed  = getintfield_default(L,    index, "depth_riverbed",  0);
391         b->y_min           = getintfield_default(L,    index, "y_min",           -31000);
392         b->y_max           = getintfield_default(L,    index, "y_max",           31000);
393         b->heat_point      = getfloatfield_default(L,  index, "heat_point",      0.f);
394         b->humidity_point  = getfloatfield_default(L,  index, "humidity_point",  0.f);
395         b->flags           = 0; //reserved
396
397         std::vector<std::string> &nn = b->m_nodenames;
398         nn.push_back(getstringfield_default(L, index, "node_top",         ""));
399         nn.push_back(getstringfield_default(L, index, "node_filler",      ""));
400         nn.push_back(getstringfield_default(L, index, "node_stone",       ""));
401         nn.push_back(getstringfield_default(L, index, "node_water_top",   ""));
402         nn.push_back(getstringfield_default(L, index, "node_water",       ""));
403         nn.push_back(getstringfield_default(L, index, "node_river_water", ""));
404         nn.push_back(getstringfield_default(L, index, "node_riverbed",    ""));
405         nn.push_back(getstringfield_default(L, index, "node_dust",        ""));
406         ndef->pendNodeResolve(b);
407
408         return b;
409 }
410
411
412 size_t get_biome_list(lua_State *L, int index,
413         BiomeManager *biomemgr, std::unordered_set<u8> *biome_id_list)
414 {
415         if (index < 0)
416                 index = lua_gettop(L) + 1 + index;
417
418         if (lua_isnil(L, index))
419                 return 0;
420
421         bool is_single = true;
422         if (lua_istable(L, index)) {
423                 lua_getfield(L, index, "name");
424                 is_single = !lua_isnil(L, -1);
425                 lua_pop(L, 1);
426         }
427
428         if (is_single) {
429                 Biome *biome = get_or_load_biome(L, index, biomemgr);
430                 if (!biome) {
431                         infostream << "get_biome_list: failed to get biome '"
432                                 << (lua_isstring(L, index) ? lua_tostring(L, index) : "")
433                                 << "'." << std::endl;
434                         return 1;
435                 }
436
437                 biome_id_list->insert(biome->index);
438                 return 0;
439         }
440
441         // returns number of failed resolutions
442         size_t fail_count = 0;
443         size_t count = 0;
444
445         for (lua_pushnil(L); lua_next(L, index); lua_pop(L, 1)) {
446                 count++;
447                 Biome *biome = get_or_load_biome(L, -1, biomemgr);
448                 if (!biome) {
449                         fail_count++;
450                         infostream << "get_biome_list: failed to get biome '"
451                                 << (lua_isstring(L, -1) ? lua_tostring(L, -1) : "")
452                                 << "'" << std::endl;
453                         continue;
454                 }
455
456                 biome_id_list->insert(biome->index);
457         }
458
459         return fail_count;
460 }
461
462 ///////////////////////////////////////////////////////////////////////////////
463
464 // get_biome_id(biomename)
465 // returns the biome id used in biomemap
466 int ModApiMapgen::l_get_biome_id(lua_State *L)
467 {
468         NO_MAP_LOCK_REQUIRED;
469
470         const char *biome_str = lua_tostring(L, 1);
471         if (!biome_str)
472                 return 0;
473
474         BiomeManager *bmgr = getServer(L)->getEmergeManager()->biomemgr;
475
476         if (!bmgr)
477                 return 0;
478
479         Biome *biome = (Biome *)bmgr->getByName(biome_str);
480
481         if (!biome || biome->index == OBJDEF_INVALID_INDEX)
482                 return 0;
483
484         lua_pushinteger(L, biome->index);
485
486         return 1;
487 }
488
489
490 // get_mapgen_object(objectname)
491 // returns the requested object used during map generation
492 int ModApiMapgen::l_get_mapgen_object(lua_State *L)
493 {
494         NO_MAP_LOCK_REQUIRED;
495
496         const char *mgobjstr = lua_tostring(L, 1);
497
498         int mgobjint;
499         if (!string_to_enum(es_MapgenObject, mgobjint, mgobjstr ? mgobjstr : ""))
500                 return 0;
501
502         enum MapgenObject mgobj = (MapgenObject)mgobjint;
503
504         EmergeManager *emerge = getServer(L)->getEmergeManager();
505         Mapgen *mg = emerge->getCurrentMapgen();
506         if (!mg)
507                 throw LuaError("Must only be called in a mapgen thread!");
508
509         size_t maplen = mg->csize.X * mg->csize.Z;
510
511         switch (mgobj) {
512         case MGOBJ_VMANIP: {
513                 MMVManip *vm = mg->vm;
514
515                 // VoxelManip object
516                 LuaVoxelManip *o = new LuaVoxelManip(vm, true);
517                 *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
518                 luaL_getmetatable(L, "VoxelManip");
519                 lua_setmetatable(L, -2);
520
521                 // emerged min pos
522                 push_v3s16(L, vm->m_area.MinEdge);
523
524                 // emerged max pos
525                 push_v3s16(L, vm->m_area.MaxEdge);
526
527                 return 3;
528         }
529         case MGOBJ_HEIGHTMAP: {
530                 if (!mg->heightmap)
531                         return 0;
532
533                 lua_newtable(L);
534                 for (size_t i = 0; i != maplen; i++) {
535                         lua_pushinteger(L, mg->heightmap[i]);
536                         lua_rawseti(L, -2, i + 1);
537                 }
538
539                 return 1;
540         }
541         case MGOBJ_BIOMEMAP: {
542                 if (!mg->biomegen)
543                         return 0;
544
545                 lua_newtable(L);
546                 for (size_t i = 0; i != maplen; i++) {
547                         lua_pushinteger(L, mg->biomegen->biomemap[i]);
548                         lua_rawseti(L, -2, i + 1);
549                 }
550
551                 return 1;
552         }
553         case MGOBJ_HEATMAP: {
554                 if (!mg->biomegen || mg->biomegen->getType() != BIOMEGEN_ORIGINAL)
555                         return 0;
556
557                 BiomeGenOriginal *bg = (BiomeGenOriginal *)mg->biomegen;
558
559                 lua_newtable(L);
560                 for (size_t i = 0; i != maplen; i++) {
561                         lua_pushnumber(L, bg->heatmap[i]);
562                         lua_rawseti(L, -2, i + 1);
563                 }
564
565                 return 1;
566         }
567
568         case MGOBJ_HUMIDMAP: {
569                 if (!mg->biomegen || mg->biomegen->getType() != BIOMEGEN_ORIGINAL)
570                         return 0;
571
572                 BiomeGenOriginal *bg = (BiomeGenOriginal *)mg->biomegen;
573
574                 lua_newtable(L);
575                 for (size_t i = 0; i != maplen; i++) {
576                         lua_pushnumber(L, bg->humidmap[i]);
577                         lua_rawseti(L, -2, i + 1);
578                 }
579
580                 return 1;
581         }
582         case MGOBJ_GENNOTIFY: {
583                 std::map<std::string, std::vector<v3s16> >event_map;
584                 std::map<std::string, std::vector<v3s16> >::iterator it;
585
586                 mg->gennotify.getEvents(event_map);
587
588                 lua_newtable(L);
589                 for (it = event_map.begin(); it != event_map.end(); ++it) {
590                         lua_newtable(L);
591
592                         for (size_t j = 0; j != it->second.size(); j++) {
593                                 push_v3s16(L, it->second[j]);
594                                 lua_rawseti(L, -2, j + 1);
595                         }
596
597                         lua_setfield(L, -2, it->first.c_str());
598                 }
599
600                 return 1;
601         }
602         }
603
604         return 0;
605 }
606
607
608 int ModApiMapgen::l_get_mapgen_params(lua_State *L)
609 {
610         NO_MAP_LOCK_REQUIRED;
611
612         log_deprecated(L, "get_mapgen_params is deprecated; "
613                 "use get_mapgen_setting instead");
614
615         std::string value;
616
617         MapSettingsManager *settingsmgr =
618                 getServer(L)->getEmergeManager()->map_settings_mgr;
619
620         lua_newtable(L);
621
622         settingsmgr->getMapSetting("mg_name", &value);
623         lua_pushstring(L, value.c_str());
624         lua_setfield(L, -2, "mgname");
625
626         settingsmgr->getMapSetting("seed", &value);
627         std::istringstream ss(value);
628         u64 seed;
629         ss >> seed;
630         lua_pushinteger(L, seed);
631         lua_setfield(L, -2, "seed");
632
633         settingsmgr->getMapSetting("water_level", &value);
634         lua_pushinteger(L, stoi(value, -32768, 32767));
635         lua_setfield(L, -2, "water_level");
636
637         settingsmgr->getMapSetting("chunksize", &value);
638         lua_pushinteger(L, stoi(value, -32768, 32767));
639         lua_setfield(L, -2, "chunksize");
640
641         settingsmgr->getMapSetting("mg_flags", &value);
642         lua_pushstring(L, value.c_str());
643         lua_setfield(L, -2, "flags");
644
645         return 1;
646 }
647
648
649 // set_mapgen_params(params)
650 // set mapgen parameters
651 int ModApiMapgen::l_set_mapgen_params(lua_State *L)
652 {
653         NO_MAP_LOCK_REQUIRED;
654
655         log_deprecated(L, "set_mapgen_params is deprecated; "
656                 "use set_mapgen_setting instead");
657
658         if (!lua_istable(L, 1))
659                 return 0;
660
661         MapSettingsManager *settingsmgr =
662                 getServer(L)->getEmergeManager()->map_settings_mgr;
663
664         lua_getfield(L, 1, "mgname");
665         if (lua_isstring(L, -1))
666                 settingsmgr->setMapSetting("mg_name", lua_tostring(L, -1), true);
667
668         lua_getfield(L, 1, "seed");
669         if (lua_isnumber(L, -1))
670                 settingsmgr->setMapSetting("seed", lua_tostring(L, -1), true);
671
672         lua_getfield(L, 1, "water_level");
673         if (lua_isnumber(L, -1))
674                 settingsmgr->setMapSetting("water_level", lua_tostring(L, -1), true);
675
676         lua_getfield(L, 1, "chunksize");
677         if (lua_isnumber(L, -1))
678                 settingsmgr->setMapSetting("chunksize", lua_tostring(L, -1), true);
679
680         warn_if_field_exists(L, 1, "flagmask",
681                 "Deprecated: flags field now includes unset flags.");
682
683         lua_getfield(L, 1, "flags");
684         if (lua_isstring(L, -1))
685                 settingsmgr->setMapSetting("mg_flags", lua_tostring(L, -1), true);
686
687         return 0;
688 }
689
690 // get_mapgen_setting(name)
691 int ModApiMapgen::l_get_mapgen_setting(lua_State *L)
692 {
693         NO_MAP_LOCK_REQUIRED;
694
695         std::string value;
696         MapSettingsManager *settingsmgr =
697                 getServer(L)->getEmergeManager()->map_settings_mgr;
698
699         const char *name = luaL_checkstring(L, 1);
700         if (!settingsmgr->getMapSetting(name, &value))
701                 return 0;
702
703         lua_pushstring(L, value.c_str());
704         return 1;
705 }
706
707 // get_mapgen_setting_noiseparams(name)
708 int ModApiMapgen::l_get_mapgen_setting_noiseparams(lua_State *L)
709 {
710         NO_MAP_LOCK_REQUIRED;
711
712         NoiseParams np;
713         MapSettingsManager *settingsmgr =
714                 getServer(L)->getEmergeManager()->map_settings_mgr;
715
716         const char *name = luaL_checkstring(L, 1);
717         if (!settingsmgr->getMapSettingNoiseParams(name, &np))
718                 return 0;
719
720         push_noiseparams(L, &np);
721         return 1;
722 }
723
724 // set_mapgen_setting(name, value, override_meta)
725 // set mapgen config values
726 int ModApiMapgen::l_set_mapgen_setting(lua_State *L)
727 {
728         NO_MAP_LOCK_REQUIRED;
729
730         MapSettingsManager *settingsmgr =
731                 getServer(L)->getEmergeManager()->map_settings_mgr;
732
733         const char *name   = luaL_checkstring(L, 1);
734         const char *value  = luaL_checkstring(L, 2);
735         bool override_meta = lua_isboolean(L, 3) && lua_toboolean(L, 3);
736
737         if (!settingsmgr->setMapSetting(name, value, override_meta)) {
738                 errorstream << "set_mapgen_setting: cannot set '"
739                         << name << "' after initialization" << std::endl;
740         }
741
742         return 0;
743 }
744
745
746 // set_mapgen_setting_noiseparams(name, noiseparams, set_default)
747 // set mapgen config values for noise parameters
748 int ModApiMapgen::l_set_mapgen_setting_noiseparams(lua_State *L)
749 {
750         NO_MAP_LOCK_REQUIRED;
751
752         MapSettingsManager *settingsmgr =
753                 getServer(L)->getEmergeManager()->map_settings_mgr;
754
755         const char *name = luaL_checkstring(L, 1);
756
757         NoiseParams np;
758         if (!read_noiseparams(L, 2, &np)) {
759                 errorstream << "set_mapgen_setting_noiseparams: cannot set '" << name
760                         << "'; invalid noiseparams table" << std::endl;
761                 return 0;
762         }
763
764         bool override_meta = lua_isboolean(L, 3) && lua_toboolean(L, 3);
765
766         if (!settingsmgr->setMapSettingNoiseParams(name, &np, override_meta)) {
767                 errorstream << "set_mapgen_setting_noiseparams: cannot set '"
768                         << name << "' after initialization" << std::endl;
769         }
770
771         return 0;
772 }
773
774
775 // set_noiseparams(name, noiseparams, set_default)
776 // set global config values for noise parameters
777 int ModApiMapgen::l_set_noiseparams(lua_State *L)
778 {
779         NO_MAP_LOCK_REQUIRED;
780
781         const char *name = luaL_checkstring(L, 1);
782
783         NoiseParams np;
784         if (!read_noiseparams(L, 2, &np)) {
785                 errorstream << "set_noiseparams: cannot set '" << name
786                         << "'; invalid noiseparams table" << std::endl;
787                 return 0;
788         }
789
790         bool set_default = !lua_isboolean(L, 3) || lua_toboolean(L, 3);
791
792         g_settings->setNoiseParams(name, np, set_default);
793
794         return 0;
795 }
796
797
798 // get_noiseparams(name)
799 int ModApiMapgen::l_get_noiseparams(lua_State *L)
800 {
801         NO_MAP_LOCK_REQUIRED;
802
803         std::string name = luaL_checkstring(L, 1);
804
805         NoiseParams np;
806         if (!g_settings->getNoiseParams(name, np))
807                 return 0;
808
809         push_noiseparams(L, &np);
810         return 1;
811 }
812
813
814 // set_gen_notify(flags, {deco_id_table})
815 int ModApiMapgen::l_set_gen_notify(lua_State *L)
816 {
817         NO_MAP_LOCK_REQUIRED;
818
819         u32 flags = 0, flagmask = 0;
820         EmergeManager *emerge = getServer(L)->getEmergeManager();
821
822         if (read_flags(L, 1, flagdesc_gennotify, &flags, &flagmask)) {
823                 emerge->gen_notify_on &= ~flagmask;
824                 emerge->gen_notify_on |= flags;
825         }
826
827         if (lua_istable(L, 2)) {
828                 lua_pushnil(L);
829                 while (lua_next(L, 2)) {
830                         if (lua_isnumber(L, -1))
831                                 emerge->gen_notify_on_deco_ids.insert((u32)lua_tonumber(L, -1));
832                         lua_pop(L, 1);
833                 }
834         }
835
836         return 0;
837 }
838
839
840 // get_gen_notify()
841 int ModApiMapgen::l_get_gen_notify(lua_State *L)
842 {
843         NO_MAP_LOCK_REQUIRED;
844
845         EmergeManager *emerge = getServer(L)->getEmergeManager();
846         push_flags_string(L, flagdesc_gennotify, emerge->gen_notify_on,
847                 emerge->gen_notify_on);
848
849         lua_newtable(L);
850         int i = 1;
851         for (u32 gen_notify_on_deco_id : emerge->gen_notify_on_deco_ids) {
852                 lua_pushnumber(L, gen_notify_on_deco_id);
853                 lua_rawseti(L, -2, i);
854                 i++;
855         }
856         return 2;
857 }
858
859
860 // register_biome({lots of stuff})
861 int ModApiMapgen::l_register_biome(lua_State *L)
862 {
863         NO_MAP_LOCK_REQUIRED;
864
865         int index = 1;
866         luaL_checktype(L, index, LUA_TTABLE);
867
868         INodeDefManager *ndef = getServer(L)->getNodeDefManager();
869         BiomeManager *bmgr    = getServer(L)->getEmergeManager()->biomemgr;
870
871         Biome *biome = read_biome_def(L, index, ndef);
872         if (!biome)
873                 return 0;
874
875         ObjDefHandle handle = bmgr->add(biome);
876         if (handle == OBJDEF_INVALID_HANDLE) {
877                 delete biome;
878                 return 0;
879         }
880
881         lua_pushinteger(L, handle);
882         return 1;
883 }
884
885
886 // register_decoration({lots of stuff})
887 int ModApiMapgen::l_register_decoration(lua_State *L)
888 {
889         NO_MAP_LOCK_REQUIRED;
890
891         int index = 1;
892         luaL_checktype(L, index, LUA_TTABLE);
893
894         INodeDefManager *ndef      = getServer(L)->getNodeDefManager();
895         DecorationManager *decomgr = getServer(L)->getEmergeManager()->decomgr;
896         BiomeManager *biomemgr     = getServer(L)->getEmergeManager()->biomemgr;
897         SchematicManager *schemmgr = getServer(L)->getEmergeManager()->schemmgr;
898
899         enum DecorationType decotype = (DecorationType)getenumfield(L, index,
900                                 "deco_type", es_DecorationType, -1);
901
902         Decoration *deco = decomgr->create(decotype);
903         if (!deco) {
904                 errorstream << "register_decoration: decoration placement type "
905                         << decotype << " not implemented" << std::endl;
906                 return 0;
907         }
908
909         deco->name       = getstringfield_default(L, index, "name", "");
910         deco->fill_ratio = getfloatfield_default(L, index, "fill_ratio", 0.02);
911         deco->y_min      = getintfield_default(L, index, "y_min", -31000);
912         deco->y_max      = getintfield_default(L, index, "y_max", 31000);
913         deco->nspawnby   = getintfield_default(L, index, "num_spawn_by", -1);
914         deco->sidelen    = getintfield_default(L, index, "sidelen", 8);
915         if (deco->sidelen <= 0) {
916                 errorstream << "register_decoration: sidelen must be "
917                         "greater than 0" << std::endl;
918                 delete deco;
919                 return 0;
920         }
921
922         //// Get node name(s) to place decoration on
923         size_t nread = getstringlistfield(L, index, "place_on", &deco->m_nodenames);
924         deco->m_nnlistsizes.push_back(nread);
925
926         //// Get decoration flags
927         getflagsfield(L, index, "flags", flagdesc_deco, &deco->flags, NULL);
928
929         //// Get NoiseParams to define how decoration is placed
930         lua_getfield(L, index, "noise_params");
931         if (read_noiseparams(L, -1, &deco->np))
932                 deco->flags |= DECO_USE_NOISE;
933         lua_pop(L, 1);
934
935         //// Get biomes associated with this decoration (if any)
936         lua_getfield(L, index, "biomes");
937         if (get_biome_list(L, -1, biomemgr, &deco->biomes))
938                 infostream << "register_decoration: couldn't get all biomes " << std::endl;
939         lua_pop(L, 1);
940
941         //// Get node name(s) to 'spawn by'
942         size_t nnames = getstringlistfield(L, index, "spawn_by", &deco->m_nodenames);
943         deco->m_nnlistsizes.push_back(nnames);
944         if (nnames == 0 && deco->nspawnby != -1) {
945                 errorstream << "register_decoration: no spawn_by nodes defined,"
946                         " but num_spawn_by specified" << std::endl;
947         }
948
949         //// Handle decoration type-specific parameters
950         bool success = false;
951         switch (decotype) {
952         case DECO_SIMPLE:
953                 success = read_deco_simple(L, (DecoSimple *)deco);
954                 break;
955         case DECO_SCHEMATIC:
956                 success = read_deco_schematic(L, schemmgr, (DecoSchematic *)deco);
957                 break;
958         case DECO_LSYSTEM:
959                 break;
960         }
961
962         if (!success) {
963                 delete deco;
964                 return 0;
965         }
966
967         ndef->pendNodeResolve(deco);
968
969         ObjDefHandle handle = decomgr->add(deco);
970         if (handle == OBJDEF_INVALID_HANDLE) {
971                 delete deco;
972                 return 0;
973         }
974
975         lua_pushinteger(L, handle);
976         return 1;
977 }
978
979
980 bool read_deco_simple(lua_State *L, DecoSimple *deco)
981 {
982         int index = 1;
983         int param2;
984
985         deco->deco_height     = getintfield_default(L, index, "height", 1);
986         deco->deco_height_max = getintfield_default(L, index, "height_max", 0);
987
988         if (deco->deco_height <= 0) {
989                 errorstream << "register_decoration: simple decoration height"
990                         " must be greater than 0" << std::endl;
991                 return false;
992         }
993
994         size_t nnames = getstringlistfield(L, index, "decoration", &deco->m_nodenames);
995         deco->m_nnlistsizes.push_back(nnames);
996         if (nnames == 0) {
997                 errorstream << "register_decoration: no decoration nodes "
998                         "defined" << std::endl;
999                 return false;
1000         }
1001
1002         param2 = getintfield_default(L, index, "param2", 0);
1003         if ((param2 < 0) || (param2 > 255)) {
1004                 errorstream << "register_decoration: param2 out of bounds (0-255)"
1005                         << std::endl;
1006                 return false;
1007         }
1008         deco->deco_param2 = (u8)param2;
1009
1010         return true;
1011 }
1012
1013
1014 bool read_deco_schematic(lua_State *L, SchematicManager *schemmgr, DecoSchematic *deco)
1015 {
1016         int index = 1;
1017
1018         deco->rotation = (Rotation)getenumfield(L, index, "rotation",
1019                 ModApiMapgen::es_Rotation, ROTATE_0);
1020
1021         deco->place_offset_y = getintfield_default(L, index, "place_offset_y", 0);
1022
1023         StringMap replace_names;
1024         lua_getfield(L, index, "replacements");
1025         if (lua_istable(L, -1))
1026                 read_schematic_replacements(L, -1, &replace_names);
1027         lua_pop(L, 1);
1028
1029         lua_getfield(L, index, "schematic");
1030         Schematic *schem = get_or_load_schematic(L, -1, schemmgr, &replace_names);
1031         lua_pop(L, 1);
1032
1033         deco->schematic = schem;
1034         return schem != NULL;
1035 }
1036
1037
1038 // register_ore({lots of stuff})
1039 int ModApiMapgen::l_register_ore(lua_State *L)
1040 {
1041         NO_MAP_LOCK_REQUIRED;
1042
1043         int index = 1;
1044         luaL_checktype(L, index, LUA_TTABLE);
1045
1046         INodeDefManager *ndef = getServer(L)->getNodeDefManager();
1047         BiomeManager *bmgr    = getServer(L)->getEmergeManager()->biomemgr;
1048         OreManager *oremgr    = getServer(L)->getEmergeManager()->oremgr;
1049
1050         enum OreType oretype = (OreType)getenumfield(L, index,
1051                                 "ore_type", es_OreType, ORE_SCATTER);
1052         Ore *ore = oremgr->create(oretype);
1053         if (!ore) {
1054                 errorstream << "register_ore: ore_type " << oretype << " not implemented\n";
1055                 return 0;
1056         }
1057
1058         ore->name           = getstringfield_default(L, index, "name", "");
1059         ore->ore_param2     = (u8)getintfield_default(L, index, "ore_param2", 0);
1060         ore->clust_scarcity = getintfield_default(L, index, "clust_scarcity", 1);
1061         ore->clust_num_ores = getintfield_default(L, index, "clust_num_ores", 1);
1062         ore->clust_size     = getintfield_default(L, index, "clust_size", 0);
1063         ore->noise          = NULL;
1064         ore->flags          = 0;
1065
1066         //// Get noise_threshold
1067         warn_if_field_exists(L, index, "noise_threshhold",
1068                 "Deprecated: new name is \"noise_threshold\".");
1069
1070         float nthresh;
1071         if (!getfloatfield(L, index, "noise_threshold", nthresh) &&
1072                         !getfloatfield(L, index, "noise_threshhold", nthresh))
1073                 nthresh = 0;
1074         ore->nthresh = nthresh;
1075
1076         //// Get y_min/y_max
1077         warn_if_field_exists(L, index, "height_min",
1078                 "Deprecated: new name is \"y_min\".");
1079         warn_if_field_exists(L, index, "height_max",
1080                 "Deprecated: new name is \"y_max\".");
1081
1082         int ymin, ymax;
1083         if (!getintfield(L, index, "y_min", ymin) &&
1084                 !getintfield(L, index, "height_min", ymin))
1085                 ymin = -31000;
1086         if (!getintfield(L, index, "y_max", ymax) &&
1087                 !getintfield(L, index, "height_max", ymax))
1088                 ymax = 31000;
1089         ore->y_min = ymin;
1090         ore->y_max = ymax;
1091
1092         if (ore->clust_scarcity <= 0 || ore->clust_num_ores <= 0) {
1093                 errorstream << "register_ore: clust_scarcity and clust_num_ores"
1094                         "must be greater than 0" << std::endl;
1095                 delete ore;
1096                 return 0;
1097         }
1098
1099         //// Get flags
1100         getflagsfield(L, index, "flags", flagdesc_ore, &ore->flags, NULL);
1101
1102         //// Get biomes associated with this decoration (if any)
1103         lua_getfield(L, index, "biomes");
1104         if (get_biome_list(L, -1, bmgr, &ore->biomes))
1105                 infostream << "register_ore: couldn't get all biomes " << std::endl;
1106         lua_pop(L, 1);
1107
1108         //// Get noise parameters if needed
1109         lua_getfield(L, index, "noise_params");
1110         if (read_noiseparams(L, -1, &ore->np)) {
1111                 ore->flags |= OREFLAG_USE_NOISE;
1112         } else if (ore->NEEDS_NOISE) {
1113                 errorstream << "register_ore: specified ore type requires valid "
1114                         "noise parameters" << std::endl;
1115                 delete ore;
1116                 return 0;
1117         }
1118         lua_pop(L, 1);
1119
1120         //// Get type-specific parameters
1121         switch (oretype) {
1122                 case ORE_SHEET: {
1123                         OreSheet *oresheet = (OreSheet *)ore;
1124
1125                         oresheet->column_height_min = getintfield_default(L, index,
1126                                 "column_height_min", 1);
1127                         oresheet->column_height_max = getintfield_default(L, index,
1128                                 "column_height_max", ore->clust_size);
1129                         oresheet->column_midpoint_factor = getfloatfield_default(L, index,
1130                                 "column_midpoint_factor", 0.5f);
1131
1132                         break;
1133                 }
1134                 case ORE_PUFF: {
1135                         OrePuff *orepuff = (OrePuff *)ore;
1136
1137                         lua_getfield(L, index, "np_puff_top");
1138                         read_noiseparams(L, -1, &orepuff->np_puff_top);
1139                         lua_pop(L, 1);
1140
1141                         lua_getfield(L, index, "np_puff_bottom");
1142                         read_noiseparams(L, -1, &orepuff->np_puff_bottom);
1143                         lua_pop(L, 1);
1144
1145                         break;
1146                 }
1147                 case ORE_VEIN: {
1148                         OreVein *orevein = (OreVein *)ore;
1149
1150                         orevein->random_factor = getfloatfield_default(L, index,
1151                                 "random_factor", 1.f);
1152
1153                         break;
1154                 }
1155                 case ORE_STRATUM: {
1156                         OreStratum *orestratum = (OreStratum *)ore;
1157
1158                         lua_getfield(L, index, "np_stratum_thickness");
1159                         read_noiseparams(L, -1, &orestratum->np_stratum_thickness);
1160                         lua_pop(L, 1);
1161
1162                         break;
1163                 }
1164                 default:
1165                         break;
1166         }
1167
1168         ObjDefHandle handle = oremgr->add(ore);
1169         if (handle == OBJDEF_INVALID_HANDLE) {
1170                 delete ore;
1171                 return 0;
1172         }
1173
1174         ore->m_nodenames.push_back(getstringfield_default(L, index, "ore", ""));
1175
1176         size_t nnames = getstringlistfield(L, index, "wherein", &ore->m_nodenames);
1177         ore->m_nnlistsizes.push_back(nnames);
1178
1179         ndef->pendNodeResolve(ore);
1180
1181         lua_pushinteger(L, handle);
1182         return 1;
1183 }
1184
1185
1186 // register_schematic({schematic}, replacements={})
1187 int ModApiMapgen::l_register_schematic(lua_State *L)
1188 {
1189         NO_MAP_LOCK_REQUIRED;
1190
1191         SchematicManager *schemmgr = getServer(L)->getEmergeManager()->schemmgr;
1192
1193         StringMap replace_names;
1194         if (lua_istable(L, 2))
1195                 read_schematic_replacements(L, 2, &replace_names);
1196
1197         Schematic *schem = load_schematic(L, 1, schemmgr->getNodeDef(),
1198                 &replace_names);
1199         if (!schem)
1200                 return 0;
1201
1202         ObjDefHandle handle = schemmgr->add(schem);
1203         if (handle == OBJDEF_INVALID_HANDLE) {
1204                 delete schem;
1205                 return 0;
1206         }
1207
1208         lua_pushinteger(L, handle);
1209         return 1;
1210 }
1211
1212
1213 // clear_registered_biomes()
1214 int ModApiMapgen::l_clear_registered_biomes(lua_State *L)
1215 {
1216         NO_MAP_LOCK_REQUIRED;
1217
1218         BiomeManager *bmgr = getServer(L)->getEmergeManager()->biomemgr;
1219         bmgr->clear();
1220         return 0;
1221 }
1222
1223
1224 // clear_registered_decorations()
1225 int ModApiMapgen::l_clear_registered_decorations(lua_State *L)
1226 {
1227         NO_MAP_LOCK_REQUIRED;
1228
1229         DecorationManager *dmgr = getServer(L)->getEmergeManager()->decomgr;
1230         dmgr->clear();
1231         return 0;
1232 }
1233
1234
1235 // clear_registered_ores()
1236 int ModApiMapgen::l_clear_registered_ores(lua_State *L)
1237 {
1238         NO_MAP_LOCK_REQUIRED;
1239
1240         OreManager *omgr = getServer(L)->getEmergeManager()->oremgr;
1241         omgr->clear();
1242         return 0;
1243 }
1244
1245
1246 // clear_registered_schematics()
1247 int ModApiMapgen::l_clear_registered_schematics(lua_State *L)
1248 {
1249         NO_MAP_LOCK_REQUIRED;
1250
1251         SchematicManager *smgr = getServer(L)->getEmergeManager()->schemmgr;
1252         smgr->clear();
1253         return 0;
1254 }
1255
1256
1257 // generate_ores(vm, p1, p2, [ore_id])
1258 int ModApiMapgen::l_generate_ores(lua_State *L)
1259 {
1260         NO_MAP_LOCK_REQUIRED;
1261
1262         EmergeManager *emerge = getServer(L)->getEmergeManager();
1263
1264         Mapgen mg;
1265         mg.seed = emerge->mgparams->seed;
1266         mg.vm   = LuaVoxelManip::checkobject(L, 1)->vm;
1267         mg.ndef = getServer(L)->getNodeDefManager();
1268
1269         v3s16 pmin = lua_istable(L, 2) ? check_v3s16(L, 2) :
1270                         mg.vm->m_area.MinEdge + v3s16(1,1,1) * MAP_BLOCKSIZE;
1271         v3s16 pmax = lua_istable(L, 3) ? check_v3s16(L, 3) :
1272                         mg.vm->m_area.MaxEdge - v3s16(1,1,1) * MAP_BLOCKSIZE;
1273         sortBoxVerticies(pmin, pmax);
1274
1275         u32 blockseed = Mapgen::getBlockSeed(pmin, mg.seed);
1276
1277         emerge->oremgr->placeAllOres(&mg, blockseed, pmin, pmax);
1278
1279         return 0;
1280 }
1281
1282
1283 // generate_decorations(vm, p1, p2, [deco_id])
1284 int ModApiMapgen::l_generate_decorations(lua_State *L)
1285 {
1286         NO_MAP_LOCK_REQUIRED;
1287
1288         EmergeManager *emerge = getServer(L)->getEmergeManager();
1289
1290         Mapgen mg;
1291         mg.seed = emerge->mgparams->seed;
1292         mg.vm   = LuaVoxelManip::checkobject(L, 1)->vm;
1293         mg.ndef = getServer(L)->getNodeDefManager();
1294
1295         v3s16 pmin = lua_istable(L, 2) ? check_v3s16(L, 2) :
1296                         mg.vm->m_area.MinEdge + v3s16(1,1,1) * MAP_BLOCKSIZE;
1297         v3s16 pmax = lua_istable(L, 3) ? check_v3s16(L, 3) :
1298                         mg.vm->m_area.MaxEdge - v3s16(1,1,1) * MAP_BLOCKSIZE;
1299         sortBoxVerticies(pmin, pmax);
1300
1301         u32 blockseed = Mapgen::getBlockSeed(pmin, mg.seed);
1302
1303         emerge->decomgr->placeAllDecos(&mg, blockseed, pmin, pmax);
1304
1305         return 0;
1306 }
1307
1308
1309 // create_schematic(p1, p2, probability_list, filename, y_slice_prob_list)
1310 int ModApiMapgen::l_create_schematic(lua_State *L)
1311 {
1312         MAP_LOCK_REQUIRED;
1313
1314         INodeDefManager *ndef = getServer(L)->getNodeDefManager();
1315
1316         const char *filename = luaL_checkstring(L, 4);
1317         CHECK_SECURE_PATH(L, filename, true);
1318
1319         Map *map = &(getEnv(L)->getMap());
1320         Schematic schem;
1321
1322         v3s16 p1 = check_v3s16(L, 1);
1323         v3s16 p2 = check_v3s16(L, 2);
1324         sortBoxVerticies(p1, p2);
1325
1326         std::vector<std::pair<v3s16, u8> > prob_list;
1327         if (lua_istable(L, 3)) {
1328                 lua_pushnil(L);
1329                 while (lua_next(L, 3)) {
1330                         if (lua_istable(L, -1)) {
1331                                 lua_getfield(L, -1, "pos");
1332                                 v3s16 pos = check_v3s16(L, -1);
1333                                 lua_pop(L, 1);
1334
1335                                 u8 prob = getintfield_default(L, -1, "prob", MTSCHEM_PROB_ALWAYS);
1336                                 prob_list.emplace_back(pos, prob);
1337                         }
1338
1339                         lua_pop(L, 1);
1340                 }
1341         }
1342
1343         std::vector<std::pair<s16, u8> > slice_prob_list;
1344         if (lua_istable(L, 5)) {
1345                 lua_pushnil(L);
1346                 while (lua_next(L, 5)) {
1347                         if (lua_istable(L, -1)) {
1348                                 s16 ypos = getintfield_default(L, -1, "ypos", 0);
1349                                 u8 prob  = getintfield_default(L, -1, "prob", MTSCHEM_PROB_ALWAYS);
1350                                 slice_prob_list.emplace_back(ypos, prob);
1351                         }
1352
1353                         lua_pop(L, 1);
1354                 }
1355         }
1356
1357         if (!schem.getSchematicFromMap(map, p1, p2)) {
1358                 errorstream << "create_schematic: failed to get schematic "
1359                         "from map" << std::endl;
1360                 return 0;
1361         }
1362
1363         schem.applyProbabilities(p1, &prob_list, &slice_prob_list);
1364
1365         schem.saveSchematicToFile(filename, ndef);
1366         actionstream << "create_schematic: saved schematic file '"
1367                 << filename << "'." << std::endl;
1368
1369         lua_pushboolean(L, true);
1370         return 1;
1371 }
1372
1373
1374 // place_schematic(p, schematic, rotation, replacement)
1375 int ModApiMapgen::l_place_schematic(lua_State *L)
1376 {
1377         MAP_LOCK_REQUIRED;
1378
1379         GET_ENV_PTR;
1380
1381         ServerMap *map = &(env->getServerMap());
1382         SchematicManager *schemmgr = getServer(L)->getEmergeManager()->schemmgr;
1383
1384         //// Read position
1385         v3s16 p = check_v3s16(L, 1);
1386
1387         //// Read rotation
1388         int rot = ROTATE_0;
1389         const char *enumstr = lua_tostring(L, 3);
1390         if (enumstr)
1391                 string_to_enum(es_Rotation, rot, std::string(enumstr));
1392
1393         //// Read force placement
1394         bool force_placement = true;
1395         if (lua_isboolean(L, 5))
1396                 force_placement = lua_toboolean(L, 5);
1397
1398         //// Read node replacements
1399         StringMap replace_names;
1400         if (lua_istable(L, 4))
1401                 read_schematic_replacements(L, 4, &replace_names);
1402
1403         //// Read schematic
1404         Schematic *schem = get_or_load_schematic(L, 2, schemmgr, &replace_names);
1405         if (!schem) {
1406                 errorstream << "place_schematic: failed to get schematic" << std::endl;
1407                 return 0;
1408         }
1409
1410         schem->placeOnMap(map, p, 0, (Rotation)rot, force_placement);
1411
1412         lua_pushboolean(L, true);
1413         return 1;
1414 }
1415
1416 int ModApiMapgen::l_place_schematic_on_vmanip(lua_State *L)
1417 {
1418         NO_MAP_LOCK_REQUIRED;
1419
1420         SchematicManager *schemmgr = getServer(L)->getEmergeManager()->schemmgr;
1421
1422         //// Read VoxelManip object
1423         MMVManip *vm = LuaVoxelManip::checkobject(L, 1)->vm;
1424
1425         //// Read position
1426         v3s16 p = check_v3s16(L, 2);
1427
1428         //// Read rotation
1429         int rot = ROTATE_0;
1430         const char *enumstr = lua_tostring(L, 4);
1431         if (enumstr)
1432                 string_to_enum(es_Rotation, rot, std::string(enumstr));
1433
1434         //// Read force placement
1435         bool force_placement = true;
1436         if (lua_isboolean(L, 6))
1437                 force_placement = lua_toboolean(L, 6);
1438
1439         //// Read node replacements
1440         StringMap replace_names;
1441         if (lua_istable(L, 5))
1442                 read_schematic_replacements(L, 5, &replace_names);
1443
1444         //// Read schematic
1445         Schematic *schem = get_or_load_schematic(L, 3, schemmgr, &replace_names);
1446         if (!schem) {
1447                 errorstream << "place_schematic: failed to get schematic" << std::endl;
1448                 return 0;
1449         }
1450
1451         bool schematic_did_fit = schem->placeOnVManip(
1452                 vm, p, 0, (Rotation)rot, force_placement);
1453
1454         lua_pushboolean(L, schematic_did_fit);
1455         return 1;
1456 }
1457
1458 // serialize_schematic(schematic, format, options={...})
1459 int ModApiMapgen::l_serialize_schematic(lua_State *L)
1460 {
1461         NO_MAP_LOCK_REQUIRED;
1462
1463         SchematicManager *schemmgr = getServer(L)->getEmergeManager()->schemmgr;
1464
1465         //// Read options
1466         bool use_comments = getboolfield_default(L, 3, "lua_use_comments", false);
1467         u32 indent_spaces = getintfield_default(L, 3, "lua_num_indent_spaces", 0);
1468
1469         //// Get schematic
1470         bool was_loaded = false;
1471         Schematic *schem = (Schematic *)get_objdef(L, 1, schemmgr);
1472         if (!schem) {
1473                 schem = load_schematic(L, 1, NULL, NULL);
1474                 was_loaded = true;
1475         }
1476         if (!schem) {
1477                 errorstream << "serialize_schematic: failed to get schematic" << std::endl;
1478                 return 0;
1479         }
1480
1481         //// Read format of definition to save as
1482         int schem_format = SCHEM_FMT_MTS;
1483         const char *enumstr = lua_tostring(L, 2);
1484         if (enumstr)
1485                 string_to_enum(es_SchematicFormatType, schem_format, std::string(enumstr));
1486
1487         //// Serialize to binary string
1488         std::ostringstream os(std::ios_base::binary);
1489         switch (schem_format) {
1490         case SCHEM_FMT_MTS:
1491                 schem->serializeToMts(&os, schem->m_nodenames);
1492                 break;
1493         case SCHEM_FMT_LUA:
1494                 schem->serializeToLua(&os, schem->m_nodenames,
1495                         use_comments, indent_spaces);
1496                 break;
1497         default:
1498                 return 0;
1499         }
1500
1501         if (was_loaded)
1502                 delete schem;
1503
1504         std::string ser = os.str();
1505         lua_pushlstring(L, ser.c_str(), ser.length());
1506         return 1;
1507 }
1508
1509
1510 void ModApiMapgen::Initialize(lua_State *L, int top)
1511 {
1512         API_FCT(get_biome_id);
1513         API_FCT(get_mapgen_object);
1514
1515         API_FCT(get_mapgen_params);
1516         API_FCT(set_mapgen_params);
1517         API_FCT(get_mapgen_setting);
1518         API_FCT(set_mapgen_setting);
1519         API_FCT(get_mapgen_setting_noiseparams);
1520         API_FCT(set_mapgen_setting_noiseparams);
1521         API_FCT(set_noiseparams);
1522         API_FCT(get_noiseparams);
1523         API_FCT(set_gen_notify);
1524         API_FCT(get_gen_notify);
1525
1526         API_FCT(register_biome);
1527         API_FCT(register_decoration);
1528         API_FCT(register_ore);
1529         API_FCT(register_schematic);
1530
1531         API_FCT(clear_registered_biomes);
1532         API_FCT(clear_registered_decorations);
1533         API_FCT(clear_registered_ores);
1534         API_FCT(clear_registered_schematics);
1535
1536         API_FCT(generate_ores);
1537         API_FCT(generate_decorations);
1538         API_FCT(create_schematic);
1539         API_FCT(place_schematic);
1540         API_FCT(place_schematic_on_vmanip);
1541         API_FCT(serialize_schematic);
1542 }