Skip to content

fix(particlesys): Add or simplify null-checks to createParticleSystem calls#2724

Open
stephanmeesters wants to merge 2 commits into
TheSuperHackers:mainfrom
stephanmeesters:fix/createparticlesystem-nullcheck
Open

fix(particlesys): Add or simplify null-checks to createParticleSystem calls#2724
stephanmeesters wants to merge 2 commits into
TheSuperHackers:mainfrom
stephanmeesters:fix/createparticlesystem-nullcheck

Conversation

@stephanmeesters
Copy link
Copy Markdown

@stephanmeesters stephanmeesters commented May 17, 2026

  • Ensure that the result of createParticleSystem is null checked
  • Remove unnecessary particle template checks when straightforward to do so

Todo

  • Replicate in Generals

@stephanmeesters stephanmeesters marked this pull request as ready for review May 17, 2026 11:14
@stephanmeesters stephanmeesters changed the title fix(particlesys): Add or optimize null-checks to createParticleSystem calls refactor(particlesys): Add or optimize null-checks to createParticleSystem calls May 17, 2026
@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 17, 2026

Greptile Summary

This PR eliminates redundant null checks on ParticleSystemTemplate* pointers before calling createParticleSystem, relying on the manager's built-in null guard (if (sysTemplate == nullptr) return nullptr) to handle null templates safely. The change also ensures the return value of createParticleSystem is always checked before use.

  • Null-template guards removed across 14 files — previously each call site checked if (template) before calling createParticleSystem; that check is now absorbed into the function itself, reducing nesting by 1–2 levels in many places.
  • Return-value null checks added or preserved — every call site now explicitly checks the returned ParticleSystem* before dereferencing it, which was occasionally missing or only conditionally reached before.
  • createSlaveSystem simplified (ParticleSys.cpp) — the explicit if (m_slaveTemplate) guard and separate variable initialisation are collapsed into a single assignment; functionally identical.

Confidence Score: 5/5

Safe to merge — all simplifications are backed by the existing null guard inside createParticleSystem, and every return value is properly checked before use.

The refactoring is mechanical and consistent: createParticleSystem already returns nullptr for a null template (confirmed at ParticleSys.cpp lines 3058–3059), so removing the outer template-null guards does not change observable behaviour in any of the 14 files. All new code paths correctly check the returned pointer before dereferencing it.

No files require special attention. The indentation inconsistency in ChinookAIUpdate.cpp is the only cosmetic issue.

Important Files Changed

Filename Overview
Core/GameEngine/Source/GameClient/System/ParticleSys.cpp Removes the redundant if (tmp) guard in update() and simplifies createSlaveSystem by removing the explicit null check before calling createParticleSystem — safe because the manager already returns nullptr for a null template.
Core/GameEngine/Source/GameClient/Drawable/Update/BeaconClientUpdate.cpp Removes nested template/system null checks — simplification is safe; behaviour change in the failsafe else path was already discussed in a prior thread.
Core/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTankTruckDraw.cpp Drops the if (sysTemplate) outer guard; createParticleSystem handles null internally, so the else/error-logging branch now also fires when the template is missing — an improvement in error coverage.
Core/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTruckDraw.cpp Same simplification as W3DTankTruckDraw.cpp; safe for the same reason.
GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/ChinookAIUpdate.cpp Removes the outer if (tmp) guard and flattens the null check; logic is correct but the if (system) block retains the indentation of the old inner scope instead of matching the surrounding code.
GeneralsMD/Code/GameEngine/Source/GameLogic/ScriptEngine/ScriptEngine.cpp Removes the if (parentTemp) wrapper around createParticleSystem; safe because the function returns nullptr for a null argument.
GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/HelicopterSlowDeathUpdate.cpp Removes the if (modData->m_attachParticleSystem) guard, reducing nesting by two levels; subsequent code is correctly gated on the system pointer.
GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/SlavedUpdate.cpp Flattens two levels of null-check nesting around createParticleSystem; safe and improves readability.
GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Behavior/AutoHealBehavior.cpp Removes the if (data->m_unitHealPulseParticleSystemTmpl) guard; since createParticleSystem handles null, the simplification is safe.
GeneralsMD/Code/GameEngine/Source/GameLogic/Object/ObjectCreationList.cpp Removes the if (tmp) guard before createParticleSystem; safe refactor, no logic change.
GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/EMPUpdate.cpp Removes the if (tmp) outer guard and flattens the null-check nesting; safe.
GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/LaserUpdate.cpp Removes the if (tmp) guards for both the main and target particle systems; safe simplification.
GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp Removes the if (tmp) guards in createConnectorFlare and createLaserBaseFlare; safe refactor, no logic change.
GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/StealthDetectorUpdate.cpp Removes three separate template null guards before createParticleSystem calls; all simplifications are safe.

Sequence Diagram

sequenceDiagram
    participant Caller
    participant TPSM as TheParticleSystemManager
    participant PS as ParticleSystem

    Note over Caller,PS: Before this PR
    Caller->>TPSM: findTemplate(name)
    TPSM-->>Caller: tmpl (may be nullptr)
    alt "tmpl != nullptr"
        Caller->>TPSM: createParticleSystem(tmpl)
        TPSM-->>Caller: sys (may be nullptr)
        alt "sys != nullptr"
            Caller->>PS: attachToObject / setPosition / etc.
        end
    end

    Note over Caller,PS: After this PR
    Caller->>TPSM: findTemplate(name)
    TPSM-->>Caller: tmpl (may be nullptr)
    Caller->>TPSM: createParticleSystem(tmpl)
    Note right of TPSM: null guard: if tmpl==nullptr return nullptr
    TPSM-->>Caller: sys (may be nullptr)
    alt "sys != nullptr"
        Caller->>PS: attachToObject / setPosition / etc.
    end
Loading
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/ChinookAIUpdate.cpp:1201-1206
The `if (system)` block (lines 1203–1206) uses 2-tab + 2-space indentation while the two lines above it (1201–1202) use tab + 6-space indentation, which is inconsistent with the surrounding code. The PR removed the outer `if (tmp)` scope but inadvertently left the inner block at its old indentation level rather than normalising it to match the context.

```suggestion
	      const ParticleSystemTemplate *tmp = TheParticleSystemManager->findTemplate( getChinookAIUpdateModuleData()->m_rotorWashParticleSystem );
	      ParticleSystem *system = TheParticleSystemManager->createParticleSystem( tmp );
	      if( system )
	      {
		      system->setPosition( &pos );
	      }
```

Reviews (2): Last reviewed commit: "Process review comments" | Re-trigger Greptile

Comment on lines +100 to 116
system = TheParticleSystemManager->createParticleSystem( particleTemplate );
if (system)
{
system = TheParticleSystemManager->createParticleSystem( particleTemplate );
if (system)
system->attachToDrawable( draw );
system->attachToDrawable( draw );
}
else// This is a failsafe... if someone has monkeyed with the particle system names, or the MP house colors
{// THis this will whip up a new particle system to match the house color provided
templateName.format("BeaconSmokeFFFFFF");
const ParticleSystemTemplate *failsafeTemplate = TheParticleSystemManager->findTemplate( templateName );
DEBUG_ASSERTCRASH(failsafeTemplate, ("Doh, this is bad \n I Could not even find the white particle system to make a failsafe system out of."));
if (failsafeTemplate)
system = TheParticleSystemManager->createParticleSystem( failsafeTemplate );
if (system)
{
system = TheParticleSystemManager->createParticleSystem( failsafeTemplate );
if (system)
{
system->attachToDrawable( draw );
system->tintAllColors( obj->getIndicatorColor() );
}
system->attachToDrawable( draw );
system->tintAllColors( obj->getIndicatorColor() );
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Failsafe else now triggers on a broader condition

Originally the else (fallback to BeaconSmokeFFFFFF) ran only when particleTemplate == nullptr, i.e. when the color-keyed template was not found. After this change it runs whenever createParticleSystem returns nullptr — which includes any future code path (e.g. particle-cap enforcement) where the manager declines to create a system for a valid template. In that scenario the failsafe would silently emit a tinted-white beacon instead of simply producing nothing, which is the unintended behavior the comment describes as "someone has monkeyed with the particle system names".

Prompt To Fix With AI
This is a comment left during a code review.
Path: Core/GameEngine/Source/GameClient/Drawable/Update/BeaconClientUpdate.cpp
Line: 100-116

Comment:
**Failsafe `else` now triggers on a broader condition**

Originally the `else` (fallback to `BeaconSmokeFFFFFF`) ran only when `particleTemplate == nullptr`, i.e. when the color-keyed template was not found. After this change it runs whenever `createParticleSystem` returns `nullptr` — which includes any future code path (e.g. particle-cap enforcement) where the manager declines to create a system for a *valid* template. In that scenario the failsafe would silently emit a tinted-white beacon instead of simply producing nothing, which is the unintended behavior the comment describes as "someone has monkeyed with the particle system names".

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Should investigate if we can remove this failsafe

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 wonder if the failsafe path can be the sole default path. What is the benefit of the preset house color beacons? Do they look different?

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The two paths differ as follows:

  • Primary path: loads a pre-baked BeaconSmoke{RRGGBB} template (e.g. BeaconSmokeFF0000). The color is authored directly into the particle system INI definition.
  • Failsafe path: loads the white BeaconSmokeFFFFFF template and then calls tintAllColors(obj->getIndicatorColor()), which multiplies all particle colors by the house color at runtime.

Visually, if the only difference between the per-color templates and the white one is the baked color value, the two paths would produce identical results — tinting white by 0xRRGGBB gives 0xRRGGBB. So yes, the failsafe could be the sole path with no visual difference, and you'd be able to delete all the BeaconSmoke{color} INI entries except the white one.

The only scenario where they'd differ is if some per-color templates have non-white base colors or other differing properties (emission rate, size, alpha curves, etc.) — in which case those distinctions would be lost. Worth checking the INI data to confirm they're all identical except for color before removing the primary path.

Tip: You can customize Greptile's behavior for this repo with .greptile/rules.md and .greptile/config.json.

@xezon xezon changed the title refactor(particlesys): Add or optimize null-checks to createParticleSystem calls fix(particlesys): Add or simplify null-checks to createParticleSystem calls May 18, 2026
@xezon xezon added Minor Severity: Minor < Major < Critical < Blocker Gen Relates to Generals ZH Relates to Zero Hour Refactor Edits the code with insignificant behavior changes, is never user facing Fix Is fixing something, but is not user facing labels May 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Fix Is fixing something, but is not user facing Gen Relates to Generals Minor Severity: Minor < Major < Critical < Blocker Refactor Edits the code with insignificant behavior changes, is never user facing ZH Relates to Zero Hour

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants