3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
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.
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.
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.
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"
27 #include "environment.h"
31 #include "mg_decoration.h"
32 #include "mg_schematic.h"
33 #include "mapgen_v5.h"
34 #include "mapgen_v7.h"
40 struct EnumString ModApiMapgen::es_BiomeTerrainType[] =
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"},
50 struct EnumString ModApiMapgen::es_DecorationType[] =
52 {DECO_SIMPLE, "simple"},
53 {DECO_SCHEMATIC, "schematic"},
54 {DECO_LSYSTEM, "lsystem"},
58 struct EnumString ModApiMapgen::es_MapgenObject[] =
60 {MGOBJ_VMANIP, "voxelmanip"},
61 {MGOBJ_HEIGHTMAP, "heightmap"},
62 {MGOBJ_BIOMEMAP, "biomemap"},
63 {MGOBJ_HEATMAP, "heatmap"},
64 {MGOBJ_HUMIDMAP, "humiditymap"},
65 {MGOBJ_GENNOTIFY, "gennotify"},
69 struct EnumString ModApiMapgen::es_OreType[] =
71 {ORE_TYPE_SCATTER, "scatter"},
72 {ORE_TYPE_SHEET, "sheet"},
73 {ORE_TYPE_BLOB, "blob"},
74 {ORE_TYPE_VEIN, "vein"},
78 struct EnumString ModApiMapgen::es_Rotation[] =
84 {ROTATE_RAND, "random"},
89 ///////////////////////////////////////////////////////////////////////////////
92 bool read_schematic(lua_State *L, int index, Schematic *schem,
93 INodeDefManager *ndef, std::map<std::string, std::string> &replace_names)
95 //// Get schematic size
96 lua_getfield(L, index, "size");
97 v3s16 size = read_v3s16(L, -1);
100 //// Get schematic data
101 lua_getfield(L, index, "data");
102 luaL_checktype(L, -1, LUA_TTABLE);
104 int numnodes = size.X * size.Y * size.Z;
105 MapNode *schemdata = new MapNode[numnodes];
109 while (lua_next(L, -2)) {
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);
122 lua_getfield(L, -1, "param1");
123 param1 = !lua_isnil(L, -1) ? lua_tonumber(L, -1) : MTSCHEM_PROB_ALWAYS;
127 lua_getfield(L, -1, "param2");
128 param2 = !lua_isnil(L, -1) ? lua_tonumber(L, -1) : 0;
131 std::map<std::string, std::string>::iterator it;
132 it = replace_names.find(name);
133 if (it != replace_names.end())
136 schemdata[i] = MapNode(ndef, name, param1, param2);
143 errorstream << "read_schematic: incorrect number of "
144 "nodes provided in raw schematic data (got " << i <<
145 ", expected " << numnodes << ")." << std::endl;
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;
155 lua_getfield(L, index, "yslice_prob");
156 if (lua_istable(L, -1)) {
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);
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;
172 schem->schemdata = schemdata;
173 schem->slice_probs = slice_probs;
178 bool get_schematic(lua_State *L, int index, Schematic *schem,
179 INodeDefManager *ndef, std::map<std::string, std::string> &replace_names)
182 index = lua_gettop(L) + 1 + index;
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);
195 void read_schematic_replacements(lua_State *L,
196 std::map<std::string, std::string> &replace_names, int index)
199 while (lua_next(L, index)) {
200 std::string replace_from;
201 std::string replace_to;
203 if (lua_istable(L, -1)) { // Old {{"x", "y"}, ...} format
204 lua_rawgeti(L, -1, 1);
205 replace_from = lua_tostring(L, -1);
208 lua_rawgeti(L, -1, 2);
209 replace_to = lua_tostring(L, -1);
211 } else { // New {x = "y", ...} format
212 replace_from = lua_tostring(L, -2);
213 replace_to = lua_tostring(L, -1);
216 replace_names[replace_from] = replace_to;
222 // get_mapgen_object(objectname)
223 // returns the requested object used during map generation
224 int ModApiMapgen::l_get_mapgen_object(lua_State *L)
226 const char *mgobjstr = lua_tostring(L, 1);
229 if (!string_to_enum(es_MapgenObject, mgobjint, mgobjstr ? mgobjstr : ""))
232 enum MapgenObject mgobj = (MapgenObject)mgobjint;
234 EmergeManager *emerge = getServer(L)->getEmergeManager();
235 Mapgen *mg = emerge->getCurrentMapgen();
239 size_t maplen = mg->csize.X * mg->csize.Z;
243 ManualMapVoxelManipulator *vm = mg->vm;
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);
252 push_v3s16(L, vm->m_area.MinEdge);
255 push_v3s16(L, vm->m_area.MaxEdge);
259 case MGOBJ_HEIGHTMAP: {
264 for (size_t i = 0; i != maplen; i++) {
265 lua_pushinteger(L, mg->heightmap[i]);
266 lua_rawseti(L, -2, i + 1);
271 case MGOBJ_BIOMEMAP: {
276 for (size_t i = 0; i != maplen; i++) {
277 lua_pushinteger(L, mg->biomemap[i]);
278 lua_rawseti(L, -2, i + 1);
283 case MGOBJ_HEATMAP: { // Mapgen V7 specific objects
285 if (strcmp(emerge->params.mg_name.c_str(), "v7"))
288 MapgenV7 *mgv7 = (MapgenV7 *)mg;
290 float *arr = (mgobj == MGOBJ_HEATMAP) ?
291 mgv7->noise_heat->result : mgv7->noise_humidity->result;
296 for (size_t i = 0; i != maplen; i++) {
297 lua_pushnumber(L, arr[i]);
298 lua_rawseti(L, -2, i + 1);
303 case MGOBJ_GENNOTIFY: {
304 std::map<std::string, std::vector<v3s16> >event_map;
305 std::map<std::string, std::vector<v3s16> >::iterator it;
307 mg->gennotify.getEvents(event_map);
310 for (it = event_map.begin(); it != event_map.end(); ++it) {
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);
318 lua_setfield(L, -2, it->first.c_str());
328 // set_mapgen_params(params)
329 // set mapgen parameters
330 int ModApiMapgen::l_set_mapgen_params(lua_State *L)
332 if (!lua_istable(L, 1))
335 EmergeManager *emerge = getServer(L)->getEmergeManager();
339 u32 flags = 0, flagmask = 0;
341 lua_getfield(L, 1, "mgname");
342 if (lua_isstring(L, -1)) {
343 emerge->params.mg_name = std::string(lua_tostring(L, -1));
344 delete emerge->params.sparams;
345 emerge->params.sparams = NULL;
348 lua_getfield(L, 1, "seed");
349 if (lua_isnumber(L, -1))
350 emerge->params.seed = lua_tointeger(L, -1);
352 lua_getfield(L, 1, "water_level");
353 if (lua_isnumber(L, -1))
354 emerge->params.water_level = lua_tointeger(L, -1);
356 lua_getfield(L, 1, "flagmask");
357 if (lua_isstring(L, -1)) {
358 flagstr = lua_tostring(L, -1);
359 emerge->params.flags &= ~readFlagString(flagstr, flagdesc_mapgen, NULL);
360 errorstream << "set_mapgen_params(): flagmask field is deprecated, "
361 "see lua_api.txt" << std::endl;
364 if (getflagsfield(L, 1, "flags", flagdesc_mapgen, &flags, &flagmask)) {
365 emerge->params.flags &= ~flagmask;
366 emerge->params.flags |= flags;
372 // set_noiseparams(name, noiseparams, set_default)
373 // set global config values for noise parameters
374 int ModApiMapgen::l_set_noiseparams(lua_State *L)
376 const char *name = luaL_checkstring(L, 1);
379 if (!read_noiseparams(L, 2, &np))
382 bool set_default = lua_isboolean(L, 3) ? lua_toboolean(L, 3) : true;
384 g_settings->setNoiseParams(name, np, set_default);
389 // set_gen_notify(flags, {deco_id_table})
390 int ModApiMapgen::l_set_gen_notify(lua_State *L)
392 u32 flags = 0, flagmask = 0;
393 EmergeManager *emerge = getServer(L)->getEmergeManager();
395 if (read_flags(L, 1, flagdesc_gennotify, &flags, &flagmask)) {
396 emerge->gen_notify_on &= ~flagmask;
397 emerge->gen_notify_on |= flags;
400 if (lua_istable(L, 2)) {
402 while (lua_next(L, 2)) {
403 if (lua_isnumber(L, -1))
404 emerge->gen_notify_on_deco_ids.insert(lua_tonumber(L, -1));
412 // register_biome({lots of stuff})
413 int ModApiMapgen::l_register_biome(lua_State *L)
416 luaL_checktype(L, index, LUA_TTABLE);
418 INodeDefManager *ndef = getServer(L)->getNodeDefManager();
419 BiomeManager *bmgr = getServer(L)->getEmergeManager()->biomemgr;
421 enum BiomeType biometype = (BiomeType)getenumfield(L, index, "type",
422 es_BiomeTerrainType, BIOME_TYPE_NORMAL);
423 Biome *b = bmgr->create(biometype);
425 b->name = getstringfield_default(L, index, "name", "");
426 b->depth_top = getintfield_default(L, index, "depth_top", 1);
427 b->depth_filler = getintfield_default(L, index, "depth_filler", 3);
428 b->height_min = getintfield_default(L, index, "height_min", 0);
429 b->height_max = getintfield_default(L, index, "height_max", 0);
430 b->heat_point = getfloatfield_default(L, index, "heat_point", 0.);
431 b->humidity_point = getfloatfield_default(L, index, "humidity_point", 0.);
432 b->flags = 0; //reserved
434 u32 id = bmgr->add(b);
440 NodeResolveInfo *nri = new NodeResolveInfo(b);
441 std::list<std::string> &nnames = nri->nodenames;
442 nnames.push_back(getstringfield_default(L, index, "node_top", ""));
443 nnames.push_back(getstringfield_default(L, index, "node_filler", ""));
444 nnames.push_back(getstringfield_default(L, index, "node_stone", ""));
445 nnames.push_back(getstringfield_default(L, index, "node_water", ""));
446 nnames.push_back(getstringfield_default(L, index, "node_dust", ""));
447 nnames.push_back(getstringfield_default(L, index, "node_dust_water", ""));
448 ndef->pendNodeResolve(nri);
450 verbosestream << "register_biome: " << b->name << std::endl;
452 lua_pushinteger(L, id);
456 int ModApiMapgen::l_clear_registered_biomes(lua_State *L)
458 BiomeManager *bmgr = getServer(L)->getEmergeManager()->biomemgr;
463 int ModApiMapgen::l_clear_registered_decorations(lua_State *L)
465 DecorationManager *dmgr = getServer(L)->getEmergeManager()->decomgr;
470 int ModApiMapgen::l_clear_registered_ores(lua_State *L)
472 OreManager *omgr = getServer(L)->getEmergeManager()->oremgr;
477 // register_decoration({lots of stuff})
478 int ModApiMapgen::l_register_decoration(lua_State *L)
481 luaL_checktype(L, index, LUA_TTABLE);
483 INodeDefManager *ndef = getServer(L)->getNodeDefManager();
484 DecorationManager *decomgr = getServer(L)->getEmergeManager()->decomgr;
485 BiomeManager *biomemgr = getServer(L)->getEmergeManager()->biomemgr;
487 enum DecorationType decotype = (DecorationType)getenumfield(L, index,
488 "deco_type", es_DecorationType, -1);
490 Decoration *deco = decomgr->create(decotype);
492 errorstream << "register_decoration: decoration placement type "
493 << decotype << " not implemented";
497 deco->name = getstringfield_default(L, index, "name", "");
498 deco->fill_ratio = getfloatfield_default(L, index, "fill_ratio", 0.02);
499 deco->sidelen = getintfield_default(L, index, "sidelen", 8);
500 if (deco->sidelen <= 0) {
501 errorstream << "register_decoration: sidelen must be "
502 "greater than 0" << std::endl;
507 NodeResolveInfo *nri = new NodeResolveInfo(deco);
509 //// Get node name(s) to place decoration on
510 std::vector<const char *> place_on_names;
511 getstringlistfield(L, index, "place_on", place_on_names);
512 nri->nodelistinfo.push_back(NodeListInfo(place_on_names.size()));
513 for (size_t i = 0; i != place_on_names.size(); i++)
514 nri->nodenames.push_back(place_on_names[i]);
516 getflagsfield(L, index, "flags", flagdesc_deco, &deco->flags, NULL);
518 //// Get NoiseParams to define how decoration is placed
519 lua_getfield(L, index, "noise_params");
520 if (read_noiseparams(L, -1, &deco->np))
521 deco->flags |= DECO_USE_NOISE;
524 //// Get biomes associated with this decoration (if any)
525 std::vector<const char *> biome_list;
526 getstringlistfield(L, index, "biomes", biome_list);
527 for (size_t i = 0; i != biome_list.size(); i++) {
528 Biome *b = (Biome *)biomemgr->getByName(biome_list[i]);
532 deco->biomes.insert(b->id);
535 //// Handle decoration type-specific parameters
536 bool success = false;
539 success = regDecoSimple(L, nri, (DecoSimple *)deco);
542 success = regDecoSchematic(L, ndef, (DecoSchematic *)deco);
548 ndef->pendNodeResolve(nri);
555 u32 id = decomgr->add(deco);
561 verbosestream << "register_decoration: " << deco->name << std::endl;
563 lua_pushinteger(L, id);
567 bool ModApiMapgen::regDecoSimple(lua_State *L,
568 NodeResolveInfo *nri, DecoSimple *deco)
572 deco->deco_height = getintfield_default(L, index, "height", 1);
573 deco->deco_height_max = getintfield_default(L, index, "height_max", 0);
574 deco->nspawnby = getintfield_default(L, index, "num_spawn_by", -1);
576 if (deco->deco_height <= 0) {
577 errorstream << "register_decoration: simple decoration height"
578 " must be greater than 0" << std::endl;
582 std::vector<const char *> deco_names;
583 getstringlistfield(L, index, "decoration", deco_names);
584 if (deco_names.size() == 0) {
585 errorstream << "register_decoration: no decoration nodes "
586 "defined" << std::endl;
589 nri->nodelistinfo.push_back(NodeListInfo(deco_names.size()));
590 for (size_t i = 0; i != deco_names.size(); i++)
591 nri->nodenames.push_back(deco_names[i]);
593 std::vector<const char *> spawnby_names;
594 getstringlistfield(L, index, "spawn_by", spawnby_names);
595 if (deco->nspawnby != -1 && spawnby_names.size() == 0) {
596 errorstream << "register_decoration: no spawn_by nodes defined,"
597 " but num_spawn_by specified" << std::endl;
600 nri->nodelistinfo.push_back(NodeListInfo(spawnby_names.size()));
601 for (size_t i = 0; i != spawnby_names.size(); i++)
602 nri->nodenames.push_back(spawnby_names[i]);
607 bool ModApiMapgen::regDecoSchematic(lua_State *L, INodeDefManager *ndef,
612 deco->rotation = (Rotation)getenumfield(L, index, "rotation",
613 es_Rotation, ROTATE_0);
615 std::map<std::string, std::string> replace_names;
616 lua_getfield(L, index, "replacements");
617 if (lua_istable(L, -1))
618 read_schematic_replacements(L, replace_names, lua_gettop(L));
621 // TODO(hmmmm): get a ref from registered schematics
622 Schematic *schem = new Schematic;
623 lua_getfield(L, index, "schematic");
624 if (!get_schematic(L, -1, schem, ndef, replace_names)) {
631 deco->schematic = schem;
636 // register_ore({lots of stuff})
637 int ModApiMapgen::l_register_ore(lua_State *L)
640 luaL_checktype(L, index, LUA_TTABLE);
642 INodeDefManager *ndef = getServer(L)->getNodeDefManager();
643 OreManager *oremgr = getServer(L)->getEmergeManager()->oremgr;
645 enum OreType oretype = (OreType)getenumfield(L, index,
646 "ore_type", es_OreType, ORE_TYPE_SCATTER);
647 Ore *ore = oremgr->create(oretype);
649 errorstream << "register_ore: ore_type " << oretype << " not implemented";
653 ore->name = getstringfield_default(L, index, "name", "");
654 ore->ore_param2 = (u8)getintfield_default(L, index, "ore_param2", 0);
655 ore->clust_scarcity = getintfield_default(L, index, "clust_scarcity", 1);
656 ore->clust_num_ores = getintfield_default(L, index, "clust_num_ores", 1);
657 ore->clust_size = getintfield_default(L, index, "clust_size", 0);
658 ore->height_min = getintfield_default(L, index, "height_min", 0);
659 ore->height_max = getintfield_default(L, index, "height_max", 0);
660 ore->nthresh = getfloatfield_default(L, index, "noise_threshhold", 0);
664 if (ore->clust_scarcity <= 0 || ore->clust_num_ores <= 0) {
665 errorstream << "register_ore: clust_scarcity and clust_num_ores"
666 "must be greater than 0" << std::endl;
671 getflagsfield(L, index, "flags", flagdesc_ore, &ore->flags, NULL);
673 lua_getfield(L, index, "noise_params");
674 if (read_noiseparams(L, -1, &ore->np)) {
675 ore->flags |= OREFLAG_USE_NOISE;
676 } else if (ore->NEEDS_NOISE) {
677 errorstream << "register_ore: specified ore type requires valid "
678 "noise parameters" << std::endl;
684 if (oretype == ORE_TYPE_VEIN) {
685 OreVein *orevein = (OreVein *)ore;
686 orevein->random_factor = getfloatfield_default(L, index,
687 "random_factor", 1.f);
690 u32 id = oremgr->add(ore);
696 NodeResolveInfo *nri = new NodeResolveInfo(ore);
697 nri->nodenames.push_back(getstringfield_default(L, index, "ore", ""));
699 std::vector<const char *> wherein_names;
700 getstringlistfield(L, index, "wherein", wherein_names);
701 nri->nodelistinfo.push_back(NodeListInfo(wherein_names.size()));
702 for (size_t i = 0; i != wherein_names.size(); i++)
703 nri->nodenames.push_back(wherein_names[i]);
705 ndef->pendNodeResolve(nri);
707 verbosestream << "register_ore: " << ore->name << std::endl;
709 lua_pushinteger(L, id);
713 // create_schematic(p1, p2, probability_list, filename)
714 int ModApiMapgen::l_create_schematic(lua_State *L)
718 Map *map = &(getEnv(L)->getMap());
719 INodeDefManager *ndef = getServer(L)->getNodeDefManager();
721 v3s16 p1 = read_v3s16(L, 1);
722 v3s16 p2 = read_v3s16(L, 2);
723 sortBoxVerticies(p1, p2);
725 std::vector<std::pair<v3s16, u8> > prob_list;
726 if (lua_istable(L, 3)) {
728 while (lua_next(L, 3)) {
729 if (lua_istable(L, -1)) {
730 lua_getfield(L, -1, "pos");
731 v3s16 pos = read_v3s16(L, -1);
734 u8 prob = getintfield_default(L, -1, "prob", MTSCHEM_PROB_ALWAYS);
735 prob_list.push_back(std::make_pair(pos, prob));
742 std::vector<std::pair<s16, u8> > slice_prob_list;
743 if (lua_istable(L, 5)) {
745 while (lua_next(L, 5)) {
746 if (lua_istable(L, -1)) {
747 s16 ypos = getintfield_default(L, -1, "ypos", 0);
748 u8 prob = getintfield_default(L, -1, "prob", MTSCHEM_PROB_ALWAYS);
749 slice_prob_list.push_back(std::make_pair(ypos, prob));
756 const char *filename = luaL_checkstring(L, 4);
758 if (!schem.getSchematicFromMap(map, p1, p2)) {
759 errorstream << "create_schematic: failed to get schematic "
760 "from map" << std::endl;
764 schem.applyProbabilities(p1, &prob_list, &slice_prob_list);
766 schem.saveSchematicToFile(filename, ndef);
767 actionstream << "create_schematic: saved schematic file '"
768 << filename << "'." << std::endl;
773 // place_schematic(p, schematic, rotation, replacement)
774 int ModApiMapgen::l_place_schematic(lua_State *L)
778 Map *map = &(getEnv(L)->getMap());
779 INodeDefManager *ndef = getServer(L)->getNodeDefManager();
782 v3s16 p = read_v3s16(L, 1);
786 if (lua_isstring(L, 3))
787 string_to_enum(es_Rotation, rot, std::string(lua_tostring(L, 3)));
789 //// Read force placement
790 bool force_placement = true;
791 if (lua_isboolean(L, 5))
792 force_placement = lua_toboolean(L, 5);
794 //// Read node replacements
795 std::map<std::string, std::string> replace_names;
796 if (lua_istable(L, 4))
797 read_schematic_replacements(L, replace_names, 4);
800 if (!get_schematic(L, 2, &schem, ndef, replace_names)) {
801 errorstream << "place_schematic: failed to get schematic" << std::endl;
805 schem.placeStructure(map, p, 0, (Rotation)rot, force_placement, ndef);
810 void ModApiMapgen::Initialize(lua_State *L, int top)
812 API_FCT(get_mapgen_object);
814 API_FCT(set_mapgen_params);
815 API_FCT(set_noiseparams);
816 API_FCT(set_gen_notify);
818 API_FCT(register_biome);
819 API_FCT(register_decoration);
820 API_FCT(register_ore);
822 API_FCT(clear_registered_biomes);
823 API_FCT(clear_registered_decorations);
824 API_FCT(clear_registered_ores);
826 API_FCT(create_schematic);
827 API_FCT(place_schematic);