Browse Source

Merge pull request #376 from greenfire27/ObjToObjEvents

Object to Object Events
Peter Robinson 9 years ago
parent
commit
cba9267c7b

+ 5 - 5
engine/source/2d/sceneobject/SceneObjectList.cc

@@ -28,7 +28,7 @@
 
 void SceneObjectList::pushBack(SceneObject* obj)
 {
-	if (find(begin(),end(),obj) == end())
+   if (::find(begin(), end(), obj) == end())
 		push_back(obj);
 }	
 
@@ -36,7 +36,7 @@ void SceneObjectList::pushBack(SceneObject* obj)
 
 void SceneObjectList::pushBackForce(SceneObject* obj)
 {
-	iterator itr = find(begin(),end(),obj);
+	iterator itr = ::find(begin(),end(),obj);
 	if (itr == end()) 
 	{
 		push_back(obj);
@@ -54,7 +54,7 @@ void SceneObjectList::pushBackForce(SceneObject* obj)
 
 void SceneObjectList::pushFront(SceneObject* obj)
 {
-	if (find(begin(),end(),obj) == end())
+	if (::find(begin(),end(),obj) == end())
 		push_front(obj);
 }	
 
@@ -62,7 +62,7 @@ void SceneObjectList::pushFront(SceneObject* obj)
 
 void SceneObjectList::remove(SceneObject* obj)
 {
-	iterator ptr = find(begin(),end(),obj);
+	iterator ptr = ::find(begin(),end(),obj);
 	if (ptr != end()) 
 		erase(ptr);
 }
@@ -71,7 +71,7 @@ void SceneObjectList::remove(SceneObject* obj)
 
 void SceneObjectList::removeStable(SceneObject* obj)
 {
-	iterator ptr = find(begin(),end(),obj);
+	iterator ptr = ::find(begin(),end(),obj);
 	if (ptr != end()) 
 		erase(ptr);
 }

+ 3 - 3
engine/source/collection/simpleHashTable.h

@@ -79,17 +79,17 @@ public:
 
 template <class T> inline void SimpleHashTable<T>::insert(T* pObject, U8 *key, U32 keyLen)
 {
-   Parent::insert(pObject, hash(key, keyLen, 0));
+   Parent::insert(pObject, ::hash(key, keyLen, 0));
 }
 
 template <class T> inline T* SimpleHashTable<T>::remove(U8 *key, U32 keyLen)
 {
-   return Parent::remove(hash(key, keyLen, 0));
+   return Parent::remove(::hash(key, keyLen, 0));
 }
 
 template <class T> inline T* SimpleHashTable<T>::retrieve(U8 *key, U32 keyLen)
 {
-   return Parent::retrieve(hash(key, keyLen, 0));
+   return Parent::retrieve(::hash(key, keyLen, 0));
 }
 
 template <class T> inline void SimpleHashTable<T>::insert(T* pObject, const char *key)

+ 5 - 5
engine/source/sim/SimObjectList.cc

@@ -28,7 +28,7 @@
 
 void SimObjectList::pushBack(SimObject* obj)
 {
-   if (find(begin(),end(),obj) == end())
+   if (::find(begin(),end(),obj) == end())
       push_back(obj);
 }	
 
@@ -36,7 +36,7 @@ void SimObjectList::pushBack(SimObject* obj)
 
 void SimObjectList::pushBackForce(SimObject* obj)
 {
-   iterator itr = find(begin(),end(),obj);
+   iterator itr = ::find(begin(),end(),obj);
    if (itr == end()) 
    {
       push_back(obj);
@@ -55,7 +55,7 @@ void SimObjectList::pushBackForce(SimObject* obj)
 
 void SimObjectList::pushFront(SimObject* obj)
 {
-   if (find(begin(),end(),obj) == end())
+   if (::find(begin(),end(),obj) == end())
       push_front(obj);
 }	
 
@@ -63,7 +63,7 @@ void SimObjectList::pushFront(SimObject* obj)
 
 void SimObjectList::remove(SimObject* obj)
 {
-   iterator ptr = find(begin(),end(),obj);
+   iterator ptr = ::find(begin(),end(),obj);
    if (ptr != end()) 
       erase(ptr);
 }
@@ -72,7 +72,7 @@ void SimObjectList::remove(SimObject* obj)
 
 void SimObjectList::removeStable(SimObject* obj)
 {
-   iterator ptr = find(begin(),end(),obj);
+   iterator ptr = ::find(begin(),end(),obj);
    if (ptr != end()) 
       erase(ptr);
 }

+ 97 - 0
engine/source/sim/simObject.cc

@@ -31,6 +31,7 @@
 #include "console/ConsoleTypeValidators.h"
 
 #include "simObject_ScriptBinding.h"
+#include <algorithm>
 
 //-----------------------------------------------------------------------------
 
@@ -67,6 +68,7 @@ SimObject::SimObject()
     mSuperClassName          = NULL;
     mProgenitorFile          = CodeBlock::getCurrentCodeBlockFullPath();
     mPeriodicTimerID         = 0;
+    bIsEventRaised           = false;
 }
 
 //---------------------------------------------------------------------------
@@ -1382,6 +1384,101 @@ void SimObject::setSuperClassNamespace( const char* superClassNamespace )
 
 //-----------------------------------------------------------------------------
 
+void SimObject::addListener(std::string objID)
+{
+   for (auto iter = mListenerList.begin(); iter != mListenerList.end(); ++iter)
+   {
+      if (iter->objID == objID)
+      {
+         iter->doomed = false;
+         return;
+      }
+   }
+
+   OtoListener listener = OtoListener();
+   listener.objID = objID;
+   listener.doomed = false;
+   mListenerList.push_back(listener);
+}
+
+//-----------------------------------------------------------------------------
+
+void SimObject::removeListener(std::string objID)
+{
+   for (auto iter = mListenerList.begin(); iter != mListenerList.end(); ++iter)
+   {
+      if (iter->objID == objID)
+      {
+         iter->doomed = true;
+      }
+   }
+   
+   if (!bIsEventRaised)
+   {
+      mListenerList.erase(std::remove_if(mListenerList.begin(), mListenerList.end(), [](OtoListener listener){ return listener.doomed; }), mListenerList.end());
+   }
+}
+
+//-----------------------------------------------------------------------------
+
+void SimObject::removeAllListeners()
+{
+   if (bIsEventRaised)
+   {
+      for (auto iter = mListenerList.begin(); iter != mListenerList.end(); ++iter)
+      {
+         iter->doomed = true;
+      }
+   }
+   else
+   {
+      mListenerList.clear();
+   }
+}
+
+//-----------------------------------------------------------------------------
+
+void SimObject::postEvent(std::string eventName, std::string data)
+{
+   std::string onEvent = "on" + eventName;
+   if (mListenerList.empty())
+   {
+      return;
+   }
+
+   if (bIsEventRaised)
+   {
+      Con::warnf("SimObject::postEvent() - To avoid circular events, you cannot raise the event '%s' until a previous event has finished.", eventName.c_str());
+      return;
+   }
+
+   bIsEventRaised = true;
+   for (auto iter = mListenerList.begin(); iter != mListenerList.end(); ++iter)
+   {
+      SimObject* pSimObject = dynamic_cast<SimObject*>(Sim::findObject(iter->objID.c_str()));
+
+      // Did we find the object?
+      if (pSimObject)
+      {
+         if (!iter->doomed && pSimObject->isMethod(onEvent.c_str()))
+         {
+            Con::executef(pSimObject, 3, onEvent.c_str(), data.c_str());
+         }
+      }
+      else
+      {
+         //it must have been deleted
+         iter->doomed = true;
+      }
+   }
+   bIsEventRaised = false;
+
+   //now to remove all doomed listeners
+   mListenerList.erase(std::remove_if(mListenerList.begin(), mListenerList.end(), [](OtoListener listener){ return listener.doomed; }), mListenerList.end());
+}
+
+//-----------------------------------------------------------------------------
+
 static S32 QSORT_CALLBACK compareFields(const void* a,const void* b)
 {
    const AbstractClassRep::Field* fa = *((const AbstractClassRep::Field**)a);

+ 20 - 0
engine/source/sim/simObject.h

@@ -37,6 +37,8 @@
 
 //-----------------------------------------------------------------------------
 
+using namespace std;
+#include <vector>
 typedef U32 SimObjectId;
 class SimGroup;
 
@@ -705,6 +707,24 @@ public:
 
     /// @}
 
+    /// @Object to Object Events
+    /// @{
+private:
+    struct OtoListener {
+        bool doomed;
+        std::string objID;
+    };
+    std::vector<OtoListener> mListenerList;
+    bool bIsEventRaised;
+public:
+    void addListener(std::string objID);
+    void removeListener(std::string objID);
+    void removeAllListeners();
+    void postEvent(std::string eventName, std::string data);
+
+    /// @}
+
+public:
     virtual void            dump();
     virtual void            dumpClassHierarchy();
 

+ 117 - 0
engine/source/sim/simObject_ScriptBinding.h

@@ -1018,4 +1018,121 @@ ConsoleMethodWithDocs(SimObject,schedule, ConsoleInt, 4, 0, (time , command , [a
 
 /*! @} */ // member group Timer Events
 
+/*! @name member group Object to Object Events
+Raise events for listening objects to consume.
+@{
+*/
+
+/*! Starts listening to another object.
+   @param SimObject The object that will be posting events.
+@return No return value.
+*/
+ConsoleMethodWithDocs(SimObject, startListening, ConsoleVoid, 3, 3, (SimObject))
+{
+   // Find the specified object.
+   SimObject* pSimObject = dynamic_cast<SimObject*>(Sim::findObject(argv[2]));
+
+   // Did we find the object?
+   if (!pSimObject)
+   {
+      // No, so warn.
+      Con::warnf("SimObject::startListening() - Could not find the specified object '%s'.", argv[2]);
+      return;
+   }
+
+   // Start Listening
+   pSimObject->addListener(object->getIdString());
+}
+
+/*! Stops listening to another object.
+@param SimObject The object that will be posting events.
+@return No return value.
+*/
+ConsoleMethodWithDocs(SimObject, stopListening, ConsoleVoid, 3, 3, (SimObject))
+{
+   // Find the specified object.
+   SimObject* pSimObject = dynamic_cast<SimObject*>(Sim::findObject(argv[2]));
+
+   // Did we find the object?
+   if (!pSimObject)
+   {
+      // No, so warn.
+      Con::warnf("SimObject::stopListening() - Could not find the specified object '%s'.", argv[2]);
+      return;
+   }
+
+   // Stop Listening
+   pSimObject->removeListener(object->getIdString());
+}
+
+/*! Adds an object so that it receives events from this object.
+@param SimObject The object that will be listening to events.
+@return No return value.
+*/
+ConsoleMethodWithDocs(SimObject, addListener, ConsoleVoid, 3, 3, (SimObject))
+{
+   // Find the specified object.
+   SimObject* pSimObject = dynamic_cast<SimObject*>(Sim::findObject(argv[2]));
+
+   // Did we find the object?
+   if (!pSimObject)
+   {
+      // No, so warn.
+      Con::warnf("SimObject::addListener() - Could not find the specified object '%s'.", argv[2]);
+      return;
+   }
+
+   // Start Listening
+   object->addListener(pSimObject->getIdString());
+}
+
+/*! Removes an object so that it no longer receives events from this object.
+@param SimObject The object that will stop listening to events.
+@return No return value.
+*/
+ConsoleMethodWithDocs(SimObject, removeListener, ConsoleVoid, 3, 3, (SimObject))
+{
+   // Find the specified object.
+   SimObject* pSimObject = dynamic_cast<SimObject*>(Sim::findObject(argv[2]));
+
+   // Did we find the object?
+   if (!pSimObject)
+   {
+      // No, so warn.
+      Con::warnf("SimObject::removeListener() - Could not find the specified object '%s'.", argv[2]);
+      return;
+   }
+
+   // Start Listening
+   object->removeListener(pSimObject->getIdString());
+}
+
+/*! Removes all listeners from this object.
+@return No return value.
+*/
+ConsoleMethodWithDocs(SimObject, removeAllListeners, ConsoleVoid, 2, 2, ())
+{
+   // Start Listening
+   object->removeAllListeners();
+}
+
+/*! Raises an event on all listening objects.
+    @param eventName The name of the event to raise. The actual function called on listeners will begin with "on" followed by the event name.
+    @param data Any data that should be passed on to the listeners.
+@return No return value.
+*/
+ConsoleMethodWithDocs(SimObject, postEvent, ConsoleVoid, 3, 4, (String eventName, String data))
+{
+   if (argc < 3)
+   {
+      Con::warnf("SimObject::postEvent() - Invalid number of parameters. You must include an Event Name.");
+      return;
+   }
+
+   // Start Listening
+   object->postEvent(argv[2], argc > 3 ? argv[3] : "");
+}
+
+/*! @} */ // member group Object to Object Events
+
 ConsoleMethodRootGroupEndWithDocs(SimObject)