Skip to content

Commit

Permalink
Sneak: Fix various problems with sneaking
Browse files Browse the repository at this point in the history
Sneaking won't actually hover you in the air, releasing shift guarantees not
falling down (same as in MC).
Sneak-jump no longer goes higher than a normal jump (^ was required for this).
Sneaking no longer avoids fall damage.
You can sneak on partial nodes (slabs, sideways slabs) correctly.
Sneaking doesn't "go out" as far anymore (0.29 instead of 0.4).
Can't jump when sneaking out as far as possible (breaks the sneak ladder).
  • Loading branch information
sfan5 authored and paramat committed Mar 16, 2017
1 parent c05dfac commit 14aa990
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 65 deletions.
108 changes: 45 additions & 63 deletions src/localplayer.cpp
Expand Up @@ -68,7 +68,7 @@ LocalPlayer::LocalPlayer(Client *client, const char *name):
m_sneak_node(32767,32767,32767),
m_sneak_node_exists(false),
m_need_to_get_new_sneak_node(true),
m_sneak_node_bb_ymax(0),
m_sneak_node_bb_top(0,0,0,0,0,0),
m_old_node_below(32767,32767,32767),
m_old_node_below_type("air"),
m_can_jump(false),
Expand All @@ -91,6 +91,21 @@ LocalPlayer::~LocalPlayer()
{
}

static aabb3f getTopBoundingBox(const std::vector<aabb3f> &nodeboxes, float max_d=1/16*BS)
{
aabb3f b_max;
b_max.reset(-BS, -BS, -BS);
for (std::vector<aabb3f>::const_iterator it = nodeboxes.begin();
it != nodeboxes.end(); ++it) {
aabb3f box = *it;
if (box.MaxEdge.Y > b_max.MaxEdge.Y)
b_max = box;
else if (box.MaxEdge.Y == b_max.MaxEdge.Y)
b_max.addInternalBox(box);
}
return aabb3f(v3f(b_max.MinEdge.X, b_max.MaxEdge.Y, b_max.MinEdge.Z), b_max.MaxEdge);
}

void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
std::vector<CollisionInfo> *collision_info)
{
Expand Down Expand Up @@ -198,8 +213,9 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
// This should always apply, otherwise there are glitches
sanity_check(d > pos_max_d);

// Maximum distance over border for sneaking
f32 sneak_max = BS*0.4;
// Max. distance (X, Z) over border for sneaking determined by collision box
// * 0.49 to keep the center just barely on the node
v3f sneak_max = m_collisionbox.getExtent() * 0.49;

/*
If sneaking, keep in range from the last walked node and don't
Expand All @@ -208,30 +224,22 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
if (control.sneak && m_sneak_node_exists &&
!(fly_allowed && g_settings->getBool("free_move")) && !in_liquid &&
physics_override_sneak && !got_teleported) {
f32 maxd = 0.5 * BS + sneak_max;
v3f lwn_f = intToFloat(m_sneak_node, BS);
position.X = rangelim(position.X, lwn_f.X-maxd, lwn_f.X+maxd);
position.Z = rangelim(position.Z, lwn_f.Z-maxd, lwn_f.Z+maxd);

if (!is_climbing) {
// Move up if necessary
f32 new_y = (lwn_f.Y - 0.5 * BS) + m_sneak_node_bb_ymax;
if (position.Y < new_y)
position.Y = new_y;
/*
Collision seems broken, since player is sinking when
sneaking over the edges of current sneaking_node.
TODO (when fixed): Set Y-speed only to 0 when position.Y < new_y.
*/
if (m_speed.Y < 0)
m_speed.Y = 0;
}
v3f sn_f = intToFloat(m_sneak_node, BS);
const v3f bmin = m_sneak_node_bb_top.MinEdge;
const v3f bmax = m_sneak_node_bb_top.MaxEdge;

position.X = rangelim(position.X,
sn_f.X+bmin.X - sneak_max.X, sn_f.X+bmax.X + sneak_max.X);
position.Z = rangelim(position.Z,
sn_f.Z+bmin.Z - sneak_max.Z, sn_f.Z+bmax.Z + sneak_max.Z);
// Because we keep the player collision box on the node,
// limiting position.Y is not necessary
}

if (got_teleported)
got_teleported = false;

// this shouldn't be hardcoded but transmitted from server
// TODO: this shouldn't be hardcoded but transmitted from server
float player_stepheight = touching_ground ? (BS*0.6) : (BS*0.2);

#ifdef __ANDROID__
Expand All @@ -255,15 +263,18 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,

//bool standing_on_unloaded = result.standing_on_unloaded;

// We want the top of the sneak node to be below the players feet
f32 position_y_mod;
if (m_sneak_node_exists)
position_y_mod = m_sneak_node_bb_top.MaxEdge.Y - 0.05 * BS;
else
position_y_mod = (1.0 - 0.05) * BS;
v3s16 current_node = floatToInt(position - v3f(0, position_y_mod, 0), BS);
/*
Check the nodes under the player to see from which node the
player is sneaking from, if any. If the node from under
the player has been removed, the player falls.
*/
f32 position_y_mod = 0.05 * BS;
if (m_sneak_node_bb_ymax > 0)
position_y_mod = m_sneak_node_bb_ymax - position_y_mod;
v3s16 current_node = floatToInt(position - v3f(0, position_y_mod, 0), BS);
if (m_sneak_node_exists &&
nodemgr->get(map->getNodeNoEx(m_old_node_below)).name == "air" &&
m_old_node_below_type != "air") {
Expand All @@ -278,21 +289,9 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
}

if (m_need_to_get_new_sneak_node && physics_override_sneak) {
m_sneak_node_bb_ymax = 0;
v3s16 pos_i_bottom = floatToInt(position - v3f(0, position_y_mod, 0), BS);
v2f player_p2df(position.X, position.Z);
f32 min_distance_f = 100000.0 * BS;
// If already seeking from some node, compare to it.
/*if(m_sneak_node_exists)
{
v3f sneaknode_pf = intToFloat(m_sneak_node, BS);
v2f sneaknode_p2df(sneaknode_pf.X, sneaknode_pf.Z);
f32 d_horiz_f = player_p2df.getDistanceFrom(sneaknode_p2df);
f32 d_vert_f = fabs(sneaknode_pf.Y + BS*0.5 - position.Y);
// Ignore if player is not on the same level (likely dropped)
if(d_vert_f < 0.15*BS)
min_distance_f = d_horiz_f;
}*/
v3s16 new_sneak_node = m_sneak_node;
for(s16 x=-1; x<=1; x++)
for(s16 z=-1; z<=1; z++)
Expand All @@ -301,12 +300,10 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
v3f pf = intToFloat(p, BS);
v2f node_p2df(pf.X, pf.Z);
f32 distance_f = player_p2df.getDistanceFrom(node_p2df);
f32 max_axis_distance_f = MYMAX(
fabs(player_p2df.X-node_p2df.X),
fabs(player_p2df.Y-node_p2df.Y));

if(distance_f > min_distance_f ||
max_axis_distance_f > 0.5*BS + sneak_max + 0.1*BS)
if (distance_f > min_distance_f ||
fabs(player_p2df.X-node_p2df.X) > (.5+.1)*BS + sneak_max.X ||
fabs(player_p2df.Y-node_p2df.Y) > (.5+.1)*BS + sneak_max.Z)
continue;


Expand All @@ -316,11 +313,10 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
continue;
// And the node above it has to be nonwalkable
node = map->getNodeNoEx(p + v3s16(0,1,0), &is_valid_position);
if (!is_valid_position || nodemgr->get(node).walkable) {
if (!is_valid_position || nodemgr->get(node).walkable)
continue;
}
if (!physics_override_sneak_glitch) {
node =map->getNodeNoEx(p + v3s16(0,2,0), &is_valid_position);
node = map->getNodeNoEx(p + v3s16(0,2,0), &is_valid_position);
if (!is_valid_position || nodemgr->get(node).walkable)
continue;
}
Expand All @@ -329,31 +325,17 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
new_sneak_node = p;
}

bool sneak_node_found = (min_distance_f < 100000.0 * BS * 0.9);

bool sneak_node_found = (min_distance_f < 100000.0 * BS);
m_sneak_node = new_sneak_node;
m_sneak_node_exists = sneak_node_found;

// Update saved top bounding box of sneak node
if (sneak_node_found) {
f32 cb_max = 0;
MapNode n = map->getNodeNoEx(m_sneak_node);
std::vector<aabb3f> nodeboxes;
n.getCollisionBoxes(nodemgr, &nodeboxes);
for (std::vector<aabb3f>::iterator it = nodeboxes.begin();
it != nodeboxes.end(); ++it) {
aabb3f box = *it;
if (box.MaxEdge.Y > cb_max)
cb_max = box.MaxEdge.Y;
}
m_sneak_node_bb_ymax = cb_max;
m_sneak_node_bb_top = getTopBoundingBox(nodeboxes);
}

/*
If sneaking, the player's collision box can be in air, so
this has to be set explicitly
*/
if(sneak_node_found && control.sneak)
touching_ground = true;
}

/*
Expand Down
4 changes: 2 additions & 2 deletions src/localplayer.h
Expand Up @@ -141,9 +141,9 @@ class LocalPlayer : public Player
bool m_sneak_node_exists;
// Whether recalculation of the sneak node is needed
bool m_need_to_get_new_sneak_node;
// Stores the max player uplift by m_sneak_node and is updated
// Stores the top bounding box of m_sneak_node and is updated
// when m_need_to_get_new_sneak_node == true
f32 m_sneak_node_bb_ymax;
aabb3f m_sneak_node_bb_top;
// Node below player, used to determine whether it has been removed,
// and its old type
v3s16 m_old_node_below;
Expand Down

2 comments on commit 14aa990

@Brackston
Copy link

@Brackston Brackston commented on 14aa990 Mar 20, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This move to remove the sneak is wrong. while I can appreciate the need to fix some of the mis-uses of sneak, don't disable a feature used daily by hundreds of players. The sneak ladder is realistic in climbing. what you have done is ruin the game for many of us players.
If we all use hacked clients in the future, will we retain the ability to have NORMAL mobility?
We don't have many players as it is and sneak was a feature that got me to leave MC and come to minetest. I am afraid we will loose more players now. Sorry if I commented in th wrong place, I just signed up to github to make a comment someplace and basically the site is confusing.

@paramat
Copy link
Contributor

@paramat paramat commented on 14aa990 Mar 20, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The best place to discuss is here #5327 i recommend reading the discussion.
Climbing using handholds cut into walls is reasonable, but the speed of 6n/s (sprinting speed) was not (and was not realistic) and was out of balance with the more realistic speeds used elsewhere in MT.
Mods are being written right now to act as replacements, i recommend using these when they appear.

Please sign in to comment.