/* ================== 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.\n" ); Cvar_Set( "sv_killserver", "0" ); return; } if ( !com_sv_running->integer ) { 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 ; 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( "vstr nextmap\n" ); 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( "vstr nextmap\n" ); 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(); // send messages back to the clients SV_SendClientMessages(); // send a heartbeat to the master if needed SV_MasterHeartbeat(); }
void SV_Frame( int msec,float fractionMsec ) { int frameMsec; int startTime=0; // 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 ) { return; } extern void SE_CheckForLanguageUpdates(void); SE_CheckForLanguageUpdates(); // will fast-return else load different language if menu changed it // allow pause if only the local client is connected if ( SV_CheckPaused() ) { return; } // go ahead and let time slip if the server really hitched badly if ( msec > 1000 ) { Com_DPrintf( "SV_Frame: Truncating msec of %i to 1000\n", msec ); msec = 1000; } // 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 ; sv.timeResidual += msec; sv.timeResidualFraction+=fractionMsec; if (sv.timeResidualFraction>=1.0f) { sv.timeResidualFraction-=1.0f; if (cl_newClock&&cl_newClock->integer) { sv.timeResidual++; } } if ( sv.timeResidual < frameMsec ) { return; } // if time is about to hit the 32nd bit, restart the // level, which will force the time back to zero, rather // than checking for negative time wraparound everywhere. // 2giga-milliseconds = 23 days, so it won't be too often if ( sv.time > 0x70000000 ) { SV_Shutdown( "Restarting server due to time wrapping" ); Com_Printf("You win. if you can play this long and not die, you deserve to win.\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( CVAR_SYSTEMINFO ) ); cvar_modifiedFlags &= ~CVAR_SYSTEMINFO; } if ( com_speeds->integer ) { startTime = Sys_Milliseconds (); } // SV_BotFrame( sv.time ); // run the game simulation in chunks while ( sv.timeResidual >= frameMsec ) { sv.timeResidual -= frameMsec; sv.time += frameMsec; re.G2API_SetTime(sv.time,G2T_SV_TIME); // let everything in the world think and move ge->RunFrame( sv.time ); } if ( com_speeds->integer ) { time_game = Sys_Milliseconds () - startTime; } SG_TestSave(); // returns immediately if not active, used for fake-save-every-cycle to test (mainly) Icarus disk code // check timeouts SV_CheckTimeouts (); // update ping based on the last known frame from all clients SV_CalcPings (); // send messages back to the clients SV_SendClientMessages (); }
/* ================== 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; } }
/* * SV_RunGameFrame */ static qboolean SV_RunGameFrame( int msec ) { static unsigned int accTime = 0; qboolean refreshSnapshot; qboolean refreshGameModule; qboolean sentFragments; accTime += msec; refreshSnapshot = qfalse; refreshGameModule = qfalse; sentFragments = SV_SendClientsFragments(); // see if it's time to run a new game frame if( accTime >= WORLDFRAMETIME ) refreshGameModule = qtrue; // see if it's time for a new snapshot if( !sentFragments && svs.gametime >= sv.nextSnapTime ) { refreshSnapshot = qtrue; refreshGameModule = qtrue; } // if there aren't pending packets to be sent, we can sleep if( dedicated->integer && !sentFragments && !refreshSnapshot ) { int sleeptime = min( WORLDFRAMETIME - ( accTime + 1 ), sv.nextSnapTime - ( svs.gametime + 1 ) ); if( sleeptime > 0 ) { socket_t *sockets [] = { &svs.socket_udp, &svs.socket_udp6 }; socket_t *opened_sockets [sizeof( sockets ) / sizeof( sockets[0] ) + 1 ]; size_t sock_ind, open_ind; // Pass only the opened sockets to the sleep function open_ind = 0; for ( sock_ind = 0; sock_ind < sizeof( sockets ) / sizeof( sockets[0] ); sock_ind++) { socket_t *sock = sockets[sock_ind]; if ( sock->open ) { opened_sockets[open_ind] = sock; open_ind++; } } opened_sockets[open_ind] = NULL; NET_Sleep( sleeptime, opened_sockets ); } } if( refreshGameModule ) { unsigned int moduleTime; // update ping based on the last known frame from all clients SV_CalcPings(); if( accTime >= WORLDFRAMETIME ) { moduleTime = WORLDFRAMETIME; accTime -= WORLDFRAMETIME; if( accTime >= WORLDFRAMETIME ) // don't let it accumulate more than 1 frame accTime = WORLDFRAMETIME - 1; } else { moduleTime = accTime; accTime = 0; } if( host_speeds->integer ) time_before_game = Sys_Milliseconds(); ge->RunFrame( moduleTime, svs.gametime ); if( host_speeds->integer ) time_after_game = Sys_Milliseconds(); } // if we don't have to send a snapshot we are done here if( refreshSnapshot ) { int extraSnapTime; // set up for sending a snapshot sv.framenum++; ge->SnapFrame(); // set time for next snapshot extraSnapTime = (int)( svs.gametime - sv.nextSnapTime ); if( extraSnapTime > svc.snapFrameTime * 0.5 ) // don't let too much time be accumulated extraSnapTime = svc.snapFrameTime * 0.5; sv.nextSnapTime = svs.gametime + ( svc.snapFrameTime - extraSnapTime ); return qtrue; } return qfalse; }
void SV_Frame(float msec) { guard(SV_Frame); time_before_game = time_after_game = 0; // if server is not active, do nothing if (!svs.initialized) return; // SV_DrawTextLeft(va("time: %10d rf: %10.5f d: %10.4f ri:%10d", sv.time, svs.realtimef, msec, svs.realtime));//!! svs.realtimef += msec; svs.realtime = appFloor(svs.realtimef); if (!sv.attractloop) { // check timeouts SV_CheckTimeouts(); } // get packets from clients SV_ReadPackets(); if (sv.state == ss_dead) return; // server was killed from one of packet (e.g. "rcon killserver") int frameTime = 100; // (sv_fps->integer > 10) ? (1000 / sv_fps->integer) : 100; // move autonomous things around if enough time has passed if (svs.realtime < sv.time) { // never let the time get too far off if (sv.time - svs.realtime > frameTime) { if (sv_showclamp->integer) appPrintf("sv lowclamp s:%d -- r:%d -> %d\n", sv.time, svs.realtime, sv.time - frameTime); svs.realtime = sv.time - frameTime; svs.realtimef = svs.realtime; } return; } SV_ClearTexts(); if (!sv.attractloop) { // update ping based on the last known frame from all clients SV_CalcPings(); // give the clients some timeslices SV_GiveMsec(); } // let everything in the world think and move /*-------- SV_RunGameFrame() ---------------*/ // we always need to bump framenum, even if we // don't run the world, otherwise the delta // compression can get confused when a client // has the "current" frame sv.framenum++; sv.time += frameTime; // = sv.framenum*100; ?? // don't run if paused if (!sv_paused->integer || sv_maxclients->integer > 1) { time_before_game = appCycles(); guardGame(ge.RunFrame); ge->RunFrame(); unguardGame; // never get more than one tic behind if (sv.time < svs.realtime) { if (sv_showclamp->integer) appPrintf("sv highclamp s:%d r:%d -> %d\n", sv.time, svs.realtime, sv.time); svs.realtime = sv.time; svs.realtimef = sv.time; } time_after_game = appCycles(); } // if extended protocol used, recalculate footstep sounds, mdx/mdl/md3 frames etc. if (sv_extProtocol->integer && !sv.attractloop) SV_PostprocessFrame(); // send messages back to the clients that had packets read this frame SV_SendClientMessages(); // save the entire world state if recording a serverdemo SV_RecordDemoMessage(); // send a heartbeat to the master if needed Master_Heartbeat(); // clear teleport flags, etc for next frame SV_PrepWorldFrame(); unguard; }