diff options
Diffstat (limited to 'src/environment.cpp')
-rw-r--r-- | src/environment.cpp | 644 |
1 files changed, 486 insertions, 158 deletions
diff --git a/src/environment.cpp b/src/environment.cpp index dbbfc6f1f..413bc7ff1 100644 --- a/src/environment.cpp +++ b/src/environment.cpp @@ -44,19 +44,27 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "map.h" #include "emerge.h" #include "util/serialize.h" -#include "jthread/jmutexautolock.h" +#include "threading/mutex_auto_lock.h" #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")" +#define LBM_NAME_ALLOWED_CHARS "abcdefghijklmnopqrstuvwxyz0123456789_:" + +// A number that is much smaller than the timeout for particle spawners should/could ever be +#define PARTICLE_SPAWNER_NO_EXPIRY -1024.f + Environment::Environment(): + m_time_of_day_speed(0), m_time_of_day(9000), m_time_of_day_f(9000./24000), - m_time_of_day_speed(0), - m_time_counter(0), + m_time_conversion_skew(0.0f), m_enable_day_night_ratio_override(false), m_day_night_ratio_override(0.0f) { m_cache_enable_shaders = g_settings->getBool("enable_shaders"); + m_cache_active_block_mgmt_interval = g_settings->getFloat("active_block_mgmt_interval"); + m_cache_abm_interval = g_settings->getFloat("abm_interval"); + m_cache_nodetimer_interval = g_settings->getFloat("nodetimer_interval"); } Environment::~Environment() @@ -70,7 +78,7 @@ Environment::~Environment() void Environment::addPlayer(Player *player) { - DSTACK(__FUNCTION_NAME); + DSTACK(FUNCTION_NAME); /* Check that peer_ids are unique. Also check that names are unique. @@ -85,28 +93,11 @@ void Environment::addPlayer(Player *player) m_players.push_back(player); } -void Environment::removePlayer(u16 peer_id) -{ - DSTACK(__FUNCTION_NAME); - - for(std::vector<Player*>::iterator i = m_players.begin(); - i != m_players.end();) - { - Player *player = *i; - if(player->peer_id == peer_id) { - delete player; - i = m_players.erase(i); - } else { - ++i; - } - } -} - -void Environment::removePlayer(const char *name) +void Environment::removePlayer(Player* player) { for (std::vector<Player*>::iterator it = m_players.begin(); it != m_players.end(); ++it) { - if (strcmp((*it)->getName(), name) == 0) { + if ((*it) == player) { delete *it; m_players.erase(it); return; @@ -197,74 +188,91 @@ std::vector<Player*> Environment::getPlayers(bool ignore_disconnected) u32 Environment::getDayNightRatio() { - if(m_enable_day_night_ratio_override) + MutexAutoLock lock(this->m_time_lock); + if (m_enable_day_night_ratio_override) return m_day_night_ratio_override; - return time_to_daynight_ratio(m_time_of_day_f*24000, m_cache_enable_shaders); + return time_to_daynight_ratio(m_time_of_day_f * 24000, m_cache_enable_shaders); } void Environment::setTimeOfDaySpeed(float speed) { - JMutexAutoLock(this->m_timeofday_lock); m_time_of_day_speed = speed; } float Environment::getTimeOfDaySpeed() { - JMutexAutoLock(this->m_timeofday_lock); - float retval = m_time_of_day_speed; - return retval; + return m_time_of_day_speed; +} + +void Environment::setDayNightRatioOverride(bool enable, u32 value) +{ + MutexAutoLock lock(this->m_time_lock); + m_enable_day_night_ratio_override = enable; + m_day_night_ratio_override = value; } void Environment::setTimeOfDay(u32 time) { - JMutexAutoLock(this->m_time_lock); + MutexAutoLock lock(this->m_time_lock); + if (m_time_of_day > time) + m_day_count++; m_time_of_day = time; m_time_of_day_f = (float)time / 24000.0; } u32 Environment::getTimeOfDay() { - JMutexAutoLock(this->m_time_lock); - u32 retval = m_time_of_day; - return retval; + MutexAutoLock lock(this->m_time_lock); + return m_time_of_day; } float Environment::getTimeOfDayF() { - JMutexAutoLock(this->m_time_lock); - float retval = m_time_of_day_f; - return retval; + MutexAutoLock lock(this->m_time_lock); + return m_time_of_day_f; } void Environment::stepTimeOfDay(float dtime) { - // getTimeOfDaySpeed lock the value we need to prevent MT problems - float day_speed = getTimeOfDaySpeed(); + MutexAutoLock lock(this->m_time_lock); + + // Cached in order to prevent the two reads we do to give + // different results (can be written by code not under the lock) + f32 cached_time_of_day_speed = m_time_of_day_speed; - m_time_counter += dtime; - f32 speed = day_speed * 24000./(24.*3600); - u32 units = (u32)(m_time_counter*speed); + f32 speed = cached_time_of_day_speed * 24000. / (24. * 3600); + m_time_conversion_skew += dtime; + u32 units = (u32)(m_time_conversion_skew * speed); bool sync_f = false; - if(units > 0){ + if (units > 0) { // Sync at overflow - if(m_time_of_day + units >= 24000) + if (m_time_of_day + units >= 24000) { sync_f = true; + m_day_count++; + } m_time_of_day = (m_time_of_day + units) % 24000; - if(sync_f) + if (sync_f) m_time_of_day_f = (float)m_time_of_day / 24000.0; } if (speed > 0) { - m_time_counter -= (f32)units / speed; + m_time_conversion_skew -= (f32)units / speed; } - if(!sync_f){ - m_time_of_day_f += day_speed/24/3600*dtime; - if(m_time_of_day_f > 1.0) + if (!sync_f) { + m_time_of_day_f += cached_time_of_day_speed / 24 / 3600 * dtime; + if (m_time_of_day_f > 1.0) m_time_of_day_f -= 1.0; - if(m_time_of_day_f < 0.0) + if (m_time_of_day_f < 0.0) m_time_of_day_f += 1.0; } } +u32 Environment::getDayCount() +{ + // Atomic<u32> counter + return m_day_count; +} + + /* ABMWithState */ @@ -282,6 +290,223 @@ ABMWithState::ABMWithState(ActiveBlockModifier *abm_): } /* + LBMManager +*/ + +void LBMContentMapping::deleteContents() +{ + for (std::vector<LoadingBlockModifierDef *>::iterator it = lbm_list.begin(); + it != lbm_list.end(); ++it) { + delete *it; + } +} + +void LBMContentMapping::addLBM(LoadingBlockModifierDef *lbm_def, IGameDef *gamedef) +{ + // Add the lbm_def to the LBMContentMapping. + // Unknown names get added to the global NameIdMapping. + INodeDefManager *nodedef = gamedef->ndef(); + + lbm_list.push_back(lbm_def); + + for (std::set<std::string>::const_iterator it = lbm_def->trigger_contents.begin(); + it != lbm_def->trigger_contents.end(); ++it) { + std::set<content_t> c_ids; + bool found = nodedef->getIds(*it, c_ids); + if (!found) { + content_t c_id = gamedef->allocateUnknownNodeId(*it); + if (c_id == CONTENT_IGNORE) { + // Seems it can't be allocated. + warningstream << "Could not internalize node name \"" << *it + << "\" while loading LBM \"" << lbm_def->name << "\"." << std::endl; + continue; + } + c_ids.insert(c_id); + } + + for (std::set<content_t>::const_iterator iit = + c_ids.begin(); iit != c_ids.end(); ++iit) { + content_t c_id = *iit; + map[c_id].push_back(lbm_def); + } + } +} + +const std::vector<LoadingBlockModifierDef *> * + LBMContentMapping::lookup(content_t c) const +{ + container_map::const_iterator it = map.find(c); + if (it == map.end()) + return NULL; + // This first dereferences the iterator, returning + // a std::vector<LoadingBlockModifierDef *> + // reference, then we convert it to a pointer. + return &(it->second); +} + +LBMManager::~LBMManager() +{ + for (std::map<std::string, LoadingBlockModifierDef *>::iterator it = + m_lbm_defs.begin(); it != m_lbm_defs.end(); ++it) { + delete it->second; + } + for (lbm_lookup_map::iterator it = m_lbm_lookup.begin(); + it != m_lbm_lookup.end(); ++it) { + (it->second).deleteContents(); + } +} + +void LBMManager::addLBMDef(LoadingBlockModifierDef *lbm_def) +{ + // Precondition, in query mode the map isn't used anymore + FATAL_ERROR_IF(m_query_mode == true, + "attempted to modify LBMManager in query mode"); + + if (!string_allowed(lbm_def->name, LBM_NAME_ALLOWED_CHARS)) { + throw ModError("Error adding LBM \"" + lbm_def->name + + "\": Does not follow naming conventions: " + "Only chararacters [a-z0-9_:] are allowed."); + } + + m_lbm_defs[lbm_def->name] = lbm_def; +} + +void LBMManager::loadIntroductionTimes(const std::string ×, + IGameDef *gamedef, u32 now) +{ + m_query_mode = true; + + // name -> time map. + // Storing it in a map first instead of + // handling the stuff directly in the loop + // removes all duplicate entries. + // TODO make this std::unordered_map + std::map<std::string, u32> introduction_times; + + /* + The introduction times string consists of name~time entries, + with each entry terminated by a semicolon. The time is decimal. + */ + + size_t idx = 0; + size_t idx_new; + while ((idx_new = times.find(";", idx)) != std::string::npos) { + std::string entry = times.substr(idx, idx_new - idx); + std::vector<std::string> components = str_split(entry, '~'); + if (components.size() != 2) + throw SerializationError("Introduction times entry \"" + + entry + "\" requires exactly one '~'!"); + const std::string &name = components[0]; + u32 time = from_string<u32>(components[1]); + introduction_times[name] = time; + idx = idx_new + 1; + } + + // Put stuff from introduction_times into m_lbm_lookup + for (std::map<std::string, u32>::const_iterator it = introduction_times.begin(); + it != introduction_times.end(); ++it) { + const std::string &name = it->first; + u32 time = it->second; + + std::map<std::string, LoadingBlockModifierDef *>::iterator def_it = + m_lbm_defs.find(name); + if (def_it == m_lbm_defs.end()) { + // This seems to be an LBM entry for + // an LBM we haven't loaded. Discard it. + continue; + } + LoadingBlockModifierDef *lbm_def = def_it->second; + if (lbm_def->run_at_every_load) { + // This seems to be an LBM entry for + // an LBM that runs at every load. + // Don't add it just yet. + continue; + } + + m_lbm_lookup[time].addLBM(lbm_def, gamedef); + + // Erase the entry so that we know later + // what elements didn't get put into m_lbm_lookup + m_lbm_defs.erase(name); + } + + // Now also add the elements from m_lbm_defs to m_lbm_lookup + // that weren't added in the previous step. + // They are introduced first time to this world, + // or are run at every load (introducement time hardcoded to U32_MAX). + + LBMContentMapping &lbms_we_introduce_now = m_lbm_lookup[now]; + LBMContentMapping &lbms_running_always = m_lbm_lookup[U32_MAX]; + + for (std::map<std::string, LoadingBlockModifierDef *>::iterator it = + m_lbm_defs.begin(); it != m_lbm_defs.end(); ++it) { + if (it->second->run_at_every_load) { + lbms_running_always.addLBM(it->second, gamedef); + } else { + lbms_we_introduce_now.addLBM(it->second, gamedef); + } + } + + // Clear the list, so that we don't delete remaining elements + // twice in the destructor + m_lbm_defs.clear(); +} + +std::string LBMManager::createIntroductionTimesString() +{ + // Precondition, we must be in query mode + FATAL_ERROR_IF(m_query_mode == false, + "attempted to query on non fully set up LBMManager"); + + std::ostringstream oss; + for (lbm_lookup_map::iterator it = m_lbm_lookup.begin(); + it != m_lbm_lookup.end(); ++it) { + u32 time = it->first; + std::vector<LoadingBlockModifierDef *> &lbm_list = it->second.lbm_list; + for (std::vector<LoadingBlockModifierDef *>::iterator iit = lbm_list.begin(); + iit != lbm_list.end(); ++iit) { + // Don't add if the LBM runs at every load, + // then introducement time is hardcoded + // and doesn't need to be stored + if ((*iit)->run_at_every_load) + continue; + oss << (*iit)->name << "~" << time << ";"; + } + } + return oss.str(); +} + +void LBMManager::applyLBMs(ServerEnvironment *env, MapBlock *block, u32 stamp) +{ + // Precondition, we need m_lbm_lookup to be initialized + FATAL_ERROR_IF(m_query_mode == false, + "attempted to query on non fully set up LBMManager"); + v3s16 pos_of_block = block->getPosRelative(); + v3s16 pos; + MapNode n; + content_t c; + lbm_lookup_map::const_iterator it = getLBMsIntroducedAfter(stamp); + for (pos.X = 0; pos.X < MAP_BLOCKSIZE; pos.X++) + for (pos.Y = 0; pos.Y < MAP_BLOCKSIZE; pos.Y++) + for (pos.Z = 0; pos.Z < MAP_BLOCKSIZE; pos.Z++) + { + n = block->getNodeNoEx(pos); + c = n.getContent(); + for (LBMManager::lbm_lookup_map::const_iterator iit = it; + iit != m_lbm_lookup.end(); ++iit) { + const std::vector<LoadingBlockModifierDef *> *lbm_list = + iit->second.lookup(c); + if (!lbm_list) + continue; + for (std::vector<LoadingBlockModifierDef *>::const_iterator iit = + lbm_list->begin(); iit != lbm_list->end(); ++iit) { + (*iit)->trigger(env, pos + pos_of_block, n); + } + } + } +} + +/* ActiveBlockList */ @@ -365,6 +590,7 @@ ServerEnvironment::ServerEnvironment(ServerMap *map, m_active_block_interval_overload_skip(0), m_game_time(0), m_game_time_fraction_counter(0), + m_last_clear_objects_time(0), m_recommended_send_interval(0.1), m_max_lag_estimate(0.1) { @@ -453,15 +679,12 @@ void ServerEnvironment::saveLoadedPlayers() } } -void ServerEnvironment::savePlayer(const std::string &playername) +void ServerEnvironment::savePlayer(RemotePlayer *player) { std::string players_path = m_path_world + DIR_DELIM "players"; fs::CreateDir(players_path); - RemotePlayer *player = static_cast<RemotePlayer*>(getPlayer(playername.c_str())); - if (player) { - player->save(players_path); - } + player->save(players_path); } Player *ServerEnvironment::loadPlayer(const std::string &playername) @@ -517,6 +740,11 @@ void ServerEnvironment::saveMeta() Settings args; args.setU64("game_time", m_game_time); args.setU64("time_of_day", getTimeOfDay()); + args.setU64("last_clear_objects_time", m_last_clear_objects_time); + args.setU64("lbm_introduction_times_version", 1); + args.set("lbm_introduction_times", + m_lbm_mgr.createIntroductionTimesString()); + args.setU64("day_count", m_day_count); args.writeLines(ss); ss<<"EnvArgsEnd\n"; @@ -554,12 +782,35 @@ void ServerEnvironment::loadMeta() throw SerializationError("Couldn't load env meta game_time"); } + setTimeOfDay(args.exists("time_of_day") ? + // set day to morning by default + args.getU64("time_of_day") : 9000); + + m_last_clear_objects_time = args.exists("last_clear_objects_time") ? + // If missing, do as if clearObjects was never called + args.getU64("last_clear_objects_time") : 0; + + std::string lbm_introduction_times = ""; try { - m_time_of_day = args.getU64("time_of_day"); + u64 ver = args.getU64("lbm_introduction_times_version"); + if (ver == 1) { + lbm_introduction_times = args.get("lbm_introduction_times"); + } else { + infostream << "ServerEnvironment::loadMeta(): Non-supported" + << " introduction time version " << ver << std::endl; + } } catch (SettingNotFoundException &e) { - // This is not as important - m_time_of_day = 9000; + // No problem, this is expected. Just continue with an empty string } + m_lbm_mgr.loadIntroductionTimes(lbm_introduction_times, m_gamedef, m_game_time); + + m_day_count = args.exists("day_count") ? + args.getU64("day_count") : 0; +} + +void ServerEnvironment::loadDefaultMeta() +{ + m_lbm_mgr.loadIntroductionTimes("", m_gamedef, m_game_time); } struct ActiveABM @@ -597,35 +848,39 @@ public: i->timer -= trigger_interval; actual_interval = trigger_interval; } - float intervals = actual_interval / trigger_interval; - if(intervals == 0) - continue; float chance = abm->getTriggerChance(); if(chance == 0) chance = 1; ActiveABM aabm; aabm.abm = abm; - aabm.chance = chance / intervals; - if(aabm.chance == 0) - aabm.chance = 1; + if(abm->getSimpleCatchUp()) { + float intervals = actual_interval / trigger_interval; + if(intervals == 0) + continue; + aabm.chance = chance / intervals; + if(aabm.chance == 0) + aabm.chance = 1; + } else { + aabm.chance = chance; + } // Trigger neighbors std::set<std::string> required_neighbors_s = abm->getRequiredNeighbors(); for(std::set<std::string>::iterator i = required_neighbors_s.begin(); - i != required_neighbors_s.end(); i++) + i != required_neighbors_s.end(); ++i) { ndef->getIds(*i, aabm.required_neighbors); } // Trigger contents std::set<std::string> contents_s = abm->getTriggerContents(); for(std::set<std::string>::iterator - i = contents_s.begin(); i != contents_s.end(); i++) + i = contents_s.begin(); i != contents_s.end(); ++i) { std::set<content_t> ids; ndef->getIds(*i, ids); for(std::set<content_t>::const_iterator k = ids.begin(); - k != ids.end(); k++) + k != ids.end(); ++k) { content_t c = *k; std::map<content_t, std::vector<ActiveABM> >::iterator j; @@ -694,7 +949,7 @@ public: continue; for(std::vector<ActiveABM>::iterator - i = j->second.begin(); i != j->second.end(); i++) { + i = j->second.begin(); i != j->second.end(); ++i) { if(myrand() % i->chance != 0) continue; @@ -749,13 +1004,19 @@ void ServerEnvironment::activateBlock(MapBlock *block, u32 additional_dtime) // Get time difference u32 dtime_s = 0; u32 stamp = block->getTimestamp(); - if(m_game_time > stamp && stamp != BLOCK_TIMESTAMP_UNDEFINED) - dtime_s = m_game_time - block->getTimestamp(); + if (m_game_time > stamp && stamp != BLOCK_TIMESTAMP_UNDEFINED) + dtime_s = m_game_time - stamp; dtime_s += additional_dtime; /*infostream<<"ServerEnvironment::activateBlock(): block timestamp: " <<stamp<<", game time: "<<m_game_time<<std::endl;*/ + // Remove stored static objects if clearObjects was called since block's timestamp + if (stamp == BLOCK_TIMESTAMP_UNDEFINED || stamp < m_last_clear_objects_time) { + block->m_static_objects.m_stored.clear(); + // do not set changed flag to avoid unnecessary mapblock writes + } + // Set current time as timestamp block->setTimestampNoChangedFlag(m_game_time); @@ -765,6 +1026,9 @@ void ServerEnvironment::activateBlock(MapBlock *block, u32 additional_dtime) // Activate stored objects activateObjects(block, dtime_s); + /* Handle LoadingBlockModifiers */ + m_lbm_mgr.applyLBMs(this, block, stamp); + // Run node timers std::map<v3s16, NodeTimer> elapsed_timers = block->m_node_timers.step((float)dtime_s); @@ -772,7 +1036,7 @@ void ServerEnvironment::activateBlock(MapBlock *block, u32 additional_dtime) MapNode n; for(std::map<v3s16, NodeTimer>::iterator i = elapsed_timers.begin(); - i != elapsed_timers.end(); i++){ + i != elapsed_timers.end(); ++i){ n = block->getNodeNoEx(i->first); v3s16 p = i->first + block->getPosRelative(); if(m_script->node_on_timer(p,n,i->second.elapsed)) @@ -790,6 +1054,11 @@ void ServerEnvironment::addActiveBlockModifier(ActiveBlockModifier *abm) m_abms.push_back(ABMWithState(abm)); } +void ServerEnvironment::addLoadingBlockModifierDef(LoadingBlockModifierDef *lbm) +{ + m_lbm_mgr.addLBMDef(lbm); +} + bool ServerEnvironment::setNode(v3s16 p, const MapNode &n) { INodeDefManager *ndef = m_gamedef->ndef(); @@ -868,22 +1137,22 @@ void ServerEnvironment::getObjectsInsideRadius(std::vector<u16> &objects, v3f po } } -void ServerEnvironment::clearAllObjects() +void ServerEnvironment::clearObjects(ClearObjectsMode mode) { - infostream<<"ServerEnvironment::clearAllObjects(): " - <<"Removing all active objects"<<std::endl; + infostream << "ServerEnvironment::clearObjects(): " + << "Removing all active objects" << std::endl; std::vector<u16> objects_to_remove; - for(std::map<u16, ServerActiveObject*>::iterator + for (std::map<u16, ServerActiveObject*>::iterator i = m_active_objects.begin(); i != m_active_objects.end(); ++i) { ServerActiveObject* obj = i->second; - if(obj->getType() == ACTIVEOBJECT_TYPE_PLAYER) + if (obj->getType() == ACTIVEOBJECT_TYPE_PLAYER) continue; u16 id = i->first; // Delete static object if block is loaded - if(obj->m_static_exists){ + if (obj->m_static_exists) { MapBlock *block = m_map->getBlockNoCreateNoEx(obj->m_static_block); - if(block){ + if (block) { block->m_static_objects.remove(id); block->raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_CLEAR_ALL_OBJECTS); @@ -891,7 +1160,7 @@ void ServerEnvironment::clearAllObjects() } } // If known by some client, don't delete immediately - if(obj->m_known_by_count > 0){ + if (obj->m_known_by_count > 0) { obj->m_pending_deactivation = true; obj->m_removed = true; continue; @@ -903,39 +1172,46 @@ void ServerEnvironment::clearAllObjects() m_script->removeObjectReference(obj); // Delete active object - if(obj->environmentDeletes()) + if (obj->environmentDeletes()) delete obj; // Id to be removed from m_active_objects objects_to_remove.push_back(id); } // Remove references from m_active_objects - for(std::vector<u16>::iterator i = objects_to_remove.begin(); + for (std::vector<u16>::iterator i = objects_to_remove.begin(); i != objects_to_remove.end(); ++i) { m_active_objects.erase(*i); } // Get list of loaded blocks std::vector<v3s16> loaded_blocks; - infostream<<"ServerEnvironment::clearAllObjects(): " - <<"Listing all loaded blocks"<<std::endl; + infostream << "ServerEnvironment::clearObjects(): " + << "Listing all loaded blocks" << std::endl; m_map->listAllLoadedBlocks(loaded_blocks); - infostream<<"ServerEnvironment::clearAllObjects(): " - <<"Done listing all loaded blocks: " - <<loaded_blocks.size()<<std::endl; + infostream << "ServerEnvironment::clearObjects(): " + << "Done listing all loaded blocks: " + << loaded_blocks.size()<<std::endl; // Get list of loadable blocks std::vector<v3s16> loadable_blocks; - infostream<<"ServerEnvironment::clearAllObjects(): " - <<"Listing all loadable blocks"<<std::endl; - m_map->listAllLoadableBlocks(loadable_blocks); - infostream<<"ServerEnvironment::clearAllObjects(): " - <<"Done listing all loadable blocks: " - <<loadable_blocks.size() - <<", now clearing"<<std::endl; + if (mode == CLEAR_OBJECTS_MODE_FULL) { + infostream << "ServerEnvironment::clearObjects(): " + << "Listing all loadable blocks" << std::endl; + m_map->listAllLoadableBlocks(loadable_blocks); + infostream << "ServerEnvironment::clearObjects(): " + << "Done listing all loadable blocks: " + << loadable_blocks.size() << std::endl; + } else { + loadable_blocks = loaded_blocks; + } + + infostream << "ServerEnvironment::clearObjects(): " + << "Now clearing objects in " << loadable_blocks.size() + << " blocks" << std::endl; // Grab a reference on each loaded block to avoid unloading it - for(std::vector<v3s16>::iterator i = loaded_blocks.begin(); + for (std::vector<v3s16>::iterator i = loaded_blocks.begin(); i != loaded_blocks.end(); ++i) { v3s16 p = *i; MapBlock *block = m_map->getBlockNoCreateNoEx(p); @@ -944,24 +1220,27 @@ void ServerEnvironment::clearAllObjects() } // Remove objects in all loadable blocks - u32 unload_interval = g_settings->getS32("max_clearobjects_extra_loaded_blocks"); - unload_interval = MYMAX(unload_interval, 1); + u32 unload_interval = U32_MAX; + if (mode == CLEAR_OBJECTS_MODE_FULL) { + unload_interval = g_settings->getS32("max_clearobjects_extra_loaded_blocks"); + unload_interval = MYMAX(unload_interval, 1); + } u32 report_interval = loadable_blocks.size() / 10; u32 num_blocks_checked = 0; u32 num_blocks_cleared = 0; u32 num_objs_cleared = 0; - for(std::vector<v3s16>::iterator i = loadable_blocks.begin(); + for (std::vector<v3s16>::iterator i = loadable_blocks.begin(); i != loadable_blocks.end(); ++i) { v3s16 p = *i; MapBlock *block = m_map->emergeBlock(p, false); - if(!block){ - errorstream<<"ServerEnvironment::clearAllObjects(): " - <<"Failed to emerge block "<<PP(p)<<std::endl; + if (!block) { + errorstream << "ServerEnvironment::clearObjects(): " + << "Failed to emerge block " << PP(p) << std::endl; continue; } u32 num_stored = block->m_static_objects.m_stored.size(); u32 num_active = block->m_static_objects.m_active.size(); - if(num_stored != 0 || num_active != 0){ + if (num_stored != 0 || num_active != 0) { block->m_static_objects.m_stored.clear(); block->m_static_objects.m_active.clear(); block->raiseModified(MOD_STATE_WRITE_NEEDED, @@ -971,23 +1250,23 @@ void ServerEnvironment::clearAllObjects() } num_blocks_checked++; - if(report_interval != 0 && - num_blocks_checked % report_interval == 0){ + if (report_interval != 0 && + num_blocks_checked % report_interval == 0) { float percent = 100.0 * (float)num_blocks_checked / - loadable_blocks.size(); - infostream<<"ServerEnvironment::clearAllObjects(): " - <<"Cleared "<<num_objs_cleared<<" objects" - <<" in "<<num_blocks_cleared<<" blocks (" - <<percent<<"%)"<<std::endl; + loadable_blocks.size(); + infostream << "ServerEnvironment::clearObjects(): " + << "Cleared " << num_objs_cleared << " objects" + << " in " << num_blocks_cleared << " blocks (" + << percent << "%)" << std::endl; } - if(num_blocks_checked % unload_interval == 0){ + if (num_blocks_checked % unload_interval == 0) { m_map->unloadUnreferencedBlocks(); } } m_map->unloadUnreferencedBlocks(); // Drop references that were added above - for(std::vector<v3s16>::iterator i = loaded_blocks.begin(); + for (std::vector<v3s16>::iterator i = loaded_blocks.begin(); i != loaded_blocks.end(); ++i) { v3s16 p = *i; MapBlock *block = m_map->getBlockNoCreateNoEx(p); @@ -995,14 +1274,16 @@ void ServerEnvironment::clearAllObjects() block->refDrop(); } - infostream<<"ServerEnvironment::clearAllObjects(): " - <<"Finished: Cleared "<<num_objs_cleared<<" objects" - <<" in "<<num_blocks_cleared<<" blocks"<<std::endl; + m_last_clear_objects_time = m_game_time; + + infostream << "ServerEnvironment::clearObjects(): " + << "Finished: Cleared " << num_objs_cleared << " objects" + << " in " << num_blocks_cleared << " blocks" << std::endl; } void ServerEnvironment::step(float dtime) { - DSTACK(__FUNCTION_NAME); + DSTACK(FUNCTION_NAME); //TimeTaker timer("ServerEnv step"); @@ -1012,7 +1293,8 @@ void ServerEnvironment::step(float dtime) // Update this one // NOTE: This is kind of funny on a singleplayer game, but doesn't // really matter that much. - m_recommended_send_interval = g_settings->getFloat("dedicated_server_step"); + static const float server_step = g_settings->getFloat("dedicated_server_step"); + m_recommended_send_interval = server_step; /* Increment game time @@ -1046,9 +1328,8 @@ void ServerEnvironment::step(float dtime) /* Manage active block list */ - if(m_active_blocks_management_interval.step(dtime, 2.0)) - { - ScopeProfiler sp(g_profiler, "SEnv: manage act. block list avg /2s", SPT_AVG); + if (m_active_blocks_management_interval.step(dtime, m_cache_active_block_mgmt_interval)) { + ScopeProfiler sp(g_profiler, "SEnv: manage act. block list avg per interval", SPT_AVG); /* Get player block positions */ @@ -1069,7 +1350,7 @@ void ServerEnvironment::step(float dtime) /* Update list of active blocks, collecting changes */ - const s16 active_block_range = g_settings->getS16("active_block_range"); + static const s16 active_block_range = g_settings->getS16("active_block_range"); std::set<v3s16> blocks_removed; std::set<v3s16> blocks_added; m_active_blocks.update(players_blockpos, active_block_range, @@ -1084,8 +1365,7 @@ void ServerEnvironment::step(float dtime) for(std::set<v3s16>::iterator i = blocks_removed.begin(); - i != blocks_removed.end(); ++i) - { + i != blocks_removed.end(); ++i) { v3s16 p = *i; /* infostream<<"Server: Block " << PP(p) @@ -1124,11 +1404,10 @@ void ServerEnvironment::step(float dtime) /* Mess around in active blocks */ - if(m_active_blocks_nodemetadata_interval.step(dtime, 1.0)) - { - ScopeProfiler sp(g_profiler, "SEnv: mess in act. blocks avg /1s", SPT_AVG); + if (m_active_blocks_nodemetadata_interval.step(dtime, m_cache_nodetimer_interval)) { + ScopeProfiler sp(g_profiler, "SEnv: mess in act. blocks avg per interval", SPT_AVG); - float dtime = 1.0; + float dtime = m_cache_nodetimer_interval; for(std::set<v3s16>::iterator i = m_active_blocks.m_list.begin(); @@ -1161,7 +1440,7 @@ void ServerEnvironment::step(float dtime) MapNode n; for(std::map<v3s16, NodeTimer>::iterator i = elapsed_timers.begin(); - i != elapsed_timers.end(); i++){ + i != elapsed_timers.end(); ++i){ n = block->getNodeNoEx(i->first); p = i->first + block->getPosRelative(); if(m_script->node_on_timer(p,n,i->second.elapsed)) @@ -1171,19 +1450,18 @@ void ServerEnvironment::step(float dtime) } } - const float abm_interval = 1.0; - if(m_active_block_modifier_interval.step(dtime, abm_interval)) + if (m_active_block_modifier_interval.step(dtime, m_cache_abm_interval)) do{ // breakable if(m_active_block_interval_overload_skip > 0){ ScopeProfiler sp(g_profiler, "SEnv: ABM overload skips"); m_active_block_interval_overload_skip--; break; } - ScopeProfiler sp(g_profiler, "SEnv: modify in blocks avg /1s", SPT_AVG); - TimeTaker timer("modify in active blocks"); + ScopeProfiler sp(g_profiler, "SEnv: modify in blocks avg per interval", SPT_AVG); + TimeTaker timer("modify in active blocks per interval"); // Initialize handling of ActiveBlockModifiers - ABMHandler abmhandler(m_abms, abm_interval, this, true); + ABMHandler abmhandler(m_abms, m_cache_abm_interval, this, true); for(std::set<v3s16>::iterator i = m_active_blocks.m_list.begin(); @@ -1208,7 +1486,7 @@ void ServerEnvironment::step(float dtime) u32 time_ms = timer.stop(true); u32 max_time_ms = 200; if(time_ms > max_time_ms){ - infostream<<"WARNING: active block modifiers took " + warningstream<<"active block modifiers took " <<time_ms<<"ms (longer than " <<max_time_ms<<"ms)"<<std::endl; m_active_block_interval_overload_skip = (time_ms / max_time_ms) + 1; @@ -1269,6 +1547,49 @@ void ServerEnvironment::step(float dtime) */ removeRemovedObjects(); } + + /* + Manage particle spawner expiration + */ + if (m_particle_management_interval.step(dtime, 1.0)) { + for (std::map<u32, float>::iterator i = m_particle_spawners.begin(); + i != m_particle_spawners.end(); ) { + //non expiring spawners + if (i->second == PARTICLE_SPAWNER_NO_EXPIRY) { + ++i; + continue; + } + + i->second -= 1.0f; + if (i->second <= 0.f) + m_particle_spawners.erase(i++); + else + ++i; + } + } +} + +u32 ServerEnvironment::addParticleSpawner(float exptime) +{ + // Timers with lifetime 0 do not expire + float time = exptime > 0.f ? exptime : PARTICLE_SPAWNER_NO_EXPIRY; + + u32 id = 0; + for (;;) { // look for unused particlespawner id + id++; + std::map<u32, float>::iterator f; + f = m_particle_spawners.find(id); + if (f == m_particle_spawners.end()) { + m_particle_spawners[id] = time; + break; + } + } + return id; +} + +void ServerEnvironment::deleteParticleSpawner(u32 id) +{ + m_particle_spawners.erase(id); } ServerActiveObject* ServerEnvironment::getActiveObject(u16 id) @@ -1318,12 +1639,11 @@ u16 ServerEnvironment::addActiveObject(ServerActiveObject *object) Finds out what new objects have been added to inside a radius around a position */ -void ServerEnvironment::getAddedActiveObjects(v3s16 pos, s16 radius, +void ServerEnvironment::getAddedActiveObjects(Player *player, s16 radius, s16 player_radius, std::set<u16> ¤t_objects, - std::set<u16> &added_objects) + std::queue<u16> &added_objects) { - v3f pos_f = intToFloat(pos, BS); f32 radius_f = radius * BS; f32 player_radius_f = player_radius * BS; @@ -1339,18 +1659,19 @@ void ServerEnvironment::getAddedActiveObjects(v3s16 pos, s16 radius, */ for(std::map<u16, ServerActiveObject*>::iterator i = m_active_objects.begin(); - i != m_active_objects.end(); ++i) - { + i != m_active_objects.end(); ++i) { u16 id = i->first; + // Get object ServerActiveObject *object = i->second; if(object == NULL) continue; + // Discard if removed or deactivating if(object->m_removed || object->m_pending_deactivation) continue; - f32 distance_f = object->getBasePosition().getDistanceFrom(pos_f); + f32 distance_f = object->getBasePosition().getDistanceFrom(player->getPosition()); if (object->getType() == ACTIVEOBJECT_TYPE_PLAYER) { // Discard if too far if (distance_f > player_radius_f && player_radius_f != 0) @@ -1364,7 +1685,7 @@ void ServerEnvironment::getAddedActiveObjects(v3s16 pos, s16 radius, if(n != current_objects.end()) continue; // Add to added_objects - added_objects.insert(id); + added_objects.push(id); } } @@ -1372,12 +1693,11 @@ void ServerEnvironment::getAddedActiveObjects(v3s16 pos, s16 radius, Finds out what objects have been removed from inside a radius around a position */ -void ServerEnvironment::getRemovedActiveObjects(v3s16 pos, s16 radius, +void ServerEnvironment::getRemovedActiveObjects(Player *player, s16 radius, s16 player_radius, std::set<u16> ¤t_objects, - std::set<u16> &removed_objects) + std::queue<u16> &removed_objects) { - v3f pos_f = intToFloat(pos, BS); f32 radius_f = radius * BS; f32 player_radius_f = player_radius * BS; @@ -1399,20 +1719,19 @@ void ServerEnvironment::getRemovedActiveObjects(v3s16 pos, s16 radius, u16 id = *i; ServerActiveObject *object = getActiveObject(id); - if(object == NULL){ - infostream<<"ServerEnvironment::getRemovedActiveObjects():" - <<" object in current_objects is NULL"<<std::endl; - removed_objects.insert(id); + if (object == NULL) { + infostream << "ServerEnvironment::getRemovedActiveObjects():" + << " object in current_objects is NULL" << std::endl; + removed_objects.push(id); continue; } - if(object->m_removed || object->m_pending_deactivation) - { - removed_objects.insert(id); + if (object->m_removed || object->m_pending_deactivation) { + removed_objects.push(id); continue; } - f32 distance_f = object->getBasePosition().getDistanceFrom(pos_f); + f32 distance_f = object->getBasePosition().getDistanceFrom(player->getPosition()); if (object->getType() == ACTIVEOBJECT_TYPE_PLAYER) { if (distance_f <= player_radius_f || player_radius_f == 0) continue; @@ -1420,7 +1739,7 @@ void ServerEnvironment::getRemovedActiveObjects(v3s16 pos, s16 radius, continue; // Object is no longer visible - removed_objects.insert(id); + removed_objects.push(id); } } @@ -1493,6 +1812,17 @@ u16 ServerEnvironment::addActiveObjectRaw(ServerActiveObject *object, delete object; return 0; } + + if (objectpos_over_limit(object->getBasePosition())) { + v3f p = object->getBasePosition(); + errorstream << "ServerEnvironment::addActiveObjectRaw(): " + << "object position (" << p.X << "," << p.Y << "," << p.Z + << ") outside maximum range" << std::endl; + if (object->environmentDeletes()) + delete object; + return 0; + } + /*infostream<<"ServerEnvironment::addActiveObjectRaw(): " <<"added (id="<<object->getId()<<")"<<std::endl;*/ @@ -1921,7 +2251,7 @@ void ServerEnvironment::deactivateFarObjects(bool force_delete) // reason. Unsuccessful attempts have been made to find // said reason. if(id && block->m_static_objects.m_active.find(id) != block->m_static_objects.m_active.end()){ - infostream<<"ServerEnv: WARNING: Performing hack #83274" + warningstream<<"ServerEnv: Performing hack #83274" <<std::endl; block->m_static_objects.remove(id); } @@ -2039,7 +2369,7 @@ ClientMap & ClientEnvironment::getClientMap() void ClientEnvironment::addPlayer(Player *player) { - DSTACK(__FUNCTION_NAME); + DSTACK(FUNCTION_NAME); /* It is a failure if player is local and there already is a local player @@ -2063,7 +2393,7 @@ LocalPlayer * ClientEnvironment::getLocalPlayer() void ClientEnvironment::step(float dtime) { - DSTACK(__FUNCTION_NAME); + DSTACK(FUNCTION_NAME); /* Step time of day */ stepTimeOfDay(dtime); @@ -2562,7 +2892,7 @@ void ClientEnvironment::damageLocalPlayer(u8 damage, bool handle_hp) event.type = CEE_PLAYER_DAMAGE; event.player_damage.amount = damage; event.player_damage.send_to_server = handle_hp; - m_client_event_queue.push_back(event); + m_client_event_queue.push(event); } void ClientEnvironment::updateLocalPlayerBreath(u16 breath) @@ -2570,7 +2900,7 @@ void ClientEnvironment::updateLocalPlayerBreath(u16 breath) ClientEnvEvent event; event.type = CEE_PLAYER_BREATH; event.player_breath.amount = breath; - m_client_event_queue.push_back(event); + m_client_event_queue.push(event); } /* @@ -2604,11 +2934,9 @@ ClientEnvEvent ClientEnvironment::getClientEvent() event.type = CEE_NONE; else { event = m_client_event_queue.front(); - m_client_event_queue.pop_front(); + m_client_event_queue.pop(); } return event; } #endif // #ifndef SERVER - - |