Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -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; }

Expand Down Expand Up @@ -508,6 +510,10 @@ class W3DModelDraw : public DrawModule, public ObjectDrawInterface
Bool m_pauseAnimation;
Int m_animationMode;

Bool m_needUpdateTurretPosition;
Bool m_lastNeedUpdateTurretPosition;
Bool m_doHandleRecoil;

void adjustAnimation(const ModelConditionInfo* prevState, Real prevAnimFraction);
Real getCurrentAnimFraction() const;
void applyCorrectModelStateAnimation();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1742,6 +1742,9 @@ 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.
getW3DModelDrawModuleData()->validateStuffForTimeAndWeather(getDrawable(),
Expand Down Expand Up @@ -2422,6 +2425,14 @@ void W3DModelDraw::handleClientTurretPositioning()
if (!m_curState || !(m_curState->m_validStuff & ModelConditionInfo::TURRETS_VALID))
return;

if (!m_needUpdateTurretPosition)
{
if(!m_lastNeedUpdateTurretPosition)
return;

m_lastNeedUpdateTurretPosition = false;
}

for (int tslot = 0; tslot < MAX_TURRETS; ++tslot)
{
const ModelConditionInfo::TurretInfo& tur = m_curState->m_turrets[tslot];
Expand Down Expand Up @@ -2493,14 +2504,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_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)
{
Expand All @@ -2520,6 +2535,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;
Expand All @@ -2544,6 +2561,7 @@ void W3DModelDraw::handleClientRecoil()
{
recoils[i].m_state = WeaponRecoilInfo::SETTLE;
}
m_doHandleRecoil = TRUE; // There's more recoil, need to update
break;

case WeaponRecoilInfo::SETTLE:
Expand All @@ -2553,6 +2571,10 @@ void W3DModelDraw::handleClientRecoil()
recoils[i].m_shift = 0.0f;
recoils[i].m_state = WeaponRecoilInfo::IDLE;
}
else
{
m_doHandleRecoil = TRUE; // There's more recoil, need to update
}
Comment thread
greptile-apps[bot] marked this conversation as resolved.
break;
}

Expand Down Expand Up @@ -3753,6 +3775,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;
Expand Down Expand Up @@ -3895,6 +3919,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;
}

//-------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -4005,6 +4031,13 @@ void W3DModelDraw::updateSubObjects()
}
}

//-------------------------------------------------------------------------------------------------
void W3DModelDraw::setNeedUpdateTurretPositioning(Bool set)
{
m_needUpdateTurretPosition = set;
if(set) m_lastNeedUpdateTurretPosition = true;
}

// ------------------------------------------------------------------------------------------------
/** CRC */
// ------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -4264,6 +4297,10 @@ void W3DModelDraw::loadPostProcess()
// extend base class
DrawModule::loadPostProcess();

m_needUpdateTurretPosition = TRUE;
m_lastNeedUpdateTurretPosition = TRUE;
m_doHandleRecoil = TRUE;

}

// ------------------------------------------------------------------------------------------------
Expand Down
2 changes: 2 additions & 0 deletions GeneralsMD/Code/GameEngine/Include/Common/DrawModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions GeneralsMD/Code/GameEngine/Include/GameClient/Drawable.h
Original file line number Diff line number Diff line change
Expand Up @@ -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; }

Expand Down
4 changes: 4 additions & 0 deletions GeneralsMD/Code/GameEngine/Include/GameLogic/Object.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 );
Expand Down Expand Up @@ -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()
Expand Down
11 changes: 11 additions & 0 deletions GeneralsMD/Code/GameEngine/Source/GameClient/Drawable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down
17 changes: 14 additions & 3 deletions GeneralsMD/Code/GameEngine/Source/GameLogic/AI/TurretAI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down Expand Up @@ -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
{
Expand All @@ -639,6 +641,7 @@ void TurretAI::setTurretTargetPosition( const Coord3D* pos )
void TurretAI::recenterTurret()
{
m_turretStateMachine->setState( TURRETAI_RECENTER );
getOwner()->setNeedUpdateTurretPositioning(TRUE);
}

//----------------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -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!
Expand Down Expand 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 &&
Expand Down Expand Up @@ -1217,12 +1223,14 @@ 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


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 )
Bool turretAligned = angleAligned && pitchAligned;
getMachineOwner()->setNeedUpdateTurretPositioning(!turretAligned);

if( turretAligned )
return STATE_SUCCESS;

return STATE_CONTINUE;
Expand Down Expand Up @@ -1374,7 +1382,10 @@ StateReturnType TurretAIIdleScanState::update()
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 )
Bool turretAligned = angleAligned && pitchAligned;
getMachineOwner()->setNeedUpdateTurretPositioning(!turretAligned);

if( turretAligned )
return STATE_SUCCESS;

return STATE_CONTINUE;
Expand Down
13 changes: 13 additions & 0 deletions GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Object.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down Expand Up @@ -4531,6 +4533,7 @@ void Object::loadPostProcess()
else
m_containedBy = nullptr;

setNeedUpdateTurretPositioning(TRUE);
}

//-------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -6552,3 +6555,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);
}
}
Loading