/* ============= SV_EmitPings ============= */ void SV_EmitPings( sizebuf_t *msg ) { sv_client_t *cl; int packet_loss; int i, ping; BF_WriteByte( msg, svc_updatepings ); for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ ) { if( cl->state != cs_spawned ) continue; SV_GetPlayerStats( cl, &ping, &packet_loss ); // there are 25 bits for each client BF_WriteOneBit( msg, 1 ); BF_WriteUBitLong( msg, i, MAX_CLIENT_BITS ); BF_WriteUBitLong( msg, ping, 12 ); BF_WriteUBitLong( msg, packet_loss, 7 ); } // end marker BF_WriteOneBit( msg, 0 ); }
/* ================== 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 ); }
void Delta_WriteTableField( sizebuf_t *msg, int tableIndex, const delta_t *pField ) { int nameIndex; delta_info_t *dt; ASSERT( pField ); if( !pField->name || !*pField->name ) return; // not initialized ? dt = Delta_FindStructByIndex( tableIndex ); ASSERT( dt && dt->bInitialized ); nameIndex = Delta_IndexForFieldInfo( dt->pInfo, pField->name ); ASSERT( nameIndex >= 0 && nameIndex < dt->maxFields ); BF_WriteByte( msg, svc_deltatable ); BF_WriteUBitLong( msg, tableIndex, 4 ); // assume we support 16 network tables BF_WriteUBitLong( msg, nameIndex, 8 ); // 255 fields by struct should be enough BF_WriteUBitLong( msg, pField->flags, 10 ); // flags are indicated various input types BF_WriteUBitLong( msg, pField->bits - 1, 5 ); // max received value is 32 (32 bit) // multipliers is null-compressed if( pField->multiplier != 1.0f ) { BF_WriteOneBit( msg, 1 ); BF_WriteFloat( msg, pField->multiplier ); } else BF_WriteOneBit( msg, 0 ); if( pField->post_multiplier != 1.0f ) { BF_WriteOneBit( msg, 1 ); BF_WriteFloat( msg, pField->post_multiplier ); } else BF_WriteOneBit( msg, 0 ); }
int SV_SoundIndex( const char *filename ) { char name[64]; int i; // don't precache sentence names! if( !filename || !filename[0] || filename[0] == '!' ) return 0; Q_strncpy( name, filename, sizeof( name )); COM_FixSlashes( name ); for( i = 1; i < MAX_SOUNDS && sv.sound_precache[i][0]; i++ ) { if( !Q_stricmp( sv.sound_precache[i], name )) return i; } if( i == MAX_SOUNDS ) { Host_Error( "SV_SoundIndex: MAX_SOUNDS limit exceeded\n" ); return 0; } // register new sound Q_strncpy( sv.sound_precache[i], name, sizeof( sv.sound_precache[i] )); if( sv.state != ss_loading ) { // send the update to everyone BF_WriteByte( &sv.reliable_datagram, svc_soundindex ); BF_WriteUBitLong( &sv.reliable_datagram, i, MAX_SOUND_BITS ); BF_WriteString( &sv.reliable_datagram, name ); } return i; }
int SV_ModelIndex( const char *filename ) { char name[64]; int i; if( !filename || !filename[0] ) return 0; if( *filename == '!' ) filename++; Q_strncpy( name, filename, sizeof( name )); COM_FixSlashes( name ); for( i = 1; i < MAX_MODELS && sv.model_precache[i][0]; i++ ) { if( !Q_stricmp( sv.model_precache[i], name )) return i; } if( i == MAX_MODELS ) { Host_Error( "SV_ModelIndex: MAX_MODELS limit exceeded\n" ); return 0; } // register new model Q_strncpy( sv.model_precache[i], name, sizeof( sv.model_precache[i] )); if( sv.state != ss_loading ) { // send the update to everyone BF_WriteByte( &sv.reliable_datagram, svc_modelindex ); BF_WriteUBitLong( &sv.reliable_datagram, i, MAX_MODEL_BITS ); BF_WriteString( &sv.reliable_datagram, name ); } return i; }
/* ============= SV_EmitEvents ============= */ static void SV_EmitEvents( sv_client_t *cl, client_frame_t *to, sizebuf_t *msg ) { event_state_t *es; event_info_t *info; entity_state_t *state; event_args_t nullargs; int ev_count = 0; int count, ent_index; int i, j, ev; Q_memset( &nullargs, 0, sizeof( nullargs )); es = &cl->events; // count events for( ev = 0; ev < MAX_EVENT_QUEUE; ev++ ) { if( es->ei[ev].index ) ev_count++; } // nothing to send if( !ev_count ) return; // nothing to send if( ev_count >= 31 ) ev_count = 31; for( i = 0; i < MAX_EVENT_QUEUE; i++ ) { info = &es->ei[i]; if( info->index == 0 ) continue; ent_index = info->entity_index; for( j = 0; j < to->num_entities; j++ ) { state = &svs.packet_entities[(to->first_entity+j)%svs.num_client_entities]; if( state->number == ent_index ) break; } if( j >= to->num_entities ) { // couldn't find info->packet_index = to->num_entities; info->args.entindex = ent_index; } else { info->packet_index = j; info->args.ducking = 0; if(!( info->args.flags & FEVENT_ORIGIN )) VectorClear( info->args.origin ); if(!( info->args.flags & FEVENT_ANGLES )) VectorClear( info->args.angles ); VectorClear( info->args.velocity ); } } BF_WriteByte( msg, svc_event ); // create message BF_WriteUBitLong( msg, ev_count, 5 ); // up to MAX_EVENT_QUEUE events for( count = i = 0; i < MAX_EVENT_QUEUE; i++ ) { info = &es->ei[i]; if( info->index == 0 ) { info->packet_index = -1; info->entity_index = -1; continue; } // only send if there's room if( count < ev_count ) { BF_WriteUBitLong( msg, info->index, MAX_EVENT_BITS ); // 1024 events if( info->packet_index == -1 ) { BF_WriteOneBit( msg, 0 ); } else { BF_WriteOneBit( msg, 1 ); BF_WriteUBitLong( msg, info->packet_index, MAX_ENTITY_BITS ); if( !Q_memcmp( &nullargs, &info->args, sizeof( event_args_t ))) { BF_WriteOneBit( msg, 0 ); } else { BF_WriteOneBit( msg, 1 ); MSG_WriteDeltaEvent( msg, &nullargs, &info->args ); } } if( info->fire_time ) { BF_WriteOneBit( msg, 1 ); BF_WriteWord( msg, Q_rint( info->fire_time * 100.0f )); } else BF_WriteOneBit( msg, 0 ); } info->index = 0; info->packet_index = -1; info->entity_index = -1; count++; } }
/* ================== 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 ); }