From 2e73a7198c0c8433475faf6730a8e97799ed0e48 Mon Sep 17 00:00:00 2001 From: IamInnocent3X Date: Fri, 2 Jan 2026 00:30:51 +0800 Subject: [PATCH 1/5] Adjusted handleClientTurretPositioning() and handleClientRecoil() to Update when Necessary --- .../GameClient/Module/W3DModelDraw.h | 5 +++ .../GameClient/Drawable/Draw/W3DModelDraw.cpp | 32 +++++++++++++++++-- .../GameEngine/Include/Common/DrawModule.h | 2 ++ .../GameEngine/Include/GameClient/Drawable.h | 2 ++ .../GameEngine/Include/GameLogic/Object.h | 4 +++ .../GameEngine/Source/GameClient/Drawable.cpp | 11 +++++++ .../Source/GameLogic/AI/TurretAI.cpp | 9 ++++++ .../Source/GameLogic/Object/Object.cpp | 17 ++++++++++ .../GameLogic/Object/Update/AIUpdate.cpp | 4 +++ GeneralsReplays | 2 +- 10 files changed, 85 insertions(+), 3 deletions(-) diff --git a/Core/GameEngineDevice/Include/W3DDevice/GameClient/Module/W3DModelDraw.h b/Core/GameEngineDevice/Include/W3DDevice/GameClient/Module/W3DModelDraw.h index 9defb85d715..463688119f5 100644 --- a/Core/GameEngineDevice/Include/W3DDevice/GameClient/Module/W3DModelDraw.h +++ b/Core/GameEngineDevice/Include/W3DDevice/GameClient/Module/W3DModelDraw.h @@ -418,6 +418,8 @@ class W3DModelDraw : public DrawModule, public ObjectDrawInterface virtual Real getAnimationScrubScalar() const; #endif + virtual void setNeedUpdateTurretPositioning(Bool set); + virtual ObjectDrawInterface* getObjectDrawInterface() override { return this; } virtual const ObjectDrawInterface* getObjectDrawInterface() const override { return this; } @@ -508,6 +510,9 @@ class W3DModelDraw : public DrawModule, public ObjectDrawInterface Bool m_pauseAnimation; Int m_animationMode; + Bool m_needUpdateTurretPosition; + Bool m_doHandleRecoil; + void adjustAnimation(const ModelConditionInfo* prevState, Real prevAnimFraction); Real getCurrentAnimFraction() const; void applyCorrectModelStateAnimation(); diff --git a/Core/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DModelDraw.cpp b/Core/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DModelDraw.cpp index 3b46fe5a5e4..f6e3ce90cec 100644 --- a/Core/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DModelDraw.cpp +++ b/Core/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DModelDraw.cpp @@ -1742,6 +1742,8 @@ W3DModelDraw::W3DModelDraw(Thing *thing, const ModuleData* moduleData) : DrawMod } m_needRecalcBoneParticleSystems = false; m_fullyObscuredByShroud = false; + m_needUpdateTurretPosition = true; + m_doHandleRecoil = true; // only validate the current time-of-day and weather conditions by default. getW3DModelDrawModuleData()->validateStuffForTimeAndWeather(getDrawable(), @@ -2419,7 +2421,7 @@ void W3DModelDraw::stopClientParticleSystems() */ void W3DModelDraw::handleClientTurretPositioning() { - if (!m_curState || !(m_curState->m_validStuff & ModelConditionInfo::TURRETS_VALID)) + if (!m_curState || !(m_curState->m_validStuff & ModelConditionInfo::TURRETS_VALID) || !m_needUpdateTurretPosition) return; for (int tslot = 0; tslot < MAX_TURRETS; ++tslot) @@ -2493,14 +2495,18 @@ void W3DModelDraw::handleClientTurretPositioning() @todo fix me someday (srj) */ +// TheSuperHackers @performance IamInnocent 01/01/26 - Adjust Turret Positioning, Recoil, and Muzzle to only Update when Necessary void W3DModelDraw::handleClientRecoil() { const W3DModelDrawModuleData* d = getW3DModelDrawModuleData(); - if (!(m_curState->m_validStuff & ModelConditionInfo::BARRELS_VALID)) + if (!(m_curState->m_validStuff & ModelConditionInfo::BARRELS_VALID) || !m_doHandleRecoil) { return; } + // Set the Requirement of Recoil Update to False first, if there is any recoil while checking, it is set to True. + m_doHandleRecoil = FALSE; + // do recoil, if any for (int wslot = 0; wslot < WEAPONSLOT_COUNT; ++wslot) { @@ -2520,6 +2526,8 @@ void W3DModelDraw::handleClientRecoil() Bool hidden = recoils[i].m_state != WeaponRecoilInfo::RECOIL_START; //DEBUG_LOG(("adjust muzzleflash %08lx for Draw %08lx state %s to %d at frame %d",subObjToHide,this,m_curState->m_description.str(),hidden?1:0,TheGameLogic->getFrame())); barrels[i].setMuzzleFlashHidden(m_renderObject, hidden); + if(!hidden) + m_doHandleRecoil = TRUE; // There's more recoil, need to update } const Real TINY_RECOIL = 0.01f; @@ -2544,6 +2552,7 @@ void W3DModelDraw::handleClientRecoil() { recoils[i].m_state = WeaponRecoilInfo::SETTLE; } + m_doHandleRecoil = TRUE; // There's more recoil, need to update break; case WeaponRecoilInfo::SETTLE: @@ -2553,6 +2562,7 @@ void W3DModelDraw::handleClientRecoil() recoils[i].m_shift = 0.0f; recoils[i].m_state = WeaponRecoilInfo::IDLE; } + m_doHandleRecoil = TRUE; // There's more recoil, need to update break; } @@ -3753,6 +3763,8 @@ Bool W3DModelDraw::handleWeaponFireFX(WeaponSlotType wslot, Int specificBarrelTo if (info.m_recoilBone || info.m_muzzleFlashBone) { + m_doHandleRecoil = TRUE; + //DEBUG_LOG(("START muzzleflash %08lx for Draw %08lx state %s at frame %d",info.m_muzzleFlashBone,this,m_curState->m_description.str(),TheGameLogic->getFrame())); WeaponRecoilInfo& recoil = m_weaponRecoilInfoVec[wslot][specificBarrelToUse]; recoil.m_state = WeaponRecoilInfo::RECOIL_START; @@ -3895,6 +3907,8 @@ void W3DModelDraw::rebuildWeaponRecoilInfo(const ModelConditionInfo* state) } } } + // Resetting Model calls for this function, everytime new recoil Info is configured, need to configure to check for new recoil or Muzzle + m_doHandleRecoil = TRUE; } //------------------------------------------------------------------------------------------------- @@ -4005,6 +4019,12 @@ void W3DModelDraw::updateSubObjects() } } +//------------------------------------------------------------------------------------------------- +void W3DModelDraw::setNeedUpdateTurretPositioning(Bool set) +{ + m_needUpdateTurretPosition = set; // A simple function with the dangers of an atomic bomb, misuse and it'll cause desync +} + // ------------------------------------------------------------------------------------------------ /** CRC */ // ------------------------------------------------------------------------------------------------ @@ -4253,6 +4273,14 @@ void W3DModelDraw::xfer( Xfer *xfer ) if( xfer->getXferMode() == XFER_LOAD && m_subObjectVec.empty() == FALSE ) updateSubObjects(); +#if !RETAIL_COMPATIBLE_CRC + // Update Turret Position + xfer->xferBool( &m_needUpdateTurretPosition ); + + // Handle Recoil + xfer->xferBool( &m_doHandleRecoil ); +#endif + } // ------------------------------------------------------------------------------------------------ diff --git a/GeneralsMD/Code/GameEngine/Include/Common/DrawModule.h b/GeneralsMD/Code/GameEngine/Include/Common/DrawModule.h index d2595fc4954..0184b43d83d 100644 --- a/GeneralsMD/Code/GameEngine/Include/Common/DrawModule.h +++ b/GeneralsMD/Code/GameEngine/Include/Common/DrawModule.h @@ -188,6 +188,8 @@ class ObjectDrawInterface virtual void setSelectable(Bool selectable) = 0; + virtual void setNeedUpdateTurretPositioning(Bool set) = 0; + /** This call says, "I want the current animation (if any) to take n frames to complete a single cycle". If it's a looping anim, each loop will take n frames. someday, we may want to add the option to insert diff --git a/GeneralsMD/Code/GameEngine/Include/GameClient/Drawable.h b/GeneralsMD/Code/GameEngine/Include/GameClient/Drawable.h index e0e4707f93c..00b51a0b8f8 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameClient/Drawable.h +++ b/GeneralsMD/Code/GameEngine/Include/GameClient/Drawable.h @@ -518,6 +518,8 @@ class Drawable : public Thing, Real getAnimationScrubScalar() const; // lorenzen // returns 0 to 1... where are we between start and finish? #endif + void setNeedUpdateTurretPositioning(Bool set); + UnsignedInt getExpirationDate() const { return m_expirationDate; } void setExpirationDate(UnsignedInt frame) { m_expirationDate = frame; } diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/Object.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/Object.h index 29d391b81a3..0771605ad6b 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/Object.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/Object.h @@ -637,6 +637,8 @@ class Object : public Thing, public Snapshot // player. These are friend_s for player. void friend_adjustPowerForPlayer( Bool incoming ); + void setNeedUpdateTurretPositioning(Bool set); + protected: void setOrRestoreTeam( Team* team, Bool restoring ); @@ -818,6 +820,8 @@ class Object : public Thing, public Snapshot Bool m_singleUseCommandUsed; Bool m_isReceivingDifficultyBonus; + Bool m_turretNeedPositioning; + }; // deleteInstance is not meant to be used with Object in order to require the use of TheGameLogic->destroyObject() diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/Drawable.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/Drawable.cpp index 9985fa0e8ce..66fe026f656 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/Drawable.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/Drawable.cpp @@ -751,6 +751,17 @@ Real Drawable::getAnimationScrubScalar() const // lorenzen } #endif +//------------------------------------------------------------------------------------------------- +void Drawable::setNeedUpdateTurretPositioning(Bool set) +{ + for (DrawModule** dm = getDrawModules(); *dm; ++dm) + { + ObjectDrawInterface* di = (*dm)->getObjectDrawInterface(); + if (di) + di->setNeedUpdateTurretPositioning(set); + } +} + //------------------------------------------------------------------------------------------------- Int Drawable::getPristineBonePositions(const char* boneNamePrefix, Int startIndex, Coord3D* positions, Matrix3D* transforms, Int maxBones) const { diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/AI/TurretAI.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/AI/TurretAI.cpp index 78395baf998..e736bba1168 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/AI/TurretAI.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/AI/TurretAI.cpp @@ -1217,13 +1217,17 @@ StateReturnType TurretAIRecenterTurretState::update() if( getMachineOwner()->testStatus( OBJECT_STATUS_UNDER_CONSTRUCTION)) return STATE_CONTINUE;//ML so that under-construction base-defenses do not re-center while under construction + getMachineOwner()->setNeedUpdateTurretPositioning(TRUE); TurretAI* turret = getTurretAI(); Bool angleAligned = turret->friend_turnTowardsAngle(turret->getNaturalTurretAngle(), 0.5f, 0.0f); Bool pitchAligned = turret->friend_turnTowardsPitch(turret->getNaturalTurretPitch(), 0.5f); if( angleAligned && pitchAligned ) + { + getMachineOwner()->setNeedUpdateTurretPositioning(FALSE); return STATE_SUCCESS; + } return STATE_CONTINUE; } @@ -1371,11 +1375,16 @@ StateReturnType TurretAIIdleScanState::update() if( getMachineOwner()->testStatus( OBJECT_STATUS_UNDER_CONSTRUCTION)) return STATE_CONTINUE;//ML so that under-construction base-defenses do not idle-scan while under construction + getMachineOwner()->setNeedUpdateTurretPositioning(TRUE); + Bool angleAligned = getTurretAI()->friend_turnTowardsAngle(getTurretAI()->getNaturalTurretAngle() + m_desiredAngle, 0.5f, 0.0f); Bool pitchAligned = getTurretAI()->friend_turnTowardsPitch(getTurretAI()->getNaturalTurretPitch(), 0.5f); if( angleAligned && pitchAligned ) + { + getMachineOwner()->setNeedUpdateTurretPositioning(FALSE); return STATE_SUCCESS; + } return STATE_CONTINUE; } diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Object.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Object.cpp index 0bd898aae75..ba3be00135d 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Object.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Object.cpp @@ -497,6 +497,8 @@ Object::Object( const ThingTemplate *tt, const ObjectStatusMaskType &objectStatu m_soleHealingBenefactorID = INVALID_ID; ///< who is the only other object that can give me this non-stacking heal benefit? m_soleHealingBenefactorExpirationFrame = 0; ///< on what frame can I accept healing (thus to switch) from a new benefactor + m_turretNeedPositioning = FALSE; + // TheSuperHackers @bugfix Mauller/xezon 02/08/2025 sendObjectCreated needs calling before CreateModule's are initialized to prevent drawable related crashes // This predominantly occurs with the veterancy create module when the chemical suits upgrade is unlocked as it tries to set the terrain decal. @@ -4322,6 +4324,11 @@ void Object::xfer( Xfer *xfer ) // health box offset xfer->xferCoord3D( &m_healthBoxOffset ); +#if !RETAIL_COMPATIBLE_CRC + // turret need positioning + xfer->xferBool( &m_turretNeedPositioning ); +#endif + // Entered & exited housekeeping. Int i; xfer->xferByte(&m_numTriggerAreasActive); @@ -6552,3 +6559,13 @@ ObjectID Object::calculateCountermeasureToDivertTo( const Object& victim ) } return INVALID_ID; } + +//------------------------------------------------------------------------------------------------- +void Object::setNeedUpdateTurretPositioning(Bool set) +{ + if(m_turretNeedPositioning != set && getDrawable()) + { + m_turretNeedPositioning = set; + getDrawable()->setNeedUpdateTurretPositioning(set); + } +} diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate.cpp index 2eed5b09878..54f1ba5273c 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate.cpp @@ -658,6 +658,7 @@ void AIUpdateInterface::setTurretTargetObject(WhichTurretType tur, Object* o, Bo { if (m_turretAI[tur]) { + getObject()->setNeedUpdateTurretPositioning(TRUE); m_turretAI[tur]->setTurretTargetObject(o, forceAttacking); } } @@ -682,6 +683,7 @@ void AIUpdateInterface::setTurretTargetPosition(WhichTurretType tur, const Coord { if (m_turretAI[tur]) { + getObject()->setNeedUpdateTurretPositioning(TRUE); m_turretAI[tur]->setTurretTargetPosition(pos); } } @@ -691,6 +693,7 @@ void AIUpdateInterface::setTurretEnabled(WhichTurretType tur, Bool enabled) { if (m_turretAI[tur]) { + getObject()->setNeedUpdateTurretPositioning(TRUE); m_turretAI[tur]->setTurretEnabled( enabled ); } } @@ -700,6 +703,7 @@ void AIUpdateInterface::recenterTurret(WhichTurretType tur) { if (m_turretAI[tur]) { + getObject()->setNeedUpdateTurretPositioning(TRUE); m_turretAI[tur]->recenterTurret(); } } diff --git a/GeneralsReplays b/GeneralsReplays index 0711bf9d1b6..af0c61ccdcc 160000 --- a/GeneralsReplays +++ b/GeneralsReplays @@ -1 +1 @@ -Subproject commit 0711bf9d1b60aeaaad98a52edd9b7b1c16be4937 +Subproject commit af0c61ccdccbf06750b0ecd2de99fe65842bfc1a From 957cc83e0bf40a4608a48a48af1c9a9a1e89eaa3 Mon Sep 17 00:00:00 2001 From: IamInnocent3X Date: Sat, 3 Jan 2026 10:38:58 +0800 Subject: [PATCH 2/5] Adjusted according to Changes Proposed --- .../GameClient/Drawable/Draw/W3DModelDraw.cpp | 19 ++++++++++++------- .../Source/GameLogic/Object/Object.cpp | 10 ++++++---- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/Core/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DModelDraw.cpp b/Core/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DModelDraw.cpp index f6e3ce90cec..404fffca674 100644 --- a/Core/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DModelDraw.cpp +++ b/Core/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DModelDraw.cpp @@ -4022,7 +4022,7 @@ void W3DModelDraw::updateSubObjects() //------------------------------------------------------------------------------------------------- void W3DModelDraw::setNeedUpdateTurretPositioning(Bool set) { - m_needUpdateTurretPosition = set; // A simple function with the dangers of an atomic bomb, misuse and it'll cause desync + m_needUpdateTurretPosition = set; } // ------------------------------------------------------------------------------------------------ @@ -4047,7 +4047,11 @@ void W3DModelDraw::xfer( Xfer *xfer ) { // version +#if RETAIL_COMPATIBLE_XFER_SAVE const XferVersion currentVersion = 2; +#else + const XferVersion currentVersion = 3; +#endif XferVersion version = currentVersion; xfer->xferVersion( &version, currentVersion ); @@ -4273,13 +4277,14 @@ void W3DModelDraw::xfer( Xfer *xfer ) if( xfer->getXferMode() == XFER_LOAD && m_subObjectVec.empty() == FALSE ) updateSubObjects(); -#if !RETAIL_COMPATIBLE_CRC - // Update Turret Position - xfer->xferBool( &m_needUpdateTurretPosition ); + if( version >= 3 ) + { + // Update Turret Position + xfer->xferBool( &m_needUpdateTurretPosition ); - // Handle Recoil - xfer->xferBool( &m_doHandleRecoil ); -#endif + // Handle Recoil + xfer->xferBool( &m_doHandleRecoil ); + } } diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Object.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Object.cpp index ba3be00135d..74d66b21070 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Object.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Object.cpp @@ -4117,7 +4117,11 @@ void Object::xfer( Xfer *xfer ) { // version +#if RETAIL_COMPATIBLE_XFER_SAVE const XferVersion currentVersion = 9; +#else + const XferVersion currentVersion = 10; +#endif XferVersion version = currentVersion; xfer->xferVersion( &version, currentVersion ); @@ -4324,10 +4328,8 @@ void Object::xfer( Xfer *xfer ) // health box offset xfer->xferCoord3D( &m_healthBoxOffset ); -#if !RETAIL_COMPATIBLE_CRC - // turret need positioning - xfer->xferBool( &m_turretNeedPositioning ); -#endif + if( version >= 10 ) + xfer->xferBool( &m_turretNeedPositioning ); // Entered & exited housekeeping. Int i; From 032da9b41f1342bf844817b107815756d6cc987e Mon Sep 17 00:00:00 2001 From: IamInnocent3X Date: Sun, 4 Jan 2026 20:16:59 +0800 Subject: [PATCH 3/5] Changes retail xfer to loadPostProcess --- .../GameClient/Drawable/Draw/W3DModelDraw.cpp | 16 +++------------- .../Source/GameLogic/Object/Object.cpp | 8 +------- 2 files changed, 4 insertions(+), 20 deletions(-) diff --git a/Core/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DModelDraw.cpp b/Core/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DModelDraw.cpp index 404fffca674..874a4341eba 100644 --- a/Core/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DModelDraw.cpp +++ b/Core/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DModelDraw.cpp @@ -4047,11 +4047,7 @@ void W3DModelDraw::xfer( Xfer *xfer ) { // version -#if RETAIL_COMPATIBLE_XFER_SAVE const XferVersion currentVersion = 2; -#else - const XferVersion currentVersion = 3; -#endif XferVersion version = currentVersion; xfer->xferVersion( &version, currentVersion ); @@ -4277,15 +4273,6 @@ void W3DModelDraw::xfer( Xfer *xfer ) if( xfer->getXferMode() == XFER_LOAD && m_subObjectVec.empty() == FALSE ) updateSubObjects(); - if( version >= 3 ) - { - // Update Turret Position - xfer->xferBool( &m_needUpdateTurretPosition ); - - // Handle Recoil - xfer->xferBool( &m_doHandleRecoil ); - } - } // ------------------------------------------------------------------------------------------------ @@ -4297,6 +4284,9 @@ void W3DModelDraw::loadPostProcess() // extend base class DrawModule::loadPostProcess(); + m_needUpdateTurretPosition = TRUE; + m_doHandleRecoil = TRUE; + } // ------------------------------------------------------------------------------------------------ diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Object.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Object.cpp index 74d66b21070..2d187ba6881 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Object.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Object.cpp @@ -4117,11 +4117,7 @@ void Object::xfer( Xfer *xfer ) { // version -#if RETAIL_COMPATIBLE_XFER_SAVE const XferVersion currentVersion = 9; -#else - const XferVersion currentVersion = 10; -#endif XferVersion version = currentVersion; xfer->xferVersion( &version, currentVersion ); @@ -4328,9 +4324,6 @@ void Object::xfer( Xfer *xfer ) // health box offset xfer->xferCoord3D( &m_healthBoxOffset ); - if( version >= 10 ) - xfer->xferBool( &m_turretNeedPositioning ); - // Entered & exited housekeeping. Int i; xfer->xferByte(&m_numTriggerAreasActive); @@ -4540,6 +4533,7 @@ void Object::loadPostProcess() else m_containedBy = nullptr; + setNeedUpdateTurretPositioning(TRUE); } //------------------------------------------------------------------------------------------------- From d9014c888729c43a753648c685188441f72a5023 Mon Sep 17 00:00:00 2001 From: IamInnocent3X Date: Tue, 30 Jun 2026 17:09:20 +0800 Subject: [PATCH 4/5] Fixed Turret snapping into other Positions when moved away from Camera on Client's side --- .../Include/W3DDevice/GameClient/Module/W3DModelDraw.h | 1 + .../W3DDevice/GameClient/Drawable/Draw/W3DModelDraw.cpp | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Core/GameEngineDevice/Include/W3DDevice/GameClient/Module/W3DModelDraw.h b/Core/GameEngineDevice/Include/W3DDevice/GameClient/Module/W3DModelDraw.h index 463688119f5..9e09f84e75e 100644 --- a/Core/GameEngineDevice/Include/W3DDevice/GameClient/Module/W3DModelDraw.h +++ b/Core/GameEngineDevice/Include/W3DDevice/GameClient/Module/W3DModelDraw.h @@ -511,6 +511,7 @@ class W3DModelDraw : public DrawModule, public ObjectDrawInterface Int m_animationMode; Bool m_needUpdateTurretPosition; + Bool m_lastNeedUpdateTurretPosition; Bool m_doHandleRecoil; void adjustAnimation(const ModelConditionInfo* prevState, Real prevAnimFraction); diff --git a/Core/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DModelDraw.cpp b/Core/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DModelDraw.cpp index 874a4341eba..c2a816ff415 100644 --- a/Core/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DModelDraw.cpp +++ b/Core/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DModelDraw.cpp @@ -1743,6 +1743,7 @@ W3DModelDraw::W3DModelDraw(Thing *thing, const ModuleData* moduleData) : DrawMod m_needRecalcBoneParticleSystems = false; m_fullyObscuredByShroud = false; m_needUpdateTurretPosition = true; + m_lastNeedUpdateTurretPosition = true; m_doHandleRecoil = true; // only validate the current time-of-day and weather conditions by default. @@ -2421,9 +2422,14 @@ void W3DModelDraw::stopClientParticleSystems() */ void W3DModelDraw::handleClientTurretPositioning() { - if (!m_curState || !(m_curState->m_validStuff & ModelConditionInfo::TURRETS_VALID) || !m_needUpdateTurretPosition) + if (!m_curState || !(m_curState->m_validStuff & ModelConditionInfo::TURRETS_VALID)) return; + if(!m_needUpdateTurretPosition && !m_lastNeedUpdateTurretPosition) + return; + + m_lastNeedUpdateTurretPosition = m_needUpdateTurretPosition; + for (int tslot = 0; tslot < MAX_TURRETS; ++tslot) { const ModelConditionInfo::TurretInfo& tur = m_curState->m_turrets[tslot]; From ab42a7ecdf4f87c489aefc184825bf4ef048f07b Mon Sep 17 00:00:00 2001 From: IamInnocent3X Date: Wed, 1 Jul 2026 18:36:30 +0800 Subject: [PATCH 5/5] Redo Fix for Turret Snapping --- .../GameClient/Module/W3DModelDraw.h | 1 - .../GameClient/Drawable/Draw/W3DModelDraw.cpp | 8 +----- .../Source/GameLogic/AI/TurretAI.cpp | 26 ++++++++++--------- .../GameLogic/Object/Update/AIUpdate.cpp | 4 --- 4 files changed, 15 insertions(+), 24 deletions(-) diff --git a/Core/GameEngineDevice/Include/W3DDevice/GameClient/Module/W3DModelDraw.h b/Core/GameEngineDevice/Include/W3DDevice/GameClient/Module/W3DModelDraw.h index 9e09f84e75e..463688119f5 100644 --- a/Core/GameEngineDevice/Include/W3DDevice/GameClient/Module/W3DModelDraw.h +++ b/Core/GameEngineDevice/Include/W3DDevice/GameClient/Module/W3DModelDraw.h @@ -511,7 +511,6 @@ class W3DModelDraw : public DrawModule, public ObjectDrawInterface Int m_animationMode; Bool m_needUpdateTurretPosition; - Bool m_lastNeedUpdateTurretPosition; Bool m_doHandleRecoil; void adjustAnimation(const ModelConditionInfo* prevState, Real prevAnimFraction); diff --git a/Core/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DModelDraw.cpp b/Core/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DModelDraw.cpp index c2a816ff415..874a4341eba 100644 --- a/Core/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DModelDraw.cpp +++ b/Core/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DModelDraw.cpp @@ -1743,7 +1743,6 @@ W3DModelDraw::W3DModelDraw(Thing *thing, const ModuleData* moduleData) : DrawMod m_needRecalcBoneParticleSystems = false; m_fullyObscuredByShroud = false; m_needUpdateTurretPosition = true; - m_lastNeedUpdateTurretPosition = true; m_doHandleRecoil = true; // only validate the current time-of-day and weather conditions by default. @@ -2422,14 +2421,9 @@ void W3DModelDraw::stopClientParticleSystems() */ void W3DModelDraw::handleClientTurretPositioning() { - if (!m_curState || !(m_curState->m_validStuff & ModelConditionInfo::TURRETS_VALID)) + if (!m_curState || !(m_curState->m_validStuff & ModelConditionInfo::TURRETS_VALID) || !m_needUpdateTurretPosition) return; - if(!m_needUpdateTurretPosition && !m_lastNeedUpdateTurretPosition) - return; - - m_lastNeedUpdateTurretPosition = m_needUpdateTurretPosition; - for (int tslot = 0; tslot < MAX_TURRETS; ++tslot) { const ModelConditionInfo::TurretInfo& tur = m_curState->m_turrets[tslot]; diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/AI/TurretAI.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/AI/TurretAI.cpp index e736bba1168..ef33181e3bc 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/AI/TurretAI.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/AI/TurretAI.cpp @@ -585,6 +585,7 @@ void TurretAI::setTurretTargetObject( Object *victim, Bool forceAttacking ) if (sid != TURRETAI_AIM && sid != TURRETAI_FIRE) m_turretStateMachine->setState( TURRETAI_AIM ); m_victimInitialTeam = victim->getTeam(); + getOwner()->setNeedUpdateTurretPositioning(TRUE); } else { @@ -625,6 +626,7 @@ void TurretAI::setTurretTargetPosition( const Coord3D* pos ) if (sid != TURRETAI_AIM && sid != TURRETAI_FIRE) m_turretStateMachine->setState( TURRETAI_AIM ); m_victimInitialTeam = nullptr; + getOwner()->setNeedUpdateTurretPositioning(TRUE); } else { @@ -639,6 +641,7 @@ void TurretAI::setTurretTargetPosition( const Coord3D* pos ) void TurretAI::recenterTurret() { m_turretStateMachine->setState( TURRETAI_RECENTER ); + getOwner()->setNeedUpdateTurretPositioning(TRUE); } //---------------------------------------------------------------------------------------------------------- @@ -746,6 +749,7 @@ UpdateSleepTime TurretAI::updateTurretAI() //------------------------------------------------------------------------------------------------- void TurretAI::setTurretEnabled( Bool enabled ) { + if (enabled) getOwner()->setNeedUpdateTurretPositioning(TRUE); if (enabled && !m_enabled) { // be sure we wake up! @@ -1153,6 +1157,8 @@ StateReturnType TurretAIAimTurretState::update() pitchAlignedToNemesis = turret->friend_turnTowardsPitch(desiredPitch, 1.0f); } + obj->setNeedUpdateTurretPositioning(!turnAlignedToNemesis || !pitchAlignedToNemesis); + // For now, we require that we're within range before we can successfully exit the AIM state, // and move into the FIRE state. if (turnAlignedToNemesis && pitchAlignedToNemesis && @@ -1217,17 +1223,15 @@ StateReturnType TurretAIRecenterTurretState::update() if( getMachineOwner()->testStatus( OBJECT_STATUS_UNDER_CONSTRUCTION)) return STATE_CONTINUE;//ML so that under-construction base-defenses do not re-center while under construction - getMachineOwner()->setNeedUpdateTurretPositioning(TRUE); - TurretAI* turret = getTurretAI(); Bool angleAligned = turret->friend_turnTowardsAngle(turret->getNaturalTurretAngle(), 0.5f, 0.0f); Bool pitchAligned = turret->friend_turnTowardsPitch(turret->getNaturalTurretPitch(), 0.5f); - if( angleAligned && pitchAligned ) - { - getMachineOwner()->setNeedUpdateTurretPositioning(FALSE); + Bool turretAligned = angleAligned && pitchAligned; + getMachineOwner()->setNeedUpdateTurretPositioning(!turretAligned); + + if( turretAligned ) return STATE_SUCCESS; - } return STATE_CONTINUE; } @@ -1375,16 +1379,14 @@ StateReturnType TurretAIIdleScanState::update() if( getMachineOwner()->testStatus( OBJECT_STATUS_UNDER_CONSTRUCTION)) return STATE_CONTINUE;//ML so that under-construction base-defenses do not idle-scan while under construction - getMachineOwner()->setNeedUpdateTurretPositioning(TRUE); - Bool angleAligned = getTurretAI()->friend_turnTowardsAngle(getTurretAI()->getNaturalTurretAngle() + m_desiredAngle, 0.5f, 0.0f); Bool pitchAligned = getTurretAI()->friend_turnTowardsPitch(getTurretAI()->getNaturalTurretPitch(), 0.5f); - if( angleAligned && pitchAligned ) - { - getMachineOwner()->setNeedUpdateTurretPositioning(FALSE); + Bool turretAligned = angleAligned && pitchAligned; + getMachineOwner()->setNeedUpdateTurretPositioning(!turretAligned); + + if( turretAligned ) return STATE_SUCCESS; - } return STATE_CONTINUE; } diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate.cpp index 54f1ba5273c..2eed5b09878 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate.cpp @@ -658,7 +658,6 @@ void AIUpdateInterface::setTurretTargetObject(WhichTurretType tur, Object* o, Bo { if (m_turretAI[tur]) { - getObject()->setNeedUpdateTurretPositioning(TRUE); m_turretAI[tur]->setTurretTargetObject(o, forceAttacking); } } @@ -683,7 +682,6 @@ void AIUpdateInterface::setTurretTargetPosition(WhichTurretType tur, const Coord { if (m_turretAI[tur]) { - getObject()->setNeedUpdateTurretPositioning(TRUE); m_turretAI[tur]->setTurretTargetPosition(pos); } } @@ -693,7 +691,6 @@ void AIUpdateInterface::setTurretEnabled(WhichTurretType tur, Bool enabled) { if (m_turretAI[tur]) { - getObject()->setNeedUpdateTurretPositioning(TRUE); m_turretAI[tur]->setTurretEnabled( enabled ); } } @@ -703,7 +700,6 @@ void AIUpdateInterface::recenterTurret(WhichTurretType tur) { if (m_turretAI[tur]) { - getObject()->setNeedUpdateTurretPositioning(TRUE); m_turretAI[tur]->recenterTurret(); } }