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/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/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/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/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 */
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..c215ad60 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);
+
+ 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..38daf6b9 100644
--- a/Sources/Plasma/FeatureLib/pfConsole/pfConsoleCommands.cpp
+++ b/Sources/Plasma/FeatureLib/pfConsole/pfConsoleCommands.cpp
@@ -3336,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
////////////////////////////////////////////////////////////////////////
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/pfLocalizationMgr/pfLocalizationDataMgr.cpp b/Sources/Plasma/FeatureLib/pfLocalizationMgr/pfLocalizationDataMgr.cpp
index 5507db20..5be240b7 100644
--- a/Sources/Plasma/FeatureLib/pfLocalizationMgr/pfLocalizationDataMgr.cpp
+++ b/Sources/Plasma/FeatureLib/pfLocalizationMgr/pfLocalizationDataMgr.cpp
@@ -278,10 +278,7 @@ void XMLCALL LocalizationXMLFile::HandleData(void *userData, const XML_Char *dat
// This gets all data between tags, including indentation and newlines
// so we'll have to ignore data when we aren't expecting it (not in a translation tag)
- std::wstring wData = L"";
-
- for (int i = 0; i < stringLength; i++)
- wData += data[i];
+ std::wstring wData = std::wstring(data, stringLength);
// we must be in a translation tag since that's the only tag that doesn't ignore the contents
file->fData[file->fCurrentAge][file->fCurrentSet][file->fCurrentElement][file->fCurrentTranslation] += wData;
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/FeatureLib/pfPython/pyVault.cpp b/Sources/Plasma/FeatureLib/pfPython/pyVault.cpp
index 46707a9e..1c40f4f1 100644
--- a/Sources/Plasma/FeatureLib/pfPython/pyVault.cpp
+++ b/Sources/Plasma/FeatureLib/pfPython/pyVault.cpp
@@ -365,7 +365,7 @@ void pyVault::AddChronicleEntry( const char * name, UInt32 type, const char * va
wchar * wEntryName = StrDupToUnicode(name);
wchar * wEntryValue = StrDupToUnicode(value);
- VaultAddChronicleEntryAndWait(wEntryName, type, wEntryValue);
+ VaultAddChronicleEntry(wEntryName, type, wEntryValue);
FREE(wEntryName);
FREE(wEntryValue);
@@ -379,6 +379,8 @@ void pyVault::SendToDevice( pyVaultNode& node, const char * deviceName )
wchar wDevName[256];
StrToUnicode(wDevName, deviceName, arrsize(wDevName));
+
+ // Note: This actually blocks (~Hoikas)
VaultPublishNode(node.GetNode()->nodeId, wDevName);
}
@@ -544,12 +546,14 @@ void pyVault::RegisterMTStation( const char * stationName, const char * backLink
wchar wSpawnPt[256];
StrToUnicode(wStationName, stationName, arrsize(wStationName));
StrToUnicode(wSpawnPt, backLinkSpawnPtObjName, arrsize(wSpawnPt));
+
+ // Note: This doesn't actually block (~Hoikas)
VaultRegisterMTStationAndWait( wStationName, wSpawnPt);
}
void pyVault::RegisterOwnedAge( const pyAgeLinkStruct & link )
{
- VaultRegisterOwnedAgeAndWait(link.GetAgeLink());
+ VaultRegisterOwnedAge(link.GetAgeLink());
}
void pyVault::UnRegisterOwnedAge( const char * ageFilename )
@@ -561,7 +565,7 @@ void pyVault::UnRegisterOwnedAge( const char * ageFilename )
void pyVault::RegisterVisitAge( const pyAgeLinkStruct & link )
{
- VaultRegisterVisitAgeAndWait(link.GetAgeLink());
+ VaultRegisterVisitAge(link.GetAgeLink());
}
void pyVault::UnRegisterVisitAge( const char * guidstr )
@@ -573,22 +577,32 @@ void pyVault::UnRegisterVisitAge( const char * guidstr )
VaultUnregisterVisitAgeAndWait(&info);
}
+//============================================================================
+void _InvitePlayerToAge(ENetError result, void* state, void* param, RelVaultNode* node)
+{
+ if (result == kNetSuccess)
+ VaultSendNode(node, (UInt32)param);
+}
+
void pyVault::InvitePlayerToAge( const pyAgeLinkStruct & link, UInt32 playerID )
{
- ENetError error;
NetVaultNode * templateNode = NEWZERO(NetVaultNode);
templateNode->IncRef();
templateNode->SetNodeType(plVault::kNodeType_TextNote);
VaultTextNoteNode visitAcc(templateNode);
visitAcc.SetNoteType(plVault::kNoteType_Visit);
visitAcc.SetVisitInfo(*link.GetAgeLink()->GetAgeInfo());
- if (RelVaultNode * rvn = VaultCreateNodeAndWaitIncRef(templateNode, &error)) {
- VaultSendNode(rvn, playerID);
- rvn->DecRef();
- }
+ VaultCreateNode(templateNode, (FVaultCreateNodeCallback)_InvitePlayerToAge, nil, (void*)playerID);
templateNode->DecRef();
}
+//============================================================================
+void _UninvitePlayerToAge(ENetError result, void* state, void* param, RelVaultNode* node)
+{
+ if (result == kNetSuccess)
+ VaultSendNode(node, (UInt32)param);
+}
+
void pyVault::UnInvitePlayerToAge( const char * str, UInt32 playerID )
{
plAgeInfoStruct info;
@@ -604,32 +618,32 @@ void pyVault::UnInvitePlayerToAge( const char * str, UInt32 playerID )
rvnLink->DecRef();
}
- ENetError error;
NetVaultNode * templateNode = NEWZERO(NetVaultNode);
templateNode->IncRef();
templateNode->SetNodeType(plVault::kNodeType_TextNote);
VaultTextNoteNode visitAcc(templateNode);
visitAcc.SetNoteType(plVault::kNoteType_UnVisit);
visitAcc.SetVisitInfo(info);
- if (RelVaultNode * rvn = VaultCreateNodeAndWaitIncRef(templateNode, &error)) {
- VaultSendNode(rvn, playerID);
- rvn->DecRef();
- }
+ VaultCreateNode(templateNode, (FVaultCreateNodeCallback)_UninvitePlayerToAge, nil, (void*)playerID);
templateNode->DecRef();
}
+//============================================================================
void pyVault::OfferLinkToPlayer( const pyAgeLinkStruct & link, UInt32 playerID )
{
hsAssert(false, "eric, port me");
}
+//============================================================================
void pyVault::CreateNeighborhood()
{
plNetClientMgr * nc = plNetClientMgr::GetInstance();
- // Unregister old hood
+ // Unregister old hood
plAgeInfoStruct info;
info.SetAgeFilename(kNeighborhoodAgeFilename);
+
+ // Note: This doesn't actually block (~Hoikas)
VaultUnregisterOwnedAgeAndWait(&info);
// Register new hood
@@ -656,11 +670,12 @@ void pyVault::CreateNeighborhood()
link.GetAgeInfo()->SetAgeUserDefinedName( title.c_str() );
link.GetAgeInfo()->SetAgeDescription( desc.c_str() );
- VaultRegisterOwnedAgeAndWait(&link);
+ VaultRegisterOwnedAge(&link);
}
bool pyVault::SetAgePublic( const pyAgeInfoStruct * ageInfo, bool makePublic )
{
+ // Note: This doesn't actually block (~Hoikas)
return VaultSetOwnedAgePublicAndWait(ageInfo->GetAgeInfo(), makePublic);
}
diff --git a/Sources/Plasma/FeatureLib/pfPython/pyVaultNode.cpp b/Sources/Plasma/FeatureLib/pfPython/pyVaultNode.cpp
index 6dfa886c..15ab3ea6 100644
--- a/Sources/Plasma/FeatureLib/pfPython/pyVaultNode.cpp
+++ b/Sources/Plasma/FeatureLib/pfPython/pyVaultNode.cpp
@@ -108,6 +108,7 @@ pyVaultNode::pyVaultNodeOperationCallback::~pyVaultNodeOperationCallback()
void pyVaultNode::pyVaultNodeOperationCallback::VaultOperationStarted( UInt32 context )
{
+ fContext = context;
if ( fCbObject )
{
// Call the callback.
@@ -407,6 +408,14 @@ void pyVaultNode::SetCreateAgeGuid( const char * v )
// Vault Node API
// Add child node
+void _AddNodeCallback(ENetError result, void* param) {
+ pyVaultNode::pyVaultNodeOperationCallback* cb = (pyVaultNode::pyVaultNodeOperationCallback*)param;
+ if (IS_NET_SUCCESS(result))
+ cb->VaultOperationComplete(hsOK);
+ else
+ cb->VaultOperationComplete(hsFail);
+}
+
PyObject* pyVaultNode::AddNode(pyVaultNode* pynode, PyObject* cbObject, UInt32 cbContext)
{
pyVaultNodeOperationCallback * cb = NEWZERO(pyVaultNodeOperationCallback)(cbObject);
@@ -437,21 +446,26 @@ PyObject* pyVaultNode::AddNode(pyVaultNode* pynode, PyObject* cbObject, UInt32 c
}
}
- // Block here until we have the child node =(
- VaultAddChildNodeAndWait(fNode->nodeId, pynode->fNode->nodeId, NetCommGetPlayer()->playerInt);
-
PyObject * nodeRef = cb->fPyNodeRef = pyVaultNodeRef::New(fNode, pynode->fNode);
Py_INCREF(nodeRef); // incref it, because we MUST return a new PyObject, and the callback "steals" the ref from us
cb->SetNode(pynode->fNode);
- cb->VaultOperationComplete(cbContext, hsResult);
-
+
+ VaultAddChildNode(fNode->nodeId,
+ pynode->fNode->nodeId,
+ NetCommGetPlayer()->playerInt,
+ (FVaultAddChildNodeCallback)_AddNodeCallback,
+ cb
+ );
+
+ // Evil undocumented functionality that some fool
+ // decided to use in xKI.py. Really???
return nodeRef;
}
else
{
// manually make the callback
cb->VaultOperationStarted( cbContext );
- cb->VaultOperationComplete( cbContext, hsFail );
+ cb->VaultOperationComplete(hsFail);
}
// just return a None object
@@ -468,14 +482,18 @@ void pyVaultNode::LinkToNode(int nodeID, PyObject* cbObject, UInt32 cbContext)
// Hack the callbacks until vault notification is in place
cb->VaultOperationStarted( cbContext );
- VaultAddChildNodeAndWait(fNode->nodeId, nodeID, NetCommGetPlayer()->playerInt);
if (RelVaultNode * rvn = VaultGetNodeIncRef(nodeID)) {
cb->SetNode(rvn);
cb->fPyNodeRef = pyVaultNodeRef::New(fNode, rvn);
rvn->DecRef();
}
- cb->VaultOperationComplete( cbContext, hsOK );
+ VaultAddChildNode(fNode->nodeId,
+ nodeID,
+ NetCommGetPlayer()->playerInt,
+ (FVaultAddChildNodeCallback)_AddNodeCallback,
+ cb
+ );
}
else
{
diff --git a/Sources/Plasma/FeatureLib/pfPython/pyVaultNode.h b/Sources/Plasma/FeatureLib/pfPython/pyVaultNode.h
index 3ff37972..193317aa 100644
--- a/Sources/Plasma/FeatureLib/pfPython/pyVaultNode.h
+++ b/Sources/Plasma/FeatureLib/pfPython/pyVaultNode.h
@@ -85,12 +85,14 @@ public:
PyObject * fCbObject;
RelVaultNode * fNode;
PyObject * fPyNodeRef;
+ UInt32 fContext;
pyVaultNodeOperationCallback(PyObject * cbObject);
~pyVaultNodeOperationCallback();
void VaultOperationStarted(UInt32 context);
void VaultOperationComplete(UInt32 context, int resultCode);
+ void VaultOperationComplete(int resultCode) { VaultOperationComplete(fContext, resultCode); }
void SetNode (RelVaultNode * rvn);
RelVaultNode * GetNode ();
diff --git a/Sources/Plasma/FeatureLib/pfPython/pyVaultPlayerInfoListNode.cpp b/Sources/Plasma/FeatureLib/pfPython/pyVaultPlayerInfoListNode.cpp
index 914c62a0..7e1cfb1d 100644
--- a/Sources/Plasma/FeatureLib/pfPython/pyVaultPlayerInfoListNode.cpp
+++ b/Sources/Plasma/FeatureLib/pfPython/pyVaultPlayerInfoListNode.cpp
@@ -92,15 +92,22 @@ hsBool pyVaultPlayerInfoListNode::HasPlayer( UInt32 playerID )
return (rvn != nil);
}
-hsBool pyVaultPlayerInfoListNode::AddPlayer( UInt32 playerID )
+//==================================================================
+
+static void IAddPlayer_NodesFound(ENetError result, void* param, unsigned nodeIdCount, const unsigned nodeIds[])
{
- if (HasPlayer(playerID))
- return true;
-
- if (!fNode)
- return false;
-
- NetVaultNode * templateNode = NEWZERO(NetVaultNode);
+ NetVaultNode* parent = static_cast(param);
+ if (nodeIdCount)
+ VaultAddChildNode(parent->GetNodeId(), nodeIds[0], VaultGetPlayerId(), nullptr, nullptr);
+ parent->DecRef();
+}
+
+void pyVaultPlayerInfoListNode::AddPlayer( UInt32 playerID )
+{
+ if (HasPlayer(playerID) || !fNode)
+ return;
+
+ NetVaultNode* templateNode = new NetVaultNode();
templateNode->IncRef();
templateNode->SetNodeType(plVault::kNodeType_PlayerInfo);
VaultPlayerInfoNode access(templateNode);
@@ -108,15 +115,14 @@ hsBool pyVaultPlayerInfoListNode::AddPlayer( UInt32 playerID )
ARRAY(unsigned) nodeIds;
VaultLocalFindNodes(templateNode, &nodeIds);
-
- if (!nodeIds.Count())
- VaultFindNodesAndWait(templateNode, &nodeIds);
-
+
+ // So, if we know about this node, we can take it easy. If not, we lazy load it.
if (nodeIds.Count())
- VaultAddChildNodeAndWait(fNode->nodeId, nodeIds[0], VaultGetPlayerId());
-
- templateNode->DecRef();
- return nodeIds.Count() != 0;
+ VaultAddChildNode(fNode->GetNodeId(), nodeIds[0], VaultGetPlayerId(), nullptr, nullptr);
+ else {
+ fNode->IncRef();
+ VaultFindNodes(templateNode, IAddPlayer_NodesFound, fNode);
+ }
}
void pyVaultPlayerInfoListNode::RemovePlayer( UInt32 playerID )
diff --git a/Sources/Plasma/FeatureLib/pfPython/pyVaultPlayerInfoListNode.h b/Sources/Plasma/FeatureLib/pfPython/pyVaultPlayerInfoListNode.h
index bf3c8bef..8bb46476 100644
--- a/Sources/Plasma/FeatureLib/pfPython/pyVaultPlayerInfoListNode.h
+++ b/Sources/Plasma/FeatureLib/pfPython/pyVaultPlayerInfoListNode.h
@@ -82,8 +82,8 @@ public:
//==================================================================
// class RelVaultNode : public plVaultFolderNode
//
- virtual hsBool HasPlayer( UInt32 playerID );
- hsBool AddPlayer( UInt32 playerID );
+ hsBool HasPlayer( UInt32 playerID );
+ void AddPlayer( UInt32 playerID );
void RemovePlayer( UInt32 playerID );
PyObject * GetPlayer( UInt32 playerID ); // returns pyVaultPlayerInfoNode
diff --git a/Sources/Plasma/FeatureLib/pfPython/pyVaultPlayerInfoListNodeGlue.cpp b/Sources/Plasma/FeatureLib/pfPython/pyVaultPlayerInfoListNodeGlue.cpp
index 27fc381f..ac675fe2 100644
--- a/Sources/Plasma/FeatureLib/pfPython/pyVaultPlayerInfoListNodeGlue.cpp
+++ b/Sources/Plasma/FeatureLib/pfPython/pyVaultPlayerInfoListNodeGlue.cpp
@@ -81,7 +81,8 @@ PYTHON_METHOD_DEFINITION(ptVaultPlayerInfoListNode, playerlistAddPlayer, args)
PyErr_SetString(PyExc_TypeError, "playerlistAddPlayer expects an unsigned long");
PYTHON_RETURN_ERROR;
}
- PYTHON_RETURN_BOOL(self->fThis->AddPlayer(playerID));
+ self->fThis->AddPlayer(playerID);
+ PYTHON_RETURN_NONE;
}
PYTHON_METHOD_DEFINITION(ptVaultPlayerInfoListNode, playerlistRemovePlayer, args)
@@ -126,7 +127,8 @@ PYTHON_METHOD_DEFINITION(ptVaultPlayerInfoListNode, addPlayer, args)
PyErr_SetString(PyExc_TypeError, "addPlayer expects an unsigned long");
PYTHON_RETURN_ERROR;
}
- PYTHON_RETURN_BOOL(self->fThis->AddPlayer(playerID));
+ self->fThis->AddPlayer(playerID);
+ PYTHON_RETURN_NONE;
}
PYTHON_METHOD_DEFINITION(ptVaultPlayerInfoListNode, removePlayer, args)
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..80c8dc2b 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,29 @@ 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 %s recvd trigger request reply:%s, wasRequesting=%d, 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/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();
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/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..48b0667c 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;
+ }
}
}
}
diff --git a/Sources/Plasma/PubUtilLib/plMessage/plVaultNotifyMsg.h b/Sources/Plasma/PubUtilLib/plMessage/plVaultNotifyMsg.h
index 65430305..6dff96d3 100644
--- a/Sources/Plasma/PubUtilLib/plMessage/plVaultNotifyMsg.h
+++ b/Sources/Plasma/PubUtilLib/plMessage/plVaultNotifyMsg.h
@@ -61,7 +61,9 @@ public:
kUnRegisteredOwnedAge = plNetCommon::VaultTasks::kUnRegisterOwnedAge,
kUnRegisteredVisitAge = plNetCommon::VaultTasks::kUnRegisterVisitAge,
kPublicAgeCreated,
- kPublicAgeRemoved
+ kPublicAgeRemoved,
+ kRegisteredSubAgeLink,
+ kRegisteredChildAgeLink,
};
plVaultNotifyMsg();
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/plNetClient/plNetClientMgr.cpp b/Sources/Plasma/PubUtilLib/plNetClient/plNetClientMgr.cpp
index b03b5d31..dc5d4e12 100644
--- a/Sources/Plasma/PubUtilLib/plNetClient/plNetClientMgr.cpp
+++ b/Sources/Plasma/PubUtilLib/plNetClient/plNetClientMgr.cpp
@@ -84,6 +84,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
#include "../plMessage/plNetVoiceListMsg.h"
#include "../plMessage/plNetCommMsgs.h"
#include "../plMessage/plNetClientMgrMsg.h"
+#include "../plMessage/plVaultNotifyMsg.h"
#include "../plResMgr/plKeyFinder.h"
#include "../plResMgr/plPageInfo.h"
#include "../plNetTransport/plNetTransportMember.h"
@@ -352,6 +353,9 @@ int plNetClientMgr::Init()
plgDispatch::Dispatch()->RegisterForExactType(plNetCommActivePlayerMsg::Index(), GetKey());
plgDispatch::Dispatch()->RegisterForExactType(plNetCommLinkToAgeMsg::Index(), GetKey());
+ // We need plVaultNotifyMsgs for the NetLinkingMgr
+ plgDispatch::Dispatch()->RegisterForType(plVaultNotifyMsg::Index(), GetKey());
+
IInitNetClientComm();
return ret;
diff --git a/Sources/Plasma/PubUtilLib/plNetClient/plNetLinkingMgr.cpp b/Sources/Plasma/PubUtilLib/plNetClient/plNetLinkingMgr.cpp
index 9ee48c4b..15c8cea2 100644
--- a/Sources/Plasma/PubUtilLib/plNetClient/plNetLinkingMgr.cpp
+++ b/Sources/Plasma/PubUtilLib/plNetClient/plNetLinkingMgr.cpp
@@ -62,7 +62,6 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
#include "../plAvatar/plArmatureMod.h"
#include "../plFile/hsFiles.h"
#include "../plMessage/plNCAgeJoinerMsg.h"
-#include "../plVault/plVault.h"
/*****************************************************************************
@@ -330,6 +329,13 @@ hsBool plNetLinkingMgr::MsgReceive( plMessage *msg )
return true;
}
+ // If a link was deferred in order to register an owned age, we will
+ // get a VaultNotify about the registration
+ if (plVaultNotifyMsg* vaultMsg = plVaultNotifyMsg::ConvertNoRef(msg)) {
+ IProcessVaultNotifyMsg(vaultMsg);
+ return true;
+ }
+
return false;
}
@@ -363,37 +369,19 @@ bool plNetLinkingMgr::IProcessLinkToAgeMsg( plLinkToAgeMsg * msg )
GetPrevAgeLink()->CopyFrom( GetAgeLink() );
GetAgeLink()->CopyFrom( msg->GetAgeLink() );
- if ( IPreProcessLink() )
+ // Actually do stuff...
+ UInt8 pre = IPreProcessLink();
+ if (pre == kLinkImmediately)
{
- GetAgeLink()->SetSpawnPoint(msg->GetAgeLink()->SpawnPoint());
-
- if (fLinkedIn) {
- // Set the link out animation we should use
- if (plSceneObject *localSO = plSceneObject::ConvertNoRef(nc->GetLocalPlayer())) {
- plArmatureMod *avMod = const_cast(plArmatureMod::ConvertNoRef(localSO->GetModifierByType(plArmatureMod::Index())));
- avMod->SetLinkInAnim(msg->GetLinkInAnimName());
- }
- // Queue leave op
- NlmLeaveAgeOp * leaveAgeOp = NEWZERO(NlmLeaveAgeOp);
- QueueOp(leaveAgeOp);
- }
-
- // Queue join op
- NlmJoinAgeOp * joinAgeOp = NEWZERO(NlmJoinAgeOp);
- joinAgeOp->age.ageInstId = (Uuid) *GetAgeLink()->GetAgeInfo()->GetAgeInstanceGuid();
- StrCopy(
- joinAgeOp->age.ageDatasetName,
- GetAgeLink()->GetAgeInfo()->GetAgeFilename(),
- arrsize(joinAgeOp->age.ageDatasetName)
- );
- StrCopy(
- joinAgeOp->age.spawnPtName,
- GetAgeLink()->SpawnPoint().GetName(),
- arrsize(joinAgeOp->age.spawnPtName)
- );
- QueueOp(joinAgeOp);
+ msg->Ref();
+ IDoLink(msg);
}
- else
+ else if (pre == kLinkDeferred)
+ {
+ msg->Ref();
+ fDeferredLink = msg;
+ }
+ else if (pre == kLinkFailed)
{
hsLogEntry( nc->ErrorMsg( "IPreProcessLink failed. Not linking." ) );
// Restore previous age info state.
@@ -407,6 +395,43 @@ bool plNetLinkingMgr::IProcessLinkToAgeMsg( plLinkToAgeMsg * msg )
////////////////////////////////////////////////////////////////////
+void plNetLinkingMgr::IDoLink(plLinkToAgeMsg* msg)
+{
+ plNetClientMgr* nc = plNetClientMgr::GetInstance();
+ GetAgeLink()->SetSpawnPoint(msg->GetAgeLink()->SpawnPoint());
+
+ if (fLinkedIn) {
+ // Set the link out animation we should use
+ if (plSceneObject *localSO = plSceneObject::ConvertNoRef(nc->GetLocalPlayer())) {
+ plArmatureMod *avMod = const_cast(plArmatureMod::ConvertNoRef(localSO->GetModifierByType(plArmatureMod::Index())));
+ avMod->SetLinkInAnim(msg->GetLinkInAnimName());
+ }
+ // Queue leave op
+ NlmLeaveAgeOp * leaveAgeOp = NEWZERO(NlmLeaveAgeOp);
+ QueueOp(leaveAgeOp);
+ }
+
+ // Queue join op
+ NlmJoinAgeOp * joinAgeOp = NEWZERO(NlmJoinAgeOp);
+ joinAgeOp->age.ageInstId = (Uuid) *GetAgeLink()->GetAgeInfo()->GetAgeInstanceGuid();
+ StrCopy(
+ joinAgeOp->age.ageDatasetName,
+ GetAgeLink()->GetAgeInfo()->GetAgeFilename(),
+ arrsize(joinAgeOp->age.ageDatasetName)
+ );
+ StrCopy(
+ joinAgeOp->age.spawnPtName,
+ GetAgeLink()->SpawnPoint().GetName(),
+ arrsize(joinAgeOp->age.spawnPtName)
+ );
+ QueueOp(joinAgeOp);
+
+ // UnRef
+ msg->UnRef();
+}
+
+////////////////////////////////////////////////////////////////////
+
bool plNetLinkingMgr::IProcessLinkingMgrMsg( plLinkingMgrMsg * msg )
{
plNetClientMgr * nc = plNetClientMgr::GetInstance();
@@ -458,6 +483,49 @@ bool plNetLinkingMgr::IProcessLinkingMgrMsg( plLinkingMgrMsg * msg )
return result;
}
+////////////////////////////////////////////////////////////////////
+
+bool plNetLinkingMgr::IProcessVaultNotifyMsg(plVaultNotifyMsg* msg)
+{
+ // No deferred link? Bye bye.
+ if (fDeferredLink == nil)
+ return false;
+
+ plAgeLinkStruct* cur = GetAgeLink();
+ RelVaultNode* cVaultLink = nil;
+ switch (msg->GetType())
+ {
+ case plVaultNotifyMsg::kRegisteredChildAgeLink:
+ case plVaultNotifyMsg::kRegisteredOwnedAge:
+ case plVaultNotifyMsg::kRegisteredSubAgeLink:
+ cVaultLink = VaultGetNodeIncRef(msg->GetArgs()->GetInt(plNetCommon::VaultTaskArgs::kAgeLinkNode));
+ break;
+ default:
+ return false;
+ }
+
+ if (cVaultLink != nil)
+ {
+ // This is something that Cyan does... >.<
+ // It's very useful though...
+ VaultAgeLinkNode accLink(cVaultLink);
+ accLink.CopyTo(cur);
+ if (RelVaultNode* rvnInfo = cVaultLink->GetChildNodeIncRef(plVault::kNodeType_AgeInfo, 1))
+ {
+ VaultAgeInfoNode accInfo(rvnInfo);
+ accInfo.CopyTo(cur->GetAgeInfo());
+ rvnInfo->DecRef();
+ }
+
+ IDoLink(fDeferredLink);
+ fDeferredLink = nil;
+ return true;
+
+ cVaultLink->DecRef();
+ }
+
+ return false;
+}
////////////////////////////////////////////////////////////////////
@@ -681,23 +749,27 @@ void plNetLinkingMgr::OfferLinkToPlayer( const plAgeInfoStruct * inInfo, UInt32
void plNetLinkingMgr::IPostProcessLink( void )
{
- bool city = (0 == stricmp( GetAgeLink()->GetAgeInfo()->GetAgeFilename(), kCityAgeFilename ));
- bool hood = (0 == stricmp( GetAgeLink()->GetAgeInfo()->GetAgeFilename(), kNeighborhoodAgeFilename ));
- bool psnl = (0 == stricmp( GetAgeLink()->GetAgeInfo()->GetAgeFilename(), kPersonalAgeFilename ));
+ // Grab some useful things...
+ plAgeLinkStruct* link = GetAgeLink();
+ plAgeInfoStruct* info = link->GetAgeInfo();
+
+ bool city = (stricmp(info->GetAgeFilename(), kCityAgeFilename) == 0);
+ bool hood = (stricmp(info->GetAgeFilename(), kNeighborhoodAgeFilename) == 0);
+ bool psnl = (stricmp(info->GetAgeFilename(), kPersonalAgeFilename) == 0);
// Update our online status
if (RelVaultNode * rvnInfo = VaultGetPlayerInfoNodeIncRef()) {
VaultPlayerInfoNode accInfo(rvnInfo);
wchar ageInstName[MAX_PATH];
- Uuid ageInstGuid = *GetAgeLink()->GetAgeInfo()->GetAgeInstanceGuid();
- StrToUnicode(ageInstName, GetAgeLink()->GetAgeInfo()->GetAgeInstanceName(), arrsize(ageInstName));
+ Uuid ageInstGuid = *info->GetAgeInstanceGuid();
+ StrToUnicode(ageInstName, info->GetAgeInstanceName(), arrsize(ageInstName));
accInfo.SetAgeInstName(ageInstName);
accInfo.SetAgeInstUuid(ageInstGuid);
accInfo.SetOnline(true);
rvnInfo->DecRef();
}
- switch (GetAgeLink()->GetLinkingRules()) {
+ switch (link->GetLinkingRules()) {
case plNetCommon::LinkingRules::kOwnedBook: {
// SPECIAL CASE: City: Every player ever created would be in the list; avoid that.
@@ -710,10 +782,12 @@ void plNetLinkingMgr::IPostProcessLink( void )
if (fldr && info)
if (!fldr->IsParentOf(info->nodeId, 1))
- VaultAddChildNodeAndWait(
+ VaultAddChildNode(
fldr->nodeId,
info->nodeId,
- NetCommGetPlayer()->playerInt
+ NetCommGetPlayer()->playerInt,
+ nil,
+ nil
);
if (fldr)
@@ -735,10 +809,12 @@ void plNetLinkingMgr::IPostProcessLink( void )
if (fldr && info)
if (!fldr->IsParentOf(info->nodeId, 1))
- VaultAddChildNodeAndWait(
+ VaultAddChildNode(
fldr->nodeId,
info->nodeId,
- NetCommGetPlayer()->playerInt
+ NetCommGetPlayer()->playerInt,
+ nil,
+ nil
);
if (fldr)
@@ -752,7 +828,7 @@ void plNetLinkingMgr::IPostProcessLink( void )
case plNetCommon::LinkingRules::kSubAgeBook: {
// Register the previous age as a sub age of the current one so that we can link back to that instance
plAgeLinkStruct subAgeLink;
- VaultAgeFindOrCreateSubAgeLinkAndWait(GetPrevAgeLink()->GetAgeInfo(), &subAgeLink, NetCommGetAge()->ageInstId);
+ VaultAgeFindOrCreateSubAgeLink(GetPrevAgeLink()->GetAgeInfo(), &subAgeLink, NetCommGetAge()->ageInstId);
}
break;
}
@@ -760,16 +836,19 @@ void plNetLinkingMgr::IPostProcessLink( void )
////////////////////////////////////////////////////////////////////
-bool plNetLinkingMgr::IPreProcessLink( void )
+UInt8 plNetLinkingMgr::IPreProcessLink( void )
{
- plNetClientMgr * nc = plNetClientMgr::GetInstance();
+ // Grab some stuff we're gonna use extensively
+ plNetClientMgr* nc = plNetClientMgr::GetInstance();
+ plAgeLinkStruct* link = GetAgeLink();
+ plAgeInfoStruct* info = link->GetAgeInfo();
- bool success = true;
+ PreProcessResult success = kLinkImmediately;
if ( nc->GetFlagsBit( plNetClientMgr::kNullSend ) )
{
hsLogEntry( nc->DebugMsg( "NetClientMgr nullsend. Not linking." ) );
- return false;
+ return kLinkFailed;
}
#if 0
@@ -787,7 +866,7 @@ bool plNetLinkingMgr::IPreProcessLink( void )
VaultPlayerInfoNode accInfo(rvnInfo);
wchar ageInstName[MAX_PATH];
Uuid ageInstGuid = *GetAgeLink()->GetAgeInfo()->GetAgeInstanceGuid();
- StrToUnicode(ageInstName, GetAgeLink()->GetAgeInfo()->GetAgeInstanceName(), arrsize(ageInstName));
+ StrToUnicode(ageInstName, info->GetAgeInstanceName(), arrsize(ageInstName));
accInfo.SetAgeInstName(ageInstName);
accInfo.SetAgeInstUuid(ageInstGuid);
accInfo.SetOnline(true);
@@ -797,50 +876,50 @@ bool plNetLinkingMgr::IPreProcessLink( void )
//------------------------------------------------------------------------
// Fixup empty fields
- if ( GetAgeLink()->GetAgeInfo()->HasAgeFilename() )
+ if (info->HasAgeFilename())
{
GetAgeLink()->GetAgeInfo()->SetAgeFilename( plNetLinkingMgr::GetProperAgeName( GetAgeLink()->GetAgeInfo()->GetAgeFilename() ).c_str() );
- if ( !GetAgeLink()->GetAgeInfo()->HasAgeInstanceName() )
+ if (!info->HasAgeInstanceName())
{
- GetAgeLink()->GetAgeInfo()->SetAgeInstanceName( GetAgeLink()->GetAgeInfo()->GetAgeFilename() );
+ info->SetAgeInstanceName(info->GetAgeFilename());
}
}
hsLogEntry( nc->DebugMsg( "plNetLinkingMgr: Pre-Process: Linking with %s rules...",
- plNetCommon::LinkingRules::LinkingRuleStr( GetAgeLink()->GetLinkingRules() ) ) );
+ plNetCommon::LinkingRules::LinkingRuleStr( link->GetLinkingRules() ) ) );
//------------------------------------------------------------------------
// SPECIAL CASE: StartUp: force basic link
- if ( stricmp( GetAgeLink()->GetAgeInfo()->GetAgeFilename(), kStartUpAgeFilename )==0 )
+ if (stricmp(info->GetAgeFilename(), kStartUpAgeFilename) == 0)
{
- GetAgeLink()->SetLinkingRules( plNetCommon::LinkingRules::kBasicLink );
+ link->SetLinkingRules( plNetCommon::LinkingRules::kBasicLink );
}
//------------------------------------------------------------------------
// SPECIAL CASE: Nexus: force original link
- if ( stricmp( GetAgeLink()->GetAgeInfo()->GetAgeFilename(), kNexusAgeFilename )==0 )
+ if (stricmp(info->GetAgeFilename(), kNexusAgeFilename) == 0)
{
- GetAgeLink()->SetLinkingRules( plNetCommon::LinkingRules::kOriginalBook );
+ link->SetLinkingRules(plNetCommon::LinkingRules::kOriginalBook);
}
//------------------------------------------------------------------------
// SPECIAL CASE: ACA: force original link
- if ( stricmp( GetAgeLink()->GetAgeInfo()->GetAgeFilename(), kAvCustomizationFilename )==0 )
+ if (stricmp(info->GetAgeFilename(), kAvCustomizationFilename ) == 0)
{
- GetAgeLink()->SetLinkingRules( plNetCommon::LinkingRules::kOriginalBook );
+ link->SetLinkingRules(plNetCommon::LinkingRules::kOriginalBook);
}
hsLogEntry( nc->DebugMsg( "plNetLinkingMgr: Process: Linking with %s rules...",
- plNetCommon::LinkingRules::LinkingRuleStr( GetAgeLink()->GetLinkingRules() ) ) );
+ plNetCommon::LinkingRules::LinkingRuleStr( link->GetLinkingRules() ) ) );
- switch ( GetAgeLink()->GetLinkingRules() )
+ switch ( link->GetLinkingRules() )
{
//--------------------------------------------------------------------
// BASIC LINK. Link to a unique instance of the age, if no instance specified.
case plNetCommon::LinkingRules::kBasicLink:
- if (!GetAgeLink()->GetAgeInfo()->HasAgeInstanceGuid())
- GetAgeLink()->GetAgeInfo()->SetAgeInstanceGuid(&plUUID(GuidGenerate()));
+ if (!info->HasAgeInstanceGuid())
+ info->SetAgeInstanceGuid(&plUUID(GuidGenerate()));
break;
//--------------------------------------------------------------------
@@ -851,12 +930,12 @@ bool plNetLinkingMgr::IPreProcessLink( void )
// we just want to find out if we own *any* link to the age, not the specific
// link that we're linking through
plAgeInfoStruct ageInfo;
- ageInfo.SetAgeFilename(GetAgeLink()->GetAgeInfo()->GetAgeFilename());
+ ageInfo.SetAgeFilename(info->GetAgeFilename());
plAgeLinkStruct ownedLink;
if (!VaultGetOwnedAgeLink(&ageInfo, &ownedLink)) {
// Fill in fields for new age create.
- if ( !GetAgeLink()->GetAgeInfo()->HasAgeUserDefinedName() )
+ if (!info->HasAgeUserDefinedName())
{
// set user-defined name
std::string title;
@@ -865,25 +944,28 @@ bool plNetLinkingMgr::IPreProcessLink( void )
xtl::format( title, "%s'", nc->GetPlayerName() );
else
xtl::format( title, "%s's", nc->GetPlayerName() );
- GetAgeLink()->GetAgeInfo()->SetAgeUserDefinedName( title.c_str() );
+ info->SetAgeUserDefinedName(title.c_str());
}
- if ( !GetAgeLink()->GetAgeInfo()->HasAgeDescription() )
+ if (!info->HasAgeDescription())
{
// set description
std::string desc;
unsigned nameLen = StrLen(nc->GetPlayerName());
if (nc->GetPlayerName()[nameLen - 1] == 's' || nc->GetPlayerName()[nameLen - 1] == 'S')
- xtl::format( desc, "%s' %s", nc->GetPlayerName(), GetAgeLink()->GetAgeInfo()->GetAgeInstanceName() );
+ xtl::format( desc, "%s' %s", nc->GetPlayerName(), info->GetAgeInstanceName() );
else
- xtl::format( desc, "%s's %s", nc->GetPlayerName(), GetAgeLink()->GetAgeInfo()->GetAgeInstanceName() );
- GetAgeLink()->GetAgeInfo()->SetAgeDescription( desc.c_str() );
+ xtl::format( desc, "%s's %s", nc->GetPlayerName(), info->GetAgeInstanceName() );
+ info->SetAgeDescription( desc.c_str() );
}
- if (!GetAgeLink()->GetAgeInfo()->HasAgeInstanceGuid()) {
- GetAgeLink()->GetAgeInfo()->SetAgeInstanceGuid(&plUUID(GuidGenerate()));
+ if (!info->HasAgeInstanceGuid()) {
+ info->SetAgeInstanceGuid(&plUUID(GuidGenerate()));
}
// register this as an owned age now before we link to it.
- VaultRegisterOwnedAgeAndWait(GetAgeLink());
+ // Note: We MUST break or the OwnedBook code will fail!
+ VaultRegisterOwnedAge(link);
+ success = kLinkDeferred;
+ break;
}
else if (RelVaultNode * linkNode = VaultGetOwnedAgeLinkIncRef(&ageInfo)) {
// We have the age in our AgesIOwnFolder. If its volatile, dump it for the new one.
@@ -891,7 +973,7 @@ bool plNetLinkingMgr::IPreProcessLink( void )
if (linkAcc.volat) {
if (VaultUnregisterOwnedAgeAndWait(&ageInfo)) {
// Fill in fields for new age create.
- if ( !GetAgeLink()->GetAgeInfo()->HasAgeUserDefinedName() )
+ if ( !info->HasAgeUserDefinedName() )
{
// set user-defined name
std::string title;
@@ -900,32 +982,36 @@ bool plNetLinkingMgr::IPreProcessLink( void )
xtl::format( title, "%s'", nc->GetPlayerName() );
else
xtl::format( title, "%s's", nc->GetPlayerName() );
- GetAgeLink()->GetAgeInfo()->SetAgeUserDefinedName( title.c_str() );
+ info->SetAgeUserDefinedName( title.c_str() );
}
- if ( !GetAgeLink()->GetAgeInfo()->HasAgeDescription() )
+ if ( !info->HasAgeDescription() )
{
// set description
std::string desc;
unsigned nameLen = StrLen(nc->GetPlayerName());
if (nc->GetPlayerName()[nameLen - 1] == 's' || nc->GetPlayerName()[nameLen - 1] == 'S')
- xtl::format( desc, "%s' %s", nc->GetPlayerName(), GetAgeLink()->GetAgeInfo()->GetAgeInstanceName() );
+ xtl::format( desc, "%s' %s", nc->GetPlayerName(), info->GetAgeInstanceName() );
else
- xtl::format( desc, "%s's %s", nc->GetPlayerName(), GetAgeLink()->GetAgeInfo()->GetAgeInstanceName() );
- GetAgeLink()->GetAgeInfo()->SetAgeDescription( desc.c_str() );
+ xtl::format( desc, "%s's %s", nc->GetPlayerName(), info->GetAgeInstanceName() );
+ info->SetAgeDescription( desc.c_str() );
}
- if (!GetAgeLink()->GetAgeInfo()->HasAgeInstanceGuid()) {
- GetAgeLink()->GetAgeInfo()->SetAgeInstanceGuid(&plUUID(GuidGenerate()));
+ if (!info->HasAgeInstanceGuid()) {
+ info->SetAgeInstanceGuid(&plUUID(GuidGenerate()));
}
- VaultRegisterOwnedAgeAndWait(GetAgeLink());
+ VaultRegisterOwnedAge(link);
+
+ // Note: We MUST break or the OwnedBook code will fail!
+ success = kLinkDeferred;
+ break;
}
}
else {
- if (stricmp(GetAgeLink()->GetAgeInfo()->GetAgeFilename(), kNeighborhoodAgeFilename) == 0) {
- // if we get here then its because we're linking to a neighborhood that we don't belong to
+ if (stricmp(info->GetAgeFilename(), kNeighborhoodAgeFilename) == 0) {
+ // if we get here then it's because we're linking to a neighborhood that we don't belong to
// and our own neighborhood book is not volatile, so really we want to basic link
- GetAgeLink()->SetLinkingRules(plNetCommon::LinkingRules::kBasicLink);
- success = true;
+ link->SetLinkingRules(plNetCommon::LinkingRules::kBasicLink);
+ success = kLinkImmediately;
break;
}
@@ -933,7 +1019,7 @@ bool plNetLinkingMgr::IPreProcessLink( void )
linkNode->DecRef();
}
}
- GetAgeLink()->SetLinkingRules( plNetCommon::LinkingRules::kOwnedBook );
+ link->SetLinkingRules( plNetCommon::LinkingRules::kOwnedBook );
// falls thru to OWNED BOOK case...
//--------------------------------------------------------------------
@@ -941,14 +1027,14 @@ bool plNetLinkingMgr::IPreProcessLink( void )
case plNetCommon::LinkingRules::kOwnedBook:
{
plAgeLinkStruct ownedLink;
- if (VaultGetOwnedAgeLink(GetAgeLink()->GetAgeInfo(), &ownedLink)) {
- GetAgeLink()->GetAgeInfo()->CopyFrom(ownedLink.GetAgeInfo());
+ if (VaultGetOwnedAgeLink(info, &ownedLink)) {
+ info->CopyFrom(ownedLink.GetAgeInfo());
// Remember spawn point (treasure book support)
- plSpawnPointInfo theSpawnPt = GetAgeLink()->SpawnPoint();
- VaultAddOwnedAgeSpawnPoint(*GetAgeLink()->GetAgeInfo()->GetAgeInstanceGuid(), theSpawnPt);
+ plSpawnPointInfo theSpawnPt = link->SpawnPoint();
+ VaultAddOwnedAgeSpawnPoint(*info->GetAgeInstanceGuid(), theSpawnPt);
}
else {
- success = false;
+ success = kLinkFailed;
}
}
break;
@@ -958,10 +1044,10 @@ bool plNetLinkingMgr::IPreProcessLink( void )
case plNetCommon::LinkingRules::kVisitBook:
{
plAgeLinkStruct visitLink;
- if (VaultGetVisitAgeLink(GetAgeLink()->GetAgeInfo(), &visitLink))
- GetAgeLink()->GetAgeInfo()->CopyFrom(visitLink.GetAgeInfo());
+ if (VaultGetVisitAgeLink(info, &visitLink))
+ info->CopyFrom(visitLink.GetAgeInfo());
else
- success = false;
+ success = kLinkFailed;
}
break;
@@ -971,10 +1057,10 @@ bool plNetLinkingMgr::IPreProcessLink( void )
case plNetCommon::LinkingRules::kSubAgeBook:
{
plAgeLinkStruct subAgeLink;
- if (VaultAgeFindOrCreateSubAgeLinkAndWait(GetAgeLink()->GetAgeInfo(), &subAgeLink, NetCommGetAge()->ageInstId))
- GetAgeLink()->GetAgeInfo()->CopyFrom(subAgeLink.GetAgeInfo());
+ if (VaultAgeFindOrCreateSubAgeLink(info, &subAgeLink, NetCommGetAge()->ageInstId))
+ info->CopyFrom(subAgeLink.GetAgeInfo());
else
- success = false;
+ success = kLinkDeferred;
}
break;
@@ -985,28 +1071,38 @@ bool plNetLinkingMgr::IPreProcessLink( void )
{
plAgeLinkStruct childLink;
wchar parentAgeName[MAX_PATH];
- if (GetAgeLink()->HasParentAgeFilename()) {
- StrToUnicode(parentAgeName, GetAgeLink()->GetParentAgeFilename(), arrsize(parentAgeName));
- success = VaultAgeFindOrCreateChildAgeLinkAndWait(parentAgeName, GetAgeLink()->GetAgeInfo(), &childLink);
- }
- else {
- success = VaultAgeFindOrCreateChildAgeLinkAndWait(nil, GetAgeLink()->GetAgeInfo(), &childLink);
+ if (link->HasParentAgeFilename())
+ StrToUnicode(parentAgeName, link->GetParentAgeFilename(), arrsize(parentAgeName));
+
+ switch(VaultAgeFindOrCreateChildAgeLink(
+ (link->HasParentAgeFilename() ? parentAgeName : nil),
+ info,
+ &childLink))
+ {
+ case hsFail:
+ success = kLinkFailed;
+ break;
+ case FALSE:
+ success = kLinkDeferred;
+ break;
+ case TRUE:
+ success = kLinkImmediately;
}
- if (success)
- GetAgeLink()->GetAgeInfo()->CopyFrom(childLink.GetAgeInfo());
+ if (success == kLinkImmediately)
+ info->CopyFrom(childLink.GetAgeInfo());
}
break;
//--------------------------------------------------------------------
// ???
- DEFAULT_FATAL(GetAgeLink()->GetLinkingRules());
+ DEFAULT_FATAL(link->GetLinkingRules());
}
hsLogEntry( nc->DebugMsg( "plNetLinkingMgr: Post-Process: Linking with %s rules...",
- plNetCommon::LinkingRules::LinkingRuleStr( GetAgeLink()->GetLinkingRules() ) ) );
+ plNetCommon::LinkingRules::LinkingRuleStr( link->GetLinkingRules() ) ) );
- hsAssert( GetAgeLink()->GetAgeInfo()->HasAgeFilename(), "AgeLink has no AgeFilename. Link will fail." );
+ hsAssert( info->HasAgeFilename(), "AgeLink has no AgeFilename. Link will fail." );
return success;
}
diff --git a/Sources/Plasma/PubUtilLib/plNetClient/plNetLinkingMgr.h b/Sources/Plasma/PubUtilLib/plNetClient/plNetLinkingMgr.h
index 1f905c09..1ec7bd50 100644
--- a/Sources/Plasma/PubUtilLib/plNetClient/plNetLinkingMgr.h
+++ b/Sources/Plasma/PubUtilLib/plNetClient/plNetLinkingMgr.h
@@ -50,6 +50,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
#include "../plMessage/plLinkToAgeMsg.h"
class plMessage;
+class plVaultNotifyMsg;
struct plNCAgeJoiner;
struct plNCAgeLeaver;
@@ -91,10 +92,23 @@ class plNetLinkingMgr
kLinkPlayerToPrevAge
};
- bool IPreProcessLink( void );
+ plLinkToAgeMsg* fDeferredLink;
+
+ enum PreProcessResult {
+ // Old style IPreProcessLink style "false" result
+ kLinkFailed,
+ // Old style IPreProcessLink style "true" result
+ kLinkImmediately,
+ // Defer the link until later, don't trash the structs
+ kLinkDeferred,
+ };
+
+ UInt8 IPreProcessLink( void );
void IPostProcessLink( void );
bool IProcessLinkingMgrMsg( plLinkingMgrMsg * msg );
bool IProcessLinkToAgeMsg( plLinkToAgeMsg * msg );
+ void IDoLink(plLinkToAgeMsg* link);
+ bool IProcessVaultNotifyMsg(plVaultNotifyMsg* msg);
bool IDispatchMsg( plMessage * msg, UInt32 playerID );
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..03996b27 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,65 @@ 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 = std::string(subSO->GetKeyName()) + "_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 +652,11 @@ hsBool plPXPhysical::HandleRefMsg(plGenRefMsg* refMsg)
break;
}
}
- else
- {
+ break;
+
+ default:
hsAssert(0, "Unknown ref type, who sent us this?");
+ break;
}
return true;
@@ -878,7 +887,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 +1034,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 +1057,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 +1125,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 +1251,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 +1269,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 +1286,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..5a710783 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;
@@ -615,15 +626,15 @@ void plSimulationMgr::Advance(float delSecs)
{
if (fExtraProfile)
Log("Step clamped from %f to limit of %f", fAccumulator, fMaxDelta);
- fAccumulator = fMaxDelta;
+ 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 / fStepSize + 0.000001f);
+ float delta = numSubSteps * fStepSize;
+ fAccumulator -= delta;
plProfile_IncCount(StepLen, (int)(delta*1000));
plProfile_BeginTiming(Step);
@@ -772,25 +783,21 @@ 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
+ 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 7f85cd1c..5720669a 100644
--- a/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.h
+++ b/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.h
@@ -122,7 +122,7 @@ protected:
// 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.
@@ -159,6 +159,7 @@ protected:
float fMaxDelta;
float fStepSize;
+
float fAccumulator;
UInt32 fStepCount;
diff --git a/Sources/Plasma/PubUtilLib/plVault/plVaultClientApi.cpp b/Sources/Plasma/PubUtilLib/plVault/plVaultClientApi.cpp
index a8e4a5dc..b1943163 100644
--- a/Sources/Plasma/PubUtilLib/plVault/plVaultClientApi.cpp
+++ b/Sources/Plasma/PubUtilLib/plVault/plVaultClientApi.cpp
@@ -2550,6 +2550,113 @@ bool VaultGetVisitAgeLink (const plAgeInfoStruct * info, class plAgeLinkStruct *
return true;
}
+//============================================================================
+namespace _VaultRegisterVisitAge {
+ struct _Params {
+
+ plSpawnPointInfo* fSpawn;
+ void* fAgeInfoId;
+
+ ~_Params() {
+ DEL(fSpawn);
+ }
+ };
+
+ void _CreateAgeLinkNode(ENetError result, void* state, void* param, RelVaultNode* node) {
+ if (IS_NET_ERROR(result)) {
+ LogMsg(kLogError, "RegisterVisitAge: Failed to create AgeLink (async)");
+ DEL(param);
+ return;
+ }
+
+ _Params* p = (_Params*)param;
+ RelVaultNode* ageInfo = VaultGetNodeIncRef((UInt32)p->fAgeInfoId);
+
+ // Add ourselves to the Can Visit folder of the age
+ if (RelVaultNode * playerInfo = VaultGetPlayerInfoNodeIncRef()) {
+ if (RelVaultNode* canVisit = ageInfo->GetChildPlayerInfoListNodeIncRef(plVault::kCanVisitFolder, 1)) {
+ VaultAddChildNode(canVisit->nodeId, playerInfo->nodeId, 0, nil, nil);
+ canVisit->DecRef();
+ }
+
+ playerInfo->DecRef();
+ }
+
+ // Get our AgesICanVisit folder
+ if (RelVaultNode* iCanVisit = VaultGetAgesICanVisitFolderIncRef()) {
+ VaultAddChildNode(node->nodeId, ageInfo->nodeId, 0, nil, nil);
+ VaultAddChildNode(iCanVisit->nodeId, node->nodeId, 0, nil, nil);
+ }
+
+ // Update the AgeLink with a spawn point
+ VaultAgeLinkNode access(node);
+ access.AddSpawnPoint(*p->fSpawn);
+
+ // Send out the VaultNotify msg
+ plVaultNotifyMsg * msg = NEWZERO(plVaultNotifyMsg);
+ msg->SetType(plVaultNotifyMsg::kRegisteredVisitAge);
+ msg->SetResultCode(true);
+ msg->GetArgs()->AddInt(plNetCommon::VaultTaskArgs::kAgeLinkNode, node->nodeId);
+ msg->Send();
+
+ //Don't leak memory
+ DEL(param);
+ }
+
+ void _DownloadCallback(ENetError result, void* param) {
+ if (IS_NET_ERROR(result)) {
+ LogMsg(kLogError, "RegisterVisitAge: Failed to download age vault (async)");
+ DEL(param);
+ return;
+ }
+
+ // Create the AgeLink node
+ VaultCreateNode(plVault::kNodeType_AgeLink, (FVaultCreateNodeCallback)_CreateAgeLinkNode, nil, param);
+ }
+
+ void _InitAgeCallback(ENetError result, void* state, void* param, UInt32 ageVaultId, UInt32 ageInfoId) {
+ if (IS_NET_ERROR(result)) {
+ LogMsg(kLogError, "RegisterVisitAge: Failed to init age vault (async)");
+ DEL(param);
+ return;
+ }
+
+ // Save the AgeInfo nodeID, then download the age vault
+ _Params* p = (_Params*)param;
+ p->fAgeInfoId = (void*)ageInfoId;
+
+ VaultDownload(L"RegisterVisitAge",
+ ageInfoId,
+ (FVaultDownloadCallback)_DownloadCallback,
+ param,
+ nil,
+ nil
+ );
+ }
+};
+
+void VaultRegisterVisitAge(const plAgeLinkStruct* link) {
+ using namespace _VaultRegisterVisitAge;
+
+ // Test to see if we already have this visit age...
+ plAgeLinkStruct existing;
+ if (VaultGetVisitAgeLink(link->GetAgeInfo(), &existing))
+ return;
+
+ // Still here? We need to actually do some work, then.
+ _Params* p = TRACKED_NEW _Params;
+ p->fSpawn = TRACKED_NEW plSpawnPointInfo(link->SpawnPoint());
+
+ // This doesn't actually *create* a new age but rather fetches the
+ // already existing age vault. Weird? Yes...
+ VaultInitAge(link->GetAgeInfo(),
+ kNilGuid,
+ (FVaultInitAgeCallback)_InitAgeCallback,
+ nil,
+ p
+ );
+}
+
//============================================================================
namespace _VaultRegisterOwnedAgeAndWait {
@@ -2807,6 +2914,123 @@ bool VaultRegisterOwnedAgeAndWait (const plAgeLinkStruct * link) {
return result;
}
+//============================================================================
+namespace _VaultRegisterOwnedAge {
+ struct _Params {
+ plSpawnPointInfo* fSpawn;
+ void* fAgeInfoId;
+
+ ~_Params() {
+ DEL(fSpawn);
+ }
+ };
+
+ void _AddAgeInfoNode(ENetError result, void* param) {
+ if (IS_NET_ERROR(result))
+ LogMsg(kLogError, "VaultRegisterOwnedAge: Failed to add info to link (async)");
+ }
+
+ void _AddAgeLinkNode(ENetError result, void* param) {
+ if (IS_NET_ERROR(result))
+ LogMsg(kLogError, "VaultRegisterOwnedAge: Failed to add age to bookshelf (async)");
+ }
+
+ void _AddPlayerInfoNode(ENetError result, void* param) {
+ if (IS_NET_ERROR(result))
+ LogMsg(kLogError, "VaultRegisterOwnedAge: Failed to add playerInfo to ageOwners (async)");
+ }
+
+ void _CreateAgeLinkNode(ENetError result, void* state, void* param, RelVaultNode* node) {
+ if (IS_NET_ERROR(result)) {
+ LogMsg(kLogError, "VaultRegisterOwnedAge: Failed to create AgeLink (async)");
+ DEL(param);
+ return;
+ }
+
+ // Grab our params
+ _Params* p = (_Params*)param;
+
+ // Set swpoint
+ VaultAgeLinkNode aln(node);
+ aln.AddSpawnPoint(*(p->fSpawn));
+
+ // Make some refs
+ RelVaultNode* agesIOwn = VaultGetAgesIOwnFolderIncRef();
+ RelVaultNode* plyrInfo = VaultGetPlayerInfoNodeIncRef();
+ VaultAddChildNode(agesIOwn->nodeId, node->nodeId, 0, (FVaultAddChildNodeCallback)_AddAgeLinkNode, nil);
+ VaultAddChildNode(node->nodeId, (UInt32)p->fAgeInfoId, 0, (FVaultAddChildNodeCallback)_AddAgeInfoNode, nil);
+
+ // Add our PlayerInfo to important places
+ if (RelVaultNode* rvnAgeInfo = VaultGetNodeIncRef((UInt32)p->fAgeInfoId)) {
+ if (RelVaultNode* rvnAgeOwners = rvnAgeInfo->GetChildPlayerInfoListNodeIncRef(plVault::kAgeOwnersFolder, 1)) {
+ VaultAddChildNode(rvnAgeOwners->nodeId, plyrInfo->nodeId, 0, (FVaultAddChildNodeCallback)_AddPlayerInfoNode, nil);
+ rvnAgeOwners->DecRef();
+ }
+
+ rvnAgeInfo->DecRef();
+ }
+
+ // Fire off vault callbacks
+ plVaultNotifyMsg* msg = NEWZERO(plVaultNotifyMsg);
+ msg->SetType(plVaultNotifyMsg::kRegisteredOwnedAge);
+ msg->SetResultCode(result);
+ msg->GetArgs()->AddInt(plNetCommon::VaultTaskArgs::kAgeLinkNode, node->nodeId);
+ msg->Send();
+
+ // Don't leak memory
+ agesIOwn->DecRef();
+ plyrInfo->DecRef();
+ DEL(p);
+ }
+
+ void _DownloadCallback(ENetError result, void* param) {
+ if (IS_NET_ERROR(result)) {
+ LogMsg(kLogError, "VaultRegisterOwnedAge: Failed to download age vault (async)");
+ DEL(param);
+ } else
+ VaultCreateNode(plVault::kNodeType_AgeLink, (FVaultCreateNodeCallback)_CreateAgeLinkNode, nil, param);
+ }
+
+ void _InitAgeCallback(ENetError result, void* state, void* param, UInt32 ageVaultId, UInt32 ageInfoVaultId) {
+ if (IS_NET_SUCCESS(result)) {
+ _Params* p = TRACKED_NEW _Params();
+ p->fAgeInfoId = (void*)ageInfoVaultId;
+ p->fSpawn = (plSpawnPointInfo*)param;
+
+ VaultDownload(
+ L"RegisterOwnedAge",
+ ageInfoVaultId,
+ (FVaultDownloadCallback)_DownloadCallback,
+ p,
+ nil,
+ nil);
+ } else
+ LogMsg(kLogError, "VaultRegisterOwnedAge: Failed to init age (async)");
+ }
+}; // namespace _VaultRegisterOwnedAge
+
+void VaultRegisterOwnedAge(const plAgeLinkStruct* link) {
+ using namespace _VaultRegisterOwnedAge;
+
+ RelVaultNode* agesIOwn = VaultGetAgesIOwnFolderIncRef();
+ if (agesIOwn == nil) {
+ LogMsg(kLogError, "VaultRegisterOwnedAge: Couldn't find the stupid AgesIOwnfolder!");
+ return;
+ }
+
+ // Make sure we don't already have the age
+ plAgeLinkStruct existing;
+ if (VaultGetOwnedAgeLink(link->GetAgeInfo(), &existing))
+ return;
+
+ // Let's go async, my friend :)
+ VaultInitAge(link->GetAgeInfo(),
+ kNilGuid,
+ (FVaultInitAgeCallback)_InitAgeCallback,
+ nil,
+ TRACKED_NEW plSpawnPointInfo(link->SpawnPoint()));
+}
+
//============================================================================
namespace _VaultRegisterVisitAgeAndWait {
@@ -3220,6 +3444,38 @@ bool VaultHasChronicleEntry (const wchar entryName[], int entryType) {
return false;
}
+//============================================================================
+void VaultAddChronicleEntry (const wchar entryName[], int entryType, const wchar entryValue[]) {
+ // Sometimes we try to create chrons in StartUp.
+ // This is bad...
+ if (GetPlayerNode() == nil)
+ return;
+
+ if (RelVaultNode* rvnChrn = VaultFindChronicleEntryIncRef(entryName, entryType)) {
+ VaultChronicleNode chrnNode(rvnChrn);
+ chrnNode.SetEntryValue(entryValue);
+ rvnChrn->DecRef();
+ } else {
+ NetVaultNode* templateNode = NEWZERO(NetVaultNode);
+ templateNode->IncRef();
+ templateNode->SetNodeType(plVault::kNodeType_Chronicle);
+ VaultChronicleNode chrnNode(templateNode);
+ chrnNode.SetEntryName(entryName);
+ chrnNode.SetEntryType(entryType);
+ chrnNode.SetEntryValue(entryValue);
+ VaultCreateNode(templateNode, (FVaultCreateNodeCallback)(_VaultAddChronicleEntryCB), nil, nil);
+ templateNode->DecRef();
+ }
+}
+
+void _VaultAddChronicleEntryCB(ENetError result, void* state, void * param, RelVaultNode* node) {
+ if (result == ENetError::kNetSuccess) {
+ RelVaultNode* rvnFldr = GetChildFolderNode(GetPlayerNode(), plVault::kChronicleFolder, 1);
+ if (rvnFldr != nil)
+ VaultAddChildNode(rvnFldr->nodeId, node->nodeId, 0, nil, nil);
+ }
+}
+
//============================================================================
void VaultAddChronicleEntryAndWait (
const wchar entryName[],
@@ -3457,7 +3713,7 @@ void VaultProcessVisitNote(RelVaultNode * rvnVisit) {
plAgeLinkStruct link;
if (visitAcc.GetVisitInfo(link.GetAgeInfo())) {
// Add it to our "ages i can visit" folder
- VaultRegisterVisitAgeAndWait(&link);
+ VaultRegisterVisitAge(&link);
}
// remove it from the inbox
VaultRemoveChildNode(rvnInbox->nodeId, rvnVisit->nodeId, nil, nil);
@@ -3504,7 +3760,7 @@ void VaultProcessPlayerInbox () {
plAgeLinkStruct link;
if (visitAcc.GetVisitInfo(link.GetAgeInfo())) {
// Add it to our "ages i can visit" folder
- VaultRegisterVisitAgeAndWait(&link);
+ VaultRegisterVisitAge(&link);
}
// remove it from the inbox
VaultRemoveChildNode(rvnInbox->nodeId, rvnVisit->nodeId, nil, nil);
@@ -4196,6 +4452,89 @@ bool VaultAgeFindOrCreateSubAgeLinkAndWait (
}
+//============================================================================
+namespace _VaultCreateSubAge {
+ void _CreateNodeCallback(ENetError result, void* state, void* param, RelVaultNode* node) {
+ if (IS_NET_ERROR(result)) {
+ LogMsg(kLogError, "CreateSubAge: Failed to create AgeLink (async)");
+ return;
+ }
+
+ // Add the children to the right places
+ VaultAddChildNode(node->nodeId, (UInt32)param, 0, nil, nil);
+ if (RelVaultNode* saFldr = VaultGetAgeSubAgesFolderIncRef()) {
+ VaultAddChildNode(saFldr->nodeId, node->nodeId, 0, nil, nil);
+ saFldr->DecRef();
+ } else
+ LogMsg(kLogError, "CreateSubAge: Couldn't find SubAges folder (async)");
+
+ // Send the VaultNotify that the plNetLinkingMgr wants...
+ plVaultNotifyMsg * msg = NEWZERO(plVaultNotifyMsg);
+ msg->SetType(plVaultNotifyMsg::kRegisteredSubAgeLink);
+ msg->SetResultCode(result);
+ msg->GetArgs()->AddInt(plNetCommon::VaultTaskArgs::kAgeLinkNode, node->nodeId);
+ msg->Send();
+ }
+
+ void _DownloadCallback(ENetError result, void* param) {
+ if (IS_NET_ERROR(result)) {
+ LogMsg(kLogError, "CreateSubAge: Failed to download age vault (async)");
+ return;
+ }
+
+ // Create the AgeLink node
+ VaultCreateNode(plVault::kNodeType_AgeLink,
+ (FVaultCreateNodeCallback)_CreateNodeCallback,
+ nil,
+ param
+ );
+ }
+
+ void _InitAgeCallback(ENetError result, void* state, void* param, UInt32 ageVaultId, UInt32 ageInfoId) {
+ if (IS_NET_ERROR(result)) {
+ LogMsg(kLogError, "CreateSubAge: Failed to init age (async)");
+ return;
+ }
+
+ // Download age vault
+ VaultDownload(L"CreateSubAge",
+ ageInfoId,
+ (FVaultDownloadCallback)_DownloadCallback,
+ (void*)ageInfoId,
+ nil,
+ nil
+ );
+ }
+}; // namespace _VaultCreateSubAge
+
+bool VaultAgeFindOrCreateSubAgeLink(const plAgeInfoStruct* info, plAgeLinkStruct* link, const Uuid& parentUuid) {
+ using namespace _VaultCreateSubAge;
+
+ // First, try to find an already existing subage
+ if (RelVaultNode* rvnLink = VaultGetSubAgeLinkIncRef(info)) {
+ VaultAgeLinkNode accLink(rvnLink);
+ accLink.CopyTo(link);
+
+ if (RelVaultNode* rvnInfo = rvnLink->GetChildNodeIncRef(plVault::kNodeType_AgeInfo, 1)) {
+ VaultAgeInfoNode accInfo(rvnInfo);
+ accInfo.CopyTo(link->GetAgeInfo());
+ rvnInfo->DecRef();
+ }
+
+ rvnLink->DecRef();
+ return true;
+ }
+
+ VaultInitAge(info,
+ parentUuid,
+ (FVaultInitAgeCallback)_InitAgeCallback,
+ nil,
+ nil
+ );
+
+ return false;
+}
+
//============================================================================
namespace _VaultCreateChildAgeAndWait {
@@ -4472,6 +4811,144 @@ bool VaultAgeFindOrCreateChildAgeLinkAndWait (
return true;
}
+//============================================================================
+namespace _VaultCreateChildAge {
+ struct _Params {
+ void* fChildAgesFldr;
+ void* fAgeInfoId;
+ };
+
+ void _CreateNodeCallback(ENetError result, void* state, void* param, RelVaultNode* node) {
+ if (IS_NET_ERROR(result)) {
+ LogMsg(kLogError, "CreateChildAge: Failed to create AgeLink (async)");
+ DEL(param);
+ return;
+ }
+
+ _Params* p = (_Params*)param;
+
+ // Add the children to the right places
+ VaultAddChildNode(node->nodeId, (UInt32)p->fAgeInfoId, 0, nil, nil);
+ VaultAddChildNode((UInt32)p->fChildAgesFldr, node->nodeId, 0, nil, nil);
+
+ // Send the VaultNotify that the plNetLinkingMgr wants...
+ plVaultNotifyMsg * msg = NEWZERO(plVaultNotifyMsg);
+ msg->SetType(plVaultNotifyMsg::kRegisteredChildAgeLink);
+ msg->SetResultCode(result);
+ msg->GetArgs()->AddInt(plNetCommon::VaultTaskArgs::kAgeLinkNode, node->nodeId);
+ msg->Send();
+
+ DEL(param);
+ }
+
+ void _DownloadCallback(ENetError result, void* param) {
+ if (IS_NET_ERROR(result)) {
+ LogMsg(kLogError, "CreateChildAge: Failed to download age vault (async)");
+ DEL(param);
+ return;
+ }
+
+ // Create the AgeLink node
+ VaultCreateNode(plVault::kNodeType_AgeLink,
+ (FVaultCreateNodeCallback)_CreateNodeCallback,
+ nil,
+ param
+ );
+ }
+
+ void _InitAgeCallback(ENetError result, void* state, void* param, UInt32 ageVaultId, UInt32 ageInfoId) {
+ if (IS_NET_ERROR(result)) {
+ LogMsg(kLogError, "CreateChildAge: Failed to init age (async)");
+ DEL(param);
+ return;
+ }
+
+ _Params* p = (_Params*)param;
+ p->fAgeInfoId = (void*)ageInfoId;
+
+ // Download age vault
+ VaultDownload(L"CreateChildAge",
+ ageInfoId,
+ (FVaultDownloadCallback)_DownloadCallback,
+ param,
+ nil,
+ nil
+ );
+ }
+}; // namespace _VaultCreateAge
+
+UInt8 VaultAgeFindOrCreateChildAgeLink(
+ const wchar parentAgeName[],
+ const plAgeInfoStruct* info,
+ plAgeLinkStruct* link)
+{
+ using namespace _VaultCreateChildAge;
+
+ // First, try to find an already existing ChildAge
+ char name[MAX_PATH];
+ StrToAnsi(name, parentAgeName, arrsize(parentAgeName));
+ plAgeInfoStruct search;
+ search.SetAgeFilename(name);
+
+ RelVaultNode* rvnParentInfo = nil;
+ if (RelVaultNode* rvnParentLink = VaultGetOwnedAgeLinkIncRef(&search)) {
+ rvnParentInfo = rvnParentLink->GetChildNodeIncRef(plVault::kNodeType_AgeInfo, 1);
+ rvnParentLink->DecRef();
+ } else // Fallback to current age
+ rvnParentInfo = VaultGetAgeInfoNodeIncRef();
+
+ // Test to make sure nothing went horribly wrong...
+ if (rvnParentInfo == nil) {
+ LogMsg(kLogError, "CreateChildAge: Couldn't find the parent ageinfo (async)");
+ return hsFail;
+ }
+
+ // Still here? Try to find the Child Ages folder
+ UInt8 retval = hsFail;
+ if (RelVaultNode* rvnChildAges = rvnParentInfo->GetChildAgeInfoListNodeIncRef(plVault::kChildAgesFolder, 1)) {
+ const char* ageName = info->GetAgeFilename();
+ wchar hack[MAX_PATH];
+ StrToUnicode(hack, ageName, arrsize(ageName));
+
+ // Search for our age
+ NetVaultNode* temp = NEWZERO(NetVaultNode);
+ temp->SetNodeType(plVault::kNodeType_AgeInfo);
+ VaultAgeInfoNode theAge(temp);
+ theAge.SetAgeFilename(hack);
+
+ if (RelVaultNode* rvnAgeInfo = rvnChildAges->GetChildNodeIncRef(temp, 2)) {
+ RelVaultNode* rvnAgeLink = rvnAgeInfo->GetParentAgeLinkIncRef();
+
+ VaultAgeLinkNode accAgeLink(rvnAgeLink);
+ accAgeLink.CopyTo(link);
+ VaultAgeInfoNode accAgeInfo(rvnAgeInfo);
+ accAgeInfo.CopyTo(link->GetAgeInfo());
+
+ rvnAgeLink->DecRef();
+ rvnAgeInfo->DecRef();
+
+ retval = TRUE;
+ } else {
+ _Params* p = TRACKED_NEW _Params;
+ p->fChildAgesFldr = (void*)rvnChildAges->nodeId;
+
+ VaultAgeInfoNode accParentInfo(rvnParentInfo);
+ VaultInitAge(info,
+ accParentInfo.ageInstUuid,
+ (FVaultInitAgeCallback)_InitAgeCallback,
+ nil,
+ p
+ );
+ }
+
+ temp->DecRef();
+ rvnChildAges->DecRef();
+ retval = FALSE;
+ }
+
+ rvnParentInfo->DecRef();
+ return retval;
+}
/*****************************************************************************
*
diff --git a/Sources/Plasma/PubUtilLib/plVault/plVaultClientApi.h b/Sources/Plasma/PubUtilLib/plVault/plVaultClientApi.h
index 4efe1a68..0505b808 100644
--- a/Sources/Plasma/PubUtilLib/plVault/plVaultClientApi.h
+++ b/Sources/Plasma/PubUtilLib/plVault/plVaultClientApi.h
@@ -349,12 +349,16 @@ bool VaultSetAgePublicAndWait (NetVaultNode * ageInfoNode, bool publicOrNot);
RelVaultNode * VaultGetVisitAgeLinkIncRef (const plAgeInfoStruct * info);
bool VaultGetVisitAgeLink (const plAgeInfoStruct * info, class plAgeLinkStruct * link);
bool VaultRegisterOwnedAgeAndWait (const plAgeLinkStruct * link);
+void VaultRegisterOwnedAge(const plAgeLinkStruct* link);
bool VaultRegisterVisitAgeAndWait (const plAgeLinkStruct * link);
+void VaultRegisterVisitAge (const plAgeLinkStruct* link);
bool VaultUnregisterOwnedAgeAndWait (const plAgeInfoStruct * info);
bool VaultUnregisterVisitAgeAndWait (const plAgeInfoStruct * info);
RelVaultNode * VaultFindChronicleEntryIncRef (const wchar entryName[], int entryType = -1);
bool VaultHasChronicleEntry (const wchar entryName[], int entryType = -1);
// if entry of same name and type already exists, value is updated
+void VaultAddChronicleEntry (const wchar entryName[], int entryType, const wchar entryValue[]);
+void _VaultAddChronicleEntryCB(ENetError result, void* state, void * param, RelVaultNode* node);
void VaultAddChronicleEntryAndWait (
const wchar entryName[],
int entryType,
@@ -421,6 +425,7 @@ void VaultAgeUpdateAgeSDL (const class plStateDataRecord * rec);
unsigned VaultAgeGetAgeTime ();
+RelVaultNode * VaultGetSubAgeLinkIncRef (const plAgeInfoStruct * info);
bool VaultAgeGetSubAgeLink (
const plAgeInfoStruct * info,
plAgeLinkStruct * link
@@ -430,12 +435,13 @@ bool VaultAgeFindOrCreateSubAgeLinkAndWait (
plAgeLinkStruct * link,
const Uuid & parentAgeInstId
);
+bool VaultAgeFindOrCreateSubAgeLink(const plAgeInfoStruct* info, plAgeLinkStruct* link, const Uuid& parentUuid);
bool VaultAgeFindOrCreateChildAgeLinkAndWait (
const wchar parentAgeName[], // nil --> current age, non-nil --> owned age by given name
const plAgeInfoStruct * info,
plAgeLinkStruct * link
);
-
+UInt8 VaultAgeFindOrCreateChildAgeLink(const wchar parentAgeName[], const plAgeInfoStruct* info, plAgeLinkStruct* link);
/*****************************************************************************