diff --git a/irr/include/vector3d.h b/irr/include/vector3d.h index a69f17e16..31dfd6955 100644 --- a/irr/include/vector3d.h +++ b/irr/include/vector3d.h @@ -7,6 +7,7 @@ #include "irrMath.h" #include +#include namespace irr { @@ -32,6 +33,9 @@ class vector3d //! Constructor with the same value for all elements explicit constexpr vector3d(T n) : X(n), Y(n), Z(n) {} + //! Array - vector conversion + constexpr vector3d(const std::array &arr) : + X(arr[0]), Y(arr[1]), Z(arr[2]) {} // operators @@ -181,6 +185,10 @@ class vector3d return *this; } + std::array toArray() const { + return {X, Y, Z}; + } + //! Get length of the vector. T getLength() const { return core::squareroot(X * X + Y * Y + Z * Z); } diff --git a/src/server/activeobjectmgr.cpp b/src/server/activeobjectmgr.cpp index 983fc0d95..e11ba166e 100644 --- a/src/server/activeobjectmgr.cpp +++ b/src/server/activeobjectmgr.cpp @@ -83,16 +83,17 @@ bool ActiveObjectMgr::registerObject(std::unique_ptr obj) return false; } - if (objectpos_over_limit(obj->getBasePosition())) { - v3f p = obj->getBasePosition(); + const v3f pos = obj->getBasePosition(); + if (objectpos_over_limit(pos)) { warningstream << "Server::ActiveObjectMgr::addActiveObjectRaw(): " - << "object position (" << p.X << "," << p.Y << "," << p.Z + << "object position (" << pos.X << "," << pos.Y << "," << pos.Z << ") outside maximum range" << std::endl; return false; } auto obj_id = obj->getId(); m_active_objects.put(obj_id, std::move(obj)); + m_spatial_index.insert(pos.toArray(), obj_id); auto new_size = m_active_objects.size(); verbosestream << "Server::ActiveObjectMgr::addActiveObjectRaw(): " @@ -115,42 +116,45 @@ void ActiveObjectMgr::removeObject(u16 id) if (!ok) { infostream << "Server::ActiveObjectMgr::removeObject(): " << "id=" << id << " not found" << std::endl; + } else { + m_spatial_index.remove(id); } } +void ActiveObjectMgr::updatePos(const v3f &pos, u16 id) { + // laziggy solution: only update if we already know the object + if (m_active_objects.get(id) != nullptr) + m_spatial_index.update(pos.toArray(), id); +} + 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.iter()) { - ServerActiveObject *obj = activeObject.second.get(); - if (!obj) - continue; - const v3f &objectpos = obj->getBasePosition(); - if (objectpos.getDistanceFromSQ(pos) > r2) - continue; + float r_squared = radius * radius; + m_spatial_index.rangeQuery((pos - v3f(radius)).toArray(), (pos + v3f(radius)).toArray(), [&](auto objPos, u16 id) { + if (v3f(objPos).getDistanceFromSQ(pos) > r_squared) + return; + auto obj = m_active_objects.get(id).get(); + if (!obj) + return; 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.iter()) { - ServerActiveObject *obj = activeObject.second.get(); + m_spatial_index.rangeQuery(box.MinEdge.toArray(), box.MaxEdge.toArray(), [&](auto _, u16 id) { + auto obj = m_active_objects.get(id).get(); if (!obj) - continue; - const v3f &objectpos = obj->getBasePosition(); - if (!box.isPointInside(objectpos)) - continue; - + return; if (!include_obj_cb || include_obj_cb(obj)) result.push_back(obj); - } + }); } void ActiveObjectMgr::getAddedActiveObjectsAroundPos(v3f player_pos, f32 radius, diff --git a/src/server/activeobjectmgr.h b/src/server/activeobjectmgr.h index dab795e8c..5e524dedb 100644 --- a/src/server/activeobjectmgr.h +++ b/src/server/activeobjectmgr.h @@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include "../activeobjectmgr.h" #include "serveractiveobject.h" +#include "util/k_d_tree.h" namespace server { @@ -38,6 +39,8 @@ class ActiveObjectMgr final : public ::ActiveObjectMgr bool registerObject(std::unique_ptr obj) override; void removeObject(u16 id) override; + void updatePos(const v3f &pos, u16 id); + void getObjectsInsideRadius(const v3f &pos, float radius, std::vector &result, std::function include_obj_cb); @@ -48,5 +51,7 @@ class ActiveObjectMgr final : public ::ActiveObjectMgr void getAddedActiveObjectsAroundPos(v3f player_pos, f32 radius, f32 player_radius, const std::set ¤t_objects, std::vector &added_objects); +private: + DynamicKdTrees<3, f32, u16> m_spatial_index; }; } // namespace server diff --git a/src/server/luaentity_sao.cpp b/src/server/luaentity_sao.cpp index 020f13fa5..12026e1cf 100644 --- a/src/server/luaentity_sao.cpp +++ b/src/server/luaentity_sao.cpp @@ -162,7 +162,7 @@ void LuaEntitySAO::step(float dtime, bool send_recommended) // Each frame, parent position is copied if the object is attached, otherwise it's calculated normally // If the object gets detached this comes into effect automatically from the last known origin if (auto *parent = getParent()) { - m_base_position = parent->getBasePosition(); + setBasePosition(parent->getBasePosition()); m_velocity = v3f(0,0,0); m_acceleration = v3f(0,0,0); } else { @@ -171,7 +171,7 @@ void LuaEntitySAO::step(float dtime, bool send_recommended) box.MinEdge *= BS; box.MaxEdge *= BS; f32 pos_max_d = BS*0.25; // Distance per iteration - v3f p_pos = m_base_position; + v3f p_pos = getBasePosition(); v3f p_velocity = m_velocity; v3f p_acceleration = m_acceleration; moveresult = collisionMoveSimple(m_env, m_env->getGameDef(), @@ -181,11 +181,11 @@ void LuaEntitySAO::step(float dtime, bool send_recommended) moveresult_p = &moveresult; // Apply results - m_base_position = p_pos; + setBasePosition(p_pos); m_velocity = p_velocity; m_acceleration = p_acceleration; } else { - m_base_position += (m_velocity + m_acceleration * 0.5f * dtime) * dtime; + addPos((m_velocity + m_acceleration * 0.5f * dtime) * dtime); m_velocity += dtime * m_acceleration; } @@ -228,7 +228,7 @@ void LuaEntitySAO::step(float dtime, bool send_recommended) } else if(m_last_sent_position_timer > 0.2){ minchange = 0.05*BS; } - float move_d = m_base_position.getDistanceFrom(m_last_sent_position); + float move_d = getBasePosition().getDistanceFrom(m_last_sent_position); move_d += m_last_sent_move_precision; float vel_d = m_velocity.getDistanceFrom(m_last_sent_velocity); if (move_d > minchange || vel_d > minchange || @@ -252,7 +252,7 @@ std::string LuaEntitySAO::getClientInitializationData(u16 protocol_version) os << serializeString16(m_init_name); // name writeU8(os, 0); // is_player writeU16(os, getId()); //id - writeV3F32(os, m_base_position); + writeV3F32(os, getBasePosition()); writeV3F32(os, m_rotation); writeU16(os, m_hp); @@ -381,7 +381,7 @@ void LuaEntitySAO::setPos(const v3f &pos) { if(isAttached()) return; - m_base_position = pos; + setBasePosition(pos); sendPosition(false, true); } @@ -389,7 +389,7 @@ void LuaEntitySAO::moveTo(v3f pos, bool continuous) { if(isAttached()) return; - m_base_position = pos; + setBasePosition(pos); if(!continuous) sendPosition(true, true); } @@ -403,7 +403,7 @@ std::string LuaEntitySAO::getDescription() { std::ostringstream oss; oss << "LuaEntitySAO \"" << m_init_name << "\" "; - auto pos = floatToInt(m_base_position, BS); + auto pos = floatToInt(getBasePosition(), BS); oss << "at " << pos; return oss.str(); } @@ -521,10 +521,10 @@ void LuaEntitySAO::sendPosition(bool do_interpolate, bool is_movement_end) // Send attachment updates instantly to the client prior updating position sendOutdatedData(); - m_last_sent_move_precision = m_base_position.getDistanceFrom( + m_last_sent_move_precision = getBasePosition().getDistanceFrom( m_last_sent_position); m_last_sent_position_timer = 0; - m_last_sent_position = m_base_position; + m_last_sent_position = getBasePosition(); m_last_sent_velocity = m_velocity; //m_last_sent_acceleration = m_acceleration; m_last_sent_rotation = m_rotation; @@ -532,7 +532,7 @@ void LuaEntitySAO::sendPosition(bool do_interpolate, bool is_movement_end) float update_interval = m_env->getSendRecommendedInterval(); std::string str = generateUpdatePositionCommand( - m_base_position, + getBasePosition(), m_velocity, m_acceleration, m_rotation, @@ -552,8 +552,8 @@ bool LuaEntitySAO::getCollisionBox(aabb3f *toset) const toset->MinEdge = m_prop.collisionbox.MinEdge * BS; toset->MaxEdge = m_prop.collisionbox.MaxEdge * BS; - toset->MinEdge += m_base_position; - toset->MaxEdge += m_base_position; + toset->MinEdge += getBasePosition(); + toset->MaxEdge += getBasePosition(); return true; } diff --git a/src/server/player_sao.cpp b/src/server/player_sao.cpp index b2e2351c9..9357ce244 100644 --- a/src/server/player_sao.cpp +++ b/src/server/player_sao.cpp @@ -86,11 +86,10 @@ std::string PlayerSAO::getDescription() void PlayerSAO::addedToEnvironment(u32 dtime_s) { ServerActiveObject::addedToEnvironment(dtime_s); - ServerActiveObject::setBasePosition(m_base_position); m_player->setPlayerSAO(this); m_player->setPeerId(m_peer_id_initial); m_peer_id_initial = PEER_ID_INEXISTENT; // don't try to use it again. - m_last_good_position = m_base_position; + m_last_good_position = getBasePosition(); } // Called before removing from environment @@ -116,7 +115,7 @@ std::string PlayerSAO::getClientInitializationData(u16 protocol_version) os << serializeString16(m_player->getName()); // name writeU8(os, 1); // is_player writeS16(os, getId()); // id - writeV3F32(os, m_base_position); + writeV3F32(os, getBasePosition()); writeV3F32(os, m_rotation); writeU16(os, getHP()); @@ -195,7 +194,7 @@ void PlayerSAO::step(float dtime, bool send_recommended) // Sequence of damage points, starting 0.1 above feet and progressing // upwards in 1 node intervals, stopping below top damage point. for (float dam_height = 0.1f; dam_height < dam_top; dam_height++) { - v3s16 p = floatToInt(m_base_position + + v3s16 p = floatToInt(getBasePosition() + v3f(0.0f, dam_height * BS, 0.0f), BS); MapNode n = m_env->getMap().getNode(p); const ContentFeatures &c = m_env->getGameDef()->ndef()->get(n); @@ -207,7 +206,7 @@ void PlayerSAO::step(float dtime, bool send_recommended) } // Top damage point - v3s16 ptop = floatToInt(m_base_position + + v3s16 ptop = floatToInt(getBasePosition() + v3f(0.0f, dam_top * BS, 0.0f), BS); MapNode ntop = m_env->getMap().getNode(ptop); const ContentFeatures &c = m_env->getGameDef()->ndef()->get(ntop); @@ -285,7 +284,7 @@ void PlayerSAO::step(float dtime, bool send_recommended) if (isAttached()) pos = m_last_good_position; else - pos = m_base_position; + pos = getBasePosition(); std::string str = generateUpdatePositionCommand( pos, @@ -344,7 +343,7 @@ std::string PlayerSAO::generateUpdatePhysicsOverrideCommand() const void PlayerSAO::setBasePosition(v3f position) { - if (m_player && position != m_base_position) + if (m_player && position != getBasePosition()) m_player->setDirty(true); // This needs to be ran for attachments too @@ -629,7 +628,7 @@ bool PlayerSAO::checkMovementCheat() if (m_is_singleplayer || isAttached() || g_settings->getBool("disable_anticheat")) { - m_last_good_position = m_base_position; + m_last_good_position = getBasePosition(); return false; } @@ -694,7 +693,7 @@ bool PlayerSAO::checkMovementCheat() if (player_max_jump < 0.0001f) player_max_jump = 0.0001f; - v3f diff = (m_base_position - m_last_good_position); + v3f diff = (getBasePosition() - m_last_good_position); float d_vert = diff.Y; diff.Y = 0; float d_horiz = diff.getLength(); @@ -710,7 +709,7 @@ bool PlayerSAO::checkMovementCheat() } if (m_move_pool.grab(required_time)) { - m_last_good_position = m_base_position; + m_last_good_position = getBasePosition(); } else { const float LAG_POOL_MIN = 5.0; float lag_pool_max = m_env->getMaxLagEstimate() * 2.0; @@ -732,8 +731,8 @@ bool PlayerSAO::getCollisionBox(aabb3f *toset) const toset->MinEdge = m_prop.collisionbox.MinEdge * BS; toset->MaxEdge = m_prop.collisionbox.MaxEdge * BS; - toset->MinEdge += m_base_position; - toset->MaxEdge += m_base_position; + toset->MinEdge += getBasePosition(); + toset->MaxEdge += getBasePosition(); return true; } diff --git a/src/server/player_sao.h b/src/server/player_sao.h index b26304589..8a11ab934 100644 --- a/src/server/player_sao.h +++ b/src/server/player_sao.h @@ -182,7 +182,7 @@ class PlayerSAO : public UnitSAO void finalize(RemotePlayer *player, const std::set &privs); - v3f getEyePosition() const { return m_base_position + getEyeOffset(); } + v3f getEyePosition() const { return getBasePosition() + getEyeOffset(); } v3f getEyeOffset() const; float getZoomFOV() const; diff --git a/src/server/serveractiveobject.cpp b/src/server/serveractiveobject.cpp index fb09464cf..c881047a8 100644 --- a/src/server/serveractiveobject.cpp +++ b/src/server/serveractiveobject.cpp @@ -31,6 +31,12 @@ ServerActiveObject::ServerActiveObject(ServerEnvironment *env, v3f pos): { } +void ServerActiveObject::setBasePosition(v3f pos) { + m_base_position = pos; + if (m_env) // HACK this doesn't feel right; *when* is m_env null? + ServerEnvironment_updatePos(m_env, pos, getId()); +} + float ServerActiveObject::getMinimumSavedMovement() { return 2.0*BS; diff --git a/src/server/serveractiveobject.h b/src/server/serveractiveobject.h index 2d09e34c1..a37cad9be 100644 --- a/src/server/serveractiveobject.h +++ b/src/server/serveractiveobject.h @@ -44,6 +44,7 @@ Some planning */ class ServerEnvironment; +void ServerEnvironment_updatePos(ServerEnvironment *senv, const v3f &pos, u16 id); struct ItemStack; struct ToolCapabilities; struct ObjectProperties; @@ -77,7 +78,7 @@ class ServerActiveObject : public ActiveObject Some simple getters/setters */ v3f getBasePosition() const { return m_base_position; } - void setBasePosition(v3f pos){ m_base_position = pos; } + void setBasePosition(v3f pos); ServerEnvironment* getEnv(){ return m_env; } /* @@ -244,7 +245,6 @@ class ServerActiveObject : public ActiveObject virtual void onDetach(int parent_id) {} ServerEnvironment *m_env; - v3f m_base_position; std::unordered_set m_attached_particle_spawners; /* @@ -272,4 +272,6 @@ class ServerActiveObject : public ActiveObject Queue of messages to be sent to the client */ std::queue m_messages_out; +private: + v3f m_base_position; // setBasePosition updates index and MUST be called }; diff --git a/src/serverenvironment.cpp b/src/serverenvironment.cpp index 87bb39d4c..39e7aecc2 100644 --- a/src/serverenvironment.cpp +++ b/src/serverenvironment.cpp @@ -2528,3 +2528,8 @@ bool ServerEnvironment::migrateAuthDatabase( } return true; } + +// HACK +void ServerEnvironment_updatePos(ServerEnvironment *senv, const v3f &pos, u16 id) { + senv->updatePos(pos, id); +} \ No newline at end of file diff --git a/src/serverenvironment.h b/src/serverenvironment.h index d5d45d0f4..71e5daa34 100644 --- a/src/serverenvironment.h +++ b/src/serverenvironment.h @@ -334,6 +334,10 @@ class ServerEnvironment final : public Environment // Find the daylight value at pos with a Depth First Search u8 findSunlight(v3s16 pos) const; + void updatePos(const v3f &pos, u16 id) { + return m_ao_manager.updatePos(pos, id); + } + // Find all active objects inside a radius around a point void getObjectsInsideRadius(std::vector &objects, const v3f &pos, float radius, std::function include_obj_cb) @@ -513,3 +517,6 @@ class ServerEnvironment final : public Environment std::unique_ptr createSAO(ActiveObjectType type, v3f pos, const std::string &data); }; + +// HACK +void ServerEnvironment_updatePos(ServerEnvironment *senv, const v3f &pos, u16 id); \ No newline at end of file