From 5b80b00dcd3cf4e2dfec7dcd3e808866aad49095 Mon Sep 17 00:00:00 2001 From: Oz Linden Date: Mon, 16 Apr 2012 22:01:27 -0400 Subject: storm-1843: remove unused ParcelMediaURLFilter capability --- indra/newview/llviewerregion.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'indra/newview/llviewerregion.cpp') diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index e3cb985ddb..a43a6c6d7d 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -1522,7 +1522,6 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) capabilityNames.append("MeshUploadFlag"); capabilityNames.append("NewFileAgentInventory"); capabilityNames.append("ParcelPropertiesUpdate"); - capabilityNames.append("ParcelMediaURLFilterList"); capabilityNames.append("ParcelNavigateMedia"); capabilityNames.append("ParcelVoiceInfoRequest"); capabilityNames.append("ProductInfoRequest"); -- cgit v1.3 From de2ce3f51ff54e67017d765c95264c66211c89da Mon Sep 17 00:00:00 2001 From: Chris Baker Date: Thu, 23 Aug 2012 19:40:10 -0700 Subject: Start of getting WSGI service on viewer --- indra/newview/llgroupmgr.cpp | 91 + indra/newview/llgroupmgr.h | 3 + indra/newview/llpanelgroupgeneral.cpp | 9 +- indra/newview/llpanelgroupinvite.cpp | 9 +- indra/newview/llpanelgrouproles.cpp | 22 +- indra/newview/llviewerregion.cpp | 3739 ++++++++++++++++----------------- 6 files changed, 1997 insertions(+), 1876 deletions(-) (limited to 'indra/newview/llviewerregion.cpp') diff --git a/indra/newview/llgroupmgr.cpp b/indra/newview/llgroupmgr.cpp index aceb7f0614..3300034f7f 100644 --- a/indra/newview/llgroupmgr.cpp +++ b/indra/newview/llgroupmgr.cpp @@ -1500,6 +1500,10 @@ void LLGroupMgr::sendGroupMembersRequest(const LLUUID& group_id) } } + + + + void LLGroupMgr::sendGroupRoleDataRequest(const LLUUID& group_id) { lldebugs << "LLGroupMgr::sendGroupRoleDataRequest" << llendl; @@ -1832,6 +1836,93 @@ void LLGroupMgr::sendGroupMemberEjects(const LLUUID& group_id, } } + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +// STUBBED IN FOR code completion +class GroupMemberDataResponder : public LLHTTPClient::Responder +{ +public: + GroupMemberDataResponder() {} + virtual ~GroupMemberDataResponder() {} + virtual void result(const LLSD& pContent); + virtual void error(U32 pStatus, const std::string& pReason) {} +private: + LLSD mMemberData; +}; + +void GroupMemberDataResponder::result(const LLSD& pContent) +{ + LL_INFOS("BAKER") << "BAKER TAG ////////////////////////////////////////////////////////////////" << LL_ENDL; + // Did we get anything in pContent? + if(pContent.size()) + { + LL_INFOS("BAKER") << "Lik dis if u cry evertim" << LL_ENDL; + + // BAKER TODO: + // Figure out what to do with all the dataz. + // Looks like processGroupMembersReply does the work + LLUUID agent_id = pContent["agent_id"]; + LLUUID group_id = pContent["group_id"]; + LLSD member_list = pContent["members"]; + LLSD titles = pContent["titles"]; + LLSD defaults = pContent["defaults"]; + + int i = 0; + ++i; + + + + } + else + { + LL_INFOS("BAKER") << "WE AIN'T FOUND SHIT!" << LL_ENDL; + + // BAKER TODO: + // Handle this case + + } + LL_INFOS("BAKER") << "//////////////////////////////////////////////////////////////////////////\n" << LL_ENDL; +} + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +// BAKER +// static +void LLGroupMgr::sendCapGroupMembersRequest(const LLUUID& group_id) +{ + //sendGroupMembersRequest(group_id); + //return; + +#if 1 + LLViewerRegion* currentRegion = gAgent.getRegion(); + + // Check to make sure we have our capabilities + if(!currentRegion->capabilitiesReceived()) + { + LL_INFOS("BAKER") << " Capabilities not received! -- OSHITSON --" << LL_ENDL; + // BAKER TODO: Handle this! + } + + // Get our capability + std::string cap_url = currentRegion->getCapability("GroupMemberData"); + + // Post to our service. Add a body containing the group_id. + LLSD body = LLSD::emptyMap(); + body["group_id"] = group_id; + + LLHTTPClient::ResponderPtr grp_data_responder = new GroupMemberDataResponder(); + // This could take a while to finish, timeout after 10 minutes. + LLHTTPClient::post(cap_url, body, grp_data_responder, LLSD(), 600); +#endif +} +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + + void LLGroupMgr::sendGroupRoleChanges(const LLUUID& group_id) { lldebugs << "LLGroupMgr::sendGroupRoleChanges" << llendl; diff --git a/indra/newview/llgroupmgr.h b/indra/newview/llgroupmgr.h index df3cd17e03..5b535f5056 100644 --- a/indra/newview/llgroupmgr.h +++ b/indra/newview/llgroupmgr.h @@ -340,6 +340,9 @@ public: static void sendGroupMemberEjects(const LLUUID& group_id, uuid_vec_t& member_ids); + // BAKER + void sendCapGroupMembersRequest(const LLUUID& group_id); + void cancelGroupRoleChanges(const LLUUID& group_id); static void processGroupPropertiesReply(LLMessageSystem* msg, void** data); diff --git a/indra/newview/llpanelgroupgeneral.cpp b/indra/newview/llpanelgroupgeneral.cpp index bc594b5517..fa5f5574dc 100644 --- a/indra/newview/llpanelgroupgeneral.cpp +++ b/indra/newview/llpanelgroupgeneral.cpp @@ -317,7 +317,12 @@ void LLPanelGroupGeneral::activate() if (!gdatap || !gdatap->isMemberDataComplete() ) { - LLGroupMgr::getInstance()->sendGroupMembersRequest(mGroupID); + ////////////////////////////////////////////////////////////////////////// + // BAKER TODO: + // Use cap here! + ////////////////////////////////////////////////////////////////////////// + LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mGroupID); + //LLGroupMgr::getInstance()->sendGroupMembersRequest(mGroupID); } mFirstUse = FALSE; @@ -714,7 +719,7 @@ void LLPanelGroupGeneral::updateMembers() for( ; mMemberProgress != gdatap->mMembers.end() && ifirst << ", " << iter->second->getTitle() << llendl; + llinfos << "Adding " << mMemberProgress->first << ", " << mMemberProgress->second->getTitle() << llendl; LLGroupMemberData* member = mMemberProgress->second; if (!member) { diff --git a/indra/newview/llpanelgroupinvite.cpp b/indra/newview/llpanelgroupinvite.cpp index 00dd206571..f05358bf59 100644 --- a/indra/newview/llpanelgroupinvite.cpp +++ b/indra/newview/llpanelgroupinvite.cpp @@ -570,7 +570,14 @@ void LLPanelGroupInvite::updateLists() if (!mPendingUpdate) { LLGroupMgr::getInstance()->sendGroupPropertiesRequest(mImplementation->mGroupID); - LLGroupMgr::getInstance()->sendGroupMembersRequest(mImplementation->mGroupID); + + ////////////////////////////////////////////////////////////////////////// + // BAKER TODO: + // Use cap here! + ////////////////////////////////////////////////////////////////////////// + LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mImplementation->mGroupID); + //LLGroupMgr::getInstance()->sendGroupMembersRequest(mImplementation->mGroupID); + LLGroupMgr::getInstance()->sendGroupRoleDataRequest(mImplementation->mGroupID); } mPendingUpdate = TRUE; diff --git a/indra/newview/llpanelgrouproles.cpp b/indra/newview/llpanelgrouproles.cpp index f825ee3215..9b0fb37693 100644 --- a/indra/newview/llpanelgrouproles.cpp +++ b/indra/newview/llpanelgrouproles.cpp @@ -356,7 +356,12 @@ void LLPanelGroupRoles::activate() if (!gdatap || !gdatap->isMemberDataComplete() ) { - LLGroupMgr::getInstance()->sendGroupMembersRequest(mGroupID); + ////////////////////////////////////////////////////////////////////////// + // BAKER TODO: + // Use cap here! + ////////////////////////////////////////////////////////////////////////// + LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mGroupID); + //LLGroupMgr::getInstance()->sendGroupMembersRequest(mGroupID); } // Check role data. @@ -1987,7 +1992,12 @@ void LLPanelGroupRolesSubTab::update(LLGroupChange gc) if (!gdatap || !gdatap->isMemberDataComplete()) { - LLGroupMgr::getInstance()->sendGroupMembersRequest(mGroupID); + ////////////////////////////////////////////////////////////////////////// + // BAKER TODO: + // Use cap here! + ////////////////////////////////////////////////////////////////////////// + LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mGroupID); + //LLGroupMgr::getInstance()->sendGroupMembersRequest(mGroupID); } if (!gdatap || !gdatap->isRoleMemberDataComplete()) @@ -2580,7 +2590,12 @@ void LLPanelGroupActionsSubTab::handleActionSelect() } else { - LLGroupMgr::getInstance()->sendGroupMembersRequest(mGroupID); + ////////////////////////////////////////////////////////////////////////// + // BAKER TODO: + // Use cap here! + ////////////////////////////////////////////////////////////////////////// + LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mGroupID); + //LLGroupMgr::getInstance()->sendGroupMembersRequest(mGroupID); } if (gdatap->isRoleDataComplete()) @@ -2604,6 +2619,7 @@ void LLPanelGroupActionsSubTab::handleActionSelect() LLGroupMgr::getInstance()->sendGroupRoleDataRequest(mGroupID); } } + void LLPanelGroupRoles::setGroupID(const LLUUID& id) { LLPanelGroupTab::setGroupID(id); diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index effa368b7a..c00d4e91d7 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -1,1870 +1,1869 @@ -/** - * @file llviewerregion.cpp - * @brief Implementation of the LLViewerRegion class. - * - * $LicenseInfo:firstyear=2000&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "llviewerregion.h" - -// linden libraries -#include "indra_constants.h" -#include "llavatarnamecache.h" // name lookup cap url -#include "llfloaterreg.h" -#include "llmath.h" -#include "llhttpclient.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 "llcallingcard.h" -#include "llcaphttpsender.h" -#include "llcapabilitylistener.h" -#include "llcommandhandler.h" -#include "lldir.h" -#include "lleventpoll.h" -#include "llfloatergodtools.h" -#include "llfloaterreporter.h" -#include "llfloaterregioninfo.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 "llvocache.h" -#include "llworld.h" -#include "llspatialpartition.h" -#include "stringize.h" -#include "llviewercontrol.h" -#include "llsdserialize.h" - -#ifdef LL_WINDOWS - #pragma warning(disable:4355) -#endif - -const F32 WATER_TEXTURE_SCALE = 8.f; // Number of times to repeat the water texture across a region -const S16 MAX_MAP_DIST = 10; -// 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. -// Give it 3 chances, each at 18 seconds to give ourselves a few seconds to connect anyways if we give up. -const S32 MAX_SEED_CAP_ATTEMPTS_BEFORE_LOGIN = 3; -const F32 CAP_REQUEST_TIMEOUT = 18; -// Even though we gave up on login, keep trying for caps after we are logged in: -const S32 MAX_CAP_REQUEST_ATTEMPTS = 30; - -typedef std::map CapabilityMap; - -class LLViewerRegionImpl { -public: - LLViewerRegionImpl(LLViewerRegion * region, LLHost const & host) - : mHost(host), - mCompositionp(NULL), - mEventPoll(NULL), - mSeedCapMaxAttempts(MAX_CAP_REQUEST_ATTEMPTS), - mSeedCapMaxAttemptsBeforeLogin(MAX_SEED_CAP_ATTEMPTS_BEFORE_LOGIN), - mSeedCapAttempts(0), - mHttpResponderID(0), - // I'd prefer to set the LLCapabilityListener name to match the region - // name -- it's disappointing that's not available at construction time. - // We could instead store an LLCapabilityListener*, making - // setRegionNameAndZone() replace the instance. Would that pose - // consistency problems? Can we even request a capability before calling - // setRegionNameAndZone()? - // For testability -- the new Michael Feathers paradigm -- - // LLCapabilityListener binds all the globals it expects to need at - // construction time. - mCapabilityListener(host.getString(), gMessageSystem, *region, - gAgent.getID(), gAgent.getSessionID()) - { - } - - 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; - // time? - // LRU info? - - // Cache ID is unique per-region, across renames, moving locations, - // etc. - LLUUID mCacheID; - - CapabilityMap mCapabilities; - - LLEventPoll* mEventPoll; - - S32 mSeedCapMaxAttempts; - S32 mSeedCapMaxAttemptsBeforeLogin; - S32 mSeedCapAttempts; - - S32 mHttpResponderID; - - /// Post an event to this LLCapabilityListener to invoke a capability message on - /// this LLViewerRegion's server - /// (https://wiki.lindenlab.com/wiki/Viewer:Messaging/Messaging_Notes#Capabilities) - LLCapabilityListener mCapabilityListener; - - //spatial partitions for objects in this region - std::vector mObjectPartition; -}; - -// 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, 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://"; - for (int i = 0; i < num_params; i++) - { - if (i > 0) - { - url += "/"; - } - url += params[i].asString(); - } - - // Process the SLapp as if it was a secondlife://{PLACE} SLurl - LLURLDispatcher::dispatch(url, "clicked", web, true); - return true; - } -}; -LLRegionHandler gRegionHandler; - -class BaseCapabilitiesComplete : public LLHTTPClient::Responder -{ - LOG_CLASS(BaseCapabilitiesComplete); -public: - BaseCapabilitiesComplete(U64 region_handle, S32 id) - : mRegionHandle(region_handle), mID(id) - { } - virtual ~BaseCapabilitiesComplete() - { } - - void error(U32 statusNum, const std::string& reason) - { - LL_WARNS2("AppInit", "Capabilities") << statusNum << ": " << reason << LL_ENDL; - LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); - if (regionp) - { - regionp->failedSeedCapability(); - } - } - - void result(const LLSD& content) - { - LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); - if(!regionp) //region was removed - { - LL_WARNS2("AppInit", "Capabilities") << "Received results for region that no longer exists!" << LL_ENDL; - return ; - } - if( mID != regionp->getHttpResponderID() ) // region is no longer referring to this responder - { - LL_WARNS2("AppInit", "Capabilities") << "Received results for a stale http responder!" << LL_ENDL; - return ; - } - - LLSD::map_const_iterator iter; - for(iter = content.beginMap(); iter != content.endMap(); ++iter) - { - regionp->setCapability(iter->first, iter->second); - LL_DEBUGS2("AppInit", "Capabilities") << "got capability for " - << iter->first << LL_ENDL; - - /* HACK we're waiting for the ServerReleaseNotes */ - if (iter->first == "ServerReleaseNotes" && regionp->getReleaseNotesRequested()) - { - regionp->showReleaseNotes(); - } - } - - regionp->setCapabilitiesReceived(true); - - if (STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState()) - { - LLStartUp::setStartupState( STATE_SEED_CAP_GRANTED ); - } - } - - static boost::intrusive_ptr build( U64 region_handle, S32 id ) - { - return boost::intrusive_ptr( - new BaseCapabilitiesComplete(region_handle, id) ); - } - -private: - U64 mRegionHandle; - S32 mID; -}; - - -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 ), - mSimAccess( SIM_ACCESS_MIN ), - mBillableFactor(1.0), - mMaxTasks(DEFAULT_MAX_REGION_WIDE_PRIM_COUNT), - mClassID(0), - mCPURatio(0), - mColoName("unknown"), - mProductSKU("unknown"), - mProductName("unknown"), - mHttpUrl(""), - mCacheLoaded(FALSE), - mCacheDirty(FALSE), - mReleaseNotesRequested(FALSE), - mCapabilitiesReceived(false) -{ - 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()); //PARTITION_HUD - mImpl->mObjectPartition.push_back(new LLTerrainPartition()); //PARTITION_TERRAIN - mImpl->mObjectPartition.push_back(new LLVoidWaterPartition()); //PARTITION_VOIDWATER - mImpl->mObjectPartition.push_back(new LLWaterPartition()); //PARTITION_WATER - mImpl->mObjectPartition.push_back(new LLTreePartition()); //PARTITION_TREE - mImpl->mObjectPartition.push_back(new LLParticlePartition()); //PARTITION_PARTICLE - mImpl->mObjectPartition.push_back(new LLGrassPartition()); //PARTITION_GRASS - mImpl->mObjectPartition.push_back(new LLVolumePartition()); //PARTITION_VOLUME - mImpl->mObjectPartition.push_back(new LLBridgePartition()); //PARTITION_BRIDGE - mImpl->mObjectPartition.push_back(new LLHUDParticlePartition());//PARTITION_HUD_PARTICLE - mImpl->mObjectPartition.push_back(NULL); //PARTITION_NONE -} - - -void LLViewerRegion::initStats() -{ - mImpl->mLastNetUpdate.reset(); - mPacketsIn = 0; - mBitsIn = 0; - mLastBitsIn = 0; - mLastPacketsIn = 0; - mPacketsOut = 0; - mLastPacketsOut = 0; - mPacketsLost = 0; - mLastPacketsLost = 0; - mPingDelay = 0; - mAlive = false; // can become false if circuit disconnects -} - -LLViewerRegion::~LLViewerRegion() -{ - 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); - - gObjectList.killObjects(this); - - delete mImpl->mCompositionp; - delete mParcelOverlay; - delete mImpl->mLandp; - delete mImpl->mEventPoll; - LLHTTPSender::clearSender(mImpl->mHost); - - saveObjectCache(); - - std::for_each(mImpl->mObjectPartition.begin(), mImpl->mObjectPartition.end(), DeletePointer()); - - delete mImpl; - mImpl = NULL; -} - -LLEventPump& LLViewerRegion::getCapAPI() const -{ - return mImpl->mCapabilityListener.getCapAPI(); -} - -/*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::hasInstance()) - { - LLVOCache::getInstance()->readFromCache(mHandle, mImpl->mCacheID, mImpl->mCacheMap) ; - } -} - - -void LLViewerRegion::saveObjectCache() -{ - if (!mCacheLoaded) - { - return; - } - - if (mImpl->mCacheMap.empty()) - { - return; - } - - if(LLVOCache::hasInstance()) - { - LLVOCache::getInstance()->writeToCache(mHandle, mImpl->mCacheID, mImpl->mCacheMap, mCacheDirty) ; - mCacheDirty = FALSE; - } - - for(LLVOCacheEntry::vocache_entry_map_t::iterator iter = mImpl->mCacheMap.begin(); iter != mImpl->mCacheMap.end(); ++iter) - { - delete iter->second; - } - mImpl->mCacheMap.clear(); -} - -void LLViewerRegion::sendMessage() -{ - gMessageSystem->sendMessage(mImpl->mHost); -} - -void LLViewerRegion::sendReliableMessage() -{ - gMessageSystem->sendReliable(mImpl->mHost); -} - -void LLViewerRegion::setFlags(BOOL b, U32 flags) -{ - if (b) - { - mRegionFlags |= flags; - } - else - { - mRegionFlags &= ~flags; - } -} - -void LLViewerRegion::setWaterHeight(F32 water_level) -{ - mImpl->mLandp->setWaterHeight(water_level); -} - -F32 LLViewerRegion::getWaterHeight() const -{ - return mImpl->mLandp->getWaterHeight(); -} - -BOOL LLViewerRegion::isVoiceEnabled() const -{ - return (getRegionFlags() & REGION_FLAGS_ALLOW_VOICE); -} - -void LLViewerRegion::setRegionFlags(U32 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(U32 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 - llinfos << "Processing region info" << llendl; - LLRegionInfoModel::instance().update(msg); - LLFloaterGodTools::processRegionInfo(msg); - LLFloaterRegionInfo::processRegionInfo(msg); - LLFloaterReporter::processRegionInfo(msg); -} - -void LLViewerRegion::setCacheID(const LLUUID& id) -{ - mImpl->mCacheID = id; -} - -S32 LLViewerRegion::renderPropertyLines() -{ - if (mParcelOverlay) - { - return mParcelOverlay->renderPropertyLines(); - } - else - { - return 0; - } -} - -// 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(); - } -} - -BOOL LLViewerRegion::idleUpdate(F32 max_update_time) -{ - LLMemType mt_ivr(LLMemType::MTYPE_IDLE_UPDATE_VIEWER_REGION); - // did_update returns TRUE if we did at least one significant update - BOOL did_update = mImpl->mLandp->idleUpdate(max_update_time); - - if (mParcelOverlay) - { - // Hopefully not a significant time sink... - mParcelOverlay->idleUpdate(); - } - - return did_update; -} - - -// 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(); - - mBitStat.addValue(mBitsIn - mLastBitsIn); - mPacketsStat.addValue(mPacketsIn - mLastPacketsIn); - mPacketsLostStat.addValue(mPacketsLost); -} - - -U32 LLViewerRegion::getPacketsLost() const -{ - LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(mImpl->mHost); - if (!cdp) - { - llinfos << "LLViewerRegion::getPacketsLost couldn't find circuit for " << mImpl->mHost << llendl; - 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()); - LLViewerRegion* region = LLWorld::getInstance()->getRegion(host); - if( !region ) - { - return; - } - - S32 target_index = input["body"]["Index"][0]["Prey"].asInteger(); - S32 you_index = input["body"]["Index"][0]["You" ].asInteger(); - - LLDynamicArray* avatar_locs = ®ion->mMapAvatars; - LLDynamicArray* avatar_ids = ®ion->mMapAvatarIDs; - avatar_locs->reset(); - avatar_ids->reset(); - - //llinfos << "coarse locations agent[0] " << input["body"]["AgentData"][0]["AgentID"].asUUID() << llendl; - //llinfos << "my agent id = " << gAgent.getID() << llendl; - //llinfos << ll_pretty_print_sd(input) << llendl; - - 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 loc = x << 16 | y << 8 | z; loc = loc; - U32 pos = 0x0; - pos |= x; - pos <<= 8; - pos |= y; - pos <<= 8; - pos |= z; - avatar_locs->put(pos); - //llinfos << "next pos: " << x << "," << y << "," << z << ": " << pos << llendl; - if(has_agent_data) // for backwards compatibility with old message format - { - LLUUID agent_id(agents_it->get("AgentID").asUUID()); - //llinfos << "next agent: " << agent_id.asString() << llendl; - avatar_ids->put(agent_id); - } - } - if (has_agent_data) - { - agents_it++; - } - } - } -}; - -// build the coarse location HTTP node under the "/message" URL -LLHTTPRegistration - gHTTPRegistrationCoarseLocationUpdate( - "/message/CoarseLocationUpdate"); - - -// the deprecated coarse location handler -void LLViewerRegion::updateCoarseLocations(LLMessageSystem* msg) -{ - //llinfos << "CoarseLocationUpdate" << llendl; - mMapAvatars.reset(); - mMapAvatarIDs.reset(); // 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); - } - - //llinfos << " object X: " << (S32)x_pos << " Y: " << (S32)y_pos - // << " Z: " << (S32)(z_pos * 4) - // << llendl; - - // 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.put(pos); - if(has_agent_data) - { - mMapAvatarIDs.put(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::getSimulatorFeatures(LLSD& sim_features) -{ - sim_features = mSimulatorFeatures; - -} - -void LLViewerRegion::setSimulatorFeatures(const LLSD& sim_features) -{ - std::stringstream str; - - LLSDSerialize::toPrettyXML(sim_features, str); - llinfos << str.str() << llendl; - mSimulatorFeatures = sim_features; -} - -LLViewerRegion::eCacheUpdateResult LLViewerRegion::cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinaryBuffer &dp) -{ - U32 local_id = objectp->getLocalID(); - U32 crc = objectp->getCRC(); - - LLVOCacheEntry* entry = get_if_there(mImpl->mCacheMap, local_id, (LLVOCacheEntry*)NULL); - - if (entry) - { - // we've seen this object before - if (entry->getCRC() == crc) - { - // Record a hit - entry->recordDupe(); - return CACHE_UPDATE_DUPE; - } - - // Update the cache entry - mImpl->mCacheMap.erase(local_id); - delete entry; - entry = new LLVOCacheEntry(local_id, crc, dp); - mImpl->mCacheMap[local_id] = entry; - return CACHE_UPDATE_CHANGED; - } - - // we haven't seen this object before - - // Create new entry and add to map - eCacheUpdateResult result = CACHE_UPDATE_ADDED; - if (mImpl->mCacheMap.size() > MAX_OBJECT_CACHE_ENTRIES) - { - delete mImpl->mCacheMap.begin()->second ; - mImpl->mCacheMap.erase(mImpl->mCacheMap.begin()); - result = CACHE_UPDATE_REPLACED; - - } - entry = new LLVOCacheEntry(local_id, crc, dp); - - mImpl->mCacheMap[local_id] = entry; - return result; -} - -// Get data packer for this object, if we have cached data -// AND the CRC matches. JC -LLDataPacker *LLViewerRegion::getDP(U32 local_id, U32 crc, U8 &cache_miss_type) -{ - //llassert(mCacheLoaded); This assert failes often, changing to early-out -- davep, 2010/10/18 - - LLVOCacheEntry* entry = get_if_there(mImpl->mCacheMap, local_id, (LLVOCacheEntry*)NULL); - - if (entry) - { - // we've seen this object before - if (entry->getCRC() == crc) - { - // Record a hit - entry->recordHit(); - cache_miss_type = CACHE_MISS_TYPE_NONE; - return entry->getDP(crc); - } - else - { - // llinfos << "CRC miss for " << local_id << llendl; - cache_miss_type = CACHE_MISS_TYPE_CRC; - mCacheMissCRC.put(local_id); - } - } - else - { - // llinfos << "Cache miss for " << local_id << llendl; - cache_miss_type = CACHE_MISS_TYPE_FULL; - mCacheMissFull.put(local_id); - } - - return NULL; -} - -void LLViewerRegion::addCacheMissFull(const U32 local_id) -{ - mCacheMissFull.put(local_id); -} - -void LLViewerRegion::requestCacheMisses() -{ - S32 full_count = mCacheMissFull.count(); - S32 crc_count = mCacheMissCRC.count(); - if (full_count == 0 && crc_count == 0) return; - - LLMessageSystem* msg = gMessageSystem; - BOOL start_new_message = TRUE; - S32 blocks = 0; - S32 i; - - // Send full cache miss updates. For these, we KNOW we don't - // have a viewer object. - for (i = 0; i < full_count; i++) - { - 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, CACHE_MISS_TYPE_FULL); - msg->addU32Fast(_PREHASH_ID, mCacheMissFull[i]); - blocks++; - - if (blocks >= 255) - { - sendReliableMessage(); - start_new_message = TRUE; - blocks = 0; - } - } - - // Send CRC miss updates. For these, we _might_ have a viewer object, - // but probably not. - for (i = 0; i < crc_count; i++) - { - 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, CACHE_MISS_TYPE_CRC); - msg->addU32Fast(_PREHASH_ID, mCacheMissCRC[i]); - blocks++; - - if (blocks >= 255) - { - sendReliableMessage(); - start_new_message = TRUE; - blocks = 0; - } - } - - // finish any pending message - if (!start_new_message) - { - sendReliableMessage(); - } - mCacheMissFull.reset(); - mCacheMissCRC.reset(); - - mCacheDirty = TRUE ; - // llinfos << "KILLDEBUG Sent cache miss full " << full_count << " crc " << crc_count << llendl; - #if LL_RECORD_VIEWER_STATS - LLViewerStatsRecorder::instance()->beginObjectUpdateEvents(this); - LLViewerStatsRecorder::instance()->recordRequestCacheMissesEvent(full_count + crc_count); - LLViewerStatsRecorder::instance()->endObjectUpdateEvents(); - #endif -} - -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]++; - } - - llinfos << "Count " << mImpl->mCacheMap.size() << llendl; - for (i = 0; i < BINS; i++) - { - llinfos << "Hits " << i << " " << hit_bin[i] << llendl; - } - for (i = 0; i < BINS; i++) - { - llinfos << "Changes " << i << " " << change_bin[i] << llendl; - } -} - -void LLViewerRegion::unpackRegionHandshake() -{ - LLMessageSystem *msg = gMessageSystem; - - U32 region_flags; - U8 sim_access; - std::string sim_name; - LLUUID sim_owner; - BOOL is_estate_manager; - F32 water_height; - F32 billable_factor; - LLUUID cache_id; - - msg->getU32 ("RegionInfo", "RegionFlags", region_flags); - 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 ); - - setRegionFlags(region_flags); - 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; - } - - LLVLComposition *compp = getComposition(); - if (compp) - { - LLUUID tmp_id; - - msg->getUUID("RegionInfo", "TerrainDetail0", tmp_id); - compp->setDetailTextureID(0, tmp_id); - msg->getUUID("RegionInfo", "TerrainDetail1", tmp_id); - compp->setDetailTextureID(1, tmp_id); - msg->getUUID("RegionInfo", "TerrainDetail2", tmp_id); - compp->setDetailTextureID(2, tmp_id); - msg->getUUID("RegionInfo", "TerrainDetail3", tmp_id); - compp->setDetailTextureID(3, tmp_id); - - F32 tmp_f32; - msg->getF32("RegionInfo", "TerrainStartHeight00", tmp_f32); - compp->setStartHeight(0, tmp_f32); - msg->getF32("RegionInfo", "TerrainStartHeight01", tmp_f32); - compp->setStartHeight(1, tmp_f32); - msg->getF32("RegionInfo", "TerrainStartHeight10", tmp_f32); - compp->setStartHeight(2, tmp_f32); - msg->getF32("RegionInfo", "TerrainStartHeight11", tmp_f32); - compp->setStartHeight(3, tmp_f32); - - msg->getF32("RegionInfo", "TerrainHeightRange00", tmp_f32); - compp->setHeightRange(0, tmp_f32); - msg->getF32("RegionInfo", "TerrainHeightRange01", tmp_f32); - compp->setHeightRange(1, tmp_f32); - msg->getF32("RegionInfo", "TerrainHeightRange10", tmp_f32); - compp->setHeightRange(2, tmp_f32); - msg->getF32("RegionInfo", "TerrainHeightRange11", tmp_f32); - 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()) - { - //this line creates frame stalls on region crossing and removing it appears to have no effect - //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"); - msg->addU32("Flags", 0x0 ); - msg->sendReliable(host); -} - -void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) -{ - capabilityNames.append("AgentState"); - capabilityNames.append("AttachmentResources"); - capabilityNames.append("AvatarPickerSearch"); - capabilityNames.append("CharacterProperties"); - capabilityNames.append("ChatSessionRequest"); - capabilityNames.append("CopyInventoryFromNotecard"); - capabilityNames.append("CreateInventoryCategory"); - capabilityNames.append("DispatchRegionInfo"); - capabilityNames.append("EstateChangeInfo"); - capabilityNames.append("EventQueueGet"); - capabilityNames.append("EnvironmentSettings"); - capabilityNames.append("ObjectMedia"); - capabilityNames.append("ObjectMediaNavigate"); - - if (gSavedSettings.getBOOL("UseHTTPInventory")) - { - capabilityNames.append("FetchLib2"); - capabilityNames.append("FetchLibDescendents2"); - capabilityNames.append("FetchInventory2"); - capabilityNames.append("FetchInventoryDescendents2"); - } - - capabilityNames.append("GetDisplayNames"); - capabilityNames.append("GetTexture"); - capabilityNames.append("GetMesh"); - capabilityNames.append("GetObjectCost"); - capabilityNames.append("GetObjectPhysicsData"); - capabilityNames.append("GroupProposalBallot"); - capabilityNames.append("HomeLocation"); - capabilityNames.append("LandResources"); - capabilityNames.append("MapLayer"); - capabilityNames.append("MapLayerGod"); - capabilityNames.append("MeshUploadFlag"); - capabilityNames.append("NavMeshGenerationStatus"); - capabilityNames.append("NewFileAgentInventory"); - capabilityNames.append("ObjectNavMeshProperties"); - capabilityNames.append("ParcelPropertiesUpdate"); - capabilityNames.append("ParcelNavigateMedia"); - capabilityNames.append("ParcelVoiceInfoRequest"); - capabilityNames.append("ProductInfoRequest"); - capabilityNames.append("ProvisionVoiceAccountRequest"); - capabilityNames.append("RemoteParcelRequest"); - 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("SimConsole"); - capabilityNames.append("SimulatorFeatures"); - capabilityNames.append("SetDisplayName"); - capabilityNames.append("SimConsoleAsync"); - capabilityNames.append("StartGroupProposal"); - capabilityNames.append("TerrainNavMeshProperties"); - capabilityNames.append("TextureStats"); - capabilityNames.append("UntrustedSimulatorMessage"); - capabilityNames.append("UpdateAgentInformation"); - capabilityNames.append("UpdateAgentLanguage"); - capabilityNames.append("UpdateGestureAgentInventory"); - capabilityNames.append("UpdateNotecardAgentInventory"); - capabilityNames.append("UpdateScriptAgent"); - capabilityNames.append("UpdateGestureTaskInventory"); - capabilityNames.append("UpdateNotecardTaskInventory"); - capabilityNames.append("UpdateScriptTask"); - capabilityNames.append("UploadBakedTexture"); - 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) - { - // llwarns << "Ignoring duplicate seed capability" << llendl; - return; - } - - delete mImpl->mEventPoll; - mImpl->mEventPoll = NULL; - - mImpl->mCapabilities.clear(); - setCapability("Seed", url); - - LLSD capabilityNames = LLSD::emptyArray(); - mImpl->buildCapabilityNames(capabilityNames); - - llinfos << "posting to seed " << url << llendl; - - S32 id = ++mImpl->mHttpResponderID; - LLHTTPClient::post(url, capabilityNames, - BaseCapabilitiesComplete::build(getHandle(), id), - LLSD(), CAP_REQUEST_TIMEOUT); -} - -S32 LLViewerRegion::getNumSeedCapRetries() -{ - return mImpl->mSeedCapAttempts; -} - -void LLViewerRegion::failedSeedCapability() -{ - // Should we retry asking for caps? - mImpl->mSeedCapAttempts++; - std::string url = getCapability("Seed"); - if ( url.empty() ) - { - LL_WARNS2("AppInit", "Capabilities") << "Failed to get seed capabilities, and can not determine url for retries!" << LL_ENDL; - return; - } - // After a few attempts, continue login. We will keep trying once in-world: - if ( mImpl->mSeedCapAttempts >= mImpl->mSeedCapMaxAttemptsBeforeLogin && - STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState() ) - { - LLStartUp::setStartupState( STATE_SEED_CAP_GRANTED ); - } - - if ( mImpl->mSeedCapAttempts < mImpl->mSeedCapMaxAttempts) - { - LLSD capabilityNames = LLSD::emptyArray(); - mImpl->buildCapabilityNames(capabilityNames); - - llinfos << "posting to seed " << url << " (retry " - << mImpl->mSeedCapAttempts << ")" << llendl; - - S32 id = ++mImpl->mHttpResponderID; - LLHTTPClient::post(url, capabilityNames, - BaseCapabilitiesComplete::build(getHandle(), id), - LLSD(), CAP_REQUEST_TIMEOUT); - } - else - { - // *TODO: Give a user pop-up about this error? - LL_WARNS2("AppInit", "Capabilities") << "Failed to get seed capabilities from '" << url << "' after " << mImpl->mSeedCapAttempts << " attempts. Giving up!" << LL_ENDL; - } -} - -class SimulatorFeaturesReceived : public LLHTTPClient::Responder -{ - LOG_CLASS(SimulatorFeaturesReceived); -public: - SimulatorFeaturesReceived(const std::string& retry_url, U64 region_handle, - S32 attempt = 0, S32 max_attempts = MAX_CAP_REQUEST_ATTEMPTS) - : mRetryURL(retry_url), mRegionHandle(region_handle), mAttempt(attempt), mMaxAttempts(max_attempts) - { } - - - void error(U32 statusNum, const std::string& reason) - { - LL_WARNS2("AppInit", "SimulatorFeatures") << statusNum << ": " << reason << LL_ENDL; - retry(); - } - - void result(const LLSD& content) - { - LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); - if(!regionp) //region is removed or responder is not created. - { - LL_WARNS2("AppInit", "SimulatorFeatures") << "Received results for region that no longer exists!" << LL_ENDL; - return ; - } - - regionp->setSimulatorFeatures(content); - } - -private: - void retry() - { - if (mAttempt < mMaxAttempts) - { - mAttempt++; - LL_WARNS2("AppInit", "SimulatorFeatures") << "Re-trying '" << mRetryURL << "'. Retry #" << mAttempt << LL_ENDL; - LLHTTPClient::get(mRetryURL, new SimulatorFeaturesReceived(*this), LLSD(), CAP_REQUEST_TIMEOUT); - } - } - - std::string mRetryURL; - U64 mRegionHandle; - S32 mAttempt; - S32 mMaxAttempts; -}; - - -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") - { - LLHTTPSender::setSender(mImpl->mHost, new LLCapHTTPSender(url)); - } - else if (name == "SimulatorFeatures") - { - // kick off a request for simulator features - LLHTTPClient::get(url, new SimulatorFeaturesReceived(url, getHandle()), LLSD(), CAP_REQUEST_TIMEOUT); - } - else - { - mImpl->mCapabilities[name] = url; - if(name == "GetTexture") - { - mHttpUrl = url ; - } - } -} - -bool LLViewerRegion::isSpecialCapabilityName(const std::string &name) -{ - return name == "EventQueueGet" || name == "UntrustedSimulatorMessage"; -} - -std::string LLViewerRegion::getCapability(const std::string& name) const -{ - CapabilityMap::const_iterator iter = mImpl->mCapabilities.find(name); - if(iter == mImpl->mCapabilities.end()) - { - return ""; - } - - return iter->second; -} - -bool LLViewerRegion::capabilitiesReceived() const -{ - return mCapabilitiesReceived; -} - -void LLViewerRegion::setCapabilitiesReceived(bool received) -{ - mCapabilitiesReceived = received; - - // Tell interested parties that we've received capabilities, - // so that they can safely use getCapability(). - if (received) - { - mCapabilitiesReceivedSignal(getRegionID()); - - // This is a single-shot signal. Forget callbacks to save resources. - mCapabilitiesReceivedSignal.disconnect_all_slots(); - } -} - -boost::signals2::connection LLViewerRegion::setCapabilitiesReceivedCallback(const caps_received_signal_t::slot_type& cb) -{ - return mCapabilitiesReceivedSignal.connect(cb); -} - -void LLViewerRegion::logActiveCapabilities() const -{ - int count = 0; - CapabilityMap::const_iterator iter; - for (iter = mImpl->mCapabilities.begin(); iter != mImpl->mCapabilities.end(); ++iter, ++count) - { - if (!iter->second.empty()) - { - llinfos << iter->first << " URL is " << iter->second << llendl; - } - } - llinfos << "Dumped " << count << " entries." << llendl; -} - -LLSpatialPartition* LLViewerRegion::getSpatialPartition(U32 type) -{ - if (type < mImpl->mObjectPartition.size()) - { - return mImpl->mObjectPartition[type]; - } - 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 U32 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& boxes) const -{ - return (mParcelOverlay != NULL) - && (mParcelOverlay->isOwnedSelf(pos) - || mParcelOverlay->isOwnedGroup(pos) - || ((mRegionFlags & ALLOW_RETURN_ENCROACHING_OBJECT) - && mParcelOverlay->encroachesOwned(boxes)) ); -} - -bool LLViewerRegion::childrenObjectReturnable( const std::vector& boxes ) const -{ - bool result = false; - result = ( mParcelOverlay && mParcelOverlay->encroachesOnUnowned( boxes ) ) ? 1 : 0; - return result; -} - -bool LLViewerRegion::objectsCrossParcel(const std::vector& boxes) const -{ - return mParcelOverlay && mParcelOverlay->encroachesOnNearbyParcel(boxes); -} - -void LLViewerRegion::getNeighboringRegions( std::vector& uniqueRegions ) -{ - mImpl->mLandp->getNeighboringRegions( uniqueRegions ); -} -void LLViewerRegion::getNeighboringRegionsStatus( std::vector& 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::meshRezEnabled() const -{ - return (mSimulatorFeatures.has("MeshRezEnabled") && - mSimulatorFeatures["MeshRezEnabled"].asBoolean()); -} - -bool LLViewerRegion::dynamicPathfindingEnabled() const -{ - return ( mSimulatorFeatures.has("DynamicPathfindingEnabled") && - mSimulatorFeatures["DynamicPathfindingEnabled"].asBoolean()); -} - +/** + * @file llviewerregion.cpp + * @brief Implementation of the LLViewerRegion class. + * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llviewerregion.h" + +// linden libraries +#include "indra_constants.h" +#include "llavatarnamecache.h" // name lookup cap url +#include "llfloaterreg.h" +#include "llmath.h" +#include "llhttpclient.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 "llcallingcard.h" +#include "llcaphttpsender.h" +#include "llcapabilitylistener.h" +#include "llcommandhandler.h" +#include "lldir.h" +#include "lleventpoll.h" +#include "llfloatergodtools.h" +#include "llfloaterreporter.h" +#include "llfloaterregioninfo.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 "llvocache.h" +#include "llworld.h" +#include "llspatialpartition.h" +#include "stringize.h" +#include "llviewercontrol.h" +#include "llsdserialize.h" + +#ifdef LL_WINDOWS + #pragma warning(disable:4355) +#endif + +const F32 WATER_TEXTURE_SCALE = 8.f; // Number of times to repeat the water texture across a region +const S16 MAX_MAP_DIST = 10; +// 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. +// Give it 3 chances, each at 18 seconds to give ourselves a few seconds to connect anyways if we give up. +const S32 MAX_SEED_CAP_ATTEMPTS_BEFORE_LOGIN = 3; +const F32 CAP_REQUEST_TIMEOUT = 18; +// Even though we gave up on login, keep trying for caps after we are logged in: +const S32 MAX_CAP_REQUEST_ATTEMPTS = 30; + +typedef std::map CapabilityMap; + +class LLViewerRegionImpl { +public: + LLViewerRegionImpl(LLViewerRegion * region, LLHost const & host) + : mHost(host), + mCompositionp(NULL), + mEventPoll(NULL), + mSeedCapMaxAttempts(MAX_CAP_REQUEST_ATTEMPTS), + mSeedCapMaxAttemptsBeforeLogin(MAX_SEED_CAP_ATTEMPTS_BEFORE_LOGIN), + mSeedCapAttempts(0), + mHttpResponderID(0), + // I'd prefer to set the LLCapabilityListener name to match the region + // name -- it's disappointing that's not available at construction time. + // We could instead store an LLCapabilityListener*, making + // setRegionNameAndZone() replace the instance. Would that pose + // consistency problems? Can we even request a capability before calling + // setRegionNameAndZone()? + // For testability -- the new Michael Feathers paradigm -- + // LLCapabilityListener binds all the globals it expects to need at + // construction time. + mCapabilityListener(host.getString(), gMessageSystem, *region, + gAgent.getID(), gAgent.getSessionID()) + { + } + + 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; + // time? + // LRU info? + + // Cache ID is unique per-region, across renames, moving locations, + // etc. + LLUUID mCacheID; + + CapabilityMap mCapabilities; + + LLEventPoll* mEventPoll; + + S32 mSeedCapMaxAttempts; + S32 mSeedCapMaxAttemptsBeforeLogin; + S32 mSeedCapAttempts; + + S32 mHttpResponderID; + + /// Post an event to this LLCapabilityListener to invoke a capability message on + /// this LLViewerRegion's server + /// (https://wiki.lindenlab.com/wiki/Viewer:Messaging/Messaging_Notes#Capabilities) + LLCapabilityListener mCapabilityListener; + + //spatial partitions for objects in this region + std::vector mObjectPartition; +}; + +// 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, 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://"; + for (int i = 0; i < num_params; i++) + { + if (i > 0) + { + url += "/"; + } + url += params[i].asString(); + } + + // Process the SLapp as if it was a secondlife://{PLACE} SLurl + LLURLDispatcher::dispatch(url, "clicked", web, true); + return true; + } +}; +LLRegionHandler gRegionHandler; + +class BaseCapabilitiesComplete : public LLHTTPClient::Responder +{ + LOG_CLASS(BaseCapabilitiesComplete); +public: + BaseCapabilitiesComplete(U64 region_handle, S32 id) + : mRegionHandle(region_handle), mID(id) + { } + virtual ~BaseCapabilitiesComplete() + { } + + void error(U32 statusNum, const std::string& reason) + { + LL_WARNS2("AppInit", "Capabilities") << statusNum << ": " << reason << LL_ENDL; + LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); + if (regionp) + { + regionp->failedSeedCapability(); + } + } + + void result(const LLSD& content) + { + LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); + if(!regionp) //region was removed + { + LL_WARNS2("AppInit", "Capabilities") << "Received results for region that no longer exists!" << LL_ENDL; + return ; + } + if( mID != regionp->getHttpResponderID() ) // region is no longer referring to this responder + { + LL_WARNS2("AppInit", "Capabilities") << "Received results for a stale http responder!" << LL_ENDL; + return ; + } + + LLSD::map_const_iterator iter; + for(iter = content.beginMap(); iter != content.endMap(); ++iter) + { + regionp->setCapability(iter->first, iter->second); + LL_DEBUGS2("AppInit", "Capabilities") << "got capability for " + << iter->first << LL_ENDL; + + /* HACK we're waiting for the ServerReleaseNotes */ + if (iter->first == "ServerReleaseNotes" && regionp->getReleaseNotesRequested()) + { + regionp->showReleaseNotes(); + } + } + + regionp->setCapabilitiesReceived(true); + + if (STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState()) + { + LLStartUp::setStartupState( STATE_SEED_CAP_GRANTED ); + } + } + + static boost::intrusive_ptr build( U64 region_handle, S32 id ) + { + return boost::intrusive_ptr( + new BaseCapabilitiesComplete(region_handle, id) ); + } + +private: + U64 mRegionHandle; + S32 mID; +}; + + +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 ), + mSimAccess( SIM_ACCESS_MIN ), + mBillableFactor(1.0), + mMaxTasks(DEFAULT_MAX_REGION_WIDE_PRIM_COUNT), + mClassID(0), + mCPURatio(0), + mColoName("unknown"), + mProductSKU("unknown"), + mProductName("unknown"), + mHttpUrl(""), + mCacheLoaded(FALSE), + mCacheDirty(FALSE), + mReleaseNotesRequested(FALSE), + mCapabilitiesReceived(false) +{ + 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()); //PARTITION_HUD + mImpl->mObjectPartition.push_back(new LLTerrainPartition()); //PARTITION_TERRAIN + mImpl->mObjectPartition.push_back(new LLVoidWaterPartition()); //PARTITION_VOIDWATER + mImpl->mObjectPartition.push_back(new LLWaterPartition()); //PARTITION_WATER + mImpl->mObjectPartition.push_back(new LLTreePartition()); //PARTITION_TREE + mImpl->mObjectPartition.push_back(new LLParticlePartition()); //PARTITION_PARTICLE + mImpl->mObjectPartition.push_back(new LLGrassPartition()); //PARTITION_GRASS + mImpl->mObjectPartition.push_back(new LLVolumePartition()); //PARTITION_VOLUME + mImpl->mObjectPartition.push_back(new LLBridgePartition()); //PARTITION_BRIDGE + mImpl->mObjectPartition.push_back(new LLHUDParticlePartition());//PARTITION_HUD_PARTICLE + mImpl->mObjectPartition.push_back(NULL); //PARTITION_NONE +} + + +void LLViewerRegion::initStats() +{ + mImpl->mLastNetUpdate.reset(); + mPacketsIn = 0; + mBitsIn = 0; + mLastBitsIn = 0; + mLastPacketsIn = 0; + mPacketsOut = 0; + mLastPacketsOut = 0; + mPacketsLost = 0; + mLastPacketsLost = 0; + mPingDelay = 0; + mAlive = false; // can become false if circuit disconnects +} + +LLViewerRegion::~LLViewerRegion() +{ + 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); + + gObjectList.killObjects(this); + + delete mImpl->mCompositionp; + delete mParcelOverlay; + delete mImpl->mLandp; + delete mImpl->mEventPoll; + LLHTTPSender::clearSender(mImpl->mHost); + + saveObjectCache(); + + std::for_each(mImpl->mObjectPartition.begin(), mImpl->mObjectPartition.end(), DeletePointer()); + + delete mImpl; + mImpl = NULL; +} + +LLEventPump& LLViewerRegion::getCapAPI() const +{ + return mImpl->mCapabilityListener.getCapAPI(); +} + +/*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::hasInstance()) + { + LLVOCache::getInstance()->readFromCache(mHandle, mImpl->mCacheID, mImpl->mCacheMap) ; + } +} + + +void LLViewerRegion::saveObjectCache() +{ + if (!mCacheLoaded) + { + return; + } + + if (mImpl->mCacheMap.empty()) + { + return; + } + + if(LLVOCache::hasInstance()) + { + LLVOCache::getInstance()->writeToCache(mHandle, mImpl->mCacheID, mImpl->mCacheMap, mCacheDirty) ; + mCacheDirty = FALSE; + } + + for(LLVOCacheEntry::vocache_entry_map_t::iterator iter = mImpl->mCacheMap.begin(); iter != mImpl->mCacheMap.end(); ++iter) + { + delete iter->second; + } + mImpl->mCacheMap.clear(); +} + +void LLViewerRegion::sendMessage() +{ + gMessageSystem->sendMessage(mImpl->mHost); +} + +void LLViewerRegion::sendReliableMessage() +{ + gMessageSystem->sendReliable(mImpl->mHost); +} + +void LLViewerRegion::setFlags(BOOL b, U32 flags) +{ + if (b) + { + mRegionFlags |= flags; + } + else + { + mRegionFlags &= ~flags; + } +} + +void LLViewerRegion::setWaterHeight(F32 water_level) +{ + mImpl->mLandp->setWaterHeight(water_level); +} + +F32 LLViewerRegion::getWaterHeight() const +{ + return mImpl->mLandp->getWaterHeight(); +} + +BOOL LLViewerRegion::isVoiceEnabled() const +{ + return (getRegionFlags() & REGION_FLAGS_ALLOW_VOICE); +} + +void LLViewerRegion::setRegionFlags(U32 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(U32 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 + llinfos << "Processing region info" << llendl; + LLRegionInfoModel::instance().update(msg); + LLFloaterGodTools::processRegionInfo(msg); + LLFloaterRegionInfo::processRegionInfo(msg); + LLFloaterReporter::processRegionInfo(msg); +} + +void LLViewerRegion::setCacheID(const LLUUID& id) +{ + mImpl->mCacheID = id; +} + +S32 LLViewerRegion::renderPropertyLines() +{ + if (mParcelOverlay) + { + return mParcelOverlay->renderPropertyLines(); + } + else + { + return 0; + } +} + +// 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(); + } +} + +BOOL LLViewerRegion::idleUpdate(F32 max_update_time) +{ + LLMemType mt_ivr(LLMemType::MTYPE_IDLE_UPDATE_VIEWER_REGION); + // did_update returns TRUE if we did at least one significant update + BOOL did_update = mImpl->mLandp->idleUpdate(max_update_time); + + if (mParcelOverlay) + { + // Hopefully not a significant time sink... + mParcelOverlay->idleUpdate(); + } + + return did_update; +} + + +// 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(); + + mBitStat.addValue(mBitsIn - mLastBitsIn); + mPacketsStat.addValue(mPacketsIn - mLastPacketsIn); + mPacketsLostStat.addValue(mPacketsLost); +} + + +U32 LLViewerRegion::getPacketsLost() const +{ + LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(mImpl->mHost); + if (!cdp) + { + llinfos << "LLViewerRegion::getPacketsLost couldn't find circuit for " << mImpl->mHost << llendl; + 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()); + LLViewerRegion* region = LLWorld::getInstance()->getRegion(host); + if( !region ) + { + return; + } + + S32 target_index = input["body"]["Index"][0]["Prey"].asInteger(); + S32 you_index = input["body"]["Index"][0]["You" ].asInteger(); + + LLDynamicArray* avatar_locs = ®ion->mMapAvatars; + LLDynamicArray* avatar_ids = ®ion->mMapAvatarIDs; + avatar_locs->reset(); + avatar_ids->reset(); + + //llinfos << "coarse locations agent[0] " << input["body"]["AgentData"][0]["AgentID"].asUUID() << llendl; + //llinfos << "my agent id = " << gAgent.getID() << llendl; + //llinfos << ll_pretty_print_sd(input) << llendl; + + 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 loc = x << 16 | y << 8 | z; loc = loc; + U32 pos = 0x0; + pos |= x; + pos <<= 8; + pos |= y; + pos <<= 8; + pos |= z; + avatar_locs->put(pos); + //llinfos << "next pos: " << x << "," << y << "," << z << ": " << pos << llendl; + if(has_agent_data) // for backwards compatibility with old message format + { + LLUUID agent_id(agents_it->get("AgentID").asUUID()); + //llinfos << "next agent: " << agent_id.asString() << llendl; + avatar_ids->put(agent_id); + } + } + if (has_agent_data) + { + agents_it++; + } + } + } +}; + +// build the coarse location HTTP node under the "/message" URL +LLHTTPRegistration + gHTTPRegistrationCoarseLocationUpdate( + "/message/CoarseLocationUpdate"); + + +// the deprecated coarse location handler +void LLViewerRegion::updateCoarseLocations(LLMessageSystem* msg) +{ + //llinfos << "CoarseLocationUpdate" << llendl; + mMapAvatars.reset(); + mMapAvatarIDs.reset(); // 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); + } + + //llinfos << " object X: " << (S32)x_pos << " Y: " << (S32)y_pos + // << " Z: " << (S32)(z_pos * 4) + // << llendl; + + // 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.put(pos); + if(has_agent_data) + { + mMapAvatarIDs.put(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::getSimulatorFeatures(LLSD& sim_features) +{ + sim_features = mSimulatorFeatures; + +} + +void LLViewerRegion::setSimulatorFeatures(const LLSD& sim_features) +{ + std::stringstream str; + + LLSDSerialize::toPrettyXML(sim_features, str); + llinfos << str.str() << llendl; + mSimulatorFeatures = sim_features; +} + +LLViewerRegion::eCacheUpdateResult LLViewerRegion::cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinaryBuffer &dp) +{ + U32 local_id = objectp->getLocalID(); + U32 crc = objectp->getCRC(); + + LLVOCacheEntry* entry = get_if_there(mImpl->mCacheMap, local_id, (LLVOCacheEntry*)NULL); + + if (entry) + { + // we've seen this object before + if (entry->getCRC() == crc) + { + // Record a hit + entry->recordDupe(); + return CACHE_UPDATE_DUPE; + } + + // Update the cache entry + mImpl->mCacheMap.erase(local_id); + delete entry; + entry = new LLVOCacheEntry(local_id, crc, dp); + mImpl->mCacheMap[local_id] = entry; + return CACHE_UPDATE_CHANGED; + } + + // we haven't seen this object before + + // Create new entry and add to map + eCacheUpdateResult result = CACHE_UPDATE_ADDED; + if (mImpl->mCacheMap.size() > MAX_OBJECT_CACHE_ENTRIES) + { + delete mImpl->mCacheMap.begin()->second ; + mImpl->mCacheMap.erase(mImpl->mCacheMap.begin()); + result = CACHE_UPDATE_REPLACED; + + } + entry = new LLVOCacheEntry(local_id, crc, dp); + + mImpl->mCacheMap[local_id] = entry; + return result; +} + +// Get data packer for this object, if we have cached data +// AND the CRC matches. JC +LLDataPacker *LLViewerRegion::getDP(U32 local_id, U32 crc, U8 &cache_miss_type) +{ + //llassert(mCacheLoaded); This assert failes often, changing to early-out -- davep, 2010/10/18 + + LLVOCacheEntry* entry = get_if_there(mImpl->mCacheMap, local_id, (LLVOCacheEntry*)NULL); + + if (entry) + { + // we've seen this object before + if (entry->getCRC() == crc) + { + // Record a hit + entry->recordHit(); + cache_miss_type = CACHE_MISS_TYPE_NONE; + return entry->getDP(crc); + } + else + { + // llinfos << "CRC miss for " << local_id << llendl; + cache_miss_type = CACHE_MISS_TYPE_CRC; + mCacheMissCRC.put(local_id); + } + } + else + { + // llinfos << "Cache miss for " << local_id << llendl; + cache_miss_type = CACHE_MISS_TYPE_FULL; + mCacheMissFull.put(local_id); + } + + return NULL; +} + +void LLViewerRegion::addCacheMissFull(const U32 local_id) +{ + mCacheMissFull.put(local_id); +} + +void LLViewerRegion::requestCacheMisses() +{ + S32 full_count = mCacheMissFull.count(); + S32 crc_count = mCacheMissCRC.count(); + if (full_count == 0 && crc_count == 0) return; + + LLMessageSystem* msg = gMessageSystem; + BOOL start_new_message = TRUE; + S32 blocks = 0; + S32 i; + + // Send full cache miss updates. For these, we KNOW we don't + // have a viewer object. + for (i = 0; i < full_count; i++) + { + 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, CACHE_MISS_TYPE_FULL); + msg->addU32Fast(_PREHASH_ID, mCacheMissFull[i]); + blocks++; + + if (blocks >= 255) + { + sendReliableMessage(); + start_new_message = TRUE; + blocks = 0; + } + } + + // Send CRC miss updates. For these, we _might_ have a viewer object, + // but probably not. + for (i = 0; i < crc_count; i++) + { + 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, CACHE_MISS_TYPE_CRC); + msg->addU32Fast(_PREHASH_ID, mCacheMissCRC[i]); + blocks++; + + if (blocks >= 255) + { + sendReliableMessage(); + start_new_message = TRUE; + blocks = 0; + } + } + + // finish any pending message + if (!start_new_message) + { + sendReliableMessage(); + } + mCacheMissFull.reset(); + mCacheMissCRC.reset(); + + mCacheDirty = TRUE ; + // llinfos << "KILLDEBUG Sent cache miss full " << full_count << " crc " << crc_count << llendl; + #if LL_RECORD_VIEWER_STATS + LLViewerStatsRecorder::instance()->beginObjectUpdateEvents(this); + LLViewerStatsRecorder::instance()->recordRequestCacheMissesEvent(full_count + crc_count); + LLViewerStatsRecorder::instance()->endObjectUpdateEvents(); + #endif +} + +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]++; + } + + llinfos << "Count " << mImpl->mCacheMap.size() << llendl; + for (i = 0; i < BINS; i++) + { + llinfos << "Hits " << i << " " << hit_bin[i] << llendl; + } + for (i = 0; i < BINS; i++) + { + llinfos << "Changes " << i << " " << change_bin[i] << llendl; + } +} + +void LLViewerRegion::unpackRegionHandshake() +{ + LLMessageSystem *msg = gMessageSystem; + + U32 region_flags; + U8 sim_access; + std::string sim_name; + LLUUID sim_owner; + BOOL is_estate_manager; + F32 water_height; + F32 billable_factor; + LLUUID cache_id; + + msg->getU32 ("RegionInfo", "RegionFlags", region_flags); + 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 ); + + setRegionFlags(region_flags); + 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; + } + + LLVLComposition *compp = getComposition(); + if (compp) + { + LLUUID tmp_id; + + msg->getUUID("RegionInfo", "TerrainDetail0", tmp_id); + compp->setDetailTextureID(0, tmp_id); + msg->getUUID("RegionInfo", "TerrainDetail1", tmp_id); + compp->setDetailTextureID(1, tmp_id); + msg->getUUID("RegionInfo", "TerrainDetail2", tmp_id); + compp->setDetailTextureID(2, tmp_id); + msg->getUUID("RegionInfo", "TerrainDetail3", tmp_id); + compp->setDetailTextureID(3, tmp_id); + + F32 tmp_f32; + msg->getF32("RegionInfo", "TerrainStartHeight00", tmp_f32); + compp->setStartHeight(0, tmp_f32); + msg->getF32("RegionInfo", "TerrainStartHeight01", tmp_f32); + compp->setStartHeight(1, tmp_f32); + msg->getF32("RegionInfo", "TerrainStartHeight10", tmp_f32); + compp->setStartHeight(2, tmp_f32); + msg->getF32("RegionInfo", "TerrainStartHeight11", tmp_f32); + compp->setStartHeight(3, tmp_f32); + + msg->getF32("RegionInfo", "TerrainHeightRange00", tmp_f32); + compp->setHeightRange(0, tmp_f32); + msg->getF32("RegionInfo", "TerrainHeightRange01", tmp_f32); + compp->setHeightRange(1, tmp_f32); + msg->getF32("RegionInfo", "TerrainHeightRange10", tmp_f32); + compp->setHeightRange(2, tmp_f32); + msg->getF32("RegionInfo", "TerrainHeightRange11", tmp_f32); + 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()) + { + //this line creates frame stalls on region crossing and removing it appears to have no effect + //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"); + msg->addU32("Flags", 0x0 ); + msg->sendReliable(host); +} + +void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) +{ + capabilityNames.append("AgentState"); + capabilityNames.append("AttachmentResources"); + capabilityNames.append("AvatarPickerSearch"); + capabilityNames.append("CharacterProperties"); + capabilityNames.append("ChatSessionRequest"); + capabilityNames.append("CopyInventoryFromNotecard"); + capabilityNames.append("CreateInventoryCategory"); + capabilityNames.append("DispatchRegionInfo"); + capabilityNames.append("EnvironmentSettings"); + capabilityNames.append("EstateChangeInfo"); + capabilityNames.append("EventQueueGet"); + + if (gSavedSettings.getBOOL("UseHTTPInventory")) + { + capabilityNames.append("FetchLib2"); + capabilityNames.append("FetchLibDescendents2"); + capabilityNames.append("FetchInventory2"); + capabilityNames.append("FetchInventoryDescendents2"); + } + + capabilityNames.append("GetDisplayNames"); + capabilityNames.append("GetMesh"); + capabilityNames.append("GetObjectCost"); + capabilityNames.append("GetObjectPhysicsData"); + capabilityNames.append("GetTexture"); + capabilityNames.append("GroupMemberData"); + capabilityNames.append("GroupProposalBallot"); + capabilityNames.append("HomeLocation"); + capabilityNames.append("LandResources"); + capabilityNames.append("MapLayer"); + capabilityNames.append("MapLayerGod"); + capabilityNames.append("MeshUploadFlag"); + capabilityNames.append("NavMeshGenerationStatus"); + capabilityNames.append("NewFileAgentInventory"); + capabilityNames.append("ObjectMedia"); + capabilityNames.append("ObjectMediaNavigate"); + capabilityNames.append("ObjectNavMeshProperties"); + capabilityNames.append("ParcelPropertiesUpdate"); + capabilityNames.append("ParcelVoiceInfoRequest"); + capabilityNames.append("ProductInfoRequest"); + capabilityNames.append("ProvisionVoiceAccountRequest"); + capabilityNames.append("RemoteParcelRequest"); + 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("UpdateGestureAgentInventory"); + capabilityNames.append("UpdateGestureTaskInventory"); + capabilityNames.append("UpdateNotecardAgentInventory"); + capabilityNames.append("UpdateNotecardTaskInventory"); + capabilityNames.append("UpdateScriptAgent"); + capabilityNames.append("UpdateScriptTask"); + capabilityNames.append("UploadBakedTexture"); + 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) + { + // llwarns << "Ignoring duplicate seed capability" << llendl; + return; + } + + delete mImpl->mEventPoll; + mImpl->mEventPoll = NULL; + + mImpl->mCapabilities.clear(); + setCapability("Seed", url); + + LLSD capabilityNames = LLSD::emptyArray(); + mImpl->buildCapabilityNames(capabilityNames); + + llinfos << "posting to seed " << url << llendl; + + S32 id = ++mImpl->mHttpResponderID; + LLHTTPClient::post(url, capabilityNames, + BaseCapabilitiesComplete::build(getHandle(), id), + LLSD(), CAP_REQUEST_TIMEOUT); +} + +S32 LLViewerRegion::getNumSeedCapRetries() +{ + return mImpl->mSeedCapAttempts; +} + +void LLViewerRegion::failedSeedCapability() +{ + // Should we retry asking for caps? + mImpl->mSeedCapAttempts++; + std::string url = getCapability("Seed"); + if ( url.empty() ) + { + LL_WARNS2("AppInit", "Capabilities") << "Failed to get seed capabilities, and can not determine url for retries!" << LL_ENDL; + return; + } + // After a few attempts, continue login. We will keep trying once in-world: + if ( mImpl->mSeedCapAttempts >= mImpl->mSeedCapMaxAttemptsBeforeLogin && + STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState() ) + { + LLStartUp::setStartupState( STATE_SEED_CAP_GRANTED ); + } + + if ( mImpl->mSeedCapAttempts < mImpl->mSeedCapMaxAttempts) + { + LLSD capabilityNames = LLSD::emptyArray(); + mImpl->buildCapabilityNames(capabilityNames); + + llinfos << "posting to seed " << url << " (retry " + << mImpl->mSeedCapAttempts << ")" << llendl; + + S32 id = ++mImpl->mHttpResponderID; + LLHTTPClient::post(url, capabilityNames, + BaseCapabilitiesComplete::build(getHandle(), id), + LLSD(), CAP_REQUEST_TIMEOUT); + } + else + { + // *TODO: Give a user pop-up about this error? + LL_WARNS2("AppInit", "Capabilities") << "Failed to get seed capabilities from '" << url << "' after " << mImpl->mSeedCapAttempts << " attempts. Giving up!" << LL_ENDL; + } +} + +class SimulatorFeaturesReceived : public LLHTTPClient::Responder +{ + LOG_CLASS(SimulatorFeaturesReceived); +public: + SimulatorFeaturesReceived(const std::string& retry_url, U64 region_handle, + S32 attempt = 0, S32 max_attempts = MAX_CAP_REQUEST_ATTEMPTS) + : mRetryURL(retry_url), mRegionHandle(region_handle), mAttempt(attempt), mMaxAttempts(max_attempts) + { } + + + void error(U32 statusNum, const std::string& reason) + { + LL_WARNS2("AppInit", "SimulatorFeatures") << statusNum << ": " << reason << LL_ENDL; + retry(); + } + + void result(const LLSD& content) + { + LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); + if(!regionp) //region is removed or responder is not created. + { + LL_WARNS2("AppInit", "SimulatorFeatures") << "Received results for region that no longer exists!" << LL_ENDL; + return ; + } + + regionp->setSimulatorFeatures(content); + } + +private: + void retry() + { + if (mAttempt < mMaxAttempts) + { + mAttempt++; + LL_WARNS2("AppInit", "SimulatorFeatures") << "Re-trying '" << mRetryURL << "'. Retry #" << mAttempt << LL_ENDL; + LLHTTPClient::get(mRetryURL, new SimulatorFeaturesReceived(*this), LLSD(), CAP_REQUEST_TIMEOUT); + } + } + + std::string mRetryURL; + U64 mRegionHandle; + S32 mAttempt; + S32 mMaxAttempts; +}; + + +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") + { + LLHTTPSender::setSender(mImpl->mHost, new LLCapHTTPSender(url)); + } + else if (name == "SimulatorFeatures") + { + // kick off a request for simulator features + LLHTTPClient::get(url, new SimulatorFeaturesReceived(url, getHandle()), LLSD(), CAP_REQUEST_TIMEOUT); + } + else + { + mImpl->mCapabilities[name] = url; + if(name == "GetTexture") + { + mHttpUrl = url ; + } + } +} + +bool LLViewerRegion::isSpecialCapabilityName(const std::string &name) +{ + return name == "EventQueueGet" || name == "UntrustedSimulatorMessage"; +} + +std::string LLViewerRegion::getCapability(const std::string& name) const +{ + CapabilityMap::const_iterator iter = mImpl->mCapabilities.find(name); + if(iter == mImpl->mCapabilities.end()) + { + return ""; + } + + return iter->second; +} + +bool LLViewerRegion::capabilitiesReceived() const +{ + return mCapabilitiesReceived; +} + +void LLViewerRegion::setCapabilitiesReceived(bool received) +{ + mCapabilitiesReceived = received; + + // Tell interested parties that we've received capabilities, + // so that they can safely use getCapability(). + if (received) + { + mCapabilitiesReceivedSignal(getRegionID()); + + // This is a single-shot signal. Forget callbacks to save resources. + mCapabilitiesReceivedSignal.disconnect_all_slots(); + } +} + +boost::signals2::connection LLViewerRegion::setCapabilitiesReceivedCallback(const caps_received_signal_t::slot_type& cb) +{ + return mCapabilitiesReceivedSignal.connect(cb); +} + +void LLViewerRegion::logActiveCapabilities() const +{ + int count = 0; + CapabilityMap::const_iterator iter; + for (iter = mImpl->mCapabilities.begin(); iter != mImpl->mCapabilities.end(); ++iter, ++count) + { + if (!iter->second.empty()) + { + llinfos << iter->first << " URL is " << iter->second << llendl; + } + } + llinfos << "Dumped " << count << " entries." << llendl; +} + +LLSpatialPartition* LLViewerRegion::getSpatialPartition(U32 type) +{ + if (type < mImpl->mObjectPartition.size()) + { + return mImpl->mObjectPartition[type]; + } + 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 U32 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& boxes) const +{ + return (mParcelOverlay != NULL) + && (mParcelOverlay->isOwnedSelf(pos) + || mParcelOverlay->isOwnedGroup(pos) + || ((mRegionFlags & ALLOW_RETURN_ENCROACHING_OBJECT) + && mParcelOverlay->encroachesOwned(boxes)) ); +} + +bool LLViewerRegion::childrenObjectReturnable( const std::vector& boxes ) const +{ + bool result = false; + result = ( mParcelOverlay && mParcelOverlay->encroachesOnUnowned( boxes ) ) ? 1 : 0; + return result; +} + +bool LLViewerRegion::objectsCrossParcel(const std::vector& boxes) const +{ + return mParcelOverlay && mParcelOverlay->encroachesOnNearbyParcel(boxes); +} + +void LLViewerRegion::getNeighboringRegions( std::vector& uniqueRegions ) +{ + mImpl->mLandp->getNeighboringRegions( uniqueRegions ); +} +void LLViewerRegion::getNeighboringRegionsStatus( std::vector& 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::meshRezEnabled() const +{ + return (mSimulatorFeatures.has("MeshRezEnabled") && + mSimulatorFeatures["MeshRezEnabled"].asBoolean()); +} + +bool LLViewerRegion::dynamicPathfindingEnabled() const +{ + return ( mSimulatorFeatures.has("DynamicPathfindingEnabled") && + mSimulatorFeatures["DynamicPathfindingEnabled"].asBoolean()); +} + -- cgit v1.3 From 3759a91ba70939c04e12202fe53673f51accab72 Mon Sep 17 00:00:00 2001 From: Baker Linden Date: Mon, 10 Sep 2012 16:30:45 -0700 Subject: Fixed line endings from DOS to UNIX. --- indra/newview/llviewerregion.cpp | 3738 +++++++++++++++++++------------------- 1 file changed, 1869 insertions(+), 1869 deletions(-) (limited to 'indra/newview/llviewerregion.cpp') diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index c00d4e91d7..d825646da0 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -1,1869 +1,1869 @@ -/** - * @file llviewerregion.cpp - * @brief Implementation of the LLViewerRegion class. - * - * $LicenseInfo:firstyear=2000&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "llviewerregion.h" - -// linden libraries -#include "indra_constants.h" -#include "llavatarnamecache.h" // name lookup cap url -#include "llfloaterreg.h" -#include "llmath.h" -#include "llhttpclient.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 "llcallingcard.h" -#include "llcaphttpsender.h" -#include "llcapabilitylistener.h" -#include "llcommandhandler.h" -#include "lldir.h" -#include "lleventpoll.h" -#include "llfloatergodtools.h" -#include "llfloaterreporter.h" -#include "llfloaterregioninfo.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 "llvocache.h" -#include "llworld.h" -#include "llspatialpartition.h" -#include "stringize.h" -#include "llviewercontrol.h" -#include "llsdserialize.h" - -#ifdef LL_WINDOWS - #pragma warning(disable:4355) -#endif - -const F32 WATER_TEXTURE_SCALE = 8.f; // Number of times to repeat the water texture across a region -const S16 MAX_MAP_DIST = 10; -// 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. -// Give it 3 chances, each at 18 seconds to give ourselves a few seconds to connect anyways if we give up. -const S32 MAX_SEED_CAP_ATTEMPTS_BEFORE_LOGIN = 3; -const F32 CAP_REQUEST_TIMEOUT = 18; -// Even though we gave up on login, keep trying for caps after we are logged in: -const S32 MAX_CAP_REQUEST_ATTEMPTS = 30; - -typedef std::map CapabilityMap; - -class LLViewerRegionImpl { -public: - LLViewerRegionImpl(LLViewerRegion * region, LLHost const & host) - : mHost(host), - mCompositionp(NULL), - mEventPoll(NULL), - mSeedCapMaxAttempts(MAX_CAP_REQUEST_ATTEMPTS), - mSeedCapMaxAttemptsBeforeLogin(MAX_SEED_CAP_ATTEMPTS_BEFORE_LOGIN), - mSeedCapAttempts(0), - mHttpResponderID(0), - // I'd prefer to set the LLCapabilityListener name to match the region - // name -- it's disappointing that's not available at construction time. - // We could instead store an LLCapabilityListener*, making - // setRegionNameAndZone() replace the instance. Would that pose - // consistency problems? Can we even request a capability before calling - // setRegionNameAndZone()? - // For testability -- the new Michael Feathers paradigm -- - // LLCapabilityListener binds all the globals it expects to need at - // construction time. - mCapabilityListener(host.getString(), gMessageSystem, *region, - gAgent.getID(), gAgent.getSessionID()) - { - } - - 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; - // time? - // LRU info? - - // Cache ID is unique per-region, across renames, moving locations, - // etc. - LLUUID mCacheID; - - CapabilityMap mCapabilities; - - LLEventPoll* mEventPoll; - - S32 mSeedCapMaxAttempts; - S32 mSeedCapMaxAttemptsBeforeLogin; - S32 mSeedCapAttempts; - - S32 mHttpResponderID; - - /// Post an event to this LLCapabilityListener to invoke a capability message on - /// this LLViewerRegion's server - /// (https://wiki.lindenlab.com/wiki/Viewer:Messaging/Messaging_Notes#Capabilities) - LLCapabilityListener mCapabilityListener; - - //spatial partitions for objects in this region - std::vector mObjectPartition; -}; - -// 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, 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://"; - for (int i = 0; i < num_params; i++) - { - if (i > 0) - { - url += "/"; - } - url += params[i].asString(); - } - - // Process the SLapp as if it was a secondlife://{PLACE} SLurl - LLURLDispatcher::dispatch(url, "clicked", web, true); - return true; - } -}; -LLRegionHandler gRegionHandler; - -class BaseCapabilitiesComplete : public LLHTTPClient::Responder -{ - LOG_CLASS(BaseCapabilitiesComplete); -public: - BaseCapabilitiesComplete(U64 region_handle, S32 id) - : mRegionHandle(region_handle), mID(id) - { } - virtual ~BaseCapabilitiesComplete() - { } - - void error(U32 statusNum, const std::string& reason) - { - LL_WARNS2("AppInit", "Capabilities") << statusNum << ": " << reason << LL_ENDL; - LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); - if (regionp) - { - regionp->failedSeedCapability(); - } - } - - void result(const LLSD& content) - { - LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); - if(!regionp) //region was removed - { - LL_WARNS2("AppInit", "Capabilities") << "Received results for region that no longer exists!" << LL_ENDL; - return ; - } - if( mID != regionp->getHttpResponderID() ) // region is no longer referring to this responder - { - LL_WARNS2("AppInit", "Capabilities") << "Received results for a stale http responder!" << LL_ENDL; - return ; - } - - LLSD::map_const_iterator iter; - for(iter = content.beginMap(); iter != content.endMap(); ++iter) - { - regionp->setCapability(iter->first, iter->second); - LL_DEBUGS2("AppInit", "Capabilities") << "got capability for " - << iter->first << LL_ENDL; - - /* HACK we're waiting for the ServerReleaseNotes */ - if (iter->first == "ServerReleaseNotes" && regionp->getReleaseNotesRequested()) - { - regionp->showReleaseNotes(); - } - } - - regionp->setCapabilitiesReceived(true); - - if (STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState()) - { - LLStartUp::setStartupState( STATE_SEED_CAP_GRANTED ); - } - } - - static boost::intrusive_ptr build( U64 region_handle, S32 id ) - { - return boost::intrusive_ptr( - new BaseCapabilitiesComplete(region_handle, id) ); - } - -private: - U64 mRegionHandle; - S32 mID; -}; - - -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 ), - mSimAccess( SIM_ACCESS_MIN ), - mBillableFactor(1.0), - mMaxTasks(DEFAULT_MAX_REGION_WIDE_PRIM_COUNT), - mClassID(0), - mCPURatio(0), - mColoName("unknown"), - mProductSKU("unknown"), - mProductName("unknown"), - mHttpUrl(""), - mCacheLoaded(FALSE), - mCacheDirty(FALSE), - mReleaseNotesRequested(FALSE), - mCapabilitiesReceived(false) -{ - 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()); //PARTITION_HUD - mImpl->mObjectPartition.push_back(new LLTerrainPartition()); //PARTITION_TERRAIN - mImpl->mObjectPartition.push_back(new LLVoidWaterPartition()); //PARTITION_VOIDWATER - mImpl->mObjectPartition.push_back(new LLWaterPartition()); //PARTITION_WATER - mImpl->mObjectPartition.push_back(new LLTreePartition()); //PARTITION_TREE - mImpl->mObjectPartition.push_back(new LLParticlePartition()); //PARTITION_PARTICLE - mImpl->mObjectPartition.push_back(new LLGrassPartition()); //PARTITION_GRASS - mImpl->mObjectPartition.push_back(new LLVolumePartition()); //PARTITION_VOLUME - mImpl->mObjectPartition.push_back(new LLBridgePartition()); //PARTITION_BRIDGE - mImpl->mObjectPartition.push_back(new LLHUDParticlePartition());//PARTITION_HUD_PARTICLE - mImpl->mObjectPartition.push_back(NULL); //PARTITION_NONE -} - - -void LLViewerRegion::initStats() -{ - mImpl->mLastNetUpdate.reset(); - mPacketsIn = 0; - mBitsIn = 0; - mLastBitsIn = 0; - mLastPacketsIn = 0; - mPacketsOut = 0; - mLastPacketsOut = 0; - mPacketsLost = 0; - mLastPacketsLost = 0; - mPingDelay = 0; - mAlive = false; // can become false if circuit disconnects -} - -LLViewerRegion::~LLViewerRegion() -{ - 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); - - gObjectList.killObjects(this); - - delete mImpl->mCompositionp; - delete mParcelOverlay; - delete mImpl->mLandp; - delete mImpl->mEventPoll; - LLHTTPSender::clearSender(mImpl->mHost); - - saveObjectCache(); - - std::for_each(mImpl->mObjectPartition.begin(), mImpl->mObjectPartition.end(), DeletePointer()); - - delete mImpl; - mImpl = NULL; -} - -LLEventPump& LLViewerRegion::getCapAPI() const -{ - return mImpl->mCapabilityListener.getCapAPI(); -} - -/*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::hasInstance()) - { - LLVOCache::getInstance()->readFromCache(mHandle, mImpl->mCacheID, mImpl->mCacheMap) ; - } -} - - -void LLViewerRegion::saveObjectCache() -{ - if (!mCacheLoaded) - { - return; - } - - if (mImpl->mCacheMap.empty()) - { - return; - } - - if(LLVOCache::hasInstance()) - { - LLVOCache::getInstance()->writeToCache(mHandle, mImpl->mCacheID, mImpl->mCacheMap, mCacheDirty) ; - mCacheDirty = FALSE; - } - - for(LLVOCacheEntry::vocache_entry_map_t::iterator iter = mImpl->mCacheMap.begin(); iter != mImpl->mCacheMap.end(); ++iter) - { - delete iter->second; - } - mImpl->mCacheMap.clear(); -} - -void LLViewerRegion::sendMessage() -{ - gMessageSystem->sendMessage(mImpl->mHost); -} - -void LLViewerRegion::sendReliableMessage() -{ - gMessageSystem->sendReliable(mImpl->mHost); -} - -void LLViewerRegion::setFlags(BOOL b, U32 flags) -{ - if (b) - { - mRegionFlags |= flags; - } - else - { - mRegionFlags &= ~flags; - } -} - -void LLViewerRegion::setWaterHeight(F32 water_level) -{ - mImpl->mLandp->setWaterHeight(water_level); -} - -F32 LLViewerRegion::getWaterHeight() const -{ - return mImpl->mLandp->getWaterHeight(); -} - -BOOL LLViewerRegion::isVoiceEnabled() const -{ - return (getRegionFlags() & REGION_FLAGS_ALLOW_VOICE); -} - -void LLViewerRegion::setRegionFlags(U32 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(U32 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 - llinfos << "Processing region info" << llendl; - LLRegionInfoModel::instance().update(msg); - LLFloaterGodTools::processRegionInfo(msg); - LLFloaterRegionInfo::processRegionInfo(msg); - LLFloaterReporter::processRegionInfo(msg); -} - -void LLViewerRegion::setCacheID(const LLUUID& id) -{ - mImpl->mCacheID = id; -} - -S32 LLViewerRegion::renderPropertyLines() -{ - if (mParcelOverlay) - { - return mParcelOverlay->renderPropertyLines(); - } - else - { - return 0; - } -} - -// 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(); - } -} - -BOOL LLViewerRegion::idleUpdate(F32 max_update_time) -{ - LLMemType mt_ivr(LLMemType::MTYPE_IDLE_UPDATE_VIEWER_REGION); - // did_update returns TRUE if we did at least one significant update - BOOL did_update = mImpl->mLandp->idleUpdate(max_update_time); - - if (mParcelOverlay) - { - // Hopefully not a significant time sink... - mParcelOverlay->idleUpdate(); - } - - return did_update; -} - - -// 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(); - - mBitStat.addValue(mBitsIn - mLastBitsIn); - mPacketsStat.addValue(mPacketsIn - mLastPacketsIn); - mPacketsLostStat.addValue(mPacketsLost); -} - - -U32 LLViewerRegion::getPacketsLost() const -{ - LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(mImpl->mHost); - if (!cdp) - { - llinfos << "LLViewerRegion::getPacketsLost couldn't find circuit for " << mImpl->mHost << llendl; - 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()); - LLViewerRegion* region = LLWorld::getInstance()->getRegion(host); - if( !region ) - { - return; - } - - S32 target_index = input["body"]["Index"][0]["Prey"].asInteger(); - S32 you_index = input["body"]["Index"][0]["You" ].asInteger(); - - LLDynamicArray* avatar_locs = ®ion->mMapAvatars; - LLDynamicArray* avatar_ids = ®ion->mMapAvatarIDs; - avatar_locs->reset(); - avatar_ids->reset(); - - //llinfos << "coarse locations agent[0] " << input["body"]["AgentData"][0]["AgentID"].asUUID() << llendl; - //llinfos << "my agent id = " << gAgent.getID() << llendl; - //llinfos << ll_pretty_print_sd(input) << llendl; - - 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 loc = x << 16 | y << 8 | z; loc = loc; - U32 pos = 0x0; - pos |= x; - pos <<= 8; - pos |= y; - pos <<= 8; - pos |= z; - avatar_locs->put(pos); - //llinfos << "next pos: " << x << "," << y << "," << z << ": " << pos << llendl; - if(has_agent_data) // for backwards compatibility with old message format - { - LLUUID agent_id(agents_it->get("AgentID").asUUID()); - //llinfos << "next agent: " << agent_id.asString() << llendl; - avatar_ids->put(agent_id); - } - } - if (has_agent_data) - { - agents_it++; - } - } - } -}; - -// build the coarse location HTTP node under the "/message" URL -LLHTTPRegistration - gHTTPRegistrationCoarseLocationUpdate( - "/message/CoarseLocationUpdate"); - - -// the deprecated coarse location handler -void LLViewerRegion::updateCoarseLocations(LLMessageSystem* msg) -{ - //llinfos << "CoarseLocationUpdate" << llendl; - mMapAvatars.reset(); - mMapAvatarIDs.reset(); // 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); - } - - //llinfos << " object X: " << (S32)x_pos << " Y: " << (S32)y_pos - // << " Z: " << (S32)(z_pos * 4) - // << llendl; - - // 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.put(pos); - if(has_agent_data) - { - mMapAvatarIDs.put(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::getSimulatorFeatures(LLSD& sim_features) -{ - sim_features = mSimulatorFeatures; - -} - -void LLViewerRegion::setSimulatorFeatures(const LLSD& sim_features) -{ - std::stringstream str; - - LLSDSerialize::toPrettyXML(sim_features, str); - llinfos << str.str() << llendl; - mSimulatorFeatures = sim_features; -} - -LLViewerRegion::eCacheUpdateResult LLViewerRegion::cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinaryBuffer &dp) -{ - U32 local_id = objectp->getLocalID(); - U32 crc = objectp->getCRC(); - - LLVOCacheEntry* entry = get_if_there(mImpl->mCacheMap, local_id, (LLVOCacheEntry*)NULL); - - if (entry) - { - // we've seen this object before - if (entry->getCRC() == crc) - { - // Record a hit - entry->recordDupe(); - return CACHE_UPDATE_DUPE; - } - - // Update the cache entry - mImpl->mCacheMap.erase(local_id); - delete entry; - entry = new LLVOCacheEntry(local_id, crc, dp); - mImpl->mCacheMap[local_id] = entry; - return CACHE_UPDATE_CHANGED; - } - - // we haven't seen this object before - - // Create new entry and add to map - eCacheUpdateResult result = CACHE_UPDATE_ADDED; - if (mImpl->mCacheMap.size() > MAX_OBJECT_CACHE_ENTRIES) - { - delete mImpl->mCacheMap.begin()->second ; - mImpl->mCacheMap.erase(mImpl->mCacheMap.begin()); - result = CACHE_UPDATE_REPLACED; - - } - entry = new LLVOCacheEntry(local_id, crc, dp); - - mImpl->mCacheMap[local_id] = entry; - return result; -} - -// Get data packer for this object, if we have cached data -// AND the CRC matches. JC -LLDataPacker *LLViewerRegion::getDP(U32 local_id, U32 crc, U8 &cache_miss_type) -{ - //llassert(mCacheLoaded); This assert failes often, changing to early-out -- davep, 2010/10/18 - - LLVOCacheEntry* entry = get_if_there(mImpl->mCacheMap, local_id, (LLVOCacheEntry*)NULL); - - if (entry) - { - // we've seen this object before - if (entry->getCRC() == crc) - { - // Record a hit - entry->recordHit(); - cache_miss_type = CACHE_MISS_TYPE_NONE; - return entry->getDP(crc); - } - else - { - // llinfos << "CRC miss for " << local_id << llendl; - cache_miss_type = CACHE_MISS_TYPE_CRC; - mCacheMissCRC.put(local_id); - } - } - else - { - // llinfos << "Cache miss for " << local_id << llendl; - cache_miss_type = CACHE_MISS_TYPE_FULL; - mCacheMissFull.put(local_id); - } - - return NULL; -} - -void LLViewerRegion::addCacheMissFull(const U32 local_id) -{ - mCacheMissFull.put(local_id); -} - -void LLViewerRegion::requestCacheMisses() -{ - S32 full_count = mCacheMissFull.count(); - S32 crc_count = mCacheMissCRC.count(); - if (full_count == 0 && crc_count == 0) return; - - LLMessageSystem* msg = gMessageSystem; - BOOL start_new_message = TRUE; - S32 blocks = 0; - S32 i; - - // Send full cache miss updates. For these, we KNOW we don't - // have a viewer object. - for (i = 0; i < full_count; i++) - { - 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, CACHE_MISS_TYPE_FULL); - msg->addU32Fast(_PREHASH_ID, mCacheMissFull[i]); - blocks++; - - if (blocks >= 255) - { - sendReliableMessage(); - start_new_message = TRUE; - blocks = 0; - } - } - - // Send CRC miss updates. For these, we _might_ have a viewer object, - // but probably not. - for (i = 0; i < crc_count; i++) - { - 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, CACHE_MISS_TYPE_CRC); - msg->addU32Fast(_PREHASH_ID, mCacheMissCRC[i]); - blocks++; - - if (blocks >= 255) - { - sendReliableMessage(); - start_new_message = TRUE; - blocks = 0; - } - } - - // finish any pending message - if (!start_new_message) - { - sendReliableMessage(); - } - mCacheMissFull.reset(); - mCacheMissCRC.reset(); - - mCacheDirty = TRUE ; - // llinfos << "KILLDEBUG Sent cache miss full " << full_count << " crc " << crc_count << llendl; - #if LL_RECORD_VIEWER_STATS - LLViewerStatsRecorder::instance()->beginObjectUpdateEvents(this); - LLViewerStatsRecorder::instance()->recordRequestCacheMissesEvent(full_count + crc_count); - LLViewerStatsRecorder::instance()->endObjectUpdateEvents(); - #endif -} - -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]++; - } - - llinfos << "Count " << mImpl->mCacheMap.size() << llendl; - for (i = 0; i < BINS; i++) - { - llinfos << "Hits " << i << " " << hit_bin[i] << llendl; - } - for (i = 0; i < BINS; i++) - { - llinfos << "Changes " << i << " " << change_bin[i] << llendl; - } -} - -void LLViewerRegion::unpackRegionHandshake() -{ - LLMessageSystem *msg = gMessageSystem; - - U32 region_flags; - U8 sim_access; - std::string sim_name; - LLUUID sim_owner; - BOOL is_estate_manager; - F32 water_height; - F32 billable_factor; - LLUUID cache_id; - - msg->getU32 ("RegionInfo", "RegionFlags", region_flags); - 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 ); - - setRegionFlags(region_flags); - 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; - } - - LLVLComposition *compp = getComposition(); - if (compp) - { - LLUUID tmp_id; - - msg->getUUID("RegionInfo", "TerrainDetail0", tmp_id); - compp->setDetailTextureID(0, tmp_id); - msg->getUUID("RegionInfo", "TerrainDetail1", tmp_id); - compp->setDetailTextureID(1, tmp_id); - msg->getUUID("RegionInfo", "TerrainDetail2", tmp_id); - compp->setDetailTextureID(2, tmp_id); - msg->getUUID("RegionInfo", "TerrainDetail3", tmp_id); - compp->setDetailTextureID(3, tmp_id); - - F32 tmp_f32; - msg->getF32("RegionInfo", "TerrainStartHeight00", tmp_f32); - compp->setStartHeight(0, tmp_f32); - msg->getF32("RegionInfo", "TerrainStartHeight01", tmp_f32); - compp->setStartHeight(1, tmp_f32); - msg->getF32("RegionInfo", "TerrainStartHeight10", tmp_f32); - compp->setStartHeight(2, tmp_f32); - msg->getF32("RegionInfo", "TerrainStartHeight11", tmp_f32); - compp->setStartHeight(3, tmp_f32); - - msg->getF32("RegionInfo", "TerrainHeightRange00", tmp_f32); - compp->setHeightRange(0, tmp_f32); - msg->getF32("RegionInfo", "TerrainHeightRange01", tmp_f32); - compp->setHeightRange(1, tmp_f32); - msg->getF32("RegionInfo", "TerrainHeightRange10", tmp_f32); - compp->setHeightRange(2, tmp_f32); - msg->getF32("RegionInfo", "TerrainHeightRange11", tmp_f32); - 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()) - { - //this line creates frame stalls on region crossing and removing it appears to have no effect - //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"); - msg->addU32("Flags", 0x0 ); - msg->sendReliable(host); -} - -void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) -{ - capabilityNames.append("AgentState"); - capabilityNames.append("AttachmentResources"); - capabilityNames.append("AvatarPickerSearch"); - capabilityNames.append("CharacterProperties"); - capabilityNames.append("ChatSessionRequest"); - capabilityNames.append("CopyInventoryFromNotecard"); - capabilityNames.append("CreateInventoryCategory"); - capabilityNames.append("DispatchRegionInfo"); - capabilityNames.append("EnvironmentSettings"); - capabilityNames.append("EstateChangeInfo"); - capabilityNames.append("EventQueueGet"); - - if (gSavedSettings.getBOOL("UseHTTPInventory")) - { - capabilityNames.append("FetchLib2"); - capabilityNames.append("FetchLibDescendents2"); - capabilityNames.append("FetchInventory2"); - capabilityNames.append("FetchInventoryDescendents2"); - } - - capabilityNames.append("GetDisplayNames"); - capabilityNames.append("GetMesh"); - capabilityNames.append("GetObjectCost"); - capabilityNames.append("GetObjectPhysicsData"); - capabilityNames.append("GetTexture"); - capabilityNames.append("GroupMemberData"); - capabilityNames.append("GroupProposalBallot"); - capabilityNames.append("HomeLocation"); - capabilityNames.append("LandResources"); - capabilityNames.append("MapLayer"); - capabilityNames.append("MapLayerGod"); - capabilityNames.append("MeshUploadFlag"); - capabilityNames.append("NavMeshGenerationStatus"); - capabilityNames.append("NewFileAgentInventory"); - capabilityNames.append("ObjectMedia"); - capabilityNames.append("ObjectMediaNavigate"); - capabilityNames.append("ObjectNavMeshProperties"); - capabilityNames.append("ParcelPropertiesUpdate"); - capabilityNames.append("ParcelVoiceInfoRequest"); - capabilityNames.append("ProductInfoRequest"); - capabilityNames.append("ProvisionVoiceAccountRequest"); - capabilityNames.append("RemoteParcelRequest"); - 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("UpdateGestureAgentInventory"); - capabilityNames.append("UpdateGestureTaskInventory"); - capabilityNames.append("UpdateNotecardAgentInventory"); - capabilityNames.append("UpdateNotecardTaskInventory"); - capabilityNames.append("UpdateScriptAgent"); - capabilityNames.append("UpdateScriptTask"); - capabilityNames.append("UploadBakedTexture"); - 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) - { - // llwarns << "Ignoring duplicate seed capability" << llendl; - return; - } - - delete mImpl->mEventPoll; - mImpl->mEventPoll = NULL; - - mImpl->mCapabilities.clear(); - setCapability("Seed", url); - - LLSD capabilityNames = LLSD::emptyArray(); - mImpl->buildCapabilityNames(capabilityNames); - - llinfos << "posting to seed " << url << llendl; - - S32 id = ++mImpl->mHttpResponderID; - LLHTTPClient::post(url, capabilityNames, - BaseCapabilitiesComplete::build(getHandle(), id), - LLSD(), CAP_REQUEST_TIMEOUT); -} - -S32 LLViewerRegion::getNumSeedCapRetries() -{ - return mImpl->mSeedCapAttempts; -} - -void LLViewerRegion::failedSeedCapability() -{ - // Should we retry asking for caps? - mImpl->mSeedCapAttempts++; - std::string url = getCapability("Seed"); - if ( url.empty() ) - { - LL_WARNS2("AppInit", "Capabilities") << "Failed to get seed capabilities, and can not determine url for retries!" << LL_ENDL; - return; - } - // After a few attempts, continue login. We will keep trying once in-world: - if ( mImpl->mSeedCapAttempts >= mImpl->mSeedCapMaxAttemptsBeforeLogin && - STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState() ) - { - LLStartUp::setStartupState( STATE_SEED_CAP_GRANTED ); - } - - if ( mImpl->mSeedCapAttempts < mImpl->mSeedCapMaxAttempts) - { - LLSD capabilityNames = LLSD::emptyArray(); - mImpl->buildCapabilityNames(capabilityNames); - - llinfos << "posting to seed " << url << " (retry " - << mImpl->mSeedCapAttempts << ")" << llendl; - - S32 id = ++mImpl->mHttpResponderID; - LLHTTPClient::post(url, capabilityNames, - BaseCapabilitiesComplete::build(getHandle(), id), - LLSD(), CAP_REQUEST_TIMEOUT); - } - else - { - // *TODO: Give a user pop-up about this error? - LL_WARNS2("AppInit", "Capabilities") << "Failed to get seed capabilities from '" << url << "' after " << mImpl->mSeedCapAttempts << " attempts. Giving up!" << LL_ENDL; - } -} - -class SimulatorFeaturesReceived : public LLHTTPClient::Responder -{ - LOG_CLASS(SimulatorFeaturesReceived); -public: - SimulatorFeaturesReceived(const std::string& retry_url, U64 region_handle, - S32 attempt = 0, S32 max_attempts = MAX_CAP_REQUEST_ATTEMPTS) - : mRetryURL(retry_url), mRegionHandle(region_handle), mAttempt(attempt), mMaxAttempts(max_attempts) - { } - - - void error(U32 statusNum, const std::string& reason) - { - LL_WARNS2("AppInit", "SimulatorFeatures") << statusNum << ": " << reason << LL_ENDL; - retry(); - } - - void result(const LLSD& content) - { - LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); - if(!regionp) //region is removed or responder is not created. - { - LL_WARNS2("AppInit", "SimulatorFeatures") << "Received results for region that no longer exists!" << LL_ENDL; - return ; - } - - regionp->setSimulatorFeatures(content); - } - -private: - void retry() - { - if (mAttempt < mMaxAttempts) - { - mAttempt++; - LL_WARNS2("AppInit", "SimulatorFeatures") << "Re-trying '" << mRetryURL << "'. Retry #" << mAttempt << LL_ENDL; - LLHTTPClient::get(mRetryURL, new SimulatorFeaturesReceived(*this), LLSD(), CAP_REQUEST_TIMEOUT); - } - } - - std::string mRetryURL; - U64 mRegionHandle; - S32 mAttempt; - S32 mMaxAttempts; -}; - - -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") - { - LLHTTPSender::setSender(mImpl->mHost, new LLCapHTTPSender(url)); - } - else if (name == "SimulatorFeatures") - { - // kick off a request for simulator features - LLHTTPClient::get(url, new SimulatorFeaturesReceived(url, getHandle()), LLSD(), CAP_REQUEST_TIMEOUT); - } - else - { - mImpl->mCapabilities[name] = url; - if(name == "GetTexture") - { - mHttpUrl = url ; - } - } -} - -bool LLViewerRegion::isSpecialCapabilityName(const std::string &name) -{ - return name == "EventQueueGet" || name == "UntrustedSimulatorMessage"; -} - -std::string LLViewerRegion::getCapability(const std::string& name) const -{ - CapabilityMap::const_iterator iter = mImpl->mCapabilities.find(name); - if(iter == mImpl->mCapabilities.end()) - { - return ""; - } - - return iter->second; -} - -bool LLViewerRegion::capabilitiesReceived() const -{ - return mCapabilitiesReceived; -} - -void LLViewerRegion::setCapabilitiesReceived(bool received) -{ - mCapabilitiesReceived = received; - - // Tell interested parties that we've received capabilities, - // so that they can safely use getCapability(). - if (received) - { - mCapabilitiesReceivedSignal(getRegionID()); - - // This is a single-shot signal. Forget callbacks to save resources. - mCapabilitiesReceivedSignal.disconnect_all_slots(); - } -} - -boost::signals2::connection LLViewerRegion::setCapabilitiesReceivedCallback(const caps_received_signal_t::slot_type& cb) -{ - return mCapabilitiesReceivedSignal.connect(cb); -} - -void LLViewerRegion::logActiveCapabilities() const -{ - int count = 0; - CapabilityMap::const_iterator iter; - for (iter = mImpl->mCapabilities.begin(); iter != mImpl->mCapabilities.end(); ++iter, ++count) - { - if (!iter->second.empty()) - { - llinfos << iter->first << " URL is " << iter->second << llendl; - } - } - llinfos << "Dumped " << count << " entries." << llendl; -} - -LLSpatialPartition* LLViewerRegion::getSpatialPartition(U32 type) -{ - if (type < mImpl->mObjectPartition.size()) - { - return mImpl->mObjectPartition[type]; - } - 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 U32 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& boxes) const -{ - return (mParcelOverlay != NULL) - && (mParcelOverlay->isOwnedSelf(pos) - || mParcelOverlay->isOwnedGroup(pos) - || ((mRegionFlags & ALLOW_RETURN_ENCROACHING_OBJECT) - && mParcelOverlay->encroachesOwned(boxes)) ); -} - -bool LLViewerRegion::childrenObjectReturnable( const std::vector& boxes ) const -{ - bool result = false; - result = ( mParcelOverlay && mParcelOverlay->encroachesOnUnowned( boxes ) ) ? 1 : 0; - return result; -} - -bool LLViewerRegion::objectsCrossParcel(const std::vector& boxes) const -{ - return mParcelOverlay && mParcelOverlay->encroachesOnNearbyParcel(boxes); -} - -void LLViewerRegion::getNeighboringRegions( std::vector& uniqueRegions ) -{ - mImpl->mLandp->getNeighboringRegions( uniqueRegions ); -} -void LLViewerRegion::getNeighboringRegionsStatus( std::vector& 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::meshRezEnabled() const -{ - return (mSimulatorFeatures.has("MeshRezEnabled") && - mSimulatorFeatures["MeshRezEnabled"].asBoolean()); -} - -bool LLViewerRegion::dynamicPathfindingEnabled() const -{ - return ( mSimulatorFeatures.has("DynamicPathfindingEnabled") && - mSimulatorFeatures["DynamicPathfindingEnabled"].asBoolean()); -} - +/** + * @file llviewerregion.cpp + * @brief Implementation of the LLViewerRegion class. + * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llviewerregion.h" + +// linden libraries +#include "indra_constants.h" +#include "llavatarnamecache.h" // name lookup cap url +#include "llfloaterreg.h" +#include "llmath.h" +#include "llhttpclient.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 "llcallingcard.h" +#include "llcaphttpsender.h" +#include "llcapabilitylistener.h" +#include "llcommandhandler.h" +#include "lldir.h" +#include "lleventpoll.h" +#include "llfloatergodtools.h" +#include "llfloaterreporter.h" +#include "llfloaterregioninfo.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 "llvocache.h" +#include "llworld.h" +#include "llspatialpartition.h" +#include "stringize.h" +#include "llviewercontrol.h" +#include "llsdserialize.h" + +#ifdef LL_WINDOWS + #pragma warning(disable:4355) +#endif + +const F32 WATER_TEXTURE_SCALE = 8.f; // Number of times to repeat the water texture across a region +const S16 MAX_MAP_DIST = 10; +// 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. +// Give it 3 chances, each at 18 seconds to give ourselves a few seconds to connect anyways if we give up. +const S32 MAX_SEED_CAP_ATTEMPTS_BEFORE_LOGIN = 3; +const F32 CAP_REQUEST_TIMEOUT = 18; +// Even though we gave up on login, keep trying for caps after we are logged in: +const S32 MAX_CAP_REQUEST_ATTEMPTS = 30; + +typedef std::map CapabilityMap; + +class LLViewerRegionImpl { +public: + LLViewerRegionImpl(LLViewerRegion * region, LLHost const & host) + : mHost(host), + mCompositionp(NULL), + mEventPoll(NULL), + mSeedCapMaxAttempts(MAX_CAP_REQUEST_ATTEMPTS), + mSeedCapMaxAttemptsBeforeLogin(MAX_SEED_CAP_ATTEMPTS_BEFORE_LOGIN), + mSeedCapAttempts(0), + mHttpResponderID(0), + // I'd prefer to set the LLCapabilityListener name to match the region + // name -- it's disappointing that's not available at construction time. + // We could instead store an LLCapabilityListener*, making + // setRegionNameAndZone() replace the instance. Would that pose + // consistency problems? Can we even request a capability before calling + // setRegionNameAndZone()? + // For testability -- the new Michael Feathers paradigm -- + // LLCapabilityListener binds all the globals it expects to need at + // construction time. + mCapabilityListener(host.getString(), gMessageSystem, *region, + gAgent.getID(), gAgent.getSessionID()) + { + } + + 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; + // time? + // LRU info? + + // Cache ID is unique per-region, across renames, moving locations, + // etc. + LLUUID mCacheID; + + CapabilityMap mCapabilities; + + LLEventPoll* mEventPoll; + + S32 mSeedCapMaxAttempts; + S32 mSeedCapMaxAttemptsBeforeLogin; + S32 mSeedCapAttempts; + + S32 mHttpResponderID; + + /// Post an event to this LLCapabilityListener to invoke a capability message on + /// this LLViewerRegion's server + /// (https://wiki.lindenlab.com/wiki/Viewer:Messaging/Messaging_Notes#Capabilities) + LLCapabilityListener mCapabilityListener; + + //spatial partitions for objects in this region + std::vector mObjectPartition; +}; + +// 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, 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://"; + for (int i = 0; i < num_params; i++) + { + if (i > 0) + { + url += "/"; + } + url += params[i].asString(); + } + + // Process the SLapp as if it was a secondlife://{PLACE} SLurl + LLURLDispatcher::dispatch(url, "clicked", web, true); + return true; + } +}; +LLRegionHandler gRegionHandler; + +class BaseCapabilitiesComplete : public LLHTTPClient::Responder +{ + LOG_CLASS(BaseCapabilitiesComplete); +public: + BaseCapabilitiesComplete(U64 region_handle, S32 id) + : mRegionHandle(region_handle), mID(id) + { } + virtual ~BaseCapabilitiesComplete() + { } + + void error(U32 statusNum, const std::string& reason) + { + LL_WARNS2("AppInit", "Capabilities") << statusNum << ": " << reason << LL_ENDL; + LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); + if (regionp) + { + regionp->failedSeedCapability(); + } + } + + void result(const LLSD& content) + { + LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); + if(!regionp) //region was removed + { + LL_WARNS2("AppInit", "Capabilities") << "Received results for region that no longer exists!" << LL_ENDL; + return ; + } + if( mID != regionp->getHttpResponderID() ) // region is no longer referring to this responder + { + LL_WARNS2("AppInit", "Capabilities") << "Received results for a stale http responder!" << LL_ENDL; + return ; + } + + LLSD::map_const_iterator iter; + for(iter = content.beginMap(); iter != content.endMap(); ++iter) + { + regionp->setCapability(iter->first, iter->second); + LL_DEBUGS2("AppInit", "Capabilities") << "got capability for " + << iter->first << LL_ENDL; + + /* HACK we're waiting for the ServerReleaseNotes */ + if (iter->first == "ServerReleaseNotes" && regionp->getReleaseNotesRequested()) + { + regionp->showReleaseNotes(); + } + } + + regionp->setCapabilitiesReceived(true); + + if (STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState()) + { + LLStartUp::setStartupState( STATE_SEED_CAP_GRANTED ); + } + } + + static boost::intrusive_ptr build( U64 region_handle, S32 id ) + { + return boost::intrusive_ptr( + new BaseCapabilitiesComplete(region_handle, id) ); + } + +private: + U64 mRegionHandle; + S32 mID; +}; + + +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 ), + mSimAccess( SIM_ACCESS_MIN ), + mBillableFactor(1.0), + mMaxTasks(DEFAULT_MAX_REGION_WIDE_PRIM_COUNT), + mClassID(0), + mCPURatio(0), + mColoName("unknown"), + mProductSKU("unknown"), + mProductName("unknown"), + mHttpUrl(""), + mCacheLoaded(FALSE), + mCacheDirty(FALSE), + mReleaseNotesRequested(FALSE), + mCapabilitiesReceived(false) +{ + 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()); //PARTITION_HUD + mImpl->mObjectPartition.push_back(new LLTerrainPartition()); //PARTITION_TERRAIN + mImpl->mObjectPartition.push_back(new LLVoidWaterPartition()); //PARTITION_VOIDWATER + mImpl->mObjectPartition.push_back(new LLWaterPartition()); //PARTITION_WATER + mImpl->mObjectPartition.push_back(new LLTreePartition()); //PARTITION_TREE + mImpl->mObjectPartition.push_back(new LLParticlePartition()); //PARTITION_PARTICLE + mImpl->mObjectPartition.push_back(new LLGrassPartition()); //PARTITION_GRASS + mImpl->mObjectPartition.push_back(new LLVolumePartition()); //PARTITION_VOLUME + mImpl->mObjectPartition.push_back(new LLBridgePartition()); //PARTITION_BRIDGE + mImpl->mObjectPartition.push_back(new LLHUDParticlePartition());//PARTITION_HUD_PARTICLE + mImpl->mObjectPartition.push_back(NULL); //PARTITION_NONE +} + + +void LLViewerRegion::initStats() +{ + mImpl->mLastNetUpdate.reset(); + mPacketsIn = 0; + mBitsIn = 0; + mLastBitsIn = 0; + mLastPacketsIn = 0; + mPacketsOut = 0; + mLastPacketsOut = 0; + mPacketsLost = 0; + mLastPacketsLost = 0; + mPingDelay = 0; + mAlive = false; // can become false if circuit disconnects +} + +LLViewerRegion::~LLViewerRegion() +{ + 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); + + gObjectList.killObjects(this); + + delete mImpl->mCompositionp; + delete mParcelOverlay; + delete mImpl->mLandp; + delete mImpl->mEventPoll; + LLHTTPSender::clearSender(mImpl->mHost); + + saveObjectCache(); + + std::for_each(mImpl->mObjectPartition.begin(), mImpl->mObjectPartition.end(), DeletePointer()); + + delete mImpl; + mImpl = NULL; +} + +LLEventPump& LLViewerRegion::getCapAPI() const +{ + return mImpl->mCapabilityListener.getCapAPI(); +} + +/*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::hasInstance()) + { + LLVOCache::getInstance()->readFromCache(mHandle, mImpl->mCacheID, mImpl->mCacheMap) ; + } +} + + +void LLViewerRegion::saveObjectCache() +{ + if (!mCacheLoaded) + { + return; + } + + if (mImpl->mCacheMap.empty()) + { + return; + } + + if(LLVOCache::hasInstance()) + { + LLVOCache::getInstance()->writeToCache(mHandle, mImpl->mCacheID, mImpl->mCacheMap, mCacheDirty) ; + mCacheDirty = FALSE; + } + + for(LLVOCacheEntry::vocache_entry_map_t::iterator iter = mImpl->mCacheMap.begin(); iter != mImpl->mCacheMap.end(); ++iter) + { + delete iter->second; + } + mImpl->mCacheMap.clear(); +} + +void LLViewerRegion::sendMessage() +{ + gMessageSystem->sendMessage(mImpl->mHost); +} + +void LLViewerRegion::sendReliableMessage() +{ + gMessageSystem->sendReliable(mImpl->mHost); +} + +void LLViewerRegion::setFlags(BOOL b, U32 flags) +{ + if (b) + { + mRegionFlags |= flags; + } + else + { + mRegionFlags &= ~flags; + } +} + +void LLViewerRegion::setWaterHeight(F32 water_level) +{ + mImpl->mLandp->setWaterHeight(water_level); +} + +F32 LLViewerRegion::getWaterHeight() const +{ + return mImpl->mLandp->getWaterHeight(); +} + +BOOL LLViewerRegion::isVoiceEnabled() const +{ + return (getRegionFlags() & REGION_FLAGS_ALLOW_VOICE); +} + +void LLViewerRegion::setRegionFlags(U32 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(U32 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 + llinfos << "Processing region info" << llendl; + LLRegionInfoModel::instance().update(msg); + LLFloaterGodTools::processRegionInfo(msg); + LLFloaterRegionInfo::processRegionInfo(msg); + LLFloaterReporter::processRegionInfo(msg); +} + +void LLViewerRegion::setCacheID(const LLUUID& id) +{ + mImpl->mCacheID = id; +} + +S32 LLViewerRegion::renderPropertyLines() +{ + if (mParcelOverlay) + { + return mParcelOverlay->renderPropertyLines(); + } + else + { + return 0; + } +} + +// 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(); + } +} + +BOOL LLViewerRegion::idleUpdate(F32 max_update_time) +{ + LLMemType mt_ivr(LLMemType::MTYPE_IDLE_UPDATE_VIEWER_REGION); + // did_update returns TRUE if we did at least one significant update + BOOL did_update = mImpl->mLandp->idleUpdate(max_update_time); + + if (mParcelOverlay) + { + // Hopefully not a significant time sink... + mParcelOverlay->idleUpdate(); + } + + return did_update; +} + + +// 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(); + + mBitStat.addValue(mBitsIn - mLastBitsIn); + mPacketsStat.addValue(mPacketsIn - mLastPacketsIn); + mPacketsLostStat.addValue(mPacketsLost); +} + + +U32 LLViewerRegion::getPacketsLost() const +{ + LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(mImpl->mHost); + if (!cdp) + { + llinfos << "LLViewerRegion::getPacketsLost couldn't find circuit for " << mImpl->mHost << llendl; + 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()); + LLViewerRegion* region = LLWorld::getInstance()->getRegion(host); + if( !region ) + { + return; + } + + S32 target_index = input["body"]["Index"][0]["Prey"].asInteger(); + S32 you_index = input["body"]["Index"][0]["You" ].asInteger(); + + LLDynamicArray* avatar_locs = ®ion->mMapAvatars; + LLDynamicArray* avatar_ids = ®ion->mMapAvatarIDs; + avatar_locs->reset(); + avatar_ids->reset(); + + //llinfos << "coarse locations agent[0] " << input["body"]["AgentData"][0]["AgentID"].asUUID() << llendl; + //llinfos << "my agent id = " << gAgent.getID() << llendl; + //llinfos << ll_pretty_print_sd(input) << llendl; + + 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 loc = x << 16 | y << 8 | z; loc = loc; + U32 pos = 0x0; + pos |= x; + pos <<= 8; + pos |= y; + pos <<= 8; + pos |= z; + avatar_locs->put(pos); + //llinfos << "next pos: " << x << "," << y << "," << z << ": " << pos << llendl; + if(has_agent_data) // for backwards compatibility with old message format + { + LLUUID agent_id(agents_it->get("AgentID").asUUID()); + //llinfos << "next agent: " << agent_id.asString() << llendl; + avatar_ids->put(agent_id); + } + } + if (has_agent_data) + { + agents_it++; + } + } + } +}; + +// build the coarse location HTTP node under the "/message" URL +LLHTTPRegistration + gHTTPRegistrationCoarseLocationUpdate( + "/message/CoarseLocationUpdate"); + + +// the deprecated coarse location handler +void LLViewerRegion::updateCoarseLocations(LLMessageSystem* msg) +{ + //llinfos << "CoarseLocationUpdate" << llendl; + mMapAvatars.reset(); + mMapAvatarIDs.reset(); // 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); + } + + //llinfos << " object X: " << (S32)x_pos << " Y: " << (S32)y_pos + // << " Z: " << (S32)(z_pos * 4) + // << llendl; + + // 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.put(pos); + if(has_agent_data) + { + mMapAvatarIDs.put(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::getSimulatorFeatures(LLSD& sim_features) +{ + sim_features = mSimulatorFeatures; + +} + +void LLViewerRegion::setSimulatorFeatures(const LLSD& sim_features) +{ + std::stringstream str; + + LLSDSerialize::toPrettyXML(sim_features, str); + llinfos << str.str() << llendl; + mSimulatorFeatures = sim_features; +} + +LLViewerRegion::eCacheUpdateResult LLViewerRegion::cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinaryBuffer &dp) +{ + U32 local_id = objectp->getLocalID(); + U32 crc = objectp->getCRC(); + + LLVOCacheEntry* entry = get_if_there(mImpl->mCacheMap, local_id, (LLVOCacheEntry*)NULL); + + if (entry) + { + // we've seen this object before + if (entry->getCRC() == crc) + { + // Record a hit + entry->recordDupe(); + return CACHE_UPDATE_DUPE; + } + + // Update the cache entry + mImpl->mCacheMap.erase(local_id); + delete entry; + entry = new LLVOCacheEntry(local_id, crc, dp); + mImpl->mCacheMap[local_id] = entry; + return CACHE_UPDATE_CHANGED; + } + + // we haven't seen this object before + + // Create new entry and add to map + eCacheUpdateResult result = CACHE_UPDATE_ADDED; + if (mImpl->mCacheMap.size() > MAX_OBJECT_CACHE_ENTRIES) + { + delete mImpl->mCacheMap.begin()->second ; + mImpl->mCacheMap.erase(mImpl->mCacheMap.begin()); + result = CACHE_UPDATE_REPLACED; + + } + entry = new LLVOCacheEntry(local_id, crc, dp); + + mImpl->mCacheMap[local_id] = entry; + return result; +} + +// Get data packer for this object, if we have cached data +// AND the CRC matches. JC +LLDataPacker *LLViewerRegion::getDP(U32 local_id, U32 crc, U8 &cache_miss_type) +{ + //llassert(mCacheLoaded); This assert failes often, changing to early-out -- davep, 2010/10/18 + + LLVOCacheEntry* entry = get_if_there(mImpl->mCacheMap, local_id, (LLVOCacheEntry*)NULL); + + if (entry) + { + // we've seen this object before + if (entry->getCRC() == crc) + { + // Record a hit + entry->recordHit(); + cache_miss_type = CACHE_MISS_TYPE_NONE; + return entry->getDP(crc); + } + else + { + // llinfos << "CRC miss for " << local_id << llendl; + cache_miss_type = CACHE_MISS_TYPE_CRC; + mCacheMissCRC.put(local_id); + } + } + else + { + // llinfos << "Cache miss for " << local_id << llendl; + cache_miss_type = CACHE_MISS_TYPE_FULL; + mCacheMissFull.put(local_id); + } + + return NULL; +} + +void LLViewerRegion::addCacheMissFull(const U32 local_id) +{ + mCacheMissFull.put(local_id); +} + +void LLViewerRegion::requestCacheMisses() +{ + S32 full_count = mCacheMissFull.count(); + S32 crc_count = mCacheMissCRC.count(); + if (full_count == 0 && crc_count == 0) return; + + LLMessageSystem* msg = gMessageSystem; + BOOL start_new_message = TRUE; + S32 blocks = 0; + S32 i; + + // Send full cache miss updates. For these, we KNOW we don't + // have a viewer object. + for (i = 0; i < full_count; i++) + { + 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, CACHE_MISS_TYPE_FULL); + msg->addU32Fast(_PREHASH_ID, mCacheMissFull[i]); + blocks++; + + if (blocks >= 255) + { + sendReliableMessage(); + start_new_message = TRUE; + blocks = 0; + } + } + + // Send CRC miss updates. For these, we _might_ have a viewer object, + // but probably not. + for (i = 0; i < crc_count; i++) + { + 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, CACHE_MISS_TYPE_CRC); + msg->addU32Fast(_PREHASH_ID, mCacheMissCRC[i]); + blocks++; + + if (blocks >= 255) + { + sendReliableMessage(); + start_new_message = TRUE; + blocks = 0; + } + } + + // finish any pending message + if (!start_new_message) + { + sendReliableMessage(); + } + mCacheMissFull.reset(); + mCacheMissCRC.reset(); + + mCacheDirty = TRUE ; + // llinfos << "KILLDEBUG Sent cache miss full " << full_count << " crc " << crc_count << llendl; + #if LL_RECORD_VIEWER_STATS + LLViewerStatsRecorder::instance()->beginObjectUpdateEvents(this); + LLViewerStatsRecorder::instance()->recordRequestCacheMissesEvent(full_count + crc_count); + LLViewerStatsRecorder::instance()->endObjectUpdateEvents(); + #endif +} + +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]++; + } + + llinfos << "Count " << mImpl->mCacheMap.size() << llendl; + for (i = 0; i < BINS; i++) + { + llinfos << "Hits " << i << " " << hit_bin[i] << llendl; + } + for (i = 0; i < BINS; i++) + { + llinfos << "Changes " << i << " " << change_bin[i] << llendl; + } +} + +void LLViewerRegion::unpackRegionHandshake() +{ + LLMessageSystem *msg = gMessageSystem; + + U32 region_flags; + U8 sim_access; + std::string sim_name; + LLUUID sim_owner; + BOOL is_estate_manager; + F32 water_height; + F32 billable_factor; + LLUUID cache_id; + + msg->getU32 ("RegionInfo", "RegionFlags", region_flags); + 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 ); + + setRegionFlags(region_flags); + 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; + } + + LLVLComposition *compp = getComposition(); + if (compp) + { + LLUUID tmp_id; + + msg->getUUID("RegionInfo", "TerrainDetail0", tmp_id); + compp->setDetailTextureID(0, tmp_id); + msg->getUUID("RegionInfo", "TerrainDetail1", tmp_id); + compp->setDetailTextureID(1, tmp_id); + msg->getUUID("RegionInfo", "TerrainDetail2", tmp_id); + compp->setDetailTextureID(2, tmp_id); + msg->getUUID("RegionInfo", "TerrainDetail3", tmp_id); + compp->setDetailTextureID(3, tmp_id); + + F32 tmp_f32; + msg->getF32("RegionInfo", "TerrainStartHeight00", tmp_f32); + compp->setStartHeight(0, tmp_f32); + msg->getF32("RegionInfo", "TerrainStartHeight01", tmp_f32); + compp->setStartHeight(1, tmp_f32); + msg->getF32("RegionInfo", "TerrainStartHeight10", tmp_f32); + compp->setStartHeight(2, tmp_f32); + msg->getF32("RegionInfo", "TerrainStartHeight11", tmp_f32); + compp->setStartHeight(3, tmp_f32); + + msg->getF32("RegionInfo", "TerrainHeightRange00", tmp_f32); + compp->setHeightRange(0, tmp_f32); + msg->getF32("RegionInfo", "TerrainHeightRange01", tmp_f32); + compp->setHeightRange(1, tmp_f32); + msg->getF32("RegionInfo", "TerrainHeightRange10", tmp_f32); + compp->setHeightRange(2, tmp_f32); + msg->getF32("RegionInfo", "TerrainHeightRange11", tmp_f32); + 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()) + { + //this line creates frame stalls on region crossing and removing it appears to have no effect + //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"); + msg->addU32("Flags", 0x0 ); + msg->sendReliable(host); +} + +void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) +{ + capabilityNames.append("AgentState"); + capabilityNames.append("AttachmentResources"); + capabilityNames.append("AvatarPickerSearch"); + capabilityNames.append("CharacterProperties"); + capabilityNames.append("ChatSessionRequest"); + capabilityNames.append("CopyInventoryFromNotecard"); + capabilityNames.append("CreateInventoryCategory"); + capabilityNames.append("DispatchRegionInfo"); + capabilityNames.append("EnvironmentSettings"); + capabilityNames.append("EstateChangeInfo"); + capabilityNames.append("EventQueueGet"); + + if (gSavedSettings.getBOOL("UseHTTPInventory")) + { + capabilityNames.append("FetchLib2"); + capabilityNames.append("FetchLibDescendents2"); + capabilityNames.append("FetchInventory2"); + capabilityNames.append("FetchInventoryDescendents2"); + } + + capabilityNames.append("GetDisplayNames"); + capabilityNames.append("GetMesh"); + capabilityNames.append("GetObjectCost"); + capabilityNames.append("GetObjectPhysicsData"); + capabilityNames.append("GetTexture"); + capabilityNames.append("GroupMemberData"); + capabilityNames.append("GroupProposalBallot"); + capabilityNames.append("HomeLocation"); + capabilityNames.append("LandResources"); + capabilityNames.append("MapLayer"); + capabilityNames.append("MapLayerGod"); + capabilityNames.append("MeshUploadFlag"); + capabilityNames.append("NavMeshGenerationStatus"); + capabilityNames.append("NewFileAgentInventory"); + capabilityNames.append("ObjectMedia"); + capabilityNames.append("ObjectMediaNavigate"); + capabilityNames.append("ObjectNavMeshProperties"); + capabilityNames.append("ParcelPropertiesUpdate"); + capabilityNames.append("ParcelVoiceInfoRequest"); + capabilityNames.append("ProductInfoRequest"); + capabilityNames.append("ProvisionVoiceAccountRequest"); + capabilityNames.append("RemoteParcelRequest"); + 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("UpdateGestureAgentInventory"); + capabilityNames.append("UpdateGestureTaskInventory"); + capabilityNames.append("UpdateNotecardAgentInventory"); + capabilityNames.append("UpdateNotecardTaskInventory"); + capabilityNames.append("UpdateScriptAgent"); + capabilityNames.append("UpdateScriptTask"); + capabilityNames.append("UploadBakedTexture"); + 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) + { + // llwarns << "Ignoring duplicate seed capability" << llendl; + return; + } + + delete mImpl->mEventPoll; + mImpl->mEventPoll = NULL; + + mImpl->mCapabilities.clear(); + setCapability("Seed", url); + + LLSD capabilityNames = LLSD::emptyArray(); + mImpl->buildCapabilityNames(capabilityNames); + + llinfos << "posting to seed " << url << llendl; + + S32 id = ++mImpl->mHttpResponderID; + LLHTTPClient::post(url, capabilityNames, + BaseCapabilitiesComplete::build(getHandle(), id), + LLSD(), CAP_REQUEST_TIMEOUT); +} + +S32 LLViewerRegion::getNumSeedCapRetries() +{ + return mImpl->mSeedCapAttempts; +} + +void LLViewerRegion::failedSeedCapability() +{ + // Should we retry asking for caps? + mImpl->mSeedCapAttempts++; + std::string url = getCapability("Seed"); + if ( url.empty() ) + { + LL_WARNS2("AppInit", "Capabilities") << "Failed to get seed capabilities, and can not determine url for retries!" << LL_ENDL; + return; + } + // After a few attempts, continue login. We will keep trying once in-world: + if ( mImpl->mSeedCapAttempts >= mImpl->mSeedCapMaxAttemptsBeforeLogin && + STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState() ) + { + LLStartUp::setStartupState( STATE_SEED_CAP_GRANTED ); + } + + if ( mImpl->mSeedCapAttempts < mImpl->mSeedCapMaxAttempts) + { + LLSD capabilityNames = LLSD::emptyArray(); + mImpl->buildCapabilityNames(capabilityNames); + + llinfos << "posting to seed " << url << " (retry " + << mImpl->mSeedCapAttempts << ")" << llendl; + + S32 id = ++mImpl->mHttpResponderID; + LLHTTPClient::post(url, capabilityNames, + BaseCapabilitiesComplete::build(getHandle(), id), + LLSD(), CAP_REQUEST_TIMEOUT); + } + else + { + // *TODO: Give a user pop-up about this error? + LL_WARNS2("AppInit", "Capabilities") << "Failed to get seed capabilities from '" << url << "' after " << mImpl->mSeedCapAttempts << " attempts. Giving up!" << LL_ENDL; + } +} + +class SimulatorFeaturesReceived : public LLHTTPClient::Responder +{ + LOG_CLASS(SimulatorFeaturesReceived); +public: + SimulatorFeaturesReceived(const std::string& retry_url, U64 region_handle, + S32 attempt = 0, S32 max_attempts = MAX_CAP_REQUEST_ATTEMPTS) + : mRetryURL(retry_url), mRegionHandle(region_handle), mAttempt(attempt), mMaxAttempts(max_attempts) + { } + + + void error(U32 statusNum, const std::string& reason) + { + LL_WARNS2("AppInit", "SimulatorFeatures") << statusNum << ": " << reason << LL_ENDL; + retry(); + } + + void result(const LLSD& content) + { + LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); + if(!regionp) //region is removed or responder is not created. + { + LL_WARNS2("AppInit", "SimulatorFeatures") << "Received results for region that no longer exists!" << LL_ENDL; + return ; + } + + regionp->setSimulatorFeatures(content); + } + +private: + void retry() + { + if (mAttempt < mMaxAttempts) + { + mAttempt++; + LL_WARNS2("AppInit", "SimulatorFeatures") << "Re-trying '" << mRetryURL << "'. Retry #" << mAttempt << LL_ENDL; + LLHTTPClient::get(mRetryURL, new SimulatorFeaturesReceived(*this), LLSD(), CAP_REQUEST_TIMEOUT); + } + } + + std::string mRetryURL; + U64 mRegionHandle; + S32 mAttempt; + S32 mMaxAttempts; +}; + + +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") + { + LLHTTPSender::setSender(mImpl->mHost, new LLCapHTTPSender(url)); + } + else if (name == "SimulatorFeatures") + { + // kick off a request for simulator features + LLHTTPClient::get(url, new SimulatorFeaturesReceived(url, getHandle()), LLSD(), CAP_REQUEST_TIMEOUT); + } + else + { + mImpl->mCapabilities[name] = url; + if(name == "GetTexture") + { + mHttpUrl = url ; + } + } +} + +bool LLViewerRegion::isSpecialCapabilityName(const std::string &name) +{ + return name == "EventQueueGet" || name == "UntrustedSimulatorMessage"; +} + +std::string LLViewerRegion::getCapability(const std::string& name) const +{ + CapabilityMap::const_iterator iter = mImpl->mCapabilities.find(name); + if(iter == mImpl->mCapabilities.end()) + { + return ""; + } + + return iter->second; +} + +bool LLViewerRegion::capabilitiesReceived() const +{ + return mCapabilitiesReceived; +} + +void LLViewerRegion::setCapabilitiesReceived(bool received) +{ + mCapabilitiesReceived = received; + + // Tell interested parties that we've received capabilities, + // so that they can safely use getCapability(). + if (received) + { + mCapabilitiesReceivedSignal(getRegionID()); + + // This is a single-shot signal. Forget callbacks to save resources. + mCapabilitiesReceivedSignal.disconnect_all_slots(); + } +} + +boost::signals2::connection LLViewerRegion::setCapabilitiesReceivedCallback(const caps_received_signal_t::slot_type& cb) +{ + return mCapabilitiesReceivedSignal.connect(cb); +} + +void LLViewerRegion::logActiveCapabilities() const +{ + int count = 0; + CapabilityMap::const_iterator iter; + for (iter = mImpl->mCapabilities.begin(); iter != mImpl->mCapabilities.end(); ++iter, ++count) + { + if (!iter->second.empty()) + { + llinfos << iter->first << " URL is " << iter->second << llendl; + } + } + llinfos << "Dumped " << count << " entries." << llendl; +} + +LLSpatialPartition* LLViewerRegion::getSpatialPartition(U32 type) +{ + if (type < mImpl->mObjectPartition.size()) + { + return mImpl->mObjectPartition[type]; + } + 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 U32 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& boxes) const +{ + return (mParcelOverlay != NULL) + && (mParcelOverlay->isOwnedSelf(pos) + || mParcelOverlay->isOwnedGroup(pos) + || ((mRegionFlags & ALLOW_RETURN_ENCROACHING_OBJECT) + && mParcelOverlay->encroachesOwned(boxes)) ); +} + +bool LLViewerRegion::childrenObjectReturnable( const std::vector& boxes ) const +{ + bool result = false; + result = ( mParcelOverlay && mParcelOverlay->encroachesOnUnowned( boxes ) ) ? 1 : 0; + return result; +} + +bool LLViewerRegion::objectsCrossParcel(const std::vector& boxes) const +{ + return mParcelOverlay && mParcelOverlay->encroachesOnNearbyParcel(boxes); +} + +void LLViewerRegion::getNeighboringRegions( std::vector& uniqueRegions ) +{ + mImpl->mLandp->getNeighboringRegions( uniqueRegions ); +} +void LLViewerRegion::getNeighboringRegionsStatus( std::vector& 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::meshRezEnabled() const +{ + return (mSimulatorFeatures.has("MeshRezEnabled") && + mSimulatorFeatures["MeshRezEnabled"].asBoolean()); +} + +bool LLViewerRegion::dynamicPathfindingEnabled() const +{ + return ( mSimulatorFeatures.has("DynamicPathfindingEnabled") && + mSimulatorFeatures["DynamicPathfindingEnabled"].asBoolean()); +} + -- cgit v1.3 From 683c43c2e0f6e4d34592528c219f34f638059223 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Thu, 20 Sep 2012 10:00:55 -0400 Subject: reapply 448b02f5b56f: MAINT-1147 Fix for frame stall on region crossing. --- indra/llrender/llimagegl.cpp | 2 + indra/llrender/llrendertarget.cpp | 36 +++++ indra/llrender/llrendertarget.h | 8 +- indra/newview/lldrawable.cpp | 25 +++- indra/newview/lldrawpool.cpp | 42 ------ indra/newview/lldrawpool.h | 4 - indra/newview/lldrawpoolterrain.cpp | 28 ++++ indra/newview/lldrawpoolterrain.h | 1 + indra/newview/lldrawpooltree.cpp | 15 ++ indra/newview/llspatialpartition.cpp | 11 +- indra/newview/llsurface.cpp | 6 + indra/newview/llsurfacepatch.cpp | 14 +- indra/newview/llviewerdisplay.cpp | 32 ++++- indra/newview/llviewermessage.cpp | 2 + indra/newview/llviewerobjectlist.cpp | 39 +++++- indra/newview/llviewerregion.cpp | 3 +- indra/newview/llviewerwindow.cpp | 3 + indra/newview/llvoavatar.cpp | 6 +- indra/newview/llvotree.cpp | 6 +- indra/newview/llworld.cpp | 5 +- indra/newview/pipeline.cpp | 258 ++++++++++++++++++++++------------- 21 files changed, 369 insertions(+), 177 deletions(-) (limited to 'indra/newview/llviewerregion.cpp') diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index 659d3ca409..a842211764 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -237,9 +237,11 @@ S32 LLImageGL::dataFormatComponents(S32 dataformat) //---------------------------------------------------------------------------- +static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE_STATS("Image Stats"); // static void LLImageGL::updateStats(F32 current_time) { + LLFastTimer t(FTM_IMAGE_UPDATE_STATS); sLastFrameTime = current_time; sBoundTextureMemoryInBytes = sCurBoundTextureMemory; sCurBoundTextureMemory = 0; diff --git a/indra/llrender/llrendertarget.cpp b/indra/llrender/llrendertarget.cpp index 99f0da330c..cc5c232380 100644 --- a/indra/llrender/llrendertarget.cpp +++ b/indra/llrender/llrendertarget.cpp @@ -69,6 +69,42 @@ LLRenderTarget::~LLRenderTarget() release(); } +void LLRenderTarget::resize(U32 resx, U32 resy, U32 color_fmt) +{ + //for accounting, get the number of pixels added/subtracted + S32 pix_diff = (resx*resy)-(mResX*mResY); + + mResX = resx; + mResY = resy; + + for (U32 i = 0; i < mTex.size(); ++i) + { //resize color attachments + gGL.getTexUnit(0)->bindManual(mUsage, mTex[i]); + LLImageGL::setManualImage(LLTexUnit::getInternalType(mUsage), 0, color_fmt, mResX, mResY, GL_RGBA, GL_UNSIGNED_BYTE, NULL, false); + sBytesAllocated += pix_diff*4; + } + + if (mDepth) + { //resize depth attachment + if (mStencil) + { + //use render buffers where stencil buffers are in play + glBindRenderbuffer(GL_RENDERBUFFER, mDepth); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, mResX, mResY); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + } + else + { + gGL.getTexUnit(0)->bindManual(mUsage, mDepth); + U32 internal_type = LLTexUnit::getInternalType(mUsage); + LLImageGL::setManualImage(internal_type, 0, GL_DEPTH_COMPONENT24, mResX, mResY, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL, false); + } + + sBytesAllocated += pix_diff*4; + } +} + + bool LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, bool stencil, LLTexUnit::eTextureType usage, bool use_fbo, S32 samples) { stop_glerror(); diff --git a/indra/llrender/llrendertarget.h b/indra/llrender/llrendertarget.h index 8360458840..e1a51304f1 100644 --- a/indra/llrender/llrendertarget.h +++ b/indra/llrender/llrendertarget.h @@ -57,8 +57,6 @@ */ -class LLMultisampleBuffer; - class LLRenderTarget { public: @@ -74,6 +72,12 @@ public: //multiple calls will release previously allocated resources bool allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, bool stencil, LLTexUnit::eTextureType usage = LLTexUnit::TT_TEXTURE, bool use_fbo = false, S32 samples = 0); + //resize existing attachments to use new resolution and color format + // CAUTION: if the GL runs out of memory attempting to resize, this render target will be undefined + // DO NOT use for screen space buffers or for scratch space for an image that might be uploaded + // DO use for render targets that resize often and aren't likely to ruin someone's day if they break + void resize(U32 resx, U32 resy, U32 color_fmt); + //add color buffer attachment //limit of 4 color attachments per render target bool addColorAttachment(U32 color_fmt); diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp index 4435e04b6c..25603ccdcf 100644 --- a/indra/newview/lldrawable.cpp +++ b/indra/newview/lldrawable.cpp @@ -57,6 +57,8 @@ const F32 MIN_SHADOW_CASTER_RADIUS = 2.0f; static LLFastTimer::DeclareTimer FTM_CULL_REBOUND("Cull Rebound"); +extern bool gShiftFrame; + //////////////////////// // @@ -716,6 +718,11 @@ void LLDrawable::updateDistance(LLCamera& camera, bool force_update) return; } + if (gShiftFrame) + { + return; + } + //switch LOD with the spatial group to avoid artifacts //LLSpatialGroup* sg = getSpatialGroup(); @@ -813,14 +820,19 @@ void LLDrawable::shiftPos(const LLVector4a &shift_vector) mXform.setPosition(mVObjp->getPositionAgent()); } - mXform.setRotation(mVObjp->getRotation()); - mXform.setScale(1,1,1); mXform.updateMatrix(); if (isStatic()) { LLVOVolume* volume = getVOVolume(); - if (!volume) + + bool rebuild = (!volume && + getRenderType() != LLPipeline::RENDER_TYPE_TREE && + getRenderType() != LLPipeline::RENDER_TYPE_TERRAIN && + getRenderType() != LLPipeline::RENDER_TYPE_SKY && + getRenderType() != LLPipeline::RENDER_TYPE_GROUND); + + if (rebuild) { gPipeline.markRebuild(this, LLDrawable::REBUILD_ALL, TRUE); } @@ -834,7 +846,7 @@ void LLDrawable::shiftPos(const LLVector4a &shift_vector) facep->mExtents[0].add(shift_vector); facep->mExtents[1].add(shift_vector); - if (!volume && facep->hasGeometry()) + if (rebuild && facep->hasGeometry()) { facep->clearVertexBuffer(); } @@ -1394,6 +1406,11 @@ void LLSpatialBridge::updateDistance(LLCamera& camera_in, bool force_update) markDead(); return; } + + if (gShiftFrame) + { + return; + } if (mDrawable->getVObj()) { diff --git a/indra/newview/lldrawpool.cpp b/indra/newview/lldrawpool.cpp index 859c561a6d..013c698445 100644 --- a/indra/newview/lldrawpool.cpp +++ b/indra/newview/lldrawpool.cpp @@ -254,48 +254,6 @@ void LLFacePool::dirtyTextures(const std::set& textures { } -// static -S32 LLFacePool::drawLoop(face_array_t& face_list) -{ - S32 res = 0; - if (!face_list.empty()) - { - for (std::vector::iterator iter = face_list.begin(); - iter != face_list.end(); iter++) - { - LLFace *facep = *iter; - res += facep->renderIndexed(); - } - } - return res; -} - -// static -S32 LLFacePool::drawLoopSetTex(face_array_t& face_list, S32 stage) -{ - S32 res = 0; - if (!face_list.empty()) - { - for (std::vector::iterator iter = face_list.begin(); - iter != face_list.end(); iter++) - { - LLFace *facep = *iter; - gGL.getTexUnit(stage)->bind(facep->getTexture(), TRUE) ; - gGL.getTexUnit(0)->activate(); - res += facep->renderIndexed(); - } - } - return res; -} - -void LLFacePool::drawLoop() -{ - if (!mDrawFace.empty()) - { - drawLoop(mDrawFace); - } -} - void LLFacePool::enqueue(LLFace* facep) { mDrawFace.push_back(facep); diff --git a/indra/newview/lldrawpool.h b/indra/newview/lldrawpool.h index 977acf7aec..ab9bb9e611 100644 --- a/indra/newview/lldrawpool.h +++ b/indra/newview/lldrawpool.h @@ -190,10 +190,6 @@ public: void buildEdges(); - static S32 drawLoop(face_array_t& face_list); - static S32 drawLoopSetTex(face_array_t& face_list, S32 stage); - void drawLoop(); - void addFaceReference(LLFace *facep); void removeFaceReference(LLFace *facep); diff --git a/indra/newview/lldrawpoolterrain.cpp b/indra/newview/lldrawpoolterrain.cpp index b95d8296fa..7fc78fb382 100644 --- a/indra/newview/lldrawpoolterrain.cpp +++ b/indra/newview/lldrawpoolterrain.cpp @@ -294,6 +294,34 @@ void LLDrawPoolTerrain::renderShadow(S32 pass) //glCullFace(GL_BACK); } + +void LLDrawPoolTerrain::drawLoop() +{ + if (!mDrawFace.empty()) + { + for (std::vector::iterator iter = mDrawFace.begin(); + iter != mDrawFace.end(); iter++) + { + LLFace *facep = *iter; + + LLMatrix4* model_matrix = &(facep->getDrawable()->getRegion()->mRenderMatrix); + + if (model_matrix != gGLLastMatrix) + { + gGLLastMatrix = model_matrix; + gGL.loadMatrix(gGLModelView); + if (model_matrix) + { + gGL.multMatrix((GLfloat*) model_matrix->mMatrix); + } + gPipeline.mMatrixOpCount++; + } + + facep->renderIndexed(); + } + } +} + void LLDrawPoolTerrain::renderFullShader() { // Hack! Get the region that this draw pool is rendering from! diff --git a/indra/newview/lldrawpoolterrain.h b/indra/newview/lldrawpoolterrain.h index 283ed87f1a..2163d087e1 100644 --- a/indra/newview/lldrawpoolterrain.h +++ b/indra/newview/lldrawpoolterrain.h @@ -83,6 +83,7 @@ protected: void renderFull2TU(); void renderFull4TU(); void renderFullShader(); + void drawLoop(); }; #endif // LL_LLDRAWPOOLSIMPLE_H diff --git a/indra/newview/lldrawpooltree.cpp b/indra/newview/lldrawpooltree.cpp index 3165a3516c..83f04e45a8 100644 --- a/indra/newview/lldrawpooltree.cpp +++ b/indra/newview/lldrawpooltree.cpp @@ -37,6 +37,7 @@ #include "llviewershadermgr.h" #include "llrender.h" #include "llviewercontrol.h" +#include "llviewerregion.h" S32 LLDrawPoolTree::sDiffTex = 0; static LLGLSLShader* shader = NULL; @@ -104,8 +105,22 @@ void LLDrawPoolTree::render(S32 pass) { LLFace *face = *iter; LLVertexBuffer* buff = face->getVertexBuffer(); + if(buff) { + LLMatrix4* model_matrix = &(face->getDrawable()->getRegion()->mRenderMatrix); + + if (model_matrix != gGLLastMatrix) + { + gGLLastMatrix = model_matrix; + gGL.loadMatrix(gGLModelView); + if (model_matrix) + { + gGL.multMatrix((GLfloat*) model_matrix->mMatrix); + } + gPipeline.mMatrixOpCount++; + } + buff->setBuffer(LLDrawPoolTree::VERTEX_DATA_MASK); buff->drawRange(LLRender::TRIANGLES, 0, buff->getNumVerts()-1, buff->getNumIndices(), 0); gPipeline.addTrianglesDrawn(buff->getNumIndices()); diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index 70bafc8b2e..d4a3e9d8f5 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -68,6 +68,7 @@ const F32 SG_OCCLUSION_FUDGE = 0.25f; #define assert_states_valid(x) #endif +extern bool gShiftFrame; static U32 sZombieGroups = 0; U32 LLSpatialGroup::sNodeCount = 0; @@ -924,7 +925,10 @@ void LLSpatialGroup::shift(const LLVector4a &offset) mObjectExtents[0].add(offset); mObjectExtents[1].add(offset); - if (!mSpatialPartition->mRenderByGroup) + if (!mSpatialPartition->mRenderByGroup && + mSpatialPartition->mPartitionType != LLViewerRegion::PARTITION_TREE && + mSpatialPartition->mPartitionType != LLViewerRegion::PARTITION_TERRAIN && + mSpatialPartition->mPartitionType != LLViewerRegion::PARTITION_BRIDGE) { setState(GEOM_DIRTY); gPipeline.markRebuild(this, TRUE); @@ -1241,6 +1245,11 @@ void LLSpatialGroup::updateDistance(LLCamera &camera) return; } + if (gShiftFrame) + { + return; + } + #if !LL_RELEASE_FOR_DOWNLOAD if (isState(LLSpatialGroup::OBJECT_DIRTY)) { diff --git a/indra/newview/llsurface.cpp b/indra/newview/llsurface.cpp index 94907ee4cc..f64a72a616 100644 --- a/indra/newview/llsurface.cpp +++ b/indra/newview/llsurface.cpp @@ -56,6 +56,7 @@ #include "lldrawable.h" extern LLPipeline gPipeline; +extern bool gShiftFrame; LLColor4U MAX_WATER_COLOR(0, 48, 96, 240); @@ -621,6 +622,11 @@ void LLSurface::moveZ(const S32 x, const S32 y, const F32 delta) void LLSurface::updatePatchVisibilities(LLAgent &agent) { + if (gShiftFrame) + { + return; + } + LLVector3 pos_region = mRegionp->getPosRegionFromGlobal(gAgentCamera.getCameraPositionGlobal()); LLSurfacePatch *patchp; diff --git a/indra/newview/llsurfacepatch.cpp b/indra/newview/llsurfacepatch.cpp index 5077c2c7e1..a9ba2bce9c 100644 --- a/indra/newview/llsurfacepatch.cpp +++ b/indra/newview/llsurfacepatch.cpp @@ -43,6 +43,7 @@ #include "lldrawpool.h" #include "noise.h" +extern bool gShiftFrame; extern U64 gFrameTime; extern LLPipeline gPipeline; @@ -218,7 +219,7 @@ void LLSurfacePatch::eval(const U32 x, const U32 y, const U32 stride, LLVector3 pos_agent.mV[VX] += x * mSurfacep->getMetersPerGrid(); pos_agent.mV[VY] += y * mSurfacep->getMetersPerGrid(); pos_agent.mV[VZ] = *(mDataZ + point_offset); - *vertex = pos_agent; + *vertex = pos_agent-mVObjp->getRegion()->getOriginAgent(); LLVector3 rel_pos = pos_agent - mSurfacep->getOriginAgent(); LLVector3 tex_pos = rel_pos * (1.f/surface_stride); @@ -366,10 +367,13 @@ void LLSurfacePatch::updateCameraDistanceRegion(const LLVector3 &pos_region) { if (LLPipeline::sDynamicLOD) { - LLVector3 dv = pos_region; - dv -= mCenterRegion; - mVisInfo.mDistance = llmax(0.f, (F32)(dv.magVec() - mRadius))/ - llmax(LLVOSurfacePatch::sLODFactor, 0.1f); + if (!gShiftFrame) + { + LLVector3 dv = pos_region; + dv -= mCenterRegion; + mVisInfo.mDistance = llmax(0.f, (F32)(dv.magVec() - mRadius))/ + llmax(LLVOSurfacePatch::sLODFactor, 0.1f); + } } else { diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index 9ef012ece1..d58ee05fb6 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -79,6 +79,7 @@ #include "llpostprocess.h" extern LLPointer gStartTexture; +extern bool gShiftFrame; LLPointer gDisconnectedImagep = NULL; @@ -162,8 +163,11 @@ void display_startup() glClear(GL_DEPTH_BUFFER_BIT); } +static LLFastTimer::DeclareTimer FTM_UPDATE_CAMERA("Update Camera"); + void display_update_camera() { + LLFastTimer t(FTM_UPDATE_CAMERA); LLMemType mt_uc(LLMemType::MTYPE_DISPLAY_UPDATE_CAMERA); // TODO: cut draw distance down if customizing avatar? // TODO: cut draw distance on per-parcel basis? @@ -217,6 +221,11 @@ static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE_CLASS("Class"); static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE_BUMP("Bump"); static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE_LIST("List"); static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE_DELETE("Delete"); +static LLFastTimer::DeclareTimer FTM_RESIZE_WINDOW("Resize Window"); +static LLFastTimer::DeclareTimer FTM_HUD_UPDATE("HUD Update"); +static LLFastTimer::DeclareTimer FTM_DISPLAY_UPDATE_GEOM("Update Geom"); +static LLFastTimer::DeclareTimer FTM_TEXTURE_UNBIND("Texture Unbind"); +static LLFastTimer::DeclareTimer FTM_TELEPORT_DISPLAY("Teleport Display"); // Paint the display! void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) @@ -226,6 +235,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) if (gWindowResized) { //skip render on frames where window has been resized + LLFastTimer t(FTM_RESIZE_WINDOW); gGL.flush(); glClear(GL_COLOR_BUFFER_BIT); gViewerWindow->getWindow()->swapBuffers(); @@ -362,6 +372,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) if (gTeleportDisplay) { + LLFastTimer t(FTM_TELEPORT_DISPLAY); LLAppViewer::instance()->pingMainloopTimeout("Display:Teleport"); const F32 TELEPORT_ARRIVAL_DELAY = 2.f; // Time to preload the world before raising the curtain after we've actually already arrived. @@ -591,6 +602,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) // *TODO: merge these two methods { + LLFastTimer t(FTM_HUD_UPDATE); LLMemType mt_uh(LLMemType::MTYPE_DISPLAY_UPDATE_HUD); LLHUDManager::getInstance()->updateEffects(); LLHUDObject::updateAll(); @@ -598,6 +610,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) } { + LLFastTimer t(FTM_DISPLAY_UPDATE_GEOM); LLMemType mt_ug(LLMemType::MTYPE_DISPLAY_UPDATE_GEOM); const F32 max_geom_update_time = 0.005f*10.f*gFrameIntervalSeconds; // 50 ms/second update time gPipeline.createObjects(max_geom_update_time); @@ -607,6 +620,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) } gPipeline.updateGL(); + stop_glerror(); S32 water_clip = 0; @@ -938,14 +952,18 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) stop_glerror(); } - for (U32 i = 0; i < gGLManager.mNumTextureImageUnits; i++) - { //dummy cleanup of any currently bound textures - if (gGL.getTexUnit(i)->getCurrType() != LLTexUnit::TT_NONE) - { - gGL.getTexUnit(i)->unbind(gGL.getTexUnit(i)->getCurrType()); - gGL.getTexUnit(i)->disable(); + { + LLFastTimer t(FTM_TEXTURE_UNBIND); + for (U32 i = 0; i < gGLManager.mNumTextureImageUnits; i++) + { //dummy cleanup of any currently bound textures + if (gGL.getTexUnit(i)->getCurrType() != LLTexUnit::TT_NONE) + { + gGL.getTexUnit(i)->unbind(gGL.getTexUnit(i)->getCurrType()); + gGL.getTexUnit(i)->disable(); + } } } + LLAppViewer::instance()->pingMainloopTimeout("Display:RenderFlush"); if (to_texture) @@ -1011,6 +1029,8 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) display_stats(); LLAppViewer::instance()->pingMainloopTimeout("Display:Done"); + + gShiftFrame = false; } void render_hud_attachments() diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 7d7d1f3047..903f4437a7 100755 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -134,6 +134,7 @@ static const U32 LLREQUEST_PERMISSION_THROTTLE_LIMIT = 5; // requests static const F32 LLREQUEST_PERMISSION_THROTTLE_INTERVAL = 10.0f; // seconds extern BOOL gDebugClicks; +extern bool gShiftFrame; // function prototypes bool check_offer_throttle(const std::string& from_name, bool check_only); @@ -3930,6 +3931,7 @@ void process_avatar_init_complete(LLMessageSystem* msg, void**) void process_agent_movement_complete(LLMessageSystem* msg, void**) { + gShiftFrame = true; gAgentMovementCompleted = true; LLUUID agent_id; diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index 8f75ba322e..ea20950b36 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -1424,12 +1424,24 @@ void LLViewerObjectList::updateActive(LLViewerObject *objectp) if (active) { //llinfos << "Adding " << objectp->mID << " " << objectp->getPCodeString() << " to active list." << llendl; - llassert(objectp->getListIndex() == -1); - - mActiveObjects.push_back(objectp); - objectp->setListIndex(mActiveObjects.size()-1); + S32 idx = objectp->getListIndex(); + if (idx <= -1) + { + mActiveObjects.push_back(objectp); + objectp->setListIndex(mActiveObjects.size()-1); + objectp->setOnActiveList(TRUE); + } + else + { + llassert(idx < mActiveObjects.size()); + llassert(mActiveObjects[idx] == objectp); - objectp->setOnActiveList(TRUE); + if (idx >= mActiveObjects.size() || + mActiveObjects[idx] != objectp) + { + llwarns << "Invalid object list index detected!" << llendl; + } + } } else { @@ -1508,6 +1520,10 @@ void LLViewerObjectList::onPhysicsFlagsFetchFailure(const LLUUID& object_id) mPendingPhysicsFlags.erase(object_id); } +static LLFastTimer::DeclareTimer FTM_SHIFT_OBJECTS("Shift Objects"); +static LLFastTimer::DeclareTimer FTM_PIPELINE_SHIFT("Pipeline Shift"); +static LLFastTimer::DeclareTimer FTM_REGION_SHIFT("Region Shift"); + void LLViewerObjectList::shiftObjects(const LLVector3 &offset) { // This is called when we shift our origin when we cross region boundaries... @@ -1519,6 +1535,8 @@ void LLViewerObjectList::shiftObjects(const LLVector3 &offset) return; } + LLFastTimer t(FTM_SHIFT_OBJECTS); + LLViewerObject *objectp; for (vobj_list_t::iterator iter = mObjects.begin(); iter != mObjects.end(); ++iter) { @@ -1535,8 +1553,15 @@ void LLViewerObjectList::shiftObjects(const LLVector3 &offset) } } - gPipeline.shiftObjects(offset); - LLWorld::getInstance()->shiftRegions(offset); + { + LLFastTimer t(FTM_PIPELINE_SHIFT); + gPipeline.shiftObjects(offset); + } + + { + LLFastTimer t(FTM_REGION_SHIFT); + LLWorld::getInstance()->shiftRegions(offset); + } } void LLViewerObjectList::repartitionObjects() diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index 493195aaa3..05c7ef5381 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -1487,7 +1487,8 @@ void LLViewerRegion::unpackRegionHandshake() // all of our terrain stuff, by if (compp->getParamsReady()) { - getLand().dirtyAllPatches(); + //this line creates frame stalls on region crossing and removing it appears to have no effect + //getLand().dirtyAllPatches(); } else { diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 30bb787fa7..af2eec9ba8 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -4768,8 +4768,11 @@ void LLViewerWindow::requestResolutionUpdate() mResDirty = true; } +static LLFastTimer::DeclareTimer FTM_WINDOW_CHECK_SETTINGS("Window Settings"); + void LLViewerWindow::checkSettings() { + LLFastTimer t(FTM_WINDOW_CHECK_SETTINGS); if (mStatesDirty) { gGL.refreshState(); diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index dee19032f1..05febdf93b 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -1460,8 +1460,6 @@ void LLVOAvatar::onShift(const LLVector4a& shift_vector) const LLVector3& shift = reinterpret_cast(shift_vector); mLastAnimExtents[0] += shift; mLastAnimExtents[1] += shift; - mNeedsImpostorUpdate = TRUE; - mNeedsAnimUpdate = TRUE; } void LLVOAvatar::updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax) @@ -5143,9 +5141,9 @@ LLJoint *LLVOAvatar::getJoint( const std::string &name ) LLJoint* jointp = NULL; - if (iter == mJointMap.end()) + if (iter == mJointMap.end() || iter->second == NULL) { //search for joint and cache found joint in lookup table - LLJoint* jointp = mRoot.findJoint(name); + jointp = mRoot.findJoint(name); mJointMap[name] = jointp; } else diff --git a/indra/newview/llvotree.cpp b/indra/newview/llvotree.cpp index 3556bde9a8..337ddfb24d 100644 --- a/indra/newview/llvotree.cpp +++ b/indra/newview/llvotree.cpp @@ -374,7 +374,7 @@ BOOL LLVOTree::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) // *TODO: I don't know what's so special about trees // that they don't get REBUILD_POSITION automatically // at a higher level. - const LLVector3 &this_position = getPositionAgent(); + const LLVector3 &this_position = getPositionRegion(); if (this_position != mLastPosition) { gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_POSITION); @@ -843,10 +843,10 @@ void LLVOTree::updateMesh() LLMatrix4 matrix; // Translate to tree base HACK - adjustment in Z plants tree underground - const LLVector3 &pos_agent = getPositionAgent(); + const LLVector3 &pos_region = getPositionRegion(); //gGL.translatef(pos_agent.mV[VX], pos_agent.mV[VY], pos_agent.mV[VZ] - 0.1f); LLMatrix4 trans_mat; - trans_mat.setTranslation(pos_agent.mV[VX], pos_agent.mV[VY], pos_agent.mV[VZ] - 0.1f); + trans_mat.setTranslation(pos_region.mV[VX], pos_region.mV[VY], pos_region.mV[VZ] - 0.1f); trans_mat *= matrix; // Rotate to tree position and bend for current trunk/wind diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp index 1a9ff608e0..78ee3e4fd9 100644 --- a/indra/newview/llworld.cpp +++ b/indra/newview/llworld.cpp @@ -657,7 +657,10 @@ void LLWorld::updateRegions(F32 max_update_time) if (did_one && max_time <= 0.f) break; max_time = llmin(max_time, max_update_time*.1f); - did_one |= regionp->idleUpdate(max_update_time); + if (regionp->idleUpdate(max_update_time)) + { + did_one = TRUE; + } } } diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 49a9b31c14..2edb5cf852 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -120,6 +120,8 @@ //#define DEBUG_INDICES #endif +bool gShiftFrame = false; + //cached settings BOOL LLPipeline::RenderAvatarVP; BOOL LLPipeline::VertexShaderEnable; @@ -217,7 +219,7 @@ BOOL gDebugPipeline = FALSE; LLPipeline gPipeline; const LLMatrix4* gGLLastMatrix = NULL; -LLFastTimer::DeclareTimer FTM_RENDER_GEOMETRY("Geometry"); +LLFastTimer::DeclareTimer FTM_RENDER_GEOMETRY("Render Geometry"); LLFastTimer::DeclareTimer FTM_RENDER_GRASS("Grass"); LLFastTimer::DeclareTimer FTM_RENDER_INVISIBLE("Invisible"); LLFastTimer::DeclareTimer FTM_RENDER_OCCLUSION("Occlusion"); @@ -234,8 +236,13 @@ LLFastTimer::DeclareTimer FTM_RENDER_BUMP("Bump"); LLFastTimer::DeclareTimer FTM_RENDER_FULLBRIGHT("Fullbright"); LLFastTimer::DeclareTimer FTM_RENDER_GLOW("Glow"); LLFastTimer::DeclareTimer FTM_GEO_UPDATE("Geo Update"); +LLFastTimer::DeclareTimer FTM_PIPELINE_CREATE("Pipeline Create"); LLFastTimer::DeclareTimer FTM_POOLRENDER("RenderPool"); LLFastTimer::DeclareTimer FTM_POOLS("Pools"); +LLFastTimer::DeclareTimer FTM_DEFERRED_POOLRENDER("RenderPool (Deferred)"); +LLFastTimer::DeclareTimer FTM_DEFERRED_POOLS("Pools (Deferred)"); +LLFastTimer::DeclareTimer FTM_POST_DEFERRED_POOLRENDER("RenderPool (Post)"); +LLFastTimer::DeclareTimer FTM_POST_DEFERRED_POOLS("Pools (Post)"); LLFastTimer::DeclareTimer FTM_RENDER_BLOOM_FBO("First FBO"); LLFastTimer::DeclareTimer FTM_STATESORT("Sort Draw State"); LLFastTimer::DeclareTimer FTM_PIPELINE("Pipeline"); @@ -1680,7 +1687,7 @@ U32 LLPipeline::addObject(LLViewerObject *vobj) void LLPipeline::createObjects(F32 max_dtime) { - LLFastTimer ftm(FTM_GEO_UPDATE); + LLFastTimer ftm(FTM_PIPELINE_CREATE); LLMemType mt(LLMemType::MTYPE_PIPELINE_CREATE_OBJECTS); LLTimer update_timer; @@ -2513,14 +2520,19 @@ BOOL LLPipeline::updateDrawableGeom(LLDrawable* drawablep, BOOL priority) static LLFastTimer::DeclareTimer FTM_SEED_VBO_POOLS("Seed VBO Pool"); +static LLFastTimer::DeclareTimer FTM_UPDATE_GL("Update GL"); + void LLPipeline::updateGL() { - while (!LLGLUpdate::sGLQ.empty()) { - LLGLUpdate* glu = LLGLUpdate::sGLQ.front(); - glu->updateGL(); - glu->mInQ = FALSE; - LLGLUpdate::sGLQ.pop_front(); + LLFastTimer t(FTM_UPDATE_GL); + while (!LLGLUpdate::sGLQ.empty()) + { + LLGLUpdate* glu = LLGLUpdate::sGLQ.front(); + glu->updateGL(); + glu->mInQ = FALSE; + LLGLUpdate::sGLQ.pop_front(); + } } { //seed VBO Pools @@ -2529,11 +2541,13 @@ void LLPipeline::updateGL() } } +static LLFastTimer::DeclareTimer FTM_REBUILD_PRIORITY_GROUPS("Rebuild Priority Groups"); + void LLPipeline::rebuildPriorityGroups() { + LLFastTimer t(FTM_REBUILD_PRIORITY_GROUPS); LLTimer update_timer; LLMemType mt(LLMemType::MTYPE_PIPELINE); - assertInitialized(); gMeshRepo.notifyLoadedMeshes(); @@ -2552,7 +2566,9 @@ void LLPipeline::rebuildPriorityGroups() mGroupQ1Locked = false; } - + +static LLFastTimer::DeclareTimer FTM_REBUILD_GROUPS("Rebuild Groups"); + void LLPipeline::rebuildGroups() { if (mGroupQ2.empty()) @@ -2560,6 +2576,7 @@ void LLPipeline::rebuildGroups() return; } + LLFastTimer t(FTM_REBUILD_GROUPS); mGroupQ2Locked = true; // Iterate through some drawables on the non-priority build queue S32 size = (S32) mGroupQ2.size(); @@ -2803,6 +2820,10 @@ void LLPipeline::markShift(LLDrawable *drawablep) } } +static LLFastTimer::DeclareTimer FTM_SHIFT_DRAWABLE("Shift Drawable"); +static LLFastTimer::DeclareTimer FTM_SHIFT_OCTREE("Shift Octree"); +static LLFastTimer::DeclareTimer FTM_SHIFT_HUD("Shift HUD"); + void LLPipeline::shiftObjects(const LLVector3 &offset) { LLMemType mt(LLMemType::MTYPE_PIPELINE_SHIFT_OBJECTS); @@ -2815,35 +2836,46 @@ void LLPipeline::shiftObjects(const LLVector3 &offset) LLVector4a offseta; offseta.load3(offset.mV); - for (LLDrawable::drawable_vector_t::iterator iter = mShiftList.begin(); - iter != mShiftList.end(); iter++) { - LLDrawable *drawablep = *iter; - if (drawablep->isDead()) + LLFastTimer t(FTM_SHIFT_DRAWABLE); + + for (LLDrawable::drawable_vector_t::iterator iter = mShiftList.begin(); + iter != mShiftList.end(); iter++) { - continue; - } - drawablep->shiftPos(offseta); - drawablep->clearState(LLDrawable::ON_SHIFT_LIST); + LLDrawable *drawablep = *iter; + if (drawablep->isDead()) + { + continue; + } + drawablep->shiftPos(offseta); + drawablep->clearState(LLDrawable::ON_SHIFT_LIST); + } + mShiftList.resize(0); } - mShiftList.resize(0); - for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); - iter != LLWorld::getInstance()->getRegionList().end(); ++iter) + { - LLViewerRegion* region = *iter; - for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++) + LLFastTimer t(FTM_SHIFT_OCTREE); + for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); + iter != LLWorld::getInstance()->getRegionList().end(); ++iter) { - LLSpatialPartition* part = region->getSpatialPartition(i); - if (part) + LLViewerRegion* region = *iter; + for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++) { - part->shift(offseta); + LLSpatialPartition* part = region->getSpatialPartition(i); + if (part) + { + part->shift(offseta); + } } } } - LLHUDText::shiftAll(offset); - LLHUDNameTag::shiftAll(offset); + { + LLFastTimer t(FTM_SHIFT_HUD); + LLHUDText::shiftAll(offset); + LLHUDNameTag::shiftAll(offset); + } display_update_camera(); } @@ -2876,8 +2908,10 @@ void LLPipeline::markPartitionMove(LLDrawable* drawable) } } +static LLFastTimer::DeclareTimer FTM_PROCESS_PARTITIONQ("PartitionQ"); void LLPipeline::processPartitionQ() { + LLFastTimer t(FTM_PROCESS_PARTITIONQ); for (LLDrawable::drawable_list_t::iterator iter = mPartitionQ.begin(); iter != mPartitionQ.end(); ++iter) { LLDrawable* drawable = *iter; @@ -4138,7 +4172,7 @@ void LLPipeline::renderGeomDeferred(LLCamera& camera) LLMemType mt_rgd(LLMemType::MTYPE_PIPELINE_RENDER_GEOM_DEFFERRED); LLFastTimer t(FTM_RENDER_GEOMETRY); - LLFastTimer t2(FTM_POOLS); + LLFastTimer t2(FTM_DEFERRED_POOLS); LLGLEnable cull(GL_CULL_FACE); @@ -4180,7 +4214,7 @@ void LLPipeline::renderGeomDeferred(LLCamera& camera) pool_set_t::iterator iter2 = iter1; if (hasRenderType(poolp->getType()) && poolp->getNumDeferredPasses() > 0) { - LLFastTimer t(FTM_POOLRENDER); + LLFastTimer t(FTM_DEFERRED_POOLRENDER); gGLLastMatrix = NULL; gGL.loadMatrix(gGLModelView); @@ -4233,7 +4267,7 @@ void LLPipeline::renderGeomDeferred(LLCamera& camera) void LLPipeline::renderGeomPostDeferred(LLCamera& camera) { LLMemType mt_rgpd(LLMemType::MTYPE_PIPELINE_RENDER_GEOM_POST_DEF); - LLFastTimer t(FTM_POOLS); + LLFastTimer t(FTM_POST_DEFERRED_POOLS); U32 cur_type = 0; LLGLEnable cull(GL_CULL_FACE); @@ -4267,7 +4301,7 @@ void LLPipeline::renderGeomPostDeferred(LLCamera& camera) pool_set_t::iterator iter2 = iter1; if (hasRenderType(poolp->getType()) && poolp->getNumPostDeferredPasses() > 0) { - LLFastTimer t(FTM_POOLRENDER); + LLFastTimer t(FTM_POST_DEFERRED_POOLRENDER); gGLLastMatrix = NULL; gGL.loadMatrix(gGLModelView); @@ -5131,8 +5165,11 @@ void LLPipeline::renderDebug() } } +static LLFastTimer::DeclareTimer FTM_REBUILD_POOLS("Rebuild Pools"); + void LLPipeline::rebuildPools() { + LLFastTimer t(FTM_REBUILD_POOLS); LLMemType mt(LLMemType::MTYPE_PIPELINE_REBUILD_POOLS); assertInitialized(); @@ -6691,13 +6728,16 @@ void LLPipeline::resetVertexBuffers() mResetVertexBuffers = true; } +static LLFastTimer::DeclareTimer FTM_RESET_VB("Reset VB"); + void LLPipeline::doResetVertexBuffers() { if (!mResetVertexBuffers) { return; } - + + LLFastTimer t(FTM_RESET_VB); mResetVertexBuffers = false; mCubeVB = NULL; @@ -9122,6 +9162,8 @@ void LLPipeline::generateHighlight(LLCamera& camera) } +static LLFastTimer::DeclareTimer FTM_GEN_SUN_SHADOW("Gen Sun Shadow"); + void LLPipeline::generateSunShadow(LLCamera& camera) { if (!sRenderDeferred || RenderShadowDetail <= 0) @@ -9129,6 +9171,8 @@ void LLPipeline::generateSunShadow(LLCamera& camera) return; } + LLFastTimer t(FTM_GEN_SUN_SHADOW); + BOOL skip_avatar_update = FALSE; if (!isAgentAvatarValid() || gAgentCamera.getCameraAnimating() || gAgentCamera.getCameraMode() != CAMERA_MODE_MOUSELOOK || !LLVOAvatar::sVisibleInFirstPerson) { @@ -9891,6 +9935,12 @@ void LLPipeline::renderGroups(LLRenderPass* pass, U32 type, U32 mask, BOOL textu } } +static LLFastTimer::DeclareTimer FTM_IMPOSTOR_MARK_VISIBLE("Impostor Mark Visible"); +static LLFastTimer::DeclareTimer FTM_IMPOSTOR_SETUP("Impostor Setup"); +static LLFastTimer::DeclareTimer FTM_IMPOSTOR_BACKGROUND("Impostor Background"); +static LLFastTimer::DeclareTimer FTM_IMPOSTOR_ALLOCATE("Impostor Allocate"); +static LLFastTimer::DeclareTimer FTM_IMPOSTOR_RESIZE("Impostor Resize"); + void LLPipeline::generateImpostor(LLVOAvatar* avatar) { LLMemType mt_gi(LLMemType::MTYPE_PIPELINE_GENERATE_IMPOSTOR); @@ -9946,101 +9996,114 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar) sImpostorRender = TRUE; LLViewerCamera* viewer_camera = LLViewerCamera::getInstance(); - markVisible(avatar->mDrawable, *viewer_camera); - LLVOAvatar::sUseImpostors = FALSE; - LLVOAvatar::attachment_map_t::iterator iter; - for (iter = avatar->mAttachmentPoints.begin(); - iter != avatar->mAttachmentPoints.end(); - ++iter) { - LLViewerJointAttachment *attachment = iter->second; - for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); - attachment_iter != attachment->mAttachedObjects.end(); - ++attachment_iter) + LLFastTimer t(FTM_IMPOSTOR_MARK_VISIBLE); + markVisible(avatar->mDrawable, *viewer_camera); + LLVOAvatar::sUseImpostors = FALSE; + + LLVOAvatar::attachment_map_t::iterator iter; + for (iter = avatar->mAttachmentPoints.begin(); + iter != avatar->mAttachmentPoints.end(); + ++iter) { - if (LLViewerObject* attached_object = (*attachment_iter)) + LLViewerJointAttachment *attachment = iter->second; + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) { - markVisible(attached_object->mDrawable->getSpatialBridge(), *viewer_camera); + if (LLViewerObject* attached_object = (*attachment_iter)) + { + markVisible(attached_object->mDrawable->getSpatialBridge(), *viewer_camera); + } } } } stateSort(*LLViewerCamera::getInstance(), result); - const LLVector4a* ext = avatar->mDrawable->getSpatialExtents(); - LLVector3 pos(avatar->getRenderPosition()+avatar->getImpostorOffset()); - LLCamera camera = *viewer_camera; - - camera.lookAt(viewer_camera->getOrigin(), pos, viewer_camera->getUpAxis()); - LLVector2 tdim; + U32 resY = 0; + U32 resX = 0; + { + LLFastTimer t(FTM_IMPOSTOR_SETUP); + const LLVector4a* ext = avatar->mDrawable->getSpatialExtents(); + LLVector3 pos(avatar->getRenderPosition()+avatar->getImpostorOffset()); - LLVector4a half_height; - half_height.setSub(ext[1], ext[0]); - half_height.mul(0.5f); + camera.lookAt(viewer_camera->getOrigin(), pos, viewer_camera->getUpAxis()); + + LLVector4a half_height; + half_height.setSub(ext[1], ext[0]); + half_height.mul(0.5f); - LLVector4a left; - left.load3(camera.getLeftAxis().mV); - left.mul(left); - left.normalize3fast(); + LLVector4a left; + left.load3(camera.getLeftAxis().mV); + left.mul(left); + left.normalize3fast(); - LLVector4a up; - up.load3(camera.getUpAxis().mV); - up.mul(up); - up.normalize3fast(); + LLVector4a up; + up.load3(camera.getUpAxis().mV); + up.mul(up); + up.normalize3fast(); - tdim.mV[0] = fabsf(half_height.dot3(left).getF32()); - tdim.mV[1] = fabsf(half_height.dot3(up).getF32()); + tdim.mV[0] = fabsf(half_height.dot3(left).getF32()); + tdim.mV[1] = fabsf(half_height.dot3(up).getF32()); - gGL.matrixMode(LLRender::MM_PROJECTION); - gGL.pushMatrix(); + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.pushMatrix(); - F32 distance = (pos-camera.getOrigin()).length(); - F32 fov = atanf(tdim.mV[1]/distance)*2.f*RAD_TO_DEG; - F32 aspect = tdim.mV[0]/tdim.mV[1]; - glh::matrix4f persp = gl_perspective(fov, aspect, 1.f, 256.f); - glh_set_current_projection(persp); - gGL.loadMatrix(persp.m); + F32 distance = (pos-camera.getOrigin()).length(); + F32 fov = atanf(tdim.mV[1]/distance)*2.f*RAD_TO_DEG; + F32 aspect = tdim.mV[0]/tdim.mV[1]; + glh::matrix4f persp = gl_perspective(fov, aspect, 1.f, 256.f); + glh_set_current_projection(persp); + gGL.loadMatrix(persp.m); - gGL.matrixMode(LLRender::MM_MODELVIEW); - gGL.pushMatrix(); - glh::matrix4f mat; - camera.getOpenGLTransform(mat.m); + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.pushMatrix(); + glh::matrix4f mat; + camera.getOpenGLTransform(mat.m); - mat = glh::matrix4f((GLfloat*) OGL_TO_CFR_ROTATION) * mat; + mat = glh::matrix4f((GLfloat*) OGL_TO_CFR_ROTATION) * mat; - gGL.loadMatrix(mat.m); - glh_set_current_modelview(mat); + gGL.loadMatrix(mat.m); + glh_set_current_modelview(mat); - glClearColor(0.0f,0.0f,0.0f,0.0f); - gGL.setColorMask(true, true); + glClearColor(0.0f,0.0f,0.0f,0.0f); + gGL.setColorMask(true, true); - // get the number of pixels per angle - F32 pa = gViewerWindow->getWindowHeightRaw() / (RAD_TO_DEG * viewer_camera->getView()); + // get the number of pixels per angle + F32 pa = gViewerWindow->getWindowHeightRaw() / (RAD_TO_DEG * viewer_camera->getView()); - //get resolution based on angle width and height of impostor (double desired resolution to prevent aliasing) - U32 resY = llmin(nhpo2((U32) (fov*pa)), (U32) 512); - U32 resX = llmin(nhpo2((U32) (atanf(tdim.mV[0]/distance)*2.f*RAD_TO_DEG*pa)), (U32) 512); + //get resolution based on angle width and height of impostor (double desired resolution to prevent aliasing) + resY = llmin(nhpo2((U32) (fov*pa)), (U32) 512); + resX = llmin(nhpo2((U32) (atanf(tdim.mV[0]/distance)*2.f*RAD_TO_DEG*pa)), (U32) 512); - if (!avatar->mImpostor.isComplete() || resX != avatar->mImpostor.getWidth() || - resY != avatar->mImpostor.getHeight()) - { - avatar->mImpostor.allocate(resX,resY,GL_RGBA,TRUE,FALSE); + if (!avatar->mImpostor.isComplete()) + { + LLFastTimer t(FTM_IMPOSTOR_ALLOCATE); + avatar->mImpostor.allocate(resX,resY,GL_RGBA,TRUE,FALSE); + + if (LLPipeline::sRenderDeferred) + { + addDeferredAttachments(avatar->mImpostor); + } - if (LLPipeline::sRenderDeferred) + gGL.getTexUnit(0)->bind(&avatar->mImpostor); + gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + } + else if(resX != avatar->mImpostor.getWidth() || + resY != avatar->mImpostor.getHeight()) { - addDeferredAttachments(avatar->mImpostor); + LLFastTimer t(FTM_IMPOSTOR_RESIZE); + avatar->mImpostor.resize(resX,resY,GL_RGBA); } - - gGL.getTexUnit(0)->bind(&avatar->mImpostor); - gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - } - avatar->mImpostor.bindTarget(); + avatar->mImpostor.bindTarget(); + } if (LLPipeline::sRenderDeferred) { @@ -10057,6 +10120,7 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar) } { //create alpha mask based on depth buffer (grey out if muted) + LLFastTimer t(FTM_IMPOSTOR_BACKGROUND); if (LLPipeline::sRenderDeferred) { GLuint buff = GL_COLOR_ATTACHMENT0; -- cgit v1.3 From 374f20edf09ff8194c715d190c114eaacac00bfe Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Wed, 3 Oct 2012 14:30:21 -0500 Subject: Fix non-thread-safe refcounting of LLHTTPClient::Responder and fix out-of-order deletion of LLTextureFetch on shutdown --- indra/llcommon/llthread.cpp | 35 ++++++++++++++----- indra/llcommon/llthread.h | 30 ++++++++++++----- indra/llmessage/llcurl.cpp | 38 +++++++-------------- indra/llmessage/llcurl.h | 15 +++------ indra/newview/llappviewer.cpp | 6 ++-- indra/newview/llassetuploadresponders.cpp | 8 ++--- indra/newview/lleventpoll.cpp | 2 +- indra/newview/llfloatertos.cpp | 6 ++-- indra/newview/lltexturefetch.cpp | 2 ++ indra/newview/lltranslate.h | 4 +-- indra/newview/llviewermessage.cpp | 4 +-- indra/newview/llviewerregion.cpp | 5 ++- .../viewer_components/updater/llupdatechecker.cpp | 39 +--------------------- indra/viewer_components/updater/llupdatechecker.h | 34 +++++++++++++++++-- 14 files changed, 117 insertions(+), 111 deletions(-) (limited to 'indra/newview/llviewerregion.cpp') diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp index a6ad6b125c..c2fbb544a8 100644 --- a/indra/llcommon/llthread.cpp +++ b/indra/llcommon/llthread.cpp @@ -114,7 +114,7 @@ LLThread::LLThread(const std::string& name, apr_pool_t *poolp) : apr_pool_create(&mAPRPoolp, NULL); // Create a subpool for this thread } mRunCondition = new LLCondition(mAPRPoolp); - + mDataLock = new LLMutex(mAPRPoolp); mLocalAPRFilePoolp = NULL ; } @@ -173,7 +173,10 @@ void LLThread::shutdown() } delete mRunCondition; - mRunCondition = 0; + mRunCondition = NULL; + + delete mDataLock; + mDataLock = NULL; if (mIsLocalPool && mAPRPoolp) { @@ -242,28 +245,30 @@ bool LLThread::runCondition(void) // Stop thread execution if requested until unpaused. void LLThread::checkPause() { - mRunCondition->lock(); + mDataLock->lock(); // This is in a while loop because the pthread API allows for spurious wakeups. while(shouldSleep()) { + mDataLock->unlock(); mRunCondition->wait(); // unlocks mRunCondition + mDataLock->lock(); // mRunCondition is locked when the thread wakes up } - mRunCondition->unlock(); + mDataLock->unlock(); } //============================================================================ void LLThread::setQuitting() { - mRunCondition->lock(); + mDataLock->lock(); if (mStatus == RUNNING) { mStatus = QUITTING; } - mRunCondition->unlock(); + mDataLock->unlock(); wake(); } @@ -285,12 +290,12 @@ void LLThread::yield() void LLThread::wake() { - mRunCondition->lock(); + mDataLock->lock(); if(!shouldSleep()) { mRunCondition->signal(); } - mRunCondition->unlock(); + mDataLock->unlock(); } void LLThread::wakeLocked() @@ -481,6 +486,19 @@ LLThreadSafeRefCount::LLThreadSafeRefCount() : { } +LLThreadSafeRefCount::LLThreadSafeRefCount(const LLThreadSafeRefCount& src) +{ + if (sMutex) + { + sMutex->lock(); + } + mRef = 0; + if (sMutex) + { + sMutex->unlock(); + } +} + LLThreadSafeRefCount::~LLThreadSafeRefCount() { if (mRef != 0) @@ -489,6 +507,7 @@ LLThreadSafeRefCount::~LLThreadSafeRefCount() } } + //============================================================================ LLResponder::~LLResponder() diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h index b52e70ab2e..892e144911 100644 --- a/indra/llcommon/llthread.h +++ b/indra/llcommon/llthread.h @@ -97,6 +97,7 @@ private: protected: std::string mName; LLCondition* mRunCondition; + LLMutex* mDataLock; apr_thread_t *mAPRThreadp; apr_pool_t *mAPRPoolp; @@ -122,15 +123,15 @@ protected: inline void unlockData(); // This is the predicate that decides whether the thread should sleep. - // It should only be called with mRunCondition locked, since the virtual runCondition() function may need to access + // It should only be called with mDataLock locked, since the virtual runCondition() function may need to access // data structures that are thread-unsafe. bool shouldSleep(void) { return (mStatus == RUNNING) && (isPaused() || (!runCondition())); } // To avoid spurious signals (and the associated context switches) when the condition may or may not have changed, you can do the following: - // mRunCondition->lock(); + // mDataLock->lock(); // if(!shouldSleep()) // mRunCondition->signal(); - // mRunCondition->unlock(); + // mDataLock->unlock(); }; //============================================================================ @@ -205,12 +206,12 @@ private: void LLThread::lockData() { - mRunCondition->lock(); + mDataLock->lock(); } void LLThread::unlockData() { - mRunCondition->unlock(); + mDataLock->unlock(); } @@ -227,15 +228,26 @@ public: private: static LLMutex* sMutex; -private: - LLThreadSafeRefCount(const LLThreadSafeRefCount&); // not implemented - LLThreadSafeRefCount&operator=(const LLThreadSafeRefCount&); // not implemented - protected: virtual ~LLThreadSafeRefCount(); // use unref() public: LLThreadSafeRefCount(); + LLThreadSafeRefCount(const LLThreadSafeRefCount&); + LLThreadSafeRefCount&operator=(const LLThreadSafeRefCount& ref) + { + if (sMutex) + { + sMutex->lock(); + } + mRef = 0; + if (sMutex) + { + sMutex->unlock(); + } + } + + void ref() { diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp index 0de47e0181..158e4ce091 100644 --- a/indra/llmessage/llcurl.cpp +++ b/indra/llmessage/llcurl.cpp @@ -133,12 +133,12 @@ std::string LLCurl::getVersionString() ////////////////////////////////////////////////////////////////////////////// LLCurl::Responder::Responder() - : mReferenceCount(0) { } LLCurl::Responder::~Responder() { + LL_CHECK_MEMORY } // virtual @@ -202,23 +202,6 @@ void LLCurl::Responder::completedHeader(U32 status, const std::string& reason, c } -namespace boost -{ - void intrusive_ptr_add_ref(LLCurl::Responder* p) - { - ++p->mReferenceCount; - } - - void intrusive_ptr_release(LLCurl::Responder* p) - { - if (p && 0 == --p->mReferenceCount) - { - delete p; - } - } -}; - - ////////////////////////////////////////////////////////////////////////////// std::set LLCurl::Easy::sFreeHandles; @@ -267,15 +250,18 @@ void LLCurl::Easy::releaseEasyHandle(CURL* handle) LLMutexLock lock(sHandleMutexp) ; if (sActiveHandles.find(handle) != sActiveHandles.end()) { + LL_CHECK_MEMORY sActiveHandles.erase(handle); - + LL_CHECK_MEMORY if(sFreeHandles.size() < MAX_NUM_FREE_HANDLES) { - sFreeHandles.insert(handle); - } - else - { + sFreeHandles.insert(handle); + LL_CHECK_MEMORY + } + else + { LLCurl::deleteEasyHandle(handle) ; + LL_CHECK_MEMORY } } else @@ -315,9 +301,7 @@ LLCurl::Easy* LLCurl::Easy::getEasy() LLCurl::Easy::~Easy() { - LL_CHECK_MEMORY releaseEasyHandle(mCurlEasyHandle); - LL_CHECK_MEMORY --gCurlEasyCount; curl_slist_free_all(mHeaders); LL_CHECK_MEMORY @@ -331,7 +315,6 @@ LLCurl::Easy::~Easy() LL_CHECK_MEMORY } mResponder = NULL; - LL_CHECK_MEMORY } void LLCurl::Easy::resetState() @@ -617,6 +600,7 @@ void LLCurl::Multi::cleanup(bool deleted) if(deleted) { easy->mResponder = NULL ; //avoid triggering mResponder. + LL_CHECK_MEMORY } delete easy; LL_CHECK_MEMORY @@ -1623,7 +1607,9 @@ void LLCurl::deleteEasyHandle(CURL* handle) if(handle) { LLMutexLock lock(sHandleMutexp) ; + LL_CHECK_MEMORY curl_easy_cleanup(handle) ; + LL_CHECK_MEMORY sTotalHandles-- ; } } diff --git a/indra/llmessage/llcurl.h b/indra/llmessage/llcurl.h index d6a7714d4c..62947bdb9d 100644 --- a/indra/llmessage/llcurl.h +++ b/indra/llmessage/llcurl.h @@ -44,6 +44,8 @@ #include "llthread.h" #include "llqueuedthread.h" #include "llframetimer.h" +#include "llpointer.h" + class LLMutex; class LLCurlThread; @@ -67,7 +69,7 @@ public: F64 mSpeedDownload; }; - class Responder + class Responder : public LLThreadSafeRefCount { //LOG_CLASS(Responder); public: @@ -126,13 +128,10 @@ public: return false; } - public: /* but not really -- don't touch this */ - U32 mReferenceCount; - private: std::string mURL; }; - typedef boost::intrusive_ptr ResponderPtr; + typedef LLPointer ResponderPtr; /** @@ -378,12 +377,6 @@ private: void cleanupMulti(LLCurl::Multi* multi) ; } ; -namespace boost -{ - void intrusive_ptr_add_ref(LLCurl::Responder* p); - void intrusive_ptr_release(LLCurl::Responder* p); -}; - class LLCurlRequest { diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index fa68b9322e..2b6d6d15fa 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -1888,8 +1888,6 @@ bool LLAppViewer::cleanup() delete sTextureCache; sTextureCache = NULL; - delete sTextureFetch; - sTextureFetch = NULL; delete sImageDecodeThread; sImageDecodeThread = NULL; delete mFastTimerLogThread; @@ -1962,6 +1960,10 @@ bool LLAppViewer::cleanup() LLCurl::cleanupClass(); LL_CHECK_MEMORY + //MUST happen AFTER LLCurl::cleanupClass + delete sTextureFetch; + sTextureFetch = NULL; + // If we're exiting to launch an URL, do that here so the screen // is at the right resolution before we launch IE. if (!gLaunchFileOnQuit.empty()) diff --git a/indra/newview/llassetuploadresponders.cpp b/indra/newview/llassetuploadresponders.cpp index 65bfc990d1..7b2c536f5a 100644 --- a/indra/newview/llassetuploadresponders.cpp +++ b/indra/newview/llassetuploadresponders.cpp @@ -919,7 +919,7 @@ public: bool uploadConfirmationCallback( const LLSD& notification, const LLSD& response, - boost::intrusive_ptr responder) + LLPointer responder) { S32 option; std::string confirmation_url; @@ -949,7 +949,7 @@ public: void confirmUpload( const std::string& confirmation_url, - boost::intrusive_ptr responder) + LLPointer responder) { if ( getFilename().empty() ) { @@ -1124,7 +1124,7 @@ void LLNewAgentInventoryVariablePriceResponder::showConfirmationDialog( // and cause sadness. mImpl->confirmUpload( confirmation_url, - boost::intrusive_ptr(this)); + LLPointer(this)); } else { @@ -1157,7 +1157,7 @@ void LLNewAgentInventoryVariablePriceResponder::showConfirmationDialog( mImpl, _1, _2, - boost::intrusive_ptr(this))); + LLPointer(this))); } } diff --git a/indra/newview/lleventpoll.cpp b/indra/newview/lleventpoll.cpp index 4f4d9a40b4..2c786b7f8b 100644 --- a/indra/newview/lleventpoll.cpp +++ b/indra/newview/lleventpoll.cpp @@ -86,7 +86,7 @@ namespace class LLEventPollEventTimer : public LLEventTimer { - typedef boost::intrusive_ptr EventPollResponderPtr; + typedef LLPointer EventPollResponderPtr; public: LLEventPollEventTimer(F32 period, EventPollResponderPtr responder) diff --git a/indra/newview/llfloatertos.cpp b/indra/newview/llfloatertos.cpp index c5df7e16e9..a242b224cd 100644 --- a/indra/newview/llfloatertos.cpp +++ b/indra/newview/llfloatertos.cpp @@ -71,9 +71,9 @@ class LLIamHere : public LLHTTPClient::Responder public: - static boost::intrusive_ptr< LLIamHere > build( LLFloaterTOS* parent ) + static LLIamHere* build( LLFloaterTOS* parent ) { - return boost::intrusive_ptr< LLIamHere >( new LLIamHere( parent ) ); + return new LLIamHere( parent ); }; virtual void setParent( LLFloaterTOS* parentIn ) @@ -102,7 +102,7 @@ class LLIamHere : public LLHTTPClient::Responder // this is global and not a class member to keep crud out of the header file namespace { - boost::intrusive_ptr< LLIamHere > gResponsePtr = 0; + LLPointer< LLIamHere > gResponsePtr = 0; }; BOOL LLFloaterTOS::postBuild() diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index 7e6dfbc9d9..a5eebf6c77 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -2944,7 +2944,9 @@ TFReqSendMetrics::doWork(LLTextureFetch * fetcher) ~lcl_responder() { + LL_CHECK_MEMORY mFetcher->decrCurlPOSTCount(); + LL_CHECK_MEMORY } // virtual diff --git a/indra/newview/lltranslate.h b/indra/newview/lltranslate.h index c58e1adb8c..db5ad9479c 100755 --- a/indra/newview/lltranslate.h +++ b/indra/newview/lltranslate.h @@ -263,8 +263,8 @@ public : EService mService; }; - typedef boost::intrusive_ptr TranslationReceiverPtr; - typedef boost::intrusive_ptr KeyVerificationReceiverPtr; + typedef LLPointer TranslationReceiverPtr; + typedef LLPointer KeyVerificationReceiverPtr; /** * Translate given text. diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 7d7d1f3047..04c7a87374 100755 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -3339,9 +3339,9 @@ public : { } - static boost::intrusive_ptr build(const std::string &from_lang, const std::string &to_lang, const std::string &mesg, const LLChat &chat, const LLSD &toast_args) + static ChatTranslationReceiver* build(const std::string &from_lang, const std::string &to_lang, const std::string &mesg, const LLChat &chat, const LLSD &toast_args) { - return boost::intrusive_ptr(new ChatTranslationReceiver(from_lang, to_lang, mesg, chat, toast_args)); + return new ChatTranslationReceiver(from_lang, to_lang, mesg, chat, toast_args); } protected: diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index 493195aaa3..1ef729e2ff 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -255,10 +255,9 @@ public: } } - static boost::intrusive_ptr build( U64 region_handle, S32 id ) + static BaseCapabilitiesComplete* build( U64 region_handle, S32 id ) { - return boost::intrusive_ptr( - new BaseCapabilitiesComplete(region_handle, id) ); + return new BaseCapabilitiesComplete(region_handle, id); } private: diff --git a/indra/viewer_components/updater/llupdatechecker.cpp b/indra/viewer_components/updater/llupdatechecker.cpp index 4da774a5f6..5edbbf9914 100644 --- a/indra/viewer_components/updater/llupdatechecker.cpp +++ b/indra/viewer_components/updater/llupdatechecker.cpp @@ -51,37 +51,6 @@ public: }; -class LLUpdateChecker::Implementation: - public LLHTTPClient::Responder -{ -public: - Implementation(Client & client); - ~Implementation(); - void checkVersion(std::string const & protocolVersion, std::string const & hostUrl, - std::string const & servicePath, std::string channel, std::string version); - - // Responder: - virtual void completed(U32 status, - const std::string & reason, - const LLSD& content); - virtual void error(U32 status, const std::string & reason); - -private: - static const char * sProtocolVersion; - - Client & mClient; - LLHTTPClient mHttpClient; - bool mInProgress; - std::string mVersion; - - std::string buildUrl(std::string const & protocolVersion, std::string const & hostUrl, - std::string const & servicePath, std::string channel, std::string version); - - LOG_CLASS(LLUpdateChecker::Implementation); -}; - - - // LLUpdateChecker //----------------------------------------------------------------------------- @@ -134,13 +103,7 @@ void LLUpdateChecker::Implementation::checkVersion(std::string const & protocolV std::string checkUrl = buildUrl(protocolVersion, hostUrl, servicePath, channel, version); LL_INFOS("UpdateCheck") << "checking for updates at " << checkUrl << llendl; - // The HTTP client will wrap a raw pointer in a boost::intrusive_ptr causing the - // passed object to be silently and automatically deleted. We pass a self- - // referential intrusive pointer to which we add a reference to keep the - // client from deleting the update checker implementation instance. - LLHTTPClient::ResponderPtr temporaryPtr(this); - boost::intrusive_ptr_add_ref(temporaryPtr.get()); - mHttpClient.get(checkUrl, temporaryPtr); + mHttpClient.get(checkUrl, this); } void LLUpdateChecker::Implementation::completed(U32 status, diff --git a/indra/viewer_components/updater/llupdatechecker.h b/indra/viewer_components/updater/llupdatechecker.h index d882169068..23f62a7c5e 100644 --- a/indra/viewer_components/updater/llupdatechecker.h +++ b/indra/viewer_components/updater/llupdatechecker.h @@ -29,6 +29,7 @@ #include +#include "llhttpclient.h" // // Implements asynchronous checking for updates. @@ -36,7 +37,36 @@ class LLUpdateChecker { public: class Client; - class Implementation; + class Implementation: + + public LLHTTPClient::Responder + { + public: + Implementation(Client & client); + ~Implementation(); + void checkVersion(std::string const & protocolVersion, std::string const & hostUrl, + std::string const & servicePath, std::string channel, std::string version); + + // Responder: + virtual void completed(U32 status, + const std::string & reason, + const LLSD& content); + virtual void error(U32 status, const std::string & reason); + + private: + static const char * sProtocolVersion; + + Client & mClient; + LLHTTPClient mHttpClient; + bool mInProgress; + std::string mVersion; + + std::string buildUrl(std::string const & protocolVersion, std::string const & hostUrl, + std::string const & servicePath, std::string channel, std::string version); + + LOG_CLASS(LLUpdateChecker::Implementation); + }; + // An exception that may be raised on check errors. class CheckError; @@ -48,7 +78,7 @@ public: std::string const & servicePath, std::string channel, std::string version); private: - boost::shared_ptr mImplementation; + LLPointer mImplementation; }; -- cgit v1.3