aboutsummaryrefslogtreecommitdiff
path: root/src/script/lua_api/l_mapgen.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/script/lua_api/l_mapgen.cpp')
-rw-r--r--src/script/lua_api/l_mapgen.cpp986
1 files changed, 664 insertions, 322 deletions
diff --git a/src/script/lua_api/l_mapgen.cpp b/src/script/lua_api/l_mapgen.cpp
index d470cef88..d30b68054 100644
--- a/src/script/lua_api/l_mapgen.cpp
+++ b/src/script/lua_api/l_mapgen.cpp
@@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "lua_api/l_vmanip.h"
#include "common/c_converter.h"
#include "common/c_content.h"
+#include "cpp_api/s_security.h"
#include "util/serialize.h"
#include "server.h"
#include "environment.h"
@@ -32,18 +33,17 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "mg_schematic.h"
#include "mapgen_v5.h"
#include "mapgen_v7.h"
+#include "filesys.h"
#include "settings.h"
-#include "main.h"
#include "log.h"
-
struct EnumString ModApiMapgen::es_BiomeTerrainType[] =
{
- {BIOME_TYPE_NORMAL, "normal"},
- {BIOME_TYPE_LIQUID, "liquid"},
- {BIOME_TYPE_NETHER, "nether"},
- {BIOME_TYPE_AETHER, "aether"},
- {BIOME_TYPE_FLAT, "flat"},
+ {BIOME_NORMAL, "normal"},
+ {BIOME_LIQUID, "liquid"},
+ {BIOME_NETHER, "nether"},
+ {BIOME_AETHER, "aether"},
+ {BIOME_FLAT, "flat"},
{0, NULL},
};
@@ -68,10 +68,10 @@ struct EnumString ModApiMapgen::es_MapgenObject[] =
struct EnumString ModApiMapgen::es_OreType[] =
{
- {ORE_TYPE_SCATTER, "scatter"},
- {ORE_TYPE_SHEET, "sheet"},
- {ORE_TYPE_BLOB, "blob"},
- {ORE_TYPE_VEIN, "vein"},
+ {ORE_SCATTER, "scatter"},
+ {ORE_SHEET, "sheet"},
+ {ORE_BLOB, "blob"},
+ {ORE_VEIN, "vein"},
{0, NULL},
};
@@ -85,116 +85,238 @@ struct EnumString ModApiMapgen::es_Rotation[] =
{0, NULL},
};
+struct EnumString ModApiMapgen::es_SchematicFormatType[] =
+{
+ {SCHEM_FMT_HANDLE, "handle"},
+ {SCHEM_FMT_MTS, "mts"},
+ {SCHEM_FMT_LUA, "lua"},
+ {0, NULL},
+};
+
+ObjDef *get_objdef(lua_State *L, int index, ObjDefManager *objmgr);
+
+Biome *get_or_load_biome(lua_State *L, int index,
+ BiomeManager *biomemgr);
+Biome *read_biome_def(lua_State *L, int index, INodeDefManager *ndef);
+size_t get_biome_list(lua_State *L, int index,
+ BiomeManager *biomemgr, std::set<u8> *biome_id_list);
+
+Schematic *get_or_load_schematic(lua_State *L, int index,
+ SchematicManager *schemmgr, StringMap *replace_names);
+Schematic *load_schematic(lua_State *L, int index, INodeDefManager *ndef,
+ StringMap *replace_names);
+Schematic *load_schematic_from_def(lua_State *L, int index,
+ INodeDefManager *ndef, StringMap *replace_names);
+bool read_schematic_def(lua_State *L, int index,
+ Schematic *schem, std::vector<std::string> *names);
+
+bool read_deco_simple(lua_State *L, DecoSimple *deco);
+bool read_deco_schematic(lua_State *L, SchematicManager *schemmgr, DecoSchematic *deco);
+
///////////////////////////////////////////////////////////////////////////////
+ObjDef *get_objdef(lua_State *L, int index, ObjDefManager *objmgr)
+{
+ if (index < 0)
+ index = lua_gettop(L) + 1 + index;
-bool read_schematic(lua_State *L, int index, Schematic *schem,
- INodeDefManager *ndef, std::map<std::string, std::string> &replace_names)
+ // If a number, assume this is a handle to an object def
+ if (lua_isnumber(L, index))
+ return objmgr->get(lua_tointeger(L, index));
+
+ // If a string, assume a name is given instead
+ if (lua_isstring(L, index))
+ return objmgr->getByName(lua_tostring(L, index));
+
+ return NULL;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+Schematic *get_or_load_schematic(lua_State *L, int index,
+ SchematicManager *schemmgr, StringMap *replace_names)
{
+ if (index < 0)
+ index = lua_gettop(L) + 1 + index;
+
+ Schematic *schem = (Schematic *)get_objdef(L, index, schemmgr);
+ if (schem)
+ return schem;
+
+ schem = load_schematic(L, index, schemmgr->getNodeDef(),
+ replace_names);
+ if (!schem)
+ return NULL;
+
+ if (schemmgr->add(schem) == OBJDEF_INVALID_HANDLE) {
+ delete schem;
+ return NULL;
+ }
+
+ return schem;
+}
+
+
+Schematic *load_schematic(lua_State *L, int index, INodeDefManager *ndef,
+ StringMap *replace_names)
+{
+ if (index < 0)
+ index = lua_gettop(L) + 1 + index;
+
+ Schematic *schem = NULL;
+
+ if (lua_istable(L, index)) {
+ schem = load_schematic_from_def(L, index, ndef,
+ replace_names);
+ if (!schem) {
+ delete schem;
+ return NULL;
+ }
+ } else if (lua_isnumber(L, index)) {
+ return NULL;
+ } else if (lua_isstring(L, index)) {
+ schem = SchematicManager::create(SCHEMATIC_NORMAL);
+
+ std::string filepath = lua_tostring(L, index);
+ if (!fs::IsPathAbsolute(filepath))
+ filepath = ModApiBase::getCurrentModPath(L) + DIR_DELIM + filepath;
+
+ if (!schem->loadSchematicFromFile(filepath, ndef,
+ replace_names)) {
+ delete schem;
+ return NULL;
+ }
+ }
+
+ return schem;
+}
+
+
+Schematic *load_schematic_from_def(lua_State *L, int index,
+ INodeDefManager *ndef, StringMap *replace_names)
+{
+ Schematic *schem = SchematicManager::create(SCHEMATIC_NORMAL);
+
+ if (!read_schematic_def(L, index, schem, &schem->m_nodenames)) {
+ delete schem;
+ return NULL;
+ }
+
+ size_t num_nodes = schem->m_nodenames.size();
+
+ schem->m_nnlistsizes.push_back(num_nodes);
+
+ if (replace_names) {
+ for (size_t i = 0; i != num_nodes; i++) {
+ StringMap::iterator it = replace_names->find(schem->m_nodenames[i]);
+ if (it != replace_names->end())
+ schem->m_nodenames[i] = it->second;
+ }
+ }
+
+ if (ndef)
+ ndef->pendNodeResolve(schem);
+
+ return schem;
+}
+
+
+bool read_schematic_def(lua_State *L, int index,
+ Schematic *schem, std::vector<std::string> *names)
+{
+ if (!lua_istable(L, index))
+ return false;
+
//// Get schematic size
lua_getfield(L, index, "size");
- v3s16 size = read_v3s16(L, -1);
+ v3s16 size = check_v3s16(L, -1);
lua_pop(L, 1);
+ schem->size = size;
+
//// Get schematic data
lua_getfield(L, index, "data");
luaL_checktype(L, -1, LUA_TTABLE);
- int numnodes = size.X * size.Y * size.Z;
- MapNode *schemdata = new MapNode[numnodes];
- int i = 0;
+ u32 numnodes = size.X * size.Y * size.Z;
+ schem->schemdata = new MapNode[numnodes];
- lua_pushnil(L);
- while (lua_next(L, -2)) {
- if (i >= numnodes) {
- i++;
- lua_pop(L, 1);
+ size_t names_base = names->size();
+ std::map<std::string, content_t> name_id_map;
+
+ u32 i = 0;
+ for (lua_pushnil(L); lua_next(L, -2); i++, lua_pop(L, 1)) {
+ if (i >= numnodes)
continue;
- }
- // same as readnode, except param1 default is MTSCHEM_PROB_CONST
- lua_getfield(L, -1, "name");
- std::string name = luaL_checkstring(L, -1);
- lua_pop(L, 1);
+ //// Read name
+ std::string name;
+ if (!getstringfield(L, -1, "name", name))
+ throw LuaError("Schematic data definition with missing name field");
+ //// Read param1/prob
u8 param1;
- lua_getfield(L, -1, "param1");
- param1 = !lua_isnil(L, -1) ? lua_tonumber(L, -1) : MTSCHEM_PROB_ALWAYS;
- lua_pop(L, 1);
-
- u8 param2;
- lua_getfield(L, -1, "param2");
- param2 = !lua_isnil(L, -1) ? lua_tonumber(L, -1) : 0;
- lua_pop(L, 1);
-
- std::map<std::string, std::string>::iterator it;
- it = replace_names.find(name);
- if (it != replace_names.end())
- name = it->second;
+ if (!getintfield(L, -1, "param1", param1) &&
+ !getintfield(L, -1, "prob", param1))
+ param1 = MTSCHEM_PROB_ALWAYS_OLD;
+
+ //// Read param2
+ u8 param2 = getintfield_default(L, -1, "param2", 0);
+
+ //// Find or add new nodename-to-ID mapping
+ std::map<std::string, content_t>::iterator it = name_id_map.find(name);
+ content_t name_index;
+ if (it != name_id_map.end()) {
+ name_index = it->second;
+ } else {
+ name_index = names->size() - names_base;
+ name_id_map[name] = name_index;
+ names->push_back(name);
+ }
- schemdata[i] = MapNode(ndef, name, param1, param2);
+ //// Perform probability/force_place fixup on param1
+ param1 >>= 1;
+ if (getboolfield_default(L, -1, "force_place", false))
+ param1 |= MTSCHEM_FORCE_PLACE;
- i++;
- lua_pop(L, 1);
+ //// Actually set the node in the schematic
+ schem->schemdata[i] = MapNode(name_index, param1, param2);
}
if (i != numnodes) {
- errorstream << "read_schematic: incorrect number of "
+ errorstream << "read_schematic_def: incorrect number of "
"nodes provided in raw schematic data (got " << i <<
", expected " << numnodes << ")." << std::endl;
- delete schemdata;
return false;
}
//// Get Y-slice probability values (if present)
- u8 *slice_probs = new u8[size.Y];
- for (i = 0; i != size.Y; i++)
- slice_probs[i] = MTSCHEM_PROB_ALWAYS;
+ schem->slice_probs = new u8[size.Y];
+ for (i = 0; i != (u32) size.Y; i++)
+ schem->slice_probs[i] = MTSCHEM_PROB_ALWAYS;
lua_getfield(L, index, "yslice_prob");
if (lua_istable(L, -1)) {
- lua_pushnil(L);
- while (lua_next(L, -2)) {
- if (getintfield(L, -1, "ypos", i) && i >= 0 && i < size.Y) {
- slice_probs[i] = getintfield_default(L, -1,
- "prob", MTSCHEM_PROB_ALWAYS);
- }
- lua_pop(L, 1);
+ for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) {
+ u16 ypos;
+ if (!getintfield(L, -1, "ypos", ypos) || (ypos >= size.Y) ||
+ !getintfield(L, -1, "prob", schem->slice_probs[ypos]))
+ continue;
+
+ schem->slice_probs[ypos] >>= 1;
}
}
- // Here, we read the nodes directly from the INodeDefManager - there is no
- // need for pending node resolutions so we'll mark this schematic as updated
- schem->flags = SCHEM_CIDS_UPDATED;
-
- schem->size = size;
- schem->schemdata = schemdata;
- schem->slice_probs = slice_probs;
return true;
}
-bool get_schematic(lua_State *L, int index, Schematic *schem,
- INodeDefManager *ndef, std::map<std::string, std::string> &replace_names)
+void read_schematic_replacements(lua_State *L, int index, StringMap *replace_names)
{
if (index < 0)
index = lua_gettop(L) + 1 + index;
- if (lua_istable(L, index)) {
- return read_schematic(L, index, schem, ndef, replace_names);
- } else if (lua_isstring(L, index)) {
- const char *filename = lua_tostring(L, index);
- return schem->loadSchematicFromFile(filename, ndef, replace_names);
- } else {
- return false;
- }
-}
-
-
-void read_schematic_replacements(lua_State *L,
- std::map<std::string, std::string> &replace_names, int index)
-{
lua_pushnil(L);
while (lua_next(L, index)) {
std::string replace_from;
@@ -213,11 +335,119 @@ void read_schematic_replacements(lua_State *L,
replace_to = lua_tostring(L, -1);
}
- replace_names[replace_from] = replace_to;
+ replace_names->insert(std::make_pair(replace_from, replace_to));
lua_pop(L, 1);
}
}
+///////////////////////////////////////////////////////////////////////////////
+
+Biome *get_or_load_biome(lua_State *L, int index, BiomeManager *biomemgr)
+{
+ if (index < 0)
+ index = lua_gettop(L) + 1 + index;
+
+ Biome *biome = (Biome *)get_objdef(L, index, biomemgr);
+ if (biome)
+ return biome;
+
+ biome = read_biome_def(L, index, biomemgr->getNodeDef());
+ if (!biome)
+ return NULL;
+
+ if (biomemgr->add(biome) == OBJDEF_INVALID_HANDLE) {
+ delete biome;
+ return NULL;
+ }
+
+ return biome;
+}
+
+
+Biome *read_biome_def(lua_State *L, int index, INodeDefManager *ndef)
+{
+ if (!lua_istable(L, index))
+ return NULL;
+
+ BiomeType biometype = (BiomeType)getenumfield(L, index, "type",
+ ModApiMapgen::es_BiomeTerrainType, BIOME_NORMAL);
+ Biome *b = BiomeManager::create(biometype);
+
+ b->name = getstringfield_default(L, index, "name", "");
+ b->depth_top = getintfield_default(L, index, "depth_top", 0);
+ b->depth_filler = getintfield_default(L, index, "depth_filler", -31000);
+ b->depth_water_top = getintfield_default(L, index, "depth_water_top", 0);
+ b->y_min = getintfield_default(L, index, "y_min", -31000);
+ b->y_max = getintfield_default(L, index, "y_max", 31000);
+ b->heat_point = getfloatfield_default(L, index, "heat_point", 0.f);
+ b->humidity_point = getfloatfield_default(L, index, "humidity_point", 0.f);
+ b->flags = 0; //reserved
+
+ std::vector<std::string> &nn = b->m_nodenames;
+ nn.push_back(getstringfield_default(L, index, "node_top", ""));
+ nn.push_back(getstringfield_default(L, index, "node_filler", ""));
+ nn.push_back(getstringfield_default(L, index, "node_stone", ""));
+ nn.push_back(getstringfield_default(L, index, "node_water_top", ""));
+ nn.push_back(getstringfield_default(L, index, "node_water", ""));
+ nn.push_back(getstringfield_default(L, index, "node_river_water", ""));
+ nn.push_back(getstringfield_default(L, index, "node_dust", ""));
+ ndef->pendNodeResolve(b);
+
+ return b;
+}
+
+
+size_t get_biome_list(lua_State *L, int index,
+ BiomeManager *biomemgr, std::set<u8> *biome_id_list)
+{
+ if (index < 0)
+ index = lua_gettop(L) + 1 + index;
+
+ if (lua_isnil(L, index))
+ return 0;
+
+ bool is_single = true;
+ if (lua_istable(L, index)) {
+ lua_getfield(L, index, "name");
+ is_single = !lua_isnil(L, -1);
+ lua_pop(L, 1);
+ }
+
+ if (is_single) {
+ Biome *biome = get_or_load_biome(L, index, biomemgr);
+ if (!biome) {
+ errorstream << "get_biome_list: failed to get biome '"
+ << (lua_isstring(L, index) ? lua_tostring(L, index) : "")
+ << "'." << std::endl;
+ return 1;
+ }
+
+ biome_id_list->insert(biome->index);
+ return 0;
+ }
+
+ // returns number of failed resolutions
+ size_t fail_count = 0;
+ size_t count = 0;
+
+ for (lua_pushnil(L); lua_next(L, index); lua_pop(L, 1)) {
+ count++;
+ Biome *biome = get_or_load_biome(L, -1, biomemgr);
+ if (!biome) {
+ fail_count++;
+ errorstream << "get_biome_list: failed to get biome '"
+ << (lua_isstring(L, -1) ? lua_tostring(L, -1) : "")
+ << "'" << std::endl;
+ continue;
+ }
+
+ biome_id_list->insert(biome->index);
+ }
+
+ return fail_count;
+}
+
+///////////////////////////////////////////////////////////////////////////////
// get_mapgen_object(objectname)
// returns the requested object used during map generation
@@ -239,92 +469,98 @@ int ModApiMapgen::l_get_mapgen_object(lua_State *L)
size_t maplen = mg->csize.X * mg->csize.Z;
switch (mgobj) {
- case MGOBJ_VMANIP: {
- MMVManip *vm = mg->vm;
+ case MGOBJ_VMANIP: {
+ MMVManip *vm = mg->vm;
- // VoxelManip object
- LuaVoxelManip *o = new LuaVoxelManip(vm, true);
- *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
- luaL_getmetatable(L, "VoxelManip");
- lua_setmetatable(L, -2);
+ // VoxelManip object
+ LuaVoxelManip *o = new LuaVoxelManip(vm, true);
+ *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
+ luaL_getmetatable(L, "VoxelManip");
+ lua_setmetatable(L, -2);
- // emerged min pos
- push_v3s16(L, vm->m_area.MinEdge);
+ // emerged min pos
+ push_v3s16(L, vm->m_area.MinEdge);
- // emerged max pos
- push_v3s16(L, vm->m_area.MaxEdge);
+ // emerged max pos
+ push_v3s16(L, vm->m_area.MaxEdge);
- return 3;
+ return 3;
+ }
+ case MGOBJ_HEIGHTMAP: {
+ if (!mg->heightmap)
+ return 0;
+
+ lua_newtable(L);
+ for (size_t i = 0; i != maplen; i++) {
+ lua_pushinteger(L, mg->heightmap[i]);
+ lua_rawseti(L, -2, i + 1);
}
- case MGOBJ_HEIGHTMAP: {
- if (!mg->heightmap)
- return 0;
-
- lua_newtable(L);
- for (size_t i = 0; i != maplen; i++) {
- lua_pushinteger(L, mg->heightmap[i]);
- lua_rawseti(L, -2, i + 1);
- }
- return 1;
+ return 1;
+ }
+ case MGOBJ_BIOMEMAP: {
+ if (!mg->biomemap)
+ return 0;
+
+ lua_newtable(L);
+ for (size_t i = 0; i != maplen; i++) {
+ lua_pushinteger(L, mg->biomemap[i]);
+ lua_rawseti(L, -2, i + 1);
}
- case MGOBJ_BIOMEMAP: {
- if (!mg->biomemap)
- return 0;
- lua_newtable(L);
- for (size_t i = 0; i != maplen; i++) {
- lua_pushinteger(L, mg->biomemap[i]);
- lua_rawseti(L, -2, i + 1);
- }
-
- return 1;
+ return 1;
+ }
+ case MGOBJ_HEATMAP: {
+ if (!mg->heatmap)
+ return 0;
+
+ lua_newtable(L);
+ for (size_t i = 0; i != maplen; i++) {
+ lua_pushnumber(L, mg->heatmap[i]);
+ lua_rawseti(L, -2, i + 1);
}
- case MGOBJ_HEATMAP: { // Mapgen V7 specific objects
- case MGOBJ_HUMIDMAP:
- if (strcmp(emerge->params.mg_name.c_str(), "v7"))
- return 0;
-
- MapgenV7 *mgv7 = (MapgenV7 *)mg;
- float *arr = (mgobj == MGOBJ_HEATMAP) ?
- mgv7->noise_heat->result : mgv7->noise_humidity->result;
- if (!arr)
- return 0;
+ return 1;
+ }
- lua_newtable(L);
- for (size_t i = 0; i != maplen; i++) {
- lua_pushnumber(L, arr[i]);
- lua_rawseti(L, -2, i + 1);
- }
+ case MGOBJ_HUMIDMAP: {
+ if (!mg->humidmap)
+ return 0;
- return 1;
+ lua_newtable(L);
+ for (size_t i = 0; i != maplen; i++) {
+ lua_pushnumber(L, mg->humidmap[i]);
+ lua_rawseti(L, -2, i + 1);
}
- case MGOBJ_GENNOTIFY: {
- std::map<std::string, std::vector<v3s16> >event_map;
- std::map<std::string, std::vector<v3s16> >::iterator it;
- mg->gennotify.getEvents(event_map);
+ return 1;
+ }
+ case MGOBJ_GENNOTIFY: {
+ std::map<std::string, std::vector<v3s16> >event_map;
+ std::map<std::string, std::vector<v3s16> >::iterator it;
- lua_newtable(L);
- for (it = event_map.begin(); it != event_map.end(); ++it) {
- lua_newtable(L);
+ mg->gennotify.getEvents(event_map);
- for (size_t j = 0; j != it->second.size(); j++) {
- push_v3s16(L, it->second[j]);
- lua_rawseti(L, -2, j + 1);
- }
+ lua_newtable(L);
+ for (it = event_map.begin(); it != event_map.end(); ++it) {
+ lua_newtable(L);
- lua_setfield(L, -2, it->first.c_str());
+ for (size_t j = 0; j != it->second.size(); j++) {
+ push_v3s16(L, it->second[j]);
+ lua_rawseti(L, -2, j + 1);
}
- return 1;
+ lua_setfield(L, -2, it->first.c_str());
}
+
+ return 1;
+ }
}
return 0;
}
+
int ModApiMapgen::l_get_mapgen_params(lua_State *L)
{
MapgenParams *params = &getServer(L)->getEmergeManager()->params;
@@ -350,6 +586,7 @@ int ModApiMapgen::l_get_mapgen_params(lua_State *L)
return 1;
}
+
// set_mapgen_params(params)
// set mapgen parameters
int ModApiMapgen::l_set_mapgen_params(lua_State *L)
@@ -389,6 +626,7 @@ int ModApiMapgen::l_set_mapgen_params(lua_State *L)
return 0;
}
+
// set_noiseparams(name, noiseparams, set_default)
// set global config values for noise parameters
int ModApiMapgen::l_set_noiseparams(lua_State *L)
@@ -406,6 +644,21 @@ int ModApiMapgen::l_set_noiseparams(lua_State *L)
return 0;
}
+
+// get_noiseparams(name)
+int ModApiMapgen::l_get_noiseparams(lua_State *L)
+{
+ std::string name = luaL_checkstring(L, 1);
+
+ NoiseParams np;
+ if (!g_settings->getNoiseParams(name, np))
+ return 0;
+
+ push_noiseparams(L, &np);
+ return 1;
+}
+
+
// set_gen_notify(flags, {deco_id_table})
int ModApiMapgen::l_set_gen_notify(lua_State *L)
{
@@ -421,7 +674,7 @@ int ModApiMapgen::l_set_gen_notify(lua_State *L)
lua_pushnil(L);
while (lua_next(L, 2)) {
if (lua_isnumber(L, -1))
- emerge->gen_notify_on_deco_ids.insert(lua_tonumber(L, -1));
+ emerge->gen_notify_on_deco_ids.insert((u32)lua_tonumber(L, -1));
lua_pop(L, 1);
}
}
@@ -429,6 +682,26 @@ int ModApiMapgen::l_set_gen_notify(lua_State *L)
return 0;
}
+
+// get_gen_notify()
+int ModApiMapgen::l_get_gen_notify(lua_State *L)
+{
+ EmergeManager *emerge = getServer(L)->getEmergeManager();
+ push_flags_string(L, flagdesc_gennotify, emerge->gen_notify_on,
+ emerge->gen_notify_on);
+
+ lua_newtable(L);
+ int i = 1;
+ for (std::set<u32>::iterator it = emerge->gen_notify_on_deco_ids.begin();
+ it != emerge->gen_notify_on_deco_ids.end(); ++it) {
+ lua_pushnumber(L, *it);
+ lua_rawseti(L, -2, i);
+ i++;
+ }
+ return 2;
+}
+
+
// register_biome({lots of stuff})
int ModApiMapgen::l_register_biome(lua_State *L)
{
@@ -438,66 +711,20 @@ int ModApiMapgen::l_register_biome(lua_State *L)
INodeDefManager *ndef = getServer(L)->getNodeDefManager();
BiomeManager *bmgr = getServer(L)->getEmergeManager()->biomemgr;
- enum BiomeType biometype = (BiomeType)getenumfield(L, index, "type",
- es_BiomeTerrainType, BIOME_TYPE_NORMAL);
- Biome *b = bmgr->create(biometype);
-
- b->name = getstringfield_default(L, index, "name", "");
- b->depth_top = getintfield_default(L, index, "depth_top", 1);
- b->depth_filler = getintfield_default(L, index, "depth_filler", 3);
- b->height_shore = getintfield_default(L, index, "height_shore", 3);
- b->depth_water_top = getintfield_default(L, index, "depth_water_top", 0);
- b->y_min = getintfield_default(L, index, "y_min", -31000);
- b->y_max = getintfield_default(L, index, "y_max", 31000);
- b->heat_point = getfloatfield_default(L, index, "heat_point", 0.f);
- b->humidity_point = getfloatfield_default(L, index, "humidity_point", 0.f);
- b->flags = 0; //reserved
+ Biome *biome = read_biome_def(L, index, ndef);
+ if (!biome)
+ return 0;
- u32 id = bmgr->add(b);
- if (id == (u32)-1) {
- delete b;
+ ObjDefHandle handle = bmgr->add(biome);
+ if (handle == OBJDEF_INVALID_HANDLE) {
+ delete biome;
return 0;
}
- NodeResolveInfo *nri = new NodeResolveInfo(b);
- std::list<std::string> &nnames = nri->nodenames;
- nnames.push_back(getstringfield_default(L, index, "node_top", ""));
- nnames.push_back(getstringfield_default(L, index, "node_filler", ""));
- nnames.push_back(getstringfield_default(L, index, "node_shore_top", ""));
- nnames.push_back(getstringfield_default(L, index, "node_shore_filler", ""));
- nnames.push_back(getstringfield_default(L, index, "node_underwater", ""));
- nnames.push_back(getstringfield_default(L, index, "node_stone", ""));
- nnames.push_back(getstringfield_default(L, index, "node_water_top", ""));
- nnames.push_back(getstringfield_default(L, index, "node_water", ""));
- nnames.push_back(getstringfield_default(L, index, "node_dust", ""));
- ndef->pendNodeResolve(nri);
-
- verbosestream << "register_biome: " << b->name << std::endl;
-
- lua_pushinteger(L, id);
+ lua_pushinteger(L, handle);
return 1;
}
-int ModApiMapgen::l_clear_registered_biomes(lua_State *L)
-{
- BiomeManager *bmgr = getServer(L)->getEmergeManager()->biomemgr;
- bmgr->clear();
- return 0;
-}
-
-int ModApiMapgen::l_clear_registered_decorations(lua_State *L)
-{
- DecorationManager *dmgr = getServer(L)->getEmergeManager()->decomgr;
- dmgr->clear();
- return 0;
-}
-
-int ModApiMapgen::l_clear_registered_ores(lua_State *L)
-{
- OreManager *omgr = getServer(L)->getEmergeManager()->oremgr;
- omgr->clear();
- return 0;
-}
// register_decoration({lots of stuff})
int ModApiMapgen::l_register_decoration(lua_State *L)
@@ -508,6 +735,7 @@ int ModApiMapgen::l_register_decoration(lua_State *L)
INodeDefManager *ndef = getServer(L)->getNodeDefManager();
DecorationManager *decomgr = getServer(L)->getEmergeManager()->decomgr;
BiomeManager *biomemgr = getServer(L)->getEmergeManager()->biomemgr;
+ SchematicManager *schemmgr = getServer(L)->getEmergeManager()->schemmgr;
enum DecorationType decotype = (DecorationType)getenumfield(L, index,
"deco_type", es_DecorationType, -1);
@@ -515,7 +743,7 @@ int ModApiMapgen::l_register_decoration(lua_State *L)
Decoration *deco = decomgr->create(decotype);
if (!deco) {
errorstream << "register_decoration: decoration placement type "
- << decotype << " not implemented";
+ << decotype << " not implemented" << std::endl;
return 0;
}
@@ -531,15 +759,11 @@ int ModApiMapgen::l_register_decoration(lua_State *L)
return 0;
}
- NodeResolveInfo *nri = new NodeResolveInfo(deco);
-
//// Get node name(s) to place decoration on
- std::vector<const char *> place_on_names;
- getstringlistfield(L, index, "place_on", place_on_names);
- nri->nodelistinfo.push_back(NodeListInfo(place_on_names.size()));
- for (size_t i = 0; i != place_on_names.size(); i++)
- nri->nodenames.push_back(place_on_names[i]);
+ size_t nread = getstringlistfield(L, index, "place_on", &deco->m_nodenames);
+ deco->m_nnlistsizes.push_back(nread);
+ //// Get decoration flags
getflagsfield(L, index, "flags", flagdesc_deco, &deco->flags, NULL);
//// Get NoiseParams to define how decoration is placed
@@ -549,51 +773,45 @@ int ModApiMapgen::l_register_decoration(lua_State *L)
lua_pop(L, 1);
//// Get biomes associated with this decoration (if any)
- std::vector<const char *> biome_list;
- getstringlistfield(L, index, "biomes", biome_list);
- for (size_t i = 0; i != biome_list.size(); i++) {
- Biome *b = (Biome *)biomemgr->getByName(biome_list[i]);
- if (!b)
- continue;
-
- deco->biomes.insert(b->id);
- }
+ lua_getfield(L, index, "biomes");
+ if (get_biome_list(L, -1, biomemgr, &deco->biomes))
+ errorstream << "register_decoration: couldn't get all biomes " << std::endl;
+ lua_pop(L, 1);
//// Handle decoration type-specific parameters
bool success = false;
switch (decotype) {
- case DECO_SIMPLE:
- success = regDecoSimple(L, nri, (DecoSimple *)deco);
- break;
- case DECO_SCHEMATIC:
- success = regDecoSchematic(L, ndef, (DecoSchematic *)deco);
- break;
- case DECO_LSYSTEM:
- break;
+ case DECO_SIMPLE:
+ success = read_deco_simple(L, (DecoSimple *)deco);
+ break;
+ case DECO_SCHEMATIC:
+ success = read_deco_schematic(L, schemmgr, (DecoSchematic *)deco);
+ break;
+ case DECO_LSYSTEM:
+ break;
}
- ndef->pendNodeResolve(nri);
-
if (!success) {
delete deco;
return 0;
}
- u32 id = decomgr->add(deco);
- if (id == (u32)-1) {
+ ndef->pendNodeResolve(deco);
+
+ ObjDefHandle handle = decomgr->add(deco);
+ if (handle == OBJDEF_INVALID_HANDLE) {
delete deco;
return 0;
}
- verbosestream << "register_decoration: " << deco->name << std::endl;
-
- lua_pushinteger(L, id);
+ lua_pushinteger(L, handle);
return 1;
}
-bool ModApiMapgen::regDecoSimple(lua_State *L,
- NodeResolveInfo *nri, DecoSimple *deco)
+
+bool read_deco_simple(lua_State *L, DecoSimple *deco)
{
+ size_t nnames;
int index = 1;
deco->deco_height = getintfield_default(L, index, "height", 1);
@@ -606,60 +824,48 @@ bool ModApiMapgen::regDecoSimple(lua_State *L,
return false;
}
- std::vector<const char *> deco_names;
- getstringlistfield(L, index, "decoration", deco_names);
- if (deco_names.size() == 0) {
+ nnames = getstringlistfield(L, index, "decoration", &deco->m_nodenames);
+ deco->m_nnlistsizes.push_back(nnames);
+ if (nnames == 0) {
errorstream << "register_decoration: no decoration nodes "
"defined" << std::endl;
return false;
}
- nri->nodelistinfo.push_back(NodeListInfo(deco_names.size()));
- for (size_t i = 0; i != deco_names.size(); i++)
- nri->nodenames.push_back(deco_names[i]);
- std::vector<const char *> spawnby_names;
- getstringlistfield(L, index, "spawn_by", spawnby_names);
- if (deco->nspawnby != -1 && spawnby_names.size() == 0) {
+ nnames = getstringlistfield(L, index, "spawn_by", &deco->m_nodenames);
+ deco->m_nnlistsizes.push_back(nnames);
+ if (nnames == 0 && deco->nspawnby != -1) {
errorstream << "register_decoration: no spawn_by nodes defined,"
" but num_spawn_by specified" << std::endl;
return false;
}
- nri->nodelistinfo.push_back(NodeListInfo(spawnby_names.size()));
- for (size_t i = 0; i != spawnby_names.size(); i++)
- nri->nodenames.push_back(spawnby_names[i]);
return true;
}
-bool ModApiMapgen::regDecoSchematic(lua_State *L, INodeDefManager *ndef,
- DecoSchematic *deco)
+
+bool read_deco_schematic(lua_State *L, SchematicManager *schemmgr, DecoSchematic *deco)
{
int index = 1;
deco->rotation = (Rotation)getenumfield(L, index, "rotation",
- es_Rotation, ROTATE_0);
+ ModApiMapgen::es_Rotation, ROTATE_0);
- std::map<std::string, std::string> replace_names;
+ StringMap replace_names;
lua_getfield(L, index, "replacements");
if (lua_istable(L, -1))
- read_schematic_replacements(L, replace_names, lua_gettop(L));
+ read_schematic_replacements(L, -1, &replace_names);
lua_pop(L, 1);
- // TODO(hmmmm): get a ref from registered schematics
- Schematic *schem = new Schematic;
lua_getfield(L, index, "schematic");
- if (!get_schematic(L, -1, schem, ndef, replace_names)) {
- lua_pop(L, 1);
- delete schem;
- return false;
- }
+ Schematic *schem = get_or_load_schematic(L, -1, schemmgr, &replace_names);
lua_pop(L, 1);
deco->schematic = schem;
-
- return true;
+ return schem != NULL;
}
+
// register_ore({lots of stuff})
int ModApiMapgen::l_register_ore(lua_State *L)
{
@@ -667,10 +873,11 @@ int ModApiMapgen::l_register_ore(lua_State *L)
luaL_checktype(L, index, LUA_TTABLE);
INodeDefManager *ndef = getServer(L)->getNodeDefManager();
+ BiomeManager *bmgr = getServer(L)->getEmergeManager()->biomemgr;
OreManager *oremgr = getServer(L)->getEmergeManager()->oremgr;
enum OreType oretype = (OreType)getenumfield(L, index,
- "ore_type", es_OreType, ORE_TYPE_SCATTER);
+ "ore_type", es_OreType, ORE_SCATTER);
Ore *ore = oremgr->create(oretype);
if (!ore) {
errorstream << "register_ore: ore_type " << oretype << " not implemented";
@@ -686,6 +893,7 @@ int ModApiMapgen::l_register_ore(lua_State *L)
ore->noise = NULL;
ore->flags = 0;
+ //// Get y_min/y_max
warn_if_field_exists(L, index, "height_min",
"Deprecated: new name is \"y_min\".");
warn_if_field_exists(L, index, "height_max",
@@ -708,8 +916,16 @@ int ModApiMapgen::l_register_ore(lua_State *L)
return 0;
}
+ //// Get flags
getflagsfield(L, index, "flags", flagdesc_ore, &ore->flags, NULL);
+ //// Get biomes associated with this decoration (if any)
+ lua_getfield(L, index, "biomes");
+ if (get_biome_list(L, -1, bmgr, &ore->biomes))
+ errorstream << "register_ore: couldn't get all biomes " << std::endl;
+ lua_pop(L, 1);
+
+ //// Get noise parameters if needed
lua_getfield(L, index, "noise_params");
if (read_noiseparams(L, -1, &ore->np)) {
ore->flags |= OREFLAG_USE_NOISE;
@@ -721,45 +937,152 @@ int ModApiMapgen::l_register_ore(lua_State *L)
}
lua_pop(L, 1);
- if (oretype == ORE_TYPE_VEIN) {
+ if (oretype == ORE_VEIN) {
OreVein *orevein = (OreVein *)ore;
orevein->random_factor = getfloatfield_default(L, index,
"random_factor", 1.f);
}
- u32 id = oremgr->add(ore);
- if (id == (u32)-1) {
+ ObjDefHandle handle = oremgr->add(ore);
+ if (handle == OBJDEF_INVALID_HANDLE) {
delete ore;
return 0;
}
- NodeResolveInfo *nri = new NodeResolveInfo(ore);
- nri->nodenames.push_back(getstringfield_default(L, index, "ore", ""));
+ ore->m_nodenames.push_back(getstringfield_default(L, index, "ore", ""));
+
+ size_t nnames = getstringlistfield(L, index, "wherein", &ore->m_nodenames);
+ ore->m_nnlistsizes.push_back(nnames);
+
+ ndef->pendNodeResolve(ore);
+
+ lua_pushinteger(L, handle);
+ return 1;
+}
+
- std::vector<const char *> wherein_names;
- getstringlistfield(L, index, "wherein", wherein_names);
- nri->nodelistinfo.push_back(NodeListInfo(wherein_names.size()));
- for (size_t i = 0; i != wherein_names.size(); i++)
- nri->nodenames.push_back(wherein_names[i]);
+// register_schematic({schematic}, replacements={})
+int ModApiMapgen::l_register_schematic(lua_State *L)
+{
+ SchematicManager *schemmgr = getServer(L)->getEmergeManager()->schemmgr;
+
+ StringMap replace_names;
+ if (lua_istable(L, 2))
+ read_schematic_replacements(L, 2, &replace_names);
- ndef->pendNodeResolve(nri);
+ Schematic *schem = load_schematic(L, 1, schemmgr->getNodeDef(),
+ &replace_names);
+ if (!schem)
+ return 0;
- verbosestream << "register_ore: " << ore->name << std::endl;
+ ObjDefHandle handle = schemmgr->add(schem);
+ if (handle == OBJDEF_INVALID_HANDLE) {
+ delete schem;
+ return 0;
+ }
- lua_pushinteger(L, id);
+ lua_pushinteger(L, handle);
return 1;
}
-// create_schematic(p1, p2, probability_list, filename)
+
+// clear_registered_biomes()
+int ModApiMapgen::l_clear_registered_biomes(lua_State *L)
+{
+ BiomeManager *bmgr = getServer(L)->getEmergeManager()->biomemgr;
+ bmgr->clear();
+ return 0;
+}
+
+
+// clear_registered_decorations()
+int ModApiMapgen::l_clear_registered_decorations(lua_State *L)
+{
+ DecorationManager *dmgr = getServer(L)->getEmergeManager()->decomgr;
+ dmgr->clear();
+ return 0;
+}
+
+
+// clear_registered_ores()
+int ModApiMapgen::l_clear_registered_ores(lua_State *L)
+{
+ OreManager *omgr = getServer(L)->getEmergeManager()->oremgr;
+ omgr->clear();
+ return 0;
+}
+
+
+// clear_registered_schematics()
+int ModApiMapgen::l_clear_registered_schematics(lua_State *L)
+{
+ SchematicManager *smgr = getServer(L)->getEmergeManager()->schemmgr;
+ smgr->clear();
+ return 0;
+}
+
+
+// generate_ores(vm, p1, p2, [ore_id])
+int ModApiMapgen::l_generate_ores(lua_State *L)
+{
+ EmergeManager *emerge = getServer(L)->getEmergeManager();
+
+ Mapgen mg;
+ mg.seed = emerge->params.seed;
+ mg.vm = LuaVoxelManip::checkobject(L, 1)->vm;
+ mg.ndef = getServer(L)->getNodeDefManager();
+
+ v3s16 pmin = lua_istable(L, 2) ? check_v3s16(L, 2) :
+ mg.vm->m_area.MinEdge + v3s16(1,1,1) * MAP_BLOCKSIZE;
+ v3s16 pmax = lua_istable(L, 3) ? check_v3s16(L, 3) :
+ mg.vm->m_area.MaxEdge - v3s16(1,1,1) * MAP_BLOCKSIZE;
+ sortBoxVerticies(pmin, pmax);
+
+ u32 blockseed = Mapgen::getBlockSeed(pmin, mg.seed);
+
+ emerge->oremgr->placeAllOres(&mg, blockseed, pmin, pmax);
+
+ return 0;
+}
+
+
+// generate_decorations(vm, p1, p2, [deco_id])
+int ModApiMapgen::l_generate_decorations(lua_State *L)
+{
+ EmergeManager *emerge = getServer(L)->getEmergeManager();
+
+ Mapgen mg;
+ mg.seed = emerge->params.seed;
+ mg.vm = LuaVoxelManip::checkobject(L, 1)->vm;
+ mg.ndef = getServer(L)->getNodeDefManager();
+
+ v3s16 pmin = lua_istable(L, 2) ? check_v3s16(L, 2) :
+ mg.vm->m_area.MinEdge + v3s16(1,1,1) * MAP_BLOCKSIZE;
+ v3s16 pmax = lua_istable(L, 3) ? check_v3s16(L, 3) :
+ mg.vm->m_area.MaxEdge - v3s16(1,1,1) * MAP_BLOCKSIZE;
+ sortBoxVerticies(pmin, pmax);
+
+ u32 blockseed = Mapgen::getBlockSeed(pmin, mg.seed);
+
+ emerge->decomgr->placeAllDecos(&mg, blockseed, pmin, pmax);
+
+ return 0;
+}
+
+
+// create_schematic(p1, p2, probability_list, filename, y_slice_prob_list)
int ModApiMapgen::l_create_schematic(lua_State *L)
{
- Schematic schem;
+ INodeDefManager *ndef = getServer(L)->getNodeDefManager();
+
+ const char *filename = luaL_checkstring(L, 4);
+ CHECK_SECURE_PATH_OPTIONAL(L, filename);
Map *map = &(getEnv(L)->getMap());
- INodeDefManager *ndef = getServer(L)->getNodeDefManager();
+ Schematic schem;
- v3s16 p1 = read_v3s16(L, 1);
- v3s16 p2 = read_v3s16(L, 2);
+ v3s16 p1 = check_v3s16(L, 1);
+ v3s16 p2 = check_v3s16(L, 2);
sortBoxVerticies(p1, p2);
std::vector<std::pair<v3s16, u8> > prob_list;
@@ -768,7 +1091,7 @@ int ModApiMapgen::l_create_schematic(lua_State *L)
while (lua_next(L, 3)) {
if (lua_istable(L, -1)) {
lua_getfield(L, -1, "pos");
- v3s16 pos = read_v3s16(L, -1);
+ v3s16 pos = check_v3s16(L, -1);
lua_pop(L, 1);
u8 prob = getintfield_default(L, -1, "prob", MTSCHEM_PROB_ALWAYS);
@@ -793,8 +1116,6 @@ int ModApiMapgen::l_create_schematic(lua_State *L)
}
}
- const char *filename = luaL_checkstring(L, 4);
-
if (!schem.getSchematicFromMap(map, p1, p2)) {
errorstream << "create_schematic: failed to get schematic "
"from map" << std::endl;
@@ -807,60 +1128,25 @@ int ModApiMapgen::l_create_schematic(lua_State *L)
actionstream << "create_schematic: saved schematic file '"
<< filename << "'." << std::endl;
+ lua_pushboolean(L, true);
return 1;
}
-// generate_ores(vm, [ore_id])
-int ModApiMapgen::l_generate_ores(lua_State *L)
-{
- EmergeManager *emerge = getServer(L)->getEmergeManager();
-
- Mapgen mg;
- mg.seed = emerge->params.seed;
- mg.vm = LuaVoxelManip::checkobject(L, 1)->vm;
- mg.ndef = getServer(L)->getNodeDefManager();
-
- u32 blockseed = Mapgen::getBlockSeed(mg.vm->m_area.MinEdge, mg.seed);
-
- emerge->oremgr->placeAllOres(&mg, blockseed,
- mg.vm->m_area.MinEdge, mg.vm->m_area.MaxEdge);
-
- return 0;
-}
-
-// generate_decorations(vm, [deco_id])
-int ModApiMapgen::l_generate_decorations(lua_State *L)
-{
- EmergeManager *emerge = getServer(L)->getEmergeManager();
-
- Mapgen mg;
- mg.seed = emerge->params.seed;
- mg.vm = LuaVoxelManip::checkobject(L, 1)->vm;
- mg.ndef = getServer(L)->getNodeDefManager();
-
- u32 blockseed = Mapgen::getBlockSeed(mg.vm->m_area.MinEdge, mg.seed);
-
- emerge->decomgr->placeAllDecos(&mg, blockseed,
- mg.vm->m_area.MinEdge, mg.vm->m_area.MaxEdge);
-
- return 0;
-}
// place_schematic(p, schematic, rotation, replacement)
int ModApiMapgen::l_place_schematic(lua_State *L)
{
- Schematic schem;
-
Map *map = &(getEnv(L)->getMap());
- INodeDefManager *ndef = getServer(L)->getNodeDefManager();
+ SchematicManager *schemmgr = getServer(L)->getEmergeManager()->schemmgr;
//// Read position
- v3s16 p = read_v3s16(L, 1);
+ v3s16 p = check_v3s16(L, 1);
//// Read rotation
int rot = ROTATE_0;
- if (lua_isstring(L, 3))
- string_to_enum(es_Rotation, rot, std::string(lua_tostring(L, 3)));
+ const char *enumstr = lua_tostring(L, 3);
+ if (enumstr)
+ string_to_enum(es_Rotation, rot, std::string(enumstr));
//// Read force placement
bool force_placement = true;
@@ -868,21 +1154,73 @@ int ModApiMapgen::l_place_schematic(lua_State *L)
force_placement = lua_toboolean(L, 5);
//// Read node replacements
- std::map<std::string, std::string> replace_names;
+ StringMap replace_names;
if (lua_istable(L, 4))
- read_schematic_replacements(L, replace_names, 4);
+ read_schematic_replacements(L, 4, &replace_names);
//// Read schematic
- if (!get_schematic(L, 2, &schem, ndef, replace_names)) {
+ Schematic *schem = get_or_load_schematic(L, 2, schemmgr, &replace_names);
+ if (!schem) {
errorstream << "place_schematic: failed to get schematic" << std::endl;
return 0;
}
- schem.placeStructure(map, p, 0, (Rotation)rot, force_placement, ndef);
+ schem->placeStructure(map, p, 0, (Rotation)rot, force_placement);
+
+ lua_pushboolean(L, true);
+ return 1;
+}
+
+// serialize_schematic(schematic, format, options={...})
+int ModApiMapgen::l_serialize_schematic(lua_State *L)
+{
+ SchematicManager *schemmgr = getServer(L)->getEmergeManager()->schemmgr;
+
+ //// Read options
+ bool use_comments = getboolfield_default(L, 3, "lua_use_comments", false);
+ u32 indent_spaces = getintfield_default(L, 3, "lua_num_indent_spaces", 0);
+
+ //// Get schematic
+ bool was_loaded = false;
+ Schematic *schem = (Schematic *)get_objdef(L, 1, schemmgr);
+ if (!schem) {
+ schem = load_schematic(L, 1, NULL, NULL);
+ was_loaded = true;
+ }
+ if (!schem) {
+ errorstream << "serialize_schematic: failed to get schematic" << std::endl;
+ return 0;
+ }
+
+ //// Read format of definition to save as
+ int schem_format = SCHEM_FMT_MTS;
+ const char *enumstr = lua_tostring(L, 2);
+ if (enumstr)
+ string_to_enum(es_SchematicFormatType, schem_format, std::string(enumstr));
+
+ //// Serialize to binary string
+ std::ostringstream os(std::ios_base::binary);
+ switch (schem_format) {
+ case SCHEM_FMT_MTS:
+ schem->serializeToMts(&os, schem->m_nodenames);
+ break;
+ case SCHEM_FMT_LUA:
+ schem->serializeToLua(&os, schem->m_nodenames,
+ use_comments, indent_spaces);
+ break;
+ default:
+ return 0;
+ }
+
+ if (was_loaded)
+ delete schem;
+ std::string ser = os.str();
+ lua_pushlstring(L, ser.c_str(), ser.length());
return 1;
}
+
void ModApiMapgen::Initialize(lua_State *L, int top)
{
API_FCT(get_mapgen_object);
@@ -890,19 +1228,23 @@ void ModApiMapgen::Initialize(lua_State *L, int top)
API_FCT(get_mapgen_params);
API_FCT(set_mapgen_params);
API_FCT(set_noiseparams);
+ API_FCT(get_noiseparams);
API_FCT(set_gen_notify);
+ API_FCT(get_gen_notify);
API_FCT(register_biome);
API_FCT(register_decoration);
API_FCT(register_ore);
+ API_FCT(register_schematic);
API_FCT(clear_registered_biomes);
API_FCT(clear_registered_decorations);
API_FCT(clear_registered_ores);
+ API_FCT(clear_registered_schematics);
API_FCT(generate_ores);
API_FCT(generate_decorations);
-
API_FCT(create_schematic);
API_FCT(place_schematic);
+ API_FCT(serialize_schematic);
}