aboutsummaryrefslogtreecommitdiff
path: root/src/environment.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/environment.cpp')
-rw-r--r--src/environment.cpp644
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 &times,
+ 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> &current_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> &current_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
-
-