/* Copyright (c) 2002-2012 Croteam Ltd. This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as published by the Free Software Foundation 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, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef SE_INCL_NETWORKMESSAGE_H #define SE_INCL_NETWORKMESSAGE_H #ifdef PRAGMA_ONCE #pragma once #endif #include #include // message type // transmitted as 6-bit value // up to 64 values allowed // upper 2 bits are used to indicate compression used // ADD NEW MESSAGE TYPES TO THE END!!! typedef enum NetworkMessageType { // broadcast requesting server infos MSG_REQ_ENUMSERVERS, MSG_SERVERINFO, MSG_KEEPALIVE, // sent when there's nothing else to send - just to keep connections valid // disconnection explanation from server MSG_INF_DISCONNECTED, // info message with pings of all players MSG_INF_PINGS, // main session state connecting to server MSG_REQ_CONNECTLOCALSESSIONSTATE, MSG_REP_CONNECTLOCALSESSIONSTATE, // remote session state connecting to server MSG_REQ_CONNECTREMOTESESSIONSTATE, MSG_REP_CONNECTREMOTESESSIONSTATE, // remote session requesting current state delta from original MSG_REQ_STATEDELTA, MSG_REP_STATEDELTA, // client initialing CRC check MSG_REQ_CRCLIST, MSG_REQ_CRCCHECK, MSG_REP_CRCCHECK, // player connecting to server MSG_REQ_CONNECTPLAYER, MSG_REP_CONNECTPLAYER, MSG_REQ_PAUSE, // request pause/unpause game // request character change for a player MSG_REQ_CHARACTERCHANGE, // action packet from client to server MSG_ACTION, // data to check for lost synchronization (client to server) MSG_SYNCCHECK, // a copy of action stored for prediction MSG_ACTIONPREDICT, // sequenced packets from server to session states MSG_SEQ_ALLACTIONS, // packed actions of all players from server to clients MSG_SEQ_ADDPLAYER, // instructions for adding a new player to session states MSG_SEQ_REMPLAYER, // instructions for removing a new player from session states MSG_SEQ_PAUSE, // game was paused/unpaused MSG_SEQ_CHARACTERCHANGE, // a player has changed character MSG_GAMESTREAMBLOCKS, // packet with one or more game stream messages MSG_REQUESTGAMESTREAMRESEND, // request for resend of a game stream message // chat messages MSG_CHAT_IN, // chat request from client to server MSG_CHAT_OUT, // chat message routed to certain clients // parameter setting messages MSG_SET_CLIENTSETTINGS, // adjust server side settings of a client // remote administration MSG_ADMIN_COMMAND, // c2s incoming console command request MSG_ADMIN_RESPONSE, // s2c results of the console command MSG_EXTRA = '/', // used for special communications like rcon and similar // added to the end so that it would not mess up old numbering - that would corrupt demo playing // disconnection confirmation from the client MSG_REP_DISCONNECTED, } MESSAGETYPE; extern struct ErrorTable MessageTypes; /* * Holder for network message, can be read/written like a stream. */ class ENGINE_API CNetworkMessage { public: MESSAGETYPE nm_mtType; // type of this message #define MAX_NETWORKMESSAGE_SIZE 2048 // max. length of message buffer UBYTE *nm_pubMessage; // the message data itself SLONG nm_slMaxSize; // size of message buffer UBYTE *nm_pubPointer; // pointer for reading/writing message SLONG nm_slSize; // size of message INDEX nm_iBit; // next bit index to read/write (0 if not reading/writing bits) public: /* Constructor for empty message (for receiving). */ CNetworkMessage(void); /* Constructor for initializing message that is to be sent. */ CNetworkMessage(MESSAGETYPE mtType); /* Copying. */ CNetworkMessage(const CNetworkMessage &nmOriginal); void operator=(const CNetworkMessage &nmOriginal); /* Destructor. */ ~CNetworkMessage(void); // reinit a message that is to be sent (to write different contents) void Reinit(void); /* Ignore the contents of this message. */ void IgnoreContents(void); // dump message to console void Dump(void); /* Get the type of this message. */ inline MESSAGETYPE GetType(void) const { ASSERT(this!=NULL); return MESSAGETYPE(nm_mtType&0x3F); }; /* Check if end of message. */ BOOL EndOfMessage(void); // rewind message to start, so that written message can be read again void Rewind(void); /* Pack a message to another message (message type is left untouched). */ void Pack(CNetworkMessage &nmPacked, CCompressor &comp); void PackDefault(CNetworkMessage &nmPacked); /* Unpack a message to another message (message type is left untouched). */ void Unpack(CNetworkMessage &nmUnpacked, CCompressor &comp); void UnpackDefault(CNetworkMessage &nmUnpacked); // read/write functions void Read(void *pvBuffer, SLONG slSize); void Write(const void *pvBuffer, SLONG slSize); void ReadBits(void *pvBuffer, INDEX ctBits); void WriteBits(const void *pvBuffer, INDEX ctBits); /* Read an object from message. */ inline CNetworkMessage &operator>>(float &f) { Read( &f, sizeof( f)); return *this; } inline CNetworkMessage &operator>>(ULONG &ul) { Read(&ul, sizeof(ul)); return *this; } inline CNetworkMessage &operator>>(UWORD &uw) { Read(&uw, sizeof(uw)); return *this; } inline CNetworkMessage &operator>>(UBYTE &ub) { Read(&ub, sizeof(ub)); return *this; } inline CNetworkMessage &operator>>(SLONG &sl) { Read(&sl, sizeof(sl)); return *this; } inline CNetworkMessage &operator>>(SWORD &sw) { Read(&sw, sizeof(sw)); return *this; } inline CNetworkMessage &operator>>(SBYTE &sb) { Read(&sb, sizeof(sb)); return *this; } inline CNetworkMessage &operator>>(MESSAGETYPE &mt) { Read(&mt, sizeof(mt)); return *this; } CNetworkMessage &operator>>(CTString &str); /* Write an object into message. */ inline CNetworkMessage &operator<<(const float &f) { Write( &f, sizeof( f)); return *this; } inline CNetworkMessage &operator<<(const double &d) { Write( &d, sizeof( d)); return *this; } inline CNetworkMessage &operator<<(const ULONG &ul) { Write(&ul, sizeof(ul)); return *this; } inline CNetworkMessage &operator<<(const UWORD &uw) { Write(&uw, sizeof(uw)); return *this; } inline CNetworkMessage &operator<<(const UBYTE &ub) { Write(&ub, sizeof(ub)); return *this; } inline CNetworkMessage &operator<<(const SLONG &sl) { Write(&sl, sizeof(sl)); return *this; } inline CNetworkMessage &operator<<(const SWORD &sw) { Write(&sw, sizeof(sw)); return *this; } inline CNetworkMessage &operator<<(const SBYTE &sb) { Write(&sb, sizeof(sb)); return *this; } inline CNetworkMessage &operator<<(const MESSAGETYPE &mt) { Write(&mt, sizeof(mt)); return *this; } CNetworkMessage &operator<<(const CTString &str); /* Insert a sub-message into this message. */ void InsertSubMessage(const CNetworkMessage &nmSubMessage); /* Extract a sub-message from this message. */ void ExtractSubMessage(CNetworkMessage &nmSubMessage); // shrink message buffer to exactly fit contents void Shrink(void); }; /* * A message block used for streaming data across network. * * These can be received duplicated or misordered. They * are resequenced at the receive side as needed. Can be sent more than one * together as submessages in a message and duplicated across messages as a * compensation for eventual packet loss. */ class CNetworkStreamBlock : public CNetworkMessage { public: CListNode nsb_lnInStream; // node in list of blocks in stream public: INDEX nsb_iSequenceNumber; // index for sorting in list public: /* Constructor for receiving -- uninitialized block. */ CNetworkStreamBlock(void); /* Constructor for sending -- empty packet with given type and sequence. */ CNetworkStreamBlock(MESSAGETYPE mtType, INDEX iSequenceNumber); /* Read a block from a received message. */ void ReadFromMessage(CNetworkMessage &nmToRead); /* Add a block to a message to send. */ void WriteToMessage(CNetworkMessage &nmToWrite); /* Remove the block from stream. */ void RemoveFromStream(void); /* Read/write the block from file stream. */ void Read_t(CTStream &strm); // throw char * void Write_t(CTStream &strm); // throw char * }; /* * !!! FIXME: R_OK is used with the unix access() API... * !!! FIXME: we're lucky...on Linux, it's a macro, but it could be an * !!! FIXME: enum just as easily. --ryan. */ #ifdef R_OK #undef R_OK #endif /* * Stream of message blocks that can be sent across network. */ class CNetworkStream { public: enum Result { R_OK = 1, R_BLOCKMISSING, // block is missing in the stream R_BLOCKNOTRECEIVEDYET, // block is not yet received }; public: CListHead ns_lhBlocks; // list of blocks of this stream (higher sequences first) /* Add a block that is already allocated to the stream. */ void AddAllocatedBlock(CNetworkStreamBlock *pnsbBlock); public: /* Constructor. */ CNetworkStream(void); /* Destructor. */ ~CNetworkStream(void); /* Clear the object (remove all blocks). */ void Clear(void); /* Copy from another network stream. */ void Copy(CNetworkStream &nsOther); // get number of blocks used by this object INDEX GetUsedBlocks(void); // get amount of memory used by this object SLONG GetUsedMemory(void); // get index of newest sequence stored INDEX GetNewestSequence(void); /* Add a block to the stream (makes a copy of block). */ void AddBlock(CNetworkStreamBlock &nsbBlock); /* Read a block as a submessage from a message and add it to the stream. */ void ReadBlock(CNetworkMessage &nmMessage); /* Get a block from stream by its sequence number. */ CNetworkStream::Result GetBlockBySequence( INDEX iSequenceNumber, CNetworkStreamBlock *&pnsbBlock); // find oldest block after given one (for batching missing sequences) INDEX GetOldestSequenceAfter(INDEX iSequenceNumber); /* Write given number of newest blocks to a message. */ INDEX WriteBlocksToMessage(CNetworkMessage &nmMessage, INDEX ctBlocks); /* Remove all blocks but the given number of newest ones. */ void RemoveOlderBlocks(INDEX ctBlocksToKeep); /* Remove all blocks with sequence older than given. */ void RemoveOlderBlocksBySequence(INDEX iLastSequenceToKeep); }; #ifdef NETSTRUCTS_PACKED #pragma pack(1) #endif class ENGINE_API CPlayerAction { public: // order is important for compression and normalization - do not reorder! FLOAT3D pa_vTranslation; ANGLE3D pa_aRotation; ANGLE3D pa_aViewRotation; ULONG pa_ulButtons; // 32 bits for action buttons (application defined) // keep flags that are likely to be changed/set more often at lower bits, // so that better compression can be achieved for network transmission __int64 pa_llCreated; // when was created (for ping calc.) in ms public: CPlayerAction(void); /* Clear the object (this sets up no actions). */ void Clear(void); // normalize action (remove invalid floats like -0) void Normalize(void); // create a checksum value for sync-check void ChecksumForSync(ULONG &ulCRC); // dump sync data to text file void DumpSync_t(CTStream &strm); // throw char * void Lerp(const CPlayerAction &pa0, const CPlayerAction &pa1, FLOAT fFactor); /* Write an object into message. */ friend CNetworkMessage &operator<<(CNetworkMessage &nm, const CPlayerAction &pa); /* Read an object from message. */ friend CNetworkMessage &operator>>(CNetworkMessage &nm, CPlayerAction &pa); /* Write an object into stream. */ friend CTStream &operator<<(CTStream &strm, const CPlayerAction &pa); /* Read an object from stream. */ friend CTStream &operator>>(CTStream &strm, CPlayerAction &pa); }; #ifdef NETSTRUCTS_PACKED #pragma pack() #endif #endif /* include-once check. */