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