/*==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 .
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
////////////////////////////////////////////////////////////////////
// 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 ; iWriteSwap(num);
int i;
for( i=0 ;iPoke(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 ;iPeek(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;iLogSubStreamStart("push me");
stream->LogReadSwap(&numMembers,"MemberListHelper NumMembers");
fMembers.clear();
int i;
for(i=0;iPeek(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;iGetClientGuid()->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;iLogReadSwap(&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;iWriteSwap(GetReceiverPlayerID(i));
return stream->GetPosition();
}
bool plNetMsgReceiversListHelper::RemoveReceiverPlayerID(UInt32 n)
{
std::vector::iterator res = std::find(fPlayerIDList.begin(), fPlayerIDList.end(), n);
if (res != fPlayerIDList.end())
{
fPlayerIDList.erase(res);
return true;
}
return false;
}