diff options
-rw-r--r-- | source/mvd_parse.c | 7 | ||||
-rw-r--r-- | source/sv_game.c | 9 | ||||
-rw-r--r-- | source/sv_local.h | 50 | ||||
-rw-r--r-- | source/sv_main.c | 22 | ||||
-rw-r--r-- | source/sv_send.c | 332 |
5 files changed, 212 insertions, 208 deletions
diff --git a/source/mvd_parse.c b/source/mvd_parse.c index 890962f..d76f03f 100644 --- a/source/mvd_parse.c +++ b/source/mvd_parse.c @@ -497,7 +497,7 @@ static void MVD_ParseSound( mvd_t *mvd, int extrabits ) { mleaf_t *leaf; int area; player_state_t *ps; - sound_packet_t *msg; + message_packet_t *msg; edict_t *entity; flags = MSG_ReadByte(); @@ -588,7 +588,7 @@ static void MVD_ParseSound( mvd_t *mvd, int extrabits ) { continue; } - msg = LIST_FIRST( sound_packet_t, &cl->msg_free, entry ); + msg = LIST_FIRST( message_packet_t, &cl->msg_free, entry ); msg->cursize = 0; msg->flags = flags; @@ -599,7 +599,8 @@ static void MVD_ParseSound( mvd_t *mvd, int extrabits ) { msg->sendchan = sendchan; List_Remove( &msg->entry ); - List_Append( &cl->msg_sound, &msg->entry ); + List_Append( &cl->msg_used[0], &msg->entry ); + cl->msg_bytes += MAX_SOUND_PACKET; } } diff --git a/source/sv_game.c b/source/sv_game.c index 9cfb42c..fa0aefe 100644 --- a/source/sv_game.c +++ b/source/sv_game.c @@ -486,7 +486,7 @@ static void PF_StartSound( edict_t *edict, int channel, mleaf_t *leaf; int area; player_state_t *ps; - sound_packet_t *msg; + message_packet_t *msg; if( !edict ) return; @@ -586,9 +586,9 @@ static void PF_StartSound( edict_t *edict, int channel, continue; } - msg = LIST_FIRST( sound_packet_t, &client->msg_free, entry ); + msg = LIST_FIRST( message_packet_t, &client->msg_free, entry ); - msg->cursize = 0; // !!! make sure this does not get Z_Free'ed + msg->cursize = 0; msg->flags = flags; msg->index = soundindex; msg->volume = volume * 255; @@ -597,7 +597,8 @@ static void PF_StartSound( edict_t *edict, int channel, msg->sendchan = sendchan; List_Remove( &msg->entry ); - List_Append( &client->msg_sound, &msg->entry ); + List_Append( &client->msg_used[0], &msg->entry ); + client->msg_bytes += MAX_SOUND_PACKET; } if( svs.mvd.dummy && sv.mvd.paused < PAUSED_FRAMES ) { diff --git a/source/sv_local.h b/source/sv_local.h index 49190ce..26b3ba8 100644 --- a/source/sv_local.h +++ b/source/sv_local.h @@ -138,22 +138,24 @@ typedef enum { #define MSG_RELIABLE 1 #define MSG_CLEAR 2 +#define MAX_SOUND_PACKET 14 + typedef struct { list_t entry; - uint16_t cursize; - byte data[MSG_TRESHOLD]; + uint16_t cursize; // zero means sound packet + union { + uint8_t data[MSG_TRESHOLD]; + struct { + uint8_t flags; + uint8_t index; + uint16_t sendchan; + uint8_t volume; + uint8_t attenuation; + uint8_t timeofs; + }; + }; } message_packet_t; -typedef struct { - list_t entry; - uint16_t cursize; - uint8_t flags; - uint8_t index; - uint16_t sendchan; - uint8_t volume; - uint8_t attenuation; - uint8_t timeofs; -} sound_packet_t; #define LATENCY_COUNTS 16 #define LATENCY_MASK ( LATENCY_COUNTS - 1 ) @@ -224,16 +226,11 @@ typedef struct client_s { // spectator speed, etc pmoveParams_t pmp; - // packetized messages for clients without - // netchan level fragmentation support + // packetized messages list_t msg_free; - list_t msg_used[2]; - list_t msg_sound; + list_t msg_used[2]; // 0 - unreliable, 1 - reliable message_packet_t *msg_pool; - - // bulk messages for clients with - // netchan level fragmentation support - sizebuf_t datagram; + size_t msg_bytes; // total size of unreliable datagram // baselines are allocated per client entity_state_t *baselines[SV_BASELINES_CHUNKS]; @@ -248,7 +245,6 @@ typedef struct client_s { // netchan type dependent methods void (*AddMessage)( struct client_s *, byte *, size_t, qboolean ); void (*WriteFrame)( struct client_s * ); - void (*FinishFrame)( struct client_s * ); void (*WriteDatagram)( struct client_s * ); netchan_t *netchan; @@ -496,16 +492,14 @@ void SV_BroadcastCommand( const char *fmt, ... ) q_printf( 1, 2 ); void SV_ClientAddMessage( client_t *client, int flags ); void SV_PacketizedClear( client_t *client ); -void SV_OldClientWriteDatagram( client_t *client ); -void SV_OldClientAddMessage( client_t *client, byte *data, +void SV_ClientWriteDatagram_Old( client_t *client ); +void SV_ClientAddMessage_Old( client_t *client, byte *data, size_t length, qboolean reliable ); -void SV_OldClientWriteReliableMessages( client_t *client, size_t maxsize ); -void SV_OldClientFinishFrame( client_t *client ); +void SV_ClientWriteReliableMessages_Old( client_t *client, size_t maxsize ); -void SV_NewClientWriteDatagram( client_t *client ); -void SV_NewClientAddMessage( client_t *client, byte *data, +void SV_ClientWriteDatagram_New( client_t *client ); +void SV_ClientAddMessage_New( client_t *client, byte *data, size_t length, qboolean reliable ); -void SV_NewClientFinishFrame( client_t *client ); void SV_CalcSendTime( client_t *client, size_t messageSize ); diff --git a/source/sv_main.c b/source/sv_main.c index 270b8f1..08b1bae 100644 --- a/source/sv_main.c +++ b/source/sv_main.c @@ -98,12 +98,6 @@ void SV_RemoveClient( client_t *client ) { client->msg_pool = NULL; } - if( client->datagram.data ) { - Z_Free( client->datagram.data ); - client->datagram.data = NULL; - client->datagram.maxsize = 0; - } - if( client->netchan ) { Netchan_Close( client->netchan ); client->netchan = NULL; @@ -522,7 +516,6 @@ static void SVC_DirectConnect( void ) { netchan_type_t nctype; char *ncstring, *acstring; int reserved; - byte *buffer; int zlib; protocol = atoi( Cmd_Argv( 1 ) ); @@ -897,7 +890,6 @@ static void SVC_DirectConnect( void ) { List_Init( &newcl->msg_free ); List_Init( &newcl->msg_used[0] ); List_Init( &newcl->msg_used[1] ); - List_Init( &newcl->msg_sound ); newcl->msg_pool = SV_Malloc( sizeof( message_packet_t ) * MSG_POOLSIZE ); for( i = 0; i < MSG_POOLSIZE; i++ ) { @@ -906,15 +898,11 @@ static void SVC_DirectConnect( void ) { // setup protocol if( nctype == NETCHAN_NEW ) { - buffer = SV_Malloc( MAX_MSGLEN ); - SZ_Init( &newcl->datagram, buffer, MAX_MSGLEN ); - newcl->AddMessage = SV_NewClientAddMessage; - newcl->WriteDatagram = SV_NewClientWriteDatagram; - newcl->FinishFrame = SV_NewClientFinishFrame; + newcl->AddMessage = SV_ClientAddMessage_New; + newcl->WriteDatagram = SV_ClientWriteDatagram_New; } else { - newcl->AddMessage = SV_OldClientAddMessage; - newcl->WriteDatagram = SV_OldClientWriteDatagram; - newcl->FinishFrame = SV_OldClientFinishFrame; + newcl->AddMessage = SV_ClientAddMessage_Old; + newcl->WriteDatagram = SV_ClientWriteDatagram_Old; } if( protocol == PROTOCOL_VERSION_DEFAULT ) { newcl->WriteFrame = SV_WriteFrameToClient_Default; @@ -1304,7 +1292,7 @@ void SV_SendAsyncPackets( void ) { // just update reliable if needed if( netchan->type == NETCHAN_OLD ) { - SV_OldClientWriteReliableMessages( client, netchan->maxpacketlen ); + SV_ClientWriteReliableMessages_Old( client, netchan->maxpacketlen ); } if( netchan->message.cursize || netchan->reliable_ack_pending || netchan->reliable_length || retransmit ) 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 ); } } |