summaryrefslogtreecommitdiff
path: root/src/server/sv_main.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/sv_main.c')
-rw-r--r--src/server/sv_main.c219
1 files changed, 217 insertions, 2 deletions
diff --git a/src/server/sv_main.c b/src/server/sv_main.c
index f6d5a7c4..ba9bf2c6 100644
--- a/src/server/sv_main.c
+++ b/src/server/sv_main.c
@@ -50,6 +50,7 @@ cvar_t *sv_minPing;
cvar_t *sv_maxPing;
cvar_t *sv_pure;
cvar_t *sv_lanForceRate; // dedicated 1 (LAN) server forces local client rates to 99999 (bug #491)
+cvar_t *sv_dequeuePeriod;
/*
=============================================================================
@@ -150,6 +151,218 @@ void SV_AddServerCommand( client_t *client, const char *cmd ) {
Q_strncpyz( client->reliableCommands[ index ], cmd, sizeof( client->reliableCommands[ index ] ) );
}
+/*
+=============
+SV_ClientIsLagging
+=============
+*/
+qboolean SV_ClientIsLagging( client_t *client )
+{
+ if( client )
+ {
+ if( client->ping >= 999 )
+ return qtrue;
+ else
+ return qfalse;
+ }
+
+ return qfalse; //is a non-existant client lagging? woooo zen
+}
+
+
+static commandQueue_t queuedCommands[ MAX_CLIENTS ];
+
+/*
+===============
+SV_PopCommandQueue
+
+Return the front of a command queue
+Must use immediately or copy to a buffer
+===============
+*/
+static const char *SV_PopCommandQueue( commandQueue_t *cq )
+{
+ if( cq->front )
+ {
+ commandQueueElement_t *cqe = cq->front;
+
+ cq->front = cqe->next;
+
+ // last element in the queue
+ if( cq->front == NULL )
+ cq->back = NULL;
+
+ cq->nextCommandTime = svs.time + sv_dequeuePeriod->integer;
+ cqe->used = qfalse;
+
+ return cqe->command;
+ }
+ else
+ return NULL;
+}
+
+/*
+===============
+SV_PushCommandQueue
+
+Put a command on a command queue
+===============
+*/
+static qboolean SV_PushCommandQueue( commandQueue_t *cq, const char *cmd )
+{
+ int i;
+
+ for( i = 0; i < MAX_RELIABLE_COMMANDS; i++ )
+ {
+ commandQueueElement_t *cqe = &cq->pool[ i ];
+
+ if( !cqe->used )
+ {
+ cqe->used = qtrue;
+ cqe->next = NULL;
+ Q_strncpyz( cqe->command, cmd, MAX_TOKEN_CHARS );
+
+ if( cq->back )
+ {
+ cq->back->next = cqe;
+ cq->back = cqe;
+ }
+ else
+ {
+ cq->front = cqe;
+ cq->back = cqe;
+ }
+
+ return qtrue;
+ }
+ }
+
+ // The queue is full, so the command cannot be queued up.
+ // Consequently, the command must be dropped -- meaning it
+ // is no longer reliable.
+ return qfalse;
+}
+
+/*
+===============
+SV_PrintCommandQueue
+===============
+*/
+#if 0 //quiet compiler
+static void SV_PrintCommandQueue( commandQueue_t *cq )
+{
+ commandQueueElement_t *cqe;
+
+ if( cq->front )
+ {
+ cqe = cq->front;
+
+ do
+ {
+ Com_Printf( "->\"%s\"", cqe->command );
+ } while( ( cqe = cqe->next ) );
+
+ Com_Printf( "\n" );
+ }
+}
+#endif
+
+/*
+===============
+SV_ReadyToDequeue
+===============
+*/
+static qboolean SV_ReadyToDequeue( commandQueue_t *cq )
+{
+ if( !cq )
+ return qfalse;
+
+ return cq->front && cq->nextCommandTime <= svs.time;
+}
+
+/*
+===============
+SV_ProcessCommandQueues
+
+Check for any outstanding commands to be sent
+===============
+*/
+void SV_ProcessCommandQueues( void )
+{
+ int i;
+
+ for( i = 0; i < MAX_CLIENTS; i++ )
+ {
+ client_t *cl = &svs.clients[ i ];
+ commandQueue_t *cq = &queuedCommands[ i ];
+
+ if( !SV_ClientIsLagging( cl ) && SV_ReadyToDequeue( cq ) )
+ {
+ const char *command = SV_PopCommandQueue( cq );
+
+ if( command )
+ SV_AddServerCommand( cl, command );
+ }
+ }
+}
+
+/*
+===============
+SV_InitCommandQueue
+===============
+*/
+void SV_InitCommandQueue( int clientNum )
+{
+ int i;
+ commandQueue_t *cq = &queuedCommands[ clientNum ];
+
+ if( clientNum >= 0 && clientNum < MAX_CLIENTS )
+ {
+ cq->front = cq->back = NULL;
+ cq->nextCommandTime = 0;
+
+ for( i = 0; i < MAX_RELIABLE_COMMANDS; i++ )
+ {
+ commandQueueElement_t *cqe = &cq->pool[ i ];
+
+ cqe->used = qfalse;
+ }
+ }
+}
+
+/*
+===============
+SV_EnqueueServerCommand
+
+Sends a command to a client
+===============
+*/
+void SV_EnqueueServerCommand( int clientNum, const char *cmd )
+{
+ commandQueue_t *cq = &queuedCommands[ clientNum ];
+ client_t *cl = &svs.clients[ clientNum ];
+
+ if( clientNum < 0 )
+ cq = NULL;
+
+ if( cq )
+ {
+ if( cq->nextCommandTime > svs.time || SV_ClientIsLagging( cl ) )
+ {
+ //can't send yet, so queue the command up
+ if( !SV_PushCommandQueue( cq, cmd ) )
+ SV_DropClient( cl,
+ va( "Failed to enqueue reliable server command (%s)", cmd ) );
+ }
+ else
+ {
+ cq->nextCommandTime = svs.time + sv_dequeuePeriod->integer;
+ SV_AddServerCommand( cl, cmd );
+ }
+ }
+ else //no queue exists for this client
+ SV_AddServerCommand( cl, cmd );
+}
/*
=================
@@ -179,7 +392,7 @@ void QDECL SV_SendServerCommand(client_t *cl, const char *fmt, ...) {
}
if ( cl != NULL ) {
- SV_AddServerCommand( cl, (char *)message );
+ SV_EnqueueServerCommand( cl - svs.clients, (char *)message );
return;
}
@@ -193,7 +406,7 @@ void QDECL SV_SendServerCommand(client_t *cl, const char *fmt, ...) {
if ( client->state < CS_PRIMED ) {
continue;
}
- SV_AddServerCommand( client, (char *)message );
+ SV_EnqueueServerCommand( client - svs.clients, (char *)message );
}
}
@@ -871,6 +1084,8 @@ void SV_Frame( int msec ) {
VM_Call (gvm, GAME_RUN_FRAME, sv.time);
}
+ SV_ProcessCommandQueues( );
+
if ( com_speeds->integer ) {
time_game = Sys_Milliseconds () - startTime;
}