/*==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 .
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==*/
#ifndef plNetMessage_h_inc
#define plNetMessage_h_inc
#include "hsUtils.h"
#include "hsTypes.h"
#include "hsStlUtils.h"
#include "hsStream.h"
#include "hsBitVector.h"
#include "hsTemplates.h"
#include "plGeneric.h"
#include "pnNetCommon/plNetServers.h"
#include "pnNetCommon/plNetGroup.h"
#include "pnFactory/plCreatable.h"
#include "pnFactory/plFactory.h"
#include "plUnifiedTime/plClientUnifiedTime.h"
#include "plNetCommon/plNetServerSessionInfo.h"
#include "plNetCommon/plNetCommon.h"
#include "plNetCommon/plNetCommonHelpers.h"
#include "plNetCommon/plNetCommonConstants.h"
#include "plStreamLogger/plStreamLogger.h"
#include "plNetMsgHelpers.h"
#include "pnNetBase/pnNetBase.h"
#include
class plMessage;
class plUUID;
////////////////////////////////////////////////////////////////////
//
// Base class for application network messages.
// These become the data in a plNetCommonMessage when sent over the network.
//
class plNetCommonMessage;
class plKey;
class plNetMessage : public plCreatable
{
friend class plNetServerMsgPlsRoutableMsg;
UInt32 fFlags; // indicates what is present in the message, always transmitted
plUnifiedTime fTimeSent; // time msg was sent (in sender's unified timeSpace), always transmitted to and from the client
double fTimeRecvd; // time msg was recvd (in rcvrs timeSpace), never transmitted
UInt32 fBytesRead; // amount of data we've already read, never transmitted
UInt32 fContext; // set by sender, included in reply. Only written if kHasContext flag set
UInt32 fTransactionID; // set by originator, included in reply. Only written if kHasTransactionID flag set
UInt32 fPlayerID; // set by originator. Only written if kHasPlayerID flag set
plUUID fAcctUUID; // set by sender (app level). Only written if kHasAcctUUID flag set
const plNetCommonMessage* fNetCoreMsg; // not sent, set by the receiver
UInt32 fPeekStatus; // not sent. set on PeekBuffer, cleared on PokeBuffer
UInt8 fProtocolVerMajor; // conditionally sent
UInt8 fProtocolVerMinor; // conditionally sent
ENetProtocol fNetProtocol; // the server this msg should be sent to. this value is not sent over wire.
enum ContentFlags
{
kNetMsgFlags,
kNetMsgTimeSent,
kNetMsgContext,
kNetMsgTransactionID,
kNetMsgPlayerID,
kNetMsgVersion,
};
protected:
virtual int IPokeBuffer(hsStream* stream, UInt32 peekOptions=0);
virtual int IPeekBuffer(hsStream* stream, UInt32 peekOptions=0);
void IWriteClassIndex(hsStream* stream);
void IReadClassIndex(hsStream* stream);
bool IPeeked() const { return fPeekStatus==kFullyPeeked;}
void ISetPeekStatus(UInt32 s) { fPeekStatus=s; }
public:
typedef UInt16 plStrLen;
static const UInt8 kVerMajor, kVerMinor; // version of the networking code
typedef UInt16 ClassIndexType; // the type returned by plCreatable::ClassIndex()
enum
{
kMaxNameLen=32
};
enum BitVectorFlags // indicates what is present in the message, always transmitted
{
kHasTimeSent = 0x1, // means fTimeSent need sending
kHasGameMsgRcvrs = 0x2, // means that this is a direct (not bcast) game msg
kEchoBackToSender = 0x4, // if broadcasting, echo packet back to sender
kRequestP2P = 0x8, // sent to gameServer on joinReq
kAllowTimeOut = 0x10, // sent to gameServer on joinReq (if release code)
kIndirectMember = 0x20, // sent to client on joinAck if he is behind a firewall
// This flag is used when the servers are firewalled and NAT'ed
// It tells a game or lobby server to ask the lookup for an external address
kPublicIPClient = 0x40, // set on a client coming from a public IP
kHasContext = 0x80, // whether or not to write fContext field
// Used with StartProcess server msgs. Whether or not the ServerAgent
// must first ask the vault for a game state associated with the
// game about to be instanced.
kAskVaultForGameState =0x100,
kHasTransactionID = 0x200, // whether or not to write fTransactionID field
kNewSDLState = 0x400, // set by client on first state packet sent, may not be necessary anymore
kInitialAgeStateRequest = 0x800,// initial request for the age state
kHasPlayerID = 0x1000, // is fPlayerID set
kUseRelevanceRegions= 0x2000, // if players use relevance regions are used, this will be filtered by region, currently set on avatar physics and control msgs
kHasAcctUUID = 0x4000, // is fAcctUUID set
kInterAgeRouting = 0x8000, // give to pls for routing.
kHasVersion = 0x10000, // if version is set
kIsSystemMessage = 0x20000,
kNeedsReliableSend = 0x40000,
kRouteToAllPlayers = 0x80000, // send this message to all online players.
};
enum PeekOptions // options for partial peeking
{
kSkipStream = 1<<0, // means we should not read the actual stream, just the stream info
kBaseClassOnly = 1<<1, // only peek or poke the baseclass info
kPartialPeekMask = kSkipStream | kBaseClassOnly,
// plNetServerMsgWithRoutingInfo derived classes need to check this
// in their PeekBuffer methods.
kJustRoutingInfo = 1<<2,
kDontClearBuffer = 1<<3,
// don't call base class peek/poke. plNetMsgOmnibus/plNetMsgVault uses this.
kDEAD_NoBaseClass = 1<<4,
// don't worry about compressing/uncompressing things. used by plNetMsgStreamHelper, and plNetMsgOmnibus.
kDontCompress = 1<<5,
kWantVersion = 1<<6,
kFullyPeeked = 0xffffffff // default fPeekStatus, set if not partial peeking
};
enum CompressionType // currently only used for plNetMsgStreams
{
kCompressionNone, // not compressed
kCompressionFailed, // failed to compress
kCompressionZlib, // zlib compressed
kCompressionDont // don't compress
};
CLASSNAME_REGISTER( plNetMessage );
GETINTERFACE_ANY( plNetMessage, plCreatable );
// plCreatable
void Read(hsStream* s, hsResMgr* mgr);
void Write(hsStream* s, hsResMgr* mgr);
void ReadVersion(hsStream* s, hsResMgr* mgr);
void WriteVersion(hsStream* s, hsResMgr* mgr);
// ctor
plNetMessage();
virtual ~plNetMessage();
static plNetMessage* CreateAndRead(const plNetCommonMessage*, plStreamLogger::EventList* el = nil);
static plNetMessage* Create(const plNetCommonMessage*);
int PokeBuffer(char* buf, int bufLen, UInt32 peekOptions=0); // put msg in buffer
int PeekBuffer(const char* buf, int bufLen, UInt32 peekOptions=0, bool forcePeek=false, plStreamLogger::EventList* el = nil); // get msg out of buffer
bool NeedsReliableSend() const { return IsBitSet(kNeedsReliableSend); }
bool IsSystemMessage() const { return IsBitSet(kIsSystemMessage); }
virtual void ValidatePoke() const;
virtual void ValidatePeek() const;
virtual bool NeedsBroadcast() const { return false; } // should game server broadcast this message to other clients?
virtual int ValidationSchemeID() const { return 1; }
// getters
int GetPackSize();
const plUnifiedTime& GetTimeSent() const { return fTimeSent; }
bool GetHasTimeSent() const { return IsBitSet(kHasTimeSent); }
double GetTimeReceived() const { return fTimeRecvd; }
bool IsBitSet(int b) const { return (fFlags & b) != 0; }
const plNetCommonMessage* GetNetCoreMsg() const { return fNetCoreMsg; }
UInt32 GetNetCoreMsgLen() const;
bool GetHasContext() const { return IsBitSet(kHasContext);}
UInt32 GetContext() const { return fContext;}
bool GetHasTransactionID() const { return IsBitSet(kHasTransactionID);}
UInt32 GetTransactionID() const { return fTransactionID;}
bool GetHasPlayerID() const { return IsBitSet(kHasPlayerID);}
UInt32 GetPlayerID() const { hsAssert(GetHasPlayerID(), "uninit playerID"); return fPlayerID; }
UInt32 JustGetPlayerID() const { return fPlayerID; }
bool GetHasAcctUUID() const { return IsBitSet(kHasAcctUUID); }
const plUUID * GetAcctUUID() const { return &fAcctUUID; }
UInt8 GetVersionMajor() const { return fProtocolVerMajor; }
UInt8 GetVersionMinor() const { return fProtocolVerMinor; }
ENetProtocol GetNetProtocol () const { return fNetProtocol; }
// setters
void SetTimeSent(const plUnifiedTime& t) { fTimeSent=t;SetHasTimeSent(true); }
void SetHasTimeSent(bool value) { SetBit( kHasTimeSent, value ); }
void SetTimeReceived(double t) { fTimeRecvd=t; }
void SetBit(int b, bool on=true) { if (on) fFlags |= b; else fFlags &= ~b; }
void SetNetCoreMsg(const plNetCommonMessage* ncmsg) { fNetCoreMsg=ncmsg; }
void SetHasContext(bool value) { SetBit(kHasContext,value);}
void SetContext(UInt32 value) { fContext=value; SetHasContext(true);}
void SetHasTransactionID(bool value) { SetBit(kHasTransactionID,value);}
void SetTransactionID(UInt32 value) { fTransactionID=value; SetHasTransactionID(true);}
void SetHasPlayerID(bool value) { SetBit(kHasPlayerID,value);}
void SetPlayerID(UInt32 value) { fPlayerID=value; SetHasPlayerID(true);}
void SetHasAcctUUID( bool v ) { SetBit( kHasAcctUUID,v ); }
void SetAcctUUID(const plUUID * v ) { fAcctUUID.CopyFrom(v); SetHasAcctUUID(true); }
void SetVersion(UInt8 maj=kVerMajor, UInt8 min=kVerMinor) { SetBit(kHasVersion); fProtocolVerMajor=maj; fProtocolVerMinor=min; }
void SetNetProtocol (ENetProtocol v ) { fNetProtocol = v; }
// init fContext, fTransactionID, etc. if needed.
void InitReplyFieldsFrom(plNetMessage * msg);
// debug
virtual std::string AsStdString() const
{
char * delim = "";
std::stringstream ss;
if ( GetHasPlayerID() )
{
ss << delim << "p:" << GetPlayerID();
delim = ",";
}
if ( GetHasTransactionID() )
{
ss << delim << "x:" << GetTransactionID();
delim = ",";
}
if ( GetHasAcctUUID() )
{
ss << delim << "a:" << GetAcctUUID()->AsStdString();
delim = ",";
}
if ( IsBitSet(kHasVersion) )
{
ss << delim << "v:" << (int)fProtocolVerMajor << "." << (int)fProtocolVerMinor;
delim = ",";
}
return ss.str().c_str();
}
};
//
// for msgs which only go from the gameserver to the client
//
class plNetMsgServerToClient : public plNetMessage
{
public:
plNetMsgServerToClient() { SetBit(kIsSystemMessage|kNeedsReliableSend); }
CLASSNAME_REGISTER( plNetMsgServerToClient );
GETINTERFACE_ANY( plNetMsgServerToClient, plNetMessage );
};
////////////////////////////////////////////////////////////////////
// Stream msg - abstract base class built with plNetMsgStreamHelper
//
class plNetMsgStream : public plNetMessage
{
protected:
plNetMsgStreamHelper fStreamHelper;
int IPokeBuffer(hsStream* stream, UInt32 peekOptions=0);
int IPeekBuffer(hsStream* stream, UInt32 peekOptions=0);
public:
CLASSNAME_REGISTER( plNetMsgStream );
GETINTERFACE_ANY_AUX(plNetMsgStream,plNetMessage,plNetMsgStreamHelper,fStreamHelper)
plNetMsgStreamHelper* StreamInfo() { return &fStreamHelper; }
const plNetMsgStreamHelper* StreamInfo() const { return &fStreamHelper; }
};
//
// Object info msg - abstract base class built with plNetMsgObjectHelper
//
class plNetMsgObject : public plNetMessage
{
private:
enum ContentFlags
{
kNetMsgObjectHelper,
};
protected:
plNetMsgObjectHelper fObjectHelper;
int IPokeBuffer(hsStream* stream, UInt32 peekOptions=0);
int IPeekBuffer(hsStream* stream, UInt32 peekOptions=0);
public:
CLASSNAME_REGISTER( plNetMsgObject );
GETINTERFACE_ANY_AUX(plNetMsgObject,plNetMessage,plNetMsgObjectHelper,fObjectHelper)
plNetMsgObjectHelper* ObjectInfo() { return &fObjectHelper; }
const plNetMsgObjectHelper* ObjectInfo() const { return &fObjectHelper; }
void ReadVersion(hsStream* s, hsResMgr* mgr);
void WriteVersion(hsStream* s, hsResMgr* mgr);
// debug
std::string AsStdString() const
{
std::string s;
char tmp[256];
xtl::format(s,"object=%s, %s",fObjectHelper.GetUoid().StringIze(tmp), plNetMessage::AsStdString().c_str());
return s;
}
};
//
// abstract baseclass which has both object and stream info
//
class plNetMsgStreamedObject : public plNetMsgObject
{
private:
enum ContentFlags
{
kStreamHelper
};
protected:
plNetMsgStreamHelper fStreamHelper;
int IPokeBuffer(hsStream* stream, UInt32 peekOptions=0);
int IPeekBuffer(hsStream* stream, UInt32 peekOptions=0);
public:
plNetMsgStreamedObject() {}
~plNetMsgStreamedObject() {}
CLASSNAME_REGISTER( plNetMsgStreamedObject );
GETINTERFACE_ANY_AUX(plNetMsgStreamedObject,plNetMsgObject,plNetMsgStreamHelper,fStreamHelper)
plNetMsgStreamHelper* StreamInfo() { return &fStreamHelper; }
const plNetMsgStreamHelper* StreamInfo() const { return &fStreamHelper; }
//virtuals
void ReadVersion(hsStream* s, hsResMgr* mgr);
void WriteVersion(hsStream* s, hsResMgr* mgr);
};
//
// New SaveState system
//
class plNetMsgSDLState : public plNetMsgStreamedObject
{
private:
enum ContentFlags
{
kSDLStateStream,
kSDLIsInitialState,
kSDLPersist,
kSDLAvatarState,
};
void ISetDescName() const;
bool fIsInitialState;
protected:
int IPokeBuffer(hsStream* stream, UInt32 peekOptions=0);
int IPeekBuffer(hsStream* stream, UInt32 peekOptions=0);
bool fPersistOnServer;
bool fIsAvatarState;
mutable std::string fDescName; // for debugging output only, not read/written
public:
CLASSNAME_REGISTER( plNetMsgSDLState );
GETINTERFACE_ANY(plNetMsgSDLState, plNetMsgStreamedObject);
plNetMsgSDLState() : fIsInitialState(0), fPersistOnServer(true), fIsAvatarState(false) { SetBit(kNeedsReliableSend); }
bool PersistOnServer() const { return fPersistOnServer != 0; }
void SetPersistOnServer(bool b) { fPersistOnServer = b; }
bool IsAvatarState() const { return fIsAvatarState != 0; }
void SetIsAvatarState(bool b) { fIsAvatarState = b; }
// debug
std::string AsStdString() const;
bool IsInitialState() const {return fIsInitialState!=0; }
void SetIsInitialState( bool v ) { fIsInitialState=v; }
void ReadVersion(hsStream* s, hsResMgr* mgr);
void WriteVersion(hsStream* s, hsResMgr* mgr);
};
//
// New SaveState system
//
class plNetMsgSDLStateBCast : public plNetMsgSDLState
{
protected:
int IPokeBuffer(hsStream* stream, UInt32 peekOptions=0);
int IPeekBuffer(hsStream* stream, UInt32 peekOptions=0);
public:
CLASSNAME_REGISTER( plNetMsgSDLStateBCast );
GETINTERFACE_ANY(plNetMsgSDLStateBCast, plNetMsgSDLState);
// virtuals
bool NeedsBroadcast() const { return true; }
void ReadVersion(hsStream* s, hsResMgr* mgr);
void WriteVersion(hsStream* s, hsResMgr* mgr);
};
//
// Object state request msg
//
class plNetMsgObjStateRequest : public plNetMsgObject
{
public:
plNetMsgObjStateRequest() { SetBit(kIsSystemMessage|kNeedsReliableSend); }
CLASSNAME_REGISTER( plNetMsgObjStateRequest );
GETINTERFACE_ANY( plNetMsgObjStateRequest, plNetMsgObject );
};
//
// abstract message class which contains a list of rooms
//
class plNetMsgRoomsList : public plNetMessage
{
protected:
std::vector fRooms;
std::vector fRoomNames; // for debug usage only
int IPokeBuffer(hsStream* stream, UInt32 peekOptions=0);
int IPeekBuffer(hsStream* stream, UInt32 peekOptions=0);
public:
plNetMsgRoomsList() {}
~plNetMsgRoomsList();
CLASSNAME_REGISTER( plNetMsgRoomsList );
GETINTERFACE_ANY( plNetMsgRoomsList, plNetMessage );
void AddRoom(plKey rmKey);
void AddRoomLocation(plLocation loc, const char* rmName);
int FindRoomLocation(plLocation loc);
int GetNumRooms() const { return fRooms.size(); }
plLocation GetRoomLoc(int i) const { return fRooms[i]; }
const char* GetRoomName(int i) const { return fRoomNames[i]; } // debug
};
//
// Game msg - wraps a plMessage.
//
class hsResMgr;
class plNetMsgGameMessage: public plNetMsgStream
{
protected:
plClientUnifiedTime fDeliveryTime; // for future timestamping
int IPokeBuffer(hsStream* stream, UInt32 peekOptions=0);
int IPeekBuffer(hsStream* stream, UInt32 peekOptions=0);
public:
plNetMsgGameMessage() { SetBit(kNeedsReliableSend); }
CLASSNAME_REGISTER( plNetMsgGameMessage );
GETINTERFACE_ANY( plNetMsgGameMessage, plNetMsgStream );
enum ContentsFlags
{
kNetGameMsgDeliveryTime,
kNetGameMsgGameMsg,
};
plClientUnifiedTime& GetDeliveryTime() { return fDeliveryTime; }
void SetDeliveryTime(plClientUnifiedTime& ut) { fDeliveryTime=ut; }
plMessage* GetContainedMsg(hsResMgr* resmgr = nil);
// virtuals
bool NeedsBroadcast() const { return true; }
void ReadVersion(hsStream* s, hsResMgr* mgr);
void WriteVersion(hsStream* s, hsResMgr* mgr);
// debug
std::string AsStdString() const
{
std::string s;
const char* noc=plFactory::GetTheFactory()->GetNameOfClass(StreamInfo()->GetStreamType());
xtl::format(s,"%s %s",plNetMsgStream::AsStdString().c_str(), noc ? noc : "?");
return s;
}
};
//
// special game msg for loading clones/avatars
//
class plNetMsgLoadClone : public plNetMsgGameMessage
{
private:
enum ContentFlags
{
kObjectHelper,
kIsPlayer,
kIsLoading,
kIsInitialState,
};
protected:
bool fIsPlayer;
bool fIsLoading;
bool fIsInitialState;
plNetMsgObjectHelper fObjectHelper;
int IPokeBuffer(hsStream* stream, UInt32 peekOptions=0);
int IPeekBuffer(hsStream* stream, UInt32 peekOptions=0);
public:
CLASSNAME_REGISTER( plNetMsgLoadClone );
GETINTERFACE_ANY_AUX(plNetMsgLoadClone, plNetMsgGameMessage,plNetMsgObjectHelper,fObjectHelper)
plNetMsgLoadClone() : fIsPlayer(true),fIsLoading(true),fIsInitialState(false) {}
void ReadVersion(hsStream* s, hsResMgr* mgr);
void WriteVersion(hsStream* s, hsResMgr* mgr);
plNetMsgObjectHelper* ObjectInfo() { return &fObjectHelper; }
const plNetMsgObjectHelper* ObjectInfo() const { return &fObjectHelper; }
bool GetIsPlayer() const { return fIsPlayer!=0; }
bool GetIsLoading() const { return fIsLoading!=0; }
bool GetIsInitialState() const { return fIsInitialState!=0; }
void SetIsPlayer(bool p) { fIsPlayer=p; }
void SetIsLoading(bool p) { fIsLoading=p; }
void SetIsInitialState(bool p) {fIsInitialState=p; }
// debug
std::string AsStdString() const
{
std::string s;
char tmp[256];
xtl::format(s,"object=%s initial=%d, %s",fObjectHelper.GetUoid().StringIze(tmp), fIsInitialState,
plNetMsgGameMessage::AsStdString().c_str());
return s;
}
};
//
// special msg when a player is paged in/out
//
class plNetMsgPlayerPage : public plNetMessage
{
protected:
int IPokeBuffer(hsStream* stream, UInt32 peekOptions=0);
int IPeekBuffer(hsStream* stream, UInt32 peekOptions=0);
public:
plUoid fUoid;
bool fUnload;
plNetMsgPlayerPage() : fUnload(false) { SetBit(kNeedsReliableSend); }
plNetMsgPlayerPage(plUoid uoid, hsBool unload) : fUoid(uoid), fUnload(unload) { }
CLASSNAME_REGISTER( plNetMsgPlayerPage );
GETINTERFACE_ANY( plNetMsgPlayerPage, plNetMessage);
};
//
// a game message that takes a list of other clients as receivers
//
class plNetMsgGameMessageDirected : public plNetMsgGameMessage
{
private:
enum ContentFlags
{
kRecievers,
};
protected:
plNetMsgReceiversListHelper fReceivers;
int IPokeBuffer(hsStream* stream, UInt32 peekOptions=0);
int IPeekBuffer(hsStream* stream, UInt32 peekOptions=0);
public:
CLASSNAME_REGISTER( plNetMsgGameMessageDirected );
GETINTERFACE_ANY_AUX(plNetMsgGameMessageDirected,plNetMsgGameMessage,
plNetMsgReceiversListHelper,fReceivers)
plNetMsgReceiversListHelper* Receivers() { return &fReceivers; }
// virtuals
void ReadVersion(hsStream* s, hsResMgr* mgr);
void WriteVersion(hsStream* s, hsResMgr* mgr);
};
//
// Message when a room is paged in/out
//
class plNetMsgPagingRoom : public plNetMsgRoomsList
{
public:
enum PageFlags
{
kPagingOut=0x1, // else paging in
kResetList=0x2, // server should reset his existing list before using this msg
kRequestState=0x4, // also want current room state sent to me
kFinalRoomInAge=0x8 // done paging in the age
};
protected:
UInt8 fPageFlags;
int IPokeBuffer(hsStream* stream, UInt32 peekOptions=0);
int IPeekBuffer(hsStream* stream, UInt32 peekOptions=0);
public:
plNetMsgPagingRoom() : fPageFlags(0) { SetBit(kIsSystemMessage|kNeedsReliableSend); }
~plNetMsgPagingRoom() {}
CLASSNAME_REGISTER( plNetMsgPagingRoom );
GETINTERFACE_ANY( plNetMsgPagingRoom, plNetMsgRoomsList );
void SetPageFlags(UInt8 f) { fPageFlags=f; }
UInt8 GetPageFlags() const { return fPageFlags; }
void SetPagingOut(hsBool b) { if (b) fPageFlags |= kPagingOut; else fPageFlags&=~kPagingOut; }
hsBool GetPagingOut() const { return (fPageFlags & kPagingOut) != 0; }
void SetResetList(hsBool b) { if (b) fPageFlags |= kResetList; else fPageFlags &=~kResetList; }
hsBool GetResetList() const { return (fPageFlags & kResetList) != 0; }
void SetRequestingState(hsBool b) { if (b) fPageFlags |= kRequestState; else fPageFlags &=~kRequestState; }
hsBool GetRequestingState() const { return (fPageFlags & kRequestState) != 0; }
// debug
std::string AsStdString() const
{
std::string s;
xtl::format(s,"pageFlags:%02X, paging %s, requestingState:%s, resetting=%d",fPageFlags,
(fPageFlags&kPagingOut)?"out":"in", (fPageFlags&kRequestState)?"yes":"no",
(fPageFlags & kResetList)!=0);
return s;
}
};
//
// Client requests game state update by rooms.
// an empty rooms list means ALL rooms I have loaded.
//
class plNetMsgGameStateRequest : public plNetMsgRoomsList
{
public:
plNetMsgGameStateRequest() { SetBit(kIsSystemMessage|kNeedsReliableSend); }
CLASSNAME_REGISTER( plNetMsgGameStateRequest );
GETINTERFACE_ANY( plNetMsgGameStateRequest, plNetMsgRoomsList );
};
//
// sent by game server to change clients ownership of a netGroup
//
class plNetMsgGroupOwner: public plNetMsgServerToClient
{
public:
class GroupInfo
{
public:
plNetGroupId fGroupID;
bool fOwnIt; // else not the owner
void Read(hsStream* s) { fGroupID.Read(s); s->LogReadSwap(&fOwnIt,"GroupOwner OwnIt"); }
void Write(hsStream* s) { fGroupID.Write(s); s->WriteSwap(fOwnIt); }
GroupInfo() : fGroupID(plNetGroup::kNetGroupUnknown), fOwnIt(false) {}
GroupInfo(plNetGroupId gID, hsBool o) : fGroupID(gID),fOwnIt(o) {}
};
protected:
std::vector fGroups;
int IPokeBuffer(hsStream* stream, UInt32 peekOptions=0);
int IPeekBuffer(hsStream* stream, UInt32 peekOptions=0);
public:
CLASSNAME_REGISTER( plNetMsgGroupOwner );
GETINTERFACE_ANY( plNetMsgGroupOwner, plNetMsgServerToClient );
// getters
int GetNumGroups() const { return fGroups.size(); }
GroupInfo GetGroupInfo(int i) const { return fGroups[i]; }
// setters
void AddGroupInfo(GroupInfo gi) { fGroups.push_back(gi); }
void ClearGroupInfo() { fGroups.clear(); }
bool IsOwner() { return fGroups[0].fOwnIt; }
};
//
// voice recording buffer
//
class plNetMsgVoice: public plNetMessage
{
private:
enum ContentFlags
{
kDead_FrameSize,
kReceivers,
kVoiceFlags,
kVoiceData
};
protected:
UInt8 fFlags; // voice flags
UInt8 fNumFrames; // number of frames encoded
std::string fVoiceData;
plNetMsgReceiversListHelper fReceivers;
int IPokeBuffer(hsStream* stream, UInt32 peekOptions=0);
int IPeekBuffer(hsStream* stream, UInt32 peekOptions=0);
public:
plNetMsgVoice(): fFlags(0), fNumFrames(0) { }
~plNetMsgVoice() {}
CLASSNAME_REGISTER( plNetMsgVoice );
GETINTERFACE_ANY_AUX(plNetMsgVoice,plNetMessage,plNetMsgReceiversListHelper,fReceivers)
void SetFlag(int f) { fFlags |= f; }
int GetFlags() { return fFlags; }
void SetNumFrames(UInt8 f) { fNumFrames = f; }
UInt8 GetNumFrames() const { return fNumFrames; }
void SetVoiceData(char *data, int len );
int GetVoiceDataLen() const { return fVoiceData.length(); }
const char *GetVoiceData() const;
plNetMsgReceiversListHelper* Receivers() { return &fReceivers; }
// virtuals
bool NeedsBroadcast() const { return true; }
void ReadVersion(hsStream* s, hsResMgr* mgr);
void WriteVersion(hsStream* s, hsResMgr* mgr);
// debug
std::string AsStdString() const
{
std::string s;
xtl::format(s,"len=%d",fVoiceData.size());
return s;
}
};
//
// base class for dealing with plNetSharedState
//
class plNetSharedState;
class plNetMsgSharedState : public plNetMsgStreamedObject
{
private:
enum ContentFlags
{
kLockRequest,
};
protected:
bool fLockRequest;
int IPokeBuffer(hsStream* stream, UInt32 peekOptions=0);
int IPeekBuffer(hsStream* stream, UInt32 peekOptions=0);
public:
plNetMsgSharedState() : fLockRequest(false) {}
~plNetMsgSharedState() {}
CLASSNAME_REGISTER( plNetMsgSharedState );
GETINTERFACE_ANY(plNetMsgSharedState, plNetMsgStreamedObject);
void CopySharedState(plNetSharedState* ss);
void SetLockRequest(hsBool b) { fLockRequest=b; }
hsBool GetLockRequest() const { return fLockRequest; }
void ReadVersion(hsStream* s, hsResMgr* mgr);
void WriteVersion(hsStream* s, hsResMgr* mgr);
// debug
std::string AsStdString() const
{
std::string s;
xtl::format(s,"lockReq=%d, %s",fLockRequest, plNetMsgStreamedObject::AsStdString().c_str());
return s;
}
};
//
// attempt to lock/unlock and set generic shared state on server.
// lock attempts will generate server reply messages confirming or denying the action.
//
class plNetMsgTestAndSet : public plNetMsgSharedState
{
public:
plNetMsgTestAndSet() { SetBit(kNeedsReliableSend); }
CLASSNAME_REGISTER( plNetMsgTestAndSet );
GETINTERFACE_ANY(plNetMsgTestAndSet, plNetMsgSharedState);
};
//
// provides a way to query sharedState on the server
//
class plNetMsgGetSharedState : public plNetMsgObject
{
protected:
char fSharedStateName[kMaxNameLen];
int IPokeBuffer(hsStream* stream, UInt32 peekOptions=0);
int IPeekBuffer(hsStream* stream, UInt32 peekOptions=0);
public:
plNetMsgGetSharedState() { *fSharedStateName=0; SetBit(kNeedsReliableSend); }
~plNetMsgGetSharedState() {}
CLASSNAME_REGISTER( plNetMsgGetSharedState );
GETINTERFACE_ANY( plNetMsgGetSharedState, plNetMsgObject );
void SetSharedStateName(char* n) { if (n) hsStrncpy(fSharedStateName, n, kMaxNameLen); }
char* GetSharedStateName() { return fSharedStateName; }
};
//
// msg which sets the update frequency for a group of objects on the server
//
class plNetMsgObjectUpdateFilter : public plNetMessage
{
protected:
plNetMsgObjectListHelper fObjectListHelper;
float fMaxUpdateFreq; // in secs
int IPokeBuffer(hsStream* stream, UInt32 peekOptions=0);
int IPeekBuffer(hsStream* stream, UInt32 peekOptions=0);
public:
plNetMsgObjectUpdateFilter() : fMaxUpdateFreq(-1) {}
~plNetMsgObjectUpdateFilter() {}
CLASSNAME_REGISTER( plNetMsgObjectUpdateFilter );
GETINTERFACE_ANY_AUX(plNetMsgObjectUpdateFilter,plNetMessage,plNetMsgObjectListHelper,fObjectListHelper)
plNetMsgObjectListHelper* ObjectListInfo() { return &fObjectListHelper; }
void SetMaxUpdateFreq(float f) { fMaxUpdateFreq=f; }
float GetMaxUpdateFreq() const { return fMaxUpdateFreq; }
};
//
// Client wants a list of all members in the session
//
class plNetMsgMembersListReq : public plNetMessage
{
public:
plNetMsgMembersListReq() { SetBit(kIsSystemMessage|kNeedsReliableSend); }
CLASSNAME_REGISTER( plNetMsgMembersListReq );
GETINTERFACE_ANY( plNetMsgMembersListReq, plNetMessage );
};
//
// Server returns a list of all members in the session
//
class plNetMsgMembersList : public plNetMsgServerToClient
{
protected:
plNetMsgMemberListHelper fMemberListHelper;
protected:
int IPokeBuffer(hsStream* stream, UInt32 peekOptions=0);
int IPeekBuffer(hsStream* stream, UInt32 peekOptions=0);
public:
CLASSNAME_REGISTER( plNetMsgMembersList );
GETINTERFACE_ANY_AUX(plNetMsgMembersList,plNetMsgServerToClient,plNetMsgMemberListHelper,fMemberListHelper)
plNetMsgMemberListHelper* MemberListInfo() { return &fMemberListHelper; }
};
//
// server tells client to add or remove a session member
//
class plNetMsgMemberUpdate : public plNetMsgServerToClient
{
protected:
plNetMsgMemberInfoHelper fMemberInfo;
bool fAddMember; // else remove member
protected:
int IPokeBuffer(hsStream* stream, UInt32 peekOptions=0);
int IPeekBuffer(hsStream* stream, UInt32 peekOptions=0);
public:
CLASSNAME_REGISTER( plNetMsgMemberUpdate );
GETINTERFACE_ANY_AUX(plNetMsgMemberUpdate,plNetMsgServerToClient,plNetMsgMemberInfoHelper,fMemberInfo)
bool AddingMember() { return fAddMember; }
void SetAddingMember(bool b) { fAddMember=b; }
plNetMsgMemberInfoHelper* MemberInfo() { return &fMemberInfo; }
bool NeedsBroadcast() const { return true; } // send to all clients
};
//
// ListenList updater msgs. For voice-broadcasting purposes.
// Contains a list of other players which I am [not] listening to.
// Sent client-client or client-server.
//
class plNetMsgListenListUpdate : public plNetMessage
{
private:
plNetMsgReceiversListHelper fReceivers; // used by server, the players we're listening to
bool fAdding; // else removing
int IPokeBuffer(hsStream* stream, UInt32 peekOptions=0);
int IPeekBuffer(hsStream* stream, UInt32 peekOptions=0);
public:
plNetMsgListenListUpdate() : fAdding(false) {}
~plNetMsgListenListUpdate() {}
CLASSNAME_REGISTER( plNetMsgListenListUpdate );
GETINTERFACE_ANY_AUX(plNetMsgListenListUpdate,plNetMessage,plNetMsgReceiversListHelper,fReceivers)
plNetMsgReceiversListHelper* Receivers() { return &fReceivers; }
bool GetAdding() const { return fAdding; }
void SetAdding(bool a) { fAdding=a; }
// virtuals
bool NeedsBroadcast() const { return true; } // use rcvrs list
};
///////////////////////////////////////////////////////////////////
class plNetMsgInitialAgeStateSent : public plNetMsgServerToClient
{
UInt32 fNumInitialSDLStates;
int IPokeBuffer(hsStream* stream, UInt32 peekOptions=0);
int IPeekBuffer(hsStream* stream, UInt32 peekOptions=0);
public:
plNetMsgInitialAgeStateSent():fNumInitialSDLStates(0){}
CLASSNAME_REGISTER( plNetMsgInitialAgeStateSent );
GETINTERFACE_ANY( plNetMsgInitialAgeStateSent, plNetMsgServerToClient);
void SetNumInitialSDLStates( UInt32 n ) { fNumInitialSDLStates=n; }
UInt32 GetNumInitialSDLStates() const { return fNumInitialSDLStates; }
};
//
// msg which sets the update frequency for a group of objects on the server
//
class plNetMsgRelevanceRegions : public plNetMessage
{
protected:
hsBitVector fRegionsImIn;
hsBitVector fRegionsICareAbout;
int IPokeBuffer(hsStream* stream, UInt32 peekOptions=0);
int IPeekBuffer(hsStream* stream, UInt32 peekOptions=0);
public:
plNetMsgRelevanceRegions() { SetBit(kNeedsReliableSend); }
~plNetMsgRelevanceRegions() {}
CLASSNAME_REGISTER( plNetMsgRelevanceRegions );
GETINTERFACE_ANY(plNetMsgRelevanceRegions, plNetMessage)
void SetRegionsICareAbout(const hsBitVector& r) { fRegionsICareAbout=r; }
void SetRegionsImIn(const hsBitVector& r) { fRegionsImIn=r; }
const hsBitVector& GetRegionsICareAbout() const { return fRegionsICareAbout; }
const hsBitVector& GetRegionsImIn() const { return fRegionsImIn; }
std::string AsStdString() const
{
std::string s;
std::string b1, b2;
int i;
for(i=0;i