/* Minetest Copyright (C) 2010-2018 nerzhul, Loic BLOT This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include "mapblock.h" #include "profiler.h" #include "activeobjectmgr.h" namespace server { ActiveObjectMgr::~ActiveObjectMgr() { if (!m_active_objects.empty()) { warningstream << "server::ActiveObjectMgr::~ActiveObjectMgr(): not cleared." << std::endl; clear(); } } void ActiveObjectMgr::clearIf(const std::function &cb) { // Make a defensive copy of the ids in case the passed callback changes the // set of active objects. // The callback is called for newly added objects iff they happen to reuse // an old id. std::vector ids = getAllIds(); for (u16 id : ids) { auto it = m_active_objects.find(id); if (it == m_active_objects.end()) continue; // obj was already removed if (cb(it->second.get(), id)) { // erase by id, `it` can be invalid now removeObject(id); } } } void ActiveObjectMgr::step( float dtime, const std::function &f) { g_profiler->avg("ActiveObjectMgr: SAO count [#]", m_active_objects.size()); // See above. std::vector ids = getAllIds(); for (u16 id : ids) { auto it = m_active_objects.find(id); if (it == m_active_objects.end()) continue; // obj was removed f(it->second.get()); } } // clang-format off bool ActiveObjectMgr::registerObject(std::unique_ptr obj) { assert(obj); // Pre-condition if (obj->getId() == 0) { u16 new_id = getFreeId(); if (new_id == 0) { errorstream << "Server::ActiveObjectMgr::addActiveObjectRaw(): " << "no free id available" << std::endl; return false; } obj->setId(new_id); } else { verbosestream << "Server::ActiveObjectMgr::addActiveObjectRaw(): " << "supplied with id " << obj->getId() << std::endl; } if (!isFreeId(obj->getId())) { errorstream << "Server::ActiveObjectMgr::addActiveObjectRaw(): " << "id is not free (" << obj->getId() << ")" << std::endl; return false; } if (objectpos_over_limit(obj->getBasePosition())) { v3f p = obj->getBasePosition(); warningstream << "Server::ActiveObjectMgr::addActiveObjectRaw(): " << "object position (" << p.X << "," << p.Y << "," << p.Z << ") outside maximum range" << std::endl; return false; } auto obj_p = obj.get(); m_active_objects[obj->getId()] = std::move(obj); verbosestream << "Server::ActiveObjectMgr::addActiveObjectRaw(): " << "Added id=" << obj_p->getId() << "; there are now " << m_active_objects.size() << " active objects." << std::endl; return true; } void ActiveObjectMgr::removeObject(u16 id) { verbosestream << "Server::ActiveObjectMgr::removeObject(): " << "id=" << id << std::endl; auto it = m_active_objects.find(id); if (it == m_active_objects.end()) { infostream << "Server::ActiveObjectMgr::removeObject(): " << "id=" << id << " not found" << std::endl; return; } // Delete the obj before erasing, as the destructor may indirectly access // m_active_objects. it->second.reset(); m_active_objects.erase(id); // `it` can be invalid now } // clang-format on void ActiveObjectMgr::getObjectsInsideRadius(const v3f &pos, float radius, std::vector &result, std::function include_obj_cb) { float r2 = radius * radius; for (auto &activeObject : m_active_objects) { ServerActiveObject *obj = activeObject.second.get(); const v3f &objectpos = obj->getBasePosition(); if (objectpos.getDistanceFromSQ(pos) > r2) continue; if (!include_obj_cb || include_obj_cb(obj)) result.push_back(obj); } } void ActiveObjectMgr::getObjectsInArea(const aabb3f &box, std::vector &result, std::function include_obj_cb) { for (auto &activeObject : m_active_objects) { ServerActiveObject *obj = activeObject.second.get(); const v3f &objectpos = obj->getBasePosition(); if (!box.isPointInside(objectpos)) continue; if (!include_obj_cb || include_obj_cb(obj)) result.push_back(obj); } } void ActiveObjectMgr::getAddedActiveObjectsAroundPos(const v3f &player_pos, f32 radius, f32 player_radius, std::set ¤t_objects, std::queue &added_objects) { /* 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.get(); if (!object) continue; if (object->isGone()) continue; f32 distance_f = object->getBasePosition().getDistanceFrom(player_pos); if (object->getType() == ACTIVEOBJECT_TYPE_PLAYER) { // Discard if too far if (distance_f > player_radius && player_radius != 0) continue; } else if (distance_f > radius) continue; // Discard if already on current_objects auto n = current_objects.find(id); if (n != current_objects.end()) continue; // Add to added_objects added_objects.push(id); } } } // namespace server