diff --git a/src/emerge.h b/src/emerge.h
index ab9fca2ba..6f204666d 100644
--- a/src/emerge.h
+++ b/src/emerge.h
@@ -44,6 +44,7 @@ class OreManager;
 class DecorationManager;
 class SchematicManager;
 class Server;
+class ModApiMapgen;
 
 // Structure containing inputs/outputs for chunk generation
 struct BlockMakeData {
@@ -111,6 +112,11 @@ private:
 };
 
 class EmergeManager {
+	/* The mod API needs unchecked access to allow:
+	 * - using decomgr or oremgr to place decos/ores
+	 * - using schemmgr to load and place schematics
+	 */
+	friend class ModApiMapgen;
 public:
 	const NodeDefManager *ndef;
 	bool enable_mapgen_debug_info;
diff --git a/src/mapgen/mg_biome.cpp b/src/mapgen/mg_biome.cpp
index f3bc4e829..8c59ac9e6 100644
--- a/src/mapgen/mg_biome.cpp
+++ b/src/mapgen/mg_biome.cpp
@@ -123,7 +123,8 @@ float BiomeManager::getHumidityAtPosOriginal(v3s16 pos, NoiseParams &np_humidity
 
 
 // For BiomeGen type 'BiomeGenOriginal'
-Biome *BiomeManager::getBiomeFromNoiseOriginal(float heat, float humidity, v3s16 pos) const
+const Biome *BiomeManager::getBiomeFromNoiseOriginal(float heat,
+	float humidity, v3s16 pos) const
 {
 	Biome *biome_closest = nullptr;
 	Biome *biome_closest_blend = nullptr;
diff --git a/src/mapgen/mg_biome.h b/src/mapgen/mg_biome.h
index 0a4471cc3..57f4aa20d 100644
--- a/src/mapgen/mg_biome.h
+++ b/src/mapgen/mg_biome.h
@@ -90,6 +90,7 @@ struct BiomeParams {
 	s32 seed;
 };
 
+// WARNING: this class is not thread-safe
 class BiomeGen {
 public:
 	virtual ~BiomeGen() = default;
@@ -233,7 +234,8 @@ public:
 		NoiseParams &np_heat_blend, u64 seed) const;
 	float getHumidityAtPosOriginal(v3s16 pos, NoiseParams &np_humidity,
 		NoiseParams &np_humidity_blend, u64 seed) const;
-	Biome *getBiomeFromNoiseOriginal(float heat, float humidity, v3s16 pos) const;
+	const Biome *getBiomeFromNoiseOriginal(float heat, float humidity,
+		v3s16 pos) const;
 
 private:
 	BiomeManager() {};
diff --git a/src/mapgen/mg_schematic.cpp b/src/mapgen/mg_schematic.cpp
index c3bd89f3a..ba102d997 100644
--- a/src/mapgen/mg_schematic.cpp
+++ b/src/mapgen/mg_schematic.cpp
@@ -359,7 +359,7 @@ bool Schematic::deserializeFromMts(std::istream *is,
 
 
 bool Schematic::serializeToMts(std::ostream *os,
-	const std::vector<std::string> &names)
+	const std::vector<std::string> &names) const
 {
 	std::ostream &ss = *os;
 
@@ -383,7 +383,8 @@ bool Schematic::serializeToMts(std::ostream *os,
 
 
 bool Schematic::serializeToLua(std::ostream *os,
-	const std::vector<std::string> &names, bool use_comments, u32 indent_spaces)
+	const std::vector<std::string> &names, bool use_comments,
+	u32 indent_spaces) const
 {
 	std::ostream &ss = *os;
 
diff --git a/src/mapgen/mg_schematic.h b/src/mapgen/mg_schematic.h
index 3222085e6..6b31251b6 100644
--- a/src/mapgen/mg_schematic.h
+++ b/src/mapgen/mg_schematic.h
@@ -106,9 +106,10 @@ public:
 	bool getSchematicFromMap(Map *map, v3s16 p1, v3s16 p2);
 
 	bool deserializeFromMts(std::istream *is, std::vector<std::string> *names);
-	bool serializeToMts(std::ostream *os, const std::vector<std::string> &names);
+	bool serializeToMts(std::ostream *os,
+		const std::vector<std::string> &names) const;
 	bool serializeToLua(std::ostream *os, const std::vector<std::string> &names,
-		bool use_comments, u32 indent_spaces);
+		bool use_comments, u32 indent_spaces) const;
 
 	void blitToVManip(MMVManip *vm, v3s16 p, Rotation rot, bool force_place);
 	bool placeOnVManip(MMVManip *vm, v3s16 p, u32 flags, Rotation rot, bool force_place);
diff --git a/src/objdef.h b/src/objdef.h
index 20565029c..e40324a88 100644
--- a/src/objdef.h
+++ b/src/objdef.h
@@ -66,6 +66,7 @@ protected:
 // WARNING: Ownership of ObjDefs is transferred to the ObjDefManager it is
 // added/set to.  Note that ObjDefs managed by ObjDefManager are NOT refcounted,
 // so the same ObjDef instance must not be referenced multiple
+// TODO: const correctness for getter methods
 class ObjDefManager {
 public:
 	ObjDefManager(IGameDef *gamedef, ObjDefType type);
diff --git a/src/script/lua_api/l_mapgen.cpp b/src/script/lua_api/l_mapgen.cpp
index ba0304be3..584085428 100644
--- a/src/script/lua_api/l_mapgen.cpp
+++ b/src/script/lua_api/l_mapgen.cpp
@@ -490,7 +490,7 @@ int ModApiMapgen::l_get_biome_id(lua_State *L)
 	if (!bmgr)
 		return 0;
 
-	Biome *biome = (Biome *)bmgr->getByName(biome_str);
+	const Biome *biome = (Biome *)bmgr->getByName(biome_str);
 	if (!biome || biome->index == OBJDEF_INVALID_INDEX)
 		return 0;
 
@@ -512,7 +512,7 @@ int ModApiMapgen::l_get_biome_name(lua_State *L)
 	if (!bmgr)
 		return 0;
 
-	Biome *b = (Biome *)bmgr->getRaw(biome_id);
+	const Biome *b = (Biome *)bmgr->getRaw(biome_id);
 	lua_pushstring(L, b->name.c_str());
 
 	return 1;
@@ -551,8 +551,6 @@ int ModApiMapgen::l_get_heat(lua_State *L)
 		return 0;
 
 	float heat = bmgr->getHeatAtPosOriginal(pos, np_heat, np_heat_blend, seed);
-	if (!heat)
-		return 0;
 
 	lua_pushnumber(L, heat);
 
@@ -593,8 +591,6 @@ int ModApiMapgen::l_get_humidity(lua_State *L)
 
 	float humidity = bmgr->getHumidityAtPosOriginal(pos, np_humidity,
 		np_humidity_blend, seed);
-	if (!humidity)
-		return 0;
 
 	lua_pushnumber(L, humidity);
 
@@ -648,7 +644,7 @@ int ModApiMapgen::l_get_biome_data(lua_State *L)
 	if (!humidity)
 		return 0;
 
-	Biome *biome = (Biome *)bmgr->getBiomeFromNoiseOriginal(heat, humidity, pos);
+	const Biome *biome = bmgr->getBiomeFromNoiseOriginal(heat, humidity, pos);
 	if (!biome || biome->index == OBJDEF_INVALID_INDEX)
 		return 0;
 
@@ -1516,8 +1512,7 @@ int ModApiMapgen::l_generate_ores(lua_State *L)
 
 	u32 blockseed = Mapgen::getBlockSeed(pmin, mg.seed);
 
-	OreManager *oremgr = (OreManager*) emerge->getOreManager(); // FIXME FIXME
-	oremgr->placeAllOres(&mg, blockseed, pmin, pmax);
+	emerge->oremgr->placeAllOres(&mg, blockseed, pmin, pmax);
 
 	return 0;
 }
@@ -1543,8 +1538,7 @@ int ModApiMapgen::l_generate_decorations(lua_State *L)
 
 	u32 blockseed = Mapgen::getBlockSeed(pmin, mg.seed);
 
-	DecorationManager *decomgr = (DecorationManager*) emerge->getDecorationManager(); // FIXME FIXME
-	decomgr->placeAllDecos(&mg, blockseed, pmin, pmax);
+	emerge->decomgr->placeAllDecos(&mg, blockseed, pmin, pmax);
 
 	return 0;
 }
@@ -1624,8 +1618,7 @@ int ModApiMapgen::l_place_schematic(lua_State *L)
 	GET_ENV_PTR;
 
 	ServerMap *map = &(env->getServerMap());
-	SchematicManager *schemmgr = (SchematicManager*)
-		getServer(L)->getEmergeManager()->getSchematicManager(); // FIXME FIXME
+	SchematicManager *schemmgr = getServer(L)->getEmergeManager()->schemmgr;
 
 	//// Read position
 	v3s16 p = check_v3s16(L, 1);
@@ -1670,8 +1663,7 @@ int ModApiMapgen::l_place_schematic_on_vmanip(lua_State *L)
 {
 	NO_MAP_LOCK_REQUIRED;
 
-	SchematicManager *schemmgr = (SchematicManager*)
-		getServer(L)->getEmergeManager()->getSchematicManager(); // FIXME FIXME
+	SchematicManager *schemmgr = getServer(L)->getEmergeManager()->schemmgr;
 
 	//// Read VoxelManip object
 	MMVManip *vm = LuaVoxelManip::checkobject(L, 1)->vm;
@@ -1727,7 +1719,7 @@ int ModApiMapgen::l_serialize_schematic(lua_State *L)
 
 	//// Get schematic
 	bool was_loaded = false;
-	Schematic *schem = (Schematic *)get_objdef(L, 1, schemmgr);
+	const Schematic *schem = (Schematic *)get_objdef(L, 1, schemmgr);
 	if (!schem) {
 		schem = load_schematic(L, 1, NULL, NULL);
 		was_loaded = true;