diff --git a/src/biome.cpp b/src/biome.cpp index e68429ef..83d4e7a4 100644 --- a/src/biome.cpp +++ b/src/biome.cpp @@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "nodedef.h" #include "map.h" //for ManualMapVoxelManipulator #include "log.h" +#include "util/numeric.h" #include "main.h" @@ -203,3 +204,54 @@ u8 BiomeDefManager::getBiomeIdByName(const char *name) { return 0; } + + +///////////////////////////// Weather + + +s16 BiomeDefManager::calcBlockHeat(v3s16 p, u64 seed, float timeofday, float totaltime) { + //variant 1: full random + //f32 heat = NoisePerlin3D(np_heat, p.X, env->getGameTime()/100, p.Z, seed); + + //variant 2: season change based on default heat map + const f32 offset = 20; // = np_heat->offset + const f32 scale = 20; // = np_heat->scale + const f32 range = 20; + f32 heat = NoisePerlin2D(np_heat, p.X, p.Z, seed); // 0..50..100 + + heat -= np_heat->offset; // -50..0..+50 + + // normalizing - todo REMOVE after fixed NoiseParams nparams_biome_def_heat = {50, 50, -> 20, 50, + if (np_heat->scale) + heat /= np_heat->scale / scale; // -20..0..+20 + + f32 seasonv = totaltime; + seasonv /= 86400 * g_settings->getS16("year_days"); // season change speed + seasonv += (f32)p.X / 3000; // you can walk to area with other season + seasonv = sin(seasonv * M_PI); + heat += (range * (heat < 0 ? 2 : 0.5)) * seasonv; // -60..0..30 + + heat += offset; // -40..0..50 + heat += p.Y / -333; // upper=colder, lower=hotter, 3c per 1000 + + // daily change, hotter at sun +4, colder at night -4 + heat += 8 * (sin(cycle_shift(timeofday, -0.25) * M_PI) - 0.5); //-44..20..54 + + return heat; +} + + +s16 BiomeDefManager::calcBlockHumidity(v3s16 p, u64 seed, float timeofday, float totaltime) { + + f32 humidity = NoisePerlin2D(np_humidity, p.X, p.Z, seed); + + f32 seasonv = totaltime; + seasonv /= 86400 * 2; // bad weather change speed (2 days) + seasonv += (f32)p.Z / 300; + humidity += 30 * sin(seasonv * M_PI); + + humidity += -12 * (sin(cycle_shift(timeofday, -0.1) * M_PI) - 0.5); + humidity = rangelim(humidity, 0, 100); + + return humidity; +} diff --git a/src/biome.h b/src/biome.h index cf3bd1b9..aa83c4e0 100644 --- a/src/biome.h +++ b/src/biome.h @@ -91,6 +91,9 @@ public: void addBiome(Biome *b); void resolveNodeNames(INodeDefManager *ndef); u8 getBiomeIdByName(const char *name); + + s16 calcBlockHeat(v3s16 p, u64 seed, float timeofday, float totaltime); + s16 calcBlockHumidity(v3s16 p, u64 seed, float timeofday, float totaltime); }; #endif diff --git a/src/constants.h b/src/constants.h index 8c478ac6..17f5d389 100644 --- a/src/constants.h +++ b/src/constants.h @@ -89,5 +89,11 @@ with this program; if not, write to the Free Software Foundation, Inc., // Maximum hit points of a player #define PLAYER_MAX_HP 20 +/* + Environmental condition constants +*/ +#define HEAT_UNDEFINED (-0x7fff-1) +#define HUMIDITY_UNDEFINED (-0x7fff-1) + #endif diff --git a/src/content_abm.cpp b/src/content_abm.cpp index 6e2d438f..fa6a128e 100644 --- a/src/content_abm.cpp +++ b/src/content_abm.cpp @@ -253,7 +253,7 @@ class LiquidFreeze : public ActiveBlockModifier { ServerMap *map = &env->getServerMap(); INodeDefManager *ndef = env->getGameDef()->ndef(); - float heat = map->getHeat(env, p); + float heat = map->updateBlockHeat(env, p); //heater = rare content_t c = map->getNodeNoEx(p - v3s16(0, -1, 0 )).getContent(); // top //more chance to freeze if air at top @@ -315,7 +315,7 @@ class LiquidMeltWeather : public ActiveBlockModifier { ServerMap *map = &env->getServerMap(); INodeDefManager *ndef = env->getGameDef()->ndef(); - float heat = map->getHeat(env, p); + float heat = map->updateBlockHeat(env, p); content_t c = map->getNodeNoEx(p - v3s16(0, -1, 0 )).getContent(); // top if (heat >= 1 && (heat >= 40 || ((myrand_range(heat, 40)) >= (c == CONTENT_AIR ? 10 : 20)))) { n.freezeMelt(ndef); @@ -378,7 +378,7 @@ void add_legacy_abms(ServerEnvironment *env, INodeDefManager *nodedef) { env->addActiveBlockModifier(new LiquidDropABM(env, nodedef)); env->addActiveBlockModifier(new LiquidMeltHot(env, nodedef)); //env->addActiveBlockModifier(new LiquidMeltAround(env, nodedef)); - if (g_settings->getBool("weather")) { + if (env->m_use_weather) { env->addActiveBlockModifier(new LiquidFreeze(env, nodedef)); env->addActiveBlockModifier(new LiquidMeltWeather(env, nodedef)); } diff --git a/src/emerge.cpp b/src/emerge.cpp index a81ff7d9..ed9aa904 100644 --- a/src/emerge.cpp +++ b/src/emerge.cpp @@ -512,8 +512,7 @@ void *EmergeThread::Thread() { ign(&m_server->m_ignore_map_edit_events_area, VoxelArea(minp, maxp)); { // takes about 90ms with -O1 on an e3-1230v2 - m_server->getScriptIface()-> - environment_OnGenerated( + m_server->getScriptIface()->environment_OnGenerated( minp, maxp, emerge->getBlockSeed(minp)); } @@ -535,14 +534,6 @@ void *EmergeThread::Thread() { if (block) modified_blocks[p] = block; - // Update weather data in mapblock - for(std::map::iterator - i = modified_blocks.begin(); - i != modified_blocks.end(); ++i) { - map->getHeat(m_server->m_env, MAP_BLOCKSIZE*i->first ,i->second); - map->getHumidity(m_server->m_env, MAP_BLOCKSIZE*i->first, i->second); - } - // Set the modified blocks unsent for all the clients for (std::map::iterator i = m_server->m_clients.begin(); diff --git a/src/environment.cpp b/src/environment.cpp index 86c98f2c..03b43689 100644 --- a/src/environment.cpp +++ b/src/environment.cpp @@ -322,6 +322,7 @@ ServerEnvironment::ServerEnvironment(ServerMap *map, m_recommended_send_interval(0.1), m_max_lag_estimate(0.1) { + m_use_weather = g_settings->getBool("weather"); } ServerEnvironment::~ServerEnvironment() @@ -808,6 +809,16 @@ void ServerEnvironment::activateBlock(MapBlock *block, u32 additional_dtime) // Activate stored objects activateObjects(block, dtime_s); + + // Calculate weather conditions + if (m_use_weather) { + m_map->updateBlockHeat(this, block->getPos() * MAP_BLOCKSIZE, block); + m_map->updateBlockHumidity(this, block->getPos() * MAP_BLOCKSIZE, block); + } else { + block->heat = HEAT_UNDEFINED; + block->humidity = HUMIDITY_UNDEFINED; + block->weather_update_time = 0; + } // Run node timers std::map elapsed_timers = diff --git a/src/environment.h b/src/environment.h index 597ad5ff..86654937 100644 --- a/src/environment.h +++ b/src/environment.h @@ -300,6 +300,10 @@ public: void reportMaxLagEstimate(float f) { m_max_lag_estimate = f; } float getMaxLagEstimate() { return m_max_lag_estimate; } + + // is weather active in this environment? + bool m_use_weather; + private: /* diff --git a/src/map.cpp b/src/map.cpp index a8fbbac2..08f255de 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -39,6 +39,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "mapgen_v6.h" #include "biome.h" #include "config.h" +#include "server.h" #include "database.h" #include "database-dummy.h" #include "database-sqlite3.h" @@ -2824,6 +2825,38 @@ MapBlock* ServerMap::finishBlockMake(BlockMakeData *data, /*infostream<<"finishBlockMake() done for ("<getEnv(); + if (senv->m_use_weather) { + for(s16 x=blockpos_min.X-extra_borders.X; + x<=blockpos_max.X+extra_borders.X; x++) + for(s16 z=blockpos_min.Z-extra_borders.Z; + z<=blockpos_max.Z+extra_borders.Z; z++) + for(s16 y=blockpos_min.Y-extra_borders.Y; + y<=blockpos_max.Y+extra_borders.Y; y++) + { + v3s16 p(x, y, z); + updateBlockHeat(senv, p * MAP_BLOCKSIZE, NULL); + updateBlockHumidity(senv, p * MAP_BLOCKSIZE, NULL); + } + } else { + for(s16 x=blockpos_min.X-extra_borders.X; + x<=blockpos_max.X+extra_borders.X; x++) + for(s16 z=blockpos_min.Z-extra_borders.Z; + z<=blockpos_max.Z+extra_borders.Z; z++) + for(s16 y=blockpos_min.Y-extra_borders.Y; + y<=blockpos_max.Y+extra_borders.Y; y++) + { + MapBlock *block = getBlockNoCreateNoEx(v3s16(x, y, z)); + block->heat = HEAT_UNDEFINED; + block->humidity = HUMIDITY_UNDEFINED; + block->weather_update_time = 0; + } + } + #if 0 if(enable_mapgen_debug_info) { @@ -3888,74 +3921,41 @@ void ServerMap::PrintInfo(std::ostream &out) out<<"ServerMap: "; } -s16 ServerMap::getHeat(ServerEnvironment *env, v3s16 p, MapBlock *block) +s16 ServerMap::updateBlockHeat(ServerEnvironment *env, v3s16 p, MapBlock *block) { - if(block == NULL) - block = getBlockNoCreateNoEx(getNodeBlockPos(p)); - if(block != NULL) { - if (env->getGameTime() - block->heat_time < 10) + u32 gametime = env->getGameTime(); + + if (block) { + if (gametime - block->weather_update_time < 10) return block->heat; + } else { + block = getBlockNoCreateNoEx(getNodeBlockPos(p)); } - //variant 1: full random - //f32 heat = NoisePerlin3D(m_emerge->biomedef->np_heat, p.X, env->getGameTime()/100, p.Z, m_emerge->params->seed); + f32 heat = m_emerge->biomedef->calcBlockHeat(p, m_seed, + env->getTimeOfDayF(), gametime * env->getTimeOfDaySpeed()); - //variant 2: season change based on default heat map - const f32 offset = 20; // = m_emerge->biomedef->np_heat->offset - const f32 scale = 20; // = m_emerge->biomedef->np_heat->scale - const f32 range = 20; - f32 heat = NoisePerlin2D(m_emerge->biomedef->np_heat, p.X, p.Z, - m_emerge->params->seed); // 0..50..100 - - heat -= m_emerge->biomedef->np_heat->offset; // -50..0..+50 - - // normalizing - todo REMOVE after fixed NoiseParams nparams_biome_def_heat = {50, 50, -> 20, 50, - if(m_emerge->biomedef->np_heat->scale) - heat /= m_emerge->biomedef->np_heat->scale / scale; // -20..0..+20 - - f32 seasonv = (f32)env->getGameTime() * env->getTimeOfDaySpeed(); - seasonv /= 86400 * g_settings->getS16("year_days"); // season change speed - seasonv += (f32)p.X / 3000; // you can walk to area with other season - seasonv = sin(seasonv * M_PI); - heat += (range * (heat < 0 ? 2 : 0.5)) * seasonv; // -60..0..30 - - heat += offset; // -40..0..50 - heat += p.Y / -333; // upper=colder, lower=hotter, 3c per 1000 - - // daily change, hotter at sun +4, colder at night -4 - heat += 8 * (sin(cycle_shift(env->getTimeOfDayF(), -0.25) * M_PI) - 0.5); //-44..20..54 - - if(block != NULL) { - block->heat = heat; - block->heat_time = env->getGameTime(); - } + block->heat = heat; + block->weather_update_time = gametime; return heat; } -s16 ServerMap::getHumidity(ServerEnvironment *env, v3s16 p, MapBlock *block) +s16 ServerMap::updateBlockHumidity(ServerEnvironment *env, v3s16 p, MapBlock *block) { - if(block == NULL) - block = getBlockNoCreateNoEx(getNodeBlockPos(p)); - if(block != NULL) { - if (env->getGameTime() - block->humidity_time < 10) + u32 gametime = env->getGameTime(); + + if (block) { + if (gametime - block->weather_update_time < 10) return block->humidity; + } else { + block = getBlockNoCreateNoEx(getNodeBlockPos(p)); } - f32 humidity = NoisePerlin2D(m_emerge->biomedef->np_humidity, p.X, p.Z, - m_emerge->params->seed); - - f32 seasonv = (f32)env->getGameTime() * env->getTimeOfDaySpeed(); - seasonv /= 86400 * 2; // bad weather change speed (2 days) - seasonv += (f32)p.Z / 300; - humidity += 30 * sin(seasonv * M_PI); - - humidity += -12 * ( sin(cycle_shift(env->getTimeOfDayF(), -0.1) * M_PI) - 0.5); - humidity = rangelim(humidity, 0, 100); - - if(block != NULL) { - block->humidity = humidity; - block->humidity_time = env->getGameTime(); - } + f32 humidity = m_emerge->biomedef->calcBlockHumidity(p, m_seed, + env->getTimeOfDayF(), gametime * env->getTimeOfDaySpeed()); + + block->humidity = humidity; + block->weather_update_time = gametime; return humidity; } diff --git a/src/map.h b/src/map.h index 34456d68..b70b18ac 100644 --- a/src/map.h +++ b/src/map.h @@ -477,8 +477,8 @@ public: // Parameters fed to the Mapgen MapgenParams *m_mgparams; - virtual s16 getHeat(ServerEnvironment *env, v3s16 p, MapBlock *block = NULL); - virtual s16 getHumidity(ServerEnvironment *env, v3s16 p, MapBlock *block = NULL); + virtual s16 updateBlockHeat(ServerEnvironment *env, v3s16 p, MapBlock *block = NULL); + virtual s16 updateBlockHumidity(ServerEnvironment *env, v3s16 p, MapBlock *block = NULL); private: // Seed used for all kinds of randomness in generation diff --git a/src/mapblock.cpp b/src/mapblock.cpp index b8278b3b..3fb2ec5e 100644 --- a/src/mapblock.cpp +++ b/src/mapblock.cpp @@ -44,9 +44,8 @@ with this program; if not, write to the Free Software Foundation, Inc., MapBlock::MapBlock(Map *parent, v3s16 pos, IGameDef *gamedef, bool dummy): heat(0), - heat_time(0), humidity(0), - humidity_time(0), + weather_update_time(0), m_parent(parent), m_pos(pos), m_gamedef(gamedef), diff --git a/src/mapblock.h b/src/mapblock.h index de49e613..e0730ffc 100644 --- a/src/mapblock.h +++ b/src/mapblock.h @@ -515,9 +515,8 @@ public: StaticObjectList m_static_objects; s16 heat; - u32 heat_time; s16 humidity; - u32 humidity_time; + u32 weather_update_time; private: /* diff --git a/src/script/lua_api/l_env.cpp b/src/script/lua_api/l_env.cpp index 8b0d8cd6..436eb014 100644 --- a/src/script/lua_api/l_env.cpp +++ b/src/script/lua_api/l_env.cpp @@ -764,7 +764,7 @@ int ModApiEnvMod::l_get_heat(lua_State *L) GET_ENV_PTR; v3s16 pos = read_v3s16(L, 1); - lua_pushnumber(L, env->getServerMap().getHeat(env, pos)); + lua_pushnumber(L, env->getServerMap().updateBlockHeat(env, pos)); return 1; } @@ -775,7 +775,7 @@ int ModApiEnvMod::l_get_humidity(lua_State *L) GET_ENV_PTR; v3s16 pos = read_v3s16(L, 1); - lua_pushnumber(L, env->getServerMap().getHumidity(env, pos)); + lua_pushnumber(L, env->getServerMap().updateBlockHumidity(env, pos)); return 1; } diff --git a/src/server.h b/src/server.h index d502d68a..bc7829f7 100644 --- a/src/server.h +++ b/src/server.h @@ -489,6 +489,7 @@ public: bool showFormspec(const char *name, const std::string &formspec, const std::string &formname); Map & getMap() { return m_env->getMap(); } + ServerEnvironment & getEnv() { return *m_env; } u32 hudAdd(Player *player, HudElement *element); bool hudRemove(Player *player, u32 id);