@@ -56,7 +56,7 @@ static HMODULE WINAPI SkipDirectPlay_LoadLibraryA(LPCSTR fileName)
5656    if  (!StrCmpIA (" enbseries\\ enbhelper.dll"  , fileName))
5757    {
5858        std::error_code ec;
59-          
59+ 
6060        //  Try to load enbhelper.dll from our custom launch directory first.
6161        const  fs::path inLaunchDir = fs::path{FromUTF8 (GetLaunchPath ())} / " enbseries"   / " enbhelper.dll"  ;
6262
@@ -146,18 +146,16 @@ CCore::CCore()
146146    //  Setup our hooks.
147147    ApplyHooks ();
148148
149-     //  No initial fps limit
150-     m_bDoneFrameRateLimit = false ;
151-     m_uiFrameRateLimit = 0 ;
152-     m_uiServerFrameRateLimit = 0 ;
153149    m_iUnminimizeFrameCounter = 0 ;
154150    m_bDidRecreateRenderTargets = false ;
155151    m_fMinStreamingMemory = 0 ;
156152    m_fMaxStreamingMemory = 0 ;
157153    m_bGettingIdleCallsFromMultiplayer = false ;
158154    m_bWindowsTimerEnabled = false ;
159155    m_timeDiscordAppLastUpdate = 0 ;
160-     m_CurrentRefreshRate = 60 ;
156+ 
157+     //  Initialize FPS limiter
158+     m_pFPSLimiter = std::make_unique<FPSLimiter::FPSLimiter>();
161159
162160    //  Create tray icon
163161    m_pTrayIcon = new  CTrayIcon ();
@@ -180,6 +178,8 @@ CCore::~CCore()
180178    //  Destroy tray icon
181179    delete  m_pTrayIcon;
182180
181+     m_pFPSLimiter.reset ();
182+ 
183183    //  This will set the GTA volume to the GTA volume value in the settings,
184184    //  and is not affected by the master volume setting.
185185    m_pLocalGUI->GetMainMenu ()->GetSettingsWindow ()->ResetGTAVolume ();
@@ -1347,7 +1347,7 @@ void CCore::OnModUnload()
13471347    m_pKeyBinds->RemoveAllControlFunctions ();
13481348
13491349    //  Reset client script frame rate limit
1350-     m_uiClientScriptFrameRateLimit =  0 ;
1350+     GetFPSLimiter ()-> SetClientEnforcedFPS (FPSLimits::FPS_UNLIMITED) ;
13511351
13521352    //  Clear web whitelist
13531353    if  (m_pWebCore)
@@ -1772,8 +1772,8 @@ void CCore::OnPostColorFilterRender()
17721772{
17731773    if  (!CGraphics::GetSingleton ().HasLine3DPostFXQueueItems () && !CGraphics::GetSingleton ().HasPrimitive3DPostFXQueueItems ())
17741774        return ;
1775-      
1776-     CGraphics::GetSingleton ().EnteringMTARenderZone ();       
1775+ 
1776+     CGraphics::GetSingleton ().EnteringMTARenderZone ();
17771777
17781778    CGraphics::GetSingleton ().DrawPrimitive3DPostFXQueue ();
17791779    CGraphics::GetSingleton ().DrawLine3DPostFXQueue ();
@@ -1831,141 +1831,14 @@ void CCore::ApplyCoreInitSettings()
18311831// 
18321832void  CCore::OnGameTimerUpdate ()
18331833{
1834-     ApplyQueuedFrameRateLimit ();
1834+     //  NOTE: (pxd) We are handling the frame limiting updates
1835+     //  earlier in the callpath (CModManager::DoPulsePreFrame, CModManager::DoPulsePostFrame)
18351836}
18361837
1837- // 
1838- //  Recalculate FPS limit to use
1839- // 
1840- //  Uses client rate from config
1841- //  Uses client rate from script
1842- //  Uses server rate from argument, or last time if not supplied
1843- // 
1844- void  CCore::RecalculateFrameRateLimit (uint uiServerFrameRateLimit, bool  bLogToConsole)
1838+ void  CCore::OnFPSLimitChange (std::uint16_t  fps)
18451839{
1846-     //  Save rate from server if valid
1847-     if  (uiServerFrameRateLimit != -1 )
1848-         m_uiServerFrameRateLimit = uiServerFrameRateLimit;
1849- 
1850-     //  Start with value set by the server
1851-     m_uiFrameRateLimit = m_uiServerFrameRateLimit;
1852- 
1853-     //  Apply client config setting
1854-     uint uiClientConfigRate;
1855-     g_pCore->GetCVars ()->Get (" fps_limit"  , uiClientConfigRate);
1856-     if  (uiClientConfigRate > 0 )
1857-         uiClientConfigRate = std::max (45U , uiClientConfigRate);
1858-     //  Lowest wins (Although zero is highest)
1859-     if  ((m_uiFrameRateLimit == 0  || uiClientConfigRate < m_uiFrameRateLimit) && uiClientConfigRate > 0 )
1860-         m_uiFrameRateLimit = uiClientConfigRate;
1861- 
1862-     //  Apply client script setting
1863-     uint uiClientScriptRate = m_uiClientScriptFrameRateLimit;
1864-     //  Lowest wins (Although zero is highest)
1865-     if  ((m_uiFrameRateLimit == 0  || uiClientScriptRate < m_uiFrameRateLimit) && uiClientScriptRate > 0 )
1866-         m_uiFrameRateLimit = uiClientScriptRate;
1867- 
1868-     if  (!IsConnected ())
1869-         m_uiFrameRateLimit = m_CurrentRefreshRate;
1870- 
1871-     //  Removes Limiter from Frame Graph if limit is zero and skips frame limit
1872-     if  (m_uiFrameRateLimit == 0 )
1873-     {
1874-         m_bQueuedFrameRateValid = false ;
1875-         GetGraphStats ()->RemoveTimingPoint (" Limiter"  );
1876-     }
1877- 
1878-     //  Print new limits to the console
1879-     if  (bLogToConsole)
1880-     {
1881-         SString strStatus (" Server FPS limit: %d"  , m_uiServerFrameRateLimit);
1882-         if  (m_uiFrameRateLimit != m_uiServerFrameRateLimit)
1883-             strStatus += SString ("  (Using %d)"  , m_uiFrameRateLimit);
1884-         CCore::GetSingleton ().GetConsole ()->Print (strStatus);
1885-     }
1886- }
1887- 
1888- // 
1889- //  Change client rate as set by script
1890- // 
1891- void  CCore::SetClientScriptFrameRateLimit (uint uiClientScriptFrameRateLimit)
1892- {
1893-     m_uiClientScriptFrameRateLimit = uiClientScriptFrameRateLimit;
1894-     RecalculateFrameRateLimit (-1 , false );
1895- }
1896- 
1897- void  CCore::SetCurrentRefreshRate (uint value)
1898- {
1899-     m_CurrentRefreshRate = value;
1900-     RecalculateFrameRateLimit (-1 , false );
1901- }
1902- 
1903- // 
1904- //  Make sure the frame rate limit has been applied since the last call
1905- // 
1906- void  CCore::EnsureFrameRateLimitApplied ()
1907- {
1908-     if  (!m_bDoneFrameRateLimit)
1909-     {
1910-         ApplyFrameRateLimit ();
1911-     }
1912-     m_bDoneFrameRateLimit = false ;
1913- }
1914- 
1915- // 
1916- //  Do FPS limiting
1917- // 
1918- //  This is called once a frame even if minimized
1919- // 
1920- void  CCore::ApplyFrameRateLimit (uint uiOverrideRate)
1921- {
1922-     TIMING_CHECKPOINT (" -CallIdle1"  );
1923-     ms_TimingCheckpoints.EndTimingCheckpoints ();
1924- 
1925-     //  Frame rate limit stuff starts here
1926-     m_bDoneFrameRateLimit = true ;
1927- 
1928-     uint uiUseRate = uiOverrideRate != -1  ? uiOverrideRate : m_uiFrameRateLimit;
1929- 
1930-     if  (uiUseRate > 0 )
1931-     {
1932-         //  Apply previous frame rate if is hasn't been done yet
1933-         ApplyQueuedFrameRateLimit ();
1934- 
1935-         //  Limit is usually applied in OnGameTimerUpdate
1936-         m_uiQueuedFrameRate = uiUseRate;
1937-         m_bQueuedFrameRateValid = true ;
1938-     }
1939- 
1940-     DoReliablePulse ();
1941- 
1942-     TIMING_GRAPH (" FrameEnd"  );
1943-     TIMING_GRAPH (" "  );
1944- }
1945- 
1946- // 
1947- //  Frame rate limit (wait) is done here.
1948- // 
1949- void  CCore::ApplyQueuedFrameRateLimit ()
1950- {
1951-     if  (m_bQueuedFrameRateValid)
1952-     {
1953-         m_bQueuedFrameRateValid = false ;
1954-         //  Calc required time in ms between frames
1955-         const  double  dTargetTimeToUse = 1000.0  / m_uiQueuedFrameRate;
1956- 
1957-         while  (true )
1958-         {
1959-             //  See if we need to wait
1960-             double  dSpare = dTargetTimeToUse - m_FrameRateTimer.Get ();
1961-             if  (dSpare <= 0.0 )
1962-                 break ;
1963-             if  (dSpare >= 10.0 )
1964-                 Sleep (1 );
1965-         }
1966-         m_FrameRateTimer.Reset ();
1967-         TIMING_GRAPH (" Limiter"  );
1968-     }
1840+     if  (m_pNet != nullptr )            //  We have to wait for the network module to be loaded
1841+         GetWebCore ()->OnFPSLimitChange (fps);
19691842}
19701843
19711844// 
@@ -2020,7 +1893,7 @@ void CCore::OnDeviceRestore()
20201893void  CCore::OnPreFxRender ()
20211894{
20221895    if  (!CGraphics::GetSingleton ().HasLine3DPreGUIQueueItems () && !CGraphics::GetSingleton ().HasPrimitive3DPreGUIQueueItems ())
2023-         return ;     
1896+         return ;
20241897
20251898    CGraphics::GetSingleton ().EnteringMTARenderZone ();
20261899
@@ -2035,7 +1908,7 @@ void CCore::OnPreFxRender()
20351908// 
20361909void  CCore::OnPreHUDRender ()
20371910{
2038-     CGraphics::GetSingleton ().EnteringMTARenderZone ();     
1911+     CGraphics::GetSingleton ().EnteringMTARenderZone ();
20391912
20401913    //  Maybe capture screen and other stuff
20411914    CGraphics::GetSingleton ().GetRenderItemManager ()->DoPulse ();
@@ -2396,7 +2269,8 @@ SString CCore::GetBlueCopyrightString()
23962269
23972270//  Set streaming memory size override [See `engineStreamingSetMemorySize`]
23982271//  Use `0` to turn it off, and thus restore the value to the `cvar` setting
2399- void  CCore::SetCustomStreamingMemory (size_t  sizeBytes) {
2272+ void  CCore::SetCustomStreamingMemory (size_t  sizeBytes)
2273+ {
24002274    //  NOTE: The override is applied to the game in `CClientGame::DoPulsePostFrame`
24012275    //  There's no specific reason we couldn't do it here, but we wont
24022276    m_CustomStreamingMemoryLimitBytes = sizeBytes;
0 commit comments