/* ================== SV_Frame Player movement occurs as a result of packet events, which happen before SV_Frame is called ================== */ void SV_Frame( int msec ) { int frameMsec; int startTime; // the menu kills the server with this cvar if ( sv_killserver->integer ) { SV_Shutdown ("Server was killed"); Cvar_Set( "sv_killserver", "0" ); return; } if (!com_sv_running->integer) { if(com_dedicated->integer) { // Block indefinitely until something interesting happens // on STDIN. NET_Sleep(-1); } return; } // allow pause if only the local client is connected if ( SV_CheckPaused() ) { return; } // if it isn't time for the next frame, do nothing if ( sv_fps->integer < 1 ) { Cvar_Set( "sv_fps", "10" ); } frameMsec = 1000 / sv_fps->integer * com_timescale->value; // don't let it scale below 1ms if(frameMsec < 1) { Cvar_Set("timescale", va("%f", sv_fps->integer / 1000.0f)); frameMsec = 1; } sv.timeResidual += msec; if (!com_dedicated->integer) SV_BotFrame (sv.time + sv.timeResidual); if ( com_dedicated->integer && sv.timeResidual < frameMsec ) { // NET_Sleep will give the OS time slices until either get a packet // or time enough for a server frame has gone by NET_Sleep(frameMsec - sv.timeResidual); return; } // if time is about to hit the 32nd bit, kick all clients // and clear sv.time, rather // than checking for negative time wraparound everywhere. // 2giga-milliseconds = 23 days, so it won't be too often if ( svs.time > 0x70000000 ) { SV_Shutdown( "Restarting server due to time wrapping" ); Cbuf_AddText( va( "map %s\n", Cvar_VariableString( "mapname" ) ) ); return; } // this can happen considerably earlier when lots of clients play and the map doesn't change if ( svs.nextSnapshotEntities >= 0x7FFFFFFE - svs.numSnapshotEntities ) { SV_Shutdown( "Restarting server due to numSnapshotEntities wrapping" ); Cbuf_AddText( va( "map %s\n", Cvar_VariableString( "mapname" ) ) ); return; } if( sv.restartTime && sv.time >= sv.restartTime ) { sv.restartTime = 0; Cbuf_AddText( "map_restart 0\n" ); return; } // update infostrings if anything has been changed if ( cvar_modifiedFlags & CVAR_SERVERINFO ) { SV_SetConfigstring( CS_SERVERINFO, Cvar_InfoString( CVAR_SERVERINFO ) ); cvar_modifiedFlags &= ~CVAR_SERVERINFO; } if ( cvar_modifiedFlags & CVAR_SYSTEMINFO ) { SV_SetConfigstring( CS_SYSTEMINFO, Cvar_InfoString_Big( CVAR_SYSTEMINFO ) ); cvar_modifiedFlags &= ~CVAR_SYSTEMINFO; } if ( com_speeds->integer ) { startTime = Sys_Milliseconds (); } else { startTime = 0; // quite a compiler warning } // update ping based on the all received frames SV_CalcPings(); if (com_dedicated->integer) SV_BotFrame (sv.time); // run the game simulation in chunks while ( sv.timeResidual >= frameMsec ) { sv.timeResidual -= frameMsec; svs.time += frameMsec; sv.time += frameMsec; // let everything in the world think and move VM_Call (gvm, GAME_RUN_FRAME, sv.time); } if ( com_speeds->integer ) { time_game = Sys_Milliseconds () - startTime; } // check timeouts SV_CheckTimeouts(); // check user info buffer thingy SV_CheckClientUserinfoTimer(); // send messages back to the clients SV_SendClientMessages(); // send a heartbeat to the master if needed SV_MasterHeartbeat(); }
/* ================== SV_Frame Player movement occurs as a result of packet events, which happen before SV_Frame is called ================== */ void SV_Frame(int msec) { int frameMsec, startTime, frameStartTime = 0, frameEndTime; char mapname[MAX_QPATH]; // Dushan static int start, end; start = Sys_Milliseconds (); svs.stats.idle += (double)(start - end) / 1000; // the menu kills the server with this cvar if(sv_killserver->integer) { SV_Shutdown("Server was killed.\n"); Cvar_Set("sv_killserver", "0"); return; } if(!com_sv_running->integer) { // Running as a server, but no map loaded #if defined (DEDICATED) // Block until something interesting happens Sys_Sleep(-1); #endif return; } // allow pause if only the local client is connected if(SV_CheckPaused()) { return; } if(com_dedicated->integer) { frameStartTime = Sys_Milliseconds(); } // if it isn't time for the next frame, do nothing if(sv_fps->integer < 1) { Cvar_Set("sv_fps", "10"); } frameMsec = 1000 / sv_fps->integer * com_timescale->value; // don't let it scale below 1ms if(frameMsec < 1) { Cvar_Set("timescale", va("%f", sv_fps->integer / 1000.0f)); frameMsec = 1; } sv.timeResidual += msec; if(!com_dedicated->integer) { SV_BotFrame(svs.time + sv.timeResidual); } if(com_dedicated->integer && sv.timeResidual < frameMsec) { // NET_Sleep will give the OS time slices until either get a packet // or time enough for a server frame has gone by NET_Sleep(frameMsec - sv.timeResidual); return; } // if time is about to hit the 32nd bit, kick all clients // and clear sv.time, rather // than checking for negative time wraparound everywhere. // 2giga-milliseconds = 23 days, so it won't be too often if(svs.time > 0x70000000) { Q_strncpyz(mapname, sv_mapname->string, MAX_QPATH); SV_Shutdown("Restarting server due to time wrapping"); // TTimo // show_bug.cgi?id=388 // there won't be a map_restart if you have shut down the server // since it doesn't restart a non-running server // instead, re-run the current map Cbuf_AddText(va("map %s\n", mapname)); return; } // this can happen considerably earlier when lots of clients play and the map doesn't change if(svs.nextSnapshotEntities >= 0x7FFFFFFE - svs.numSnapshotEntities) { Q_strncpyz(mapname, sv_mapname->string, MAX_QPATH); SV_Shutdown("Restarting server due to numSnapshotEntities wrapping"); // TTimo see above Cbuf_AddText(va("map %s\n", mapname)); return; } if(sv.restartTime && svs.time >= sv.restartTime) { sv.restartTime = 0; Cbuf_AddText("map_restart 0\n"); return; } // update infostrings if anything has been changed if(cvar_modifiedFlags & CVAR_SERVERINFO) { SV_SetConfigstring(CS_SERVERINFO, Cvar_InfoString(CVAR_SERVERINFO | CVAR_SERVERINFO_NOUPDATE)); cvar_modifiedFlags &= ~CVAR_SERVERINFO; } if(cvar_modifiedFlags & CVAR_SERVERINFO_NOUPDATE) { SV_SetConfigstringNoUpdate(CS_SERVERINFO, Cvar_InfoString(CVAR_SERVERINFO | CVAR_SERVERINFO_NOUPDATE)); cvar_modifiedFlags &= ~CVAR_SERVERINFO_NOUPDATE; } if(cvar_modifiedFlags & CVAR_SYSTEMINFO) { SV_SetConfigstring(CS_SYSTEMINFO, Cvar_InfoString_Big(CVAR_SYSTEMINFO)); cvar_modifiedFlags &= ~CVAR_SYSTEMINFO; } // NERVE - SMF if(cvar_modifiedFlags & CVAR_WOLFINFO) { SV_SetConfigstring(CS_WOLFINFO, Cvar_InfoString(CVAR_WOLFINFO)); cvar_modifiedFlags &= ~CVAR_WOLFINFO; } if(com_speeds->integer) { startTime = Sys_Milliseconds(); } else { startTime = 0; // quite a compiler warning } // update ping based on the all received frames SV_CalcPings(); if(com_dedicated->integer) { SV_BotFrame(svs.time); } // run the game simulation in chunks while(sv.timeResidual >= frameMsec) { sv.timeResidual -= frameMsec; svs.time += frameMsec; // let everything in the world think and move #if !defined (UPDATE_SERVER) VM_Call(gvm, GAME_RUN_FRAME, svs.time); #endif #ifdef USE_PHYSICS CMod_PhysicsUpdate(svs.time, 1.0f / sv_fps->integer); #endif } if(com_speeds->integer) { time_game = Sys_Milliseconds() - startTime; } // check timeouts SV_CheckTimeouts(); // check user info buffer thingy SV_CheckClientUserinfoTimer(); // send messages back to the clients SV_SendClientMessages(); // send a heartbeat to the master if needed SV_MasterHeartbeat(HEARTBEAT_GAME); if(com_dedicated->integer) { frameEndTime = Sys_Milliseconds(); svs.totalFrameTime += (frameEndTime - frameStartTime); svs.currentFrameIndex++; //if( svs.currentFrameIndex % 50 == 0 ) // Com_Printf( "currentFrameIndex: %i\n", svs.currentFrameIndex ); if(svs.currentFrameIndex == SERVER_PERFORMANCECOUNTER_FRAMES) { int averageFrameTime; averageFrameTime = svs.totalFrameTime / SERVER_PERFORMANCECOUNTER_FRAMES; svs.sampleTimes[svs.currentSampleIndex % SERVER_PERFORMANCECOUNTER_SAMPLES] = averageFrameTime; svs.currentSampleIndex++; if(svs.currentSampleIndex > SERVER_PERFORMANCECOUNTER_SAMPLES) { int totalTime, i; totalTime = 0; for(i = 0; i < SERVER_PERFORMANCECOUNTER_SAMPLES; i++) { totalTime += svs.sampleTimes[i]; } if(!totalTime) { totalTime = 1; } averageFrameTime = totalTime / SERVER_PERFORMANCECOUNTER_SAMPLES; svs.serverLoad = (averageFrameTime / (float)frameMsec) * 100; } //Com_Printf( "serverload: %i (%i/%i)\n", svs.serverLoad, averageFrameTime, frameMsec ); svs.totalFrameTime = 0; svs.currentFrameIndex = 0; } } else { svs.serverLoad = -1; } // collect timing statistics end = Sys_Milliseconds (); svs.stats.active += ((double) (end-start)) / 1000; if (++svs.stats.count == STATFRAMES) { svs.stats.latched_active = svs.stats.active; svs.stats.latched_idle = svs.stats.idle; svs.stats.latched_packets = svs.stats.packets; svs.stats.active = 0; svs.stats.idle = 0; svs.stats.packets = 0; svs.stats.count = 0; } }