/* $Id: message.hpp,v 1.7 2005/12/06 21:31:52 chfreund Exp $ */ #ifndef _MESSAGE_HPP_ #define _MESSAGE_HPP_ #include #include "global.hpp" #include "serializable.hpp" #include "serialize.hpp" #include "event.hpp" #include "player.hpp" #include "world.hpp" /*! \brief Base class for messages that are sent between client and server * * What to do if you want to create a new message class: * -# Derive the new message class from Message * - Implement a default constructor and a constructor taking a * const Message& argument * - Implement all virtual functions * -# Extend the enum Request in Message for the new message type * -# Extend the switch statement in Comm::tcpRecvPacket() */ struct Message : public Serializable { //! Types of messages enum Type { UNKNOWN = 0, BAIT, BAIT_ANSWER, REQUEST, INFO, CONNECT, ADD_PLAYER, REMOVE_PLAYER, WORLD, EVENT, ECHO, CHAT, SYNC_PROGRESS, QUIT }; //! Type of the message Type type; //! Size of the message Uint32 dataSize; //! Flag if serialized data following this header is compressed bool compressed; //! Size of the uncompressed data if compression is used Uint32 uncompressedDataSize; //! Constructor Message( Type t = UNKNOWN ) : type( t ), dataSize( 0 ), compressed( false ), uncompressedDataSize( 0 ) { } //! Destructor virtual ~Message() { } /*! \return The constant size of the message header */ static Uint32 getStaticSerializeBufferSize() { return Serialize::sizeOf() + 2 * Serialize::sizeOf() + Serialize::sizeOf(); } /*! \return Size of the \b data (not counting the headers!) contained in * the message */ virtual Uint32 getDataSize() const { return 0; } /*! Serialize the header of the message to the buffer starting * at \em bufferPointer * \param bufferPointer pointer to the buffer */ void serializeHeader( Uint8*& bufferPointer ) const { Serialize::serialize( type, bufferPointer ); Serialize::serialize( dataSize, bufferPointer ); Serialize::serialize( compressed, bufferPointer ); Serialize::serialize( uncompressedDataSize, bufferPointer ); } /*! Deserialize the header of the message from the buffer starting * at \em bufferPointer * \param bufferPointer pointer to the buffer */ void deserializeHeader( Uint8*& bufferPointer ) { Serialize::deserialize( bufferPointer, type ); Serialize::deserialize( bufferPointer, dataSize ); Serialize::deserialize( bufferPointer, compressed ); Serialize::deserialize( bufferPointer, uncompressedDataSize ); } /*! Serialize the data contained in the message to the buffer starting * at \em bufferPointer * \param bufferPointer pointer to the buffer */ virtual void serializeData( Uint8*& bufferPointer ) const { } /*! Deserialize the data contained in the message from the buffer starting * at \em bufferPointer * \param bufferPointer pointer to the buffer */ virtual void deserializeData( Uint8*& bufferPointer ) { } /*! Serialize the whole message into the buffer starting at * \em bufferPointer */ virtual void serialize( Uint8*& bufferPointer ) const { serializeHeader( bufferPointer ); serializeData( bufferPointer ); } /*! Deserialize the whole message from the buffer starting at * \em bufferPointer */ virtual void deserialize( Uint8*& bufferPointer ) { deserializeHeader( bufferPointer ); deserializeData( bufferPointer ); } /*! \return The size needed for a buffer to contain all data * for serialization */ virtual Uint32 getSerializeBufferSize() const { return Message::getStaticSerializeBufferSize() + getDataSize(); } virtual Message* clone() const { Message* newMessage = NEW Message( *this ); return newMessage; }; }; /*! \brief A specialized packet message for general requests */ struct RequestMessage : public Message { //! The request type: an answer message with this type is requested Type request; //! Constructor RequestMessage() : Message( REQUEST ), request( UNKNOWN ) { } //! Constructor RequestMessage( const Message& message ) : Message( message ) { } //! Destructor virtual ~RequestMessage() { } /*! \return Size of the \b data (not counting the headers!) contained in * the message */ virtual Uint32 getDataSize() const { return Serialize::sizeOf(); } /*! Serialize the whole message into the buffer starting at * \em bufferPointer */ virtual void serializeData( Uint8*& bufferPointer ) const { Serialize::serialize( request, bufferPointer ); } /*! Deserialize the data contained in the message in the buffer starting * at \em bufferPointer * \param bufferPointer pointer to the buffer */ virtual void deserializeData( Uint8*& bufferPointer ) { Serialize::deserialize( bufferPointer, request ); } virtual Message* clone() const { RequestMessage* newMessage = NEW RequestMessage( *this ); return newMessage; }; }; /*! \brief A specialized packet message for requests for information * about the game running on a server */ struct InfoMessage : public Message { //! The game theme String theme; //! The gamemode Uint8 gamemode; //! The number of players Uint8 numberPlayers; //! The players std::vector player; //! Constructor InfoMessage() : Message( INFO ), theme( "dummy" ) { } //! Constructor InfoMessage( const Message& message ) : Message( message ) { } //! Destructor virtual ~InfoMessage() { } /*! \return Size of the \b data (not counting the headers!) contained in * the message */ virtual Uint32 getDataSize() const { Uint32 playerSize = 0; for ( std::vector::const_iterator it = player.begin(); it != player.end(); it++ ) { playerSize += (*it)->getSerializeBufferSize(); } return theme.getSerializeBufferSize() + 2 * Serialize::sizeOf() + playerSize; } /*! Serialize the whole message into the buffer starting at * \em bufferPointer */ virtual void serializeData( Uint8*& bufferPointer ) const { theme.serialize( bufferPointer ); Serialize::serialize( gamemode, bufferPointer ); Serialize::serialize( numberPlayers, bufferPointer ); for ( std::vector::const_iterator it = player.begin(); it != player.end(); it++ ) { (*it)->serialize( bufferPointer ); } } /*! Deserialize the data contained in the message in the buffer starting * at \em bufferPointer * \param bufferPointer pointer to the buffer */ virtual void deserializeData( Uint8*& bufferPointer ) { theme.deserialize( bufferPointer ); Serialize::deserialize( bufferPointer, gamemode ); Serialize::deserialize( bufferPointer, numberPlayers ); for ( Uint8 i = 0; i < numberPlayers; i++ ) { Player* p = new Player(); p->deserialize( bufferPointer ); player.push_back( p ); } } virtual Message* clone() const { InfoMessage* newMessage = NEW InfoMessage( *this ); return newMessage; }; }; /*! \brief A specialized message class for connection requests * from clients */ struct ConnectMessage : public Message { //! The local UDP port of the client Uint16 udpPort; //! The client id Uint8 clientID; //! Constructor ConnectMessage() : Message( CONNECT ), udpPort( 0 ) { } //! Constructor ConnectMessage( const Message& message ) : Message( message ) { } //! Destructor virtual ~ConnectMessage() { } /*! \return Size of the \b data (not counting the headers!) contained in * the message */ virtual Uint32 getDataSize() const { return Serialize::sizeOf() + Serialize::sizeOf(); } /*! Serialize the whole message into the buffer starting at * \em bufferPointer */ virtual void serializeData( Uint8*& bufferPointer ) const { Serialize::serialize( udpPort, bufferPointer ); Serialize::serialize( clientID, bufferPointer ); } /*! Deserialize the data contained in the message in the buffer starting * at \em bufferPointer * \param bufferPointer pointer to the buffer */ virtual void deserializeData( Uint8*& bufferPointer ) { Serialize::deserialize( bufferPointer, udpPort ); Serialize::deserialize( bufferPointer, clientID ); } virtual Message* clone() const { ConnectMessage* newMessage = NEW ConnectMessage( *this ); return newMessage; }; }; /*! \brief A specialized message class for transmitting a player */ struct AddPlayerMessage : public Message { //! The client ID of the client "owning" this player Uint8 clientID; //! The local player number in the owning client Uint8 localPlayerNumber; //! The global player number in the world Uint8 globalPlayerNumber; //! The player to be transmitted Player* player; //! The frame where the player enters the world Uint8 frame; //! The index for the message Uint32 frameSequenceIndex; //! Constructor AddPlayerMessage( Uint8 pn = 0, Player* p = 0 ) : Message( ADD_PLAYER ), clientID( 0 ), localPlayerNumber( pn ), globalPlayerNumber( 0 ), player( p ), frame( 0 ), frameSequenceIndex( 0 ) { } //! Constructor AddPlayerMessage( const Message& message ) : Message( message ), clientID( 0 ), localPlayerNumber( 0 ), globalPlayerNumber( 0 ), player( 0 ), frame( 0 ), frameSequenceIndex( 0 ) { } //! Destructor virtual ~AddPlayerMessage() { // to delete player or not to delete... that is the question } /*! \return Size of the \b data (not counting the headers!) contained in * the packet */ virtual Uint32 getDataSize() const { return player->getSerializeBufferSize() + 4 * Serialize::sizeOf() + Serialize::sizeOf(); } /*! Serialize the whole packet into the buffer starting at * \em bufferPointer */ virtual void serializeData( Uint8*& bufferPointer ) const { Serialize::serialize( clientID, bufferPointer ); Serialize::serialize( localPlayerNumber, bufferPointer ); Serialize::serialize( globalPlayerNumber, bufferPointer ); if ( player ) { player->serialize( bufferPointer ); } Serialize::serialize( frame, bufferPointer ); Serialize::serialize( frameSequenceIndex, bufferPointer ); } /*! Deserialize the data contained in the packet in the buffer starting * at \em bufferPointer * \param bufferPointer pointer to the buffer */ virtual void deserializeData( Uint8*& bufferPointer ) { Serialize::deserialize( bufferPointer, clientID ); Serialize::deserialize( bufferPointer, localPlayerNumber ); Serialize::deserialize( bufferPointer, globalPlayerNumber ); if ( !player ) { player = new Player(); } player->deserialize( bufferPointer ); Serialize::deserialize( bufferPointer, frame ); Serialize::deserialize( bufferPointer, frameSequenceIndex ); } virtual Message* clone() const { AddPlayerMessage* newMessage = NEW AddPlayerMessage( *this ); return newMessage; }; }; /*! \brief A specialized packet class for transmitting a world */ struct WorldMessage : public Message { //! The world to be transmitted World* world; //! The current frame number for the world Uint8 frame; //! The player ID for the new player Uint8 playerID; //! Constructor WorldMessage() : Message( WORLD ), world( 0 ) { } //! Constructor WorldMessage( const Message& message ) : Message( message ), world( 0 ) { } //! Destructor virtual ~WorldMessage() { // to delete world or not to delete... that is the question } /*! \return Size of the \b data (not counting the headers!) contained in * the packet */ virtual Uint32 getDataSize() const { return world->getSerializeBufferSize() + 2 * Serialize::sizeOf(); } /*! Serialize the whole packet into the buffer starting at * \em bufferPointer */ virtual void serializeData( Uint8*& bufferPointer ) const { if ( world ) { world->serialize( bufferPointer ); } Serialize::serialize( frame, bufferPointer ); Serialize::serialize( playerID, bufferPointer ); } /*! Deserialize the data contained in the packet in the buffer starting * at \em bufferPointer * \param bufferPointer pointer to the buffer */ virtual void deserializeData( Uint8*& bufferPointer ) { if ( !world ) { world = new World(); } world->deserialize( bufferPointer ); Serialize::deserialize( bufferPointer, frame ); Serialize::deserialize( bufferPointer, playerID ); } virtual Message* clone() const { WorldMessage* newMessage = NEW WorldMessage( *this ); return newMessage; }; }; /*! \brief A specialized packet class for transmitting a chat message */ struct ChatMessage : public Message { //! The chat message to be transmitted String message; SDL_Color color; //! Constructor ChatMessage() : Message( CHAT ) { } //! Constructor ChatMessage( const Message& m ) : Message( m ) { } //! Destructor virtual ~ChatMessage() { } /*! \return Size of the \b data (not counting the headers!) contained in * the packet */ virtual Uint32 getDataSize() const { return message.getSerializeBufferSize() + 3 * Serialize::sizeOf(); } /*! Serialize the whole packet into the buffer starting at * \em bufferPointer */ virtual void serializeData( Uint8*& bufferPointer ) const { message.serialize( bufferPointer ); Serialize::serialize( color.r, bufferPointer ); Serialize::serialize( color.g, bufferPointer ); Serialize::serialize( color.b, bufferPointer ); } /*! Deserialize the data contained in the packet in the buffer starting * at \em bufferPointer * \param bufferPointer pointer to the buffer */ virtual void deserializeData( Uint8*& bufferPointer ) { message.deserialize( bufferPointer ); Serialize::deserialize( bufferPointer, color.r ); Serialize::deserialize( bufferPointer, color.g ); Serialize::deserialize( bufferPointer, color.b ); } virtual Message* clone() const { ChatMessage* newMessage = NEW ChatMessage( *this ); return newMessage; }; }; struct EventMessage : public Message { //! Number of events stored in this message Uint8 numberEvents; //! The events Event* event; //! The last consecutive echo frame the client has received Uint32 lastReceivedFrame; //! Constructor EventMessage( Uint8 nEvents = 1 ) : Message( EVENT ), numberEvents( nEvents ) { event = new Event[numberEvents]; } //! Constructor EventMessage( const Message& message ) : Message( message ), event( 0 ) { } //! Destructor virtual ~EventMessage() { delete[] event; } /*! \return Size of the \b data (not counting the headers!) contained in * the packet */ virtual Uint32 getDataSize() const { return Serialize::sizeOf() + numberEvents * Serialize::sizeOf() + Serialize::sizeOf(); } /*! Serialize the whole packet into the buffer starting at * \em bufferPointer */ virtual void serializeData( Uint8*& bufferPointer ) const { Serialize::serialize( numberEvents, bufferPointer ); for ( Uint8 i = 0; i < numberEvents; i++ ) { event[i].serialize( bufferPointer ); } Serialize::serialize( lastReceivedFrame, bufferPointer ); } /*! Deserialize the data contained in the packet in the buffer starting * at \em bufferPointer * \param bufferPointer pointer to the buffer */ virtual void deserializeData( Uint8*& bufferPointer ) { Serialize::deserialize( bufferPointer, numberEvents ); delete[] event; event = new Event[numberEvents]; for ( Uint8 i = 0; i < numberEvents; i++ ) { event[i].deserialize( bufferPointer ); } Serialize::deserialize( bufferPointer, lastReceivedFrame ); } virtual Message* clone() const { EventMessage* newMessage = NEW EventMessage( *this ); return newMessage; }; void dump() const { DBG( 2 ) printf( "Event message contains %d events:\n", numberEvents ); for ( Uint8 e = 0; e < numberEvents; e++ ) { DBG( 2 ) printf( "\t%d: %x\n", e, event[e].get() ); } } }; struct EchoMessage : public Message { //! The frame the echo message is referring to Uint32 frame; //! The status of the server Status status; //! The number of connected clients Uint8 numberClients; //! The counter of the random number generator Uint32 randomCounter; //! The number of non-echo messages to be received after this frame Uint32 numberMessages; //! The events from all clients Event event[MAX_NUMBER_OF_PLAYERS]; //! Constructor EchoMessage() : Message( ECHO ) { } //! Constructor EchoMessage( const Message& message ) : Message( message ) { } //! Destructor virtual ~EchoMessage() { } /*! \return Size of the \b data (not counting the headers!) contained in * the packet */ virtual Uint32 getDataSize() const { return Serialize::sizeOf() + 1 * Serialize::sizeOf() + 3 * Serialize::sizeOf() + MAX_NUMBER_OF_PLAYERS * Event::getStaticSerializeBufferSize(); } /*! Serialize the whole packet into the buffer starting at * \em bufferPointer */ virtual void serializeData( Uint8*& bufferPointer ) const { Serialize::serialize( frame, bufferPointer ); Serialize::serialize( status, bufferPointer ); Serialize::serialize( numberClients, bufferPointer ); Serialize::serialize( randomCounter, bufferPointer ); Serialize::serialize( numberMessages, bufferPointer ); for ( int i = 0; i < MAX_NUMBER_OF_PLAYERS; i++ ) { event[i].serialize( bufferPointer ); } } /*! Deserialize the data contained in the packet in the buffer starting * at \em bufferPointer * \param bufferPointer pointer to the buffer */ virtual void deserializeData( Uint8*& bufferPointer ) { Serialize::deserialize( bufferPointer, frame ); Serialize::deserialize( bufferPointer, status ); Serialize::deserialize( bufferPointer, numberClients ); Serialize::deserialize( bufferPointer, randomCounter ); Serialize::deserialize( bufferPointer, numberMessages ); for ( int i = 0; i < MAX_NUMBER_OF_PLAYERS; i++ ) { event[i].deserialize( bufferPointer ); } } virtual Message* clone() const { EchoMessage* newMessage = NEW EchoMessage( *this ); return newMessage; }; }; struct RemovePlayerMessage : public Message { //! The number of the player that has quit Uint8 playerNumber; //! The frame when the player has quit Uint8 frame; //! The index for the message Uint32 frameSequenceIndex; //! Constructor RemovePlayerMessage( Uint8 pn = 0 ) : Message( REMOVE_PLAYER ), playerNumber( pn ) { } //! Constructor RemovePlayerMessage( const Message& message ) : Message( message ) { } //! Destructor virtual ~RemovePlayerMessage() { } /*! \return Size of the \b data (not counting the headers!) contained in * the packet */ virtual Uint32 getDataSize() const { return 2 * Serialize::sizeOf() + Serialize::sizeOf(); } /*! Serialize the whole packet into the buffer starting at * \em bufferPointer */ virtual void serializeData( Uint8*& bufferPointer ) const { Serialize::serialize( playerNumber, bufferPointer ); Serialize::serialize( frame, bufferPointer ); Serialize::serialize( frameSequenceIndex, bufferPointer ); } /*! Deserialize the data contained in the packet in the buffer starting * at \em bufferPointer * \param bufferPointer pointer to the buffer */ virtual void deserializeData( Uint8*& bufferPointer ) { Serialize::deserialize( bufferPointer, playerNumber ); Serialize::deserialize( bufferPointer, frame ); Serialize::deserialize( bufferPointer, frameSequenceIndex ); } virtual Message* clone() const { RemovePlayerMessage* newMessage = NEW RemovePlayerMessage( *this ); return newMessage; }; }; struct QuitMessage : public Message { //! Constructor QuitMessage() : Message( QUIT ) { } //! Constructor QuitMessage( const Message& message ) : Message( message ) { } //! Destructor virtual ~QuitMessage() { } /*! \return Size of the \b data (not counting the headers!) contained in * the message */ virtual Uint32 getDataSize() const { return 0; } /*! Serialize the whole message into the buffer starting at * \em bufferPointer */ virtual void serializeData( Uint8*& bufferPointer ) const { } /*! Deserialize the data contained in the message in the buffer starting * at \em bufferPointer * \param bufferPointer pointer to the buffer */ virtual void deserializeData( Uint8*& bufferPointer ) { } virtual Message* clone() const { QuitMessage* newMessage = NEW QuitMessage( *this ); return newMessage; }; }; struct BaitMessage : public Message { Uint32 magicData; //! Constructor BaitMessage() : Message( BAIT ), magicData( 0xb8b8 ) { } //! Constructor BaitMessage( const Message& message ) : Message( message ) { } //! Destructor virtual ~BaitMessage() { } /*! \return Size of the \b data (not counting the headers!) contained in * the message */ virtual Uint32 getDataSize() const { return Serialize::sizeOf(); } /*! Serialize the whole message into the buffer starting at * \em bufferPointer */ virtual void serializeData( Uint8*& bufferPointer ) const { Serialize::serialize( magicData, bufferPointer ); } /*! Deserialize the data contained in the message in the buffer starting * at \em bufferPointer * \param bufferPointer pointer to the buffer */ virtual void deserializeData( Uint8*& bufferPointer ) { Serialize::deserialize( bufferPointer, magicData ); } virtual Message* clone() const { BaitMessage* newMessage = NEW BaitMessage( *this ); return newMessage; }; }; struct BaitAnswerMessage : public Message { Uint32 magicData; Uint16 serverPort; //! The game theme String theme; //! The number of players Uint8 numberPlayers; //! Constructor BaitAnswerMessage() : Message( BAIT_ANSWER ), magicData( 0xb8b8 ), theme( "dummy" ) { } //! Constructor BaitAnswerMessage( const Message& message ) : Message( message ) { } //! Destructor virtual ~BaitAnswerMessage() { } /*! \return Size of the \b data (not counting the headers!) contained in * the message */ virtual Uint32 getDataSize() const { return Serialize::sizeOf() + Serialize::sizeOf() + theme.getSerializeBufferSize() + Serialize::sizeOf(); } /*! Serialize the whole message into the buffer starting at * \em bufferPointer */ virtual void serializeData( Uint8*& bufferPointer ) const { Serialize::serialize( magicData, bufferPointer ); Serialize::serialize( serverPort, bufferPointer ); theme.serialize( bufferPointer ); Serialize::serialize( numberPlayers, bufferPointer ); } /*! Deserialize the data contained in the message in the buffer starting * at \em bufferPointer * \param bufferPointer pointer to the buffer */ virtual void deserializeData( Uint8*& bufferPointer ) { Serialize::deserialize( bufferPointer, magicData ); Serialize::deserialize( bufferPointer, serverPort ); theme.deserialize( bufferPointer ); Serialize::deserialize( bufferPointer, numberPlayers ); } virtual Message* clone() const { BaitAnswerMessage* newMessage = NEW BaitAnswerMessage( *this ); return newMessage; }; }; struct SyncProgressMessage : public Message { //! The total message size Sint32 messageSize; //! The data already sent Sint32 dataSent; //! Constructor SyncProgressMessage() : Message( SYNC_PROGRESS ), messageSize( 0 ), dataSent( 0 ) { } //! Constructor SyncProgressMessage( const Message& message ) : Message( message ) { } //! Destructor virtual ~SyncProgressMessage() { } /*! \return Size of the \b data (not counting the headers!) contained in * the message */ virtual Uint32 getDataSize() const { return 2 * Serialize::sizeOf(); } /*! Serialize the whole message into the buffer starting at * \em bufferPointer */ virtual void serializeData( Uint8*& bufferPointer ) const { Serialize::serialize( messageSize, bufferPointer ); Serialize::serialize( dataSent, bufferPointer ); } /*! Deserialize the data contained in the message in the buffer starting * at \em bufferPointer * \param bufferPointer pointer to the buffer */ virtual void deserializeData( Uint8*& bufferPointer ) { Serialize::deserialize( bufferPointer, messageSize ); Serialize::deserialize( bufferPointer, dataSent ); } virtual Message* clone() const { SyncProgressMessage* newMessage = NEW SyncProgressMessage( *this ); return newMessage; }; }; #endif // _MESSAGE_HPP_