summaryrefslogtreecommitdiff
path: root/src/server
diff options
context:
space:
mode:
Diffstat (limited to 'src/server')
-rw-r--r--src/server/server.h21
-rw-r--r--src/server/sv_client.c1
-rw-r--r--src/server/sv_init.c1
-rw-r--r--src/server/sv_main.c219
4 files changed, 240 insertions, 2 deletions
diff --git a/src/server/server.h b/src/server/server.h
index 8eb43550..bd37c262 100644
--- a/src/server/server.h
+++ b/src/server/server.h
@@ -171,6 +171,26 @@ typedef struct client_s {
int oldServerTime;
} client_t;
+typedef struct commandQueueElement_s
+{
+ qboolean used;
+ struct commandQueueElement_s *next;
+ char command[ MAX_TOKEN_CHARS ];
+} commandQueueElement_t;
+
+typedef struct commandQueue_s
+{
+ int nextCommandTime; //next time that the queue can be popped
+
+ int numElements;
+ commandQueueElement_t *front;
+ commandQueueElement_t *back;
+
+ commandQueueElement_t pool[ MAX_RELIABLE_COMMANDS ];
+} commandQueue_t;
+
+void SV_InitCommandQueue( int clientNum );
+
//=============================================================================
@@ -244,6 +264,7 @@ extern cvar_t *sv_minPing;
extern cvar_t *sv_maxPing;
extern cvar_t *sv_pure;
extern cvar_t *sv_lanForceRate;
+extern cvar_t *sv_dequeuePeriod;
//===========================================================
diff --git a/src/server/sv_client.c b/src/server/sv_client.c
index 0272fab0..ffab3bfc 100644
--- a/src/server/sv_client.c
+++ b/src/server/sv_client.c
@@ -487,6 +487,7 @@ void SV_ClientEnterWorld( client_t *client, usercmd_t *cmd ) {
ent = SV_GentityNum( clientNum );
ent->s.number = clientNum;
client->gentity = ent;
+ SV_InitCommandQueue( clientNum );
client->deltaMessage = -1;
client->nextSnapshotTime = svs.time; // generate a snapshot immediately
diff --git a/src/server/sv_init.c b/src/server/sv_init.c
index 251dfcac..c30b1228 100644
--- a/src/server/sv_init.c
+++ b/src/server/sv_init.c
@@ -610,6 +610,7 @@ void SV_Init (void) {
sv_killserver = Cvar_Get ("sv_killserver", "0", 0);
sv_mapChecksum = Cvar_Get ("sv_mapChecksum", "", CVAR_ROM);
sv_lanForceRate = Cvar_Get ("sv_lanForceRate", "1", CVAR_ARCHIVE );
+ sv_dequeuePeriod = Cvar_Get ("sv_dequeuePeriod", "500", CVAR_ARCHIVE );
// initialize bot cvars so they are listed and can be set before loading the botlib
SV_BotInitCvars();
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;
}