Prechádzať zdrojové kódy

Find navigation mesh from the scene in a delayed manner. Plus other codepath consistency fixes for CrowdManager. Closes #1565.

Lasse Öörni 9 rokov pred
rodič
commit
3dfb4a4c0b

+ 41 - 12
Source/Urho3D/Navigation/CrowdManager.cpp

@@ -97,10 +97,10 @@ void CrowdManager::ApplyAttributes()
     if (scene && navigationMeshId_)
     {
         NavigationMesh* navMesh = dynamic_cast<NavigationMesh*>(scene->GetComponent(navigationMeshId_));
-        if (navMesh)
+        if (navMesh && navMesh != navigationMesh_)
         {
-            navMeshChange = navMesh != navigationMesh_;
-            navigationMesh_ = navMesh;
+            SetNavigationMesh(navMesh); // This will also CreateCrowd(), so the rest of the function is unnecessary
+            return;
         }
     }
     // In case of receiving an invalid component id, revert it back to the existing navmesh component id (if any)
@@ -235,10 +235,23 @@ void CrowdManager::SetMaxAgentRadius(float maxAgentRadius)
 
 void CrowdManager::SetNavigationMesh(NavigationMesh* navMesh)
 {
+    UnsubscribeFromEvent(E_COMPONENTADDED);
+    UnsubscribeFromEvent(E_NAVIGATION_MESH_REBUILT);
+    UnsubscribeFromEvent(E_COMPONENTREMOVED);
+
     if (navMesh != navigationMesh_)     // It is possible to reset navmesh pointer back to 0
     {
+        Scene* scene = GetScene();
+
         navigationMesh_ = navMesh;
         navigationMeshId_ = navMesh ? navMesh->GetID() : 0;
+
+        if (navMesh)
+        {
+            SubscribeToEvent(navMesh, E_NAVIGATION_MESH_REBUILT, URHO3D_HANDLER(CrowdManager, HandleNavMeshChanged));
+            SubscribeToEvent(scene, E_COMPONENTREMOVED, URHO3D_HANDLER(CrowdManager, HandleNavMeshChanged));
+        }
+
         CreateCrowd();
         MarkNetworkUpdate();
     }
@@ -619,21 +632,23 @@ void CrowdManager::OnSceneSet(Scene* scene)
         SubscribeToEvent(scene, E_SCENESUBSYSTEMUPDATE, URHO3D_HANDLER(CrowdManager, HandleSceneSubsystemUpdate));
 
         // Attempt to auto discover a NavigationMesh component (or its derivative) under the scene node
-        NavigationMesh* navMesh = scene->GetDerivedComponent<NavigationMesh>(true);
-        if (navMesh)
+        if (navigationMeshId_ == 0)
         {
-            navigationMesh_ = navMesh;
-            navigationMeshId_ = navMesh->GetID();
-            CreateCrowd();
-
-            SubscribeToEvent(navMesh->GetNode(), E_NAVIGATION_MESH_REBUILT, URHO3D_HANDLER(CrowdManager, HandleNavMeshChanged));
-            SubscribeToEvent(navMesh->GetNode(), E_COMPONENTREMOVED, URHO3D_HANDLER(CrowdManager, HandleNavMeshChanged));
+            NavigationMesh* navMesh = scene->GetDerivedComponent<NavigationMesh>(true);
+            if (navMesh)
+                SetNavigationMesh(navMesh);
+            else
+            {
+                // If not found, attempt to find in a delayed manner
+                SubscribeToEvent(scene, E_COMPONENTADDED, URHO3D_HANDLER(CrowdManager, HandleComponentAdded));
+            }
         }
     }
     else
     {
         UnsubscribeFromEvent(E_SCENESUBSYSTEMUPDATE);
         UnsubscribeFromEvent(E_NAVIGATION_MESH_REBUILT);
+        UnsubscribeFromEvent(E_COMPONENTADDED);
         UnsubscribeFromEvent(E_COMPONENTREMOVED);
 
         navigationMesh_ = 0;
@@ -674,8 +689,10 @@ void CrowdManager::HandleNavMeshChanged(StringHash eventType, VariantMap& eventD
     NavigationMesh* navMesh;
     if (eventType == E_NAVIGATION_MESH_REBUILT)
     {
-        // The mesh being rebuilt may not have existed before
         navMesh = static_cast<NavigationMesh*>(eventData[NavigationMeshRebuilt::P_MESH].GetPtr());
+        // Reset internal pointer so that the same navmesh can be reassigned and the crowd creation be reattempted
+        if (navMesh == navigationMesh_)
+            navigationMesh_.Reset();
     }
     else
     {
@@ -687,7 +704,19 @@ void CrowdManager::HandleNavMeshChanged(StringHash eventType, VariantMap& eventD
         // Since this is a component removed event, reset our own navmesh pointer
         navMesh = 0;
     }
+
     SetNavigationMesh(navMesh);
 }
 
+void CrowdManager::HandleComponentAdded(StringHash eventType, VariantMap& eventData)
+{
+    Scene* scene = GetScene();
+    if (scene)
+    {
+        NavigationMesh* navMesh = scene->GetDerivedComponent<NavigationMesh>(true);
+        if (navMesh)
+            SetNavigationMesh(navMesh);
+    }
+}
+
 }

+ 3 - 1
Source/Urho3D/Navigation/CrowdManager.h

@@ -176,11 +176,13 @@ private:
     void HandleSceneSubsystemUpdate(StringHash eventType, VariantMap& eventData);
     /// Handle navigation mesh changed event. It can be navmesh being rebuilt or being removed from its node.
     void HandleNavMeshChanged(StringHash eventType, VariantMap& eventData);
+    /// Handle component added in the scene to check for late addition of the navmesh.
+    void HandleComponentAdded(StringHash eventType, VariantMap& eventData);
 
     /// Internal Detour crowd object.
     dtCrowd* crowd_;
     /// NavigationMesh for which the crowd was created.
-    NavigationMesh* navigationMesh_;
+    WeakPtr<NavigationMesh> navigationMesh_;
     /// The NavigationMesh component Id for pending crowd creation.
     unsigned navigationMeshId_;
     /// The maximum number of agents the crowd can manage.