Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions Core/GameEngine/Include/Common/FramePacer.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class FramePacer
void reset(); ///< Move the frame timing anchor to now and predict the next update time from the target frame rate. Call after a long blocking operation so its duration does not leak into the next frame delta.

void setFramesPerSecondLimit( Int fps ); ///< Set the update fps limit.
UnsignedInt changeFramesPerSecondLimit( FpsValueChange change ); ///< Step the update fps limit to the next/prev preset, apply it, and return the new value.
Int getFramesPerSecondLimit() const; ///< Get the update fps limit.
void enableFramesPerSecondLimit( Bool enable ); ///< Enable or disable the update fps limit.
Bool isFramesPerSecondLimitEnabled() const; ///< Returns whether the fps limit is enabled here.
Expand All @@ -57,9 +58,9 @@ class FramePacer
Bool isTimeFrozen() const;
Bool isGameHalted() const;

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.
Int getLogicTimeScaleFps() const; ///< Get the raw logic time scale fps value.
void enableLogicTimeScale( Bool enable ); ///< Enable or disable the logic time scale setup. If disabled, the simulation time scale is bound to the render frame time or network update time.
UnsignedInt changeLogicTimeScaleFps( FpsValueChange change ); ///< Step the logic time scale fps to the next/prev preset, apply and enable/disable it as needed, and return the resulting value.
void enableLogicTimeScale( Bool enable, Int fps = -1 ); ///< Enable or disable the logic time scale setup. If fps >= 0, also sets the logic time scale fps before enabling. If disabled, the simulation time scale is bound to the render frame time or network update time.
Bool isLogicTimeScaleEnabled() const; ///< Check whether the logic time scale setup is enabled.
Int getActualLogicTimeScaleFps(LogicTimeQueryFlags flags = 0) const; ///< Get the real logic time scale fps, depending on the max render fps, network state and enabled state.
Real getActualLogicTimeScaleRatio(LogicTimeQueryFlags flags = 0) const; ///< Get the real logic time scale ratio, depending on the max render fps, network state and enabled state.
Expand Down
24 changes: 10 additions & 14 deletions Core/GameEngine/Include/Common/FrameRateLimit.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,30 +50,26 @@ class RenderFpsPreset
UncappedFpsValue = 1000000,
};

static UnsignedInt getNextFpsValue(UnsignedInt value);
static UnsignedInt getPrevFpsValue(UnsignedInt value);
static UnsignedInt changeFpsValue(UnsignedInt value, FpsValueChange change);

private:
static UnsignedInt getNextFpsValue(UnsignedInt value);
static UnsignedInt getPrevFpsValue(UnsignedInt value);

static const UnsignedInt s_fpsValues[];
};


class LogicTimeScaleFpsPreset
{
public:
enum CPP_11(: UnsignedInt)
{
#if RTS_DEBUG
MinFpsValue = 5,
#else
MinFpsValue = LOGICFRAMES_PER_SECOND,
#endif
StepFpsValue = 5,
};

static UnsignedInt getNextFpsValue(UnsignedInt value);
static UnsignedInt getPrevFpsValue(UnsignedInt value);
static UnsignedInt changeFpsValue(UnsignedInt value, FpsValueChange change);
static UnsignedInt changeFpsValue(UnsignedInt value, FpsValueChange change, UnsignedInt snapValue = 0);

private:
static UnsignedInt getNextFpsValue(UnsignedInt value, UnsignedInt snapValue = 0);
static UnsignedInt getPrevFpsValue(UnsignedInt value, UnsignedInt snapValue = 0);

static const UnsignedInt s_fpsValues[];
};

49 changes: 43 additions & 6 deletions Core/GameEngine/Source/Common/FramePacer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,17 @@ void FramePacer::setFramesPerSecondLimit( Int fps )
m_maxFPS = fps;
}

UnsignedInt FramePacer::changeFramesPerSecondLimit( FpsValueChange change )
{
UnsignedInt maxRenderFps = getFramesPerSecondLimit();
maxRenderFps = RenderFpsPreset::changeFpsValue(maxRenderFps, change);

setFramesPerSecondLimit(maxRenderFps);
TheWritableGlobalData->m_useFpsLimit = (maxRenderFps != RenderFpsPreset::UncappedFpsValue);

return maxRenderFps;
}

Int FramePacer::getFramesPerSecondLimit() const
{
return m_maxFPS;
Expand Down Expand Up @@ -111,7 +122,8 @@ Bool FramePacer::isActualFramesPerSecondLimitEnabled() const

Int FramePacer::getActualFramesPerSecondLimit() const
{
return isActualFramesPerSecondLimitEnabled() ? getFramesPerSecondLimit() : RenderFpsPreset::UncappedFpsValue;
const Int limit = isActualFramesPerSecondLimitEnabled() ? getFramesPerSecondLimit() : RenderFpsPreset::UncappedFpsValue;
return (TheNetwork != nullptr) ? std::max(limit, static_cast<Int>(LOGICFRAMES_PER_SECOND)) : limit;
}

Real FramePacer::getUpdateTime() const
Expand Down Expand Up @@ -151,18 +163,43 @@ Bool FramePacer::isGameHalted() const
return m_isGameHalted;
}

void FramePacer::setLogicTimeScaleFps( Int fps )
Int FramePacer::getLogicTimeScaleFps() const
{
m_logicTimeScaleFPS = fps;
return m_logicTimeScaleFPS;
}

Int FramePacer::getLogicTimeScaleFps() const
UnsignedInt FramePacer::changeLogicTimeScaleFps( FpsValueChange change )
{
return m_logicTimeScaleFPS;
const UnsignedInt maxRenderFps = getFramesPerSecondLimit();
UnsignedInt logicTimeScaleFps = getLogicTimeScaleFps();

if (!isLogicTimeScaleEnabled())
{
logicTimeScaleFps = maxRenderFps;
}

logicTimeScaleFps = LogicTimeScaleFpsPreset::changeFpsValue(logicTimeScaleFps, change, maxRenderFps);

// Ensure logic FPS never exceeds render FPS
if (logicTimeScaleFps > maxRenderFps && logicTimeScaleFps != RenderFpsPreset::UncappedFpsValue)
{
logicTimeScaleFps = maxRenderFps;
}

const bool enableTimescale = (logicTimeScaleFps < maxRenderFps);

// TheSuperHackers @info Preserve the last real FPS in m_logicTimeScaleFPS so re-enabling timescale resumes from a sane value.
enableLogicTimeScale(enableTimescale, enableTimescale ? (Int)logicTimeScaleFps : -1);

return getLogicTimeScaleFps();
}

void FramePacer::enableLogicTimeScale( Bool enable )
void FramePacer::enableLogicTimeScale( Bool enable, Int fps )
{
if (fps >= 0)
{
m_logicTimeScaleFPS = fps;
}
m_enableLogicTimeScale = enable;
}

Expand Down
75 changes: 61 additions & 14 deletions Core/GameEngine/Source/Common/FrameRateLimit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,11 @@ void FrameRateLimit::reset()


const UnsignedInt RenderFpsPreset::s_fpsValues[] = {
30, 50, 56, 60, 65, 70, 72, 75, 80, 85, 90, 100, 110, 120, 144, 240, 480, UncappedFpsValue };
15, 30, 50, 56, 60, 65, 70, 72, 75, 80, 85, 90, 100, 110, 120, 144, 240, 480, UncappedFpsValue };
Comment thread
githubawn marked this conversation as resolved.

static_assert(LOGICFRAMES_PER_SECOND <= 30, "Min FPS values need to be revisited!");
// TheSuperHackers @info s_fpsValues MUST be strictly ascending; the search loops break on first match.
const UnsignedInt LogicTimeScaleFpsPreset::s_fpsValues[] = {
1, 5, 15, 30, 45, 60, 75, 90, 105, 120, 240, 480, 960, RenderFpsPreset::UncappedFpsValue };
Comment thread
greptile-apps[bot] marked this conversation as resolved.

UnsignedInt RenderFpsPreset::getNextFpsValue(UnsignedInt value)
{
Expand Down Expand Up @@ -109,30 +111,75 @@ UnsignedInt RenderFpsPreset::changeFpsValue(UnsignedInt value, FpsValueChange ch
}
}


UnsignedInt LogicTimeScaleFpsPreset::getNextFpsValue(UnsignedInt value)
UnsignedInt LogicTimeScaleFpsPreset::getNextFpsValue(UnsignedInt value, UnsignedInt snapValue)
{
return value + StepFpsValue;
UnsignedInt nextValue = RenderFpsPreset::UncappedFpsValue;

// Check if snapValue (e.g. current render FPS) is the next closest candidate
if (snapValue > value && snapValue < nextValue)
{
nextValue = snapValue;
}

// Check predefined steps
for (size_t i = 0; i < ARRAY_SIZE(s_fpsValues); ++i)
{
const UnsignedInt fpsValue = s_fpsValues[i];
if (fpsValue > value)
{
if (fpsValue < nextValue)
{
nextValue = fpsValue;
}
break;
}
}

return nextValue;
}

UnsignedInt LogicTimeScaleFpsPreset::getPrevFpsValue(UnsignedInt value)
UnsignedInt LogicTimeScaleFpsPreset::getPrevFpsValue(UnsignedInt value, UnsignedInt snapValue)
{
if (value - StepFpsValue < MinFpsValue)
UnsignedInt prevValue = s_fpsValues[0]; // Floor/seed for the search loop

// Check if snapValue (e.g. current render FPS) is the previous closest candidate.
// Note: if snapValue == value, neither branch below fires and the snap point is
// intentionally skipped — the caller must step to a different preset.
if (snapValue > prevValue && snapValue < value)
{
return MinFpsValue;
prevValue = snapValue;
}
else

// Check predefined steps
for (int i = (int)ARRAY_SIZE(s_fpsValues) - 1; i >= 0; --i)
{
return value - StepFpsValue;
const UnsignedInt fpsValue = s_fpsValues[i];
if (fpsValue < value)
{
if (fpsValue > prevValue)
{
prevValue = fpsValue;
}

break;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add white line after closing bracket

}
}

return prevValue;
}

UnsignedInt LogicTimeScaleFpsPreset::changeFpsValue(UnsignedInt value, FpsValueChange change)
UnsignedInt LogicTimeScaleFpsPreset::changeFpsValue(UnsignedInt value, FpsValueChange change, UnsignedInt snapValue)
{
switch (change)
{
default:
case FpsValueChange_Increase: return getNextFpsValue(value);
case FpsValueChange_Decrease: return getPrevFpsValue(value);
case FpsValueChange_Increase:
return getNextFpsValue(value, snapValue);

case FpsValueChange_Decrease:
return getPrevFpsValue(value, snapValue);

default:
assert(false);
return value;
}
}
41 changes: 2 additions & 39 deletions Core/GameEngine/Source/GameClient/MessageStream/CommandXlat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -182,11 +182,7 @@ Bool hasThingsInProduction(PlayerType playerType)

bool changeMaxRenderFps(FpsValueChange change)
{
UnsignedInt maxRenderFps = TheFramePacer->getFramesPerSecondLimit();
maxRenderFps = RenderFpsPreset::changeFpsValue(maxRenderFps, change);

TheFramePacer->setFramesPerSecondLimit(maxRenderFps);
TheWritableGlobalData->m_useFpsLimit = (maxRenderFps != RenderFpsPreset::UncappedFpsValue);
const UnsignedInt maxRenderFps = TheFramePacer->changeFramesPerSecondLimit(change);

UnicodeString message;

Expand All @@ -209,40 +205,7 @@ bool changeLogicTimeScale(FpsValueChange change)
if (TheNetwork != nullptr)
return false;

const UnsignedInt maxRenderFps = TheFramePacer->getFramesPerSecondLimit();
UnsignedInt maxRenderRemainder = LogicTimeScaleFpsPreset::StepFpsValue;
maxRenderRemainder -= maxRenderFps % LogicTimeScaleFpsPreset::StepFpsValue;
maxRenderRemainder %= LogicTimeScaleFpsPreset::StepFpsValue;

UnsignedInt logicTimeScaleFps = TheFramePacer->getLogicTimeScaleFps();
// Set the value to the max render fps value plus a bit when time scale is
// disabled. This ensures that the time scale does not re-enable with a
// 'surprise' value.
if (!TheFramePacer->isLogicTimeScaleEnabled())
{
logicTimeScaleFps = maxRenderFps + maxRenderRemainder;
}
// Ceil the value at the max render fps value plus a bit so that the next fps
// value decrease would undercut the max render fps at the correct step value.
// Example: render fps 72 -> logic value ceiled to 75 -> decreased to 70.
logicTimeScaleFps = min(logicTimeScaleFps, maxRenderFps + maxRenderRemainder);
logicTimeScaleFps = LogicTimeScaleFpsPreset::changeFpsValue(logicTimeScaleFps, change);

// Set value before potentially disabling it.
if (TheFramePacer->isLogicTimeScaleEnabled())
{
TheFramePacer->setLogicTimeScaleFps(logicTimeScaleFps);
Comment thread
githubawn marked this conversation as resolved.
}

TheFramePacer->enableLogicTimeScale(logicTimeScaleFps < maxRenderFps);

// Set value after potentially enabling it.
if (TheFramePacer->isLogicTimeScaleEnabled())
{
TheFramePacer->setLogicTimeScaleFps(logicTimeScaleFps);
}

logicTimeScaleFps = TheFramePacer->getLogicTimeScaleFps();
const UnsignedInt logicTimeScaleFps = TheFramePacer->changeLogicTimeScaleFps(change);
const UnsignedInt actualLogicTimeScaleFps = TheFramePacer->getActualLogicTimeScaleFps();
const Real actualLogicTimeScaleRatio = TheFramePacer->getActualLogicTimeScaleRatio();

Expand Down
Loading