mirror of
https://foundry.openuru.org/gitblit/r/CWE-ou-minkata.git
synced 2025-07-21 04:39:45 +00:00
Hoist MOULOpenSourceClientPlugin/Plasma20/* to top level
to match H'uru layout and make patching/cherry-picking easier.
This commit is contained in:
563
Sources/Plasma/PubUtilLib/plNetMessage/plNetMsgHelpers.cpp
Normal file
563
Sources/Plasma/PubUtilLib/plNetMessage/plNetMsgHelpers.cpp
Normal file
@ -0,0 +1,563 @@
|
||||
/*==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 "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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user