diff --git a/source/gameengine/GameLogic/SCA_IActuator.cpp b/source/gameengine/GameLogic/SCA_IActuator.cpp index c2be36d5108..be7c2651686 100644 --- a/source/gameengine/GameLogic/SCA_IActuator.cpp +++ b/source/gameengine/GameLogic/SCA_IActuator.cpp @@ -67,6 +67,8 @@ void SCA_IActuator::Activate(SG_DList& head) } } +// this function is only used to deactivate actuators outside the logic loop +// e.g. when an object is deleted. void SCA_IActuator::Deactivate() { if (QDelink()) diff --git a/source/gameengine/GameLogic/SCA_IActuator.h b/source/gameengine/GameLogic/SCA_IActuator.h index 2bd92c343b9..27afcbc386b 100644 --- a/source/gameengine/GameLogic/SCA_IActuator.h +++ b/source/gameengine/GameLogic/SCA_IActuator.h @@ -33,8 +33,7 @@ #include /* - * Use of SG_DList : element of actuator being deactivated - * Head: SCA_LogicManager::m_removedActuators + * Use of SG_DList : None * Use of SG_QList : element of activated actuator list of their owner * Head: SCA_IObject::m_activeActuators */ diff --git a/source/gameengine/GameLogic/SCA_ILogicBrick.h b/source/gameengine/GameLogic/SCA_ILogicBrick.h index 90881c0536f..779e5397a6a 100644 --- a/source/gameengine/GameLogic/SCA_ILogicBrick.h +++ b/source/gameengine/GameLogic/SCA_ILogicBrick.h @@ -92,6 +92,34 @@ public: it.add_back(this); } + // insert in a QList at position corresponding to m_Execute_Priority + // inside a longer list that contains elements of other objects. + // Sorting is done only between the elements of the same object. + // head is the head of the combined list + // current points to the first element of the object in the list, NULL if none yet + void InsertSelfActiveQList(SG_QList& head, SG_QList** current) + { + if (!*current) + { + // first element can be put anywhere + head.QAddBack(this); + *current = this; + return; + } + // note: we assume current points actually to one o our element, skip the tests + SG_QList::iterator it(head,*current); + if (m_Execute_Priority <= (*it)->m_Execute_Priority) + { + // this element comes before the first + *current = this; + } + else + { + for(++it; !it.end() && (*it)->m_gameobj == m_gameobj && m_Execute_Priority > (*it)->m_Execute_Priority; ++it); + } + it.add_back(this); + } + virtual bool LessComparedTo(SCA_ILogicBrick* other); virtual PyObject* py_getattro(PyObject *attr); diff --git a/source/gameengine/GameLogic/SCA_IObject.cpp b/source/gameengine/GameLogic/SCA_IObject.cpp index 2b87a7c1526..9876f2512c0 100644 --- a/source/gameengine/GameLogic/SCA_IObject.cpp +++ b/source/gameengine/GameLogic/SCA_IObject.cpp @@ -41,7 +41,8 @@ MT_Point3 SCA_IObject::m_sDummy=MT_Point3(0,0,0); SG_QList SCA_IObject::m_activeBookmarkedControllers; -SCA_IObject::SCA_IObject(PyTypeObject* T): CValue(T), m_initState(0), m_state(0) +SCA_IObject::SCA_IObject(PyTypeObject* T): CValue(T), m_initState(0), m_state(0), m_firstState(NULL) + { m_suspended = false; } diff --git a/source/gameengine/GameLogic/SCA_IObject.h b/source/gameengine/GameLogic/SCA_IObject.h index c4f346059d4..eae427741ca 100644 --- a/source/gameengine/GameLogic/SCA_IObject.h +++ b/source/gameengine/GameLogic/SCA_IObject.h @@ -52,6 +52,7 @@ class SCA_IObject : public CValue Py_Header; protected: + friend class KX_StateActuator; friend class SCA_IActuator; friend class SCA_IController; SCA_SensorList m_sensors; @@ -97,6 +98,11 @@ protected: */ unsigned int m_state; + /** + * pointer inside state actuator list for sorting + */ + SG_QList* m_firstState; + public: SCA_IObject(PyTypeObject* T=&Type); diff --git a/source/gameengine/GameLogic/SCA_LogicManager.cpp b/source/gameengine/GameLogic/SCA_LogicManager.cpp index 7acec465921..83271288154 100644 --- a/source/gameengine/GameLogic/SCA_LogicManager.cpp +++ b/source/gameengine/GameLogic/SCA_LogicManager.cpp @@ -212,17 +212,22 @@ void SCA_LogicManager::UpdateFrame(double curtime, bool frame) (*ie)->UpdateFrame(); SG_DList::iterator io(m_activeActuators); - for (io.begin(); !io.end(); ++io) + for (io.begin(); !io.end(); ) { - SG_QList::iterator ia(*(*io)); - for (ia.begin(); !ia.end(); ++ia) + SG_QList* ahead = *io; + // increment now so that we can remove the current element + ++io; + SG_QList::iterator ia(*ahead); + for (ia.begin(); !ia.end(); ) { SCA_IActuator* actua = *ia; + // increment first to allow removal of inactive actuators. + ++ia; if (!actua->Update(curtime, frame)) { - // cannot deactive the actuator now as it will disturb the list - m_removedActuators.AddBack(actua); - actua->SetActive(false); + // this actuator is not active anymore, remove + actua->QDelink(); + actua->SetActive(false); } else if (actua->IsNoLink()) { // This actuator has no more links but it still active @@ -235,14 +240,11 @@ void SCA_LogicManager::UpdateFrame(double curtime, bool frame) actua->AddEvent(event); } } - } - - for (SCA_IActuator* act = (SCA_IActuator*)m_removedActuators.Remove(); - act != NULL; - act = (SCA_IActuator*)m_removedActuators.Remove()) - { - act->Deactivate(); - act->SetActive(false); + if (ahead->QEmpty()) + { + // no more active controller, remove from main list + ahead->Delink(); + } } } diff --git a/source/gameengine/GameLogic/SCA_LogicManager.h b/source/gameengine/GameLogic/SCA_LogicManager.h index fe7b40b3ba4..53e75e1eaee 100644 --- a/source/gameengine/GameLogic/SCA_LogicManager.h +++ b/source/gameengine/GameLogic/SCA_LogicManager.h @@ -87,9 +87,6 @@ class SCA_LogicManager GEN_Map m_map_gamemeshname_to_blendobj; GEN_Map m_map_blendobj_to_gameobj; - - // head of actuators being deactivated during the logic update - SG_DList m_removedActuators; public: SCA_LogicManager(); virtual ~SCA_LogicManager(); diff --git a/source/gameengine/Ketsji/KX_StateActuator.cpp b/source/gameengine/Ketsji/KX_StateActuator.cpp index 5f9730d7e10..f6979eee0f4 100644 --- a/source/gameengine/Ketsji/KX_StateActuator.cpp +++ b/source/gameengine/Ketsji/KX_StateActuator.cpp @@ -73,7 +73,10 @@ KX_StateActuator::Update() { bool bNegativeEvent = IsNegativeEvent(); unsigned int objMask; - + + // execution of state actuator means that we are in the execution phase, reset this pointer + // because all the active actuator of this object will be removed for sure. + m_gameobj->m_firstState = NULL; RemoveAllEvents(); if (bNegativeEvent) return false; @@ -102,6 +105,8 @@ KX_StateActuator::Update() return false; } +// this function is only used to deactivate actuators outside the logic loop +// e.g. when an object is deleted. void KX_StateActuator::Deactivate() { if (QDelink()) @@ -115,9 +120,10 @@ void KX_StateActuator::Deactivate() void KX_StateActuator::Activate(SG_DList& head) { - // no need to sort the state actuators - if (m_stateActuatorHead.QAddBack(this)) + // sort the state actuators per object on the global list + if (QEmpty()) { + InsertSelfActiveQList(m_stateActuatorHead, &m_gameobj->m_firstState); // add front to make sure it runs before other actuators head.AddFront(&m_stateActuatorHead); } diff --git a/source/gameengine/SceneGraph/SG_QList.h b/source/gameengine/SceneGraph/SG_QList.h index 7a6b2e466c9..d8afc33ea4f 100644 --- a/source/gameengine/SceneGraph/SG_QList.h +++ b/source/gameengine/SceneGraph/SG_QList.h @@ -49,7 +49,7 @@ public: T* m_current; public: typedef iterator _myT; - iterator(SG_QList& head) : m_head(head), m_current(NULL) {} + iterator(SG_QList& head, SG_QList* current=NULL) : m_head(head) { m_current = (T*)current; } ~iterator() {} void begin()