diff options
author | Andrey Nazarov <skuller@skuller.net> | 2008-08-21 12:07:42 +0000 |
---|---|---|
committer | Andrey Nazarov <skuller@skuller.net> | 2008-08-21 12:07:42 +0000 |
commit | 6464d32435c9b42d0a02501d019fc271f7c91ceb (patch) | |
tree | f5288308b20d0261f0ac528b34eaa34b3ce7c81b /source/sv_send.c | |
parent | babc9ddfcd2f123f919d6586d84580698488a968 (diff) |
Reworked the way datagram is built for protocol 36 clients.
Server now tries to preserve exact order of all kids of unreliable messages
if entire datagram fits into network message.
Diffstat (limited to 'source/sv_send.c')
-rw-r--r-- | source/sv_send.c | 332 |
1 files changed, 176 insertions, 156 deletions
diff --git a/source/sv_send.c b/source/sv_send.c index 680369f..e43db67 100644 --- a/source/sv_send.c +++ b/source/sv_send.c @@ -343,18 +343,18 @@ static inline void SV_PacketizedRemove( client_t *client, message_packet_t *msg } } +#define FOR_EACH_MSG_SAFE( list ) LIST_FOR_EACH_SAFE( message_packet_t, msg, next, list, entry ) + void SV_PacketizedClear( client_t *client ) { message_packet_t *msg, *next; - LIST_FOR_EACH_SAFE( message_packet_t, msg, next, &client->msg_used[0], entry ) { - SV_PacketizedRemove( client, msg ); - } - LIST_FOR_EACH_SAFE( message_packet_t, msg, next, &client->msg_used[1], entry ) { + FOR_EACH_MSG_SAFE( &client->msg_used[0] ) { SV_PacketizedRemove( client, msg ); } - LIST_FOR_EACH_SAFE( message_packet_t, msg, next, &client->msg_sound, entry ) { + FOR_EACH_MSG_SAFE( &client->msg_used[1] ) { SV_PacketizedRemove( client, msg ); } + client->msg_bytes = 0; } message_packet_t *SV_PacketizedAdd( client_t *client, byte *data, @@ -384,12 +384,14 @@ message_packet_t *SV_PacketizedAdd( client_t *client, byte *data, msg->cursize = ( uint16_t )len; List_Append( &client->msg_used[reliable], &msg->entry ); + if( !reliable ) { + client->msg_bytes += len; + } return msg; } -static void SV_AddClientSounds( client_t *client, size_t maxsize ) { - sound_packet_t *msg, *next; +static void emit_snd( client_t *client, message_packet_t *msg ) { edict_t *edict; entity_state_t *state; vec3_t origin; @@ -397,75 +399,93 @@ static void SV_AddClientSounds( client_t *client, size_t maxsize ) { int flags, entnum; int i, j; - frame = &client->frames[sv.framenum & UPDATE_MASK]; + entnum = msg->sendchan >> 3; + flags = msg->flags; - LIST_FOR_EACH_SAFE( sound_packet_t, msg, next, &client->msg_sound, entry ) { - entnum = msg->sendchan >> 3; - flags = msg->flags; + edict = EDICT_POOL( client, entnum ); + + // send origin for invisible entities + if( edict->svflags & SVF_NOCLIENT ) { + flags |= SND_POS; + } - edict = EDICT_POOL( client, entnum ); - - // send origin for invisible entities - if( edict->svflags & SVF_NOCLIENT ) { - flags |= SND_POS; - } + // default client doesn't know that bmodels have weird origins + if( edict->solid == SOLID_BSP && client->protocol == PROTOCOL_VERSION_DEFAULT ) { + flags |= SND_POS; + } - // default client doesn't know that bmodels have weird origins - if( edict->solid == SOLID_BSP && client->protocol == PROTOCOL_VERSION_DEFAULT ) { - flags |= SND_POS; - } + // check if position needs to be explicitly sent + if( ( flags & SND_POS ) == 0 ) { + frame = &client->frames[sv.framenum & UPDATE_MASK]; - // check if position needs to be explicitly sent - if( ( flags & SND_POS ) == 0 ) { - for( i = 0; i < frame->numEntities; i++ ) { - j = ( frame->firstEntity + i ) % svs.numEntityStates; - state = &svs.entityStates[j]; - if( state->number == entnum ) { - break; - } + for( i = 0; i < frame->numEntities; i++ ) { + j = ( frame->firstEntity + i ) % svs.numEntityStates; + state = &svs.entityStates[j]; + if( state->number == entnum ) { + break; } - if( i == frame->numEntities ) { - if( sv_debug_send->integer ) { - Com_Printf( S_COLOR_BLUE "Forcing position on entity %d for %s\n", - entnum, client->name ); - } - flags |= SND_POS; // entity is not present in frame + } + if( i == frame->numEntities ) { + if( sv_debug_send->integer ) { + Com_Printf( S_COLOR_BLUE "Forcing position on entity %d for %s\n", + entnum, client->name ); } + flags |= SND_POS; // entity is not present in frame } + } + + MSG_WriteByte( svc_sound ); + MSG_WriteByte( flags ); + MSG_WriteByte( msg->index ); - // if this msg fits, write it - if( msg_write.cursize + 16 > maxsize ) { - break; + if( flags & SND_VOLUME ) + MSG_WriteByte( msg->volume ); + if( flags & SND_ATTENUATION ) + MSG_WriteByte( msg->attenuation ); + if( flags & SND_OFFSET ) + MSG_WriteByte( msg->timeofs ); + + MSG_WriteShort( msg->sendchan ); + + if( flags & SND_POS ) { + // use the entity origin unless it is a bmodel + if( edict->solid == SOLID_BSP ) { + VectorAvg( edict->mins, edict->maxs, origin ); + VectorAdd( edict->s.origin, origin, origin ); + } else { + VectorCopy( edict->s.origin, origin ); } - MSG_WriteByte( svc_sound ); - MSG_WriteByte( flags ); - MSG_WriteByte( msg->index ); + MSG_WritePos( origin ); + } +} - if( flags & SND_VOLUME ) - MSG_WriteByte( msg->volume ); - if( flags & SND_ATTENUATION ) - MSG_WriteByte( msg->attenuation ); - if( flags & SND_OFFSET ) - MSG_WriteByte( msg->timeofs ); +static inline void write_snd( client_t *client, message_packet_t *msg, size_t maxsize ) { + // if this msg fits, write it + if( msg_write.cursize + MAX_SOUND_PACKET <= maxsize ) { + emit_snd( client, msg ); + } + List_Remove( &msg->entry ); + List_Insert( &client->msg_free, &msg->entry ); +} - MSG_WriteShort( msg->sendchan ); +static inline void write_msg( client_t *client, message_packet_t *msg, size_t maxsize ) { + // if this msg fits, write it + if( msg_write.cursize + msg->cursize <= maxsize ) { + MSG_WriteData( msg->data, msg->cursize ); + } + SV_PacketizedRemove( client, msg ); +} - if( flags & SND_POS ) { - // use the entity origin unless it is a bmodel - if( edict->solid == SOLID_BSP ) { - VectorAvg( edict->mins, edict->maxs, origin ); - VectorAdd( edict->s.origin, origin, origin ); - } else { - VectorCopy( edict->s.origin, origin ); - } +static inline void emit_messages( client_t *client, size_t maxsize ) { + message_packet_t *msg, *next; - MSG_WritePos( origin ); + FOR_EACH_MSG_SAFE( &client->msg_used[0] ) { + if( msg->cursize ) { + write_msg( client, msg, maxsize ); + } else { + write_snd( client, msg, maxsize ); } - - // move message to the free pool - List_Remove( &msg->entry ); - List_Insert( &client->msg_free, &msg->entry ); } } @@ -477,9 +497,8 @@ FRAME UPDATES - DEFAULT, R1Q2 AND Q2PRO CLIENTS (OLD NETCHAN) =============================================================================== */ -#define FOR_EACH_MSG( list ) LIST_FOR_EACH_SAFE( message_packet_t, msg, next, list, entry ) -void SV_OldClientAddMessage( client_t *client, byte *data, +void SV_ClientAddMessage_Old( client_t *client, byte *data, size_t len, qboolean reliable ) { if( len > client->netchan->maxpacketlen ) { @@ -496,13 +515,13 @@ void SV_OldClientAddMessage( client_t *client, byte *data, /* ======================= -SV_OldClient_SendReliableMessages +SV_ClientWriteReliableMessages_Old This should be the only place data is ever written to client->netchan.message ======================= */ -void SV_OldClientWriteReliableMessages( client_t *client, size_t maxsize ) { +void SV_ClientWriteReliableMessages_Old( client_t *client, size_t maxsize ) { message_packet_t *msg, *next; int count; @@ -515,7 +534,7 @@ void SV_OldClientWriteReliableMessages( client_t *client, size_t maxsize ) { // find at least one reliable message to send count = 0; - FOR_EACH_MSG( &client->msg_used[1] ) { + FOR_EACH_MSG_SAFE( &client->msg_used[1] ) { // stop if this msg doesn't fit (reliables must be delivered in order) if( client->netchan->message.cursize + msg->cursize > maxsize ) { if( !count ) { @@ -536,22 +555,69 @@ void SV_OldClientWriteReliableMessages( client_t *client, size_t maxsize ) { } } -static inline void write_msg( client_t *client, message_packet_t *msg, size_t maxsize ) { - // if this msg fits, write it - if( msg_write.cursize + msg->cursize <= maxsize ) { - MSG_WriteData( msg->data, msg->cursize ); +static void repack_messages( client_t *client, size_t maxsize ) { + message_packet_t *msg, *next; + + if( msg_write.cursize + 4 > maxsize ) { + return; + } + + // temp entities first + FOR_EACH_MSG_SAFE( &client->msg_used[0] ) { + if( !msg->cursize || msg->data[0] != svc_temp_entity ) { + continue; + } + // ignore some low-priority effects, these checks come from r1q2 + if( msg->data[1] == TE_BLOOD || msg->data[1] == TE_SPLASH || + msg->data[1] == TE_GUNSHOT || msg->data[1] == TE_BULLET_SPARKS || + msg->data[1] == TE_SHOTGUN ) + { + continue; + } + write_msg( client, msg, maxsize ); + } + + if( msg_write.cursize + 4 > maxsize ) { + return; + } + + // then entity sounds + FOR_EACH_MSG_SAFE( &client->msg_used[0] ) { + if( !msg->cursize ) { + write_snd( client, msg, maxsize ); + } + } + + if( msg_write.cursize + 4 > maxsize ) { + return; + } + + // then positioned sounds + FOR_EACH_MSG_SAFE( &client->msg_used[0] ) { + if( msg->cursize && msg->data[0] == svc_sound ) { + write_msg( client, msg, maxsize ); + } } - SV_PacketizedRemove( client, msg ); -} + if( msg_write.cursize + 4 > maxsize ) { + return; + } + + // then everything else left + FOR_EACH_MSG_SAFE( &client->msg_used[0] ) { + if( msg->cursize ) { + write_msg( client, msg, maxsize ); + } + } +} /* ======================= -OldClient_SendDatagram +SV_ClientWriteDatagram_Old ======================= */ -void SV_OldClientWriteDatagram( client_t *client ) { - message_packet_t *msg, *next; +void SV_ClientWriteDatagram_Old( client_t *client ) { + message_packet_t *msg; size_t maxsize, cursize; maxsize = client->netchan->maxpacketlen; @@ -578,50 +644,19 @@ void SV_OldClientWriteDatagram( client_t *client ) { SZ_Clear( &msg_write ); } - // now try to write unreliable messages - // it is necessary for this to be after the WriteEntities + // now write unreliable messages + // it is necessary for this to be after the WriteFrame // so that entity references will be current - if( msg_write.cursize + 4 <= maxsize ) { - // temp entities first - FOR_EACH_MSG( &client->msg_used[0] ) { - if( msg->data[0] != svc_temp_entity ) { - continue; - } - // ignore some low-priority effects, these checks come from r1q2 - if( msg->data[1] == TE_BLOOD || msg->data[1] == TE_SPLASH || - msg->data[1] == TE_GUNSHOT || msg->data[1] == TE_BULLET_SPARKS || - msg->data[1] == TE_SHOTGUN ) - { - continue; - } - write_msg( client, msg, maxsize ); - } - - if( msg_write.cursize + 4 <= maxsize ) { - // then entity sounds - SV_AddClientSounds( client, maxsize ); - - // then positioned sounds - if( msg_write.cursize + 4 <= maxsize ) { - FOR_EACH_MSG( &client->msg_used[0] ) { - if( msg->data[0] != svc_sound ) { - continue; - } - write_msg( client, msg, maxsize ); - } + if( msg_write.cursize + client->msg_bytes > maxsize ) { + // throw out some low priority effects + repack_messages( client, maxsize ); + } else { + // all messages fit, write them in order + emit_messages( client, maxsize ); + } - if( msg_write.cursize + 4 <= maxsize ) { - // then everything else left - FOR_EACH_MSG( &client->msg_used[0] ) { - write_msg( client, msg, maxsize ); - } - } - } - } - } - // write at least one reliable message - SV_OldClientWriteReliableMessages( client, + SV_ClientWriteReliableMessages_Old( client, client->netchan->maxpacketlen - msg_write.cursize ); // send the datagram @@ -634,19 +669,6 @@ void SV_OldClientWriteDatagram( client_t *client ) { SZ_Clear( &msg_write ); } -void SV_OldClientFinishFrame( client_t *client ) { - message_packet_t *msg, *next; - - // clear all unreliable messages still left - FOR_EACH_MSG( &client->msg_used[0] ) { - SV_PacketizedRemove( client, msg ); - } - - FOR_EACH_MSG( &client->msg_sound ) { - SV_PacketizedRemove( client, msg ); - } -} - /* =============================================================================== @@ -655,14 +677,17 @@ FRAME UPDATES - Q2PRO CLIENTS (NEW NETCHAN) =============================================================================== */ -void SV_NewClientAddMessage( client_t *client, byte *data, - size_t length, qboolean reliable ) +void SV_ClientAddMessage_New( client_t *client, byte *data, + size_t len, qboolean reliable ) { - sizebuf_t *buf = reliable ? &client->netchan->message : &client->datagram; - SZ_Write( buf, data, length ); + if( reliable ) { + SZ_Write( &client->netchan->message, data, len ); + } else { + SV_PacketizedAdd( client, data, len, qfalse ); + } } -void SV_NewClientWriteDatagram( client_t *client ) { +void SV_ClientWriteDatagram_New( client_t *client ) { size_t cursize; // send over all the relevant entity_state_t @@ -675,19 +700,15 @@ void SV_NewClientWriteDatagram( client_t *client ) { SZ_Clear( &msg_write ); } - // copy the accumulated multicast datagram + // now write unreliable messages // for this client out to the message - // it is necessary for this to be after the WriteEntities + // it is necessary for this to be after the WriteFrame // so that entity references will be current - if( client->datagram.overflowed ) { - Com_WPrintf( "Datagram overflowed for %s\n", client->name ); - } else if( msg_write.cursize + client->datagram.cursize > msg_write.maxsize ) { + if( msg_write.cursize + client->msg_bytes > msg_write.maxsize ) { Com_WPrintf( "Dumping datagram for %s\n", client->name ); - } else { - MSG_WriteData( client->datagram.data, client->datagram.cursize ); - } - - SV_AddClientSounds( client, msg_write.maxsize ); + } else { + emit_messages( client, msg_write.maxsize ); + } if( sv_pad_packets->integer ) { size_t pad = msg_write.cursize + sv_pad_packets->integer; @@ -711,16 +732,6 @@ void SV_NewClientWriteDatagram( client_t *client ) { SZ_Clear( &msg_write ); } -void SV_NewClientFinishFrame( client_t *client ) { - message_packet_t *msg, *next; - - // clear all unreliable messages still left - SZ_Clear( &client->datagram ); - - FOR_EACH_MSG( &client->msg_sound ) { - SV_PacketizedRemove( client, msg ); - } -} /* =============================================================================== @@ -730,6 +741,15 @@ COMMON STUFF =============================================================================== */ +static void finish_frame( client_t *client ) { + message_packet_t *msg, *next; + + FOR_EACH_MSG_SAFE( &client->msg_used[0] ) { + SV_PacketizedRemove( client, msg ); + } + client->msg_bytes = 0; +} + /* ======================= SV_SendClientMessages @@ -774,8 +794,8 @@ void SV_SendClientMessages( void ) { } finish: - // clear the unreliable datagram - client->FinishFrame( client ); + // clear all unreliable messages still left + finish_frame( client ); } } |