diff options
author | Ansariel <ansariel.hiller@phoenixviewer.com> | 2024-05-22 21:25:21 +0200 |
---|---|---|
committer | Andrey Lihatskiy <alihatskiy@productengine.com> | 2024-05-22 22:40:26 +0300 |
commit | e2e37cced861b98de8c1a7c9c0d3a50d2d90e433 (patch) | |
tree | 1bb897489ce524986f6196201c10ac0d8861aa5f /indra/newview/llviewerregion.cpp | |
parent | 069ea06848f766466f1a281144c82a0f2bd79f3a (diff) |
Fix line endlings
Diffstat (limited to 'indra/newview/llviewerregion.cpp')
-rwxr-xr-x | indra/newview/llviewerregion.cpp | 7352 |
1 files changed, 3676 insertions, 3676 deletions
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index 7633ec62df..41af61ec97 100755 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -1,3676 +1,3676 @@ -/**
- * @file llviewerregion.cpp
- * @brief Implementation of the LLViewerRegion class.
- *
- * $LicenseInfo:firstyear=2000&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010-2013, 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 "llviewerregion.h"
-
-// linden libraries
-#include "indra_constants.h"
-#include "llaisapi.h"
-#include "llavatarnamecache.h" // name lookup cap url
-#include "llfloaterreg.h"
-#include "llmath.h"
-#include "llregionflags.h"
-#include "llregionhandle.h"
-#include "llsurface.h"
-#include "message.h"
-//#include "vmath.h"
-#include "v3math.h"
-#include "v4math.h"
-
-#include "llagent.h"
-#include "llagentcamera.h"
-#include "llappviewer.h"
-#include "llavatarrenderinfoaccountant.h"
-#include "llcallingcard.h"
-#include "llcommandhandler.h"
-#include "lldir.h"
-#include "lleventpoll.h"
-#include "llfloatergodtools.h"
-#include "llfloaterreporter.h"
-#include "llfloaterregioninfo.h"
-#include "llgltfmateriallist.h"
-#include "llhttpnode.h"
-#include "llregioninfomodel.h"
-#include "llsdutil.h"
-#include "llstartup.h"
-#include "lltrans.h"
-#include "llurldispatcher.h"
-#include "llviewerobjectlist.h"
-#include "llviewerparceloverlay.h"
-#include "llviewerstatsrecorder.h"
-#include "llvlmanager.h"
-#include "llvlcomposition.h"
-#include "llvoavatarself.h"
-#include "llvocache.h"
-#include "llworld.h"
-#include "llspatialpartition.h"
-#include "stringize.h"
-#include "llviewercontrol.h"
-#include "llsdserialize.h"
-#include "llfloaterperms.h"
-#include "llvieweroctree.h"
-#include "llviewerdisplay.h"
-#include "llviewerwindow.h"
-#include "llprogressview.h"
-#include "llcoros.h"
-#include "lleventcoro.h"
-#include "llcorehttputil.h"
-#include "llcallstack.h"
-#include "llsettingsdaycycle.h"
-
-#include <boost/regex.hpp>
-
-#ifdef LL_WINDOWS
- #pragma warning(disable:4355)
-#endif
-
-// When we receive a base grant of capabilities that has a different number of
-// capabilities than the original base grant received for the region, print
-// out the two lists of capabilities for analysis.
-//#define DEBUG_CAPS_GRANTS
-
-// The server only keeps our pending agent info for 60 seconds.
-// We want to allow for seed cap retry, but its not useful after that 60 seconds.
-// Even though we gave up on login, keep trying for caps after we are logged in:
-const S32 MAX_CAP_REQUEST_ATTEMPTS = 30;
-const U32 DEFAULT_MAX_REGION_WIDE_PRIM_COUNT = 15000;
-
-bool LLViewerRegion::sVOCacheCullingEnabled = false;
-S32 LLViewerRegion::sLastCameraUpdated = 0;
-S32 LLViewerRegion::sNewObjectCreationThrottle = -1;
-LLViewerRegion::vocache_entry_map_t LLViewerRegion::sRegionCacheCleanup;
-
-typedef std::map<std::string, std::string> CapabilityMap;
-
-static void log_capabilities(const CapabilityMap &capmap);
-
-namespace
-{
-
-void newRegionEntry(LLViewerRegion& region)
-{
- LL_INFOS("LLViewerRegion") << "Entering region [" << region.getName() << "]" << LL_ENDL;
- gDebugInfo["CurrentRegion"] = region.getName();
- LLAppViewer::instance()->writeDebugInfo();
-}
-
-} // anonymous namespace
-
-// support for secondlife:///app/region/{REGION} SLapps
-// N.B. this is defined to work exactly like the classic secondlife://{REGION}
-// However, the later syntax cannot support spaces in the region name because
-// spaces (and %20 chars) are illegal in the hostname of an http URL. Some
-// browsers let you get away with this, but some do not (such as Qt's Webkit).
-// Hence we introduced the newer secondlife:///app/region alternative.
-class LLRegionHandler : public LLCommandHandler
-{
-public:
- // requests will be throttled from a non-trusted browser
- LLRegionHandler() : LLCommandHandler("region", UNTRUSTED_THROTTLE) {}
-
- bool handle(const LLSD& params, const LLSD& query_map, const std::string& grid, LLMediaCtrl* web)
- {
- // make sure that we at least have a region name
- int num_params = params.size();
- if (num_params < 1)
- {
- return false;
- }
-
- // build a secondlife://{PLACE} SLurl from this SLapp
- std::string url = "secondlife://";
- if (!grid.empty())
- {
- url += grid + "/secondlife/";
- }
- boost::regex name_rx("[A-Za-z0-9()_%]+");
- boost::regex coord_rx("[0-9]+");
- for (int i = 0; i < num_params; i++)
- {
- if (i > 0)
- {
- url += "/";
- }
- if (!boost::regex_match(params[i].asString(), i > 0 ? coord_rx : name_rx))
- {
- return false;
- }
-
- url += params[i].asString();
- }
-
- // Process the SLapp as if it was a secondlife://{PLACE} SLurl
- LLURLDispatcher::dispatch(url, LLCommandHandler::NAV_TYPE_CLICKED, web, true);
- return true;
- }
-
-};
-LLRegionHandler gRegionHandler;
-
-
-class LLViewerRegionImpl
-{
-public:
- LLViewerRegionImpl(LLViewerRegion * region, LLHost const & host):
- mHost(host),
- mCompositionp(NULL),
- mEventPoll(NULL),
- mSeedCapMaxAttempts(MAX_CAP_REQUEST_ATTEMPTS),
- mSeedCapAttempts(0),
- mHttpResponderID(0),
- mLastCameraUpdate(0),
- mLastCameraOrigin(),
- mVOCachePartition(NULL),
- mLandp(NULL)
- {}
-
- static void buildCapabilityNames(LLSD& capabilityNames);
-
- // The surfaces and other layers
- LLSurface* mLandp;
-
- // Region geometry data
- LLVector3d mOriginGlobal; // Location of southwest corner of region (meters)
- LLVector3d mCenterGlobal; // Location of center in world space (meters)
- LLHost mHost;
-
- // The unique ID for this region.
- LLUUID mRegionID;
-
- // region/estate owner - usually null.
- LLUUID mOwnerID;
-
- // Network statistics for the region's circuit...
- LLTimer mLastNetUpdate;
-
- // Misc
- LLVLComposition *mCompositionp; // Composition layer for the surface
-
- LLVOCacheEntry::vocache_entry_map_t mCacheMap; //all cached entries
- LLVOCacheEntry::vocache_entry_set_t mActiveSet; //all active entries;
- LLVOCacheEntry::vocache_entry_set_t mWaitingSet; //entries waiting for LLDrawable to be generated.
- std::set< LLPointer<LLViewerOctreeGroup> > mVisibleGroups; //visible groupa
- LLVOCachePartition* mVOCachePartition;
- LLVOCacheEntry::vocache_entry_set_t mVisibleEntries; //must-be-created visible entries wait for objects creation.
- LLVOCacheEntry::vocache_entry_priority_list_t mWaitingList; //transient list storing sorted visible entries waiting for object creation.
- std::set<U32> mNonCacheableCreatedList; //list of local ids of all non-cacheable objects
- LLVOCacheEntry::vocache_gltf_overrides_map_t mGLTFOverridesLLSD; // for materials
-
- // time?
- // LRU info?
-
- // Cache ID is unique per-region, across renames, moving locations,
- // etc.
- LLUUID mCacheID;
-
- CapabilityMap mCapabilities;
- CapabilityMap mSecondCapabilitiesTracker;
-
- LLEventPoll* mEventPoll;
-
- S32 mSeedCapMaxAttempts;
- S32 mSeedCapAttempts;
-
- S32 mHttpResponderID;
-
- //spatial partitions for objects in this region
- std::vector<LLViewerOctreePartition*> mObjectPartition;
-
- LLVector3 mLastCameraOrigin;
- U32 mLastCameraUpdate;
-
- static void requestBaseCapabilitiesCoro(U64 regionHandle);
- static void requestBaseCapabilitiesCompleteCoro(U64 regionHandle);
- static void requestSimulatorFeatureCoro(std::string url, U64 regionHandle);
-};
-
-void LLViewerRegionImpl::requestBaseCapabilitiesCoro(U64 regionHandle)
-{
- LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
- LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
- httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("BaseCapabilitiesRequest", httpPolicy));
- LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
-
- LLSD result;
- LLViewerRegion *regionp = NULL;
-
- // This loop is used for retrying a capabilities request.
- do
- {
- if (STATE_WORLD_INIT > LLStartUp::getStartupState())
- {
- LL_INFOS("AppInit", "Capabilities") << "Aborting capabilities request, reason: returned to login screen" << LL_ENDL;
- return;
- }
-
- if (!LLWorld::instanceExists())
- {
- LL_WARNS("AppInit", "Capabilities") << "Attempting to get capabilities, but world no longer exists!" << LL_ENDL;
- return;
- }
-
- regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle);
- if (!regionp) //region was removed
- {
- LL_WARNS("AppInit", "Capabilities") << "Attempting to get capabilities for region that no longer exists!" << LL_ENDL;
- return; // this error condition is not recoverable.
- }
- LLViewerRegionImpl* impl = regionp->getRegionImplNC();
- LL_DEBUGS("AppInit", "Capabilities") << "requesting seed caps for handle " << regionHandle
- << " name " << regionp->getName() << LL_ENDL;
-
- std::string url = regionp->getCapability("Seed");
- if (url.empty())
- {
- LL_WARNS("AppInit", "Capabilities") << "Failed to get seed capabilities, and can not determine url!" << LL_ENDL;
- regionp->setCapabilitiesError();
- return; // this error condition is not recoverable.
- }
-
- // record that we just entered a new region
- newRegionEntry(*regionp);
-
- if (impl->mSeedCapAttempts > impl->mSeedCapMaxAttempts)
- {
- // *TODO: Give a user pop-up about this error?
- LL_WARNS("AppInit", "Capabilities") << "Failed to get seed capabilities from '" << url << "' after " << impl->mSeedCapAttempts << " attempts. Giving up!" << LL_ENDL;
- return; // this error condition is not recoverable.
- }
-
- S32 id = ++(impl->mHttpResponderID);
-
- LLSD capabilityNames = LLSD::emptyArray();
- impl->buildCapabilityNames(capabilityNames);
-
- LL_INFOS("AppInit", "Capabilities") << "Requesting seed from " << url
- << " region name " << regionp->getName()
- << " region id " << regionp->getRegionID()
- << " handle " << regionp->getHandle()
- << " (attempt #" << impl->mSeedCapAttempts + 1 << ")" << LL_ENDL;
- LL_DEBUGS("AppInit", "Capabilities") << "Capabilities requested: " << capabilityNames << LL_ENDL;
-
- regionp = NULL;
- impl = NULL;
- result = httpAdapter->postAndSuspend(httpRequest, url, capabilityNames);
-
- if (STATE_WORLD_INIT > LLStartUp::getStartupState())
- {
- LL_INFOS("AppInit", "Capabilities") << "Aborting capabilities request, reason: returned to login screen" << LL_ENDL;
- return;
- }
-
- if (LLApp::isExiting() || gDisconnected)
- {
- LL_DEBUGS("AppInit", "Capabilities") << "Shutting down" << LL_ENDL;
- return;
- }
-
- if (!LLWorld::instanceExists())
- {
- LL_WARNS("AppInit", "Capabilities") << "Received capabilities, but world no longer exists!" << LL_ENDL;
- return;
- }
-
- regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle);
- if (!regionp) //region was removed
- {
- LL_WARNS("AppInit", "Capabilities") << "Received capabilities for region that no longer exists!" << LL_ENDL;
- return; // this error condition is not recoverable.
- }
-
- impl = regionp->getRegionImplNC();
-
- ++(impl->mSeedCapAttempts);
-
- if (!result.isMap() || result.has("error"))
- {
- LL_WARNS("AppInit", "Capabilities") << "Malformed response" << LL_ENDL;
- // setup for retry.
- continue;
- }
-
- LLSD httpResults = result["http_result"];
- LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
- if (!status)
- {
- LL_WARNS("AppInit", "Capabilities") << "HttpStatus error " << LL_ENDL;
- // setup for retry.
- continue;
- }
-
- // remove the http_result from the llsd
- result.erase("http_result");
-
- if (id != impl->mHttpResponderID) // region is no longer referring to this request
- {
- LL_WARNS("AppInit", "Capabilities") << "Received results for a stale capabilities request!" << LL_ENDL;
- // setup for retry.
- continue;
- }
-
- LLSD::map_const_iterator iter;
- for (iter = result.beginMap(); iter != result.endMap(); ++iter)
- {
- regionp->setCapability(iter->first, iter->second);
-
- LL_DEBUGS("AppInit", "Capabilities")
- << "Capability '" << iter->first << "' is '" << iter->second << "'" << LL_ENDL;
- }
-
-#if 0
- log_capabilities(mCapabilities);
-#endif
-
- LL_DEBUGS("AppInit", "Capabilities", "Teleport") << "received caps for handle " << regionHandle
- << " region name " << regionp->getName() << LL_ENDL;
- regionp->setCapabilitiesReceived(true);
-
- break;
- }
- while (true);
-
- if (regionp && regionp->isCapabilityAvailable("ServerReleaseNotes") &&
- regionp->getReleaseNotesRequested())
- { // *HACK: we're waiting for the ServerReleaseNotes
- regionp->showReleaseNotes();
- }
-}
-
-
-void LLViewerRegionImpl::requestBaseCapabilitiesCompleteCoro(U64 regionHandle)
-{
- LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
- LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
- httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("BaseCapabilitiesRequest", httpPolicy));
- LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
-
- LLSD result;
- LLViewerRegion *regionp = NULL;
-
- // This loop is used for retrying a capabilities request.
- do
- {
- LLWorld *world_inst = LLWorld::getInstance(); // Not a singleton!
- if (!world_inst)
- {
- LL_WARNS("AppInit", "Capabilities") << "Attempting to get capabilities, but world no longer exists!" << LL_ENDL;
- return;
- }
-
- regionp = world_inst->getRegionFromHandle(regionHandle);
- if (!regionp) //region was removed
- {
- LL_WARNS("AppInit", "Capabilities") << "Attempting to get capabilities for region that no longer exists!" << LL_ENDL;
- break; // this error condition is not recoverable.
- }
-
- std::string url = regionp->getCapabilityDebug("Seed");
- if (url.empty())
- {
- LL_WARNS("AppInit", "Capabilities") << "Failed to get seed capabilities, and can not determine url!" << LL_ENDL;
- if (regionp->getCapability("Seed").empty())
- {
- // initial attempt failed to get this cap as well
- regionp->setCapabilitiesError();
- }
- break; // this error condition is not recoverable.
- }
-
- // record that we just entered a new region
- newRegionEntry(*regionp);
-
- LLSD capabilityNames = LLSD::emptyArray();
- buildCapabilityNames(capabilityNames);
-
- LL_INFOS("AppInit", "Capabilities") << "Requesting second Seed from " << url << " for region " << regionp->getRegionID() << LL_ENDL;
-
- regionp = NULL;
- world_inst = NULL;
- result = httpAdapter->postAndSuspend(httpRequest, url, capabilityNames);
-
- LLSD httpResults = result["http_result"];
- LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
- if (!status)
- {
- LL_WARNS("AppInit", "Capabilities") << "HttpStatus error " << LL_ENDL;
- break; // no retry
- }
-
- if (LLApp::isExiting() || gDisconnected)
- {
- break;
- }
-
- world_inst = LLWorld::getInstance();
- if (!world_inst)
- {
- LL_WARNS("AppInit", "Capabilities") << "Received capabilities, but world no longer exists!" << LL_ENDL;
- return;
- }
-
- regionp = world_inst->getRegionFromHandle(regionHandle);
- if (!regionp) //region was removed
- {
- LL_WARNS("AppInit", "Capabilities") << "Received capabilities for region that no longer exists!" << LL_ENDL;
- break; // this error condition is not recoverable.
- }
- LLViewerRegionImpl* impl = regionp->getRegionImplNC();
-
- // remove the http_result from the llsd
- result.erase("http_result");
-
- LLSD::map_const_iterator iter;
- for (iter = result.beginMap(); iter != result.endMap(); ++iter)
- {
- regionp->setCapabilityDebug(iter->first, iter->second);
- //LL_INFOS()<<"BaseCapabilitiesCompleteTracker New Caps "<<iter->first<<" "<< iter->second<<LL_ENDL;
- }
-
-#if 0
- log_capabilities(impl->mCapabilities);
-#endif
-
- if (impl->mCapabilities.size() != impl->mSecondCapabilitiesTracker.size())
- {
- LL_WARNS("AppInit", "Capabilities")
- << "Sim sent duplicate base caps that differ in size from what we initially received - most likely content. "
- << "mCapabilities == " << impl->mCapabilities.size()
- << " mSecondCapabilitiesTracker == " << impl->mSecondCapabilitiesTracker.size()
- << LL_ENDL;
-#ifdef DEBUG_CAPS_GRANTS
- LL_WARNS("AppInit", "Capabilities")
- << "Initial Base capabilities: " << LL_ENDL;
-
- log_capabilities(impl->mCapabilities);
-
- LL_WARNS("AppInit", "Capabilities")
- << "Latest base capabilities: " << LL_ENDL;
-
- log_capabilities(impl->mSecondCapabilitiesTracker);
-
-#endif
-
- if (impl->mSecondCapabilitiesTracker.size() > impl->mCapabilities.size())
- {
- // *HACK Since we were granted more base capabilities in this grant request than the initial, replace
- // the old with the new. This shouldn't happen i.e. we should always get the same capabilities from a
- // sim. The simulator fix from SH-3895 should prevent it from happening, at least in the case of the
- // inventory api capability grants.
-
- // Need to clear a std::map before copying into it because old keys take precedence.
- impl->mCapabilities.clear();
- impl->mCapabilities = impl->mSecondCapabilitiesTracker;
- }
- }
- else
- {
- LL_DEBUGS("CrossingCaps") << "Sim sent multiple base cap grants with matching sizes." << LL_ENDL;
- }
- impl->mSecondCapabilitiesTracker.clear();
- }
- while (false);
-}
-
-void LLViewerRegionImpl::requestSimulatorFeatureCoro(std::string url, U64 regionHandle)
-{
- LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
- LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
- httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("BaseCapabilitiesRequest", httpPolicy));
- LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
-
- LLViewerRegion *regionp = NULL;
- S32 attemptNumber = 0;
- // This loop is used for retrying a capabilities request.
- do
- {
- ++attemptNumber;
-
- if (attemptNumber > MAX_CAP_REQUEST_ATTEMPTS)
- {
- LL_WARNS("AppInit", "SimulatorFeatures") << "Retries count exceeded attempting to get Simulator feature from "
- << url << LL_ENDL;
- break;
- }
-
- LLWorld *world_inst = LLWorld::getInstance(); // Not a singleton!
- if (!world_inst)
- {
- LL_WARNS("AppInit", "Capabilities") << "Attempting to request Sim Feature, but world no longer exists!" << LL_ENDL;
- return;
- }
-
- regionp = world_inst->getRegionFromHandle(regionHandle);
- if (!regionp) //region was removed
- {
- LL_WARNS("AppInit", "SimulatorFeatures") << "Attempting to request Sim Feature for region that no longer exists!" << LL_ENDL;
- break; // this error condition is not recoverable.
- }
-
- regionp = NULL;
- world_inst = NULL;
- LLSD result = httpAdapter->getAndSuspend(httpRequest, url);
-
- LLSD httpResults = result["http_result"];
- LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
- if (!status)
- {
- LL_WARNS("AppInit", "SimulatorFeatures") << "HttpStatus error retrying" << LL_ENDL;
- continue;
- }
-
- if (LLApp::isExiting() || gDisconnected)
- {
- break;
- }
-
- // remove the http_result from the llsd
- result.erase("http_result");
-
- world_inst = LLWorld::getInstance();
- if (!world_inst)
- {
- LL_WARNS("AppInit", "Capabilities") << "Attempting to request Sim Feature, but world no longer exists!" << LL_ENDL;
- return;
- }
-
- regionp = world_inst->getRegionFromHandle(regionHandle);
- if (!regionp) //region was removed
- {
- LL_WARNS("AppInit", "SimulatorFeatures") << "Attempting to set Sim Feature for region that no longer exists!" << LL_ENDL;
- break; // this error condition is not recoverable.
- }
-
- regionp->setSimulatorFeatures(result);
-
- break;
- }
- while (true);
-
-}
-
-LLViewerRegion::LLViewerRegion(const U64 &handle,
- const LLHost &host,
- const U32 grids_per_region_edge,
- const U32 grids_per_patch_edge,
- const F32 region_width_meters)
-: mImpl(new LLViewerRegionImpl(this, host)),
- mHandle(handle),
- mTimeDilation(1.0f),
- mName(""),
- mZoning(""),
- mIsEstateManager(false),
- mRegionFlags( REGION_FLAGS_DEFAULT ),
- mRegionProtocols( 0 ),
- mSimAccess( SIM_ACCESS_MIN ),
- mBillableFactor(1.0),
- mMaxTasks(DEFAULT_MAX_REGION_WIDE_PRIM_COUNT),
- mCentralBakeVersion(1),
- mClassID(0),
- mCPURatio(0),
- mColoName("unknown"),
- mProductSKU("unknown"),
- mProductName("unknown"),
- mViewerAssetUrl(""),
- mCacheLoaded(false),
- mCacheDirty(false),
- mReleaseNotesRequested(false),
- mCapabilitiesState(CAPABILITIES_STATE_INIT),
- mSimulatorFeaturesReceived(false),
- mBitsReceived(0.f),
- mPacketsReceived(0.f),
- mDead(false),
- mLastVisitedEntry(NULL),
- mInvisibilityCheckHistory(-1),
- mPaused(false),
- mRegionCacheHitCount(0),
- mRegionCacheMissCount(0),
- mInterestListMode(IL_MODE_DEFAULT)
-{
- mWidth = region_width_meters;
- mImpl->mOriginGlobal = from_region_handle(handle);
- updateRenderMatrix();
-
- mImpl->mLandp = new LLSurface('l', NULL);
-
- // Create the composition layer for the surface
- mImpl->mCompositionp =
- new LLVLComposition(mImpl->mLandp,
- grids_per_region_edge,
- region_width_meters / grids_per_region_edge);
- mImpl->mCompositionp->setSurface(mImpl->mLandp);
-
- // Create the surfaces
- mImpl->mLandp->setRegion(this);
- mImpl->mLandp->create(grids_per_region_edge,
- grids_per_patch_edge,
- mImpl->mOriginGlobal,
- mWidth);
-
- mParcelOverlay = new LLViewerParcelOverlay(this, region_width_meters);
-
- setOriginGlobal(from_region_handle(handle));
- calculateCenterGlobal();
-
- // Create the object lists
- initStats();
-
- //create object partitions
- //MUST MATCH declaration of eObjectPartitions
- mImpl->mObjectPartition.push_back(new LLHUDPartition(this)); //PARTITION_HUD
- mImpl->mObjectPartition.push_back(new LLTerrainPartition(this)); //PARTITION_TERRAIN
- mImpl->mObjectPartition.push_back(new LLVoidWaterPartition(this)); //PARTITION_VOIDWATER
- mImpl->mObjectPartition.push_back(new LLWaterPartition(this)); //PARTITION_WATER
- mImpl->mObjectPartition.push_back(new LLTreePartition(this)); //PARTITION_TREE
- mImpl->mObjectPartition.push_back(new LLParticlePartition(this)); //PARTITION_PARTICLE
- mImpl->mObjectPartition.push_back(new LLGrassPartition(this)); //PARTITION_GRASS
- mImpl->mObjectPartition.push_back(new LLVolumePartition(this)); //PARTITION_VOLUME
- mImpl->mObjectPartition.push_back(new LLBridgePartition(this)); //PARTITION_BRIDGE
- mImpl->mObjectPartition.push_back(new LLAvatarPartition(this)); //PARTITION_AVATAR
- mImpl->mObjectPartition.push_back(new LLControlAVPartition(this)); //PARTITION_CONTROL_AV
- mImpl->mObjectPartition.push_back(new LLHUDParticlePartition(this));//PARTITION_HUD_PARTICLE
- mImpl->mObjectPartition.push_back(new LLVOCachePartition(this)); //PARTITION_VO_CACHE
- mImpl->mObjectPartition.push_back(NULL); //PARTITION_NONE
- mImpl->mVOCachePartition = getVOCachePartition();
-
- setCapabilitiesReceivedCallback(boost::bind(&LLAvatarRenderInfoAccountant::scanNewRegion, _1));
-}
-
-
-void LLViewerRegion::initStats()
-{
- mImpl->mLastNetUpdate.reset();
- mPacketsIn = 0;
- mBitsIn = (U32Bits)0;
- mLastBitsIn = (U32Bits)0;
- mLastPacketsIn = 0;
- mPacketsOut = 0;
- mLastPacketsOut = 0;
- mPacketsLost = 0;
- mLastPacketsLost = 0;
- mPingDelay = (U32Seconds)0;
- mAlive = false; // can become false if circuit disconnects
-}
-
-static LLTrace::BlockTimerStatHandle FTM_CLEANUP_REGION_OBJECTS("Cleanup Region Objects");
-static LLTrace::BlockTimerStatHandle FTM_SAVE_REGION_CACHE("Save Region Cache");
-
-LLViewerRegion::~LLViewerRegion()
-{
- LL_PROFILE_ZONE_SCOPED;
- mDead = true;
- mImpl->mActiveSet.clear();
- mImpl->mVisibleEntries.clear();
- mImpl->mVisibleGroups.clear();
- mImpl->mWaitingSet.clear();
-
- gVLManager.cleanupData(this);
- // Can't do this on destruction, because the neighbor pointers might be invalid.
- // This should be reference counted...
- disconnectAllNeighbors();
- LLViewerPartSim::getInstance()->cleanupRegion(this);
-
- {
- LL_RECORD_BLOCK_TIME(FTM_CLEANUP_REGION_OBJECTS);
- gObjectList.killObjects(this);
- }
-
- delete mImpl->mCompositionp;
- delete mParcelOverlay;
- delete mImpl->mLandp;
- delete mImpl->mEventPoll;
-#if 0
- LLHTTPSender::clearSender(mImpl->mHost);
-#endif
- std::for_each(mImpl->mObjectPartition.begin(), mImpl->mObjectPartition.end(), DeletePointer());
-
- {
- LL_RECORD_BLOCK_TIME(FTM_SAVE_REGION_CACHE);
- saveObjectCache();
- }
-
- delete mImpl;
- mImpl = NULL;
-}
-
-/*virtual*/
-const LLHost& LLViewerRegion::getHost() const
-{
- return mImpl->mHost;
-}
-
-LLSurface & LLViewerRegion::getLand() const
-{
- return *mImpl->mLandp;
-}
-
-const LLUUID& LLViewerRegion::getRegionID() const
-{
- return mImpl->mRegionID;
-}
-
-void LLViewerRegion::setRegionID(const LLUUID& region_id)
-{
- mImpl->mRegionID = region_id;
-}
-
-void LLViewerRegion::loadObjectCache()
-{
- if (mCacheLoaded)
- {
- return;
- }
-
- // Presume success. If it fails, we don't want to try again.
- mCacheLoaded = true;
-
- if(LLVOCache::instanceExists())
- {
- LLVOCache & vocache = LLVOCache::instance();
- vocache.readFromCache(mHandle, mImpl->mCacheID, mImpl->mCacheMap);
- vocache.readGenericExtrasFromCache(mHandle, mImpl->mCacheID, mImpl->mGLTFOverridesLLSD);
-
- if (mImpl->mCacheMap.empty())
- {
- mCacheDirty = true;
- }
- }
-}
-
-
-void LLViewerRegion::saveObjectCache()
-{
- if (!mCacheLoaded)
- {
- return;
- }
-
- if (mImpl->mCacheMap.empty())
- {
- return;
- }
-
- if(LLVOCache::instanceExists())
- {
- const F32 start_time_threshold = 600.0f; //seconds
- bool removal_enabled = sVOCacheCullingEnabled && (mRegionTimer.getElapsedTimeF32() > start_time_threshold); //allow to remove invalid objects from object cache file.
-
- LLVOCache & instance = LLVOCache::instance();
-
- instance.writeToCache(mHandle, mImpl->mCacheID, mImpl->mCacheMap, mCacheDirty, removal_enabled);
- instance.writeGenericExtrasToCache(mHandle, mImpl->mCacheID, mImpl->mGLTFOverridesLLSD, mCacheDirty, removal_enabled);
- mCacheDirty = false;
- }
-
- if (LLAppViewer::instance()->isQuitting())
- {
- mImpl->mCacheMap.clear();
- }
- else
- {
- // Map of LLVOCacheEntry takes time to release, store map for cleanup on idle
- sRegionCacheCleanup.insert(mImpl->mCacheMap.begin(), mImpl->mCacheMap.end());
- mImpl->mCacheMap.clear();
- // TODO - probably need to do the same for overrides cache
- }
-}
-
-void LLViewerRegion::sendMessage()
-{
- gMessageSystem->sendMessage(mImpl->mHost);
-}
-
-void LLViewerRegion::sendReliableMessage()
-{
- gMessageSystem->sendReliable(mImpl->mHost);
-}
-
-void LLViewerRegion::setWaterHeight(F32 water_level)
-{
- mImpl->mLandp->setWaterHeight(water_level);
-}
-
-F32 LLViewerRegion::getWaterHeight() const
-{
- return mImpl->mLandp->getWaterHeight();
-}
-
-bool LLViewerRegion::isVoiceEnabled() const
-{
- return getRegionFlag(REGION_FLAGS_ALLOW_VOICE);
-}
-
-void LLViewerRegion::setRegionFlags(U64 flags)
-{
- mRegionFlags = flags;
-}
-
-
-void LLViewerRegion::setOriginGlobal(const LLVector3d &origin_global)
-{
- mImpl->mOriginGlobal = origin_global;
- updateRenderMatrix();
- mImpl->mLandp->setOriginGlobal(origin_global);
- mWind.setOriginGlobal(origin_global);
- calculateCenterGlobal();
-}
-
-void LLViewerRegion::updateRenderMatrix()
-{
- mRenderMatrix.setTranslation(getOriginAgent());
-}
-
-void LLViewerRegion::setTimeDilation(F32 time_dilation)
-{
- mTimeDilation = time_dilation;
-}
-
-const LLVector3d & LLViewerRegion::getOriginGlobal() const
-{
- return mImpl->mOriginGlobal;
-}
-
-LLVector3 LLViewerRegion::getOriginAgent() const
-{
- return gAgent.getPosAgentFromGlobal(mImpl->mOriginGlobal);
-}
-
-const LLVector3d & LLViewerRegion::getCenterGlobal() const
-{
- return mImpl->mCenterGlobal;
-}
-
-LLVector3 LLViewerRegion::getCenterAgent() const
-{
- return gAgent.getPosAgentFromGlobal(mImpl->mCenterGlobal);
-}
-
-void LLViewerRegion::setOwner(const LLUUID& owner_id)
-{
- mImpl->mOwnerID = owner_id;
-}
-
-const LLUUID& LLViewerRegion::getOwner() const
-{
- return mImpl->mOwnerID;
-}
-
-void LLViewerRegion::setRegionNameAndZone (const std::string& name_zone)
-{
- std::string::size_type pipe_pos = name_zone.find('|');
- S32 length = name_zone.size();
- if (pipe_pos != std::string::npos)
- {
- mName = name_zone.substr(0, pipe_pos);
- mZoning = name_zone.substr(pipe_pos+1, length-(pipe_pos+1));
- }
- else
- {
- mName = name_zone;
- mZoning = "";
- }
-
- LLStringUtil::stripNonprintable(mName);
- LLStringUtil::stripNonprintable(mZoning);
-}
-
-bool LLViewerRegion::canManageEstate() const
-{
- return gAgent.isGodlike()
- || isEstateManager()
- || gAgent.getID() == getOwner();
-}
-
-const std::string LLViewerRegion::getSimAccessString() const
-{
- return accessToString(mSimAccess);
-}
-
-std::string LLViewerRegion::getLocalizedSimProductName() const
-{
- std::string localized_spn;
- return LLTrans::findString(localized_spn, mProductName) ? localized_spn : mProductName;
-}
-
-// static
-std::string LLViewerRegion::regionFlagsToString(U64 flags)
-{
- std::string result;
-
- if (flags & REGION_FLAGS_SANDBOX)
- {
- result += "Sandbox";
- }
-
- if (flags & REGION_FLAGS_ALLOW_DAMAGE)
- {
- result += " Not Safe";
- }
-
- return result;
-}
-
-// static
-std::string LLViewerRegion::accessToString(U8 sim_access)
-{
- switch(sim_access)
- {
- case SIM_ACCESS_PG:
- return LLTrans::getString("SIM_ACCESS_PG");
-
- case SIM_ACCESS_MATURE:
- return LLTrans::getString("SIM_ACCESS_MATURE");
-
- case SIM_ACCESS_ADULT:
- return LLTrans::getString("SIM_ACCESS_ADULT");
-
- case SIM_ACCESS_DOWN:
- return LLTrans::getString("SIM_ACCESS_DOWN");
-
- case SIM_ACCESS_MIN:
- default:
- return LLTrans::getString("SIM_ACCESS_MIN");
- }
-}
-
-// static
-std::string LLViewerRegion::getAccessIcon(U8 sim_access)
-{
- switch(sim_access)
- {
- case SIM_ACCESS_MATURE:
- return "Parcel_M_Dark";
-
- case SIM_ACCESS_ADULT:
- return "Parcel_R_Light";
-
- case SIM_ACCESS_PG:
- return "Parcel_PG_Light";
-
- case SIM_ACCESS_MIN:
- default:
- return "";
- }
-}
-
-// static
-std::string LLViewerRegion::accessToShortString(U8 sim_access)
-{
- switch(sim_access) /* Flawfinder: ignore */
- {
- case SIM_ACCESS_PG:
- return "PG";
-
- case SIM_ACCESS_MATURE:
- return "M";
-
- case SIM_ACCESS_ADULT:
- return "A";
-
- case SIM_ACCESS_MIN:
- default:
- return "U";
- }
-}
-
-// static
-U8 LLViewerRegion::shortStringToAccess(const std::string &sim_access)
-{
- U8 accessValue;
-
- if (LLStringUtil::compareStrings(sim_access, "PG") == 0)
- {
- accessValue = SIM_ACCESS_PG;
- }
- else if (LLStringUtil::compareStrings(sim_access, "M") == 0)
- {
- accessValue = SIM_ACCESS_MATURE;
- }
- else if (LLStringUtil::compareStrings(sim_access, "A") == 0)
- {
- accessValue = SIM_ACCESS_ADULT;
- }
- else
- {
- accessValue = SIM_ACCESS_MIN;
- }
-
- return accessValue;
-}
-
-// static
-void LLViewerRegion::processRegionInfo(LLMessageSystem* msg, void**)
-{
- // send it to 'observers'
- // *TODO: switch the floaters to using LLRegionInfoModel
- LL_INFOS() << "Processing region info" << LL_ENDL;
- LLRegionInfoModel::instance().update(msg);
- LLFloaterGodTools::processRegionInfo(msg);
- LLFloaterRegionInfo::processRegionInfo(msg);
-}
-
-void LLViewerRegion::setCacheID(const LLUUID& id)
-{
- mImpl->mCacheID = id;
-}
-
-void LLViewerRegion::renderPropertyLines()
-{
- if (mParcelOverlay)
- {
- mParcelOverlay->renderPropertyLines();
- }
-}
-
-void LLViewerRegion::renderPropertyLinesOnMinimap(F32 scale_pixels_per_meter, const F32 *parcel_outline_color)
-{
- if (mParcelOverlay)
- {
- mParcelOverlay->renderPropertyLinesOnMinimap(scale_pixels_per_meter, parcel_outline_color);
- }
-}
-
-
-// This gets called when the height field changes.
-void LLViewerRegion::dirtyHeights()
-{
- // Property lines need to be reconstructed when the land changes.
- if (mParcelOverlay)
- {
- mParcelOverlay->setDirty();
- }
-}
-
-//physically delete the cache entry
-void LLViewerRegion::killCacheEntry(LLVOCacheEntry* entry, bool for_rendering)
-{
- if(!entry || !entry->isValid())
- {
- return;
- }
-
- if(for_rendering && !entry->isState(LLVOCacheEntry::ACTIVE))
- {
- addNewObject(entry); //force to add to rendering pipeline
- }
-
- //remove from active list and waiting list
- if(entry->isState(LLVOCacheEntry::ACTIVE))
- {
- mImpl->mActiveSet.erase(entry);
- }
- else
- {
- if(entry->isState(LLVOCacheEntry::WAITING))
- {
- mImpl->mWaitingSet.erase(entry);
- }
-
- //remove from mVOCachePartition
- removeFromVOCacheTree(entry);
- }
-
- //remove from the forced visible list
- mImpl->mVisibleEntries.erase(entry);
-
- //disconnect from parent if it is a child
- if(entry->getParentID() > 0)
- {
- LLVOCacheEntry* parent = getCacheEntry(entry->getParentID());
- if(parent)
- {
- parent->removeChild(entry);
- }
- }
- else if(entry->getNumOfChildren() > 0)//remove children from cache if has any
- {
- LLVOCacheEntry* child = entry->getChild();
- while(child != NULL)
- {
- killCacheEntry(child, for_rendering);
- child = entry->getChild();
- }
- }
-
- //will remove it from the object cache, real deletion
- entry->setState(LLVOCacheEntry::INACTIVE);
- entry->removeOctreeEntry();
- entry->setValid(false);
-
- // TODO kill extras/material overrides cache too
-}
-
-//physically delete the cache entry
-void LLViewerRegion::killCacheEntry(U32 local_id)
-{
- killCacheEntry(getCacheEntry(local_id));
-}
-
-U32 LLViewerRegion::getNumOfActiveCachedObjects() const
-{
- return mImpl->mActiveSet.size();
-}
-
-void LLViewerRegion::addActiveCacheEntry(LLVOCacheEntry* entry)
-{
- if(!entry || mDead)
- {
- return;
- }
- if(entry->isState(LLVOCacheEntry::ACTIVE))
- {
- return; //already inserted.
- }
-
- if(entry->isState(LLVOCacheEntry::WAITING))
- {
- mImpl->mWaitingSet.erase(entry);
- }
-
- entry->setState(LLVOCacheEntry::ACTIVE);
- entry->setVisible();
-
- llassert(entry->getEntry()->hasDrawable());
- mImpl->mActiveSet.insert(entry);
-}
-
-void LLViewerRegion::removeActiveCacheEntry(LLVOCacheEntry* entry, LLDrawable* drawablep)
-{
- if(mDead || !entry || !entry->isValid())
- {
- return;
- }
- if(!entry->isState(LLVOCacheEntry::ACTIVE))
- {
- return; //not an active entry.
- }
-
- //shift to the local regional space from agent space
- if(drawablep != NULL && drawablep->getVObj().notNull())
- {
- const LLVector3& pos = drawablep->getVObj()->getPositionRegion();
- LLVector4a shift;
- shift.load3(pos.mV);
- shift.sub(entry->getPositionGroup());
- entry->shift(shift);
- }
-
- if(entry->getParentID() > 0) //is a child
- {
- LLVOCacheEntry* parent = getCacheEntry(entry->getParentID());
- if(parent)
- {
- parent->addChild(entry);
- }
- else //parent not in cache.
- {
- //this happens only when parent is not cacheable.
- mOrphanMap[entry->getParentID()].push_back(entry->getLocalID());
- }
- }
- else //insert to vo cache tree.
- {
- entry->updateParentBoundingInfo();
- entry->saveBoundingSphere();
- addToVOCacheTree(entry);
- }
-
- mImpl->mVisibleEntries.erase(entry);
- mImpl->mActiveSet.erase(entry);
- mImpl->mWaitingSet.erase(entry);
- entry->setState(LLVOCacheEntry::INACTIVE);
-}
-
-bool LLViewerRegion::addVisibleGroup(LLViewerOctreeGroup* group)
-{
- if(mDead || group->isEmpty())
- {
- return false;
- }
-
- mImpl->mVisibleGroups.insert(group);
-
- return true;
-}
-
-U32 LLViewerRegion::getNumOfVisibleGroups() const
-{
- return mImpl ? mImpl->mVisibleGroups.size() : 0;
-}
-
-void LLViewerRegion::updateReflectionProbes()
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY;
- const F32 probe_spacing = 32.f;
- const F32 probe_radius = sqrtf((probe_spacing * 0.5f) * (probe_spacing * 0.5f) * 3.f);
- const F32 hover_height = 2.f;
-
- F32 start = probe_spacing * 0.5f;
-
- U32 grid_width = REGION_WIDTH_METERS / probe_spacing;
-
- mReflectionMaps.resize(grid_width * grid_width);
-
- F32 water_height = getWaterHeight();
- LLVector3 origin = getOriginAgent();
-
- for (U32 i = 0; i < grid_width; ++i)
- {
- F32 x = i * probe_spacing + start;
- for (U32 j = 0; j < grid_width; ++j)
- {
- F32 y = j * probe_spacing + start;
-
- U32 idx = i * grid_width + j;
-
- if (mReflectionMaps[idx].isNull())
- {
- mReflectionMaps[idx] = gPipeline.mReflectionMapManager.addProbe();
- }
-
- LLVector3 probe_origin = LLVector3(x, y, llmax(water_height, mImpl->mLandp->resolveHeightRegion(x, y)));
- probe_origin.mV[2] += hover_height;
- probe_origin += origin;
-
- mReflectionMaps[idx]->mOrigin.load3(probe_origin.mV);
- mReflectionMaps[idx]->mRadius = probe_radius;
- }
- }
-}
-
-void LLViewerRegion::addToVOCacheTree(LLVOCacheEntry* entry)
-{
- if(!sVOCacheCullingEnabled)
- {
- return;
- }
-
- if(mDead || !entry || !entry->getEntry() || !entry->isValid())
- {
- return;
- }
- if(entry->getParentID() > 0)
- {
- return; //no child prim in cache octree.
- }
-
- if(entry->hasState(LLVOCacheEntry::IN_VO_TREE))
- {
- return; //already in the tree.
- }
-
- llassert_always(!entry->getGroup()); //not in octree.
- llassert(!entry->getEntry()->hasDrawable()); //not have drawables
-
- if(mImpl->mVOCachePartition->addEntry(entry->getEntry()))
- {
- entry->setState(LLVOCacheEntry::IN_VO_TREE);
- }
-}
-
-void LLViewerRegion::removeFromVOCacheTree(LLVOCacheEntry* entry)
-{
- if(mDead || !entry || !entry->getEntry())
- {
- return;
- }
-
- if(!entry->hasState(LLVOCacheEntry::IN_VO_TREE))
- {
- return; //not in the tree.
- }
- entry->clearState(LLVOCacheEntry::IN_VO_TREE);
-
- mImpl->mVOCachePartition->removeEntry(entry->getEntry());
-}
-
-//add child objects as visible entries
-void LLViewerRegion::addVisibleChildCacheEntry(LLVOCacheEntry* parent, LLVOCacheEntry* child)
-{
- if(mDead)
- {
- return;
- }
-
- if(parent && (!parent->isValid() || !parent->isState(LLVOCacheEntry::ACTIVE)))
- {
- return; //parent must be valid and in rendering pipeline
- }
-
- if(child && (!child->getEntry() || !child->isValid() || !child->isState(LLVOCacheEntry::INACTIVE)))
- {
- return; //child must be valid and not in the rendering pipeline
- }
-
- if(child)
- {
- child->setState(LLVOCacheEntry::IN_QUEUE);
- mImpl->mVisibleEntries.insert(child);
- }
- else if(parent && parent->getNumOfChildren() > 0) //add all children
- {
- child = parent->getChild();
- while(child != NULL)
- {
- addVisibleChildCacheEntry(NULL, child);
- child = parent->getChild();
- }
- }
-}
-
-void LLViewerRegion::updateVisibleEntries(F32 max_time)
-{
- if(mDead)
- {
- return;
- }
-
- if(mImpl->mVisibleGroups.empty() && mImpl->mVisibleEntries.empty())
- {
- return;
- }
-
- if(!sNewObjectCreationThrottle)
- {
- return;
- }
-
- const F32 LARGE_SCENE_CONTRIBUTION = 1000.f; //a large number to force to load the object.
- const LLVector3 camera_origin = LLViewerCamera::getInstance()->getOrigin();
- const U32 cur_frame = LLViewerOctreeEntryData::getCurrentFrame();
- bool needs_update = ((cur_frame - mImpl->mLastCameraUpdate) > 5) && ((camera_origin - mImpl->mLastCameraOrigin).lengthSquared() > 10.f);
- U32 last_update = mImpl->mLastCameraUpdate;
- LLVector4a local_origin;
- local_origin.load3((camera_origin - getOriginAgent()).mV);
-
- //process visible entries
- for(LLVOCacheEntry::vocache_entry_set_t::iterator iter = mImpl->mVisibleEntries.begin(); iter != mImpl->mVisibleEntries.end();)
- {
- LLVOCacheEntry* vo_entry = *iter;
-
- if(vo_entry->isValid() && vo_entry->getState() < LLVOCacheEntry::WAITING)
- {
- //set a large number to force to load this object.
- vo_entry->setSceneContribution(LARGE_SCENE_CONTRIBUTION);
-
- mImpl->mWaitingList.insert(vo_entry);
- ++iter;
- }
- else
- {
- LLVOCacheEntry::vocache_entry_set_t::iterator next_iter = iter;
- ++next_iter;
- mImpl->mVisibleEntries.erase(iter);
- iter = next_iter;
- }
- }
-
- //
- //process visible groups
- //
- //object projected area threshold
- F32 projection_threshold = LLVOCacheEntry::getSquaredPixelThreshold(mImpl->mVOCachePartition->isFrontCull());
- F32 dist_threshold = mImpl->mVOCachePartition->isFrontCull() ? gAgentCamera.mDrawDistance : LLVOCacheEntry::sRearFarRadius;
-
- std::set< LLPointer<LLViewerOctreeGroup> >::iterator group_iter = mImpl->mVisibleGroups.begin();
- for(; group_iter != mImpl->mVisibleGroups.end(); ++group_iter)
- {
- LLPointer<LLViewerOctreeGroup> group = *group_iter;
- if(group->getNumRefs() < 3 || //group to be deleted
- !group->getOctreeNode() || group->isEmpty()) //group empty
- {
- continue;
- }
-
- for (LLViewerOctreeGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i)
- {
- if((*i)->hasVOCacheEntry())
- {
- LLVOCacheEntry* vo_entry = (LLVOCacheEntry*)(*i)->getVOCacheEntry();
-
- if(vo_entry->getParentID() > 0) //is a child
- {
- //child visibility depends on its parent.
- continue;
- }
- if(!vo_entry->isValid())
- {
- continue; //skip invalid entry.
- }
-
- vo_entry->calcSceneContribution(local_origin, needs_update, last_update, dist_threshold);
- if(vo_entry->getSceneContribution() > projection_threshold)
- {
- mImpl->mWaitingList.insert(vo_entry);
- }
- }
- }
- }
-
- if(needs_update)
- {
- mImpl->mLastCameraOrigin = camera_origin;
- mImpl->mLastCameraUpdate = cur_frame;
- }
-
- return;
-}
-
-void LLViewerRegion::createVisibleObjects(F32 max_time)
-{
- if(mDead)
- {
- return;
- }
- if(mImpl->mWaitingList.empty())
- {
- mImpl->mVOCachePartition->setCullHistory(false);
- return;
- }
-
- S32 throttle = sNewObjectCreationThrottle;
- bool has_new_obj = false;
- LLTimer update_timer;
- for(LLVOCacheEntry::vocache_entry_priority_list_t::iterator iter = mImpl->mWaitingList.begin();
- iter != mImpl->mWaitingList.end(); ++iter)
- {
- LLVOCacheEntry* vo_entry = *iter;
-
- if(vo_entry->getState() < LLVOCacheEntry::WAITING)
- {
- addNewObject(vo_entry);
- has_new_obj = true;
- if(throttle > 0 && !(--throttle) && update_timer.getElapsedTimeF32() > max_time)
- {
- break;
- }
- }
- }
-
- mImpl->mVOCachePartition->setCullHistory(has_new_obj);
-
- return;
-}
-
-void LLViewerRegion::clearCachedVisibleObjects()
-{
- mImpl->mWaitingList.clear();
- mImpl->mVisibleGroups.clear();
-
- //reset all occluders
- mImpl->mVOCachePartition->resetOccluders();
- mPaused = true;
-
- //clean visible entries
- for(LLVOCacheEntry::vocache_entry_set_t::iterator iter = mImpl->mVisibleEntries.begin(); iter != mImpl->mVisibleEntries.end();)
- {
- LLVOCacheEntry* entry = *iter;
- LLVOCacheEntry* parent = getCacheEntry(entry->getParentID());
-
- if(!entry->getParentID() || parent) //no child or parent is cache-able
- {
- if(parent) //has a cache-able parent
- {
- parent->addChild(entry);
- }
-
- LLVOCacheEntry::vocache_entry_set_t::iterator next_iter = iter;
- ++next_iter;
- mImpl->mVisibleEntries.erase(iter);
- iter = next_iter;
- }
- else //parent is not cache-able, leave it.
- {
- ++iter;
- }
- }
-
- //remove all visible entries.
- mLastVisitedEntry = NULL;
- std::vector<LLDrawable*> delete_list;
- for(LLVOCacheEntry::vocache_entry_set_t::iterator iter = mImpl->mActiveSet.begin();
- iter != mImpl->mActiveSet.end(); ++iter)
- {
- LLVOCacheEntry* vo_entry = *iter;
- if (!vo_entry || !vo_entry->getEntry())
- {
- continue;
- }
- LLDrawable* drawablep = (LLDrawable*)vo_entry->getEntry()->getDrawable();
-
- if(drawablep && !drawablep->getParent())
- {
- delete_list.push_back(drawablep);
- }
- }
-
- if(!delete_list.empty())
- {
- for(S32 i = 0; i < delete_list.size(); i++)
- {
- gObjectList.killObject(delete_list[i]->getVObj());
- }
- delete_list.clear();
- }
-
- return;
-}
-
-//perform some necessary but very light updates.
-//to replace the function idleUpdate(...) in case there is no enough time.
-void LLViewerRegion::lightIdleUpdate()
-{
- if(!sVOCacheCullingEnabled)
- {
- return;
- }
- if(mImpl->mCacheMap.empty())
- {
- return;
- }
-
- //reset all occluders
- mImpl->mVOCachePartition->resetOccluders();
-}
-
-void LLViewerRegion::idleUpdate(F32 max_update_time)
-{
- LL_PROFILE_ZONE_SCOPED;
- LLTimer update_timer;
- F32 max_time;
-
- mLastUpdate = LLViewerOctreeEntryData::getCurrentFrame();
-
- mImpl->mLandp->idleUpdate(max_update_time);
-
- if (mParcelOverlay)
- {
- // Hopefully not a significant time sink...
- mParcelOverlay->idleUpdate();
- }
-
- if(!sVOCacheCullingEnabled)
- {
- return;
- }
- if(mImpl->mCacheMap.empty())
- {
- return;
- }
- if(mPaused)
- {
- mPaused = false; //unpause.
- }
-
- LLViewerCamera::eCameraID old_camera_id = LLViewerCamera::sCurCameraID;
- LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
-
- //reset all occluders
- mImpl->mVOCachePartition->resetOccluders();
-
- max_time = max_update_time - update_timer.getElapsedTimeF32();
-
- //kill invisible objects
- killInvisibleObjects(max_time * 0.4f);
- max_time = max_update_time - update_timer.getElapsedTimeF32();
-
- updateVisibleEntries(max_time);
- max_time = max_update_time - update_timer.getElapsedTimeF32();
-
- createVisibleObjects(max_time);
-
- mImpl->mWaitingList.clear();
- mImpl->mVisibleGroups.clear();
-
- LLViewerCamera::sCurCameraID = old_camera_id;
- return;
-}
-
-// static
-void LLViewerRegion::idleCleanup(F32 max_update_time)
-{
- LLTimer update_timer;
- while (!sRegionCacheCleanup.empty() && (max_update_time - update_timer.getElapsedTimeF32() > 0))
- {
- sRegionCacheCleanup.erase(sRegionCacheCleanup.begin());
- }
-}
-
-//update the throttling number for new object creation
-void LLViewerRegion::calcNewObjectCreationThrottle()
-{
- static LLCachedControl<S32> new_object_creation_throttle(gSavedSettings,"NewObjectCreationThrottle");
- static LLCachedControl<F32> throttle_delay_time(gSavedSettings,"NewObjectCreationThrottleDelayTime");
- static LLFrameTimer timer;
-
- //
- //sNewObjectCreationThrottle =
- //-2: throttle is disabled because either the screen is showing progress view, or immediate after the screen is not black
- //-1: throttle is disabled by the debug setting
- //0: no new object creation is allowed
- //>0: valid throttling number
- //
-
- if(gViewerWindow->getProgressView()->getVisible() && throttle_delay_time > 0.f)
- {
- sNewObjectCreationThrottle = -2; //cancel the throttling
- timer.reset();
- }
- else if(sNewObjectCreationThrottle < -1) //just recoved from the login/teleport screen
- {
- if(timer.getElapsedTimeF32() > throttle_delay_time) //wait for throttle_delay_time to reset the throttle
- {
- sNewObjectCreationThrottle = new_object_creation_throttle; //reset
- if(sNewObjectCreationThrottle < -1)
- {
- sNewObjectCreationThrottle = -1;
- }
- }
- }
-
- //update some LLVOCacheEntry debug setting factors.
- LLVOCacheEntry::updateDebugSettings();
-}
-
-bool LLViewerRegion::isViewerCameraStatic()
-{
- return sLastCameraUpdated < LLViewerOctreeEntryData::getCurrentFrame();
-}
-
-void LLViewerRegion::killInvisibleObjects(F32 max_time)
-{
-#if 1 // TODO: kill this. This is ill-conceived, objects that aren't in the camera frustum should not be deleted from memory.
- // because of this, every time you turn around the simulator sends a swarm of full object update messages from cache
- // probe misses and objects have to be reloaded from scratch. From some reason, disabling this causes holes to
- // appear in the scene when flying back and forth between regions
- if(!sVOCacheCullingEnabled)
- {
- return;
- }
- if(mImpl->mActiveSet.empty())
- {
- return;
- }
- if(sNewObjectCreationThrottle < 0)
- {
- return;
- }
-
- LLTimer update_timer;
- LLVector4a camera_origin;
- camera_origin.load3(LLViewerCamera::getInstance()->getOrigin().mV);
- LLVector4a local_origin;
- local_origin.load3((LLViewerCamera::getInstance()->getOrigin() - getOriginAgent()).mV);
- F32 back_threshold = LLVOCacheEntry::sRearFarRadius;
-
- size_t max_update = 64;
- if(!mInvisibilityCheckHistory && isViewerCameraStatic())
- {
- //history is clean, reduce number of checking
- max_update /= 2;
- }
-
- std::vector<LLDrawable*> delete_list;
- S32 update_counter = llmin(max_update, mImpl->mActiveSet.size());
- LLVOCacheEntry::vocache_entry_set_t::iterator iter = mImpl->mActiveSet.upper_bound(mLastVisitedEntry);
-
- for(; update_counter > 0; --update_counter, ++iter)
- {
- if(iter == mImpl->mActiveSet.end())
- {
- iter = mImpl->mActiveSet.begin();
- }
- if((*iter)->getParentID() > 0)
- {
- continue; //skip child objects, they are removed with their parent.
- }
-
- LLVOCacheEntry* vo_entry = *iter;
- if(!vo_entry->isAnyVisible(camera_origin, local_origin, back_threshold) && vo_entry->mLastCameraUpdated < sLastCameraUpdated)
- {
- killObject(vo_entry, delete_list);
- }
-
- if(max_time < update_timer.getElapsedTimeF32()) //time out
- {
- break;
- }
- }
-
- if(iter == mImpl->mActiveSet.end())
- {
- mLastVisitedEntry = NULL;
- }
- else
- {
- mLastVisitedEntry = *iter;
- }
-
- mInvisibilityCheckHistory <<= 1;
- if(!delete_list.empty())
- {
- mInvisibilityCheckHistory |= 1;
- S32 count = delete_list.size();
- for(S32 i = 0; i < count; i++)
- {
- gObjectList.killObject(delete_list[i]->getVObj());
- }
- delete_list.clear();
- }
-
- return;
-#endif
-}
-
-void LLViewerRegion::killObject(LLVOCacheEntry* entry, std::vector<LLDrawable*>& delete_list)
-{
- //kill the object.
- LLDrawable* drawablep = (LLDrawable*)entry->getEntry()->getDrawable();
- llassert(drawablep);
- llassert(drawablep->getRegion() == this);
-
- if(drawablep && !drawablep->getParent())
- {
- LLViewerObject* v_obj = drawablep->getVObj();
- if (v_obj->isSelected()
- || (v_obj->flagAnimSource() && isAgentAvatarValid() && gAgentAvatarp->hasMotionFromSource(v_obj->getID())))
- {
- // do not remove objects user is interacting with
- ((LLViewerOctreeEntryData*)drawablep)->setVisible();
- return;
- }
- LLViewerObject::const_child_list_t& child_list = v_obj->getChildren();
- for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin();
- iter != child_list.end(); iter++)
- {
- LLViewerObject* child = *iter;
- if(child->mDrawable)
- {
- if( !child->mDrawable->getEntry()
- || !child->mDrawable->getEntry()->hasVOCacheEntry()
- || child->isSelected()
- || (child->flagAnimSource() && isAgentAvatarValid() && gAgentAvatarp->hasMotionFromSource(child->getID())))
- {
- //do not remove parent if any of its children non-cacheable, animating or selected
- //especially for the case that an avatar sits on a cache-able object
- ((LLViewerOctreeEntryData*)drawablep)->setVisible();
- return;
- }
-
- LLOcclusionCullingGroup* group = (LLOcclusionCullingGroup*)child->mDrawable->getGroup();
- if(group && group->isAnyRecentlyVisible())
- {
- //set the parent visible if any of its children visible.
- ((LLViewerOctreeEntryData*)drawablep)->setVisible();
- return;
- }
- }
- }
- delete_list.push_back(drawablep);
- }
-}
-
-LLViewerObject* LLViewerRegion::addNewObject(LLVOCacheEntry* entry)
-{
- if(!entry || !entry->getEntry())
- {
- if(entry)
- {
- mImpl->mVisibleEntries.erase(entry);
- entry->setState(LLVOCacheEntry::INACTIVE);
- }
- return NULL;
- }
-
- LLViewerObject* obj = NULL;
- if(!entry->getEntry()->hasDrawable()) //not added to the rendering pipeline yet
- {
- //add the object
- obj = gObjectList.processObjectUpdateFromCache(entry, this);
- if(obj)
- {
- if(!entry->isState(LLVOCacheEntry::ACTIVE))
- {
- mImpl->mWaitingSet.insert(entry);
- entry->setState(LLVOCacheEntry::WAITING);
- }
- }
- }
- else
- {
- LLViewerRegion* old_regionp = ((LLDrawable*)entry->getEntry()->getDrawable())->getRegion();
- if(old_regionp != this)
- {
- //this object exists in two regions at the same time;
- //this case can be safely ignored here because
- //server should soon send update message to remove one region for this object.
-
- LL_WARNS() << "Entry: " << entry->getLocalID() << " exists in two regions at the same time." << LL_ENDL;
- return NULL;
- }
-
- LL_WARNS() << "Entry: " << entry->getLocalID() << " in rendering pipeline but not set to be active." << LL_ENDL;
-
- //should not hit here any more, but does not hurt either, just put it back to active list
- addActiveCacheEntry(entry);
- }
-
- return obj;
-}
-
-//update object cache if the object receives a full-update or terse update
-//update_type == EObjectUpdateType::OUT_TERSE_IMPROVED or EObjectUpdateType::OUT_FULL
-LLViewerObject* LLViewerRegion::updateCacheEntry(U32 local_id, LLViewerObject* objectp)
-{
- LLVOCacheEntry* entry = getCacheEntry(local_id);
- if (!entry)
- {
- return objectp; //not in the cache, do nothing.
- }
- if(!objectp) //object not created
- {
- //create a new object from cache.
- objectp = addNewObject(entry);
- }
-
- //remove from cache.
- killCacheEntry(entry, true);
-
- return objectp;
-}
-
-// As above, but forcibly do the update.
-void LLViewerRegion::forceUpdate()
-{
- mImpl->mLandp->idleUpdate(0.f);
-
- if (mParcelOverlay)
- {
- mParcelOverlay->idleUpdate(true);
- }
-}
-
-void LLViewerRegion::connectNeighbor(LLViewerRegion *neighborp, U32 direction)
-{
- mImpl->mLandp->connectNeighbor(neighborp->mImpl->mLandp, direction);
-}
-
-
-void LLViewerRegion::disconnectAllNeighbors()
-{
- mImpl->mLandp->disconnectAllNeighbors();
-}
-
-LLVLComposition * LLViewerRegion::getComposition() const
-{
- return mImpl->mCompositionp;
-}
-
-F32 LLViewerRegion::getCompositionXY(const S32 x, const S32 y) const
-{
- if (x >= 256)
- {
- if (y >= 256)
- {
- LLVector3d center = getCenterGlobal() + LLVector3d(256.f, 256.f, 0.f);
- LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromPosGlobal(center);
- if (regionp)
- {
- // OK, we need to do some hackery here - different simulators no longer use
- // the same composition values, necessarily.
- // If we're attempting to blend, then we want to make the fractional part of
- // this region match the fractional of the adjacent. For now, just minimize
- // the delta.
- F32 our_comp = getComposition()->getValueScaled(255, 255);
- F32 adj_comp = regionp->getComposition()->getValueScaled(x - 256.f, y - 256.f);
- while (llabs(our_comp - adj_comp) >= 1.f)
- {
- if (our_comp > adj_comp)
- {
- adj_comp += 1.f;
- }
- else
- {
- adj_comp -= 1.f;
- }
- }
- return adj_comp;
- }
- }
- else
- {
- LLVector3d center = getCenterGlobal() + LLVector3d(256.f, 0, 0.f);
- LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromPosGlobal(center);
- if (regionp)
- {
- // OK, we need to do some hackery here - different simulators no longer use
- // the same composition values, necessarily.
- // If we're attempting to blend, then we want to make the fractional part of
- // this region match the fractional of the adjacent. For now, just minimize
- // the delta.
- F32 our_comp = getComposition()->getValueScaled(255.f, (F32)y);
- F32 adj_comp = regionp->getComposition()->getValueScaled(x - 256.f, (F32)y);
- while (llabs(our_comp - adj_comp) >= 1.f)
- {
- if (our_comp > adj_comp)
- {
- adj_comp += 1.f;
- }
- else
- {
- adj_comp -= 1.f;
- }
- }
- return adj_comp;
- }
- }
- }
- else if (y >= 256)
- {
- LLVector3d center = getCenterGlobal() + LLVector3d(0.f, 256.f, 0.f);
- LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromPosGlobal(center);
- if (regionp)
- {
- // OK, we need to do some hackery here - different simulators no longer use
- // the same composition values, necessarily.
- // If we're attempting to blend, then we want to make the fractional part of
- // this region match the fractional of the adjacent. For now, just minimize
- // the delta.
- F32 our_comp = getComposition()->getValueScaled((F32)x, 255.f);
- F32 adj_comp = regionp->getComposition()->getValueScaled((F32)x, y - 256.f);
- while (llabs(our_comp - adj_comp) >= 1.f)
- {
- if (our_comp > adj_comp)
- {
- adj_comp += 1.f;
- }
- else
- {
- adj_comp -= 1.f;
- }
- }
- return adj_comp;
- }
- }
-
- return getComposition()->getValueScaled((F32)x, (F32)y);
-}
-
-void LLViewerRegion::calculateCenterGlobal()
-{
- mImpl->mCenterGlobal = mImpl->mOriginGlobal;
- mImpl->mCenterGlobal.mdV[VX] += 0.5 * mWidth;
- mImpl->mCenterGlobal.mdV[VY] += 0.5 * mWidth;
- mImpl->mCenterGlobal.mdV[VZ] = 0.5 * mImpl->mLandp->getMinZ() + mImpl->mLandp->getMaxZ();
-}
-
-void LLViewerRegion::calculateCameraDistance()
-{
- mCameraDistanceSquared = (F32)(gAgentCamera.getCameraPositionGlobal() - getCenterGlobal()).magVecSquared();
-}
-
-std::ostream& operator<<(std::ostream &s, const LLViewerRegion ®ion)
-{
- s << "{ ";
- s << region.mImpl->mHost;
- s << " mOriginGlobal = " << region.getOriginGlobal()<< "\n";
- std::string name(region.getName()), zone(region.getZoning());
- if (! name.empty())
- {
- s << " mName = " << name << '\n';
- }
- if (! zone.empty())
- {
- s << " mZoning = " << zone << '\n';
- }
- s << "}";
- return s;
-}
-
-
-// ---------------- Protected Member Functions ----------------
-
-void LLViewerRegion::updateNetStats()
-{
- F32 dt = mImpl->mLastNetUpdate.getElapsedTimeAndResetF32();
-
- LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(mImpl->mHost);
- if (!cdp)
- {
- mAlive = false;
- return;
- }
-
- mAlive = true;
- mDeltaTime = dt;
-
- mLastPacketsIn = mPacketsIn;
- mLastBitsIn = mBitsIn;
- mLastPacketsOut = mPacketsOut;
- mLastPacketsLost = mPacketsLost;
-
- mPacketsIn = cdp->getPacketsIn();
- mBitsIn = 8 * cdp->getBytesIn();
- mPacketsOut = cdp->getPacketsOut();
- mPacketsLost = cdp->getPacketsLost();
- mPingDelay = cdp->getPingDelay();
-
- mBitsReceived += mBitsIn - mLastBitsIn;
- mPacketsReceived += mPacketsIn - mLastPacketsIn;
-}
-
-
-U32 LLViewerRegion::getPacketsLost() const
-{
- LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(mImpl->mHost);
- if (!cdp)
- {
- LL_INFOS() << "LLViewerRegion::getPacketsLost couldn't find circuit for " << mImpl->mHost << LL_ENDL;
- return 0;
- }
- else
- {
- return cdp->getPacketsLost();
- }
-}
-
-S32 LLViewerRegion::getHttpResponderID() const
-{
- return mImpl->mHttpResponderID;
-}
-
-bool LLViewerRegion::pointInRegionGlobal(const LLVector3d &point_global) const
-{
- LLVector3 pos_region = getPosRegionFromGlobal(point_global);
-
- if (pos_region.mV[VX] < 0)
- {
- return false;
- }
- if (pos_region.mV[VX] >= mWidth)
- {
- return false;
- }
- if (pos_region.mV[VY] < 0)
- {
- return false;
- }
- if (pos_region.mV[VY] >= mWidth)
- {
- return false;
- }
- return true;
-}
-
-LLVector3 LLViewerRegion::getPosRegionFromGlobal(const LLVector3d &point_global) const
-{
- LLVector3 pos_region;
- pos_region.setVec(point_global - mImpl->mOriginGlobal);
- return pos_region;
-}
-
-LLVector3d LLViewerRegion::getPosGlobalFromRegion(const LLVector3 &pos_region) const
-{
- LLVector3d pos_region_d;
- pos_region_d.setVec(pos_region);
- return pos_region_d + mImpl->mOriginGlobal;
-}
-
-LLVector3 LLViewerRegion::getPosAgentFromRegion(const LLVector3 &pos_region) const
-{
- LLVector3d pos_global = getPosGlobalFromRegion(pos_region);
-
- return gAgent.getPosAgentFromGlobal(pos_global);
-}
-
-LLVector3 LLViewerRegion::getPosRegionFromAgent(const LLVector3 &pos_agent) const
-{
- return pos_agent - getOriginAgent();
-}
-
-F32 LLViewerRegion::getLandHeightRegion(const LLVector3& region_pos)
-{
- return mImpl->mLandp->resolveHeightRegion( region_pos );
-}
-
-bool LLViewerRegion::isAlive()
-{
- return mAlive;
-}
-
-bool LLViewerRegion::isOwnedSelf(const LLVector3& pos)
-{
- if (mParcelOverlay)
- {
- return mParcelOverlay->isOwnedSelf(pos);
- } else {
- return false;
- }
-}
-
-// Owned by a group you belong to? (officer or member)
-bool LLViewerRegion::isOwnedGroup(const LLVector3& pos)
-{
- if (mParcelOverlay)
- {
- return mParcelOverlay->isOwnedGroup(pos);
- } else {
- return false;
- }
-}
-
-// the new TCP coarse location handler node
-class CoarseLocationUpdate : public LLHTTPNode
-{
-public:
- virtual void post(
- ResponsePtr responder,
- const LLSD& context,
- const LLSD& input) const
- {
- LLHost host(input["sender"].asString());
-
- LLWorld *world_inst = LLWorld::getInstance(); // Not a singleton!
- if (!world_inst)
- {
- return;
- }
-
- LLViewerRegion* region = world_inst->getRegion(host);
- if( !region )
- {
- return;
- }
-
- S32 target_index = input["body"]["Index"][0]["Prey"].asInteger();
- S32 you_index = input["body"]["Index"][0]["You" ].asInteger();
-
- std::vector<U32>* avatar_locs = ®ion->mMapAvatars;
- std::vector<LLUUID>* avatar_ids = ®ion->mMapAvatarIDs;
- avatar_locs->clear();
- avatar_ids->clear();
-
- //LL_INFOS() << "coarse locations agent[0] " << input["body"]["AgentData"][0]["AgentID"].asUUID() << LL_ENDL;
- //LL_INFOS() << "my agent id = " << gAgent.getID() << LL_ENDL;
- //LL_INFOS() << ll_pretty_print_sd(input) << LL_ENDL;
-
- LLSD
- locs = input["body"]["Location"],
- agents = input["body"]["AgentData"];
- LLSD::array_iterator
- locs_it = locs.beginArray(),
- agents_it = agents.beginArray();
- bool has_agent_data = input["body"].has("AgentData");
-
- for(int i=0;
- locs_it != locs.endArray();
- i++, locs_it++)
- {
- U8
- x = locs_it->get("X").asInteger(),
- y = locs_it->get("Y").asInteger(),
- z = locs_it->get("Z").asInteger();
- // treat the target specially for the map, and don't add you or the target
- if(i == target_index)
- {
- LLVector3d global_pos(region->getOriginGlobal());
- global_pos.mdV[VX] += (F64)x;
- global_pos.mdV[VY] += (F64)y;
- global_pos.mdV[VZ] += (F64)z * 4.0;
- LLAvatarTracker::instance().setTrackedCoarseLocation(global_pos);
- }
- else if( i != you_index)
- {
- U32 pos = 0x0;
- pos |= x;
- pos <<= 8;
- pos |= y;
- pos <<= 8;
- pos |= z;
- avatar_locs->push_back(pos);
- //LL_INFOS() << "next pos: " << x << "," << y << "," << z << ": " << pos << LL_ENDL;
- if(has_agent_data) // for backwards compatibility with old message format
- {
- LLUUID agent_id(agents_it->get("AgentID").asUUID());
- //LL_INFOS() << "next agent: " << agent_id.asString() << LL_ENDL;
- avatar_ids->push_back(agent_id);
- }
- }
- if (has_agent_data)
- {
- agents_it++;
- }
- }
- }
-};
-
-// build the coarse location HTTP node under the "/message" URL
-LLHTTPRegistration<CoarseLocationUpdate>
- gHTTPRegistrationCoarseLocationUpdate(
- "/message/CoarseLocationUpdate");
-
-
-// the deprecated coarse location handler
-void LLViewerRegion::updateCoarseLocations(LLMessageSystem* msg)
-{
- //LL_INFOS() << "CoarseLocationUpdate" << LL_ENDL;
- mMapAvatars.clear();
- mMapAvatarIDs.clear(); // only matters in a rare case but it's good to be safe.
-
- U8 x_pos = 0;
- U8 y_pos = 0;
- U8 z_pos = 0;
-
- U32 pos = 0x0;
-
- S16 agent_index;
- S16 target_index;
- msg->getS16Fast(_PREHASH_Index, _PREHASH_You, agent_index);
- msg->getS16Fast(_PREHASH_Index, _PREHASH_Prey, target_index);
-
- bool has_agent_data = msg->has(_PREHASH_AgentData);
- S32 count = msg->getNumberOfBlocksFast(_PREHASH_Location);
- for(S32 i = 0; i < count; i++)
- {
- msg->getU8Fast(_PREHASH_Location, _PREHASH_X, x_pos, i);
- msg->getU8Fast(_PREHASH_Location, _PREHASH_Y, y_pos, i);
- msg->getU8Fast(_PREHASH_Location, _PREHASH_Z, z_pos, i);
- LLUUID agent_id = LLUUID::null;
- if(has_agent_data)
- {
- msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id, i);
- }
-
- //LL_INFOS() << " object X: " << (S32)x_pos << " Y: " << (S32)y_pos
- // << " Z: " << (S32)(z_pos * 4)
- // << LL_ENDL;
-
- // treat the target specially for the map
- if(i == target_index)
- {
- LLVector3d global_pos(mImpl->mOriginGlobal);
- global_pos.mdV[VX] += (F64)(x_pos);
- global_pos.mdV[VY] += (F64)(y_pos);
- global_pos.mdV[VZ] += (F64)(z_pos) * 4.0;
- LLAvatarTracker::instance().setTrackedCoarseLocation(global_pos);
- }
-
- //don't add you
- if( i != agent_index)
- {
- pos = 0x0;
- pos |= x_pos;
- pos <<= 8;
- pos |= y_pos;
- pos <<= 8;
- pos |= z_pos;
- mMapAvatars.push_back(pos);
- if(has_agent_data)
- {
- mMapAvatarIDs.push_back(agent_id);
- }
- }
- }
-}
-
-void LLViewerRegion::getInfo(LLSD& info)
-{
- info["Region"]["Host"] = getHost().getIPandPort();
- info["Region"]["Name"] = getName();
- U32 x, y;
- from_region_handle(getHandle(), &x, &y);
- info["Region"]["Handle"]["x"] = (LLSD::Integer)x;
- info["Region"]["Handle"]["y"] = (LLSD::Integer)y;
-}
-
-void LLViewerRegion::requestSimulatorFeatures()
-{
- LL_DEBUGS("SimulatorFeatures") << "region " << getName() << " ptr " << this
- << " trying to request SimulatorFeatures" << LL_ENDL;
- // kick off a request for simulator features
- std::string url = getCapability("SimulatorFeatures");
- if (!url.empty())
- {
- std::string coroname =
- LLCoros::instance().launch("LLViewerRegionImpl::requestSimulatorFeatureCoro",
- boost::bind(&LLViewerRegionImpl::requestSimulatorFeatureCoro, url, getHandle()));
-
- // requestSimulatorFeatures can be called from other coros,
- // launch() acts like a suspend()
- // Make sure we are still good to do
- LLCoros::checkStop();
-
- LL_INFOS("AppInit", "SimulatorFeatures") << "Launching " << coroname << " requesting simulator features from " << url << " for region " << getRegionID() << LL_ENDL;
- }
- else
- {
- LL_WARNS("AppInit", "SimulatorFeatures") << "SimulatorFeatures cap not set" << LL_ENDL;
- }
-}
-
-boost::signals2::connection LLViewerRegion::setSimulatorFeaturesReceivedCallback(const caps_received_signal_t::slot_type& cb)
-{
- return mSimulatorFeaturesReceivedSignal.connect(cb);
-}
-
-void LLViewerRegion::setSimulatorFeaturesReceived(bool received)
-{
- mSimulatorFeaturesReceived = received;
- if (received)
- {
- mSimulatorFeaturesReceivedSignal(getRegionID(), this);
- mSimulatorFeaturesReceivedSignal.disconnect_all_slots();
- }
-}
-
-bool LLViewerRegion::simulatorFeaturesReceived() const
-{
- return mSimulatorFeaturesReceived;
-}
-
-void LLViewerRegion::getSimulatorFeatures(LLSD& sim_features) const
-{
- sim_features = mSimulatorFeatures;
-
-}
-
-void LLViewerRegion::setSimulatorFeatures(const LLSD& sim_features)
-{
- std::stringstream str;
-
- LLSDSerialize::toPrettyXML(sim_features, str);
- LL_INFOS() << "region " << getName() << " " << str.str() << LL_ENDL;
- mSimulatorFeatures = sim_features;
-
- setSimulatorFeaturesReceived(true);
-
-}
-
-//this is called when the parent is not cacheable.
-//move all orphan children out of cache and insert to rendering octree.
-void LLViewerRegion::findOrphans(U32 parent_id)
-{
- orphan_list_t::iterator iter = mOrphanMap.find(parent_id);
- if(iter != mOrphanMap.end())
- {
- std::vector<U32>* children = &mOrphanMap[parent_id];
- for(S32 i = 0; i < children->size(); i++)
- {
- //parent is visible, so is the child.
- addVisibleChildCacheEntry(NULL, getCacheEntry((*children)[i]));
- }
- children->clear();
- mOrphanMap.erase(parent_id);
- }
-}
-
-void LLViewerRegion::decodeBoundingInfo(LLVOCacheEntry* entry)
-{
- if(!sVOCacheCullingEnabled)
- {
- gObjectList.processObjectUpdateFromCache(entry, this);
- return;
- }
- if(!entry || !entry->isValid())
- {
- return;
- }
-
- if(!entry->getEntry())
- {
- entry->setOctreeEntry(NULL);
- }
-
- if(entry->getEntry()->hasDrawable()) //already in the rendering pipeline
- {
- LLViewerRegion* old_regionp = ((LLDrawable*)entry->getEntry()->getDrawable())->getRegion();
- if(old_regionp != this && old_regionp)
- {
- LLViewerObject* obj = ((LLDrawable*)entry->getEntry()->getDrawable())->getVObj();
- if(obj)
- {
- //remove from old region
- old_regionp->killCacheEntry(obj->getLocalID());
-
- //change region
- obj->setRegion(this);
- }
- }
-
- addActiveCacheEntry(entry);
-
- //set parent id
- U32 parent_id = 0;
- if (entry->getDP()) // NULL if nothing cached
- {
- LLViewerObject::unpackParentID(entry->getDP(), parent_id);
- }
- if(parent_id != entry->getParentID())
- {
- entry->setParentID(parent_id);
- }
-
- //update the object
- gObjectList.processObjectUpdateFromCache(entry, this);
- return; //done
- }
-
- //must not be active.
- llassert_always(!entry->isState(LLVOCacheEntry::ACTIVE));
- removeFromVOCacheTree(entry); //remove from cache octree if it is in.
-
- LLVector3 pos;
- LLVector3 scale;
- LLQuaternion rot;
-
- //decode spatial info and parent info
- U32 parent_id = entry->getDP() ? LLViewerObject::extractSpatialExtents(entry->getDP(), pos, scale, rot) : entry->getParentID();
-
- U32 old_parent_id = entry->getParentID();
- bool same_old_parent = false;
- if(parent_id != old_parent_id) //parent changed.
- {
- if(old_parent_id > 0) //has an old parent, disconnect it
- {
- LLVOCacheEntry* old_parent = getCacheEntry(old_parent_id);
- if(old_parent)
- {
- old_parent->removeChild(entry);
- if(!old_parent->isState(LLVOCacheEntry::INACTIVE))
- {
- mImpl->mVisibleEntries.erase(entry);
- entry->setState(LLVOCacheEntry::INACTIVE);
- }
- }
- }
- entry->setParentID(parent_id);
- }
- else
- {
- same_old_parent = true;
- }
-
- if(parent_id > 0) //has a new parent
- {
- //1, find the parent in cache
- LLVOCacheEntry* parent = getCacheEntry(parent_id);
-
- //2, parent is not in the cache, put into the orphan list.
- if(!parent)
- {
- if(!same_old_parent)
- {
- //check if parent is non-cacheable and already created
- if(isNonCacheableObjectCreated(parent_id))
- {
- //parent is visible, so is the child.
- addVisibleChildCacheEntry(NULL, entry);
- }
- else
- {
- entry->setBoundingInfo(pos, scale);
- mOrphanMap[parent_id].push_back(entry->getLocalID());
- }
- }
- else
- {
- entry->setBoundingInfo(pos, scale);
- }
- }
- else //parent in cache.
- {
- if(!parent->isState(LLVOCacheEntry::INACTIVE))
- {
- //parent is visible, so is the child.
- addVisibleChildCacheEntry(parent, entry);
- }
- else
- {
- entry->setBoundingInfo(pos, scale);
- parent->addChild(entry);
-
- if(parent->getGroup()) //re-insert parent to vo-cache tree because its bounding info changed.
- {
- removeFromVOCacheTree(parent);
- addToVOCacheTree(parent);
- }
- }
- }
-
- return;
- }
-
- //
- //no parent
- //
- entry->setBoundingInfo(pos, scale);
-
- if(!parent_id) //a potential parent
- {
- //find all children and update their bounding info
- orphan_list_t::iterator iter = mOrphanMap.find(entry->getLocalID());
- if(iter != mOrphanMap.end())
- {
- std::vector<U32>* orphans = &mOrphanMap[entry->getLocalID()];
- S32 size = orphans->size();
- for(S32 i = 0; i < size; i++)
- {
- LLVOCacheEntry* child = getCacheEntry((*orphans)[i]);
- if(child)
- {
- entry->addChild(child);
- }
- }
- orphans->clear();
- mOrphanMap.erase(entry->getLocalID());
- }
- }
-
- if(!entry->getGroup() && entry->isState(LLVOCacheEntry::INACTIVE))
- {
- addToVOCacheTree(entry);
- }
- return ;
-}
-
-LLViewerRegion::eCacheUpdateResult LLViewerRegion::cacheFullUpdate(LLDataPackerBinaryBuffer &dp, U32 flags)
-{
- eCacheUpdateResult result;
- U32 crc;
- U32 local_id;
-
- LLViewerObject::unpackU32(&dp, local_id, "LocalID");
- LLViewerObject::unpackU32(&dp, crc, "CRC");
-
- LLVOCacheEntry* entry = getCacheEntry(local_id, false);
-
- if (entry)
- {
- entry->setValid();
-
- // we've seen this object before
- if (entry->getCRC() == crc)
- {
- LL_DEBUGS("AnimatedObjects") << " got dupe for local_id " << local_id << LL_ENDL;
- dumpStack("AnimatedObjectsStack");
-
- // Record a hit
- entry->recordDupe();
- result = CACHE_UPDATE_DUPE;
- }
- else //CRC changed
- {
- LL_DEBUGS("AnimatedObjects") << " got update for local_id " << local_id << LL_ENDL;
- dumpStack("AnimatedObjectsStack");
-
- // Update the cache entry
- entry->updateEntry(crc, dp);
-
- decodeBoundingInfo(entry);
-
- result = CACHE_UPDATE_CHANGED;
- }
- }
- else
- {
- LL_DEBUGS("AnimatedObjects") << " got first notification for local_id " << local_id << LL_ENDL;
- dumpStack("AnimatedObjectsStack");
-
- // we haven't seen this object before
- // Create new entry and add to map
- result = CACHE_UPDATE_ADDED;
- entry = new LLVOCacheEntry(local_id, crc, dp);
- record(LLStatViewer::OBJECT_CACHE_HIT_RATE, LLUnits::Ratio::fromValue(0));
-
- mImpl->mCacheMap[local_id] = entry;
-
- decodeBoundingInfo(entry);
- }
- entry->setUpdateFlags(flags);
-
- return result;
- }
-
-LLViewerRegion::eCacheUpdateResult LLViewerRegion::cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinaryBuffer &dp, U32 flags)
-{
- eCacheUpdateResult result = cacheFullUpdate(dp, flags);
-
- return result;
-}
-
-void LLViewerRegion::cacheFullUpdateGLTFOverride(const LLGLTFOverrideCacheEntry &override_data)
-{
- U32 local_id = override_data.mLocalId;
- mImpl->mGLTFOverridesLLSD[local_id] = override_data;
-}
-
-LLVOCacheEntry* LLViewerRegion::getCacheEntryForOctree(U32 local_id)
-{
- if(!sVOCacheCullingEnabled)
- {
- return NULL;
- }
-
- LLVOCacheEntry* entry = getCacheEntry(local_id);
- removeFromVOCacheTree(entry);
-
- return entry;
-}
-
-LLVOCacheEntry* LLViewerRegion::getCacheEntry(U32 local_id, bool valid)
-{
- LLVOCacheEntry::vocache_entry_map_t::iterator iter = mImpl->mCacheMap.find(local_id);
- if(iter != mImpl->mCacheMap.end())
- {
- if(!valid || iter->second->isValid())
- {
- return iter->second;
- }
- }
- return NULL;
-}
-
-void LLViewerRegion::addCacheMiss(U32 id, LLViewerRegion::eCacheMissType cache_miss_type)
-{
- mRegionCacheMissCount++;
- mCacheMissList.push_back(CacheMissItem(id, cache_miss_type));
-}
-
-//check if a non-cacheable object is already created.
-bool LLViewerRegion::isNonCacheableObjectCreated(U32 local_id)
-{
- if(mImpl && local_id > 0 && mImpl->mNonCacheableCreatedList.find(local_id) != mImpl->mNonCacheableCreatedList.end())
- {
- return true;
- }
- return false;
-}
-
-void LLViewerRegion::removeFromCreatedList(U32 local_id)
-{
- if(mImpl && local_id > 0)
- {
- std::set<U32>::iterator iter = mImpl->mNonCacheableCreatedList.find(local_id);
- if(iter != mImpl->mNonCacheableCreatedList.end())
- {
- mImpl->mNonCacheableCreatedList.erase(iter);
- }
- }
- }
-
-void LLViewerRegion::addToCreatedList(U32 local_id)
-{
- if(mImpl && local_id > 0)
- {
- mImpl->mNonCacheableCreatedList.insert(local_id);
- }
-}
-
-// Get data packer for this object, if we have cached data
-// AND the CRC matches. JC
-bool LLViewerRegion::probeCache(U32 local_id, U32 crc, U32 flags, U8 &cache_miss_type)
-{
- //llassert(mCacheLoaded); This assert failes often, changing to early-out -- davep, 2010/10/18
-
- LLVOCacheEntry* entry = getCacheEntry(local_id, false);
-
- if (entry)
- {
- // we've seen this object before
- if (entry->getCRC() == crc)
- {
- // Record a hit
- mRegionCacheHitCount++;
- entry->recordHit();
- cache_miss_type = CACHE_MISS_TYPE_NONE;
- entry->setUpdateFlags(flags);
-
- if(entry->isState(LLVOCacheEntry::ACTIVE))
- {
- ((LLDrawable*)entry->getEntry()->getDrawable())->getVObj()->loadFlags(flags);
- return true;
- }
-
- if(entry->isValid())
- {
- return true; //already probed
- }
-
- entry->setValid();
- decodeBoundingInfo(entry);
-
- //loadCacheMiscExtras(local_id, entry, crc);
-
- return true;
- }
- else
- {
- // LL_INFOS() << "CRC miss for " << local_id << LL_ENDL;
-
- addCacheMiss(local_id, CACHE_MISS_TYPE_CRC);
- cache_miss_type = CACHE_MISS_TYPE_CRC;
- }
- }
- else
- { // Total miss, don't have the object in cache
- // LL_INFOS() << "Cache miss for " << local_id << LL_ENDL;
- addCacheMiss(local_id, CACHE_MISS_TYPE_TOTAL);
- cache_miss_type = CACHE_MISS_TYPE_TOTAL;
- }
-
- return false;
-}
-
-void LLViewerRegion::addCacheMissFull(const U32 local_id)
-{
- addCacheMiss(local_id, CACHE_MISS_TYPE_TOTAL);
-}
-
-void LLViewerRegion::requestCacheMisses()
-{
- if (!mCacheMissList.size())
- {
- return;
- }
-
- LLMessageSystem* msg = gMessageSystem;
- bool start_new_message = true;
- S32 blocks = 0;
-
- //send requests for all cache-missed objects
- for (CacheMissItem::cache_miss_list_t::iterator iter = mCacheMissList.begin(); iter != mCacheMissList.end(); ++iter)
- {
- if (start_new_message)
- {
- msg->newMessageFast(_PREHASH_RequestMultipleObjects);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- start_new_message = false;
- }
-
- msg->nextBlockFast(_PREHASH_ObjectData);
- msg->addU8Fast(_PREHASH_CacheMissType, (*iter).mType);
- msg->addU32Fast(_PREHASH_ID, (*iter).mID);
-
- LL_DEBUGS("AnimatedObjects") << "Requesting cache missed object " << (*iter).mID << LL_ENDL;
-
- blocks++;
-
- if (blocks >= 255)
- {
- sendReliableMessage();
- start_new_message = true;
- blocks = 0;
- }
- }
-
- // finish any pending message
- if (!start_new_message)
- {
- sendReliableMessage();
- }
-
- mCacheDirty = true ;
- // LL_INFOS() << "KILLDEBUG Sent cache miss full " << full_count << " crc " << crc_count << LL_ENDL;
- LLViewerStatsRecorder::instance().requestCacheMissesEvent(mCacheMissList.size());
-
- mCacheMissList.clear();
-}
-
-void LLViewerRegion::dumpCache()
-{
- const S32 BINS = 4;
- S32 hit_bin[BINS];
- S32 change_bin[BINS];
-
- S32 i;
- for (i = 0; i < BINS; ++i)
- {
- hit_bin[i] = 0;
- change_bin[i] = 0;
- }
-
- LLVOCacheEntry *entry;
- for(LLVOCacheEntry::vocache_entry_map_t::iterator iter = mImpl->mCacheMap.begin(); iter != mImpl->mCacheMap.end(); ++iter)
- {
- entry = iter->second ;
-
- S32 hits = entry->getHitCount();
- S32 changes = entry->getCRCChangeCount();
-
- hits = llclamp(hits, 0, BINS-1);
- changes = llclamp(changes, 0, BINS-1);
-
- hit_bin[hits]++;
- change_bin[changes]++;
- }
-
- LL_INFOS() << "Count " << mImpl->mCacheMap.size() << LL_ENDL;
- for (i = 0; i < BINS; i++)
- {
- LL_INFOS() << "Hits " << i << " " << hit_bin[i] << LL_ENDL;
- }
- for (i = 0; i < BINS; i++)
- {
- LL_INFOS() << "Changes " << i << " " << change_bin[i] << LL_ENDL;
- }
- // TODO - add overrides cache too
-}
-
-void LLViewerRegion::unpackRegionHandshake()
-{
- LLMessageSystem *msg = gMessageSystem;
-
- U64 region_flags = 0;
- U64 region_protocols = 0;
- U8 sim_access;
- std::string sim_name;
- LLUUID sim_owner;
- bool is_estate_manager;
- F32 water_height;
- F32 billable_factor;
- LLUUID cache_id;
-
- msg->getU8 ("RegionInfo", "SimAccess", sim_access);
- msg->getString ("RegionInfo", "SimName", sim_name);
- msg->getUUID ("RegionInfo", "SimOwner", sim_owner);
- msg->getBOOL ("RegionInfo", "IsEstateManager", is_estate_manager);
- msg->getF32 ("RegionInfo", "WaterHeight", water_height);
- msg->getF32 ("RegionInfo", "BillableFactor", billable_factor);
- msg->getUUID ("RegionInfo", "CacheID", cache_id );
-
- if (msg->has(_PREHASH_RegionInfo4))
- {
- msg->getU64Fast(_PREHASH_RegionInfo4, _PREHASH_RegionFlagsExtended, region_flags);
- msg->getU64Fast(_PREHASH_RegionInfo4, _PREHASH_RegionProtocols, region_protocols);
- }
- else
- {
- U32 flags = 0;
- msg->getU32Fast(_PREHASH_RegionInfo, _PREHASH_RegionFlags, flags);
- region_flags = flags;
- }
-
- setRegionFlags(region_flags);
- setRegionProtocols(region_protocols);
- setSimAccess(sim_access);
- setRegionNameAndZone(sim_name);
- setOwner(sim_owner);
- setIsEstateManager(is_estate_manager);
- setWaterHeight(water_height);
- setBillableFactor(billable_factor);
- setCacheID(cache_id);
-
- LLUUID region_id;
- msg->getUUID("RegionInfo2", "RegionID", region_id);
- setRegionID(region_id);
-
- // Retrieve the CR-53 (Homestead/Land SKU) information
- S32 classID = 0;
- S32 cpuRatio = 0;
- std::string coloName;
- std::string productSKU;
- std::string productName;
-
- // the only reasonable way to decide if we actually have any data is to
- // check to see if any of these fields have positive sizes
- if (msg->getSize("RegionInfo3", "ColoName") > 0 ||
- msg->getSize("RegionInfo3", "ProductSKU") > 0 ||
- msg->getSize("RegionInfo3", "ProductName") > 0)
- {
- msg->getS32 ("RegionInfo3", "CPUClassID", classID);
- msg->getS32 ("RegionInfo3", "CPURatio", cpuRatio);
- msg->getString ("RegionInfo3", "ColoName", coloName);
- msg->getString ("RegionInfo3", "ProductSKU", productSKU);
- msg->getString ("RegionInfo3", "ProductName", productName);
-
- mClassID = classID;
- mCPURatio = cpuRatio;
- mColoName = coloName;
- mProductSKU = productSKU;
- mProductName = productName;
- }
-
- mCentralBakeVersion = region_protocols & 1; // was (S32)gSavedSettings.getBOOL("UseServerTextureBaking");
- LLVLComposition *compp = getComposition();
- if (compp)
- {
- LLUUID tmp_id;
-
- bool changed = false;
-
- // Get the 4 textures for land
- msg->getUUID("RegionInfo", "TerrainDetail0", tmp_id);
- changed |= (tmp_id != compp->getDetailTextureID(0));
- compp->setDetailTextureID(0, tmp_id);
-
- msg->getUUID("RegionInfo", "TerrainDetail1", tmp_id);
- changed |= (tmp_id != compp->getDetailTextureID(1));
- compp->setDetailTextureID(1, tmp_id);
-
- msg->getUUID("RegionInfo", "TerrainDetail2", tmp_id);
- changed |= (tmp_id != compp->getDetailTextureID(2));
- compp->setDetailTextureID(2, tmp_id);
-
- msg->getUUID("RegionInfo", "TerrainDetail3", tmp_id);
- changed |= (tmp_id != compp->getDetailTextureID(3));
- compp->setDetailTextureID(3, tmp_id);
-
- // Get the start altitude and range values for land textures
- F32 tmp_f32;
- msg->getF32("RegionInfo", "TerrainStartHeight00", tmp_f32);
- changed |= (tmp_f32 != compp->getStartHeight(0));
- compp->setStartHeight(0, tmp_f32);
-
- msg->getF32("RegionInfo", "TerrainStartHeight01", tmp_f32);
- changed |= (tmp_f32 != compp->getStartHeight(1));
- compp->setStartHeight(1, tmp_f32);
-
- msg->getF32("RegionInfo", "TerrainStartHeight10", tmp_f32);
- changed |= (tmp_f32 != compp->getStartHeight(2));
- compp->setStartHeight(2, tmp_f32);
-
- msg->getF32("RegionInfo", "TerrainStartHeight11", tmp_f32);
- changed |= (tmp_f32 != compp->getStartHeight(3));
- compp->setStartHeight(3, tmp_f32);
-
-
- msg->getF32("RegionInfo", "TerrainHeightRange00", tmp_f32);
- changed |= (tmp_f32 != compp->getHeightRange(0));
- compp->setHeightRange(0, tmp_f32);
-
- msg->getF32("RegionInfo", "TerrainHeightRange01", tmp_f32);
- changed |= (tmp_f32 != compp->getHeightRange(1));
- compp->setHeightRange(1, tmp_f32);
-
- msg->getF32("RegionInfo", "TerrainHeightRange10", tmp_f32);
- changed |= (tmp_f32 != compp->getHeightRange(2));
- compp->setHeightRange(2, tmp_f32);
-
- msg->getF32("RegionInfo", "TerrainHeightRange11", tmp_f32);
- changed |= (tmp_f32 != compp->getHeightRange(3));
- compp->setHeightRange(3, tmp_f32);
-
- // If this is an UPDATE (params already ready, we need to regenerate
- // all of our terrain stuff, by
- if (compp->getParamsReady())
- {
- // Update if the land changed
- if (changed)
- {
- getLand().dirtyAllPatches();
- }
- }
- else
- {
- compp->setParamsReady();
- }
- }
-
-
- // Now that we have the name, we can load the cache file
- // off disk.
- loadObjectCache();
-
- // After loading cache, signal that simulator can start
- // sending data.
- // TODO: Send all upstream viewer->sim handshake info here.
- LLHost host = msg->getSender();
- msg->newMessage("RegionHandshakeReply");
- msg->nextBlock("AgentData");
- msg->addUUID("AgentID", gAgent.getID());
- msg->addUUID("SessionID", gAgent.getSessionID());
- msg->nextBlock("RegionInfo");
-
- U32 flags = 0;
- flags |= REGION_HANDSHAKE_SUPPORTS_SELF_APPEARANCE;
-
- if(sVOCacheCullingEnabled)
- {
- flags |= 0x00000001; //set the bit 0 to be 1 to ask sim to send all cacheable objects.
- }
- if(mImpl->mCacheMap.empty())
- {
- flags |= 0x00000002; //set the bit 1 to be 1 to tell sim the cache file is empty, no need to send cache probes.
- }
- msg->addU32("Flags", flags );
- msg->sendReliable(host);
-
- mRegionTimer.reset(); //reset region timer.
-}
-
-// static
-void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
-{
- capabilityNames.append("AbuseCategories");
- capabilityNames.append("AcceptFriendship");
- capabilityNames.append("AcceptGroupInvite"); // ReadOfflineMsgs recieved messages only!!!
- capabilityNames.append("AgentPreferences");
- capabilityNames.append("AgentProfile");
- capabilityNames.append("AgentState");
- capabilityNames.append("AttachmentResources");
- capabilityNames.append("AvatarPickerSearch");
- capabilityNames.append("AvatarRenderInfo");
- capabilityNames.append("CharacterProperties");
- capabilityNames.append("ChatSessionRequest");
- capabilityNames.append("CopyInventoryFromNotecard");
- capabilityNames.append("CreateInventoryCategory");
- capabilityNames.append("DeclineFriendship");
- capabilityNames.append("DeclineGroupInvite"); // ReadOfflineMsgs recieved messages only!!!
- capabilityNames.append("DispatchRegionInfo");
- capabilityNames.append("DirectDelivery");
- capabilityNames.append("EnvironmentSettings");
- capabilityNames.append("EstateAccess");
- capabilityNames.append("EstateChangeInfo");
- capabilityNames.append("EventQueueGet");
- capabilityNames.append("ExtEnvironment");
-
- capabilityNames.append("FetchLib2");
- capabilityNames.append("FetchLibDescendents2");
- capabilityNames.append("FetchInventory2");
- capabilityNames.append("FetchInventoryDescendents2");
- capabilityNames.append("IncrementCOFVersion");
- AISAPI::getCapNames(capabilityNames);
-
- capabilityNames.append("InterestList");
-
- capabilityNames.append("InventoryThumbnailUpload");
- capabilityNames.append("GetDisplayNames");
- capabilityNames.append("GetExperiences");
- capabilityNames.append("AgentExperiences");
- capabilityNames.append("FindExperienceByName");
- capabilityNames.append("GetExperienceInfo");
- capabilityNames.append("GetAdminExperiences");
- capabilityNames.append("GetCreatorExperiences");
- capabilityNames.append("ExperiencePreferences");
- capabilityNames.append("GroupExperiences");
- capabilityNames.append("UpdateExperience");
- capabilityNames.append("IsExperienceAdmin");
- capabilityNames.append("IsExperienceContributor");
- capabilityNames.append("RegionExperiences");
- capabilityNames.append("ExperienceQuery");
- capabilityNames.append("GetMetadata");
- capabilityNames.append("GetObjectCost");
- capabilityNames.append("GetObjectPhysicsData");
- capabilityNames.append("GroupAPIv1");
- capabilityNames.append("GroupMemberData");
- capabilityNames.append("GroupProposalBallot");
- capabilityNames.append("HomeLocation");
- capabilityNames.append("LandResources");
- capabilityNames.append("LSLSyntax");
- capabilityNames.append("MapLayer");
- capabilityNames.append("MapLayerGod");
- capabilityNames.append("MeshUploadFlag");
- capabilityNames.append("ModifyMaterialParams");
- capabilityNames.append("NavMeshGenerationStatus");
- capabilityNames.append("NewFileAgentInventory");
- capabilityNames.append("ObjectAnimation");
- capabilityNames.append("ObjectMedia");
- capabilityNames.append("ObjectMediaNavigate");
- capabilityNames.append("ObjectNavMeshProperties");
- capabilityNames.append("ParcelPropertiesUpdate");
- capabilityNames.append("ParcelVoiceInfoRequest");
- capabilityNames.append("ProductInfoRequest");
- capabilityNames.append("ProvisionVoiceAccountRequest");
- capabilityNames.append("ReadOfflineMsgs"); // Requires to respond reliably: AcceptFriendship, AcceptGroupInvite, DeclineFriendship, DeclineGroupInvite
- capabilityNames.append("RegionObjects");
- capabilityNames.append("RemoteParcelRequest");
- capabilityNames.append("RenderMaterials");
- capabilityNames.append("RequestTextureDownload");
- capabilityNames.append("ResourceCostSelected");
- capabilityNames.append("RetrieveNavMeshSrc");
- capabilityNames.append("SearchStatRequest");
- capabilityNames.append("SearchStatTracking");
- capabilityNames.append("SendPostcard");
- capabilityNames.append("SendUserReport");
- capabilityNames.append("SendUserReportWithScreenshot");
- capabilityNames.append("ServerReleaseNotes");
- capabilityNames.append("SetDisplayName");
- capabilityNames.append("SimConsoleAsync");
- capabilityNames.append("SimulatorFeatures");
- capabilityNames.append("StartGroupProposal");
- capabilityNames.append("TerrainNavMeshProperties");
- capabilityNames.append("TextureStats");
- capabilityNames.append("UntrustedSimulatorMessage");
- capabilityNames.append("UpdateAgentInformation");
- capabilityNames.append("UpdateAgentLanguage");
- capabilityNames.append("UpdateAvatarAppearance");
- capabilityNames.append("UpdateGestureAgentInventory");
- capabilityNames.append("UpdateGestureTaskInventory");
- capabilityNames.append("UpdateNotecardAgentInventory");
- capabilityNames.append("UpdateNotecardTaskInventory");
- capabilityNames.append("UpdateScriptAgent");
- capabilityNames.append("UpdateScriptTask");
- capabilityNames.append("UpdateSettingsAgentInventory");
- capabilityNames.append("UpdateSettingsTaskInventory");
- capabilityNames.append("UploadAgentProfileImage");
- capabilityNames.append("UpdateMaterialAgentInventory");
- capabilityNames.append("UpdateMaterialTaskInventory");
- capabilityNames.append("UploadBakedTexture");
- capabilityNames.append("UserInfo");
- capabilityNames.append("ViewerAsset");
- capabilityNames.append("ViewerBenefits");
- capabilityNames.append("ViewerMetrics");
- capabilityNames.append("ViewerStartAuction");
- capabilityNames.append("ViewerStats");
-
- // Please add new capabilities alphabetically to reduce
- // merge conflicts.
-}
-
-void LLViewerRegion::setSeedCapability(const std::string& url)
-{
- if (getCapability("Seed") == url)
- {
- setCapabilityDebug("Seed", url);
- LL_WARNS("CrossingCaps") << "Received duplicate seed capability for " << getRegionID() << ", posting to seed " <<
- url << LL_ENDL;
-
- //Instead of just returning we build up a second set of seed caps and compare them
- //to the "original" seed cap received and determine why there is problem!
- std::string coroname =
- LLCoros::instance().launch("LLEnvironmentRequest::requestBaseCapabilitiesCompleteCoro",
- boost::bind(&LLViewerRegionImpl::requestBaseCapabilitiesCompleteCoro, getHandle()));
-
- // setSeedCapability can be called from other coros,
- // launch() acts like a suspend()
- // Make sure we are still good to do
- LLCoros::checkStop();
-
- return;
- }
-
- delete mImpl->mEventPoll;
- mImpl->mEventPoll = NULL;
-
- mImpl->mCapabilities.clear();
- setCapability("Seed", url);
-
- std::string coroname =
- LLCoros::instance().launch("LLViewerRegionImpl::requestBaseCapabilitiesCoro",
- boost::bind(&LLViewerRegionImpl::requestBaseCapabilitiesCoro, getHandle()));
-
- // setSeedCapability can be called from other coros,
- // launch() acts like a suspend()
- // Make sure we are still good to do
- LLCoros::checkStop();
-
- LL_INFOS("AppInit", "Capabilities") << "Launching " << coroname << " requesting seed capabilities from " << url << " for region " << getRegionID() << LL_ENDL;
-}
-
-S32 LLViewerRegion::getNumSeedCapRetries()
-{
- return mImpl->mSeedCapAttempts;
-}
-
-void LLViewerRegion::setCapability(const std::string& name, const std::string& url)
-{
- if(name == "EventQueueGet")
- {
- delete mImpl->mEventPoll;
- mImpl->mEventPoll = NULL;
- mImpl->mEventPoll = new LLEventPoll(url, getHost());
- }
- else if(name == "UntrustedSimulatorMessage")
- {
- mImpl->mHost.setUntrustedSimulatorCap(url);
- }
- else if (name == "SimulatorFeatures")
- {
- mImpl->mCapabilities["SimulatorFeatures"] = url;
- requestSimulatorFeatures();
- }
- else
- {
- mImpl->mCapabilities[name] = url;
- if(name == "ViewerAsset")
- {
- /*==============================================================*/
- // The following inserted lines are a hack for testing MAINT-7081,
- // which is why the indentation and formatting are left ugly.
- const char* VIEWERASSET = getenv("VIEWERASSET");
- if (VIEWERASSET)
- {
- mImpl->mCapabilities[name] = VIEWERASSET;
- mViewerAssetUrl = VIEWERASSET;
- }
- else
- /*==============================================================*/
- mViewerAssetUrl = url;
- }
- }
-}
-
-void LLViewerRegion::setCapabilityDebug(const std::string& name, const std::string& url)
-{
- // Continue to not add certain caps, as we do in setCapability. This is so they match up when we check them later.
- if ( ! ( name == "EventQueueGet" || name == "UntrustedSimulatorMessage" || name == "SimulatorFeatures" ) )
- {
- mImpl->mSecondCapabilitiesTracker[name] = url;
- if(name == "ViewerAsset")
- {
- /*==============================================================*/
- // The following inserted lines are a hack for testing MAINT-7081,
- // which is why the indentation and formatting are left ugly.
- const char* VIEWERASSET = getenv("VIEWERASSET");
- if (VIEWERASSET)
- {
- mImpl->mSecondCapabilitiesTracker[name] = VIEWERASSET;
- mViewerAssetUrl = VIEWERASSET;
- }
- else
- /*==============================================================*/
- mViewerAssetUrl = url;
- }
- }
-}
-
-std::string LLViewerRegion::getCapabilityDebug(const std::string& name) const
-{
- CapabilityMap::const_iterator iter = mImpl->mSecondCapabilitiesTracker.find(name);
- if (iter == mImpl->mSecondCapabilitiesTracker.end())
- {
- return "";
- }
-
- return iter->second;
-}
-
-
-bool LLViewerRegion::isSpecialCapabilityName(const std::string &name)
-{
- return name == "EventQueueGet" || name == "UntrustedSimulatorMessage";
-}
-
-std::string LLViewerRegion::getCapability(const std::string& name) const
-{
- if (!capabilitiesReceived() && (name!=std::string("Seed")) && (name!=std::string("ObjectMedia")))
- {
- LL_WARNS() << "getCapability called before caps received for " << name << LL_ENDL;
- }
-
- CapabilityMap::const_iterator iter = mImpl->mCapabilities.find(name);
- if(iter == mImpl->mCapabilities.end())
- {
- return "";
- }
-
- return iter->second;
-}
-
-bool LLViewerRegion::isCapabilityAvailable(const std::string& name) const
-{
- if (!capabilitiesReceived() && (name!=std::string("Seed")) && (name!=std::string("ObjectMedia")))
- {
- LL_WARNS() << "isCapabilityAvailable called before caps received for " << name << LL_ENDL;
- }
-
- CapabilityMap::const_iterator iter = mImpl->mCapabilities.find(name);
- if(iter == mImpl->mCapabilities.end())
- {
- return false;
- }
-
- return true;
-}
-
-bool LLViewerRegion::capabilitiesReceived() const
-{
- return mCapabilitiesState == CAPABILITIES_STATE_RECEIVED;
-}
-
-bool LLViewerRegion::capabilitiesError() const
-{
- return mCapabilitiesState == CAPABILITIES_STATE_ERROR;
-}
-
-void LLViewerRegion::setCapabilitiesReceived(bool received)
-{
- mCapabilitiesState = received ? CAPABILITIES_STATE_RECEIVED : CAPABILITIES_STATE_INIT;
-
- // Tell interested parties that we've received capabilities,
- // so that they can safely use getCapability().
- if (received)
- {
- mCapabilitiesReceivedSignal(getRegionID(), this);
-
- LLFloaterPermsDefault::sendInitialPerms();
-
- // This is a single-shot signal. Forget callbacks to save resources.
- mCapabilitiesReceivedSignal.disconnect_all_slots();
-
- // Set the region to the desired interest list mode
- setInterestListMode(gAgent.getInterestListMode());
- }
-}
-
-void LLViewerRegion::setCapabilitiesError()
-{
- mCapabilitiesState = CAPABILITIES_STATE_ERROR;
-}
-
-boost::signals2::connection LLViewerRegion::setCapabilitiesReceivedCallback(const caps_received_signal_t::slot_type& cb)
-{
- return mCapabilitiesReceivedSignal.connect(cb);
-}
-
-void LLViewerRegion::logActiveCapabilities() const
-{
- log_capabilities(mImpl->mCapabilities);
-}
-
-
-bool LLViewerRegion::requestPostCapability(const std::string &capName, LLSD &postData, httpCallback_t cbSuccess, httpCallback_t cbFailure)
-{
- std::string url = getCapability(capName);
-
- if (url.empty())
- {
- LL_WARNS("Region") << "Could not retrieve region " << getRegionID()
- << " POST capability \"" << capName << "\"" << LL_ENDL;
- return false;
- }
-
- LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpPost(url, gAgent.getAgentPolicy(), postData, cbSuccess, cbFailure);
- return true;
-}
-
-bool LLViewerRegion::requestGetCapability(const std::string &capName, httpCallback_t cbSuccess, httpCallback_t cbFailure)
-{
- std::string url;
-
- url = getCapability(capName);
-
- if (url.empty())
- {
- LL_WARNS("Region") << "Could not retrieve region " << getRegionID()
- << " GET capability \"" << capName << "\"" << LL_ENDL;
- return false;
- }
-
- LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpGet(url, gAgent.getAgentPolicy(), cbSuccess, cbFailure);
- return true;
-}
-
-bool LLViewerRegion::requestDelCapability(const std::string &capName, httpCallback_t cbSuccess, httpCallback_t cbFailure)
-{
- std::string url;
-
- url = getCapability(capName);
-
- if (url.empty())
- {
- LL_WARNS("Region") << "Could not retrieve region " << getRegionID() << " DEL capability \"" << capName << "\"" << LL_ENDL;
- return false;
- }
-
- LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpDel(url, gAgent.getAgentPolicy(), cbSuccess, cbFailure);
- return true;
-}
-
-void LLViewerRegion::setInterestListMode(const std::string &new_mode)
-{
- if (new_mode != mInterestListMode)
- {
- mInterestListMode = new_mode;
-
- if (mInterestListMode != IL_MODE_DEFAULT && mInterestListMode != IL_MODE_360)
- {
- LL_WARNS("360Capture") << "Region " << getRegionID() << " setInterestListMode() invalid interest list mode: "
- << mInterestListMode << ", setting to default" << LL_ENDL;
- mInterestListMode = IL_MODE_DEFAULT;
- }
-
- LLSD body;
- body["mode"] = mInterestListMode;
- if (requestPostCapability("InterestList", body,
- [](const LLSD &response) {
- LL_DEBUGS("360Capture") << "InterestList capability responded: \n"
- << ll_pretty_print_sd(response) << LL_ENDL;
- }))
- {
- LL_DEBUGS("360Capture") << "Region " << getRegionID()
- << " Successfully posted an InterestList capability request with payload: \n"
- << ll_pretty_print_sd(body) << LL_ENDL;
- }
- else
- {
- LL_WARNS("360Capture") << "Region " << getRegionID()
- << " Unable to post an InterestList capability request with payload: \n"
- << ll_pretty_print_sd(body) << LL_ENDL;
- }
- }
- else
- {
- LL_DEBUGS("360Capture") << "Region " << getRegionID() << "No change, skipping Interest List mode POST to "
- << new_mode << " mode" << LL_ENDL;
- }
-}
-
-
-void LLViewerRegion::resetInterestList()
-{
- if (requestDelCapability("InterestList", [](const LLSD &response) {
- LL_DEBUGS("360Capture") << "InterestList capability DEL responded: \n" << ll_pretty_print_sd(response) << LL_ENDL;
- }))
- {
- LL_DEBUGS("360Capture") << "Region " << getRegionID() << " Successfully reset InterestList capability" << LL_ENDL;
- }
- else
- {
- LL_WARNS("360Capture") << "Region " << getRegionID() << " Unable to DEL InterestList capability request" << LL_ENDL;
- }
-}
-
-
-LLSpatialPartition *LLViewerRegion::getSpatialPartition(U32 type)
-{
- if (type < mImpl->mObjectPartition.size() && type < PARTITION_VO_CACHE)
- {
- return (LLSpatialPartition*)mImpl->mObjectPartition[type];
- }
- return NULL;
-}
-
-LLVOCachePartition* LLViewerRegion::getVOCachePartition()
-{
- if(PARTITION_VO_CACHE < mImpl->mObjectPartition.size())
- {
- return (LLVOCachePartition*)mImpl->mObjectPartition[PARTITION_VO_CACHE];
- }
- return NULL;
-}
-
-// the viewer can not yet distinquish between normal- and estate-owned objects
-// so we collapse these two bits and enable the UI if either are set
-const U64 ALLOW_RETURN_ENCROACHING_OBJECT = REGION_FLAGS_ALLOW_RETURN_ENCROACHING_OBJECT
- | REGION_FLAGS_ALLOW_RETURN_ENCROACHING_ESTATE_OBJECT;
-
-bool LLViewerRegion::objectIsReturnable(const LLVector3& pos, const std::vector<LLBBox>& boxes) const
-{
- return (mParcelOverlay != NULL)
- && (mParcelOverlay->isOwnedSelf(pos)
- || mParcelOverlay->isOwnedGroup(pos)
- || (getRegionFlag(ALLOW_RETURN_ENCROACHING_OBJECT)
- && mParcelOverlay->encroachesOwned(boxes)) );
-}
-
-bool LLViewerRegion::childrenObjectReturnable( const std::vector<LLBBox>& boxes ) const
-{
- bool result = false;
- result = ( mParcelOverlay && mParcelOverlay->encroachesOnUnowned( boxes ) ) ? 1 : 0;
- return result;
-}
-
-bool LLViewerRegion::objectsCrossParcel(const std::vector<LLBBox>& boxes) const
-{
- return mParcelOverlay && mParcelOverlay->encroachesOnNearbyParcel(boxes);
-}
-
-void LLViewerRegion::getNeighboringRegions( std::vector<LLViewerRegion*>& uniqueRegions )
-{
- mImpl->mLandp->getNeighboringRegions( uniqueRegions );
-}
-void LLViewerRegion::getNeighboringRegionsStatus( std::vector<S32>& regions )
-{
- mImpl->mLandp->getNeighboringRegionsStatus( regions );
-}
-void LLViewerRegion::showReleaseNotes()
-{
- std::string url = this->getCapability("ServerReleaseNotes");
-
- if (url.empty()) {
- // HACK haven't received the capability yet, we'll wait until
- // it arives.
- mReleaseNotesRequested = true;
- return;
- }
-
- LLWeb::loadURL(url);
- mReleaseNotesRequested = false;
-}
-
-std::string LLViewerRegion::getDescription() const
-{
- return stringize(*this);
-}
-
-bool LLViewerRegion::meshUploadEnabled() const
-{
- return (mSimulatorFeatures.has("MeshUploadEnabled") &&
- mSimulatorFeatures["MeshUploadEnabled"].asBoolean());
-}
-
-bool LLViewerRegion::bakesOnMeshEnabled() const
-{
- return (mSimulatorFeatures.has("BakesOnMeshEnabled") &&
- mSimulatorFeatures["BakesOnMeshEnabled"].asBoolean());
-}
-
-bool LLViewerRegion::meshRezEnabled() const
-{
- return (mSimulatorFeatures.has("MeshRezEnabled") &&
- mSimulatorFeatures["MeshRezEnabled"].asBoolean());
-}
-
-bool LLViewerRegion::dynamicPathfindingEnabled() const
-{
- return ( mSimulatorFeatures.has("DynamicPathfindingEnabled") &&
- mSimulatorFeatures["DynamicPathfindingEnabled"].asBoolean());
-}
-
-bool LLViewerRegion::avatarHoverHeightEnabled() const
-{
- return ( mSimulatorFeatures.has("AvatarHoverHeightEnabled") &&
- mSimulatorFeatures["AvatarHoverHeightEnabled"].asBoolean());
-}
-/* Static Functions */
-
-void log_capabilities(const CapabilityMap &capmap)
-{
- S32 count = 0;
- CapabilityMap::const_iterator iter;
- for (iter = capmap.begin(); iter != capmap.end(); ++iter, ++count)
- {
- if (!iter->second.empty())
- {
- LL_INFOS() << "log_capabilities: " << iter->first << " URL is " << iter->second << LL_ENDL;
- }
- }
- LL_INFOS() << "log_capabilities: Dumped " << count << " entries." << LL_ENDL;
-}
-void LLViewerRegion::resetMaterialsCapThrottle()
-{
- F32 requests_per_sec = 1.0f; // original default;
- if ( mSimulatorFeatures.has("RenderMaterialsCapability")
- && mSimulatorFeatures["RenderMaterialsCapability"].isReal() )
- {
- requests_per_sec = mSimulatorFeatures["RenderMaterialsCapability"].asReal();
- if ( requests_per_sec == 0.0f )
- {
- requests_per_sec = 1.0f;
- LL_WARNS("Materials")
- << "region '" << getName()
- << "' returned zero for RenderMaterialsCapability; using default "
- << requests_per_sec << " per second"
- << LL_ENDL;
- }
- LL_DEBUGS("Materials") << "region '" << getName()
- << "' RenderMaterialsCapability " << requests_per_sec
- << LL_ENDL;
- }
- else
- {
- LL_DEBUGS("Materials")
- << "region '" << getName()
- << "' did not return RenderMaterialsCapability, using default "
- << requests_per_sec << " per second"
- << LL_ENDL;
- }
-
- mMaterialsCapThrottleTimer.resetWithExpiry( 1.0f / requests_per_sec );
-}
-
-U32 LLViewerRegion::getMaxMaterialsPerTransaction() const
-{
- U32 max_entries = 50; // original hard coded default
- if ( mSimulatorFeatures.has( "MaxMaterialsPerTransaction" )
- && mSimulatorFeatures[ "MaxMaterialsPerTransaction" ].isInteger())
- {
- max_entries = mSimulatorFeatures[ "MaxMaterialsPerTransaction" ].asInteger();
- }
- return max_entries;
-}
-
-std::string LLViewerRegion::getSimHostName()
-{
- if (mSimulatorFeaturesReceived)
- {
- return mSimulatorFeatures.has("HostName") ? mSimulatorFeatures["HostName"].asString() : getHost().getHostName();
- }
- return std::string("...");
-}
-
-void LLViewerRegion::applyCacheMiscExtras(LLViewerObject* obj)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY;
- llassert(obj);
-
- U32 local_id = obj->getLocalID();
- auto iter = mImpl->mGLTFOverridesLLSD.find(local_id);
- if (iter != mImpl->mGLTFOverridesLLSD.end())
- {
- llassert(iter->second.mGLTFMaterial.size() == iter->second.mSides.size());
-
- for (auto& side : iter->second.mGLTFMaterial)
- {
- obj->setTEGLTFMaterialOverride(side.first, side.second);
- }
- }
-}
-
+/** + * @file llviewerregion.cpp + * @brief Implementation of the LLViewerRegion class. + * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010-2013, 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 "llviewerregion.h" + +// linden libraries +#include "indra_constants.h" +#include "llaisapi.h" +#include "llavatarnamecache.h" // name lookup cap url +#include "llfloaterreg.h" +#include "llmath.h" +#include "llregionflags.h" +#include "llregionhandle.h" +#include "llsurface.h" +#include "message.h" +//#include "vmath.h" +#include "v3math.h" +#include "v4math.h" + +#include "llagent.h" +#include "llagentcamera.h" +#include "llappviewer.h" +#include "llavatarrenderinfoaccountant.h" +#include "llcallingcard.h" +#include "llcommandhandler.h" +#include "lldir.h" +#include "lleventpoll.h" +#include "llfloatergodtools.h" +#include "llfloaterreporter.h" +#include "llfloaterregioninfo.h" +#include "llgltfmateriallist.h" +#include "llhttpnode.h" +#include "llregioninfomodel.h" +#include "llsdutil.h" +#include "llstartup.h" +#include "lltrans.h" +#include "llurldispatcher.h" +#include "llviewerobjectlist.h" +#include "llviewerparceloverlay.h" +#include "llviewerstatsrecorder.h" +#include "llvlmanager.h" +#include "llvlcomposition.h" +#include "llvoavatarself.h" +#include "llvocache.h" +#include "llworld.h" +#include "llspatialpartition.h" +#include "stringize.h" +#include "llviewercontrol.h" +#include "llsdserialize.h" +#include "llfloaterperms.h" +#include "llvieweroctree.h" +#include "llviewerdisplay.h" +#include "llviewerwindow.h" +#include "llprogressview.h" +#include "llcoros.h" +#include "lleventcoro.h" +#include "llcorehttputil.h" +#include "llcallstack.h" +#include "llsettingsdaycycle.h" + +#include <boost/regex.hpp> + +#ifdef LL_WINDOWS + #pragma warning(disable:4355) +#endif + +// When we receive a base grant of capabilities that has a different number of +// capabilities than the original base grant received for the region, print +// out the two lists of capabilities for analysis. +//#define DEBUG_CAPS_GRANTS + +// The server only keeps our pending agent info for 60 seconds. +// We want to allow for seed cap retry, but its not useful after that 60 seconds. +// Even though we gave up on login, keep trying for caps after we are logged in: +const S32 MAX_CAP_REQUEST_ATTEMPTS = 30; +const U32 DEFAULT_MAX_REGION_WIDE_PRIM_COUNT = 15000; + +bool LLViewerRegion::sVOCacheCullingEnabled = false; +S32 LLViewerRegion::sLastCameraUpdated = 0; +S32 LLViewerRegion::sNewObjectCreationThrottle = -1; +LLViewerRegion::vocache_entry_map_t LLViewerRegion::sRegionCacheCleanup; + +typedef std::map<std::string, std::string> CapabilityMap; + +static void log_capabilities(const CapabilityMap &capmap); + +namespace +{ + +void newRegionEntry(LLViewerRegion& region) +{ + LL_INFOS("LLViewerRegion") << "Entering region [" << region.getName() << "]" << LL_ENDL; + gDebugInfo["CurrentRegion"] = region.getName(); + LLAppViewer::instance()->writeDebugInfo(); +} + +} // anonymous namespace + +// support for secondlife:///app/region/{REGION} SLapps +// N.B. this is defined to work exactly like the classic secondlife://{REGION} +// However, the later syntax cannot support spaces in the region name because +// spaces (and %20 chars) are illegal in the hostname of an http URL. Some +// browsers let you get away with this, but some do not (such as Qt's Webkit). +// Hence we introduced the newer secondlife:///app/region alternative. +class LLRegionHandler : public LLCommandHandler +{ +public: + // requests will be throttled from a non-trusted browser + LLRegionHandler() : LLCommandHandler("region", UNTRUSTED_THROTTLE) {} + + bool handle(const LLSD& params, const LLSD& query_map, const std::string& grid, LLMediaCtrl* web) + { + // make sure that we at least have a region name + int num_params = params.size(); + if (num_params < 1) + { + return false; + } + + // build a secondlife://{PLACE} SLurl from this SLapp + std::string url = "secondlife://"; + if (!grid.empty()) + { + url += grid + "/secondlife/"; + } + boost::regex name_rx("[A-Za-z0-9()_%]+"); + boost::regex coord_rx("[0-9]+"); + for (int i = 0; i < num_params; i++) + { + if (i > 0) + { + url += "/"; + } + if (!boost::regex_match(params[i].asString(), i > 0 ? coord_rx : name_rx)) + { + return false; + } + + url += params[i].asString(); + } + + // Process the SLapp as if it was a secondlife://{PLACE} SLurl + LLURLDispatcher::dispatch(url, LLCommandHandler::NAV_TYPE_CLICKED, web, true); + return true; + } + +}; +LLRegionHandler gRegionHandler; + + +class LLViewerRegionImpl +{ +public: + LLViewerRegionImpl(LLViewerRegion * region, LLHost const & host): + mHost(host), + mCompositionp(NULL), + mEventPoll(NULL), + mSeedCapMaxAttempts(MAX_CAP_REQUEST_ATTEMPTS), + mSeedCapAttempts(0), + mHttpResponderID(0), + mLastCameraUpdate(0), + mLastCameraOrigin(), + mVOCachePartition(NULL), + mLandp(NULL) + {} + + static void buildCapabilityNames(LLSD& capabilityNames); + + // The surfaces and other layers + LLSurface* mLandp; + + // Region geometry data + LLVector3d mOriginGlobal; // Location of southwest corner of region (meters) + LLVector3d mCenterGlobal; // Location of center in world space (meters) + LLHost mHost; + + // The unique ID for this region. + LLUUID mRegionID; + + // region/estate owner - usually null. + LLUUID mOwnerID; + + // Network statistics for the region's circuit... + LLTimer mLastNetUpdate; + + // Misc + LLVLComposition *mCompositionp; // Composition layer for the surface + + LLVOCacheEntry::vocache_entry_map_t mCacheMap; //all cached entries + LLVOCacheEntry::vocache_entry_set_t mActiveSet; //all active entries; + LLVOCacheEntry::vocache_entry_set_t mWaitingSet; //entries waiting for LLDrawable to be generated. + std::set< LLPointer<LLViewerOctreeGroup> > mVisibleGroups; //visible groupa + LLVOCachePartition* mVOCachePartition; + LLVOCacheEntry::vocache_entry_set_t mVisibleEntries; //must-be-created visible entries wait for objects creation. + LLVOCacheEntry::vocache_entry_priority_list_t mWaitingList; //transient list storing sorted visible entries waiting for object creation. + std::set<U32> mNonCacheableCreatedList; //list of local ids of all non-cacheable objects + LLVOCacheEntry::vocache_gltf_overrides_map_t mGLTFOverridesLLSD; // for materials + + // time? + // LRU info? + + // Cache ID is unique per-region, across renames, moving locations, + // etc. + LLUUID mCacheID; + + CapabilityMap mCapabilities; + CapabilityMap mSecondCapabilitiesTracker; + + LLEventPoll* mEventPoll; + + S32 mSeedCapMaxAttempts; + S32 mSeedCapAttempts; + + S32 mHttpResponderID; + + //spatial partitions for objects in this region + std::vector<LLViewerOctreePartition*> mObjectPartition; + + LLVector3 mLastCameraOrigin; + U32 mLastCameraUpdate; + + static void requestBaseCapabilitiesCoro(U64 regionHandle); + static void requestBaseCapabilitiesCompleteCoro(U64 regionHandle); + static void requestSimulatorFeatureCoro(std::string url, U64 regionHandle); +}; + +void LLViewerRegionImpl::requestBaseCapabilitiesCoro(U64 regionHandle) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("BaseCapabilitiesRequest", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + + LLSD result; + LLViewerRegion *regionp = NULL; + + // This loop is used for retrying a capabilities request. + do + { + if (STATE_WORLD_INIT > LLStartUp::getStartupState()) + { + LL_INFOS("AppInit", "Capabilities") << "Aborting capabilities request, reason: returned to login screen" << LL_ENDL; + return; + } + + if (!LLWorld::instanceExists()) + { + LL_WARNS("AppInit", "Capabilities") << "Attempting to get capabilities, but world no longer exists!" << LL_ENDL; + return; + } + + regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle); + if (!regionp) //region was removed + { + LL_WARNS("AppInit", "Capabilities") << "Attempting to get capabilities for region that no longer exists!" << LL_ENDL; + return; // this error condition is not recoverable. + } + LLViewerRegionImpl* impl = regionp->getRegionImplNC(); + LL_DEBUGS("AppInit", "Capabilities") << "requesting seed caps for handle " << regionHandle + << " name " << regionp->getName() << LL_ENDL; + + std::string url = regionp->getCapability("Seed"); + if (url.empty()) + { + LL_WARNS("AppInit", "Capabilities") << "Failed to get seed capabilities, and can not determine url!" << LL_ENDL; + regionp->setCapabilitiesError(); + return; // this error condition is not recoverable. + } + + // record that we just entered a new region + newRegionEntry(*regionp); + + if (impl->mSeedCapAttempts > impl->mSeedCapMaxAttempts) + { + // *TODO: Give a user pop-up about this error? + LL_WARNS("AppInit", "Capabilities") << "Failed to get seed capabilities from '" << url << "' after " << impl->mSeedCapAttempts << " attempts. Giving up!" << LL_ENDL; + return; // this error condition is not recoverable. + } + + S32 id = ++(impl->mHttpResponderID); + + LLSD capabilityNames = LLSD::emptyArray(); + impl->buildCapabilityNames(capabilityNames); + + LL_INFOS("AppInit", "Capabilities") << "Requesting seed from " << url + << " region name " << regionp->getName() + << " region id " << regionp->getRegionID() + << " handle " << regionp->getHandle() + << " (attempt #" << impl->mSeedCapAttempts + 1 << ")" << LL_ENDL; + LL_DEBUGS("AppInit", "Capabilities") << "Capabilities requested: " << capabilityNames << LL_ENDL; + + regionp = NULL; + impl = NULL; + result = httpAdapter->postAndSuspend(httpRequest, url, capabilityNames); + + if (STATE_WORLD_INIT > LLStartUp::getStartupState()) + { + LL_INFOS("AppInit", "Capabilities") << "Aborting capabilities request, reason: returned to login screen" << LL_ENDL; + return; + } + + if (LLApp::isExiting() || gDisconnected) + { + LL_DEBUGS("AppInit", "Capabilities") << "Shutting down" << LL_ENDL; + return; + } + + if (!LLWorld::instanceExists()) + { + LL_WARNS("AppInit", "Capabilities") << "Received capabilities, but world no longer exists!" << LL_ENDL; + return; + } + + regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle); + if (!regionp) //region was removed + { + LL_WARNS("AppInit", "Capabilities") << "Received capabilities for region that no longer exists!" << LL_ENDL; + return; // this error condition is not recoverable. + } + + impl = regionp->getRegionImplNC(); + + ++(impl->mSeedCapAttempts); + + if (!result.isMap() || result.has("error")) + { + LL_WARNS("AppInit", "Capabilities") << "Malformed response" << LL_ENDL; + // setup for retry. + continue; + } + + LLSD httpResults = result["http_result"]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + if (!status) + { + LL_WARNS("AppInit", "Capabilities") << "HttpStatus error " << LL_ENDL; + // setup for retry. + continue; + } + + // remove the http_result from the llsd + result.erase("http_result"); + + if (id != impl->mHttpResponderID) // region is no longer referring to this request + { + LL_WARNS("AppInit", "Capabilities") << "Received results for a stale capabilities request!" << LL_ENDL; + // setup for retry. + continue; + } + + LLSD::map_const_iterator iter; + for (iter = result.beginMap(); iter != result.endMap(); ++iter) + { + regionp->setCapability(iter->first, iter->second); + + LL_DEBUGS("AppInit", "Capabilities") + << "Capability '" << iter->first << "' is '" << iter->second << "'" << LL_ENDL; + } + +#if 0 + log_capabilities(mCapabilities); +#endif + + LL_DEBUGS("AppInit", "Capabilities", "Teleport") << "received caps for handle " << regionHandle + << " region name " << regionp->getName() << LL_ENDL; + regionp->setCapabilitiesReceived(true); + + break; + } + while (true); + + if (regionp && regionp->isCapabilityAvailable("ServerReleaseNotes") && + regionp->getReleaseNotesRequested()) + { // *HACK: we're waiting for the ServerReleaseNotes + regionp->showReleaseNotes(); + } +} + + +void LLViewerRegionImpl::requestBaseCapabilitiesCompleteCoro(U64 regionHandle) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("BaseCapabilitiesRequest", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + + LLSD result; + LLViewerRegion *regionp = NULL; + + // This loop is used for retrying a capabilities request. + do + { + LLWorld *world_inst = LLWorld::getInstance(); // Not a singleton! + if (!world_inst) + { + LL_WARNS("AppInit", "Capabilities") << "Attempting to get capabilities, but world no longer exists!" << LL_ENDL; + return; + } + + regionp = world_inst->getRegionFromHandle(regionHandle); + if (!regionp) //region was removed + { + LL_WARNS("AppInit", "Capabilities") << "Attempting to get capabilities for region that no longer exists!" << LL_ENDL; + break; // this error condition is not recoverable. + } + + std::string url = regionp->getCapabilityDebug("Seed"); + if (url.empty()) + { + LL_WARNS("AppInit", "Capabilities") << "Failed to get seed capabilities, and can not determine url!" << LL_ENDL; + if (regionp->getCapability("Seed").empty()) + { + // initial attempt failed to get this cap as well + regionp->setCapabilitiesError(); + } + break; // this error condition is not recoverable. + } + + // record that we just entered a new region + newRegionEntry(*regionp); + + LLSD capabilityNames = LLSD::emptyArray(); + buildCapabilityNames(capabilityNames); + + LL_INFOS("AppInit", "Capabilities") << "Requesting second Seed from " << url << " for region " << regionp->getRegionID() << LL_ENDL; + + regionp = NULL; + world_inst = NULL; + result = httpAdapter->postAndSuspend(httpRequest, url, capabilityNames); + + LLSD httpResults = result["http_result"]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + if (!status) + { + LL_WARNS("AppInit", "Capabilities") << "HttpStatus error " << LL_ENDL; + break; // no retry + } + + if (LLApp::isExiting() || gDisconnected) + { + break; + } + + world_inst = LLWorld::getInstance(); + if (!world_inst) + { + LL_WARNS("AppInit", "Capabilities") << "Received capabilities, but world no longer exists!" << LL_ENDL; + return; + } + + regionp = world_inst->getRegionFromHandle(regionHandle); + if (!regionp) //region was removed + { + LL_WARNS("AppInit", "Capabilities") << "Received capabilities for region that no longer exists!" << LL_ENDL; + break; // this error condition is not recoverable. + } + LLViewerRegionImpl* impl = regionp->getRegionImplNC(); + + // remove the http_result from the llsd + result.erase("http_result"); + + LLSD::map_const_iterator iter; + for (iter = result.beginMap(); iter != result.endMap(); ++iter) + { + regionp->setCapabilityDebug(iter->first, iter->second); + //LL_INFOS()<<"BaseCapabilitiesCompleteTracker New Caps "<<iter->first<<" "<< iter->second<<LL_ENDL; + } + +#if 0 + log_capabilities(impl->mCapabilities); +#endif + + if (impl->mCapabilities.size() != impl->mSecondCapabilitiesTracker.size()) + { + LL_WARNS("AppInit", "Capabilities") + << "Sim sent duplicate base caps that differ in size from what we initially received - most likely content. " + << "mCapabilities == " << impl->mCapabilities.size() + << " mSecondCapabilitiesTracker == " << impl->mSecondCapabilitiesTracker.size() + << LL_ENDL; +#ifdef DEBUG_CAPS_GRANTS + LL_WARNS("AppInit", "Capabilities") + << "Initial Base capabilities: " << LL_ENDL; + + log_capabilities(impl->mCapabilities); + + LL_WARNS("AppInit", "Capabilities") + << "Latest base capabilities: " << LL_ENDL; + + log_capabilities(impl->mSecondCapabilitiesTracker); + +#endif + + if (impl->mSecondCapabilitiesTracker.size() > impl->mCapabilities.size()) + { + // *HACK Since we were granted more base capabilities in this grant request than the initial, replace + // the old with the new. This shouldn't happen i.e. we should always get the same capabilities from a + // sim. The simulator fix from SH-3895 should prevent it from happening, at least in the case of the + // inventory api capability grants. + + // Need to clear a std::map before copying into it because old keys take precedence. + impl->mCapabilities.clear(); + impl->mCapabilities = impl->mSecondCapabilitiesTracker; + } + } + else + { + LL_DEBUGS("CrossingCaps") << "Sim sent multiple base cap grants with matching sizes." << LL_ENDL; + } + impl->mSecondCapabilitiesTracker.clear(); + } + while (false); +} + +void LLViewerRegionImpl::requestSimulatorFeatureCoro(std::string url, U64 regionHandle) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("BaseCapabilitiesRequest", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + + LLViewerRegion *regionp = NULL; + S32 attemptNumber = 0; + // This loop is used for retrying a capabilities request. + do + { + ++attemptNumber; + + if (attemptNumber > MAX_CAP_REQUEST_ATTEMPTS) + { + LL_WARNS("AppInit", "SimulatorFeatures") << "Retries count exceeded attempting to get Simulator feature from " + << url << LL_ENDL; + break; + } + + LLWorld *world_inst = LLWorld::getInstance(); // Not a singleton! + if (!world_inst) + { + LL_WARNS("AppInit", "Capabilities") << "Attempting to request Sim Feature, but world no longer exists!" << LL_ENDL; + return; + } + + regionp = world_inst->getRegionFromHandle(regionHandle); + if (!regionp) //region was removed + { + LL_WARNS("AppInit", "SimulatorFeatures") << "Attempting to request Sim Feature for region that no longer exists!" << LL_ENDL; + break; // this error condition is not recoverable. + } + + regionp = NULL; + world_inst = NULL; + LLSD result = httpAdapter->getAndSuspend(httpRequest, url); + + LLSD httpResults = result["http_result"]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + if (!status) + { + LL_WARNS("AppInit", "SimulatorFeatures") << "HttpStatus error retrying" << LL_ENDL; + continue; + } + + if (LLApp::isExiting() || gDisconnected) + { + break; + } + + // remove the http_result from the llsd + result.erase("http_result"); + + world_inst = LLWorld::getInstance(); + if (!world_inst) + { + LL_WARNS("AppInit", "Capabilities") << "Attempting to request Sim Feature, but world no longer exists!" << LL_ENDL; + return; + } + + regionp = world_inst->getRegionFromHandle(regionHandle); + if (!regionp) //region was removed + { + LL_WARNS("AppInit", "SimulatorFeatures") << "Attempting to set Sim Feature for region that no longer exists!" << LL_ENDL; + break; // this error condition is not recoverable. + } + + regionp->setSimulatorFeatures(result); + + break; + } + while (true); + +} + +LLViewerRegion::LLViewerRegion(const U64 &handle, + const LLHost &host, + const U32 grids_per_region_edge, + const U32 grids_per_patch_edge, + const F32 region_width_meters) +: mImpl(new LLViewerRegionImpl(this, host)), + mHandle(handle), + mTimeDilation(1.0f), + mName(""), + mZoning(""), + mIsEstateManager(false), + mRegionFlags( REGION_FLAGS_DEFAULT ), + mRegionProtocols( 0 ), + mSimAccess( SIM_ACCESS_MIN ), + mBillableFactor(1.0), + mMaxTasks(DEFAULT_MAX_REGION_WIDE_PRIM_COUNT), + mCentralBakeVersion(1), + mClassID(0), + mCPURatio(0), + mColoName("unknown"), + mProductSKU("unknown"), + mProductName("unknown"), + mViewerAssetUrl(""), + mCacheLoaded(false), + mCacheDirty(false), + mReleaseNotesRequested(false), + mCapabilitiesState(CAPABILITIES_STATE_INIT), + mSimulatorFeaturesReceived(false), + mBitsReceived(0.f), + mPacketsReceived(0.f), + mDead(false), + mLastVisitedEntry(NULL), + mInvisibilityCheckHistory(-1), + mPaused(false), + mRegionCacheHitCount(0), + mRegionCacheMissCount(0), + mInterestListMode(IL_MODE_DEFAULT) +{ + mWidth = region_width_meters; + mImpl->mOriginGlobal = from_region_handle(handle); + updateRenderMatrix(); + + mImpl->mLandp = new LLSurface('l', NULL); + + // Create the composition layer for the surface + mImpl->mCompositionp = + new LLVLComposition(mImpl->mLandp, + grids_per_region_edge, + region_width_meters / grids_per_region_edge); + mImpl->mCompositionp->setSurface(mImpl->mLandp); + + // Create the surfaces + mImpl->mLandp->setRegion(this); + mImpl->mLandp->create(grids_per_region_edge, + grids_per_patch_edge, + mImpl->mOriginGlobal, + mWidth); + + mParcelOverlay = new LLViewerParcelOverlay(this, region_width_meters); + + setOriginGlobal(from_region_handle(handle)); + calculateCenterGlobal(); + + // Create the object lists + initStats(); + + //create object partitions + //MUST MATCH declaration of eObjectPartitions + mImpl->mObjectPartition.push_back(new LLHUDPartition(this)); //PARTITION_HUD + mImpl->mObjectPartition.push_back(new LLTerrainPartition(this)); //PARTITION_TERRAIN + mImpl->mObjectPartition.push_back(new LLVoidWaterPartition(this)); //PARTITION_VOIDWATER + mImpl->mObjectPartition.push_back(new LLWaterPartition(this)); //PARTITION_WATER + mImpl->mObjectPartition.push_back(new LLTreePartition(this)); //PARTITION_TREE + mImpl->mObjectPartition.push_back(new LLParticlePartition(this)); //PARTITION_PARTICLE + mImpl->mObjectPartition.push_back(new LLGrassPartition(this)); //PARTITION_GRASS + mImpl->mObjectPartition.push_back(new LLVolumePartition(this)); //PARTITION_VOLUME + mImpl->mObjectPartition.push_back(new LLBridgePartition(this)); //PARTITION_BRIDGE + mImpl->mObjectPartition.push_back(new LLAvatarPartition(this)); //PARTITION_AVATAR + mImpl->mObjectPartition.push_back(new LLControlAVPartition(this)); //PARTITION_CONTROL_AV + mImpl->mObjectPartition.push_back(new LLHUDParticlePartition(this));//PARTITION_HUD_PARTICLE + mImpl->mObjectPartition.push_back(new LLVOCachePartition(this)); //PARTITION_VO_CACHE + mImpl->mObjectPartition.push_back(NULL); //PARTITION_NONE + mImpl->mVOCachePartition = getVOCachePartition(); + + setCapabilitiesReceivedCallback(boost::bind(&LLAvatarRenderInfoAccountant::scanNewRegion, _1)); +} + + +void LLViewerRegion::initStats() +{ + mImpl->mLastNetUpdate.reset(); + mPacketsIn = 0; + mBitsIn = (U32Bits)0; + mLastBitsIn = (U32Bits)0; + mLastPacketsIn = 0; + mPacketsOut = 0; + mLastPacketsOut = 0; + mPacketsLost = 0; + mLastPacketsLost = 0; + mPingDelay = (U32Seconds)0; + mAlive = false; // can become false if circuit disconnects +} + +static LLTrace::BlockTimerStatHandle FTM_CLEANUP_REGION_OBJECTS("Cleanup Region Objects"); +static LLTrace::BlockTimerStatHandle FTM_SAVE_REGION_CACHE("Save Region Cache"); + +LLViewerRegion::~LLViewerRegion() +{ + LL_PROFILE_ZONE_SCOPED; + mDead = true; + mImpl->mActiveSet.clear(); + mImpl->mVisibleEntries.clear(); + mImpl->mVisibleGroups.clear(); + mImpl->mWaitingSet.clear(); + + gVLManager.cleanupData(this); + // Can't do this on destruction, because the neighbor pointers might be invalid. + // This should be reference counted... + disconnectAllNeighbors(); + LLViewerPartSim::getInstance()->cleanupRegion(this); + + { + LL_RECORD_BLOCK_TIME(FTM_CLEANUP_REGION_OBJECTS); + gObjectList.killObjects(this); + } + + delete mImpl->mCompositionp; + delete mParcelOverlay; + delete mImpl->mLandp; + delete mImpl->mEventPoll; +#if 0 + LLHTTPSender::clearSender(mImpl->mHost); +#endif + std::for_each(mImpl->mObjectPartition.begin(), mImpl->mObjectPartition.end(), DeletePointer()); + + { + LL_RECORD_BLOCK_TIME(FTM_SAVE_REGION_CACHE); + saveObjectCache(); + } + + delete mImpl; + mImpl = NULL; +} + +/*virtual*/ +const LLHost& LLViewerRegion::getHost() const +{ + return mImpl->mHost; +} + +LLSurface & LLViewerRegion::getLand() const +{ + return *mImpl->mLandp; +} + +const LLUUID& LLViewerRegion::getRegionID() const +{ + return mImpl->mRegionID; +} + +void LLViewerRegion::setRegionID(const LLUUID& region_id) +{ + mImpl->mRegionID = region_id; +} + +void LLViewerRegion::loadObjectCache() +{ + if (mCacheLoaded) + { + return; + } + + // Presume success. If it fails, we don't want to try again. + mCacheLoaded = true; + + if(LLVOCache::instanceExists()) + { + LLVOCache & vocache = LLVOCache::instance(); + vocache.readFromCache(mHandle, mImpl->mCacheID, mImpl->mCacheMap); + vocache.readGenericExtrasFromCache(mHandle, mImpl->mCacheID, mImpl->mGLTFOverridesLLSD); + + if (mImpl->mCacheMap.empty()) + { + mCacheDirty = true; + } + } +} + + +void LLViewerRegion::saveObjectCache() +{ + if (!mCacheLoaded) + { + return; + } + + if (mImpl->mCacheMap.empty()) + { + return; + } + + if(LLVOCache::instanceExists()) + { + const F32 start_time_threshold = 600.0f; //seconds + bool removal_enabled = sVOCacheCullingEnabled && (mRegionTimer.getElapsedTimeF32() > start_time_threshold); //allow to remove invalid objects from object cache file. + + LLVOCache & instance = LLVOCache::instance(); + + instance.writeToCache(mHandle, mImpl->mCacheID, mImpl->mCacheMap, mCacheDirty, removal_enabled); + instance.writeGenericExtrasToCache(mHandle, mImpl->mCacheID, mImpl->mGLTFOverridesLLSD, mCacheDirty, removal_enabled); + mCacheDirty = false; + } + + if (LLAppViewer::instance()->isQuitting()) + { + mImpl->mCacheMap.clear(); + } + else + { + // Map of LLVOCacheEntry takes time to release, store map for cleanup on idle + sRegionCacheCleanup.insert(mImpl->mCacheMap.begin(), mImpl->mCacheMap.end()); + mImpl->mCacheMap.clear(); + // TODO - probably need to do the same for overrides cache + } +} + +void LLViewerRegion::sendMessage() +{ + gMessageSystem->sendMessage(mImpl->mHost); +} + +void LLViewerRegion::sendReliableMessage() +{ + gMessageSystem->sendReliable(mImpl->mHost); +} + +void LLViewerRegion::setWaterHeight(F32 water_level) +{ + mImpl->mLandp->setWaterHeight(water_level); +} + +F32 LLViewerRegion::getWaterHeight() const +{ + return mImpl->mLandp->getWaterHeight(); +} + +bool LLViewerRegion::isVoiceEnabled() const +{ + return getRegionFlag(REGION_FLAGS_ALLOW_VOICE); +} + +void LLViewerRegion::setRegionFlags(U64 flags) +{ + mRegionFlags = flags; +} + + +void LLViewerRegion::setOriginGlobal(const LLVector3d &origin_global) +{ + mImpl->mOriginGlobal = origin_global; + updateRenderMatrix(); + mImpl->mLandp->setOriginGlobal(origin_global); + mWind.setOriginGlobal(origin_global); + calculateCenterGlobal(); +} + +void LLViewerRegion::updateRenderMatrix() +{ + mRenderMatrix.setTranslation(getOriginAgent()); +} + +void LLViewerRegion::setTimeDilation(F32 time_dilation) +{ + mTimeDilation = time_dilation; +} + +const LLVector3d & LLViewerRegion::getOriginGlobal() const +{ + return mImpl->mOriginGlobal; +} + +LLVector3 LLViewerRegion::getOriginAgent() const +{ + return gAgent.getPosAgentFromGlobal(mImpl->mOriginGlobal); +} + +const LLVector3d & LLViewerRegion::getCenterGlobal() const +{ + return mImpl->mCenterGlobal; +} + +LLVector3 LLViewerRegion::getCenterAgent() const +{ + return gAgent.getPosAgentFromGlobal(mImpl->mCenterGlobal); +} + +void LLViewerRegion::setOwner(const LLUUID& owner_id) +{ + mImpl->mOwnerID = owner_id; +} + +const LLUUID& LLViewerRegion::getOwner() const +{ + return mImpl->mOwnerID; +} + +void LLViewerRegion::setRegionNameAndZone (const std::string& name_zone) +{ + std::string::size_type pipe_pos = name_zone.find('|'); + S32 length = name_zone.size(); + if (pipe_pos != std::string::npos) + { + mName = name_zone.substr(0, pipe_pos); + mZoning = name_zone.substr(pipe_pos+1, length-(pipe_pos+1)); + } + else + { + mName = name_zone; + mZoning = ""; + } + + LLStringUtil::stripNonprintable(mName); + LLStringUtil::stripNonprintable(mZoning); +} + +bool LLViewerRegion::canManageEstate() const +{ + return gAgent.isGodlike() + || isEstateManager() + || gAgent.getID() == getOwner(); +} + +const std::string LLViewerRegion::getSimAccessString() const +{ + return accessToString(mSimAccess); +} + +std::string LLViewerRegion::getLocalizedSimProductName() const +{ + std::string localized_spn; + return LLTrans::findString(localized_spn, mProductName) ? localized_spn : mProductName; +} + +// static +std::string LLViewerRegion::regionFlagsToString(U64 flags) +{ + std::string result; + + if (flags & REGION_FLAGS_SANDBOX) + { + result += "Sandbox"; + } + + if (flags & REGION_FLAGS_ALLOW_DAMAGE) + { + result += " Not Safe"; + } + + return result; +} + +// static +std::string LLViewerRegion::accessToString(U8 sim_access) +{ + switch(sim_access) + { + case SIM_ACCESS_PG: + return LLTrans::getString("SIM_ACCESS_PG"); + + case SIM_ACCESS_MATURE: + return LLTrans::getString("SIM_ACCESS_MATURE"); + + case SIM_ACCESS_ADULT: + return LLTrans::getString("SIM_ACCESS_ADULT"); + + case SIM_ACCESS_DOWN: + return LLTrans::getString("SIM_ACCESS_DOWN"); + + case SIM_ACCESS_MIN: + default: + return LLTrans::getString("SIM_ACCESS_MIN"); + } +} + +// static +std::string LLViewerRegion::getAccessIcon(U8 sim_access) +{ + switch(sim_access) + { + case SIM_ACCESS_MATURE: + return "Parcel_M_Dark"; + + case SIM_ACCESS_ADULT: + return "Parcel_R_Light"; + + case SIM_ACCESS_PG: + return "Parcel_PG_Light"; + + case SIM_ACCESS_MIN: + default: + return ""; + } +} + +// static +std::string LLViewerRegion::accessToShortString(U8 sim_access) +{ + switch(sim_access) /* Flawfinder: ignore */ + { + case SIM_ACCESS_PG: + return "PG"; + + case SIM_ACCESS_MATURE: + return "M"; + + case SIM_ACCESS_ADULT: + return "A"; + + case SIM_ACCESS_MIN: + default: + return "U"; + } +} + +// static +U8 LLViewerRegion::shortStringToAccess(const std::string &sim_access) +{ + U8 accessValue; + + if (LLStringUtil::compareStrings(sim_access, "PG") == 0) + { + accessValue = SIM_ACCESS_PG; + } + else if (LLStringUtil::compareStrings(sim_access, "M") == 0) + { + accessValue = SIM_ACCESS_MATURE; + } + else if (LLStringUtil::compareStrings(sim_access, "A") == 0) + { + accessValue = SIM_ACCESS_ADULT; + } + else + { + accessValue = SIM_ACCESS_MIN; + } + + return accessValue; +} + +// static +void LLViewerRegion::processRegionInfo(LLMessageSystem* msg, void**) +{ + // send it to 'observers' + // *TODO: switch the floaters to using LLRegionInfoModel + LL_INFOS() << "Processing region info" << LL_ENDL; + LLRegionInfoModel::instance().update(msg); + LLFloaterGodTools::processRegionInfo(msg); + LLFloaterRegionInfo::processRegionInfo(msg); +} + +void LLViewerRegion::setCacheID(const LLUUID& id) +{ + mImpl->mCacheID = id; +} + +void LLViewerRegion::renderPropertyLines() +{ + if (mParcelOverlay) + { + mParcelOverlay->renderPropertyLines(); + } +} + +void LLViewerRegion::renderPropertyLinesOnMinimap(F32 scale_pixels_per_meter, const F32 *parcel_outline_color) +{ + if (mParcelOverlay) + { + mParcelOverlay->renderPropertyLinesOnMinimap(scale_pixels_per_meter, parcel_outline_color); + } +} + + +// This gets called when the height field changes. +void LLViewerRegion::dirtyHeights() +{ + // Property lines need to be reconstructed when the land changes. + if (mParcelOverlay) + { + mParcelOverlay->setDirty(); + } +} + +//physically delete the cache entry +void LLViewerRegion::killCacheEntry(LLVOCacheEntry* entry, bool for_rendering) +{ + if(!entry || !entry->isValid()) + { + return; + } + + if(for_rendering && !entry->isState(LLVOCacheEntry::ACTIVE)) + { + addNewObject(entry); //force to add to rendering pipeline + } + + //remove from active list and waiting list + if(entry->isState(LLVOCacheEntry::ACTIVE)) + { + mImpl->mActiveSet.erase(entry); + } + else + { + if(entry->isState(LLVOCacheEntry::WAITING)) + { + mImpl->mWaitingSet.erase(entry); + } + + //remove from mVOCachePartition + removeFromVOCacheTree(entry); + } + + //remove from the forced visible list + mImpl->mVisibleEntries.erase(entry); + + //disconnect from parent if it is a child + if(entry->getParentID() > 0) + { + LLVOCacheEntry* parent = getCacheEntry(entry->getParentID()); + if(parent) + { + parent->removeChild(entry); + } + } + else if(entry->getNumOfChildren() > 0)//remove children from cache if has any + { + LLVOCacheEntry* child = entry->getChild(); + while(child != NULL) + { + killCacheEntry(child, for_rendering); + child = entry->getChild(); + } + } + + //will remove it from the object cache, real deletion + entry->setState(LLVOCacheEntry::INACTIVE); + entry->removeOctreeEntry(); + entry->setValid(false); + + // TODO kill extras/material overrides cache too +} + +//physically delete the cache entry +void LLViewerRegion::killCacheEntry(U32 local_id) +{ + killCacheEntry(getCacheEntry(local_id)); +} + +U32 LLViewerRegion::getNumOfActiveCachedObjects() const +{ + return mImpl->mActiveSet.size(); +} + +void LLViewerRegion::addActiveCacheEntry(LLVOCacheEntry* entry) +{ + if(!entry || mDead) + { + return; + } + if(entry->isState(LLVOCacheEntry::ACTIVE)) + { + return; //already inserted. + } + + if(entry->isState(LLVOCacheEntry::WAITING)) + { + mImpl->mWaitingSet.erase(entry); + } + + entry->setState(LLVOCacheEntry::ACTIVE); + entry->setVisible(); + + llassert(entry->getEntry()->hasDrawable()); + mImpl->mActiveSet.insert(entry); +} + +void LLViewerRegion::removeActiveCacheEntry(LLVOCacheEntry* entry, LLDrawable* drawablep) +{ + if(mDead || !entry || !entry->isValid()) + { + return; + } + if(!entry->isState(LLVOCacheEntry::ACTIVE)) + { + return; //not an active entry. + } + + //shift to the local regional space from agent space + if(drawablep != NULL && drawablep->getVObj().notNull()) + { + const LLVector3& pos = drawablep->getVObj()->getPositionRegion(); + LLVector4a shift; + shift.load3(pos.mV); + shift.sub(entry->getPositionGroup()); + entry->shift(shift); + } + + if(entry->getParentID() > 0) //is a child + { + LLVOCacheEntry* parent = getCacheEntry(entry->getParentID()); + if(parent) + { + parent->addChild(entry); + } + else //parent not in cache. + { + //this happens only when parent is not cacheable. + mOrphanMap[entry->getParentID()].push_back(entry->getLocalID()); + } + } + else //insert to vo cache tree. + { + entry->updateParentBoundingInfo(); + entry->saveBoundingSphere(); + addToVOCacheTree(entry); + } + + mImpl->mVisibleEntries.erase(entry); + mImpl->mActiveSet.erase(entry); + mImpl->mWaitingSet.erase(entry); + entry->setState(LLVOCacheEntry::INACTIVE); +} + +bool LLViewerRegion::addVisibleGroup(LLViewerOctreeGroup* group) +{ + if(mDead || group->isEmpty()) + { + return false; + } + + mImpl->mVisibleGroups.insert(group); + + return true; +} + +U32 LLViewerRegion::getNumOfVisibleGroups() const +{ + return mImpl ? mImpl->mVisibleGroups.size() : 0; +} + +void LLViewerRegion::updateReflectionProbes() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY; + const F32 probe_spacing = 32.f; + const F32 probe_radius = sqrtf((probe_spacing * 0.5f) * (probe_spacing * 0.5f) * 3.f); + const F32 hover_height = 2.f; + + F32 start = probe_spacing * 0.5f; + + U32 grid_width = REGION_WIDTH_METERS / probe_spacing; + + mReflectionMaps.resize(grid_width * grid_width); + + F32 water_height = getWaterHeight(); + LLVector3 origin = getOriginAgent(); + + for (U32 i = 0; i < grid_width; ++i) + { + F32 x = i * probe_spacing + start; + for (U32 j = 0; j < grid_width; ++j) + { + F32 y = j * probe_spacing + start; + + U32 idx = i * grid_width + j; + + if (mReflectionMaps[idx].isNull()) + { + mReflectionMaps[idx] = gPipeline.mReflectionMapManager.addProbe(); + } + + LLVector3 probe_origin = LLVector3(x, y, llmax(water_height, mImpl->mLandp->resolveHeightRegion(x, y))); + probe_origin.mV[2] += hover_height; + probe_origin += origin; + + mReflectionMaps[idx]->mOrigin.load3(probe_origin.mV); + mReflectionMaps[idx]->mRadius = probe_radius; + } + } +} + +void LLViewerRegion::addToVOCacheTree(LLVOCacheEntry* entry) +{ + if(!sVOCacheCullingEnabled) + { + return; + } + + if(mDead || !entry || !entry->getEntry() || !entry->isValid()) + { + return; + } + if(entry->getParentID() > 0) + { + return; //no child prim in cache octree. + } + + if(entry->hasState(LLVOCacheEntry::IN_VO_TREE)) + { + return; //already in the tree. + } + + llassert_always(!entry->getGroup()); //not in octree. + llassert(!entry->getEntry()->hasDrawable()); //not have drawables + + if(mImpl->mVOCachePartition->addEntry(entry->getEntry())) + { + entry->setState(LLVOCacheEntry::IN_VO_TREE); + } +} + +void LLViewerRegion::removeFromVOCacheTree(LLVOCacheEntry* entry) +{ + if(mDead || !entry || !entry->getEntry()) + { + return; + } + + if(!entry->hasState(LLVOCacheEntry::IN_VO_TREE)) + { + return; //not in the tree. + } + entry->clearState(LLVOCacheEntry::IN_VO_TREE); + + mImpl->mVOCachePartition->removeEntry(entry->getEntry()); +} + +//add child objects as visible entries +void LLViewerRegion::addVisibleChildCacheEntry(LLVOCacheEntry* parent, LLVOCacheEntry* child) +{ + if(mDead) + { + return; + } + + if(parent && (!parent->isValid() || !parent->isState(LLVOCacheEntry::ACTIVE))) + { + return; //parent must be valid and in rendering pipeline + } + + if(child && (!child->getEntry() || !child->isValid() || !child->isState(LLVOCacheEntry::INACTIVE))) + { + return; //child must be valid and not in the rendering pipeline + } + + if(child) + { + child->setState(LLVOCacheEntry::IN_QUEUE); + mImpl->mVisibleEntries.insert(child); + } + else if(parent && parent->getNumOfChildren() > 0) //add all children + { + child = parent->getChild(); + while(child != NULL) + { + addVisibleChildCacheEntry(NULL, child); + child = parent->getChild(); + } + } +} + +void LLViewerRegion::updateVisibleEntries(F32 max_time) +{ + if(mDead) + { + return; + } + + if(mImpl->mVisibleGroups.empty() && mImpl->mVisibleEntries.empty()) + { + return; + } + + if(!sNewObjectCreationThrottle) + { + return; + } + + const F32 LARGE_SCENE_CONTRIBUTION = 1000.f; //a large number to force to load the object. + const LLVector3 camera_origin = LLViewerCamera::getInstance()->getOrigin(); + const U32 cur_frame = LLViewerOctreeEntryData::getCurrentFrame(); + bool needs_update = ((cur_frame - mImpl->mLastCameraUpdate) > 5) && ((camera_origin - mImpl->mLastCameraOrigin).lengthSquared() > 10.f); + U32 last_update = mImpl->mLastCameraUpdate; + LLVector4a local_origin; + local_origin.load3((camera_origin - getOriginAgent()).mV); + + //process visible entries + for(LLVOCacheEntry::vocache_entry_set_t::iterator iter = mImpl->mVisibleEntries.begin(); iter != mImpl->mVisibleEntries.end();) + { + LLVOCacheEntry* vo_entry = *iter; + + if(vo_entry->isValid() && vo_entry->getState() < LLVOCacheEntry::WAITING) + { + //set a large number to force to load this object. + vo_entry->setSceneContribution(LARGE_SCENE_CONTRIBUTION); + + mImpl->mWaitingList.insert(vo_entry); + ++iter; + } + else + { + LLVOCacheEntry::vocache_entry_set_t::iterator next_iter = iter; + ++next_iter; + mImpl->mVisibleEntries.erase(iter); + iter = next_iter; + } + } + + // + //process visible groups + // + //object projected area threshold + F32 projection_threshold = LLVOCacheEntry::getSquaredPixelThreshold(mImpl->mVOCachePartition->isFrontCull()); + F32 dist_threshold = mImpl->mVOCachePartition->isFrontCull() ? gAgentCamera.mDrawDistance : LLVOCacheEntry::sRearFarRadius; + + std::set< LLPointer<LLViewerOctreeGroup> >::iterator group_iter = mImpl->mVisibleGroups.begin(); + for(; group_iter != mImpl->mVisibleGroups.end(); ++group_iter) + { + LLPointer<LLViewerOctreeGroup> group = *group_iter; + if(group->getNumRefs() < 3 || //group to be deleted + !group->getOctreeNode() || group->isEmpty()) //group empty + { + continue; + } + + for (LLViewerOctreeGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i) + { + if((*i)->hasVOCacheEntry()) + { + LLVOCacheEntry* vo_entry = (LLVOCacheEntry*)(*i)->getVOCacheEntry(); + + if(vo_entry->getParentID() > 0) //is a child + { + //child visibility depends on its parent. + continue; + } + if(!vo_entry->isValid()) + { + continue; //skip invalid entry. + } + + vo_entry->calcSceneContribution(local_origin, needs_update, last_update, dist_threshold); + if(vo_entry->getSceneContribution() > projection_threshold) + { + mImpl->mWaitingList.insert(vo_entry); + } + } + } + } + + if(needs_update) + { + mImpl->mLastCameraOrigin = camera_origin; + mImpl->mLastCameraUpdate = cur_frame; + } + + return; +} + +void LLViewerRegion::createVisibleObjects(F32 max_time) +{ + if(mDead) + { + return; + } + if(mImpl->mWaitingList.empty()) + { + mImpl->mVOCachePartition->setCullHistory(false); + return; + } + + S32 throttle = sNewObjectCreationThrottle; + bool has_new_obj = false; + LLTimer update_timer; + for(LLVOCacheEntry::vocache_entry_priority_list_t::iterator iter = mImpl->mWaitingList.begin(); + iter != mImpl->mWaitingList.end(); ++iter) + { + LLVOCacheEntry* vo_entry = *iter; + + if(vo_entry->getState() < LLVOCacheEntry::WAITING) + { + addNewObject(vo_entry); + has_new_obj = true; + if(throttle > 0 && !(--throttle) && update_timer.getElapsedTimeF32() > max_time) + { + break; + } + } + } + + mImpl->mVOCachePartition->setCullHistory(has_new_obj); + + return; +} + +void LLViewerRegion::clearCachedVisibleObjects() +{ + mImpl->mWaitingList.clear(); + mImpl->mVisibleGroups.clear(); + + //reset all occluders + mImpl->mVOCachePartition->resetOccluders(); + mPaused = true; + + //clean visible entries + for(LLVOCacheEntry::vocache_entry_set_t::iterator iter = mImpl->mVisibleEntries.begin(); iter != mImpl->mVisibleEntries.end();) + { + LLVOCacheEntry* entry = *iter; + LLVOCacheEntry* parent = getCacheEntry(entry->getParentID()); + + if(!entry->getParentID() || parent) //no child or parent is cache-able + { + if(parent) //has a cache-able parent + { + parent->addChild(entry); + } + + LLVOCacheEntry::vocache_entry_set_t::iterator next_iter = iter; + ++next_iter; + mImpl->mVisibleEntries.erase(iter); + iter = next_iter; + } + else //parent is not cache-able, leave it. + { + ++iter; + } + } + + //remove all visible entries. + mLastVisitedEntry = NULL; + std::vector<LLDrawable*> delete_list; + for(LLVOCacheEntry::vocache_entry_set_t::iterator iter = mImpl->mActiveSet.begin(); + iter != mImpl->mActiveSet.end(); ++iter) + { + LLVOCacheEntry* vo_entry = *iter; + if (!vo_entry || !vo_entry->getEntry()) + { + continue; + } + LLDrawable* drawablep = (LLDrawable*)vo_entry->getEntry()->getDrawable(); + + if(drawablep && !drawablep->getParent()) + { + delete_list.push_back(drawablep); + } + } + + if(!delete_list.empty()) + { + for(S32 i = 0; i < delete_list.size(); i++) + { + gObjectList.killObject(delete_list[i]->getVObj()); + } + delete_list.clear(); + } + + return; +} + +//perform some necessary but very light updates. +//to replace the function idleUpdate(...) in case there is no enough time. +void LLViewerRegion::lightIdleUpdate() +{ + if(!sVOCacheCullingEnabled) + { + return; + } + if(mImpl->mCacheMap.empty()) + { + return; + } + + //reset all occluders + mImpl->mVOCachePartition->resetOccluders(); +} + +void LLViewerRegion::idleUpdate(F32 max_update_time) +{ + LL_PROFILE_ZONE_SCOPED; + LLTimer update_timer; + F32 max_time; + + mLastUpdate = LLViewerOctreeEntryData::getCurrentFrame(); + + mImpl->mLandp->idleUpdate(max_update_time); + + if (mParcelOverlay) + { + // Hopefully not a significant time sink... + mParcelOverlay->idleUpdate(); + } + + if(!sVOCacheCullingEnabled) + { + return; + } + if(mImpl->mCacheMap.empty()) + { + return; + } + if(mPaused) + { + mPaused = false; //unpause. + } + + LLViewerCamera::eCameraID old_camera_id = LLViewerCamera::sCurCameraID; + LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD; + + //reset all occluders + mImpl->mVOCachePartition->resetOccluders(); + + max_time = max_update_time - update_timer.getElapsedTimeF32(); + + //kill invisible objects + killInvisibleObjects(max_time * 0.4f); + max_time = max_update_time - update_timer.getElapsedTimeF32(); + + updateVisibleEntries(max_time); + max_time = max_update_time - update_timer.getElapsedTimeF32(); + + createVisibleObjects(max_time); + + mImpl->mWaitingList.clear(); + mImpl->mVisibleGroups.clear(); + + LLViewerCamera::sCurCameraID = old_camera_id; + return; +} + +// static +void LLViewerRegion::idleCleanup(F32 max_update_time) +{ + LLTimer update_timer; + while (!sRegionCacheCleanup.empty() && (max_update_time - update_timer.getElapsedTimeF32() > 0)) + { + sRegionCacheCleanup.erase(sRegionCacheCleanup.begin()); + } +} + +//update the throttling number for new object creation +void LLViewerRegion::calcNewObjectCreationThrottle() +{ + static LLCachedControl<S32> new_object_creation_throttle(gSavedSettings,"NewObjectCreationThrottle"); + static LLCachedControl<F32> throttle_delay_time(gSavedSettings,"NewObjectCreationThrottleDelayTime"); + static LLFrameTimer timer; + + // + //sNewObjectCreationThrottle = + //-2: throttle is disabled because either the screen is showing progress view, or immediate after the screen is not black + //-1: throttle is disabled by the debug setting + //0: no new object creation is allowed + //>0: valid throttling number + // + + if(gViewerWindow->getProgressView()->getVisible() && throttle_delay_time > 0.f) + { + sNewObjectCreationThrottle = -2; //cancel the throttling + timer.reset(); + } + else if(sNewObjectCreationThrottle < -1) //just recoved from the login/teleport screen + { + if(timer.getElapsedTimeF32() > throttle_delay_time) //wait for throttle_delay_time to reset the throttle + { + sNewObjectCreationThrottle = new_object_creation_throttle; //reset + if(sNewObjectCreationThrottle < -1) + { + sNewObjectCreationThrottle = -1; + } + } + } + + //update some LLVOCacheEntry debug setting factors. + LLVOCacheEntry::updateDebugSettings(); +} + +bool LLViewerRegion::isViewerCameraStatic() +{ + return sLastCameraUpdated < LLViewerOctreeEntryData::getCurrentFrame(); +} + +void LLViewerRegion::killInvisibleObjects(F32 max_time) +{ +#if 1 // TODO: kill this. This is ill-conceived, objects that aren't in the camera frustum should not be deleted from memory. + // because of this, every time you turn around the simulator sends a swarm of full object update messages from cache + // probe misses and objects have to be reloaded from scratch. From some reason, disabling this causes holes to + // appear in the scene when flying back and forth between regions + if(!sVOCacheCullingEnabled) + { + return; + } + if(mImpl->mActiveSet.empty()) + { + return; + } + if(sNewObjectCreationThrottle < 0) + { + return; + } + + LLTimer update_timer; + LLVector4a camera_origin; + camera_origin.load3(LLViewerCamera::getInstance()->getOrigin().mV); + LLVector4a local_origin; + local_origin.load3((LLViewerCamera::getInstance()->getOrigin() - getOriginAgent()).mV); + F32 back_threshold = LLVOCacheEntry::sRearFarRadius; + + size_t max_update = 64; + if(!mInvisibilityCheckHistory && isViewerCameraStatic()) + { + //history is clean, reduce number of checking + max_update /= 2; + } + + std::vector<LLDrawable*> delete_list; + S32 update_counter = llmin(max_update, mImpl->mActiveSet.size()); + LLVOCacheEntry::vocache_entry_set_t::iterator iter = mImpl->mActiveSet.upper_bound(mLastVisitedEntry); + + for(; update_counter > 0; --update_counter, ++iter) + { + if(iter == mImpl->mActiveSet.end()) + { + iter = mImpl->mActiveSet.begin(); + } + if((*iter)->getParentID() > 0) + { + continue; //skip child objects, they are removed with their parent. + } + + LLVOCacheEntry* vo_entry = *iter; + if(!vo_entry->isAnyVisible(camera_origin, local_origin, back_threshold) && vo_entry->mLastCameraUpdated < sLastCameraUpdated) + { + killObject(vo_entry, delete_list); + } + + if(max_time < update_timer.getElapsedTimeF32()) //time out + { + break; + } + } + + if(iter == mImpl->mActiveSet.end()) + { + mLastVisitedEntry = NULL; + } + else + { + mLastVisitedEntry = *iter; + } + + mInvisibilityCheckHistory <<= 1; + if(!delete_list.empty()) + { + mInvisibilityCheckHistory |= 1; + S32 count = delete_list.size(); + for(S32 i = 0; i < count; i++) + { + gObjectList.killObject(delete_list[i]->getVObj()); + } + delete_list.clear(); + } + + return; +#endif +} + +void LLViewerRegion::killObject(LLVOCacheEntry* entry, std::vector<LLDrawable*>& delete_list) +{ + //kill the object. + LLDrawable* drawablep = (LLDrawable*)entry->getEntry()->getDrawable(); + llassert(drawablep); + llassert(drawablep->getRegion() == this); + + if(drawablep && !drawablep->getParent()) + { + LLViewerObject* v_obj = drawablep->getVObj(); + if (v_obj->isSelected() + || (v_obj->flagAnimSource() && isAgentAvatarValid() && gAgentAvatarp->hasMotionFromSource(v_obj->getID()))) + { + // do not remove objects user is interacting with + ((LLViewerOctreeEntryData*)drawablep)->setVisible(); + return; + } + LLViewerObject::const_child_list_t& child_list = v_obj->getChildren(); + for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); + iter != child_list.end(); iter++) + { + LLViewerObject* child = *iter; + if(child->mDrawable) + { + if( !child->mDrawable->getEntry() + || !child->mDrawable->getEntry()->hasVOCacheEntry() + || child->isSelected() + || (child->flagAnimSource() && isAgentAvatarValid() && gAgentAvatarp->hasMotionFromSource(child->getID()))) + { + //do not remove parent if any of its children non-cacheable, animating or selected + //especially for the case that an avatar sits on a cache-able object + ((LLViewerOctreeEntryData*)drawablep)->setVisible(); + return; + } + + LLOcclusionCullingGroup* group = (LLOcclusionCullingGroup*)child->mDrawable->getGroup(); + if(group && group->isAnyRecentlyVisible()) + { + //set the parent visible if any of its children visible. + ((LLViewerOctreeEntryData*)drawablep)->setVisible(); + return; + } + } + } + delete_list.push_back(drawablep); + } +} + +LLViewerObject* LLViewerRegion::addNewObject(LLVOCacheEntry* entry) +{ + if(!entry || !entry->getEntry()) + { + if(entry) + { + mImpl->mVisibleEntries.erase(entry); + entry->setState(LLVOCacheEntry::INACTIVE); + } + return NULL; + } + + LLViewerObject* obj = NULL; + if(!entry->getEntry()->hasDrawable()) //not added to the rendering pipeline yet + { + //add the object + obj = gObjectList.processObjectUpdateFromCache(entry, this); + if(obj) + { + if(!entry->isState(LLVOCacheEntry::ACTIVE)) + { + mImpl->mWaitingSet.insert(entry); + entry->setState(LLVOCacheEntry::WAITING); + } + } + } + else + { + LLViewerRegion* old_regionp = ((LLDrawable*)entry->getEntry()->getDrawable())->getRegion(); + if(old_regionp != this) + { + //this object exists in two regions at the same time; + //this case can be safely ignored here because + //server should soon send update message to remove one region for this object. + + LL_WARNS() << "Entry: " << entry->getLocalID() << " exists in two regions at the same time." << LL_ENDL; + return NULL; + } + + LL_WARNS() << "Entry: " << entry->getLocalID() << " in rendering pipeline but not set to be active." << LL_ENDL; + + //should not hit here any more, but does not hurt either, just put it back to active list + addActiveCacheEntry(entry); + } + + return obj; +} + +//update object cache if the object receives a full-update or terse update +//update_type == EObjectUpdateType::OUT_TERSE_IMPROVED or EObjectUpdateType::OUT_FULL +LLViewerObject* LLViewerRegion::updateCacheEntry(U32 local_id, LLViewerObject* objectp) +{ + LLVOCacheEntry* entry = getCacheEntry(local_id); + if (!entry) + { + return objectp; //not in the cache, do nothing. + } + if(!objectp) //object not created + { + //create a new object from cache. + objectp = addNewObject(entry); + } + + //remove from cache. + killCacheEntry(entry, true); + + return objectp; +} + +// As above, but forcibly do the update. +void LLViewerRegion::forceUpdate() +{ + mImpl->mLandp->idleUpdate(0.f); + + if (mParcelOverlay) + { + mParcelOverlay->idleUpdate(true); + } +} + +void LLViewerRegion::connectNeighbor(LLViewerRegion *neighborp, U32 direction) +{ + mImpl->mLandp->connectNeighbor(neighborp->mImpl->mLandp, direction); +} + + +void LLViewerRegion::disconnectAllNeighbors() +{ + mImpl->mLandp->disconnectAllNeighbors(); +} + +LLVLComposition * LLViewerRegion::getComposition() const +{ + return mImpl->mCompositionp; +} + +F32 LLViewerRegion::getCompositionXY(const S32 x, const S32 y) const +{ + if (x >= 256) + { + if (y >= 256) + { + LLVector3d center = getCenterGlobal() + LLVector3d(256.f, 256.f, 0.f); + LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromPosGlobal(center); + if (regionp) + { + // OK, we need to do some hackery here - different simulators no longer use + // the same composition values, necessarily. + // If we're attempting to blend, then we want to make the fractional part of + // this region match the fractional of the adjacent. For now, just minimize + // the delta. + F32 our_comp = getComposition()->getValueScaled(255, 255); + F32 adj_comp = regionp->getComposition()->getValueScaled(x - 256.f, y - 256.f); + while (llabs(our_comp - adj_comp) >= 1.f) + { + if (our_comp > adj_comp) + { + adj_comp += 1.f; + } + else + { + adj_comp -= 1.f; + } + } + return adj_comp; + } + } + else + { + LLVector3d center = getCenterGlobal() + LLVector3d(256.f, 0, 0.f); + LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromPosGlobal(center); + if (regionp) + { + // OK, we need to do some hackery here - different simulators no longer use + // the same composition values, necessarily. + // If we're attempting to blend, then we want to make the fractional part of + // this region match the fractional of the adjacent. For now, just minimize + // the delta. + F32 our_comp = getComposition()->getValueScaled(255.f, (F32)y); + F32 adj_comp = regionp->getComposition()->getValueScaled(x - 256.f, (F32)y); + while (llabs(our_comp - adj_comp) >= 1.f) + { + if (our_comp > adj_comp) + { + adj_comp += 1.f; + } + else + { + adj_comp -= 1.f; + } + } + return adj_comp; + } + } + } + else if (y >= 256) + { + LLVector3d center = getCenterGlobal() + LLVector3d(0.f, 256.f, 0.f); + LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromPosGlobal(center); + if (regionp) + { + // OK, we need to do some hackery here - different simulators no longer use + // the same composition values, necessarily. + // If we're attempting to blend, then we want to make the fractional part of + // this region match the fractional of the adjacent. For now, just minimize + // the delta. + F32 our_comp = getComposition()->getValueScaled((F32)x, 255.f); + F32 adj_comp = regionp->getComposition()->getValueScaled((F32)x, y - 256.f); + while (llabs(our_comp - adj_comp) >= 1.f) + { + if (our_comp > adj_comp) + { + adj_comp += 1.f; + } + else + { + adj_comp -= 1.f; + } + } + return adj_comp; + } + } + + return getComposition()->getValueScaled((F32)x, (F32)y); +} + +void LLViewerRegion::calculateCenterGlobal() +{ + mImpl->mCenterGlobal = mImpl->mOriginGlobal; + mImpl->mCenterGlobal.mdV[VX] += 0.5 * mWidth; + mImpl->mCenterGlobal.mdV[VY] += 0.5 * mWidth; + mImpl->mCenterGlobal.mdV[VZ] = 0.5 * mImpl->mLandp->getMinZ() + mImpl->mLandp->getMaxZ(); +} + +void LLViewerRegion::calculateCameraDistance() +{ + mCameraDistanceSquared = (F32)(gAgentCamera.getCameraPositionGlobal() - getCenterGlobal()).magVecSquared(); +} + +std::ostream& operator<<(std::ostream &s, const LLViewerRegion ®ion) +{ + s << "{ "; + s << region.mImpl->mHost; + s << " mOriginGlobal = " << region.getOriginGlobal()<< "\n"; + std::string name(region.getName()), zone(region.getZoning()); + if (! name.empty()) + { + s << " mName = " << name << '\n'; + } + if (! zone.empty()) + { + s << " mZoning = " << zone << '\n'; + } + s << "}"; + return s; +} + + +// ---------------- Protected Member Functions ---------------- + +void LLViewerRegion::updateNetStats() +{ + F32 dt = mImpl->mLastNetUpdate.getElapsedTimeAndResetF32(); + + LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(mImpl->mHost); + if (!cdp) + { + mAlive = false; + return; + } + + mAlive = true; + mDeltaTime = dt; + + mLastPacketsIn = mPacketsIn; + mLastBitsIn = mBitsIn; + mLastPacketsOut = mPacketsOut; + mLastPacketsLost = mPacketsLost; + + mPacketsIn = cdp->getPacketsIn(); + mBitsIn = 8 * cdp->getBytesIn(); + mPacketsOut = cdp->getPacketsOut(); + mPacketsLost = cdp->getPacketsLost(); + mPingDelay = cdp->getPingDelay(); + + mBitsReceived += mBitsIn - mLastBitsIn; + mPacketsReceived += mPacketsIn - mLastPacketsIn; +} + + +U32 LLViewerRegion::getPacketsLost() const +{ + LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(mImpl->mHost); + if (!cdp) + { + LL_INFOS() << "LLViewerRegion::getPacketsLost couldn't find circuit for " << mImpl->mHost << LL_ENDL; + return 0; + } + else + { + return cdp->getPacketsLost(); + } +} + +S32 LLViewerRegion::getHttpResponderID() const +{ + return mImpl->mHttpResponderID; +} + +bool LLViewerRegion::pointInRegionGlobal(const LLVector3d &point_global) const +{ + LLVector3 pos_region = getPosRegionFromGlobal(point_global); + + if (pos_region.mV[VX] < 0) + { + return false; + } + if (pos_region.mV[VX] >= mWidth) + { + return false; + } + if (pos_region.mV[VY] < 0) + { + return false; + } + if (pos_region.mV[VY] >= mWidth) + { + return false; + } + return true; +} + +LLVector3 LLViewerRegion::getPosRegionFromGlobal(const LLVector3d &point_global) const +{ + LLVector3 pos_region; + pos_region.setVec(point_global - mImpl->mOriginGlobal); + return pos_region; +} + +LLVector3d LLViewerRegion::getPosGlobalFromRegion(const LLVector3 &pos_region) const +{ + LLVector3d pos_region_d; + pos_region_d.setVec(pos_region); + return pos_region_d + mImpl->mOriginGlobal; +} + +LLVector3 LLViewerRegion::getPosAgentFromRegion(const LLVector3 &pos_region) const +{ + LLVector3d pos_global = getPosGlobalFromRegion(pos_region); + + return gAgent.getPosAgentFromGlobal(pos_global); +} + +LLVector3 LLViewerRegion::getPosRegionFromAgent(const LLVector3 &pos_agent) const +{ + return pos_agent - getOriginAgent(); +} + +F32 LLViewerRegion::getLandHeightRegion(const LLVector3& region_pos) +{ + return mImpl->mLandp->resolveHeightRegion( region_pos ); +} + +bool LLViewerRegion::isAlive() +{ + return mAlive; +} + +bool LLViewerRegion::isOwnedSelf(const LLVector3& pos) +{ + if (mParcelOverlay) + { + return mParcelOverlay->isOwnedSelf(pos); + } else { + return false; + } +} + +// Owned by a group you belong to? (officer or member) +bool LLViewerRegion::isOwnedGroup(const LLVector3& pos) +{ + if (mParcelOverlay) + { + return mParcelOverlay->isOwnedGroup(pos); + } else { + return false; + } +} + +// the new TCP coarse location handler node +class CoarseLocationUpdate : public LLHTTPNode +{ +public: + virtual void post( + ResponsePtr responder, + const LLSD& context, + const LLSD& input) const + { + LLHost host(input["sender"].asString()); + + LLWorld *world_inst = LLWorld::getInstance(); // Not a singleton! + if (!world_inst) + { + return; + } + + LLViewerRegion* region = world_inst->getRegion(host); + if( !region ) + { + return; + } + + S32 target_index = input["body"]["Index"][0]["Prey"].asInteger(); + S32 you_index = input["body"]["Index"][0]["You" ].asInteger(); + + std::vector<U32>* avatar_locs = ®ion->mMapAvatars; + std::vector<LLUUID>* avatar_ids = ®ion->mMapAvatarIDs; + avatar_locs->clear(); + avatar_ids->clear(); + + //LL_INFOS() << "coarse locations agent[0] " << input["body"]["AgentData"][0]["AgentID"].asUUID() << LL_ENDL; + //LL_INFOS() << "my agent id = " << gAgent.getID() << LL_ENDL; + //LL_INFOS() << ll_pretty_print_sd(input) << LL_ENDL; + + LLSD + locs = input["body"]["Location"], + agents = input["body"]["AgentData"]; + LLSD::array_iterator + locs_it = locs.beginArray(), + agents_it = agents.beginArray(); + bool has_agent_data = input["body"].has("AgentData"); + + for(int i=0; + locs_it != locs.endArray(); + i++, locs_it++) + { + U8 + x = locs_it->get("X").asInteger(), + y = locs_it->get("Y").asInteger(), + z = locs_it->get("Z").asInteger(); + // treat the target specially for the map, and don't add you or the target + if(i == target_index) + { + LLVector3d global_pos(region->getOriginGlobal()); + global_pos.mdV[VX] += (F64)x; + global_pos.mdV[VY] += (F64)y; + global_pos.mdV[VZ] += (F64)z * 4.0; + LLAvatarTracker::instance().setTrackedCoarseLocation(global_pos); + } + else if( i != you_index) + { + U32 pos = 0x0; + pos |= x; + pos <<= 8; + pos |= y; + pos <<= 8; + pos |= z; + avatar_locs->push_back(pos); + //LL_INFOS() << "next pos: " << x << "," << y << "," << z << ": " << pos << LL_ENDL; + if(has_agent_data) // for backwards compatibility with old message format + { + LLUUID agent_id(agents_it->get("AgentID").asUUID()); + //LL_INFOS() << "next agent: " << agent_id.asString() << LL_ENDL; + avatar_ids->push_back(agent_id); + } + } + if (has_agent_data) + { + agents_it++; + } + } + } +}; + +// build the coarse location HTTP node under the "/message" URL +LLHTTPRegistration<CoarseLocationUpdate> + gHTTPRegistrationCoarseLocationUpdate( + "/message/CoarseLocationUpdate"); + + +// the deprecated coarse location handler +void LLViewerRegion::updateCoarseLocations(LLMessageSystem* msg) +{ + //LL_INFOS() << "CoarseLocationUpdate" << LL_ENDL; + mMapAvatars.clear(); + mMapAvatarIDs.clear(); // only matters in a rare case but it's good to be safe. + + U8 x_pos = 0; + U8 y_pos = 0; + U8 z_pos = 0; + + U32 pos = 0x0; + + S16 agent_index; + S16 target_index; + msg->getS16Fast(_PREHASH_Index, _PREHASH_You, agent_index); + msg->getS16Fast(_PREHASH_Index, _PREHASH_Prey, target_index); + + bool has_agent_data = msg->has(_PREHASH_AgentData); + S32 count = msg->getNumberOfBlocksFast(_PREHASH_Location); + for(S32 i = 0; i < count; i++) + { + msg->getU8Fast(_PREHASH_Location, _PREHASH_X, x_pos, i); + msg->getU8Fast(_PREHASH_Location, _PREHASH_Y, y_pos, i); + msg->getU8Fast(_PREHASH_Location, _PREHASH_Z, z_pos, i); + LLUUID agent_id = LLUUID::null; + if(has_agent_data) + { + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id, i); + } + + //LL_INFOS() << " object X: " << (S32)x_pos << " Y: " << (S32)y_pos + // << " Z: " << (S32)(z_pos * 4) + // << LL_ENDL; + + // treat the target specially for the map + if(i == target_index) + { + LLVector3d global_pos(mImpl->mOriginGlobal); + global_pos.mdV[VX] += (F64)(x_pos); + global_pos.mdV[VY] += (F64)(y_pos); + global_pos.mdV[VZ] += (F64)(z_pos) * 4.0; + LLAvatarTracker::instance().setTrackedCoarseLocation(global_pos); + } + + //don't add you + if( i != agent_index) + { + pos = 0x0; + pos |= x_pos; + pos <<= 8; + pos |= y_pos; + pos <<= 8; + pos |= z_pos; + mMapAvatars.push_back(pos); + if(has_agent_data) + { + mMapAvatarIDs.push_back(agent_id); + } + } + } +} + +void LLViewerRegion::getInfo(LLSD& info) +{ + info["Region"]["Host"] = getHost().getIPandPort(); + info["Region"]["Name"] = getName(); + U32 x, y; + from_region_handle(getHandle(), &x, &y); + info["Region"]["Handle"]["x"] = (LLSD::Integer)x; + info["Region"]["Handle"]["y"] = (LLSD::Integer)y; +} + +void LLViewerRegion::requestSimulatorFeatures() +{ + LL_DEBUGS("SimulatorFeatures") << "region " << getName() << " ptr " << this + << " trying to request SimulatorFeatures" << LL_ENDL; + // kick off a request for simulator features + std::string url = getCapability("SimulatorFeatures"); + if (!url.empty()) + { + std::string coroname = + LLCoros::instance().launch("LLViewerRegionImpl::requestSimulatorFeatureCoro", + boost::bind(&LLViewerRegionImpl::requestSimulatorFeatureCoro, url, getHandle())); + + // requestSimulatorFeatures can be called from other coros, + // launch() acts like a suspend() + // Make sure we are still good to do + LLCoros::checkStop(); + + LL_INFOS("AppInit", "SimulatorFeatures") << "Launching " << coroname << " requesting simulator features from " << url << " for region " << getRegionID() << LL_ENDL; + } + else + { + LL_WARNS("AppInit", "SimulatorFeatures") << "SimulatorFeatures cap not set" << LL_ENDL; + } +} + +boost::signals2::connection LLViewerRegion::setSimulatorFeaturesReceivedCallback(const caps_received_signal_t::slot_type& cb) +{ + return mSimulatorFeaturesReceivedSignal.connect(cb); +} + +void LLViewerRegion::setSimulatorFeaturesReceived(bool received) +{ + mSimulatorFeaturesReceived = received; + if (received) + { + mSimulatorFeaturesReceivedSignal(getRegionID(), this); + mSimulatorFeaturesReceivedSignal.disconnect_all_slots(); + } +} + +bool LLViewerRegion::simulatorFeaturesReceived() const +{ + return mSimulatorFeaturesReceived; +} + +void LLViewerRegion::getSimulatorFeatures(LLSD& sim_features) const +{ + sim_features = mSimulatorFeatures; + +} + +void LLViewerRegion::setSimulatorFeatures(const LLSD& sim_features) +{ + std::stringstream str; + + LLSDSerialize::toPrettyXML(sim_features, str); + LL_INFOS() << "region " << getName() << " " << str.str() << LL_ENDL; + mSimulatorFeatures = sim_features; + + setSimulatorFeaturesReceived(true); + +} + +//this is called when the parent is not cacheable. +//move all orphan children out of cache and insert to rendering octree. +void LLViewerRegion::findOrphans(U32 parent_id) +{ + orphan_list_t::iterator iter = mOrphanMap.find(parent_id); + if(iter != mOrphanMap.end()) + { + std::vector<U32>* children = &mOrphanMap[parent_id]; + for(S32 i = 0; i < children->size(); i++) + { + //parent is visible, so is the child. + addVisibleChildCacheEntry(NULL, getCacheEntry((*children)[i])); + } + children->clear(); + mOrphanMap.erase(parent_id); + } +} + +void LLViewerRegion::decodeBoundingInfo(LLVOCacheEntry* entry) +{ + if(!sVOCacheCullingEnabled) + { + gObjectList.processObjectUpdateFromCache(entry, this); + return; + } + if(!entry || !entry->isValid()) + { + return; + } + + if(!entry->getEntry()) + { + entry->setOctreeEntry(NULL); + } + + if(entry->getEntry()->hasDrawable()) //already in the rendering pipeline + { + LLViewerRegion* old_regionp = ((LLDrawable*)entry->getEntry()->getDrawable())->getRegion(); + if(old_regionp != this && old_regionp) + { + LLViewerObject* obj = ((LLDrawable*)entry->getEntry()->getDrawable())->getVObj(); + if(obj) + { + //remove from old region + old_regionp->killCacheEntry(obj->getLocalID()); + + //change region + obj->setRegion(this); + } + } + + addActiveCacheEntry(entry); + + //set parent id + U32 parent_id = 0; + if (entry->getDP()) // NULL if nothing cached + { + LLViewerObject::unpackParentID(entry->getDP(), parent_id); + } + if(parent_id != entry->getParentID()) + { + entry->setParentID(parent_id); + } + + //update the object + gObjectList.processObjectUpdateFromCache(entry, this); + return; //done + } + + //must not be active. + llassert_always(!entry->isState(LLVOCacheEntry::ACTIVE)); + removeFromVOCacheTree(entry); //remove from cache octree if it is in. + + LLVector3 pos; + LLVector3 scale; + LLQuaternion rot; + + //decode spatial info and parent info + U32 parent_id = entry->getDP() ? LLViewerObject::extractSpatialExtents(entry->getDP(), pos, scale, rot) : entry->getParentID(); + + U32 old_parent_id = entry->getParentID(); + bool same_old_parent = false; + if(parent_id != old_parent_id) //parent changed. + { + if(old_parent_id > 0) //has an old parent, disconnect it + { + LLVOCacheEntry* old_parent = getCacheEntry(old_parent_id); + if(old_parent) + { + old_parent->removeChild(entry); + if(!old_parent->isState(LLVOCacheEntry::INACTIVE)) + { + mImpl->mVisibleEntries.erase(entry); + entry->setState(LLVOCacheEntry::INACTIVE); + } + } + } + entry->setParentID(parent_id); + } + else + { + same_old_parent = true; + } + + if(parent_id > 0) //has a new parent + { + //1, find the parent in cache + LLVOCacheEntry* parent = getCacheEntry(parent_id); + + //2, parent is not in the cache, put into the orphan list. + if(!parent) + { + if(!same_old_parent) + { + //check if parent is non-cacheable and already created + if(isNonCacheableObjectCreated(parent_id)) + { + //parent is visible, so is the child. + addVisibleChildCacheEntry(NULL, entry); + } + else + { + entry->setBoundingInfo(pos, scale); + mOrphanMap[parent_id].push_back(entry->getLocalID()); + } + } + else + { + entry->setBoundingInfo(pos, scale); + } + } + else //parent in cache. + { + if(!parent->isState(LLVOCacheEntry::INACTIVE)) + { + //parent is visible, so is the child. + addVisibleChildCacheEntry(parent, entry); + } + else + { + entry->setBoundingInfo(pos, scale); + parent->addChild(entry); + + if(parent->getGroup()) //re-insert parent to vo-cache tree because its bounding info changed. + { + removeFromVOCacheTree(parent); + addToVOCacheTree(parent); + } + } + } + + return; + } + + // + //no parent + // + entry->setBoundingInfo(pos, scale); + + if(!parent_id) //a potential parent + { + //find all children and update their bounding info + orphan_list_t::iterator iter = mOrphanMap.find(entry->getLocalID()); + if(iter != mOrphanMap.end()) + { + std::vector<U32>* orphans = &mOrphanMap[entry->getLocalID()]; + S32 size = orphans->size(); + for(S32 i = 0; i < size; i++) + { + LLVOCacheEntry* child = getCacheEntry((*orphans)[i]); + if(child) + { + entry->addChild(child); + } + } + orphans->clear(); + mOrphanMap.erase(entry->getLocalID()); + } + } + + if(!entry->getGroup() && entry->isState(LLVOCacheEntry::INACTIVE)) + { + addToVOCacheTree(entry); + } + return ; +} + +LLViewerRegion::eCacheUpdateResult LLViewerRegion::cacheFullUpdate(LLDataPackerBinaryBuffer &dp, U32 flags) +{ + eCacheUpdateResult result; + U32 crc; + U32 local_id; + + LLViewerObject::unpackU32(&dp, local_id, "LocalID"); + LLViewerObject::unpackU32(&dp, crc, "CRC"); + + LLVOCacheEntry* entry = getCacheEntry(local_id, false); + + if (entry) + { + entry->setValid(); + + // we've seen this object before + if (entry->getCRC() == crc) + { + LL_DEBUGS("AnimatedObjects") << " got dupe for local_id " << local_id << LL_ENDL; + dumpStack("AnimatedObjectsStack"); + + // Record a hit + entry->recordDupe(); + result = CACHE_UPDATE_DUPE; + } + else //CRC changed + { + LL_DEBUGS("AnimatedObjects") << " got update for local_id " << local_id << LL_ENDL; + dumpStack("AnimatedObjectsStack"); + + // Update the cache entry + entry->updateEntry(crc, dp); + + decodeBoundingInfo(entry); + + result = CACHE_UPDATE_CHANGED; + } + } + else + { + LL_DEBUGS("AnimatedObjects") << " got first notification for local_id " << local_id << LL_ENDL; + dumpStack("AnimatedObjectsStack"); + + // we haven't seen this object before + // Create new entry and add to map + result = CACHE_UPDATE_ADDED; + entry = new LLVOCacheEntry(local_id, crc, dp); + record(LLStatViewer::OBJECT_CACHE_HIT_RATE, LLUnits::Ratio::fromValue(0)); + + mImpl->mCacheMap[local_id] = entry; + + decodeBoundingInfo(entry); + } + entry->setUpdateFlags(flags); + + return result; + } + +LLViewerRegion::eCacheUpdateResult LLViewerRegion::cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinaryBuffer &dp, U32 flags) +{ + eCacheUpdateResult result = cacheFullUpdate(dp, flags); + + return result; +} + +void LLViewerRegion::cacheFullUpdateGLTFOverride(const LLGLTFOverrideCacheEntry &override_data) +{ + U32 local_id = override_data.mLocalId; + mImpl->mGLTFOverridesLLSD[local_id] = override_data; +} + +LLVOCacheEntry* LLViewerRegion::getCacheEntryForOctree(U32 local_id) +{ + if(!sVOCacheCullingEnabled) + { + return NULL; + } + + LLVOCacheEntry* entry = getCacheEntry(local_id); + removeFromVOCacheTree(entry); + + return entry; +} + +LLVOCacheEntry* LLViewerRegion::getCacheEntry(U32 local_id, bool valid) +{ + LLVOCacheEntry::vocache_entry_map_t::iterator iter = mImpl->mCacheMap.find(local_id); + if(iter != mImpl->mCacheMap.end()) + { + if(!valid || iter->second->isValid()) + { + return iter->second; + } + } + return NULL; +} + +void LLViewerRegion::addCacheMiss(U32 id, LLViewerRegion::eCacheMissType cache_miss_type) +{ + mRegionCacheMissCount++; + mCacheMissList.push_back(CacheMissItem(id, cache_miss_type)); +} + +//check if a non-cacheable object is already created. +bool LLViewerRegion::isNonCacheableObjectCreated(U32 local_id) +{ + if(mImpl && local_id > 0 && mImpl->mNonCacheableCreatedList.find(local_id) != mImpl->mNonCacheableCreatedList.end()) + { + return true; + } + return false; +} + +void LLViewerRegion::removeFromCreatedList(U32 local_id) +{ + if(mImpl && local_id > 0) + { + std::set<U32>::iterator iter = mImpl->mNonCacheableCreatedList.find(local_id); + if(iter != mImpl->mNonCacheableCreatedList.end()) + { + mImpl->mNonCacheableCreatedList.erase(iter); + } + } + } + +void LLViewerRegion::addToCreatedList(U32 local_id) +{ + if(mImpl && local_id > 0) + { + mImpl->mNonCacheableCreatedList.insert(local_id); + } +} + +// Get data packer for this object, if we have cached data +// AND the CRC matches. JC +bool LLViewerRegion::probeCache(U32 local_id, U32 crc, U32 flags, U8 &cache_miss_type) +{ + //llassert(mCacheLoaded); This assert failes often, changing to early-out -- davep, 2010/10/18 + + LLVOCacheEntry* entry = getCacheEntry(local_id, false); + + if (entry) + { + // we've seen this object before + if (entry->getCRC() == crc) + { + // Record a hit + mRegionCacheHitCount++; + entry->recordHit(); + cache_miss_type = CACHE_MISS_TYPE_NONE; + entry->setUpdateFlags(flags); + + if(entry->isState(LLVOCacheEntry::ACTIVE)) + { + ((LLDrawable*)entry->getEntry()->getDrawable())->getVObj()->loadFlags(flags); + return true; + } + + if(entry->isValid()) + { + return true; //already probed + } + + entry->setValid(); + decodeBoundingInfo(entry); + + //loadCacheMiscExtras(local_id, entry, crc); + + return true; + } + else + { + // LL_INFOS() << "CRC miss for " << local_id << LL_ENDL; + + addCacheMiss(local_id, CACHE_MISS_TYPE_CRC); + cache_miss_type = CACHE_MISS_TYPE_CRC; + } + } + else + { // Total miss, don't have the object in cache + // LL_INFOS() << "Cache miss for " << local_id << LL_ENDL; + addCacheMiss(local_id, CACHE_MISS_TYPE_TOTAL); + cache_miss_type = CACHE_MISS_TYPE_TOTAL; + } + + return false; +} + +void LLViewerRegion::addCacheMissFull(const U32 local_id) +{ + addCacheMiss(local_id, CACHE_MISS_TYPE_TOTAL); +} + +void LLViewerRegion::requestCacheMisses() +{ + if (!mCacheMissList.size()) + { + return; + } + + LLMessageSystem* msg = gMessageSystem; + bool start_new_message = true; + S32 blocks = 0; + + //send requests for all cache-missed objects + for (CacheMissItem::cache_miss_list_t::iterator iter = mCacheMissList.begin(); iter != mCacheMissList.end(); ++iter) + { + if (start_new_message) + { + msg->newMessageFast(_PREHASH_RequestMultipleObjects); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + start_new_message = false; + } + + msg->nextBlockFast(_PREHASH_ObjectData); + msg->addU8Fast(_PREHASH_CacheMissType, (*iter).mType); + msg->addU32Fast(_PREHASH_ID, (*iter).mID); + + LL_DEBUGS("AnimatedObjects") << "Requesting cache missed object " << (*iter).mID << LL_ENDL; + + blocks++; + + if (blocks >= 255) + { + sendReliableMessage(); + start_new_message = true; + blocks = 0; + } + } + + // finish any pending message + if (!start_new_message) + { + sendReliableMessage(); + } + + mCacheDirty = true ; + // LL_INFOS() << "KILLDEBUG Sent cache miss full " << full_count << " crc " << crc_count << LL_ENDL; + LLViewerStatsRecorder::instance().requestCacheMissesEvent(mCacheMissList.size()); + + mCacheMissList.clear(); +} + +void LLViewerRegion::dumpCache() +{ + const S32 BINS = 4; + S32 hit_bin[BINS]; + S32 change_bin[BINS]; + + S32 i; + for (i = 0; i < BINS; ++i) + { + hit_bin[i] = 0; + change_bin[i] = 0; + } + + LLVOCacheEntry *entry; + for(LLVOCacheEntry::vocache_entry_map_t::iterator iter = mImpl->mCacheMap.begin(); iter != mImpl->mCacheMap.end(); ++iter) + { + entry = iter->second ; + + S32 hits = entry->getHitCount(); + S32 changes = entry->getCRCChangeCount(); + + hits = llclamp(hits, 0, BINS-1); + changes = llclamp(changes, 0, BINS-1); + + hit_bin[hits]++; + change_bin[changes]++; + } + + LL_INFOS() << "Count " << mImpl->mCacheMap.size() << LL_ENDL; + for (i = 0; i < BINS; i++) + { + LL_INFOS() << "Hits " << i << " " << hit_bin[i] << LL_ENDL; + } + for (i = 0; i < BINS; i++) + { + LL_INFOS() << "Changes " << i << " " << change_bin[i] << LL_ENDL; + } + // TODO - add overrides cache too +} + +void LLViewerRegion::unpackRegionHandshake() +{ + LLMessageSystem *msg = gMessageSystem; + + U64 region_flags = 0; + U64 region_protocols = 0; + U8 sim_access; + std::string sim_name; + LLUUID sim_owner; + bool is_estate_manager; + F32 water_height; + F32 billable_factor; + LLUUID cache_id; + + msg->getU8 ("RegionInfo", "SimAccess", sim_access); + msg->getString ("RegionInfo", "SimName", sim_name); + msg->getUUID ("RegionInfo", "SimOwner", sim_owner); + msg->getBOOL ("RegionInfo", "IsEstateManager", is_estate_manager); + msg->getF32 ("RegionInfo", "WaterHeight", water_height); + msg->getF32 ("RegionInfo", "BillableFactor", billable_factor); + msg->getUUID ("RegionInfo", "CacheID", cache_id ); + + if (msg->has(_PREHASH_RegionInfo4)) + { + msg->getU64Fast(_PREHASH_RegionInfo4, _PREHASH_RegionFlagsExtended, region_flags); + msg->getU64Fast(_PREHASH_RegionInfo4, _PREHASH_RegionProtocols, region_protocols); + } + else + { + U32 flags = 0; + msg->getU32Fast(_PREHASH_RegionInfo, _PREHASH_RegionFlags, flags); + region_flags = flags; + } + + setRegionFlags(region_flags); + setRegionProtocols(region_protocols); + setSimAccess(sim_access); + setRegionNameAndZone(sim_name); + setOwner(sim_owner); + setIsEstateManager(is_estate_manager); + setWaterHeight(water_height); + setBillableFactor(billable_factor); + setCacheID(cache_id); + + LLUUID region_id; + msg->getUUID("RegionInfo2", "RegionID", region_id); + setRegionID(region_id); + + // Retrieve the CR-53 (Homestead/Land SKU) information + S32 classID = 0; + S32 cpuRatio = 0; + std::string coloName; + std::string productSKU; + std::string productName; + + // the only reasonable way to decide if we actually have any data is to + // check to see if any of these fields have positive sizes + if (msg->getSize("RegionInfo3", "ColoName") > 0 || + msg->getSize("RegionInfo3", "ProductSKU") > 0 || + msg->getSize("RegionInfo3", "ProductName") > 0) + { + msg->getS32 ("RegionInfo3", "CPUClassID", classID); + msg->getS32 ("RegionInfo3", "CPURatio", cpuRatio); + msg->getString ("RegionInfo3", "ColoName", coloName); + msg->getString ("RegionInfo3", "ProductSKU", productSKU); + msg->getString ("RegionInfo3", "ProductName", productName); + + mClassID = classID; + mCPURatio = cpuRatio; + mColoName = coloName; + mProductSKU = productSKU; + mProductName = productName; + } + + mCentralBakeVersion = region_protocols & 1; // was (S32)gSavedSettings.getBOOL("UseServerTextureBaking"); + LLVLComposition *compp = getComposition(); + if (compp) + { + LLUUID tmp_id; + + bool changed = false; + + // Get the 4 textures for land + msg->getUUID("RegionInfo", "TerrainDetail0", tmp_id); + changed |= (tmp_id != compp->getDetailTextureID(0)); + compp->setDetailTextureID(0, tmp_id); + + msg->getUUID("RegionInfo", "TerrainDetail1", tmp_id); + changed |= (tmp_id != compp->getDetailTextureID(1)); + compp->setDetailTextureID(1, tmp_id); + + msg->getUUID("RegionInfo", "TerrainDetail2", tmp_id); + changed |= (tmp_id != compp->getDetailTextureID(2)); + compp->setDetailTextureID(2, tmp_id); + + msg->getUUID("RegionInfo", "TerrainDetail3", tmp_id); + changed |= (tmp_id != compp->getDetailTextureID(3)); + compp->setDetailTextureID(3, tmp_id); + + // Get the start altitude and range values for land textures + F32 tmp_f32; + msg->getF32("RegionInfo", "TerrainStartHeight00", tmp_f32); + changed |= (tmp_f32 != compp->getStartHeight(0)); + compp->setStartHeight(0, tmp_f32); + + msg->getF32("RegionInfo", "TerrainStartHeight01", tmp_f32); + changed |= (tmp_f32 != compp->getStartHeight(1)); + compp->setStartHeight(1, tmp_f32); + + msg->getF32("RegionInfo", "TerrainStartHeight10", tmp_f32); + changed |= (tmp_f32 != compp->getStartHeight(2)); + compp->setStartHeight(2, tmp_f32); + + msg->getF32("RegionInfo", "TerrainStartHeight11", tmp_f32); + changed |= (tmp_f32 != compp->getStartHeight(3)); + compp->setStartHeight(3, tmp_f32); + + + msg->getF32("RegionInfo", "TerrainHeightRange00", tmp_f32); + changed |= (tmp_f32 != compp->getHeightRange(0)); + compp->setHeightRange(0, tmp_f32); + + msg->getF32("RegionInfo", "TerrainHeightRange01", tmp_f32); + changed |= (tmp_f32 != compp->getHeightRange(1)); + compp->setHeightRange(1, tmp_f32); + + msg->getF32("RegionInfo", "TerrainHeightRange10", tmp_f32); + changed |= (tmp_f32 != compp->getHeightRange(2)); + compp->setHeightRange(2, tmp_f32); + + msg->getF32("RegionInfo", "TerrainHeightRange11", tmp_f32); + changed |= (tmp_f32 != compp->getHeightRange(3)); + compp->setHeightRange(3, tmp_f32); + + // If this is an UPDATE (params already ready, we need to regenerate + // all of our terrain stuff, by + if (compp->getParamsReady()) + { + // Update if the land changed + if (changed) + { + getLand().dirtyAllPatches(); + } + } + else + { + compp->setParamsReady(); + } + } + + + // Now that we have the name, we can load the cache file + // off disk. + loadObjectCache(); + + // After loading cache, signal that simulator can start + // sending data. + // TODO: Send all upstream viewer->sim handshake info here. + LLHost host = msg->getSender(); + msg->newMessage("RegionHandshakeReply"); + msg->nextBlock("AgentData"); + msg->addUUID("AgentID", gAgent.getID()); + msg->addUUID("SessionID", gAgent.getSessionID()); + msg->nextBlock("RegionInfo"); + + U32 flags = 0; + flags |= REGION_HANDSHAKE_SUPPORTS_SELF_APPEARANCE; + + if(sVOCacheCullingEnabled) + { + flags |= 0x00000001; //set the bit 0 to be 1 to ask sim to send all cacheable objects. + } + if(mImpl->mCacheMap.empty()) + { + flags |= 0x00000002; //set the bit 1 to be 1 to tell sim the cache file is empty, no need to send cache probes. + } + msg->addU32("Flags", flags ); + msg->sendReliable(host); + + mRegionTimer.reset(); //reset region timer. +} + +// static +void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) +{ + capabilityNames.append("AbuseCategories"); + capabilityNames.append("AcceptFriendship"); + capabilityNames.append("AcceptGroupInvite"); // ReadOfflineMsgs recieved messages only!!! + capabilityNames.append("AgentPreferences"); + capabilityNames.append("AgentProfile"); + capabilityNames.append("AgentState"); + capabilityNames.append("AttachmentResources"); + capabilityNames.append("AvatarPickerSearch"); + capabilityNames.append("AvatarRenderInfo"); + capabilityNames.append("CharacterProperties"); + capabilityNames.append("ChatSessionRequest"); + capabilityNames.append("CopyInventoryFromNotecard"); + capabilityNames.append("CreateInventoryCategory"); + capabilityNames.append("DeclineFriendship"); + capabilityNames.append("DeclineGroupInvite"); // ReadOfflineMsgs recieved messages only!!! + capabilityNames.append("DispatchRegionInfo"); + capabilityNames.append("DirectDelivery"); + capabilityNames.append("EnvironmentSettings"); + capabilityNames.append("EstateAccess"); + capabilityNames.append("EstateChangeInfo"); + capabilityNames.append("EventQueueGet"); + capabilityNames.append("ExtEnvironment"); + + capabilityNames.append("FetchLib2"); + capabilityNames.append("FetchLibDescendents2"); + capabilityNames.append("FetchInventory2"); + capabilityNames.append("FetchInventoryDescendents2"); + capabilityNames.append("IncrementCOFVersion"); + AISAPI::getCapNames(capabilityNames); + + capabilityNames.append("InterestList"); + + capabilityNames.append("InventoryThumbnailUpload"); + capabilityNames.append("GetDisplayNames"); + capabilityNames.append("GetExperiences"); + capabilityNames.append("AgentExperiences"); + capabilityNames.append("FindExperienceByName"); + capabilityNames.append("GetExperienceInfo"); + capabilityNames.append("GetAdminExperiences"); + capabilityNames.append("GetCreatorExperiences"); + capabilityNames.append("ExperiencePreferences"); + capabilityNames.append("GroupExperiences"); + capabilityNames.append("UpdateExperience"); + capabilityNames.append("IsExperienceAdmin"); + capabilityNames.append("IsExperienceContributor"); + capabilityNames.append("RegionExperiences"); + capabilityNames.append("ExperienceQuery"); + capabilityNames.append("GetMetadata"); + capabilityNames.append("GetObjectCost"); + capabilityNames.append("GetObjectPhysicsData"); + capabilityNames.append("GroupAPIv1"); + capabilityNames.append("GroupMemberData"); + capabilityNames.append("GroupProposalBallot"); + capabilityNames.append("HomeLocation"); + capabilityNames.append("LandResources"); + capabilityNames.append("LSLSyntax"); + capabilityNames.append("MapLayer"); + capabilityNames.append("MapLayerGod"); + capabilityNames.append("MeshUploadFlag"); + capabilityNames.append("ModifyMaterialParams"); + capabilityNames.append("NavMeshGenerationStatus"); + capabilityNames.append("NewFileAgentInventory"); + capabilityNames.append("ObjectAnimation"); + capabilityNames.append("ObjectMedia"); + capabilityNames.append("ObjectMediaNavigate"); + capabilityNames.append("ObjectNavMeshProperties"); + capabilityNames.append("ParcelPropertiesUpdate"); + capabilityNames.append("ParcelVoiceInfoRequest"); + capabilityNames.append("ProductInfoRequest"); + capabilityNames.append("ProvisionVoiceAccountRequest"); + capabilityNames.append("ReadOfflineMsgs"); // Requires to respond reliably: AcceptFriendship, AcceptGroupInvite, DeclineFriendship, DeclineGroupInvite + capabilityNames.append("RegionObjects"); + capabilityNames.append("RemoteParcelRequest"); + capabilityNames.append("RenderMaterials"); + capabilityNames.append("RequestTextureDownload"); + capabilityNames.append("ResourceCostSelected"); + capabilityNames.append("RetrieveNavMeshSrc"); + capabilityNames.append("SearchStatRequest"); + capabilityNames.append("SearchStatTracking"); + capabilityNames.append("SendPostcard"); + capabilityNames.append("SendUserReport"); + capabilityNames.append("SendUserReportWithScreenshot"); + capabilityNames.append("ServerReleaseNotes"); + capabilityNames.append("SetDisplayName"); + capabilityNames.append("SimConsoleAsync"); + capabilityNames.append("SimulatorFeatures"); + capabilityNames.append("StartGroupProposal"); + capabilityNames.append("TerrainNavMeshProperties"); + capabilityNames.append("TextureStats"); + capabilityNames.append("UntrustedSimulatorMessage"); + capabilityNames.append("UpdateAgentInformation"); + capabilityNames.append("UpdateAgentLanguage"); + capabilityNames.append("UpdateAvatarAppearance"); + capabilityNames.append("UpdateGestureAgentInventory"); + capabilityNames.append("UpdateGestureTaskInventory"); + capabilityNames.append("UpdateNotecardAgentInventory"); + capabilityNames.append("UpdateNotecardTaskInventory"); + capabilityNames.append("UpdateScriptAgent"); + capabilityNames.append("UpdateScriptTask"); + capabilityNames.append("UpdateSettingsAgentInventory"); + capabilityNames.append("UpdateSettingsTaskInventory"); + capabilityNames.append("UploadAgentProfileImage"); + capabilityNames.append("UpdateMaterialAgentInventory"); + capabilityNames.append("UpdateMaterialTaskInventory"); + capabilityNames.append("UploadBakedTexture"); + capabilityNames.append("UserInfo"); + capabilityNames.append("ViewerAsset"); + capabilityNames.append("ViewerBenefits"); + capabilityNames.append("ViewerMetrics"); + capabilityNames.append("ViewerStartAuction"); + capabilityNames.append("ViewerStats"); + + // Please add new capabilities alphabetically to reduce + // merge conflicts. +} + +void LLViewerRegion::setSeedCapability(const std::string& url) +{ + if (getCapability("Seed") == url) + { + setCapabilityDebug("Seed", url); + LL_WARNS("CrossingCaps") << "Received duplicate seed capability for " << getRegionID() << ", posting to seed " << + url << LL_ENDL; + + //Instead of just returning we build up a second set of seed caps and compare them + //to the "original" seed cap received and determine why there is problem! + std::string coroname = + LLCoros::instance().launch("LLEnvironmentRequest::requestBaseCapabilitiesCompleteCoro", + boost::bind(&LLViewerRegionImpl::requestBaseCapabilitiesCompleteCoro, getHandle())); + + // setSeedCapability can be called from other coros, + // launch() acts like a suspend() + // Make sure we are still good to do + LLCoros::checkStop(); + + return; + } + + delete mImpl->mEventPoll; + mImpl->mEventPoll = NULL; + + mImpl->mCapabilities.clear(); + setCapability("Seed", url); + + std::string coroname = + LLCoros::instance().launch("LLViewerRegionImpl::requestBaseCapabilitiesCoro", + boost::bind(&LLViewerRegionImpl::requestBaseCapabilitiesCoro, getHandle())); + + // setSeedCapability can be called from other coros, + // launch() acts like a suspend() + // Make sure we are still good to do + LLCoros::checkStop(); + + LL_INFOS("AppInit", "Capabilities") << "Launching " << coroname << " requesting seed capabilities from " << url << " for region " << getRegionID() << LL_ENDL; +} + +S32 LLViewerRegion::getNumSeedCapRetries() +{ + return mImpl->mSeedCapAttempts; +} + +void LLViewerRegion::setCapability(const std::string& name, const std::string& url) +{ + if(name == "EventQueueGet") + { + delete mImpl->mEventPoll; + mImpl->mEventPoll = NULL; + mImpl->mEventPoll = new LLEventPoll(url, getHost()); + } + else if(name == "UntrustedSimulatorMessage") + { + mImpl->mHost.setUntrustedSimulatorCap(url); + } + else if (name == "SimulatorFeatures") + { + mImpl->mCapabilities["SimulatorFeatures"] = url; + requestSimulatorFeatures(); + } + else + { + mImpl->mCapabilities[name] = url; + if(name == "ViewerAsset") + { + /*==============================================================*/ + // The following inserted lines are a hack for testing MAINT-7081, + // which is why the indentation and formatting are left ugly. + const char* VIEWERASSET = getenv("VIEWERASSET"); + if (VIEWERASSET) + { + mImpl->mCapabilities[name] = VIEWERASSET; + mViewerAssetUrl = VIEWERASSET; + } + else + /*==============================================================*/ + mViewerAssetUrl = url; + } + } +} + +void LLViewerRegion::setCapabilityDebug(const std::string& name, const std::string& url) +{ + // Continue to not add certain caps, as we do in setCapability. This is so they match up when we check them later. + if ( ! ( name == "EventQueueGet" || name == "UntrustedSimulatorMessage" || name == "SimulatorFeatures" ) ) + { + mImpl->mSecondCapabilitiesTracker[name] = url; + if(name == "ViewerAsset") + { + /*==============================================================*/ + // The following inserted lines are a hack for testing MAINT-7081, + // which is why the indentation and formatting are left ugly. + const char* VIEWERASSET = getenv("VIEWERASSET"); + if (VIEWERASSET) + { + mImpl->mSecondCapabilitiesTracker[name] = VIEWERASSET; + mViewerAssetUrl = VIEWERASSET; + } + else + /*==============================================================*/ + mViewerAssetUrl = url; + } + } +} + +std::string LLViewerRegion::getCapabilityDebug(const std::string& name) const +{ + CapabilityMap::const_iterator iter = mImpl->mSecondCapabilitiesTracker.find(name); + if (iter == mImpl->mSecondCapabilitiesTracker.end()) + { + return ""; + } + + return iter->second; +} + + +bool LLViewerRegion::isSpecialCapabilityName(const std::string &name) +{ + return name == "EventQueueGet" || name == "UntrustedSimulatorMessage"; +} + +std::string LLViewerRegion::getCapability(const std::string& name) const +{ + if (!capabilitiesReceived() && (name!=std::string("Seed")) && (name!=std::string("ObjectMedia"))) + { + LL_WARNS() << "getCapability called before caps received for " << name << LL_ENDL; + } + + CapabilityMap::const_iterator iter = mImpl->mCapabilities.find(name); + if(iter == mImpl->mCapabilities.end()) + { + return ""; + } + + return iter->second; +} + +bool LLViewerRegion::isCapabilityAvailable(const std::string& name) const +{ + if (!capabilitiesReceived() && (name!=std::string("Seed")) && (name!=std::string("ObjectMedia"))) + { + LL_WARNS() << "isCapabilityAvailable called before caps received for " << name << LL_ENDL; + } + + CapabilityMap::const_iterator iter = mImpl->mCapabilities.find(name); + if(iter == mImpl->mCapabilities.end()) + { + return false; + } + + return true; +} + +bool LLViewerRegion::capabilitiesReceived() const +{ + return mCapabilitiesState == CAPABILITIES_STATE_RECEIVED; +} + +bool LLViewerRegion::capabilitiesError() const +{ + return mCapabilitiesState == CAPABILITIES_STATE_ERROR; +} + +void LLViewerRegion::setCapabilitiesReceived(bool received) +{ + mCapabilitiesState = received ? CAPABILITIES_STATE_RECEIVED : CAPABILITIES_STATE_INIT; + + // Tell interested parties that we've received capabilities, + // so that they can safely use getCapability(). + if (received) + { + mCapabilitiesReceivedSignal(getRegionID(), this); + + LLFloaterPermsDefault::sendInitialPerms(); + + // This is a single-shot signal. Forget callbacks to save resources. + mCapabilitiesReceivedSignal.disconnect_all_slots(); + + // Set the region to the desired interest list mode + setInterestListMode(gAgent.getInterestListMode()); + } +} + +void LLViewerRegion::setCapabilitiesError() +{ + mCapabilitiesState = CAPABILITIES_STATE_ERROR; +} + +boost::signals2::connection LLViewerRegion::setCapabilitiesReceivedCallback(const caps_received_signal_t::slot_type& cb) +{ + return mCapabilitiesReceivedSignal.connect(cb); +} + +void LLViewerRegion::logActiveCapabilities() const +{ + log_capabilities(mImpl->mCapabilities); +} + + +bool LLViewerRegion::requestPostCapability(const std::string &capName, LLSD &postData, httpCallback_t cbSuccess, httpCallback_t cbFailure) +{ + std::string url = getCapability(capName); + + if (url.empty()) + { + LL_WARNS("Region") << "Could not retrieve region " << getRegionID() + << " POST capability \"" << capName << "\"" << LL_ENDL; + return false; + } + + LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpPost(url, gAgent.getAgentPolicy(), postData, cbSuccess, cbFailure); + return true; +} + +bool LLViewerRegion::requestGetCapability(const std::string &capName, httpCallback_t cbSuccess, httpCallback_t cbFailure) +{ + std::string url; + + url = getCapability(capName); + + if (url.empty()) + { + LL_WARNS("Region") << "Could not retrieve region " << getRegionID() + << " GET capability \"" << capName << "\"" << LL_ENDL; + return false; + } + + LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpGet(url, gAgent.getAgentPolicy(), cbSuccess, cbFailure); + return true; +} + +bool LLViewerRegion::requestDelCapability(const std::string &capName, httpCallback_t cbSuccess, httpCallback_t cbFailure) +{ + std::string url; + + url = getCapability(capName); + + if (url.empty()) + { + LL_WARNS("Region") << "Could not retrieve region " << getRegionID() << " DEL capability \"" << capName << "\"" << LL_ENDL; + return false; + } + + LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpDel(url, gAgent.getAgentPolicy(), cbSuccess, cbFailure); + return true; +} + +void LLViewerRegion::setInterestListMode(const std::string &new_mode) +{ + if (new_mode != mInterestListMode) + { + mInterestListMode = new_mode; + + if (mInterestListMode != IL_MODE_DEFAULT && mInterestListMode != IL_MODE_360) + { + LL_WARNS("360Capture") << "Region " << getRegionID() << " setInterestListMode() invalid interest list mode: " + << mInterestListMode << ", setting to default" << LL_ENDL; + mInterestListMode = IL_MODE_DEFAULT; + } + + LLSD body; + body["mode"] = mInterestListMode; + if (requestPostCapability("InterestList", body, + [](const LLSD &response) { + LL_DEBUGS("360Capture") << "InterestList capability responded: \n" + << ll_pretty_print_sd(response) << LL_ENDL; + })) + { + LL_DEBUGS("360Capture") << "Region " << getRegionID() + << " Successfully posted an InterestList capability request with payload: \n" + << ll_pretty_print_sd(body) << LL_ENDL; + } + else + { + LL_WARNS("360Capture") << "Region " << getRegionID() + << " Unable to post an InterestList capability request with payload: \n" + << ll_pretty_print_sd(body) << LL_ENDL; + } + } + else + { + LL_DEBUGS("360Capture") << "Region " << getRegionID() << "No change, skipping Interest List mode POST to " + << new_mode << " mode" << LL_ENDL; + } +} + + +void LLViewerRegion::resetInterestList() +{ + if (requestDelCapability("InterestList", [](const LLSD &response) { + LL_DEBUGS("360Capture") << "InterestList capability DEL responded: \n" << ll_pretty_print_sd(response) << LL_ENDL; + })) + { + LL_DEBUGS("360Capture") << "Region " << getRegionID() << " Successfully reset InterestList capability" << LL_ENDL; + } + else + { + LL_WARNS("360Capture") << "Region " << getRegionID() << " Unable to DEL InterestList capability request" << LL_ENDL; + } +} + + +LLSpatialPartition *LLViewerRegion::getSpatialPartition(U32 type) +{ + if (type < mImpl->mObjectPartition.size() && type < PARTITION_VO_CACHE) + { + return (LLSpatialPartition*)mImpl->mObjectPartition[type]; + } + return NULL; +} + +LLVOCachePartition* LLViewerRegion::getVOCachePartition() +{ + if(PARTITION_VO_CACHE < mImpl->mObjectPartition.size()) + { + return (LLVOCachePartition*)mImpl->mObjectPartition[PARTITION_VO_CACHE]; + } + return NULL; +} + +// the viewer can not yet distinquish between normal- and estate-owned objects +// so we collapse these two bits and enable the UI if either are set +const U64 ALLOW_RETURN_ENCROACHING_OBJECT = REGION_FLAGS_ALLOW_RETURN_ENCROACHING_OBJECT + | REGION_FLAGS_ALLOW_RETURN_ENCROACHING_ESTATE_OBJECT; + +bool LLViewerRegion::objectIsReturnable(const LLVector3& pos, const std::vector<LLBBox>& boxes) const +{ + return (mParcelOverlay != NULL) + && (mParcelOverlay->isOwnedSelf(pos) + || mParcelOverlay->isOwnedGroup(pos) + || (getRegionFlag(ALLOW_RETURN_ENCROACHING_OBJECT) + && mParcelOverlay->encroachesOwned(boxes)) ); +} + +bool LLViewerRegion::childrenObjectReturnable( const std::vector<LLBBox>& boxes ) const +{ + bool result = false; + result = ( mParcelOverlay && mParcelOverlay->encroachesOnUnowned( boxes ) ) ? 1 : 0; + return result; +} + +bool LLViewerRegion::objectsCrossParcel(const std::vector<LLBBox>& boxes) const +{ + return mParcelOverlay && mParcelOverlay->encroachesOnNearbyParcel(boxes); +} + +void LLViewerRegion::getNeighboringRegions( std::vector<LLViewerRegion*>& uniqueRegions ) +{ + mImpl->mLandp->getNeighboringRegions( uniqueRegions ); +} +void LLViewerRegion::getNeighboringRegionsStatus( std::vector<S32>& regions ) +{ + mImpl->mLandp->getNeighboringRegionsStatus( regions ); +} +void LLViewerRegion::showReleaseNotes() +{ + std::string url = this->getCapability("ServerReleaseNotes"); + + if (url.empty()) { + // HACK haven't received the capability yet, we'll wait until + // it arives. + mReleaseNotesRequested = true; + return; + } + + LLWeb::loadURL(url); + mReleaseNotesRequested = false; +} + +std::string LLViewerRegion::getDescription() const +{ + return stringize(*this); +} + +bool LLViewerRegion::meshUploadEnabled() const +{ + return (mSimulatorFeatures.has("MeshUploadEnabled") && + mSimulatorFeatures["MeshUploadEnabled"].asBoolean()); +} + +bool LLViewerRegion::bakesOnMeshEnabled() const +{ + return (mSimulatorFeatures.has("BakesOnMeshEnabled") && + mSimulatorFeatures["BakesOnMeshEnabled"].asBoolean()); +} + +bool LLViewerRegion::meshRezEnabled() const +{ + return (mSimulatorFeatures.has("MeshRezEnabled") && + mSimulatorFeatures["MeshRezEnabled"].asBoolean()); +} + +bool LLViewerRegion::dynamicPathfindingEnabled() const +{ + return ( mSimulatorFeatures.has("DynamicPathfindingEnabled") && + mSimulatorFeatures["DynamicPathfindingEnabled"].asBoolean()); +} + +bool LLViewerRegion::avatarHoverHeightEnabled() const +{ + return ( mSimulatorFeatures.has("AvatarHoverHeightEnabled") && + mSimulatorFeatures["AvatarHoverHeightEnabled"].asBoolean()); +} +/* Static Functions */ + +void log_capabilities(const CapabilityMap &capmap) +{ + S32 count = 0; + CapabilityMap::const_iterator iter; + for (iter = capmap.begin(); iter != capmap.end(); ++iter, ++count) + { + if (!iter->second.empty()) + { + LL_INFOS() << "log_capabilities: " << iter->first << " URL is " << iter->second << LL_ENDL; + } + } + LL_INFOS() << "log_capabilities: Dumped " << count << " entries." << LL_ENDL; +} +void LLViewerRegion::resetMaterialsCapThrottle() +{ + F32 requests_per_sec = 1.0f; // original default; + if ( mSimulatorFeatures.has("RenderMaterialsCapability") + && mSimulatorFeatures["RenderMaterialsCapability"].isReal() ) + { + requests_per_sec = mSimulatorFeatures["RenderMaterialsCapability"].asReal(); + if ( requests_per_sec == 0.0f ) + { + requests_per_sec = 1.0f; + LL_WARNS("Materials") + << "region '" << getName() + << "' returned zero for RenderMaterialsCapability; using default " + << requests_per_sec << " per second" + << LL_ENDL; + } + LL_DEBUGS("Materials") << "region '" << getName() + << "' RenderMaterialsCapability " << requests_per_sec + << LL_ENDL; + } + else + { + LL_DEBUGS("Materials") + << "region '" << getName() + << "' did not return RenderMaterialsCapability, using default " + << requests_per_sec << " per second" + << LL_ENDL; + } + + mMaterialsCapThrottleTimer.resetWithExpiry( 1.0f / requests_per_sec ); +} + +U32 LLViewerRegion::getMaxMaterialsPerTransaction() const +{ + U32 max_entries = 50; // original hard coded default + if ( mSimulatorFeatures.has( "MaxMaterialsPerTransaction" ) + && mSimulatorFeatures[ "MaxMaterialsPerTransaction" ].isInteger()) + { + max_entries = mSimulatorFeatures[ "MaxMaterialsPerTransaction" ].asInteger(); + } + return max_entries; +} + +std::string LLViewerRegion::getSimHostName() +{ + if (mSimulatorFeaturesReceived) + { + return mSimulatorFeatures.has("HostName") ? mSimulatorFeatures["HostName"].asString() : getHost().getHostName(); + } + return std::string("..."); +} + +void LLViewerRegion::applyCacheMiscExtras(LLViewerObject* obj) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY; + llassert(obj); + + U32 local_id = obj->getLocalID(); + auto iter = mImpl->mGLTFOverridesLLSD.find(local_id); + if (iter != mImpl->mGLTFOverridesLLSD.end()) + { + llassert(iter->second.mGLTFMaterial.size() == iter->second.mSides.size()); + + for (auto& side : iter->second.mGLTFMaterial) + { + obj->setTEGLTFMaterialOverride(side.first, side.second); + } + } +} + |