Noise: Prevent unittest crash caused by division by zero
[oweals/minetest.git] / src / serverenvironment.cpp
index 4d2c87a4dfceb8297433580f5bb4941dc31b6dfb..19dff956eb9dd748c413159d6f8c73de4447cd26 100644 (file)
@@ -30,7 +30,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "remoteplayer.h"
 #include "scripting_server.h"
 #include "server.h"
-#include "voxelalgorithms.h"
 #include "util/serialize.h"
 #include "util/basic_macros.h"
 #include "util/pointedthing.h"
@@ -54,8 +53,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 */
 
 ABMWithState::ABMWithState(ActiveBlockModifier *abm_):
-       abm(abm_),
-       timer(0)
+       abm(abm_)
 {
        // Initialize timer to random value to spread processing
        float itv = abm->getTriggerInterval();
@@ -71,9 +69,8 @@ ABMWithState::ABMWithState(ActiveBlockModifier *abm_):
 
 void LBMContentMapping::deleteContents()
 {
-       for (std::vector<LoadingBlockModifierDef *>::iterator it = lbm_list.begin();
-               it != lbm_list.end(); ++it) {
-               delete *it;
+       for (auto &it : lbm_list) {
+               delete it;
        }
 }
 
@@ -85,24 +82,21 @@ void LBMContentMapping::addLBM(LoadingBlockModifierDef *lbm_def, IGameDef *gamed
 
        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) {
+       for (const std::string &nodeTrigger: lbm_def->trigger_contents) {
                std::set<content_t> c_ids;
-               bool found = nodedef->getIds(*it, c_ids);
+               bool found = nodedef->getIds(nodeTrigger, c_ids);
                if (!found) {
-                       content_t c_id = gamedef->allocateUnknownNodeId(*it);
+                       content_t c_id = gamedef->allocateUnknownNodeId(nodeTrigger);
                        if (c_id == CONTENT_IGNORE) {
                                // Seems it can't be allocated.
-                               warningstream << "Could not internalize node name \"" << *it
+                               warningstream << "Could not internalize node name \"" << nodeTrigger
                                        << "\" 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;
+               for (content_t c_id : c_ids) {
                        map[c_id].push_back(lbm_def);
                }
        }
@@ -111,7 +105,7 @@ void LBMContentMapping::addLBM(LoadingBlockModifierDef *lbm_def, IGameDef *gamed
 const std::vector<LoadingBlockModifierDef *> *
 LBMContentMapping::lookup(content_t c) const
 {
-       container_map::const_iterator it = map.find(c);
+       lbm_map::const_iterator it = map.find(c);
        if (it == map.end())
                return NULL;
        // This first dereferences the iterator, returning
@@ -122,13 +116,12 @@ LBMContentMapping::lookup(content_t c) const
 
 LBMManager::~LBMManager()
 {
-       for (std::map<std::string, LoadingBlockModifierDef *>::iterator it =
-               m_lbm_defs.begin(); it != m_lbm_defs.end(); ++it) {
-               delete it->second;
+       for (auto &m_lbm_def : m_lbm_defs) {
+               delete m_lbm_def.second;
        }
-       for (lbm_lookup_map::iterator it = m_lbm_lookup.begin();
-               it != m_lbm_lookup.end(); ++it) {
-               (it->second).deleteContents();
+
+       for (auto &it : m_lbm_lookup) {
+               (it.second).deleteContents();
        }
 }
 
@@ -141,7 +134,7 @@ void LBMManager::addLBMDef(LoadingBlockModifierDef *lbm_def)
        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.");
+                               "Only characters [a-z0-9_:] are allowed.");
        }
 
        m_lbm_defs[lbm_def->name] = lbm_def;
@@ -214,12 +207,11 @@ void LBMManager::loadIntroductionTimes(const std::string &times,
        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);
+       for (auto &m_lbm_def : m_lbm_defs) {
+               if (m_lbm_def.second->run_at_every_load) {
+                       lbms_running_always.addLBM(m_lbm_def.second, gamedef);
                } else {
-                       lbms_we_introduce_now.addLBM(it->second, gamedef);
+                       lbms_we_introduce_now.addLBM(m_lbm_def.second, gamedef);
                }
        }
 
@@ -235,18 +227,16 @@ std::string LBMManager::createIntroductionTimesString()
                "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) {
+       for (const auto &it : m_lbm_lookup) {
+               u32 time = it.first;
+               const std::vector<LoadingBlockModifierDef *> &lbm_list = it.second.lbm_list;
+               for (const auto &lbm_def : lbm_list) {
                        // 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)
+                       if (lbm_def->run_at_every_load)
                                continue;
-                       oss << (*iit)->name << "~" << time << ";";
+                       oss << lbm_def->name << "~" << time << ";";
                }
        }
        return oss.str();
@@ -274,9 +264,8 @@ void LBMManager::applyLBMs(ServerEnvironment *env, MapBlock *block, u32 stamp)
                                                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);
+                                       for (auto lbmdef : *lbm_list) {
+                                               lbmdef->trigger(env, pos + pos_of_block, n);
                                        }
                                }
                        }
@@ -365,15 +354,7 @@ ServerEnvironment::ServerEnvironment(ServerMap *map,
        m_map(map),
        m_script(scriptIface),
        m_server(server),
-       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),
-       m_player_database(NULL)
+       m_path_world(path_world)
 {
        // Determine which database backend to use
        std::string conf_path = path_world + DIR_DELIM + "world.mt";
@@ -579,7 +560,8 @@ PlayerSAO *ServerEnvironment::loadPlayer(RemotePlayer *player, bool *new_player,
                // If the player exists, ensure that they respawn inside legal bounds
                // This fixes an assert crash when the player can't be added
                // to the environment
-               if (objectpos_over_limit(playersao->getBasePosition())) {
+               ServerMap &map = getServerMap();
+               if (map.getMapgenParams()->saoPosOverLimit(playersao->getBasePosition())) {
                        actionstream << "Respawn position for player \""
                                << player->getName() << "\" outside limits, resetting" << std::endl;
                        playersao->setBasePosition(m_server->findSpawnPos());
@@ -721,7 +703,7 @@ public:
                                chance = 1;
                        ActiveABM aabm;
                        aabm.abm = abm;
-                       if(abm->getSimpleCatchUp()) {
+                       if (abm->getSimpleCatchUp()) {
                                float intervals = actual_interval / trigger_interval;
                                if(intervals == 0)
                                        continue;
@@ -731,25 +713,23 @@ public:
                        } 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)
-                       {
-                               ndef->getIds(*i, aabm.required_neighbors);
+                       const std::set<std::string> &required_neighbors_s =
+                               abm->getRequiredNeighbors();
+                       for (std::set<std::string>::iterator rn = required_neighbors_s.begin();
+                                       rn != required_neighbors_s.end(); ++rn) {
+                               ndef->getIds(*rn, 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)
-                       {
+                       const std::set<std::string> &contents_s = abm->getTriggerContents();
+                       for (std::set<std::string>::iterator cs = contents_s.begin();
+                                       cs != contents_s.end(); ++cs) {
                                std::set<content_t> ids;
-                               ndef->getIds(*i, ids);
-                               for(std::set<content_t>::const_iterator k = ids.begin();
-                                       k != ids.end(); ++k)
-                               {
+                               ndef->getIds(*cs, ids);
+                               for (std::set<content_t>::const_iterator k = ids.begin();
+                                               k != ids.end(); ++k) {
                                        content_t c = *k;
                                        if (c >= m_aabms.size())
                                                m_aabms.resize(c + 256, NULL);
@@ -1001,9 +981,10 @@ bool ServerEnvironment::swapNode(v3s16 p, const MapNode &n)
        return true;
 }
 
-void ServerEnvironment::getObjectsInsideRadius(std::vector<u16> &objects, v3f pos, float radius)
+void ServerEnvironment::getObjectsInsideRadius(std::vector<u16> &objects, v3f pos,
+       float radius)
 {
-       for (ActiveObjectMap::iterator i = m_active_objects.begin();
+       for (ServerActiveObjectMap::iterator i = m_active_objects.begin();
                i != m_active_objects.end(); ++i) {
                ServerActiveObject* obj = i->second;
                u16 id = i->first;
@@ -1019,7 +1000,7 @@ void ServerEnvironment::clearObjects(ClearObjectsMode mode)
        infostream << "ServerEnvironment::clearObjects(): "
                << "Removing all active objects" << std::endl;
        std::vector<u16> objects_to_remove;
-       for (ActiveObjectMap::iterator i = m_active_objects.begin();
+       for (ServerActiveObjectMap::iterator i = m_active_objects.begin();
                i != m_active_objects.end(); ++i) {
                ServerActiveObject* obj = i->second;
                if (obj->getType() == ACTIVEOBJECT_TYPE_PLAYER)
@@ -1169,7 +1150,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.
-       static const float server_step = g_settings->getFloat("dedicated_server_step");
+       static thread_local const float server_step =
+                       g_settings->getFloat("dedicated_server_step");
        m_recommended_send_interval = server_step;
 
        /*
@@ -1230,7 +1212,8 @@ void ServerEnvironment::step(float dtime)
                /*
                        Update list of active blocks, collecting changes
                */
-               static const s16 active_block_range = g_settings->getS16("active_block_range");
+               static thread_local 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,
@@ -1397,7 +1380,7 @@ void ServerEnvironment::step(float dtime)
                        send_recommended = true;
                }
 
-               for(ActiveObjectMap::iterator i = m_active_objects.begin();
+               for (ServerActiveObjectMap::iterator i = m_active_objects.begin();
                        i != m_active_objects.end(); ++i) {
                        ServerActiveObject* obj = i->second;
                        // Don't step if is to be removed or stored statically
@@ -1431,7 +1414,7 @@ void ServerEnvironment::step(float dtime)
                Manage particle spawner expiration
        */
        if (m_particle_management_interval.step(dtime, 1.0)) {
-               for (UNORDERED_MAP<u32, float>::iterator i = m_particle_spawners.begin();
+               for (std::unordered_map<u32, float>::iterator i = m_particle_spawners.begin();
                        i != m_particle_spawners.end(); ) {
                        //non expiring spawners
                        if (i->second == PARTICLE_SPAWNER_NO_EXPIRY) {
@@ -1456,7 +1439,7 @@ u32 ServerEnvironment::addParticleSpawner(float exptime)
        u32 id = 0;
        for (;;) { // look for unused particlespawner id
                id++;
-               UNORDERED_MAP<u32, float>::iterator f = m_particle_spawners.find(id);
+               std::unordered_map<u32, float>::iterator f = m_particle_spawners.find(id);
                if (f == m_particle_spawners.end()) {
                        m_particle_spawners[id] = time;
                        break;
@@ -1478,7 +1461,7 @@ u32 ServerEnvironment::addParticleSpawner(float exptime, u16 attached_id)
 void ServerEnvironment::deleteParticleSpawner(u32 id, bool remove_from_object)
 {
        m_particle_spawners.erase(id);
-       UNORDERED_MAP<u32, u16>::iterator it = m_particle_spawner_attachments.find(id);
+       std::unordered_map<u32, u16>::iterator it = m_particle_spawner_attachments.find(id);
        if (it != m_particle_spawner_attachments.end()) {
                u16 obj_id = (*it).second;
                ServerActiveObject *sao = getActiveObject(obj_id);
@@ -1491,11 +1474,11 @@ void ServerEnvironment::deleteParticleSpawner(u32 id, bool remove_from_object)
 
 ServerActiveObject* ServerEnvironment::getActiveObject(u16 id)
 {
-       ActiveObjectMap::iterator n = m_active_objects.find(id);
+       ServerActiveObjectMap::const_iterator n = m_active_objects.find(id);
        return (n != m_active_objects.end() ? n->second : NULL);
 }
 
-bool isFreeServerActiveObjectId(u16 id, ActiveObjectMap &objects)
+bool isFreeServerActiveObjectId(u16 id, ServerActiveObjectMap &objects)
 {
        if (id == 0)
                return false;
@@ -1503,7 +1486,7 @@ bool isFreeServerActiveObjectId(u16 id, ActiveObjectMap &objects)
        return objects.find(id) == objects.end();
 }
 
-u16 getFreeServerActiveObjectId(ActiveObjectMap &objects)
+u16 getFreeServerActiveObjectId(ServerActiveObjectMap &objects)
 {
        //try to reuse id's as late as possible
        static u16 last_used_id = 0;
@@ -1548,7 +1531,7 @@ void ServerEnvironment::getAddedActiveObjects(PlayerSAO *playersao, s16 radius,
                - discard objects that are found in current_objects.
                - add remaining objects to added_objects
        */
-       for (ActiveObjectMap::iterator i = m_active_objects.begin();
+       for (ServerActiveObjectMap::iterator i = m_active_objects.begin();
                i != m_active_objects.end(); ++i) {
                u16 id = i->first;
 
@@ -1644,7 +1627,7 @@ void ServerEnvironment::setStaticForActiveObjectsInBlock(
                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
-               ActiveObjectMap::iterator ao_it = m_active_objects.find(so_it->first);
+               ServerActiveObjectMap::const_iterator 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(): "
@@ -1669,6 +1652,38 @@ ActiveObjectMessage ServerEnvironment::getActiveObjectMessage()
        return message;
 }
 
+void ServerEnvironment::getSelectedActiveObjects(
+       const core::line3d<f32> &shootline_on_map,
+       std::vector<PointedThing> &objects)
+{
+       std::vector<u16> objectIds;
+       getObjectsInsideRadius(objectIds, shootline_on_map.start,
+               shootline_on_map.getLength() + 10.0f);
+       const v3f line_vector = shootline_on_map.getVector();
+
+       for (u32 i = 0; i < objectIds.size(); i++) {
+               ServerActiveObject* obj = getActiveObject(objectIds[i]);
+
+               aabb3f selection_box;
+               if (!obj->getSelectionBox(&selection_box))
+                       continue;
+
+               v3f pos = obj->getBasePosition();
+
+               aabb3f offsetted_box(selection_box.MinEdge + pos,
+                       selection_box.MaxEdge + pos);
+
+               v3f current_intersection;
+               v3s16 current_normal;
+               if (boxLineCollision(offsetted_box, shootline_on_map.start, line_vector,
+                               &current_intersection, &current_normal)) {
+                       objects.push_back(PointedThing(
+                               (s16) objectIds[i], current_intersection, current_normal,
+                               (current_intersection - shootline_on_map.start).getLengthSQ()));
+               }
+       }
+}
+
 /*
        ************ Private methods *************
 */
@@ -1763,7 +1778,7 @@ u16 ServerEnvironment::addActiveObjectRaw(ServerActiveObject *object,
 void ServerEnvironment::removeRemovedObjects()
 {
        std::vector<u16> objects_to_remove;
-       for(ActiveObjectMap::iterator i = m_active_objects.begin();
+       for(ServerActiveObjectMap::iterator i = m_active_objects.begin();
                i != m_active_objects.end(); ++i) {
                u16 id = i->first;
                ServerActiveObject* obj = i->second;
@@ -1981,7 +1996,7 @@ void ServerEnvironment::activateObjects(MapBlock *block, u32 dtime_s)
 void ServerEnvironment::deactivateFarObjects(bool _force_delete)
 {
        std::vector<u16> objects_to_remove;
-       for(ActiveObjectMap::iterator i = m_active_objects.begin();
+       for (ServerActiveObjectMap::iterator i = m_active_objects.begin();
                i != m_active_objects.end(); ++i) {
                // force_delete might be overriden per object
                bool force_delete = _force_delete;