Optimize get_objects_inside_radius calls (#9671)

* Optimize getObjectsInsideRadius calls

our previous implementation calls the ActiveObjectMgr to return ids and then lookup those ids in the same map and test each object
Instead now we call the global map to return the pointers directly and we ask filtering when building the list using lamba.

This drop double looping over ranges of active objects (and then filtered one) and drop x lookups on the map regarding the first call results
This commit is contained in:
Loïc Blot 2020-04-16 08:25:48 +02:00 committed by GitHub
parent 62ae7adab2
commit e8ac5a31cf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 55 additions and 39 deletions

@ -360,17 +360,19 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
// Calculate distance by speed, add own extent and 1.5m of tolerance // Calculate distance by speed, add own extent and 1.5m of tolerance
f32 distance = speed_f->getLength() * dtime + f32 distance = speed_f->getLength() * dtime +
box_0.getExtent().getLength() + 1.5f * BS; box_0.getExtent().getLength() + 1.5f * BS;
std::vector<u16> s_objects;
s_env->getObjectsInsideRadius(s_objects, *pos_f, distance);
for (u16 obj_id : s_objects) { // search for objects which are not us, or we are not its parent
ServerActiveObject *current = s_env->getActiveObject(obj_id); // we directly use the callback to populate the result to prevent
// a useless result loop here
if (!self || (self != current && auto include_obj_cb = [self, &objects] (ServerActiveObject *obj) {
self != current->getParent())) { if (!self || (self != obj && self != obj->getParent())) {
objects.push_back((ActiveObject*)current); objects.push_back((ActiveObject *)obj);
} }
} return false;
};
std::vector<ServerActiveObject *> s_objects;
s_env->getObjectsInsideRadius(s_objects, *pos_f, distance, include_obj_cb);
} }
} }

@ -681,22 +681,22 @@ int ModApiEnvMod::l_get_player_by_name(lua_State *L)
int ModApiEnvMod::l_get_objects_inside_radius(lua_State *L) int ModApiEnvMod::l_get_objects_inside_radius(lua_State *L)
{ {
GET_ENV_PTR; GET_ENV_PTR;
ScriptApiBase *script = getScriptApiBase(L);
// Do it // Do it
v3f pos = checkFloatPos(L, 1); v3f pos = checkFloatPos(L, 1);
float radius = readParam<float>(L, 2) * BS; float radius = readParam<float>(L, 2) * BS;
std::vector<u16> ids; std::vector<ServerActiveObject *> objs;
env->getObjectsInsideRadius(ids, pos, radius);
ScriptApiBase *script = getScriptApiBase(L); auto include_obj_cb = [](ServerActiveObject *obj){ return !obj->isGone(); };
lua_createtable(L, ids.size(), 0); env->getObjectsInsideRadius(objs, pos, radius, include_obj_cb);
std::vector<u16>::const_iterator iter = ids.begin();
for(u32 i = 0; iter != ids.end(); ++iter) { int i = 0;
ServerActiveObject *obj = env->getActiveObject(*iter); lua_createtable(L, objs.size(), 0);
if (!obj->isGone()) { for (const auto obj : objs) {
// Insert object reference into table // Insert object reference into table
script->objectrefGetOrCreate(L, obj); script->objectrefGetOrCreate(L, obj);
lua_rawseti(L, -2, ++i); lua_rawseti(L, -2, ++i);
}
} }
return 1; return 1;
} }

@ -111,17 +111,19 @@ void ActiveObjectMgr::removeObject(u16 id)
} }
// clang-format on // clang-format on
void ActiveObjectMgr::getObjectsInsideRadius( void ActiveObjectMgr::getObjectsInsideRadius(const v3f &pos, float radius,
const v3f &pos, float radius, std::vector<u16> &result) std::vector<ServerActiveObject *> &result,
std::function<bool(ServerActiveObject *obj)> include_obj_cb)
{ {
float r2 = radius * radius; float r2 = radius * radius;
for (auto &activeObject : m_active_objects) { for (auto &activeObject : m_active_objects) {
ServerActiveObject *obj = activeObject.second; ServerActiveObject *obj = activeObject.second;
u16 id = activeObject.first;
const v3f &objectpos = obj->getBasePosition(); const v3f &objectpos = obj->getBasePosition();
if (objectpos.getDistanceFromSQ(pos) > r2) if (objectpos.getDistanceFromSQ(pos) > r2)
continue; continue;
result.push_back(id);
if (!include_obj_cb || include_obj_cb(obj))
result.push_back(obj);
} }
} }

@ -35,8 +35,9 @@ public:
bool registerObject(ServerActiveObject *obj) override; bool registerObject(ServerActiveObject *obj) override;
void removeObject(u16 id) override; void removeObject(u16 id) override;
void getObjectsInsideRadius( void getObjectsInsideRadius(const v3f &pos, float radius,
const v3f &pos, float radius, std::vector<u16> &result); std::vector<ServerActiveObject *> &result,
std::function<bool(ServerActiveObject *obj)> include_obj_cb);
void getAddedActiveObjectsAroundPos(const v3f &player_pos, f32 radius, void getAddedActiveObjectsAroundPos(const v3f &player_pos, f32 radius,
f32 player_radius, std::set<u16> &current_objects, f32 player_radius, std::set<u16> &current_objects,

@ -1608,14 +1608,12 @@ void ServerEnvironment::getSelectedActiveObjects(
const core::line3d<f32> &shootline_on_map, const core::line3d<f32> &shootline_on_map,
std::vector<PointedThing> &objects) std::vector<PointedThing> &objects)
{ {
std::vector<u16> objectIds; std::vector<ServerActiveObject *> objs;
getObjectsInsideRadius(objectIds, shootline_on_map.start, getObjectsInsideRadius(objs, shootline_on_map.start,
shootline_on_map.getLength() + 10.0f); shootline_on_map.getLength() + 10.0f, nullptr);
const v3f line_vector = shootline_on_map.getVector(); const v3f line_vector = shootline_on_map.getVector();
for (u16 objectId : objectIds) { for (auto obj : objs) {
ServerActiveObject* obj = getActiveObject(objectId);
aabb3f selection_box; aabb3f selection_box;
if (!obj->getSelectionBox(&selection_box)) if (!obj->getSelectionBox(&selection_box))
continue; continue;
@ -1630,7 +1628,7 @@ void ServerEnvironment::getSelectedActiveObjects(
if (boxLineCollision(offsetted_box, shootline_on_map.start, line_vector, if (boxLineCollision(offsetted_box, shootline_on_map.start, line_vector,
&current_intersection, &current_normal)) { &current_intersection, &current_normal)) {
objects.emplace_back( objects.emplace_back(
(s16) objectId, current_intersection, current_normal, (s16) obj->getId(), current_intersection, current_normal,
(current_intersection - shootline_on_map.start).getLengthSQ()); (current_intersection - shootline_on_map.start).getLengthSQ());
} }
} }

@ -323,9 +323,10 @@ public:
bool swapNode(v3s16 p, const MapNode &n); bool swapNode(v3s16 p, const MapNode &n);
// Find all active objects inside a radius around a point // Find all active objects inside a radius around a point
void getObjectsInsideRadius(std::vector<u16> &objects, const v3f &pos, float radius) void getObjectsInsideRadius(std::vector<ServerActiveObject *> &objects, const v3f &pos, float radius,
std::function<bool(ServerActiveObject *obj)> include_obj_cb)
{ {
return m_ao_manager.getObjectsInsideRadius(pos, radius, objects); return m_ao_manager.getObjectsInsideRadius(pos, radius, objects, include_obj_cb);
} }
// Clear objects, loading and going through every MapBlock // Clear objects, loading and going through every MapBlock

@ -148,14 +148,26 @@ void TestServerActiveObjectMgr::testGetObjectsInsideRadius()
saomgr.registerObject(new TestServerActiveObject(p)); saomgr.registerObject(new TestServerActiveObject(p));
} }
std::vector<u16> result; std::vector<ServerActiveObject *> result;
saomgr.getObjectsInsideRadius(v3f(), 50, result); saomgr.getObjectsInsideRadius(v3f(), 50, result, nullptr);
UASSERTCMP(int, ==, result.size(), 1); UASSERTCMP(int, ==, result.size(), 1);
result.clear(); result.clear();
saomgr.getObjectsInsideRadius(v3f(), 750, result); saomgr.getObjectsInsideRadius(v3f(), 750, result, nullptr);
UASSERTCMP(int, ==, result.size(), 2); UASSERTCMP(int, ==, result.size(), 2);
result.clear();
saomgr.getObjectsInsideRadius(v3f(), 750000, result, nullptr);
UASSERTCMP(int, ==, result.size(), 5);
result.clear();
auto include_obj_cb = [](ServerActiveObject *obj) {
return (obj->getBasePosition().X != 10);
};
saomgr.getObjectsInsideRadius(v3f(), 750000, result, include_obj_cb);
UASSERTCMP(int, ==, result.size(), 4);
clearSAOMgr(&saomgr); clearSAOMgr(&saomgr);
} }