1
0
mirror of https://foundry.openuru.org/gitblit/r/CWE-ou-minkata.git synced 2025-07-18 19:29:09 +00:00

Initial Commit of CyanWorlds.com Engine Open Source Client/Plugin

This commit is contained in:
jwplatt
2011-03-12 12:34:52 -05:00
commit b970ae4bad
3976 changed files with 1301355 additions and 0 deletions

View File

@ -0,0 +1,594 @@
/*==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;
}
}
}

View File

@ -0,0 +1,81 @@
/*==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==*/
#ifndef plLinkEffectsMgr_inc
#define plLinkEffectsMgr_inc
#include "../pnKeyedObject/hsKeyedObject.h"
class plLinkEffectsTriggerMsg;
class plPseudoLinkEffectMsg;
class plLinkEffectsMgr : public hsKeyedObject
{
protected:
// Collection of links in progress (in or out)
hsTArray<plLinkEffectsTriggerMsg *> fLinks;
// Players we know exist, but aren't ready to link yet
hsTArray<plLinkEffectsTriggerMsg *> fWaitlist;
// Queue of delayed messages from people linking in that
// we haven't received yet but are no longer necessary,
// because we either received the trigger from them, or
// they're no longer in the age.
hsTArray<plLinkEffectsTriggerMsg *> fDeadlist;
// queue of pseudo link messages
hsTArray<plPseudoLinkEffectMsg *> fPseudolist;
plLinkEffectsTriggerMsg *IFindLinkTriggerMsg(plKey avatarKey);
void IAddLink(plLinkEffectsTriggerMsg *msg);
void IAddWait(plLinkEffectsTriggerMsg *msg);
void IAddDead(plLinkEffectsTriggerMsg *msg);
void IAddPsuedo(plPseudoLinkEffectMsg *msg);
void IRemovePseudo(plKey avatarKey);
plPseudoLinkEffectMsg* IFindPseudo(plKey avatarKey);
hsBool IHuntWaitlist(plLinkEffectsTriggerMsg *msg);
hsBool IHuntWaitlist(plKey linkKey);
hsBool IHuntDeadlist(plLinkEffectsTriggerMsg *msg);
void ISendAllReadyCallbacks();
public:
plLinkEffectsMgr();
~plLinkEffectsMgr();
void Init();
CLASSNAME_REGISTER( plLinkEffectsMgr );
GETINTERFACE_ANY( plLinkEffectsMgr, hsKeyedObject );
void WaitForEffect(plKey linkKey, hsScalar time);
void WaitForPseudoEffect(plKey linkKey, hsScalar time);
plMessage *WaitForEffect(plKey linkKey);
virtual hsBool MsgReceive(plMessage *msg);
};
#endif // plLinkEffectsMgr_inc

View File

@ -0,0 +1,476 @@
/*==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==*/
/*****************************************************************************
*
* $/Plasma20/Sources/Plasma/PubUtilLib/plNetClient/plNetCliAgeJoiner.cpp
*
* Encapsulates all of the horrible ugliness that the age load process has become
*
***/
#include "plNetCliAgeJoiner.h"
#include "plNetClientMgr.h"
#include "plNetLinkingMgr.h"
#include "../pnSceneObject/plSceneObject.h"
#include "../pnSceneObject/plCoordinateInterface.h"
#include "../pnMessage/plPlayerPageMsg.h"
#include "../pnMessage/plTimeMsg.h"
#include "../plNetClientComm/plNetClientComm.h"
#include "../plAgeLoader/plAgeLoader.h"
#include "../plAgeLoader/plBackgroundDownloader.h"
#include "../plAvatar/plAvatarMgr.h"
#include "../plVault/plVault.h"
#include "../plNetMessage/plNetMessage.h"
#include "../plMessage/plNetCommMsgs.h"
#include "../plMessage/plAgeLoadedMsg.h"
#include "../plMessage/plInputIfaceMgrMsg.h"
#include "../plMessage/plNetClientMgrMsg.h"
#include "../plProgressMgr/plProgressMgr.h"
#include "../pnDispatch/plDispatch.h"
#include "../plResMgr/plResManager.h"
/*****************************************************************************
*
* Private
*
***/
struct plNCAgeJoiner {
enum NextOp {
kNoOp,
kLoadAge,
kLoadPlayer,
kRequestAgeState,
kPropagatePlayer,
kDestroyProgressBar,
kEnableClickables,
kSimStateRcvd,
kNotifyAgeLoaded,
};
NextOp nextOp;
NetCommAge age;
FNCAgeJoinerCallback callback;
void * userState;
bool complete;
plOperationProgress* progressBar;
plNCAgeJoiner (
const NetCommAge & age,
FNCAgeJoinerCallback callback,
void * userState
);
~plNCAgeJoiner ();
void Start ();
void Complete (bool success, const char msg[]);
bool MsgReceive (plMessage * msg);
void Update ();
void ExecNextOp ();
static void IDispatchMsgReceiveCallback ();
static void IResMgrProgressBarCallback (plKey key);
static plNCAgeJoiner* s_instance;
};
plNCAgeJoiner* plNCAgeJoiner::s_instance = nil;
/*****************************************************************************
*
* Local functions
*
***/
//============================================================================
void AgeVaultDownloadCallback (
ENetError result,
void * param
) {
plNCAgeJoiner * joiner = (plNCAgeJoiner *)param;
if (IS_NET_ERROR(result)) {
joiner->Complete(false, "Failed to download age vault");
}
else {
// vault downloaded. start loading age data
LogMsg(kLogPerf, L"AgeJoiner: Next:kLoadAge (vault downloaded)");
joiner->nextOp = plNCAgeJoiner::kLoadAge;
}
}
/*****************************************************************************
*
* plNCAgeJoiner
*
***/
//============================================================================
plNCAgeJoiner::plNCAgeJoiner (
const NetCommAge & age,
FNCAgeJoinerCallback callback,
void * userState
) : nextOp(kNoOp)
, age(age)
, callback(callback)
, userState(userState)
, progressBar(nil)
{
}
//============================================================================
plNCAgeJoiner::~plNCAgeJoiner () {
}
//============================================================================
void plNCAgeJoiner::IDispatchMsgReceiveCallback () {
if (s_instance)
s_instance->progressBar->Increment(1);
}
//============================================================================
void plNCAgeJoiner::IResMgrProgressBarCallback (plKey key) {
#ifndef PLASMA_EXTERNAL_RELEASE
if (s_instance)
s_instance->progressBar->SetStatusText(key->GetName());
#endif
}
//============================================================================
void plNCAgeJoiner::Complete (bool success, const char msg[]) {
if (!complete) {
complete = true;
s_instance = nil;
NCAgeJoinerCompleteNotify notify;
notify.success = success;
notify.msg = msg;
callback(this, kAgeJoinerComplete, &notify, userState);
DEL(this);
}
if (plBackgroundDownloader::GetInstance())
plBackgroundDownloader::GetInstance()->UnPause();
}
//============================================================================
void plNCAgeJoiner::Start () {
s_instance = this;
plNetClientMgr * nc = plNetClientMgr::GetInstance();
nc->SetFlagsBit(plNetClientMgr::kPlayingGame, false);
nc->fServerTimeOffset = 0; // reset since we're connecting to a new server
nc->fRequiredNumInitialSDLStates = 0;
nc->fNumInitialSDLStates = 0;
nc->SetFlagsBit(plNetClientApp::kNeedInitialAgeStateCount);
nc->SetFlagsBit(plNetClientApp::kLoadingInitialAgeState);
// if we're linking to startup then set the OfflineAge flag
// so we by-pass the game server
if (StrLen(age.ageDatasetName) == 0 || StrCmpI(age.ageDatasetName, "StartUp") == 0)
nc->SetFlagsBit(plNetClientApp::kLinkingToOfflineAge);
else
nc->SetFlagsBit(plNetClientApp::kLinkingToOfflineAge, false);
plAgeLoader* al = plAgeLoader::GetInstance();
al->UpdateAge(age.ageDatasetName);
nc->ResetServerTimeOffset();
NetCommLinkToAge(
age,
this
);
}
//============================================================================
void plNCAgeJoiner::ExecNextOp () {
plNetClientMgr * nc = plNetClientMgr::GetInstance();
plAvatarMgr * am = plAvatarMgr::GetInstance();
plAgeLoader * al = plAgeLoader::GetInstance();
NextOp next = nextOp;
nextOp = kNoOp;
switch (next) {
//====================================================================
case kNoOp: {
}
break;
//====================================================================
case kLoadAge: {
LogMsg(kLogPerf, L"AgeJoiner: Exec:kLoadAge");
// Start progress bar
char str[256];
#ifdef PLASMA_EXTERNAL_RELEASE
StrCopy(str, "Loading age...", arrsize(str));
#else
StrPrintf(str, arrsize(str), "Loading age %s...", age.ageDatasetName);
#endif
progressBar = plProgressMgr::GetInstance()->RegisterOperation(0, str, plProgressMgr::kNone, false, true);
plDispatch::SetMsgRecieveCallback(IDispatchMsgReceiveCallback);
((plResManager*)hsgResMgr::ResMgr())->SetProgressBarProc(IResMgrProgressBarCallback);
// Start loading age data
al->LoadAge(age.ageDatasetName);
}
break;
//====================================================================
case kLoadPlayer: {
LogMsg(kLogPerf, L"AgeJoiner: Exec:kLoadPlayer");
// Start loading local player
const char * avatarName;
if (NetCommNeedToLoadAvatar()) {
if (nc->GetFlagsBit(plNetClientApp::kLinkingToOfflineAge))
avatarName = "Male";
else
avatarName = NetCommGetPlayer()->avatarDatasetName;
const char * linkInName = plNetLinkingMgr::GetInstance()->GetAgeLink()->SpawnPoint().GetName();
am->LoadPlayer( avatarName, nil, linkInName );
}
else {
LogMsg(kLogPerf, L"AgeJoiner: Next:kPropagatePlayer");
nextOp = kPropagatePlayer;
}
}
break;
//====================================================================
case kPropagatePlayer: {
LogMsg(kLogPerf, L"AgeJoiner: Exec:kPropagatePlayer");
// Add our avatar to the scene
int spawnPt = am->FindSpawnPoint(age.spawnPtName);
nc->IPlayerChangeAge(false /*not exiting*/, spawnPt);
if (!nc->GetFlagsBit(plNetClientApp::kLinkingToOfflineAge))
// Add our avatar to the game state
am->PropagateLocalPlayer(spawnPt);
LogMsg(kLogPerf, L"AgeJoiner: Next:kRequestAgeState");
nextOp = kRequestAgeState;
}
break;
//============================================================================
case kRequestAgeState: {
LogMsg(kLogPerf, L"AgeJoiner: Exec:kRequestAgeState");
if (nc->GetFlagsBit(plNetClientApp::kLinkingToOfflineAge)) {
LogMsg(kLogPerf, L"AgeJoiner: Next:kSimStateRcvd");
nextOp = kSimStateRcvd;
}
else {
// Request age player list
nc->ISendMembersListRequest();
// Request initial SDL state
plNetMsgGameStateRequest gsmsg;
gsmsg.SetNetProtocol(kNetProtocolCli2Game);
gsmsg.SetBit(plNetMessage::kInitialAgeStateRequest);
nc->SendMsg(&gsmsg);
// Send our avatar settings
nc->SendLocalPlayerAvatarCustomizations();
}
}
break;
//====================================================================
case kSimStateRcvd: {
nc->NotifyRcvdAllSDLStates();
}
break;
//============================================================================
case kDestroyProgressBar: {
plDispatch::SetMsgRecieveCallback(nil);
((plResManager*)hsgResMgr::ResMgr())->SetProgressBarProc(nil);
delete progressBar;
progressBar = nil;
nextOp = kEnableClickables;
}
break;
//====================================================================
case kEnableClickables: {
LogMsg(kLogPerf, L"AgeJoiner: Exec:kEnableClickables");
// Enable scene clickables
(void)(TRACKED_NEW plInputIfaceMgrMsg(plInputIfaceMgrMsg::kEnableClickables))->Send();
LogMsg(kLogPerf, L"AgeJoiner: Next:kNotifyAgeLoaded");
nextOp = kNotifyAgeLoaded;
}
break;
//====================================================================
case kNotifyAgeLoaded: {
LogMsg(kLogPerf, L"AgeJoiner: Exec:kNotifyAgeLoaded");
nc->SetFlagsBit(plNetClientApp::kPlayingGame);
nc->SetFlagsBit(plNetClientApp::kNeedToSendInitialAgeStateLoadedMsg);
plAgeLoader::GetInstance()->NotifyAgeLoaded(true);
Complete(true, "Age joined");
}
break;
DEFAULT_FATAL(nextOp);
}
}
//============================================================================
bool plNCAgeJoiner::MsgReceive (plMessage * msg) {
plNetClientMgr * nc = plNetClientMgr::GetInstance();
plAvatarMgr * am = plAvatarMgr::GetInstance();
plAgeLoader * al = plAgeLoader::GetInstance();
//========================================================================
// Connected to age instance
//========================================================================
if (plNetCommLinkToAgeMsg * linkToAgeMsg = plNetCommLinkToAgeMsg::ConvertNoRef(msg)) {
if (IS_NET_ERROR(linkToAgeMsg->result)) {
Complete(false, "LinkToAge failed");
}
else if (unsigned ageVaultId = NetCommGetAge()->ageVaultId) {
// Download the age vault
VaultDownload(
L"AgeJoin",
ageVaultId,
AgeVaultDownloadCallback,
this,
nil, // FVaultDownloadProgressCallback
this
);
}
else {
// not vault to downloaded, just start loading age data
LogMsg(kLogPerf, L"AgeJoiner: Next:kLoadAge (no vault)");
nextOp = kLoadAge;
}
return true;
}
//========================================================================
// All age data paged in
//========================================================================
if (plAgeLoaded2Msg * ageLoaded2Msg = plAgeLoaded2Msg::ConvertNoRef(msg)) {
// Exec custom age settings
al->ExecPendingAgeFniFiles();
al->ExecPendingAgeCsvFiles();
LogMsg(kLogPerf, L"AgeJoiner: Next:kLoadPlayer");
nextOp = kLoadPlayer;
return true;
}
//========================================================================
// Local avatar loaded
//========================================================================
plPlayerPageMsg * playerPageMsg = plPlayerPageMsg::ConvertNoRef(msg);
if (playerPageMsg && !playerPageMsg->fUnload && playerPageMsg->fPlayer && playerPageMsg->fLocallyOriginated) {
if (NetCommNeedToLoadAvatar())
NetCommSetAvatarLoaded();
LogMsg(kLogPerf, L"AgeJoiner: Next:kPropagatePlayer");
nextOp = kPropagatePlayer;
return false; // NetClientMgr must also handle this message
}
//========================================================================
// Received all SDL states
//========================================================================
plNetClientMgrMsg * netClientMgrMsg = plNetClientMgrMsg::ConvertNoRef(msg);
if (netClientMgrMsg && netClientMgrMsg->type == plNetClientMgrMsg::kNotifyRcvdAllSDLStates) {
LogMsg(kLogPerf, L"AgeJoiner: Next:kEnableClickables");
nextOp = kDestroyProgressBar;
return true;
}
return false;
}
//============================================================================
void plNCAgeJoiner::Update () {
ExecNextOp();
}
/*****************************************************************************
*
* Exports
*
***/
//============================================================================
void NCAgeJoinerCreate (
plNCAgeJoiner ** pjoiner,
const NetCommAge & age,
FNCAgeJoinerCallback callback,
void * userState
) {
ASSERT(pjoiner);
ASSERT(callback);
plNCAgeJoiner * joiner;
*pjoiner = joiner = NEWZERO(plNCAgeJoiner)(
age,
callback,
userState
);
joiner->Start();
}
//============================================================================
bool NCAgeJoinerMsgReceive (
plNCAgeJoiner * joiner,
plMessage * msg
) {
ASSERT(joiner);
return joiner->MsgReceive(msg);
}
//============================================================================
void NCAgeJoinerUpdate (
plNCAgeJoiner * joiner
) {
ASSERT(joiner);
joiner->Update();
}

View File

@ -0,0 +1,85 @@
/*==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==*/
/*****************************************************************************
*
* $/Plasma20/Sources/Plasma/PubUtilLib/plNetClient/plNetCliAgeJoiner.h
*
***/
#ifndef PLASMA20_SOURCES_PLASMA_PUBUTILLIB_PLNETCLIENT_PLNETCLIAGEJOINER_H
#define PLASMA20_SOURCES_PLASMA_PUBUTILLIB_PLNETCLIENT_PLNETCLIAGEJOINER_H
#include "HeadSpin.h"
#include "../pnUtils/pnUtils.h"
#include "../plNetClientComm/plNetClientComm.h"
/*****************************************************************************
*
*
*
***/
class plMessage;
struct plNCAgeJoiner;
enum ENCAgeJoinerNotify {
kAgeJoinerComplete, // notify --> NCAgeJoinerCompleteNotify *, after callback, joiner is destroyed
kNumAgeJoinerNotifications
};
struct NCAgeJoinerCompleteNotify {
bool success;
const char * msg;
};
typedef void (* FNCAgeJoinerCallback)(
plNCAgeJoiner * joiner,
unsigned type, // ENCAgeJoinerNotify
void * notify,
void * userState
);
void NCAgeJoinerCreate (
plNCAgeJoiner ** joiner,
const NetCommAge & age,
FNCAgeJoinerCallback callback,
void * userState
);
bool NCAgeJoinerMsgReceive ( // returns true of message was processed
plNCAgeJoiner * joiner,
plMessage * msg
);
void NCAgeJoinerUpdate (
plNCAgeJoiner * joiner
);
#endif // PLASMA20_SOURCES_PLASMA_PUBUTILLIB_PLNETCLIENT_PLNETCLIAGEJOINER_H

View File

@ -0,0 +1,284 @@
/*==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==*/
/*****************************************************************************
*
* $/Plasma20/Sources/Plasma/PubUtilLib/plNetClient/plNetCliAgeLeaver.cpp
*
***/
#include "plNetCliAgeLeaver.h"
#include "plNetClientMgr.h"
#include "plNetLinkingMgr.h"
#include "../pnMessage/plTimeMsg.h"
#include "../plNetClientComm/plNetClientComm.h"
#include "../plNetGameLib/plNetGameLib.h"
#include "../plAgeLoader/plAgeLoader.h"
#include "../plAgeLoader/plBackgroundDownloader.h"
#include "../plAvatar/plAvatarMgr.h"
#include "../plVault/plVault.h"
#include "../plMessage/plLoadAgeMsg.h"
#include "../plMessage/plAgeLoadedMsg.h"
#include "../plMessage/plInputIfaceMgrMsg.h"
/*****************************************************************************
*
* Private
*
***/
struct plNCAgeLeaver {
enum NextOp {
kNoOp,
kDisableClickables,
kLinkOutFX,
kUnloadAge,
kNotifyAgeUnloaded,
};
NextOp nextOp;
bool quitting;
bool complete;
FNCAgeLeaverCallback callback;
void * userState;
plNCAgeLeaver (
bool quitting,
FNCAgeLeaverCallback callback,
void * userState
);
~plNCAgeLeaver ();
void Start ();
void Complete (bool success, const char msg[]);
bool MsgReceive (plMessage * msg);
void Update ();
void ExecNextOp ();
};
/*****************************************************************************
*
* plNCAgeLeaver
*
***/
//============================================================================
plNCAgeLeaver::plNCAgeLeaver (
bool quitting,
FNCAgeLeaverCallback callback,
void * userState
) : nextOp(kNoOp)
, quitting(quitting)
, complete(false)
, callback(callback)
, userState(userState)
{
}
//============================================================================
plNCAgeLeaver::~plNCAgeLeaver () {
}
//============================================================================
void plNCAgeLeaver::Start () {
if (plBackgroundDownloader::GetInstance())
plBackgroundDownloader::GetInstance()->Pause();
nextOp = kLinkOutFX;
}
//============================================================================
void plNCAgeLeaver::Complete (bool success, const char msg[]) {
if (!complete) {
complete = true;
NCAgeLeaveCompleteNotify notify;
notify.success = success;
notify.msg = msg;
callback(this, kAgeLeaveComplete, &notify, userState);
DEL(this);
}
}
//============================================================================
bool plNCAgeLeaver::MsgReceive (plMessage * msg) {
plNetClientMgr * nc = plNetClientMgr::GetInstance();
plAvatarMgr * am = plAvatarMgr::GetInstance();
plAgeLoader * al = plAgeLoader::GetInstance();
//========================================================================
// Done with link out effects
//========================================================================
if (plLinkOutUnloadMsg * linkOutUnloadMsg = plLinkOutUnloadMsg::ConvertNoRef(msg))
{
if (!linkOutUnloadMsg->HasBCastFlag(plMessage::kNetNonLocal)
&& linkOutUnloadMsg->GetPlayerID() == NetCommGetPlayer()->playerInt
) {
nextOp = kUnloadAge;
}
return true;
}
//========================================================================
// Age data unloaded
//========================================================================
if (plAgeLoadedMsg * ageLoadedMsg = plAgeLoadedMsg::ConvertNoRef(msg)) {
if (!ageLoadedMsg->fLoaded) {
nextOp = kNotifyAgeUnloaded;
return true;
}
return false;
}
return false;
}
//============================================================================
void plNCAgeLeaver::ExecNextOp () {
plNetClientMgr * nc = plNetClientMgr::GetInstance();
plAvatarMgr * am = plAvatarMgr::GetInstance();
plAgeLoader * al = plAgeLoader::GetInstance();
NextOp next = nextOp;
nextOp = kNoOp;
switch (next) {
//====================================================================
case kNoOp: {
}
break;
//====================================================================
case kDisableClickables: {
(TRACKED_NEW plInputIfaceMgrMsg(plInputIfaceMgrMsg::kDisableClickables))->Send();
nextOp = kLinkOutFX;
}
break;
//====================================================================
case kLinkOutFX: {
nc->StartLinkOutFX();
}
break;
//====================================================================
case kUnloadAge: {
NetCliGameDisconnect();
// Cull nodes that were part of this age vault (but not shared by the player's vault)
VaultCull(NetCommGetAge()->ageVaultId);
// remove the age device inbox mappings
VaultClearDeviceInboxMap();
// Tell our local player that he's unspawning (if that is indeed the case)
nc->IPlayerChangeAge(true /* exiting */, 0/* respawn */);
// disconnect age vault
// @@@ TODO: Unload age vault here
plAgeLoader::GetInstance()->UnloadAge(); // unload age
nc->ISendCameraReset(false/*leaving age*/); // reset camera
nc->IUnloadRemotePlayers(); // unload other players
if (NetCommNeedToLoadAvatar())
am->UnLoadLocalPlayer();
}
break;
//====================================================================
case kNotifyAgeUnloaded: {
// Set "Playing Game" bit to false
nc->SetFlagsBit(plNetClientMgr::kPlayingGame, false);
// Release AgeSDL object, if any
if (nc->fAgeSDLObjectKey)
nc->GetKey()->Release(nc->fAgeSDLObjectKey);
// All done leaving age
Complete(true, "Age unloaded");
}
break;
DEFAULT_FATAL(nextOp);
}
}
//============================================================================
void plNCAgeLeaver::Update () {
ExecNextOp();
}
/*****************************************************************************
*
* Exports
*
***/
//============================================================================
void NCAgeLeaverCreate (
plNCAgeLeaver ** pleaver,
bool quitting,
FNCAgeLeaverCallback callback,
void * userState
) {
ASSERT(pleaver);
ASSERT(callback);
plNCAgeLeaver * leaver;
*pleaver = leaver = NEWZERO(plNCAgeLeaver)(
quitting,
callback,
userState
);
leaver->Start();
}
//============================================================================
bool NCAgeLeaverMsgReceive (
plNCAgeLeaver * leaver,
plMessage * msg
) {
ASSERT(leaver);
return leaver->MsgReceive(msg);
}
//============================================================================
void NCAgeLeaverUpdate (
plNCAgeLeaver * leaver
) {
ASSERT(leaver);
leaver->Update();
}

View File

@ -0,0 +1,84 @@
/*==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==*/
/*****************************************************************************
*
* $/Plasma20/Sources/Plasma/PubUtilLib/plNetClient/plNetCliAgeLeaver.h
*
***/
#ifndef PLASMA20_SOURCES_PLASMA_PUBUTILLIB_PLNETCLIENT_PLNETCLIAGELEAVER_H
#define PLASMA20_SOURCES_PLASMA_PUBUTILLIB_PLNETCLIENT_PLNETCLIAGELEAVER_H
#include "HeadSpin.h"
#include "../pnUtils/pnUtils.h"
#include "../pnNetBase/pnNetBase.h"
/*****************************************************************************
*
*
*
***/
class plMessage;
struct plNCAgeLeaver;
enum ENCAgeLeaverNotify {
kAgeLeaveComplete, // notify --> NCAgeLeaveCompleteNotify *, after callback, leaver is destroyed
kNumAgeLeaverNotifications
};
struct NCAgeLeaveCompleteNotify {
bool success;
const char * msg;
};
typedef void (* FNCAgeLeaverCallback)(
plNCAgeLeaver * leaver,
unsigned type, // ENCAgeLeaverNotify
void * notify,
void * userState
);
void NCAgeLeaverCreate (
plNCAgeLeaver ** leaver,
bool quitting,
FNCAgeLeaverCallback callback,
void * userState
);
bool NCAgeLeaverMsgReceive ( // returns true of message was processed
plNCAgeLeaver * leaver,
plMessage * msg
);
void NCAgeLeaverUpdate (
plNCAgeLeaver * leaver
);
#endif // PLASMA20_SOURCES_PLASMA_PUBUTILLIB_PLNETCLIENT_PLNETCLIAGELEAVER_H

View File

@ -0,0 +1,68 @@
/*==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 "hsTimer.h"
#include "plNetClientMgr.h"
#include "plNetLinkingMgr.h"
#include "../plNetClientRecorder/plNetClientRecorder.h"
#include "../plNetMessage/plNetMessage.h"
#include "plgDispatch.h"
//
// Code for interfacing with plNetClientComm library, which in turn
// handles most client-server communication
//
int plNetClientCommMsgHandler::HandleMessage( plNetMessage* msg )
{
plNetClientMgr* nc=plNetClientMgr::GetInstance();
int ret = nc->fMsgHandler.ReceiveMsg(msg);
return ret;
}
int plNetClientMgr::IInitNetClientComm()
{
NetCommActivatePostInitErrorHandler();
ASSERT(!GetFlagsBit(kNetClientCommInited));
fNetClientComm.SetDefaultHandler(&fNetClientCommMsgHandler);
SetFlagsBit(kNetClientCommInited);
return hsOK;
}
//
// Cleanup netClientComm related stuff
//
int plNetClientMgr::IDeInitNetClientComm()
{
SetFlagsBit(kNetClientCommInited, false);
return hsOK;
}

View File

@ -0,0 +1,41 @@
/*==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==*/
#ifndef plNetClientCreatable_inc
#define plNetClientCreatable_inc
#include "../pnFactory/plCreator.h"
#include "plNetClientMgr.h"
REGISTER_CREATABLE( plNetClientMgr );
#include "../plNetTransport/plNetTransportMember.h"
REGISTER_CREATABLE( plNetTransportMember );
#include "plLinkEffectsMgr.h"
REGISTER_CREATABLE( plLinkEffectsMgr );
#endif // plNetClientCreatable_inc

View File

@ -0,0 +1,55 @@
/*==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 "hsResMgr.h"
#include "plNetClientGroup.h"
#include "../plResMgr/plKeyFinder.h"
#include "../plResMgr/plPageInfo.h"
//
// cache room desc string, from fID
//
void plNetClientGroups::ISetGroupDesc(plNetGroupId& grpId)
{
if (grpId.Room() == plNetGroup::kNetGroupUnknown.Room())
grpId.SetDesc("Unknown");
else
if (grpId.Room()== plNetGroup::kNetGroupLocalPlayer.Room())
grpId.SetDesc("LocalPlayer");
else
if (grpId.Room()== plNetGroup::kNetGroupRemotePlayer.Room())
grpId.SetDesc("RemotePlayer");
else
if (grpId.Room()== plNetGroup::kNetGroupLocalPhysicals.Room())
grpId.SetDesc("LocalPhysicals");
else
if (grpId.Room()== plNetGroup::kNetGroupRemotePhysicals.Room())
grpId.SetDesc("RemotePhysicals");
else
{
const plPageInfo* pageInfo=plKeyFinder::Instance().GetLocationInfo(grpId.Room());
grpId.SetDesc(pageInfo->GetPage());
}
}

View File

@ -0,0 +1,122 @@
/*==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==*/
#ifndef plNetClientGroup_h
#define plNetClientGroup_h
#include "hsStlUtils.h"
#include "../../NucleusLib/pnNetCommon/plNetGroup.h"
//
// represents a collection of net groups.
// abstracted so that we can switch to a different container structure if necessary
//
class plNetClientGroups
{
friend class plNetClientMgr;
private:
struct OwnedGroup
{
plNetGroupId fGroup;
bool fOwnIt;
bool operator<(const OwnedGroup& other) const { return other.fGroup<fGroup; }
bool operator==(const OwnedGroup& other) const { return (other.fGroup==fGroup && other.fOwnIt==fOwnIt); }
OwnedGroup(plNetGroupId g, bool o) : fGroup(g),fOwnIt(o) { fGroup.SetDesc(g.GetDesc()); }
OwnedGroup() : fOwnIt(false) {}
};
std::set<OwnedGroup> fGroups;
std::set<OwnedGroup>::iterator IFind(const plNetGroupId& grpId)
{
std::set<OwnedGroup>::iterator it=fGroups.begin();
for( ; it != fGroups.end(); it++)
if ((*it).fGroup==grpId)
break;
return it;
}
// const version
std::set<OwnedGroup>::const_iterator IFind(const plNetGroupId& grpId) const
{
std::set<OwnedGroup>::const_iterator it=fGroups.begin();
for( ; it != fGroups.end(); it++)
if ((*it).fGroup==grpId)
break;
return it;
}
void ISetGroupDesc(plNetGroupId& grpId);
public:
void Reset()
{
ClearGroups();
SetGroup(plNetGroup::kNetGroupLocalPlayer, true /*ownit*/);
SetGroup(plNetGroup::kNetGroupRemotePlayer, false /*ownit*/);
SetGroup(plNetGroup::kNetGroupLocalPhysicals, true /*ownit*/);
SetGroup(plNetGroup::kNetGroupRemotePhysicals, false /*ownit*/);
}
void SetGroup(plNetGroupId& grpId, bool ownIt)
{
std::set<OwnedGroup>::iterator it=IFind(grpId);
if (it != fGroups.end())
(*it).fOwnIt=ownIt;
else
{
ISetGroupDesc(grpId);
fGroups.insert(OwnedGroup(grpId, ownIt));
}
}
#if 0
void RemoveGroup(const plNetGroupId& grpId)
{
std::set<OwnedGroup>::iterator it=IFind(grpId);
if (it != fGroups.end())
fGroups.erase(it);
}
#else
void ClearGroups()
{
fGroups.clear();
}
#endif
int IsGroupLocal(const plNetGroupId& grpId) const
{
std::set<OwnedGroup>::const_iterator it=IFind(grpId);
if (it != fGroups.end())
{
if ((*it).fOwnIt)
return 1; // yes
return 0; // no
}
return -1; // don't know about it
}
};
#endif // plNetClientGroup_h

View File

@ -0,0 +1,398 @@
/*==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==*/
#ifndef PL_NET_CLIENT_inc
#define PL_NET_CLIENT_inc
#include "hsConfig.h"
#include "hsUtils.h"
#include "hsStlUtils.h"
#include "plNetClientGroup.h"
#include "plNetVoiceList.h"
#include "plNetClientMsgHandler.h"
#include "plNetClientStats.h" // STATS Counters
#include "../pnNetCommon/plNetApp.h"
#include "../plNetTransport/plNetTransport.h"
#include "../plEncryption/plChecksum.h"
#include "../plNetCommon/plNetServerSessionInfo.h"
#include "../plNetClientComm/plNetClientComm.h"
#include "../plUnifiedTime/plUnifiedTime.h"
#pragma warning(disable: 4284)
////////////////////////////////////////////////////////////////////
class plUoid;
class hsStream;
class plKey;
class plNetMessage;
class plSynchedObject;
struct DistSqInfo;
class plStatusLog;
class plOperationProgress;
class plIDataServer;
class plPlate;
class plLoadCloneMsg;
class plPlayerPageMsg;
class plNetClientRecorder;
class plVaultPlayerNode;
class plVaultAgeNode;
class plNetVoiceListMsg;
class plStateDataRecord;
class plCCRPetitionMsg;
class plNetMsgPagingRoom;
struct plNetClientCommMsgHandler : plNetClientComm::MsgHandler {
int HandleMessage( plNetMessage* msg );
};
class plNetClientMgr : public plNetClientApp
{
private:
typedef std::vector<plKey> plKeyVec;
public:
enum NetChannels
{
kNetChanDefault,
kNetChanVoice,
kNetChanListenListUpdate,
kNetChanDirectedMsg,
kNetNumChannels
};
enum DirectedSendFlags
{
kInterAgeMsg = 0x1
};
enum ListenListMode
{
kListenList_Distance = 0,
kListenList_Forced,
kListenList_End,
};
enum RefContext
{
kVaultImage = 0,
kAgeSDLHook = 1
};
struct PendingLoad
{
// must be set by user
plStateDataRecord* fSDRec; // the sdl data record
plUoid fUoid; // the object it's meant for
UInt32 fPlayerID; // the player that originally sent the state
// set by NetClient
plKey fKey; // the key of the object it's meant for
double fQueuedTime;
int fQueueTimeResets;
PendingLoad() : fSDRec(nil),fPlayerID(0),fKey(nil),fQueuedTime(0.0),fQueueTimeResets(0) {}
~PendingLoad();
};
private:
// plOperationProgress *fProgressBar;
plOperationProgress *fTaskProgBar;
typedef std::list<PendingLoad*> PendingLoadsList;
PendingLoadsList fPendingLoads;
// pending room page msgs
std::vector<plNetMsgPagingRoom*> fPendingPagingRoomMsgs;
plNetTransport fTransport;
// groups of objects in the game. Each group is mastered by a single client.
plNetClientGroups fNetGroups;
// cached char info
plKey fLocalPlayerKey;
plKeyVec fRemotePlayerKeys;
// plKeyVec fNPCKeys;
class plNetClientMgrMsg * fDisableMsg;
// ini info
std::string fIniAccountName;
std::string fIniAccountPass;
std::string fIniAuthServer;
UInt32 fIniPlayerID; // the player we want to load from vault.
std::string fSPDesiredPlayerName; // SP: the player we want to load from vault.
// server info
double fServerTimeOffset; // diff between our unified time and server's unified time
UInt32 fTimeSamples;
double fLastTimeUpdate;
UInt8 fJoinOrder; // returned by the server
// voice lists
int fListenListMode; // how we are generating our listen list
plNetListenList fListenList; // other players I'm listening to
plNetTalkList fTalkList; // other players I'm talking to
plNetClientMsgHandler fMsgHandler;
// recorder support
plNetClientRecorder* fMsgRecorder;
std::vector<plNetClientRecorder*> fMsgPlayers;
plKey fAgeSDLObjectKey;
UInt8 fExperimentalLevel;
plNetClientStats fNetClientStats;
UInt8 fPingServerType; // non-zero if we're pinging someone
float fOverrideAgeTimeOfDayPercent; // for console debugging
int fNumInitialSDLStates;
int fRequiredNumInitialSDLStates;
// simplification of object ownership...one player owns all non-physical objects in the world
// physical objects are owned by whoever touched them most recently (or the "owner" if nobody
// has touched it yet)
bool fIsOwner;
//
void ICheckPendingStateLoad(double secs);
int IDeduceLocallyOwned(const plUoid& loc) const;
bool IHandlePlayerPageMsg(plPlayerPageMsg *playerMsg); // ***
void IShowLists();
void IShowRooms();
void IShowAvatars();
void IShowRelevanceRegions();
int ISendDirtyState(double secs);
int ISendMembersListRequest();
int ISendRoomsReset();
void ISendCCRPetition(plCCRPetitionMsg* petMsg);
void ISendCameraReset(hsBool bEnteringAge);
hsBool IUpdateListenList(double secs);
void IHandleNetVoiceListMsg(plNetVoiceListMsg* msg);
hsBool IApplyNewListenList(std::vector<DistSqInfo>& newListenList, hsBool forceSynch);
int IPrepMsg(plNetMessage* msg);
void IPlayerChangeAge(hsBool exiting, Int32 spawnPt);
void IAddCloneRoom();
void IRemoveCloneRoom();
void IUnloadRemotePlayers();
plKey ILoadClone(plLoadCloneMsg *cloneMsg);
bool IFindModifier(plSynchedObject* obj, Int16 classIdx);
void IClearPendingLoads();
// recorder
bool IIsRecordableMsg(plNetMessage* msg);
void IPlaybackMsgs();
void IRequestAgeState();
void IDumpOSVersionInfo() const;
int ISendGameMessage(plMessage* msg);
void IDisableNet ();
public:
plNetClientMgr();
~plNetClientMgr();
CLASSNAME_REGISTER( plNetClientMgr );
GETINTERFACE_ANY( plNetClientMgr, plNetClientApp );
static plNetClientMgr* GetInstance() { return plNetClientMgr::ConvertNoRef(fInstance); }
void StartLinkOutFX();
void StartLinkInFX();
hsBool MsgReceive(plMessage* msg);
void Shutdown();
int Init();
void QueueDisableNet (bool showDlg, const char msg[]);
int SendMsg(plNetMessage* msg);
int Update(double secs);
int IsLocallyOwned(const plSynchedObject* obj) const; // returns yes/no/maybe
int IsLocallyOwned(const plUoid&) const; // for special cases, like sceneNodes. returns yes/no/maybe
plNetGroupId GetEffectiveNetGroup(const plSynchedObject*& obj) const;
plNetGroupId SelectNetGroup(plSynchedObject* objIn, plKey groupKey);
void SendLocalPlayerAvatarCustomizations();
void SendApplyAvatarCustomizationsMsg(const plKey msgReceiver, bool netPropagate=true, bool localPropagate=true);
// plLoggable
bool Log(const char* str) const;
// setters
void SetIniAuthServer(const char * value) { fIniAuthServer=value;}
void SetIniAccountName(const char * value) { fIniAccountName=value;}
void SetIniAccountPass(const char * value) { fIniAccountPass=value;}
void SetIniPlayerID(UInt32 value) { fIniPlayerID=value;}
void SetSPDesiredPlayerName( const char * value ) { fSPDesiredPlayerName=value;}
const char * GetSPDesiredPlayerName() const { return fSPDesiredPlayerName.c_str(); }
void SetLocalPlayerKey(plKey l, hsBool pageOut=false);
void SetNullSend(hsBool on); // turn null send on/off
void SetPingServer(UInt8 serverType) { fPingServerType = serverType; }
// getters
UInt32 GetPlayerID( void ) const;
const char * GetPlayerName( const plKey avKey=nil ) const;
const char * GetPlayerNameById (unsigned playerId) const;
unsigned GetPlayerIdByName(const char name[]) const;
UInt8 GetJoinOrder() const { return fJoinOrder; } // only valid at join time
plKey GetLocalPlayerKey() const { return fLocalPlayerKey; }
plSynchedObject* GetLocalPlayer(hsBool forceLoad=false) const;
hsBool IsPeerToPeer() const { return false; }
hsBool IsConnected() const { return true; }
void IncNumInitialSDLStates();
void ResetNumInitialSDLStates() { fNumInitialSDLStates=0; }
int GetNumInitialSDLStates() const { return fNumInitialSDLStates; }
void SetRequiredNumInitialSDLStates( int v ) { fRequiredNumInitialSDLStates=v; }
int GetRequiredNumInitialSDLStates() const { return fRequiredNumInitialSDLStates; }
// Linking progress
void StartTaskProgress( const char *msg, int numSteps );
void IncTaskProgress( const char *msg );
// avatar vault actions
int UploadPlayerVault(UInt32 vaultFlags);
// remote players
const std::vector<plKey>& RemotePlayerKeys() const { return fRemotePlayerKeys; }
plSynchedObject* GetRemotePlayer(int i) const;
void AddRemotePlayerKey(plKey p);
hsBool IsRemotePlayerKey(const plKey p, int* idx=nil);
bool IsAPlayerKey(const plKey pKey) { return (pKey==GetLocalPlayerKey() || IsRemotePlayerKey(pKey)); }
void SetConsoleOutput( bool b ) { SetFlagsBit(kConsoleOutput, b); }
bool GetConsoleOutput() const { return GetFlagsBit(kConsoleOutput); }
// Net groups
const plNetClientGroups* GetNetGroups() const { return &fNetGroups; }
plNetClientGroups* GetNetGroups() { return &fNetGroups; }
// Voice Lists
plNetListenList* GetListenList() { return &fListenList; }
plNetTalkList* GetTalkList() { return &fTalkList; }
void SetListenListMode (int i);
void SynchTalkList();
int GetListenListMode() { return fListenListMode; }
// network activity-generated events, passed to current task
bool CanSendMsg(plNetMessage * msg);
const plNetTransport& TransportMgr() const { return fTransport; }
plNetTransport& TransportMgr() { return fTransport; }
bool ObjectInLocalAge(const plSynchedObject* obj) const;
// time converters
plUnifiedTime GetServerTime() const;
const char* GetServerLogTimeAsString(std::string& ts) const;
double GetCurrentAgeElapsedSeconds() const;
float GetCurrentAgeTimeOfDayPercent() const;
bool RecordMsgs(const char* recType, const char* recName);
bool PlaybackMsgs(const char* recName);
void MakeCCRInvisible(plKey avKey, int level);
bool CCRVaultConnected() const { return GetFlagsBit(kCCRVaultConnected); }
UInt8 GetExperimentalLevel() const { return fExperimentalLevel; }
void AddPendingLoad(PendingLoad *pl);
const plKey& GetAgeSDLObjectKey() const { return fAgeSDLObjectKey; }
plUoid GetAgeSDLObjectUoid(const char* ageName) const;
plNetClientComm& GetNetClientComm() { return fNetClientComm; }
const char* plNetClientMgr::GetNextAgeFilename();
plNetClientStats& GetNetClientStats() { return fNetClientStats; }
void SetOverrideAgeTimeOfDayPercent(float f) { fOverrideAgeTimeOfDayPercent=f; }
void AddPendingPagingRoomMsg( plNetMsgPagingRoom * msg );
void MaybeSendPendingPagingRoomMsgs();
void SendPendingPagingRoomMsgs();
void ClearPendingPagingRoomMsgs();
void NotifyRcvdAllSDLStates();
plOperationProgress* GetTaskProgBar() { return fTaskProgBar; }
bool DebugMsgV(const char* fmt, va_list args) const;
bool ErrorMsgV(const char* fmt, va_list args) const;
bool WarningMsgV(const char* fmt, va_list args) const;
bool AppMsgV(const char* fmt, va_list args) const;
bool IsObjectOwner();
void SetObjectOwner(bool own);
void StoreSDLState(const plStateDataRecord* sdRec, const plUoid& uoid, UInt32 sendFlags, UInt32 writeOptions);
void UpdateServerTimeOffset(plNetMessage* msg);
void ResetServerTimeOffset();
private:
plNetClientComm fNetClientComm;
plNetClientCommMsgHandler fNetClientCommMsgHandler;
int IInitNetClientComm();
int IDeInitNetClientComm();
void INetClientCommOpStarted(UInt32 context);
void INetClientCommOpComplete(UInt32 context, int resultCode);
friend struct plNCAgeJoiner;
friend struct plNCAgeLeaver;
friend class plNetDniInfoSource;
friend class plNetTalkList;
friend class plNetClientMsgHandler;
friend struct plNetClientCommMsgHandler;
};
#define plCheckNetMgrResult_VoidReturn(r,s) if (hsFailed(r)) { ErrorMsg(s); hsAssert(false,s); return; }
// returns int
#define plCheckNetMgrResult_ValReturn(r,s) if (hsFailed(r)) { ErrorMsg(s); hsAssert(false,s); return r; }
// returns bool
#define plCheckNetMgrResult_BoolReturn(r,s) if (hsFailed(r)) { ErrorMsg(s); hsAssert(false,s); return false; }
#endif // PL_NET_CLIENT_inc

View File

@ -0,0 +1,171 @@
/*==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==*/
#if 1 // for debugging
#include "plCreatableIndex.h"
#include "../plModifier/plResponderModifier.h"
#include "../plSurface/plLayerAnimation.h"
#endif
#include "hsStream.h"
#include "plNetClientMgr.h"
#include "plgDispatch.h"
#include "hsResMgr.h"
#include "hsTimer.h"
#include "../plNetMessage/plNetMessage.h"
#include "../pnKeyedObject/plKey.h"
#include "../pnKeyedObject/plFixedKey.h"
#include "../pnKeyedObject/hsKeyedObject.h"
#include "../pnSceneObject/plSceneObject.h"
#include "../pnModifier/plModifier.h"
#include "../pnMessage/plNodeRefMsg.h"
#include "../pnMessage/plClientMsg.h"
#include "../pnMessage/plNodeChangeMsg.h"
#include "../pnMessage/plPlayerPageMsg.h"
#include "../plScene/plSceneNode.h"
#include "../plScene/plRelevanceMgr.h"
#include "../plNetTransport/plNetTransportMember.h"
#include "../plResMgr/plKeyFinder.h"
#include "../plAgeDescription/plAgeDescription.h"
#include "../plAvatar/plArmatureMod.h"
#include "../plAvatar/plAvatarMgr.h"
#include "../plSDL/plSDL.h"
/// TEMP HACK TO LOAD CONSOLE INIT FILES ON AGE LOAD
#include "../plMessage/plConsoleMsg.h"
#include "../plMessage/plLoadAvatarMsg.h"
#include "../plMessage/plAgeLoadedMsg.h"
#include "../plAgeLoader/plResPatcher.h"
#include "../plProgressMgr/plProgressMgr.h"
#include "../plResMgr/plRegistryHelpers.h"
#include "../plResMgr/plRegistryNode.h"
#include "../plResMgr/plResManager.h"
#include "process.h" // for getpid()
extern hsBool gDataServerLocal;
// Load Player object
// a clone will be created if cloneNum>0
// returns the playerKey if successful.
//
// Don't call this directly. Send a clone message to the NetClientManager instead.
// Load an object, optionally cloning if necessary.
plKey plNetClientMgr::ILoadClone(plLoadCloneMsg *pCloneMsg)
{
plKey cloneKey = pCloneMsg->GetCloneKey();
if(pCloneMsg->GetIsLoading())
{
if (cloneKey->ObjectIsLoaded())
{
char tmp[256];
DebugMsg("ILoadClone: object %s is already loaded, ignoring", cloneKey->GetUoid().StringIze(tmp));
return cloneKey;
}
// check if local or remote player before loading
plLoadAvatarMsg* loadAvMsg=plLoadAvatarMsg::ConvertNoRef(pCloneMsg);
if (loadAvMsg && loadAvMsg->GetIsPlayer())
{
bool originating = ( pCloneMsg->GetOriginatingPlayerID() == this->GetPlayerID() );
if (originating)
fLocalPlayerKey = cloneKey;
else
AddRemotePlayerKey(cloneKey);
}
plKey cloneNodeKey = hsgResMgr::ResMgr()->FindKey(kNetClientCloneRoom_KEY);
// Put the clone into the room, which also forces it to load.
plNodeRefMsg* nodeRefCloneMsg = TRACKED_NEW plNodeRefMsg(cloneNodeKey, plNodeRefMsg::kOnRequest, -1, plNodeRefMsg::kObject);
hsgResMgr::ResMgr()->AddViaNotify(cloneKey, nodeRefCloneMsg, plRefFlags::kActiveRef);
// Finally, pump the dispatch system so all the new refs get delivered. ?
plgDispatch::Dispatch()->MsgQueueProcess();
}
else // we're unloading a clone
{
if (!cloneKey->ObjectIsLoaded())
{
DebugMsg("ILoadClone: object %s is already unloaded, ignoring", cloneKey->GetName());
return cloneKey;
}
ICheckPendingStateLoad(hsTimer::GetSysSeconds());
plSynchEnabler p(false); // turn off dirty tracking while in this function
GetKey()->Release(cloneKey); // undo the active ref we took in ILoadClone
// send message to scene object to remove him from the room
plNodeChangeMsg* nodeChange = TRACKED_NEW plNodeChangeMsg(GetKey(), cloneKey, nil);
plgDispatch::MsgSend(nodeChange);
}
plKey requestorKey = pCloneMsg->GetRequestorKey();
// Readdress the message to the requestor and send it again
plKey myKey = GetKey();
pCloneMsg->SetBCastFlag(plMessage::kNetPropagate, false);
pCloneMsg->ClearReceivers();
pCloneMsg->AddReceiver(requestorKey);
pCloneMsg->Ref(); // each message send unrefs once
pCloneMsg->Send();
return cloneKey;
}
//
// Cause a player to respawn. This is typically called on the local player when he links to a new age.
// or for unspawn:
//
void plNetClientMgr::IPlayerChangeAge(hsBool exitAge, Int32 spawnPt)
{
plArmatureMod *avatar = plAvatarMgr::GetInstance()->GetLocalAvatar();
if (avatar)
{
plSynchEnabler ps(false); // disable state change tracking while we change ages
if (exitAge)
avatar->LeaveAge();
else
{
hsBool validSpawn = (spawnPt >= 0);
avatar->EnterAge(!validSpawn);
if (validSpawn)
avatar->SpawnAt(spawnPt, hsTimer::GetSysSeconds());
}
}
else if (fLocalPlayerKey)
{
ErrorMsg("Can't find avatarMod %s", fLocalPlayerKey->GetName());
}
}

View File

@ -0,0 +1,117 @@
/*==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 "plgDispatch.h"
#include "plNetClientMgr.h"
#include "../pnNetCommon/pnNetCommon.h"
#include "../pnMessage/plTimeMsg.h"
#include "../plNetClientRecorder/plNetClientRecorder.h"
//
// make a recording of current play
//
bool plNetClientMgr::RecordMsgs(const char* recType, const char* recName)
{
if (!fMsgRecorder)
{
if (stricmp(recType,"stream") == 0)
fMsgRecorder = TRACKED_NEW plNetClientStreamRecorder;
if (stricmp(recType,"stressstream") == 0)
fMsgRecorder = TRACKED_NEW plNetClientStressStreamRecorder;
if (stricmp(recType,"stats") == 0)
fMsgRecorder = TRACKED_NEW plNetClientStatsRecorder;
if (stricmp(recType,"streamandstats") == 0)
fMsgRecorder = TRACKED_NEW plNetClientStreamAndStatsRecorder(TRACKED_NEW plNetClientStreamRecorder(), TRACKED_NEW plNetClientStatsRecorder());
if (stricmp(recType,"stressstreamandstats") == 0)
fMsgRecorder = TRACKED_NEW plNetClientStreamAndStatsRecorder(TRACKED_NEW plNetClientStressStreamRecorder(), TRACKED_NEW plNetClientStatsRecorder());
if (!fMsgRecorder || !fMsgRecorder->BeginRecording(recName))
{
delete fMsgRecorder;
fMsgRecorder = nil;
return false;
}
return true;
}
return false;
}
//
// play a recording
//
bool plNetClientMgr::PlaybackMsgs(const char* recName)
{
hsLogEntry(DebugMsg("DEMO: Beginning Playback"));
plNetClientRecorder* player = TRACKED_NEW plNetClientStreamRecorder;
if (player->BeginPlayback(recName))
{
fMsgPlayers.push_back(player);
// plgDispatch::Dispatch()->RegisterForExactType(plEvalMsg::Index(), GetKey());
return true;
}
else
{
delete player;
return false;
}
}
//
//
//
void plNetClientMgr::IPlaybackMsgs()
{
for (int i = 0; i < fMsgPlayers.size(); i++)
{
plNetClientRecorder* recorder = fMsgPlayers[i];
if (recorder->IsQueueEmpty())
{
delete recorder;
fMsgPlayers.erase(fMsgPlayers.begin()+i);
i--;
if (fMsgPlayers.empty())
{
// plgDispatch::Dispatch()->UnRegisterForExactType(plEvalMsg::Index(), GetKey());
}
}
else
{
while (plNetMessage* msg = recorder->GetNextMessage())
{
hsLogEntry(DebugMsg("<Recorded Msg>"));
fMsgHandler.ReceiveMsg(msg);
}
}
}
}

View File

@ -0,0 +1,460 @@
/*==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 "hsTimer.h"
#include "hsResMgr.h"
#include "plNetClientMgr.h"
#include "plCreatableIndex.h"
#include "plNetObjectDebugger.h"
#include "plNetClientMsgScreener.h"
#include "../pnNetCommon/plSynchedObject.h"
#include "../pnNetCommon/plSDLTypes.h"
#include "../pnMessage/plCameraMsg.h"
#include "../plNetClientRecorder/plNetClientRecorder.h"
#include "../plMessage/plLoadCloneMsg.h"
#include "../plMessage/plLoadAvatarMsg.h"
#include "../plAvatar/plAvatarClothing.h"
#include "../plAvatar/plArmatureMod.h"
#include "../plAvatar/plAvatarMgr.h"
#include "../plNetMessage/plNetMessage.h"
#include "../plMessage/plCCRMsg.h"
#include "../plVault/plVault.h"
#include "../plContainer/plConfigInfo.h"
#include "../plDrawable/plMorphSequence.h"
#include "../plParticleSystem/plParticleSystem.h"
#include "../plParticleSystem/plParticleSDLMod.h"
#include "../plResMgr/plLocalization.h"
#include "../../FeatureLib/pfMessage/pfKIMsg.h" // TMP
#include "../plNetGameLib/plNetGameLib.h"
#include "../plSDL/plSDL.h"
//
// request members list from server
//
int plNetClientMgr::ISendMembersListRequest()
{
plNetMsgMembersListReq msg;
msg.SetNetProtocol(kNetProtocolCli2Game);
return SendMsg(&msg);
}
//
// reset paged in rooms list on server
//
int plNetClientMgr::ISendRoomsReset()
{
plNetMsgPagingRoom msg;
msg.SetPageFlags(plNetMsgPagingRoom::kResetList);
msg.SetNetProtocol(kNetProtocolCli2Game);
return SendMsg(&msg);
}
//
// Make sure all dirty objects save their state.
// Mark those objects as clean and clear the dirty list.
//
int plNetClientMgr::ISendDirtyState(double secs)
{
std::vector<plSynchedObject::StateDefn> carryOvers;
Int32 num=plSynchedObject::GetNumDirtyStates();
#if 0
if (num)
{
DebugMsg("%d dirty sdl state msgs queued, t=%f", num, secs);
}
#endif
Int32 i;
for(i=0;i<num;i++)
{
plSynchedObject::StateDefn* state=plSynchedObject::GetDirtyState(i);
plSynchedObject* obj=state->GetObject();
if (!obj)
continue; // could add to carryOvers
if (!(state->fSendFlags & plSynchedObject::kSkipLocalOwnershipCheck))
{
int localOwned=obj->IsLocallyOwned();
if (localOwned==plSynchedObject::kNo)
{
DebugMsg("Late rejection of queued SDL state, obj %s, sdl %s",
state->fObjKey->GetName(), state->fSDLName.c_str());
continue;
}
}
obj->CallDirtyNotifiers();
obj->SendSDLStateMsg(state->fSDLName.c_str(), state->fSendFlags);
}
plSynchedObject::ClearDirtyState(carryOvers);
return hsOK;
}
//
// Given a plasma petition msg, send a petition text node to the vault
// vault will detect and fwd to CCR system.
//
void plNetClientMgr::ISendCCRPetition(plCCRPetitionMsg* petMsg)
{
// petition msg info
UInt8 type = petMsg->GetType();
const char* title = petMsg->GetTitle();
const char* note = petMsg->GetNote();
std::string work = note;
std::replace( work.begin(), work.end(), '\n', '\t' );
note = work.c_str();
// stuff petition info fields into a config info object
plConfigInfo info;
info.AddValue( "Petition", "Type", type );
info.AddValue( "Petition", "Content", note );
info.AddValue( "Petition", "Title", title );
info.AddValue( "Petition", "Language", plLocalization::GetLanguageName( plLocalization::GetLanguage() ) );
info.AddValue( "Petition", "AcctName", NetCommGetAccount()->accountNameAnsi );
char buffy[20];
sprintf( buffy, "%lu", GetPlayerID() );
info.AddValue( "Petition", "PlayerID", buffy );
info.AddValue( "Petition", "PlayerName", GetPlayerName() );
// write config info formatted like an ini file to a buffer
hsRAMStream ram;
info.WriteTo( &plIniStreamConfigSource( &ram ) );
int size = ram.GetPosition();
ram.Rewind();
std::string buf;
buf.resize( size );
ram.CopyToMem( (void*)buf.data() );
wchar * wStr = StrDupToUnicode(buf.c_str());
NetCliAuthSendCCRPetition(wStr);
FREE(wStr);
}
//
// send a msg to reset the camera in a new age
//
void plNetClientMgr::ISendCameraReset(hsBool bEnteringAge)
{
plCameraMsg* pCamMsg = TRACKED_NEW plCameraMsg;
if (bEnteringAge)
pCamMsg->SetCmd(plCameraMsg::kResetOnEnter);
else
pCamMsg->SetCmd(plCameraMsg::kResetOnExit);
pCamMsg->SetBCastFlag(plMessage::kBCastByExactType, false);
plUoid U2(kVirtualCamera1_KEY);
plKey pCamKey = hsgResMgr::ResMgr()->FindKey(U2);
if (pCamKey)
pCamMsg->AddReceiver(pCamKey);
pCamMsg->Send();
}
//
// When we link in to a new age, we need to send our avatar state up to the gameserver
//
void plNetClientMgr::SendLocalPlayerAvatarCustomizations()
{
plSynchEnabler ps(true); // make sure synching is enabled, since this happens during load
const plArmatureMod * avMod = plAvatarMgr::GetInstance()->GetLocalAvatar();
hsAssert(avMod,"Failed to get local avatar armature modifier.");
avMod->GetClothingOutfit()->DirtySynchState(kSDLClothing, plSynchedObject::kBCastToClients | plSynchedObject::kForceFullSend);
plSceneObject* pObj = (const_cast<plArmatureMod*>(avMod))->GetFollowerParticleSystemSO();
if (pObj)
{
const plParticleSystem* sys = plParticleSystem::ConvertNoRef(pObj->GetModifierByType(plParticleSystem::Index()));
if (sys)
(const_cast<plParticleSystem*>(sys))->GetSDLMod()->SendState(plSynchedObject::kBCastToClients | plSynchedObject::kForceFullSend);
}
// may want to do this all the time, but for now stealthmode is the only extra avatar state we care about
// don't bcast this to other clients, the invis level is contained in the linkIn msg which will synch other clients
if (avMod->IsInStealthMode() && avMod->GetTarget(0))
avMod->GetTarget(0)->DirtySynchState(kSDLAvatar, plSynchedObject::kForceFullSend);
hsTArray<const plMorphSequence*> morphs;
plMorphSequence::FindMorphMods(avMod->GetTarget(0), morphs);
int i;
for (i = 0; i < morphs.GetCount(); i++)
if (morphs[i]->GetTarget(0))
morphs[i]->GetTarget(0)->DirtySynchState(kSDLMorphSequence, plSynchedObject::kBCastToClients);
}
//
// Called to send a plasma msg out over the network. Called by the dispatcher.
// return hsOK if ok
//
int plNetClientMgr::ISendGameMessage(plMessage* msg)
{
if (GetFlagsBit(kDisabled))
return hsOK;
static plNetClientMsgScreener screener; // make static so that there's only 1 log per session
if (!screener.AllowMessage(msg))
{
if (GetFlagsBit(kScreenMessages))
return hsOK; // filter out illegal messages
}
// TEMP
if (GetFlagsBit(kSilencePlayer))
{
pfKIMsg* kiMsg = pfKIMsg::ConvertNoRef(msg);
if (kiMsg && kiMsg->GetCommand()==pfKIMsg::kHACKChatMsg)
return hsOK;
}
plNetPlayerIDList* dstIDs = msg->GetNetReceivers();
#ifdef HS_DEBUGGING
if ( dstIDs )
{
DebugMsg( "Preparing to send %s to specific players.", msg->ClassName() );
}
#endif
// get sender object
plSynchedObject* synchedObj = msg->GetSender() ? plSynchedObject::ConvertNoRef(msg->GetSender()->ObjectIsLoaded()) : nil;
// if sender is flagged as localOnly, he shouldn't talk to the network
if (synchedObj && !synchedObj->IsNetSynched() )
return hsOK;
// choose appropriate type of net game msg wrapper
plNetMsgGameMessage* netMsgWrap=nil;
plLoadCloneMsg* loadClone = plLoadCloneMsg::ConvertNoRef(msg);
if (loadClone)
{
plLoadAvatarMsg* lam=plLoadAvatarMsg::ConvertNoRef(msg);
netMsgWrap = TRACKED_NEW plNetMsgLoadClone;
plNetMsgLoadClone* netLoadClone=plNetMsgLoadClone::ConvertNoRef(netMsgWrap);
netLoadClone->SetIsPlayer(lam && lam->GetIsPlayer());
netLoadClone->SetIsLoading(loadClone->GetIsLoading()!=0);
netLoadClone->ObjectInfo()->SetFromKey(loadClone->GetCloneKey());
}
else
if (dstIDs)
{
netMsgWrap = TRACKED_NEW plNetMsgGameMessageDirected;
int i;
for(i=0;i<dstIDs->size();i++)
{
UInt32 playerID = (*dstIDs)[i];
if (playerID == NetCommGetPlayer()->playerInt)
continue;
hsLogEntry( DebugMsg( "\tAdding receiver: %lu" , playerID ) );
((plNetMsgGameMessageDirected*)netMsgWrap)->Receivers()->AddReceiverPlayerID( playerID );
}
}
else
netMsgWrap = TRACKED_NEW plNetMsgGameMessage;
// check delivery timestamp
if (msg->GetTimeStamp()<=hsTimer::GetSysSeconds())
msg->SetTimeStamp(0);
else
netMsgWrap->GetDeliveryTime().SetFromGameTime(msg->GetTimeStamp(), hsTimer::GetSysSeconds());
// write message (and label) to ram stream
hsRAMStream stream;
hsgResMgr::ResMgr()->WriteCreatable(&stream, msg);
// put stream in net msg wrapper
netMsgWrap->StreamInfo()->CopyStream(&stream);
// hsLogEntry( DebugMsg(plDispatchLog::GetInstance()->MakeMsgInfoString(msg, "\tActionMsg:",0)) );
// check if this msg uses direct communication (sent to specific rcvrs)
// if so the server can filter it
hsBool bCast = msg->HasBCastFlag(plMessage::kBCastByExactType) ||
msg->HasBCastFlag(plMessage::kBCastByType);
hsBool directCom = msg->GetNumReceivers()>0;
if( directCom )
{
// It's direct if we have receivers AND any of them are in non-virtual locations
int i;
for( i = 0, directCom = false; i < msg->GetNumReceivers(); i++ )
{
if( !msg->GetReceiver( i )->GetUoid().GetLocation().IsVirtual() &&
!msg->GetReceiver( i )->GetUoid().GetLocation().IsReserved()
// && !IsBuiltIn
)
{
directCom = true;
break;
}
}
if (!directCom)
bCast = true;
}
if (!directCom && !bCast && !dstIDs)
WarningMsg("Msg %s has no rcvrs or bcast instructions?", msg->ClassName());
hsAssert(!(directCom && bCast), "msg has both rcvrs and bcast instructions, rcvrs ignored");
if (directCom && !bCast)
{
netMsgWrap->SetBit(plNetMessage::kHasGameMsgRcvrs); // for quick server filtering
netMsgWrap->StreamInfo()->SetCompressionType(plNetMessage::kCompressionDont);
}
//
// check for net propagated plasma msgs which should be filtered by relevance regions.
// currently only avatar control messages.
//
if (msg->HasBCastFlag(plMessage::kNetUseRelevanceRegions))
{
netMsgWrap->SetBit(plNetMessage::kUseRelevanceRegions);
}
//
// CCRs can route a plMessage to all online players.
//
hsBool ccrSendToAllPlayers = false;
#ifndef PLASMA_EXTERNAL_RELEASE
if ( AmCCR() )
{
ccrSendToAllPlayers = msg->HasBCastFlag( plMessage::kCCRSendToAllPlayers );
if ( ccrSendToAllPlayers )
netMsgWrap->SetBit( plNetMessage::kRouteToAllPlayers );
}
#endif
//
// check for inter-age routing. if set, online rcvrs not in current age will receive
// this msg courtesy of pls routing.
//
if ( !ccrSendToAllPlayers )
{
hsBool allowInterAge = msg->HasBCastFlag( plMessage::kNetAllowInterAge );
if ( allowInterAge )
netMsgWrap->SetBit(plNetMessage::kInterAgeRouting);
}
// check for reliable send
if (msg->HasBCastFlag(plMessage::kNetSendUnreliable) &&
!(synchedObj && (synchedObj->GetSynchFlags() & plSynchedObject::kSendReliably)) )
netMsgWrap->SetBit(plNetMessage::kNeedsReliableSend, 0); // clear reliable net send bit
#ifdef HS_DEBUGGING
Int16 type=*(Int16*)netMsgWrap->StreamInfo()->GetStreamBuf();
hsAssert(type>=0 && type<plCreatableIndex::plNumClassIndices, "garbage type out");
#endif
netMsgWrap->SetPlayerID(GetPlayerID());
netMsgWrap->SetNetProtocol(kNetProtocolCli2Game);
int ret = SendMsg(netMsgWrap);
if (plNetObjectDebugger::GetInstance()->IsDebugObject(msg->GetSender() ? msg->GetSender()->ObjectIsLoaded() : nil))
{
#if 0
hsLogEntry(plNetObjectDebugger::GetInstance()->LogMsg(
xtl::format("<SND> object:%s, rcvr %s %s",
msg->GetSender(),
msg->GetNumReceivers() ? msg->GetReceiver(0)->GetName() : "?",
netMsgWrap->AsStdString().c_str()).c_str()));
#endif
}
delete netMsgWrap;
return ret;
}
//
// Send a net msg. Delivers to transport mgr who sends p2p or to server
//
int plNetClientMgr::SendMsg(plNetMessage* msg)
{
if (GetFlagsBit(kDisabled))
return hsOK;
if (!CanSendMsg(msg))
return hsOK;
// If we're recording messages, set an identifying flag and echo the message back to ourselves
if (fMsgRecorder && fMsgRecorder->IsRecordableMsg(msg))
{
msg->SetBit(plNetMessage::kEchoBackToSender, true);
}
msg->SetTimeSent(plUnifiedTime::GetCurrentTime());
int channel = IPrepMsg(msg);
// hsLogEntry( DebugMsg( "<SND> %s %s", msg->ClassName(), msg->AsStdString().c_str()) );
int ret=fTransport.SendMsg(channel, msg);
// Debug
if (plNetMsgVoice::ConvertNoRef(msg))
SetFlagsBit(kSendingVoice);
if (plNetMsgGameMessage::ConvertNoRef(msg))
SetFlagsBit(kSendingActions);
plCheckNetMgrResult_ValReturn(ret,(char*)xtl::format("Failed to send %s, NC ret=%d",
msg->ClassName(), ret).c_str());
return ret;
}
void plNetClientMgr::StoreSDLState(const plStateDataRecord* sdRec, const plUoid& uoid,
UInt32 sendFlags, UInt32 writeOptions)
{
// send to server
plNetMsgSDLState* msg = sdRec->PrepNetMsg(0, writeOptions);
msg->SetNetProtocol(kNetProtocolCli2Game);
msg->ObjectInfo()->SetUoid(uoid);
if (sendFlags & plSynchedObject::kNewState)
msg->SetBit(plNetMessage::kNewSDLState);
if (sendFlags & plSynchedObject::kUseRelevanceRegions)
msg->SetBit(plNetMessage::kUseRelevanceRegions);
if (sendFlags & plSynchedObject::kDontPersistOnServer)
msg->SetPersistOnServer(false);
if (sendFlags & plSynchedObject::kIsAvatarState)
msg->SetIsAvatarState(true);
bool broadcast = (sendFlags & plSynchedObject::kBCastToClients) != 0;
if (broadcast && plNetClientApp::GetInstance())
{
msg->SetPlayerID(plNetClientApp::GetInstance()->GetPlayerID());
}
SendMsg(msg);
DEL(msg);
}

View File

@ -0,0 +1,375 @@
/*==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 "plNetClientMgr.h"
#include "plNetLinkingMgr.h"
#include "../pnSceneObject/plSceneObject.h"
#include "../plPipeline/plPlates.h"
#include "../plPipeline/plDebugText.h"
#include "../plNetTransport/plNetTransportMember.h"
#include "../plAvatar/plArmatureMod.h"
#include "../plScene/plRelevanceMgr.h"
//
// Code which displays stuff on the screen
//
//
// show lists of members, listenList, and talkList
//
void plNetClientMgr::IShowLists()
{
plNetLinkingMgr * lm = plNetLinkingMgr::GetInstance();
plDebugText &txt = plDebugText::Instance();
int y,x,i;
const int yOff=10, xOff=300, startY=70, startX=10;
char str[256];
// My player info
x=startX;
y=startY;
plSceneObject *player = plSceneObject::ConvertNoRef(GetLocalPlayer());
hsPoint3 pos = (player ? player->GetLocalToWorld() * hsPoint3(0, 0, 0) : hsPoint3(0, 0, 0));
sprintf(str, "%s%s PlyrName=%s PlyrID=%d AcctID=%d P2P=%d Join#=%d Peers=%d %.1f,%.1f,%.1f",
GetFlagsBit(kSendingVoice) ? "V" : " ",
GetFlagsBit(kSendingActions) ? "A" : " ",
GetPlayerName(), GetPlayerID(), 0,
IsPeerToPeer(), GetJoinOrder(), 0,
pos.fX, pos.fY, pos.fZ);
txt.DrawString(x,y,str,255,255,255,255);
SetFlagsBit(kSendingVoice, 0);
SetFlagsBit(kSendingActions, 0);
y+=yOff;
sprintf(str, " Server=%s ILIAS=%d", "foo",
IsLoadingInitialAgeState());
txt.DrawString(x,y,str,255,255,255,255);
// MEMBERS
y+=yOff;
int baseY=y;
txt.DrawString(x,y," Members",255,255,255,255,plDebugText::kStyleBold);
y+=yOff;
plNetTransportMember** members=nil;
fTransport.GetMemberListDistSorted(members);
for(i=0;i<fTransport.GetNumMembers();i++)
{
plNetTransportMember* mbr=members[i];
hsAssert(mbr, "ShowLists: nil member?");
if (mbr->IsServer())
continue;
player = (mbr->GetAvatarKey() ? plSceneObject::ConvertNoRef(mbr->GetAvatarKey()->ObjectIsLoaded()) : nil);
sprintf(str, "%s%s %s p2p=%d dist=%.1f",
mbr->GetTransportFlags() & plNetTransportMember::kSendingVoice ? "V" : " ",
mbr->GetTransportFlags() & plNetTransportMember::kSendingActions ? "A" : " ",
mbr->AsStdString().c_str(),
mbr->IsPeerToPeer(),
mbr->GetDistSq() != hsScalarMax ? hsSquareRoot(mbr->GetDistSq()) :-1.f);
txt.DrawString(x,y,str);
y+=yOff;
mbr->SetTransportFlags(mbr->GetTransportFlags() &
~(plNetTransportMember::kSendingVoice|plNetTransportMember::kSendingActions));
}
delete [] members;
// LISTENLIST
x+=xOff;
y=baseY;
txt.DrawString(x,y,"ListenList",255,255,255,255,plDebugText::kStyleBold);
y+=yOff;
for(i=0;i<GetListenList()->GetNumMembers();i++)
{
sprintf(str, "name=%s", GetListenList()->GetMember(i)->AsStdString().c_str());
txt.DrawString(x,y,str);
y+=yOff;
}
// TALKLIST
x+=xOff;
y=baseY;
txt.DrawString(x,y,"TalkList",255,255,255,255,plDebugText::kStyleBold);
y+=yOff;
for(i=0;i<GetTalkList()->GetNumMembers();i++)
{
sprintf(str, "name=%s", GetTalkList()->GetMember(i)->AsStdString().c_str());
txt.DrawString(x,y,str);
y+=yOff;
}
}
//
// show lists of members, listenList, and talkList
//
void plNetClientMgr::IShowRooms()
{
plDebugText &txt = plDebugText::Instance();
int y,x;
const int yOff=10, xOff=300, startY=70, startX=10;
char str[256];
// OWNEDLIST
x=startX;
y=startY;
txt.DrawString(x,y,"RoomsOwned",255,255,255,255,plDebugText::kStyleBold);
y+=yOff;
std::set<plNetClientGroups::OwnedGroup>::iterator it=GetNetGroups()->fGroups.begin();
for(;it != GetNetGroups()->fGroups.end(); it++)
{
if ((*it).fOwnIt)
{
sprintf(str, "%s", (*it).fGroup.GetDesc());
txt.DrawString(x,y,str);
y+=yOff;
}
}
// NOTOWNEDLIST
x+=xOff;
y=startY;
txt.DrawString(x,y,"RoomsNotOwned",255,255,255,255,plDebugText::kStyleBold);
y+=yOff;
it=GetNetGroups()->fGroups.begin();
for(;it != GetNetGroups()->fGroups.end(); it++)
{
if (!(*it).fOwnIt)
{
sprintf(str, "%s", (*it).fGroup.GetDesc());
txt.DrawString(x,y,str);
y+=yOff;
}
}
}
UInt32 IPrintRelRegion(const hsBitVector& region, int x, int y, const hsBitVector* cmpRegion)
{
char buf[256];
int maxBits = 255;
UInt32 num = plRelevanceMgr::Instance()->GetNumRegions();
if (num > maxBits)
num = maxBits;
bool orTrue = false;
int i;
for (i = 0; i < num; i++)
{
buf[i] = (region.IsBitSet(i) ? '1' : '0');
if (cmpRegion && cmpRegion->IsBitSet(i) && region.IsBitSet(i))
orTrue = true;
}
buf[i] = '\0';
plDebugText& txt = plDebugText::Instance() ;
if (orTrue)
txt.DrawString(x, y, buf, 0, 255, 0);
else
txt.DrawString(x, y, buf);
return txt.CalcStringWidth(buf);
}
void plNetClientMgr::IShowRelevanceRegions()
{
plDebugText& txt = plDebugText::Instance();
const int yOff = 12, xOff = 20, startY=70, startX=10;
int x = startX, y = startY;
const char* title = "Name / In / Care";
txt.DrawString(x, y - yOff, title, 255, 255, 255, 255, plDebugText::kStyleBold);
plNetTransportMember** members = nil;
fTransport.GetMemberListDistSorted(members);
//
// Print out the player names in the first column
//
UInt32 maxPlayerName = 0;
txt.DrawString(x, y, GetPlayerName());
maxPlayerName = hsMaximum(maxPlayerName, txt.CalcStringWidth(GetPlayerName()));
y += yOff;
int i;
for (i = 0; i < fTransport.GetNumMembers(); i++)
{
plNetTransportMember* mbr = members[i];
hsAssert(mbr, "ShowLists: nil member?");
if (mbr->IsServer())
continue;
const char* name = mbr->GetPlayerName();
txt.DrawString(x, y, name);
maxPlayerName = hsMaximum(maxPlayerName, txt.CalcStringWidth(name));
y += yOff;
}
x = startX + maxPlayerName + xOff;
y = startY;
//
// Print out the regions
//
const hsBitVector* ourCare = nil;
const hsBitVector* ourIn = nil;
plSceneObject* player = plSceneObject::ConvertNoRef(GetLocalPlayer());
if (player)
{
const plArmatureMod *avMod = plArmatureMod::ConvertNoRef(player->GetModifierByType(plArmatureMod::Index()));
if (avMod)
{
ourIn = &avMod->GetRelRegionImIn();
UInt32 width = IPrintRelRegion(*ourIn, x, y, nil);
ourCare = &avMod->GetRelRegionCareAbout();
IPrintRelRegion(*ourCare, x + width + xOff, y, nil);
y += yOff;
}
}
for (i = 0; i < fTransport.GetNumMembers(); i++)
{
plNetTransportMember* mbr = members[i];
if (mbr->IsServer())
continue;
player = (mbr->GetAvatarKey() ? plSceneObject::ConvertNoRef(mbr->GetAvatarKey()->ObjectIsLoaded()) : nil);
if (player)
{
const plArmatureMod* avMod = plArmatureMod::ConvertNoRef(player->GetModifierByType(plArmatureMod::Index()));
if (avMod)
{
const hsBitVector& in = avMod->GetRelRegionImIn();
UInt32 width = IPrintRelRegion(in, x, y, ourCare);
const hsBitVector& care = avMod->GetRelRegionCareAbout();
IPrintRelRegion(care, x + width + xOff, y, ourIn);
y += yOff;
}
}
}
delete [] members;
}
void plNetClientMgr::IShowAvatars()
{
plDebugText &txt = plDebugText::Instance();
txt.SetFont( "Courier New", 6 );
int y,x,i;
const int yOff=10, xOff=285, startY=100, startX=10;
char str[256];
// Me
x=startX;
y=startY-yOff*3;
plSceneObject *player = plSceneObject::ConvertNoRef(GetLocalPlayer());
hsPoint3 pos = (player ? player->GetLocalToWorld() * hsPoint3(0, 0, 0) : hsPoint3(0, 0, 0));
hsVector3 ori = (player ? player->GetLocalToWorld() * hsVector3(0, -1, 0) : hsVector3(0, 0, 0));
sprintf(str, "%s: pos(%.2f, %.2f, %.2f) ori(%.2f, %.2f, %.2f)",
GetPlayerName(), pos.fX, pos.fY, pos.fZ, ori.fX, ori.fY, ori.fZ);
txt.DrawString(x,y,str,255,255,255,255);
if (player)
{
const plArmatureMod *avMod = plArmatureMod::ConvertNoRef(player->GetModifierByType(plArmatureMod::Index()));
if (avMod)
{
plArmatureMod* pNonConstArm = const_cast<plArmatureMod*>(avMod);
plSceneObject* pObj = pNonConstArm->GetFollowerParticleSystemSO();
if (pObj)
{
y+=yOff;
y+=yOff;
hsPoint3 pos = (pObj ? pObj->GetLocalToWorld() * hsPoint3(0, 0, 0) : hsPoint3(0, 0, 0));
hsVector3 ori = (pObj ? pObj->GetLocalToWorld() * hsVector3(0, -1, 0) : hsVector3(0, 0, 0));
sprintf(str, "%s: pos(%.2f, %.2f, %.2f) ori(%.2f, %.2f, %.2f)",
pObj->GetKeyName(), pos.fX, pos.fY, pos.fZ, ori.fX, ori.fY, ori.fZ);
txt.DrawString(x,y,str,255,255,255,255);
}
}
}
// Others
y=startY;
x=startX;
plNetTransportMember** members=nil;
fTransport.GetMemberListDistSorted(members);
for(i=0;i<fTransport.GetNumMembers();i++)
{
plNetTransportMember* mbr=members[i];
hsAssert(mbr, "ShowLists: nil member?");
if (mbr->IsServer())
continue;
player = (mbr->GetAvatarKey() ? plSceneObject::ConvertNoRef(mbr->GetAvatarKey()->ObjectIsLoaded()) : nil);
pos = (player ? player->GetLocalToWorld() * hsPoint3(0, 0, 0) : hsPoint3(0, 0, 0));
ori = (player ? player->GetLocalToWorld() * hsVector3(0, -1, 0) : hsVector3(0, 0, 0));
sprintf(str, "%s: pos(%.2f, %.2f, %.2f) ori(%.2f, %.2f, %.2f)",
mbr->AsStdString().c_str(), pos.fX, pos.fY, pos.fZ, ori.fX, ori.fY, ori.fZ);
txt.DrawString(x,y,str);
y+=yOff;
if (player)
{
const plArmatureMod *avMod = plArmatureMod::ConvertNoRef(player->GetModifierByType(plArmatureMod::Index()));
if (avMod)
{
plArmatureMod* pNonConstArm = const_cast<plArmatureMod*>(avMod);
plSceneObject* pObj = pNonConstArm->GetFollowerParticleSystemSO();
if (pObj)
{
y+=yOff;
y+=yOff;
hsPoint3 pos = (pObj ? pObj->GetLocalToWorld() * hsPoint3(0, 0, 0) : hsPoint3(0, 0, 0));
hsVector3 ori = (pObj ? pObj->GetLocalToWorld() * hsVector3(0, -1, 0) : hsVector3(0, 0, 0));
sprintf(str, "%s: pos(%.2f, %.2f, %.2f) ori(%.2f, %.2f, %.2f)",
pObj->GetKeyName(), pos.fX, pos.fY, pos.fZ, ori.fX, ori.fY, ori.fZ);
txt.DrawString(x,y,str,255,255,255,255);
}
}
}
}
delete [] members;
txt.SetFont( "Courier New", 8 );
}

View File

@ -0,0 +1,25 @@
/*==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==*/

View File

@ -0,0 +1,25 @@
/*==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==*/

View File

@ -0,0 +1,394 @@
/*==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 <algorithm>
#include "hsMatrix44.h"
#include "hsGeometry3.h"
#include "plNetClientMgr.h"
#include "../plNetMessage/plNetMessage.h"
#include "../pnNetCommon/plNetServers.h"
#include "../pnSceneObject/plSceneObject.h"
#include "../pnSceneObject/plCoordinateInterface.h"
#include "../pnKeyedObject/plKey.h"
#include "../plNetTransport/plNetTransportMember.h"
#include "../plMessage/plMemberUpdateMsg.h"
#include "../plMessage/plNetVoiceListMsg.h"
#include "../plStatusLog/plStatusLog.h"
#include "../plVault/plVault.h"
#define SAME_TALK_AND_LISTEN
struct DistSqInfo
{
plNetTransportMember* fMbr;
float fDistSq;
DistSqInfo(plNetTransportMember* m, float d) : fMbr(m),fDistSq(d) {}
};
bool lessComp(DistSqInfo a, DistSqInfo b)
{
return (a.fDistSq<b.fDistSq);
}
//
// see if new listen list differs from current one
// apply new list if there's a difference
// send listenList update msgs to old and new members in the list
// return true if the new list is different
//
hsBool plNetClientMgr::IApplyNewListenList(std::vector<DistSqInfo>& newListenList, hsBool forceSynch)
{
hsBool changed=false;
int i;
// see if new listen list differs from current one
if (forceSynch || newListenList.size() != GetListenList()->GetNumMembers())
changed=true;
else
{
for(i=0;i<newListenList.size(); i++)
{
if (GetListenList()->FindMember(newListenList[i].fMbr)==-1)
{
changed=true;
break;
}
}
}
// set as new listen list
if (changed)
{
DebugMsg("ListenList changed, forceSynch=%d\n", forceSynch);
plNetMsgListenListUpdate llu;
llu.SetPlayerID(GetPlayerID());
llu.SetNetProtocol(kNetProtocolCli2Game);
//
// for each client in the old list, if not in the new list, send a ListenList remove msg
//
llu.Receivers()->Clear();
llu.SetAdding(false);
for(i=0;i<GetListenList()->GetNumMembers(); i++)
{
hsBool found=false;
if (!forceSynch)
{
int j;
for(j=0;j<newListenList.size(); j++)
{
if (newListenList[j].fMbr==GetListenList()->GetMember(i))
{
found=true;
break;
}
}
}
if (found==false)
{
llu.Receivers()->AddReceiverPlayerID(GetListenList()->GetMember(i)->GetPlayerID());
}
}
#ifndef SAME_TALK_AND_LISTEN
if (llu.Receivers()->GetNumReceivers())
{
// DEBUGGING
int i;
for(i=0;i<llu.Receivers()->GetNumReceivers(); i++)
{
int idx=fTransport.FindMember(llu.Receivers()->GetReceiverClientNum(i));
plNetTransportMember* mbr=fTransport.GetMember(idx);
DebugMsg("<SEND %s> ListenListUpdate msg, adding=%d\n",
mbr->AsStdString().c_str(), llu.GetAdding());
}
SendMsg(&llu);
}
#endif
//
// for each client in the new list, [if not in the old list,] send a ListenList add msg
//
llu.Receivers()->Clear();
llu.SetAdding(true);
for(i=0;i<newListenList.size(); i++)
{
if (forceSynch || GetListenList()->FindMember(newListenList[i].fMbr)==-1)
{
// if not in the old list, send a ListenList add msg
llu.Receivers()->AddReceiverPlayerID(newListenList[i].fMbr->GetPlayerID());
}
}
#ifndef SAME_TALK_AND_LISTEN
if (llu.Receivers()->GetNumReceivers())
{
// DEBUGGING
int i;
for(i=0;i<llu.Receivers()->GetNumReceivers(); i++)
{
int cNum=llu.Receivers()->GetReceiverClientNum(i);
int idx=fTransport.FindMember(cNum);
plNetTransportMember* mbr=fTransport.GetMember(idx);
DebugMsg("<SEND %s> ListenListUpdate msg, adding=%d, cNum=%d\n",
mbr->AsStdString().c_str(), llu.GetAdding(), cNum);
}
SendMsg(&llu);
}
#endif
//
// set as new listen list
//
GetListenList()->Clear();
#ifdef HS_DEBUGGING
DebugMsg("New ListenList, size=%d\n", newListenList.size());
#endif
for(i=0;i<newListenList.size(); i++)
{
GetListenList()->AddMember(newListenList[i].fMbr);
#ifdef HS_DEBUGGING
DebugMsg("\tLL Member %d, name=%s, cNum=%d, dist=%f\n",
i, newListenList[i].fMbr->AsStdString().c_str(),
newListenList[i].fMbr->GetPlayerID(), newListenList[i].fDistSq);
#endif
}
}
return changed;
}
//
// Periodically updates the list of what remote players I'm listening to.
// Used to filter voice streams.
// Returns true if the listenList was changed.
// Note: Updates distSq to each member. Other things rely on this so we must do it even if p2p is disabled.
//
hsBool plNetClientMgr::IUpdateListenList(double secs)
{
if (GetFlagsBit(kDisabled))
return false;
if (!fLocalPlayerKey || !fLocalPlayerKey->ObjectIsLoaded())
return false;
hsBool changed = false;
if (secs - GetListenList()->GetLastUpdateTime()>plNetListenList::kUpdateInterval)
{
GetListenList()->SetLastUpdateTime(secs);
std::vector<DistSqInfo> newListenList;
switch (fListenListMode)
{
case kListenList_Forced:
{
#ifdef SAME_TALK_AND_LISTEN
SynchTalkList();
#endif
}
return true;
case kListenList_Distance:
{
// Finds the 3 closest players to our local player
// Search is unoptimized for now...
// compute our players pos
plSceneObject* locPlayer = plSceneObject::ConvertNoRef(fLocalPlayerKey->ObjectIsLoaded());
hsAssert(locPlayer, "local player is not a sceneObject?");
hsAssert(locPlayer->GetCoordinateInterface(), "locPlayer has no coordInterface");
hsMatrix44 l2w=locPlayer->GetCoordinateInterface()->GetLocalToWorld();
hsPoint3 locPlayerPos=l2w.GetTranslate();
int i;
for(i=0;i<fTransport.GetNumMembers();i++)
{
fTransport.GetMember(i)->SetDistSq(hsScalarMax);
if (fTransport.GetMember(i)->IsServer())
continue;
if(VaultAmIgnoringPlayer(fTransport.GetMember(i)->GetPlayerID()))
{
continue;
}
plKey k=fTransport.GetMember(i)->GetAvatarKey();
#if 0
if (!k)
{
DebugMsg("UpdateListenList: Nil avatar key on member %s\n",
fTransport.GetMember(i)->AsStdString().c_str());
}
#endif
plSceneObject* obj=plSceneObject::ConvertNoRef(k ? k->ObjectIsLoaded() : nil);
if (obj && obj->GetCoordinateInterface())
{
#if 1
// compute distSq to me
l2w=obj->GetCoordinateInterface()->GetLocalToWorld();
hsPoint3 pos=l2w.GetTranslate();
float distSq = hsVector3(&pos, &locPlayerPos).MagnitudeSquared();
fTransport.GetMember(i)->SetDistSq(distSq);
// I can't listen to players that are more than 50 ft away
if (distSq>plNetListenList::kMaxListenDistSq)
continue;
// if we are p2p and member isn't, skip them.
if ( IsPeerToPeer() && !fTransport.GetMember(i)->IsPeerToPeer() )
continue;
// otherwise, we aren't p2p so just update the listen list
// normally so it will update in the gui as distance changes.
#else
float distSq=1;
#endif
// if we have < 3 elements in the list, grow the list, or,
// if obj is closer than item 3, add it to the list.
// keep the list (3) elements sorted.
if (plNetListenList::kMaxListenListSize==-1 ||
newListenList.size()<plNetListenList::kMaxListenListSize ||
(distSq<newListenList[plNetListenList::kMaxListenListSize-1].fDistSq) )
{
DistSqInfo dsi(fTransport.GetMember(i), distSq);
if (plNetListenList::kMaxListenListSize==-1 ||
newListenList.size()<plNetListenList::kMaxListenListSize)
{
newListenList.push_back(dsi);
}
else
{
newListenList[plNetListenList::kMaxListenListSize-1]=dsi;
}
if (plNetListenList::kMaxListenListSize!=-1) // don't need to sort every time in this case
{
std::sort(newListenList.begin(), newListenList.end(), lessComp);
}
}
}
if (plNetListenList::kMaxListenListSize==-1 && newListenList.size())
{
std::sort(newListenList.begin(), newListenList.end(), lessComp);
}
}
}
break;
default:
break;
}
hsAssert(plNetListenList::kMaxListenListSize==-1 || newListenList.size()<=plNetListenList::kMaxListenListSize,
"illegal new listenlist size");
changed = IApplyNewListenList(newListenList,
#ifdef SAME_TALK_AND_LISTEN
false
#else
GetListenList()->CheckForceSynch()
#endif
);
}
// update talkList based on listenList
if (changed)
{
#ifdef SAME_TALK_AND_LISTEN
SynchTalkList();
#endif
// notify KI, member distances have been updated
plMemberUpdateMsg* mu = TRACKED_NEW plMemberUpdateMsg;
mu->Send();
}
return changed;
}
void plNetClientMgr::SynchTalkList()
{
GetTalkList()->Clear();
int i;
for(i=0;i<GetListenList()->GetNumMembers(); i++)
GetTalkList()->AddMember(GetListenList()->GetMember(i));
}
void plNetClientMgr::SetListenListMode(int i)
{
// set new mode, clear list and force update
fListenListMode = i;
GetListenList()->Clear();
GetListenList()->SetLastUpdateTime(0.f);
}
void plNetClientMgr::IHandleNetVoiceListMsg(plNetVoiceListMsg* msg)
{
if (msg->GetCmd() == plNetVoiceListMsg::kForcedListenerMode)
{
// first make sure this message applies to us:
int i;
bool included = false;
for (i = 0; i < msg->GetClientList()->Count(); i++)
{
if (msg->GetClientList()->AcquireArray()[i] == NetCommGetPlayer()->playerInt)
{
included = true;
break;
}
}
if (!included)
return;
SetListenListMode(kListenList_Forced);
// add in the members we receive from python
for (i = 0; i < msg->GetClientList()->Count(); i++)
{
plNetTransportMember **members = nil;
plNetClientMgr::GetInstance()->TransportMgr().GetMemberListDistSorted( members );
if( members != nil)
{
for(int j= 0; j < plNetClientMgr::GetInstance()->TransportMgr().GetNumMembers(); j++ )
{
plNetTransportMember *mbr = members[ j ];
if( mbr != nil && mbr->GetAvatarKey() != nil && mbr->GetPlayerID() == msg->GetClientList()->AcquireArray()[i])
{
plNetClientMgr::GetInstance()->GetListenList()->AddMember(mbr);
}
}
}
delete [] members;
}
}
else
if (msg->GetCmd() == plNetVoiceListMsg::kDistanceMode)
{
// again, see that it is us that we care about:
if (msg->GetRemovedKey() == GetLocalPlayerKey())
SetListenListMode(kListenList_Distance);
}
}

View File

@ -0,0 +1,593 @@
/*==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 "hsTimer.h"
#include "plNetClientMgr.h"
#include "plNetClientMsgHandler.h"
#include "hsResMgr.h"
#include "plCreatableIndex.h"
#include "plgDispatch.h"
#include "plNetLinkingMgr.h"
#include "plCCRMgrBase.h"
#include "../pnKeyedObject/plKey.h"
#include "../pnKeyedObject/plFixedKey.h"
#include "../pnKeyedObject/hsKeyedObject.h"
#include "../pnSceneObject/plSceneObject.h"
#include "../pnSceneObject/plObjInterface.h"
#include "../pnSceneObject/plCoordinateInterface.h"
#include "../pnMessage/plObjRefMsg.h"
#include "../pnMessage/plNodeRefMsg.h"
#include "../pnMessage/plClientMsg.h"
//#include "../pnMessage/plWarpMsg.h"
#include "../pnMessage/plTimeMsg.h"
#include "../pnMessage/plCameraMsg.h"
#include "../pnMessage/plPlayerPageMsg.h"
#include "../pnFactory/plCreator.h"
#include "../pnSceneObject/plAudioInterface.h"
#include "../pnNetCommon/plSDLTypes.h"
#include "../plAudible/plWinAudible.h"
#include "../plAvatar/plAvatarMgr.h"
#include "../plNetTransport/plNetTransportMember.h"
#include "../plMessage/plMemberUpdateMsg.h"
#include "../plMessage/plNetOwnershipMsg.h"
#include "../plMessage/plCCRMsg.h"
#include "../plVault/plVault.h"
#include "../plSDL/plSDL.h"
#include "../plNetCommon/plNetCommonConstants.h"
#include "../plNetMessage/plNetMessage.h"
#include "../plNetMessage/plNetCommonMessage.h"
#include "../../FeatureLib/pfMessage/pfKIMsg.h" // Should be moved to PubUtil level
////////////////////////////////////////////////////////////////////////
plNetClientMsgHandler::plNetClientMsgHandler(plNetClientMgr * mgr)
{
SetNetApp(mgr);
}
plNetClientMsgHandler::~plNetClientMsgHandler()
{
}
plNetClientMgr * plNetClientMsgHandler::IGetNetClientMgr()
{
return plNetClientMgr::ConvertNoRef(GetNetApp());
}
int plNetClientMsgHandler::PeekMsg(plNetMessage * netMsg)
{
plNetClientMgr * nc = IGetNetClientMgr();
int cnt = -1;
if (netMsg->GetNetCoreMsg()) // && !netMsg->Peeked()) // not needed
{
cnt = netMsg->PeekBuffer(netMsg->GetNetCoreMsg()->GetData(), netMsg->GetNetCoreMsg()->GetLen());
hsAssert(cnt,"0 length message");
}
return cnt;
}
void plNetClientMsgHandler::IFillInTransportMember(const plNetMsgMemberInfoHelper* mbi, plNetTransportMember* mbr)
{
const plNetClientMgr* nc=IGetNetClientMgr();
UInt16 port = mbi->GetClientGuid()->GetSrcPort();
UInt32 addr = mbi->GetClientGuid()->GetSrcAddr();
UInt32 flags = mbi->GetFlags();
UInt32 plrID = mbi->GetClientGuid()->GetPlayerID();
plUoid avUoid = mbi->GetAvatarUoid();
plKey avKey=hsgResMgr::ResMgr()->FindKey(avUoid);
mbr->SetPlayerName(mbi->GetClientGuid()->GetPlayerName());
mbr->SetFlags(flags);
mbr->SetPlayerID(plrID);
mbr->SetCCRLevel(mbi->GetClientGuid()->GetCCRLevel());
if (avKey)
mbr->SetAvatarKey(avKey);
}
int plNetClientMsgHandler::ReceiveMsg(plNetMessage *& netMsg)
{
#ifdef HS_DEBUGGING
//plNetClientMgr::GetInstance()->DebugMsg("<RCV> %s", netMsg->ClassName());
#endif
plNetClientMgr::GetInstance()->UpdateServerTimeOffset(netMsg);
switch(netMsg->ClassIndex())
{
default:
plNetClientMgr::GetInstance()->ErrorMsg( "Unknown msg: %s", netMsg->ClassName() );
return hsFail;
MSG_HANDLER_CASE(plNetMsgTerminated)
MSG_HANDLER_CASE(plNetMsgGroupOwner)
case CLASS_INDEX_SCOPED(plNetMsgSDLStateBCast):
MSG_HANDLER_CASE(plNetMsgSDLState)
case CLASS_INDEX_SCOPED(plNetMsgGameMessageDirected):
case CLASS_INDEX_SCOPED(plNetMsgLoadClone):
MSG_HANDLER_CASE(plNetMsgGameMessage)
MSG_HANDLER_CASE(plNetMsgVoice)
MSG_HANDLER_CASE(plNetMsgMembersList)
MSG_HANDLER_CASE(plNetMsgMemberUpdate)
MSG_HANDLER_CASE(plNetMsgListenListUpdate)
MSG_HANDLER_CASE(plNetMsgInitialAgeStateSent)
}
}
////////////////////////////////////////////////////////////////////
MSG_HANDLER_DEFN(plNetClientMsgHandler,plNetMsgTerminated)
{
return hsOK;
}
MSG_HANDLER_DEFN(plNetClientMsgHandler,plNetMsgGroupOwner)
{
plNetClientMgr* nc = IGetNetClientMgr();
plNetMsgGroupOwner* m = plNetMsgGroupOwner::ConvertNoRef(netMsg);
PeekMsg(m);
/* !!! THIS LOG MSG CRASHES THE CLIENT SOMETIMES! -eap
hsLogEntry( nc->DebugMsg("<RCV> %s, %s, sz=%d",
m->ClassName(), m->AsStdString().c_str(), m->GetNetCoreMsgLen()) );
*/
/*
plNetOwnershipMsg* netOwnMsg = TRACKED_NEW plNetOwnershipMsg;
int i;
for(i=0;i<m->GetNumGroups();i++)
{
plNetMsgGroupOwner::GroupInfo gr=m->GetGroupInfo(i);
netOwnMsg->AddGroupInfo(gr);
nc->GetNetGroups()->SetGroup(gr.fGroupID, gr.fOwnIt!=0 ? true : false);
hsLogEntry( nc->DebugMsg("\tGroup 0x%x, ownIt=%d\n", (const char*)gr.fGroupID.Room().GetSequenceNumber(), gr.fOwnIt) );
}
if (netOwnMsg->GetNumGroups())
netOwnMsg->Send();
else
delete netOwnMsg;
*/
nc->SetObjectOwner(m->IsOwner());
return hsOK;
}
MSG_HANDLER_DEFN(plNetClientMsgHandler,plNetMsgSDLState)
{
plNetClientMgr* nc = IGetNetClientMgr();
plNetMsgSDLState* m = plNetMsgSDLState::ConvertNoRef(netMsg);
PeekMsg(m);
/* !!! THIS LOG MSG CRASHES THE CLIENT SOMETIMES! -eap
hsLogEntry( nc->DebugMsg("<RCV> %s, %s, sz=%d",
m->ClassName(), m->AsStdString().c_str(), m->GetNetCoreMsgLen()) );
*/
UInt32 rwFlags = 0;
if ( m->IsInitialState() )
{
nc->IncNumInitialSDLStates();
rwFlags |= plSDL::kMakeDirty; // if initial state, we want all vars.
}
else if ( nc->GetFlagsBit( plNetClientApp::kLoadingInitialAgeState ) )
{
if ( nc->GetFlagsBit( plNetClientApp::kNeedInitialAgeStateCount ) )
{
hsLogEntry( nc->DebugMsg( "Ignoring SDL state because we are still joining age and don't have initial age state count yet." ) );
return hsOK;
}
if ( nc->GetNumInitialSDLStates()<nc->GetRequiredNumInitialSDLStates() )
{
hsLogEntry( nc->DebugMsg( "Ignoring SDL state because we are still joining age and have not received all initial state yet." ) );
return hsOK;
}
hsLogEntry( nc->DebugMsg( "We are still joining age, but have all initial states. Accepting this state (risky?)." ) );
}
// extract stateDataRecord from msg
hsReadOnlyStream stream(m->StreamInfo()->GetStreamLen(), m->StreamInfo()->GetStreamBuf());
char* descName = nil;
int ver;
plStateDataRecord::ReadStreamHeader(&stream, &descName, &ver);
plStateDescriptor* des = plSDLMgr::GetInstance()->FindDescriptor(descName, ver);
if (strcmpi(descName, kSDLAvatarPhysical) == 0)
rwFlags |= plSDL::kKeepDirty;
//
// ERROR CHECK SDL FILE
//
plStateDataRecord* sdRec = des ? TRACKED_NEW plStateDataRecord(des) : nil;
if (!sdRec || sdRec->GetDescriptor()->GetVersion()!=ver)
{
std::string err;
if (!sdRec)
err = xtl::format( "SDL descriptor %s missing, v=%d", descName, ver);
else
err = xtl::format( "SDL descriptor %s, version mismatch, server v=%d, client v=%d",
descName, ver, sdRec->GetDescriptor()->GetVersion());
hsAssert(false, err.c_str());
nc->ErrorMsg(const_cast<char*>(err.c_str()));
// Post Quit message
nc->QueueDisableNet(true, "SDL Desc Problem");
delete sdRec;
}
else if( sdRec->Read( &stream, 0, rwFlags ) )
{
plStateDataRecord* stateRec = nil;
if (m->IsInitialState())
{
stateRec = TRACKED_NEW plStateDataRecord(des);
stateRec->SetFromDefaults(false);
stateRec->UpdateFrom(*sdRec, rwFlags);
delete sdRec;
}
else
stateRec = sdRec;
plNetClientMgr::PendingLoad* pl = TRACKED_NEW plNetClientMgr::PendingLoad();
pl->fSDRec = stateRec; // will be deleted when PendingLoad is processed
if (m->GetHasPlayerID())
pl->fPlayerID = m->GetPlayerID(); // copy originating playerID if we have it
pl->fUoid = m->ObjectInfo()->GetUoid();
// queue up state
nc->fPendingLoads.push_back(pl);
hsLogEntry( nc->DebugMsg( "Added pending SDL delivery for %s:%s", m->ObjectInfo()->GetObjectName(), des->GetName() ) );
}
else
delete sdRec;
delete [] descName; // We've only used descName for a lookup (via SDR, and some error strings. Must delete now.
return hsOK;
}
MSG_HANDLER_DEFN(plNetClientMsgHandler,plNetMsgGameMessage)
{
plNetClientMgr* nc = IGetNetClientMgr();
plNetMsgGameMessage* m = plNetMsgGameMessage::ConvertNoRef(netMsg);
if (m)
{
PeekMsg(m);
plNetMsgLoadClone * lcMsg = plNetMsgLoadClone::ConvertNoRef( m );
if ( lcMsg )
{
if ( lcMsg->GetIsInitialState() )
{
nc->IncNumInitialSDLStates();
}
}
hsReadOnlyStream stream(m->StreamInfo()->GetStreamLen(), m->StreamInfo()->GetStreamBuf());
plMessage* gameMsg = plMessage::ConvertNoRef(hsgResMgr::ResMgr()->ReadCreatable(&stream));
hsAssert(gameMsg, "nil game msg?");
if (gameMsg)
{
/* !!! THIS LOG MSG CRASHES THE CLIENT SOMETIMES!!! -eap
hsLogEntry( nc->DebugMsg("<RCV> %s, %s, sndr %s rcvr %s sz=%d",
m->ClassName(), m->AsStdString().c_str(),
gameMsg->GetSender() ? gameMsg->GetSender()->GetName() : "?",
gameMsg->GetNumReceivers() ? gameMsg->GetReceiver(0)->GetName() : "?",
m->GetNetCoreMsgLen()) );
*/
if (lcMsg)
{
if (!lcMsg->GetIsLoading())
{
plLoadAvatarMsg* unloadClone = plLoadAvatarMsg::ConvertNoRef(gameMsg);
if (unloadClone)
{
plLoadAvatarMsg* unloadMsg = TRACKED_NEW plLoadAvatarMsg(unloadClone->GetCloneKey(), unloadClone->GetRequestorKey(), unloadClone->GetUserData(), unloadClone->GetIsPlayer(), false);
unloadMsg->SetOriginatingPlayerID(unloadClone->GetOriginatingPlayerID());
gameMsg = unloadMsg;
}
}
else
{
plLoadCloneMsg* loadClone = plLoadCloneMsg::ConvertNoRef(gameMsg);
if (loadClone)
{
int idx = nc->fTransport.FindMember(loadClone->GetOriginatingPlayerID());
if (idx == -1)
{
hsLogEntry( nc->DebugMsg( "Ignoring load clone because player isn't in our players list: %d", loadClone->GetOriginatingPlayerID()) );
return hsOK;
}
}
}
}
plNetClientApp::UnInheritNetMsgFlags(gameMsg);
gameMsg->SetBCastFlag(plMessage::kNetCreatedRemotely);
if (!m->GetDeliveryTime().AtEpoch())
{
double timeStamp;
double secs=hsTimer::GetSysSeconds();
m->GetDeliveryTime().ConvertToGameTime(&timeStamp, secs);
hsAssert(timeStamp>=secs, "invalid future timeStamp");
gameMsg->SetTimeStamp(timeStamp);
nc->DebugMsg("Converting game msg future timeStamp, curT=%f, futT=%f", secs, timeStamp);
}
plgDispatch::Dispatch()->MsgSend(gameMsg);
// Debug
if (m->GetHasPlayerID())
{
int idx=nc->fTransport.FindMember(m->GetPlayerID());
plNetTransportMember* mbr = idx != -1 ? nc->fTransport.GetMember(idx) : nil;
if (mbr)
mbr->SetTransportFlags(mbr->GetTransportFlags() | plNetTransportMember::kSendingActions);
}
return hsOK;
}
}
return hsFail;
}
MSG_HANDLER_DEFN(plNetClientMsgHandler,plNetMsgVoice)
{
plNetClientMgr* nc = IGetNetClientMgr();
plNetMsgVoice* m = plNetMsgVoice::ConvertNoRef(netMsg);
PeekMsg(m);
/* !!! THIS LOG MSG CRASHES THE CLIENT SOMETIMES! -eap
hsLogEntry( nc->DebugMsg("<RCV> %s, %s, sz=%d",
m->ClassName(), m->AsStdString().c_str(), m->GetNetCoreMsgLen()) );
*/
int bufLen = m->GetVoiceDataLen();
const char* buf = m->GetVoiceData();
BYTE flags = m->GetFlags();
BYTE numFrames = m->GetNumFrames();
plKey key = NULL;
// plKey key=hsgResMgr::ResMgr()->FindKey(m->ObjectInfo()->GetUoid());
// Filter ignored sender
if ( VaultAmIgnoringPlayer( m->GetPlayerID() ) )
{
hsLogEntry( nc->DebugMsg( "Ignoring voice chat from ignored player %lu", m->GetPlayerID() ) );
return hsOK;
}
int idx=nc->fTransport.FindMember(m->GetPlayerID());
plNetTransportMember* mbr = idx != -1 ? nc->fTransport.GetMember(idx) : nil;
if (mbr)
{
key = mbr->GetAvatarKey();
// filter based on listen/talk list (for forced mode)
if (nc->GetListenListMode() == plNetClientMgr::kListenList_Forced)
{
if (nc->GetListenList()->FindMember( mbr ))
{
hsLogEntry( nc->DebugMsg( "Ignoring voice chat from ignored player %lu", m->GetPlayerID() ) );
return hsOK;
}
}
mbr->SetTransportFlags(mbr->GetTransportFlags() | plNetTransportMember::kSendingVoice);
}
// hsKeyedObject* obj = key ? key->ObjectIsLoaded() : nil;
plSceneObject* avObj = key ? plSceneObject::ConvertNoRef( key->ObjectIsLoaded() ) : nil;
// if (obj)
if (avObj)
{
plAudible * aud = avObj->GetAudioInterface()->GetAudible();
pl2WayWinAudible* pAud = pl2WayWinAudible::ConvertNoRef(aud);
if (pAud)
pAud->PlayNetworkedSpeech(buf, bufLen, numFrames, flags);
else
{
nc->ErrorMsg("\tObject doesn't have audible");
}
}
else
{
nc->DebugMsg("\tCan't find loaded object\n");
}
return hsOK;
}
MSG_HANDLER_DEFN(plNetClientMsgHandler,plNetMsgMembersList)
{
plNetClientMgr* nc = IGetNetClientMgr();
plNetMsgMembersList* m = plNetMsgMembersList::ConvertNoRef(netMsg);
PeekMsg(m);
/* !!! THIS LOG MSG CRASHES THE CLIENT SOMETIMES! -eap
hsLogEntry( nc->DebugMsg("<RCV> %s, %s, sz=%d",
m->ClassName(), m->AsStdString().c_str(), m->GetNetCoreMsgLen()) );
*/
int i;
// remove existing members, except server
for( i=nc->fTransport.GetNumMembers()-1 ; i>=0; i-- )
{
if (!nc->fTransport.GetMember(i)->IsServer())
{
nc->fTransport.RemoveMember(i);
}
} // for
// update the members list from the msg.
// this app is not one of the members in the msg
for( i=0 ;i<m->MemberListInfo()->GetNumMembers() ;i++ )
{
plNetTransportMember* mbr = TRACKED_NEW plNetTransportMember(nc);
IFillInTransportMember(m->MemberListInfo()->GetMember(i), mbr);
hsLogEntry(nc->DebugMsg("\tAdding transport member, name=%s, p2p=%d, plrID=%d\n", mbr->AsStdString().c_str(), mbr->IsPeerToPeer(), mbr->GetPlayerID()));
int idx=nc->fTransport.AddMember(mbr);
hsAssert(idx>=0, "Failed adding member?");
} // for
// new player has been aded send local MembersUpdate msg
plMemberUpdateMsg* mu = TRACKED_NEW plMemberUpdateMsg;
mu->Send();
return hsOK;
}
MSG_HANDLER_DEFN(plNetClientMsgHandler,plNetMsgMemberUpdate)
{
plNetClientMgr* nc = IGetNetClientMgr();
plNetMsgMemberUpdate* m = plNetMsgMemberUpdate::ConvertNoRef(netMsg);
PeekMsg(m);
/* !!! THIS LOG MSG CRASHES THE CLIENT SOMETIMES! -eap
hsLogEntry( nc->DebugMsg("<RCV> %s, %s, sz=%d",
m->ClassName(), m->AsStdString().c_str(), m->GetNetCoreMsgLen()) );
*/
if (m->AddingMember())
{
plNetTransportMember* mbr=nil;
int idx = nc->fTransport.FindMember(m->MemberInfo()->GetClientGuid()->GetPlayerID());
if ( idx>=0 )
mbr = nc->fTransport.GetMember(idx);
else
mbr = TRACKED_NEW plNetTransportMember(nc);
hsAssert(mbr, "nil xport member");
IFillInTransportMember(m->MemberInfo(), mbr);
if ( idx<0 )
{ // didn't find him
if ( nc->fTransport.AddMember(mbr)<0 )
delete mbr; // delete newly created member
}
}
else
{
int idx=nc->fTransport.FindMember(m->MemberInfo()->GetClientGuid()->GetPlayerID());
if (idx<0)
{
hsLogEntry( nc->DebugMsg("\tCan't find member to remove.") );
}
else
{
nc->fTransport.RemoveMember(idx);
}
}
// new player has been aded send local MembersUpdate msg
plMemberUpdateMsg* mu = TRACKED_NEW plMemberUpdateMsg;
mu->Send();
return hsOK;
}
MSG_HANDLER_DEFN(plNetClientMsgHandler,plNetMsgListenListUpdate)
{
plNetClientMgr* nc = IGetNetClientMgr();
plNetMsgListenListUpdate* m = plNetMsgListenListUpdate::ConvertNoRef(netMsg);
PeekMsg(m);
/* !!! THIS LOG MSG CRASHES THE CLIENT SOMETIMES! -eap
hsLogEntry( nc->DebugMsg("<RCV> %s, %s, sz=%d",
m->ClassName(), m->AsStdString().c_str(), m->GetNetCoreMsgLen()) );
*/
int idx=nc->fTransport.FindMember(m->GetPlayerID());
plNetTransportMember* tm = (idx==-1 ? nil : nc->fTransport.GetMember(idx));
if(!tm)
{
#if 0
tm = TRACKED_NEW plNetTransportMember(nc);
tm->SetClientNum(m->GetSenderClientNum());
int idx=nc->fTransport.AddMember(tm);
hsAssert(idx>=0, "Failed adding member?");
nc->DebugMsg("ListenListUpdate msg: Adding member on the fly\n");
#endif
return hsOK;
}
if (m->GetAdding())
{
// add the sender to my talk list
nc->GetTalkList()->AddMember(tm);
}
else
{
// remove the sender from my talk list
nc->GetTalkList()->RemoveMember(tm);
}
return hsOK;
}
MSG_HANDLER_DEFN(plNetClientMsgHandler,plNetMsgInitialAgeStateSent)
{
plNetClientMgr * nc = IGetNetClientMgr();
plNetMsgInitialAgeStateSent* msg = plNetMsgInitialAgeStateSent::ConvertNoRef(netMsg);
PeekMsg(msg);
/* !!! THIS LOG MSG CRASHES THE CLIENT SOMETIMES! -eap
hsLogEntry( nc->DebugMsg("<RCV> %s, %s, sz=%d",
netMsg->ClassName(), netMsg->AsStdString().c_str(), netMsg->GetNetCoreMsgLen()) );
*/
nc->DebugMsg( "Initial age SDL count: %d", msg->GetNumInitialSDLStates( ) );
nc->SetRequiredNumInitialSDLStates( msg->GetNumInitialSDLStates() );
nc->SetFlagsBit( plNetClientApp::kNeedInitialAgeStateCount, false );
if (nc->GetNumInitialSDLStates() >= nc->GetRequiredNumInitialSDLStates()) {
nc->ICheckPendingStateLoad(hsTimer::GetSysSeconds());
nc->NotifyRcvdAllSDLStates();
}
return hsOK;
}
////////////////////////////////////////////////////////////////////
// End.

View File

@ -0,0 +1,72 @@
/*==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==*/
#ifndef plNetClientMsgHandler_inc
#define plNetClientMsgHandler_inc
#include "../plNetCommon/plNetMsgHandler.h"
#include "hsStlUtils.h"
///////////////////////////////////////////////////////////////////
//
// define msg handler fxn for netClient msgs
//
class plNetClientMgr;
class plNetMsgMemberInfoHelper;
class plNetTransportMember;
///////////////////////////////////////////////////////////////////
class plNetClientMsgHandler : public plNetMsgHandler
{
//protected:
enum // SendOrTimeOut return values and meanings
{
kTimedOutNoRetry = -1,
kDoNothing = 0,
kSend = 1,
};
plNetClientMgr * IGetNetClientMgr();
void IFillInTransportMember(const plNetMsgMemberInfoHelper* mbi, plNetTransportMember* mbr);
public:
plNetClientMsgHandler(plNetClientMgr * mgr);
~plNetClientMsgHandler();
int ReceiveMsg(plNetMessage *& netMsg);
int PeekMsg(plNetMessage * netMsg); // return msgsize on success. -1 on error.
MSG_HANDLER_DECL(plNetMsgTerminated)
MSG_HANDLER_DECL(plNetMsgGroupOwner)
MSG_HANDLER_DECL(plNetMsgSDLState)
MSG_HANDLER_DECL(plNetMsgGameMessage)
MSG_HANDLER_DECL(plNetMsgVoice)
MSG_HANDLER_DECL(plNetMsgMembersList)
MSG_HANDLER_DECL(plNetMsgMemberUpdate)
MSG_HANDLER_DECL(plNetMsgListenListUpdate)
MSG_HANDLER_DECL(plNetMsgInitialAgeStateSent)
};
#endif // plNetClientMsgHandler_inc

View File

@ -0,0 +1,109 @@
/*==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 "plNetClientMsgScreener.h"
#include "plNetLinkingMgr.h"
#include "../pnNetCommon/plNetApp.h"
#include "../pnMessage/plMessage.h"
#include "../plStatusLog/plStatusLog.h"
#include "../plAvatar/plAvatarMgr.h"
#include "../plAvatar/plArmatureMod.h"
///////////////////////////////////////////////////////////////
// CLIENT Version
///////////////////////////////////////////////////////////////
plNetClientMsgScreener::plNetClientMsgScreener()
{
DebugMsg("created");
}
//
// For plLoggable base
//
void plNetClientMsgScreener::ICreateStatusLog() const
{
fStatusLog = plStatusLogMgr::GetInstance().CreateStatusLog(40, "NetScreener.log",
plStatusLog::kTimestamp | plStatusLog::kFilledBackground | plStatusLog::kAlignToTop);
}
//
// return cur age name
//
const char* plNetClientMsgScreener::IGetAgeName() const
{
plNetLinkingMgr *lm = plNetLinkingMgr::GetInstance();
return lm && lm->GetAgeLink()->GetAgeInfo() ? lm->GetAgeLink()->GetAgeInfo()->GetAgeFilename() : "?";
}
//
// Check if key is local avatar
//
bool plNetClientMsgScreener::IIsLocalAvatarKey(plKey key, const plNetGameMember* gm) const
{
return (!key || key==plNetClientApp::GetInstance()->GetLocalPlayerKey());
}
bool plNetClientMsgScreener::IIsLocalArmatureModKey(plKey key, const plNetGameMember* gm) const
{
plKey playerKey = plNetClientApp::GetInstance()->GetLocalPlayerKey();
plArmatureMod* aMod = playerKey ? plAvatarMgr::GetInstance()->FindAvatar(playerKey) : nil;
return (!key || key==(aMod ? aMod->GetKey() : nil));
}
//
// Check if CCR
//
bool plNetClientMsgScreener::IIsSenderCCR(const plNetGameMember* gm) const
{
return plNetClientApp::GetInstance()->AmCCR();
}
//
// return true if msg is allowed/accepted as a net msg
//
bool plNetClientMsgScreener::AllowMessage(const plMessage* msg) const
{
if (!msg)
return false;
Answer ans=IAllowMessageType(msg->ClassIndex());
if (ans==kYes)
return true;
if (ans==kNo)
{
// WarningMsg("Quick-reject net propagated msg %s", msg->ClassName());
return false;
}
if (!IValidateMessage(msg))
{
// WarningMsg("Validation failed. Blocking net propagated msg %s", msg->ClassName());
return false;
}
return true;
}

View 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/>.
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 plNetClientMsgScreener_h
#define plNetClientMsgScreener_h
#include "../plNetCommon/plNetMsgScreener.h"
//
// Client-side version
//
class plNetClientMsgScreener : public plNetMsgScreener
{
protected:
void ICreateStatusLog() const;
const char* IGetSenderName(const plNetGameMember* gm) const { return "local"; }
const char* IGetAgeName() const;
bool IIsLocalAvatarKey(plKey key, const plNetGameMember* gm) const;
bool IIsLocalArmatureModKey(plKey key, const plNetGameMember* gm) const;
bool IIsSenderCCR(const plNetGameMember* gm=nil) const;
bool IAmClient() const { return true; }
public:
plNetClientMsgScreener();
bool AllowMessage(const plMessage* msg) const;
};
#endif // plNetClientMsgScreener_h

View File

@ -0,0 +1,91 @@
/*==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 "plNetClientStats.h"
#include "plNetClientMgr.h"
#include "hsTimer.h"
plNetClientStats::plNetClientStats() :
fNumVaultMsgsSent(0),
fNumVaultMsgsRcvd(0),
fVaultMsgSentBytes(0),
fVaultMsgRcvdBytes(0),
fAgeStatsULBits(0),
fAgeStatsDLBits(0),
fAgeStatsLinkInTime(0)
{
}
//
// return the avg UL bps used so far in this age
//
float plNetClientStats::GetAgeStatsULBitsPerSec() const
{
double elapsedAgeTime = hsTimer::GetSeconds() - fAgeStatsLinkInTime;
return (float)(fAgeStatsULBits/elapsedAgeTime);
}
//
// return the acks that were conpressed so far
//
UInt32 plNetClientStats::GetRecvdMultipleAcks() const
{
return fRecvdMultipleAcks;
}
//
// return the avg DL bps used so far in this age
//
float plNetClientStats::GetAgeStatsDLBitsPerSec() const
{
double elapsedAgeTime = hsTimer::GetSeconds() - fAgeStatsLinkInTime;
return (float)(fAgeStatsDLBits/elapsedAgeTime);
}
//
// Accumulate the UL/DL bits & acks used from the netCore state
//
void plNetClientStats::UpdateAgeStats()
{
plNetClientMgr* nc=plNetClientMgr::GetInstance();
#if 0
fAgeStatsDLBits += nc->GetNetCore()->GetStats()->GetDLBits();
fAgeStatsULBits += nc->GetNetCore()->GetStats()->GetULBits();
fRecvdMultipleAcks += nc->GetNetCore()->GetStats()->GetRecvdMultipleAcks();
#endif
}
//
// Call when you join an age
//
void plNetClientStats::ResetAgeStats()
{
fAgeStatsDLBits = fAgeStatsULBits = 0;
fRecvdMultipleAcks = 0;
fAgeStatsLinkInTime = hsTimer::GetSeconds();
}

View File

@ -0,0 +1,76 @@
/*==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==*/
#ifndef plNetClientStats_h
#define plNetClientStats_h
#include "hsTypes.h"
//
// Holds stats counters used by the Net Client
//
class plNetClientStats
{
public:
plNetClientStats();
//
// Vault Stats
//
private:
// Vault msg counters
UInt32 fNumVaultMsgsSent;
UInt32 fNumVaultMsgsRcvd;
UInt32 fVaultMsgSentBytes;
UInt32 fVaultMsgRcvdBytes;
public:
// msg counters
UInt32 GetNumVaultMsgsSent() const { return fNumVaultMsgsSent; }
UInt32 GetNumVaultMsgsRcvd() const { return fNumVaultMsgsRcvd; }
UInt32 GetVaultMsgSentBytes() const { return fVaultMsgSentBytes; }
UInt32 GetVaultMsgRcvdBytes() const { return fVaultMsgRcvdBytes; }
void TallyVaultMsgSent( int size ) { fNumVaultMsgsSent++; fVaultMsgSentBytes+=size; }
void TallyVaultMsgRcvd( int size ) { fNumVaultMsgsRcvd++; fVaultMsgRcvdBytes+=size; }
void ResetVaultMsgCounters() { fNumVaultMsgsSent=fNumVaultMsgsRcvd=fVaultMsgSentBytes=fVaultMsgRcvdBytes=0; }
//
// NetClient BW Stats, kept per age
//
private:
int fAgeStatsULBits, fAgeStatsDLBits;
UInt32 fRecvdMultipleAcks;
double fAgeStatsLinkInTime;
public:
void UpdateAgeStats();
void ResetAgeStats();
float GetAgeStatsULBitsPerSec() const;
float GetAgeStatsDLBitsPerSec() const;
UInt32 GetRecvdMultipleAcks() const;
};
#endif // plNetClientStats_h

View File

@ -0,0 +1,164 @@
/*==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 "plNetClientMgr.h"
#include "plNetClientVNodeMgr.h"
#include "../plNetMessage/plNetMessage.h"
#include "../plGImage/plMipmap.h"
#include "../plJPEG/plJPEG.h"
#include "../plVault/plVault.h"
#include "hsResMgr.h"
#include "../pnMessage/plRefMsg.h"
#include "../plVault/plDniCoordinateInfo.h"
#include "../plVault/plAgeInfoSource.h"
#include "plNetLinkingMgr.h"
#include "../plStatusLog/plStatusLog.h"
#include "../plClientState/plClientStateMgr.h"
#include "../plSDL/plSDL.h"
#include "../plAgeLoader/plAgeLoader.h"
#include "../../FeatureLib/pfMessage/pfKIMsg.h"
////////////////////////////////////////////////////////////////////
class plNetClientAgeInfoSource : public plAgeInfoSource
{
plDniCoordinateInfo fNilCoords; // TEMPORARY
public:
const plDniCoordinateInfo * GetAgeCoords( void ) const
{
return &fNilCoords; // tmp
}
const plUnifiedTime * GetAgeTime( void ) const
{
static plUnifiedTime ut;
ut.SetSecsDouble(plNetClientMgr::GetInstance()->GetCurrentAgeElapsedSeconds());
return &ut;
}
const char * GetAgeName( void ) const
{
return plNetLinkingMgr::GetInstance()->GetAgeLink()->GetAgeInfo()->GetAgeInstanceName();
}
const plUUID * GetAgeGuid( void ) const
{
return plNetLinkingMgr::GetInstance()->GetAgeLink()->GetAgeInfo()->GetAgeInstanceGuid();
}
static plNetClientAgeInfoSource * GetInstance( void )
{
static plNetClientAgeInfoSource Me;
return &Me;
}
};
//// Image/Mipmap Conversion //////////////////////////////////////////////////
hsBool StuffImageIntoNode( plMipmap * src, RelVaultNode * dst )
{
VaultImageNode image(dst);
hsRAMStream ramStream;
// Create our JPEG stream
plJPEG::Instance().SetWriteQuality( 30 ); // In percent quality
if( !plJPEG::Instance().WriteToStream( &ramStream, src ) )
return false;
unsigned bytes = ramStream.GetEOF();
byte * buffer = (byte *)ALLOC(bytes);
ramStream.CopyToMem(buffer);
image.SetImageData(buffer, bytes);
image.SetImageType( VaultImageNode::kJPEG );
// possibly make a plKey for the mipmap.
return ExtractImageFromNode( dst );
}
hsBool ExtractImageFromNode( RelVaultNode * src)
{
// no id? exit now. we will be called again when element is given an id.
if ( src->nodeId == 0 )
return false;
VaultCliImageNode image(src);
// already have a mipmap and it has a key? release it
if ( image.fMipmap && image.fMipmap->GetKey()!=nil )
{
plNetClientMgr::GetInstance()->GetKey()->Release( image.fMipmap->GetKey() );
image.fMipmap = nil;
}
// convert image data to a plMipmap
switch( image.imgType )
{
case VaultImageNode::kJPEG:
{
// Copy to a RAM stream so the JPEG class is happy
hsRAMStream ramStream;
ramStream.Write( image.imgDataLen, image.imgData );
ramStream.Rewind();
// create mipmap from image data
image.fMipmap = plJPEG::Instance().ReadFromStream( &ramStream );
}
break;
default:
{
hsAssert( false, "ExtractImageFromNode: Invalid image type" );
return false; // Invalid image type
}
}
if ( !image.fMipmap )
{
hsAssert( false, "ExtractImageFromNode failed" );
return false;
}
// we now have a mipmap, but it doesn't have a key. make a key for it
static int UniqueIdentifier = 0;
char keyName[512];
sprintf( keyName, "VaultImage_%lu_%d", src->nodeId, UniqueIdentifier++ );
// create a key for the mipmap
plKey imageKey = hsgResMgr::ResMgr()->NewKey( keyName, image.fMipmap, plLocation::kGlobalFixedLoc );
// ref the image key
hsgResMgr::ResMgr()->AddViaNotify( imageKey, TRACKED_NEW plGenRefMsg(
plNetClientMgr::GetInstance()->GetKey(), plRefMsg::kOnCreate, 0, plNetClientMgr::kVaultImage ),
plRefFlags::kActiveRef );
return ( image.fMipmap->GetKey()!=nil );
}
////////////////////////////////////////////////////////////////////
// End.

View File

@ -0,0 +1,234 @@
/*==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 "plNetClientMgr.h"
#include "plNetClientVault.h"
#include "../pnNetCommon/plNetMsg.h"
#include "../plGImage/plMipmap.h"
#include "../plJPEG/plJPEG.h"
#include "../plVault/plVaultTasks.h"
#include "hsResMgr.h"
#include "../pnMessage/plRefMsg.h"
#include "../plVault/plDniCoordinateInfo.h"
#include "../plVault/plAgeInfoSource.h"
////////////////////////////////////////////////////////////////////
class plNetClientAgeInfoSource : public plAgeInfoSource
{
plDniCoordinateInfo fNilCoords; // TEMPORARY
public:
const plDniCoordinateInfo * GetAgeCoords( void ) const
{
return &fNilCoords; // tmp
}
const plUnifiedTime * GetAgeTime( void ) const
{
static plUnifiedTime ut;
ut.SetSecsDouble(plNetClientMgr::GetInstance()->GetCurrentAgeElapsedSeconds());
return &ut;
}
const char * GetAgeName( void ) const
{
return plNetClientMgr::GetInstance()->GetAgeName();
}
const plServerGuid * GetAgeGuid( void ) const
{
return plNetClientMgr::GetInstance()->GetCurrSessionInfo()->GetServerGuid();
}
static plNetClientAgeInfoSource * GetInstance( void )
{
static plNetClientAgeInfoSource Me;
return &Me;
}
};
////////////////////////////////////////////////////////////////////
plNetClientVault::plNetClientVault()
{
}
plNetApp * plNetClientVault::GetNetApp( void ) const
{
return plNetClientMgr::GetInstance();
}
plAgeInfoSource * plNetClientVault::GetAgeInfo( void ) const
{
return plNetClientAgeInfoSource::GetInstance();
}
void plNetClientVault::IInitNode( plVaultNode * node )
{
plVaultImageNode * IMG = plVaultImageNode::ConvertNoRef( node );
if ( IMG )
{
plNetClientVault::ExtractImageFromNode( IMG );
}
}
void plNetClientVault::IFiniNode( plVaultNode * node )
{
plVaultImageNode * IMG = plVaultImageNode::ConvertNoRef( node );
if ( IMG && IMG->GetMipmap() )
{
plNetClientMgr::GetInstance()->GetKey()->Release( IMG->GetMipmap()->GetKey() );
IMG->ISetMipmap( nil );
}
}
int plNetClientVault::ISendNetMsg( plNetMsgVault * msg, UInt32 sendFlags )
{
return plNetClientMgr::GetInstance()->SendMsg( msg, sendFlags );
}
void plNetClientVault::IOnTaskTimedOut( plVaultTask * task )
{
std::string msg;
xtl::format( msg, "KI task timed out: %s", task->ClassName() );
plNetClientMgr::GetInstance()->OnNetFailure( msg.c_str(), true );
}
bool plNetClientVault::IAmOnline( void ) const
{
return plNetClientMgr::GetInstance()->IsEnabled()!=0;
}
//// Image/Mipmap Conversion //////////////////////////////////////////////////
hsBool plNetClientVault::StuffImageIntoNode( plMipmap * src, plVaultImageNode * dst )
{
hsRAMStream ramStream;
// Create our JPEG stream
plJPEG::Instance().SetWriteQuality( 50 ); // In percent quality
if( !plJPEG::Instance().WriteToStream( &ramStream, src ) )
return false;
// Copy the stream to the image element now
void * buffer = dst->AllocBuffer( ramStream.GetEOF() );
if( buffer == nil )
return false;
ramStream.CopyToMem( buffer );
dst->SetImageType( plVaultImageNode::kJPEG );
// possibly make a plKey for the mipmap.
return plNetClientVault::ExtractImageFromNode( dst );
}
hsBool plNetClientVault::ExtractImageFromNode( plVaultImageNode * src)
{
// no id? exit now. we will be called again when element is given an id.
if ( src->GetID()==0 )
return false;
// already have a mipmap and it has a key? release it
if ( src->GetMipmap() && src->GetMipmap()->GetKey()!=nil )
{
plNetClientMgr::GetInstance()->GetKey()->Release( src->GetMipmap()->GetKey() );
src->ISetMipmap( nil );
}
// convert image data to a plMipmap
switch( src->GetImageType() )
{
case plVaultImageNode::kJPEG:
{
// Copy to a RAM stream so the JPEG class is happy
hsRAMStream ramStream;
ramStream.Write( src->GetBufSize(), src->GetBuffer() );
ramStream.Rewind();
// create mipmap from image data
src->ISetMipmap( plJPEG::Instance().ReadFromStream( &ramStream ) );
}
break;
default:
{
hsAssert( false, "ExtractImageFromNode: Invalid image type" );
return false; // Invalid image type
}
}
if ( !src->GetMipmap() )
{
hsAssert( false, "ExtractImageFromNode failed" );
return false;
}
// we now have a mipmap, but it doesn't have a key. make a key for it
static int UniqueIdentifier = 0;
char keyName[512];
sprintf( keyName, "VaultImage_%lu_%d", src->GetID(), UniqueIdentifier++ );
// create a key for the mipmap
plKey imageKey = hsgResMgr::ResMgr()->NewKey( keyName, src->IGetMipmap(),
plLocation::kGlobalFixedLoc );
// ref the image key
hsgResMgr::ResMgr()->AddViaNotify( imageKey, new plGenRefMsg(
plNetClientMgr::GetInstance()->GetKey(), plRefMsg::kOnCreate, 0, 0 ),
plRefFlags::kActiveRef );
return ( src->GetMipmap()->GetKey()!=nil );
}
////////////////////////////////////////////////////////////////////
plNetPlayerVault::plNetPlayerVault()
{
}
bool plNetPlayerVault::IIsThisMe( plVaultPlayerInfoNode * node ) const
{
return GetPlayer()->GetPlayerInfo()->GetID()==node->GetID();
}
plVaultPlayerNode * plNetPlayerVault::GetPlayer( void ) const
{
return plVaultPlayerNode::ConvertNoRef( GetRootNode() );
}
void plNetPlayerVault::IFillOutConnectFields( plNetMsgVault * msg ) const
{
msg->AddInt( plVault::kArg_VaultClientType, plVault::kNodeType_VaultPlayer );
msg->AddInt( plVault::kArg_VaultClientID, plNetClientMgr::GetInstance()->GetDesiredPlayerID() );
}
bool plNetPlayerVault::IIsThisMsgMine( plNetMsgVault * msg ) const
{
if ( plVaultClient::IIsThisMsgMine( msg ) )
return true;
return ( msg->GetInt( plVault::kArg_VaultClientID )==plNetClientMgr::GetInstance()->GetDesiredPlayerID() );
}
////////////////////////////////////////////////////////////////////
// End.

View File

@ -0,0 +1,71 @@
/*==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==*/
#ifndef plNetClientVault_h_inc
#define plNetClientVault_h_inc
#include "../plVault/plVaultClient.h"
class plMipmap;
class plVaultImageNode;
////////////////////////////////////////////////////////////////////
class plNetClientVault : public plVaultClient
{
protected:
void IInitNode( plVaultNode * node );
void IFiniNode( plVaultNode * node );
int ISendNetMsg( plNetMsgVault * msg, UInt32 sendFlags=0 );
void IOnTaskTimedOut( plVaultTask * task );
bool IAmOnline( void ) const;
public:
plNetClientVault();
plNetApp * GetNetApp( void ) const;
plAgeInfoSource * GetAgeInfo( void ) const;
// static helpers to convert between plMipmap and plVaultImageNode
static hsBool StuffImageIntoNode( plMipmap * src, plVaultImageNode * dst );
static hsBool ExtractImageFromNode( plVaultImageNode * src );
};
////////////////////////////////////////////////////////////////////
class plNetPlayerVault : public plNetClientVault
{
protected:
bool IIsThisMe( plVaultPlayerInfoNode * node ) const;
void IFillOutConnectFields( plNetMsgVault * msg ) const;
bool IIsThisMsgMine( plNetMsgVault * msg ) const;
public:
plNetPlayerVault();
plVaultPlayerNode * GetPlayer( void ) const;
};
#endif // plNetClientVault_h_inc

View File

@ -0,0 +1,148 @@
/*==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==*/
#ifndef plNetLinkingMgr_h_inc
#define plNetLinkingMgr_h_inc
#include "hsTypes.h"
#include "hsStlUtils.h"
#include "hsBitVector.h"
#include "../plNetCommon/plNetServerSessionInfo.h"
#include "../plNetCommon/plNetCommon.h"
#include "../plMessage/plLinkToAgeMsg.h"
class plMessage;
struct plNCAgeJoiner;
struct plNCAgeLeaver;
class plNetLinkingMgr
{
static void NCAgeJoinerCallback (
plNCAgeJoiner * joiner,
unsigned type,
void * notify,
void * userState
);
static void NCAgeLeaverCallback (
plNCAgeLeaver * leaver,
unsigned type,
void * notify,
void * userState
);
friend struct NCAgeJoinerCallback;
friend struct NCAgeLeaverCallback;
static void ExecNextOp ();
plNetLinkingMgr();
plNetLinkingMgr(const plNetLinkingMgr &);
enum Cmds
{
kNilCmd,
// Sent to a player to have them call us back with info for linking to their age.
kLinkPlayerHere,
// Offer link to player.
kOfferLinkToPlayer,
// Offer link to another player from a public linking book (to my instance of the age w/out going through personal age)
kOfferLinkFromPublicBook,
// Sent to a player to have them link to their last age
kLinkPlayerToPrevAge
};
bool IPreProcessLink( void );
void IPostProcessLink( void );
bool IProcessLinkingMgrMsg( plLinkingMgrMsg * msg );
bool IProcessLinkToAgeMsg( plLinkToAgeMsg * msg );
bool IDispatchMsg( plMessage * msg, UInt32 playerID );
public:
static plNetLinkingMgr * GetInstance();
hsBool MsgReceive( plMessage *msg ); // TODO: Make this a hsKeyedObject so we can really handle messages.
void Update();
bool IsEnabled( void ) const { return fLinkingEnabled;}
void SetEnabled( bool b );
bool LinkedIn () const { return fLinkedIn && fLinkingEnabled; }
bool Linking () const { return !fLinkedIn && !fLinkingEnabled; }
// Link to an age.
void LinkToAge( plAgeLinkStruct * link, UInt32 playerID=kInvalidPlayerID );
void LinkToAge( plAgeLinkStruct * link, const char* linkAnim, UInt32 playerID=kInvalidPlayerID );
// Link to my last age.
void LinkToPrevAge( UInt32 playerID=kInvalidPlayerID );
// Link to my Personal Age
void LinkToMyPersonalAge( UInt32 playerID=kInvalidPlayerID );
// Link to my Neighborhood Age
void LinkToMyNeighborhoodAge( UInt32 playerID=kInvalidPlayerID );
// Link a player here.
void LinkPlayerHere( UInt32 playerID );
// Link player to specified age
void LinkPlayerToAge( plAgeLinkStruct * link, UInt32 playerID );
// Link player back to his last age
void LinkPlayerToPrevAge( UInt32 playerID );
// Link us to a players age.
void LinkToPlayersAge( UInt32 playerID );
// Offer a link to player.
void OfferLinkToPlayer( const plAgeLinkStruct * info, UInt32 playerID, plKey replyKey );
void OfferLinkToPlayer( const plAgeInfoStruct * info, UInt32 playerID );
void OfferLinkToPlayer( const plAgeLinkStruct * info, UInt32 playerID );
// Leave the current age
void LeaveAge (bool quitting);
// link info
plAgeLinkStruct * GetAgeLink() { return &fAgeLink; }
plAgeLinkStruct * GetPrevAgeLink() { return &fPrevAgeLink; }
// lobby info
void SetLobbyAddr( const char * ipaddr ) { fLobbyInfo.SetServerAddr( ipaddr );}
void SetLobbyPort( int port ) { fLobbyInfo.SetServerPort( port );}
const plNetServerSessionInfo * GetLobbyServerInfo( void ) const { return &fLobbyInfo;}
// helpers
static std::string GetProperAgeName( const char * ageName ); // attempt to fix wrong case age name.
private:
bool fLinkingEnabled;
bool fLinkedIn;
// The age we are either joining or are joined with.
plAgeLinkStruct fAgeLink;
// The age we just left.
plAgeLinkStruct fPrevAgeLink;
// The lobby we want to talk to.
plNetServerSessionInfo fLobbyInfo;
};
#endif // plNetLinkingMgr_h_inc

View File

@ -0,0 +1,306 @@
/*==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 "plNetObjectDebugger.h"
#include "hsResMgr.h"
#include "hsTemplates.h"
#include "../pnUtils/pnUtils.h"
#include "../pnKeyedObject/hsKeyedObject.h"
#include "../plStatusLog/plStatusLog.h"
#include "../plResMgr/plKeyFinder.h"
#include "../plNetClient/plNetClientMgr.h"
#include "../plAgeLoader/plAgeLoader.h"
plNetObjectDebugger::DebugObject::DebugObject(const char* objName, plLocation& loc, UInt32 flags) :
fLoc(loc),
fFlags(flags)
{
std::string tmp = objName;
hsStrLower((char*)tmp.c_str());
fObjName = tmp;
}
//
// return true if string matches objName according to flags
//
bool plNetObjectDebugger::DebugObject::StringMatches(const char* str) const
{
if (!str)
return false;
if (fFlags & kExactStringMatch)
return !stricmp(str, fObjName.c_str());
if (fFlags & kEndStringMatch)
{
int len=strlen(str);
if (len>fObjName.size())
return false;
return !stricmp(str, fObjName.c_str()+fObjName.size()-len);
}
if (fFlags & kStartStringMatch)
{
int len=strlen(str);
if (len>fObjName.size())
return false;
return !strnicmp(str, fObjName.c_str(), strlen(str));
}
if (fFlags & kSubStringMatch)
{
std::string tmp = str;
hsStrLower((char*)tmp.c_str());
return (strstr(tmp.c_str(), fObjName.c_str()) != nil);
}
hsAssert(false, "missing flags");
return false;
}
//
// if both objName and pageName are provided, and this object has page info,
// return true if object matches both string and location.
// else just return true if object matches string
//
bool plNetObjectDebugger::DebugObject::ObjectMatches(const char* objName, const char* pageName)
{
if (!objName)
return false;
if (!pageName || (fFlags & kPageMatch)==0)
{
// only have enough info to match by objName
return StringMatches(objName);
}
plLocation loc;
loc = plKeyFinder::Instance().FindLocation(NetCommGetAge()->ageDatasetName, pageName);
return (StringMatches(objName) && loc==fLoc);
}
//
// try to match by plLocation
//
bool plNetObjectDebugger::DebugObject::ObjectMatches(const hsKeyedObject* obj)
{
if (!obj || !obj->GetKey())
return false;
if ((fFlags & kPageMatch)==0)
{
// match based on object name only
return StringMatches(obj->GetKeyName());
}
return (obj->GetKey()->GetUoid().GetLocation()==fLoc);
}
/////////////////////////////////////////////////////////////////
// plNetObjectDebugger
/////////////////////////////////////////////////////////////////
plNetObjectDebugger::plNetObjectDebugger() : fStatusLog(nil), fDebugging(false)
{
}
plNetObjectDebugger::~plNetObjectDebugger()
{
ClearAllDebugObjects();
delete fStatusLog;
}
//
// STATIC
//
plNetObjectDebugger* plNetObjectDebugger::GetInstance()
{
static plNetObjectDebugger gNetObjectDebugger;
if (plNetObjectDebuggerBase::GetInstance()==nil)
plNetObjectDebuggerBase::SetInstance(&gNetObjectDebugger);
return &gNetObjectDebugger;
}
//
// create StatusLog if necessary
//
void plNetObjectDebugger::ICreateStatusLog() const
{
if (!fStatusLog)
{
fStatusLog = plStatusLogMgr::GetInstance().CreateStatusLog(40, "NetObject.log",
plStatusLog::kFilledBackground | plStatusLog::kAlignToTop | plStatusLog::kTimestamp );
}
}
bool plNetObjectDebugger::AddDebugObject(const char* objName, const char* pageName)
{
if (!objName)
return false;
int size=strlen(objName)+1;
hsTempArray<char> tmpObjName(size);
memset(tmpObjName, 0, size);
//
// set string matching flags
//
int len = strlen(objName);
UInt32 flags=0;
if (objName[0]=='*')
{
if (objName[len-1]=='*')
{
flags = kSubStringMatch; // *foo*
strncpy(tmpObjName, objName+1, strlen(objName)-2);
}
else
{
flags = kEndStringMatch; // *foo
strncpy(tmpObjName, objName+1, strlen(objName)-1);
}
}
if (!flags && objName[len-1]=='*')
{
flags = kStartStringMatch; // foo*
strncpy(tmpObjName, objName, strlen(objName)-1);
}
if (!flags)
{
flags = kExactStringMatch;
strcpy(tmpObjName, objName);
}
//
// set plLocation
//
plLocation loc;
if (pageName)
{
loc = plKeyFinder::Instance().FindLocation(NetCommGetAge()->ageDatasetName, pageName);
flags |= kPageMatch;
}
fDebugObjects.push_back(TRACKED_NEW DebugObject(tmpObjName, loc, flags));
ICreateStatusLog();
return true;
}
bool plNetObjectDebugger::RemoveDebugObject(const char* objName, const char* pageName)
{
bool didIt=false;
if (!pageName)
{
DebugObjectList::iterator it =fDebugObjects.begin();
for( ; it != fDebugObjects.end(); )
{
if ( (*it) && (*it)->ObjectMatches(objName, pageName))
{
delete *it;
it = fDebugObjects.erase(it);
didIt=true;
}
else
it++;
}
}
return didIt;
}
void plNetObjectDebugger::ClearAllDebugObjects()
{
DebugObjectList::iterator it =fDebugObjects.begin();
for( ; it != fDebugObjects.end(); it++)
{
delete *it;
}
fDebugObjects.clear();
}
//
// write to status log if there's a string match
//
void plNetObjectDebugger::LogMsgIfMatch(const char* msg) const
{
if (GetNumDebugObjects()==0 || !msg)
return;
// extract object name from msg, expects '...object:foo,...'
std::string tmp = msg;
hsStrLower((char*)tmp.c_str());
std::string objTag="object";
char* c=strstr(tmp.c_str(), objTag.c_str());
if (c && c != tmp.c_str())
{
c+=objTag.size();
// move past spaces
while ( *c || *c==' ' )
c++;
char objName[128];
int i=0;
// copy objName token
while(*c && *c != ',' && *c != ' ' && i<127)
objName[i++] = *c++;
objName[i]=0;
DebugObjectList::const_iterator it = fDebugObjects.begin();
for( objName[0]; it != fDebugObjects.end(); it++)
{
if ((*it) && (*it)->StringMatches(objName))
{
LogMsg(msg);
break;
}
}
}
}
void plNetObjectDebugger::LogMsg(const char* msg) const
{
DEBUG_MSG(msg);
}
bool plNetObjectDebugger::IsDebugObject(const hsKeyedObject* obj) const
{
DebugObjectList::const_iterator it =fDebugObjects.begin();
for( ; it != fDebugObjects.end(); it++)
if ((*it) && (*it)->ObjectMatches(obj))
{
return true;
}
return false;
}

View File

@ -0,0 +1,85 @@
/*==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==*/
#ifndef plNetObjectDebugger_inc
#define plNetObjectDebugger_inc
#include "hsTypes.h"
#include "hsStlUtils.h"
#include "../pnKeyedObject/plUoid.h"
#include "../pnNetCommon/plNetApp.h"
class hsKeyedObject;
class plStatusLog;
class plNetObjectDebugger : public plNetObjectDebuggerBase
{
public:
enum Flags
{
kExactStringMatch = 0x1,
kEndStringMatch = 0x2,
kStartStringMatch = 0x4,
kSubStringMatch = 0x8,
kPageMatch = 0x10 // has page info specified
};
private:
struct DebugObject
{
std::string fObjName;
plLocation fLoc;
UInt32 fFlags;
bool StringMatches(const char* str) const; // return true if string matches objName according to flags
bool ObjectMatches(const hsKeyedObject* obj);
bool ObjectMatches(const char* objName, const char* pageName);
DebugObject(const char* objName, plLocation& loc, UInt32 flags);
};
typedef std::vector<DebugObject*> DebugObjectList;
DebugObjectList fDebugObjects;
mutable plStatusLog* fStatusLog;
bool fDebugging;
void ICreateStatusLog() const;
public:
plNetObjectDebugger();
~plNetObjectDebugger();
static plNetObjectDebugger* GetInstance();
bool GetDebugging() const { return fDebugging; }
void SetDebugging(bool b) { fDebugging=b; }
// object fxns
bool AddDebugObject(const char* objName, const char* pageName=nil);
bool RemoveDebugObject(const char* objName, const char* pageName=nil);
void ClearAllDebugObjects();
int GetNumDebugObjects() const { return fDebugObjects.size(); }
bool IsDebugObject(const hsKeyedObject* obj) const;
void LogMsgIfMatch(const char* msg) const; // write to status log if there's a string match
void LogMsg(const char* msg) const;
};
#endif // plNetObjectDebugger_inc

View File

@ -0,0 +1,145 @@
/*==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 <algorithm>
#include "plgDispatch.h"
#include "plNetClientMgr.h"
#include "plNetVoiceList.h"
#include "../plNetTransport/plNetTransportMember.h"
#include "../pnMessage/plSoundMsg.h"
#include "../pnKeyedObject/plKey.h"
#include "../plStatusLog/plStatusLog.h"
// statics
float plNetListenList::kUpdateInterval=0.5f;
int plNetListenList::kMaxListenListSize=-1; // -1 is unlimited
float plNetListenList::kMaxListenDistSq=75.0f*75.0f;
int plNetVoiceList::FindMember(plNetTransportMember* e)
{
VoiceListType::iterator result = std::find(fMembers.begin(), fMembers.end(), e);
return result!=fMembers.end() ? result-fMembers.begin() : -1;
}
/*****************************************************************************
*
* plNetTalkList
*
***/
void plNetTalkList::UpdateTransportGroup(plNetClientMgr* nc)
{
if (fFlags & kDirty)
{
nc->fTransport.ClearChannelGrp(plNetClientMgr::kNetChanVoice);
if (nc->IsPeerToPeer())
{
int i;
for(i=0;i<GetNumMembers();i++)
{
if (GetMember(i)->IsPeerToPeer())
nc->fTransport.SubscribeToChannelGrp(GetMember(i), plNetClientMgr::kNetChanVoice);
}
}
fFlags &= ~kDirty;
}
}
void plNetTalkList::AddMember(plNetTransportMember* e)
{
if (FindMember(e)==-1)
{
plStatusLog::AddLineS("voice.log", "Adding %s to talk list", e->AsStdString().c_str());
fMembers.push_back(e);
}
fFlags |= kDirty;
}
void plNetTalkList::RemoveMember(plNetTransportMember* e)
{
int idx=FindMember(e);
if (idx!=-1)
{
plStatusLog::AddLineS("voice.log", "Removing %s from talklist", e->AsStdString().c_str());
fMembers.erase(fMembers.begin()+idx);
}
fFlags |= kDirty;
}
void plNetTalkList::Clear()
{
plNetVoiceList::Clear();
fFlags |= kDirty;
}
/*****************************************************************************
*
* plNetListenList
*
***/
void plNetListenList::AddMember(plNetTransportMember* e)
{
if (FindMember(e)==-1)
{
plStatusLog::AddLineS("voice.log", "Adding %s to listen list ", e->AsStdString().c_str());
fMembers.push_back(e);
#if 0
// call the new member's win audible and set talk icon parameters
plSoundMsg* pMsg = TRACKED_NEW plSoundMsg;
plArmatureMod* pMod = plArmatureMod::ConvertNoRef(e->GetAvatarKey()->GetObjectPtr());
if (pMod)
pMsg->AddReceiver(pMod->GetTarget(0)->GetKey());
pMsg->SetCmd(plSoundMsg::kSetTalkIcon);
pMsg->fIndex = GetNumMembers();
pMsg->fNameStr = (UInt32)e->GetName();
plgDispatch::MsgSend(pMsg);
#endif
}
}
void plNetListenList::RemoveMember(plNetTransportMember* e)
{
int idx=FindMember(e);
if (idx!=-1)
{
fMembers.erase(fMembers.begin()+idx);
plStatusLog::AddLineS("voice.log", "Removing %s from listen list", e->AsStdString().c_str());
#if 0
// call the new member's win audible and set talk icon parameters
plSoundMsg* pMsg = TRACKED_NEW plSoundMsg;
plArmatureMod* pMod = plArmatureMod::ConvertNoRef(e->GetAvatarKey()->GetObjectPtr());
if (pMod)
pMsg->AddReceiver(pMod->GetTarget(0)->GetKey());
pMsg->SetCmd(plSoundMsg::kClearTalkIcon);
plgDispatch::MsgSend(pMsg);
#endif
}
}

View File

@ -0,0 +1,107 @@
/*==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==*/
#ifndef plNetVoiceList_h
#define plNetVoiceList_h
#include "hsTypes.h"
#include "hsStlUtils.h"
//
// a simple class used by the net client code to hold listenLists and talkLists
// for voice filtering.
//
class plNetTransportMember;
class plNetVoiceList
{
protected:
typedef std::vector<plNetTransportMember*> VoiceListType;
protected:
VoiceListType fMembers;
public:
plNetVoiceList() {}
virtual ~plNetVoiceList() {}
int GetNumMembers() const { return fMembers.size(); }
plNetTransportMember* GetMember(int i) const { return fMembers[i]; }
virtual void AddMember(plNetTransportMember* e) = 0;
virtual void RemoveMember(plNetTransportMember* e) = 0;
virtual void Clear() { fMembers.clear(); }
int FindMember(plNetTransportMember* e); // return index or -1
};
//
// Specialized version for listen list
// a list of other player I am listening to
//
class plNetListenList : public plNetVoiceList
{
private:
double fLastUpdateTime;
int fNumUpdates;
public:
plNetListenList() : fNumUpdates(0) {}
~plNetListenList() {}
static float kUpdateInterval;
static int kMaxListenListSize;
static float kMaxListenDistSq;
void SetLastUpdateTime(double t) { fLastUpdateTime=t; fNumUpdates++; }
double GetLastUpdateTime() { return fLastUpdateTime; }
hsBool CheckForceSynch() { if (fNumUpdates>10) { fNumUpdates=0; return true;} return false; }
virtual void AddMember(plNetTransportMember* e);
virtual void RemoveMember(plNetTransportMember* e);
};
//
// Specialized version for talk list
// a list of other players I am talking to
//
class plNetClientMgr;
class plNetTalkList : public plNetVoiceList
{
private:
enum
{
kDirty = 0x1
};
UInt32 fFlags;
public:
plNetTalkList() : fFlags(0) {}
~plNetTalkList() {}
void UpdateTransportGroup(plNetClientMgr* nc);
void AddMember(plNetTransportMember* e);
void RemoveMember(plNetTransportMember* e);
void Clear();
};
#endif // plNetVoiceList_h