From a908f8d0024fafc3238201e4c9fa872446b07c04 Mon Sep 17 00:00:00 2001 From: megamage Date: Sun, 8 Feb 2009 21:43:46 -0600 Subject: [PATCH] [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 (With adaptation) --HG-- branch : trunk --- src/game/MotionMaster.cpp | 180 ++++++++++++++++++++++---------------- src/game/MotionMaster.h | 61 ++++++++++--- src/shared/revision_nr.h | 2 +- 3 files changed, 155 insertions(+), 88 deletions(-) diff --git a/src/game/MotionMaster.cpp b/src/game/MotionMaster.cpp index 96072014fa..d74602844a 100644 --- a/src/game/MotionMaster.cpp +++ b/src/game/MotionMaster.cpp @@ -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,45 +68,113 @@ 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() ); + if(reset) 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 MotionMaster::MoveRandom(float spawndist) { @@ -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()) diff --git a/src/game/MotionMaster.h b/src/game/MotionMaster.h index 73145665ae..2822cdcd32 100644 --- a/src/game/MotionMaster.h +++ b/src/game/MotionMaster.h @@ -22,7 +22,7 @@ #define TRINITY_MOTIONMASTER_H #include "Common.h" -#include +#include 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 { private: //typedef std::stack 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 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 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 private: void Mutate(MovementGenerator *m, MovementSlot slot); // 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 diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 0d4ffb5b9b..f8ffeb005b 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7236" + #define REVISION_NR "7238" #endif // __REVISION_NR_H__