From d5c441253669c9f88dea948d261e0d8934d28fb9 Mon Sep 17 00:00:00 2001 From: SmallJoker Date: Sat, 4 Apr 2020 21:27:23 +0200 Subject: Revert collision tweaks #9365 and #9327 (#9591) This reverts commit df74d369a395f0b99bd23fa3e7fb4c628c3df336. This reverts commit 908e76247922d4adf879b3996c4f75bdbb4e536d. Restores the original collision detection bugs to release 5.2.0 prior the large collision detection fix. --- src/collision.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/collision.cpp') diff --git a/src/collision.cpp b/src/collision.cpp index a4c5454ae..a443be7ab 100644 --- a/src/collision.cpp +++ b/src/collision.cpp @@ -415,12 +415,12 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef, Collision uncertainty radius Make it a bit larger than the maximum distance of movement */ - //f32 d = pos_max_d * 1.1f; + f32 d = pos_max_d * 1.1f; + // A fairly large value in here makes moving smoother + //f32 d = 0.15*BS; - - f32 d = 0.3f; // Temporary fix, any nonzero d causes collision glitches, the more the greater it is. - // ultimately it has to be determined if any uncertainty is involved, and if it is, eliminated - // and d & pos_max_d params removed from function calls. + // This should always apply, otherwise there are glitches + assert(d > pos_max_d); // invariant int loopcount = 0; -- cgit v1.2.3 From 3ad5388c6d3894e2f4aa7158cc2b62b626f0f967 Mon Sep 17 00:00:00 2001 From: TheTermos <55103816+TheTermos@users.noreply.github.com> Date: Wed, 8 Apr 2020 22:45:05 +0200 Subject: Collision various fixes (#9343) --- src/client/localplayer.h | 2 + src/collision.cpp | 222 +++++++++++++++++++--------------------- src/collision.h | 2 +- src/unittest/test_collision.cpp | 64 ++++++------ 4 files changed, 141 insertions(+), 149 deletions(-) (limited to 'src/collision.cpp') diff --git a/src/client/localplayer.h b/src/client/localplayer.h index 95dceb1f4..d88ae17ac 100644 --- a/src/client/localplayer.h +++ b/src/client/localplayer.h @@ -141,6 +141,8 @@ public: void setCollisionbox(const aabb3f &box) { m_collisionbox = box; } + const aabb3f& getCollisionbox() const { return m_collisionbox; } + float getZoomFOV() const { return m_zoom_fov; } void setZoomFOV(float zoom_fov) { m_zoom_fov = zoom_fov; } diff --git a/src/collision.cpp b/src/collision.cpp index a443be7ab..0d37ea436 100644 --- a/src/collision.cpp +++ b/src/collision.cpp @@ -25,16 +25,13 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "gamedef.h" #ifndef SERVER #include "client/clientenvironment.h" +#include "client/localplayer.h" #endif #include "serverenvironment.h" #include "serverobject.h" #include "util/timetaker.h" #include "profiler.h" -// float error is 10 - 9.96875 = 0.03125 -//#define COLL_ZERO 0.032 // broken unit tests -#define COLL_ZERO 0 - struct NearbyCollisionInfo { NearbyCollisionInfo(bool is_ul, bool is_obj, int bouncy, @@ -61,118 +58,102 @@ struct NearbyCollisionInfo { // The time after which the collision occurs is stored in dtime. CollisionAxis axisAlignedCollision( const aabb3f &staticbox, const aabb3f &movingbox, - const v3f &speed, f32 d, f32 *dtime) + const v3f &speed, f32 *dtime) { //TimeTaker tt("axisAlignedCollision"); - f32 xsize = (staticbox.MaxEdge.X - staticbox.MinEdge.X) - COLL_ZERO; // reduce box size for solve collision stuck (flying sand) - f32 ysize = (staticbox.MaxEdge.Y - staticbox.MinEdge.Y); // - COLL_ZERO; // Y - no sense for falling, but maybe try later - f32 zsize = (staticbox.MaxEdge.Z - staticbox.MinEdge.Z) - COLL_ZERO; - aabb3f relbox( - movingbox.MinEdge.X - staticbox.MinEdge.X, - movingbox.MinEdge.Y - staticbox.MinEdge.Y, - movingbox.MinEdge.Z - staticbox.MinEdge.Z, - movingbox.MaxEdge.X - staticbox.MinEdge.X, - movingbox.MaxEdge.Y - staticbox.MinEdge.Y, - movingbox.MaxEdge.Z - staticbox.MinEdge.Z + movingbox.MaxEdge.X - movingbox.MinEdge.X + staticbox.MaxEdge.X - staticbox.MinEdge.X, // sum of the widths + movingbox.MaxEdge.Y - movingbox.MinEdge.Y + staticbox.MaxEdge.Y - staticbox.MinEdge.Y, + movingbox.MaxEdge.Z - movingbox.MinEdge.Z + staticbox.MaxEdge.Z - staticbox.MinEdge.Z, + std::max(movingbox.MaxEdge.X, staticbox.MaxEdge.X) - std::min(movingbox.MinEdge.X, staticbox.MinEdge.X), //outer bounding 'box' dimensions + std::max(movingbox.MaxEdge.Y, staticbox.MaxEdge.Y) - std::min(movingbox.MinEdge.Y, staticbox.MinEdge.Y), + std::max(movingbox.MaxEdge.Z, staticbox.MaxEdge.Z) - std::min(movingbox.MinEdge.Z, staticbox.MinEdge.Z) ); - if(speed.X > 0) // Check for collision with X- plane - { - if (relbox.MaxEdge.X <= d) { - *dtime = -relbox.MaxEdge.X / speed.X; - if ((relbox.MinEdge.Y + speed.Y * (*dtime) < ysize) && - (relbox.MaxEdge.Y + speed.Y * (*dtime) > COLL_ZERO) && - (relbox.MinEdge.Z + speed.Z * (*dtime) < zsize) && - (relbox.MaxEdge.Z + speed.Z * (*dtime) > COLL_ZERO)) - return COLLISION_AXIS_X; - } - else if(relbox.MinEdge.X > xsize) - { - return COLLISION_AXIS_NONE; - } - } - else if(speed.X < 0) // Check for collision with X+ plane - { - if (relbox.MinEdge.X >= xsize - d) { - *dtime = (xsize - relbox.MinEdge.X) / speed.X; - if ((relbox.MinEdge.Y + speed.Y * (*dtime) < ysize) && - (relbox.MaxEdge.Y + speed.Y * (*dtime) > COLL_ZERO) && - (relbox.MinEdge.Z + speed.Z * (*dtime) < zsize) && - (relbox.MaxEdge.Z + speed.Z * (*dtime) > COLL_ZERO)) - return COLLISION_AXIS_X; - } - else if(relbox.MaxEdge.X < 0) - { - return COLLISION_AXIS_NONE; + const f32 dtime_max = *dtime; + const f32 inner_margin = -1.5f; + f32 distance; + f32 time; + + if (speed.X) { + distance = relbox.MaxEdge.X - relbox.MinEdge.X; + + *dtime = distance >= 0 ? std::abs(distance / speed.X) : -std::abs(distance / speed.X); + time = std::max(*dtime, 0.0f); + + if (distance > inner_margin) { + if (*dtime <= dtime_max) { + if ((speed.X > 0 && staticbox.MaxEdge.X > movingbox.MaxEdge.X) || + (speed.X < 0 && staticbox.MinEdge.X < movingbox.MinEdge.X)) { + if ( + (std::max(movingbox.MaxEdge.Y + speed.Y * time, staticbox.MaxEdge.Y) + - std::min(movingbox.MinEdge.Y + speed.Y * time, staticbox.MinEdge.Y) + - relbox.MinEdge.Y < 0) && + (std::max(movingbox.MaxEdge.Z + speed.Z * time, staticbox.MaxEdge.Z) + - std::min(movingbox.MinEdge.Z + speed.Z * time, staticbox.MinEdge.Z) + - relbox.MinEdge.Z < 0) + ) + return COLLISION_AXIS_X; + } + } else { + return COLLISION_AXIS_NONE; + } } } // NO else if here - if(speed.Y > 0) // Check for collision with Y- plane - { - if (relbox.MaxEdge.Y <= d) { - *dtime = -relbox.MaxEdge.Y / speed.Y; - if ((relbox.MinEdge.X + speed.X * (*dtime) < xsize) && - (relbox.MaxEdge.X + speed.X * (*dtime) > COLL_ZERO) && - (relbox.MinEdge.Z + speed.Z * (*dtime) < zsize) && - (relbox.MaxEdge.Z + speed.Z * (*dtime) > COLL_ZERO)) - return COLLISION_AXIS_Y; - } - else if(relbox.MinEdge.Y > ysize) - { - return COLLISION_AXIS_NONE; - } - } - else if(speed.Y < 0) // Check for collision with Y+ plane - { - if (relbox.MinEdge.Y >= ysize - d) { - *dtime = (ysize - relbox.MinEdge.Y) / speed.Y; - if ((relbox.MinEdge.X + speed.X * (*dtime) < xsize) && - (relbox.MaxEdge.X + speed.X * (*dtime) > COLL_ZERO) && - (relbox.MinEdge.Z + speed.Z * (*dtime) < zsize) && - (relbox.MaxEdge.Z + speed.Z * (*dtime) > COLL_ZERO)) - return COLLISION_AXIS_Y; - } - else if(relbox.MaxEdge.Y < 0) - { - return COLLISION_AXIS_NONE; + if (speed.Y) { + distance = relbox.MaxEdge.Y - relbox.MinEdge.Y; + + *dtime = distance >= 0 ? std::abs(distance / speed.Y) : -std::abs(distance / speed.Y); + time = std::max(*dtime, 0.0f); + + if (distance > inner_margin) { + if (*dtime <= dtime_max) { + if ((speed.Y > 0 && staticbox.MaxEdge.Y > movingbox.MaxEdge.Y) || + (speed.Y < 0 && staticbox.MinEdge.Y < movingbox.MinEdge.Y)) { + if ( + (std::max(movingbox.MaxEdge.X + speed.X * time, staticbox.MaxEdge.X) + - std::min(movingbox.MinEdge.X + speed.X * time, staticbox.MinEdge.X) + - relbox.MinEdge.X < 0) && + (std::max(movingbox.MaxEdge.Z + speed.Z * time, staticbox.MaxEdge.Z) + - std::min(movingbox.MinEdge.Z + speed.Z * time, staticbox.MinEdge.Z) + - relbox.MinEdge.Z < 0) + ) + return COLLISION_AXIS_Y; + } + } else { + return COLLISION_AXIS_NONE; + } } } // NO else if here - if(speed.Z > 0) // Check for collision with Z- plane - { - if (relbox.MaxEdge.Z <= d) { - *dtime = -relbox.MaxEdge.Z / speed.Z; - if ((relbox.MinEdge.X + speed.X * (*dtime) < xsize) && - (relbox.MaxEdge.X + speed.X * (*dtime) > COLL_ZERO) && - (relbox.MinEdge.Y + speed.Y * (*dtime) < ysize) && - (relbox.MaxEdge.Y + speed.Y * (*dtime) > COLL_ZERO)) - return COLLISION_AXIS_Z; - } - //else if(relbox.MinEdge.Z > zsize) - //{ - // return COLLISION_AXIS_NONE; - //} - } - else if(speed.Z < 0) // Check for collision with Z+ plane - { - if (relbox.MinEdge.Z >= zsize - d) { - *dtime = (zsize - relbox.MinEdge.Z) / speed.Z; - if ((relbox.MinEdge.X + speed.X * (*dtime) < xsize) && - (relbox.MaxEdge.X + speed.X * (*dtime) > COLL_ZERO) && - (relbox.MinEdge.Y + speed.Y * (*dtime) < ysize) && - (relbox.MaxEdge.Y + speed.Y * (*dtime) > COLL_ZERO)) - return COLLISION_AXIS_Z; + if (speed.Z) { + distance = relbox.MaxEdge.Z - relbox.MinEdge.Z; + + *dtime = distance >= 0 ? std::abs(distance / speed.Z) : -std::abs(distance / speed.Z); + time = std::max(*dtime, 0.0f); + + if (distance > inner_margin) { + if (*dtime <= dtime_max) { + if ((speed.Z > 0 && staticbox.MaxEdge.Z > movingbox.MaxEdge.Z) || + (speed.Z < 0 && staticbox.MinEdge.Z < movingbox.MinEdge.Z)) { + if ( + (std::max(movingbox.MaxEdge.X + speed.X * time, staticbox.MaxEdge.X) + - std::min(movingbox.MinEdge.X + speed.X * time, staticbox.MinEdge.X) + - relbox.MinEdge.X < 0) && + (std::max(movingbox.MaxEdge.Y + speed.Y * time, staticbox.MaxEdge.Y) + - std::min(movingbox.MinEdge.Y + speed.Y * time, staticbox.MinEdge.Y) + - relbox.MinEdge.Y < 0) + ) + return COLLISION_AXIS_Z; + } + } } - //else if(relbox.MaxEdge.Z < 0) - //{ - // return COLLISION_AXIS_NONE; - //} } return COLLISION_AXIS_NONE; @@ -405,22 +386,25 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef, } } } +#ifndef SERVER + if (self && c_env) { + LocalPlayer *lplayer = c_env->getLocalPlayer(); + if (lplayer->getParent() == nullptr) { + aabb3f lplayer_collisionbox = lplayer->getCollisionbox(); + v3f lplayer_pos = lplayer->getPosition(); + lplayer_collisionbox.MinEdge += lplayer_pos; + lplayer_collisionbox.MaxEdge += lplayer_pos; + cinfo.emplace_back(false, true, 0, v3s16(), lplayer_collisionbox); + } + } +#endif } //tt3 /* Collision detection */ - /* - Collision uncertainty radius - Make it a bit larger than the maximum distance of movement - */ - f32 d = pos_max_d * 1.1f; - // A fairly large value in here makes moving smoother - //f32 d = 0.15*BS; - - // This should always apply, otherwise there are glitches - assert(d > pos_max_d); // invariant + f32 d = 0.0f; int loopcount = 0; @@ -450,9 +434,9 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef, continue; // Find nearest collision of the two boxes (raytracing-like) - f32 dtime_tmp; + f32 dtime_tmp = nearest_dtime; CollisionAxis collided = axisAlignedCollision(box_info.box, - movingbox, *speed_f, d, &dtime_tmp); + movingbox, *speed_f, &dtime_tmp); if (collided == -1 || dtime_tmp >= nearest_dtime) continue; @@ -470,11 +454,18 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef, // Otherwise, a collision occurred. NearbyCollisionInfo &nearest_info = cinfo[nearest_boxindex]; const aabb3f& cbox = nearest_info.box; + + //movingbox except moved to the horizontal position it would be after step up + aabb3f stepbox = movingbox; + stepbox.MinEdge.X += speed_f->X * dtime; + stepbox.MinEdge.Z += speed_f->Z * dtime; + stepbox.MaxEdge.X += speed_f->X * dtime; + stepbox.MaxEdge.Z += speed_f->Z * dtime; // Check for stairs. bool step_up = (nearest_collided != COLLISION_AXIS_Y) && // must not be Y direction (movingbox.MinEdge.Y < cbox.MaxEdge.Y) && (movingbox.MinEdge.Y + stepheight > cbox.MaxEdge.Y) && - (!wouldCollideWithCeiling(cinfo, movingbox, + (!wouldCollideWithCeiling(cinfo, stepbox, cbox.MaxEdge.Y - movingbox.MinEdge.Y, d)); @@ -483,7 +474,7 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef, // Move to the point of collision and reduce dtime by nearest_dtime if (nearest_dtime < 0) { - // Handle negative nearest_dtime (can be caused by the d allowance) + // Handle negative nearest_dtime if (!step_up) { if (nearest_collided == COLLISION_AXIS_X) pos_f->X += speed_f->X * nearest_dtime; @@ -562,9 +553,8 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef, Object touches ground if object's minimum Y is near node's maximum Y and object's X-Z-area overlaps with the node's X-Z-area. - - Use 0.15*BS so that it is easier to get on a node. */ + if (cbox.MaxEdge.X - d > box.MinEdge.X && cbox.MinEdge.X + d < box.MaxEdge.X && cbox.MaxEdge.Z - d > box.MinEdge.Z && cbox.MinEdge.Z + d < box.MaxEdge.Z) { @@ -574,7 +564,7 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef, box.MinEdge += *pos_f; box.MaxEdge += *pos_f; } - if (std::fabs(cbox.MaxEdge.Y - box.MinEdge.Y) < 0.15f * BS) { + if (std::fabs(cbox.MaxEdge.Y - box.MinEdge.Y) < 0.05f) { result.touching_ground = true; if (box_info.is_object) diff --git a/src/collision.h b/src/collision.h index 85df02c96..fa47cccc1 100644 --- a/src/collision.h +++ b/src/collision.h @@ -77,7 +77,7 @@ collisionMoveResult collisionMoveSimple(Environment *env,IGameDef *gamedef, // dtime receives time until first collision, invalid if -1 is returned CollisionAxis axisAlignedCollision( const aabb3f &staticbox, const aabb3f &movingbox, - const v3f &speed, f32 d, f32 *dtime); + const v3f &speed, f32 *dtime); // Helper function: // Checks if moving the movingbox up by the given distance would hit a ceiling. diff --git a/src/unittest/test_collision.cpp b/src/unittest/test_collision.cpp index 332d3fa13..2f39c2489 100644 --- a/src/unittest/test_collision.cpp +++ b/src/unittest/test_collision.cpp @@ -50,38 +50,38 @@ void TestCollision::testAxisAlignedCollision() aabb3f s(bx, by, bz, bx+1, by+1, bz+1); aabb3f m(bx-2, by, bz, bx-1, by+1, bz+1); v3f v(1, 0, 0); - f32 dtime = 0; - UASSERT(axisAlignedCollision(s, m, v, 0, &dtime) == 0); + f32 dtime = 1.0f; + UASSERT(axisAlignedCollision(s, m, v, &dtime) == 0); UASSERT(fabs(dtime - 1.000) < 0.001); } { aabb3f s(bx, by, bz, bx+1, by+1, bz+1); aabb3f m(bx-2, by, bz, bx-1, by+1, bz+1); v3f v(-1, 0, 0); - f32 dtime = 0; - UASSERT(axisAlignedCollision(s, m, v, 0, &dtime) == -1); + f32 dtime = 1.0f; + UASSERT(axisAlignedCollision(s, m, v, &dtime) == -1); } { aabb3f s(bx, by, bz, bx+1, by+1, bz+1); aabb3f m(bx-2, by+1.5, bz, bx-1, by+2.5, bz-1); v3f v(1, 0, 0); - f32 dtime; - UASSERT(axisAlignedCollision(s, m, v, 0, &dtime) == -1); + f32 dtime = 1.0f; + UASSERT(axisAlignedCollision(s, m, v, &dtime) == -1); } { aabb3f s(bx, by, bz, bx+1, by+1, bz+1); aabb3f m(bx-2, by-1.5, bz, bx-1.5, by+0.5, bz+1); v3f v(0.5, 0.1, 0); - f32 dtime; - UASSERT(axisAlignedCollision(s, m, v, 0, &dtime) == 0); + f32 dtime = 3.0f; + UASSERT(axisAlignedCollision(s, m, v, &dtime) == 0); UASSERT(fabs(dtime - 3.000) < 0.001); } { aabb3f s(bx, by, bz, bx+1, by+1, bz+1); aabb3f m(bx-2, by-1.5, bz, bx-1.5, by+0.5, bz+1); v3f v(0.5, 0.1, 0); - f32 dtime; - UASSERT(axisAlignedCollision(s, m, v, 0, &dtime) == 0); + f32 dtime = 3.0f; + UASSERT(axisAlignedCollision(s, m, v, &dtime) == 0); UASSERT(fabs(dtime - 3.000) < 0.001); } @@ -90,38 +90,38 @@ void TestCollision::testAxisAlignedCollision() aabb3f s(bx, by, bz, bx+1, by+1, bz+1); aabb3f m(bx+2, by, bz, bx+3, by+1, bz+1); v3f v(-1, 0, 0); - f32 dtime; - UASSERT(axisAlignedCollision(s, m, v, 0, &dtime) == 0); + f32 dtime = 1.0f; + UASSERT(axisAlignedCollision(s, m, v, &dtime) == 0); UASSERT(fabs(dtime - 1.000) < 0.001); } { aabb3f s(bx, by, bz, bx+1, by+1, bz+1); aabb3f m(bx+2, by, bz, bx+3, by+1, bz+1); v3f v(1, 0, 0); - f32 dtime; - UASSERT(axisAlignedCollision(s, m, v, 0, &dtime) == -1); + f32 dtime = 1.0f; + UASSERT(axisAlignedCollision(s, m, v, &dtime) == -1); } { aabb3f s(bx, by, bz, bx+1, by+1, bz+1); aabb3f m(bx+2, by, bz+1.5, bx+3, by+1, bz+3.5); v3f v(-1, 0, 0); - f32 dtime; - UASSERT(axisAlignedCollision(s, m, v, 0, &dtime) == -1); + f32 dtime = 1.0f; + UASSERT(axisAlignedCollision(s, m, v, &dtime) == -1); } { aabb3f s(bx, by, bz, bx+1, by+1, bz+1); aabb3f m(bx+2, by-1.5, bz, bx+2.5, by-0.5, bz+1); v3f v(-0.5, 0.2, 0); - f32 dtime; - UASSERT(axisAlignedCollision(s, m, v, 0, &dtime) == 1); // Y, not X! + f32 dtime = 2.5f; + UASSERT(axisAlignedCollision(s, m, v, &dtime) == 1); // Y, not X! UASSERT(fabs(dtime - 2.500) < 0.001); } { aabb3f s(bx, by, bz, bx+1, by+1, bz+1); aabb3f m(bx+2, by-1.5, bz, bx+2.5, by-0.5, bz+1); v3f v(-0.5, 0.3, 0); - f32 dtime; - UASSERT(axisAlignedCollision(s, m, v, 0, &dtime) == 0); + f32 dtime = 2.0f; + UASSERT(axisAlignedCollision(s, m, v, &dtime) == 0); UASSERT(fabs(dtime - 2.000) < 0.001); } @@ -132,48 +132,48 @@ void TestCollision::testAxisAlignedCollision() aabb3f s(bx, by, bz, bx+2, by+2, bz+2); aabb3f m(bx+2.3, by+2.29, bz+2.29, bx+4.2, by+4.2, bz+4.2); v3f v(-1./3, -1./3, -1./3); - f32 dtime; - UASSERT(axisAlignedCollision(s, m, v, 0, &dtime) == 0); + f32 dtime = 1.0f; + UASSERT(axisAlignedCollision(s, m, v, &dtime) == 0); UASSERT(fabs(dtime - 0.9) < 0.001); } { aabb3f s(bx, by, bz, bx+2, by+2, bz+2); aabb3f m(bx+2.29, by+2.3, bz+2.29, bx+4.2, by+4.2, bz+4.2); v3f v(-1./3, -1./3, -1./3); - f32 dtime; - UASSERT(axisAlignedCollision(s, m, v, 0, &dtime) == 1); + f32 dtime = 1.0f; + UASSERT(axisAlignedCollision(s, m, v, &dtime) == 1); UASSERT(fabs(dtime - 0.9) < 0.001); } { aabb3f s(bx, by, bz, bx+2, by+2, bz+2); aabb3f m(bx+2.29, by+2.29, bz+2.3, bx+4.2, by+4.2, bz+4.2); v3f v(-1./3, -1./3, -1./3); - f32 dtime; - UASSERT(axisAlignedCollision(s, m, v, 0, &dtime) == 2); + f32 dtime = 1.0f; + UASSERT(axisAlignedCollision(s, m, v, &dtime) == 2); UASSERT(fabs(dtime - 0.9) < 0.001); } { aabb3f s(bx, by, bz, bx+2, by+2, bz+2); aabb3f m(bx-4.2, by-4.2, bz-4.2, bx-2.3, by-2.29, bz-2.29); v3f v(1./7, 1./7, 1./7); - f32 dtime; - UASSERT(axisAlignedCollision(s, m, v, 0, &dtime) == 0); + f32 dtime = 17.0f; + UASSERT(axisAlignedCollision(s, m, v, &dtime) == 0); UASSERT(fabs(dtime - 16.1) < 0.001); } { aabb3f s(bx, by, bz, bx+2, by+2, bz+2); aabb3f m(bx-4.2, by-4.2, bz-4.2, bx-2.29, by-2.3, bz-2.29); v3f v(1./7, 1./7, 1./7); - f32 dtime; - UASSERT(axisAlignedCollision(s, m, v, 0, &dtime) == 1); + f32 dtime = 17.0f; + UASSERT(axisAlignedCollision(s, m, v, &dtime) == 1); UASSERT(fabs(dtime - 16.1) < 0.001); } { aabb3f s(bx, by, bz, bx+2, by+2, bz+2); aabb3f m(bx-4.2, by-4.2, bz-4.2, bx-2.29, by-2.29, bz-2.3); v3f v(1./7, 1./7, 1./7); - f32 dtime; - UASSERT(axisAlignedCollision(s, m, v, 0, &dtime) == 2); + f32 dtime = 17.0f; + UASSERT(axisAlignedCollision(s, m, v, &dtime) == 2); UASSERT(fabs(dtime - 16.1) < 0.001); } } -- cgit v1.2.3 From 6d43736172f8459cb70219186ae003c56c389f2a Mon Sep 17 00:00:00 2001 From: Loic Blot Date: Fri, 10 Apr 2020 21:25:42 +0200 Subject: Move serveractiveobject & unitsao Move serverobject.{cpp,h} to server/serveractiveobject.{cpp,h} Move UnitSAO class to dedicated files --- build/android/jni/Android.mk | 2 +- src/CMakeLists.txt | 1 - src/collision.cpp | 2 +- src/content_sao.cpp | 296 ------------------------------ src/content_sao.h | 92 +--------- src/emerge.cpp | 1 - src/environment.cpp | 1 - src/inventorymanager.cpp | 2 +- src/mapgen/mapgen_v6.cpp | 1 - src/script/common/c_content.cpp | 2 +- src/script/cpp_api/s_base.cpp | 2 +- src/script/lua_api/l_object.cpp | 2 +- src/server.cpp | 2 +- src/server/CMakeLists.txt | 2 + src/server/activeobjectmgr.h | 2 +- src/server/serveractiveobject.cpp | 114 ++++++++++++ src/server/serveractiveobject.h | 265 +++++++++++++++++++++++++++ src/server/unit_sao.cpp | 318 +++++++++++++++++++++++++++++++++ src/server/unit_sao.h | 113 ++++++++++++ src/serverobject.cpp | 114 ------------ src/serverobject.h | 265 --------------------------- util/travis/clang-format-whitelist.txt | 6 +- 22 files changed, 823 insertions(+), 782 deletions(-) create mode 100644 src/server/serveractiveobject.cpp create mode 100644 src/server/serveractiveobject.h create mode 100644 src/server/unit_sao.cpp create mode 100644 src/server/unit_sao.h delete mode 100644 src/serverobject.cpp delete mode 100644 src/serverobject.h (limited to 'src/collision.cpp') diff --git a/build/android/jni/Android.mk b/build/android/jni/Android.mk index a2f32440a..32a16c174 100644 --- a/build/android/jni/Android.mk +++ b/build/android/jni/Android.mk @@ -259,7 +259,7 @@ LOCAL_SRC_FILES := \ jni/src/serverenvironment.cpp \ jni/src/serverlist.cpp \ jni/src/server/mods.cpp \ - jni/src/serverobject.cpp \ + jni/src/server/serveractiveobject.cpp \ jni/src/settings.cpp \ jni/src/staticobject.cpp \ jni/src/tileanimation.cpp \ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4b1d6d647..faa117d41 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -421,7 +421,6 @@ set(common_SRCS server.cpp serverenvironment.cpp serverlist.cpp - serverobject.cpp settings.cpp staticobject.cpp terminal_chat_console.cpp diff --git a/src/collision.cpp b/src/collision.cpp index 0d37ea436..d9fbd3202 100644 --- a/src/collision.cpp +++ b/src/collision.cpp @@ -28,7 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "client/localplayer.h" #endif #include "serverenvironment.h" -#include "serverobject.h" +#include "server/serveractiveobject.h" #include "util/timetaker.h" #include "profiler.h" diff --git a/src/content_sao.cpp b/src/content_sao.cpp index be7674f52..0d387b53a 100644 --- a/src/content_sao.cpp +++ b/src/content_sao.cpp @@ -106,302 +106,6 @@ private: // Prototype (registers item for deserialization) TestSAO proto_TestSAO(NULL, v3f(0,0,0)); -/* - UnitSAO - */ - -UnitSAO::UnitSAO(ServerEnvironment *env, v3f pos): - ServerActiveObject(env, pos) -{ - // Initialize something to armor groups - m_armor_groups["fleshy"] = 100; -} - -ServerActiveObject *UnitSAO::getParent() const -{ - if (!m_attachment_parent_id) - return nullptr; - // Check if the parent still exists - ServerActiveObject *obj = m_env->getActiveObject(m_attachment_parent_id); - - return obj; -} - -void UnitSAO::setArmorGroups(const ItemGroupList &armor_groups) -{ - m_armor_groups = armor_groups; - m_armor_groups_sent = false; -} - -const ItemGroupList &UnitSAO::getArmorGroups() const -{ - return m_armor_groups; -} - -void UnitSAO::setAnimation(v2f frame_range, float frame_speed, float frame_blend, bool frame_loop) -{ - // store these so they can be updated to clients - m_animation_range = frame_range; - m_animation_speed = frame_speed; - m_animation_blend = frame_blend; - m_animation_loop = frame_loop; - m_animation_sent = false; -} - -void UnitSAO::getAnimation(v2f *frame_range, float *frame_speed, float *frame_blend, bool *frame_loop) -{ - *frame_range = m_animation_range; - *frame_speed = m_animation_speed; - *frame_blend = m_animation_blend; - *frame_loop = m_animation_loop; -} - -void UnitSAO::setAnimationSpeed(float frame_speed) -{ - m_animation_speed = frame_speed; - m_animation_speed_sent = false; -} - -void UnitSAO::setBonePosition(const std::string &bone, v3f position, v3f rotation) -{ - // store these so they can be updated to clients - m_bone_position[bone] = core::vector2d(position, rotation); - m_bone_position_sent = false; -} - -void UnitSAO::getBonePosition(const std::string &bone, v3f *position, v3f *rotation) -{ - *position = m_bone_position[bone].X; - *rotation = m_bone_position[bone].Y; -} - -void UnitSAO::setAttachment(int parent_id, const std::string &bone, v3f position, v3f rotation) -{ - // Attachments need to be handled on both the server and client. - // If we just attach on the server, we can only copy the position of the parent. Attachments - // are still sent to clients at an interval so players might see them lagging, plus we can't - // read and attach to skeletal bones. - // If we just attach on the client, the server still sees the child at its original location. - // This breaks some things so we also give the server the most accurate representation - // even if players only see the client changes. - - int old_parent = m_attachment_parent_id; - m_attachment_parent_id = parent_id; - m_attachment_bone = bone; - m_attachment_position = position; - m_attachment_rotation = rotation; - m_attachment_sent = false; - - if (parent_id != old_parent) { - onDetach(old_parent); - onAttach(parent_id); - } -} - -void UnitSAO::getAttachment(int *parent_id, std::string *bone, v3f *position, - v3f *rotation) const -{ - *parent_id = m_attachment_parent_id; - *bone = m_attachment_bone; - *position = m_attachment_position; - *rotation = m_attachment_rotation; -} - -void UnitSAO::clearChildAttachments() -{ - for (int child_id : m_attachment_child_ids) { - // Child can be NULL if it was deleted earlier - if (ServerActiveObject *child = m_env->getActiveObject(child_id)) - child->setAttachment(0, "", v3f(0, 0, 0), v3f(0, 0, 0)); - } - m_attachment_child_ids.clear(); -} - -void UnitSAO::clearParentAttachment() -{ - ServerActiveObject *parent = nullptr; - if (m_attachment_parent_id) { - parent = m_env->getActiveObject(m_attachment_parent_id); - setAttachment(0, "", m_attachment_position, m_attachment_rotation); - } else { - setAttachment(0, "", v3f(0, 0, 0), v3f(0, 0, 0)); - } - // Do it - if (parent) - parent->removeAttachmentChild(m_id); -} - -void UnitSAO::addAttachmentChild(int child_id) -{ - m_attachment_child_ids.insert(child_id); -} - -void UnitSAO::removeAttachmentChild(int child_id) -{ - m_attachment_child_ids.erase(child_id); -} - -const std::unordered_set &UnitSAO::getAttachmentChildIds() const -{ - return m_attachment_child_ids; -} - -void UnitSAO::onAttach(int parent_id) -{ - if (!parent_id) - return; - - ServerActiveObject *parent = m_env->getActiveObject(parent_id); - - if (!parent || parent->isGone()) - return; // Do not try to notify soon gone parent - - if (parent->getType() == ACTIVEOBJECT_TYPE_LUAENTITY) { - // Call parent's on_attach field - m_env->getScriptIface()->luaentity_on_attach_child(parent_id, this); - } -} - -void UnitSAO::onDetach(int parent_id) -{ - if (!parent_id) - return; - - ServerActiveObject *parent = m_env->getActiveObject(parent_id); - if (getType() == ACTIVEOBJECT_TYPE_LUAENTITY) - m_env->getScriptIface()->luaentity_on_detach(m_id, parent); - - if (!parent || parent->isGone()) - return; // Do not try to notify soon gone parent - - if (parent->getType() == ACTIVEOBJECT_TYPE_LUAENTITY) - m_env->getScriptIface()->luaentity_on_detach_child(parent_id, this); -} - -ObjectProperties* UnitSAO::accessObjectProperties() -{ - return &m_prop; -} - -void UnitSAO::notifyObjectPropertiesModified() -{ - m_properties_sent = false; -} - -std::string UnitSAO::generateUpdateAttachmentCommand() const -{ - std::ostringstream os(std::ios::binary); - // command - writeU8(os, AO_CMD_ATTACH_TO); - // parameters - writeS16(os, m_attachment_parent_id); - os << serializeString(m_attachment_bone); - writeV3F32(os, m_attachment_position); - writeV3F32(os, m_attachment_rotation); - return os.str(); -} - -std::string UnitSAO::generateUpdateBonePositionCommand(const std::string &bone, - const v3f &position, const v3f &rotation) -{ - std::ostringstream os(std::ios::binary); - // command - writeU8(os, AO_CMD_SET_BONE_POSITION); - // parameters - os << serializeString(bone); - writeV3F32(os, position); - writeV3F32(os, rotation); - return os.str(); -} - - -std::string UnitSAO::generateUpdateAnimationSpeedCommand() const -{ - std::ostringstream os(std::ios::binary); - // command - writeU8(os, AO_CMD_SET_ANIMATION_SPEED); - // parameters - writeF32(os, m_animation_speed); - return os.str(); -} - -std::string UnitSAO::generateUpdateAnimationCommand() const -{ - std::ostringstream os(std::ios::binary); - // command - writeU8(os, AO_CMD_SET_ANIMATION); - // parameters - writeV2F32(os, m_animation_range); - writeF32(os, m_animation_speed); - writeF32(os, m_animation_blend); - // these are sent inverted so we get true when the server sends nothing - writeU8(os, !m_animation_loop); - return os.str(); -} - - -std::string UnitSAO::generateUpdateArmorGroupsCommand() const -{ - std::ostringstream os(std::ios::binary); - writeU8(os, AO_CMD_UPDATE_ARMOR_GROUPS); - writeU16(os, m_armor_groups.size()); - for (const auto &armor_group : m_armor_groups) { - os< &getAttachmentChildIds() const; - ServerActiveObject *getParent() const; - ObjectProperties* accessObjectProperties(); - void notifyObjectPropertiesModified(); - - std::string generateUpdateAttachmentCommand() const; - std::string generateUpdateAnimationSpeedCommand() const; - std::string generateUpdateAnimationCommand() const; - std::string generateUpdateArmorGroupsCommand() const; - static std::string generateUpdatePositionCommand(const v3f &position, const v3f &velocity, - const v3f &acceleration, const v3f &rotation, bool do_interpolate, - bool is_movement_end, f32 update_interval); - std::string generateSetPropertiesCommand(const ObjectProperties &prop) const; - void sendPunchCommand(); - static std::string generateUpdateBonePositionCommand(const std::string &bone, - const v3f &position, const v3f &rotation); - -protected: - u16 m_hp = 1; - - v3f m_rotation; - - bool m_properties_sent = true; - ObjectProperties m_prop; - - ItemGroupList m_armor_groups; - bool m_armor_groups_sent = false; - - v2f m_animation_range; - float m_animation_speed = 0.0f; - float m_animation_blend = 0.0f; - bool m_animation_loop = true; - bool m_animation_sent = false; - bool m_animation_speed_sent = false; - - // Stores position and rotation for each bone name - std::unordered_map> m_bone_position; - bool m_bone_position_sent = false; - - int m_attachment_parent_id = 0; - std::unordered_set m_attachment_child_ids; - std::string m_attachment_bone = ""; - v3f m_attachment_position; - v3f m_attachment_rotation; - bool m_attachment_sent = false; -private: - void onAttach(int parent_id); - void onDetach(int parent_id); - - std::string generatePunchCommand(u16 result_hp) const; -}; - /* LuaEntitySAO needs some internals exposed. */ diff --git a/src/emerge.cpp b/src/emerge.cpp index 4835c3fad..fe885447c 100644 --- a/src/emerge.cpp +++ b/src/emerge.cpp @@ -42,7 +42,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "profiler.h" #include "scripting_server.h" #include "server.h" -#include "serverobject.h" #include "settings.h" #include "voxel.h" diff --git a/src/environment.cpp b/src/environment.cpp index c997be3ff..6751f39e4 100644 --- a/src/environment.cpp +++ b/src/environment.cpp @@ -21,7 +21,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "environment.h" #include "collision.h" #include "raycast.h" -#include "serverobject.h" #include "scripting_server.h" #include "server.h" #include "daynightratio.h" diff --git a/src/inventorymanager.cpp b/src/inventorymanager.cpp index 5a24f95a4..b6f464901 100644 --- a/src/inventorymanager.cpp +++ b/src/inventorymanager.cpp @@ -22,7 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "log.h" #include "serverenvironment.h" #include "scripting_server.h" -#include "serverobject.h" +#include "server/serveractiveobject.h" #include "settings.h" #include "craftdef.h" #include "rollback_interface.h" diff --git a/src/mapgen/mapgen_v6.cpp b/src/mapgen/mapgen_v6.cpp index 8a863c044..f473f725d 100644 --- a/src/mapgen/mapgen_v6.cpp +++ b/src/mapgen/mapgen_v6.cpp @@ -27,7 +27,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "mapblock.h" #include "mapnode.h" #include "map.h" -//#include "serverobject.h" #include "content_sao.h" #include "nodedef.h" #include "voxelalgorithms.h" diff --git a/src/script/common/c_content.cpp b/src/script/common/c_content.cpp index accbb1a87..60f12052f 100644 --- a/src/script/common/c_content.cpp +++ b/src/script/common/c_content.cpp @@ -29,7 +29,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "server.h" #include "log.h" #include "tool.h" -#include "serverobject.h" +#include "server/serveractiveobject.h" #include "porting.h" #include "mapgen/mg_schematic.h" #include "noise.h" diff --git a/src/script/cpp_api/s_base.cpp b/src/script/cpp_api/s_base.cpp index f234a15d4..16c20eeae 100644 --- a/src/script/cpp_api/s_base.cpp +++ b/src/script/cpp_api/s_base.cpp @@ -22,7 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "cpp_api/s_security.h" #include "lua_api/l_object.h" #include "common/c_converter.h" -#include "serverobject.h" +#include "server/serveractiveobject.h" #include "filesys.h" #include "content/mods.h" #include "porting.h" diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp index 5cd978d73..1ea144a1c 100644 --- a/src/script/lua_api/l_object.cpp +++ b/src/script/lua_api/l_object.cpp @@ -27,7 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "common/c_content.h" #include "log.h" #include "tool.h" -#include "serverobject.h" +#include "server/serveractiveobject.h" #include "content_sao.h" #include "remoteplayer.h" #include "server.h" diff --git a/src/server.cpp b/src/server.cpp index 062fe0798..529466f6b 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -34,7 +34,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "version.h" #include "filesys.h" #include "mapblock.h" -#include "serverobject.h" +#include "server/serveractiveobject.h" #include "settings.h" #include "profiler.h" #include "log.h" diff --git a/src/server/CMakeLists.txt b/src/server/CMakeLists.txt index e964c69ff..9fa5ed9fa 100644 --- a/src/server/CMakeLists.txt +++ b/src/server/CMakeLists.txt @@ -1,4 +1,6 @@ set(server_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/activeobjectmgr.cpp ${CMAKE_CURRENT_SOURCE_DIR}/mods.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/serveractiveobject.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/unit_sao.cpp PARENT_SCOPE) diff --git a/src/server/activeobjectmgr.h b/src/server/activeobjectmgr.h index a502ac6ed..5fea1bea6 100644 --- a/src/server/activeobjectmgr.h +++ b/src/server/activeobjectmgr.h @@ -22,7 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include #include "../activeobjectmgr.h" -#include "serverobject.h" +#include "serveractiveobject.h" namespace server { diff --git a/src/server/serveractiveobject.cpp b/src/server/serveractiveobject.cpp new file mode 100644 index 000000000..3aa78c7d5 --- /dev/null +++ b/src/server/serveractiveobject.cpp @@ -0,0 +1,114 @@ +/* +Minetest +Copyright (C) 2010-2013 celeron55, Perttu Ahola + +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 "serveractiveobject.h" +#include +#include "inventory.h" +#include "constants.h" // BS +#include "log.h" + +ServerActiveObject::ServerActiveObject(ServerEnvironment *env, v3f pos): + ActiveObject(0), + m_env(env), + m_base_position(pos) +{ +} + +ServerActiveObject* ServerActiveObject::create(ActiveObjectType type, + ServerEnvironment *env, u16 id, v3f pos, + const std::string &data) +{ + // Find factory function + std::map::iterator n; + n = m_types.find(type); + if(n == m_types.end()) { + // These are 0.3 entity types, return without error. + if (ACTIVEOBJECT_TYPE_ITEM <= type && type <= ACTIVEOBJECT_TYPE_MOBV2) { + return NULL; + } + + // If factory is not found, just return. + warningstream<<"ServerActiveObject: No factory for type=" + <second; + ServerActiveObject *object = (*f)(env, pos, data); + return object; +} + +void ServerActiveObject::registerType(u16 type, Factory f) +{ + std::map::iterator n; + n = m_types.find(type); + if(n != m_types.end()) + return; + m_types[type] = f; +} + +float ServerActiveObject::getMinimumSavedMovement() +{ + return 2.0*BS; +} + +ItemStack ServerActiveObject::getWieldedItem(ItemStack *selected, ItemStack *hand) const +{ + *selected = ItemStack(); + if (hand) + *hand = ItemStack(); + + return ItemStack(); +} + +bool ServerActiveObject::setWieldedItem(const ItemStack &item) +{ + return false; +} + +std::string ServerActiveObject::generateUpdateInfantCommand(u16 infant_id, u16 protocol_version) +{ + std::ostringstream os(std::ios::binary); + // command + writeU8(os, AO_CMD_SPAWN_INFANT); + // parameters + writeU16(os, infant_id); + writeU8(os, getSendType()); + os << serializeLongString(getClientInitializationData(protocol_version)); + return os.str(); +} + +std::string ServerActiveObject::generateUpdateNametagAttributesCommand(const video::SColor &color) const +{ + std::ostringstream os(std::ios::binary); + // command + writeU8(os, AO_CMD_UPDATE_NAMETAG_ATTRIBUTES); + // parameters + writeU8(os, 1); // version for forward compatibility + writeARGB8(os, color); + return os.str(); +} + +void ServerActiveObject::dumpAOMessagesToQueue(std::queue &queue) +{ + while (!m_messages_out.empty()) { + queue.push(m_messages_out.front()); + m_messages_out.pop(); + } +} \ No newline at end of file diff --git a/src/server/serveractiveobject.h b/src/server/serveractiveobject.h new file mode 100644 index 000000000..2e013a6b6 --- /dev/null +++ b/src/server/serveractiveobject.h @@ -0,0 +1,265 @@ +/* +Minetest +Copyright (C) 2010-2013 celeron55, Perttu Ahola + +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. +*/ + +#pragma once + +#include +#include "irrlichttypes_bloated.h" +#include "activeobject.h" +#include "inventorymanager.h" +#include "itemgroup.h" +#include "util/container.h" + +/* + +Some planning +------------- + +* Server environment adds an active object, which gets the id 1 +* The active object list is scanned for each client once in a while, + and it finds out what objects have been added that are not known + by the client yet. This scan is initiated by the Server class and + the result ends up directly to the server. +* A network packet is created with the info and sent to the client. +* Environment converts objects to static data and static data to + objects, based on how close players are to them. + +*/ + +class ServerEnvironment; +struct ItemStack; +struct ToolCapabilities; +struct ObjectProperties; +struct PlayerHPChangeReason; + +class ServerActiveObject : public ActiveObject +{ +public: + /* + NOTE: m_env can be NULL, but step() isn't called if it is. + Prototypes are used that way. + */ + ServerActiveObject(ServerEnvironment *env, v3f pos); + virtual ~ServerActiveObject() = default; + + virtual ActiveObjectType getSendType() const + { return getType(); } + + // Called after id has been set and has been inserted in environment + virtual void addedToEnvironment(u32 dtime_s){}; + // Called before removing from environment + virtual void removingFromEnvironment(){}; + // Returns true if object's deletion is the job of the + // environment + virtual bool environmentDeletes() const + { return true; } + + // Create a certain type of ServerActiveObject + static ServerActiveObject* create(ActiveObjectType type, + ServerEnvironment *env, u16 id, v3f pos, + const std::string &data); + + /* + Some simple getters/setters + */ + v3f getBasePosition() const { return m_base_position; } + void setBasePosition(v3f pos){ m_base_position = pos; } + ServerEnvironment* getEnv(){ return m_env; } + + /* + Some more dynamic interface + */ + + virtual void setPos(const v3f &pos) + { setBasePosition(pos); } + // continuous: if true, object does not stop immediately at pos + virtual void moveTo(v3f pos, bool continuous) + { setBasePosition(pos); } + // If object has moved less than this and data has not changed, + // saving to disk may be omitted + virtual float getMinimumSavedMovement(); + + virtual std::string getDescription(){return "SAO";} + + /* + Step object in time. + Messages added to messages are sent to client over network. + + send_recommended: + True at around 5-10 times a second, same for all objects. + This is used to let objects send most of the data at the + same time so that the data can be combined in a single + packet. + */ + virtual void step(float dtime, bool send_recommended){} + + /* + The return value of this is passed to the client-side object + when it is created + */ + virtual std::string getClientInitializationData(u16 protocol_version) {return "";} + + /* + The return value of this is passed to the server-side object + when it is created (converted from static to active - actually + the data is the static form) + */ + virtual void getStaticData(std::string *result) const + { + assert(isStaticAllowed()); + *result = ""; + } + /* + Return false in here to never save and instead remove object + on unload. getStaticData() will not be called in that case. + */ + virtual bool isStaticAllowed() const + {return true;} + + // Returns tool wear + virtual u16 punch(v3f dir, + const ToolCapabilities *toolcap = nullptr, + ServerActiveObject *puncher = nullptr, + float time_from_last_punch = 1000000.0f) + { return 0; } + virtual void rightClick(ServerActiveObject *clicker) + {} + virtual void setHP(s32 hp, const PlayerHPChangeReason &reason) + {} + virtual u16 getHP() const + { return 0; } + + virtual void setArmorGroups(const ItemGroupList &armor_groups) + {} + virtual const ItemGroupList &getArmorGroups() const + { static ItemGroupList rv; return rv; } + virtual void setPhysicsOverride(float physics_override_speed, float physics_override_jump, float physics_override_gravity) + {} + virtual void setAnimation(v2f frames, float frame_speed, float frame_blend, bool frame_loop) + {} + virtual void getAnimation(v2f *frames, float *frame_speed, float *frame_blend, bool *frame_loop) + {} + virtual void setAnimationSpeed(float frame_speed) + {} + virtual void setBonePosition(const std::string &bone, v3f position, v3f rotation) + {} + virtual void getBonePosition(const std::string &bone, v3f *position, v3f *lotation) + {} + virtual const std::unordered_set &getAttachmentChildIds() const + { static std::unordered_set rv; return rv; } + virtual ServerActiveObject *getParent() const { return nullptr; } + virtual ObjectProperties* accessObjectProperties() + { return NULL; } + virtual void notifyObjectPropertiesModified() + {} + + // Inventory and wielded item + virtual Inventory *getInventory() const + { return NULL; } + virtual InventoryLocation getInventoryLocation() const + { return InventoryLocation(); } + virtual void setInventoryModified() + {} + virtual std::string getWieldList() const + { return ""; } + virtual u16 getWieldIndex() const + { return 0; } + virtual ItemStack getWieldedItem(ItemStack *selected, + ItemStack *hand = nullptr) const; + virtual bool setWieldedItem(const ItemStack &item); + inline void attachParticleSpawner(u32 id) + { + m_attached_particle_spawners.insert(id); + } + inline void detachParticleSpawner(u32 id) + { + m_attached_particle_spawners.erase(id); + } + + std::string generateUpdateInfantCommand(u16 infant_id, u16 protocol_version); + std::string generateUpdateNametagAttributesCommand(const video::SColor &color) const; + + void dumpAOMessagesToQueue(std::queue &queue); + + /* + Number of players which know about this object. Object won't be + deleted until this is 0 to keep the id preserved for the right + object. + */ + u16 m_known_by_count = 0; + + /* + - Whether this object is to be removed when nobody knows about + it anymore. + - Removal is delayed to preserve the id for the time during which + it could be confused to some other object by some client. + - This is usually set to true by the step() method when the object wants + to be deleted but can be set by anything else too. + */ + bool m_pending_removal = false; + + /* + Same purpose as m_pending_removal but for deactivation. + deactvation = save static data in block, remove active object + + If this is set alongside with m_pending_removal, removal takes + priority. + */ + bool m_pending_deactivation = false; + + /* + A getter that unifies the above to answer the question: + "Can the environment still interact with this object?" + */ + inline bool isGone() const + { return m_pending_removal || m_pending_deactivation; } + + /* + Whether the object's static data has been stored to a block + */ + bool m_static_exists = false; + /* + The block from which the object was loaded from, and in which + a copy of the static data resides. + */ + v3s16 m_static_block = v3s16(1337,1337,1337); + +protected: + virtual void onAttach(int parent_id) {} + virtual void onDetach(int parent_id) {} + + // Used for creating objects based on type + typedef ServerActiveObject* (*Factory) + (ServerEnvironment *env, v3f pos, + const std::string &data); + static void registerType(u16 type, Factory f); + + ServerEnvironment *m_env; + v3f m_base_position; + std::unordered_set m_attached_particle_spawners; + + /* + Queue of messages to be sent to the client + */ + std::queue m_messages_out; + +private: + // Used for creating objects based on type + static std::map m_types; +}; diff --git a/src/server/unit_sao.cpp b/src/server/unit_sao.cpp new file mode 100644 index 000000000..66be67522 --- /dev/null +++ b/src/server/unit_sao.cpp @@ -0,0 +1,318 @@ +/* +Minetest +Copyright (C) 2010-2013 celeron55, Perttu Ahola +Copyright (C) 2013-2020 Minetest core developers & community + +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 "unit_sao.h" +#include "scripting_server.h" +#include "serverenvironment.h" + +/* + UnitSAO + */ + +UnitSAO::UnitSAO(ServerEnvironment *env, v3f pos): + ServerActiveObject(env, pos) +{ + // Initialize something to armor groups + m_armor_groups["fleshy"] = 100; +} + +ServerActiveObject *UnitSAO::getParent() const +{ + if (!m_attachment_parent_id) + return nullptr; + // Check if the parent still exists + ServerActiveObject *obj = m_env->getActiveObject(m_attachment_parent_id); + + return obj; +} + +void UnitSAO::setArmorGroups(const ItemGroupList &armor_groups) +{ + m_armor_groups = armor_groups; + m_armor_groups_sent = false; +} + +const ItemGroupList &UnitSAO::getArmorGroups() const +{ + return m_armor_groups; +} + +void UnitSAO::setAnimation(v2f frame_range, float frame_speed, float frame_blend, bool frame_loop) +{ + // store these so they can be updated to clients + m_animation_range = frame_range; + m_animation_speed = frame_speed; + m_animation_blend = frame_blend; + m_animation_loop = frame_loop; + m_animation_sent = false; +} + +void UnitSAO::getAnimation(v2f *frame_range, float *frame_speed, float *frame_blend, bool *frame_loop) +{ + *frame_range = m_animation_range; + *frame_speed = m_animation_speed; + *frame_blend = m_animation_blend; + *frame_loop = m_animation_loop; +} + +void UnitSAO::setAnimationSpeed(float frame_speed) +{ + m_animation_speed = frame_speed; + m_animation_speed_sent = false; +} + +void UnitSAO::setBonePosition(const std::string &bone, v3f position, v3f rotation) +{ + // store these so they can be updated to clients + m_bone_position[bone] = core::vector2d(position, rotation); + m_bone_position_sent = false; +} + +void UnitSAO::getBonePosition(const std::string &bone, v3f *position, v3f *rotation) +{ + *position = m_bone_position[bone].X; + *rotation = m_bone_position[bone].Y; +} + +void UnitSAO::setAttachment(int parent_id, const std::string &bone, v3f position, v3f rotation) +{ + // Attachments need to be handled on both the server and client. + // If we just attach on the server, we can only copy the position of the parent. Attachments + // are still sent to clients at an interval so players might see them lagging, plus we can't + // read and attach to skeletal bones. + // If we just attach on the client, the server still sees the child at its original location. + // This breaks some things so we also give the server the most accurate representation + // even if players only see the client changes. + + int old_parent = m_attachment_parent_id; + m_attachment_parent_id = parent_id; + m_attachment_bone = bone; + m_attachment_position = position; + m_attachment_rotation = rotation; + m_attachment_sent = false; + + if (parent_id != old_parent) { + onDetach(old_parent); + onAttach(parent_id); + } +} + +void UnitSAO::getAttachment(int *parent_id, std::string *bone, v3f *position, + v3f *rotation) const +{ + *parent_id = m_attachment_parent_id; + *bone = m_attachment_bone; + *position = m_attachment_position; + *rotation = m_attachment_rotation; +} + +void UnitSAO::clearChildAttachments() +{ + for (int child_id : m_attachment_child_ids) { + // Child can be NULL if it was deleted earlier + if (ServerActiveObject *child = m_env->getActiveObject(child_id)) + child->setAttachment(0, "", v3f(0, 0, 0), v3f(0, 0, 0)); + } + m_attachment_child_ids.clear(); +} + +void UnitSAO::clearParentAttachment() +{ + ServerActiveObject *parent = nullptr; + if (m_attachment_parent_id) { + parent = m_env->getActiveObject(m_attachment_parent_id); + setAttachment(0, "", m_attachment_position, m_attachment_rotation); + } else { + setAttachment(0, "", v3f(0, 0, 0), v3f(0, 0, 0)); + } + // Do it + if (parent) + parent->removeAttachmentChild(m_id); +} + +void UnitSAO::addAttachmentChild(int child_id) +{ + m_attachment_child_ids.insert(child_id); +} + +void UnitSAO::removeAttachmentChild(int child_id) +{ + m_attachment_child_ids.erase(child_id); +} + +const std::unordered_set &UnitSAO::getAttachmentChildIds() const +{ + return m_attachment_child_ids; +} + +void UnitSAO::onAttach(int parent_id) +{ + if (!parent_id) + return; + + ServerActiveObject *parent = m_env->getActiveObject(parent_id); + + if (!parent || parent->isGone()) + return; // Do not try to notify soon gone parent + + if (parent->getType() == ACTIVEOBJECT_TYPE_LUAENTITY) { + // Call parent's on_attach field + m_env->getScriptIface()->luaentity_on_attach_child(parent_id, this); + } +} + +void UnitSAO::onDetach(int parent_id) +{ + if (!parent_id) + return; + + ServerActiveObject *parent = m_env->getActiveObject(parent_id); + if (getType() == ACTIVEOBJECT_TYPE_LUAENTITY) + m_env->getScriptIface()->luaentity_on_detach(m_id, parent); + + if (!parent || parent->isGone()) + return; // Do not try to notify soon gone parent + + if (parent->getType() == ACTIVEOBJECT_TYPE_LUAENTITY) + m_env->getScriptIface()->luaentity_on_detach_child(parent_id, this); +} + +ObjectProperties* UnitSAO::accessObjectProperties() +{ + return &m_prop; +} + +void UnitSAO::notifyObjectPropertiesModified() +{ + m_properties_sent = false; +} + +std::string UnitSAO::generateUpdateAttachmentCommand() const +{ + std::ostringstream os(std::ios::binary); + // command + writeU8(os, AO_CMD_ATTACH_TO); + // parameters + writeS16(os, m_attachment_parent_id); + os << serializeString(m_attachment_bone); + writeV3F32(os, m_attachment_position); + writeV3F32(os, m_attachment_rotation); + return os.str(); +} + +std::string UnitSAO::generateUpdateBonePositionCommand(const std::string &bone, + const v3f &position, const v3f &rotation) +{ + std::ostringstream os(std::ios::binary); + // command + writeU8(os, AO_CMD_SET_BONE_POSITION); + // parameters + os << serializeString(bone); + writeV3F32(os, position); + writeV3F32(os, rotation); + return os.str(); +} + + +std::string UnitSAO::generateUpdateAnimationSpeedCommand() const +{ + std::ostringstream os(std::ios::binary); + // command + writeU8(os, AO_CMD_SET_ANIMATION_SPEED); + // parameters + writeF32(os, m_animation_speed); + return os.str(); +} + +std::string UnitSAO::generateUpdateAnimationCommand() const +{ + std::ostringstream os(std::ios::binary); + // command + writeU8(os, AO_CMD_SET_ANIMATION); + // parameters + writeV2F32(os, m_animation_range); + writeF32(os, m_animation_speed); + writeF32(os, m_animation_blend); + // these are sent inverted so we get true when the server sends nothing + writeU8(os, !m_animation_loop); + return os.str(); +} + + +std::string UnitSAO::generateUpdateArmorGroupsCommand() const +{ + std::ostringstream os(std::ios::binary); + writeU8(os, AO_CMD_UPDATE_ARMOR_GROUPS); + writeU16(os, m_armor_groups.size()); + for (const auto &armor_group : m_armor_groups) { + os< +Copyright (C) 2013-2020 Minetest core developers & community + +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. +*/ + +#pragma once + +#include "object_properties.h" +#include "serveractiveobject.h" + +class UnitSAO: public ServerActiveObject +{ +public: + UnitSAO(ServerEnvironment *env, v3f pos); + virtual ~UnitSAO() = default; + + void setRotation(v3f rotation) { m_rotation = rotation; } + const v3f &getRotation() const { return m_rotation; } + v3f getRadRotation() { return m_rotation * core::DEGTORAD; } + + // Deprecated + f32 getRadYawDep() const { return (m_rotation.Y + 90.) * core::DEGTORAD; } + + u16 getHP() const { return m_hp; } + // Use a function, if isDead can be defined by other conditions + bool isDead() const { return m_hp == 0; } + + inline bool isAttached() const + { return getParent(); } + + inline bool isImmortal() const + { return itemgroup_get(getArmorGroups(), "immortal"); } + + void setArmorGroups(const ItemGroupList &armor_groups); + const ItemGroupList &getArmorGroups() const; + void setAnimation(v2f frame_range, float frame_speed, float frame_blend, bool frame_loop); + void getAnimation(v2f *frame_range, float *frame_speed, float *frame_blend, bool *frame_loop); + void setAnimationSpeed(float frame_speed); + void setBonePosition(const std::string &bone, v3f position, v3f rotation); + void getBonePosition(const std::string &bone, v3f *position, v3f *rotation); + void setAttachment(int parent_id, const std::string &bone, v3f position, v3f rotation); + void getAttachment(int *parent_id, std::string *bone, v3f *position, + v3f *rotation) const; + void clearChildAttachments(); + void clearParentAttachment(); + void addAttachmentChild(int child_id); + void removeAttachmentChild(int child_id); + const std::unordered_set &getAttachmentChildIds() const; + ServerActiveObject *getParent() const; + ObjectProperties* accessObjectProperties(); + void notifyObjectPropertiesModified(); + + std::string generateUpdateAttachmentCommand() const; + std::string generateUpdateAnimationSpeedCommand() const; + std::string generateUpdateAnimationCommand() const; + std::string generateUpdateArmorGroupsCommand() const; + static std::string generateUpdatePositionCommand(const v3f &position, const v3f &velocity, + const v3f &acceleration, const v3f &rotation, bool do_interpolate, + bool is_movement_end, f32 update_interval); + std::string generateSetPropertiesCommand(const ObjectProperties &prop) const; + void sendPunchCommand(); + static std::string generateUpdateBonePositionCommand(const std::string &bone, + const v3f &position, const v3f &rotation); + +protected: + u16 m_hp = 1; + + v3f m_rotation; + + bool m_properties_sent = true; + ObjectProperties m_prop; + + ItemGroupList m_armor_groups; + bool m_armor_groups_sent = false; + + v2f m_animation_range; + float m_animation_speed = 0.0f; + float m_animation_blend = 0.0f; + bool m_animation_loop = true; + bool m_animation_sent = false; + bool m_animation_speed_sent = false; + + // Stores position and rotation for each bone name + std::unordered_map> m_bone_position; + bool m_bone_position_sent = false; + + int m_attachment_parent_id = 0; + std::unordered_set m_attachment_child_ids; + std::string m_attachment_bone = ""; + v3f m_attachment_position; + v3f m_attachment_rotation; + bool m_attachment_sent = false; +private: + void onAttach(int parent_id); + void onDetach(int parent_id); + + std::string generatePunchCommand(u16 result_hp) const; +}; diff --git a/src/serverobject.cpp b/src/serverobject.cpp deleted file mode 100644 index 119a41b7b..000000000 --- a/src/serverobject.cpp +++ /dev/null @@ -1,114 +0,0 @@ -/* -Minetest -Copyright (C) 2010-2013 celeron55, Perttu Ahola - -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 "serverobject.h" -#include -#include "inventory.h" -#include "constants.h" // BS -#include "log.h" - -ServerActiveObject::ServerActiveObject(ServerEnvironment *env, v3f pos): - ActiveObject(0), - m_env(env), - m_base_position(pos) -{ -} - -ServerActiveObject* ServerActiveObject::create(ActiveObjectType type, - ServerEnvironment *env, u16 id, v3f pos, - const std::string &data) -{ - // Find factory function - std::map::iterator n; - n = m_types.find(type); - if(n == m_types.end()) { - // These are 0.3 entity types, return without error. - if (ACTIVEOBJECT_TYPE_ITEM <= type && type <= ACTIVEOBJECT_TYPE_MOBV2) { - return NULL; - } - - // If factory is not found, just return. - warningstream<<"ServerActiveObject: No factory for type=" - <second; - ServerActiveObject *object = (*f)(env, pos, data); - return object; -} - -void ServerActiveObject::registerType(u16 type, Factory f) -{ - std::map::iterator n; - n = m_types.find(type); - if(n != m_types.end()) - return; - m_types[type] = f; -} - -float ServerActiveObject::getMinimumSavedMovement() -{ - return 2.0*BS; -} - -ItemStack ServerActiveObject::getWieldedItem(ItemStack *selected, ItemStack *hand) const -{ - *selected = ItemStack(); - if (hand) - *hand = ItemStack(); - - return ItemStack(); -} - -bool ServerActiveObject::setWieldedItem(const ItemStack &item) -{ - return false; -} - -std::string ServerActiveObject::generateUpdateInfantCommand(u16 infant_id, u16 protocol_version) -{ - std::ostringstream os(std::ios::binary); - // command - writeU8(os, AO_CMD_SPAWN_INFANT); - // parameters - writeU16(os, infant_id); - writeU8(os, getSendType()); - os << serializeLongString(getClientInitializationData(protocol_version)); - return os.str(); -} - -std::string ServerActiveObject::generateUpdateNametagAttributesCommand(const video::SColor &color) const -{ - std::ostringstream os(std::ios::binary); - // command - writeU8(os, AO_CMD_UPDATE_NAMETAG_ATTRIBUTES); - // parameters - writeU8(os, 1); // version for forward compatibility - writeARGB8(os, color); - return os.str(); -} - -void ServerActiveObject::dumpAOMessagesToQueue(std::queue &queue) -{ - while (!m_messages_out.empty()) { - queue.push(m_messages_out.front()); - m_messages_out.pop(); - } -} \ No newline at end of file diff --git a/src/serverobject.h b/src/serverobject.h deleted file mode 100644 index 2e013a6b6..000000000 --- a/src/serverobject.h +++ /dev/null @@ -1,265 +0,0 @@ -/* -Minetest -Copyright (C) 2010-2013 celeron55, Perttu Ahola - -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. -*/ - -#pragma once - -#include -#include "irrlichttypes_bloated.h" -#include "activeobject.h" -#include "inventorymanager.h" -#include "itemgroup.h" -#include "util/container.h" - -/* - -Some planning -------------- - -* Server environment adds an active object, which gets the id 1 -* The active object list is scanned for each client once in a while, - and it finds out what objects have been added that are not known - by the client yet. This scan is initiated by the Server class and - the result ends up directly to the server. -* A network packet is created with the info and sent to the client. -* Environment converts objects to static data and static data to - objects, based on how close players are to them. - -*/ - -class ServerEnvironment; -struct ItemStack; -struct ToolCapabilities; -struct ObjectProperties; -struct PlayerHPChangeReason; - -class ServerActiveObject : public ActiveObject -{ -public: - /* - NOTE: m_env can be NULL, but step() isn't called if it is. - Prototypes are used that way. - */ - ServerActiveObject(ServerEnvironment *env, v3f pos); - virtual ~ServerActiveObject() = default; - - virtual ActiveObjectType getSendType() const - { return getType(); } - - // Called after id has been set and has been inserted in environment - virtual void addedToEnvironment(u32 dtime_s){}; - // Called before removing from environment - virtual void removingFromEnvironment(){}; - // Returns true if object's deletion is the job of the - // environment - virtual bool environmentDeletes() const - { return true; } - - // Create a certain type of ServerActiveObject - static ServerActiveObject* create(ActiveObjectType type, - ServerEnvironment *env, u16 id, v3f pos, - const std::string &data); - - /* - Some simple getters/setters - */ - v3f getBasePosition() const { return m_base_position; } - void setBasePosition(v3f pos){ m_base_position = pos; } - ServerEnvironment* getEnv(){ return m_env; } - - /* - Some more dynamic interface - */ - - virtual void setPos(const v3f &pos) - { setBasePosition(pos); } - // continuous: if true, object does not stop immediately at pos - virtual void moveTo(v3f pos, bool continuous) - { setBasePosition(pos); } - // If object has moved less than this and data has not changed, - // saving to disk may be omitted - virtual float getMinimumSavedMovement(); - - virtual std::string getDescription(){return "SAO";} - - /* - Step object in time. - Messages added to messages are sent to client over network. - - send_recommended: - True at around 5-10 times a second, same for all objects. - This is used to let objects send most of the data at the - same time so that the data can be combined in a single - packet. - */ - virtual void step(float dtime, bool send_recommended){} - - /* - The return value of this is passed to the client-side object - when it is created - */ - virtual std::string getClientInitializationData(u16 protocol_version) {return "";} - - /* - The return value of this is passed to the server-side object - when it is created (converted from static to active - actually - the data is the static form) - */ - virtual void getStaticData(std::string *result) const - { - assert(isStaticAllowed()); - *result = ""; - } - /* - Return false in here to never save and instead remove object - on unload. getStaticData() will not be called in that case. - */ - virtual bool isStaticAllowed() const - {return true;} - - // Returns tool wear - virtual u16 punch(v3f dir, - const ToolCapabilities *toolcap = nullptr, - ServerActiveObject *puncher = nullptr, - float time_from_last_punch = 1000000.0f) - { return 0; } - virtual void rightClick(ServerActiveObject *clicker) - {} - virtual void setHP(s32 hp, const PlayerHPChangeReason &reason) - {} - virtual u16 getHP() const - { return 0; } - - virtual void setArmorGroups(const ItemGroupList &armor_groups) - {} - virtual const ItemGroupList &getArmorGroups() const - { static ItemGroupList rv; return rv; } - virtual void setPhysicsOverride(float physics_override_speed, float physics_override_jump, float physics_override_gravity) - {} - virtual void setAnimation(v2f frames, float frame_speed, float frame_blend, bool frame_loop) - {} - virtual void getAnimation(v2f *frames, float *frame_speed, float *frame_blend, bool *frame_loop) - {} - virtual void setAnimationSpeed(float frame_speed) - {} - virtual void setBonePosition(const std::string &bone, v3f position, v3f rotation) - {} - virtual void getBonePosition(const std::string &bone, v3f *position, v3f *lotation) - {} - virtual const std::unordered_set &getAttachmentChildIds() const - { static std::unordered_set rv; return rv; } - virtual ServerActiveObject *getParent() const { return nullptr; } - virtual ObjectProperties* accessObjectProperties() - { return NULL; } - virtual void notifyObjectPropertiesModified() - {} - - // Inventory and wielded item - virtual Inventory *getInventory() const - { return NULL; } - virtual InventoryLocation getInventoryLocation() const - { return InventoryLocation(); } - virtual void setInventoryModified() - {} - virtual std::string getWieldList() const - { return ""; } - virtual u16 getWieldIndex() const - { return 0; } - virtual ItemStack getWieldedItem(ItemStack *selected, - ItemStack *hand = nullptr) const; - virtual bool setWieldedItem(const ItemStack &item); - inline void attachParticleSpawner(u32 id) - { - m_attached_particle_spawners.insert(id); - } - inline void detachParticleSpawner(u32 id) - { - m_attached_particle_spawners.erase(id); - } - - std::string generateUpdateInfantCommand(u16 infant_id, u16 protocol_version); - std::string generateUpdateNametagAttributesCommand(const video::SColor &color) const; - - void dumpAOMessagesToQueue(std::queue &queue); - - /* - Number of players which know about this object. Object won't be - deleted until this is 0 to keep the id preserved for the right - object. - */ - u16 m_known_by_count = 0; - - /* - - Whether this object is to be removed when nobody knows about - it anymore. - - Removal is delayed to preserve the id for the time during which - it could be confused to some other object by some client. - - This is usually set to true by the step() method when the object wants - to be deleted but can be set by anything else too. - */ - bool m_pending_removal = false; - - /* - Same purpose as m_pending_removal but for deactivation. - deactvation = save static data in block, remove active object - - If this is set alongside with m_pending_removal, removal takes - priority. - */ - bool m_pending_deactivation = false; - - /* - A getter that unifies the above to answer the question: - "Can the environment still interact with this object?" - */ - inline bool isGone() const - { return m_pending_removal || m_pending_deactivation; } - - /* - Whether the object's static data has been stored to a block - */ - bool m_static_exists = false; - /* - The block from which the object was loaded from, and in which - a copy of the static data resides. - */ - v3s16 m_static_block = v3s16(1337,1337,1337); - -protected: - virtual void onAttach(int parent_id) {} - virtual void onDetach(int parent_id) {} - - // Used for creating objects based on type - typedef ServerActiveObject* (*Factory) - (ServerEnvironment *env, v3f pos, - const std::string &data); - static void registerType(u16 type, Factory f); - - ServerEnvironment *m_env; - v3f m_base_position; - std::unordered_set m_attached_particle_spawners; - - /* - Queue of messages to be sent to the client - */ - std::queue m_messages_out; - -private: - // Used for creating objects based on type - static std::map m_types; -}; diff --git a/util/travis/clang-format-whitelist.txt b/util/travis/clang-format-whitelist.txt index 7b2fd8236..816ec2c59 100644 --- a/util/travis/clang-format-whitelist.txt +++ b/util/travis/clang-format-whitelist.txt @@ -402,16 +402,14 @@ src/script/scripting_server.cpp src/script/scripting_server.h src/serialization.cpp src/serialization.h -src/serveractiveobjectmap.cpp -src/serveractiveobjectmap.h src/server.cpp src/serverenvironment.cpp src/serverenvironment.h src/server.h src/serverlist.cpp src/serverlist.h -src/serverobject.cpp -src/serverobject.h +src/server/serveractiveobject.cpp +src/server/serveractiveobject.h src/settings.cpp src/settings.h src/settings_translation_file.cpp -- cgit v1.2.3 From e8ac5a31cf12afcfddf8e3ed31e8038930edb06f Mon Sep 17 00:00:00 2001 From: Loïc Blot Date: Thu, 16 Apr 2020 08:25:48 +0200 Subject: 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 --- src/collision.cpp | 20 +++++++++++--------- src/script/lua_api/l_env.cpp | 24 ++++++++++++------------ src/server/activeobjectmgr.cpp | 10 ++++++---- src/server/activeobjectmgr.h | 5 +++-- src/serverenvironment.cpp | 12 +++++------- src/serverenvironment.h | 5 +++-- src/unittest/test_serveractiveobjectmgr.cpp | 18 +++++++++++++++--- 7 files changed, 55 insertions(+), 39 deletions(-) (limited to 'src/collision.cpp') diff --git a/src/collision.cpp b/src/collision.cpp index d9fbd3202..6d24bc699 100644 --- a/src/collision.cpp +++ b/src/collision.cpp @@ -360,17 +360,19 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef, // Calculate distance by speed, add own extent and 1.5m of tolerance f32 distance = speed_f->getLength() * dtime + box_0.getExtent().getLength() + 1.5f * BS; - std::vector s_objects; - s_env->getObjectsInsideRadius(s_objects, *pos_f, distance); - for (u16 obj_id : s_objects) { - ServerActiveObject *current = s_env->getActiveObject(obj_id); - - if (!self || (self != current && - self != current->getParent())) { - objects.push_back((ActiveObject*)current); + // search for objects which are not us, or we are not its parent + // we directly use the callback to populate the result to prevent + // a useless result loop here + auto include_obj_cb = [self, &objects] (ServerActiveObject *obj) { + if (!self || (self != obj && self != obj->getParent())) { + objects.push_back((ActiveObject *)obj); } - } + return false; + }; + + std::vector s_objects; + s_env->getObjectsInsideRadius(s_objects, *pos_f, distance, include_obj_cb); } } diff --git a/src/script/lua_api/l_env.cpp b/src/script/lua_api/l_env.cpp index 8c45a1510..831464d3b 100644 --- a/src/script/lua_api/l_env.cpp +++ b/src/script/lua_api/l_env.cpp @@ -681,22 +681,22 @@ int ModApiEnvMod::l_get_player_by_name(lua_State *L) int ModApiEnvMod::l_get_objects_inside_radius(lua_State *L) { GET_ENV_PTR; + ScriptApiBase *script = getScriptApiBase(L); // Do it v3f pos = checkFloatPos(L, 1); float radius = readParam(L, 2) * BS; - std::vector ids; - env->getObjectsInsideRadius(ids, pos, radius); - ScriptApiBase *script = getScriptApiBase(L); - lua_createtable(L, ids.size(), 0); - std::vector::const_iterator iter = ids.begin(); - for(u32 i = 0; iter != ids.end(); ++iter) { - ServerActiveObject *obj = env->getActiveObject(*iter); - if (!obj->isGone()) { - // Insert object reference into table - script->objectrefGetOrCreate(L, obj); - lua_rawseti(L, -2, ++i); - } + std::vector objs; + + auto include_obj_cb = [](ServerActiveObject *obj){ return !obj->isGone(); }; + env->getObjectsInsideRadius(objs, pos, radius, include_obj_cb); + + int i = 0; + lua_createtable(L, objs.size(), 0); + for (const auto obj : objs) { + // Insert object reference into table + script->objectrefGetOrCreate(L, obj); + lua_rawseti(L, -2, ++i); } return 1; } diff --git a/src/server/activeobjectmgr.cpp b/src/server/activeobjectmgr.cpp index 984ae7794..1b8e31409 100644 --- a/src/server/activeobjectmgr.cpp +++ b/src/server/activeobjectmgr.cpp @@ -111,17 +111,19 @@ void ActiveObjectMgr::removeObject(u16 id) } // clang-format on -void ActiveObjectMgr::getObjectsInsideRadius( - const v3f &pos, float radius, std::vector &result) +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; - u16 id = activeObject.first; const v3f &objectpos = obj->getBasePosition(); if (objectpos.getDistanceFromSQ(pos) > r2) continue; - result.push_back(id); + + if (!include_obj_cb || include_obj_cb(obj)) + result.push_back(obj); } } diff --git a/src/server/activeobjectmgr.h b/src/server/activeobjectmgr.h index 5fea1bea6..bc2085499 100644 --- a/src/server/activeobjectmgr.h +++ b/src/server/activeobjectmgr.h @@ -35,8 +35,9 @@ public: bool registerObject(ServerActiveObject *obj) override; void removeObject(u16 id) override; - void getObjectsInsideRadius( - const v3f &pos, float radius, std::vector &result); + void getObjectsInsideRadius(const v3f &pos, float radius, + std::vector &result, + std::function include_obj_cb); void getAddedActiveObjectsAroundPos(const v3f &player_pos, f32 radius, f32 player_radius, std::set ¤t_objects, diff --git a/src/serverenvironment.cpp b/src/serverenvironment.cpp index 739384673..27f0c1e3d 100644 --- a/src/serverenvironment.cpp +++ b/src/serverenvironment.cpp @@ -1608,14 +1608,12 @@ void ServerEnvironment::getSelectedActiveObjects( const core::line3d &shootline_on_map, std::vector &objects) { - std::vector objectIds; - getObjectsInsideRadius(objectIds, shootline_on_map.start, - shootline_on_map.getLength() + 10.0f); + std::vector objs; + getObjectsInsideRadius(objs, shootline_on_map.start, + shootline_on_map.getLength() + 10.0f, nullptr); const v3f line_vector = shootline_on_map.getVector(); - for (u16 objectId : objectIds) { - ServerActiveObject* obj = getActiveObject(objectId); - + for (auto obj : objs) { aabb3f selection_box; if (!obj->getSelectionBox(&selection_box)) continue; @@ -1630,7 +1628,7 @@ void ServerEnvironment::getSelectedActiveObjects( if (boxLineCollision(offsetted_box, shootline_on_map.start, line_vector, ¤t_intersection, ¤t_normal)) { objects.emplace_back( - (s16) objectId, current_intersection, current_normal, + (s16) obj->getId(), current_intersection, current_normal, (current_intersection - shootline_on_map.start).getLengthSQ()); } } diff --git a/src/serverenvironment.h b/src/serverenvironment.h index 55ecbd05f..f814b95c0 100644 --- a/src/serverenvironment.h +++ b/src/serverenvironment.h @@ -323,9 +323,10 @@ public: bool swapNode(v3s16 p, const MapNode &n); // Find all active objects inside a radius around a point - void getObjectsInsideRadius(std::vector &objects, const v3f &pos, float radius) + void getObjectsInsideRadius(std::vector &objects, const v3f &pos, float radius, + std::function 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 diff --git a/src/unittest/test_serveractiveobjectmgr.cpp b/src/unittest/test_serveractiveobjectmgr.cpp index 0806972ab..aa0047400 100644 --- a/src/unittest/test_serveractiveobjectmgr.cpp +++ b/src/unittest/test_serveractiveobjectmgr.cpp @@ -148,14 +148,26 @@ void TestServerActiveObjectMgr::testGetObjectsInsideRadius() saomgr.registerObject(new TestServerActiveObject(p)); } - std::vector result; - saomgr.getObjectsInsideRadius(v3f(), 50, result); + std::vector result; + saomgr.getObjectsInsideRadius(v3f(), 50, result, nullptr); UASSERTCMP(int, ==, result.size(), 1); result.clear(); - saomgr.getObjectsInsideRadius(v3f(), 750, result); + saomgr.getObjectsInsideRadius(v3f(), 750, result, nullptr); 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); } -- cgit v1.2.3 From 5cbe8437a8f7efc9c76baf23de700e96ad96b385 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Thu, 16 Apr 2020 10:23:48 +0200 Subject: Swap out -ffast-math for a safe subset of optimization flags (#9682) It caused more trouble than its worth. fixes #3943, fixes #5330 --- src/CMakeLists.txt | 7 ++++++- src/collision.cpp | 3 +++ 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'src/collision.cpp') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fa261547b..d5f774d77 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -713,6 +713,11 @@ else() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DWIN32_LEAN_AND_MEAN") endif() + # Use a safe subset of flags to speed up math calculations: + # - we don't need errno or math exceptions + # - we don't deal with Inf/NaN or signed zero + set(MATH_FLAGS "-fno-math-errno -fno-trapping-math -ffinite-math-only -fno-signed-zeros") + set(CMAKE_CXX_FLAGS_RELEASE "-DNDEBUG ${RELEASE_WARNING_FLAGS} ${WARNING_FLAGS} ${OTHER_FLAGS} -Wall -pipe -funroll-loops") if(CMAKE_SYSTEM_NAME MATCHES "(Darwin|BSD|DragonFly)") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Os") @@ -723,7 +728,7 @@ else() AND CMAKE_CXX_COMPILER_VERSION MATCHES "^9\\.") # Clang 9 has broken -ffast-math on glibc else() - set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -ffast-math") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${MATH_FLAGS}") endif() endif(CMAKE_SYSTEM_NAME MATCHES "(Darwin|BSD|DragonFly)") set(CMAKE_CXX_FLAGS_SEMIDEBUG "-g -O1 -Wall -Wabi ${WARNING_FLAGS} ${OTHER_FLAGS}") diff --git a/src/collision.cpp b/src/collision.cpp index 6d24bc699..a089f3377 100644 --- a/src/collision.cpp +++ b/src/collision.cpp @@ -32,6 +32,9 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "util/timetaker.h" #include "profiler.h" +#ifdef __FAST_MATH__ +#warning "-ffast-math is known to cause bugs in collision code, do not use!" +#endif struct NearbyCollisionInfo { NearbyCollisionInfo(bool is_ul, bool is_obj, int bouncy, -- cgit v1.2.3 From b6b80f55c8a2bf4eae440108b3274f2f921e3a94 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Sun, 26 Apr 2020 22:52:00 +0200 Subject: Expose collided objects in moveresult closes #9787 --- doc/lua_api.txt | 1 + src/collision.cpp | 40 ++++++++++++++++++++++++++-------------- src/collision.h | 1 + src/script/common/c_content.cpp | 3 +++ 4 files changed, 31 insertions(+), 14 deletions(-) (limited to 'src/collision.cpp') diff --git a/doc/lua_api.txt b/doc/lua_api.txt index b1099ec59..948e0f89e 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -6632,6 +6632,7 @@ Collision info passed to `on_step`: type = string, -- "node" or "object", axis = string, -- "x", "y" or "z" node_pos = vector, -- if type is "node" + object = ObjectRef, -- if type is "object" old_velocity = vector, new_velocity = vector, }, diff --git a/src/collision.cpp b/src/collision.cpp index a089f3377..3b5e79a66 100644 --- a/src/collision.cpp +++ b/src/collision.cpp @@ -37,18 +37,30 @@ with this program; if not, write to the Free Software Foundation, Inc., #endif struct NearbyCollisionInfo { - NearbyCollisionInfo(bool is_ul, bool is_obj, int bouncy, - const v3s16 &pos, const aabb3f &box) : + // node + NearbyCollisionInfo(bool is_ul, int bouncy, const v3s16 &pos, + const aabb3f &box) : is_unloaded(is_ul), - is_object(is_obj), + obj(nullptr), bouncy(bouncy), position(pos), box(box) {} + // object + NearbyCollisionInfo(ActiveObject *obj, int bouncy, + const aabb3f &box) : + is_unloaded(false), + obj(obj), + bouncy(bouncy), + box(box) + {} + + inline bool isObject() const { return obj != nullptr; } + bool is_unloaded; bool is_step_up = false; - bool is_object; + ActiveObject *obj; int bouncy; v3s16 position; aabb3f box; @@ -312,13 +324,13 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef, for (auto box : nodeboxes) { box.MinEdge += posf; box.MaxEdge += posf; - cinfo.emplace_back(false, false, n_bouncy_value, p, box); + cinfo.emplace_back(false, n_bouncy_value, p, box); } } else { // Collide with unloaded nodes (position invalid) and loaded // CONTENT_IGNORE nodes (position valid) aabb3f box = getNodeBox(p, BS); - cinfo.emplace_back(true, false, 0, p, box); + cinfo.emplace_back(true, 0, p, box); } } @@ -383,12 +395,10 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef, iter != objects.end(); ++iter) { ActiveObject *object = *iter; - if (object) { + if (object && object->collideWithObjects()) { aabb3f object_collisionbox; - if (object->getCollisionBox(&object_collisionbox) && - object->collideWithObjects()) { - cinfo.emplace_back(false, true, 0, v3s16(), object_collisionbox); - } + if (object->getCollisionBox(&object_collisionbox)) + cinfo.emplace_back(object, 0, object_collisionbox); } } #ifndef SERVER @@ -399,7 +409,8 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef, v3f lplayer_pos = lplayer->getPosition(); lplayer_collisionbox.MinEdge += lplayer_pos; lplayer_collisionbox.MaxEdge += lplayer_pos; - cinfo.emplace_back(false, true, 0, v3s16(), lplayer_collisionbox); + ActiveObject *obj = (ActiveObject*) lplayer->getCAO(); + cinfo.emplace_back(obj, 0, lplayer_collisionbox); } } #endif @@ -498,12 +509,13 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef, is_collision = false; CollisionInfo info; - if (nearest_info.is_object) + if (nearest_info.isObject()) info.type = COLLISION_OBJECT; else info.type = COLLISION_NODE; info.node_p = nearest_info.position; + info.object = nearest_info.obj; info.old_speed = *speed_f; info.plane = nearest_collided; @@ -572,7 +584,7 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef, if (std::fabs(cbox.MaxEdge.Y - box.MinEdge.Y) < 0.05f) { result.touching_ground = true; - if (box_info.is_object) + if (box_info.isObject()) result.standing_on_object = true; } } diff --git a/src/collision.h b/src/collision.h index fa47cccc1..87a502828 100644 --- a/src/collision.h +++ b/src/collision.h @@ -48,6 +48,7 @@ struct CollisionInfo CollisionType type = COLLISION_NODE; CollisionAxis axis = COLLISION_AXIS_NONE; v3s16 node_p = v3s16(-32768,-32768,-32768); // COLLISION_NODE + ActiveObject *object = nullptr; // COLLISION_OBJECT v3f old_speed; v3f new_speed; int plane = -1; diff --git a/src/script/common/c_content.cpp b/src/script/common/c_content.cpp index 95364000c..dac828316 100644 --- a/src/script/common/c_content.cpp +++ b/src/script/common/c_content.cpp @@ -2043,6 +2043,9 @@ void push_collision_move_result(lua_State *L, const collisionMoveResult &res) if (c.type == COLLISION_NODE) { push_v3s16(L, c.node_p); lua_setfield(L, -2, "node_pos"); + } else if (c.type == COLLISION_OBJECT) { + push_objectRef(L, c.object->getId()); + lua_setfield(L, -2, "object"); } push_v3f(L, c.old_speed / BS); -- cgit v1.2.3 From 6ef7ad09bbed9176d0d15f53b5cb14ef6e18a3b2 Mon Sep 17 00:00:00 2001 From: TheTermos <55103816+TheTermos@users.noreply.github.com> Date: Thu, 14 May 2020 19:28:27 +0200 Subject: Collision detection - #9343 follow-up (#9764) * truncate speed to prevent inf result * code styling * change truncate() input parameters --- src/collision.cpp | 121 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 69 insertions(+), 52 deletions(-) (limited to 'src/collision.cpp') diff --git a/src/collision.cpp b/src/collision.cpp index 3b5e79a66..06ef820c5 100644 --- a/src/collision.cpp +++ b/src/collision.cpp @@ -66,6 +66,22 @@ struct NearbyCollisionInfo { aabb3f box; }; +// Helper functions: +// Truncate floating point numbers to specified number of decimal places +// in order to move all the floating point error to one side of the correct value +static inline f32 truncate(const f32 val, const f32 factor) +{ + return truncf(val * factor) / factor; +} + +static inline v3f truncate(const v3f& vec, const f32 factor) +{ + return v3f( + truncate(vec.X, factor), + truncate(vec.Y, factor), + truncate(vec.Z, factor) + ); +} // Helper function: // Checks for collision of a moving aabbox with a static aabbox @@ -78,70 +94,70 @@ CollisionAxis axisAlignedCollision( //TimeTaker tt("axisAlignedCollision"); aabb3f relbox( - movingbox.MaxEdge.X - movingbox.MinEdge.X + staticbox.MaxEdge.X - staticbox.MinEdge.X, // sum of the widths - movingbox.MaxEdge.Y - movingbox.MinEdge.Y + staticbox.MaxEdge.Y - staticbox.MinEdge.Y, - movingbox.MaxEdge.Z - movingbox.MinEdge.Z + staticbox.MaxEdge.Z - staticbox.MinEdge.Z, + (movingbox.MaxEdge.X - movingbox.MinEdge.X) + (staticbox.MaxEdge.X - staticbox.MinEdge.X), // sum of the widths + (movingbox.MaxEdge.Y - movingbox.MinEdge.Y) + (staticbox.MaxEdge.Y - staticbox.MinEdge.Y), + (movingbox.MaxEdge.Z - movingbox.MinEdge.Z) + (staticbox.MaxEdge.Z - staticbox.MinEdge.Z), std::max(movingbox.MaxEdge.X, staticbox.MaxEdge.X) - std::min(movingbox.MinEdge.X, staticbox.MinEdge.X), //outer bounding 'box' dimensions std::max(movingbox.MaxEdge.Y, staticbox.MaxEdge.Y) - std::min(movingbox.MinEdge.Y, staticbox.MinEdge.Y), std::max(movingbox.MaxEdge.Z, staticbox.MaxEdge.Z) - std::min(movingbox.MinEdge.Z, staticbox.MinEdge.Z) ); const f32 dtime_max = *dtime; - const f32 inner_margin = -1.5f; + f32 inner_margin; // the distance of clipping recovery f32 distance; f32 time; - if (speed.X) { - distance = relbox.MaxEdge.X - relbox.MinEdge.X; - *dtime = distance >= 0 ? std::abs(distance / speed.X) : -std::abs(distance / speed.X); + if (speed.Y) { + distance = relbox.MaxEdge.Y - relbox.MinEdge.Y; + *dtime = distance / std::abs(speed.Y); time = std::max(*dtime, 0.0f); - if (distance > inner_margin) { - if (*dtime <= dtime_max) { - if ((speed.X > 0 && staticbox.MaxEdge.X > movingbox.MaxEdge.X) || - (speed.X < 0 && staticbox.MinEdge.X < movingbox.MinEdge.X)) { - if ( - (std::max(movingbox.MaxEdge.Y + speed.Y * time, staticbox.MaxEdge.Y) - - std::min(movingbox.MinEdge.Y + speed.Y * time, staticbox.MinEdge.Y) - - relbox.MinEdge.Y < 0) && + if (*dtime <= dtime_max) { + inner_margin = std::max(-0.5f * (staticbox.MaxEdge.Y - staticbox.MinEdge.Y), -2.0f); + + if ((speed.Y > 0 && staticbox.MinEdge.Y - movingbox.MaxEdge.Y > inner_margin) || + (speed.Y < 0 && movingbox.MinEdge.Y - staticbox.MaxEdge.Y > inner_margin)) { + if ( + (std::max(movingbox.MaxEdge.X + speed.X * time, staticbox.MaxEdge.X) + - std::min(movingbox.MinEdge.X + speed.X * time, staticbox.MinEdge.X) + - relbox.MinEdge.X < 0) && (std::max(movingbox.MaxEdge.Z + speed.Z * time, staticbox.MaxEdge.Z) - std::min(movingbox.MinEdge.Z + speed.Z * time, staticbox.MinEdge.Z) - relbox.MinEdge.Z < 0) - ) - return COLLISION_AXIS_X; - } - } else { - return COLLISION_AXIS_NONE; + ) + return COLLISION_AXIS_Y; } } + else { + return COLLISION_AXIS_NONE; + } } // NO else if here - if (speed.Y) { - distance = relbox.MaxEdge.Y - relbox.MinEdge.Y; - - *dtime = distance >= 0 ? std::abs(distance / speed.Y) : -std::abs(distance / speed.Y); + if (speed.X) { + distance = relbox.MaxEdge.X - relbox.MinEdge.X; + *dtime = distance / std::abs(speed.X); time = std::max(*dtime, 0.0f); - if (distance > inner_margin) { - if (*dtime <= dtime_max) { - if ((speed.Y > 0 && staticbox.MaxEdge.Y > movingbox.MaxEdge.Y) || - (speed.Y < 0 && staticbox.MinEdge.Y < movingbox.MinEdge.Y)) { - if ( - (std::max(movingbox.MaxEdge.X + speed.X * time, staticbox.MaxEdge.X) - - std::min(movingbox.MinEdge.X + speed.X * time, staticbox.MinEdge.X) - - relbox.MinEdge.X < 0) && + if (*dtime <= dtime_max) { + inner_margin = std::max(-0.5f * (staticbox.MaxEdge.X - staticbox.MinEdge.X), -2.0f); + + if ((speed.X > 0 && staticbox.MinEdge.X - movingbox.MaxEdge.X > inner_margin) || + (speed.X < 0 && movingbox.MinEdge.X - staticbox.MaxEdge.X > inner_margin)) { + if ( + (std::max(movingbox.MaxEdge.Y + speed.Y * time, staticbox.MaxEdge.Y) + - std::min(movingbox.MinEdge.Y + speed.Y * time, staticbox.MinEdge.Y) + - relbox.MinEdge.Y < 0) && (std::max(movingbox.MaxEdge.Z + speed.Z * time, staticbox.MaxEdge.Z) - std::min(movingbox.MinEdge.Z + speed.Z * time, staticbox.MinEdge.Z) - relbox.MinEdge.Z < 0) - ) - return COLLISION_AXIS_Y; - } - } else { - return COLLISION_AXIS_NONE; + ) + return COLLISION_AXIS_X; } + } else { + return COLLISION_AXIS_NONE; } } @@ -149,24 +165,23 @@ CollisionAxis axisAlignedCollision( if (speed.Z) { distance = relbox.MaxEdge.Z - relbox.MinEdge.Z; - - *dtime = distance >= 0 ? std::abs(distance / speed.Z) : -std::abs(distance / speed.Z); + *dtime = distance / std::abs(speed.Z); time = std::max(*dtime, 0.0f); - if (distance > inner_margin) { - if (*dtime <= dtime_max) { - if ((speed.Z > 0 && staticbox.MaxEdge.Z > movingbox.MaxEdge.Z) || - (speed.Z < 0 && staticbox.MinEdge.Z < movingbox.MinEdge.Z)) { - if ( - (std::max(movingbox.MaxEdge.X + speed.X * time, staticbox.MaxEdge.X) - - std::min(movingbox.MinEdge.X + speed.X * time, staticbox.MinEdge.X) - - relbox.MinEdge.X < 0) && + if (*dtime <= dtime_max) { + inner_margin = std::max(-0.5f * (staticbox.MaxEdge.Z - staticbox.MinEdge.Z), -2.0f); + + if ((speed.Z > 0 && staticbox.MinEdge.Z - movingbox.MaxEdge.Z > inner_margin) || + (speed.Z < 0 && movingbox.MinEdge.Z - staticbox.MaxEdge.Z > inner_margin)) { + if ( + (std::max(movingbox.MaxEdge.X + speed.X * time, staticbox.MaxEdge.X) + - std::min(movingbox.MinEdge.X + speed.X * time, staticbox.MinEdge.X) + - relbox.MinEdge.X < 0) && (std::max(movingbox.MaxEdge.Y + speed.Y * time, staticbox.MaxEdge.Y) - std::min(movingbox.MinEdge.Y + speed.Y * time, staticbox.MinEdge.Y) - relbox.MinEdge.Y < 0) - ) - return COLLISION_AXIS_Z; - } + ) + return COLLISION_AXIS_Z; } } } @@ -245,6 +260,8 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef, speed_f->X = rangelim(speed_f->X, -5000, 5000); speed_f->Z = rangelim(speed_f->Z, -5000, 5000); + *speed_f = truncate(*speed_f, 10000.0f); + /* Collect node boxes in movement range */ @@ -464,7 +481,7 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef, if (nearest_collided == COLLISION_AXIS_NONE) { // No collision with any collision box. - *pos_f += *speed_f * dtime; + *pos_f += truncate(*speed_f * dtime, 100.0f); dtime = 0; // Set to 0 to avoid "infinite" loop due to small FP numbers } else { // Otherwise, a collision occurred. @@ -500,7 +517,7 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef, pos_f->Z += speed_f->Z * nearest_dtime; } } else { - *pos_f += *speed_f * nearest_dtime; + *pos_f += truncate(*speed_f * nearest_dtime, 100.0f); dtime -= nearest_dtime; } -- cgit v1.2.3 From 0fc51db7722f9aa1e0aa2dacade6041c932b0731 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Mon, 18 May 2020 23:23:25 +0200 Subject: Add missing sao->isGone() checks fixes #9883 --- src/collision.cpp | 3 ++- src/serverenvironment.cpp | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'src/collision.cpp') diff --git a/src/collision.cpp b/src/collision.cpp index 06ef820c5..d85a56884 100644 --- a/src/collision.cpp +++ b/src/collision.cpp @@ -397,7 +397,8 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef, // we directly use the callback to populate the result to prevent // a useless result loop here auto include_obj_cb = [self, &objects] (ServerActiveObject *obj) { - if (!self || (self != obj && self != obj->getParent())) { + if (!obj->isGone() && + (!self || (self != obj && self != obj->getParent()))) { objects.push_back((ActiveObject *)obj); } return false; diff --git a/src/serverenvironment.cpp b/src/serverenvironment.cpp index 6bf7399cf..d485c32e8 100644 --- a/src/serverenvironment.cpp +++ b/src/serverenvironment.cpp @@ -1623,6 +1623,8 @@ void ServerEnvironment::getSelectedActiveObjects( const v3f line_vector = shootline_on_map.getVector(); for (auto obj : objs) { + if (obj->isGone()) + continue; aabb3f selection_box; if (!obj->getSelectionBox(&selection_box)) continue; -- cgit v1.2.3