/*! * @file connection_monitor.h \brief interface for all classes that have to be synchronized */ #ifndef _SYNCHRONIZEABLE_H #define _SYNCHRONIZEABLE_H #include "base_object.h" #include "netdefs.h" #include "converter.h" #include #include //State constants: They have to be of the form 2^n #define STATE_SERVER 1 #define STATE_OUTOFSYNC 2 #define STATE_REQUESTEDSYNC 4 enum { NWT_SS_WE_STATE = 1000000, NWT_SS_B, NWT_SS_FLAGS, NWT_SS_MOUSEDIRX, NWT_SS_MOUSEDIRY, NWT_SS_MOUSEDIRZ, NWT_SS_MOUSEDIRW, NWT_SS_PN_SYNC, NWT_SS_VELX, NWT_SS_VELY, NWT_SS_VELZ, NWT_SS_PL_SYNC, NWT_SS_CO_N, NWT_SS_CO_CLID, NWT_HS_HOST_ID, NWT_HS_NGM_ID, NWT_PL_B, NWT_PL_FLAGS, NWT_PL_SCORE, NWT_PN_BO_WRITESTATE, NWT_PN_PARENTMODE, NWT_PN_COORX, NWT_PN_COORY, NWT_PN_COORZ, NWT_PN_ROTX, NWT_PN_ROTY, NWT_PN_ROTZ, NWT_PN_ROTV, NWT_PN_FLAGS, NWT_PN_SCOORX, NWT_PN_SCOORY, NWT_PN_SCOORZ, NWT_PN_SROTX, NWT_PN_SROTY, NWT_PN_SROTZ, NWT_PN_SROTV, NWT_BO_NAME, NWT_WE_PN_WRITESTATE, NWT_WE_PN_MODELFILENAME, NWT_WE_PN_SCALING, NWT_GT_WE_STATE, NWT_SB_WE_STATE, NWT_SB_SIZE, NWT_SB_TEXTURENAME, NWT_TER_WE_STATE, NWT_PU_WE_STATE, NWT_TPU_WE_STATE, NWT_LPU_WE_STATE, NWT_WPU_WE_STATE, NWT_PPU_WE_STATE, NWT_PPU_TYPE, NWT_PPU_VALUE, NWT_PPU_MINVALUE, NWT_PPU_MAXVALUE, NWT_WAT_STATE, NWT_WAT_WE_STATE, NWT_WAT_SIZEX, NWT_WAT_SIZEY, NWT_WAT_RESX, NWT_WAT_RESY, NWT_WAT_HEIGHT }; //macros to help writing data in byte buffer /* * Important: these macros must be used in * SYNCHELP_READ_*: virtual void writeBytes(const byte* data, int length, int sender); * SYNCHELP_WRITE_*: virtual int readBytes(byte* data, int maxLength, int * reciever); * with the same argument names! * * id is one int out of that enum on top of this comment it is used to identify * read/write. when you read a value you have to use exactly the same as you used * to write or you will see an assertion failing. * * SYNCHELP_WRITE_BEGIN() * SYNCHELP_WRITE_INT(i,id) * SYNCHELP_WRITE_FLOAT(f,id) * SYNCHELP_WRITE_BYTE(b,id) * SYNCHELP_WRITE_STRING(s,id) * SYNCHELP_WRITE_N * * SYNCHELP_READ_BEGIN() * SYNCHELP_READ_INT(i,id) * SYNCHELP_READ_FLOAT(f,id) * SYNCHELP_READ_STRING(s,l,id) l = size of buffer s * SYNCHELP_READ_STRINGM(s,id) allocates memory for string! you have to delete this later * SYNCHELP_READ_BYTE(b,id) * SYNCHELP_READ_REMAINING() returns the remaining buffer size * SYNCHELP_READ_NEXTBYTE() reads the next byte but it is not removed from the buffer * SYNCHELP_READ_N * * * * Example 1: * SYNCHELP_READ_BEGIN(); * SYNCHELP_READ_FLOAT(size); * SYNCHELP_READ_STRING( textureName, 1024 ); //1024 is the length of textureName * delete[] textureName; * textureName = NULL; * SYNCHELP_READ_STRINGM( texturename ); //this will call new char[strlen()+1] * * Example 2: * SYNCHELP_WRITE_BEGIN(); * SYNCHELP_WRITE_FLOAT(this->size); * SYNCHELP_WRITE_STRING(this->textureName); * return SYNCHELP_WRITE_N; * */ #define SYNCHELP_WRITE_DEBUG(n) {\ __synchelp_write_n = Converter::intToByteArray( n, data+__synchelp_write_i, maxLength-__synchelp_write_i ); \ assert( __synchelp_write_n == INTSIZE ); \ __synchelp_write_i += __synchelp_write_n; \ } #define SYNCHELP_READ_DEBUG(n) { \ int nn; \ __synchelp_read_n = Converter::byteArrayToInt( data+__synchelp_read_i, &nn ); \ assert( __synchelp_read_n == INTSIZE ); \ if ( n != nn ) { \ PRINTF(1)("Check your code! read/writes not in right order! read %d instead of %d\n", nn, n); \ assert( false ); \ } \ __synchelp_read_i += __synchelp_read_n; \ } #define SYNCHELP_WRITE_BEGIN() int __synchelp_write_i = 0; \ int __synchelp_write_n #define SYNCHELP_WRITE_INT(i,n) { SYNCHELP_WRITE_DEBUG(n); \ __synchelp_write_n = \ Converter::intToByteArray( i, data+__synchelp_write_i, maxLength-__synchelp_write_i ); \ assert( __synchelp_write_n == INTSIZE ); \ if ( __synchelp_write_n <= 0) \ { \ PRINTF(1)("Buffer is too small to store a int\n"); \ return 0; \ } \ __synchelp_write_i += __synchelp_write_n; \ } #define SYNCHELP_WRITE_FLOAT(f,n) { SYNCHELP_WRITE_DEBUG(n); \ __synchelp_write_n = \ Converter::floatToByteArray( f, data+__synchelp_write_i, maxLength-__synchelp_write_i ); \ assert( __synchelp_write_n == FLOATSIZE ); \ if ( __synchelp_write_n <= 0) \ { \ PRINTF(1)("Buffer is too small to store a float\n"); \ return 0; \ } \ __synchelp_write_i += __synchelp_write_n; \ } #define SYNCHELP_WRITE_BYTE(b,n) { SYNCHELP_WRITE_DEBUG(n); \ \ if (maxLength - __synchelp_write_i < 1) \ { \ PRINTF(1)("Buffer is too small to store string\n"); \ return 0; \ } \ data[__synchelp_write_i] = b; \ __synchelp_write_i++; \ } #define SYNCHELP_WRITE_STRING(s,n) { SYNCHELP_WRITE_DEBUG(n); \ if (s!=NULL) {\ __synchelp_write_n = \ Converter::stringToByteArray( s, data+__synchelp_write_i, strlen(s), maxLength-__synchelp_write_i ); \ assert( __synchelp_write_n == strlen(s)+INTSIZE ); \ } else {\ __synchelp_write_n = \ Converter::stringToByteArray( "", data+__synchelp_write_i, strlen(""), maxLength-__synchelp_write_i ); \ assert( __synchelp_write_n == strlen("")+INTSIZE ); } \ if ( __synchelp_write_n <= 0) \ { \ PRINTF(1)("Buffer is too small to store string\n"); \ return 0; \ } \ __synchelp_write_i += __synchelp_write_n; \ } #define SYNCHELP_WRITE_N __synchelp_write_i #define SYNCHELP_WRITE_FKT(f,n) { SYNCHELP_WRITE_DEBUG(n); \ __synchelp_write_i += \ f( data+__synchelp_write_i, maxLength-__synchelp_write_i ); \ } #define SYNCHELP_READ_BEGIN() int __synchelp_read_i = 0; \ int __synchelp_read_n #define SYNCHELP_READ_INT(i,n) { SYNCHELP_READ_DEBUG(n); \ if ( length-__synchelp_read_i < INTSIZE ) \ { \ PRINTF(1)("There is not enough data to read an int\n"); \ return 0; \ } \ __synchelp_read_n = Converter::byteArrayToInt( data+__synchelp_read_i, &i ); \ assert( __synchelp_read_n == INTSIZE ); \ __synchelp_read_i += __synchelp_read_n; \ } #define SYNCHELP_READ_FLOAT(f,n) { SYNCHELP_READ_DEBUG(n); \ if ( length-__synchelp_read_i < FLOATSIZE ) \ { \ PRINTF(1)("There is not enough data to read a flaot\n"); \ return 0; \ } \ __synchelp_read_n = Converter::byteArrayToFloat( data+__synchelp_read_i, &f ); \ assert( __synchelp_read_n == FLOATSIZE ) ;\ __synchelp_read_i += __synchelp_read_n; \ } #define SYNCHELP_READ_STRING(s,l,n) {SYNCHELP_READ_DEBUG(n); \ __synchelp_read_n = Converter::byteArrayToString( data+__synchelp_read_i, s, l ); \ assert( __synchelp_read_n == strlen(s)+INTSIZE ) ;\ if ( __synchelp_read_n <0 ) \ { \ PRINTF(1)("There is not enough data to read string\n"); \ return 0; \ } \ __synchelp_read_i += __synchelp_read_n; \ } #define SYNCHELP_READ_STRINGM(s,n) { SYNCHELP_READ_DEBUG(n); \ __synchelp_read_n = Converter::byteArrayToStringM( data+__synchelp_read_i, s ); \ assert( __synchelp_read_n == strlen(s)+INTSIZE ) ;\ if ( __synchelp_read_n <0 ) \ { \ PRINTF(1)("There is not enough data to read string\n"); \ return 0; \ } \ __synchelp_read_i += __synchelp_read_n; \ } #define SYNCHELP_READ_BYTE(b,n) { SYNCHELP_READ_DEBUG(n); \ if ( length-__synchelp_read_i < 1 ) \ { \ PRINTF(1)("There is not enough data to read a byte\n"); \ return 0; \ } \ b = data[__synchelp_read_i]; \ __synchelp_read_i ++; \ } #define SYNCHELP_READ_FKT(f,n) { SYNCHELP_READ_DEBUG(n); \ __synchelp_read_i += \ f( data+__synchelp_read_i, length-__synchelp_read_i, sender); \ } #define SYNCHELP_READ_REMAINING() ( length-__synchelp_read_i ) #define SYNCHELP_READ_NEXTBYTE() ( data[__synchelp_read_i] ) #define SYNCHELP_READ_N __synchelp_read_i class NetworkStream; class Synchronizeable : virtual public BaseObject { public: Synchronizeable(); virtual ~Synchronizeable(); virtual int writeBytes(const byte* data, int length, int sender); virtual int readBytes(byte* data, int maxLength, int * reciever); virtual void writeDebug() const; virtual void readDebug() const; void setIsServer( bool isServer ); void setIsOutOfSync( bool outOfSync ); void setRequestedSync( bool requestedSync ); bool isServer(); bool isOutOfSync(); bool requestedSync(); inline void setUniqueID( int id ){ uniqueID = id; } inline int getUniqueID() const { return uniqueID; } inline int getHostID() { return this->hostID; } inline int getOwner(){ return owner; } inline void setOwner(int owner){ this->owner = owner; } /** @returns true if this Synchronizeable has to be synchronized over network */ inline bool beSynchronized() { return this->bSynchronize; } /** @param bSynchronize sets the Synchronizeable to be sunchronized or not */ inline void setSynchronized(bool bSynchronize) { this->bSynchronize = bSynchronize; } inline void requestSync( int hostID ){ this->synchronizeRequests.push_back( hostID ); } inline int getRequestSync( void ){ if ( this->synchronizeRequests.size()>0 ){ int n = *(synchronizeRequests.begin()); synchronizeRequests.pop_front(); return n; } else { return -1; } }; inline void setNetworkStream(NetworkStream* stream) { this->networkStream = stream; } inline NetworkStream* getNetworkStream() { return this->networkStream; } protected: NetworkStream* networkStream; int state; private: int uniqueID; int owner; int hostID; bool bSynchronize; std::list synchronizeRequests; }; #endif /* _SYNCHRONIZEABLE_H */