@@ -66,9 +66,10 @@ LocalPlayer::LocalPlayer(Client *client, const char *name):
66
66
hurt_tilt_strength(0 .0f ),
67
67
m_position(0 ,0 ,0 ),
68
68
m_sneak_node(32767 ,32767 ,32767 ),
69
+ m_sneak_node_bb_top(0 ,0 ,0 ,0 ,0 ,0 ),
69
70
m_sneak_node_exists(false ),
70
71
m_need_to_get_new_sneak_node(true ),
71
- m_sneak_node_bb_top( 0 , 0 , 0 , 0 , 0 , 0 ),
72
+ m_sneak_ladder_detected( false ),
72
73
m_old_node_below(32767 ,32767 ,32767 ),
73
74
m_old_node_below_type(" air" ),
74
75
m_can_jump(false ),
@@ -91,7 +92,7 @@ LocalPlayer::~LocalPlayer()
91
92
{
92
93
}
93
94
94
- static aabb3f getTopBoundingBox (const std::vector<aabb3f> &nodeboxes, float max_d= 1 / 16 *BS )
95
+ static aabb3f getTopBoundingBox (const std::vector<aabb3f> &nodeboxes)
95
96
{
96
97
aabb3f b_max;
97
98
b_max.reset (-BS, -BS, -BS);
@@ -106,6 +107,50 @@ static aabb3f getTopBoundingBox(const std::vector<aabb3f> &nodeboxes, float max_
106
107
return aabb3f (v3f (b_max.MinEdge .X , b_max.MaxEdge .Y , b_max.MinEdge .Z ), b_max.MaxEdge );
107
108
}
108
109
110
+ #define GETNODE (map, p3, v2, y, valid ) \
111
+ (map)->getNodeNoEx((p3) + v3s16((v2).X, y, (v2).Y), valid)
112
+
113
+ // pos is the node the player is standing inside(!)
114
+ static bool detectSneakLadder(Map *map, INodeDefManager *nodemgr, v3s16 pos)
115
+ {
116
+ // Detects a structure known as "sneak ladder" or "sneak elevator"
117
+ // that relies on bugs to provide a fast means of vertical transportation,
118
+ // the bugs have since been fixed but this function remains to keep it working.
119
+ // NOTE: This is just entirely a huge hack and causes way too many problems.
120
+ bool is_valid_position;
121
+ MapNode node;
122
+ // X/Z vectors for 4 neighboring nodes
123
+ static const v2s16 vecs[] = { v2s16 (-1 , 0 ), v2s16 (1 , 0 ), v2s16 (0 , -1 ), v2s16 (0 , 1 ) };
124
+
125
+ for (u16 i = 0 ; i < ARRLEN (vecs); i++) {
126
+ const v2s16 vec = vecs[i];
127
+
128
+ // walkability of bottom & top node should differ
129
+ node = GETNODE (map, pos, vec, 0 , &is_valid_position);
130
+ if (!is_valid_position)
131
+ continue ;
132
+ bool w = nodemgr->get (node).walkable ;
133
+ node = GETNODE (map, pos, vec, 1 , &is_valid_position);
134
+ if (!is_valid_position || w == nodemgr->get (node).walkable )
135
+ continue ;
136
+
137
+ // check one more node above OR below with corresponding walkability
138
+ node = GETNODE (map, pos, vec, -1 , &is_valid_position);
139
+ bool ok = is_valid_position && w != nodemgr->get (node).walkable ;
140
+ if (!ok) {
141
+ node = GETNODE (map, pos, vec, 2 , &is_valid_position);
142
+ ok = is_valid_position && w == nodemgr->get (node).walkable ;
143
+ }
144
+
145
+ if (ok)
146
+ return true ;
147
+ }
148
+
149
+ return false ;
150
+ }
151
+
152
+ #undef GETNODE
153
+
109
154
void LocalPlayer::move (f32 dtime, Environment *env, f32 pos_max_d,
110
155
std::vector<CollisionInfo> *collision_info)
111
156
{
@@ -216,6 +261,8 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
216
261
// Max. distance (X, Z) over border for sneaking determined by collision box
217
262
// * 0.49 to keep the center just barely on the node
218
263
v3f sneak_max = m_collisionbox.getExtent () * 0.49 ;
264
+ if (m_sneak_ladder_detected)
265
+ sneak_max = v3f (0.4 * BS, 0 , 0.4 * BS); // restore legacy behaviour
219
266
220
267
/*
221
268
If sneaking, keep in range from the last walked node and don't
@@ -234,6 +281,11 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
234
281
sn_f.Z +bmin.Z - sneak_max.Z , sn_f.Z +bmax.Z + sneak_max.Z );
235
282
// Because we keep the player collision box on the node,
236
283
// limiting position.Y is not necessary
284
+
285
+ if (m_sneak_ladder_detected) {
286
+ // this sometimes causes some weird slow sinking but *shrug*
287
+ m_speed.Y = MYMAX (m_speed.Y , 0 );
288
+ }
237
289
}
238
290
239
291
if (got_teleported)
@@ -261,8 +313,6 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
261
313
bool touching_ground_was = touching_ground;
262
314
touching_ground = result.touching_ground ;
263
315
264
- // bool standing_on_unloaded = result.standing_on_unloaded;
265
-
266
316
// We want the top of the sneak node to be below the players feet
267
317
f32 position_y_mod;
268
318
if (m_sneak_node_exists)
@@ -289,14 +339,13 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
289
339
}
290
340
291
341
if (m_need_to_get_new_sneak_node && physics_override_sneak) {
292
- v3s16 pos_i_bottom = floatToInt (position - v3f (0 , position_y_mod, 0 ), BS);
293
342
v2f player_p2df (position.X , position.Z );
294
343
f32 min_distance_f = 100000.0 * BS;
295
344
v3s16 new_sneak_node = m_sneak_node;
296
345
for (s16 x=-1 ; x<=1 ; x++)
297
346
for (s16 z=-1 ; z<=1 ; z++)
298
347
{
299
- v3s16 p = pos_i_bottom + v3s16 (x,0 ,z);
348
+ v3s16 p = current_node + v3s16 (x,0 ,z);
300
349
v3f pf = intToFloat (p, BS);
301
350
v2f node_p2df (pf.X , pf.Z );
302
351
f32 distance_f = player_p2df.getDistanceFrom (node_p2df);
@@ -309,17 +358,28 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
309
358
310
359
// The node to be sneaked on has to be walkable
311
360
node = map->getNodeNoEx (p, &is_valid_position);
312
- if (!is_valid_position || nodemgr->get (node).walkable == false )
313
- continue ;
314
- // And the node above it has to be nonwalkable
315
- node = map->getNodeNoEx (p + v3s16 (0 ,1 ,0 ), &is_valid_position);
316
- if (!is_valid_position || nodemgr->get (node).walkable )
361
+ if (!is_valid_position || !nodemgr->get (node).walkable )
317
362
continue ;
363
+ // And the node(s) above have to be nonwalkable
364
+ bool ok = true ;
318
365
if (!physics_override_sneak_glitch) {
319
- node = map->getNodeNoEx (p + v3s16 (0 ,2 ,0 ), &is_valid_position);
320
- if (!is_valid_position || nodemgr->get (node).walkable )
321
- continue ;
366
+ u16 height = ceilf (
367
+ (m_collisionbox.MaxEdge .Y - m_collisionbox.MinEdge .Y ) / BS
368
+ );
369
+ for (u16 y = 1 ; y <= height; y++) {
370
+ node = map->getNodeNoEx (p + v3s16 (0 ,y,0 ), &is_valid_position);
371
+ if (!is_valid_position || nodemgr->get (node).walkable ) {
372
+ ok = false ;
373
+ break ;
374
+ }
375
+ }
376
+ } else {
377
+ // legacy behaviour: check just one node
378
+ node = map->getNodeNoEx (p + v3s16 (0 ,1 ,0 ), &is_valid_position);
379
+ ok = is_valid_position && !nodemgr->get (node).walkable ;
322
380
}
381
+ if (!ok)
382
+ continue ;
323
383
324
384
min_distance_f = distance_f;
325
385
new_sneak_node = p;
@@ -329,12 +389,17 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
329
389
m_sneak_node = new_sneak_node;
330
390
m_sneak_node_exists = sneak_node_found;
331
391
332
- // Update saved top bounding box of sneak node
333
392
if (sneak_node_found) {
393
+ // Update saved top bounding box of sneak node
334
394
MapNode n = map->getNodeNoEx (m_sneak_node);
335
395
std::vector<aabb3f> nodeboxes;
336
396
n.getCollisionBoxes (nodemgr, &nodeboxes);
337
397
m_sneak_node_bb_top = getTopBoundingBox (nodeboxes);
398
+
399
+ m_sneak_ladder_detected = physics_override_sneak_glitch &&
400
+ detectSneakLadder (map, nodemgr, floatToInt (position, BS));
401
+ } else {
402
+ m_sneak_ladder_detected = false ;
338
403
}
339
404
}
340
405
@@ -566,7 +631,7 @@ void LocalPlayer::applyControl(float dtime)
566
631
speedV.Y = movement_speed_walk;
567
632
}
568
633
}
569
- else if (m_can_jump)
634
+ else if (m_can_jump || (control. sneak && m_sneak_ladder_detected) )
570
635
{
571
636
/*
572
637
NOTE: The d value in move() affects jump height by
0 commit comments