Fix memory leaks due to messed up memory handling for particles as well as their spawners

This commit is contained in:
sapier 2015-01-05 18:34:59 +01:00
parent e201620ee1
commit 63867b1a37
5 changed files with 285 additions and 184 deletions

View File

@ -248,6 +248,7 @@ Client::Client(
device->getSceneManager(), device->getSceneManager(),
tsrc, this, device tsrc, this, device
), ),
m_particle_manager(&m_env),
m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, ipv6, this), m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, ipv6, this),
m_device(device), m_device(device),
m_server_ser_ver(SER_FMT_VER_INVALID), m_server_ser_ver(SER_FMT_VER_INVALID),
@ -2854,6 +2855,11 @@ MtEventManager* Client::getEventManager()
return m_event; return m_event;
} }
ParticleManager* Client::getParticleManager()
{
return &m_particle_manager;
}
scene::IAnimatedMesh* Client::getMesh(const std::string &filename) scene::IAnimatedMesh* Client::getMesh(const std::string &filename)
{ {
std::map<std::string, std::string>::const_iterator i = std::map<std::string, std::string>::const_iterator i =

View File

@ -454,6 +454,7 @@ public:
virtual u16 allocateUnknownNodeId(const std::string &name); virtual u16 allocateUnknownNodeId(const std::string &name);
virtual ISoundManager* getSoundManager(); virtual ISoundManager* getSoundManager();
virtual MtEventManager* getEventManager(); virtual MtEventManager* getEventManager();
virtual ParticleManager* getParticleManager();
virtual bool checkLocalPrivilege(const std::string &priv) virtual bool checkLocalPrivilege(const std::string &priv)
{ return checkPrivilege(priv); } { return checkPrivilege(priv); }
virtual scene::IAnimatedMesh* getMesh(const std::string &filename); virtual scene::IAnimatedMesh* getMesh(const std::string &filename);
@ -497,8 +498,10 @@ private:
ISoundManager *m_sound; ISoundManager *m_sound;
MtEventManager *m_event; MtEventManager *m_event;
MeshUpdateThread m_mesh_update_thread; MeshUpdateThread m_mesh_update_thread;
ClientEnvironment m_env; ClientEnvironment m_env;
ParticleManager m_particle_manager;
con::Connection m_con; con::Connection m_con;
IrrlichtDevice *m_device; IrrlichtDevice *m_device;
// Server serialization version // Server serialization version

View File

@ -1800,8 +1800,6 @@ void Game::shutdown()
if (sky) if (sky)
sky->drop(); sky->drop();
clear_particles();
/* cleanup menus */ /* cleanup menus */
while (g_menumgr.menuCount() > 0) { while (g_menumgr.menuCount() > 0) {
g_menumgr.m_stack.front()->setVisible(false); g_menumgr.m_stack.front()->setVisible(false);
@ -3016,44 +3014,11 @@ void Game::processClientEvents(CameraOrientation *cam, float *damage_flash)
delete(event.show_formspec.formspec); delete(event.show_formspec.formspec);
delete(event.show_formspec.formname); delete(event.show_formspec.formname);
} else if (event.type == CE_SPAWN_PARTICLE) { } else if ((event.type == CE_SPAWN_PARTICLE) ||
video::ITexture *texture = (event.type == CE_ADD_PARTICLESPAWNER) ||
gamedef->tsrc()->getTexture(*(event.spawn_particle.texture)); (event.type == CE_DELETE_PARTICLESPAWNER)) {
client->getParticleManager()->handleParticleEvent(&event, gamedef,
new Particle(gamedef, smgr, player, client->getEnv(), smgr, player);
*event.spawn_particle.pos,
*event.spawn_particle.vel,
*event.spawn_particle.acc,
event.spawn_particle.expirationtime,
event.spawn_particle.size,
event.spawn_particle.collisiondetection,
event.spawn_particle.vertical,
texture,
v2f(0.0, 0.0),
v2f(1.0, 1.0));
} else if (event.type == CE_ADD_PARTICLESPAWNER) {
video::ITexture *texture =
gamedef->tsrc()->getTexture(*(event.add_particlespawner.texture));
new ParticleSpawner(gamedef, smgr, player,
event.add_particlespawner.amount,
event.add_particlespawner.spawntime,
*event.add_particlespawner.minpos,
*event.add_particlespawner.maxpos,
*event.add_particlespawner.minvel,
*event.add_particlespawner.maxvel,
*event.add_particlespawner.minacc,
*event.add_particlespawner.maxacc,
event.add_particlespawner.minexptime,
event.add_particlespawner.maxexptime,
event.add_particlespawner.minsize,
event.add_particlespawner.maxsize,
event.add_particlespawner.collisiondetection,
event.add_particlespawner.vertical,
texture,
event.add_particlespawner.id);
} else if (event.type == CE_DELETE_PARTICLESPAWNER) {
delete_particlespawner(event.delete_particlespawner.id);
} else if (event.type == CE_HUDADD) { } else if (event.type == CE_HUDADD) {
u32 id = event.hudadd.id; u32 id = event.hudadd.id;
@ -3615,8 +3580,8 @@ void Game::handleDigging(GameRunData *runData,
if (m_cache_enable_particles) { if (m_cache_enable_particles) {
const ContentFeatures &features = const ContentFeatures &features =
client->getNodeDefManager()->get(n); client->getNodeDefManager()->get(n);
addPunchingParticles(gamedef, smgr, player, client->getParticleManager()->addPunchingParticles(gamedef, smgr,
client->getEnv(), nodepos, features.tiles); player, nodepos, features.tiles);
} }
} }
@ -3662,9 +3627,8 @@ void Game::handleDigging(GameRunData *runData,
if (m_cache_enable_particles) { if (m_cache_enable_particles) {
const ContentFeatures &features = const ContentFeatures &features =
client->getNodeDefManager()->get(wasnode); client->getNodeDefManager()->get(wasnode);
addDiggingParticles client->getParticleManager()->addDiggingParticles(gamedef, smgr,
(gamedef, smgr, player, client->getEnv(), player, nodepos, features.tiles);
nodepos, features.tiles);
} }
runData->dig_time = 0; runData->dig_time = 0;
@ -3787,9 +3751,7 @@ void Game::updateFrame(std::vector<aabb3f> &highlight_boxes,
/* /*
Update particles Update particles
*/ */
client->getParticleManager()->step(dtime);
allparticles_step(dtime);
allparticlespawners_step(dtime, client->getEnv());
/* /*
Fog Fog

View File

@ -31,6 +31,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "environment.h" #include "environment.h"
#include "clientmap.h" #include "clientmap.h"
#include "mapnode.h" #include "mapnode.h"
#include "client.h"
/* /*
Utility Utility
@ -43,14 +44,11 @@ v3f random_v3f(v3f min, v3f max)
rand()/(float)RAND_MAX*(max.Z-min.Z)+min.Z); rand()/(float)RAND_MAX*(max.Z-min.Z)+min.Z);
} }
std::vector<Particle*> all_particles;
std::map<u32, ParticleSpawner*> all_particlespawners;
Particle::Particle( Particle::Particle(
IGameDef *gamedef, IGameDef *gamedef,
scene::ISceneManager* smgr, scene::ISceneManager* smgr,
LocalPlayer *player, LocalPlayer *player,
ClientEnvironment &env, ClientEnvironment *env,
v3f pos, v3f pos,
v3f velocity, v3f velocity,
v3f acceleration, v3f acceleration,
@ -66,7 +64,7 @@ Particle::Particle(
{ {
// Misc // Misc
m_gamedef = gamedef; m_gamedef = gamedef;
m_env = &env; m_env = env;
// Texture // Texture
m_material.setFlag(video::EMF_LIGHTING, false); m_material.setFlag(video::EMF_LIGHTING, false);
@ -100,8 +98,6 @@ Particle::Particle(
// Init model // Init model
updateVertices(); updateVertices();
all_particles.push_back(this);
} }
Particle::~Particle() Particle::~Particle()
@ -216,98 +212,6 @@ void Particle::updateVertices()
} }
} }
/*
Helpers
*/
void allparticles_step (float dtime)
{
for(std::vector<Particle*>::iterator i = all_particles.begin();
i != all_particles.end();)
{
if ((*i)->get_expired())
{
(*i)->remove();
delete *i;
i = all_particles.erase(i);
}
else
{
(*i)->step(dtime);
i++;
}
}
}
void addDiggingParticles(IGameDef* gamedef, scene::ISceneManager* smgr,
LocalPlayer *player, ClientEnvironment &env, v3s16 pos,
const TileSpec tiles[])
{
for (u16 j = 0; j < 32; j++) // set the amount of particles here
{
addNodeParticle(gamedef, smgr, player, env, pos, tiles);
}
}
void addPunchingParticles(IGameDef* gamedef, scene::ISceneManager* smgr,
LocalPlayer *player, ClientEnvironment &env,
v3s16 pos, const TileSpec tiles[])
{
addNodeParticle(gamedef, smgr, player, env, pos, tiles);
}
// add a particle of a node
// used by digging and punching particles
void addNodeParticle(IGameDef* gamedef, scene::ISceneManager* smgr,
LocalPlayer *player, ClientEnvironment &env, v3s16 pos,
const TileSpec tiles[])
{
// Texture
u8 texid = myrand_range(0,5);
video::ITexture *texture = tiles[texid].texture;
// Only use first frame of animated texture
f32 ymax = 1;
if(tiles[texid].material_flags & MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES)
ymax /= tiles[texid].animation_frame_count;
float size = rand()%64/512.;
float visual_size = BS*size;
v2f texsize(size*2, ymax*size*2);
v2f texpos;
texpos.X = ((rand()%64)/64.-texsize.X);
texpos.Y = ymax*((rand()%64)/64.-texsize.Y);
// Physics
v3f velocity( (rand()%100/50.-1)/1.5,
rand()%100/35.,
(rand()%100/50.-1)/1.5);
v3f acceleration(0,-9,0);
v3f particlepos = v3f(
(f32)pos.X+rand()%100/200.-0.25,
(f32)pos.Y+rand()%100/200.-0.25,
(f32)pos.Z+rand()%100/200.-0.25
);
new Particle(
gamedef,
smgr,
player,
env,
particlepos,
velocity,
acceleration,
rand()%100/100., // expiration time
visual_size,
true,
false,
texture,
texpos,
texsize);
}
/* /*
ParticleSpawner ParticleSpawner
*/ */
@ -316,7 +220,9 @@ ParticleSpawner::ParticleSpawner(IGameDef* gamedef, scene::ISceneManager *smgr,
u16 amount, float time, u16 amount, float time,
v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
float minexptime, float maxexptime, float minsize, float maxsize, float minexptime, float maxexptime, float minsize, float maxsize,
bool collisiondetection, bool vertical, video::ITexture *texture, u32 id) bool collisiondetection, bool vertical, video::ITexture *texture, u32 id,
ParticleManager *p_manager) :
m_particlemanager(p_manager)
{ {
m_gamedef = gamedef; m_gamedef = gamedef;
m_smgr = smgr; m_smgr = smgr;
@ -343,13 +249,11 @@ ParticleSpawner::ParticleSpawner(IGameDef* gamedef, scene::ISceneManager *smgr,
float spawntime = (float)rand()/(float)RAND_MAX*m_spawntime; float spawntime = (float)rand()/(float)RAND_MAX*m_spawntime;
m_spawntimes.push_back(spawntime); m_spawntimes.push_back(spawntime);
} }
all_particlespawners.insert(std::pair<u32, ParticleSpawner*>(id, this));
} }
ParticleSpawner::~ParticleSpawner() {} ParticleSpawner::~ParticleSpawner() {}
void ParticleSpawner::step(float dtime, ClientEnvironment &env) void ParticleSpawner::step(float dtime, ClientEnvironment* env)
{ {
m_time += dtime; m_time += dtime;
@ -372,7 +276,7 @@ void ParticleSpawner::step(float dtime, ClientEnvironment &env)
*(m_maxsize-m_minsize) *(m_maxsize-m_minsize)
+m_minsize; +m_minsize;
new Particle( Particle* toadd = new Particle(
m_gamedef, m_gamedef,
m_smgr, m_smgr,
m_player, m_player,
@ -387,6 +291,7 @@ void ParticleSpawner::step(float dtime, ClientEnvironment &env)
m_texture, m_texture,
v2f(0.0, 0.0), v2f(0.0, 0.0),
v2f(1.0, 1.0)); v2f(1.0, 1.0));
m_particlemanager->addParticle(toadd);
i = m_spawntimes.erase(i); i = m_spawntimes.erase(i);
} }
else else
@ -431,50 +336,245 @@ void ParticleSpawner::step(float dtime, ClientEnvironment &env)
} }
} }
void allparticlespawners_step (float dtime, ClientEnvironment &env)
ParticleManager::ParticleManager(ClientEnvironment* env) :
m_env(env)
{}
ParticleManager::~ParticleManager()
{ {
clearAll();
}
void ParticleManager::step(float dtime)
{
stepParticles (dtime);
stepSpawners (dtime);
}
void ParticleManager::stepSpawners (float dtime)
{
JMutexAutoLock lock(m_spawner_list_lock);
for(std::map<u32, ParticleSpawner*>::iterator i = for(std::map<u32, ParticleSpawner*>::iterator i =
all_particlespawners.begin(); m_particle_spawners.begin();
i != all_particlespawners.end();) i != m_particle_spawners.end();)
{ {
if (i->second->get_expired()) if (i->second->get_expired())
{ {
delete i->second; delete i->second;
all_particlespawners.erase(i++); m_particle_spawners.erase(i++);
} }
else else
{ {
i->second->step(dtime, env); i->second->step(dtime, m_env);
i++; i++;
} }
} }
} }
void delete_particlespawner (u32 id) void ParticleManager::stepParticles (float dtime)
{ {
if (all_particlespawners.find(id) != all_particlespawners.end()) JMutexAutoLock lock(m_particle_list_lock);
for(std::vector<Particle*>::iterator i = m_particles.begin();
i != m_particles.end();)
{ {
delete all_particlespawners.find(id)->second; if ((*i)->get_expired())
all_particlespawners.erase(id); {
(*i)->remove();
delete *i;
i = m_particles.erase(i);
}
else
{
(*i)->step(dtime);
i++;
}
} }
} }
void clear_particles () void ParticleManager::clearAll ()
{ {
JMutexAutoLock lock(m_spawner_list_lock);
JMutexAutoLock lock2(m_particle_list_lock);
for(std::map<u32, ParticleSpawner*>::iterator i = for(std::map<u32, ParticleSpawner*>::iterator i =
all_particlespawners.begin(); m_particle_spawners.begin();
i != all_particlespawners.end();) i != m_particle_spawners.end();)
{ {
delete i->second; delete i->second;
all_particlespawners.erase(i++); m_particle_spawners.erase(i++);
} }
for(std::vector<Particle*>::iterator i = for(std::vector<Particle*>::iterator i =
all_particles.begin(); m_particles.begin();
i != all_particles.end();) i != m_particles.end();)
{ {
(*i)->remove(); (*i)->remove();
delete *i; delete *i;
i = all_particles.erase(i); i = m_particles.erase(i);
} }
} }
void ParticleManager::handleParticleEvent(ClientEvent *event, IGameDef *gamedef,
scene::ISceneManager* smgr, LocalPlayer *player)
{
if (event->type == CE_DELETE_PARTICLESPAWNER) {
JMutexAutoLock lock(m_spawner_list_lock);
if (m_particle_spawners.find(event->delete_particlespawner.id) !=
m_particle_spawners.end())
{
delete m_particle_spawners.find(event->delete_particlespawner.id)->second;
m_particle_spawners.erase(event->delete_particlespawner.id);
}
// no allocated memory in delete event
return;
}
if (event->type == CE_ADD_PARTICLESPAWNER) {
{
JMutexAutoLock lock(m_spawner_list_lock);
if (m_particle_spawners.find(event->delete_particlespawner.id) !=
m_particle_spawners.end())
{
delete m_particle_spawners.find(event->delete_particlespawner.id)->second;
m_particle_spawners.erase(event->delete_particlespawner.id);
}
}
video::ITexture *texture =
gamedef->tsrc()->getTexture(*(event->add_particlespawner.texture));
ParticleSpawner* toadd = new ParticleSpawner(gamedef, smgr, player,
event->add_particlespawner.amount,
event->add_particlespawner.spawntime,
*event->add_particlespawner.minpos,
*event->add_particlespawner.maxpos,
*event->add_particlespawner.minvel,
*event->add_particlespawner.maxvel,
*event->add_particlespawner.minacc,
*event->add_particlespawner.maxacc,
event->add_particlespawner.minexptime,
event->add_particlespawner.maxexptime,
event->add_particlespawner.minsize,
event->add_particlespawner.maxsize,
event->add_particlespawner.collisiondetection,
event->add_particlespawner.vertical,
texture,
event->add_particlespawner.id,
this);
/* delete allocated content of event */
delete event->add_particlespawner.minpos;
delete event->add_particlespawner.maxpos;
delete event->add_particlespawner.minvel;
delete event->add_particlespawner.maxvel;
delete event->add_particlespawner.minacc;
delete event->add_particlespawner.texture;
delete event->add_particlespawner.maxacc;
{
JMutexAutoLock lock(m_spawner_list_lock);
m_particle_spawners.insert(
std::pair<u32, ParticleSpawner*>(
event->delete_particlespawner.id,
toadd));
}
return;
}
if (event->type == CE_SPAWN_PARTICLE) {
video::ITexture *texture =
gamedef->tsrc()->getTexture(*(event->spawn_particle.texture));
Particle* toadd = new Particle(gamedef, smgr, player, m_env,
*event->spawn_particle.pos,
*event->spawn_particle.vel,
*event->spawn_particle.acc,
event->spawn_particle.expirationtime,
event->spawn_particle.size,
event->spawn_particle.collisiondetection,
event->spawn_particle.vertical,
texture,
v2f(0.0, 0.0),
v2f(1.0, 1.0));
addParticle(toadd);
delete event->spawn_particle.pos;
delete event->spawn_particle.vel;
delete event->spawn_particle.acc;
return;
}
}
void ParticleManager::addDiggingParticles(IGameDef* gamedef, scene::ISceneManager* smgr,
LocalPlayer *player, v3s16 pos, const TileSpec tiles[])
{
for (u16 j = 0; j < 32; j++) // set the amount of particles here
{
addNodeParticle(gamedef, smgr, player, pos, tiles);
}
}
void ParticleManager::addPunchingParticles(IGameDef* gamedef, scene::ISceneManager* smgr,
LocalPlayer *player, v3s16 pos, const TileSpec tiles[])
{
addNodeParticle(gamedef, smgr, player, pos, tiles);
}
void ParticleManager::addNodeParticle(IGameDef* gamedef, scene::ISceneManager* smgr,
LocalPlayer *player, v3s16 pos, const TileSpec tiles[])
{
// Texture
u8 texid = myrand_range(0, 5);
video::ITexture *texture = tiles[texid].texture;
// Only use first frame of animated texture
f32 ymax = 1;
if(tiles[texid].material_flags & MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES)
ymax /= tiles[texid].animation_frame_count;
float size = rand() % 64 / 512.;
float visual_size = BS * size;
v2f texsize(size * 2, ymax * size * 2);
v2f texpos;
texpos.X = ((rand() % 64) / 64. - texsize.X);
texpos.Y = ymax * ((rand() % 64) / 64. - texsize.Y);
// Physics
v3f velocity((rand() % 100 / 50. - 1) / 1.5,
rand() % 100 / 35.,
(rand() % 100 / 50. - 1) / 1.5);
v3f acceleration(0,-9,0);
v3f particlepos = v3f(
(f32) pos.X + rand() %100 /200. - 0.25,
(f32) pos.Y + rand() %100 /200. - 0.25,
(f32) pos.Z + rand() %100 /200. - 0.25
);
Particle* toadd = new Particle(
gamedef,
smgr,
player,
m_env,
particlepos,
velocity,
acceleration,
rand() % 100 / 100., // expiration time
visual_size,
true,
false,
texture,
texpos,
texsize);
addParticle(toadd);
}
void ParticleManager::addParticle(Particle* toadd)
{
JMutexAutoLock lock(m_particle_list_lock);
m_particles.push_back(toadd);
}

View File

@ -28,6 +28,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "localplayer.h" #include "localplayer.h"
#include "environment.h" #include "environment.h"
struct ClientEvent;
class ParticleManager;
class Particle : public scene::ISceneNode class Particle : public scene::ISceneNode
{ {
public: public:
@ -35,7 +38,7 @@ class Particle : public scene::ISceneNode
IGameDef* gamedef, IGameDef* gamedef,
scene::ISceneManager* mgr, scene::ISceneManager* mgr,
LocalPlayer *player, LocalPlayer *player,
ClientEnvironment &env, ClientEnvironment *env,
v3f pos, v3f pos,
v3f velocity, v3f velocity,
v3f acceleration, v3f acceleration,
@ -114,16 +117,18 @@ class ParticleSpawner
bool collisiondetection, bool collisiondetection,
bool vertical, bool vertical,
video::ITexture *texture, video::ITexture *texture,
u32 id); u32 id,
ParticleManager* p_manager);
~ParticleSpawner(); ~ParticleSpawner();
void step(float dtime, ClientEnvironment &env); void step(float dtime, ClientEnvironment *env);
bool get_expired () bool get_expired ()
{ return (m_amount <= 0) && m_spawntime != 0; } { return (m_amount <= 0) && m_spawntime != 0; }
private: private:
ParticleManager* m_particlemanager;
float m_time; float m_time;
IGameDef *m_gamedef; IGameDef *m_gamedef;
scene::ISceneManager *m_smgr; scene::ISceneManager *m_smgr;
@ -144,24 +149,49 @@ class ParticleSpawner
std::vector<float> m_spawntimes; std::vector<float> m_spawntimes;
bool m_collisiondetection; bool m_collisiondetection;
bool m_vertical; bool m_vertical;
}; };
void allparticles_step (float dtime); /**
void allparticlespawners_step (float dtime, ClientEnvironment &env); * Class doing particle as well as their spawners handling
*/
class ParticleManager
{
friend class ParticleSpawner;
public:
ParticleManager(ClientEnvironment* env);
~ParticleManager();
void delete_particlespawner (u32 id); void step (float dtime);
void clear_particles ();
void addDiggingParticles(IGameDef* gamedef, scene::ISceneManager* smgr, void handleParticleEvent(ClientEvent *event,IGameDef *gamedef,
LocalPlayer *player, ClientEnvironment &env, v3s16 pos, scene::ISceneManager* smgr, LocalPlayer *player);
const TileSpec tiles[]);
void addPunchingParticles(IGameDef* gamedef, scene::ISceneManager* smgr, void addDiggingParticles(IGameDef* gamedef, scene::ISceneManager* smgr,
LocalPlayer *player, ClientEnvironment &env, v3s16 pos, LocalPlayer *player, v3s16 pos, const TileSpec tiles[]);
const TileSpec tiles[]);
void addNodeParticle(IGameDef* gamedef, scene::ISceneManager* smgr, void addPunchingParticles(IGameDef* gamedef, scene::ISceneManager* smgr,
LocalPlayer *player, ClientEnvironment &env, v3s16 pos, LocalPlayer *player, v3s16 pos, const TileSpec tiles[]);
const TileSpec tiles[]);
void addNodeParticle(IGameDef* gamedef, scene::ISceneManager* smgr,
LocalPlayer *player, v3s16 pos, const TileSpec tiles[]);
protected:
void addParticle(Particle* toadd);
private:
void stepParticles (float dtime);
void stepSpawners (float dtime);
void clearAll ();
std::vector<Particle*> m_particles;
std::map<u32, ParticleSpawner*> m_particle_spawners;
ClientEnvironment* m_env;
JMutex m_particle_list_lock;
JMutex m_spawner_list_lock;
};
#endif #endif