[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
MotionMaster::UpdateMotion(const uint32 &diff)
MotionMaster::UpdateMotion(uint32 diff)
{
if( i_owner->hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED) )
return;
assert( !empty() );
m_cleanFlag |= MMCF_UPDATE;
if (!top()->Update(*i_owner, diff))
{
m_cleanFlag &= ~MMCF_UPDATE;
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
MotionMaster::Clear(bool reset)
MotionMaster::DirectClean(bool reset)
{
while( !empty() && size() > 1 )
{
@ -103,7 +131,24 @@ MotionMaster::Clear(bool reset)
}
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 )
return;
@ -129,6 +174,30 @@ MotionMaster::MovementExpired(bool reset)
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()
{
if( empty() || !isStatic( top() ) )

View file

@ -21,6 +21,7 @@
#include "Common.h"
#include <stack>
#include <vector>
class MovementGenerator;
class Unit;
@ -45,13 +46,21 @@ enum MovementGeneratorType
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 *>
{
private:
typedef std::stack<MovementGenerator *> Impl;
typedef std::vector<MovementGenerator *> ExpireList;
public:
explicit MotionMaster(Unit *unit) : i_owner(unit) {}
explicit MotionMaster(Unit *unit) : i_owner(unit), m_expList(NULL), m_cleanFlag(MMCF_NONE) {}
~MotionMaster();
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 end() const { return Impl::c.end(); }
void UpdateMotion(const uint32 &diff);
void Clear(bool reset = true);
void MovementExpired(bool reset = true);
void UpdateMotion(uint32 diff);
void Clear(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 MoveTargetedHome();
@ -87,6 +120,14 @@ class MANGOS_DLL_SPEC MotionMaster : private std::stack<MovementGenerator *>
private:
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

View file

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