[7237] Fixed crash when MotionMaster's Clean or ExpireMovement called from MovementGenerator update.

Implemented delayed movement generators removed in case cleanup is triggered
from movement generator update. For this purpose is in runtime allocated vector
for temporary store of all deleted movement generators. After delayed delete
this vector is deleted.

Signed-off-by: ApoC <apoc@nymfe.net>
This commit is contained in:
ApoC 2009-01-26 00:54:27 +01:00
parent 7dffae89da
commit 6e65999d86
3 changed files with 119 additions and 9 deletions

View file

@ -74,17 +74,45 @@ MotionMaster::~MotionMaster()
} }
void void
MotionMaster::UpdateMotion(const uint32 &diff) MotionMaster::UpdateMotion(uint32 diff)
{ {
if( i_owner->hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED) ) if( i_owner->hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED) )
return; return;
assert( !empty() ); assert( !empty() );
m_cleanFlag |= MMCF_UPDATE;
if (!top()->Update(*i_owner, diff)) if (!top()->Update(*i_owner, diff))
{
m_cleanFlag &= ~MMCF_UPDATE;
MovementExpired(); MovementExpired();
}
else
m_cleanFlag &= ~MMCF_UPDATE;
if (m_expList)
{
for (int i = 0; i < m_expList.size(); ++i)
{
MovementGenerator* mg = m_expList[i];
if (!isStatic(mg))
delete mg;
}
delete m_expList;
m_expList = NULL;
if (empty())
Initialize();
if (m_cleanFlag & MMCF_RESET)
{
top()->Reset(*i_owner);
m_cleanFlag &= ~MMCF_RESET;
}
}
} }
void void
MotionMaster::Clear(bool reset) MotionMaster::DirectClean(bool reset)
{ {
while( !empty() && size() > 1 ) while( !empty() && size() > 1 )
{ {
@ -103,7 +131,24 @@ MotionMaster::Clear(bool reset)
} }
void void
MotionMaster::MovementExpired(bool reset) MotionMaster::DelayedClean()
{
if (empty() || size() == 1)
return;
m_expList = new ExpireList();
while( !empty() && size() > 1 )
{
MovementGenerator *curr = top();
curr->Finalize(*i_owner);
pop();
if( !isStatic( curr ) )
m_expList->push_back(curr);
}
}
void
MotionMaster::DirectExpire(bool reset)
{ {
if( empty() || size() == 1 ) if( empty() || size() == 1 )
return; return;
@ -129,6 +174,30 @@ MotionMaster::MovementExpired(bool reset)
if (reset) top()->Reset(*i_owner); if (reset) top()->Reset(*i_owner);
} }
void
MotionMaster::DelayedExpire()
{
if( empty() || size() == 1 )
return;
MovementGenerator *curr = top();
curr->Finalize(*i_owner);
pop();
if( !isStatic(curr) )
m_expList->push_back(curr);
m_expList = new ExpireList();
while( !empty() && top()->GetMovementGeneratorType() == TARGETED_MOTION_TYPE )
{
// Should check if target is still valid? If not valid it will crash.
curr = top();
curr->Finalize(*i_owner);
pop();
m_expList->push_back(curr);
}
}
void MotionMaster::MoveIdle() void MotionMaster::MoveIdle()
{ {
if( empty() || !isStatic( top() ) ) if( empty() || !isStatic( top() ) )

View file

@ -21,6 +21,7 @@
#include "Common.h" #include "Common.h"
#include <stack> #include <stack>
#include <vector>
class MovementGenerator; class MovementGenerator;
class Unit; class Unit;
@ -45,13 +46,21 @@ enum MovementGeneratorType
DISTRACT_MOTION_TYPE = 10, // IdleMovementGenerator.h DISTRACT_MOTION_TYPE = 10, // IdleMovementGenerator.h
}; };
enum MMCleanFlag
{
MMCF_NONE = 0,
MMCF_UPDATE = 1, // Clear or Expire called from update
MMCF_RESET = 2 // Flag if need top()->Reset()
};
class MANGOS_DLL_SPEC MotionMaster : private std::stack<MovementGenerator *> class MANGOS_DLL_SPEC MotionMaster : private std::stack<MovementGenerator *>
{ {
private: private:
typedef std::stack<MovementGenerator *> Impl; typedef std::stack<MovementGenerator *> Impl;
typedef std::vector<MovementGenerator *> ExpireList;
public: public:
explicit MotionMaster(Unit *unit) : i_owner(unit) {} explicit MotionMaster(Unit *unit) : i_owner(unit), m_expList(NULL), m_cleanFlag(MMCF_NONE) {}
~MotionMaster(); ~MotionMaster();
void Initialize(); void Initialize();
@ -65,9 +74,33 @@ class MANGOS_DLL_SPEC MotionMaster : private std::stack<MovementGenerator *>
const_iterator begin() const { return Impl::c.begin(); } const_iterator begin() const { return Impl::c.begin(); }
const_iterator end() const { return Impl::c.end(); } const_iterator end() const { return Impl::c.end(); }
void UpdateMotion(const uint32 &diff); void UpdateMotion(uint32 diff);
void Clear(bool reset = true); void Clear(bool reset = true)
void MovementExpired(bool reset = true); {
if (m_cleanFlag & MMCF_UPDATE)
{
if(reset)
m_cleanFlag |= MMCF_RESET;
else
m_cleanFlag &= ~MMCF_RESET;
DelayedClean();
}
else
DirectClean(reset);
}
void MovementExpired(bool reset = true)
{
if (m_cleanFlag & MMCF_UPDATE)
{
if(reset)
m_cleanFlag |= MMCF_RESET;
else
m_cleanFlag &= ~MMCF_RESET;
DelayedExpire();
}
else
DirectExpire(reset);
}
void MoveIdle(); void MoveIdle();
void MoveTargetedHome(); void MoveTargetedHome();
@ -87,6 +120,14 @@ class MANGOS_DLL_SPEC MotionMaster : private std::stack<MovementGenerator *>
private: private:
void Mutate(MovementGenerator *m); // use Move* functions instead void Mutate(MovementGenerator *m); // use Move* functions instead
Unit *i_owner; void DirectClean(bool reset);
void DelayedClean();
void DirectExpire(bool reset);
void DelayedExpire();
Unit *i_owner;
ExpireList *m_expList;
uint8 m_cleanFlag;
}; };
#endif #endif

View file

@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__ #ifndef __REVISION_NR_H__
#define __REVISION_NR_H__ #define __REVISION_NR_H__
#define REVISION_NR "7236" #define REVISION_NR "7237"
#endif // __REVISION_NR_H__ #endif // __REVISION_NR_H__