/* ======================= SV_SendClientMessages ======================= */ void SV_SendClientMessages( void ) { sv_client_t *cl; int i; if( sv.state == ss_dead ) return; // send a message to each connected client for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ ) { if( !cl->state ) continue; if( !cl->edict || (cl->edict->v.flags & (FL_FAKECLIENT|FL_SPECTATOR))) continue; // update any userinfo packets that have changed if( cl->sendinfo ) { cl->sendinfo = false; SV_FullClientUpdate( cl, &sv.multicast ); } if( cl->sendmovevars ) { cl->sendmovevars = false; SV_UpdatePhysinfo( cl, &sv.multicast ); } // if the reliable message overflowed, drop the client if( cl->netchan.message.overflowed ) { MSG_Clear( &cl->netchan.message ); MSG_Clear( &cl->reliable ); MSG_Clear( &cl->datagram ); SV_BroadcastPrintf( PRINT_HIGH, "%s overflowed\n", cl->name ); SV_DropClient( cl ); cl->send_message = true; } // only send messages if the client has sent one if( !cl->send_message ) continue; if( cl->state == cs_spawned ) { // don't overrun bandwidth if( SV_RateDrop( cl )) continue; SV_SendClientDatagram( cl ); } else { // just update reliable if( cl->netchan.message.cursize || svs.realtime - cl->netchan.last_sent > 1000 ) Netchan_Transmit( &cl->netchan, 0, NULL ); } // yes, message really sended cl->send_message = false; } }
/* * SV_SendClientMessages */ void SV_SendClientMessages( void ) { int i; client_t *client; // send a message to each connected client for( i = 0, client = svs.clients; i < sv_maxclients->integer; i++, client++ ) { if( client->state == CS_FREE || client->state == CS_ZOMBIE ) continue; if( client->edict && ( client->edict->r.svflags & SVF_FAKECLIENT ) ) { client->lastSentFrameNum = sv.framenum; continue; } if( !client->tvclient ) { SV_UpdateActivity(); } if( client->state == CS_SPAWNED ) { if( !SV_SendClientDatagram( client ) ) { Com_Printf( "Error sending message to %s: %s\n", client->name, NET_ErrorString() ); if( client->reliable ) { SV_DropClient( client, DROP_TYPE_GENERAL, "Error sending message: %s\n", NET_ErrorString() ); } } } else { // send pending reliable commands, or send heartbeats for not timing out if( client->reliableSequence > client->reliableAcknowledge || svs.realtime - client->lastPacketSentTime > 1000 ) { SV_InitClientMessage( client, &tmpMessage, NULL, 0 ); SV_AddReliableCommandsToMessage( client, &tmpMessage ); if( !SV_SendMessageToClient( client, &tmpMessage ) ) { Com_Printf( "Error sending message to %s: %s\n", client->name, NET_ErrorString() ); if( client->reliable ) { SV_DropClient( client, DROP_TYPE_GENERAL, "Error sending message: %s\n", NET_ErrorString() ); } } } } } }
/* ======================= SV_SendClientMessages ======================= */ void SV_SendClientMessages( void ) { sv_client_t *cl; int i; svs.currentPlayer = NULL; svs.currentPlayerNum = 0; if( sv.state == ss_dead ) return; SV_UpdateToReliableMessages (); // send a message to each connected client for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ ) { if( !cl->state || cl->fakeclient ) continue; if( cl->skip_message ) { cl->skip_message = false; continue; } if( !host_limitlocal->integer && NET_IsLocalAddress( cl->netchan.remote_address )) cl->send_message = true; if( cl->state == cs_spawned ) { // Try to send a message as soon as we can. // If the target time for sending is within the next frame interval ( based on last frame ), // trigger the send now. Note that in single player, // send_message is also set to true any time a packet arrives from the client. float time_unti_next_message = cl->next_messagetime - (host.realtime + host.frametime); if( time_unti_next_message <= 0.0f ) cl->send_message = true; // something got hosed if( time_unti_next_message > 2.0f ) cl->send_message = true; } // if the reliable message overflowed, drop the client if( BF_CheckOverflow( &cl->netchan.message )) { BF_Clear( &cl->netchan.message ); BF_Clear( &cl->datagram ); SV_BroadcastPrintf( PRINT_HIGH, "%s overflowed\n", cl->name ); MsgDev( D_WARN, "reliable overflow for %s\n", cl->name ); SV_DropClient( cl ); cl->send_message = true; cl->netchan.cleartime = 0; // don't choke this message } else if( cl->send_message ) { // If we haven't gotten a message in sv_failuretime seconds, then stop sending messages to this client // until we get another packet in from the client. This prevents crash/drop and reconnect where they are // being hosed with "sequenced packet without connection" packets. if(( host.realtime - cl->netchan.last_received ) > sv_failuretime->value ) cl->send_message = false; } // only send messages if the client has sent one // and the bandwidth is not choked if( !cl->send_message ) continue; // Bandwidth choke active? if( !Netchan_CanPacket( &cl->netchan )) { cl->chokecount++; continue; } cl->send_message = false; // Now that we were able to send, reset timer to point to next possible send time. cl->next_messagetime = host.realtime + host.frametime + cl->cl_updaterate; if( cl->state == cs_spawned ) { SV_SendClientDatagram( cl ); } else { // just update reliable Netchan_Transmit( &cl->netchan, 0, NULL ); } } // reset current client svs.currentPlayer = NULL; svs.currentPlayerNum = 0; }