From b3197fc12e41bc60e3510d840c67ef98816c3ae8 Mon Sep 17 00:00:00 2001
From: Todd Stinson <stinson@lindenlab.com>
Date: Mon, 12 Mar 2012 18:48:40 -0700
Subject: [PATCH] PATH-304: Making the navmesh version information work for
 both Premium Wilderness regions (old pathfinding simulator build with missing
 capabilities) as well as the new pathfinding simulator builds with the
 version services.

---
 indra/newview/CMakeLists.txt                 |   2 +
 indra/newview/llpathfindingmanager.cpp       | 170 +++++++++++++++----
 indra/newview/llpathfindingmanager.h         |  11 +-
 indra/newview/llpathfindingnavmesh.cpp       |  18 +-
 indra/newview/llpathfindingnavmesh.h         |   8 +
 indra/newview/llpathfindingnavmeshstatus.cpp | 134 +++++++++++++++
 indra/newview/llpathfindingnavmeshstatus.h   |  77 +++++++++
 indra/newview/llpathfindingnavmeshzone.cpp   |  11 +-
 indra/newview/llviewerregion.cpp             |   1 +
 9 files changed, 391 insertions(+), 41 deletions(-)
 create mode 100644 indra/newview/llpathfindingnavmeshstatus.cpp
 create mode 100644 indra/newview/llpathfindingnavmeshstatus.h

diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 44cb23b648c..36b7e136d01 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -421,6 +421,7 @@ set(viewer_SOURCE_FILES
     llpathfindinglinksetlist.cpp
     llpathfindingmanager.cpp
     llpathfindingnavmesh.cpp
+    llpathfindingnavmeshstatus.cpp
     llpathfindingnavmeshzone.cpp
     llphysicsmotion.cpp
     llphysicsshapebuilderutil.cpp
@@ -976,6 +977,7 @@ set(viewer_HEADER_FILES
     llpathfindinglinksetlist.h
     llpathfindingmanager.h
     llpathfindingnavmesh.h
+    llpathfindingnavmeshstatus.h
     llpathfindingnavmeshzone.h
     llphysicsmotion.h
     llphysicsshapebuilderutil.h
diff --git a/indra/newview/llpathfindingmanager.cpp b/indra/newview/llpathfindingmanager.cpp
index ebefebbb645..9cd3d5625c7 100644
--- a/indra/newview/llpathfindingmanager.cpp
+++ b/indra/newview/llpathfindingmanager.cpp
@@ -30,12 +30,14 @@
 
 #include "llviewerprecompiledheaders.h"
 #include "llsd.h"
+#include "lluuid.h"
 #include "llpathfindingmanager.h"
 #include "llsingleton.h"
 #include "llhttpclient.h"
 #include "llagent.h"
 #include "llviewerregion.h"
 #include "llpathfindingnavmesh.h"
+#include "llpathfindingnavmeshstatus.h"
 #include "llpathfindinglinkset.h"
 #include "llpathfindinglinksetlist.h"
 #include "llhttpnode.h"
@@ -45,14 +47,16 @@
 
 #define CAP_SERVICE_RETRIEVE_NAVMESH  "RetrieveNavMeshSrc"
 
-#define CAP_SERVICE_AGENT_STATE       "AgentPreferences"
+#define CAP_SERVICE_NAVMESH_STATUS "NavMeshGenerationStatus"
+
+#define CAP_SERVICE_AGENT_STATE     "AgentPreferences"
 #define ALTER_NAVMESH_OBJECTS_FIELD "alter_navmesh_objects"
 #define DEPRECATED_ALTER_NAVMESH_OBJECTS_FIELD "alter_permanent_objects"
 
-#define CAP_SERVICE_OBJECT_LINKSETS   "ObjectNavMeshProperties"
-#define CAP_SERVICE_TERRAIN_LINKSETS  "TerrainNavMeshProperties"
+#define CAP_SERVICE_OBJECT_LINKSETS  "ObjectNavMeshProperties"
+#define CAP_SERVICE_TERRAIN_LINKSETS "TerrainNavMeshProperties"
 
-#define SIM_MESSAGE_NAVMESH_STATUS_UPDATE "/message/NavmeshStatusUpdate"
+#define SIM_MESSAGE_NAVMESH_STATUS_UPDATE "/message/NavMeshStatusUpdate"
 
 //---------------------------------------------------------------------------
 // LLNavMeshSimStateChangeNode
@@ -66,6 +70,27 @@ class LLNavMeshSimStateChangeNode : public LLHTTPNode
 
 LLHTTPRegistration<LLNavMeshSimStateChangeNode> gHTTPRegistrationNavMeshSimStateChangeNode(SIM_MESSAGE_NAVMESH_STATUS_UPDATE);
 
+//---------------------------------------------------------------------------
+// NavMeshStatusResponder
+//---------------------------------------------------------------------------
+
+class NavMeshStatusResponder : public LLHTTPClient::Responder
+{
+public:
+	NavMeshStatusResponder(const std::string &pCapabilityURL, LLViewerRegion *pRegion);
+	virtual ~NavMeshStatusResponder();
+
+	virtual void result(const LLSD &pContent);
+	virtual void error(U32 pStatus, const std::string& pReason);
+
+protected:
+
+private:
+	std::string    mCapabilityURL;
+	LLViewerRegion *mRegion;
+	LLUUID         mRegionUUID;
+};
+
 //---------------------------------------------------------------------------
 // NavMeshResponder
 //---------------------------------------------------------------------------
@@ -193,7 +218,6 @@ class TerrainLinksetsResponder : public LLHTTPClient::Responder
 LLPathfindingManager::LLPathfindingManager()
 	: LLSingleton<LLPathfindingManager>(),
 	mNavMeshMap(),
-	mNavMeshVersionXXX(0),
 	mAgentStateSignal(),
 	mAgentState(kAgentStateUnknown),
 	mLastKnownNonErrorAgentState(kAgentStateUnknown)
@@ -206,7 +230,12 @@ LLPathfindingManager::~LLPathfindingManager()
 
 bool LLPathfindingManager::isPathfindingEnabledForCurrentRegion() const
 {
-	std::string retrieveNavMeshURL = getRetrieveNavMeshURLForCurrentRegion();
+	return isPathfindingEnabledForRegion(getCurrentRegion());
+}
+
+bool LLPathfindingManager::isPathfindingEnabledForRegion(LLViewerRegion *pRegion) const
+{
+	std::string retrieveNavMeshURL = getRetrieveNavMeshURLForRegion(pRegion);
 	return !retrieveNavMeshURL.empty();
 }
 
@@ -231,39 +260,64 @@ void LLPathfindingManager::requestGetNavMeshForRegion(LLViewerRegion *pRegion)
 {
 	LLPathfindingNavMeshPtr navMeshPtr = getNavMeshForRegion(pRegion);
 
-	if (navMeshPtr->hasNavMeshVersion(mNavMeshVersionXXX))
+	if ((pRegion == NULL) || !isPathfindingEnabledForRegion(pRegion))
 	{
-		navMeshPtr->handleRefresh();
+		navMeshPtr->handleNavMeshNotEnabled();
 	}
 	else
 	{
-		if (pRegion == NULL)
+		std::string navMeshStatusURL = getNavMeshStatusURLForRegion(pRegion);
+#ifdef DEPRECATED_UNVERSIONED_NAVMESH
+		if (navMeshStatusURL.empty())
 		{
-			navMeshPtr->handleNavMeshNotEnabled();
+			sendRequestGetNavMeshForRegion(navMeshPtr, pRegion, navMeshPtr->getNavMeshVersion() + 1U);
 		}
 		else
 		{
-			std::string navMeshURL = getRetrieveNavMeshURLForRegion(pRegion);
-			if (navMeshURL.empty())
-			{
-				navMeshPtr->handleNavMeshNotEnabled();
-			}
-			else
-			{
-				navMeshPtr->handleNavMeshStart(mNavMeshVersionXXX);
-				LLHTTPClient::ResponderPtr responder = new NavMeshResponder(navMeshURL, mNavMeshVersionXXX, navMeshPtr);
+			LLHTTPClient::ResponderPtr navMeshStatusResponder = new NavMeshStatusResponder(navMeshStatusURL, pRegion);
+			LLHTTPClient::get(navMeshStatusURL, navMeshStatusResponder);
+		}
+#else // DEPRECATED_UNVERSIONED_NAVMESH
+		llassert(!navMeshStatusURL.empty());
+		LLHTTPClient::ResponderPtr navMeshStatusResponder = new NavMeshStatusResponder(navMeshStatusURL, pRegion);
+		LLHTTPClient::get(navMeshStatusURL, navMeshStatusResponder);
+#endif // DEPRECATED_UNVERSIONED_NAVMESH
+	}
+}
 
-				LLSD postData;
-				LLHTTPClient::post(navMeshURL, postData, responder);
-			}
+void LLPathfindingManager::handleNavMeshStatusRequest(const LLPathfindingNavMeshStatus &pNavMeshStatus, LLViewerRegion *pRegion)
+{
+	LLPathfindingNavMeshPtr navMeshPtr = getNavMeshForRegion(pNavMeshStatus.getRegionUUID());
+
+	if (!pNavMeshStatus.isValid())
+	{
+		navMeshPtr->handleNavMeshError();
+	}
+	else
+	{
+		if (navMeshPtr->hasNavMeshVersion(pNavMeshStatus.getVersion()))
+		{
+			navMeshPtr->handleRefresh();
+		}
+		else
+		{
+			sendRequestGetNavMeshForRegion(navMeshPtr, pRegion, pNavMeshStatus.getVersion());
 		}
 	}
 }
 
-void LLPathfindingManager::handleNavMeshUpdate(const LLUUID &pRegionUUID, U32 pNavMeshVersion)
+void LLPathfindingManager::handleNavMeshStatusUpdate(const LLPathfindingNavMeshStatus &pNavMeshStatus)
 {
-	LLPathfindingNavMeshPtr navMeshPtr = getNavMeshForRegion(pRegionUUID);
-	navMeshPtr->handleNavMeshNewVersion(++mNavMeshVersionXXX);
+	LLPathfindingNavMeshPtr navMeshPtr = getNavMeshForRegion(pNavMeshStatus.getRegionUUID());
+
+	if (!pNavMeshStatus.isValid())
+	{
+		navMeshPtr->handleNavMeshError();
+	}
+	else
+	{
+		navMeshPtr->handleNavMeshNewVersion(pNavMeshStatus.getVersion());
+	}
 }
 
 LLPathfindingManager::agent_state_slot_t LLPathfindingManager::registerAgentStateListener(agent_state_callback_t pAgentStateCallback)
@@ -391,6 +445,31 @@ LLPathfindingManager::ELinksetsRequestStatus LLPathfindingManager::requestSetLin
 	return status;
 }
 
+void LLPathfindingManager::sendRequestGetNavMeshForRegion(LLPathfindingNavMeshPtr navMeshPtr, LLViewerRegion *pRegion, U32 pNavMeshVersion)
+{
+	if ((pRegion == NULL) || !pRegion->isAlive())
+	{
+		navMeshPtr->handleNavMeshNotEnabled();
+	}
+	else
+	{
+		std::string navMeshURL = getRetrieveNavMeshURLForRegion(pRegion);
+
+		if (navMeshURL.empty())
+		{
+			navMeshPtr->handleNavMeshNotEnabled();
+		}
+		else
+		{
+			navMeshPtr->handleNavMeshStart(pNavMeshVersion);
+			LLHTTPClient::ResponderPtr responder = new NavMeshResponder(navMeshURL, pNavMeshVersion, navMeshPtr);
+
+			LLSD postData;
+			LLHTTPClient::post(navMeshURL, postData, responder);
+		}
+	}
+}
+
 LLPathfindingNavMeshPtr LLPathfindingManager::getNavMeshForRegion(const LLUUID &pRegionUUID)
 {
 	LLPathfindingNavMeshPtr navMeshPtr;
@@ -487,9 +566,9 @@ void LLPathfindingManager::handleAgentStateError(U32 pStatus, const std::string
 	setAgentState(kAgentStateError);
 }
 
-std::string LLPathfindingManager::getRetrieveNavMeshURLForCurrentRegion() const
+std::string LLPathfindingManager::getNavMeshStatusURLForRegion(LLViewerRegion *pRegion) const
 {
-	return getCapabilityURLForCurrentRegion(CAP_SERVICE_RETRIEVE_NAVMESH);
+	return getCapabilityURLForRegion(pRegion, CAP_SERVICE_NAVMESH_STATUS);
 }
 
 std::string LLPathfindingManager::getRetrieveNavMeshURLForRegion(LLViewerRegion *pRegion) const
@@ -546,9 +625,40 @@ LLViewerRegion *LLPathfindingManager::getCurrentRegion() const
 
 void LLNavMeshSimStateChangeNode::post(ResponsePtr pResponse, const LLSD &pContext, const LLSD &pInput) const
 {
-	LLViewerRegion *region = gAgent.getRegion();
-	U32 navMeshVersion = 0U;
-	LLPathfindingManager::getInstance()->handleNavMeshUpdate(region->getRegionID(), navMeshVersion);
+	LLPathfindingNavMeshStatus navMeshStatus(pContext);
+	LLPathfindingManager::getInstance()->handleNavMeshStatusUpdate(pContext);
+}
+
+//---------------------------------------------------------------------------
+// NavMeshStatusResponder
+//---------------------------------------------------------------------------
+
+NavMeshStatusResponder::NavMeshStatusResponder(const std::string &pCapabilityURL, LLViewerRegion *pRegion)
+	: mCapabilityURL(pCapabilityURL),
+	mRegion(pRegion),
+	mRegionUUID()
+{
+	if (mRegion != NULL)
+	{
+		mRegionUUID = mRegion->getRegionID();
+	}
+}
+
+NavMeshStatusResponder::~NavMeshStatusResponder()
+{
+}
+
+void NavMeshStatusResponder::result(const LLSD &pContent)
+{
+	LLPathfindingNavMeshStatus navMeshStatus(mRegionUUID, pContent);
+	LLPathfindingManager::getInstance()->handleNavMeshStatusRequest(navMeshStatus, mRegion);
+}
+
+void NavMeshStatusResponder::error(U32 pStatus, const std::string& pReason)
+{
+	llwarns << "error with request to URL '" << mCapabilityURL << "' because " << pReason << " (statusCode:" << pStatus << ")" << llendl;
+	LLPathfindingNavMeshStatus navMeshStatus(mRegionUUID);
+	LLPathfindingManager::getInstance()->handleNavMeshStatusRequest(navMeshStatus, mRegion);
 }
 
 //---------------------------------------------------------------------------
diff --git a/indra/newview/llpathfindingmanager.h b/indra/newview/llpathfindingmanager.h
index 3e85cb1291d..3a849d02909 100644
--- a/indra/newview/llpathfindingmanager.h
+++ b/indra/newview/llpathfindingmanager.h
@@ -42,6 +42,7 @@
 
 class LLFloater;
 class LLViewerRegion;
+class LLPathfindingNavMeshStatus;
 
 class LLPathfindingManager : public LLSingleton<LLPathfindingManager>
 {
@@ -74,13 +75,16 @@ class LLPathfindingManager : public LLSingleton<LLPathfindingManager>
 	virtual ~LLPathfindingManager();
 
 	bool isPathfindingEnabledForCurrentRegion() const;
+	bool isPathfindingEnabledForRegion(LLViewerRegion *pRegion) const;
 
 	bool isAllowAlterPermanent();
 	bool isAllowViewTerrainProperties() const;
 
 	LLPathfindingNavMesh::navmesh_slot_t registerNavMeshListenerForRegion(LLViewerRegion *pRegion, LLPathfindingNavMesh::navmesh_callback_t pNavMeshCallback);
 	void requestGetNavMeshForRegion(LLViewerRegion *pRegion);
-	void handleNavMeshUpdate(const LLUUID &pRegionUUID, U32 pNavMeshVersion);
+
+	void handleNavMeshStatusRequest(const LLPathfindingNavMeshStatus &pNavMeshStatus, LLViewerRegion *pRegion);
+	void handleNavMeshStatusUpdate(const LLPathfindingNavMeshStatus &pNavMeshStatus);
 
 	agent_state_slot_t registerAgentStateListener(agent_state_callback_t pAgentStateCallback);
 	EAgentState        getAgentState();
@@ -93,6 +97,8 @@ class LLPathfindingManager : public LLSingleton<LLPathfindingManager>
 protected:
 
 private:
+	void sendRequestGetNavMeshForRegion(LLPathfindingNavMeshPtr navMeshPtr, LLViewerRegion *pRegion, U32 pNavMeshVersion);
+
 	LLPathfindingNavMeshPtr getNavMeshForRegion(const LLUUID &pRegionUUID);
 	LLPathfindingNavMeshPtr getNavMeshForRegion(LLViewerRegion *pRegion);
 
@@ -103,7 +109,7 @@ class LLPathfindingManager : public LLSingleton<LLPathfindingManager>
 	void handleAgentStateResult(const LLSD &pContent, EAgentState pRequestedAgentState);
 	void handleAgentStateError(U32 pStatus, const std::string &pReason, const std::string &pURL);
 
-	std::string getRetrieveNavMeshURLForCurrentRegion() const;
+	std::string getNavMeshStatusURLForRegion(LLViewerRegion *pRegion) const;
 	std::string getRetrieveNavMeshURLForRegion(LLViewerRegion *pRegion) const;
 	std::string getAgentStateURLForCurrentRegion() const;
 	std::string getObjectLinksetsURLForCurrentRegion() const;
@@ -114,7 +120,6 @@ class LLPathfindingManager : public LLSingleton<LLPathfindingManager>
 	LLViewerRegion *getCurrentRegion() const;
 
 	NavMeshMap           mNavMeshMap;
-	U32                  mNavMeshVersionXXX; // XXX stinson 03/02/2012 : a hacky way of doing versions for now
 
 	agent_state_signal_t mAgentStateSignal;
 	EAgentState          mAgentState;
diff --git a/indra/newview/llpathfindingnavmesh.cpp b/indra/newview/llpathfindingnavmesh.cpp
index 84343cf31ee..81fa7b24db1 100644
--- a/indra/newview/llpathfindingnavmesh.cpp
+++ b/indra/newview/llpathfindingnavmesh.cpp
@@ -66,9 +66,12 @@ void LLPathfindingNavMesh::handleRefresh()
 
 void LLPathfindingNavMesh::handleNavMeshNewVersion(U32 pNavMeshVersion)
 {
-	mNavMeshData.clear();
-	mNavMeshVersion = pNavMeshVersion;
-	setRequestStatus(kNavMeshRequestNeedsUpdate);
+	if (mNavMeshVersion != pNavMeshVersion)
+	{
+		mNavMeshData.clear();
+		mNavMeshVersion = pNavMeshVersion;
+		setRequestStatus(kNavMeshRequestNeedsUpdate);
+	}
 }
 
 void LLPathfindingNavMesh::handleNavMeshStart(U32 pNavMeshVersion)
@@ -121,13 +124,18 @@ void LLPathfindingNavMesh::handleNavMeshNotEnabled()
 	setRequestStatus(kNavMeshRequestNotEnabled);
 }
 
+void LLPathfindingNavMesh::handleNavMeshError()
+{
+	mNavMeshData.clear();
+	setRequestStatus(kNavMeshRequestError);
+}
+
 void LLPathfindingNavMesh::handleNavMeshError(U32 pStatus, const std::string &pReason, const std::string &pURL, U32 pNavMeshVersion)
 {
 	llwarns << "error with request to URL '" << pURL << "' because " << pReason << " (statusCode:" << pStatus << ")" << llendl;
 	if (mNavMeshVersion == pNavMeshVersion)
 	{
-		mNavMeshData.clear();
-		setRequestStatus(kNavMeshRequestError);
+		handleNavMeshError();
 	}
 }
 
diff --git a/indra/newview/llpathfindingnavmesh.h b/indra/newview/llpathfindingnavmesh.h
index eb9ef9683da..3bdb485d37a 100644
--- a/indra/newview/llpathfindingnavmesh.h
+++ b/indra/newview/llpathfindingnavmesh.h
@@ -42,6 +42,9 @@ class LLPathfindingNavMesh;
 
 typedef boost::shared_ptr<LLPathfindingNavMesh> LLPathfindingNavMeshPtr;
 
+// XXX stinson 03/12/2012 : This definition is in place to support an older version of the pathfinding simulator that does not have versioned information
+#define DEPRECATED_UNVERSIONED_NAVMESH
+
 class LLPathfindingNavMesh
 {
 public:
@@ -63,6 +66,10 @@ class LLPathfindingNavMesh
 
 	navmesh_slot_t registerNavMeshListener(navmesh_callback_t pNavMeshCallback);
 
+#ifdef DEPRECATED_UNVERSIONED_NAVMESH
+	U32  getNavMeshVersion() const {return mNavMeshVersion;};
+#endif // DEPRECATED_UNVERSIONED_NAVMESH
+
 	bool hasNavMeshVersion(U32 pNavMeshVersion) const;
 
 	void handleRefresh();
@@ -70,6 +77,7 @@ class LLPathfindingNavMesh
 	void handleNavMeshStart(U32 pNavMeshVersion);
 	void handleNavMeshResult(const LLSD &pContent, U32 pNavMeshVersion);
 	void handleNavMeshNotEnabled();
+	void handleNavMeshError();
 	void handleNavMeshError(U32 pStatus, const std::string &pReason, const std::string &pURL, U32 pNavMeshVersion);
 
 protected:
diff --git a/indra/newview/llpathfindingnavmeshstatus.cpp b/indra/newview/llpathfindingnavmeshstatus.cpp
new file mode 100644
index 00000000000..67be0459a55
--- /dev/null
+++ b/indra/newview/llpathfindingnavmeshstatus.cpp
@@ -0,0 +1,134 @@
+/** 
+ * @file llpathfindingnavmeshstatus.cpp
+ * @author William Todd Stinson
+ * @brief A class for representing the navmesh status of a pathfinding region.
+ *
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+#include "llsd.h"
+#include "lluuid.h"
+#include "llstring.h"
+#include "llpathfindingnavmeshstatus.h"
+
+#include <string>
+
+#define REGION_FIELD  "region"
+#define STATE_FIELD   "state"
+#define VERSION_FIELD "version"
+
+const std::string LLPathfindingNavMeshStatus::sStatusPending("pending");
+const std::string LLPathfindingNavMeshStatus::sStatusBuilding("building");
+const std::string LLPathfindingNavMeshStatus::sStatusComplete("complete");
+const std::string LLPathfindingNavMeshStatus::sStatusRepending("repending");
+
+
+//---------------------------------------------------------------------------
+// LLPathfindingNavMeshStatus
+//---------------------------------------------------------------------------
+
+LLPathfindingNavMeshStatus::LLPathfindingNavMeshStatus(const LLUUID &pRegionUUID)
+	: mIsValid(false),
+	mRegionUUID(pRegionUUID),
+	mVersion(0U),
+	mStatus(kComplete)
+{
+}
+
+LLPathfindingNavMeshStatus::LLPathfindingNavMeshStatus(const LLUUID &pRegionUUID, const LLSD &pContent)
+	: mIsValid(true),
+	mRegionUUID(pRegionUUID),
+	mVersion(0U),
+	mStatus(kComplete)
+{
+	parseStatus(pContent);
+}
+
+LLPathfindingNavMeshStatus::LLPathfindingNavMeshStatus(const LLSD &pContent)
+	: mIsValid(true),
+	mRegionUUID(),
+	mVersion(0U),
+	mStatus(kComplete)
+{
+	llassert(pContent.has(REGION_FIELD));
+	llassert(pContent.get(REGION_FIELD).isUUID());
+	mRegionUUID = pContent.get(REGION_FIELD).asUUID();
+
+	parseStatus(pContent);
+}
+
+LLPathfindingNavMeshStatus::LLPathfindingNavMeshStatus(const LLPathfindingNavMeshStatus &pOther)
+	: mIsValid(pOther.mIsValid),
+	mRegionUUID(pOther.mRegionUUID),
+	mVersion(pOther.mVersion),
+	mStatus(pOther.mStatus)
+{
+}
+
+LLPathfindingNavMeshStatus::~LLPathfindingNavMeshStatus()
+{
+}
+
+LLPathfindingNavMeshStatus &LLPathfindingNavMeshStatus::operator =(const LLPathfindingNavMeshStatus &pOther)
+{
+	mIsValid = pOther.mIsValid;
+	mRegionUUID = pOther.mRegionUUID;
+	mVersion = pOther.mVersion;
+	mStatus = pOther.mStatus;
+
+	return *this;
+}
+
+void LLPathfindingNavMeshStatus::parseStatus(const LLSD &pContent)
+{
+	llassert(pContent.has(VERSION_FIELD));
+	llassert(pContent.get(VERSION_FIELD).isInteger());
+	llassert(pContent.get(VERSION_FIELD).asInteger() >= 0);
+	mVersion = static_cast<U32>(pContent.get(VERSION_FIELD).asInteger());
+
+	llassert(pContent.has(STATE_FIELD));
+	llassert(pContent.get(STATE_FIELD).isString());
+	std::string status = pContent.get(STATE_FIELD).asString();
+
+	if (LLStringUtil::compareStrings(status, sStatusPending))
+	{
+		mStatus = kPending;
+	}
+	else if (LLStringUtil::compareStrings(status, sStatusBuilding))
+	{
+		mStatus = kBuilding;
+	}
+	else if (LLStringUtil::compareStrings(status, sStatusComplete))
+	{
+		mStatus = kComplete;
+	}
+	else if (LLStringUtil::compareStrings(status, sStatusRepending))
+	{
+		mStatus = kRepending;
+	}
+	else
+	{
+		mStatus = kComplete;
+		llassert(0);
+	}
+}
diff --git a/indra/newview/llpathfindingnavmeshstatus.h b/indra/newview/llpathfindingnavmeshstatus.h
new file mode 100644
index 00000000000..fcc876059d2
--- /dev/null
+++ b/indra/newview/llpathfindingnavmeshstatus.h
@@ -0,0 +1,77 @@
+/** 
+ * @file llpathfindingnavmeshstatus.h
+ * @author William Todd Stinson
+ * @brief A class for representing the navmesh status of a pathfinding region.
+ *
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc. 
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLPATHFINDINGNAVMESHSTATUS_H
+#define LL_LLPATHFINDINGNAVMESHSTATUS_H
+
+#include "lluuid.h"
+
+#include <string>
+
+class LLSD;
+
+class LLPathfindingNavMeshStatus
+{
+public:
+	typedef enum
+	{
+		kPending,
+		kBuilding,
+		kComplete,
+		kRepending
+	} ENavMeshStatus;
+
+	LLPathfindingNavMeshStatus(const LLUUID &pRegionUUID);
+	LLPathfindingNavMeshStatus(const LLUUID &pRegionUUID, const LLSD &pContent);
+	LLPathfindingNavMeshStatus(const LLSD &pContent);
+	LLPathfindingNavMeshStatus(const LLPathfindingNavMeshStatus &pOther);
+	virtual ~LLPathfindingNavMeshStatus();
+
+	LLPathfindingNavMeshStatus &operator =(const LLPathfindingNavMeshStatus &pOther);
+
+	bool           isValid() const        {return mIsValid;};
+	const LLUUID   &getRegionUUID() const {return mRegionUUID;};
+	U32            getVersion() const     {return mVersion;};
+	ENavMeshStatus getStatus() const      {return mStatus;};
+
+protected:
+
+private:
+	void           parseStatus(const LLSD &pContent);
+
+	bool           mIsValid;
+	LLUUID         mRegionUUID;
+	U32            mVersion;
+	ENavMeshStatus mStatus;
+
+	static const std::string sStatusPending;
+	static const std::string sStatusBuilding;
+	static const std::string sStatusComplete;
+	static const std::string sStatusRepending;
+};
+
+#endif // LL_LLPATHFINDINGNAVMESHSTATUS_H
diff --git a/indra/newview/llpathfindingnavmeshzone.cpp b/indra/newview/llpathfindingnavmeshzone.cpp
index 3767834655c..83238ec8690 100644
--- a/indra/newview/llpathfindingnavmeshzone.cpp
+++ b/indra/newview/llpathfindingnavmeshzone.cpp
@@ -311,10 +311,15 @@ LLPathfindingNavMesh::ENavMeshRequestStatus LLPathfindingNavMeshZone::NavMeshLoc
 void LLPathfindingNavMeshZone::NavMeshLocation::handleNavMesh(LLPathfindingNavMesh::ENavMeshRequestStatus pNavMeshRequestStatus, const LLUUID &pRegionUUID, U32 pNavMeshVersion, const LLSD::Binary &pNavMeshData)
 {
 	llassert(mRegionUUID == pRegionUUID);
-	mRequestStatus = pNavMeshRequestStatus;
-	if ((pNavMeshRequestStatus == LLPathfindingNavMesh::kNavMeshRequestCompleted) && (!mHasNavMesh || (mNavMeshVersion != pNavMeshVersion)))
+	if (pNavMeshRequestStatus != LLPathfindingNavMesh::kNavMeshRequestCompleted)
+	{
+		mRequestStatus = pNavMeshRequestStatus;
+		mLocationCallback();
+	}
+	else if (!mHasNavMesh || (mNavMeshVersion != pNavMeshVersion))
 	{
 		llassert(!pNavMeshData.empty());
+		mRequestStatus = pNavMeshRequestStatus;
 		mHasNavMesh = true;
 		mNavMeshVersion = pNavMeshVersion;
 		llassert(LLPathingLib::getInstance() != NULL);
@@ -322,8 +327,8 @@ void LLPathfindingNavMeshZone::NavMeshLocation::handleNavMesh(LLPathfindingNavMe
 		{
 			LLPathingLib::getInstance()->extractNavMeshSrcFromLLSD(pNavMeshData, mDirection);
 		}
+		mLocationCallback();
 	}
-	mLocationCallback();
 }
 
 void LLPathfindingNavMeshZone::NavMeshLocation::clear()
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index 6e422a58214..fc04546bb82 100644
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -1522,6 +1522,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
 	capabilityNames.append("MapLayer");
 	capabilityNames.append("MapLayerGod");
 	capabilityNames.append("MeshUploadFlag");	
+	capabilityNames.append("NavMeshGenerationStatus");
 	capabilityNames.append("NavMeshUpload");
 	capabilityNames.append("NewFileAgentInventory");
 	capabilityNames.append("ObjectNavMeshProperties");
-- 
GitLab