/*==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; }