You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
594 lines
18 KiB
594 lines
18 KiB
14 years ago
|
/*==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/>.
|
||
|
|
||
|
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 "hsTypes.h"
|
||
|
#include "../pnKeyedObject/plKey.h"
|
||
|
#include "hsTemplates.h"
|
||
|
#include "hsStream.h"
|
||
|
#include "plLinkEffectsMgr.h"
|
||
|
#include "../pnMessage/plEventCallbackMsg.h"
|
||
|
#include "../pnMessage/plTimeMsg.h"
|
||
|
#include "../pnMessage/plPlayerPageMsg.h"
|
||
|
#include "../plMessage/plLinkToAgeMsg.h"
|
||
|
#include "../plMessage/plTransitionMsg.h"
|
||
|
#include "plgDispatch.h"
|
||
|
#include "hsResMgr.h"
|
||
|
#include "hsTimer.h"
|
||
|
#include "../pnNetCommon/plNetApp.h"
|
||
|
#include "../plNetClient/plNetClientMgr.h"
|
||
|
#include "../pnSceneObject/plSceneObject.h"
|
||
|
#include "../plNetTransport/plNetTransportMember.h"
|
||
|
#include "../plVault/plVault.h"
|
||
|
#include "../plNetClient/plNetLinkingMgr.h"
|
||
|
#include "../plAgeLoader/plAgeLoader.h"
|
||
|
#include "../pnSceneObject/plCoordinateInterface.h"
|
||
|
#include "../pnMessage/plWarpMsg.h"
|
||
|
#include "../pnKeyedObject/plFixedKey.h"
|
||
|
|
||
|
// chronicle var
|
||
|
#define kCleftSolved L"CleftSolved"
|
||
|
|
||
|
#include "../plAvatar/plArmatureMod.h"
|
||
|
#include "../plAvatar/plAvatarTasks.h"
|
||
|
#include "../plAvatar/plAGAnim.h"
|
||
|
#include "../plMessage/plAvatarMsg.h"
|
||
|
#include "../plMessage/plLoadAgeMsg.h"
|
||
|
|
||
|
plLinkEffectsMgr::plLinkEffectsMgr()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
plLinkEffectsMgr::~plLinkEffectsMgr()
|
||
|
{
|
||
|
int i;
|
||
|
for( i = 0; i < fLinks.GetCount(); i++ )
|
||
|
{
|
||
|
hsRefCnt_SafeUnRef(fLinks[i]);
|
||
|
}
|
||
|
for( i = 0; i < fWaitlist.GetCount(); i++ )
|
||
|
{
|
||
|
hsRefCnt_SafeUnRef(fWaitlist[i]);
|
||
|
}
|
||
|
for( i = 0; i < fDeadlist.GetCount(); i++ )
|
||
|
{
|
||
|
hsRefCnt_SafeUnRef(fDeadlist[i]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void plLinkEffectsMgr::Init()
|
||
|
{
|
||
|
plgDispatch::Dispatch()->RegisterForExactType(plPlayerPageMsg::Index(), GetKey());
|
||
|
plgDispatch::Dispatch()->RegisterForExactType(plPseudoLinkEffectMsg::Index(), GetKey());
|
||
|
}
|
||
|
|
||
|
plLinkEffectsTriggerMsg *plLinkEffectsMgr::IFindLinkTriggerMsg(plKey linkKey)
|
||
|
{
|
||
|
int i;
|
||
|
for (i = 0; i < fLinks.GetCount(); i++)
|
||
|
{
|
||
|
if (fLinks[i]->GetLinkKey() == linkKey)
|
||
|
return fLinks[i];
|
||
|
}
|
||
|
return nil;
|
||
|
}
|
||
|
|
||
|
void plLinkEffectsMgr::IAddLink(plLinkEffectsTriggerMsg *msg)
|
||
|
{
|
||
|
hsRefCnt_SafeRef(msg);
|
||
|
fLinks.Append(msg);
|
||
|
}
|
||
|
|
||
|
void plLinkEffectsMgr::IAddWait(plLinkEffectsTriggerMsg *msg)
|
||
|
{
|
||
|
hsRefCnt_SafeRef(msg);
|
||
|
fWaitlist.Append(msg);
|
||
|
}
|
||
|
|
||
|
void plLinkEffectsMgr::IAddDead(plLinkEffectsTriggerMsg *msg)
|
||
|
{
|
||
|
hsRefCnt_SafeRef(msg);
|
||
|
fDeadlist.Append(msg);
|
||
|
}
|
||
|
|
||
|
void plLinkEffectsMgr::IAddPsuedo(plPseudoLinkEffectMsg *msg)
|
||
|
{
|
||
|
hsRefCnt_SafeRef(msg);
|
||
|
fPseudolist.Append(msg);
|
||
|
}
|
||
|
|
||
|
hsBool plLinkEffectsMgr::IHuntWaitlist(plLinkEffectsTriggerMsg *msg)
|
||
|
{
|
||
|
int i;
|
||
|
hsBool found = false;
|
||
|
for (i = fWaitlist.GetCount() - 1; i >= 0; i--)
|
||
|
{
|
||
|
if (fWaitlist[i] == msg)
|
||
|
{
|
||
|
found = true;
|
||
|
hsRefCnt_SafeUnRef(fWaitlist[i]);
|
||
|
fWaitlist.Remove(i);
|
||
|
plNetApp::GetInstance()->DebugMsg("Received backup LinkEffectsTriggerMsg. Never got remote trigger!\n");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return found || IHuntWaitlist(msg->GetLinkKey());
|
||
|
}
|
||
|
|
||
|
hsBool plLinkEffectsMgr::IHuntWaitlist(plKey linkKey)
|
||
|
{
|
||
|
int i;
|
||
|
hsBool found = false;
|
||
|
for (i = fWaitlist.GetCount() - 1; i >= 0; i--)
|
||
|
{
|
||
|
if (fWaitlist[i]->GetLinkKey() == linkKey)
|
||
|
{
|
||
|
found = true;
|
||
|
IAddDead(fWaitlist[i]);
|
||
|
|
||
|
hsRefCnt_SafeUnRef(fWaitlist[i]);
|
||
|
fWaitlist.Remove(i);
|
||
|
plNetApp::GetInstance()->DebugMsg("Received remote LinkEffectsTriggerMsg. Awaiting backup.\n");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return found;
|
||
|
}
|
||
|
|
||
|
hsBool plLinkEffectsMgr::IHuntDeadlist(plLinkEffectsTriggerMsg *msg)
|
||
|
{
|
||
|
int i;
|
||
|
hsBool found = false;
|
||
|
for (i = fDeadlist.GetCount() - 1; i >= 0; i--)
|
||
|
{
|
||
|
if (fDeadlist[i] == msg)
|
||
|
{
|
||
|
found = true;
|
||
|
hsRefCnt_SafeUnRef(fDeadlist[i]);
|
||
|
fDeadlist.Remove(i);
|
||
|
plNetApp::GetInstance()->DebugMsg("Received backup LinkEffectsTriggerMsg. Cleanly ignoring since we received remote trigger.\n");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return found;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
void plLinkEffectsMgr::ISendAllReadyCallbacks()
|
||
|
{
|
||
|
int i;
|
||
|
for (i = fLinks.GetCount() - 1; i >= 0; i--)
|
||
|
{
|
||
|
if (fLinks[i]->fEffects <= 0)
|
||
|
{
|
||
|
if (fLinks[i]->IsLeavingAge())
|
||
|
{
|
||
|
if (fLinks[i]->GetLinkKey() == plNetClientApp::GetInstance()->GetLocalPlayerKey())
|
||
|
{
|
||
|
plLinkOutUnloadMsg* lam = TRACKED_NEW plLinkOutUnloadMsg; // derived from LoadAgeMsg
|
||
|
lam->SetAgeFilename( NetCommGetAge()->ageDatasetName );
|
||
|
lam->AddReceiver(plNetClientMgr::GetInstance()->GetKey());
|
||
|
lam->SetPlayerID(plNetClientMgr::GetInstance()->GetPlayerID());
|
||
|
lam->Send();
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
plLinkInDoneMsg* lid = TRACKED_NEW plLinkInDoneMsg;
|
||
|
lid->AddReceiver(fLinks[i]->GetLinkKey());
|
||
|
lid->SetBCastFlag(plMessage::kPropagateToModifiers);
|
||
|
lid->Send();
|
||
|
|
||
|
if (fLinks[i]->GetLinkKey() == plNetClientApp::GetInstance()->GetLocalPlayerKey())
|
||
|
{
|
||
|
plLinkInDoneMsg* lid = TRACKED_NEW plLinkInDoneMsg;
|
||
|
lid->AddReceiver(plNetClientMgr::GetInstance()->GetKey());
|
||
|
lid->Send();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
hsRefCnt_SafeUnRef(fLinks[i]);
|
||
|
fLinks.Remove(i);
|
||
|
|
||
|
hsStatusMessage("Done - removing link FX msg\n");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
hsBool plLinkEffectsMgr::MsgReceive(plMessage *msg)
|
||
|
{
|
||
|
plNetClientMgr* nc = plNetClientMgr::GetInstance();
|
||
|
plNetLinkingMgr* lm = plNetLinkingMgr::GetInstance();
|
||
|
|
||
|
plPseudoLinkEffectMsg* pSeudoMsg = plPseudoLinkEffectMsg::ConvertNoRef(msg);
|
||
|
if (pSeudoMsg)
|
||
|
{
|
||
|
// verify valid avatar and "link" objects
|
||
|
if (!pSeudoMsg->fAvatarKey)
|
||
|
return true;
|
||
|
if (!pSeudoMsg->fLinkObjKey)
|
||
|
return true;
|
||
|
if (!pSeudoMsg->fLinkObjKey->ObjectIsLoaded())
|
||
|
return true;
|
||
|
if (!plNetClientMgr::GetInstance()->IsAPlayerKey(pSeudoMsg->fAvatarKey))
|
||
|
return true;
|
||
|
// send the trigger message to the avatar...
|
||
|
plPseudoLinkAnimTriggerMsg* pMsg = TRACKED_NEW plPseudoLinkAnimTriggerMsg(true, pSeudoMsg->fAvatarKey);
|
||
|
pMsg->SetSender(GetKey());
|
||
|
pMsg->Send();
|
||
|
IAddPsuedo(pSeudoMsg);
|
||
|
}
|
||
|
|
||
|
plPseudoLinkAnimCallbackMsg* pSeudoCallback = plPseudoLinkAnimCallbackMsg::ConvertNoRef(msg);
|
||
|
if (pSeudoCallback)
|
||
|
{
|
||
|
// warp the avatar to his new position
|
||
|
plPseudoLinkEffectMsg* pMsg = IFindPseudo(pSeudoCallback->fAvatarKey);
|
||
|
if (pMsg)
|
||
|
{
|
||
|
plSceneObject* pObj = plSceneObject::ConvertNoRef(pMsg->fLinkObjKey->ObjectIsLoaded());
|
||
|
if (pObj && pObj->GetCoordinateInterface())
|
||
|
{
|
||
|
hsMatrix44 mat = pObj->GetCoordinateInterface()->GetLocalToWorld();
|
||
|
// create message
|
||
|
plWarpMsg* pMsg = TRACKED_NEW plWarpMsg(mat);
|
||
|
pMsg->SetWarpFlags(plWarpMsg::kFlushTransform);
|
||
|
pMsg->AddReceiver(pSeudoCallback->fAvatarKey);
|
||
|
plUoid U(kVirtualCamera1_KEY);
|
||
|
plKey pCamKey = hsgResMgr::ResMgr()->FindKey(U);
|
||
|
if (pCamKey)
|
||
|
{
|
||
|
pMsg->AddReceiver(pCamKey);
|
||
|
}
|
||
|
plgDispatch::MsgSend( pMsg ); // whoosh... off it goes
|
||
|
// now make him re-appear
|
||
|
plPseudoLinkAnimTriggerMsg* pTrigMsg = TRACKED_NEW plPseudoLinkAnimTriggerMsg(false, pSeudoCallback->fAvatarKey);
|
||
|
pTrigMsg->SetSender(GetKey());
|
||
|
pTrigMsg->Send();
|
||
|
IRemovePseudo(pSeudoCallback->fAvatarKey);
|
||
|
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
plLinkEffectsTriggerPrepMsg *tpMsg = plLinkEffectsTriggerPrepMsg::ConvertNoRef(msg);
|
||
|
if (tpMsg)
|
||
|
{
|
||
|
plNetApp::GetInstance()->DebugMsg("Received LinkEffectsTriggerPREPMsg\n");
|
||
|
IAddWait(tpMsg->GetTrigger());
|
||
|
plLinkEffectPrepBCMsg *bcpMsg = TRACKED_NEW plLinkEffectPrepBCMsg;
|
||
|
bcpMsg->fLeavingAge = tpMsg->fLeavingAge;
|
||
|
bcpMsg->fLinkKey = tpMsg->fLinkKey;
|
||
|
bcpMsg->Send();
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
plLinkEffectsTriggerMsg* pTriggerMsg = plLinkEffectsTriggerMsg::ConvertNoRef(msg);
|
||
|
if (pTriggerMsg)
|
||
|
{
|
||
|
plNetApp::GetInstance()->DebugMsg("Received LinkEffectsTriggerMsg, local=%d, linkingIn=%d, stealth=%d",
|
||
|
!msg->HasBCastFlag(plMessage::kNetNonLocal),
|
||
|
!pTriggerMsg->IsLeavingAge(), pTriggerMsg->GetInvisLevel());
|
||
|
|
||
|
plKey linkKey = pTriggerMsg->GetLinkKey();
|
||
|
if (linkKey == nil)
|
||
|
return true;
|
||
|
|
||
|
if ((linkKey != nc->GetLocalPlayerKey()) &&
|
||
|
(!pTriggerMsg->IsLeavingAge()))
|
||
|
{
|
||
|
if (IHuntDeadlist(pTriggerMsg)) // Just an obselete safety trigger
|
||
|
return true;
|
||
|
|
||
|
if (!IHuntWaitlist(pTriggerMsg))
|
||
|
{
|
||
|
plNetApp::GetInstance()->DebugMsg("Unexpected linkEffectsTriggerMsg. Ignoring\n");
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
plSceneObject *avatar = plSceneObject::ConvertNoRef(linkKey->ObjectIsLoaded());
|
||
|
if (avatar == nil)
|
||
|
{
|
||
|
plNetApp::GetInstance()->DebugMsg("Can't find avatar, mod=%s\n", linkKey->GetName());
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
// This is not the right place to catch this problem.
|
||
|
// if (IFindLinkTriggerMsg(linkKey) != nil)
|
||
|
// {
|
||
|
// hsAssert(false, "Trying to link an Avatar already in the process of linking.");
|
||
|
// return true;
|
||
|
// }
|
||
|
|
||
|
if (pTriggerMsg->GetInvisLevel() && linkKey != nc->GetLocalPlayerKey())
|
||
|
{
|
||
|
#ifdef PLASMA_EXTERNAL_RELEASE
|
||
|
// Verify that the server told us that the invisible avatar is a CCR
|
||
|
plNetTransportMember* mbr=nc->TransportMgr().GetMember(nc->TransportMgr().FindMember(linkKey));
|
||
|
if (!mbr || mbr->GetCCRLevel()<pTriggerMsg->GetInvisLevel())
|
||
|
{
|
||
|
plNetApp::StaticErrorMsg("Remote Avatar trying to be stealthy - REJECTING since he's not a CCR");
|
||
|
}
|
||
|
else
|
||
|
#endif
|
||
|
{
|
||
|
plNetApp::StaticDebugMsg("Remote Avatar is in stealth mode - making invisible");
|
||
|
nc->MakeCCRInvisible(pTriggerMsg->GetLinkKey(), pTriggerMsg->GetInvisLevel());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (pTriggerMsg->IsLeavingAge())
|
||
|
hsStatusMessage("Starting LinkOut FX\n");
|
||
|
else
|
||
|
hsStatusMessage("Starting LinkIn FX\n");
|
||
|
|
||
|
plLinkEffectBCMsg *BCMsg = TRACKED_NEW plLinkEffectBCMsg();
|
||
|
BCMsg->fLinkKey = linkKey;
|
||
|
BCMsg->SetLinkFlag(plLinkEffectBCMsg::kLeavingAge, pTriggerMsg->IsLeavingAge());
|
||
|
BCMsg->SetLinkFlag(plLinkEffectBCMsg::kSendCallback, true);
|
||
|
|
||
|
// Check if you have a Yeesha book, and mute sound if you don't.
|
||
|
// 'CleftSolved' gets set when you click on the linking panel in the cleft,
|
||
|
// so we use that instead of checking KILevel.
|
||
|
// Also, check if you're going to/from the ACA, or through the fissure, and mute sound if you are.
|
||
|
if (linkKey == nc->GetLocalPlayerKey())
|
||
|
{
|
||
|
if(lm) {
|
||
|
const char *ageName = lm->GetAgeLink()->GetAgeInfo()->GetAgeFilename();
|
||
|
const char *prevAgeName = lm->GetPrevAgeLink()->GetAgeInfo()->GetAgeFilename();
|
||
|
|
||
|
bool linkToStartup = ageName && !stricmp(ageName, kStartUpAgeFilename ); // To Startup
|
||
|
bool linkFromStartup = prevAgeName && !stricmp(prevAgeName, kStartUpAgeFilename); // Leaving Startup
|
||
|
|
||
|
bool cleftSolved = VaultHasChronicleEntry( kCleftSolved );
|
||
|
|
||
|
bool linkToACA = ageName && !stricmp(ageName, kAvCustomizationFilename);
|
||
|
bool linkFromACA = prevAgeName && !stricmp(prevAgeName, kAvCustomizationFilename);
|
||
|
|
||
|
bool linkToFissureDrop = lm &&
|
||
|
lm->GetAgeLink()->HasSpawnPt() &&
|
||
|
lm->GetAgeLink()->SpawnPoint().GetName() &&
|
||
|
!stricmp(lm->GetAgeLink()->SpawnPoint().GetName(), kCleftAgeLinkInPointFissureDrop);
|
||
|
bool linkToDsntFromShell = lm &&
|
||
|
lm->GetAgeLink()->HasSpawnPt() &&
|
||
|
lm->GetAgeLink()->SpawnPoint().GetTitle() &&
|
||
|
!stricmp(lm->GetAgeLink()->SpawnPoint().GetTitle(), kDescentLinkFromShell);
|
||
|
if ( linkToACA || linkFromACA || linkToStartup || linkFromStartup || linkToFissureDrop || linkToDsntFromShell)
|
||
|
{
|
||
|
BCMsg->SetLinkFlag(plLinkEffectBCMsg::kMute);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
BCMsg->SetSender(GetKey());
|
||
|
if (msg->HasBCastFlag(plMessage::kNetNonLocal))
|
||
|
// terminate the remote cascade and start a new (local) cascade, since the rcvr is localOnly and will reject remote msgs
|
||
|
BCMsg->SetBCastFlag(plMessage::kNetStartCascade);
|
||
|
plgDispatch::MsgSend(BCMsg);
|
||
|
|
||
|
if (!pTriggerMsg->IsLeavingAge()) // Avatar is currently entering a new age
|
||
|
{
|
||
|
plATCAnim *linkInAnim = nil;
|
||
|
plKey linkInAnimKey = nil;
|
||
|
const plArmatureMod *avMod = plArmatureMod::ConvertNoRef(avatar->GetModifierByType(plArmatureMod::Index()));
|
||
|
if (pTriggerMsg->HasBCastFlag(plMessage::kNetNonLocal))
|
||
|
{
|
||
|
// Remote trigger, they should tell us how they linked in.
|
||
|
linkInAnimKey = pTriggerMsg->GetLinkInAnimKey();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// this is our backup trigger we send ourselves. We've already received the remote player's SDL.
|
||
|
linkInAnimKey = avMod ? avMod->GetLinkInAnimKey() : nil;
|
||
|
}
|
||
|
linkInAnim = plATCAnim::ConvertNoRef(linkInAnimKey ? linkInAnimKey->ObjectIsLoaded() : nil);
|
||
|
|
||
|
if (avMod && linkInAnim)
|
||
|
{
|
||
|
plAvOneShotTask *task = TRACKED_NEW plAvOneShotTask(linkInAnim->GetName(), false, false, nil);
|
||
|
task->fBackwards = true;
|
||
|
task->fDisableLooping = true;
|
||
|
task->fDisablePhysics = false;
|
||
|
(TRACKED_NEW plAvTaskMsg(GetKey(), avMod->GetKey(), task))->Send();
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
IAddLink(pTriggerMsg); // refs the avatarMod
|
||
|
|
||
|
// Dummy msg sent after the broadcast. This guarantees we have a callback to actually trigger the
|
||
|
// link, plus we know any effect broadcast messages will have processed before this (and therefore
|
||
|
// have told us to wait for them.)
|
||
|
pTriggerMsg->fEffects++;
|
||
|
plLinkCallbackMsg *dummyMsg = TRACKED_NEW plLinkCallbackMsg();
|
||
|
dummyMsg->AddReceiver(GetKey());
|
||
|
dummyMsg->fLinkKey = linkKey;
|
||
|
plgDispatch::MsgSend(dummyMsg);
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
// callbacks from linkout events
|
||
|
plLinkCallbackMsg* pLinkCallbackMsg = plLinkCallbackMsg::ConvertNoRef(msg);
|
||
|
if (pLinkCallbackMsg)
|
||
|
{
|
||
|
plNetApp::GetInstance()->DebugMsg("Received pLinkCallbackMsg, localmsg=%d\n",
|
||
|
!msg->HasBCastFlag(plMessage::kNetNonLocal));
|
||
|
|
||
|
static char str[ 128 ];
|
||
|
plLinkEffectsTriggerMsg *pTriggerMsg = IFindLinkTriggerMsg(pLinkCallbackMsg->fLinkKey);
|
||
|
if (pTriggerMsg == nil)
|
||
|
{
|
||
|
hsAssert(true, "Received a callback for an avatar that isn't linking.");
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
if (--pTriggerMsg->fEffects == 0)
|
||
|
{
|
||
|
plNetApp::GetInstance()->DebugMsg("All link callbacks received.\n" );
|
||
|
plgDispatch::Dispatch()->RegisterForExactType(plTimeMsg::Index(), GetKey());
|
||
|
}
|
||
|
else if (pTriggerMsg->fEffects < 0 )
|
||
|
{
|
||
|
plNetApp::GetInstance()->DebugMsg("Too many link callbacks received for avatar %s. Ignoring extras.\n",
|
||
|
pTriggerMsg->GetLinkKey()->GetName());
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
plNetApp::GetInstance()->DebugMsg("%d link callbacks left until avatar %s links...\n",
|
||
|
pTriggerMsg->fEffects, pTriggerMsg->GetLinkKey()->GetName());
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
plTimeMsg *time = plTimeMsg::ConvertNoRef(msg);
|
||
|
if (time) // This is how we know we're out of the render function, and it's safe to pageIn/Out nodes
|
||
|
{
|
||
|
plgDispatch::Dispatch()->UnRegisterForExactType(plTimeMsg::Index(), GetKey());
|
||
|
ISendAllReadyCallbacks();
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
plPlayerPageMsg *pageMsg = plPlayerPageMsg::ConvertNoRef(msg);
|
||
|
if (pageMsg)
|
||
|
{
|
||
|
if (pageMsg->fUnload)
|
||
|
{
|
||
|
IHuntWaitlist(pageMsg->fPlayer);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
const hsScalar kMaxTimeForLinkTrigger = 30.f;
|
||
|
|
||
|
// If we're not loading state, we're in the age. So this avatar coming in must be linking in.
|
||
|
// If the player is us, no prep is necessary.
|
||
|
if (!plNetClientApp::GetInstance()->IsLoadingInitialAgeState() &&
|
||
|
(pageMsg->fPlayer != nc->GetLocalPlayerKey()))
|
||
|
{
|
||
|
plLinkEffectsTriggerMsg *trigMsg = TRACKED_NEW plLinkEffectsTriggerMsg;
|
||
|
trigMsg->SetLeavingAge(false);
|
||
|
trigMsg->SetLinkKey(pageMsg->fPlayer);
|
||
|
|
||
|
// Send off the prep message right away
|
||
|
plLinkEffectsTriggerPrepMsg *trigPrepMsg = TRACKED_NEW plLinkEffectsTriggerPrepMsg;
|
||
|
trigPrepMsg->fLinkKey = pageMsg->fPlayer;
|
||
|
trigPrepMsg->SetTrigger(trigMsg);
|
||
|
trigPrepMsg->Send(GetKey());
|
||
|
|
||
|
// Send off a delayed safety trigger. If things are going along properly,
|
||
|
// we'll get a trigger from the player linking in before this message is
|
||
|
// received, and we'll ignore it.
|
||
|
double timeToDeliver = hsTimer::GetSysSeconds() + kMaxTimeForLinkTrigger;
|
||
|
trigMsg->SetTimeStamp(timeToDeliver);
|
||
|
trigMsg->Send(GetKey());
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return hsKeyedObject::MsgReceive(msg);
|
||
|
}
|
||
|
|
||
|
void plLinkEffectsMgr::WaitForEffect(plKey linkKey, hsScalar time)
|
||
|
{
|
||
|
plLinkEffectsTriggerMsg *msg = IFindLinkTriggerMsg(linkKey);
|
||
|
if (msg == nil)
|
||
|
{
|
||
|
hsAssert(true, "Request to wait on an effect for an avatar that isn't linking.");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
msg->fEffects++;
|
||
|
plLinkCallbackMsg *callback = TRACKED_NEW plLinkCallbackMsg();
|
||
|
callback->fEvent = kStop;
|
||
|
callback->fRepeats = 0;
|
||
|
callback->fLinkKey = linkKey;
|
||
|
double timeToDeliver = hsTimer::GetSysSeconds() + time;
|
||
|
callback->SetTimeStamp( timeToDeliver );
|
||
|
callback->Send( GetKey() );
|
||
|
}
|
||
|
|
||
|
plMessage *plLinkEffectsMgr::WaitForEffect(plKey linkKey)
|
||
|
{
|
||
|
plLinkEffectsTriggerMsg *msg = IFindLinkTriggerMsg(linkKey);
|
||
|
if (msg == nil)
|
||
|
{
|
||
|
hsAssert(true, "Request to wait on an effect for an avatar that isn't linking.");
|
||
|
return nil;
|
||
|
}
|
||
|
|
||
|
msg->fEffects++;
|
||
|
|
||
|
plLinkCallbackMsg *callback = TRACKED_NEW plLinkCallbackMsg();
|
||
|
callback->fEvent = kStop;
|
||
|
callback->fRepeats = 0;
|
||
|
callback->fLinkKey = linkKey;
|
||
|
callback->AddReceiver( GetKey() );
|
||
|
return callback;
|
||
|
}
|
||
|
|
||
|
void plLinkEffectsMgr::WaitForPseudoEffect(plKey linkKey, hsScalar time)
|
||
|
{
|
||
|
plPseudoLinkEffectMsg* msg = IFindPseudo(linkKey);
|
||
|
if (msg == nil)
|
||
|
{
|
||
|
hsAssert(true, "Request to wait on an fake effect for an avatar that isn't fake linking.");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
plPseudoLinkAnimCallbackMsg* callback = TRACKED_NEW plPseudoLinkAnimCallbackMsg();
|
||
|
callback->fAvatarKey = linkKey;
|
||
|
double timeToDeliver = hsTimer::GetSysSeconds() + time;
|
||
|
callback->SetTimeStamp( timeToDeliver );
|
||
|
callback->Send( GetKey() );
|
||
|
}
|
||
|
|
||
|
plPseudoLinkEffectMsg* plLinkEffectsMgr::IFindPseudo(plKey avatarKey)
|
||
|
{
|
||
|
int i;
|
||
|
for (i = 0; i < fPseudolist.GetCount(); i++)
|
||
|
{
|
||
|
if (fPseudolist[i]->fAvatarKey == avatarKey)
|
||
|
return fPseudolist[i];
|
||
|
}
|
||
|
return nil;
|
||
|
|
||
|
}
|
||
|
|
||
|
void plLinkEffectsMgr::IRemovePseudo(plKey avatarKey)
|
||
|
{
|
||
|
int i;
|
||
|
for (i = 0; i < fPseudolist.GetCount(); i++)
|
||
|
{
|
||
|
if (fPseudolist[i]->fAvatarKey == avatarKey)
|
||
|
{
|
||
|
fPseudolist.Remove(i);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|