LocalPlayer: Restore 2u height sneak jump (#15015)

Fix 1: Do not consider LocalPlayer's CAO in the collision data.
Fix 2: work around the "aabbox3d::intersectsWithBox" edge-case.
This commit is contained in:
SmallJoker 2024-08-26 21:23:12 +02:00 committed by GitHub
parent 21ed680b10
commit 8109563a02
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 20 additions and 13 deletions

@ -360,7 +360,7 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
collisionMoveResult result = collisionMoveSimple(env, m_client, collisionMoveResult result = collisionMoveSimple(env, m_client,
pos_max_d, m_collisionbox, player_stepheight, dtime, pos_max_d, m_collisionbox, player_stepheight, dtime,
&position, &m_speed, accel_f); &position, &m_speed, accel_f, m_cao);
bool could_sneak = control.sneak && !free_move && !in_liquid && bool could_sneak = control.sneak && !free_move && !in_liquid &&
!is_climbing && physics_override.sneak; !is_climbing && physics_override.sneak;
@ -444,7 +444,7 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
v3f check_pos = position; v3f check_pos = position;
check_pos.Y += y_diff * dtime * 22.0f + BS * 0.01f; check_pos.Y += y_diff * dtime * 22.0f + BS * 0.01f;
if (y_diff < BS * 0.6f || (physics_override.sneak_glitch if (y_diff < BS * 0.6f || (physics_override.sneak_glitch
&& !collision_check_intersection(env, m_client, m_collisionbox, check_pos))) { && !collision_check_intersection(env, m_client, m_collisionbox, check_pos, m_cao))) {
// Smoothen the movement (based on 'position.Y = bmax.Y') // Smoothen the movement (based on 'position.Y = bmax.Y')
position.Y = std::min(check_pos.Y, bmax.Y); position.Y = std::min(check_pos.Y, bmax.Y);
m_speed.Y = 0.0f; m_speed.Y = 0.0f;
@ -990,7 +990,7 @@ void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d,
collisionMoveResult result = collisionMoveSimple(env, m_client, collisionMoveResult result = collisionMoveSimple(env, m_client,
pos_max_d, m_collisionbox, player_stepheight, dtime, pos_max_d, m_collisionbox, player_stepheight, dtime,
&position, &m_speed, accel_f); &position, &m_speed, accel_f, m_cao);
// Position was slightly changed; update standing node pos // Position was slightly changed; update standing node pos
if (touching_ground) if (touching_ground)
@ -1254,7 +1254,7 @@ void LocalPlayer::handleAutojump(f32 dtime, Environment *env,
// try at peak of jump, zero step height // try at peak of jump, zero step height
collisionMoveResult jump_result = collisionMoveSimple(env, m_client, pos_max_d, collisionMoveResult jump_result = collisionMoveSimple(env, m_client, pos_max_d,
m_collisionbox, 0.0f, dtime, &jump_pos, &jump_speed, v3f(0.0f)); m_collisionbox, 0.0f, dtime, &jump_pos, &jump_speed, v3f(0.0f), m_cao);
// see if we can get a little bit farther horizontally if we had // see if we can get a little bit farther horizontally if we had
// jumped // jumped

@ -273,7 +273,7 @@ static void add_object_boxes(Environment *env,
const v3f pos_f, const v3f speed_f, ActiveObject *self, const v3f pos_f, const v3f speed_f, ActiveObject *self,
std::vector<NearbyCollisionInfo> &cinfo) std::vector<NearbyCollisionInfo> &cinfo)
{ {
auto process_object = [&] (ActiveObject *object) { auto process_object = [&cinfo] (ActiveObject *object) {
if (object && object->collideWithObjects()) { if (object && object->collideWithObjects()) {
aabb3f box; aabb3f box;
if (object->getCollisionBox(&box)) if (object->getCollisionBox(&box))
@ -292,7 +292,7 @@ static void add_object_boxes(Environment *env,
c_env->getActiveObjects(pos_f, distance, clientobjects); c_env->getActiveObjects(pos_f, distance, clientobjects);
for (auto &clientobject : clientobjects) { for (auto &clientobject : clientobjects) {
// Do collide with everything but itself and the parent CAO // Do collide with everything but itself and children
if (!self || (self != clientobject.obj && if (!self || (self != clientobject.obj &&
self != clientobject.obj->getParent())) { self != clientobject.obj->getParent())) {
process_object(clientobject.obj); process_object(clientobject.obj);
@ -301,12 +301,12 @@ static void add_object_boxes(Environment *env,
// add collision with local player // add collision with local player
LocalPlayer *lplayer = c_env->getLocalPlayer(); LocalPlayer *lplayer = c_env->getLocalPlayer();
if (lplayer->getParent() == nullptr) { auto *obj = (ClientActiveObject*) lplayer->getCAO();
if (!self || (self != obj && self != obj->getParent())) {
aabb3f lplayer_collisionbox = lplayer->getCollisionbox(); aabb3f lplayer_collisionbox = lplayer->getCollisionbox();
v3f lplayer_pos = lplayer->getPosition(); v3f lplayer_pos = lplayer->getPosition();
lplayer_collisionbox.MinEdge += lplayer_pos; lplayer_collisionbox.MinEdge += lplayer_pos;
lplayer_collisionbox.MaxEdge += lplayer_pos; lplayer_collisionbox.MaxEdge += lplayer_pos;
auto *obj = (ActiveObject*) lplayer->getCAO();
cinfo.emplace_back(obj, 0, lplayer_collisionbox); cinfo.emplace_back(obj, 0, lplayer_collisionbox);
} }
} }
@ -315,7 +315,7 @@ static void add_object_boxes(Environment *env,
{ {
ServerEnvironment *s_env = dynamic_cast<ServerEnvironment*>(env); ServerEnvironment *s_env = dynamic_cast<ServerEnvironment*>(env);
if (s_env) { if (s_env) {
// search for objects which are not us, or we are not its parent. // search for objects which are not us and not our children.
// we directly process the object in this callback to avoid useless // we directly process the object in this callback to avoid useless
// looping afterwards. // looping afterwards.
auto include_obj_cb = [self, &process_object] (ServerActiveObject *obj) { auto include_obj_cb = [self, &process_object] (ServerActiveObject *obj) {
@ -623,8 +623,10 @@ bool collision_check_intersection(Environment *env, IGameDef *gamedef,
Collision detection Collision detection
*/ */
aabb3f checkbox = box_0; aabb3f checkbox = box_0;
checkbox.MinEdge += pos_f; // aabbox3d::intersectsWithBox(box) returns true when the faces are touching perfectly.
checkbox.MaxEdge += pos_f; // However, we do not want want a true-ish return value in that case. Add some tolerance.
checkbox.MinEdge += pos_f + (0.1f * BS);
checkbox.MaxEdge += pos_f - (0.1f * BS);
/* /*
Go through every node and object box Go through every node and object box

@ -65,7 +65,8 @@ struct collisionMoveResult
std::vector<CollisionInfo> collisions; std::vector<CollisionInfo> collisions;
}; };
// Moves using a single iteration; speed should not exceed pos_max_d/dtime /// @brief Moves using a single iteration; speed should not exceed pos_max_d/dtime
/// @param self (optional) ActiveObject to ignore in the collision detection.
collisionMoveResult collisionMoveSimple(Environment *env,IGameDef *gamedef, collisionMoveResult collisionMoveSimple(Environment *env,IGameDef *gamedef,
f32 pos_max_d, const aabb3f &box_0, f32 pos_max_d, const aabb3f &box_0,
f32 stepheight, f32 dtime, f32 stepheight, f32 dtime,
@ -73,7 +74,11 @@ collisionMoveResult collisionMoveSimple(Environment *env,IGameDef *gamedef,
v3f accel_f, ActiveObject *self=NULL, v3f accel_f, ActiveObject *self=NULL,
bool collide_with_objects=true); bool collide_with_objects=true);
// check if box is in collision on actual position /// @brief A simpler version of "collisionMoveSimple" that only checks whether
/// a collision occurs at the given position.
/// @param self (optional) ActiveObject to ignore in the collision detection.
/// @returns `true` when `box_0` truly intersects with a node or object.
/// Touching faces are not counted as intersection.
bool collision_check_intersection(Environment *env, IGameDef *gamedef, bool collision_check_intersection(Environment *env, IGameDef *gamedef,
const aabb3f &box_0, const v3f &pos_f, ActiveObject *self = nullptr, const aabb3f &box_0, const v3f &pos_f, ActiveObject *self = nullptr,
bool collide_with_objects = true); bool collide_with_objects = true);