@@ -264,7 +264,7 @@ IMPLEMENT_CALLBACK( PlayerData, onLeaveLiquid, void, ( Player* obj, const char*
264264 " @param obj The Player object\n "
265265 " @param type The type of liquid the player has left\n " );
266266
267- IMPLEMENT_CALLBACK ( PlayerData, animationDone, void , ( Player* obj, const char * animName), ( obj, animName),
267+ IMPLEMENT_CALLBACK ( PlayerData, animationDone, void , ( Player* obj,const char * animName), ( obj, animName),
268268 " @brief Called on the server when a scripted animation completes.\n\n "
269269 " @param obj The Player object\n "
270270 " @see Player::setActionThread() for setting a scripted animation and its 'hold' parameter to "
@@ -4805,7 +4805,7 @@ Point3F Player::_move( const F32 travelTime, Collision *outCol )
48054805 static Polyhedron sBoxPolyhedron ;
48064806 static ExtrudedPolyList sExtrudedPolyList ;
48074807 static ExtrudedPolyList sPhysZonePolyList ;
4808-
4808+ Vector<VectorF> norms;
48094809 for (; count < sMoveRetryCount ; count++) {
48104810 F32 speed = mVelocity .len ();
48114811 if (!speed && !mDeath .haveVelocity ())
@@ -4931,7 +4931,7 @@ Point3F Player::_move( const F32 travelTime, Collision *outCol )
49314931 mFalling = false ;
49324932
49334933 // Back off...
4934- if ( velLen > 0 . f ) {
4934+ if ( velLen > POINT_EPSILON ) {
49354935 F32 newT = getMin (0 .01f / velLen, dt);
49364936 start -= mVelocity * newT;
49374937 totalMotion -= velLen * newT;
@@ -4983,31 +4983,83 @@ Point3F Player::_move( const F32 travelTime, Collision *outCol )
49834983 // Subtract out velocity
49844984 VectorF dv = collision->normal * (bd + sNormalElasticity );
49854985 mVelocity += dv;
4986+
4987+ bool blocked = false ;
49864988 if (count == 0 )
49874989 {
49884990 firstNormal = collision->normal ;
49894991 }
49904992 else
49914993 {
4992- if (count == 1 )
4994+ bool uniqueNorm = true ;
4995+ for (U32 norm = 0 ; norm < norms.size (); norm++)
49934996 {
4994- // Re-orient velocity along the crease.
4995- if (mDot (dv,firstNormal) < 0 .0f &&
4996- mDot (collision->normal ,firstNormal) < 0 .0f )
4997+ if (mFabs (mDot (collision->normal , norms[norm])) > (1 .0f - POINT_EPSILON ))
49974998 {
4998- VectorF nv;
4999- mCross (collision->normal ,firstNormal,&nv);
5000- F32 nvl = nv.len ();
5001- if (nvl)
4999+ uniqueNorm = false ;
5000+ break ;
5001+ }
5002+ }
5003+ if (uniqueNorm)
5004+ {
5005+ VectorF n = collision->normal ;
5006+ n.normalizeSafe ();
5007+ norms.push_back (n);
5008+ }
5009+ // Use the number of unique normals to determine how to project velocity
5010+ if (norms.size () == 1 )
5011+ {
5012+ VectorF n = norms[0 ];
5013+ mVelocity -= mDot (mVelocity , n) * n;
5014+ if (mVelocity .lenSquared () < POINT_EPSILON )
5015+ blocked = true ;
5016+ }
5017+ else if (norms.size () == 2 )
5018+ {
5019+ VectorF nv;
5020+ mCross (norms[0 ], norms[1 ], &nv);
5021+ F32 nvl = nv.len ();
5022+ if (nvl > POINT_EPSILON )
5023+ {
5024+ nv /= nvl;
5025+ F32 vel = mClampF (mDot (mVelocity , nv), -speed, speed);
5026+ mVelocity = nv * vel;
5027+ if (mVelocity .lenSquared () < POINT_EPSILON )
5028+ blocked = true ;
5029+ }
5030+ else blocked = true ;
5031+ }
5032+ else // 3 or more unique normals: project off all using a Gram-Schmidt variant
5033+ {
5034+ Vector<VectorF> orthoNorms;
5035+ for (U32 i = 0 ; i < norms.size (); ++i)
5036+ {
5037+ VectorF n = norms[i];
5038+ for (U32 j = 0 ; j < orthoNorms.size (); ++j)
5039+ n -= mDot (n, orthoNorms[j]) * orthoNorms[j];
5040+ if (n.lenSquared () > POINT_EPSILON )
50025041 {
5003- if (mDot (nv,mVelocity ) < 0 .0f )
5004- nvl = -nvl;
5005- nv *= mVelocity .len () / nvl;
5006- mVelocity = nv;
5042+ n.normalize ();
5043+ orthoNorms.push_back (n);
50075044 }
50085045 }
5046+ for (U32 i = 0 ; i < orthoNorms.size (); ++i)
5047+ mVelocity -= mDot (mVelocity , orthoNorms[i]) * orthoNorms[i];
5048+ if (mVelocity .lenSquared () < POINT_EPSILON )
5049+ blocked = true ;
50095050 }
50105051 }
5052+ if (blocked)
5053+ {
5054+ mVelocity .zero ();
5055+ return start;
5056+ }
5057+ F32 newSpeed = mVelocity .len ();
5058+ if (newSpeed > speed)
5059+ {
5060+ mVelocity .normalize ();
5061+ mVelocity *= speed;
5062+ }
50115063 }
50125064 else
50135065 {
@@ -5017,7 +5069,7 @@ Point3F Player::_move( const F32 travelTime, Collision *outCol )
50175069 }
50185070 }
50195071
5020- if (count == sMoveRetryCount )
5072+ if (count == sMoveRetryCount || mVelocity . lenSquared () < POINT_EPSILON )
50215073 {
50225074 // Failed to move
50235075 start = initialPosition;
0 commit comments