/** * @file llmenuoptionpathfindingrebakenavmesh.cpp * @brief Implementation of llmenuoptionpathfindingrebakenavmesh * @author Prep@lindenlab.com * * $LicenseInfo:firstyear=2012&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2012, 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 "llmenuoptionpathfindingrebakenavmesh.h" #include <boost/bind.hpp> #include <boost/signals2.hpp> #include "llagent.h" #include "llenvmanager.h" #include "llnotificationsutil.h" #include "llpathfindingmanager.h" #include "llpathfindingnavmesh.h" #include "llpathfindingnavmeshstatus.h" #include "llviewerregion.h" LLMenuOptionPathfindingRebakeNavmesh::LLMenuOptionPathfindingRebakeNavmesh() : LLSingleton<LLMenuOptionPathfindingRebakeNavmesh>(), mIsInitialized(false), mCanRebakeRegion(false), mRebakeNavMeshMode(kRebakeNavMesh_Default), mNavMeshSlot(), mRegionCrossingSlot(), mAgentStateSlot() { } LLMenuOptionPathfindingRebakeNavmesh::~LLMenuOptionPathfindingRebakeNavmesh() { if (mIsInitialized) { if (mRebakeNavMeshMode == kRebakeNavMesh_RequestSent) { LL_WARNS("navmeshRebaking") << "During destruction of the LLMenuOptionPathfindingRebakeNavmesh " << "singleton, the mode indicates that a request has been sent for which a response has yet " << "to be received. This could contribute to a crash on exit." << LL_ENDL; } quit(); } } void LLMenuOptionPathfindingRebakeNavmesh::initialize() { if (!mIsInitialized) { mIsInitialized = true; setMode(kRebakeNavMesh_Default); createNavMeshStatusListenerForCurrentRegion(); if ( !mRegionCrossingSlot.connected() ) { mRegionCrossingSlot = LLEnvManagerNew::getInstance()->setRegionChangeCallback(boost::bind(&LLMenuOptionPathfindingRebakeNavmesh::handleRegionBoundaryCrossed, this)); } if (!mAgentStateSlot.connected()) { mAgentStateSlot = LLPathfindingManager::getInstance()->registerAgentStateListener(boost::bind(&LLMenuOptionPathfindingRebakeNavmesh::handleAgentState, this, _1)); } LLPathfindingManager::getInstance()->requestGetAgentState(); } } void LLMenuOptionPathfindingRebakeNavmesh::quit() { if (mIsInitialized) // Quitting from the login screen leaves this uninitialized { if (mNavMeshSlot.connected()) { mNavMeshSlot.disconnect(); } if (mRegionCrossingSlot.connected()) { mRegionCrossingSlot.disconnect(); } if (mAgentStateSlot.connected()) { mAgentStateSlot.disconnect(); } mIsInitialized = false; } } bool LLMenuOptionPathfindingRebakeNavmesh::canRebakeRegion() const { if (!mIsInitialized) { LL_ERRS("navmeshRebaking") << "LLMenuOptionPathfindingRebakeNavmesh class has not been initialized " << "when the ability to rebake navmesh is being requested." << LL_ENDL; } return mCanRebakeRegion; } LLMenuOptionPathfindingRebakeNavmesh::ERebakeNavMeshMode LLMenuOptionPathfindingRebakeNavmesh::getMode() const { if (!mIsInitialized) { LL_ERRS("navmeshRebaking") << "LLMenuOptionPathfindingRebakeNavmesh class has not been initialized " << "when the mode is being requested." << LL_ENDL; } return mRebakeNavMeshMode; } void LLMenuOptionPathfindingRebakeNavmesh::sendRequestRebakeNavmesh() { if (!mIsInitialized) { LL_ERRS("navmeshRebaking") << "LLMenuOptionPathfindingRebakeNavmesh class has not been initialized " << "when the request is being made to rebake the navmesh." << LL_ENDL; } else { if (!canRebakeRegion()) { LL_WARNS("navmeshRebaking") << "attempting to rebake navmesh when user does not have permissions " << "on this region" << LL_ENDL; } if (getMode() != kRebakeNavMesh_Available) { LL_WARNS("navmeshRebaking") << "attempting to rebake navmesh when mode is not available" << LL_ENDL; } setMode(kRebakeNavMesh_RequestSent); LLPathfindingManager::getInstance()->requestRebakeNavMesh(boost::bind(&LLMenuOptionPathfindingRebakeNavmesh::handleRebakeNavMeshResponse, this, _1)); } } void LLMenuOptionPathfindingRebakeNavmesh::setMode(ERebakeNavMeshMode pRebakeNavMeshMode) { mRebakeNavMeshMode = pRebakeNavMeshMode; } void LLMenuOptionPathfindingRebakeNavmesh::handleAgentState(BOOL pCanRebakeRegion) { llassert(mIsInitialized); mCanRebakeRegion = pCanRebakeRegion; } void LLMenuOptionPathfindingRebakeNavmesh::handleRebakeNavMeshResponse(bool pResponseStatus) { llassert(mIsInitialized); if (mIsInitialized) { if (getMode() == kRebakeNavMesh_RequestSent) { setMode(pResponseStatus ? kRebakeNavMesh_InProgress : kRebakeNavMesh_Default); } if (!pResponseStatus) { LLNotificationsUtil::add("PathfindingCannotRebakeNavmesh"); } } } void LLMenuOptionPathfindingRebakeNavmesh::handleNavMeshStatus(const LLPathfindingNavMeshStatus &pNavMeshStatus) { llassert(mIsInitialized); if (mIsInitialized) { ERebakeNavMeshMode rebakeNavMeshMode = kRebakeNavMesh_Default; if (pNavMeshStatus.isValid()) { switch (pNavMeshStatus.getStatus()) { case LLPathfindingNavMeshStatus::kPending : case LLPathfindingNavMeshStatus::kRepending : rebakeNavMeshMode = kRebakeNavMesh_Available; break; case LLPathfindingNavMeshStatus::kBuilding : rebakeNavMeshMode = kRebakeNavMesh_InProgress; break; case LLPathfindingNavMeshStatus::kComplete : rebakeNavMeshMode = kRebakeNavMesh_NotAvailable; break; default : rebakeNavMeshMode = kRebakeNavMesh_Default; llassert(0); break; } } setMode(rebakeNavMeshMode); } } void LLMenuOptionPathfindingRebakeNavmesh::handleRegionBoundaryCrossed() { llassert(mIsInitialized); if (mIsInitialized) { createNavMeshStatusListenerForCurrentRegion(); mCanRebakeRegion = FALSE; LLPathfindingManager::getInstance()->requestGetAgentState(); } } void LLMenuOptionPathfindingRebakeNavmesh::createNavMeshStatusListenerForCurrentRegion() { if (mNavMeshSlot.connected()) { mNavMeshSlot.disconnect(); } LLViewerRegion *currentRegion = gAgent.getRegion(); if (currentRegion != NULL) { mNavMeshSlot = LLPathfindingManager::getInstance()->registerNavMeshListenerForRegion(currentRegion, boost::bind(&LLMenuOptionPathfindingRebakeNavmesh::handleNavMeshStatus, this, _2)); LLPathfindingManager::getInstance()->requestGetNavMeshForRegion(currentRegion, true); } }