Skip to content
2 changes: 2 additions & 0 deletions Core/GameEngine/Source/GameClient/System/ParticleSys.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3346,6 +3346,8 @@ void ParticleSystemManager::xfer( Xfer *xfer )
}
else
{
DEBUG_ASSERTCRASH(m_allParticleSystemList.empty(), ("ParticleSystemManager: particle systems list is expected empty at start of xfer-load."));

const ParticleSystemTemplate *systemTemplate;

// read each particle system
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,6 @@ W3DTankDraw::W3DTankDraw( Thing *thing, const ModuleData* moduleData )
m_lastDirection.y=0.0f;
m_lastDirection.z=0.0f;

createTreadEmitters();
}

//-------------------------------------------------------------------------------------------------
Expand All @@ -126,27 +125,35 @@ void W3DTankDraw::tossTreadEmitters()

//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
void W3DTankDraw::createTreadEmitters()
static ParticleSystemID createParticleSystem( const AsciiString &name, const Drawable *drawable )
{
const AsciiString *treadDebrisNames[2];
static_assert(ARRAY_SIZE(treadDebrisNames) == ARRAY_SIZE(m_treadDebrisIDs), "Array size must match");
treadDebrisNames[0] = &getW3DTankDrawModuleData()->m_treadDebrisNameLeft;
treadDebrisNames[1] = &getW3DTankDrawModuleData()->m_treadDebrisNameRight;
const ParticleSystemTemplate *sysTemplate = TheParticleSystemManager->findTemplate(name);
ParticleSystem *particleSys = TheParticleSystemManager->createParticleSystem( sysTemplate );
if (!particleSys)
return INVALID_PARTICLE_SYSTEM_ID;

particleSys->attachToDrawable(drawable);
// important: mark it as do-not-save, since we'll just re-create it when we reload.
particleSys->setSaveable(FALSE);
// they come into being stopped.
particleSys->stop();

return particleSys->getSystemID();
}

for (size_t i = 0; i < ARRAY_SIZE(m_treadDebrisIDs); ++i)
void W3DTankDraw::createTreadEmitters()
{
if (getW3DTankDrawModuleData())
{
if (m_treadDebrisIDs[i] == INVALID_PARTICLE_SYSTEM_ID)
static_assert(ARRAY_SIZE(m_treadDebrisIDs) == 2, "m_treadDebrisIDs array size is expected to be 2");

if (m_treadDebrisIDs[0] == INVALID_PARTICLE_SYSTEM_ID)
{
if (const ParticleSystemTemplate *sysTemplate = TheParticleSystemManager->findTemplate(*treadDebrisNames[i]))
{
ParticleSystem *particleSys = TheParticleSystemManager->createParticleSystem( sysTemplate );
particleSys->attachToDrawable(getDrawable());
// important: mark it as do-not-save, since we'll just re-create it when we reload.
particleSys->setSaveable(FALSE);
// they come into being stopped.
particleSys->stop();
m_treadDebrisIDs[i] = particleSys->getSystemID();
}
m_treadDebrisIDs[0] = createParticleSystem(getW3DTankDrawModuleData()->m_treadDebrisNameLeft, getDrawable());
}
if (m_treadDebrisIDs[1] == INVALID_PARTICLE_SYSTEM_ID)
{
m_treadDebrisIDs[1] = createParticleSystem(getW3DTankDrawModuleData()->m_treadDebrisNameRight, getDrawable());
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest put a static assert nearby that the array size is expected 2.

}
}
Expand Down Expand Up @@ -336,6 +343,9 @@ void W3DTankDraw::doDrawModule(const Matrix3D* transformMtx)
if (velMult.z > 1.0f)
velMult.z = 1.0f;

// TheSuperHackers @bugfix 14/03/2026 Delay emitter creation until draw
createTreadEmitters();

for (size_t i = 0; i < ARRAY_SIZE(m_treadDebrisIDs); ++i)
{
if (ParticleSystem *particleSys = TheParticleSystemManager->findParticleSystem(m_treadDebrisIDs[i]))
Expand Down Expand Up @@ -435,8 +445,4 @@ void W3DTankDraw::loadPostProcess()
// extend base class
W3DModelDraw::loadPostProcess();

// toss any existing tread emitters and re-create 'em (since this module expects 'em to always be around)
tossTreadEmitters();
createTreadEmitters();

}
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,6 @@ m_prevRenderObj(nullptr)

m_treadCount=0;

createTreadEmitters();
}

//-------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -182,30 +181,35 @@ void W3DTankTruckDraw::setFullyObscuredByShroud(Bool fullyObscured)

//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
static ParticleSystemID createParticleSystem( const AsciiString &name, const Drawable *drawable )
{
const ParticleSystemTemplate *sysTemplate = TheParticleSystemManager->findTemplate(name);
ParticleSystem *particleSys = TheParticleSystemManager->createParticleSystem( sysTemplate );
if (!particleSys)
return INVALID_PARTICLE_SYSTEM_ID;

particleSys->attachToDrawable(drawable);
// important: mark it as do-not-save, since we'll just re-create it when we reload.
particleSys->setSaveable(FALSE);
// they come into being stopped.
particleSys->stop();

return particleSys->getSystemID();
}

void W3DTankTruckDraw::createTreadEmitters()
{
if (getW3DTankTruckDrawModuleData())
{
const AsciiString *treadDebrisNames[2];
static_assert(ARRAY_SIZE(treadDebrisNames) == ARRAY_SIZE(m_treadDebrisIDs), "Array size must match");
treadDebrisNames[0] = &getW3DTankTruckDrawModuleData()->m_treadDebrisNameLeft;
treadDebrisNames[1] = &getW3DTankTruckDrawModuleData()->m_treadDebrisNameRight;
static_assert(ARRAY_SIZE(m_treadDebrisIDs) == 2, "m_treadDebrisIDs array size is expected to be 2");

for (size_t i = 0; i < ARRAY_SIZE(m_treadDebrisIDs); ++i)
if (m_treadDebrisIDs[0] == INVALID_PARTICLE_SYSTEM_ID)
{
if (m_treadDebrisIDs[i] == INVALID_PARTICLE_SYSTEM_ID)
{
if (const ParticleSystemTemplate *sysTemplate = TheParticleSystemManager->findTemplate(*treadDebrisNames[i]))
{
ParticleSystem *particleSys = TheParticleSystemManager->createParticleSystem( sysTemplate );
particleSys->attachToDrawable(getDrawable());
// important: mark it as do-not-save, since we'll just re-create it when we reload.
particleSys->setSaveable(FALSE);
// they come into being stopped.
particleSys->stop();
m_treadDebrisIDs[i] = particleSys->getSystemID();
}
}
m_treadDebrisIDs[0] = createParticleSystem(getW3DTankTruckDrawModuleData()->m_treadDebrisNameLeft, getDrawable());
}
if (m_treadDebrisIDs[1] == INVALID_PARTICLE_SYSTEM_ID)
{
m_treadDebrisIDs[1] = createParticleSystem(getW3DTankTruckDrawModuleData()->m_treadDebrisNameRight, getDrawable());
}
}
}
Expand Down Expand Up @@ -509,6 +513,7 @@ void W3DTankTruckDraw::doDrawModule(const Matrix3D* transformMtx)
updateBones();
updateTreadObjects();
}

// get object physics state
PhysicsBehavior *physics = obj->getPhysics();
if (physics == nullptr)
Expand Down Expand Up @@ -668,6 +673,9 @@ void W3DTankTruckDraw::doDrawModule(const Matrix3D* transformMtx)
if (velMult.z > 1.0f)
velMult.z = 1.0f;

// TheSuperHackers @bugfix 14/03/2026 Delay emitter creation until draw
createTreadEmitters();

for (size_t i = 0; i < ARRAY_SIZE(m_treadDebrisIDs); ++i)
{
if (ParticleSystem *particleSys = TheParticleSystemManager->findParticleSystem(m_treadDebrisIDs[i]))
Expand Down Expand Up @@ -761,8 +769,4 @@ void W3DTankTruckDraw::loadPostProcess()
// toss any existing wheel emitters (no need to re-create; we'll do that on demand)
tossWheelEmitters();

// toss any existing tread emitters and re-create 'em (since this module expects 'em to always be around)
tossTreadEmitters();
createTreadEmitters();

}
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ class AutoHealBehavior : public UpdateModule,
private:

void pulseHealObject( Object *obj );
void createEmitters();

ParticleSystemID m_radiusParticleSystemID;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ class GrantStealthBehavior : public UpdateModule
private:

void grantStealthToObject( Object *obj );
void createEmitters();

ParticleSystemID m_radiusParticleSystemID;
Real m_currentScanRadius;
};
Original file line number Diff line number Diff line change
Expand Up @@ -94,21 +94,6 @@ AutoHealBehavior::AutoHealBehavior( Thing *thing, const ModuleData* moduleData )
m_radiusParticleSystemID = INVALID_PARTICLE_SYSTEM_ID;
m_soonestHealFrame = 0;
m_stopped = false;
Object *obj = getObject();

{
if( d->m_radiusParticleSystemTmpl )
{
ParticleSystem *particleSystem;

particleSystem = TheParticleSystemManager->createParticleSystem( d->m_radiusParticleSystemTmpl );
if( particleSystem )
{
particleSystem->setPosition( obj->getPosition() );
m_radiusParticleSystemID = particleSystem->getSystemID();
}
}
}

if (d->m_initiallyActive)
{
Expand Down Expand Up @@ -194,6 +179,9 @@ UpdateSleepTime AutoHealBehavior::update()
return UPDATE_SLEEP_FOREVER;
}

// TheSuperHackers @bugfix stephanmeesters 14/03/2026 Delay emitter creation until update
createEmitters();

//DEBUG_LOG(("doing auto heal %d",TheGameLogic->getFrame()));

if( d->m_affectsWholePlayer )
Expand Down Expand Up @@ -374,3 +362,19 @@ void AutoHealBehavior::loadPostProcess()
UpgradeMux::upgradeMuxLoadPostProcess();

}

// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
void AutoHealBehavior::createEmitters()
{
if( m_radiusParticleSystemID == INVALID_PARTICLE_SYSTEM_ID )
{
const AutoHealBehaviorModuleData *d = getAutoHealBehaviorModuleData();
ParticleSystem *particleSystem = TheParticleSystemManager->createParticleSystem(d->m_radiusParticleSystemTmpl);
if( particleSystem )
{
particleSystem->setPosition( getObject()->getPosition() );
m_radiusParticleSystemID = particleSystem->getSystemID();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -96,24 +96,7 @@ GrantStealthBehavior::GrantStealthBehavior( Thing *thing, const ModuleData* modu

m_currentScanRadius = d->m_startRadius;


Object *obj = getObject();

{
if( d->m_radiusParticleSystemTmpl )
{
ParticleSystem *particleSystem;

particleSystem = TheParticleSystemManager->createParticleSystem( d->m_radiusParticleSystemTmpl );
if( particleSystem )
{
particleSystem->setPosition( obj->getPosition() );
m_radiusParticleSystemID = particleSystem->getSystemID();
}
}
}

setWakeFrame( getObject(), UPDATE_SLEEP_NONE );
setWakeFrame( getObject(), UPDATE_SLEEP_NONE );
}

//-------------------------------------------------------------------------------------------------
Expand All @@ -139,6 +122,9 @@ UpdateSleepTime GrantStealthBehavior::update()
if ( self->isEffectivelyDead())
return UPDATE_SLEEP_FOREVER;

// TheSuperHackers @bugfix stephanmeesters 14/03/2026 Delay emitter creation until update
createEmitters();

const GrantStealthBehaviorModuleData *d = getGrantStealthBehaviorModuleData();
// setup scan filters
PartitionFilterRelationship relationship( self, PartitionFilterRelationship::ALLOW_ALLIES );
Expand Down Expand Up @@ -246,5 +232,20 @@ void GrantStealthBehavior::loadPostProcess()
// extend base class
UpdateModule::loadPostProcess();

}

// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
void GrantStealthBehavior::createEmitters()
{
if( m_radiusParticleSystemID == INVALID_PARTICLE_SYSTEM_ID )
{
const GrantStealthBehaviorModuleData *d = getGrantStealthBehaviorModuleData();
ParticleSystem *particleSystem = TheParticleSystemManager->createParticleSystem(d->m_radiusParticleSystemTmpl);
if( particleSystem )
{
particleSystem->setPosition( getObject()->getPosition() );
m_radiusParticleSystemID = particleSystem->getSystemID();
}
}
}
Loading