From bb8610d655bbd200adc6b14333b7e81cabc90a75 Mon Sep 17 00:00:00 2001 From: Bobby Battista Date: Tue, 15 Sep 2026 11:19:26 -0400 Subject: [PATCH 1/6] bugfix(drawable): Decouple fade timing from render rate --- .../Code/GameEngine/Include/GameClient/Drawable.h | 2 +- .../GameEngine/Source/GameClient/Drawable.cpp | 15 ++++++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/GeneralsMD/Code/GameEngine/Include/GameClient/Drawable.h b/GeneralsMD/Code/GameEngine/Include/GameClient/Drawable.h index 7169b8cb51f..84c7431dc0f 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameClient/Drawable.h +++ b/GeneralsMD/Code/GameEngine/Include/GameClient/Drawable.h @@ -687,7 +687,7 @@ class Drawable : public Thing, FADING_OUT }; FadingMode m_fadeMode; - UnsignedInt m_timeElapsedFade; ///< for how many frames have i been fading + Real m_timeElapsedFade; ///< for how long have i been fading (in 30fps-equivalent frames) UnsignedInt m_timeToFade; ///< how slowly am I fading UnsignedInt m_shroudClearFrame; ///< Last frame the local player saw this drawable "OBJECTSHROUD_CLEAR" diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/Drawable.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/Drawable.cpp index 54dff3325f2..3e73c20de6a 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/Drawable.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/Drawable.cpp @@ -1149,7 +1149,9 @@ void Drawable::updateDrawable() Real numer = (m_fadeMode == FADING_IN) ? (m_timeElapsedFade) : (m_timeToFade-m_timeElapsedFade); setDrawableOpacity(numer/(Real)m_timeToFade); - ++m_timeElapsedFade; + // TheSuperHackers @bugfix bobtista 15/09/2026 Decouple Drawable fade timing from render updates. + const Real fadeTimeScale = TheFramePacer->getActualLogicTimeScaleOverFpsRatio(); + m_timeElapsedFade += fadeTimeScale; if (m_timeElapsedFade > m_timeToFade) m_fadeMode = FADING_NONE; @@ -1167,7 +1169,9 @@ void Drawable::updateDrawable() { //LERP (*dm)->setTerrainDecalOpacity(m_decalOpacity); - m_decalOpacity += m_decalOpacityFadeRate; + // TheSuperHackers @bugfix bobtista 15/09/2026 Decouple decal opacity fade timing from render updates. + const Real decalFadeTimeScale = TheFramePacer->getActualLogicTimeScaleOverFpsRatio(); + m_decalOpacity += m_decalOpacityFadeRate * decalFadeTimeScale; } //--------------- @@ -5035,7 +5039,12 @@ void Drawable::xfer( Xfer *xfer ) xfer->xferUser( &m_fadeMode, sizeof( FadingMode ) ); // time elapsed fade - xfer->xferUnsignedInt( &m_timeElapsedFade ); + UnsignedInt timeElapsedFadeFrames = static_cast(m_timeElapsedFade); + xfer->xferUnsignedInt( &timeElapsedFadeFrames ); + if (xfer->getXferMode() == XFER_LOAD) + { + m_timeElapsedFade = static_cast(timeElapsedFadeFrames); + } // time to fade xfer->xferUnsignedInt( &m_timeToFade ); From 0ef50c60e86f1c06cb14bdcd7f050c75e143d4d8 Mon Sep 17 00:00:00 2001 From: Bobby Battista Date: Tue, 15 Sep 2026 11:19:37 -0400 Subject: [PATCH 2/6] bugfix(drawable): Replicate fade timing fix to Generals --- .../Code/GameEngine/Include/GameClient/Drawable.h | 2 +- .../GameEngine/Source/GameClient/Drawable.cpp | 15 ++++++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/Generals/Code/GameEngine/Include/GameClient/Drawable.h b/Generals/Code/GameEngine/Include/GameClient/Drawable.h index bbe206ff429..a621d1051a8 100644 --- a/Generals/Code/GameEngine/Include/GameClient/Drawable.h +++ b/Generals/Code/GameEngine/Include/GameClient/Drawable.h @@ -687,7 +687,7 @@ class Drawable : public Thing, FADING_OUT }; FadingMode m_fadeMode; - UnsignedInt m_timeElapsedFade; ///< for how many frames have i been fading + Real m_timeElapsedFade; ///< for how long have i been fading (in 30fps-equivalent frames) UnsignedInt m_timeToFade; ///< how slowly am I fading UnsignedInt m_shroudClearFrame; ///< Last frame the local player saw this drawable "OBJECTSHROUD_CLEAR" diff --git a/Generals/Code/GameEngine/Source/GameClient/Drawable.cpp b/Generals/Code/GameEngine/Source/GameClient/Drawable.cpp index e482166c024..9daaa4c6549 100644 --- a/Generals/Code/GameEngine/Source/GameClient/Drawable.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/Drawable.cpp @@ -1147,7 +1147,9 @@ void Drawable::updateDrawable() Real numer = (m_fadeMode == FADING_IN) ? (m_timeElapsedFade) : (m_timeToFade-m_timeElapsedFade); setDrawableOpacity(numer/(Real)m_timeToFade); - ++m_timeElapsedFade; + // TheSuperHackers @bugfix bobtista 15/09/2026 Decouple Drawable fade timing from render updates. + const Real fadeTimeScale = TheFramePacer->getActualLogicTimeScaleOverFpsRatio(); + m_timeElapsedFade += fadeTimeScale; if (m_timeElapsedFade > m_timeToFade) m_fadeMode = FADING_NONE; @@ -1165,7 +1167,9 @@ void Drawable::updateDrawable() { //LERP (*dm)->setTerrainDecalOpacity(m_decalOpacity); - m_decalOpacity += m_decalOpacityFadeRate; + // TheSuperHackers @bugfix bobtista 15/09/2026 Decouple decal opacity fade timing from render updates. + const Real decalFadeTimeScale = TheFramePacer->getActualLogicTimeScaleOverFpsRatio(); + m_decalOpacity += m_decalOpacityFadeRate * decalFadeTimeScale; } //--------------- @@ -5030,7 +5034,12 @@ void Drawable::xfer( Xfer *xfer ) xfer->xferUser( &m_fadeMode, sizeof( FadingMode ) ); // time elapsed fade - xfer->xferUnsignedInt( &m_timeElapsedFade ); + UnsignedInt timeElapsedFadeFrames = static_cast(m_timeElapsedFade); + xfer->xferUnsignedInt( &timeElapsedFadeFrames ); + if (xfer->getXferMode() == XFER_LOAD) + { + m_timeElapsedFade = static_cast(timeElapsedFadeFrames); + } // time to fade xfer->xferUnsignedInt( &m_timeToFade ); From d726a1e60cf5068f2afe0f6c3967886c0bd8f607 Mon Sep 17 00:00:00 2001 From: Bobby Battista Date: Wed, 16 Sep 2026 20:33:23 -0400 Subject: [PATCH 3/6] fix(drawable): Finish fades and preserve fractional save progress --- .../GameEngine/Source/GameClient/Drawable.cpp | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/Drawable.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/Drawable.cpp index 3e73c20de6a..200c4658aec 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/Drawable.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/Drawable.cpp @@ -1150,11 +1150,13 @@ void Drawable::updateDrawable() setDrawableOpacity(numer/(Real)m_timeToFade); // TheSuperHackers @bugfix bobtista 15/09/2026 Decouple Drawable fade timing from render updates. - const Real fadeTimeScale = TheFramePacer->getActualLogicTimeScaleOverFpsRatio(); - m_timeElapsedFade += fadeTimeScale; + m_timeElapsedFade += TheFramePacer->getActualLogicTimeScaleOverFpsRatio(); if (m_timeElapsedFade > m_timeToFade) + { + setDrawableOpacity(m_fadeMode == FADING_IN ? 1.0f : 0.0f); m_fadeMode = FADING_NONE; + } } } @@ -1170,8 +1172,7 @@ void Drawable::updateDrawable() //LERP (*dm)->setTerrainDecalOpacity(m_decalOpacity); // TheSuperHackers @bugfix bobtista 15/09/2026 Decouple decal opacity fade timing from render updates. - const Real decalFadeTimeScale = TheFramePacer->getActualLogicTimeScaleOverFpsRatio(); - m_decalOpacity += m_decalOpacityFadeRate * decalFadeTimeScale; + m_decalOpacity += m_decalOpacityFadeRate * TheFramePacer->getActualLogicTimeScaleOverFpsRatio(); } //--------------- @@ -4854,6 +4855,7 @@ void Drawable::xferDrawableModules( Xfer *xfer ) * 6: Added m_ambientSoundEnabledFromScript flag (Added in Zero Hour) * 7: Save the customize ambient sound info (Added in Zero Hour) * 8: TheSuperHackers @bugfix Removed m_prevTintStatus because loading its value is unnecessary and undesirable + * 9: TheSuperHackers @info Preserve fractional fade progress in non-retail saves */ // ------------------------------------------------------------------------------------------------ void Drawable::xfer( Xfer *xfer ) @@ -4865,7 +4867,7 @@ void Drawable::xfer( Xfer *xfer ) #elif RETAIL_COMPATIBLE_XFER_SAVE const XferVersion currentVersion = 7; #else - const XferVersion currentVersion = 8; + const XferVersion currentVersion = 9; #endif XferVersion version = currentVersion; xfer->xferVersion( &version, currentVersion ); @@ -5039,11 +5041,18 @@ void Drawable::xfer( Xfer *xfer ) xfer->xferUser( &m_fadeMode, sizeof( FadingMode ) ); // time elapsed fade - UnsignedInt timeElapsedFadeFrames = static_cast(m_timeElapsedFade); - xfer->xferUnsignedInt( &timeElapsedFadeFrames ); - if (xfer->getXferMode() == XFER_LOAD) + if (version >= 9) + { + xfer->xferReal( &m_timeElapsedFade ); + } + else { - m_timeElapsedFade = static_cast(timeElapsedFadeFrames); + UnsignedInt timeElapsedFadeFrames = static_cast(m_timeElapsedFade); + xfer->xferUnsignedInt( &timeElapsedFadeFrames ); + if (xfer->getXferMode() == XFER_LOAD) + { + m_timeElapsedFade = static_cast(timeElapsedFadeFrames); + } } // time to fade From 4c14eae9271cd4ab02308624fb3a15a09327eafb Mon Sep 17 00:00:00 2001 From: Bobby Battista Date: Wed, 16 Sep 2026 20:33:37 -0400 Subject: [PATCH 4/6] fix(drawable): Replicate fade completion and save fixes to Generals --- .../GameEngine/Source/GameClient/Drawable.cpp | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/Generals/Code/GameEngine/Source/GameClient/Drawable.cpp b/Generals/Code/GameEngine/Source/GameClient/Drawable.cpp index 9daaa4c6549..e968fe8a4a4 100644 --- a/Generals/Code/GameEngine/Source/GameClient/Drawable.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/Drawable.cpp @@ -1148,11 +1148,13 @@ void Drawable::updateDrawable() setDrawableOpacity(numer/(Real)m_timeToFade); // TheSuperHackers @bugfix bobtista 15/09/2026 Decouple Drawable fade timing from render updates. - const Real fadeTimeScale = TheFramePacer->getActualLogicTimeScaleOverFpsRatio(); - m_timeElapsedFade += fadeTimeScale; + m_timeElapsedFade += TheFramePacer->getActualLogicTimeScaleOverFpsRatio(); if (m_timeElapsedFade > m_timeToFade) + { + setDrawableOpacity(m_fadeMode == FADING_IN ? 1.0f : 0.0f); m_fadeMode = FADING_NONE; + } } } @@ -1168,8 +1170,7 @@ void Drawable::updateDrawable() //LERP (*dm)->setTerrainDecalOpacity(m_decalOpacity); // TheSuperHackers @bugfix bobtista 15/09/2026 Decouple decal opacity fade timing from render updates. - const Real decalFadeTimeScale = TheFramePacer->getActualLogicTimeScaleOverFpsRatio(); - m_decalOpacity += m_decalOpacityFadeRate * decalFadeTimeScale; + m_decalOpacity += m_decalOpacityFadeRate * TheFramePacer->getActualLogicTimeScaleOverFpsRatio(); } //--------------- @@ -4849,6 +4850,7 @@ void Drawable::xferDrawableModules( Xfer *xfer ) * 6: Added m_ambientSoundEnabledFromScript flag (Added in Zero Hour) * 7: Save the customize ambient sound info (Added in Zero Hour) * 8: TheSuperHackers @bugfix Removed m_prevTintStatus because loading its value is unnecessary and undesirable + * 9: TheSuperHackers @info Preserve fractional fade progress in non-retail saves */ // ------------------------------------------------------------------------------------------------ void Drawable::xfer( Xfer *xfer ) @@ -4860,7 +4862,7 @@ void Drawable::xfer( Xfer *xfer ) #elif RETAIL_COMPATIBLE_XFER_SAVE const XferVersion currentVersion = 7; #else - const XferVersion currentVersion = 8; + const XferVersion currentVersion = 9; #endif XferVersion version = currentVersion; xfer->xferVersion( &version, currentVersion ); @@ -5034,11 +5036,18 @@ void Drawable::xfer( Xfer *xfer ) xfer->xferUser( &m_fadeMode, sizeof( FadingMode ) ); // time elapsed fade - UnsignedInt timeElapsedFadeFrames = static_cast(m_timeElapsedFade); - xfer->xferUnsignedInt( &timeElapsedFadeFrames ); - if (xfer->getXferMode() == XFER_LOAD) + if (version >= 9) + { + xfer->xferReal( &m_timeElapsedFade ); + } + else { - m_timeElapsedFade = static_cast(timeElapsedFadeFrames); + UnsignedInt timeElapsedFadeFrames = static_cast(m_timeElapsedFade); + xfer->xferUnsignedInt( &timeElapsedFadeFrames ); + if (xfer->getXferMode() == XFER_LOAD) + { + m_timeElapsedFade = static_cast(timeElapsedFadeFrames); + } } // time to fade From 231e76d6d4d4b7de966c7f7911e68ad1ccf2473b Mon Sep 17 00:00:00 2001 From: Bobby Battista Date: Fri, 18 Sep 2026 01:08:33 -0400 Subject: [PATCH 5/6] refactor(drawable): Address fade timing review feedback --- .../Code/GameEngine/Include/GameClient/Drawable.h | 4 ++-- .../Code/GameEngine/Source/GameClient/Drawable.cpp | 13 +++++++------ .../GameEngine/Source/GameClient/GameClient.cpp | 4 +++- .../GameLogic/Object/Update/StealthUpdate.cpp | 5 +++-- 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/GeneralsMD/Code/GameEngine/Include/GameClient/Drawable.h b/GeneralsMD/Code/GameEngine/Include/GameClient/Drawable.h index 84c7431dc0f..bd2d15a1cbe 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameClient/Drawable.h +++ b/GeneralsMD/Code/GameEngine/Include/GameClient/Drawable.h @@ -412,7 +412,7 @@ class Drawable : public Thing, const Matrix3D *getTransformMatrix() const; ///< return the world transform void draw(); ///< render the drawable to the given view - void updateDrawable(); ///< update the drawable + void updateDrawable(Real timeScale); ///< update the drawable void drawIconUI(); ///< draw "icon"(s) needed on drawable (health bars, veterency, etc) @@ -687,7 +687,7 @@ class Drawable : public Thing, FADING_OUT }; FadingMode m_fadeMode; - Real m_timeElapsedFade; ///< for how long have i been fading (in 30fps-equivalent frames) + Real m_timeElapsedFade; ///< for how many logic frames - incl. fractional ones - have i been fading UnsignedInt m_timeToFade; ///< how slowly am I fading UnsignedInt m_shroudClearFrame; ///< Last frame the local player saw this drawable "OBJECTSHROUD_CLEAR" diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/Drawable.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/Drawable.cpp index 200c4658aec..e201874662a 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/Drawable.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/Drawable.cpp @@ -1127,7 +1127,7 @@ void Drawable::imitateStealthLook( Drawable& otherDraw ) /** update is called once per frame */ //------------------------------------------------------------------------------------------------- //DECLARE_PERF_TIMER(updateDrawable) -void Drawable::updateDrawable() +void Drawable::updateDrawable(Real timeScale) { //USE_PERF_TIMER(updateDrawable) @@ -1148,15 +1148,16 @@ void Drawable::updateDrawable() { Real numer = (m_fadeMode == FADING_IN) ? (m_timeElapsedFade) : (m_timeToFade-m_timeElapsedFade); - setDrawableOpacity(numer/(Real)m_timeToFade); + Real opacity = numer/(Real)m_timeToFade; // TheSuperHackers @bugfix bobtista 15/09/2026 Decouple Drawable fade timing from render updates. - m_timeElapsedFade += TheFramePacer->getActualLogicTimeScaleOverFpsRatio(); + m_timeElapsedFade += timeScale; if (m_timeElapsedFade > m_timeToFade) { - setDrawableOpacity(m_fadeMode == FADING_IN ? 1.0f : 0.0f); + opacity = m_fadeMode == FADING_IN ? 1.0f : 0.0f; m_fadeMode = FADING_NONE; } + setDrawableOpacity(opacity); } } @@ -1172,7 +1173,7 @@ void Drawable::updateDrawable() //LERP (*dm)->setTerrainDecalOpacity(m_decalOpacity); // TheSuperHackers @bugfix bobtista 15/09/2026 Decouple decal opacity fade timing from render updates. - m_decalOpacity += m_decalOpacityFadeRate * TheFramePacer->getActualLogicTimeScaleOverFpsRatio(); + m_decalOpacity += m_decalOpacityFadeRate * timeScale; } //--------------- @@ -4855,7 +4856,7 @@ void Drawable::xferDrawableModules( Xfer *xfer ) * 6: Added m_ambientSoundEnabledFromScript flag (Added in Zero Hour) * 7: Save the customize ambient sound info (Added in Zero Hour) * 8: TheSuperHackers @bugfix Removed m_prevTintStatus because loading its value is unnecessary and undesirable - * 9: TheSuperHackers @info Preserve fractional fade progress in non-retail saves + * 9: TheSuperHackers @tweak m_timeElapsedFade is now serialized as Real instead of UnsignedInt */ // ------------------------------------------------------------------------------------------------ void Drawable::xfer( Xfer *xfer ) diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp index e3d83bb7323..f143e550cd1 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp @@ -33,6 +33,7 @@ // USER INCLUDES ////////////////////////////////////////////////////////////// #include "Common/ActionManager.h" +#include "Common/FramePacer.h" #include "Common/GameEngine.h" #include "Common/GameState.h" #include "Common/Recorder.h" @@ -641,6 +642,7 @@ void GameClient::update() // call the update for all client drawables + const Real timeScale = TheFramePacer->getActualLogicTimeScaleOverFpsRatio(); Drawable* draw = firstDrawable(); while (draw) { // update() could free the Drawable, so go ahead and grab 'next' @@ -688,7 +690,7 @@ void GameClient::update() draw->setFullyObscuredByShroud(ss >= OBJECTSHROUD_FOGGED); } } - draw->updateDrawable(); + draw->updateDrawable(timeScale); draw = next; } } diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/StealthUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/StealthUpdate.cpp index 8f09c707af2..b1a82a0ead8 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/StealthUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/StealthUpdate.cpp @@ -33,6 +33,7 @@ #define DEFINE_OBJECT_STATUS_NAMES // INCLUDES /////////////////////////////////////////////////////////////////////////////////////// +#include "Common/FramePacer.h" #include "Common/GameState.h" #include "Common/GameUtility.h" #include "Common/Player.h" @@ -1001,7 +1002,7 @@ void StealthUpdate::changeVisualDisguise() draw->setPosition( self->getPosition() ); draw->setOrientation( self->getOrientation() ); draw->setModelConditionFlags( flags ); - draw->updateDrawable(); + draw->updateDrawable(TheFramePacer->getActualLogicTimeScaleOverFpsRatio()); self->getPhysics()->resetDynamicPhysics(); if( selected ) { @@ -1059,7 +1060,7 @@ void StealthUpdate::changeVisualDisguise() draw->setPosition( self->getPosition() ); draw->setOrientation( self->getOrientation() ); draw->setModelConditionFlags( flags ); - draw->updateDrawable(); + draw->updateDrawable(TheFramePacer->getActualLogicTimeScaleOverFpsRatio()); self->getPhysics()->resetDynamicPhysics(); if (TheGlobalData->m_timeOfDay == TIME_OF_DAY_NIGHT) draw->setIndicatorColor( self->getNightIndicatorColor() ); From ba2eeacb980adb45091a54cf14f03fc49b37776e Mon Sep 17 00:00:00 2001 From: Bobby Battista Date: Fri, 18 Sep 2026 01:08:43 -0400 Subject: [PATCH 6/6] refactor(drawable): Replicate fade review changes to Generals --- .../Code/GameEngine/Include/GameClient/Drawable.h | 4 ++-- .../Code/GameEngine/Source/GameClient/Drawable.cpp | 13 +++++++------ .../GameEngine/Source/GameClient/GameClient.cpp | 4 +++- .../GameLogic/Object/Update/StealthUpdate.cpp | 5 +++-- 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/Generals/Code/GameEngine/Include/GameClient/Drawable.h b/Generals/Code/GameEngine/Include/GameClient/Drawable.h index a621d1051a8..11341b9b52e 100644 --- a/Generals/Code/GameEngine/Include/GameClient/Drawable.h +++ b/Generals/Code/GameEngine/Include/GameClient/Drawable.h @@ -412,7 +412,7 @@ class Drawable : public Thing, const Matrix3D *getTransformMatrix() const; ///< return the world transform void draw(); ///< render the drawable to the given view - void updateDrawable(); ///< update the drawable + void updateDrawable(Real timeScale); ///< update the drawable void drawIconUI(); ///< draw "icon"(s) needed on drawable (health bars, veterency, etc) @@ -687,7 +687,7 @@ class Drawable : public Thing, FADING_OUT }; FadingMode m_fadeMode; - Real m_timeElapsedFade; ///< for how long have i been fading (in 30fps-equivalent frames) + Real m_timeElapsedFade; ///< for how many logic frames - incl. fractional ones - have i been fading UnsignedInt m_timeToFade; ///< how slowly am I fading UnsignedInt m_shroudClearFrame; ///< Last frame the local player saw this drawable "OBJECTSHROUD_CLEAR" diff --git a/Generals/Code/GameEngine/Source/GameClient/Drawable.cpp b/Generals/Code/GameEngine/Source/GameClient/Drawable.cpp index e968fe8a4a4..86e05cd7b90 100644 --- a/Generals/Code/GameEngine/Source/GameClient/Drawable.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/Drawable.cpp @@ -1125,7 +1125,7 @@ void Drawable::imitateStealthLook( Drawable& otherDraw ) /** update is called once per frame */ //------------------------------------------------------------------------------------------------- //DECLARE_PERF_TIMER(updateDrawable) -void Drawable::updateDrawable() +void Drawable::updateDrawable(Real timeScale) { //USE_PERF_TIMER(updateDrawable) @@ -1146,15 +1146,16 @@ void Drawable::updateDrawable() { Real numer = (m_fadeMode == FADING_IN) ? (m_timeElapsedFade) : (m_timeToFade-m_timeElapsedFade); - setDrawableOpacity(numer/(Real)m_timeToFade); + Real opacity = numer/(Real)m_timeToFade; // TheSuperHackers @bugfix bobtista 15/09/2026 Decouple Drawable fade timing from render updates. - m_timeElapsedFade += TheFramePacer->getActualLogicTimeScaleOverFpsRatio(); + m_timeElapsedFade += timeScale; if (m_timeElapsedFade > m_timeToFade) { - setDrawableOpacity(m_fadeMode == FADING_IN ? 1.0f : 0.0f); + opacity = m_fadeMode == FADING_IN ? 1.0f : 0.0f; m_fadeMode = FADING_NONE; } + setDrawableOpacity(opacity); } } @@ -1170,7 +1171,7 @@ void Drawable::updateDrawable() //LERP (*dm)->setTerrainDecalOpacity(m_decalOpacity); // TheSuperHackers @bugfix bobtista 15/09/2026 Decouple decal opacity fade timing from render updates. - m_decalOpacity += m_decalOpacityFadeRate * TheFramePacer->getActualLogicTimeScaleOverFpsRatio(); + m_decalOpacity += m_decalOpacityFadeRate * timeScale; } //--------------- @@ -4850,7 +4851,7 @@ void Drawable::xferDrawableModules( Xfer *xfer ) * 6: Added m_ambientSoundEnabledFromScript flag (Added in Zero Hour) * 7: Save the customize ambient sound info (Added in Zero Hour) * 8: TheSuperHackers @bugfix Removed m_prevTintStatus because loading its value is unnecessary and undesirable - * 9: TheSuperHackers @info Preserve fractional fade progress in non-retail saves + * 9: TheSuperHackers @tweak m_timeElapsedFade is now serialized as Real instead of UnsignedInt */ // ------------------------------------------------------------------------------------------------ void Drawable::xfer( Xfer *xfer ) diff --git a/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp b/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp index 7fc03e4e0ea..64e911203af 100644 --- a/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp @@ -33,6 +33,7 @@ // USER INCLUDES ////////////////////////////////////////////////////////////// #include "Common/ActionManager.h" +#include "Common/FramePacer.h" #include "Common/GameEngine.h" #include "Common/GameState.h" #include "Common/Recorder.h" @@ -604,6 +605,7 @@ void GameClient::update() // call the update for all client drawables + const Real timeScale = TheFramePacer->getActualLogicTimeScaleOverFpsRatio(); Drawable* draw = firstDrawable(); while (draw) { // update() could free the Drawable, so go ahead and grab 'next' @@ -651,7 +653,7 @@ void GameClient::update() draw->setFullyObscuredByShroud(ss >= OBJECTSHROUD_FOGGED); } } - draw->updateDrawable(); + draw->updateDrawable(timeScale); draw = next; } } diff --git a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/StealthUpdate.cpp b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/StealthUpdate.cpp index a653701eca8..2034604e7fa 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/StealthUpdate.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/StealthUpdate.cpp @@ -33,6 +33,7 @@ #define DEFINE_OBJECT_STATUS_NAMES // INCLUDES /////////////////////////////////////////////////////////////////////////////////////// +#include "Common/FramePacer.h" #include "Common/GameState.h" #include "Common/GameUtility.h" #include "Common/Player.h" @@ -708,7 +709,7 @@ void StealthUpdate::changeVisualDisguise() draw->setPosition( self->getPosition() ); draw->setOrientation( self->getOrientation() ); draw->setModelConditionFlags( flags ); - draw->updateDrawable(); + draw->updateDrawable(TheFramePacer->getActualLogicTimeScaleOverFpsRatio()); self->getPhysics()->resetDynamicPhysics(); if( selected ) { @@ -762,7 +763,7 @@ void StealthUpdate::changeVisualDisguise() draw->setPosition( self->getPosition() ); draw->setOrientation( self->getOrientation() ); draw->setModelConditionFlags( flags ); - draw->updateDrawable(); + draw->updateDrawable(TheFramePacer->getActualLogicTimeScaleOverFpsRatio()); self->getPhysics()->resetDynamicPhysics(); if (TheGlobalData->m_timeOfDay == TIME_OF_DAY_NIGHT) draw->setIndicatorColor( self->getNightIndicatorColor() );