@@ -25,16 +25,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
25
25
#include " gamedef.h"
26
26
#ifndef SERVER
27
27
#include " client/clientenvironment.h"
28
+ #include " client/localplayer.h"
28
29
#endif
29
30
#include " serverenvironment.h"
30
31
#include " serverobject.h"
31
32
#include " util/timetaker.h"
32
33
#include " profiler.h"
33
34
34
- // float error is 10 - 9.96875 = 0.03125
35
- // #define COLL_ZERO 0.032 // broken unit tests
36
- #define COLL_ZERO 0
37
-
38
35
39
36
struct NearbyCollisionInfo {
40
37
NearbyCollisionInfo (bool is_ul, bool is_obj, int bouncy,
@@ -61,118 +58,102 @@ struct NearbyCollisionInfo {
61
58
// The time after which the collision occurs is stored in dtime.
62
59
CollisionAxis axisAlignedCollision (
63
60
const aabb3f &staticbox, const aabb3f &movingbox,
64
- const v3f &speed, f32 d, f32 *dtime)
61
+ const v3f &speed, f32 *dtime)
65
62
{
66
63
// TimeTaker tt("axisAlignedCollision");
67
64
68
- f32 xsize = (staticbox.MaxEdge .X - staticbox.MinEdge .X ) - COLL_ZERO; // reduce box size for solve collision stuck (flying sand)
69
- f32 ysize = (staticbox.MaxEdge .Y - staticbox.MinEdge .Y ); // - COLL_ZERO; // Y - no sense for falling, but maybe try later
70
- f32 zsize = (staticbox.MaxEdge .Z - staticbox.MinEdge .Z ) - COLL_ZERO;
71
-
72
65
aabb3f relbox (
73
- movingbox.MinEdge .X - staticbox.MinEdge .X ,
74
- movingbox.MinEdge .Y - staticbox.MinEdge .Y ,
75
- movingbox.MinEdge .Z - staticbox.MinEdge .Z ,
76
- movingbox.MaxEdge .X - staticbox.MinEdge .X ,
77
- movingbox.MaxEdge .Y - staticbox.MinEdge .Y ,
78
- movingbox.MaxEdge .Z - staticbox.MinEdge .Z
66
+ movingbox.MaxEdge . X - movingbox. MinEdge .X + staticbox. MaxEdge . X - staticbox.MinEdge .X , // sum of the widths
67
+ movingbox.MaxEdge . Y - movingbox. MinEdge . Y + staticbox. MaxEdge .Y - staticbox.MinEdge .Y ,
68
+ movingbox.MaxEdge . Z - movingbox. MinEdge . Z + staticbox. MaxEdge .Z - staticbox.MinEdge .Z ,
69
+ std::max ( movingbox.MaxEdge .X , staticbox. MaxEdge . X ) - std::min (movingbox. MinEdge . X , staticbox.MinEdge .X ), // outer bounding 'box' dimensions
70
+ std::max ( movingbox.MaxEdge .Y , staticbox. MaxEdge . Y ) - std::min (movingbox. MinEdge . Y , staticbox.MinEdge .Y ) ,
71
+ std::max ( movingbox.MaxEdge .Z , staticbox. MaxEdge . Z ) - std::min (movingbox. MinEdge . Z , staticbox.MinEdge .Z )
79
72
);
80
73
81
- if (speed. X > 0 ) // Check for collision with X- plane
82
- {
83
- if (relbox. MaxEdge . X <= d) {
84
- *dtime = -relbox. MaxEdge . X / speed. X ;
85
- if ((relbox. MinEdge . Y + speed. Y * (*dtime) < ysize) &&
86
- (relbox. MaxEdge . Y + speed.Y * (*dtime) > COLL_ZERO) &&
87
- ( relbox.MinEdge . Z + speed. Z * (*dtime) < zsize) &&
88
- (relbox. MaxEdge . Z + speed. Z * (*dtime) > COLL_ZERO))
89
- return COLLISION_AXIS_X ;
90
- }
91
- else if (relbox. MinEdge . X > xsize)
92
- {
93
- return COLLISION_AXIS_NONE;
94
- }
95
- }
96
- else if (speed. X < 0 ) // Check for collision with X+ plane
97
- {
98
- if (relbox .MinEdge .X >= xsize - d) {
99
- *dtime = (xsize - relbox.MinEdge .X ) / speed. X ;
100
- if ((relbox. MinEdge . Y + speed.Y * (*dtime) < ysize) &&
101
- (relbox. MaxEdge . Y + speed.Y * (*dtime) > COLL_ZERO) &&
102
- ( relbox.MinEdge .Z + speed. Z * (*dtime) < zsize) &&
103
- (relbox. MaxEdge . Z + speed. Z * (*dtime) > COLL_ZERO))
104
- return COLLISION_AXIS_X;
105
- }
106
- else if (relbox. MaxEdge . X < 0 )
107
- {
108
- return COLLISION_AXIS_NONE;
74
+ const f32 dtime_max = *dtime;
75
+ const f32 inner_margin = - 1 . 5f ;
76
+ f32 distance;
77
+ f32 time ;
78
+
79
+ if ( speed.X ) {
80
+ distance = relbox.MaxEdge . X - relbox. MinEdge . X ;
81
+
82
+ *dtime = distance >= 0 ? std::abs (distance / speed. X ) : - std::abs (distance / speed. X ) ;
83
+ time = std::max (*dtime, 0 . 0f );
84
+
85
+ if (distance > inner_margin) {
86
+ if (*dtime <= dtime_max) {
87
+ if ((speed. X > 0 && staticbox. MaxEdge . X > movingbox. MaxEdge . X ) ||
88
+ (speed. X < 0 && staticbox. MinEdge . X < movingbox. MinEdge . X )) {
89
+ if (
90
+ ( std::max (movingbox. MaxEdge . Y + speed. Y * time , staticbox. MaxEdge . Y )
91
+ - std::min (movingbox .MinEdge .Y + speed. Y * time , staticbox. MinEdge . Y )
92
+ - relbox.MinEdge .Y < 0 ) &&
93
+ ( std::max (movingbox. MaxEdge . Z + speed.Z * time , staticbox. MaxEdge . Z )
94
+ - std::min (movingbox. MinEdge . Z + speed.Z * time , staticbox. MinEdge . Z )
95
+ - relbox.MinEdge .Z < 0 )
96
+ )
97
+ return COLLISION_AXIS_X;
98
+ }
99
+ } else {
100
+ return COLLISION_AXIS_NONE;
101
+ }
109
102
}
110
103
}
111
104
112
105
// NO else if here
113
106
114
- if (speed.Y > 0 ) // Check for collision with Y- plane
115
- {
116
- if (relbox.MaxEdge .Y <= d) {
117
- *dtime = -relbox.MaxEdge .Y / speed.Y ;
118
- if ((relbox.MinEdge .X + speed.X * (*dtime) < xsize) &&
119
- (relbox.MaxEdge .X + speed.X * (*dtime) > COLL_ZERO) &&
120
- (relbox.MinEdge .Z + speed.Z * (*dtime) < zsize) &&
121
- (relbox.MaxEdge .Z + speed.Z * (*dtime) > COLL_ZERO))
122
- return COLLISION_AXIS_Y;
123
- }
124
- else if (relbox.MinEdge .Y > ysize)
125
- {
126
- return COLLISION_AXIS_NONE;
127
- }
128
- }
129
- else if (speed.Y < 0 ) // Check for collision with Y+ plane
130
- {
131
- if (relbox.MinEdge .Y >= ysize - d) {
132
- *dtime = (ysize - relbox.MinEdge .Y ) / speed.Y ;
133
- if ((relbox.MinEdge .X + speed.X * (*dtime) < xsize) &&
134
- (relbox.MaxEdge .X + speed.X * (*dtime) > COLL_ZERO) &&
135
- (relbox.MinEdge .Z + speed.Z * (*dtime) < zsize) &&
136
- (relbox.MaxEdge .Z + speed.Z * (*dtime) > COLL_ZERO))
137
- return COLLISION_AXIS_Y;
138
- }
139
- else if (relbox.MaxEdge .Y < 0 )
140
- {
141
- return COLLISION_AXIS_NONE;
107
+ if (speed.Y ) {
108
+ distance = relbox.MaxEdge .Y - relbox.MinEdge .Y ;
109
+
110
+ *dtime = distance >= 0 ? std::abs (distance / speed.Y ) : -std::abs (distance / speed.Y );
111
+ time = std::max (*dtime, 0 .0f );
112
+
113
+ if (distance > inner_margin) {
114
+ if (*dtime <= dtime_max) {
115
+ if ((speed.Y > 0 && staticbox.MaxEdge .Y > movingbox.MaxEdge .Y ) ||
116
+ (speed.Y < 0 && staticbox.MinEdge .Y < movingbox.MinEdge .Y )) {
117
+ if (
118
+ (std::max (movingbox.MaxEdge .X + speed.X * time , staticbox.MaxEdge .X )
119
+ - std::min (movingbox.MinEdge .X + speed.X * time , staticbox.MinEdge .X )
120
+ - relbox.MinEdge .X < 0 ) &&
121
+ (std::max (movingbox.MaxEdge .Z + speed.Z * time , staticbox.MaxEdge .Z )
122
+ - std::min (movingbox.MinEdge .Z + speed.Z * time , staticbox.MinEdge .Z )
123
+ - relbox.MinEdge .Z < 0 )
124
+ )
125
+ return COLLISION_AXIS_Y;
126
+ }
127
+ } else {
128
+ return COLLISION_AXIS_NONE;
129
+ }
142
130
}
143
131
}
144
132
145
133
// NO else if here
146
134
147
- if (speed.Z > 0 ) // Check for collision with Z- plane
148
- {
149
- if (relbox.MaxEdge .Z <= d) {
150
- *dtime = -relbox.MaxEdge .Z / speed.Z ;
151
- if ((relbox.MinEdge .X + speed.X * (*dtime) < xsize) &&
152
- (relbox.MaxEdge .X + speed.X * (*dtime) > COLL_ZERO) &&
153
- (relbox.MinEdge .Y + speed.Y * (*dtime) < ysize) &&
154
- (relbox.MaxEdge .Y + speed.Y * (*dtime) > COLL_ZERO))
155
- return COLLISION_AXIS_Z;
156
- }
157
- // else if(relbox.MinEdge.Z > zsize)
158
- // {
159
- // return COLLISION_AXIS_NONE;
160
- // }
161
- }
162
- else if (speed.Z < 0 ) // Check for collision with Z+ plane
163
- {
164
- if (relbox.MinEdge .Z >= zsize - d) {
165
- *dtime = (zsize - relbox.MinEdge .Z ) / speed.Z ;
166
- if ((relbox.MinEdge .X + speed.X * (*dtime) < xsize) &&
167
- (relbox.MaxEdge .X + speed.X * (*dtime) > COLL_ZERO) &&
168
- (relbox.MinEdge .Y + speed.Y * (*dtime) < ysize) &&
169
- (relbox.MaxEdge .Y + speed.Y * (*dtime) > COLL_ZERO))
170
- return COLLISION_AXIS_Z;
135
+ if (speed.Z ) {
136
+ distance = relbox.MaxEdge .Z - relbox.MinEdge .Z ;
137
+
138
+ *dtime = distance >= 0 ? std::abs (distance / speed.Z ) : -std::abs (distance / speed.Z );
139
+ time = std::max (*dtime, 0 .0f );
140
+
141
+ if (distance > inner_margin) {
142
+ if (*dtime <= dtime_max) {
143
+ if ((speed.Z > 0 && staticbox.MaxEdge .Z > movingbox.MaxEdge .Z ) ||
144
+ (speed.Z < 0 && staticbox.MinEdge .Z < movingbox.MinEdge .Z )) {
145
+ if (
146
+ (std::max (movingbox.MaxEdge .X + speed.X * time , staticbox.MaxEdge .X )
147
+ - std::min (movingbox.MinEdge .X + speed.X * time , staticbox.MinEdge .X )
148
+ - relbox.MinEdge .X < 0 ) &&
149
+ (std::max (movingbox.MaxEdge .Y + speed.Y * time , staticbox.MaxEdge .Y )
150
+ - std::min (movingbox.MinEdge .Y + speed.Y * time , staticbox.MinEdge .Y )
151
+ - relbox.MinEdge .Y < 0 )
152
+ )
153
+ return COLLISION_AXIS_Z;
154
+ }
155
+ }
171
156
}
172
- // else if(relbox.MaxEdge.Z < 0)
173
- // {
174
- // return COLLISION_AXIS_NONE;
175
- // }
176
157
}
177
158
178
159
return COLLISION_AXIS_NONE;
@@ -405,22 +386,25 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
405
386
}
406
387
}
407
388
}
389
+ #ifndef SERVER
390
+ if (self && c_env) {
391
+ LocalPlayer *lplayer = c_env->getLocalPlayer ();
392
+ if (lplayer->getParent () == nullptr ) {
393
+ aabb3f lplayer_collisionbox = lplayer->getCollisionbox ();
394
+ v3f lplayer_pos = lplayer->getPosition ();
395
+ lplayer_collisionbox.MinEdge += lplayer_pos;
396
+ lplayer_collisionbox.MaxEdge += lplayer_pos;
397
+ cinfo.emplace_back (false , true , 0 , v3s16 (), lplayer_collisionbox);
398
+ }
399
+ }
400
+ #endif
408
401
} // tt3
409
402
410
403
/*
411
404
Collision detection
412
405
*/
413
406
414
- /*
415
- Collision uncertainty radius
416
- Make it a bit larger than the maximum distance of movement
417
- */
418
- f32 d = pos_max_d * 1 .1f ;
419
- // A fairly large value in here makes moving smoother
420
- // f32 d = 0.15*BS;
421
-
422
- // This should always apply, otherwise there are glitches
423
- assert (d > pos_max_d); // invariant
407
+ f32 d = 0 .0f ;
424
408
425
409
int loopcount = 0 ;
426
410
@@ -450,9 +434,9 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
450
434
continue ;
451
435
452
436
// Find nearest collision of the two boxes (raytracing-like)
453
- f32 dtime_tmp;
437
+ f32 dtime_tmp = nearest_dtime ;
454
438
CollisionAxis collided = axisAlignedCollision (box_info.box ,
455
- movingbox, *speed_f, d, &dtime_tmp);
439
+ movingbox, *speed_f, &dtime_tmp);
456
440
457
441
if (collided == -1 || dtime_tmp >= nearest_dtime)
458
442
continue ;
@@ -470,11 +454,18 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
470
454
// Otherwise, a collision occurred.
471
455
NearbyCollisionInfo &nearest_info = cinfo[nearest_boxindex];
472
456
const aabb3f& cbox = nearest_info.box ;
457
+
458
+ // movingbox except moved to the horizontal position it would be after step up
459
+ aabb3f stepbox = movingbox;
460
+ stepbox.MinEdge .X += speed_f->X * dtime;
461
+ stepbox.MinEdge .Z += speed_f->Z * dtime;
462
+ stepbox.MaxEdge .X += speed_f->X * dtime;
463
+ stepbox.MaxEdge .Z += speed_f->Z * dtime;
473
464
// Check for stairs.
474
465
bool step_up = (nearest_collided != COLLISION_AXIS_Y) && // must not be Y direction
475
466
(movingbox.MinEdge .Y < cbox.MaxEdge .Y ) &&
476
467
(movingbox.MinEdge .Y + stepheight > cbox.MaxEdge .Y ) &&
477
- (!wouldCollideWithCeiling (cinfo, movingbox ,
468
+ (!wouldCollideWithCeiling (cinfo, stepbox ,
478
469
cbox.MaxEdge .Y - movingbox.MinEdge .Y ,
479
470
d));
480
471
@@ -483,7 +474,7 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
483
474
484
475
// Move to the point of collision and reduce dtime by nearest_dtime
485
476
if (nearest_dtime < 0 ) {
486
- // Handle negative nearest_dtime (can be caused by the d allowance)
477
+ // Handle negative nearest_dtime
487
478
if (!step_up) {
488
479
if (nearest_collided == COLLISION_AXIS_X)
489
480
pos_f->X += speed_f->X * nearest_dtime;
@@ -562,9 +553,8 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
562
553
Object touches ground if object's minimum Y is near node's
563
554
maximum Y and object's X-Z-area overlaps with the node's
564
555
X-Z-area.
565
-
566
- Use 0.15*BS so that it is easier to get on a node.
567
556
*/
557
+
568
558
if (cbox.MaxEdge .X - d > box.MinEdge .X && cbox.MinEdge .X + d < box.MaxEdge .X &&
569
559
cbox.MaxEdge .Z - d > box.MinEdge .Z &&
570
560
cbox.MinEdge .Z + d < box.MaxEdge .Z ) {
@@ -574,7 +564,7 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
574
564
box.MinEdge += *pos_f;
575
565
box.MaxEdge += *pos_f;
576
566
}
577
- if (std::fabs (cbox.MaxEdge .Y - box.MinEdge .Y ) < 0 .15f * BS ) {
567
+ if (std::fabs (cbox.MaxEdge .Y - box.MinEdge .Y ) < 0 .05f ) {
578
568
result.touching_ground = true ;
579
569
580
570
if (box_info.is_object )
0 commit comments