diff --git a/GeneralsMD/Code/GameEngine/Include/Common/DrawModule.h b/GeneralsMD/Code/GameEngine/Include/Common/DrawModule.h index 2f9cfd1572..c0d966b2b9 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 b66eb7dc96..9415fd60dd 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( void ) 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 9c601848f6..3656bb7169 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/Object.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/Object.h @@ -632,6 +632,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 ); @@ -813,6 +815,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 9f1f5f7eaf..bab62fc0de 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/Drawable.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/Drawable.cpp @@ -761,6 +761,17 @@ Real Drawable::getAnimationScrubScalar( void ) 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 073f5b4fd0..001b98397e 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/AI/TurretAI.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/AI/TurretAI.cpp @@ -1219,13 +1219,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; } @@ -1373,11 +1377,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 7052147358..69e28c97db 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. @@ -4452,6 +4454,7 @@ void Object::loadPostProcess() else m_containedBy = NULL; + setNeedUpdateTurretPositioning(TRUE); } //------------------------------------------------------------------------------------------------- @@ -6452,3 +6455,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 7bc310b7d6..62822eaab3 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/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/Module/W3DModelDraw.h b/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/Module/W3DModelDraw.h index 1d33cb947e..e6d76cb028 100644 --- a/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/Module/W3DModelDraw.h +++ b/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/Module/W3DModelDraw.h @@ -418,6 +418,8 @@ class W3DModelDraw : public DrawModule, public ObjectDrawInterface virtual Real getAnimationScrubScalar( void ) const; #endif + virtual void setNeedUpdateTurretPositioning(Bool set); + virtual ObjectDrawInterface* getObjectDrawInterface() { return this; } virtual const ObjectDrawInterface* getObjectDrawInterface() const { 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/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DModelDraw.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DModelDraw.cpp index fccd5c32e0..7aebb33961 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DModelDraw.cpp +++ b/GeneralsMD/Code/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(), @@ -2417,7 +2419,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) @@ -2491,14 +2493,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) { @@ -2518,6 +2524,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; @@ -2542,6 +2550,7 @@ void W3DModelDraw::handleClientRecoil() { recoils[i].m_state = WeaponRecoilInfo::SETTLE; } + m_doHandleRecoil = TRUE; // There's more recoil, need to update break; case WeaponRecoilInfo::SETTLE: @@ -2551,6 +2560,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; } @@ -3764,6 +3774,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; @@ -3906,6 +3918,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; } //------------------------------------------------------------------------------------------------- @@ -4016,6 +4030,12 @@ void W3DModelDraw::updateSubObjects() } } +//------------------------------------------------------------------------------------------------- +void W3DModelDraw::setNeedUpdateTurretPositioning(Bool set) +{ + m_needUpdateTurretPosition = set; +} + // ------------------------------------------------------------------------------------------------ /** CRC */ // ------------------------------------------------------------------------------------------------ @@ -4275,6 +4295,9 @@ void W3DModelDraw::loadPostProcess( void ) // extend base class DrawModule::loadPostProcess(); + m_needUpdateTurretPosition = TRUE; + m_doHandleRecoil = TRUE; + } // ------------------------------------------------------------------------------------------------