|
|
|
/*==LICENSE==*
|
|
|
|
|
|
|
|
CyanWorlds.com Engine - MMOG client, server and tools
|
|
|
|
Copyright (C) 2011 Cyan Worlds, Inc.
|
|
|
|
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
Additional permissions under GNU GPL version 3 section 7
|
|
|
|
|
|
|
|
If you modify this Program, or any covered work, by linking or
|
|
|
|
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
|
|
|
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
|
|
|
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
|
|
|
(or a modified version of those libraries),
|
|
|
|
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
|
|
|
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
|
|
|
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
|
|
|
licensors of this Program grant you additional
|
|
|
|
permission to convey the resulting work. Corresponding Source for a
|
|
|
|
non-source form of such a combination shall include the source code for
|
|
|
|
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
|
|
|
work.
|
|
|
|
|
|
|
|
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
|
|
|
or by snail mail at:
|
|
|
|
Cyan Worlds, Inc.
|
|
|
|
14617 N Newport Hwy
|
|
|
|
Mead, WA 99021
|
|
|
|
|
|
|
|
*==LICENSE==*/
|
|
|
|
#include "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 "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_t port = mbi->GetClientGuid()->GetSrcPort();
|
|
|
|
uint32_t addr = mbi->GetClientGuid()->GetSrcAddr();
|
|
|
|
uint32_t flags = mbi->GetFlags();
|
|
|
|
uint32_t 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 = 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_t 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());
|
|
|
|
plString descName;
|
|
|
|
int ver;
|
|
|
|
plStateDataRecord::ReadStreamHeader(&stream, &descName, &ver);
|
|
|
|
plStateDescriptor* des = plSDLMgr::GetInstance()->FindDescriptor(descName, ver);
|
|
|
|
|
|
|
|
if (descName.CompareI(kSDLAvatarPhysical) == 0)
|
|
|
|
rwFlags |= plSDL::kKeepDirty;
|
|
|
|
|
|
|
|
//
|
|
|
|
// ERROR CHECK SDL FILE
|
|
|
|
//
|
|
|
|
plStateDataRecord* sdRec = des ? new plStateDataRecord(des) : nil;
|
|
|
|
if (!sdRec || sdRec->GetDescriptor()->GetVersion()!=ver)
|
|
|
|
{
|
|
|
|
plString err;
|
|
|
|
if (!sdRec)
|
|
|
|
err = plFormat("SDL descriptor {} missing, v={}", descName, ver);
|
|
|
|
else
|
|
|
|
err = plFormat("SDL descriptor {}, version mismatch, server v={}, client v={}",
|
|
|
|
descName, ver, sdRec->GetDescriptor()->GetVersion());
|
|
|
|
|
|
|
|
hsAssert(false, err.c_str());
|
|
|
|
nc->ErrorMsg(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 = new plStateDataRecord(des);
|
|
|
|
stateRec->SetFromDefaults(false);
|
|
|
|
stateRec->UpdateFrom(*sdRec, rwFlags);
|
|
|
|
|
|
|
|
delete sdRec;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
stateRec = sdRec;
|
|
|
|
|
|
|
|
plNetClientMgr::PendingLoad* pl = 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().c_str(), des->GetName().c_str() ) );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
delete sdRec;
|
|
|
|
|
|
|
|
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 = 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);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Do some basic security checks on the incoming message because
|
|
|
|
// we cannot nesecarily trust the server because the server trusts
|
|
|
|
// the remote client WAY too much.
|
|
|
|
if (!IGetNetClientMgr()->fScreener.AllowIncomingMessage(gameMsg))
|
|
|
|
return hsOK;
|
|
|
|
|
|
|
|
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();
|
|
|
|
uint8_t flags = m->GetFlags();
|
|
|
|
uint8_t numFrames = m->GetNumFrames();
|
|
|
|
plKey key;
|
|
|
|
|
|
|
|
// 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 = new plNetTransportMember(nc);
|
|
|
|
IFillInTransportMember(m->MemberListInfo()->GetMember(i), mbr);
|
|
|
|
hsLogEntry(nc->DebugMsg("\tAdding transport member, name=%s, p2p=%d, plrID=%d\n", mbr->AsString().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 = 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 = 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 = 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 = 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.
|