From eda35100b6c6f7d9b01c257557147545b563dc74 Mon Sep 17 00:00:00 2001 From: Loïc Blot Date: Thu, 13 Dec 2018 20:18:54 +0100 Subject: Add an activeobject manager to hold active objects (#7939) * Add an activeobject manager to hold active objects * Add unittests --- src/serverenvironment.cpp | 272 ++++++++++------------------------------------ 1 file changed, 58 insertions(+), 214 deletions(-) (limited to 'src/serverenvironment.cpp') diff --git a/src/serverenvironment.cpp b/src/serverenvironment.cpp index efb93b9a2..4837449e6 100644 --- a/src/serverenvironment.cpp +++ b/src/serverenvironment.cpp @@ -1047,29 +1047,13 @@ bool ServerEnvironment::swapNode(v3s16 p, const MapNode &n) return true; } -void ServerEnvironment::getObjectsInsideRadius(std::vector &objects, v3f pos, - float radius) -{ - for (auto &activeObject : m_active_objects) { - ServerActiveObject* obj = activeObject.second; - u16 id = activeObject.first; - v3f objectpos = obj->getBasePosition(); - if (objectpos.getDistanceFrom(pos) > radius) - continue; - objects.push_back(id); - } -} - void ServerEnvironment::clearObjects(ClearObjectsMode mode) { infostream << "ServerEnvironment::clearObjects(): " << "Removing all active objects" << std::endl; - std::vector objects_to_remove; - for (auto &it : m_active_objects) { - u16 id = it.first; - ServerActiveObject* obj = it.second; + auto cb_removal = [this] (ServerActiveObject *obj, u16 id) { if (obj->getType() == ACTIVEOBJECT_TYPE_PLAYER) - continue; + return false; // Delete static object if block is loaded deleteStaticFromBlock(obj, id, MOD_REASON_CLEAR_ALL_OBJECTS, true); @@ -1077,7 +1061,7 @@ void ServerEnvironment::clearObjects(ClearObjectsMode mode) // If known by some client, don't delete immediately if (obj->m_known_by_count > 0) { obj->m_pending_removal = true; - continue; + return false; } // Tell the object about removal @@ -1088,14 +1072,11 @@ void ServerEnvironment::clearObjects(ClearObjectsMode mode) // Delete active object 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 (u16 i : objects_to_remove) { - m_active_objects.erase(i); - } + return true; + }; + + m_ao_manager.clear(cb_removal); // Get list of loaded blocks std::vector loaded_blocks; @@ -1386,32 +1367,28 @@ void ServerEnvironment::step(float dtime) */ { ScopeProfiler sp(g_profiler, "SEnv: step act. objs avg", SPT_AVG); - //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; - if(m_send_recommended_timer > getSendRecommendedInterval()) - { + if (m_send_recommended_timer > getSendRecommendedInterval()) { m_send_recommended_timer -= getSendRecommendedInterval(); send_recommended = true; } - for (auto &ao_it : m_active_objects) { - ServerActiveObject* obj = ao_it.second; + auto cb_state = [this, dtime, send_recommended] (ServerActiveObject *obj) { if (obj->isGone()) - continue; + return; // Step object obj->step(dtime, send_recommended); // Read messages from object while (!obj->m_messages_out.empty()) { - m_active_object_messages.push(obj->m_messages_out.front()); + this->m_active_object_messages.push(obj->m_messages_out.front()); obj->m_messages_out.pop(); } - } + }; + m_ao_manager.step(dtime, cb_state); } /* @@ -1484,44 +1461,6 @@ void ServerEnvironment::deleteParticleSpawner(u32 id, bool remove_from_object) } } -ServerActiveObject* ServerEnvironment::getActiveObject(u16 id) -{ - ServerActiveObjectMap::const_iterator n = m_active_objects.find(id); - return (n != m_active_objects.end() ? n->second : NULL); -} - -/** - * Verify if id is a free active object id - * @param id - * @return true if slot is free - */ -bool ServerEnvironment::isFreeServerActiveObjectId(u16 id) const -{ - if (id == 0) - return false; - - return m_active_objects.find(id) == m_active_objects.end(); -} - -/** - * Retrieve the first free ActiveObject ID - * @return free activeobject ID or 0 if none was found - */ -u16 ServerEnvironment::getFreeServerActiveObjectId() -{ - // try to reuse id's as late as possible - static u16 last_used_id = 0; - u16 startid = last_used_id; - for (;;) { - last_used_id++; - if (isFreeServerActiveObjectId(last_used_id)) - return last_used_id; - - if (last_used_id == startid) - return 0; - } -} - u16 ServerEnvironment::addActiveObject(ServerActiveObject *object) { assert(object); // Pre-condition @@ -1542,43 +1481,11 @@ void ServerEnvironment::getAddedActiveObjects(PlayerSAO *playersao, s16 radius, 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 removed/deactivated objects, - - discard objects that are too far away, - - discard objects that are found in current_objects. - - add remaining objects to added_objects - */ - for (auto &ao_it : m_active_objects) { - u16 id = ao_it.first; - - // Get object - ServerActiveObject *object = ao_it.second; - if (object == NULL) - continue; + if (player_radius_f < 0.0f) + player_radius_f = 0.0f; - if (object->isGone()) - continue; - - f32 distance_f = object->getBasePosition(). - getDistanceFrom(playersao->getBasePosition()); - if (object->getType() == ACTIVEOBJECT_TYPE_PLAYER) { - // Discard if too far - 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::iterator n; - n = current_objects.find(id); - if(n != current_objects.end()) - continue; - // Add to added_objects - added_objects.push(id); - } + m_ao_manager.getAddedActiveObjectsAroundPos(playersao->getBasePosition(), radius_f, + player_radius_f, current_objects, added_objects); } /* @@ -1639,8 +1546,8 @@ void ServerEnvironment::setStaticForActiveObjectsInBlock( for (auto &so_it : block->m_static_objects.m_active) { // Get the ServerActiveObject counterpart to this StaticObject - ServerActiveObjectMap::const_iterator ao_it = m_active_objects.find(so_it.first); - if (ao_it == m_active_objects.end()) { + ServerActiveObject *sao = m_ao_manager.getActiveObject(so_it.first); + if (!sao) { // 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 " @@ -1648,7 +1555,6 @@ void ServerEnvironment::setStaticForActiveObjectsInBlock( continue; } - ServerActiveObject *sao = ao_it->second; sao->m_static_exists = static_exists; sao->m_static_block = static_block; } @@ -1703,60 +1609,17 @@ void ServerEnvironment::getSelectedActiveObjects( u16 ServerEnvironment::addActiveObjectRaw(ServerActiveObject *object, bool set_changed, u32 dtime_s) { - assert(object); // Pre-condition - if(object->getId() == 0){ - u16 new_id = getFreeServerActiveObjectId(); - if(new_id == 0) - { - errorstream<<"ServerEnvironment::addActiveObjectRaw(): " - <<"no free ids available"<environmentDeletes()) - delete object; - return 0; - } - object->setId(new_id); - } - else{ - verbosestream<<"ServerEnvironment::addActiveObjectRaw(): " - <<"supplied with id "<getId()<getId())) { - errorstream<<"ServerEnvironment::addActiveObjectRaw(): " - <<"id is not free ("<getId()<<")"<environmentDeletes()) - delete object; - return 0; - } - - if (objectpos_over_limit(object->getBasePosition())) { - v3f p = object->getBasePosition(); - warningstream << "ServerEnvironment::addActiveObjectRaw(): " - << "object position (" << p.X << "," << p.Y << "," << p.Z - << ") outside maximum range" << std::endl; - if (object->environmentDeletes()) - delete object; + if (!m_ao_manager.registerObject(object)) { return 0; } - /*infostream<<"ServerEnvironment::addActiveObjectRaw(): " - <<"added (id="<getId()<<")"<getId()] = object; - - verbosestream<<"ServerEnvironment::addActiveObjectRaw(): " - <<"Added id="<getId()<<"; there are now " - <addObjectReference(object); // Post-initialize object object->addedToEnvironment(dtime_s); // Add static data to block - if(object->isStaticAllowed()) - { + if (object->isStaticAllowed()) { // Add static object to active static list of the block v3f objectpos = object->getBasePosition(); StaticObject s_obj(object, objectpos); @@ -1787,24 +1650,19 @@ u16 ServerEnvironment::addActiveObjectRaw(ServerActiveObject *object, */ void ServerEnvironment::removeRemovedObjects() { - std::vector objects_to_remove; - for (auto &ao_it : m_active_objects) { - u16 id = ao_it.first; - ServerActiveObject* obj = ao_it.second; - + auto clear_cb = [this] (ServerActiveObject *obj, u16 id) { // This shouldn't happen but check it if (!obj) { errorstream << "ServerEnvironment::removeRemovedObjects(): " << "NULL object found. id=" << id << std::endl; - objects_to_remove.push_back(id); - continue; + return true; } /* We will handle objects marked for removal or deactivation */ if (!obj->isGone()) - continue; + return false; /* Delete static data from block if removed @@ -1815,7 +1673,7 @@ void ServerEnvironment::removeRemovedObjects() // If still known by clients, don't actually remove. On some future // invocation this will be 0, which is when removal will continue. if(obj->m_known_by_count > 0) - continue; + return false; /* Move static data from active to stored if deactivated @@ -1823,8 +1681,7 @@ void ServerEnvironment::removeRemovedObjects() if (!obj->m_pending_removal && obj->m_static_exists) { MapBlock *block = m_map->emergeBlock(obj->m_static_block, false); if (block) { - std::map::iterator i = - block->m_static_objects.m_active.find(id); + const auto i = block->m_static_objects.m_active.find(id); if (i != block->m_static_objects.m_active.end()) { block->m_static_objects.m_stored.push_back(i->second); block->m_static_objects.m_active.erase(id); @@ -1848,15 +1705,13 @@ void ServerEnvironment::removeRemovedObjects() m_script->removeObjectReference(obj); // Delete - if(obj->environmentDeletes()) + if (obj->environmentDeletes()) delete obj; - objects_to_remove.push_back(id); - } - // Remove references from m_active_objects - for (u16 i : objects_to_remove) { - m_active_objects.erase(i); - } + return true; + }; + + m_ao_manager.clear(clear_cb); } static void print_hexdump(std::ostream &o, const std::string &data) @@ -1976,24 +1831,19 @@ void ServerEnvironment::activateObjects(MapBlock *block, u32 dtime_s) */ void ServerEnvironment::deactivateFarObjects(bool _force_delete) { - std::vector objects_to_remove; - for (auto &ao_it : m_active_objects) { + auto cb_deactivate = [this, _force_delete] (ServerActiveObject *obj, u16 id) { // force_delete might be overriden per object bool force_delete = _force_delete; - ServerActiveObject* obj = ao_it.second; - assert(obj); - // Do not deactivate if static data creation not allowed - if(!force_delete && !obj->isStaticAllowed()) - continue; + if (!force_delete && !obj->isStaticAllowed()) + return false; // removeRemovedObjects() is responsible for these - if(!force_delete && obj->isGone()) - continue; + if (!force_delete && obj->isGone()) + return false; - u16 id = ao_it.first; - v3f objectpos = obj->getBasePosition(); + const v3f &objectpos = obj->getBasePosition(); // The block in which the object resides in v3s16 blockpos_o = getNodeBlockPos(floatToInt(objectpos, BS)); @@ -2001,11 +1851,9 @@ void ServerEnvironment::deactivateFarObjects(bool _force_delete) // If object's static data is stored in a deactivated block and object // is actually located in an active block, re-save to the block in // which the object is actually located in. - if(!force_delete && - obj->m_static_exists && - !m_active_blocks.contains(obj->m_static_block) && - m_active_blocks.contains(blockpos_o)) - { + if (!force_delete && obj->m_static_exists && + !m_active_blocks.contains(obj->m_static_block) && + m_active_blocks.contains(blockpos_o)) { // Delete from block where object was located deleteStaticFromBlock(obj, id, MOD_REASON_STATIC_DATA_REMOVED, false); @@ -2013,16 +1861,16 @@ void ServerEnvironment::deactivateFarObjects(bool _force_delete) // Save to block where object is located saveStaticToBlock(blockpos_o, id, obj, s_obj, MOD_REASON_STATIC_DATA_ADDED); - continue; + return false; } // If block is still active, don't remove - if(!force_delete && m_active_blocks.contains(blockpos_o)) - continue; + if (!force_delete && m_active_blocks.contains(blockpos_o)) + return false; verbosestream << "ServerEnvironment::deactivateFarObjects(): " - << "deactivating object id=" << id << " on inactive block " - << PP(blockpos_o) << std::endl; + << "deactivating object id=" << id << " on inactive block " + << PP(blockpos_o) << std::endl; // If known by some client, don't immediately delete. bool pending_delete = (obj->m_known_by_count > 0 && !force_delete); @@ -2045,8 +1893,7 @@ void ServerEnvironment::deactivateFarObjects(bool _force_delete) MapBlock *block = m_map->emergeBlock(obj->m_static_block, false); if (block) { - std::map::iterator n = - block->m_static_objects.m_active.find(id); + const auto n = block->m_static_objects.m_active.find(id); if (n != block->m_static_objects.m_active.end()) { StaticObject static_old = n->second; @@ -2085,18 +1932,18 @@ void ServerEnvironment::deactivateFarObjects(bool _force_delete) If known by some client, set pending deactivation. Otherwise delete it immediately. */ - if(pending_delete && !force_delete) - { + if (pending_delete && !force_delete) { verbosestream << "ServerEnvironment::deactivateFarObjects(): " - << "object id=" << id << " is known by clients" - << "; not deleting yet" << std::endl; + << "object id=" << id << " is known by clients" + << "; not deleting yet" << std::endl; obj->m_pending_deactivation = true; - continue; + return false; } + verbosestream << "ServerEnvironment::deactivateFarObjects(): " - << "object id=" << id << " is not known by clients" - << "; deleting" << std::endl; + << "object id=" << id << " is not known by clients" + << "; deleting" << std::endl; // Tell the object about removal obj->removingFromEnvironment(); @@ -2104,16 +1951,13 @@ void ServerEnvironment::deactivateFarObjects(bool _force_delete) 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 (u16 i : objects_to_remove) { - m_active_objects.erase(i); - } + return true; + }; + + m_ao_manager.clear(cb_deactivate); } void ServerEnvironment::deleteStaticFromBlock( -- cgit v1.2.3