]> git.lizzy.rs Git - minetest.git/blobdiff - src/environment.cpp
Use single box for halo mesh
[minetest.git] / src / environment.cpp
index 96353dffb90f3afb851779856588cb3c665ebed4..3bf5e1f0a41b6fd8803a10d231b8017a93ca18e4 100644 (file)
@@ -39,19 +39,20 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #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 "jthread/jmutexautolock.h"
+#include "threading/mutex_auto_lock.h"
 
 #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
 
 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)
 {
@@ -69,7 +70,7 @@ Environment::~Environment()
 
 void Environment::addPlayer(Player *player)
 {
-       DSTACK(__FUNCTION_NAME);
+       DSTACK(FUNCTION_NAME);
        /*
                Check that peer_ids are unique.
                Also check that names are unique.
@@ -84,28 +85,11 @@ void Environment::addPlayer(Player *player)
        m_players.push_back(player);
 }
 
-void Environment::removePlayer(u16 peer_id)
-{
-       DSTACK(__FUNCTION_NAME);
-
-       for(std::vector<Player*>::iterator i = m_players.begin();
-                       i != m_players.end();)
-       {
-               Player *player = *i;
-               if(player->peer_id == peer_id) {
-                       delete player;
-                       i = m_players.erase(i);
-               } else {
-                       ++i;
-               }
-       }
-}
-
-void Environment::removePlayer(const char *name)
+void Environment::removePlayer(Player* player)
 {
        for (std::vector<Player*>::iterator it = m_players.begin();
                        it != m_players.end(); ++it) {
-               if (strcmp((*it)->getName(), name) == 0) {
+               if ((*it) == player) {
                        delete *it;
                        m_players.erase(it);
                        return;
@@ -196,70 +180,76 @@ std::vector<Player*> Environment::getPlayers(bool ignore_disconnected)
 
 u32 Environment::getDayNightRatio()
 {
-       if(m_enable_day_night_ratio_override)
+       MutexAutoLock lock(this->m_time_lock);
+       if (m_enable_day_night_ratio_override)
                return m_day_night_ratio_override;
-       return time_to_daynight_ratio(m_time_of_day_f*24000, m_cache_enable_shaders);
+       return time_to_daynight_ratio(m_time_of_day_f * 24000, m_cache_enable_shaders);
 }
 
 void Environment::setTimeOfDaySpeed(float speed)
 {
-       JMutexAutoLock(this->m_timeofday_lock);
        m_time_of_day_speed = speed;
 }
 
 float Environment::getTimeOfDaySpeed()
 {
-       JMutexAutoLock(this->m_timeofday_lock);
-       float retval = m_time_of_day_speed;
-       return retval;
+       return m_time_of_day_speed;
+}
+
+void Environment::setDayNightRatioOverride(bool enable, u32 value)
+{
+       MutexAutoLock lock(this->m_time_lock);
+       m_enable_day_night_ratio_override = enable;
+       m_day_night_ratio_override = value;
 }
 
 void Environment::setTimeOfDay(u32 time)
 {
-       JMutexAutoLock(this->m_time_lock);
+       MutexAutoLock lock(this->m_time_lock);
        m_time_of_day = time;
        m_time_of_day_f = (float)time / 24000.0;
 }
 
 u32 Environment::getTimeOfDay()
 {
-       JMutexAutoLock(this->m_time_lock);
-       u32 retval = m_time_of_day;
-       return retval;
+       MutexAutoLock lock(this->m_time_lock);
+       return m_time_of_day;
 }
 
 float Environment::getTimeOfDayF()
 {
-       JMutexAutoLock(this->m_time_lock);
-       float retval = m_time_of_day_f;
-       return retval;
+       MutexAutoLock lock(this->m_time_lock);
+       return m_time_of_day_f;
 }
 
 void Environment::stepTimeOfDay(float dtime)
 {
-       // getTimeOfDaySpeed lock the value we need to prevent MT problems
-       float day_speed = getTimeOfDaySpeed();
+       MutexAutoLock lock(this->m_time_lock);
+
+       // Cached in order to prevent the two reads we do to give
+       // different results (can be written by code not under the lock)
+       f32 cached_time_of_day_speed = m_time_of_day_speed;
 
-       m_time_counter += dtime;
-       f32 speed = day_speed * 24000./(24.*3600);
-       u32 units = (u32)(m_time_counter*speed);
+       f32 speed = cached_time_of_day_speed * 24000. / (24. * 3600);
+       m_time_conversion_skew += dtime;
+       u32 units = (u32)(m_time_conversion_skew * speed);
        bool sync_f = false;
-       if(units > 0){
+       if (units > 0) {
                // Sync at overflow
-               if(m_time_of_day + units >= 24000)
+               if (m_time_of_day + units >= 24000)
                        sync_f = true;
                m_time_of_day = (m_time_of_day + units) % 24000;
-               if(sync_f)
+               if (sync_f)
                        m_time_of_day_f = (float)m_time_of_day / 24000.0;
        }
        if (speed > 0) {
-               m_time_counter -= (f32)units / speed;
+               m_time_conversion_skew -= (f32)units / speed;
        }
-       if(!sync_f){
-               m_time_of_day_f += day_speed/24/3600*dtime;
-               if(m_time_of_day_f > 1.0)
+       if (!sync_f) {
+               m_time_of_day_f += cached_time_of_day_speed / 24 / 3600 * dtime;
+               if (m_time_of_day_f > 1.0)
                        m_time_of_day_f -= 1.0;
-               if(m_time_of_day_f < 0.0)
+               if (m_time_of_day_f < 0.0)
                        m_time_of_day_f += 1.0;
        }
 }
@@ -364,6 +354,7 @@ ServerEnvironment::ServerEnvironment(ServerMap *map,
        m_active_block_interval_overload_skip(0),
        m_game_time(0),
        m_game_time_fraction_counter(0),
+       m_last_clear_objects_time(0),
        m_recommended_send_interval(0.1),
        m_max_lag_estimate(0.1)
 {
@@ -425,6 +416,18 @@ bool ServerEnvironment::line_of_sight(v3f pos1, v3f pos2, float stepsize, v3s16
        return true;
 }
 
+void ServerEnvironment::kickAllPlayers(AccessDeniedCode reason,
+               const std::string &str_reason, bool reconnect)
+{
+       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);
+       }
+}
+
 void ServerEnvironment::saveLoadedPlayers()
 {
        std::string players_path = m_path_world + DIR_DELIM "players";
@@ -440,15 +443,12 @@ void ServerEnvironment::saveLoadedPlayers()
        }
 }
 
-void ServerEnvironment::savePlayer(const std::string &playername)
+void ServerEnvironment::savePlayer(RemotePlayer *player)
 {
        std::string players_path = m_path_world + DIR_DELIM "players";
        fs::CreateDir(players_path);
 
-       RemotePlayer *player = static_cast<RemotePlayer*>(getPlayer(playername.c_str()));
-       if (player) {
-               player->save(players_path);
-       }
+       player->save(players_path);
 }
 
 Player *ServerEnvironment::loadPlayer(const std::string &playername)
@@ -504,6 +504,7 @@ void ServerEnvironment::saveMeta()
        Settings args;
        args.setU64("game_time", m_game_time);
        args.setU64("time_of_day", getTimeOfDay());
+       args.setU64("last_clear_objects_time", m_last_clear_objects_time);
        args.writeLines(ss);
        ss<<"EnvArgsEnd\n";
 
@@ -542,10 +543,17 @@ void ServerEnvironment::loadMeta()
        }
 
        try {
-               m_time_of_day = args.getU64("time_of_day");
+               setTimeOfDay(args.getU64("time_of_day"));
        } catch (SettingNotFoundException &e) {
                // This is not as important
-               m_time_of_day = 9000;
+               setTimeOfDay(9000);
+       }
+
+       try {
+               m_last_clear_objects_time = args.getU64("last_clear_objects_time");
+       } catch (SettingNotFoundException &e) {
+               // If missing, do as if clearObjects was never called
+               m_last_clear_objects_time = 0;
        }
 }
 
@@ -584,35 +592,39 @@ 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::vector<ActiveABM> >::iterator j;
@@ -681,7 +693,7 @@ class ABMHandler
                                continue;
 
                        for(std::vector<ActiveABM>::iterator
-                                       i = j->second.begin(); i != j->second.end(); i++) {
+                                       i = j->second.begin(); i != j->second.end(); ++i) {
                                if(myrand() % i->chance != 0)
                                        continue;
 
@@ -736,13 +748,19 @@ void ServerEnvironment::activateBlock(MapBlock *block, u32 additional_dtime)
        // Get time difference
        u32 dtime_s = 0;
        u32 stamp = block->getTimestamp();
-       if(m_game_time > stamp && stamp != BLOCK_TIMESTAMP_UNDEFINED)
-               dtime_s = m_game_time - block->getTimestamp();
+       if (m_game_time > stamp && stamp != BLOCK_TIMESTAMP_UNDEFINED)
+               dtime_s = m_game_time - stamp;
        dtime_s += additional_dtime;
 
        /*infostream<<"ServerEnvironment::activateBlock(): block timestamp: "
                        <<stamp<<", game time: "<<m_game_time<<std::endl;*/
 
+       // Remove stored static objects if clearObjects was called since block's timestamp
+       if (stamp == BLOCK_TIMESTAMP_UNDEFINED || stamp < m_last_clear_objects_time) {
+               block->m_static_objects.m_stored.clear();
+               // do not set changed flag to avoid unnecessary mapblock writes
+       }
+
        // Set current time as timestamp
        block->setTimestampNoChangedFlag(m_game_time);
 
@@ -759,7 +777,7 @@ void ServerEnvironment::activateBlock(MapBlock *block, u32 additional_dtime)
                MapNode n;
                for(std::map<v3s16, NodeTimer>::iterator
                                i = elapsed_timers.begin();
-                               i != elapsed_timers.end(); i++){
+                               i != elapsed_timers.end(); ++i){
                        n = block->getNodeNoEx(i->first);
                        v3s16 p = i->first + block->getPosRelative();
                        if(m_script->node_on_timer(p,n,i->second.elapsed))
@@ -855,30 +873,30 @@ void ServerEnvironment::getObjectsInsideRadius(std::vector<u16> &objects, v3f po
        }
 }
 
-void ServerEnvironment::clearAllObjects()
+void ServerEnvironment::clearObjects(ClearObjectsMode mode)
 {
-       infostream<<"ServerEnvironment::clearAllObjects(): "
-                       <<"Removing all active objects"<<std::endl;
+       infostream << "ServerEnvironment::clearObjects(): "
+               << "Removing all active objects" << std::endl;
        std::vector<u16> objects_to_remove;
-       for(std::map<u16, ServerActiveObject*>::iterator
+       for (std::map<u16, ServerActiveObject*>::iterator
                        i = m_active_objects.begin();
                        i != m_active_objects.end(); ++i) {
                ServerActiveObject* obj = i->second;
-               if(obj->getType() == ACTIVEOBJECT_TYPE_PLAYER)
+               if (obj->getType() == ACTIVEOBJECT_TYPE_PLAYER)
                        continue;
                u16 id = i->first;
                // Delete static object if block is loaded
-               if(obj->m_static_exists){
+               if (obj->m_static_exists) {
                        MapBlock *block = m_map->getBlockNoCreateNoEx(obj->m_static_block);
-                       if(block){
+                       if (block) {
                                block->m_static_objects.remove(id);
                                block->raiseModified(MOD_STATE_WRITE_NEEDED,
-                                               "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;
@@ -890,39 +908,46 @@ void ServerEnvironment::clearAllObjects()
                m_script->removeObjectReference(obj);
 
                // Delete active object
-               if(obj->environmentDeletes())
+               if (obj->environmentDeletes())
                        delete obj;
                // Id to be removed from m_active_objects
                objects_to_remove.push_back(id);
        }
 
        // Remove references from m_active_objects
-       for(std::vector<u16>::iterator i = objects_to_remove.begin();
+       for (std::vector<u16>::iterator i = objects_to_remove.begin();
                        i != objects_to_remove.end(); ++i) {
                m_active_objects.erase(*i);
        }
 
        // Get list of loaded blocks
        std::vector<v3s16> loaded_blocks;
-       infostream<<"ServerEnvironment::clearAllObjects(): "
-                       <<"Listing all loaded blocks"<<std::endl;
+       infostream << "ServerEnvironment::clearObjects(): "
+               << "Listing all loaded blocks" << std::endl;
        m_map->listAllLoadedBlocks(loaded_blocks);
-       infostream<<"ServerEnvironment::clearAllObjects(): "
-                       <<"Done listing all loaded blocks: "
-                       <<loaded_blocks.size()<<std::endl;
+       infostream << "ServerEnvironment::clearObjects(): "
+               << "Done listing all loaded blocks: "
+               << loaded_blocks.size()<<std::endl;
 
        // Get list of loadable blocks
        std::vector<v3s16> loadable_blocks;
-       infostream<<"ServerEnvironment::clearAllObjects(): "
-                       <<"Listing all loadable blocks"<<std::endl;
-       m_map->listAllLoadableBlocks(loadable_blocks);
-       infostream<<"ServerEnvironment::clearAllObjects(): "
-                       <<"Done listing all loadable blocks: "
-                       <<loadable_blocks.size()
-                       <<", now clearing"<<std::endl;
+       if (mode == CLEAR_OBJECTS_MODE_FULL) {
+               infostream << "ServerEnvironment::clearObjects(): "
+                       << "Listing all loadable blocks" << std::endl;
+               m_map->listAllLoadableBlocks(loadable_blocks);
+               infostream << "ServerEnvironment::clearObjects(): "
+                       << "Done listing all loadable blocks: "
+                       << loadable_blocks.size() << std::endl;
+       } else {
+               loadable_blocks = loaded_blocks;
+       }
+
+       infostream << "ServerEnvironment::clearObjects(): "
+               << "Now clearing objects in " << loadable_blocks.size()
+               << " blocks" << std::endl;
 
        // Grab a reference on each loaded block to avoid unloading it
-       for(std::vector<v3s16>::iterator i = loaded_blocks.begin();
+       for (std::vector<v3s16>::iterator i = loaded_blocks.begin();
                        i != loaded_blocks.end(); ++i) {
                v3s16 p = *i;
                MapBlock *block = m_map->getBlockNoCreateNoEx(p);
@@ -931,50 +956,53 @@ void ServerEnvironment::clearAllObjects()
        }
 
        // Remove objects in all loadable blocks
-       u32 unload_interval = g_settings->getS32("max_clearobjects_extra_loaded_blocks");
-       unload_interval = MYMAX(unload_interval, 1);
+       u32 unload_interval = U32_MAX;
+       if (mode == CLEAR_OBJECTS_MODE_FULL) {
+               unload_interval = g_settings->getS32("max_clearobjects_extra_loaded_blocks");
+               unload_interval = MYMAX(unload_interval, 1);
+       }
        u32 report_interval = loadable_blocks.size() / 10;
        u32 num_blocks_checked = 0;
        u32 num_blocks_cleared = 0;
        u32 num_objs_cleared = 0;
-       for(std::vector<v3s16>::iterator i = loadable_blocks.begin();
+       for (std::vector<v3s16>::iterator i = loadable_blocks.begin();
                        i != loadable_blocks.end(); ++i) {
                v3s16 p = *i;
                MapBlock *block = m_map->emergeBlock(p, false);
-               if(!block){
-                       errorstream<<"ServerEnvironment::clearAllObjects(): "
-                                       <<"Failed to emerge block "<<PP(p)<<std::endl;
+               if (!block) {
+                       errorstream << "ServerEnvironment::clearObjects(): "
+                               << "Failed to emerge block " << PP(p) << std::endl;
                        continue;
                }
                u32 num_stored = block->m_static_objects.m_stored.size();
                u32 num_active = block->m_static_objects.m_active.size();
-               if(num_stored != 0 || num_active != 0){
+               if (num_stored != 0 || num_active != 0) {
                        block->m_static_objects.m_stored.clear();
                        block->m_static_objects.m_active.clear();
                        block->raiseModified(MOD_STATE_WRITE_NEEDED,
-                                       "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::vector<v3s16>::iterator i = loaded_blocks.begin();
+       for (std::vector<v3s16>::iterator i = loaded_blocks.begin();
                        i != loaded_blocks.end(); ++i) {
                v3s16 p = *i;
                MapBlock *block = m_map->getBlockNoCreateNoEx(p);
@@ -982,14 +1010,16 @@ void ServerEnvironment::clearAllObjects()
                block->refDrop();
        }
 
-       infostream<<"ServerEnvironment::clearAllObjects(): "
-                       <<"Finished: Cleared "<<num_objs_cleared<<" objects"
-                       <<" in "<<num_blocks_cleared<<" blocks"<<std::endl;
+       m_last_clear_objects_time = m_game_time;
+
+       infostream << "ServerEnvironment::clearObjects(): "
+               << "Finished: Cleared " << num_objs_cleared << " objects"
+               << " in " << num_blocks_cleared << " blocks" << std::endl;
 }
 
 void ServerEnvironment::step(float dtime)
 {
-       DSTACK(__FUNCTION_NAME);
+       DSTACK(FUNCTION_NAME);
 
        //TimeTaker timer("ServerEnv step");
 
@@ -1139,7 +1169,7 @@ void ServerEnvironment::step(float dtime)
                        // 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 =
@@ -1148,7 +1178,7 @@ void ServerEnvironment::step(float dtime)
                                MapNode n;
                                for(std::map<v3s16, NodeTimer>::iterator
                                                i = elapsed_timers.begin();
-                                               i != elapsed_timers.end(); i++){
+                                               i != elapsed_timers.end(); ++i){
                                        n = block->getNodeNoEx(i->first);
                                        p = i->first + block->getPosRelative();
                                        if(m_script->node_on_timer(p,n,i->second.elapsed))
@@ -1195,7 +1225,7 @@ void ServerEnvironment::step(float dtime)
                u32 time_ms = timer.stop(true);
                u32 max_time_ms = 200;
                if(time_ms > max_time_ms){
-                       infostream<<"WARNING: active block modifiers took "
+                       warningstream<<"active block modifiers took "
                                        <<time_ms<<"ms (longer than "
                                        <<max_time_ms<<"ms)"<<std::endl;
                        m_active_block_interval_overload_skip = (time_ms / max_time_ms) + 1;
@@ -1301,61 +1331,15 @@ u16 ServerEnvironment::addActiveObject(ServerActiveObject *object)
        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;
 
@@ -1371,18 +1355,19 @@ void ServerEnvironment::getAddedActiveObjects(v3s16 pos, s16 radius,
        */
        for(std::map<u16, ServerActiveObject*>::iterator
                        i = m_active_objects.begin();
-                       i != m_active_objects.end(); ++i)
-       {
+                       i != m_active_objects.end(); ++i) {
                u16 id = i->first;
+
                // Get object
                ServerActiveObject *object = i->second;
                if(object == NULL)
                        continue;
+
                // Discard if removed or deactivating
                if(object->m_removed || object->m_pending_deactivation)
                        continue;
 
-               f32 distance_f = object->getBasePosition().getDistanceFrom(pos_f);
+               f32 distance_f = object->getBasePosition().getDistanceFrom(player->getPosition());
                if (object->getType() == ACTIVEOBJECT_TYPE_PLAYER) {
                        // Discard if too far
                        if (distance_f > player_radius_f && player_radius_f != 0)
@@ -1396,7 +1381,7 @@ void ServerEnvironment::getAddedActiveObjects(v3s16 pos, s16 radius,
                if(n != current_objects.end())
                        continue;
                // Add to added_objects
-               added_objects.insert(id);
+               added_objects.push(id);
        }
 }
 
@@ -1404,12 +1389,11 @@ void ServerEnvironment::getAddedActiveObjects(v3s16 pos, s16 radius,
        Finds out what objects have been removed from
        inside a radius around a position
 */
-void ServerEnvironment::getRemovedActiveObjects(v3s16 pos, s16 radius,
+void ServerEnvironment::getRemovedActiveObjects(Player *player, s16 radius,
                s16 player_radius,
                std::set<u16> &current_objects,
-               std::set<u16> &removed_objects)
+               std::queue<u16> &removed_objects)
 {
-       v3f pos_f = intToFloat(pos, BS);
        f32 radius_f = radius * BS;
        f32 player_radius_f = player_radius * BS;
 
@@ -1431,20 +1415,19 @@ void ServerEnvironment::getRemovedActiveObjects(v3s16 pos, s16 radius,
                u16 id = *i;
                ServerActiveObject *object = getActiveObject(id);
 
-               if(object == NULL){
-                       infostream<<"ServerEnvironment::getRemovedActiveObjects():"
-                                       <<" object in current_objects is NULL"<<std::endl;
-                       removed_objects.insert(id);
+               if (object == NULL) {
+                       infostream << "ServerEnvironment::getRemovedActiveObjects():"
+                               << " object in current_objects is NULL" << std::endl;
+                       removed_objects.push(id);
                        continue;
                }
 
-               if(object->m_removed || object->m_pending_deactivation)
-               {
-                       removed_objects.insert(id);
+               if (object->m_removed || object->m_pending_deactivation) {
+                       removed_objects.push(id);
                        continue;
                }
 
-               f32 distance_f = object->getBasePosition().getDistanceFrom(pos_f);
+               f32 distance_f = object->getBasePosition().getDistanceFrom(player->getPosition());
                if (object->getType() == ACTIVEOBJECT_TYPE_PLAYER) {
                        if (distance_f <= player_radius_f || player_radius_f == 0)
                                continue;
@@ -1452,7 +1435,34 @@ void ServerEnvironment::getRemovedActiveObjects(v3s16 pos, s16 radius,
                        continue;
 
                // Object is no longer visible
-               removed_objects.insert(id);
+               removed_objects.push(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;
+               }
+
+               ServerActiveObject *sao = ao_it->second;
+               sao->m_static_exists = static_exists;
+               sao->m_static_block  = static_block;
        }
 }
 
@@ -1498,6 +1508,17 @@ u16 ServerEnvironment::addActiveObjectRaw(ServerActiveObject *object,
                        delete object;
                return 0;
        }
+
+       if (objectpos_over_limit(object->getBasePosition())) {
+               v3f p = object->getBasePosition();
+               errorstream << "ServerEnvironment::addActiveObjectRaw(): "
+                       << "object position (" << p.X << "," << p.Y << "," << p.Z
+                       << ") outside maximum range" << std::endl;
+               if (object->environmentDeletes())
+                       delete object;
+               return 0;
+       }
+
        /*infostream<<"ServerEnvironment::addActiveObjectRaw(): "
                        <<"added (id="<<object->getId()<<")"<<std::endl;*/
 
@@ -1530,7 +1551,7 @@ u16 ServerEnvironment::addActiveObjectRaw(ServerActiveObject *object,
 
                        if(set_changed)
                                block->raiseModified(MOD_STATE_WRITE_NEEDED,
-                                               "addActiveObjectRaw");
+                                       MOD_REASON_ADD_ACTIVE_OBJECT_RAW);
                } else {
                        v3s16 p = floatToInt(objectpos, BS);
                        errorstream<<"ServerEnvironment::addActiveObjectRaw(): "
@@ -1579,7 +1600,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 "
@@ -1604,7 +1625,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 "
@@ -1690,8 +1711,7 @@ 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;
        }
 
@@ -1812,7 +1832,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);
@@ -1825,7 +1845,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;
                }
 
@@ -1853,27 +1873,29 @@ void ServerEnvironment::deactivateFarObjects(bool force_delete)
                        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;
+                                       }
                                }
                        }
 
@@ -1890,8 +1912,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);
                                }
                        }
 
@@ -1926,7 +1947,7 @@ void ServerEnvironment::deactivateFarObjects(bool force_delete)
                                        // reason. Unsuccessful attempts have been made to find
                                        // said reason.
                                        if(id && block->m_static_objects.m_active.find(id) != block->m_static_objects.m_active.end()){
-                                               infostream<<"ServerEnv: WARNING: Performing hack #83274"
+                                               warningstream<<"ServerEnv: Performing hack #83274"
                                                                <<std::endl;
                                                block->m_static_objects.remove(id);
                                        }
@@ -1937,8 +1958,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);
 
                                        obj->m_static_exists = true;
                                        obj->m_static_block = block->getPos();
@@ -1993,7 +2013,6 @@ void ServerEnvironment::deactivateFarObjects(bool force_delete)
        }
 }
 
-
 #ifndef SERVER
 
 #include "clientsimpleobject.h"
@@ -2012,7 +2031,7 @@ ClientEnvironment::ClientEnvironment(ClientMap *map, scene::ISceneManager *smgr,
        m_irr(irr)
 {
        char zero = 0;
-       memset(m_attachements, zero, sizeof(m_attachements));
+       memset(attachement_parent_ids, zero, sizeof(attachement_parent_ids));
 }
 
 ClientEnvironment::~ClientEnvironment()
@@ -2046,7 +2065,7 @@ ClientMap & ClientEnvironment::getClientMap()
 
 void ClientEnvironment::addPlayer(Player *player)
 {
-       DSTACK(__FUNCTION_NAME);
+       DSTACK(FUNCTION_NAME);
        /*
                It is a failure if player is local and there already is a local
                player
@@ -2070,7 +2089,7 @@ LocalPlayer * ClientEnvironment::getLocalPlayer()
 
 void ClientEnvironment::step(float dtime)
 {
-       DSTACK(__FUNCTION_NAME);
+       DSTACK(FUNCTION_NAME);
 
        /* Step time of day */
        stepTimeOfDay(dtime);
@@ -2172,15 +2191,6 @@ void ClientEnvironment::step(float dtime)
 
                                        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);
@@ -2403,6 +2413,15 @@ 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;
@@ -2529,28 +2548,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;
        }
 }
 
@@ -2574,7 +2588,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)
@@ -2582,7 +2596,7 @@ void ClientEnvironment::updateLocalPlayerBreath(u16 breath)
        ClientEnvEvent event;
        event.type = CEE_PLAYER_BREATH;
        event.player_breath.amount = breath;
-       m_client_event_queue.push_back(event);
+       m_client_event_queue.push(event);
 }
 
 /*
@@ -2616,7 +2630,7 @@ 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;
 }