Skip to content

Commit 14aa990

Browse files
sfan5paramat
authored andcommittedMar 16, 2017
Sneak: Fix various problems with sneaking
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).
1 parent c05dfac commit 14aa990

File tree

2 files changed

+47
-65
lines changed

2 files changed

+47
-65
lines changed
 

‎src/localplayer.cpp

+45-63
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ LocalPlayer::LocalPlayer(Client *client, const char *name):
6868
m_sneak_node(32767,32767,32767),
6969
m_sneak_node_exists(false),
7070
m_need_to_get_new_sneak_node(true),
71-
m_sneak_node_bb_ymax(0),
71+
m_sneak_node_bb_top(0,0,0,0,0,0),
7272
m_old_node_below(32767,32767,32767),
7373
m_old_node_below_type("air"),
7474
m_can_jump(false),
@@ -91,6 +91,21 @@ LocalPlayer::~LocalPlayer()
9191
{
9292
}
9393

94+
static aabb3f getTopBoundingBox(const std::vector<aabb3f> &nodeboxes, float max_d=1/16*BS)
95+
{
96+
aabb3f b_max;
97+
b_max.reset(-BS, -BS, -BS);
98+
for (std::vector<aabb3f>::const_iterator it = nodeboxes.begin();
99+
it != nodeboxes.end(); ++it) {
100+
aabb3f box = *it;
101+
if (box.MaxEdge.Y > b_max.MaxEdge.Y)
102+
b_max = box;
103+
else if (box.MaxEdge.Y == b_max.MaxEdge.Y)
104+
b_max.addInternalBox(box);
105+
}
106+
return aabb3f(v3f(b_max.MinEdge.X, b_max.MaxEdge.Y, b_max.MinEdge.Z), b_max.MaxEdge);
107+
}
108+
94109
void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
95110
std::vector<CollisionInfo> *collision_info)
96111
{
@@ -198,8 +213,9 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
198213
// This should always apply, otherwise there are glitches
199214
sanity_check(d > pos_max_d);
200215

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

204220
/*
205221
If sneaking, keep in range from the last walked node and don't
@@ -208,30 +224,22 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
208224
if (control.sneak && m_sneak_node_exists &&
209225
!(fly_allowed && g_settings->getBool("free_move")) && !in_liquid &&
210226
physics_override_sneak && !got_teleported) {
211-
f32 maxd = 0.5 * BS + sneak_max;
212-
v3f lwn_f = intToFloat(m_sneak_node, BS);
213-
position.X = rangelim(position.X, lwn_f.X-maxd, lwn_f.X+maxd);
214-
position.Z = rangelim(position.Z, lwn_f.Z-maxd, lwn_f.Z+maxd);
215-
216-
if (!is_climbing) {
217-
// Move up if necessary
218-
f32 new_y = (lwn_f.Y - 0.5 * BS) + m_sneak_node_bb_ymax;
219-
if (position.Y < new_y)
220-
position.Y = new_y;
221-
/*
222-
Collision seems broken, since player is sinking when
223-
sneaking over the edges of current sneaking_node.
224-
TODO (when fixed): Set Y-speed only to 0 when position.Y < new_y.
225-
*/
226-
if (m_speed.Y < 0)
227-
m_speed.Y = 0;
228-
}
227+
v3f sn_f = intToFloat(m_sneak_node, BS);
228+
const v3f bmin = m_sneak_node_bb_top.MinEdge;
229+
const v3f bmax = m_sneak_node_bb_top.MaxEdge;
230+
231+
position.X = rangelim(position.X,
232+
sn_f.X+bmin.X - sneak_max.X, sn_f.X+bmax.X + sneak_max.X);
233+
position.Z = rangelim(position.Z,
234+
sn_f.Z+bmin.Z - sneak_max.Z, sn_f.Z+bmax.Z + sneak_max.Z);
235+
// Because we keep the player collision box on the node,
236+
// limiting position.Y is not necessary
229237
}
230238

231239
if (got_teleported)
232240
got_teleported = false;
233241

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

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

256264
//bool standing_on_unloaded = result.standing_on_unloaded;
257265

266+
// We want the top of the sneak node to be below the players feet
267+
f32 position_y_mod;
268+
if (m_sneak_node_exists)
269+
position_y_mod = m_sneak_node_bb_top.MaxEdge.Y - 0.05 * BS;
270+
else
271+
position_y_mod = (1.0 - 0.05) * BS;
272+
v3s16 current_node = floatToInt(position - v3f(0, position_y_mod, 0), BS);
258273
/*
259274
Check the nodes under the player to see from which node the
260275
player is sneaking from, if any. If the node from under
261276
the player has been removed, the player falls.
262277
*/
263-
f32 position_y_mod = 0.05 * BS;
264-
if (m_sneak_node_bb_ymax > 0)
265-
position_y_mod = m_sneak_node_bb_ymax - position_y_mod;
266-
v3s16 current_node = floatToInt(position - v3f(0, position_y_mod, 0), BS);
267278
if (m_sneak_node_exists &&
268279
nodemgr->get(map->getNodeNoEx(m_old_node_below)).name == "air" &&
269280
m_old_node_below_type != "air") {
@@ -278,21 +289,9 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
278289
}
279290

280291
if (m_need_to_get_new_sneak_node && physics_override_sneak) {
281-
m_sneak_node_bb_ymax = 0;
282292
v3s16 pos_i_bottom = floatToInt(position - v3f(0, position_y_mod, 0), BS);
283293
v2f player_p2df(position.X, position.Z);
284294
f32 min_distance_f = 100000.0 * BS;
285-
// If already seeking from some node, compare to it.
286-
/*if(m_sneak_node_exists)
287-
{
288-
v3f sneaknode_pf = intToFloat(m_sneak_node, BS);
289-
v2f sneaknode_p2df(sneaknode_pf.X, sneaknode_pf.Z);
290-
f32 d_horiz_f = player_p2df.getDistanceFrom(sneaknode_p2df);
291-
f32 d_vert_f = fabs(sneaknode_pf.Y + BS*0.5 - position.Y);
292-
// Ignore if player is not on the same level (likely dropped)
293-
if(d_vert_f < 0.15*BS)
294-
min_distance_f = d_horiz_f;
295-
}*/
296295
v3s16 new_sneak_node = m_sneak_node;
297296
for(s16 x=-1; x<=1; x++)
298297
for(s16 z=-1; z<=1; z++)
@@ -301,12 +300,10 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
301300
v3f pf = intToFloat(p, BS);
302301
v2f node_p2df(pf.X, pf.Z);
303302
f32 distance_f = player_p2df.getDistanceFrom(node_p2df);
304-
f32 max_axis_distance_f = MYMAX(
305-
fabs(player_p2df.X-node_p2df.X),
306-
fabs(player_p2df.Y-node_p2df.Y));
307303

308-
if(distance_f > min_distance_f ||
309-
max_axis_distance_f > 0.5*BS + sneak_max + 0.1*BS)
304+
if (distance_f > min_distance_f ||
305+
fabs(player_p2df.X-node_p2df.X) > (.5+.1)*BS + sneak_max.X ||
306+
fabs(player_p2df.Y-node_p2df.Y) > (.5+.1)*BS + sneak_max.Z)
310307
continue;
311308

312309

@@ -316,11 +313,10 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
316313
continue;
317314
// And the node above it has to be nonwalkable
318315
node = map->getNodeNoEx(p + v3s16(0,1,0), &is_valid_position);
319-
if (!is_valid_position || nodemgr->get(node).walkable) {
316+
if (!is_valid_position || nodemgr->get(node).walkable)
320317
continue;
321-
}
322318
if (!physics_override_sneak_glitch) {
323-
node =map->getNodeNoEx(p + v3s16(0,2,0), &is_valid_position);
319+
node = map->getNodeNoEx(p + v3s16(0,2,0), &is_valid_position);
324320
if (!is_valid_position || nodemgr->get(node).walkable)
325321
continue;
326322
}
@@ -329,31 +325,17 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
329325
new_sneak_node = p;
330326
}
331327

332-
bool sneak_node_found = (min_distance_f < 100000.0 * BS * 0.9);
333-
328+
bool sneak_node_found = (min_distance_f < 100000.0 * BS);
334329
m_sneak_node = new_sneak_node;
335330
m_sneak_node_exists = sneak_node_found;
336331

332+
// Update saved top bounding box of sneak node
337333
if (sneak_node_found) {
338-
f32 cb_max = 0;
339334
MapNode n = map->getNodeNoEx(m_sneak_node);
340335
std::vector<aabb3f> nodeboxes;
341336
n.getCollisionBoxes(nodemgr, &nodeboxes);
342-
for (std::vector<aabb3f>::iterator it = nodeboxes.begin();
343-
it != nodeboxes.end(); ++it) {
344-
aabb3f box = *it;
345-
if (box.MaxEdge.Y > cb_max)
346-
cb_max = box.MaxEdge.Y;
347-
}
348-
m_sneak_node_bb_ymax = cb_max;
337+
m_sneak_node_bb_top = getTopBoundingBox(nodeboxes);
349338
}
350-
351-
/*
352-
If sneaking, the player's collision box can be in air, so
353-
this has to be set explicitly
354-
*/
355-
if(sneak_node_found && control.sneak)
356-
touching_ground = true;
357339
}
358340

359341
/*

‎src/localplayer.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -141,9 +141,9 @@ class LocalPlayer : public Player
141141
bool m_sneak_node_exists;
142142
// Whether recalculation of the sneak node is needed
143143
bool m_need_to_get_new_sneak_node;
144-
// Stores the max player uplift by m_sneak_node and is updated
144+
// Stores the top bounding box of m_sneak_node and is updated
145145
// when m_need_to_get_new_sneak_node == true
146-
f32 m_sneak_node_bb_ymax;
146+
aabb3f m_sneak_node_bb_top;
147147
// Node below player, used to determine whether it has been removed,
148148
// and its old type
149149
v3s16 m_old_node_below;

2 commit comments

Comments
 (2)

Brackston commented on Mar 20, 2017

@Brackston

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 commented on Mar 20, 2017

@paramat
Contributor

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.