From 576ac25f03a5dd4980dd9deaea270bfe63ef0381 Mon Sep 17 00:00:00 2001 From: John Johns Date: Mon, 31 May 2021 10:48:56 -0700 Subject: [PATCH 01/13] Hoikas' subworld fixes including PhysX support 1) Allow plSubWorldMsg to be sent over the network https://github.com/H-uru/Plasma/pull/107 2) Cleanup VolumeSensorConditionalObject https://github.com/H-uru/Plasma/pull/537 3) Add two new compiler feature tests - HeadSpin.h changes ONLY, as prerequisite for VolumeSensorConditionalObject https://github.com/H-uru/Plasma/commit/45be91c0e37cbd8131afe0b1dec468ba61e5e52c 4) Fix a crash and a silly identified by Coverity - changes for VolumeSensorConditionalObject ONLY https://github.com/H-uru/Plasma/pull/851/commits/a702cb9d3fb1dd453d4bbf94ffb92b3586f1fe82 5) PXSubworld (Havok/CC subworld physics support ported to PhysX/MOULa) https://github.com/H-uru/Plasma/pull/555 --- .../Plasma/PubUtilLib/plPhysX/plPhysX.vcxproj | 2 + .../plPhysX/plPhysX.vcxproj.filters | 6 + Sources/Plasma/CoreLib/HeadSpin.h | 16 + .../plObjectInBoxConditionalObject.cpp | 358 ++++++------------ .../plObjectInBoxConditionalObject.h | 44 ++- .../pfConsole/pfConsoleCommands.cpp | 9 + .../pfConsole/pfGameConsoleCommands.cpp | 8 - .../FeatureLib/pfPython/pySceneObject.cpp | 14 + .../FeatureLib/pfPython/pySceneObject.h | 3 + .../FeatureLib/pfPython/pySceneObjectGlue.cpp | 12 + .../Plasma/NucleusLib/inc/plCreatableIndex.h | 1 + .../NucleusLib/pnMessage/plServerReplyMsg.h | 11 +- .../NucleusLib/pnModifier/plLogicModBase.cpp | 56 +-- .../NucleusLib/pnModifier/plLogicModBase.h | 9 +- .../PubUtilLib/plAvatar/plArmatureMod.cpp | 2 +- .../PubUtilLib/plAvatar/plArmatureMod.h | 2 +- .../PubUtilLib/plModifier/plLogicModifier.cpp | 9 + .../PubUtilLib/plModifier/plLogicModifier.h | 1 + .../plNetCommon/plNetMsgScreener.cpp | 1 + .../PubUtilLib/plPhysX/plPXPhysical.cpp | 241 ++++++------ .../Plasma/PubUtilLib/plPhysX/plPXPhysical.h | 22 +- .../PubUtilLib/plPhysX/plPXSubWorld.cpp | 52 +++ .../Plasma/PubUtilLib/plPhysX/plPXSubWorld.h | 67 ++++ .../PubUtilLib/plPhysX/plPhysXCreatable.h | 3 + .../PubUtilLib/plPhysX/plSimulationMgr.cpp | 13 +- 25 files changed, 543 insertions(+), 419 deletions(-) create mode 100644 Sources/Plasma/PubUtilLib/plPhysX/plPXSubWorld.cpp create mode 100644 Sources/Plasma/PubUtilLib/plPhysX/plPXSubWorld.h diff --git a/Build/VS2010/Plasma/PubUtilLib/plPhysX/plPhysX.vcxproj b/Build/VS2010/Plasma/PubUtilLib/plPhysX/plPhysX.vcxproj index 2e8abad4..df4d769d 100644 --- a/Build/VS2010/Plasma/PubUtilLib/plPhysX/plPhysX.vcxproj +++ b/Build/VS2010/Plasma/PubUtilLib/plPhysX/plPhysX.vcxproj @@ -169,6 +169,7 @@ + @@ -178,6 +179,7 @@ + diff --git a/Build/VS2010/Plasma/PubUtilLib/plPhysX/plPhysX.vcxproj.filters b/Build/VS2010/Plasma/PubUtilLib/plPhysX/plPhysX.vcxproj.filters index 6c960a03..72dd754e 100644 --- a/Build/VS2010/Plasma/PubUtilLib/plPhysX/plPhysX.vcxproj.filters +++ b/Build/VS2010/Plasma/PubUtilLib/plPhysX/plPhysX.vcxproj.filters @@ -26,6 +26,9 @@ Source Files + + Source Files + @@ -49,5 +52,8 @@ Header Files + + Header Files + \ No newline at end of file diff --git a/Sources/Plasma/CoreLib/HeadSpin.h b/Sources/Plasma/CoreLib/HeadSpin.h index bfa616f0..e8ca8edd 100644 --- a/Sources/Plasma/CoreLib/HeadSpin.h +++ b/Sources/Plasma/CoreLib/HeadSpin.h @@ -48,4 +48,20 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "hsTypes.h" #include "hsMalloc.h" +#ifdef HAVE_OVERRIDE +# define HS_OVERRIDE override +# define HS_FINAL final +#else +# define HS_OVERRIDE +# define HS_FINAL +#endif + +#ifdef HAVE_NOEXCEPT +# define HS_NOEXCEPT noexcept +# define HS_NOEXCEPT_IF(cond) noexcept(cond) +#else +# define HS_NOEXCEPT throw() +# define HS_NOEXCEPT_IF(cond) +#endif + #endif diff --git a/Sources/Plasma/FeatureLib/pfConditional/plObjectInBoxConditionalObject.cpp b/Sources/Plasma/FeatureLib/pfConditional/plObjectInBoxConditionalObject.cpp index ad359e5c..7cec3bff 100644 --- a/Sources/Plasma/FeatureLib/pfConditional/plObjectInBoxConditionalObject.cpp +++ b/Sources/Plasma/FeatureLib/pfConditional/plObjectInBoxConditionalObject.cpp @@ -49,8 +49,8 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "../pnNetCommon/plNetApp.h" #include "../plAvatar/plArmatureMod.h" #include "../pnSceneObject/plSceneObject.h" - -bool plVolumeSensorConditionalObject::makeBriceHappyVar = true; +#include "../pnMessage/plPlayerPageMsg.h" +#include "../../NucleusLib/inc/plgDispatch.h" plObjectInBoxConditionalObject::plObjectInBoxConditionalObject() : fCurrentTrigger(nil) @@ -129,12 +129,52 @@ fTrigNum(-1), fType(0), fFirst(false), fTriggered(false), -fIgnoreExtraEnters(true) +fFlags(kIgnoreExtraEnters) { SetSatisfied(true); } +void plVolumeSensorConditionalObject::IgnoreExtraEnters(bool ignore) +{ + if (ignore) + fFlags |= kIgnoreExtraEnters; + else + fFlags &= ~kIgnoreExtraEnters; +} + +void plVolumeSensorConditionalObject::NoServerArbitration(bool noArbitration) +{ + if (noArbitration) { + plgDispatch::Dispatch()->RegisterForExactType(plPlayerPageMsg::Index(), GetKey()); + fFlags |= kNoServerArbitration; + } else { + plgDispatch::Dispatch()->UnRegisterForExactType(plPlayerPageMsg::Index(), GetKey()); + fFlags &= ~kNoServerArbitration; + } +} + +bool plVolumeSensorConditionalObject::IIsLocal(const plKey& key) const +{ + if (key == plNetClientApp::GetInstance()->GetLocalPlayerKey()) + return true; + + const plSceneObject* hitter = plSceneObject::ConvertNoRef(key->ObjectIsLoaded()); + if (hitter) { + for (size_t i = 0; i < hitter->GetNumModifiers(); ++i) { + const plArmatureMod* am = plArmatureMod::ConvertNoRef(hitter->GetModifier(i)); + if (am && !am->IsLocalAI()) + return false; + } + if (hitter->IsLocallyOwned() != plSynchedObject::kYes) + return false; + } + + // Yes, I know that we're saying YES for not loaded objects. This matches the previous behavior. + return true; +} + + hsBool plVolumeSensorConditionalObject::MsgReceive(plMessage* msg) { plActivatorMsg* pActivateMsg = plActivatorMsg::ConvertNoRef(msg); @@ -144,55 +184,40 @@ hsBool plVolumeSensorConditionalObject::MsgReceive(plMessage* msg) if (!fLogicMod->HasFlag(plLogicModBase::kRequestingTrigger)) fLogicMod->GetNotify()->ClearEvents(); + // Track the hittee for the NoArbitration case so we can trigger the exit volume on link out + fHittee = pActivateMsg->fHiteeObj; + + // Track the enters/exits on all clients if (pActivateMsg->fTriggerType == plActivatorMsg::kVolumeEnter) { - int i; - for (i = 0; i < fInside.Count(); i++) - { - if (fInside[i] == pActivateMsg->fHitterObj) - { - if (fIgnoreExtraEnters) - return false; // this is the "correct" way to handle this situation - break; // this is for those special situations where, due to some physics oddity, we need to allow the avatar to enter without exiting - } - } - if (i == fInside.Count()) - fInside.Append(pActivateMsg->fHitterObj); - if (makeBriceHappyVar) - { - plSceneObject *pObj = plSceneObject::ConvertNoRef( pActivateMsg->fHitterObj->ObjectIsLoaded() ); - if( pObj ) - { - //need to check for human vs quabish type things in here - int i; - for( i = 0; i < pObj->GetNumModifiers(); i++ ) - { - if (plArmatureMod::ConvertNoRef( pObj->GetModifier(i))) - { - if (plNetClientApp::GetInstance()->GetLocalPlayerKey() != pActivateMsg->fHitterObj) - { - plArmatureMod *am=const_cast( plArmatureMod::ConvertNoRef(pObj->GetModifier(i))); - if((am->IsLocalAI())==nil) - { - return false; - } - } - } - } - plSynchedObject* syncObj = (plSynchedObject*)pObj; - if (syncObj->IsLocallyOwned() != plSynchedObject::kYes) - { - return false; - } - } + auto it = fInside.find(pActivateMsg->fHitterObj); + if (it != fInside.end() && fFlags & kIgnoreExtraEnters) { + // This is normally what we should do. You're already inside the region, + // so we don't care about a dupe enter. However, PhysX is weird, so sometimes + // we might want to allow dupe enters. + return false; } + fInside.insert(pActivateMsg->fHitterObj); + + // From here on out, we only care about local avatars + if (!IIsLocal(pActivateMsg->fHitterObj)) + return false; if (fType == kTypeEnter) { fLogicMod->GetNotify()->AddCollisionEvent(true, pActivateMsg->fHitterObj, pActivateMsg->fHiteeObj, false); - fLogicMod->RequestTrigger(false); + if ((fFlags & kNoServerArbitration)) + { + if (Satisfied()) + fLogicMod->Trigger(false); + } + else + { + fLogicMod->RequestTrigger(false); + } } else + if (fType == kTypeExit && !(fFlags & kNoServerArbitration)) { fLogicMod->GetNotify()->AddCollisionEvent(false, pActivateMsg->fHitterObj, pActivateMsg->fHiteeObj, false); fLogicMod->RequestUnTrigger(); @@ -202,56 +227,54 @@ hsBool plVolumeSensorConditionalObject::MsgReceive(plMessage* msg) else if (pActivateMsg->fTriggerType == plActivatorMsg::kVolumeExit) { - for (int i = 0; i < fInside.Count(); i++) - { - if (fInside[i] == pActivateMsg->fHitterObj) + auto it = fInside.find(pActivateMsg->fHitterObj); + if (it == fInside.end()) + return false; + fInside.erase(it); + + // From here on out, we only care about local avatars + if (!IIsLocal(pActivateMsg->fHitterObj)) + return false; + + if (fType == kTypeExit) { + fLogicMod->GetNotify()->AddCollisionEvent(false, pActivateMsg->fHitterObj, pActivateMsg->fHiteeObj, false); + if (fFlags & kNoServerArbitration) { - fInside.Remove(i); - if (makeBriceHappyVar) - { - //need to check for human vs quabish type things in here - plSceneObject *pObj = plSceneObject::ConvertNoRef( pActivateMsg->fHitterObj->ObjectIsLoaded() ); - if( pObj ) - { - int i; - for( i = 0; i < pObj->GetNumModifiers(); i++ ) - { - if (plArmatureMod::ConvertNoRef( pObj->GetModifier(i))) - { - if (plNetClientApp::GetInstance()->GetLocalPlayerKey() != pActivateMsg->fHitterObj) - { - plArmatureMod *am=const_cast( plArmatureMod::ConvertNoRef(pObj->GetModifier(i))); - if((am->IsLocalAI())==nil) - { - return false; - } - } - } - } - plSynchedObject* syncObj = (plSynchedObject*)pObj; - if (syncObj->IsLocallyOwned() != plSynchedObject::kYes) - { - return false; - } - } - } - if (fType == kTypeExit) - { - fLogicMod->GetNotify()->AddCollisionEvent(false, pActivateMsg->fHitterObj, pActivateMsg->fHiteeObj, false); - fLogicMod->RequestTrigger(false); - - } - else - { - fLogicMod->GetNotify()->AddCollisionEvent(true, pActivateMsg->fHitterObj, pActivateMsg->fHiteeObj, false); - fLogicMod->RequestUnTrigger(); - } - return false; + if (Satisfied()) + fLogicMod->Trigger(false); + } + else + { + fLogicMod->RequestTrigger(false); } } + else if (fType == kTypeEnter && !(fFlags & kNoServerArbitration)) + { + fLogicMod->GetNotify()->AddCollisionEvent(true, pActivateMsg->fHitterObj, pActivateMsg->fHiteeObj, false); + fLogicMod->RequestUnTrigger(); + } + return true; } + return true; + } - return false; + plPlayerPageMsg* page = plPlayerPageMsg::ConvertNoRef(msg); + if (page && page->fUnload) { + hsAssert(fFlags & kNoServerArbitration, "WTF -- should only get here if the VSCO skips arbitration!"); + + auto it = fInside.find(page->fPlayer); + if (it != fInside.end()) { + fInside.erase(it); + if (fHittee && fType == kTypeExit) { + const plSceneObject* hitteeSO = plSceneObject::ConvertNoRef(fHittee->ObjectIsLoaded()); + if (hitteeSO && hitteeSO->IsLocallyOwned() == plSynchedObject::kYes) { + fLogicMod->GetNotify()->AddCollisionEvent(false, page->fPlayer, fHittee, false); + if (Satisfied()) + fLogicMod->Trigger(false); + } + } + } + return true; } return plConditionalObject::MsgReceive(msg); } @@ -260,20 +283,20 @@ hsBool plVolumeSensorConditionalObject::Satisfied() { if (fType == kTypeExit && fFirst && !fTriggered) { - if (fInside.Count()) + if (!fInside.empty()) fTriggered = true; return true; } if (fTriggered) { - if (fInside.Count() == 0) + if (fInside.empty()) fTriggered = false; return false; } if (fTrigNum == -1) return true; - if (fInside.Count() == fTrigNum) + if (fInside.size() == fTrigNum) return true; else return false; @@ -293,156 +316,11 @@ void plVolumeSensorConditionalObject::Write(hsStream* stream, hsResMgr* mgr) stream->WriteSwap32(fType); stream->WriteBool(fFirst); } -#include "../pnMessage/plPlayerPageMsg.h" -#include "../../NucleusLib/inc/plgDispatch.h" -hsBool plVolumeSensorConditionalObjectNoArbitration::MsgReceive(plMessage* msg) -{ - plActivatorMsg* pActivateMsg = plActivatorMsg::ConvertNoRef(msg); - if (pActivateMsg) - { - // single player hack - if (!fLogicMod->HasFlag(plLogicModBase::kRequestingTrigger)) - fLogicMod->GetNotify()->ClearEvents(); - fHittee= pActivateMsg->fHiteeObj; - if (pActivateMsg->fTriggerType == plActivatorMsg::kVolumeEnter) - { - int i; - for (i = 0; i < fInside.Count(); i++) - { - if (fInside[i] == pActivateMsg->fHitterObj) - { - if (fIgnoreExtraEnters) - return false; // this is the "correct" way to handle this situation - break; // this is for those special situations where, due to some physics oddity, we need to allow the avatar to enter without exiting - } - } - if (i == fInside.Count()) - fInside.Append(pActivateMsg->fHitterObj); - if (makeBriceHappyVar) - { - plSceneObject *pObj = plSceneObject::ConvertNoRef( pActivateMsg->fHitterObj->ObjectIsLoaded() ); - if( pObj ) - { - //need to check for human vs quabish type things in here - int i; - for( i = 0; i < pObj->GetNumModifiers(); i++ ) - { - if (plArmatureMod::ConvertNoRef( pObj->GetModifier(i))) - { - if (plNetClientApp::GetInstance()->GetLocalPlayerKey() != pActivateMsg->fHitterObj) - { - plArmatureMod *am=const_cast( plArmatureMod::ConvertNoRef(pObj->GetModifier(i))); - if((am->IsLocalAI())==nil) - { - return false; - } - } - } - } - plSynchedObject* syncObj = (plSynchedObject*)pObj; - if (syncObj->IsLocallyOwned() != plSynchedObject::kYes) - { - return false; - } - } - } - if (fType == kTypeEnter) - { - fLogicMod->GetNotify()->AddCollisionEvent(true, pActivateMsg->fHitterObj, pActivateMsg->fHiteeObj, false); - //fLogicMod->RequestTrigger(false); - - if (!Satisfied()) - return false; - - fLogicMod->Trigger(false); - } - - return false; - } - else - if (pActivateMsg->fTriggerType == plActivatorMsg::kVolumeExit) - { - for (int i = 0; i < fInside.Count(); i++) - { - if (fInside[i] == pActivateMsg->fHitterObj) - { - fInside.Remove(i); - if (makeBriceHappyVar) - { - //need to check for human vs quabish type things in here - plSceneObject *pObj = plSceneObject::ConvertNoRef( pActivateMsg->fHitterObj->ObjectIsLoaded() ); - if( pObj ) - { - int i; - for( i = 0; i < pObj->GetNumModifiers(); i++ ) - { - if (plArmatureMod::ConvertNoRef( pObj->GetModifier(i))) - { - if (plNetClientApp::GetInstance()->GetLocalPlayerKey() != pActivateMsg->fHitterObj) - { - plArmatureMod *am=const_cast( plArmatureMod::ConvertNoRef(pObj->GetModifier(i))); - if((am->IsLocalAI())==nil) - { - return false; - } - } - } - } - plSynchedObject* syncObj = (plSynchedObject*)pObj; - if (syncObj->IsLocallyOwned() != plSynchedObject::kYes) - { - return false; - } - } - } - if (fType == kTypeExit) - { - fLogicMod->GetNotify()->AddCollisionEvent(false, pActivateMsg->fHitterObj, pActivateMsg->fHiteeObj, false); - //fLogicMod->RequestTrigger(false); - if (!Satisfied()) - return false; - - fLogicMod->Trigger(false); - } - return false; - } - } - } - - return false; - } - - plPlayerPageMsg* page = plPlayerPageMsg::ConvertNoRef(msg); - if(page && page->fUnload) - { - for(int j= 0; j< fInside.Count(); j++) - { - if(fInside[j] == page->fPlayer) - {//this is the one inside - if(fHittee) - { - plSceneObject *so = plSceneObject::ConvertNoRef(fHittee->ObjectIsLoaded()); - if(so && so->IsLocallyOwned()) - { - if (fType == kTypeExit) - { - fLogicMod->GetNotify()->AddCollisionEvent(false, page->fPlayer, fHittee, false); - //fLogicMod->RequestTrigger(false); - if (!Satisfied()) - return false; - fLogicMod->Trigger(false); - } - } - } - fInside.Remove(j); - } - } - } - return plConditionalObject::MsgReceive(msg); -} void plVolumeSensorConditionalObjectNoArbitration::Read(hsStream* stream, hsResMgr* mgr) { plVolumeSensorConditionalObject::Read(stream, mgr); - plgDispatch::Dispatch()->RegisterForExactType(plPlayerPageMsg::Index(), GetKey()); -} \ No newline at end of file + + // We must have a valid fpKey before we do this, hence why this is not in the constructor + NoServerArbitration(true); +} diff --git a/Sources/Plasma/FeatureLib/pfConditional/plObjectInBoxConditionalObject.h b/Sources/Plasma/FeatureLib/pfConditional/plObjectInBoxConditionalObject.h index 9eab8eb4..27c1accc 100644 --- a/Sources/Plasma/FeatureLib/pfConditional/plObjectInBoxConditionalObject.h +++ b/Sources/Plasma/FeatureLib/pfConditional/plObjectInBoxConditionalObject.h @@ -43,8 +43,10 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #ifndef plObjectInBoxConditionalObject_inc #define plObjectInBoxConditionalObject_inc +#include #include "../../NucleusLib/pnModifier/plConditionalObject.h" #include "hsTemplates.h" +#include class plKey; @@ -77,16 +79,25 @@ class plVolumeSensorConditionalObject : public plConditionalObject protected: - hsTArray fInside; + std::set fInside; int fTrigNum; int fType; hsBool fFirst; hsBool fTriggered; - hsBool fIgnoreExtraEnters; -public: - static bool makeBriceHappyVar; + plKey fHittee; + uint32_t fFlags; + + enum + { + /** */ + kIgnoreExtraEnters = (1<<0), + kNoServerArbitration = (1<<1), + }; + bool IIsLocal(const plKey& key) const; + +public: enum { @@ -99,33 +110,30 @@ public: CLASSNAME_REGISTER( plVolumeSensorConditionalObject ); GETINTERFACE_ANY( plVolumeSensorConditionalObject, plConditionalObject ); - virtual hsBool MsgReceive(plMessage* msg); + hsBool MsgReceive(plMessage* msg); - void Evaluate(){;} + void Evaluate() {} void Reset() { SetSatisfied(false); } - virtual hsBool Satisfied(); + hsBool Satisfied() HS_OVERRIDE; void SetType(int i) { fType = i; } void SetTrigNum(int i) { fTrigNum = i; } void SetFirst(hsBool b) { fFirst = b; } - void IgnoreExtraEnters(hsBool ignore = true) {fIgnoreExtraEnters = ignore;} + void IgnoreExtraEnters(bool ignore = true); + void NoServerArbitration(bool noArbitration = true); - virtual void Read(hsStream* stream, hsResMgr* mgr); - virtual void Write(hsStream* stream, hsResMgr* mgr); + void Read(hsStream* stream, hsResMgr* mgr) HS_OVERRIDE; + void Write(hsStream* stream, hsResMgr* mgr) HS_OVERRIDE; }; class plVolumeSensorConditionalObjectNoArbitration : public plVolumeSensorConditionalObject { public: - plVolumeSensorConditionalObjectNoArbitration ():plVolumeSensorConditionalObject(){;} - ~plVolumeSensorConditionalObjectNoArbitration (){;} - CLASSNAME_REGISTER( plVolumeSensorConditionalObjectNoArbitration ); - GETINTERFACE_ANY( plVolumeSensorConditionalObjectNoArbitration, plConditionalObject ); - virtual hsBool MsgReceive(plMessage* msg); - virtual void Read(hsStream* stream, hsResMgr* mgr); -protected: - plKey fHittee; + CLASSNAME_REGISTER(plVolumeSensorConditionalObjectNoArbitration); + GETINTERFACE_ANY( plVolumeSensorConditionalObjectNoArbitration, plVolumeSensorConditionalObject); + + virtual void Read(hsStream* stream, hsResMgr* mgr) HS_OVERRIDE; }; diff --git a/Sources/Plasma/FeatureLib/pfConsole/pfConsoleCommands.cpp b/Sources/Plasma/FeatureLib/pfConsole/pfConsoleCommands.cpp index b6c7fb28..6a140eb4 100644 --- a/Sources/Plasma/FeatureLib/pfConsole/pfConsoleCommands.cpp +++ b/Sources/Plasma/FeatureLib/pfConsole/pfConsoleCommands.cpp @@ -447,6 +447,15 @@ PF_CONSOLE_BASE_CMD( SampleCmd3, "int, ...", "Sample command #3" ) } } +PF_CONSOLE_CMD(Logic, + DelayArbitration, + "int millis", + "Simulates network delay for LogicMod arbitration") +{ + int ms = params[0]; + plLogicModBase::SetArbitrationDelay(ms); +} + #endif // LIMIT_CONSOLE_COMMANDS diff --git a/Sources/Plasma/FeatureLib/pfConsole/pfGameConsoleCommands.cpp b/Sources/Plasma/FeatureLib/pfConsole/pfGameConsoleCommands.cpp index 4147e9cb..719af55c 100644 --- a/Sources/Plasma/FeatureLib/pfConsole/pfGameConsoleCommands.cpp +++ b/Sources/Plasma/FeatureLib/pfConsole/pfGameConsoleCommands.cpp @@ -457,11 +457,3 @@ PF_CONSOLE_CMD( Game, SetLocalClientAsAdmin, "bool enable", "Makes chat messages plgDispatch::MsgSend( msg ); } #endif - -#include "../pfConditional/plObjectInBoxConditionalObject.h" - -PF_CONSOLE_CMD( Game, BreakVolumeSensors, "bool break", "reverts to old broken volume sensor logic" ) -{ - bool b = params[ 0 ]; - plVolumeSensorConditionalObject::makeBriceHappyVar = !b; -} diff --git a/Sources/Plasma/FeatureLib/pfPython/pySceneObject.cpp b/Sources/Plasma/FeatureLib/pfPython/pySceneObject.cpp index 1aa2d8f3..4d94af91 100644 --- a/Sources/Plasma/FeatureLib/pfPython/pySceneObject.cpp +++ b/Sources/Plasma/FeatureLib/pfPython/pySceneObject.cpp @@ -993,3 +993,17 @@ void pySceneObject::VolumeSensorIgnoreExtraEnters(bool ignore) } } } + +void pySceneObject::VolumeSensorNoArbitration(bool noArbitration) +{ + if (fSceneObjects.Count() > 0) { + plSceneObject* obj = plSceneObject::ConvertNoRef(fSceneObjects[0]->ObjectIsLoaded()); + if (obj) { + for (size_t i = 0; i < obj->GetNumModifiers(); ++i) { + plLogicModifier* logic = const_cast(plLogicModifier::ConvertNoRef(obj->GetModifier(i))); + if (logic) + logic->VolumeNoArbitration(noArbitration); + } + } + } +} \ No newline at end of file diff --git a/Sources/Plasma/FeatureLib/pfPython/pySceneObject.h b/Sources/Plasma/FeatureLib/pfPython/pySceneObject.h index 9f22a1b3..65988273 100644 --- a/Sources/Plasma/FeatureLib/pfPython/pySceneObject.h +++ b/Sources/Plasma/FeatureLib/pfPython/pySceneObject.h @@ -200,6 +200,9 @@ public: // hack for garrison void VolumeSensorIgnoreExtraEnters(bool ignore); + + /** More SubWorld hacks */ + void VolumeSensorNoArbitration(bool noArbitration); }; #endif // _pySceneObject_h_ diff --git a/Sources/Plasma/FeatureLib/pfPython/pySceneObjectGlue.cpp b/Sources/Plasma/FeatureLib/pfPython/pySceneObjectGlue.cpp index c379a1fe..8966dbc9 100644 --- a/Sources/Plasma/FeatureLib/pfPython/pySceneObjectGlue.cpp +++ b/Sources/Plasma/FeatureLib/pfPython/pySceneObjectGlue.cpp @@ -452,6 +452,17 @@ PYTHON_METHOD_DEFINITION(ptSceneobject, volumeSensorIgnoreExtraEnters, args) PYTHON_RETURN_NONE; } +PYTHON_METHOD_DEFINITION(ptSceneobject, volumeSensorNoArbitration, args) +{ + bool noArbitration = true; + if (!PyArg_ParseTuple(args, "|b", &noArbitration)) { + PyErr_SetString(PyExc_TypeError, "volumeSensorNoArbitration expects an optional boolean"); + PYTHON_RETURN_ERROR; + } + self->fThis->VolumeSensorNoArbitration(noArbitration); + PYTHON_RETURN_NONE; +} + PYTHON_START_METHODS_TABLE(ptSceneobject) PYTHON_METHOD(ptSceneobject, addKey, "Params: key\nMostly used internally.\n" "Add another sceneobject ptKey"), @@ -510,6 +521,7 @@ PYTHON_START_METHODS_TABLE(ptSceneobject) PYTHON_METHOD(ptSceneobject, getSoundIndex, "Params: sndComponentName\nGet the index of the requested sound component"), PYTHON_METHOD(ptSceneobject, volumeSensorIgnoreExtraEnters, "Params: ignore\nTells the volume sensor attached to this object to ignore extra enters (default), or not (hack for garrison)."), + PYTHON_METHOD(ptSceneobject, volumeSensorNoArbitration, "Params: noArbitration\nTells the volume sensor attached to this object whether or not to negotiate exclusive locks with the server."), PYTHON_END_METHODS_TABLE; PYTHON_GET_DEFINITION(ptSceneobject, draw) diff --git a/Sources/Plasma/NucleusLib/inc/plCreatableIndex.h b/Sources/Plasma/NucleusLib/inc/plCreatableIndex.h index 6c2d9a51..75f0e728 100644 --- a/Sources/Plasma/NucleusLib/inc/plCreatableIndex.h +++ b/Sources/Plasma/NucleusLib/inc/plCreatableIndex.h @@ -367,6 +367,7 @@ CLASS_INDEX_LIST_START CLASS_INDEX(plDynamicCamMap), CLASS_INDEX(plRidingAnimatedPhysicalDetector), CLASS_INDEX(plVolumeSensorConditionalObjectNoArbitration), + CLASS_INDEX(plPXSubWorld), //--------------------------------------------------------- // Keyed objects above this line, unkeyed (such as messages) below.. //--------------------------------------------------------- diff --git a/Sources/Plasma/NucleusLib/pnMessage/plServerReplyMsg.h b/Sources/Plasma/NucleusLib/pnMessage/plServerReplyMsg.h index 05c81c70..ffb6b6b5 100644 --- a/Sources/Plasma/NucleusLib/pnMessage/plServerReplyMsg.h +++ b/Sources/Plasma/NucleusLib/pnMessage/plServerReplyMsg.h @@ -57,6 +57,8 @@ class hsResMgr; class plServerReplyMsg : public plMessage { int fType; + bool fWasDelayed; + public: enum @@ -67,10 +69,13 @@ public: }; void SetType(int t) { fType = t; } - int GetType() { return fType; } + int GetType() const { return fType; } + + void SetWasDelayed(bool v) { fWasDelayed = v; } + bool GetWasDelayed() const { return fWasDelayed; } - plServerReplyMsg() : fType(kUnInit) { } - plServerReplyMsg(const plKey &s, const plKey &r, const double* t) : plMessage(s,r,t), fType(kUnInit) { } + plServerReplyMsg() : fType(kUnInit), fWasDelayed(false) { } + plServerReplyMsg(const plKey &s, const plKey &r, const double* t) : plMessage(s,r,t), fType(kUnInit), fWasDelayed(false) { } CLASSNAME_REGISTER( plServerReplyMsg ); GETINTERFACE_ANY( plServerReplyMsg, plMessage ); diff --git a/Sources/Plasma/NucleusLib/pnModifier/plLogicModBase.cpp b/Sources/Plasma/NucleusLib/pnModifier/plLogicModBase.cpp index ab48b16c..deb05294 100644 --- a/Sources/Plasma/NucleusLib/pnModifier/plLogicModBase.cpp +++ b/Sources/Plasma/NucleusLib/pnModifier/plLogicModBase.cpp @@ -44,6 +44,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "plgDispatch.h" #include "hsResMgr.h" #include "hsTimer.h" +#include "../pnTimer/plTimerCallbackManager.h" #include "../pnSceneObject/plSceneObject.h" #include "../pnNetCommon/plGenericVar.h" #include "../pnNetCommon/plNetApp.h" @@ -53,6 +54,8 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "../pnMessage/plEnableMsg.h" #include "../pnMessage/plServerReplyMsg.h" +uint32_t plLogicModBase::sArbitrationDelayMs = 0; + void plLogicModBase::ConsoleTrigger(plKey playerKey) { // Setup the event data in case this is a OneShot responder that needs it @@ -138,31 +141,12 @@ hsBool plLogicModBase::MsgReceive(plMessage* msg) plServerReplyMsg* pSMsg = plServerReplyMsg::ConvertNoRef(msg); if (pSMsg) { - hsAssert(pSMsg->GetType() != plServerReplyMsg::kUnInit, "uninit server reply msg"); - -#if 1 - char str[256]; - sprintf(str, "LM: LogicModifier %s recvd trigger request reply:%s, wasRequesting=%d, t=%f\n", GetKeyName(), - pSMsg->GetType() == plServerReplyMsg::kDeny ? "denied" : "confirmed", - HasFlag(kRequestingTrigger), hsTimer::GetSysSeconds()); - plNetClientApp::GetInstance()->DebugMsg(str); -#endif - - if (pSMsg->GetType() == plServerReplyMsg::kDeny) - { - if (HasFlag(kRequestingTrigger)) - { - plNetClientApp::GetInstance()->DebugMsg("\tLM: Denied, clearing requestingTrigger"); - ClearFlag(kRequestingTrigger); - } - else - plNetClientApp::GetInstance()->DebugMsg("\tLM: Denied, but not requesting?"); - } - else - { - hsBool netRequest=false; // we're triggering as a result of a local activation - PreTrigger(netRequest); - IUpdateSharedState(false /* untriggering */); + if (sArbitrationDelayMs == 0 || pSMsg->GetWasDelayed()) { + IHandleArbitration(pSMsg); + } else { + pSMsg->SetWasDelayed(true); + pSMsg->Ref(); // timer callback manager steals this reference + plgTimerCallbackMgr::NewTimer(static_cast(sArbitrationDelayMs) / 1000, pSMsg); } return true; } @@ -186,6 +170,28 @@ hsBool plLogicModBase::MsgReceive(plMessage* msg) return plSingleModifier::MsgReceive(msg); } +void plLogicModBase::IHandleArbitration(plServerReplyMsg* pSMsg) +{ + hsAssert(pSMsg->GetType() != plServerReplyMsg::kUnInit, "uninit server reply msg"); + plNetClientApp::GetInstance()->DebugMsg("LM: LogicModifier {} recvd trigger request reply:{}, wasRequesting={}, t={f}\n", + GetKeyName(), + pSMsg->GetType() == plServerReplyMsg::kDeny ? "denied" : "confirmed", + HasFlag(kRequestingTrigger), hsTimer::GetSysSeconds()); + + if (pSMsg->GetType() == plServerReplyMsg::kDeny) { + if (HasFlag(kRequestingTrigger)) { + plNetClientApp::GetInstance()->DebugMsg("\tLM: Denied, clearing requestingTrigger"); + ClearFlag(kRequestingTrigger); + } else { + plNetClientApp::GetInstance()->DebugMsg("\tLM: Denied, but not requesting?"); + } + } else { + bool netRequest=false; // we're triggering as a result of a local activation + PreTrigger(netRequest); + IUpdateSharedState(false /* untriggering */); + } +} + void plLogicModBase::RequestTrigger(hsBool netRequest) { if (HasFlag(kTriggered)) diff --git a/Sources/Plasma/NucleusLib/pnModifier/plLogicModBase.h b/Sources/Plasma/NucleusLib/pnModifier/plLogicModBase.h index 6a9050ff..908f5924 100644 --- a/Sources/Plasma/NucleusLib/pnModifier/plLogicModBase.h +++ b/Sources/Plasma/NucleusLib/pnModifier/plLogicModBase.h @@ -43,6 +43,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #ifndef plLogicModBase_inc #define plLogicModBase_inc +#include #include "plSingleModifier.h" #include "../pnNetCommon/plSynchedValue.h" #include "hsTemplates.h" @@ -66,6 +67,8 @@ public: }; protected: + static uint32_t sArbitrationDelayMs; + hsTArray fCommandList; hsTArray fReceiverList; UInt32 fCounterLimit; @@ -77,6 +80,7 @@ protected: virtual hsBool IEval(double secs, hsScalar del, UInt32 dirty) {return false;} void IUpdateSharedState(bool triggered) const; + void IHandleArbitration(class plServerReplyMsg* msg); hsBool IEvalCounter(); virtual void PreTrigger(hsBool netRequest); virtual void Trigger(hsBool netRequest); @@ -85,7 +89,7 @@ protected: void CreateNotifyMsg(); public: - friend plVolumeSensorConditionalObjectNoArbitration; + friend class plVolumeSensorConditionalObject; plLogicModBase(); ~plLogicModBase(); CLASSNAME_REGISTER( plLogicModBase ); @@ -121,6 +125,9 @@ public: // for debug purposes only! void ConsoleTrigger(plKey playerKey); void ConsoleRequestTrigger(); + + /** Specifies an amount of time (in milliseconds) to delay processing server arbitration responses */ + static void SetArbitrationDelay(uint32_t ms) { sArbitrationDelayMs = ms; } }; diff --git a/Sources/Plasma/PubUtilLib/plAvatar/plArmatureMod.cpp b/Sources/Plasma/PubUtilLib/plAvatar/plArmatureMod.cpp index f69e6cba..90fc261c 100644 --- a/Sources/Plasma/PubUtilLib/plAvatar/plArmatureMod.cpp +++ b/Sources/Plasma/PubUtilLib/plAvatar/plArmatureMod.cpp @@ -1978,7 +1978,7 @@ hsBool plArmatureMod::IsLocalAvatar() return plAvatarMgr::GetInstance()->GetLocalAvatar() == this; } -hsBool plArmatureMod::IsLocalAI() +hsBool plArmatureMod::IsLocalAI() const { plAvBrainCritter* ai = plAvBrainCritter::ConvertNoRef(FindBrainByClass(plAvBrainCritter::Index())); if (ai) diff --git a/Sources/Plasma/PubUtilLib/plAvatar/plArmatureMod.h b/Sources/Plasma/PubUtilLib/plAvatar/plArmatureMod.h index 26d1839c..b79f2105 100644 --- a/Sources/Plasma/PubUtilLib/plAvatar/plArmatureMod.h +++ b/Sources/Plasma/PubUtilLib/plAvatar/plArmatureMod.h @@ -220,7 +220,7 @@ public: void GetPositionAndRotationSim(hsPoint3* position, hsQuat* rotation); hsBool IsLocalAvatar(); - hsBool IsLocalAI(); + hsBool IsLocalAI() const; virtual const plSceneObject *FindBone(const char * name) const; virtual const plSceneObject *FindBone(UInt32 id) const; // use an id from an appropriate taxonomy, such as plAvBrainHuman::BoneID virtual void AddBoneMapping(UInt32 id, const plSceneObject *bone); diff --git a/Sources/Plasma/PubUtilLib/plModifier/plLogicModifier.cpp b/Sources/Plasma/PubUtilLib/plModifier/plLogicModifier.cpp index ab6f15c0..8ec40186 100644 --- a/Sources/Plasma/PubUtilLib/plModifier/plLogicModifier.cpp +++ b/Sources/Plasma/PubUtilLib/plModifier/plLogicModifier.cpp @@ -279,3 +279,12 @@ void plLogicModifier::VolumeIgnoreExtraEnters(bool ignore /* = true */) condition->IgnoreExtraEnters(ignore); } } + +void plLogicModifier::VolumeNoArbitration(bool noArbitration) +{ + for (size_t i = 0; i < fConditionList.Count(); ++i) { + plVolumeSensorConditionalObject* condition = plVolumeSensorConditionalObject::ConvertNoRef(fConditionList[i]); + if (condition) + condition->NoServerArbitration(noArbitration); + } +} diff --git a/Sources/Plasma/PubUtilLib/plModifier/plLogicModifier.h b/Sources/Plasma/PubUtilLib/plModifier/plLogicModifier.h index 77f2b922..10952e18 100644 --- a/Sources/Plasma/PubUtilLib/plModifier/plLogicModifier.h +++ b/Sources/Plasma/PubUtilLib/plModifier/plLogicModifier.h @@ -70,6 +70,7 @@ public: virtual void Reset(bool bCounterReset); void VolumeIgnoreExtraEnters(bool ignore = true); // hack for garrison + void VolumeNoArbitration(bool noArbitration = true); int fMyCursor; }; diff --git a/Sources/Plasma/PubUtilLib/plNetCommon/plNetMsgScreener.cpp b/Sources/Plasma/PubUtilLib/plNetCommon/plNetMsgScreener.cpp index 53b97ff5..22714384 100644 --- a/Sources/Plasma/PubUtilLib/plNetCommon/plNetMsgScreener.cpp +++ b/Sources/Plasma/PubUtilLib/plNetCommon/plNetMsgScreener.cpp @@ -127,6 +127,7 @@ plNetMsgScreener::Answer plNetMsgScreener::IAllowMessageType(Int16 classIndex, c case CLASS_INDEX_SCOPED(plClothingMsg): case CLASS_INDEX_SCOPED(plEnableMsg): case CLASS_INDEX_SCOPED(plLinkToAgeMsg): + case CLASS_INDEX_SCOPED(plSubWorldMsg): return kYes; // definitely yes or no (based on whether sender is a CCR) diff --git a/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysical.cpp b/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysical.cpp index 3745f067..ad8afe22 100644 --- a/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysical.cpp +++ b/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysical.cpp @@ -61,6 +61,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "../pnKeyedObject/plKey.h" #include "../pnMessage/plCorrectionMsg.h" #include "../pnMessage/plNodeRefMsg.h" +#include "../pnMessage/plObjRefMsg.h" #include "../pnMessage/plSDLModifierMsg.h" #include "../plMessage/plSimStateMsg.h" #include "../plMessage/plSimInfluenceMsg.h" @@ -72,6 +73,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "../plStatusLog/plStatusLog.h" #include "plPXConvert.h" #include "plPXPhysicalControllerCore.h" +#include "plPXSubWorld.h" #include "../plModifier/plDetectorLog.h" @@ -84,25 +86,6 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #define LogActivate(func) if (fActor->isSleeping()) SimLog("%s activated by %s", GetKeyName(), func); -PhysRecipe::PhysRecipe() - : mass(0.f) - , friction(0.f) - , restitution(0.f) - , bounds(plSimDefs::kBoundsMax) - , group(plSimDefs::kGroupMax) - , reportsOn(0) - , objectKey(nil) - , sceneNode(nil) - , worldKey(nil) - , convexMesh(nil) - , triMesh(nil) - , radius(0.f) - , offset(0.f, 0.f, 0.f) - , meshStream(nil) -{ - l2s.Reset(); -} - plProfile_Extern(MaySendLocation); plProfile_Extern(LocationsSent); plProfile_Extern(PhysicsUpdates); @@ -128,19 +111,15 @@ int plPXPhysical::fNumberAnimatedActivators = 0; plPXPhysical::plPXPhysical() : fSDLMod(nil) , fActor(nil) - , fBoundsType(plSimDefs::kBoundsMax) , fLOSDBs(plSimDefs::kLOSDBNone) , fGroup(plSimDefs::kGroupMax) , fReportsOn(0) , fLastSyncTime(0.0f) , fProxyGen(nil) - , fSceneNode(nil) - , fWorldKey(nil) , fSndGroup(nil) , fWorldHull(nil) , fSaveTriangles(nil) , fHullNumberPlanes(0) - , fMass(0.f) , fWeWereHit(false) , fHitForce(0,0,0) , fHitPos(0,0,0) @@ -354,15 +333,14 @@ hsBool plPXPhysical::Should_I_Trigger(hsBool enter, hsPoint3& pos) } -hsBool plPXPhysical::Init(PhysRecipe& recipe) +hsBool plPXPhysical::Init() { hsBool startAsleep = false; - fBoundsType = recipe.bounds; - fGroup = recipe.group; - fReportsOn = recipe.reportsOn; - fObjectKey = recipe.objectKey; - fSceneNode = recipe.sceneNode; - fWorldKey = recipe.worldKey; + + fGroup = fRecipe.group; + fReportsOn = fRecipe.reportsOn; + fObjectKey = fRecipe.objectKey; + fSceneNode = fRecipe.sceneNode; NxActorDesc actorDesc; NxSphereShapeDesc sphereDesc; @@ -370,19 +348,19 @@ hsBool plPXPhysical::Init(PhysRecipe& recipe) NxTriangleMeshShapeDesc trimeshShapeDesc; NxBoxShapeDesc boxDesc; - plPXConvert::Matrix(recipe.l2s, actorDesc.globalPose); + plPXConvert::Matrix(fRecipe.l2s, actorDesc.globalPose); - switch (fBoundsType) + switch (fRecipe.bounds) { case plSimDefs::kSphereBounds: { hsMatrix44 sphereL2W; sphereL2W.Reset(); - sphereL2W.SetTranslate(&recipe.offset); + sphereL2W.SetTranslate(&fRecipe.offset); - sphereDesc.radius = recipe.radius; + sphereDesc.radius = fRecipe.radius; plPXConvert::Matrix(sphereL2W, sphereDesc.localPose); - sphereDesc.group = fGroup; + sphereDesc.group = fRecipe.group; actorDesc.shapes.pushBack(&sphereDesc); } break; @@ -391,54 +369,54 @@ hsBool plPXPhysical::Init(PhysRecipe& recipe) // If this is read time (ie, meshStream is nil), turn the convex hull // into a box. That way the data won't have to change when convex hulls // actually work right. - if (fGroup == plSimDefs::kGroupDetector && recipe.meshStream == nil) + if (fRecipe.group == plSimDefs::kGroupDetector && fRecipe.meshStream == nil) { #ifdef USE_BOXES_FOR_DETECTOR_HULLS - MakeBoxFromHull(recipe.convexMesh, boxDesc); - plSimulationMgr::GetInstance()->GetSDK()->releaseConvexMesh(*recipe.convexMesh); - boxDesc.group = fGroup; + MakeBoxFromHull(fRecipe.convexMesh, boxDesc); + plSimulationMgr::GetInstance()->GetSDK()->releaseConvexMesh(*fRecipe.convexMesh); + boxDesc.group = fRecipe.group; actorDesc.shapes.push_back(&boxDesc); #else #ifdef USE_PHYSX_CONVEXHULL_WORKAROUND // make a hull of planes for testing IsInside - IMakeHull(recipe.convexMesh,recipe.l2s); + IMakeHull(fRecipe.convexMesh,fRecipe.l2s); #endif // USE_PHYSX_CONVEXHULL_WORKAROUND - convexShapeDesc.meshData = recipe.convexMesh; - convexShapeDesc.userData = recipe.meshStream; - convexShapeDesc.group = fGroup; + convexShapeDesc.meshData = fRecipe.convexMesh; + convexShapeDesc.userData = fRecipe.meshStream; + convexShapeDesc.group = fRecipe.group; actorDesc.shapes.pushBack(&convexShapeDesc); #endif // USE_BOXES_FOR_DETECTOR_HULLS } else { - convexShapeDesc.meshData = recipe.convexMesh; - convexShapeDesc.userData = recipe.meshStream; - convexShapeDesc.group = fGroup; + convexShapeDesc.meshData = fRecipe.convexMesh; + convexShapeDesc.userData = fRecipe.meshStream; + convexShapeDesc.group = fRecipe.group; actorDesc.shapes.pushBack(&convexShapeDesc); } break; case plSimDefs::kBoxBounds: { - boxDesc.dimensions = plPXConvert::Point(recipe.bDimensions); + boxDesc.dimensions = plPXConvert::Point(fRecipe.bDimensions); hsMatrix44 boxL2W; boxL2W.Reset(); - boxL2W.SetTranslate(&recipe.bOffset); + boxL2W.SetTranslate(&fRecipe.bOffset); plPXConvert::Matrix(boxL2W, boxDesc.localPose); - boxDesc.group = fGroup; + boxDesc.group = fRecipe.group; actorDesc.shapes.push_back(&boxDesc); } break; case plSimDefs::kExplicitBounds: case plSimDefs::kProxyBounds: - if (fGroup == plSimDefs::kGroupDetector) + if (fRecipe.group == plSimDefs::kGroupDetector) { SimLog("Someone using an Exact on a detector region: %s", GetKeyName()); } - trimeshShapeDesc.meshData = recipe.triMesh; - trimeshShapeDesc.userData = recipe.meshStream; - trimeshShapeDesc.group = fGroup; + trimeshShapeDesc.meshData = fRecipe.triMesh; + trimeshShapeDesc.userData = fRecipe.meshStream; + trimeshShapeDesc.group = fRecipe.group; actorDesc.shapes.pushBack(&trimeshShapeDesc); break; default: @@ -449,10 +427,9 @@ hsBool plPXPhysical::Init(PhysRecipe& recipe) // Now fill out the body, or dynamic part of the physical NxBodyDesc bodyDesc; - fMass = recipe.mass; - if (recipe.mass != 0) + if (fRecipe.mass != 0) { - bodyDesc.mass = recipe.mass; + bodyDesc.mass = fRecipe.mass; actorDesc.body = &bodyDesc; if (GetProperty(plSimulationInterface::kPinned)) @@ -461,13 +438,13 @@ hsBool plPXPhysical::Init(PhysRecipe& recipe) startAsleep = true; // put it to sleep if they are going to be frozen } - if (fGroup != plSimDefs::kGroupDynamic || GetProperty(plSimulationInterface::kPhysAnim)) + if (fRecipe.group != plSimDefs::kGroupDynamic || GetProperty(plSimulationInterface::kPhysAnim)) { SetProperty(plSimulationInterface::kPassive, true); // Even though the code for animated physicals and animated activators are the same // keep these code snippets separated for fine tuning. Thanks. - if (fGroup == plSimDefs::kGroupDynamic) + if (fRecipe.group == plSimDefs::kGroupDynamic) { // handle the animated physicals.... make kinematic for now. fNumberAnimatedPhysicals++; @@ -495,7 +472,7 @@ hsBool plPXPhysical::Init(PhysRecipe& recipe) // Put the dynamics into actor group 1. The actor groups are only used for // deciding who we get contact reports for. - if (fGroup == plSimDefs::kGroupDynamic) + if (fRecipe.group == plSimDefs::kGroupDynamic) actorDesc.group = 1; NxScene* scene = plSimulationMgr::GetInstance()->GetScene(fWorldKey); @@ -512,7 +489,7 @@ hsBool plPXPhysical::Init(PhysRecipe& recipe) return false; NxShape* shape = fActor->getShapes()[0]; - shape->setMaterial(plSimulationMgr::GetInstance()->GetMaterialIdx(scene, recipe.friction, recipe.restitution)); + shape->setMaterial(plSimulationMgr::GetInstance()->GetMaterialIdx(scene, fRecipe.friction, fRecipe.restitution)); // Turn on the trigger flags for any detectors. // @@ -523,7 +500,7 @@ hsBool plPXPhysical::Init(PhysRecipe& recipe) // problems trying to calculate an intertial tensor. By letting it be // created as a normal dynamic first, then setting the flags, we work around // that problem. - if (fGroup == plSimDefs::kGroupDetector) + if (fRecipe.group == plSimDefs::kGroupDetector) { shape->setFlag(NX_TRIGGER_ON_ENTER, true); shape->setFlag(NX_TRIGGER_ON_LEAVE, true); @@ -547,14 +524,8 @@ hsBool plPXPhysical::Init(PhysRecipe& recipe) plNodeRefMsg* refMsg = TRACKED_NEW plNodeRefMsg(fSceneNode, plRefMsg::kOnCreate, -1, plNodeRefMsg::kPhysical); hsgResMgr::ResMgr()->AddViaNotify(GetKey(), refMsg, plRefFlags::kActiveRef); - if (fWorldKey) - { - plGenRefMsg* ref = TRACKED_NEW plGenRefMsg(GetKey(), plRefMsg::kOnCreate, 0, kPhysRefWorld); - hsgResMgr::ResMgr()->AddViaNotify(fWorldKey, ref, plRefFlags::kActiveRef); - } - // only dynamic physicals without noSync need SDLs - if ( fGroup == plSimDefs::kGroupDynamic && !fProps.IsBitSet(plSimulationInterface::kNoSynchronize) ) + if ( fRecipe.group == plSimDefs::kGroupDynamic && !fProps.IsBitSet(plSimulationInterface::kNoSynchronize) ) { // add SDL modifier plSceneObject* sceneObj = plSceneObject::ConvertNoRef(fObjectKey->ObjectIsLoaded()); @@ -611,29 +582,66 @@ hsBool plPXPhysical::MsgReceive( plMessage* msg ) hsBool plPXPhysical::HandleRefMsg(plGenRefMsg* refMsg) { UInt8 refCtxt = refMsg->GetContext(); - plKey refKey = refMsg->GetRef()->GetKey(); - plKey ourKey = GetKey(); - PhysRefType refType = PhysRefType(refMsg->fType); - const char* refKeyName = refKey ? refKey->GetName() : "MISSING"; + switch (refMsg->fType) { + case kPhysRefWorld: { + switch (refCtxt) { + case plRefMsg::kOnCreate: + case plRefMsg::kOnRequest: + // PotS files specify a plHKSubWorld as the subworld key. For everything else, + // the subworlds are a plSceneObject key. For sanity purposes, we will allow + // references to the plPXSubWorld here. HOWEVER, we will need to grab the target + // and replace our reference... + if (plPXSubWorld* subWorldIface = plPXSubWorld::ConvertNoRef(refMsg->GetRef())) { + hsAssert(subWorldIface->GetOwnerKey(), "subworld owner is NULL?! Uh oh..."); + plGenRefMsg* replaceRefMsg = new plGenRefMsg(GetKey(), plRefMsg::kOnReplace, 0, kPhysRefWorld); + hsgResMgr::ResMgr()->AddViaNotify(subWorldIface->GetOwnerKey(), replaceRefMsg, plRefFlags::kActiveRef); + } + // fall-thru is intentional :) + case plRefMsg::kOnReplace: + // loading into a subworld + if (plSceneObject* subSO = plSceneObject::ConvertNoRef(refMsg->GetRef())) { + fWorldKey = subSO->GetKey(); + + // Cyan produced files will never have plPXSubWorld as this is a H'uru-ism. + // Let us make a default one such that we can play with default subworlds at runtime. + // HAAAAAAAAAX!!! + plPXSubWorld* subWorldIface = plPXSubWorld::ConvertNoRef(subSO->GetGenericInterface(plPXSubWorld::Index())); + if (!subWorldIface) { + subWorldIface = new plPXSubWorld(); + + // This can be simplified if/when incorporating zrax' String Theory library + std::string strKeyName = subSO->GetKeyName(); + strKeyName += "_DefSubWorld"; + const char *cKeyName = strKeyName.c_str(); + + hsgResMgr::ResMgr()->NewKey(cKeyName, + subWorldIface, GetKey()->GetUoid().GetLocation()); + + plObjRefMsg* subIfaceRef = new plObjRefMsg(subSO->GetKey(), plRefMsg::kOnCreate, 0, plObjRefMsg::kInterface); + // this will send the reference immediately + hsgResMgr::ResMgr()->SendRef(subWorldIface, subIfaceRef, plRefFlags::kActiveRef); + } - if (refType == kPhysRefWorld) - { - if (refCtxt == plRefMsg::kOnCreate || refCtxt == plRefMsg::kOnRequest) - { - // Cache the initial transform, since we assume the sceneobject already knows - // that and doesn't need to be told again - IGetTransformGlobal(fCachedLocal2World); + // Now, we can initialize the physical... + Init(); + IGetTransformGlobal(fCachedLocal2World); + return true; + } } - if (refCtxt == plRefMsg::kOnDestroy) - { + break; + case plRefMsg::kOnDestroy: { // our world was deleted out from under us: move to the main world + // NOTE: this was not implemented even before the PXSubWorld rewrite. + // not going to bother! // hsAssert(0, "Lost world"); } + break; } - else if (refType == kPhysRefSndGroup) - { - switch (refCtxt) + break; + + case kPhysRefSndGroup: { + switch (refCtxt) { case plRefMsg::kOnCreate: case plRefMsg::kOnRequest: @@ -645,9 +653,11 @@ hsBool plPXPhysical::HandleRefMsg(plGenRefMsg* refMsg) break; } } - else - { + break; + + default: hsAssert(0, "Unknown ref type, who sent us this?"); + break; } return true; @@ -878,7 +888,6 @@ void plPXPhysical::IGetTransformGlobal(hsMatrix44& l2w) const { plSceneObject* so = plSceneObject::ConvertNoRef(fWorldKey->ObjectIsLoaded()); hsAssert(so, "Scene object not loaded while accessing subworld."); - // We'll hit this at export time, when the ci isn't ready yet, so do a check if (so->GetCoordinateInterface()) { const hsMatrix44& s2w = so->GetCoordinateInterface()->GetLocalToWorld(); @@ -1026,23 +1035,22 @@ void plPXPhysical::Read(hsStream* stream, hsResMgr* mgr) plPhysical::Read(stream, mgr); ClearMatrix(fCachedLocal2World); - PhysRecipe recipe; - recipe.mass = stream->ReadSwapScalar(); - recipe.friction = stream->ReadSwapScalar(); - recipe.restitution = stream->ReadSwapScalar(); - recipe.bounds = (plSimDefs::Bounds)stream->ReadByte(); - recipe.group = (plSimDefs::Group)stream->ReadByte(); - recipe.reportsOn = stream->ReadSwap32(); + fRecipe.mass = stream->ReadSwapScalar(); + fRecipe.friction = stream->ReadSwapScalar(); + fRecipe.restitution = stream->ReadSwapScalar(); + fRecipe.bounds = (plSimDefs::Bounds)stream->ReadByte(); + fRecipe.group = (plSimDefs::Group)stream->ReadByte(); + fRecipe.reportsOn = stream->ReadSwap32(); fLOSDBs = stream->ReadSwap16(); //hack for swim regions currently they are labeled as static av blockers if(fLOSDBs==plSimDefs::kLOSDBSwimRegion) { - recipe.group=plSimDefs::kGroupMax; + fRecipe.group=plSimDefs::kGroupMax; } // - recipe.objectKey = mgr->ReadKey(stream); - recipe.sceneNode = mgr->ReadKey(stream); - recipe.worldKey = mgr->ReadKey(stream); + fRecipe.objectKey = mgr->ReadKey(stream); + fRecipe.sceneNode = mgr->ReadKey(stream); + fRecipe.worldKey = mgr->ReadKeyNotifyMe(stream, new plGenRefMsg(GetKey(), plRefMsg::kOnCreate, 0, kPhysRefWorld), plRefFlags::kActiveRef); mgr->ReadKeyNotifyMe(stream, TRACKED_NEW plGenRefMsg(GetKey(), plRefMsg::kOnCreate, 0, kPhysRefSndGroup), plRefFlags::kActiveRef); @@ -1050,30 +1058,33 @@ void plPXPhysical::Read(hsStream* stream, hsResMgr* mgr) hsQuat rot; pos.Read(stream); rot.Read(stream); - rot.MakeMatrix(&recipe.l2s); - recipe.l2s.SetTranslate(&pos); + rot.MakeMatrix(&fRecipe.l2s); + fRecipe.l2s.SetTranslate(&pos); fProps.Read(stream); - if (recipe.bounds == plSimDefs::kSphereBounds) + if (fRecipe.bounds == plSimDefs::kSphereBounds) { - recipe.radius = stream->ReadSwapScalar(); - recipe.offset.Read(stream); + fRecipe.radius = stream->ReadSwapScalar(); + fRecipe.offset.Read(stream); } - else if (recipe.bounds == plSimDefs::kBoxBounds) + else if (fRecipe.bounds == plSimDefs::kBoxBounds) { - recipe.bDimensions.Read(stream); - recipe.bOffset.Read(stream); + fRecipe.bDimensions.Read(stream); + fRecipe.bOffset.Read(stream); } else { - if (recipe.bounds == plSimDefs::kHullBounds) - recipe.convexMesh = IReadHull(stream); + if (fRecipe.bounds == plSimDefs::kHullBounds) + fRecipe.convexMesh = IReadHull(stream); else - recipe.triMesh = IReadTriMesh(stream); + fRecipe.triMesh = IReadTriMesh(stream); } - Init(recipe); + // If we do not have a world, specified, we go ahead and init into the main world... + // This will been done in MsgReceive otherwise + if (!fRecipe.worldKey) + Init(); hsAssert(!fProxyGen, "Already have proxy gen, double read?"); @@ -1115,7 +1126,7 @@ void plPXPhysical::Read(hsStream* stream, hsResMgr* mgr) // Statics are yellow physColor.Set(1.f,0.8f,0.2f,1.f); // if in a subworld... slightly transparent - if(fWorldKey) + if(fRecipe.worldKey) opac = 0.6f; } else @@ -1241,7 +1252,7 @@ void plPXPhysical::Write(hsStream* stream, hsResMgr* mgr) stream->WriteSwapScalar(fActor->getMass()); stream->WriteSwapScalar(friction); stream->WriteSwapScalar(restitution); - stream->WriteByte(fBoundsType); + stream->WriteByte(fRecipe.bounds); stream->WriteByte(fGroup); stream->WriteSwap32(fReportsOn); stream->WriteSwap16(fLOSDBs); @@ -1259,14 +1270,14 @@ void plPXPhysical::Write(hsStream* stream, hsResMgr* mgr) fProps.Write(stream); - if (fBoundsType == plSimDefs::kSphereBounds) + if (fRecipe.bounds == plSimDefs::kSphereBounds) { const NxSphereShape* sphereShape = shape->isSphere(); stream->WriteSwapScalar(sphereShape->getRadius()); hsPoint3 localPos = plPXConvert::Point(sphereShape->getLocalPosition()); localPos.Write(stream); } - else if (fBoundsType == plSimDefs::kBoxBounds) + else if (fRecipe.bounds == plSimDefs::kBoxBounds) { const NxBoxShape* boxShape = shape->isBox(); hsPoint3 dim = plPXConvert::Point(boxShape->getDimensions()); @@ -1276,7 +1287,7 @@ void plPXPhysical::Write(hsStream* stream, hsResMgr* mgr) } else { - if (fBoundsType == plSimDefs::kHullBounds) + if (fRecipe.bounds == plSimDefs::kHullBounds) hsAssert(shape->isConvexMesh(), "Hull shape isn't a convex mesh"); else hsAssert(shape->isTriangleMesh(), "Exact shape isn't a trimesh"); diff --git a/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysical.h b/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysical.h index 5c4ca8ae..54b99644 100644 --- a/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysical.h +++ b/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysical.h @@ -47,6 +47,9 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "../plPhysical/plSimDefs.h" #include "hsBitVector.h" #include "hsUtils.h" +#include +#include +#include class NxActor; class NxConvexMesh; @@ -72,8 +75,6 @@ class NxCapsule; class PhysRecipe { public: - PhysRecipe(); - hsScalar mass; hsScalar friction; hsScalar restitution; @@ -100,6 +101,12 @@ public: // For export time only. The original data used to create the mesh hsVectorStream* meshStream; + + PhysRecipe() + : mass(0.f), friction(0.f), restitution(0.f), bounds(plSimDefs::kBoundsMax), + group(plSimDefs::kGroupMax), reportsOn(0), convexMesh(nullptr), triMesh(nullptr), + radius(0.f), offset(0.f, 0.f, 0.f), meshStream(nullptr) + { } }; class plPXPhysical : public plPhysical @@ -120,7 +127,7 @@ public: GETINTERFACE_ANY(plPXPhysical, plPhysical); // Export time and internal use only - hsBool Init(PhysRecipe& recipe); + hsBool Init(); virtual void Read(hsStream* s, hsResMgr* mgr); virtual void Write(hsStream* s, hsResMgr* mgr); @@ -191,7 +198,11 @@ public: //this partially for exclude regions vs avatar capsule virtual hsBool OverlapWithCapsule(NxCapsule& cap); - virtual hsScalar GetMass() {return fMass;} + virtual hsScalar GetMass() {return fRecipe.mass;} + + PhysRecipe& GetRecipe() { return fRecipe; } + const PhysRecipe& GetRecipe() const { return fRecipe; } + protected: class NxConvexMesh* IReadHull(hsStream* s); class NxTriangleMesh* IReadTriMesh(hsStream* s); @@ -244,12 +255,11 @@ protected: NxActor* fActor; plKey fWorldKey; // either a subworld or nil - plSimDefs::Bounds fBoundsType; + PhysRecipe fRecipe; plSimDefs::Group fGroup; UInt32 fReportsOn; // bit vector for groups we report interactions with UInt16 fLOSDBs; // Which LOS databases we get put into hsBitVector fProps; // plSimulationInterface::plSimulationProperties kept here - float fMass; plKey fObjectKey; // the key to our scene object plKey fSceneNode; // the room we're in diff --git a/Sources/Plasma/PubUtilLib/plPhysX/plPXSubWorld.cpp b/Sources/Plasma/PubUtilLib/plPhysX/plPXSubWorld.cpp new file mode 100644 index 00000000..b295089a --- /dev/null +++ b/Sources/Plasma/PubUtilLib/plPhysX/plPXSubWorld.cpp @@ -0,0 +1,52 @@ +/*==LICENSE==* +CyanWorlds.com Engine - MMOG client, server and tools +Copyright (C) 2011 Cyan Worlds, Inc. +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +You should have received a copy of the GNU General Public License +along with this program. If not, see . +Additional permissions under GNU GPL version 3 section 7 +If you modify this Program, or any covered work, by linking or +combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, +NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent +JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK +(or a modified version of those libraries), +containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, +PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG +JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the +licensors of this Program grant you additional +permission to convey the resulting work. Corresponding Source for a +non-source form of such a combination shall include the source code for +the parts of OpenSSL and IJG JPEG Library used as well as that of the covered +work. +You can contact Cyan Worlds, Inc. by email legal@cyan.com + or by snail mail at: + Cyan Worlds, Inc. + 14617 N Newport Hwy + Mead, WA 99021 +*==LICENSE==*/ + +#include "plPXSubWorld.h" + +void plPXSubWorld::Read(hsStream* s, hsResMgr* mgr) +{ + plObjInterface::Read(s, mgr); + fGravity.Read(s); +} + +void plPXSubWorld::Write(hsStream* s, hsResMgr* mgr) +{ + plObjInterface::Write(s, mgr); + fGravity.Write(s); +} + +void plPXSubWorld::SetTransform(const hsMatrix44& l2w, const hsMatrix44& w2l) +{ + // All this magick is handled elsewhere... Not asserting due to call spam. +} \ No newline at end of file diff --git a/Sources/Plasma/PubUtilLib/plPhysX/plPXSubWorld.h b/Sources/Plasma/PubUtilLib/plPhysX/plPXSubWorld.h new file mode 100644 index 00000000..77bf5fe0 --- /dev/null +++ b/Sources/Plasma/PubUtilLib/plPhysX/plPXSubWorld.h @@ -0,0 +1,67 @@ +/*==LICENSE==* +CyanWorlds.com Engine - MMOG client, server and tools +Copyright (C) 2011 Cyan Worlds, Inc. +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +You should have received a copy of the GNU General Public License +along with this program. If not, see . +Additional permissions under GNU GPL version 3 section 7 +If you modify this Program, or any covered work, by linking or +combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, +NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent +JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK +(or a modified version of those libraries), +containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, +PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG +JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the +licensors of this Program grant you additional +permission to convey the resulting work. Corresponding Source for a +non-source form of such a combination shall include the source code for +the parts of OpenSSL and IJG JPEG Library used as well as that of the covered +work. +You can contact Cyan Worlds, Inc. by email legal@cyan.com + or by snail mail at: + Cyan Worlds, Inc. + 14617 N Newport Hwy + Mead, WA 99021 +*==LICENSE==*/ + +#ifndef plPXSubWorld_h_inc +#define plPXSubWorld_h_inc + +#include "../../NucleusLib/pnSceneObject/plObjInterface.h" +#include "hsGeometry3.h" + +#define X_GRAVITY 0.f +#define Y_GRAVITY 0.f +#define Z_GRAVITY -32.174049f + +class plPXSubWorld : public plObjInterface +{ + hsVector3 fGravity; + +public: + plPXSubWorld() : fGravity(X_GRAVITY, Y_GRAVITY, Z_GRAVITY) { } + plPXSubWorld(const hsVector3& gravity) : fGravity(gravity) { } + + CLASSNAME_REGISTER(plPXSubWorld); + GETINTERFACE_ANY(plPXSubWorld, plObjInterface); + + void Read(hsStream* s, hsResMgr* mgr) HS_OVERRIDE; + void Write(hsStream* s, hsResMgr* mgr) HS_OVERRIDE; + + Int32 GetNumProperties() const HS_OVERRIDE { return 0; } + void SetTransform(const hsMatrix44& l2w, const hsMatrix44& w2l) HS_OVERRIDE; + + const hsVector3& GetGravity() const { return fGravity; } + hsVector3& GetGravity() { return fGravity; } + void SetGravity(const hsVector3& gravity) { fGravity = gravity; } +}; + +#endif // plPXSubWorld_h_inc \ No newline at end of file diff --git a/Sources/Plasma/PubUtilLib/plPhysX/plPhysXCreatable.h b/Sources/Plasma/PubUtilLib/plPhysX/plPhysXCreatable.h index cf986171..9c8cbfab 100644 --- a/Sources/Plasma/PubUtilLib/plPhysX/plPhysXCreatable.h +++ b/Sources/Plasma/PubUtilLib/plPhysX/plPhysXCreatable.h @@ -48,6 +48,9 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com REGISTER_CREATABLE(plPXPhysical); +#include "plPXSubWorld.h" +REGISTER_CREATABLE(plPXSubWorld); + //#include "plHKSimulationSynchMsg.h" //REGISTER_CREATABLE(plHKSimulationSynchMsg); diff --git a/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.cpp b/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.cpp index 5603c566..fc922676 100644 --- a/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.cpp +++ b/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.cpp @@ -49,6 +49,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "plPXPhysical.h" #include "plPXPhysicalControllerCore.h" #include "plPXConvert.h" +#include "plPXSubWorld.h" #include "plLOSDispatch.h" #include "../plPhysical/plPhysicsSoundMgr.h" #include "../plStatusLog/plStatusLog.h" @@ -424,8 +425,18 @@ NxScene* plSimulationMgr::GetScene(plKey world) { UInt32 maxSteps = (UInt32)hsCeil(fMaxDelta / fStepSize); + // The world key is assumed to be loaded (or null for main world) if we are here. + // As such, let us grab the plSceneObject's PXSubWorld definition to figure out + // what gravity should look like. Who knows, we might be in MC Escher land... + NxVec3 gravity(X_GRAVITY, Y_GRAVITY, Z_GRAVITY); + if (plSceneObject* so = plSceneObject::ConvertNoRef(world->VerifyLoaded())) { + if (plPXSubWorld* subworld = plPXSubWorld::ConvertNoRef(so->GetGenericInterface(plPXSubWorld::Index()))) { + gravity = plPXConvert::Vector(subworld->GetGravity()); + } + } + NxSceneDesc sceneDesc; - sceneDesc.gravity.set(0, 0, -32.174049f); + sceneDesc.gravity = gravity; sceneDesc.userTriggerReport = &gSensorReport; sceneDesc.userContactReport = &gContactReport; sceneDesc.maxTimestep = fStepSize; From 59b45769eeb14cc608315c71d8f6094d2a4863a6 Mon Sep 17 00:00:00 2001 From: John Johns Date: Mon, 31 May 2021 11:14:26 -0700 Subject: [PATCH 02/13] Cleaner string handling courtesy rarified --- Sources/Plasma/PubUtilLib/plPhysX/plPXPhysical.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysical.cpp b/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysical.cpp index ad8afe22..03996b27 100644 --- a/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysical.cpp +++ b/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysical.cpp @@ -611,8 +611,7 @@ hsBool plPXPhysical::HandleRefMsg(plGenRefMsg* refMsg) subWorldIface = new plPXSubWorld(); // This can be simplified if/when incorporating zrax' String Theory library - std::string strKeyName = subSO->GetKeyName(); - strKeyName += "_DefSubWorld"; + std::string strKeyName = std::string(subSO->GetKeyName()) + "_DefSubWorld"; const char *cKeyName = strKeyName.c_str(); hsgResMgr::ResMgr()->NewKey(cKeyName, From e455a71c2ed3eb6215c2ab5e59e712dd2a49a56b Mon Sep 17 00:00:00 2001 From: John Johns Date: Mon, 31 May 2021 15:01:46 -0700 Subject: [PATCH 03/13] Hoikas' framerate unlock https://github.com/H-uru/Plasma/pull/143 --- Sources/Plasma/Apps/plClient/plClient.cpp | 31 +++++------ .../PubUtilLib/plPhysX/plSimulationMgr.cpp | 54 +++++++------------ .../PubUtilLib/plPhysX/plSimulationMgr.h | 17 ------ 3 files changed, 32 insertions(+), 70 deletions(-) diff --git a/Sources/Plasma/Apps/plClient/plClient.cpp b/Sources/Plasma/Apps/plClient/plClient.cpp index c1013bf1..eb5ab0ef 100644 --- a/Sources/Plasma/Apps/plClient/plClient.cpp +++ b/Sources/Plasma/Apps/plClient/plClient.cpp @@ -1287,7 +1287,20 @@ void plClient::IProgressMgrCallbackProc(plOperationProgress * progress) return; fInstance->fMessagePumpProc(); - fInstance->IDraw(); + + // HACK HACK HACK HACK! + // Yes, this is the ORIGINAL, EVIL famerate limit from plClient::IDraw (except I bumped it to 60fps) + // As it so happens, this callback is happening in the main resource loading thread + // Without this NASTY ASS HACK, we draw after loading every KO, which starves the loader. + // At some point, a better solution should be found... Like running the loader in a separate thread. + static float lastDrawTime; + static const float kMaxFrameRate = 1.f/60.f; + float currTime = (float) hsTimer::GetSeconds(); + if ((currTime - lastDrawTime) > kMaxFrameRate) + { + fInstance->IDraw(); + lastDrawTime = currTime; + } } //============================================================================ @@ -1847,22 +1860,6 @@ hsBool plClient::IDrawProgress() { hsBool plClient::IDraw() { - // Limit framerate - static float lastDrawTime; - static const float kMaxFrameRate = 1.f/30.f; - float currTime = (float) hsTimer::GetSeconds(); - if (!fPipeline->IsDebugFlagSet(plPipeDbg::kFlagNVPerfHUD)) - { - // If we're using NVPerfHUD to step through draw calls, - // We're going to have a frame delta of zero. In that - // case we need to draw no matter what, and we don't - // care as much about starving other threads because - // we're presumably just debugging a graphics glitch. - if ((currTime - lastDrawTime) < kMaxFrameRate) - return true; - } - lastDrawTime = currTime; - // If we're shutting down, don't attempt to draw. Doing so // tends to cause a device reload each frame. if (fDone) diff --git a/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.cpp b/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.cpp index 5603c566..b1b8b0bc 100644 --- a/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.cpp +++ b/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.cpp @@ -347,8 +347,6 @@ plSimulationMgr* plSimulationMgr::GetInstance() plSimulationMgr::plSimulationMgr() : fSuspended(true) - , fMaxDelta(kDefaultMaxDelta) - , fStepSize(kDefaultStepSize) , fAccumulator(0.0f) , fStepCount(0) , fLOSDispatch(TRACKED_NEW plLOSDispatch()) @@ -422,16 +420,20 @@ NxScene* plSimulationMgr::GetScene(plKey world) if (!scene) { - UInt32 maxSteps = (UInt32)hsCeil(fMaxDelta / fStepSize); - NxSceneDesc sceneDesc; sceneDesc.gravity.set(0, 0, -32.174049f); sceneDesc.userTriggerReport = &gSensorReport; sceneDesc.userContactReport = &gContactReport; - sceneDesc.maxTimestep = fStepSize; - sceneDesc.maxIter = maxSteps; scene = fSDK->createScene(sceneDesc); + // See "Advancing The Simulation State" in the PhysX SDK Documentation + // This will cause PhysX to only update for our step size. If we call simulate + // faster than that, PhysX will return immediately. If we call it slower than that, + // PhysX will do some extra steps for us (isn't that nice?). + // Anyway, this should be a good way to make us independent of the framerate. + // If not, I blame the usual suspects + scene->setTiming(kDefaultStepSize); + // Most physicals use the default friction and restitution values, so we // make them the default. NxMaterial* mat = scene->getMaterialFromIndex(0); @@ -605,25 +607,25 @@ void plSimulationMgr::Advance(float delSecs) return; fAccumulator += delSecs; - if (fAccumulator < fStepSize) + if (fAccumulator < kDefaultStepSize) { // Not enough time has passed to perform a substep. - plPXPhysicalControllerCore::UpdateNonPhysical(fAccumulator / fStepSize); + plPXPhysicalControllerCore::UpdateNonPhysical(fAccumulator / kDefaultStepSize); return; } - else if (fAccumulator > fMaxDelta) + else if (fAccumulator > kDefaultMaxDelta) { if (fExtraProfile) - Log("Step clamped from %f to limit of %f", fAccumulator, fMaxDelta); - fAccumulator = fMaxDelta; + Log("Step clamped from %f to limit of %f", fAccumulator, kDefaultMaxDelta); + fAccumulator = kDefaultMaxDelta; } ++fStepCount; - // Perform as many whole substeps as possible saving the remainder in our accumulator. - int numSubSteps = (int)(fAccumulator / fStepSize + 0.000001f); - float delta = numSubSteps * fStepSize; - fAccumulator -= delta; + // Perform as many whole substeps as possible saving the remainder in our accumulator. + int numSubSteps = (int)(fAccumulator / kDefaultStepSize + 0.000001f); + float delta = numSubSteps * kDefaultStepSize; + fAccumulator -= delta; plProfile_IncCount(StepLen, (int)(delta*1000)); plProfile_BeginTiming(Step); @@ -649,7 +651,7 @@ void plSimulationMgr::Advance(float delSecs) } } - plPXPhysicalControllerCore::Update(numSubSteps, fAccumulator / fStepSize); + plPXPhysicalControllerCore::Update(numSubSteps, fAccumulator / kDefaultStepSize); //sending off and clearing the Collision Messages generated by scene->simulate IDispatchCollisionMessages(); @@ -773,26 +775,6 @@ void plSimulationMgr::ISendUpdates() // ///////////////////////////////////////////////////////////////// -void plSimulationMgr::SetMaxDelta(float maxDelta) -{ - fMaxDelta = maxDelta; -} - -float plSimulationMgr::GetMaxDelta() const -{ - return fMaxDelta; -} - -void plSimulationMgr::SetStepsPerSecond(int stepsPerSecond) -{ - fStepSize = 1.0f / (float)stepsPerSecond; -} - -int plSimulationMgr::GetStepsPerSecond() -{ - return (int)((1.0 / fStepSize) + 0.5f); // round to nearest int -} - int plSimulationMgr::GetMaterialIdx(NxScene* scene, hsScalar friction, hsScalar restitution) { if (friction == 0.5f && restitution == 0.5f) diff --git a/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.h b/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.h index 7f85cd1c..34975a23 100644 --- a/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.h +++ b/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.h @@ -115,20 +115,6 @@ protected: plSimulationMgr(); virtual ~plSimulationMgr(); - // Set the maximum amount of time (in seconds) that the physics will advance - // between frames. If a frame-to-frame delta is bigger than this, we'll - // clamp it to this value. - // WARNING: animation doesn't do this, so if we clamp the time animated - // physicals and the avatar may move at a faster rate than usual. - void SetMaxDelta(float maxDelta); - float GetMaxDelta() const; - - // Set the number of steps per second that physics will advance. - // The more steps per second, the less fallthough and more accurate - // simulation response. - void SetStepsPerSecond(int stepsPerSecond); - int GetStepsPerSecond(); - // Walk through the synchronization requests and send them as appropriate. void IProcessSynchs(); @@ -157,10 +143,7 @@ protected: // but nothing will move. bool fSuspended; - float fMaxDelta; - float fStepSize; float fAccumulator; - UInt32 fStepCount; // A utility class to keep track of a request for a physical synchronization. From 5fc5c81c0832b814c7ef67099ff2dd7b497ef0c1 Mon Sep 17 00:00:00 2001 From: John Johns Date: Mon, 31 May 2021 16:15:26 -0700 Subject: [PATCH 04/13] Hoikas' fix for crash when triggering missing animation https://github.com/H-uru/Plasma/pull/103 --- .../Plasma/PubUtilLib/plAvatar/plAnimStage.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Sources/Plasma/PubUtilLib/plAvatar/plAnimStage.cpp b/Sources/Plasma/PubUtilLib/plAvatar/plAnimStage.cpp index 4a6c9814..0b481513 100644 --- a/Sources/Plasma/PubUtilLib/plAvatar/plAnimStage.cpp +++ b/Sources/Plasma/PubUtilLib/plAvatar/plAnimStage.cpp @@ -424,6 +424,14 @@ bool plAnimStage::IMoveBackward(double time, float delta, float &overrun, plArma bool infiniteLoop = fLoops == -1; bool loopsRemain = fCurLoop > 0 || infiniteLoop; + // If we don't have this animation, just pretend to have worked. + // Otherwise, we crash the client. + if (!fAnimInstance) + { + hsAssert(false, "AnimInstance nil"); + return true; + } + // This must be here before we set the local time. if (fAnimInstance->GetTimeConvert()) fAnimInstance->GetTimeConvert()->Backwards(); @@ -476,6 +484,14 @@ bool plAnimStage::IMoveForward(double time, float delta, float &overrun, plArmat // first get the target time in local time, ignoring overruns float target = fLocalTime + delta; + // If we don't have this animation, just pretend to have worked. + // Otherwise, we crash the client. + if (!fAnimInstance) + { + hsAssert(false, "AnimInstance nil"); + return true; + } + if (fAnimInstance->GetTimeConvert()) fAnimInstance->GetTimeConvert()->Forewards(); From 0c5c58679143b13b33a9348093e0759ea7812196 Mon Sep 17 00:00:00 2001 From: John Johns Date: Sat, 5 Jun 2021 20:13:17 -0700 Subject: [PATCH 05/13] Unstringtheoryify the DebugMsg --- Sources/Plasma/NucleusLib/pnModifier/plLogicModBase.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Sources/Plasma/NucleusLib/pnModifier/plLogicModBase.cpp b/Sources/Plasma/NucleusLib/pnModifier/plLogicModBase.cpp index deb05294..66131615 100644 --- a/Sources/Plasma/NucleusLib/pnModifier/plLogicModBase.cpp +++ b/Sources/Plasma/NucleusLib/pnModifier/plLogicModBase.cpp @@ -173,8 +173,9 @@ hsBool plLogicModBase::MsgReceive(plMessage* msg) void plLogicModBase::IHandleArbitration(plServerReplyMsg* pSMsg) { hsAssert(pSMsg->GetType() != plServerReplyMsg::kUnInit, "uninit server reply msg"); - plNetClientApp::GetInstance()->DebugMsg("LM: LogicModifier {} recvd trigger request reply:{}, wasRequesting={}, t={f}\n", - GetKeyName(), + + plNetClientApp::GetInstance()->DebugMsg("LM: LogicModifier %s recvd trigger request reply:%s, wasRequesting=%d, t=%f\n", + GetKeyName().c_str(), pSMsg->GetType() == plServerReplyMsg::kDeny ? "denied" : "confirmed", HasFlag(kRequestingTrigger), hsTimer::GetSysSeconds()); From 40c692d6a9ec5441e2949edf32c6dc18378daed1 Mon Sep 17 00:00:00 2001 From: John Johns Date: Sat, 5 Jun 2021 20:23:56 -0700 Subject: [PATCH 06/13] Remove an unnecessary 'virtual' per Adam --- .../FeatureLib/pfConditional/plObjectInBoxConditionalObject.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Plasma/FeatureLib/pfConditional/plObjectInBoxConditionalObject.h b/Sources/Plasma/FeatureLib/pfConditional/plObjectInBoxConditionalObject.h index 27c1accc..c215ad60 100644 --- a/Sources/Plasma/FeatureLib/pfConditional/plObjectInBoxConditionalObject.h +++ b/Sources/Plasma/FeatureLib/pfConditional/plObjectInBoxConditionalObject.h @@ -133,7 +133,7 @@ public: CLASSNAME_REGISTER(plVolumeSensorConditionalObjectNoArbitration); GETINTERFACE_ANY( plVolumeSensorConditionalObjectNoArbitration, plVolumeSensorConditionalObject); - virtual void Read(hsStream* stream, hsResMgr* mgr) HS_OVERRIDE; + void Read(hsStream* stream, hsResMgr* mgr) HS_OVERRIDE; }; From a6c941b08713be1621590e16b342fce0015999f4 Mon Sep 17 00:00:00 2001 From: John Johns Date: Sun, 6 Jun 2021 11:50:21 -0700 Subject: [PATCH 07/13] Fix previous fix for destringtheoryification --- Sources/Plasma/NucleusLib/pnModifier/plLogicModBase.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Plasma/NucleusLib/pnModifier/plLogicModBase.cpp b/Sources/Plasma/NucleusLib/pnModifier/plLogicModBase.cpp index 66131615..80c8dc2b 100644 --- a/Sources/Plasma/NucleusLib/pnModifier/plLogicModBase.cpp +++ b/Sources/Plasma/NucleusLib/pnModifier/plLogicModBase.cpp @@ -175,7 +175,7 @@ void plLogicModBase::IHandleArbitration(plServerReplyMsg* pSMsg) hsAssert(pSMsg->GetType() != plServerReplyMsg::kUnInit, "uninit server reply msg"); plNetClientApp::GetInstance()->DebugMsg("LM: LogicModifier %s recvd trigger request reply:%s, wasRequesting=%d, t=%f\n", - GetKeyName().c_str(), + GetKeyName(), pSMsg->GetType() == plServerReplyMsg::kDeny ? "denied" : "confirmed", HasFlag(kRequestingTrigger), hsTimer::GetSysSeconds()); From 22d7ff292c70b139d16cfc99163e58f8a98c5722 Mon Sep 17 00:00:00 2001 From: John Johns Date: Sun, 6 Jun 2021 14:52:56 -0700 Subject: [PATCH 08/13] Fix misplaced insert of DelayArbitration command --- .../FeatureLib/pfConsole/pfConsoleCommands.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfConsole/pfConsoleCommands.cpp b/Sources/Plasma/FeatureLib/pfConsole/pfConsoleCommands.cpp index 6a140eb4..38daf6b9 100644 --- a/Sources/Plasma/FeatureLib/pfConsole/pfConsoleCommands.cpp +++ b/Sources/Plasma/FeatureLib/pfConsole/pfConsoleCommands.cpp @@ -447,15 +447,6 @@ PF_CONSOLE_BASE_CMD( SampleCmd3, "int, ...", "Sample command #3" ) } } -PF_CONSOLE_CMD(Logic, - DelayArbitration, - "int millis", - "Simulates network delay for LogicMod arbitration") -{ - int ms = params[0]; - plLogicModBase::SetArbitrationDelay(ms); -} - #endif // LIMIT_CONSOLE_COMMANDS @@ -3345,6 +3336,15 @@ PF_CONSOLE_CMD(Logic, WriteDetectorLog, "", "Write detector log to logfile") DetectorDoLogfile(); } +PF_CONSOLE_CMD(Logic, + DelayArbitration, + "int millis", + "Simulates network delay for LogicMod arbitration") +{ + int ms = params[0]; + plLogicModBase::SetArbitrationDelay(ms); +} + #endif // LIMIT_CONSOLE_COMMANDS //////////////////////////////////////////////////////////////////////// From d0f1e6f3e7f8c083e60249e6c1fa30f124bfadb2 Mon Sep 17 00:00:00 2001 From: John Johns Date: Thu, 24 Jun 2021 22:05:24 -0700 Subject: [PATCH 09/13] Remove the PhysX changes orig. bundled with unlock --- .../PubUtilLib/plPhysX/plSimulationMgr.cpp | 44 ++++++++++++------- .../PubUtilLib/plPhysX/plSimulationMgr.h | 18 ++++++++ 2 files changed, 47 insertions(+), 15 deletions(-) diff --git a/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.cpp b/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.cpp index b1b8b0bc..0715523e 100644 --- a/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.cpp +++ b/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.cpp @@ -347,6 +347,8 @@ plSimulationMgr* plSimulationMgr::GetInstance() plSimulationMgr::plSimulationMgr() : fSuspended(true) + , fMaxDelta(kDefaultMaxDelta) + , fStepSize(kDefaultStepSize) , fAccumulator(0.0f) , fStepCount(0) , fLOSDispatch(TRACKED_NEW plLOSDispatch()) @@ -420,20 +422,16 @@ NxScene* plSimulationMgr::GetScene(plKey world) if (!scene) { + UInt32 maxSteps = (UInt32)hsCeil(fMaxDelta / fStepSize); + NxSceneDesc sceneDesc; sceneDesc.gravity.set(0, 0, -32.174049f); sceneDesc.userTriggerReport = &gSensorReport; sceneDesc.userContactReport = &gContactReport; + sceneDesc.maxTimestep = fStepSize; + sceneDesc.maxIter = maxSteps; scene = fSDK->createScene(sceneDesc); - // See "Advancing The Simulation State" in the PhysX SDK Documentation - // This will cause PhysX to only update for our step size. If we call simulate - // faster than that, PhysX will return immediately. If we call it slower than that, - // PhysX will do some extra steps for us (isn't that nice?). - // Anyway, this should be a good way to make us independent of the framerate. - // If not, I blame the usual suspects - scene->setTiming(kDefaultStepSize); - // Most physicals use the default friction and restitution values, so we // make them the default. NxMaterial* mat = scene->getMaterialFromIndex(0); @@ -607,24 +605,24 @@ void plSimulationMgr::Advance(float delSecs) return; fAccumulator += delSecs; - if (fAccumulator < kDefaultStepSize) + if (fAccumulator < fStepSize) { // Not enough time has passed to perform a substep. - plPXPhysicalControllerCore::UpdateNonPhysical(fAccumulator / kDefaultStepSize); + plPXPhysicalControllerCore::UpdateNonPhysical(fAccumulator / fStepSize); return; } - else if (fAccumulator > kDefaultMaxDelta) + else if (fAccumulator > fMaxDelta) { if (fExtraProfile) - Log("Step clamped from %f to limit of %f", fAccumulator, kDefaultMaxDelta); + Log("Step clamped from %f to limit of %f", fAccumulator, fMaxDelta); fAccumulator = kDefaultMaxDelta; } ++fStepCount; // Perform as many whole substeps as possible saving the remainder in our accumulator. - int numSubSteps = (int)(fAccumulator / kDefaultStepSize + 0.000001f); - float delta = numSubSteps * kDefaultStepSize; + int numSubSteps = (int)(fAccumulator / fStepSize + 0.000001f); + float delta = numSubSteps * fStepSize; fAccumulator -= delta; plProfile_IncCount(StepLen, (int)(delta*1000)); @@ -651,7 +649,7 @@ void plSimulationMgr::Advance(float delSecs) } } - plPXPhysicalControllerCore::Update(numSubSteps, fAccumulator / kDefaultStepSize); + plPXPhysicalControllerCore::Update(numSubSteps, fAccumulator / fStepSize); //sending off and clearing the Collision Messages generated by scene->simulate IDispatchCollisionMessages(); @@ -774,6 +772,22 @@ void plSimulationMgr::ISendUpdates() // RESOLUTION & TIMEOUT PARAMETERS // ///////////////////////////////////////////////////////////////// +void plSimulationMgr::SetMaxDelta(float maxDelta) +{ + fMaxDelta = maxDelta; +} +float plSimulationMgr::GetMaxDelta() const +{ + return fMaxDelta; +} +void plSimulationMgr::SetStepsPerSecond(int stepsPerSecond) +{ + fStepSize = 1.0f / (float)stepsPerSecond; +} +int plSimulationMgr::GetStepsPerSecond() +{ + return (int)((1.0 / fStepSize) + 0.5f); // round to nearest int +} int plSimulationMgr::GetMaterialIdx(NxScene* scene, hsScalar friction, hsScalar restitution) { diff --git a/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.h b/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.h index 34975a23..5720669a 100644 --- a/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.h +++ b/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.h @@ -115,6 +115,20 @@ protected: plSimulationMgr(); virtual ~plSimulationMgr(); + // Set the maximum amount of time (in seconds) that the physics will advance + // between frames. If a frame-to-frame delta is bigger than this, we'll + // clamp it to this value. + // WARNING: animation doesn't do this, so if we clamp the time animated + // physicals and the avatar may move at a faster rate than usual. + void SetMaxDelta(float maxDelta); + float GetMaxDelta() const; + + // Set the number of steps per second that physics will advance. + // The more steps per second, the less fallthough and more accurate + // simulation response. + void SetStepsPerSecond(int stepsPerSecond); + int GetStepsPerSecond(); + // Walk through the synchronization requests and send them as appropriate. void IProcessSynchs(); @@ -143,7 +157,11 @@ protected: // but nothing will move. bool fSuspended; + float fMaxDelta; + float fStepSize; + float fAccumulator; + UInt32 fStepCount; // A utility class to keep track of a request for a physical synchronization. From f57ce3a775692b3e2065b0090adc5080bf504717 Mon Sep 17 00:00:00 2001 From: rarified Date: Sun, 27 Jun 2021 10:01:36 -0600 Subject: [PATCH 10/13] index on master: c914ba5b Merge branch 'rarified/directoryreorg' closes #6 --- Build/VS2010/Plasma/Apps/plClient/plClient.vcxproj | 8 ++++---- Sources/Plasma/CoreLib/hsTypes.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Build/VS2010/Plasma/Apps/plClient/plClient.vcxproj b/Build/VS2010/Plasma/Apps/plClient/plClient.vcxproj index 6c030412..060030e7 100644 --- a/Build/VS2010/Plasma/Apps/plClient/plClient.vcxproj +++ b/Build/VS2010/Plasma/Apps/plClient/plClient.vcxproj @@ -426,12 +426,12 @@ %(PreprocessorDefinitions) %(PreprocessorDefinitions) - \Plasma20\Plasma20\..\Sources\Plasma\Apps\plClient\res;%(AdditionalIncludeDirectories) - \Plasma20\Plasma20\..\Sources\Plasma\Apps\plClient\res;%(AdditionalIncludeDirectories) + ..\..\..\..\Sources\Plasma\Apps\plClient\res;%(AdditionalIncludeDirectories) + ..\..\..\..\Sources\Plasma\Apps\plClient\res;%(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) - \Plasma20\Plasma20\..\Sources\Plasma\Apps\plClient\res;%(AdditionalIncludeDirectories) - \Plasma20\Plasma20\..\Sources\Plasma\Apps\plClient\res;%(AdditionalIncludeDirectories) + ..\..\..\..\Sources\Plasma\Apps\plClient\res;%(AdditionalIncludeDirectories) + ..\..\..\..\Sources\Plasma\Apps\plClient\res;%(AdditionalIncludeDirectories) diff --git a/Sources/Plasma/CoreLib/hsTypes.h b/Sources/Plasma/CoreLib/hsTypes.h index 254eac17..8beec654 100644 --- a/Sources/Plasma/CoreLib/hsTypes.h +++ b/Sources/Plasma/CoreLib/hsTypes.h @@ -597,7 +597,7 @@ void DebugMsgV (const char fmt[], va_list args); #ifdef PLASMA_EXTERNAL_RELEASE #define hsStatusMessage(x) NULL_STMT - #define hsStatusMessageF(x,y) NULL_STMT + #define hsStatusMessageF(x, ...) NULL_STMT #else /* Not external release */ From fe15d68425975217f2b7b780660840661fa5ce9e Mon Sep 17 00:00:00 2001 From: rarified Date: Sun, 27 Jun 2021 10:03:15 -0600 Subject: [PATCH 11/13] Incorporate stashed fixes to build paths, hsTypes.h macro to reduce build warning noise. --- .../MSVC10Projects/Plasma/Apps/plClient/plClient.vcxproj | 8 ++++---- .../Plasma20/Sources/Plasma/CoreLib/hsTypes.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/MOULOpenSourceClientPlugin/Plasma20/MSVC10Projects/Plasma/Apps/plClient/plClient.vcxproj b/MOULOpenSourceClientPlugin/Plasma20/MSVC10Projects/Plasma/Apps/plClient/plClient.vcxproj index b785950a..eab0e966 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/MSVC10Projects/Plasma/Apps/plClient/plClient.vcxproj +++ b/MOULOpenSourceClientPlugin/Plasma20/MSVC10Projects/Plasma/Apps/plClient/plClient.vcxproj @@ -426,12 +426,12 @@ %(PreprocessorDefinitions) %(PreprocessorDefinitions) - \Plasma20\Plasma20\Sources\Plasma\Apps\plClient\res;%(AdditionalIncludeDirectories) - \Plasma20\Plasma20\Sources\Plasma\Apps\plClient\res;%(AdditionalIncludeDirectories) + ..\..\..\..\Sources\Plasma\Apps\plClient\res;%(AdditionalIncludeDirectories) + ..\..\..\..\Sources\Plasma\Apps\plClient\res;%(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) - \Plasma20\Plasma20\Sources\Plasma\Apps\plClient\res;%(AdditionalIncludeDirectories) - \Plasma20\Plasma20\Sources\Plasma\Apps\plClient\res;%(AdditionalIncludeDirectories) + ..\..\..\..\Sources\Plasma\Apps\plClient\res;%(AdditionalIncludeDirectories) + ..\..\..\..\Sources\Plasma\Apps\plClient\res;%(AdditionalIncludeDirectories) diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/CoreLib/hsTypes.h b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/CoreLib/hsTypes.h index 254eac17..8beec654 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/CoreLib/hsTypes.h +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/CoreLib/hsTypes.h @@ -597,7 +597,7 @@ void DebugMsgV (const char fmt[], va_list args); #ifdef PLASMA_EXTERNAL_RELEASE #define hsStatusMessage(x) NULL_STMT - #define hsStatusMessageF(x,y) NULL_STMT + #define hsStatusMessageF(x, ...) NULL_STMT #else /* Not external release */ From 4550451ae58d7ab06b2f572dee1811552a77cc61 Mon Sep 17 00:00:00 2001 From: John Johns Date: Fri, 2 Jul 2021 17:57:23 -0700 Subject: [PATCH 12/13] Fix things that framerate unlock will expose Hoikas pointed these out to me https://github.com/H-uru/Plasma/pull/503 https://github.com/H-uru/Plasma/pull/505 --- .../Plasma/PubUtilLib/plInterp/hsInterp.cpp | 2 +- .../PubUtilLib/plInterp/plAnimTimeConvert.cpp | 18 ++++++++++++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/Sources/Plasma/PubUtilLib/plInterp/hsInterp.cpp b/Sources/Plasma/PubUtilLib/plInterp/hsInterp.cpp index 092e7496..8495f710 100644 --- a/Sources/Plasma/PubUtilLib/plInterp/hsInterp.cpp +++ b/Sources/Plasma/PubUtilLib/plInterp/hsInterp.cpp @@ -404,7 +404,7 @@ void hsInterp::GetBoundaryKeyFrames(hsScalar time, UInt32 numKeys, void *keys, U { hsAssert(numKeys>1, "Must have more than 1 keyframe"); int k1, k2; - UInt16 frame = (UInt16)(time * MAX_FRAMES_PER_SEC); + float frame = (time * MAX_FRAMES_PER_SEC); // boundary case, past end if (frame > GetKey(numKeys-1, keys, size)->fFrame) diff --git a/Sources/Plasma/PubUtilLib/plInterp/plAnimTimeConvert.cpp b/Sources/Plasma/PubUtilLib/plInterp/plAnimTimeConvert.cpp index d0f5e4e7..31970667 100644 --- a/Sources/Plasma/PubUtilLib/plInterp/plAnimTimeConvert.cpp +++ b/Sources/Plasma/PubUtilLib/plInterp/plAnimTimeConvert.cpp @@ -557,8 +557,13 @@ hsScalar plAnimTimeConvert::WorldToAnimTime(double wSecs) { if (secs > fLoopEnd) { - secs = fmodf(secs - fLoopBegin, fLoopEnd - fLoopBegin) + fLoopBegin; - wrapped = true; + float result = fmodf(secs - fLoopBegin, fLoopEnd - fLoopBegin) + fLoopBegin; + // if fLoopBegin == fLoopEnd == 0, result will not be a number + if (!isnan(result)) + { + secs = result; + wrapped = true; + } } } } @@ -576,8 +581,13 @@ hsScalar plAnimTimeConvert::WorldToAnimTime(double wSecs) { if (secs < fLoopBegin) { - secs = fLoopEnd - fmodf(fLoopEnd - secs, fLoopEnd - fLoopBegin); - wrapped = true; + float result = fLoopEnd - fmodf(fLoopEnd - secs, fLoopEnd - fLoopBegin); + // if fLoopBegin == fLoopEnd == 0, result will not be a number + if (!isnan(result)) + { + secs = result; + wrapped = true; + } } } } From 8ca8eb29d3d70c1a9433e26555e3080178e40b58 Mon Sep 17 00:00:00 2001 From: rarified Date: Tue, 6 Jul 2021 14:37:41 -0600 Subject: [PATCH 13/13] Replace isnan() reference with _isnan(). VS2010 didn't have it in std::cmath. --- Sources/Plasma/PubUtilLib/plInterp/plAnimTimeConvert.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/Plasma/PubUtilLib/plInterp/plAnimTimeConvert.cpp b/Sources/Plasma/PubUtilLib/plInterp/plAnimTimeConvert.cpp index 31970667..48b0667c 100644 --- a/Sources/Plasma/PubUtilLib/plInterp/plAnimTimeConvert.cpp +++ b/Sources/Plasma/PubUtilLib/plInterp/plAnimTimeConvert.cpp @@ -559,7 +559,7 @@ hsScalar plAnimTimeConvert::WorldToAnimTime(double wSecs) { float result = fmodf(secs - fLoopBegin, fLoopEnd - fLoopBegin) + fLoopBegin; // if fLoopBegin == fLoopEnd == 0, result will not be a number - if (!isnan(result)) + if (!_isnan(result)) { secs = result; wrapped = true; @@ -583,7 +583,7 @@ hsScalar plAnimTimeConvert::WorldToAnimTime(double wSecs) { float result = fLoopEnd - fmodf(fLoopEnd - secs, fLoopEnd - fLoopBegin); // if fLoopBegin == fLoopEnd == 0, result will not be a number - if (!isnan(result)) + if (!_isnan(result)) { secs = result; wrapped = true;