Skip to content

Commit

Permalink
Replace main event loop frame-waiting and net messages synchronization
Browse files Browse the repository at this point in the history
  • Loading branch information
karnute committed May 9, 2017
1 parent 8ed058b commit 86b8087
Show file tree
Hide file tree
Showing 8 changed files with 262 additions and 81 deletions.
89 changes: 74 additions & 15 deletions code/qcommon/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -2692,6 +2692,27 @@ int Com_ModifyMsec( int msec ) {
return msec;
}

/*
=================
Com_TimeVal
=================
*/

int Com_TimeVal(int minMsec)
{
int timeVal;

timeVal = Sys_Milliseconds() - com_frameTime;

if(timeVal >= minMsec)
timeVal = 0;
else
timeVal = minMsec - timeVal;

return timeVal;
}


/*
=================
Com_Frame
Expand All @@ -2700,7 +2721,8 @@ Com_Frame
void Com_Frame( void ) {

int msec, minMsec;
static int lastTime;
int timeVal, timeValSV;
static int lastTime = 0, bias = 0;

int timeBeforeFirstEvents;
int timeBeforeServer;
Expand Down Expand Up @@ -2746,19 +2768,57 @@ void Com_Frame( void ) {
timeBeforeFirstEvents = Sys_Milliseconds ();
}

// we may want to spin here if things are going too fast
if ( !com_dedicated->integer && com_maxfps->integer > 0 && !com_timedemo->integer && !CL_IsDownloading()) {
minMsec = 1000 / com_maxfps->integer;
} else {
minMsec = 1;
// Figure out how much time we have
if(!com_timedemo->integer)
{
if(com_dedicated->integer)
minMsec = SV_FrameMsec();
else
{
if(com_maxfps->integer > 0 && !com_timedemo->integer && !CL_IsDownloading())
minMsec = 1000 / com_maxfps->integer;
else
minMsec = 1;

timeVal = com_frameTime - lastTime;
bias += timeVal - minMsec;

if(bias > minMsec)
bias = minMsec;

// Adjust minMsec if previous frame took too long to render so
// that framerate is stable at the requested value.
minMsec -= bias;
}
}
do {
com_frameTime = Com_EventLoop();
if ( lastTime > com_frameTime ) {
lastTime = com_frameTime; // possible on first frame
else
minMsec = 1;

do
{
if(com_sv_running->integer)
{
timeValSV = SV_SendQueuedPackets();

timeVal = Com_TimeVal(minMsec);

if(timeValSV < timeVal)
timeVal = timeValSV;
}
msec = com_frameTime - lastTime;
} while ( msec < minMsec );
else
timeVal = Com_TimeVal(minMsec);

if(timeVal < 1)
NET_Sleep(0);
else
NET_Sleep(timeVal - 1);
} while(Com_TimeVal(minMsec));

lastTime = com_frameTime;
com_frameTime = Com_EventLoop();

msec = com_frameTime - lastTime;

Cbuf_Execute ();

if (com_altivec->modified)
Expand All @@ -2767,10 +2827,7 @@ void Com_Frame( void ) {
com_altivec->modified = qfalse;
}

lastTime = com_frameTime;

// mess with msec if needed
com_frameMsec = msec;
msec = Com_ModifyMsec( msec );

//
Expand Down Expand Up @@ -2828,6 +2885,8 @@ void Com_Frame( void ) {
}
}

NET_FlushPacketQueue();

//
// report timing information
//
Expand Down
4 changes: 4 additions & 0 deletions code/qcommon/net_chan.c
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,10 @@ void Netchan_TransmitNextFragment( netchan_t *chan ) {
// send the datagram
NET_SendPacket( chan->sock, send.cursize, send.data, chan->remoteAddress );

// Store send time and size of this packet for rate control
chan->lastSentTime = Sys_Milliseconds();
chan->lastSentSize = send.cursize;

if ( showpackets->integer ) {
Com_Printf ("%s send %4i : s=%i fragment=%i,%i\n"
, netsrcString[ chan->sock ]
Expand Down
5 changes: 5 additions & 0 deletions code/qcommon/qcommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,9 @@ typedef struct {
int unsentFragmentStart;
int unsentLength;
byte unsentBuffer[MAX_MSGLEN];

int lastSentTime;
int lastSentSize;
} netchan_t;

void Netchan_Init( int qport );
Expand Down Expand Up @@ -950,7 +953,9 @@ void SV_Init( void );
void SV_Shutdown( char *finalmsg );
void SV_Frame( int msec );
void SV_PacketEvent( netadr_t from, msg_t *msg );
int SV_FrameMsec(void);
qboolean SV_GameCommand( void );
int SV_SendQueuedPackets(void);


//
Expand Down
5 changes: 4 additions & 1 deletion code/server/server.h
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,7 @@ void SV_RemoveOperatorCommands (void);

void SV_MasterHeartbeat (void);
void SV_MasterShutdown (void);
int SV_RateMsec(client_t *client);



Expand Down Expand Up @@ -368,6 +369,8 @@ void SV_ExecuteClientCommand( client_t *cl, const char *s, qboolean clientOK );
void SV_ClientThink (client_t *cl, usercmd_t *cmd);

void SV_WriteDownloadToClient( client_t *cl , msg_t *msg );
int SV_SendDownloadMessages(void);
int SV_SendQueuedMessages(void);

//
// sv_ccmds.c
Expand Down Expand Up @@ -474,6 +477,6 @@ void SV_ClipToEntity( trace_t *trace, const vec3_t start, const vec3_t mins, con
// sv_net_chan.c
//
void SV_Netchan_Transmit( client_t *client, msg_t *msg);
void SV_Netchan_TransmitNextFragment( client_t *client );
int SV_Netchan_TransmitNextFragment( client_t *client );
qboolean SV_Netchan_Process( client_t *client, msg_t *msg );

34 changes: 34 additions & 0 deletions code/server/sv_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -1059,6 +1059,40 @@ void SV_WriteDownloadToClient( client_t *cl , msg_t *msg )
}
}


/*
==================
SV_SendQueuedMessages
Send one round of fragments, or queued messages to all clients that have data pending.
Return the shortest time interval for sending next packet to client
==================
*/

int SV_SendQueuedMessages(void)
{
int i, retval = -1, nextFragT;
client_t *cl;

for(i=0; i < sv_maxclients->integer; i++)
{
cl = &svs.clients[i];

if(cl->state)
{
nextFragT = SV_RateMsec(cl);

if(!nextFragT)
nextFragT = SV_Netchan_TransmitNextFragment(cl);

if(nextFragT >= 0 && (retval == -1 || retval > nextFragT))
retval = nextFragT;
}
}

return retval;
}

/*
=================
SV_Disconnect_f
Expand Down
93 changes: 93 additions & 0 deletions code/server/sv_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -974,6 +974,30 @@ qboolean SV_CheckPaused( void ) {
return qtrue;
}


/*
==================
SV_FrameMsec
Return time in millseconds until processing of the next server frame.
==================
*/
int SV_FrameMsec()
{
if(sv_fps)
{
int frameMsec;

frameMsec = 1000.0f / sv_fps->value;

if(frameMsec < sv.timeResidual)
return 0;
else
return frameMsec - sv.timeResidual;
}
else
return 1;
}

/*
==================
SV_Frame
Expand Down Expand Up @@ -1104,5 +1128,74 @@ void SV_Frame( int msec ) {
SV_MasterHeartbeat();
}

/*
====================
SV_RateMsec
Return the number of msec until another message can be sent to
a client based on its rate settings
====================
*/

#define UDPIP6_HEADER_SIZE 48

int SV_RateMsec(client_t *client)
{
int rate, rateMsec;
int messageSize;

messageSize = client->netchan.lastSentSize;
rate = client->rate;

if(sv_maxRate->integer)
{
if(sv_maxRate->integer < 1000)
Cvar_Set( "sv_MaxRate", "1000" );
if(sv_maxRate->integer < rate)
rate = sv_maxRate->integer;
}

if(sv_minRate->integer)
{
if(sv_minRate->integer < 1000)
Cvar_Set("sv_minRate", "1000");
if(sv_minRate->integer > rate)
rate = sv_minRate->integer;
}

messageSize += UDPIP6_HEADER_SIZE;

rateMsec = messageSize * 1000 / ((int) (rate * com_timescale->value));
rate = Sys_Milliseconds() - client->netchan.lastSentTime;

if(rate > rateMsec)
return 0;
else
return rateMsec - rate;
}

/*
====================
SV_SendQueuedPackets
Send download messages and queued packets in the time that we're idle, i.e.
not computing a server frame or sending client snapshots.
Return the time in msec until we expect to be called next
====================
*/

int SV_SendQueuedPackets()
{
int delayT;
int timeVal = INT_MAX;

// Send out fragmented packets now that we're idle
delayT = SV_SendQueuedMessages();
if(delayT >= 0)
timeVal = delayT;

return timeVal;
}

//============================================================================

Loading

0 comments on commit 86b8087

Please sign in to comment.