From 5f9f3fa7ca2609ad8c613a2da062845f4947425d Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Thu, 18 Sep 2025 19:38:04 +0200 Subject: [PATCH 1/2] fix(view): Prevent moving the camera with most user inputs during camera playback in Replay playback --- GeneralsMD/Code/GameEngine/Include/GameClient/View.h | 3 +++ GeneralsMD/Code/GameEngine/Source/GameClient/View.cpp | 8 ++++++++ .../Source/GameLogic/System/GameLogicDispatch.cpp | 3 +++ .../Source/W3DDevice/GameClient/W3DView.cpp | 4 ++++ 4 files changed, 18 insertions(+) diff --git a/GeneralsMD/Code/GameEngine/Include/GameClient/View.h b/GeneralsMD/Code/GameEngine/Include/GameClient/View.h index b204b908e11..d78c3884247 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameClient/View.h +++ b/GeneralsMD/Code/GameEngine/Include/GameClient/View.h @@ -131,6 +131,7 @@ class View : public Snapshot virtual void setOrigin( Int x, Int y) { m_originX=x; m_originY=y;} ///< Sets location of top-left view corner on display virtual void getOrigin( Int *x, Int *y) { *x=m_originX; *y=m_originY;} ///< Return location of top-left view corner on display + virtual void lockViewUntilFrame(UnsignedInt frame); ///< Locks the current view until the given frame is reached. virtual void forceRedraw() = 0; virtual void lookAt( const Coord3D *o ); ///< Center the view on the given coordinate @@ -259,6 +260,8 @@ class View : public Snapshot UnsignedInt m_id; ///< Rhe ID of this view static UnsignedInt m_idNext; ///< Used for allocating view ID's for all views + UnsignedInt m_viewLockedUntilFrame; + Coord3D m_pos; ///< Position of this view, in world coordinates Int m_width, m_height; ///< Dimensions of the view Int m_originX, m_originY; ///< Location of top/left view corner diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/View.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/View.cpp index 7d49cb9a7f0..f32bdc71575 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/View.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/View.cpp @@ -43,6 +43,7 @@ View::View( void ) { //Added By Sadullah Nader //Initialization(s) inserted + m_viewLockedUntilFrame = 0u; m_currentHeightAboveGround = 0.0f; m_defaultAngle = 0.0f; m_defaultPitchAngle = 0.0f; @@ -110,6 +111,8 @@ void View::reset( void ) { // Only fixing the reported bug. Who knows what side effects resetting the rest could have. m_zoomLimited = TRUE; + + m_viewLockedUntilFrame = 0u; } /** @@ -126,6 +129,11 @@ void View::zoom( Real height ) setHeightAboveGround(getHeightAboveGround() + height); } +void View::lockViewUntilFrame(UnsignedInt frame) +{ + m_viewLockedUntilFrame = frame; +} + /** * Center the view on the given coordinate. */ diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogicDispatch.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogicDispatch.cpp index 03722719892..889b7a3ca53 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogicDispatch.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogicDispatch.cpp @@ -1901,6 +1901,9 @@ void GameLogic::logicMessageDispatcher( GameMessage *msg, void *userData ) loc.init(pos.x, pos.y, pos.z, angle, pitch, zoom); TheTacticalView->setLocation( &loc ); + // TheSuperHackers @fix xezon 18/09/2025 Lock the new location to avoid user input from changing the camera in this frame. + TheTacticalView->lockViewUntilFrame( getFrame() + 1 ); + if (!TheLookAtTranslator->hasMouseMovedRecently()) { TheMouse->setCursor( (Mouse::MouseCursor)(msg->getArgument( 4 )->integer) ); diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp index 49909a61422..c4e22165672 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp @@ -544,6 +544,10 @@ void W3DView::setCameraTransform( void ) { if (TheGlobalData->m_headless) return; + + if (m_viewLockedUntilFrame > TheGameClient->getFrame()) + return; + m_cameraHasMovedSinceRequest = true; Matrix3D cameraTransform( 1 ); From 28c0d7f02e3c5ea47d62c97572afb3273653e96a Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Sat, 20 Sep 2025 12:50:44 +0200 Subject: [PATCH 2/2] Replicate in Generals --- Generals/Code/GameEngine/Include/GameClient/View.h | 3 +++ Generals/Code/GameEngine/Source/GameClient/View.cpp | 8 ++++++++ .../Source/GameLogic/System/GameLogicDispatch.cpp | 3 +++ .../Source/W3DDevice/GameClient/W3DView.cpp | 4 ++++ 4 files changed, 18 insertions(+) diff --git a/Generals/Code/GameEngine/Include/GameClient/View.h b/Generals/Code/GameEngine/Include/GameClient/View.h index ae60609b1e0..0b426e64652 100644 --- a/Generals/Code/GameEngine/Include/GameClient/View.h +++ b/Generals/Code/GameEngine/Include/GameClient/View.h @@ -131,6 +131,7 @@ class View : public Snapshot virtual void setOrigin( Int x, Int y) { m_originX=x; m_originY=y;} ///< Sets location of top-left view corner on display virtual void getOrigin( Int *x, Int *y) { *x=m_originX; *y=m_originY;} ///< Return location of top-left view corner on display + virtual void lockViewUntilFrame(UnsignedInt frame); ///< Locks the current view until the given frame is reached. virtual void forceRedraw() = 0; virtual void lookAt( const Coord3D *o ); ///< Center the view on the given coordinate @@ -255,6 +256,8 @@ class View : public Snapshot UnsignedInt m_id; ///< Rhe ID of this view static UnsignedInt m_idNext; ///< Used for allocating view ID's for all views + UnsignedInt m_viewLockedUntilFrame; + Coord3D m_pos; ///< Position of this view, in world coordinates Int m_width, m_height; ///< Dimensions of the view Int m_originX, m_originY; ///< Location of top/left view corner diff --git a/Generals/Code/GameEngine/Source/GameClient/View.cpp b/Generals/Code/GameEngine/Source/GameClient/View.cpp index c7c16c651ac..caddaedb75e 100644 --- a/Generals/Code/GameEngine/Source/GameClient/View.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/View.cpp @@ -43,6 +43,7 @@ View::View( void ) { //Added By Sadullah Nader //Initialization(s) inserted + m_viewLockedUntilFrame = 0u; m_currentHeightAboveGround = 0.0f; m_defaultAngle = 0.0f; m_defaultPitchAngle = 0.0f; @@ -110,6 +111,8 @@ void View::reset( void ) { // Only fixing the reported bug. Who knows what side effects resetting the rest could have. m_zoomLimited = TRUE; + + m_viewLockedUntilFrame = 0u; } /** @@ -126,6 +129,11 @@ void View::zoom( Real height ) setHeightAboveGround(getHeightAboveGround() + height); } +void View::lockViewUntilFrame(UnsignedInt frame) +{ + m_viewLockedUntilFrame = frame; +} + /** * Center the view on the given coordinate. */ diff --git a/Generals/Code/GameEngine/Source/GameLogic/System/GameLogicDispatch.cpp b/Generals/Code/GameEngine/Source/GameLogic/System/GameLogicDispatch.cpp index b2f16ae9fcc..3ffbd73acd3 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/System/GameLogicDispatch.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/System/GameLogicDispatch.cpp @@ -1873,6 +1873,9 @@ void GameLogic::logicMessageDispatcher( GameMessage *msg, void *userData ) loc.init(pos.x, pos.y, pos.z, angle, pitch, zoom); TheTacticalView->setLocation( &loc ); + // TheSuperHackers @fix xezon 18/09/2025 Lock the new location to avoid user input from changing the camera in this frame. + TheTacticalView->lockViewUntilFrame( getFrame() + 1 ); + if (!TheLookAtTranslator->hasMouseMovedRecently()) { TheMouse->setCursor( (Mouse::MouseCursor)(msg->getArgument( 4 )->integer) ); diff --git a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp index 5e9875b3d70..5e80699000c 100644 --- a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp +++ b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp @@ -413,6 +413,10 @@ void W3DView::setCameraTransform( void ) { if (TheGlobalData->m_headless) return; + + if (m_viewLockedUntilFrame > TheGameClient->getFrame()) + return; + m_cameraHasMovedSinceRequest = true; Matrix3D cameraTransform( 1 );