From 54ab35465e823cf1f9dfd1926d0d510d4ca1d012 Mon Sep 17 00:00:00 2001 From: Bobby Battista Date: Fri, 19 Dec 2025 16:40:53 -0500 Subject: [PATCH 01/13] fix(input): Convert double-click fast drive timing from frames to real-time milliseconds --- .../Module/ParticleUplinkCannonUpdate.h | 8 ++- .../Update/ParticleUplinkCannonUpdate.cpp | 51 +++++++++++++++++-- 2 files changed, 52 insertions(+), 7 deletions(-) diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/ParticleUplinkCannonUpdate.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/ParticleUplinkCannonUpdate.h index a022329ba1..9ab722ab19 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/ParticleUplinkCannonUpdate.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/ParticleUplinkCannonUpdate.h @@ -227,8 +227,12 @@ class ParticleUplinkCannonUpdate : public SpecialPowerUpdateModule UnsignedInt m_nextDamagePulseFrame; UnsignedInt m_startAttackFrame; UnsignedInt m_startDecayFrame; - UnsignedInt m_lastDrivingClickFrame; - UnsignedInt m_2ndLastDrivingClickFrame; +#if RETAIL_COMPATIBLE_XFER_SAVE + UnsignedInt m_lastDrivingClickFrame; // Frame number for retail compatibility + UnsignedInt m_2ndLastDrivingClickFrame; // Frame number for retail compatibility +#endif + UnsignedInt m_lastDrivingClickTimeMsec; // Real-time milliseconds + UnsignedInt m_2ndLastDrivingClickTimeMsec; // Real-time milliseconds UnsignedInt m_nextDestWaypointID; XferVersion m_xferVersion; diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp index bb41f47e12..125bd5c01e 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp @@ -185,8 +185,12 @@ ParticleUplinkCannonUpdate::ParticleUplinkCannonUpdate( Thing *thing, const Modu m_nextDamagePulseFrame = 0; m_startAttackFrame = 0; m_startDecayFrame = 0; +#if RETAIL_COMPATIBLE_XFER_SAVE m_lastDrivingClickFrame = 0; m_2ndLastDrivingClickFrame = 0; +#endif + m_lastDrivingClickTimeMsec = 0; + m_2ndLastDrivingClickTimeMsec = 0; m_clientShroudedLastFrame = FALSE; for( Int i = 0; i < MAX_OUTER_NODES; i++ ) @@ -375,8 +379,12 @@ void ParticleUplinkCannonUpdate::setSpecialPowerOverridableDestination( const Co { m_overrideTargetDestination = *loc; m_manualTargetMode = TRUE; +#if RETAIL_COMPATIBLE_XFER_SAVE m_2ndLastDrivingClickFrame = m_lastDrivingClickFrame; m_lastDrivingClickFrame = TheGameLogic->getFrame(); +#endif + m_2ndLastDrivingClickTimeMsec = m_lastDrivingClickTimeMsec; + m_lastDrivingClickTimeMsec = timeGetTime(); } } @@ -568,7 +576,11 @@ UpdateSleepTime ParticleUplinkCannonUpdate::update() else { Real speed = data->m_manualDrivingSpeed; - if( m_scriptedWaypointMode || m_lastDrivingClickFrame - m_2ndLastDrivingClickFrame < data->m_doubleClickToFastDriveDelay ) +#if !RETAIL_COMPATIBLE_CRC + if( m_scriptedWaypointMode || (m_lastDrivingClickTimeMsec != 0 && m_2ndLastDrivingClickTimeMsec != 0 && m_lastDrivingClickTimeMsec - m_2ndLastDrivingClickTimeMsec < data->m_doubleClickToFastDriveDelay) ) +#else + if( m_scriptedWaypointMode || (m_lastDrivingClickFrame - m_2ndLastDrivingClickFrame < data->m_doubleClickToFastDriveDelay) ) +#endif { //Because we double clicked, use the faster driving speed. speed = data->m_manualFastDrivingSpeed; @@ -1397,6 +1409,7 @@ void ParticleUplinkCannonUpdate::crc( Xfer *xfer ) * 2: Serialize decay frames * 3: Serialize scripted waypoints (Added for Zero Hour) * 4: TheSuperHackers @tweak Serialize orbit to target laser radius + * 5: TheSuperHackers @tweak Changed m_lastDrivingClickFrame to m_lastDrivingClickTimeMsec (frames to milliseconds) */ // ------------------------------------------------------------------------------------------------ void ParticleUplinkCannonUpdate::xfer( Xfer *xfer ) @@ -1407,7 +1420,7 @@ void ParticleUplinkCannonUpdate::xfer( Xfer *xfer ) #if RETAIL_COMPATIBLE_XFER_SAVE const XferVersion currentVersion = 3; #else - const XferVersion currentVersion = 4; + const XferVersion currentVersion = 5; #endif XferVersion version = currentVersion; xfer->xferVersion( &version, currentVersion ); @@ -1504,11 +1517,39 @@ void ParticleUplinkCannonUpdate::xfer( Xfer *xfer ) m_startDecayFrame = m_startAttackFrame + data->m_totalFiringFrames; } - // the time of last manual target click + // the time of last manual target click (milliseconds) +#if RETAIL_COMPATIBLE_XFER_SAVE + // Retail builds stay at version 3 for compatibility, so always use old frame format xfer->xferUnsignedInt( & m_lastDrivingClickFrame ); - - // the time of the 2nd last manual target click xfer->xferUnsignedInt( &m_2ndLastDrivingClickFrame ); +#if !RETAIL_COMPATIBLE_CRC + if( xfer->getXferMode() == XFER_LOAD ) + { + // Can't convert frames to milliseconds accurately, so set to 0 + m_lastDrivingClickTimeMsec = 0; + m_2ndLastDrivingClickTimeMsec = 0; + } +#endif +#else + if( version >= 5 ) + { + xfer->xferUnsignedInt( & m_lastDrivingClickTimeMsec ); + xfer->xferUnsignedInt( &m_2ndLastDrivingClickTimeMsec ); + } + else + { + // Old versions stored frame numbers, which we can't meaningfully convert to milliseconds + UnsignedInt oldLastDrivingClickFrame = 0; + UnsignedInt old2ndLastDrivingClickFrame = 0; + xfer->xferUnsignedInt( &oldLastDrivingClickFrame ); + xfer->xferUnsignedInt( &old2ndLastDrivingClickFrame ); + if( xfer->getXferMode() == XFER_LOAD ) + { + m_lastDrivingClickTimeMsec = 0; + m_2ndLastDrivingClickTimeMsec = 0; + } + } +#endif if( version >= 3 ) { From 2947b70df1b74af25c2b415d9023ed300ca16ca1 Mon Sep 17 00:00:00 2001 From: Bobby Battista Date: Sat, 20 Dec 2025 15:17:06 -0500 Subject: [PATCH 02/13] refactor(input): Extract double-click condition to variable in ParticleUplinkCannon --- .../GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp | 3 ++- .../GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp index 70860c672b..6c30470cc7 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp @@ -518,7 +518,8 @@ UpdateSleepTime ParticleUplinkCannonUpdate::update() else { Real speed = data->m_manualDrivingSpeed; - if( m_lastDrivingClickFrame - m_2ndLastDrivingClickFrame < data->m_doubleClickToFastDriveDelay ) + const Bool useFasterSpeed = m_lastDrivingClickFrame - m_2ndLastDrivingClickFrame < data->m_doubleClickToFastDriveDelay; + if( useFasterSpeed ) { //Because we double clicked, use the faster driving speed. speed = data->m_manualFastDrivingSpeed; diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp index 125bd5c01e..9e4c887c68 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp @@ -577,10 +577,11 @@ UpdateSleepTime ParticleUplinkCannonUpdate::update() { Real speed = data->m_manualDrivingSpeed; #if !RETAIL_COMPATIBLE_CRC - if( m_scriptedWaypointMode || (m_lastDrivingClickTimeMsec != 0 && m_2ndLastDrivingClickTimeMsec != 0 && m_lastDrivingClickTimeMsec - m_2ndLastDrivingClickTimeMsec < data->m_doubleClickToFastDriveDelay) ) + const Bool useFasterSpeed = m_scriptedWaypointMode || (m_lastDrivingClickTimeMsec != 0 && m_2ndLastDrivingClickTimeMsec != 0 && m_lastDrivingClickTimeMsec - m_2ndLastDrivingClickTimeMsec < data->m_doubleClickToFastDriveDelay); #else - if( m_scriptedWaypointMode || (m_lastDrivingClickFrame - m_2ndLastDrivingClickFrame < data->m_doubleClickToFastDriveDelay) ) + const Bool useFasterSpeed = m_scriptedWaypointMode || (m_lastDrivingClickFrame - m_2ndLastDrivingClickFrame < data->m_doubleClickToFastDriveDelay); #endif + if( useFasterSpeed ) { //Because we double clicked, use the faster driving speed. speed = data->m_manualFastDrivingSpeed; From a9473e46e477ef028a9950b68b14c702e6474cd0 Mon Sep 17 00:00:00 2001 From: Bobby Battista Date: Sat, 20 Dec 2025 15:17:43 -0500 Subject: [PATCH 03/13] style: Fix spacing inconsistency in ParticleUplinkCannon xfer function --- .../GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp | 2 +- .../GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp index 6c30470cc7..3ba21da564 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp @@ -1421,7 +1421,7 @@ void ParticleUplinkCannonUpdate::xfer( Xfer *xfer ) } // the time of last manual target click - xfer->xferUnsignedInt( & m_lastDrivingClickFrame ); + xfer->xferUnsignedInt( &m_lastDrivingClickFrame ); // the time of the 2nd last manual target click xfer->xferUnsignedInt( &m_2ndLastDrivingClickFrame ); diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp index 9e4c887c68..de786e14a4 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp @@ -1521,7 +1521,7 @@ void ParticleUplinkCannonUpdate::xfer( Xfer *xfer ) // the time of last manual target click (milliseconds) #if RETAIL_COMPATIBLE_XFER_SAVE // Retail builds stay at version 3 for compatibility, so always use old frame format - xfer->xferUnsignedInt( & m_lastDrivingClickFrame ); + xfer->xferUnsignedInt( &m_lastDrivingClickFrame ); xfer->xferUnsignedInt( &m_2ndLastDrivingClickFrame ); #if !RETAIL_COMPATIBLE_CRC if( xfer->getXferMode() == XFER_LOAD ) @@ -1534,7 +1534,7 @@ void ParticleUplinkCannonUpdate::xfer( Xfer *xfer ) #else if( version >= 5 ) { - xfer->xferUnsignedInt( & m_lastDrivingClickTimeMsec ); + xfer->xferUnsignedInt( &m_lastDrivingClickTimeMsec ); xfer->xferUnsignedInt( &m_2ndLastDrivingClickTimeMsec ); } else From ca97546aac790aaadb5820612311c5fadb9ff10a Mon Sep 17 00:00:00 2001 From: Bobby Battista Date: Sat, 20 Dec 2025 15:18:18 -0500 Subject: [PATCH 04/13] refactor: Make millisecond variables conditional in ParticleUplinkCannon retail builds --- .../Module/ParticleUplinkCannonUpdate.h | 7 +++--- .../Update/ParticleUplinkCannonUpdate.cpp | 22 +++++++------------ 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/ParticleUplinkCannonUpdate.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/ParticleUplinkCannonUpdate.h index 9ab722ab19..fed305aa1f 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/ParticleUplinkCannonUpdate.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/ParticleUplinkCannonUpdate.h @@ -227,12 +227,13 @@ class ParticleUplinkCannonUpdate : public SpecialPowerUpdateModule UnsignedInt m_nextDamagePulseFrame; UnsignedInt m_startAttackFrame; UnsignedInt m_startDecayFrame; -#if RETAIL_COMPATIBLE_XFER_SAVE - UnsignedInt m_lastDrivingClickFrame; // Frame number for retail compatibility +#if RETAIL_COMPATIBLE_CRC || RETAIL_COMPATIBLE_XFER_SAVE + UnsignedInt m_lastDrivingClickFrame; // Frame number for retail compatibility UnsignedInt m_2ndLastDrivingClickFrame; // Frame number for retail compatibility -#endif +#else UnsignedInt m_lastDrivingClickTimeMsec; // Real-time milliseconds UnsignedInt m_2ndLastDrivingClickTimeMsec; // Real-time milliseconds +#endif UnsignedInt m_nextDestWaypointID; XferVersion m_xferVersion; diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp index de786e14a4..91dd602800 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp @@ -185,12 +185,13 @@ ParticleUplinkCannonUpdate::ParticleUplinkCannonUpdate( Thing *thing, const Modu m_nextDamagePulseFrame = 0; m_startAttackFrame = 0; m_startDecayFrame = 0; -#if RETAIL_COMPATIBLE_XFER_SAVE +#if RETAIL_COMPATIBLE_CRC || RETAIL_COMPATIBLE_XFER_SAVE m_lastDrivingClickFrame = 0; m_2ndLastDrivingClickFrame = 0; -#endif +#else m_lastDrivingClickTimeMsec = 0; m_2ndLastDrivingClickTimeMsec = 0; +#endif m_clientShroudedLastFrame = FALSE; for( Int i = 0; i < MAX_OUTER_NODES; i++ ) @@ -379,12 +380,13 @@ void ParticleUplinkCannonUpdate::setSpecialPowerOverridableDestination( const Co { m_overrideTargetDestination = *loc; m_manualTargetMode = TRUE; -#if RETAIL_COMPATIBLE_XFER_SAVE +#if RETAIL_COMPATIBLE_CRC || RETAIL_COMPATIBLE_XFER_SAVE m_2ndLastDrivingClickFrame = m_lastDrivingClickFrame; m_lastDrivingClickFrame = TheGameLogic->getFrame(); -#endif +#else m_2ndLastDrivingClickTimeMsec = m_lastDrivingClickTimeMsec; m_lastDrivingClickTimeMsec = timeGetTime(); +#endif } } @@ -1518,19 +1520,11 @@ void ParticleUplinkCannonUpdate::xfer( Xfer *xfer ) m_startDecayFrame = m_startAttackFrame + data->m_totalFiringFrames; } - // the time of last manual target click (milliseconds) -#if RETAIL_COMPATIBLE_XFER_SAVE + // the time of last manual target click +#if RETAIL_COMPATIBLE_CRC || RETAIL_COMPATIBLE_XFER_SAVE // Retail builds stay at version 3 for compatibility, so always use old frame format xfer->xferUnsignedInt( &m_lastDrivingClickFrame ); xfer->xferUnsignedInt( &m_2ndLastDrivingClickFrame ); -#if !RETAIL_COMPATIBLE_CRC - if( xfer->getXferMode() == XFER_LOAD ) - { - // Can't convert frames to milliseconds accurately, so set to 0 - m_lastDrivingClickTimeMsec = 0; - m_2ndLastDrivingClickTimeMsec = 0; - } -#endif #else if( version >= 5 ) { From c0547afaad72b6138eacac859ef6a8768de6ccaf Mon Sep 17 00:00:00 2001 From: Bobby Battista Date: Sun, 21 Dec 2025 14:30:05 -0500 Subject: [PATCH 05/13] fix(input): Fix double-click fast drive timing in ParticleUplinkCannon --- .../GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp index 91dd602800..34ab87d647 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp @@ -578,10 +578,10 @@ UpdateSleepTime ParticleUplinkCannonUpdate::update() else { Real speed = data->m_manualDrivingSpeed; -#if !RETAIL_COMPATIBLE_CRC - const Bool useFasterSpeed = m_scriptedWaypointMode || (m_lastDrivingClickTimeMsec != 0 && m_2ndLastDrivingClickTimeMsec != 0 && m_lastDrivingClickTimeMsec - m_2ndLastDrivingClickTimeMsec < data->m_doubleClickToFastDriveDelay); +#if RETAIL_COMPATIBLE_CRC + const Bool useFasterSpeed = m_scriptedWaypointMode || (m_lastDrivingClickFrame != 0 && m_2ndLastDrivingClickFrame != 0 && m_lastDrivingClickFrame - m_2ndLastDrivingClickFrame < data->m_doubleClickToFastDriveDelay); #else - const Bool useFasterSpeed = m_scriptedWaypointMode || (m_lastDrivingClickFrame - m_2ndLastDrivingClickFrame < data->m_doubleClickToFastDriveDelay); + const Bool useFasterSpeed = m_scriptedWaypointMode || (m_lastDrivingClickTimeMsec != 0 && m_2ndLastDrivingClickTimeMsec != 0 && m_lastDrivingClickTimeMsec - m_2ndLastDrivingClickTimeMsec < data->m_doubleClickToFastDriveDelay); #endif if( useFasterSpeed ) { From 5ef7b71ab16103df3a01d2876431dee605c16dc8 Mon Sep 17 00:00:00 2001 From: Bobby Battista Date: Sun, 21 Dec 2025 14:37:01 -0500 Subject: [PATCH 06/13] Replicate to generals --- .../Module/ParticleUplinkCannonUpdate.h | 9 +++- .../Update/ParticleUplinkCannonUpdate.cpp | 51 +++++++++++++++++-- 2 files changed, 53 insertions(+), 7 deletions(-) diff --git a/Generals/Code/GameEngine/Include/GameLogic/Module/ParticleUplinkCannonUpdate.h b/Generals/Code/GameEngine/Include/GameLogic/Module/ParticleUplinkCannonUpdate.h index 9101cd2a58..8a5d9ada50 100644 --- a/Generals/Code/GameEngine/Include/GameLogic/Module/ParticleUplinkCannonUpdate.h +++ b/Generals/Code/GameEngine/Include/GameLogic/Module/ParticleUplinkCannonUpdate.h @@ -225,8 +225,13 @@ class ParticleUplinkCannonUpdate : public UpdateModule, public SpecialPowerUpdat UnsignedInt m_nextDamagePulseFrame; UnsignedInt m_startAttackFrame; UnsignedInt m_startDecayFrame; - UnsignedInt m_lastDrivingClickFrame; - UnsignedInt m_2ndLastDrivingClickFrame; +#if RETAIL_COMPATIBLE_CRC || RETAIL_COMPATIBLE_XFER_SAVE + UnsignedInt m_lastDrivingClickFrame; // Frame number for retail compatibility + UnsignedInt m_2ndLastDrivingClickFrame; // Frame number for retail compatibility +#else + UnsignedInt m_lastDrivingClickTimeMsec; // Real-time milliseconds + UnsignedInt m_2ndLastDrivingClickTimeMsec; // Real-time milliseconds +#endif XferVersion m_xferVersion; diff --git a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp index 3ba21da564..2063a33453 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp @@ -184,8 +184,13 @@ ParticleUplinkCannonUpdate::ParticleUplinkCannonUpdate( Thing *thing, const Modu m_nextDamagePulseFrame = 0; m_startAttackFrame = 0; m_startDecayFrame = 0; +#if RETAIL_COMPATIBLE_CRC || RETAIL_COMPATIBLE_XFER_SAVE m_lastDrivingClickFrame = 0; m_2ndLastDrivingClickFrame = 0; +#else + m_lastDrivingClickTimeMsec = 0; + m_2ndLastDrivingClickTimeMsec = 0; +#endif m_clientShroudedLastFrame = FALSE; for( Int i = 0; i < MAX_OUTER_NODES; i++ ) @@ -325,8 +330,13 @@ void ParticleUplinkCannonUpdate::setSpecialPowerOverridableDestination( const Co { m_overrideTargetDestination = *loc; m_manualTargetMode = true; +#if RETAIL_COMPATIBLE_CRC || RETAIL_COMPATIBLE_XFER_SAVE m_2ndLastDrivingClickFrame = m_lastDrivingClickFrame; m_lastDrivingClickFrame = TheGameLogic->getFrame(); +#else + m_2ndLastDrivingClickTimeMsec = m_lastDrivingClickTimeMsec; + m_lastDrivingClickTimeMsec = timeGetTime(); +#endif } } @@ -518,7 +528,11 @@ UpdateSleepTime ParticleUplinkCannonUpdate::update() else { Real speed = data->m_manualDrivingSpeed; - const Bool useFasterSpeed = m_lastDrivingClickFrame - m_2ndLastDrivingClickFrame < data->m_doubleClickToFastDriveDelay; +#if RETAIL_COMPATIBLE_CRC + const Bool useFasterSpeed = m_lastDrivingClickFrame != 0 && m_2ndLastDrivingClickFrame != 0 && m_lastDrivingClickFrame - m_2ndLastDrivingClickFrame < data->m_doubleClickToFastDriveDelay; +#else + const Bool useFasterSpeed = m_lastDrivingClickTimeMsec != 0 && m_2ndLastDrivingClickTimeMsec != 0 && m_lastDrivingClickTimeMsec - m_2ndLastDrivingClickTimeMsec < data->m_doubleClickToFastDriveDelay; +#endif if( useFasterSpeed ) { //Because we double clicked, use the faster driving speed. @@ -1312,7 +1326,9 @@ void ParticleUplinkCannonUpdate::crc( Xfer *xfer ) * Version Info: * 1: Initial version * 2: Serialize decay frames + * 3: TheSuperHackers @tweak Added m_manualTargetMode * 4: TheSuperHackers @tweak Serialize orbit to target laser radius + * 5: TheSuperHackers @tweak Changed m_lastDrivingClickFrame to m_lastDrivingClickTimeMsec (frames to milliseconds) */ // ------------------------------------------------------------------------------------------------ void ParticleUplinkCannonUpdate::xfer( Xfer *xfer ) @@ -1320,10 +1336,10 @@ void ParticleUplinkCannonUpdate::xfer( Xfer *xfer ) const ParticleUplinkCannonUpdateModuleData *data = getParticleUplinkCannonUpdateModuleData(); // version -#if RETAIL_COMPATIBLE_XFER_SAVE +#if RETAIL_COMPATIBLE_CRC || RETAIL_COMPATIBLE_XFER_SAVE const XferVersion currentVersion = 2; #else - const XferVersion currentVersion = 4; + const XferVersion currentVersion = 5; #endif XferVersion version = currentVersion; xfer->xferVersion( &version, currentVersion ); @@ -1421,10 +1437,35 @@ void ParticleUplinkCannonUpdate::xfer( Xfer *xfer ) } // the time of last manual target click +#if RETAIL_COMPATIBLE_CRC || RETAIL_COMPATIBLE_XFER_SAVE + // Retail builds stay at version 3 for compatibility, so always use old frame format xfer->xferUnsignedInt( &m_lastDrivingClickFrame ); - - // the time of the 2nd last manual target click xfer->xferUnsignedInt( &m_2ndLastDrivingClickFrame ); +#else + if( version >= 5 ) + { + xfer->xferUnsignedInt( &m_lastDrivingClickTimeMsec ); + xfer->xferUnsignedInt( &m_2ndLastDrivingClickTimeMsec ); + } + else + { + // Old versions stored frame numbers, which we can't meaningfully convert to milliseconds + UnsignedInt oldLastDrivingClickFrame = 0; + UnsignedInt old2ndLastDrivingClickFrame = 0; + xfer->xferUnsignedInt( &oldLastDrivingClickFrame ); + xfer->xferUnsignedInt( &old2ndLastDrivingClickFrame ); + if( xfer->getXferMode() == XFER_LOAD ) + { + m_lastDrivingClickTimeMsec = 0; + m_2ndLastDrivingClickTimeMsec = 0; + } + } +#endif + + if( version >= 3 ) + { + xfer->xferBool( &m_manualTargetMode ); + } if( version >= 4 ) { From 933adbc5c7681101d7e68519d3bf9652113bdbf0 Mon Sep 17 00:00:00 2001 From: Bobby Battista Date: Sun, 21 Dec 2025 18:53:48 -0500 Subject: [PATCH 07/13] refactor(input): Remove unnecessary null checks from double-click timing, add debug assertions --- .../GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp | 6 ++++-- .../GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp index 2063a33453..7f9153844f 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp @@ -529,9 +529,11 @@ UpdateSleepTime ParticleUplinkCannonUpdate::update() { Real speed = data->m_manualDrivingSpeed; #if RETAIL_COMPATIBLE_CRC - const Bool useFasterSpeed = m_lastDrivingClickFrame != 0 && m_2ndLastDrivingClickFrame != 0 && m_lastDrivingClickFrame - m_2ndLastDrivingClickFrame < data->m_doubleClickToFastDriveDelay; + DEBUG_ASSERTCRASH(m_lastDrivingClickFrame >= m_2ndLastDrivingClickFrame, ("m_lastDrivingClickFrame should always be >= m_2ndLastDrivingClickFrame")); + const Bool useFasterSpeed = m_lastDrivingClickFrame - m_2ndLastDrivingClickFrame < data->m_doubleClickToFastDriveDelay; #else - const Bool useFasterSpeed = m_lastDrivingClickTimeMsec != 0 && m_2ndLastDrivingClickTimeMsec != 0 && m_lastDrivingClickTimeMsec - m_2ndLastDrivingClickTimeMsec < data->m_doubleClickToFastDriveDelay; + DEBUG_ASSERTCRASH(m_lastDrivingClickTimeMsec >= m_2ndLastDrivingClickTimeMsec, ("m_lastDrivingClickTimeMsec should always be >= m_2ndLastDrivingClickTimeMsec")); + const Bool useFasterSpeed = m_lastDrivingClickTimeMsec - m_2ndLastDrivingClickTimeMsec < data->m_doubleClickToFastDriveDelay; #endif if( useFasterSpeed ) { diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp index 34ab87d647..e4536d6863 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp @@ -579,9 +579,11 @@ UpdateSleepTime ParticleUplinkCannonUpdate::update() { Real speed = data->m_manualDrivingSpeed; #if RETAIL_COMPATIBLE_CRC - const Bool useFasterSpeed = m_scriptedWaypointMode || (m_lastDrivingClickFrame != 0 && m_2ndLastDrivingClickFrame != 0 && m_lastDrivingClickFrame - m_2ndLastDrivingClickFrame < data->m_doubleClickToFastDriveDelay); + DEBUG_ASSERTCRASH(m_lastDrivingClickFrame >= m_2ndLastDrivingClickFrame, ("m_lastDrivingClickFrame should always be >= m_2ndLastDrivingClickFrame")); + const Bool useFasterSpeed = m_scriptedWaypointMode || (m_lastDrivingClickFrame - m_2ndLastDrivingClickFrame < data->m_doubleClickToFastDriveDelay); #else - const Bool useFasterSpeed = m_scriptedWaypointMode || (m_lastDrivingClickTimeMsec != 0 && m_2ndLastDrivingClickTimeMsec != 0 && m_lastDrivingClickTimeMsec - m_2ndLastDrivingClickTimeMsec < data->m_doubleClickToFastDriveDelay); + DEBUG_ASSERTCRASH(m_lastDrivingClickTimeMsec >= m_2ndLastDrivingClickTimeMsec, ("m_lastDrivingClickTimeMsec should always be >= m_2ndLastDrivingClickTimeMsec")); + const Bool useFasterSpeed = m_scriptedWaypointMode || (m_lastDrivingClickTimeMsec - m_2ndLastDrivingClickTimeMsec < data->m_doubleClickToFastDriveDelay); #endif if( useFasterSpeed ) { From 8b755a724fb44ff7e90503dca7ad17270d415bf2 Mon Sep 17 00:00:00 2001 From: Bobby Battista Date: Tue, 30 Dec 2025 20:01:29 -0800 Subject: [PATCH 08/13] Use RETAIL_COMPATIBLE_CRC || RETAIL_COMPATIBLE_XFER_SAVE for ParticleUplinkCannon xfer version --- .../GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp index e4536d6863..a714507bb8 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp @@ -1422,7 +1422,7 @@ void ParticleUplinkCannonUpdate::xfer( Xfer *xfer ) const ParticleUplinkCannonUpdateModuleData *data = getParticleUplinkCannonUpdateModuleData(); // version -#if RETAIL_COMPATIBLE_XFER_SAVE +#if RETAIL_COMPATIBLE_CRC || RETAIL_COMPATIBLE_XFER_SAVE const XferVersion currentVersion = 3; #else const XferVersion currentVersion = 5; From e0433f567c10643cea2871ac562fe46498ccd356 Mon Sep 17 00:00:00 2001 From: Bobby Battista Date: Wed, 31 Dec 2025 18:31:20 -0800 Subject: [PATCH 09/13] fix(particle-uplink): use consistent RETAIL_COMPATIBLE macros and fix units mismatch --- .../GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp | 4 ++-- .../GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp index 7f9153844f..727fa49a74 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp @@ -528,12 +528,12 @@ UpdateSleepTime ParticleUplinkCannonUpdate::update() else { Real speed = data->m_manualDrivingSpeed; -#if RETAIL_COMPATIBLE_CRC +#if RETAIL_COMPATIBLE_CRC || RETAIL_COMPATIBLE_XFER_SAVE DEBUG_ASSERTCRASH(m_lastDrivingClickFrame >= m_2ndLastDrivingClickFrame, ("m_lastDrivingClickFrame should always be >= m_2ndLastDrivingClickFrame")); const Bool useFasterSpeed = m_lastDrivingClickFrame - m_2ndLastDrivingClickFrame < data->m_doubleClickToFastDriveDelay; #else DEBUG_ASSERTCRASH(m_lastDrivingClickTimeMsec >= m_2ndLastDrivingClickTimeMsec, ("m_lastDrivingClickTimeMsec should always be >= m_2ndLastDrivingClickTimeMsec")); - const Bool useFasterSpeed = m_lastDrivingClickTimeMsec - m_2ndLastDrivingClickTimeMsec < data->m_doubleClickToFastDriveDelay; + const Bool useFasterSpeed = m_lastDrivingClickTimeMsec - m_2ndLastDrivingClickTimeMsec < data->m_doubleClickToFastDriveDelay * MSEC_PER_LOGICFRAME_REAL; #endif if( useFasterSpeed ) { diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp index a714507bb8..1978868806 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp @@ -578,12 +578,12 @@ UpdateSleepTime ParticleUplinkCannonUpdate::update() else { Real speed = data->m_manualDrivingSpeed; -#if RETAIL_COMPATIBLE_CRC +#if RETAIL_COMPATIBLE_CRC || RETAIL_COMPATIBLE_XFER_SAVE DEBUG_ASSERTCRASH(m_lastDrivingClickFrame >= m_2ndLastDrivingClickFrame, ("m_lastDrivingClickFrame should always be >= m_2ndLastDrivingClickFrame")); const Bool useFasterSpeed = m_scriptedWaypointMode || (m_lastDrivingClickFrame - m_2ndLastDrivingClickFrame < data->m_doubleClickToFastDriveDelay); #else DEBUG_ASSERTCRASH(m_lastDrivingClickTimeMsec >= m_2ndLastDrivingClickTimeMsec, ("m_lastDrivingClickTimeMsec should always be >= m_2ndLastDrivingClickTimeMsec")); - const Bool useFasterSpeed = m_scriptedWaypointMode || (m_lastDrivingClickTimeMsec - m_2ndLastDrivingClickTimeMsec < data->m_doubleClickToFastDriveDelay); + const Bool useFasterSpeed = m_scriptedWaypointMode || (m_lastDrivingClickTimeMsec - m_2ndLastDrivingClickTimeMsec < data->m_doubleClickToFastDriveDelay * MSEC_PER_LOGICFRAME_REAL); #endif if( useFasterSpeed ) { From 7f9bd37387f0cad82c79cce0b9f7c2b9f0bbdcfc Mon Sep 17 00:00:00 2001 From: Bobby Battista Date: Wed, 31 Dec 2025 18:33:03 -0800 Subject: [PATCH 10/13] refactor(particle-uplink): parse double-click delay as milliseconds for non-retail builds --- .../GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp | 6 +++++- .../GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp index 727fa49a74..ed0f8ce728 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp @@ -148,7 +148,11 @@ ParticleUplinkCannonUpdateModuleData::ParticleUplinkCannonUpdateModuleData() { "ManualDrivingSpeed", INI::parseReal, NULL, offsetof( ParticleUplinkCannonUpdateModuleData, m_manualDrivingSpeed ) }, { "ManualFastDrivingSpeed", INI::parseReal, NULL, offsetof( ParticleUplinkCannonUpdateModuleData, m_manualFastDrivingSpeed ) }, +#if RETAIL_COMPATIBLE_CRC || RETAIL_COMPATIBLE_XFER_SAVE { "DoubleClickToFastDriveDelay", INI::parseDurationUnsignedInt, NULL, offsetof( ParticleUplinkCannonUpdateModuleData, m_doubleClickToFastDriveDelay ) }, +#else + { "DoubleClickToFastDriveDelay", INI::parseUnsignedInt, NULL, offsetof( ParticleUplinkCannonUpdateModuleData, m_doubleClickToFastDriveDelay ) }, +#endif { 0, 0, 0, 0 } }; @@ -533,7 +537,7 @@ UpdateSleepTime ParticleUplinkCannonUpdate::update() const Bool useFasterSpeed = m_lastDrivingClickFrame - m_2ndLastDrivingClickFrame < data->m_doubleClickToFastDriveDelay; #else DEBUG_ASSERTCRASH(m_lastDrivingClickTimeMsec >= m_2ndLastDrivingClickTimeMsec, ("m_lastDrivingClickTimeMsec should always be >= m_2ndLastDrivingClickTimeMsec")); - const Bool useFasterSpeed = m_lastDrivingClickTimeMsec - m_2ndLastDrivingClickTimeMsec < data->m_doubleClickToFastDriveDelay * MSEC_PER_LOGICFRAME_REAL; + const Bool useFasterSpeed = m_lastDrivingClickTimeMsec - m_2ndLastDrivingClickTimeMsec < data->m_doubleClickToFastDriveDelay; #endif if( useFasterSpeed ) { diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp index 1978868806..ae589000d3 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp @@ -147,7 +147,11 @@ ParticleUplinkCannonUpdateModuleData::ParticleUplinkCannonUpdateModuleData() { "ManualDrivingSpeed", INI::parseReal, NULL, offsetof( ParticleUplinkCannonUpdateModuleData, m_manualDrivingSpeed ) }, { "ManualFastDrivingSpeed", INI::parseReal, NULL, offsetof( ParticleUplinkCannonUpdateModuleData, m_manualFastDrivingSpeed ) }, +#if RETAIL_COMPATIBLE_CRC || RETAIL_COMPATIBLE_XFER_SAVE { "DoubleClickToFastDriveDelay", INI::parseDurationUnsignedInt, NULL, offsetof( ParticleUplinkCannonUpdateModuleData, m_doubleClickToFastDriveDelay ) }, +#else + { "DoubleClickToFastDriveDelay", INI::parseUnsignedInt, NULL, offsetof( ParticleUplinkCannonUpdateModuleData, m_doubleClickToFastDriveDelay ) }, +#endif { 0, 0, 0, 0 } }; @@ -583,7 +587,7 @@ UpdateSleepTime ParticleUplinkCannonUpdate::update() const Bool useFasterSpeed = m_scriptedWaypointMode || (m_lastDrivingClickFrame - m_2ndLastDrivingClickFrame < data->m_doubleClickToFastDriveDelay); #else DEBUG_ASSERTCRASH(m_lastDrivingClickTimeMsec >= m_2ndLastDrivingClickTimeMsec, ("m_lastDrivingClickTimeMsec should always be >= m_2ndLastDrivingClickTimeMsec")); - const Bool useFasterSpeed = m_scriptedWaypointMode || (m_lastDrivingClickTimeMsec - m_2ndLastDrivingClickTimeMsec < data->m_doubleClickToFastDriveDelay * MSEC_PER_LOGICFRAME_REAL); + const Bool useFasterSpeed = m_scriptedWaypointMode || (m_lastDrivingClickTimeMsec - m_2ndLastDrivingClickTimeMsec < data->m_doubleClickToFastDriveDelay); #endif if( useFasterSpeed ) { From 5c75f5ed45c2f91891b7f98e8a57469ea892cd2c Mon Sep 17 00:00:00 2001 From: Bobby Battista Date: Fri, 2 Jan 2026 11:41:45 -0800 Subject: [PATCH 11/13] nit: update comments to match our format --- .../GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp | 2 +- .../GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp index ed0f8ce728..5be03c9e45 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp @@ -1333,7 +1333,7 @@ void ParticleUplinkCannonUpdate::crc( Xfer *xfer ) * 1: Initial version * 2: Serialize decay frames * 3: TheSuperHackers @tweak Added m_manualTargetMode - * 4: TheSuperHackers @tweak Serialize orbit to target laser radius + * 4: TheSuperHackers @tweak Added m_orbitToTargetLaserRadius * 5: TheSuperHackers @tweak Changed m_lastDrivingClickFrame to m_lastDrivingClickTimeMsec (frames to milliseconds) */ // ------------------------------------------------------------------------------------------------ diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp index ae589000d3..6fd400b1fe 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp @@ -1417,7 +1417,7 @@ void ParticleUplinkCannonUpdate::crc( Xfer *xfer ) * 1: Initial version * 2: Serialize decay frames * 3: Serialize scripted waypoints (Added for Zero Hour) - * 4: TheSuperHackers @tweak Serialize orbit to target laser radius + * 4: TheSuperHackers @tweak Added m_orbitToTargetLaserRadius * 5: TheSuperHackers @tweak Changed m_lastDrivingClickFrame to m_lastDrivingClickTimeMsec (frames to milliseconds) */ // ------------------------------------------------------------------------------------------------ From 12b2f8d552905fe0bbd34d55b53e57f4a6a4dd75 Mon Sep 17 00:00:00 2001 From: Bobby Battista Date: Sat, 3 Jan 2026 12:57:01 -0800 Subject: [PATCH 12/13] remove redundant xfer load branch in ParticleUplinkCannonUpdate --- .../GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp | 7 +------ .../GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp | 7 +------ 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp index 5be03c9e45..e1f7a49e56 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp @@ -1455,16 +1455,11 @@ void ParticleUplinkCannonUpdate::xfer( Xfer *xfer ) } else { - // Old versions stored frame numbers, which we can't meaningfully convert to milliseconds + // Old versions stored frame numbers, read and discard to advance file position. UnsignedInt oldLastDrivingClickFrame = 0; UnsignedInt old2ndLastDrivingClickFrame = 0; xfer->xferUnsignedInt( &oldLastDrivingClickFrame ); xfer->xferUnsignedInt( &old2ndLastDrivingClickFrame ); - if( xfer->getXferMode() == XFER_LOAD ) - { - m_lastDrivingClickTimeMsec = 0; - m_2ndLastDrivingClickTimeMsec = 0; - } } #endif diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp index 6fd400b1fe..5d91f061bf 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp @@ -1539,16 +1539,11 @@ void ParticleUplinkCannonUpdate::xfer( Xfer *xfer ) } else { - // Old versions stored frame numbers, which we can't meaningfully convert to milliseconds + // Old versions stored frame numbers, read and discard to advance file position. UnsignedInt oldLastDrivingClickFrame = 0; UnsignedInt old2ndLastDrivingClickFrame = 0; xfer->xferUnsignedInt( &oldLastDrivingClickFrame ); xfer->xferUnsignedInt( &old2ndLastDrivingClickFrame ); - if( xfer->getXferMode() == XFER_LOAD ) - { - m_lastDrivingClickTimeMsec = 0; - m_2ndLastDrivingClickTimeMsec = 0; - } } #endif From 99e68e12ce3c09043e0687b56968edbd69d7a610 Mon Sep 17 00:00:00 2001 From: Bobby Battista Date: Tue, 6 Jan 2026 12:40:16 -0800 Subject: [PATCH 13/13] remove xfer of timeGetTime values and fix xfer version numbering --- .../Update/ParticleUplinkCannonUpdate.cpp | 28 ++++++------------- .../Update/ParticleUplinkCannonUpdate.cpp | 24 +++++----------- 2 files changed, 16 insertions(+), 36 deletions(-) diff --git a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp index e1f7a49e56..5179e37747 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp @@ -1332,9 +1332,8 @@ void ParticleUplinkCannonUpdate::crc( Xfer *xfer ) * Version Info: * 1: Initial version * 2: Serialize decay frames - * 3: TheSuperHackers @tweak Added m_manualTargetMode - * 4: TheSuperHackers @tweak Added m_orbitToTargetLaserRadius - * 5: TheSuperHackers @tweak Changed m_lastDrivingClickFrame to m_lastDrivingClickTimeMsec (frames to milliseconds) + * 3: TheSuperHackers @tweak Serialize manual target mode + * 4: TheSuperHackers @tweak Serialize orbit to target laser radius */ // ------------------------------------------------------------------------------------------------ void ParticleUplinkCannonUpdate::xfer( Xfer *xfer ) @@ -1345,7 +1344,7 @@ void ParticleUplinkCannonUpdate::xfer( Xfer *xfer ) #if RETAIL_COMPATIBLE_CRC || RETAIL_COMPATIBLE_XFER_SAVE const XferVersion currentVersion = 2; #else - const XferVersion currentVersion = 5; + const XferVersion currentVersion = 4; #endif XferVersion version = currentVersion; xfer->xferVersion( &version, currentVersion ); @@ -1444,29 +1443,20 @@ void ParticleUplinkCannonUpdate::xfer( Xfer *xfer ) // the time of last manual target click #if RETAIL_COMPATIBLE_CRC || RETAIL_COMPATIBLE_XFER_SAVE - // Retail builds stay at version 3 for compatibility, so always use old frame format xfer->xferUnsignedInt( &m_lastDrivingClickFrame ); xfer->xferUnsignedInt( &m_2ndLastDrivingClickFrame ); #else - if( version >= 5 ) - { - xfer->xferUnsignedInt( &m_lastDrivingClickTimeMsec ); - xfer->xferUnsignedInt( &m_2ndLastDrivingClickTimeMsec ); - } - else - { - // Old versions stored frame numbers, read and discard to advance file position. - UnsignedInt oldLastDrivingClickFrame = 0; - UnsignedInt old2ndLastDrivingClickFrame = 0; - xfer->xferUnsignedInt( &oldLastDrivingClickFrame ); - xfer->xferUnsignedInt( &old2ndLastDrivingClickFrame ); - } -#endif + // TheSuperHackers @info timeGetTime values are machine-relative and meaningless on load. + // Write/read dummy values to maintain file format compatibility. + UnsignedInt dummyClickTime = 0; + xfer->xferUnsignedInt( &dummyClickTime ); + xfer->xferUnsignedInt( &dummyClickTime ); if( version >= 3 ) { xfer->xferBool( &m_manualTargetMode ); } +#endif if( version >= 4 ) { diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp index 5d91f061bf..702c30d54d 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp @@ -1417,8 +1417,7 @@ void ParticleUplinkCannonUpdate::crc( Xfer *xfer ) * 1: Initial version * 2: Serialize decay frames * 3: Serialize scripted waypoints (Added for Zero Hour) - * 4: TheSuperHackers @tweak Added m_orbitToTargetLaserRadius - * 5: TheSuperHackers @tweak Changed m_lastDrivingClickFrame to m_lastDrivingClickTimeMsec (frames to milliseconds) + * 4: TheSuperHackers @tweak Serialize orbit to target laser radius */ // ------------------------------------------------------------------------------------------------ void ParticleUplinkCannonUpdate::xfer( Xfer *xfer ) @@ -1429,7 +1428,7 @@ void ParticleUplinkCannonUpdate::xfer( Xfer *xfer ) #if RETAIL_COMPATIBLE_CRC || RETAIL_COMPATIBLE_XFER_SAVE const XferVersion currentVersion = 3; #else - const XferVersion currentVersion = 5; + const XferVersion currentVersion = 4; #endif XferVersion version = currentVersion; xfer->xferVersion( &version, currentVersion ); @@ -1528,23 +1527,14 @@ void ParticleUplinkCannonUpdate::xfer( Xfer *xfer ) // the time of last manual target click #if RETAIL_COMPATIBLE_CRC || RETAIL_COMPATIBLE_XFER_SAVE - // Retail builds stay at version 3 for compatibility, so always use old frame format xfer->xferUnsignedInt( &m_lastDrivingClickFrame ); xfer->xferUnsignedInt( &m_2ndLastDrivingClickFrame ); #else - if( version >= 5 ) - { - xfer->xferUnsignedInt( &m_lastDrivingClickTimeMsec ); - xfer->xferUnsignedInt( &m_2ndLastDrivingClickTimeMsec ); - } - else - { - // Old versions stored frame numbers, read and discard to advance file position. - UnsignedInt oldLastDrivingClickFrame = 0; - UnsignedInt old2ndLastDrivingClickFrame = 0; - xfer->xferUnsignedInt( &oldLastDrivingClickFrame ); - xfer->xferUnsignedInt( &old2ndLastDrivingClickFrame ); - } + // TheSuperHackers @info timeGetTime values are machine-relative and meaningless on load. + // Write/read dummy values to maintain file format compatibility. + UnsignedInt dummyClickTime = 0; + xfer->xferUnsignedInt( &dummyClickTime ); + xfer->xferUnsignedInt( &dummyClickTime ); #endif if( version >= 3 )