Skip to content

Commit e022dc5

Browse files
authored
bugfix(fps): Fix and improve logic time step and render update decoupling (#1528)
1 parent 5eaa6aa commit e022dc5

File tree

58 files changed

+760
-500
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+760
-500
lines changed

Core/GameEngine/Include/Common/GameDefines.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
#pragma once
2020

21+
#include "WWDefines.h"
22+
2123
// Note: Retail compatibility must not be broken before this project officially does.
2224
// Use RETAIL_COMPATIBLE_CRC and RETAIL_COMPATIBLE_XFER_SAVE to guard breaking changes.
2325

Core/Libraries/Source/WWVegas/WWLib/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ set(WWLIB_SRC
133133
widestring.h
134134
win.h
135135
WWCommon.h
136+
WWDefines.h
136137
wwfile.cpp
137138
WWFILE.H
138139
wwstring.cpp

Core/Libraries/Source/WWVegas/WWLib/WWCommon.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
#pragma once
2020

21-
#include <stringex.h>
21+
#include "stringex.h"
2222

2323
#if defined(_MSC_VER) && _MSC_VER < 1300
2424
typedef unsigned MemValueType;
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*
2+
** Command & Conquer Generals Zero Hour(tm)
3+
** Copyright 2025 TheSuperHackers
4+
**
5+
** This program is free software: you can redistribute it and/or modify
6+
** it under the terms of the GNU General Public License as published by
7+
** the Free Software Foundation, either version 3 of the License, or
8+
** (at your option) any later version.
9+
**
10+
** This program is distributed in the hope that it will be useful,
11+
** but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
** GNU General Public License for more details.
14+
**
15+
** You should have received a copy of the GNU General Public License
16+
** along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
*/
18+
19+
#pragma once
20+
21+
// The WW3D Sync time. This was originally 33 ms, ~30 fps, integer.
22+
// Changing or removing this will require tweaking all Drawable code that concerns logic time step, including locomotion physics.
23+
#ifndef MSEC_PER_WWSYNC_FRAME
24+
#define MSEC_PER_WWSYNC_FRAME (33)
25+
#endif

Core/Libraries/Source/WWVegas/WWLib/always.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
#define ALWAYS_H
4242

4343
#include "WWCommon.h"
44+
#include "WWDefines.h"
4445

4546
#include <assert.h>
4647
#include <new>

Generals/Code/GameEngine/Include/Common/GameEngine.h

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,16 @@ class Radar;
5353
class WebBrowser;
5454
class ParticleSystemManager;
5555

56-
/**
57-
* The implementation of the game engine
58-
*/
5956
class GameEngine : public SubsystemInterface
6057
{
58+
public:
59+
60+
typedef UnsignedInt LogicTimeQueryFlags;
61+
enum LogicTimeQueryFlags_ CPP_11(: LogicTimeQueryFlags)
62+
{
63+
IgnoreFrozenTime = 1<<0, // Ignore frozen time for the query
64+
IgnoreHaltedGame = 1<<1, // Ignore halted game for the query
65+
};
6166

6267
public:
6368

@@ -76,13 +81,18 @@ class GameEngine : public SubsystemInterface
7681
Real getUpdateTime(); ///< Get the last engine update delta time.
7782
Real getUpdateFps(); ///< Get the last engine update fps.
7883

84+
static Bool isTimeFrozen(); ///< Returns true if a script has frozen time.
85+
static Bool isGameHalted(); ///< Returns true if the game is paused or the network is stalling.
86+
7987
virtual void setLogicTimeScaleFps( Int fps ); ///< Set the logic time scale fps and therefore scale the simulation time. Is capped by the max render fps and does not apply to network matches.
8088
virtual Int getLogicTimeScaleFps(); ///< Get the raw logic time scale fps value.
8189
virtual void enableLogicTimeScale( Bool enable ); ///< Enable the logic time scale setup. If disabled, the simulation time scale is bound to the render frame time or network update time.
8290
virtual Bool isLogicTimeScaleEnabled(); ///< Check whether the logic time scale setup is enabled.
83-
Int getActualLogicTimeScaleFps(); ///< Get the real logic time scale fps, depending on the max render fps, network state and enabled state.
84-
Real getActualLogicTimeScaleRatio(); ///< Get the real logic time scale ratio, depending on the max render fps, network state and enabled state.
85-
Real getActualLogicTimeScaleOverFpsRatio(); ///< Get the real logic time scale over render fps ratio, used to scale down steps in render updates to match logic updates.
91+
Int getActualLogicTimeScaleFps(LogicTimeQueryFlags flags = 0); ///< Get the real logic time scale fps, depending on the max render fps, network state and enabled state.
92+
Real getActualLogicTimeScaleRatio(LogicTimeQueryFlags flags = 0); ///< Get the real logic time scale ratio, depending on the max render fps, network state and enabled state.
93+
Real getActualLogicTimeScaleOverFpsRatio(LogicTimeQueryFlags flags = 0); ///< Get the real logic time scale over render fps ratio, used to scale down steps in render updates to match logic updates.
94+
Real getLogicTimeStepSeconds(LogicTimeQueryFlags flags = 0); ///< Get the logic time step in seconds
95+
Real getLogicTimeStepMilliseconds(LogicTimeQueryFlags flags = 0); ///< Get the logic time step in milliseconds
8696

8797
virtual void setQuitting( Bool quitting ); ///< set quitting status
8898
virtual Bool getQuitting(void); ///< is app getting ready to quit.
@@ -97,6 +107,10 @@ class GameEngine : public SubsystemInterface
97107

98108
virtual void resetSubsystems( void );
99109

110+
Bool canUpdateGameLogic();
111+
Bool canUpdateNetworkGameLogic();
112+
Bool canUpdateRegularGameLogic();
113+
100114
virtual FileSystem *createFileSystem( void ); ///< Factory for FileSystem classes
101115
virtual LocalFileSystem *createLocalFileSystem( void ) = 0; ///< Factory for LocalFileSystem classes
102116
virtual ArchiveFileSystem *createArchiveFileSystem( void ) = 0; ///< Factory for ArchiveFileSystem classes
@@ -117,11 +131,14 @@ class GameEngine : public SubsystemInterface
117131
Real m_updateTime; ///< Last engine update delta time
118132
Real m_logicTimeAccumulator; ///< Frame time accumulated towards submitting a new logic frame
119133

120-
Bool m_quitting; ///< true when we need to quit the game
121-
Bool m_isActive; ///< app has OS focus.
134+
Bool m_quitting; ///< true when we need to quit the game
135+
Bool m_isActive; ///< app has OS focus.
122136
Bool m_enableLogicTimeScale;
137+
Bool m_isTimeFrozen;
138+
Bool m_isGameHalted;
123139

124140
};
141+
125142
inline void GameEngine::setQuitting( Bool quitting ) { m_quitting = quitting; }
126143
inline Bool GameEngine::getQuitting(void) { return m_quitting; }
127144

Generals/Code/GameEngine/Include/GameClient/Drawable.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,7 @@ class Drawable : public Thing,
390390

391391
const Matrix3D *getTransformMatrix( void ) const; ///< return the world transform
392392

393-
void draw( View *view ); ///< render the drawable to the given view
393+
void draw(); ///< render the drawable to the given view
394394
void updateDrawable(); ///< update the drawable
395395

396396
void drawIconUI( void ); ///< draw "icon"(s) needed on drawable (health bars, veterency, etc)
@@ -600,6 +600,8 @@ class Drawable : public Thing,
600600

601601
private:
602602

603+
const Locomotor* getLocomotor() const;
604+
603605
// note, these are lazily allocated!
604606
TintEnvelope* m_selectionFlashEnvelope; ///< used for selection flash, works WITH m_colorTintEnvelope
605607
TintEnvelope* m_colorTintEnvelope; ///< house color flashing, etc... works WITH m_selectionFlashEnvelope
@@ -644,6 +646,8 @@ class Drawable : public Thing,
644646

645647
DrawableLocoInfo* m_locoInfo; // lazily allocated
646648

649+
PhysicsXformInfo* m_physicsXform;
650+
647651
DynamicAudioEventRTS* m_ambientSound; ///< sound module for ambient sound (lazily allocated)
648652
Bool m_ambientSoundEnabled;
649653

Generals/Code/GameEngine/Include/GameLogic/GameLogic.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ class GameLogic : public SubsystemInterface, public Snapshot
197197
void updateObjectsChangedTriggerAreas(void) {m_frameObjectsChangedTriggerAreas = m_frame;}
198198
UnsignedInt getFrameObjectsChangedTriggerAreas(void) {return m_frameObjectsChangedTriggerAreas;}
199199

200+
void exitGame();
200201
void clearGameData(Bool showScoreScreen = TRUE); ///< Clear the game data
201202
void closeWindows( void );
202203

@@ -205,7 +206,7 @@ class GameLogic : public SubsystemInterface, public Snapshot
205206

206207
void bindObjectAndDrawable(Object* obj, Drawable* draw);
207208

208-
void setGamePausedInFrame( UnsignedInt frame );
209+
void setGamePausedInFrame( UnsignedInt frame, Bool disableLogicTimeScale );
209210
UnsignedInt getGamePauseFrame() const { return m_pauseFrame; }
210211
void setGamePaused( Bool paused, Bool pauseMusic = TRUE, Bool pauseInput = TRUE );
211212
Bool isGamePaused( void );
@@ -352,6 +353,7 @@ class GameLogic : public SubsystemInterface, public Snapshot
352353
Bool m_pauseInput;
353354
Bool m_inputEnabledMemory;// Latches used to remember what to restore to after we unpause
354355
Bool m_mouseVisibleMemory;
356+
Bool m_logicTimeScaleEnabledMemory;
355357

356358
Bool m_progressComplete[MAX_SLOTS];
357359
enum { PROGRESS_COMPLETE_TIMEOUT = 60000 }; ///< Timeout we wait for when we've completed our Load

Generals/Code/GameEngine/Include/GameNetwork/NetworkInterface.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ class NetworkInterface : public SubsystemInterface
6868

6969
virtual void setLocalAddress(UnsignedInt ip, UnsignedInt port) = 0; ///< Tell the network what local ip and port to bind to.
7070
virtual Bool isFrameDataReady( void ) = 0; ///< Are the commands for the next frame available?
71+
virtual Bool isStalling() = 0;
7172
virtual void parseUserList( const GameInfo *game ) = 0; ///< Parse a userlist, creating connections
7273
virtual void startGame(void) = 0; ///< Sets the network game frame counter to -1
7374
virtual UnsignedInt getRunAhead(void) = 0; ///< Get the current RunAhead value

0 commit comments

Comments
 (0)