You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
547 lines
14 KiB
547 lines
14 KiB
/*==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 "plNetMsgHelpers.h" |
|
#include "plNetMessage.h" |
|
#include "plCompression/plZlibCompress.h" |
|
#include "pnNetCommon/plNetServers.h" |
|
#include "pnNetCommon/plNetApp.h" |
|
#include "pnKeyedObject/plKey.h" |
|
#include "pnMessage/plMessage.h" |
|
#include "hsStream.h" |
|
#include <algorithm> |
|
|
|
|
|
//////////////////////////////////////////////////////////////////// |
|
// plNetMsgStreamableHelper |
|
|
|
plNetMsgStreamableHelper & plNetMsgStreamableHelper::operator =(hsStreamable * value) |
|
{ |
|
fObject = value; |
|
return *this; |
|
} |
|
|
|
int plNetMsgStreamableHelper::Poke(hsStream* stream, UInt32 peekOptions) |
|
{ |
|
hsAssert(fObject, "plNetMsgStreamableHelper::Poke: fObject not set."); |
|
fObject->Write(stream); |
|
return stream->GetPosition(); |
|
} |
|
|
|
int plNetMsgStreamableHelper::Peek(hsStream* stream, UInt32 peekOptions) |
|
{ |
|
hsAssert(fObject, "plNetMsgStreamableHelper::Peek: fObject not set."); |
|
fObject->Read(stream); |
|
return stream->GetPosition(); |
|
} |
|
|
|
//////////////////////////////////////////////////////////////////// |
|
// plNetMsgCreatableHelper |
|
|
|
plNetMsgCreatableHelper::plNetMsgCreatableHelper(plCreatable * object) |
|
:fCreatable(object) |
|
,fWeCreatedIt(false) |
|
{ |
|
} |
|
|
|
plNetMsgCreatableHelper::~plNetMsgCreatableHelper() |
|
{ |
|
if (fWeCreatedIt) |
|
hsRefCnt_SafeUnRef(fCreatable); |
|
} |
|
|
|
plNetMsgCreatableHelper & plNetMsgCreatableHelper::operator =(plCreatable * value) |
|
{ |
|
SetObject(value); |
|
return *this; |
|
} |
|
|
|
plNetMsgCreatableHelper::operator plCreatable*() |
|
{ |
|
return GetObject(); |
|
} |
|
|
|
plNetMsgCreatableHelper::operator const plCreatable*() |
|
{ |
|
return GetObject(); |
|
} |
|
|
|
void plNetMsgCreatableHelper::SetObject(plCreatable * object) |
|
{ |
|
if (fWeCreatedIt) |
|
hsRefCnt_SafeUnRef(fCreatable); |
|
fCreatable = object; |
|
fWeCreatedIt = false; |
|
} |
|
|
|
plCreatable * plNetMsgCreatableHelper::GetObject() |
|
{ |
|
return fCreatable; |
|
} |
|
|
|
int plNetMsgCreatableHelper::Poke(hsStream * s, UInt32 peekOptions) |
|
{ |
|
hsAssert(fCreatable,"plNetMsgCreatableHelper::Poke: fCreatable not set"); |
|
UInt16 classIndex = fCreatable->ClassIndex(); |
|
s->WriteSwap(classIndex); |
|
fCreatable->Write(s,nil); |
|
return s->GetPosition(); |
|
} |
|
|
|
int plNetMsgCreatableHelper::Peek(hsStream * s, UInt32 peekOptions) |
|
{ |
|
UInt16 classIndex; |
|
s->LogSubStreamStart("push me"); |
|
s->LogReadSwap(&classIndex,"ClassIdx"); |
|
SetObject(plFactory::Create(classIndex)); |
|
fWeCreatedIt = true; |
|
hsAssert(fCreatable,"plNetMsgCreatableHelper::Peek: Failed to create plCreatable. Invalid ClassIndex?"); |
|
fCreatable->Read(s,nil); |
|
s->LogSubStreamEnd(); |
|
return s->GetPosition(); |
|
} |
|
|
|
|
|
///////////////////////////////////////////////////////// |
|
// NOT A MSG |
|
// PL STREAM MSG - HELPER class |
|
///////////////////////////////////////////////////////// |
|
plNetMsgStreamHelper::plNetMsgStreamHelper() : fStreamBuf(nil), fStreamType(-1), fStreamLen(0), |
|
fCompressionType(plNetMessage::kCompressionNone), fUncompressedSize(0), |
|
fCompressionThreshold( kDefaultCompressionThreshold ) |
|
{ |
|
} |
|
|
|
void plNetMsgStreamHelper::Clear() |
|
{ |
|
delete [] fStreamBuf; |
|
fStreamBuf = nil; |
|
fStreamType = 0xff; |
|
fStreamLen = 0; |
|
fCompressionType = plNetMessage::kCompressionNone; |
|
fCompressionThreshold = kDefaultCompressionThreshold; |
|
} |
|
|
|
int plNetMsgStreamHelper::Poke(hsStream* stream, UInt32 peekOptions) |
|
{ |
|
if ( !(peekOptions & plNetMessage::kDontCompress) ) |
|
Compress(); |
|
stream->WriteSwap(fUncompressedSize); |
|
stream->WriteSwap(fCompressionType); |
|
stream->WriteSwap(fStreamLen); |
|
stream->Write(fStreamLen, fStreamBuf); |
|
return stream->GetPosition(); |
|
} |
|
|
|
int plNetMsgStreamHelper::Peek(hsStream* stream, const UInt32 peekOptions) |
|
{ |
|
stream->LogSubStreamStart("Stream Helper"); |
|
stream->LogReadSwap(&fUncompressedSize,"UncompressedSize"); |
|
stream->LogReadSwap(&fCompressionType,"CompressionType"); |
|
stream->LogReadSwap(&fStreamLen,"StreamLen"); |
|
|
|
if (fStreamLen) // stream data exists |
|
{ |
|
if (!(peekOptions & plNetMessage::kSkipStream)) |
|
{ |
|
if (!fStreamBuf) |
|
IAllocStream(fStreamLen); |
|
stream->LogRead(fStreamLen, fStreamBuf,"StreamData"); |
|
if ( !(peekOptions & plNetMessage::kDontCompress) ) |
|
Uncompress(); |
|
fStreamType = *(Int16*)fStreamBuf; // grab from start fo stream |
|
} |
|
else |
|
{ |
|
stream->ReadSwap(&fStreamType); // never compressed, set by reading directly from stream |
|
stream->LogSkip(fStreamLen-sizeof(fStreamType),"SkippedStreamHelper"); |
|
} |
|
} |
|
stream->LogSubStreamEnd(); |
|
return stream->GetPosition(); |
|
} |
|
|
|
void plNetMsgStreamHelper::ReadVersion(hsStream* s, hsResMgr* mgr) |
|
{ |
|
hsBitVector contentFlags; |
|
contentFlags.Read(s); |
|
|
|
if (contentFlags.IsBitSet(kUncompressedSize)) |
|
s->ReadSwap(&fUncompressedSize); |
|
if (contentFlags.IsBitSet(kCompressionType)) |
|
s->ReadSwap(&fCompressionType); |
|
if (contentFlags.IsBitSet(kStreamLen)) |
|
s->ReadSwap(&fStreamLen); |
|
if (contentFlags.IsBitSet(kStreamBuf)) |
|
{ |
|
if (!fStreamBuf) |
|
IAllocStream(fStreamLen); |
|
s->Read(fStreamLen,fStreamBuf); |
|
} |
|
} |
|
|
|
void plNetMsgStreamHelper::WriteVersion(hsStream* s, hsResMgr* mgr) |
|
{ |
|
hsBitVector contentFlags; |
|
contentFlags.SetBit(kUncompressedSize); |
|
contentFlags.SetBit(kCompressionType); |
|
contentFlags.SetBit(kStreamLen); |
|
contentFlags.SetBit(kStreamBuf); |
|
contentFlags.Write(s); |
|
|
|
s->WriteSwap(fUncompressedSize); |
|
s->WriteSwap(fCompressionType); |
|
s->WriteSwap(fStreamLen); |
|
s->Write(fStreamLen,fStreamBuf); |
|
} |
|
|
|
void plNetMsgStreamHelper::IAllocStream(UInt32 len) |
|
{ |
|
delete [] fStreamBuf; |
|
fStreamBuf=nil; |
|
fStreamLen=len; |
|
if (len) |
|
fStreamBuf = TRACKED_NEW UInt8[len]; |
|
} |
|
|
|
void plNetMsgStreamHelper::CopyStream(hsStream* ssStream) |
|
{ |
|
UInt32 len=ssStream->GetEOF(); |
|
IAllocStream(len); |
|
ssStream->CopyToMem(fStreamBuf); |
|
fStreamType = *(Int16*)fStreamBuf; |
|
} |
|
|
|
void plNetMsgStreamHelper::CopyStream(Int32 len, const void* buf) |
|
{ |
|
IAllocStream(len); |
|
memcpy(fStreamBuf, buf, len); |
|
fStreamType = *(Int16*)fStreamBuf; |
|
} |
|
|
|
void plNetMsgStreamHelper::CopyFrom(const plNetMsgStreamHelper* other) |
|
{ |
|
fUncompressedSize = other->GetUncompressedSize(); |
|
fCompressionType = other->GetCompressionType(); |
|
CopyStream(other->GetStreamLen(), other->GetStreamBuf()); |
|
} |
|
|
|
bool plNetMsgStreamHelper::Compress(int offset) |
|
{ |
|
if ( !IsCompressable() ) |
|
return true; |
|
|
|
plZlibCompress compressor; |
|
UInt8* buf = (UInt8*)GetStreamBuf(); // skip creatable index |
|
UInt32 bufLen = GetStreamLen(); |
|
UInt32 uncompressedSize = bufLen; |
|
SetUncompressedSize( uncompressedSize ); |
|
if ( compressor.Compress( &buf, &bufLen, offset) ) |
|
{ |
|
SetCompressionType( plNetMessage::kCompressionZlib ); |
|
SetStreamLen(bufLen); |
|
SetStreamBuf(buf); |
|
Int32 diff = uncompressedSize-bufLen; |
|
#if 0 |
|
plNetApp::StaticDebugMsg( "\tCompressed stream: %lu->%lu bytes, (%s %d bytes, %.1f%%)", |
|
uncompressedSize, bufLen, (diff>=0)?"shrunk":"GREW?!?", diff, (diff/(float)uncompressedSize)*100 ); |
|
#endif |
|
return true; |
|
} |
|
else |
|
{ |
|
hsAssert( false, "plNetMsgStreamHelper: Compression failed" ); |
|
SetCompressionType( plNetMessage::kCompressionFailed ); |
|
return false; |
|
} |
|
} |
|
|
|
bool plNetMsgStreamHelper::Uncompress(int offset) |
|
{ |
|
if ( !IsCompressed() ) |
|
return true; |
|
|
|
UInt32 origLen = GetStreamLen(); |
|
plZlibCompress compressor; |
|
UInt8* buf = (UInt8*)GetStreamBuf(); |
|
UInt32 bufLen = origLen; |
|
if ( compressor.Uncompress( &buf, &bufLen, GetUncompressedSize(), offset ) ) |
|
{ |
|
SetCompressionType( plNetMessage::kCompressionNone ); |
|
SetStreamLen(bufLen); |
|
SetStreamBuf(buf); |
|
Int32 diff = bufLen-origLen; |
|
#if 0 |
|
plNetApp::StaticDebugMsg( "\tUncompressed stream: %lu->%lu bytes, (%s %d bytes, %.1f%%)", |
|
origLen, bufLen, (diff>=0)?"grew":"SHRUNK?!?", diff, (diff/(float)bufLen)*100 ); |
|
#endif |
|
return true; |
|
} |
|
else |
|
{ |
|
hsAssert( false, "plNetMsgStreamHelper: Uncompression failed" ); |
|
SetCompressionType( plNetMessage::kCompressionFailed ); |
|
return false; |
|
} |
|
} |
|
|
|
bool plNetMsgStreamHelper::IsCompressed() const |
|
{ |
|
return ( fCompressionType==plNetMessage::kCompressionZlib ); |
|
} |
|
|
|
bool plNetMsgStreamHelper::IsCompressable() const |
|
{ |
|
return ( fCompressionType==plNetMessage::kCompressionNone |
|
&& fStreamLen>fCompressionThreshold ); |
|
} |
|
|
|
|
|
|
|
//////////////////////////////////////////////////////// |
|
// NOT A MSG |
|
// plNetMsgObject - HELPER class |
|
//////////////////////////////////////////////////////// |
|
|
|
plNetMsgObjectHelper & plNetMsgObjectHelper::operator =(const plNetMsgObjectHelper & other) |
|
{ |
|
fUoid = other.GetUoid(); |
|
return *this; |
|
} |
|
|
|
int plNetMsgObjectHelper::Poke(hsStream* stream, UInt32 peekOptions) |
|
{ |
|
fUoid.Write(stream); |
|
|
|
return stream->GetPosition(); |
|
} |
|
|
|
int plNetMsgObjectHelper::Peek(hsStream* stream, const UInt32 peekOptions) |
|
{ |
|
stream->LogSubStreamStart("push me"); |
|
fUoid.Read(stream); |
|
stream->LogSubStreamEnd(); |
|
return stream->GetPosition(); |
|
} |
|
|
|
hsBool plNetMsgObjectHelper::SetFromKey(const plKey &key) |
|
{ |
|
if (!key || !key->GetName()) |
|
return false; |
|
|
|
fUoid = key->GetUoid(); |
|
|
|
return true; |
|
} |
|
|
|
void plNetMsgObjectHelper::ReadVersion(hsStream* s, hsResMgr* mgr) |
|
{ |
|
hsBitVector contentFlags; |
|
contentFlags.Read(s); |
|
|
|
if (contentFlags.IsBitSet(kObjHelperUoid)) |
|
fUoid.Read(s); |
|
} |
|
|
|
void plNetMsgObjectHelper::WriteVersion(hsStream* s, hsResMgr* mgr) |
|
{ |
|
hsBitVector contentFlags; |
|
contentFlags.SetBit(kObjHelperUoid); |
|
contentFlags.Write(s); |
|
|
|
// kObjHelperUoid |
|
fUoid.Write(s); |
|
} |
|
|
|
//////////////////////////////////////////////////////// |
|
// NOT A MSG |
|
// plNetMsgObjectList - HELPER class |
|
//////////////////////////////////////////////////////// |
|
plNetMsgObjectListHelper::~plNetMsgObjectListHelper() |
|
{ |
|
Reset(); |
|
} |
|
|
|
void plNetMsgObjectListHelper::Reset() |
|
{ |
|
int i; |
|
for( i=0 ; i<GetNumObjects() ; i++ ) |
|
{ |
|
delete GetObject(i); |
|
fObjects[i] = nil; |
|
} // for |
|
fObjects.clear(); |
|
} |
|
|
|
int plNetMsgObjectListHelper::Poke(hsStream* stream, UInt32 peekOptions) |
|
{ |
|
Int16 num = GetNumObjects(); |
|
stream->WriteSwap(num); |
|
int i; |
|
for( i=0 ;i<num ;i++ ) |
|
{ |
|
GetObject(i)->Poke(stream, peekOptions); |
|
} // for |
|
|
|
return stream->GetPosition(); |
|
} |
|
|
|
int plNetMsgObjectListHelper::Peek(hsStream* stream, const UInt32 peekOptions) |
|
{ |
|
Reset(); |
|
|
|
stream->LogSubStreamStart("push me"); |
|
Int16 num; |
|
stream->LogReadSwap(&num,"ObjectListHelper Num"); |
|
|
|
int i; |
|
for( i=0 ;i<num ;i++ ) |
|
{ |
|
fObjects.push_back(TRACKED_NEW plNetMsgObjectHelper); |
|
GetObject(i)->Peek(stream, peekOptions); |
|
} // for |
|
stream->LogSubStreamEnd(); |
|
return stream->GetPosition(); |
|
} |
|
|
|
//////////////////////////////////////////////////////// |
|
// NOT A MSG |
|
// plNetMsgMemberInfoHelper - HELPER class |
|
//////////////////////////////////////////////////////// |
|
plNetMsgMemberInfoHelper::plNetMsgMemberInfoHelper() |
|
: fFlags(0) |
|
{ |
|
} |
|
|
|
int plNetMsgMemberInfoHelper::Peek(hsStream* s, const UInt32 peekOptions) |
|
{ |
|
s->LogSubStreamStart("push me"); |
|
s->LogReadSwap(&fFlags,"MemberInfoHelper Flags"); |
|
fClientGuid.Read( s, nil ); |
|
fAvatarUoid.Read(s); |
|
s->LogSubStreamEnd(); |
|
return s->GetPosition(); |
|
} |
|
|
|
int plNetMsgMemberInfoHelper::Poke(hsStream* s, const UInt32 peekOptions) |
|
{ |
|
s->WriteSwap(fFlags); |
|
fClientGuid.Write( s, nil ); |
|
fAvatarUoid.Write(s); |
|
return s->GetPosition(); |
|
} |
|
|
|
//////////////////////////////////////////////////////// |
|
// NOT A MSG |
|
// plNetMsgMemberListHelper - HELPER class |
|
//////////////////////////////////////////////////////// |
|
plNetMsgMemberListHelper::~plNetMsgMemberListHelper() |
|
{ |
|
int i; |
|
for(i=0;i<GetNumMembers();i++) |
|
delete fMembers[i]; |
|
} |
|
|
|
int plNetMsgMemberListHelper::Peek(hsStream* stream, const UInt32 peekOptions) |
|
{ |
|
Int16 numMembers; |
|
stream->LogSubStreamStart("push me"); |
|
stream->LogReadSwap(&numMembers,"MemberListHelper NumMembers"); |
|
fMembers.clear(); |
|
int i; |
|
for(i=0;i<numMembers;i++) |
|
{ |
|
plNetMsgMemberInfoHelper* addr=TRACKED_NEW plNetMsgMemberInfoHelper; |
|
addr->Peek(stream, peekOptions); |
|
AddMember(addr); |
|
} |
|
stream->LogSubStreamEnd(); |
|
return stream->GetPosition(); |
|
} |
|
|
|
int plNetMsgMemberListHelper::Poke(hsStream* stream, const UInt32 peekOptions) |
|
{ |
|
Int16 numMembers = (Int16)GetNumMembers(); |
|
stream->WriteSwap(numMembers); |
|
|
|
int i; |
|
for(i=0;i<numMembers;i++) |
|
{ |
|
fMembers[i]->GetClientGuid()->SetClientKey(""); |
|
fMembers[i]->GetClientGuid()->SetAccountUUID(plUUID()); |
|
fMembers[i]->Poke(stream, peekOptions); |
|
} |
|
|
|
return stream->GetPosition(); |
|
} |
|
|
|
|
|
//////////////////////////////////////////////////////// |
|
// NOT A MSG |
|
// plNetMsgReceiversListHelper - HELPER class |
|
//////////////////////////////////////////////////////// |
|
|
|
int plNetMsgReceiversListHelper::Peek(hsStream* stream, const UInt32 peekOptions) |
|
{ |
|
UInt8 numIDs; |
|
stream->LogSubStreamStart("push me"); |
|
stream->LogReadSwap(&numIDs,"ReceiversListHelper NumIDs"); |
|
|
|
fPlayerIDList.clear(); |
|
int i; |
|
for(i=0;i<numIDs;i++) |
|
{ |
|
UInt32 ID; |
|
stream->LogReadSwap(&ID,"ReceiversListHelper ID"); |
|
AddReceiverPlayerID(ID); |
|
} |
|
stream->LogSubStreamEnd(); |
|
return stream->GetPosition(); |
|
} |
|
|
|
int plNetMsgReceiversListHelper::Poke(hsStream* stream, const UInt32 peekOptions) |
|
{ |
|
UInt8 numIDs = (UInt8)GetNumReceivers(); |
|
stream->WriteSwap(numIDs); |
|
|
|
int i; |
|
for(i=0;i<numIDs;i++) |
|
stream->WriteSwap(GetReceiverPlayerID(i)); |
|
|
|
return stream->GetPosition(); |
|
} |
|
|
|
|
|
bool plNetMsgReceiversListHelper::RemoveReceiverPlayerID(UInt32 n) |
|
{ |
|
std::vector<UInt32>::iterator res = std::find(fPlayerIDList.begin(), fPlayerIDList.end(), n); |
|
if (res != fPlayerIDList.end()) |
|
{ |
|
fPlayerIDList.erase(res); |
|
return true; |
|
} |
|
return false; |
|
} |
|
|
|
|