mirror of
https://foundry.openuru.org/gitblit/r/CWE-ou-minkata.git
synced 2025-07-14 02:27:40 -04:00
Merge branch 'master' into ticket/10
This commit is contained in:
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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*>( 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*>( 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;
|
||||
}
|
||||
|
||||
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 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*>( 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*>( 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());
|
||||
}
|
||||
|
||||
// We must have a valid fpKey before we do this, hence why this is not in the constructor
|
||||
NoServerArbitration(true);
|
||||
}
|
||||
|
@ -43,8 +43,10 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
#ifndef plObjectInBoxConditionalObject_inc
|
||||
#define plObjectInBoxConditionalObject_inc
|
||||
|
||||
#include <stdint.h>
|
||||
#include "../../NucleusLib/pnModifier/plConditionalObject.h"
|
||||
#include "hsTemplates.h"
|
||||
#include <set>
|
||||
|
||||
class plKey;
|
||||
|
||||
@ -77,17 +79,26 @@ class plVolumeSensorConditionalObject : public plConditionalObject
|
||||
|
||||
protected:
|
||||
|
||||
hsTArray<plKey> fInside;
|
||||
std::set<plKey> fInside;
|
||||
int fTrigNum;
|
||||
int fType;
|
||||
hsBool fFirst;
|
||||
hsBool fTriggered;
|
||||
hsBool fIgnoreExtraEnters;
|
||||
|
||||
plKey fHittee;
|
||||
uint32_t fFlags;
|
||||
|
||||
enum
|
||||
{
|
||||
/** */
|
||||
kIgnoreExtraEnters = (1<<0),
|
||||
kNoServerArbitration = (1<<1),
|
||||
};
|
||||
|
||||
bool IIsLocal(const plKey& key) const;
|
||||
|
||||
public:
|
||||
|
||||
static bool makeBriceHappyVar;
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
kTypeEnter = 1,
|
||||
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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*>(plLogicModifier::ConvertNoRef(obj->GetModifier(i)));
|
||||
if (logic)
|
||||
logic->VolumeNoArbitration(noArbitration);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -200,6 +200,9 @@ public:
|
||||
|
||||
// hack for garrison
|
||||
void VolumeSensorIgnoreExtraEnters(bool ignore);
|
||||
|
||||
/** More SubWorld hacks */
|
||||
void VolumeSensorNoArbitration(bool noArbitration);
|
||||
};
|
||||
|
||||
#endif // _pySceneObject_h_
|
||||
|
@ -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)
|
||||
|
@ -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..
|
||||
//---------------------------------------------------------
|
||||
|
@ -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; }
|
||||
|
||||
plServerReplyMsg() : fType(kUnInit) { }
|
||||
plServerReplyMsg(const plKey &s, const plKey &r, const double* t) : plMessage(s,r,t), fType(kUnInit) { }
|
||||
void SetWasDelayed(bool v) { fWasDelayed = v; }
|
||||
bool GetWasDelayed() const { return fWasDelayed; }
|
||||
|
||||
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 );
|
||||
|
@ -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<float>(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))
|
||||
|
@ -43,6 +43,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
#ifndef plLogicModBase_inc
|
||||
#define plLogicModBase_inc
|
||||
|
||||
#include <stdint.h>
|
||||
#include "plSingleModifier.h"
|
||||
#include "../pnNetCommon/plSynchedValue.h"
|
||||
#include "hsTemplates.h"
|
||||
@ -66,6 +67,8 @@ public:
|
||||
};
|
||||
|
||||
protected:
|
||||
static uint32_t sArbitrationDelayMs;
|
||||
|
||||
hsTArray<plMessage*> fCommandList;
|
||||
hsTArray<plKey> 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; }
|
||||
};
|
||||
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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)
|
||||
|
@ -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();
|
||||
|
||||
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);
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 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");
|
||||
|
@ -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 <memory>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
|
||||
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
|
||||
|
52
Sources/Plasma/PubUtilLib/plPhysX/plPXSubWorld.cpp
Normal file
52
Sources/Plasma/PubUtilLib/plPhysX/plPXSubWorld.cpp
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
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.
|
||||
}
|
67
Sources/Plasma/PubUtilLib/plPhysX/plPXSubWorld.h
Normal file
67
Sources/Plasma/PubUtilLib/plPhysX/plPXSubWorld.h
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
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
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
Reference in New Issue
Block a user