From 6796abb46be0befe7d0353c54d17b5a33645837f Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Fri, 15 May 2026 11:53:59 +0200 Subject: [PATCH 1/2] fix(particlesys): Simplify ParticleSystemManagerDummy setup --- .../Include/GameClient/ParticleSys.h | 45 +++++++++++++++++-- .../Source/Common/ReplaySimulation.cpp | 2 - .../Drawable/Update/BeaconClientUpdate.cpp | 6 +-- Core/GameEngine/Source/GameClient/FXList.cpp | 2 +- .../Include/GameClient/GameClient.h | 2 - .../Source/GameClient/GameClient.cpp | 9 ---- 6 files changed, 45 insertions(+), 21 deletions(-) diff --git a/Core/GameEngine/Include/GameClient/ParticleSys.h b/Core/GameEngine/Include/GameClient/ParticleSys.h index 5054cd2b8f8..e9b391c3baa 100644 --- a/Core/GameEngine/Include/GameClient/ParticleSys.h +++ b/Core/GameEngine/Include/GameClient/ParticleSys.h @@ -753,6 +753,8 @@ class ParticleSystemManager : public SubsystemInterface, virtual void reset() override; ///< reset the manager and all particle systems virtual void update() override; ///< update all particle systems + virtual Bool isDummy() const { return false; } + virtual Int getOnScreenParticleCount() = 0; ///< returns the number of particles on screen virtual void setOnScreenParticleCount(int count); @@ -761,8 +763,7 @@ class ParticleSystemManager : public SubsystemInterface, ParticleSystemTemplate *newTemplate( const AsciiString &name ); /// given a template, instantiate a particle system - ParticleSystem *createParticleSystem( const ParticleSystemTemplate *sysTemplate, - Bool createSlaves = TRUE ); + virtual ParticleSystem *createParticleSystem( const ParticleSystemTemplate *sysTemplate, Bool createSlaves = TRUE ); /** given a template, instantiate a particle system. if attachTo is not null, attach the particle system to the given object. @@ -835,15 +836,53 @@ class ParticleSystemManager : public SubsystemInterface, ParticleSystemIDMap m_systemMap; ///< a hash map of all particle systems }; + // TheSuperHackers @feature bobtista 31/01/2026 -// ParticleSystemManager that does nothing. Used for Headless Mode. +// ParticleSystemManager that does nothing. Cannot create particle systems and templates. Used for Headless Mode. class ParticleSystemManagerDummy : public ParticleSystemManager { +#if RETAIL_COMPATIBLE_CRC + struct StaticParticleSystemTemplate : public ParticleSystemTemplate + { + StaticParticleSystemTemplate() + : ParticleSystemTemplate("dummy") {} + }; + struct StaticParticleSystem : public ParticleSystem + { + StaticParticleSystem(const StaticParticleSystemTemplate *sysTemplate) + : ParticleSystem(sysTemplate, ParticleSystemID(0), TRUE) {} + }; +#endif + public: +#if RETAIL_COMPATIBLE_CRC + // Must not overload init to keep loading the particle system templates, + // which are unfortunately needed to preserve the correct logic crc. +#else + virtual void init() override {} + virtual void reset() override {} +#endif + virtual void update() override {} + + virtual Bool isDummy() const override { return true; } + virtual Int getOnScreenParticleCount() override { return 0; } virtual void doParticles(RenderInfoClass &rinfo) override {} virtual void queueParticleRender() override {} + virtual ParticleSystem *createParticleSystem(const ParticleSystemTemplate *sysTemplate, Bool createSlaves = TRUE) override + { +#if RETAIL_COMPATIBLE_CRC + if (sysTemplate == nullptr) + return nullptr; + static StaticParticleSystemTemplate dummyTemplate; + static StaticParticleSystem dummySystem(&dummyTemplate); + return &dummySystem; +#else + return nullptr; +#endif + } + protected: virtual void crc( Xfer *xfer ) override {} virtual void xfer( Xfer *xfer ) override {} diff --git a/Core/GameEngine/Source/Common/ReplaySimulation.cpp b/Core/GameEngine/Source/Common/ReplaySimulation.cpp index 7d18b5cb58f..e6871769a94 100644 --- a/Core/GameEngine/Source/Common/ReplaySimulation.cpp +++ b/Core/GameEngine/Source/Common/ReplaySimulation.cpp @@ -86,8 +86,6 @@ int ReplaySimulation::simulateReplaysInThisProcess(const std::vectorgetPlaybackFrameCount() / LOGICFRAMES_PER_SECOND; while (TheRecorder->isPlaybackInProgress()) { - TheGameClient->updateHeadless(); - const int progressFrameInterval = 10*60*LOGICFRAMES_PER_SECOND; if (TheGameLogic->getFrame() != 0 && TheGameLogic->getFrame() % progressFrameInterval == 0) { diff --git a/Core/GameEngine/Source/GameClient/Drawable/Update/BeaconClientUpdate.cpp b/Core/GameEngine/Source/GameClient/Drawable/Update/BeaconClientUpdate.cpp index 63071f8340c..77a594ab1df 100644 --- a/Core/GameEngine/Source/GameClient/Drawable/Update/BeaconClientUpdate.cpp +++ b/Core/GameEngine/Source/GameClient/Drawable/Update/BeaconClientUpdate.cpp @@ -94,9 +94,7 @@ static ParticleSystem* createParticleSystem( Drawable *draw ) AsciiString templateName; templateName.format("BeaconSmoke%6.6X", (0xffffff & obj->getIndicatorColor())); const ParticleSystemTemplate *particleTemplate = TheParticleSystemManager->findTemplate( templateName ); - - DEBUG_ASSERTCRASH(particleTemplate, ("Could not find particle system %s", templateName.str())); - + DEBUG_ASSERTCRASH(TheParticleSystemManager->isDummy() || particleTemplate, ("Could not find particle system %s", templateName.str())); if (particleTemplate) { system = TheParticleSystemManager->createParticleSystem( particleTemplate ); @@ -107,7 +105,7 @@ static ParticleSystem* createParticleSystem( Drawable *draw ) {// 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.")); + DEBUG_ASSERTCRASH(TheParticleSystemManager->isDummy() || failsafeTemplate, ("Doh, this is bad \n I Could not even find the white particle system to make a failsafe system out of.")); system = TheParticleSystemManager->createParticleSystem( failsafeTemplate ); if (system) { diff --git a/Core/GameEngine/Source/GameClient/FXList.cpp b/Core/GameEngine/Source/GameClient/FXList.cpp index 50ab4135ae0..a9f630638fd 100644 --- a/Core/GameEngine/Source/GameClient/FXList.cpp +++ b/Core/GameEngine/Source/GameClient/FXList.cpp @@ -600,7 +600,7 @@ class ParticleSystemFXNugget : public FXNugget } const ParticleSystemTemplate *tmp = TheParticleSystemManager->findTemplate(m_name); - DEBUG_ASSERTCRASH(tmp, ("ParticleSystem %s not found",m_name.str())); + DEBUG_ASSERTCRASH(TheParticleSystemManager->isDummy() || tmp, ("ParticleSystem %s not found",m_name.str())); if (tmp) { for (Int i = 0; i < m_count; i++ ) diff --git a/GeneralsMD/Code/GameEngine/Include/GameClient/GameClient.h b/GeneralsMD/Code/GameEngine/Include/GameClient/GameClient.h index ea8e3a59c5d..3650be5ee24 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameClient/GameClient.h +++ b/GeneralsMD/Code/GameEngine/Include/GameClient/GameClient.h @@ -98,8 +98,6 @@ class GameClient : public SubsystemInterface, void step(); ///< Do one fixed time step - void updateHeadless(); - void addDrawableToLookupTable( Drawable *draw ); ///< add drawable ID to hash lookup table void removeDrawableFromLookupTable( Drawable *draw ); ///< remove drawable ID from hash lookup table diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp index cb91389555b..d1c956e533a 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp @@ -787,15 +787,6 @@ void GameClient::step() TheDisplay->step(); } -void GameClient::updateHeadless() -{ - // TheSuperHackers @info helmutbuhler 03/05/2025 bobtista 02/02/2026 - // Update particles to prevent accumulation in headless mode. Particles are generated - // during GameLogic and only cleaned up during rendering. update() lets particles finish - // their lifecycle naturally instead of abruptly removing them with reset(). - TheParticleSystemManager->update(); -} - Bool GameClient::isMovieAbortRequested() { if (TheGameEngine) From 00d7bdc8b8498d53a38d27d1561034cdd8ef3acc Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Fri, 22 May 2026 21:22:59 +0200 Subject: [PATCH 2/2] Pass false --- Core/GameEngine/Include/GameClient/ParticleSys.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/GameEngine/Include/GameClient/ParticleSys.h b/Core/GameEngine/Include/GameClient/ParticleSys.h index e9b391c3baa..b8e9ba698ed 100644 --- a/Core/GameEngine/Include/GameClient/ParticleSys.h +++ b/Core/GameEngine/Include/GameClient/ParticleSys.h @@ -850,7 +850,7 @@ class ParticleSystemManagerDummy : public ParticleSystemManager struct StaticParticleSystem : public ParticleSystem { StaticParticleSystem(const StaticParticleSystemTemplate *sysTemplate) - : ParticleSystem(sysTemplate, ParticleSystemID(0), TRUE) {} + : ParticleSystem(sysTemplate, ParticleSystemID(0), false) {} }; #endif