Move files to subdirectories (#6599)
[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 "mapgen/mg_biome.h"
31 #include "mapgen/mg_ore.h"
32 #include "mapgen/mg_decoration.h"
33 #include "mapgen/mg_schematic.h"
34 #include "mapgen/mapgen_v5.h"
35 #include "mapgen/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->place_offset_y = getintfield_default(L, index, "place_offset_y", 0);
915         deco->sidelen        = getintfield_default(L, index, "sidelen", 8);
916         if (deco->sidelen <= 0) {
917                 errorstream << "register_decoration: sidelen must be "
918                         "greater than 0" << std::endl;
919                 delete deco;
920                 return 0;
921         }
922
923         //// Get node name(s) to place decoration on
924         size_t nread = getstringlistfield(L, index, "place_on", &deco->m_nodenames);
925         deco->m_nnlistsizes.push_back(nread);
926
927         //// Get decoration flags
928         getflagsfield(L, index, "flags", flagdesc_deco, &deco->flags, NULL);
929
930         //// Get NoiseParams to define how decoration is placed
931         lua_getfield(L, index, "noise_params");
932         if (read_noiseparams(L, -1, &deco->np))
933                 deco->flags |= DECO_USE_NOISE;
934         lua_pop(L, 1);
935
936         //// Get biomes associated with this decoration (if any)
937         lua_getfield(L, index, "biomes");
938         if (get_biome_list(L, -1, biomemgr, &deco->biomes))
939                 infostream << "register_decoration: couldn't get all biomes " << std::endl;
940         lua_pop(L, 1);
941
942         //// Get node name(s) to 'spawn by'
943         size_t nnames = getstringlistfield(L, index, "spawn_by", &deco->m_nodenames);
944         deco->m_nnlistsizes.push_back(nnames);
945         if (nnames == 0 && deco->nspawnby != -1) {
946                 errorstream << "register_decoration: no spawn_by nodes defined,"
947                         " but num_spawn_by specified" << std::endl;
948         }
949
950         //// Handle decoration type-specific parameters
951         bool success = false;
952         switch (decotype) {
953         case DECO_SIMPLE:
954                 success = read_deco_simple(L, (DecoSimple *)deco);
955                 break;
956         case DECO_SCHEMATIC:
957                 success = read_deco_schematic(L, schemmgr, (DecoSchematic *)deco);
958                 break;
959         case DECO_LSYSTEM:
960                 break;
961         }
962
963         if (!success) {
964                 delete deco;
965                 return 0;
966         }
967
968         ndef->pendNodeResolve(deco);
969
970         ObjDefHandle handle = decomgr->add(deco);
971         if (handle == OBJDEF_INVALID_HANDLE) {
972                 delete deco;
973                 return 0;
974         }
975
976         lua_pushinteger(L, handle);
977         return 1;
978 }
979
980
981 bool read_deco_simple(lua_State *L, DecoSimple *deco)
982 {
983         int index = 1;
984         int param2;
985         int param2_max;
986
987         deco->deco_height     = getintfield_default(L, index, "height", 1);
988         deco->deco_height_max = getintfield_default(L, index, "height_max", 0);
989
990         if (deco->deco_height <= 0) {
991                 errorstream << "register_decoration: simple decoration height"
992                         " must be greater than 0" << std::endl;
993                 return false;
994         }
995
996         size_t nnames = getstringlistfield(L, index, "decoration", &deco->m_nodenames);
997         deco->m_nnlistsizes.push_back(nnames);
998
999         if (nnames == 0) {
1000                 errorstream << "register_decoration: no decoration nodes "
1001                         "defined" << std::endl;
1002                 return false;
1003         }
1004
1005         param2 = getintfield_default(L, index, "param2", 0);
1006         param2_max = getintfield_default(L, index, "param2_max", 0);
1007
1008         if (param2 < 0 || param2 > 255 || param2_max < 0 || param2_max > 255) {
1009                 errorstream << "register_decoration: param2 or param2_max out of bounds (0-255)"
1010                         << std::endl;
1011                 return false;
1012         }
1013
1014         deco->deco_param2 = (u8)param2;
1015         deco->deco_param2_max = (u8)param2_max;
1016
1017         return true;
1018 }
1019
1020
1021 bool read_deco_schematic(lua_State *L, SchematicManager *schemmgr, DecoSchematic *deco)
1022 {
1023         int index = 1;
1024
1025         deco->rotation = (Rotation)getenumfield(L, index, "rotation",
1026                 ModApiMapgen::es_Rotation, ROTATE_0);
1027
1028         StringMap replace_names;
1029         lua_getfield(L, index, "replacements");
1030         if (lua_istable(L, -1))
1031                 read_schematic_replacements(L, -1, &replace_names);
1032         lua_pop(L, 1);
1033
1034         lua_getfield(L, index, "schematic");
1035         Schematic *schem = get_or_load_schematic(L, -1, schemmgr, &replace_names);
1036         lua_pop(L, 1);
1037
1038         deco->schematic = schem;
1039         return schem != NULL;
1040 }
1041
1042
1043 // register_ore({lots of stuff})
1044 int ModApiMapgen::l_register_ore(lua_State *L)
1045 {
1046         NO_MAP_LOCK_REQUIRED;
1047
1048         int index = 1;
1049         luaL_checktype(L, index, LUA_TTABLE);
1050
1051         INodeDefManager *ndef = getServer(L)->getNodeDefManager();
1052         BiomeManager *bmgr    = getServer(L)->getEmergeManager()->biomemgr;
1053         OreManager *oremgr    = getServer(L)->getEmergeManager()->oremgr;
1054
1055         enum OreType oretype = (OreType)getenumfield(L, index,
1056                                 "ore_type", es_OreType, ORE_SCATTER);
1057         Ore *ore = oremgr->create(oretype);
1058         if (!ore) {
1059                 errorstream << "register_ore: ore_type " << oretype << " not implemented\n";
1060                 return 0;
1061         }
1062
1063         ore->name           = getstringfield_default(L, index, "name", "");
1064         ore->ore_param2     = (u8)getintfield_default(L, index, "ore_param2", 0);
1065         ore->clust_scarcity = getintfield_default(L, index, "clust_scarcity", 1);
1066         ore->clust_num_ores = getintfield_default(L, index, "clust_num_ores", 1);
1067         ore->clust_size     = getintfield_default(L, index, "clust_size", 0);
1068         ore->noise          = NULL;
1069         ore->flags          = 0;
1070
1071         //// Get noise_threshold
1072         warn_if_field_exists(L, index, "noise_threshhold",
1073                 "Deprecated: new name is \"noise_threshold\".");
1074
1075         float nthresh;
1076         if (!getfloatfield(L, index, "noise_threshold", nthresh) &&
1077                         !getfloatfield(L, index, "noise_threshhold", nthresh))
1078                 nthresh = 0;
1079         ore->nthresh = nthresh;
1080
1081         //// Get y_min/y_max
1082         warn_if_field_exists(L, index, "height_min",
1083                 "Deprecated: new name is \"y_min\".");
1084         warn_if_field_exists(L, index, "height_max",
1085                 "Deprecated: new name is \"y_max\".");
1086
1087         int ymin, ymax;
1088         if (!getintfield(L, index, "y_min", ymin) &&
1089                 !getintfield(L, index, "height_min", ymin))
1090                 ymin = -31000;
1091         if (!getintfield(L, index, "y_max", ymax) &&
1092                 !getintfield(L, index, "height_max", ymax))
1093                 ymax = 31000;
1094         ore->y_min = ymin;
1095         ore->y_max = ymax;
1096
1097         if (ore->clust_scarcity <= 0 || ore->clust_num_ores <= 0) {
1098                 errorstream << "register_ore: clust_scarcity and clust_num_ores"
1099                         "must be greater than 0" << std::endl;
1100                 delete ore;
1101                 return 0;
1102         }
1103
1104         //// Get flags
1105         getflagsfield(L, index, "flags", flagdesc_ore, &ore->flags, NULL);
1106
1107         //// Get biomes associated with this decoration (if any)
1108         lua_getfield(L, index, "biomes");
1109         if (get_biome_list(L, -1, bmgr, &ore->biomes))
1110                 infostream << "register_ore: couldn't get all biomes " << std::endl;
1111         lua_pop(L, 1);
1112
1113         //// Get noise parameters if needed
1114         lua_getfield(L, index, "noise_params");
1115         if (read_noiseparams(L, -1, &ore->np)) {
1116                 ore->flags |= OREFLAG_USE_NOISE;
1117         } else if (ore->NEEDS_NOISE) {
1118                 errorstream << "register_ore: specified ore type requires valid "
1119                         "noise parameters" << std::endl;
1120                 delete ore;
1121                 return 0;
1122         }
1123         lua_pop(L, 1);
1124
1125         //// Get type-specific parameters
1126         switch (oretype) {
1127                 case ORE_SHEET: {
1128                         OreSheet *oresheet = (OreSheet *)ore;
1129
1130                         oresheet->column_height_min = getintfield_default(L, index,
1131                                 "column_height_min", 1);
1132                         oresheet->column_height_max = getintfield_default(L, index,
1133                                 "column_height_max", ore->clust_size);
1134                         oresheet->column_midpoint_factor = getfloatfield_default(L, index,
1135                                 "column_midpoint_factor", 0.5f);
1136
1137                         break;
1138                 }
1139                 case ORE_PUFF: {
1140                         OrePuff *orepuff = (OrePuff *)ore;
1141
1142                         lua_getfield(L, index, "np_puff_top");
1143                         read_noiseparams(L, -1, &orepuff->np_puff_top);
1144                         lua_pop(L, 1);
1145
1146                         lua_getfield(L, index, "np_puff_bottom");
1147                         read_noiseparams(L, -1, &orepuff->np_puff_bottom);
1148                         lua_pop(L, 1);
1149
1150                         break;
1151                 }
1152                 case ORE_VEIN: {
1153                         OreVein *orevein = (OreVein *)ore;
1154
1155                         orevein->random_factor = getfloatfield_default(L, index,
1156                                 "random_factor", 1.f);
1157
1158                         break;
1159                 }
1160                 case ORE_STRATUM: {
1161                         OreStratum *orestratum = (OreStratum *)ore;
1162
1163                         lua_getfield(L, index, "np_stratum_thickness");
1164                         // If thickness noise missing unset 'use noise' flag
1165                         if (!read_noiseparams(L, -1, &orestratum->np_stratum_thickness))
1166                                 ore->flags &= ~OREFLAG_USE_NOISE;
1167                         lua_pop(L, 1);
1168
1169                         break;
1170                 }
1171                 default:
1172                         break;
1173         }
1174
1175         ObjDefHandle handle = oremgr->add(ore);
1176         if (handle == OBJDEF_INVALID_HANDLE) {
1177                 delete ore;
1178                 return 0;
1179         }
1180
1181         ore->m_nodenames.push_back(getstringfield_default(L, index, "ore", ""));
1182
1183         size_t nnames = getstringlistfield(L, index, "wherein", &ore->m_nodenames);
1184         ore->m_nnlistsizes.push_back(nnames);
1185
1186         ndef->pendNodeResolve(ore);
1187
1188         lua_pushinteger(L, handle);
1189         return 1;
1190 }
1191
1192
1193 // register_schematic({schematic}, replacements={})
1194 int ModApiMapgen::l_register_schematic(lua_State *L)
1195 {
1196         NO_MAP_LOCK_REQUIRED;
1197
1198         SchematicManager *schemmgr = getServer(L)->getEmergeManager()->schemmgr;
1199
1200         StringMap replace_names;
1201         if (lua_istable(L, 2))
1202                 read_schematic_replacements(L, 2, &replace_names);
1203
1204         Schematic *schem = load_schematic(L, 1, schemmgr->getNodeDef(),
1205                 &replace_names);
1206         if (!schem)
1207                 return 0;
1208
1209         ObjDefHandle handle = schemmgr->add(schem);
1210         if (handle == OBJDEF_INVALID_HANDLE) {
1211                 delete schem;
1212                 return 0;
1213         }
1214
1215         lua_pushinteger(L, handle);
1216         return 1;
1217 }
1218
1219
1220 // clear_registered_biomes()
1221 int ModApiMapgen::l_clear_registered_biomes(lua_State *L)
1222 {
1223         NO_MAP_LOCK_REQUIRED;
1224
1225         BiomeManager *bmgr = getServer(L)->getEmergeManager()->biomemgr;
1226         bmgr->clear();
1227         return 0;
1228 }
1229
1230
1231 // clear_registered_decorations()
1232 int ModApiMapgen::l_clear_registered_decorations(lua_State *L)
1233 {
1234         NO_MAP_LOCK_REQUIRED;
1235
1236         DecorationManager *dmgr = getServer(L)->getEmergeManager()->decomgr;
1237         dmgr->clear();
1238         return 0;
1239 }
1240
1241
1242 // clear_registered_ores()
1243 int ModApiMapgen::l_clear_registered_ores(lua_State *L)
1244 {
1245         NO_MAP_LOCK_REQUIRED;
1246
1247         OreManager *omgr = getServer(L)->getEmergeManager()->oremgr;
1248         omgr->clear();
1249         return 0;
1250 }
1251
1252
1253 // clear_registered_schematics()
1254 int ModApiMapgen::l_clear_registered_schematics(lua_State *L)
1255 {
1256         NO_MAP_LOCK_REQUIRED;
1257
1258         SchematicManager *smgr = getServer(L)->getEmergeManager()->schemmgr;
1259         smgr->clear();
1260         return 0;
1261 }
1262
1263
1264 // generate_ores(vm, p1, p2, [ore_id])
1265 int ModApiMapgen::l_generate_ores(lua_State *L)
1266 {
1267         NO_MAP_LOCK_REQUIRED;
1268
1269         EmergeManager *emerge = getServer(L)->getEmergeManager();
1270
1271         Mapgen mg;
1272         mg.seed = emerge->mgparams->seed;
1273         mg.vm   = LuaVoxelManip::checkobject(L, 1)->vm;
1274         mg.ndef = getServer(L)->getNodeDefManager();
1275
1276         v3s16 pmin = lua_istable(L, 2) ? check_v3s16(L, 2) :
1277                         mg.vm->m_area.MinEdge + v3s16(1,1,1) * MAP_BLOCKSIZE;
1278         v3s16 pmax = lua_istable(L, 3) ? check_v3s16(L, 3) :
1279                         mg.vm->m_area.MaxEdge - v3s16(1,1,1) * MAP_BLOCKSIZE;
1280         sortBoxVerticies(pmin, pmax);
1281
1282         u32 blockseed = Mapgen::getBlockSeed(pmin, mg.seed);
1283
1284         emerge->oremgr->placeAllOres(&mg, blockseed, pmin, pmax);
1285
1286         return 0;
1287 }
1288
1289
1290 // generate_decorations(vm, p1, p2, [deco_id])
1291 int ModApiMapgen::l_generate_decorations(lua_State *L)
1292 {
1293         NO_MAP_LOCK_REQUIRED;
1294
1295         EmergeManager *emerge = getServer(L)->getEmergeManager();
1296
1297         Mapgen mg;
1298         mg.seed = emerge->mgparams->seed;
1299         mg.vm   = LuaVoxelManip::checkobject(L, 1)->vm;
1300         mg.ndef = getServer(L)->getNodeDefManager();
1301
1302         v3s16 pmin = lua_istable(L, 2) ? check_v3s16(L, 2) :
1303                         mg.vm->m_area.MinEdge + v3s16(1,1,1) * MAP_BLOCKSIZE;
1304         v3s16 pmax = lua_istable(L, 3) ? check_v3s16(L, 3) :
1305                         mg.vm->m_area.MaxEdge - v3s16(1,1,1) * MAP_BLOCKSIZE;
1306         sortBoxVerticies(pmin, pmax);
1307
1308         u32 blockseed = Mapgen::getBlockSeed(pmin, mg.seed);
1309
1310         emerge->decomgr->placeAllDecos(&mg, blockseed, pmin, pmax);
1311
1312         return 0;
1313 }
1314
1315
1316 // create_schematic(p1, p2, probability_list, filename, y_slice_prob_list)
1317 int ModApiMapgen::l_create_schematic(lua_State *L)
1318 {
1319         MAP_LOCK_REQUIRED;
1320
1321         INodeDefManager *ndef = getServer(L)->getNodeDefManager();
1322
1323         const char *filename = luaL_checkstring(L, 4);
1324         CHECK_SECURE_PATH(L, filename, true);
1325
1326         Map *map = &(getEnv(L)->getMap());
1327         Schematic schem;
1328
1329         v3s16 p1 = check_v3s16(L, 1);
1330         v3s16 p2 = check_v3s16(L, 2);
1331         sortBoxVerticies(p1, p2);
1332
1333         std::vector<std::pair<v3s16, u8> > prob_list;
1334         if (lua_istable(L, 3)) {
1335                 lua_pushnil(L);
1336                 while (lua_next(L, 3)) {
1337                         if (lua_istable(L, -1)) {
1338                                 lua_getfield(L, -1, "pos");
1339                                 v3s16 pos = check_v3s16(L, -1);
1340                                 lua_pop(L, 1);
1341
1342                                 u8 prob = getintfield_default(L, -1, "prob", MTSCHEM_PROB_ALWAYS);
1343                                 prob_list.emplace_back(pos, prob);
1344                         }
1345
1346                         lua_pop(L, 1);
1347                 }
1348         }
1349
1350         std::vector<std::pair<s16, u8> > slice_prob_list;
1351         if (lua_istable(L, 5)) {
1352                 lua_pushnil(L);
1353                 while (lua_next(L, 5)) {
1354                         if (lua_istable(L, -1)) {
1355                                 s16 ypos = getintfield_default(L, -1, "ypos", 0);
1356                                 u8 prob  = getintfield_default(L, -1, "prob", MTSCHEM_PROB_ALWAYS);
1357                                 slice_prob_list.emplace_back(ypos, prob);
1358                         }
1359
1360                         lua_pop(L, 1);
1361                 }
1362         }
1363
1364         if (!schem.getSchematicFromMap(map, p1, p2)) {
1365                 errorstream << "create_schematic: failed to get schematic "
1366                         "from map" << std::endl;
1367                 return 0;
1368         }
1369
1370         schem.applyProbabilities(p1, &prob_list, &slice_prob_list);
1371
1372         schem.saveSchematicToFile(filename, ndef);
1373         actionstream << "create_schematic: saved schematic file '"
1374                 << filename << "'." << std::endl;
1375
1376         lua_pushboolean(L, true);
1377         return 1;
1378 }
1379
1380
1381 // place_schematic(p, schematic, rotation, replacement)
1382 int ModApiMapgen::l_place_schematic(lua_State *L)
1383 {
1384         MAP_LOCK_REQUIRED;
1385
1386         GET_ENV_PTR;
1387
1388         ServerMap *map = &(env->getServerMap());
1389         SchematicManager *schemmgr = getServer(L)->getEmergeManager()->schemmgr;
1390
1391         //// Read position
1392         v3s16 p = check_v3s16(L, 1);
1393
1394         //// Read rotation
1395         int rot = ROTATE_0;
1396         const char *enumstr = lua_tostring(L, 3);
1397         if (enumstr)
1398                 string_to_enum(es_Rotation, rot, std::string(enumstr));
1399
1400         //// Read force placement
1401         bool force_placement = true;
1402         if (lua_isboolean(L, 5))
1403                 force_placement = lua_toboolean(L, 5);
1404
1405         //// Read node replacements
1406         StringMap replace_names;
1407         if (lua_istable(L, 4))
1408                 read_schematic_replacements(L, 4, &replace_names);
1409
1410         //// Read schematic
1411         Schematic *schem = get_or_load_schematic(L, 2, schemmgr, &replace_names);
1412         if (!schem) {
1413                 errorstream << "place_schematic: failed to get schematic" << std::endl;
1414                 return 0;
1415         }
1416
1417         schem->placeOnMap(map, p, 0, (Rotation)rot, force_placement);
1418
1419         lua_pushboolean(L, true);
1420         return 1;
1421 }
1422
1423 int ModApiMapgen::l_place_schematic_on_vmanip(lua_State *L)
1424 {
1425         NO_MAP_LOCK_REQUIRED;
1426
1427         SchematicManager *schemmgr = getServer(L)->getEmergeManager()->schemmgr;
1428
1429         //// Read VoxelManip object
1430         MMVManip *vm = LuaVoxelManip::checkobject(L, 1)->vm;
1431
1432         //// Read position
1433         v3s16 p = check_v3s16(L, 2);
1434
1435         //// Read rotation
1436         int rot = ROTATE_0;
1437         const char *enumstr = lua_tostring(L, 4);
1438         if (enumstr)
1439                 string_to_enum(es_Rotation, rot, std::string(enumstr));
1440
1441         //// Read force placement
1442         bool force_placement = true;
1443         if (lua_isboolean(L, 6))
1444                 force_placement = lua_toboolean(L, 6);
1445
1446         //// Read node replacements
1447         StringMap replace_names;
1448         if (lua_istable(L, 5))
1449                 read_schematic_replacements(L, 5, &replace_names);
1450
1451         //// Read schematic
1452         Schematic *schem = get_or_load_schematic(L, 3, schemmgr, &replace_names);
1453         if (!schem) {
1454                 errorstream << "place_schematic: failed to get schematic" << std::endl;
1455                 return 0;
1456         }
1457
1458         bool schematic_did_fit = schem->placeOnVManip(
1459                 vm, p, 0, (Rotation)rot, force_placement);
1460
1461         lua_pushboolean(L, schematic_did_fit);
1462         return 1;
1463 }
1464
1465 // serialize_schematic(schematic, format, options={...})
1466 int ModApiMapgen::l_serialize_schematic(lua_State *L)
1467 {
1468         NO_MAP_LOCK_REQUIRED;
1469
1470         SchematicManager *schemmgr = getServer(L)->getEmergeManager()->schemmgr;
1471
1472         //// Read options
1473         bool use_comments = getboolfield_default(L, 3, "lua_use_comments", false);
1474         u32 indent_spaces = getintfield_default(L, 3, "lua_num_indent_spaces", 0);
1475
1476         //// Get schematic
1477         bool was_loaded = false;
1478         Schematic *schem = (Schematic *)get_objdef(L, 1, schemmgr);
1479         if (!schem) {
1480                 schem = load_schematic(L, 1, NULL, NULL);
1481                 was_loaded = true;
1482         }
1483         if (!schem) {
1484                 errorstream << "serialize_schematic: failed to get schematic" << std::endl;
1485                 return 0;
1486         }
1487
1488         //// Read format of definition to save as
1489         int schem_format = SCHEM_FMT_MTS;
1490         const char *enumstr = lua_tostring(L, 2);
1491         if (enumstr)
1492                 string_to_enum(es_SchematicFormatType, schem_format, std::string(enumstr));
1493
1494         //// Serialize to binary string
1495         std::ostringstream os(std::ios_base::binary);
1496         switch (schem_format) {
1497         case SCHEM_FMT_MTS:
1498                 schem->serializeToMts(&os, schem->m_nodenames);
1499                 break;
1500         case SCHEM_FMT_LUA:
1501                 schem->serializeToLua(&os, schem->m_nodenames,
1502                         use_comments, indent_spaces);
1503                 break;
1504         default:
1505                 return 0;
1506         }
1507
1508         if (was_loaded)
1509                 delete schem;
1510
1511         std::string ser = os.str();
1512         lua_pushlstring(L, ser.c_str(), ser.length());
1513         return 1;
1514 }
1515
1516
1517 void ModApiMapgen::Initialize(lua_State *L, int top)
1518 {
1519         API_FCT(get_biome_id);
1520         API_FCT(get_mapgen_object);
1521
1522         API_FCT(get_mapgen_params);
1523         API_FCT(set_mapgen_params);
1524         API_FCT(get_mapgen_setting);
1525         API_FCT(set_mapgen_setting);
1526         API_FCT(get_mapgen_setting_noiseparams);
1527         API_FCT(set_mapgen_setting_noiseparams);
1528         API_FCT(set_noiseparams);
1529         API_FCT(get_noiseparams);
1530         API_FCT(set_gen_notify);
1531         API_FCT(get_gen_notify);
1532
1533         API_FCT(register_biome);
1534         API_FCT(register_decoration);
1535         API_FCT(register_ore);
1536         API_FCT(register_schematic);
1537
1538         API_FCT(clear_registered_biomes);
1539         API_FCT(clear_registered_decorations);
1540         API_FCT(clear_registered_ores);
1541         API_FCT(clear_registered_schematics);
1542
1543         API_FCT(generate_ores);
1544         API_FCT(generate_decorations);
1545         API_FCT(create_schematic);
1546         API_FCT(place_schematic);
1547         API_FCT(place_schematic_on_vmanip);
1548         API_FCT(serialize_schematic);
1549 }