mirror of
https://github.com/ptitSeb/Serious-Engine
synced 2024-12-26 15:44:51 +01:00
312 lines
12 KiB
C++
312 lines
12 KiB
C++
/* 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 <Engine/Base/Lists.h>
|
|
#include <Engine/Math/Vector.h>
|
|
|
|
// 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 *
|
|
};
|
|
|
|
/*
|
|
* 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);
|
|
};
|
|
|
|
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);
|
|
};
|
|
|
|
|
|
#endif /* include-once check. */
|
|
|