/* ================== SCR_ModalMessage Displays a text string in the center of the screen and waits for a Y or N keypress. ================== */ int SCR_ModalMessage (const char *text, float timeout) //johnfitz -- timeout { double time1, time2; //johnfitz -- timeout if (cls.state == ca_dedicated) return true; scr_notifystring = text; // draw a fresh screen scr_drawdialog = true; SCR_UpdateScreen (); scr_drawdialog = false; S_ClearBuffer (); // so dma doesn't loop current sound time1 = Sys_DoubleTime () + timeout; //johnfitz -- timeout time2 = 0.0f; //johnfitz -- timeout do { key_count = -1; // wait for a key down and up Sys_SendKeyEvents (); Sys_Sleep(16); if (timeout) time2 = Sys_DoubleTime (); //johnfitz -- zero timeout means wait forever. } while (key_lastpress != 'y' && key_lastpress != 'n' && key_lastpress != K_ESCAPE && time2 <= time1); // make sure we don't ignore the next keypress if (key_count < 0) key_count = 0; // SCR_UpdateScreen (); //johnfitz -- commented out //johnfitz -- timeout if (time2 > time1) return false; //johnfitz return key_lastpress == 'y'; }
/* ================ Sys_Error NOTE: we must prepare engine to shutdown before call this ================ */ void Sys_Error( const char *error, ... ) { va_list argptr; char text[MAX_SYSPATH]; if( host.state == HOST_ERR_FATAL ) return; // don't execute more than once // make sure that console received last message if( host.change_game ) Sys_Sleep( 200 ); error_on_exit = true; host.state = HOST_ERR_FATAL; va_start( argptr, error ); Q_vsprintf( text, error, argptr ); va_end( argptr ); SV_SysError( text ); if( host.type == HOST_NORMAL ) { #ifdef XASH_SDL if( host.hWnd ) SDL_HideWindow( host.hWnd ); #endif VID_RestoreGamma(); } if( host.developer > 0 ) { Con_ShowConsole( true ); Con_DisableInput(); // disable input line for dedicated server MSGBOX( text ); Sys_Print( text ); // print error message Sys_WaitForQuit(); } else { Con_ShowConsole( false ); MSGBOX( text ); } Sys_Quit(); }
//yuck, but necessary for synchronizing startup void SV_AntiCheat_WaitForInitialConnect (void) { int attempts; if (!acSocket) return; attempts = 0; while (acSocket && !anticheat_ready) { SV_AntiCheat_Run (); Sys_Sleep (1); //something is wrong, abort. if (++attempts == 5000) break; } }
/* ================ Sys_WaitForQuit wait for 'Esc' key will be hit ================ */ void Sys_WaitForQuit( void ) { MSG msg; Con_RegisterHotkeys(); msg.message = 0; // wait for the user to quit while( msg.message != WM_QUIT ) { if( PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) { TranslateMessage( &msg ); DispatchMessage( &msg ); } else Sys_Sleep( 20 ); } }
void DD_WaitForOptimalUpdateTime(void) { // All times are in milliseconds. static uint prevUpdateTime = 0; uint nowTime, elapsed = 0; uint targetUpdateTime; // optimalDelta is integer on purpose: we're measuring time at a 1 ms // accuracy, so we can't use fractions of a millisecond. const uint optimalDelta = (maxFrameRate > 0? 1000/maxFrameRate : 1); if(Sys_IsShuttingDown()) return; // No need for finesse. // This is when we would ideally like to make the update. targetUpdateTime = prevUpdateTime + optimalDelta; // Check the current time. nowTime = Timer_RealMilliseconds(); elapsed = nowTime - prevUpdateTime; if(elapsed < optimalDelta) { uint needSleepMs = optimalDelta - elapsed; // We need to wait until the optimal time has passed. if(needSleepMs > 5) { // Longer sleep, yield to other threads. Sys_Sleep(needSleepMs - 3); // Leave some room for inaccuracies. } // Attempt to make sure we really wait until the optimal time. Sys_BlockUntilRealTime(targetUpdateTime); nowTime = Timer_RealMilliseconds(); elapsed = nowTime - prevUpdateTime; } // The time for this update. prevUpdateTime = nowTime; timeDeltaStatistics((int)elapsed - (int)optimalDelta); }
/* ======================== idSessionLocal::LoadGameCheckDiscNumber ======================== */ bool idSessionLocal::LoadGameCheckDiscNumber( idSaveLoadParms & parms ) { #if 0 idStr mapName = parms.description.GetMapName(); assert( !discSwapStateMgr->IsWorking() ); discSwapStateMgr->Init( &parms.callbackSignal, idDiscSwapStateManager::DISC_SWAP_COMMAND_LOAD ); //// TODO_KC this is probably broken now... //discSwapStateMgr->folder = folder; //discSwapStateMgr->spawnInfo = newSpawnInfo; //discSwapStateMgr->spawnSpot = newSpawnPoint; //discSwapStateMgr->instanceFileName = instanceFileName; discSwapStateMgr->user = session->GetSignInManager().GetMasterLocalUser(); discSwapStateMgr->map = mapName; discSwapStateMgr->Pump(); while ( discSwapStateMgr->IsWorking() ) { Sys_Sleep( 15 ); // process input and render discSwapStateMgr->Pump(); } idDiscSwapStateManager::discSwapStateError_t discSwapError = discSwapStateMgr->GetError(); if ( discSwapError == idDiscSwapStateManager::DSSE_CANCEL ) { parms.errorCode = SAVEGAME_E_CANCELLED; } else if ( discSwapError == idDiscSwapStateManager::DSSE_INSUFFICIENT_ROOM ) { parms.errorCode = SAVEGAME_E_INSUFFICIENT_ROOM; parms.requiredSpaceInBytes = discSwapStateMgr->GetRequiredStorageBytes(); } else if ( discSwapError == idDiscSwapStateManager::DSSE_CORRECT_DISC_ALREADY ) { parms.errorCode = SAVEGAME_E_NONE; } else if ( discSwapError != idDiscSwapStateManager::DSSE_OK ) { parms.errorCode = SAVEGAME_E_DISC_SWAP; } if ( parms.errorCode == SAVEGAME_E_UNKNOWN ) { parms.errorCode = SAVEGAME_E_DISC_SWAP; } #endif return ( parms.GetError() == SAVEGAME_E_NONE ); }
/* * SV_MM_Logout */ static void SV_MM_Logout( qboolean force ) { stat_query_t *query; unsigned int timeout; if( !sv_mm_initialized || !sv_mm_session ) return; query = sq_api->CreateQuery( "slogout", qfalse ); if( query == NULL ) return; sv_mm_logout_semaphore = qfalse; // TODO: pull the authkey out of cvar into file sq_api->SetField( query, "ssession", va( "%d", sv_mm_session ) ); sq_api->SetCallback( query, sv_mm_logout_done, NULL ); sq_api->Send( query ); if( force ) { timeout = Sys_Milliseconds(); while( !sv_mm_logout_semaphore && Sys_Milliseconds() < ( timeout + MM_LOGOUT_TIMEOUT ) ) { sq_api->Poll(); Sys_Sleep( 10 ); } if( !sv_mm_logout_semaphore ) Com_Printf("SV_MM_Logout: Failed to force logout\n"); else Com_Printf("SV_MM_Logout: force logout successful\n"); sv_mm_logout_semaphore = qfalse; // dont call this, we are coming from shutdown // SV_MM_Shutdown( qfalse ); } }
void Sys_Error (const char *error, ...) { va_list argptr; char text[1024]; Sys_Backtrace(); #ifdef COMPILE_MAP Mem_Shutdown(); #endif va_start(argptr, error); Q_vsnprintf(text, sizeof(text), error, argptr); va_end(argptr); /* Echo to console */ Sys_ConsoleOutput("\n"); Sys_ConsoleOutput(text); Sys_ConsoleOutput("\n"); /* Display the message and set a timer so we can flash the text */ SetWindowText(sys_console.hWndMsg, text); SetTimer(sys_console.hWnd, 1, 1000, NULL); sys_console.timerActive = true; /* Show/hide everything we need */ ShowWindow(sys_console.hWndMsg, SW_SHOW); ShowWindow(sys_console.hWndInput, SW_HIDE); Sys_ShowConsole(true); /* Wait for the user to quit */ while (1) { Sys_ConsoleLoop(true); /* Don't hog the CPU */ Sys_Sleep(25); } }
Int32 CCXApplication::_OnAppIdle(MESSAGE_t * pMsg, UInt32 uData) { CCXApplication * pThis = CCXApplication::sharedApplication(); CCXEGLView * pView = CCDirector::sharedDirector()->getOpenGLView(); if (pThis && pView && pThis->m_bRunning) { if (pThis->m_bNeedStop) { pThis->m_bNeedStop = FALSE; pThis->m_bRunning = FALSE; } else { #ifdef _TRANZDA_VM_ LARGE_INTEGER nNow; QueryPerformanceCounter(&nNow); if (nNow.QuadPart - s_nLast.QuadPart >= s_nAnimationInterval.QuadPart) { pView->UpdateWindow(0); s_nLast.QuadPart = nNow.QuadPart; } #else long long nNow = getTimeOfDayMicroSecond(); if (nNow - s_nLast >= s_nAnimationInterval) { pView->UpdateWindow(0); s_nLast = nNow; } #endif else { Sys_Sleep(0); } Sys_PostMessage2(MESSAGE_PRIOR_LOWEST, &pThis->m_tMsg); } } return 1; }
void CGameWorld::run() { ULONG dtime; static ULONG frame = 0; m_iOldTime = Sys_GetTime(); ULONG endTime = Sys_GetTime() + (30 * 1000); while(g_bGameRun) { m_iOldTime = m_iTime; m_iTime = Sys_GetTime(); process(); if(m_iTime - m_iSyncTime >= g_cfg.r2c_interval) { m_iSyncTime = m_iTime; time_t nTime =0; time(&nTime); } dtime = m_iTime - m_iOldTime; float fDeltaTime = float(dtime) / 1000.0f; //OnRun(fDeltaTime); if(dtime < 10) { Sys_Sleep(10); } else if(dtime > 300) { printf("frame time = %d \r\n",dtime); } } }
/* ======================== GLimp_TestSwapBuffers ======================== */ void GLimp_TestSwapBuffers( const idCmdArgs& args ) { idLib::Printf( "GLimp_TimeSwapBuffers\n" ); static const int MAX_FRAMES = 5; uint64 timestamps[MAX_FRAMES]; qglDisable( GL_SCISSOR_TEST ); int frameMilliseconds = 16; for( int swapInterval = 2 ; swapInterval >= -1 ; swapInterval-- ) { wglSwapIntervalEXT( swapInterval ); for( int i = 0 ; i < MAX_FRAMES ; i++ ) { if( swapInterval == -1 ) { Sys_Sleep( frameMilliseconds ); } if( i & 1 ) { qglClearColor( 0, 1, 0, 1 ); } else { qglClearColor( 1, 0, 0, 1 ); } qglClear( GL_COLOR_BUFFER_BIT ); qwglSwapBuffers( win32.hDC ); qglFinish(); timestamps[i] = Sys_Microseconds(); } idLib::Printf( "\nswapinterval %i\n", swapInterval ); for( int i = 1 ; i < MAX_FRAMES ; i++ ) { idLib::Printf( "%i microseconds\n", ( int )( timestamps[i] - timestamps[i - 1] ) ); } } }
int main( int argc, char **argv ) { unsigned int oldtime, newtime, time; InitSig(); #if defined ( __MACOSX__ ) && !defined ( DEDICATED_ONLY ) char resourcesPath[MAXPATHLEN]; CFURLGetFileSystemRepresentation( CFBundleCopyResourcesDirectoryURL( CFBundleGetMainBundle() ), 1, (UInt8 *)resourcesPath, MAXPATHLEN ); chdir( resourcesPath ); SDL_Init( SDL_INIT_VIDEO ); #endif Qcommon_Init( argc, argv ); fcntl( 0, F_SETFL, fcntl( 0, F_GETFL, 0 ) | O_NONBLOCK ); oldtime = Sys_Milliseconds(); while( true ) { // find time spent rendering last frame do { newtime = Sys_Milliseconds(); time = newtime - oldtime; if( time > 0 ) { break; } #ifdef PUTCPU2SLEEP Sys_Sleep( 0 ); #endif } while( 1 ); oldtime = newtime; Qcommon_Frame( time ); } #if defined ( __MACOSX__ ) && !defined ( DEDICATED_ONLY ) SDL_Quit(); #endif }
static int Child(void *arg) { volatile char *name = (char *) arg; int i,j; char *addr; USLOSS_Console("Child \"%s\" starting.\n", name); for (i = 0; i < ITERATIONS; i++) { for (j = 0; j < PAGES; j++) { addr = vmRegion + j * pageSize; USLOSS_Console("Child \"%s\" writing to page %d @ %p\n", name, j, addr); *addr = *name; } Sys_Sleep(1); for (j = 0; j < PAGES; j++) { addr = vmRegion + j * pageSize; assert(*addr == *name); } } USLOSS_Console("Child \"%s\" done.\n", name); return 0; }
int main( int argc, char **argv ) { unsigned int oldtime, newtime, time; #if defined( __APPLE__ ) && !defined( DEDICATED_ONLY ) char resourcesPath[MAXPATHLEN]; CFURLGetFileSystemRepresentation( CFBundleCopyResourcesDirectoryURL( CFBundleGetMainBundle() ), 1, (UInt8 *)resourcesPath, MAXPATHLEN ); chdir( resourcesPath ); #endif #if defined( __WIN32__ ) #if defined( _DEBUG ) SDL_SetHint( SDL_HINT_ALLOW_TOPMOST, "0" ); #endif #endif SDL_Init( SDL_INIT_VIDEO ); Qcommon_Init( argc, argv ); oldtime = Sys_Milliseconds(); while( true ) { // find time spent rendering last frame do { newtime = Sys_Milliseconds(); time = newtime - oldtime; if( time > 0 ) break; Sys_Sleep( 0 ); } while( 1 ); oldtime = newtime; Qcommon_Frame( time ); } SDL_Quit(); }
// // The actual work of accepting a new incoming connection // is done in a separate thread. This is to avoid blocking // the main thread on new connections. // // Incoming player connections are handled completely in the // thread function. The function does the SSL handshake and // then waits for the version data. Upon receiving the version // data, the player is either redirected to a Lounge Server // or the upgrade process is initiated. // THREADPROC_RETURN CDECL AcceptPlayerProc(VOID* pV) { CAccepter::Inst()->incThreads(); CAccepter::AcceptItem* pI = (CAccepter::AcceptItem*)pV; SOCKET sockfd = pI->sock_; SOCKET newsd = INVALID_SOCKET; try { newsd = Sys_accept_SSL(sockfd); if (newsd != INVALID_SOCKET) { CLB::Inst()->handlePlayerConnection(newsd); } } catch(...) { Err::Log() << "Exception in player accept thread!\n"; } // The connection is completely handled by now if (newsd != INVALID_SOCKET) { // Allow some time for the data to get there Sys_Sleep(1000); Sys_closesocket(newsd); } delete pI; CAccepter::Inst()->decThreads(); }
void Error( const char *error, ... ) { char out_buffer[4096]; char tmp[4096]; va_list argptr; va_start( argptr, error ); vsprintf( tmp, error, argptr ); va_end( argptr ); sprintf( out_buffer, "************ ERROR ************\n%s\n", tmp ); FPrintf( SYS_ERR, out_buffer ); #ifdef DBG_XML DumpXML(); #endif //++timo HACK ALERT .. if we shut down too fast the xml stream won't reach the listener. // a clean solution is to send a sync request node in the stream and wait for an answer before exiting Sys_Sleep( 1000 ); Broadcast_Shutdown(); exit( 1 ); }
/* =================== GLW_ChangeDislaySettingsIfNeeded Optionally ChangeDisplaySettings to get a different fullscreen resolution. Default uses the full desktop resolution. =================== */ static bool GLW_ChangeDislaySettingsIfNeeded( glimpParms_t parms ) { // If we had previously changed the display settings on a different monitor, // go back to standard. if( win32.cdsFullscreen != 0 && win32.cdsFullscreen != parms.fullScreen ) { win32.cdsFullscreen = 0; ChangeDisplaySettings( 0, 0 ); Sys_Sleep( 1000 ); // Give the driver some time to think about this change } // 0 is dragable mode on desktop, -1 is borderless window on desktop if( parms.fullScreen <= 0 ) { return true; } // if we are already in the right resolution, don't do a ChangeDisplaySettings int x, y, width, height, displayHz; if( !GetDisplayCoordinates( parms.fullScreen - 1, x, y, width, height, displayHz ) ) { return false; } if( width == parms.width && height == parms.height && ( displayHz == parms.displayHz || parms.displayHz == 0 ) ) { return true; } DEVMODE dm = {}; dm.dmSize = sizeof( dm ); dm.dmPelsWidth = parms.width; dm.dmPelsHeight = parms.height; dm.dmBitsPerPel = 32; dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL; if( parms.displayHz != 0 ) { dm.dmDisplayFrequency = parms.displayHz; dm.dmFields |= DM_DISPLAYFREQUENCY; } common->Printf( "...calling CDS: " ); const char* const deviceName = GetDisplayName( parms.fullScreen - 1 ); int cdsRet; if( ( cdsRet = ChangeDisplaySettingsEx( deviceName, &dm, NULL, CDS_FULLSCREEN, NULL ) ) == DISP_CHANGE_SUCCESSFUL ) { common->Printf( "ok\n" ); win32.cdsFullscreen = parms.fullScreen; return true; } common->Printf( "^3failed^0, " ); PrintCDSError( cdsRet ); return false; }
void Host_Main(void) { double time1 = 0; double time2 = 0; double time3 = 0; double cl_timer = 0, sv_timer = 0; double clframetime, deltacleantime, olddirtytime, dirtytime; double wait; int pass1, pass2, pass3, i; char vabuf[1024]; qboolean playing; Host_Init(); realtime = 0; host_dirtytime = Sys_DirtyTime(); for (;;) { if (setjmp(host_abortframe)) { SCR_ClearLoadingScreen(false); continue; // something bad happened, or the server disconnected } olddirtytime = host_dirtytime; dirtytime = Sys_DirtyTime(); deltacleantime = dirtytime - olddirtytime; if (deltacleantime < 0) { // warn if it's significant if (deltacleantime < -0.01) Con_Printf("Host_Mingled: time stepped backwards (went from %f to %f, difference %f)\n", olddirtytime, dirtytime, deltacleantime); deltacleantime = 0; } else if (deltacleantime >= 1800) { Con_Printf("Host_Mingled: time stepped forward (went from %f to %f, difference %f)\n", olddirtytime, dirtytime, deltacleantime); deltacleantime = 0; } realtime += deltacleantime; host_dirtytime = dirtytime; cl_timer += deltacleantime; sv_timer += deltacleantime; if (!svs.threaded) { svs.perf_acc_realtime += deltacleantime; // Look for clients who have spawned playing = false; for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++) if(host_client->begun) if(host_client->netconnection) playing = true; if(sv.time < 10) { // don't accumulate time for the first 10 seconds of a match // so things can settle svs.perf_acc_realtime = svs.perf_acc_sleeptime = svs.perf_acc_lost = svs.perf_acc_offset = svs.perf_acc_offset_squared = svs.perf_acc_offset_max = svs.perf_acc_offset_samples = 0; } else if(svs.perf_acc_realtime > 5) { svs.perf_cpuload = 1 - svs.perf_acc_sleeptime / svs.perf_acc_realtime; svs.perf_lost = svs.perf_acc_lost / svs.perf_acc_realtime; if(svs.perf_acc_offset_samples > 0) { svs.perf_offset_max = svs.perf_acc_offset_max; svs.perf_offset_avg = svs.perf_acc_offset / svs.perf_acc_offset_samples; svs.perf_offset_sdev = sqrt(svs.perf_acc_offset_squared / svs.perf_acc_offset_samples - svs.perf_offset_avg * svs.perf_offset_avg); } if(svs.perf_lost > 0 && developer_extra.integer) if(playing) // only complain if anyone is looking Con_DPrintf("Server can't keep up: %s\n", Host_TimingReport(vabuf, sizeof(vabuf))); svs.perf_acc_realtime = svs.perf_acc_sleeptime = svs.perf_acc_lost = svs.perf_acc_offset = svs.perf_acc_offset_squared = svs.perf_acc_offset_max = svs.perf_acc_offset_samples = 0; } } if (slowmo.value < 0.00001 && slowmo.value != 0) Cvar_SetValue("slowmo", 0); if (host_framerate.value < 0.00001 && host_framerate.value != 0) Cvar_SetValue("host_framerate", 0); // keep the random time dependent, but not when playing demos/benchmarking if(!*sv_random_seed.string && !cls.demoplayback) rand(); // get new key events Key_EventQueue_Unblock(); SndSys_SendKeyEvents(); Sys_SendKeyEvents(); NetConn_UpdateSockets(); Log_DestBuffer_Flush(); // receive packets on each main loop iteration, as the main loop may // be undersleeping due to select() detecting a new packet if (sv.active && !svs.threaded) NetConn_ServerFrame(); Curl_Run(); // check for commands typed to the host Host_GetConsoleCommands(); // when a server is running we only execute console commands on server frames // (this mainly allows frikbot .way config files to work properly by staying in sync with the server qc) // otherwise we execute them on client frames if (sv.active ? sv_timer > 0 : cl_timer > 0) { // process console commands // R_TimeReport("preconsole"); CL_VM_PreventInformationLeaks(); Cbuf_Frame(); // R_TimeReport("console"); } //Con_Printf("%6.0f %6.0f\n", cl_timer * 1000000.0, sv_timer * 1000000.0); // if the accumulators haven't become positive yet, wait a while if (cls.state == ca_dedicated) wait = sv_timer * -1000000.0; else if (!sv.active || svs.threaded) wait = cl_timer * -1000000.0; else wait = max(cl_timer, sv_timer) * -1000000.0; if (!cls.timedemo && wait >= 1) { double time0, delta; if(host_maxwait.value <= 0) wait = min(wait, 1000000.0); else wait = min(wait, host_maxwait.value * 1000.0); if(wait < 1) wait = 1; // because we cast to int time0 = Sys_DirtyTime(); if (sv_checkforpacketsduringsleep.integer && !sys_usenoclockbutbenchmark.integer && !svs.threaded) { NetConn_SleepMicroseconds((int)wait); if (cls.state != ca_dedicated) NetConn_ClientFrame(); // helps server browser get good ping values // TODO can we do the same for ServerFrame? Probably not. } else Sys_Sleep((int)wait); delta = Sys_DirtyTime() - time0; if (delta < 0 || delta >= 1800) delta = 0; if (!svs.threaded) svs.perf_acc_sleeptime += delta; // R_TimeReport("sleep"); continue; } // limit the frametime steps to no more than 100ms each if (cl_timer > 0.1) cl_timer = 0.1; if (sv_timer > 0.1) { if (!svs.threaded) svs.perf_acc_lost += (sv_timer - 0.1); sv_timer = 0.1; } R_TimeReport("---"); //------------------- // // server operations // //------------------- // limit the frametime steps to no more than 100ms each if (sv.active && sv_timer > 0 && !svs.threaded) { // execute one or more server frames, with an upper limit on how much // execution time to spend on server frames to avoid freezing the game if // the server is overloaded, this execution time limit means the game will // slow down if the server is taking too long. int framecount, framelimit = 1; double advancetime, aborttime = 0; float offset; prvm_prog_t *prog = SVVM_prog; // run the world state // don't allow simulation to run too fast or too slow or logic glitches can occur // stop running server frames if the wall time reaches this value if (sys_ticrate.value <= 0) advancetime = sv_timer; else if (cl.islocalgame && !sv_fixedframeratesingleplayer.integer) { // synchronize to the client frametime, but no less than 10ms and no more than 100ms advancetime = bound(0.01, cl_timer, 0.1); } else { advancetime = sys_ticrate.value; // listen servers can run multiple server frames per client frame framelimit = cl_maxphysicsframesperserverframe.integer; aborttime = Sys_DirtyTime() + 0.1; } if(slowmo.value > 0 && slowmo.value < 1) advancetime = min(advancetime, 0.1 / slowmo.value); else advancetime = min(advancetime, 0.1); if(advancetime > 0) { offset = Sys_DirtyTime() - dirtytime;if (offset < 0 || offset >= 1800) offset = 0; offset += sv_timer; ++svs.perf_acc_offset_samples; svs.perf_acc_offset += offset; svs.perf_acc_offset_squared += offset * offset; if(svs.perf_acc_offset_max < offset) svs.perf_acc_offset_max = offset; } // only advance time if not paused // the game also pauses in singleplayer when menu or console is used sv.frametime = advancetime * slowmo.value; if (host_framerate.value) sv.frametime = host_framerate.value; if (sv.paused || (cl.islocalgame && (key_dest != key_game || key_consoleactive || cl.csqc_paused))) sv.frametime = 0; for (framecount = 0;framecount < framelimit && sv_timer > 0;framecount++) { sv_timer -= advancetime; // move things around and think unless paused if (sv.frametime) SV_Physics(); // if this server frame took too long, break out of the loop if (framelimit > 1 && Sys_DirtyTime() >= aborttime) break; } R_TimeReport("serverphysics"); // send all messages to the clients SV_SendClientMessages(); if (sv.paused == 1 && realtime > sv.pausedstart && sv.pausedstart > 0) { prog->globals.fp[OFS_PARM0] = realtime - sv.pausedstart; PRVM_serverglobalfloat(time) = sv.time; prog->ExecuteProgram(prog, PRVM_serverfunction(SV_PausedTic), "QC function SV_PausedTic is missing"); } // send an heartbeat if enough time has passed since the last one NetConn_Heartbeat(0); R_TimeReport("servernetwork"); } else if (!svs.threaded) { // don't let r_speeds display jump around R_TimeReport("serverphysics"); R_TimeReport("servernetwork"); } //------------------- // // client operations // //------------------- if (cls.state != ca_dedicated && (cl_timer > 0 || cls.timedemo || ((vid_activewindow ? cl_maxfps : cl_maxidlefps).value < 1))) { R_TimeReport("---"); Collision_Cache_NewFrame(); R_TimeReport("photoncache"); // decide the simulation time if (cls.capturevideo.active) { //*** if (cls.capturevideo.realtime) clframetime = cl.realframetime = max(cl_timer, 1.0 / cls.capturevideo.framerate); else { clframetime = 1.0 / cls.capturevideo.framerate; cl.realframetime = max(cl_timer, clframetime); } } else if (vid_activewindow && cl_maxfps.value >= 1 && !cls.timedemo) { clframetime = cl.realframetime = max(cl_timer, 1.0 / cl_maxfps.value); // when running slow, we need to sleep to keep input responsive wait = bound(0, cl_maxfps_alwayssleep.value * 1000, 100000); if (wait > 0) Sys_Sleep((int)wait); } else if (!vid_activewindow && cl_maxidlefps.value >= 1 && !cls.timedemo) clframetime = cl.realframetime = max(cl_timer, 1.0 / cl_maxidlefps.value); else clframetime = cl.realframetime = cl_timer; // apply slowmo scaling clframetime *= cl.movevars_timescale; // scale playback speed of demos by slowmo cvar if (cls.demoplayback) { clframetime *= slowmo.value; // if demo playback is paused, don't advance time at all if (cls.demopaused) clframetime = 0; } else { // host_framerate overrides all else if (host_framerate.value) clframetime = host_framerate.value; if (cl.paused || (cl.islocalgame && (key_dest != key_game || key_consoleactive || cl.csqc_paused))) clframetime = 0; } if (cls.timedemo) clframetime = cl.realframetime = cl_timer; // deduct the frame time from the accumulator cl_timer -= cl.realframetime; cl.oldtime = cl.time; cl.time += clframetime; // update video if (host_speeds.integer) time1 = Sys_DirtyTime(); R_TimeReport("pre-input"); // Collect input into cmd CL_Input(); R_TimeReport("input"); // check for new packets NetConn_ClientFrame(); // read a new frame from a demo if needed CL_ReadDemoMessage(); R_TimeReport("clientnetwork"); // now that packets have been read, send input to server CL_SendMove(); R_TimeReport("sendmove"); // update client world (interpolate entities, create trails, etc) CL_UpdateWorld(); R_TimeReport("lerpworld"); CL_Video_Frame(); R_TimeReport("client"); CL_UpdateScreen(); CL_MeshEntities_Reset(); R_TimeReport("render"); if (host_speeds.integer) time2 = Sys_DirtyTime(); // update audio if(cl.csqc_usecsqclistener) { S_Update(&cl.csqc_listenermatrix); cl.csqc_usecsqclistener = false; } else S_Update(&r_refdef.view.matrix); CDAudio_Update(); R_TimeReport("audio"); // reset gathering of mouse input in_mouse_x = in_mouse_y = 0; if (host_speeds.integer) { pass1 = (int)((time1 - time3)*1000000); time3 = Sys_DirtyTime(); pass2 = (int)((time2 - time1)*1000000); pass3 = (int)((time3 - time2)*1000000); Con_Printf("%6ius total %6ius server %6ius gfx %6ius snd\n", pass1+pass2+pass3, pass1, pass2, pass3); } } #if MEMPARANOIA Mem_CheckSentinelsGlobal(); #else if (developer_memorydebug.integer) Mem_CheckSentinelsGlobal(); #endif // if there is some time remaining from this frame, reset the timers if (cl_timer >= 0) cl_timer = 0; if (sv_timer >= 0) { if (!svs.threaded) svs.perf_acc_lost += sv_timer; sv_timer = 0; } host_framecount++; } }
/* * Sys_Thread_Yield */ void Sys_Thread_Yield( void ) { Sys_Sleep(0); }
/* =============== idGameThread::Run Run in a background thread for performance, but can also be called directly in the foreground thread for comparison. =============== */ int idGameThread::Run() { commonLocal.frameTiming.startGameTime = Sys_Microseconds(); // debugging tool to test frame dropping behavior if ( com_sleepGame.GetInteger() ) { Sys_Sleep( com_sleepGame.GetInteger() ); } if ( numGameFrames == 0 ) { // Ensure there's no stale gameReturn data from a paused game ret = gameReturn_t(); } if ( isClient ) { // run the game logic for ( int i = 0; i < numGameFrames; i++ ) { SCOPED_PROFILE_EVENT( "Client Prediction" ); if ( userCmdMgr ) { game->ClientRunFrame( *userCmdMgr, ( i == numGameFrames - 1 ), ret ); } if ( ret.syncNextGameFrame || ret.sessionCommand[0] != 0 ) { break; } } } else { // run the game logic for ( int i = 0; i < numGameFrames; i++ ) { SCOPED_PROFILE_EVENT( "GameTic" ); if ( userCmdMgr ) { game->RunFrame( *userCmdMgr, ret ); } if ( ret.syncNextGameFrame || ret.sessionCommand[0] != 0 ) { break; } } } // we should have consumed all of our usercmds if ( userCmdMgr ) { if ( userCmdMgr->HasUserCmdForPlayer( game->GetLocalClientNum() ) && common->GetCurrentGame() == DOOM3_BFG ) { idLib::Printf( "idGameThread::Run: didn't consume all usercmds\n" ); } } commonLocal.frameTiming.finishGameTime = Sys_Microseconds(); SetThreadGameTime( ( commonLocal.frameTiming.finishGameTime - commonLocal.frameTiming.startGameTime ) / 1000 ); // build render commands and geometry { SCOPED_PROFILE_EVENT( "Draw" ); commonLocal.Draw(); } commonLocal.frameTiming.finishDrawTime = Sys_Microseconds(); SetThreadRenderTime( ( commonLocal.frameTiming.finishDrawTime - commonLocal.frameTiming.finishGameTime ) / 1000 ); SetThreadTotalTime( ( commonLocal.frameTiming.finishDrawTime - commonLocal.frameTiming.startGameTime ) / 1000 ); return 0; }
/* ================= idCommonLocal::Frame ================= */ void idCommonLocal::Frame() { try { SCOPED_PROFILE_EVENT( "Common::Frame" ); // This is the only place this is incremented idLib::frameNumber++; // allow changing SIMD usage on the fly if ( com_forceGenericSIMD.IsModified() ) { idSIMD::InitProcessor( "doom", com_forceGenericSIMD.GetBool() ); com_forceGenericSIMD.ClearModified(); } // Do the actual switch between Doom 3 and the classics here so // that things don't get confused in the middle of the frame. PerformGameSwitch(); // pump all the events Sys_GenerateEvents(); // write config file if anything changed WriteConfiguration(); eventLoop->RunEventLoop(); // Activate the shell if it's been requested if ( showShellRequested && game ) { game->Shell_Show( true ); showShellRequested = false; } // if the console or another gui is down, we don't need to hold the mouse cursor bool chatting = false; if ( console->Active() || Dialog().IsDialogActive() || session->IsSystemUIShowing() || ( game && game->InhibitControls() && !IsPlayingDoomClassic() ) ) { Sys_GrabMouseCursor( false ); usercmdGen->InhibitUsercmd( INHIBIT_SESSION, true ); chatting = true; } else { Sys_GrabMouseCursor( true ); usercmdGen->InhibitUsercmd( INHIBIT_SESSION, false ); } const bool pauseGame = ( !mapSpawned || ( !IsMultiplayer() && ( Dialog().IsDialogPausing() || session->IsSystemUIShowing() || ( game && game->Shell_IsActive() ) ) ) ) && !IsPlayingDoomClassic(); // save the screenshot and audio from the last draw if needed if ( aviCaptureMode ) { idStr name = va("demos/%s/%s_%05i.tga", aviDemoShortName.c_str(), aviDemoShortName.c_str(), aviDemoFrameCount++ ); renderSystem->TakeScreenshot( com_aviDemoWidth.GetInteger(), com_aviDemoHeight.GetInteger(), name, com_aviDemoSamples.GetInteger(), NULL ); // remove any printed lines at the top before taking the screenshot console->ClearNotifyLines(); // this will call Draw, possibly multiple times if com_aviDemoSamples is > 1 renderSystem->TakeScreenshot( com_aviDemoWidth.GetInteger(), com_aviDemoHeight.GetInteger(), name, com_aviDemoSamples.GetInteger(), NULL ); } //-------------------------------------------- // wait for the GPU to finish drawing // // It is imporant to minimize the time spent between this // section and the call to renderSystem->RenderCommandBuffers(), // because the GPU is completely idle. //-------------------------------------------- // this should exit right after vsync, with the GPU idle and ready to draw // This may block if the GPU isn't finished renderng the previous frame. frameTiming.startSyncTime = Sys_Microseconds(); const emptyCommand_t * renderCommands = NULL; if ( com_smp.GetBool() ) { renderCommands = renderSystem->SwapCommandBuffers( &time_frontend, &time_backend, &time_shadows, &time_gpu ); } else { // the GPU will stay idle through command generation for minimal // input latency renderSystem->SwapCommandBuffers_FinishRendering( &time_frontend, &time_backend, &time_shadows, &time_gpu ); } frameTiming.finishSyncTime = Sys_Microseconds(); //-------------------------------------------- // Determine how many game tics we are going to run, // now that the previous frame is completely finished. // // It is important that any waiting on the GPU be done // before this, or there will be a bad stuttering when // dropping frames for performance management. //-------------------------------------------- // input: // thisFrameTime // com_noSleep // com_engineHz // com_fixedTic // com_deltaTimeClamp // IsMultiplayer // // in/out state: // gameFrame // gameTimeResidual // lastFrameTime // syncNextFrame // // Output: // numGameFrames // How many game frames to run int numGameFrames = 0; for(;;) { const int thisFrameTime = Sys_Milliseconds(); static int lastFrameTime = thisFrameTime; // initialized only the first time const int deltaMilliseconds = thisFrameTime - lastFrameTime; lastFrameTime = thisFrameTime; // if there was a large gap in time since the last frame, or the frame // rate is very very low, limit the number of frames we will run const int clampedDeltaMilliseconds = Min( deltaMilliseconds, com_deltaTimeClamp.GetInteger() ); gameTimeResidual += clampedDeltaMilliseconds * timescale.GetFloat(); // don't run any frames when paused if ( pauseGame ) { gameFrame++; gameTimeResidual = 0; break; } // debug cvar to force multiple game tics if ( com_fixedTic.GetInteger() > 0 ) { numGameFrames = com_fixedTic.GetInteger(); gameFrame += numGameFrames; gameTimeResidual = 0; break; } if ( syncNextGameFrame ) { // don't sleep at all syncNextGameFrame = false; gameFrame++; numGameFrames++; gameTimeResidual = 0; break; } for ( ;; ) { // How much time to wait before running the next frame, // based on com_engineHz const int frameDelay = FRAME_TO_MSEC( gameFrame + 1 ) - FRAME_TO_MSEC( gameFrame ); if ( gameTimeResidual < frameDelay ) { break; } gameTimeResidual -= frameDelay; gameFrame++; numGameFrames++; // if there is enough residual left, we may run additional frames } if ( numGameFrames > 0 ) { // ready to actually run them break; } // if we are vsyncing, we always want to run at least one game // frame and never sleep, which might happen due to scheduling issues // if we were just looking at real time. if ( com_noSleep.GetBool() ) { numGameFrames = 1; gameFrame += numGameFrames; gameTimeResidual = 0; break; } // not enough time has passed to run a frame, as might happen if // we don't have vsync on, or the monitor is running at 120hz while // com_engineHz is 60, so sleep a bit and check again Sys_Sleep( 0 ); } //-------------------------------------------- // It would be better to push as much of this as possible // either before or after the renderSystem->SwapCommandBuffers(), // because the GPU is completely idle. //-------------------------------------------- // Update session and syncronize to the new session state after sleeping session->UpdateSignInManager(); session->Pump(); session->ProcessSnapAckQueue(); if ( session->GetState() == idSession::LOADING ) { // If the session reports we should be loading a map, load it! ExecuteMapChange(); mapSpawnData.savegameFile = NULL; mapSpawnData.persistentPlayerInfo.Clear(); return; } else if ( session->GetState() != idSession::INGAME && mapSpawned ) { // If the game is running, but the session reports we are not in a game, disconnect // This happens when a server disconnects us or we sign out LeaveGame(); return; } if ( mapSpawned && !pauseGame ) { if ( IsClient() ) { RunNetworkSnapshotFrame(); } } ExecuteReliableMessages(); // send frame and mouse events to active guis GuiFrameEvents(); //-------------------------------------------- // Prepare usercmds and kick off the game processing // in a background thread //-------------------------------------------- // get the previous usercmd for bypassed head tracking transform const usercmd_t previousCmd = usercmdGen->GetCurrentUsercmd(); // build a new usercmd int deviceNum = session->GetSignInManager().GetMasterInputDevice(); usercmdGen->BuildCurrentUsercmd( deviceNum ); if ( deviceNum == -1 ) { for ( int i = 0; i < MAX_INPUT_DEVICES; i++ ) { Sys_PollJoystickInputEvents( i ); Sys_EndJoystickInputEvents(); } } if ( pauseGame ) { usercmdGen->Clear(); } usercmd_t newCmd = usercmdGen->GetCurrentUsercmd(); // Store server game time - don't let time go past last SS time in case we are extrapolating if ( IsClient() ) { newCmd.serverGameMilliseconds = std::min( Game()->GetServerGameTimeMs(), Game()->GetSSEndTime() ); } else { newCmd.serverGameMilliseconds = Game()->GetServerGameTimeMs(); } userCmdMgr.MakeReadPtrCurrentForPlayer( Game()->GetLocalClientNum() ); // Stuff a copy of this userCmd for each game frame we are going to run. // Ideally, the usercmds would be built in another thread so you could // still get 60hz control accuracy when the game is running slower. for ( int i = 0 ; i < numGameFrames ; i++ ) { newCmd.clientGameMilliseconds = FRAME_TO_MSEC( gameFrame-numGameFrames+i+1 ); userCmdMgr.PutUserCmdForPlayer( game->GetLocalClientNum(), newCmd ); } // If we're in Doom or Doom 2, run tics and upload the new texture. if ( ( GetCurrentGame() == DOOM_CLASSIC || GetCurrentGame() == DOOM2_CLASSIC ) && !( Dialog().IsDialogPausing() || session->IsSystemUIShowing() ) ) { RunDoomClassicFrame(); } // start the game / draw command generation thread going in the background gameReturn_t ret = gameThread.RunGameAndDraw( numGameFrames, userCmdMgr, IsClient(), gameFrame - numGameFrames ); if ( !com_smp.GetBool() ) { // in non-smp mode, run the commands we just generated, instead of // frame-delayed ones from a background thread renderCommands = renderSystem->SwapCommandBuffers_FinishCommandBuffers(); } //---------------------------------------- // Run the render back end, getting the GPU busy with new commands // ASAP to minimize the pipeline bubble. //---------------------------------------- frameTiming.startRenderTime = Sys_Microseconds(); renderSystem->RenderCommandBuffers( renderCommands ); if ( com_sleepRender.GetInteger() > 0 ) { // debug tool to test frame adaption Sys_Sleep( com_sleepRender.GetInteger() ); } frameTiming.finishRenderTime = Sys_Microseconds(); // make sure the game / draw thread has completed // This may block if the game is taking longer than the render back end gameThread.WaitForThread(); // Send local usermds to the server. // This happens after the game frame has run so that prediction data is up to date. SendUsercmds( Game()->GetLocalClientNum() ); // Now that we have an updated game frame, we can send out new snapshots to our clients session->Pump(); // Pump to get updated usercmds to relay SendSnapshots(); // Render the sound system using the latest commands from the game thread if ( pauseGame ) { soundWorld->Pause(); soundSystem->SetPlayingSoundWorld( menuSoundWorld ); } else { soundWorld->UnPause(); soundSystem->SetPlayingSoundWorld( soundWorld ); } soundSystem->Render(); // process the game return for map changes, etc ProcessGameReturn( ret ); idLobbyBase & lobby = session->GetActivePlatformLobbyBase(); if ( lobby.HasActivePeers() ) { if ( net_drawDebugHud.GetInteger() == 1 ) { lobby.DrawDebugNetworkHUD(); } if ( net_drawDebugHud.GetInteger() == 2 ) { lobby.DrawDebugNetworkHUD2(); } lobby.DrawDebugNetworkHUD_ServerSnapshotMetrics( net_drawDebugHud.GetInteger() == 3 ); } // report timing information if ( com_speeds.GetBool() ) { static int lastTime = Sys_Milliseconds(); int nowTime = Sys_Milliseconds(); int com_frameMsec = nowTime - lastTime; lastTime = nowTime; Printf( "frame:%d all:%3d gfr:%3d rf:%3lld bk:%3lld\n", idLib::frameNumber, com_frameMsec, time_gameFrame, time_frontend / 1000, time_backend / 1000 ); time_gameFrame = 0; time_gameDraw = 0; } // the FPU stack better be empty at this point or some bad code or compiler bug left values on the stack if ( !Sys_FPU_StackIsEmpty() ) { Printf( Sys_FPU_GetState() ); FatalError( "idCommon::Frame: the FPU stack is not empty at the end of the frame\n" ); } mainFrameTiming = frameTiming; session->GetSaveGameManager().Pump(); } catch( idException & ) { return; // an ERP_DROP was thrown } }
/* =============== idCommonLocal::Draw =============== */ void idCommonLocal::Draw() { // debugging tool to test frame dropping behavior if ( com_sleepDraw.GetInteger() ) { Sys_Sleep( com_sleepDraw.GetInteger() ); } if ( loadGUI != NULL ) { loadGUI->Render( renderSystem, Sys_Milliseconds() ); } else if ( currentGame == DOOM_CLASSIC || currentGame == DOOM2_CLASSIC ) { const float sysWidth = renderSystem->GetWidth() * renderSystem->GetPixelAspect(); const float sysHeight = renderSystem->GetHeight(); const float sysAspect = sysWidth / sysHeight; const float doomAspect = 4.0f / 3.0f; const float adjustment = sysAspect / doomAspect; const float barHeight = ( adjustment >= 1.0f ) ? 0.0f : ( 1.0f - adjustment ) * (float)SCREEN_HEIGHT * 0.25f; const float barWidth = ( adjustment <= 1.0f ) ? 0.0f : ( adjustment - 1.0f ) * (float)SCREEN_WIDTH * 0.25f; if ( barHeight > 0.0f ) { renderSystem->SetColor( colorBlack ); renderSystem->DrawStretchPic( 0, 0, SCREEN_WIDTH, barHeight, 0, 0, 1, 1, whiteMaterial ); renderSystem->DrawStretchPic( 0, SCREEN_HEIGHT - barHeight, SCREEN_WIDTH, barHeight, 0, 0, 1, 1, whiteMaterial ); } if ( barWidth > 0.0f ) { renderSystem->SetColor( colorBlack ); renderSystem->DrawStretchPic( 0, 0, barWidth, SCREEN_HEIGHT, 0, 0, 1, 1, whiteMaterial ); renderSystem->DrawStretchPic( SCREEN_WIDTH - barWidth, 0, barWidth, SCREEN_HEIGHT, 0, 0, 1, 1, whiteMaterial ); } renderSystem->SetColor4( 1, 1, 1, 1 ); renderSystem->DrawStretchPic( barWidth, barHeight, SCREEN_WIDTH - barWidth * 2.0f, SCREEN_HEIGHT - barHeight * 2.0f, 0, 0, 1, 1, doomClassicMaterial ); } else if ( game && game->Shell_IsActive() ) { bool gameDraw = game->Draw( game->GetLocalClientNum() ); if ( !gameDraw ) { renderSystem->SetColor( colorBlack ); renderSystem->DrawStretchPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0, 1, 1, whiteMaterial ); } game->Shell_Render(); } else if ( readDemo ) { renderWorld->RenderScene( ¤tDemoRenderView ); renderSystem->DrawDemoPics(); } else if ( mapSpawned ) { bool gameDraw = false; // normal drawing for both single and multi player if ( !com_skipGameDraw.GetBool() && Game()->GetLocalClientNum() >= 0 ) { // draw the game view int start = Sys_Milliseconds(); if ( game ) { gameDraw = game->Draw( Game()->GetLocalClientNum() ); } int end = Sys_Milliseconds(); time_gameDraw += ( end - start ); // note time used for com_speeds } if ( !gameDraw ) { renderSystem->SetColor( colorBlack ); renderSystem->DrawStretchPic( 0, 0, 640, 480, 0, 0, 1, 1, whiteMaterial ); } // save off the 2D drawing from the game if ( writeDemo ) { renderSystem->WriteDemoPics(); } } else { renderSystem->SetColor4( 0, 0, 0, 1 ); renderSystem->DrawStretchPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0, 1, 1, whiteMaterial ); } { SCOPED_PROFILE_EVENT( "Post-Draw" ); // draw the wipe material on top of this if it hasn't completed yet DrawWipeModel(); Dialog().Render( loadGUI != NULL ); // draw the half console / notify console on top of everything console->Draw( false ); } }
qboolean Sys_GetAntiCheatAPI(void) { Sys_Sleep(1500); return qfalse; }
/* =============== idCommonLocal::ExecuteMapChange Performs the initialization of a game based on session match parameters, used for both single player and multiplayer, but not for renderDemos, which don't create a game at all. Exits with mapSpawned = true =============== */ void idCommonLocal::ExecuteMapChange() { if ( session->GetState() != idSession::LOADING ) { idLib::Warning( "Session state is not LOADING in ExecuteMapChange" ); return; } // Clear all dialogs before beginning the load common->Dialog().ClearDialogs( true ); // Remember the current load ID. // This is so we can tell if we had a new loadmap request from within an existing loadmap call const int cachedLoadingID = session->GetLoadingID(); const idMatchParameters & matchParameters = session->GetActingGameStateLobbyBase().GetMatchParms(); if ( matchParameters.numSlots <= 0 ) { idLib::Warning( "numSlots <= 0 in ExecuteMapChange" ); return; } insideExecuteMapChange = true; common->Printf( "--------- Execute Map Change ---------\n" ); common->Printf( "Map: %s\n", matchParameters.mapName.c_str() ); // ensure that r_znear is reset to the default value // this fixes issues with the projection matrix getting messed up when switching maps or loading a saved game // while an in-game cinematic is playing. cvarSystem->SetCVarFloat( "r_znear", 1.0f ); // reset all cheat cvars for a multiplayer game if ( IsMultiplayer() ) { cvarSystem->ResetFlaggedVariables( CVAR_CHEAT ); } int start = Sys_Milliseconds(); for ( int i = 0; i < MAX_INPUT_DEVICES; i++ ) { Sys_SetRumble( i, 0, 0 ); } // close console and remove any prints from the notify lines console->Close(); // clear all menu sounds soundWorld->Pause(); menuSoundWorld->ClearAllSoundEmitters(); soundSystem->SetPlayingSoundWorld( menuSoundWorld ); soundSystem->Render(); // extract the map name from serverinfo currentMapName = matchParameters.mapName; currentMapName.StripFileExtension(); idStrStatic< MAX_OSPATH > fullMapName = "maps/"; fullMapName += currentMapName; fullMapName.SetFileExtension( "map" ); if ( mapSpawnData.savegameFile ) { fileSystem->BeginLevelLoad( currentMapName, NULL, 0 ); } else { fileSystem->BeginLevelLoad( currentMapName, saveFile.GetDataPtr(), saveFile.GetAllocated() ); } // capture the current screen and start a wipe // immediately complete the wipe to fade out the level transition // run the wipe to completion StartWipe( "wipeMaterial", true ); CompleteWipe(); int sm = Sys_Milliseconds(); // shut down the existing game if it is running UnloadMap(); int ms = Sys_Milliseconds() - sm; common->Printf( "%6d msec to unload map\n", ms ); // Free media from previous level and // note which media we are going to need to load sm = Sys_Milliseconds(); renderSystem->BeginLevelLoad(); soundSystem->BeginLevelLoad(); declManager->BeginLevelLoad(); uiManager->BeginLevelLoad(); ms = Sys_Milliseconds() - sm; common->Printf( "%6d msec to free assets\n", ms ); //Sys_DumpMemory( true ); // load / program a gui to stay up on the screen while loading // set the loading gui that we will wipe to bool hellMap = false; LoadLoadingGui( currentMapName, hellMap ); // Stop rendering the wipe ClearWipe(); if ( fileSystem->UsingResourceFiles() ) { idStrStatic< MAX_OSPATH > manifestName = currentMapName; manifestName.Replace( "game/", "maps/" ); manifestName.Replace( "/mp/", "/" ); manifestName += ".preload"; idPreloadManifest manifest; manifest.LoadManifest( manifestName ); renderSystem->Preload( manifest, currentMapName ); soundSystem->Preload( manifest ); game->Preload( manifest ); } if ( common->IsMultiplayer() ) { // In multiplayer, make sure the player is either 60Hz or 120Hz // to avoid potential issues. const float mpEngineHz = ( com_engineHz.GetFloat() < 90.0f ) ? 60.0f : 120.0f; com_engineHz_denominator = 100LL * mpEngineHz; com_engineHz_latched = mpEngineHz; } else { // allow com_engineHz to be changed between map loads com_engineHz_denominator = 100LL * com_engineHz.GetFloat(); com_engineHz_latched = com_engineHz.GetFloat(); } // note any warning prints that happen during the load process common->ClearWarnings( currentMapName ); // release the mouse cursor // before we do this potentially long operation Sys_GrabMouseCursor( false ); // let the renderSystem load all the geometry if ( !renderWorld->InitFromMap( fullMapName ) ) { common->Error( "couldn't load %s", fullMapName.c_str() ); } // for the synchronous networking we needed to roll the angles over from // level to level, but now we can just clear everything usercmdGen->InitForNewMap(); // load and spawn all other entities ( from a savegame possibly ) if ( mapSpawnData.savegameFile ) { if ( !game->InitFromSaveGame( fullMapName, renderWorld, soundWorld, mapSpawnData.savegameFile, mapSpawnData.stringTableFile, mapSpawnData.savegameVersion ) ) { // If the loadgame failed, end the session, which will force us to go back to the main menu session->QuitMatchToTitle(); } } else { if ( !IsMultiplayer() ) { assert( game->GetLocalClientNum() == 0 ); assert( matchParameters.gameMode == GAME_MODE_SINGLEPLAYER ); assert( matchParameters.gameMap == GAME_MAP_SINGLEPLAYER ); game->SetPersistentPlayerInfo( 0, mapSpawnData.persistentPlayerInfo ); } game->SetServerInfo( matchParameters.serverInfo ); game->InitFromNewMap( fullMapName, renderWorld, soundWorld, matchParameters.gameMode, Sys_Milliseconds() ); } game->Shell_CreateMenu( true ); // Reset some values important to multiplayer ResetNetworkingState(); // If the session state is not loading here, something went wrong. if ( session->GetState() == idSession::LOADING && session->GetLoadingID() == cachedLoadingID ) { // Notify session we are done loading session->LoadingFinished(); while ( session->GetState() == idSession::LOADING ) { Sys_GenerateEvents(); session->UpdateSignInManager(); session->Pump(); Sys_Sleep( 10 ); } } if ( !mapSpawnData.savegameFile ) { // run a single frame to catch any resources that are referenced by events posted in spawn idUserCmdMgr emptyCommandManager; gameReturn_t emptyGameReturn; for ( int playerIndex = 0; playerIndex < MAX_PLAYERS; ++playerIndex ) { emptyCommandManager.PutUserCmdForPlayer( playerIndex, usercmd_t() ); } if ( IsClient() ) { game->ClientRunFrame( emptyCommandManager, false, emptyGameReturn ); } else { game->RunFrame( emptyCommandManager, emptyGameReturn ); } } renderSystem->EndLevelLoad(); soundSystem->EndLevelLoad(); declManager->EndLevelLoad(); uiManager->EndLevelLoad( currentMapName ); fileSystem->EndLevelLoad(); if ( !mapSpawnData.savegameFile && !IsMultiplayer() ) { common->Printf( "----- Running initial game frames -----\n" ); // In single player, run a bunch of frames to make sure ragdolls are settled idUserCmdMgr emptyCommandManager; gameReturn_t emptyGameReturn; for ( int i = 0; i < 100; i++ ) { for ( int playerIndex = 0; playerIndex < MAX_PLAYERS; ++playerIndex ) { emptyCommandManager.PutUserCmdForPlayer( playerIndex, usercmd_t() ); } game->RunFrame( emptyCommandManager, emptyGameReturn ); } // kick off an auto-save of the game (so we can always continue in this map if we die before hitting an autosave) common->Printf( "----- Saving Game -----\n" ); SaveGame( "autosave" ); } common->Printf( "----- Generating Interactions -----\n" ); // let the renderSystem generate interactions now that everything is spawned renderWorld->GenerateAllInteractions(); { int vertexMemUsedKB = vertexCache.staticData.vertexMemUsed.GetValue() / 1024; int indexMemUsedKB = vertexCache.staticData.indexMemUsed.GetValue() / 1024; idLib::Printf( "Used %dkb of static vertex memory (%d%%)\n", vertexMemUsedKB, vertexMemUsedKB * 100 / ( STATIC_VERTEX_MEMORY / 1024 ) ); idLib::Printf( "Used %dkb of static index memory (%d%%)\n", indexMemUsedKB, indexMemUsedKB * 100 / ( STATIC_INDEX_MEMORY / 1024 ) ); } if ( common->JapaneseCensorship() ) { if ( currentMapName.Icmp( "game/mp/d3xpdm3" ) == 0 ) { const idMaterial * gizpool2 = declManager->FindMaterial( "textures/hell/gizpool2" ); idMaterial * chiglass1bluex = const_cast<idMaterial *>( declManager->FindMaterial( "textures/sfx/chiglass1bluex" ) ); idTempArray<char> text( gizpool2->GetTextLength() ); gizpool2->GetText( text.Ptr() ); chiglass1bluex->Parse( text.Ptr(), text.Num(), false ); } } common->PrintWarnings(); session->Pump(); if ( session->GetState() != idSession::INGAME ) { // Something went wrong, don't process stale reliables that have been queued up. reliableQueue.Clear(); } usercmdGen->Clear(); // remove any prints from the notify lines console->ClearNotifyLines(); Sys_SetPhysicalWorkMemory( -1, -1 ); // at this point we should be done with the loading gui so we kill it delete loadGUI; loadGUI = NULL; // capture the current screen and start a wipe StartWipe( "wipe2Material" ); // we are valid for game draws now insideExecuteMapChange = false; mapSpawned = true; Sys_ClearEvents(); int msec = Sys_Milliseconds() - start; common->Printf( "%6d msec to load %s\n", msec, currentMapName.c_str() ); //Sys_DumpMemory( false ); // Issue a render at the very end of the load process to update soundTime before the first frame soundSystem->Render(); }
//----------------------------------------------------------------------------- // Purpose: the main loop for the dedicated server // Output : value to return to shell //----------------------------------------------------------------------------- DWORD WINAPI ServerThreadFunc( LPVOID threadobject ) { int iret = DLL_NORMAL; IDedicatedServerAPI *engineAPI; char cur[1024]; _getcwd(cur,1024); CSysModule *engineModule = NULL; CreateInterfaceFn engineFactory = NULL; while(iret!=DLL_CLOSE ) { //_chdir(UTIL_GetBaseDir()); vgui::filesystem()->Unmount(); engineModule = Sys_LoadModule( g_pszengine ); if ( !engineModule ) { goto cleanup; } engineFactory = Sys_GetFactory( engineModule ); if ( engineFactory ) { engineAPI = ( IDedicatedServerAPI * )engineFactory( VENGINE_HLDS_API_VERSION, NULL ); } if ( !engineAPI ) { goto cleanup; } server.SetEngineAPI(engineAPI); engineAPI->Init( UTIL_GetBaseDir(),server.GetCmdline(), Sys_GetFactoryThis() ); vgui::filesystem()->Mount(); if(strlen(server.GetCvars())>0) { engineAPI->AddConsoleText(server.GetCvars()); server.ResetCvars(); } while ( 1 ) { // Try to allow other apps to get some CPU Sys_Sleep( 1 ); // Check for shutdown event if ( !engineAPI->RunFrame() ) break; server.UpdateStatus( 0 ); } server.SetEngineAPI(NULL); server.SetInstance(NULL); iret = engineAPI->Shutdown(); Sys_UnloadModule( engineModule ); } // while(iret != DLL_CLOSE && gbAppHasBeenTerminated==FALSE ) cleanup: // this line is IMPORTANT! SetEvent(server.GetShutDownHandle()); // tell the main window we have shut down now //return 0; ExitThread(0); }
// Engage sleep mode void sleep() { Sys_SetWakeupSource(0x0f); Sys_Sleep(); }
int main ( int argc, char* argv[] ) { int i; char commandLine[ MAX_STRING_CHARS ] = { 0 }; Sys_PlatformInit(); CON_Init(); // get the initial time base Sys_Milliseconds(); #ifdef MACOS_X // This is passed if we are launched by double-clicking if ( argc >= 2 && Q_strncmp ( argv[1], "-psn", 4 ) == 0 ) argc = 1; #endif Sys_SetBinaryPath( Sys_Dirname( argv[ 0 ] ) ); Sys_SetDefaultInstallPath( DEFAULT_BASEDIR ); // Concatenate the command line for passing to Com_Init for( i = 1; i < argc; i++ ) { const bool containsSpaces = (strchr(argv[i], ' ') != NULL); if (containsSpaces) Q_strcat( commandLine, sizeof( commandLine ), "\"" ); Q_strcat( commandLine, sizeof( commandLine ), argv[ i ] ); if (containsSpaces) Q_strcat( commandLine, sizeof( commandLine ), "\"" ); Q_strcat( commandLine, sizeof( commandLine ), " " ); } Com_Init (commandLine); NET_Init(); // main game loop while (1) { bool shouldSleep = false; #if !defined(_JK2EXE) if ( com_dedicated->integer ) { shouldSleep = true; } #endif #if !defined(DEDICATED) if ( com_minimized->integer ) { shouldSleep = true; } #endif if ( shouldSleep ) { Sys_Sleep( 5 ); } // make sure mouse and joystick are only called once a frame IN_Frame(); // run the game Com_Frame(); } // never gets here return 0; }
void idSessionLocal::HandleNoteCommands( const char *menuCommand ) { guiActive = NULL; if ( idStr::Icmp( menuCommand, "note" ) == 0 && mapSpawned ) { idFile *file = NULL; for ( int tries = 0; tries < 10; tries++ ) { file = fileSystem->OpenExplicitFileRead( NOTEDATFILE ); if ( file != NULL ) { break; } Sys_Sleep( 500 ); } int noteNumber = 1000; if ( file ) { file->Read( ¬eNumber, 4 ); fileSystem->CloseFile( file ); } int i; idStr str, noteNum, shotName, workName, fileName = "viewnotes/"; idStrList fileList; const char *severity = NULL; const char *p = guiTakeNotes->State().GetString( "notefile" ); if ( p == NULL || *p == '\0' ) { p = cvarSystem->GetCVarString( "ui_name" ); } bool extended = guiTakeNotes->State().GetBool( "extended" ); if ( extended ) { if ( guiTakeNotes->State().GetInt( "severity" ) == 1 ) { severity = "WishList_Viewnotes/"; } else { severity = "MustFix_Viewnotes/"; } fileName += severity; const idDecl *mapDecl = declManager->FindType(DECL_ENTITYDEF, mapSpawnData.serverInfo.GetString( "si_map" ), false ); const idDeclEntityDef *mapInfo = static_cast<const idDeclEntityDef *>(mapDecl); if ( mapInfo ) { fileName += mapInfo->dict.GetString( "devname" ); } else { fileName += mapSpawnData.serverInfo.GetString( "si_map" ); fileName.StripFileExtension(); } int count = guiTakeNotes->State().GetInt( "person_numsel" ); if ( count == 0 ) { fileList.Append( fileName + "/Nobody" ); } else { for ( i = 0; i < count; i++ ) { int person = guiTakeNotes->State().GetInt( va( "person_sel_%i", i ) ); workName = fileName + "/"; workName += guiTakeNotes->State().GetString( va( "person_item_%i", person ), "Nobody" ); fileList.Append( workName ); } } } else { fileName += "maps/"; fileName += mapSpawnData.serverInfo.GetString( "si_map" ); fileName.StripFileExtension(); fileList.Append( fileName ); } bool bCon = cvarSystem->GetCVarBool( "con_noPrint" ); cvarSystem->SetCVarBool( "con_noPrint", true ); for ( i = 0; i < fileList.Num(); i++ ) { workName = fileList[i]; workName += "/"; workName += p; int workNote = noteNumber; R_ScreenshotFilename( workNote, workName, shotName ); noteNum = shotName; noteNum.StripPath(); noteNum.StripFileExtension(); if ( severity && *severity ) { workName = severity; workName += "viewNotes"; } sprintf( str, "recordViewNotes \"%s\" \"%s\" \"%s\"\n", workName.c_str(), noteNum.c_str(), guiTakeNotes->State().GetString( "note" ) ); cmdSystem->BufferCommandText( CMD_EXEC_NOW, str ); cmdSystem->ExecuteCommandBuffer(); UpdateScreen(); renderSystem->TakeScreenshot( renderSystem->GetScreenWidth(), renderSystem->GetScreenHeight(), shotName, 1, NULL ); } noteNumber++; for ( int tries = 0; tries < 10; tries++ ) { file = fileSystem->OpenExplicitFileWrite( "p:/viewnotes/notenumber.dat" ); if ( file != NULL ) { break; } Sys_Sleep( 500 ); } if ( file ) { file->Write( ¬eNumber, 4 ); fileSystem->CloseFile( file ); } cmdSystem->BufferCommandText( CMD_EXEC_NOW, "closeViewNotes\n" ); cvarSystem->SetCVarBool( "con_noPrint", bCon ); } }
/** * @sa Qcommon_Frame */ void NET_Wait (int timeout) { struct timeval tv; int ready; int i; fd_set read_fds_out; fd_set write_fds_out; memcpy(&read_fds_out, &read_fds, sizeof(read_fds_out)); memcpy(&write_fds_out, &write_fds, sizeof(write_fds_out)); /* select() won't notice that loopback streams are ready, so we'll * eliminate the delay directly */ if (loopback_ready) timeout = 0; tv.tv_sec = timeout / 1000; tv.tv_usec = 1000 * (timeout % 1000); #ifdef _WIN32 if (read_fds_out.fd_count == 0) { Sys_Sleep(timeout); ready = 0; } else #endif ready = select(maxfd, &read_fds_out, &write_fds_out, nullptr, &tv); if (ready == -1) { Com_Printf("select failed: %s\n", netStringError(netError)); return; } if (ready == 0 && !loopback_ready) return; if (server_socket != INVALID_SOCKET && FD_ISSET(server_socket, &read_fds_out)) { const SOCKET client_socket = accept(server_socket, nullptr, 0); if (client_socket == INVALID_SOCKET) { if (errno != EAGAIN) Com_Printf("accept on socket %d failed: %s\n", server_socket, netStringError(netError)); } else do_accept(client_socket); } for (i = 0; i < MAX_STREAMS; i++) { struct net_stream* s = streams[i]; if (!s) continue; if (s->loopback) { /* If the peer is gone and the buffer is empty, close the stream */ if (!s->loopback_peer && NET_StreamGetLength(s) == 0) { NET_StreamClose(s); } /* Note that s is potentially invalid after the callback returns - we'll close dead streams on the next pass */ else if (s->ready && s->func) { s->func(s); } continue; } if (s->socket == INVALID_SOCKET) continue; if (FD_ISSET(s->socket, &write_fds_out)) { char buf[4096]; int len; if (dbuffer_len(s->outbound) == 0) { FD_CLR(s->socket, &write_fds); /* Finished streams are closed when their outbound queues empty */ if (s->finished) NET_StreamClose(s); continue; } { const ScopedMutex scopedMutex(netMutex); len = s->outbound->get(buf, sizeof(buf)); len = send(s->socket, buf, len, 0); s->outbound->remove(len); } if (len < 0) { Com_Printf("write on socket %d failed: %s\n", s->socket, netStringError(netError)); NET_StreamClose(s); continue; } Com_DPrintf(DEBUG_SERVER, "wrote %d bytes to stream %d (%s)\n", len, i, NET_StreamPeerToName(s, buf, sizeof(buf), true)); } if (FD_ISSET(s->socket, &read_fds_out)) { char buf[4096]; const int len = recv(s->socket, buf, sizeof(buf), 0); if (len <= 0) { if (len == -1) Com_Printf("read on socket %d failed: %s\n", s->socket, netStringError(netError)); NET_StreamClose(s); continue; } else { if (s->inbound) { SDL_LockMutex(netMutex); s->inbound->add(buf, len); SDL_UnlockMutex(netMutex); Com_DPrintf(DEBUG_SERVER, "read %d bytes from stream %d (%s)\n", len, i, NET_StreamPeerToName(s, buf, sizeof(buf), true)); /* Note that s is potentially invalid after the callback returns */ if (s->func) s->func(s); continue; } } } } for (i = 0; i < MAX_DATAGRAM_SOCKETS; i++) { struct datagram_socket* s = datagram_sockets[i]; if (!s) continue; if (FD_ISSET(s->socket, &write_fds_out)) { if (s->queue) { struct datagram* dgram = s->queue; const int len = sendto(s->socket, dgram->msg, dgram->len, 0, (struct sockaddr* )dgram->addr, s->addrlen); if (len == -1) Com_Printf("sendto on socket %d failed: %s\n", s->socket, netStringError(netError)); /* Regardless of whether it worked, we don't retry datagrams */ s->queue = dgram->next; Mem_Free(dgram->msg); Mem_Free(dgram->addr); Mem_Free(dgram); if (!s->queue) s->queue_tail = &s->queue; } else { FD_CLR(s->socket, &write_fds); } } if (FD_ISSET(s->socket, &read_fds_out)) { char buf[256]; char addrbuf[256]; socklen_t addrlen = sizeof(addrbuf); const int len = recvfrom(s->socket, buf, sizeof(buf), 0, (struct sockaddr* )addrbuf, &addrlen); if (len == -1) Com_Printf("recvfrom on socket %d failed: %s\n", s->socket, netStringError(netError)); else s->func(s, buf, len, (struct sockaddr* )addrbuf); } } loopback_ready = false; }
void Cplm::mainLoop() { CStrOut message; int i = 0; // If a player left in the middle of hand, it might // happen that the pot still has money - if so, give // the chips here to the player if (!inGame_ && (table_->countPlayers(PLAYER_STATE_ACTIVE) < 2 || table_->numPlayersSittingIn() < 2 || CTournament::Inst()->pause())) { doCleanup(); Sys_Sleep(2000); if (!CTournament::Inst()->isTournament()) { // Players are sitting out CpduAnnounce pdu(table_); pdu.sendAnnounce("Waiting for players to sit in"); Sys_Sleep(2000); } return; } else { // The game thread function calls this repeatedly. // It only gets this far when there's enough players for a game. // First off, get the game number, and setLog all of the current players. memcpy((void*)¤tInstr_, pgl_->fetchInstr(), sizeof(pgl_instr_t)); switch (currentInstr_.opcode) { case (Instr_NOP): break; case (Instr_Deal): deal(); break; // Deal Cards To All Active Players case (Instr_Ante): // Do ANTE { table_->setGameNumber(); CpduGameNumber::SendGameNumber(table_); for (i = 0; i < 10; i++) { CPlayer* player = table_->getPlayerFromSlot(i); if (player) { message << CStrOut::Clear << "Seat " << i << ": " << player->getUsername() << " (" << player->getChips() << " in chips)"; table_->setLog(message.str()); } } ante(); } break; case (Instr_Draw): draw(); break; // Allow Players to Draw Cards case (Instr_Bet): bet(); break; // Do a betting Round case (Instr_Showdown): showdown(); break; // Do Showdown/Announce default: printf("Unknown operation %d!\n", (int)currentInstr_.opcode); break; } } }