Add MapSettingsManager and new mapgen setting script API functions
authorkwolekr <kwolekr@minetest.net>
Fri, 24 Jun 2016 22:15:56 +0000 (18:15 -0400)
committerkwolekr <kwolekr@minetest.net>
Sun, 3 Jul 2016 19:38:36 +0000 (15:38 -0400)
This commit refactors the majority of the Mapgen settings system.
- MapgenParams is now owned by MapSettingsManager, itself a part of ServerMap,
  instead of the EmergeManager.
- New Script API functions added:
    core.get_mapgen_setting
    core.get_mapgen_setting_noiseparams,
    core.set_mapgen_setting, and
    core.set_mapgen_setting_noiseparams.
- minetest.get/set_mapgen_params are deprecated by the above new functions.
- It is now possible to view and modify any arbitrary mapgen setting from a mod,
  rather than the base MapgenParams structure.
- MapgenSpecificParams has been removed.

31 files changed:
build/android/jni/Android.mk
doc/lua_api.txt
src/CMakeLists.txt
src/emerge.cpp
src/emerge.h
src/map.cpp
src/map.h
src/map_settings_manager.cpp [new file with mode: 0644]
src/map_settings_manager.h [new file with mode: 0644]
src/mapgen.cpp
src/mapgen.h
src/mapgen_flat.cpp
src/mapgen_flat.h
src/mapgen_fractal.cpp
src/mapgen_fractal.h
src/mapgen_singlenode.h
src/mapgen_v5.cpp
src/mapgen_v5.h
src/mapgen_v6.cpp
src/mapgen_v6.h
src/mapgen_v7.cpp
src/mapgen_v7.h
src/mapgen_valleys.cpp
src/mapgen_valleys.h
src/script/lua_api/l_mapgen.cpp
src/script/lua_api/l_mapgen.h
src/script/lua_api/l_vmanip.cpp
src/server.cpp
src/subgame.cpp
src/unittest/CMakeLists.txt
src/unittest/test_map_settings_manager.cpp [new file with mode: 0644]

index afd8c76b24b42ba3c9a7214999c5dad7c474d59b..a42ab76b8a70704357786a1b15d99dfe553f3c02 100644 (file)
@@ -169,6 +169,7 @@ LOCAL_SRC_FILES := \
                jni/src/log.cpp                           \
                jni/src/main.cpp                          \
                jni/src/map.cpp                           \
+               jni/src/map_settings_manager.cpp          \
                jni/src/mapblock.cpp                      \
                jni/src/mapblock_mesh.cpp                 \
                jni/src/mapgen.cpp                        \
@@ -238,6 +239,7 @@ LOCAL_SRC_FILES := \
                jni/src/unittest/test_connection.cpp      \
                jni/src/unittest/test_filepath.cpp        \
                jni/src/unittest/test_inventory.cpp       \
+               jni/src/unittest/test_map_settings_manager.cpp \
                jni/src/unittest/test_mapnode.cpp         \
                jni/src/unittest/test_nodedef.cpp         \
                jni/src/unittest/test_noderesolver.cpp    \
index 6d359379e6842b3b1fc9e5672037d2d24497ade4..29756606850c332f028bd53581aa07842b9c1233 100644 (file)
@@ -2089,7 +2089,9 @@ and `minetest.auth_reload` call the authetification handler.
       given biome_name string.
 * `minetest.get_mapgen_params()` Returns mapgen parameters, a table containing
   `mgname`, `seed`, `chunksize`, `water_level`, and `flags`.
+  * Deprecated: use minetest.get_mapgen_setting(name) instead
 * `minetest.set_mapgen_params(MapgenParams)`
+    * Deprecated: use minetest.set_mapgen_setting(name, value, override) instead
     * Set map generation parameters
     * Function cannot be called after the registration period; only initialization
       and `on_mapgen_init`
@@ -2099,6 +2101,23 @@ and `minetest.auth_reload` call the authetification handler.
         * `flags` contains a comma-delimited string of flags to set,
           or if the prefix `"no"` is attached, clears instead.
         * `flags` is in the same format and has the same options as `mg_flags` in `minetest.conf`
+* `minetest.get_mapgen_setting(name)`
+    * Gets the *active* mapgen setting (or nil if none exists) in string format with the following
+      order of precedence:
+        1) Settings loaded from map_meta.txt or overrides set during mod execution
+        2) Settings set by mods without a metafile override
+        3) Settings explicitly set in the user config file, minetest.conf
+        4) Settings set as the user config default
+* `minetest.get_mapgen_setting_noiseparams(name)`
+    * Same as above, but returns the value as a NoiseParams table if the setting `name` exists
+      and is a valid NoiseParams
+* `minetest.set_mapgen_setting(name, value, [override_meta=false])`
+   * Sets a mapgen param to `value`, and will take effect if the corresponding mapgen setting
+     is not already present in map_meta.txt.  If the optional boolean override_meta is set to true,
+     this setting will become the active setting regardless of the map metafile contents.
+   * Note: to set the seed, use "seed", not "fixed_map_seed"
+* `minetest.set_mapgen_setting_noiseparams(name, value, [override_meta=false])`
+   * Same as above, except value is a NoiseParams table
 * `minetest.set_noiseparams(name, noiseparams, set_default)`
     * Sets the noiseparams setting of `name` to the noiseparams table specified in `noiseparams`.
     * `set_default` is an optional boolean (default: `true`) that specifies whether the setting
index bffc1f7eb7306dfd2f0dec77076868ead98a4a48..bcd7a5984bfe9995132669ccc0a4a3664543a441 100644 (file)
@@ -414,6 +414,7 @@ set(common_SRCS
        light.cpp
        log.cpp
        map.cpp
+       map_settings_manager.cpp
        mapblock.cpp
        mapgen.cpp
        mapgen_flat.cpp
index 48de6cb1a7ee94573a31025a3ad5387e85d0b958..daf42f5e230acc244a6359f240793e8c42f90054 100644 (file)
@@ -156,37 +156,19 @@ EmergeManager::~EmergeManager()
 }
 
 
-void EmergeManager::loadMapgenParams()
-{
-       params.load(*g_settings);
-}
-
-
-void EmergeManager::initMapgens()
+bool EmergeManager::initMapgens(MapgenParams *params)
 {
        if (m_mapgens.size())
-               return;
-
-       MapgenType mgtype = Mapgen::getMapgenType(params.mg_name);
-       if (mgtype == MAPGEN_INVALID) {
-               const char *default_mapgen_name = Mapgen::getMapgenName(MAPGEN_DEFAULT);
-               errorstream << "EmergeManager: mapgen " << params.mg_name <<
-                       " not registered; falling back to " <<
-                       default_mapgen_name << std::endl;
-
-               params.mg_name = default_mapgen_name;
-               mgtype = MAPGEN_DEFAULT;
-       }
+               return false;
 
-       if (!params.sparams) {
-               params.sparams = Mapgen::createMapgenParams(mgtype);
-               params.sparams->readParams(g_settings);
-       }
+       this->mgparams = params;
 
        for (u32 i = 0; i != m_threads.size(); i++) {
-               Mapgen *mg = Mapgen::createMapgen(mgtype, i, &params, this);
+               Mapgen *mg = Mapgen::createMapgen(params->mgtype, i, params, this);
                m_mapgens.push_back(mg);
        }
+
+       return true;
 }
 
 
@@ -288,12 +270,14 @@ bool EmergeManager::enqueueBlockEmergeEx(
 // Mapgen-related helper functions
 //
 
+
+// TODO(hmmmm): Move this to ServerMap
 v3s16 EmergeManager::getContainingChunk(v3s16 blockpos)
 {
-       return getContainingChunk(blockpos, params.chunksize);
+       return getContainingChunk(blockpos, mgparams->chunksize);
 }
 
-
+// TODO(hmmmm): Move this to ServerMap
 v3s16 EmergeManager::getContainingChunk(v3s16 blockpos, s16 chunksize)
 {
        s16 coff = -chunksize / 2;
@@ -327,7 +311,7 @@ int EmergeManager::getGroundLevelAtPoint(v2s16 p)
        return m_mapgens[0]->getGroundLevelAtPoint(p);
 }
 
-
+// TODO(hmmmm): Move this to ServerMap
 bool EmergeManager::isBlockUnderground(v3s16 blockpos)
 {
 #if 0
@@ -338,7 +322,7 @@ bool EmergeManager::isBlockUnderground(v3s16 blockpos)
 #endif
 
        // Use a simple heuristic; the above method is wildly inaccurate anyway.
-       return blockpos.Y * (MAP_BLOCKSIZE + 1) <= params.water_level;
+       return blockpos.Y * (MAP_BLOCKSIZE + 1) <= mgparams->water_level;
 }
 
 bool EmergeManager::pushBlockEmergeData(
index 303a35529531673c95de0a04c2c80f343fec4f88..cf067714562bfe4dbff71f63bddb2ca4b142e101 100644 (file)
@@ -97,8 +97,16 @@ public:
        u32 gen_notify_on;
        std::set<u32> gen_notify_on_deco_ids;
 
-       // Map generation parameters
-       MapgenParams params;
+       // Parameters passed to mapgens owned by ServerMap
+       // TODO(hmmmm): Remove this after mapgen helper methods using them
+       // are moved to ServerMap
+       MapgenParams *mgparams;
+
+       // Hackish workaround:
+       // For now, EmergeManager must hold onto a ptr to the Map's setting manager
+       // since the Map can only be accessed through the Environment, and the
+       // Environment is not created until after script initialization.
+       MapSettingsManager *map_settings_mgr;
 
        // Managers of various map generation-related components
        BiomeManager *biomemgr;
@@ -110,8 +118,7 @@ public:
        EmergeManager(IGameDef *gamedef);
        ~EmergeManager();
 
-       void loadMapgenParams();
-       void initMapgens();
+       bool initMapgens(MapgenParams *mgparams);
 
        void startThreads();
        void stopThreads();
index a1f2086ceb012cd58a682c20040ffc40c334f346..38f0fa37ca754060a0866019b8bd9e38f03bb75e 100644 (file)
@@ -2130,11 +2130,15 @@ void Map::removeNodeTimer(v3s16 p)
 */
 ServerMap::ServerMap(std::string savedir, IGameDef *gamedef, EmergeManager *emerge):
        Map(dout_server, gamedef),
+       settings_mgr(g_settings, savedir + DIR_DELIM + "map_meta.txt"),
        m_emerge(emerge),
        m_map_metadata_changed(true)
 {
        verbosestream<<FUNCTION_NAME<<std::endl;
 
+       // Tell the EmergeManager about our MapSettingsManager
+       emerge->map_settings_mgr = &settings_mgr;
+
        /*
                Try to load map; if not found, create a new one.
        */
@@ -2170,26 +2174,15 @@ ServerMap::ServerMap(std::string savedir, IGameDef *gamedef, EmergeManager *emer
                        }
                        else
                        {
-                               try{
-                                       // Load map metadata (seed, chunksize)
-                                       loadMapMeta();
-                               }
-                               catch(SettingNotFoundException &e){
-                                       infostream<<"ServerMap:  Some metadata not found."
-                                                         <<" Using default settings."<<std::endl;
-                               }
-                               catch(FileNotGoodException &e){
-                                       warningstream<<"Could not load map metadata"
-                                                       //<<" Disabling chunk-based generator."
-                                                       <<std::endl;
-                                       //m_chunksize = 0;
-                               }
 
-                               infostream<<"ServerMap: Successfully loaded map "
-                                               <<"metadata from "<<savedir
-                                               <<", assuming valid save directory."
-                                               <<" seed="<< m_emerge->params.seed <<"."
-                                               <<std::endl;
+                               if (settings_mgr.loadMapMeta()) {
+                                       infostream << "ServerMap: Metadata loaded from "
+                                               << savedir << std::endl;
+                               } else {
+                                       infostream << "ServerMap: Metadata could not be loaded "
+                                               "from " << savedir << ", assuming valid save "
+                                               "directory." << std::endl;
+                               }
 
                                m_map_saving_enabled = true;
                                // Map loaded, not creating new one
@@ -2259,19 +2252,26 @@ ServerMap::~ServerMap()
 #endif
 }
 
+MapgenParams *ServerMap::getMapgenParams()
+{
+       // getMapgenParams() should only ever be called after Server is initialized
+       assert(settings_mgr.mapgen_params != NULL);
+       return settings_mgr.mapgen_params;
+}
+
 u64 ServerMap::getSeed()
 {
-       return m_emerge->params.seed;
+       return getMapgenParams()->seed;
 }
 
 s16 ServerMap::getWaterLevel()
 {
-       return m_emerge->params.water_level;
+       return getMapgenParams()->water_level;
 }
 
 bool ServerMap::initBlockMake(v3s16 blockpos, BlockMakeData *data)
 {
-       s16 csize = m_emerge->params.chunksize;
+       s16 csize = getMapgenParams()->chunksize;
        v3s16 bpmin = EmergeManager::getContainingChunk(blockpos, csize);
        v3s16 bpmax = bpmin + v3s16(1, 1, 1) * (csize - 1);
 
@@ -2287,7 +2287,7 @@ bool ServerMap::initBlockMake(v3s16 blockpos, BlockMakeData *data)
                blockpos_over_limit(full_bpmax))
                return false;
 
-       data->seed = m_emerge->params.seed;
+       data->seed = getSeed();
        data->blockpos_min = bpmin;
        data->blockpos_max = bpmax;
        data->blockpos_requested = blockpos;
@@ -2905,8 +2905,9 @@ void ServerMap::save(ModifiedState save_level)
                infostream<<"ServerMap: Saving whole map, this can take time."
                                <<std::endl;
 
-       if(m_map_metadata_changed || save_level == MOD_STATE_CLEAN) {
-               saveMapMeta();
+       if (m_map_metadata_changed || save_level == MOD_STATE_CLEAN) {
+               if (settings_mgr.saveMapMeta())
+                       m_map_metadata_changed = false;
        }
 
        // Profile modified reasons
@@ -3005,55 +3006,6 @@ void ServerMap::listAllLoadedBlocks(std::vector<v3s16> &dst)
        }
 }
 
-void ServerMap::saveMapMeta()
-{
-       DSTACK(FUNCTION_NAME);
-
-       createDirs(m_savedir);
-
-       std::string fullpath = m_savedir + DIR_DELIM + "map_meta.txt";
-       std::ostringstream oss(std::ios_base::binary);
-       Settings conf;
-
-       m_emerge->params.save(conf);
-       conf.writeLines(oss);
-
-       oss << "[end_of_params]\n";
-
-       if(!fs::safeWriteToFile(fullpath, oss.str())) {
-               errorstream << "ServerMap::saveMapMeta(): "
-                               << "could not write " << fullpath << std::endl;
-               throw FileNotGoodException("Cannot save chunk metadata");
-       }
-
-       m_map_metadata_changed = false;
-}
-
-void ServerMap::loadMapMeta()
-{
-       DSTACK(FUNCTION_NAME);
-
-       Settings conf;
-       std::string fullpath = m_savedir + DIR_DELIM + "map_meta.txt";
-
-       std::ifstream is(fullpath.c_str(), std::ios_base::binary);
-       if (!is.good()) {
-               errorstream << "ServerMap::loadMapMeta(): "
-                       "could not open " << fullpath << std::endl;
-               throw FileNotGoodException("Cannot open map metadata");
-       }
-
-       if (!conf.parseConfigLines(is, "[end_of_params]")) {
-               throw SerializationError("ServerMap::loadMapMeta(): "
-                               "[end_of_params] not found!");
-       }
-
-       m_emerge->params.load(conf);
-
-       verbosestream << "ServerMap::loadMapMeta(): seed="
-               << m_emerge->params.seed << std::endl;
-}
-
 void ServerMap::saveSectorMeta(ServerMapSector *sector)
 {
        DSTACK(FUNCTION_NAME);
index 23da564713fbd1411a6f8f2d60d83a70cb38e1bb..13775fde1d1acb16f031da3aad5117f9a8aa9481 100644 (file)
--- a/src/map.h
+++ b/src/map.h
@@ -33,6 +33,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "modifiedstate.h"
 #include "util/container.h"
 #include "nodetimer.h"
+#include "map_settings_manager.h"
 
 class Settings;
 class Database;
@@ -46,8 +47,6 @@ class IRollbackManager;
 class EmergeManager;
 class ServerEnvironment;
 struct BlockMakeData;
-struct MapgenParams;
-
 
 /*
        MapEditEvent
@@ -463,9 +462,8 @@ public:
        void save(ModifiedState save_level);
        void listAllLoadableBlocks(std::vector<v3s16> &dst);
        void listAllLoadedBlocks(std::vector<v3s16> &dst);
-       // Saves map seed and possibly other stuff
-       void saveMapMeta();
-       void loadMapMeta();
+
+       MapgenParams *getMapgenParams();
 
        /*void saveChunkMeta();
        void loadChunkMeta();*/
@@ -506,6 +504,8 @@ public:
        u64 getSeed();
        s16 getWaterLevel();
 
+       MapSettingsManager settings_mgr;
+
 private:
        // Emerge manager
        EmergeManager *m_emerge;
diff --git a/src/map_settings_manager.cpp b/src/map_settings_manager.cpp
new file mode 100644 (file)
index 0000000..53d1712
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+Minetest
+Copyright (C) 2010-2013 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "debug.h"
+#include "filesys.h"
+#include "log.h"
+#include "mapgen.h"
+#include "settings.h"
+
+#include "map_settings_manager.h"
+
+MapSettingsManager::MapSettingsManager(
+       Settings *user_settings, const std::string &map_meta_path)
+{
+       m_map_meta_path = map_meta_path;
+       m_user_settings = user_settings;
+       m_map_settings  = new Settings;
+       mapgen_params   = NULL;
+
+       assert(m_user_settings != NULL);
+}
+
+
+MapSettingsManager::~MapSettingsManager()
+{
+       delete m_map_settings;
+       delete mapgen_params;
+}
+
+
+bool MapSettingsManager::getMapSetting(
+       const std::string &name, std::string *value_out)
+{
+       if (m_map_settings->getNoEx(name, *value_out))
+               return true;
+
+       // Compatibility kludge
+       if (m_user_settings == g_settings && name == "seed")
+               return m_user_settings->getNoEx("fixed_map_seed", *value_out);
+
+       return m_user_settings->getNoEx(name, *value_out);
+}
+
+
+bool MapSettingsManager::getMapSettingNoiseParams(
+       const std::string &name, NoiseParams *value_out)
+{
+       return m_map_settings->getNoiseParams(name, *value_out) ||
+               m_user_settings->getNoiseParams(name, *value_out);
+}
+
+
+bool MapSettingsManager::setMapSetting(
+       const std::string &name, const std::string &value, bool override_meta)
+{
+       if (mapgen_params)
+               return false;
+
+       if (override_meta)
+               m_map_settings->set(name, value);
+       else
+               m_map_settings->setDefault(name, value);
+
+       return true;
+}
+
+
+bool MapSettingsManager::setMapSettingNoiseParams(
+       const std::string &name, const NoiseParams *value, bool override_meta)
+{
+       if (mapgen_params)
+               return false;
+
+       m_map_settings->setNoiseParams(name, *value, !override_meta);
+       return true;
+}
+
+
+bool MapSettingsManager::loadMapMeta()
+{
+       std::ifstream is(m_map_meta_path.c_str(), std::ios_base::binary);
+
+       if (!is.good()) {
+               errorstream << "loadMapMeta: could not open "
+                       << m_map_meta_path << std::endl;
+               return false;
+       }
+
+       if (!m_map_settings->parseConfigLines(is, "[end_of_params]")) {
+               errorstream << "loadMapMeta: [end_of_params] not found!" << std::endl;
+               return false;
+       }
+
+       return true;
+}
+
+
+bool MapSettingsManager::saveMapMeta()
+{
+       // If mapgen params haven't been created yet; abort
+       if (!mapgen_params)
+               return false;
+
+       if (!fs::CreateAllDirs(fs::RemoveLastPathComponent(m_map_meta_path))) {
+               errorstream << "saveMapMeta: could not create dirs to "
+                       << m_map_meta_path;
+               return false;
+       }
+
+       std::ostringstream oss(std::ios_base::binary);
+       Settings conf;
+
+       mapgen_params->MapgenParams::writeParams(&conf);
+       mapgen_params->writeParams(&conf);
+       conf.writeLines(oss);
+
+       // NOTE: If there are ever types of map settings other than
+       // those relating to map generation, save them here
+
+       oss << "[end_of_params]\n";
+
+       if (!fs::safeWriteToFile(m_map_meta_path, oss.str())) {
+               errorstream << "saveMapMeta: could not write "
+                       << m_map_meta_path << std::endl;
+               return false;
+       }
+
+       return true;
+}
+
+
+MapgenParams *MapSettingsManager::makeMapgenParams()
+{
+       if (mapgen_params)
+               return mapgen_params;
+
+       assert(m_user_settings != NULL);
+       assert(m_map_settings != NULL);
+
+       // At this point, we have (in order of precedence):
+       // 1). m_mapgen_settings->m_settings containing map_meta.txt settings or
+       //     explicit overrides from scripts
+       // 2). m_mapgen_settings->m_defaults containing script-set mgparams without
+       //     overrides
+       // 3). g_settings->m_settings containing all user-specified config file
+       //     settings
+       // 4). g_settings->m_defaults containing any low-priority settings from
+       //     scripts, e.g. mods using Lua as an enhanced config file)
+
+       // Now, get the mapgen type so we can create the appropriate MapgenParams
+       std::string mg_name;
+       MapgenType mgtype = getMapSetting("mg_name", &mg_name) ?
+               Mapgen::getMapgenType(mg_name) : MAPGEN_DEFAULT;
+       if (mgtype == MAPGEN_INVALID) {
+               errorstream << "EmergeManager: mapgen '" << mg_name <<
+                       "' not valid; falling back to " <<
+                       Mapgen::getMapgenName(MAPGEN_DEFAULT) << std::endl;
+               mgtype = MAPGEN_DEFAULT;
+       }
+
+       // Create our MapgenParams
+       MapgenParams *params = Mapgen::createMapgenParams(mgtype);
+       if (params == NULL)
+               return NULL;
+
+       params->mgtype = mgtype;
+
+       // Load the rest of the mapgen params from our active settings
+       params->MapgenParams::readParams(m_user_settings);
+       params->MapgenParams::readParams(m_map_settings);
+       params->readParams(m_user_settings);
+       params->readParams(m_map_settings);
+
+       // Hold onto our params
+       mapgen_params = params;
+
+       return params;
+}
diff --git a/src/map_settings_manager.h b/src/map_settings_manager.h
new file mode 100644 (file)
index 0000000..9f766f1
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+Minetest
+Copyright (C) 2010-2013 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef MAP_SETTINGS_MANAGER_HEADER
+#define MAP_SETTINGS_MANAGER_HEADER
+
+#include <string>
+
+class Settings;
+struct NoiseParams;
+struct MapgenParams;
+
+/*
+       MapSettingsManager is a centralized object for management (creating,
+       loading, storing, saving, etc.) of config settings related to the Map.
+
+       It has two phases: the initial r/w "gather and modify settings" state, and
+       the final r/o "read and save settings" state.
+
+       The typical use case is, in order, as follows:
+       - Create a MapSettingsManager object
+       - Try to load map metadata into it from the metadata file
+       - Manually view and modify the current configuration as desired through a
+         Settings-like interface
+       - When all modifications are finished, create a 'Parameters' object
+         containing the finalized, active parameters.  This could be passed along
+         to whichever Map-related objects that may require it.
+       - Save these active settings to the metadata file when requested
+*/
+class MapSettingsManager {
+public:
+       // Finalized map generation parameters
+       MapgenParams *mapgen_params;
+
+       MapSettingsManager(Settings *user_settings,
+               const std::string &map_meta_path);
+       ~MapSettingsManager();
+
+       bool getMapSetting(const std::string &name, std::string *value_out);
+
+       bool getMapSettingNoiseParams(
+               const std::string &name, NoiseParams *value_out);
+
+       // Note: Map config becomes read-only after makeMapgenParams() gets called
+       // (i.e. mapgen_params is non-NULL).  Attempts to set map config after
+       // params have been finalized will result in failure.
+       bool setMapSetting(const std::string &name,
+               const std::string &value, bool override_meta = false);
+
+       bool setMapSettingNoiseParams(const std::string &name,
+               const NoiseParams *value, bool override_meta = false);
+
+       bool loadMapMeta();
+       bool saveMapMeta();
+       MapgenParams *makeMapgenParams();
+
+private:
+       std::string m_map_meta_path;
+       Settings *m_map_settings;
+       Settings *m_user_settings;
+};
+
+#endif
index e45233b33199b9ec38aca193c5591540d6d011ea..b6fda91ac0920c932365ba206e10357fc2a33bfd 100644 (file)
@@ -176,26 +176,26 @@ Mapgen *Mapgen::createMapgen(MapgenType mgtype, int mgid,
 {
        switch (mgtype) {
        case MAPGEN_FLAT:
-               return new MapgenFlat(mgid, params, emerge);
+               return new MapgenFlat(mgid, (MapgenFlatParams *)params, emerge);
        case MAPGEN_FRACTAL:
-               return new MapgenFractal(mgid, params, emerge);
+               return new MapgenFractal(mgid, (MapgenFractalParams *)params, emerge);
        case MAPGEN_SINGLENODE:
-               return new MapgenSinglenode(mgid, params, emerge);
+               return new MapgenSinglenode(mgid, (MapgenSinglenodeParams *)params, emerge);
        case MAPGEN_V5:
-               return new MapgenV5(mgid, params, emerge);
+               return new MapgenV5(mgid, (MapgenV5Params *)params, emerge);
        case MAPGEN_V6:
-               return new MapgenV6(mgid, params, emerge);
+               return new MapgenV6(mgid, (MapgenV6Params *)params, emerge);
        case MAPGEN_V7:
-               return new MapgenV7(mgid, params, emerge);
+               return new MapgenV7(mgid, (MapgenV7Params *)params, emerge);
        case MAPGEN_VALLEYS:
-               return new MapgenValleys(mgid, params, emerge);
+               return new MapgenValleys(mgid, (MapgenValleysParams *)params, emerge);
        default:
                return NULL;
        }
 }
 
 
-MapgenSpecificParams *Mapgen::createMapgenParams(MapgenType mgtype)
+MapgenParams *Mapgen::createMapgenParams(MapgenType mgtype)
 {
        switch (mgtype) {
        case MAPGEN_FLAT:
@@ -970,52 +970,46 @@ void GenerateNotifier::getEvents(
 MapgenParams::~MapgenParams()
 {
        delete bparams;
-       delete sparams;
 }
 
 
-void MapgenParams::load(const Settings &settings)
+void MapgenParams::readParams(const Settings *settings)
 {
        std::string seed_str;
-       const char *seed_name = (&settings == g_settings) ? "fixed_map_seed" : "seed";
+       const char *seed_name = (settings == g_settings) ? "fixed_map_seed" : "seed";
 
-       if (settings.getNoEx(seed_name, seed_str) && !seed_str.empty())
-               seed = read_seed(seed_str.c_str());
-       else
-               myrand_bytes(&seed, sizeof(seed));
+       if (settings->getNoEx(seed_name, seed_str)) {
+               if (!seed_str.empty())
+                       seed = read_seed(seed_str.c_str());
+               else
+                       myrand_bytes(&seed, sizeof(seed));
+       }
+
+       std::string mg_name;
+       if (settings->getNoEx("mg_name", mg_name))
+               this->mgtype = Mapgen::getMapgenType(mg_name);
 
-       settings.getNoEx("mg_name", mg_name);
-       settings.getS16NoEx("water_level", water_level);
-       settings.getS16NoEx("chunksize", chunksize);
-       settings.getFlagStrNoEx("mg_flags", flags, flagdesc_mapgen);
+       settings->getS16NoEx("water_level", water_level);
+       settings->getS16NoEx("chunksize", chunksize);
+       settings->getFlagStrNoEx("mg_flags", flags, flagdesc_mapgen);
 
        delete bparams;
        bparams = BiomeManager::createBiomeParams(BIOMEGEN_ORIGINAL);
        if (bparams) {
-               bparams->readParams(&settings);
+               bparams->readParams(settings);
                bparams->seed = seed;
        }
-
-       delete sparams;
-       MapgenType mgtype = Mapgen::getMapgenType(mg_name);
-       if (mgtype != MAPGEN_INVALID) {
-               sparams = Mapgen::createMapgenParams(mgtype);
-               sparams->readParams(&settings);
-       }
 }
 
 
-void MapgenParams::save(Settings &settings) const
+void MapgenParams::writeParams(Settings *settings) const
 {
-       settings.set("mg_name", mg_name);
-       settings.setU64("seed", seed);
-       settings.setS16("water_level", water_level);
-       settings.setS16("chunksize", chunksize);
-       settings.setFlagStr("mg_flags", flags, flagdesc_mapgen, U32_MAX);
+       settings->set("mg_name", Mapgen::getMapgenName(mgtype));
+       settings->setU64("seed", seed);
+       settings->setS16("water_level", water_level);
+       settings->setS16("chunksize", chunksize);
+       settings->setFlagStr("mg_flags", flags, flagdesc_mapgen, U32_MAX);
 
        if (bparams)
-               bparams->writeParams(&settings);
-
-       if (sparams)
-               sparams->writeParams(&settings);
+               bparams->writeParams(settings);
 }
index 618a2f6b8996adbc2965f0634856320faa16b90c..5fcf2a36548085d9d7809e89b27a872b4a9fc38d 100644 (file)
@@ -119,37 +119,29 @@ enum MapgenType {
        MAPGEN_INVALID,
 };
 
-struct MapgenSpecificParams {
-       virtual void readParams(const Settings *settings) = 0;
-       virtual void writeParams(Settings *settings) const = 0;
-       virtual ~MapgenSpecificParams() {}
-};
-
 struct MapgenParams {
-       std::string mg_name;
+       MapgenType mgtype;
        s16 chunksize;
        u64 seed;
        s16 water_level;
        u32 flags;
 
        BiomeParams *bparams;
-       MapgenSpecificParams *sparams;
 
        MapgenParams() :
-               mg_name(MAPGEN_DEFAULT_NAME),
+               mgtype(MAPGEN_DEFAULT),
                chunksize(5),
                seed(0),
                water_level(1),
                flags(MG_CAVES | MG_LIGHT | MG_DECORATIONS),
-               bparams(NULL),
-               sparams(NULL)
+               bparams(NULL)
        {
        }
 
        virtual ~MapgenParams();
 
-       void load(const Settings &settings);
-       void save(Settings &settings) const;
+       virtual void readParams(const Settings *settings);
+       virtual void writeParams(Settings *settings) const;
 };
 
 
@@ -217,7 +209,7 @@ public:
        static const char *getMapgenName(MapgenType mgtype);
        static Mapgen *createMapgen(MapgenType mgtype, int mgid,
                MapgenParams *params, EmergeManager *emerge);
-       static MapgenSpecificParams *createMapgenParams(MapgenType mgtype);
+       static MapgenParams *createMapgenParams(MapgenType mgtype);
        static void getMapgenNames(std::vector<const char *> *mgnames, bool include_hidden);
 
 private:
index 956af999a39fae3a10f722a4fe4ea022ba2e799c..2c1715e61ba06134b61e38dcf6f3c7dd6abebe3d 100644 (file)
@@ -49,26 +49,24 @@ FlagDesc flagdesc_mapgen_flat[] = {
 ///////////////////////////////////////////////////////////////////////////////////////
 
 
-MapgenFlat::MapgenFlat(int mapgenid, MapgenParams *params, EmergeManager *emerge)
+MapgenFlat::MapgenFlat(int mapgenid, MapgenFlatParams *params, EmergeManager *emerge)
        : MapgenBasic(mapgenid, params, emerge)
 {
-       MapgenFlatParams *sp = (MapgenFlatParams *)params->sparams;
-
-       this->spflags          = sp->spflags;
-       this->ground_level     = sp->ground_level;
-       this->large_cave_depth = sp->large_cave_depth;
-       this->cave_width       = sp->cave_width;
-       this->lake_threshold   = sp->lake_threshold;
-       this->lake_steepness   = sp->lake_steepness;
-       this->hill_threshold   = sp->hill_threshold;
-       this->hill_steepness   = sp->hill_steepness;
+       this->spflags          = params->spflags;
+       this->ground_level     = params->ground_level;
+       this->large_cave_depth = params->large_cave_depth;
+       this->cave_width       = params->cave_width;
+       this->lake_threshold   = params->lake_threshold;
+       this->lake_steepness   = params->lake_steepness;
+       this->hill_threshold   = params->hill_threshold;
+       this->hill_steepness   = params->hill_steepness;
 
        //// 2D noise
-       noise_terrain      = new Noise(&sp->np_terrain,      seed, csize.X, csize.Z);
-       noise_filler_depth = new Noise(&sp->np_filler_depth, seed, csize.X, csize.Z);
+       noise_terrain      = new Noise(&params->np_terrain,      seed, csize.X, csize.Z);
+       noise_filler_depth = new Noise(&params->np_filler_depth, seed, csize.X, csize.Z);
 
-       MapgenBasic::np_cave1 = sp->np_cave1;
-       MapgenBasic::np_cave2 = sp->np_cave2;
+       MapgenBasic::np_cave1 = params->np_cave1;
+       MapgenBasic::np_cave2 = params->np_cave2;
 }
 
 
index 39b6dc30272c2da368c5c47bf5d82a58039692fe..8b3de2bcffa0b9bb394b3b6c8bb330243e079372 100644 (file)
@@ -32,7 +32,7 @@ class BiomeManager;
 extern FlagDesc flagdesc_mapgen_flat[];
 
 
-struct MapgenFlatParams : public MapgenSpecificParams {
+struct MapgenFlatParams : public MapgenParams {
        u32 spflags;
        s16 ground_level;
        s16 large_cave_depth;
@@ -55,7 +55,7 @@ struct MapgenFlatParams : public MapgenSpecificParams {
 
 class MapgenFlat : public MapgenBasic {
 public:
-       MapgenFlat(int mapgenid, MapgenParams *params, EmergeManager *emerge);
+       MapgenFlat(int mapgenid, MapgenFlatParams *params, EmergeManager *emerge);
        ~MapgenFlat();
 
        virtual MapgenType getType() const { return MAPGEN_FLAT; }
index 9e4c210dc16b753872f37b41a48cab1205b947ca..0951a0afa2fc198e341e026368c041bc8b08ec8f 100644 (file)
@@ -47,29 +47,27 @@ FlagDesc flagdesc_mapgen_fractal[] = {
 ///////////////////////////////////////////////////////////////////////////////////////
 
 
-MapgenFractal::MapgenFractal(int mapgenid, MapgenParams *params, EmergeManager *emerge)
+MapgenFractal::MapgenFractal(int mapgenid, MapgenFractalParams *params, EmergeManager *emerge)
        : MapgenBasic(mapgenid, params, emerge)
 {
-       MapgenFractalParams *sp = (MapgenFractalParams *)params->sparams;
-
-       this->spflags    = sp->spflags;
-       this->cave_width = sp->cave_width;
-       this->fractal    = sp->fractal;
-       this->iterations = sp->iterations;
-       this->scale      = sp->scale;
-       this->offset     = sp->offset;
-       this->slice_w    = sp->slice_w;
-       this->julia_x    = sp->julia_x;
-       this->julia_y    = sp->julia_y;
-       this->julia_z    = sp->julia_z;
-       this->julia_w    = sp->julia_w;
+       this->spflags    = params->spflags;
+       this->cave_width = params->cave_width;
+       this->fractal    = params->fractal;
+       this->iterations = params->iterations;
+       this->scale      = params->scale;
+       this->offset     = params->offset;
+       this->slice_w    = params->slice_w;
+       this->julia_x    = params->julia_x;
+       this->julia_y    = params->julia_y;
+       this->julia_z    = params->julia_z;
+       this->julia_w    = params->julia_w;
 
        //// 2D terrain noise
-       noise_seabed       = new Noise(&sp->np_seabed, seed, csize.X, csize.Z);
-       noise_filler_depth = new Noise(&sp->np_filler_depth, seed, csize.X, csize.Z);
+       noise_seabed       = new Noise(&params->np_seabed, seed, csize.X, csize.Z);
+       noise_filler_depth = new Noise(&params->np_filler_depth, seed, csize.X, csize.Z);
 
-       MapgenBasic::np_cave1 = sp->np_cave1;
-       MapgenBasic::np_cave2 = sp->np_cave2;
+       MapgenBasic::np_cave1 = params->np_cave1;
+       MapgenBasic::np_cave2 = params->np_cave2;
 
        this->formula = fractal / 2 + fractal % 2;
        this->julia   = fractal % 2 == 0;
index cbd5567c4b4ce65c561ce70b915eb54d3d26cca7..3331848bcfeb08a9b76278d687c76231b5767145 100644 (file)
@@ -33,7 +33,7 @@ class BiomeManager;
 extern FlagDesc flagdesc_mapgen_fractal[];
 
 
-struct MapgenFractalParams : public MapgenSpecificParams {
+struct MapgenFractalParams : public MapgenParams {
        u32 spflags;
        float cave_width;
        u16 fractal;
@@ -59,7 +59,7 @@ struct MapgenFractalParams : public MapgenSpecificParams {
 
 class MapgenFractal : public MapgenBasic {
 public:
-       MapgenFractal(int mapgenid, MapgenParams *params, EmergeManager *emerge);
+       MapgenFractal(int mapgenid, MapgenFractalParams *params, EmergeManager *emerge);
        ~MapgenFractal();
 
        virtual MapgenType getType() const { return MAPGEN_FRACTAL; }
index 58672a0ede4dfeeb24b5c300f1169f3e7361c9b2..07520134d31ee828e899c614384cb36ec147644a 100644 (file)
@@ -22,7 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 #include "mapgen.h"
 
-struct MapgenSinglenodeParams : public MapgenSpecificParams {
+struct MapgenSinglenodeParams : public MapgenParams {
        MapgenSinglenodeParams() {}
        ~MapgenSinglenodeParams() {}
 
index 74d5e1ee3297045821f89e04a5632b11463cbb59..9f189e25399b58f161992293ee15f9acee0dd8aa 100644 (file)
@@ -45,25 +45,23 @@ FlagDesc flagdesc_mapgen_v5[] = {
 };
 
 
-MapgenV5::MapgenV5(int mapgenid, MapgenParams *params, EmergeManager *emerge)
+MapgenV5::MapgenV5(int mapgenid, MapgenV5Params *params, EmergeManager *emerge)
        : MapgenBasic(mapgenid, params, emerge)
 {
-       MapgenV5Params *sp = (MapgenV5Params *)params->sparams;
-
-       this->spflags    = sp->spflags;
-       this->cave_width = sp->cave_width;
+       this->spflags    = params->spflags;
+       this->cave_width = params->cave_width;
 
        // Terrain noise
-       noise_filler_depth = new Noise(&sp->np_filler_depth, seed, csize.X, csize.Z);
-       noise_factor       = new Noise(&sp->np_factor,       seed, csize.X, csize.Z);
-       noise_height       = new Noise(&sp->np_height,       seed, csize.X, csize.Z);
+       noise_filler_depth = new Noise(&params->np_filler_depth, seed, csize.X, csize.Z);
+       noise_factor       = new Noise(&params->np_factor,       seed, csize.X, csize.Z);
+       noise_height       = new Noise(&params->np_height,       seed, csize.X, csize.Z);
 
        // 3D terrain noise
        // 1-up 1-down overgeneration
-       noise_ground = new Noise(&sp->np_ground, seed, csize.X, csize.Y + 2, csize.Z);
+       noise_ground = new Noise(&params->np_ground, seed, csize.X, csize.Y + 2, csize.Z);
 
-       MapgenBasic::np_cave1 = sp->np_cave1;
-       MapgenBasic::np_cave2 = sp->np_cave2;
+       MapgenBasic::np_cave1 = params->np_cave1;
+       MapgenBasic::np_cave2 = params->np_cave2;
 }
 
 
index 5f6b1038375424afd36cb95b1beb1c29b7008979..ddb090a9c4a06af16bd3ace7d5e93de82bb9045f 100644 (file)
@@ -30,7 +30,7 @@ class BiomeManager;
 extern FlagDesc flagdesc_mapgen_v5[];
 
 
-struct MapgenV5Params : public MapgenSpecificParams {
+struct MapgenV5Params : public MapgenParams {
        u32 spflags;
        float cave_width;
        NoiseParams np_filler_depth;
@@ -50,7 +50,7 @@ struct MapgenV5Params : public MapgenSpecificParams {
 
 class MapgenV5 : public MapgenBasic {
 public:
-       MapgenV5(int mapgenid, MapgenParams *params, EmergeManager *emerge);
+       MapgenV5(int mapgenid, MapgenV5Params *params, EmergeManager *emerge);
        ~MapgenV5();
 
        virtual MapgenType getType() const { return MAPGEN_V5; }
index caa64827ecb64d685fa966ac48972c85df870575..e4444963f650c393f0b46f8bfeab5924d126b68a 100644 (file)
@@ -53,7 +53,7 @@ FlagDesc flagdesc_mapgen_v6[] = {
 /////////////////////////////////////////////////////////////////////////////
 
 
-MapgenV6::MapgenV6(int mapgenid, MapgenParams *params, EmergeManager *emerge)
+MapgenV6::MapgenV6(int mapgenid, MapgenV6Params *params, EmergeManager *emerge)
        : Mapgen(mapgenid, params, emerge)
 {
        this->m_emerge = emerge;
@@ -61,26 +61,25 @@ MapgenV6::MapgenV6(int mapgenid, MapgenParams *params, EmergeManager *emerge)
 
        this->heightmap = new s16[csize.X * csize.Z];
 
-       MapgenV6Params *sp = (MapgenV6Params *)params->sparams;
-       this->spflags     = sp->spflags;
-       this->freq_desert = sp->freq_desert;
-       this->freq_beach  = sp->freq_beach;
+       this->spflags     = params->spflags;
+       this->freq_desert = params->freq_desert;
+       this->freq_beach  = params->freq_beach;
 
-       np_cave        = &sp->np_cave;
-       np_humidity    = &sp->np_humidity;
-       np_trees       = &sp->np_trees;
-       np_apple_trees = &sp->np_apple_trees;
+       np_cave        = &params->np_cave;
+       np_humidity    = &params->np_humidity;
+       np_trees       = &params->np_trees;
+       np_apple_trees = &params->np_apple_trees;
 
        //// Create noise objects
-       noise_terrain_base   = new Noise(&sp->np_terrain_base,   seed, csize.X, csize.Y);
-       noise_terrain_higher = new Noise(&sp->np_terrain_higher, seed, csize.X, csize.Y);
-       noise_steepness      = new Noise(&sp->np_steepness,      seed, csize.X, csize.Y);
-       noise_height_select  = new Noise(&sp->np_height_select,  seed, csize.X, csize.Y);
-       noise_mud            = new Noise(&sp->np_mud,            seed, csize.X, csize.Y);
-       noise_beach          = new Noise(&sp->np_beach,          seed, csize.X, csize.Y);
-       noise_biome          = new Noise(&sp->np_biome,          seed,
+       noise_terrain_base   = new Noise(&params->np_terrain_base,   seed, csize.X, csize.Y);
+       noise_terrain_higher = new Noise(&params->np_terrain_higher, seed, csize.X, csize.Y);
+       noise_steepness      = new Noise(&params->np_steepness,      seed, csize.X, csize.Y);
+       noise_height_select  = new Noise(&params->np_height_select,  seed, csize.X, csize.Y);
+       noise_mud            = new Noise(&params->np_mud,            seed, csize.X, csize.Y);
+       noise_beach          = new Noise(&params->np_beach,          seed, csize.X, csize.Y);
+       noise_biome          = new Noise(&params->np_biome,          seed,
                        csize.X + 2 * MAP_BLOCKSIZE, csize.Y + 2 * MAP_BLOCKSIZE);
-       noise_humidity       = new Noise(&sp->np_humidity,       seed,
+       noise_humidity       = new Noise(&params->np_humidity,       seed,
                        csize.X + 2 * MAP_BLOCKSIZE, csize.Y + 2 * MAP_BLOCKSIZE);
 
        //// Resolve nodes to be used
index 20b0bf92ecc6a89af65ec3f4905c51f8ec95f98c..f018ffaca182bb35fe76e091793e55f677c3adad 100644 (file)
@@ -53,7 +53,7 @@ enum BiomeV6Type
 };
 
 
-struct MapgenV6Params : public MapgenSpecificParams {
+struct MapgenV6Params : public MapgenParams {
        u32 spflags;
        float freq_desert;
        float freq_beach;
@@ -124,7 +124,7 @@ public:
        content_t c_mossycobble;
        content_t c_stair_cobble;
 
-       MapgenV6(int mapgenid, MapgenParams *params, EmergeManager *emerge);
+       MapgenV6(int mapgenid, MapgenV6Params *params, EmergeManager *emerge);
        ~MapgenV6();
 
        virtual MapgenType getType() const { return MAPGEN_V6; }
index c24b3e8d1318b6e124b4d3d0a4f66b732f318c17..d14fdb97a5f0ea56eac2d83164ec2d06147f8b9f 100644 (file)
@@ -50,30 +50,28 @@ FlagDesc flagdesc_mapgen_v7[] = {
 ///////////////////////////////////////////////////////////////////////////////
 
 
-MapgenV7::MapgenV7(int mapgenid, MapgenParams *params, EmergeManager *emerge)
+MapgenV7::MapgenV7(int mapgenid, MapgenV7Params *params, EmergeManager *emerge)
        : MapgenBasic(mapgenid, params, emerge)
 {
-       MapgenV7Params *sp = (MapgenV7Params *)params->sparams;
-
-       this->spflags    = sp->spflags;
-       this->cave_width = sp->cave_width;
+       this->spflags    = params->spflags;
+       this->cave_width = params->cave_width;
 
        //// Terrain noise
-       noise_terrain_base    = new Noise(&sp->np_terrain_base,    seed, csize.X, csize.Z);
-       noise_terrain_alt     = new Noise(&sp->np_terrain_alt,     seed, csize.X, csize.Z);
-       noise_terrain_persist = new Noise(&sp->np_terrain_persist, seed, csize.X, csize.Z);
-       noise_height_select   = new Noise(&sp->np_height_select,   seed, csize.X, csize.Z);
-       noise_filler_depth    = new Noise(&sp->np_filler_depth,    seed, csize.X, csize.Z);
-       noise_mount_height    = new Noise(&sp->np_mount_height,    seed, csize.X, csize.Z);
-       noise_ridge_uwater    = new Noise(&sp->np_ridge_uwater,    seed, csize.X, csize.Z);
+       noise_terrain_base    = new Noise(&params->np_terrain_base,    seed, csize.X, csize.Z);
+       noise_terrain_alt     = new Noise(&params->np_terrain_alt,     seed, csize.X, csize.Z);
+       noise_terrain_persist = new Noise(&params->np_terrain_persist, seed, csize.X, csize.Z);
+       noise_height_select   = new Noise(&params->np_height_select,   seed, csize.X, csize.Z);
+       noise_filler_depth    = new Noise(&params->np_filler_depth,    seed, csize.X, csize.Z);
+       noise_mount_height    = new Noise(&params->np_mount_height,    seed, csize.X, csize.Z);
+       noise_ridge_uwater    = new Noise(&params->np_ridge_uwater,    seed, csize.X, csize.Z);
 
        //// 3d terrain noise
        // 1-up 1-down overgeneration
-       noise_mountain = new Noise(&sp->np_mountain, seed, csize.X, csize.Y + 2, csize.Z);
-       noise_ridge    = new Noise(&sp->np_ridge,    seed, csize.X, csize.Y + 2, csize.Z);
+       noise_mountain = new Noise(&params->np_mountain, seed, csize.X, csize.Y + 2, csize.Z);
+       noise_ridge    = new Noise(&params->np_ridge,    seed, csize.X, csize.Y + 2, csize.Z);
 
-       MapgenBasic::np_cave1 = sp->np_cave1;
-       MapgenBasic::np_cave2 = sp->np_cave2;
+       MapgenBasic::np_cave1 = params->np_cave1;
+       MapgenBasic::np_cave2 = params->np_cave2;
 }
 
 
index c75f18a93b5c251d4a28ca697a35e12164bdfd77..3a6bc0801c86238a9bb7cab7d4ff08bcafb6b350 100644 (file)
@@ -32,7 +32,7 @@ class BiomeManager;
 extern FlagDesc flagdesc_mapgen_v7[];
 
 
-struct MapgenV7Params : public MapgenSpecificParams {
+struct MapgenV7Params : public MapgenParams {
        u32 spflags;
        float cave_width;
        NoiseParams np_terrain_base;
@@ -56,7 +56,7 @@ struct MapgenV7Params : public MapgenSpecificParams {
 
 class MapgenV7 : public MapgenBasic {
 public:
-       MapgenV7(int mapgenid, MapgenParams *params, EmergeManager *emerge);
+       MapgenV7(int mapgenid, MapgenV7Params *params, EmergeManager *emerge);
        ~MapgenV7();
 
        virtual MapgenType getType() const { return MAPGEN_V7; }
index 02a8fbfe02c4c0bd3ce1f75fb3ff942bde415cf7..a61f1b329930ae2f0a67f279e41aeedaa7b0d3d3 100644 (file)
@@ -64,7 +64,7 @@ static FlagDesc flagdesc_mapgen_valleys[] = {
 ///////////////////////////////////////////////////////////////////////////////
 
 
-MapgenValleys::MapgenValleys(int mapgenid, MapgenParams *params, EmergeManager *emerge)
+MapgenValleys::MapgenValleys(int mapgenid, MapgenValleysParams *params, EmergeManager *emerge)
        : MapgenBasic(mapgenid, params, emerge)
 {
        // NOTE: MapgenValleys has a hard dependency on BiomeGenOriginal
@@ -73,34 +73,33 @@ MapgenValleys::MapgenValleys(int mapgenid, MapgenParams *params, EmergeManager *
        this->map_gen_limit = MYMIN(MAX_MAP_GENERATION_LIMIT,
                        g_settings->getU16("map_generation_limit"));
 
-       MapgenValleysParams *sp = (MapgenValleysParams *)params->sparams;
        BiomeParamsOriginal *bp = (BiomeParamsOriginal *)params->bparams;
 
-       this->spflags            = sp->spflags;
-       this->altitude_chill     = sp->altitude_chill;
-       this->large_cave_depth   = sp->large_cave_depth;
-       this->lava_features_lim  = rangelim(sp->lava_features, 0, 10);
-       this->massive_cave_depth = sp->massive_cave_depth;
-       this->river_depth_bed    = sp->river_depth + 1.f;
-       this->river_size_factor  = sp->river_size / 100.f;
-       this->water_features_lim = rangelim(sp->water_features, 0, 10);
-       this->cave_width         = sp->cave_width;
+       this->spflags            = params->spflags;
+       this->altitude_chill     = params->altitude_chill;
+       this->large_cave_depth   = params->large_cave_depth;
+       this->lava_features_lim  = rangelim(params->lava_features, 0, 10);
+       this->massive_cave_depth = params->massive_cave_depth;
+       this->river_depth_bed    = params->river_depth + 1.f;
+       this->river_size_factor  = params->river_size / 100.f;
+       this->water_features_lim = rangelim(params->water_features, 0, 10);
+       this->cave_width         = params->cave_width;
 
        //// 2D Terrain noise
-       noise_filler_depth       = new Noise(&sp->np_filler_depth,       seed, csize.X, csize.Z);
-       noise_inter_valley_slope = new Noise(&sp->np_inter_valley_slope, seed, csize.X, csize.Z);
-       noise_rivers             = new Noise(&sp->np_rivers,             seed, csize.X, csize.Z);
-       noise_terrain_height     = new Noise(&sp->np_terrain_height,     seed, csize.X, csize.Z);
-       noise_valley_depth       = new Noise(&sp->np_valley_depth,       seed, csize.X, csize.Z);
-       noise_valley_profile     = new Noise(&sp->np_valley_profile,     seed, csize.X, csize.Z);
+       noise_filler_depth       = new Noise(&params->np_filler_depth,       seed, csize.X, csize.Z);
+       noise_inter_valley_slope = new Noise(&params->np_inter_valley_slope, seed, csize.X, csize.Z);
+       noise_rivers             = new Noise(&params->np_rivers,             seed, csize.X, csize.Z);
+       noise_terrain_height     = new Noise(&params->np_terrain_height,     seed, csize.X, csize.Z);
+       noise_valley_depth       = new Noise(&params->np_valley_depth,       seed, csize.X, csize.Z);
+       noise_valley_profile     = new Noise(&params->np_valley_profile,     seed, csize.X, csize.Z);
 
        //// 3D Terrain noise
        // 1-up 1-down overgeneration
-       noise_inter_valley_fill = new Noise(&sp->np_inter_valley_fill, seed, csize.X, csize.Y + 2, csize.Z);
+       noise_inter_valley_fill = new Noise(&params->np_inter_valley_fill, seed, csize.X, csize.Y + 2, csize.Z);
        // 1-down overgeneraion
-       noise_cave1             = new Noise(&sp->np_cave1,             seed, csize.X, csize.Y + 1, csize.Z);
-       noise_cave2             = new Noise(&sp->np_cave2,             seed, csize.X, csize.Y + 1, csize.Z);
-       noise_massive_caves     = new Noise(&sp->np_massive_caves,     seed, csize.X, csize.Y + 1, csize.Z);
+       noise_cave1             = new Noise(&params->np_cave1,             seed, csize.X, csize.Y + 1, csize.Z);
+       noise_cave2             = new Noise(&params->np_cave2,             seed, csize.X, csize.Y + 1, csize.Z);
+       noise_massive_caves     = new Noise(&params->np_massive_caves,     seed, csize.X, csize.Y + 1, csize.Z);
 
        this->humid_rivers       = (spflags & MGVALLEYS_HUMID_RIVERS);
        this->use_altitude_chill = (spflags & MGVALLEYS_ALT_CHILL);
index 00f6aff0765f2ad78066e32a63730a8dd5534a9d..6dd7ebc47e01ba45b4371d4e51ef23b6633f5be3 100644 (file)
@@ -46,7 +46,7 @@ class BiomeGenOriginal;
 //extern Profiler *mapgen_profiler;
 
 
-struct MapgenValleysParams : public MapgenSpecificParams {
+struct MapgenValleysParams : public MapgenParams {
        u32 spflags;
        s16 large_cave_depth;
        s16 massive_cave_depth;
@@ -88,7 +88,7 @@ struct TerrainNoise {
 class MapgenValleys : public MapgenBasic {
 public:
 
-       MapgenValleys(int mapgenid, MapgenParams *params, EmergeManager *emerge);
+       MapgenValleys(int mapgenid, MapgenValleysParams *params, EmergeManager *emerge);
        ~MapgenValleys();
 
        virtual MapgenType getType() const { return MAPGEN_VALLEYS; }
index dc188f8a4a2cc3db9207aea81aff1f1fb5152d9f..9f14838ce4b4ac6c56fe1d92ef1a509a444013c2 100644 (file)
@@ -600,24 +600,37 @@ int ModApiMapgen::l_get_mapgen_params(lua_State *L)
 {
        NO_MAP_LOCK_REQUIRED;
 
-       MapgenParams *params = &getServer(L)->getEmergeManager()->params;
+       log_deprecated(L, "get_mapgen_params is deprecated; "
+               "use get_mapgen_setting instead");
+
+       std::string value;
+
+       MapSettingsManager *settingsmgr =
+               getServer(L)->getEmergeManager()->map_settings_mgr;
 
        lua_newtable(L);
 
-       lua_pushstring(L, params->mg_name.c_str());
+       settingsmgr->getMapSetting("mg_name", &value);
+       lua_pushstring(L, value.c_str());
        lua_setfield(L, -2, "mgname");
 
-       lua_pushinteger(L, params->seed);
+       settingsmgr->getMapSetting("seed", &value);
+       std::istringstream ss(value);
+       u64 seed;
+       ss >> seed;
+       lua_pushinteger(L, seed);
        lua_setfield(L, -2, "seed");
 
-       lua_pushinteger(L, params->water_level);
+       settingsmgr->getMapSetting("water_level", &value);
+       lua_pushinteger(L, stoi(value, -32768, 32767));
        lua_setfield(L, -2, "water_level");
 
-       lua_pushinteger(L, params->chunksize);
+       settingsmgr->getMapSetting("chunksize", &value);
+       lua_pushinteger(L, stoi(value, -32768, 32767));
        lua_setfield(L, -2, "chunksize");
 
-       std::string flagstr = writeFlagString(params->flags, flagdesc_mapgen, U32_MAX);
-       lua_pushstring(L, flagstr.c_str());
+       settingsmgr->getMapSetting("mg_flags", &value);
+       lua_pushstring(L, value.c_str());
        lua_setfield(L, -2, "flags");
 
        return 1;
@@ -630,44 +643,120 @@ int ModApiMapgen::l_set_mapgen_params(lua_State *L)
 {
        NO_MAP_LOCK_REQUIRED;
 
+       log_deprecated(L, "set_mapgen_params is deprecated; "
+               "use set_mapgen_setting instead");
+
        if (!lua_istable(L, 1))
                return 0;
 
-       EmergeManager *emerge = getServer(L)->getEmergeManager();
-       if (emerge->isRunning())
-               throw LuaError("Cannot set parameters while mapgen is running");
-
-       MapgenParams *params = &emerge->params;
-       u32 flags = 0, flagmask = 0;
+       MapSettingsManager *settingsmgr =
+               getServer(L)->getEmergeManager()->map_settings_mgr;
 
        lua_getfield(L, 1, "mgname");
-       if (lua_isstring(L, -1)) {
-               params->mg_name = lua_tostring(L, -1);
-               delete params->sparams;
-               params->sparams = NULL;
-       }
+       if (lua_isstring(L, -1))
+               settingsmgr->setMapSetting("mg_name", lua_tostring(L, -1), true);
 
        lua_getfield(L, 1, "seed");
        if (lua_isnumber(L, -1))
-               params->seed = lua_tointeger(L, -1);
+               settingsmgr->setMapSetting("seed", lua_tostring(L, -1), true);
 
        lua_getfield(L, 1, "water_level");
        if (lua_isnumber(L, -1))
-               params->water_level = lua_tointeger(L, -1);
+               settingsmgr->setMapSetting("water_level", lua_tostring(L, -1), true);
 
        lua_getfield(L, 1, "chunksize");
        if (lua_isnumber(L, -1))
-               params->chunksize = lua_tointeger(L, -1);
+               settingsmgr->setMapSetting("chunksize", lua_tostring(L, -1), true);
 
        warn_if_field_exists(L, 1, "flagmask",
                "Deprecated: flags field now includes unset flags.");
-       lua_getfield(L, 1, "flagmask");
+
+       lua_getfield(L, 1, "flags");
        if (lua_isstring(L, -1))
-               params->flags &= ~readFlagString(lua_tostring(L, -1), flagdesc_mapgen, NULL);
+               settingsmgr->setMapSetting("mg_flags", lua_tostring(L, -1), true);
+
+       return 0;
+}
+
+// get_mapgen_setting(name)
+int ModApiMapgen::l_get_mapgen_setting(lua_State *L)
+{
+       NO_MAP_LOCK_REQUIRED;
 
-       if (getflagsfield(L, 1, "flags", flagdesc_mapgen, &flags, &flagmask)) {
-               params->flags &= ~flagmask;
-               params->flags |= flags;
+       std::string value;
+       MapSettingsManager *settingsmgr =
+               getServer(L)->getEmergeManager()->map_settings_mgr;
+
+       const char *name = luaL_checkstring(L, 1);
+       if (!settingsmgr->getMapSetting(name, &value))
+               return 0;
+
+       lua_pushstring(L, value.c_str());
+       return 1;
+}
+
+// get_mapgen_setting_noiseparams(name)
+int ModApiMapgen::l_get_mapgen_setting_noiseparams(lua_State *L)
+{
+       NO_MAP_LOCK_REQUIRED;
+
+       NoiseParams np;
+       MapSettingsManager *settingsmgr =
+               getServer(L)->getEmergeManager()->map_settings_mgr;
+
+       const char *name = luaL_checkstring(L, 1);
+       if (!settingsmgr->getMapSettingNoiseParams(name, &np))
+               return 0;
+
+       push_noiseparams(L, &np);
+       return 1;
+}
+
+// set_mapgen_setting(name, value, override_meta)
+// set mapgen config values
+int ModApiMapgen::l_set_mapgen_setting(lua_State *L)
+{
+       NO_MAP_LOCK_REQUIRED;
+
+       MapSettingsManager *settingsmgr =
+               getServer(L)->getEmergeManager()->map_settings_mgr;
+
+       const char *name   = luaL_checkstring(L, 1);
+       const char *value  = luaL_checkstring(L, 2);
+       bool override_meta = lua_isboolean(L, 3) ? lua_toboolean(L, 3) : false;
+
+       if (!settingsmgr->setMapSetting(name, value, override_meta)) {
+               errorstream << "set_mapgen_setting: cannot set '"
+                       << name << "' after initialization" << std::endl;
+       }
+
+       return 0;
+}
+
+
+// set_mapgen_setting_noiseparams(name, noiseparams, set_default)
+// set mapgen config values for noise parameters
+int ModApiMapgen::l_set_mapgen_setting_noiseparams(lua_State *L)
+{
+       NO_MAP_LOCK_REQUIRED;
+
+       MapSettingsManager *settingsmgr =
+               getServer(L)->getEmergeManager()->map_settings_mgr;
+
+       const char *name = luaL_checkstring(L, 1);
+
+       NoiseParams np;
+       if (!read_noiseparams(L, 2, &np)) {
+               errorstream << "set_mapgen_setting_noiseparams: cannot set '" << name
+                       << "'; invalid noiseparams table" << std::endl;
+               return 0;
+       }
+
+       bool override_meta = lua_isboolean(L, 3) ? lua_toboolean(L, 3) : false;
+
+       if (!settingsmgr->setMapSettingNoiseParams(name, &np, override_meta)) {
+               errorstream << "set_mapgen_setting_noiseparams: cannot set '"
+                       << name << "' after initialization" << std::endl;
        }
 
        return 0;
@@ -683,8 +772,11 @@ int ModApiMapgen::l_set_noiseparams(lua_State *L)
        const char *name = luaL_checkstring(L, 1);
 
        NoiseParams np;
-       if (!read_noiseparams(L, 2, &np))
+       if (!read_noiseparams(L, 2, &np)) {
+               errorstream << "set_noiseparams: cannot set '" << name
+                       << "'; invalid noiseparams table" << std::endl;
                return 0;
+       }
 
        bool set_default = lua_isboolean(L, 3) ? lua_toboolean(L, 3) : true;
 
@@ -1143,7 +1235,7 @@ int ModApiMapgen::l_generate_ores(lua_State *L)
        EmergeManager *emerge = getServer(L)->getEmergeManager();
 
        Mapgen mg;
-       mg.seed = emerge->params.seed;
+       mg.seed = emerge->mgparams->seed;
        mg.vm   = LuaVoxelManip::checkobject(L, 1)->vm;
        mg.ndef = getServer(L)->getNodeDefManager();
 
@@ -1169,7 +1261,7 @@ int ModApiMapgen::l_generate_decorations(lua_State *L)
        EmergeManager *emerge = getServer(L)->getEmergeManager();
 
        Mapgen mg;
-       mg.seed = emerge->params.seed;
+       mg.seed = emerge->mgparams->seed;
        mg.vm   = LuaVoxelManip::checkobject(L, 1)->vm;
        mg.ndef = getServer(L)->getNodeDefManager();
 
@@ -1393,6 +1485,10 @@ void ModApiMapgen::Initialize(lua_State *L, int top)
 
        API_FCT(get_mapgen_params);
        API_FCT(set_mapgen_params);
+       API_FCT(get_mapgen_setting);
+       API_FCT(set_mapgen_setting);
+       API_FCT(get_mapgen_setting_noiseparams);
+       API_FCT(set_mapgen_setting_noiseparams);
        API_FCT(set_noiseparams);
        API_FCT(get_noiseparams);
        API_FCT(set_gen_notify);
index 9751c0db6723d92b1c9ef13616a8326ae36716ce..bb94575c72feef5302d74a36beabe30bdfa1a2df 100644 (file)
@@ -40,6 +40,18 @@ private:
        // set mapgen parameters
        static int l_set_mapgen_params(lua_State *L);
 
+       // get_mapgen_setting(name)
+       static int l_get_mapgen_setting(lua_State *L);
+
+       // set_mapgen_setting(name, value, override_meta)
+       static int l_set_mapgen_setting(lua_State *L);
+
+       // get_mapgen_setting_noiseparams(name)
+       static int l_get_mapgen_setting_noiseparams(lua_State *L);
+
+       // set_mapgen_setting_noiseparams(name, value, override_meta)
+       static int l_set_mapgen_setting_noiseparams(lua_State *L);
+
        // set_noiseparam_defaults(name, noiseparams, set_default)
        static int l_set_noiseparams(lua_State *L);
 
index f138664087606208df7b3fed544f95d9902b6038..0d8123acd437eaea75b8e8c08398df5a5667fcef 100644 (file)
@@ -190,7 +190,7 @@ int LuaVoxelManip::l_calc_lighting(lua_State *L)
        Mapgen mg;
        mg.vm          = vm;
        mg.ndef        = ndef;
-       mg.water_level = emerge->params.water_level;
+       mg.water_level = emerge->mgparams->water_level;
 
        mg.calcLighting(pmin, pmax, fpmin, fpmax, propagate_shadow);
 
index f7f698d500eba882e3fab2e1198d3691f2e3d0a9..97a53f189e05e3c3c4f1c815b7f291f1c341dade 100644 (file)
@@ -266,9 +266,6 @@ Server::Server(
        //lock environment
        MutexAutoLock envlock(m_env_mutex);
 
-       // Load mapgen params from Settings
-       m_emerge->loadMapgenParams();
-
        // Create the Map (loads map_meta.txt, overriding configured mapgen params)
        ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
 
@@ -331,8 +328,11 @@ Server::Server(
 
        m_clients.setEnv(m_env);
 
+       if (!servermap->settings_mgr.makeMapgenParams())
+               FATAL_ERROR("Couldn't create any mapgen type");
+
        // Initialize mapgens
-       m_emerge->initMapgens();
+       m_emerge->initMapgens(servermap->getMapgenParams());
 
        m_enable_rollback_recording = g_settings->getBool("enable_rollback_recording");
        if (m_enable_rollback_recording) {
@@ -402,11 +402,8 @@ Server::~Server()
        m_emerge->stopThreads();
 
        // Delete things in the reverse order of creation
-       delete m_env;
-
-       // N.B. the EmergeManager should be deleted after the Environment since Map
-       // depends on EmergeManager to write its current params to the map meta
        delete m_emerge;
+       delete m_env;
        delete m_rollback;
        delete m_banmanager;
        delete m_event;
@@ -655,7 +652,7 @@ void Server::AsyncRunStep(bool initial_step)
                                        m_env->getGameTime(),
                                        m_lag,
                                        m_gamespec.id,
-                                       m_emerge->params.mg_name,
+                                       Mapgen::getMapgenName(m_emerge->mgparams->mgtype),
                                        m_mods);
                        counter = 0.01;
                }
index 7e9a0b368e3452f99821c7a39359c5b163086ea2..55bbd395447f198290d2db001d177cf16a148ec1 100644 (file)
@@ -313,8 +313,8 @@ bool loadGameConfAndInitWorld(const std::string &path, const SubgameSpec &gamesp
                Settings conf;
                MapgenParams params;
 
-               params.load(*g_settings);
-               params.save(conf);
+               params.readParams(g_settings);
+               params.writeParams(&conf);
                conf.writeLines(oss);
                oss << "[end_of_params]\n";
 
index a07ed8ba5ace062530eb72ff6125f013f6ee2369..34de99e12425b625ac160005cd583257faec8278 100644 (file)
@@ -6,6 +6,7 @@ set (UNITTEST_SRCS
        ${CMAKE_CURRENT_SOURCE_DIR}/test_connection.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/test_filepath.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/test_inventory.cpp
+       ${CMAKE_CURRENT_SOURCE_DIR}/test_map_settings_manager.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/test_mapnode.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/test_nodedef.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/test_noderesolver.cpp
diff --git a/src/unittest/test_map_settings_manager.cpp b/src/unittest/test_map_settings_manager.cpp
new file mode 100644 (file)
index 0000000..b2ad531
--- /dev/null
@@ -0,0 +1,255 @@
+ /*
+Minetest
+Copyright (C) 2010-2014 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "test.h"
+
+#include "noise.h"
+#include "settings.h"
+#include "mapgen_v5.h"
+#include "util/sha1.h"
+#include "map_settings_manager.h"
+
+class TestMapSettingsManager : public TestBase {
+public:
+       TestMapSettingsManager() { TestManager::registerTestModule(this); }
+       const char *getName() { return "TestMapSettingsManager"; }
+
+       void makeUserConfig(Settings *conf);
+       std::string makeMetaFile(bool make_corrupt);
+
+       void runTests(IGameDef *gamedef);
+
+       void testMapSettingsManager();
+       void testMapMetaSaveLoad();
+       void testMapMetaFailures();
+};
+
+static TestMapSettingsManager g_test_instance;
+
+void TestMapSettingsManager::runTests(IGameDef *gamedef)
+{
+       TEST(testMapSettingsManager);
+       TEST(testMapMetaSaveLoad);
+       TEST(testMapMetaFailures);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+
+void check_noise_params(const NoiseParams *np1, const NoiseParams *np2)
+{
+       UASSERTEQ(float, np1->offset, np2->offset);
+       UASSERTEQ(float, np1->scale, np2->scale);
+       UASSERT(np1->spread == np2->spread);
+       UASSERTEQ(s32, np1->seed, np2->seed);
+       UASSERTEQ(u16, np1->octaves, np2->octaves);
+       UASSERTEQ(float, np1->persist, np2->persist);
+       UASSERTEQ(float, np1->lacunarity, np2->lacunarity);
+       UASSERTEQ(u32, np1->flags, np2->flags);
+}
+
+
+std::string read_file_to_string(const std::string &filepath)
+{
+       std::string buf;
+       FILE *f = fopen(filepath.c_str(), "rb");
+       if (!f)
+               return "";
+
+       fseek(f, 0, SEEK_END);
+
+       long filesize = ftell(f);
+       if (filesize == -1)
+               return "";
+       rewind(f);
+
+       buf.resize(filesize);
+
+       fread(&buf[0], 1, filesize, f);
+
+       fclose(f);
+       return buf;
+}
+
+
+void TestMapSettingsManager::makeUserConfig(Settings *conf)
+{
+       conf->set("mg_name", "v7");
+       conf->set("seed", "5678");
+       conf->set("water_level", "20");
+       conf->set("mgv5_np_factor", "0, 12,  (500, 250, 500), 920382, 5, 0.45, 3.0");
+       conf->set("mgv5_np_height", "0, 15, (500, 250, 500), 841746,  5, 0.5,  3.0");
+       conf->set("mgv5_np_filler_depth", "20, 1, (150, 150, 150), 261, 4, 0.7,  1.0");
+       conf->set("mgv5_np_ground", "-43, 40, (80,  80,  80),  983240, 4, 0.55, 2.0");
+}
+
+
+std::string TestMapSettingsManager::makeMetaFile(bool make_corrupt)
+{
+       std::string metafile = getTestTempFile();
+
+       const char *metafile_contents =
+               "mg_name = v5\n"
+               "seed = 1234\n"
+               "mg_flags = light\n"
+               "mgv5_np_filler_depth = 20, 1, (150, 150, 150), 261, 4, 0.7,  1.0\n"
+               "mgv5_np_height = 20, 10, (250, 250, 250), 84174,  4, 0.5,  1.0\n";
+
+       FILE *f = fopen(metafile.c_str(), "wb");
+       UASSERT(f != NULL);
+
+       fputs(metafile_contents, f);
+       if (!make_corrupt)
+               fputs("[end_of_params]\n", f);
+
+       fclose(f);
+
+       return metafile;
+}
+
+
+void TestMapSettingsManager::testMapSettingsManager()
+{
+       Settings user_settings;
+       makeUserConfig(&user_settings);
+
+       std::string test_mapmeta_path = makeMetaFile(false);
+
+       MapSettingsManager mgr(&user_settings, test_mapmeta_path);
+       std::string value;
+
+       UASSERT(mgr.getMapSetting("mg_name", &value));
+       UASSERT(value == "v7");
+
+       // Pretend we're initializing the ServerMap
+       UASSERT(mgr.loadMapMeta());
+
+       // Pretend some scripts are requesting mapgen params
+       UASSERT(mgr.getMapSetting("mg_name", &value));
+       UASSERT(value == "v5");
+       UASSERT(mgr.getMapSetting("seed", &value));
+       UASSERT(value == "1234");
+       UASSERT(mgr.getMapSetting("water_level", &value));
+       UASSERT(value == "20");
+
+    // Pretend we have some mapgen settings configured from the scripting
+       UASSERT(mgr.setMapSetting("water_level", "15"));
+       UASSERT(mgr.setMapSetting("seed", "02468"));
+       UASSERT(mgr.setMapSetting("mg_flags", "nolight", true));
+
+       NoiseParams script_np_filler_depth(0, 100, v3f(200, 100, 200), 261, 4, 0.7, 2.0);
+       NoiseParams script_np_factor(0, 100, v3f(50, 50, 50), 920381, 3, 0.45, 2.0);
+       NoiseParams script_np_height(0, 100, v3f(450, 450, 450), 84174, 4, 0.5, 2.0);
+       NoiseParams meta_np_height(20, 10, v3f(250, 250, 250), 84174,  4, 0.5,  1.0);
+       NoiseParams user_np_ground(-43, 40, v3f(80,  80,  80),  983240, 4, 0.55, 2.0, NOISE_FLAG_EASED);
+
+       mgr.setMapSettingNoiseParams("mgv5_np_filler_depth", &script_np_filler_depth, true);
+       mgr.setMapSettingNoiseParams("mgv5_np_height", &script_np_height);
+       mgr.setMapSettingNoiseParams("mgv5_np_factor", &script_np_factor);
+
+       // Now make our Params and see if the values are correctly sourced
+       MapgenParams *params = mgr.makeMapgenParams();
+       UASSERT(params->mgtype == MAPGEN_V5);
+       UASSERT(params->chunksize == 5);
+       UASSERT(params->water_level == 15);
+       UASSERT(params->seed == 1234);
+       UASSERT((params->flags & MG_LIGHT) == 0);
+
+       MapgenV5Params *v5params = (MapgenV5Params *)params;
+
+       check_noise_params(&v5params->np_filler_depth, &script_np_filler_depth);
+       check_noise_params(&v5params->np_factor, &script_np_factor);
+       check_noise_params(&v5params->np_height, &meta_np_height);
+       check_noise_params(&v5params->np_ground, &user_np_ground);
+
+       UASSERT(mgr.setMapSetting("foobar", "25") == false);
+
+       // Pretend the ServerMap is shutting down
+       UASSERT(mgr.saveMapMeta());
+
+       // Make sure our interface expectations are met
+       UASSERT(mgr.mapgen_params == params);
+       UASSERT(mgr.makeMapgenParams() == params);
+
+       // Load the resulting map_meta.txt and make sure it contains what we expect
+       unsigned char expected_contents_hash[20] = {
+               0xf6, 0x44, 0x90, 0xb7, 0xab, 0xd8, 0x91, 0xf4, 0x08, 0x96,
+               0xfc, 0x7e, 0xed, 0x01, 0xc5, 0x9a, 0xfd, 0x2f, 0x2d, 0x79
+       };
+
+       SHA1 ctx;
+       std::string metafile_contents = read_file_to_string(test_mapmeta_path);
+       ctx.addBytes(&metafile_contents[0], metafile_contents.size());
+       unsigned char *sha1_result = ctx.getDigest();
+       int resultdiff = memcmp(sha1_result, expected_contents_hash, 20);
+       free(sha1_result);
+
+       UASSERT(!resultdiff);
+}
+
+
+void TestMapSettingsManager::testMapMetaSaveLoad()
+{
+       Settings conf;
+       std::string path = getTestTempDirectory()
+               + DIR_DELIM + "foobar" + DIR_DELIM + "map_meta.txt";
+
+       // Create a set of mapgen params and save them to map meta
+       conf.set("seed", "12345");
+       conf.set("water_level", "5");
+       MapSettingsManager mgr1(&conf, path);
+       MapgenParams *params1 = mgr1.makeMapgenParams();
+       UASSERT(params1);
+       UASSERT(mgr1.saveMapMeta());
+
+       // Now try loading the map meta to mapgen params
+       conf.set("seed", "67890");
+       conf.set("water_level", "32");
+       MapSettingsManager mgr2(&conf, path);
+       UASSERT(mgr2.loadMapMeta());
+       MapgenParams *params2 = mgr2.makeMapgenParams();
+       UASSERT(params2);
+
+       // Check that both results are correct
+       UASSERTEQ(u64, params1->seed, 12345);
+       UASSERTEQ(s16, params1->water_level, 5);
+       UASSERTEQ(u64, params2->seed, 12345);
+       UASSERTEQ(s16, params2->water_level, 5);
+}
+
+
+void TestMapSettingsManager::testMapMetaFailures()
+{
+       std::string test_mapmeta_path;
+       Settings conf;
+
+       // Check to see if it'll fail on a non-existent map meta file
+       test_mapmeta_path = "woobawooba/fgdfg/map_meta.txt";
+       UASSERT(!fs::PathExists(test_mapmeta_path));
+
+       MapSettingsManager mgr1(&conf, test_mapmeta_path);
+       UASSERT(!mgr1.loadMapMeta());
+
+       // Check to see if it'll fail on a corrupt map meta file
+       test_mapmeta_path = makeMetaFile(true);
+       UASSERT(fs::PathExists(test_mapmeta_path));
+
+       MapSettingsManager mgr2(&conf, test_mapmeta_path);
+       UASSERT(!mgr2.loadMapMeta());
+}