From 6a65a4cf5b6b10839254c0c5846ec2dbfea882f8 Mon Sep 17 00:00:00 2001 From: Andrei Karas Date: Sat, 23 Jul 2016 02:14:30 +0300 Subject: Allow delete untracker being particle effects. This fix some possible memory leaks. --- src/actormanager.cpp | 15 +++++++++++++++ src/actormanager.h | 2 ++ src/being/actorsprite.cpp | 27 ++++++++++++++++++++++++--- src/being/actorsprite.h | 11 +++++++++-- src/being/being.cpp | 6 +++--- src/being/localplayer.cpp | 2 +- src/effectmanager.cpp | 4 ++-- src/particle/particle.cpp | 11 +++++++++++ src/particle/particle.h | 7 +++++++ src/particle/particlelist.cpp | 5 +++-- 10 files changed, 77 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/actormanager.cpp b/src/actormanager.cpp index 7da8249b0..bee73cd05 100644 --- a/src/actormanager.cpp +++ b/src/actormanager.cpp @@ -405,6 +405,21 @@ Being *ActorManager::findBeing(const BeingId id) const return nullptr; } +ActorSprite *ActorManager::findActor(const BeingId id) const +{ + const ActorSpritesMapConstIterator it = mActorsIdMap.find(id); + if (it != mActorsIdMap.end()) + { + ActorSprite *const actor = (*it).second; + if (actor && + actor->getId() == id) + { + return actor; + } + } + return nullptr; +} + Being *ActorManager::findBeing(const int x, const int y, const ActorTypeT type) const { diff --git a/src/actormanager.h b/src/actormanager.h index 7ab4b1d67..ad53ff729 100644 --- a/src/actormanager.h +++ b/src/actormanager.h @@ -124,6 +124,8 @@ class ActorManager final: public ConfigListener */ Being *findBeing(const BeingId id) const A_WARN_UNUSED; + ActorSprite *findActor(const BeingId id) const A_WARN_UNUSED; + /** * Returns a being at specific coordinates. */ diff --git a/src/being/actorsprite.cpp b/src/being/actorsprite.cpp index f0dfc07ec..3a9c457a4 100644 --- a/src/being/actorsprite.cpp +++ b/src/being/actorsprite.cpp @@ -33,6 +33,7 @@ #include "listeners/debugmessagelistener.h" +#include "particle/particle.h" #include "particle/particleengine.h" #include "resources/db/statuseffectdb.h" @@ -141,9 +142,29 @@ void ActorSprite::setMap(Map *const map) mMustResetParticles = true; // Reset status particles on next redraw } -void ActorSprite::controlParticle(Particle *const particle) +void ActorSprite::controlAutoParticle(Particle *const particle) { - mChildParticleEffects.addLocally(particle); + if (particle) + { + particle->setActor(mId); + mChildParticleEffects.addLocally(particle); + } +} + +void ActorSprite::controlCustomParticle(Particle *const particle) +{ + if (particle) + { + // The effect may not die without the beings permission or we segfault + particle->disableAutoDelete(); + mChildParticleEffects.addLocally(particle); + } +} + +void ActorSprite::controlParticleDeleted(Particle *const particle) +{ + if (particle) + mChildParticleEffects.removeLocally(particle); } void ActorSprite::setTargetType(const TargetCursorTypeT type) @@ -456,7 +477,7 @@ void ActorSprite::setupSpriteDisplay(const SpriteDisplay &display, FOR_EACH (StringVectCIter, itr, display.particles) { Particle *const p = particleEngine->addEffect(*itr, 0, 0); - controlParticle(p); + controlAutoParticle(p); } } diff --git a/src/being/actorsprite.h b/src/being/actorsprite.h index 6f5c020c2..c06f1c983 100644 --- a/src/being/actorsprite.h +++ b/src/being/actorsprite.h @@ -81,9 +81,14 @@ class ActorSprite notfinal : public CompoundSprite, public Actor { return BlockType::NONE; } /** - * Take control of a particle. + * Take control of a particle. Particle can be auto deleted. */ - void controlParticle(Particle *const particle); + void controlAutoParticle(Particle *const particle); + + /** + * Take control of a particle. Owner must remove particle by self. + */ + void controlCustomParticle(Particle *const particle); /** * Returns the required size of a target cursor for this being. @@ -190,6 +195,8 @@ class ActorSprite notfinal : public CompoundSprite, public Actor mChildParticleEffects.size(); } + void controlParticleDeleted(Particle *const particle); + protected: /** * A status effect block is a 16 bit mask of status effects. We assign diff --git a/src/being/being.cpp b/src/being/being.cpp index b5732b15f..0cf52c353 100644 --- a/src/being/being.cpp +++ b/src/being/being.cpp @@ -1349,7 +1349,7 @@ void Being::fireMissile(Being *restrict const victim, { target->moveBy(Vector(0.0F, 0.0F, 32.0F)); target->setLifetime(1000); - victim->controlParticle(target); + victim->controlAutoParticle(target); missile->setDestination(target, 7, 0); missile->setDieDistance(8); @@ -4849,7 +4849,7 @@ void Being::addItemParticles(const int id, FOR_EACH (StringVectCIter, itr, display.particles) { Particle *const p = particleEngine->addEffect(*itr, 0, 0); - controlParticle(p); + controlCustomParticle(p); pi->files.push_back(*itr); pi->particles.push_back(p); } @@ -4893,7 +4893,7 @@ void Being::recreateItemParticles() restrict2 { Particle *const p = particleEngine->addEffect( *str, 0, 0); - controlParticle(p); + controlCustomParticle(p); pi->particles.push_back(p); } } diff --git a/src/being/localplayer.cpp b/src/being/localplayer.cpp index 25699f704..e065fafe4 100644 --- a/src/being/localplayer.cpp +++ b/src/being/localplayer.cpp @@ -2709,7 +2709,7 @@ void LocalPlayer::setTestParticle(const std::string &fileName, if (!fileName.empty()) { mTestParticle = particleEngine->addEffect(fileName, 0, 0, 0); - controlParticle(mTestParticle); + controlCustomParticle(mTestParticle); if (updateHash) mTestParticleHash = UpdaterWindow::getFileHash(mTestParticleName); } diff --git a/src/effectmanager.cpp b/src/effectmanager.cpp index feec7ae98..7ed51092d 100644 --- a/src/effectmanager.cpp +++ b/src/effectmanager.cpp @@ -134,7 +134,7 @@ bool EffectManager::trigger(const int id, { Particle *const selfFX = particleEngine->addEffect( effect.gfx, 0, 0, rotation); - being->controlParticle(selfFX); + being->controlAutoParticle(selfFX); } if (!effect.sfx.empty()) soundManager.playSfx(effect.sfx); @@ -165,7 +165,7 @@ Particle *EffectManager::triggerReturn(const int id, { rValue = particleEngine->addEffect( effect.gfx, 0, 0, rotation); - being->controlParticle(rValue); + being->controlCustomParticle(rValue); } if (!effect.sfx.empty()) soundManager.playSfx(effect.sfx); diff --git a/src/particle/particle.cpp b/src/particle/particle.cpp index 4e7b154c0..a04cee6f3 100644 --- a/src/particle/particle.cpp +++ b/src/particle/particle.cpp @@ -22,8 +22,11 @@ #include "particle/particle.h" +#include "actormanager.h" #include "logger.h" +#include "being/actorsprite.h" + #include "particle/animationparticle.h" #include "particle/particleemitter.h" #include "particle/rotationalparticle.h" @@ -61,6 +64,7 @@ Particle::Particle() : mType(ParticleType::Normal), mAnimation(nullptr), mImage(nullptr), + mActor(BeingId_zero), mChildEmitters(), mChildParticles(), mChildMoveParticles(), @@ -82,6 +86,13 @@ Particle::Particle() : Particle::~Particle() { + if (mActor != BeingId_zero && + actorManager) + { + ActorSprite *const actor = actorManager->findActor(mActor); + if (actor) + actor->controlParticleDeleted(this); + } // Delete child emitters and child particles clear(); delete2(mAnimation); diff --git a/src/particle/particle.h b/src/particle/particle.h index f1a8154b6..859a61505 100644 --- a/src/particle/particle.h +++ b/src/particle/particle.h @@ -28,6 +28,8 @@ #include "enums/particle/alivestatus.h" #include "enums/particle/particletype.h" +#include "enums/simpletypes/beingid.h" + #include "particle/particleengine.h" #include "localconsts.h" @@ -238,6 +240,9 @@ class Particle notfinal : public Actor const signed char conditions) restrict2 { mDeathEffect = effectFile; mDeathEffectConditions = conditions; } + void setActor(const BeingId actor) + { mActor = actor; } + protected: void updateSelf() restrict2; @@ -270,6 +275,8 @@ class Particle notfinal : public Actor /**< The image used for this particle. */ Image *restrict mImage; + BeingId mActor; + private: // List of child emitters. Emitters mChildEmitters; diff --git a/src/particle/particlelist.cpp b/src/particle/particlelist.cpp index 0d2a2f195..209ecfd32 100644 --- a/src/particle/particlelist.cpp +++ b/src/particle/particlelist.cpp @@ -44,8 +44,6 @@ void ParticleList::addLocally(Particle *const particle) { if (particle) { - // The effect may not die without the beings permission or we segfault - particle->disableAutoDelete(); mElements.push_back(particle); mSize ++; } @@ -74,7 +72,10 @@ void ParticleList::removeLocally(const Particle *const particle) void ParticleList::clearLocally() { FOR_EACH (ParticleListCIter, it, mElements) + { (*it)->kill(); + (*it)->prepareToDie(); + } mElements.clear(); mSize = 0U; -- cgit v1.2.3-60-g2f50