phoenix-firestorm/indra/newview/llpathfindingnavmeshzone.cpp

477 lines
15 KiB
C++

/**
* @file llpathfindingnavmeshzone.cpp
* @author William Todd Stinson
* @brief A class for representing the zone of navmeshes containing and possible surrounding the current 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 "llagent.h"
#include "llviewerregion.h"
#include "llpathfindingnavmesh.h"
#include "llpathfindingnavmeshzone.h"
#include "llpathfindingmanager.h"
#include "llviewercontrol.h"
#include "llpathinglib.h"
#include <string>
#include <vector>
#include <boost/bind.hpp>
#define CENTER_REGION 99
//---------------------------------------------------------------------------
// LLPathfindingNavMeshZone
//---------------------------------------------------------------------------
LLPathfindingNavMeshZone::LLPathfindingNavMeshZone()
: mNavMeshLocationPtrs(),
mNavMeshZoneRequestStatus(kNavMeshZoneRequestUnknown),
mNavMeshZoneSignal()
{
}
LLPathfindingNavMeshZone::~LLPathfindingNavMeshZone()
{
}
LLPathfindingNavMeshZone::navmesh_zone_slot_t LLPathfindingNavMeshZone::registerNavMeshZoneListener(navmesh_zone_callback_t pNavMeshZoneCallback)
{
return mNavMeshZoneSignal.connect(pNavMeshZoneCallback);
}
void LLPathfindingNavMeshZone::initialize()
{
mNavMeshLocationPtrs.clear();
#ifdef XXX_STINSON_DEBUG_NAVMESH_ZONE
LLViewerRegion *currentRegion = gAgent.getRegion();
if (currentRegion != NULL)
{
llinfos << "STINSON DEBUG: currentRegion: '" << currentRegion->getName() << "' (" << currentRegion->getRegionID().asString() << ")" << llendl;
std::vector<S32> availableRegions;
currentRegion->getNeighboringRegionsStatus( availableRegions );
std::vector<LLViewerRegion*> neighborRegionsPtrs;
currentRegion->getNeighboringRegions( neighborRegionsPtrs );
for (std::vector<S32>::const_iterator statusIter = availableRegions.begin();
statusIter != availableRegions.end(); ++statusIter)
{
LLViewerRegion *region = neighborRegionsPtrs[statusIter - availableRegions.begin()];
llinfos << "STINSON DEBUG: region #" << *statusIter << ": '" << region->getName() << "' (" << region->getRegionID().asString() << ")" << llendl;
}
}
#endif // XXX_STINSON_DEBUG_NAVMESH_ZONE
NavMeshLocationPtr centerNavMeshPtr(new NavMeshLocation(CENTER_REGION, boost::bind(&LLPathfindingNavMeshZone::handleNavMeshLocation, this)));
mNavMeshLocationPtrs.push_back(centerNavMeshPtr);
U32 neighborRegionDir = gSavedSettings.getU32("RetrieveNeighboringRegion");
if (neighborRegionDir != CENTER_REGION)
{
NavMeshLocationPtr neighborNavMeshPtr(new NavMeshLocation(neighborRegionDir, boost::bind(&LLPathfindingNavMeshZone::handleNavMeshLocation, this)));
mNavMeshLocationPtrs.push_back(neighborNavMeshPtr);
}
}
void LLPathfindingNavMeshZone::enable()
{
for (NavMeshLocationPtrs::iterator navMeshLocationPtrIter = mNavMeshLocationPtrs.begin();
navMeshLocationPtrIter != mNavMeshLocationPtrs.end(); ++navMeshLocationPtrIter)
{
NavMeshLocationPtr navMeshLocationPtr = *navMeshLocationPtrIter;
navMeshLocationPtr->enable();
}
}
void LLPathfindingNavMeshZone::disable()
{
for (NavMeshLocationPtrs::iterator navMeshLocationPtrIter = mNavMeshLocationPtrs.begin();
navMeshLocationPtrIter != mNavMeshLocationPtrs.end(); ++navMeshLocationPtrIter)
{
NavMeshLocationPtr navMeshLocationPtr = *navMeshLocationPtrIter;
navMeshLocationPtr->disable();
}
}
void LLPathfindingNavMeshZone::refresh()
{
llassert(LLPathingLib::getInstance() != NULL);
if (LLPathingLib::getInstance() != NULL)
{
LLPathingLib::getInstance()->cleanupResidual();
}
for (NavMeshLocationPtrs::iterator navMeshLocationPtrIter = mNavMeshLocationPtrs.begin();
navMeshLocationPtrIter != mNavMeshLocationPtrs.end(); ++navMeshLocationPtrIter)
{
NavMeshLocationPtr navMeshLocationPtr = *navMeshLocationPtrIter;
navMeshLocationPtr->refresh();
}
}
LLPathfindingNavMeshZone::ENavMeshZoneStatus LLPathfindingNavMeshZone::getNavMeshZoneStatus() const
{
bool hasPending = false;
bool hasBuilding = false;
bool hasComplete = false;
bool hasRepending = false;
for (NavMeshLocationPtrs::const_iterator navMeshLocationPtrIter = mNavMeshLocationPtrs.begin();
navMeshLocationPtrIter != mNavMeshLocationPtrs.end(); ++navMeshLocationPtrIter)
{
const NavMeshLocationPtr navMeshLocationPtr = *navMeshLocationPtrIter;
switch (navMeshLocationPtr->getNavMeshStatus())
{
case LLPathfindingNavMeshStatus::kPending :
hasPending = true;
break;
case LLPathfindingNavMeshStatus::kBuilding :
hasBuilding = true;
break;
case LLPathfindingNavMeshStatus::kComplete :
hasComplete = true;
break;
case LLPathfindingNavMeshStatus::kRepending :
hasRepending = true;
break;
default :
hasPending = true;
llassert(0);
break;
}
}
ENavMeshZoneStatus zoneStatus = kNavMeshZoneComplete;
if (hasRepending || (hasPending && hasBuilding))
{
zoneStatus = kNavMeshZonePendingAndBuilding;
}
else if (hasComplete)
{
if (hasPending)
{
zoneStatus = kNavMeshZoneSomePending;
}
else if (hasBuilding)
{
zoneStatus = kNavMeshZoneSomeBuilding;
}
else
{
zoneStatus = kNavMeshZoneComplete;
}
}
else if (hasPending)
{
zoneStatus = kNavMeshZonePending;
}
else if (hasBuilding)
{
zoneStatus = kNavMeshZoneBuilding;
}
return zoneStatus;
}
void LLPathfindingNavMeshZone::handleNavMeshLocation()
{
updateStatus();
}
void LLPathfindingNavMeshZone::updateStatus()
{
bool hasRequestUnknown = false;
bool hasRequestWaiting = false;
bool hasRequestChecking = false;
bool hasRequestNeedsUpdate = false;
bool hasRequestStarted = false;
bool hasRequestCompleted = false;
bool hasRequestNotEnabled = false;
bool hasRequestError = false;
#ifdef XXX_STINSON_DEBUG_NAVMESH_ZONE
llinfos << "STINSON DEBUG: Navmesh zone update BEGIN" << llendl;
#endif // XXX_STINSON_DEBUG_NAVMESH_ZONE
for (NavMeshLocationPtrs::const_iterator navMeshLocationPtrIter = mNavMeshLocationPtrs.begin();
navMeshLocationPtrIter != mNavMeshLocationPtrs.end(); ++navMeshLocationPtrIter)
{
const NavMeshLocationPtr navMeshLocationPtr = *navMeshLocationPtrIter;
#ifdef XXX_STINSON_DEBUG_NAVMESH_ZONE
llinfos << "STINSON DEBUG: region #" << navMeshLocationPtr->getDirection() << ": region(" << navMeshLocationPtr->getRegionUUID().asString() << ") status:" << navMeshLocationPtr->getRequestStatus() << llendl;
#endif // XXX_STINSON_DEBUG_NAVMESH_ZONE
switch (navMeshLocationPtr->getRequestStatus())
{
case LLPathfindingNavMesh::kNavMeshRequestUnknown :
hasRequestUnknown = true;
break;
case LLPathfindingNavMesh::kNavMeshRequestWaiting :
hasRequestWaiting = true;
break;
case LLPathfindingNavMesh::kNavMeshRequestChecking :
hasRequestChecking = true;
break;
case LLPathfindingNavMesh::kNavMeshRequestNeedsUpdate :
hasRequestNeedsUpdate = true;
break;
case LLPathfindingNavMesh::kNavMeshRequestStarted :
hasRequestStarted = true;
break;
case LLPathfindingNavMesh::kNavMeshRequestCompleted :
hasRequestCompleted = true;
break;
case LLPathfindingNavMesh::kNavMeshRequestNotEnabled :
hasRequestNotEnabled = true;
break;
case LLPathfindingNavMesh::kNavMeshRequestError :
hasRequestError = true;
break;
default :
hasRequestError = true;
llassert(0);
break;
}
}
ENavMeshZoneRequestStatus zoneRequestStatus = kNavMeshZoneRequestUnknown;
if (hasRequestWaiting)
{
zoneRequestStatus = kNavMeshZoneRequestWaiting;
#ifdef XXX_STINSON_DEBUG_NAVMESH_ZONE
llinfos << "STINSON DEBUG: Navmesh zone update is WAITING" << llendl;
#endif // XXX_STINSON_DEBUG_NAVMESH_ZONE
}
else if (hasRequestNeedsUpdate)
{
zoneRequestStatus = kNavMeshZoneRequestNeedsUpdate;
#ifdef XXX_STINSON_DEBUG_NAVMESH_ZONE
llinfos << "STINSON DEBUG: Navmesh zone update is NEEDS UPDATE" << llendl;
#endif // XXX_STINSON_DEBUG_NAVMESH_ZONE
}
else if (hasRequestChecking)
{
zoneRequestStatus = kNavMeshZoneRequestChecking;
#ifdef XXX_STINSON_DEBUG_NAVMESH_ZONE
llinfos << "STINSON DEBUG: Navmesh zone update is CHECKING" << llendl;
#endif // XXX_STINSON_DEBUG_NAVMESH_ZONE
}
else if (hasRequestStarted)
{
zoneRequestStatus = kNavMeshZoneRequestStarted;
#ifdef XXX_STINSON_DEBUG_NAVMESH_ZONE
llinfos << "STINSON DEBUG: Navmesh zone update is STARTED" << llendl;
#endif // XXX_STINSON_DEBUG_NAVMESH_ZONE
}
else if (hasRequestError)
{
zoneRequestStatus = kNavMeshZoneRequestError;
#ifdef XXX_STINSON_DEBUG_NAVMESH_ZONE
llinfos << "STINSON DEBUG: Navmesh zone update is ERROR" << llendl;
#endif // XXX_STINSON_DEBUG_NAVMESH_ZONE
}
else if (hasRequestUnknown)
{
zoneRequestStatus = kNavMeshZoneRequestUnknown;
#ifdef XXX_STINSON_DEBUG_NAVMESH_ZONE
llinfos << "STINSON DEBUG: Navmesh zone update is UNKNOWN" << llendl;
#endif // XXX_STINSON_DEBUG_NAVMESH_ZONE
}
else if (hasRequestCompleted)
{
zoneRequestStatus = kNavMeshZoneRequestCompleted;
#ifdef XXX_STINSON_DEBUG_NAVMESH_ZONE
llinfos << "STINSON DEBUG: Navmesh zone update is COMPLETED" << llendl;
#endif // XXX_STINSON_DEBUG_NAVMESH_ZONE
}
else if (hasRequestNotEnabled)
{
zoneRequestStatus = kNavMeshZoneRequestNotEnabled;
#ifdef XXX_STINSON_DEBUG_NAVMESH_ZONE
llinfos << "STINSON DEBUG: Navmesh zone update is NOT ENABLED" << llendl;
#endif // XXX_STINSON_DEBUG_NAVMESH_ZONE
}
else
{
zoneRequestStatus = kNavMeshZoneRequestError;
#ifdef XXX_STINSON_DEBUG_NAVMESH_ZONE
llinfos << "STINSON DEBUG: Navmesh zone update is BAD ERROR" << llendl;
#endif // XXX_STINSON_DEBUG_NAVMESH_ZONE
llassert(0);
}
if ((mNavMeshZoneRequestStatus != kNavMeshZoneRequestCompleted) &&
(zoneRequestStatus == kNavMeshZoneRequestCompleted))
{
#ifdef XXX_STINSON_DEBUG_NAVMESH_ZONE
llinfos << "STINSON DEBUG: Navmesh zone update is stitching" << llendl;
#endif // XXX_STINSON_DEBUG_NAVMESH_ZONE
llassert(LLPathingLib::getInstance() != NULL);
if (LLPathingLib::getInstance() != NULL)
{
LLPathingLib::getInstance()->processNavMeshData();
}
#ifdef XXX_STINSON_DEBUG_NAVMESH_ZONE
llinfos << "STINSON DEBUG: Navmesh zone update stitching is done" << llendl;
#endif // XXX_STINSON_DEBUG_NAVMESH_ZONE
}
mNavMeshZoneRequestStatus = zoneRequestStatus;
mNavMeshZoneSignal(mNavMeshZoneRequestStatus);
}
//---------------------------------------------------------------------------
// LLPathfindingNavMeshZone::NavMeshLocation
//---------------------------------------------------------------------------
LLPathfindingNavMeshZone::NavMeshLocation::NavMeshLocation(S32 pDirection, navmesh_location_callback_t pLocationCallback)
: mDirection(pDirection),
mRegionUUID(),
mHasNavMesh(false),
mNavMeshVersion(0U),
mNavMeshStatus(LLPathfindingNavMeshStatus::kComplete),
mLocationCallback(pLocationCallback),
mRequestStatus(LLPathfindingNavMesh::kNavMeshRequestUnknown),
mNavMeshSlot()
{
}
LLPathfindingNavMeshZone::NavMeshLocation::~NavMeshLocation()
{
}
void LLPathfindingNavMeshZone::NavMeshLocation::enable()
{
clear();
LLViewerRegion *region = getRegion();
if (region == NULL)
{
mRegionUUID.setNull();
}
else
{
mRegionUUID = region->getRegionID();
mNavMeshSlot = LLPathfindingManager::getInstance()->registerNavMeshListenerForRegion(region, boost::bind(&LLPathfindingNavMeshZone::NavMeshLocation::handleNavMesh, this, _1, _2, _3));
}
}
void LLPathfindingNavMeshZone::NavMeshLocation::refresh()
{
LLViewerRegion *region = getRegion();
if (region == NULL)
{
llassert(mRegionUUID.isNull());
LLPathfindingNavMeshStatus newNavMeshStatus(mRegionUUID);
LLSD::Binary nullData;
handleNavMesh(LLPathfindingNavMesh::kNavMeshRequestNotEnabled, newNavMeshStatus, nullData);
}
else
{
llassert(mRegionUUID == region->getRegionID());
LLPathfindingManager::getInstance()->requestGetNavMeshForRegion(region);
}
}
void LLPathfindingNavMeshZone::NavMeshLocation::disable()
{
clear();
}
LLPathfindingNavMesh::ENavMeshRequestStatus LLPathfindingNavMeshZone::NavMeshLocation::getRequestStatus() const
{
return mRequestStatus;
}
LLPathfindingNavMeshStatus::ENavMeshStatus LLPathfindingNavMeshZone::NavMeshLocation::getNavMeshStatus() const
{
return mNavMeshStatus;
}
void LLPathfindingNavMeshZone::NavMeshLocation::handleNavMesh(LLPathfindingNavMesh::ENavMeshRequestStatus pNavMeshRequestStatus, const LLPathfindingNavMeshStatus &pNavMeshStatus, const LLSD::Binary &pNavMeshData)
{
llassert(mRegionUUID == pNavMeshStatus.getRegionUUID());
if ((pNavMeshRequestStatus == LLPathfindingNavMesh::kNavMeshRequestCompleted) &&
(!mHasNavMesh || (mNavMeshVersion != pNavMeshStatus.getVersion())))
{
llassert(!pNavMeshData.empty());
mHasNavMesh = true;
mNavMeshVersion = pNavMeshStatus.getVersion();
llassert(LLPathingLib::getInstance() != NULL);
if (LLPathingLib::getInstance() != NULL)
{
LLPathingLib::getInstance()->extractNavMeshSrcFromLLSD(pNavMeshData, mDirection);
}
}
mRequestStatus = pNavMeshRequestStatus;
mNavMeshStatus = pNavMeshStatus.getStatus();
mLocationCallback();
}
void LLPathfindingNavMeshZone::NavMeshLocation::clear()
{
mHasNavMesh = false;
mRequestStatus = LLPathfindingNavMesh::kNavMeshRequestUnknown;
mNavMeshStatus = LLPathfindingNavMeshStatus::kComplete;
if (mNavMeshSlot.connected())
{
mNavMeshSlot.disconnect();
}
}
LLViewerRegion *LLPathfindingNavMeshZone::NavMeshLocation::getRegion() const
{
LLViewerRegion *region = NULL;
LLViewerRegion *currentRegion = gAgent.getRegion();
if (currentRegion != NULL)
{
if (mDirection == CENTER_REGION)
{
region = currentRegion;
}
else
{
//User wants to pull in a neighboring region
std::vector<S32> availableRegions;
currentRegion->getNeighboringRegionsStatus( availableRegions );
//Is the desired region in the available list
std::vector<S32>::iterator foundElem = std::find(availableRegions.begin(),availableRegions.end(),mDirection);
if ( foundElem != availableRegions.end() )
{
std::vector<LLViewerRegion*> neighborRegionsPtrs;
currentRegion->getNeighboringRegions( neighborRegionsPtrs );
region = neighborRegionsPtrs[foundElem - availableRegions.begin()];
}
}
}
return region;
}