New Benchmarks, All Server Positions caught now. Next would be to make other server operations use the better lookup method (like keeping client SAOs up to date)

This commit is contained in:
ExeVirus 2024-05-11 17:25:31 -04:00
parent 2d4f9dd789
commit b416cec314
12 changed files with 153 additions and 56 deletions

View File

@ -47,6 +47,52 @@ inline void fill(server::ActiveObjectMgr &mgr, size_t n)
}
template <size_t N>
void benchInsertObjects(Catch::Benchmark::Chronometer &meter)
{
server::ActiveObjectMgr mgr;
meter.measure([&] {
fill(mgr, N);
});
mgr.clear(); // implementation expects this
}
template <size_t N>
void benchRemoveObjects(Catch::Benchmark::Chronometer &meter)
{
server::ActiveObjectMgr mgr;
fill(mgr, N);
meter.measure([&] {
mgr.clear();
});
mgr.clear();
}
template <size_t N>
void benchUpdateObjectPositions(Catch::Benchmark::Chronometer &meter)
{
server::ActiveObjectMgr mgr;
std::vector<v3f> newPositions;
newPositions.reserve(N);
fill(mgr, N);
for (size_t i = 0; i < N; i++) {
newPositions.push_back(randpos());
}
meter.measure([&] {
size_t i = 0;
mgr.step(0,[&](ServerActiveObject* obj){
mgr.updateObjectPosition(obj->getId(), obj->getBasePosition(), newPositions.at(i));
++i;
});
});
mgr.clear();
}
template <size_t N>
void benchGetObjectsInsideRadius(Catch::Benchmark::Chronometer &meter)
{
@ -102,10 +148,26 @@ void benchGetObjectsInArea(Catch::Benchmark::Chronometer &meter)
BENCHMARK_ADVANCED("in_area_" #_count)(Catch::Benchmark::Chronometer meter) \
{ benchGetObjectsInArea<_count>(meter); };
#define BENCH_INSERT(_count) \
BENCHMARK_ADVANCED("insert_objects_" #_count)(Catch::Benchmark::Chronometer meter) \
{ benchInsertObjects<_count>(meter); };
#define BENCH_REMOVE(_count) \
BENCHMARK_ADVANCED("remove_objects_" #_count)(Catch::Benchmark::Chronometer meter) \
{ benchRemoveObjects<_count>(meter); };
#define BENCH_UPDATE(_count) \
BENCHMARK_ADVANCED("update_objects_" #_count)(Catch::Benchmark::Chronometer meter) \
{ benchUpdateObjectPositions<_count>(meter); };
TEST_CASE("ActiveObjectMgr") {
// BENCH_INSIDE_RADIUS(200)
// BENCH_INSIDE_RADIUS(1450)
// BENCH_INSIDE_RADIUS(10000)
BENCH_INSERT(10000)
BENCH_REMOVE(10000)
BENCH_UPDATE(10000)
BENCH_INSIDE_RADIUS(200)
BENCH_INSIDE_RADIUS(1450)
BENCH_INSIDE_RADIUS(10000)
BENCH_IN_AREA(200)
BENCH_IN_AREA(1450)

View File

@ -34,6 +34,12 @@ ActiveObjectMgr::~ActiveObjectMgr()
}
}
void ActiveObjectMgr::clear()
{
::ActiveObjectMgr<ServerActiveObject>::clear();
m_spatial_map.removeAll();
}
void ActiveObjectMgr::clearIf(const std::function<bool(ServerActiveObject *, u16)> &cb)
{
for (auto &it : m_active_objects.iter()) {
@ -61,6 +67,11 @@ void ActiveObjectMgr::step(
g_profiler->avg("ActiveObjectMgr: SAO count [#]", count);
}
void ActiveObjectMgr::updateObjectPosition(u16 id, const v3f &last_position, const v3f &new_position)
{
m_spatial_map.updatePosition(id, last_position, new_position);
}
bool ActiveObjectMgr::registerObject(std::unique_ptr<ServerActiveObject> obj)
{
assert(obj); // Pre-condition
@ -93,7 +104,7 @@ bool ActiveObjectMgr::registerObject(std::unique_ptr<ServerActiveObject> obj)
auto obj_id = obj->getId();
m_active_objects.put(obj_id, std::move(obj));
m_spatial_map.insert(obj_id, obj->getBasePosition());
//m_spatial_map.insert(obj_id, obj->getBasePosition());
auto new_size = m_active_objects.size();
verbosestream << "Server::ActiveObjectMgr::addActiveObjectRaw(): "
@ -175,9 +186,9 @@ void ActiveObjectMgr::getAddedActiveObjectsAroundPos(v3f player_pos, f32 radius,
- discard objects that are found in current_objects.
- add remaining objects to added_objects
*/
float r2 = radius * radius;
aabb3f bounds(player_pos.X-radius, player_pos.Y-radius, player_pos.Z-radius,
player_pos.X+radius, player_pos.Y+radius, player_pos.Z+radius);
f32 offset = radius > player_radius ? radius : player_radius;
aabb3f bounds(player_pos.X-offset, player_pos.Y-offset, player_pos.Z-offset,
player_pos.X+offset, player_pos.Y+offset, player_pos.Z+offset);
m_spatial_map.getRelevantObjectIds(bounds, [&](u16 id) {
auto obj = m_active_objects.get(id).get();
if (!obj) { // should never be hit

View File

@ -36,12 +36,16 @@ public:
void clearIf(const std::function<bool(ServerActiveObject *, u16)> &cb);
void step(float dtime,
const std::function<void(ServerActiveObject *)> &f) override;
void clear();
bool registerObject(std::unique_ptr<ServerActiveObject> obj) override;
void removeObject(u16 id) override;
void updateObjectPosition(u16 id, const v3f &last_position, const v3f &new_position);
void getObjectsInsideRadius(const v3f &pos, float radius,
std::vector<ServerActiveObject *> &result,
std::function<bool(ServerActiveObject *obj)> include_obj_cb);
void getObjectsInArea(const aabb3f &box,
std::vector<ServerActiveObject *> &result,
std::function<bool(ServerActiveObject *obj)> include_obj_cb);

View File

@ -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;
setBasePosition(getBasePosition() + (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;
}

View File

@ -86,11 +86,11 @@ std::string PlayerSAO::getDescription()
void PlayerSAO::addedToEnvironment(u32 dtime_s)
{
ServerActiveObject::addedToEnvironment(dtime_s);
ServerActiveObject::setBasePosition(m_base_position);
ServerActiveObject::setBasePosition(getBasePosition());
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 +116,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 +195,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 +207,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 +285,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,
@ -342,9 +342,9 @@ std::string PlayerSAO::generateUpdatePhysicsOverrideCommand() const
return os.str();
}
void PlayerSAO::setBasePosition(v3f position)
void PlayerSAO::setBasePosition(const 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
@ -397,7 +397,7 @@ void PlayerSAO::addPos(const v3f &added_pos)
m_env->getGameDef()->SendMovePlayerRel(getPeerID(), added_pos);
}
void PlayerSAO::moveTo(v3f pos, bool continuous)
void PlayerSAO::moveTo(const v3f &pos, bool continuous)
{
if(isAttached())
return;
@ -629,7 +629,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 +694,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 +710,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 +732,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;
}

View File

@ -88,10 +88,10 @@ public:
std::string getClientInitializationData(u16 protocol_version) override;
void getStaticData(std::string *result) const override;
void step(float dtime, bool send_recommended) override;
void setBasePosition(v3f position);
void setBasePosition(const v3f &position);
void setPos(const v3f &pos) override;
void addPos(const v3f &added_pos) override;
void moveTo(v3f pos, bool continuous) override;
void moveTo(const v3f &pos, bool continuous) override;
void setPlayerYaw(const float yaw);
// Data should not be sent at player initialization
void setPlayerYawAndSend(const float yaw);
@ -182,7 +182,7 @@ public:
void finalize(RemotePlayer *player, const std::set<std::string> &privs);
v3f getEyePosition() const { return m_base_position + getEyeOffset(); }
v3f getEyePosition() const { return getBasePosition() + getEyeOffset(); }
v3f getEyeOffset() const;
float getZoomFOV() const;

View File

@ -18,6 +18,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
*/
#include "serveractiveobject.h"
#include "serverenvironment.h"
#include <fstream>
#include "inventory.h"
#include "inventorymanager.h"
@ -31,6 +32,13 @@ ServerActiveObject::ServerActiveObject(ServerEnvironment *env, v3f pos):
{
}
void ServerActiveObject::setBasePosition(const v3f &pos) {
if( getEnv() != nullptr) {
getEnv()->updateObjectPosition(getId(), m_base_position, pos);
}
m_base_position = pos;
}
float ServerActiveObject::getMinimumSavedMovement()
{
return 2.0*BS;

View File

@ -77,7 +77,7 @@ public:
Some simple getters/setters
*/
v3f getBasePosition() const { return m_base_position; }
void setBasePosition(v3f pos){ m_base_position = pos; }
void setBasePosition(const v3f &pos);
ServerEnvironment* getEnv(){ return m_env; }
/*
@ -87,9 +87,9 @@ public:
virtual void setPos(const v3f &pos)
{ setBasePosition(pos); }
virtual void addPos(const v3f &added_pos)
{ setBasePosition(m_base_position + added_pos); }
{ setBasePosition(getBasePosition() + added_pos); }
// continuous: if true, object does not stop immediately at pos
virtual void moveTo(v3f pos, bool continuous)
virtual void moveTo(const v3f &pos, bool continuous)
{ setBasePosition(pos); }
// If object has moved less than this and data has not changed,
// saving to disk may be omitted

View File

@ -24,13 +24,13 @@ namespace server
{
// all inserted entires go into the uncached vector
void SpatialMap::insert(u16 id, v3f pos)
void SpatialMap::insert(u16 id, const v3f &pos)
{
m_cached.insert({SpatialKey(pos), id});
}
// Invalidates upon position update
void SpatialMap::updatePosition(u16 id, v3f &oldPos, v3f& newPos)
void SpatialMap::updatePosition(u16 id, const v3f &oldPos, const v3f &newPos)
{
// Try to leave early if already in the same bucket:
auto range = m_cached.equal_range(SpatialKey(newPos));
@ -50,10 +50,10 @@ void SpatialMap::updatePosition(u16 id, v3f &oldPos, v3f& newPos)
}
// place in new bucket
m_cached.insert(std::pair<SpatialKey,u16>(newPos, id));
insert(id, newPos);
}
void SpatialMap::remove(u16 id, v3f pos)
void SpatialMap::remove(u16 id, const v3f &pos)
{
SpatialKey key(pos);
if(m_cached.find(key) != m_cached.end()) {
@ -78,6 +78,16 @@ void SpatialMap::remove(u16 id)
}
}
void SpatialMap::removeAll()
{
m_cached.clear();
}
void SpatialMap::removeMapblock(const v3f &mapblockOrigin)
{
m_cached.erase(SpatialKey(mapblockOrigin));
}
void SpatialMap::getRelevantObjectIds(const aabb3f &box, const std::function<void(u16 id)> &callback)
{
if(!m_cached.empty()) {

View File

@ -28,10 +28,12 @@ namespace server
class SpatialMap
{
public:
void insert(u16 id, v3f pos);
void remove(u16 id, v3f pos);
void remove(u16 id)
void updatePosition(u16 id, v3f &oldPos, v3f& newPos);
void insert(u16 id, const v3f &pos);
void remove(u16 id, const v3f &pos);
void remove(u16 id);
void removeMapblock(const v3f &mapblockOrigin); // removes all entities at a given mapblock
void removeAll();
void updatePosition(u16 id, const v3f &oldPos, const v3f &newPos);
void getRelevantObjectIds(const aabb3f &box, const std::function<void(u16 id)> &callback);
protected:
@ -52,9 +54,9 @@ protected:
z = _z;
}
}
SpatialKey(v3f _pos) : SpatialKey(_pos.X, _pos.Y, _pos.Z){}
SpatialKey(const v3f &_pos) : SpatialKey(_pos.X, _pos.Y, _pos.Z){}
bool operator==(const SpatialKey& other) const {
bool operator==(const SpatialKey &other) const {
return (x == other.x && y == other.y && z == other.z);
}
} SpatialKey;

View File

@ -1587,12 +1587,7 @@ void ServerEnvironment::step(float dtime)
object_count++;
// Step object
v3f last_position = obj->getBasePosition();
obj->step(dtime, send_recommended);
v3f new_position = obj->getBasePosition();
if(last_position != new_position) {
m_ao_manager.updateCachedObjectID(obj->getId(), last_position, new_position);
}
// Read messages from object
obj->dumpAOMessagesToQueue(m_active_object_messages);

View File

@ -348,6 +348,11 @@ public:
return m_ao_manager.getObjectsInArea(box, objects, include_obj_cb);
}
void updateObjectPosition(u16 id, const v3f &last_position, const v3f &new_position)
{
m_ao_manager.updateObjectPosition(id, last_position, new_position);
}
// Clear objects, loading and going through every MapBlock
void clearObjects(ClearObjectsMode mode);