From 559dd9946988cd35a7c26bcafe7d0f8c42dc547a Mon Sep 17 00:00:00 2001 From: Ekdohibs Date: Mon, 21 Mar 2016 12:58:52 +0100 Subject: Make node timers more efficient --- src/map.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/map.h') diff --git a/src/map.h b/src/map.h index 78614d228..23da56471 100644 --- a/src/map.h +++ b/src/map.h @@ -327,7 +327,7 @@ public: */ NodeTimer getNodeTimer(v3s16 p); - void setNodeTimer(v3s16 p, NodeTimer t); + void setNodeTimer(const NodeTimer &t); void removeNodeTimer(v3s16 p); /* -- cgit v1.2.3 From 3c63c3044d5e4ca36c2649c530f31622581d90fd Mon Sep 17 00:00:00 2001 From: kwolekr Date: Fri, 24 Jun 2016 18:15:56 -0400 Subject: Add MapSettingsManager and new mapgen setting script API functions 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. --- build/android/jni/Android.mk | 2 + doc/lua_api.txt | 19 +++ src/CMakeLists.txt | 1 + src/emerge.cpp | 40 ++--- src/emerge.h | 15 +- src/map.cpp | 100 +++-------- src/map.h | 10 +- src/map_settings_manager.cpp | 194 ++++++++++++++++++++++ src/map_settings_manager.h | 79 +++++++++ src/mapgen.cpp | 68 ++++---- src/mapgen.h | 20 +-- src/mapgen_flat.cpp | 28 ++-- src/mapgen_flat.h | 4 +- src/mapgen_fractal.cpp | 34 ++-- src/mapgen_fractal.h | 4 +- src/mapgen_singlenode.h | 2 +- src/mapgen_v5.cpp | 20 +-- src/mapgen_v5.h | 4 +- src/mapgen_v6.cpp | 33 ++-- src/mapgen_v6.h | 4 +- src/mapgen_v7.cpp | 30 ++-- src/mapgen_v7.h | 4 +- src/mapgen_valleys.cpp | 41 +++-- src/mapgen_valleys.h | 4 +- src/script/lua_api/l_mapgen.cpp | 154 +++++++++++++---- src/script/lua_api/l_mapgen.h | 12 ++ src/script/lua_api/l_vmanip.cpp | 2 +- src/server.cpp | 15 +- src/subgame.cpp | 4 +- src/unittest/CMakeLists.txt | 1 + src/unittest/test_map_settings_manager.cpp | 255 +++++++++++++++++++++++++++++ 31 files changed, 889 insertions(+), 314 deletions(-) create mode 100644 src/map_settings_manager.cpp create mode 100644 src/map_settings_manager.h create mode 100644 src/unittest/test_map_settings_manager.cpp (limited to 'src/map.h') diff --git a/build/android/jni/Android.mk b/build/android/jni/Android.mk index afd8c76b2..a42ab76b8 100644 --- a/build/android/jni/Android.mk +++ b/build/android/jni/Android.mk @@ -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 \ diff --git a/doc/lua_api.txt b/doc/lua_api.txt index 6d359379e..297566068 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -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 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index bffc1f7eb..bcd7a5984 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -414,6 +414,7 @@ set(common_SRCS light.cpp log.cpp map.cpp + map_settings_manager.cpp mapblock.cpp mapgen.cpp mapgen_flat.cpp diff --git a/src/emerge.cpp b/src/emerge.cpp index 48de6cb1a..daf42f5e2 100644 --- a/src/emerge.cpp +++ b/src/emerge.cpp @@ -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, ¶ms, 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( diff --git a/src/emerge.h b/src/emerge.h index 303a35529..cf0677145 100644 --- a/src/emerge.h +++ b/src/emerge.h @@ -97,8 +97,16 @@ public: u32 gen_notify_on; std::set 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(); diff --git a/src/map.cpp b/src/map.cpp index a1f2086ce..38f0fa37c 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -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<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."<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." < &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); diff --git a/src/map.h b/src/map.h index 23da56471..13775fde1 100644 --- 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 &dst); void listAllLoadedBlocks(std::vector &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 index 000000000..53d17125c --- /dev/null +++ b/src/map_settings_manager.cpp @@ -0,0 +1,194 @@ +/* +Minetest +Copyright (C) 2010-2013 kwolekr, Ryan Kwolek + +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 index 000000000..9f766f1f0 --- /dev/null +++ b/src/map_settings_manager.h @@ -0,0 +1,79 @@ +/* +Minetest +Copyright (C) 2010-2013 kwolekr, Ryan Kwolek + +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 + +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 diff --git a/src/mapgen.cpp b/src/mapgen.cpp index e45233b33..b6fda91ac 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -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); } diff --git a/src/mapgen.h b/src/mapgen.h index 618a2f6b8..5fcf2a365 100644 --- a/src/mapgen.h +++ b/src/mapgen.h @@ -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 *mgnames, bool include_hidden); private: diff --git a/src/mapgen_flat.cpp b/src/mapgen_flat.cpp index 956af999a..2c1715e61 100644 --- a/src/mapgen_flat.cpp +++ b/src/mapgen_flat.cpp @@ -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(¶ms->np_terrain, seed, csize.X, csize.Z); + noise_filler_depth = new Noise(¶ms->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; } diff --git a/src/mapgen_flat.h b/src/mapgen_flat.h index 39b6dc302..8b3de2bcf 100644 --- a/src/mapgen_flat.h +++ b/src/mapgen_flat.h @@ -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; } diff --git a/src/mapgen_fractal.cpp b/src/mapgen_fractal.cpp index 9e4c210dc..0951a0afa 100644 --- a/src/mapgen_fractal.cpp +++ b/src/mapgen_fractal.cpp @@ -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(¶ms->np_seabed, seed, csize.X, csize.Z); + noise_filler_depth = new Noise(¶ms->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; diff --git a/src/mapgen_fractal.h b/src/mapgen_fractal.h index cbd5567c4..3331848bc 100644 --- a/src/mapgen_fractal.h +++ b/src/mapgen_fractal.h @@ -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; } diff --git a/src/mapgen_singlenode.h b/src/mapgen_singlenode.h index 58672a0ed..07520134d 100644 --- a/src/mapgen_singlenode.h +++ b/src/mapgen_singlenode.h @@ -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() {} diff --git a/src/mapgen_v5.cpp b/src/mapgen_v5.cpp index 74d5e1ee3..9f189e253 100644 --- a/src/mapgen_v5.cpp +++ b/src/mapgen_v5.cpp @@ -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(¶ms->np_filler_depth, seed, csize.X, csize.Z); + noise_factor = new Noise(¶ms->np_factor, seed, csize.X, csize.Z); + noise_height = new Noise(¶ms->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(¶ms->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; } diff --git a/src/mapgen_v5.h b/src/mapgen_v5.h index 5f6b10383..ddb090a9c 100644 --- a/src/mapgen_v5.h +++ b/src/mapgen_v5.h @@ -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; } diff --git a/src/mapgen_v6.cpp b/src/mapgen_v6.cpp index caa64827e..e4444963f 100644 --- a/src/mapgen_v6.cpp +++ b/src/mapgen_v6.cpp @@ -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 = ¶ms->np_cave; + np_humidity = ¶ms->np_humidity; + np_trees = ¶ms->np_trees; + np_apple_trees = ¶ms->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(¶ms->np_terrain_base, seed, csize.X, csize.Y); + noise_terrain_higher = new Noise(¶ms->np_terrain_higher, seed, csize.X, csize.Y); + noise_steepness = new Noise(¶ms->np_steepness, seed, csize.X, csize.Y); + noise_height_select = new Noise(¶ms->np_height_select, seed, csize.X, csize.Y); + noise_mud = new Noise(¶ms->np_mud, seed, csize.X, csize.Y); + noise_beach = new Noise(¶ms->np_beach, seed, csize.X, csize.Y); + noise_biome = new Noise(¶ms->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(¶ms->np_humidity, seed, csize.X + 2 * MAP_BLOCKSIZE, csize.Y + 2 * MAP_BLOCKSIZE); //// Resolve nodes to be used diff --git a/src/mapgen_v6.h b/src/mapgen_v6.h index 20b0bf92e..f018ffaca 100644 --- a/src/mapgen_v6.h +++ b/src/mapgen_v6.h @@ -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; } diff --git a/src/mapgen_v7.cpp b/src/mapgen_v7.cpp index c24b3e8d1..d14fdb97a 100644 --- a/src/mapgen_v7.cpp +++ b/src/mapgen_v7.cpp @@ -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(¶ms->np_terrain_base, seed, csize.X, csize.Z); + noise_terrain_alt = new Noise(¶ms->np_terrain_alt, seed, csize.X, csize.Z); + noise_terrain_persist = new Noise(¶ms->np_terrain_persist, seed, csize.X, csize.Z); + noise_height_select = new Noise(¶ms->np_height_select, seed, csize.X, csize.Z); + noise_filler_depth = new Noise(¶ms->np_filler_depth, seed, csize.X, csize.Z); + noise_mount_height = new Noise(¶ms->np_mount_height, seed, csize.X, csize.Z); + noise_ridge_uwater = new Noise(¶ms->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(¶ms->np_mountain, seed, csize.X, csize.Y + 2, csize.Z); + noise_ridge = new Noise(¶ms->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; } diff --git a/src/mapgen_v7.h b/src/mapgen_v7.h index c75f18a93..3a6bc0801 100644 --- a/src/mapgen_v7.h +++ b/src/mapgen_v7.h @@ -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; } diff --git a/src/mapgen_valleys.cpp b/src/mapgen_valleys.cpp index 02a8fbfe0..a61f1b329 100644 --- a/src/mapgen_valleys.cpp +++ b/src/mapgen_valleys.cpp @@ -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(¶ms->np_filler_depth, seed, csize.X, csize.Z); + noise_inter_valley_slope = new Noise(¶ms->np_inter_valley_slope, seed, csize.X, csize.Z); + noise_rivers = new Noise(¶ms->np_rivers, seed, csize.X, csize.Z); + noise_terrain_height = new Noise(¶ms->np_terrain_height, seed, csize.X, csize.Z); + noise_valley_depth = new Noise(¶ms->np_valley_depth, seed, csize.X, csize.Z); + noise_valley_profile = new Noise(¶ms->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(¶ms->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(¶ms->np_cave1, seed, csize.X, csize.Y + 1, csize.Z); + noise_cave2 = new Noise(¶ms->np_cave2, seed, csize.X, csize.Y + 1, csize.Z); + noise_massive_caves = new Noise(¶ms->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); diff --git a/src/mapgen_valleys.h b/src/mapgen_valleys.h index 00f6aff07..6dd7ebc47 100644 --- a/src/mapgen_valleys.h +++ b/src/mapgen_valleys.h @@ -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; } diff --git a/src/script/lua_api/l_mapgen.cpp b/src/script/lua_api/l_mapgen.cpp index dc188f8a4..9f14838ce 100644 --- a/src/script/lua_api/l_mapgen.cpp +++ b/src/script/lua_api/l_mapgen.cpp @@ -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); diff --git a/src/script/lua_api/l_mapgen.h b/src/script/lua_api/l_mapgen.h index 9751c0db6..bb94575c7 100644 --- a/src/script/lua_api/l_mapgen.h +++ b/src/script/lua_api/l_mapgen.h @@ -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); diff --git a/src/script/lua_api/l_vmanip.cpp b/src/script/lua_api/l_vmanip.cpp index f13866408..0d8123acd 100644 --- a/src/script/lua_api/l_vmanip.cpp +++ b/src/script/lua_api/l_vmanip.cpp @@ -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); diff --git a/src/server.cpp b/src/server.cpp index f7f698d50..97a53f189 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -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; } diff --git a/src/subgame.cpp b/src/subgame.cpp index 7e9a0b368..55bbd3954 100644 --- a/src/subgame.cpp +++ b/src/subgame.cpp @@ -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"; diff --git a/src/unittest/CMakeLists.txt b/src/unittest/CMakeLists.txt index a07ed8ba5..34de99e12 100644 --- a/src/unittest/CMakeLists.txt +++ b/src/unittest/CMakeLists.txt @@ -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 index 000000000..b2ad53192 --- /dev/null +++ b/src/unittest/test_map_settings_manager.cpp @@ -0,0 +1,255 @@ + /* +Minetest +Copyright (C) 2010-2014 kwolekr, Ryan Kwolek + +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()); +} -- cgit v1.2.3 From 155288ee981c70f505526347cb2bcda4df1c8e6b Mon Sep 17 00:00:00 2001 From: Loic Blot Date: Thu, 6 Oct 2016 19:20:12 +0200 Subject: use unordered containers where possible (patch 4 on X) Also remove some unused parameters/functions --- src/content_sao.cpp | 28 ++++++++++++++++++---------- src/content_sao.h | 5 +++-- src/guiFormSpecMenu.h | 4 +--- src/map.h | 1 + src/mapblock_mesh.cpp | 24 ++++++++++-------------- src/mapblock_mesh.h | 15 ++++++++------- src/network/serverpackethandler.cpp | 4 +--- src/script/cpp_api/s_async.cpp | 3 ++- src/script/cpp_api/s_async.h | 2 +- src/server.cpp | 21 +++++++++------------ src/server.h | 16 ++++++---------- src/util/numeric.cpp | 2 +- src/util/numeric.h | 37 ++----------------------------------- 13 files changed, 63 insertions(+), 99 deletions(-) (limited to 'src/map.h') diff --git a/src/content_sao.cpp b/src/content_sao.cpp index 1e7e788e9..895c26044 100644 --- a/src/content_sao.cpp +++ b/src/content_sao.cpp @@ -347,8 +347,10 @@ void LuaEntitySAO::step(float dtime, bool send_recommended) if(m_bone_position_sent == false){ m_bone_position_sent = true; - for(std::map >::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii){ - std::string str = gob_cmd_update_bone_position((*ii).first, (*ii).second.X, (*ii).second.Y); + for (UNORDERED_MAP >::const_iterator + ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii){ + std::string str = gob_cmd_update_bone_position((*ii).first, + (*ii).second.X, (*ii).second.Y); // create message and add to list ActiveObjectMessage aom(getId(), true, str); m_messages_out.push(aom); @@ -383,8 +385,10 @@ std::string LuaEntitySAO::getClientInitializationData(u16 protocol_version) os< >::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii){ - os< >::const_iterator + ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii) { + os << serializeLongString(gob_cmd_update_bone_position((*ii).first, + (*ii).second.X, (*ii).second.Y)); // m_bone_position.size } os< >::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii){ + for (UNORDERED_MAP >::const_iterator + ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii) { os< >::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii){ - std::string str = gob_cmd_update_bone_position((*ii).first, (*ii).second.X, (*ii).second.Y); + for (UNORDERED_MAP >::const_iterator + ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii) { + std::string str = gob_cmd_update_bone_position((*ii).first, + (*ii).second.X, (*ii).second.Y); // create message and add to list ActiveObjectMessage aom(getId(), true, str); m_messages_out.push(aom); } } - if(m_attachment_sent == false){ + if (!m_attachment_sent){ m_attachment_sent = true; - std::string str = gob_cmd_update_attachment(m_attachment_parent_id, m_attachment_bone, m_attachment_position, m_attachment_rotation); + std::string str = gob_cmd_update_attachment(m_attachment_parent_id, + m_attachment_bone, m_attachment_position, m_attachment_rotation); // create message and add to list ActiveObjectMessage aom(getId(), true, str); m_messages_out.push(aom); diff --git a/src/content_sao.h b/src/content_sao.h index 44d40d332..ccae90b77 100644 --- a/src/content_sao.h +++ b/src/content_sao.h @@ -112,7 +112,7 @@ private: bool m_animation_loop; bool m_animation_sent; - std::map > m_bone_position; + UNORDERED_MAP > m_bone_position; bool m_bone_position_sent; int m_attachment_parent_id; @@ -321,7 +321,8 @@ private: bool m_animation_loop; bool m_animation_sent; - std::map > m_bone_position; // Stores position and rotation for each bone name + // Stores position and rotation for each bone name + UNORDERED_MAP > m_bone_position; bool m_bone_position_sent; int m_attachment_parent_id; diff --git a/src/guiFormSpecMenu.h b/src/guiFormSpecMenu.h index 21054b725..153720975 100644 --- a/src/guiFormSpecMenu.h +++ b/src/guiFormSpecMenu.h @@ -409,8 +409,6 @@ protected: std::vector > > m_dropdowns; ItemSpec *m_selected_item; - f32 m_timer1; - f32 m_timer2; u32 m_selected_amount; bool m_selected_dragging; @@ -462,7 +460,7 @@ private: GUITable::TableOptions table_options; GUITable::TableColumns table_columns; // used to restore table selection/scroll/treeview state - std::map table_dyndata; + UNORDERED_MAP table_dyndata; } parserData; typedef struct { diff --git a/src/map.h b/src/map.h index 13775fde1..c73fa92bf 100644 --- a/src/map.h +++ b/src/map.h @@ -32,6 +32,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "voxel.h" #include "modifiedstate.h" #include "util/container.h" +#include "util/cpp11_container.h" #include "nodetimer.h" #include "map_settings_manager.h" diff --git a/src/mapblock_mesh.cpp b/src/mapblock_mesh.cpp index a11fb5887..00f83e7ab 100644 --- a/src/mapblock_mesh.cpp +++ b/src/mapblock_mesh.cpp @@ -1033,7 +1033,7 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset): m_enable_shaders = data->m_use_shaders; m_use_tangent_vertices = data->m_use_tangent_vertices; m_enable_vbo = g_settings->getBool("enable_vbo"); - + if (g_settings->getBool("enable_minimap")) { m_minimap_mapblock = new MinimapMapblock; m_minimap_mapblock->getMinimapNodes( @@ -1298,10 +1298,8 @@ bool MapBlockMesh::animate(bool faraway, float time, int crack, u32 daynight_rat // Cracks if(crack != m_last_crack) { - for(std::map::iterator - i = m_crack_materials.begin(); - i != m_crack_materials.end(); ++i) - { + for (UNORDERED_MAP::iterator i = m_crack_materials.begin(); + i != m_crack_materials.end(); ++i) { scene::IMeshBuffer *buf = m_mesh->getMeshBuffer(i->first); std::string basename = i->second; @@ -1315,9 +1313,9 @@ bool MapBlockMesh::animate(bool faraway, float time, int crack, u32 daynight_rat // If the current material is also animated, // update animation info - std::map::iterator anim_iter = - m_animation_tiles.find(i->first); - if(anim_iter != m_animation_tiles.end()){ + UNORDERED_MAP::iterator anim_iter = + m_animation_tiles.find(i->first); + if (anim_iter != m_animation_tiles.end()){ TileSpec &tile = anim_iter->second; tile.texture = new_texture; tile.texture_id = new_texture_id; @@ -1330,10 +1328,8 @@ bool MapBlockMesh::animate(bool faraway, float time, int crack, u32 daynight_rat } // Texture animation - for(std::map::iterator - i = m_animation_tiles.begin(); - i != m_animation_tiles.end(); ++i) - { + for (UNORDERED_MAP::iterator i = m_animation_tiles.begin(); + i != m_animation_tiles.end(); ++i) { const TileSpec &tile = i->second; // Figure out current frame int frameoffset = m_animation_frame_offsets[i->first]; @@ -1443,7 +1439,7 @@ void MeshCollector::append(const TileSpec &tile, vertices[i].Color, vertices[i].TCoords); p->vertices.push_back(vert); } - } + } for (u32 i = 0; i < numIndices; i++) { u32 j = indices[i] + vertex_count; @@ -1499,7 +1495,7 @@ void MeshCollector::append(const TileSpec &tile, vertices[i].Normal, c, vertices[i].TCoords); p->vertices.push_back(vert); } - } + } for (u32 i = 0; i < numIndices; i++) { u32 j = indices[i] + vertex_count; diff --git a/src/mapblock_mesh.h b/src/mapblock_mesh.h index f89fbe669..8376468da 100644 --- a/src/mapblock_mesh.h +++ b/src/mapblock_mesh.h @@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "irrlichttypes_extrabloated.h" #include "client/tile.h" #include "voxel.h" +#include "util/cpp11_container.h" #include class IGameDef; @@ -121,7 +122,7 @@ public: if(m_animation_force_timer > 0) m_animation_force_timer--; } - + void updateCameraOffset(v3s16 camera_offset); private: @@ -144,20 +145,20 @@ private: // Last crack value passed to animate() int m_last_crack; // Maps mesh buffer (i.e. material) indices to base texture names - std::map m_crack_materials; + UNORDERED_MAP m_crack_materials; // Animation info: texture animationi // Maps meshbuffers to TileSpecs - std::map m_animation_tiles; - std::map m_animation_frames; // last animation frame - std::map m_animation_frame_offsets; - + UNORDERED_MAP m_animation_tiles; + UNORDERED_MAP m_animation_frames; // last animation frame + UNORDERED_MAP m_animation_frame_offsets; + // Animation info: day/night transitions // Last daynight_ratio value passed to animate() u32 m_last_daynight_ratio; // For each meshbuffer, maps vertex indices to (day,night) pairs std::map > > m_daynight_diffs; - + // Camera offset info -> do we have to translate the mesh? v3s16 m_camera_offset; }; diff --git a/src/network/serverpackethandler.cpp b/src/network/serverpackethandler.cpp index a8bfd9068..f9061cc4f 100644 --- a/src/network/serverpackethandler.cpp +++ b/src/network/serverpackethandler.cpp @@ -1693,9 +1693,7 @@ void Server::handleCommand_RemovedSounds(NetworkPacket* pkt) *pkt >> id; - std::map::iterator i = - m_playing_sounds.find(id); - + UNORDERED_MAP::iterator i = m_playing_sounds.find(id); if (i == m_playing_sounds.end()) continue; diff --git a/src/script/cpp_api/s_async.cpp b/src/script/cpp_api/s_async.cpp index 9bf3fcf49..1fb84fab6 100644 --- a/src/script/cpp_api/s_async.cpp +++ b/src/script/cpp_api/s_async.cpp @@ -81,6 +81,7 @@ bool AsyncEngine::registerFunction(const char* name, lua_CFunction func) if (initDone) { return false; } + functionList[name] = func; return true; } @@ -203,7 +204,7 @@ void AsyncEngine::pushFinishedJobs(lua_State* L) { /******************************************************************************/ void AsyncEngine::prepareEnvironment(lua_State* L, int top) { - for (std::map::iterator it = functionList.begin(); + for (UNORDERED_MAP::iterator it = functionList.begin(); it != functionList.end(); it++) { lua_pushstring(L, it->first.c_str()); lua_pushcfunction(L, it->second); diff --git a/src/script/cpp_api/s_async.h b/src/script/cpp_api/s_async.h index 8d612d58c..016381e5f 100644 --- a/src/script/cpp_api/s_async.h +++ b/src/script/cpp_api/s_async.h @@ -132,7 +132,7 @@ private: bool initDone; // Internal store for registred functions - std::map functionList; + UNORDERED_MAP functionList; // Internal counter to create job IDs unsigned int jobIdCounter; diff --git a/src/server.cpp b/src/server.cpp index 639e6462a..2dd070b1a 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -868,7 +868,7 @@ void Server::AsyncRunStep(bool initial_step) m_clients.unlock(); // Clear buffered_messages - for(UNORDERED_MAP* >::iterator + for (UNORDERED_MAP* >::iterator i = buffered_messages.begin(); i != buffered_messages.end(); ++i) { delete i->second; @@ -2016,16 +2016,15 @@ s32 Server::playSound(const SimpleSoundSpec &spec, void Server::stopSound(s32 handle) { // Get sound reference - std::map::iterator i = - m_playing_sounds.find(handle); - if(i == m_playing_sounds.end()) + UNORDERED_MAP::iterator i = m_playing_sounds.find(handle); + if (i == m_playing_sounds.end()) return; ServerPlayingSound &psound = i->second; NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4); pkt << handle; - for(std::set::iterator i = psound.clients.begin(); + for (UNORDERED_SET::iterator i = psound.clients.begin(); i != psound.clients.end(); ++i) { // Send as reliable m_clients.send(*i, 0, &pkt, true); @@ -2322,7 +2321,7 @@ void Server::sendMediaAnnouncement(u16 peer_id) NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id); pkt << (u16) m_media.size(); - for (std::map::iterator i = m_media.begin(); + for (UNORDERED_MAP::iterator i = m_media.begin(); i != m_media.end(); ++i) { pkt << i->first << i->second.sha1_digest; } @@ -2367,7 +2366,7 @@ void Server::sendRequestedMedia(u16 peer_id, i != tosend.end(); ++i) { const std::string &name = *i; - if(m_media.find(name) == m_media.end()) { + if (m_media.find(name) == m_media.end()) { errorstream<<"Server::sendRequestedMedia(): Client asked for " <<"unknown file \""<<(name)<<"\""<::iterator - i = m_playing_sounds.begin(); - i != m_playing_sounds.end();) - { + for (UNORDERED_MAP::iterator + i = m_playing_sounds.begin(); i != m_playing_sounds.end();) { ServerPlayingSound &psound = i->second; psound.clients.erase(peer_id); - if(psound.clients.empty()) + if (psound.clients.empty()) m_playing_sounds.erase(i++); else ++i; diff --git a/src/server.h b/src/server.h index 3ad894b38..34427a71a 100644 --- a/src/server.h +++ b/src/server.h @@ -157,7 +157,7 @@ struct ServerSoundParams struct ServerPlayingSound { ServerSoundParams params; - std::set clients; // peer ids + UNORDERED_SET clients; // peer ids }; class Server : public con::PeerHandler, public MapEventReceiver, @@ -243,11 +243,9 @@ public: std::wstring getStatusString(); // read shutdown state - inline bool getShutdownRequested() - { return m_shutdown_requested; } + inline bool getShutdownRequested() const { return m_shutdown_requested; } // request server to shutdown - inline void requestShutdown() { m_shutdown_requested = true; } void requestShutdown(const std::string &msg, bool reconnect) { m_shutdown_requested = true; @@ -323,8 +321,7 @@ public: const ModSpec* getModSpec(const std::string &modname) const; void getModNames(std::vector &modlist); std::string getBuiltinLuaPath(); - inline std::string getWorldPath() const - { return m_path_world; } + inline std::string getWorldPath() const { return m_path_world; } inline bool isSingleplayer() { return m_simple_singleplayer_mode; } @@ -356,8 +353,7 @@ public: bool setSky(Player *player, const video::SColor &bgcolor, const std::string &type, const std::vector ¶ms); - bool overrideDayNightRatio(Player *player, bool do_override, - float brightness); + bool overrideDayNightRatio(Player *player, bool do_override, float brightness); /* con::PeerHandler implementation. */ void peerAdded(con::Peer *peer); @@ -654,12 +650,12 @@ private: u16 m_ignore_map_edit_events_peer_id; // media files known to server - std::map m_media; + UNORDERED_MAP m_media; /* Sounds */ - std::map m_playing_sounds; + UNORDERED_MAP m_playing_sounds; s32 m_next_sound_id; /* diff --git a/src/util/numeric.cpp b/src/util/numeric.cpp index 42ebd9022..6a7bfcac9 100644 --- a/src/util/numeric.cpp +++ b/src/util/numeric.cpp @@ -27,7 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include -std::map > FacePositionCache::m_cache; +UNORDERED_MAP > FacePositionCache::m_cache; Mutex FacePositionCache::m_cache_mutex; // Calculate the borders of a "d-radius" cube // TODO: Make it work without mutex and data races, probably thread-local diff --git a/src/util/numeric.h b/src/util/numeric.h index 615327864..4cdc254c3 100644 --- a/src/util/numeric.h +++ b/src/util/numeric.h @@ -26,8 +26,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "../irr_v3d.h" #include "../irr_aabb3d.h" #include "../threading/mutex.h" +#include "cpp11_container.h" #include -#include #include @@ -41,26 +41,10 @@ public: static std::vector getFacePositions(u16 d); private: static void generateFacePosition(u16 d); - static std::map > m_cache; + static UNORDERED_MAP > m_cache; static Mutex m_cache_mutex; }; -class IndentationRaiser -{ -public: - IndentationRaiser(u16 *indentation) - { - m_indentation = indentation; - (*m_indentation)++; - } - ~IndentationRaiser() - { - (*m_indentation)--; - } -private: - u16 *m_indentation; -}; - inline s16 getContainerPos(s16 p, s16 d) { return (p>=0 ? p : p-d+1) / d; @@ -149,23 +133,6 @@ inline bool isInArea(v3s16 p, v3s16 d) #define rangelim(d, min, max) ((d) < (min) ? (min) : ((d)>(max)?(max):(d))) #define myfloor(x) ((x) > 0.0 ? (int)(x) : (int)(x) - 1) -inline v3s16 arealim(v3s16 p, s16 d) -{ - if(p.X < 0) - p.X = 0; - if(p.Y < 0) - p.Y = 0; - if(p.Z < 0) - p.Z = 0; - if(p.X > d-1) - p.X = d-1; - if(p.Y > d-1) - p.Y = d-1; - if(p.Z > d-1) - p.Z = d-1; - return p; -} - // The naive swap performs better than the xor version #define SWAP(t, x, y) do { \ t temp = x; \ -- cgit v1.2.3 From c071efaa43ad3dcba7d60a7a67e942aae2a7dc83 Mon Sep 17 00:00:00 2001 From: Dániel Juhász Date: Thu, 20 Oct 2016 21:41:38 +0200 Subject: Improved lighting This commit rewrites the procedure that is responsible for light updating. this commit -provides iterative solutions for unlighting and light spreading -introduces a new priority queue-like container for the iteration -creates per-node MapBlock caching to reduce retrieving MapBlocks from the map -calculates with map block positions and in-block relative node coordinates -skips light updating if it is not necessary since the node's new light will be the same as its old light was --- src/map.cpp | 441 ++---------------------------------- src/map.h | 16 +- src/mapnode.cpp | 16 +- src/mapnode.h | 9 + src/voxelalgorithms.cpp | 584 ++++++++++++++++++++++++++++++++++++++++++++++++ src/voxelalgorithms.h | 20 ++ 6 files changed, 643 insertions(+), 443 deletions(-) (limited to 'src/map.h') diff --git a/src/map.cpp b/src/map.cpp index 38f0fa37c..1694582db 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "mapblock.h" #include "filesys.h" #include "voxel.h" +#include "voxelalgorithms.h" #include "porting.h" #include "serialization.h" #include "nodemetadata.h" @@ -234,7 +235,6 @@ void Map::setNode(v3s16 p, MapNode & n) block->setNodeNoCheck(relpos, n); } - /* Goes recursively through the neighbours of the node. @@ -413,20 +413,6 @@ void Map::unspreadLight(enum LightBank bank, unspreadLight(bank, unlighted_nodes, light_sources, modified_blocks); } -/* - A single-node wrapper of the above -*/ -void Map::unLightNeighbors(enum LightBank bank, - v3s16 pos, u8 lightwas, - std::set & light_sources, - std::map & modified_blocks) -{ - std::map from_nodes; - from_nodes[pos] = lightwas; - - unspreadLight(bank, from_nodes, light_sources, modified_blocks); -} - /* Lights neighbors of from_nodes, collects all them and then goes on recursively. @@ -568,108 +554,6 @@ void Map::spreadLight(enum LightBank bank, spreadLight(bank, lighted_nodes, modified_blocks); } -/* - A single-node source variation of the above. -*/ -void Map::lightNeighbors(enum LightBank bank, - v3s16 pos, - std::map & modified_blocks) -{ - std::set from_nodes; - from_nodes.insert(pos); - spreadLight(bank, from_nodes, modified_blocks); -} - -v3s16 Map::getBrightestNeighbour(enum LightBank bank, v3s16 p) -{ - INodeDefManager *nodemgr = m_gamedef->ndef(); - - v3s16 dirs[6] = { - v3s16(0,0,1), // back - v3s16(0,1,0), // top - v3s16(1,0,0), // right - v3s16(0,0,-1), // front - v3s16(0,-1,0), // bottom - v3s16(-1,0,0), // left - }; - - u8 brightest_light = 0; - v3s16 brightest_pos(0,0,0); - bool found_something = false; - - // Loop through 6 neighbors - for(u16 i=0; i<6; i++){ - // Get the position of the neighbor node - v3s16 n2pos = p + dirs[i]; - MapNode n2; - bool is_valid_position; - n2 = getNodeNoEx(n2pos, &is_valid_position); - if (!is_valid_position) - continue; - - if(n2.getLight(bank, nodemgr) > brightest_light || found_something == false){ - brightest_light = n2.getLight(bank, nodemgr); - brightest_pos = n2pos; - found_something = true; - } - } - - if(found_something == false) - throw InvalidPositionException(); - - return brightest_pos; -} - -/* - Propagates sunlight down from a node. - Starting point gets sunlight. - - Returns the lowest y value of where the sunlight went. - - Mud is turned into grass in where the sunlight stops. -*/ -s16 Map::propagateSunlight(v3s16 start, - std::map & modified_blocks) -{ - INodeDefManager *nodemgr = m_gamedef->ndef(); - - s16 y = start.Y; - for(; ; y--) - { - v3s16 pos(start.X, y, start.Z); - - v3s16 blockpos = getNodeBlockPos(pos); - MapBlock *block; - try{ - block = getBlockNoCreate(blockpos); - } - catch(InvalidPositionException &e) - { - break; - } - - v3s16 relpos = pos - blockpos*MAP_BLOCKSIZE; - bool is_valid_position; - MapNode n = block->getNode(relpos, &is_valid_position); - if (!is_valid_position) - break; - - if(nodemgr->get(n).sunlight_propagates) - { - n.setLight(LIGHTBANK_DAY, LIGHT_SUN, nodemgr); - block->setNode(relpos, n); - - modified_blocks[blockpos] = block; - } - else - { - // Sunlight goes no further - break; - } - } - return y + 1; -} - void Map::updateLighting(enum LightBank bank, std::map & a_blocks, std::map & modified_blocks) @@ -922,150 +806,29 @@ void Map::updateLighting(std::map & a_blocks, } } -/* -*/ void Map::addNodeAndUpdate(v3s16 p, MapNode n, std::map &modified_blocks, bool remove_metadata) { INodeDefManager *ndef = m_gamedef->ndef(); - /*PrintInfo(m_dout); - m_dout<<"Map::addNodeAndUpdate(): p=(" - < light_sources; - - /* - Collect old node for rollback - */ + // Collect old node for rollback RollbackNode rollback_oldnode(this, p, m_gamedef); - /* - If there is a node at top and it doesn't have sunlight, - there has not been any sunlight going down. - - Otherwise there probably is. - */ - - bool is_valid_position; - MapNode topnode = getNodeNoEx(toppos, &is_valid_position); - - if(is_valid_position && topnode.getLight(LIGHTBANK_DAY, ndef) != LIGHT_SUN) - node_under_sunlight = false; - - /* - Remove all light that has come out of this node - */ - - enum LightBank banks[] = - { - LIGHTBANK_DAY, - LIGHTBANK_NIGHT - }; - for(s32 i=0; i<2; i++) - { - enum LightBank bank = banks[i]; + // This is needed for updating the lighting + MapNode oldnode = getNodeNoEx(p); - u8 lightwas = getNodeNoEx(p).getLight(bank, ndef); - - // Add the block of the added node to modified_blocks - v3s16 blockpos = getNodeBlockPos(p); - MapBlock * block = getBlockNoCreate(blockpos); - assert(block != NULL); - modified_blocks[blockpos] = block; - - assert(isValidPosition(p)); - - // Unlight neighbours of node. - // This means setting light of all consequent dimmer nodes - // to 0. - // This also collects the nodes at the border which will spread - // light again into this. - unLightNeighbors(bank, p, lightwas, light_sources, modified_blocks); - - n.setLight(bank, 0, ndef); - } - - /* - If node lets sunlight through and is under sunlight, it has - sunlight too. - */ - if(node_under_sunlight && ndef->get(n).sunlight_propagates) - { - n.setLight(LIGHTBANK_DAY, LIGHT_SUN, ndef); - } - - /* - Remove node metadata - */ + // Remove node metadata if (remove_metadata) { removeNodeMetadata(p); } - /* - Set the node on the map - */ - + // Set the node on the map setNode(p, n); - /* - If node is under sunlight and doesn't let sunlight through, - take all sunlighted nodes under it and clear light from them - and from where the light has been spread. - TODO: This could be optimized by mass-unlighting instead - of looping - */ - if(node_under_sunlight && !ndef->get(n).sunlight_propagates) - { - s16 y = p.Y - 1; - for(;; y--){ - //m_dout<<"y="<::iterator i = modified_blocks.begin(); i != modified_blocks.end(); ++i) @@ -1073,9 +836,7 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n, i->second->expireDayNightDiff(); } - /* - Report for rollback - */ + // Report for rollback if(m_gamedef->rollback()) { RollbackNode rollback_newnode(this, p, m_gamedef); @@ -1085,22 +846,23 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n, } /* - Add neighboring liquid nodes and the node itself if it is - liquid (=water node was added) to transform queue. - */ + Add neighboring liquid nodes and this node to transform queue. + (it's vital for the node itself to get updated last, if it was removed.) + */ v3s16 dirs[7] = { - v3s16(0,0,0), // self v3s16(0,0,1), // back v3s16(0,1,0), // top v3s16(1,0,0), // right v3s16(0,0,-1), // front v3s16(0,-1,0), // bottom v3s16(-1,0,0), // left + v3s16(0,0,0), // self }; for(u16 i=0; i<7; i++) { v3s16 p2 = p + dirs[i]; + bool is_valid_position; MapNode n2 = getNodeNoEx(p2, &is_valid_position); if(is_valid_position && (ndef->get(n2).isLiquid() || n2.getContent() == CONTENT_AIR)) @@ -1110,183 +872,10 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n, } } -/* -*/ void Map::removeNodeAndUpdate(v3s16 p, std::map &modified_blocks) { - INodeDefManager *ndef = m_gamedef->ndef(); - - /*PrintInfo(m_dout); - m_dout<<"Map::removeNodeAndUpdate(): p=(" - < light_sources; - - enum LightBank banks[] = - { - LIGHTBANK_DAY, - LIGHTBANK_NIGHT - }; - for(s32 i=0; i<2; i++) - { - enum LightBank bank = banks[i]; - - /* - Unlight neighbors (in case the node is a light source) - */ - unLightNeighbors(bank, p, - getNodeNoEx(p).getLight(bank, ndef), - light_sources, modified_blocks); - } - - /* - Remove node metadata - */ - - removeNodeMetadata(p); - - /* - Remove the node. - This also clears the lighting. - */ - - MapNode n(replace_material); - setNode(p, n); - - for(s32 i=0; i<2; i++) - { - enum LightBank bank = banks[i]; - - /* - Recalculate lighting - */ - spreadLight(bank, light_sources, modified_blocks); - } - - // Add the block of the removed node to modified_blocks - v3s16 blockpos = getNodeBlockPos(p); - MapBlock * block = getBlockNoCreate(blockpos); - assert(block != NULL); - modified_blocks[blockpos] = block; - - /* - If the removed node was under sunlight, propagate the - sunlight down from it and then light all neighbors - of the propagated blocks. - */ - if(node_under_sunlight) - { - s16 ybottom = propagateSunlight(p, modified_blocks); - /*m_dout<<"Node was under sunlight. " - "Propagating sunlight"; - m_dout<<" -> ybottom="<= ybottom; y--) - { - v3s16 p2(p.X, y, p.Z); - /*m_dout<<"lighting neighbors of node (" - <::iterator - i = modified_blocks.begin(); - i != modified_blocks.end(); ++i) - { - i->second->expireDayNightDiff(); - } - - /* - Report for rollback - */ - if(m_gamedef->rollback()) - { - RollbackNode rollback_newnode(this, p, m_gamedef); - RollbackAction action; - action.setSetNode(p, rollback_oldnode, rollback_newnode); - m_gamedef->rollback()->reportAction(action); - } - - /* - Add neighboring liquid nodes and this node to transform queue. - (it's vital for the node itself to get updated last.) - */ - v3s16 dirs[7] = { - v3s16(0,0,1), // back - v3s16(0,1,0), // top - v3s16(1,0,0), // right - v3s16(0,0,-1), // front - v3s16(0,-1,0), // bottom - v3s16(-1,0,0), // left - v3s16(0,0,0), // self - }; - for(u16 i=0; i<7; i++) - { - v3s16 p2 = p + dirs[i]; - - bool is_position_valid; - MapNode n2 = getNodeNoEx(p2, &is_position_valid); - if (is_position_valid - && (ndef->get(n2).isLiquid() || n2.getContent() == CONTENT_AIR)) - { - m_transforming_liquid.push_back(p2); - } - } + addNodeAndUpdate(p, MapNode(CONTENT_AIR), modified_blocks, true); } bool Map::addNodeWithEvent(v3s16 p, MapNode n, bool remove_metadata) diff --git a/src/map.h b/src/map.h index c73fa92bf..e8d40e982 100644 --- a/src/map.h +++ b/src/map.h @@ -211,24 +211,10 @@ public: std::set & light_sources, std::map & modified_blocks); - void unLightNeighbors(enum LightBank bank, - v3s16 pos, u8 lightwas, - std::set & light_sources, - std::map & modified_blocks); - void spreadLight(enum LightBank bank, std::set & from_nodes, std::map & modified_blocks); - - void lightNeighbors(enum LightBank bank, - v3s16 pos, - std::map & modified_blocks); - - v3s16 getBrightestNeighbour(enum LightBank bank, v3s16 p); - - s16 propagateSunlight(v3s16 start, - std::map & modified_blocks); - + void updateLighting(enum LightBank bank, std::map & a_blocks, std::map & modified_blocks); diff --git a/src/mapnode.cpp b/src/mapnode.cpp index eba47446d..5efebf3d8 100644 --- a/src/mapnode.cpp +++ b/src/mapnode.cpp @@ -54,10 +54,10 @@ MapNode::MapNode(INodeDefManager *ndef, const std::string &name, param2 = a_param2; } -void MapNode::setLight(enum LightBank bank, u8 a_light, INodeDefManager *nodemgr) +void MapNode::setLight(enum LightBank bank, u8 a_light, const ContentFeatures &f) { // If node doesn't contain light data, ignore this - if(nodemgr->get(*this).param_type != CPT_LIGHT) + if(f.param_type != CPT_LIGHT) return; if(bank == LIGHTBANK_DAY) { @@ -73,6 +73,11 @@ void MapNode::setLight(enum LightBank bank, u8 a_light, INodeDefManager *nodemgr assert("Invalid light bank" == NULL); } +void MapNode::setLight(enum LightBank bank, u8 a_light, INodeDefManager *nodemgr) +{ + setLight(bank, a_light, nodemgr->get(*this)); +} + bool MapNode::isLightDayNightEq(INodeDefManager *nodemgr) const { const ContentFeatures &f = nodemgr->get(*this); @@ -103,6 +108,13 @@ u8 MapNode::getLight(enum LightBank bank, INodeDefManager *nodemgr) const return MYMAX(f.light_source, light); } +u8 MapNode::getLightRaw(enum LightBank bank, const ContentFeatures &f) const +{ + if(f.param_type == CPT_LIGHT) + return bank == LIGHTBANK_DAY ? param1 & 0x0f : (param1 >> 4) & 0x0f; + return 0; +} + u8 MapNode::getLightNoChecks(enum LightBank bank, const ContentFeatures *f) const { return MYMAX(f->light_source, diff --git a/src/mapnode.h b/src/mapnode.h index 2f6224f02..0bd61c554 100644 --- a/src/mapnode.h +++ b/src/mapnode.h @@ -191,6 +191,8 @@ struct MapNode param2 = p; } + void setLight(enum LightBank bank, u8 a_light, const ContentFeatures &f); + void setLight(enum LightBank bank, u8 a_light, INodeDefManager *nodemgr); /** @@ -202,6 +204,13 @@ struct MapNode u8 getLight(enum LightBank bank, INodeDefManager *nodemgr) const; + /*! + * Returns the node's light level from param1. + * If the node emits light, it is ignored. + * \param f the ContentFeatures of this node. + */ + u8 getLightRaw(enum LightBank bank, const ContentFeatures &f) const; + /** * This function differs from getLight(enum LightBank bank, INodeDefManager *nodemgr) * in that the ContentFeatures of the node in question are not retrieved by diff --git a/src/voxelalgorithms.cpp b/src/voxelalgorithms.cpp index f067a221a..019ec1bc6 100644 --- a/src/voxelalgorithms.cpp +++ b/src/voxelalgorithms.cpp @@ -19,6 +19,9 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "voxelalgorithms.h" #include "nodedef.h" +#include "mapblock.h" +#include "map.h" +#include "util/timetaker.h" namespace voxalgo { @@ -153,5 +156,586 @@ SunlightPropagateResult propagateSunlight(VoxelManipulator &v, VoxelArea a, return SunlightPropagateResult(bottom_sunlight_valid); } +/*! + * A direction. + * 0=X+ + * 1=Y+ + * 2=Z+ + * 3=Z- + * 4=Y- + * 5=X- + * 6=no direction + * Two directions ate opposite only if their sum is 5. + */ +typedef u8 direction; +/*! + * Relative node position. + * This represents a node's position in its map block. + * All coordinates must be between 0 and 15. + */ +typedef v3s16 relative_v3; +/*! + * Position of a map block. + * One block_pos unit is as long as 16 node position units. + */ +typedef v3s16 mapblock_v3; + +//! Contains information about a node whose light is about to change. +struct ChangingLight { + //! Relative position of the node in its map block. + relative_v3 rel_position; + //! Position of the node's block. + mapblock_v3 block_position; + //! Reference to the node's block. + MapBlock *block; + /*! + * Direction from the node that caused this node's changing + * to this node. + */ + direction source_direction; + + ChangingLight() : + rel_position(), + block_position(), + block(NULL), + source_direction(6) + {} + + ChangingLight(relative_v3 rel_pos, mapblock_v3 block_pos, + MapBlock *b, direction source_dir) : + rel_position(rel_pos), + block_position(block_pos), + block(b), + source_direction(source_dir) + {} +}; + +/*! + * A fast, priority queue-like container to contain ChangingLights. + * The ChangingLights are ordered by the given light levels. + * The brightest ChangingLight is returned first. + */ +struct LightQueue { + //! For each light level there is a vector. + std::vector lights[LIGHT_SUN + 1]; + //! Light of the brightest ChangingLight in the queue. + u8 max_light; + + /*! + * Creates a LightQueue. + * \param reserve for each light level that many slots are reserved. + */ + LightQueue(size_t reserve) + { + max_light = LIGHT_SUN; + for (u8 i = 0; i <= LIGHT_SUN; i++) { + lights[i].reserve(reserve); + } + } + + /*! + * Returns the next brightest ChangingLight and + * removes it from the queue. + * If there were no elements in the queue, the given parameters + * remain unmodified. + * \param light light level of the popped ChangingLight + * \param data the ChangingLight that was popped + * \returns true if there was a ChangingLight in the queue. + */ + bool next(u8 &light, ChangingLight &data) + { + while (lights[max_light].empty()) { + if (max_light == 0) { + return false; + } + max_light--; + } + light = max_light; + data = lights[max_light].back(); + lights[max_light].pop_back(); + return true; + } + + /*! + * Adds an element to the queue. + * The parameters are the same as in ChangingLight's constructor. + * \param light light level of the ChangingLight + */ + inline void push(u8 light, relative_v3 &rel_pos, mapblock_v3 &block_pos, + MapBlock *block, direction source_dir) + { + lights[light].push_back( + ChangingLight(rel_pos, block_pos, block, source_dir)); + } +}; + +/*! + * This type of light queue is for unlighting. + * A node can be pushed in it only if its raw light is zero. + * This prevents pushing nodes twice into this queue. + * The light of the pushed ChangingLight must be the + * light of the node before unlighting it. + */ +typedef LightQueue UnlightQueue; +/*! + * This type of light queue is for spreading lights. + * While spreading lights, all the nodes in it must + * have the same light as the light level the ChangingLights + * were pushed into this queue with. This prevents unnecessary + * re-pushing of the nodes into the queue. + * If a node doesn't let light trough but emits light, it can be added + * too. + */ +typedef LightQueue ReLightQueue; + +/*! + * neighbor_dirs[i] points towards + * the direction i. + * See the definition of the type "direction" + */ +const static v3s16 neighbor_dirs[6] = { + v3s16(1, 0, 0), // right + v3s16(0, 1, 0), // top + v3s16(0, 0, 1), // back + v3s16(0, 0, -1), // front + v3s16(0, -1, 0), // bottom + v3s16(-1, 0, 0), // left +}; + +/*! + * Transforms the given map block offset by one node towards + * the specified direction. + * \param dir the direction of the transformation + * \param rel_pos the node's relative position in its map block + * \param block_pos position of the node's block + */ +bool stepRelBlockPos(direction dir, relative_v3 &rel_pos, + mapblock_v3 &block_pos) +{ + switch (dir) { + case 0: + if (rel_pos.X < MAP_BLOCKSIZE - 1) { + rel_pos.X++; + } else { + rel_pos.X = 0; + block_pos.X++; + return true; + } + break; + case 1: + if (rel_pos.Y < MAP_BLOCKSIZE - 1) { + rel_pos.Y++; + } else { + rel_pos.Y = 0; + block_pos.Y++; + return true; + } + break; + case 2: + if (rel_pos.Z < MAP_BLOCKSIZE - 1) { + rel_pos.Z++; + } else { + rel_pos.Z = 0; + block_pos.Z++; + return true; + } + break; + case 3: + if (rel_pos.Z > 0) { + rel_pos.Z--; + } else { + rel_pos.Z = MAP_BLOCKSIZE - 1; + block_pos.Z--; + return true; + } + break; + case 4: + if (rel_pos.Y > 0) { + rel_pos.Y--; + } else { + rel_pos.Y = MAP_BLOCKSIZE - 1; + block_pos.Y--; + return true; + } + break; + case 5: + if (rel_pos.X > 0) { + rel_pos.X--; + } else { + rel_pos.X = MAP_BLOCKSIZE - 1; + block_pos.X--; + return true; + } + break; + } + return false; +} + +/* + * Removes all light that is potentially emitted by the specified + * light sources. These nodes will have zero light. + * Returns all nodes whose light became zero but should be re-lighted. + * + * \param bank the light bank in which the procedure operates + * \param from_nodes nodes whose light is removed + * \param light_sources nodes that should be re-lighted + * \param modified_blocks output, all modified map blocks are added to this + */ +void unspreadLight(Map *map, INodeDefManager *nodemgr, LightBank bank, + UnlightQueue &from_nodes, ReLightQueue &light_sources, + std::map & modified_blocks) +{ + // Stores data popped from from_nodes + u8 current_light; + ChangingLight current; + // Data of the current neighbor + mapblock_v3 neighbor_block_pos; + relative_v3 neighbor_rel_pos; + // A dummy boolean + bool is_valid_position; + // Direction of the brightest neighbor of the node + direction source_dir; + while (from_nodes.next(current_light, current)) { + // For all nodes that need unlighting + + // There is no brightest neighbor + source_dir = 6; + // The current node + const MapNode &node = current.block->getNodeNoCheck( + current.rel_position, &is_valid_position); + const ContentFeatures &f = nodemgr->get(node); + // If the node emits light, it behaves like it had a + // brighter neighbor. + u8 brightest_neighbor_light = f.light_source + 1; + for (direction i = 0; i < 6; i++) { + //For each neighbor + + // The node that changed this node has already zero light + // and it can't give light to this node + if (current.source_direction + i == 5) { + continue; + } + // Get the neighbor's position and block + neighbor_rel_pos = current.rel_position; + neighbor_block_pos = current.block_position; + MapBlock *neighbor_block; + if (stepRelBlockPos(i, neighbor_rel_pos, neighbor_block_pos)) { + neighbor_block = map->getBlockNoCreateNoEx(neighbor_block_pos); + if (neighbor_block == NULL) { + continue; + } + } else { + neighbor_block = current.block; + } + // Get the neighbor itself + MapNode neighbor = neighbor_block->getNodeNoCheck(neighbor_rel_pos, + &is_valid_position); + const ContentFeatures &neighbor_f = nodemgr->get( + neighbor.getContent()); + u8 neighbor_light = neighbor.getLightRaw(bank, neighbor_f); + // If the neighbor has at least as much light as this node, then + // it won't lose its light, since it should have been added to + // from_nodes earlier, so its light would be zero. + if (neighbor_f.light_propagates && neighbor_light < current_light) { + // Unlight, but only if the node has light. + if (neighbor_light > 0) { + neighbor.setLight(bank, 0, neighbor_f); + neighbor_block->setNodeNoCheck(neighbor_rel_pos, neighbor); + from_nodes.push(neighbor_light, neighbor_rel_pos, + neighbor_block_pos, neighbor_block, i); + // The current node was modified earlier, so its block + // is in modified_blocks. + if (current.block != neighbor_block) { + modified_blocks[neighbor_block_pos] = neighbor_block; + } + } + } else { + // The neighbor can light up this node. + if (neighbor_light < neighbor_f.light_source) { + neighbor_light = neighbor_f.light_source; + } + if (brightest_neighbor_light < neighbor_light) { + brightest_neighbor_light = neighbor_light; + source_dir = i; + } + } + } + // If the brightest neighbor is able to light up this node, + // then add this node to the output nodes. + if (brightest_neighbor_light > 1 && f.light_propagates) { + brightest_neighbor_light--; + light_sources.push(brightest_neighbor_light, current.rel_position, + current.block_position, current.block, + (source_dir == 6) ? 6 : 5 - source_dir + /* with opposite direction*/); + } + } +} + +/* + * Spreads light from the specified starting nodes. + * + * Before calling this procedure, make sure that all ChangingLights + * in light_sources have as much light on the map as they have in + * light_sources (if the queue contains a node multiple times, the brightest + * occurrence counts). + * + * \param bank the light bank in which the procedure operates + * \param light_sources starting nodes + * \param modified_blocks output, all modified map blocks are added to this + */ +void spreadLight(Map *map, INodeDefManager *nodemgr, LightBank bank, + LightQueue & light_sources, std::map & modified_blocks) +{ + // The light the current node can provide to its neighbors. + u8 spreading_light; + // The ChangingLight for the current node. + ChangingLight current; + // Position of the current neighbor. + mapblock_v3 neighbor_block_pos; + relative_v3 neighbor_rel_pos; + // A dummy boolean. + bool is_valid_position; + while (light_sources.next(spreading_light, current)) { + spreading_light--; + for (direction i = 0; i < 6; i++) { + // This node can't light up its light source + if (current.source_direction + i == 5) { + continue; + } + // Get the neighbor's position and block + neighbor_rel_pos = current.rel_position; + neighbor_block_pos = current.block_position; + MapBlock *neighbor_block; + if (stepRelBlockPos(i, neighbor_rel_pos, neighbor_block_pos)) { + neighbor_block = map->getBlockNoCreateNoEx(neighbor_block_pos); + if (neighbor_block == NULL) { + continue; + } + } else { + neighbor_block = current.block; + } + // Get the neighbor itself + MapNode neighbor = neighbor_block->getNodeNoCheck(neighbor_rel_pos, + &is_valid_position); + const ContentFeatures &f = nodemgr->get(neighbor.getContent()); + if (f.light_propagates) { + // Light up the neighbor, if it has less light than it should. + u8 neighbor_light = neighbor.getLightRaw(bank, f); + if (neighbor_light < spreading_light) { + neighbor.setLight(bank, spreading_light, f); + neighbor_block->setNodeNoCheck(neighbor_rel_pos, neighbor); + light_sources.push(spreading_light, neighbor_rel_pos, + neighbor_block_pos, neighbor_block, i); + // The current node was modified earlier, so its block + // is in modified_blocks. + if (current.block != neighbor_block) { + modified_blocks[neighbor_block_pos] = neighbor_block; + } + } + } + } + } +} + +/*! + * Returns true if the node gets sunlight from the + * node above it. + * + * \param pos position of the node. + */ +bool isSunlightAbove(Map *map, v3s16 pos, INodeDefManager *ndef) +{ + bool sunlight = true; + mapblock_v3 source_block_pos; + relative_v3 source_rel_pos; + getNodeBlockPosWithOffset(pos + v3s16(0, 1, 0), source_block_pos, + source_rel_pos); + // If the node above has sunlight, this node also can get it. + MapBlock *source_block = map->getBlockNoCreateNoEx(source_block_pos); + if (source_block == NULL) { + // But if there is no node above, then use heuristics + MapBlock *node_block = map->getBlockNoCreateNoEx(getNodeBlockPos(pos)); + if (node_block == NULL) { + sunlight = false; + } else { + sunlight = !node_block->getIsUnderground(); + } + } else { + bool is_valid_position; + MapNode above = source_block->getNodeNoCheck(source_rel_pos, + &is_valid_position); + if (is_valid_position) { + if (above.getContent() == CONTENT_IGNORE) { + // Trust heuristics + if (source_block->getIsUnderground()) { + sunlight = false; + } + } else if (above.getLight(LIGHTBANK_DAY, ndef) != LIGHT_SUN) { + // If the node above doesn't have sunlight, this + // node is in shadow. + sunlight = false; + } + } + } + return sunlight; +} + +static const LightBank banks[] = { LIGHTBANK_DAY, LIGHTBANK_NIGHT }; + +void update_lighting_node(Map *map, INodeDefManager *ndef, v3s16 p, + MapNode oldnode, std::map & modified_blocks) +{ + // For node getter functions + bool is_valid_position; + + // Get position and block of the changed node + relative_v3 rel_pos; + mapblock_v3 block_pos; + getNodeBlockPosWithOffset(p, block_pos, rel_pos); + MapBlock *block = map->getBlockNoCreateNoEx(block_pos); + if (block == NULL || block->isDummy()) { + return; + } + + // Process each light bank separately + for (s32 i = 0; i < 2; i++) { + // Get the new node + MapNode n = block->getNodeNoCheck(rel_pos, &is_valid_position); + if (!is_valid_position) { + break; + } + LightBank bank = banks[i]; + + // Light of the old node + u8 old_light = oldnode.getLight(bank, ndef); + + // Add the block of the added node to modified_blocks + modified_blocks[block_pos] = block; + + // Get new light level of the node + u8 new_light = 0; + if (ndef->get(n).light_propagates) { + if (bank == LIGHTBANK_DAY && ndef->get(n).sunlight_propagates + && isSunlightAbove(map, p, ndef)) { + new_light = LIGHT_SUN; + } else { + new_light = ndef->get(n).light_source; + for (int i = 0; i < 6; i++) { + v3s16 p2 = p + neighbor_dirs[i]; + bool is_valid; + MapNode n2 = map->getNodeNoEx(p2, &is_valid); + if (is_valid) { + u8 spread = n2.getLight(bank, ndef); + // If the neighbor is at least as bright as + // this node then its light is not from + // this node. + // Its light can spread to this node. + if (spread > new_light && spread >= old_light) { + new_light = spread - 1; + } + } + } + } + } else { + // If this is an opaque node, it still can emit light. + new_light = ndef->get(n).light_source; + } + + ReLightQueue light_sources(256); + + if (new_light > 0) { + light_sources.push(new_light, rel_pos, block_pos, block, 6); + } + + if (new_light < old_light) { + // The node became opaque or doesn't provide as much + // light as the previous one, so it must be unlighted. + LightQueue disappearing_lights(256); + + // Add to unlight queue + n.setLight(bank, 0, ndef); + block->setNodeNoCheck(rel_pos, n); + disappearing_lights.push(old_light, rel_pos, block_pos, block, 6); + + // Remove sunlight, if there was any + if (bank == LIGHTBANK_DAY && old_light == LIGHT_SUN) { + for (s16 y = p.Y - 1;; y--) { + v3s16 n2pos(p.X, y, p.Z); + + MapNode n2; + + n2 = map->getNodeNoEx(n2pos, &is_valid_position); + if (!is_valid_position) + break; + + // If this node doesn't have sunlight, the nodes below + // it don't have too. + if (n2.getLight(LIGHTBANK_DAY, ndef) != LIGHT_SUN) { + break; + } + // Remove sunlight and add to unlight queue. + n2.setLight(LIGHTBANK_DAY, 0, ndef); + map->setNode(n2pos, n2); + relative_v3 rel_pos2; + mapblock_v3 block_pos2; + getNodeBlockPosWithOffset(n2pos, block_pos2, rel_pos2); + MapBlock *block2 = map->getBlockNoCreateNoEx(block_pos2); + disappearing_lights.push(LIGHT_SUN, rel_pos2, block_pos2, + block2, 4 /* The node above caused the change */); + } + } + // Remove lights + unspreadLight(map, ndef, bank, disappearing_lights, light_sources, + modified_blocks); + } else if (new_light > old_light) { + // It is sure that the node provides more light than the previous + // one, unlighting is not necessary. + // Propagate sunlight + if (bank == LIGHTBANK_DAY && new_light == LIGHT_SUN) { + for (s16 y = p.Y - 1;; y--) { + v3s16 n2pos(p.X, y, p.Z); + + MapNode n2; + + n2 = map->getNodeNoEx(n2pos, &is_valid_position); + if (!is_valid_position) + break; + + // This should not happen, but if the node has sunlight + // then the iteration should stop. + if (n2.getLight(LIGHTBANK_DAY, ndef) == LIGHT_SUN) { + break; + } + // If the node terminates sunlight, stop. + if (!ndef->get(n2).sunlight_propagates) { + break; + } + relative_v3 rel_pos2; + mapblock_v3 block_pos2; + getNodeBlockPosWithOffset(n2pos, block_pos2, rel_pos2); + MapBlock *block2 = map->getBlockNoCreateNoEx(block_pos2); + // Mark node for lighting. + light_sources.push(LIGHT_SUN, rel_pos2, block_pos2, block2, + 4); + } + } + } + // Initialize light values for light spreading. + for (u8 i = 0; i <= LIGHT_SUN; i++) { + const std::vector &lights = light_sources.lights[i]; + for (std::vector::const_iterator it = lights.begin(); + it < lights.end(); it++) { + MapNode n = it->block->getNodeNoCheck(it->rel_position, + &is_valid_position); + n.setLight(bank, i, ndef); + it->block->setNodeNoCheck(it->rel_position, n); + } + } + // Spread lights. + spreadLight(map, ndef, bank, light_sources, modified_blocks); + } +} + } // namespace voxalgo diff --git a/src/voxelalgorithms.h b/src/voxelalgorithms.h index 2eba6a176..f2b2fde32 100644 --- a/src/voxelalgorithms.h +++ b/src/voxelalgorithms.h @@ -25,6 +25,9 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include +class Map; +class MapBlock; + namespace voxalgo { @@ -52,6 +55,23 @@ SunlightPropagateResult propagateSunlight(VoxelManipulator &v, VoxelArea a, std::set & light_sources, INodeDefManager *ndef); +/*! + * Updates the lighting on the map. + * The result will be correct only if + * no nodes were changed except the given one. + * + * \param p position of the changed node + * \param oldnode this node was overwritten on the map + * \param modified_blocks output, contains all map blocks that + * the function modified + */ +void update_lighting_node( + Map *map, + INodeDefManager *ndef, + v3s16 p, + MapNode oldnode, + std::map &modified_blocks); + } // namespace voxalgo #endif -- cgit v1.2.3