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 @@ public: //! 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 @@ public: 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 155cf50fb..a9297c479 100644 --- a/src/server/activeobjectmgr.cpp +++ b/src/server/activeobjectmgr.cpp @@ -68,16 +68,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(): " @@ -100,6 +101,8 @@ void ActiveObjectMgr::removeObject(u16 id) if (!ok) { infostream << "Server::ActiveObjectMgr::removeObject(): " << "id=" << id << " not found" << std::endl; + } else { + m_spatial_index.remove(id); } } @@ -113,39 +116,40 @@ void ActiveObjectMgr::invalidateActiveObjectObserverCaches() } } +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( diff --git a/src/server/activeobjectmgr.h b/src/server/activeobjectmgr.h index 854a75b18..a63227c60 100644 --- a/src/server/activeobjectmgr.h +++ b/src/server/activeobjectmgr.h @@ -8,6 +8,7 @@ #include #include "../activeobjectmgr.h" #include "serveractiveobject.h" +#include "util/k_d_tree.h" namespace server { @@ -25,6 +26,8 @@ public: void invalidateActiveObjectObserverCaches(); + void updatePos(const v3f &pos, u16 id); + void getObjectsInsideRadius(const v3f &pos, float radius, std::vector &result, std::function include_obj_cb); @@ -36,5 +39,7 @@ public: 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 5de0167d6..0ad3daba6 100644 --- a/src/server/luaentity_sao.cpp +++ b/src/server/luaentity_sao.cpp @@ -147,7 +147,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 { @@ -155,7 +155,7 @@ void LuaEntitySAO::step(float dtime, bool send_recommended) aabb3f box = m_prop.collisionbox; box.MinEdge *= BS; box.MaxEdge *= BS; - 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(), @@ -165,11 +165,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; } @@ -212,7 +212,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 || @@ -236,7 +236,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); @@ -365,7 +365,7 @@ void LuaEntitySAO::setPos(const v3f &pos) { if(isAttached()) return; - m_base_position = pos; + setBasePosition(pos); sendPosition(false, true); } @@ -373,7 +373,7 @@ void LuaEntitySAO::moveTo(v3f pos, bool continuous) { if(isAttached()) return; - m_base_position = pos; + setBasePosition(pos); if(!continuous) sendPosition(true, true); } @@ -387,7 +387,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(); } @@ -503,10 +503,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; @@ -514,7 +514,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, @@ -534,8 +534,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 5d6b891fa..87169d33e 100644 --- a/src/server/player_sao.cpp +++ b/src/server/player_sao.cpp @@ -71,11 +71,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 @@ -101,7 +100,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()); @@ -185,7 +184,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); @@ -197,7 +196,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); @@ -274,7 +273,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, @@ -333,7 +332,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 @@ -637,7 +636,7 @@ bool PlayerSAO::checkMovementCheat() if (m_is_singleplayer || isAttached() || !(anticheat_flags & AC_MOVEMENT)) { - m_last_good_position = m_base_position; + m_last_good_position = getBasePosition(); return false; } @@ -702,7 +701,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(); @@ -723,7 +722,7 @@ bool PlayerSAO::checkMovementCheat() required_time /= anticheat_movement_tolerance; 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; @@ -745,8 +744,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 a792f0c11..9998d8018 100644 --- a/src/server/player_sao.h +++ b/src/server/player_sao.h @@ -168,7 +168,7 @@ public: 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 913c402ed..7e5d813c5 100644 --- a/src/server/serveractiveobject.cpp +++ b/src/server/serveractiveobject.cpp @@ -14,6 +14,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 8b60bc5f8..317445315 100644 --- a/src/server/serveractiveobject.h +++ b/src/server/serveractiveobject.h @@ -30,6 +30,7 @@ Some planning */ class ServerEnvironment; +void ServerEnvironment_updatePos(ServerEnvironment *senv, const v3f &pos, u16 id); struct ItemStack; struct ToolCapabilities; struct ObjectProperties; @@ -63,7 +64,7 @@ public: 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; } /* @@ -245,7 +246,6 @@ protected: virtual void onMarkedForRemoval() {} ServerEnvironment *m_env; - v3f m_base_position; std::unordered_set m_attached_particle_spawners; /* @@ -273,4 +273,6 @@ protected: 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 d60e41ad9..3b1a4114f 100644 --- a/src/serverenvironment.cpp +++ b/src/serverenvironment.cpp @@ -2563,3 +2563,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 42f777dde..69d38c2b6 100644 --- a/src/serverenvironment.h +++ b/src/serverenvironment.h @@ -335,6 +335,10 @@ public: // 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) @@ -514,3 +518,6 @@ private: 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