/* ============================================================================= movevars_t communication ============================================================================= */ qboolean MSG_WriteDeltaMovevars( sizebuf_t *msg, movevars_t *from, movevars_t *to ) { delta_t *pField; delta_info_t *dt; int i, startBit; int numChanges = 0; dt = Delta_FindStruct( "movevars_t" ); ASSERT( dt && dt->bInitialized ); pField = dt->pFields; ASSERT( pField ); startBit = msg->iCurBit; // activate fields and call custom encode func Delta_CustomEncode( dt, from, to ); BF_WriteByte( msg, svc_deltamovevars ); // process fields for( i = 0; i < dt->numFields; i++, pField++ ) { if( Delta_WriteField( msg, pField, from, to, 0.0f )) numChanges++; } // if we have no changes - kill the message if( !numChanges ) { BF_SeekToBit( msg, startBit ); return false; } return true; }
/* ================== MSG_WriteWeaponData Writes current client data only for local client Other clients can grab the client state from entity_state_t ================== */ void MSG_WriteWeaponData( sizebuf_t *msg, weapon_data_t *from, weapon_data_t *to, float timebase, int index ) { delta_t *pField; delta_info_t *dt; int i, startBit; int numChanges = 0; dt = Delta_FindStruct( "weapon_data_t" ); if( !dt || !dt->bInitialized ) { Host_Error( "MSG_WriteWeaponData: delta not initialized!\n" ); } pField = dt->pFields; ASSERT( pField ); // activate fields and call custom encode func Delta_CustomEncode( dt, from, to ); startBit = msg->iCurBit; BF_WriteOneBit( msg, 1 ); BF_WriteUBitLong( msg, index, MAX_WEAPON_BITS ); // process fields for( i = 0; i < dt->numFields; i++, pField++ ) { if( Delta_WriteField( msg, pField, from, to, timebase )) numChanges++; } // if we have no changes - kill the message if( !numChanges ) BF_SeekToBit( msg, startBit ); }
/* ================== MSG_WriteDeltaEntity Writes part of a packetentities message, including the entity number. Can delta from either a baseline or a previous packet_entity If to is NULL, a remove entity update will be sent If force is not set, then nothing at all will be generated if the entity is identical, under the assumption that the in-order delta code will catch it. ================== */ void MSG_WriteDeltaEntity( entity_state_t *from, entity_state_t *to, sizebuf_t *msg, qboolean force, qboolean player, float timebase ) { delta_info_t *dt = NULL; delta_t *pField; int i, startBit; int numChanges = 0; if( to == NULL ) { int fRemoveType; if( from == NULL ) return; // a NULL to is a delta remove message BF_WriteWord( msg, from->number ); // fRemoveType: // 0 - keep alive, has delta-update // 1 - remove from delta message (but keep states) // 2 - completely remove from server if( force ) fRemoveType = 2; else fRemoveType = 1; BF_WriteUBitLong( msg, fRemoveType, 2 ); return; } startBit = msg->iCurBit; if( to->number < 0 || to->number >= GI->max_edicts ) { MsgDev( D_ERROR, "MSG_WriteDeltaEntity: Bad entity number: %i\n", to->number ); return; } BF_WriteWord( msg, to->number ); BF_WriteUBitLong( msg, 0, 2 ); // alive if( to->entityType != from->entityType ) { BF_WriteOneBit( msg, 1 ); BF_WriteUBitLong( msg, to->entityType, 2 ); } else BF_WriteOneBit( msg, 0 ); if( to->entityType == ENTITY_NORMAL ) { if( player ) { dt = Delta_FindStruct( "entity_state_player_t" ); } else { dt = Delta_FindStruct( "entity_state_t" ); } } else if( to->entityType == ENTITY_BEAM ) { dt = Delta_FindStruct( "custom_entity_state_t" ); } ASSERT( dt && dt->bInitialized ); pField = dt->pFields; ASSERT( pField ); // activate fields and call custom encode func Delta_CustomEncode( dt, from, to ); // process fields for( i = 0; i < dt->numFields; i++, pField++ ) { if( Delta_WriteField( msg, pField, from, to, timebase )) numChanges++; } // if we have no changes - kill the message if( !numChanges && !force ) BF_SeekToBit( msg, startBit ); }
/* ============================== Netchan_CopyFileFragments ============================== */ qboolean Netchan_CopyFileFragments( netchan_t *chan, sizebuf_t *msg ) { fragbuf_t *p, *n; char filename[CS_SIZE]; int nsize; byte *buffer; int pos; if( !chan->incomingready[FRAG_FILE_STREAM] ) return false; if( !chan->incomingbufs[FRAG_FILE_STREAM] ) { MsgDev( D_WARN, "Netchan_CopyFileFragments: Called with no fragments readied\n" ); chan->incomingready[FRAG_FILE_STREAM] = false; return false; } p = chan->incomingbufs[FRAG_FILE_STREAM]; BF_Init( msg, "NetMessage", net_message_buffer, sizeof( net_message_buffer )); // copy in first chunk so we can get filename out BF_WriteBits( msg, BF_GetData( &p->frag_message ), BF_GetNumBitsWritten( &p->frag_message )); BF_SeekToBit( msg, 0 ); // rewind buffer //Q_strncpy( filename, BF_ReadString( msg ), sizeof( filename )); Q_snprintf( filename, sizeof( filename ), "downloaded/%s", BF_ReadString( msg ) ); if( Q_strlen( filename ) <= 0 ) { MsgDev( D_ERROR, "File fragment received with no filename\nFlushing input queue\n" ); // clear out bufs Netchan_FlushIncoming( chan, FRAG_FILE_STREAM ); return false; } else if( Q_strstr( filename, ".." )) { MsgDev( D_ERROR, "File fragment received with relative path, ignoring\n" ); // clear out bufs Netchan_FlushIncoming( chan, FRAG_FILE_STREAM ); return false; } Q_strncpy( chan->incomingfilename, filename, sizeof( chan->incomingfilename )); if( FS_FileExists( filename, false )) { MsgDev( D_ERROR, "Can't download %s, already exists\n", filename ); // clear out bufs Netchan_FlushIncoming( chan, FRAG_FILE_STREAM ); return true; } // create file from buffers nsize = 0; while ( p ) { nsize += BF_GetNumBytesWritten( &p->frag_message ); // Size will include a bit of slop, oh well if( p == chan->incomingbufs[FRAG_FILE_STREAM] ) { nsize -= BF_GetNumBytesRead( msg ); } p = p->next; } buffer = Mem_Alloc( net_mempool, nsize + 1 ); p = chan->incomingbufs[ FRAG_FILE_STREAM ]; pos = 0; while( p ) { int cursize; n = p->next; cursize = BF_GetNumBytesWritten( &p->frag_message ); // first message has the file name, don't write that into the data stream, // just write the rest of the actual data if( p == chan->incomingbufs[FRAG_FILE_STREAM] ) { // copy it in cursize -= BF_GetNumBytesRead( msg ); Q_memcpy( &buffer[pos], &p->frag_message.pData[BF_GetNumBytesRead( msg )], cursize ); } else { Q_memcpy( &buffer[pos], p->frag_message.pData, cursize ); } pos += cursize; Mem_Free( p ); p = n; } FS_WriteFile( filename, buffer, pos ); Mem_Free( buffer ); // clear remnants BF_Clear( msg ); chan->incomingbufs[FRAG_FILE_STREAM] = NULL; // reset flag chan->incomingready[FRAG_FILE_STREAM] = false; return true; }