]> git.lizzy.rs Git - minetest.git/blobdiff - src/environment.cpp
Add an [invert:<mode> texture modifier
[minetest.git] / src / environment.cpp
index fa7ce2ae57f5e27d505342239d34479bd0e84429..eea2646997c466989bfed37a05ae7ad43fb51e7a 100644 (file)
@@ -17,6 +17,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
 
+#include <fstream>
 #include "environment.h"
 #include "filesys.h"
 #include "porting.h"
@@ -31,43 +32,53 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "scripting_game.h"
 #include "nodedef.h"
 #include "nodemetadata.h"
-#include "main.h" // For g_settings, g_profiler
 #include "gamedef.h"
 #ifndef SERVER
 #include "clientmap.h"
 #include "localplayer.h"
+#include "mapblock_mesh.h"
 #include "event.h"
 #endif
+#include "server.h"
 #include "daynightratio.h"
 #include "map.h"
 #include "emerge.h"
 #include "util/serialize.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()
 {
        // Deallocate players
-       for(std::list<Player*>::iterator i = m_players.begin();
-                       i != m_players.end(); ++i)
-       {
+       for(std::vector<Player*>::iterator i = m_players.begin();
+                       i != m_players.end(); ++i) {
                delete (*i);
        }
 }
 
 void Environment::addPlayer(Player *player)
 {
-       DSTACK(__FUNCTION_NAME);
+       DSTACK(FUNCTION_NAME);
        /*
                Check that peer_ids are unique.
                Also check that names are unique.
@@ -75,35 +86,29 @@ void Environment::addPlayer(Player *player)
        */
        // If peer id is non-zero, it has to be unique.
        if(player->peer_id != 0)
-               assert(getPlayer(player->peer_id) == NULL);
+               FATAL_ERROR_IF(getPlayer(player->peer_id) != NULL, "Peer id not unique");
        // Name has to be unique.
-       assert(getPlayer(player->getName()) == NULL);
+       FATAL_ERROR_IF(getPlayer(player->getName()) != NULL, "Player name not unique");
        // Add.
        m_players.push_back(player);
 }
 
-void Environment::removePlayer(u16 peer_id)
+void Environment::removePlayer(Player* player)
 {
-       DSTACK(__FUNCTION_NAME);
-
-       for(std::list<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;
+       for (std::vector<Player*>::iterator it = m_players.begin();
+                       it != m_players.end(); ++it) {
+               if ((*it) == player) {
+                       delete *it;
+                       m_players.erase(it);
+                       return;
                }
        }
 }
 
 Player * Environment::getPlayer(u16 peer_id)
 {
-       for(std::list<Player*>::iterator i = m_players.begin();
-                       i != m_players.end(); ++i)
-       {
+       for(std::vector<Player*>::iterator i = m_players.begin();
+                       i != m_players.end(); ++i) {
                Player *player = *i;
                if(player->peer_id == peer_id)
                        return player;
@@ -113,9 +118,8 @@ Player * Environment::getPlayer(u16 peer_id)
 
 Player * Environment::getPlayer(const char *name)
 {
-       for(std::list<Player*>::iterator i = m_players.begin();
-                       i != m_players.end(); ++i)
-       {
+       for(std::vector<Player*>::iterator i = m_players.begin();
+                       i != m_players.end(); ++i) {
                Player *player = *i;
                if(strcmp(player->getName(), name) == 0)
                        return player;
@@ -125,15 +129,13 @@ Player * Environment::getPlayer(const char *name)
 
 Player * Environment::getRandomConnectedPlayer()
 {
-       std::list<Player*> connected_players = getPlayers(true);
+       std::vector<Player*> connected_players = getPlayers(true);
        u32 chosen_one = myrand() % connected_players.size();
        u32 j = 0;
-       for(std::list<Player*>::iterator
+       for(std::vector<Player*>::iterator
                        i = connected_players.begin();
-                       i != connected_players.end(); ++i)
-       {
-               if(j == chosen_one)
-               {
+                       i != connected_players.end(); ++i) {
+               if(j == chosen_one) {
                        Player *player = *i;
                        return player;
                }
@@ -144,17 +146,15 @@ Player * Environment::getRandomConnectedPlayer()
 
 Player * Environment::getNearestConnectedPlayer(v3f pos)
 {
-       std::list<Player*> connected_players = getPlayers(true);
+       std::vector<Player*> connected_players = getPlayers(true);
        f32 nearest_d = 0;
        Player *nearest_player = NULL;
-       for(std::list<Player*>::iterator
+       for(std::vector<Player*>::iterator
                        i = connected_players.begin();
-                       i != connected_players.end(); ++i)
-       {
+                       i != connected_players.end(); ++i) {
                Player *player = *i;
                f32 d = player->getPosition().getDistanceFrom(pos);
-               if(d < nearest_d || nearest_player == NULL)
-               {
+               if(d < nearest_d || nearest_player == NULL) {
                        nearest_d = d;
                        nearest_player = player;
                }
@@ -162,22 +162,20 @@ Player * Environment::getNearestConnectedPlayer(v3f pos)
        return nearest_player;
 }
 
-std::list<Player*> Environment::getPlayers()
+std::vector<Player*> Environment::getPlayers()
 {
        return m_players;
 }
 
-std::list<Player*> Environment::getPlayers(bool ignore_disconnected)
+std::vector<Player*> Environment::getPlayers(bool ignore_disconnected)
 {
-       std::list<Player*> newlist;
-       for(std::list<Player*>::iterator
+       std::vector<Player*> newlist;
+       for(std::vector<Player*>::iterator
                        i = m_players.begin();
-                       i != m_players.end(); ++i)
-       {
+                       i != m_players.end(); ++i) {
                Player *player = *i;
-               
-               if(ignore_disconnected)
-               {
+
+               if(ignore_disconnected) {
                        // Ignore disconnected players
                        if(player->peer_id == 0)
                                continue;
@@ -190,36 +188,91 @@ std::list<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;
-       bool smooth = g_settings->getBool("enable_shaders");
-       return time_to_daynight_ratio(m_time_of_day_f*24000, smooth);
+       return time_to_daynight_ratio(m_time_of_day_f * 24000, m_cache_enable_shaders);
+}
+
+void Environment::setTimeOfDaySpeed(float speed)
+{
+       m_time_of_day_speed = speed;
+}
+
+float Environment::getTimeOfDaySpeed()
+{
+       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)
+{
+       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()
+{
+       MutexAutoLock lock(this->m_time_lock);
+       return m_time_of_day;
+}
+
+float Environment::getTimeOfDayF()
+{
+       MutexAutoLock lock(this->m_time_lock);
+       return m_time_of_day_f;
 }
 
 void Environment::stepTimeOfDay(float dtime)
 {
-       m_time_counter += dtime;
-       f32 speed = m_time_of_day_speed * 24000./(24.*3600);
-       u32 units = (u32)(m_time_counter*speed);
-       m_time_counter -= (f32)units / speed;
+       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;
+
+       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(!sync_f){
-               m_time_of_day_f += m_time_of_day_speed/24/3600*dtime;
-               if(m_time_of_day_f > 1.0)
+       if (speed > 0) {
+               m_time_conversion_skew -= (f32)units / speed;
+       }
+       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
 */
@@ -236,6 +289,223 @@ ABMWithState::ABMWithState(ActiveBlockModifier *abm_):
        timer = myrand_range(minval, maxval);
 }
 
+/*
+       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
 */
@@ -252,7 +522,7 @@ void fillRadiusBlock(v3s16 p0, s16 r, std::set<v3s16> &list)
        }
 }
 
-void ActiveBlockList::update(std::list<v3s16> &active_positions,
+void ActiveBlockList::update(std::vector<v3s16> &active_positions,
                s16 radius,
                std::set<v3s16> &blocks_removed,
                std::set<v3s16> &blocks_added)
@@ -261,7 +531,7 @@ void ActiveBlockList::update(std::list<v3s16> &active_positions,
                Create the new list
        */
        std::set<v3s16> newlist = m_forceloaded_list;
-       for(std::list<v3s16>::iterator i = active_positions.begin();
+       for(std::vector<v3s16>::iterator i = active_positions.begin();
                        i != active_positions.end(); ++i)
        {
                fillRadiusBlock(*i, radius, newlist);
@@ -310,14 +580,17 @@ void ActiveBlockList::update(std::list<v3s16> &active_positions,
 */
 
 ServerEnvironment::ServerEnvironment(ServerMap *map,
-               GameScripting *scriptIface, IGameDef *gamedef):
+               GameScripting *scriptIface, IGameDef *gamedef,
+               const std::string &path_world) :
        m_map(map),
        m_script(scriptIface),
        m_gamedef(gamedef),
+       m_path_world(path_world),
        m_send_recommended_timer(0),
        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)
 {
@@ -336,7 +609,7 @@ ServerEnvironment::~ServerEnvironment()
        m_map->drop();
 
        // Delete ActiveBlockModifiers
-       for(std::list<ABMWithState>::iterator
+       for(std::vector<ABMWithState>::iterator
                        i = m_abms.begin(); i != m_abms.end(); ++i){
                delete i->abm;
        }
@@ -358,8 +631,8 @@ bool ServerEnvironment::line_of_sight(v3f pos1, v3f pos2, float stepsize, v3s16
 
        //calculate normalized direction vector
        v3f normalized_vector = v3f((pos2.X - pos1.X)/distance,
-                                                               (pos2.Y - pos1.Y)/distance,
-                                                               (pos2.Z - pos1.Z)/distance);
+                               (pos2.Y - pos1.Y)/distance,
+                               (pos2.Z - pos1.Z)/distance);
 
        //find out if there's a node on path between pos1 and pos2
        for (float i = 1; i < distance; i += stepsize) {
@@ -379,196 +652,87 @@ bool ServerEnvironment::line_of_sight(v3f pos1, v3f pos2, float stepsize, v3s16
        return true;
 }
 
-void ServerEnvironment::serializePlayers(const std::string &savedir)
+void ServerEnvironment::kickAllPlayers(AccessDeniedCode reason,
+               const std::string &str_reason, bool reconnect)
 {
-       std::string players_path = savedir + "/players";
-       fs::CreateDir(players_path);
-
-       std::set<Player*> saved_players;
-
-       std::vector<fs::DirListNode> player_files = fs::GetDirListing(players_path);
-       for(u32 i=0; i<player_files.size(); i++)
-       {
-               if(player_files[i].dir || player_files[i].name[0] == '.')
-                       continue;
-               
-               // Full path to this file
-               std::string path = players_path + "/" + player_files[i].name;
-
-               //infostream<<"Checking player file "<<path<<std::endl;
-
-               // Load player to see what is its name
-               RemotePlayer testplayer(m_gamedef);
-               {
-                       // Open file and deserialize
-                       std::ifstream is(path.c_str(), std::ios_base::binary);
-                       if(is.good() == false)
-                       {
-                               infostream<<"Failed to read "<<path<<std::endl;
-                               continue;
-                       }
-                       testplayer.deSerialize(is, player_files[i].name);
-               }
-
-               //infostream<<"Loaded test player with name "<<testplayer.getName()<<std::endl;
-               
-               // Search for the player
-               std::string playername = testplayer.getName();
-               Player *player = getPlayer(playername.c_str());
-               if(player == NULL)
-               {
-                       infostream<<"Didn't find matching player, ignoring file "<<path<<std::endl;
-                       continue;
-               }
-
-               //infostream<<"Found matching player, overwriting."<<std::endl;
-
-               // OK, found. Save player there.
-               if(player->checkModified())
-               {
-                       // Open file and serialize
-                       std::ostringstream ss(std::ios_base::binary);
-                       player->serialize(ss);
-                       if(!fs::safeWriteToFile(path, ss.str()))
-                       {
-                               infostream<<"Failed to write "<<path<<std::endl;
-                               continue;
-                       }
-                       saved_players.insert(player);
-               } else {
-                       saved_players.insert(player);
-               }
+       for (std::vector<Player*>::iterator it = m_players.begin();
+                       it != m_players.end();
+                       ++it) {
+               ((Server*)m_gamedef)->DenyAccessVerCompliant((*it)->peer_id,
+                       (*it)->protocol_version, (AccessDeniedCode)reason,
+                       str_reason, reconnect);
        }
+}
 
-       for(std::list<Player*>::iterator i = m_players.begin();
-                       i != m_players.end(); ++i)
-       {
-               Player *player = *i;
-               if(saved_players.find(player) != saved_players.end())
-               {
-                       /*infostream<<"Player "<<player->getName()
-                                       <<" was already saved."<<std::endl;*/
-                       continue;
-               }
-               std::string playername = player->getName();
-               // Don't save unnamed player
-               if(playername == "")
-               {
-                       //infostream<<"Not saving unnamed player."<<std::endl;
-                       continue;
-               }
-               /*
-                       Find a sane filename
-               */
-               if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS) == false)
-                       playername = "player";
-               std::string path = players_path + "/" + playername;
-               bool found = false;
-               for(u32 i=0; i<1000; i++)
-               {
-                       if(fs::PathExists(path) == false)
-                       {
-                               found = true;
-                               break;
-                       }
-                       path = players_path + "/" + playername + itos(i);
-               }
-               if(found == false)
-               {
-                       infostream<<"Didn't find free file for player"<<std::endl;
-                       continue;
-               }
+void ServerEnvironment::saveLoadedPlayers()
+{
+       std::string players_path = m_path_world + DIR_DELIM "players";
+       fs::CreateDir(players_path);
 
-               {
-                       /*infostream<<"Saving player "<<player->getName()<<" to "
-                                       <<path<<std::endl;*/
-                       // Open file and serialize
-                       std::ostringstream ss(std::ios_base::binary);
-                       player->serialize(ss);
-                       if(!fs::safeWriteToFile(path, ss.str()))
-                       {
-                               infostream<<"Failed to write "<<path<<std::endl;
-                               continue;
-                       }
-                       saved_players.insert(player);
+       for (std::vector<Player*>::iterator it = m_players.begin();
+                       it != m_players.end();
+                       ++it) {
+               RemotePlayer *player = static_cast<RemotePlayer*>(*it);
+               if (player->checkModified()) {
+                       player->save(players_path);
                }
        }
-
-       //infostream<<"Saved "<<saved_players.size()<<" players."<<std::endl;
 }
 
-void ServerEnvironment::deSerializePlayers(const std::string &savedir)
+void ServerEnvironment::savePlayer(RemotePlayer *player)
 {
-       std::string players_path = savedir + "/players";
+       std::string players_path = m_path_world + DIR_DELIM "players";
+       fs::CreateDir(players_path);
 
-       std::vector<fs::DirListNode> player_files = fs::GetDirListing(players_path);
-       for(u32 i=0; i<player_files.size(); i++)
-       {
-               if(player_files[i].dir)
-                       continue;
-               
-               // Full path to this file
-               std::string path = players_path + "/" + player_files[i].name;
+       player->save(players_path);
+}
 
-               //infostream<<"Checking player file "<<path<<std::endl;
+Player *ServerEnvironment::loadPlayer(const std::string &playername)
+{
+       bool newplayer = false;
+       bool found = false;
+       std::string players_path = m_path_world + DIR_DELIM "players" DIR_DELIM;
+       std::string path = players_path + playername;
 
-               // Load player to see what is its name
-               RemotePlayer testplayer(m_gamedef);
-               {
-                       // Open file and deserialize
-                       std::ifstream is(path.c_str(), std::ios_base::binary);
-                       if(is.good() == false)
-                       {
-                               infostream<<"Failed to read "<<path<<std::endl;
-                               continue;
-                       }
-                       testplayer.deSerialize(is, player_files[i].name);
-               }
+       RemotePlayer *player = static_cast<RemotePlayer *>(getPlayer(playername.c_str()));
+       if (!player) {
+               player = new RemotePlayer(m_gamedef, "");
+               newplayer = true;
+       }
 
-               if(!string_allowed(testplayer.getName(), PLAYERNAME_ALLOWED_CHARS))
-               {
-                       infostream<<"Not loading player with invalid name: "
-                                       <<testplayer.getName()<<std::endl;
-               }
-
-               /*infostream<<"Loaded test player with name "<<testplayer.getName()
-                               <<std::endl;*/
-               
-               // Search for the player
-               std::string playername = testplayer.getName();
-               Player *player = getPlayer(playername.c_str());
-               bool newplayer = false;
-               if(player == NULL)
-               {
-                       //infostream<<"Is a new player"<<std::endl;
-                       player = new RemotePlayer(m_gamedef);
-                       newplayer = true;
-               }
+       for (u32 i = 0; i < PLAYER_FILE_ALTERNATE_TRIES; i++) {
+               //// Open file and deserialize
+               std::ifstream is(path.c_str(), std::ios_base::binary);
+               if (!is.good())
+                       continue;
+               player->deSerialize(is, path);
+               is.close();
 
-               // Load player
-               {
-                       verbosestream<<"Reading player "<<testplayer.getName()<<" from "
-                                       <<path<<std::endl;
-                       // Open file and deserialize
-                       std::ifstream is(path.c_str(), std::ios_base::binary);
-                       if(is.good() == false)
-                       {
-                               infostream<<"Failed to read "<<path<<std::endl;
-                               continue;
-                       }
-                       player->deSerialize(is, player_files[i].name);
+               if (player->getName() == playername) {
+                       found = true;
+                       break;
                }
 
-               if(newplayer)
-               {
-                       addPlayer(player);
-               }
+               path = players_path + playername + itos(i);
+       }
+
+       if (!found) {
+               infostream << "Player file for player " << playername
+                               << " not found" << std::endl;
+               if (newplayer)
+                       delete player;
+               return NULL;
        }
+
+       if (newplayer)
+               addPlayer(player);
+       player->setModified(false);
+       return player;
 }
 
-void ServerEnvironment::saveMeta(const std::string &savedir)
+void ServerEnvironment::saveMeta()
 {
-       std::string path = savedir + "/env_meta.txt";
+       std::string path = m_path_world + DIR_DELIM "env_meta.txt";
 
        // Open file and serialize
        std::ostringstream ss(std::ios_base::binary);
@@ -576,6 +740,11 @@ void ServerEnvironment::saveMeta(const std::string &savedir)
        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";
 
@@ -587,47 +756,61 @@ void ServerEnvironment::saveMeta(const std::string &savedir)
        }
 }
 
-void ServerEnvironment::loadMeta(const std::string &savedir)
+void ServerEnvironment::loadMeta()
 {
-       std::string path = savedir + "/env_meta.txt";
+       std::string path = m_path_world + DIR_DELIM "env_meta.txt";
 
        // Open file and deserialize
        std::ifstream is(path.c_str(), std::ios_base::binary);
-       if(is.good() == false)
-       {
-               infostream<<"ServerEnvironment::loadMeta(): Failed to open "
-                               <<path<<std::endl;
+       if (!is.good()) {
+               infostream << "ServerEnvironment::loadMeta(): Failed to open "
+                               << path << std::endl;
                throw SerializationError("Couldn't load env meta");
        }
 
        Settings args;
-       
-       for(;;)
-       {
-               if(is.eof())
-                       throw SerializationError
-                                       ("ServerEnvironment::loadMeta(): EnvArgsEnd not found");
-               std::string line;
-               std::getline(is, line);
-               std::string trimmedline = trim(line);
-               if(trimmedline == "EnvArgsEnd")
-                       break;
-               args.parseConfigLine(line);
+
+       if (!args.parseConfigLines(is, "EnvArgsEnd")) {
+               throw SerializationError("ServerEnvironment::loadMeta(): "
+                               "EnvArgsEnd not found!");
        }
-       
-       try{
+
+       try {
                m_game_time = args.getU64("game_time");
-       }catch(SettingNotFoundException &e){
+       } catch (SettingNotFoundException &e) {
                // Getting this is crucial, otherwise timestamps are useless
                throw SerializationError("Couldn't load env meta game_time");
        }
 
-       try{
-               m_time_of_day = args.getU64("time_of_day");
-       }catch(SettingNotFoundException &e){
-               // This is not as important
-               m_time_of_day = 9000;
+       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 {
+               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) {
+               // 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
@@ -641,9 +824,9 @@ class ABMHandler
 {
 private:
        ServerEnvironment *m_env;
-       std::map<content_t, std::list<ActiveABM> > m_aabms;
+       std::map<content_t, std::vector<ActiveABM> > m_aabms;
 public:
-       ABMHandler(std::list<ABMWithState> &abms,
+       ABMHandler(std::vector<ABMWithState> &abms,
                        float dtime_s, ServerEnvironment *env,
                        bool use_timers):
                m_env(env)
@@ -651,8 +834,8 @@ class ABMHandler
                if(dtime_s < 0.001)
                        return;
                INodeDefManager *ndef = env->getGameDef()->ndef();
-               for(std::list<ABMWithState>::iterator
-                               i = abms.begin(); i != abms.end(); ++i){
+               for(std::vector<ABMWithState>::iterator
+                               i = abms.begin(); i != abms.end(); ++i) {
                        ActiveBlockModifier *abm = i->abm;
                        float trigger_interval = abm->getTriggerInterval();
                        if(trigger_interval < 0.001)
@@ -665,41 +848,45 @@ class ABMHandler
                                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::list<ActiveABM> >::iterator j;
+                                       std::map<content_t, std::vector<ActiveABM> >::iterator j;
                                        j = m_aabms.find(c);
                                        if(j == m_aabms.end()){
-                                               std::list<ActiveABM> aabmlist;
+                                               std::vector<ActiveABM> aabmlist;
                                                m_aabms[c] = aabmlist;
                                                j = m_aabms.find(c);
                                        }
@@ -756,14 +943,13 @@ class ABMHandler
                        content_t c = n.getContent();
                        v3s16 p = p0 + block->getPosRelative();
 
-                       std::map<content_t, std::list<ActiveABM> >::iterator j;
+                       std::map<content_t, std::vector<ActiveABM> >::iterator j;
                        j = m_aabms.find(c);
                        if(j == m_aabms.end())
                                continue;
 
-                       for(std::list<ActiveABM>::iterator
-                                       i = j->second.begin(); i != j->second.end(); i++)
-                       {
+                       for(std::vector<ActiveABM>::iterator
+                                       i = j->second.begin(); i != j->second.end(); ++i) {
                                if(myrand() % i->chance != 0)
                                        continue;
 
@@ -818,34 +1004,43 @@ 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);
 
        /*infostream<<"ServerEnvironment::activateBlock(): block is "
                        <<dtime_s<<" seconds old."<<std::endl;*/
-       
+
        // 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 =
+       std::vector<NodeTimer> elapsed_timers =
                block->m_node_timers.step((float)dtime_s);
-       if(!elapsed_timers.empty()){
+       if (!elapsed_timers.empty()) {
                MapNode n;
-               for(std::map<v3s16, NodeTimer>::iterator
+               for (std::vector<NodeTimer>::iterator
                                i = elapsed_timers.begin();
-                               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))
-                               block->setNodeTimer(i->first,NodeTimer(i->second.timeout,0));
+                               i != elapsed_timers.end(); ++i){
+                       n = block->getNodeNoEx(i->position);
+                       v3s16 p = i->position + block->getPosRelative();
+                       if (m_script->node_on_timer(p, n, i->elapsed))
+                               block->setNodeTimer(NodeTimer(i->timeout, 0, i->position));
                }
        }
 
@@ -859,23 +1054,35 @@ 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();
        MapNode n_old = m_map->getNodeNoEx(p);
+
        // Call destructor
-       if(ndef->get(n_old).has_on_destruct)
+       if (ndef->get(n_old).has_on_destruct)
                m_script->node_on_destruct(p, n_old);
+
        // Replace node
-       bool succeeded = m_map->addNodeWithEvent(p, n);
-       if(!succeeded)
+       if (!m_map->addNodeWithEvent(p, n))
                return false;
+
+       // Update active VoxelManipulator if a mapgen thread
+       m_map->updateVManip(p);
+
        // Call post-destructor
-       if(ndef->get(n_old).has_after_destruct)
+       if (ndef->get(n_old).has_after_destruct)
                m_script->node_after_destruct(p, n_old);
+
        // Call constructor
-       if(ndef->get(n).has_on_construct)
+       if (ndef->get(n).has_on_construct)
                m_script->node_on_construct(p, n);
+
        return true;
 }
 
@@ -883,29 +1090,40 @@ bool ServerEnvironment::removeNode(v3s16 p)
 {
        INodeDefManager *ndef = m_gamedef->ndef();
        MapNode n_old = m_map->getNodeNoEx(p);
+
        // Call destructor
-       if(ndef->get(n_old).has_on_destruct)
+       if (ndef->get(n_old).has_on_destruct)
                m_script->node_on_destruct(p, n_old);
+
        // Replace with air
        // This is slightly optimized compared to addNodeWithEvent(air)
-       bool succeeded = m_map->removeNodeWithEvent(p);
-       if(!succeeded)
+       if (!m_map->removeNodeWithEvent(p))
                return false;
+
+       // Update active VoxelManipulator if a mapgen thread
+       m_map->updateVManip(p);
+
        // Call post-destructor
-       if(ndef->get(n_old).has_after_destruct)
+       if (ndef->get(n_old).has_after_destruct)
                m_script->node_after_destruct(p, n_old);
+
        // Air doesn't require constructor
        return true;
 }
 
 bool ServerEnvironment::swapNode(v3s16 p, const MapNode &n)
 {
-       return m_map->addNodeWithEvent(p, n, false);
+       if (!m_map->addNodeWithEvent(p, n, false))
+               return false;
+
+       // Update active VoxelManipulator if a mapgen thread
+       m_map->updateVManip(p);
+
+       return true;
 }
 
-std::set<u16> ServerEnvironment::getObjectsInsideRadius(v3f pos, float radius)
+void ServerEnvironment::getObjectsInsideRadius(std::vector<u16> &objects, v3f pos, float radius)
 {
-       std::set<u16> objects;
        for(std::map<u16, ServerActiveObject*>::iterator
                        i = m_active_objects.begin();
                        i != m_active_objects.end(); ++i)
@@ -915,36 +1133,34 @@ std::set<u16> ServerEnvironment::getObjectsInsideRadius(v3f pos, float radius)
                v3f objectpos = obj->getBasePosition();
                if(objectpos.getDistanceFrom(pos) > radius)
                        continue;
-               objects.insert(id);
+               objects.push_back(id);
        }
-       return objects;
 }
 
-void ServerEnvironment::clearAllObjects()
+void ServerEnvironment::clearObjects(ClearObjectsMode mode)
 {
-       infostream<<"ServerEnvironment::clearAllObjects(): "
-                       <<"Removing all active objects"<<std::endl;
-       std::list<u16> objects_to_remove;
-       for(std::map<u16, ServerActiveObject*>::iterator
+       infostream << "ServerEnvironment::clearObjects(): "
+               << "Removing all active objects" << std::endl;
+       std::vector<u16> objects_to_remove;
+       for (std::map<u16, ServerActiveObject*>::iterator
                        i = m_active_objects.begin();
-                       i != m_active_objects.end(); ++i)
-       {
+                       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,
-                                               "clearAllObjects");
+                                               MOD_REASON_CLEAR_ALL_OBJECTS);
                                obj->m_static_exists = false;
                        }
                }
                // 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;
@@ -956,110 +1172,119 @@ 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::list<u16>::iterator i = objects_to_remove.begin();
-                       i != objects_to_remove.end(); ++i)
-       {
+       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::list<v3s16> loaded_blocks;
-       infostream<<"ServerEnvironment::clearAllObjects(): "
-                       <<"Listing all loaded blocks"<<std::endl;
+       std::vector<v3s16> loaded_blocks;
+       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::list<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;
+       std::vector<v3s16> loadable_blocks;
+       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::list<v3s16>::iterator i = loaded_blocks.begin();
-                       i != loaded_blocks.end(); ++i)
-       {
+       for (std::vector<v3s16>::iterator i = loaded_blocks.begin();
+                       i != loaded_blocks.end(); ++i) {
                v3s16 p = *i;
                MapBlock *block = m_map->getBlockNoCreateNoEx(p);
-               assert(block);
+               assert(block != NULL);
                block->refGrab();
        }
 
        // 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::list<v3s16>::iterator i = loadable_blocks.begin();
-                       i != loadable_blocks.end(); ++i)
-       {
+       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,
-                                       "clearAllObjects");
+                               MOD_REASON_CLEAR_ALL_OBJECTS);
                        num_objs_cleared += num_stored + num_active;
                        num_blocks_cleared++;
                }
                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::list<v3s16>::iterator i = loaded_blocks.begin();
-                       i != loaded_blocks.end(); ++i)
-       {
+       for (std::vector<v3s16>::iterator i = loaded_blocks.begin();
+                       i != loaded_blocks.end(); ++i) {
                v3s16 p = *i;
                MapBlock *block = m_map->getBlockNoCreateNoEx(p);
                assert(block);
                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");
 
        /* Step time of day */
@@ -1068,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
@@ -1079,21 +1305,21 @@ void ServerEnvironment::step(float dtime)
                m_game_time += inc_i;
                m_game_time_fraction_counter -= (float)inc_i;
        }
-       
+
        /*
                Handle players
        */
        {
                ScopeProfiler sp(g_profiler, "SEnv: handle players avg", SPT_AVG);
-               for(std::list<Player*>::iterator i = m_players.begin();
+               for(std::vector<Player*>::iterator i = m_players.begin();
                                i != m_players.end(); ++i)
                {
                        Player *player = *i;
-                       
+
                        // Ignore disconnected players
                        if(player->peer_id == 0)
                                continue;
-                       
+
                        // Move
                        player->move(dtime, this, 100*BS);
                }
@@ -1102,30 +1328,29 @@ 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
                */
-               std::list<v3s16> players_blockpos;
-               for(std::list<Player*>::iterator
+               std::vector<v3s16> players_blockpos;
+               for(std::vector<Player*>::iterator
                                i = m_players.begin();
-                               i != m_players.end(); ++i)
-               {
+                               i != m_players.end(); ++i) {
                        Player *player = *i;
                        // Ignore disconnected players
                        if(player->peer_id == 0)
                                continue;
+
                        v3s16 blockpos = getNodeBlockPos(
                                        floatToInt(player->getPosition(), BS));
                        players_blockpos.push_back(blockpos);
                }
-               
+
                /*
                        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,
@@ -1137,20 +1362,19 @@ void ServerEnvironment::step(float dtime)
 
                // Convert active objects that are no more in active blocks to static
                deactivateFarObjects(false);
-               
+
                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)
                                << " became inactive"<<std::endl; */
-                       
+
                        MapBlock *block = m_map->getBlockNoCreateNoEx(p);
                        if(block==NULL)
                                continue;
-                       
+
                        // Set current time as timestamp (and let it set ChangedFlag)
                        block->setTimestamp(m_game_time);
                }
@@ -1180,18 +1404,17 @@ 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);
-               
-               float dtime = 1.0;
+       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 = m_cache_nodetimer_interval;
 
                for(std::set<v3s16>::iterator
                                i = m_active_blocks.m_list.begin();
                                i != m_active_blocks.m_list.end(); ++i)
                {
                        v3s16 p = *i;
-                       
+
                        /*infostream<<"Server: Block ("<<p.X<<","<<p.Y<<","<<p.Z
                                        <<") being handled"<<std::endl;*/
 
@@ -1201,59 +1424,60 @@ void ServerEnvironment::step(float dtime)
 
                        // Reset block usage timer
                        block->resetUsageTimer();
-                       
+
                        // Set current time as timestamp
                        block->setTimestampNoChangedFlag(m_game_time);
                        // If time has changed much from the one on disk,
                        // set block to be saved when it is unloaded
                        if(block->getTimestamp() > block->getDiskTimestamp() + 60)
                                block->raiseModified(MOD_STATE_WRITE_AT_UNLOAD,
-                                               "Timestamp older than 60s (step)");
+                                       MOD_REASON_BLOCK_EXPIRED);
 
                        // Run node timers
-                       std::map<v3s16, NodeTimer> elapsed_timers =
+                       std::vector<NodeTimer> elapsed_timers =
                                block->m_node_timers.step((float)dtime);
-                       if(!elapsed_timers.empty()){
+                       if (!elapsed_timers.empty()) {
                                MapNode n;
-                               for(std::map<v3s16, NodeTimer>::iterator
+                               for (std::vector<NodeTimer>::iterator
                                                i = elapsed_timers.begin();
-                                               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))
-                                               block->setNodeTimer(i->first,NodeTimer(i->second.timeout,0));
+                                               i != elapsed_timers.end(); ++i) {
+                                       n = block->getNodeNoEx(i->position);
+                                       p = i->position + block->getPosRelative();
+                                       if (m_script->node_on_timer(p, n, i->elapsed)) {
+                                               block->setNodeTimer(NodeTimer(
+                                                       i->timeout, 0, i->position));
+                                       }
                                }
                        }
                }
        }
-       
-       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();
                                i != m_active_blocks.m_list.end(); ++i)
                {
                        v3s16 p = *i;
-                       
+
                        /*infostream<<"Server: Block ("<<p.X<<","<<p.Y<<","<<p.Z
                                        <<") being handled"<<std::endl;*/
 
                        MapBlock *block = m_map->getBlockNoCreateNoEx(p);
-                       if(block==NULL)
+                       if(block == NULL)
                                continue;
-                       
+
                        // Set current time as timestamp
                        block->setTimestampNoChangedFlag(m_game_time);
 
@@ -1264,13 +1488,13 @@ 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;
                }
        }while(0);
-       
+
        /*
                Step script environment (run global on_step())
        */
@@ -1284,7 +1508,7 @@ void ServerEnvironment::step(float dtime)
                //TimeTaker timer("Step active objects");
 
                g_profiler->avg("SEnv: num of objects", m_active_objects.size());
-               
+
                // This helps the objects to send data at the same time
                bool send_recommended = false;
                m_send_recommended_timer += dtime;
@@ -1299,11 +1523,6 @@ void ServerEnvironment::step(float dtime)
                                i != m_active_objects.end(); ++i)
                {
                        ServerActiveObject* obj = i->second;
-                       // Remove non-peaceful mobs on peaceful mode
-                       if(g_settings->getBool("only_peaceful_mobs")){
-                               if(!obj->isPeaceful())
-                                       obj->m_removed = true;
-                       }
                        // Don't step if is to be removed or stored statically
                        if(obj->m_removed || obj->m_pending_deactivation)
                                continue;
@@ -1312,12 +1531,13 @@ void ServerEnvironment::step(float dtime)
                        // Read messages from object
                        while(!obj->m_messages_out.empty())
                        {
-                               m_active_object_messages.push_back(
-                                               obj->m_messages_out.pop_front());
+                               m_active_object_messages.push(
+                                               obj->m_messages_out.front());
+                               obj->m_messages_out.pop();
                        }
                }
        }
-       
+
        /*
                Manage active objects
        */
@@ -1329,6 +1549,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)
@@ -1360,7 +1623,7 @@ u16 getFreeServerActiveObjectId(
                last_used_id ++;
                if(isFreeServerActiveObjectId(last_used_id, objects))
                        return last_used_id;
-               
+
                if(last_used_id == startid)
                        return 0;
        }
@@ -1368,67 +1631,27 @@ u16 getFreeServerActiveObjectId(
 
 u16 ServerEnvironment::addActiveObject(ServerActiveObject *object)
 {
-       assert(object);
+       assert(object); // Pre-condition
        m_added_objects++;
        u16 id = addActiveObjectRaw(object, true, 0);
        return id;
 }
 
-#if 0
-bool ServerEnvironment::addActiveObjectAsStatic(ServerActiveObject *obj)
-{
-       assert(obj);
-
-       v3f objectpos = obj->getBasePosition(); 
-
-       // The block in which the object resides in
-       v3s16 blockpos_o = getNodeBlockPos(floatToInt(objectpos, BS));
-
-       /*
-               Update the static data
-       */
-
-       // Create new static object
-       std::string staticdata = obj->getStaticData();
-       StaticObject s_obj(obj->getType(), objectpos, staticdata);
-       // Add to the block where the object is located in
-       v3s16 blockpos = getNodeBlockPos(floatToInt(objectpos, BS));
-       // Get or generate the block
-       MapBlock *block = m_map->emergeBlock(blockpos);
-
-       bool succeeded = false;
-
-       if(block)
-       {
-               block->m_static_objects.insert(0, s_obj);
-               block->raiseModified(MOD_STATE_WRITE_AT_UNLOAD,
-                               "addActiveObjectAsStatic");
-               succeeded = true;
-       }
-       else{
-               infostream<<"ServerEnvironment::addActiveObjectAsStatic: "
-                               <<"Could not find or generate "
-                               <<"a block for storing static object"<<std::endl;
-               succeeded = false;
-       }
-
-       if(obj->environmentDeletes())
-               delete obj;
-
-       return succeeded;
-}
-#endif
-
 /*
        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;
+
+       if (player_radius_f < 0)
+               player_radius_f = 0;
+
        /*
                Go through the object list,
                - discard m_removed objects,
@@ -1438,29 +1661,33 @@ 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;
-               if(object->unlimitedTransferDistance() == false){
+
+               f32 distance_f = object->getBasePosition().getDistanceFrom(player->getPosition());
+               if (object->getType() == ACTIVEOBJECT_TYPE_PLAYER) {
                        // Discard if too far
-                       f32 distance_f = object->getBasePosition().getDistanceFrom(pos_f);
-                       if(distance_f > radius_f)
+                       if (distance_f > player_radius_f && player_radius_f != 0)
                                continue;
-               }
+               } else if (distance_f > radius_f)
+                       continue;
+
                // Discard if already on current_objects
                std::set<u16>::iterator n;
                n = current_objects.find(id);
                if(n != current_objects.end())
                        continue;
                // Add to added_objects
-               added_objects.insert(id);
+               added_objects.push(id);
        }
 }
 
@@ -1468,12 +1695,17 @@ 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;
+
+       if (player_radius_f < 0)
+               player_radius_f = 0;
+
        /*
                Go through current_objects; object is removed if:
                - object is not found in m_active_objects (this is actually an
@@ -1489,32 +1721,54 @@ 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;
                }
-               
-               // If transfer distance is unlimited, don't remove
-               if(object->unlimitedTransferDistance())
+
+               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;
+               } else if (distance_f <= radius_f)
                        continue;
 
-               f32 distance_f = object->getBasePosition().getDistanceFrom(pos_f);
+               // Object is no longer visible
+               removed_objects.push(id);
+       }
+}
 
-               if(distance_f >= radius_f)
-               {
-                       removed_objects.insert(id);
+void ServerEnvironment::setStaticForActiveObjectsInBlock(
+       v3s16 blockpos, bool static_exists, v3s16 static_block)
+{
+       MapBlock *block = m_map->getBlockNoCreateNoEx(blockpos);
+       if (!block)
+               return;
+
+       for (std::map<u16, StaticObject>::iterator
+                       so_it = block->m_static_objects.m_active.begin();
+                       so_it != block->m_static_objects.m_active.end(); ++so_it) {
+               // Get the ServerActiveObject counterpart to this StaticObject
+               std::map<u16, ServerActiveObject *>::iterator ao_it;
+               ao_it = m_active_objects.find(so_it->first);
+               if (ao_it == m_active_objects.end()) {
+                       // If this ever happens, there must be some kind of nasty bug.
+                       errorstream << "ServerEnvironment::setStaticForObjectsInBlock(): "
+                               "Object from MapBlock::m_static_objects::m_active not found "
+                               "in m_active_objects";
                        continue;
                }
-               
-               // Not removed
+
+               ServerActiveObject *sao = ao_it->second;
+               sao->m_static_exists = static_exists;
+               sao->m_static_block  = static_block;
        }
 }
 
@@ -1522,9 +1776,9 @@ ActiveObjectMessage ServerEnvironment::getActiveObjectMessage()
 {
        if(m_active_object_messages.empty())
                return ActiveObjectMessage(0);
-       
+
        ActiveObjectMessage message = m_active_object_messages.front();
-       m_active_object_messages.pop_front();
+       m_active_object_messages.pop();
        return message;
 }
 
@@ -1535,7 +1789,7 @@ ActiveObjectMessage ServerEnvironment::getActiveObjectMessage()
 u16 ServerEnvironment::addActiveObjectRaw(ServerActiveObject *object,
                bool set_changed, u32 dtime_s)
 {
-       assert(object);
+       assert(object); // Pre-condition
        if(object->getId() == 0){
                u16 new_id = getFreeServerActiveObjectId(m_active_objects);
                if(new_id == 0)
@@ -1560,21 +1814,32 @@ 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;*/
-                       
+
        m_active_objects[object->getId()] = object;
-  
+
        verbosestream<<"ServerEnvironment::addActiveObjectRaw(): "
                        <<"Added id="<<object->getId()<<"; there are now "
                        <<m_active_objects.size()<<" active objects."
                        <<std::endl;
-       
+
        // Register reference in scripting api (must be done before post-init)
        m_script->addObjectReference(object);
        // Post-initialize object
        object->addedToEnvironment(dtime_s);
-       
+
        // Add static data to block
        if(object->isStaticAllowed())
        {
@@ -1591,8 +1856,8 @@ u16 ServerEnvironment::addActiveObjectRaw(ServerActiveObject *object,
                        object->m_static_block = blockpos;
 
                        if(set_changed)
-                               block->raiseModified(MOD_STATE_WRITE_NEEDED, 
-                                               "addActiveObjectRaw");
+                               block->raiseModified(MOD_STATE_WRITE_NEEDED,
+                                       MOD_REASON_ADD_ACTIVE_OBJECT_RAW);
                } else {
                        v3s16 p = floatToInt(objectpos, BS);
                        errorstream<<"ServerEnvironment::addActiveObjectRaw(): "
@@ -1600,7 +1865,7 @@ u16 ServerEnvironment::addActiveObjectRaw(ServerActiveObject *object,
                                        <<" statically (pos="<<PP(p)<<")"<<std::endl;
                }
        }
-       
+
        return object->getId();
 }
 
@@ -1609,11 +1874,10 @@ u16 ServerEnvironment::addActiveObjectRaw(ServerActiveObject *object,
 */
 void ServerEnvironment::removeRemovedObjects()
 {
-       std::list<u16> objects_to_remove;
+       std::vector<u16> objects_to_remove;
        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;
                ServerActiveObject* obj = i->second;
                // This shouldn't happen but check it
@@ -1642,7 +1906,7 @@ void ServerEnvironment::removeRemovedObjects()
                        if (block) {
                                block->m_static_objects.remove(id);
                                block->raiseModified(MOD_STATE_WRITE_NEEDED,
-                                               "removeRemovedObjects/remove");
+                                       MOD_REASON_REMOVE_OBJECTS_REMOVE);
                                obj->m_static_exists = false;
                        } else {
                                infostream<<"Failed to emerge block from which an object to "
@@ -1667,7 +1931,7 @@ void ServerEnvironment::removeRemovedObjects()
                                        block->m_static_objects.m_stored.push_back(i->second);
                                        block->m_static_objects.m_active.erase(id);
                                        block->raiseModified(MOD_STATE_WRITE_NEEDED,
-                                                       "removeRemovedObjects/deactivate");
+                                               MOD_REASON_REMOVE_OBJECTS_DEACTIVATE);
                                }
                        } else {
                                infostream<<"Failed to emerge block from which an object to "
@@ -1683,13 +1947,13 @@ void ServerEnvironment::removeRemovedObjects()
                // Delete
                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::list<u16>::iterator i = objects_to_remove.begin();
-                       i != objects_to_remove.end(); ++i)
-       {
+       for(std::vector<u16>::iterator i = objects_to_remove.begin();
+                       i != objects_to_remove.end(); ++i) {
                m_active_objects.erase(*i);
        }
 }
@@ -1733,17 +1997,19 @@ static void print_hexdump(std::ostream &o, const std::string &data)
 */
 void ServerEnvironment::activateObjects(MapBlock *block, u32 dtime_s)
 {
-       if(block==NULL)
+       if(block == NULL)
                return;
+
        // Ignore if no stored objects (to not set changed flag)
-       if(block->m_static_objects.m_stored.size() == 0)
+       if(block->m_static_objects.m_stored.empty())
                return;
+
        verbosestream<<"ServerEnvironment::activateObjects(): "
                        <<"activating objects of block "<<PP(block->getPos())
                        <<" ("<<block->m_static_objects.m_stored.size()
                        <<" objects)"<<std::endl;
        bool large_amount = (block->m_static_objects.m_stored.size() > g_settings->getU16("max_objects_per_block"));
-       if(large_amount){
+       if (large_amount) {
                errorstream<<"suspiciously large amount of objects detected: "
                                <<block->m_static_objects.m_stored.size()<<" in "
                                <<PP(block->getPos())
@@ -1751,32 +2017,28 @@ void ServerEnvironment::activateObjects(MapBlock *block, u32 dtime_s)
                // Clear stored list
                block->m_static_objects.m_stored.clear();
                block->raiseModified(MOD_STATE_WRITE_NEEDED,
-                               "stored list cleared in activateObjects due to "
-                               "large amount of objects");
+                       MOD_REASON_TOO_MANY_OBJECTS);
                return;
        }
 
        // Activate stored objects
-       std::list<StaticObject> new_stored;
-       for(std::list<StaticObject>::iterator
+       std::vector<StaticObject> new_stored;
+       for (std::vector<StaticObject>::iterator
                        i = block->m_static_objects.m_stored.begin();
-                       i != block->m_static_objects.m_stored.end(); ++i)
-       {
-               /*infostream<<"Server: Creating an active object from "
-                               <<"static data"<<std::endl;*/
+                       i != block->m_static_objects.m_stored.end(); ++i) {
                StaticObject &s_obj = *i;
+
                // Create an active object from the data
                ServerActiveObject *obj = ServerActiveObject::create
-                               (s_obj.type, this, 0, s_obj.pos, s_obj.data);
+                               ((ActiveObjectType) s_obj.type, this, 0, s_obj.pos, s_obj.data);
                // If couldn't create object, store static data back.
-               if(obj==NULL)
-               {
+               if(obj == NULL) {
                        errorstream<<"ServerEnvironment::activateObjects(): "
                                        <<"failed to create active object from static object "
                                        <<"in block "<<PP(s_obj.pos/BS)
                                        <<" type="<<(int)s_obj.type<<" data:"<<std::endl;
                        print_hexdump(verbosestream, s_obj.data);
-                       
+
                        new_stored.push_back(s_obj);
                        continue;
                }
@@ -1789,10 +2051,9 @@ void ServerEnvironment::activateObjects(MapBlock *block, u32 dtime_s)
        // Clear stored list
        block->m_static_objects.m_stored.clear();
        // Add leftover failed stuff to stored list
-       for(std::list<StaticObject>::iterator
+       for(std::vector<StaticObject>::iterator
                        i = new_stored.begin();
-                       i != new_stored.end(); ++i)
-       {
+                       i != new_stored.end(); ++i) {
                StaticObject &s_obj = *i;
                block->m_static_objects.m_stored.push_back(s_obj);
        }
@@ -1828,18 +2089,17 @@ void ServerEnvironment::activateObjects(MapBlock *block, u32 dtime_s)
        If force_delete is set, active object is deleted nevertheless. It
        shall only be set so in the destructor of the environment.
 
-       If block wasn't generated (not in memory or on disk), 
+       If block wasn't generated (not in memory or on disk),
 */
 void ServerEnvironment::deactivateFarObjects(bool force_delete)
 {
-       std::list<u16> objects_to_remove;
+       std::vector<u16> objects_to_remove;
        for(std::map<u16, ServerActiveObject*>::iterator
                        i = m_active_objects.begin();
-                       i != m_active_objects.end(); ++i)
-       {
+                       i != m_active_objects.end(); ++i) {
                ServerActiveObject* obj = i->second;
                assert(obj);
-               
+
                // Do not deactivate if static data creation not allowed
                if(!force_delete && !obj->isStaticAllowed())
                        continue;
@@ -1849,7 +2109,7 @@ void ServerEnvironment::deactivateFarObjects(bool force_delete)
                        continue;
 
                u16 id = i->first;
-               v3f objectpos = obj->getBasePosition(); 
+               v3f objectpos = obj->getBasePosition();
 
                // The block in which the object resides in
                v3s16 blockpos_o = getNodeBlockPos(floatToInt(objectpos, BS));
@@ -1878,7 +2138,7 @@ void ServerEnvironment::deactivateFarObjects(bool force_delete)
                        block->m_static_objects.insert(id, s_obj);
                        obj->m_static_block = blockpos_o;
                        block->raiseModified(MOD_STATE_WRITE_NEEDED,
-                                       "deactivateFarObjects: Static data moved in");
+                               MOD_REASON_STATIC_DATA_ADDED);
 
                        // Delete from block where object was located
                        block = m_map->emergeBlock(old_static_block, false);
@@ -1891,7 +2151,7 @@ void ServerEnvironment::deactivateFarObjects(bool force_delete)
                        }
                        block->m_static_objects.remove(id);
                        block->raiseModified(MOD_STATE_WRITE_NEEDED,
-                                       "deactivateFarObjects: Static data moved out");
+                               MOD_REASON_STATIC_DATA_REMOVED);
                        continue;
                }
 
@@ -1915,36 +2175,38 @@ void ServerEnvironment::deactivateFarObjects(bool force_delete)
                        // Create new static object
                        std::string staticdata_new = obj->getStaticData();
                        StaticObject s_obj(obj->getType(), objectpos, staticdata_new);
-                       
+
                        bool stays_in_same_block = false;
                        bool data_changed = true;
 
-                       if(obj->m_static_exists){
-                               if(obj->m_static_block == blockpos_o)
+                       if (obj->m_static_exists) {
+                               if (obj->m_static_block == blockpos_o)
                                        stays_in_same_block = true;
 
                                MapBlock *block = m_map->emergeBlock(obj->m_static_block, false);
-                               
-                               std::map<u16, StaticObject>::iterator n =
+
+                               if (block) {
+                                       std::map<u16, StaticObject>::iterator n =
                                                block->m_static_objects.m_active.find(id);
-                               if(n != block->m_static_objects.m_active.end()){
-                                       StaticObject static_old = n->second;
+                                       if (n != block->m_static_objects.m_active.end()) {
+                                               StaticObject static_old = n->second;
 
-                                       float save_movem = obj->getMinimumSavedMovement();
+                                               float save_movem = obj->getMinimumSavedMovement();
 
-                                       if(static_old.data == staticdata_new &&
-                                                       (static_old.pos - objectpos).getLength() < save_movem)
-                                               data_changed = false;
-                               } else {
-                                       errorstream<<"ServerEnvironment::deactivateFarObjects(): "
+                                               if (static_old.data == staticdata_new &&
+                                                               (static_old.pos - objectpos).getLength() < save_movem)
+                                                       data_changed = false;
+                                       } else {
+                                               errorstream<<"ServerEnvironment::deactivateFarObjects(): "
                                                        <<"id="<<id<<" m_static_exists=true but "
                                                        <<"static data doesn't actually exist in "
                                                        <<PP(obj->m_static_block)<<std::endl;
+                                       }
                                }
                        }
 
                        bool shall_be_written = (!stays_in_same_block || data_changed);
-                       
+
                        // Delete old static object
                        if(obj->m_static_exists)
                        {
@@ -1956,8 +2218,7 @@ void ServerEnvironment::deactivateFarObjects(bool force_delete)
                                        // Only mark block as modified if data changed considerably
                                        if(shall_be_written)
                                                block->raiseModified(MOD_STATE_WRITE_NEEDED,
-                                                               "deactivateFarObjects: Static data "
-                                                               "changed considerably");
+                                                       MOD_REASON_STATIC_DATA_CHANGED);
                                }
                        }
 
@@ -1992,20 +2253,19 @@ 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);
                                        }
                                        // Store static data
                                        u16 store_id = pending_delete ? id : 0;
                                        block->m_static_objects.insert(store_id, s_obj);
-                                       
+
                                        // Only mark block as modified if data changed considerably
                                        if(shall_be_written)
                                                block->raiseModified(MOD_STATE_WRITE_NEEDED,
-                                                               "deactivateFarObjects: Static data "
-                                                               "changed considerably");
-                                       
+                                                       MOD_REASON_STATIC_DATA_CHANGED);
+
                                        obj->m_static_exists = true;
                                        obj->m_static_block = block->getPos();
                                }
@@ -2035,7 +2295,7 @@ void ServerEnvironment::deactivateFarObjects(bool force_delete)
                        obj->m_pending_deactivation = true;
                        continue;
                }
-               
+
                verbosestream<<"ServerEnvironment::deactivateFarObjects(): "
                                <<"object id="<<id<<" is not known by clients"
                                <<"; deleting"<<std::endl;
@@ -2053,14 +2313,12 @@ void ServerEnvironment::deactivateFarObjects(bool force_delete)
        }
 
        // Remove references from m_active_objects
-       for(std::list<u16>::iterator i = objects_to_remove.begin();
-                       i != objects_to_remove.end(); ++i)
-       {
+       for(std::vector<u16>::iterator i = objects_to_remove.begin();
+                       i != objects_to_remove.end(); ++i) {
                m_active_objects.erase(*i);
        }
 }
 
-
 #ifndef SERVER
 
 #include "clientsimpleobject.h"
@@ -2078,6 +2336,8 @@ ClientEnvironment::ClientEnvironment(ClientMap *map, scene::ISceneManager *smgr,
        m_gamedef(gamedef),
        m_irr(irr)
 {
+       char zero = 0;
+       memset(attachement_parent_ids, zero, sizeof(attachement_parent_ids));
 }
 
 ClientEnvironment::~ClientEnvironment()
@@ -2090,9 +2350,8 @@ ClientEnvironment::~ClientEnvironment()
                delete i->second;
        }
 
-       for(std::list<ClientSimpleObject*>::iterator
-                       i = m_simple_objects.begin(); i != m_simple_objects.end(); ++i)
-       {
+       for(std::vector<ClientSimpleObject*>::iterator
+                       i = m_simple_objects.begin(); i != m_simple_objects.end(); ++i) {
                delete *i;
        }
 
@@ -2112,21 +2371,21 @@ 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
        */
-       assert(!(player->isLocal() == true && getLocalPlayer() != NULL));
+       FATAL_ERROR_IF(player->isLocal() == true && getLocalPlayer() != NULL,
+               "Player is local but there is already a local player");
 
        Environment::addPlayer(player);
 }
 
 LocalPlayer * ClientEnvironment::getLocalPlayer()
 {
-       for(std::list<Player*>::iterator i = m_players.begin();
-                       i != m_players.end(); ++i)
-       {
+       for(std::vector<Player*>::iterator i = m_players.begin();
+                       i != m_players.end(); ++i) {
                Player *player = *i;
                if(player->isLocal())
                        return (LocalPlayer*)player;
@@ -2136,7 +2395,7 @@ LocalPlayer * ClientEnvironment::getLocalPlayer()
 
 void ClientEnvironment::step(float dtime)
 {
-       DSTACK(__FUNCTION_NAME);
+       DSTACK(FUNCTION_NAME);
 
        /* Step time of day */
        stepTimeOfDay(dtime);
@@ -2149,15 +2408,15 @@ void ClientEnvironment::step(float dtime)
        LocalPlayer *lplayer = getLocalPlayer();
        assert(lplayer);
        // collision info queue
-       std::list<CollisionInfo> player_collisions;
-       
+       std::vector<CollisionInfo> player_collisions;
+
        /*
                Get the speed the player is going
        */
        bool is_climbing = lplayer->is_climbing;
-       
+
        f32 player_speed = lplayer->getSpeed().getLength();
-       
+
        /*
                Maximum position increment
        */
@@ -2169,15 +2428,15 @@ void ClientEnvironment::step(float dtime)
        f32 dtime_max_increment = 1;
        if(player_speed > 0.001)
                dtime_max_increment = position_max_increment / player_speed;
-       
+
        // Maximum time increment is 10ms or lower
        if(dtime_max_increment > 0.01)
                dtime_max_increment = 0.01;
-       
+
        // Don't allow overly huge dtime
        if(dtime > 0.5)
                dtime = 0.5;
-       
+
        f32 dtime_downcount = dtime;
 
        /*
@@ -2205,11 +2464,11 @@ void ClientEnvironment::step(float dtime)
                        */
                        dtime_downcount = 0;
                }
-               
+
                /*
                        Handle local player
                */
-               
+
                {
                        // Apply physics
                        if(free_move == false && is_climbing == false)
@@ -2235,18 +2494,9 @@ void ClientEnvironment::step(float dtime)
                                        if(dl > lplayer->movement_liquid_fluidity_smooth)
                                                dl = lplayer->movement_liquid_fluidity_smooth;
                                        dl *= (lplayer->liquid_viscosity * viscosity_factor) + (1 - viscosity_factor);
-                                       
+
                                        v3f d = d_wanted.normalize() * dl;
                                        speed += d;
-                                       
-#if 0 // old code
-                                       if(speed.X > lplayer->movement_liquid_fluidity + lplayer->movement_liquid_fluidity_smooth)      speed.X -= lplayer->movement_liquid_fluidity_smooth;
-                                       if(speed.X < -lplayer->movement_liquid_fluidity - lplayer->movement_liquid_fluidity_smooth)     speed.X += lplayer->movement_liquid_fluidity_smooth;
-                                       if(speed.Y > lplayer->movement_liquid_fluidity + lplayer->movement_liquid_fluidity_smooth)      speed.Y -= lplayer->movement_liquid_fluidity_smooth;
-                                       if(speed.Y < -lplayer->movement_liquid_fluidity - lplayer->movement_liquid_fluidity_smooth)     speed.Y += lplayer->movement_liquid_fluidity_smooth;
-                                       if(speed.Z > lplayer->movement_liquid_fluidity + lplayer->movement_liquid_fluidity_smooth)      speed.Z -= lplayer->movement_liquid_fluidity_smooth;
-                                       if(speed.Z < -lplayer->movement_liquid_fluidity - lplayer->movement_liquid_fluidity_smooth)     speed.Z += lplayer->movement_liquid_fluidity_smooth;
-#endif
                                }
 
                                lplayer->setSpeed(speed);
@@ -2261,13 +2511,11 @@ void ClientEnvironment::step(float dtime)
                }
        }
        while(dtime_downcount > 0.001);
-               
+
        //std::cout<<"Looped "<<loopcount<<" times."<<std::endl;
-       
-       for(std::list<CollisionInfo>::iterator
-                       i = player_collisions.begin();
-                       i != player_collisions.end(); ++i)
-       {
+
+       for(std::vector<CollisionInfo>::iterator i = player_collisions.begin();
+                       i != player_collisions.end(); ++i) {
                CollisionInfo &info = *i;
                v3f speed_diff = info.new_speed - info.old_speed;;
                // Handle only fall damage
@@ -2300,14 +2548,14 @@ void ClientEnvironment::step(float dtime)
                        }
                }
        }
-       
+
        /*
                A quick draft of lava damage
        */
        if(m_lava_hurt_interval.step(dtime, 1.0))
        {
                v3f pf = lplayer->getPosition();
-               
+
                // Feet, middle and head
                v3s16 p1 = floatToInt(pf + v3f(0, BS*0.1, 0), BS);
                MapNode n1 = m_map->getNodeNoEx(p1);
@@ -2323,7 +2571,7 @@ void ClientEnvironment::step(float dtime)
                                m_gamedef->ndef()->get(n2).damage_per_second);
                damage_per_second = MYMAX(damage_per_second,
                                m_gamedef->ndef()->get(n3).damage_per_second);
-               
+
                if(damage_per_second != 0)
                {
                        damageLocalPlayer(damage_per_second, true);
@@ -2382,39 +2630,42 @@ void ClientEnvironment::step(float dtime)
        /*
                Stuff that can be done in an arbitarily large dtime
        */
-       for(std::list<Player*>::iterator i = m_players.begin();
-                       i != m_players.end(); ++i)
-       {
+       for(std::vector<Player*>::iterator i = m_players.begin();
+                       i != m_players.end(); ++i) {
                Player *player = *i;
-               
+
                /*
                        Handle non-local players
                */
-               if(player->isLocal() == false)
-               {
+               if(player->isLocal() == false) {
                        // Move
                        player->move(dtime, this, 100*BS);
 
                }
-               
-               // Update lighting on all players on client
-               float light = 1.0;
-               try{
-                       // Get node at head
-                       v3s16 p = player->getLightPosition();
-                       MapNode n = m_map->getNode(p);
-                       light = n.getLightBlendF1((float)getDayNightRatio()/1000, m_gamedef->ndef());
-               }
-               catch(InvalidPositionException &e){
-                       light = blend_light_f1((float)getDayNightRatio()/1000, LIGHT_SUN, 0);
-               }
-               player->light = light;
        }
-       
+
+       // Update lighting on local player (used for wield item)
+       u32 day_night_ratio = getDayNightRatio();
+       {
+               // Get node at head
+
+               // On InvalidPositionException, use this as default
+               // (day: LIGHT_SUN, night: 0)
+               MapNode node_at_lplayer(CONTENT_AIR, 0x0f, 0);
+
+               v3s16 p = lplayer->getLightPosition();
+               node_at_lplayer = m_map->getNodeNoEx(p);
+
+               u16 light = getInteriorLight(node_at_lplayer, 0, m_gamedef->ndef());
+               u8 day = light & 0xff;
+               u8 night = (light >> 8) & 0xff;
+               finalColorBlend(lplayer->light_color, day, night, day_night_ratio);
+       }
+
        /*
                Step active objects and update lighting of them
        */
-       
+
        g_profiler->avg("CEnv: num of objects", m_active_objects.size());
        bool update_lighting = m_active_object_light_update_interval.step(dtime, 0.21);
        for(std::map<u16, ClientActiveObject*>::iterator
@@ -2429,15 +2680,16 @@ void ClientEnvironment::step(float dtime)
                {
                        // Update lighting
                        u8 light = 0;
-                       try{
-                               // Get node at head
-                               v3s16 p = obj->getLightPosition();
-                               MapNode n = m_map->getNode(p);
-                               light = n.getLightBlend(getDayNightRatio(), m_gamedef->ndef());
-                       }
-                       catch(InvalidPositionException &e){
-                               light = blend_light(getDayNightRatio(), LIGHT_SUN, 0);
-                       }
+                       bool pos_ok;
+
+                       // Get node at head
+                       v3s16 p = obj->getLightPosition();
+                       MapNode n = m_map->getNodeNoEx(p, &pos_ok);
+                       if (pos_ok)
+                               light = n.getLightBlend(day_night_ratio, m_gamedef->ndef());
+                       else
+                               light = blend_light(day_night_ratio, LIGHT_SUN, 0);
+
                        obj->updateLight(light);
                }
        }
@@ -2446,25 +2698,36 @@ void ClientEnvironment::step(float dtime)
                Step and handle simple objects
        */
        g_profiler->avg("CEnv: num of simple objects", m_simple_objects.size());
-       for(std::list<ClientSimpleObject*>::iterator
-                       i = m_simple_objects.begin(); i != m_simple_objects.end();)
-       {
-               ClientSimpleObject *simple = *i;
-               std::list<ClientSimpleObject*>::iterator cur = i;
-               ++i;
+       for(std::vector<ClientSimpleObject*>::iterator
+                       i = m_simple_objects.begin(); i != m_simple_objects.end();) {
+               std::vector<ClientSimpleObject*>::iterator cur = i;
+               ClientSimpleObject *simple = *cur;
+
                simple->step(dtime);
-               if(simple->m_to_be_removed){
+               if(simple->m_to_be_removed) {
                        delete simple;
-                       m_simple_objects.erase(cur);
+                       i = m_simple_objects.erase(cur);
+               }
+               else {
+                       ++i;
                }
        }
 }
-       
+
 void ClientEnvironment::addSimpleObject(ClientSimpleObject *simple)
 {
        m_simple_objects.push_back(simple);
 }
 
+GenericCAO* ClientEnvironment::getGenericCAO(u16 id)
+{
+       ClientActiveObject *obj = getActiveObject(id);
+       if (obj && obj->getType() == ACTIVEOBJECT_TYPE_GENERIC)
+               return (GenericCAO*) obj;
+       else
+               return NULL;
+}
+
 ClientActiveObject* ClientEnvironment::getActiveObject(u16 id)
 {
        std::map<u16, ClientActiveObject*>::iterator n;
@@ -2494,7 +2757,7 @@ u16 getFreeClientActiveObjectId(
                last_used_id ++;
                if(isFreeClientActiveObjectId(last_used_id, objects))
                        return last_used_id;
-               
+
                if(last_used_id == startid)
                        return 0;
        }
@@ -2502,7 +2765,7 @@ u16 getFreeClientActiveObjectId(
 
 u16 ClientEnvironment::addActiveObject(ClientActiveObject *object)
 {
-       assert(object);
+       assert(object); // Pre-condition
        if(object->getId() == 0)
        {
                u16 new_id = getFreeClientActiveObjectId(m_active_objects);
@@ -2528,15 +2791,16 @@ u16 ClientEnvironment::addActiveObject(ClientActiveObject *object)
        object->addToScene(m_smgr, m_texturesource, m_irr);
        { // Update lighting immediately
                u8 light = 0;
-               try{
-                       // Get node at head
-                       v3s16 p = object->getLightPosition();
-                       MapNode n = m_map->getNode(p);
+               bool pos_ok;
+
+               // Get node at head
+               v3s16 p = object->getLightPosition();
+               MapNode n = m_map->getNodeNoEx(p, &pos_ok);
+               if (pos_ok)
                        light = n.getLightBlend(getDayNightRatio(), m_gamedef->ndef());
-               }
-               catch(InvalidPositionException &e){
+               else
                        light = blend_light(getDayNightRatio(), LIGHT_SUN, 0);
-               }
+
                object->updateLight(light);
        }
        return object->getId();
@@ -2546,7 +2810,7 @@ void ClientEnvironment::addActiveObject(u16 id, u8 type,
                const std::string &init_data)
 {
        ClientActiveObject* obj =
-                       ClientActiveObject::create(type, m_gamedef, this);
+                       ClientActiveObject::create((ActiveObjectType) type, m_gamedef, this);
        if(obj == NULL)
        {
                infostream<<"ClientEnvironment::addActiveObject(): "
@@ -2554,7 +2818,7 @@ void ClientEnvironment::addActiveObject(u16 id, u8 type,
                                <<std::endl;
                return;
        }
-       
+
        obj->setId(id);
 
        try
@@ -2590,28 +2854,23 @@ void ClientEnvironment::removeActiveObject(u16 id)
        m_active_objects.erase(id);
 }
 
-void ClientEnvironment::processActiveObjectMessage(u16 id,
-               const std::string &data)
+void ClientEnvironment::processActiveObjectMessage(u16 id, const std::string &data)
 {
-       ClientActiveObject* obj = getActiveObject(id);
-       if(obj == NULL)
-       {
-               infostream<<"ClientEnvironment::processActiveObjectMessage():"
-                               <<" got message for id="<<id<<", which doesn't exist."
-                               <<std::endl;
+       ClientActiveObject *obj = getActiveObject(id);
+       if (obj == NULL) {
+               infostream << "ClientEnvironment::processActiveObjectMessage():"
+                       << " got message for id=" << id << ", which doesn't exist."
+                       << std::endl;
                return;
        }
-       try
-       {
+
+       try {
                obj->processMessage(data);
-       }
-       catch(SerializationError &e)
-       {
+       } catch (SerializationError &e) {
                errorstream<<"ClientEnvironment::processActiveObjectMessage():"
-                               <<" id="<<id<<" type="<<obj->getType()
-                               <<" SerializationError in processMessage(),"
-                               <<" message="<<serializeJsonString(data)
-                               <<std::endl;
+                       << " id=" << id << " type=" << obj->getType()
+                       << " SerializationError in processMessage(): " << e.what()
+                       << std::endl;
        }
 }
 
@@ -2623,9 +2882,9 @@ void ClientEnvironment::damageLocalPlayer(u8 damage, bool handle_hp)
 {
        LocalPlayer *lplayer = getLocalPlayer();
        assert(lplayer);
-       
-       if(handle_hp){
-               if(lplayer->hp > damage)
+
+       if (handle_hp) {
+               if (lplayer->hp > damage)
                        lplayer->hp -= damage;
                else
                        lplayer->hp = 0;
@@ -2635,7 +2894,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)
@@ -2643,13 +2902,13 @@ 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);
 }
 
 /*
        Client likes to call these
 */
-       
+
 void ClientEnvironment::getActiveObjects(v3f origin, f32 max_d,
                std::vector<DistanceSortedActiveObject> &dest)
 {
@@ -2677,11 +2936,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
-
-