From b907f8978ab96eed95d55ef930ad5cbede45bc5c Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Sat, 11 Feb 2012 01:08:47 -0500 Subject: [PATCH 1/7] Fix landing behaviors Looks like Cyan broke these when they fixed superjumps. It appears that LinearVelocity is only good while the PhysicalControllerCore is updating, and it stashes the result for later so nothing else can touch it. Regardless, we need to test AchievedLinearVelocity outside of the update proc. --- Sources/Plasma/PubUtilLib/plAvatar/plAvCallbackAction.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Sources/Plasma/PubUtilLib/plAvatar/plAvCallbackAction.cpp b/Sources/Plasma/PubUtilLib/plAvatar/plAvCallbackAction.cpp index c59b5f4f..235c3450 100644 --- a/Sources/Plasma/PubUtilLib/plAvatar/plAvCallbackAction.cpp +++ b/Sources/Plasma/PubUtilLib/plAvatar/plAvCallbackAction.cpp @@ -133,8 +133,10 @@ void plWalkingController::RecalcVelocity(double timeNow, double timePrev, hsBool if (fController && !fWalkingStrategy->IsOnGround()) { + // PhysX Hack: AchievedLinearVelocity is a Cyanic fix for superjumps. LinearVelocity is + // always (0,0,0) outside of the controller update proc fImpactTime = fWalkingStrategy->GetAirTime(); - fImpactVelocity = fController->GetLinearVelocity(); + fImpactVelocity = fController->GetAchievedLinearVelocity(); fClearImpact = false; } else From 0689901c5ee055376b91616f94341ee22a1360e9 Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Sat, 11 Feb 2012 01:18:29 -0500 Subject: [PATCH 2/7] Band-aid for poorly modelled stairs Looks like the Cyan modellers didn't extend the stair ramps all the way down in some places. To compensate, we can now take higher steps but can't walk on slopes quite as steep as before. I think this should balance out nicely. --- .../PubUtilLib/plAvatar/plPhysicalControllerCore.h | 2 +- .../PubUtilLib/plPhysX/plPXPhysicalControllerCore.cpp | 10 +++------- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.h b/Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.h index c8415ef1..00f6ce31 100644 --- a/Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.h +++ b/Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.h @@ -50,7 +50,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "hsQuat.h" #define PHYSX_ONLY_TRIGGER_FROM_KINEMATIC 1 -#define kSLOPELIMIT (cosf(hsDegreesToRadians(55.f))) +#define kSLOPELIMIT (cosf(hsDegreesToRadians(45.f))) class plCoordinateInterface; class plPhysical; diff --git a/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalControllerCore.cpp b/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalControllerCore.cpp index d213fc18..0d09739d 100644 --- a/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalControllerCore.cpp +++ b/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalControllerCore.cpp @@ -71,13 +71,8 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #define kPhysxSkinWidth 0.1f #define kPhysZOffset ((fRadius + (fHeight / 2)) + kPhysxSkinWidth) -//#define kSLOPELIMIT (cosf(NxMath::degToRad(55.f))) -//#define kPhysicalHeightFudge 0.4f // this fudge was used for PhysX 2.4 #define kPhysicalHeightFudge 0.0f - -//#define STEP_OFFSET 1.0f -#define STEP_OFFSET 0.5f -//#define STEP_OFFSET 0.15f +#define STEP_OFFSET 1.f #ifndef PLASMA_EXTERNAL_RELEASE @@ -99,9 +94,9 @@ public: plPXPhysicalControllerCore* ac = plPXPhysicalControllerCore::FindController(hit.controller); NxActor& actor = hit.shape->getActor(); plPXPhysical* phys = (plPXPhysical*)actor.userData; - static float SlopeLimit = kSLOPELIMIT; hsVector3 normal = plPXConvert::Vector(hit.worldNormal); ac->fMovementInterface->IAddContactNormals(normal); + #ifndef PLASMA_EXTERNAL_RELEASE plDbgCollisionInfo info; info.fNormal = normal; @@ -124,6 +119,7 @@ public: } ac->fDbgCollisionInfo.Append(info); #endif PLASMA_EXTERNAL_RELEASE + // If the avatar hit a movable physical, apply some force to it. hsVector3 dir = plPXConvert::Vector(hit.dir); float dirdotup=dir.fZ; From 8ec1a92359aec43b690a058fe976a3fbe53c5ee3 Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Sat, 11 Feb 2012 01:21:06 -0500 Subject: [PATCH 3/7] Rewrite kickable force stuff... Cyan's old code was confusing and would allow you to walk on top of small kickables. Now, we impart force to these small kickables up to a certain point where imparting force to them becomes somewhat risky. --- .../plPhysX/plPXPhysicalControllerCore.cpp | 66 +++++-------------- 1 file changed, 18 insertions(+), 48 deletions(-) diff --git a/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalControllerCore.cpp b/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalControllerCore.cpp index 0d09739d..78b9b2aa 100644 --- a/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalControllerCore.cpp +++ b/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalControllerCore.cpp @@ -73,6 +73,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #define kPhysZOffset ((fRadius + (fHeight / 2)) + kPhysxSkinWidth) #define kPhysicalHeightFudge 0.0f #define STEP_OFFSET 1.f +#define kAvatarMass 160.f #ifndef PLASMA_EXTERNAL_RELEASE @@ -84,8 +85,6 @@ static ControllerManager gControllerMgr; static std::vector gControllers; static bool gRebuildCache=false; -#define AvatarMass 200.f - class PXControllerHitReportWalk : public NxUserControllerHitReport { public: @@ -127,15 +126,16 @@ public: NxExtendedVec3 controllerPos=hit.controller->getPosition(); hsVector3 bottomOfTheCapsule((float)controllerPos.x,(float)controllerPos.y,(float)controllerPos.z); bottomOfTheCapsule.fZ=bottomOfTheCapsule.fZ-(ac->fHeight/2.0f + ac->fRadius); - if (actor.isDynamic() ) + if (actor.isDynamic() && phys ) { if((hit.worldPos.z- bottomOfTheCapsule.fZ)<=ac->fRadius)//bottom hemisphere { - //onTopOfSlopeLimit - if (phys && phys->GetProperty(plSimulationInterface::kPhysAnim)) + // If this is an animated physical, we can stand on it + if (phys->GetProperty(plSimulationInterface::kPhysAnim)) { if(normal.fZ>=0) - {//we consider this ground + { + //we consider this ground ac->fMovementInterface->AddOnTopOfObject(phys); } } @@ -157,52 +157,22 @@ public: setNetGroupID->Send(obj->GetKey()); } plSimulationMgr::GetInstance()->ConsiderSynch(phys, nil); - // We only allow horizontal pushes. Vertical pushes when we stand on - // dynamic objects creates useless stress on the solver. - - hsVector3 vel=ac->GetLinearVelocity()- plPXConvert::Vector( actor.getLinearVelocity()); - if(dirdotup>=0)vel.fZ=0.001f; - else vel.fZ=0.0f; - static float kAvieMass = 140.f/32.f; - if (!vel.IsEmpty()) - { - static float kForceScale = 140.0f; - NxF32 coeff; - NxExtendedVec3 norm2=hit.controller->getPosition(); - norm2.x=hit.worldPos.x-bottomOfTheCapsule.fX; - norm2.y=hit.worldPos.y-bottomOfTheCapsule.fY; - if((hit.worldPos.z- bottomOfTheCapsule.fZ)fRadius)//bottom hemisphere - { - norm2.normalize(); - norm2.z=0.01f; - } - else if((hit.worldPos.z- bottomOfTheCapsule.fZ)<(ac->fRadius+ac->fHeight)) - { - norm2.z=0.0f; - norm2.normalize(); - } - else - {//must be the top so the normal is displacement from the pos - center - //of top hemisphere - norm2.z=hit.worldPos.z - ((ac->fRadius+ac->fHeight + bottomOfTheCapsule.fZ)); - norm2.normalize(); - } - - - float proj=(float)(norm2.x*dir.fX+dir.fY*norm2.y+dir.fZ*norm2.z); - coeff =abs(proj*kForceScale*vel.Magnitude()); - vel.fZ=(float)norm2.z; - vel.fY=(float)norm2.y; - vel.fX=(float)norm2.x; - phys->SetHitForce(vel*coeff, pos); - } + + // Now, let's impart some force, fool. + // Note: This is a VERY simple implementation. The old one was too hacky and caused weird stuff to happen. + hsVector3 acceleration = (ac->GetLinearVelocity() - plPXConvert::Vector(actor.getLinearVelocity())); + hsVector3 force2impart = acceleration * kAvatarMass; + // Bad things happen if we impart force directly on top of the actor, so let's allow the avatar to run + // over those physicals and not break them. This is mostly an issue with stuff smaller than step size. + if (!force2impart.IsEmpty() && normal.fZ < .90f) + phys->SetHitForce(force2impart, pos); } } else // else if the avatar hit a static { return NX_ACTION_NONE; } - if (phys && phys->GetProperty(plSimulationInterface::kAvAnimPushable)) + if (phys->GetProperty(plSimulationInterface::kAvAnimPushable)) { hsQuat inverseRotation = ac->fLocalRotation.Inverse(); hsVector3 normal = plPXConvert::Vector(hit.worldNormal); @@ -542,7 +512,7 @@ NxScene* scene = plSimulationMgr::GetInstance()->GetScene(fWorldKey); capDesc.materialIndex= plSimulationMgr::GetInstance()->GetMaterialIdx(scene, 0.0,0.0); actorDesc.shapes.pushBack(&capDesc); NxBodyDesc bodyDesc; - bodyDesc.mass = AvatarMass;//1.f; + bodyDesc.mass = kAvatarMass; actorDesc.body = &bodyDesc; bodyDesc.flags = NX_BF_KINEMATIC; bodyDesc.flags |=NX_BF_DISABLE_GRAVITY ; @@ -615,7 +585,7 @@ void plPXPhysicalControllerCore::ICreateController(const hsPoint3& pos) capDesc.materialIndex= plSimulationMgr::GetInstance()->GetMaterialIdx(scene, 0.0,0.0); actorDesc.globalPose=actor->getGlobalPose(); NxBodyDesc bodyDesc; - bodyDesc.mass = AvatarMass; + bodyDesc.mass = kAvatarMass; actorDesc.body = &bodyDesc; bodyDesc.flags = NX_BF_KINEMATIC; bodyDesc.flags |=NX_BF_DISABLE_GRAVITY ; From 9795b4e7fcde3071c9ecbfaf5db17f07bfd52f17 Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Sat, 11 Feb 2012 17:25:11 -0500 Subject: [PATCH 4/7] Fix unsafe cleanup in ~plCameraRegionDetector Deleting an hsRefCnt is evil, we should ALWAYS hsRefCnt_SafeUnRef (we might have a nullptr) it because someone might ref it. hsRefCnt will explictly crash if you delete it when the refcnt != 1. Also, take this opportunity to vector-ize things. --- .../plPhysical/plCollisionDetector.cpp | 25 ++++++++----------- .../plPhysical/plCollisionDetector.h | 6 +++-- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/Sources/Plasma/PubUtilLib/plPhysical/plCollisionDetector.cpp b/Sources/Plasma/PubUtilLib/plPhysical/plCollisionDetector.cpp index 84ef6799..761db0e3 100644 --- a/Sources/Plasma/PubUtilLib/plPhysical/plCollisionDetector.cpp +++ b/Sources/Plasma/PubUtilLib/plPhysical/plCollisionDetector.cpp @@ -236,13 +236,8 @@ void plCollisionDetector::Write(hsStream* stream, hsResMgr* mgr) plCameraRegionDetector::~plCameraRegionDetector() { - for(int i = 0; i < fMessages.Count(); i++) - { - plMessage* pMsg = fMessages[i]; - fMessages.Remove(i); - delete(pMsg); - } - fMessages.SetCountAndZero(0); + for (plCameraMsgVec::iterator it = fMessages.begin(); it != fMessages.end(); ++it) + hsRefCnt_SafeUnRef(*it); } void plCameraRegionDetector::ITrigger(plKey hitter, bool entering, bool immediate) @@ -314,7 +309,7 @@ void plCameraRegionDetector::ISendSavedTriggerMsgs() { if (fSavingSendMsg) { - for (int i = 0; i < fMessages.Count(); i++) + for (size_t i = 0; i < fMessages.size(); ++i) { char str[256]; @@ -322,13 +317,13 @@ void plCameraRegionDetector::ISendSavedTriggerMsgs() if (fSavedMsgEnterFlag) { fMessages[i]->SetCmd(plCameraMsg::kEntering); - sprintf(str, "Entering cameraRegion: %s - Evals=%d -msg %d of %d\n", GetKeyName().c_str(),fNumEvals,i+1,fMessages.Count()); + sprintf(str, "Entering cameraRegion: %s - Evals=%d -msg %d of %d\n", GetKeyName().c_str(),fNumEvals,i+1,fMessages.size()); fIsInside = true; } else { fMessages[i]->ClearCmd(plCameraMsg::kEntering); - sprintf(str, "Exiting cameraRegion: %s - Evals=%d -msg %d of %d\n", GetKeyName().c_str(),fNumEvals,i+1,fMessages.Count()); + sprintf(str, "Exiting cameraRegion: %s - Evals=%d -msg %d of %d\n", GetKeyName().c_str(),fNumEvals,i+1,fMessages.size()); fIsInside = false; } plgDispatch::MsgSend(fMessages[i]); @@ -372,8 +367,8 @@ void plCameraRegionDetector::Read(hsStream* stream, hsResMgr* mgr) { plDetectorModifier::Read(stream, mgr); int n = stream->ReadLE32(); - fMessages.SetCountAndZero(n); - for(int i = 0; i < n; i++ ) + fMessages.resize(n); + for(size_t i = 0; i < n; i++ ) { plCameraMsg* pMsg = plCameraMsg::ConvertNoRef(mgr->ReadCreatable(stream)); fMessages[i] = pMsg; @@ -383,9 +378,9 @@ void plCameraRegionDetector::Read(hsStream* stream, hsResMgr* mgr) void plCameraRegionDetector::Write(hsStream* stream, hsResMgr* mgr) { plDetectorModifier::Write(stream, mgr); - stream->WriteLE32(fMessages.GetCount()); - for(int i = 0; i < fMessages.GetCount(); i++ ) - mgr->WriteCreatable( stream, fMessages[i] ); + stream->WriteLE32(fMessages.size()); + for(plCameraMsgVec::iterator it = fMessages.begin(); it != fMessages.end(); ++it) + mgr->WriteCreatable( stream, *it ); } void plCameraRegionDetector::IHandleEval(plEvalMsg *pEval) diff --git a/Sources/Plasma/PubUtilLib/plPhysical/plCollisionDetector.h b/Sources/Plasma/PubUtilLib/plPhysical/plCollisionDetector.h index 8333b663..5600a442 100644 --- a/Sources/Plasma/PubUtilLib/plPhysical/plCollisionDetector.h +++ b/Sources/Plasma/PubUtilLib/plPhysical/plCollisionDetector.h @@ -177,7 +177,9 @@ public: class plCameraRegionDetector : public plObjectInVolumeDetector { protected: - hsTArray fMessages; + typedef std::vector plCameraMsgVec; + + plCameraMsgVec fMessages; bool fIsInside; bool fSavingSendMsg; bool fSavedMsgEnterFlag; @@ -193,7 +195,7 @@ public: ~plCameraRegionDetector(); virtual hsBool MsgReceive(plMessage* msg); - void AddMessage(plCameraMsg* pMsg) { fMessages.Append(pMsg); } + void AddMessage(plCameraMsg* pMsg) { fMessages.push_back(pMsg); } CLASSNAME_REGISTER( plCameraRegionDetector ); GETINTERFACE_ANY( plCameraRegionDetector, plCollisionDetector ); From 1b0e139ae5727895670b4823d143ed76e93ac29c Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Sat, 11 Feb 2012 19:46:32 -0500 Subject: [PATCH 5/7] Only send out one collide msg per frame This addresses a "PhysX turd" that some Cyan programmer noted in plCollisionDetector. Cleaning up that cruft is pending... --- .../PubUtilLib/plPhysX/plSimulationMgr.cpp | 55 +++++++++++++------ .../PubUtilLib/plPhysX/plSimulationMgr.h | 9 ++- 2 files changed, 47 insertions(+), 17 deletions(-) diff --git a/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.cpp b/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.cpp index 051c4761..bc0e7b0b 100644 --- a/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.cpp +++ b/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.cpp @@ -156,7 +156,7 @@ class SensorReport : public NxUserTriggerReport { if (plSimulationMgr::fExtraProfile) DetectorLogRed("-->Send Collision (CH) %s %s",triggerPhys->GetObjectKey()->GetName().c_str(),status & NX_TRIGGER_ON_ENTER ? "enter" : "exit"); - SendCollisionMsg(triggerPhys->GetObjectKey(), otherKey, true); + plSimulationMgr::GetInstance()->AddCollisionMsg(triggerPhys->GetObjectKey(), otherKey, true); } else if (status & NX_TRIGGER_ON_ENTER) { @@ -167,7 +167,7 @@ class SensorReport : public NxUserTriggerReport { if (plSimulationMgr::fExtraProfile) DetectorLogRed("-->Send Collision (CH) %s %s",triggerPhys->GetObjectKey()->GetName().c_str(),status & NX_TRIGGER_ON_ENTER ? "enter" : "exit"); - SendCollisionMsg(triggerPhys->GetObjectKey(), otherKey, false); + plSimulationMgr::GetInstance()->AddCollisionMsg(triggerPhys->GetObjectKey(), otherKey, false); } else if (status & NX_TRIGGER_ON_LEAVE) { @@ -187,13 +187,13 @@ class SensorReport : public NxUserTriggerReport { if (plSimulationMgr::fExtraProfile) DetectorLogRed("-->Send Collision %s %s",triggerPhys->GetObjectKey()->GetName().c_str(),status & NX_TRIGGER_ON_ENTER ? "enter" : "exit"); - SendCollisionMsg(triggerPhys->GetObjectKey(), otherKey, true); + plSimulationMgr::GetInstance()->AddCollisionMsg(triggerPhys->GetObjectKey(), otherKey, true); } if (status & NX_TRIGGER_ON_LEAVE) { if (plSimulationMgr::fExtraProfile) DetectorLogRed("-->Send Collision %s %s",triggerPhys->GetObjectKey()->GetName().c_str(),status & NX_TRIGGER_ON_ENTER ? "enter" : "exit"); - SendCollisionMsg(triggerPhys->GetObjectKey(), otherKey, false); + plSimulationMgr::GetInstance()->AddCollisionMsg(triggerPhys->GetObjectKey(), otherKey, false); } if (!(status & NX_TRIGGER_ON_ENTER) && !(status & NX_TRIGGER_ON_LEAVE) ) { @@ -205,18 +205,6 @@ class SensorReport : public NxUserTriggerReport #endif // USE_PHYSX_CONVEXHULL_WORKAROUND } } - - void SendCollisionMsg(plKey receiver, plKey hitter, hsBool entering) - { - DetectorLogYellow("Collision: %s was triggered by %s. Sending an %s msg", receiver->GetName().c_str(), - hitter ? hitter->GetName().c_str() : "(nil)" , entering ? "'enter'" : "'exit'"); - plCollideMsg* msg = new plCollideMsg; - msg->fOtherKey = hitter; - msg->fEntering = entering; - msg->AddReceiver(receiver); - plgDispatch::Dispatch()->MsgQueue(msg); // Sends the msg on the next client update - } - } gSensorReport; // This gets called by PhysX whenever two actor groups that are set to report @@ -599,6 +587,32 @@ void plSimulationMgr::UpdateAvatarInDetector(plKey world, plPXPhysical* detector } } +void plSimulationMgr::AddCollisionMsg(plKey hitee, plKey hitter, bool enter) +{ + // First, make sure we have no dupes + for (CollisionVec::iterator it = fCollideMsgs.begin(); it != fCollideMsgs.end(); ++it) + { + plCollideMsg* pMsg = *it; + + // Should only ever be one receiver. + // If there's more than one, you suck. + if (pMsg->fOtherKey == hitter && pMsg->GetReceiver(0) == hitee) + { + DetectorLogRed("DUPE: %s hit %s", + (hitter ? hitter->GetName().c_str() : "(nil)"), + (hitee ? hitee->GetName().c_str() : "(nil)")); + return; + } + } + + // Still here? Then this must be a unique hit! + plCollideMsg* pMsg = new plCollideMsg; + pMsg->AddReceiver(hitee); + pMsg->fOtherKey = hitter; + pMsg->fEntering = enter; + fCollideMsgs.push_back(pMsg); +} + void plSimulationMgr::Advance(float delSecs) { if (fSuspended) @@ -693,6 +707,15 @@ void plSimulationMgr::Advance(float delSecs) void plSimulationMgr::ISendUpdates() { + for (CollisionVec::iterator it = fCollideMsgs.begin(); it != fCollideMsgs.end(); ++it) + { + plCollideMsg* pMsg = *it; + DetectorLogYellow("Collision: %s was triggered by %s. Sending an %s msg", pMsg->GetReceiver(0)->GetName().c_str(), + pMsg->fOtherKey ? pMsg->fOtherKey->GetName().c_str() : "(nil)" , pMsg->fEntering ? "'enter'" : "'exit'"); + plgDispatch::Dispatch()->MsgSend(pMsg); + } + fCollideMsgs.clear(); + SceneMap::iterator it = fScenes.begin(); for (; it != fScenes.end(); it++) { diff --git a/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.h b/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.h index 2a75d943..d25ae4ac 100644 --- a/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.h +++ b/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.h @@ -102,11 +102,14 @@ public: // PHYSX FIXME - walk thru all the convex hull detector regions to see if we are in any... we're either coming or going void UpdateDetectorsInScene(plKey world, plKey avatar, hsPoint3& pos, bool entering); void UpdateAvatarInDetector(plKey world, plPXPhysical* detector); + //Fix to Move collision messages and their handling out of the simulation step - void AddCollisionMsg(plCollideMsg* msg); + void AddCollisionMsg(plKey hitee, plKey hitter, bool entering); + #ifndef PLASMA_EXTERNAL_RELEASE static bool fDisplayAwakeActors; #endif //PLASMA_EXTERNAL_RELEASE + protected: friend class ContactReport; @@ -125,6 +128,10 @@ protected: plPhysicsSoundMgr* fSoundMgr; + // Pending collision messages + typedef std::vector CollisionVec; + CollisionVec fCollideMsgs; + // A mapping from a key to a PhysX scene. The key is either the // SimulationMgr key, for the main world, or a SceneObject key if it's a // subworld. From 7dcf2e66a328545dc01e045c23c17263b9a37ca6 Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Sat, 11 Feb 2012 22:22:22 -0500 Subject: [PATCH 6/7] Greatly simplify collision detectors --- .../PubUtilLib/plPhysX/plSimulationMgr.cpp | 6 +- .../plPhysical/plCollisionDetector.cpp | 348 ++---------------- .../plPhysical/plCollisionDetector.h | 59 +-- 3 files changed, 51 insertions(+), 362 deletions(-) diff --git a/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.cpp b/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.cpp index bc0e7b0b..97454212 100644 --- a/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.cpp +++ b/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.cpp @@ -595,10 +595,12 @@ void plSimulationMgr::AddCollisionMsg(plKey hitee, plKey hitter, bool enter) plCollideMsg* pMsg = *it; // Should only ever be one receiver. - // If there's more than one, you suck. + // Oh, it seems we should update the hit status. The latest might be different than the older... + // Even in the same frame >.< if (pMsg->fOtherKey == hitter && pMsg->GetReceiver(0) == hitee) { - DetectorLogRed("DUPE: %s hit %s", + pMsg->fEntering = enter; + DetectorLogRed("DUPLICATE COLLISION: %s hit %s", (hitter ? hitter->GetName().c_str() : "(nil)"), (hitee ? hitee->GetName().c_str() : "(nil)")); return; diff --git a/Sources/Plasma/PubUtilLib/plPhysical/plCollisionDetector.cpp b/Sources/Plasma/PubUtilLib/plPhysical/plCollisionDetector.cpp index 761db0e3..57a3648d 100644 --- a/Sources/Plasma/PubUtilLib/plPhysical/plCollisionDetector.cpp +++ b/Sources/Plasma/PubUtilLib/plPhysical/plCollisionDetector.cpp @@ -242,67 +242,28 @@ plCameraRegionDetector::~plCameraRegionDetector() void plCameraRegionDetector::ITrigger(plKey hitter, bool entering, bool immediate) { - -#ifdef USE_PHYSX_COLLISION_FLUTTER_WORKAROUND - // PHYSX_FIXME hack for PhysX turd that sends bunches of enter/exits over one frame - if (entering && fNumEvals - fLastExitEval <= 1 && fSavingSendMsg) - { - DetectorLog("%s: Skipping Camera Entering volume", GetKeyName().c_str()); - fLastEnterEval = fNumEvals; - if (fSavingSendMsg) - { - DetectorLog("%s: Dumping saved Camera Exiting volume", GetKeyName().c_str()); - } - fSavingSendMsg = false; - return; - } - if (!entering && fNumEvals - fLastEnterEval <= 1 && fSavingSendMsg) - { - DetectorLog("%s: Skipping Exiting volume", GetKeyName().c_str()); - fLastExitEval = fNumEvals; - if (fSavingSendMsg) - { - DetectorLog("%s: Dumping saved Camera Entering volume", GetKeyName().c_str()); - } - fSavingSendMsg = false; - return; - } - - // get rid of any saved messages... this should happen though if (fSavingSendMsg) - { - DetectorLog("%s: Killing saved camera message... shouldn't happen", GetKeyName().c_str()); - } - // end PHYSX_FIXME hack for PhysX turd that sends bunches of enter/exits over one frame -#endif // USE_PHYSX_COLLISION_FLUTTER_WORKAROUND + DetectorLogRed("%s: Stale messages on ITrigger. This should never happen!", GetKeyName().c_str()); + if (fIsInside && entering) + DetectorLogRed("%s: Duplicate enter! Did we miss an exit?", GetKeyName().c_str()); + else if (!fIsInside && !entering) + DetectorLogRed("%s: Duplicate exit! Did we miss an enter?", GetKeyName().c_str()); fSavingSendMsg = true; fSavedMsgEnterFlag = entering; if (entering) { - //DetectorLog("%s: Saving camera Entering volume - Evals=%d", GetKeyName().c_str(),fNumEvals); + DetectorLog("%s: Saving camera Entering volume - Evals=%d", GetKeyName().c_str(),fNumEvals); fLastEnterEval = fNumEvals; } else { - //DetectorLog("%s: Saving camera Exiting volume - Evals=%d", GetKeyName().c_str(),fNumEvals); + DetectorLog("%s: Saving camera Exiting volume - Evals=%d", GetKeyName().c_str(),fNumEvals); fLastExitEval = fNumEvals; } -#ifdef USE_PHYSX_COLLISION_FLUTTER_WORKAROUND - // PHYSX_FIXME hack for PhysX turd that sends bunches of enter/exits over one frame - // we're saving the message to be dispatched later... if (immediate) - { -#endif // USE_PHYSX_COLLISION_FLUTTER_WORKAROUND - ISendSavedTriggerMsgs(); - -#ifdef USE_PHYSX_COLLISION_FLUTTER_WORKAROUND - } -#endif // USE_PHYSX_COLLISION_FLUTTER_WORKAROUND - - } void plCameraRegionDetector::ISendSavedTriggerMsgs() @@ -311,23 +272,20 @@ void plCameraRegionDetector::ISendSavedTriggerMsgs() { for (size_t i = 0; i < fMessages.size(); ++i) { - char str[256]; - hsRefCnt_SafeRef(fMessages[i]); if (fSavedMsgEnterFlag) { fMessages[i]->SetCmd(plCameraMsg::kEntering); - sprintf(str, "Entering cameraRegion: %s - Evals=%d -msg %d of %d\n", GetKeyName().c_str(),fNumEvals,i+1,fMessages.size()); + DetectorLog("Entering cameraRegion: %s - Evals=%d -msg %d of %d\n", GetKeyName().c_str(),fNumEvals,i+1,fMessages.size()); fIsInside = true; } else { fMessages[i]->ClearCmd(plCameraMsg::kEntering); - sprintf(str, "Exiting cameraRegion: %s - Evals=%d -msg %d of %d\n", GetKeyName().c_str(),fNumEvals,i+1,fMessages.size()); + DetectorLog("Exiting cameraRegion: %s - Evals=%d -msg %d of %d\n", GetKeyName().c_str(),fNumEvals,i+1,fMessages.size()); fIsInside = false; } plgDispatch::MsgSend(fMessages[i]); - DetectorLog("%s", str); } } fSavingSendMsg = false; @@ -337,30 +295,15 @@ void plCameraRegionDetector::ISendSavedTriggerMsgs() hsBool plCameraRegionDetector::MsgReceive(plMessage* msg) { plCollideMsg* pCollMsg = plCollideMsg::ConvertNoRef(msg); - if (pCollMsg) { // camera collisions are only for the local player if (plNetClientApp::GetInstance()->GetLocalPlayerKey() != pCollMsg->fOtherKey) return true; - - -#ifdef USE_PHYSX_MULTIPLE_CAMREGION_ENTER - // first determine if this is a multiple camera region enter (PHYSX BUG WORKAROUND) - if (!fWaitingForEval) - {//plObjectInVolumeCollisionDetector::MsgReceive() will flip fWaitingForEval - // and registers for the Eval, child objects of plObjectInVolumeCollisionDetector - //must decide when they are no longer interested in Evals. I suggest using IHandleEvals() - - fNumEvals = 0; - fLastEnterEval=-999; - fLastExitEval=-999; - } - - // end of (PHYSX BUG WORKAROUND) -#endif // USE_PHYSX_MULTIPLE_CAMREG_ENTER - + // Fall through to plObjectInVolumeDetector, which will register us for plEvalMsg + // and handle it for us. (Hint: See ISendSavedTriggerMsgs) } + return plObjectInVolumeDetector::MsgReceive(msg); } void plCameraRegionDetector::Read(hsStream* stream, hsResMgr* mgr) @@ -383,23 +326,6 @@ void plCameraRegionDetector::Write(hsStream* stream, hsResMgr* mgr) mgr->WriteCreatable( stream, *it ); } -void plCameraRegionDetector::IHandleEval(plEvalMsg *pEval) -{ - fNumEvals++; - if (fNumEvals - fLastEnterEval > 1 && fNumEvals-fLastExitEval>1) - { - ISendSavedTriggerMsgs(); - plgDispatch::Dispatch()->UnRegisterForExactType(plEvalMsg::Index(), GetKey()); - fWaitingForEval = false; - } - else - { - if(fSavedActivatorMsg) - DetectorLog("%s didn't send its message. fNumEvals=%d fLastEnterEval=%d, fLastExit=%d", - GetKeyName().c_str(),fNumEvals, fLastEnterEval, fLastExitEval); - - } -} ///////////////////////////////// ///////////////////////////////// @@ -409,127 +335,8 @@ void plCameraRegionDetector::IHandleEval(plEvalMsg *pEval) void plObjectInVolumeDetector::ITrigger(plKey hitter, bool entering, bool immediate) { -#ifdef USE_PHYSX_COLLISION_FLUTTER_WORKAROUND - // PHYSX_FIXME hack for PhysX turd that sends bunches of enter/exits over one frame -/* if (entering && fNumEvals - fLastExitEval <= 1 && fSavedActivatorMsg) - { - //DetectorLog("%s: Skipping Entering volume", GetKeyName()); - fLastEnterEval = fNumEvals; - if (fSavedActivatorMsg) - { - //DetectorLog("%s: Dumping saved Exiting volume", GetKeyName()); - delete fSavedActivatorMsg; - } - fSavedActivatorMsg = nil; - return; - } - if (!entering && fNumEvals - fLastEnterEval <= 1 && fSavedActivatorMsg) - { - //DetectorLog("%s: Skipping Exiting volume", GetKeyName()); - fLastExitEval = fNumEvals; - if (fSavedActivatorMsg) - { - //DetectorLog("%s: Dumping saved Entering volume", GetKeyName()); - delete fSavedActivatorMsg; - } - fSavedActivatorMsg = nil; - return; - } - - // get rid of any saved messages... this should happen though - if (fSavedActivatorMsg) - { - delete fSavedActivatorMsg; - DetectorLog("%s: Killing saved message... shouldn't happen", GetKeyName()); - } - // end PHYSX_FIXME hack for PhysX turd that sends bunches of enter/exits over one frame -*/ - if(!immediate) - { - - bookKeepingList::iterator curit=fCollisionList.begin(); - while(curit!=fCollisionList.end()) - { - if(hitter==(*curit)->hitter) - {//hey the object is already in my list - //try and figure out what my real state is - if(entering) - { - (*curit)->enters++; - if(!(*curit)->fSubStepCurState) - {//We weren't already in - (*curit)->fSubStepCurState =true; - } - } - else - { - (*curit)->exits++; - if((*curit)->fSubStepCurState) - {//We were already in - (*curit)->fSubStepCurState =false; - } - } - //get out - break; - } - curit++; - } - if(curit==fCollisionList.end()) - { - //hitter was not in the list add him in - //hitter was not in the current frame list - //lets find out its state in the begining of the frame - ResidentSet::iterator curres = fCurrentResidents.find(hitter); - bool initialState; - if(curres != fCurrentResidents.end()) - initialState =true; - else - initialState =false; - - plCollisionBookKeepingInfo* BookKeeper=new plCollisionBookKeepingInfo(hitter); - if(entering) - { - BookKeeper->enters++; - BookKeeper->fSubStepCurState =true; - } - else - { - BookKeeper->exits++; - BookKeeper->fSubStepCurState =false; - } - fCollisionList.push_front(BookKeeper); - } - - - } - else - { - plActivatorMsg* ActivatorMsg = new plActivatorMsg; - ActivatorMsg->AddReceivers(fReceivers); - if (fProxyKey) - ActivatorMsg->fHiteeObj = fProxyKey; - else - ActivatorMsg->fHiteeObj = GetTarget()->GetKey(); - - ActivatorMsg->fHitterObj = hitter; - ActivatorMsg->SetSender(GetKey()); - if (entering) - { - ActivatorMsg->SetTriggerType(plActivatorMsg::kVolumeEnter); - } - else - { - ActivatorMsg->SetTriggerType(plActivatorMsg::kVolumeExit); - } - - plgDispatch::MsgSend(ActivatorMsg); - - - } -#endif // USE_PHYSX_COLLISION_FLUTTER_WORKAROUND - -/* fSavedActivatorMsg = new plActivatorMsg; - + hsRefCnt_SafeUnRef(fSavedActivatorMsg); + fSavedActivatorMsg = new plActivatorMsg; fSavedActivatorMsg->AddReceivers(fReceivers); if (fProxyKey) @@ -542,47 +349,36 @@ void plObjectInVolumeDetector::ITrigger(plKey hitter, bool entering, bool immedi if (entering) { - //DetectorLog("%s: Saving Entering volume - Evals=%d", GetKeyName(),fNumEvals); + DetectorLog("%s: Saving Entering volume - Evals=%d", GetKeyName().c_str(), fNumEvals); fSavedActivatorMsg->SetTriggerType(plActivatorMsg::kVolumeEnter); fLastEnterEval = fNumEvals; } else { - //DetectorLog("%s: Saving Exiting volume - Evals=%d", GetKeyName(),fNumEvals); + DetectorLog("%s: Saving Exiting volume - Evals=%d", GetKeyName().c_str(), fNumEvals); fSavedActivatorMsg->SetTriggerType(plActivatorMsg::kVolumeExit); fLastExitEval = fNumEvals; } -*/ -#ifdef USE_PHYSX_COLLISION_FLUTTER_WORKAROUND - // PHYSX_FIXME hack for PhysX turd that sends bunches of enter/exits over one frame - // we're saving the message to be dispatched later... - if (immediate) - { -#endif // USE_PHYSX_COLLISION_FLUTTER_WORKAROUND - - // fSavedActivatorMsg = nil; - -#ifdef USE_PHYSX_COLLISION_FLUTTER_WORKAROUND - } -#endif // USE_PHYSX_COLLISION_FLUTTER_WORKAROUND + if (immediate) + ISendSavedTriggerMsgs(); } -/* + void plObjectInVolumeDetector::ISendSavedTriggerMsgs() { if (fSavedActivatorMsg) { if (fSavedActivatorMsg->fTriggerType == plActivatorMsg::kVolumeEnter) - DetectorLog("%s: Sending Entering volume - Evals=%d", GetKeyName(),fNumEvals); + DetectorLog("%s: Sending Entering volume - Evals=%d", GetKeyName().c_str(), fNumEvals); else - DetectorLog("%s: Sending Exiting volume - Evals=%d", GetKeyName(),fNumEvals); + DetectorLog("%s: Sending Exiting volume - Evals=%d", GetKeyName().c_str(), fNumEvals); // we're saving the message to be dispatched later... plgDispatch::MsgSend(fSavedActivatorMsg); } fSavedActivatorMsg = nil; } -*/ + hsBool plObjectInVolumeDetector::MsgReceive(plMessage* msg) { plCollideMsg* pCollMsg = plCollideMsg::ConvertNoRef(msg); @@ -591,36 +387,18 @@ hsBool plObjectInVolumeDetector::MsgReceive(plMessage* msg) // If the avatar is disabled (flying around), don't trigger if (IIsDisabledAvatar(pCollMsg->fOtherKey)) return false; - -#ifdef USE_PHYSX_COLLISION_FLUTTER_WORKAROUND - // PHYSX_FIXME hack for PhysX turd that sends bunches of enter/exits over one frame - if (!fWaitingForEval) - { - plgDispatch::Dispatch()->RegisterForExactType(plEvalMsg::Index(), GetKey()); - fWaitingForEval = true; - } - // end PHYSX_FIXME hack for PhysX turd that sends bunches of enter/exits over one frame -#endif // USE_PHYSX_COLLISION_FLUTTER_WORKAROUND ITrigger(pCollMsg->fOtherKey, (pCollMsg->fEntering != 0)); - + plgDispatch::Dispatch()->RegisterForExactType(plEvalMsg::Index(), GetKey()); return true; } -#ifdef USE_PHYSX_COLLISION_FLUTTER_WORKAROUND - // PHYSX_FIXME hack for PhysX turd that sends bunches of enter/exits over one frame - plEvalMsg* pEval = plEvalMsg::ConvertNoRef(msg); - if (pEval) + plEvalMsg* pEvalMsg = plEvalMsg::ConvertNoRef(msg); + if (pEvalMsg) { - - //if (fSavedActivatorMsg) - // DetectorLog("%s: InVolumeEval=%d with saved message", GetKeyName(), fNumEvals); - //else - // DetectorLog("%s: InVolumeEval=%d without saved message", GetKeyName(), fNumEvals); - IHandleEval(pEval); - + fNumEvals++; + ISendSavedTriggerMsgs(); + plgDispatch::Dispatch()->UnRegisterForExactType(plEvalMsg::Index(), GetKey()); } - // end PHYSX_FIXME hack for PhysX turd that sends bunches of enter/exits over one frame -#endif // USE_PHYSX_COLLISION_FLUTTER_WORKAROUND plPlayerPageMsg* pageMsg = plPlayerPageMsg::ConvertNoRef(msg); if (pageMsg && pageMsg->fUnload) @@ -631,75 +409,6 @@ hsBool plObjectInVolumeDetector::MsgReceive(plMessage* msg) return plCollisionDetector::MsgReceive(msg); } -void plObjectInVolumeDetector::IHandleEval(plEvalMsg* pEval) -{ - plgDispatch::Dispatch()->UnRegisterForExactType(plEvalMsg::Index(), GetKey()); - fWaitingForEval = false; - for(bookKeepingList::reverse_iterator it= fCollisionList.rbegin();it!=fCollisionList.rend(); it++) - { - bool alreadyInside; - ResidentSet::iterator HitIt; - HitIt = fCurrentResidents.find((*it)->hitter); - if(HitIt != fCurrentResidents.end()) alreadyInside = true; - else alreadyInside=false; - plActivatorMsg* actout=new plActivatorMsg; - actout->fHitterObj=((*it)->hitter); - actout->SetSender(GetKey()); - if (fProxyKey) - actout->fHiteeObj = fProxyKey; - else - actout->fHiteeObj = GetTarget()->GetKey(); - if((*it)->fSubStepCurState)//current substate says we are entered - {//different enters and exits - //figure out what to do - if(!alreadyInside) - {//we are actuall entering - actout->SetTriggerType(plActivatorMsg::kVolumeEnter); - fCurrentResidents.insert((*it)->hitter); - actout->AddReceivers(fReceivers); - actout->Send(); - DetectorLog("%s sent an Enter ActivatorMsg. To: %s", GetKeyName().c_str(), GetTarget()->GetKeyName().c_str() ); - } - else - { - DetectorLog("%s squelched an Enter ActivatorMsg.", GetKeyName().c_str()); - delete actout; - } - } - else - { - //fSubStepCurState says we are outside - if(alreadyInside) - {//we are actuall exiting - actout->SetTriggerType(plActivatorMsg::kVolumeExit); - fCurrentResidents.erase((*it)->hitter); - actout->AddReceivers(fReceivers); - actout->Send(); - DetectorLog("%s sent an Exit ActivatorMsg. To: %s", GetKeyName().c_str(), GetTarget()->GetKeyName().c_str()); - } - else - { - DetectorLog("%s squelched an Exit ActivatorMsg.", GetKeyName().c_str()); - delete actout; - } - } - } - DetectorLog("*********"); - for(bookKeepingList::iterator it = fCollisionList.begin(); it != fCollisionList.end(); it ++) - { - delete (*it); - } - DetectorLog("This is the regions inhabitants after the op"); - for(ResidentSet::iterator it = fCurrentResidents.begin(); it!= fCurrentResidents.end(); it++) - { - DetectorLog("%s", (*it)->GetName().c_str()); - } - DetectorLog("*********"); - - fCollisionList.clear(); - -} - void plObjectInVolumeDetector::SetTarget(plSceneObject* so) { plCollisionDetector::SetTarget(so); @@ -725,6 +434,7 @@ void plObjectInVolumeDetector::Write(hsStream* stream, hsResMgr* mgr) plObjectInVolumeAndFacingDetector::plObjectInVolumeAndFacingDetector() : + plObjectInVolumeDetector(), fFacingTolerance(0), fNeedWalkingForward(false), fAvatarInVolume(false), diff --git a/Sources/Plasma/PubUtilLib/plPhysical/plCollisionDetector.h b/Sources/Plasma/PubUtilLib/plPhysical/plCollisionDetector.h index 5600a442..f2fa65ea 100644 --- a/Sources/Plasma/PubUtilLib/plPhysical/plCollisionDetector.h +++ b/Sources/Plasma/PubUtilLib/plPhysical/plCollisionDetector.h @@ -73,7 +73,8 @@ public: kTypeBump = 0x20, }; - plCollisionDetector() : fType(0), fTriggered(false), fBumped(false){;} + plCollisionDetector() : fType(0), fTriggered(false), fBumped(false){ } + plCollisionDetector(int8_t type) : fType(type), fTriggered(false), fBumped(false) { } virtual ~plCollisionDetector(){;} virtual hsBool MsgReceive(plMessage* msg); @@ -90,48 +91,26 @@ public: // sub type for object-in-volume detectors class plObjectInVolumeDetector : public plCollisionDetector { -public: - class plCollisionBookKeepingInfo - { - friend class plObjectInVolumeDetector; - public: - plCollisionBookKeepingInfo(plKey& hit) - { - hitter=hit; - enters=0; - exits=0; - } - ~plCollisionBookKeepingInfo() - { - hitter=nil; - } - protected: - plKey hitter; - int enters,exits; - bool fSubStepCurState; - }; protected: virtual void ITrigger(plKey hitter, bool entering, bool immediate=false); - //virtual void ISendSavedTriggerMsgs(); - virtual void IHandleEval(plEvalMsg* pEval); - bool fWaitingForEval; + virtual void ISendSavedTriggerMsgs(); plActivatorMsg* fSavedActivatorMsg; - - typedef std::list bookKeepingList; - bookKeepingList fCollisionList; - typedef std::set ResidentSet; - ResidentSet fCurrentResidents; + uint32_t fNumEvals; + uint32_t fLastEnterEval; + uint32_t fLastExitEval; public: - plObjectInVolumeDetector() - { - fWaitingForEval=false;fSavedActivatorMsg=nil; - - } - plObjectInVolumeDetector(int8_t i){fType = i;fWaitingForEval=false;fSavedActivatorMsg=nil;} - virtual ~plObjectInVolumeDetector(){;} + plObjectInVolumeDetector() + : plCollisionDetector(), fSavedActivatorMsg(nil), fNumEvals(0), fLastEnterEval(0), fLastExitEval(0) + { } + + plObjectInVolumeDetector(int8_t type) + : plCollisionDetector(type), fSavedActivatorMsg(nil), fNumEvals(0), fLastEnterEval(0), fLastExitEval(0) + { } + + virtual ~plObjectInVolumeDetector() { } virtual hsBool MsgReceive(plMessage* msg); @@ -183,15 +162,13 @@ protected: bool fIsInside; bool fSavingSendMsg; bool fSavedMsgEnterFlag; - int fNumEvals; - int fLastEnterEval; - int fLastExitEval; virtual void ITrigger(plKey hitter, bool entering, bool immediate=false); virtual void ISendSavedTriggerMsgs(); - virtual void IHandleEval(plEvalMsg* pEval); public: - plCameraRegionDetector(){ fIsInside = false; fSavingSendMsg = false; } + plCameraRegionDetector() + : plObjectInVolumeDetector(), fIsInside(false), fSavingSendMsg(false) + { } ~plCameraRegionDetector(); virtual hsBool MsgReceive(plMessage* msg); From 80213f3edd75f9a9f87ba7f63c69190233c8c3a4 Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Sat, 11 Feb 2012 22:40:42 -0500 Subject: [PATCH 7/7] Fix weird jitters when jumping and kicking NOTE: If you are using a version of PhysX prior to 2.6.4, then you should test very carefully if you should keep this commit. This change fixed a bug that caused avatars to get stuck falling against certain colliders. It seems to no longer be needed. --- .../plAvatar/plPhysicalControllerCore.cpp | 41 ------------------- 1 file changed, 41 deletions(-) diff --git a/Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.cpp b/Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.cpp index f43af2ec..66c0cc7a 100644 --- a/Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.cpp +++ b/Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.cpp @@ -323,48 +323,7 @@ void plWalkingStrategy::Apply(float delSecs) LinearVelocity.fX = AchievedLinearVelocity.fX; LinearVelocity.fY = AchievedLinearVelocity.fY; } - if (!IsOnGround() || IsOnFalseGround()) - { - // We're not on solid ground, so we should be sliding against whatever - // we're hitting (like a rock cliff). Each vector in fSlidingNormals is - // the surface normal of a collision that's too steep to be ground, so - // we project our current velocity onto that plane and slide along the - // wall. - // - // Also, sometimes PhysX reports a bunch of collisions from the wall, - // but nothing from underneath (when there should be). So if we're not - // touching ground, we offset the avatar in the direction of the - // surface normal(s). This doesn't fix the issue 100%, but it's a hell - // of a lot better than nothing, and suitable duct tape until a future - // PhysX revision fixes the issue. - // - // Yes, there's room for optimization here if we care. - hsVector3 offset(0.f, 0.f, 0.f); - for (int i = 0; i < fContactNormals.GetCount(); i++) - { - offset += fContactNormals[i]; - hsVector3 velNorm = LinearVelocity; - - if (velNorm.MagnitudeSquared() > 0) - velNorm.Normalize(); - if (velNorm * fContactNormals[i] < 0) - { - hsVector3 proj = (velNorm % fContactNormals[i]) % fContactNormals[i]; - if (velNorm * proj < 0) - proj *= -1.f; - LinearVelocity = LinearVelocity.Magnitude() * proj; - } - } - if (offset.MagnitudeSquared() > 0) - { - // 5 ft/sec is roughly the speed we walk backwards. - // The higher the value, the less likely you'll trip - // the bug, and this seems reasonable. - offset.Normalize(); - LinearVelocity += offset * 5.0f; - } - } //make terminal velocity equal to k. it is wrong but has been this way and //don't want to break any puzzles. on top of that it will reduce tunneling behavior if(LinearVelocity.fZ