Bläddra i källkod

Events now trigger their subscribers in the order they subscribed

BearishSun 9 år sedan
förälder
incheckning
9ceee03530
1 ändrade filer med 71 tillägg och 7 borttagningar
  1. 71 7
      Source/BansheeUtility/Include/BsEvent.h

+ 71 - 7
Source/BansheeUtility/Include/BsEvent.h

@@ -45,7 +45,8 @@ namespace BansheeEngine
 	struct EventInternalData
 	{
 		EventInternalData()
-			:mConnections(nullptr), mFreeConnections(nullptr)
+			:mConnections(nullptr), mLastConnection(nullptr), mFreeConnections(nullptr), mNewConnections(nullptr), 
+			mIsCurrentlyTriggering(false)
 		{ }
 
 		~EventInternalData()
@@ -67,6 +68,30 @@ namespace BansheeEngine
 
 				conn = next;
 			}
+
+			conn = mNewConnections;
+			while (conn != nullptr)
+			{
+				BaseConnectionData* next = conn->next;
+				bs_free(conn);
+
+				conn = next;
+			}
+		}
+
+		/** Appends a new connection to the active connection array. */
+		void connect(BaseConnectionData* conn)
+		{
+			conn->prev = mLastConnection;
+
+			if (mLastConnection != nullptr)
+				mLastConnection->next = conn;
+
+			mLastConnection = conn;
+
+			// First connection
+			if (mConnections == nullptr)
+				mConnections = conn;
 		}
 
 		/**
@@ -101,6 +126,9 @@ namespace BansheeEngine
 
 				conn = next;
 			}
+
+			mConnections = nullptr;
+			mLastConnection = nullptr;
 		}
 
 		/**
@@ -127,6 +155,8 @@ namespace BansheeEngine
 
 			if (conn->next != nullptr)
 				conn->next->prev = conn->prev;
+			else
+				mLastConnection = conn->prev;
 
 			conn->prev = nullptr;
 			conn->next = nullptr;
@@ -142,9 +172,12 @@ namespace BansheeEngine
 		}
 
 		BaseConnectionData* mConnections;
+		BaseConnectionData* mLastConnection;
 		BaseConnectionData* mFreeConnections;
+		BaseConnectionData* mNewConnections;
 
 		RecursiveMutex mMutex;
+		bool mIsCurrentlyTriggering;
 	};
 
 	/** @} */
@@ -286,12 +319,21 @@ namespace BansheeEngine
 			if (connData == nullptr)
 				connData = bs_new<ConnectionData>();
 
-			connData->next = mInternalData->mConnections;
+			// If currently iterating over the connection list, delay modifying it until done
+			if(mInternalData->mIsCurrentlyTriggering)
+			{
+				connData->prev = mInternalData->mNewConnections;
 
-			if (mInternalData->mConnections != nullptr)
-				mInternalData->mConnections->prev = connData;
+				if (mInternalData->mNewConnections != nullptr)
+					mInternalData->mNewConnections->next = connData;
+
+				mInternalData->mNewConnections = connData;
+			}
+			else
+			{
+				mInternalData->connect(connData);
+			}
 
-			mInternalData->mConnections = connData;
 			connData->func = func;
 
 			return HEvent(mInternalData, connData);
@@ -305,9 +347,8 @@ namespace BansheeEngine
 			SPtr<EventInternalData> internalData = mInternalData;
 
 			RecursiveLock lock(internalData->mMutex);
+			internalData->mIsCurrentlyTriggering = true;
 
-			// Hidden dependency: If any new connections are made during these callbacks they must be
-			// inserted at the start of the linked list so that we don't trigger them here.
 			ConnectionData* conn = static_cast<ConnectionData*>(internalData->mConnections);
 			while (conn != nullptr)
 			{
@@ -319,6 +360,29 @@ namespace BansheeEngine
 
 				conn = next;
 			}
+
+			internalData->mIsCurrentlyTriggering = false;
+
+			// If any new connections were added during the above calls, add them to the connection list
+			if(internalData->mNewConnections != nullptr)
+			{
+				BaseConnectionData* lastNewConnection = internalData->mNewConnections;
+				while (lastNewConnection != nullptr)
+					lastNewConnection = lastNewConnection->next;
+
+				BaseConnectionData* currentConnection = lastNewConnection;
+				while(currentConnection != nullptr)
+				{
+					BaseConnectionData* prevConnection = currentConnection->prev;
+					currentConnection->next = nullptr;
+					currentConnection->prev = nullptr;
+
+					mInternalData->connect(currentConnection);
+					currentConnection = prevConnection;
+				}
+
+				internalData->mNewConnections = nullptr;
+			}
 		}
 
 		/** Clear all callbacks from the event. */