[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 <[email protected]>

(With adaptation)

--HG--
branch : trunk
This commit is contained in:
megamage
2009-02-08 21:43:46 -06:00
parent 62a6911dc7
commit a908f8d002
3 changed files with 155 additions and 88 deletions
+105 -73
View File
@@ -47,11 +47,7 @@ MotionMaster::Initialize()
{
MovementGenerator *curr = top();
pop();
if(!curr)
continue;
curr->Finalize(*i_owner);
if( !isStatic( curr ) )
delete curr;
if(curr) DirectDelete(curr);
}
// set new default movement generator
@@ -72,43 +68,111 @@ MotionMaster::~MotionMaster()
{
MovementGenerator *curr = top();
pop();
if(!curr)
continue;
curr->Finalize(*i_owner);
if( !isStatic( curr ) )
delete curr;
if(curr) DirectDelete(curr);
}
}
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];
DirectDelete(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 )
{
MovementGenerator *curr = top();
pop();
if(!curr)
continue;
curr->Finalize(*i_owner);
if( !isStatic( curr ) )
delete curr;
if(curr) DirectDelete(curr);
}
if(reset)
{
assert( !empty() );
top()->Reset(*i_owner);
}
void
MotionMaster::DelayedClean()
{
while( !empty() && size() > 1 )
{
MovementGenerator *curr = top();
pop();
if(curr) DelayedDelete(curr);
}
}
void
MotionMaster::DirectExpire(bool reset)
{
if( empty() || size() == 1 )
return;
MovementGenerator *curr = top();
pop();
DirectDelete(curr);
while(!top())
--i_top;
if(empty())
Initialize();
if(reset)
top()->Reset(*i_owner);
}
void
MotionMaster::DelayedExpire()
{
if( empty() || size() == 1 )
return;
MovementGenerator *curr = top();
pop();
DelayedDelete(curr);
while(!top())
--i_top;
}
void MotionMaster::MoveIdle(MovementSlot slot)
{
//if( empty() || !isStatic( top() ) )
// push( &si_idleMovement );
if(!isStatic(Impl[slot]))
Mutate(&si_idleMovement, slot);
}
void
@@ -121,43 +185,6 @@ MotionMaster::MoveRandom(float spawndist)
}
}
void
MotionMaster::MovementExpired(bool reset)
{
if( empty() || size() == 1 )
return;
MovementGenerator *curr = top();
curr->Finalize(*i_owner);
pop();
if( !isStatic(curr) )
delete curr;
assert( !empty() );
while(!top())
--i_top;
/*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();
delete curr;
}*/
if( empty() )
Initialize();
if (reset) top()->Reset(*i_owner);
}
void MotionMaster::MoveIdle(MovementSlot slot)
{
//if( empty() || !isStatic( top() ) )
// push( &si_idleMovement );
if(!isStatic(Impl[slot]))
Mutate(&si_idleMovement, slot);
}
void
MotionMaster::MoveTargetedHome()
{
@@ -360,9 +387,10 @@ void MotionMaster::Mutate(MovementGenerator *m, MovementSlot slot)
{
if(MovementGenerator *curr = Impl[slot])
{
curr->Finalize(*i_owner);
if( !isStatic( curr ) )
delete curr;
if(i_top == slot && (m_cleanFlag & MMCF_UPDATE))
DelayedDelete(curr);
else
DirectDelete(curr);
}
else if(i_top < slot)
{
@@ -370,20 +398,6 @@ void MotionMaster::Mutate(MovementGenerator *m, MovementSlot slot)
}
m->Initialize(*i_owner);
Impl[slot] = m;
/*if (!empty())
{
switch(top()->GetMovementGeneratorType())
{
// HomeMovement is not that important, delete it if meanwhile a new comes
case HOME_MOTION_TYPE:
// DistractMovement interrupted by any other movement
case DISTRACT_MOTION_TYPE:
MovementExpired(false);
}
}
m->Initialize(*i_owner);
push(m);*/
}
void MotionMaster::MovePath(uint32 path_id, bool repeatable)
@@ -432,6 +446,24 @@ MovementGeneratorType MotionMaster::GetCurrentMovementGeneratorType() const
return top()->GetMovementGeneratorType();
}
void MotionMaster::DirectDelete(_Ty curr)
{
if(isStatic(curr))
return;
curr->Finalize(*i_owner);
delete curr;
}
void MotionMaster::DelayedDelete(_Ty curr)
{
sLog.outError("CRASH ALARM! Unit (Entry %u) is trying to delete its updating MG (Type %u)!", i_owner->GetEntry(), curr->GetMovementGeneratorType());
if(isStatic(curr))
return;
if(!m_expList)
m_expList = new ExpireList();
m_expList->push_back(curr);
}
bool MotionMaster::GetDestination(float &x, float &y, float &z)
{
if(empty())
+47 -12
View File
@@ -22,7 +22,7 @@
#define TRINITY_MOTIONMASTER_H
#include "Common.h"
#include <stack>
#include <vector>
class MovementGenerator;
class Unit;
@@ -55,12 +55,20 @@ enum MovementSlot
MAX_MOTION_SLOT,
};
enum MMCleanFlag
{
MMCF_NONE = 0,
MMCF_UPDATE = 1, // Clear or Expire called from update
MMCF_RESET = 2 // Flag if need top()->Reset()
};
class TRINITY_DLL_SPEC MotionMaster //: private std::stack<MovementGenerator *>
{
private:
//typedef std::stack<MovementGenerator *> Impl;
typedef MovementGenerator* _Ty;
_Ty Impl[MAX_MOTION_SLOT];
typedef std::vector<_Ty> ExpireList;
int i_top;
bool empty() const { return i_top < 0; }
@@ -68,7 +76,7 @@ class TRINITY_DLL_SPEC MotionMaster //: private std::stack<MovementGenerator *>
void push(_Ty _Val) { ++i_top; Impl[i_top] = _Val; }
public:
explicit MotionMaster(Unit *unit) : i_owner(unit), i_top(-1)
explicit MotionMaster(Unit *unit) : i_owner(unit), m_expList(NULL), m_cleanFlag(MMCF_NONE), i_top(-1)
{
for(int i = 0; i < MAX_MOTION_SLOT; ++i)
Impl[i] = NULL;
@@ -77,21 +85,40 @@ class TRINITY_DLL_SPEC MotionMaster //: private std::stack<MovementGenerator *>
void Initialize();
//MovementGenerator* operator->(void) { return top(); }
int size() const { return i_top + 1; }
_Ty top() const { return Impl[i_top]; }
_Ty GetMotionSlot(int slot) { return Impl[slot]; }
/*using Impl::top;
using Impl::empty;
typedef Impl::container_type::const_iterator const_iterator;
const_iterator begin() const { return Impl::c.begin(); }
const_iterator end() const { return Impl::c.end(); }*/
void DirectDelete(_Ty curr);
void DelayedDelete(_Ty curr);
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(MovementSlot slot = MOTION_SLOT_ACTIVE);
void MoveTargetedHome();
@@ -114,6 +141,14 @@ class TRINITY_DLL_SPEC MotionMaster //: private std::stack<MovementGenerator *>
private:
void Mutate(MovementGenerator *m, MovementSlot slot); // use Move* functions instead
void DirectClean(bool reset);
void DelayedClean();
void DirectExpire(bool reset);
void DelayedExpire();
Unit *i_owner;
ExpireList *m_expList;
uint8 m_cleanFlag;
};
#endif
+1 -1
View File
@@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__
#define __REVISION_NR_H__
#define REVISION_NR "7236"
#define REVISION_NR "7238"
#endif // __REVISION_NR_H__