void GhostEntity::updateStep() { const size_t runsize = ghostData.RunData.Count(); if (step < 0 || step >= runsize) { currentStep = nextStep = NULL; return; } currentStep = &ghostData.RunData[step]; float currentTime = ((float)Plat_FloatTime() - startTime); if (currentTime > currentStep->tim) {//catching up to a fast ghost, you came in late unsigned int x = step + 1; while (++x < runsize) { if (Q_strlen(ghostData.RunData[x].map) > 0) { Q_strcpy(currentMap, ghostData.RunData[x].map); } if (currentTime < ghostData.RunData[x].tim) { break; } } step = x - 1; } currentStep = &ghostData.RunData[step];//update it to the new step //here's where we can get current time: currentStep->tim GhostRun* thisrun = GhostEngine::getEngine()->getRun(this); GhostHud::hud()->UpdateGhost((size_t)thisrun, step, currentMap); currentTime = ((float)Plat_FloatTime() - startTime);//update to new time if (step == (runsize - 1)) {//if it's on the last step thisrun->EndRun(); } else { nextStep = &ghostData.RunData[step+1]; } }
/* ============= RunThreadsOn ============= */ void RunThreadsOn( int workcnt, qboolean showpacifier, RunThreadsFn fn, void *pUserData ) { int start, end; start = Plat_FloatTime(); dispatch = 0; workcount = workcnt; StartPacifier(""); pacifier = showpacifier; #ifdef _PROFILE threaded = false; (*func)( 0 ); return; #endif RunThreads_Start( fn, pUserData ); RunThreads_End(); end = Plat_FloatTime(); if (pacifier) { EndPacifier(false); printf (" (%i)\n", end-start); } }
//----------------------------------------------------------------------------- // Tests the process.cpp stuff //----------------------------------------------------------------------------- int main( int argc, char **argv ) { CommandLine()->CreateCmdLine( argc, argv ); InstallSpewFunction(); float flDelay = CommandLine()->ParmValue( "-delay", 0.0f ); const char *pEndMessage = CommandLine()->ParmValue( "-message", "Test Finished!\n" ); int nEndExtraBytes = CommandLine()->ParmValue( "-extrabytes", 0 ); if ( flDelay > 0.0f ) { float t = Plat_FloatTime(); while ( Plat_FloatTime() - t < flDelay ) { } } Msg( pEndMessage ); if ( nEndExtraBytes ) { while( --nEndExtraBytes >= 0 ) { Msg( "%c", ( nEndExtraBytes % 10 ) + '0' ); } } return 0; }
/* ============= FloodAreas Mark each leaf with an area, bounded by CONTENTS_AREAPORTAL ============= */ void FloodAreas (tree_t *tree) { int start = Plat_FloatTime(); qprintf ("--- FloodAreas ---\n"); Msg("Processing areas..."); FindAreas_r (tree->headnode); SetAreaPortalAreas_r (tree, tree->headnode); qprintf ("%5i areas\n", c_areas); Msg("done (%d)\n", (int)(Plat_FloatTime() - start) ); }
DETOUR_DECL_STATIC(void, S_Play, const char *pszName, bool flush) { std::lock_guard<std::mutex> lock(m_S_Play); LOGMEM("[%12.7f] BEGIN S_Play\n", Plat_FloatTime()); { SCOPED_INCREMENT(rc_S_Play); DETOUR_STATIC_CALL(S_Play)(pszName, flush); } LOGMEM("[%12.7f] END S_Play\n\n", Plat_FloatTime()); }
//----------------------------------------------------------------------------- // main application //----------------------------------------------------------------------------- void CVsVGuiWindow::PaintWindow() { if ( m_nCurrentTick == m_nLastRenderedTick || !g_pVGui->IsRunning() ) { ValidateRect( m_hWnd, NULL ); return; } m_nCurrentTick = m_nLastRenderedTick; vgui::VPANEL root = g_pVGuiSurface->GetEmbeddedPanel(); g_pVGuiSurface->Invalidate( root ); RECT windowRect; CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); ::GetClientRect( m_hWnd, &windowRect ); g_pMaterialSystem->SetView( m_hWnd ); pRenderContext->Viewport( 0, 0, windowRect.right, windowRect.bottom ); float flStartTime = Plat_FloatTime(); pRenderContext->ClearColor4ub( 76, 88, 68, 255 ); pRenderContext->ClearBuffers( true, true ); g_pMaterialSystem->BeginFrame( 0 ); // draw from the main panel down if ( m_hMainPanel.Get() ) { int w, h; m_hMainPanel->GetSize( w, h ); if ( w != windowRect.right || h != windowRect.bottom ) { m_hMainPanel->SetBounds( 0, 0, windowRect.right, windowRect.bottom ); m_hMainPanel->Repaint(); } g_pVGuiSurface->RestrictPaintToSinglePanel( m_hMainPanel->GetVPanel() ); g_pVGuiSurface->PaintTraverseEx( root, true ); g_pVGuiSurface->RestrictPaintToSinglePanel( 0 ); } g_pMaterialSystem->EndFrame(); g_pMaterialSystem->SwapBuffers(); g_pMaterialSystem->SetView( NULL ); ValidateRect( m_hWnd, NULL ); m_flRenderDelayTime = Plat_FloatTime() - flStartTime; m_flRenderDelayTime = max( m_flRenderDelayTime, 0.015f ); }
//----------------------------------------------------------------------------- // Runs the main loop. //----------------------------------------------------------------------------- void IGameManager::Start() { Assert( !m_bIsRunning && m_bIsInitialized ); m_bIsRunning = true; m_bStopRequested = false; // This option is useful when running the app twice on the same machine // It makes the 2nd instance of the app run a lot faster bool bPlayNice = ( CommandLine()->CheckParm( "-yieldcycles" ) != 0 ); float flStartTime = m_flCurrentTime = m_flLastTime = Plat_FloatTime(); int nFramesSimulated = 0; int nCount = m_GameManagers.Count(); while ( !m_bStopRequested ) { UpdateLevelStateMachine(); m_flLastTime = m_flCurrentTime; m_flCurrentTime = Plat_FloatTime(); int nSimulationFramesNeeded = 1 + (int)( ( m_flCurrentTime - flStartTime ) / TICK_INTERVAL ); while( nSimulationFramesNeeded > nFramesSimulated ) { for ( int i = 0; i < nCount; ++i ) { if ( m_GameManagers[i]->PerformsSimulation() ) { m_GameManagers[i]->Update(); } } ++m_nFrameNumber; ++nFramesSimulated; } // Always do I/O related managers regardless of framerate for ( int i = 0; i < nCount; ++i ) { if ( !m_GameManagers[i]->PerformsSimulation() ) { m_GameManagers[i]->Update(); } } if ( bPlayNice ) { Sleep( 1 ); } } m_bIsRunning = false; }
//----------------------------------------------------------------------------- // Purpose: Called when it's time for a physically moved objects (plats, doors, etc) // to run it's game code. // All other entity thinking is done during worldspawn's think //----------------------------------------------------------------------------- void C_BaseEntity::PhysicsDispatchThink( BASEPTR thinkFunc ) { float thinkLimit = think_limit.GetFloat(); float startTime = 0.0; /* // This doesn't apply on the client, really if ( IsDormant() ) { Warning( "Dormant entity %s is thinking!!\n", GetClassname() ); Assert(0); } */ if ( thinkLimit ) { startTime = Plat_FloatTime(); } if ( thinkFunc ) { (this->*thinkFunc)(); } if ( thinkLimit ) { // calculate running time of the AI in milliseconds float time = ( Plat_FloatTime() - startTime ) * 1000.0f; if ( time > thinkLimit ) { #if 0 // If its an NPC print out the shedule/task that took so long CAI_BaseNPC *pNPC = MyNPCPointer(); if (pNPC && pNPC->GetCurSchedule()) { pNPC->ReportOverThinkLimit( time ); } else #endif { #ifdef WIN32 Msg( "CLIENT: %s(%s) thinking for %.02f ms!!!\n", GetClassname(), typeid(this).raw_name(), time ); #else Msg( "CLIENT: %s(%s) thinking for %.02f ms!!!\n", GetClassname(), typeid(this).name(), time ); #endif } } } }
//----------------------------------------------------------------------------- // Purpose: Called when it's time for a physically moved objects (plats, doors, etc) // to run it's game code. // All other entity thinking is done during worldspawn's think //----------------------------------------------------------------------------- void C_BaseEntity::PhysicsPyDispatchThink( bp::object thinkFunc ) { float thinkLimit = think_limit.GetFloat(); float startTime = 0.0; /* // This doesn't apply on the client, really if ( IsDormant() ) { Warning( "Dormant entity %s is thinking!!\n", GetClassname() ); Assert(0); } */ if ( thinkLimit ) { startTime = Plat_FloatTime(); } if ( thinkFunc.ptr() != Py_None ) { try { thinkFunc(); } catch(boost::python::error_already_set &) { PyErr_Print(); } } if ( thinkLimit ) { // calculate running time of the AI in milliseconds float time = ( Plat_FloatTime() - startTime ) * 1000.0f; if ( time > thinkLimit ) { #if 0 // If its an NPC print out the shedule/task that took so long CAI_BaseNPC *pNPC = MyNPCPointer(); if (pNPC && pNPC->GetCurSchedule()) { pNPC->ReportOverThinkLimit( time ); } else #endif { Msg( "CLIENT: %s(%s) thinking for %.02f ms!!!\n", GetClassname(), typeid(this).raw_name(), time ); } } } }
// This tracks a list void AddServicesBrowserIP( const CIPAddr &ipFrom ) { for ( int i=0; i < g_ServicesBrowsers.Count(); i++ ) { if ( g_ServicesBrowsers[i].m_Addr == ipFrom ) { g_ServicesBrowsers[i].m_flLastPingTime = Plat_FloatTime(); return; } } CServicesBrowserInfo info; info.m_Addr = ipFrom; info.m_flLastPingTime = Plat_FloatTime(); g_ServicesBrowsers.AddToTail( info ); }
void BaseTimedTester::ProcessTests() { if((Plat_FloatTime() - m_lastTestDone) < m_jobMinPeriod) return; m_lastTestDone = Plat_FloatTime(); PlayerHandler* h = nullptr; for(int x = 1; x <= MAX_PLAYERS; ++x) { h = NczPlayerManager::GetInstance()->GetPlayerHandlerByIndex(x); if(h->status == GetFilter()) { ProcessPlayerTest(h->playerClass); } } }
void HandlePacket_KILL_PROCESS( const CIPAddr *ipFrom ) { if ( Plat_FloatTime() - g_flLastKillProcessTime > 5 ) { KillRunningProcess( "Got a KILL_PROCESS packet. Stopping the worker executable.\n", true ); if ( ipFrom ) { AddServicesBrowserIP( *ipFrom ); SendStateToServicesBrowsers(); } g_flLastKillProcessTime = Plat_FloatTime(); } }
virtual void UpdateBenchmark() { // No benchmark running? if ( m_BenchmarkState == BENCHMARKSTATE_NOT_RUNNING ) return; // Wait a certain number of ticks to start the benchmark. if ( m_BenchmarkState == BENCHMARKSTATE_START_WAIT ) { if ( (Plat_FloatTime() - m_flBenchmarkStartTime) < m_flBenchmarkStartWaitTime ) { UpdateStartWaitCounter(); return; } else { // Ok, now we're officially starting it. Msg( "Starting benchmark!\n" ); m_flLastBenchmarkCounterUpdate = m_flBenchmarkStartTime = Plat_FloatTime(); m_fl_ValidTime_BenchmarkStartTime = Benchmark_ValidTime(); m_nBenchmarkStartTick = gpGlobals->tickcount; m_nLastPhysicsObjectTick = m_nLastPhysicsForceTick = 0; m_BenchmarkState = BENCHMARKSTATE_RUNNING; StartVProfRecord(); RandomSeed( 0 ); m_RandomStream.SetSeed( 0 ); } } int nTicksRunSoFar = gpGlobals->tickcount - m_nBenchmarkStartTick; UpdateBenchmarkCounter(); // Are we finished with the benchmark? if ( nTicksRunSoFar >= sv_benchmark_numticks.GetInt() ) { EndVProfRecord(); OutputResults(); EndBenchmark(); return; } // Ok, update whatever we're doing in the benchmark. UpdatePlayerCreation(); UpdateVPhysicsObjects(); CServerBenchmarkHook::s_pBenchmarkHook->UpdateBenchmark(); }
// nBenchmarkMode: 0 = no benchmark // 1 = benchmark // 2 = exit out afterwards and write sv_benchmark.txt bool InternalStartBenchmark( int nBenchmarkMode, float flCountdown ) { bool bWasRunningBenchmark = (m_BenchmarkState != BENCHMARKSTATE_NOT_RUNNING); if ( nBenchmarkMode == 0 ) { // Tear down the previous benchmark environment if necessary. if ( bWasRunningBenchmark ) EndBenchmark(); return false; } m_nBenchmarkMode = nBenchmarkMode; if ( !CServerBenchmarkHook::s_pBenchmarkHook ) Error( "This game doesn't support server benchmarks (no CServerBenchmarkHook found)." ); m_BenchmarkState = BENCHMARKSTATE_START_WAIT; m_flBenchmarkStartTime = Plat_FloatTime(); m_flBenchmarkStartWaitTime = flCountdown; m_nBotsCreated = 0; m_nStartWaitCounter = -1; // Setup the benchmark environment. engine->SetDedicatedServerBenchmarkMode( true ); // Run 1 tick per frame and ignore all timing stuff. // Tell the game-specific hook that we're starting. CServerBenchmarkHook::s_pBenchmarkHook->StartBenchmark(); CServerBenchmarkHook::s_pBenchmarkHook->GetPhysicsModelNames( m_PhysicsModelNames ); return true; }
DETOUR_DECL_MEMBER(void *, IMemAlloc_Realloc, void *pMem, size_t nSize) { std::lock_guard<std::mutex> lock(m_Realloc); SCOPED_INCREMENT(rc_Realloc); auto result = DETOUR_MEMBER_CALL(IMemAlloc_Realloc)(pMem, nSize); if (mem_tracking && rc_Realloc <= 1 && nSize >= cvar_minimum.GetInt()) { auto it = mems.find(pMem); if (it != mems.end()) { mems.erase(it); if (mems.find(result) == mems.end()) { LOGMEM("[%12.7f] Realloc %7u 0x%08x => 0x%08x\n", Plat_FloatTime(), nSize, (uintptr_t)pMem, (uintptr_t)result); mems[result] = nSize; } else { Warning("IMemAlloc::Realloc: pointer already in map!\n"); } } else { // Warning("IMemAlloc::Realloc: reallocation of untracked pointer!\n"); } // if (cvar_realloc.GetBool()) { // LOGMEM("[%12.7f] Realloc %7u 0x%08x => 0x%08x\n", Plat_FloatTime(), nSize, (uintptr_t)pMem, (uintptr_t)result); // } } return result; }
//--------------------------------------------------------------------------------- // Purpose: called when a client spawns into a server (i.e as they begin to play) //--------------------------------------------------------------------------------- void CNoCheatZPlugin::ClientActive( edict_t *pEntity ) { Msg("%f : CNoCheatZPlugin::ClientActive\n", Plat_FloatTime()); NczPlayerManager::GetInstance()->ClientActive(pEntity); PlayerHandler* ph = NczPlayerManager::GetInstance()->GetPlayerHandlerByEdict(pEntity); if(ph->status > BOT) HookBasePlayer(ph->playerClass); }
//----------------------------------------------------------------------------- // Purpose: called when an event that counts toward an achievement occurs //----------------------------------------------------------------------------- void CBaseAchievement::IncrementCount() { if ( !IsAchieved() ) { if ( !m_pAchievementMgr->CheckAchievementsEnabled() ) { Msg( "Achievements disabled, ignoring achievement progress for %s\n", GetName() ); return; } // on client, where the count is kept, increment count m_iCount++; // if this achievement gets saved w/global state, flag our global state as dirty if ( GetFlags() & ACH_SAVE_GLOBAL ) { m_pAchievementMgr->SetDirty( true ); } if ( cc_achievement_debug.GetInt() ) { Msg( "Achievement count increased for %s: %d/%d\n", GetName(), m_iCount, m_iGoal ); } // if this achievement's progress should be stored in Steam, set the steam stat for it if ( StoreProgressInSteam() && steamapicontext->SteamUserStats() ) { // Set the Steam stat with the same name as the achievement. Only cached locally until we upload it. char pszProgressName[1024]; Q_snprintf( pszProgressName, 1024, "%s_STAT", GetName() ); bool bRet = steamapicontext->SteamUserStats()->SetStat( CGameID( engine->GetAppID() ), pszProgressName, m_iCount ); if ( !bRet ) { DevMsg( "ISteamUserStats::GetStat failed to set progress value in Steam for achievement %s\n", pszProgressName ); } // Upload user data to commit the change to Steam so if the client crashes, progress isn't lost. // Only upload if we haven't uploaded recently, to keep us from spamming Steam with uploads. If we don't // upload now, it will get uploaded no later than level shutdown. if ( ( m_pAchievementMgr->GetTimeLastUpload() == 0 ) || ( Plat_FloatTime() - m_pAchievementMgr->GetTimeLastUpload() > 60 * 15 ) ) { m_pAchievementMgr->UploadUserData(); } } // if we've hit goal, award the achievement if ( m_iGoal > 0 ) { if ( m_iCount >= m_iGoal ) { AwardAchievement(); } else { HandleProgressUpdate(); } } } }
void SignalGlobalUpdate(void) { float stamp=Plat_FloatTime(); for(int i=0;i<NELEMS(g_EventTimes);i++) { g_EventTimes[i] = stamp; g_EventTimeCounters[i]++; } }
static double Benchmark_ValidTime() { bool bOld = Plat_IsInBenchmarkMode(); Plat_SetBenchmarkMode( false ); double flRet = Plat_FloatTime(); Plat_SetBenchmarkMode( bOld ); return flRet; }
void UpdateBenchmarkCounter() { float flCurTime = Plat_FloatTime(); if ( (flCurTime - m_flLastBenchmarkCounterUpdate) > 3.0f ) { m_flLastBenchmarkCounterUpdate = flCurTime; Msg( "Benchmark: %d%% complete.\n", ((gpGlobals->tickcount - m_nBenchmarkStartTick) * 100) / sv_benchmark_numticks.GetInt() ); } }
void AddJobMemory( int id[4] ) { TimeoutJobIDs(); CJobMemory job; memcpy( job.m_ID, id, sizeof( job.m_ID ) ); job.m_Time = Plat_FloatTime(); g_JobMemories.AddToTail( job ); }
void UpdateStartWaitCounter() { int nSecondsLeft = (int)ceil( m_flBenchmarkStartWaitTime - (Plat_FloatTime() - m_flBenchmarkStartTime) ); if ( m_nStartWaitCounter != nSecondsLeft ) { Msg( "Starting benchmark in %d seconds...\n", nSecondsLeft ); m_nStartWaitCounter = nSecondsLeft; } }
static cell_t GetEngineTime(IPluginContext *pContext, const cell_t *params) { #if SOURCE_ENGINE >= SE_NUCLEARDAWN float fTime = Plat_FloatTime(); #else float fTime = engine->Time(); #endif return sp_ftoc(fTime); }
bool CAddr_Sym_Regex::FindAddrLinux(uintptr_t& addr) const { float t1 = Plat_FloatTime(); auto results = LibMgr::FindSymRegex(this->GetLibrary(), this->GetSymbol()); float t2 = Plat_FloatTime(); ConColorMsg(Color(0xff, 0x00, 0xff, 0xff), "Regex lookup for \"%s\" \"%s\": %.3f ms\n", this->GetName(), this->GetSymbol(), (t2 - t1) * 1000.0f); bool success = std::get<0>(results); std::string& name = std::get<1>(results); void *sym_addr = std::get<2>(results); if (!success || sym_addr == nullptr) { return false; } addr = (uintptr_t)sym_addr; return true; }
//----------------------------------------------------------------------------- // Purpose: Build faces for the detail brushes and merge them into the BSP // Input : *worldtree - // brush_start - // brush_end - //----------------------------------------------------------------------------- face_t *MergeDetailTree( tree_t *worldtree, int brush_start, int brush_end ) { int start; bspbrush_t *detailbrushes = NULL; tree_t *detailtree = NULL; face_t *pFaces = NULL; face_t *pLeafFaceList = NULL; // Grab the list of detail brushes detailbrushes = MakeBspBrushList (brush_start, brush_end, map_mins, map_maxs, ONLY_DETAIL ); if (detailbrushes) { start = Plat_FloatTime(); Msg("Chop Details..."); // if there are detail brushes, chop them against each other if (!nocsg) detailbrushes = ChopBrushes (detailbrushes); Msg("done (%d)\n", (int)(Plat_FloatTime() - start) ); // Now mark the visible sides so we can eliminate all detail brush sides // that are covered by other detail brush sides // NOTE: This still leaves detail brush sides that are covered by the world. (these are removed in the merge operation) Msg("Find Visible Detail Sides..."); pFaces = ComputeVisibleBrushSides( detailbrushes ); TryMergeFaceList( &pFaces ); SubdivideFaceList( &pFaces ); Msg("done (%d)\n", (int)(Plat_FloatTime() - start) ); start = Plat_FloatTime(); Msg("Merging details..."); // Merge the detail solids and faces into the world tree // Merge all of the faces into the world tree pLeafFaceList = FilterFacesIntoTree( worldtree, pFaces ); FilterBrushesIntoTree( worldtree, detailbrushes ); FreeFaceList( pFaces ); FreeBrushList(detailbrushes); Msg("done (%d)\n", (int)(Plat_FloatTime() - start) ); } return pLeafFaceList; }
void CStatusWindow::StatusPrint( int r, int g, int b, bool overwrite, const char *text ) { float curtime = (float)Plat_FloatTime(); char sz[32]; sprintf( sz, "%.3f ", curtime ); OutputDebugString( sz ); OutputDebugString( text ); char fixedtext[ 512 ]; char *in, *out; in = (char *)text; out = fixedtext; int c = 0; while ( *in && c < 511 ) { if ( *in == '\n' || *in == '\r' ) { *in++; } else { *out++ = *in++; c++; } } *out = 0; if ( overwrite ) { m_nCurrentLine--; } int i = m_nCurrentLine & TEXT_LINE_MASK; strncpy( m_rgTextLines[ i ].m_szText, fixedtext, 511 ); m_rgTextLines[ i ].m_szText[ 511 ] = 0; m_rgTextLines[ i ].r = r; m_rgTextLines[ i ].g = g; m_rgTextLines[ i ].b = b; m_rgTextLines[ i ].curtime = curtime; m_nCurrentLine++; if ( m_nCurrentLine <= MAX_TEXT_LINES ) { PositionSliders( 0 ); } m_pScrollbar->setValue( m_pScrollbar->getMaxValue() ); redraw(); }
void C_Prop_Hallucination::OnDataChanged( DataUpdateType_t type ) { if( !m_bEnabled ) { if( m_bVisibleEligible && (m_fLastStateChangeTime != 0.0f) ) { m_fLastStateChangeTime = Plat_FloatTime(); } m_bVisibleEligible = false; } }
static void Graphical_WorkUnitCompleted( int iWorkUnit ) { if ( !g_bUseGraphics ) return; EnterCriticalSection( &g_CS ); g_WUStatus[iWorkUnit].m_iState = 4; g_WUStatus[iWorkUnit].m_flTransitionTime = Plat_FloatTime() + 0.1f; ++g_nChanges; LeaveCriticalSection( &g_CS ); }
double BaseTimedTester::GetTesterTime() const { /*if(this->m_timeBase == GAME) { return (double)(CIFaceManager::GetInstance()->GetIengine()->Time()); } else { return Plat_FloatTime(); }*/ return Plat_FloatTime(); }
void CMOD_Build_Map_Frame::OnThink() { BaseClass::OnThink(); if ( m_pMapBuilder ) { m_pMapBuilder->Update( Plat_FloatTime() ); } UpdateProgress(); if (m_fCloseWindowTime > 0 && m_fCloseWindowTime <= Plat_FloatTime()) { // tell the engine we've finished compiling the map, so it can continue connecting to a remote server engine->ClientCmd( "asw_engine_finished_building_map" ); /* if ( m_pMapBuilder ) { if ( m_bEditMapAfterBuild ) { char buffer[512]; Q_snprintf(buffer, sizeof(buffer), "progress_enable\nmap %s edit %s\n", m_pMapBuilder->GetMapName(), m_szMapEditFilename ); m_pMapBuilder = NULL; engine->ClientCmd(buffer); } else if ( m_bRunMapAfterBuild ) { char buffer[512]; Q_snprintf(buffer, sizeof(buffer), "progress_enable\nmap %s\n", m_pMapBuilder->GetMapName() ); m_pMapBuilder = NULL; engine->ClientCmd(buffer); } } */ OnClose(); m_fCloseWindowTime = 0; } }