From 7616537bc071bc93f8d36c84b94603528be1efb0 Mon Sep 17 00:00:00 2001
From: kwolekr <kwolekr@minetest.net>
Date: Wed, 12 Nov 2014 23:01:13 -0500
Subject: [PATCH] Add Generator Element Management framework

Add BiomeManager, OreManager, DecorationManager, and SchematicManager
---
 src/emerge.cpp                  |  28 +++---
 src/emerge.h                    |  32 ++++---
 src/mapgen.cpp                  |  84 ++++++++++++++++--
 src/mapgen.h                    |  43 ++++++++--
 src/mapgen_v5.cpp               |  16 ++--
 src/mapgen_v5.h                 |   2 +-
 src/mapgen_v6.cpp               |  10 +--
 src/mapgen_v6.h                 |   1 +
 src/mapgen_v7.cpp               |  22 ++---
 src/mapgen_v7.h                 |   3 +-
 src/mg_biome.cpp                |  87 +++++--------------
 src/mg_biome.h                  |  54 ++++++------
 src/mg_decoration.cpp           |  71 ++++++++++++---
 src/mg_decoration.h             |  57 ++++++++++--
 src/mg_ore.cpp                  |  48 ++++++++---
 src/mg_ore.h                    |  48 ++++++++---
 src/mg_schematic.cpp            | 131 ++++++++++------------------
 src/mg_schematic.h              |  47 +++++-----
 src/script/common/c_content.cpp | 148 +++++++++++++++++---------------
 src/script/common/c_content.h   |  12 ++-
 src/script/lua_api/l_mapgen.cpp | 129 +++++++++++++++-------------
 src/script/lua_api/l_mapgen.h   |   3 +-
 22 files changed, 616 insertions(+), 460 deletions(-)

diff --git a/src/emerge.cpp b/src/emerge.cpp
index 7427f6f4b..6410e56e9 100644
--- a/src/emerge.cpp
+++ b/src/emerge.cpp
@@ -40,8 +40,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "log.h"
 #include "nodedef.h"
 #include "mg_biome.h"
-#include "mg_decoration.h"
 #include "mg_ore.h"
+#include "mg_decoration.h"
+#include "mg_schematic.h"
 #include "mapgen_v5.h"
 #include "mapgen_v6.h"
 #include "mapgen_v7.h"
@@ -88,8 +89,11 @@ EmergeManager::EmergeManager(IGameDef *gamedef) {
 	registerMapgen("v7",         new MapgenFactoryV7());
 	registerMapgen("singlenode", new MapgenFactorySinglenode());
 
-	this->ndef     = gamedef->getNodeDefManager();
-	this->biomedef = new BiomeDefManager(gamedef->getNodeDefManager()->getResolver());
+	this->ndef      = gamedef->getNodeDefManager();
+	this->biomemgr  = new BiomeManager(gamedef);
+	this->oremgr    = new OreManager(gamedef);
+	this->decomgr   = new DecorationManager(gamedef);
+	this->schemmgr  = new SchematicManager(gamedef);
 	this->gennotify = 0;
 
 	// Note that accesses to this variable are not synchronized.
@@ -141,21 +145,15 @@ EmergeManager::~EmergeManager() {
 	emergethread.clear();
 	mapgen.clear();
 
-	for (unsigned int i = 0; i < ores.size(); i++)
-		delete ores[i];
-	ores.clear();
-
-	for (unsigned int i = 0; i < decorations.size(); i++)
-		delete decorations[i];
-	decorations.clear();
-
-	for (std::map<std::string, MapgenFactory *>::iterator it = mglist.begin();
-			it != mglist.end(); ++it) {
+	std::map<std::string, MapgenFactory *>::iterator it;
+	for (it = mglist.begin(); it != mglist.end(); ++it)
 		delete it->second;
-	}
 	mglist.clear();
 
-	delete biomedef;
+	delete biomemgr;
+	delete oremgr;
+	delete decomgr;
+	delete schemmgr;
 
 	if (params.sparams) {
 		delete params.sparams;
diff --git a/src/emerge.h b/src/emerge.h
index c8b99a6e1..712289d30 100644
--- a/src/emerge.h
+++ b/src/emerge.h
@@ -23,8 +23,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include <map>
 #include "irr_v3d.h"
 #include "util/container.h"
-#include "map.h" // for ManualMapVoxelManipulator
 #include "mapgen.h" // for MapgenParams
+#include "map.h"
 
 #define MGPARAMS_SET_MGNAME      1
 #define MGPARAMS_SET_SEED        2
@@ -34,16 +34,20 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #define BLOCK_EMERGE_ALLOWGEN (1<<0)
 
 #define EMERGE_DBG_OUT(x) \
-	{ if (enable_mapgen_debug_info) \
-	infostream << "EmergeThread: " x << std::endl; }
+	do {                                                   \
+		if (enable_mapgen_debug_info)                      \
+			infostream << "EmergeThread: " x << std::endl; \
+	} while (0)
 
 class EmergeThread;
-class Biome;
-class BiomeDefManager;
-class Decoration;
-class Ore;
 class INodeDefManager;
 class Settings;
+//class ManualMapVoxelManipulator;
+
+class BiomeManager;
+class OreManager;
+class DecorationManager;
+class SchematicManager;
 
 struct BlockMakeData {
 	ManualMapVoxelManipulator *vmanip;
@@ -88,16 +92,18 @@ class EmergeManager {
 
 	u32 gennotify;
 
-	//block emerge queue data structures
+	//// Block emerge queue data structures
 	JMutex queuemutex;
 	std::map<v3s16, BlockEmergeData *> blocks_enqueued;
 	std::map<u16, u16> peer_queue_count;
 
-	//Mapgen-related structures
-	BiomeDefManager *biomedef;
-	std::vector<Ore *> ores;
-	std::vector<Decoration *> decorations;
+	//// Managers of map generation-related components
+	BiomeManager *biomemgr;
+	OreManager *oremgr;
+	DecorationManager *decomgr;
+	SchematicManager *schemmgr;
 
+	//// Methods
 	EmergeManager(IGameDef *gamedef);
 	~EmergeManager();
 
@@ -105,7 +111,7 @@ class EmergeManager {
 	void initMapgens();
 	Mapgen *getCurrentMapgen();
 	Mapgen *createMapgen(std::string mgname, int mgid,
-						MapgenParams *mgparams);
+		MapgenParams *mgparams);
 	MapgenSpecificParams *createMapgenParams(std::string mgname);
 	void startThreads();
 	void stopThreads();
diff --git a/src/mapgen.cpp b/src/mapgen.cpp
index 3627675dc..1d3b5869b 100644
--- a/src/mapgen.cpp
+++ b/src/mapgen.cpp
@@ -37,6 +37,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "filesys.h"
 #include "log.h"
 
+const char *GenElementManager::ELEMENT_TITLE = "element";
 
 FlagDesc flagdesc_mapgen[] = {
 	{"trees",    MG_TREES},
@@ -57,16 +58,10 @@ FlagDesc flagdesc_gennotify[] = {
 	{NULL,               0}
 };
 
-///////////////////////////////////////////////////////////////////////////////
-
-
-
-
 
 ///////////////////////////////////////////////////////////////////////////////
 
 
-
 Mapgen::Mapgen() {
 	seed        = 0;
 	water_level = 0;
@@ -283,10 +278,85 @@ void Mapgen::calcLightingOld(v3s16 nmin, v3s16 nmax) {
 		std::map<v3s16, u8> unlight_from;
 
 		voxalgo::clearLightAndCollectSources(*vm, a, bank, ndef,
-											 light_sources, unlight_from);
+			light_sources, unlight_from);
 		voxalgo::propagateSunlight(*vm, a, sunlight, light_sources, ndef);
 
 		vm->unspreadLight(bank, unlight_from, light_sources, ndef);
 		vm->spreadLight(bank, light_sources, ndef);
 	}
 }
+
+
+///////////////////////////////////////////////////////////////////////////////
+
+
+GenElementManager::~GenElementManager()
+{
+	for (size_t i = 0; i != m_elements.size(); i++)
+		delete m_elements[i];
+}
+
+
+u32 GenElementManager::add(GenElement *elem)
+{
+	size_t nelem = m_elements.size();
+
+	for (size_t i = 0; i != nelem; i++) {
+		if (m_elements[i] == NULL) {
+			elem->id = i;
+			m_elements[i] = elem;
+			return i;
+		}
+	}
+
+	if (nelem >= this->ELEMENT_LIMIT)
+		return -1;
+
+	elem->id = nelem;
+	m_elements.push_back(elem);
+
+	verbosestream << "GenElementManager: added " << this->ELEMENT_TITLE
+		<< " element '" << elem->name << "'" << std::endl;
+
+	return nelem;
+}
+
+
+GenElement *GenElementManager::get(u32 id)
+{
+	return (id < m_elements.size()) ? m_elements[id] : NULL;
+}
+
+
+GenElement *GenElementManager::getByName(const char *name)
+{
+	for (size_t i = 0; i != m_elements.size(); i++) {
+		GenElement *elem = m_elements[i];
+		if (elem && !strcmp(elem->name.c_str(), name))
+			return elem;
+	}
+
+	return NULL;
+}
+
+GenElement *GenElementManager::getByName(std::string &name)
+{
+	return getByName(name.c_str());
+}
+
+
+GenElement *GenElementManager::update(u32 id, GenElement *elem)
+{
+	if (id >= m_elements.size())
+		return false;
+
+	GenElement *old_elem = m_elements[id];
+	m_elements[id] = elem;
+	return old_elem;
+}
+
+
+GenElement *GenElementManager::remove(u32 id)
+{
+	return update(id, NULL);
+}
diff --git a/src/mapgen.h b/src/mapgen.h
index e29616342..5b189d963 100644
--- a/src/mapgen.h
+++ b/src/mapgen.h
@@ -20,13 +20,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #ifndef MAPGEN_HEADER
 #define MAPGEN_HEADER
 
-#include "irrlichttypes_bloated.h"
-#include "util/container.h" // UniqueQueue
-#include "gamedef.h"
 #include "nodedef.h"
 #include "mapnode.h"
-#include "noise.h"
-#include "settings.h"
+#include "util/string.h"
+#include "util/container.h"
 
 #define DEFAULT_MAPGEN "v6"
 
@@ -39,11 +36,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 #define NUM_GEN_NOTIFY 6
 
+class Settings;
+class ManualMapVoxelManipulator;
+class INodeDefManager;
 
 extern FlagDesc flagdesc_mapgen[];
 extern FlagDesc flagdesc_gennotify[];
 
-class BiomeDefManager;
 class Biome;
 class EmergeManager;
 class MapBlock;
@@ -53,7 +52,6 @@ struct BlockMakeData;
 class VoxelArea;
 class Map;
 
-
 enum MapgenObject {
 	MGOBJ_VMANIP,
 	MGOBJ_HEIGHTMAP,
@@ -131,10 +129,37 @@ class Mapgen {
 
 struct MapgenFactory {
 	virtual Mapgen *createMapgen(int mgid, MapgenParams *params,
-								 EmergeManager *emerge) = 0;
+		EmergeManager *emerge) = 0;
 	virtual MapgenSpecificParams *createMapgenParams() = 0;
 	virtual ~MapgenFactory() {}
 };
 
-#endif
+class GenElement {
+public:
+	uint32_t id;
+	std::string name;
+};
+
+class GenElementManager {
+public:
+	static const char *ELEMENT_TITLE;
+	static const size_t ELEMENT_LIMIT = -1;
 
+	GenElementManager() {}
+	virtual ~GenElementManager();
+
+	virtual GenElement *create(int type) = 0;
+
+	virtual u32 add(GenElement *elem);
+	virtual GenElement *get(u32 id);
+	virtual GenElement *update(u32 id, GenElement *elem);
+	virtual GenElement *remove(u32 id);
+
+	virtual GenElement *getByName(const char *name);
+	virtual GenElement *getByName(std::string &name);
+
+protected:
+	std::vector<GenElement *> m_elements;
+};
+
+#endif
diff --git a/src/mapgen_v5.cpp b/src/mapgen_v5.cpp
index 4cc382807..afe34164c 100644
--- a/src/mapgen_v5.cpp
+++ b/src/mapgen_v5.cpp
@@ -51,7 +51,7 @@ MapgenV5::MapgenV5(int mapgenid, MapgenParams *params, EmergeManager *emerge_) {
 	this->generating  = false;
 	this->id     = mapgenid;
 	this->emerge = emerge_;
-	this->bmgr   = emerge->biomedef;
+	this->bmgr   = emerge->biomemgr;
 
 	this->seed        = (int)params->seed;
 	this->water_level = params->water_level;
@@ -247,16 +247,10 @@ void MapgenV5::makeChunk(BlockMakeData *data) {
 	}
 
 	// Generate the registered decorations
-	for (size_t i = 0; i != emerge->decorations.size(); i++) {
-		Decoration *deco = emerge->decorations[i];
-		deco->placeDeco(this, blockseed + i, node_min, node_max);
-	}
+	emerge->decomgr->placeAllDecos(this, blockseed, node_min, node_max);
 
 	// Generate the registered ores
-	for (unsigned int i = 0; i != emerge->ores.size(); i++) {
-		Ore *ore = emerge->ores[i];
-		ore->placeOre(this, blockseed + i, node_min, node_max);
-	}
+	emerge->oremgr->placeAllOres(this, blockseed, node_min, node_max);
 
 	// Sprinkle some dust on top after everything else was generated
 	dustTopNodes();
@@ -405,7 +399,7 @@ void MapgenV5::generateBiomes() {
 	
 	for (s16 z = node_min.Z; z <= node_max.Z; z++)
 	for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
-		Biome *biome  = bmgr->biomes[biomemap[index]];
+		Biome *biome  = (Biome *)bmgr->get(biomemap[index]);
 		s16 dfiller   = biome->depth_filler + noise_filler_depth->result[index];
 		s16 y0_top    = biome->depth_top;
 		s16 y0_filler = biome->depth_filler + biome->depth_top + dfiller;
@@ -467,7 +461,7 @@ void MapgenV5::dustTopNodes() {
 
 	for (s16 z = node_min.Z; z <= node_max.Z; z++)
 	for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
-		Biome *biome = bmgr->biomes[biomemap[index]];
+		Biome *biome = (Biome *)bmgr->get(biomemap[index]);
 	
 		if (biome->c_dust == CONTENT_IGNORE)
 			continue;
diff --git a/src/mapgen_v5.h b/src/mapgen_v5.h
index 6f98ad2e4..f50afc42d 100644
--- a/src/mapgen_v5.h
+++ b/src/mapgen_v5.h
@@ -50,7 +50,7 @@ struct MapgenV5Params : public MapgenSpecificParams {
 class MapgenV5 : public Mapgen {
 public:
 	EmergeManager *emerge;
-	BiomeDefManager *bmgr;
+	BiomeManager *bmgr;
 
 	int ystride;
 	int zstride;
diff --git a/src/mapgen_v6.cpp b/src/mapgen_v6.cpp
index c126165dc..30d512783 100644
--- a/src/mapgen_v6.cpp
+++ b/src/mapgen_v6.cpp
@@ -537,16 +537,10 @@ void MapgenV6::makeChunk(BlockMakeData *data) {
 		placeTreesAndJungleGrass();
 	
 	// Generate the registered decorations
-	for (unsigned int i = 0; i != emerge->decorations.size(); i++) {
-		Decoration *deco = emerge->decorations[i];
-		deco->placeDeco(this, blockseed + i, node_min, node_max);
-	}
+	emerge->decomgr->placeAllDecos(this, blockseed, node_min, node_max);
 
 	// Generate the registered ores
-	for (unsigned int i = 0; i != emerge->ores.size(); i++) {
-		Ore *ore = emerge->ores[i];
-		ore->placeOre(this, blockseed + i, node_min, node_max);
-	}
+	emerge->oremgr->placeAllOres(this, blockseed, node_min, node_max);
 
 	// Calculate lighting
 	if (flags & MG_LIGHT)
diff --git a/src/mapgen_v6.h b/src/mapgen_v6.h
index fa9ea3b1b..1fac37fb6 100644
--- a/src/mapgen_v6.h
+++ b/src/mapgen_v6.h
@@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #define MAPGENV6_HEADER
 
 #include "mapgen.h"
+#include "noise.h"
 
 #define AVERAGE_MUD_AMOUNT 4
 
diff --git a/src/mapgen_v7.cpp b/src/mapgen_v7.cpp
index 77aff6e06..8961d8431 100644
--- a/src/mapgen_v7.cpp
+++ b/src/mapgen_v7.cpp
@@ -53,7 +53,7 @@ MapgenV7::MapgenV7(int mapgenid, MapgenParams *params, EmergeManager *emerge) {
 	this->generating  = false;
 	this->id     = mapgenid;
 	this->emerge = emerge;
-	this->bmgr   = emerge->biomedef;
+	this->bmgr   = emerge->biomemgr;
 
 	this->seed        = (int)params->seed;
 	this->water_level = params->water_level;
@@ -250,16 +250,12 @@ void MapgenV7::makeChunk(BlockMakeData *data) {
 		dgen.generate(blockseed, full_node_min, full_node_max);
 	}
 
-	for (size_t i = 0; i != emerge->decorations.size(); i++) {
-		Decoration *deco = emerge->decorations[i];
-		deco->placeDeco(this, blockseed + i, node_min, node_max);
-	}
+	// Generate the registered decorations
+	emerge->decomgr->placeAllDecos(this, blockseed, node_min, node_max);
+
+	// Generate the registered ores
+	emerge->oremgr->placeAllOres(this, blockseed, node_min, node_max);
 
-	for (size_t i = 0; i != emerge->ores.size(); i++) {
-		Ore *ore = emerge->ores[i];
-		ore->placeOre(this, blockseed + i, node_min, node_max);
-	}
-	
 	// Sprinkle some dust on top after everything else was generated
 	dustTopNodes();
 	
@@ -538,11 +534,11 @@ void MapgenV7::generateBiomes() {
 	
 	for (s16 z = node_min.Z; z <= node_max.Z; z++)
 	for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
-		Biome *biome  = bmgr->biomes[biomemap[index]];
+		Biome *biome  = (Biome *)bmgr->get(biomemap[index]);
 		s16 dfiller   = biome->depth_filler + noise_filler_depth->result[index];
 		s16 y0_top    = biome->depth_top;
 		s16 y0_filler = biome->depth_filler + biome->depth_top + dfiller;
-		
+
 		s16 nplaced = 0;
 		u32 i = vm->m_area.index(x, node_max.Y, z);	
 
@@ -607,7 +603,7 @@ void MapgenV7::dustTopNodes() {
 
 	for (s16 z = node_min.Z; z <= node_max.Z; z++)
 	for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
-		Biome *biome = bmgr->biomes[biomemap[index]];
+		Biome *biome = (Biome *)bmgr->get(biomemap[index]);
 	
 		if (biome->c_dust == CONTENT_IGNORE)
 			continue;
diff --git a/src/mapgen_v7.h b/src/mapgen_v7.h
index a7c80928f..bc497309b 100644
--- a/src/mapgen_v7.h
+++ b/src/mapgen_v7.h
@@ -26,6 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #define MGV7_MOUNTAINS   0x01
 #define MGV7_RIDGES      0x02
 
+class BiomeManager;
 
 extern FlagDesc flagdesc_mapgen_v7[];
 
@@ -52,7 +53,7 @@ struct MapgenV7Params : public MapgenSpecificParams {
 class MapgenV7 : public Mapgen {
 public:
 	EmergeManager *emerge;
-	BiomeDefManager *bmgr;
+	BiomeManager *bmgr;
 
 	int ystride;
 	int zstride;
diff --git a/src/mg_biome.cpp b/src/mg_biome.cpp
index b1172a09d..4b9bc0dc1 100644
--- a/src/mg_biome.cpp
+++ b/src/mg_biome.cpp
@@ -18,6 +18,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 */
 
 #include "mg_biome.h"
+#include "gamedef.h"
 #include "nodedef.h"
 #include "map.h" //for ManualMapVoxelManipulator
 #include "log.h"
@@ -26,19 +27,25 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "util/mathconstants.h"
 #include "porting.h"
 
+const char *BiomeManager::ELEMENT_TITLE = "biome";
+
 NoiseParams nparams_biome_def_heat(50, 50, v3f(500.0, 500.0, 500.0), 5349, 3, 0.70);
 NoiseParams nparams_biome_def_humidity(50, 50, v3f(500.0, 500.0, 500.0), 842, 3, 0.55);
 
 
-BiomeDefManager::BiomeDefManager(NodeResolver *resolver)
+///////////////////////////////////////////////////////////////////////////////
+
+
+BiomeManager::BiomeManager(IGameDef *gamedef)
 {
-	biome_registration_finished = false;
+	NodeResolver *resolver = gamedef->getNodeDefManager()->getResolver();
+
 	np_heat     = &nparams_biome_def_heat;
 	np_humidity = &nparams_biome_def_humidity;
 
 	// Create default biome to be used in case none exist
 	Biome *b = new Biome;
-	
+
 	b->id             = 0;
 	b->name           = "Default";
 	b->flags          = 0;
@@ -55,41 +62,21 @@ BiomeDefManager::BiomeDefManager(NodeResolver *resolver)
 	resolver->addNode("air",                 "", CONTENT_AIR, &b->c_dust);
 	resolver->addNode("mapgen_water_source", "", CONTENT_AIR, &b->c_dust_water);
 
-	biomes.push_back(b);
+	add(b);
 }
 
 
-BiomeDefManager::~BiomeDefManager()
+
+BiomeManager::~BiomeManager()
 {
 	//if (biomecache)
 	//	delete[] biomecache;
-	
-	for (size_t i = 0; i != biomes.size(); i++)
-		delete biomes[i];
 }
 
 
-Biome *BiomeDefManager::createBiome(BiomeTerrainType btt)
-{
-	/*switch (btt) {
-		case BIOME_TERRAIN_NORMAL:
-			return new Biome;
-		case BIOME_TERRAIN_LIQUID:
-			return new BiomeLiquid;
-		case BIOME_TERRAIN_NETHER:
-			return new BiomeHell;
-		case BIOME_TERRAIN_AETHER:
-			return new BiomeSky;
-		case BIOME_TERRAIN_FLAT:
-			return new BiomeSuperflat;
-	}
-	return NULL;*/
-	return new Biome;
-}
-
 
 // just a PoC, obviously needs optimization later on (precalculate this)
-void BiomeDefManager::calcBiomes(BiomeNoiseInput *input, u8 *biomeid_map)
+void BiomeManager::calcBiomes(BiomeNoiseInput *input, u8 *biomeid_map)
 {
 	int i = 0;
 	for (int y = 0; y != input->mapsize.Y; y++) {
@@ -102,38 +89,17 @@ void BiomeDefManager::calcBiomes(BiomeNoiseInput *input, u8 *biomeid_map)
 }
 
 
-bool BiomeDefManager::addBiome(Biome *b)
-{
-	if (biome_registration_finished) {
-		errorstream << "BiomeDefManager: biome registration already "
-			"finished, dropping " << b->name << std::endl;
-		return false;
-	}
-	
-	size_t nbiomes = biomes.size();
-	if (nbiomes >= 0xFF) {
-		errorstream << "BiomeDefManager: too many biomes, dropping "
-			<< b->name << std::endl;
-		return false;
-	}
-
-	b->id = (u8)nbiomes;
-	biomes.push_back(b);
-	verbosestream << "BiomeDefManager: added biome " << b->name << std::endl;
-
-	return true;
-}
-
-
-Biome *BiomeDefManager::getBiome(float heat, float humidity, s16 y)
+Biome *BiomeManager::getBiome(float heat, float humidity, s16 y)
 {
 	Biome *b, *biome_closest = NULL;
 	float dist_min = FLT_MAX;
 
-	for (size_t i = 1; i < biomes.size(); i++) {
-		b = biomes[i];
-		if (y > b->height_max || y < b->height_min)
+	for (size_t i = 1; i < m_elements.size(); i++) {
+		b = (Biome *)m_elements[i];
+		if (!b || y > b->height_max || y < b->height_min) {
+			printf("not good - %p %d %d %d\n", b, y, b->height_max, b->height_min);
 			continue;
+		}
 
 		float d_heat     = heat     - b->heat_point;
 		float d_humidity = humidity - b->humidity_point;
@@ -145,16 +111,5 @@ Biome *BiomeDefManager::getBiome(float heat, float humidity, s16 y)
 		}
 	}
 	
-	return biome_closest ? biome_closest : biomes[0];
-}
-
-
-u8 BiomeDefManager::getBiomeIdByName(const char *name)
-{
-	for (size_t i = 0; i != biomes.size(); i++) {
-		if (!strcasecmp(name, biomes[i]->name.c_str()))
-			return i;
-	}
-	
-	return 0;
+	return biome_closest ? biome_closest : (Biome *)m_elements[0];
 }
diff --git a/src/mg_biome.h b/src/mg_biome.h
index 3724652bd..9c653a768 100644
--- a/src/mg_biome.h
+++ b/src/mg_biome.h
@@ -20,12 +20,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #ifndef MG_BIOME_HEADER
 #define MG_BIOME_HEADER
 
-#include <string>
-#include "nodedef.h"
-#include "gamedef.h"
-#include "mapnode.h"
-#include "noise.h"
 #include "mapgen.h"
+#include "noise.h"
+
+//#include <string>
+//#include "nodedef.h"
+//#include "gamedef.h"
+//#include "mapnode.h"
 
 enum BiomeTerrainType
 {
@@ -39,10 +40,16 @@ enum BiomeTerrainType
 extern NoiseParams nparams_biome_def_heat;
 extern NoiseParams nparams_biome_def_humidity;
 
-class Biome {
+
+struct BiomeNoiseInput {
+	v2s16 mapsize;
+	float *heat_map;
+	float *humidity_map;
+	s16 *height_map;
+};
+
+class Biome : public GenElement {
 public:
-	u8 id;
-	std::string name;
 	u32 flags;
 
 	content_t c_top;
@@ -60,33 +67,24 @@ class Biome {
 	float humidity_point;
 };
 
-struct BiomeNoiseInput {
-	v2s16 mapsize;
-	float *heat_map;
-	float *humidity_map;
-	s16 *height_map;
-};
-
-class BiomeDefManager {
+class BiomeManager : public GenElementManager {
 public:
-	std::vector<Biome *> biomes;
+	static const char *ELEMENT_TITLE;
+	static const size_t ELEMENT_LIMIT = 0x100;
 
-	bool biome_registration_finished;
 	NoiseParams *np_heat;
 	NoiseParams *np_humidity;
 
-	BiomeDefManager(NodeResolver *resolver);
-	~BiomeDefManager();
+	BiomeManager(IGameDef *gamedef);
+	~BiomeManager();
 
-	Biome *createBiome(BiomeTerrainType btt);
-	void  calcBiomes(BiomeNoiseInput *input, u8 *biomeid_map);
-	Biome *getBiome(float heat, float humidity, s16 y);
+	Biome *create(int btt)
+	{
+		return new Biome;
+	}
 
-	bool addBiome(Biome *b);
-	u8 getBiomeIdByName(const char *name);
-
-	s16 calcBlockHeat(v3s16 p, u64 seed, float timeofday, float totaltime);
-	s16 calcBlockHumidity(v3s16 p, u64 seed, float timeofday, float totaltime);
+	void calcBiomes(BiomeNoiseInput *input, u8 *biomeid_map);
+	Biome *getBiome(float heat, float humidity, s16 y);
 };
 
 #endif
diff --git a/src/mg_decoration.cpp b/src/mg_decoration.cpp
index 7f6126bfc..3604b06c0 100644
--- a/src/mg_decoration.cpp
+++ b/src/mg_decoration.cpp
@@ -20,28 +20,44 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "mg_decoration.h"
 #include "mg_schematic.h"
 #include "mapgen.h"
+#include "noise.h"
 #include "map.h"
 #include "log.h"
 #include "util/numeric.h"
 
+const char *DecorationManager::ELEMENT_TITLE = "decoration";
+
+FlagDesc flagdesc_deco_schematic[] = {
+	{"place_center_x", DECO_PLACE_CENTER_X},
+	{"place_center_y", DECO_PLACE_CENTER_Y},
+	{"place_center_z", DECO_PLACE_CENTER_Z},
+	{NULL,             0}
+};
+
+
 ///////////////////////////////////////////////////////////////////////////////
 
 
-Decoration *createDecoration(DecorationType type)
+size_t DecorationManager::placeAllDecos(Mapgen *mg, u32 seed, v3s16 nmin, v3s16 nmax)
 {
-	switch (type) {
-	case DECO_SIMPLE:
-		return new DecoSimple;
-	case DECO_SCHEMATIC:
-		return new DecoSchematic;
-	//case DECO_LSYSTEM:
-	//	return new DecoLSystem;
-	default:
-		return NULL;
+	size_t nplaced = 0;
+
+	for (size_t i = 0; i != m_elements.size(); i++) {
+		Decoration *deco = (Decoration *)m_elements[i];
+		if (!deco)
+			continue;
+
+		nplaced += deco->placeDeco(mg, seed, nmin, nmax);
+		seed++;
 	}
+
+	return nplaced;
 }
 
 
+///////////////////////////////////////////////////////////////////////////////
+
+
 Decoration::Decoration()
 {
 	mapseed    = 0;
@@ -57,7 +73,7 @@ Decoration::~Decoration()
 }
 
 
-void Decoration::placeDeco(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax)
+size_t Decoration::placeDeco(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax)
 {
 	PseudoRandom ps(blockseed + 53);
 	int carea_size = nmax.X - nmin.X + 1;
@@ -131,6 +147,8 @@ void Decoration::placeDeco(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax)
 			generate(mg, &ps, max_y, v3s16(x, y, z));
 		}
 	}
+
+	return 0;
 }
 
 
@@ -190,6 +208,7 @@ void Decoration::placeCutoffs(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax)
 
 ///////////////////////////////////////////////////////////////////////////////
 
+
 bool DecoSimple::canPlaceDecoration(ManualMapVoxelManipulator *vm, v3s16 p)
 {
 	// Don't bother if there aren't any decorations to place
@@ -269,7 +288,33 @@ int DecoSimple::getHeight()
 }
 
 
-std::string DecoSimple::getName()
+///////////////////////////////////////////////////////////////////////////////
+
+
+void DecoSchematic::generate(Mapgen *mg, PseudoRandom *pr, s16 max_y, v3s16 p)
+{
+	ManualMapVoxelManipulator *vm = mg->vm;
+
+	if (flags & DECO_PLACE_CENTER_X)
+		p.X -= (schematic->size.X + 1) / 2;
+	if (flags & DECO_PLACE_CENTER_Y)
+		p.Y -= (schematic->size.Y + 1) / 2;
+	if (flags & DECO_PLACE_CENTER_Z)
+		p.Z -= (schematic->size.Z + 1) / 2;
+
+	u32 vi = vm->m_area.index(p);
+	content_t c = vm->m_data[vi].getContent();
+	if (!CONTAINS(c_place_on, c))
+		return;
+
+	Rotation rot = (rotation == ROTATE_RAND) ?
+		(Rotation)pr->range(ROTATE_0, ROTATE_270) : rotation;
+
+	schematic->blitToVManip(p, vm, rot, false, mg->ndef);
+}
+
+
+int DecoSchematic::getHeight()
 {
-	return "";
+	return schematic->size.Y;
 }
diff --git a/src/mg_decoration.h b/src/mg_decoration.h
index 78ff9dc2e..d5c9f0165 100644
--- a/src/mg_decoration.h
+++ b/src/mg_decoration.h
@@ -21,12 +21,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #define MG_DECORATION_HEADER
 
 #include <set>
-#include "mapnode.h"
+#include "mapgen.h"
 
 class NoiseParams;
 class Mapgen;
 class ManualMapVoxelManipulator;
 class PseudoRandom;
+class Schematic;
 
 enum DecorationType {
 	DECO_SIMPLE,
@@ -34,6 +35,13 @@ enum DecorationType {
 	DECO_LSYSTEM
 };
 
+#define DECO_PLACE_CENTER_X 0x01
+#define DECO_PLACE_CENTER_Y 0x02
+#define DECO_PLACE_CENTER_Z 0x04
+
+extern FlagDesc flagdesc_deco_schematic[];
+
+
 #if 0
 struct CutoffData {
 	VoxelArea a;
@@ -49,7 +57,7 @@ struct CutoffData {
 };
 #endif
 
-class Decoration {
+class Decoration : public GenElement {
 public:
 	INodeDefManager *ndef;
 
@@ -66,12 +74,11 @@ class Decoration {
 	Decoration();
 	virtual ~Decoration();
 
-	void placeDeco(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax);
-	void placeCutoffs(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax);
+	size_t placeDeco(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax);
+	size_t placeCutoffs(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax);
 
 	virtual void generate(Mapgen *mg, PseudoRandom *pr, s16 max_y, v3s16 p) = 0;
 	virtual int getHeight() = 0;
-	virtual std::string getName() = 0;
 };
 
 class DecoSimple : public Decoration {
@@ -87,9 +94,22 @@ class DecoSimple : public Decoration {
 	bool canPlaceDecoration(ManualMapVoxelManipulator *vm, v3s16 p);
 	virtual void generate(Mapgen *mg, PseudoRandom *pr, s16 max_y, v3s16 p);
 	virtual int getHeight();
-	virtual std::string getName();
 };
 
+class DecoSchematic : public Decoration {
+public:
+	u32 flags;
+	Rotation rotation;
+	Schematic *schematic;
+	std::string filename;
+
+	~DecoSchematic() {}
+
+	void generate(Mapgen *mg, PseudoRandom *pr, s16 max_y, v3s16 p);
+	virtual int getHeight();
+};
+
+
 /*
 class DecoLSystem : public Decoration {
 public:
@@ -97,6 +117,29 @@ class DecoLSystem : public Decoration {
 };
 */
 
-Decoration *createDecoration(DecorationType type);
+class DecorationManager : public GenElementManager {
+public:
+	static const char *ELEMENT_TITLE;
+	static const size_t ELEMENT_LIMIT = 0x10000;
+
+	DecorationManager(IGameDef *gamedef) {}
+	~DecorationManager() {}
+
+	Decoration *create(int type)
+	{
+		switch (type) {
+		case DECO_SIMPLE:
+			return new DecoSimple;
+		case DECO_SCHEMATIC:
+			return new DecoSchematic;
+		//case DECO_LSYSTEM:
+		//	return new DecoLSystem;
+		default:
+			return NULL;
+		}
+	}
+
+	size_t placeAllDecos(Mapgen *mg, u32 seed, v3s16 nmin, v3s16 nmax);
+};
 
 #endif
diff --git a/src/mg_ore.cpp b/src/mg_ore.cpp
index c8d224dc6..9e2d456ee 100644
--- a/src/mg_ore.cpp
+++ b/src/mg_ore.cpp
@@ -19,10 +19,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 #include "mg_ore.h"
 #include "mapgen.h"
+#include "noise.h"
 #include "util/numeric.h"
 #include "map.h"
 #include "log.h"
 
+const char *OreManager::ELEMENT_TITLE = "ore";
 
 FlagDesc flagdesc_ore[] = {
 	{"absheight",            OREFLAG_ABSHEIGHT},
@@ -31,24 +33,36 @@ FlagDesc flagdesc_ore[] = {
 	{NULL,                   0}
 };
 
+
 ///////////////////////////////////////////////////////////////////////////////
 
 
-Ore *createOre(OreType type)
+size_t OreManager::placeAllOres(Mapgen *mg, u32 seed, v3s16 nmin, v3s16 nmax)
 {
-	switch (type) {
-	case ORE_SCATTER:
-		return new OreScatter;
-	case ORE_SHEET:
-		return new OreSheet;
-	//case ORE_CLAYLIKE: //TODO: implement this!
-	//	return new OreClaylike;
-	default:
-		return NULL;
+	size_t nplaced = 0;
+
+	for (size_t i = 0; i != m_elements.size(); i++) {
+		Ore *ore = (Ore *)m_elements[i];
+		if (!ore)
+			continue;
+
+		nplaced += ore->placeOre(mg, seed, nmin, nmax);
+		seed++;
 	}
+
+	return nplaced;
 }
 
 
+///////////////////////////////////////////////////////////////////////////////
+
+Ore::Ore()
+{
+	c_ore   = CONTENT_IGNORE;
+	np      = NULL;
+	noise   = NULL;
+}
+
 Ore::~Ore()
 {
 	delete np;
@@ -56,7 +70,13 @@ Ore::~Ore()
 }
 
 
-void Ore::placeOre(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax)
+std::string Ore::getName()
+{
+	return name;
+}
+
+
+size_t Ore::placeOre(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax)
 {
 	int in_range = 0;
 
@@ -64,7 +84,7 @@ void Ore::placeOre(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax)
 	if (flags & OREFLAG_ABSHEIGHT)
 		in_range |= (nmin.Y >= -height_max && nmax.Y <= -height_min) << 1;
 	if (!in_range)
-		return;
+		return 0;
 
 	int ymin, ymax;
 	if (in_range & ORE_RANGE_MIRROR) {
@@ -75,11 +95,13 @@ void Ore::placeOre(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax)
 		ymax = MYMIN(nmax.Y, height_max);
 	}
 	if (clust_size >= ymax - ymin + 1)
-		return;
+		return 0;
 
 	nmin.Y = ymin;
 	nmax.Y = ymax;
 	generate(mg->vm, mg->seed, blockseed, nmin, nmax);
+
+	return 0;
 }
 
 
diff --git a/src/mg_ore.h b/src/mg_ore.h
index c279703a8..c1124b0f9 100644
--- a/src/mg_ore.h
+++ b/src/mg_ore.h
@@ -21,7 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #define MG_ORE_HEADER
 
 #include "util/string.h"
-#include "mapnode.h"
+#include "mapgen.h"
 
 class NoiseParams;
 class Noise;
@@ -29,10 +29,13 @@ class Mapgen;
 class ManualMapVoxelManipulator;
 
 /////////////////// Ore generation flags
+
 // Use absolute value of height to determine ore placement
 #define OREFLAG_ABSHEIGHT 0x01
+
 // Use 3d noise to get density of ore placement, instead of just the position
 #define OREFLAG_DENSITY   0x02 // not yet implemented
+
 // For claylike ore types, place ore if the number of surrounding
 // nodes isn't the specified node
 #define OREFLAG_NODEISNT  0x04 // not yet implemented
@@ -40,7 +43,6 @@ class ManualMapVoxelManipulator;
 #define ORE_RANGE_ACTUAL 1
 #define ORE_RANGE_MIRROR 2
 
-extern FlagDesc flagdesc_ore[];
 
 enum OreType {
 	ORE_SCATTER,
@@ -48,7 +50,9 @@ enum OreType {
 	ORE_CLAYLIKE
 };
 
-class Ore {
+extern FlagDesc flagdesc_ore[];
+
+class Ore : public GenElement {
 public:
 	content_t c_ore;                  // the node to place
 	std::vector<content_t> c_wherein; // the nodes to be placed in
@@ -63,32 +67,50 @@ class Ore {
 	NoiseParams *np;    // noise for distribution of clusters (NULL for uniform scattering)
 	Noise *noise;
 
-	Ore() {
-		c_ore   = CONTENT_IGNORE;
-		np      = NULL;
-		noise   = NULL;
-	}
-
+	Ore();
 	virtual ~Ore();
 
-	void placeOre(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax);
+	size_t placeOre(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax);
 	virtual void generate(ManualMapVoxelManipulator *vm, int seed,
 						u32 blockseed, v3s16 nmin, v3s16 nmax) = 0;
+	virtual std::string getName();
 };
 
 class OreScatter : public Ore {
-	~OreScatter() {}
+	virtual ~OreScatter() {}
 	virtual void generate(ManualMapVoxelManipulator *vm, int seed,
 						u32 blockseed, v3s16 nmin, v3s16 nmax);
 };
 
 class OreSheet : public Ore {
-	~OreSheet() {}
+	virtual ~OreSheet() {}
 	virtual void generate(ManualMapVoxelManipulator *vm, int seed,
 						u32 blockseed, v3s16 nmin, v3s16 nmax);
 };
 
-Ore *createOre(OreType type);
+class OreManager : public GenElementManager {
+public:
+	static const char *ELEMENT_TITLE;
+	static const size_t ELEMENT_LIMIT = 0x10000;
+
+	OreManager(IGameDef *gamedef) {}
+	~OreManager() {}
+
+	Ore *create(int type)
+	{
+		switch (type) {
+		case ORE_SCATTER:
+			return new OreScatter;
+		case ORE_SHEET:
+			return new OreSheet;
+		//case ORE_CLAYLIKE: //TODO: implement this!
+		//	return new OreClaylike;
+		default:
+			return NULL;
+		}
+	}
 
+	size_t placeAllOres(Mapgen *mg, u32 seed, v3s16 nmin, v3s16 nmax);
+};
 
 #endif
diff --git a/src/mg_schematic.cpp b/src/mg_schematic.cpp
index 8b34fb4fd..92cbf8e4e 100644
--- a/src/mg_schematic.cpp
+++ b/src/mg_schematic.cpp
@@ -28,79 +28,42 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "serialization.h"
 #include "filesys.h"
 
-FlagDesc flagdesc_deco_schematic[] = {
-	{"place_center_x", DECO_PLACE_CENTER_X},
-	{"place_center_y", DECO_PLACE_CENTER_Y},
-	{"place_center_z", DECO_PLACE_CENTER_Z},
-	{NULL,             0}
-};
+const char *SchematicManager::ELEMENT_TITLE = "schematic";
+
 
 ///////////////////////////////////////////////////////////////////////////////
 
 
-DecoSchematic::DecoSchematic()
+Schematic::Schematic()
 {
-	schematic   = NULL;
+	schemdata   = NULL;
 	slice_probs = NULL;
 	flags       = 0;
 	size        = v3s16(0, 0, 0);
 }
 
 
-DecoSchematic::~DecoSchematic()
+Schematic::~Schematic()
 {
-	delete []schematic;
+	delete []schemdata;
 	delete []slice_probs;
 }
 
 
-void DecoSchematic::updateContentIds()
+void Schematic::updateContentIds()
 {
-	if (flags & DECO_SCHEM_CIDS_UPDATED)
+	if (flags & SCHEM_CIDS_UPDATED)
 		return;
 
-	flags |= DECO_SCHEM_CIDS_UPDATED;
+	flags |= SCHEM_CIDS_UPDATED;
 
 	for (int i = 0; i != size.X * size.Y * size.Z; i++)
-		schematic[i].setContent(c_nodes[schematic[i].getContent()]);
+		schemdata[i].setContent(c_nodes[schemdata[i].getContent()]);
 }
 
 
-void DecoSchematic::generate(Mapgen *mg, PseudoRandom *pr, s16 max_y, v3s16 p)
-{
-	ManualMapVoxelManipulator *vm = mg->vm;
-
-	if (flags & DECO_PLACE_CENTER_X)
-		p.X -= (size.X + 1) / 2;
-	if (flags & DECO_PLACE_CENTER_Y)
-		p.Y -= (size.Y + 1) / 2;
-	if (flags & DECO_PLACE_CENTER_Z)
-		p.Z -= (size.Z + 1) / 2;
-
-	u32 vi = vm->m_area.index(p);
-	content_t c = vm->m_data[vi].getContent();
-	if (!CONTAINS(c_place_on, c))
-		return;
-
-	Rotation rot = (rotation == ROTATE_RAND) ?
-		(Rotation)pr->range(ROTATE_0, ROTATE_270) : rotation;
-
-	blitToVManip(p, vm, rot, false);
-}
-
-
-int DecoSchematic::getHeight() {
-	return size.Y;
-}
-
-
-std::string DecoSchematic::getName() {
-	return filename;
-}
-
-
-void DecoSchematic::blitToVManip(v3s16 p, ManualMapVoxelManipulator *vm,
-	Rotation rot, bool force_placement)
+void Schematic::blitToVManip(v3s16 p, ManualMapVoxelManipulator *vm,
+	Rotation rot, bool force_placement, INodeDefManager *ndef)
 {
 	int xstride = 1;
 	int ystride = size.X;
@@ -150,10 +113,10 @@ void DecoSchematic::blitToVManip(v3s16 p, ManualMapVoxelManipulator *vm,
 				if (!vm->m_area.contains(vi))
 					continue;
 
-				if (schematic[i].getContent() == CONTENT_IGNORE)
+				if (schemdata[i].getContent() == CONTENT_IGNORE)
 					continue;
 
-				if (schematic[i].param1 == MTSCHEM_PROB_NEVER)
+				if (schemdata[i].param1 == MTSCHEM_PROB_NEVER)
 					continue;
 
 				if (!force_placement) {
@@ -162,11 +125,11 @@ void DecoSchematic::blitToVManip(v3s16 p, ManualMapVoxelManipulator *vm,
 						continue;
 				}
 
-				if (schematic[i].param1 != MTSCHEM_PROB_ALWAYS &&
-					myrand_range(1, 255) > schematic[i].param1)
+				if (schemdata[i].param1 != MTSCHEM_PROB_ALWAYS &&
+					myrand_range(1, 255) > schemdata[i].param1)
 					continue;
 
-				vm->m_data[vi] = schematic[i];
+				vm->m_data[vi] = schemdata[i];
 				vm->m_data[vi].param1 = 0;
 
 				if (rot)
@@ -178,13 +141,14 @@ void DecoSchematic::blitToVManip(v3s16 p, ManualMapVoxelManipulator *vm,
 }
 
 
-void DecoSchematic::placeStructure(Map *map, v3s16 p, bool force_placement)
+void Schematic::placeStructure(Map *map, v3s16 p, u32 flags,
+	Rotation rot, bool force_placement, INodeDefManager *ndef)
 {
-	assert(schematic != NULL);
+	assert(schemdata != NULL);
 	ManualMapVoxelManipulator *vm = new ManualMapVoxelManipulator(map);
 
-	Rotation rot = (rotation == ROTATE_RAND) ?
-		(Rotation)myrand_range(ROTATE_0, ROTATE_270) : rotation;
+	if (rot == ROTATE_RAND)
+		rot = (Rotation)myrand_range(ROTATE_0, ROTATE_270);
 
 	v3s16 s = (rot == ROTATE_90 || rot == ROTATE_270) ?
 				v3s16(size.Z, size.Y, size.X) : size;
@@ -200,7 +164,7 @@ void DecoSchematic::placeStructure(Map *map, v3s16 p, bool force_placement)
 	v3s16 bp2 = getNodeBlockPos(p + s - v3s16(1,1,1));
 	vm->initialEmerge(bp1, bp2);
 
-	blitToVManip(p, vm, rot, force_placement);
+	blitToVManip(p, vm, rot, force_placement, ndef);
 
 	std::map<v3s16, MapBlock *> lighting_modified_blocks;
 	std::map<v3s16, MapBlock *> modified_blocks;
@@ -221,13 +185,14 @@ void DecoSchematic::placeStructure(Map *map, v3s16 p, bool force_placement)
 }
 
 
-bool DecoSchematic::loadSchematicFile(NodeResolver *resolver,
+bool Schematic::loadSchematicFromFile(const char *filename,
+	NodeResolver *resolver,
 	std::map<std::string, std::string> &replace_names)
 {
 	content_t cignore = CONTENT_IGNORE;
 	bool have_cignore = false;
 
-	std::ifstream is(filename.c_str(), std::ios_base::binary);
+	std::ifstream is(filename, std::ios_base::binary);
 
 	u32 signature = readU32(is);
 	if (signature != MTSCHEM_FILE_SIGNATURE) {
@@ -247,13 +212,8 @@ bool DecoSchematic::loadSchematicFile(NodeResolver *resolver,
 
 	delete []slice_probs;
 	slice_probs = new u8[size.Y];
-	if (version >= 3) {
-		for (int y = 0; y != size.Y; y++)
-			slice_probs[y] = readU8(is);
-	} else {
-		for (int y = 0; y != size.Y; y++)
-			slice_probs[y] = MTSCHEM_PROB_ALWAYS;
-	}
+	for (int y = 0; y != size.Y; y++)
+		slice_probs[y] = (version >= 3) ? readU8(is) : MTSCHEM_PROB_ALWAYS;
 
 	int nodecount = size.X * size.Y * size.Z;
 
@@ -268,7 +228,6 @@ bool DecoSchematic::loadSchematicFile(NodeResolver *resolver,
 		}
 
 		std::map<std::string, std::string>::iterator it;
-
 		it = replace_names.find(name);
 		if (it != replace_names.end())
 			name = it->second;
@@ -276,17 +235,17 @@ bool DecoSchematic::loadSchematicFile(NodeResolver *resolver,
 		resolver->addNodeList(name.c_str(), &c_nodes);
 	}
 
-	delete []schematic;
-	schematic = new MapNode[nodecount];
-	MapNode::deSerializeBulk(is, SER_FMT_VER_HIGHEST_READ, schematic,
+	delete []schemdata;
+	schemdata = new MapNode[nodecount];
+	MapNode::deSerializeBulk(is, SER_FMT_VER_HIGHEST_READ, schemdata,
 				nodecount, 2, 2, true);
 
 	if (version == 1) { // fix up the probability values
 		for (int i = 0; i != nodecount; i++) {
-			if (schematic[i].param1 == 0)
-				schematic[i].param1 = MTSCHEM_PROB_ALWAYS;
-			if (have_cignore && schematic[i].getContent() == cignore)
-				schematic[i].param1 = MTSCHEM_PROB_NEVER;
+			if (schemdata[i].param1 == 0)
+				schemdata[i].param1 = MTSCHEM_PROB_ALWAYS;
+			if (have_cignore && schemdata[i].getContent() == cignore)
+				schemdata[i].param1 = MTSCHEM_PROB_NEVER;
 		}
 	}
 
@@ -324,7 +283,7 @@ bool DecoSchematic::loadSchematicFile(NodeResolver *resolver,
 	2 - Fixed messy never/always place; 0 probability is now never, 0xFF is always
 	3 - Added y-slice probabilities; this allows for variable height structures
 */
-void DecoSchematic::saveSchematicFile(INodeDefManager *ndef)
+void Schematic::saveSchematicToFile(const char *filename, INodeDefManager *ndef)
 {
 	std::ostringstream ss(std::ios_base::binary);
 
@@ -337,7 +296,7 @@ void DecoSchematic::saveSchematicFile(INodeDefManager *ndef)
 
 	std::vector<content_t> usednodes;
 	int nodecount = size.X * size.Y * size.Z;
-	build_nnlist_and_update_ids(schematic, nodecount, &usednodes);
+	build_nnlist_and_update_ids(schemdata, nodecount, &usednodes);
 
 	u16 numids = usednodes.size();
 	writeU16(ss, numids); // name count
@@ -345,7 +304,7 @@ void DecoSchematic::saveSchematicFile(INodeDefManager *ndef)
 		ss << serializeString(ndef->get(usednodes[i]).name); // node names
 
 	// compressed bulk node data
-	MapNode::serializeBulk(ss, SER_FMT_VER_HIGHEST_WRITE, schematic,
+	MapNode::serializeBulk(ss, SER_FMT_VER_HIGHEST_WRITE, schemdata,
 				nodecount, 2, 2, true);
 
 	fs::safeWriteToFile(filename, ss.str());
@@ -377,7 +336,7 @@ void build_nnlist_and_update_ids(MapNode *nodes, u32 nodecount,
 }
 
 
-bool DecoSchematic::getSchematicFromMap(Map *map, v3s16 p1, v3s16 p2)
+bool Schematic::getSchematicFromMap(Map *map, v3s16 p1, v3s16 p2)
 {
 	ManualMapVoxelManipulator *vm = new ManualMapVoxelManipulator(map);
 
@@ -391,15 +350,15 @@ bool DecoSchematic::getSchematicFromMap(Map *map, v3s16 p1, v3s16 p2)
 	for (s16 y = 0; y != size.Y; y++)
 		slice_probs[y] = MTSCHEM_PROB_ALWAYS;
 
-	schematic = new MapNode[size.X * size.Y * size.Z];
+	schemdata = new MapNode[size.X * size.Y * size.Z];
 
 	u32 i = 0;
 	for (s16 z = p1.Z; z <= p2.Z; z++)
 	for (s16 y = p1.Y; y <= p2.Y; y++) {
 		u32 vi = vm->m_area.index(p1.X, y, z);
 		for (s16 x = p1.X; x <= p2.X; x++, i++, vi++) {
-			schematic[i] = vm->m_data[vi];
-			schematic[i].param1 = MTSCHEM_PROB_ALWAYS;
+			schemdata[i] = vm->m_data[vi];
+			schemdata[i].param1 = MTSCHEM_PROB_ALWAYS;
 		}
 	}
 
@@ -408,7 +367,7 @@ bool DecoSchematic::getSchematicFromMap(Map *map, v3s16 p1, v3s16 p2)
 }
 
 
-void DecoSchematic::applyProbabilities(v3s16 p0,
+void Schematic::applyProbabilities(v3s16 p0,
 	std::vector<std::pair<v3s16, u8> > *plist,
 	std::vector<std::pair<s16, u8> > *splist)
 {
@@ -417,11 +376,11 @@ void DecoSchematic::applyProbabilities(v3s16 p0,
 		int index = p.Z * (size.Y * size.X) + p.Y * size.X + p.X;
 		if (index < size.Z * size.Y * size.X) {
 			u8 prob = (*plist)[i].second;
-			schematic[index].param1 = prob;
+			schemdata[index].param1 = prob;
 
 			// trim unnecessary node names from schematic
 			if (prob == MTSCHEM_PROB_NEVER)
-				schematic[index].setContent(CONTENT_AIR);
+				schemdata[index].setContent(CONTENT_AIR);
 		}
 	}
 
diff --git a/src/mg_schematic.h b/src/mg_schematic.h
index 8a495fef2..9d4d4a716 100644
--- a/src/mg_schematic.h
+++ b/src/mg_schematic.h
@@ -30,11 +30,8 @@ class ManualMapVoxelManipulator;
 class PseudoRandom;
 class NodeResolver;
 
-/////////////////// Decoration flags
-#define DECO_PLACE_CENTER_X     1
-#define DECO_PLACE_CENTER_Y     2
-#define DECO_PLACE_CENTER_Z     4
-#define DECO_SCHEM_CIDS_UPDATED 8
+/////////////////// Schematic flags
+#define SCHEM_CIDS_UPDATED 0x08
 
 
 #define MTSCHEM_FILE_SIGNATURE 0x4d54534d // 'MTSM'
@@ -44,42 +41,50 @@ class NodeResolver;
 #define MTSCHEM_PROB_NEVER  0x00
 #define MTSCHEM_PROB_ALWAYS 0xFF
 
-extern FlagDesc flagdesc_deco_schematic[];
 
-class DecoSchematic : public Decoration {
+class Schematic : public GenElement {
 public:
-	std::string filename;
-
 	std::vector<content_t> c_nodes;
 
 	u32 flags;
-	Rotation rotation;
 	v3s16 size;
-	MapNode *schematic;
+	MapNode *schemdata;
 	u8 *slice_probs;
 
-	DecoSchematic();
-	~DecoSchematic();
+	Schematic();
+	~Schematic();
 
 	void updateContentIds();
-	virtual void generate(Mapgen *mg, PseudoRandom *pr, s16 max_y, v3s16 p);
-	virtual int getHeight();
-	virtual std::string getName();
 
 	void blitToVManip(v3s16 p, ManualMapVoxelManipulator *vm,
-					Rotation rot, bool force_placement);
+		Rotation rot, bool force_placement, INodeDefManager *ndef);
 
-	bool loadSchematicFile(NodeResolver *resolver,
+	bool loadSchematicFromFile(const char *filename, NodeResolver *resolver,
 		std::map<std::string, std::string> &replace_names);
-	void saveSchematicFile(INodeDefManager *ndef);
-
+	void saveSchematicToFile(const char *filename, INodeDefManager *ndef);
 	bool getSchematicFromMap(Map *map, v3s16 p1, v3s16 p2);
-	void placeStructure(Map *map, v3s16 p, bool force_placement);
+
+	void placeStructure(Map *map, v3s16 p, u32 flags,
+		Rotation rot, bool force_placement, INodeDefManager *nef);
 	void applyProbabilities(v3s16 p0,
 		std::vector<std::pair<v3s16, u8> > *plist,
 		std::vector<std::pair<s16, u8> > *splist);
 };
 
+class SchematicManager : public GenElementManager {
+public:
+	static const char *ELEMENT_TITLE;
+	static const size_t ELEMENT_LIMIT = 0x10000;
+
+	SchematicManager(IGameDef *gamedef) {}
+	~SchematicManager() {}
+
+	Schematic *create(int type)
+	{
+		return new Schematic;
+	}
+};
+
 void build_nnlist_and_update_ids(MapNode *nodes, u32 nodecount,
 					std::vector<content_t> *usednodes);
 
diff --git a/src/script/common/c_content.cpp b/src/script/common/c_content.cpp
index 88bbedec5..0e1e608c4 100644
--- a/src/script/common/c_content.cpp
+++ b/src/script/common/c_content.cpp
@@ -1009,86 +1009,98 @@ bool read_noiseparams_nc(lua_State *L, int index, NoiseParams *np)
 }
 
 /******************************************************************************/
-bool read_schematic(lua_State *L, int index, DecoSchematic *dschem, Server *server) {
+
+bool get_schematic(lua_State *L, int index, Schematic *schem,
+	INodeDefManager *ndef, std::map<std::string, std::string> &replace_names)
+{
 	if (index < 0)
 		index = lua_gettop(L) + 1 + index;
 
-	INodeDefManager *ndef = server->getNodeDefManager();
-
 	if (lua_istable(L, index)) {
-		lua_getfield(L, index, "size");
-		v3s16 size = read_v3s16(L, -1);
-		lua_pop(L, 1);
-		
-		int numnodes = size.X * size.Y * size.Z;
-		MapNode *schemdata = new MapNode[numnodes];
-		int i = 0;
-		
-		// Get schematic data
-		lua_getfield(L, index, "data");
-		luaL_checktype(L, -1, LUA_TTABLE);
-		
-		lua_pushnil(L);
-		while (lua_next(L, -2)) {
-			if (i < numnodes) {
-				// same as readnode, except param1 default is MTSCHEM_PROB_CONST
-				lua_getfield(L, -1, "name");
-				const char *name = luaL_checkstring(L, -1);
-				lua_pop(L, 1);
-				
-				u8 param1;
-				lua_getfield(L, -1, "param1");
-				param1 = !lua_isnil(L, -1) ? lua_tonumber(L, -1) : MTSCHEM_PROB_ALWAYS;
-				lua_pop(L, 1);
+		return read_schematic(L, index, schem, ndef, replace_names);
+	} else if (lua_isstring(L, index)) {
+		NodeResolver *resolver = ndef->getResolver();
+		const char *filename = lua_tostring(L, index);
+		return schem->loadSchematicFromFile(filename, resolver, replace_names);
+	} else {
+		return false;
+	}
+}
+
+bool read_schematic(lua_State *L, int index, Schematic *schem,
+	INodeDefManager *ndef, std::map<std::string, std::string> &replace_names)
+{
+	//// Get schematic size
+	lua_getfield(L, index, "size");
+	v3s16 size = read_v3s16(L, -1);
+	lua_pop(L, 1);
+
+	//// Get schematic data
+	lua_getfield(L, index, "data");
+	luaL_checktype(L, -1, LUA_TTABLE);
 	
-				u8 param2;
-				lua_getfield(L, -1, "param2");
-				param2 = !lua_isnil(L, -1) ? lua_tonumber(L, -1) : 0;
-				lua_pop(L, 1);
-				
-				schemdata[i] = MapNode(ndef, name, param1, param2);
-			}
-			
-			i++;
+	int numnodes = size.X * size.Y * size.Z;
+	MapNode *schemdata = new MapNode[numnodes];
+	int i = 0;
+
+	lua_pushnil(L);
+	while (lua_next(L, -2)) {
+		if (i < numnodes) {
+			// 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);
+
+			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;
+
+			schemdata[i] = MapNode(ndef, name, param1, param2);
 		}
 		
-		if (i != numnodes) {
-			errorstream << "read_schematic: incorrect number of "
-				"nodes provided in raw schematic data (got " << i <<
-				", expected " << numnodes << ")." << std::endl;
-			return false;
-		}
+		i++;
+		lua_pop(L, 1);
+	}
 
-		u8 *sliceprobs = new u8[size.Y];
-		for (i = 0; i != size.Y; i++)
-			sliceprobs[i] = MTSCHEM_PROB_ALWAYS;
-
-		// Get Y-slice probability values (if present)
-		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) {
-					sliceprobs[i] = getintfield_default(L, -1,
-						"prob", MTSCHEM_PROB_ALWAYS);
-				}
-				lua_pop(L, 1);
-			}
-		}
+	if (i != numnodes) {
+		errorstream << "read_schematic: incorrect number of "
+			"nodes provided in raw schematic data (got " << i <<
+			", expected " << numnodes << ")." << std::endl;
+		return false;
+	}
 
-		dschem->size        = size;
-		dschem->schematic   = schemdata;
-		dschem->slice_probs = sliceprobs;
+	//// 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;
 
-	} else if (lua_isstring(L, index)) {
-		dschem->filename = std::string(lua_tostring(L, index));
-	} else {
-		errorstream << "read_schematic: missing schematic "
-			"filename or raw schematic data" << std::endl;
-		return false;
+	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);
+		}
 	}
-	
+
+	schem->flags       = 0;
+	schem->size        = size;
+	schem->schemdata   = schemdata;
+	schem->slice_probs = slice_probs;
 	return true;
 }
 
diff --git a/src/script/common/c_content.h b/src/script/common/c_content.h
index f48c673bd..5b4dff2bd 100644
--- a/src/script/common/c_content.h
+++ b/src/script/common/c_content.h
@@ -59,7 +59,7 @@ struct DigParams;
 struct HitParams;
 struct EnumString;
 struct NoiseParams;
-class DecoSchematic;
+class Schematic;
 
 
 ContentFeatures    read_content_features         (lua_State *L, int index);
@@ -151,10 +151,14 @@ NoiseParams*       read_noiseparams          (lua_State *L, int index);
 
 bool               read_noiseparams_nc       (lua_State *L, int index,
                                               NoiseParams *np);
-
+bool               get_schematic             (lua_State *L, int index,
+                                              Schematic *schem,
+                                              INodeDefManager *ndef,
+                             std::map<std::string, std::string> &replace_names);
 bool               read_schematic            (lua_State *L, int index,
-                                              DecoSchematic *dschem,
-                                              Server *server);
+                                              Schematic *dschem,
+                                              INodeDefManager *ndef,
+                             std::map<std::string, std::string> &replace_names);
 
 void               luaentity_get             (lua_State *L,u16 id);
 
diff --git a/src/script/lua_api/l_mapgen.cpp b/src/script/lua_api/l_mapgen.cpp
index 2ed9fadf9..71b1f4740 100644
--- a/src/script/lua_api/l_mapgen.cpp
+++ b/src/script/lua_api/l_mapgen.cpp
@@ -25,13 +25,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "util/serialize.h"
 #include "server.h"
 #include "environment.h"
-#include "mg_biome.h"
 #include "emerge.h"
 #include "mg_biome.h"
 #include "mg_ore.h"
 #include "mg_decoration.h"
 #include "mg_schematic.h"
 #include "mapgen_v7.h"
+#include "settings.h"
 #include "main.h"
 #include "log.h"
 
@@ -85,7 +85,7 @@ struct EnumString ModApiMapgen::es_Rotation[] =
 
 
 static void read_schematic_replacements(lua_State *L,
-	std::map<std::string, std::string> replace_names, int index)
+	std::map<std::string, std::string> &replace_names, int index)
 {
 	lua_pushnil(L);
 	while (lua_next(L, index)) {
@@ -310,13 +310,13 @@ int ModApiMapgen::l_register_biome(lua_State *L)
 	luaL_checktype(L, index, LUA_TTABLE);
 
 	NodeResolver *resolver = getServer(L)->getNodeDefManager()->getResolver();
-	BiomeDefManager *bmgr  = getServer(L)->getEmergeManager()->biomedef;
+	BiomeManager *bmgr     = getServer(L)->getEmergeManager()->biomemgr;
 
 	enum BiomeTerrainType terrain = (BiomeTerrainType)getenumfield(L, index,
 				"terrain_type", es_BiomeTerrainType, BIOME_TERRAIN_NORMAL);
-	Biome *b = bmgr->createBiome(terrain);
+	Biome *b = bmgr->create(terrain);
 
-	b->name           = getstringfield_default(L, index, "name", "<no name>");
+	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_min     = getintfield_default(L, index, "height_min",   0);
@@ -325,7 +325,8 @@ int ModApiMapgen::l_register_biome(lua_State *L)
 	b->humidity_point = getfloatfield_default(L, index, "humidity_point", 0.);
 	b->flags          = 0; //reserved
 
-	if (!bmgr->addBiome(b)) {
+	u32 id = bmgr->add(b);
+	if (id == (u32)-1) {
 		delete b;
 		return 0;
 	}
@@ -344,7 +345,8 @@ int ModApiMapgen::l_register_biome(lua_State *L)
 
 	verbosestream << "register_biome: " << b->name << std::endl;
 
-	return 0;
+	lua_pushinteger(L, id);
+	return 1;
 }
 
 // register_decoration({lots of stuff})
@@ -353,20 +355,22 @@ int ModApiMapgen::l_register_decoration(lua_State *L)
 	int index = 1;
 	luaL_checktype(L, index, LUA_TTABLE);
 
-	EmergeManager *emerge = getServer(L)->getEmergeManager();
-	BiomeDefManager *bdef = emerge->biomedef;
-	NodeResolver *resolver = getServer(L)->getNodeDefManager()->getResolver();
+	INodeDefManager *ndef      = getServer(L)->getNodeDefManager();
+	NodeResolver *resolver     = getServer(L)->getNodeDefManager()->getResolver();
+	DecorationManager *decomgr = getServer(L)->getEmergeManager()->decomgr;
+	BiomeManager *biomemgr     = getServer(L)->getEmergeManager()->biomemgr;
 
 	enum DecorationType decotype = (DecorationType)getenumfield(L, index,
 				"deco_type", es_DecorationType, -1);
 
-	Decoration *deco = createDecoration(decotype);
+	Decoration *deco = decomgr->create(decotype);
 	if (!deco) {
 		errorstream << "register_decoration: decoration placement type "
 			<< decotype << " not implemented";
 		return 0;
 	}
 	
+	deco->name       = getstringfield_default(L, index, "name", "");
 	deco->fill_ratio = getfloatfield_default(L, index, "fill_ratio", 0.02);
 	deco->sidelen    = getintfield_default(L, index, "sidelen", 8);
 	if (deco->sidelen <= 0) {
@@ -391,9 +395,11 @@ int ModApiMapgen::l_register_decoration(lua_State *L)
 	std::vector<const char *> biome_list;
 	getstringlistfield(L, index, "biomes", biome_list);
 	for (size_t i = 0; i != biome_list.size(); i++) {
-		u8 biomeid = bdef->getBiomeIdByName(biome_list[i]);
-		if (biomeid)
-			deco->biomes.insert(biomeid);
+		Biome *b = (Biome *)biomemgr->getByName(biome_list[i]);
+		if (!b)
+			continue;
+
+		deco->biomes.insert(b->id);
 	}
 
 	//// Handle decoration type-specific parameters
@@ -403,7 +409,7 @@ int ModApiMapgen::l_register_decoration(lua_State *L)
 			success = regDecoSimple(L, resolver, (DecoSimple *)deco);
 			break;
 		case DECO_SCHEMATIC:
-			success = regDecoSchematic(L, resolver, (DecoSchematic *)deco);
+			success = regDecoSchematic(L, ndef, (DecoSchematic *)deco);
 			break;
 		case DECO_LSYSTEM:
 			break;
@@ -414,12 +420,14 @@ int ModApiMapgen::l_register_decoration(lua_State *L)
 		return 0;
 	}
 
-	emerge->decorations.push_back(deco);
-
-	verbosestream << "register_decoration: decoration '" << deco->getName()
-		<< "' registered" << std::endl;
+	u32 id = decomgr->add(deco);
+	if (id == (u32)-1) {
+		delete deco;
+		return 0;
+	}
 
-	return 0;
+	lua_pushinteger(L, id);
+	return 1;
 }
 
 bool ModApiMapgen::regDecoSimple(lua_State *L,
@@ -461,8 +469,8 @@ bool ModApiMapgen::regDecoSimple(lua_State *L,
 	return true;
 }
 
-bool ModApiMapgen::regDecoSchematic(lua_State *L,
-		NodeResolver *resolver, DecoSchematic *deco)
+bool ModApiMapgen::regDecoSchematic(lua_State *L, INodeDefManager *ndef,
+	DecoSchematic *deco)
 {
 	int index = 1;
 
@@ -478,19 +486,16 @@ bool ModApiMapgen::regDecoSchematic(lua_State *L,
 		read_schematic_replacements(L, replace_names, lua_gettop(L));
 	lua_pop(L, 1);
 
+	Schematic *schem = new Schematic;
 	lua_getfield(L, index, "schematic");
-	if (!read_schematic(L, -1, deco, getServer(L))) {
+	if (!get_schematic(L, -1, schem, ndef, replace_names)) {
 		lua_pop(L, 1);
+		delete schem;
 		return false;
 	}
 	lua_pop(L, 1);
 
-	if (!deco->filename.empty() &&
-		!deco->loadSchematicFile(resolver, replace_names)) {
-		errorstream << "register_decoration: failed to load schematic"
-			" file '" << deco->filename << "'" << std::endl;
-		return false;
-	}
+	deco->schematic = schem;
 
 	return true;
 }
@@ -501,25 +506,25 @@ int ModApiMapgen::l_register_ore(lua_State *L)
 	int index = 1;
 	luaL_checktype(L, index, LUA_TTABLE);
 
-	EmergeManager *emerge  = getServer(L)->getEmergeManager();
 	NodeResolver *resolver = getServer(L)->getNodeDefManager()->getResolver();
+	OreManager *oremgr     = getServer(L)->getEmergeManager()->oremgr;
 
 	enum OreType oretype = (OreType)getenumfield(L, index,
 				"ore_type", es_OreType, ORE_SCATTER);
-	Ore *ore = createOre(oretype);
+	Ore *ore = oremgr->create(oretype);
 	if (!ore) {
-		errorstream << "register_ore: ore_type "
-			<< oretype << " not implemented";
+		errorstream << "register_ore: ore_type " << oretype << " not implemented";
 		return 0;
 	}
 
+	ore->name           = getstringfield_default(L, index, "name", "");
 	ore->ore_param2     = (u8)getintfield_default(L, index, "ore_param2", 0);
 	ore->clust_scarcity = getintfield_default(L, index, "clust_scarcity", 1);
 	ore->clust_num_ores = getintfield_default(L, index, "clust_num_ores", 1);
 	ore->clust_size     = getintfield_default(L, index, "clust_size", 0);
 	ore->height_min     = getintfield_default(L, index, "height_min", 0);
 	ore->height_max     = getintfield_default(L, index, "height_max", 0);
-	ore->nthresh        = getfloatfield_default(L, index, "noise_threshhold", 0.);
+	ore->nthresh        = getfloatfield_default(L, index, "noise_threshhold", 0);
 	ore->noise          = NULL;
 	ore->flags          = 0;
 
@@ -536,6 +541,12 @@ int ModApiMapgen::l_register_ore(lua_State *L)
 	ore->np = read_noiseparams(L, -1);
 	lua_pop(L, 1);
 
+	u32 id = oremgr->add(ore);
+	if (id == (u32)-1) {
+		delete ore;
+		return 0;
+	}
+
 	std::vector<const char *> wherein_names;
 	getstringlistfield(L, index, "wherein", wherein_names);
 	for (size_t i = 0; i != wherein_names.size(); i++)
@@ -544,17 +555,14 @@ int ModApiMapgen::l_register_ore(lua_State *L)
 	resolver->addNode(getstringfield_default(L, index, "ore", ""),
 		"", CONTENT_AIR, &ore->c_ore);
 
-	emerge->ores.push_back(ore);
-
-	//verbosestream << "register_ore: ore '" << ore->ore_name
-	//	<< "' registered" << std::endl;
-	return 0;
+	lua_pushinteger(L, id);
+	return 1;
 }
 
 // create_schematic(p1, p2, probability_list, filename)
 int ModApiMapgen::l_create_schematic(lua_State *L)
 {
-	DecoSchematic dschem;
+	Schematic schem;
 
 	Map *map = &(getEnv(L)->getMap());
 	INodeDefManager *ndef = getServer(L)->getNodeDefManager();
@@ -594,20 +602,19 @@ int ModApiMapgen::l_create_schematic(lua_State *L)
 		}
 	}
 
-	const char *s = lua_tostring(L, 4);
-	dschem.filename = std::string(s ? s : "");
+	const char *filename = luaL_checkstring(L, 4);
 
-	if (!dschem.getSchematicFromMap(map, p1, p2)) {
+	if (!schem.getSchematicFromMap(map, p1, p2)) {
 		errorstream << "create_schematic: failed to get schematic "
 			"from map" << std::endl;
 		return 0;
 	}
 
-	dschem.applyProbabilities(p1, &prob_list, &slice_prob_list);
+	schem.applyProbabilities(p1, &prob_list, &slice_prob_list);
 
-	dschem.saveSchematicFile(ndef);
+	schem.saveSchematicToFile(filename, ndef);
 	actionstream << "create_schematic: saved schematic file '"
-		<< dschem.filename << "'." << std::endl;
+		<< filename << "'." << std::endl;
 
 	return 1;
 }
@@ -615,38 +622,36 @@ int ModApiMapgen::l_create_schematic(lua_State *L)
 // place_schematic(p, schematic, rotation, replacement)
 int ModApiMapgen::l_place_schematic(lua_State *L)
 {
-	DecoSchematic dschem;
+	Schematic schem;
 
 	Map *map = &(getEnv(L)->getMap());
-	NodeResolver *resolver = getServer(L)->getNodeDefManager()->getResolver();
+	INodeDefManager *ndef = getServer(L)->getNodeDefManager();
 
+	//// Read position
 	v3s16 p = read_v3s16(L, 1);
-	if (!read_schematic(L, 2, &dschem, getServer(L)))
-		return 0;
 
+	//// Read rotation
 	int rot = ROTATE_0;
 	if (lua_isstring(L, 3))
 		string_to_enum(es_Rotation, rot, std::string(lua_tostring(L, 3)));
 
-	dschem.rotation = (Rotation)rot;
+	//// Read force placement
+	bool force_placement = true;
+	if (lua_isboolean(L, 5))
+		force_placement = lua_toboolean(L, 5);
 
+	//// Read node replacements
 	std::map<std::string, std::string> replace_names;
 	if (lua_istable(L, 4))
 		read_schematic_replacements(L, replace_names, 4);
 
-	bool force_placement = true;
-	if (lua_isboolean(L, 5))
-		force_placement = lua_toboolean(L, 5);
-
-	if (!dschem.filename.empty()) {
-		if (!dschem.loadSchematicFile(resolver, replace_names)) {
-			errorstream << "place_schematic: failed to load schematic file '"
-				<< dschem.filename << "'" << std::endl;
-			return 0;
-		}
+	//// Read schematic
+	if (!get_schematic(L, 2, &schem, ndef, replace_names)) {
+		errorstream << "place_schematic: failed to get schematic" << std::endl;
+		return 0;
 	}
 
-	dschem.placeStructure(map, p, force_placement);
+	schem.placeStructure(map, p, 0, (Rotation)rot, force_placement, ndef);
 
 	return 1;
 }
diff --git a/src/script/lua_api/l_mapgen.h b/src/script/lua_api/l_mapgen.h
index d14471a08..dac0f00a7 100644
--- a/src/script/lua_api/l_mapgen.h
+++ b/src/script/lua_api/l_mapgen.h
@@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 #include "lua_api/l_base.h"
 
+class INodeDefManager;
 class NodeResolver;
 class DecoSimple;
 class DecoSchematic;
@@ -60,7 +61,7 @@ class ModApiMapgen : public ModApiBase {
 	static bool regDecoSimple(lua_State *L,
 			NodeResolver *resolver, DecoSimple *deco);
 	static bool regDecoSchematic(lua_State *L,
-			NodeResolver *resolver, DecoSchematic *deco);
+			INodeDefManager *ndef, DecoSchematic *deco);
 
 	static struct EnumString es_BiomeTerrainType[];
 	static struct EnumString es_DecorationType[];
-- 
GitLab