From 18a378139f8cbb58924e93f012b1445a1328e38f Mon Sep 17 00:00:00 2001 From: Christoph Sommer Date: Mon, 5 Feb 2007 20:41:23 +0000 Subject: [PATCH] Fixed nasty bug with remove_listener hooks SVN-Revision: 4814 --- src/game_object.cpp | 34 +++++++++++++++++++++++++++++++++- src/game_object.hpp | 15 +++++++-------- src/trigger/trigger_base.cpp | 27 +++++++++++++++++++++------ src/trigger/trigger_base.hpp | 2 +- 4 files changed, 62 insertions(+), 16 deletions(-) diff --git a/src/game_object.cpp b/src/game_object.cpp index 1faa7bd3f..273367f6e 100644 --- a/src/game_object.cpp +++ b/src/game_object.cpp @@ -18,7 +18,7 @@ // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include - +#include "log.hpp" #include "game_object.hpp" #include "object_remove_listener.hpp" @@ -38,3 +38,35 @@ GameObject::~GameObject() entry = next; } } + + +void +GameObject::add_remove_listener(ObjectRemoveListener* listener) +{ + RemoveListenerListEntry* entry = new RemoveListenerListEntry(); + entry->next = remove_listeners; + entry->listener = listener; + remove_listeners = entry; +} + +void +GameObject::del_remove_listener(ObjectRemoveListener* listener) +{ + RemoveListenerListEntry* entry = remove_listeners; + if (entry->listener == listener) { + remove_listeners = entry->next; + delete entry; + return; + } + RemoveListenerListEntry* next = entry->next; + while(next != NULL) { + if (next->listener == listener) { + entry->next = next->next; + delete next; + break; + } + entry = next; + next = next->next; + } +} + diff --git a/src/game_object.hpp b/src/game_object.hpp index f463f88d4..22aa3a6ad 100644 --- a/src/game_object.hpp +++ b/src/game_object.hpp @@ -69,14 +69,13 @@ public: /** registers a remove listener which will be called if the object * gets removed/destroyed */ - void add_remove_listener(ObjectRemoveListener* listener) - { - RemoveListenerListEntry* entry = new RemoveListenerListEntry(); - entry->next = remove_listeners; - entry->listener = listener; - - remove_listeners = entry; - } + void add_remove_listener(ObjectRemoveListener* listener); + + /** + * unregisters a remove listener, so it will no longer be called if the object + * gets removed/destroyed + */ + void del_remove_listener(ObjectRemoveListener* listener); const std::string& get_name() const { diff --git a/src/trigger/trigger_base.cpp b/src/trigger/trigger_base.cpp index 47e09c532..a221b2998 100644 --- a/src/trigger/trigger_base.cpp +++ b/src/trigger/trigger_base.cpp @@ -22,25 +22,34 @@ #include "trigger_base.hpp" #include "video/drawing_context.hpp" #include "object/player.hpp" +#include "log.hpp" TriggerBase::TriggerBase() - : sprite(0), lasthit(false), hit(false), losetouch_listener(0) + : sprite(0), lasthit(false), hit(false) { set_group(COLGROUP_TOUCHABLE); } TriggerBase::~TriggerBase() { + // unregister remove_listener hooks, so nobody will try to call us after we've been destroyed + for (std::list::iterator i = losetouch_listeners.begin(); i != losetouch_listeners.end(); i++) { + Player* p = *i; + p->del_remove_listener(this); + } + losetouch_listeners.clear(); } void TriggerBase::update(float ) { if (lasthit && !hit) { - if (losetouch_listener) { - event(*losetouch_listener, EVENT_LOSETOUCH); - losetouch_listener = 0; + for (std::list::iterator i = losetouch_listeners.begin(); i != losetouch_listeners.end(); i++) { + Player* p = *i; + event(*p, EVENT_LOSETOUCH); + p->del_remove_listener(this); } + losetouch_listeners.clear(); } lasthit = hit; hit = false; @@ -62,7 +71,7 @@ TriggerBase::collision(GameObject& other, const CollisionHit& ) if(player) { hit = true; if(!lasthit) { - losetouch_listener = player; + losetouch_listeners.push_back(player); player->add_remove_listener(this); event(*player, EVENT_TOUCH); } @@ -74,6 +83,12 @@ TriggerBase::collision(GameObject& other, const CollisionHit& ) void TriggerBase::object_removed(GameObject* object) { - if (losetouch_listener == object) losetouch_listener = 0; + for (std::list::iterator i = losetouch_listeners.begin(); i != losetouch_listeners.end(); i++) { + Player* p = *i; + if (p == object) { + losetouch_listeners.erase(i); + break; + } + } } diff --git a/src/trigger/trigger_base.hpp b/src/trigger/trigger_base.hpp index d03d85b08..571dac5b0 100644 --- a/src/trigger/trigger_base.hpp +++ b/src/trigger/trigger_base.hpp @@ -62,7 +62,7 @@ private: bool lasthit; bool hit; - Player* losetouch_listener; /**< Player that will be informed when we lose touch with him */ + std::list losetouch_listeners; /**< Players that will be informed when we lose touch with them */ }; #endif /*SUPERTUX_INTERACTIVE_OBJECT_H*/ -- 2.11.0