Shorten ManualMapVoxelManipulator to MMVManip
[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 "util/serialize.h"
26 #include "server.h"
27 #include "environment.h"
28 #include "emerge.h"
29 #include "mg_biome.h"
30 #include "mg_ore.h"
31 #include "mg_decoration.h"
32 #include "mg_schematic.h"
33 #include "mapgen_v5.h"
34 #include "mapgen_v7.h"
35 #include "settings.h"
36 #include "main.h"
37 #include "log.h"
38
39
40 struct EnumString ModApiMapgen::es_BiomeTerrainType[] =
41 {
42         {BIOME_TYPE_NORMAL, "normal"},
43         {BIOME_TYPE_LIQUID, "liquid"},
44         {BIOME_TYPE_NETHER, "nether"},
45         {BIOME_TYPE_AETHER, "aether"},
46         {BIOME_TYPE_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_TYPE_SCATTER, "scatter"},
72         {ORE_TYPE_SHEET,   "sheet"},
73         {ORE_TYPE_BLOB,    "blob"},
74         {ORE_TYPE_VEIN,    "vein"},
75         {0, NULL},
76 };
77
78 struct EnumString ModApiMapgen::es_Rotation[] =
79 {
80         {ROTATE_0,    "0"},
81         {ROTATE_90,   "90"},
82         {ROTATE_180,  "180"},
83         {ROTATE_270,  "270"},
84         {ROTATE_RAND, "random"},
85         {0, NULL},
86 };
87
88
89 ///////////////////////////////////////////////////////////////////////////////
90
91
92 bool read_schematic(lua_State *L, int index, Schematic *schem,
93         INodeDefManager *ndef, std::map<std::string, std::string> &replace_names)
94 {
95         //// Get schematic size
96         lua_getfield(L, index, "size");
97         v3s16 size = read_v3s16(L, -1);
98         lua_pop(L, 1);
99
100         //// Get schematic data
101         lua_getfield(L, index, "data");
102         luaL_checktype(L, -1, LUA_TTABLE);
103
104         int numnodes = size.X * size.Y * size.Z;
105         MapNode *schemdata = new MapNode[numnodes];
106         int i = 0;
107
108         lua_pushnil(L);
109         while (lua_next(L, -2)) {
110                 if (i >= numnodes) {
111                         i++;
112                         lua_pop(L, 1);
113                         continue;
114                 }
115
116                 // same as readnode, except param1 default is MTSCHEM_PROB_CONST
117                 lua_getfield(L, -1, "name");
118                 std::string name = luaL_checkstring(L, -1);
119                 lua_pop(L, 1);
120
121                 u8 param1;
122                 lua_getfield(L, -1, "param1");
123                 param1 = !lua_isnil(L, -1) ? lua_tonumber(L, -1) : MTSCHEM_PROB_ALWAYS;
124                 lua_pop(L, 1);
125
126                 u8 param2;
127                 lua_getfield(L, -1, "param2");
128                 param2 = !lua_isnil(L, -1) ? lua_tonumber(L, -1) : 0;
129                 lua_pop(L, 1);
130
131                 std::map<std::string, std::string>::iterator it;
132                 it = replace_names.find(name);
133                 if (it != replace_names.end())
134                         name = it->second;
135
136                 schemdata[i] = MapNode(ndef, name, param1, param2);
137
138                 i++;
139                 lua_pop(L, 1);
140         }
141
142         if (i != numnodes) {
143                 errorstream << "read_schematic: incorrect number of "
144                         "nodes provided in raw schematic data (got " << i <<
145                         ", expected " << numnodes << ")." << std::endl;
146                 delete schemdata;
147                 return false;
148         }
149
150         //// Get Y-slice probability values (if present)
151         u8 *slice_probs = new u8[size.Y];
152         for (i = 0; i != size.Y; i++)
153                 slice_probs[i] = MTSCHEM_PROB_ALWAYS;
154
155         lua_getfield(L, index, "yslice_prob");
156         if (lua_istable(L, -1)) {
157                 lua_pushnil(L);
158                 while (lua_next(L, -2)) {
159                         if (getintfield(L, -1, "ypos", i) && i >= 0 && i < size.Y) {
160                                 slice_probs[i] = getintfield_default(L, -1,
161                                         "prob", MTSCHEM_PROB_ALWAYS);
162                         }
163                         lua_pop(L, 1);
164                 }
165         }
166
167         // Here, we read the nodes directly from the INodeDefManager - there is no
168         // need for pending node resolutions so we'll mark this schematic as updated
169         schem->flags       = SCHEM_CIDS_UPDATED;
170
171         schem->size        = size;
172         schem->schemdata   = schemdata;
173         schem->slice_probs = slice_probs;
174         return true;
175 }
176
177
178 bool get_schematic(lua_State *L, int index, Schematic *schem,
179         INodeDefManager *ndef, std::map<std::string, std::string> &replace_names)
180 {
181         if (index < 0)
182                 index = lua_gettop(L) + 1 + index;
183
184         if (lua_istable(L, index)) {
185                 return read_schematic(L, index, schem, ndef, replace_names);
186         } else if (lua_isstring(L, index)) {
187                 const char *filename = lua_tostring(L, index);
188                 return schem->loadSchematicFromFile(filename, ndef, replace_names);
189         } else {
190                 return false;
191         }
192 }
193
194
195 void read_schematic_replacements(lua_State *L,
196         std::map<std::string, std::string> &replace_names, int index)
197 {
198         lua_pushnil(L);
199         while (lua_next(L, index)) {
200                 std::string replace_from;
201                 std::string replace_to;
202
203                 if (lua_istable(L, -1)) { // Old {{"x", "y"}, ...} format
204                         lua_rawgeti(L, -1, 1);
205                         replace_from = lua_tostring(L, -1);
206                         lua_pop(L, 1);
207
208                         lua_rawgeti(L, -1, 2);
209                         replace_to = lua_tostring(L, -1);
210                         lua_pop(L, 1);
211                 } else { // New {x = "y", ...} format
212                         replace_from = lua_tostring(L, -2);
213                         replace_to = lua_tostring(L, -1);
214                 }
215
216                 replace_names[replace_from] = replace_to;
217                 lua_pop(L, 1);
218         }
219 }
220
221
222 // get_mapgen_object(objectname)
223 // returns the requested object used during map generation
224 int ModApiMapgen::l_get_mapgen_object(lua_State *L)
225 {
226         const char *mgobjstr = lua_tostring(L, 1);
227
228         int mgobjint;
229         if (!string_to_enum(es_MapgenObject, mgobjint, mgobjstr ? mgobjstr : ""))
230                 return 0;
231
232         enum MapgenObject mgobj = (MapgenObject)mgobjint;
233
234         EmergeManager *emerge = getServer(L)->getEmergeManager();
235         Mapgen *mg = emerge->getCurrentMapgen();
236         if (!mg)
237                 return 0;
238
239         size_t maplen = mg->csize.X * mg->csize.Z;
240
241         switch (mgobj) {
242                 case MGOBJ_VMANIP: {
243                         MMVManip *vm = mg->vm;
244
245                         // VoxelManip object
246                         LuaVoxelManip *o = new LuaVoxelManip(vm, true);
247                         *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
248                         luaL_getmetatable(L, "VoxelManip");
249                         lua_setmetatable(L, -2);
250
251                         // emerged min pos
252                         push_v3s16(L, vm->m_area.MinEdge);
253
254                         // emerged max pos
255                         push_v3s16(L, vm->m_area.MaxEdge);
256
257                         return 3;
258                 }
259                 case MGOBJ_HEIGHTMAP: {
260                         if (!mg->heightmap)
261                                 return 0;
262
263                         lua_newtable(L);
264                         for (size_t i = 0; i != maplen; i++) {
265                                 lua_pushinteger(L, mg->heightmap[i]);
266                                 lua_rawseti(L, -2, i + 1);
267                         }
268
269                         return 1;
270                 }
271                 case MGOBJ_BIOMEMAP: {
272                         if (!mg->biomemap)
273                                 return 0;
274
275                         lua_newtable(L);
276                         for (size_t i = 0; i != maplen; i++) {
277                                 lua_pushinteger(L, mg->biomemap[i]);
278                                 lua_rawseti(L, -2, i + 1);
279                         }
280
281                         return 1;
282                 }
283                 case MGOBJ_HEATMAP: { // Mapgen V7 specific objects
284                 case MGOBJ_HUMIDMAP:
285                         if (strcmp(emerge->params.mg_name.c_str(), "v7"))
286                                 return 0;
287
288                         MapgenV7 *mgv7 = (MapgenV7 *)mg;
289
290                         float *arr = (mgobj == MGOBJ_HEATMAP) ?
291                                 mgv7->noise_heat->result : mgv7->noise_humidity->result;
292                         if (!arr)
293                                 return 0;
294
295                         lua_newtable(L);
296                         for (size_t i = 0; i != maplen; i++) {
297                                 lua_pushnumber(L, arr[i]);
298                                 lua_rawseti(L, -2, i + 1);
299                         }
300
301                         return 1;
302                 }
303                 case MGOBJ_GENNOTIFY: {
304                         std::map<std::string, std::vector<v3s16> >event_map;
305                         std::map<std::string, std::vector<v3s16> >::iterator it;
306
307                         mg->gennotify.getEvents(event_map);
308
309                         lua_newtable(L);
310                         for (it = event_map.begin(); it != event_map.end(); ++it) {
311                                 lua_newtable(L);
312
313                                 for (size_t j = 0; j != it->second.size(); j++) {
314                                         push_v3s16(L, it->second[j]);
315                                         lua_rawseti(L, -2, j + 1);
316                                 }
317
318                                 lua_setfield(L, -2, it->first.c_str());
319                         }
320
321                         return 1;
322                 }
323         }
324
325         return 0;
326 }
327
328 int ModApiMapgen::l_get_mapgen_params(lua_State *L)
329 {
330         MapgenParams *params = &getServer(L)->getEmergeManager()->params;
331
332         lua_newtable(L);
333
334         lua_pushstring(L, params->mg_name.c_str());
335         lua_setfield(L, -2, "mgname");
336
337         lua_pushinteger(L, params->seed);
338         lua_setfield(L, -2, "seed");
339
340         lua_pushinteger(L, params->water_level);
341         lua_setfield(L, -2, "water_level");
342
343         lua_pushinteger(L, params->chunksize);
344         lua_setfield(L, -2, "chunksize");
345
346         std::string flagstr = writeFlagString(params->flags, flagdesc_mapgen, (u32)-1);
347         lua_pushstring(L, flagstr.c_str());
348         lua_setfield(L, -2, "flags");
349
350         return 1;
351 }
352
353 // set_mapgen_params(params)
354 // set mapgen parameters
355 int ModApiMapgen::l_set_mapgen_params(lua_State *L)
356 {
357         if (!lua_istable(L, 1))
358                 return 0;
359
360         MapgenParams *params = &getServer(L)->getEmergeManager()->params;
361         u32 flags = 0, flagmask = 0;
362
363         lua_getfield(L, 1, "mgname");
364         if (lua_isstring(L, -1)) {
365                 params->mg_name = lua_tostring(L, -1);
366                 delete params->sparams;
367                 params->sparams = NULL;
368         }
369
370         lua_getfield(L, 1, "seed");
371         if (lua_isnumber(L, -1))
372                 params->seed = lua_tointeger(L, -1);
373
374         lua_getfield(L, 1, "water_level");
375         if (lua_isnumber(L, -1))
376                 params->water_level = lua_tointeger(L, -1);
377
378         warn_if_field_exists(L, 1, "flagmask",
379                 "Deprecated: flags field now includes unset flags.");
380         lua_getfield(L, 1, "flagmask");
381         if (lua_isstring(L, -1))
382                 params->flags &= ~readFlagString(lua_tostring(L, -1), flagdesc_mapgen, NULL);
383
384         if (getflagsfield(L, 1, "flags", flagdesc_mapgen, &flags, &flagmask)) {
385                 params->flags &= ~flagmask;
386                 params->flags |= flags;
387         }
388
389         return 0;
390 }
391
392 // set_noiseparams(name, noiseparams, set_default)
393 // set global config values for noise parameters
394 int ModApiMapgen::l_set_noiseparams(lua_State *L)
395 {
396         const char *name = luaL_checkstring(L, 1);
397
398         NoiseParams np;
399         if (!read_noiseparams(L, 2, &np))
400                 return 0;
401
402         bool set_default = lua_isboolean(L, 3) ? lua_toboolean(L, 3) : true;
403
404         g_settings->setNoiseParams(name, np, set_default);
405
406         return 0;
407 }
408
409 // set_gen_notify(flags, {deco_id_table})
410 int ModApiMapgen::l_set_gen_notify(lua_State *L)
411 {
412         u32 flags = 0, flagmask = 0;
413         EmergeManager *emerge = getServer(L)->getEmergeManager();
414
415         if (read_flags(L, 1, flagdesc_gennotify, &flags, &flagmask)) {
416                 emerge->gen_notify_on &= ~flagmask;
417                 emerge->gen_notify_on |= flags;
418         }
419
420         if (lua_istable(L, 2)) {
421                 lua_pushnil(L);
422                 while (lua_next(L, 2)) {
423                         if (lua_isnumber(L, -1))
424                                 emerge->gen_notify_on_deco_ids.insert(lua_tonumber(L, -1));
425                         lua_pop(L, 1);
426                 }
427         }
428
429         return 0;
430 }
431
432 // register_biome({lots of stuff})
433 int ModApiMapgen::l_register_biome(lua_State *L)
434 {
435         int index = 1;
436         luaL_checktype(L, index, LUA_TTABLE);
437
438         INodeDefManager *ndef = getServer(L)->getNodeDefManager();
439         BiomeManager *bmgr    = getServer(L)->getEmergeManager()->biomemgr;
440
441         enum BiomeType biometype = (BiomeType)getenumfield(L, index, "type",
442                 es_BiomeTerrainType, BIOME_TYPE_NORMAL);
443         Biome *b = bmgr->create(biometype);
444
445         b->name            = getstringfield_default(L, index, "name", "");
446         b->depth_top       = getintfield_default(L, index, "depth_top",          1);
447         b->depth_filler    = getintfield_default(L, index, "depth_filler",       3);
448         b->height_shore    = getintfield_default(L, index, "height_shore",       3);
449         b->depth_water_top = getintfield_default(L, index, "depth_water_top",    0);
450         b->y_min           = getintfield_default(L, index, "y_min",         -31000);
451         b->y_max           = getintfield_default(L, index, "y_max",          31000);
452         b->heat_point      = getfloatfield_default(L, index, "heat_point",     0.f);
453         b->humidity_point  = getfloatfield_default(L, index, "humidity_point", 0.f);
454         b->flags           = 0; //reserved
455
456         u32 id = bmgr->add(b);
457         if (id == (u32)-1) {
458                 delete b;
459                 return 0;
460         }
461
462         NodeResolveInfo *nri = new NodeResolveInfo(b);
463         std::list<std::string> &nnames = nri->nodenames;
464         nnames.push_back(getstringfield_default(L, index, "node_top",          ""));
465         nnames.push_back(getstringfield_default(L, index, "node_filler",       ""));
466         nnames.push_back(getstringfield_default(L, index, "node_shore_top",    ""));
467         nnames.push_back(getstringfield_default(L, index, "node_shore_filler", ""));
468         nnames.push_back(getstringfield_default(L, index, "node_underwater",   ""));
469         nnames.push_back(getstringfield_default(L, index, "node_stone",        ""));
470         nnames.push_back(getstringfield_default(L, index, "node_water_top",    ""));
471         nnames.push_back(getstringfield_default(L, index, "node_water",        ""));
472         nnames.push_back(getstringfield_default(L, index, "node_dust",         ""));
473         ndef->pendNodeResolve(nri);
474
475         verbosestream << "register_biome: " << b->name << std::endl;
476
477         lua_pushinteger(L, id);
478         return 1;
479 }
480
481 int ModApiMapgen::l_clear_registered_biomes(lua_State *L)
482 {
483         BiomeManager *bmgr = getServer(L)->getEmergeManager()->biomemgr;
484         bmgr->clear();
485         return 0;
486 }
487
488 int ModApiMapgen::l_clear_registered_decorations(lua_State *L)
489 {
490         DecorationManager *dmgr = getServer(L)->getEmergeManager()->decomgr;
491         dmgr->clear();
492         return 0;
493 }
494
495 int ModApiMapgen::l_clear_registered_ores(lua_State *L)
496 {
497         OreManager *omgr = getServer(L)->getEmergeManager()->oremgr;
498         omgr->clear();
499         return 0;
500 }
501
502 // register_decoration({lots of stuff})
503 int ModApiMapgen::l_register_decoration(lua_State *L)
504 {
505         int index = 1;
506         luaL_checktype(L, index, LUA_TTABLE);
507
508         INodeDefManager *ndef      = getServer(L)->getNodeDefManager();
509         DecorationManager *decomgr = getServer(L)->getEmergeManager()->decomgr;
510         BiomeManager *biomemgr     = getServer(L)->getEmergeManager()->biomemgr;
511
512         enum DecorationType decotype = (DecorationType)getenumfield(L, index,
513                                 "deco_type", es_DecorationType, -1);
514
515         Decoration *deco = decomgr->create(decotype);
516         if (!deco) {
517                 errorstream << "register_decoration: decoration placement type "
518                         << decotype << " not implemented";
519                 return 0;
520         }
521
522         deco->name       = getstringfield_default(L, index, "name", "");
523         deco->fill_ratio = getfloatfield_default(L, index, "fill_ratio", 0.02);
524         deco->y_min      = getintfield_default(L, index, "y_min", -31000);
525         deco->y_max      = getintfield_default(L, index, "y_max", 31000);
526         deco->sidelen    = getintfield_default(L, index, "sidelen", 8);
527         if (deco->sidelen <= 0) {
528                 errorstream << "register_decoration: sidelen must be "
529                         "greater than 0" << std::endl;
530                 delete deco;
531                 return 0;
532         }
533
534         NodeResolveInfo *nri = new NodeResolveInfo(deco);
535
536         //// Get node name(s) to place decoration on
537         std::vector<const char *> place_on_names;
538         getstringlistfield(L, index, "place_on", place_on_names);
539         nri->nodelistinfo.push_back(NodeListInfo(place_on_names.size()));
540         for (size_t i = 0; i != place_on_names.size(); i++)
541                 nri->nodenames.push_back(place_on_names[i]);
542
543         getflagsfield(L, index, "flags", flagdesc_deco, &deco->flags, NULL);
544
545         //// Get NoiseParams to define how decoration is placed
546         lua_getfield(L, index, "noise_params");
547         if (read_noiseparams(L, -1, &deco->np))
548                 deco->flags |= DECO_USE_NOISE;
549         lua_pop(L, 1);
550
551         //// Get biomes associated with this decoration (if any)
552         std::vector<const char *> biome_list;
553         getstringlistfield(L, index, "biomes", biome_list);
554         for (size_t i = 0; i != biome_list.size(); i++) {
555                 Biome *b = (Biome *)biomemgr->getByName(biome_list[i]);
556                 if (!b)
557                         continue;
558
559                 deco->biomes.insert(b->id);
560         }
561
562         //// Handle decoration type-specific parameters
563         bool success = false;
564         switch (decotype) {
565                 case DECO_SIMPLE:
566                         success = regDecoSimple(L, nri, (DecoSimple *)deco);
567                         break;
568                 case DECO_SCHEMATIC:
569                         success = regDecoSchematic(L, ndef, (DecoSchematic *)deco);
570                         break;
571                 case DECO_LSYSTEM:
572                         break;
573         }
574
575         ndef->pendNodeResolve(nri);
576
577         if (!success) {
578                 delete deco;
579                 return 0;
580         }
581
582         u32 id = decomgr->add(deco);
583         if (id == (u32)-1) {
584                 delete deco;
585                 return 0;
586         }
587
588         verbosestream << "register_decoration: " << deco->name << std::endl;
589
590         lua_pushinteger(L, id);
591         return 1;
592 }
593
594 bool ModApiMapgen::regDecoSimple(lua_State *L,
595                 NodeResolveInfo *nri, DecoSimple *deco)
596 {
597         int index = 1;
598
599         deco->deco_height     = getintfield_default(L, index, "height", 1);
600         deco->deco_height_max = getintfield_default(L, index, "height_max", 0);
601         deco->nspawnby        = getintfield_default(L, index, "num_spawn_by", -1);
602
603         if (deco->deco_height <= 0) {
604                 errorstream << "register_decoration: simple decoration height"
605                         " must be greater than 0" << std::endl;
606                 return false;
607         }
608
609         std::vector<const char *> deco_names;
610         getstringlistfield(L, index, "decoration", deco_names);
611         if (deco_names.size() == 0) {
612                 errorstream << "register_decoration: no decoration nodes "
613                         "defined" << std::endl;
614                 return false;
615         }
616         nri->nodelistinfo.push_back(NodeListInfo(deco_names.size()));
617         for (size_t i = 0; i != deco_names.size(); i++)
618                 nri->nodenames.push_back(deco_names[i]);
619
620         std::vector<const char *> spawnby_names;
621         getstringlistfield(L, index, "spawn_by", spawnby_names);
622         if (deco->nspawnby != -1 && spawnby_names.size() == 0) {
623                 errorstream << "register_decoration: no spawn_by nodes defined,"
624                         " but num_spawn_by specified" << std::endl;
625                 return false;
626         }
627         nri->nodelistinfo.push_back(NodeListInfo(spawnby_names.size()));
628         for (size_t i = 0; i != spawnby_names.size(); i++)
629                 nri->nodenames.push_back(spawnby_names[i]);
630
631         return true;
632 }
633
634 bool ModApiMapgen::regDecoSchematic(lua_State *L, INodeDefManager *ndef,
635         DecoSchematic *deco)
636 {
637         int index = 1;
638
639         deco->rotation = (Rotation)getenumfield(L, index, "rotation",
640                 es_Rotation, ROTATE_0);
641
642         std::map<std::string, std::string> replace_names;
643         lua_getfield(L, index, "replacements");
644         if (lua_istable(L, -1))
645                 read_schematic_replacements(L, replace_names, lua_gettop(L));
646         lua_pop(L, 1);
647
648         // TODO(hmmmm): get a ref from registered schematics
649         Schematic *schem = new Schematic;
650         lua_getfield(L, index, "schematic");
651         if (!get_schematic(L, -1, schem, ndef, replace_names)) {
652                 lua_pop(L, 1);
653                 delete schem;
654                 return false;
655         }
656         lua_pop(L, 1);
657
658         deco->schematic = schem;
659
660         return true;
661 }
662
663 // register_ore({lots of stuff})
664 int ModApiMapgen::l_register_ore(lua_State *L)
665 {
666         int index = 1;
667         luaL_checktype(L, index, LUA_TTABLE);
668
669         INodeDefManager *ndef = getServer(L)->getNodeDefManager();
670         OreManager *oremgr    = getServer(L)->getEmergeManager()->oremgr;
671
672         enum OreType oretype = (OreType)getenumfield(L, index,
673                                 "ore_type", es_OreType, ORE_TYPE_SCATTER);
674         Ore *ore = oremgr->create(oretype);
675         if (!ore) {
676                 errorstream << "register_ore: ore_type " << oretype << " not implemented";
677                 return 0;
678         }
679
680         ore->name           = getstringfield_default(L, index, "name", "");
681         ore->ore_param2     = (u8)getintfield_default(L, index, "ore_param2", 0);
682         ore->clust_scarcity = getintfield_default(L, index, "clust_scarcity", 1);
683         ore->clust_num_ores = getintfield_default(L, index, "clust_num_ores", 1);
684         ore->clust_size     = getintfield_default(L, index, "clust_size", 0);
685         ore->nthresh        = getfloatfield_default(L, index, "noise_threshhold", 0);
686         ore->noise          = NULL;
687         ore->flags          = 0;
688
689         warn_if_field_exists(L, index, "height_min",
690                 "Deprecated: new name is \"y_min\".");
691         warn_if_field_exists(L, index, "height_max",
692                 "Deprecated: new name is \"y_max\".");
693
694         int ymin, ymax;
695         if (!getintfield(L, index, "y_min", ymin) &&
696                 !getintfield(L, index, "height_min", ymin))
697                 ymin = -31000;
698         if (!getintfield(L, index, "y_max", ymax) &&
699                 !getintfield(L, index, "height_max", ymax))
700                 ymax = 31000;
701         ore->y_min = ymin;
702         ore->y_max = ymax;
703
704         if (ore->clust_scarcity <= 0 || ore->clust_num_ores <= 0) {
705                 errorstream << "register_ore: clust_scarcity and clust_num_ores"
706                         "must be greater than 0" << std::endl;
707                 delete ore;
708                 return 0;
709         }
710
711         getflagsfield(L, index, "flags", flagdesc_ore, &ore->flags, NULL);
712
713         lua_getfield(L, index, "noise_params");
714         if (read_noiseparams(L, -1, &ore->np)) {
715                 ore->flags |= OREFLAG_USE_NOISE;
716         } else if (ore->NEEDS_NOISE) {
717                 errorstream << "register_ore: specified ore type requires valid "
718                         "noise parameters" << std::endl;
719                 delete ore;
720                 return 0;
721         }
722         lua_pop(L, 1);
723
724         if (oretype == ORE_TYPE_VEIN) {
725                 OreVein *orevein = (OreVein *)ore;
726                 orevein->random_factor = getfloatfield_default(L, index,
727                         "random_factor", 1.f);
728         }
729
730         u32 id = oremgr->add(ore);
731         if (id == (u32)-1) {
732                 delete ore;
733                 return 0;
734         }
735
736         NodeResolveInfo *nri = new NodeResolveInfo(ore);
737         nri->nodenames.push_back(getstringfield_default(L, index, "ore", ""));
738
739         std::vector<const char *> wherein_names;
740         getstringlistfield(L, index, "wherein", wherein_names);
741         nri->nodelistinfo.push_back(NodeListInfo(wherein_names.size()));
742         for (size_t i = 0; i != wherein_names.size(); i++)
743                 nri->nodenames.push_back(wherein_names[i]);
744
745         ndef->pendNodeResolve(nri);
746
747         verbosestream << "register_ore: " << ore->name << std::endl;
748
749         lua_pushinteger(L, id);
750         return 1;
751 }
752
753 // create_schematic(p1, p2, probability_list, filename)
754 int ModApiMapgen::l_create_schematic(lua_State *L)
755 {
756         Schematic schem;
757
758         Map *map = &(getEnv(L)->getMap());
759         INodeDefManager *ndef = getServer(L)->getNodeDefManager();
760
761         v3s16 p1 = read_v3s16(L, 1);
762         v3s16 p2 = read_v3s16(L, 2);
763         sortBoxVerticies(p1, p2);
764
765         std::vector<std::pair<v3s16, u8> > prob_list;
766         if (lua_istable(L, 3)) {
767                 lua_pushnil(L);
768                 while (lua_next(L, 3)) {
769                         if (lua_istable(L, -1)) {
770                                 lua_getfield(L, -1, "pos");
771                                 v3s16 pos = read_v3s16(L, -1);
772                                 lua_pop(L, 1);
773
774                                 u8 prob = getintfield_default(L, -1, "prob", MTSCHEM_PROB_ALWAYS);
775                                 prob_list.push_back(std::make_pair(pos, prob));
776                         }
777
778                         lua_pop(L, 1);
779                 }
780         }
781
782         std::vector<std::pair<s16, u8> > slice_prob_list;
783         if (lua_istable(L, 5)) {
784                 lua_pushnil(L);
785                 while (lua_next(L, 5)) {
786                         if (lua_istable(L, -1)) {
787                                 s16 ypos = getintfield_default(L, -1, "ypos", 0);
788                                 u8 prob  = getintfield_default(L, -1, "prob", MTSCHEM_PROB_ALWAYS);
789                                 slice_prob_list.push_back(std::make_pair(ypos, prob));
790                         }
791
792                         lua_pop(L, 1);
793                 }
794         }
795
796         const char *filename = luaL_checkstring(L, 4);
797
798         if (!schem.getSchematicFromMap(map, p1, p2)) {
799                 errorstream << "create_schematic: failed to get schematic "
800                         "from map" << std::endl;
801                 return 0;
802         }
803
804         schem.applyProbabilities(p1, &prob_list, &slice_prob_list);
805
806         schem.saveSchematicToFile(filename, ndef);
807         actionstream << "create_schematic: saved schematic file '"
808                 << filename << "'." << std::endl;
809
810         return 1;
811 }
812
813 // generate_ores(vm, [ore_id])
814 int ModApiMapgen::l_generate_ores(lua_State *L)
815 {
816         EmergeManager *emerge = getServer(L)->getEmergeManager();
817
818         Mapgen mg;
819         mg.seed = emerge->params.seed;
820         mg.vm   = LuaVoxelManip::checkobject(L, 1)->vm;
821         mg.ndef = getServer(L)->getNodeDefManager();
822
823         u32 blockseed = Mapgen::getBlockSeed(mg.vm->m_area.MinEdge, mg.seed);
824
825         emerge->oremgr->placeAllOres(&mg, blockseed,
826                 mg.vm->m_area.MinEdge, mg.vm->m_area.MaxEdge);
827
828         return 0;
829 }
830
831 // generate_decorations(vm, [deco_id])
832 int ModApiMapgen::l_generate_decorations(lua_State *L)
833 {
834         EmergeManager *emerge = getServer(L)->getEmergeManager();
835
836         Mapgen mg;
837         mg.seed = emerge->params.seed;
838         mg.vm   = LuaVoxelManip::checkobject(L, 1)->vm;
839         mg.ndef = getServer(L)->getNodeDefManager();
840
841         u32 blockseed = Mapgen::getBlockSeed(mg.vm->m_area.MinEdge, mg.seed);
842
843         emerge->decomgr->placeAllDecos(&mg, blockseed,
844                 mg.vm->m_area.MinEdge, mg.vm->m_area.MaxEdge);
845
846         return 0;
847 }
848
849 // place_schematic(p, schematic, rotation, replacement)
850 int ModApiMapgen::l_place_schematic(lua_State *L)
851 {
852         Schematic schem;
853
854         Map *map = &(getEnv(L)->getMap());
855         INodeDefManager *ndef = getServer(L)->getNodeDefManager();
856
857         //// Read position
858         v3s16 p = read_v3s16(L, 1);
859
860         //// Read rotation
861         int rot = ROTATE_0;
862         if (lua_isstring(L, 3))
863                 string_to_enum(es_Rotation, rot, std::string(lua_tostring(L, 3)));
864
865         //// Read force placement
866         bool force_placement = true;
867         if (lua_isboolean(L, 5))
868                 force_placement = lua_toboolean(L, 5);
869
870         //// Read node replacements
871         std::map<std::string, std::string> replace_names;
872         if (lua_istable(L, 4))
873                 read_schematic_replacements(L, replace_names, 4);
874
875         //// Read schematic
876         if (!get_schematic(L, 2, &schem, ndef, replace_names)) {
877                 errorstream << "place_schematic: failed to get schematic" << std::endl;
878                 return 0;
879         }
880
881         schem.placeStructure(map, p, 0, (Rotation)rot, force_placement, ndef);
882
883         return 1;
884 }
885
886 void ModApiMapgen::Initialize(lua_State *L, int top)
887 {
888         API_FCT(get_mapgen_object);
889
890         API_FCT(get_mapgen_params);
891         API_FCT(set_mapgen_params);
892         API_FCT(set_noiseparams);
893         API_FCT(set_gen_notify);
894
895         API_FCT(register_biome);
896         API_FCT(register_decoration);
897         API_FCT(register_ore);
898
899         API_FCT(clear_registered_biomes);
900         API_FCT(clear_registered_decorations);
901         API_FCT(clear_registered_ores);
902
903         API_FCT(generate_ores);
904         API_FCT(generate_decorations);
905
906         API_FCT(create_schematic);
907         API_FCT(place_schematic);
908 }