diff options
Diffstat (limited to 'indra/newview')
151 files changed, 6769 insertions, 5960 deletions
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index ee33c41930..42b47d5e64 100755 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -99,6 +99,7 @@ include_directories(SYSTEM  set(viewer_SOURCE_FILES      groupchatlistener.cpp      llaccountingcostmanager.cpp +    llaisapi.cpp      llagent.cpp      llagentaccess.cpp      llagentcamera.cpp @@ -109,7 +110,6 @@ set(viewer_SOURCE_FILES      llagentpilot.cpp      llagentui.cpp      llagentwearables.cpp -    llagentwearablesfetch.cpp      llanimstatelabels.cpp      llappcorehttp.cpp      llappearancemgr.cpp @@ -314,6 +314,7 @@ set(viewer_SOURCE_FILES      llhasheduniqueid.cpp      llhints.cpp      llhomelocationresponder.cpp +    llhttpretrypolicy.cpp      llhudeffect.cpp      llhudeffectbeam.cpp      llhudeffectlookat.cpp @@ -690,6 +691,7 @@ set(viewer_HEADER_FILES      groupchatlistener.h      llaccountingcost.h      llaccountingcostmanager.h +    llaisapi.h      llagent.h      llagentaccess.h      llagentcamera.h @@ -700,7 +702,6 @@ set(viewer_HEADER_FILES      llagentpilot.h      llagentui.h      llagentwearables.h -    llagentwearablesfetch.h      llanimstatelabels.h      llappcorehttp.h      llappearance.h @@ -907,6 +908,7 @@ set(viewer_HEADER_FILES      llgroupmgr.h      llhasheduniqueid.h      llhints.h +    llhttpretrypolicy.h      llhomelocationresponder.h      llhudeffect.h      llhudeffectbeam.h @@ -2168,10 +2170,21 @@ if (LL_TESTS)      #llviewertexturelist.cpp    ) +  set(test_libs +    ${JSONCPP_LIBRARIES} +    ${CURL_LIBRARIES} +    ) +    set_source_files_properties(      lltranslate.cpp      PROPERTIES -    LL_TEST_ADDITIONAL_LIBRARIES "${JSONCPP_LIBRARIES}" +    LL_TEST_ADDITIONAL_LIBRARIES "${test_libs}" +  ) + +  set_source_files_properties( +    llmediadataclient.cpp +    PROPERTIES +    LL_TEST_ADDITIONAL_LIBRARIES "${CURL_LIBRARIES}"    )    set_source_files_properties( @@ -2252,6 +2265,7 @@ if (LL_TESTS)    set(test_libs      ${LLMESSAGE_LIBRARIES} +    ${LLCOREHTTP_LIBRARIES}      ${WINDOWS_LIBRARIES}      ${LLVFS_LIBRARIES}      ${LLMATH_LIBRARIES} @@ -2292,6 +2306,8 @@ if (LL_TESTS)      "${test_libs}"      ) +  LL_ADD_INTEGRATION_TEST(llhttpretrypolicy "llhttpretrypolicy.cpp" "${test_libs}") +    #ADD_VIEWER_BUILD_TEST(llmemoryview viewer)    #ADD_VIEWER_BUILD_TEST(llagentaccess viewer)    #ADD_VIEWER_BUILD_TEST(lltextureinfo viewer) diff --git a/indra/newview/app_settings/logcontrol.xml b/indra/newview/app_settings/logcontrol.xml index 7da047aed5..15cb5bc0eb 100755 --- a/indra/newview/app_settings/logcontrol.xml +++ b/indra/newview/app_settings/logcontrol.xml @@ -43,6 +43,7 @@  					<key>tags</key>  						<array>  						<!-- sample entry for debugging specific items	 +						     <string>Inventory</string>  						     <string>SceneLoadTiming</string>  						     <string>Avatar</string>  						     <string>Voice</string>		 diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 56001ff46f..71715ed801 100755 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -11759,6 +11759,17 @@        <key>Value</key>        <integer>0</integer>      </map> +  <key>TextureFetchFakeFailureRate</key> +  <map> +    <key>Comment</key> +    <string>Simulate HTTP fetch failures for some server bake textures.</string> +    <key>Persist</key> +    <integer>1</integer> +    <key>Type</key> +    <string>F32</string> +    <key>Value</key> +    <integer>0.0</integer> +  </map>      <key>TextureFetchSource</key>      <map>        <key>Comment</key> diff --git a/indra/newview/character/avatar_lad.xml b/indra/newview/character/avatar_lad.xml index 6de5b18c3c..9ec6428ee6 100755 --- a/indra/newview/character/avatar_lad.xml +++ b/indra/newview/character/avatar_lad.xml @@ -4480,7 +4480,7 @@       group="1"       sex="female"       name="Breast_Physics_UpDown_Driven" -     wearable="shape" +     wearable="physics"       edit_group="driven"       value_default="0"       value_min="-3" @@ -4502,7 +4502,7 @@       group="1"       sex="female"       name="Breast_Physics_InOut_Driven" -     wearable="shape" +     wearable="physics"       edit_group="driven"       value_default="0"       value_min="-1.25" @@ -4524,7 +4524,6 @@       group="1"       name="Belly_Physics_Torso_UpDown_Driven"       wearable="physics" -     cross_wearable="true"       edit_group="driven"       value_default="0"       value_min="-1" @@ -4542,7 +4541,6 @@       group="1"       name="Breast_Physics_LeftRight_Driven"       wearable="physics" -     cross_wearable="true"       edit_group="driven"       value_default="0"       value_min="-2" @@ -7716,7 +7714,7 @@ render_pass="bump">        <param         id="868" -       group="0" +       group="3"         wearable="shirt"         edit_group="shirt"         edit_group_order="8" @@ -8839,7 +8837,7 @@ render_pass="bump">        <param         id="869" -       group="0" +       group="3"         wearable="pants"         edit_group="pants"         edit_group_order="6" @@ -9760,7 +9758,7 @@ render_pass="bump">      <param       id="163" -     group="0" +     group="3"       wearable="skin"       edit_group="skin_facedetail"       edit_group_order="3" @@ -11819,7 +11817,7 @@ render_pass="bump">      <param       id="877" -     group="0" +     group="3"       name="Jacket Wrinkles"       label="Jacket Wrinkles"       wearable="jacket" diff --git a/indra/newview/llaccountingcostmanager.cpp b/indra/newview/llaccountingcostmanager.cpp index 150b97baa5..a42286a9e4 100755 --- a/indra/newview/llaccountingcostmanager.cpp +++ b/indra/newview/llaccountingcostmanager.cpp @@ -36,6 +36,7 @@ LLAccountingCostManager::LLAccountingCostManager()  //===============================================================================  class LLAccountingCostResponder : public LLCurl::Responder  { +	LOG_CLASS(LLAccountingCostResponder);  public:  	LLAccountingCostResponder( const LLSD& objectIDs, const LLHandle<LLAccountingCostObserver>& observer_handle )  	: mObjectIDs( objectIDs ), @@ -56,24 +57,27 @@ public:  		}  	} -	void errorWithContent( U32 statusNum, const std::string& reason, const LLSD& content ) +protected: +	void httpFailure()  	{ -		LL_WARNS() << "Transport error [status:" << statusNum << "]: " << content <<LL_ENDL; +		LL_WARNS() << dumpResponse() << LL_ENDL;  		clearPendingRequests();  		LLAccountingCostObserver* observer = mObserverHandle.get();  		if (observer && observer->getTransactionID() == mTransactionID)  		{ -			observer->setErrorStatus(statusNum, reason); +			observer->setErrorStatus(getStatus(), getReason());  		}  	} -	void result( const LLSD& content ) +	void httpSuccess()  	{ +		const LLSD& content = getContent();  		//Check for error  		if ( !content.isMap() || content.has("error") )  		{ -			LL_WARNS()	<< "Error on fetched data"<< LL_ENDL; +			failureResult(HTTP_INTERNAL_ERROR, "Error on fetched data", content); +			return;  		}  		else if (content.has("selected"))  		{ diff --git a/indra/newview/llaccountingcostmanager.h b/indra/newview/llaccountingcostmanager.h index 0bca1f54ef..3ade34c81d 100755 --- a/indra/newview/llaccountingcostmanager.h +++ b/indra/newview/llaccountingcostmanager.h @@ -38,7 +38,7 @@ public:  	LLAccountingCostObserver() { mObserverHandle.bind(this); }  	virtual ~LLAccountingCostObserver() {}  	virtual void onWeightsUpdate(const SelectionCost& selection_cost) = 0; -	virtual void setErrorStatus(U32 status, const std::string& reason) = 0; +	virtual void setErrorStatus(S32 status, const std::string& reason) = 0;  	const LLHandle<LLAccountingCostObserver>& getObserverHandle() const { return mObserverHandle; }  	const LLUUID& getTransactionID() { return mTransactionID; } diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index eb9ca542a3..aa8e0bad76 100755 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -406,7 +406,7 @@ LLAgent::LLAgent() :  	mNextFidgetTime(0.f),  	mCurrentFidget(0),  	mFirstLogin(FALSE), -	mGenderChosen(FALSE), +	mOutfitChosen(FALSE),  	mVoiceConnected(false), @@ -809,30 +809,6 @@ void LLAgent::standUp()  	setControlFlags(AGENT_CONTROL_STAND_UP);  } - -void LLAgent::handleServerBakeRegionTransition(const LLUUID& region_id) -{ -	LL_INFOS() << "called" << LL_ENDL; - - -	// Old-style appearance entering a server-bake region. -	if (isAgentAvatarValid() && -		!gAgentAvatarp->isUsingServerBakes() && -		(mRegionp->getCentralBakeVersion()>0)) -	{ -		LL_INFOS() << "update requested due to region transition" << LL_ENDL; -		LLAppearanceMgr::instance().requestServerAppearanceUpdate(); -	} -	// new-style appearance entering a non-bake region, -	// need to check for existence of the baking service. -	else if (isAgentAvatarValid() && -			 gAgentAvatarp->isUsingServerBakes() && -			 mRegionp->getCentralBakeVersion()==0) -	{ -		gAgentAvatarp->checkForUnsupportedServerBakeAppearance(); -	} -} -  void LLAgent::changeParcels()  {  	LL_DEBUGS("AgentLocation") << "Calling ParcelChanged callbacks" << LL_ENDL; @@ -934,19 +910,6 @@ void LLAgent::setRegion(LLViewerRegion *regionp)  	LLFloaterMove::sUpdateFlyingStatus(); -	// If the newly entered region is using server bakes, and our -	// current appearance is non-baked, request appearance update from -	// server. -	if (mRegionp->capabilitiesReceived()) -	{ -		handleServerBakeRegionTransition(mRegionp->getRegionID()); -	} -	else -	{ -		// Need to handle via callback after caps arrive. -		mRegionp->setCapabilitiesReceivedCallback(boost::bind(&LLAgent::handleServerBakeRegionTransition,this,_1)); -	} -  	if (notifyRegionChange)  	{  		LL_DEBUGS("AgentLocation") << "Calling RegionChanged callbacks" << LL_ENDL; @@ -1917,7 +1880,7 @@ BOOL LLAgent::needsRenderAvatar()  		return FALSE;  	} -	return mShowAvatar && mGenderChosen; +	return mShowAvatar && mOutfitChosen;  }  // TRUE if we need to render your own avatar's head. @@ -2565,17 +2528,19 @@ int LLAgent::convertTextToMaturity(char text)  class LLMaturityPreferencesResponder : public LLHTTPClient::Responder  { +	LOG_CLASS(LLMaturityPreferencesResponder);  public:  	LLMaturityPreferencesResponder(LLAgent *pAgent, U8 pPreferredMaturity, U8 pPreviousMaturity);  	virtual ~LLMaturityPreferencesResponder(); -	virtual void result(const LLSD &pContent); -	virtual void errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent); +protected: +	virtual void httpSuccess(); +	virtual void httpFailure();  protected:  private: -	U8 parseMaturityFromServerResponse(const LLSD &pContent); +	U8 parseMaturityFromServerResponse(const LLSD &pContent) const;  	LLAgent                                  *mAgent;  	U8                                       mPreferredMaturity; @@ -2594,39 +2559,43 @@ LLMaturityPreferencesResponder::~LLMaturityPreferencesResponder()  {  } -void LLMaturityPreferencesResponder::result(const LLSD &pContent) +void LLMaturityPreferencesResponder::httpSuccess()  { -	U8 actualMaturity = parseMaturityFromServerResponse(pContent); +	U8 actualMaturity = parseMaturityFromServerResponse(getContent());  	if (actualMaturity != mPreferredMaturity)  	{ -		LL_WARNS() << "while attempting to change maturity preference from '" << LLViewerRegion::accessToString(mPreviousMaturity) -			<< "' to '" << LLViewerRegion::accessToString(mPreferredMaturity) << "', the server responded with '" -			<< LLViewerRegion::accessToString(actualMaturity) << "' [value:" << static_cast<U32>(actualMaturity) << ", llsd:" -			<< pContent << "]" << LL_ENDL; +		LL_WARNS() << "while attempting to change maturity preference from '" +				   << LLViewerRegion::accessToString(mPreviousMaturity) +				   << "' to '" << LLViewerRegion::accessToString(mPreferredMaturity)  +				   << "', the server responded with '" +				   << LLViewerRegion::accessToString(actualMaturity)  +				   << "' [value:" << static_cast<U32>(actualMaturity)  +				   << "], " << dumpResponse() << LL_ENDL;  	}  	mAgent->handlePreferredMaturityResult(actualMaturity);  } -void LLMaturityPreferencesResponder::errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent) +void LLMaturityPreferencesResponder::httpFailure()  { -	LL_WARNS() << "while attempting to change maturity preference from '" << LLViewerRegion::accessToString(mPreviousMaturity) -		<< "' to '" << LLViewerRegion::accessToString(mPreferredMaturity) << "', we got an error with [status:" -		<< pStatus << "]: " << (pContent.isDefined() ? pContent : LLSD(pReason)) << LL_ENDL; +	LL_WARNS() << "while attempting to change maturity preference from '"  +			   << LLViewerRegion::accessToString(mPreviousMaturity) +			   << "' to '" << LLViewerRegion::accessToString(mPreferredMaturity)  +			<< "', " << dumpResponse() << LL_ENDL;  	mAgent->handlePreferredMaturityError();  } -U8 LLMaturityPreferencesResponder::parseMaturityFromServerResponse(const LLSD &pContent) +U8 LLMaturityPreferencesResponder::parseMaturityFromServerResponse(const LLSD &pContent) const  {  	U8 maturity = SIM_ACCESS_MIN; -	llassert(!pContent.isUndefined()); +	llassert(pContent.isDefined());  	llassert(pContent.isMap());  	llassert(pContent.has("access_prefs"));  	llassert(pContent.get("access_prefs").isMap());  	llassert(pContent.get("access_prefs").has("max"));  	llassert(pContent.get("access_prefs").get("max").isString()); -	if (!pContent.isUndefined() && pContent.isMap() && pContent.has("access_prefs") +	if (pContent.isDefined() && pContent.isMap() && pContent.has("access_prefs")  		&& pContent.get("access_prefs").isMap() && pContent.get("access_prefs").has("max")  		&& pContent.get("access_prefs").get("max").isString())  	{ @@ -2772,7 +2741,7 @@ void LLAgent::sendMaturityPreferenceToServer(U8 pPreferredMaturity)  		// If we don't have a region, report it as an error  		if (getRegion() == NULL)  		{ -			responderPtr->errorWithContent(0U, "region is not defined", LLSD()); +			responderPtr->failureResult(0U, "region is not defined", LLSD());  		}  		else  		{ @@ -2782,7 +2751,7 @@ void LLAgent::sendMaturityPreferenceToServer(U8 pPreferredMaturity)  			// If the capability is not defined, report it as an error  			if (url.empty())  			{ -				responderPtr->errorWithContent(0U,  +				responderPtr->failureResult(0U,   							"capability 'UpdateAgentInformation' is not defined for region", LLSD());  			}  			else @@ -3330,8 +3299,7 @@ class LLAgentDropGroupViewerNode : public LLHTTPNode  			!input.has("body") )  		{  			//what to do with badly formed message? -			response->statusUnknownError(400); -			response->result(LLSD("Invalid message parameters")); +			response->extendedResult(HTTP_BAD_REQUEST, LLSD("Invalid message parameters"));  		}  		LLSD body = input["body"]; @@ -3400,8 +3368,7 @@ class LLAgentDropGroupViewerNode : public LLHTTPNode  		else  		{  			//what to do with badly formed message? -			response->statusUnknownError(400); -			response->result(LLSD("Invalid message parameters")); +			response->extendedResult(HTTP_BAD_REQUEST, LLSD("Invalid message parameters"));  		}  	}  }; @@ -3683,82 +3650,6 @@ void LLAgent::processControlRelease(LLMessageSystem *msg, void **)  }  */ -//static -void LLAgent::processAgentCachedTextureResponse(LLMessageSystem *mesgsys, void **user_data) -{ -	gAgentQueryManager.mNumPendingQueries--; -	if (gAgentQueryManager.mNumPendingQueries == 0) -	{ -		selfStopPhase("fetch_texture_cache_entries"); -	} - -	if (!isAgentAvatarValid() || gAgentAvatarp->isDead()) -	{ -		LL_WARNS() << "No avatar for user in cached texture update!" << LL_ENDL; -		return; -	} - -	if (isAgentAvatarValid() && gAgentAvatarp->isEditingAppearance()) -	{ -		// ignore baked textures when in customize mode -		return; -	} - -	S32 query_id; -	mesgsys->getS32Fast(_PREHASH_AgentData, _PREHASH_SerialNum, query_id); - -	S32 num_texture_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_WearableData); - - -	S32 num_results = 0; -	for (S32 texture_block = 0; texture_block < num_texture_blocks; texture_block++) -	{ -		LLUUID texture_id; -		U8 texture_index; - -		mesgsys->getUUIDFast(_PREHASH_WearableData, _PREHASH_TextureID, texture_id, texture_block); -		mesgsys->getU8Fast(_PREHASH_WearableData, _PREHASH_TextureIndex, texture_index, texture_block); - - -		if ((S32)texture_index < TEX_NUM_INDICES ) -		{	 -			const LLAvatarAppearanceDictionary::TextureEntry *texture_entry = LLAvatarAppearanceDictionary::instance().getTexture((ETextureIndex)texture_index); -			if (texture_entry) -			{ -				EBakedTextureIndex baked_index = texture_entry->mBakedTextureIndex; - -				if (gAgentQueryManager.mActiveCacheQueries[baked_index] == query_id) -				{ -					if (texture_id.notNull()) -					{ -						//LL_INFOS() << "Received cached texture " << (U32)texture_index << ": " << texture_id << LL_ENDL; -						gAgentAvatarp->setCachedBakedTexture((ETextureIndex)texture_index, texture_id); -						//gAgentAvatarp->setTETexture( LLVOAvatar::sBakedTextureIndices[texture_index], texture_id ); -						gAgentQueryManager.mActiveCacheQueries[baked_index] = 0; -						num_results++; -					} -					else -					{ -						// no cache of this bake. request upload. -						gAgentAvatarp->invalidateComposite(gAgentAvatarp->getLayerSet(baked_index),TRUE); -					} -				} -			} -		} -	} -	LL_INFOS() << "Received cached texture response for " << num_results << " textures." << LL_ENDL; -	gAgentAvatarp->outputRezTiming("Fetched agent wearables textures from cache. Will now load them"); - -	gAgentAvatarp->updateMeshTextures(); - -	if (gAgentQueryManager.mNumPendingQueries == 0) -	{ -		// RN: not sure why composites are disabled at this point -		gAgentAvatarp->setCompositeUpdatesEnabled(TRUE); -		gAgent.sendAgentSetAppearance(); -	} -} -  BOOL LLAgent::anyControlGrabbed() const  {  	for (U32 i = 0; i < TOTAL_CONTROLS; i++) @@ -4351,192 +4242,6 @@ void LLAgent::requestLeaveGodMode()  	sendReliableMessage();  } -// For debugging, trace agent state at times appearance message are sent out. -void LLAgent::dumpSentAppearance(const std::string& dump_prefix) -{ -	std::string outfilename = get_sequential_numbered_file_name(dump_prefix,".xml"); - -	LLAPRFile outfile; -	std::string fullpath = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,outfilename); -	outfile.open(fullpath, LL_APR_WB ); -	apr_file_t* file = outfile.getFileHandle(); -	if (!file) -	{ -		return; -	} -	else -	{ -		LL_DEBUGS("Avatar") << "dumping sent appearance message to " << fullpath << LL_ENDL; -	} - -	LLVisualParam* appearance_version_param = gAgentAvatarp->getVisualParam(11000); -	if (appearance_version_param) -	{ -		F32 value = appearance_version_param->getWeight(); -		dump_visual_param(file, appearance_version_param, value); -	} -	for (LLAvatarAppearanceDictionary::Textures::const_iterator iter = LLAvatarAppearanceDictionary::getInstance()->getTextures().begin(); -		 iter != LLAvatarAppearanceDictionary::getInstance()->getTextures().end(); -		 ++iter) -	{ -		const ETextureIndex index = iter->first; -		const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = iter->second; -		if (texture_dict->mIsBakedTexture) -		{ -			LLTextureEntry* entry = gAgentAvatarp->getTE((U8) index); -			const LLUUID& uuid = entry->getID(); -			apr_file_printf( file, "\t\t<texture te=\"%i\" uuid=\"%s\"/>\n", index, uuid.asString().c_str()); -		} -	} -} - -//----------------------------------------------------------------------------- -// sendAgentSetAppearance() -//----------------------------------------------------------------------------- -void LLAgent::sendAgentSetAppearance() -{ -	if (gAgentQueryManager.mNumPendingQueries > 0)  -	{ -		return; -	} - -	if (!isAgentAvatarValid() || (getRegion() && getRegion()->getCentralBakeVersion())) return; - -	// At this point we have a complete appearance to send and are in a non-baking region. -	// DRANO FIXME -	//gAgentAvatarp->setIsUsingServerBakes(FALSE); -	S32 sb_count, host_count, both_count, neither_count; -	gAgentAvatarp->bakedTextureOriginCounts(sb_count, host_count, both_count, neither_count); -	if (both_count != 0 || neither_count != 0) -	{ -		LL_WARNS() << "bad bake texture state " << sb_count << "," << host_count << "," << both_count << "," << neither_count << LL_ENDL; -	} -	if (sb_count != 0 && host_count == 0) -	{ -		gAgentAvatarp->setIsUsingServerBakes(true); -	} -	else if (sb_count == 0 && host_count != 0) -	{ -		gAgentAvatarp->setIsUsingServerBakes(false); -	} -	else if (sb_count + host_count > 0) -	{ -		LL_WARNS() << "unclear baked texture state, not sending appearance" << LL_ENDL; -		return; -	} -	 -	 -	LL_DEBUGS("Avatar") << gAgentAvatarp->avString() << "TAT: Sent AgentSetAppearance: " << gAgentAvatarp->getBakedStatusForPrintout() << LL_ENDL; -	//dumpAvatarTEs( "sendAgentSetAppearance()" ); - -	LLMessageSystem* msg = gMessageSystem; -	msg->newMessageFast(_PREHASH_AgentSetAppearance); -	msg->nextBlockFast(_PREHASH_AgentData); -	msg->addUUIDFast(_PREHASH_AgentID, getID()); -	msg->addUUIDFast(_PREHASH_SessionID, getSessionID()); - -	// correct for the collision tolerance (to make it look like the  -	// agent is actually walking on the ground/object) -	// NOTE -- when we start correcting all of the other Havok geometry  -	// to compensate for the COLLISION_TOLERANCE ugliness we will have  -	// to tweak this number again -	const LLVector3 body_size = gAgentAvatarp->mBodySize + gAgentAvatarp->mAvatarOffset; -	msg->addVector3Fast(_PREHASH_Size, body_size);	 - -	// To guard against out of order packets -	// Note: always start by sending 1.  This resets the server's count. 0 on the server means "uninitialized" -	mAppearanceSerialNum++; -	msg->addU32Fast(_PREHASH_SerialNum, mAppearanceSerialNum ); - -	// is texture data current relative to wearables? -	// KLW - TAT this will probably need to check the local queue. -	BOOL textures_current = gAgentAvatarp->areTexturesCurrent(); - -	for(U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++ ) -	{ -		const ETextureIndex texture_index = LLAvatarAppearanceDictionary::bakedToLocalTextureIndex((EBakedTextureIndex)baked_index); - -		// if we're not wearing a skirt, we don't need the texture to be baked -		if (texture_index == TEX_SKIRT_BAKED && !gAgentAvatarp->isWearingWearableType(LLWearableType::WT_SKIRT)) -		{ -			continue; -		} - -		// IMG_DEFAULT_AVATAR means not baked. 0 index should be ignored for baked textures -		if (!gAgentAvatarp->isTextureDefined(texture_index, 0)) -		{ -			LL_DEBUGS("Avatar") << "texture not current for baked " << (S32)baked_index << " local " << (S32)texture_index << LL_ENDL; -			textures_current = FALSE; -			break; -		} -	} - -	// only update cache entries if we have all our baked textures - -	// FIXME DRANO need additional check for not in appearance editing -	// mode, if still using local composites need to set using local -	// composites to false, and update mesh textures. -	if (textures_current) -	{ -		bool enable_verbose_dumps = gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"); -		std::string dump_prefix = gAgentAvatarp->getFullname() + "_sent_appearance"; -		if (enable_verbose_dumps) -		{ -			dumpSentAppearance(dump_prefix); -		} -		LL_DEBUGS("Avatar") << gAgentAvatarp->avString() << "TAT: Sending cached texture data" << LL_ENDL; -		for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++) -		{ -			BOOL generate_valid_hash = TRUE; -			if (isAgentAvatarValid() && !gAgentAvatarp->isBakedTextureFinal((LLAvatarAppearanceDefines::EBakedTextureIndex)baked_index)) -			{ -				generate_valid_hash = FALSE; -				LL_DEBUGS("Avatar") << gAgentAvatarp->avString() << "Not caching baked texture upload for " << (U32)baked_index << " due to being uploaded at low resolution." << LL_ENDL; -			} - -			const LLUUID hash = gAgentWearables.computeBakedTextureHash((EBakedTextureIndex) baked_index, generate_valid_hash); -			if (hash.notNull()) -			{ -				ETextureIndex texture_index = LLAvatarAppearanceDictionary::bakedToLocalTextureIndex((EBakedTextureIndex) baked_index); -				msg->nextBlockFast(_PREHASH_WearableData); -				msg->addUUIDFast(_PREHASH_CacheID, hash); -				msg->addU8Fast(_PREHASH_TextureIndex, (U8)texture_index); -			} -		} -		msg->nextBlockFast(_PREHASH_ObjectData); -		gAgentAvatarp->sendAppearanceMessage( gMessageSystem ); -	} -	else -	{ -		// If the textures aren't baked, send NULL for texture IDs -		// This means the baked texture IDs on the server will be untouched. -		// Once all textures are baked, another AvatarAppearance message will be sent to update the TEs -		msg->nextBlockFast(_PREHASH_ObjectData); -		gMessageSystem->addBinaryDataFast(_PREHASH_TextureEntry, NULL, 0); -	} - - -	S32 transmitted_params = 0; -	for (LLViewerVisualParam* param = (LLViewerVisualParam*)gAgentAvatarp->getFirstVisualParam(); -		 param; -		 param = (LLViewerVisualParam*)gAgentAvatarp->getNextVisualParam()) -	{ -		if (param->getGroup() == VISUAL_PARAM_GROUP_TWEAKABLE) // do not transmit params of group VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT -		{ -			msg->nextBlockFast(_PREHASH_VisualParam ); -			 -			// We don't send the param ids.  Instead, we assume that the receiver has the same params in the same sequence. -			const F32 param_value = param->getWeight(); -			const U8 new_weight = F32_to_U8(param_value, param->getMinWeight(), param->getMaxWeight()); -			msg->addU8Fast(_PREHASH_ParamValue, new_weight ); -			transmitted_params++; -		} -	} - -	//LL_INFOS() << "Avatar XML num VisualParams transmitted = " << transmitted_params << LL_ENDL; -	sendReliableMessage(); -} -  void LLAgent::sendAgentDataUpdateRequest()  {  	gMessageSystem->newMessageFast(_PREHASH_AgentDataUpdateRequest); @@ -4679,23 +4384,6 @@ void LLAgent::renderAutoPilotTarget()  /********************************************************************************/ -LLAgentQueryManager gAgentQueryManager; - -LLAgentQueryManager::LLAgentQueryManager() : -	mWearablesCacheQueryID(0), -	mNumPendingQueries(0), -	mUpdateSerialNum(0) -{ -	for (U32 i = 0; i < BAKED_NUM_INDICES; i++) -	{ -		mActiveCacheQueries[i] = 0; -	} -} - -LLAgentQueryManager::~LLAgentQueryManager() -{ -} -  //-----------------------------------------------------------------------------  // LLTeleportRequest  //----------------------------------------------------------------------------- diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h index 1a573d32ce..a2e9cedd88 100755 --- a/indra/newview/llagent.h +++ b/indra/newview/llagent.h @@ -161,12 +161,13 @@ public:  	// Gender  	//--------------------------------------------------------------------  public: -	// On the very first login, gender isn't chosen until the user clicks -	// in a dialog.  We don't render the avatar until they choose. -	BOOL 			isGenderChosen() const 	{ return mGenderChosen; } -	void			setGenderChosen(BOOL b)	{ mGenderChosen = b; } +	// On the very first login, outfit needs to be chosen by some +	// mechanism, usually by loading the requested initial outfit.  We +	// don't render the avatar until the choice is made. +	BOOL 			isOutfitChosen() const 	{ return mOutfitChosen; } +	void			setOutfitChosen(BOOL b)	{ mOutfitChosen = b; }  private: -	BOOL			mGenderChosen; +	BOOL			mOutfitChosen;  /**                    Identity   **                                                                            ** @@ -652,7 +653,6 @@ private:  	void            handleTeleportFinished();  	void            handleTeleportFailed(); -	void			handleServerBakeRegionTransition(const LLUUID& region_id);  	//--------------------------------------------------------------------  	// Teleport State @@ -888,8 +888,6 @@ private:  public:  	void			sendMessage(); // Send message to this agent's region  	void			sendReliableMessage(); -	void 			dumpSentAppearance(const std::string& dump_prefix); -	void			sendAgentSetAppearance();  	void 			sendAgentDataUpdateRequest();  	void 			sendAgentUserInfoRequest();  	// IM to Email and Online visibility @@ -903,7 +901,6 @@ public:  	static void		processAgentGroupDataUpdate(LLMessageSystem *msg, void **);  	static void		processAgentDropGroup(LLMessageSystem *msg, void **);  	static void		processScriptControlChange(LLMessageSystem *msg, void **); -	static void		processAgentCachedTextureResponse(LLMessageSystem *mesgsys, void **user_data);  /**                    Messaging   **                                                                            ** @@ -932,24 +929,4 @@ inline bool operator==(const LLGroupData &a, const LLGroupData &b)  	return (a.mID == b.mID);  } -class LLAgentQueryManager -{ -	friend class LLAgent; -	friend class LLAgentWearables; -	 -public: -	LLAgentQueryManager(); -	virtual ~LLAgentQueryManager(); -	 -	BOOL 			hasNoPendingQueries() const 	{ return getNumPendingQueries() == 0; } -	S32 			getNumPendingQueries() const 	{ return mNumPendingQueries; } -private: -	S32				mNumPendingQueries; -	S32				mWearablesCacheQueryID; -	U32				mUpdateSerialNum; -	S32		    	mActiveCacheQueries[LLAvatarAppearanceDefines::BAKED_NUM_INDICES]; -}; - -extern LLAgentQueryManager gAgentQueryManager; -  #endif diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp index 58981d0e06..26626ad894 100755 --- a/indra/newview/llagentwearables.cpp +++ b/indra/newview/llagentwearables.cpp @@ -30,7 +30,6 @@  #include "llaccordionctrltab.h"  #include "llagent.h"  #include "llagentcamera.h" -#include "llagentwearablesfetch.h"  #include "llappearancemgr.h"  #include "llcallbacklist.h"  #include "llfloatersidepanelcontainer.h" @@ -70,7 +69,7 @@ void wear_and_edit_cb(const LLUUID& inv_item)  	gAgentWearables.requestEditingWearable(inv_item);  	// Wear it. -	LLAppearanceMgr::instance().wearItemOnAvatar(inv_item); +	LLAppearanceMgr::instance().wearItemOnAvatar(inv_item,true);  }  /////////////////////////////////////////////////////////////////////////////// @@ -127,13 +126,6 @@ void LLAgentWearables::dump()  		}  	} -	LL_INFOS() << "Total items awaiting wearable update " << mItemsAwaitingWearableUpdate.size() << LL_ENDL; -	for (std::set<LLUUID>::iterator it = mItemsAwaitingWearableUpdate.begin(); -		 it != mItemsAwaitingWearableUpdate.end(); -		 ++it) -	{ -		LL_INFOS() << (*it).asString() << LL_ENDL; -	}  }  struct LLAgentDumper @@ -183,23 +175,9 @@ void LLAgentWearables::initClass()  void LLAgentWearables::setAvatarObject(LLVOAvatarSelf *avatar)  {  	llassert(avatar); -	avatar->outputRezTiming("Sending wearables request"); -	sendAgentWearablesRequest();  	setAvatarAppearance(avatar);  } -// wearables -LLAgentWearables::createStandardWearablesAllDoneCallback::~createStandardWearablesAllDoneCallback() -{ -	LL_INFOS() << "destructor - all done?" << LL_ENDL; -	gAgentWearables.createStandardWearablesAllDone(); -} - -LLAgentWearables::sendAgentWearablesUpdateCallback::~sendAgentWearablesUpdateCallback() -{ -	gAgentWearables.sendAgentWearablesUpdate(); -} -  /**   * @brief Construct a callback for dealing with the wearables.   * @@ -210,7 +188,7 @@ LLAgentWearables::sendAgentWearablesUpdateCallback::~sendAgentWearablesUpdateCal   * @param wearable The wearable data.   * @param todo Bitmask of actions to take on completion.   */ -LLAgentWearables::addWearableToAgentInventoryCallback::addWearableToAgentInventoryCallback( +LLAgentWearables::AddWearableToAgentInventoryCallback::AddWearableToAgentInventoryCallback(  	LLPointer<LLRefCount> cb, LLWearableType::EType type, U32 index, LLViewerWearable* wearable, U32 todo, const std::string description) :  	mType(type),  	mIndex(index),	 @@ -222,42 +200,24 @@ LLAgentWearables::addWearableToAgentInventoryCallback::addWearableToAgentInvento  	LL_INFOS() << "constructor" << LL_ENDL;  } -void LLAgentWearables::addWearableToAgentInventoryCallback::fire(const LLUUID& inv_item) +void LLAgentWearables::AddWearableToAgentInventoryCallback::fire(const LLUUID& inv_item)  { -	if (mTodo & CALL_CREATESTANDARDDONE) -	{ -		LL_INFOS() << "callback fired, inv_item " << inv_item.asString() << LL_ENDL; -	} -  	if (inv_item.isNull())  		return;  	gAgentWearables.addWearabletoAgentInventoryDone(mType, mIndex, inv_item, mWearable); -	if (mTodo & CALL_UPDATE) -	{ -		gAgentWearables.sendAgentWearablesUpdate(); -	} -	if (mTodo & CALL_RECOVERDONE) -	{ -		LLAppearanceMgr::instance().addCOFItemLink(inv_item,false); -		gAgentWearables.recoverMissingWearableDone(); -	}  	/*  	 * Do this for every one in the loop  	 */ -	if (mTodo & CALL_CREATESTANDARDDONE) -	{ -		LLAppearanceMgr::instance().addCOFItemLink(inv_item,false); -		gAgentWearables.createStandardWearablesDone(mType, mIndex); -	}  	if (mTodo & CALL_MAKENEWOUTFITDONE)  	{  		gAgentWearables.makeNewOutfitDone(mType, mIndex);  	}  	if (mTodo & CALL_WEARITEM)  	{ -		LLAppearanceMgr::instance().addCOFItemLink(inv_item, true, NULL, mDescription); +		LLAppearanceMgr::instance().addCOFItemLink(inv_item,  +			new LLUpdateAppearanceAndEditWearableOnDestroy(inv_item), mDescription);  	}  } @@ -304,81 +264,7 @@ void LLAgentWearables::addWearabletoAgentInventoryDone(const LLWearableType::ETy  	gInventory.notifyObservers();  } -void LLAgentWearables::sendAgentWearablesUpdate() -{ -	// First make sure that we have inventory items for each wearable -	for (S32 type=0; type < LLWearableType::WT_COUNT; ++type) -	{ -		for (U32 index=0; index < getWearableCount((LLWearableType::EType)type); ++index) -		{ -			LLViewerWearable* wearable = getViewerWearable((LLWearableType::EType)type,index); -			if (wearable) -			{ -				if (wearable->getItemID().isNull()) -				{ -					LLPointer<LLInventoryCallback> cb = -						new addWearableToAgentInventoryCallback( -							LLPointer<LLRefCount>(NULL), -							(LLWearableType::EType)type, -							index, -							wearable, -							addWearableToAgentInventoryCallback::CALL_NONE); -					addWearableToAgentInventory(cb, wearable); -				} -				else -				{ -					gInventory.addChangedMask(LLInventoryObserver::LABEL, -											  wearable->getItemID()); -				} -			} -		} -	} - -	// Then make sure the inventory is in sync with the avatar. -	gInventory.notifyObservers(); - -	// Send the AgentIsNowWearing  -	gMessageSystem->newMessageFast(_PREHASH_AgentIsNowWearing); - -	gMessageSystem->nextBlockFast(_PREHASH_AgentData); -	gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); -	gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - -	LL_DEBUGS() << "sendAgentWearablesUpdate()" << LL_ENDL; -	// MULTI-WEARABLE: DEPRECATED: HACK: index to 0- server database tables don't support concept of multiwearables. -	for (S32 type=0; type < LLWearableType::WT_COUNT; ++type) -	{ -		gMessageSystem->nextBlockFast(_PREHASH_WearableData); - -		U8 type_u8 = (U8)type; -		gMessageSystem->addU8Fast(_PREHASH_WearableType, type_u8); - -		LLViewerWearable* wearable = getViewerWearable((LLWearableType::EType)type, 0); -		if (wearable) -		{ -			//LL_INFOS() << "Sending wearable " << wearable->getName() << LL_ENDL; -			LLUUID item_id = wearable->getItemID(); -			const LLViewerInventoryItem *item = gInventory.getItem(item_id); -			if (item && item->getIsLinkType()) -			{ -				// Get the itemID that this item points to.  i.e. make sure -				// we are storing baseitems, not their links, in the database. -				item_id = item->getLinkedUUID(); -			} -			gMessageSystem->addUUIDFast(_PREHASH_ItemID, item_id);			 -		} -		else -		{ -			//LL_INFOS() << "Not wearing wearable type " << LLWearableType::getTypeName((LLWearableType::EType)i) << LL_ENDL; -			gMessageSystem->addUUIDFast(_PREHASH_ItemID, LLUUID::null); -		} - -		LL_DEBUGS() << "       " << LLWearableType::getTypeLabel((LLWearableType::EType)type) << ": " << (wearable ? wearable->getAssetID() : LLUUID::null) << LL_ENDL; -	} -	gAgent.sendReliableMessage(); -} - -void LLAgentWearables::saveWearable(const LLWearableType::EType type, const U32 index, BOOL send_update, +void LLAgentWearables::saveWearable(const LLWearableType::EType type, const U32 index,  									const std::string new_name)  {  	LLViewerWearable* old_wearable = getViewerWearable(type, index); @@ -419,23 +305,14 @@ void LLAgentWearables::saveWearable(const LLWearableType::EType type, const U32  										  item->getFlags(),  										  item->getCreationDate());  			template_item->setTransactionID(new_wearable->getTransactionID()); -			template_item->updateServer(FALSE); -			gInventory.updateItem(template_item); -			if (name_changed) -			{ -				gInventory.notifyObservers(); -			} +			update_inventory_item(template_item, gAgentAvatarp->mEndCustomizeCallback);  		}  		else  		{  			// Add a new inventory item (shouldn't ever happen here) -			U32 todo = addWearableToAgentInventoryCallback::CALL_NONE; -			if (send_update) -			{ -				todo |= addWearableToAgentInventoryCallback::CALL_UPDATE; -			} +			U32 todo = AddWearableToAgentInventoryCallback::CALL_NONE;  			LLPointer<LLInventoryCallback> cb = -				new addWearableToAgentInventoryCallback( +				new AddWearableToAgentInventoryCallback(  					LLPointer<LLRefCount>(NULL),  					type,  					index, @@ -445,12 +322,7 @@ void LLAgentWearables::saveWearable(const LLWearableType::EType type, const U32  			return;  		} -		gAgentAvatarp->wearableUpdated( type, TRUE ); - -		if (send_update) -		{ -			sendAgentWearablesUpdate(); -		} +		gAgentAvatarp->wearableUpdated(type);  	}  } @@ -484,12 +356,12 @@ void LLAgentWearables::saveWearableAs(const LLWearableType::EType type,  		old_wearable,  		trunc_name);  	LLPointer<LLInventoryCallback> cb = -		new addWearableToAgentInventoryCallback( +		new AddWearableToAgentInventoryCallback(  			LLPointer<LLRefCount>(NULL),  			type,  			index,  			new_wearable, -			addWearableToAgentInventoryCallback::CALL_WEARITEM, +			AddWearableToAgentInventoryCallback::CALL_WEARITEM,  			description  			);  	LLUUID category_id; @@ -526,8 +398,6 @@ void LLAgentWearables::revertWearable(const LLWearableType::EType type, const U3  	{  		wearable->revertValues();  	} - -	gAgent.sendAgentSetAppearance();  }  void LLAgentWearables::saveAllWearables() @@ -540,9 +410,8 @@ void LLAgentWearables::saveAllWearables()  	for (S32 i=0; i < LLWearableType::WT_COUNT; i++)  	{  		for (U32 j=0; j < getWearableCount((LLWearableType::EType)i); j++) -			saveWearable((LLWearableType::EType)i, j, FALSE); +			saveWearable((LLWearableType::EType)i, j);  	} -	sendAgentWearablesUpdate();  }  // Called when the user changes the name of a wearable inventory item that is currently being worn. @@ -571,7 +440,6 @@ void LLAgentWearables::setWearableName(const LLUUID& item_id, const std::string&  				old_wearable->setName(old_name);  				setWearable((LLWearableType::EType)i,j,new_wearable); -				sendAgentWearablesUpdate();  				break;  			}  		} @@ -692,15 +560,6 @@ LLViewerWearable*	LLAgentWearables::getWearableFromAssetID(const LLUUID& asset_i  	return NULL;  } -void LLAgentWearables::sendAgentWearablesRequest() -{ -	gMessageSystem->newMessageFast(_PREHASH_AgentWearablesRequest); -	gMessageSystem->nextBlockFast(_PREHASH_AgentData); -	gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); -	gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); -	gAgent.sendReliableMessage(); -} -  LLViewerWearable* LLAgentWearables::getViewerWearable(const LLWearableType::EType type, U32 index /*= 0*/)  {  	return dynamic_cast<LLViewerWearable*> (getWearable(type, index)); @@ -722,8 +581,7 @@ void LLAgentWearables::wearableUpdated(LLWearable *wearable, BOOL removed)  {  	if (isAgentAvatarValid())  	{ -		const BOOL upload_result = removed; -		gAgentAvatarp->wearableUpdated(wearable->getType(), upload_result); +		gAgentAvatarp->wearableUpdated(wearable->getType());  	}  	LLWearableData::wearableUpdated(wearable, removed); @@ -743,23 +601,13 @@ void LLAgentWearables::wearableUpdated(LLWearable *wearable, BOOL removed)  			wearable->setDefinitionVersion(22);  			U32 index = getWearableIndex(wearable);  			LL_INFOS() << "forcing wearable type " << wearable->getType() << " to version 22 from 24" << LL_ENDL; -			saveWearable(wearable->getType(),index,TRUE); +			saveWearable(wearable->getType(),index);  		}  		checkWearableAgainstInventory(viewer_wearable);  	}  } -BOOL LLAgentWearables::itemUpdatePending(const LLUUID& item_id) const -{ -	return mItemsAwaitingWearableUpdate.find(item_id) != mItemsAwaitingWearableUpdate.end(); -} - -U32 LLAgentWearables::itemUpdatePendingCount() const -{ -	return mItemsAwaitingWearableUpdate.size(); -} -  const LLUUID LLAgentWearables::getWearableItemID(LLWearableType::EType type, U32 index) const  {  	const LLViewerWearable *wearable = getViewerWearable(type,index); @@ -783,157 +631,6 @@ BOOL LLAgentWearables::isWearingItem(const LLUUID& item_id) const  	return getWearableFromItemID(item_id) != NULL;  } -// MULTI-WEARABLE: DEPRECATED (see backwards compatibility) -// static -// ! BACKWARDS COMPATIBILITY ! When we stop supporting viewer1.23, we can assume -// that viewers have a Current Outfit Folder and won't need this message, and thus -// we can remove/ignore this whole function. EXCEPT gAgentWearables.notifyLoadingStarted -void LLAgentWearables::processAgentInitialWearablesUpdate(LLMessageSystem* mesgsys, void** user_data) -{ -	// We should only receive this message a single time.  Ignore subsequent AgentWearablesUpdates -	// that may result from AgentWearablesRequest having been sent more than once. -	if (mInitialWearablesUpdateReceived) -		return; - -	if (isAgentAvatarValid()) -	{ -		gAgentAvatarp->startPhase("process_initial_wearables_update"); -		gAgentAvatarp->outputRezTiming("Received initial wearables update"); -	} - -	// notify subscribers that wearables started loading. See EXT-7777 -	// *TODO: find more proper place to not be called from deprecated method. -	// Seems such place is found: LLInitialWearablesFetch::processContents() -	gAgentWearables.notifyLoadingStarted(); - -	mInitialWearablesUpdateReceived = true; - -	LLUUID agent_id; -	gMessageSystem->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); - -	if (isAgentAvatarValid() && (agent_id == gAgentAvatarp->getID())) -	{ -		gMessageSystem->getU32Fast(_PREHASH_AgentData, _PREHASH_SerialNum, gAgentQueryManager.mUpdateSerialNum); -		 -		const S32 NUM_BODY_PARTS = 4; -		S32 num_wearables = gMessageSystem->getNumberOfBlocksFast(_PREHASH_WearableData); -		if (num_wearables < NUM_BODY_PARTS) -		{ -			// Transitional state.  Avatars should always have at least their body parts (hair, eyes, shape and skin). -			// The fact that they don't have any here (only a dummy is sent) implies that either: -			// 1. This account existed before we had wearables -			// 2. The database has gotten messed up -			// 3. This is the account's first login (i.e. the wearables haven't been generated yet). -			return; -		} - -		// Get the UUID of the current outfit folder (will be created if it doesn't exist) -		const LLUUID current_outfit_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); -		LLInitialWearablesFetch* outfit = new LLInitialWearablesFetch(current_outfit_id); -		 -		//LL_DEBUGS() << "processAgentInitialWearablesUpdate()" << LL_ENDL; -		// Add wearables -		// MULTI-WEARABLE: DEPRECATED: Message only supports one wearable per type, will be ignored in future. -		gAgentWearables.mItemsAwaitingWearableUpdate.clear(); -		for (S32 i=0; i < num_wearables; i++) -		{ -			// Parse initial wearables data from message system -			U8 type_u8 = 0; -			gMessageSystem->getU8Fast(_PREHASH_WearableData, _PREHASH_WearableType, type_u8, i); -			if (type_u8 >= LLWearableType::WT_COUNT) -			{ -				continue; -			} -			const LLWearableType::EType type = (LLWearableType::EType) type_u8; -			 -			LLUUID item_id; -			gMessageSystem->getUUIDFast(_PREHASH_WearableData, _PREHASH_ItemID, item_id, i); -			 -			LLUUID asset_id; -			gMessageSystem->getUUIDFast(_PREHASH_WearableData, _PREHASH_AssetID, asset_id, i); -			if (asset_id.isNull()) -			{ -				LLViewerWearable::removeFromAvatar(type, FALSE); -			} -			else -			{ -				LLAssetType::EType asset_type = LLWearableType::getAssetType(type); -				if (asset_type == LLAssetType::AT_NONE) -				{ -					continue; -				} -				 -				// MULTI-WEARABLE: DEPRECATED: this message only supports one wearable per type. Should be ignored in future versions -				 -				// Store initial wearables data until we know whether we have the current outfit folder or need to use the data. -				LLInitialWearablesFetch::InitialWearableData wearable_data(type, item_id, asset_id); -				outfit->add(wearable_data); -			} -			 -			LL_DEBUGS() << "       " << LLWearableType::getTypeLabel(type) << LL_ENDL; -		} -		 -		// Get the complete information on the items in the inventory and set up an observer -		// that will trigger when the complete information is fetched. -		outfit->startFetch(); -		if(outfit->isFinished()) -		{ -			// everything is already here - call done. -			outfit->done(); -		} -		else -		{ -			// it's all on it's way - add an observer, and the inventory -			// will call done for us when everything is here. -			gInventory.addObserver(outfit); -		} -		 -	} -} - -// Normally, all wearables referred to "AgentWearablesUpdate" will correspond to actual assets in the -// database.  If for some reason, we can't load one of those assets, we can try to reconstruct it so that -// the user isn't left without a shape, for example.  (We can do that only after the inventory has loaded.) -void LLAgentWearables::recoverMissingWearable(const LLWearableType::EType type, U32 index) -{ -	// Try to recover by replacing missing wearable with a new one. -	LLNotificationsUtil::add("ReplacedMissingWearable"); -	LL_DEBUGS() << "Wearable " << LLWearableType::getTypeLabel(type) << " could not be downloaded.  Replaced inventory item with default wearable." << LL_ENDL; -	LLViewerWearable* new_wearable = LLWearableList::instance().createNewWearable(type, gAgentAvatarp); - -	setWearable(type,index,new_wearable); -	//new_wearable->writeToAvatar(TRUE); - -	// Add a new one in the lost and found folder. -	// (We used to overwrite the "not found" one, but that could potentially -	// destory content.) JC -	const LLUUID lost_and_found_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); -	LLPointer<LLInventoryCallback> cb = -		new addWearableToAgentInventoryCallback( -			LLPointer<LLRefCount>(NULL), -			type, -			index, -			new_wearable, -			addWearableToAgentInventoryCallback::CALL_RECOVERDONE); -	addWearableToAgentInventory(cb, new_wearable, lost_and_found_id, TRUE); -} - -void LLAgentWearables::recoverMissingWearableDone() -{ -	// Have all the wearables that the avatar was wearing at log-in arrived or been fabricated? -	updateWearablesLoaded(); -	if (areWearablesLoaded()) -	{ -		// Make sure that the server's idea of the avatar's wearables actually match the wearables. -		gAgent.sendAgentSetAppearance(); -	} -	else -	{ -		gInventory.addChangedMask(LLInventoryObserver::LABEL, LLUUID::null); -		gInventory.notifyObservers(); -	} -} -  void LLAgentWearables::addLocalTextureObject(const LLWearableType::EType wearable_type, const LLAvatarAppearanceDefines::ETextureIndex texture_type, U32 wearable_index)  {  	LLViewerWearable* wearable = getViewerWearable((LLWearableType::EType)wearable_type, wearable_index); @@ -957,7 +654,7 @@ public:  	/* virtual */ void fire(const LLUUID& inv_item)  	{  		LL_INFOS() << "One item created " << inv_item.asString() << LL_ENDL; -		LLViewerInventoryItem *item = gInventory.getItem(inv_item); +		LLConstPointer<LLInventoryObject> item = gInventory.getItem(inv_item);  		mItemsToLink.push_back(item);  		updatePendingWearable(inv_item);  	} @@ -965,9 +662,9 @@ public:  	{  		LL_INFOS() << "All items created" << LL_ENDL;  		LLPointer<LLInventoryCallback> link_waiter = new LLUpdateAppearanceOnDestroy; -		LLAppearanceMgr::instance().linkAll(LLAppearanceMgr::instance().getCOF(), -											mItemsToLink, -											link_waiter); +		link_inventory_array(LLAppearanceMgr::instance().getCOF(), +							 mItemsToLink, +							 link_waiter);  	}  	void addPendingWearable(LLViewerWearable *wearable)  	{ @@ -1016,7 +713,7 @@ public:  	}  private: -	LLInventoryModel::item_array_t mItemsToLink; +	LLInventoryObject::const_object_list_t mItemsToLink;  	std::vector<LLViewerWearable*> mWearablesAwaitingItems;  }; @@ -1068,28 +765,38 @@ void LLAgentWearables::createStandardWearables()  	}  } -void LLAgentWearables::createStandardWearablesDone(S32 type, U32 index) +// We no longer need this message in the current viewer, but send +// it for now to maintain compatibility with release viewers. Can +// remove this function once the SH-3455 changesets are universally deployed. +void LLAgentWearables::sendDummyAgentWearablesUpdate()  { -	LL_INFOS() << "type " << type << " index " << index << LL_ENDL; +	LL_DEBUGS("Avatar") << "sendAgentWearablesUpdate()" << LL_ENDL; -	if (!isAgentAvatarValid()) return; -	gAgentAvatarp->updateVisualParams(); -} +	// Send the AgentIsNowWearing  +	gMessageSystem->newMessageFast(_PREHASH_AgentIsNowWearing); +	 +	gMessageSystem->nextBlockFast(_PREHASH_AgentData); +	gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); +	gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); -void LLAgentWearables::createStandardWearablesAllDone() -{ -	// ... because sendAgentWearablesUpdate will notify inventory -	// observers. -	LL_INFOS() << "all done?" << LL_ENDL; +	// Send 4 standardized nonsense item ids (same as returned by the modified sim, not that it especially matters). +	gMessageSystem->nextBlockFast(_PREHASH_WearableData); +	gMessageSystem->addU8Fast(_PREHASH_WearableType, U8(1)); +	gMessageSystem->addUUIDFast(_PREHASH_ItemID, LLUUID("db5a4e5f-9da3-44c8-992d-1181c5795498"));			 -	mWearablesLoaded = TRUE;  -	checkWearablesLoaded(); -	notifyLoadingFinished(); -	 -	updateServer(); +	gMessageSystem->nextBlockFast(_PREHASH_WearableData); +	gMessageSystem->addU8Fast(_PREHASH_WearableType, U8(2)); +	gMessageSystem->addUUIDFast(_PREHASH_ItemID, LLUUID("6969c7cc-f72f-4a76-a19b-c293cce8ce4f"));			 + +	gMessageSystem->nextBlockFast(_PREHASH_WearableData); +	gMessageSystem->addU8Fast(_PREHASH_WearableType, U8(3)); +	gMessageSystem->addUUIDFast(_PREHASH_ItemID, LLUUID("7999702b-b291-48f9-8903-c91dfb828408"));			 -	// Treat this as the first texture entry message, if none received yet -	gAgentAvatarp->onFirstTEMessageReceived(); +	gMessageSystem->nextBlockFast(_PREHASH_WearableData); +	gMessageSystem->addU8Fast(_PREHASH_WearableType, U8(4)); +	gMessageSystem->addUUIDFast(_PREHASH_ItemID, LLUUID("566cb59e-ef60-41d7-bfa6-e0f293fbea40"));			 + +	gAgent.sendReliableMessage();  }  void LLAgentWearables::makeNewOutfitDone(S32 type, U32 index) @@ -1205,11 +912,10 @@ void LLAgentWearables::removeWearableFinal(const LLWearableType::EType type, boo  		for (S32 i=max_entry; i>=0; i--)  		{  			LLViewerWearable* old_wearable = getViewerWearable(type,i); -			//queryWearableCache(); // moved below  			if (old_wearable)  			{  				popWearable(old_wearable); -				old_wearable->removeFromAvatar(TRUE); +				old_wearable->removeFromAvatar();  			}  		}  		clearWearableType(type); @@ -1217,48 +923,99 @@ void LLAgentWearables::removeWearableFinal(const LLWearableType::EType type, boo  	else  	{  		LLViewerWearable* old_wearable = getViewerWearable(type, index); -		//queryWearableCache(); // moved below  		if (old_wearable)  		{  			popWearable(old_wearable); -			old_wearable->removeFromAvatar(TRUE); +			old_wearable->removeFromAvatar();  		}  	} -	queryWearableCache(); - -	// Update the server -	updateServer();  	gInventory.notifyObservers();  }  // Assumes existing wearables are not dirty.  void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& items, -										 const std::vector< LLViewerWearable* >& wearables, -										 BOOL remove) +										 const std::vector< LLViewerWearable* >& wearables)  {  	LL_INFOS() << "setWearableOutfit() start" << LL_ENDL; +	S32 count = wearables.size(); +	llassert(items.size() == count); + +	// Check for whether outfit already matches the one requested +	S32 matched = 0, mismatched = 0; +	const S32 arr_size = LLWearableType::WT_COUNT; +	S32 type_counts[arr_size]; +	std::fill(type_counts,type_counts+arr_size,0); +	for (S32 i = 0; i < count; i++) +	{ +		LLViewerWearable* new_wearable = wearables[i]; +		LLPointer<LLInventoryItem> new_item = items[i]; + +		const LLWearableType::EType type = new_wearable->getType(); +		if (type < 0 || type>=LLWearableType::WT_COUNT) +		{ +			LL_WARNS() << "invalid type " << type << LL_ENDL; +			mismatched++; +			continue; +		} +		S32 index = type_counts[type]; +		type_counts[type]++; + +		LLViewerWearable *curr_wearable = dynamic_cast<LLViewerWearable*>(getWearable(type,index)); +		if (!new_wearable || !curr_wearable || +			new_wearable->getAssetID() != curr_wearable->getAssetID()) +		{ +			LL_DEBUGS("Avatar") << "mismatch, type " << type << " index " << index +								<< " names " << (curr_wearable ? curr_wearable->getName() : "NONE")  << "," +								<< " names " << (new_wearable ? new_wearable->getName() : "NONE")  << LL_ENDL; +			mismatched++; +			continue; +		} + +		if (curr_wearable->getName() != new_item->getName() || +			curr_wearable->getItemID() != new_item->getUUID()) +		{ +			LL_DEBUGS("Avatar") << "mismatch on name or inventory id, names " +								<< curr_wearable->getName() << " vs " << new_item->getName() +								<< " item ids " << curr_wearable->getItemID() << " vs " << new_item->getUUID() +								<< LL_ENDL; +			mismatched++; +			continue; +		} +		// If we got here, everything matches. +		matched++; +	} +	LL_DEBUGS("Avatar") << "matched " << matched << " mismatched " << mismatched << LL_ENDL; +	for (S32 j=0; j<LLWearableType::WT_COUNT; j++) +	{ +		LLWearableType::EType type = (LLWearableType::EType) j; +		if (getWearableCount(type) != type_counts[j]) +		{ +			LL_DEBUGS("Avatar") << "count mismatch for type " << j << " current " << getWearableCount(j) << " requested " << type_counts[j] << LL_ENDL;  +			mismatched++; +		} +	} +	if (mismatched == 0) +	{ +		LL_DEBUGS("Avatar") << "no changes, bailing out" << LL_ENDL; +		return; +	} +	 +	  	// TODO: Removed check for ensuring that teens don't remove undershirt and underwear. Handle later -	if (remove) +	// note: shirt is the first non-body part wearable item. Update if wearable order changes. +	// This loop should remove all clothing, but not any body parts +	for (S32 j = 0; j < (S32)LLWearableType::WT_COUNT; j++)  	{ -		// note: shirt is the first non-body part wearable item. Update if wearable order changes. -		// This loop should remove all clothing, but not any body parts -		for (S32 type = 0; type < (S32)LLWearableType::WT_COUNT; type++) +		if (LLWearableType::getAssetType((LLWearableType::EType)j) == LLAssetType::AT_CLOTHING)  		{ -			if (LLWearableType::getAssetType((LLWearableType::EType)type) == LLAssetType::AT_CLOTHING) -			{ -				removeWearable((LLWearableType::EType)type, true, 0); -			} +			removeWearable((LLWearableType::EType)j, true, 0);  		}  	} -	S32 count = wearables.size(); -	llassert(items.size() == count); - -	S32 i; -	for (i = 0; i < count; i++) +	for (S32 i = 0; i < count; i++)  	{  		LLViewerWearable* new_wearable = wearables[i];  		LLPointer<LLInventoryItem> new_item = items[i]; @@ -1305,14 +1062,12 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it  	// Start rendering & update the server  	mWearablesLoaded = TRUE;  -	checkWearablesLoaded(); +  	notifyLoadingFinished(); -	queryWearableCache(); -	updateServer();  	gAgentAvatarp->dumpAvatarTEs("setWearableOutfit"); -	LL_DEBUGS() << "setWearableOutfit() end" << LL_ENDL; +	LL_DEBUGS("Avatar") << "setWearableOutfit() end" << LL_ENDL;  } @@ -1429,79 +1184,6 @@ void LLAgentWearables::setWearableFinal(LLInventoryItem* new_item, LLViewerWeara  		LL_INFOS() << "Replaced current element 0 for type " << type  				<< " size is now " << getWearableCount(type) << LL_ENDL;  	} - -	//LL_INFOS() << "LLVOAvatar::setWearableItem()" << LL_ENDL; -	queryWearableCache(); -	//new_wearable->writeToAvatar(TRUE); - -	updateServer(); -} - -void LLAgentWearables::queryWearableCache() -{ -	if (!areWearablesLoaded() || (gAgent.getRegion() && gAgent.getRegion()->getCentralBakeVersion())) -	{ -		return; -	} - -	// Look up affected baked textures. -	// If they exist: -	//		disallow updates for affected layersets (until dataserver responds with cache request.) -	//		If cache miss, turn updates back on and invalidate composite. -	//		If cache hit, modify baked texture entries. -	// -	// Cache requests contain list of hashes for each baked texture entry. -	// Response is list of valid baked texture assets. (same message) - -	gMessageSystem->newMessageFast(_PREHASH_AgentCachedTexture); -	gMessageSystem->nextBlockFast(_PREHASH_AgentData); -	gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); -	gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); -	gMessageSystem->addS32Fast(_PREHASH_SerialNum, gAgentQueryManager.mWearablesCacheQueryID); - -	S32 num_queries = 0; -	for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++) -	{ -		LLUUID hash_id = computeBakedTextureHash((EBakedTextureIndex) baked_index); -		if (hash_id.notNull()) -		{ -			num_queries++; -			// *NOTE: make sure at least one request gets packed - -			ETextureIndex te_index = LLAvatarAppearanceDictionary::bakedToLocalTextureIndex((EBakedTextureIndex)baked_index); - -			//LL_INFOS() << "Requesting texture for hash " << hash << " in baked texture slot " << baked_index << LL_ENDL; -			gMessageSystem->nextBlockFast(_PREHASH_WearableData); -			gMessageSystem->addUUIDFast(_PREHASH_ID, hash_id); -			gMessageSystem->addU8Fast(_PREHASH_TextureIndex, (U8)te_index); -		} - -		gAgentQueryManager.mActiveCacheQueries[baked_index] = gAgentQueryManager.mWearablesCacheQueryID; -	} -	//VWR-22113: gAgent.getRegion() can return null if invalid, seen here on logout -	if(gAgent.getRegion()) -	{ -		if (isAgentAvatarValid()) -		{ -			selfStartPhase("fetch_texture_cache_entries"); -			gAgentAvatarp->outputRezTiming("Fetching textures from cache"); -		} - -		LL_DEBUGS("Avatar") << gAgentAvatarp->avString() << "Requesting texture cache entry for " << num_queries << " baked textures" << LL_ENDL; -		gMessageSystem->sendReliable(gAgent.getRegion()->getHost()); -		gAgentQueryManager.mNumPendingQueries++; -		gAgentQueryManager.mWearablesCacheQueryID++; -	} -} - -// virtual -void LLAgentWearables::invalidateBakedTextureHash(LLMD5& hash) const -{ -	// Add some garbage into the hash so that it becomes invalid. -	if (isAgentAvatarValid()) -	{ -		hash.update((const unsigned char*)gAgentAvatarp->getID().mData, UUID_BYTES); -	}  }  // User has picked "remove from avatar" from a menu. @@ -1687,17 +1369,6 @@ void LLAgentWearables::userAttachMultipleAttachments(LLInventoryModel::item_arra  	}  } -void LLAgentWearables::checkWearablesLoaded() const -{ -#ifdef SHOW_ASSERT -	U32 item_pend_count = itemUpdatePendingCount(); -	if (mWearablesLoaded) -	{ -		llassert(item_pend_count==0); -	} -#endif -} -  // Returns false if the given wearable is already topmost/bottommost  // (depending on closer_to_body parameter).  bool LLAgentWearables::canMoveWearable(const LLUUID& item_id, bool closer_to_body) const @@ -1714,20 +1385,9 @@ bool LLAgentWearables::canMoveWearable(const LLUUID& item_id, bool closer_to_bod  BOOL LLAgentWearables::areWearablesLoaded() const  { -	checkWearablesLoaded();  	return mWearablesLoaded;  } -// MULTI-WEARABLE: DEPRECATED: item pending count relies on old messages that don't support multi-wearables. do not trust to be accurate -void LLAgentWearables::updateWearablesLoaded() -{ -	mWearablesLoaded = (itemUpdatePendingCount()==0); -	if (mWearablesLoaded) -	{ -		notifyLoadingFinished(); -	} -} -  bool LLAgentWearables::canWearableBeRemoved(const LLViewerWearable* wearable) const  {  	if (!wearable) return false; @@ -1737,7 +1397,7 @@ bool LLAgentWearables::canWearableBeRemoved(const LLViewerWearable* wearable) co  	return !(((type == LLWearableType::WT_SHAPE) || (type == LLWearableType::WT_SKIN) || (type == LLWearableType::WT_HAIR) || (type == LLWearableType::WT_EYES))  			 && (getWearableCount(type) <= 1) );		    } -void LLAgentWearables::animateAllWearableParams(F32 delta, BOOL upload_bake) +void LLAgentWearables::animateAllWearableParams(F32 delta)  {  	for( S32 type = 0; type < LLWearableType::WT_COUNT; ++type )  	{ @@ -1747,7 +1407,7 @@ void LLAgentWearables::animateAllWearableParams(F32 delta, BOOL upload_bake)  			llassert(wearable);  			if (wearable)  			{ -				wearable->animateParams(delta, upload_bake); +				wearable->animateParams(delta);  			}  		}  	} @@ -1870,30 +1530,6 @@ void LLAgentWearables::editWearableIfRequested(const LLUUID& item_id)  	}  } -void LLAgentWearables::updateServer() -{ -	sendAgentWearablesUpdate(); -	gAgent.sendAgentSetAppearance(); -} - -void LLAgentWearables::populateMyOutfitsFolder(void) -{	 -	LL_INFOS() << "starting outfit population" << LL_ENDL; - -	const LLUUID& my_outfits_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); -	LLLibraryOutfitsFetch* outfits = new LLLibraryOutfitsFetch(my_outfits_id); -	outfits->mMyOutfitsID = my_outfits_id; -	 -	// Get the complete information on the items in the inventory and  -	// setup an observer that will wait for that to happen. -	gInventory.addObserver(outfits); -	outfits->startFetch(); -	if (outfits->isFinished()) -	{ -		outfits->done(); -	} -} -  boost::signals2::connection LLAgentWearables::addLoadingStartedCallback(loading_started_callback_t cb)  {  	return mLoadingStartedSignal.connect(cb); @@ -1912,6 +1548,7 @@ bool LLAgentWearables::changeInProgress() const  void LLAgentWearables::notifyLoadingStarted()  {  	mCOFChangeInProgress = true; +	mCOFChangeTimer.reset();  	mLoadingStartedSignal();  } diff --git a/indra/newview/llagentwearables.h b/indra/newview/llagentwearables.h index 02d24892b5..cdb1bdbe05 100755 --- a/indra/newview/llagentwearables.h +++ b/indra/newview/llagentwearables.h @@ -42,7 +42,6 @@  class LLInventoryItem;  class LLVOAvatarSelf;  class LLViewerWearable; -class LLInitialWearablesFetch;  class LLViewerObject;  class LLAgentWearables : public LLInitClass<LLAgentWearables>, public LLWearableData @@ -51,7 +50,6 @@ class LLAgentWearables : public LLInitClass<LLAgentWearables>, public LLWearable  	// Constructors / destructors / Initializers  	//--------------------------------------------------------------------  public: -	friend class LLInitialWearablesFetch;  	LLAgentWearables();  	virtual ~LLAgentWearables(); @@ -62,9 +60,6 @@ public:  	// LLInitClass interface  	static void initClass(); -protected: -	void			createStandardWearablesDone(S32 type, U32 index/* = 0*/); -	void			createStandardWearablesAllDone();  	//--------------------------------------------------------------------  	// Queries @@ -77,6 +72,7 @@ public:  	BOOL			isWearableCopyable(LLWearableType::EType type, U32 index /*= 0*/) const;  	BOOL			areWearablesLoaded() const;  	bool			isCOFChangeInProgress() const { return mCOFChangeInProgress; } +	F32				getCOFChangeTime() const { return mCOFChangeTimer.getElapsedTimeF32(); }  	void			updateWearablesLoaded();  	void			checkWearablesLoaded() const;  	bool			canMoveWearable(const LLUUID& item_id, bool closer_to_body) const; @@ -84,7 +80,7 @@ public:  	// Note: False for shape, skin, eyes, and hair, unless you have MORE than 1.  	bool			canWearableBeRemoved(const LLViewerWearable* wearable) const; -	void			animateAllWearableParams(F32 delta, BOOL upload_bake); +	void			animateAllWearableParams(F32 delta);  	//--------------------------------------------------------------------  	// Accessors @@ -107,7 +103,7 @@ private:  	/*virtual*/void	wearableUpdated(LLWearable *wearable, BOOL removed);  public:  	void			setWearableItem(LLInventoryItem* new_item, LLViewerWearable* wearable, bool do_append = false); -	void			setWearableOutfit(const LLInventoryItem::item_array_t& items, const std::vector< LLViewerWearable* >& wearables, BOOL remove); +	void			setWearableOutfit(const LLInventoryItem::item_array_t& items, const std::vector< LLViewerWearable* >& wearables);  	void			setWearableName(const LLUUID& item_id, const std::string& new_name);  	// *TODO: Move this into llappearance/LLWearableData ?  	void			addLocalTextureObject(const LLWearableType::EType wearable_type, const LLAvatarAppearanceDefines::ETextureIndex texture_type, U32 wearable_index); @@ -151,31 +147,10 @@ private:  	void			removeWearableFinal(const LLWearableType::EType type, bool do_remove_all /*= false*/, U32 index /*= 0*/);  protected:  	static bool		onRemoveWearableDialog(const LLSD& notification, const LLSD& response); -	 -	//-------------------------------------------------------------------- -	// Server Communication -	//-------------------------------------------------------------------- -public: -	// Processes the initial wearables update message (if necessary, since the outfit folder makes it redundant) -	static void		processAgentInitialWearablesUpdate(LLMessageSystem* mesgsys, void** user_data); - -protected: -	/*virtual*/ void	invalidateBakedTextureHash(LLMD5& hash) const; -	void			sendAgentWearablesUpdate(); -	void			sendAgentWearablesRequest(); -	void			queryWearableCache(); -	void 			updateServer(); -	static void		onInitialWearableAssetArrived(LLViewerWearable* wearable, void* userdata);  	//--------------------------------------------------------------------  	// Outfits  	//-------------------------------------------------------------------- -public: -	 -	// Should only be called if we *know* we've never done so before, since users may -	// not want the Library outfits to stay in their quick outfit selector and can delete them. -	void			populateMyOutfitsFolder(); -  private:  	void			makeNewOutfitDone(S32 type, U32 index);  @@ -184,11 +159,16 @@ private:  	//--------------------------------------------------------------------  public:	  	void			saveWearableAs(const LLWearableType::EType type, const U32 index, const std::string& new_name, const std::string& description, BOOL save_in_lost_and_found); -	void			saveWearable(const LLWearableType::EType type, const U32 index, BOOL send_update = TRUE, +	void			saveWearable(const LLWearableType::EType type, const U32 index,  								 const std::string new_name = "");  	void			saveAllWearables();  	void			revertWearable(const LLWearableType::EType type, const U32 index); +	// We no longer need this message in the current viewer, but send +	// it for now to maintain compatibility with release viewers. Can +	// remove this function once the SH-3455 changesets are universally deployed. +	void			sendDummyAgentWearablesUpdate(); +  	//--------------------------------------------------------------------  	// Static UI hooks  	//-------------------------------------------------------------------- @@ -202,9 +182,6 @@ public:  	static void		userRemoveMultipleAttachments(llvo_vec_t& llvo_array);  	static void		userAttachMultipleAttachments(LLInventoryModel::item_array_t& obj_item_array); -	BOOL			itemUpdatePending(const LLUUID& item_id) const; -	U32				itemUpdatePendingCount() const; -  	//--------------------------------------------------------------------  	// Signals  	//-------------------------------------------------------------------- @@ -231,29 +208,18 @@ private:  private:  	static BOOL		mInitialWearablesUpdateReceived;  	BOOL			mWearablesLoaded; -	std::set<LLUUID>	mItemsAwaitingWearableUpdate;  	/**  	 * True if agent's outfit is being changed now.  	 */  	BOOL			mCOFChangeInProgress; +	LLTimer			mCOFChangeTimer;  	//--------------------------------------------------------------------------------  	// Support classes  	//--------------------------------------------------------------------------------  private: -	class createStandardWearablesAllDoneCallback : public LLRefCount -	{ -	protected: -		~createStandardWearablesAllDoneCallback(); -	}; -	class sendAgentWearablesUpdateCallback : public LLRefCount -	{ -	protected: -		~sendAgentWearablesUpdateCallback(); -	}; - -	class addWearableToAgentInventoryCallback : public LLInventoryCallback +	class AddWearableToAgentInventoryCallback : public LLInventoryCallback  	{  	public:  		enum ETodo @@ -266,7 +232,7 @@ private:  			CALL_WEARITEM = 16  		}; -		addWearableToAgentInventoryCallback(LLPointer<LLRefCount> cb, +		AddWearableToAgentInventoryCallback(LLPointer<LLRefCount> cb,  											LLWearableType::EType type,  											U32 index,  											LLViewerWearable* wearable, diff --git a/indra/newview/llagentwearablesfetch.cpp b/indra/newview/llagentwearablesfetch.cpp deleted file mode 100755 index af0f02861d..0000000000 --- a/indra/newview/llagentwearablesfetch.cpp +++ /dev/null @@ -1,600 +0,0 @@ -/**  - * @file llagentwearablesfetch.cpp - * @brief LLAgentWearblesFetch class implementation - * - * $LicenseInfo:firstyear=2001&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 "llagentwearablesfetch.h" - -#include "llagent.h" -#include "llagentwearables.h" -#include "llappearancemgr.h" -#include "llinventoryfunctions.h" -#include "llstartup.h" -#include "llvoavatarself.h" - - -void order_my_outfits_cb() -	{ -		if (!LLApp::isRunning()) -		{ -			LL_WARNS() << "called during shutdown, skipping" << LL_ENDL; -			return; -		} -		 -		const LLUUID& my_outfits_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); -		if (my_outfits_id.isNull()) return; - -		LLInventoryModel::cat_array_t* cats; -		LLInventoryModel::item_array_t* items; -		gInventory.getDirectDescendentsOf(my_outfits_id, cats, items); -		if (!cats) return; - -		//My Outfits should at least contain saved initial outfit and one another outfit -		if (cats->size() < 2) -		{ -			LL_WARNS() << "My Outfits category was not populated properly" << LL_ENDL; -			return; -		} - -		LL_INFOS() << "Starting updating My Outfits with wearables ordering information" << LL_ENDL; - -		for (LLInventoryModel::cat_array_t::iterator outfit_iter = cats->begin(); -			outfit_iter != cats->end(); ++outfit_iter) -		{ -			const LLUUID& cat_id = (*outfit_iter)->getUUID(); -			if (cat_id.isNull()) continue; - -			// saved initial outfit already contains wearables ordering information -			if (cat_id == LLAppearanceMgr::getInstance()->getBaseOutfitUUID()) continue; - -			LLAppearanceMgr::getInstance()->updateClothingOrderingInfo(cat_id); -		} - -		LL_INFOS() << "Finished updating My Outfits with wearables ordering information" << LL_ENDL; -	} - -LLInitialWearablesFetch::LLInitialWearablesFetch(const LLUUID& cof_id) : -	LLInventoryFetchDescendentsObserver(cof_id) -{ -	if (isAgentAvatarValid()) -	{ -		gAgentAvatarp->startPhase("initial_wearables_fetch"); -		gAgentAvatarp->outputRezTiming("Initial wearables fetch started"); -	} -} - -LLInitialWearablesFetch::~LLInitialWearablesFetch() -{ -} - -// virtual -void LLInitialWearablesFetch::done() -{ -	// Delay processing the actual results of this so it's not handled within -	// gInventory.notifyObservers.  The results will be handled in the next -	// idle tick instead. -	gInventory.removeObserver(this); -	doOnIdleOneTime(boost::bind(&LLInitialWearablesFetch::processContents,this)); -	if (isAgentAvatarValid()) -	{ -		gAgentAvatarp->stopPhase("initial_wearables_fetch"); -		gAgentAvatarp->outputRezTiming("Initial wearables fetch done"); -	} -} - -void LLInitialWearablesFetch::add(InitialWearableData &data) - -{ -	mAgentInitialWearables.push_back(data); -} - -void LLInitialWearablesFetch::processContents() -{ -	if(!gAgentAvatarp) //no need to process wearables if the agent avatar is deleted. -	{ -		delete this; -		return ; -	} - -	// Fetch the wearable items from the Current Outfit Folder -	LLInventoryModel::cat_array_t cat_array; -	LLInventoryModel::item_array_t wearable_array; -	LLFindWearables is_wearable; -	llassert_always(mComplete.size() != 0); -	gInventory.collectDescendentsIf(mComplete.front(), cat_array, wearable_array,  -									LLInventoryModel::EXCLUDE_TRASH, is_wearable); - -	LLAppearanceMgr::instance().setAttachmentInvLinkEnable(true); -	if (wearable_array.size() > 0) -	{ -		gAgentWearables.notifyLoadingStarted(); -		LLAppearanceMgr::instance().updateAppearanceFromCOF(); -	} -	else -	{ -		// if we're constructing the COF from the wearables message, we don't have a proper outfit link -		LLAppearanceMgr::instance().setOutfitDirty(true); -		processWearablesMessage(); -	} -	delete this; -} - -class LLFetchAndLinkObserver: public LLInventoryFetchItemsObserver -{ -public: -	LLFetchAndLinkObserver(uuid_vec_t& ids): -		LLInventoryFetchItemsObserver(ids) -	{ -	} -	~LLFetchAndLinkObserver() -	{ -	} -	virtual void done() -	{ -		gInventory.removeObserver(this); - -		// Link to all fetched items in COF. -		LLPointer<LLInventoryCallback> link_waiter = new LLUpdateAppearanceOnDestroy; -		for (uuid_vec_t::iterator it = mIDs.begin(); -			 it != mIDs.end(); -			 ++it) -		{ -			LLUUID id = *it; -			LLViewerInventoryItem *item = gInventory.getItem(*it); -			if (!item) -			{ -				LL_WARNS() << "fetch failed!" << LL_ENDL; -				continue; -			} - -			link_inventory_item(gAgent.getID(), -								item->getLinkedUUID(), -								LLAppearanceMgr::instance().getCOF(), -								item->getName(), -								item->getDescription(), -								LLAssetType::AT_LINK, -								link_waiter); -		} -	} -}; - -void LLInitialWearablesFetch::processWearablesMessage() -{ -	if (!mAgentInitialWearables.empty()) // We have an empty current outfit folder, use the message data instead. -	{ -		const LLUUID current_outfit_id = LLAppearanceMgr::instance().getCOF(); -		uuid_vec_t ids; -		for (U8 i = 0; i < mAgentInitialWearables.size(); ++i) -		{ -			// Populate the current outfit folder with links to the wearables passed in the message -			InitialWearableData *wearable_data = new InitialWearableData(mAgentInitialWearables[i]); // This will be deleted in the callback. -			 -			if (wearable_data->mAssetID.notNull()) -			{ -				ids.push_back(wearable_data->mItemID); -			} -			else -			{ -				LL_INFOS() << "Invalid wearable, type " << wearable_data->mType << " itemID " -				<< wearable_data->mItemID << " assetID " << wearable_data->mAssetID << LL_ENDL; -				delete wearable_data; -			} -		} - -		// Add all current attachments to the requested items as well. -		if (isAgentAvatarValid()) -		{ -			for (LLVOAvatar::attachment_map_t::const_iterator iter = gAgentAvatarp->mAttachmentPoints.begin();  -				 iter != gAgentAvatarp->mAttachmentPoints.end(); ++iter) -			{ -				LLViewerJointAttachment* attachment = iter->second; -				if (!attachment) continue; -				for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); -					 attachment_iter != attachment->mAttachedObjects.end(); -					 ++attachment_iter) -				{ -					LLViewerObject* attached_object = (*attachment_iter); -					if (!attached_object) continue; -					const LLUUID& item_id = attached_object->getAttachmentItemID(); -					if (item_id.isNull()) continue; -					ids.push_back(item_id); -				} -			} -		} - -		// Need to fetch the inventory items for ids, then create links to them after they arrive. -		LLFetchAndLinkObserver *fetcher = new LLFetchAndLinkObserver(ids); -		fetcher->startFetch(); -		// If no items to be fetched, done will never be triggered. -		// TODO: Change LLInventoryFetchItemsObserver::fetchItems to trigger done() on this condition. -		if (fetcher->isFinished()) -		{ -			fetcher->done(); -		} -		else -		{ -			gInventory.addObserver(fetcher); -		} -	} -	else -	{ -		LL_WARNS("Wearables") << "No current outfit folder items found and no initial wearables fallback message received." << LL_ENDL; -	} -} - -LLLibraryOutfitsFetch::LLLibraryOutfitsFetch(const LLUUID& my_outfits_id) :  -	LLInventoryFetchDescendentsObserver(my_outfits_id), -	mCurrFetchStep(LOFS_FOLDER),  -	mOutfitsPopulated(false)  -{ -	LL_INFOS() << "created" << LL_ENDL; - -	mMyOutfitsID = LLUUID::null; -	mClothingID = LLUUID::null; -	mLibraryClothingID = LLUUID::null; -	mImportedClothingID = LLUUID::null; -	mImportedClothingName = "Imported Library Clothing"; -} - -LLLibraryOutfitsFetch::~LLLibraryOutfitsFetch() -{ -	LL_INFOS() << "destroyed" << LL_ENDL; -} - -void LLLibraryOutfitsFetch::done() -{ -	LL_INFOS() << "start" << LL_ENDL; - -	// Delay this until idle() routine, since it's a heavy operation and -	// we also can't have it run within notifyObservers. -	doOnIdleOneTime(boost::bind(&LLLibraryOutfitsFetch::doneIdle,this)); -	gInventory.removeObserver(this); // Prevent doOnIdleOneTime from being added twice. -} - -void LLLibraryOutfitsFetch::doneIdle() -{ -	LL_INFOS() << "start" << LL_ENDL; - -	gInventory.addObserver(this); // Add this back in since it was taken out during ::done() -	 -	switch (mCurrFetchStep) -	{ -		case LOFS_FOLDER: -			folderDone(); -			mCurrFetchStep = LOFS_OUTFITS; -			break; -		case LOFS_OUTFITS: -			outfitsDone(); -			mCurrFetchStep = LOFS_LIBRARY; -			break; -		case LOFS_LIBRARY: -			libraryDone(); -			mCurrFetchStep = LOFS_IMPORTED; -			break; -		case LOFS_IMPORTED: -			importedFolderDone(); -			mCurrFetchStep = LOFS_CONTENTS; -			break; -		case LOFS_CONTENTS: -			contentsDone(); -			break; -		default: -			LL_WARNS() << "Got invalid state for outfit fetch: " << mCurrFetchStep << LL_ENDL; -			mOutfitsPopulated = TRUE; -			break; -	} - -	// We're completely done.  Cleanup. -	if (mOutfitsPopulated) -	{ -		gInventory.removeObserver(this); -		delete this; -		return; -	} -} - -void LLLibraryOutfitsFetch::folderDone() -{ -	LL_INFOS() << "start" << LL_ENDL; - -	LLInventoryModel::cat_array_t cat_array; -	LLInventoryModel::item_array_t wearable_array; -	gInventory.collectDescendents(mMyOutfitsID, cat_array, wearable_array,  -								  LLInventoryModel::EXCLUDE_TRASH); -	 -	// Early out if we already have items in My Outfits -	// except the case when My Outfits contains just initial outfit -	if (cat_array.size() > 1) -	{ -		mOutfitsPopulated = true; -		return; -	} - -	mClothingID = gInventory.findCategoryUUIDForType(LLFolderType::FT_CLOTHING); -	mLibraryClothingID = gInventory.findLibraryCategoryUUIDForType(LLFolderType::FT_CLOTHING, false); - -	// If Library->Clothing->Initial Outfits exists, use that. -	LLNameCategoryCollector matchFolderFunctor("Initial Outfits"); -	cat_array.clear(); -	gInventory.collectDescendentsIf(mLibraryClothingID, -									cat_array, wearable_array,  -									LLInventoryModel::EXCLUDE_TRASH, -									matchFolderFunctor); -	if (cat_array.size() > 0) -	{ -		const LLViewerInventoryCategory *cat = cat_array.at(0); -		mLibraryClothingID = cat->getUUID(); -	} - -	mComplete.clear(); -	 -	// Get the complete information on the items in the inventory. -	uuid_vec_t folders; -	folders.push_back(mClothingID); -	folders.push_back(mLibraryClothingID); -	setFetchIDs(folders); -	startFetch(); -	if (isFinished()) -	{ -		done(); -	} -} - -void LLLibraryOutfitsFetch::outfitsDone() -{ -	LL_INFOS() << "start" << LL_ENDL; - -	LLInventoryModel::cat_array_t cat_array; -	LLInventoryModel::item_array_t wearable_array; -	uuid_vec_t folders; -	 -	// Collect the contents of the Library's Clothing folder -	gInventory.collectDescendents(mLibraryClothingID, cat_array, wearable_array,  -								  LLInventoryModel::EXCLUDE_TRASH); -	 -	llassert(cat_array.size() > 0); -	for (LLInventoryModel::cat_array_t::const_iterator iter = cat_array.begin(); -		 iter != cat_array.end(); -		 ++iter) -	{ -		const LLViewerInventoryCategory *cat = iter->get(); -		 -		// Get the names and id's of every outfit in the library, skip "Ruth" -		// because it's a low quality legacy outfit -		if (cat->getName() != "Ruth") -		{ -			// Get the name of every outfit in the library  -			folders.push_back(cat->getUUID()); -			mLibraryClothingFolders.push_back(cat->getUUID()); -		} -	} -	cat_array.clear(); -	wearable_array.clear(); - -	// Check if you already have an "Imported Library Clothing" folder -	LLNameCategoryCollector matchFolderFunctor(mImportedClothingName); -	gInventory.collectDescendentsIf(mClothingID,  -									cat_array, wearable_array,  -									LLInventoryModel::EXCLUDE_TRASH, -									matchFolderFunctor); -	if (cat_array.size() > 0) -	{ -		const LLViewerInventoryCategory *cat = cat_array.at(0); -		mImportedClothingID = cat->getUUID(); -	} -	 -	mComplete.clear(); -	setFetchIDs(folders); -	startFetch(); -	if (isFinished()) -	{ -		done(); -	} -} - -class LLLibraryOutfitsCopyDone: public LLInventoryCallback -{ -public: -	LLLibraryOutfitsCopyDone(LLLibraryOutfitsFetch * fetcher): -	mFireCount(0), mLibraryOutfitsFetcher(fetcher) -	{ -	} -	 -	virtual ~LLLibraryOutfitsCopyDone() -	{ -		if (!LLApp::isExiting() && mLibraryOutfitsFetcher) -		{ -			gInventory.addObserver(mLibraryOutfitsFetcher); -			mLibraryOutfitsFetcher->done(); -		} -	} -	 -	/* virtual */ void fire(const LLUUID& inv_item) -	{ -		mFireCount++; -	} -private: -	U32 mFireCount; -	LLLibraryOutfitsFetch * mLibraryOutfitsFetcher; -}; - -// Copy the clothing folders from the library into the imported clothing folder -void LLLibraryOutfitsFetch::libraryDone() -{ -	LL_INFOS() << "start" << LL_ENDL; - -	if (mImportedClothingID != LLUUID::null) -	{ -		// Skip straight to fetching the contents of the imported folder -		importedFolderFetch(); -		return; -	} - -	// Remove observer; next autopopulation step will be triggered externally by LLLibraryOutfitsCopyDone. -	gInventory.removeObserver(this); -	 -	LLPointer<LLInventoryCallback> copy_waiter = new LLLibraryOutfitsCopyDone(this); -	mImportedClothingID = gInventory.createNewCategory(mClothingID, -													   LLFolderType::FT_NONE, -													   mImportedClothingName); -	// Copy each folder from library into clothing unless it already exists. -	for (uuid_vec_t::const_iterator iter = mLibraryClothingFolders.begin(); -		 iter != mLibraryClothingFolders.end(); -		 ++iter) -	{ -		const LLUUID& src_folder_id = (*iter); // Library clothing folder ID -		const LLViewerInventoryCategory *cat = gInventory.getCategory(src_folder_id); -		if (!cat) -		{ -			LL_WARNS() << "Library folder import for uuid:" << src_folder_id << " failed to find folder." << LL_ENDL; -			continue; -		} -		 -		if (!LLAppearanceMgr::getInstance()->getCanMakeFolderIntoOutfit(src_folder_id)) -		{ -			LL_INFOS() << "Skipping non-outfit folder name:" << cat->getName() << LL_ENDL; -			continue; -		} -		 -		// Don't copy the category if it already exists. -		LLNameCategoryCollector matchFolderFunctor(cat->getName()); -		LLInventoryModel::cat_array_t cat_array; -		LLInventoryModel::item_array_t wearable_array; -		gInventory.collectDescendentsIf(mImportedClothingID,  -										cat_array, wearable_array,  -										LLInventoryModel::EXCLUDE_TRASH, -										matchFolderFunctor); -		if (cat_array.size() > 0) -		{ -			continue; -		} - -		LLUUID dst_folder_id = gInventory.createNewCategory(mImportedClothingID, -															LLFolderType::FT_NONE, -															cat->getName()); -		LLAppearanceMgr::getInstance()->shallowCopyCategoryContents(src_folder_id, dst_folder_id, copy_waiter); -	} -} - -void LLLibraryOutfitsFetch::importedFolderFetch() -{ -	LL_INFOS() << "start" << LL_ENDL; - -	// Fetch the contents of the Imported Clothing Folder -	uuid_vec_t folders; -	folders.push_back(mImportedClothingID); -	 -	mComplete.clear(); -	setFetchIDs(folders); -	startFetch(); -	if (isFinished()) -	{ -		done(); -	} -} - -void LLLibraryOutfitsFetch::importedFolderDone() -{ -	LL_INFOS() << "start" << LL_ENDL; - -	LLInventoryModel::cat_array_t cat_array; -	LLInventoryModel::item_array_t wearable_array; -	uuid_vec_t folders; -	 -	// Collect the contents of the Imported Clothing folder -	gInventory.collectDescendents(mImportedClothingID, cat_array, wearable_array,  -								  LLInventoryModel::EXCLUDE_TRASH); -	 -	for (LLInventoryModel::cat_array_t::const_iterator iter = cat_array.begin(); -		 iter != cat_array.end(); -		 ++iter) -	{ -		const LLViewerInventoryCategory *cat = iter->get(); -		 -		// Get the name of every imported outfit -		folders.push_back(cat->getUUID()); -		mImportedClothingFolders.push_back(cat->getUUID()); -	} -	 -	mComplete.clear(); -	setFetchIDs(folders); -	startFetch(); -	if (isFinished()) -	{ -		done(); -	} -} - -void LLLibraryOutfitsFetch::contentsDone() -{		 -	LL_INFOS() << "start" << LL_ENDL; - -	LLInventoryModel::cat_array_t cat_array; -	LLInventoryModel::item_array_t wearable_array; -	 -	LLPointer<LLInventoryCallback> order_myoutfits_on_destroy = new LLBoostFuncInventoryCallback(no_op_inventory_func, order_my_outfits_cb); - -	for (uuid_vec_t::const_iterator folder_iter = mImportedClothingFolders.begin(); -		 folder_iter != mImportedClothingFolders.end(); -		 ++folder_iter) -	{ -		const LLUUID &folder_id = (*folder_iter); -		const LLViewerInventoryCategory *cat = gInventory.getCategory(folder_id); -		if (!cat) -		{ -			LL_WARNS() << "Library folder import for uuid:" << folder_id << " failed to find folder." << LL_ENDL; -			continue; -		} - -		//initial outfit should be already in My Outfits -		if (cat->getName() == LLStartUp::getInitialOutfitName()) continue; -		 -		// First, make a folder in the My Outfits directory. -		LLUUID new_outfit_folder_id = gInventory.createNewCategory(mMyOutfitsID, LLFolderType::FT_OUTFIT, cat->getName()); -		 -		cat_array.clear(); -		wearable_array.clear(); -		// Collect the contents of each imported clothing folder, so we can create new outfit links for it -		gInventory.collectDescendents(folder_id, cat_array, wearable_array,  -									  LLInventoryModel::EXCLUDE_TRASH); -		 -		for (LLInventoryModel::item_array_t::const_iterator wearable_iter = wearable_array.begin(); -			 wearable_iter != wearable_array.end(); -			 ++wearable_iter) -		{ -			const LLViewerInventoryItem *item = wearable_iter->get(); -			link_inventory_item(gAgent.getID(), -								item->getLinkedUUID(), -								new_outfit_folder_id, -								item->getName(), -								item->getDescription(), -								LLAssetType::AT_LINK, -								order_myoutfits_on_destroy); -		} -	} - -	mOutfitsPopulated = true; -} - diff --git a/indra/newview/llagentwearablesfetch.h b/indra/newview/llagentwearablesfetch.h deleted file mode 100755 index bedc445c0e..0000000000 --- a/indra/newview/llagentwearablesfetch.h +++ /dev/null @@ -1,114 +0,0 @@ -/**  - * @file llagentwearablesinitialfetch.h - * @brief LLAgentWearablesInitialFetch class header file - * - * $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$ - */ - -#ifndef LL_LLAGENTWEARABLESINITIALFETCH_H -#define LL_LLAGENTWEARABLESINITIALFETCH_H - -#include "llinventoryobserver.h" -#include "llwearabletype.h" -#include "lluuid.h" - -//-------------------------------------------------------------------- -// InitialWearablesFetch -//  -// This grabs contents from the COF and processes them. -// The processing is handled in idle(), i.e. outside of done(), -// to avoid gInventory.notifyObservers recursion. -//-------------------------------------------------------------------- -class LLInitialWearablesFetch : public LLInventoryFetchDescendentsObserver -{ -	LOG_CLASS(LLInitialWearablesFetch); - -public: -	LLInitialWearablesFetch(const LLUUID& cof_id); -	~LLInitialWearablesFetch(); -	virtual void done(); - -	struct InitialWearableData -	{ -		LLWearableType::EType mType; -		LLUUID mItemID; -		LLUUID mAssetID; -		InitialWearableData(LLWearableType::EType type, LLUUID& itemID, LLUUID& assetID) : -			mType(type), -			mItemID(itemID), -			mAssetID(assetID) -		{} -	}; - -	void add(InitialWearableData &data); - -protected: -	void processWearablesMessage(); -	void processContents(); - -private: -	typedef std::vector<InitialWearableData> initial_wearable_data_vec_t; -	initial_wearable_data_vec_t mAgentInitialWearables; // Wearables from the old agent wearables msg -}; - -//-------------------------------------------------------------------- -// InitialWearablesFetch -//  -// This grabs outfits from the Library and copies those over to the user's -// outfits folder, typically during first-ever login. -//-------------------------------------------------------------------- -class LLLibraryOutfitsFetch : public LLInventoryFetchDescendentsObserver -{ -public: -	enum ELibraryOutfitFetchStep -	{ -		LOFS_FOLDER = 0, -		LOFS_OUTFITS, -		LOFS_LIBRARY, -		LOFS_IMPORTED, -		LOFS_CONTENTS -	}; - -	LLLibraryOutfitsFetch(const LLUUID& my_outfits_id); -	~LLLibraryOutfitsFetch(); - -	virtual void done(); -	void doneIdle(); -	LLUUID mMyOutfitsID; -	void importedFolderFetch(); -protected: -	void folderDone(); -	void outfitsDone(); -	void libraryDone(); -	void importedFolderDone(); -	void contentsDone(); -	enum ELibraryOutfitFetchStep mCurrFetchStep; -	uuid_vec_t mLibraryClothingFolders; -	uuid_vec_t mImportedClothingFolders; -	bool mOutfitsPopulated; -	LLUUID mClothingID; -	LLUUID mLibraryClothingID; -	LLUUID mImportedClothingID; -	std::string mImportedClothingName; -}; - -#endif // LL_AGENTWEARABLESINITIALFETCH_H diff --git a/indra/newview/llaisapi.cpp b/indra/newview/llaisapi.cpp new file mode 100755 index 0000000000..da66ea357a --- /dev/null +++ b/indra/newview/llaisapi.cpp @@ -0,0 +1,867 @@ +/**  + * @file llaisapi.cpp + * @brief classes and functions for interfacing with the v3+ ais inventory service.  + * + * $LicenseInfo:firstyear=2013&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2013, Linden Research, Inc. + *  + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + *  + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + *  + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + *  + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA + * $/LicenseInfo$ + * + */ + +#include "llviewerprecompiledheaders.h" +#include "llaisapi.h" + +#include "llagent.h" +#include "llcallbacklist.h" +#include "llinventorymodel.h" +#include "llsdutil.h" +#include "llviewerregion.h" +#include "llinventoryobserver.h" + +///---------------------------------------------------------------------------- +/// Classes for AISv3 support. +///---------------------------------------------------------------------------- + +// AISCommand - base class for retry-able HTTP requests using the AISv3 cap. +AISCommand::AISCommand(LLPointer<LLInventoryCallback> callback): +	mCommandFunc(NULL), +	mCallback(callback) +{ +	mRetryPolicy = new LLAdaptiveRetryPolicy(1.0, 32.0, 2.0, 10); +} + +bool AISCommand::run_command() +{ +	if (NULL == mCommandFunc) +	{ +		// This may happen if a command failed to initiate itself. +		LL_WARNS("Inventory") << "AIS command attempted with null command function" << LL_ENDL; +		return false; +	} +	else +	{ +		mCommandFunc(); +		return true; +	} +} + +void AISCommand::setCommandFunc(command_func_type command_func) +{ +	mCommandFunc = command_func; +} +	 +// virtual +bool AISCommand::getResponseUUID(const LLSD& content, LLUUID& id) +{ +	return false; +} +	 +/* virtual */ +void AISCommand::httpSuccess() +{ +	// Command func holds a reference to self, need to release it +	// after a success or final failure. +	setCommandFunc(no_op); +		 +	const LLSD& content = getContent(); +	if (!content.isMap()) +	{ +		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); +		return; +	} +	mRetryPolicy->onSuccess(); +		 +	gInventory.onAISUpdateReceived("AISCommand", content); + +	if (mCallback) +	{ +		LLUUID id; // will default to null if parse fails. +		getResponseUUID(content,id); +		mCallback->fire(id); +	} +} + +/*virtual*/ +void AISCommand::httpFailure() +{ +	LL_WARNS("Inventory") << dumpResponse() << LL_ENDL; +	S32 status = getStatus(); +	const LLSD& headers = getResponseHeaders(); +	mRetryPolicy->onFailure(status, headers); +	F32 seconds_to_wait; +	if (mRetryPolicy->shouldRetry(seconds_to_wait)) +	{ +		doAfterInterval(boost::bind(&AISCommand::run_command,this),seconds_to_wait); +	} +	else +	{ +		// Command func holds a reference to self, need to release it +		// after a success or final failure. +		// *TODO: Notify user?  This seems bad. +		setCommandFunc(no_op); +	} +} + +//static +bool AISCommand::isAPIAvailable() +{ +	if (gAgent.getRegion()) +	{ +		return gAgent.getRegion()->isCapabilityAvailable("InventoryAPIv3"); +	} +	return false; +} + +//static +bool AISCommand::getInvCap(std::string& cap) +{ +	if (gAgent.getRegion()) +	{ +		cap = gAgent.getRegion()->getCapability("InventoryAPIv3"); +	} +	if (!cap.empty()) +	{ +		return true; +	} +	return false; +} + +//static +bool AISCommand::getLibCap(std::string& cap) +{ +	if (gAgent.getRegion()) +	{ +		cap = gAgent.getRegion()->getCapability("LibraryAPIv3"); +	} +	if (!cap.empty()) +	{ +		return true; +	} +	return false; +} + +//static +void AISCommand::getCapabilityNames(LLSD& capabilityNames) +{ +	capabilityNames.append("InventoryAPIv3"); +	capabilityNames.append("LibraryAPIv3"); +} + +RemoveItemCommand::RemoveItemCommand(const LLUUID& item_id, +									 LLPointer<LLInventoryCallback> callback): +	AISCommand(callback) +{ +	std::string cap; +	if (!getInvCap(cap)) +	{ +		LL_WARNS() << "No cap found" << LL_ENDL; +		return; +	} +	std::string url = cap + std::string("/item/") + item_id.asString(); +	LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL; +	LLHTTPClient::ResponderPtr responder = this; +	LLSD headers; +	F32 timeout = HTTP_REQUEST_EXPIRY_SECS; +	command_func_type cmd = boost::bind(&LLHTTPClient::del, url, responder, headers, timeout); +	setCommandFunc(cmd); +} + +RemoveCategoryCommand::RemoveCategoryCommand(const LLUUID& item_id, +											 LLPointer<LLInventoryCallback> callback): +	AISCommand(callback) +{ +	std::string cap; +	if (!getInvCap(cap)) +	{ +		LL_WARNS() << "No cap found" << LL_ENDL; +		return; +	} +	std::string url = cap + std::string("/category/") + item_id.asString(); +	LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL; +	LLHTTPClient::ResponderPtr responder = this; +	LLSD headers; +	F32 timeout = HTTP_REQUEST_EXPIRY_SECS; +	command_func_type cmd = boost::bind(&LLHTTPClient::del, url, responder, headers, timeout); +	setCommandFunc(cmd); +} + +PurgeDescendentsCommand::PurgeDescendentsCommand(const LLUUID& item_id, +												 LLPointer<LLInventoryCallback> callback): +	AISCommand(callback) +{ +	std::string cap; +	if (!getInvCap(cap)) +	{ +		LL_WARNS() << "No cap found" << LL_ENDL; +		return; +	} +	std::string url = cap + std::string("/category/") + item_id.asString() + "/children"; +	LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL; +	LLCurl::ResponderPtr responder = this; +	LLSD headers; +	F32 timeout = HTTP_REQUEST_EXPIRY_SECS; +	command_func_type cmd = boost::bind(&LLHTTPClient::del, url, responder, headers, timeout); +	setCommandFunc(cmd); +} + +UpdateItemCommand::UpdateItemCommand(const LLUUID& item_id, +									 const LLSD& updates, +									 LLPointer<LLInventoryCallback> callback): +	mUpdates(updates), +	AISCommand(callback) +{ +	std::string cap; +	if (!getInvCap(cap)) +	{ +		LL_WARNS() << "No cap found" << LL_ENDL; +		return; +	} +	std::string url = cap + std::string("/item/") + item_id.asString(); +	LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL; +	LL_DEBUGS("Inventory") << "request: " << ll_pretty_print_sd(mUpdates) << LL_ENDL; +	LLCurl::ResponderPtr responder = this; +	LLSD headers; +	headers["Content-Type"] = "application/llsd+xml"; +	F32 timeout = HTTP_REQUEST_EXPIRY_SECS; +	command_func_type cmd = boost::bind(&LLHTTPClient::patch, url, mUpdates, responder, headers, timeout); +	setCommandFunc(cmd); +} + +UpdateCategoryCommand::UpdateCategoryCommand(const LLUUID& cat_id, +											 const LLSD& updates, +											 LLPointer<LLInventoryCallback> callback): +	mUpdates(updates), +	AISCommand(callback) +{ +	std::string cap; +	if (!getInvCap(cap)) +	{ +		LL_WARNS() << "No cap found" << LL_ENDL; +		return; +	} +	std::string url = cap + std::string("/category/") + cat_id.asString(); +	LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL; +	LLCurl::ResponderPtr responder = this; +	LLSD headers; +	headers["Content-Type"] = "application/llsd+xml"; +	F32 timeout = HTTP_REQUEST_EXPIRY_SECS; +	command_func_type cmd = boost::bind(&LLHTTPClient::patch, url, mUpdates, responder, headers, timeout); +	setCommandFunc(cmd); +} + +CreateInventoryCommand::CreateInventoryCommand(const LLUUID& parent_id, +							 				   const LLSD& new_inventory, +							 				   LLPointer<LLInventoryCallback> callback): +	mNewInventory(new_inventory), +	AISCommand(callback) +{ +	std::string cap; +	if (!getInvCap(cap)) +	{ +		LL_WARNS() << "No cap found" << LL_ENDL; +		return; +	} +	LLUUID tid; +	tid.generate(); +	std::string url = cap + std::string("/category/") + parent_id.asString() + "?tid=" + tid.asString(); +	LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL; +	LLCurl::ResponderPtr responder = this; +	LLSD headers; +	headers["Content-Type"] = "application/llsd+xml"; +	F32 timeout = HTTP_REQUEST_EXPIRY_SECS; +	command_func_type cmd = boost::bind(&LLHTTPClient::post, url, mNewInventory, responder, headers, timeout); +	setCommandFunc(cmd); +} + +SlamFolderCommand::SlamFolderCommand(const LLUUID& folder_id, const LLSD& contents, LLPointer<LLInventoryCallback> callback): +	mContents(contents), +	AISCommand(callback) +{ +	std::string cap; +	if (!getInvCap(cap)) +	{ +		LL_WARNS() << "No cap found" << LL_ENDL; +		return; +	} +	LLUUID tid; +	tid.generate(); +	std::string url = cap + std::string("/category/") + folder_id.asString() + "/links?tid=" + tid.asString(); +	LL_INFOS() << url << LL_ENDL; +	LLCurl::ResponderPtr responder = this; +	LLSD headers; +	headers["Content-Type"] = "application/llsd+xml"; +	F32 timeout = HTTP_REQUEST_EXPIRY_SECS; +	command_func_type cmd = boost::bind(&LLHTTPClient::put, url, mContents, responder, headers, timeout); +	setCommandFunc(cmd); +} + +CopyLibraryCategoryCommand::CopyLibraryCategoryCommand(const LLUUID& source_id, +													   const LLUUID& dest_id, +													   LLPointer<LLInventoryCallback> callback): +	AISCommand(callback) +{ +	std::string cap; +	if (!getLibCap(cap)) +	{ +		LL_WARNS() << "No cap found" << LL_ENDL; +		return; +	} +	LL_DEBUGS("Inventory") << "Copying library category: " << source_id << " => " << dest_id << LL_ENDL; +	LLUUID tid; +	tid.generate(); +	std::string url = cap + std::string("/category/") + source_id.asString() + "?tid=" + tid.asString(); +	LL_INFOS() << url << LL_ENDL; +	LLCurl::ResponderPtr responder = this; +	LLSD headers; +	F32 timeout = HTTP_REQUEST_EXPIRY_SECS; +	command_func_type cmd = boost::bind(&LLHTTPClient::copy, url, dest_id.asString(), responder, headers, timeout); +	setCommandFunc(cmd); +} + +bool CopyLibraryCategoryCommand::getResponseUUID(const LLSD& content, LLUUID& id) +{ +	if (content.has("category_id")) +	{ +		id = content["category_id"]; +		return true; +	} +	return false; +} + +AISUpdate::AISUpdate(const LLSD& update) +{ +	parseUpdate(update); +} + +void AISUpdate::clearParseResults() +{ +	mCatDescendentDeltas.clear(); +	mCatDescendentsKnown.clear(); +	mCatVersionsUpdated.clear(); +	mItemsCreated.clear(); +	mItemsUpdated.clear(); +	mCategoriesCreated.clear(); +	mCategoriesUpdated.clear(); +	mObjectsDeletedIds.clear(); +	mItemIds.clear(); +	mCategoryIds.clear(); +} + +void AISUpdate::parseUpdate(const LLSD& update) +{ +	clearParseResults(); +	parseMeta(update); +	parseContent(update); +} + +void AISUpdate::parseMeta(const LLSD& update) +{ +	// parse _categories_removed -> mObjectsDeletedIds +	uuid_list_t cat_ids; +	parseUUIDArray(update,"_categories_removed",cat_ids); +	for (uuid_list_t::const_iterator it = cat_ids.begin(); +		 it != cat_ids.end(); ++it) +	{ +		LLViewerInventoryCategory *cat = gInventory.getCategory(*it); +		mCatDescendentDeltas[cat->getParentUUID()]--; +		mObjectsDeletedIds.insert(*it); +	} + +	// parse _categories_items_removed -> mObjectsDeletedIds +	uuid_list_t item_ids; +	parseUUIDArray(update,"_category_items_removed",item_ids); +	parseUUIDArray(update,"_removed_items",item_ids); +	for (uuid_list_t::const_iterator it = item_ids.begin(); +		 it != item_ids.end(); ++it) +	{ +		LLViewerInventoryItem *item = gInventory.getItem(*it); +		mCatDescendentDeltas[item->getParentUUID()]--; +		mObjectsDeletedIds.insert(*it); +	} + +	// parse _broken_links_removed -> mObjectsDeletedIds +	uuid_list_t broken_link_ids; +	parseUUIDArray(update,"_broken_links_removed",broken_link_ids); +	for (uuid_list_t::const_iterator it = broken_link_ids.begin(); +		 it != broken_link_ids.end(); ++it) +	{ +		LLViewerInventoryItem *item = gInventory.getItem(*it); +		mCatDescendentDeltas[item->getParentUUID()]--; +		mObjectsDeletedIds.insert(*it); +	} + +	// parse _created_items +	parseUUIDArray(update,"_created_items",mItemIds); + +	// parse _created_categories +	parseUUIDArray(update,"_created_categories",mCategoryIds); + +	// Parse updated category versions. +	const std::string& ucv = "_updated_category_versions"; +	if (update.has(ucv)) +	{ +		for(LLSD::map_const_iterator it = update[ucv].beginMap(), +				end = update[ucv].endMap(); +			it != end; ++it) +		{ +			const LLUUID id((*it).first); +			S32 version = (*it).second.asInteger(); +			mCatVersionsUpdated[id] = version; +		} +	} +} + +void AISUpdate::parseContent(const LLSD& update) +{ +	if (update.has("linked_id")) +	{ +		parseLink(update); +	} +	else if (update.has("item_id")) +	{ +		parseItem(update); +	} + +	if (update.has("category_id")) +	{ +		parseCategory(update); +	} +	else +	{ +		if (update.has("_embedded")) +		{ +			parseEmbedded(update["_embedded"]); +		} +	} +} + +void AISUpdate::parseItem(const LLSD& item_map) +{ +	LLUUID item_id = item_map["item_id"].asUUID(); +	LLPointer<LLViewerInventoryItem> new_item(new LLViewerInventoryItem); +	LLViewerInventoryItem *curr_item = gInventory.getItem(item_id); +	if (curr_item) +	{ +		// Default to current values where not provided. +		new_item->copyViewerItem(curr_item); +	} +	BOOL rv = new_item->unpackMessage(item_map); +	if (rv) +	{ +		if (curr_item) +		{ +			mItemsUpdated[item_id] = new_item; +			// This statement is here to cause a new entry with 0 +			// delta to be created if it does not already exist; +			// otherwise has no effect. +			mCatDescendentDeltas[new_item->getParentUUID()]; +		} +		else +		{ +			mItemsCreated[item_id] = new_item; +			mCatDescendentDeltas[new_item->getParentUUID()]++; +		} +	} +	else +	{ +		// *TODO: Wow, harsh.  Should we just complain and get out? +		LL_ERRS() << "unpack failed" << LL_ENDL; +	} +} + +void AISUpdate::parseLink(const LLSD& link_map) +{ +	LLUUID item_id = link_map["item_id"].asUUID(); +	LLPointer<LLViewerInventoryItem> new_link(new LLViewerInventoryItem); +	LLViewerInventoryItem *curr_link = gInventory.getItem(item_id); +	if (curr_link) +	{ +		// Default to current values where not provided. +		new_link->copyViewerItem(curr_link); +	} +	BOOL rv = new_link->unpackMessage(link_map); +	if (rv) +	{ +		const LLUUID& parent_id = new_link->getParentUUID(); +		if (curr_link) +		{ +			mItemsUpdated[item_id] = new_link; +			// This statement is here to cause a new entry with 0 +			// delta to be created if it does not already exist; +			// otherwise has no effect. +			mCatDescendentDeltas[parent_id]; +		} +		else +		{ +			LLPermissions default_perms; +			default_perms.init(gAgent.getID(),gAgent.getID(),LLUUID::null,LLUUID::null); +			default_perms.initMasks(PERM_NONE,PERM_NONE,PERM_NONE,PERM_NONE,PERM_NONE); +			new_link->setPermissions(default_perms); +			LLSaleInfo default_sale_info; +			new_link->setSaleInfo(default_sale_info); +			//LL_DEBUGS("Inventory") << "creating link from llsd: " << ll_pretty_print_sd(link_map) << LL_ENDL; +			mItemsCreated[item_id] = new_link; +			mCatDescendentDeltas[parent_id]++; +		} +	} +	else +	{ +		// *TODO: Wow, harsh.  Should we just complain and get out? +		LL_ERRS() << "unpack failed" << LL_ENDL; +	} +} + + +void AISUpdate::parseCategory(const LLSD& category_map) +{ +	LLUUID category_id = category_map["category_id"].asUUID(); + +	// Check descendent count first, as it may be needed +	// to populate newly created categories +	if (category_map.has("_embedded")) +	{ +		parseDescendentCount(category_id, category_map["_embedded"]); +	} + +	LLPointer<LLViewerInventoryCategory> new_cat(new LLViewerInventoryCategory(category_id)); +	LLViewerInventoryCategory *curr_cat = gInventory.getCategory(category_id); +	if (curr_cat) +	{ +		// Default to current values where not provided. +		new_cat->copyViewerCategory(curr_cat); +	} +	BOOL rv = new_cat->unpackMessage(category_map); +	// *NOTE: unpackMessage does not unpack version or descendent count. +	//if (category_map.has("version")) +	//{ +	//	mCatVersionsUpdated[category_id] = category_map["version"].asInteger(); +	//} +	if (rv) +	{ +		if (curr_cat) +		{ +			mCategoriesUpdated[category_id] = new_cat; +			// This statement is here to cause a new entry with 0 +			// delta to be created if it does not already exist; +			// otherwise has no effect. +			mCatDescendentDeltas[new_cat->getParentUUID()]; +			// Capture update for the category itself as well. +			mCatDescendentDeltas[category_id]; +		} +		else +		{ +			// Set version/descendents for newly created categories. +			if (category_map.has("version")) +			{ +				S32 version = category_map["version"].asInteger(); +				LL_DEBUGS("Inventory") << "Setting version to " << version +									   << " for new category " << category_id << LL_ENDL; +				new_cat->setVersion(version); +			} +			uuid_int_map_t::const_iterator lookup_it = mCatDescendentsKnown.find(category_id); +			if (mCatDescendentsKnown.end() != lookup_it) +			{ +				S32 descendent_count = lookup_it->second; +				LL_DEBUGS("Inventory") << "Setting descendents count to " << descendent_count  +									   << " for new category " << category_id << LL_ENDL; +				new_cat->setDescendentCount(descendent_count); +			} +			mCategoriesCreated[category_id] = new_cat; +			mCatDescendentDeltas[new_cat->getParentUUID()]++; +		} +	} +	else +	{ +		// *TODO: Wow, harsh.  Should we just complain and get out? +		LL_ERRS() << "unpack failed" << LL_ENDL; +	} + +	// Check for more embedded content. +	if (category_map.has("_embedded")) +	{ +		parseEmbedded(category_map["_embedded"]); +	} +} + +void AISUpdate::parseDescendentCount(const LLUUID& category_id, const LLSD& embedded) +{ +	// We can only determine true descendent count if this contains all descendent types. +	if (embedded.has("categories") && +		embedded.has("links") && +		embedded.has("items")) +	{ +		mCatDescendentsKnown[category_id]  = embedded["categories"].size(); +		mCatDescendentsKnown[category_id] += embedded["links"].size(); +		mCatDescendentsKnown[category_id] += embedded["items"].size(); +	} +} + +void AISUpdate::parseEmbedded(const LLSD& embedded) +{ +	if (embedded.has("links")) // _embedded in a category +	{ +		parseEmbeddedLinks(embedded["links"]); +	} +	if (embedded.has("items")) // _embedded in a category +	{ +		parseEmbeddedItems(embedded["items"]); +	} +	if (embedded.has("item")) // _embedded in a link +	{ +		parseEmbeddedItem(embedded["item"]); +	} +	if (embedded.has("categories")) // _embedded in a category +	{ +		parseEmbeddedCategories(embedded["categories"]); +	} +	if (embedded.has("category")) // _embedded in a link +	{ +		parseEmbeddedCategory(embedded["category"]); +	} +} + +void AISUpdate::parseUUIDArray(const LLSD& content, const std::string& name, uuid_list_t& ids) +{ +	if (content.has(name)) +	{ +		for(LLSD::array_const_iterator it = content[name].beginArray(), +				end = content[name].endArray(); +				it != end; ++it) +		{ +			ids.insert((*it).asUUID()); +		} +	} +} + +void AISUpdate::parseEmbeddedLinks(const LLSD& links) +{ +	for(LLSD::map_const_iterator linkit = links.beginMap(), +			linkend = links.endMap(); +		linkit != linkend; ++linkit) +	{ +		const LLUUID link_id((*linkit).first); +		const LLSD& link_map = (*linkit).second; +		if (mItemIds.end() == mItemIds.find(link_id)) +		{ +			LL_DEBUGS("Inventory") << "Ignoring link not in items list " << link_id << LL_ENDL; +		} +		else +		{ +			parseLink(link_map); +		} +	} +} + +void AISUpdate::parseEmbeddedItem(const LLSD& item) +{ +	// a single item (_embedded in a link) +	if (item.has("item_id")) +	{ +		if (mItemIds.end() != mItemIds.find(item["item_id"].asUUID())) +		{ +			parseItem(item); +		} +	} +} + +void AISUpdate::parseEmbeddedItems(const LLSD& items) +{ +	// a map of items (_embedded in a category) +	for(LLSD::map_const_iterator itemit = items.beginMap(), +			itemend = items.endMap(); +		itemit != itemend; ++itemit) +	{ +		const LLUUID item_id((*itemit).first); +		const LLSD& item_map = (*itemit).second; +		if (mItemIds.end() == mItemIds.find(item_id)) +		{ +			LL_DEBUGS("Inventory") << "Ignoring item not in items list " << item_id << LL_ENDL; +		} +		else +		{ +			parseItem(item_map); +		} +	} +} + +void AISUpdate::parseEmbeddedCategory(const LLSD& category) +{ +	// a single category (_embedded in a link) +	if (category.has("category_id")) +	{ +		if (mCategoryIds.end() != mCategoryIds.find(category["category_id"].asUUID())) +		{ +			parseCategory(category); +		} +	} +} + +void AISUpdate::parseEmbeddedCategories(const LLSD& categories) +{ +	// a map of categories (_embedded in a category) +	for(LLSD::map_const_iterator categoryit = categories.beginMap(), +			categoryend = categories.endMap(); +		categoryit != categoryend; ++categoryit) +	{ +		const LLUUID category_id((*categoryit).first); +		const LLSD& category_map = (*categoryit).second; +		if (mCategoryIds.end() == mCategoryIds.find(category_id)) +		{ +			LL_DEBUGS("Inventory") << "Ignoring category not in categories list " << category_id << LL_ENDL; +		} +		else +		{ +			parseCategory(category_map); +		} +	} +} + +void AISUpdate::doUpdate() +{ +	// Do version/descendent accounting. +	for (std::map<LLUUID,S32>::const_iterator catit = mCatDescendentDeltas.begin(); +		 catit != mCatDescendentDeltas.end(); ++catit) +	{ +		LL_DEBUGS("Inventory") << "descendent accounting for " << catit->first << LL_ENDL; + +		const LLUUID cat_id(catit->first); +		// Don't account for update if we just created this category. +		if (mCategoriesCreated.find(cat_id) != mCategoriesCreated.end()) +		{ +			LL_DEBUGS("Inventory") << "Skipping version increment for new category " << cat_id << LL_ENDL; +			continue; +		} + +		// Don't account for update unless AIS told us it updated that category. +		if (mCatVersionsUpdated.find(cat_id) == mCatVersionsUpdated.end()) +		{ +			LL_DEBUGS("Inventory") << "Skipping version increment for non-updated category " << cat_id << LL_ENDL; +			continue; +		} + +		// If we have a known descendent count, set that now. +		LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id); +		if (cat) +		{ +			S32 descendent_delta = catit->second; +			S32 old_count = cat->getDescendentCount(); +			LL_DEBUGS("Inventory") << "Updating descendent count for " +								   << cat->getName() << " " << cat_id +								   << " with delta " << descendent_delta << " from " +								   << old_count << " to " << (old_count+descendent_delta) << LL_ENDL; +			LLInventoryModel::LLCategoryUpdate up(cat_id, descendent_delta); +			gInventory.accountForUpdate(up); +		} +		else +		{ +			LL_DEBUGS("Inventory") << "Skipping version accounting for unknown category " << cat_id << LL_ENDL; +		} +	} + +	// CREATE CATEGORIES +	for (deferred_category_map_t::const_iterator create_it = mCategoriesCreated.begin(); +		 create_it != mCategoriesCreated.end(); ++create_it) +	{ +		LLUUID category_id(create_it->first); +		LLPointer<LLViewerInventoryCategory> new_category = create_it->second; + +		gInventory.updateCategory(new_category, LLInventoryObserver::CREATE); +		LL_DEBUGS("Inventory") << "created category " << category_id << LL_ENDL; +	} + +	// UPDATE CATEGORIES +	for (deferred_category_map_t::const_iterator update_it = mCategoriesUpdated.begin(); +		 update_it != mCategoriesUpdated.end(); ++update_it) +	{ +		LLUUID category_id(update_it->first); +		LLPointer<LLViewerInventoryCategory> new_category = update_it->second; +		// Since this is a copy of the category *before* the accounting update, above, +		// we need to transfer back the updated version/descendent count. +		LLViewerInventoryCategory* curr_cat = gInventory.getCategory(new_category->getUUID()); +		if (NULL == curr_cat) +		{ +			LL_WARNS("Inventory") << "Failed to update unknown category " << new_category->getUUID() << LL_ENDL; +		} +		else +		{ +			new_category->setVersion(curr_cat->getVersion()); +			new_category->setDescendentCount(curr_cat->getDescendentCount()); +			gInventory.updateCategory(new_category); +			LL_DEBUGS("Inventory") << "updated category " << new_category->getName() << " " << category_id << LL_ENDL; +		} +	} + +	// CREATE ITEMS +	for (deferred_item_map_t::const_iterator create_it = mItemsCreated.begin(); +		 create_it != mItemsCreated.end(); ++create_it) +	{ +		LLUUID item_id(create_it->first); +		LLPointer<LLViewerInventoryItem> new_item = create_it->second; + +		// FIXME risky function since it calls updateServer() in some +		// cases.  Maybe break out the update/create cases, in which +		// case this is create. +		LL_DEBUGS("Inventory") << "created item " << item_id << LL_ENDL; +		gInventory.updateItem(new_item, LLInventoryObserver::CREATE); +	} +	 +	// UPDATE ITEMS +	for (deferred_item_map_t::const_iterator update_it = mItemsUpdated.begin(); +		 update_it != mItemsUpdated.end(); ++update_it) +	{ +		LLUUID item_id(update_it->first); +		LLPointer<LLViewerInventoryItem> new_item = update_it->second; +		// FIXME risky function since it calls updateServer() in some +		// cases.  Maybe break out the update/create cases, in which +		// case this is update. +		LL_DEBUGS("Inventory") << "updated item " << item_id << LL_ENDL; +		//LL_DEBUGS("Inventory") << ll_pretty_print_sd(new_item->asLLSD()) << LL_ENDL; +		gInventory.updateItem(new_item); +	} + +	// DELETE OBJECTS +	for (uuid_list_t::const_iterator del_it = mObjectsDeletedIds.begin(); +		 del_it != mObjectsDeletedIds.end(); ++del_it) +	{ +		LL_DEBUGS("Inventory") << "deleted item " << *del_it << LL_ENDL; +		gInventory.onObjectDeletedFromServer(*del_it, false, false, false); +	} + +	// TODO - how can we use this version info? Need to be sure all +	// changes are going through AIS first, or at least through +	// something with a reliable responder. +	for (uuid_int_map_t::iterator ucv_it = mCatVersionsUpdated.begin(); +		 ucv_it != mCatVersionsUpdated.end(); ++ucv_it) +	{ +		const LLUUID id = ucv_it->first; +		S32 version = ucv_it->second; +		LLViewerInventoryCategory *cat = gInventory.getCategory(id); +		LL_DEBUGS("Inventory") << "cat version update " << cat->getName() << " to version " << cat->getVersion() << LL_ENDL; +		if (cat->getVersion() != version) +		{ +			LL_WARNS() << "Possible version mismatch for category " << cat->getName() +					<< ", viewer version " << cat->getVersion() +					<< " server version " << version << LL_ENDL; +		} +	} + +	gInventory.notifyObservers(); +} + diff --git a/indra/newview/llaisapi.h b/indra/newview/llaisapi.h new file mode 100755 index 0000000000..5a2ec94af9 --- /dev/null +++ b/indra/newview/llaisapi.h @@ -0,0 +1,183 @@ +/**  + * @file llaisapi.h + * @brief classes and functions for interfacing with the v3+ ais inventory service.  + * + * $LicenseInfo:firstyear=2013&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2013, Linden Research, Inc. + *  + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + *  + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + *  + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + *  + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLAISAPI_H +#define LL_LLAISAPI_H + +#include "lluuid.h" +#include <map> +#include <set> +#include <string> +#include "llcurl.h" +#include "llhttpclient.h" +#include "llhttpretrypolicy.h" +#include "llviewerinventory.h" + +class AISCommand: public LLHTTPClient::Responder +{ +public: +	typedef boost::function<void()> command_func_type; + +	AISCommand(LLPointer<LLInventoryCallback> callback); + +	virtual ~AISCommand() {} + +	bool run_command(); + +	void setCommandFunc(command_func_type command_func); +	 +	// Need to do command-specific parsing to get an id here, for +	// LLInventoryCallback::fire().  May or may not need to bother, +	// since most LLInventoryCallbacks do their work in the +	// destructor. +	 +	/* virtual */ void httpSuccess(); +	/* virtual */ void httpFailure(); + +	static bool isAPIAvailable(); +	static bool getInvCap(std::string& cap); +	static bool getLibCap(std::string& cap); +	static void getCapabilityNames(LLSD& capabilityNames); + +protected: +	virtual bool getResponseUUID(const LLSD& content, LLUUID& id); + +private: +	command_func_type mCommandFunc; +	LLPointer<LLHTTPRetryPolicy> mRetryPolicy; +	LLPointer<LLInventoryCallback> mCallback; +}; + +class RemoveItemCommand: public AISCommand +{ +public: +	RemoveItemCommand(const LLUUID& item_id, +					  LLPointer<LLInventoryCallback> callback); +}; + +class RemoveCategoryCommand: public AISCommand +{ +public: +	RemoveCategoryCommand(const LLUUID& item_id, +						  LLPointer<LLInventoryCallback> callback); +}; + +class PurgeDescendentsCommand: public AISCommand +{ +public: +	PurgeDescendentsCommand(const LLUUID& item_id, +							LLPointer<LLInventoryCallback> callback); +}; + +class UpdateItemCommand: public AISCommand +{ +public: +	UpdateItemCommand(const LLUUID& item_id, +					  const LLSD& updates, +					  LLPointer<LLInventoryCallback> callback); +private: +	LLSD mUpdates; +}; + +class UpdateCategoryCommand: public AISCommand +{ +public: +	UpdateCategoryCommand(const LLUUID& cat_id, +						  const LLSD& updates, +						  LLPointer<LLInventoryCallback> callback); +private: +	LLSD mUpdates; +}; + +class SlamFolderCommand: public AISCommand +{ +public: +	SlamFolderCommand(const LLUUID& folder_id, const LLSD& contents, LLPointer<LLInventoryCallback> callback); +	 +private: +	LLSD mContents; +}; + +class CopyLibraryCategoryCommand: public AISCommand +{ +public: +	CopyLibraryCategoryCommand(const LLUUID& source_id, const LLUUID& dest_id, LLPointer<LLInventoryCallback> callback); + +protected: +	/* virtual */ bool getResponseUUID(const LLSD& content, LLUUID& id); +}; + +class CreateInventoryCommand: public AISCommand +{ +public: +	CreateInventoryCommand(const LLUUID& parent_id, const LLSD& new_inventory, LLPointer<LLInventoryCallback> callback); + +private: +	LLSD mNewInventory; +}; + +class AISUpdate +{ +public: +	AISUpdate(const LLSD& update); +	void parseUpdate(const LLSD& update); +	void parseMeta(const LLSD& update); +	void parseContent(const LLSD& update); +	void parseUUIDArray(const LLSD& content, const std::string& name, uuid_list_t& ids); +	void parseLink(const LLSD& link_map); +	void parseItem(const LLSD& link_map); +	void parseCategory(const LLSD& link_map); +	void parseDescendentCount(const LLUUID& category_id, const LLSD& embedded); +	void parseEmbedded(const LLSD& embedded); +	void parseEmbeddedLinks(const LLSD& links); +	void parseEmbeddedItems(const LLSD& items); +	void parseEmbeddedCategories(const LLSD& categories); +	void parseEmbeddedItem(const LLSD& item); +	void parseEmbeddedCategory(const LLSD& category); +	void doUpdate(); +private: +	void clearParseResults(); + +	typedef std::map<LLUUID,S32> uuid_int_map_t; +	uuid_int_map_t mCatDescendentDeltas; +	uuid_int_map_t mCatDescendentsKnown; +	uuid_int_map_t mCatVersionsUpdated; + +	typedef std::map<LLUUID,LLPointer<LLViewerInventoryItem> > deferred_item_map_t; +	deferred_item_map_t mItemsCreated; +	deferred_item_map_t mItemsUpdated; +	typedef std::map<LLUUID,LLPointer<LLViewerInventoryCategory> > deferred_category_map_t; +	deferred_category_map_t mCategoriesCreated; +	deferred_category_map_t mCategoriesUpdated; + +	// These keep track of uuid's mentioned in meta values. +	// Useful for filtering out which content we are interested in. +	uuid_list_t mObjectsDeletedIds; +	uuid_list_t mItemIds; +	uuid_list_t mCategoryIds; +}; + +#endif diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 81f713502f..a4c430bada 100755 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -52,6 +52,8 @@  #include "llwearablelist.h"  #include "llsdutil.h"  #include "llsdserialize.h" +#include "llhttpretrypolicy.h" +#include "llaisapi.h"  #if LL_MSVC  // disable boost::lexical_cast warning @@ -196,7 +198,7 @@ public:  		LLEventTimer(5.0)  	{  		if (!mTrackingPhase.empty()) -	{ +		{  			selfStartPhase(mTrackingPhase);  		}  	} @@ -212,23 +214,22 @@ public:  			addItem(item->getUUID());  		}  	} -		 +  	// Request or re-request operation for specified item.  	void addItem(const LLUUID& item_id)  	{  		LL_DEBUGS("Avatar") << "item_id " << item_id << LL_ENDL; -  		if (!requestOperation(item_id))  		{  			LL_DEBUGS("Avatar") << "item_id " << item_id << " requestOperation false, skipping" << LL_ENDL;  			return; -	} +		}  		mPendingRequests++;  		// On a re-request, this will reset the timer.  		mWaitTimes[item_id] = LLTimer();  		if (mRetryCounts.find(item_id) == mRetryCounts.end()) -	{ +		{  			mRetryCounts[item_id] = 0;  		}  		else @@ -242,7 +243,7 @@ public:  	void onOp(const LLUUID& src_id, const LLUUID& dst_id, LLTimer timestamp)  	{  		if (ll_frand() < gSavedSettings.getF32("InventoryDebugSimulateLateOpRate")) -	{ +		{  			LL_WARNS() << "Simulating late operation by punting handling to later" << LL_ENDL;  			doAfterInterval(boost::bind(&LLCallAfterInventoryBatchMgr::onOp,this,src_id,dst_id,timestamp),  							mRetryAfter); @@ -265,12 +266,12 @@ public:  			onCompletionOrFailure();  		}  	} -		 +  	void onCompletionOrFailure()  	{  		assert (!mCompletionOrFailureCalled);  		mCompletionOrFailureCalled = true; - +		  		// Will never call onCompletion() if any item has been flagged as  		// a failure - otherwise could wind up with corrupted  		// outfit, involuntary nudity, etc. @@ -288,7 +289,7 @@ public:  			onFailure();  		}  	} -		 +  	void onFailure()  	{  		LL_INFOS() << "failed" << LL_ENDL; @@ -300,7 +301,7 @@ public:  		LL_INFOS() << "done" << LL_ENDL;  		mOnCompletionFunc();  	} - +	  	// virtual  	// Will be deleted after returning true - only safe to do this if all callbacks have fired.  	BOOL tick() @@ -313,7 +314,7 @@ public:  		// been serviced, since it will result in this object being  		// deleted.  		bool all_done = (mPendingRequests==0); -		 +  		if (!mWaitTimes.empty())  		{  			LL_WARNS() << "still waiting on " << mWaitTimes.size() << " items" << LL_ENDL; @@ -323,20 +324,20 @@ public:  				// Use a copy of iterator because it may be erased/invalidated.  				std::map<LLUUID,LLTimer>::iterator curr_it = it;  				++it; - +				  				F32 time_waited = curr_it->second.getElapsedTimeF32();  				S32 retries = mRetryCounts[curr_it->first];  				if (time_waited > mRetryAfter)  				{  					if (retries < mMaxRetries) -		{ +					{  						LL_DEBUGS("Avatar") << "Waited " << time_waited <<  							" for " << curr_it->first << ", retrying" << LL_ENDL;  						mRetryCount++;  						addItem(curr_it->first); -		} -		else -		{ +					} +					else +					{  						LL_WARNS() << "Giving up on " << curr_it->first << " after too many retries" << LL_ENDL;  						mWaitTimes.erase(curr_it);  						mFailCount++; @@ -347,8 +348,8 @@ public:  					onCompletionOrFailure();  				} +			}  		} -	}  		return all_done;  	} @@ -360,7 +361,7 @@ public:  		LL_DEBUGS("Avatar") << "Times: n " << mTimeStats.getCount() << " min " << mTimeStats.getMinValue() << " max " << mTimeStats.getMaxValue() << LL_ENDL;  		LL_DEBUGS("Avatar") << "Mean " << mTimeStats.getMean() << " stddev " << mTimeStats.getStdDev() << LL_ENDL;  	} - +	  	virtual ~LLCallAfterInventoryBatchMgr()  	{  		LL_DEBUGS("Avatar") << "deleting" << LL_ENDL; @@ -396,10 +397,16 @@ public:  		LLCallAfterInventoryBatchMgr(dst_cat_id, phase_name, on_completion_func, on_failure_func, retry_after, max_retries)  	{  		addItems(src_items); +		sInstanceCount++;  	} +	~LLCallAfterInventoryCopyMgr() +	{ +		sInstanceCount--; +	} +	  	virtual bool requestOperation(const LLUUID& item_id) -		{ +	{  		LLViewerInventoryItem *item = gInventory.getItem(item_id);  		llassert(item);  		LL_DEBUGS("Avatar") << "copying item " << item_id << LL_ENDL; @@ -418,95 +425,86 @@ public:  			);  		return true;  	} + +	static S32 getInstanceCount() { return sInstanceCount; } +	 +private: +	static S32 sInstanceCount;  }; -class LLCallAfterInventoryLinkMgr: public LLCallAfterInventoryBatchMgr +S32 LLCallAfterInventoryCopyMgr::sInstanceCount = 0; + +class LLWearCategoryAfterCopy: public LLInventoryCallback  {  public: -	LLCallAfterInventoryLinkMgr(LLInventoryModel::item_array_t& src_items, -								const LLUUID& dst_cat_id, -								const std::string& phase_name, -								nullary_func_t on_completion_func, -								nullary_func_t on_failure_func = no_op, -								 F32 retry_after = DEFAULT_RETRY_AFTER_INTERVAL, -								 S32 max_retries = DEFAULT_MAX_RETRIES -		): -		LLCallAfterInventoryBatchMgr(dst_cat_id, phase_name, on_completion_func, on_failure_func, retry_after, max_retries) +	LLWearCategoryAfterCopy(bool append): +		mAppend(append) +	{} + +	// virtual +	void fire(const LLUUID& id)  	{ -		addItems(src_items); +		// Wear the inventory category. +		LLInventoryCategory* cat = gInventory.getCategory(id); +		LLAppearanceMgr::instance().wearInventoryCategoryOnAvatar(cat, mAppend);  	} -	 -	virtual bool requestOperation(const LLUUID& item_id) -	{ -		bool request_sent = false; -		LLViewerInventoryItem *item = gInventory.getItem(item_id); -		if (item) -		{ -			if (item->getParentUUID() == mDstCatID) -			{ -				LL_DEBUGS("Avatar") << "item " << item_id << " name " << item->getName() << " is already a child of " << mDstCatID << LL_ENDL; -				return false; -			} -			LL_DEBUGS("Avatar") << "linking item " << item_id << " name " << item->getName() << " to " << mDstCatID << LL_ENDL; -			// create an inventory item link. -			if (ll_frand() < gSavedSettings.getF32("InventoryDebugSimulateOpFailureRate")) -			{ -				LL_DEBUGS("Avatar") << "simulating failure by not sending request for item " << item_id << LL_ENDL; -				return true; -			} -			link_inventory_item(gAgent.getID(), -								item->getLinkedUUID(), -								mDstCatID, -								item->getName(), -								item->getActualDescription(), -								LLAssetType::AT_LINK, -								new LLBoostFuncInventoryCallback( -									boost::bind(&LLCallAfterInventoryBatchMgr::onOp,this,item_id,_1,LLTimer()))); -			return true; -		} -		else -		{ -			// create a base outfit link if appropriate. -			LLViewerInventoryCategory *catp = gInventory.getCategory(item_id); -			if (!catp) -			{ -				LL_WARNS() << "link request failed, id not found as inventory item or category " << item_id << LL_ENDL; -				return false; -			} -			const LLUUID cof = LLAppearanceMgr::instance().getCOF(); -			std::string new_outfit_name = ""; -			LLAppearanceMgr::instance().purgeBaseOutfitLink(cof); +private: +	bool mAppend; +}; -			if (catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT) +class LLTrackPhaseWrapper : public LLInventoryCallback +{ +public: +	LLTrackPhaseWrapper(const std::string& phase_name, LLPointer<LLInventoryCallback> cb = NULL): +		mTrackingPhase(phase_name), +		mCB(cb)  	{ -				if (ll_frand() < gSavedSettings.getF32("InventoryDebugSimulateOpFailureRate")) +		selfStartPhase(mTrackingPhase); +	} + +	// virtual +	void fire(const LLUUID& id) +	{ +		if (mCB)  		{ -					LL_DEBUGS("Avatar") << "simulating failure by not sending request for item " << item_id << LL_ENDL; -					return true; -				} -				LL_DEBUGS("Avatar") << "linking folder " << item_id << " name " << catp->getName() << " to cof " << cof << LL_ENDL; -				link_inventory_item(gAgent.getID(), item_id, cof, catp->getName(), "", -									LLAssetType::AT_LINK_FOLDER,  -									new LLBoostFuncInventoryCallback( -										boost::bind(&LLCallAfterInventoryBatchMgr::onOp,this,item_id,_1,LLTimer()))); -				new_outfit_name = catp->getName(); -				request_sent = true; -			} -	 -			LLAppearanceMgr::instance().updatePanelOutfitName(new_outfit_name); +			mCB->fire(id);  		} -		return request_sent;  	} + +	// virtual +	~LLTrackPhaseWrapper() +	{ +		selfStopPhase(mTrackingPhase); +	} + +protected: +	std::string mTrackingPhase; +	LLPointer<LLInventoryCallback> mCB;  }; -LLUpdateAppearanceOnDestroy::LLUpdateAppearanceOnDestroy(bool update_base_outfit_ordering): +LLUpdateAppearanceOnDestroy::LLUpdateAppearanceOnDestroy(bool enforce_item_restrictions, +														 bool enforce_ordering, +														 nullary_func_t post_update_func  +	):  	mFireCount(0), -	mUpdateBaseOrder(update_base_outfit_ordering) +	mEnforceItemRestrictions(enforce_item_restrictions), +	mEnforceOrdering(enforce_ordering), +	mPostUpdateFunc(post_update_func)  {  	selfStartPhase("update_appearance_on_destroy");  } +void LLUpdateAppearanceOnDestroy::fire(const LLUUID& inv_item) +{ +	LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(inv_item); +	const std::string item_name = item ? item->getName() : "ITEM NOT FOUND"; +#ifndef LL_RELEASE_FOR_DOWNLOAD +	LL_DEBUGS("Avatar") << self_av_string() << "callback fired [ name:" << item_name << " UUID:" << inv_item << " count:" << mFireCount << " ] " << LL_ENDL; +#endif +	mFireCount++; +} +  LLUpdateAppearanceOnDestroy::~LLUpdateAppearanceOnDestroy()  {  	if (!LLApp::isExiting()) @@ -516,20 +514,46 @@ LLUpdateAppearanceOnDestroy::~LLUpdateAppearanceOnDestroy()  		selfStopPhase("update_appearance_on_destroy"); -		LLAppearanceMgr::instance().updateAppearanceFromCOF(mUpdateBaseOrder); +		LLAppearanceMgr::instance().updateAppearanceFromCOF(mEnforceItemRestrictions, +															mEnforceOrdering, +															mPostUpdateFunc);  	}  } -void LLUpdateAppearanceOnDestroy::fire(const LLUUID& inv_item) +LLUpdateAppearanceAndEditWearableOnDestroy::LLUpdateAppearanceAndEditWearableOnDestroy(const LLUUID& item_id): +	mItemID(item_id)  { -	LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(inv_item); -	const std::string item_name = item ? item->getName() : "ITEM NOT FOUND"; -#ifndef LL_RELEASE_FOR_DOWNLOAD -	LL_DEBUGS("Avatar") << self_av_string() << "callback fired [ name:" << item_name << " UUID:" << inv_item << " count:" << mFireCount << " ] " << LL_ENDL; -#endif -	mFireCount++;  } +void edit_wearable_and_customize_avatar(LLUUID item_id) +{ +	// Start editing the item if previously requested. +	gAgentWearables.editWearableIfRequested(item_id); +	 +	// TODO: camera mode may not be changed if a debug setting is tweaked +	if( gAgentCamera.cameraCustomizeAvatar() ) +	{ +		// If we're in appearance editing mode, the current tab may need to be refreshed +		LLSidepanelAppearance *panel = dynamic_cast<LLSidepanelAppearance*>( +			LLFloaterSidePanelContainer::getPanel("appearance")); +		if (panel) +		{ +			panel->showDefaultSubpart(); +		} +	} +} + +LLUpdateAppearanceAndEditWearableOnDestroy::~LLUpdateAppearanceAndEditWearableOnDestroy() +{ +	if (!LLApp::isExiting()) +	{ +		LLAppearanceMgr::instance().updateAppearanceFromCOF( +			true,true, +			boost::bind(edit_wearable_and_customize_avatar, mItemID)); +	} +} + +  struct LLFoundData  {  	LLFoundData() : @@ -593,6 +617,8 @@ public:  	bool isMostRecent();  	void handleLateArrivals();  	void resetTime(F32 timeout); +	static S32 countActive() { return sActiveHoldingPatterns.size(); } +	S32 index() { return mIndex; }  private:  	found_list_t mFoundList; @@ -606,12 +632,15 @@ private:  	bool mFired;  	typedef std::set<LLWearableHoldingPattern*> type_set_hp;  	static type_set_hp sActiveHoldingPatterns; +	static S32 sNextIndex; +	S32 mIndex;  	bool mIsMostRecent;  	std::set<LLViewerWearable*> mLateArrivals;  	bool mIsAllComplete;  };  LLWearableHoldingPattern::type_set_hp LLWearableHoldingPattern::sActiveHoldingPatterns; +S32 LLWearableHoldingPattern::sNextIndex = 0;  LLWearableHoldingPattern::LLWearableHoldingPattern():  	mResolved(0), @@ -619,13 +648,13 @@ LLWearableHoldingPattern::LLWearableHoldingPattern():  	mIsMostRecent(true),  	mIsAllComplete(false)  { -	if (sActiveHoldingPatterns.size()>0) +	if (countActive()>0)  	{  		LL_INFOS() << "Creating LLWearableHoldingPattern when " -				<< sActiveHoldingPatterns.size() -				<< " other attempts are active." -				<< " Flagging others as invalid." -				<< LL_ENDL; +				   << countActive() +				   << " other attempts are active." +				   << " Flagging others as invalid." +				   << LL_ENDL;  		for (type_set_hp::iterator it = sActiveHoldingPatterns.begin();  			 it != sActiveHoldingPatterns.end();  			 ++it) @@ -634,7 +663,9 @@ LLWearableHoldingPattern::LLWearableHoldingPattern():  		}  	} +	mIndex = sNextIndex++;  	sActiveHoldingPatterns.insert(this); +	LL_DEBUGS("Avatar") << "HP " << index() << " created" << LL_ENDL;  	selfStartPhase("holding_pattern");  } @@ -645,6 +676,7 @@ LLWearableHoldingPattern::~LLWearableHoldingPattern()  	{  		selfStopPhase("holding_pattern");  	} +	LL_DEBUGS("Avatar") << "HP " << index() << " deleted" << LL_ENDL;  }  bool LLWearableHoldingPattern::isMostRecent() @@ -733,7 +765,10 @@ void LLWearableHoldingPattern::checkMissingWearables()  	resetTime(60.0F); -	selfStartPhase("get_missing_wearables"); +	if (isMostRecent()) +	{ +		selfStartPhase("get_missing_wearables_2"); +	}  	if (!pollMissingWearables())  	{  		doOnIdleRepeating(boost::bind(&LLWearableHoldingPattern::pollMissingWearables,this)); @@ -773,8 +808,8 @@ void LLWearableHoldingPattern::onAllComplete()  	}  	// Update wearables. -	LL_INFOS("Avatar") << self_av_string() << "Updating agent wearables with " << mResolved << " wearable items " << LL_ENDL; -	LLAppearanceMgr::instance().updateAgentWearables(this, false); +	LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " updating agent wearables with " << mResolved << " wearable items " << LL_ENDL; +	LLAppearanceMgr::instance().updateAgentWearables(this);  	// Update attachments to match those requested.  	if (isAgentAvatarValid()) @@ -797,7 +832,10 @@ void LLWearableHoldingPattern::onAllComplete()  void LLWearableHoldingPattern::onFetchCompletion()  { -	selfStopPhase("get_wearables"); +	if (isMostRecent()) +	{ +		selfStopPhase("get_wearables_2"); +	}  	if (!isMostRecent())  	{ @@ -823,7 +861,7 @@ bool LLWearableHoldingPattern::pollFetchCompletion()  	if (done)  	{ -		LL_INFOS("Avatar") << self_av_string() << "polling, done status: " << completed << " timed out " << timed_out +		LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " polling, done status: " << completed << " timed out " << timed_out  				<< " elapsed " << mWaitTime.getElapsedTimeF32() << LL_ENDL;  		mFired = true; @@ -841,69 +879,64 @@ bool LLWearableHoldingPattern::pollFetchCompletion()  void recovered_item_link_cb(const LLUUID& item_id, LLWearableType::EType type, LLViewerWearable *wearable, LLWearableHoldingPattern* holder)  {  	if (!holder->isMostRecent()) -		{ -			LL_WARNS() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; -			// runway skip here? -		} +	{ +		LL_WARNS() << "HP " << holder->index() << " skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; +		// runway skip here? +	} -	LL_INFOS() << "Recovered item link for type " << type << LL_ENDL; +	LL_INFOS() << "HP " << holder->index() << " recovered item link for type " << type << LL_ENDL;  	holder->eraseTypeToLink(type); -		// Add wearable to FoundData for actual wearing -		LLViewerInventoryItem *item = gInventory.getItem(item_id); -		LLViewerInventoryItem *linked_item = item ? item->getLinkedItem() : NULL; +	// Add wearable to FoundData for actual wearing +	LLViewerInventoryItem *item = gInventory.getItem(item_id); +	LLViewerInventoryItem *linked_item = item ? item->getLinkedItem() : NULL; -		if (linked_item) -		{ -			gInventory.addChangedMask(LLInventoryObserver::LABEL, linked_item->getUUID()); +	if (linked_item) +	{ +		gInventory.addChangedMask(LLInventoryObserver::LABEL, linked_item->getUUID()); -			if (item) -			{ -				LLFoundData found(linked_item->getUUID(), -								  linked_item->getAssetUUID(), -								  linked_item->getName(), -								  linked_item->getType(), -								  linked_item->isWearableType() ? linked_item->getWearableType() : LLWearableType::WT_INVALID, -								  true // is replacement -					); +		if (item) +		{ +			LLFoundData found(linked_item->getUUID(), +							  linked_item->getAssetUUID(), +							  linked_item->getName(), +							  linked_item->getType(), +							  linked_item->isWearableType() ? linked_item->getWearableType() : LLWearableType::WT_INVALID, +							  true // is replacement +				);  			found.mWearable = wearable;  			holder->getFoundList().push_front(found); -			} -			else -			{ -				LL_WARNS() << self_av_string() << "inventory item not found for recovered wearable" << LL_ENDL; -			}  		}  		else  		{  			LL_WARNS() << self_av_string() << "inventory link not found for recovered wearable" << LL_ENDL;  		}  	} +	else +	{ +		LL_WARNS() << self_av_string() << "HP " << holder->index() << " inventory link not found for recovered wearable" << LL_ENDL; +	} +}  void recovered_item_cb(const LLUUID& item_id, LLWearableType::EType type, LLViewerWearable *wearable, LLWearableHoldingPattern* holder)  {  	if (!holder->isMostRecent()) -		{ -			// runway skip here? -			LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; -		} +	{ +		// runway skip here? +		LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; +	}  	LL_DEBUGS("Avatar") << self_av_string() << "Recovered item for type " << type << LL_ENDL; -		LLViewerInventoryItem *itemp = gInventory.getItem(item_id); +	LLConstPointer<LLInventoryObject> itemp = gInventory.getItem(item_id);  	wearable->setItemID(item_id); -	LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(recovered_item_link_cb,_1,type,wearable,holder));  	holder->eraseTypeToRecover(type); -		llassert(itemp); -		if (itemp) -		{ -			link_inventory_item( gAgent.getID(), -					     item_id, -					     LLAppearanceMgr::instance().getCOF(), -					     itemp->getName(), -						 itemp->getDescription(), -					     LLAssetType::AT_LINK, -					     cb); -		} +	llassert(itemp); +	if (itemp) +	{ +		LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(recovered_item_link_cb,_1,type,wearable,holder)); + +		link_inventory_object(LLAppearanceMgr::instance().getCOF(), itemp, cb);  	} +}  void LLWearableHoldingPattern::recoverMissingWearable(LLWearableType::EType type)  { @@ -916,7 +949,7 @@ void LLWearableHoldingPattern::recoverMissingWearable(LLWearableType::EType type  		// Try to recover by replacing missing wearable with a new one.  	LLNotificationsUtil::add("ReplacedMissingWearable");  	LL_DEBUGS() << "Wearable " << LLWearableType::getTypeLabel(type) -			 << " could not be downloaded.  Replaced inventory item with default wearable." << LL_ENDL; +				<< " could not be downloaded.  Replaced inventory item with default wearable." << LL_ENDL;  	LLViewerWearable* wearable = LLWearableList::instance().createNewWearable(type, gAgentAvatarp);  	// Add a new one in the lost and found folder. @@ -949,7 +982,7 @@ void LLWearableHoldingPattern::clearCOFLinksForMissingWearables()  		if ((data.mWearableType < LLWearableType::WT_COUNT) && (!data.mWearable))  		{  			// Wearable link that was never resolved; remove links to it from COF -			LL_INFOS("Avatar") << self_av_string() << "removing link for unresolved item " << data.mItemID.asString() << LL_ENDL; +			LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " removing link for unresolved item " << data.mItemID.asString() << LL_ENDL;  			LLAppearanceMgr::instance().removeCOFItemLinks(data.mItemID);  		}  	} @@ -969,7 +1002,7 @@ bool LLWearableHoldingPattern::pollMissingWearables()  	if (!done)  	{ -		LL_INFOS("Avatar") << self_av_string() << "polling missing wearables, waiting for items " << mTypesToRecover.size() +		LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " polling missing wearables, waiting for items " << mTypesToRecover.size()  				<< " links " << mTypesToLink.size()  				<< " wearables, timed out " << timed_out  				<< " elapsed " << mWaitTime.getElapsedTimeF32() @@ -978,7 +1011,10 @@ bool LLWearableHoldingPattern::pollMissingWearables()  	if (done)  	{ -		selfStopPhase("get_missing_wearables"); +		if (isMostRecent()) +		{ +			selfStopPhase("get_missing_wearables_2"); +		}  		gAgentAvatarp->debugWearablesLoaded(); @@ -1016,7 +1052,7 @@ void LLWearableHoldingPattern::handleLateArrivals()  		LL_WARNS() << self_av_string() << "Late arrivals not handled - in middle of missing wearables processing" << LL_ENDL;  	} -	LL_INFOS("Avatar") << self_av_string() << "Need to handle " << mLateArrivals.size() << " late arriving wearables" << LL_ENDL; +	LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " need to handle " << mLateArrivals.size() << " late arriving wearables" << LL_ENDL;  	// Update mFoundList using late-arriving wearables.  	std::set<LLWearableType::EType> replaced_types; @@ -1079,7 +1115,7 @@ void LLWearableHoldingPattern::handleLateArrivals()  	mLateArrivals.clear();  	// Update appearance based on mFoundList -	LLAppearanceMgr::instance().updateAgentWearables(this, false); +	LLAppearanceMgr::instance().updateAgentWearables(this);  }  void LLWearableHoldingPattern::resetTime(F32 timeout) @@ -1096,7 +1132,7 @@ void LLWearableHoldingPattern::onWearableAssetFetch(LLViewerWearable *wearable)  	}  	mResolved += 1;  // just counting callbacks, not successes. -	LL_DEBUGS("Avatar") << self_av_string() << "resolved " << mResolved << "/" << getFoundList().size() << LL_ENDL; +	LL_DEBUGS("Avatar") << self_av_string() << "HP " << index() << " resolved " << mResolved << "/" << getFoundList().size() << LL_ENDL;  	if (!wearable)  	{  		LL_WARNS() << self_av_string() << "no wearable found" << LL_ENDL; @@ -1203,8 +1239,7 @@ const LLViewerInventoryItem* LLAppearanceMgr::getBaseOutfitLink()  									cat_array,  									item_array,  									false, -									is_category, -									false); +									is_category);  	for (LLInventoryModel::item_array_t::const_iterator iter = item_array.begin();  		 iter != item_array.end();  		 iter++) @@ -1270,8 +1305,12 @@ void wear_on_avatar_cb(const LLUUID& inv_item, bool do_replace = false)  	}  } -bool LLAppearanceMgr::wearItemOnAvatar(const LLUUID& item_id_to_wear, bool do_update, bool replace, LLPointer<LLInventoryCallback> cb) +bool LLAppearanceMgr::wearItemOnAvatar(const LLUUID& item_id_to_wear, +									   bool do_update, +									   bool replace, +									   LLPointer<LLInventoryCallback> cb)  { +  	if (item_id_to_wear.isNull()) return false;  	// *TODO: issue with multi-wearable should be fixed: @@ -1290,7 +1329,7 @@ bool LLAppearanceMgr::wearItemOnAvatar(const LLUUID& item_id_to_wear, bool do_up  	if (gInventory.isObjectDescendentOf(item_to_wear->getUUID(), gInventory.getLibraryRootFolderID()))  	{  		LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(wear_on_avatar_cb,_1,replace)); -		copy_inventory_item(gAgent.getID(), item_to_wear->getPermissions().getOwner(), item_to_wear->getUUID(), LLUUID::null, std::string(),cb); +		copy_inventory_item(gAgent.getID(), item_to_wear->getPermissions().getOwner(), item_to_wear->getUUID(), LLUUID::null, std::string(), cb);  		return false;  	}   	else if (!gInventory.isObjectDescendentOf(item_to_wear->getUUID(), gInventory.getRootFolderID())) @@ -1310,15 +1349,22 @@ bool LLAppearanceMgr::wearItemOnAvatar(const LLUUID& item_id_to_wear, bool do_up  	switch (item_to_wear->getType())  	{  	case LLAssetType::AT_CLOTHING: -		if (gAgentWearables.areWearablesLoaded()) +	if (gAgentWearables.areWearablesLoaded())  		{ +			if (!cb && do_update) +			{ +				cb = new LLUpdateAppearanceAndEditWearableOnDestroy(item_id_to_wear); +			}  			S32 wearable_count = gAgentWearables.getWearableCount(item_to_wear->getWearableType());  			if ((replace && wearable_count != 0) ||  				(wearable_count >= LLAgentWearables::MAX_CLOTHING_PER_TYPE) )  			{ -				removeCOFItemLinks(gAgentWearables.getWearableItemID(item_to_wear->getWearableType(), wearable_count-1)); +				LLUUID item_id = gAgentWearables.getWearableItemID(item_to_wear->getWearableType(), +																   wearable_count-1); +				removeCOFItemLinks(item_id, cb);  			} -			addCOFItemLink(item_to_wear, do_update, cb); + +			addCOFItemLink(item_to_wear, cb);  		}   		break;  	case LLAssetType::AT_BODYPART: @@ -1327,8 +1373,11 @@ bool LLAppearanceMgr::wearItemOnAvatar(const LLUUID& item_id_to_wear, bool do_up  		// Remove the existing wearables of the same type.  		// Remove existing body parts anyway because we must not be able to wear e.g. two skins.  		removeCOFLinksOfType(item_to_wear->getWearableType()); - -		addCOFItemLink(item_to_wear, do_update, cb); +		if (!cb && do_update) +		{ +			cb = new LLUpdateAppearanceAndEditWearableOnDestroy(item_id_to_wear); +		} +		addCOFItemLink(item_to_wear, cb);  		break;  	case LLAssetType::AT_OBJECT:  		rez_attachment(item_to_wear, NULL, replace); @@ -1457,6 +1506,58 @@ void LLAppearanceMgr::shallowCopyCategory(const LLUUID& src_id, const LLUUID& ds  	gInventory.notifyObservers();  } +void LLAppearanceMgr::slamCategoryLinks(const LLUUID& src_id, const LLUUID& dst_id, +										bool include_folder_links, LLPointer<LLInventoryCallback> cb) +{ +	LLInventoryModel::cat_array_t* cats; +	LLInventoryModel::item_array_t* items; +	LLSD contents = LLSD::emptyArray(); +	gInventory.getDirectDescendentsOf(src_id, cats, items); +	LL_INFOS() << "copying " << items->size() << " items" << LL_ENDL; +	for (LLInventoryModel::item_array_t::const_iterator iter = items->begin(); +		 iter != items->end(); +		 ++iter) +	{ +		const LLViewerInventoryItem* item = (*iter); +		switch (item->getActualType()) +		{ +			case LLAssetType::AT_LINK: +			{ +				LL_DEBUGS("Avatar") << "linking inventory item " << item->getName() << LL_ENDL; +				//getActualDescription() is used for a new description  +				//to propagate ordering information saved in descriptions of links +				LLSD item_contents; +				item_contents["name"] = item->getName(); +				item_contents["desc"] = item->getActualDescription(); +				item_contents["linked_id"] = item->getLinkedUUID(); +				item_contents["type"] = LLAssetType::AT_LINK;  +				contents.append(item_contents); +				break; +			} +			case LLAssetType::AT_LINK_FOLDER: +			{ +				LLViewerInventoryCategory *catp = item->getLinkedCategory(); +				if (catp && include_folder_links) +				{ +					LL_DEBUGS("Avatar") << "linking inventory folder " << item->getName() << LL_ENDL; +					LLSD base_contents; +					base_contents["name"] = catp->getName(); +					base_contents["desc"] = ""; // categories don't have descriptions. +					base_contents["linked_id"] = catp->getLinkedUUID(); +					base_contents["type"] = LLAssetType::AT_LINK_FOLDER;  +					contents.append(base_contents); +				} +				break; +			} +			default: +			{ +				// Linux refuses to compile unless all possible enums are handled. Really, Linux? +				break; +			} +		} +	} +	slam_inventory_folder(dst_id, contents, cb); +}  // Copy contents of src_id to dst_id.  void LLAppearanceMgr::shallowCopyCategoryContents(const LLUUID& src_id, const LLUUID& dst_id,  													  LLPointer<LLInventoryCallback> cb) @@ -1465,6 +1566,7 @@ void LLAppearanceMgr::shallowCopyCategoryContents(const LLUUID& src_id, const LL  	LLInventoryModel::item_array_t* items;  	gInventory.getDirectDescendentsOf(src_id, cats, items);  	LL_INFOS() << "copying " << items->size() << " items" << LL_ENDL; +	LLInventoryObject::const_object_list_t link_array;  	for (LLInventoryModel::item_array_t::const_iterator iter = items->begin();  		 iter != items->end();  		 ++iter) @@ -1474,14 +1576,8 @@ void LLAppearanceMgr::shallowCopyCategoryContents(const LLUUID& src_id, const LL  		{  			case LLAssetType::AT_LINK:  			{ -				//getActualDescription() is used for a new description  -				//to propagate ordering information saved in descriptions of links -				link_inventory_item(gAgent.getID(), -									item->getLinkedUUID(), -									dst_id, -									item->getName(), -									item->getActualDescription(), -									LLAssetType::AT_LINK, cb); +				LL_DEBUGS("Avatar") << "linking inventory item " << item->getName() << LL_ENDL; +				link_array.push_back(LLConstPointer<LLInventoryObject>(item));  				break;  			}  			case LLAssetType::AT_LINK_FOLDER: @@ -1490,12 +1586,8 @@ void LLAppearanceMgr::shallowCopyCategoryContents(const LLUUID& src_id, const LL  				// Skip copying outfit links.  				if (catp && catp->getPreferredType() != LLFolderType::FT_OUTFIT)  				{ -					link_inventory_item(gAgent.getID(), -										item->getLinkedUUID(), -										dst_id, -										item->getName(), -										item->getDescription(), -										LLAssetType::AT_LINK_FOLDER, cb); +					LL_DEBUGS("Avatar") << "linking inventory folder " << item->getName() << LL_ENDL; +					link_array.push_back(LLConstPointer<LLInventoryObject>(item));  				}  				break;  			} @@ -1504,7 +1596,7 @@ void LLAppearanceMgr::shallowCopyCategoryContents(const LLUUID& src_id, const LL  			case LLAssetType::AT_BODYPART:  			case LLAssetType::AT_GESTURE:  			{ -				LL_INFOS() << "copying inventory item " << item->getName() << LL_ENDL; +				LL_DEBUGS("Avatar") << "copying inventory item " << item->getName() << LL_ENDL;  				copy_inventory_item(gAgent.getID(),  									item->getPermissions().getOwner(),  									item->getUUID(), @@ -1518,6 +1610,10 @@ void LLAppearanceMgr::shallowCopyCategoryContents(const LLUUID& src_id, const LL  				break;  		}  	} +	if (!link_array.empty()) +	{ +		link_inventory_array(dst_id, link_array, cb); +	}  }  BOOL LLAppearanceMgr::getCanMakeFolderIntoOutfit(const LLUUID& folder_id) @@ -1582,15 +1678,13 @@ bool LLAppearanceMgr::getCanRemoveOutfit(const LLUUID& outfit_cat_id)  // static  bool LLAppearanceMgr::getCanRemoveFromCOF(const LLUUID& outfit_cat_id)  { -	LLInventoryModel::cat_array_t cats; -	LLInventoryModel::item_array_t items; +	if (gAgentWearables.isCOFChangeInProgress()) +	{ +		return false; +	} +  	LLFindWearablesEx is_worn(/*is_worn=*/ true, /*include_body_parts=*/ false); -	gInventory.collectDescendentsIf(outfit_cat_id, -		cats, -		items, -		LLInventoryModel::EXCLUDE_TRASH, -		is_worn); -	return items.size() > 0; +	return gInventory.hasMatchingDirectDescendent(outfit_cat_id, is_worn);  }  // static @@ -1601,15 +1695,8 @@ bool LLAppearanceMgr::getCanAddToCOF(const LLUUID& outfit_cat_id)  		return false;  	} -	LLInventoryModel::cat_array_t cats; -	LLInventoryModel::item_array_t items;  	LLFindWearablesEx not_worn(/*is_worn=*/ false, /*include_body_parts=*/ false); -	gInventory.collectDescendentsIf(outfit_cat_id, -		cats, -		items, -		LLInventoryModel::EXCLUDE_TRASH, -		not_worn); -	return items.size() > 0; +	return gInventory.hasMatchingDirectDescendent(outfit_cat_id, not_worn);  }  bool LLAppearanceMgr::getCanReplaceCOF(const LLUUID& outfit_cat_id) @@ -1627,18 +1714,11 @@ bool LLAppearanceMgr::getCanReplaceCOF(const LLUUID& outfit_cat_id)  	}  	// Check whether the outfit contains any wearables we aren't wearing already (STORM-702). -	LLInventoryModel::cat_array_t cats; -	LLInventoryModel::item_array_t items; -	LLFindWearablesEx is_worn(/*is_worn=*/ false, /*include_body_parts=*/ true); -	gInventory.collectDescendentsIf(outfit_cat_id, -		cats, -		items, -		LLInventoryModel::EXCLUDE_TRASH, -		is_worn); -	return items.size() > 0; +	LLFindWearablesEx not_worn(/*is_worn=*/ false, /*include_body_parts=*/ true); +	return gInventory.hasMatchingDirectDescendent(outfit_cat_id, not_worn);  } -void LLAppearanceMgr::purgeBaseOutfitLink(const LLUUID& category) +void LLAppearanceMgr::purgeBaseOutfitLink(const LLUUID& category, LLPointer<LLInventoryCallback> cb)  {  	LLInventoryModel::cat_array_t cats;  	LLInventoryModel::item_array_t items; @@ -1649,46 +1729,14 @@ void LLAppearanceMgr::purgeBaseOutfitLink(const LLUUID& category)  		LLViewerInventoryItem *item = items.at(i);  		if (item->getActualType() != LLAssetType::AT_LINK_FOLDER)  			continue; -		if (item->getIsLinkType()) +		LLViewerInventoryCategory* catp = item->getLinkedCategory(); +		if(catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT)  		{ -			LLViewerInventoryCategory* catp = item->getLinkedCategory(); -			if(catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT) -			{ -				gInventory.purgeObject(item->getUUID()); -			} +			remove_inventory_item(item->getUUID(), cb);  		}  	}  } -void LLAppearanceMgr::purgeCategory(const LLUUID& category, bool keep_outfit_links, LLInventoryModel::item_array_t* keep_items) -{ -	LLInventoryModel::cat_array_t cats; -	LLInventoryModel::item_array_t items; -	gInventory.collectDescendents(category, cats, items, -								  LLInventoryModel::EXCLUDE_TRASH); -	for (S32 i = 0; i < items.size(); ++i) -	{ -		LLViewerInventoryItem *item = items.at(i); -		if (keep_outfit_links && (item->getActualType() == LLAssetType::AT_LINK_FOLDER)) -			continue; -		if (item->getIsLinkType()) -		{ -#if 0 -			if (keep_items && keep_items->find(item) != LLInventoryModel::item_array_t::FAIL) -			{ -				LL_INFOS() << "preserved item" << LL_ENDL; -			} -			else -			{ -			gInventory.purgeObject(item->getUUID()); -		} -#else -			gInventory.purgeObject(item->getUUID()); -		} -#endif -	} -} -  // Keep the last N wearables of each type.  For viewer 2.0, N is 1 for  // both body parts and clothing items.  void LLAppearanceMgr::filterWearableItems( @@ -1713,33 +1761,14 @@ void LLAppearanceMgr::filterWearableItems(  	}  } -// Create links to all listed items. -void LLAppearanceMgr::linkAll(const LLUUID& cat_uuid, -							  LLInventoryModel::item_array_t& items, -							  LLPointer<LLInventoryCallback> cb) -{ -	for (S32 i=0; i<items.size(); i++) -	{ -		const LLInventoryItem* item = items.at(i).get(); -		link_inventory_item(gAgent.getID(), -							item->getLinkedUUID(), -							cat_uuid, -							item->getName(), -							item->getActualDescription(), -							LLAssetType::AT_LINK, -							cb); - -		const LLViewerInventoryCategory *cat = gInventory.getCategory(cat_uuid); -		const std::string cat_name = cat ? cat->getName() : "CAT NOT FOUND"; -#ifndef LL_RELEASE_FOR_DOWNLOAD -		LL_DEBUGS("Avatar") << self_av_string() << "Linking Item [ name:" << item->getName() << " UUID:" << item->getUUID() << " ] to Category [ name:" << cat_name << " UUID:" << cat_uuid << " ] " << LL_ENDL; -#endif -	} -} -  void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append)  {  	LLViewerInventoryCategory *pcat = gInventory.getCategory(category); +	if (!pcat) +	{ +		LL_WARNS() << "no category found for id " << category << LL_ENDL; +		return; +	}  	LL_INFOS("Avatar") << self_av_string() << "starting, cat '" << (pcat ? pcat->getName() : "[UNKNOWN]") << "'" << LL_ENDL;  	const LLUUID cof = getCOF(); @@ -1748,7 +1777,7 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append)  	if (!append)  	{  		LLInventoryModel::item_array_t gest_items; -		getDescendentsOfAssetType(cof, gest_items, LLAssetType::AT_GESTURE, false); +		getDescendentsOfAssetType(cof, gest_items, LLAssetType::AT_GESTURE);  		for(S32 i = 0; i  < gest_items.size(); ++i)  		{  			LLViewerInventoryItem *gest_item = gest_items.at(i); @@ -1765,8 +1794,8 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append)  	// required parts are missing.  	// Preserve body parts from COF if appending.  	LLInventoryModel::item_array_t body_items; -	getDescendentsOfAssetType(cof, body_items, LLAssetType::AT_BODYPART, false); -	getDescendentsOfAssetType(category, body_items, LLAssetType::AT_BODYPART, false); +	getDescendentsOfAssetType(cof, body_items, LLAssetType::AT_BODYPART); +	getDescendentsOfAssetType(category, body_items, LLAssetType::AT_BODYPART);  	if (append)  		reverse(body_items.begin(), body_items.end());  	// Reduce body items to max of one per type. @@ -1776,8 +1805,8 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append)  	// - Wearables: include COF contents only if appending.  	LLInventoryModel::item_array_t wear_items;  	if (append) -		getDescendentsOfAssetType(cof, wear_items, LLAssetType::AT_CLOTHING, false); -	getDescendentsOfAssetType(category, wear_items, LLAssetType::AT_CLOTHING, false); +		getDescendentsOfAssetType(cof, wear_items, LLAssetType::AT_CLOTHING); +	getDescendentsOfAssetType(category, wear_items, LLAssetType::AT_CLOTHING);  	// Reduce wearables to max of one per type.  	removeDuplicateItems(wear_items);  	filterWearableItems(wear_items, LLAgentWearables::MAX_CLOTHING_PER_TYPE); @@ -1785,15 +1814,15 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append)  	// - Attachments: include COF contents only if appending.  	LLInventoryModel::item_array_t obj_items;  	if (append) -		getDescendentsOfAssetType(cof, obj_items, LLAssetType::AT_OBJECT, false); -	getDescendentsOfAssetType(category, obj_items, LLAssetType::AT_OBJECT, false); +		getDescendentsOfAssetType(cof, obj_items, LLAssetType::AT_OBJECT); +	getDescendentsOfAssetType(category, obj_items, LLAssetType::AT_OBJECT);  	removeDuplicateItems(obj_items);  	// - Gestures: include COF contents only if appending.  	LLInventoryModel::item_array_t gest_items;  	if (append) -		getDescendentsOfAssetType(cof, gest_items, LLAssetType::AT_GESTURE, false); -	getDescendentsOfAssetType(category, gest_items, LLAssetType::AT_GESTURE, false); +		getDescendentsOfAssetType(cof, gest_items, LLAssetType::AT_GESTURE); +	getDescendentsOfAssetType(category, gest_items, LLAssetType::AT_GESTURE);  	removeDuplicateItems(gest_items);  	// Create links to new COF contents. @@ -1803,23 +1832,56 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append)  	std::copy(obj_items.begin(), obj_items.end(), std::back_inserter(all_items));  	std::copy(gest_items.begin(), gest_items.end(), std::back_inserter(all_items)); +	// Find any wearables that need description set to enforce ordering. +	desc_map_t desc_map; +	getWearableOrderingDescUpdates(wear_items, desc_map); +  	// Will link all the above items. -	LLPointer<LLInventoryCallback> link_waiter = new LLUpdateAppearanceOnDestroy; -	linkAll(cof,all_items,link_waiter); +	// link_waiter enforce flags are false because we've already fixed everything up in updateCOF(). +	LLPointer<LLInventoryCallback> link_waiter = new LLUpdateAppearanceOnDestroy(false,false); +	LLSD contents = LLSD::emptyArray(); -	// Add link to outfit if category is an outfit.  -	if (!append) +	for (LLInventoryModel::item_array_t::const_iterator it = all_items.begin(); +		 it != all_items.end(); ++it)  	{ -		createBaseOutfitLink(category, link_waiter); -	} +		LLSD item_contents; +		LLInventoryItem *item = *it; -	// Remove current COF contents.  Have to do this after creating -	// the link_waiter so links can be followed for any items that get -	// carried over (e.g. keeping old shape if the new outfit does not -	// contain one) -	bool keep_outfit_links = append; -	purgeCategory(cof, keep_outfit_links, &all_items); -	gInventory.notifyObservers(); +		std::string desc; +		desc_map_t::const_iterator desc_iter = desc_map.find(item->getUUID()); +		if (desc_iter != desc_map.end()) +		{ +			desc = desc_iter->second; +			LL_DEBUGS("Avatar") << item->getName() << " overriding desc to: " << desc +								<< " (was: " << item->getActualDescription() << ")" << LL_ENDL; +		} +		else +		{ +			desc = item->getActualDescription(); +		} + +		item_contents["name"] = item->getName(); +		item_contents["desc"] = desc; +		item_contents["linked_id"] = item->getLinkedUUID(); +		item_contents["type"] = LLAssetType::AT_LINK;  +		contents.append(item_contents); +	} +	const LLUUID& base_id = append ? getBaseOutfitUUID() : category; +	LLViewerInventoryCategory *base_cat = gInventory.getCategory(base_id); +	if (base_cat) +	{ +		LLSD base_contents; +		base_contents["name"] = base_cat->getName(); +		base_contents["desc"] = ""; +		base_contents["linked_id"] = base_cat->getLinkedUUID(); +		base_contents["type"] = LLAssetType::AT_LINK_FOLDER;  +		contents.append(base_contents); +	} +	if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage")) +	{ +		dump_sequential_xml(gAgentAvatarp->getFullname() + "_slam_request", contents); +	} +	slam_inventory_folder(getCOF(), contents, link_waiter);  	LL_DEBUGS("Avatar") << self_av_string() << "waiting for LLUpdateAppearanceOnDestroy" << LL_ENDL;  } @@ -1840,21 +1902,20 @@ void LLAppearanceMgr::createBaseOutfitLink(const LLUUID& category, LLPointer<LLI  	LLViewerInventoryCategory* catp = gInventory.getCategory(category);  	std::string new_outfit_name = ""; -	purgeBaseOutfitLink(cof); +	purgeBaseOutfitLink(cof, link_waiter);  	if (catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT)  	{ -		link_inventory_item(gAgent.getID(), category, cof, catp->getName(), "", -							LLAssetType::AT_LINK_FOLDER, link_waiter); +		link_inventory_object(cof, catp, link_waiter);  		new_outfit_name = catp->getName();  	}  	updatePanelOutfitName(new_outfit_name);  } -void LLAppearanceMgr::updateAgentWearables(LLWearableHoldingPattern* holder, bool append) +void LLAppearanceMgr::updateAgentWearables(LLWearableHoldingPattern* holder)  { -	LL_DEBUGS() << "updateAgentWearables()" << LL_ENDL; +	LL_DEBUGS("Avatar") << "updateAgentWearables()" << LL_ENDL;  	LLInventoryItem::item_array_t items;  	std::vector< LLViewerWearable* > wearables;  	wearables.reserve(32); @@ -1881,10 +1942,15 @@ void LLAppearanceMgr::updateAgentWearables(LLWearableHoldingPattern* holder, boo  	if(wearables.size() > 0)  	{ -		gAgentWearables.setWearableOutfit(items, wearables, !append); +		gAgentWearables.setWearableOutfit(items, wearables);  	}  } +S32 LLAppearanceMgr::countActiveHoldingPatterns() +{ +	return LLWearableHoldingPattern::countActive(); +} +  static void remove_non_link_items(LLInventoryModel::item_array_t &items)  {  	LLInventoryModel::item_array_t pruned_items; @@ -1933,12 +1999,12 @@ void item_array_diff(LLInventoryModel::item_array_t& full_list,  S32 LLAppearanceMgr::findExcessOrDuplicateItems(const LLUUID& cat_id,  												 LLAssetType::EType type,  												 S32 max_items, -												 LLInventoryModel::item_array_t& items_to_kill) +												 LLInventoryObject::object_list_t& items_to_kill)  {  	S32 to_kill_count = 0;  	LLInventoryModel::item_array_t items; -	getDescendentsOfAssetType(cat_id, items, type, false); +	getDescendentsOfAssetType(cat_id, items, type);  	LLInventoryModel::item_array_t curr_items = items;  	removeDuplicateItems(items);  	if (max_items > 0) @@ -1951,40 +2017,39 @@ S32 LLAppearanceMgr::findExcessOrDuplicateItems(const LLUUID& cat_id,  		 it != kill_items.end();  		 ++it)  	{ -		items_to_kill.push_back(*it); +		items_to_kill.push_back(LLPointer<LLInventoryObject>(*it));  		to_kill_count++;  	}  	return to_kill_count;  } -												  -void LLAppearanceMgr::enforceItemRestrictions() -{ -	S32 purge_count = 0; -	LLInventoryModel::item_array_t items_to_kill; -	purge_count += findExcessOrDuplicateItems(getCOF(),LLAssetType::AT_BODYPART, -											  1, items_to_kill); -	purge_count += findExcessOrDuplicateItems(getCOF(),LLAssetType::AT_CLOTHING, -											  LLAgentWearables::MAX_CLOTHING_PER_TYPE, items_to_kill); -	purge_count += findExcessOrDuplicateItems(getCOF(),LLAssetType::AT_OBJECT, -											  -1, items_to_kill); +void LLAppearanceMgr::findAllExcessOrDuplicateItems(const LLUUID& cat_id, +													LLInventoryObject::object_list_t& items_to_kill) +{ +	findExcessOrDuplicateItems(cat_id,LLAssetType::AT_BODYPART, +							   1, items_to_kill); +	findExcessOrDuplicateItems(cat_id,LLAssetType::AT_CLOTHING, +							   LLAgentWearables::MAX_CLOTHING_PER_TYPE, items_to_kill); +	findExcessOrDuplicateItems(cat_id,LLAssetType::AT_OBJECT, +							   -1, items_to_kill); +} +void LLAppearanceMgr::enforceCOFItemRestrictions(LLPointer<LLInventoryCallback> cb) +{ +	LLInventoryObject::object_list_t items_to_kill; +	findAllExcessOrDuplicateItems(getCOF(), items_to_kill);  	if (items_to_kill.size()>0)  	{ -		for (LLInventoryModel::item_array_t::iterator it = items_to_kill.begin(); -			 it != items_to_kill.end(); -			 ++it) -		{ -			LLViewerInventoryItem *item = *it; -			LL_DEBUGS("Avatar") << self_av_string() << "purging duplicate or excess item " << item->getName() << LL_ENDL; -			gInventory.purgeObject(item->getUUID()); -		} -		gInventory.notifyObservers(); +		// Remove duplicate or excess wearables. Should normally be enforced at the UI level, but +		// this should catch anything that gets through. +		remove_inventory_items(items_to_kill, cb);  	}  } -void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering) +void LLAppearanceMgr::updateAppearanceFromCOF(bool enforce_item_restrictions, +											  bool enforce_ordering, +											  nullary_func_t post_update_func)  {  	if (mIsInUpdateAppearanceFromCOF)  	{ @@ -1992,19 +2057,43 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering)  		return;  	} -	BoolSetter setIsInUpdateAppearanceFromCOF(mIsInUpdateAppearanceFromCOF); -	selfStartPhase("update_appearance_from_cof"); -  	LL_DEBUGS("Avatar") << self_av_string() << "starting" << LL_ENDL; -	//checking integrity of the COF in terms of ordering of wearables,  -	//checking and updating links' descriptions of wearables in the COF (before analyzed for "dirty" state) -	updateClothingOrderingInfo(LLUUID::null, update_base_outfit_ordering); +	if (enforce_item_restrictions) +	{ +		// The point here is just to call +		// updateAppearanceFromCOF() again after excess items +		// have been removed. That time we will set +		// enforce_item_restrictions to false so we don't get +		// caught in a perpetual loop. +		LLPointer<LLInventoryCallback> cb( +			new LLUpdateAppearanceOnDestroy(false, enforce_ordering, post_update_func)); +		enforceCOFItemRestrictions(cb); +		return; +	} + +	if (enforce_ordering) +	{ +		//checking integrity of the COF in terms of ordering of wearables,  +		//checking and updating links' descriptions of wearables in the COF (before analyzed for "dirty" state) + +		// As with enforce_item_restrictions handling above, we want +		// to wait for the update callbacks, then (finally!) call +		// updateAppearanceFromCOF() with no additional COF munging needed. +		LLPointer<LLInventoryCallback> cb( +			new LLUpdateAppearanceOnDestroy(false, false, post_update_func)); +		updateClothingOrderingInfo(LLUUID::null, cb); +		return; +	} + +	if (!validateClothingOrderingInfo()) +	{ +		LL_WARNS() << "Clothing ordering error" << LL_ENDL; +	} + +	BoolSetter setIsInUpdateAppearanceFromCOF(mIsInUpdateAppearanceFromCOF); +	selfStartPhase("update_appearance_from_cof"); -	// Remove duplicate or excess wearables. Should normally be enforced at the UI level, but -	// this should catch anything that gets through. -	enforceItemRestrictions(); -	  	// update dirty flag to see if the state of the COF matches  	// the saved outfit stored as a folder link  	updateIsDirty(); @@ -2014,13 +2103,7 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering)  	{  		requestServerAppearanceUpdate();  	} -	// DRANO really should wait for the appearance message to set this. -	// verify that deleting this line doesn't break anything. -	//gAgentAvatarp->setIsUsingServerBakes(gAgent.getRegion() && gAgent.getRegion()->getCentralBakeVersion()); -	 -	//dumpCat(getCOF(),"COF, start"); -	bool follow_folder_links = false;  	LLUUID current_outfit_id = getCOF();  	// Find all the wearables that are in the COF's subtree. @@ -2028,7 +2111,7 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering)  	LLInventoryModel::item_array_t wear_items;  	LLInventoryModel::item_array_t obj_items;  	LLInventoryModel::item_array_t gest_items; -	getUserDescendents(current_outfit_id, wear_items, obj_items, gest_items, follow_folder_links); +	getUserDescendents(current_outfit_id, wear_items, obj_items, gest_items);  	// Get rid of non-links in case somehow the COF was corrupted.  	remove_non_link_items(wear_items);  	remove_non_link_items(obj_items); @@ -2037,6 +2120,13 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering)  	dumpItemArray(wear_items,"asset_dump: wear_item");  	dumpItemArray(obj_items,"asset_dump: obj_item"); +	LLViewerInventoryCategory *cof = gInventory.getCategory(current_outfit_id); +	if (!gInventory.isCategoryComplete(current_outfit_id)) +	{ +		LL_WARNS() << "COF info is not complete. Version " << cof->getVersion() +				<< " descendent_count " << cof->getDescendentCount() +				<< " viewer desc count " << cof->getViewerDescendentCount() << LL_ENDL; +	}  	if(!wear_items.size())  	{  		LLNotificationsUtil::add("CouldNotPutOnOutfit"); @@ -2047,6 +2137,8 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering)  	sortItemsByActualDescription(wear_items); +	LL_DEBUGS("Avatar") << "HP block starts" << LL_ENDL; +	LLTimer hp_block_timer;  	LLWearableHoldingPattern* holder = new LLWearableHoldingPattern;  	holder->setObjItems(obj_items); @@ -2096,7 +2188,7 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering)  		}  	} -	selfStartPhase("get_wearables"); +	selfStartPhase("get_wearables_2");  	for (LLWearableHoldingPattern::found_list_t::iterator it = holder->getFoundList().begin();  		 it != holder->getFoundList().end(); ++it) @@ -2120,12 +2212,14 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering)  	{  		doOnIdleRepeating(boost::bind(&LLWearableHoldingPattern::pollFetchCompletion,holder));  	} +	post_update_func(); + +	LL_DEBUGS("Avatar") << "HP block ends, elapsed " << hp_block_timer.getElapsedTimeF32() << LL_ENDL;  }  void LLAppearanceMgr::getDescendentsOfAssetType(const LLUUID& category,  													LLInventoryModel::item_array_t& items, -													LLAssetType::EType type, -													bool follow_folder_links) +													LLAssetType::EType type)  {  	LLInventoryModel::cat_array_t cats;  	LLIsType is_of_type(type); @@ -2133,15 +2227,13 @@ void LLAppearanceMgr::getDescendentsOfAssetType(const LLUUID& category,  									cats,  									items,  									LLInventoryModel::EXCLUDE_TRASH, -									is_of_type, -									follow_folder_links); +									is_of_type);  }  void LLAppearanceMgr::getUserDescendents(const LLUUID& category,   											 LLInventoryModel::item_array_t& wear_items,  											 LLInventoryModel::item_array_t& obj_items, -											 LLInventoryModel::item_array_t& gest_items, -											 bool follow_folder_links) +											 LLInventoryModel::item_array_t& gest_items)  {  	LLInventoryModel::cat_array_t wear_cats;  	LLFindWearables is_wearable; @@ -2149,8 +2241,7 @@ void LLAppearanceMgr::getUserDescendents(const LLUUID& category,  									wear_cats,  									wear_items,  									LLInventoryModel::EXCLUDE_TRASH, -									is_wearable, -									follow_folder_links); +									is_wearable);  	LLInventoryModel::cat_array_t obj_cats;  	LLIsType is_object( LLAssetType::AT_OBJECT ); @@ -2158,8 +2249,7 @@ void LLAppearanceMgr::getUserDescendents(const LLUUID& category,  									obj_cats,  									obj_items,  									LLInventoryModel::EXCLUDE_TRASH, -									is_object, -									follow_folder_links); +									is_object);  	// Find all gestures in this folder  	LLInventoryModel::cat_array_t gest_cats; @@ -2168,8 +2258,7 @@ void LLAppearanceMgr::getUserDescendents(const LLUUID& category,  									gest_cats,  									gest_items,  									LLInventoryModel::EXCLUDE_TRASH, -									is_gesture, -									follow_folder_links); +									is_gesture);  }  void LLAppearanceMgr::wearInventoryCategory(LLInventoryCategory* category, bool copy, bool append) @@ -2184,10 +2273,36 @@ void LLAppearanceMgr::wearInventoryCategory(LLInventoryCategory* category, bool  	LL_INFOS("Avatar") << self_av_string() << "wearInventoryCategory( " << category->getName()  			 << " )" << LL_ENDL; -	selfStartPhase("wear_inventory_category_fetch"); -	callAfterCategoryFetch(category->getUUID(),boost::bind(&LLAppearanceMgr::wearCategoryFinal, -														   &LLAppearanceMgr::instance(), -														   category->getUUID(), copy, append)); +	// If we are copying from library, attempt to use AIS to copy the category. +	bool ais_ran=false; +	if (copy && AISCommand::isAPIAvailable()) +	{ +		LLUUID parent_id; +		parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CLOTHING); +		if (parent_id.isNull()) +		{ +			parent_id = gInventory.getRootFolderID(); +		} + +		LLPointer<LLInventoryCallback> copy_cb = new LLWearCategoryAfterCopy(append); +		LLPointer<LLInventoryCallback> track_cb = new LLTrackPhaseWrapper( +													std::string("wear_inventory_category_callback"), copy_cb); +		LLPointer<AISCommand> cmd_ptr = new CopyLibraryCategoryCommand(category->getUUID(), parent_id, track_cb); +		ais_ran=cmd_ptr->run_command(); +	} + +	if (!ais_ran) +	{ +		selfStartPhase("wear_inventory_category_fetch"); +		callAfterCategoryFetch(category->getUUID(),boost::bind(&LLAppearanceMgr::wearCategoryFinal, +															   &LLAppearanceMgr::instance(), +															   category->getUUID(), copy, append)); +	} +} + +S32 LLAppearanceMgr::getActiveCopyOperations() const +{ +	return LLCallAfterInventoryCopyMgr::getInstanceCount();   }  void LLAppearanceMgr::wearCategoryFinal(LLUUID& cat_id, bool copy_items, bool append) @@ -2268,7 +2383,7 @@ void LLAppearanceMgr::wearInventoryCategoryOnAvatar( LLInventoryCategory* catego  	// Avoid unintentionally overwriting old wearables.  We have to do  	// this up front to avoid having to deal with the case of multiple  	// wearables being dirty. -	if(!category) return; +	if (!category) return;  	if ( !LLInventoryCallbackManager::is_instantiated() )  	{ @@ -2288,6 +2403,7 @@ void LLAppearanceMgr::wearInventoryCategoryOnAvatar( LLInventoryCategory* catego  	LLAppearanceMgr::changeOutfit(TRUE, category->getUUID(), append);  } +// FIXME do we really want to search entire inventory for matching name?  void LLAppearanceMgr::wearOutfitByName(const std::string& name)  {  	LL_INFOS("Avatar") << self_av_string() << "Wearing category " << name << LL_ENDL; @@ -2341,9 +2457,8 @@ bool areMatchingWearables(const LLViewerInventoryItem *a, const LLViewerInventor  class LLDeferredCOFLinkObserver: public LLInventoryObserver  {  public: -	LLDeferredCOFLinkObserver(const LLUUID& item_id, bool do_update, LLPointer<LLInventoryCallback> cb = NULL, std::string description = ""): +	LLDeferredCOFLinkObserver(const LLUUID& item_id, LLPointer<LLInventoryCallback> cb, const std::string& description):  		mItemID(item_id), -		mDoUpdate(do_update),  		mCallback(cb),  		mDescription(description)  	{ @@ -2359,14 +2474,13 @@ public:  		if (item)  		{  			gInventory.removeObserver(this); -			LLAppearanceMgr::instance().addCOFItemLink(item,mDoUpdate,mCallback); +			LLAppearanceMgr::instance().addCOFItemLink(item, mCallback, mDescription);  			delete this;  		}  	}  private:  	const LLUUID mItemID; -	bool mDoUpdate;  	std::string mDescription;  	LLPointer<LLInventoryCallback> mCallback;  }; @@ -2374,42 +2488,26 @@ private:  // BAP - note that this runs asynchronously if the item is not already loaded from inventory.  // Dangerous if caller assumes link will exist after calling the function. -void LLAppearanceMgr::addCOFItemLink(const LLUUID &item_id, bool do_update, LLPointer<LLInventoryCallback> cb, const std::string description) +void LLAppearanceMgr::addCOFItemLink(const LLUUID &item_id, +									 LLPointer<LLInventoryCallback> cb, +									 const std::string description)  {  	const LLInventoryItem *item = gInventory.getItem(item_id);  	if (!item)  	{ -		LLDeferredCOFLinkObserver *observer = new LLDeferredCOFLinkObserver(item_id, do_update, cb, description); +		LLDeferredCOFLinkObserver *observer = new LLDeferredCOFLinkObserver(item_id, cb, description);  		gInventory.addObserver(observer);  	}  	else  	{ -		addCOFItemLink(item, do_update, cb, description); -	} -} - -void modified_cof_cb(const LLUUID& inv_item) -{		 -	LLAppearanceMgr::instance().updateAppearanceFromCOF(); - -	// Start editing the item if previously requested. -	gAgentWearables.editWearableIfRequested(inv_item); - -	// TODO: camera mode may not be changed if a debug setting is tweaked -	if( gAgentCamera.cameraCustomizeAvatar() ) -	{ -		// If we're in appearance editing mode, the current tab may need to be refreshed -		LLSidepanelAppearance *panel = dynamic_cast<LLSidepanelAppearance*>(LLFloaterSidePanelContainer::getPanel("appearance")); -		if (panel) -		{ -			panel->showDefaultSubpart(); -		} +		addCOFItemLink(item, cb, description);  	}  } -void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item, bool do_update, LLPointer<LLInventoryCallback> cb, const std::string description) -{		 -	std::string link_description = description; +void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item, +									 LLPointer<LLInventoryCallback> cb, +									 const std::string description) +{  	const LLViewerInventoryItem *vitem = dynamic_cast<const LLViewerInventoryItem*>(item);  	if (!vitem)  	{ @@ -2449,43 +2547,23 @@ void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item, bool do_update  			++count;  			if (is_body_part && inv_item->getIsLinkType()  && (vitem->getWearableType() == wearable_type))  			{ -				gInventory.purgeObject(inv_item->getUUID()); +				remove_inventory_item(inv_item->getUUID(), cb);  			}  			else if (count >= LLAgentWearables::MAX_CLOTHING_PER_TYPE)  			{  				// MULTI-WEARABLES: make sure we don't go over MAX_CLOTHING_PER_TYPE -				gInventory.purgeObject(inv_item->getUUID()); +				remove_inventory_item(inv_item->getUUID(), cb);  			}  		}  	} -	if (linked_already) -	{ -		if (do_update) -		{	 -			LLAppearanceMgr::updateAppearanceFromCOF(); -		} -		return; -	} -	else +	if (!linked_already)  	{ -		if(do_update && cb.isNull()) -		{ -			cb = new LLBoostFuncInventoryCallback(modified_cof_cb); -		} -		if (vitem->getIsLinkType()) -		{ -			link_description = vitem->getActualDescription(); -		} -		link_inventory_item( gAgent.getID(), -							 vitem->getLinkedUUID(), -							 getCOF(), -							 vitem->getName(), -							 link_description, -							 LLAssetType::AT_LINK, -							 cb); +		LLViewerInventoryItem *copy_item = new LLViewerInventoryItem; +		copy_item->copyViewerItem(vitem); +		copy_item->setDescription(description); +		link_inventory_object(getCOF(), copy_item, cb);  	} -	return;  }  LLInventoryModel::item_array_t LLAppearanceMgr::findCOFItemLinks(const LLUUID& item_id) @@ -2515,6 +2593,12 @@ LLInventoryModel::item_array_t LLAppearanceMgr::findCOFItemLinks(const LLUUID& i  	return result;  } +bool LLAppearanceMgr::isLinkedInCOF(const LLUUID& item_id) +{ +	LLInventoryModel::item_array_t links = LLAppearanceMgr::instance().findCOFItemLinks(item_id); +	return links.size() > 0; +} +  void LLAppearanceMgr::removeAllClothesFromAvatar()  {  	// Fetch worn clothes (i.e. the ones in COF). @@ -2525,8 +2609,7 @@ void LLAppearanceMgr::removeAllClothesFromAvatar()  									dummy,  									clothing_items,  									LLInventoryModel::EXCLUDE_TRASH, -									is_clothing, -									false); +									is_clothing);  	uuid_vec_t item_ids;  	for (LLInventoryModel::item_array_t::iterator it = clothing_items.begin();  		it != clothing_items.end(); ++it) @@ -2570,7 +2653,7 @@ void LLAppearanceMgr::removeAllAttachmentsFromAvatar()  	removeItemsFromAvatar(ids_to_remove);  } -void LLAppearanceMgr::removeCOFItemLinks(const LLUUID& item_id) +void LLAppearanceMgr::removeCOFItemLinks(const LLUUID& item_id, LLPointer<LLInventoryCallback> cb)  {  	gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); @@ -2585,12 +2668,12 @@ void LLAppearanceMgr::removeCOFItemLinks(const LLUUID& item_id)  		const LLInventoryItem* item = item_array.at(i).get();  		if (item->getIsLinkType() && item->getLinkedUUID() == item_id)  		{ -			gInventory.purgeObject(item->getUUID()); +			remove_inventory_item(item->getUUID(), cb);  		}  	}  } -void LLAppearanceMgr::removeCOFLinksOfType(LLWearableType::EType type) +void LLAppearanceMgr::removeCOFLinksOfType(LLWearableType::EType type, LLPointer<LLInventoryCallback> cb)  {  	LLFindWearablesOfType filter_wearables_of_type(type);  	LLInventoryModel::cat_array_t cats; @@ -2603,7 +2686,7 @@ void LLAppearanceMgr::removeCOFLinksOfType(LLWearableType::EType type)  		const LLViewerInventoryItem* item = *it;  		if (item->getIsLinkType()) // we must operate on links only  		{ -			gInventory.purgeObject(item->getUUID()); +			remove_inventory_item(item->getUUID(), cb);  		}  	}  } @@ -2642,7 +2725,7 @@ void LLAppearanceMgr::updateIsDirty()  	if (base_outfit.notNull())  	{ -		LLIsOfAssetType collector = LLIsOfAssetType(LLAssetType::AT_LINK); +		LLIsValidItemLink collector;  		LLInventoryModel::cat_array_t cof_cats;  		LLInventoryModel::item_array_t cof_items; @@ -2656,6 +2739,7 @@ void LLAppearanceMgr::updateIsDirty()  		if(outfit_items.size() != cof_items.size())  		{ +			LL_DEBUGS("Avatar") << "item count different - base " << outfit_items.size() << " cof " << cof_items.size() << LL_ENDL;  			// Current outfit folder should have one more item than the outfit folder.  			// this one item is the link back to the outfit folder itself.  			mOutfitIsDirty = true; @@ -2675,11 +2759,30 @@ void LLAppearanceMgr::updateIsDirty()  				item1->getName() != item2->getName() ||  				item1->getActualDescription() != item2->getActualDescription())  			{ +				if (item1->getLinkedUUID() != item2->getLinkedUUID()) +				{ +					LL_DEBUGS("Avatar") << "link id different " << LL_ENDL; +				} +				else +				{ +					if (item1->getName() != item2->getName()) +					{ +						LL_DEBUGS("Avatar") << "name different " << item1->getName() << " " << item2->getName() << LL_ENDL; +					} +					if (item1->getActualDescription() != item2->getActualDescription()) +					{ +						LL_DEBUGS("Avatar") << "desc different " << item1->getActualDescription() +											<< " " << item2->getActualDescription()  +											<< " names " << item1->getName() << " " << item2->getName() << LL_ENDL; +					} +				}  				mOutfitIsDirty = true;  				return;  			}  		}  	} +	llassert(!mOutfitIsDirty); +	LL_DEBUGS("Avatar") << "clean" << LL_ENDL;  }  // *HACK: Must match name in Library or agent inventory @@ -2761,23 +2864,6 @@ void LLAppearanceMgr::copyLibraryGestures()  	}  } -void LLAppearanceMgr::autopopulateOutfits() -{ -	// If this is the very first time the user has logged into viewer2+ (from a legacy viewer, or new account) -	// then auto-populate outfits from the library into the My Outfits folder. - -	LL_INFOS("Avatar") << self_av_string() << "avatar fully visible" << LL_ENDL; - -	static bool check_populate_my_outfits = true; -	if (check_populate_my_outfits &&  -		(LLInventoryModel::getIsFirstTimeInViewer2()  -		 || gSavedSettings.getBOOL("MyOutfitsAutofill"))) -	{ -		gAgentWearables.populateMyOutfitsFolder(); -	} -	check_populate_my_outfits = false; -} -  // Handler for anything that's deferred until avatar de-clouds.  void LLAppearanceMgr::onFirstFullyVisible()  { @@ -2785,10 +2871,6 @@ void LLAppearanceMgr::onFirstFullyVisible()  	gAgentAvatarp->reportAvatarRezTime();  	gAgentAvatarp->debugAvatarVisible(); -	// The auto-populate is failing at the point of generating outfits -	// folders, so don't do the library copy until that is resolved. -	// autopopulateOutfits(); -  	// If this is the first time we've ever logged in,  	// then copy default gestures from the library.  	if (gAgent.isFirstLogin()) { @@ -2803,9 +2885,27 @@ void appearance_mgr_update_dirty_state()  	if (LLAppearanceMgr::instanceExists())  	{  		LLAppearanceMgr::getInstance()->updateIsDirty(); +		LLAppearanceMgr::getInstance()->setOutfitLocked(false); +		gAgentWearables.notifyLoadingFinished();  	}  } +void update_base_outfit_after_ordering() +{ +	LLAppearanceMgr& app_mgr = LLAppearanceMgr::instance(); +	 +	LLPointer<LLInventoryCallback> dirty_state_updater = +		new LLBoostFuncInventoryCallback(no_op_inventory_func, appearance_mgr_update_dirty_state); + +	//COF contains only links so we copy to the Base Outfit only links +	const LLUUID base_outfit_id = app_mgr.getBaseOutfitUUID(); +	bool copy_folder_links = false; +	app_mgr.slamCategoryLinks(app_mgr.getCOF(), base_outfit_id, copy_folder_links, dirty_state_updater); + +} + +// Save COF changes - update the contents of the current base outfit +// to match the current COF. Fails if no current base outfit is set.  bool LLAppearanceMgr::updateBaseOutfit()  {  	if (isOutfitLocked()) @@ -2814,23 +2914,20 @@ bool LLAppearanceMgr::updateBaseOutfit()  		llassert(!isOutfitLocked());  		return false;  	} +  	setOutfitLocked(true);  	gAgentWearables.notifyLoadingStarted();  	const LLUUID base_outfit_id = getBaseOutfitUUID();  	if (base_outfit_id.isNull()) return false; +	LL_DEBUGS("Avatar") << "saving cof to base outfit " << base_outfit_id << LL_ENDL; -	updateClothingOrderingInfo(); - -	// in a Base Outfit we do not remove items, only links -	purgeCategory(base_outfit_id, false); - -	LLPointer<LLInventoryCallback> dirty_state_updater = -		new LLBoostFuncInventoryCallback(no_op_inventory_func, appearance_mgr_update_dirty_state); - -	//COF contains only links so we copy to the Base Outfit only links -	shallowCopyCategoryContents(getCOF(), base_outfit_id, dirty_state_updater); +	LLPointer<LLInventoryCallback> cb = +		new LLBoostFuncInventoryCallback(no_op_inventory_func, update_base_outfit_after_ordering); +	// Really shouldn't be needed unless there's a race condition - +	// updateAppearanceFromCOF() already calls updateClothingOrderingInfo. +	updateClothingOrderingInfo(LLUUID::null, cb);  	return true;  } @@ -2878,12 +2975,6 @@ struct WearablesOrderComparator  	bool operator()(const LLInventoryItem* item1, const LLInventoryItem* item2)  	{ -		if (!item1 || !item2) -		{ -			LL_WARNS() << "either item1 or item2 is NULL" << LL_ENDL; -			return true; -		} -		  		const std::string& desc1 = item1->getActualDescription();  		const std::string& desc2 = item2->getActualDescription(); @@ -2897,260 +2988,373 @@ struct WearablesOrderComparator  		//items with ordering information but not for the associated wearables type  		if (!item1_valid && item2_valid)   			return false; +		else if (item1_valid && !item2_valid) +			return true; -		return true; +		return item1->getName() < item2->getName();  	}  	U32 mControlSize;  }; -void LLAppearanceMgr::updateClothingOrderingInfo(LLUUID cat_id, bool update_base_outfit_ordering) +void LLAppearanceMgr::getWearableOrderingDescUpdates(LLInventoryModel::item_array_t& wear_items, +													 desc_map_t& desc_map)  { -	if (cat_id.isNull()) -	{ -		cat_id = getCOF(); -		if (update_base_outfit_ordering) -		{ -			const LLUUID base_outfit_id = getBaseOutfitUUID(); -			if (base_outfit_id.notNull()) -			{ -				updateClothingOrderingInfo(base_outfit_id,false); -			} -		} -	} - -	// COF is processed if cat_id is not specified -	LLInventoryModel::item_array_t wear_items; -	getDescendentsOfAssetType(cat_id, wear_items, LLAssetType::AT_CLOTHING, false); -  	wearables_by_type_t items_by_type(LLWearableType::WT_COUNT);  	divvyWearablesByType(wear_items, items_by_type); -	bool inventory_changed = false;  	for (U32 type = LLWearableType::WT_SHIRT; type < LLWearableType::WT_COUNT; type++)  	{ -		  		U32 size = items_by_type[type].size();  		if (!size) continue; - +		  		//sinking down invalid items which need reordering  		std::sort(items_by_type[type].begin(), items_by_type[type].end(), WearablesOrderComparator((LLWearableType::EType) type)); - +		  		//requesting updates only for those links which don't have "valid" descriptions  		for (U32 i = 0; i < size; i++)  		{  			LLViewerInventoryItem* item = items_by_type[type][i];  			if (!item) continue; - +			  			std::string new_order_str = build_order_string((LLWearableType::EType)type, i);  			if (new_order_str == item->getActualDescription()) continue; - -			item->setDescription(new_order_str); -			item->setComplete(TRUE); - 			item->updateServer(FALSE); -			gInventory.updateItem(item); -			inventory_changed = true; +			desc_map[item->getUUID()] = new_order_str;  		}  	} - -	//*TODO do we really need to notify observers? -	if (inventory_changed) gInventory.notifyObservers();  } -// This is intended for use with HTTP Clients/Responders, but is not -// specifically coupled with those classes. -class LLHTTPRetryPolicy: public LLThreadSafeRefCount +bool LLAppearanceMgr::validateClothingOrderingInfo(LLUUID cat_id)  { -public: -	LLHTTPRetryPolicy() {} -	virtual ~LLHTTPRetryPolicy() {} -	virtual bool shouldRetry(U32 status, F32& seconds_to_wait) = 0; -}; +	// COF is processed if cat_id is not specified +	if (cat_id.isNull()) +	{ +		cat_id = getCOF(); +	} -// Example of simplest possible policy, not necessarily recommended. -class LLAlwaysRetryImmediatelyPolicy: public LLHTTPRetryPolicy -{ -public: -	LLAlwaysRetryImmediatelyPolicy() {} -	bool shouldRetry(U32 status, F32& seconds_to_wait) +	LLInventoryModel::item_array_t wear_items; +	getDescendentsOfAssetType(cat_id, wear_items, LLAssetType::AT_CLOTHING); + +	// Identify items for which desc needs to change. +	desc_map_t desc_map; +	getWearableOrderingDescUpdates(wear_items, desc_map); + +	for (desc_map_t::const_iterator it = desc_map.begin(); +		 it != desc_map.end(); ++it)  	{ -		seconds_to_wait = 0.0; -		return true; +		const LLUUID& item_id = it->first; +		const std::string& new_order_str = it->second; +		LLViewerInventoryItem *item = gInventory.getItem(item_id); +		LL_WARNS() << "Order validation fails: " << item->getName() +				<< " needs to update desc to: " << new_order_str +				<< " (from: " << item->getActualDescription() << ")" << LL_ENDL;  	} -}; +	 +	return desc_map.size() == 0; +} -// Very general policy with geometric back-off after failures, -// up to a maximum delay, and maximum number of retries. -class LLAdaptiveRetryPolicy: public LLHTTPRetryPolicy +void LLAppearanceMgr::updateClothingOrderingInfo(LLUUID cat_id, +												 LLPointer<LLInventoryCallback> cb)  { -public: -	LLAdaptiveRetryPolicy(F32 min_delay, F32 max_delay, F32 backoff_factor, U32 max_retries): -		mMinDelay(min_delay), -		mMaxDelay(max_delay), -		mBackoffFactor(backoff_factor), -		mMaxRetries(max_retries), -		mDelay(min_delay), -		mRetryCount(0) +	// COF is processed if cat_id is not specified +	if (cat_id.isNull())  	{ +		cat_id = getCOF();  	} -	bool shouldRetry(U32 status, F32& seconds_to_wait) +	LLInventoryModel::item_array_t wear_items; +	getDescendentsOfAssetType(cat_id, wear_items, LLAssetType::AT_CLOTHING); + +	// Identify items for which desc needs to change. +	desc_map_t desc_map; +	getWearableOrderingDescUpdates(wear_items, desc_map); + +	for (desc_map_t::const_iterator it = desc_map.begin(); +		 it != desc_map.end(); ++it)  	{ -		seconds_to_wait = mDelay; -		mDelay = llclamp(mDelay*mBackoffFactor,mMinDelay,mMaxDelay); -		mRetryCount++; -		return (mRetryCount<=mMaxRetries); +		LLSD updates; +		const LLUUID& item_id = it->first; +		const std::string& new_order_str = it->second; +		LLViewerInventoryItem *item = gInventory.getItem(item_id); +		LL_DEBUGS("Avatar") << item->getName() << " updating desc to: " << new_order_str +			<< " (was: " << item->getActualDescription() << ")" << LL_ENDL; +		updates["desc"] = new_order_str; +		update_inventory_item(item_id,updates,cb);  	} +		 +} + +class RequestAgentUpdateAppearanceResponder: public LLHTTPClient::Responder +{ +	LOG_CLASS(RequestAgentUpdateAppearanceResponder); + +	friend class LLAppearanceMgr; +	 +public: +	RequestAgentUpdateAppearanceResponder(); + +	virtual ~RequestAgentUpdateAppearanceResponder();  private: -	F32 mMinDelay; // delay never less than this value -	F32 mMaxDelay; // delay never exceeds this value -	F32 mBackoffFactor; // delay increases by this factor after each retry, up to mMaxDelay. -	U32 mMaxRetries; // maximum number of times shouldRetry will return true. -	F32 mDelay; // current delay. -	U32 mRetryCount; // number of times shouldRetry has been called. +	// Called when sendServerAppearanceUpdate called. May or may not +	// trigger a request depending on various bits of state. +	void onRequestRequested(); + +	// Post the actual appearance request to cap. +	void sendRequest(); + +	void debugCOF(const LLSD& content); + +protected: +	// Successful completion. +	/* virtual */ void httpSuccess(); + +	// Error +	/*virtual*/ void httpFailure(); + +	void onFailure(); +	void onSuccess(); + +	S32 mInFlightCounter; +	LLTimer mInFlightTimer; +	LLPointer<LLHTTPRetryPolicy> mRetryPolicy;  }; -class RequestAgentUpdateAppearanceResponder: public LLHTTPClient::Responder +RequestAgentUpdateAppearanceResponder::RequestAgentUpdateAppearanceResponder()  { -public: -	RequestAgentUpdateAppearanceResponder() +	bool retry_on_4xx = true; +	mRetryPolicy = new LLAdaptiveRetryPolicy(1.0, 32.0, 2.0, 10, retry_on_4xx); +	mInFlightCounter = 0; +} + +RequestAgentUpdateAppearanceResponder::~RequestAgentUpdateAppearanceResponder() +{ +} + +void RequestAgentUpdateAppearanceResponder::onRequestRequested() +{ +	// If we have already received an update for this or higher cof version, ignore. +	S32 cof_version = LLAppearanceMgr::instance().getCOFVersion(); +	S32 last_rcv = gAgentAvatarp->mLastUpdateReceivedCOFVersion; +	S32 last_req = gAgentAvatarp->mLastUpdateRequestCOFVersion; +	LL_DEBUGS("Avatar") << "cof_version " << cof_version +						<< " last_rcv " << last_rcv +						<< " last_req " << last_req +						<< " in flight " << mInFlightCounter << LL_ENDL; +	if ((mInFlightCounter>0) && (mInFlightTimer.hasExpired()))  	{ -		mRetryPolicy = new LLAdaptiveRetryPolicy(1.0, 32.0, 2.0, 10); +		LL_WARNS("Avatar") << "in flight timer expired, resetting " << LL_ENDL; +		mInFlightCounter = 0; +	} +	if (cof_version < last_rcv) +	{ +		LL_DEBUGS("Avatar") << "Have already received update for cof version " << last_rcv +							<< " will not request for " << cof_version << LL_ENDL; +		return; +	} +	if (mInFlightCounter>0 && last_req >= cof_version) +	{ +		LL_DEBUGS("Avatar") << "Request already in flight for cof version " << last_req  +							<< " will not request for " << cof_version << LL_ENDL; +		return;  	} -	virtual ~RequestAgentUpdateAppearanceResponder() +	// Actually send the request. +	LL_DEBUGS("Avatar") << "Will send request for cof_version " << cof_version << LL_ENDL; +	mRetryPolicy->reset(); +	sendRequest(); +} +	 +void RequestAgentUpdateAppearanceResponder::sendRequest() +{ +	if (gAgentAvatarp->isEditingAppearance())   	{ +		// don't send out appearance updates if in appearance editing mode +		return;  	} -	// Successful completion. -	/* virtual */ void result(const LLSD& content) +	if (!gAgent.getRegion())  	{ -		LL_DEBUGS("Avatar") << "content: " << ll_pretty_print_sd(content) << LL_ENDL; -		if (content["success"].asBoolean()) +		LL_WARNS() << "Region not set, cannot request server appearance update" << LL_ENDL; +		return; +	} +	if (gAgent.getRegion()->getCentralBakeVersion()==0) +	{ +		LL_WARNS() << "Region does not support baking" << LL_ENDL; +	} +	std::string url = gAgent.getRegion()->getCapability("UpdateAvatarAppearance");	 +	if (url.empty()) +	{ +		LL_WARNS() << "No cap for UpdateAvatarAppearance." << LL_ENDL; +		return; +	} +	 +	LLSD body; +	S32 cof_version = LLAppearanceMgr::instance().getCOFVersion(); +	if (gSavedSettings.getBOOL("DebugAvatarExperimentalServerAppearanceUpdate")) +	{ +		body = LLAppearanceMgr::instance().dumpCOF(); +	} +	else +	{ +		body["cof_version"] = cof_version; +		if (gSavedSettings.getBOOL("DebugForceAppearanceRequestFailure"))  		{ -			LL_DEBUGS("Avatar") << "OK" << LL_ENDL; -			if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage")) +			body["cof_version"] = cof_version+999; +		} +	} +	LL_DEBUGS("Avatar") << "request url " << url << " my_cof_version " << cof_version << LL_ENDL; + +	mInFlightCounter++; +	mInFlightTimer.setTimerExpirySec(60.0); +	LLHTTPClient::post(url, body, this); +	llassert(cof_version >= gAgentAvatarp->mLastUpdateRequestCOFVersion); +	gAgentAvatarp->mLastUpdateRequestCOFVersion = cof_version; +} + +void RequestAgentUpdateAppearanceResponder::debugCOF(const LLSD& content) +{ +	LL_INFOS("Avatar") << "AIS COF, version received: " << content["expected"].asInteger() +					   << " ================================= " << LL_ENDL; +	std::set<LLUUID> ais_items, local_items; +	const LLSD& cof_raw = content["cof_raw"]; +	for (LLSD::array_const_iterator it = cof_raw.beginArray(); +		 it != cof_raw.endArray(); ++it) +	{ +		const LLSD& item = *it; +		if (item["parent_id"].asUUID() == LLAppearanceMgr::instance().getCOF()) +		{ +			ais_items.insert(item["item_id"].asUUID()); +			if (item["type"].asInteger() == 24) // link +			{ +				LL_INFOS("Avatar") << "AIS Link: item_id: " << item["item_id"].asUUID() +								   << " linked_item_id: " << item["asset_id"].asUUID() +								   << " name: " << item["name"].asString() +								   << LL_ENDL;  +			} +			else if (item["type"].asInteger() == 25) // folder link +			{ +				LL_INFOS("Avatar") << "AIS Folder link: item_id: " << item["item_id"].asUUID() +								   << " linked_item_id: " << item["asset_id"].asUUID() +								   << " name: " << item["name"].asString() +								   << LL_ENDL;  +			} +			else  			{ -				dumpContents(gAgentAvatarp->getFullname() + "_appearance_request_ok", content); +				LL_INFOS("Avatar") << "AIS Other: item_id: " << item["item_id"].asUUID() +								   << " linked_item_id: " << item["asset_id"].asUUID() +								   << " name: " << item["name"].asString() +								   << " type: " << item["type"].asInteger() +								   << LL_ENDL;   			}  		} -		else +	} +	LL_INFOS("Avatar") << LL_ENDL; +	LL_INFOS("Avatar") << "Local COF, version requested: " << content["observed"].asInteger()  +					   << " ================================= " << LL_ENDL; +	LLInventoryModel::cat_array_t cat_array; +	LLInventoryModel::item_array_t item_array; +	gInventory.collectDescendents(LLAppearanceMgr::instance().getCOF(), +								  cat_array,item_array,LLInventoryModel::EXCLUDE_TRASH); +	for (S32 i=0; i<item_array.size(); i++) +	{ +		const LLViewerInventoryItem* inv_item = item_array.at(i).get(); +		local_items.insert(inv_item->getUUID()); +		LL_INFOS("Avatar") << "LOCAL: item_id: " << inv_item->getUUID() +						   << " linked_item_id: " << inv_item->getLinkedUUID() +						   << " name: " << inv_item->getName() +						   << " parent: " << inv_item->getParentUUID() +						   << LL_ENDL; +	} +	LL_INFOS("Avatar") << " ================================= " << LL_ENDL; +	S32 local_only = 0, ais_only = 0; +	for (std::set<LLUUID>::iterator it = local_items.begin(); it != local_items.end(); ++it) +	{ +		if (ais_items.find(*it) == ais_items.end())  		{ -			onFailure(200); +			LL_INFOS("Avatar") << "LOCAL ONLY: " << *it << LL_ENDL; +			local_only++;  		}  	} - -	// Error -	/*virtual*/ void errorWithContent(U32 status, const std::string& reason, const LLSD& content) +	for (std::set<LLUUID>::iterator it = ais_items.begin(); it != ais_items.end(); ++it)  	{ -		LL_WARNS() << "appearance update request failed, status: " << status << " reason: " << reason << " code: " << content["code"].asInteger() << " error: \"" << content["error"].asString() << "\"" << LL_ENDL; -		if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage")) +		if (local_items.find(*it) == local_items.end())  		{ -			dumpContents(gAgentAvatarp->getFullname() + "_appearance_request_error", content); -			debugCOF(content); -		 +			LL_INFOS("Avatar") << "AIS ONLY: " << *it << LL_ENDL; +			ais_only++;  		} -		onFailure(status); -	}	 +	} +	if (local_only==0 && ais_only==0) +	{ +		LL_INFOS("Avatar") << "COF contents identical, only version numbers differ (req " +						   << content["observed"].asInteger() +						   << " rcv " << content["expected"].asInteger() +						   << ")" << LL_ENDL; +	} +} -	void onFailure(U32 status) +/* virtual */ void RequestAgentUpdateAppearanceResponder::httpSuccess() +{ +	const LLSD& content = getContent(); +	if (!content.isMap())  	{ -		F32 seconds_to_wait; -		if (mRetryPolicy->shouldRetry(status,seconds_to_wait)) -		{ -			LL_INFOS() << "retrying" << LL_ENDL; -			doAfterInterval(boost::bind(&LLAppearanceMgr::requestServerAppearanceUpdate, -										LLAppearanceMgr::getInstance(), -										LLCurl::ResponderPtr(this)), -							seconds_to_wait); -		} -		else +		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); +		return; +	} +	if (content["success"].asBoolean()) +	{ +		LL_DEBUGS("Avatar") << "succeeded" << LL_ENDL; +		if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"))  		{ -			LL_WARNS() << "giving up after too many retries" << LL_ENDL; +			dump_sequential_xml(gAgentAvatarp->getFullname() + "_appearance_request_ok", content);  		} -	}	 -	void dumpContents(const std::string outprefix, const LLSD& content) +		onSuccess(); +	} +	else  	{ -		std::string outfilename = get_sequential_numbered_file_name(outprefix,".xml"); -		std::string fullpath = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,outfilename); -		std::ofstream ofs(fullpath.c_str(), std::ios_base::out); -		ofs << LLSDOStreamer<LLSDXMLFormatter>(content, LLSDFormatter::OPTIONS_PRETTY); -		LL_DEBUGS("Avatar") << "results saved to: " << fullpath << LL_ENDL; +		failureResult(HTTP_INTERNAL_ERROR, "Non-success response", content);  	} +} + +void RequestAgentUpdateAppearanceResponder::onSuccess() +{ +	mInFlightCounter = llmax(mInFlightCounter-1,0); +} + +/*virtual*/ void RequestAgentUpdateAppearanceResponder::httpFailure() +{ +	LL_WARNS("Avatar") << "appearance update request failed, status " +					   << getStatus() << " reason " << getReason() << LL_ENDL; -	void debugCOF(const LLSD& content) +	if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"))  	{ -		LL_DEBUGS("Avatar") << "AIS COF, version found: " << content["expected"].asInteger() << LL_ENDL; -		std::set<LLUUID> ais_items, local_items; -		const LLSD& cof_raw = content["cof_raw"]; -		for (LLSD::array_const_iterator it = cof_raw.beginArray(); -			 it != cof_raw.endArray(); ++it) -		{ -			const LLSD& item = *it; -			if (item["parent_id"].asUUID() == LLAppearanceMgr::instance().getCOF()) -			{ -				ais_items.insert(item["item_id"].asUUID()); -				if (item["type"].asInteger() == 24) // link -				{ -					LL_DEBUGS("Avatar") << "Link: item_id: " << item["item_id"].asUUID() -										<< " linked_item_id: " << item["asset_id"].asUUID() -										<< " name: " << item["name"].asString() -										<< LL_ENDL;  -				} -				else if (item["type"].asInteger() == 25) // folder link -				{ -					LL_DEBUGS("Avatar") << "Folder link: item_id: " << item["item_id"].asUUID() -										<< " linked_item_id: " << item["asset_id"].asUUID() -										<< " name: " << item["name"].asString() -										<< LL_ENDL;  -					 -				} -				else -				{ -					LL_DEBUGS("Avatar") << "Other: item_id: " << item["item_id"].asUUID() -										<< " linked_item_id: " << item["asset_id"].asUUID() -										<< " name: " << item["name"].asString() -										<< LL_ENDL;  -				} -			} -		} -		LL_DEBUGS("Avatar") << LL_ENDL; -		LL_DEBUGS("Avatar") << "Local COF, version requested: " << content["observed"].asInteger() << LL_ENDL; -		LLInventoryModel::cat_array_t cat_array; -		LLInventoryModel::item_array_t item_array; -		gInventory.collectDescendents(LLAppearanceMgr::instance().getCOF(), -									  cat_array,item_array,LLInventoryModel::EXCLUDE_TRASH); -		for (S32 i=0; i<item_array.size(); i++) -		{ -			const LLViewerInventoryItem* inv_item = item_array.at(i).get(); -			local_items.insert(inv_item->getUUID()); -			LL_DEBUGS("Avatar") << "item_id: " << inv_item->getUUID() -								<< " linked_item_id: " << inv_item->getLinkedUUID() -								<< " name: " << inv_item->getName() -								<< LL_ENDL; -		} -		LL_DEBUGS("Avatar") << LL_ENDL; -		for (std::set<LLUUID>::iterator it = local_items.begin(); it != local_items.end(); ++it) -		{ -			if (ais_items.find(*it) == ais_items.end()) -			{ -				LL_DEBUGS("Avatar") << "LOCAL ONLY: " << *it << LL_ENDL; -			} -		} -		for (std::set<LLUUID>::iterator it = ais_items.begin(); it != ais_items.end(); ++it) -		{ -			if (local_items.find(*it) == local_items.end()) -			{ -				LL_DEBUGS("Avatar") << "AIS ONLY: " << *it << LL_ENDL; -			} -		} +		const LLSD& content = getContent(); +		dump_sequential_xml(gAgentAvatarp->getFullname() + "_appearance_request_error", content); +		debugCOF(content);  	} +	onFailure(); +} + +void RequestAgentUpdateAppearanceResponder::onFailure() +{ +	mInFlightCounter = llmax(mInFlightCounter-1,0); + +	F32 seconds_to_wait; +	mRetryPolicy->onFailure(getStatus(), getResponseHeaders()); +	if (mRetryPolicy->shouldRetry(seconds_to_wait)) +	{ +		LL_INFOS() << "retrying" << LL_ENDL; +		doAfterInterval(boost::bind(&RequestAgentUpdateAppearanceResponder::sendRequest,this), +						seconds_to_wait); +	} +	else +	{ +		LL_WARNS() << "giving up after too many retries" << LL_ENDL; +	} +}	 -	LLPointer<LLHTTPRetryPolicy> mRetryPolicy; -};  LLSD LLAppearanceMgr::dumpCOF() const  { @@ -3215,58 +3419,14 @@ LLSD LLAppearanceMgr::dumpCOF() const  	return result;  } -void LLAppearanceMgr::requestServerAppearanceUpdate(LLCurl::ResponderPtr responder_ptr) +void LLAppearanceMgr::requestServerAppearanceUpdate()  { -	if (gAgentAvatarp->isEditingAppearance())  -	{ -		// don't send out appearance updates if in appearance editing mode -		return; -	} - -	if (!gAgent.getRegion()) -	{ -		LL_WARNS() << "Region not set, cannot request server appearance update" << LL_ENDL; -		return; -	} -	if (gAgent.getRegion()->getCentralBakeVersion()==0) -	{ -		LL_WARNS() << "Region does not support baking" << LL_ENDL; -	} -	std::string url = gAgent.getRegion()->getCapability("UpdateAvatarAppearance");	 -	if (url.empty()) -	{ -		LL_WARNS() << "No cap for UpdateAvatarAppearance." << LL_ENDL; -		return; -	} - -	LLSD body; -	S32 cof_version = getCOFVersion(); -	if (gSavedSettings.getBOOL("DebugAvatarExperimentalServerAppearanceUpdate")) -	{ -		body = dumpCOF(); -	} -	else -	{ -		body["cof_version"] = cof_version; -		if (gSavedSettings.getBOOL("DebugForceAppearanceRequestFailure")) -		{ -			body["cof_version"] = cof_version+999; -		} -	} -	LL_DEBUGS("Avatar") << "request url " << url << " my_cof_version " << cof_version << LL_ENDL; - -	//LLCurl::ResponderPtr responder_ptr; -	if (!responder_ptr.get()) -	{ -		responder_ptr = new RequestAgentUpdateAppearanceResponder; -	} -	LLHTTPClient::post(url, body, responder_ptr); -	llassert(cof_version >= gAgentAvatarp->mLastUpdateRequestCOFVersion); -	gAgentAvatarp->mLastUpdateRequestCOFVersion = cof_version; +	mAppearanceResponder->onRequestRequested();  }  class LLIncrementCofVersionResponder : public LLHTTPClient::Responder  { +	LOG_CLASS(LLIncrementCofVersionResponder);  public:  	LLIncrementCofVersionResponder() : LLHTTPClient::Responder()  	{ @@ -3277,22 +3437,31 @@ public:  	{  	} -	virtual void result(const LLSD &pContent) +protected: +	virtual void httpSuccess()  	{  		LL_INFOS() << "Successfully incremented agent's COF." << LL_ENDL; -		S32 new_version = pContent["category"]["version"].asInteger(); +		const LLSD& content = getContent(); +		if (!content.isMap()) +		{ +			failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); +			return; +		} +		S32 new_version = content["category"]["version"].asInteger();  		// cof_version should have increased  		llassert(new_version > gAgentAvatarp->mLastUpdateRequestCOFVersion);  		gAgentAvatarp->mLastUpdateRequestCOFVersion = new_version;  	} -	virtual void errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& content) + +	virtual void httpFailure()  	{ -		LL_WARNS() << "While attempting to increment the agent's cof we got an error with [status:" -				<< pStatus << "]: " << content << LL_ENDL; +		LL_WARNS("Avatar") << "While attempting to increment the agent's cof we got an error " +						   << dumpResponse() << LL_ENDL;  		F32 seconds_to_wait; -		if (mRetryPolicy->shouldRetry(pStatus,seconds_to_wait)) +		mRetryPolicy->onFailure(getStatus(), getResponseHeaders()); +		if (mRetryPolicy->shouldRetry(seconds_to_wait))  		{  			LL_INFOS() << "retrying" << LL_ENDL;  			doAfterInterval(boost::bind(&LLAppearanceMgr::incrementCofVersion, @@ -3306,6 +3475,7 @@ public:  		}  	} +private:  	LLPointer<LLHTTPRetryPolicy> mRetryPolicy;  }; @@ -3338,6 +3508,15 @@ void LLAppearanceMgr::incrementCofVersion(LLHTTPClient::ResponderPtr responder_p  	LLHTTPClient::get(url, body, responder_ptr, headers, 30.0f);  } +U32 LLAppearanceMgr::getNumAttachmentsInCOF() +{ +	const LLUUID cof = getCOF(); +	LLInventoryModel::item_array_t obj_items; +	getDescendentsOfAssetType(cof, obj_items, LLAssetType::AT_OBJECT); +	return obj_items.size(); +} + +  std::string LLAppearanceMgr::getAppearanceServiceURL() const  {  	if (gSavedSettings.getString("DebugAvatarAppearanceServiceURLOverride").empty()) @@ -3348,57 +3527,91 @@ std::string LLAppearanceMgr::getAppearanceServiceURL() const  }  void show_created_outfit(LLUUID& folder_id, bool show_panel = true) +{ +	if (!LLApp::isRunning())  	{ -		if (!LLApp::isRunning()) -		{ -			LL_WARNS() << "called during shutdown, skipping" << LL_ENDL; -			return; -		} - -		LLSD key; -		 +		LL_WARNS() << "called during shutdown, skipping" << LL_ENDL; +		return; +	} +	 +	LL_DEBUGS("Avatar") << "called" << LL_ENDL; +	LLSD key; +	  	//EXT-7727. For new accounts inventory callback is created during login process  	// and may be processed after login process is finished  	if (show_panel) -		{ -			LLFloaterSidePanelContainer::showPanel("appearance", "panel_outfits_inventory", key); - -		} -		LLOutfitsList *outfits_list = -			dynamic_cast<LLOutfitsList*>(LLFloaterSidePanelContainer::getPanel("appearance", "outfitslist_tab")); -		if (outfits_list) -		{ +	{ +		LL_DEBUGS("Avatar") << "showing panel" << LL_ENDL; +		LLFloaterSidePanelContainer::showPanel("appearance", "panel_outfits_inventory", key); +		 +	} +	LLOutfitsList *outfits_list = +		dynamic_cast<LLOutfitsList*>(LLFloaterSidePanelContainer::getPanel("appearance", "outfitslist_tab")); +	if (outfits_list) +	{  		outfits_list->setSelectedOutfitByUUID(folder_id); -		} - -		LLAppearanceMgr::getInstance()->updateIsDirty(); -		gAgentWearables.notifyLoadingFinished(); // New outfit is saved. -		LLAppearanceMgr::getInstance()->updatePanelOutfitName("");  	} +	 +	LLAppearanceMgr::getInstance()->updateIsDirty(); +	gAgentWearables.notifyLoadingFinished(); // New outfit is saved. +	LLAppearanceMgr::getInstance()->updatePanelOutfitName(""); + +	// For SSB, need to update appearance after we add a base outfit +	// link, since, the COF version has changed. There is a race +	// condition in initial outfit setup which can lead to rez +	// failures - SH-3860. +	LL_DEBUGS("Avatar") << "requesting appearance update after createBaseOutfitLink" << LL_ENDL; +	LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy; +	LLAppearanceMgr::getInstance()->createBaseOutfitLink(folder_id, cb); +} -LLUUID LLAppearanceMgr::makeNewOutfitLinks(const std::string& new_folder_name, bool show_panel) +void LLAppearanceMgr::onOutfitFolderCreated(const LLUUID& folder_id, bool show_panel)  { -	if (!isAgentAvatarValid()) return LLUUID::null; - -	gAgentWearables.notifyLoadingStarted(); +	LLPointer<LLInventoryCallback> cb = +		new LLBoostFuncInventoryCallback(no_op_inventory_func, +										 boost::bind(&LLAppearanceMgr::onOutfitFolderCreatedAndClothingOrdered,this,folder_id,show_panel)); +	updateClothingOrderingInfo(LLUUID::null, cb); +} -	// First, make a folder in the My Outfits directory. -	const LLUUID parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); -	LLUUID folder_id = gInventory.createNewCategory( -		parent_id, -		LLFolderType::FT_OUTFIT, -		new_folder_name); +void LLAppearanceMgr::onOutfitFolderCreatedAndClothingOrdered(const LLUUID& folder_id, bool show_panel) +{ +	LLPointer<LLInventoryCallback> cb = +		new LLBoostFuncInventoryCallback(no_op_inventory_func, +										 boost::bind(show_created_outfit,folder_id,show_panel)); +	bool copy_folder_links = false; +	slamCategoryLinks(getCOF(), folder_id, copy_folder_links, cb); +} -	updateClothingOrderingInfo(); +void LLAppearanceMgr::makeNewOutfitLinks(const std::string& new_folder_name, bool show_panel) +{ +	if (!isAgentAvatarValid()) return; -	LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(no_op_inventory_func, -																		 boost::bind(show_created_outfit,folder_id,show_panel)); -	shallowCopyCategoryContents(getCOF(),folder_id, cb); -	createBaseOutfitLink(folder_id, cb); +	LL_DEBUGS("Avatar") << "creating new outfit" << LL_ENDL; -	dumpCat(folder_id,"COF, new outfit"); +	gAgentWearables.notifyLoadingStarted(); -	return folder_id; +	// First, make a folder in the My Outfits directory. +	const LLUUID parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); +	if (AISCommand::isAPIAvailable()) +	{ +		// cap-based category creation was buggy until recently. use +		// existence of AIS as an indicator the fix is present. Does +		// not actually use AIS to create the category. +		inventory_func_type func = boost::bind(&LLAppearanceMgr::onOutfitFolderCreated,this,_1,show_panel); +		LLUUID folder_id = gInventory.createNewCategory( +			parent_id, +			LLFolderType::FT_OUTFIT, +			new_folder_name, +			func); +	} +	else +	{		 +		LLUUID folder_id = gInventory.createNewCategory( +			parent_id, +			LLFolderType::FT_OUTFIT, +			new_folder_name); +		onOutfitFolderCreated(folder_id, show_panel); +	}  }  void LLAppearanceMgr::wearBaseOutfit() @@ -3414,23 +3627,24 @@ void LLAppearanceMgr::removeItemsFromAvatar(const uuid_vec_t& ids_to_remove)  	if (ids_to_remove.empty())  	{  		LL_WARNS() << "called with empty list, nothing to do" << LL_ENDL; +		return;  	} +	LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy;  	for (uuid_vec_t::const_iterator it = ids_to_remove.begin(); it != ids_to_remove.end(); ++it)  	{  		const LLUUID& id_to_remove = *it;  		const LLUUID& linked_item_id = gInventory.getLinkedItemID(id_to_remove); -		removeCOFItemLinks(linked_item_id); +		removeCOFItemLinks(linked_item_id, cb);  		addDoomedTempAttachment(linked_item_id);  	} -	updateAppearanceFromCOF();  }  void LLAppearanceMgr::removeItemFromAvatar(const LLUUID& id_to_remove)  {  	LLUUID linked_item_id = gInventory.getLinkedItemID(id_to_remove); -	removeCOFItemLinks(linked_item_id); +	LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy; +	removeCOFItemLinks(linked_item_id, cb);  	addDoomedTempAttachment(linked_item_id); -	updateAppearanceFromCOF();  } @@ -3490,7 +3704,12 @@ bool LLAppearanceMgr::moveWearable(LLViewerInventoryItem* item, bool closer_to_b  	swap_item->setDescription(item->getActualDescription());  	item->setDescription(tmp); +	// LL_DEBUGS("Inventory") << "swap, item " +	// 					   << ll_pretty_print_sd(item->asLLSD()) +	// 					   << " swap_item " +	// 					   << ll_pretty_print_sd(swap_item->asLLSD()) << LL_ENDL; +	// FIXME switch to use AISv3 where supported.  	//items need to be updated on a dataserver  	item->setComplete(TRUE);  	item->updateServer(FALSE); @@ -3504,7 +3723,7 @@ bool LLAppearanceMgr::moveWearable(LLViewerInventoryItem* item, bool closer_to_b  	bool result = false;  	if (result = gAgentWearables.moveWearable(item, closer_to_body))  	{ -		gAgentAvatarp->wearableUpdated(item->getWearableType(), FALSE); +		gAgentAvatarp->wearableUpdated(item->getWearableType());  	}  	setOutfitDirty(true); @@ -3566,7 +3785,8 @@ LLAppearanceMgr::LLAppearanceMgr():  	mAttachmentInvLinkEnabled(false),  	mOutfitIsDirty(false),  	mOutfitLocked(false), -	mIsInUpdateAppearanceFromCOF(false) +	mIsInUpdateAppearanceFromCOF(false), +	mAppearanceResponder(new RequestAgentUpdateAppearanceResponder)  {  	LLOutfitObserver& outfit_observer = LLOutfitObserver::instance(); @@ -3616,7 +3836,11 @@ void LLAppearanceMgr::registerAttachment(const LLUUID& item_id)  		   // we have to pass do_update = true to call LLAppearanceMgr::updateAppearanceFromCOF.  		   // it will trigger gAgentWariables.notifyLoadingFinished()  		   // But it is not acceptable solution. See EXT-7777 -		   LLAppearanceMgr::addCOFItemLink(item_id, false);  // Add COF link for item. +		   if (!isLinkedInCOF(item_id)) +		   { +			   LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy(); +			   LLAppearanceMgr::addCOFItemLink(item_id, cb);  // Add COF link for item. +		   }  	   }  	   else  	   { @@ -3640,22 +3864,21 @@ void LLAppearanceMgr::unregisterAttachment(const LLUUID& item_id)  BOOL LLAppearanceMgr::getIsInCOF(const LLUUID& obj_id) const  { -	return gInventory.isObjectDescendentOf(obj_id, getCOF()); +	const LLUUID& cof = getCOF(); +	if (obj_id == cof) +		return TRUE; +	const LLInventoryObject* obj = gInventory.getObject(obj_id); +	if (obj && obj->getParentUUID() == cof) +		return TRUE; +	return FALSE;  }  // static  bool LLAppearanceMgr::isLinkInCOF(const LLUUID& obj_id)  { -	 LLInventoryModel::cat_array_t cats; -	 LLInventoryModel::item_array_t items; -	 LLLinkedItemIDMatches find_links(gInventory.getLinkedItemID(obj_id)); -	 gInventory.collectDescendentsIf(LLAppearanceMgr::instance().getCOF(), -									 cats, -									 items, -	 LLInventoryModel::EXCLUDE_TRASH, -	 find_links); - -	 return !items.empty(); +	const LLUUID& target_id = gInventory.getLinkedItemID(obj_id); +	LLLinkedItemIDMatches find_links(target_id); +	return gInventory.hasMatchingDirectDescendent(LLAppearanceMgr::instance().getCOF(), find_links);  }  BOOL LLAppearanceMgr::getIsProtectedCOFItem(const LLUUID& obj_id) const @@ -3672,18 +3895,6 @@ BOOL LLAppearanceMgr::getIsProtectedCOFItem(const LLUUID& obj_id) const  	// For now, don't allow direct deletion from the COF.  Instead, force users  	// to choose "Detach" or "Take Off".  	return TRUE; -	/* -	const LLInventoryObject *obj = gInventory.getObject(obj_id); -	if (!obj) return FALSE; - -	// Can't delete bodyparts, since this would be equivalent to removing the item. -	if (obj->getType() == LLAssetType::AT_BODYPART) return TRUE; - -	// Can't delete the folder link, since this is saved for bookkeeping. -	if (obj->getActualType() == LLAssetType::AT_LINK_FOLDER) return TRUE; - -	return FALSE; -	*/  }  class CallAfterCategoryFetchStage2: public LLInventoryFetchItemsObserver @@ -3824,7 +4035,7 @@ public:  			LLAppearanceMgr::getInstance()->wearInventoryCategory(category, true, false);  			// *TODOw: This may not be necessary if initial outfit is chosen already -- josh -			gAgent.setGenderChosen(TRUE); +			gAgent.setOutfitChosen(TRUE);  		}  		// release avatar picker keyboard focus diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h index b5ef0bd935..7742a19c07 100755 --- a/indra/newview/llappearancemgr.h +++ b/indra/newview/llappearancemgr.h @@ -39,6 +39,7 @@  class LLWearableHoldingPattern;  class LLInventoryCallback;  class LLOutfitUnLockTimer; +class RequestAgentUpdateAppearanceResponder;  class LLAppearanceMgr: public LLSingleton<LLAppearanceMgr>  { @@ -50,7 +51,9 @@ class LLAppearanceMgr: public LLSingleton<LLAppearanceMgr>  public:  	typedef std::vector<LLInventoryModel::item_array_t> wearables_by_type_t; -	void updateAppearanceFromCOF(bool update_base_outfit_ordering = false); +	void updateAppearanceFromCOF(bool enforce_item_restrictions = true, +								 bool enforce_ordering = true, +								 nullary_func_t post_update_func = no_op);  	bool needToSaveCOF();  	void updateCOF(const LLUUID& category, bool append = false);  	void wearInventoryCategory(LLInventoryCategory* category, bool copy, bool append); @@ -65,9 +68,18 @@ public:  	S32 findExcessOrDuplicateItems(const LLUUID& cat_id,  								   LLAssetType::EType type,  								   S32 max_items, -								   LLInventoryModel::item_array_t& items_to_kill); -	void enforceItemRestrictions(); - +								   LLInventoryObject::object_list_t& items_to_kill); +	void findAllExcessOrDuplicateItems(const LLUUID& cat_id, +									  LLInventoryObject::object_list_t& items_to_kill); +	void enforceCOFItemRestrictions(LLPointer<LLInventoryCallback> cb); + +	S32 getActiveCopyOperations() const; + +	// Replace category contents with copied links via the slam_inventory_folder +	// command (single inventory operation where supported) +	void slamCategoryLinks(const LLUUID& src_id, const LLUUID& dst_id, +						   bool include_folder_links, LLPointer<LLInventoryCallback> cb); +   	// Copy all items and the src category itself.  	void shallowCopyCategory(const LLUUID& src_id, const LLUUID& dst_id,  							 LLPointer<LLInventoryCallback> cb); @@ -106,15 +118,18 @@ public:  	const LLUUID getBaseOutfitUUID();  	// Wear/attach an item (from a user's inventory) on the agent -	bool wearItemOnAvatar(const LLUUID& item_to_wear, bool do_update = true, bool replace = false, LLPointer<LLInventoryCallback> cb = NULL); +	bool wearItemOnAvatar(const LLUUID& item_to_wear, bool do_update, bool replace = false, +						  LLPointer<LLInventoryCallback> cb = NULL);  	// Update the displayed outfit name in UI.  	void updatePanelOutfitName(const std::string& name); -	void purgeBaseOutfitLink(const LLUUID& category); +	void purgeBaseOutfitLink(const LLUUID& category, LLPointer<LLInventoryCallback> cb = NULL);  	void createBaseOutfitLink(const LLUUID& category, LLPointer<LLInventoryCallback> link_waiter); -	void updateAgentWearables(LLWearableHoldingPattern* holder, bool append); +	void updateAgentWearables(LLWearableHoldingPattern* holder); + +	S32 countActiveHoldingPatterns();  	// For debugging - could be moved elsewhere.  	void dumpCat(const LLUUID& cat_id, const std::string& msg); @@ -125,21 +140,17 @@ public:  	void registerAttachment(const LLUUID& item_id);  	void setAttachmentInvLinkEnable(bool val); -	// utility function for bulk linking. -	void linkAll(const LLUUID& category, -				 LLInventoryModel::item_array_t& items, -				 LLPointer<LLInventoryCallback> cb); -  	// Add COF link to individual item. -	void addCOFItemLink(const LLUUID& item_id, bool do_update = true, LLPointer<LLInventoryCallback> cb = NULL, const std::string description = ""); -	void addCOFItemLink(const LLInventoryItem *item, bool do_update = true, LLPointer<LLInventoryCallback> cb = NULL, const std::string description = ""); +	void addCOFItemLink(const LLUUID& item_id, LLPointer<LLInventoryCallback> cb = NULL, const std::string description = ""); +	void addCOFItemLink(const LLInventoryItem *item, LLPointer<LLInventoryCallback> cb = NULL, const std::string description = "");  	// Find COF entries referencing the given item.  	LLInventoryModel::item_array_t findCOFItemLinks(const LLUUID& item_id); +	bool isLinkedInCOF(const LLUUID& item_id);  	// Remove COF entries -	void removeCOFItemLinks(const LLUUID& item_id); -	void removeCOFLinksOfType(LLWearableType::EType type); +	void removeCOFItemLinks(const LLUUID& item_id, LLPointer<LLInventoryCallback> cb = NULL); +	void removeCOFLinksOfType(LLWearableType::EType type, LLPointer<LLInventoryCallback> cb = NULL);  	void removeAllClothesFromAvatar();  	void removeAllAttachmentsFromAvatar(); @@ -156,12 +167,11 @@ public:  	// should only be necessary to do on initial login.  	void updateIsDirty(); +	void setOutfitLocked(bool locked); +  	// Called when self avatar is first fully visible.  	void onFirstFullyVisible(); -	// Create initial outfits from library. -	void autopopulateOutfits(); -  	// Copy initial gestures from library.  	void copyLibraryGestures(); @@ -176,7 +186,10 @@ public:  	void removeItemFromAvatar(const LLUUID& item_id); -	LLUUID makeNewOutfitLinks(const std::string& new_folder_name,bool show_panel = true); +	void onOutfitFolderCreated(const LLUUID& folder_id, bool show_panel); +	void onOutfitFolderCreatedAndClothingOrdered(const LLUUID& folder_id, bool show_panel); + +	void makeNewOutfitLinks(const std::string& new_folder_name,bool show_panel = true);  	bool moveWearable(LLViewerInventoryItem* item, bool closer_to_body); @@ -185,18 +198,27 @@ public:  	//Divvy items into arrays by wearable type  	static void divvyWearablesByType(const LLInventoryModel::item_array_t& items, wearables_by_type_t& items_by_type); +	typedef std::map<LLUUID,std::string> desc_map_t; + +	void getWearableOrderingDescUpdates(LLInventoryModel::item_array_t& wear_items, desc_map_t& desc_map); +  	//Check ordering information on wearables stored in links' descriptions and update if it is invalid  	// COF is processed if cat_id is not specified -	void updateClothingOrderingInfo(LLUUID cat_id = LLUUID::null, bool update_base_outfit_ordering = false); +	bool validateClothingOrderingInfo(LLUUID cat_id = LLUUID::null); +	 +	void updateClothingOrderingInfo(LLUUID cat_id = LLUUID::null, +									LLPointer<LLInventoryCallback> cb = NULL);  	bool isOutfitLocked() { return mOutfitLocked; }  	bool isInUpdateAppearanceFromCOF() { return mIsInUpdateAppearanceFromCOF; } -	void requestServerAppearanceUpdate(LLCurl::ResponderPtr responder_ptr = NULL); +	void requestServerAppearanceUpdate();  	void incrementCofVersion(LLHTTPClient::ResponderPtr responder_ptr = NULL); +	U32 getNumAttachmentsInCOF(); +  	// *HACK Remove this after server side texture baking is deployed on all sims.  	void incrementCofVersionLegacy(); @@ -217,24 +239,21 @@ private:  	void getDescendentsOfAssetType(const LLUUID& category,   										  LLInventoryModel::item_array_t& items, -										  LLAssetType::EType type, -										  bool follow_folder_links); +										  LLAssetType::EType type);  	void getUserDescendents(const LLUUID& category,   								   LLInventoryModel::item_array_t& wear_items,  								   LLInventoryModel::item_array_t& obj_items, -								   LLInventoryModel::item_array_t& gest_items, -								   bool follow_folder_links); +								   LLInventoryModel::item_array_t& gest_items); -	void purgeCategory(const LLUUID& category, bool keep_outfit_links, LLInventoryModel::item_array_t* keep_items = NULL);  	static void onOutfitRename(const LLSD& notification, const LLSD& response); -	void setOutfitLocked(bool locked); -  	bool mAttachmentInvLinkEnabled;  	bool mOutfitIsDirty;  	bool mIsInUpdateAppearanceFromCOF; // to detect recursive calls. +	LLPointer<RequestAgentUpdateAppearanceResponder> mAppearanceResponder; +  	/**  	 * Lock for blocking operations on outfit until server reply or timeout exceed  	 * to avoid unsynchronized outfit state or performing duplicate operations. @@ -266,17 +285,31 @@ public:  class LLUpdateAppearanceOnDestroy: public LLInventoryCallback  {  public: -	LLUpdateAppearanceOnDestroy(bool update_base_outfit_ordering = false); +	LLUpdateAppearanceOnDestroy(bool enforce_item_restrictions = true, +								bool enforce_ordering = true, +								nullary_func_t post_update_func = no_op);  	virtual ~LLUpdateAppearanceOnDestroy();  	/* virtual */ void fire(const LLUUID& inv_item);  private:  	U32 mFireCount; -	bool mUpdateBaseOrder; +	bool mEnforceItemRestrictions; +	bool mEnforceOrdering; +	nullary_func_t mPostUpdateFunc;  }; +class LLUpdateAppearanceAndEditWearableOnDestroy: public LLInventoryCallback +{ +public: +	LLUpdateAppearanceAndEditWearableOnDestroy(const LLUUID& item_id); + +	/* virtual */ void fire(const LLUUID& item_id) {} -#define SUPPORT_ENSEMBLES 0 +	~LLUpdateAppearanceAndEditWearableOnDestroy(); +	 +private: +	LLUUID mItemID; +};  LLUUID findDescendentCategoryIDByName(const LLUUID& parent_id,const std::string& name); diff --git a/indra/newview/llassetuploadqueue.cpp b/indra/newview/llassetuploadqueue.cpp index 2b428aec4b..8833c57948 100755 --- a/indra/newview/llassetuploadqueue.cpp +++ b/indra/newview/llassetuploadqueue.cpp @@ -36,6 +36,7 @@  class LLAssetUploadChainResponder : public LLUpdateTaskInventoryResponder  { +	LOG_CLASS(LLAssetUploadChainResponder);  public:  	LLAssetUploadChainResponder(const LLSD& post_data, @@ -51,52 +52,54 @@ public:  		mDataSize(data_size),  		mScriptName(script_name)  	{ - 	} +	}  	virtual ~LLAssetUploadChainResponder()  -   	{ -   		if(mSupplier) -   		{ -   			LLAssetUploadQueue *queue = mSupplier->get(); -   			if (queue) -   			{ -   				// Give ownership of supplier back to queue. -   				queue->mSupplier = mSupplier; -   				mSupplier = NULL; -   			} -   		} -   		delete mSupplier; +	{ +		if(mSupplier) +		{ +			LLAssetUploadQueue *queue = mSupplier->get(); +			if (queue) +			{ +				// Give ownership of supplier back to queue. +				queue->mSupplier = mSupplier; +				mSupplier = NULL; +			} +		} +		delete mSupplier;  		delete mData; -   	} +	} -	virtual void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content) -   	{ -		LL_WARNS() << "LLAssetUploadChainResponder Error [status:"  -				<< statusNum << "]: " << content << LL_ENDL; -		LLUpdateTaskInventoryResponder::errorWithContent(statusNum, reason, content); -   		LLAssetUploadQueue *queue = mSupplier->get(); -   		if (queue) +protected: +	virtual void httpFailure() +	{ +		// Parent class will spam the failure. +		//LL_WARNS() << dumpResponse() << LL_ENDL; +		LLUpdateTaskInventoryResponder::httpFailure(); +		LLAssetUploadQueue *queue = mSupplier->get(); +		if (queue) +		{ +			queue->request(&mSupplier); +		} +	} + +	virtual void httpSuccess() +	{ +		LLUpdateTaskInventoryResponder::httpSuccess(); +		LLAssetUploadQueue *queue = mSupplier->get(); +		if (queue)  		{ -   			queue->request(&mSupplier); -   		} -   	} - -	virtual void result(const LLSD& content) -   	{ -		LLUpdateTaskInventoryResponder::result(content); -   		LLAssetUploadQueue *queue = mSupplier->get(); -   		if (queue) -   		{ -   			// Responder is reused across 2 phase upload, -   			// so only start next upload after 2nd phase complete. -   			std::string state = content["state"]; -   			if(state == "complete") -   			{ -   				queue->request(&mSupplier); -   			} -   		}	 -   	} +			// Responder is reused across 2 phase upload, +			// so only start next upload after 2nd phase complete. +			const std::string& state = getContent()["state"].asStringRef(); +			if(state == "complete") +			{ +				queue->request(&mSupplier); +			} +		} +	} +public:  	virtual void uploadUpload(const LLSD& content)  	{  		std::string uploader = content["uploader"]; diff --git a/indra/newview/llassetuploadresponders.cpp b/indra/newview/llassetuploadresponders.cpp index d86e63589f..a98ff64d0a 100755 --- a/indra/newview/llassetuploadresponders.cpp +++ b/indra/newview/llassetuploadresponders.cpp @@ -225,37 +225,41 @@ LLAssetUploadResponder::~LLAssetUploadResponder()  }  // virtual -void LLAssetUploadResponder::errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content) +void LLAssetUploadResponder::httpFailure()  { -	LL_INFOS() << "LLAssetUploadResponder::error [status:"  -			<< statusNum << "]: " << content << LL_ENDL; +	// *TODO: Add adaptive retry policy? +	LL_WARNS() << dumpResponse() << LL_ENDL;  	LLSD args; -	switch(statusNum) +	if (isHttpClientErrorStatus(getStatus()))  	{ -		case 400: -			args["FILE"] = (mFileName.empty() ? mVFileID.asString() : mFileName); -			args["REASON"] = "Error in upload request.  Please visit " -				"http://secondlife.com/support for help fixing this problem."; -			LLNotificationsUtil::add("CannotUploadReason", args); -			break; -		case 500: -		default: -			args["FILE"] = (mFileName.empty() ? mVFileID.asString() : mFileName); -			args["REASON"] = "The server is experiencing unexpected " -				"difficulties."; -			LLNotificationsUtil::add("CannotUploadReason", args); -			break; +		args["FILE"] = (mFileName.empty() ? mVFileID.asString() : mFileName); +		args["REASON"] = "Error in upload request.  Please visit " +			"http://secondlife.com/support for help fixing this problem."; +		LLNotificationsUtil::add("CannotUploadReason", args); +	} +	else +	{ +		args["FILE"] = (mFileName.empty() ? mVFileID.asString() : mFileName); +		args["REASON"] = "The server is experiencing unexpected " +			"difficulties."; +		LLNotificationsUtil::add("CannotUploadReason", args);  	}  	LLUploadDialog::modalUploadFinished();  	LLFilePicker::instance().reset();  // unlock file picker when bulk upload fails  }  //virtual  -void LLAssetUploadResponder::result(const LLSD& content) +void LLAssetUploadResponder::httpSuccess()  { +	const LLSD& content = getContent(); +	if (!content.isMap()) +	{ +		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); +		return; +	}  	LL_DEBUGS() << "LLAssetUploadResponder::result from capabilities" << LL_ENDL; -	std::string state = content["state"]; +	const std::string& state = content["state"].asStringRef();  	if (state == "upload")  	{ @@ -280,7 +284,7 @@ void LLAssetUploadResponder::result(const LLSD& content)  void LLAssetUploadResponder::uploadUpload(const LLSD& content)  { -	std::string uploader = content["uploader"]; +	const std::string& uploader = content["uploader"].asStringRef();  	if (mFileName.empty())  	{  		LLHTTPClient::postFile(uploader, mVFileID, mAssetType, this); @@ -293,6 +297,7 @@ void LLAssetUploadResponder::uploadUpload(const LLSD& content)  void LLAssetUploadResponder::uploadFailure(const LLSD& content)  { +	LL_WARNS() << dumpResponse() << LL_ENDL;  	// remove the "Uploading..." message  	LLUploadDialog::modalUploadFinished();  	LLFloater* floater_snapshot = LLFloaterReg::findInstance("snapshot"); @@ -301,7 +306,7 @@ void LLAssetUploadResponder::uploadFailure(const LLSD& content)  		floater_snapshot->notify(LLSD().with("set-finished", LLSD().with("ok", false).with("msg", "inventory")));  	} -	std::string reason = content["state"]; +	const std::string& reason = content["state"].asStringRef();  	// deal with L$ errors  	if (reason == "insufficient funds")  	{ @@ -340,9 +345,9 @@ LLNewAgentInventoryResponder::LLNewAgentInventoryResponder(  }  // virtual -void LLNewAgentInventoryResponder::errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content) +void LLNewAgentInventoryResponder::httpFailure()  { -	LLAssetUploadResponder::errorWithContent(statusNum, reason, content); +	LLAssetUploadResponder::httpFailure();  	//LLImportColladaAssetCache::getInstance()->assetUploaded(mVFileID, LLUUID(), FALSE);  } @@ -445,58 +450,6 @@ void LLNewAgentInventoryResponder::uploadComplete(const LLSD& content)  	//LLImportColladaAssetCache::getInstance()->assetUploaded(mVFileID, content["new_asset"], TRUE);  } -LLSendTexLayerResponder::LLSendTexLayerResponder(const LLSD& post_data, -												 const LLUUID& vfile_id, -												 LLAssetType::EType asset_type, -												 LLBakedUploadData * baked_upload_data) :  -	LLAssetUploadResponder(post_data, vfile_id, asset_type), -	mBakedUploadData(baked_upload_data) -{ -} - -LLSendTexLayerResponder::~LLSendTexLayerResponder() -{ -	// mBakedUploadData is normally deleted by calls to LLViewerTexLayerSetBuffer::onTextureUploadComplete() below -	if (mBakedUploadData) -	{	// ...but delete it in the case where uploadComplete() is never called -		delete mBakedUploadData; -		mBakedUploadData = NULL; -	} -} - - -// Baked texture upload completed -void LLSendTexLayerResponder::uploadComplete(const LLSD& content) -{ -	LLUUID item_id = mPostData["item_id"]; - -	std::string result = content["state"]; -	LLUUID new_id = content["new_asset"]; - -	LL_INFOS() << "result: " << result << " new_id: " << new_id << LL_ENDL; -	if (result == "complete" -		&& mBakedUploadData != NULL) -	{	// Invoke  -		LLViewerTexLayerSetBuffer::onTextureUploadComplete(new_id, (void*) mBakedUploadData, 0, LL_EXSTAT_NONE); -		mBakedUploadData = NULL;	// deleted in onTextureUploadComplete() -	} -	else -	{	// Invoke the original callback with an error result -		LLViewerTexLayerSetBuffer::onTextureUploadComplete(new_id, (void*) mBakedUploadData, -1, LL_EXSTAT_NONE); -		mBakedUploadData = NULL;	// deleted in onTextureUploadComplete() -	} -} - -void LLSendTexLayerResponder::errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content) -{ -	LL_INFOS() << "LLSendTexLayerResponder error [status:" -			<< statusNum << "]: " << content << LL_ENDL; -	 -	// Invoke the original callback with an error result -	LLViewerTexLayerSetBuffer::onTextureUploadComplete(LLUUID(), (void*) mBakedUploadData, -1, LL_EXSTAT_NONE); -	mBakedUploadData = NULL;	// deleted in onTextureUploadComplete() -} -  LLUpdateAgentInventoryResponder::LLUpdateAgentInventoryResponder(  	const LLSD& post_data,  	const LLUUID& vfile_id, @@ -1009,19 +962,14 @@ LLNewAgentInventoryVariablePriceResponder::~LLNewAgentInventoryVariablePriceResp  	delete mImpl;  } -void LLNewAgentInventoryVariablePriceResponder::errorWithContent( -	U32 statusNum, -	const std::string& reason, -	const LLSD& content) +void LLNewAgentInventoryVariablePriceResponder::httpFailure()  { -	LL_DEBUGS()  -		<< "LLNewAgentInventoryVariablePrice::error " << statusNum  -		<< " reason: " << reason << LL_ENDL; +	const LLSD& content = getContent(); +	LL_WARNS("Upload") << dumpResponse() << LL_ENDL; -	if ( content.has("error") ) +	static const std::string _ERROR = "error"; +	if ( content.has(_ERROR) )  	{ -		static const std::string _ERROR = "error"; -  		mImpl->onTransportError(content[_ERROR]);  	}  	else @@ -1030,8 +978,14 @@ void LLNewAgentInventoryVariablePriceResponder::errorWithContent(  	}  } -void LLNewAgentInventoryVariablePriceResponder::result(const LLSD& content) +void LLNewAgentInventoryVariablePriceResponder::httpSuccess()  { +	const LLSD& content = getContent(); +	if (!content.isMap()) +	{ +		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); +		return; +	}  	// Parse out application level errors and the appropriate  	// responses for them  	static const std::string _ERROR = "error"; @@ -1047,6 +1001,7 @@ void LLNewAgentInventoryVariablePriceResponder::result(const LLSD& content)  	// Check for application level errors  	if ( content.has(_ERROR) )  	{ +		LL_WARNS("Upload") << dumpResponse() << LL_ENDL;  		onApplicationLevelError(content[_ERROR]);  		return;  	} @@ -1090,6 +1045,7 @@ void LLNewAgentInventoryVariablePriceResponder::result(const LLSD& content)  	}  	else  	{ +		LL_WARNS("Upload") << dumpResponse() << LL_ENDL;  		onApplicationLevelError("");  	}  } diff --git a/indra/newview/llassetuploadresponders.h b/indra/newview/llassetuploadresponders.h index a6d1016136..7fbebc7481 100755 --- a/indra/newview/llassetuploadresponders.h +++ b/indra/newview/llassetuploadresponders.h @@ -33,6 +33,8 @@  // via capabilities  class LLAssetUploadResponder : public LLHTTPClient::Responder  { +protected: +	LOG_CLASS(LLAssetUploadResponder);  public:  	LLAssetUploadResponder(const LLSD& post_data,  							const LLUUID& vfile_id, @@ -42,8 +44,11 @@ public:  							LLAssetType::EType asset_type);  	~LLAssetUploadResponder(); -    virtual void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content); -	virtual void result(const LLSD& content); +protected: +	virtual void httpFailure(); +	virtual void httpSuccess(); + +public:  	virtual void uploadUpload(const LLSD& content);  	virtual void uploadComplete(const LLSD& content);  	virtual void uploadFailure(const LLSD& content); @@ -58,6 +63,7 @@ protected:  // TODO*: Remove this once deprecated  class LLNewAgentInventoryResponder : public LLAssetUploadResponder  { +	LOG_CLASS(LLNewAgentInventoryResponder);  public:  	LLNewAgentInventoryResponder(  		const LLSD& post_data, @@ -67,9 +73,10 @@ public:  		const LLSD& post_data,  		const std::string& file_name,  		LLAssetType::EType asset_type); -    virtual void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content);  	virtual void uploadComplete(const LLSD& content);  	virtual void uploadFailure(const LLSD& content); +protected: +	virtual void httpFailure();  };  // A base class which goes through and performs some default @@ -79,6 +86,7 @@ public:  class LLNewAgentInventoryVariablePriceResponder :  	public LLHTTPClient::Responder  { +	LOG_CLASS(LLNewAgentInventoryVariablePriceResponder);  public:  	LLNewAgentInventoryVariablePriceResponder(  		const LLUUID& vfile_id, @@ -91,12 +99,11 @@ public:  		const LLSD& inventory_info);  	virtual ~LLNewAgentInventoryVariablePriceResponder(); -	void errorWithContent( -		U32 statusNum, -		const std::string& reason, -		const LLSD& content); -	void result(const LLSD& content); +private: +	/* virtual */ void httpFailure(); +	/* virtual */ void httpSuccess(); +public:  	virtual void onApplicationLevelError(  		const LLSD& error);  	virtual void showConfirmationDialog( @@ -109,24 +116,6 @@ private:  	Impl* mImpl;  }; -struct LLBakedUploadData; -class LLSendTexLayerResponder : public LLAssetUploadResponder -{ -	LOG_CLASS(LLSendTexLayerResponder); -public: -	LLSendTexLayerResponder(const LLSD& post_data, -							const LLUUID& vfile_id, -							LLAssetType::EType asset_type, -							LLBakedUploadData * baked_upload_data); - -	~LLSendTexLayerResponder(); - -	virtual void uploadComplete(const LLSD& content); -	virtual void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content); - -	LLBakedUploadData * mBakedUploadData; -}; -  class LLUpdateAgentInventoryResponder : public LLAssetUploadResponder  {  public: diff --git a/indra/newview/llbreastmotion.cpp b/indra/newview/llbreastmotion.cpp index 9a8cd5ceae..3a88bab3b3 100755 --- a/indra/newview/llbreastmotion.cpp +++ b/indra/newview/llbreastmotion.cpp @@ -340,8 +340,7 @@ BOOL LLBreastMotion::onUpdate(F32 time, U8* joint_mask)  		if (mBreastParamsDriven[i])  		{  			mCharacter->setVisualParamWeight(mBreastParamsDriven[i], -											 new_local_pt[i], -											 FALSE); +											 new_local_pt[i]);  		}  	} diff --git a/indra/newview/llclassifiedstatsresponder.cpp b/indra/newview/llclassifiedstatsresponder.cpp index bc7815fba2..f1ef8e9a03 100755 --- a/indra/newview/llclassifiedstatsresponder.cpp +++ b/indra/newview/llclassifiedstatsresponder.cpp @@ -42,8 +42,14 @@ LLClassifiedStatsResponder::LLClassifiedStatsResponder(LLUUID classified_id)  {}  /*virtual*/ -void LLClassifiedStatsResponder::result(const LLSD& content) +void LLClassifiedStatsResponder::httpSuccess()  { +	const LLSD& content = getContent(); +	if (!content.isMap()) +	{ +		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); +		return; +	}  	S32 teleport = content["teleport_clicks"].asInteger();  	S32 map = content["map_clicks"].asInteger();  	S32 profile = content["profile_clicks"].asInteger(); @@ -59,7 +65,8 @@ void LLClassifiedStatsResponder::result(const LLSD& content)  }  /*virtual*/ -void LLClassifiedStatsResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void LLClassifiedStatsResponder::httpFailure()  { -	LL_INFOS() << "LLClassifiedStatsResponder::error [status:" << status << "]: " << content << LL_ENDL; +	LL_WARNS() << dumpResponse() << LL_ENDL;  } + diff --git a/indra/newview/llclassifiedstatsresponder.h b/indra/newview/llclassifiedstatsresponder.h index 06dcb62fd0..efa4d82411 100755 --- a/indra/newview/llclassifiedstatsresponder.h +++ b/indra/newview/llclassifiedstatsresponder.h @@ -33,13 +33,15 @@  class LLClassifiedStatsResponder : public LLHTTPClient::Responder  { +	LOG_CLASS(LLClassifiedStatsResponder);  public:  	LLClassifiedStatsResponder(LLUUID classified_id); + +protected:  	//If we get back a normal response, handle it here -	virtual void result(const LLSD& content); +	virtual void httpSuccess();  	//If we get back an error (not found, etc...), handle it here -	 -	virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content); +	virtual void httpFailure();  protected:  	LLUUID mClassifiedID; diff --git a/indra/newview/llemote.cpp b/indra/newview/llemote.cpp index 510ff69acf..b9ef297c00 100755 --- a/indra/newview/llemote.cpp +++ b/indra/newview/llemote.cpp @@ -79,13 +79,13 @@ BOOL LLEmote::onActivate()  	LLVisualParam* default_param = mCharacter->getVisualParam( "Express_Closed_Mouth" );  	if( default_param )  	{ -		default_param->setWeight( default_param->getMaxWeight(), FALSE ); +		default_param->setWeight( default_param->getMaxWeight());  	}  	mParam = mCharacter->getVisualParam(mName.c_str());  	if (mParam)  	{ -		mParam->setWeight(0.f, FALSE); +		mParam->setWeight(0.f);  		mCharacter->updateVisualParams();  	} @@ -101,7 +101,7 @@ BOOL LLEmote::onUpdate(F32 time, U8* joint_mask)  	if( mParam )  	{  		F32 weight = mParam->getMinWeight() + mPose.getWeight() * (mParam->getMaxWeight() - mParam->getMinWeight()); -		mParam->setWeight(weight, FALSE); +		mParam->setWeight(weight);  		// Cross fade against the default parameter  		LLVisualParam* default_param = mCharacter->getVisualParam( "Express_Closed_Mouth" ); @@ -110,7 +110,7 @@ BOOL LLEmote::onUpdate(F32 time, U8* joint_mask)  			F32 default_param_weight = default_param->getMinWeight() +   				(1.f - mPose.getWeight()) * ( default_param->getMaxWeight() - default_param->getMinWeight() ); -			default_param->setWeight( default_param_weight, FALSE ); +			default_param->setWeight( default_param_weight);  		}  		mCharacter->updateVisualParams(); @@ -127,13 +127,13 @@ void LLEmote::onDeactivate()  {  	if( mParam )  	{ -		mParam->setWeight( mParam->getDefaultWeight(), FALSE ); +		mParam->setWeight( mParam->getDefaultWeight());  	}  	LLVisualParam* default_param = mCharacter->getVisualParam( "Express_Closed_Mouth" );  	if( default_param )  	{ -		default_param->setWeight( default_param->getMaxWeight(), FALSE ); +		default_param->setWeight( default_param->getMaxWeight());  	}  	mCharacter->updateVisualParams(); diff --git a/indra/newview/llestateinfomodel.cpp b/indra/newview/llestateinfomodel.cpp index 761adc5942..78d619a315 100755 --- a/indra/newview/llestateinfomodel.cpp +++ b/indra/newview/llestateinfomodel.cpp @@ -112,19 +112,19 @@ void LLEstateInfoModel::notifyCommit()  class LLEstateChangeInfoResponder : public LLHTTPClient::Responder  { -public: - +	LOG_CLASS(LLEstateChangeInfoResponder); +protected:  	// if we get a normal response, handle it here -	virtual void result(const LLSD& content) +	virtual void httpSuccesss()  	{  		LL_INFOS() << "Committed estate info" << LL_ENDL;  		LLEstateInfoModel::instance().notifyCommit();  	}  	// if we get an error response -	virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content) +	virtual void httpFailure()  	{ -		LL_WARNS() << "Failed to commit estate info [status:" << status << "]: " << content << LL_ENDL; +		LL_WARNS() << "Failed to commit estate info " << dumpResponse() << LL_ENDL;  	}  }; diff --git a/indra/newview/lleventpoll.cpp b/indra/newview/lleventpoll.cpp index fbd9466afe..4de6ad4d2f 100755 --- a/indra/newview/lleventpoll.cpp +++ b/indra/newview/lleventpoll.cpp @@ -31,7 +31,7 @@  #include "llagent.h"  #include "llhttpclient.h" -#include "llhttpstatuscodes.h" +#include "llhttpconstants.h"  #include "llsdserialize.h"  #include "lleventtimer.h"  #include "llviewerregion.h" @@ -49,6 +49,7 @@ namespace  	class LLEventPollResponder : public LLHTTPClient::Responder  	{ +		LOG_CLASS(LLEventPollResponder);  	public:  		static LLHTTPClient::ResponderPtr start(const std::string& pollURL, const LLHost& sender); @@ -56,19 +57,19 @@ namespace  		void makeRequest(); +		/* virtual */ void completedRaw(const LLChannelDescriptors& channels, +								  const LLIOPipe::buffer_ptr_t& buffer); +  	private:  		LLEventPollResponder(const std::string&	pollURL, const LLHost& sender);  		~LLEventPollResponder();  		void handleMessage(const LLSD& content); -		virtual	void errorWithContent(U32 status, const std::string& reason, const LLSD& content); -		virtual	void result(const LLSD&	content); -		virtual void completedRaw(U32 status, -									const std::string& reason, -									const LLChannelDescriptors& channels, -									const LLIOPipe::buffer_ptr_t& buffer); +		/* virtual */ void httpFailure(); +		/* virtual */ void httpSuccess(); +  	private:  		bool	mDone; @@ -149,20 +150,18 @@ namespace  	}  	// virtual  -	void LLEventPollResponder::completedRaw(U32 status, -									const std::string& reason, -									const LLChannelDescriptors& channels, -									const LLIOPipe::buffer_ptr_t& buffer) +	void LLEventPollResponder::completedRaw(const LLChannelDescriptors& channels, +											const LLIOPipe::buffer_ptr_t& buffer)  	{ -		if (status == HTTP_BAD_GATEWAY) +		if (getStatus() == HTTP_BAD_GATEWAY)  		{  			// These errors are not parsable as LLSD,   			// which LLHTTPClient::Responder::completedRaw will try to do. -			completed(status, reason, LLSD()); +			httpCompleted();  		}  		else  		{ -			LLHTTPClient::Responder::completedRaw(status,reason,channels,buffer); +			LLHTTPClient::Responder::completedRaw(channels,buffer);  		}  	} @@ -187,13 +186,13 @@ namespace  	}  	//virtual -	void LLEventPollResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +	void LLEventPollResponder::httpFailure()  	{  		if (mDone) return;  		// A HTTP_BAD_GATEWAY (502) error is our standard timeout response  		// we get this when there are no events. -		if ( status == HTTP_BAD_GATEWAY )	 +		if ( getStatus() == HTTP_BAD_GATEWAY )  		{  			mErrorCount = 0;  			makeRequest(); @@ -207,13 +206,13 @@ namespace  										+ mErrorCount * EVENT_POLL_ERROR_RETRY_SECONDS_INC  									, this); -			LL_WARNS() << "LLEventPollResponder error [status:" << status << "]: " << content << LL_ENDL; +			LL_WARNS() << dumpResponse() << LL_ENDL;  		}  		else  		{ -			LL_WARNS() << "LLEventPollResponder error <" << mCount  -					<< "> [status:" << status << "]: " << content -					<<	(mDone ? " -- done"	: "") << LL_ENDL; +			LL_WARNS() << dumpResponse() +					   << " [count:" << mCount << "] " +					   << (mDone ? " -- done" : "") << LL_ENDL;  			stop();  			// At this point we have given up and the viewer will not receive HTTP messages from the simulator. @@ -234,7 +233,7 @@ namespace  	}  	//virtual -	void LLEventPollResponder::result(const LLSD& content) +	void LLEventPollResponder::httpSuccess()  	{  		LL_DEBUGS() <<	"LLEventPollResponder::result <" << mCount	<< ">"  				 <<	(mDone ? " -- done"	: "") << LL_ENDL; @@ -243,10 +242,12 @@ namespace  		mErrorCount = 0; -		if (!content.get("events") || +		const LLSD& content = getContent(); +		if (!content.isMap() || +			!content.get("events") ||  			!content.get("id"))  		{ -			LL_WARNS() << "received event poll with no events or id key" << LL_ENDL; +			LL_WARNS() << "received event poll with no events or id key: " << dumpResponse() << LL_ENDL;  			makeRequest();  			return;  		} @@ -260,8 +261,8 @@ namespace  		}  		// was LL_INFOS() but now that CoarseRegionUpdate is TCP @ 1/second, it'd be too verbose for viewer logs. -MG -		LL_DEBUGS()  << "LLEventPollResponder::completed <" <<	mCount << "> " << events.size() << "events (id " -				 <<	LLSDXMLStreamer(mAcknowledge) << ")" << LL_ENDL; +		LL_DEBUGS()  << "LLEventPollResponder::httpSuccess <" <<	mCount << "> " << events.size() << "events (id " +					 <<	LLSDXMLStreamer(mAcknowledge) << ")" << LL_ENDL;  		LLSD::array_const_iterator i = events.beginArray();  		LLSD::array_const_iterator end = events.endArray(); diff --git a/indra/newview/llfacebookconnect.cpp b/indra/newview/llfacebookconnect.cpp index 514aac46fc..e2fa117453 100644..100755 --- a/indra/newview/llfacebookconnect.cpp +++ b/indra/newview/llfacebookconnect.cpp @@ -110,28 +110,36 @@ public:          LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTION_IN_PROGRESS);      } -	virtual void completed(U32 status, const std::string& reason, const LLSD& content) +	/* virtual */ void httpSuccess()  	{ -		if (isGoodStatus(status)) +		LL_DEBUGS("FacebookConnect") << "Connect successful. " << dumpResponse() << LL_ENDL; +		LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTED); +	} + +	/* virtual */ void httpFailure() +	{ +		if ( HTTP_FOUND == getStatus() )  		{ -			LL_DEBUGS("FacebookConnect") << "Connect successful. content: " << content << LL_ENDL; -			 -            LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTED); +			const std::string& location = getResponseHeader(HTTP_IN_HEADER_LOCATION); +			if (location.empty()) +			{ +				LL_WARNS("FacebookConnect") << "Missing Location header " << dumpResponse() +							 << "[headers:" << getResponseHeaders() << "]" << LL_ENDL; +			} +			else +			{ +				LLFacebookConnect::instance().openFacebookWeb(location); +			}  		} -		else if (status != 302) +		else  		{ -            LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTION_FAILED); -            log_facebook_connect_error("Connect", status, reason, content.get("error_code"), content.get("error_description")); +			LL_WARNS("FacebookConnect") << dumpResponse() << LL_ENDL; +			LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTION_FAILED); +			const LLSD& content = getContent(); +			log_facebook_connect_error("Connect", getStatus(), getReason(), +									   content.get("error_code"), content.get("error_description"));  		}  	} -     -    void completedHeader(U32 status, const std::string& reason, const LLSD& content) -    { -        if (status == 302) -        { -            LLFacebookConnect::instance().openFacebookWeb(content["location"]); -        } -    }  };  /////////////////////////////////////////////////////////////////////////////// @@ -145,34 +153,42 @@ public:  	{  		LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_POSTING);  	} -	 -	virtual void completed(U32 status, const std::string& reason, const LLSD& content) + +	/* virtual */ void httpSuccess() +	{ +		toast_user_for_success(); +		LL_DEBUGS("FacebookConnect") << "Post successful. " << dumpResponse() << LL_ENDL; +		LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_POSTED); +	} + +	/* virtual */ void httpFailure()  	{ -		if (isGoodStatus(status)) +		if ( HTTP_FOUND == getStatus() )  		{ -            toast_user_for_success(); -			LL_DEBUGS("FacebookConnect") << "Post successful. content: " << content << LL_ENDL; -			 -			LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_POSTED); +			const std::string& location = getResponseHeader(HTTP_IN_HEADER_LOCATION); +			if (location.empty()) +			{ +				LL_WARNS("FacebookConnect") << "Missing Location header " << dumpResponse() +							 << "[headers:" << getResponseHeaders() << "]" << LL_ENDL; +			} +			else +			{ +				LLFacebookConnect::instance().openFacebookWeb(location); +			}  		} -		else if (status == 404) +		else if ( HTTP_NOT_FOUND == getStatus() )  		{  			LLFacebookConnect::instance().connectToFacebook();  		}  		else  		{ -            LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_POST_FAILED); -            log_facebook_connect_error("Share", status, reason, content.get("error_code"), content.get("error_description")); +			LL_WARNS("FacebookConnect") << dumpResponse() << LL_ENDL; +			LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_POST_FAILED); +			const LLSD& content = getContent(); +			log_facebook_connect_error("Share", getStatus(), getReason(), +									   content.get("error_code"), content.get("error_description"));  		}  	} -     -    void completedHeader(U32 status, const std::string& reason, const LLSD& content) -    { -        if (status == 302) -        { -            LLFacebookConnect::instance().openFacebookWeb(content["location"]); -        } -    }  };  /////////////////////////////////////////////////////////////////////////////// @@ -196,24 +212,27 @@ public:  		LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_NOT_CONNECTED);  	} -	virtual void completed(U32 status, const std::string& reason, const LLSD& content) +	/* virtual */ void httpSuccess()  	{ -		if (isGoodStatus(status))  -		{ -			LL_DEBUGS("FacebookConnect") << "Disconnect successful. content: " << content << LL_ENDL; -			setUserDisconnected(); +		LL_DEBUGS("FacebookConnect") << "Disconnect successful. " << dumpResponse() << LL_ENDL; +		setUserDisconnected(); +	} -		} +	/* virtual */ void httpFailure() +	{  		//User not found so already disconnected -		else if(status == 404) +		if ( HTTP_NOT_FOUND == getStatus() )  		{ -			LL_DEBUGS("FacebookConnect") << "Already disconnected. content: " << content << LL_ENDL; +			LL_DEBUGS("FacebookConnect") << "Already disconnected. " << dumpResponse() << LL_ENDL;  			setUserDisconnected();  		}  		else  		{ +			LL_WARNS("FacebookConnect") << dumpResponse() << LL_ENDL;  			LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_DISCONNECT_FAILED); -            log_facebook_connect_error("Disconnect", status, reason, content.get("error_code"), content.get("error_description")); +			const LLSD& content = getContent(); +			log_facebook_connect_error("Disconnect", getStatus(), getReason(), +									   content.get("error_code"), content.get("error_description"));  		}  	}  }; @@ -229,34 +248,35 @@ public:      {  		LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTION_IN_PROGRESS);      } -     -	virtual void completed(U32 status, const std::string& reason, const LLSD& content) + +	/* virtual */ void httpSuccess()  	{ -		if (isGoodStatus(status)) +		LL_DEBUGS("FacebookConnect") << "Connect successful. " << dumpResponse() << LL_ENDL; +		LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTED); +	} + +	/* virtual */ void httpFailure() +	{ +		// show the facebook login page if not connected yet +		if ( HTTP_NOT_FOUND == getStatus() )  		{ -			LL_DEBUGS("FacebookConnect") << "Connect successful. content: " << content << LL_ENDL; -             -            LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTED); +			LL_DEBUGS("FacebookConnect") << "Not connected. " << dumpResponse() << LL_ENDL; +			if (mAutoConnect) +			{ +				LLFacebookConnect::instance().connectToFacebook(); +			} +			else +			{ +				LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_NOT_CONNECTED); +			}  		}  		else  		{ -			// show the facebook login page if not connected yet -			if (status == 404) -			{ -				if (mAutoConnect) -				{ -					LLFacebookConnect::instance().connectToFacebook(); -				} -				else -				{ -					LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_NOT_CONNECTED); -				} -			} -            else -            { -                LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTION_FAILED); -				log_facebook_connect_error("Connected", status, reason, content.get("error_code"), content.get("error_description")); -            } +			LL_WARNS("FacebookConnect") << dumpResponse() << LL_ENDL; +			LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_DISCONNECT_FAILED); +			const LLSD& content = getContent(); +			log_facebook_connect_error("Connected", getStatus(), getReason(), +									   content.get("error_code"), content.get("error_description"));  		}  	} @@ -271,25 +291,27 @@ class LLFacebookInfoResponder : public LLHTTPClient::Responder  	LOG_CLASS(LLFacebookInfoResponder);  public: -	virtual void completed(U32 status, const std::string& reason, const LLSD& info) +	/* virtual */ void httpSuccess() +	{ +		LL_INFOS("FacebookConnect") << "Facebook: Info received" << LL_ENDL; +		LL_DEBUGS("FacebookConnect") << "Getting Facebook info successful. " << dumpResponse() << LL_ENDL; +		LLFacebookConnect::instance().storeInfo(getContent()); +	} + +	/* virtual */ void httpFailure()  	{ -		if (isGoodStatus(status)) +		if ( HTTP_FOUND == getStatus() )  		{  			LL_INFOS() << "Facebook: Info received" << LL_ENDL; -			LL_DEBUGS("FacebookConnect") << "Getting Facebook info successful. info: " << info << LL_ENDL; -			LLFacebookConnect::instance().storeInfo(info); +			LL_DEBUGS("FacebookConnect") << "Getting Facebook info successful. info: " << getContent() << LL_ENDL; +			LLFacebookConnect::instance().storeInfo(getContent());  		}  		else  		{ -			log_facebook_connect_error("Info", status, reason, info.get("error_code"), info.get("error_description")); -		} -	} - -	void completedHeader(U32 status, const std::string& reason, const LLSD& content) -	{ -		if (status == 302) -		{ -			LLFacebookConnect::instance().openFacebookWeb(content["location"]); +			LL_WARNS("FacebookConnect") << dumpResponse() << LL_ENDL; +			const LLSD& content = getContent(); +			log_facebook_connect_error("Info", getStatus(), getReason(), +									   content.get("error_code"), content.get("error_description"));  		}  	}  }; @@ -300,27 +322,36 @@ class LLFacebookFriendsResponder : public LLHTTPClient::Responder  {  	LOG_CLASS(LLFacebookFriendsResponder);  public: +     +	/* virtual */ void httpSuccess() +	{ +		LL_DEBUGS("FacebookConnect") << "Getting Facebook friends successful. " << dumpResponse() << LL_ENDL; +		LLFacebookConnect::instance().storeContent(getContent()); +	} -	virtual void completed(U32 status, const std::string& reason, const LLSD& content) +	/* virtual */ void httpFailure()  	{ -		if (isGoodStatus(status)) +		if ( HTTP_FOUND == getStatus() )  		{ -			LL_DEBUGS("FacebookConnect") << "Getting Facebook friends successful. content: " << content << LL_ENDL; -			LLFacebookConnect::instance().storeContent(content); +			const std::string& location = getResponseHeader(HTTP_IN_HEADER_LOCATION); +			if (location.empty()) +			{ +				LL_WARNS("FacebookConnect") << "Missing Location header " << dumpResponse() +							 << "[headers:" << getResponseHeaders() << "]" << LL_ENDL; +			} +			else +			{ +				LLFacebookConnect::instance().openFacebookWeb(location); +			}  		}  		else  		{ -            log_facebook_connect_error("Friends", status, reason, content.get("error_code"), content.get("error_description")); +			LL_WARNS("FacebookConnect") << dumpResponse() << LL_ENDL; +			const LLSD& content = getContent(); +			log_facebook_connect_error("Friends", getStatus(), getReason(), +									   content.get("error_code"), content.get("error_description"));  		}  	} - -    void completedHeader(U32 status, const std::string& reason, const LLSD& content) -    { -        if (status == 302) -        { -            LLFacebookConnect::instance().openFacebookWeb(content["location"]); -        } -    }  };  /////////////////////////////////////////////////////////////////////////////// diff --git a/indra/newview/llfeaturemanager.cpp b/indra/newview/llfeaturemanager.cpp index 8c3a4bb5c0..d0555477ea 100755 --- a/indra/newview/llfeaturemanager.cpp +++ b/indra/newview/llfeaturemanager.cpp @@ -39,6 +39,7 @@  #include "llgl.h"  #include "llappviewer.h" +#include "llbufferstream.h"  #include "llhttpclient.h"  #include "llnotificationsutil.h"  #include "llviewercontrol.h" @@ -609,6 +610,7 @@ bool LLFeatureManager::parseGPUTable(std::string filename)  // responder saves table into file  class LLHTTPFeatureTableResponder : public LLHTTPClient::Responder  { +	LOG_CLASS(LLHTTPFeatureTableResponder);  public:  	LLHTTPFeatureTableResponder(std::string filename) : @@ -617,11 +619,10 @@ public:  	} -	virtual void completedRaw(U32 status, const std::string& reason, -							  const LLChannelDescriptors& channels, +	virtual void completedRaw(const LLChannelDescriptors& channels,  							  const LLIOPipe::buffer_ptr_t& buffer)  	{ -		if (isGoodStatus(status)) +		if (isGoodStatus())  		{  			// write to file @@ -640,7 +641,18 @@ public:  				out.close();  			}  		} -		 +		else +		{ +			char body[1025];  +			body[1024] = '\0'; +			LLBufferStream istr(channels, buffer.get()); +			istr.get(body,1024); +			if (strlen(body) > 0) +			{ +				mContent["body"] = body; +			} +			LL_WARNS() << dumpResponse() << LL_ENDL; +		}  	}  private: diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp index 8402148a46..a7f5cd9dac 100755 --- a/indra/newview/llfilepicker.cpp +++ b/indra/newview/llfilepicker.cpp @@ -1105,9 +1105,9 @@ static std::string add_imageload_filter_to_gtkchooser(GtkWindow *picker)  {  	GtkFileFilter *gfilter = gtk_file_filter_new();  	gtk_file_filter_add_pattern(gfilter, "*.tga"); -	gtk_file_filter_add_mime_type(gfilter, "image/jpeg"); -	gtk_file_filter_add_mime_type(gfilter, "image/png"); -	gtk_file_filter_add_mime_type(gfilter, "image/bmp"); +	gtk_file_filter_add_mime_type(gfilter, HTTP_CONTENT_IMAGE_JPEG.c_str()); +	gtk_file_filter_add_mime_type(gfilter, HTTP_CONTENT_IMAGE_PNG.c_str()); +	gtk_file_filter_add_mime_type(gfilter, HTTP_CONTENT_IMAGE_BMP.c_str());  	std::string filtername = LLTrans::getString("image_files") + " (*.tga; *.bmp; *.jpg; *.png)";  	add_common_filters_to_gtkchooser(gfilter, picker, filtername);  	return filtername; @@ -1115,13 +1115,13 @@ static std::string add_imageload_filter_to_gtkchooser(GtkWindow *picker)  static std::string add_script_filter_to_gtkchooser(GtkWindow *picker)  { -	return add_simple_mime_filter_to_gtkchooser(picker,  "text/plain", +	return add_simple_mime_filter_to_gtkchooser(picker,  HTTP_CONTENT_TEXT_PLAIN,  							LLTrans::getString("script_files") + " (*.lsl)");  }  static std::string add_dictionary_filter_to_gtkchooser(GtkWindow *picker)  { -	return add_simple_mime_filter_to_gtkchooser(picker,  "text/plain", +	return add_simple_mime_filter_to_gtkchooser(picker, HTTP_CONTENT_TEXT_PLAIN,  							LLTrans::getString("dictionary_files") + " (*.dic; *.xcu)");  } @@ -1177,7 +1177,7 @@ BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename  			break;  		case FFSAVE_BMP:  			caption += add_simple_mime_filter_to_gtkchooser -				(picker, "image/bmp", LLTrans::getString("bitmap_image_files") + " (*.bmp)"); +				(picker, HTTP_CONTENT_IMAGE_BMP, LLTrans::getString("bitmap_image_files") + " (*.bmp)");  			suggest_ext = ".bmp";  			break;  		case FFSAVE_PNG: @@ -1211,6 +1211,7 @@ BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename  			suggest_ext = ".raw";  			break;  		case FFSAVE_J2C: +			// *TODO: Should this be 'image/j2c' ?  			caption += add_simple_mime_filter_to_gtkchooser  				(picker, "images/jp2",  				 LLTrans::getString("compressed_image_files") + " (*.j2c)"); diff --git a/indra/newview/llfloaterabout.cpp b/indra/newview/llfloaterabout.cpp index efaba1d7a4..15b94034bb 100755 --- a/indra/newview/llfloaterabout.cpp +++ b/indra/newview/llfloaterabout.cpp @@ -76,14 +76,9 @@ class LLServerReleaseNotesURLFetcher : public LLHTTPClient::Responder  {  	LOG_CLASS(LLServerReleaseNotesURLFetcher);  public: -  	static void startFetch(); -	/*virtual*/ void completedHeader(U32 status, const std::string& reason, const LLSD& content); -	/*virtual*/ void completedRaw( -		U32 status, -		const std::string& reason, -		const LLChannelDescriptors& channels, -		const LLIOPipe::buffer_ptr_t& buffer); +private: +	/* virtual */ void httpCompleted();  };  ///---------------------------------------------------------------------------- @@ -303,16 +298,15 @@ void LLServerReleaseNotesURLFetcher::startFetch()  }  // virtual -void LLServerReleaseNotesURLFetcher::completedHeader(U32 status, const std::string& reason, const LLSD& content) +void LLServerReleaseNotesURLFetcher::httpCompleted()  { -	LL_DEBUGS() << "Status: " << status << LL_ENDL; -	LL_DEBUGS() << "Reason: " << reason << LL_ENDL; -	LL_DEBUGS() << "Headers: " << content << LL_ENDL; +	LL_DEBUGS("ServerReleaseNotes") << dumpResponse()  +									<< " [headers:" << getResponseHeaders() << "]" << LL_ENDL;  	LLFloaterAbout* floater_about = LLFloaterReg::getTypedInstance<LLFloaterAbout>("sl_about");  	if (floater_about)  	{ -		std::string location = content["location"].asString(); +		std::string location = getResponseHeader(HTTP_IN_HEADER_LOCATION);  		if (location.empty())  		{  			location = LLTrans::getString("ErrorFetchingServerReleaseNotesURL"); @@ -321,14 +315,3 @@ void LLServerReleaseNotesURLFetcher::completedHeader(U32 status, const std::stri  	}  } -// virtual -void LLServerReleaseNotesURLFetcher::completedRaw( -	U32 status, -	const std::string& reason, -	const LLChannelDescriptors& channels, -	const LLIOPipe::buffer_ptr_t& buffer) -{ -	// Do nothing. -	// We're overriding just because the base implementation tries to -	// deserialize LLSD which triggers warnings. -} diff --git a/indra/newview/llfloateravatarpicker.cpp b/indra/newview/llfloateravatarpicker.cpp index c1e6673406..3e032d0e4a 100755 --- a/indra/newview/llfloateravatarpicker.cpp +++ b/indra/newview/llfloateravatarpicker.cpp @@ -458,13 +458,15 @@ BOOL LLFloaterAvatarPicker::visibleItemsSelected() const  class LLAvatarPickerResponder : public LLHTTPClient::Responder  { +	LOG_CLASS(LLAvatarPickerResponder);  public:  	LLUUID mQueryID;      std::string mName;  	LLAvatarPickerResponder(const LLUUID& id, const std::string& name) : mQueryID(id), mName(name) { } -	/*virtual*/ void completed(U32 status, const std::string& reason, const LLSD& content) +protected: +	/*virtual*/ void httpCompleted()  	{  		//std::ostringstream ss;  		//LLSDSerialize::toPrettyXML(content, ss); @@ -472,19 +474,18 @@ public:  		// in case of invalid characters, the avatar picker returns a 400  		// just set it to process so it displays 'not found' -		if (isGoodStatus(status) || status == 400) +		if (isGoodStatus() || getStatus() == HTTP_BAD_REQUEST)  		{  			LLFloaterAvatarPicker* floater =  				LLFloaterReg::findTypedInstance<LLFloaterAvatarPicker>("avatar_picker", mName);  			if (floater)  			{ -				floater->processResponse(mQueryID, content); +				floater->processResponse(mQueryID, getContent());  			}  		}  		else  		{ -			LL_WARNS() << "avatar picker failed [status:" << status << "]: " << content << LL_ENDL; -			 +			LL_WARNS() << "avatar picker failed " << dumpResponse() << LL_ENDL;  		}  	}  }; diff --git a/indra/newview/llfloaterbuycurrencyhtml.cpp b/indra/newview/llfloaterbuycurrencyhtml.cpp index 0c408f556d..a69aa8d227 100755 --- a/indra/newview/llfloaterbuycurrencyhtml.cpp +++ b/indra/newview/llfloaterbuycurrencyhtml.cpp @@ -27,6 +27,7 @@  #include "llviewerprecompiledheaders.h"  #include "llfloaterbuycurrencyhtml.h" +#include "llhttpconstants.h"  #include "llstatusbar.h"  //////////////////////////////////////////////////////////////////////////////// @@ -85,7 +86,7 @@ void LLFloaterBuyCurrencyHTML::navigateToFinalURL()  	LL_INFOS() << "Buy currency HTML parsed URL is " << buy_currency_url << LL_ENDL;  	// kick off the navigation -	mBrowser->navigateTo( buy_currency_url, "text/html" ); +	mBrowser->navigateTo( buy_currency_url, HTTP_CONTENT_TEXT_HTML );  }  //////////////////////////////////////////////////////////////////////////////// diff --git a/indra/newview/llfloatergesture.cpp b/indra/newview/llfloatergesture.cpp index 1452d53265..9797b5c062 100755 --- a/indra/newview/llfloatergesture.cpp +++ b/indra/newview/llfloatergesture.cpp @@ -617,9 +617,10 @@ void LLFloaterGesture::addToCurrentOutFit()  	uuid_vec_t ids;  	getSelectedIds(ids);  	LLAppearanceMgr* am = LLAppearanceMgr::getInstance(); +	LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy;  	for(uuid_vec_t::const_iterator it = ids.begin(); it != ids.end(); it++)  	{ -		am->addCOFItemLink(*it); +		am->addCOFItemLink(*it, cb);  	}  } diff --git a/indra/newview/llfloaterhelpbrowser.cpp b/indra/newview/llfloaterhelpbrowser.cpp index 4cb632bd6a..c0bb213540 100755 --- a/indra/newview/llfloaterhelpbrowser.cpp +++ b/indra/newview/llfloaterhelpbrowser.cpp @@ -29,6 +29,7 @@  #include "llfloaterhelpbrowser.h"  #include "llfloaterreg.h" +#include "llhttpconstants.h"  #include "llpluginclassmedia.h"  #include "llmediactrl.h"  #include "llviewerwindow.h" @@ -37,7 +38,6 @@  #include "llui.h"  #include "llurlhistory.h" -#include "llmediactrl.h"  #include "llviewermedia.h"  #include "llviewerhelp.h" @@ -148,7 +148,7 @@ void LLFloaterHelpBrowser::openMedia(const std::string& media_url)  {  	// explicitly make the media mime type for this floater since it will  	// only ever display one type of content (Web). -	mBrowser->setHomePageUrl(media_url, "text/html"); -	mBrowser->navigateTo(media_url, "text/html"); +	mBrowser->setHomePageUrl(media_url, HTTP_CONTENT_TEXT_HTML); +	mBrowser->navigateTo(media_url, HTTP_CONTENT_TEXT_HTML);  	setCurrentURL(media_url);  } diff --git a/indra/newview/llfloaterimsession.cpp b/indra/newview/llfloaterimsession.cpp index f61359f87a..7852a1f7b3 100644..100755 --- a/indra/newview/llfloaterimsession.cpp +++ b/indra/newview/llfloaterimsession.cpp @@ -1181,16 +1181,17 @@ BOOL LLFloaterIMSession::isInviteAllowed() const  class LLSessionInviteResponder : public LLHTTPClient::Responder  { +	LOG_CLASS(LLSessionInviteResponder);  public:  	LLSessionInviteResponder(const LLUUID& session_id)  	{  		mSessionID = session_id;  	} -	void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content) +protected: +	void httpFailure()  	{ -		LL_WARNS() << "Error inviting all agents to session [status:"  -				<< statusNum << "]: " << content << LL_ENDL; +		LL_WARNS() << "Error inviting all agents to session " << dumpResponse() << LL_ENDL;  		//throw something back to the viewer here?  	} diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 12c1a68ccd..b17ce97a2e 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -5861,7 +5861,7 @@ void LLFloaterModelPreview::handleModelPhysicsFeeReceived()  	mUploadBtn->setEnabled(mHasUploadPerm && !mUploadModelUrl.empty());  } -void LLFloaterModelPreview::setModelPhysicsFeeErrorStatus(U32 status, const std::string& reason) +void LLFloaterModelPreview::setModelPhysicsFeeErrorStatus(S32 status, const std::string& reason)  {  	LL_WARNS() << "LLFloaterModelPreview::setModelPhysicsFeeErrorStatus(" << status << " : " << reason << ")" << LL_ENDL;  	doOnIdleOneTime(boost::bind(&LLFloaterModelPreview::toggleCalculateButton, this, true)); @@ -5937,7 +5937,7 @@ void LLFloaterModelPreview::onPermissionsReceived(const LLSD& result)  	getChild<LLTextBox>("warning_message")->setVisible(!mHasUploadPerm);  } -void LLFloaterModelPreview::setPermissonsErrorStatus(U32 status, const std::string& reason) +void LLFloaterModelPreview::setPermissonsErrorStatus(S32 status, const std::string& reason)  {  	LL_WARNS() << "LLFloaterModelPreview::setPermissonsErrorStatus(" << status << " : " << reason << ")" << LL_ENDL; diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index e588418f7b..6c0c60b87f 100755 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -200,11 +200,11 @@ public:  	/*virtual*/ void onPermissionsReceived(const LLSD& result);  	// called when error occurs during permissions request -	/*virtual*/ void setPermissonsErrorStatus(U32 status, const std::string& reason); +	/*virtual*/ void setPermissonsErrorStatus(S32 status, const std::string& reason);  	/*virtual*/ void onModelPhysicsFeeReceived(const LLSD& result, std::string upload_url);  				void handleModelPhysicsFeeReceived(); -	/*virtual*/ void setModelPhysicsFeeErrorStatus(U32 status, const std::string& reason); +	/*virtual*/ void setModelPhysicsFeeErrorStatus(S32 status, const std::string& reason);  	/*virtual*/ void onModelUploadSuccess(); diff --git a/indra/newview/llfloatermodeluploadbase.cpp b/indra/newview/llfloatermodeluploadbase.cpp index 2ad2d32652..22a8ac4705 100755 --- a/indra/newview/llfloatermodeluploadbase.cpp +++ b/indra/newview/llfloatermodeluploadbase.cpp @@ -44,8 +44,10 @@ void LLFloaterModelUploadBase::requestAgentUploadPermissions()  	if (!url.empty())  	{ -		LL_INFOS()<< typeid(*this).name() <<"::requestAgentUploadPermissions() requesting for upload model permissions from: "<< url <<LL_ENDL; -		LLHTTPClient::get(url, new LLUploadModelPremissionsResponder(getPermObserverHandle())); +		LL_INFOS()<< typeid(*this).name() +				  << "::requestAgentUploadPermissions() requesting for upload model permissions from: " +				  << url << LL_ENDL; +		LLHTTPClient::get(url, new LLUploadModelPermissionsResponder(getPermObserverHandle()));  	}  	else  	{ diff --git a/indra/newview/llfloatermodeluploadbase.h b/indra/newview/llfloatermodeluploadbase.h index a52bc28687..d9a8879687 100755 --- a/indra/newview/llfloatermodeluploadbase.h +++ b/indra/newview/llfloatermodeluploadbase.h @@ -37,13 +37,13 @@ public:  	virtual ~LLFloaterModelUploadBase(){}; -	virtual void setPermissonsErrorStatus(U32 status, const std::string& reason) = 0; +	virtual void setPermissonsErrorStatus(S32 status, const std::string& reason) = 0;  	virtual void onPermissionsReceived(const LLSD& result) = 0;  	virtual void onModelPhysicsFeeReceived(const LLSD& result, std::string upload_url) = 0; -	virtual void setModelPhysicsFeeErrorStatus(U32 status, const std::string& reason) = 0; +	virtual void setModelPhysicsFeeErrorStatus(S32 status, const std::string& reason) = 0;  	virtual void onModelUploadSuccess() {}; diff --git a/indra/newview/llfloaterobjectweights.cpp b/indra/newview/llfloaterobjectweights.cpp index 94bf8974bb..feaeef4ad0 100755 --- a/indra/newview/llfloaterobjectweights.cpp +++ b/indra/newview/llfloaterobjectweights.cpp @@ -123,7 +123,7 @@ void LLFloaterObjectWeights::onWeightsUpdate(const SelectionCost& selection_cost  }  //virtual -void LLFloaterObjectWeights::setErrorStatus(U32 status, const std::string& reason) +void LLFloaterObjectWeights::setErrorStatus(S32 status, const std::string& reason)  {  	const std::string text = getString("nothing_selected"); diff --git a/indra/newview/llfloaterobjectweights.h b/indra/newview/llfloaterobjectweights.h index 9a244573be..1a2c317bad 100755 --- a/indra/newview/llfloaterobjectweights.h +++ b/indra/newview/llfloaterobjectweights.h @@ -63,7 +63,7 @@ public:  	/*virtual*/ void onOpen(const LLSD& key);  	/*virtual*/ void onWeightsUpdate(const SelectionCost& selection_cost); -	/*virtual*/ void setErrorStatus(U32 status, const std::string& reason); +	/*virtual*/ void setErrorStatus(S32 status, const std::string& reason);  	void updateLandImpacts(const LLParcel* parcel);  	void refresh(); diff --git a/indra/newview/llfloateropenobject.cpp b/indra/newview/llfloateropenobject.cpp index 4bfef8b45f..9986bdbd7f 100755 --- a/indra/newview/llfloateropenobject.cpp +++ b/indra/newview/llfloateropenobject.cpp @@ -162,21 +162,17 @@ void LLFloaterOpenObject::moveToInventory(bool wear)  	{  		parent_category_id = gInventory.getRootFolderID();  	} -	 -	LLCategoryCreate* cat_data = new LLCategoryCreate(object_id, wear); -	 + +	inventory_func_type func = boost::bind(LLFloaterOpenObject::callbackCreateInventoryCategory,_1,object_id,wear);  	LLUUID category_id = gInventory.createNewCategory(parent_category_id,   													  LLFolderType::FT_NONE,   													  name, -													  callbackCreateInventoryCategory, -													  (void*)cat_data); +													  func);  	//If we get a null category ID, we are using a capability in createNewCategory and we will  	//handle the following in the callbackCreateInventoryCategory routine.  	if ( category_id.notNull() )  	{ -		delete cat_data; -		  		LLCatAndWear* data = new LLCatAndWear;  		data->mCatID = category_id;  		data->mWear = wear; @@ -198,20 +194,17 @@ void LLFloaterOpenObject::moveToInventory(bool wear)  }  // static -void LLFloaterOpenObject::callbackCreateInventoryCategory(const LLSD& result, void* data) +void LLFloaterOpenObject::callbackCreateInventoryCategory(const LLUUID& category_id, LLUUID object_id, bool wear)  { -	LLCategoryCreate* cat_data = (LLCategoryCreate*)data; -	 -	LLUUID category_id = result["folder_id"].asUUID();  	LLCatAndWear* wear_data = new LLCatAndWear;  	wear_data->mCatID = category_id; -	wear_data->mWear = cat_data->mWear; +	wear_data->mWear = wear;  	wear_data->mFolderResponded = true;  	// Copy and/or move the items into the newly created folder.  	// Ignore any "you're going to break this item" messages. -	BOOL success = move_inv_category_world_to_agent(cat_data->mObjectID, category_id, TRUE, +	BOOL success = move_inv_category_world_to_agent(object_id, category_id, TRUE,  													callbackMoveInventory,   													(void*)wear_data);  	if (!success) @@ -221,7 +214,6 @@ void LLFloaterOpenObject::callbackCreateInventoryCategory(const LLSD& result, vo  		LLNotificationsUtil::add("OpenObjectCannotCopy");  	} -	delete cat_data;	  }  // static diff --git a/indra/newview/llfloateropenobject.h b/indra/newview/llfloateropenobject.h index bf7fe69c65..8e472804a4 100755 --- a/indra/newview/llfloateropenobject.h +++ b/indra/newview/llfloateropenobject.h @@ -45,15 +45,6 @@ public:  	void dirty(); -	class LLCategoryCreate -	{ -		public: -			LLCategoryCreate(LLUUID object_id, bool wear) : mObjectID(object_id), mWear(wear) {} -		public: -			LLUUID mObjectID; -			bool mWear; -	}; -	  	struct LLCatAndWear  	{  		LLUUID mCatID; @@ -72,7 +63,7 @@ protected:  	void onClickMoveToInventory();  	void onClickMoveAndWear(); -	static void callbackCreateInventoryCategory(const LLSD& result, void* data); +	static void callbackCreateInventoryCategory(const LLUUID& category_id, LLUUID object_id, bool wear);  	static void callbackMoveInventory(S32 result, void* data);  private: diff --git a/indra/newview/llfloaterregiondebugconsole.cpp b/indra/newview/llfloaterregiondebugconsole.cpp index bed34abee8..40757a4d04 100755 --- a/indra/newview/llfloaterregiondebugconsole.cpp +++ b/indra/newview/llfloaterregiondebugconsole.cpp @@ -73,24 +73,29 @@ namespace  	// called if this request times out.  	class AsyncConsoleResponder : public LLHTTPClient::Responder  	{ -	public: +		LOG_CLASS(AsyncConsoleResponder); +	protected:  		/* virtual */ -		void errorWithContent(U32 status, const std::string& reason, const LLSD& content) +		void httpFailure()  		{ +			LL_WARNS("Console") << dumpResponse() << LL_ENDL;  			sConsoleReplySignal(UNABLE_TO_SEND_COMMAND);  		}  	};  	class ConsoleResponder : public LLHTTPClient::Responder  	{ +		LOG_CLASS(ConsoleResponder);  	public:  		ConsoleResponder(LLTextEditor *output) : mOutput(output)  		{  		} +	protected:  		/*virtual*/ -		void error(U32 status, const std::string& reason) +		void httpFailure()  		{ +			LL_WARNS("Console") << dumpResponse() << LL_ENDL;  			if (mOutput)  			{  				mOutput->appendText( @@ -100,8 +105,10 @@ namespace  		}  		/*virtual*/ -		void result(const LLSD& content) +		void httpSuccess()  		{ +			const LLSD& content = getContent(); +			LL_DEBUGS("Console") << content << LL_ENDL;  			if (mOutput)  			{  				mOutput->appendText( @@ -109,6 +116,7 @@ namespace  			}  		} +	public:  		LLTextEditor * mOutput;  	}; diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp index d67089ff85..5e9b25b474 100755 --- a/indra/newview/llfloaterregioninfo.cpp +++ b/indra/newview/llfloaterregioninfo.cpp @@ -759,12 +759,12 @@ bool LLPanelRegionGeneralInfo::onMessageCommit(const LLSD& notification, const L  class ConsoleRequestResponder : public LLHTTPClient::Responder  { -public: +	LOG_CLASS(ConsoleRequestResponder); +protected:  	/*virtual*/ -	void errorWithContent(U32 status, const std::string& reason, const LLSD& content) +	void httpFailure()  	{ -		LL_WARNS() << "ConsoleRequestResponder error requesting mesh_rez_enabled [status:" -				<< status << "]: " << content << LL_ENDL; +		LL_WARNS() << "error requesting mesh_rez_enabled " << dumpResponse() << LL_ENDL;  	}  }; @@ -772,12 +772,12 @@ public:  // called if this request times out.  class ConsoleUpdateResponder : public LLHTTPClient::Responder  { -public: +	LOG_CLASS(ConsoleUpdateResponder); +protected:  	/* virtual */ -	void errorWithContent(U32 status, const std::string& reason, const LLSD& content) +	void httpFailure()  	{ -		LL_WARNS() << "ConsoleRequestResponder error updating mesh enabled region setting [status:" -				<< status << "]: " << content << LL_ENDL; +		LL_WARNS() << "error updating mesh enabled region setting " << dumpResponse() << LL_ENDL;  	}  }; @@ -2244,14 +2244,16 @@ void LLPanelEstateInfo::getEstateOwner()  class LLEstateChangeInfoResponder : public LLHTTPClient::Responder  { +	LOG_CLASS(LLEstateChangeInfoResponder);  public:  	LLEstateChangeInfoResponder(LLPanelEstateInfo* panel)  	{  		mpPanel = panel->getHandle();  	} +protected:  	// if we get a normal response, handle it here -	virtual void result(const LLSD& content) +	virtual void httpSuccess()  	{  		LL_INFOS("Windlight") << "Successfully committed estate info" << LL_ENDL; @@ -2262,10 +2264,9 @@ public:  	}  	// if we get an error response -	virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content) +	virtual void httpFailure()  	{ -		LL_INFOS() << "LLEstateChangeInfoResponder::error [status:" -			<< status << "]: " << content << LL_ENDL; +		LL_WARNS("Windlight") << dumpResponse() << LL_ENDL;  	}  private:  	LLHandle<LLPanel> mpPanel; diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp index 825159703c..a3b9713e3e 100755 --- a/indra/newview/llfloaterreporter.cpp +++ b/indra/newview/llfloaterreporter.cpp @@ -707,16 +707,18 @@ public:  class LLUserReportResponder : public LLHTTPClient::Responder  { +	LOG_CLASS(LLUserReportResponder);  public:  	LLUserReportResponder(): LLHTTPClient::Responder()  {} -	void errorWithContent(U32 status, const std::string& reason, const LLSD& content) -	{ -		// *TODO do some user messaging here -		LLUploadDialog::modalUploadFinished(); -	} -	void result(const LLSD& content) +private: +	void httpCompleted()  	{ +		if (!isGoodStatus()) +		{ +			// *TODO do some user messaging here +			LL_WARNS("UserReport") << dumpResponse() << LL_ENDL; +		}  		// we don't care about what the server returns  		LLUploadDialog::modalUploadFinished();  	} diff --git a/indra/newview/llfloaterscriptlimits.cpp b/indra/newview/llfloaterscriptlimits.cpp index 2ed7bb842d..5fbdd75e97 100755 --- a/indra/newview/llfloaterscriptlimits.cpp +++ b/indra/newview/llfloaterscriptlimits.cpp @@ -183,8 +183,14 @@ void LLPanelScriptLimitsInfo::updateChild(LLUICtrl* child_ctr)  // Responders  ///---------------------------------------------------------------------------- -void fetchScriptLimitsRegionInfoResponder::result(const LLSD& content) +void fetchScriptLimitsRegionInfoResponder::httpSuccess()  { +	const LLSD& content = getContent(); +	if (!content.isMap()) +	{ +		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); +		return; +	}  	//we don't need to test with a fake respose here (shouldn't anyway)  #ifdef DUMP_REPLIES_TO_LLINFOS @@ -221,13 +227,14 @@ void fetchScriptLimitsRegionInfoResponder::result(const LLSD& content)  	}  } -void fetchScriptLimitsRegionInfoResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void fetchScriptLimitsRegionInfoResponder::httpFailure()  { -	LL_WARNS() << "fetchScriptLimitsRegionInfoResponder error [status:" << status << "]: " << content << LL_ENDL; +	LL_WARNS() << dumpResponse() << LL_ENDL;  } -void fetchScriptLimitsRegionSummaryResponder::result(const LLSD& content_ref) +void fetchScriptLimitsRegionSummaryResponder::httpSuccess()  { +	const LLSD& content_ref = getContent();  #ifdef USE_FAKE_RESPONSES  	LLSD fake_content; @@ -268,6 +275,12 @@ void fetchScriptLimitsRegionSummaryResponder::result(const LLSD& content_ref)  #endif +	if (!content.isMap()) +	{ +		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); +		return; +	} +  #ifdef DUMP_REPLIES_TO_LLINFOS @@ -291,7 +304,7 @@ void fetchScriptLimitsRegionSummaryResponder::result(const LLSD& content_ref)  		LLTabContainer* tab = instance->getChild<LLTabContainer>("scriptlimits_panels");  		if(tab)  		{ -		LLPanelScriptLimitsRegionMemory* panel_memory = (LLPanelScriptLimitsRegionMemory*)tab->getChild<LLPanel>("script_limits_region_memory_panel"); +			LLPanelScriptLimitsRegionMemory* panel_memory = (LLPanelScriptLimitsRegionMemory*)tab->getChild<LLPanel>("script_limits_region_memory_panel");  			if(panel_memory)  			{  				panel_memory->getChild<LLUICtrl>("loading_text")->setValue(LLSD(std::string(""))); @@ -301,20 +314,21 @@ void fetchScriptLimitsRegionSummaryResponder::result(const LLSD& content_ref)  				{  					btn->setEnabled(true);  				} -				 -		panel_memory->setRegionSummary(content); -	} -} + +				panel_memory->setRegionSummary(content); +			} +		}  	}  } -void fetchScriptLimitsRegionSummaryResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void fetchScriptLimitsRegionSummaryResponder::httpFailure()  { -	LL_WARNS() << "fetchScriptLimitsRegionSummaryResponder error [status:" << status << "]: " << content << LL_ENDL; +	LL_WARNS() << dumpResponse() << LL_ENDL;  } -void fetchScriptLimitsRegionDetailsResponder::result(const LLSD& content_ref) +void fetchScriptLimitsRegionDetailsResponder::httpSuccess()  { +	const LLSD& content_ref = getContent();  #ifdef USE_FAKE_RESPONSES  /*  Updated detail service, ** denotes field added: @@ -377,6 +391,12 @@ result (map)  #endif +	if (!content.isMap()) +	{ +		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); +		return; +	} +  #ifdef DUMP_REPLIES_TO_LLINFOS  	LLSDNotationStreamer notation_streamer(content); @@ -417,13 +437,14 @@ result (map)  	}  } -void fetchScriptLimitsRegionDetailsResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void fetchScriptLimitsRegionDetailsResponder::httpFailure()  { -	LL_WARNS() << "fetchScriptLimitsRegionDetailsResponder error [status:" << status << "]: " << content << LL_ENDL; +	LL_WARNS() << dumpResponse() << LL_ENDL;  } -void fetchScriptLimitsAttachmentInfoResponder::result(const LLSD& content_ref) +void fetchScriptLimitsAttachmentInfoResponder::httpSuccess()  { +	const LLSD& content_ref = getContent();  #ifdef USE_FAKE_RESPONSES @@ -465,6 +486,12 @@ void fetchScriptLimitsAttachmentInfoResponder::result(const LLSD& content_ref)  #endif +	if (!content.isMap()) +	{ +		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); +		return; +	} +  #ifdef DUMP_REPLIES_TO_LLINFOS  	LLSDNotationStreamer notation_streamer(content); @@ -513,9 +540,9 @@ void fetchScriptLimitsAttachmentInfoResponder::result(const LLSD& content_ref)  	}  } -void fetchScriptLimitsAttachmentInfoResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void fetchScriptLimitsAttachmentInfoResponder::httpFailure()  { -	LL_WARNS() << "fetchScriptLimitsAttachmentInfoResponder error [status:" << status << "]: " << content << LL_ENDL; +	LL_WARNS() << dumpResponse() << LL_ENDL;  }  ///---------------------------------------------------------------------------- @@ -586,7 +613,7 @@ void LLPanelScriptLimitsRegionMemory::setParcelID(const LLUUID& parcel_id)  }  // virtual -void LLPanelScriptLimitsRegionMemory::setErrorStatus(U32 status, const std::string& reason) +void LLPanelScriptLimitsRegionMemory::setErrorStatus(S32 status, const std::string& reason)  {  	LL_WARNS() << "Can't handle remote parcel request."<< " Http Status: "<< status << ". Reason : "<< reason<<LL_ENDL;  } diff --git a/indra/newview/llfloaterscriptlimits.h b/indra/newview/llfloaterscriptlimits.h index f8732ef94b..a5cb1b6184 100755 --- a/indra/newview/llfloaterscriptlimits.h +++ b/indra/newview/llfloaterscriptlimits.h @@ -85,49 +85,49 @@ protected:  class fetchScriptLimitsRegionInfoResponder: public LLHTTPClient::Responder  { -	public: -		fetchScriptLimitsRegionInfoResponder(const LLSD& info) : mInfo(info) {}; - -		void result(const LLSD& content); -		void errorWithContent(U32 status, const std::string& reason, const LLSD& content); -	public: -	protected: -		LLSD mInfo; +	LOG_CLASS(fetchScriptLimitsRegionInfoResponder); +public: +	fetchScriptLimitsRegionInfoResponder(const LLSD& info) : mInfo(info) {}; + +private: +	/* virtual */ void httpSuccess(); +	/* virtual */ void httpFailure(); +	LLSD mInfo;  };  class fetchScriptLimitsRegionSummaryResponder: public LLHTTPClient::Responder  { -	public: -		fetchScriptLimitsRegionSummaryResponder(const LLSD& info) : mInfo(info) {}; - -		void result(const LLSD& content); -		void errorWithContent(U32 status, const std::string& reason, const LLSD& content); -	public: -	protected: -		LLSD mInfo; +	LOG_CLASS(fetchScriptLimitsRegionSummaryResponder); +public: +	fetchScriptLimitsRegionSummaryResponder(const LLSD& info) : mInfo(info) {}; + +private: +	/* virtual */ void httpSuccess(); +	/* virtual */ void httpFailure(); +	LLSD mInfo;  };  class fetchScriptLimitsRegionDetailsResponder: public LLHTTPClient::Responder  { -	public: -		fetchScriptLimitsRegionDetailsResponder(const LLSD& info) : mInfo(info) {}; - -		void result(const LLSD& content); -		void errorWithContent(U32 status, const std::string& reason, const LLSD& content); -	public: -	protected: -		LLSD mInfo; +	LOG_CLASS(fetchScriptLimitsRegionDetailsResponder); +public: +	fetchScriptLimitsRegionDetailsResponder(const LLSD& info) : mInfo(info) {}; + +private: +	/* virtual */ void httpSuccess(); +	/* virtual */ void httpFailure(); +	LLSD mInfo;  };  class fetchScriptLimitsAttachmentInfoResponder: public LLHTTPClient::Responder  { -	public: -		fetchScriptLimitsAttachmentInfoResponder() {}; +	LOG_CLASS(fetchScriptLimitsAttachmentInfoResponder); +public: +	fetchScriptLimitsAttachmentInfoResponder() {}; -		void result(const LLSD& content); -		void errorWithContent(U32 status, const std::string& reason, const LLSD& content); -	public: -	protected: +private: +	/* virtual */ void httpSuccess(); +	/* virtual */ void httpFailure();  };  ///////////////////////////////////////////////////////////////////////////// @@ -190,7 +190,7 @@ protected:  // LLRemoteParcelInfoObserver interface:  /*virtual*/ void processParcelInfo(const LLParcelData& parcel_data);  /*virtual*/ void setParcelID(const LLUUID& parcel_id); -/*virtual*/ void setErrorStatus(U32 status, const std::string& reason); +/*virtual*/ void setErrorStatus(S32 status, const std::string& reason);  	static void onClickRefresh(void* userdata);  	static void onClickHighlight(void* userdata); diff --git a/indra/newview/llfloatersearch.cpp b/indra/newview/llfloatersearch.cpp index 2a946b1edf..a446b767ac 100755 --- a/indra/newview/llfloatersearch.cpp +++ b/indra/newview/llfloatersearch.cpp @@ -30,6 +30,7 @@  #include "llcommandhandler.h"  #include "llfloaterreg.h"  #include "llfloatersearch.h" +#include "llhttpconstants.h"  #include "llmediactrl.h"  #include "llnotificationsutil.h"  #include "lllogininstance.h" @@ -200,5 +201,5 @@ void LLFloaterSearch::search(const SearchQuery &p)  	url = LLWeb::expandURLSubstitutions(url, subs);  	// and load the URL in the web view -	mWebBrowser->navigateTo(url, "text/html"); +	mWebBrowser->navigateTo(url, HTTP_CONTENT_TEXT_HTML);  } diff --git a/indra/newview/llfloatertos.cpp b/indra/newview/llfloatertos.cpp index a242b224cd..0613ffc94d 100755 --- a/indra/newview/llfloatertos.cpp +++ b/indra/newview/llfloatertos.cpp @@ -36,7 +36,7 @@  #include "llbutton.h"  #include "llevents.h"  #include "llhttpclient.h" -#include "llhttpstatuscodes.h"	// for HTTP_FOUND +#include "llhttpconstants.h"  #include "llnotificationsutil.h"  #include "llradiogroup.h"  #include "lltextbox.h" @@ -62,42 +62,46 @@ LLFloaterTOS::LLFloaterTOS(const LLSD& data)  // on parent class indicating if the web server is working or not  class LLIamHere : public LLHTTPClient::Responder  { -	private: -		LLIamHere( LLFloaterTOS* parent ) : -		   mParent( parent ) -		{} +	LOG_CLASS(LLIamHere); +private: +	LLIamHere( LLFloaterTOS* parent ) : +	   mParent( parent ) +	{} -		LLFloaterTOS* mParent; +	LLFloaterTOS* mParent; -	public: - -		static LLIamHere* build( LLFloaterTOS* parent ) -		{ -			return new LLIamHere( parent ); -		}; -		 -		virtual void  setParent( LLFloaterTOS* parentIn ) -		{ -			mParent = parentIn; -		}; -		 -		virtual void result( const LLSD& content ) +public: +	static LLIamHere* build( LLFloaterTOS* parent ) +	{ +		return new LLIamHere( parent ); +	} +	 +	virtual void  setParent( LLFloaterTOS* parentIn ) +	{ +		mParent = parentIn; +	} +	 +protected: +	virtual void httpSuccess() +	{ +		if ( mParent )  		{ -			if ( mParent ) -				mParent->setSiteIsAlive( true ); -		}; +			mParent->setSiteIsAlive( true ); +		} +	} -		virtual void error( U32 status, const std::string& reason ) +	virtual void httpFailure() +	{ +		LL_DEBUGS("LLIamHere") << dumpResponse() << LL_ENDL; +		if ( mParent )  		{ -			if ( mParent ) -			{ -				// *HACK: For purposes of this alive check, 302 Found -				// (aka Moved Temporarily) is considered alive.  The web site -				// redirects this link to a "cache busting" temporary URL. JC -				bool alive = (status == HTTP_FOUND); -				mParent->setSiteIsAlive( alive ); -			} -		}; +			// *HACK: For purposes of this alive check, 302 Found +			// (aka Moved Temporarily) is considered alive.  The web site +			// redirects this link to a "cache busting" temporary URL. JC +			bool alive = (getStatus() == HTTP_FOUND); +			mParent->setSiteIsAlive( alive ); +		} +	}  };  // this is global and not a class member to keep crud out of the header file diff --git a/indra/newview/llfloaterurlentry.cpp b/indra/newview/llfloaterurlentry.cpp index e85d849c9a..e26f1e9ea5 100755 --- a/indra/newview/llfloaterurlentry.cpp +++ b/indra/newview/llfloaterurlentry.cpp @@ -48,31 +48,30 @@ static LLFloaterURLEntry* sInstance = NULL;  // on the Panel Land Media and to discover the MIME type  class LLMediaTypeResponder : public LLHTTPClient::Responder  { +	LOG_CLASS(LLMediaTypeResponder);  public:  	LLMediaTypeResponder( const LLHandle<LLFloater> parent ) : -	  mParent( parent ) -	  {} - -	  LLHandle<LLFloater> mParent; - - -	  virtual void completedHeader(U32 status, const std::string& reason, const LLSD& content) -	  { -		  std::string media_type = content["content-type"].asString(); -		  std::string::size_type idx1 = media_type.find_first_of(";"); -		  std::string mime_type = media_type.substr(0, idx1); -		  completeAny(status, mime_type); -	  } - -	  void completeAny(U32 status, const std::string& mime_type) -	  { -		  // Set empty type to none/none.  Empty string is reserved for legacy parcels -		  // which have no mime type set. -		  std::string resolved_mime_type = ! mime_type.empty() ? mime_type : LLMIMETypes::getDefaultMimeType(); -		  LLFloaterURLEntry* floater_url_entry = (LLFloaterURLEntry*)mParent.get(); -		  if ( floater_url_entry ) -			  floater_url_entry->headerFetchComplete( status, resolved_mime_type ); -	  } +		mParent( parent ) +	{} + +	LLHandle<LLFloater> mParent; + +private: +	/* virtual */ void httpCompleted() +	{ +		const std::string& media_type = getResponseHeader(HTTP_IN_HEADER_CONTENT_TYPE); +		std::string::size_type idx1 = media_type.find_first_of(";"); +		std::string mime_type = media_type.substr(0, idx1); + +		// Set empty type to none/none.  Empty string is reserved for legacy parcels +		// which have no mime type set. +		std::string resolved_mime_type = ! mime_type.empty() ? mime_type : LLMIMETypes::getDefaultMimeType(); +		LLFloaterURLEntry* floater_url_entry = (LLFloaterURLEntry*)mParent.get(); +		if ( floater_url_entry ) +		{ +			floater_url_entry->headerFetchComplete( getStatus(), resolved_mime_type ); +		} +	}  };  //----------------------------------------------------------------------------- @@ -136,7 +135,7 @@ void LLFloaterURLEntry::buildURLHistory()  	}  } -void LLFloaterURLEntry::headerFetchComplete(U32 status, const std::string& mime_type) +void LLFloaterURLEntry::headerFetchComplete(S32 status, const std::string& mime_type)  {  	LLPanelLandMedia* panel_media = dynamic_cast<LLPanelLandMedia*>(mPanelLandMediaHandle.get());  	if (panel_media) diff --git a/indra/newview/llfloaterurlentry.h b/indra/newview/llfloaterurlentry.h index dfb49fe5ac..bdd1ebe592 100755 --- a/indra/newview/llfloaterurlentry.h +++ b/indra/newview/llfloaterurlentry.h @@ -40,7 +40,7 @@ public:  	// that panel via the handle.  	static LLHandle<LLFloater> show(LLHandle<LLPanel> panel_land_media_handle, const std::string media_url);  	/*virtual*/	BOOL	postBuild(); -	void headerFetchComplete(U32 status, const std::string& mime_type); +	void headerFetchComplete(S32 status, const std::string& mime_type);  	bool addURLToCombobox(const std::string& media_url); diff --git a/indra/newview/llfloaterwebcontent.cpp b/indra/newview/llfloaterwebcontent.cpp index a3a78b5d8b..f72adbb880 100755 --- a/indra/newview/llfloaterwebcontent.cpp +++ b/indra/newview/llfloaterwebcontent.cpp @@ -29,6 +29,7 @@  #include "llcombobox.h"  #include "lliconctrl.h"  #include "llfloaterreg.h" +#include "llhttpconstants.h"  #include "llfacebookconnect.h"  #include "lllayoutstack.h"  #include "llpluginclassmedia.h" @@ -240,9 +241,9 @@ void LLFloaterWebContent::open_media(const Params& p)  {  	// Specifying a mime type of text/html here causes the plugin system to skip the MIME type probe and just open a browser plugin.  	LLViewerMedia::proxyWindowOpened(p.target(), p.id()); -	mWebBrowser->setHomePageUrl(p.url, "text/html"); +	mWebBrowser->setHomePageUrl(p.url, HTTP_CONTENT_TEXT_HTML);  	mWebBrowser->setTarget(p.target); -	mWebBrowser->navigateTo(p.url, "text/html"); +	mWebBrowser->navigateTo(p.url, HTTP_CONTENT_TEXT_HTML);  	set_current_url(p.url); @@ -489,7 +490,7 @@ void LLFloaterWebContent::onEnterAddress()      LLStringUtil::trim(url);  	if ( url.length() > 0 )  	{ -		mWebBrowser->navigateTo( url, "text/html"); +		mWebBrowser->navigateTo(url, HTTP_CONTENT_TEXT_HTML);  	};  } diff --git a/indra/newview/llfriendcard.cpp b/indra/newview/llfriendcard.cpp index 6566ef5dca..307e259006 100755 --- a/indra/newview/llfriendcard.cpp +++ b/indra/newview/llfriendcard.cpp @@ -38,6 +38,7 @@  #include "llcallingcard.h" // for LLAvatarTracker  #include "llviewerinventory.h"  #include "llinventorymodel.h" +#include "llcallbacklist.h"  // Constants; @@ -86,7 +87,7 @@ const LLUUID& get_folder_uuid(const LLUUID& parentFolderUUID, LLInventoryCollect  	if (cats_count > 1)  	{ -		LL_WARNS("LLFriendCardsManager") +		LL_WARNS_ONCE("LLFriendCardsManager")  			<< "There is more than one Friend card folder."  			<< "The first folder will be used."  			<< LL_ENDL; @@ -154,7 +155,7 @@ void LLInitialFriendCardsFetch::done()  	// This observer is no longer needed.  	gInventory.removeObserver(this); -	mCheckFolderCallback(); +	doOnIdleOneTime(mCheckFolderCallback);  	delete this;  } diff --git a/indra/newview/llgesturemgr.cpp b/indra/newview/llgesturemgr.cpp index ffddeeb129..b15556d73d 100755 --- a/indra/newview/llgesturemgr.cpp +++ b/indra/newview/llgesturemgr.cpp @@ -299,6 +299,12 @@ void LLGestureMgr::activateGestureWithAsset(const LLUUID& item_id,  } +void notify_update_label(const LLUUID& base_item_id) +{ +	gInventory.addChangedMask(LLInventoryObserver::LABEL, base_item_id); +	LLGestureMgr::instance().notifyObservers(); +} +  void LLGestureMgr::deactivateGesture(const LLUUID& item_id)  {  	const LLUUID& base_item_id = get_linked_uuid(item_id); @@ -322,7 +328,6 @@ void LLGestureMgr::deactivateGesture(const LLUUID& item_id)  	}  	mActive.erase(it); -	gInventory.addChangedMask(LLInventoryObserver::LABEL, base_item_id);  	// Inform the database of this change  	LLMessageSystem* msg = gMessageSystem; @@ -338,9 +343,11 @@ void LLGestureMgr::deactivateGesture(const LLUUID& item_id)  	gAgent.sendReliableMessage(); -	LLAppearanceMgr::instance().removeCOFItemLinks(base_item_id); +	LLPointer<LLInventoryCallback> cb = +		new LLBoostFuncInventoryCallback(no_op_inventory_func, +										 boost::bind(notify_update_label,base_item_id)); -	notifyObservers(); +	LLAppearanceMgr::instance().removeCOFItemLinks(base_item_id, cb);  } diff --git a/indra/newview/llgroupmgr.cpp b/indra/newview/llgroupmgr.cpp index b2ad737a1d..d5b817ce76 100755 --- a/indra/newview/llgroupmgr.cpp +++ b/indra/newview/llgroupmgr.cpp @@ -1851,23 +1851,31 @@ void LLGroupMgr::sendGroupMemberEjects(const LLUUID& group_id,  // Responder class for capability group management  class GroupMemberDataResponder : public LLHTTPClient::Responder  { +	LOG_CLASS(GroupMemberDataResponder);  public: -		GroupMemberDataResponder() {} -		virtual ~GroupMemberDataResponder() {} -		virtual void result(const LLSD& pContent); -		virtual void errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent); +	GroupMemberDataResponder() {} +	virtual ~GroupMemberDataResponder() {} +  private: -		LLSD mMemberData; +	/* virtual */ void httpSuccess(); +	/* virtual */ void httpFailure(); +	LLSD mMemberData;  }; -void GroupMemberDataResponder::errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent) +void GroupMemberDataResponder::httpFailure()  { -	LL_WARNS("GrpMgr") << "Error receiving group member data [status:"  -		<< pStatus << "]: " << pContent << LL_ENDL; +	LL_WARNS("GrpMgr") << "Error receiving group member data " +		<< dumpResponse() << LL_ENDL;  } -void GroupMemberDataResponder::result(const LLSD& content) +void GroupMemberDataResponder::httpSuccess()  { +	const LLSD& content = getContent(); +	if (!content.isMap()) +	{ +		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); +		return; +	}  	LLGroupMgr::processCapGroupMembersRequest(content);  } diff --git a/indra/newview/llhomelocationresponder.cpp b/indra/newview/llhomelocationresponder.cpp index eefa8bd42a..d0492bcdb4 100755 --- a/indra/newview/llhomelocationresponder.cpp +++ b/indra/newview/llhomelocationresponder.cpp @@ -33,71 +33,76 @@  #include "llagent.h"  #include "llviewerregion.h" -void LLHomeLocationResponder::result( const LLSD& content ) +void LLHomeLocationResponder::httpSuccess()  { +  const LLSD& content = getContent();    LLVector3 agent_pos;    bool      error = true; -		 +    do { -	 +      // was the call to /agent/<agent-id>/home-location successful?      // If not, we keep error set to true      if( ! content.has("success") )      {        break;      } -		 +      if( 0 != strncmp("true", content["success"].asString().c_str(), 4 ) )      {        break;      } -		 +      // did the simulator return a "justified" home location?      // If no, we keep error set to true      if( ! content.has( "HomeLocation" ) )      {        break;      } -		 +      if( ! content["HomeLocation"].has("LocationPos") )      {        break;      } -		 +      if( ! content["HomeLocation"]["LocationPos"].has("X") )      {        break;      }      agent_pos.mV[VX] = content["HomeLocation"]["LocationPos"]["X"].asInteger(); -		 +      if( ! content["HomeLocation"]["LocationPos"].has("Y") )      {        break;      }      agent_pos.mV[VY] = content["HomeLocation"]["LocationPos"]["Y"].asInteger(); -		 +      if( ! content["HomeLocation"]["LocationPos"].has("Z") )      {        break;      }      agent_pos.mV[VZ] = content["HomeLocation"]["LocationPos"]["Z"].asInteger(); -		 +      error = false;    } while( 0 ); -	 -  if( ! error ) + +  if( error ) +  { +    failureResult(HTTP_INTERNAL_ERROR, "Invalid server response content", content); +  } +  else    {      LL_INFOS() << "setting home position" << LL_ENDL; -		 +      LLViewerRegion *viewer_region = gAgent.getRegion();      gAgent.setHomePosRegion( viewer_region->getHandle(), agent_pos );    }  } -void LLHomeLocationResponder::errorWithContent( U32 status, const std::string& reason, const LLSD& content ) +void LLHomeLocationResponder::httpFailure()  { -	LL_WARNS() << "LLHomeLocationResponder error [status:" << status << "]: " << content << LL_ENDL; +  LL_WARNS() << dumpResponse() << LL_ENDL;  } diff --git a/indra/newview/llhomelocationresponder.h b/indra/newview/llhomelocationresponder.h index 9bf4b12c4e..adc6c8cb58 100755 --- a/indra/newview/llhomelocationresponder.h +++ b/indra/newview/llhomelocationresponder.h @@ -35,8 +35,10 @@  /* Typedef, Enum, Class, Struct, etc. */  class LLHomeLocationResponder : public LLHTTPClient::Responder  { -	virtual void result( const LLSD& content ); -	virtual void errorWithContent( U32 status, const std::string& reason, const LLSD& content ); +	LOG_CLASS(LLHomeLocationResponder); +private: +	/* virtual */ void httpSuccess(); +	/* virtual */ void httpFailure();  };  #endif diff --git a/indra/newview/llhttpretrypolicy.cpp b/indra/newview/llhttpretrypolicy.cpp new file mode 100755 index 0000000000..2d4ce6c883 --- /dev/null +++ b/indra/newview/llhttpretrypolicy.cpp @@ -0,0 +1,142 @@ +/**  + * @file llhttpretrypolicy.h + * @brief Header for a retry policy class intended for use with http responders. + * + * $LicenseInfo:firstyear=2013&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2013, Linden Research, Inc. + *  + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + *  + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + *  + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + *  + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llhttpretrypolicy.h" + +LLAdaptiveRetryPolicy::LLAdaptiveRetryPolicy(F32 min_delay, F32 max_delay, F32 backoff_factor, U32 max_retries, bool retry_on_4xx): +	mMinDelay(min_delay), +	mMaxDelay(max_delay), +	mBackoffFactor(backoff_factor), +	mMaxRetries(max_retries), +	mRetryOn4xx(retry_on_4xx) +{ +	init(); +} + +void LLAdaptiveRetryPolicy::init() +{ +	mDelay = mMinDelay; +	mRetryCount = 0; +	mShouldRetry = true; +} + +void LLAdaptiveRetryPolicy::reset() +{ +	init(); +} + +bool LLAdaptiveRetryPolicy::getRetryAfter(const LLSD& headers, F32& retry_header_time) +{ +	return (headers.has(HTTP_IN_HEADER_RETRY_AFTER) +			&& getSecondsUntilRetryAfter(headers[HTTP_IN_HEADER_RETRY_AFTER].asStringRef(), retry_header_time)); +} + +bool LLAdaptiveRetryPolicy::getRetryAfter(const LLCore::HttpHeaders *headers, F32& retry_header_time) +{ +	if (headers) +	{ +		const std::string *retry_value = headers->find(HTTP_IN_HEADER_RETRY_AFTER.c_str());  +		if (retry_value &&  +			getSecondsUntilRetryAfter(*retry_value, retry_header_time)) +		{ +			return true; +		} +	} +	return false; +} + +void LLAdaptiveRetryPolicy::onSuccess() +{ +	init(); +} + +void LLAdaptiveRetryPolicy::onFailure(S32 status, const LLSD& headers) +{ +	F32 retry_header_time; +	bool has_retry_header_time = getRetryAfter(headers,retry_header_time); +	onFailureCommon(status, has_retry_header_time, retry_header_time); +} +   +void LLAdaptiveRetryPolicy::onFailure(const LLCore::HttpResponse *response) +{ +	F32 retry_header_time; +	const LLCore::HttpHeaders *headers = response->getHeaders(); +	bool has_retry_header_time = getRetryAfter(headers,retry_header_time); +	onFailureCommon(response->getStatus().mType, has_retry_header_time, retry_header_time); +} + +void LLAdaptiveRetryPolicy::onFailureCommon(S32 status, bool has_retry_header_time, F32 retry_header_time) +{ +	if (!mShouldRetry) +	{ +		LL_INFOS() << "keep on failing" << LL_ENDL; +		return; +	} +	if (mRetryCount > 0) +	{ +		mDelay = llclamp(mDelay*mBackoffFactor,mMinDelay,mMaxDelay); +	} +	// Honor server Retry-After header. +	// Status 503 may ask us to wait for a certain amount of time before retrying. +	F32 wait_time = mDelay; +	if (has_retry_header_time) +	{ +		wait_time = retry_header_time; +	} + +	if (mRetryCount>=mMaxRetries) +	{ +		LL_INFOS() << "Too many retries " << mRetryCount << ", will not retry" << LL_ENDL; +		mShouldRetry = false; +	} +	if (!mRetryOn4xx && !isHttpServerErrorStatus(status)) +	{ +		LL_INFOS() << "Non-server error " << status << ", will not retry" << LL_ENDL; +		mShouldRetry = false; +	} +	if (mShouldRetry) +	{ +		LL_INFOS() << "Retry count " << mRetryCount << " should retry after " << wait_time << LL_ENDL; +		mRetryTimer.reset(); +		mRetryTimer.setTimerExpirySec(wait_time); +	} +	mRetryCount++; +} +	 + +bool LLAdaptiveRetryPolicy::shouldRetry(F32& seconds_to_wait) const +{ +	if (mRetryCount == 0) +	{ +		// Called shouldRetry before any failure. +		seconds_to_wait = F32_MAX; +		return false; +	} +	seconds_to_wait = mShouldRetry ? (F32) mRetryTimer.getRemainingTimeF32() : F32_MAX; +	return mShouldRetry; +} diff --git a/indra/newview/llhttpretrypolicy.h b/indra/newview/llhttpretrypolicy.h new file mode 100755 index 0000000000..cf79e0b401 --- /dev/null +++ b/indra/newview/llhttpretrypolicy.h @@ -0,0 +1,98 @@ +/**  + * @file file llhttpretrypolicy.h + * @brief declarations for http retry policy class. + * + * $LicenseInfo:firstyear=2013&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2013, Linden Research, Inc. + *  + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + *  + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + *  + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + *  + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA + * $/LicenseInfo$ + */ +										 +#ifndef LL_RETRYPOLICY_H +#define LL_RETRYPOLICY_H + +#include "lltimer.h" +#include "llthread.h" + +#include "llhttpconstants.h" + +// For compatibility with new core http lib. +#include "httpresponse.h" +#include "httpheaders.h" + +// This is intended for use with HTTP Clients/Responders, but is not +// specifically coupled with those classes. +class LLHTTPRetryPolicy: public LLThreadSafeRefCount +{ +public: +	LLHTTPRetryPolicy() {} + +	virtual ~LLHTTPRetryPolicy() {} +	// Call after a sucess to reset retry state. + +	virtual void onSuccess() = 0; +	// Call once after an HTTP failure to update state. +	virtual void onFailure(S32 status, const LLSD& headers) = 0; + +	virtual void onFailure(const LLCore::HttpResponse *response) = 0; + +	virtual bool shouldRetry(F32& seconds_to_wait) const = 0; + +	virtual void reset() = 0; +}; + +// Very general policy with geometric back-off after failures, +// up to a maximum delay, and maximum number of retries. +class LLAdaptiveRetryPolicy: public LLHTTPRetryPolicy +{ +public: +	LLAdaptiveRetryPolicy(F32 min_delay, F32 max_delay, F32 backoff_factor, U32 max_retries, bool retry_on_4xx = false); + +	// virtual +	void onSuccess(); + +	void reset(); +	 +	// virtual +	void onFailure(S32 status, const LLSD& headers); +	// virtual +	void onFailure(const LLCore::HttpResponse *response); +	// virtual +	bool shouldRetry(F32& seconds_to_wait) const; + +protected: +	void init(); +	bool getRetryAfter(const LLSD& headers, F32& retry_header_time); +	bool getRetryAfter(const LLCore::HttpHeaders *headers, F32& retry_header_time); +	void onFailureCommon(S32 status, bool has_retry_header_time, F32 retry_header_time); + +private: + +	const F32 mMinDelay; // delay never less than this value +	const F32 mMaxDelay; // delay never exceeds this value +	const F32 mBackoffFactor; // delay increases by this factor after each retry, up to mMaxDelay. +	const U32 mMaxRetries; // maximum number of times shouldRetry will return true. +	F32 mDelay; // current default delay. +	U32 mRetryCount; // number of times shouldRetry has been called. +	LLTimer mRetryTimer; // time until next retry. +	bool mShouldRetry; // Becomes false after too many retries, or the wrong sort of status received, etc. +	bool mRetryOn4xx; // Normally only retry on 5xx server errors. +}; + +#endif diff --git a/indra/newview/llimpanel.cpp b/indra/newview/llimpanel.cpp index 34ccab0302..c194dc05b0 100755 --- a/indra/newview/llimpanel.cpp +++ b/indra/newview/llimpanel.cpp @@ -388,16 +388,17 @@ void LLFloaterIMPanel::draw()  class LLSessionInviteResponder : public LLHTTPClient::Responder  { +	LOG_CLASS(LLSessionInviteResponder);  public:  	LLSessionInviteResponder(const LLUUID& session_id)  	{  		mSessionID = session_id;  	} -	void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content) +protected: +	void httpFailure()  	{ -		LL_WARNS() << "Error inviting all agents to session [status:"  -				<< statusNum << "]: " << content << LL_ENDL; +		LL_WARNS() << "Error inviting all agents to session " << dumpResponse() << LL_ENDL;  		//throw something back to the viewer here?  	} diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index af93778c10..8917c07759 100755 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -1460,6 +1460,7 @@ void start_deprecated_conference_chat(  class LLStartConferenceChatResponder : public LLHTTPClient::Responder  { +	LOG_CLASS(LLStartConferenceChatResponder);  public:  	LLStartConferenceChatResponder(  		const LLUUID& temp_session_id, @@ -1473,10 +1474,12 @@ public:  		mAgents = agents_to_invite;  	} -	virtual void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content) +protected: +	virtual void httpFailure()  	{  		//try an "old school" way. -		if ( statusNum == 400 ) +		// *TODO: What about other error status codes?  4xx 5xx? +		if ( getStatus() == HTTP_BAD_REQUEST )  		{  			start_deprecated_conference_chat(  				mTempSessionID, @@ -1485,8 +1488,7 @@ public:  				mAgents);  		} -		LL_WARNS() << "LLStartConferenceChatResponder error [status:" -				<< statusNum << "]: " << content << LL_ENDL; +		LL_WARNS() << dumpResponse() << LL_ENDL;  		//else throw an error back to the client?  		//in theory we should have just have these error strings @@ -1578,6 +1580,7 @@ bool LLIMModel::sendStartSession(  class LLViewerChatterBoxInvitationAcceptResponder :  	public LLHTTPClient::Responder  { +	LOG_CLASS(LLViewerChatterBoxInvitationAcceptResponder);  public:  	LLViewerChatterBoxInvitationAcceptResponder(  		const LLUUID& session_id, @@ -1587,8 +1590,15 @@ public:  		mInvitiationType = invitation_type;  	} -	void result(const LLSD& content) +private: +	void httpSuccess()  	{ +		const LLSD& content = getContent(); +		if (!content.isMap()) +		{ +			failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); +			return; +		}  		if ( gIMMgr)  		{  			LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID); @@ -1633,19 +1643,17 @@ public:  		}  	} -	void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content) +	void httpFailure()  	{ -		LL_WARNS() << "LLViewerChatterBoxInvitationAcceptResponder error [status:" -				<< statusNum << "]: " << content << LL_ENDL; +		LL_WARNS() << dumpResponse() << LL_ENDL;  		//throw something back to the viewer here?  		if ( gIMMgr )  		{  			gIMMgr->clearPendingAgentListUpdates(mSessionID);  			gIMMgr->clearPendingInvitation(mSessionID); -			if ( 404 == statusNum ) +			if ( HTTP_NOT_FOUND == getStatus() )  			{ -				std::string error_string; -				error_string = "session_does_not_exist_error"; +				static const std::string error_string("session_does_not_exist_error");  				gIMMgr->showSessionStartError(error_string, mSessionID);  			}  		} diff --git a/indra/newview/llinspectavatar.cpp b/indra/newview/llinspectavatar.cpp index b75140238e..1e15dc832c 100755 --- a/indra/newview/llinspectavatar.cpp +++ b/indra/newview/llinspectavatar.cpp @@ -292,11 +292,6 @@ void LLInspectAvatar::processAvatarData(LLAvatarData* data)  	delete mPropertiesRequest;  	mPropertiesRequest = NULL;  } -/* -prep# -			virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content) -				LL_WARNS() << "MuteVoiceResponder error [status:" << status << "]: " << content << LL_ENDL; -	*/  void LLInspectAvatar::updateVolumeSlider()  { diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 0bb6b5509f..47b47bf705 100755 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -199,6 +199,7 @@ const std::string& LLInvFVBridge::getDisplayName() const  	{  		buildDisplayName();  	} +  	return mDisplayName;  } @@ -1248,17 +1249,10 @@ LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type,  void LLInvFVBridge::purgeItem(LLInventoryModel *model, const LLUUID &uuid)  { -	LLInventoryCategory* cat = model->getCategory(uuid); -	if (cat) -	{ -		model->purgeDescendentsOf(uuid); -		model->notifyObservers(); -	}  	LLInventoryObject* obj = model->getObject(uuid);  	if (obj)  	{ -		model->purgeObject(uuid); -		model->notifyObservers(); +		remove_inventory_object(uuid, NULL);  	}  } @@ -1703,18 +1697,18 @@ void LLItemBridge::buildDisplayName() const  	else  	{  		mDisplayName.assign(LLStringUtil::null); -} - +	} +	  	mSearchableName.assign(mDisplayName);  	mSearchableName.append(getLabelSuffix());  	LLStringUtil::toUpper(mSearchableName); - +	      //Name set, so trigger a sort      if(mParent) -{ -        mParent->requestSort(); -	} +	{ +		mParent->requestSort();  	} +}  LLFontGL::StyleFlags LLItemBridge::getLabelStyle() const  { @@ -1828,13 +1822,9 @@ BOOL LLItemBridge::renameItem(const std::string& new_name)  	LLViewerInventoryItem* item = getItem();  	if(item && (item->getName() != new_name))  	{ -		LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item); -		new_item->rename(new_name); -		new_item->updateServer(FALSE); -		model->updateItem(new_item); - -		model->notifyObservers(); -		buildDisplayName(); +		LLSD updates; +		updates["name"] = new_name; +		update_inventory_item(item->getUUID(),updates, NULL);  	}  	// return FALSE because we either notified observers (& therefore  	// rebuilt) or we didn't update. @@ -1870,16 +1860,8 @@ BOOL LLItemBridge::removeItem()  	{  		if (!item->getIsLinkType())  		{ -			LLInventoryModel::cat_array_t cat_array; -			LLInventoryModel::item_array_t item_array; -			LLLinkedItemIDMatches is_linked_item_match(mUUID); -			gInventory.collectDescendentsIf(gInventory.getRootFolderID(), -											cat_array, -											item_array, -											LLInventoryModel::INCLUDE_TRASH, -											is_linked_item_match); - -			const U32 num_links = cat_array.size() + item_array.size(); +			LLInventoryModel::item_array_t item_array = gInventory.collectLinksTo(mUUID); +			const U32 num_links = item_array.size();  			if (num_links > 0)  			{  				// Warn if the user is will break any links when deleting this item. @@ -2030,6 +2012,13 @@ void LLFolderBridge::buildDisplayName() const  std::string LLFolderBridge::getLabelSuffix() const  { +    static LLCachedControl<F32> folder_loading_message_delay(gSavedSettings, "FolderLoadingMessageWaitTime", 0.5f); +     +    if (mIsLoading && mTimeSinceRequestStart.getElapsedTimeF32() >= folder_loading_message_delay()) +    { +        return llformat(" ( %s ) ", LLTrans::getString("LoadingData").c_str()); +    } +          if (isMarketplaceListingsFolder())      {          std::string suffix = ""; @@ -2092,49 +2081,19 @@ LLFontGL::StyleFlags LLFolderBridge::getLabelStyle() const  void LLFolderBridge::update()  { -	bool possibly_has_children = false; -	bool up_to_date = isUpToDate(); -	if(!up_to_date && hasChildren()) // we know we have children but  haven't  fetched them (doesn't obey filter) -	{ -		possibly_has_children = true; -	} - -	bool loading = (possibly_has_children -		&& !up_to_date ); +	// we know we have children but  haven't  fetched them (doesn't obey filter) +	bool loading = !isUpToDate() && hasChildren() && mFolderViewItem->isOpen();  	if (loading != mIsLoading)  	{ -		if ( loading && !mIsLoading ) +		if ( loading )  		{  			// Measure how long we've been in the loading state  			mTimeSinceRequestStart.reset();  		} +		mIsLoading = loading; -		const BOOL in_inventory = gInventory.isObjectDescendentOf(getUUID(),   gInventory.getRootFolderID()); -		const BOOL in_library = gInventory.isObjectDescendentOf(getUUID(),   gInventory.getLibraryRootFolderID()); - -		bool root_is_loading = false; -		if (in_inventory) -		{ -			root_is_loading =   LLInventoryModelBackgroundFetch::instance().inventoryFetchInProgress(); -		} -		if (in_library) -		{ -			root_is_loading =   LLInventoryModelBackgroundFetch::instance().libraryFetchInProgress(); -		} -		if ((mIsLoading -				&&	mTimeSinceRequestStart.getElapsedTimeF32() >=   gSavedSettings.getF32("FolderLoadingMessageWaitTime")) -			||	(LLInventoryModelBackgroundFetch::instance().folderFetchActive() -				&&	root_is_loading)) -		{ -			mDisplayName = LLInvFVBridge::getDisplayName() + " ( " +   LLTrans::getString("LoadingData") + " ) "; -			mIsLoading = true; -		} -		else -		{ -			mDisplayName = LLInvFVBridge::getDisplayName(); -			mIsLoading = false; -		} +		mFolderViewItem->refresh();  	}  } @@ -2513,49 +2472,13 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,  					}  				}  			} -			// if target is an outfit or current outfit folder we use link -			if (move_is_into_current_outfit || move_is_into_outfit) +			// if target is current outfit folder we use link +			if (move_is_into_current_outfit && +				inv_cat->getPreferredType() == LLFolderType::FT_NONE)  			{ -				if (inv_cat->getPreferredType() == LLFolderType::FT_NONE) -				{ -					if (move_is_into_current_outfit) -					{ -						// traverse category and add all contents to currently worn. -						BOOL append = true; -						LLAppearanceMgr::instance().wearInventoryCategory(inv_cat, false, append); -					} -					else -					{ -						// Recursively create links in target outfit. -						LLInventoryModel::cat_array_t cats; -						LLInventoryModel::item_array_t items; -						model->collectDescendents(cat_id, cats, items, LLInventoryModel::EXCLUDE_TRASH); -						LLAppearanceMgr::instance().linkAll(mUUID,items,NULL); -					} -				} -				else -				{ -#if SUPPORT_ENSEMBLES -					// BAP - should skip if dup. -					if (move_is_into_current_outfit) -					{ -						LLAppearanceMgr::instance().addEnsembleLink(inv_cat); -					} -					else -					{ -						LLPointer<LLInventoryCallback> cb = NULL; -						const std::string empty_description = ""; -						link_inventory_item( -							gAgent.getID(), -							cat_id, -							mUUID, -							inv_cat->getName(), -							empty_description, -							LLAssetType::AT_LINK_FOLDER, -							cb); -					} -#endif -				} +				// traverse category and add all contents to currently worn. +				BOOL append = true; +				LLAppearanceMgr::instance().wearInventoryCategory(inv_cat, false, append);  			}  			else if (move_is_into_outbox && !move_is_from_outbox)  			{ @@ -2960,17 +2883,6 @@ void LLFolderBridge::performAction(LLInventoryModel* model, std::string action)  		modifyOutfit(FALSE);  		return;  	} -#if SUPPORT_ENSEMBLES -	else if ("wearasensemble" == action) -	{ -		LLInventoryModel* model = getInventoryModel(); -		if(!model) return; -		LLViewerInventoryCategory* cat = getCategory(); -		if(!cat) return; -		LLAppearanceMgr::instance().addEnsembleLink(cat,true); -		return; -	} -#endif  	else if ("addtooutfit" == action)  	{  		modifyOutfit(TRUE); @@ -3197,9 +3109,12 @@ LLUIImagePtr LLFolderBridge::getIconOverlay() const  	return NULL;  } -  BOOL LLFolderBridge::renameItem(const std::string& new_name)  { + +	LLScrollOnRenameObserver *observer = new LLScrollOnRenameObserver(mUUID, mRoot); +	gInventory.addObserver(observer); +  	rename_category(getInventoryModel(), mUUID, new_name);  	// return FALSE because we either notified observers (& therefore @@ -3477,28 +3392,9 @@ void LLFolderBridge::pasteLinkFromClipboard()  					dropToOutfit(item, move_is_into_current_outfit);  				}  			} -			else if (LLInventoryCategory *cat = model->getCategory(object_id)) +			else if (LLConstPointer<LLInventoryObject> obj = model->getObject(object_id))  			{ -				const std::string empty_description = ""; -				link_inventory_item( -					gAgent.getID(), -					cat->getUUID(), -					parent_id, -					cat->getName(), -					empty_description, -					LLAssetType::AT_LINK_FOLDER, -					LLPointer<LLInventoryCallback>(NULL)); -			} -			else if (LLInventoryItem *item = model->getItem(object_id)) -			{ -				link_inventory_item( -					gAgent.getID(), -					item->getLinkedUUID(), -					parent_id, -					item->getName(), -					item->getDescription(), -					LLAssetType::AT_LINK, -					LLPointer<LLInventoryCallback>(NULL)); +				link_inventory_object(parent_id, obj, LLPointer<LLInventoryCallback>(NULL));  			}  		}  		// Change mode to paste for next paste @@ -3595,16 +3491,6 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t&   items                      items.push_back(std::string("New Body Parts"));                  }  			} -#if SUPPORT_ENSEMBLES -			// Changing folder types is an unfinished unsupported feature -			// and can lead to unexpected behavior if enabled. -			items.push_back(std::string("Change Type")); -			const LLViewerInventoryCategory *cat = getCategory(); -			if (cat && LLFolderType::lookupIsProtectedType(cat->getPreferredType())) -			{ -				disabled_items.push_back(std::string("Change Type")); -			} -#endif  			getClipboardEntries(false, items, disabled_items, flags);  		}  		else @@ -3767,6 +3653,10 @@ void LLFolderBridge::buildContextMenuFolderOptions(U32 flags,   menuentry_vec_t&  		{  			disabled_items.push_back(std::string("Replace Outfit"));  		} +		if (!LLAppearanceMgr::instance().getCanAddToCOF(mUUID)) +		{ +			disabled_items.push_back(std::string("Add To Outfit")); +		}  		items.push_back(std::string("Outfit Separator"));  	}  } @@ -4097,14 +3987,7 @@ void LLFolderBridge::dropToOutfit(LLInventoryItem* inv_item, BOOL move_is_into_c  	else  	{  		LLPointer<LLInventoryCallback> cb = NULL; -		link_inventory_item( -			gAgent.getID(), -			inv_item->getLinkedUUID(), -			mUUID, -			inv_item->getName(), -			inv_item->getDescription(), -			LLAssetType::AT_LINK, -			cb); +		link_inventory_object(mUUID, LLConstPointer<LLInventoryObject>(inv_item), cb);  	}  } diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index eeaedc197f..418679d17c 100755 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -257,7 +257,7 @@ public:  	LLFolderBridge(LLInventoryPanel* inventory,   				   LLFolderView* root,  				   const LLUUID& uuid)  -        :       LLInvFVBridge(inventory, root, uuid), +	:	LLInvFVBridge(inventory, root, uuid),  		mCallingCards(FALSE),  		mWearables(FALSE),  		mIsLoading(false) diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index a34863c9a7..baa2a08933 100755 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -237,12 +237,9 @@ void rename_category(LLInventoryModel* model, const LLUUID& cat_id, const std::s  		return;  	} -	LLPointer<LLViewerInventoryCategory> new_cat = new LLViewerInventoryCategory(cat); -	new_cat->rename(new_name); -	new_cat->updateServer(FALSE); -	model->updateCategory(new_cat); - -	model->notifyObservers(); +	LLSD updates; +	updates["name"] = new_name; +	update_inventory_category(cat_id, updates, NULL);  }  void copy_inventory_category(LLInventoryModel* model, @@ -1597,6 +1594,13 @@ bool LLIsOfAssetType::operator()(LLInventoryCategory* cat, LLInventoryItem* item  	return FALSE;  } +bool LLIsValidItemLink::operator()(LLInventoryCategory* cat, LLInventoryItem* item) +{ +	LLViewerInventoryItem *vitem = dynamic_cast<LLViewerInventoryItem*>(item); +	if (!vitem) return false; +	return (vitem->getActualType() == LLAssetType::AT_LINK  && !vitem->getIsBrokenLink()); +} +  bool LLIsTypeWithPermissions::operator()(LLInventoryCategory* cat, LLInventoryItem* item)  {  	if(mType == LLAssetType::AT_CATEGORY) diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h index 5dd317e218..5018e5a53e 100755 --- a/indra/newview/llinventoryfunctions.h +++ b/indra/newview/llinventoryfunctions.h @@ -201,6 +201,13 @@ protected:  	LLAssetType::EType mType;  }; +class LLIsValidItemLink : public LLInventoryCollectFunctor +{ +public: +	virtual bool operator()(LLInventoryCategory* cat, +							LLInventoryItem* item); +}; +  class LLIsTypeWithPermissions : public LLInventoryCollectFunctor  {  public: diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 6d980d1564..8f8ea8e602 100755 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -27,6 +27,7 @@  #include "llviewerprecompiledheaders.h"  #include "llinventorymodel.h" +#include "llaisapi.h"  #include "llagent.h"  #include "llagentwearables.h"  #include "llappearancemgr.h" @@ -48,6 +49,7 @@  #include "llcallbacklist.h"  #include "llvoavatarself.h"  #include "llgesturemgr.h" +#include "llsdutil.h"  #include <typeinfo>  //#define DIFF_INVENTORY_FILES @@ -103,17 +105,7 @@ bool LLCanCache::operator()(LLInventoryCategory* cat, LLInventoryItem* item)  		if(c->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN)  		{  			S32 descendents_server = c->getDescendentCount(); -			LLInventoryModel::cat_array_t* cats; -			LLInventoryModel::item_array_t* items; -			mModel->getDirectDescendentsOf( -				c->getUUID(), -				cats, -				items); -			S32 descendents_actual = 0; -			if(cats && items) -			{ -				descendents_actual = cats->size() + items->size(); -			} +			S32 descendents_actual = c->getViewerDescendentCount();  			if(descendents_server == descendents_actual)  			{  				mCachedCatIDs.insert(c->getUUID()); @@ -135,6 +127,7 @@ LLInventoryModel gInventory;  LLInventoryModel::LLInventoryModel()  :	mModifyMask(LLInventoryObserver::ALL),  	mChangedItemIDs(), +	mBacklinkMMap(),  	mCategoryMap(),  	mItemMap(),  	mCategoryLock(), @@ -252,6 +245,23 @@ const LLViewerInventoryCategory* LLInventoryModel::getFirstDescendantOf(const LL  	return NULL;  } +bool LLInventoryModel::getObjectTopmostAncestor(const LLUUID& object_id, LLUUID& result) const +{ +	LLInventoryObject *object = getObject(object_id); +	while (object && object->getParentUUID().notNull()) +	{ +		LLInventoryObject *parent_object = getObject(object->getParentUUID()); +		if (!parent_object) +		{ +			LL_WARNS() << "unable to trace topmost ancestor, missing item for uuid " << object->getParentUUID() << LL_ENDL; +			return false; +		} +		object = parent_object; +	} +	result = object->getUUID(); +	return true; +} +  // Get the object by id. Returns NULL if not found.  LLInventoryObject* LLInventoryModel::getObject(const LLUUID& id) const  { @@ -429,15 +439,12 @@ void LLInventoryModel::consolidateForType(const LLUUID& main_id, LLFolderType::E  	}  } -// findCategoryUUIDForType() returns the uuid of the category that -// specifies 'type' as what it defaults to containing. The category is -// not necessarily only for that type. *NOTE: This will create a new -// inventory category on the fly if one does not exist. -const LLUUID LLInventoryModel::findCategoryUUIDForType(LLFolderType::EType preferred_type, bool create_folder/*, -					  bool find_in_library*/) +const LLUUID LLInventoryModel::findCategoryUUIDForTypeInRoot( +	LLFolderType::EType preferred_type, +	bool create_folder, +	const LLUUID& root_id)  {  	LLUUID rv = LLUUID::null; -	const LLUUID &root_id = /*(find_in_library) ? gInventory.getLibraryRootFolderID() :*/ gInventory.getRootFolderID();  	if(LLFolderType::FT_ROOT_INVENTORY == preferred_type)  	{  		rv = root_id; @@ -453,14 +460,17 @@ const LLUUID LLInventoryModel::findCategoryUUIDForType(LLFolderType::EType prefe  			{  				if(cats->at(i)->getPreferredType() == preferred_type)  				{ -					rv = cats->at(i)->getUUID(); -					break; +					const LLUUID& folder_id = cats->at(i)->getUUID(); +					if (rv.isNull() || folder_id < rv) +					{ +						rv = folder_id; +					}  				}  			}  		}  	} -	if(rv.isNull() && isInventoryUsable() && (create_folder && true/*!find_in_library*/)) +	if(rv.isNull() && isInventoryUsable() && create_folder)  	{  		if(root_id.notNull())  		{ @@ -470,68 +480,49 @@ const LLUUID LLInventoryModel::findCategoryUUIDForType(LLFolderType::EType prefe  	return rv;  } -const LLUUID LLInventoryModel::findLibraryCategoryUUIDForType(LLFolderType::EType preferred_type, bool create_folder) +// findCategoryUUIDForType() returns the uuid of the category that +// specifies 'type' as what it defaults to containing. The category is +// not necessarily only for that type. *NOTE: This will create a new +// inventory category on the fly if one does not exist. +const LLUUID LLInventoryModel::findCategoryUUIDForType(LLFolderType::EType preferred_type, bool create_folder)  { -	LLUUID rv = LLUUID::null; - -	const LLUUID &root_id = gInventory.getLibraryRootFolderID(); -	if(LLFolderType::FT_ROOT_INVENTORY == preferred_type) -	{ -		rv = root_id; -	} -	else if (root_id.notNull()) -	{ -		cat_array_t* cats = NULL; -		cats = get_ptr_in_map(mParentChildCategoryTree, root_id); -		if(cats) -		{ -			S32 count = cats->size(); -			for(S32 i = 0; i < count; ++i) -			{ -				if(cats->at(i)->getPreferredType() == preferred_type) -				{ -					rv = cats->at(i)->getUUID(); -					break; -				} -			} -		} -	} +	return findCategoryUUIDForTypeInRoot(preferred_type, create_folder, gInventory.getRootFolderID()); +} -	if(rv.isNull() && isInventoryUsable() && (create_folder && true/*!find_in_library*/)) -	{ -		if(root_id.notNull()) -		{ -			return createNewCategory(root_id, preferred_type, LLStringUtil::null); -		} -	} -	return rv; +const LLUUID LLInventoryModel::findLibraryCategoryUUIDForType(LLFolderType::EType preferred_type, bool create_folder) +{ +	return findCategoryUUIDForTypeInRoot(preferred_type, create_folder, gInventory.getLibraryRootFolderID());  }  class LLCreateInventoryCategoryResponder : public LLHTTPClient::Responder  { +	LOG_CLASS(LLCreateInventoryCategoryResponder);  public:  	LLCreateInventoryCategoryResponder(LLInventoryModel* model,  -									   void (*callback)(const LLSD&, void*), -									   void* user_data) : -										mModel(model), -										mCallback(callback),  -										mData(user_data)  +									   boost::optional<inventory_func_type> callback): +		mModel(model), +		mCallback(callback)   	{  	} -	virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content) +protected: +	virtual void httpFailure()  	{ -		LL_WARNS("InvAPI") << "CreateInventoryCategory failed [status:" -				<< status << "]: " << content << LL_ENDL; +		LL_WARNS("InvAPI") << dumpResponse() << LL_ENDL;  	} -	virtual void result(const LLSD& content) +	virtual void httpSuccess()  	{  		//Server has created folder. -		 +		const LLSD& content = getContent(); +		if (!content.isMap() || !content.has("folder_id")) +		{ +			failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); +			return; +		}  		LLUUID category_id = content["folder_id"].asUUID(); -		 +		LL_DEBUGS("Avatar") << ll_pretty_print_sd(content) << LL_ENDL;  		// Add the category to the internal representation  		LLPointer<LLViewerInventoryCategory> cat =  		new LLViewerInventoryCategory( category_id,  @@ -544,17 +535,15 @@ public:  		LLInventoryModel::LLCategoryUpdate update(cat->getParentUUID(), 1);  		mModel->accountForUpdate(update);  		mModel->updateCategory(cat); -		 -		if (mCallback && mData) + +		if (mCallback)  		{ -			mCallback(content, mData); +			mCallback.get()(category_id);  		} -		  	}  private: -	void (*mCallback)(const LLSD&, void*); -	void* mData; +	boost::optional<inventory_func_type> mCallback;  	LLInventoryModel* mModel;  }; @@ -565,8 +554,7 @@ private:  LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id,  										   LLFolderType::EType preferred_type,  										   const std::string& pname, -										   void (*callback)(const LLSD&, void*),	//Default to NULL -										   void* user_data)							//Default to NULL +										   boost::optional<inventory_func_type> callback)  {  	LLUUID id; @@ -593,33 +581,32 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id,  		name.assign(LLViewerFolderType::lookupNewCategoryName(preferred_type));  	} -	if ( callback && user_data )  //callback required for acked message. +	LLViewerRegion* viewer_region = gAgent.getRegion(); +	std::string url; +	if ( viewer_region ) +		url = viewer_region->getCapability("CreateInventoryCategory"); +	 +	if (!url.empty() && callback.get_ptr())  	{ -		LLViewerRegion* viewer_region = gAgent.getRegion(); -		std::string url; -		if ( viewer_region ) -			url = viewer_region->getCapability("CreateInventoryCategory"); +		//Let's use the new capability. -		if (!url.empty()) -		{ -			//Let's use the new capability. -			 -			LLSD request, body; -			body["folder_id"] = id; -			body["parent_id"] = parent_id; -			body["type"] = (LLSD::Integer) preferred_type; -			body["name"] = name; -			 -			request["message"] = "CreateInventoryCategory"; -			request["payload"] = body; -			 -	//		viewer_region->getCapAPI().post(request); -			LLHTTPClient::post( -							   url, -							   body, -							   new LLCreateInventoryCategoryResponder(this, callback, user_data) ); -			return LLUUID::null; -		} +		LLSD request, body; +		body["folder_id"] = id; +		body["parent_id"] = parent_id; +		body["type"] = (LLSD::Integer) preferred_type; +		body["name"] = name; +		 +		request["message"] = "CreateInventoryCategory"; +		request["payload"] = body; + +		LL_DEBUGS("Avatar") << "create category request: " << ll_pretty_print_sd(request) << LL_ENDL; +		//		viewer_region->getCapAPI().post(request); +		LLHTTPClient::post( +			url, +			body, +			new LLCreateInventoryCategoryResponder(this, callback) ); + +		return LLUUID::null;  	}  	// Add the category to the internal representation @@ -646,6 +633,40 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id,  	return id;  } +// This is optimized for the case that we just want to know whether a +// category has any immediate children meeting a condition, without +// needing to recurse or build up any lists. +bool LLInventoryModel::hasMatchingDirectDescendent(const LLUUID& cat_id, +												   LLInventoryCollectFunctor& filter) +{ +	LLInventoryModel::cat_array_t *cats; +	LLInventoryModel::item_array_t *items; +	getDirectDescendentsOf(cat_id, cats, items); +	if (cats) +	{ +		for (LLInventoryModel::cat_array_t::const_iterator it = cats->begin(); +			 it != cats->end(); ++it) +		{ +			if (filter(*it,NULL)) +			{ +				return true; +			} +		} +	} +	if (items) +	{ +		for (LLInventoryModel::item_array_t::const_iterator it = items->begin(); +			 it != items->end(); ++it) +		{ +			if (filter(NULL,*it)) +			{ +				return true; +			} +		} +	} +	return false; +} +												    // Starting with the object specified, add its descendents to the  // array provided, but do not add the inventory object specified by  // id. There is no guaranteed order. Neither array will be erased @@ -677,8 +698,7 @@ void LLInventoryModel::collectDescendentsIf(const LLUUID& id,  											cat_array_t& cats,  											item_array_t& items,  											BOOL include_trash, -											LLInventoryCollectFunctor& add, -											BOOL follow_folder_links) +											LLInventoryCollectFunctor& add)  {  	// Start with categories  	if(!include_trash) @@ -705,36 +725,6 @@ void LLInventoryModel::collectDescendentsIf(const LLUUID& id,  	LLViewerInventoryItem* item = NULL;  	item_array_t* item_array = get_ptr_in_map(mParentChildItemTree, id); -	// Follow folder links recursively.  Currently never goes more -	// than one level deep (for current outfit support) -	// Note: if making it fully recursive, need more checking against infinite loops. -	if (follow_folder_links && item_array) -	{ -		S32 count = item_array->size(); -		for(S32 i = 0; i < count; ++i) -		{ -			item = item_array->at(i); -			if (item && item->getActualType() == LLAssetType::AT_LINK_FOLDER) -			{ -				LLViewerInventoryCategory *linked_cat = item->getLinkedCategory(); -				if (linked_cat && linked_cat->getPreferredType() != LLFolderType::FT_OUTFIT) -					// BAP - was  -					// LLAssetType::lookupIsEnsembleCategoryType(linked_cat->getPreferredType())) -					// Change back once ensemble typing is in place. -				{ -					if(add(linked_cat,NULL)) -					{ -						// BAP should this be added here?  May not -						// matter if it's only being used in current -						// outfit traversal. -						cats.push_back(LLPointer<LLViewerInventoryCategory>(linked_cat)); -					} -					collectDescendentsIf(linked_cat->getUUID(), cats, items, include_trash, add, FALSE); -				} -			} -		} -	} -	  	// Move onto items  	if(item_array)  	{ @@ -756,26 +746,7 @@ void LLInventoryModel::addChangedMaskForLinks(const LLUUID& object_id, U32 mask)  	if (!obj || obj->getIsLinkType())  		return; -	LLInventoryModel::cat_array_t cat_array; -	LLInventoryModel::item_array_t item_array; -	LLLinkedItemIDMatches is_linked_item_match(object_id); -	collectDescendentsIf(gInventory.getRootFolderID(), -						 cat_array, -						 item_array, -						 LLInventoryModel::INCLUDE_TRASH, -						 is_linked_item_match); -	if (cat_array.empty() && item_array.empty()) -	{ -		return; -	} -	for (LLInventoryModel::cat_array_t::iterator cat_iter = cat_array.begin(); -		 cat_iter != cat_array.end(); -		 cat_iter++) -	{ -		LLViewerInventoryCategory *linked_cat = (*cat_iter); -		addChangedMask(mask, linked_cat->getUUID()); -	}; - +	LLInventoryModel::item_array_t item_array = collectLinksTo(object_id);  	for (LLInventoryModel::item_array_t::iterator iter = item_array.begin();  		 iter != item_array.end();  		 iter++) @@ -803,17 +774,27 @@ LLViewerInventoryItem* LLInventoryModel::getLinkedItem(const LLUUID& object_id)  	return object_id.notNull() ? getItem(getLinkedItemID(object_id)) : NULL;  } -LLInventoryModel::item_array_t LLInventoryModel::collectLinkedItems(const LLUUID& id, -																	const LLUUID& start_folder_id) +LLInventoryModel::item_array_t LLInventoryModel::collectLinksTo(const LLUUID& id)  { +	// Get item list via collectDescendents (slow!)  	item_array_t items; -	LLInventoryModel::cat_array_t cat_array; -	LLLinkedItemIDMatches is_linked_item_match(id); -	collectDescendentsIf((start_folder_id == LLUUID::null ? gInventory.getRootFolderID() : start_folder_id), -						 cat_array, -						 items, -						 LLInventoryModel::INCLUDE_TRASH, -						 is_linked_item_match); +	const LLInventoryObject *obj = getObject(id); +	// FIXME - should be as in next line, but this is causing a +	// stack-smashing crash of cause TBD... check in the REBUILD code. +	//if (obj && obj->getIsLinkType()) +	if (!obj || obj->getIsLinkType()) +		return items; +	 +	std::pair<backlink_mmap_t::iterator, backlink_mmap_t::iterator> range = mBacklinkMMap.equal_range(id); +	for (backlink_mmap_t::iterator it = range.first; it != range.second; ++it) +	{ +		LLViewerInventoryItem *item = getItem(it->second); +		if (item) +		{ +			items.push_back(item); +		} +	} +  	return items;  } @@ -830,9 +811,8 @@ bool LLInventoryModel::isInventoryUsable() const  // Calling this method with an inventory item will either change an  // existing item with a matching item_id, or will add the item to the  // current inventory. -U32 LLInventoryModel::updateItem(const LLViewerInventoryItem* item) +U32 LLInventoryModel::updateItem(const LLViewerInventoryItem* item, U32 mask)  { -	U32 mask = LLInventoryObserver::NONE;  	if(item->getUUID().isNull())  	{  		return mask; @@ -1011,7 +991,7 @@ LLInventoryModel::item_array_t* LLInventoryModel::getUnlockedItemArray(const LLU  // Calling this method with an inventory category will either change  // an existing item with the matching id, or it will add the category. -void LLInventoryModel::updateCategory(const LLViewerInventoryCategory* cat) +void LLInventoryModel::updateCategory(const LLViewerInventoryCategory* cat, U32 mask)  {  	if(!cat || cat->getUUID().isNull())  	{ @@ -1188,8 +1168,199 @@ void LLInventoryModel::changeCategoryParent(LLViewerInventoryCategory* cat,  	notifyObservers();  } +void LLInventoryModel::onAISUpdateReceived(const std::string& context, const LLSD& update) +{ +	LLTimer timer; +	if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage")) +	{ +		dump_sequential_xml(gAgentAvatarp->getFullname() + "_ais_update", update); +	} + +	AISUpdate ais_update(update); // parse update llsd into stuff to do. +	ais_update.doUpdate(); // execute the updates in the appropriate order. +	LL_INFOS() << "elapsed: " << timer.getElapsedTimeF32() << LL_ENDL; +} + +// Does not appear to be used currently. +void LLInventoryModel::onItemUpdated(const LLUUID& item_id, const LLSD& updates, bool update_parent_version) +{ +	U32 mask = LLInventoryObserver::NONE; + +	LLPointer<LLViewerInventoryItem> item = gInventory.getItem(item_id); +	LL_DEBUGS("Inventory") << "item_id: [" << item_id << "] name " << (item ? item->getName() : "(NOT FOUND)") << LL_ENDL; +	if(item) +	{ +		for (LLSD::map_const_iterator it = updates.beginMap(); +			 it != updates.endMap(); ++it) +		{ +			if (it->first == "name") +			{ +				LL_INFOS() << "Updating name from " << item->getName() << " to " << it->second.asString() << LL_ENDL; +				item->rename(it->second.asString()); +				mask |= LLInventoryObserver::LABEL; +			} +			else if (it->first == "desc") +			{ +				LL_INFOS() << "Updating description from " << item->getActualDescription() +						<< " to " << it->second.asString() << LL_ENDL; +				item->setDescription(it->second.asString()); +			} +			else +			{ +				LL_ERRS() << "unhandled updates for field: " << it->first << LL_ENDL; +			} +		} +		mask |= LLInventoryObserver::INTERNAL; +		addChangedMask(mask, item->getUUID()); +		if (update_parent_version) +		{ +			// Descendent count is unchanged, but folder version incremented. +			LLInventoryModel::LLCategoryUpdate up(item->getParentUUID(), 0); +			accountForUpdate(up); +		} +		gInventory.notifyObservers(); // do we want to be able to make this optional? +	} +} + +// Not used? +void LLInventoryModel::onCategoryUpdated(const LLUUID& cat_id, const LLSD& updates) +{ +	U32 mask = LLInventoryObserver::NONE; + +	LLPointer<LLViewerInventoryCategory> cat = gInventory.getCategory(cat_id); +	LL_DEBUGS("Inventory") << "cat_id: [" << cat_id << "] name " << (cat ? cat->getName() : "(NOT FOUND)") << LL_ENDL; +	if(cat) +	{ +		for (LLSD::map_const_iterator it = updates.beginMap(); +			 it != updates.endMap(); ++it) +		{ +			if (it->first == "name") +			{ +				LL_INFOS() << "Updating name from " << cat->getName() << " to " << it->second.asString() << LL_ENDL; +				cat->rename(it->second.asString()); +				mask |= LLInventoryObserver::LABEL; +			} +			else +			{ +				LL_ERRS() << "unhandled updates for field: " << it->first << LL_ENDL; +			} +		} +		mask |= LLInventoryObserver::INTERNAL; +		addChangedMask(mask, cat->getUUID()); +		gInventory.notifyObservers(); // do we want to be able to make this optional? +	} +} + +// Update model after descendents have been purged. +void LLInventoryModel::onDescendentsPurgedFromServer(const LLUUID& object_id, bool fix_broken_links) +{ +	LLPointer<LLViewerInventoryCategory> cat = getCategory(object_id); +	if (cat.notNull()) +	{ +		// do the cache accounting +		S32 descendents = cat->getDescendentCount(); +		if(descendents > 0) +		{ +			LLInventoryModel::LLCategoryUpdate up(object_id, -descendents); +			accountForUpdate(up); +		} + +		// we know that descendent count is 0, however since the +		// accounting may actually not do an update, we should force +		// it here. +		cat->setDescendentCount(0); + +		// unceremoniously remove anything we have locally stored. +		LLInventoryModel::cat_array_t categories; +		LLInventoryModel::item_array_t items; +		collectDescendents(object_id, +						   categories, +						   items, +						   LLInventoryModel::INCLUDE_TRASH); +		S32 count = items.size(); + +		LLUUID uu_id; +		for(S32 i = 0; i < count; ++i) +		{ +			uu_id = items.at(i)->getUUID(); + +			// This check prevents the deletion of a previously deleted item. +			// This is necessary because deletion is not done in a hierarchical +			// order. The current item may have been already deleted as a child +			// of its deleted parent. +			if (getItem(uu_id)) +			{ +				deleteObject(uu_id, fix_broken_links); +			} +		} + +		count = categories.size(); +		// Slightly kludgy way to make sure categories are removed +		// only after their child categories have gone away. + +		// FIXME: Would probably make more sense to have this whole +		// descendent-clearing thing be a post-order recursive +		// function to get the leaf-up behavior automatically. +		S32 deleted_count; +		S32 total_deleted_count = 0; +		do +		{ +			deleted_count = 0; +			for(S32 i = 0; i < count; ++i) +			{ +				uu_id = categories.at(i)->getUUID(); +				if (getCategory(uu_id)) +				{ +					cat_array_t* cat_list = getUnlockedCatArray(uu_id); +					if (!cat_list || (cat_list->size() == 0)) +					{ +						deleteObject(uu_id, fix_broken_links); +						deleted_count++; +					} +				} +			} +			total_deleted_count += deleted_count; +		} +		while (deleted_count > 0); +		if (total_deleted_count != count) +		{ +			LL_WARNS() << "Unexpected count of categories deleted, got " +					<< total_deleted_count << " expected " << count << LL_ENDL; +		} +		//gInventory.validate(); +	} +} + +// Update model after an item is confirmed as removed from +// server. Works for categories or items. +void LLInventoryModel::onObjectDeletedFromServer(const LLUUID& object_id, bool fix_broken_links, bool update_parent_version, bool do_notify_observers) +{ +	LLPointer<LLInventoryObject> obj = getObject(object_id); +	if(obj) +	{ +		if (getCategory(object_id)) +		{ +			// For category, need to delete/update all children first. +			onDescendentsPurgedFromServer(object_id, fix_broken_links); +		} + + +		// From item/cat removeFromServer() +		if (update_parent_version) +		{ +			LLInventoryModel::LLCategoryUpdate up(obj->getParentUUID(), -1); +			accountForUpdate(up); +		} + +		// From purgeObject() +		LLPreview::hide(object_id); +		deleteObject(object_id, fix_broken_links, do_notify_observers); +	} +} + +  // Delete a particular inventory object by ID. -void LLInventoryModel::deleteObject(const LLUUID& id) +void LLInventoryModel::deleteObject(const LLUUID& id, bool fix_broken_links, bool do_notify_observers)  {  	LL_DEBUGS() << "LLInventoryModel::deleteObject()" << LL_ENDL;  	LLPointer<LLInventoryObject> obj = getObject(id); @@ -1225,155 +1396,64 @@ void LLInventoryModel::deleteObject(const LLUUID& id)  	item_list = getUnlockedItemArray(id);  	if(item_list)  	{ +		if (item_list->size()) +		{ +			LL_WARNS() << "Deleting cat " << id << " while it still has child items" << LL_ENDL; +		}  		delete item_list;  		mParentChildItemTree.erase(id);  	}  	cat_list = getUnlockedCatArray(id);  	if(cat_list)  	{ +		if (cat_list->size()) +		{ +			LL_WARNS() << "Deleting cat " << id << " while it still has child cats" << LL_ENDL; +		}  		delete cat_list;  		mParentChildCategoryTree.erase(id);  	} -	obj = NULL; // delete obj -	updateLinkedObjectsFromPurge(id); -} +	addChangedMask(LLInventoryObserver::REMOVE, id); -// Delete a particular inventory item by ID, and remove it from the server. -void LLInventoryModel::purgeObject(const LLUUID &id) -{ -	LL_DEBUGS() << "LLInventoryModel::purgeObject() [ id: " << id << " ] " << LL_ENDL; -	LLPointer<LLInventoryObject> obj = getObject(id); -	if(obj) +	bool is_link_type = obj->getIsLinkType(); +	if (is_link_type) +	{ +		removeBacklinkInfo(obj->getUUID(), obj->getLinkedUUID()); +	} + +	// Can't have links to links, so there's no need for this update +	// if the item removed is a link. Can also skip if source of the +	// update is getting broken link info separately. +	obj = NULL; // delete obj +	if (fix_broken_links && !is_link_type) +	{ +		updateLinkedObjectsFromPurge(id); +	} +	if (do_notify_observers)  	{ -		obj->removeFromServer(); -		LLPreview::hide(id); -		deleteObject(id); +		notifyObservers();  	}  }  void LLInventoryModel::updateLinkedObjectsFromPurge(const LLUUID &baseobj_id)  { -	LLInventoryModel::item_array_t item_array = collectLinkedItems(baseobj_id); +	LLInventoryModel::item_array_t item_array = collectLinksTo(baseobj_id);  	// REBUILD is expensive, so clear the current change list first else  	// everything else on the changelist will also get rebuilt. -	gInventory.notifyObservers(); -	for (LLInventoryModel::item_array_t::const_iterator iter = item_array.begin(); -		 iter != item_array.end(); -		 iter++) +	if (item_array.size() > 0)  	{ -		const LLViewerInventoryItem *linked_item = (*iter); -		const LLUUID &item_id = linked_item->getUUID(); -		if (item_id == baseobj_id) continue; -		addChangedMask(LLInventoryObserver::REBUILD, item_id); -	} -	gInventory.notifyObservers(); -} - -// This is a method which collects the descendents of the id -// provided. If the category is not found, no action is -// taken. This method goes through the long winded process of -// cancelling any calling cards, removing server representation of -// folders, items, etc in a fairly efficient manner. -void LLInventoryModel::purgeDescendentsOf(const LLUUID& id) -{ -	LLPointer<LLViewerInventoryCategory> cat = getCategory(id); -	if (cat.notNull()) -	{ -		if (LLClipboard::instance().hasContents() && LLClipboard::instance().isCutMode()) -		{ -			// Something on the clipboard is in "cut mode" and needs to be preserved -			LL_INFOS() << "LLInventoryModel::purgeDescendentsOf " << cat->getName() -			<< " iterate and purge non hidden items" << LL_ENDL; -			cat_array_t* categories; -			item_array_t* items; -			// Get the list of direct descendants in that category passed as argument -			getDirectDescendentsOf(id, categories, items); -			std::vector<LLUUID> list_uuids; -			// Make a unique list with all the UUIDs of the direct descendants (items and categories are not treated differently) -			// Note: we need to do that shallow copy as purging things will invalidate the categories or items lists -			for (cat_array_t::const_iterator it = categories->begin(); it != categories->end(); ++it) -			{ -				list_uuids.push_back((*it)->getUUID()); -			} -			for (item_array_t::const_iterator it = items->begin(); it != items->end(); ++it) -			{ -				list_uuids.push_back((*it)->getUUID()); -			} -			// Iterate through the list and only purge the UUIDs that are not on the clipboard -			for (std::vector<LLUUID>::const_iterator it = list_uuids.begin(); it != list_uuids.end(); ++it) -			{ -				if (!LLClipboard::instance().isOnClipboard(*it)) -				{ -					purgeObject(*it); -				} -			} -		} -		else +		gInventory.notifyObservers(); +		for (LLInventoryModel::item_array_t::const_iterator iter = item_array.begin(); +			iter != item_array.end(); +			iter++)  		{ -			// Fast purge -			// do the cache accounting -			LL_INFOS() << "LLInventoryModel::purgeDescendentsOf " << cat->getName() -				<< LL_ENDL; -			S32 descendents = cat->getDescendentCount(); -			if(descendents > 0) -			{ -				LLCategoryUpdate up(id, -descendents); -				accountForUpdate(up); -			} - -			// we know that descendent count is 0, however since the -			// accounting may actually not do an update, we should force -			// it here. -			cat->setDescendentCount(0); - -			// send it upstream -			LLMessageSystem* msg = gMessageSystem; -			msg->newMessage("PurgeInventoryDescendents"); -			msg->nextBlock("AgentData"); -			msg->addUUID("AgentID", gAgent.getID()); -			msg->addUUID("SessionID", gAgent.getSessionID()); -			msg->nextBlock("InventoryData"); -			msg->addUUID("FolderID", id); -			gAgent.sendReliableMessage(); - -			// unceremoniously remove anything we have locally stored. -			cat_array_t categories; -			item_array_t items; -			collectDescendents(id, -							   categories, -							   items, -							   INCLUDE_TRASH); -			S32 count = items.size(); - -			item_map_t::iterator item_map_end = mItemMap.end(); -			cat_map_t::iterator cat_map_end = mCategoryMap.end(); -			LLUUID uu_id; - -			for(S32 i = 0; i < count; ++i) -			{ -				uu_id = items.at(i)->getUUID(); - -				// This check prevents the deletion of a previously deleted item. -				// This is necessary because deletion is not done in a hierarchical -				// order. The current item may have been already deleted as a child -				// of its deleted parent. -				if (mItemMap.find(uu_id) != item_map_end) -				{ -					deleteObject(uu_id); -				} -			} - -			count = categories.size(); -			for(S32 i = 0; i < count; ++i) -			{ -				uu_id = categories.at(i)->getUUID(); -				if (mCategoryMap.find(uu_id) != cat_map_end) -				{ -					deleteObject(uu_id); -				} -			} +			const LLViewerInventoryItem *linked_item = (*iter); +			const LLUUID &item_id = linked_item->getUUID(); +			if (item_id == baseobj_id) continue; +			addChangedMask(LLInventoryObserver::REBUILD, item_id);  		} +		gInventory.notifyObservers();  	}  } @@ -1428,6 +1508,7 @@ void LLInventoryModel::notifyObservers()  	mModifyMask = LLInventoryObserver::NONE;  	mChangedItemIDs.clear(); +	mAddedItemIDs.clear();  	mIsNotifyObservers = FALSE;  } @@ -1441,6 +1522,19 @@ void LLInventoryModel::addChangedMask(U32 mask, const LLUUID& referent)  		// (which is in the process of processing the list of items marked for change).  		// This means the change may fail to be processed.  		LL_WARNS() << "Adding changed mask within notify observers!  Change will likely be lost." << LL_ENDL; +		LLViewerInventoryItem *item = getItem(referent); +		if (item) +		{ +			LL_WARNS() << "Item " << item->getName() << LL_ENDL; +		} +		else +		{ +			LLViewerInventoryCategory *cat = getCategory(referent); +			if (cat) +			{ +				LL_WARNS() << "Category " << cat->getName() << LL_ENDL; +			} +		}  	}  	mModifyMask |= mask;  @@ -1448,19 +1542,30 @@ void LLInventoryModel::addChangedMask(U32 mask, const LLUUID& referent)  	{  		mChangedItemIDs.insert(referent);          update_marketplace_category(referent); + +		if (mask & LLInventoryObserver::ADD) +		{ +			mAddedItemIDs.insert(referent); +		} -        // Update all linked items.  Starting with just LABEL because I'm -        // not sure what else might need to be accounted for this. -        if (mModifyMask & LLInventoryObserver::LABEL) -        { -            addChangedMaskForLinks(referent, LLInventoryObserver::LABEL); -        } +		// Update all linked items.  Starting with just LABEL because I'm +		// not sure what else might need to be accounted for this. +		if (mask & LLInventoryObserver::LABEL) +		{ +			addChangedMaskForLinks(referent, LLInventoryObserver::LABEL); +		}  	}  }  // If we get back a normal response, handle it here -void  LLInventoryModel::fetchInventoryResponder::result(const LLSD& content) -{	 +void LLInventoryModel::fetchInventoryResponder::httpSuccess() +{ +	const LLSD& content = getContent(); +	if (!content.isMap()) +	{ +		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); +		return; +	}  	start_new_inventory_observer();  	/*LLUUID agent_id; @@ -1481,8 +1586,8 @@ void  LLInventoryModel::fetchInventoryResponder::result(const LLSD& content)  		LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem;  		titem->unpackMessage(content["items"][i]); -		LL_DEBUGS() << "LLInventoryModel::messageUpdateCore() item id:" -				 << titem->getUUID() << LL_ENDL; +		LL_DEBUGS() << "LLInventoryModel::fetchInventoryResponder item id: " +					<< titem->getUUID() << LL_ENDL;  		items.push_back(titem);  		// examine update for changes.  		LLViewerInventoryItem* itemp = gInventory.getItem(titem->getUUID()); @@ -1519,9 +1624,9 @@ void  LLInventoryModel::fetchInventoryResponder::result(const LLSD& content)  }  //If we get back an error (not found, etc...), handle it here -void LLInventoryModel::fetchInventoryResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void LLInventoryModel::fetchInventoryResponder::httpFailure()  { -	LL_WARNS() << "fetchInventory error [status:" << status << "]: " << content << LL_ENDL; +	LL_WARNS() << dumpResponse() << LL_ENDL;  	gInventory.notifyObservers();  } @@ -1613,6 +1718,47 @@ void LLInventoryModel::addCategory(LLViewerInventoryCategory* category)  	}  } +bool LLInventoryModel::hasBacklinkInfo(const LLUUID& link_id, const LLUUID& target_id) const +{ +	std::pair <backlink_mmap_t::const_iterator, backlink_mmap_t::const_iterator> range; +	range = mBacklinkMMap.equal_range(target_id); +	for (backlink_mmap_t::const_iterator it = range.first; it != range.second; ++it) +	{ +		if (it->second == link_id) +		{ +			return true; +		} +	} +	return false; +} + +void LLInventoryModel::addBacklinkInfo(const LLUUID& link_id, const LLUUID& target_id) +{ +	if (!hasBacklinkInfo(link_id, target_id)) +	{ +		mBacklinkMMap.insert(std::make_pair(target_id, link_id)); +	} +} + +void LLInventoryModel::removeBacklinkInfo(const LLUUID& link_id, const LLUUID& target_id) +{ +	std::pair <backlink_mmap_t::iterator, backlink_mmap_t::iterator> range; +	range = mBacklinkMMap.equal_range(target_id); +	for (backlink_mmap_t::iterator it = range.first; it != range.second; ) +	{ +		if (it->second == link_id) +		{ +			backlink_mmap_t::iterator delete_it = it; // iterator will be invalidated by erase. +			++it; +			mBacklinkMMap.erase(delete_it); +		} +		else +		{ +			++it; +		} +	} +} +  void LLInventoryModel::addItem(LLViewerInventoryItem* item)  {  	llassert(item); @@ -1634,7 +1780,13 @@ void LLInventoryModel::addItem(LLViewerInventoryItem* item)  		{  			LL_INFOS() << "Adding broken link [ name: " << item->getName() << " itemID: " << item->getUUID() << " assetID: " << item->getAssetUUID() << " )  parent: " << item->getParentUUID() << LL_ENDL;  		} - +		if (item->getIsLinkType()) +		{ +			// Add back-link from linked-to UUID. +			const LLUUID& link_id = item->getUUID(); +			const LLUUID& target_id = item->getLinkedUUID(); +			addBacklinkInfo(link_id, target_id); +		}  		mItemMap[item->getUUID()] = item;  	}  } @@ -1653,6 +1805,7 @@ void LLInventoryModel::empty()  		mParentChildItemTree.end(),  		DeletePairedPointer());  	mParentChildItemTree.clear(); +	mBacklinkMMap.clear(); // forget all backlink information.  	mCategoryMap.clear(); // remove all references (should delete entries)  	mItemMap.clear(); // remove all references (should delete entries)  	mLastItem = NULL; @@ -1664,37 +1817,34 @@ void LLInventoryModel::accountForUpdate(const LLCategoryUpdate& update) const  	LLViewerInventoryCategory* cat = getCategory(update.mCategoryID);  	if(cat)  	{ -		bool accounted = false;  		S32 version = cat->getVersion();  		if(version != LLViewerInventoryCategory::VERSION_UNKNOWN)  		{  			S32 descendents_server = cat->getDescendentCount(); -			LLInventoryModel::cat_array_t* cats; -			LLInventoryModel::item_array_t* items; -			getDirectDescendentsOf(update.mCategoryID, cats, items); -			S32 descendents_actual = 0; -			if(cats && items) -			{ -				descendents_actual = cats->size() + items->size(); -			} +			S32 descendents_actual = cat->getViewerDescendentCount();  			if(descendents_server == descendents_actual)  			{ -				accounted = true;  				descendents_actual += update.mDescendentDelta;  				cat->setDescendentCount(descendents_actual);  				cat->setVersion(++version); -				LL_DEBUGS() << "accounted: '" << cat->getName() << "' " -						 << version << " with " << descendents_actual -						 << " descendents." << LL_ENDL; +				LL_DEBUGS("Inventory") << "accounted: '" << cat->getName() << "' " +									   << version << " with " << descendents_actual +									   << " descendents." << LL_ENDL; +			} +			else +			{ +				// Error condition, this means that the category did not register that +				// it got new descendents (perhaps because it is still being loaded) +				// which means its descendent count will be wrong. +				LL_WARNS() << "Accounting failed for '" << cat->getName() << "' version:" +						   << version << " due to mismatched descendent count:  server == " +						   << descendents_server << ", viewer == " << descendents_actual << LL_ENDL;  			}  		} -		if(!accounted) +		else  		{ -			// Error condition, this means that the category did not register that -			// it got new descendents (perhaps because it is still being loaded) -			// which means its descendent count will be wrong. -			LL_WARNS() << "Accounting failed for '" << cat->getName() << "' version:" -					 << version << LL_ENDL; +			LL_WARNS() << "Accounting failed for '" << cat->getName() << "' version: unknown ("  +					   << version << ")" << LL_ENDL;  		}  	}  	else @@ -1728,47 +1878,6 @@ void LLInventoryModel::accountForUpdate(  	}  } - -/* -void LLInventoryModel::incrementCategoryVersion(const LLUUID& category_id) -{ -	LLViewerInventoryCategory* cat = getCategory(category_id); -	if(cat) -	{ -		S32 version = cat->getVersion(); -		if(LLViewerInventoryCategory::VERSION_UNKNOWN != version) -		{ -			cat->setVersion(version + 1); -			LL_INFOS() << "IncrementVersion: " << cat->getName() << " " -					<< cat->getVersion() << LL_ENDL; -		} -		else -		{ -			LL_INFOS() << "Attempt to increment version when unknown: " -					<< category_id << LL_ENDL; -		} -	} -	else -	{ -		LL_INFOS() << "Attempt to increment category: " << category_id << LL_ENDL; -	} -} -void LLInventoryModel::incrementCategorySetVersion( -	const std::set<LLUUID>& categories) -{ -	if(!categories.empty()) -	{  -		std::set<LLUUID>::const_iterator it = categories.begin(); -		std::set<LLUUID>::const_iterator end = categories.end(); -		for(; it != end; ++it) -		{ -			incrementCategoryVersion(*it); -		} -	} -} -*/ - -  LLInventoryModel::EHasChildren LLInventoryModel::categoryHasChildren(  	const LLUUID& cat_id) const  { @@ -1809,14 +1918,7 @@ bool LLInventoryModel::isCategoryComplete(const LLUUID& cat_id) const  	if(cat && (cat->getVersion()!=LLViewerInventoryCategory::VERSION_UNKNOWN))  	{  		S32 descendents_server = cat->getDescendentCount(); -		LLInventoryModel::cat_array_t* cats; -		LLInventoryModel::item_array_t* items; -		getDirectDescendentsOf(cat_id, cats, items); -		S32 descendents_actual = 0; -		if(cats && items) -		{ -			descendents_actual = cats->size() + items->size(); -		} +		S32 descendents_actual = cat->getViewerDescendentCount();  		if(descendents_server == descendents_actual)  		{  			return true; @@ -2154,11 +2256,16 @@ void LLInventoryModel::buildParentChildMap()  	S32 count = cats.size();  	S32 i;  	S32 lost = 0; +	cat_array_t lost_cats;  	for(i = 0; i < count; ++i)  	{  		LLViewerInventoryCategory* cat = cats.at(i);  		catsp = getUnlockedCatArray(cat->getParentUUID()); -		if(catsp) +		if(catsp && +		   // Only the two root folders should be children of null. +		   // Others should go to lost & found. +		   (cat->getParentUUID().notNull() ||  +			cat->getPreferredType() == LLFolderType::FT_ROOT_INVENTORY ))  		{  			catsp->push_back(cat);  		} @@ -2171,34 +2278,9 @@ void LLInventoryModel::buildParentChildMap()  			// which would be (folder_id, new_parent_id) to be sent up  			// to the server.  			LL_INFOS() << "Lost category: " << cat->getUUID() << " - " -					<< cat->getName() << LL_ENDL; +					   << cat->getName() << LL_ENDL;  			++lost; -			// plop it into the lost & found. -			LLFolderType::EType pref = cat->getPreferredType(); -			if ((LLFolderType::FT_NONE == pref) || (LLFolderType::FT_MARKETPLACE_STOCK == pref)) -			{ -				cat->setParent(findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND)); -			} -			else if(LLFolderType::FT_ROOT_INVENTORY == pref) -			{ -				// it's the root -				cat->setParent(LLUUID::null); -			} -			else -			{ -				// it's a protected folder. -				cat->setParent(gInventory.getRootFolderID()); -			} -			cat->updateServer(TRUE); -			catsp = getUnlockedCatArray(cat->getParentUUID()); -			if(catsp) -			{ -				catsp->push_back(cat); -			} -			else -			{		 -				LL_WARNS() << "Lost and found Not there!!" << LL_ENDL; -			} +			lost_cats.push_back(cat);  		}  	}  	if(lost) @@ -2206,6 +2288,42 @@ void LLInventoryModel::buildParentChildMap()  		LL_WARNS() << "Found  " << lost << " lost categories." << LL_ENDL;  	} +	// Do moves in a separate pass to make sure we've properly filed +	// the FT_LOST_AND_FOUND category before we try to find its UUID. +	for(i = 0; i<lost_cats.size(); ++i) +	{ +		LLViewerInventoryCategory *cat = lost_cats.at(i); + +		// plop it into the lost & found. +		LLFolderType::EType pref = cat->getPreferredType(); +		if(LLFolderType::FT_NONE == pref) +		{ +			cat->setParent(findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND)); +		} +		else if(LLFolderType::FT_ROOT_INVENTORY == pref) +		{ +			// it's the root +			cat->setParent(LLUUID::null); +		} +		else +		{ +			// it's a protected folder. +			cat->setParent(gInventory.getRootFolderID()); +		} +		// FIXME note that updateServer() fails with protected +		// types, so this will not work as intended in that case. +		cat->updateServer(TRUE); +		catsp = getUnlockedCatArray(cat->getParentUUID()); +		if(catsp) +		{ +			catsp->push_back(cat); +		} +		else +		{		 +			LL_WARNS() << "Lost and found Not there!!" << LL_ENDL; +		} +	} +  	const BOOL COF_exists = (findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, FALSE) != LLUUID::null);  	sFirstTimeInViewer2 = !COF_exists || gAgent.isFirstLogin(); @@ -2238,7 +2356,7 @@ void LLInventoryModel::buildParentChildMap()  		else  		{  			LL_INFOS() << "Lost item: " << item->getUUID() << " - " -					<< item->getName() << LL_ENDL; +					   << item->getName() << LL_ENDL;  			++lost;  			// plop it into the lost & found.  			// @@ -2329,11 +2447,25 @@ void LLInventoryModel::buildParentChildMap()  			// The inv tree is built.  			mIsAgentInvUsable = true; -			LL_INFOS() << "Inventory initialized, notifying observers" << LL_ENDL; -			addChangedMask(LLInventoryObserver::ALL, LLUUID::null); -			notifyObservers(); +			// notifyObservers() has been moved to +			// llstartup/idle_startup() after this func completes. +			// Allows some system categories to be created before +			// observers start firing.  		}  	} + +	if (!gInventory.validate()) +	{ +	 	LL_WARNS() << "model failed validity check!" << LL_ENDL; +	} +} + +void LLInventoryModel::createCommonSystemCategories() +{ +	gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH,true); +	gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE,true); +	gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD,true); +	gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS,true);  }  struct LLUUIDAndName @@ -2557,7 +2689,7 @@ void LLInventoryModel::registerCallbacks(LLMessageSystem* msg)  void LLInventoryModel::processUpdateCreateInventoryItem(LLMessageSystem* msg, void**)  {  	// do accounting and highlight new items if they arrive -	if (gInventory.messageUpdateCore(msg, true)) +	if (gInventory.messageUpdateCore(msg, true, LLInventoryObserver::UPDATE_CREATE))  	{  		U32 callback_id;  		LLUUID item_id; @@ -2577,7 +2709,7 @@ void LLInventoryModel::processFetchInventoryReply(LLMessageSystem* msg, void**)  } -bool LLInventoryModel::messageUpdateCore(LLMessageSystem* msg, bool account) +bool LLInventoryModel::messageUpdateCore(LLMessageSystem* msg, bool account, U32 mask)  {  	//make sure our added inventory observer is active  	start_new_inventory_observer(); @@ -2631,10 +2763,14 @@ bool LLInventoryModel::messageUpdateCore(LLMessageSystem* msg, bool account)  	}  	U32 changes = 0x0; +	if (account) +	{ +		mask |= LLInventoryObserver::CREATE; +	}  	//as above, this loop never seems to loop more than once per call  	for (item_array_t::iterator it = items.begin(); it != items.end(); ++it)  	{ -		changes |= gInventory.updateItem(*it); +		changes |= gInventory.updateItem(*it, mask);  	}  	gInventory.notifyObservers();  	gViewerWindow->getWindow()->decBusyCount(); @@ -2872,7 +3008,7 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**)  	LLUUID tid;  	msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_TransactionID, tid);  #ifndef LL_RELEASE_FOR_DOWNLOAD -	LL_INFOS() << "Bulk inventory: " << tid << LL_ENDL; +	LL_DEBUGS("Inventory") << "Bulk inventory: " << tid << LL_ENDL;  #endif  	update_map_t update; @@ -2884,9 +3020,9 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**)  	{  		LLPointer<LLViewerInventoryCategory> tfolder = new LLViewerInventoryCategory(gAgent.getID());  		tfolder->unpackMessage(msg, _PREHASH_FolderData, i); -		LL_INFOS() << "unpacked folder '" << tfolder->getName() << "' (" -				<< tfolder->getUUID() << ") in " << tfolder->getParentUUID() -				<< LL_ENDL; +		LL_DEBUGS("Inventory") << "unpacked folder '" << tfolder->getName() << "' (" +							   << tfolder->getUUID() << ") in " << tfolder->getParentUUID() +							   << LL_ENDL;  		if(tfolder->getUUID().notNull())  		{  			folders.push_back(tfolder); @@ -2926,8 +3062,8 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**)  	{  		LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem;  		titem->unpackMessage(msg, _PREHASH_ItemData, i); -		LL_INFOS() << "unpacked item '" << titem->getName() << "' in " -				<< titem->getParentUUID() << LL_ENDL; +		LL_DEBUGS("Inventory") << "unpacked item '" << titem->getName() << "' in " +							   << titem->getParentUUID() << LL_ENDL;  		U32 callback_id;  		msg->getU32Fast(_PREHASH_ItemData, _PREHASH_CallbackID, callback_id);  		if(titem->getUUID().notNull() ) // && callback_id.notNull() ) @@ -3004,6 +3140,9 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**)  		InventoryCallbackInfo cbinfo = (*inv_it);  		gInventoryCallbacks.fire(cbinfo.mCallback, cbinfo.mInvID);  	} + +	//gInventory.validate(); +  	// Don't show the inventory.  We used to call showAgentInventory here.  	//LLFloaterInventory* view = LLFloaterInventory::getActiveInventory();  	//if(view) @@ -3062,7 +3201,8 @@ void LLInventoryModel::processInventoryDescendents(LLMessageSystem* msg,void**)  		// If the item has already been added (e.g. from link prefetch), then it doesn't need to be re-added.  		if (gInventory.getItem(titem->getUUID()))  		{ -			LL_DEBUGS() << "Skipping prefetched item [ Name: " << titem->getName() << " | Type: " << titem->getActualType() << " | ItemUUID: " << titem->getUUID() << " ] " << LL_ENDL; +			LL_DEBUGS("Inventory") << "Skipping prefetched item [ Name: " << titem->getName() +								   << " | Type: " << titem->getActualType() << " | ItemUUID: " << titem->getUUID() << " ] " << LL_ENDL;  			continue;  		}  		gInventory.updateItem(titem); @@ -3148,8 +3288,7 @@ bool LLInventoryModel::callbackEmptyFolderType(const LLSD& notification, const L  	if (option == 0) // YES  	{  		const LLUUID folder_id = findCategoryUUIDForType(preferred_type); -		purgeDescendentsOf(folder_id); -		notifyObservers(); +		purge_descendents_of(folder_id, NULL);  	}  	return false;  } @@ -3164,8 +3303,7 @@ void LLInventoryModel::emptyFolderType(const std::string notification, LLFolderT  	else  	{  		const LLUUID folder_id = findCategoryUUIDForType(preferred_type); -		purgeDescendentsOf(folder_id); -		notifyObservers(); +		purge_descendents_of(folder_id, NULL);  	}  } @@ -3452,6 +3590,305 @@ void LLInventoryModel::dumpInventory() const  	LL_INFOS() << "\n**********************\nEnd Inventory Dump" << LL_ENDL;  } +// Do various integrity checks on model, logging issues found and +// returning an overall good/bad flag. +bool LLInventoryModel::validate() const +{ +	bool valid = true; + +	if (getRootFolderID().isNull()) +	{ +		LL_WARNS() << "no root folder id" << LL_ENDL; +		valid = false; +	} +	if (getLibraryRootFolderID().isNull()) +	{ +		LL_WARNS() << "no root folder id" << LL_ENDL; +		valid = false; +	} + +	if (mCategoryMap.size() + 1 != mParentChildCategoryTree.size()) +	{ +		// ParentChild should be one larger because of the special entry for null uuid. +		LL_INFOS() << "unexpected sizes: cat map size " << mCategoryMap.size() +				<< " parent/child " << mParentChildCategoryTree.size() << LL_ENDL; +		valid = false; +	} +	S32 cat_lock = 0; +	S32 item_lock = 0; +	S32 desc_unknown_count = 0; +	S32 version_unknown_count = 0; +	for(cat_map_t::const_iterator cit = mCategoryMap.begin(); cit != mCategoryMap.end(); ++cit) +	{ +		const LLUUID& cat_id = cit->first; +		const LLViewerInventoryCategory *cat = cit->second; +		if (!cat) +		{ +			LL_WARNS() << "invalid cat" << LL_ENDL; +			valid = false; +			continue; +		} +		if (cat_id != cat->getUUID()) +		{ +			LL_WARNS() << "cat id/index mismatch " << cat_id << " " << cat->getUUID() << LL_ENDL; +			valid = false; +		} + +		if (cat->getParentUUID().isNull()) +		{ +			if (cat_id != getRootFolderID() && cat_id != getLibraryRootFolderID()) +			{ +				LL_WARNS() << "cat " << cat_id << " has no parent, but is not root (" +						<< getRootFolderID() << ") or library root (" +						<< getLibraryRootFolderID() << ")" << LL_ENDL; +			} +		} +		cat_array_t* cats; +		item_array_t* items; +		getDirectDescendentsOf(cat_id,cats,items); +		if (!cats || !items) +		{ +			LL_WARNS() << "invalid direct descendents for " << cat_id << LL_ENDL; +			valid = false; +			continue; +		} +		if (cat->getDescendentCount() == LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN) +		{ +			desc_unknown_count++; +		} +		else if (cats->size() + items->size() != cat->getDescendentCount()) +		{ +			LL_WARNS() << "invalid desc count for " << cat_id << " name [" << cat->getName() +					<< "] parent " << cat->getParentUUID() +					<< " cached " << cat->getDescendentCount() +					<< " expected " << cats->size() << "+" << items->size() +					<< "=" << cats->size() +items->size() << LL_ENDL; +			valid = false; +		} +		if (cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN) +		{ +			version_unknown_count++; +		} +		if (mCategoryLock.count(cat_id)) +		{ +			cat_lock++; +		} +		if (mItemLock.count(cat_id)) +		{ +			item_lock++; +		} +		for (S32 i = 0; i<items->size(); i++) +		{ +			LLViewerInventoryItem *item = items->at(i); + +			if (!item) +			{ +				LL_WARNS() << "null item at index " << i << " for cat " << cat_id << LL_ENDL; +				valid = false; +				continue; +			} + +			const LLUUID& item_id = item->getUUID(); +			 +			if (item->getParentUUID() != cat_id) +			{ +				LL_WARNS() << "wrong parent for " << item_id << " found " +						<< item->getParentUUID() << " expected " << cat_id +						<< LL_ENDL; +				valid = false; +			} + + +			// Entries in items and mItemMap should correspond. +			item_map_t::const_iterator it = mItemMap.find(item_id); +			if (it == mItemMap.end()) +			{ +				LL_WARNS() << "item " << item_id << " found as child of " +						<< cat_id << " but not in top level mItemMap" << LL_ENDL; +				valid = false; +			} +			else +			{ +				LLViewerInventoryItem *top_item = it->second; +				if (top_item != item) +				{ +					LL_WARNS() << "item mismatch, item_id " << item_id +							<< " top level entry is different, uuid " << top_item->getUUID() << LL_ENDL; +				} +			} + +			// Topmost ancestor should be root or library. +			LLUUID topmost_ancestor_id; +			bool found = getObjectTopmostAncestor(item_id, topmost_ancestor_id); +			if (!found) +			{ +				LL_WARNS() << "unable to find topmost ancestor for " << item_id << LL_ENDL; +				valid = false; +			} +			else +			{ +				if (topmost_ancestor_id != getRootFolderID() && +					topmost_ancestor_id != getLibraryRootFolderID()) +				{ +					LL_WARNS() << "unrecognized top level ancestor for " << item_id +							<< " got " << topmost_ancestor_id +							<< " expected " << getRootFolderID() +							<< " or " << getLibraryRootFolderID() << LL_ENDL; +					valid = false; +				} +			} +		} + +		// Does this category appear as a child of its supposed parent? +		const LLUUID& parent_id = cat->getParentUUID(); +		if (!parent_id.isNull()) +		{ +			cat_array_t* cats; +			item_array_t* items; +			getDirectDescendentsOf(parent_id,cats,items); +			if (!cats) +			{ +				LL_WARNS() << "cat " << cat_id << " name [" << cat->getName() +						<< "] orphaned - no child cat array for alleged parent " << parent_id << LL_ENDL; +				valid = false; +			} +			else +			{ +				bool found = false; +				for (S32 i = 0; i<cats->size(); i++) +				{ +					LLViewerInventoryCategory *kid_cat = cats->at(i); +					if (kid_cat == cat) +					{ +						found = true; +						break; +					} +				} +				if (!found) +				{ +					LL_WARNS() << "cat " << cat_id << " name [" << cat->getName() +							<< "] orphaned - not found in child cat array of alleged parent " << parent_id << LL_ENDL; +				} +			} +		} +	} + +	for(item_map_t::const_iterator iit = mItemMap.begin(); iit != mItemMap.end(); ++iit) +	{ +		const LLUUID& item_id = iit->first; +		LLViewerInventoryItem *item = iit->second; +		if (item->getUUID() != item_id) +		{ +			LL_WARNS() << "item_id " << item_id << " does not match " << item->getUUID() << LL_ENDL; +			valid = false; +		} + +		const LLUUID& parent_id = item->getParentUUID(); +		if (parent_id.isNull()) +		{ +			LL_WARNS() << "item " << item_id << " name [" << item->getName() << "] has null parent id!" << LL_ENDL; +		} +		else +		{ +			cat_array_t* cats; +			item_array_t* items; +			getDirectDescendentsOf(parent_id,cats,items); +			if (!items) +			{ +				LL_WARNS() << "item " << item_id << " name [" << item->getName() +						<< "] orphaned - alleged parent has no child items list " << parent_id << LL_ENDL; +			} +			else +			{ +				bool found = false; +				for (S32 i=0; i<items->size(); ++i) +				{ +					if (items->at(i) == item)  +					{ +						found = true; +						break; +					} +				} +				if (!found) +				{ +					LL_WARNS() << "item " << item_id << " name [" << item->getName() +							<< "] orphaned - not found as child of alleged parent " << parent_id << LL_ENDL; +				} +			} +				 +		} +		// Link checking +		if (item->getIsLinkType()) +		{ +			const LLUUID& link_id = item->getUUID(); +			const LLUUID& target_id = item->getLinkedUUID(); +			LLViewerInventoryItem *target_item = getItem(target_id); +			LLViewerInventoryCategory *target_cat = getCategory(target_id); +			// Linked-to UUID should have back reference to this link. +			if (!hasBacklinkInfo(link_id, target_id)) +			{ +				LL_WARNS() << "link " << item->getUUID() << " type " << item->getActualType() +						<< " missing backlink info at target_id " << target_id +						<< LL_ENDL; +			} +			// Links should have referents. +			if (item->getActualType() == LLAssetType::AT_LINK && !target_item) +			{ +				LL_WARNS() << "broken item link " << item->getName() << " id " << item->getUUID() << LL_ENDL; +			} +			else if (item->getActualType() == LLAssetType::AT_LINK_FOLDER && !target_cat) +			{ +				LL_WARNS() << "broken folder link " << item->getName() << " id " << item->getUUID() << LL_ENDL; +			} +			if (target_item && target_item->getIsLinkType()) +			{ +				LL_WARNS() << "link " << item->getName() << " references a link item " +						<< target_item->getName() << " " << target_item->getUUID() << LL_ENDL; +			} + +			// Links should not have backlinks. +			std::pair<backlink_mmap_t::const_iterator, backlink_mmap_t::const_iterator> range = mBacklinkMMap.equal_range(link_id); +			if (range.first != range.second) +			{ +				LL_WARNS() << "Link item " << item->getName() << " has backlinks!" << LL_ENDL; +			} +		} +		else +		{ +			// Check the backlinks of a non-link item. +			const LLUUID& target_id = item->getUUID(); +			std::pair<backlink_mmap_t::const_iterator, backlink_mmap_t::const_iterator> range = mBacklinkMMap.equal_range(target_id); +			for (backlink_mmap_t::const_iterator it = range.first; it != range.second; ++it) +			{ +				const LLUUID& link_id = it->second; +				LLViewerInventoryItem *link_item = getItem(link_id); +				if (!link_item || !link_item->getIsLinkType()) +				{ +					LL_WARNS() << "invalid backlink from target " << item->getName() << " to " << link_id << LL_ENDL; +				} +			} +		} +	} +	 +	if (cat_lock > 0 || item_lock > 0) +	{ +		LL_INFOS() << "Found locks on some categories: sub-cat arrays " +				<< cat_lock << ", item arrays " << item_lock << LL_ENDL; +	} +	if (desc_unknown_count != 0) +	{ +		LL_INFOS() << "Found " << desc_unknown_count << " cats with unknown descendent count" << LL_ENDL;  +	} +	if (version_unknown_count != 0) +	{ +		LL_INFOS() << "Found " << version_unknown_count << " cats with unknown version" << LL_ENDL; +	} + +	LL_INFOS() << "Validate done, valid = " << (U32) valid << LL_ENDL; + +	return valid; +} +  ///----------------------------------------------------------------------------  /// Local function definitions  ///---------------------------------------------------------------------------- diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index 7dd7ac8e9a..2e957809be 100755 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -33,6 +33,7 @@  #include "llcurl.h"  #include "lluuid.h"  #include "llpermissionsflags.h" +#include "llviewerinventory.h"  #include "llstring.h"  #include "llmd5.h"  #include <map> @@ -44,14 +45,9 @@ class LLInventoryObserver;  class LLInventoryObject;  class LLInventoryItem;  class LLInventoryCategory; -class LLViewerInventoryItem; -class LLViewerInventoryCategory; -class LLViewerInventoryItem; -class LLViewerInventoryCategory;  class LLMessageSystem;  class LLInventoryCollectFunctor; -  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  // LLInventoryModel  // @@ -80,11 +76,12 @@ public:  	class fetchInventoryResponder : public LLCurl::Responder  	{ +		LOG_CLASS(fetchInventoryResponder);  	public:  		fetchInventoryResponder(const LLSD& request_sd) : mRequestSD(request_sd) {}; -		void result(const LLSD& content);			 -		void errorWithContent(U32 status, const std::string& reason, const LLSD& content);  	protected: +		virtual void httpSuccess(); +		virtual void httpFailure();  		LLSD mRequestSD;  	}; @@ -137,6 +134,8 @@ public:  	// during authentication. Returns true if everything parsed.  	bool loadSkeleton(const LLSD& options, const LLUUID& owner_id);  	void buildParentChildMap(); // brute force method to rebuild the entire parent-child relations +	void createCommonSystemCategories(); +	  	// Call on logout to save a terse representation.  	void cache(const LLUUID& parent_folder_id, const LLUUID& agent_id);  private: @@ -155,6 +154,15 @@ private:  	parent_cat_map_t mParentChildCategoryTree;  	parent_item_map_t mParentChildItemTree; +	// Track links to items and categories. We do not store item or +	// category pointers here, because broken links are also supported. +	typedef std::multimap<LLUUID, LLUUID> backlink_mmap_t; +	backlink_mmap_t mBacklinkMMap; // key = target_id: ID of item, values = link_ids: IDs of item or folder links referencing it. +	// For internal use only +	bool hasBacklinkInfo(const LLUUID& link_id, const LLUUID& target_id) const; +	void addBacklinkInfo(const LLUUID& link_id, const LLUUID& target_id); +	void removeBacklinkInfo(const LLUUID& link_id, const LLUUID& target_id); +	  	//--------------------------------------------------------------------  	// Login  	//-------------------------------------------------------------------- @@ -203,6 +211,9 @@ public:  		EXCLUDE_TRASH = FALSE,   		INCLUDE_TRASH = TRUE   	}; +	// Simpler existence test if matches don't actually need to be collected. +	bool hasMatchingDirectDescendent(const LLUUID& cat_id, +									 LLInventoryCollectFunctor& filter);  	void collectDescendents(const LLUUID& id,  							cat_array_t& categories,  							item_array_t& items, @@ -211,22 +222,27 @@ public:  							  cat_array_t& categories,  							  item_array_t& items,  							  BOOL include_trash, -							  LLInventoryCollectFunctor& add, -							  BOOL follow_folder_links = FALSE); +							  LLInventoryCollectFunctor& add);  	// Collect all items in inventory that are linked to item_id.  	// Assumes item_id is itself not a linked item. -	item_array_t collectLinkedItems(const LLUUID& item_id, -									const LLUUID& start_folder_id = LLUUID::null); -	 +	item_array_t collectLinksTo(const LLUUID& item_id);  	// Check if one object has a parent chain up to the category specified by UUID.  	BOOL isObjectDescendentOf(const LLUUID& obj_id, const LLUUID& cat_id) const; +	// Follow parent chain to the top. +	bool getObjectTopmostAncestor(const LLUUID& object_id, LLUUID& result) const; +	  	//--------------------------------------------------------------------  	// Find  	//--------------------------------------------------------------------  public: +	const LLUUID findCategoryUUIDForTypeInRoot( +		LLFolderType::EType preferred_type, +		bool create_folder, +		const LLUUID& root_id); +  	// Returns the uuid of the category that specifies 'type' as what it   	// defaults to containing. The category is not necessarily only for that type.   	//    NOTE: If create_folder is true, this will create a new inventory category  @@ -296,7 +312,7 @@ public:  	//    NOTE: In usage, you will want to perform cache accounting  	//    operations in LLInventoryModel::accountForUpdate() or  	//    LLViewerInventoryItem::updateServer() before calling this method. -	U32 updateItem(const LLViewerInventoryItem* item); +	U32 updateItem(const LLViewerInventoryItem* item, U32 mask = 0);  	// Change an existing item with the matching id or add  	// the category. No notifcation will be sent to observers. This @@ -305,7 +321,7 @@ public:  	//    NOTE: In usage, you will want to perform cache accounting  	//    operations in accountForUpdate() or LLViewerInventoryCategory::  	//    updateServer() before calling this method. -	void updateCategory(const LLViewerInventoryCategory* cat); +	void updateCategory(const LLViewerInventoryCategory* cat, U32 mask = 0);  	// Move the specified object id to the specified category and  	// update the internal structures. No cache accounting, @@ -326,11 +342,31 @@ public:  	// Delete  	//--------------------------------------------------------------------  public: + +	// Update model after an AISv3 update received for any operation. +	void onAISUpdateReceived(const std::string& context, const LLSD& update); +		 +	// Update model after an item is confirmed as removed from +	// server. Works for categories or items. +	void onObjectDeletedFromServer(const LLUUID& item_id, +								   bool fix_broken_links = true, +								   bool update_parent_version = true, +								   bool do_notify_observers = true); + +	// Update model after all descendents removed from server. +	void onDescendentsPurgedFromServer(const LLUUID& object_id, bool fix_broken_links = true); + +	// Update model after an existing item gets updated on server. +	void onItemUpdated(const LLUUID& item_id, const LLSD& updates, bool update_parent_version); + +	// Update model after an existing category gets updated on server. +	void onCategoryUpdated(const LLUUID& cat_id, const LLSD& updates); +  	// Delete a particular inventory object by ID. Will purge one  	// object from the internal data structures, maintaining a  	// consistent internal state. No cache accounting, observer  	// notification, or server update is performed. -	void deleteObject(const LLUUID& id); +	void deleteObject(const LLUUID& id, bool fix_broken_links = true, bool do_notify_observers = true);  	/// move Item item_id to Trash  	void removeItem(const LLUUID& item_id);  	/// move Category category_id to Trash @@ -338,17 +374,6 @@ public:  	/// removeItem() or removeCategory(), whichever is appropriate  	void removeObject(const LLUUID& object_id); -	// Delete a particular inventory object by ID, and delete it from -	// the server. Also updates linked items. -	void purgeObject(const LLUUID& id); - -	// Collects and purges the descendants of the id -	// provided. If the category is not found, no action is -	// taken. This method goes through the long winded process of -	// removing server representation of folders and items while doing -	// cache accounting in a fairly efficient manner. This method does -	// not notify observers (though maybe it should...) -	void purgeDescendentsOf(const LLUUID& id);  protected:  	void updateLinkedObjectsFromPurge(const LLUUID& baseobj_id); @@ -383,8 +408,7 @@ public:  	LLUUID createNewCategory(const LLUUID& parent_id,  							 LLFolderType::EType preferred_type,  							 const std::string& name, -							 void (*callback)(const LLSD&, void*) = NULL, -							 void* user_data = NULL ); +							 boost::optional<inventory_func_type> callback = boost::optional<inventory_func_type>());  protected:  	// Internal methods that add inventory and make sure that all of  	// the internal data structures are consistent. These methods @@ -461,7 +485,9 @@ public:  	// been changed 'under the hood', but outside the control of the  	// inventory. The next notify will include that notification.  	void addChangedMask(U32 mask, const LLUUID& referent); +	  	const changed_items_t& getChangedIDs() const { return mChangedItemIDs; } +	const changed_items_t& getAddedIDs() const { return mAddedItemIDs; }  protected:  	// Updates all linked items pointing to this id.  	void addChangedMaskForLinks(const LLUUID& object_id, U32 mask); @@ -472,6 +498,8 @@ private:  	// Variables used to track what has changed since the last notify.  	U32 mModifyMask;  	changed_items_t mChangedItemIDs; +	changed_items_t mAddedItemIDs; +	  	//--------------------------------------------------------------------  	// Observers @@ -533,7 +561,7 @@ public:  	static void processMoveInventoryItem(LLMessageSystem* msg, void**);  	static void processFetchInventoryReply(LLMessageSystem* msg, void**);  protected: -	bool messageUpdateCore(LLMessageSystem* msg, bool do_accounting); +	bool messageUpdateCore(LLMessageSystem* msg, bool do_accounting, U32 mask = 0x0);  	//--------------------------------------------------------------------  	// Locks @@ -555,6 +583,7 @@ private:  	//--------------------------------------------------------------------  public:  	void dumpInventory() const; +	bool validate() const;  /**                    Miscellaneous   **                                                                            ** diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp index a8fda4fcf8..2de37b0790 100755 --- a/indra/newview/llinventorymodelbackgroundfetch.cpp +++ b/indra/newview/llinventorymodelbackgroundfetch.cpp @@ -1,6 +1,6 @@  /**  - * @file llinventorymodel.cpp - * @brief Implementation of the inventory model used to track agent inventory. + * @file llinventorymodelbackgroundfetch.cpp + * @brief Implementation of background fetching of inventory.   *   * $LicenseInfo:firstyear=2002&license=viewerlgpl$   * Second Life Viewer Source Code @@ -172,8 +172,11 @@ void LLInventoryModelBackgroundFetch::setAllFoldersFetched()  		mRecursiveLibraryFetchStarted)  	{  		mAllFoldersFetched = TRUE; +		//LL_INFOS() << "All folders fetched, validating" << LL_ENDL; +		//gInventory.validate();  	}  	mFolderFetchActive = false; +	mBackgroundFetchActive = false;  }  void LLInventoryModelBackgroundFetch::backgroundFetchCB(void *) @@ -363,35 +366,40 @@ void LLInventoryModelBackgroundFetch::incrFetchCount(S16 fetching)  class LLInventoryModelFetchItemResponder : public LLInventoryModel::fetchInventoryResponder  { +	LOG_CLASS(LLInventoryModelFetchItemResponder);  public: -	LLInventoryModelFetchItemResponder(const LLSD& request_sd) : LLInventoryModel::fetchInventoryResponder(request_sd) {}; -	void result(const LLSD& content);			 -	void errorWithContent(U32 status, const std::string& reason, const LLSD& content); +	LLInventoryModelFetchItemResponder(const LLSD& request_sd) : +		LLInventoryModel::fetchInventoryResponder(request_sd) +	{ +		LLInventoryModelBackgroundFetch::instance().incrFetchCount(1); +	} +private: +	/* virtual */ void httpCompleted() +	{ +		LLInventoryModelBackgroundFetch::instance().incrFetchCount(-1); +		LLInventoryModel::fetchInventoryResponder::httpCompleted(); +	}  }; -void LLInventoryModelFetchItemResponder::result( const LLSD& content ) -{ -	LLInventoryModel::fetchInventoryResponder::result(content); -	LLInventoryModelBackgroundFetch::instance().incrFetchCount(-1); -} - -void LLInventoryModelFetchItemResponder::errorWithContent( U32 status, const std::string& reason, const LLSD& content ) -{ -	LLInventoryModel::fetchInventoryResponder::errorWithContent(status, reason, content); -	LLInventoryModelBackgroundFetch::instance().incrFetchCount(-1); -} - -  class LLInventoryModelFetchDescendentsResponder: public LLHTTPClient::Responder  { +	LOG_CLASS(LLInventoryModelFetchDescendentsResponder);  public:  	LLInventoryModelFetchDescendentsResponder(const LLSD& request_sd, uuid_vec_t recursive_cats) :   		mRequestSD(request_sd),  		mRecursiveCatUUIDs(recursive_cats) -	{}; +	{ +		LLInventoryModelBackgroundFetch::instance().incrFetchCount(1); +	}  	//LLInventoryModelFetchDescendentsResponder() {}; -	void result(const LLSD& content); -	void errorWithContent(U32 status, const std::string& reason, const LLSD& content); +private: +	/* virtual */ void httpCompleted() +	{ +		LLInventoryModelBackgroundFetch::instance().incrFetchCount(-1); +		LLHTTPClient::Responder::httpCompleted(); +	} +	/* virtual */ void httpSuccess(); +	/* virtual */ void httpFailure();  protected:  	BOOL getIsRecursive(const LLUUID& cat_id) const;  private: @@ -400,8 +408,14 @@ private:  };  // If we get back a normal response, handle it here. -void LLInventoryModelFetchDescendentsResponder::result(const LLSD& content) +void LLInventoryModelFetchDescendentsResponder::httpSuccess()  { +	const LLSD& content = getContent(); +	if (!content.isMap()) +	{ +		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); +		return; +	}  	LLInventoryModelBackgroundFetch *fetcher = LLInventoryModelBackgroundFetch::getInstance();  	if (content.has("folders"))	  	{ @@ -508,16 +522,15 @@ void LLInventoryModelFetchDescendentsResponder::result(const LLSD& content)  		for(LLSD::array_const_iterator folder_it = content["bad_folders"].beginArray();  			folder_it != content["bad_folders"].endArray();  			++folder_it) -		{	 +		{ +			// *TODO: Stop copying data  			LLSD folder_sd = *folder_it;  			// These folders failed on the dataserver.  We probably don't want to retry them. -			LL_INFOS() << "Folder " << folder_sd["folder_id"].asString()  -					<< "Error: " << folder_sd["error"].asString() << LL_ENDL; +			LL_WARNS() << "Folder " << folder_sd["folder_id"].asString()  +					   << "Error: " << folder_sd["error"].asString() << LL_ENDL;  		}  	} - -	fetcher->incrFetchCount(-1);  	if (fetcher->isBulkFetchProcessingComplete())  	{ @@ -529,21 +542,21 @@ void LLInventoryModelFetchDescendentsResponder::result(const LLSD& content)  }  // If we get back an error (not found, etc...), handle it here. -void LLInventoryModelFetchDescendentsResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void LLInventoryModelFetchDescendentsResponder::httpFailure()  { +	LL_WARNS() << dumpResponse() << LL_ENDL;  	LLInventoryModelBackgroundFetch *fetcher = LLInventoryModelBackgroundFetch::getInstance(); -	LL_INFOS() << "LLInventoryModelFetchDescendentsResponder::error [status:" -			<< status << "]: " << content << LL_ENDL; +	LL_INFOS() << dumpResponse() << LL_ENDL;  	fetcher->incrFetchCount(-1); -	if (status==499) // timed out +	if (getStatus()==HTTP_INTERNAL_ERROR) // timed out or curl failure  	{  		for(LLSD::array_const_iterator folder_it = mRequestSD["folders"].beginArray();  			folder_it != mRequestSD["folders"].endArray();  			++folder_it) -		{	 +		{  			LLSD folder_sd = *folder_it;  			LLUUID folder_id = folder_sd["folder_id"];  			const BOOL recursive = getIsRecursive(folder_id); @@ -586,7 +599,7 @@ void LLInventoryModelBackgroundFetch::bulkFetch()  		(mFetchTimer.getElapsedTimeF32() < mMinTimeBetweenFetches))  	{  		return; // just bail if we are disconnected -	}	 +	}  	U32 item_count=0;  	U32 folder_count=0; @@ -686,63 +699,46 @@ void LLInventoryModelBackgroundFetch::bulkFetch()  	{  		if (folder_count)  		{ -			std::string url = region->getCapability("FetchInventoryDescendents2");    +			std::string url = region->getCapability("FetchInventoryDescendents2");   			  			if ( !url.empty() )  			{ -			mFetchCount++; -			if (folder_request_body["folders"].size()) -			{ -				LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(folder_request_body, recursive_cats); -				LLHTTPClient::post(url, folder_request_body, fetcher, 300.0); -			} -			if (folder_request_body_lib["folders"].size()) -			{ -				std::string url_lib = gAgent.getRegion()->getCapability("FetchLibDescendents2"); +				if (folder_request_body["folders"].size()) +				{ +					LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(folder_request_body, recursive_cats); +					LLHTTPClient::post(url, folder_request_body, fetcher, 300.0); +				} +				if (folder_request_body_lib["folders"].size()) +				{ +					std::string url_lib = gAgent.getRegion()->getCapability("FetchLibDescendents2"); -				LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(folder_request_body_lib, recursive_cats); -				LLHTTPClient::post(url_lib, folder_request_body_lib, fetcher, 300.0); +					LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(folder_request_body_lib, recursive_cats); +					LLHTTPClient::post(url_lib, folder_request_body_lib, fetcher, 300.0); +				}  			}  		} -		}  		if (item_count)  		{  			std::string url;  			if (item_request_body.size())  			{ -				mFetchCount++;  				url = region->getCapability("FetchInventory2");  				if (!url.empty())  				{  					LLSD body; -					body["agent_id"]	= gAgent.getID();  					body["items"] = item_request_body;  					LLHTTPClient::post(url, body, new LLInventoryModelFetchItemResponder(body));  				} -				//else -				//{ -				//	LLMessageSystem* msg = gMessageSystem; -				//	msg->newMessage("FetchInventory"); -				//	msg->nextBlock("AgentData"); -				//	msg->addUUID("AgentID", gAgent.getID()); -				//	msg->addUUID("SessionID", gAgent.getSessionID()); -				//	msg->nextBlock("InventoryData"); -				//	msg->addUUID("OwnerID", mPermissions.getOwner()); -				//	msg->addUUID("ItemID", mUUID); -				//	gAgent.sendReliableMessage(); -				//}  			}  			if (item_request_body_lib.size())  			{ -				mFetchCount++;  				url = region->getCapability("FetchLib2");  				if (!url.empty())  				{  					LLSD body; -					body["agent_id"]	= gAgent.getID();  					body["items"] = item_request_body_lib;  					LLHTTPClient::post(url, body, new LLInventoryModelFetchItemResponder(body)); diff --git a/indra/newview/llinventoryobserver.cpp b/indra/newview/llinventoryobserver.cpp index 2cbf9bb8b6..2dd8dce42f 100755 --- a/indra/newview/llinventoryobserver.cpp +++ b/indra/newview/llinventoryobserver.cpp @@ -465,41 +465,13 @@ void LLInventoryFetchComboObserver::startFetch()  	mFetchDescendents->startFetch();  } -void LLInventoryExistenceObserver::watchItem(const LLUUID& id) -{ -	if (id.notNull()) -	{ -		mMIA.push_back(id); -	} -} - -void LLInventoryExistenceObserver::changed(U32 mask) -{ -	// scan through the incomplete items and move or erase them as -	// appropriate. -	if (!mMIA.empty()) -	{ -		for (uuid_vec_t::iterator it = mMIA.begin(); it < mMIA.end(); ) -		{ -			LLViewerInventoryItem* item = gInventory.getItem(*it); -			if (!item) -			{ -				++it; -				continue; -			} -			mExist.push_back(*it); -			it = mMIA.erase(it); -		} -		if (mMIA.empty()) -		{ -			done(); -		} -	} -} - +// See comment preceding LLInventoryAddedObserver::changed() for some +// concerns that also apply to this observer.  void LLInventoryAddItemByAssetObserver::changed(U32 mask)  { -	if(!(mask & LLInventoryObserver::ADD)) +	if(!(mask & LLInventoryObserver::ADD) || +	   !(mask & LLInventoryObserver::CREATE) || +	   !(mask & LLInventoryObserver::UPDATE_CREATE))  	{  		return;  	} @@ -510,20 +482,12 @@ void LLInventoryAddItemByAssetObserver::changed(U32 mask)  		return;  	} -	LLMessageSystem* msg = gMessageSystem; -	if (!(msg->getMessageName() && (0 == strcmp(msg->getMessageName(), "UpdateCreateInventoryItem")))) +	const uuid_set_t& added = gInventory.getAddedIDs(); +	for (uuid_set_t::iterator it = added.begin(); it != added.end(); ++it)  	{ -		// this is not our message -		return; // to prevent a crash. EXT-7921; -	} - -	LLPointer<LLViewerInventoryItem> item = new LLViewerInventoryItem; -	S32 num_blocks = msg->getNumberOfBlocksFast(_PREHASH_InventoryData); -	for(S32 i = 0; i < num_blocks; ++i) -	{ -		item->unpackMessage(msg, _PREHASH_InventoryData, i); +		LLInventoryItem *item = gInventory.getItem(*it);  		const LLUUID& asset_uuid = item->getAssetUUID(); -		if (item->getUUID().notNull() && asset_uuid.notNull()) +		if (item && item->getUUID().notNull() && asset_uuid.notNull())  		{  			if (isAssetWatched(asset_uuid))  			{ @@ -532,11 +496,11 @@ void LLInventoryAddItemByAssetObserver::changed(U32 mask)  			}  		}  	} - +	  	if (mAddedItems.size() == mWatchedAssets.size())  	{ -		done();  		LL_DEBUGS("Inventory_Move") << "All watched items are added & processed." << LL_ENDL; +		done();  		mAddedItems.clear();  		// Unable to clean watched items here due to somebody can require to check them in current frame. @@ -566,41 +530,28 @@ bool LLInventoryAddItemByAssetObserver::isAssetWatched( const LLUUID& asset_id )  	return std::find(mWatchedAssets.begin(), mWatchedAssets.end(), asset_id) != mWatchedAssets.end();  } +// This observer used to explicitly check for whether it was being +// called as a result of an UpdateCreateInventoryItem message. It has +// now been decoupled enough that it's not actually checking the +// message system, but now we have the special UPDATE_CREATE flag +// being used for the same purpose. Fixing this, as we would need to +// do to get rid of the message, is somewhat subtle because there's no +// particular obvious criterion for when creating a new item should +// trigger this observer and when it shouldn't. For example, creating +// a new notecard with new->notecard causes a preview window to pop up +// via the derived class LLOpenTaskOffer, but creating a new notecard +// by copy and paste does not, solely because one goes through +// UpdateCreateInventoryItem and the other doesn't.  void LLInventoryAddedObserver::changed(U32 mask)  { -	if (!(mask & LLInventoryObserver::ADD)) +	if (!(mask & LLInventoryObserver::ADD) || +		!(mask & LLInventoryObserver::CREATE) || +		!(mask & LLInventoryObserver::UPDATE_CREATE))  	{  		return;  	} -	// *HACK: If this was in response to a packet off -	// the network, figure out which item was updated. -	LLMessageSystem* msg = gMessageSystem; - -	std::string msg_name = msg->getMessageName(); -	if (msg_name.empty()) -	{ -		return; -	} -	 -	// We only want newly created inventory items. JC -	if ( msg_name != "UpdateCreateInventoryItem") -	{ -		return; -	} - -	LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem; -	S32 num_blocks = msg->getNumberOfBlocksFast(_PREHASH_InventoryData); -	for (S32 i = 0; i < num_blocks; ++i) -	{ -		titem->unpackMessage(msg, _PREHASH_InventoryData, i); -		if (!(titem->getUUID().isNull())) -		{ -			//we don't do anything with null keys -			mAdded.push_back(titem->getUUID()); -		} -	} -	if (!mAdded.empty()) +	if (!gInventory.getAddedIDs().empty())  	{  		done();  	} @@ -613,9 +564,9 @@ void LLInventoryCategoryAddedObserver::changed(U32 mask)  		return;  	} -	const LLInventoryModel::changed_items_t& changed_ids = gInventory.getChangedIDs(); +	const LLInventoryModel::changed_items_t& added_ids = gInventory.getAddedIDs(); -	for (LLInventoryModel::changed_items_t::const_iterator cit = changed_ids.begin(); cit != changed_ids.end(); ++cit) +	for (LLInventoryModel::changed_items_t::const_iterator cit = added_ids.begin(); cit != added_ids.end(); ++cit)  	{  		LLViewerInventoryCategory* cat = gInventory.getCategory(*cit); @@ -633,58 +584,6 @@ void LLInventoryCategoryAddedObserver::changed(U32 mask)  	}  } - -LLInventoryTransactionObserver::LLInventoryTransactionObserver(const LLTransactionID& transaction_id) : -	mTransactionID(transaction_id) -{ -} - -void LLInventoryTransactionObserver::changed(U32 mask) -{ -	if (mask & LLInventoryObserver::ADD) -	{ -		// This could be it - see if we are processing a bulk update -		LLMessageSystem* msg = gMessageSystem; -		if (msg->getMessageName() -		   && (0 == strcmp(msg->getMessageName(), "BulkUpdateInventory"))) -		{ -			// we have a match for the message - now check the -			// transaction id. -			LLUUID id; -			msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_TransactionID, id); -			if (id == mTransactionID) -			{ -				// woo hoo, we found it -				uuid_vec_t folders; -				uuid_vec_t items; -				S32 count; -				count = msg->getNumberOfBlocksFast(_PREHASH_FolderData); -				S32 i; -				for (i = 0; i < count; ++i) -				{ -					msg->getUUIDFast(_PREHASH_FolderData, _PREHASH_FolderID, id, i); -					if (id.notNull()) -					{ -						folders.push_back(id); -					} -				} -				count = msg->getNumberOfBlocksFast(_PREHASH_ItemData); -				for (i = 0; i < count; ++i) -				{ -					msg->getUUIDFast(_PREHASH_ItemData, _PREHASH_ItemID, id, i); -					if (id.notNull()) -					{ -						items.push_back(id); -					} -				} - -				// call the derived class the implements this method. -				done(folders, items); -			} -		} -	} -} -  void LLInventoryCategoriesObserver::changed(U32 mask)  {  	if (!mCategoryMap.size()) @@ -702,7 +601,7 @@ void LLInventoryCategoriesObserver::changed(U32 mask)  		LLViewerInventoryCategory* category = gInventory.getCategory(cat_id);  		if (!category)          { -            llwarns << "Category : Category id = " << cat_id << " disappeared" << llendl; +            LL_WARNS() << "Category : Category id = " << cat_id << " disappeared" << LL_ENDL;  			cat_data.mCallback();              // Keep track of those deleted categories so we can remove them              deleted_categories_ids.push_back(cat_id); @@ -833,3 +732,23 @@ LLInventoryCategoriesObserver::LLCategoryData::LLCategoryData(  {  	mItemNameHash.finalize();  } + +void LLScrollOnRenameObserver::changed(U32 mask) +{ +	if (mask & LLInventoryObserver::LABEL) +	{ +		const uuid_set_t& changed_item_ids = gInventory.getChangedIDs(); +		for (uuid_set_t::const_iterator it = changed_item_ids.begin(); it != changed_item_ids.end(); ++it) +		{ +			const LLUUID& id = *it; +			if (id == mUUID) +			{ +				mView->scrollToShowSelection(); +					 +				gInventory.removeObserver(this); +				delete this; +				return; +			} +		} +	} +} diff --git a/indra/newview/llinventoryobserver.h b/indra/newview/llinventoryobserver.h index aa1eae84d7..8cf6a6bdab 100755 --- a/indra/newview/llinventoryobserver.h +++ b/indra/newview/llinventoryobserver.h @@ -58,6 +58,9 @@ public:  		GESTURE 		= 64,  		REBUILD 		= 128, 	// Item UI changed (e.g. item type different)  		SORT 			= 256, 	// Folder needs to be resorted. +		CREATE			= 512,  // With ADD, item has just been created. +		// unfortunately a particular message is still associated with some unique semantics. +		UPDATE_CREATE	= 1024,  // With ADD, item added via UpdateCreateInventoryItem  		ALL 			= 0xffffffff  	};  	LLInventoryObserver(); @@ -152,25 +155,6 @@ protected:  };  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLInventoryExistenceObserver -// -//   Used as a base class for doing something when all the -//   observed item ids exist in the inventory somewhere. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLInventoryExistenceObserver : public LLInventoryObserver -{ -public: -	LLInventoryExistenceObserver() {} -	/*virtual*/ void changed(U32 mask); - -	void watchItem(const LLUUID& id); -protected: -	virtual void done() = 0; -	uuid_vec_t mExist; -	uuid_vec_t mMIA; -}; - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  // Class LLInventoryMovedObserver  //  // This class is used as a base class for doing something when all the @@ -209,13 +193,11 @@ private:  class LLInventoryAddedObserver : public LLInventoryObserver  {  public: -	LLInventoryAddedObserver() : mAdded() {} +	LLInventoryAddedObserver() {}  	/*virtual*/ void changed(U32 mask);  protected:  	virtual void done() = 0; - -	uuid_vec_t mAdded;  };  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -241,25 +223,6 @@ protected:  };  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLInventoryTransactionObserver -// -//   Base class for doing something when an inventory transaction completes. -//   NOTE: This class is not quite complete. Avoid using unless you fix up its -//   functionality gaps. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLInventoryTransactionObserver : public LLInventoryObserver -{ -public: -	LLInventoryTransactionObserver(const LLTransactionID& transaction_id); -	/*virtual*/ void changed(U32 mask); - -protected: -	virtual void done(const uuid_vec_t& folders, const uuid_vec_t& items) = 0; - -	LLTransactionID mTransactionID; -}; - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  // Class LLInventoryCompletionObserver  //  //   Base class for doing something when when all observed items are locally  @@ -326,4 +289,22 @@ protected:  	category_map_t				mCategoryMap;  }; +class LLFolderView; + +// Force a FolderView to scroll after an item in the corresponding view has been renamed. +class LLScrollOnRenameObserver: public LLInventoryObserver +{ +public: +	LLFolderView *mView; +	LLUUID mUUID; +	 +	LLScrollOnRenameObserver(const LLUUID& uuid, LLFolderView *view): +		mUUID(uuid), +		mView(view) +	{ +	} +	/* virtual */ void changed(U32 mask); +}; + +  #endif // LL_LLINVENTORYOBSERVERS_H diff --git a/indra/newview/lllocalbitmaps.cpp b/indra/newview/lllocalbitmaps.cpp index 1948475530..8e4950f5c2 100755 --- a/indra/newview/lllocalbitmaps.cpp +++ b/indra/newview/lllocalbitmaps.cpp @@ -541,7 +541,7 @@ void LLLocalBitmap::updateUserLayers(LLUUID old_id, LLUUID new_id, LLWearableTyp  					{  						U32 index = gAgentWearables.getWearableIndex(wearable);  						gAgentAvatarp->setLocalTexture(reg_texind, gTextureList.getImage(new_id), FALSE, index); -						gAgentAvatarp->wearableUpdated(type, FALSE); +						gAgentAvatarp->wearableUpdated(type);  						/* telling the manager to rebake once update cycle is fully done */  						LLLocalBitmapMgr::setNeedsRebake(); diff --git a/indra/newview/lllocationinputctrl.cpp b/indra/newview/lllocationinputctrl.cpp index af194aaa1d..8d21fda8f9 100755 --- a/indra/newview/lllocationinputctrl.cpp +++ b/indra/newview/lllocationinputctrl.cpp @@ -107,8 +107,8 @@ public:  private:  	/*virtual*/ void done()  	{ -		uuid_vec_t::const_iterator it = mAdded.begin(), end = mAdded.end(); -		for(; it != end; ++it) +		const uuid_set_t& added = gInventory.getAddedIDs(); +		for (uuid_set_t::const_iterator it = added.begin(); it != added.end(); ++it)  		{  			LLInventoryItem* item = gInventory.getItem(*it);  			if (!item || item->getType() != LLAssetType::AT_LANDMARK) @@ -124,8 +124,6 @@ private:  				mInput->onLandmarkLoaded(lm);  			}  		} - -		mAdded.clear();  	}  	LLLocationInputCtrl* mInput; @@ -142,7 +140,11 @@ public:  private:  	/*virtual*/ void changed(U32 mask)  	{ -		if (mask & (~(LLInventoryObserver::LABEL|LLInventoryObserver::INTERNAL|LLInventoryObserver::ADD))) +		if (mask & (~(LLInventoryObserver::LABEL| +					  LLInventoryObserver::INTERNAL| +					  LLInventoryObserver::ADD| +					  LLInventoryObserver::CREATE| +					  LLInventoryObserver::UPDATE_CREATE)))  		{  			mInput->updateAddLandmarkButton();  		} diff --git a/indra/newview/llmarketplacefunctions.cpp b/indra/newview/llmarketplacefunctions.cpp index 8d237b1868..7925662663 100755 --- a/indra/newview/llmarketplacefunctions.cpp +++ b/indra/newview/llmarketplacefunctions.cpp @@ -136,7 +136,7 @@ public:      void completedHeader(U32 status, const std::string& reason, const LLSD& content)      { -		if (isGoodStatus(status) || sBypassMerchant) +		if (((200 <= status ) && (status < 300)) || sBypassMerchant)  		{              log_SLM_infos("Get /merchant", status, "User is a merchant");              LLMarketplaceData::instance().setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_MERCHANT); @@ -166,7 +166,7 @@ public:                                const LLChannelDescriptors& channels,                                const LLIOPipe::buffer_ptr_t& buffer)      { -		if (!isGoodStatus(status)) +		if (!(200 <= status ) && (status < 300))  		{              log_SLM_warning("Get /listings", status, reason, "", "");              return; @@ -225,7 +225,7 @@ public:                                const LLChannelDescriptors& channels,                                const LLIOPipe::buffer_ptr_t& buffer)      { -		if (!isGoodStatus(status)) +		if (!(200 <= status ) && (status < 300))  		{              log_SLM_warning("Post /listings", status, reason, "", "");              return; @@ -285,7 +285,7 @@ public:          strstrm << istr.rdbuf();          const std::string body = strstrm.str(); -		if (!isGoodStatus(status)) +		if (!(200 <= status ) && (status < 300))  		{              log_SLM_warning("Get /listing", status, reason, "", body);              return; @@ -345,7 +345,7 @@ public:          strstrm << istr.rdbuf();          const std::string body = strstrm.str(); -		if (!isGoodStatus(status)) +		if (!(200 <= status ) && (status < 300))  		{              log_SLM_warning("Put /listing", status, reason, "", body);              return; @@ -402,7 +402,7 @@ public:                                const LLChannelDescriptors& channels,                                const LLIOPipe::buffer_ptr_t& buffer)      { -		if (!isGoodStatus(status)) +		if (!(200 <= status ) && (status < 300))  		{              log_SLM_warning("Put /associate_inventory", status, reason, "", "");              return; @@ -474,7 +474,7 @@ public:          strstrm << istr.rdbuf();          const std::string body = strstrm.str(); - 		if (!isGoodStatus(status)) + 		if (!(200 <= status ) && (status < 300))  		{              log_SLM_warning("Delete /listing", status, reason, "", body);              return; @@ -516,7 +516,7 @@ namespace LLMarketplaceImport  	bool hasSessionCookie();  	bool inProgress();  	bool resultPending(); -	U32 getResultStatus(); +	S32 getResultStatus();  	const LLSD& getResults();  	bool establishMarketplaceSessionCookie(); @@ -530,7 +530,7 @@ namespace LLMarketplaceImport  	static bool sImportInProgress = false;  	static bool sImportPostPending = false;  	static bool sImportGetPending = false; -	static U32 sImportResultStatus = 0; +	static S32 sImportResultStatus = 0;  	static LLSD sImportResults = LLSD::emptyMap();  	static LLTimer slmGetTimer; @@ -540,23 +540,26 @@ namespace LLMarketplaceImport  	class LLImportPostResponder : public LLHTTPClient::Responder  	{ +		LOG_CLASS(LLImportPostResponder);  	public:  		LLImportPostResponder() : LLCurl::Responder() {} -		 -		void completed(U32 status, const std::string& reason, const LLSD& content) + +	protected: +		/* virtual */ void httpCompleted()  		{  			slmPostTimer.stop();  			if (gSavedSettings.getBOOL("InventoryOutboxLogging"))  			{ -				LL_INFOS() << " SLM POST status: " << status << LL_ENDL; -				LL_INFOS() << " SLM POST reason: " << reason << LL_ENDL; -				LL_INFOS() << " SLM POST content: " << content.asString() << LL_ENDL; -				LL_INFOS() << " SLM POST timer: " << slmPostTimer.getElapsedTimeF32() << LL_ENDL; +				LL_INFOS() << " SLM [timer:" << slmPostTimer.getElapsedTimeF32() << "] " +						   << dumpResponse() << LL_ENDL;  			} -			// MAINT-2301 : we determined we can safely ignore that error in that context -			if (status == MarketplaceErrorCodes::IMPORT_JOB_TIMEOUT) +			S32 status = getStatus(); +			if ((status == MarketplaceErrorCodes::IMPORT_REDIRECT) || +				(status == MarketplaceErrorCodes::IMPORT_AUTHENTICATION_ERROR) || +				// MAINT-2301 : we determined we can safely ignore that error in that context +				(status == MarketplaceErrorCodes::IMPORT_JOB_TIMEOUT))  			{  				if (gSavedSettings.getBOOL("InventoryOutboxLogging"))  				{ @@ -577,39 +580,37 @@ namespace LLMarketplaceImport  			sImportInProgress = (status == MarketplaceErrorCodes::IMPORT_DONE);  			sImportPostPending = false;  			sImportResultStatus = status; -			sImportId = content; +			sImportId = getContent();  		}  	};  	class LLImportGetResponder : public LLHTTPClient::Responder  	{ +		LOG_CLASS(LLImportGetResponder);  	public:  		LLImportGetResponder() : LLCurl::Responder() {} -		void completedHeader(U32 status, const std::string& reason, const LLSD& content) +	protected: +		/* virtual */ void httpCompleted()  		{ -			const std::string& set_cookie_string = content["set-cookie"].asString(); +			const std::string& set_cookie_string = getResponseHeader(HTTP_IN_HEADER_SET_COOKIE);  			if (!set_cookie_string.empty())  			{  				sMarketplaceCookie = set_cookie_string;  			} -		} -		 -		void completed(U32 status, const std::string& reason, const LLSD& content) -		{ +  			slmGetTimer.stop();  			if (gSavedSettings.getBOOL("InventoryOutboxLogging"))  			{ -				LL_INFOS() << " SLM GET status: " << status << LL_ENDL; -				LL_INFOS() << " SLM GET reason: " << reason << LL_ENDL; -				LL_INFOS() << " SLM GET content: " << content.asString() << LL_ENDL; -				LL_INFOS() << " SLM GET timer: " << slmGetTimer.getElapsedTimeF32() << LL_ENDL; +				LL_INFOS() << " SLM [timer:" << slmGetTimer.getElapsedTimeF32() << "] " +						   << dumpResponse() << LL_ENDL;  			}              // MAINT-2452 : Do not clear the cookie on IMPORT_DONE_WITH_ERRORS : Happens when trying to import objects with wrong permissions              // ACME-1221 : Do not clear the cookie on IMPORT_NOT_FOUND : Happens for newly created Merchant accounts that are initally empty +			S32 status = getStatus();  			if ((status >= MarketplaceErrorCodes::IMPORT_BAD_REQUEST) &&                  (status != MarketplaceErrorCodes::IMPORT_DONE_WITH_ERRORS) &&                  (status != MarketplaceErrorCodes::IMPORT_NOT_FOUND)) @@ -628,7 +629,7 @@ namespace LLMarketplaceImport  			sImportInProgress = (status == MarketplaceErrorCodes::IMPORT_PROCESSING);  			sImportGetPending = false;  			sImportResultStatus = status; -			sImportResults = content; +			sImportResults = getContent();  		}  	}; @@ -649,7 +650,7 @@ namespace LLMarketplaceImport  		return (sImportPostPending || sImportGetPending);  	} -	U32 getResultStatus() +	S32 getResultStatus()  	{  		return sImportResultStatus;  	} @@ -713,10 +714,11 @@ namespace LLMarketplaceImport  		// Make the headers for the post  		LLSD headers = LLSD::emptyMap(); -		headers["Accept"] = "*/*"; -		headers["Cookie"] = sMarketplaceCookie; -		headers["Content-Type"] = "application/llsd+xml"; -		headers["User-Agent"] = LLViewerMedia::getCurrentUserAgent(); +		headers[HTTP_OUT_HEADER_ACCEPT] = "*/*"; +		headers[HTTP_OUT_HEADER_COOKIE] = sMarketplaceCookie; +		// *TODO: Why are we setting Content-Type for a GET request? +		headers[HTTP_OUT_HEADER_CONTENT_TYPE] = HTTP_CONTENT_LLSD_XML; +		headers[HTTP_OUT_HEADER_USER_AGENT] = LLViewerMedia::getCurrentUserAgent();  		if (gSavedSettings.getBOOL("InventoryOutboxLogging"))  		{ @@ -750,11 +752,11 @@ namespace LLMarketplaceImport  		// Make the headers for the post  		LLSD headers = LLSD::emptyMap(); -		headers["Accept"] = "*/*"; -		headers["Connection"] = "Keep-Alive"; -		headers["Cookie"] = sMarketplaceCookie; -		headers["Content-Type"] = "application/xml"; -		headers["User-Agent"] = LLViewerMedia::getCurrentUserAgent(); +		headers[HTTP_OUT_HEADER_ACCEPT] = "*/*"; +		headers[HTTP_OUT_HEADER_CONNECTION] = "Keep-Alive"; +		headers[HTTP_OUT_HEADER_COOKIE] = sMarketplaceCookie; +		headers[HTTP_OUT_HEADER_CONTENT_TYPE] = HTTP_CONTENT_XML; +		headers[HTTP_OUT_HEADER_USER_AGENT] = LLViewerMedia::getCurrentUserAgent();  		if (gSavedSettings.getBOOL("InventoryOutboxLogging"))  		{ diff --git a/indra/newview/llmaterialmgr.cpp b/indra/newview/llmaterialmgr.cpp index df6a42db4d..a1f6a01aa0 100644..100755 --- a/indra/newview/llmaterialmgr.cpp +++ b/indra/newview/llmaterialmgr.cpp @@ -71,8 +71,8 @@ public:  	LLMaterialsResponder(const std::string& pMethod, const std::string& pCapabilityURL, CallbackFunction pCallback);  	virtual ~LLMaterialsResponder(); -	virtual void result(const LLSD& pContent); -	virtual void error(U32 pStatus, const std::string& pReason); +	virtual void httpSuccess(); +	virtual void httpFailure();  private:  	std::string      mMethod; @@ -92,14 +92,19 @@ LLMaterialsResponder::~LLMaterialsResponder()  {  } -void LLMaterialsResponder::result(const LLSD& pContent) +void LLMaterialsResponder::httpSuccess()  { +	const LLSD& pContent = getContent(); +  	LL_DEBUGS("Materials") << LL_ENDL;  	mCallback(true, pContent);  } -void LLMaterialsResponder::error(U32 pStatus, const std::string& pReason) +void LLMaterialsResponder::httpFailure()  { +	U32 pStatus = (U32) getStatus(); +	const std::string& pReason = getReason(); +	  	LL_WARNS("Materials")  		<< "\n--------------------------------------------------------------------------\n"  		<< mMethod << " Error[" << pStatus << "] cannot access cap '" << MATERIALS_CAPABILITY_NAME diff --git a/indra/newview/llmediactrl.cpp b/indra/newview/llmediactrl.cpp index 323445afa6..f406bb9f06 100755 --- a/indra/newview/llmediactrl.cpp +++ b/indra/newview/llmediactrl.cpp @@ -52,6 +52,7 @@  #include "llsdutil.h"  #include "lllayoutstack.h"  #include "lliconctrl.h" +#include "llhttpconstants.h"  #include "lltextbox.h"  #include "llbutton.h"  #include "llcheckboxctrl.h" @@ -576,7 +577,7 @@ void LLMediaCtrl::navigateToLocalPage( const std::string& subdir, const std::str  	{  		mCurrentNavUrl = expanded_filename;  		mMediaSource->setSize(mTextureWidth, mTextureHeight); -		mMediaSource->navigateTo(expanded_filename, "text/html", false); +		mMediaSource->navigateTo(expanded_filename, HTTP_CONTENT_TEXT_HTML, false);  	}  } @@ -948,7 +949,7 @@ void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event)  			LL_DEBUGS("Media") <<  "Media event:  MEDIA_EVENT_NAVIGATE_ERROR_PAGE" << LL_ENDL;  			if ( mErrorPageURL.length() > 0 )  			{ -				navigateTo(mErrorPageURL, "text/html"); +				navigateTo(mErrorPageURL, HTTP_CONTENT_TEXT_HTML);  			};  		};  		break; diff --git a/indra/newview/llmediadataclient.cpp b/indra/newview/llmediadataclient.cpp index e3b46d5d2f..691be13610 100755 --- a/indra/newview/llmediadataclient.cpp +++ b/indra/newview/llmediadataclient.cpp @@ -35,7 +35,7 @@  #include <boost/lexical_cast.hpp> -#include "llhttpstatuscodes.h" +#include "llhttpconstants.h"  #include "llsdutil.h"  #include "llmediaentry.h"  #include "lltextureentry.h" @@ -564,7 +564,7 @@ LLMediaDataClient::Responder::Responder(const request_ptr_t &request)  }  /*virtual*/ -void LLMediaDataClient::Responder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void LLMediaDataClient::Responder::httpFailure()  {  	mRequest->stopTracking(); @@ -574,9 +574,17 @@ void LLMediaDataClient::Responder::errorWithContent(U32 status, const std::strin  		return;  	} -	if (status == HTTP_SERVICE_UNAVAILABLE) +	if (getStatus() == HTTP_SERVICE_UNAVAILABLE)  	{ -		F32 retry_timeout = mRequest->getRetryTimerDelay(); +		F32 retry_timeout; +#if 0 +		// *TODO: Honor server Retry-After header. +		if (!hasResponseHeader(HTTP_IN_HEADER_RETRY_AFTER) +			|| !getSecondsUntilRetryAfter(getResponseHeader(HTTP_IN_HEADER_RETRY_AFTER), retry_timeout)) +#endif +		{ +			retry_timeout = mRequest->getRetryTimerDelay(); +		}  		mRequest->incRetryCount(); @@ -594,15 +602,16 @@ void LLMediaDataClient::Responder::errorWithContent(U32 status, const std::strin  				<< mRequest->getRetryCount() << " exceeds " << mRequest->getMaxNumRetries() << ", not retrying" << LL_ENDL;  		}  	} +	// *TODO: Redirect on 3xx status codes.  	else   	{ -		LL_WARNS("LLMediaDataClient") << *mRequest << " http error [status:"  -				<< status << "]:" << content << ")" << LL_ENDL; +		LL_WARNS("LLMediaDataClient") << *mRequest << " http failure " +				<< dumpResponse() << LL_ENDL;  	}  }  /*virtual*/ -void LLMediaDataClient::Responder::result(const LLSD& content) +void LLMediaDataClient::Responder::httpSuccess()  {  	mRequest->stopTracking(); @@ -612,7 +621,7 @@ void LLMediaDataClient::Responder::result(const LLSD& content)  		return;  	} -	LL_DEBUGS("LLMediaDataClientResponse") << *mRequest << " result : " << ll_print_sd(content) << LL_ENDL; +	LL_DEBUGS("LLMediaDataClientResponse") << *mRequest << " " << dumpResponse() << LL_ENDL;  }  ////////////////////////////////////////////////////////////////////////////////////// @@ -876,7 +885,7 @@ LLMediaDataClient::Responder *LLObjectMediaDataClient::RequestUpdate::createResp  /*virtual*/ -void LLObjectMediaDataClient::Responder::result(const LLSD& content) +void LLObjectMediaDataClient::Responder::httpSuccess()  {  	getRequest()->stopTracking(); @@ -886,10 +895,16 @@ void LLObjectMediaDataClient::Responder::result(const LLSD& content)  		return;  	} +	const LLSD& content = getContent(); +	if (!content.isMap()) +	{ +		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); +		return; +	} +  	// This responder is only used for GET requests, not UPDATE. +	LL_DEBUGS("LLMediaDataClientResponse") << *(getRequest()) << " " << dumpResponse() << LL_ENDL; -	LL_DEBUGS("LLMediaDataClientResponse") << *(getRequest()) << " GET returned: " << ll_print_sd(content) << LL_ENDL; -	  	// Look for an error  	if (content.has("error"))  	{ @@ -1003,7 +1018,7 @@ LLMediaDataClient::Responder *LLObjectMediaNavigateClient::RequestNavigate::crea  }  /*virtual*/ -void LLObjectMediaNavigateClient::Responder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void LLObjectMediaNavigateClient::Responder::httpFailure()  {  	getRequest()->stopTracking(); @@ -1015,14 +1030,14 @@ void LLObjectMediaNavigateClient::Responder::errorWithContent(U32 status, const  	// Bounce back (unless HTTP_SERVICE_UNAVAILABLE, in which case call base  	// class -	if (status == HTTP_SERVICE_UNAVAILABLE) +	if (getStatus() == HTTP_SERVICE_UNAVAILABLE)  	{ -		LLMediaDataClient::Responder::errorWithContent(status, reason, content); +		LLMediaDataClient::Responder::httpFailure();  	}  	else  	{  		// bounce the face back -		LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Error navigating: http code=" << status << LL_ENDL; +		LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Error navigating: " << dumpResponse() << LL_ENDL;  		const LLSD &payload = getRequest()->getPayload();  		// bounce the face back  		getRequest()->getObject()->mediaNavigateBounceBack((LLSD::Integer)payload[LLTextureEntry::TEXTURE_INDEX_KEY]); @@ -1030,7 +1045,7 @@ void LLObjectMediaNavigateClient::Responder::errorWithContent(U32 status, const  }  /*virtual*/ -void LLObjectMediaNavigateClient::Responder::result(const LLSD& content) +void LLObjectMediaNavigateClient::Responder::httpSuccess()  {  	getRequest()->stopTracking(); @@ -1040,8 +1055,9 @@ void LLObjectMediaNavigateClient::Responder::result(const LLSD& content)  		return;  	} -	LL_INFOS("LLMediaDataClient") << *(getRequest()) << " NAVIGATE returned " << ll_print_sd(content) << LL_ENDL; +	LL_INFOS("LLMediaDataClient") << *(getRequest()) << " NAVIGATE returned " << dumpResponse() << LL_ENDL; +	const LLSD& content = getContent();  	if (content.has("error"))  	{  		const LLSD &error = content["error"]; @@ -1065,6 +1081,6 @@ void LLObjectMediaNavigateClient::Responder::result(const LLSD& content)  	else   	{  		// No action required. -		LL_DEBUGS("LLMediaDataClientResponse") << *(getRequest()) << " result : " << ll_print_sd(content) << LL_ENDL; +		LL_DEBUGS("LLMediaDataClientResponse") << *(getRequest()) << " " << dumpResponse() << LL_ENDL;  	}  } diff --git a/indra/newview/llmediadataclient.h b/indra/newview/llmediadataclient.h index 89e20a28d0..231b883c32 100755 --- a/indra/newview/llmediadataclient.h +++ b/indra/newview/llmediadataclient.h @@ -74,8 +74,9 @@ public:  // Abstracts the Cap URL, the request, and the responder  class LLMediaDataClient : public LLRefCount  { -public: +protected:      LOG_CLASS(LLMediaDataClient); +public:      const static F32 QUEUE_TIMER_DELAY;// = 1.0; // seconds(s)  	const static F32 UNAVAILABLE_RETRY_TIMER_DELAY;// = 5.0; // secs @@ -192,14 +193,16 @@ protected:  	// Responder  	class Responder : public LLHTTPClient::Responder  	{ +		LOG_CLASS(Responder);  	public:  		Responder(const request_ptr_t &request); +		request_ptr_t &getRequest() { return mRequest; } + +	protected:  		//If we get back an error (not found, etc...), handle it here -		virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content); +		virtual void httpFailure();  		//If we get back a normal response, handle it here.	 Default just logs it. -		virtual void result(const LLSD& content); - -		request_ptr_t &getRequest() { return mRequest; } +		virtual void httpSuccess();  	private:  		request_ptr_t mRequest; @@ -287,8 +290,9 @@ private:  // MediaDataClient specific for the ObjectMedia cap  class LLObjectMediaDataClient : public LLMediaDataClient  { -public: +protected:      LOG_CLASS(LLObjectMediaDataClient); +public:      LLObjectMediaDataClient(F32 queue_timer_delay = QUEUE_TIMER_DELAY,  							F32 retry_timer_delay = UNAVAILABLE_RETRY_TIMER_DELAY,  							U32 max_retries = MAX_RETRIES, @@ -341,10 +345,12 @@ protected:      class Responder : public LLMediaDataClient::Responder      { +        LOG_CLASS(Responder);      public:          Responder(const request_ptr_t &request)              : LLMediaDataClient::Responder(request) {} -        virtual void result(const LLSD &content); +    protected: +        virtual void httpSuccess();      };  private:  	// The Get/Update data client needs a second queue to avoid object updates starving load-ins. @@ -362,8 +368,9 @@ private:  // MediaDataClient specific for the ObjectMediaNavigate cap  class LLObjectMediaNavigateClient : public LLMediaDataClient  { -public: +protected:      LOG_CLASS(LLObjectMediaNavigateClient); +public:  	// NOTE: from llmediaservice.h  	static const int ERROR_PERMISSION_DENIED_CODE = 8002; @@ -397,11 +404,13 @@ protected:      class Responder : public LLMediaDataClient::Responder      { +        LOG_CLASS(Responder);      public:          Responder(const request_ptr_t &request)              : LLMediaDataClient::Responder(request) {} -		virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content); -        virtual void result(const LLSD &content); +    protected: +        virtual void httpFailure(); +        virtual void httpSuccess();      private:          void mediaNavigateBounceBack();      }; diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 08d2d03b9b..80a427c0b8 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -27,8 +27,10 @@  #include "llviewerprecompiledheaders.h" +#include "apr_pools.h" +#include "apr_dso.h" +#include "llhttpconstants.h"  #include "llapr.h" -#include "llhttpstatuscodes.h"  #include "llmeshrepository.h"  #include "llagent.h" @@ -515,6 +517,7 @@ S32 LLMeshRepoThread::sRequestWaterLevel = 0;  class LLMeshHandlerBase : public LLCore::HttpHandler  {  public: +	LOG_CLASS(LLMeshHandlerBase);  	LLMeshHandlerBase()  		: LLCore::HttpHandler(),  		  mMeshParams(), @@ -547,6 +550,7 @@ public:  class LLMeshHeaderHandler : public LLMeshHandlerBase  {  public: +	LOG_CLASS(LLMeshHeaderHandler);  	LLMeshHeaderHandler(const LLVolumeParams & mesh_params)  		: LLMeshHandlerBase()  	{ @@ -603,6 +607,7 @@ public:  class LLMeshSkinInfoHandler : public LLMeshHandlerBase  	{  public: +	LOG_CLASS(LLMeshSkinInfoHandler);  	LLMeshSkinInfoHandler(const LLUUID& id, U32 offset, U32 size)  		: LLMeshHandlerBase(),  		  mMeshID(id), @@ -632,6 +637,7 @@ public:  class LLMeshDecompositionHandler : public LLMeshHandlerBase  	{  public: +	LOG_CLASS(LLMeshDecompositionHandler);  	LLMeshDecompositionHandler(const LLUUID& id, U32 offset, U32 size)  		: LLMeshHandlerBase(),  		  mMeshID(id), @@ -661,6 +667,7 @@ public:  class LLMeshPhysicsShapeHandler : public LLMeshHandlerBase  	{  public: +	LOG_CLASS(LLMeshPhysicsShapeHandler);  	LLMeshPhysicsShapeHandler(const LLUUID& id, U32 offset, U32 size)  		: LLMeshHandlerBase(),  		  mMeshID(id), @@ -736,7 +743,6 @@ void log_upload_error(LLCore::HttpStatus status, const LLSD& content,  	}  } -  LLMeshRepoThread::LLMeshRepoThread()  : LLThread("mesh repo"),    mHttpRequest(NULL), diff --git a/indra/newview/llpanelclassified.cpp b/indra/newview/llpanelclassified.cpp index 62966e3a4e..3cd39d7c7e 100755 --- a/indra/newview/llpanelclassified.cpp +++ b/indra/newview/llpanelclassified.cpp @@ -96,15 +96,11 @@ class LLClassifiedClickMessageResponder : public LLHTTPClient::Responder  {  	LOG_CLASS(LLClassifiedClickMessageResponder); -public: +protected:  	// If we get back an error (not found, etc...), handle it here -	virtual void errorWithContent( -		U32 status, -		const std::string& reason, -		const LLSD& content) +	virtual void httpFailure()  	{ -		LL_WARNS() << "Sending click message failed (" << status << "): [" << reason << "]" << LL_ENDL; -		LL_WARNS() << "Content: [" << content << "]" << LL_ENDL; +		LL_WARNS() << "Sending click message failed " << dumpResponse() << LL_ENDL;  	}  }; diff --git a/indra/newview/llpaneleditwearable.cpp b/indra/newview/llpaneleditwearable.cpp index daa7df682b..ac00c5d986 100755 --- a/indra/newview/llpaneleditwearable.cpp +++ b/indra/newview/llpaneleditwearable.cpp @@ -944,11 +944,11 @@ void LLPanelEditWearable::onCommitSexChange()          LLViewerWearable*     wearable = gAgentWearables.getViewerWearable(type, index);          if (wearable)          { -                wearable->setVisualParamWeight(param->getID(), is_new_sex_male, FALSE); +                wearable->setVisualParamWeight(param->getID(), is_new_sex_male);          } -        param->setWeight( is_new_sex_male, FALSE ); +        param->setWeight( is_new_sex_male); -        gAgentAvatarp->updateSexDependentLayerSets( FALSE ); +        gAgentAvatarp->updateSexDependentLayerSets();          gAgentAvatarp->updateVisualParams(); @@ -983,7 +983,7 @@ void LLPanelEditWearable::onTexturePickerCommit(const LLUICtrl* ctrl)                                  U32 index = gAgentWearables.getWearableIndex(getWearable());                                  gAgentAvatarp->setLocalTexture(entry->mTextureIndex, image, FALSE, index);                                  LLVisualParamHint::requestHintUpdates(); -                                gAgentAvatarp->wearableUpdated(type, FALSE); +                                gAgentAvatarp->wearableUpdated(type);                          }                  }                  else @@ -1007,9 +1007,9 @@ void LLPanelEditWearable::onColorSwatchCommit(const LLUICtrl* ctrl)                          const LLColor4& new_color = LLColor4(ctrl->getValue());                          if( old_color != new_color )                          { -                                getWearable()->setClothesColor(entry->mTextureIndex, new_color, TRUE); +                                getWearable()->setClothesColor(entry->mTextureIndex, new_color);                                  LLVisualParamHint::requestHintUpdates(); -                                gAgentAvatarp->wearableUpdated(getWearable()->getType(), FALSE); +                                gAgentAvatarp->wearableUpdated(getWearable()->getType());                          }                  }                  else @@ -1080,10 +1080,10 @@ void LLPanelEditWearable::saveChanges(bool force_save_as)          if (force_save_as)          { -                // the name of the wearable has changed, re-save wearable with new name -                LLAppearanceMgr::instance().removeCOFItemLinks(mWearablePtr->getItemID()); +			// the name of the wearable has changed, re-save wearable with new name +			LLAppearanceMgr::instance().removeCOFItemLinks(mWearablePtr->getItemID(),gAgentAvatarp->mEndCustomizeCallback);  			gAgentWearables.saveWearableAs(mWearablePtr->getType(), index, new_name, description, FALSE); -                mNameEditor->setText(mWearableItem->getName()); +			mNameEditor->setText(mWearableItem->getName());          }          else          { @@ -1093,17 +1093,19 @@ void LLPanelEditWearable::saveChanges(bool force_save_as)  			if (link_item)  			{  				// Create new link -				link_inventory_item( gAgent.getID(), -									 link_item->getLinkedUUID(), -									 LLAppearanceMgr::instance().getCOF(), -									 link_item->getName(), -									 description, -									 LLAssetType::AT_LINK, -									 NULL); +				LL_DEBUGS("Avatar") << "link refresh, creating new link to " << link_item->getLinkedUUID() +									<< " removing old link at " << link_item->getUUID() +									<< " wearable item id " << mWearablePtr->getItemID() << LL_ENDL; + +				LLInventoryObject::const_object_list_t obj_array; +				obj_array.push_back(LLConstPointer<LLInventoryObject>(link_item)); +				link_inventory_array(LLAppearanceMgr::instance().getCOF(), +									 obj_array,  +									 gAgentAvatarp->mEndCustomizeCallback);  				// Remove old link -				gInventory.purgeObject(link_item->getUUID()); +				remove_inventory_item(link_item->getUUID(), gAgentAvatarp->mEndCustomizeCallback);  			} -                gAgentWearables.saveWearable(mWearablePtr->getType(), index, TRUE, new_name); +			gAgentWearables.saveWearable(mWearablePtr->getType(), index, new_name);          } @@ -1121,7 +1123,7 @@ void LLPanelEditWearable::revertChanges()          mNameEditor->setText(mWearableItem->getName());          updatePanelPickerControls(mWearablePtr->getType());          updateTypeSpecificControls(mWearablePtr->getType()); -        gAgentAvatarp->wearableUpdated(mWearablePtr->getType(), FALSE); +        gAgentAvatarp->wearableUpdated(mWearablePtr->getType());  }  void LLPanelEditWearable::showWearable(LLViewerWearable* wearable, BOOL show, BOOL disable_camera_switch) @@ -1583,7 +1585,7 @@ void LLPanelEditWearable::onInvisibilityCommit(LLCheckBoxCtrl* checkbox_ctrl, LL                  LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture( IMG_INVISIBLE );                  U32 index = gAgentWearables.getWearableIndex(getWearable());                  gAgentAvatarp->setLocalTexture(te, image, FALSE, index); -                gAgentAvatarp->wearableUpdated(getWearable()->getType(), FALSE); +                gAgentAvatarp->wearableUpdated(getWearable()->getType());          }          else          { @@ -1600,7 +1602,7 @@ void LLPanelEditWearable::onInvisibilityCommit(LLCheckBoxCtrl* checkbox_ctrl, LL                  U32 index = gAgentWearables.getWearableIndex(getWearable());                  gAgentAvatarp->setLocalTexture(te, image, FALSE, index); -                gAgentAvatarp->wearableUpdated(getWearable()->getType(), FALSE); +                gAgentAvatarp->wearableUpdated(getWearable()->getType());          }          updatePanelPickerControls(getWearable()->getType()); diff --git a/indra/newview/llpanellandmarks.cpp b/indra/newview/llpanellandmarks.cpp index 343f2b413f..67cbc91332 100755 --- a/indra/newview/llpanellandmarks.cpp +++ b/indra/newview/llpanellandmarks.cpp @@ -527,7 +527,7 @@ void LLLandmarksPanel::setParcelID(const LLUUID& parcel_id)  }  // virtual -void LLLandmarksPanel::setErrorStatus(U32 status, const std::string& reason) +void LLLandmarksPanel::setErrorStatus(S32 status, const std::string& reason)  {  	LL_WARNS() << "Can't handle remote parcel request."<< " Http Status: "<< status << ". Reason : "<< reason<<LL_ENDL;  } diff --git a/indra/newview/llpanellandmarks.h b/indra/newview/llpanellandmarks.h index 80310d1524..c11cbe05ae 100755 --- a/indra/newview/llpanellandmarks.h +++ b/indra/newview/llpanellandmarks.h @@ -108,7 +108,7 @@ protected:  	//LLRemoteParcelInfoObserver interface  	/*virtual*/ void processParcelInfo(const LLParcelData& parcel_data);  	/*virtual*/ void setParcelID(const LLUUID& parcel_id); -	/*virtual*/ void setErrorStatus(U32 status, const std::string& reason); +	/*virtual*/ void setErrorStatus(S32 status, const std::string& reason);  private:  	void initFavoritesInventoryPanel(); diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index e2b4d098e9..088eaa8e0d 100755 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -421,7 +421,7 @@ void LLPanelLogin::showLoginWidgets()  		sInstance->reshapeBrowser();  		// *TODO: Append all the usual login parameters, like first_login=Y etc.  		std::string splash_screen_url = LLGridManager::getInstance()->getLoginPage(); -		web_browser->navigateTo( splash_screen_url, "text/html" ); +		web_browser->navigateTo( splash_screen_url, HTTP_CONTENT_TEXT_HTML );  		LLUICtrl* username_combo = sInstance->getChild<LLUICtrl>("username_combo");  		username_combo->setFocus(TRUE);  	} @@ -785,7 +785,7 @@ void LLPanelLogin::loadLoginPage()  	if (web_browser->getCurrentNavUrl() != login_uri.asString())  	{  		LL_DEBUGS("AppInit") << "loading:    " << login_uri << LL_ENDL; -		web_browser->navigateTo( login_uri.asString(), "text/html" ); +		web_browser->navigateTo( login_uri.asString(), HTTP_CONTENT_TEXT_HTML );  	}  } diff --git a/indra/newview/llpaneloutfitedit.cpp b/indra/newview/llpaneloutfitedit.cpp index e48aa88937..8ccbb03fcc 100755 --- a/indra/newview/llpaneloutfitedit.cpp +++ b/indra/newview/llpaneloutfitedit.cpp @@ -1184,12 +1184,12 @@ BOOL LLPanelOutfitEdit::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,  			 * second argument is used to delay the appearance update until all dragged items  			 * are added to optimize user experience.  			 */ -			LLAppearanceMgr::instance().addCOFItemLink(item->getLinkedUUID(), false); +			LLAppearanceMgr::instance().addCOFItemLink(item->getLinkedUUID());  		}  		else  		{  			// if asset id is not available for the item we must wear it immediately (attachments only) -			LLAppearanceMgr::instance().addCOFItemLink(item->getLinkedUUID(), true); +			LLAppearanceMgr::instance().addCOFItemLink(item->getLinkedUUID(), new LLUpdateAppearanceAndEditWearableOnDestroy(item->getUUID()));  		}  	} diff --git a/indra/newview/llpaneloutfitsinventory.cpp b/indra/newview/llpaneloutfitsinventory.cpp index 3c72607678..1e1f59055f 100755 --- a/indra/newview/llpaneloutfitsinventory.cpp +++ b/indra/newview/llpaneloutfitsinventory.cpp @@ -76,7 +76,8 @@ BOOL LLPanelOutfitsInventory::postBuild()  	// Fetch your outfits folder so that the links are in memory.  	// ( This is only necessary if we want to show a warning if a user deletes an item that has a  	// a link in an outfit, see "ConfirmItemDeleteHasLinks". ) -	const LLUUID &outfits_cat = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTFIT, false); + +	const LLUUID &outfits_cat = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false);  	if (outfits_cat.notNull())  	{  		LLInventoryModelBackgroundFetch::instance().start(outfits_cat); @@ -183,7 +184,7 @@ bool LLPanelOutfitsInventory::onSaveCommit(const LLSD& notification, const LLSD&  		LLStringUtil::trim(outfit_name);  		if( !outfit_name.empty() )  		{ -			LLUUID outfit_folder = LLAppearanceMgr::getInstance()->makeNewOutfitLinks(outfit_name); +			LLAppearanceMgr::getInstance()->makeNewOutfitLinks(outfit_name);  			LLSidepanelAppearance* panel_appearance = getAppearanceSP();  			if (panel_appearance) diff --git a/indra/newview/llpanelpick.h b/indra/newview/llpanelpick.h index 3c1f14759c..7a8bd66fcf 100755 --- a/indra/newview/llpanelpick.h +++ b/indra/newview/llpanelpick.h @@ -86,7 +86,7 @@ public:  	//This stuff we got from LLRemoteParcelObserver, in the last one we intentionally do nothing  	/*virtual*/ void processParcelInfo(const LLParcelData& parcel_data);  	/*virtual*/ void setParcelID(const LLUUID& parcel_id) { mParcelId = parcel_id; } -	/*virtual*/ void setErrorStatus(U32 status, const std::string& reason) {}; +	/*virtual*/ void setErrorStatus(S32 status, const std::string& reason) {};  protected: diff --git a/indra/newview/llpanelplaceinfo.cpp b/indra/newview/llpanelplaceinfo.cpp index 4ae0c0eb12..4e7c5f6ed2 100755 --- a/indra/newview/llpanelplaceinfo.cpp +++ b/indra/newview/llpanelplaceinfo.cpp @@ -169,15 +169,15 @@ void LLPanelPlaceInfo::displayParcelInfo(const LLUUID& region_id,  }  // virtual -void LLPanelPlaceInfo::setErrorStatus(U32 status, const std::string& reason) +void LLPanelPlaceInfo::setErrorStatus(S32 status, const std::string& reason)  {  	// We only really handle 404 and 499 errors  	std::string error_text; -	if(status == 404) +	if(status == HTTP_NOT_FOUND)  	{  		error_text = getString("server_error_text");  	} -	else if(status == 499) +	else if(status == HTTP_INTERNAL_ERROR)  	{  		error_text = getString("server_forbidden_text");  	} diff --git a/indra/newview/llpanelplaceinfo.h b/indra/newview/llpanelplaceinfo.h index 64f0b6b550..30327378ef 100755 --- a/indra/newview/llpanelplaceinfo.h +++ b/indra/newview/llpanelplaceinfo.h @@ -86,7 +86,7 @@ public:  	void displayParcelInfo(const LLUUID& region_id,  						   const LLVector3d& pos_global); -	/*virtual*/ void setErrorStatus(U32 status, const std::string& reason); +	/*virtual*/ void setErrorStatus(S32 status, const std::string& reason);  	/*virtual*/ void processParcelInfo(const LLParcelData& parcel_data); diff --git a/indra/newview/llpanelplaces.cpp b/indra/newview/llpanelplaces.cpp index c05b379fd8..2be96b9b78 100755 --- a/indra/newview/llpanelplaces.cpp +++ b/indra/newview/llpanelplaces.cpp @@ -168,8 +168,7 @@ public:  protected:  	/*virtual*/ void done()  	{ -		mPlaces->showAddedLandmarkInfo(mAdded); -		mAdded.clear(); +		mPlaces->showAddedLandmarkInfo(gInventory.getAddedIDs());  	}  private: @@ -217,7 +216,7 @@ public:  			LLRemoteParcelInfoProcessor::getInstance()->sendParcelInfoRequest(parcel_id);  		}  	} -	/*virtual*/ void setErrorStatus(U32 status, const std::string& reason) +	/*virtual*/ void setErrorStatus(S32 status, const std::string& reason)  	{  		LL_ERRS() << "Can't complete remote parcel request. Http Status: "  			   << status << ". Reason : " << reason << LL_ENDL; @@ -1100,9 +1099,9 @@ void LLPanelPlaces::changedGlobalPos(const LLVector3d &global_pos)  	updateVerbs();  } -void LLPanelPlaces::showAddedLandmarkInfo(const uuid_vec_t& items) +void LLPanelPlaces::showAddedLandmarkInfo(const uuid_set_t& items)  { -	for (uuid_vec_t::const_iterator item_iter = items.begin(); +	for (uuid_set_t::const_iterator item_iter = items.begin();  		 item_iter != items.end();  		 ++item_iter)  	{ diff --git a/indra/newview/llpanelplaces.h b/indra/newview/llpanelplaces.h index b6019ca32e..c3d1b9bc53 100755 --- a/indra/newview/llpanelplaces.h +++ b/indra/newview/llpanelplaces.h @@ -69,7 +69,7 @@ public:  	void changedGlobalPos(const LLVector3d &global_pos);  	// Opens landmark info panel when agent creates or receives landmark. -	void showAddedLandmarkInfo(const uuid_vec_t& items); +	void showAddedLandmarkInfo(const uuid_set_t& items);  	void setItem(LLInventoryItem* item); diff --git a/indra/newview/llpathfindingmanager.cpp b/indra/newview/llpathfindingmanager.cpp index ae5b3b4e76..4977a72dc6 100755 --- a/indra/newview/llpathfindingmanager.cpp +++ b/indra/newview/llpathfindingmanager.cpp @@ -103,17 +103,16 @@ LLHTTPRegistration<LLAgentStateChangeNode> gHTTPRegistrationAgentStateChangeNode  class NavMeshStatusResponder : public LLHTTPClient::Responder  { +	LOG_CLASS(NavMeshStatusResponder);  public: -	NavMeshStatusResponder(const std::string &pCapabilityURL, LLViewerRegion *pRegion, bool pIsGetStatusOnly); +	NavMeshStatusResponder(LLViewerRegion *pRegion, bool pIsGetStatusOnly);  	virtual ~NavMeshStatusResponder(); -	virtual void result(const LLSD &pContent); -	virtual void errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent); -  protected: +	virtual void httpSuccess(); +	virtual void httpFailure();  private: -	std::string    mCapabilityURL;  	LLViewerRegion *mRegion;  	LLUUID         mRegionUUID;  	bool           mIsGetStatusOnly; @@ -125,17 +124,16 @@ private:  class NavMeshResponder : public LLHTTPClient::Responder  { +    LOG_CLASS(NavMeshResponder);  public: -	NavMeshResponder(const std::string &pCapabilityURL, U32 pNavMeshVersion, LLPathfindingNavMeshPtr pNavMeshPtr); +	NavMeshResponder(U32 pNavMeshVersion, LLPathfindingNavMeshPtr pNavMeshPtr);  	virtual ~NavMeshResponder(); -	virtual void result(const LLSD &pContent); -	virtual void errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent); -  protected: +	virtual void httpSuccess(); +	virtual void httpFailure();  private: -	std::string             mCapabilityURL;  	U32                     mNavMeshVersion;  	LLPathfindingNavMeshPtr mNavMeshPtr;  }; @@ -146,17 +144,14 @@ private:  class AgentStateResponder : public LLHTTPClient::Responder  { +	LOG_CLASS(AgentStateResponder);  public: -	AgentStateResponder(const std::string &pCapabilityURL); +	AgentStateResponder();  	virtual ~AgentStateResponder(); -	virtual void result(const LLSD &pContent); -	virtual void errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent); -  protected: - -private: -	std::string mCapabilityURL; +	virtual void httpSuccess(); +	virtual void httpFailure();  }; @@ -165,17 +160,16 @@ private:  //---------------------------------------------------------------------------  class NavMeshRebakeResponder : public LLHTTPClient::Responder  { +	LOG_CLASS(NavMeshRebakeResponder);  public: -	NavMeshRebakeResponder(const std::string &pCapabilityURL, LLPathfindingManager::rebake_navmesh_callback_t pRebakeNavMeshCallback); +	NavMeshRebakeResponder(LLPathfindingManager::rebake_navmesh_callback_t pRebakeNavMeshCallback);  	virtual ~NavMeshRebakeResponder(); -	virtual void result(const LLSD &pContent); -	virtual void errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent); -  protected: +	virtual void httpSuccess(); +	virtual void httpFailure();  private: -	std::string                                     mCapabilityURL;  	LLPathfindingManager::rebake_navmesh_callback_t mRebakeNavMeshCallback;  }; @@ -190,11 +184,9 @@ public:  	virtual ~LinksetsResponder();  	void handleObjectLinksetsResult(const LLSD &pContent); -	void handleObjectLinksetsError(U32 pStatus, const std::string &pReason,  -								   const LLSD& pContent, const std::string &pURL); +	void handleObjectLinksetsError();  	void handleTerrainLinksetsResult(const LLSD &pContent); -	void handleTerrainLinksetsError(U32 pStatus, const std::string &pReason, -									const LLSD& pContent, const std::string &pURL); +	void handleTerrainLinksetsError();  protected: @@ -227,17 +219,16 @@ typedef boost::shared_ptr<LinksetsResponder> LinksetsResponderPtr;  class ObjectLinksetsResponder : public LLHTTPClient::Responder  { +	LOG_CLASS(ObjectLinksetsResponder);  public: -	ObjectLinksetsResponder(const std::string &pCapabilityURL, LinksetsResponderPtr pLinksetsResponsderPtr); +	ObjectLinksetsResponder(LinksetsResponderPtr pLinksetsResponsderPtr);  	virtual ~ObjectLinksetsResponder(); -	virtual void result(const LLSD &pContent); -	virtual void errorWithContent(U32 pStatus, const std::string &pReason, const LLSD& pContent); -  protected: +	virtual void httpSuccess(); +	virtual void httpFailure();  private: -	std::string          mCapabilityURL;  	LinksetsResponderPtr mLinksetsResponsderPtr;  }; @@ -247,17 +238,16 @@ private:  class TerrainLinksetsResponder : public LLHTTPClient::Responder  { +	LOG_CLASS(TerrainLinksetsResponder);  public: -	TerrainLinksetsResponder(const std::string &pCapabilityURL, LinksetsResponderPtr pLinksetsResponsderPtr); +	TerrainLinksetsResponder(LinksetsResponderPtr pLinksetsResponsderPtr);  	virtual ~TerrainLinksetsResponder(); -	virtual void result(const LLSD &pContent); -	virtual void errorWithContent(U32 pStatus, const std::string &pReason, const LLSD& pContent); -  protected: +	virtual void httpSuccess(); +	virtual void httpFailure();  private: -	std::string          mCapabilityURL;  	LinksetsResponderPtr mLinksetsResponsderPtr;  }; @@ -267,17 +257,16 @@ private:  class CharactersResponder : public LLHTTPClient::Responder  { +	LOG_CLASS(TerrainLinksetsResponder);  public: -	CharactersResponder(const std::string &pCapabilityURL, LLPathfindingManager::request_id_t pRequestId, LLPathfindingManager::object_request_callback_t pCharactersCallback); +	CharactersResponder(LLPathfindingManager::request_id_t pRequestId, LLPathfindingManager::object_request_callback_t pCharactersCallback);  	virtual ~CharactersResponder(); -	virtual void result(const LLSD &pContent); -	virtual void errorWithContent(U32 pStatus, const std::string &pReason, const LLSD& pContent); -  protected: +	virtual void httpSuccess(); +	virtual void httpFailure();  private: -	std::string                                     mCapabilityURL;  	LLPathfindingManager::request_id_t              mRequestId;  	LLPathfindingManager::object_request_callback_t mCharactersCallback;  }; @@ -364,7 +353,7 @@ void LLPathfindingManager::requestGetNavMeshForRegion(LLViewerRegion *pRegion, b  		std::string navMeshStatusURL = getNavMeshStatusURLForRegion(pRegion);  		llassert(!navMeshStatusURL.empty());  		navMeshPtr->handleNavMeshCheckVersion(); -		LLHTTPClient::ResponderPtr navMeshStatusResponder = new NavMeshStatusResponder(navMeshStatusURL, pRegion, pIsGetStatusOnly); +		LLHTTPClient::ResponderPtr navMeshStatusResponder = new NavMeshStatusResponder(pRegion, pIsGetStatusOnly);  		LLHTTPClient::get(navMeshStatusURL, navMeshStatusResponder);  	}  } @@ -398,12 +387,12 @@ void LLPathfindingManager::requestGetLinksets(request_id_t pRequestId, object_re  			bool doRequestTerrain = isAllowViewTerrainProperties();  			LinksetsResponderPtr linksetsResponderPtr(new LinksetsResponder(pRequestId, pLinksetsCallback, true, doRequestTerrain)); -			LLHTTPClient::ResponderPtr objectLinksetsResponder = new ObjectLinksetsResponder(objectLinksetsURL, linksetsResponderPtr); +			LLHTTPClient::ResponderPtr objectLinksetsResponder = new ObjectLinksetsResponder(linksetsResponderPtr);  			LLHTTPClient::get(objectLinksetsURL, objectLinksetsResponder);  			if (doRequestTerrain)  			{ -				LLHTTPClient::ResponderPtr terrainLinksetsResponder = new TerrainLinksetsResponder(terrainLinksetsURL, linksetsResponderPtr); +				LLHTTPClient::ResponderPtr terrainLinksetsResponder = new TerrainLinksetsResponder(linksetsResponderPtr);  				LLHTTPClient::get(terrainLinksetsURL, terrainLinksetsResponder);  			}  		} @@ -447,13 +436,13 @@ void LLPathfindingManager::requestSetLinksets(request_id_t pRequestId, const LLP  			if (!objectPostData.isUndefined())  			{ -				LLHTTPClient::ResponderPtr objectLinksetsResponder = new ObjectLinksetsResponder(objectLinksetsURL, linksetsResponderPtr); +				LLHTTPClient::ResponderPtr objectLinksetsResponder = new ObjectLinksetsResponder(linksetsResponderPtr);  				LLHTTPClient::put(objectLinksetsURL, objectPostData, objectLinksetsResponder);  			}  			if (!terrainPostData.isUndefined())  			{ -				LLHTTPClient::ResponderPtr terrainLinksetsResponder = new TerrainLinksetsResponder(terrainLinksetsURL, linksetsResponderPtr); +				LLHTTPClient::ResponderPtr terrainLinksetsResponder = new TerrainLinksetsResponder(linksetsResponderPtr);  				LLHTTPClient::put(terrainLinksetsURL, terrainPostData, terrainLinksetsResponder);  			}  		} @@ -486,7 +475,7 @@ void LLPathfindingManager::requestGetCharacters(request_id_t pRequestId, object_  		{  			pCharactersCallback(pRequestId, kRequestStarted, emptyCharacterListPtr); -			LLHTTPClient::ResponderPtr charactersResponder = new CharactersResponder(charactersURL, pRequestId, pCharactersCallback); +			LLHTTPClient::ResponderPtr charactersResponder = new CharactersResponder(pRequestId, pCharactersCallback);  			LLHTTPClient::get(charactersURL, charactersResponder);  		}  	} @@ -519,7 +508,7 @@ void LLPathfindingManager::requestGetAgentState()  		{  			std::string agentStateURL = getAgentStateURLForRegion(currentRegion);  			llassert(!agentStateURL.empty()); -			LLHTTPClient::ResponderPtr responder = new AgentStateResponder(agentStateURL); +			LLHTTPClient::ResponderPtr responder = new AgentStateResponder();  			LLHTTPClient::get(agentStateURL, responder);  		}  	} @@ -543,7 +532,7 @@ void LLPathfindingManager::requestRebakeNavMesh(rebake_navmesh_callback_t pRebak  		llassert(!navMeshStatusURL.empty());  		LLSD postData;			  		postData["command"] = "rebuild"; -		LLHTTPClient::ResponderPtr responder = new NavMeshRebakeResponder(navMeshStatusURL, pRebakeNavMeshCallback); +		LLHTTPClient::ResponderPtr responder = new NavMeshRebakeResponder(pRebakeNavMeshCallback);  		LLHTTPClient::post(navMeshStatusURL, postData, responder);  	}  } @@ -565,7 +554,7 @@ void LLPathfindingManager::sendRequestGetNavMeshForRegion(LLPathfindingNavMeshPt  		else  		{  			navMeshPtr->handleNavMeshStart(pNavMeshStatus); -			LLHTTPClient::ResponderPtr responder = new NavMeshResponder(navMeshURL, pNavMeshStatus.getVersion(), navMeshPtr); +			LLHTTPClient::ResponderPtr responder = new NavMeshResponder(pNavMeshStatus.getVersion(), navMeshPtr);  			LLSD postData;  			LLHTTPClient::post(navMeshURL, postData, responder); @@ -779,9 +768,8 @@ void LLAgentStateChangeNode::post(ResponsePtr pResponse, const LLSD &pContext, c  // NavMeshStatusResponder  //--------------------------------------------------------------------------- -NavMeshStatusResponder::NavMeshStatusResponder(const std::string &pCapabilityURL, LLViewerRegion *pRegion, bool pIsGetStatusOnly) +NavMeshStatusResponder::NavMeshStatusResponder(LLViewerRegion *pRegion, bool pIsGetStatusOnly)  	: LLHTTPClient::Responder(), -	mCapabilityURL(pCapabilityURL),  	mRegion(pRegion),  	mRegionUUID(),  	mIsGetStatusOnly(pIsGetStatusOnly) @@ -796,15 +784,15 @@ NavMeshStatusResponder::~NavMeshStatusResponder()  {  } -void NavMeshStatusResponder::result(const LLSD &pContent) +void NavMeshStatusResponder::httpSuccess()  { -	LLPathfindingNavMeshStatus navMeshStatus(mRegionUUID, pContent); +	LLPathfindingNavMeshStatus navMeshStatus(mRegionUUID, getContent());  	LLPathfindingManager::getInstance()->handleNavMeshStatusRequest(navMeshStatus, mRegion, mIsGetStatusOnly);  } -void NavMeshStatusResponder::errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent) +void NavMeshStatusResponder::httpFailure()  { -	LL_WARNS() << "NavMeshStatusResponder error [status:" << pStatus << "]: " << pContent << LL_ENDL; +	LL_WARNS() << dumpResponse() << LL_ENDL;  	LLPathfindingNavMeshStatus navMeshStatus(mRegionUUID);  	LLPathfindingManager::getInstance()->handleNavMeshStatusRequest(navMeshStatus, mRegion, mIsGetStatusOnly);  } @@ -813,9 +801,8 @@ void NavMeshStatusResponder::errorWithContent(U32 pStatus, const std::string& pR  // NavMeshResponder  //--------------------------------------------------------------------------- -NavMeshResponder::NavMeshResponder(const std::string &pCapabilityURL, U32 pNavMeshVersion, LLPathfindingNavMeshPtr pNavMeshPtr) +NavMeshResponder::NavMeshResponder(U32 pNavMeshVersion, LLPathfindingNavMeshPtr pNavMeshPtr)  	: LLHTTPClient::Responder(), -	mCapabilityURL(pCapabilityURL),  	mNavMeshVersion(pNavMeshVersion),  	mNavMeshPtr(pNavMeshPtr)  { @@ -825,23 +812,23 @@ NavMeshResponder::~NavMeshResponder()  {  } -void NavMeshResponder::result(const LLSD &pContent) +void NavMeshResponder::httpSuccess()  { -	mNavMeshPtr->handleNavMeshResult(pContent, mNavMeshVersion); +	mNavMeshPtr->handleNavMeshResult(getContent(), mNavMeshVersion);  } -void NavMeshResponder::errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent) +void NavMeshResponder::httpFailure()  { -	mNavMeshPtr->handleNavMeshError(pStatus, pReason, pContent, mCapabilityURL, mNavMeshVersion); +	LL_WARNS() << dumpResponse() << LL_ENDL; +	mNavMeshPtr->handleNavMeshError(mNavMeshVersion);  }  //---------------------------------------------------------------------------  // AgentStateResponder  //--------------------------------------------------------------------------- -AgentStateResponder::AgentStateResponder(const std::string &pCapabilityURL) +AgentStateResponder::AgentStateResponder()  : LLHTTPClient::Responder() -, mCapabilityURL(pCapabilityURL)  {  } @@ -849,17 +836,18 @@ AgentStateResponder::~AgentStateResponder()  {  } -void AgentStateResponder::result(const LLSD &pContent) +void AgentStateResponder::httpSuccess()  { +	const LLSD& pContent = getContent();  	llassert(pContent.has(AGENT_STATE_CAN_REBAKE_REGION_FIELD));  	llassert(pContent.get(AGENT_STATE_CAN_REBAKE_REGION_FIELD).isBoolean());  	BOOL canRebakeRegion = pContent.get(AGENT_STATE_CAN_REBAKE_REGION_FIELD).asBoolean();  	LLPathfindingManager::getInstance()->handleAgentState(canRebakeRegion);  } -void AgentStateResponder::errorWithContent(U32 pStatus, const std::string &pReason, const LLSD& pContent) +void AgentStateResponder::httpFailure()  { -	LL_WARNS() << "AgentStateResponder error [status:" << pStatus << "]: " << pContent << LL_ENDL; +	LL_WARNS() << dumpResponse() << LL_ENDL;  	LLPathfindingManager::getInstance()->handleAgentState(FALSE);  } @@ -867,9 +855,8 @@ void AgentStateResponder::errorWithContent(U32 pStatus, const std::string &pReas  //---------------------------------------------------------------------------  // navmesh rebake responder  //--------------------------------------------------------------------------- -NavMeshRebakeResponder::NavMeshRebakeResponder(const std::string &pCapabilityURL, LLPathfindingManager::rebake_navmesh_callback_t pRebakeNavMeshCallback) +NavMeshRebakeResponder::NavMeshRebakeResponder(LLPathfindingManager::rebake_navmesh_callback_t pRebakeNavMeshCallback)  	: LLHTTPClient::Responder(), -	mCapabilityURL(pCapabilityURL),  	mRebakeNavMeshCallback(pRebakeNavMeshCallback)  {  } @@ -878,14 +865,14 @@ NavMeshRebakeResponder::~NavMeshRebakeResponder()  {  } -void NavMeshRebakeResponder::result(const LLSD &pContent) +void NavMeshRebakeResponder::httpSuccess()  {  	mRebakeNavMeshCallback(true);  } -void NavMeshRebakeResponder::errorWithContent(U32 pStatus, const std::string &pReason, const LLSD& pContent) +void NavMeshRebakeResponder::httpFailure()  { -	LL_WARNS() << "NavMeshRebakeResponder error [status:" << pStatus << "]: " << pContent << LL_ENDL; +	LL_WARNS() << dumpResponse() << LL_ENDL;  	mRebakeNavMeshCallback(false);  } @@ -918,11 +905,9 @@ void LinksetsResponder::handleObjectLinksetsResult(const LLSD &pContent)  	}  } -void LinksetsResponder::handleObjectLinksetsError(U32 pStatus, const std::string &pReason, -												 const LLSD& pContent, const std::string &pURL) +void LinksetsResponder::handleObjectLinksetsError()  { -	LL_WARNS() << "LinksetsResponder object linksets error with request to URL '" << pURL << "' [status:" -			<< pStatus << "]: " << pContent << LL_ENDL; +	LL_WARNS() << "LinksetsResponder object linksets error" << LL_ENDL;  	mObjectMessagingState = kReceivedError;  	if (mTerrainMessagingState != kWaiting)  	{ @@ -941,11 +926,9 @@ void LinksetsResponder::handleTerrainLinksetsResult(const LLSD &pContent)  	}  } -void LinksetsResponder::handleTerrainLinksetsError(U32 pStatus, const std::string &pReason, -												   const LLSD& pContent, const std::string &pURL) +void LinksetsResponder::handleTerrainLinksetsError()  { -	LL_WARNS() << "LinksetsResponder terrain linksets error with request to URL '" << pURL << "' [status:" -			<< pStatus << "]: " << pContent << LL_ENDL; +	LL_WARNS() << "LinksetsResponder terrain linksets error" << LL_ENDL;  	mTerrainMessagingState = kReceivedError;  	if (mObjectMessagingState != kWaiting)  	{ @@ -979,9 +962,8 @@ void LinksetsResponder::sendCallback()  // ObjectLinksetsResponder  //--------------------------------------------------------------------------- -ObjectLinksetsResponder::ObjectLinksetsResponder(const std::string &pCapabilityURL, LinksetsResponderPtr pLinksetsResponsderPtr) +ObjectLinksetsResponder::ObjectLinksetsResponder(LinksetsResponderPtr pLinksetsResponsderPtr)  	: LLHTTPClient::Responder(), -	mCapabilityURL(pCapabilityURL),  	mLinksetsResponsderPtr(pLinksetsResponsderPtr)  {  } @@ -990,23 +972,23 @@ ObjectLinksetsResponder::~ObjectLinksetsResponder()  {  } -void ObjectLinksetsResponder::result(const LLSD &pContent) +void ObjectLinksetsResponder::httpSuccess()  { -	mLinksetsResponsderPtr->handleObjectLinksetsResult(pContent); +	mLinksetsResponsderPtr->handleObjectLinksetsResult(getContent());  } -void ObjectLinksetsResponder::errorWithContent(U32 pStatus, const std::string &pReason, const LLSD& pContent) +void ObjectLinksetsResponder::httpFailure()  { -	mLinksetsResponsderPtr->handleObjectLinksetsError(pStatus, pReason, pContent, mCapabilityURL); +	LL_WARNS() << dumpResponse() << LL_ENDL; +	mLinksetsResponsderPtr->handleObjectLinksetsError();  }  //---------------------------------------------------------------------------  // TerrainLinksetsResponder  //--------------------------------------------------------------------------- -TerrainLinksetsResponder::TerrainLinksetsResponder(const std::string &pCapabilityURL, LinksetsResponderPtr pLinksetsResponsderPtr) +TerrainLinksetsResponder::TerrainLinksetsResponder(LinksetsResponderPtr pLinksetsResponsderPtr)  	: LLHTTPClient::Responder(), -	mCapabilityURL(pCapabilityURL),  	mLinksetsResponsderPtr(pLinksetsResponsderPtr)  {  } @@ -1015,23 +997,23 @@ TerrainLinksetsResponder::~TerrainLinksetsResponder()  {  } -void TerrainLinksetsResponder::result(const LLSD &pContent) +void TerrainLinksetsResponder::httpSuccess()  { -	mLinksetsResponsderPtr->handleTerrainLinksetsResult(pContent); +	mLinksetsResponsderPtr->handleTerrainLinksetsResult(getContent());  } -void TerrainLinksetsResponder::errorWithContent(U32 pStatus, const std::string &pReason, const LLSD& pContent) +void TerrainLinksetsResponder::httpFailure()  { -	mLinksetsResponsderPtr->handleTerrainLinksetsError(pStatus, pReason, pContent, mCapabilityURL); +	LL_WARNS() << dumpResponse() << LL_ENDL; +	mLinksetsResponsderPtr->handleTerrainLinksetsError();  }  //---------------------------------------------------------------------------  // CharactersResponder  //--------------------------------------------------------------------------- -CharactersResponder::CharactersResponder(const std::string &pCapabilityURL, LLPathfindingManager::request_id_t pRequestId, LLPathfindingManager::object_request_callback_t pCharactersCallback) +CharactersResponder::CharactersResponder(LLPathfindingManager::request_id_t pRequestId, LLPathfindingManager::object_request_callback_t pCharactersCallback)  	: LLHTTPClient::Responder(), -	mCapabilityURL(pCapabilityURL),  	mRequestId(pRequestId),  	mCharactersCallback(pCharactersCallback)  { @@ -1041,15 +1023,15 @@ CharactersResponder::~CharactersResponder()  {  } -void CharactersResponder::result(const LLSD &pContent) +void CharactersResponder::httpSuccess()  { -	LLPathfindingObjectListPtr characterListPtr = LLPathfindingObjectListPtr(new LLPathfindingCharacterList(pContent)); +	LLPathfindingObjectListPtr characterListPtr = LLPathfindingObjectListPtr(new LLPathfindingCharacterList(getContent()));  	mCharactersCallback(mRequestId, LLPathfindingManager::kRequestCompleted, characterListPtr);  } -void CharactersResponder::errorWithContent(U32 pStatus, const std::string &pReason, const LLSD& pContent) +void CharactersResponder::httpFailure()  { -	LL_WARNS() << "CharactersResponder error [status:" << pStatus << "]: " << pContent << LL_ENDL; +	LL_WARNS() << dumpResponse() << LL_ENDL;  	LLPathfindingObjectListPtr characterListPtr =  LLPathfindingObjectListPtr(new LLPathfindingCharacterList());  	mCharactersCallback(mRequestId, LLPathfindingManager::kRequestError, characterListPtr); diff --git a/indra/newview/llpathfindingnavmesh.cpp b/indra/newview/llpathfindingnavmesh.cpp index 40f5d8c23e..0287c07f96 100755 --- a/indra/newview/llpathfindingnavmesh.cpp +++ b/indra/newview/llpathfindingnavmesh.cpp @@ -184,10 +184,8 @@ void LLPathfindingNavMesh::handleNavMeshError()  	setRequestStatus(kNavMeshRequestError);  } -void LLPathfindingNavMesh::handleNavMeshError(U32 pStatus, const std::string &pReason, const LLSD& pContent, const std::string &pURL, U32 pNavMeshVersion) +void LLPathfindingNavMesh::handleNavMeshError(U32 pNavMeshVersion)  { -	LL_WARNS() << "LLPathfindingNavMesh error with request to URL '" << pURL << "' [status:" -			<< pStatus << "]: " << pContent << LL_ENDL;  	if (mNavMeshStatus.getVersion() == pNavMeshVersion)  	{  		handleNavMeshError(); diff --git a/indra/newview/llpathfindingnavmesh.h b/indra/newview/llpathfindingnavmesh.h index b872ccad7c..87f32b8d56 100755 --- a/indra/newview/llpathfindingnavmesh.h +++ b/indra/newview/llpathfindingnavmesh.h @@ -74,7 +74,7 @@ public:  	void handleNavMeshResult(const LLSD &pContent, U32 pNavMeshVersion);  	void handleNavMeshNotEnabled();  	void handleNavMeshError(); -	void handleNavMeshError(U32 pStatus, const std::string &pReason, const LLSD& pContent, const std::string &pURL, U32 pNavMeshVersion); +	void handleNavMeshError(U32 pNavMeshVersion);  protected: diff --git a/indra/newview/llphysicsmotion.cpp b/indra/newview/llphysicsmotion.cpp index 05ef436bd9..ea10d03264 100755 --- a/indra/newview/llphysicsmotion.cpp +++ b/indra/newview/llphysicsmotion.cpp @@ -668,9 +668,7 @@ BOOL LLPhysicsMotion::onUpdate(F32 time)  			if ((driver_param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE) &&  			    (driver_param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT))  			{ -				mCharacter->setVisualParamWeight(driver_param, -								 0, -								 FALSE); +				mCharacter->setVisualParamWeight(driver_param, 0);  			}  			S32 num_driven = driver_param->getDrivenParamsCount();  			for (S32 i = 0; i < num_driven; ++i) @@ -770,7 +768,5 @@ void LLPhysicsMotion::setParamValue(const LLViewerVisualParam *param,  	// Scale from [0,1] to [value_min_local,value_max_local]          const F32 new_value_local = value_min_local + (value_max_local-value_min_local) * new_value_rescaled; -        mCharacter->setVisualParamWeight(param, -                                         new_value_local, -                                         FALSE); +        mCharacter->setVisualParamWeight(param, new_value_local);  } diff --git a/indra/newview/llpreview.cpp b/indra/newview/llpreview.cpp index b379ef7bdb..6d032ad3d3 100755 --- a/indra/newview/llpreview.cpp +++ b/indra/newview/llpreview.cpp @@ -400,13 +400,6 @@ void LLPreview::onDiscardBtn(void* data)  	self->mForceClose = TRUE;  	self->closeFloater(); -	// Delete the item entirely -	/* -	item->removeFromServer(); -	gInventory.deleteObject(item->getUUID()); -	gInventory.notifyObservers(); -	*/ -  	// Move the item to the trash  	const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);  	if (item->getParentUUID() != trash_id) diff --git a/indra/newview/llproductinforequest.cpp b/indra/newview/llproductinforequest.cpp index e85194d173..e92bf4590d 100755 --- a/indra/newview/llproductinforequest.cpp +++ b/indra/newview/llproductinforequest.cpp @@ -35,18 +35,24 @@  class LLProductInfoRequestResponder : public LLHTTPClient::Responder  { -public: +	LOG_CLASS(LLProductInfoRequestResponder); +private:  	//If we get back a normal response, handle it here -	virtual void result(const LLSD& content) +	/* virtual */ void httpSuccess()  	{ -		LLProductInfoRequestManager::instance().setSkuDescriptions(content); +		const LLSD& content = getContent(); +		if (!content.isArray()) +		{ +			failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); +			return; +		} +		LLProductInfoRequestManager::instance().setSkuDescriptions(getContent());  	}  	//If we get back an error (not found, etc...), handle it here -	virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content) +	/* virtual */ void httpFailure()  	{ -		LL_WARNS() << "LLProductInfoRequest error [status:" -				<< status << ":] " << content << LL_ENDL; +		LL_WARNS() << dumpResponse() << LL_ENDL;  	}  }; diff --git a/indra/newview/llremoteparcelrequest.cpp b/indra/newview/llremoteparcelrequest.cpp index 13120fdf45..29dcc12f9e 100755 --- a/indra/newview/llremoteparcelrequest.cpp +++ b/indra/newview/llremoteparcelrequest.cpp @@ -47,9 +47,15 @@ LLRemoteParcelRequestResponder::LLRemoteParcelRequestResponder(LLHandle<LLRemote  //If we get back a normal response, handle it here  //virtual -void LLRemoteParcelRequestResponder::result(const LLSD& content) +void LLRemoteParcelRequestResponder::httpSuccess()  { -	LLUUID parcel_id = content["parcel_id"]; +	const LLSD& content = getContent(); +	if (!content.isMap() || !content.has("parcel_id")) +	{ +		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); +		return; +	} +	LLUUID parcel_id = getContent()["parcel_id"];  	// Panel inspecting the information may be closed and destroyed  	// before this response is received. @@ -62,17 +68,16 @@ void LLRemoteParcelRequestResponder::result(const LLSD& content)  //If we get back an error (not found, etc...), handle it here  //virtual -void LLRemoteParcelRequestResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void LLRemoteParcelRequestResponder::httpFailure()  { -	LL_WARNS() << "LLRemoteParcelRequest error [status:" -			<< status << "]: " << content << LL_ENDL; +	LL_WARNS() << dumpResponse() << LL_ENDL;  	// Panel inspecting the information may be closed and destroyed  	// before this response is received.  	LLRemoteParcelInfoObserver* observer = mObserverHandle.get();  	if (observer)  	{ -		observer->setErrorStatus(status, reason); +		observer->setErrorStatus(getStatus(), getReason());  	}  } diff --git a/indra/newview/llremoteparcelrequest.h b/indra/newview/llremoteparcelrequest.h index e4b8791f7c..35348b69ff 100755 --- a/indra/newview/llremoteparcelrequest.h +++ b/indra/newview/llremoteparcelrequest.h @@ -38,16 +38,17 @@ class LLRemoteParcelInfoObserver;  class LLRemoteParcelRequestResponder : public LLHTTPClient::Responder  { +	LOG_CLASS(LLRemoteParcelRequestResponder);  public:  	LLRemoteParcelRequestResponder(LLHandle<LLRemoteParcelInfoObserver> observer_handle); +private:  	//If we get back a normal response, handle it here -	/*virtual*/ void result(const LLSD& content); +	/*virtual*/ void httpSuccess();  	//If we get back an error (not found, etc...), handle it here -	/*virtual*/ void errorWithContent(U32 status, const std::string& reason, const LLSD& content); +	/*virtual*/ void httpFailure(); -protected:  	LLHandle<LLRemoteParcelInfoObserver> mObserverHandle;  }; @@ -79,7 +80,7 @@ public:  	virtual ~LLRemoteParcelInfoObserver() {}  	virtual void processParcelInfo(const LLParcelData& parcel_data) = 0;  	virtual void setParcelID(const LLUUID& parcel_id) = 0; -	virtual void setErrorStatus(U32 status, const std::string& reason) = 0; +	virtual void setErrorStatus(S32 status, const std::string& reason) = 0;  	LLHandle<LLRemoteParcelInfoObserver>	getObserverHandle() const { return mObserverHandle; }  protected: diff --git a/indra/newview/llscrollingpanelparam.cpp b/indra/newview/llscrollingpanelparam.cpp index a7e24b86b1..bfa453a0ae 100755 --- a/indra/newview/llscrollingpanelparam.cpp +++ b/indra/newview/llscrollingpanelparam.cpp @@ -266,7 +266,7 @@ void LLScrollingPanelParam::onHintHeldDown( LLVisualParamHint* hint )  			if (slider->getMinValue() < new_percent  				&& new_percent < slider->getMaxValue())  			{ -				mWearable->setVisualParamWeight( hint->getVisualParam()->getID(), new_weight, FALSE); +				mWearable->setVisualParamWeight( hint->getVisualParam()->getID(), new_weight);  				mWearable->writeToAvatar(gAgentAvatarp);  				gAgentAvatarp->updateVisualParams(); @@ -299,7 +299,7 @@ void LLScrollingPanelParam::onHintMinMouseUp( void* userdata )  			if (slider->getMinValue() < new_percent  				&& new_percent < slider->getMaxValue())  			{ -				self->mWearable->setVisualParamWeight(hint->getVisualParam()->getID(), new_weight, FALSE); +				self->mWearable->setVisualParamWeight(hint->getVisualParam()->getID(), new_weight);  				self->mWearable->writeToAvatar(gAgentAvatarp);  				slider->setValue( self->weightToPercent( new_weight ) );  			} @@ -333,7 +333,7 @@ void LLScrollingPanelParam::onHintMaxMouseUp( void* userdata )  				if (slider->getMinValue() < new_percent  					&& new_percent < slider->getMaxValue())  				{ -					self->mWearable->setVisualParamWeight(hint->getVisualParam()->getID(), new_weight, FALSE); +					self->mWearable->setVisualParamWeight(hint->getVisualParam()->getID(), new_weight);  					self->mWearable->writeToAvatar(gAgentAvatarp);  					slider->setValue( self->weightToPercent( new_weight ) );  				} diff --git a/indra/newview/llscrollingpanelparambase.cpp b/indra/newview/llscrollingpanelparambase.cpp index 8e083ddb6c..fe7a362723 100755 --- a/indra/newview/llscrollingpanelparambase.cpp +++ b/indra/newview/llscrollingpanelparambase.cpp @@ -93,7 +93,7 @@ void LLScrollingPanelParamBase::onSliderMoved(LLUICtrl* ctrl, void* userdata)  	F32 new_weight = self->percentToWeight( (F32)slider->getValue().asReal() );  	if (current_weight != new_weight )  	{ -		self->mWearable->setVisualParamWeight( param->getID(), new_weight, FALSE ); +		self->mWearable->setVisualParamWeight( param->getID(), new_weight);  		self->mWearable->writeToAvatar(gAgentAvatarp);  		gAgentAvatarp->updateVisualParams();  	} diff --git a/indra/newview/llsidepanelappearance.cpp b/indra/newview/llsidepanelappearance.cpp index c938a478f7..64f24cd291 100755 --- a/indra/newview/llsidepanelappearance.cpp +++ b/indra/newview/llsidepanelappearance.cpp @@ -452,7 +452,7 @@ void LLSidepanelAppearance::editWearable(LLViewerWearable *wearable, LLView *dat  	LLFloaterSidePanelContainer::showPanel("appearance", LLSD());  	LLSidepanelAppearance *panel = dynamic_cast<LLSidepanelAppearance*>(data);  	if (panel) -	{ +	{	  		panel->showWearableEditPanel(wearable, disable_camera_switch);  	}  } diff --git a/indra/newview/llspeakers.cpp b/indra/newview/llspeakers.cpp index f25076d47e..89302c3c64 100755 --- a/indra/newview/llspeakers.cpp +++ b/indra/newview/llspeakers.cpp @@ -270,21 +270,23 @@ bool LLSpeakersDelayActionsStorage::isTimerStarted(const LLUUID& speaker_id)  class ModerationResponder : public LLHTTPClient::Responder  { +	LOG_CLASS(ModerationResponder);  public:  	ModerationResponder(const LLUUID& session_id)  	{  		mSessionID = session_id;  	} -	virtual void error(U32 status, const std::string& reason) +protected: +	virtual void httpFailure()  	{ -		LL_WARNS() << status << ": " << reason << LL_ENDL; +		LL_WARNS() << dumpResponse() << LL_ENDL;  		if ( gIMMgr )  		{  			//403 == you're not a mod  			//should be disabled if you're not a moderator -			if ( 403 == status ) +			if ( HTTP_FORBIDDEN == getStatus() )  			{  				gIMMgr->showSessionEventError(  											  "mute", @@ -855,10 +857,7 @@ void LLIMSpeakerMgr::updateSpeakers(const LLSD& update)  		}  	}  } -/*prep# -	virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content) -		LL_WARNS() << "ModerationResponder error [status:" << status << "]: " << content << LL_ENDL; -		*/ +  void LLIMSpeakerMgr::toggleAllowTextChat(const LLUUID& speaker_id)  {  	LLPointer<LLSpeaker> speakerp = findSpeaker(speaker_id); diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index a76b4bbe09..56fac3b092 100755 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -311,6 +311,12 @@ void update_texture_fetch()  	gTextureList.updateImages(0.10f);  } +void set_flags_and_update_appearance() +{ +	LLAppearanceMgr::instance().setAttachmentInvLinkEnable(true); +	LLAppearanceMgr::instance().updateAppearanceFromCOF(true, true, no_op); +} +  // Returns false to skip other idle processing. Should only return  // true when all initialization done.  bool idle_startup() @@ -1287,6 +1293,8 @@ bool idle_startup()  		LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(gFirstSimHandle);  		LL_INFOS("AppInit") << "Adding initial simulator " << regionp->getOriginGlobal() << LL_ENDL; +		LL_DEBUGS("CrossingCaps") << "Calling setSeedCapability from init_idle(). Seed cap == " +		<< gFirstSimSeedCap << LL_ENDL;  		regionp->setSeedCapability(gFirstSimSeedCap);  		LL_DEBUGS("AppInit") << "Waiting for seed grant ...." << LL_ENDL;  		display_startup(); @@ -1771,6 +1779,15 @@ bool idle_startup()  		// This method MUST be called before gInventory.findCategoryUUIDForType because of   		// gInventory.mIsAgentInvUsable is set to true in the gInventory.buildParentChildMap.  		gInventory.buildParentChildMap(); +		gInventory.createCommonSystemCategories(); + +		// It's debatable whether this flag is a good idea - sets all +		// bits, and in general it isn't true that inventory +		// initialization generates all types of changes. Maybe add an +		// INITIALIZE mask bit instead? +		gInventory.addChangedMask(LLInventoryObserver::ALL, LLUUID::null); +		gInventory.notifyObservers(); +		  		display_startup();  		//all categories loaded. lets create "My Favorites" category @@ -2018,7 +2035,7 @@ bool idle_startup()  	{  		display_startup();  		F32 timeout_frac = timeout.getElapsedTimeF32()/PRECACHING_DELAY; - +		  		// We now have an inventory skeleton, so if this is a user's first  		// login, we can start setting up their clothing and avatar   		// appearance.  This helps to avoid the generic "Ruth" avatar in @@ -2027,18 +2044,38 @@ bool idle_startup()  			&& !sInitialOutfit.empty()    // registration set up an outfit  			&& !sInitialOutfitGender.empty() // and a gender  			&& isAgentAvatarValid()	  // can't wear clothes without object -			&& !gAgent.isGenderChosen() ) // nothing already loading +			&& !gAgent.isOutfitChosen()) // nothing already loading  		{  			// Start loading the wearables, textures, gestures  			LLStartUp::loadInitialOutfit( sInitialOutfit, sInitialOutfitGender );  		} +		// If not first login, we need to fetch COF contents and +		// compute appearance from that. +		if (isAgentAvatarValid() && !gAgent.isFirstLogin() && !gAgent.isOutfitChosen()) +		{ +			gAgentWearables.notifyLoadingStarted(); +			gAgent.setOutfitChosen(TRUE); +			gAgentWearables.sendDummyAgentWearablesUpdate(); +			callAfterCategoryFetch(LLAppearanceMgr::instance().getCOF(), set_flags_and_update_appearance); +		}  		display_startup();  		// wait precache-delay and for agent's avatar or a lot longer. -		if(((timeout_frac > 1.f) && isAgentAvatarValid()) -		   || (timeout_frac > 3.f)) +		if ((timeout_frac > 1.f) && isAgentAvatarValid()) +		{ +			LLStartUp::setStartupState( STATE_WEARABLES_WAIT ); +		} +		else if (timeout_frac > 10.f)   		{ +			// If we exceed the wait above while isAgentAvatarValid is +			// not true yet, we will change startup state and +			// eventually (once avatar does get created) wind up at +			// the gender chooser. This should occur only in very +			// unusual circumstances, so set the timeout fairly high +			// to minimize mistaken hits here. +			LL_WARNS() << "Wait for valid avatar state exceeded "  +					<< timeout.getElapsedTimeF32() << " will invoke gender chooser" << LL_ENDL;   			LLStartUp::setStartupState( STATE_WEARABLES_WAIT );  		}  		else @@ -2060,12 +2097,11 @@ bool idle_startup()  		const F32 wearables_time = wearables_timer.getElapsedTimeF32();  		static LLCachedControl<F32> max_wearables_time(gSavedSettings, "ClothingLoadingDelay"); -		display_startup(); -		if (!gAgent.isGenderChosen() && isAgentAvatarValid()) +		if (!gAgent.isOutfitChosen() && isAgentAvatarValid())  		{ -			// No point in waiting for clothing, we don't even -			// know what gender we are.  Pop a dialog to ask and -			// proceed to draw the world. JC +			// No point in waiting for clothing, we don't even know +			// what outfit we want.  Pop up a gender chooser dialog to +			// ask and proceed to draw the world. JC  			//  			// *NOTE: We might hit this case even if we have an  			// initial outfit, but if the load hasn't started @@ -2075,7 +2111,10 @@ bool idle_startup()  				callback_choose_gender);  			LLStartUp::setStartupState( STATE_CLEANUP );  		} -		else if (wearables_time >= max_wearables_time()) +		 +		display_startup(); + +		if (gAgent.isOutfitChosen() && (wearables_time > max_wearables_time))  		{  			LLNotificationsUtil::add("ClothingLoading");  			record(LLStatViewer::LOADING_WEARABLES_LONG_DELAY, wearables_time); @@ -2086,25 +2125,24 @@ bool idle_startup()  				&& gAgentAvatarp->isFullyLoaded())  		{  			// wait for avatar to be completely loaded -			//LL_INFOS() << "avatar fully loaded" << LL_ENDL; -			LLStartUp::setStartupState( STATE_CLEANUP ); -		} -		// OK to just get the wearables -		else if (!gAgent.isFirstLogin() && gAgentWearables.areWearablesLoaded() ) -		{ -			// We have our clothing, proceed. -			//LL_INFOS() << "wearables loaded" << LL_ENDL; -			LLStartUp::setStartupState( STATE_CLEANUP ); +			if (isAgentAvatarValid() +				&& gAgentAvatarp->isFullyLoaded()) +			{ +				LL_DEBUGS("Avatar") << "avatar fully loaded" << LL_ENDL; +				LLStartUp::setStartupState( STATE_CLEANUP ); +				return TRUE; +			}  		}  		else  		{ -			display_startup(); -			update_texture_fetch(); -			display_startup(); -			set_startup_status(0.9f + 0.1f * wearables_time / max_wearables_time(), -				LLTrans::getString("LoginDownloadingClothing").c_str(), -				gAgent.mMOTD.c_str()); -			display_startup(); +			// OK to just get the wearables +			if ( gAgentWearables.areWearablesLoaded() ) +			{ +				// We have our clothing, proceed. +				LL_DEBUGS("Avatar") << "wearables loaded" << LL_ENDL; +				LLStartUp::setStartupState( STATE_CLEANUP ); +				return TRUE; +			}  		}  		//fall through this frame to STATE_CLEANUP  	} @@ -2351,8 +2389,6 @@ void register_viewer_callbacks(LLMessageSystem* msg)  	msg->setHandlerFuncFast(_PREHASH_RemoveNameValuePair,	process_remove_name_value);  	msg->setHandlerFuncFast(_PREHASH_AvatarAnimation,		process_avatar_animation);  	msg->setHandlerFuncFast(_PREHASH_AvatarAppearance,		process_avatar_appearance); -	msg->setHandlerFunc("AgentCachedTextureResponse",	LLAgent::processAgentCachedTextureResponse); -	msg->setHandlerFunc("RebakeAvatarTextures", LLVOAvatarSelf::processRebakeAvatarTextures);  	msg->setHandlerFuncFast(_PREHASH_CameraConstraint,		process_camera_constraint);  	msg->setHandlerFuncFast(_PREHASH_AvatarSitResponse,		process_avatar_sit_response);  	msg->setHandlerFunc("SetFollowCamProperties",			process_set_follow_cam_properties); @@ -2426,9 +2462,6 @@ void register_viewer_callbacks(LLMessageSystem* msg)  	// msg->setHandlerFuncFast(_PREHASH_ReputationIndividualReply,  	//					LLFloaterRate::processReputationIndividualReply); -	msg->setHandlerFuncFast(_PREHASH_AgentWearablesUpdate, -						LLAgentWearables::processAgentInitialWearablesUpdate ); -  	msg->setHandlerFunc("ScriptControlChange",  						LLAgent::processScriptControlChange ); @@ -2585,9 +2618,8 @@ void LLStartUp::loadInitialOutfit( const std::string& outfit_folder_name,  		LL_DEBUGS() << "initial outfit category id: " << cat_id << LL_ENDL;  	} -	// This is really misnamed -- it means we have started loading -	// an outfit/shape that will give the avatar a gender eventually. JC -	gAgent.setGenderChosen(TRUE); +	gAgent.setOutfitChosen(TRUE); +	gAgentWearables.sendDummyAgentWearablesUpdate();  }  //static @@ -2600,10 +2632,10 @@ void LLStartUp::saveInitialOutfit()  	if (sWearablesLoadedCon.connected())  	{ -		LL_DEBUGS() << "sWearablesLoadedCon is connected, disconnecting" << LL_ENDL; +		LL_DEBUGS("Avatar") << "sWearablesLoadedCon is connected, disconnecting" << LL_ENDL;  		sWearablesLoadedCon.disconnect();  	} -	LL_DEBUGS() << "calling makeNewOutfitLinks( \"" << sInitialOutfit << "\" )" << LL_ENDL; +	LL_DEBUGS("Avatar") << "calling makeNewOutfitLinks( \"" << sInitialOutfit << "\" )" << LL_ENDL;  	LLAppearanceMgr::getInstance()->makeNewOutfitLinks(sInitialOutfit,false);  } @@ -3348,7 +3380,11 @@ bool process_login_success_response()  		flag = login_flags["gendered"].asString();  		if(flag == "Y")  		{ -			gAgent.setGenderChosen(TRUE); +			// We don't care about this flag anymore; now base whether +			// outfit is chosen on COF contents, initial outfit +			// requested and available, etc. + +			//gAgent.setGenderChosen(TRUE);  		}  		bool pacific_daylight_time = false; diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index 2acd38b753..14a42dd8dc 100755 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -36,7 +36,7 @@  #include "lldir.h"  #include "llhttpclient.h" -#include "llhttpstatuscodes.h" +#include "llhttpconstants.h"  #include "llimage.h"  #include "llimagej2c.h"  #include "llimageworker.h" @@ -64,6 +64,8 @@  #include "bufferarray.h"  #include "bufferstream.h" +#include "llhttpretrypolicy.h" +  bool LLTextureFetchDebugger::sDebuggerEnabled = false ;  LLTrace::EventStatHandle<LLUnit<F32, LLUnits::Percent> > LLTextureFetch::sCacheHitRate("texture_cache_hits");  LLTrace::EventStatHandle<F64Milliseconds > LLTextureFetch::sCacheReadLatency("texture_cache_read_latency"); @@ -245,6 +247,25 @@ static const S32 HTTP_REQUESTS_IN_QUEUE_LOW_WATER = 20;			// Active level at whi  ////////////////////////////////////////////////////////////////////////////// +static const char* e_state_name[] = +{ +	"INVALID", +	"INIT", +	"LOAD_FROM_TEXTURE_CACHE", +	"CACHE_POST", +	"LOAD_FROM_NETWORK", +	"LOAD_FROM_SIMULATOR", +	"WAIT_HTTP_RESOURCE", +	"WAIT_HTTP_RESOURCE2", +	"SEND_HTTP_REQ", +	"WAIT_HTTP_REQ", +	"DECODE_IMAGE", +	"DECODE_IMAGE_UPDATE", +	"WRITE_TO_CACHE", +	"WAIT_ON_WRITE", +	"DONE" +}; +  class LLTextureFetchWorker : public LLWorkerClass, public LLCore::HttpHandler  { @@ -383,12 +404,14 @@ public:  	void setCanUseHTTP(bool can_use_http) { mCanUseHTTP = can_use_http; }  	bool getCanUseHTTP() const { return mCanUseHTTP; } +	void setUrl(const std::string& url) { mUrl = url; } +  	LLTextureFetch & getFetcher() { return *mFetcher; }  	// Inherited from LLCore::HttpHandler  	// Threads:  Ttf  	virtual void onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response); -	 +  protected:  	LLTextureFetchWorker(LLTextureFetch* fetcher, FTType f_type,  						 const std::string& url, const LLUUID& id, const LLHost& host, @@ -549,6 +572,8 @@ private:  	S32 mActiveCount;  	LLCore::HttpStatus mGetStatus;  	std::string mGetReason; +	LLAdaptiveRetryPolicy mFetchRetryPolicy; +  	// Work Data  	LLMutex mWorkMutex; @@ -894,7 +919,8 @@ LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher,  	  mHttpHasResource(false),  	  mCacheReadCount(0U),  	  mCacheWriteCount(0U), -	  mResourceWaitCount(0U) +	  mResourceWaitCount(0U), +	  mFetchRetryPolicy(10.0,3600.0,2.0,10)  {  	mCanUseNET = mUrl.empty() ; @@ -1153,6 +1179,7 @@ bool LLTextureFetchWorker::doWork(S32 param)  		mDesiredSize = llmax(mDesiredSize, TEXTURE_CACHE_ENTRY_SIZE); // min desired size is TEXTURE_CACHE_ENTRY_SIZE  		LL_DEBUGS("Texture") << mID << ": Priority: " << llformat("%8.0f",mImagePriority)  							 << " Desired Discard: " << mDesiredDiscard << " Desired Size: " << mDesiredSize << LL_ENDL; +  		// fall through  	} @@ -1183,9 +1210,7 @@ bool LLTextureFetchWorker::doWork(S32 param)  																		  offset, size, responder);  				mCacheReadTimer.reset();  			} -/* SH-3980 - disabling caching of server bakes until we can fix the blurring problems */ -/*			else if ((mUrl.empty()||mFTType==FTT_SERVER_BAKE) && mFetcher->canLoadFromCache()) */ -			else if (mUrl.empty() && mFetcher->canLoadFromCache()) +			else if ((mUrl.empty() || mFTType==FTT_SERVER_BAKE) && mFetcher->canLoadFromCache())  			{  				setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it @@ -1275,6 +1300,21 @@ bool LLTextureFetchWorker::doWork(S32 param)  	if (mState == LOAD_FROM_NETWORK)  	{ +		// Check for retries to previous server failures. +		F32 wait_seconds; +		if (mFetchRetryPolicy.shouldRetry(wait_seconds)) +		{ +			if (wait_seconds <= 0.0) +			{ +				LL_INFOS() << mID << " retrying now" << LL_ENDL; +			} +			else +			{ +				//LL_INFOS() << mID << " waiting to retry for " << wait_seconds << " seconds" << LL_ENDL; +				return false; +			} +		} +  		static LLCachedControl<bool> use_http(gSavedSettings,"ImagePipelineUseHTTP", true);  // 		if (mHost != LLHost::invalid) get_url = false; @@ -1291,7 +1331,11 @@ bool LLTextureFetchWorker::doWork(S32 param)  				std::string http_url = region->getHttpUrl() ;  				if (!http_url.empty())  				{ -					mUrl = http_url + "/?texture_id=" + mID.asString().c_str(); +					if (mFTType != FTT_DEFAULT) +					{ +						LL_WARNS() << "trying to seek a non-default texture on the sim. Bad!" << LL_ENDL; +					} +					setUrl(http_url + "/?texture_id=" + mID.asString().c_str());  					mWriteToCacheState = CAN_WRITE ; //because this texture has a fixed texture id.  				}  				else @@ -1306,12 +1350,11 @@ bool LLTextureFetchWorker::doWork(S32 param)  				mCanUseHTTP = false;  			}  		} -#if 0 /* SH-3980 - disabling caching of server bakes until we can fix the blurring problems */ -		if (mFTType == FTT_SERVER_BAKE) +		else if (mFTType == FTT_SERVER_BAKE)  		{  			mWriteToCacheState = CAN_WRITE;  		} -#endif +  		if (mCanUseHTTP && !mUrl.empty())  		{  			setState(WAIT_HTTP_RESOURCE); @@ -1345,7 +1388,6 @@ bool LLTextureFetchWorker::doWork(S32 param)  			//recordTextureStart(false);  			//setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); -			LL_DEBUGS("Texture") << mID << " does this happen?" << LL_ENDL;  			return false;  		}  	} @@ -1487,12 +1529,14 @@ bool LLTextureFetchWorker::doWork(S32 param)  								 << LL_ENDL;  			// Will call callbackHttpGet when curl request completes +			// Only server bake images use the returned headers currently, for getting retry-after field. +			LLCore::HttpOptions *options = (mFTType == FTT_SERVER_BAKE) ? mFetcher->mHttpOptionsWithHeaders: mFetcher->mHttpOptions;  			mHttpHandle = mFetcher->mHttpRequest->requestGetByteRange(mHttpPolicyClass,  																	  mWorkPriority,  																	  mUrl,  																	  mRequestedOffset,  																	  mRequestedSize, -																	  mFetcher->mHttpOptions, +																	  options,  																	  mFetcher->mHttpHeaders,  																	  this);  		} @@ -1524,16 +1568,22 @@ bool LLTextureFetchWorker::doWork(S32 param)  			{  				if (http_not_found == mGetStatus)  				{ -					if(mWriteToCacheState == NOT_WRITE) //map tiles +					if (mFTType != FTT_MAP_TILE) +					{ +						LL_WARNS() << "Texture missing from server (404): " << mUrl << LL_ENDL; +					} + +					if(mWriteToCacheState == NOT_WRITE) //map tiles or server bakes  					{  						setState(DONE);  						releaseHttpSemaphore(); -						LL_DEBUGS("Texture") << mID << " abort: WAIT_HTTP_REQ not found" << LL_ENDL; -						return true; // failed, means no map tile on the empty region. +						if (mFTType != FTT_MAP_TILE) +						{ +							LL_WARNS("Texture") << mID << " abort: WAIT_HTTP_REQ not found" << LL_ENDL; +						} +						return true;   					} -					LL_WARNS() << "Texture missing from server (404): " << mUrl << LL_ENDL; -  					// roll back to try UDP  					if (mCanUseNET)  					{ @@ -1548,6 +1598,10 @@ bool LLTextureFetchWorker::doWork(S32 param)  				else if (http_service_unavail == mGetStatus)  				{  					LL_INFOS_ONCE("Texture") << "Texture server busy (503): " << mUrl << LL_ENDL; +					LL_INFOS() << "503: HTTP GET failed for: " << mUrl +							<< " Status: " << mGetStatus.toHex() +							<< " Reason: '" << mGetReason << "'" +							<< LL_ENDL;  				}  				else if (http_not_sat == mGetStatus)  				{ @@ -1562,7 +1616,10 @@ bool LLTextureFetchWorker::doWork(S32 param)  							<< LL_ENDL;  				} -				mUrl.clear(); +				if (mFTType != FTT_SERVER_BAKE) +				{ +					mUrl.clear(); +				}  				if (cur_size > 0)  				{  					// Use available data @@ -1589,7 +1646,7 @@ bool LLTextureFetchWorker::doWork(S32 param)  			// Clear the url since we're done with the fetch  			// Note: mUrl is used to check is fetching is required so failure to clear it will force an http fetch  			// next time the texture is requested, even if the data have already been fetched. -			if(mWriteToCacheState != NOT_WRITE) +			if(mWriteToCacheState != NOT_WRITE && mFTType != FTT_SERVER_BAKE)  			{  				// Why do we want to keep url if NOT_WRITE - is this a proxy for map tiles?  				mUrl.clear(); @@ -1768,7 +1825,7 @@ bool LLTextureFetchWorker::doWork(S32 param)  				if (mCachedSize > 0 && !mInLocalCache && mRetryAttempt == 0)  				{  					// Cache file should be deleted, try again -// 					LL_WARNS() << mID << ": Decode of cached file failed (removed), retrying" << LL_ENDL; + 					LL_WARNS() << mID << ": Decode of cached file failed (removed), retrying" << LL_ENDL;  					llassert_always(mDecodeHandle == 0);  					mFormattedImage = NULL;  					++mRetryAttempt; @@ -1895,14 +1952,48 @@ void LLTextureFetchWorker::onCompleted(LLCore::HttpHandle handle, LLCore::HttpRe  		mFetcher->mTextureInfo.setRequestCompleteTimeAndLog(mID, LLTimer::getTotalTime());  	} +	static LLCachedControl<F32> fake_failure_rate(gSavedSettings, "TextureFetchFakeFailureRate", 0.0f); +	F32 rand_val = ll_frand(); +	F32 rate = fake_failure_rate; +	if (mFTType == FTT_SERVER_BAKE && (fake_failure_rate > 0.0) && (rand_val < fake_failure_rate)) +	{ +		LL_WARNS() << mID << " for debugging, setting fake failure status for texture " << mID +				<< " (rand was " << rand_val << "/" << rate << ")" << LL_ENDL; +		response->setStatus(LLCore::HttpStatus(503)); +	}  	bool success = true;  	bool partial = false;  	LLCore::HttpStatus status(response->getStatus()); +	if (!status && (mFTType == FTT_SERVER_BAKE)) +	{ +		LL_INFOS() << mID << " state " << e_state_name[mState] << LL_ENDL; +		mFetchRetryPolicy.onFailure(response); +		F32 retry_after; +		if (mFetchRetryPolicy.shouldRetry(retry_after)) +		{ +			LL_INFOS() << mID << " will retry after " << retry_after << " seconds, resetting state to LOAD_FROM_NETWORK" << LL_ENDL; +			mFetcher->removeFromHTTPQueue(mID, S32Bytes(0)); +			std::string reason(status.toString()); +			setGetStatus(status, reason); +			releaseHttpSemaphore(); +			setState(LOAD_FROM_NETWORK); +			return; +		} +		else +		{ +			LL_INFOS() << mID << " will not retry" << LL_ENDL; +		} +	} +	else +	{ +		mFetchRetryPolicy.onSuccess(); +	}  	LL_DEBUGS("Texture") << "HTTP COMPLETE: " << mID -			 << " status: " << status.toTerseString() -			 << " '" << status.toString() << "'" +						 << " status: " << status.toTerseString() +						 << " '" << status.toString() << "'"  						 << LL_ENDL; +  //	unsigned int offset(0), length(0), full_length(0);  //	response->getRange(&offset, &length, &full_length);  // 	LL_WARNS() << "HTTP COMPLETE: " << mID << " handle: " << handle @@ -1911,13 +2002,18 @@ void LLTextureFetchWorker::onCompleted(LLCore::HttpHandle handle, LLCore::HttpRe  // 			<< " offset: " << offset << " length: " << length  // 			<< LL_ENDL; +	std::string reason(status.toString()); +	setGetStatus(status, reason);  	if (! status)  	{  		success = false; -		std::string reason(status.toString()); -		setGetStatus(status, reason); -		LL_WARNS() << "CURL GET FAILED, status: " << status.toTerseString() -				<< " reason: " << reason << LL_ENDL; +		if (mFTType != FTT_MAP_TILE) // missing map tiles are normal, don't complain about them. +		{ +			std::string reason(status.toString()); +			setGetStatus(status, reason); +			LL_WARNS() << "CURL GET FAILED, status: " << status.toTerseString() +					<< " reason: " << reason << LL_ENDL; +		}  	}  	else  	{ @@ -2477,7 +2573,11 @@ bool LLTextureFetch::createRequest(FTType f_type, const std::string& url, const  	{  		return false;  	} -	 + +	if (f_type == FTT_SERVER_BAKE) +	{ +		LL_DEBUGS("Avatar") << " requesting " << id << " " << w << "x" << h << " discard " << desired_discard << " type " << f_type << LL_ENDL; +	}  	LLTextureFetchWorker* worker = getWorker(id) ;  	if (worker)  	{ @@ -2493,7 +2593,18 @@ bool LLTextureFetch::createRequest(FTType f_type, const std::string& url, const  	S32 desired_size;  	std::string exten = gDirUtilp->getExtension(url); -	if (!url.empty() && (!exten.empty() && LLImageBase::getCodecFromExtension(exten) != IMG_CODEC_J2C)) +	if (f_type == FTT_SERVER_BAKE) +	{ +		// SH-4030: This case should be redundant with the following one, just +		// breaking it out here to clarify that it's intended behavior. +		llassert(!url.empty() && (!exten.empty() && LLImageBase::getCodecFromExtension(exten) != IMG_CODEC_J2C)); + +		// Do full requests for baked textures to reduce interim blurring. +		LL_DEBUGS("Texture") << "full request for " << id << " texture is FTT_SERVER_BAKE" << LL_ENDL; +		desired_size = MAX_IMAGE_DATA_SIZE; +		desired_discard = 0; +	} +	else if (!url.empty() && (!exten.empty() && LLImageBase::getCodecFromExtension(exten) != IMG_CODEC_J2C))  	{  		LL_DEBUGS("Texture") << "full request for " << id << " exten is not J2C: " << exten << LL_ENDL;  		// Only do partial requests for J2C at the moment @@ -2535,7 +2646,8 @@ bool LLTextureFetch::createRequest(FTType f_type, const std::string& url, const  		worker->mNeedsAux = needs_aux;  		worker->setImagePriority(priority);  		worker->setDesiredDiscard(desired_discard, desired_size); -		worker->setCanUseHTTP(can_use_http) ; +		worker->setCanUseHTTP(can_use_http); +		worker->setUrl(url);  		if (!worker->haveWork())  		{  			worker->setState(LLTextureFetchWorker::INIT); @@ -2562,7 +2674,8 @@ bool LLTextureFetch::createRequest(FTType f_type, const std::string& url, const  		worker->unlockWorkMutex();										// -Mw  	} - 	LL_DEBUGS("Texture") << "REQUESTED: " << id << " Discard: " << desired_discard << " size " << desired_size << LL_ENDL; + 	LL_DEBUGS("Texture") << "REQUESTED: " << id << " f_type " << fttype_to_string(f_type) +						 << " Discard: " << desired_discard << " size " << desired_size << LL_ENDL;  	return true;  } @@ -2741,7 +2854,8 @@ LLTextureFetchWorker* LLTextureFetch::getWorker(const LLUUID& id)  // Threads:  T*  bool LLTextureFetch::getRequestFinished(const LLUUID& id, S32& discard_level, -										LLPointer<LLImageRaw>& raw, LLPointer<LLImageRaw>& aux) +										LLPointer<LLImageRaw>& raw, LLPointer<LLImageRaw>& aux, +										LLCore::HttpStatus& last_http_get_status)  {  	bool res = false;  	LLTextureFetchWorker* worker = getWorker(id); @@ -2763,6 +2877,7 @@ bool LLTextureFetch::getRequestFinished(const LLUUID& id, S32& discard_level,  		else if (worker->checkWork())  		{  			worker->lockWorkMutex();									// +Mw +			last_http_get_status = worker->mGetStatus;  			discard_level = worker->mDecodedDiscard;  			raw = worker->mRawImage;  			aux = worker->mAuxImage; @@ -3233,25 +3348,14 @@ bool LLTextureFetchWorker::insertPacket(S32 index, U8* data, S32 size)  void LLTextureFetchWorker::setState(e_state new_state)  { -	static const char* e_state_name[] = -	{ -		"INVALID", -		"INIT", -		"LOAD_FROM_TEXTURE_CACHE", -		"CACHE_POST", -		"LOAD_FROM_NETWORK", -		"LOAD_FROM_SIMULATOR", -		"WAIT_HTTP_RESOURCE", -		"WAIT_HTTP_RESOURCE2", -		"SEND_HTTP_REQ", -		"WAIT_HTTP_REQ", -		"DECODE_IMAGE", -		"DECODE_IMAGE_UPDATE", -		"WRITE_TO_CACHE", -		"WAIT_ON_WRITE", -		"DONE" -	}; -	LL_DEBUGS("Texture") << "id: " << mID << " FTType: " << mFTType << " disc: " << mDesiredDiscard << " sz: " << mDesiredSize << " state: " << e_state_name[mState] << " => " << e_state_name[new_state] << LL_ENDL; +	if (mFTType == FTT_SERVER_BAKE) +	{ +	// NOTE: turning on these log statements is a reliable way to get +	// blurry images fairly frequently. Presumably this is an +	// indication of some subtle timing or locking issue. + +//		LL_INFOS("Texture") << "id: " << mID << " FTType: " << mFTType << " disc: " << mDesiredDiscard << " sz: " << mDesiredSize << " state: " << e_state_name[mState] << " => " << e_state_name[new_state] << LL_ENDL; +	}  	mState = new_state;  } @@ -4016,7 +4120,7 @@ LLTextureFetchDebugger::~LLTextureFetchDebugger()  void LLTextureFetchDebugger::init()  { -	mState = IDLE; +	setDebuggerState(IDLE);  	mCacheReadTime = -1.f;  	mCacheWriteTime = -1.f; @@ -4113,7 +4217,7 @@ void LLTextureFetchDebugger::startDebug()  	//clear the current fetching queue  	gTextureList.clearFetchingRequests(); -	mState = START_DEBUG; +	setDebuggerState(START_DEBUG);  }  bool LLTextureFetchDebugger::processStartDebug(F32 max_time) @@ -4188,7 +4292,7 @@ void LLTextureFetchDebugger::tryToStopDebug()  	//clear the current debug work  	S32 size = mFetchingHistory.size(); -	switch(mState) +	switch(mDebuggerState)  	{  	case READ_CACHE:		  		for(S32 i = 0 ; i < size; i++) @@ -4261,7 +4365,7 @@ void LLTextureFetchDebugger::addHistoryEntry(LLTextureFetchWorker* worker)  	if(mFreezeHistory)  	{ -		if(mState == REFETCH_VIS_CACHE || mState == REFETCH_VIS_HTTP) +		if(mDebuggerState == REFETCH_VIS_CACHE || mDebuggerState == REFETCH_VIS_HTTP)  		{  			mRefetchedVisPixels += worker->mRawImage->getWidth() * worker->mRawImage->getHeight();  			mRefetchedVisData += worker->mFormattedImage->getDataSize(); @@ -4306,9 +4410,9 @@ void LLTextureFetchDebugger::unlockCache()  void LLTextureFetchDebugger::debugCacheRead()  {  	lockCache(); -	llassert_always(mState == IDLE); +	llassert_always(mDebuggerState == IDLE);  	mTimer.reset(); -	mState = READ_CACHE; +	setDebuggerState(READ_CACHE);  	mCacheReadTime = -1.f;  	S32 size = mFetchingHistory.size(); @@ -4342,9 +4446,9 @@ void LLTextureFetchDebugger::debugCacheWrite()  	clearCache();  	lockCache(); -	llassert_always(mState == IDLE); +	llassert_always(mDebuggerState == IDLE);  	mTimer.reset(); -	mState = WRITE_CACHE; +	setDebuggerState(WRITE_CACHE);  	mCacheWriteTime = -1.f;  	S32 size = mFetchingHistory.size(); @@ -4371,9 +4475,9 @@ void LLTextureFetchDebugger::unlockDecoder()  void LLTextureFetchDebugger::debugDecoder()  {  	lockDecoder(); -	llassert_always(mState == IDLE); +	llassert_always(mDebuggerState == IDLE);  	mTimer.reset(); -	mState = DECODING; +	setDebuggerState(DECODING);  	mDecodingTime = -1.f;  	S32 size = mFetchingHistory.size(); @@ -4392,7 +4496,7 @@ void LLTextureFetchDebugger::debugDecoder()  void LLTextureFetchDebugger::debugHTTP()  { -	llassert_always(mState == IDLE); +	llassert_always(mDebuggerState == IDLE);  	LLViewerRegion* region = gAgent.getRegion();  	if (!region) @@ -4409,7 +4513,7 @@ void LLTextureFetchDebugger::debugHTTP()  	}  	mTimer.reset(); -	mState = HTTP_FETCHING; +	setDebuggerState(HTTP_FETCHING);  	mHTTPTime = -1.f;  	S32 size = mFetchingHistory.size(); @@ -4489,8 +4593,8 @@ S32 LLTextureFetchDebugger::fillCurlQueue()  void LLTextureFetchDebugger::debugGLTextureCreation()  { -	llassert_always(mState == IDLE); -	mState = GL_TEX; +	llassert_always(mDebuggerState == IDLE); +	setDebuggerState(GL_TEX);  	mTempTexList.clear();  	S32 size = mFetchingHistory.size(); @@ -4611,8 +4715,8 @@ void LLTextureFetchDebugger::scanRefetchList()  void LLTextureFetchDebugger::debugRefetchVisibleFromCache()  { -	llassert_always(mState == IDLE); -	mState = REFETCH_VIS_CACHE; +	llassert_always(mDebuggerState == IDLE); +	setDebuggerState(REFETCH_VIS_CACHE);  	clearTextures();  	mFetcher->setLoadSource(LLTextureFetch::FROM_ALL); @@ -4626,8 +4730,8 @@ void LLTextureFetchDebugger::debugRefetchVisibleFromCache()  void LLTextureFetchDebugger::debugRefetchVisibleFromHTTP()  { -	llassert_always(mState == IDLE); -	mState = REFETCH_VIS_HTTP; +	llassert_always(mDebuggerState == IDLE); +	setDebuggerState(REFETCH_VIS_HTTP);  	clearTextures();  	mFetcher->setLoadSource(LLTextureFetch::FROM_HTTP_ONLY); @@ -4641,8 +4745,8 @@ void LLTextureFetchDebugger::debugRefetchVisibleFromHTTP()  void LLTextureFetchDebugger::debugRefetchAllFromCache()  { -	llassert_always(mState == IDLE); -	mState = REFETCH_ALL_CACHE; +	llassert_always(mDebuggerState == IDLE); +	setDebuggerState(REFETCH_ALL_CACHE);  	clearTextures();  	makeRefetchList(); @@ -4658,8 +4762,8 @@ void LLTextureFetchDebugger::debugRefetchAllFromCache()  void LLTextureFetchDebugger::debugRefetchAllFromHTTP()  { -	llassert_always(mState == IDLE); -	mState = REFETCH_ALL_HTTP; +	llassert_always(mDebuggerState == IDLE); +	setDebuggerState(REFETCH_ALL_HTTP);  	clearTextures();  	makeRefetchList(); @@ -4675,19 +4779,19 @@ void LLTextureFetchDebugger::debugRefetchAllFromHTTP()  bool LLTextureFetchDebugger::update(F32 max_time)  { -	switch(mState) +	switch(mDebuggerState)  	{  	case START_DEBUG:  		if(processStartDebug(max_time))  		{ -			mState = IDLE; +			setDebuggerState(IDLE);  		}  		break;  	case READ_CACHE:  		if(!mTextureCache->update(1))  		{  			mCacheReadTime = mTimer.getElapsedTimeF32() ; -			mState = IDLE; +			setDebuggerState(IDLE);  			unlockCache();  		}  		break; @@ -4695,7 +4799,7 @@ bool LLTextureFetchDebugger::update(F32 max_time)  		if(!mTextureCache->update(1))  		{  			mCacheWriteTime = mTimer.getElapsedTimeF32() ; -			mState = IDLE; +			setDebuggerState(IDLE);  			unlockCache();  		}  		break; @@ -4703,7 +4807,7 @@ bool LLTextureFetchDebugger::update(F32 max_time)  		if(!mImageDecodeThread->update(1))  		{  			mDecodingTime =  mTimer.getElapsedTimeF32() ; -			mState = IDLE; +			setDebuggerState(IDLE);  			unlockDecoder();  		}  		break; @@ -4713,13 +4817,13 @@ bool LLTextureFetchDebugger::update(F32 max_time)  		if (!fillCurlQueue() && mNbCurlCompleted == mFetchingHistory.size())  		{  			mHTTPTime =  mTimer.getElapsedTimeF32() ; -			mState = IDLE; +			setDebuggerState(IDLE);  		}  		break;  	case GL_TEX:  		if(processGLCreation(max_time))  		{ -			mState = IDLE; +			setDebuggerState(IDLE);  			mTempTexList.clear();  		}  		break; @@ -4727,7 +4831,7 @@ bool LLTextureFetchDebugger::update(F32 max_time)  		if (LLAppViewer::getTextureFetch()->getNumRequests() == 0)  		{  			mRefetchVisCacheTime = mTimer.getElapsedTimeF32() ; -			mState = IDLE; +			setDebuggerState(IDLE);  			mFetcher->lockFetcher(true);  			mFetcher->resetLoadSource();  		} @@ -4736,7 +4840,7 @@ bool LLTextureFetchDebugger::update(F32 max_time)  		if (LLAppViewer::getTextureFetch()->getNumRequests() == 0)  		{  			mRefetchVisHTTPTime = mTimer.getElapsedTimeF32() ; -			mState = IDLE; +			setDebuggerState(IDLE);  			mFetcher->lockFetcher(true);  			mFetcher->resetLoadSource();  		} @@ -4753,7 +4857,7 @@ bool LLTextureFetchDebugger::update(F32 max_time)  			}  			mRefetchAllCacheTime = mTimer.getElapsedTimeF32() ; -			mState = IDLE;  +			setDebuggerState(IDLE);   			mFetcher->lockFetcher(true);  			mFetcher->resetLoadSource();  			mRefetchList.clear(); @@ -4765,7 +4869,7 @@ bool LLTextureFetchDebugger::update(F32 max_time)  		if (LLAppViewer::getTextureFetch()->getNumRequests() == 0)  		{  			mRefetchAllHTTPTime = mTimer.getElapsedTimeF32() ; -			mState = IDLE; +			setDebuggerState(IDLE);  			mFetcher->lockFetcher(true);  			mFetcher->resetLoadSource();  			mRefetchList.clear(); @@ -4773,11 +4877,11 @@ bool LLTextureFetchDebugger::update(F32 max_time)  		}  		break;  	default: -		mState = IDLE; +		setDebuggerState(IDLE);  		break;  	} -	return mState == IDLE; +	return mDebuggerState == IDLE;  }  void LLTextureFetchDebugger::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response) diff --git a/indra/newview/lltexturefetch.h b/indra/newview/lltexturefetch.h index d7fb2b4356..c4da2e8685 100755 --- a/indra/newview/lltexturefetch.h +++ b/indra/newview/lltexturefetch.h @@ -95,7 +95,8 @@ public:  	// Threads:  T*  	bool getRequestFinished(const LLUUID& id, S32& discard_level, -							LLPointer<LLImageRaw>& raw, LLPointer<LLImageRaw>& aux); +							LLPointer<LLImageRaw>& raw, LLPointer<LLImageRaw>& aux, +							LLCore::HttpStatus& last_http_get_status);  	// Threads:  T*  	bool updateRequestPriority(const LLUUID& id, F32 priority); @@ -396,6 +397,9 @@ private:  	e_tex_source mFetchSource;  	e_tex_source mOriginFetchSource; +	// Retry logic +	//LLAdaptiveRetryPolicy mFetchRetryPolicy; +	  public:  	//debug use  	LLTextureFetchDebugger* getFetchDebugger() { return mFetchDebugger;} @@ -475,8 +479,9 @@ private:  	typedef std::map<LLCore::HttpHandle, S32> handle_fetch_map_t;  	handle_fetch_map_t mHandleToFetchIndex; -	 -	e_debug_state mState; + +	void setDebuggerState(e_debug_state new_state) { mDebuggerState = new_state; } +	e_debug_state mDebuggerState;  	F32 mCacheReadTime;  	F32 mCacheWriteTime; @@ -549,7 +554,7 @@ public:  	void callbackDecoded(S32 id, bool success, LLImageRaw* raw, LLImageRaw* aux);  	void callbackHTTP(FetchEntry & fetch, LLCore::HttpResponse * response); -	e_debug_state getState()             {return mState;} +	e_debug_state getState()             {return mDebuggerState;}  	S32  getNumFetchedTextures()         {return mNumFetchedTextures;}  	S32  getNumFetchingRequests()        {return mFetchingHistory.size();}  	S32  getNumCacheHits()               {return mNumCacheHits;} diff --git a/indra/newview/lltextureview.cpp b/indra/newview/lltextureview.cpp index 8ee83b5df0..aa1f680a1e 100755 --- a/indra/newview/lltextureview.cpp +++ b/indra/newview/lltextureview.cpp @@ -434,15 +434,7 @@ void LLAvatarTexBar::draw()  		if (!layerset_buffer) continue;  		LLColor4 text_color = LLColor4::white; -		 -		if (layerset_buffer->uploadNeeded()) -		{ -			text_color = LLColor4::red; -		} - 		if (layerset_buffer->uploadInProgress()) -		{ -			text_color = LLColor4::magenta; -		} +  		std::string text = layerset_buffer->dumpTextureInfo();  		LLFontGL::getFontMonospace()->renderUTF8(text, 0, l_offset, v_offset + line_height*line_num,  												 text_color, LLFontGL::LEFT, LLFontGL::TOP); //, LLFontGL::BOLD, LLFontGL::DROP_SHADOW_SOFT); diff --git a/indra/newview/lltoolmorph.cpp b/indra/newview/lltoolmorph.cpp index 148e5a015b..2d458db36b 100755 --- a/indra/newview/lltoolmorph.cpp +++ b/indra/newview/lltoolmorph.cpp @@ -54,6 +54,7 @@  #include "llviewercamera.h"  #include "llviewertexturelist.h"  #include "llviewerobject.h" +#include "llviewerwearable.h"  #include "llviewerwindow.h"  #include "llvoavatarself.h"  #include "pipeline.h" @@ -147,13 +148,20 @@ BOOL LLVisualParamHint::needsRender()  void LLVisualParamHint::preRender(BOOL clear_depth)  { +	LLViewerWearable* wearable = (LLViewerWearable*)mWearablePtr; +	if (wearable) +	{ +		wearable->setVolatile(TRUE); +	}  	mLastParamWeight = mVisualParam->getWeight(); -	mWearablePtr->setVisualParamWeight(mVisualParam->getID(), mVisualParamWeight, FALSE); -	gAgentAvatarp->setVisualParamWeight(mVisualParam->getID(), mVisualParamWeight, FALSE); +	mWearablePtr->setVisualParamWeight(mVisualParam->getID(), mVisualParamWeight); +	gAgentAvatarp->setVisualParamWeight(mVisualParam->getID(), mVisualParamWeight);  	gAgentAvatarp->setVisualParamWeight("Blink_Left", 0.f);  	gAgentAvatarp->setVisualParamWeight("Blink_Right", 0.f);  	gAgentAvatarp->updateComposites(); -	gAgentAvatarp->updateVisualParams(); +	// Calling LLCharacter version, as we don't want position/height changes to cause the avatar to jump +	// up and down when we're doing preview renders. -Nyx +	gAgentAvatarp->LLCharacter::updateVisualParams();  	gAgentAvatarp->updateGeometry(gAgentAvatarp->mDrawable);  	gAgentAvatarp->updateLOD(); @@ -238,7 +246,13 @@ BOOL LLVisualParamHint::render()  		gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);  	}  	gAgentAvatarp->setVisualParamWeight(mVisualParam->getID(), mLastParamWeight); -	mWearablePtr->setVisualParamWeight(mVisualParam->getID(), mLastParamWeight, FALSE); +	mWearablePtr->setVisualParamWeight(mVisualParam->getID(), mLastParamWeight); +	LLViewerWearable* wearable = (LLViewerWearable*)mWearablePtr; +	if (wearable) +	{ +		wearable->setVolatile(FALSE); +	} +  	gAgentAvatarp->updateVisualParams();  	gGL.color4f(1,1,1,1);  	mGLTexturep->setGLTextureCreated(true); diff --git a/indra/newview/lltranslate.cpp b/indra/newview/lltranslate.cpp index 7e80d72dec..c0ba0a1f39 100755 --- a/indra/newview/lltranslate.cpp +++ b/indra/newview/lltranslate.cpp @@ -84,7 +84,7 @@ bool LLGoogleTranslationHandler::parseResponse(  		return false;  	} -	if (status != STATUS_OK) +	if (status != HTTP_OK)  	{  		// Request failed. Extract error message from the response.  		parseErrorResponse(root, status, err_msg); @@ -186,7 +186,7 @@ bool LLBingTranslationHandler::parseResponse(  	std::string& detected_lang,  	std::string& err_msg) const  { -	if (status != STATUS_OK) +	if (status != HTTP_OK)  	{  		static const std::string MSG_BEGIN_MARKER = "Message: ";  		size_t begin = body.find(MSG_BEGIN_MARKER); @@ -251,8 +251,6 @@ LLTranslate::TranslationReceiver::TranslationReceiver(const std::string& from_la  // virtual  void LLTranslate::TranslationReceiver::completedRaw( -	U32 http_status, -	const std::string& reason,  	const LLChannelDescriptors& channels,  	const LLIOPipe::buffer_ptr_t& buffer)  { @@ -262,8 +260,8 @@ void LLTranslate::TranslationReceiver::completedRaw(  	const std::string body = strstrm.str();  	std::string translation, detected_lang, err_msg; -	int status = http_status; -	LL_DEBUGS("Translate") << "HTTP status: " << status << " " << reason << LL_ENDL; +	int status = getStatus(); +	LL_DEBUGS("Translate") << "HTTP status: " << status << " " << getReason() << LL_ENDL;  	LL_DEBUGS("Translate") << "Response body: " << body << LL_ENDL;  	if (mHandler.parseResponse(status, body, translation, detected_lang, err_msg))  	{ @@ -301,12 +299,10 @@ LLTranslate::EService LLTranslate::KeyVerificationReceiver::getService() const  // virtual  void LLTranslate::KeyVerificationReceiver::completedRaw( -	U32 http_status, -	const std::string& reason,  	const LLChannelDescriptors& channels,  	const LLIOPipe::buffer_ptr_t& buffer)  { -	bool ok = (http_status == 200); +	bool ok = (getStatus() == HTTP_OK);  	setVerificationStatus(ok);  } @@ -398,8 +394,8 @@ void LLTranslate::sendRequest(const std::string& url, LLHTTPClient::ResponderPtr  			LLVersionInfo::getPatch(),  			LLVersionInfo::getBuild()); -		sHeader.insert("Accept", "text/plain"); -		sHeader.insert("User-Agent", user_agent); +		sHeader.insert(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_TEXT_PLAIN); +		sHeader.insert(HTTP_OUT_HEADER_USER_AGENT, user_agent);  	}  	LLHTTPClient::get(url, responder, sHeader, REQUEST_TIMEOUT); diff --git a/indra/newview/lltranslate.h b/indra/newview/lltranslate.h index db5ad9479c..972274714a 100755 --- a/indra/newview/lltranslate.h +++ b/indra/newview/lltranslate.h @@ -95,9 +95,6 @@ public:  	virtual bool isConfigured() const = 0;  	virtual ~LLTranslationAPIHandler() {} - -protected: -	static const int STATUS_OK = 200;  };  /// Google Translate v2 API handler. @@ -201,8 +198,6 @@ public :  		 * @see mHandler  		 */  		/*virtual*/ void completedRaw( -			U32 http_status, -			const std::string& reason,  			const LLChannelDescriptors& channels,  			const LLIOPipe::buffer_ptr_t& buffer); @@ -250,8 +245,6 @@ public :  		 * @see setVerificationStatus()  		 */  		/*virtual*/ void completedRaw( -			U32 http_status, -			const std::string& reason,  			const LLChannelDescriptors& channels,  			const LLIOPipe::buffer_ptr_t& buffer); diff --git a/indra/newview/lluploadfloaterobservers.cpp b/indra/newview/lluploadfloaterobservers.cpp index 248f1bf1d5..69b9b1f9f1 100755 --- a/indra/newview/lluploadfloaterobservers.cpp +++ b/indra/newview/lluploadfloaterobservers.cpp @@ -1,6 +1,6 @@  /**   * @file lluploadfloaterobservers.cpp - * @brief LLUploadModelPremissionsResponder definition + * @brief LLUploadModelPermissionsResponder definition   *   * $LicenseInfo:firstyear=2011&license=viewerlgpl$   * Second Life Viewer Source Code @@ -28,26 +28,31 @@  #include "lluploadfloaterobservers.h" -LLUploadModelPremissionsResponder::LLUploadModelPremissionsResponder(const LLHandle<LLUploadPermissionsObserver>& observer) +LLUploadModelPermissionsResponder::LLUploadModelPermissionsResponder(const LLHandle<LLUploadPermissionsObserver>& observer)  :mObserverHandle(observer)  {  } -void LLUploadModelPremissionsResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void LLUploadModelPermissionsResponder::httpFailure()  { -	LL_WARNS() << "LLUploadModelPremissionsResponder error [status:" -			<< status << "]: " << content << LL_ENDL; +	LL_WARNS() << dumpResponse() << LL_ENDL;  	LLUploadPermissionsObserver* observer = mObserverHandle.get();  	if (observer)  	{ -		observer->setPermissonsErrorStatus(status, reason); +		observer->setPermissonsErrorStatus(getStatus(), getReason());  	}  } -void LLUploadModelPremissionsResponder::result(const LLSD& content) +void LLUploadModelPermissionsResponder::httpSuccess()  { +	const LLSD& content = getContent(); +	if (!content.isMap()) +	{ +		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); +		return; +	}  	LLUploadPermissionsObserver* observer = mObserverHandle.get();  	if (observer) @@ -55,3 +60,4 @@ void LLUploadModelPremissionsResponder::result(const LLSD& content)  		observer->onPermissionsReceived(content);  	}  } + diff --git a/indra/newview/lluploadfloaterobservers.h b/indra/newview/lluploadfloaterobservers.h index b43ddb44d9..4ff4a827a5 100755 --- a/indra/newview/lluploadfloaterobservers.h +++ b/indra/newview/lluploadfloaterobservers.h @@ -1,6 +1,6 @@  /**   * @file lluploadfloaterobservers.h - * @brief LLUploadModelPremissionsResponder declaration + * @brief LLUploadModelPermissionsResponder declaration   *   * $LicenseInfo:firstyear=2011&license=viewerlgpl$   * Second Life Viewer Source Code @@ -39,7 +39,7 @@ public:  	virtual ~LLUploadPermissionsObserver() {}  	virtual void onPermissionsReceived(const LLSD& result) = 0; -	virtual void setPermissonsErrorStatus(U32 status, const std::string& reason) = 0; +	virtual void setPermissonsErrorStatus(S32 status, const std::string& reason) = 0;  	LLHandle<LLUploadPermissionsObserver> getPermObserverHandle() const {return mUploadPermObserverHandle;} @@ -54,7 +54,7 @@ public:  	virtual ~LLWholeModelFeeObserver() {}  	virtual void onModelPhysicsFeeReceived(const LLSD& result, std::string upload_url) = 0; -	virtual void setModelPhysicsFeeErrorStatus(U32 status, const std::string& reason) = 0; +	virtual void setModelPhysicsFeeErrorStatus(S32 status, const std::string& reason) = 0;  	LLHandle<LLWholeModelFeeObserver> getWholeModelFeeObserverHandle() const { return mWholeModelFeeObserverHandle; } @@ -80,17 +80,16 @@ protected:  }; -class LLUploadModelPremissionsResponder : public LLHTTPClient::Responder +class LLUploadModelPermissionsResponder : public LLHTTPClient::Responder  { +	LOG_CLASS(LLUploadModelPermissionsResponder);  public: - -	LLUploadModelPremissionsResponder(const LLHandle<LLUploadPermissionsObserver>& observer); - -	void errorWithContent(U32 status, const std::string& reason, const LLSD& content); - -	void result(const LLSD& content); +	LLUploadModelPermissionsResponder(const LLHandle<LLUploadPermissionsObserver>& observer);  private: +	/* virtual */ void httpSuccess(); +	/* virtual */ void httpFailure(); +  	LLHandle<LLUploadPermissionsObserver> mObserverHandle;  }; diff --git a/indra/newview/llviewerdisplayname.cpp b/indra/newview/llviewerdisplayname.cpp index 3d794f0d91..e390e8776d 100755 --- a/indra/newview/llviewerdisplayname.cpp +++ b/indra/newview/llviewerdisplayname.cpp @@ -58,12 +58,12 @@ namespace LLViewerDisplayName  class LLSetDisplayNameResponder : public LLHTTPClient::Responder  { -public: +	LOG_CLASS(LLSetDisplayNameResponder); +private:  	// only care about errors -	/*virtual*/ void errorWithContent(U32 status, const std::string& reason, const LLSD& content) +	/*virtual*/ void httpFailure()  	{ -		LL_WARNS() << "LLSetDisplayNameResponder error [status:" -				<< status << "]: " << content << LL_ENDL; +		LL_WARNS() << dumpResponse() << LL_ENDL;  		LLViewerDisplayName::sSetDisplayNameSignal(false, "", LLSD());  		LLViewerDisplayName::sSetDisplayNameSignal.disconnect_all_slots();  	} @@ -86,7 +86,7 @@ void LLViewerDisplayName::set(const std::string& display_name, const set_name_sl  	// People API can return localized error messages.  Indicate our  	// language preference via header.  	LLSD headers; -	headers["Accept-Language"] = LLUI::getLanguage(); +	headers[HTTP_OUT_HEADER_ACCEPT_LANGUAGE] = LLUI::getLanguage();  	// People API requires both the old and new value to change a variable.  	// Our display name will be in cache before the viewer's UI is available @@ -128,7 +128,7 @@ public:  		LLSD body = input["body"];  		S32 status = body["status"].asInteger(); -		bool success = (status == 200); +		bool success = (status == HTTP_OK);  		std::string reason = body["reason"].asString();  		LLSD content = body["content"]; @@ -137,7 +137,7 @@ public:  		// If viewer's concept of display name is out-of-date, the set request  		// will fail with 409 Conflict.  If that happens, fetch up-to-date  		// name information. -		if (status == 409) +		if (status == HTTP_CONFLICT)  		{  			LLUUID agent_id = gAgent.getID();  			// Flush stale data diff --git a/indra/newview/llviewerfoldertype.cpp b/indra/newview/llviewerfoldertype.cpp index 289c1b1530..e633282be8 100644 --- a/indra/newview/llviewerfoldertype.cpp +++ b/indra/newview/llviewerfoldertype.cpp @@ -147,14 +147,10 @@ LLViewerFolderDictionary::LLViewerFolderDictionary()  	addEntry(LLFolderType::FT_NONE, 				new ViewerFolderEntry("New Folder",				"Inv_FolderOpen",		"Inv_FolderClosed",		FALSE,     false, "default")); -#if SUPPORT_ENSEMBLES -	initEnsemblesFromFile(); -#else  	for (U32 type = (U32)LLFolderType::FT_ENSEMBLE_START; type <= (U32)LLFolderType::FT_ENSEMBLE_END; ++type)  	{  		addEntry((LLFolderType::EType)type, 		new ViewerFolderEntry("New Folder",				"Inv_FolderOpen",		"Inv_FolderClosed",		FALSE,     false)); -	}	 -#endif +	}  }  bool LLViewerFolderDictionary::initEnsemblesFromFile() diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index b653ba1b9e..a6dd0ed83a 100755 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -31,6 +31,7 @@  #include "llsdserialize.h"  #include "message.h" +#include "llaisapi.h"  #include "llagent.h"  #include "llagentcamera.h"  #include "llagentwearables.h" @@ -65,9 +66,12 @@  #include "llavataractions.h"  #include "lllogininstance.h"  #include "llfavoritesbar.h" +#include "llclipboard.h" +#include "llhttpretrypolicy.h" -// Two do-nothing ops for use in callbacks. +// do-nothing ops for use in callbacks.  void no_op_inventory_func(const LLUUID&) {}  +void no_op_llsd_func(const LLSD&) {}  void no_op() {}  ///---------------------------------------------------------------------------- @@ -256,7 +260,6 @@ public:  };  LLInventoryHandler gInventoryHandler; -  ///----------------------------------------------------------------------------  /// Class LLViewerInventoryItem  ///---------------------------------------------------------------------------- @@ -345,24 +348,6 @@ void LLViewerInventoryItem::cloneViewerItem(LLPointer<LLViewerInventoryItem>& ne  	}  } -void LLViewerInventoryItem::removeFromServer() -{ -	LL_DEBUGS() << "Removing inventory item " << mUUID << " from server." -			 << LL_ENDL; - -	LLInventoryModel::LLCategoryUpdate up(mParentUUID, -1); -	gInventory.accountForUpdate(up); - -	LLMessageSystem* msg = gMessageSystem; -	msg->newMessageFast(_PREHASH_RemoveInventoryItem); -	msg->nextBlockFast(_PREHASH_AgentData); -	msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); -	msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());  -	msg->nextBlockFast(_PREHASH_InventoryData); -	msg->addUUIDFast(_PREHASH_ItemID, mUUID); -	gAgent.sendReliableMessage(); -} -  void LLViewerInventoryItem::updateServer(BOOL is_new) const  {  	if(!mIsComplete) @@ -376,8 +361,9 @@ void LLViewerInventoryItem::updateServer(BOOL is_new) const  	if(gAgent.getID() != mPermissions.getOwner())  	{  		// *FIX: deal with this better. -		LL_WARNS() << "LLViewerInventoryItem::updateServer() - for unowned item" -				<< LL_ENDL; +		LL_WARNS() << "LLViewerInventoryItem::updateServer() - for unowned item " +				   << ll_pretty_print_sd(this->asLLSD()) +				   << LL_ENDL;  		return;  	}  	LLInventoryModel::LLCategoryUpdate up(mParentUUID, is_new ? 1 : 0); @@ -444,7 +430,7 @@ void LLViewerInventoryItem::fetchFromServer(void) const  }  // virtual -BOOL LLViewerInventoryItem::unpackMessage(LLSD item) +BOOL LLViewerInventoryItem::unpackMessage(const LLSD& item)  {  	BOOL rv = LLInventoryItem::fromLLSD(item); @@ -469,7 +455,7 @@ void LLViewerInventoryItem::setTransactionID(const LLTransactionID& transaction_  {  	mTransactionID = transaction_id;  } -// virtual +  void LLViewerInventoryItem::packMessage(LLMessageSystem* msg) const  {  	msg->addUUIDFast(_PREHASH_ItemID, mUUID); @@ -488,6 +474,7 @@ void LLViewerInventoryItem::packMessage(LLMessageSystem* msg) const  	U32 crc = getCRC32();  	msg->addU32Fast(_PREHASH_CRC, crc);  } +  // virtual  BOOL LLViewerInventoryItem::importFile(LLFILE* fp)  { @@ -599,6 +586,15 @@ void LLViewerInventoryCategory::copyViewerCategory(const LLViewerInventoryCatego  } +void LLViewerInventoryCategory::packMessage(LLMessageSystem* msg) const +{ +	msg->addUUIDFast(_PREHASH_FolderID, mUUID); +	msg->addUUIDFast(_PREHASH_ParentID, mParentUUID); +	S8 type = static_cast<S8>(mPreferredType); +	msg->addS8Fast(_PREHASH_Type, type); +	msg->addStringFast(_PREHASH_Name, mName); +} +  void LLViewerInventoryCategory::updateParentOnServer(BOOL restamp) const  {  	LLMessageSystem* msg = gMessageSystem; @@ -637,30 +633,6 @@ void LLViewerInventoryCategory::updateServer(BOOL is_new) const  	gAgent.sendReliableMessage();  } -void LLViewerInventoryCategory::removeFromServer( void ) -{ -	LL_INFOS() << "Removing inventory category " << mUUID << " from server." -			<< LL_ENDL; -	// communicate that change with the server. -	if(LLFolderType::lookupIsProtectedType(mPreferredType)) -	{ -		LLNotificationsUtil::add("CannotRemoveProtectedCategories"); -		return; -	} - -	LLInventoryModel::LLCategoryUpdate up(mParentUUID, -1); -	gInventory.accountForUpdate(up); - -	LLMessageSystem* msg = gMessageSystem; -	msg->newMessageFast(_PREHASH_RemoveInventoryFolder); -	msg->nextBlockFast(_PREHASH_AgentData); -	msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); -	msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); -	msg->nextBlockFast(_PREHASH_FolderData); -	msg->addUUIDFast(_PREHASH_FolderID, mUUID); -	gAgent.sendReliableMessage(); -} -  S32 LLViewerInventoryCategory::getVersion() const  {  	return mVersion; @@ -729,6 +701,19 @@ bool LLViewerInventoryCategory::fetch()  	return false;  } +S32 LLViewerInventoryCategory::getViewerDescendentCount() const +{ +	LLInventoryModel::cat_array_t* cats; +	LLInventoryModel::item_array_t* items; +	gInventory.getDirectDescendentsOf(getUUID(), cats, items); +	S32 descendents_actual = 0; +	if(cats && items) +	{ +		descendents_actual = cats->size() + items->size(); +	} +	return descendents_actual; +} +  bool LLViewerInventoryCategory::importFileLocal(LLFILE* fp)  {  	// *NOTE: This buffer size is hard coded into scanf() below. @@ -917,6 +902,21 @@ void LLViewerInventoryCategory::localizeName()  	LLLocalizedInventoryItemsDictionary::getInstance()->localizeInventoryObjectName(mName);  } +// virtual +BOOL LLViewerInventoryCategory::unpackMessage(const LLSD& category) +{ +	BOOL rv = LLInventoryCategory::fromLLSD(category); +	localizeName(); +	return rv; +} + +// virtual +void LLViewerInventoryCategory::unpackMessage(LLMessageSystem* msg, const char* block, S32 block_num) +{ +	LLInventoryCategory::unpackMessage(msg, block, block_num); +	localizeName(); +} +  ///----------------------------------------------------------------------------  /// Local function definitions  ///---------------------------------------------------------------------------- @@ -1110,75 +1110,148 @@ void copy_inventory_item(  	gAgent.sendReliableMessage();  } -void link_inventory_item( -	const LLUUID& agent_id, -	const LLUUID& item_id, -	const LLUUID& parent_id, -	const std::string& new_name, -	const std::string& new_description, -	const LLAssetType::EType asset_type, -	LLPointer<LLInventoryCallback> cb) +// Create link to single inventory object. +void link_inventory_object(const LLUUID& category, +			 LLConstPointer<LLInventoryObject> baseobj, +			 LLPointer<LLInventoryCallback> cb)  { -	const LLInventoryObject *baseobj = gInventory.getObject(item_id);  	if (!baseobj)  	{ -		LL_WARNS() << "attempt to link to unknown item, linked-to-item's itemID " << item_id << LL_ENDL; -		return; -	} -	if (baseobj && baseobj->getIsLinkType()) -	{ -		LL_WARNS() << "attempt to create a link to a link, linked-to-item's itemID " << item_id << LL_ENDL; +		LL_WARNS() << "Attempt to link to non-existent object" << LL_ENDL;  		return;  	} -	if (baseobj && !LLAssetType::lookupCanLink(baseobj->getType())) -	{ -		// Fail if item can be found but is of a type that can't be linked. -		// Arguably should fail if the item can't be found too, but that could -		// be a larger behavioral change. -		LL_WARNS() << "attempt to link an unlinkable item, type = " << baseobj->getActualType() << LL_ENDL; -		return; -	} -	 -	LLUUID transaction_id; -	LLInventoryType::EType inv_type = LLInventoryType::IT_NONE; -	if (dynamic_cast<const LLInventoryCategory *>(baseobj)) -	{ -		inv_type = LLInventoryType::IT_CATEGORY; -	} -	else +	LLInventoryObject::const_object_list_t obj_array; +	obj_array.push_back(baseobj); +	link_inventory_array(category, obj_array, cb); +} + +void link_inventory_object(const LLUUID& category, +			 const LLUUID& id, +			 LLPointer<LLInventoryCallback> cb) +{ +	LLConstPointer<LLInventoryObject> baseobj = gInventory.getObject(id); +	link_inventory_object(category, baseobj, cb); +} + +// Create links to all listed inventory objects. +void link_inventory_array(const LLUUID& category, +			 LLInventoryObject::const_object_list_t& baseobj_array, +			 LLPointer<LLInventoryCallback> cb) +{ +#ifndef LL_RELEASE_FOR_DOWNLOAD +	const LLViewerInventoryCategory *cat = gInventory.getCategory(category); +	const std::string cat_name = cat ? cat->getName() : "CAT NOT FOUND"; +#endif +	LLInventoryObject::const_object_list_t::const_iterator it = baseobj_array.begin(); +	LLInventoryObject::const_object_list_t::const_iterator end = baseobj_array.end(); +	LLSD links = LLSD::emptyArray(); +	for (; it != end; ++it)  	{ -		const LLViewerInventoryItem *baseitem = dynamic_cast<const LLViewerInventoryItem *>(baseobj); -		if (baseitem) +		const LLInventoryObject* baseobj = *it; +		if (!baseobj)  		{ -			inv_type = baseitem->getInventoryType(); +			LL_WARNS() << "attempt to link to unknown object" << LL_ENDL; +			continue;  		} -	} -#if 1 // debugging stuff -	LLViewerInventoryCategory* cat = gInventory.getCategory(parent_id); -	LL_DEBUGS() << "cat: " << cat << LL_ENDL; -	 +		if (!LLAssetType::lookupCanLink(baseobj->getType())) +		{ +			// Fail if item can be found but is of a type that can't be linked. +			// Arguably should fail if the item can't be found too, but that could +			// be a larger behavioral change. +			LL_WARNS() << "attempt to link an unlinkable object, type = " << baseobj->getActualType() << LL_ENDL; +			continue; +		} +		 +		LLInventoryType::EType inv_type = LLInventoryType::IT_NONE; +		LLAssetType::EType asset_type = LLAssetType::AT_NONE; +		std::string new_desc; +		LLUUID linkee_id; +		if (dynamic_cast<const LLInventoryCategory *>(baseobj)) +		{ +			inv_type = LLInventoryType::IT_CATEGORY; +			asset_type = LLAssetType::AT_LINK_FOLDER; +			linkee_id = baseobj->getUUID(); +		} +		else +		{ +			const LLViewerInventoryItem *baseitem = dynamic_cast<const LLViewerInventoryItem *>(baseobj); +			if (baseitem) +			{ +				inv_type = baseitem->getInventoryType(); +				new_desc = baseitem->getActualDescription(); +				switch (baseitem->getActualType()) +				{ +					case LLAssetType::AT_LINK: +					case LLAssetType::AT_LINK_FOLDER: +						linkee_id = baseobj->getLinkedUUID(); +						asset_type = baseitem->getActualType(); +						break; +					default: +						linkee_id = baseobj->getUUID(); +						asset_type = LLAssetType::AT_LINK; +						break; +				} +			} +			else +			{ +				LL_WARNS() << "could not convert object into an item or category: " << baseobj->getUUID() << LL_ENDL; +				continue; +			} +		} + +		LLSD link = LLSD::emptyMap(); +		link["linked_id"] = linkee_id; +		link["type"] = (S8)asset_type; +		link["inv_type"] = (S8)inv_type; +		link["name"] = baseobj->getName(); +		link["desc"] = new_desc; +		links.append(link); + +#ifndef LL_RELEASE_FOR_DOWNLOAD +		LL_DEBUGS("Inventory") << "Linking Object [ name:" << baseobj->getName()  +							   << " UUID:" << baseobj->getUUID()  +							   << " ] into Category [ name:" << cat_name  +							   << " UUID:" << category << " ] " << LL_ENDL;  #endif -	LLMessageSystem* msg = gMessageSystem; -	msg->newMessageFast(_PREHASH_LinkInventoryItem); -	msg->nextBlock(_PREHASH_AgentData); +	} + +	bool ais_ran = false; +	if (AISCommand::isAPIAvailable())  	{ -		msg->addUUIDFast(_PREHASH_AgentID, agent_id); -		msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); +		LLSD new_inventory = LLSD::emptyMap(); +		new_inventory["links"] = links; +		LLPointer<AISCommand> cmd_ptr = new CreateInventoryCommand(category, new_inventory, cb); +		ais_ran = cmd_ptr->run_command();  	} -	msg->nextBlock(_PREHASH_InventoryBlock); + +	if (!ais_ran)  	{ -		msg->addU32Fast(_PREHASH_CallbackID, gInventoryCallbacks.registerCB(cb)); -		msg->addUUIDFast(_PREHASH_FolderID, parent_id); -		msg->addUUIDFast(_PREHASH_TransactionID, transaction_id); -		msg->addUUIDFast(_PREHASH_OldItemID, item_id); -		msg->addS8Fast(_PREHASH_Type, (S8)asset_type); -		msg->addS8Fast(_PREHASH_InvType, (S8)inv_type); -		msg->addStringFast(_PREHASH_Name, new_name); -		msg->addStringFast(_PREHASH_Description, new_description); +		LLMessageSystem* msg = gMessageSystem; +		for (LLSD::array_iterator iter = links.beginArray(); iter != links.endArray(); ++iter ) +		{ +			msg->newMessageFast(_PREHASH_LinkInventoryItem); +			msg->nextBlock(_PREHASH_AgentData); +			{ +				msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); +				msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); +			} +			msg->nextBlock(_PREHASH_InventoryBlock); +			{ +				LLSD link = (*iter); +				msg->addU32Fast(_PREHASH_CallbackID, gInventoryCallbacks.registerCB(cb)); +				msg->addUUIDFast(_PREHASH_FolderID, category); +				msg->addUUIDFast(_PREHASH_TransactionID, LLUUID::null); +				msg->addUUIDFast(_PREHASH_OldItemID, link["linked_id"].asUUID()); +				msg->addS8Fast(_PREHASH_Type, link["type"].asInteger()); +				msg->addS8Fast(_PREHASH_InvType, link["inv_type"].asInteger()); +				msg->addStringFast(_PREHASH_Name, link["name"].asString()); +				msg->addStringFast(_PREHASH_Description, link["desc"].asString()); +			} +			gAgent.sendReliableMessage(); +		}  	} -	gAgent.sendReliableMessage();  }  void move_inventory_item( @@ -1202,6 +1275,392 @@ void move_inventory_item(  	gAgent.sendReliableMessage();  } +// Should call this with an update_item that's been copied and +// modified from an original source item, rather than modifying the +// source item directly. +void update_inventory_item( +	LLViewerInventoryItem *update_item, +	LLPointer<LLInventoryCallback> cb) +{ +	const LLUUID& item_id = update_item->getUUID(); +	bool ais_ran = false; +	if (AISCommand::isAPIAvailable()) +	{ +		LLSD updates = update_item->asLLSD(); +		// Replace asset_id and/or shadow_id with transaction_id (hash_id) +		if (updates.has("asset_id")) +		{ +			updates.erase("asset_id"); +			updates["hash_id"] = update_item->getTransactionID(); +		} +		if (updates.has("shadow_id")) +		{ +			updates.erase("shadow_id"); +			updates["hash_id"] = update_item->getTransactionID(); +		} +		LLPointer<AISCommand> cmd_ptr = new UpdateItemCommand(item_id, updates, cb); +		ais_ran = cmd_ptr->run_command(); +	} +	if (!ais_ran) +	{ +		LLPointer<LLViewerInventoryItem> obj = gInventory.getItem(item_id); +		LL_DEBUGS("Inventory") << "item_id: [" << item_id << "] name " << (update_item ? update_item->getName() : "(NOT FOUND)") << LL_ENDL; +		if(obj) +		{ +			LLMessageSystem* msg = gMessageSystem; +			msg->newMessageFast(_PREHASH_UpdateInventoryItem); +			msg->nextBlockFast(_PREHASH_AgentData); +			msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); +			msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); +			msg->addUUIDFast(_PREHASH_TransactionID, update_item->getTransactionID()); +			msg->nextBlockFast(_PREHASH_InventoryData); +			msg->addU32Fast(_PREHASH_CallbackID, 0); +			update_item->packMessage(msg); +			gAgent.sendReliableMessage(); + +			LLInventoryModel::LLCategoryUpdate up(update_item->getParentUUID(), 0); +			gInventory.accountForUpdate(up); +			gInventory.updateItem(update_item); +			if (cb) +			{ +				cb->fire(item_id); +			} +		} +	} +} + +// Note this only supports updating an existing item. Goes through AISv3 +// code path where available. Not all uses of item->updateServer() can +// easily be switched to this paradigm. +void update_inventory_item( +	const LLUUID& item_id, +	const LLSD& updates, +	LLPointer<LLInventoryCallback> cb) +{ +	bool ais_ran = false; +	if (AISCommand::isAPIAvailable()) +	{ +		LLPointer<AISCommand> cmd_ptr = new UpdateItemCommand(item_id, updates, cb); +		ais_ran = cmd_ptr->run_command(); +	} +	if (!ais_ran) +	{ +		LLPointer<LLViewerInventoryItem> obj = gInventory.getItem(item_id); +		LL_DEBUGS("Inventory") << "item_id: [" << item_id << "] name " << (obj ? obj->getName() : "(NOT FOUND)") << LL_ENDL; +		if(obj) +		{ +			LLPointer<LLViewerInventoryItem> new_item(new LLViewerInventoryItem); +			new_item->copyViewerItem(obj); +			new_item->fromLLSD(updates,false); + +			LLMessageSystem* msg = gMessageSystem; +			msg->newMessageFast(_PREHASH_UpdateInventoryItem); +			msg->nextBlockFast(_PREHASH_AgentData); +			msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); +			msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); +			msg->addUUIDFast(_PREHASH_TransactionID, new_item->getTransactionID()); +			msg->nextBlockFast(_PREHASH_InventoryData); +			msg->addU32Fast(_PREHASH_CallbackID, 0); +			new_item->packMessage(msg); +			gAgent.sendReliableMessage(); + +			LLInventoryModel::LLCategoryUpdate up(new_item->getParentUUID(), 0); +			gInventory.accountForUpdate(up); +			gInventory.updateItem(new_item); +			if (cb) +			{ +				cb->fire(item_id); +			} +		} +	} +} + +void update_inventory_category( +	const LLUUID& cat_id, +	const LLSD& updates, +	LLPointer<LLInventoryCallback> cb) +{ +	LLPointer<LLViewerInventoryCategory> obj = gInventory.getCategory(cat_id); +	LL_DEBUGS("Inventory") << "cat_id: [" << cat_id << "] name " << (obj ? obj->getName() : "(NOT FOUND)") << LL_ENDL; +	if(obj) +	{ +		if (LLFolderType::lookupIsProtectedType(obj->getPreferredType())) +		{ +			LLNotificationsUtil::add("CannotModifyProtectedCategories"); +			return; +		} + +		LLPointer<LLViewerInventoryCategory> new_cat = new LLViewerInventoryCategory(obj); +		new_cat->fromLLSD(updates); +		// FIXME - restore this once the back-end work has been done. +		if (AISCommand::isAPIAvailable()) +		{ +			LLSD new_llsd = new_cat->asLLSD(); +			LLPointer<AISCommand> cmd_ptr = new UpdateCategoryCommand(cat_id, new_llsd, cb); +			cmd_ptr->run_command(); +		} +		else // no cap +		{ +			LLMessageSystem* msg = gMessageSystem; +			msg->newMessageFast(_PREHASH_UpdateInventoryFolder); +			msg->nextBlockFast(_PREHASH_AgentData); +			msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); +			msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); +			msg->nextBlockFast(_PREHASH_FolderData); +			new_cat->packMessage(msg); +			gAgent.sendReliableMessage(); + +			LLInventoryModel::LLCategoryUpdate up(new_cat->getParentUUID(), 0); +			gInventory.accountForUpdate(up); +			gInventory.updateCategory(new_cat); +			if (cb) +			{ +				cb->fire(cat_id); +			} +		} +	} +} + +void remove_inventory_items( +	LLInventoryObject::object_list_t& items_to_kill, +	LLPointer<LLInventoryCallback> cb) +{ +	for (LLInventoryObject::object_list_t::iterator it = items_to_kill.begin(); +		 it != items_to_kill.end(); +		 ++it) +	{ +		remove_inventory_item(*it, cb); +	} +} + +void remove_inventory_item( +	const LLUUID& item_id, +	LLPointer<LLInventoryCallback> cb) +{ +	LLPointer<LLInventoryObject> obj = gInventory.getItem(item_id); +	if (obj) +	{ +		remove_inventory_item(obj, cb); +	} +	else +	{ +		LL_DEBUGS("Inventory") << "item_id: [" << item_id << "] name " << "(NOT FOUND)" << LL_ENDL; +	} +} + +void remove_inventory_item( +	LLPointer<LLInventoryObject> obj, +	LLPointer<LLInventoryCallback> cb) +{ +	if(obj) +	{ +		const LLUUID item_id(obj->getUUID()); +		LL_DEBUGS("Inventory") << "item_id: [" << item_id << "] name " << obj->getName() << LL_ENDL; +		if (AISCommand::isAPIAvailable()) +		{ +			LLPointer<AISCommand> cmd_ptr = new RemoveItemCommand(item_id, cb); +			cmd_ptr->run_command(); +		} +		else // no cap +		{ +			LLMessageSystem* msg = gMessageSystem; +			msg->newMessageFast(_PREHASH_RemoveInventoryItem); +			msg->nextBlockFast(_PREHASH_AgentData); +			msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); +			msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());  +			msg->nextBlockFast(_PREHASH_InventoryData); +			msg->addUUIDFast(_PREHASH_ItemID, item_id); +			gAgent.sendReliableMessage(); + +			// Update inventory and call callback immediately since +			// message-based system has no callback mechanism (!) +			gInventory.onObjectDeletedFromServer(item_id); +			if (cb) +			{ +				cb->fire(item_id); +			} +		} +	} +	else +	{ +		// *TODO: Clean up callback? +		LL_WARNS() << "remove_inventory_item called for invalid or nonexistent item." << LL_ENDL; +	} +} + +class LLRemoveCategoryOnDestroy: public LLInventoryCallback +{ +public: +	LLRemoveCategoryOnDestroy(const LLUUID& cat_id, LLPointer<LLInventoryCallback> cb): +		mID(cat_id), +		mCB(cb) +	{ +	} +	/* virtual */ void fire(const LLUUID& item_id) {} +	~LLRemoveCategoryOnDestroy() +	{ +		LLInventoryModel::EHasChildren children = gInventory.categoryHasChildren(mID); +		if(children != LLInventoryModel::CHILDREN_NO) +		{ +			LL_WARNS() << "remove descendents failed, cannot remove category " << LL_ENDL; +		} +		else +		{ +			remove_inventory_category(mID, mCB); +		} +	} +private: +	LLUUID mID; +	LLPointer<LLInventoryCallback> mCB; +}; + +void remove_inventory_category( +	const LLUUID& cat_id, +	LLPointer<LLInventoryCallback> cb) +{ +	LL_DEBUGS("Inventory") << "cat_id: [" << cat_id << "] " << LL_ENDL; +	LLPointer<LLViewerInventoryCategory> obj = gInventory.getCategory(cat_id); +	if(obj) +	{ +		if(LLFolderType::lookupIsProtectedType(obj->getPreferredType())) +		{ +			LLNotificationsUtil::add("CannotRemoveProtectedCategories"); +			return; +		} +		if (AISCommand::isAPIAvailable()) +		{ +			LLPointer<AISCommand> cmd_ptr = new RemoveCategoryCommand(cat_id, cb); +			cmd_ptr->run_command(); +		} +		else // no cap +		{ +			// RemoveInventoryFolder does not remove children, so must +			// clear descendents first. +			LLInventoryModel::EHasChildren children = gInventory.categoryHasChildren(cat_id); +			if(children != LLInventoryModel::CHILDREN_NO) +			{ +				LL_DEBUGS("Inventory") << "Will purge descendents first before deleting category " << cat_id << LL_ENDL; +				LLPointer<LLInventoryCallback> wrap_cb = new LLRemoveCategoryOnDestroy(cat_id, cb);  +				purge_descendents_of(cat_id, wrap_cb); +				return; +			} + +			LLMessageSystem* msg = gMessageSystem; +			msg->newMessageFast(_PREHASH_RemoveInventoryFolder); +			msg->nextBlockFast(_PREHASH_AgentData); +			msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); +			msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); +			msg->nextBlockFast(_PREHASH_FolderData); +			msg->addUUIDFast(_PREHASH_FolderID, cat_id); +			gAgent.sendReliableMessage(); + +			// Update inventory and call callback immediately since +			// message-based system has no callback mechanism (!) +			gInventory.onObjectDeletedFromServer(cat_id); +			if (cb) +			{ +				cb->fire(cat_id); +			} +		} +	} +	else +	{ +		LL_WARNS() << "remove_inventory_category called for invalid or nonexistent item " << cat_id << LL_ENDL; +	} +} + +void remove_inventory_object( +	const LLUUID& object_id, +	LLPointer<LLInventoryCallback> cb) +{ +	if (gInventory.getCategory(object_id)) +	{ +		remove_inventory_category(object_id, cb); +	} +	else +	{ +		remove_inventory_item(object_id, cb); +	} +} + +// This is a method which collects the descendents of the id +// provided. If the category is not found, no action is +// taken. This method goes through the long winded process of +// cancelling any calling cards, removing server representation of +// folders, items, etc in a fairly efficient manner. +void purge_descendents_of(const LLUUID& id, LLPointer<LLInventoryCallback> cb) +{ +	LLInventoryModel::EHasChildren children = gInventory.categoryHasChildren(id); +	if(children == LLInventoryModel::CHILDREN_NO) +	{ +		LL_DEBUGS("Inventory") << "No descendents to purge for " << id << LL_ENDL; +		return; +	} +	LLPointer<LLViewerInventoryCategory> cat = gInventory.getCategory(id); +	if (cat.notNull()) +	{ +		if (LLClipboard::instance().hasContents() && LLClipboard::instance().isCutMode()) +		{ +			// Something on the clipboard is in "cut mode" and needs to be preserved +			LL_DEBUGS("Inventory") << "purge_descendents_of clipboard case " << cat->getName() +								   << " iterate and purge non hidden items" << LL_ENDL; +			LLInventoryModel::cat_array_t* categories; +			LLInventoryModel::item_array_t* items; +			// Get the list of direct descendants in tha categoy passed as argument +			gInventory.getDirectDescendentsOf(id, categories, items); +			std::vector<LLUUID> list_uuids; +			// Make a unique list with all the UUIDs of the direct descendants (items and categories are not treated differently) +			// Note: we need to do that shallow copy as purging things will invalidate the categories or items lists +			for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin(); it != categories->end(); ++it) +			{ +				list_uuids.push_back((*it)->getUUID()); +			} +			for (LLInventoryModel::item_array_t::const_iterator it = items->begin(); it != items->end(); ++it) +			{ +				list_uuids.push_back((*it)->getUUID()); +			} +			// Iterate through the list and only purge the UUIDs that are not on the clipboard +			for (std::vector<LLUUID>::const_iterator it = list_uuids.begin(); it != list_uuids.end(); ++it) +			{ +				if (!LLClipboard::instance().isOnClipboard(*it)) +				{ +					remove_inventory_object(*it, NULL); +				} +			} +		} +		else +		{ +			if (AISCommand::isAPIAvailable()) +			{ +				LLPointer<AISCommand> cmd_ptr = new PurgeDescendentsCommand(id, cb); +				cmd_ptr->run_command(); +			} +			else // no cap +			{ +				// Fast purge +				LL_DEBUGS("Inventory") << "purge_descendents_of fast case " << cat->getName() << LL_ENDL; + +				// send it upstream +				LLMessageSystem* msg = gMessageSystem; +				msg->newMessage("PurgeInventoryDescendents"); +				msg->nextBlock("AgentData"); +				msg->addUUID("AgentID", gAgent.getID()); +				msg->addUUID("SessionID", gAgent.getSessionID()); +				msg->nextBlock("InventoryData"); +				msg->addUUID("FolderID", id); +				gAgent.sendReliableMessage(); + +				// Update model immediately because there is no callback mechanism. +				gInventory.onDescendentsPurgedFromServer(id); +				if (cb) +				{ +					cb->fire(id); +				} +			} +		} +	} +} +  const LLUUID get_folder_by_itemtype(const LLInventoryItem *src)  {  	LLUUID retval = LLUUID::null; @@ -1301,6 +1760,53 @@ void create_new_item(const std::string& name,  }	 +void slam_inventory_folder(const LLUUID& folder_id, +						   const LLSD& contents, +						   LLPointer<LLInventoryCallback> cb) +{ +	if (AISCommand::isAPIAvailable()) +	{ +		LL_DEBUGS("Avatar") << "using AISv3 to slam folder, id " << folder_id +							<< " new contents: " << ll_pretty_print_sd(contents) << LL_ENDL; +		LLPointer<AISCommand> cmd_ptr = new SlamFolderCommand(folder_id, contents, cb); +		cmd_ptr->run_command(); +	} +	else // no cap +	{ +		LL_DEBUGS("Avatar") << "using item-by-item calls to slam folder, id " << folder_id +							<< " new contents: " << ll_pretty_print_sd(contents) << LL_ENDL; +		for (LLSD::array_const_iterator it = contents.beginArray(); +			 it != contents.endArray(); +			 ++it) +		{ +			const LLSD& item_contents = *it; +			LLViewerInventoryItem *item = new LLViewerInventoryItem; +			item->fromLLSD(item_contents); +			link_inventory_object(folder_id, item, cb); +		} +		remove_folder_contents(folder_id,false,cb); +	} +} + +void remove_folder_contents(const LLUUID& category, bool keep_outfit_links, +							LLPointer<LLInventoryCallback> cb) +{ +	LLInventoryModel::cat_array_t cats; +	LLInventoryModel::item_array_t items; +	gInventory.collectDescendents(category, cats, items, +								  LLInventoryModel::EXCLUDE_TRASH); +	for (S32 i = 0; i < items.size(); ++i) +	{ +		LLViewerInventoryItem *item = items.at(i); +		if (keep_outfit_links && (item->getActualType() == LLAssetType::AT_LINK_FOLDER)) +			continue; +		if (item->getIsLinkType()) +		{ +			remove_inventory_item(item->getUUID(), cb); +		} +	} +} +  const std::string NEW_LSL_NAME = "New Script"; // *TODO:Translate? (probably not)  const std::string NEW_NOTECARD_NAME = "New Note"; // *TODO:Translate? (probably not)  const std::string NEW_GESTURE_NAME = "New Gesture"; // *TODO:Translate? (probably not) @@ -1736,3 +2242,5 @@ BOOL LLViewerInventoryItem::regenerateLink()  	gInventory.notifyObservers();  	return TRUE;  } + + diff --git a/indra/newview/llviewerinventory.h b/indra/newview/llviewerinventory.h index d0dcf53b3f..b6bfb834af 100755 --- a/indra/newview/llviewerinventory.h +++ b/indra/newview/llviewerinventory.h @@ -118,14 +118,13 @@ public:  	void cloneViewerItem(LLPointer<LLViewerInventoryItem>& newitem) const;  	// virtual methods -	virtual void removeFromServer( void );  	virtual void updateParentOnServer(BOOL restamp) const;  	virtual void updateServer(BOOL is_new) const;  	void fetchFromServer(void) const; -	//virtual void packMessage(LLMessageSystem* msg) const; +	virtual void packMessage(LLMessageSystem* msg) const;  	virtual BOOL unpackMessage(LLMessageSystem* msg, const char* block, S32 block_num = 0); -	virtual BOOL unpackMessage(LLSD item); +	virtual BOOL unpackMessage(const LLSD& item);  	virtual BOOL importFile(LLFILE* fp);  	virtual BOOL importLegacyStream(std::istream& input_stream); @@ -139,7 +138,6 @@ public:  	void setComplete(BOOL complete) { mIsComplete = complete; }  	//void updateAssetOnServer() const; -	virtual void packMessage(LLMessageSystem* msg) const;  	virtual void setTransactionID(const LLTransactionID& transaction_id);  	struct comparePointers  	{ @@ -198,10 +196,11 @@ public:  	LLViewerInventoryCategory(const LLViewerInventoryCategory* other);  	void copyViewerCategory(const LLViewerInventoryCategory* other); -	virtual void removeFromServer();  	virtual void updateParentOnServer(BOOL restamp_children) const;  	virtual void updateServer(BOOL is_new) const; +	virtual void packMessage(LLMessageSystem* msg) const; +  	const LLUUID& getOwnerID() const { return mOwnerID; }  	// Version handling @@ -218,6 +217,8 @@ public:  	enum { DESCENDENT_COUNT_UNKNOWN = -1 };  	S32 getDescendentCount() const { return mDescendentCount; }  	void setDescendentCount(S32 descendents) { mDescendentCount = descendents; } +	// How many descendents do we currently have information for in the InventoryModel? +	S32 getViewerDescendentCount() const;  	// file handling on the viewer. These are not meant for anything  	// other than caching. @@ -225,6 +226,8 @@ public:  	bool importFileLocal(LLFILE* fp);  	void determineFolderType();  	void changeType(LLFolderType::EType new_folder_type); +	virtual void unpackMessage(LLMessageSystem* msg, const char* block, S32 block_num = 0); +	virtual BOOL unpackMessage(const LLSD& category);      // returns true if the category object will accept the incoming item      bool acceptItem(LLInventoryItem* inv_item); @@ -267,9 +270,11 @@ private:  };  typedef boost::function<void(const LLUUID&)> inventory_func_type; -void no_op_inventory_func(const LLUUID&); // A do-nothing inventory_func - +typedef boost::function<void(const LLSD&)> llsd_func_type;  typedef boost::function<void()> nullary_func_type; + +void no_op_inventory_func(const LLUUID&); // A do-nothing inventory_func +void no_op_llsd_func(const LLSD&); // likewise for LLSD  void no_op(); // A do-nothing nullary func.  // Shim between inventory callback and boost function/callable @@ -277,7 +282,7 @@ class LLBoostFuncInventoryCallback: public LLInventoryCallback  {  public: -	LLBoostFuncInventoryCallback(inventory_func_type fire_func, +	LLBoostFuncInventoryCallback(inventory_func_type fire_func = no_op_inventory_func,  								 nullary_func_type destroy_func = no_op):  		mFireFunc(fire_func),  		mDestroyFunc(destroy_func) @@ -351,14 +356,16 @@ void copy_inventory_item(  	const std::string& new_name,  	LLPointer<LLInventoryCallback> cb); -void link_inventory_item( -	const LLUUID& agent_id, -	const LLUUID& item_id, -	const LLUUID& parent_id, -	const std::string& new_name, -	const std::string& new_description, -	const LLAssetType::EType asset_type, -	LLPointer<LLInventoryCallback> cb); +// utility functions for inventory linking. +void link_inventory_object(const LLUUID& category, +			 LLConstPointer<LLInventoryObject> baseobj, +			 LLPointer<LLInventoryCallback> cb); +void link_inventory_object(const LLUUID& category, +			 const LLUUID& id, +			 LLPointer<LLInventoryCallback> cb); +void link_inventory_array(const LLUUID& category, +						  LLInventoryObject::const_object_list_t& baseobj_array, +						  LLPointer<LLInventoryCallback> cb);  void move_inventory_item(  	const LLUUID& agent_id, @@ -368,6 +375,44 @@ void move_inventory_item(  	const std::string& new_name,  	LLPointer<LLInventoryCallback> cb); +void update_inventory_item( +	LLViewerInventoryItem *update_item, +	LLPointer<LLInventoryCallback> cb); + +void update_inventory_item( +	const LLUUID& item_id, +	const LLSD& updates, +	LLPointer<LLInventoryCallback> cb); + +void update_inventory_category( +	const LLUUID& cat_id, +	const LLSD& updates, +	LLPointer<LLInventoryCallback> cb); + +void remove_inventory_items( +	LLInventoryObject::object_list_t& items, +	LLPointer<LLInventoryCallback> cb); + +void remove_inventory_item( +	LLPointer<LLInventoryObject> obj, +	LLPointer<LLInventoryCallback> cb); + +void remove_inventory_item( +	const LLUUID& item_id, +	LLPointer<LLInventoryCallback> cb); +	 +void remove_inventory_category( +	const LLUUID& cat_id, +	LLPointer<LLInventoryCallback> cb); +	 +void remove_inventory_object( +	const LLUUID& object_id, +	LLPointer<LLInventoryCallback> cb); + +void purge_descendents_of( +	const LLUUID& cat_id, +	LLPointer<LLInventoryCallback> cb); +  const LLUUID get_folder_by_itemtype(const LLInventoryItem *src);  void copy_inventory_from_notecard(const LLUUID& destination_id, @@ -382,4 +427,11 @@ void menu_create_inventory_item(LLInventoryPanel* root,  								const LLSD& userdata,  								const LLUUID& default_parent_uuid = LLUUID::null); +void slam_inventory_folder(const LLUUID& folder_id, +						   const LLSD& contents, +						   LLPointer<LLInventoryCallback> cb); + +void remove_folder_contents(const LLUUID& folder_id, bool keep_outfit_links, +							  LLPointer<LLInventoryCallback> cb); +  #endif // LL_LLVIEWERINVENTORY_H diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index a4e3c8cdbd..7aa0af5d93 100755 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -157,7 +157,7 @@ LLViewerMediaObserver::~LLViewerMediaObserver()  // on the Panel Land Media and to discover the MIME type  class LLMimeDiscoveryResponder : public LLHTTPClient::Responder  { -LOG_CLASS(LLMimeDiscoveryResponder); +	LOG_CLASS(LLMimeDiscoveryResponder);  public:  	LLMimeDiscoveryResponder( viewer_media_t media_impl)  		: mMediaImpl(media_impl), @@ -176,13 +176,19 @@ public:  		disconnectOwner();  	} -	virtual void completedHeader(U32 status, const std::string& reason, const LLSD& content) +private: +	/* virtual */ void httpCompleted()  	{ -		std::string media_type = content["content-type"].asString(); +		if (!isGoodStatus()) +		{ +			LL_WARNS() << dumpResponse() +					<< " [headers:" << getResponseHeaders() << "]" << LL_ENDL; +		} +		const std::string& media_type = getResponseHeader(HTTP_IN_HEADER_CONTENT_TYPE);  		std::string::size_type idx1 = media_type.find_first_of(";");  		std::string mime_type = media_type.substr(0, idx1); -		LL_DEBUGS() << "status is " << status << ", media type \"" << media_type << "\"" << LL_ENDL; +		LL_DEBUGS() << "status is " << getStatus() << ", media type \"" << media_type << "\"" << LL_ENDL;  		// 2xx status codes indicate success.  		// Most 4xx status codes are successful enough for our purposes. @@ -199,32 +205,27 @@ public:  //			)  		// We now no longer check the error code returned from the probe.  		// If we have a mime type, use it.  If not, default to the web plugin and let it handle error reporting. -		if(1) +		//if(1)  		{  			// The probe was successful.  			if(mime_type.empty())  			{  				// Some sites don't return any content-type header at all.  				// Treat an empty mime type as text/html. -				mime_type = "text/html"; +				mime_type = HTTP_CONTENT_TEXT_HTML;  			} -			 -			completeAny(status, mime_type);  		} -		else -		{ -			LL_WARNS() << "responder failed with status " << status << ", reason " << reason << LL_ENDL; -		 -			if(mMediaImpl) -			{ -				mMediaImpl->mMediaSourceFailed = true; -			} -		} - -	} +		//else +		//{ +		//	LL_WARNS() << "responder failed with status " << dumpResponse() << LL_ENDL; +		// +		//	if(mMediaImpl) +		//	{ +		//		mMediaImpl->mMediaSourceFailed = true; +		//	} +		//	return; +		//} -	void completeAny(U32 status, const std::string& mime_type) -	{  		// the call to initializeMedia may disconnect the responder, which will clear mMediaImpl.  		// Make a local copy so we can call loadURI() afterwards.  		LLViewerMediaImpl *impl = mMediaImpl; @@ -240,6 +241,7 @@ public:  		}  	} +public:  	void cancelRequest()  	{  		disconnectOwner(); @@ -268,7 +270,7 @@ public:  class LLViewerMediaOpenIDResponder : public LLHTTPClient::Responder  { -LOG_CLASS(LLViewerMediaOpenIDResponder); +	LOG_CLASS(LLViewerMediaOpenIDResponder);  public:  	LLViewerMediaOpenIDResponder( )  	{ @@ -278,23 +280,17 @@ public:  	{  	} -	/* virtual */ void completedHeader(U32 status, const std::string& reason, const LLSD& content) -	{ -		LL_DEBUGS("MediaAuth") << "status = " << status << ", reason = " << reason << LL_ENDL; -		LL_DEBUGS("MediaAuth") << content << LL_ENDL; -		std::string cookie = content["set-cookie"].asString(); -		 -		LLViewerMedia::openIDCookieResponse(cookie); -	} -  	/* virtual */ void completedRaw( -		U32 status, -		const std::string& reason,  		const LLChannelDescriptors& channels,  		const LLIOPipe::buffer_ptr_t& buffer)  	{ -		// This is just here to disable the default behavior (attempting to parse the response as llsd). -		// We don't care about the content of the response, only the set-cookie header. +		// We don't care about the content of the response, only the Set-Cookie header. +		LL_DEBUGS("MediaAuth") << dumpResponse()  +				<< " [headers:" << getResponseHeaders() << "]" << LL_ENDL; +		const std::string& cookie = getResponseHeader(HTTP_IN_HEADER_SET_COOKIE); +		 +		// *TODO: What about bad status codes?  Does this destroy previous cookies? +		LLViewerMedia::openIDCookieResponse(cookie);  	}  }; @@ -312,17 +308,23 @@ public:  	{  	} -	/* virtual */ void completedHeader(U32 status, const std::string& reason, const LLSD& content) +	 void completedRaw( +		const LLChannelDescriptors& channels, +		const LLIOPipe::buffer_ptr_t& buffer)  	{ -		LL_WARNS("MediaAuth") << "status = " << status << ", reason = " << reason << LL_ENDL; +		// We don't care about the content of the response, only the set-cookie header. +		LL_WARNS("MediaAuth") << dumpResponse()  +				<< " [headers:" << getResponseHeaders() << "]" << LL_ENDL; -		LLSD stripped_content = content; -		stripped_content.erase("set-cookie"); +		LLSD stripped_content = getResponseHeaders(); +		// *TODO: Check that this works. +		stripped_content.erase(HTTP_IN_HEADER_SET_COOKIE);  		LL_WARNS("MediaAuth") << stripped_content << LL_ENDL; -		std::string cookie = content["set-cookie"].asString(); +		const std::string& cookie = getResponseHeader(HTTP_IN_HEADER_SET_COOKIE);  		LL_DEBUGS("MediaAuth") << "cookie = " << cookie << LL_ENDL; +		// *TODO: What about bad status codes?  Does this destroy previous cookies?  		LLViewerMedia::getCookieStore()->setCookiesFromHost(cookie, mHost);  		// Set cookie for snapshot publishing. @@ -330,16 +332,6 @@ public:  		LLWebProfile::setAuthCookie(auth_cookie);  	} -	 void completedRaw( -		U32 status, -		const std::string& reason, -		const LLChannelDescriptors& channels, -		const LLIOPipe::buffer_ptr_t& buffer) -	{ -		// This is just here to disable the default behavior (attempting to parse the response as llsd). -		// We don't care about the content of the response, only the set-cookie header. -	} -  	std::string mHost;  }; @@ -1386,10 +1378,12 @@ void LLViewerMedia::removeCookie(const std::string &name, const std::string &dom  LLSD LLViewerMedia::getHeaders()  {  	LLSD headers = LLSD::emptyMap(); -	headers["Accept"] = "*/*"; -	headers["Content-Type"] = "application/xml"; -	headers["Cookie"] = sOpenIDCookie; -	headers["User-Agent"] = getCurrentUserAgent(); +	headers[HTTP_OUT_HEADER_ACCEPT] = "*/*"; +	// *TODO: Should this be 'application/llsd+xml' ? +	// *TODO: Should this even be set at all?   This header is only not overridden in 'GET' methods. +	headers[HTTP_OUT_HEADER_CONTENT_TYPE] = HTTP_CONTENT_XML; +	headers[HTTP_OUT_HEADER_COOKIE] = sOpenIDCookie; +	headers[HTTP_OUT_HEADER_USER_AGENT] = getCurrentUserAgent();  	return headers;  } @@ -1427,9 +1421,9 @@ void LLViewerMedia::setOpenIDCookie()  		// Do a web profile get so we can store the cookie   		LLSD headers = LLSD::emptyMap(); -		headers["Accept"] = "*/*"; -		headers["Cookie"] = sOpenIDCookie; -		headers["User-Agent"] = getCurrentUserAgent(); +		headers[HTTP_OUT_HEADER_ACCEPT] = "*/*"; +		headers[HTTP_OUT_HEADER_COOKIE] = sOpenIDCookie; +		headers[HTTP_OUT_HEADER_USER_AGENT] = getCurrentUserAgent();  		std::string profile_url = getProfileURL("");  		LLURL raw_profile_url( profile_url.c_str() ); @@ -1459,9 +1453,9 @@ void LLViewerMedia::openIDSetup(const std::string &openid_url, const std::string  	LLSD headers = LLSD::emptyMap();  	// Keep LLHTTPClient from adding an "Accept: application/llsd+xml" header -	headers["Accept"] = "*/*"; +	headers[HTTP_OUT_HEADER_ACCEPT] = "*/*";  	// and use the expected content-type for a post, instead of the LLHTTPClient::postRaw() default of "application/octet-stream" -	headers["Content-Type"] = "application/x-www-form-urlencoded"; +	headers[HTTP_OUT_HEADER_CONTENT_TYPE] = "application/x-www-form-urlencoded";  	// postRaw() takes ownership of the buffer and releases it later, so we need to allocate a new buffer here.  	size_t size = openid_token.size(); @@ -1533,7 +1527,7 @@ void LLViewerMedia::createSpareBrowserMediaSource()  		// The null owner will keep the browser plugin from fully initializing   		// (specifically, it keeps LLPluginClassMedia from negotiating a size change,   		// which keeps MediaPluginWebkit::initBrowserWindow from doing anything until we have some necessary data, like the background color) -		sSpareBrowserMediaSource = LLViewerMediaImpl::newSourceFromMediaType("text/html", NULL, 0, 0); +		sSpareBrowserMediaSource = LLViewerMediaImpl::newSourceFromMediaType(HTTP_CONTENT_TEXT_HTML, NULL, 0, 0);  	}  } @@ -2644,16 +2638,16 @@ void LLViewerMediaImpl::navigateInternal()  			//    Accept: application/llsd+xml  			// which is really not what we want.  			LLSD headers = LLSD::emptyMap(); -			headers["Accept"] = "*/*"; +			headers[HTTP_OUT_HEADER_ACCEPT] = "*/*";  			// Allow cookies in the response, to prevent a redirect loop when accessing join.secondlife.com -			headers["Cookie"] = ""; +			headers[HTTP_OUT_HEADER_COOKIE] = "";  			LLHTTPClient::getHeaderOnly( mMediaURL, new LLMimeDiscoveryResponder(this), headers, 10.0f);  		}  		else if("data" == scheme || "file" == scheme || "about" == scheme)  		{  			// FIXME: figure out how to really discover the type for these schemes  			// We use "data" internally for a text/html url for loading the login screen -			if(initializeMedia("text/html")) +			if(initializeMedia(HTTP_CONTENT_TEXT_HTML))  			{  				loadURI();  			} diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 9c08ec7e77..b23e23f32e 100755 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -7839,6 +7839,7 @@ void handle_buy_currency_test(void*)  	LLFloaterReg::showInstance("buy_currency_html", LLSD(url));  } +// SUNSHINE CLEANUP - is only the request update at the end needed now?  void handle_rebake_textures(void*)  {  	if (!isAgentAvatarValid()) return; diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 00d28a4307..0d1ffd2b51 100755 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -1010,7 +1010,12 @@ class LLOpenTaskOffer : public LLInventoryAddedObserver  protected:  	/*virtual*/ void done()  	{ -		for (uuid_vec_t::iterator it = mAdded.begin(); it != mAdded.end();) +		uuid_vec_t added; +		for(uuid_set_t::const_iterator it = gInventory.getAddedIDs().begin(); it != gInventory.getAddedIDs().end(); ++it) +		{ +			added.push_back(*it); +		} +		for (uuid_vec_t::iterator it = added.begin(); it != added.end();)  		{  			const LLUUID& item_uuid = *it;  			bool was_moved = false; @@ -1032,13 +1037,12 @@ protected:  			if (was_moved)  			{ -				it = mAdded.erase(it); +				it = added.erase(it);  			}  			else ++it;  		} -		open_inventory_offer(mAdded, ""); -		mAdded.clear(); +		open_inventory_offer(added, "");  	}   }; @@ -1047,8 +1051,12 @@ class LLOpenTaskGroupOffer : public LLInventoryAddedObserver  protected:  	/*virtual*/ void done()  	{ -		open_inventory_offer(mAdded, "group_offer"); -		mAdded.clear(); +		uuid_vec_t added; +		for(uuid_set_t::const_iterator it = gInventory.getAddedIDs().begin(); it != gInventory.getAddedIDs().end(); ++it) +		{ +			added.push_back(*it); +		} +		open_inventory_offer(added, "group_offer");  		gInventory.removeObserver(this);  		delete this;  	} @@ -4001,6 +4009,8 @@ void process_teleport_finish(LLMessageSystem* msg, void**)  	gAgent.setTeleportState( LLAgent::TELEPORT_MOVING );  	gAgent.setTeleportMessage(LLAgent::sTeleportProgressMessages["contacting"]); +	LL_DEBUGS("CrossingCaps") << "Calling setSeedCapability from process_teleport_finish(). Seed cap == " +			<< seedCap << LL_ENDL;  	regionp->setSeedCapability(seedCap);  	// Don't send camera updates to the new region until we're @@ -4116,10 +4126,6 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**)  		gAgent.setTeleportState( LLAgent::TELEPORT_START_ARRIVAL ); -		// set the appearance on teleport since the new sim does not -		// know what you look like. -		gAgent.sendAgentSetAppearance(); -  		if (isAgentAvatarValid())  		{  			// Set the new position @@ -4243,6 +4249,9 @@ void process_crossed_region(LLMessageSystem* msg, void**)  	send_complete_agent_movement(sim_host);  	LLViewerRegion* regionp = LLWorld::getInstance()->addRegion(region_handle, sim_host); + +	LL_DEBUGS("CrossingCaps") << "Calling setSeedCapability from process_crossed_region(). Seed cap == " +			<< seedCap << LL_ENDL;  	regionp->setSeedCapability(seedCap);  } diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 1dabe07942..7c60be7046 100755 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -56,6 +56,7 @@  #include "llaudiosourcevo.h"  #include "llagent.h"  #include "llagentcamera.h" +#include "llagentwearables.h"  #include "llbbox.h"  #include "llbox.h"  #include "llcylinder.h" @@ -152,6 +153,7 @@ LLViewerObject *LLViewerObject::createObject(const LLUUID &id, const LLPCode pco  			{  				gAgentAvatarp = new LLVOAvatarSelf(id, pcode, regionp);  				gAgentAvatarp->initInstance(); +				gAgentWearables.setAvatarObject(gAgentAvatarp);  			}  			else   			{ @@ -5502,6 +5504,28 @@ void LLViewerObject::clearDrawableState(U32 state, BOOL recursive)  	}  } +BOOL LLViewerObject::isDrawableState(U32 state, BOOL recursive) const +{ +	BOOL matches = FALSE; +	if (mDrawable) +	{ +		matches = mDrawable->isState(state); +	} +	if (recursive) +	{ +		for (child_list_t::const_iterator iter = mChildList.begin(); +			 (iter != mChildList.end()) && matches; iter++) +		{ +			LLViewerObject* child = *iter; +			matches &= child->isDrawableState(state, recursive); +		} +	} + +	return matches; +} + + +  //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!  // RN: these functions assume a 2-level hierarchy   //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index d92c00a6b2..bab107cc57 100755 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -415,6 +415,7 @@ public:  	void setDrawableState(U32 state, BOOL recursive = TRUE);  	void clearDrawableState(U32 state, BOOL recursive = TRUE); +	BOOL isDrawableState(U32 state, BOOL recursive = TRUE) const;  	// Called when the drawable shifts  	virtual void onShift(const LLVector4a &shift_vector)	{ } diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index 0e40db8504..7f5d2ac125 100755 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -796,6 +796,7 @@ void LLViewerObjectList::updateApparentAngles(LLAgent &agent)  class LLObjectCostResponder : public LLCurl::Responder  { +	LOG_CLASS(LLObjectCostResponder);  public:  	LLObjectCostResponder(const LLSD& object_ids)  		: mObjectIDs(object_ids) @@ -816,20 +817,19 @@ public:  		}  	} -	void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content) +private: +	/* virtual */ void httpFailure()  	{ -		LL_WARNS() -			<< "Transport error requesting object cost " -			<< "[status: " << statusNum << "]: " -			<< content << LL_ENDL; +		LL_WARNS() << dumpResponse() << LL_ENDL;  		// TODO*: Error message to user  		// For now just clear the request from the pending list  		clear_object_list_pending_requests();  	} -	void result(const LLSD& content) +	/* virtual */ void httpSuccess()  	{ +		const LLSD& content = getContent();  		if ( !content.isMap() || content.has("error") )  		{  			// Improper response or the request had an error, @@ -885,6 +885,7 @@ private:  class LLPhysicsFlagsResponder : public LLCurl::Responder  { +	LOG_CLASS(LLPhysicsFlagsResponder);  public:  	LLPhysicsFlagsResponder(const LLSD& object_ids)  		: mObjectIDs(object_ids) @@ -905,20 +906,19 @@ public:  		}  	} -	void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content) +private: +	/* virtual */ void httpFailure()  	{ -		LL_WARNS() -			<< "Transport error requesting object physics flags " -			<< "[status: " << statusNum << "]: " -			<< content << LL_ENDL; +		LL_WARNS() << dumpResponse() << LL_ENDL;  		// TODO*: Error message to user  		// For now just clear the request from the pending list  		clear_object_list_pending_requests();  	} -	void result(const LLSD& content) +	/* virtual void */ void httpSuccess()  	{ +		const LLSD& content = getContent();  		if ( !content.isMap() || content.has("error") )  		{  			// Improper response or the request had an error, diff --git a/indra/newview/llviewerparcelmedia.cpp b/indra/newview/llviewerparcelmedia.cpp index b55154f889..37b249dddd 100755 --- a/indra/newview/llviewerparcelmedia.cpp +++ b/indra/newview/llviewerparcelmedia.cpp @@ -99,7 +99,7 @@ void LLViewerParcelMedia::update(LLParcel* parcel)  			std::string mediaCurrentUrl = std::string( parcel->getMediaCurrentURL());  			// if we have a current (link sharing) url, use it instead -			if (mediaCurrentUrl != "" && parcel->getMediaType() == "text/html") +			if (mediaCurrentUrl != "" && parcel->getMediaType() == HTTP_CONTENT_TEXT_HTML)  			{  				mediaUrl = mediaCurrentUrl;  			} diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index e9af5213d8..b80969e8b3 100755 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -30,6 +30,7 @@  // linden libraries  #include "indra_constants.h" +#include "llaisapi.h"  #include "llavatarnamecache.h"		// name lookup cap url  #include "llfloaterreg.h"  #include "llmath.h" @@ -80,6 +81,11 @@  	#pragma warning(disable:4355)  #endif +// When we receive a base grant of capabilities that has a different number of  +// capabilities than the original base grant received for the region, print  +// out the two lists of capabilities for analysis. +//#define DEBUG_CAPS_GRANTS +  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. @@ -97,6 +103,8 @@ S32  LLViewerRegion::sNewObjectCreationThrottle = -1;  typedef std::map<std::string, std::string> CapabilityMap; +static void log_capabilities(const CapabilityMap &capmap); +  class LLViewerRegionImpl {  public:  	LLViewerRegionImpl(LLViewerRegion * region, LLHost const & host) @@ -164,7 +172,7 @@ public:  	CapabilityMap mCapabilities;  	CapabilityMap mSecondCapabilitiesTracker;  -	 +  	LLEventPoll* mEventPoll;  	S32 mSeedCapMaxAttempts; @@ -228,24 +236,30 @@ class BaseCapabilitiesComplete : public LLHTTPClient::Responder  {  	LOG_CLASS(BaseCapabilitiesComplete);  public: -    BaseCapabilitiesComplete(U64 region_handle, S32 id) +	BaseCapabilitiesComplete(U64 region_handle, S32 id)  		: mRegionHandle(region_handle), mID(id) -    { } +	{ }  	virtual ~BaseCapabilitiesComplete()  	{ } -    void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content) -    { -		LL_WARNS("AppInit", "Capabilities") << "[status:" << statusNum << ":] " << content << LL_ENDL; +	static BaseCapabilitiesComplete* build( U64 region_handle, S32 id ) +	{ +		return new BaseCapabilitiesComplete(region_handle, id); +	} + +private: +	/* virtual */void httpFailure() +	{ +		LL_WARNS("AppInit", "Capabilities") << dumpResponse() << LL_ENDL;  		LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle);  		if (regionp)  		{  			regionp->failedSeedCapability();  		} -    } +	} -    void result(const LLSD& content) -    { +	/* virtual */ void httpSuccess() +	{  		LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle);  		if(!regionp) //region was removed  		{ @@ -259,12 +273,19 @@ public:  			return ;  		} +		const LLSD& content = getContent(); +		if (!content.isMap()) +		{ +			failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); +			return; +		}  		LLSD::map_const_iterator iter;  		for(iter = content.beginMap(); iter != content.endMap(); ++iter)  		{  			regionp->setCapability(iter->first, iter->second); -			 -			LL_DEBUGS("AppInit", "Capabilities") << "got capability for " << iter->first << LL_ENDL; + +			LL_DEBUGS("AppInit", "Capabilities") << "got capability for "  +				<< iter->first << LL_ENDL;  			/* HACK we're waiting for the ServerReleaseNotes */  			if (iter->first == "ServerReleaseNotes" && regionp->getReleaseNotesRequested()) @@ -281,11 +302,6 @@ public:  		}  	} -    static BaseCapabilitiesComplete* build( U64 region_handle, S32 id ) -    { -		return new BaseCapabilitiesComplete(region_handle, id); -    } -  private:  	U64 mRegionHandle;  	S32 mID; @@ -302,19 +318,32 @@ public:  	virtual ~BaseCapabilitiesCompleteTracker()  	{ } -	void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content) +	static BaseCapabilitiesCompleteTracker* build( U64 region_handle ) +	{ +		return new BaseCapabilitiesCompleteTracker( region_handle ); +	} + +private: +	/* virtual */ void httpFailure()  	{ -		LL_WARNS() << "BaseCapabilitiesCompleteTracker error [status:" -				<< statusNum << "]: " << content << LL_ENDL; +		LL_WARNS() << dumpResponse() << LL_ENDL;  	} -	void result(const LLSD& content) +	/* virtual */ void httpSuccess()  	{  		LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle);  		if( !regionp )   		{ +			LL_WARNS("AppInit", "Capabilities") << "Received results for region that no longer exists!" << LL_ENDL;  			return ; -		}		 +		} + +		const LLSD& content = getContent(); +		if (!content.isMap()) +		{ +			failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); +			return; +		}  		LLSD::map_const_iterator iter;  		for(iter = content.beginMap(); iter != content.endMap(); ++iter)  		{ @@ -324,32 +353,46 @@ public:  		if ( regionp->getRegionImpl()->mCapabilities.size() != regionp->getRegionImpl()->mSecondCapabilitiesTracker.size() )  		{ -			LL_INFOS() << "BaseCapabilitiesCompleteTracker " << "sim " << regionp->getName() -				<< " sent duplicate seed caps that differs in size - most likely content. "  -				<< (S32) regionp->getRegionImpl()->mCapabilities.size() << " vs " << regionp->getRegionImpl()->mSecondCapabilitiesTracker.size() -				<< LL_ENDL;			 -			 -			//todo#add cap debug versus original check? -			/* -			CapabilityMap::const_iterator iter = regionp->getRegionImpl()->mCapabilities.begin(); -			while (iter!=regionp->getRegionImpl()->mCapabilities.end() ) +			LL_WARNS("AppInit", "Capabilities")  +				<< "Sim sent duplicate base caps that differ in size from what we initially received - most likely content. " +				<< "mCapabilities == " << regionp->getRegionImpl()->mCapabilities.size() +				<< " mSecondCapabilitiesTracker == " << regionp->getRegionImpl()->mSecondCapabilitiesTracker.size() +				<< LL_ENDL; +#ifdef DEBUG_CAPS_GRANTS +			LL_WARNS("AppInit", "Capabilities") +				<< "Initial Base capabilities: " << LL_ENDL; + +			log_capabilities(regionp->getRegionImpl()->mCapabilities); + +			LL_WARNS("AppInit", "Capabilities") +							<< "Latest base capabilities: " << LL_ENDL; + +			log_capabilities(regionp->getRegionImpl()->mSecondCapabilitiesTracker); + +#endif + +			if (regionp->getRegionImpl()->mSecondCapabilitiesTracker.size() > regionp->getRegionImpl()->mCapabilities.size() )  			{ -				LL_INFOS() << "BaseCapabilitiesCompleteTracker Original " << iter->first << " " << iter->second<<LL_ENDL; -				++iter; +				// *HACK Since we were granted more base capabilities in this grant request than the initial, replace +				// the old with the new. This shouldn't happen i.e. we should always get the same capabilities from a +				// sim. The simulator fix from SH-3895 should prevent it from happening, at least in the case of the +				// inventory api capability grants. + +				// Need to clear a std::map before copying into it because old keys take precedence. +				regionp->getRegionImplNC()->mCapabilities.clear(); +				regionp->getRegionImplNC()->mCapabilities = regionp->getRegionImpl()->mSecondCapabilitiesTracker;  			} -			*/ -			regionp->getRegionImplNC()->mSecondCapabilitiesTracker.clear();  		} - +		else +		{ +			LL_DEBUGS("CrossingCaps") << "Sim sent multiple base cap grants with matching sizes." << LL_ENDL; +		} +		regionp->getRegionImplNC()->mSecondCapabilitiesTracker.clear();  	} -	static BaseCapabilitiesCompleteTracker* build( U64 region_handle ) -	{ -		return new BaseCapabilitiesCompleteTracker( region_handle ); -	}  private: -	U64 mRegionHandle;	 +	U64 mRegionHandle;  }; @@ -369,7 +412,7 @@ LLViewerRegion::LLViewerRegion(const U64 &handle,  	mSimAccess( SIM_ACCESS_MIN ),  	mBillableFactor(1.0),  	mMaxTasks(DEFAULT_MAX_REGION_WIDE_PRIM_COUNT), -	mCentralBakeVersion(0), +	mCentralBakeVersion(1),  	mClassID(0),  	mCPURatio(0),  	mColoName("unknown"), @@ -2584,6 +2627,8 @@ void LLViewerRegion::unpackRegionHandshake()  	msg->nextBlock("RegionInfo");  	U32 flags = 0; +	flags |= REGION_HANDSHAKE_SUPPORTS_SELF_APPEARANCE; +  	if(sVOCacheCullingEnabled)  	{  		flags |= 0x00000001; //set the bit 0 to be 1 to ask sim to send all cacheable objects.		 @@ -2617,12 +2662,13 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)  	//capabilityNames.append("FacebookRedirect");  	if (gSavedSettings.getBOOL("UseHTTPInventory")) -	{ +	{	  		capabilityNames.append("FetchLib2");  		capabilityNames.append("FetchLibDescendents2");  		capabilityNames.append("FetchInventory2");  		capabilityNames.append("FetchInventoryDescendents2");  		capabilityNames.append("IncrementCOFVersion"); +		AISCommand::getCapabilityNames(capabilityNames);  	}  	capabilityNames.append("GetDisplayNames"); @@ -2637,7 +2683,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)  	capabilityNames.append("LandResources");  	capabilityNames.append("MapLayer");  	capabilityNames.append("MapLayerGod"); -	capabilityNames.append("MeshUploadFlag"); +	capabilityNames.append("MeshUploadFlag");	  	capabilityNames.append("NavMeshGenerationStatus");  	capabilityNames.append("NewFileAgentInventory");  	capabilityNames.append("ObjectMedia"); @@ -2678,7 +2724,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)  	capabilityNames.append("ViewerMetrics");  	capabilityNames.append("ViewerStartAuction");  	capabilityNames.append("ViewerStats"); -	 +  	// Please add new capabilities alphabetically to reduce  	// merge conflicts.  } @@ -2686,8 +2732,11 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)  void LLViewerRegion::setSeedCapability(const std::string& url)  {  	if (getCapability("Seed") == url) -    { -		//LL_WARNS() << "Ignoring duplicate seed capability" << LL_ENDL; +    {	 +		setCapabilityDebug("Seed", url); +		LL_DEBUGS("CrossingCaps") <<  "Received duplicate seed capability, posting to seed " << +				url	<< LL_ENDL; +  		//Instead of just returning we build up a second set of seed caps and compare them   		//to the "original" seed cap received and determine why there is problem!  		LLSD capabilityNames = LLSD::emptyArray(); @@ -2760,31 +2809,36 @@ 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 errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content) -    { -		LL_WARNS("AppInit", "SimulatorFeatures") << "[status:" << statusNum << "]: " << content << LL_ENDL; +	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) +	{ } + +	/* virtual */ void httpFailure() +	{ +		LL_WARNS("AppInit", "SimulatorFeatures") << dumpResponse() << LL_ENDL;  		retry(); -    } +	} -    void result(const LLSD& content) -    { +	/* virtual */ void httpSuccess() +	{  		LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle);  		if(!regionp) //region is removed or responder is not created.  		{ -			LL_WARNS("AppInit", "SimulatorFeatures") << "Received results for region that no longer exists!" << LL_ENDL; +			LL_WARNS("AppInit", "SimulatorFeatures")  +				<< "Received results for region that no longer exists!" << LL_ENDL;  			return ;  		} -		 + +		const LLSD& content = getContent(); +		if (!content.isMap()) +		{ +			failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); +			return; +		}  		regionp->setSimulatorFeatures(content);  	} -private:  	void retry()  	{  		if (mAttempt < mMaxAttempts) @@ -2794,7 +2848,7 @@ private:  			LLHTTPClient::get(mRetryURL, new SimulatorFeaturesReceived(*this), LLSD(), CAP_REQUEST_TIMEOUT);  		}  	} -	 +  	std::string mRetryURL;  	U64 mRegionHandle;  	S32 mAttempt; @@ -2831,7 +2885,16 @@ void LLViewerRegion::setCapability(const std::string& name, const std::string& u  void LLViewerRegion::setCapabilityDebug(const std::string& name, const std::string& url)  { -	mImpl->mSecondCapabilitiesTracker[name] = url; +	// Continue to not add certain caps, as we do in setCapability. This is so they match up when we check them later. +	if ( ! ( name == "EventQueueGet" || name == "UntrustedSimulatorMessage" || name == "SimulatorFeatures" ) ) +	{ +		mImpl->mSecondCapabilitiesTracker[name] = url; +		if(name == "GetTexture") +		{ +			mHttpUrl = url ; +		} +	} +  }  bool LLViewerRegion::isSpecialCapabilityName(const std::string &name) @@ -2843,7 +2906,7 @@ std::string LLViewerRegion::getCapability(const std::string& name) const  {  	if (!capabilitiesReceived() && (name!=std::string("Seed")) && (name!=std::string("ObjectMedia")))  	{ -		LL_WARNS() << "getCapability called before caps received" << LL_ENDL; +		LL_WARNS() << "getCapability called before caps received for " << name << LL_ENDL;  	}  	CapabilityMap::const_iterator iter = mImpl->mCapabilities.find(name); @@ -2855,6 +2918,22 @@ std::string LLViewerRegion::getCapability(const std::string& name) const  	return iter->second;  } +bool LLViewerRegion::isCapabilityAvailable(const std::string& name) const +{ +	if (!capabilitiesReceived() && (name!=std::string("Seed")) && (name!=std::string("ObjectMedia"))) +	{ +		LL_WARNS() << "isCapabilityAvailable called before caps received for " << name << LL_ENDL; +	} +	 +	CapabilityMap::const_iterator iter = mImpl->mCapabilities.find(name); +	if(iter == mImpl->mCapabilities.end()) +	{ +		return false; +	} + +	return true; +} +  bool LLViewerRegion::capabilitiesReceived() const  {  	return mCapabilitiesReceived; @@ -2882,16 +2961,7 @@ boost::signals2::connection LLViewerRegion::setCapabilitiesReceivedCallback(cons  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()) -		{ -			LL_INFOS() << iter->first << " URL is " << iter->second << LL_ENDL; -		} -	} -	LL_INFOS() << "Dumped " << count << " entries." << LL_ENDL; +	log_capabilities(mImpl->mCapabilities);  }  LLSpatialPartition* LLViewerRegion::getSpatialPartition(U32 type) @@ -2983,7 +3053,21 @@ bool LLViewerRegion::dynamicPathfindingEnabled() const  	return ( mSimulatorFeatures.has("DynamicPathfindingEnabled") &&  			 mSimulatorFeatures["DynamicPathfindingEnabled"].asBoolean());  } +/* Static Functions */ +void log_capabilities(const CapabilityMap &capmap) +{ +	S32 count = 0; +	CapabilityMap::const_iterator iter; +	for (iter = capmap.begin(); iter != capmap.end(); ++iter, ++count) +	{ +		if (!iter->second.empty()) +		{ +			LL_INFOS() << "log_capabilities: " << iter->first << " URL is " << iter->second << LL_ENDL; +		} +	} +	LL_INFOS() << "log_capabilities: Dumped " << count << " entries." << LL_ENDL; +}  void LLViewerRegion::resetMaterialsCapThrottle()  {  	F32 requests_per_sec = 	1.0f; // original default; @@ -3028,3 +3112,4 @@ U32 LLViewerRegion::getMaxMaterialsPerTransaction() const  } + diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h index 00d3900a88..1e225553b8 100755 --- a/indra/newview/llviewerregion.h +++ b/indra/newview/llviewerregion.h @@ -48,6 +48,8 @@  #define WATER 2  const U32	MAX_OBJECT_CACHE_ENTRIES = 50000; +// Region handshake flags +const U32 REGION_HANDSHAKE_SUPPORTS_SELF_APPEARANCE = 1U << 2;  class LLEventPoll;  class LLVLComposition; @@ -255,6 +257,7 @@ public:  	S32 getNumSeedCapRetries();  	void setCapability(const std::string& name, const std::string& url);  	void setCapabilityDebug(const std::string& name, const std::string& url); +	bool isCapabilityAvailable(const std::string& name) const;  	// implements LLCapabilityProvider      virtual std::string getCapability(const std::string& name) const; diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp index d5ae2d1030..f60829e9e8 100755 --- a/indra/newview/llviewerstats.cpp +++ b/indra/newview/llviewerstats.cpp @@ -412,18 +412,19 @@ void update_statistics()  class ViewerStatsResponder : public LLHTTPClient::Responder  { +	LOG_CLASS(ViewerStatsResponder);  public: -    ViewerStatsResponder() { } +	ViewerStatsResponder() { } -    void error(U32 statusNum, const std::string& reason) -    { -		LL_INFOS() << "ViewerStatsResponder::error " << statusNum << " " -				<< reason << LL_ENDL; -    } +private: +	/* virtual */ void httpFailure() +	{ +		LL_WARNS() << dumpResponse() << LL_ENDL; +	} -    void result(const LLSD& content) -    { -		LL_INFOS() << "ViewerStatsResponder::result" << LL_ENDL; +	/* virtual */ void httpSuccess() +	{ +		LL_INFOS() << "OK" << LL_ENDL;  	}  }; @@ -622,44 +623,28 @@ void send_stats()  	LLViewerStats::instance().getRecording().resume();  } -LLFrameTimer& LLViewerStats::PhaseMap::getPhaseTimer(const std::string& phase_name) +LLTimer& LLViewerStats::PhaseMap::getPhaseTimer(const std::string& phase_name)  {  	phase_map_t::iterator iter = mPhaseMap.find(phase_name);  	if (iter == mPhaseMap.end())  	{ -		LLFrameTimer timer; +		LLTimer timer;  		mPhaseMap[phase_name] = timer;  	} -	LLFrameTimer& timer = mPhaseMap[phase_name]; +	LLTimer& timer = mPhaseMap[phase_name];  	return timer;  }  void LLViewerStats::PhaseMap::startPhase(const std::string& phase_name)  { -	LLFrameTimer& timer = getPhaseTimer(phase_name); -	LL_DEBUGS() << "startPhase " << phase_name << LL_ENDL; -	timer.unpause(); -} - -void LLViewerStats::PhaseMap::stopAllPhases() -{ -	for (phase_map_t::iterator iter = mPhaseMap.begin(); -		 iter != mPhaseMap.end(); ++iter) -	{ -		const std::string& phase_name = iter->first; -		if (iter->second.getStarted()) -		{ -			// Going from started to paused state - record stats. -			recordPhaseStat(phase_name,iter->second.getElapsedTimeF32()); -		} -		LL_DEBUGS() << "stopPhase (all) " << phase_name << LL_ENDL; -		iter->second.pause(); -	} +	LLTimer& timer = getPhaseTimer(phase_name); +	timer.start(); +	//LL_DEBUGS("Avatar") << "startPhase " << phase_name << LL_ENDL;  }  void LLViewerStats::PhaseMap::clearPhases()  { -	LL_DEBUGS() << "clearPhases" << LL_ENDL; +	//LL_DEBUGS("Avatar") << "clearPhases" << LL_ENDL;  	mPhaseMap.clear();  } @@ -684,7 +669,6 @@ LLViewerStats::PhaseMap::PhaseMap()  {  } -  void LLViewerStats::PhaseMap::stopPhase(const std::string& phase_name)  {  	phase_map_t::iterator iter = mPhaseMap.find(phase_name); @@ -697,6 +681,7 @@ void LLViewerStats::PhaseMap::stopPhase(const std::string& phase_name)  		}  	}  } +  // static  LLViewerStats::StatsAccumulator& LLViewerStats::PhaseMap::getPhaseStats(const std::string& phase_name)  { @@ -720,14 +705,18 @@ void LLViewerStats::PhaseMap::recordPhaseStat(const std::string& phase_name, F32  bool LLViewerStats::PhaseMap::getPhaseValues(const std::string& phase_name, F32& elapsed, bool& completed)  {  	phase_map_t::iterator iter = mPhaseMap.find(phase_name); +	bool found = false;  	if (iter != mPhaseMap.end())  	{ +		found = true;  		elapsed =  iter->second.getElapsedTimeF32();  		completed = !iter->second.getStarted(); -		return true; +		//LL_DEBUGS("Avatar") << " phase_name " << phase_name << " elapsed " << elapsed << " completed " << completed << " timer addr " << (S32)(&iter->second) << LL_ENDL;  	}  	else  	{ -		return false; +		//LL_DEBUGS("Avatar") << " phase_name " << phase_name << " NOT FOUND"  << LL_ENDL;  	} + +	return found;  } diff --git a/indra/newview/llviewerstats.h b/indra/newview/llviewerstats.h index 0d959ed034..7843652589 100755 --- a/indra/newview/llviewerstats.h +++ b/indra/newview/llviewerstats.h @@ -342,7 +342,7 @@ public:  	// Phase tracking (originally put in for avatar rezzing), tracking  	// progress of active/completed phases for activities like outfit changing. -	typedef std::map<std::string,LLFrameTimer>	phase_map_t; +	typedef std::map<std::string,LLTimer>	phase_map_t;  	typedef std::map<std::string,StatsAccumulator>	phase_stats_t;  	class PhaseMap  	{ @@ -351,11 +351,10 @@ public:  		static phase_stats_t sStats;  	public:  		PhaseMap(); -		LLFrameTimer& 	getPhaseTimer(const std::string& phase_name); +		LLTimer& 		getPhaseTimer(const std::string& phase_name);  		bool 			getPhaseValues(const std::string& phase_name, F32& elapsed, bool& completed);  		void			startPhase(const std::string& phase_name);  		void			stopPhase(const std::string& phase_name); -		void			stopAllPhases();  		void			clearPhases();  		LLSD			asLLSD();  		static StatsAccumulator& getPhaseStats(const std::string& phase_name); diff --git a/indra/newview/llviewertexlayer.cpp b/indra/newview/llviewertexlayer.cpp index 62e8da81ec..65ba3fb6e5 100755 --- a/indra/newview/llviewertexlayer.cpp +++ b/indra/newview/llviewertexlayer.cpp @@ -37,7 +37,6 @@  #include "llglslshader.h"  #include "llvoavatarself.h"  #include "pipeline.h" -#include "llassetuploadresponders.h"  #include "llviewercontrol.h"  static const S32 BAKE_UPLOAD_ATTEMPTS = 7; @@ -46,22 +45,6 @@ static const F32 BAKE_UPLOAD_RETRY_DELAY = 2.f; // actual delay grows by power o  // runway consolidate  extern std::string self_av_string(); - -//----------------------------------------------------------------------------- -// LLBakedUploadData() -//----------------------------------------------------------------------------- -LLBakedUploadData::LLBakedUploadData(const LLVOAvatarSelf* avatar, -									 LLViewerTexLayerSet* layerset, -									 const LLUUID& id, -									 bool highest_res) : -	mAvatar(avatar), -	mTexLayerSet(layerset), -	mID(id), -	mStartTime(LLFrameTimer::getTotalTime()),		// Record starting time -	mIsHighestRes(highest_res) -{  -} -  //-----------------------------------------------------------------------------  // LLViewerTexLayerSetBuffer  // The composite image that a LLViewerTexLayerSet writes to.  Each LLViewerTexLayerSet has one. @@ -75,15 +58,10 @@ LLViewerTexLayerSetBuffer::LLViewerTexLayerSetBuffer(LLTexLayerSet* const owner,  	// ORDER_LAST => must render these after the hints are created.  	LLTexLayerSetBuffer(owner),  	LLViewerDynamicTexture( width, height, 4, LLViewerDynamicTexture::ORDER_LAST, TRUE ),  -	mUploadPending(FALSE), // Not used for any logic here, just to sync sending of updates -	mNeedsUpload(FALSE), -	mNumLowresUploads(0), -	mUploadFailCount(0),  	mNeedsUpdate(TRUE),  	mNumLowresUpdates(0)  {  	LLViewerTexLayerSetBuffer::sGLByteCount += getSize(); -	mNeedsUploadTimer.start();  	mNeedsUpdateTimer.start();  } @@ -126,33 +104,6 @@ void LLViewerTexLayerSetBuffer::requestUpdate()  	restartUpdateTimer();  	mNeedsUpdate = TRUE;  	mNumLowresUpdates = 0; -	// If we're in the middle of uploading a baked texture, we don't care about it any more. -	// When it's downloaded, ignore it. -	mUploadID.setNull(); -} - -void LLViewerTexLayerSetBuffer::requestUpload() -{ -	conditionalRestartUploadTimer(); -	mNeedsUpload = TRUE; -	mNumLowresUploads = 0; -	mUploadPending = TRUE; -} - -void LLViewerTexLayerSetBuffer::conditionalRestartUploadTimer() -{ -	// If we requested a new upload but haven't even uploaded -	// a low res version of our last upload request, then -	// keep the timer ticking instead of resetting it. -	if (mNeedsUpload && (mNumLowresUploads == 0)) -	{ -		mNeedsUploadTimer.unpause(); -	} -	else -	{ -		mNeedsUploadTimer.reset(); -		mNeedsUploadTimer.start(); -	}  }  void LLViewerTexLayerSetBuffer::restartUpdateTimer() @@ -161,25 +112,16 @@ void LLViewerTexLayerSetBuffer::restartUpdateTimer()  	mNeedsUpdateTimer.start();  } -void LLViewerTexLayerSetBuffer::cancelUpload() -{ -	mNeedsUpload = FALSE; -	mUploadPending = FALSE; -	mNeedsUploadTimer.pause(); -	mUploadRetryTimer.reset(); -} -  // virtual  BOOL LLViewerTexLayerSetBuffer::needsRender()  {  	llassert(mTexLayerSet->getAvatarAppearance() == gAgentAvatarp);  	if (!isAgentAvatarValid()) return FALSE; -	const BOOL upload_now = mNeedsUpload && isReadyToUpload();  	const BOOL update_now = mNeedsUpdate && isReadyToUpdate(); -	// Don't render if we don't want to (or aren't ready to) upload or update. -	if (!(update_now || upload_now)) +	// Don't render if we don't want to (or aren't ready to) update. +	if (!update_now)  	{  		return FALSE;  	} @@ -190,11 +132,10 @@ BOOL LLViewerTexLayerSetBuffer::needsRender()  		return FALSE;  	} -	// Don't render if we are trying to create a shirt texture but aren't wearing a skirt. +	// Don't render if we are trying to create a skirt texture but aren't wearing a skirt.  	if (gAgentAvatarp->getBakedTE(getViewerTexLayerSet()) == LLAvatarAppearanceDefines::TEX_SKIRT_BAKED &&   		!gAgentAvatarp->isWearingWearableType(LLWearableType::WT_SKIRT))  	{ -		cancelUpload();  		return FALSE;  	} @@ -222,36 +163,7 @@ void LLViewerTexLayerSetBuffer::postRenderTexLayerSet(BOOL success)  // virtual  void LLViewerTexLayerSetBuffer::midRenderTexLayerSet(BOOL success)  { -	// do we need to upload, and do we have sufficient data to create an uploadable composite? -	// TODO: When do we upload the texture if gAgent.mNumPendingQueries is non-zero? -	const BOOL upload_now = mNeedsUpload && isReadyToUpload();  	const BOOL update_now = mNeedsUpdate && isReadyToUpdate(); - -	if(upload_now) -	{ -		if (!success) -		{ -			LL_INFOS() << "Failed attempt to bake " << mTexLayerSet->getBodyRegionName() << LL_ENDL; -			mUploadPending = FALSE; -		} -		else -		{ -			LLViewerTexLayerSet* layer_set = getViewerTexLayerSet(); -			if (layer_set->isVisible()) -			{ -				layer_set->getAvatar()->debugBakedTextureUpload(layer_set->getBakedTexIndex(), FALSE); // FALSE for start of upload, TRUE for finish. -				doUpload(); -			} -			else -			{ -				mUploadPending = FALSE; -				mNeedsUpload = FALSE; -				mNeedsUploadTimer.pause(); -				layer_set->getAvatar()->setNewBakedTexture(layer_set->getBakedTexIndex(),IMG_INVISIBLE); -			} -		} -	} -	  	if (update_now)  	{  		doUpdate(); @@ -267,60 +179,6 @@ BOOL LLViewerTexLayerSetBuffer::isInitialized(void) const  	return mGLTexturep.notNull() && mGLTexturep->isGLTextureCreated();  } -BOOL LLViewerTexLayerSetBuffer::uploadPending() const -{ -	return mUploadPending; -} - -BOOL LLViewerTexLayerSetBuffer::uploadNeeded() const -{ -	return mNeedsUpload; -} - -BOOL LLViewerTexLayerSetBuffer::uploadInProgress() const -{ -	return !mUploadID.isNull(); -} - -BOOL LLViewerTexLayerSetBuffer::isReadyToUpload() const -{ -	if (!gAgentQueryManager.hasNoPendingQueries()) return FALSE; // Can't upload if there are pending queries. -	if (isAgentAvatarValid() && gAgentAvatarp->isEditingAppearance()) return FALSE; // Don't upload if avatar is being edited. - -	BOOL ready = FALSE; -	if (getViewerTexLayerSet()->isLocalTextureDataFinal()) -	{ -		// If we requested an upload and have the final LOD ready, upload (or wait a while if this is a retry) -		if (mUploadFailCount == 0) -		{ -			ready = TRUE; -		} -		else -		{ -			ready = mUploadRetryTimer.getElapsedTimeF32() >= BAKE_UPLOAD_RETRY_DELAY * (1 << (mUploadFailCount - 1)); -		} -	} -	else -	{ -		// Upload if we've hit a timeout.  Upload is a pretty expensive process so we need to make sure -		// we aren't doing uploads too frequently. -		const U32 texture_timeout = gSavedSettings.getU32("AvatarBakedTextureUploadTimeout"); -		if (texture_timeout != 0) -		{ -			// The timeout period increases exponentially between every lowres upload in order to prevent -			// spamming the server with frequent uploads. -			const U32 texture_timeout_threshold = texture_timeout*(1 << mNumLowresUploads); - -			// If we hit our timeout and have textures available at even lower resolution, then upload. -			const BOOL is_upload_textures_timeout = mNeedsUploadTimer.getElapsedTimeF32() >= texture_timeout_threshold; -			const BOOL has_lower_lod = getViewerTexLayerSet()->isLocalTextureDataAvailable(); -			ready = has_lower_lod && is_upload_textures_timeout; -		} -	} - -	return ready; -} -  BOOL LLViewerTexLayerSetBuffer::isReadyToUpdate() const  {  	// If we requested an update and have the final LOD ready, then update. @@ -358,159 +216,6 @@ BOOL LLViewerTexLayerSetBuffer::requestUpdateImmediate()  	return result;  } -// Create the baked texture, send it out to the server, then wait for it to come -// back so we can switch to using it. -void LLViewerTexLayerSetBuffer::doUpload() -{ -	LLViewerTexLayerSet* layer_set = getViewerTexLayerSet(); -	LL_DEBUGS("Avatar") << "Uploading baked " << layer_set->getBodyRegionName() << LL_ENDL; -	add(LLStatViewer::TEX_BAKES, 1); - -	// Don't need caches since we're baked now.  (note: we won't *really* be baked  -	// until this image is sent to the server and the Avatar Appearance message is received.) -	layer_set->deleteCaches(); - -	// Get the COLOR information from our texture -	U8* baked_color_data = new U8[ mFullWidth * mFullHeight * 4 ]; -	glReadPixels(mOrigin.mX, mOrigin.mY, mFullWidth, mFullHeight, GL_RGBA, GL_UNSIGNED_BYTE, baked_color_data ); -	stop_glerror(); - -	// Get the MASK information from our texture -	LLGLSUIDefault gls_ui; -	LLPointer<LLImageRaw> baked_mask_image = new LLImageRaw(mFullWidth, mFullHeight, 1 ); -	U8* baked_mask_data = baked_mask_image->getData();  -	layer_set->gatherMorphMaskAlpha(baked_mask_data, -									mOrigin.mX, mOrigin.mY, -									mFullWidth, mFullHeight); - - -	// Create the baked image from our color and mask information -	const S32 baked_image_components = 5; // red green blue [bump] clothing -	LLPointer<LLImageRaw> baked_image = new LLImageRaw( mFullWidth, mFullHeight, baked_image_components ); -	U8* baked_image_data = baked_image->getData(); -	S32 i = 0; -	for (S32 u=0; u < mFullWidth; u++) -	{ -		for (S32 v=0; v < mFullHeight; v++) -		{ -			baked_image_data[5*i + 0] = baked_color_data[4*i + 0]; -			baked_image_data[5*i + 1] = baked_color_data[4*i + 1]; -			baked_image_data[5*i + 2] = baked_color_data[4*i + 2]; -			baked_image_data[5*i + 3] = baked_color_data[4*i + 3]; // alpha should be correct for eyelashes. -			baked_image_data[5*i + 4] = baked_mask_data[i]; -			i++; -		} -	} -	 -	LLPointer<LLImageJ2C> compressedImage = new LLImageJ2C; -	const char* comment_text = LINDEN_J2C_COMMENT_PREFIX "RGBHM"; // writes into baked_color_data. 5 channels (rgb, heightfield/alpha, mask) -	if (compressedImage->encode(baked_image, comment_text)) -	{ -		LLTransactionID tid; -		tid.generate(); -		const LLAssetID asset_id = tid.makeAssetID(gAgent.getSecureSessionID()); -		if (LLVFile::writeFile(compressedImage->getData(), compressedImage->getDataSize(), -							   gVFS, asset_id, LLAssetType::AT_TEXTURE)) -		{ -			// Read back the file and validate. -			BOOL valid = FALSE; -			LLPointer<LLImageJ2C> integrity_test = new LLImageJ2C; -			S32 file_size = 0; -			LLVFile file(gVFS, asset_id, LLAssetType::AT_TEXTURE); -			file_size = file.getSize(); -			U8* data = integrity_test->allocateData(file_size); -			file.read(data, file_size); -			if (data) -			{ -				valid = integrity_test->validate(data, file_size); // integrity_test will delete 'data' -			} -			else -			{ -				integrity_test->setLastError("Unable to read entire file"); -			} -			 -			if (valid) -			{ -				const bool highest_lod = layer_set->isLocalTextureDataFinal(); -				// Baked_upload_data is owned by the responder and deleted after the request completes. -				LLBakedUploadData* baked_upload_data = new LLBakedUploadData(gAgentAvatarp,  -																			 layer_set,  -																			 asset_id, -																			 highest_lod); -				// upload ID is used to avoid overlaps, e.g. when the user rapidly makes two changes outside of Face Edit. -				mUploadID = asset_id; - -				// Upload the image -				const std::string url = gAgent.getRegion()->getCapability("UploadBakedTexture"); -				if(!url.empty() -					&& !LLPipeline::sForceOldBakedUpload // toggle debug setting UploadBakedTexOld to change between the new caps method and old method -					&& (mUploadFailCount < (BAKE_UPLOAD_ATTEMPTS - 1))) // Try last ditch attempt via asset store if cap upload is failing. -				{ -					LLSD body = LLSD::emptyMap(); -					// The responder will call LLViewerTexLayerSetBuffer::onTextureUploadComplete() -					LLHTTPClient::post(url, body, new LLSendTexLayerResponder(body, mUploadID, LLAssetType::AT_TEXTURE, baked_upload_data)); -					LL_INFOS() << "Baked texture upload via capability of " << mUploadID << " to " << url << LL_ENDL; -				}  -				else -				{ -					gAssetStorage->storeAssetData(tid, -												  LLAssetType::AT_TEXTURE, -												  LLViewerTexLayerSetBuffer::onTextureUploadComplete, -												  baked_upload_data, -												  TRUE,		// temp_file -												  TRUE,		// is_priority -												  TRUE);	// store_local -					LL_INFOS() << "Baked texture upload via Asset Store." <<  LL_ENDL; -				} - -				if (highest_lod) -				{ -					// Sending the final LOD for the baked texture.  All done, pause  -					// the upload timer so we know how long it took. -					mNeedsUpload = FALSE; -					mNeedsUploadTimer.pause(); -				} -				else -				{ -					// Sending a lower level LOD for the baked texture.  Restart the upload timer. -					mNumLowresUploads++; -					mNeedsUploadTimer.unpause(); -					mNeedsUploadTimer.reset(); -				} - -				// Print out notification that we uploaded this texture. -				if (gSavedSettings.getBOOL("DebugAvatarRezTime")) -				{ -					const std::string lod_str = highest_lod ? "HighRes" : "LowRes"; -					LLSD args; -					args["EXISTENCE"] = llformat("%d",(U32)layer_set->getAvatar()->debugGetExistenceTimeElapsedF32()); -					args["TIME"] = llformat("%d",(U32)mNeedsUploadTimer.getElapsedTimeF32()); -					args["BODYREGION"] = layer_set->getBodyRegionName(); -					args["RESOLUTION"] = lod_str; -					LLNotificationsUtil::add("AvatarRezSelfBakedTextureUploadNotification",args); -					LL_DEBUGS("Avatar") << self_av_string() << "Uploading [ name: " << layer_set->getBodyRegionName() << " res:" << lod_str << " time:" << (U32)mNeedsUploadTimer.getElapsedTimeF32() << " ]" << LL_ENDL; -				} -			} -			else -			{ -				// The read back and validate operation failed.  Remove the uploaded file. -				mUploadPending = FALSE; -				LLVFile file(gVFS, asset_id, LLAssetType::AT_TEXTURE, LLVFile::WRITE); -				file.remove(); -				LL_INFOS() << "Unable to create baked upload file (reason: corrupted)." << LL_ENDL; -			} -		} -	} -	else -	{ -		// The VFS write file operation failed. -		mUploadPending = FALSE; -		LL_INFOS() << "Unable to create baked upload file (reason: failed to write file)" << LL_ENDL; -	} - -	delete [] baked_color_data; -} -  // Mostly bookkeeping; don't need to actually "do" anything since  // render() will actually do the update.  void LLViewerTexLayerSetBuffer::doUpdate() @@ -547,82 +252,6 @@ void LLViewerTexLayerSetBuffer::doUpdate()  	}  } -// static -void LLViewerTexLayerSetBuffer::onTextureUploadComplete(const LLUUID& uuid, -												  void* userdata, -												  S32 result, -												  LLExtStat ext_status) // StoreAssetData callback (not fixed) -{ -	LLBakedUploadData* baked_upload_data = (LLBakedUploadData*)userdata; - -	if (isAgentAvatarValid() && -		!gAgentAvatarp->isDead() && -		(baked_upload_data->mAvatar == gAgentAvatarp) && // Sanity check: only the user's avatar should be uploading textures. -		(baked_upload_data->mTexLayerSet->hasComposite())) -	{ -		LLViewerTexLayerSetBuffer* layerset_buffer = baked_upload_data->mTexLayerSet->getViewerComposite(); -		S32 failures = layerset_buffer->mUploadFailCount; -		layerset_buffer->mUploadFailCount = 0; - -		if (layerset_buffer->mUploadID.isNull()) -		{ -			// The upload got canceled, we should be in the -			// process of baking a new texture so request an -			// upload with the new data - -			// BAP: does this really belong in this callback, as -			// opposed to where the cancellation takes place? -			// suspect this does nothing. -			layerset_buffer->requestUpload(); -		} -		else if (baked_upload_data->mID == layerset_buffer->mUploadID) -		{ -			// This is the upload we're currently waiting for. -			layerset_buffer->mUploadID.setNull(); -			const std::string name(baked_upload_data->mTexLayerSet->getBodyRegionName()); -			const std::string resolution = baked_upload_data->mIsHighestRes ? " full res " : " low res "; -			if (result >= 0) -			{ -				layerset_buffer->mUploadPending = FALSE; // Allows sending of AgentSetAppearance later -				LLAvatarAppearanceDefines::ETextureIndex baked_te = gAgentAvatarp->getBakedTE(layerset_buffer->getViewerTexLayerSet()); -				// Update baked texture info with the new UUID -				U64 now = LLFrameTimer::getTotalTime();		// Record starting time -				LL_INFOS() << "Baked" << resolution << "texture upload for " << name << " took " << (S32)((now - baked_upload_data->mStartTime) / 1000) << " ms" << LL_ENDL; -				gAgentAvatarp->setNewBakedTexture(baked_te, uuid); -			} -			else -			{	 -				++failures; -				S32 max_attempts = baked_upload_data->mIsHighestRes ? BAKE_UPLOAD_ATTEMPTS : 1; // only retry final bakes -				LL_WARNS() << "Baked" << resolution << "texture upload for " << name << " failed (attempt " << failures << "/" << max_attempts << ")" << LL_ENDL; -				if (failures < max_attempts) -				{ -					layerset_buffer->mUploadFailCount = failures; -					layerset_buffer->mUploadRetryTimer.start(); -					layerset_buffer->requestUpload(); -				} -			} -		} -		else -		{ -			LL_INFOS() << "Received baked texture out of date, ignored." << LL_ENDL; -		} - -		gAgentAvatarp->dirtyMesh(); -	} -	else -	{ -		// Baked texture failed to upload (in which case since we -		// didn't set the new baked texture, it means that they'll try -		// and rebake it at some point in the future (after login?)), -		// or this response to upload is out of date, in which case a -		// current response should be on the way or already processed. -		LL_WARNS() << "Baked upload failed" << LL_ENDL; -	} - -	delete baked_upload_data; -} -  //-----------------------------------------------------------------------------  // LLViewerTexLayerSet  // An ordered set of texture layers that get composited into a single texture. @@ -664,20 +293,6 @@ void LLViewerTexLayerSet::requestUpdate()  	}  } -void LLViewerTexLayerSet::requestUpload() -{ -	createComposite(); -	getViewerComposite()->requestUpload(); -} - -void LLViewerTexLayerSet::cancelUpload() -{ -	if(mComposite) -	{ -		getViewerComposite()->cancelUpload(); -	} -} -  void LLViewerTexLayerSet::updateComposite()  {  	createComposite(); @@ -730,19 +345,12 @@ const std::string LLViewerTexLayerSetBuffer::dumpTextureInfo() const  {  	if (!isAgentAvatarValid()) return ""; -	const BOOL is_high_res = !mNeedsUpload; -	const U32 num_low_res = mNumLowresUploads; -	const U32 upload_time = (U32)mNeedsUploadTimer.getElapsedTimeF32(); +	const BOOL is_high_res = TRUE;  +	const U32 num_low_res = 0;  	const std::string local_texture_info = gAgentAvatarp->debugDumpLocalTextureDataInfo(getViewerTexLayerSet()); -	std::string status 				= "CREATING "; -	if (!uploadNeeded()) status 	= "DONE     "; -	if (uploadInProgress()) status 	= "UPLOADING"; - -	std::string text = llformat("[%s] [HiRes:%d LoRes:%d] [Elapsed:%d] %s", -								status.c_str(), +	std::string text = llformat("[HiRes:%d LoRes:%d] %s",  								is_high_res, num_low_res, -								upload_time,   								local_texture_info.c_str());  	return text;  } diff --git a/indra/newview/llviewertexlayer.h b/indra/newview/llviewertexlayer.h index 959c883da8..027ae255ec 100644..100755 --- a/indra/newview/llviewertexlayer.h +++ b/indra/newview/llviewertexlayer.h @@ -47,8 +47,6 @@ public:  	virtual ~LLViewerTexLayerSet();  	/*virtual*/void				requestUpdate(); -	void						requestUpload(); -	void						cancelUpload();  	BOOL						isLocalTextureDataAvailable() const;  	BOOL						isLocalTextureDataFinal() const;  	void						updateComposite(); @@ -116,31 +114,6 @@ protected:  	virtual BOOL			render() { return renderTexLayerSet(); }  	//-------------------------------------------------------------------- -	// Uploads -	//-------------------------------------------------------------------- -public: -	void					requestUpload(); -	void					cancelUpload(); -	BOOL					uploadNeeded() const; 			// We need to upload a new texture -	BOOL					uploadInProgress() const; 		// We have started uploading a new texture and are awaiting the result -	BOOL					uploadPending() const; 			// We are expecting a new texture to be uploaded at some point -	static void				onTextureUploadComplete(const LLUUID& uuid, -													void* userdata, -													S32 result, LLExtStat ext_status); -protected: -	BOOL					isReadyToUpload() const; -	void					doUpload(); 					// Does a read back and upload. -	void					conditionalRestartUploadTimer(); -private: -	BOOL					mNeedsUpload; 					// Whether we need to send our baked textures to the server -	U32						mNumLowresUploads; 				// Number of times we've sent a lowres version of our baked textures to the server -	BOOL					mUploadPending; 				// Whether we have received back the new baked textures -	LLUUID					mUploadID; 						// The current upload process (null if none). -	LLFrameTimer    		mNeedsUploadTimer; 				// Tracks time since upload was requested and performed. -	S32						mUploadFailCount;				// Number of consecutive upload failures -	LLFrameTimer    		mUploadRetryTimer; 				// Tracks time since last upload failure. - -	//--------------------------------------------------------------------  	// Updates  	//--------------------------------------------------------------------  public: @@ -156,25 +129,5 @@ private:  	LLFrameTimer    		mNeedsUpdateTimer; 				// Tracks time since update was requested and performed.  }; - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// LLBakedUploadData -// -// Used by LLTexLayerSetBuffer for a callback. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -struct LLBakedUploadData -{ -	LLBakedUploadData(const LLVOAvatarSelf* avatar, -					  LLViewerTexLayerSet* layerset,  -					  const LLUUID& id, -					  bool highest_res); -	~LLBakedUploadData() {} -	const LLUUID				mID; -	const LLVOAvatarSelf*		mAvatar; // note: backlink only; don't LLPointer  -	LLViewerTexLayerSet*		mTexLayerSet; -   	const U64					mStartTime;	// for measuring baked texture upload time -   	const bool					mIsHighestRes; // whether this is a "final" bake, or intermediate low res -}; -  #endif  // LL_VIEWER_TEXLAYER_H diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 3be82a5531..ba89aafc84 100755 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -961,6 +961,27 @@ void LLViewerTexture::updateBindStatsForTester()  //end of LLViewerTexture  //---------------------------------------------------------------------------------------------- +const std::string& fttype_to_string(const FTType& fttype) +{ +	static const std::string ftt_unknown("FTT_UNKNOWN"); +	static const std::string ftt_default("FTT_DEFAULT"); +	static const std::string ftt_server_bake("FTT_SERVER_BAKE"); +	static const std::string ftt_host_bake("FTT_HOST_BAKE"); +	static const std::string ftt_map_tile("FTT_MAP_TILE"); +	static const std::string ftt_local_file("FTT_LOCAL_FILE"); +	static const std::string ftt_error("FTT_ERROR"); +	switch(fttype) +	{ +		case FTT_UNKNOWN: return ftt_unknown; break; +		case FTT_DEFAULT: return ftt_default; break; +		case FTT_SERVER_BAKE: return ftt_server_bake; break; +		case FTT_HOST_BAKE: return ftt_host_bake; break; +		case FTT_MAP_TILE: return ftt_map_tile; break; +		case FTT_LOCAL_FILE: return ftt_local_file; break; +	} +	return ftt_error; +} +  //----------------------------------------------------------------------------------------------  //start of LLViewerFetchedTexture  //---------------------------------------------------------------------------------------------- @@ -973,7 +994,7 @@ LLViewerFetchedTexture::LLViewerFetchedTexture(const LLUUID& id, FTType f_type,  	mFTType = f_type;  	if (mFTType == FTT_HOST_BAKE)  	{ -		mCanUseHTTP = false; +		LL_WARNS() << "Unsupported fetch type " << mFTType << LL_ENDL;  	}  	generateGLTexture();  } @@ -998,6 +1019,7 @@ void LLViewerFetchedTexture::init(bool firstinit)  {  	mOrigWidth = 0;  	mOrigHeight = 0; +	mHasAux = FALSE;  	mNeedsAux = FALSE;  	mRequestedDiscardLevel = -1;  	mRequestedDownloadPriority = 0.f; @@ -1054,7 +1076,7 @@ void LLViewerFetchedTexture::init(bool firstinit)  	mLastReferencedSavedRawImageTime = 0.0f;  	mKeptSavedRawImageTime = 0.f;  	mLastCallBackActiveTime = 0.f; - +	mForceCallbackFetch = FALSE;  	mInDebug = FALSE;  	mFTType = FTT_UNKNOWN; @@ -1836,9 +1858,14 @@ bool LLViewerFetchedTexture::updateFetch()  		if (mRawImage.notNull()) sRawCount--;  		if (mAuxRawImage.notNull()) sAuxCount--; -		bool finished = LLAppViewer::getTextureFetch()->getRequestFinished(getID(), fetch_discard, mRawImage, mAuxRawImage); +		bool finished = LLAppViewer::getTextureFetch()->getRequestFinished(getID(), fetch_discard, mRawImage, mAuxRawImage, +																		   mLastHttpGetStatus);  		if (mRawImage.notNull()) sRawCount++; -		if (mAuxRawImage.notNull()) sAuxCount++; +		if (mAuxRawImage.notNull()) +		{ +			mHasAux = TRUE; +			sAuxCount++; +		}  		if (finished)  		{  			mIsFetching = FALSE; @@ -1899,20 +1926,34 @@ bool LLViewerFetchedTexture::updateFetch()  			if ((decode_priority > 0) && (mRawDiscardLevel < 0 || mRawDiscardLevel == INVALID_DISCARD_LEVEL))  			{  				// We finished but received no data -				if (current_discard < 0) +				if (getDiscardLevel() < 0)  				{ -					LL_WARNS() << "!mIsFetching, setting as missing, decode_priority " << decode_priority -							<< " mRawDiscardLevel " << mRawDiscardLevel -							<< " current_discard " << current_discard -							<< LL_ENDL; +					if (getFTType() != FTT_MAP_TILE) +					{ +						LL_WARNS() << mID +								<< " Fetch failure, setting as missing, decode_priority " << decode_priority +								<< " mRawDiscardLevel " << mRawDiscardLevel +								<< " current_discard " << current_discard +								<< " stats " << mLastHttpGetStatus.toHex() +								<< LL_ENDL; +					}  					setIsMissingAsset();  					desired_discard = -1;  				}  				else  				{  					//LL_WARNS() << mID << ": Setting min discard to " << current_discard << LL_ENDL; -					mMinDiscardLevel = current_discard; -					desired_discard = current_discard; +					if(current_discard >= 0) +					{ +						mMinDiscardLevel = current_discard; +						desired_discard = current_discard; +					} +					else +					{ +						S32 dis_level = getDiscardLevel(); +						mMinDiscardLevel = dis_level; +						desired_discard = dis_level; +					}  				}  				destroyRawImage();  			} @@ -2083,29 +2124,43 @@ void LLViewerFetchedTexture::forceToDeleteRequest()  	mDesiredDiscardLevel = getMaxDiscardLevel() + 1;  } -void LLViewerFetchedTexture::setIsMissingAsset() +void LLViewerFetchedTexture::setIsMissingAsset(BOOL is_missing)  { -	if (mUrl.empty()) +	if (is_missing == mIsMissingAsset)  	{ -		LL_WARNS() << mID << ": Marking image as missing" << LL_ENDL; +		return;  	} -	else +	if (is_missing)  	{ -		// This may or may not be an error - it is normal to have no -		// map tile on an empty region, but bad if we're failing on a -		// server bake texture. -		LL_WARNS() << mUrl << ": Marking image as missing" << LL_ENDL; +		if (mUrl.empty()) +		{ +			LL_WARNS() << mID << ": Marking image as missing" << LL_ENDL; +		} +		else +		{ +			// This may or may not be an error - it is normal to have no +			// map tile on an empty region, but bad if we're failing on a +			// server bake texture. +			if (getFTType() != FTT_MAP_TILE) +			{ +				LL_WARNS() << mUrl << ": Marking image as missing" << LL_ENDL; +			} +		} +		if (mHasFetcher) +		{ +			LLAppViewer::getTextureFetch()->deleteRequest(getID(), true); +			mHasFetcher = FALSE; +			mIsFetching = FALSE; +			mLastPacketTimer.reset(); +			mFetchState = 0; +			mFetchPriority = 0; +		}  	} -	if (mHasFetcher) +	else  	{ -		LLAppViewer::getTextureFetch()->deleteRequest(getID(), true); -		mHasFetcher = FALSE; -		mIsFetching = FALSE; -		mLastPacketTimer.reset(); -		mFetchState = 0; -		mFetchPriority = 0; +		LL_INFOS() << mID << ": un-flagging missing asset" << LL_ENDL;  	} -	mIsMissingAsset = TRUE; +	mIsMissingAsset = is_missing;  }  void LLViewerFetchedTexture::setLoadedCallback( loaded_callback_func loaded_callback, @@ -2148,10 +2203,19 @@ void LLViewerFetchedTexture::setLoadedCallback( loaded_callback_func loaded_call  	}  	if (mNeedsAux && mAuxRawImage.isNull() && getDiscardLevel() >= 0)  	{ -		// We need aux data, but we've already loaded the image, and it didn't have any -		LL_WARNS() << "No aux data available for callback for image:" << getID() << LL_ENDL; +		if(mHasAux) +		{ +			//trigger a refetch +			forceToRefetchTexture(); +		} +		else +		{ +			// We need aux data, but we've already loaded the image, and it didn't have any +			LL_WARNS() << "No aux data available for callback for image:" << getID() << LL_ENDL; +		}  	} -	mLastCallBackActiveTime = sCurrentTime; +	mLastCallBackActiveTime = sCurrentTime ; +        mLastReferencedSavedRawImageTime = sCurrentTime;  }  void LLViewerFetchedTexture::clearCallbackEntryList() @@ -2262,8 +2326,9 @@ void LLViewerFetchedTexture::unpauseLoadedCallbacks(const LLLoadedCallbackEntry:  			}  		}  	} -	mPauseLoadedCallBacks = FALSE; -	mLastCallBackActiveTime = sCurrentTime; +	mPauseLoadedCallBacks = FALSE ; +	mLastCallBackActiveTime = sCurrentTime ; +	mForceCallbackFetch = TRUE;  	if(need_raw)  	{  		mSaveRawImage = TRUE; @@ -2303,7 +2368,8 @@ void LLViewerFetchedTexture::pauseLoadedCallbacks(const LLLoadedCallbackEntry::s  bool LLViewerFetchedTexture::doLoadedCallbacks()  { -	static const F32 MAX_INACTIVE_TIME = 900.f; //seconds +	static const F32 MAX_INACTIVE_TIME = 900.f ; //seconds +	static const F32 MAX_IDLE_WAIT_TIME = 5.f ; //seconds  	if (mNeedsCreateTexture)  	{ @@ -2316,14 +2382,30 @@ bool LLViewerFetchedTexture::doLoadedCallbacks()  	}	  	if(sCurrentTime - mLastCallBackActiveTime > MAX_INACTIVE_TIME && !mIsFetching)  	{ -		clearCallbackEntryList(); //remove all callbacks. -		return false; +		if (mFTType == FTT_SERVER_BAKE) +		{ +			//output some debug info +			LL_INFOS() << "baked texture: " << mID << "clears all call backs due to inactivity." << LL_ENDL; +			LL_INFOS() << mUrl << LL_ENDL; +			LL_INFOS() << "current discard: " << getDiscardLevel() << " current discard for fetch: " << getCurrentDiscardLevelForFetching() << +				" Desired discard: " << getDesiredDiscardLevel() << "decode Pri: " << getDecodePriority() << LL_ENDL; +		} + +		clearCallbackEntryList() ; //remove all callbacks. +		return false ;  	}  	bool res = false;  	if (isMissingAsset())  	{ +		if (mFTType == FTT_SERVER_BAKE) +		{ +			//output some debug info +			LL_INFOS() << "baked texture: " << mID << "is missing." << LL_ENDL; +			LL_INFOS() << mUrl << LL_ENDL; +		} +  		for(callback_list_t::iterator iter = mLoadedCallbackList.begin();  			iter != mLoadedCallbackList.end(); )  		{ @@ -2508,6 +2590,9 @@ bool LLViewerFetchedTexture::doLoadedCallbacks()  		}  	} +	// Done with any raw image data at this point (will be re-created if we still have callbacks) +	destroyRawImage(); +  	//  	// If we have no callbacks, take us off of the image callback list.  	// @@ -2515,10 +2600,13 @@ bool LLViewerFetchedTexture::doLoadedCallbacks()  	{  		gTextureList.mCallbackList.erase(this);  	} +	else if(!res && mForceCallbackFetch && sCurrentTime - mLastCallBackActiveTime > MAX_IDLE_WAIT_TIME && !mIsFetching) +	{ +		//wait for long enough but no fetching request issued, force one. +		forceToRefetchTexture(mLoadedCallbackDesiredDiscardLevel, 5.f); +		mForceCallbackFetch = FALSE; //fire once. +	} -	// Done with any raw image data at this point (will be re-created if we still have callbacks) -	destroyRawImage(); -	  	return res;  } @@ -2600,7 +2688,7 @@ bool LLViewerFetchedTexture::needsToSaveRawImage()  void LLViewerFetchedTexture::destroyRawImage()  {	 -	if (mAuxRawImage.notNull()) +	if (mAuxRawImage.notNull() && !needsToSaveRawImage())  	{  		sAuxCount--;  		mAuxRawImage = NULL; @@ -2756,6 +2844,24 @@ void LLViewerFetchedTexture::saveRawImage()  	mLastReferencedSavedRawImageTime = sCurrentTime;  } +//force to refetch the texture to the discard level  +void LLViewerFetchedTexture::forceToRefetchTexture(S32 desired_discard, F32 kept_time) +{ +	if(mForceToSaveRawImage) +	{ +		desired_discard = llmin(desired_discard, mDesiredSavedRawDiscardLevel); +		kept_time = llmax(kept_time, mKeptSavedRawImageTime); +	} + +	//trigger a new fetch. +	mForceToSaveRawImage = TRUE ; +	mDesiredSavedRawDiscardLevel = desired_discard ; +	mKeptSavedRawImageTime = kept_time ; +	mLastReferencedSavedRawImageTime = sCurrentTime ; +	mSavedRawImage = NULL ; +	mSavedRawDiscardLevel = -1 ; +} +  void LLViewerFetchedTexture::forceToSaveRawImage(S32 desired_discard, F32 kept_time)   {   	mKeptSavedRawImageTime = kept_time; @@ -2796,13 +2902,19 @@ void LLViewerFetchedTexture::destroySavedRawImage()  	clearCallbackEntryList(); -	mSavedRawImage = NULL; -	mForceToSaveRawImage  = FALSE; -	mSaveRawImage = FALSE; -	mSavedRawDiscardLevel = -1; -	mDesiredSavedRawDiscardLevel = -1; -	mLastReferencedSavedRawImageTime = 0.0f; -	mKeptSavedRawImageTime = 0.f; +	mSavedRawImage = NULL ; +	mForceToSaveRawImage  = FALSE ; +	mSaveRawImage = FALSE ; +	mSavedRawDiscardLevel = -1 ; +	mDesiredSavedRawDiscardLevel = -1 ; +	mLastReferencedSavedRawImageTime = 0.0f ; +	mKeptSavedRawImageTime = 0.f ; +	 +	if(mAuxRawImage.notNull()) +	{ +		sAuxCount--; +		mAuxRawImage = NULL; +	}  }  LLImageRaw* LLViewerFetchedTexture::getSavedRawImage()  diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h index b12b988513..307204da60 100755 --- a/indra/newview/llviewertexture.h +++ b/indra/newview/llviewertexture.h @@ -34,6 +34,7 @@  #include "llgltypes.h"  #include "llrender.h"  #include "llmetricperformancetester.h" +#include "httpcommon.h"  #include <map>  #include <list> @@ -41,6 +42,7 @@  extern const S32Megabytes gMinVideoRam;  extern const S32Megabytes gMaxVideoRam; +class LLFace;  class LLImageGL ;  class LLImageRaw;  class LLViewerObject; @@ -97,6 +99,7 @@ public:  		DYNAMIC_TEXTURE,  		FETCHED_TEXTURE,  		LOD_TEXTURE, +		ATLAS_TEXTURE,  		INVALID_TEXTURE_TYPE  	}; @@ -118,7 +121,7 @@ public:  	LLViewerTexture(const U32 width, const U32 height, const U8 components, BOOL usemipmaps) ;  	virtual S8 getType() const; -	virtual BOOL isMissingAsset()const ; +	virtual BOOL isMissingAsset() const ;  	virtual void dump();	// debug info to LL_INFOS()  	/*virtual*/ bool bindDefaultImage(const S32 stage = 0) ; @@ -244,6 +247,8 @@ enum FTType  	FTT_LOCAL_FILE // fetch directly from a local file.  }; +const std::string& fttype_to_string(const FTType& fttype); +  //  //textures are managed in gTextureList.  //raw image data is fetched from remote or local cache @@ -340,8 +345,8 @@ public:  	// more data.  	/*virtual*/ void setKnownDrawSize(S32 width, S32 height); -	void setIsMissingAsset(); -	/*virtual*/ BOOL isMissingAsset()	const		{ return mIsMissingAsset; } +	void setIsMissingAsset(BOOL is_missing = true); +	/*virtual*/ BOOL isMissingAsset() const { return mIsMissingAsset; }  	// returns dimensions of original image for local files (before power of two scaling)  	// and returns 0 for all asset system images @@ -383,6 +388,7 @@ public:  	BOOL        isCachedRawImageReady() const {return mCachedRawImageReady ;}  	BOOL        isRawImageValid()const { return mIsRawImageValid ; }	  	void        forceToSaveRawImage(S32 desired_discard = 0, F32 kept_time = 0.f) ; +	void        forceToRefetchTexture(S32 desired_discard = 0, F32 kept_time = 60.f);  	/*virtual*/ void setCachedRawImage(S32 discard_level, LLImageRaw* imageraw) ;  	void        destroySavedRawImage() ;  	LLImageRaw* getSavedRawImage() ; @@ -411,10 +417,16 @@ private:  	void saveRawImage() ;  	void setCachedRawImage() ; +	//for atlas +	void resetFaceAtlas() ; +	void invalidateAtlas(BOOL rebuild_geom) ; +	BOOL insertToAtlas() ; +  private:  	BOOL  mFullyLoaded;  	BOOL  mInDebug;  	BOOL  mInFastCacheList; +	BOOL  mForceCallbackFetch;  protected:		  	std::string mLocalFileName; @@ -442,11 +454,13 @@ protected:  	S8  mMinDesiredDiscardLevel;	// The minimum discard level we'd like to have  	S8  mNeedsAux;					// We need to decode the auxiliary channels +	S8  mHasAux;                    // We have aux channels  	S8  mDecodingAux;				// Are we decoding high components  	S8  mIsRawImageValid;  	S8  mHasFetcher;				// We've made a fecth request  	S8  mIsFetching;				// Fetch request is active -	bool mCanUseHTTP ;              //This texture can be fetched through http if true. +	bool mCanUseHTTP;              //This texture can be fetched through http if true. +	LLCore::HttpStatus mLastHttpGetStatus; // Result of the most recently completed http request for this texture.  	FTType mFTType; // What category of image is this - map tile, server bake, etc?  	mutable S8 mIsMissingAsset;		// True if we know that there is no image asset with this image id in the database.		 diff --git a/indra/newview/llviewerwearable.cpp b/indra/newview/llviewerwearable.cpp index a544cc81da..7de82a4710 100644..100755 --- a/indra/newview/llviewerwearable.cpp +++ b/indra/newview/llviewerwearable.cpp @@ -73,14 +73,16 @@ private:  static std::string asset_id_to_filename(const LLUUID &asset_id);  LLViewerWearable::LLViewerWearable(const LLTransactionID& transaction_id) : -	LLWearable() +	LLWearable(), +	mVolatile(FALSE)  {  	mTransactionID = transaction_id;  	mAssetID = mTransactionID.makeAssetID(gAgent.getSecureSessionID());  }  LLViewerWearable::LLViewerWearable(const LLAssetID& asset_id) : -	LLWearable() +	LLWearable(), +	mVolatile(FALSE)  {  	mAssetID = asset_id;  	mTransactionID.setNull(); @@ -265,7 +267,7 @@ void LLViewerWearable::setParamsToDefaults()  	{  		if( (((LLViewerVisualParam*)param)->getWearableType() == mType ) && (param->isTweakable() ) )  		{ -			setVisualParamWeight(param->getID(),param->getDefaultWeight(), FALSE); +			setVisualParamWeight(param->getID(),param->getDefaultWeight());  		}  	}  } @@ -321,16 +323,6 @@ void LLViewerWearable::writeToAvatar(LLAvatarAppearance *avatarp)  	if (!viewer_avatar->isValid()) return; -#if 0 -	// FIXME DRANO - kludgy way to avoid overwriting avatar state from wearables. -	// Ideally would avoid calling this func in the first place. -	if (viewer_avatar->isUsingServerBakes() && -		!viewer_avatar->isUsingLocalAppearance()) -	{ -		return; -	} -#endif -  	ESex old_sex = avatarp->getSex();  	LLWearable::writeToAvatar(avatarp); @@ -360,19 +352,14 @@ void LLViewerWearable::writeToAvatar(LLAvatarAppearance *avatarp)  	ESex new_sex = avatarp->getSex();  	if( old_sex != new_sex )  	{ -		viewer_avatar->updateSexDependentLayerSets( FALSE ); +		viewer_avatar->updateSexDependentLayerSets();  	}	 -	 -//	if( upload_bake ) -//	{ -//		gAgent.sendAgentSetAppearance(); -//	}  }  // Updates the user's avatar's appearance, replacing this wearables' parameters and textures with default values.  // static  -void LLViewerWearable::removeFromAvatar( LLWearableType::EType type, BOOL upload_bake ) +void LLViewerWearable::removeFromAvatar( LLWearableType::EType type)  {  	if (!isAgentAvatarValid()) return; @@ -391,7 +378,7 @@ void LLViewerWearable::removeFromAvatar( LLWearableType::EType type, BOOL upload  		if( (((LLViewerVisualParam*)param)->getWearableType() == type) && (param->isTweakable() ) )  		{  			S32 param_id = param->getID(); -			gAgentAvatarp->setVisualParamWeight( param_id, param->getDefaultWeight(), upload_bake ); +			gAgentAvatarp->setVisualParamWeight( param_id, param->getDefaultWeight());  		}  	} @@ -401,12 +388,7 @@ void LLViewerWearable::removeFromAvatar( LLWearableType::EType type, BOOL upload  	}  	gAgentAvatarp->updateVisualParams(); -	gAgentAvatarp->wearableUpdated(type, FALSE); - -//	if( upload_bake ) -//	{ -//		gAgent.sendAgentSetAppearance(); -//	} +	gAgentAvatarp->wearableUpdated(type);  }  // Does not copy mAssetID. @@ -479,13 +461,6 @@ void LLViewerWearable::setItemID(const LLUUID& item_id)  void LLViewerWearable::revertValues()  { -#if 0 -	// DRANO avoid overwrite when not in local appearance -	if (isAgentAvatarValid() && gAgentAvatarp->isUsingServerBakes() && !gAgentAvatarp->isUsingLocalAppearance()) -	{ -		return; -	} -#endif  	LLWearable::revertValues(); @@ -523,13 +498,6 @@ void LLViewerWearable::refreshName()  	}  } -// virtual -void LLViewerWearable::addToBakedTextureHash(LLMD5& hash) const -{ -	LLUUID asset_id = getAssetID(); -	hash.update((const unsigned char*)asset_id.mData, UUID_BYTES); -} -  struct LLWearableSaveData  {  	LLWearableType::EType mType; diff --git a/indra/newview/llviewerwearable.h b/indra/newview/llviewerwearable.h index 8f49e3c4e2..62cd5e21ad 100644..100755 --- a/indra/newview/llviewerwearable.h +++ b/indra/newview/llviewerwearable.h @@ -62,13 +62,15 @@ public:  	BOOL				isOldVersion() const;  	/*virtual*/ void	writeToAvatar(LLAvatarAppearance *avatarp); -	void				removeFromAvatar( BOOL upload_bake )	{ LLViewerWearable::removeFromAvatar( mType, upload_bake ); } -	static void			removeFromAvatar( LLWearableType::EType type, BOOL upload_bake );  +	void				removeFromAvatar()	{ LLViewerWearable::removeFromAvatar( mType); } +	static void			removeFromAvatar( LLWearableType::EType type);   	/*virtual*/ EImportResult	importStream( std::istream& input_stream, LLAvatarAppearance* avatarp );  	void				setParamsToDefaults();  	void				setTexturesToDefaults(); +	void				setVolatile(BOOL is_volatile) { mVolatile = is_volatile; } // TRUE when doing preview renders, some updates will be suppressed. +	BOOL				getVolatile() { return mVolatile; }  	/*virtual*/ LLUUID	getDefaultTextureImageID(LLAvatarAppearanceDefines::ETextureIndex index) const; @@ -89,14 +91,14 @@ public:  	// the wearable was worn. make sure the name of the wearable object matches the LLViewerInventoryItem,  	// not the wearable asset itself.  	void				refreshName(); - -	// Update the baked texture hash. -	/*virtual*/void		addToBakedTextureHash(LLMD5& hash) const; +	/*virtual*/void		addToBakedTextureHash(LLMD5& hash) const {}  protected:  	LLAssetID			mAssetID;  	LLTransactionID		mTransactionID; +	BOOL 				mVolatile; // True when rendering preview images. Can suppress some updates. +  	LLUUID				mItemID;  // ID of the inventory item in the agent's inventory	  }; diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index ec794e527d..b2b5c9d903 100755 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -2023,7 +2023,7 @@ void LLViewerWindow::initWorldUI()  		destinations->setErrorPageURL(gSavedSettings.getString("GenericErrorPageURL"));  		std::string url = gSavedSettings.getString("DestinationGuideURL");  		url = LLWeb::expandURLSubstitutions(url, LLSD()); -		destinations->navigateTo(url, "text/html"); +		destinations->navigateTo(url, HTTP_CONTENT_TEXT_HTML);  	}  	LLMediaCtrl* avatar_picker = LLFloaterReg::getInstance("avatar")->findChild<LLMediaCtrl>("avatar_picker_contents");  	if (avatar_picker) @@ -2031,7 +2031,7 @@ void LLViewerWindow::initWorldUI()  		avatar_picker->setErrorPageURL(gSavedSettings.getString("GenericErrorPageURL"));  		std::string url = gSavedSettings.getString("AvatarPickerURL");  		url = LLWeb::expandURLSubstitutions(url, LLSD()); -		avatar_picker->navigateTo(url, "text/html"); +		avatar_picker->navigateTo(url, HTTP_CONTENT_TEXT_HTML);  	}  } diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 04f64a4997..9f42776d78 100755 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -109,7 +109,7 @@ extern F32 SPEED_ADJUST_MAX;  extern F32 SPEED_ADJUST_MAX_SEC;  extern F32 ANIM_SPEED_MAX;  extern F32 ANIM_SPEED_MIN; - +extern U32 JOINT_COUNT_REQUIRED_FOR_FULLRIG;  // #define OUTPUT_BREAST_DATA @@ -713,7 +713,6 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,  	mLastRezzedStatus(-1),  	mIsEditingAppearance(FALSE),  	mUseLocalAppearance(FALSE), -	mUseServerBakes(FALSE), // FIXME DRANO consider using boost::optional, defaulting to unknown.  	mLastUpdateRequestCOFVersion(-1),  	mLastUpdateReceivedCOFVersion(-1)  { @@ -723,7 +722,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,  	const BOOL needsSendToSim = false; // currently, this HUD effect doesn't need to pack and unpack data to do its job  	mVoiceVisualizer = ( LLVoiceVisualizer *)LLHUDManager::getInstance()->createViewerEffect( LLHUDObject::LL_HUD_EFFECT_VOICE_VISUALIZER, needsSendToSim ); -	LL_DEBUGS() << "LLVOAvatar Constructor (0x" << this << ") id:" << mID << LL_ENDL; +	LL_DEBUGS("Avatar") << "LLVOAvatar Constructor (0x" << this << ") id:" << mID << LL_ENDL;  	mPelvisp = NULL; @@ -830,8 +829,8 @@ LLVOAvatar::~LLVOAvatar()  		}  	logPendingPhases(); - -	LL_DEBUGS() << "LLVOAvatar Destructor (0x" << this << ") id:" << mID << LL_ENDL; +	 +	LL_DEBUGS("Avatar") << "LLVOAvatar Destructor (0x" << this << ") id:" << mID << LL_ENDL;  	std::for_each(mAttachmentPoints.begin(), mAttachmentPoints.end(), DeletePairedPointer());  	mAttachmentPoints.clear(); @@ -1085,7 +1084,7 @@ void LLVOAvatar::restoreGL()  	gAgentAvatarp->setCompositeUpdatesEnabled(TRUE);  	for (U32 i = 0; i < gAgentAvatarp->mBakedTextureDatas.size(); i++)  	{ -		gAgentAvatarp->invalidateComposite(gAgentAvatarp->getTexLayerSet(i), FALSE); +		gAgentAvatarp->invalidateComposite(gAgentAvatarp->getTexLayerSet(i));  	}  	gAgentAvatarp->updateMeshTextures();  } @@ -1252,6 +1251,7 @@ LLTexLayerSet* LLVOAvatar::createTexLayerSet()  const LLVector3 LLVOAvatar::getRenderPosition() const  { +  	if (mDrawable.isNull() || mDrawable->getGeneration() < 0)  	{  		return getPositionAgent(); @@ -1274,6 +1274,8 @@ const LLVector3 LLVOAvatar::getRenderPosition() const  	{  		return getPosition() * mDrawable->getParent()->getRenderMatrix();  	} +	 +	  }  void LLVOAvatar::updateDrawable(BOOL force_damped) @@ -1309,6 +1311,8 @@ void LLVOAvatar::updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax)  		mImpostorOffset = LLVector3(pos_group.getF32ptr())-getRenderPosition();  		mDrawable->setPositionGroup(pos_group);  	} +	 +	  }  void LLVOAvatar::getSpatialExtents(LLVector4a& newMin, LLVector4a& newMax) @@ -1986,24 +1990,23 @@ LLViewerFetchedTexture *LLVOAvatar::getBakedTextureImage(const U8 te, const LLUU  		// Should already exist, don't need to find it on sim or baked-texture host.  		result = gTextureList.findImage(uuid);  	} -  	if (!result)  {  		const std::string url = getImageURL(te,uuid); -		if (!url.empty()) -	{ -			LL_DEBUGS("Avatar") << avString() << "from URL " << url << LL_ENDL; -			result = LLViewerTextureManager::getFetchedTextureFromUrl( -				url, FTT_SERVER_BAKE, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, uuid); -	} -	else -	{ -			LL_DEBUGS("Avatar") << avString() << "from host " << uuid << LL_ENDL; -			LLHost host = getObjectHost(); -			result = LLViewerTextureManager::getFetchedTexture( -				uuid, FTT_HOST_BAKE, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, host); + +		if (url.empty()) +		{ +			LL_WARNS() << "unable to determine URL for te " << te << " uuid " << uuid << LL_ENDL; +			return NULL; +		} +		LL_DEBUGS("Avatar") << avString() << "get server-bake image from URL " << url << LL_ENDL; +		result = LLViewerTextureManager::getFetchedTextureFromUrl( +			url, FTT_SERVER_BAKE, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, uuid); +		if (result->isMissingAsset()) +		{ +			result->setIsMissingAsset(false); +		}  	} -}  	return result;  } @@ -2231,8 +2234,8 @@ void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled)  				if ( mLipSyncActive )  				{ -					if( mOohMorph ) mOohMorph->setWeight(mOohMorph->getMinWeight(), FALSE); -					if( mAahMorph ) mAahMorph->setWeight(mAahMorph->getMinWeight(), FALSE); +					if( mOohMorph ) mOohMorph->setWeight(mOohMorph->getMinWeight()); +					if( mAahMorph ) mAahMorph->setWeight(mAahMorph->getMinWeight());  					mLipSyncActive = false;  					LLCharacter::updateVisualParams(); @@ -2255,7 +2258,7 @@ void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled)  		{  			LLVector3 tagPos = mRoot->getWorldPosition();  			tagPos[VZ] -= mPelvisToFoot; -			tagPos[VZ] += ( mBodySize[VZ] + 0.125f ); +			tagPos[VZ] += ( mBodySize[VZ] + 0.125f ); // does not need mAvatarOffset -Nyx  			mVoiceVisualizer->setVoiceSourceWorldPosition( tagPos );  		}  	}//if ( voiceEnabled ) @@ -2395,14 +2398,10 @@ void LLVOAvatar::idleUpdateAppearanceAnimation()  			{  				if (param->isTweakable())  				{ -					param->stopAnimating(FALSE); +					param->stopAnimating();  				}  			}  			updateVisualParams(); -			if (isSelf()) -			{ -				gAgent.sendAgentSetAppearance(); -			}  		}  		else  		{ @@ -2418,7 +2417,7 @@ void LLVOAvatar::idleUpdateAppearanceAnimation()  				{  					if (param->isTweakable())  					{ -						param->animate(morph_amt, FALSE); +						param->animate(morph_amt);  					}  				}  			} @@ -2471,7 +2470,7 @@ void LLVOAvatar::idleUpdateLipSync(bool voice_enabled)  			F32 ooh_weight = mOohMorph->getMinWeight()  				+ ooh_morph_amount * (mOohMorph->getMaxWeight() - mOohMorph->getMinWeight()); -			mOohMorph->setWeight( ooh_weight, FALSE ); +			mOohMorph->setWeight( ooh_weight);  		}  		if( mAahMorph ) @@ -2479,7 +2478,7 @@ void LLVOAvatar::idleUpdateLipSync(bool voice_enabled)  			F32 aah_weight = mAahMorph->getMinWeight()  				+ aah_morph_amount * (mAahMorph->getMaxWeight() - mAahMorph->getMinWeight()); -			mAahMorph->setWeight( aah_weight, FALSE ); +			mAahMorph->setWeight( aah_weight);  		}  		mLipSyncActive = true; @@ -2996,6 +2995,8 @@ void LLVOAvatar::idleUpdateNameTagPosition(const LLVector3& root_pos_last)  	local_camera_up.normalize();  	local_camera_up = local_camera_up * inv_root_rot; + +	// position is based on head position, does not require mAvatarOffset here. - Nyx  	LLVector3 avatar_ellipsoid(mBodySize.mV[VX] * 0.4f,  								mBodySize.mV[VY] * 0.4f,  								mBodySize.mV[VZ] * NAMETAG_VERT_OFFSET_WEIGHT); @@ -3175,7 +3176,10 @@ void	LLVOAvatar::forceUpdateVisualMuteSettings()  // called on both your avatar and other avatars  //------------------------------------------------------------------------  BOOL LLVOAvatar::updateCharacter(LLAgent &agent) -{ +{	 +	// clear debug text +	mDebugText.clear(); +  	if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"))  	{  		S32 central_bake_version = -1; @@ -3189,7 +3193,7 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)  										  isSelf() ? (all_local_downloaded ? "L" : "l") : "-",  										  all_baked_downloaded ? "B" : "b",  										  mUseLocalAppearance, mIsEditingAppearance, -										  mUseServerBakes, central_bake_version); +										  1, central_bake_version);  		std::string origin_string = bakedTextureOriginInfo();  		debug_line += " [" + origin_string + "]";  		S32 curr_cof_version = LLAppearanceMgr::instance().getCOFVersion(); @@ -3689,6 +3693,9 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)  	//mesh vertices need to be reskinned  	mNeedsSkin = TRUE; + +		 +	  	return TRUE;  }  //----------------------------------------------------------------------------- @@ -3722,9 +3729,9 @@ void LLVOAvatar::setPelvisOffset( bool hasOffset, const LLVector3& offsetAmount,  {  	mHasPelvisOffset = hasOffset;  	if ( mHasPelvisOffset ) -	{ +	{	  		//Store off last pelvis to foot value -		mLastPelvisToFoot = mPelvisToFoot; +		mLastPelvisToFoot = mPelvisToFoot;		  		mPelvisOffset	  = offsetAmount;  		mLastPelvisFixup  = mPelvisFixup;  		mPelvisFixup	  = pelvisFixup; @@ -3734,18 +3741,16 @@ void LLVOAvatar::setPelvisOffset( bool hasOffset, const LLVector3& offsetAmount,  // postPelvisSetRecalc  //------------------------------------------------------------------------  void LLVOAvatar::postPelvisSetRecalc( void ) -{	 -	computeBodySize();  -	mRoot->touch(); -	mRoot->updateWorldMatrixChildren();	 -	dirtyMesh(); -	updateHeadOffset(); +{		 +	mRoot->updateWorldMatrixChildren();			 +	computeBodySize(); +	dirtyMesh(2);  }  //------------------------------------------------------------------------ -// pelisPoke +// setPelvisOffset  //------------------------------------------------------------------------  void LLVOAvatar::setPelvisOffset( F32 pelvisFixupAmount ) -{	 +{		  	mHasPelvisOffset  = true;  	mLastPelvisFixup  = mPelvisFixup;	  	mPelvisFixup	  = pelvisFixupAmount;	 @@ -4285,34 +4290,6 @@ bool LLVOAvatar::allBakedTexturesCompletelyDownloaded() const  	return allTexturesCompletelyDownloaded(baked_ids);  } -void LLVOAvatar::bakedTextureOriginCounts(S32 &sb_count, // server-bake, has origin URL. -										  S32 &host_count, // host-based bake, has host. -										  S32 &both_count, // error - both host and URL set. -										  S32 &neither_count) // error - neither set. -{ -	sb_count = host_count = both_count = neither_count = 0; -	 -	std::set<LLUUID> baked_ids; -	collectBakedTextureUUIDs(baked_ids); -	for (std::set<LLUUID>::const_iterator it = baked_ids.begin(); it != baked_ids.end(); ++it) -	{ -		LLViewerFetchedTexture *imagep = gTextureList.findImage(*it); -		bool has_url = false, has_host = false; -		if (!imagep->getUrl().empty()) -		{ -			has_url = true; -		} -		if (imagep->getTargetHost().isOk()) -		{ -			has_host = true; -		} -		if (has_url && !has_host) sb_count++; -		else if (has_host && !has_url) host_count++; -		else if (has_host && has_url) both_count++; -		else if (!has_host && !has_url) neither_count++; -	} -} -  std::string LLVOAvatar::bakedTextureOriginInfo()  {  	std::string result; @@ -4553,19 +4530,6 @@ void LLVOAvatar::updateTextures()  		{  			const S32 boost_level = getAvatarBakedBoostLevel();  			imagep = LLViewerTextureManager::staticCastToFetchedTexture(getImage(texture_index,0), TRUE); -			// Spam if this is a baked texture, not set to default image, without valid host info -			if (isIndexBakedTexture((ETextureIndex)texture_index) -				&& imagep->getID() != IMG_DEFAULT_AVATAR -				&& imagep->getID() != IMG_INVISIBLE -				&& !isUsingServerBakes()  -				&& !imagep->getTargetHost().isOk()) -			{ -				LL_WARNS_ONCE("Texture") << "LLVOAvatar::updateTextures No host for texture " -										 << imagep->getID() << " for avatar " -										 << (isSelf() ? "<myself>" : getID().asString())  -										 << " on host " << getRegion()->getHost() << LL_ENDL; -			} -  			addBakedTextureStats( imagep, mPixelArea, texel_area_ratio, boost_level );			  		}  	} @@ -4585,7 +4549,7 @@ void LLVOAvatar::addLocalTextureStats( ETextureIndex idx, LLViewerFetchedTexture  }  const S32 MAX_TEXTURE_UPDATE_INTERVAL = 64 ; //need to call updateTextures() at least every 32 frames.	 -const S32 MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL = S32_MAX ; //frames +const S32 MAX_TEXTURE_VIRTUAL_SIZE_RESET_INTERVAL = S32_MAX ; //frames  void LLVOAvatar::checkTextureLoading()  {  	static const F32 MAX_INVISIBLE_WAITING_TIME = 15.f ; //seconds @@ -4648,11 +4612,11 @@ const F32  ADDITIONAL_PRI = 0.5f;  void LLVOAvatar::addBakedTextureStats( LLViewerFetchedTexture* imagep, F32 pixel_area, F32 texel_area_ratio, S32 boost_level)  {  	//Note: -	//if this function is not called for the last MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL frames,  +	//if this function is not called for the last MAX_TEXTURE_VIRTUAL_SIZE_RESET_INTERVAL frames,   	//the texture pipeline will stop fetching this texture.  	imagep->resetTextureStats(); -	imagep->setMaxVirtualSizeResetInterval(MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL); +	imagep->setMaxVirtualSizeResetInterval(MAX_TEXTURE_VIRTUAL_SIZE_RESET_INTERVAL);  	imagep->resetMaxVirtualSizeResetCounter() ;  	mMaxPixelArea = llmax(pixel_area, mMaxPixelArea); @@ -4697,22 +4661,19 @@ const std::string LLVOAvatar::getImageURL(const U8 te, const LLUUID &uuid)  {  	llassert(isIndexBakedTexture(ETextureIndex(te)));  	std::string url = ""; -	if (isUsingServerBakes()) +	const std::string& appearance_service_url = LLAppearanceMgr::instance().getAppearanceServiceURL(); +	if (appearance_service_url.empty())  	{ -		const std::string& appearance_service_url = LLAppearanceMgr::instance().getAppearanceServiceURL(); -		if (appearance_service_url.empty()) -		{ -			// Probably a server-side issue if we get here: -			LL_WARNS() << "AgentAppearanceServiceURL not set - Baked texture requests will fail" << LL_ENDL; -			return url; -		} +		// Probably a server-side issue if we get here: +		LL_WARNS() << "AgentAppearanceServiceURL not set - Baked texture requests will fail" << LL_ENDL; +		return url; +	} -		const LLAvatarAppearanceDictionary::TextureEntry* texture_entry = LLAvatarAppearanceDictionary::getInstance()->getTexture((ETextureIndex)te); -		if (texture_entry != NULL) -		{ -			url = appearance_service_url + "texture/" + getID().asString() + "/" + texture_entry->mDefaultImageName + "/" + uuid.asString(); -			//LL_INFOS() << "baked texture url: " << url << LL_ENDL; -		} +	const LLAvatarAppearanceDictionary::TextureEntry* texture_entry = LLAvatarAppearanceDictionary::getInstance()->getTexture((ETextureIndex)te); +	if (texture_entry != NULL) +	{ +		url = appearance_service_url + "texture/" + getID().asString() + "/" + texture_entry->mDefaultImageName + "/" + uuid.asString(); +		//LL_INFOS() << "baked texture url: " << url << LL_ENDL;  	}  	return url;  } @@ -5096,70 +5057,39 @@ LLJoint *LLVOAvatar::getJoint( const std::string &name )  	return jointp;  } - -//----------------------------------------------------------------------------- -// resetJointPositions -//----------------------------------------------------------------------------- -void LLVOAvatar::resetJointPositions( void ) -{ -	avatar_joint_list_t::iterator iter = mSkeleton.begin(); -	avatar_joint_list_t::iterator end  = mSkeleton.end(); -	for (; iter != end; ++iter) -	{ -		(*iter)->restoreOldXform(); -		(*iter)->setId( LLUUID::null ); -	} -	mHasPelvisOffset = false; -	mPelvisFixup	 = mLastPelvisFixup; -} -//----------------------------------------------------------------------------- -// resetSpecificJointPosition -//----------------------------------------------------------------------------- -void LLVOAvatar::resetSpecificJointPosition( const std::string& name ) -{ -	LLJoint* pJoint = mRoot->findJoint( name ); -	 -	if ( pJoint  && pJoint->doesJointNeedToBeReset() ) -	{ -		pJoint->restoreOldXform(); -		pJoint->setId( LLUUID::null ); -		//If we're reseting the pelvis position make sure not to apply offset -		if ( name == "mPelvis" ) -		{ -			mHasPelvisOffset = false; -		} -	} -	else -	{ -		LL_INFOS()<<"Did not find "<< name.c_str()<<LL_ENDL; -	} -}  //-----------------------------------------------------------------------------  // resetJointPositionsToDefault  //-----------------------------------------------------------------------------  void LLVOAvatar::resetJointPositionsToDefault( void ) -{ +{	  	//Subsequent joints are relative to pelvis  	avatar_joint_list_t::iterator iter = mSkeleton.begin();  	avatar_joint_list_t::iterator end  = mSkeleton.end(); + +	LLJoint* pJointPelvis = getJoint("mPelvis"); +	  	for (; iter != end; ++iter)  	{  		LLJoint* pJoint = (*iter); -		if ( pJoint->doesJointNeedToBeReset() ) +		//Reset joints except for pelvis +		if ( pJoint && pJoint != pJointPelvis && pJoint->doesJointNeedToBeReset() ) +		{			 +			pJoint->setId( LLUUID::null ); +			pJoint->restoreOldXform(); +		}		 +		else +		if ( pJoint && pJoint == pJointPelvis && pJoint->doesJointNeedToBeReset() )  		{  			pJoint->setId( LLUUID::null ); -			//restore joints to default positions, however skip over the pelvis -			// *TODO: How does this pointer check skip over pelvis? -			if ( pJoint ) -			{ -				pJoint->restoreOldXform(); -			} -		} -	} +			pJoint->setPosition( LLVector3( 0.0f, 0.0f, 0.0f) ); +			pJoint->setJointResetFlag( false ); +		}		 +	}	 +		  	//make sure we don't apply the joint offset  	mHasPelvisOffset = false;  	mPelvisFixup	 = mLastPelvisFixup; -	postPelvisSetRecalc(); +	postPelvisSetRecalc();	  }  //-----------------------------------------------------------------------------  // getCharacterPosition() @@ -5314,7 +5244,7 @@ BOOL LLVOAvatar::loadSkeletonNode ()  			{  				attachment->setOriginalPosition(info->mPosition);  			} - +			  			if (info->mHasRotation)  			{  				LLQuaternion rotation; @@ -5384,7 +5314,6 @@ void LLVOAvatar::updateVisualParams()  	dirtyMesh();  	updateHeadOffset();  } -  //-----------------------------------------------------------------------------  // isActive()  //----------------------------------------------------------------------------- @@ -5541,11 +5470,11 @@ BOOL LLVOAvatar::updateGeometry(LLDrawable *drawable)  //-----------------------------------------------------------------------------  // updateSexDependentLayerSets()  //----------------------------------------------------------------------------- -void LLVOAvatar::updateSexDependentLayerSets( BOOL upload_bake ) +void LLVOAvatar::updateSexDependentLayerSets()  { -	invalidateComposite( mBakedTextureDatas[BAKED_HEAD].mTexLayerSet, upload_bake ); -	invalidateComposite( mBakedTextureDatas[BAKED_UPPER].mTexLayerSet, upload_bake ); -	invalidateComposite( mBakedTextureDatas[BAKED_LOWER].mTexLayerSet, upload_bake ); +	invalidateComposite( mBakedTextureDatas[BAKED_HEAD].mTexLayerSet); +	invalidateComposite( mBakedTextureDatas[BAKED_UPPER].mTexLayerSet); +	invalidateComposite( mBakedTextureDatas[BAKED_LOWER].mTexLayerSet);  }  //----------------------------------------------------------------------------- @@ -5761,6 +5690,7 @@ void LLVOAvatar::lazyAttach()  void LLVOAvatar::resetHUDAttachments()  { +  	for (attachment_map_t::iterator iter = mAttachmentPoints.begin();   		 iter != mAttachmentPoints.end();  		 ++iter) @@ -5813,10 +5743,10 @@ void LLVOAvatar::cleanupAttachedMesh( LLViewerObject* pVO )  		{  			const LLMeshSkinInfo* pSkinData = gMeshRepo.getSkinInfo( pVObj->getVolume()->getParams().getSculptID(), pVObj );  			if (pSkinData  -				&& pSkinData->mJointNames.size() > 20				// full rig -				&& pSkinData->mAlternateBindMatrix.size() > 0) -					{ -						LLVOAvatar::resetJointPositionsToDefault(); +				&& pSkinData->mJointNames.size() > JOINT_COUNT_REQUIRED_FOR_FULLRIG	// full rig +				&& pSkinData->mAlternateBindMatrix.size() > 0 ) +					{				 +						LLVOAvatar::resetJointPositionsToDefault();							  						//Need to handle the repositioning of the cam, updating rig data etc during outfit editing   						//This handles the case where we detach a replacement rig.  						if ( gAgentCamera.cameraCustomizeAvatar() ) @@ -5835,6 +5765,7 @@ void LLVOAvatar::cleanupAttachedMesh( LLViewerObject* pVO )  //-----------------------------------------------------------------------------  BOOL LLVOAvatar::detachObject(LLViewerObject *viewer_object)  { +  	for (attachment_map_t::iterator iter = mAttachmentPoints.begin();   		 iter != mAttachmentPoints.end();  		 ++iter) @@ -5845,6 +5776,7 @@ BOOL LLVOAvatar::detachObject(LLViewerObject *viewer_object)  		{  			mVisualComplexityStale = TRUE;  			cleanupAttachedMesh( viewer_object ); +		  			attachment->removeObject(viewer_object);  			LL_DEBUGS() << "Detaching object " << viewer_object->mID << " from " << attachment->getName() << LL_ENDL;  			return TRUE; @@ -6058,8 +5990,6 @@ BOOL LLVOAvatar::isWearingWearableType(LLWearableType::EType type) const  	return FALSE;  } - -  LLViewerObject *	LLVOAvatar::findAttachmentByID( const LLUUID & target_id ) const  {  	for(attachment_map_t::const_iterator attachment_points_iter = mAttachmentPoints.begin(); @@ -6083,9 +6013,8 @@ LLViewerObject *	LLVOAvatar::findAttachmentByID( const LLUUID & target_id ) cons  	return NULL;  } -  // virtual -void LLVOAvatar::invalidateComposite( LLTexLayerSet* layerset, BOOL upload_result ) +void LLVOAvatar::invalidateComposite( LLTexLayerSet* layerset)  {  } @@ -6094,18 +6023,18 @@ void LLVOAvatar::invalidateAll()  }  // virtual -void LLVOAvatar::onGlobalColorChanged(const LLTexGlobalColor* global_color, BOOL upload_bake ) +void LLVOAvatar::onGlobalColorChanged(const LLTexGlobalColor* global_color)  {  	if (global_color == mTexSkinColor)  	{ -		invalidateComposite( mBakedTextureDatas[BAKED_HEAD].mTexLayerSet, upload_bake ); -		invalidateComposite( mBakedTextureDatas[BAKED_UPPER].mTexLayerSet, upload_bake ); -		invalidateComposite( mBakedTextureDatas[BAKED_LOWER].mTexLayerSet, upload_bake ); +		invalidateComposite( mBakedTextureDatas[BAKED_HEAD].mTexLayerSet); +		invalidateComposite( mBakedTextureDatas[BAKED_UPPER].mTexLayerSet); +		invalidateComposite( mBakedTextureDatas[BAKED_LOWER].mTexLayerSet);  	}  	else if (global_color == mTexHairColor)  	{ -		invalidateComposite( mBakedTextureDatas[BAKED_HEAD].mTexLayerSet, upload_bake ); -		invalidateComposite( mBakedTextureDatas[BAKED_HAIR].mTexLayerSet, upload_bake ); +		invalidateComposite( mBakedTextureDatas[BAKED_HEAD].mTexLayerSet); +		invalidateComposite( mBakedTextureDatas[BAKED_HAIR].mTexLayerSet);  		// ! BACKWARDS COMPATIBILITY !  		// Fix for dealing with avatars from viewers that don't bake hair. @@ -6127,7 +6056,7 @@ void LLVOAvatar::onGlobalColorChanged(const LLTexGlobalColor* global_color, BOOL  	else if (global_color == mTexEyeColor)  	{  //		LL_INFOS() << "invalidateComposite cause: onGlobalColorChanged( eyecolor )" << LL_ENDL;  -		invalidateComposite( mBakedTextureDatas[BAKED_EYES].mTexLayerSet,  upload_bake ); +		invalidateComposite( mBakedTextureDatas[BAKED_EYES].mTexLayerSet);  	}  	updateMeshTextures();  } @@ -6218,9 +6147,12 @@ void LLVOAvatar::clearPhases()  void LLVOAvatar::startPhase(const std::string& phase_name)  { -	F32 elapsed; -	bool completed; -	if (getPhases().getPhaseValues(phase_name, elapsed, completed)) +	F32 elapsed = 0.0; +	bool completed = false; +	bool found = getPhases().getPhaseValues(phase_name, elapsed, completed); +	//LL_DEBUGS("Avatar") << avString() << " phase state " << phase_name +	//					<< " found " << found << " elapsed " << elapsed << " completed " << completed << LL_ENDL; +	if (found)  	{  		if (!completed)  		{ @@ -6233,9 +6165,9 @@ void LLVOAvatar::startPhase(const std::string& phase_name)  }  void LLVOAvatar::stopPhase(const std::string& phase_name, bool err_check) -		{ -	F32 elapsed; -	bool completed; +{ +	F32 elapsed = 0.0; +	bool completed = false;  	if (getPhases().getPhaseValues(phase_name, elapsed, completed))  	{  		if (!completed) @@ -6321,7 +6253,7 @@ void LLVOAvatar::logMetricsTimerRecord(const std::string& phase_name, F32 elapse  		}  	record["grid_x"] = LLSD::Integer(grid_x);  	record["grid_y"] = LLSD::Integer(grid_y); -	record["is_using_server_bakes"] = ((bool) isUsingServerBakes()); +	record["is_using_server_bakes"] = true;  	record["is_self"] = isSelf();  	if (isAgentAvatarValid()) @@ -6566,6 +6498,8 @@ void LLVOAvatar::updateMeshTextures()  				// we'll consider it loaded and use it (rather than  				// doing compositing).  				useBakedTexture( baked_img->getID() ); +                                mLoadedCallbacksPaused |= !isVisible(); +                                checkTextureLoading();  			}  			else  			{ @@ -6578,6 +6512,10 @@ void LLVOAvatar::updateMeshTextures()  				}  				baked_img->setLoadedCallback(onBakedTextureLoaded, SWITCH_TO_BAKED_DISCARD, FALSE, FALSE, new LLUUID( mID ),   					src_callback_list, paused ); + +                               // this could add paused texture callbacks +                               mLoadedCallbacksPaused |= paused;  +                               checkTextureLoading();  			}  		}  		else if (layerset && isUsingLocalAppearance()) @@ -6724,8 +6662,6 @@ void LLVOAvatar::applyMorphMask(U8* tex_data, S32 width, S32 height, S32 num_com  	}  } - -  // returns TRUE if morph masks are present and not valid for a given baked texture, FALSE otherwise  BOOL LLVOAvatar::morphMaskNeedsUpdate(LLAvatarAppearanceDefines::EBakedTextureIndex index)  { @@ -6936,6 +6872,9 @@ void LLVOAvatar::onFirstTEMessageReceived()  				LL_DEBUGS("Avatar") << avString() << "layer_baked, setting onInitialBakedTextureLoaded as callback" << LL_ENDL;  				image->setLoadedCallback( onInitialBakedTextureLoaded, MAX_DISCARD_LEVEL, FALSE, FALSE, new LLUUID( mID ),   					src_callback_list, paused ); + +                               // this could add paused texture callbacks +                               mLoadedCallbacksPaused |= paused;   			}  		} @@ -7008,7 +6947,7 @@ void dump_visual_param(apr_file_t* file, LLVisualParam* viewer_param, F32 value)  void LLVOAvatar::dumpAppearanceMsgParams( const std::string& dump_prefix,  	const LLAppearanceMessageContents& contents) -	{ +{  	std::string outfilename = get_sequential_numbered_file_name(dump_prefix,".xml");  	const std::vector<F32>& params_for_dump = contents.mParamWeights;  	const LLTEContents& tec = contents.mTEContents; @@ -7035,7 +6974,8 @@ void LLVOAvatar::dumpAppearanceMsgParams( const std::string& dump_prefix,  	LLVisualParam* param = getFirstVisualParam();  	for (S32 i = 0; i < params_for_dump.size(); i++)  	{ -		while( param && (param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE) ) // should not be any of group VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT +		while( param && ((param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE) &&  +						 (param->getGroup() != VISUAL_PARAM_GROUP_TRANSMIT_NOT_TWEAKABLE)) ) // should not be any of group VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT  		{  			param = getNextVisualParam();  		} @@ -7089,7 +7029,8 @@ void LLVOAvatar::parseAppearanceMessage(LLMessageSystem* mesgsys, LLAppearanceMe  		{  			for( S32 i = 0; i < num_blocks; i++ )  			{ -				while( param && (param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE) ) // should not be any of group VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT +				while( param && ((param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE) &&  +								 (param->getGroup() != VISUAL_PARAM_GROUP_TRANSMIT_NOT_TWEAKABLE)) ) // should not be any of group VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT  				{  					param = getNextVisualParam();  				} @@ -7110,7 +7051,8 @@ void LLVOAvatar::parseAppearanceMessage(LLMessageSystem* mesgsys, LLAppearanceMe  			}  		} -		const S32 expected_tweakable_count = getVisualParamCountInGroup(VISUAL_PARAM_GROUP_TWEAKABLE); // don't worry about VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT +		const S32 expected_tweakable_count = getVisualParamCountInGroup(VISUAL_PARAM_GROUP_TWEAKABLE) + +											 getVisualParamCountInGroup(VISUAL_PARAM_GROUP_TRANSMIT_NOT_TWEAKABLE); // don't worry about VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT  		if (num_blocks != expected_tweakable_count)  		{  			LL_DEBUGS("Avatar") << "Number of params in AvatarAppearance msg (" << num_blocks << ") does not match number of tweakable params in avatar xml file (" << expected_tweakable_count << ").  Processing what we can.  object: " << getID() << LL_ENDL; @@ -7157,13 +7099,13 @@ bool resolve_appearance_version(const LLAppearanceMessageContents& contents, S32  	{  		appearance_version = contents.mParamAppearanceVersion;  	} -	if (contents.mAppearanceVersion >= 0) +	else if (contents.mAppearanceVersion > 0)  	{  		appearance_version = contents.mAppearanceVersion;  	} -	if (appearance_version < 0) // still not set, go with 0. +	else // still not set, go with 1.  	{ -		appearance_version = 0; +		appearance_version = 1;  	}  	LL_DEBUGS("Avatar") << "appearance version info - field " << contents.mAppearanceVersion  						<< " param: " << contents.mParamAppearanceVersion @@ -7201,24 +7143,21 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )  		LL_WARNS() << "bad appearance version info, discarding" << LL_ENDL;  		return;  	} +	llassert(appearance_version > 0); +	if (appearance_version > 1) +	{ +		LL_WARNS() << "unsupported appearance version " << appearance_version << ", discarding appearance message" << LL_ENDL; +		return; +	} +  	S32 this_update_cof_version = contents.mCOFVersion;  	S32 last_update_request_cof_version = mLastUpdateRequestCOFVersion; -	// Only now that we have result of appearance_version can we decide whether to bail out.  	if( isSelf() )  	{  		LL_DEBUGS("Avatar") << "this_update_cof_version " << this_update_cof_version  				<< " last_update_request_cof_version " << last_update_request_cof_version  				<<  " my_cof_version " << LLAppearanceMgr::instance().getCOFVersion() << LL_ENDL; - -		if (getRegion() && (getRegion()->getCentralBakeVersion()==0)) -		{ -			LL_WARNS() << avString() << "Received AvatarAppearance message for self in non-server-bake region" << LL_ENDL; -		} -		if( mFirstTEMessageReceived && (appearance_version == 0)) -		{ -			return; -		}  	}  	else  	{ @@ -7227,7 +7166,6 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )  	// Check for stale update.  	if (isSelf() -		&& (appearance_version>0)  		&& (this_update_cof_version < last_update_request_cof_version))  	{  		LL_WARNS() << "Stale appearance update, wanted version " << last_update_request_cof_version @@ -7241,6 +7179,7 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )  		return;  	} +	// SUNSHINE CLEANUP - is this case OK now?  	S32 num_params = contents.mParamWeights.size();  	if (num_params <= 1)  	{ @@ -7252,10 +7191,14 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )  		return;  	} +	// No backsies zone - if we get here, the message should be valid and usable, will be processed. + +	// Note: +	// RequestAgentUpdateAppearanceResponder::onRequestRequested() +	// assumes that cof version is only updated with server-bake +	// appearance messages.  	mLastUpdateReceivedCOFVersion = this_update_cof_version; -	setIsUsingServerBakes(appearance_version > 0); -  	applyParsedTEMessage(contents.mTEContents);  	// prevent the overwriting of valid baked textures with invalid baked textures @@ -7265,9 +7208,15 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )  			&& mBakedTextureDatas[baked_index].mLastTextureID != IMG_DEFAULT  			&& baked_index != BAKED_SKIRT)  		{ +			LL_DEBUGS("Avatar") << avString() << " baked_index " << (S32) baked_index << " using mLastTextureID " << mBakedTextureDatas[baked_index].mLastTextureID << LL_ENDL;  			setTEImage(mBakedTextureDatas[baked_index].mTextureIndex,   				LLViewerTextureManager::getFetchedTexture(mBakedTextureDatas[baked_index].mLastTextureID, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE));  		} +		else +		{ +			LL_DEBUGS("Avatar") << avString() << " baked_index " << (S32) baked_index << " using texture id " +								<< getTE(mBakedTextureDatas[baked_index].mTextureIndex)->getID() << LL_ENDL; +		}  	}  	// runway - was @@ -7293,32 +7242,38 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )  		LL_DEBUGS("Avatar") << avString() << " handle visual params, num_params " << num_params << LL_ENDL;  		BOOL params_changed = FALSE;  		BOOL interp_params = FALSE; +		S32 params_changed_count = 0;  		for( S32 i = 0; i < num_params; i++ )  		{  			LLVisualParam* param = contents.mParams[i];  			F32 newWeight = contents.mParamWeights[i]; -				if (is_first_appearance_message || (param->getWeight() != newWeight)) +			if (is_first_appearance_message || (param->getWeight() != newWeight)) +			{ +				params_changed = TRUE; +				params_changed_count++; + +				if(is_first_appearance_message)  				{ -					params_changed = TRUE; -					if(is_first_appearance_message) -					{ -						param->setWeight(newWeight, FALSE); -					} -					else -					{ -						interp_params = TRUE; -						param->setAnimationTarget(newWeight, FALSE); -					} +					//LL_DEBUGS("Avatar") << "param slam " << i << " " << newWeight << LL_ENDL; +					param->setWeight(newWeight);  				} +				else +				{ +					interp_params = TRUE; +					param->setAnimationTarget(newWeight); +				} +			}  		} -		const S32 expected_tweakable_count = getVisualParamCountInGroup(VISUAL_PARAM_GROUP_TWEAKABLE); // don't worry about VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT +		const S32 expected_tweakable_count = getVisualParamCountInGroup(VISUAL_PARAM_GROUP_TWEAKABLE) + +											 getVisualParamCountInGroup(VISUAL_PARAM_GROUP_TRANSMIT_NOT_TWEAKABLE); // don't worry about VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT  		if (num_params != expected_tweakable_count)  		{  			LL_DEBUGS("Avatar") << "Number of params in AvatarAppearance msg (" << num_params << ") does not match number of tweakable params in avatar xml file (" << expected_tweakable_count << ").  Processing what we can.  object: " << getID() << LL_ENDL;  		} +		LL_DEBUGS("Avatar") << "Changed " << params_changed_count << " params" << LL_ENDL;  		if (params_changed)  		{  			if (interp_params) @@ -7330,7 +7285,7 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )  			ESex new_sex = getSex();  			if( old_sex != new_sex )  			{ -				updateSexDependentLayerSets( FALSE ); +				updateSexDependentLayerSets();  			}	  		} @@ -7368,7 +7323,6 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )  	}  	updateMeshTextures(); -  	//if (enable_verbose_dumps) dumpArchetypeXML(dump_prefix + "process_end");  } @@ -7553,7 +7507,7 @@ void LLVOAvatar::useBakedTexture( const LLUUID& id )  		LLViewerTexture* image_baked = getImage( mBakedTextureDatas[i].mTextureIndex, 0 );  		if (id == image_baked->getID())  		{ -			LL_DEBUGS("Avatar") << avString() << " i " << i << " id " << id << LL_ENDL; +			//LL_DEBUGS("Avatar") << avString() << " i " << i << " id " << id << LL_ENDL;  			mBakedTextureDatas[i].mIsLoaded = true;  			mBakedTextureDatas[i].mLastTextureID = id;  			mBakedTextureDatas[i].mIsUsed = true; @@ -7626,6 +7580,15 @@ std::string get_sequential_numbered_file_name(const std::string& prefix,  	return outfilename;  } +void dump_sequential_xml(const std::string outprefix, const LLSD& content) +{ +	std::string outfilename = get_sequential_numbered_file_name(outprefix,".xml"); +	std::string fullpath = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,outfilename); +	std::ofstream ofs(fullpath.c_str(), std::ios_base::out); +	ofs << LLSDOStreamer<LLSDXMLFormatter>(content, LLSDFormatter::OPTIONS_PRETTY); +	LL_DEBUGS("Avatar") << "results saved to: " << fullpath << LL_ENDL; +} +  void LLVOAvatar::dumpArchetypeXML(const std::string& prefix, bool group_by_wearables )  {  	std::string outprefix(prefix); @@ -7634,10 +7597,6 @@ void LLVOAvatar::dumpArchetypeXML(const std::string& prefix, bool group_by_weara  		outprefix = getFullname() + (isSelf()?"_s":"_o");  	}  	if (outprefix.empty()) -{ -		outprefix = getFullname() + (isSelf()?"_s":"_o"); -	} -	if (outprefix.empty())  	{  		outprefix = std::string("new_archetype");  	} @@ -7704,6 +7663,7 @@ void LLVOAvatar::dumpArchetypeXML(const std::string& prefix, bool group_by_weara  		for (U8 te = 0; te < TEX_NUM_INDICES; te++)  		{ +			{  				// MULTIPLE_WEARABLES: extend to multiple wearables?  				LLViewerTexture* te_image = getImage((ETextureIndex)te, 0);  				if( te_image ) @@ -7715,6 +7675,7 @@ void LLVOAvatar::dumpArchetypeXML(const std::string& prefix, bool group_by_weara  			}  		} +	}  	apr_file_printf( file, "\t</archetype>\n" );  	apr_file_printf( file, "\n</linden_genepool>\n" ); @@ -7837,41 +7798,6 @@ void LLVOAvatar::startAppearanceAnimation()  }  // virtual -void LLVOAvatar::bodySizeChanged() -{	 -	if (isSelf() && !LLAppearanceMgr::instance().isInUpdateAppearanceFromCOF()) -	{	// notify simulator of change in size -		// but not if we are in the middle of updating appearance -		gAgent.sendAgentSetAppearance(); -} -} - -BOOL LLVOAvatar::isUsingServerBakes() const -{ -#if 1 -	// Sanity check - visual param for appearance version should match mUseServerBakes -	LLVisualParam* appearance_version_param = getVisualParam(11000); -	llassert(appearance_version_param); -	F32 wt = appearance_version_param->getWeight(); -	F32 expect_wt = mUseServerBakes ? 1.0 : 0.0; -	if (!is_approx_equal(wt,expect_wt)) -{ -		LL_WARNS() << "wt " << wt << " differs from expected " << expect_wt << LL_ENDL; -	} -#endif - -	return mUseServerBakes; -		} -		 -void LLVOAvatar::setIsUsingServerBakes(BOOL newval) -		{ -	mUseServerBakes = newval; -	LLVisualParam* appearance_version_param = getVisualParam(11000); -	llassert(appearance_version_param); -	appearance_version_param->setWeight(newval ? 1.0 : 0.0, false); -		} - -// virtual  void LLVOAvatar::removeMissingBakedTextures()  			{  } diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 9d0391b42c..42ff7bff92 100755 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -199,9 +199,7 @@ public:  	virtual LLJoint*		getJoint(const std::string &name); -	void					resetJointPositions( void );  	void					resetJointPositionsToDefault( void ); -	void					resetSpecificJointPosition( const std::string& name );  	/*virtual*/ const LLUUID&	getID() const;  	/*virtual*/ void			addDebugText(const std::string& text); @@ -210,7 +208,7 @@ public:  	/*virtual*/ F32				getPixelArea() const;  	/*virtual*/ LLVector3d		getPosGlobalFromAgent(const LLVector3 &position);  	/*virtual*/ LLVector3		getPosAgentFromGlobal(const LLVector3d &position); -	virtual void			updateVisualParams(); +	virtual void				updateVisualParams();  /**                    Inherited @@ -442,7 +440,7 @@ public:  	// Global colors  	//--------------------------------------------------------------------  public: -	/*virtual*/void onGlobalColorChanged(const LLTexGlobalColor* global_color, BOOL upload_bake); +	/*virtual*/void onGlobalColorChanged(const LLTexGlobalColor* global_color);  	//--------------------------------------------------------------------  	// Visibility @@ -602,7 +600,7 @@ protected:  	// Composites  	//--------------------------------------------------------------------  public: -	virtual void	invalidateComposite(LLTexLayerSet* layerset, BOOL upload_result); +	virtual void	invalidateComposite(LLTexLayerSet* layerset);  	virtual void	invalidateAll();  	virtual void	setCompositeUpdatesEnabled(bool b) {}  	virtual void 	setCompositeUpdatesEnabled(U32 index, bool b) {} @@ -639,7 +637,7 @@ private:  public:  	void			debugColorizeSubMeshes(U32 i, const LLColor4& color);  	virtual void 	updateMeshTextures(); -	void 			updateSexDependentLayerSets(BOOL upload_bake); +	void 			updateSexDependentLayerSets();  	virtual void	dirtyMesh(); // Dirty the avatar mesh  	void 			updateMeshData();  protected: @@ -672,7 +670,6 @@ public:  	void 			processAvatarAppearance(LLMessageSystem* mesgsys);  	void 			hideSkirt();  	void			startAppearanceAnimation(); -	/*virtual*/ void bodySizeChanged();  	//--------------------------------------------------------------------  	// Appearance morphing @@ -685,12 +682,6 @@ public:  	// editing or when waiting for a subsequent server rebake.  	/*virtual*/ BOOL	isUsingLocalAppearance() const { return mUseLocalAppearance; } -	// True if this avatar should fetch its baked textures via the new -	// appearance mechanism. -	BOOL				isUsingServerBakes() const; -	void 				setIsUsingServerBakes(BOOL newval); - -  	// True if we are currently in appearance editing mode. Often but  	// not always the same as isUsingLocalAppearance().  	/*virtual*/ BOOL	isEditingAppearance() const { return mIsEditingAppearance; } @@ -703,7 +694,6 @@ private:  	F32				mLastAppearanceBlendTime;  	BOOL			mIsEditingAppearance; // flag for if we're actively in appearance editing mode  	BOOL			mUseLocalAppearance; // flag for if we're using a local composite -	BOOL			mUseServerBakes; // flag for if baked textures should be fetched from baking service (false if they're temporary uploads)  	//--------------------------------------------------------------------  	// Visibility @@ -1031,10 +1021,11 @@ protected: // Shared with LLVOAvatarSelf  }; // LLVOAvatar  extern const F32 SELF_ADDITIONAL_PRI; -extern const S32 MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL; +extern const S32 MAX_TEXTURE_VIRTUAL_SIZE_RESET_INTERVAL;  std::string get_sequential_numbered_file_name(const std::string& prefix,  											  const std::string& suffix); +void dump_sequential_xml(const std::string outprefix, const LLSD& content);  void dump_visual_param(apr_file_t* file, LLVisualParam* viewer_param, F32 value);  #endif // LL_VOAVATAR_H diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index 319da1abb5..1f497bc107 100755 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -161,8 +161,6 @@ LLVOAvatarSelf::LLVOAvatarSelf(const LLUUID& id,  	mRegionCrossingCount(0),  	mInitialBakesLoaded(false)  { -	gAgentWearables.setAvatarObject(this); -  	mMotionController.mIsSelf = TRUE;  	LL_DEBUGS() << "Marking avatar as self " << id << LL_ENDL; @@ -188,15 +186,6 @@ bool update_avatar_rez_metrics()  	return false;  } -bool check_for_unsupported_baked_appearance() -{ -	if (!isAgentAvatarValid()) -		return true; - -	gAgentAvatarp->checkForUnsupportedServerBakeAppearance(); -	return false; -} -  void LLVOAvatarSelf::initInstance()  {  	BOOL status = TRUE; @@ -233,7 +222,33 @@ void LLVOAvatarSelf::initInstance()  	//doPeriodically(output_self_av_texture_diagnostics, 30.0);  	doPeriodically(update_avatar_rez_metrics, 5.0); -	doPeriodically(check_for_unsupported_baked_appearance, 120.0); +	doPeriodically(boost::bind(&LLVOAvatarSelf::checkStuckAppearance, this), 30.0); +} + +bool LLVOAvatarSelf::checkStuckAppearance() +{ +	const F32 CONDITIONAL_UNSTICK_INTERVAL = 300.0; +	const F32 UNCONDITIONAL_UNSTICK_INTERVAL = 600.0; +	 +	if (gAgentWearables.isCOFChangeInProgress()) +	{ +		LL_DEBUGS("Avatar") << "checking for stuck appearance" << LL_ENDL; +		F32 change_time = gAgentWearables.getCOFChangeTime(); +		LL_DEBUGS("Avatar") << "change in progress for " << change_time << " seconds" << LL_ENDL; +		S32 active_hp = LLAppearanceMgr::instance().countActiveHoldingPatterns(); +		LL_DEBUGS("Avatar") << "active holding patterns " << active_hp << " seconds" << LL_ENDL; +		S32 active_copies = LLAppearanceMgr::instance().getActiveCopyOperations(); +		LL_DEBUGS("Avatar") << "active copy operations " << active_copies << LL_ENDL; + +		if ((change_time > CONDITIONAL_UNSTICK_INTERVAL && active_copies == 0) || +			(change_time > UNCONDITIONAL_UNSTICK_INTERVAL)) +		{ +			gAgentWearables.notifyLoadingFinished(); +		} +	} + +	// Return false to continue running check periodically. +	return LLApp::isExiting();  }  // virtual @@ -644,55 +659,42 @@ LLJoint *LLVOAvatarSelf::getJoint(const std::string &name)  	}  	return LLVOAvatar::getJoint(name);  } -//virtual -void LLVOAvatarSelf::resetJointPositions( void ) -{ -	return LLVOAvatar::resetJointPositions(); -}  // virtual -BOOL LLVOAvatarSelf::setVisualParamWeight(const LLVisualParam *which_param, F32 weight, BOOL upload_bake ) +BOOL LLVOAvatarSelf::setVisualParamWeight(const LLVisualParam *which_param, F32 weight)  {  	if (!which_param)  	{  		return FALSE;  	}  	LLViewerVisualParam *param = (LLViewerVisualParam*) LLCharacter::getVisualParam(which_param->getID()); -	return setParamWeight(param,weight,upload_bake); +	return setParamWeight(param,weight);  }  // virtual -BOOL LLVOAvatarSelf::setVisualParamWeight(const char* param_name, F32 weight, BOOL upload_bake ) +BOOL LLVOAvatarSelf::setVisualParamWeight(const char* param_name, F32 weight)  {  	if (!param_name)  	{  		return FALSE;  	}  	LLViewerVisualParam *param = (LLViewerVisualParam*) LLCharacter::getVisualParam(param_name); -	return setParamWeight(param,weight,upload_bake); +	return setParamWeight(param,weight);  }  // virtual -BOOL LLVOAvatarSelf::setVisualParamWeight(S32 index, F32 weight, BOOL upload_bake ) +BOOL LLVOAvatarSelf::setVisualParamWeight(S32 index, F32 weight)  {  	LLViewerVisualParam *param = (LLViewerVisualParam*) LLCharacter::getVisualParam(index); -	return setParamWeight(param,weight,upload_bake); +	return setParamWeight(param,weight);  } -BOOL LLVOAvatarSelf::setParamWeight(const LLViewerVisualParam *param, F32 weight, BOOL upload_bake ) +BOOL LLVOAvatarSelf::setParamWeight(const LLViewerVisualParam *param, F32 weight)  {  	if (!param)  	{  		return FALSE;  	} -#if 0 -	// FIXME DRANO - kludgy way to avoid overwriting avatar state from wearables. -	if (isUsingServerBakes() && !isUsingLocalAppearance()) -	{ -		return FALSE; -	} -#endif -  	if (param->getCrossWearable())  	{  		LLWearableType::EType type = (LLWearableType::EType)param->getWearableType(); @@ -702,12 +704,12 @@ BOOL LLVOAvatarSelf::setParamWeight(const LLViewerVisualParam *param, F32 weight  			LLViewerWearable *wearable = gAgentWearables.getViewerWearable(type,count);  			if (wearable)  			{ -				wearable->setVisualParamWeight(param->getID(), weight, upload_bake); +				wearable->setVisualParamWeight(param->getID(), weight);  			}  		}  	} -	return LLCharacter::setVisualParamWeight(param,weight,upload_bake); +	return LLCharacter::setVisualParamWeight(param,weight);  }  /*virtual*/  @@ -720,7 +722,7 @@ void LLVOAvatarSelf::updateVisualParams()  void LLVOAvatarSelf::idleUpdateAppearanceAnimation()  {  	// Animate all top-level wearable visual parameters -	gAgentWearables.animateAllWearableParams(calcMorphAmount(), FALSE); +	gAgentWearables.animateAllWearableParams(calcMorphAmount());  	// apply wearable visual params to avatar  	for (U32 type = 0; type < LLWearableType::WT_COUNT; type++) @@ -762,57 +764,6 @@ void LLVOAvatarSelf::stopMotionFromSource(const LLUUID& source_id)  	}  } -//virtual -U32  LLVOAvatarSelf::processUpdateMessage(LLMessageSystem *mesgsys, -													 void **user_data, -													 U32 block_num, -													 const EObjectUpdateType update_type, -													 LLDataPacker *dp) -{ -	U32 retval = LLVOAvatar::processUpdateMessage(mesgsys,user_data,block_num,update_type,dp); - -#if 0 -	// DRANO - it's not clear this does anything useful. If we wait -	// until an appearance message has been received, we already have -	// the texture ids. If we don't wait, we don't yet know where to -	// look for baked textures, because we haven't received the -	// appearance version data from the appearance message. This looks -	// like an old optimization that's incompatible with server-side -	// texture baking. -	 -	// FIXME DRANO - skipping in the case of !mFirstAppearanceMessageReceived prevents us from trying to -	// load textures before we know where they come from (ie, from baking service or not); -	// unknown impact on performance. -	if (mInitialBakesLoaded == false && retval == 0x0 && mFirstAppearanceMessageReceived) -	{ -		// call update textures to force the images to be created -		updateMeshTextures(); - -		// unpack the texture UUIDs to the texture slots -		if(mesgsys != NULL) -		{ -		retval = unpackTEMessage(mesgsys, _PREHASH_ObjectData, (S32) block_num); -		} - -		// need to trigger a few operations to get the avatar to use the new bakes -		for (U32 i = 0; i < mBakedTextureDatas.size(); i++) -		{ -			const LLAvatarAppearanceDefines::ETextureIndex te = mBakedTextureDatas[i].mTextureIndex; -			LLUUID texture_id = getTEImage(te)->getID(); -			setNewBakedTexture(te, texture_id); -			mInitialBakeIDs[i] = texture_id; -		} - -		onFirstTEMessageReceived(); - -		mInitialBakesLoaded = true; -	} -#endif - -	return retval; -} - -  void LLVOAvatarSelf::setLocalTextureTE(U8 te, LLViewerTexture* image, U32 index)  {  	if (te >= TEX_NUM_INDICES) @@ -864,13 +815,9 @@ void LLVOAvatarSelf::removeMissingBakedTextures()  		{  			LLViewerTexLayerSet *layerset = getTexLayerSet(i);  			layerset->setUpdatesEnabled(TRUE); -			invalidateComposite(layerset, FALSE); -		} -		updateMeshTextures();	// may call back into this function -		if (getRegion() && !getRegion()->getCentralBakeVersion()) -		{ -			requestLayerSetUploads(); +			invalidateComposite(layerset);  		} +		updateMeshTextures();  	}  } @@ -1039,7 +986,7 @@ void LLVOAvatarSelf::updateAttachmentVisibility(U32 camera_mode)  // forces an update to any baked textures relevant to type.  // will force an upload of the resulting bake if the second parameter is TRUE  //----------------------------------------------------------------------------- -void LLVOAvatarSelf::wearableUpdated( LLWearableType::EType type, BOOL upload_result ) +void LLVOAvatarSelf::wearableUpdated(LLWearableType::EType type)  {  	for (LLAvatarAppearanceDictionary::BakedTextures::const_iterator baked_iter = LLAvatarAppearanceDictionary::getInstance()->getBakedTextures().begin();  		 baked_iter != LLAvatarAppearanceDictionary::getInstance()->getBakedTextures().end(); @@ -1061,20 +1008,13 @@ void LLVOAvatarSelf::wearableUpdated( LLWearableType::EType type, BOOL upload_re  					if (layerset)  					{  						layerset->setUpdatesEnabled(true); -						invalidateComposite(layerset, upload_result); +						invalidateComposite(layerset);  					}  					break;  				}  			}  		}  	} -	 -	// Physics type has no associated baked textures, but change of params needs to be sent to -	// other avatars. -	if (type == LLWearableType::WT_PHYSICS) -	  { -	    gAgent.sendAgentSetAppearance(); -	  }  }  //----------------------------------------------------------------------------- @@ -1486,15 +1426,6 @@ BOOL LLVOAvatarSelf::isAllLocalTextureDataFinal() const  	return TRUE;  } -BOOL LLVOAvatarSelf::isBakedTextureFinal(const LLAvatarAppearanceDefines::EBakedTextureIndex index) const -{ -	const LLViewerTexLayerSet *layerset = getLayerSet(index); -	if (!layerset) return FALSE; -	const LLViewerTexLayerSetBuffer *layerset_buffer = layerset->getViewerComposite(); -	if (!layerset_buffer) return FALSE; -	return !layerset_buffer->uploadNeeded(); -} -  BOOL LLVOAvatarSelf::isTextureDefined(LLAvatarAppearanceDefines::ETextureIndex type, U32 index) const  {  	LLUUID id; @@ -1552,49 +1483,12 @@ BOOL LLVOAvatarSelf::isTextureVisible(LLAvatarAppearanceDefines::ETextureIndex t  	return isTextureVisible(type,index);  } - -//----------------------------------------------------------------------------- -// requestLayerSetUploads() -//----------------------------------------------------------------------------- -void LLVOAvatarSelf::requestLayerSetUploads() -{ -	for (U32 i = 0; i < mBakedTextureDatas.size(); i++) -	{ -		requestLayerSetUpload((EBakedTextureIndex)i); -	} -} - -void LLVOAvatarSelf::requestLayerSetUpload(LLAvatarAppearanceDefines::EBakedTextureIndex i) -{ -	ETextureIndex tex_index = mBakedTextureDatas[i].mTextureIndex; -	const BOOL layer_baked = isTextureDefined(tex_index, gAgentWearables.getWearableCount(tex_index)); -	LLViewerTexLayerSet *layerset = getLayerSet(i); -	if (!layer_baked && layerset) -	{ -		layerset->requestUpload(); -	} -} -  bool LLVOAvatarSelf::areTexturesCurrent() const  { -	return !hasPendingBakedUploads() && gAgentWearables.areWearablesLoaded(); +	return gAgentWearables.areWearablesLoaded();  } -// virtual -bool LLVOAvatarSelf::hasPendingBakedUploads() const -{ -	for (U32 i = 0; i < mBakedTextureDatas.size(); i++) -	{ -		LLViewerTexLayerSet* layerset = getTexLayerSet(i); -		if (layerset && layerset->getViewerComposite() && layerset->getViewerComposite()->uploadPending()) -		{ -			return true; -		} -	} -	return false; -} - -void LLVOAvatarSelf::invalidateComposite( LLTexLayerSet* layerset, BOOL upload_result ) +void LLVOAvatarSelf::invalidateComposite( LLTexLayerSet* layerset)  {  	LLViewerTexLayerSet *layer_set = dynamic_cast<LLViewerTexLayerSet*>(layerset);  	if( !layer_set || !layer_set->getUpdatesEnabled() ) @@ -1605,16 +1499,6 @@ void LLVOAvatarSelf::invalidateComposite( LLTexLayerSet* layerset, BOOL upload_r  	layer_set->requestUpdate();  	layer_set->invalidateMorphMasks(); - -	if( upload_result  && (getRegion() && !getRegion()->getCentralBakeVersion())) -	{ -		llassert(isSelf()); - -		ETextureIndex baked_te = getBakedTE( layer_set ); -		setTEImage( baked_te, LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT_AVATAR) ); -		layer_set->requestUpload(); -		updateMeshTextures(); -	}  }  void LLVOAvatarSelf::invalidateAll() @@ -1622,7 +1506,7 @@ void LLVOAvatarSelf::invalidateAll()  	for (U32 i = 0; i < mBakedTextureDatas.size(); i++)  	{  		LLViewerTexLayerSet *layerset = getTexLayerSet(i); -		invalidateComposite(layerset, TRUE); +		invalidateComposite(layerset);  	}  	//mDebugSelfLoadTimer.reset();  } @@ -2217,27 +2101,9 @@ const std::string LLVOAvatarSelf::debugDumpAllLocalTextureDataInfo() const  	return text;  } - -#if 0 -// Dump avatar metrics data. -LLSD LLVOAvatarSelf::metricsData() -{ -	// runway - add region info -	LLSD result; -	result["rez_status"] = LLVOAvatar::rezStatusToString(getRezzedStatus()); -	result["timers"]["debug_existence"] = mDebugExistenceTimer.getElapsedTimeF32(); -	result["timers"]["ruth_debug"] = mRuthDebugTimer.getElapsedTimeF32(); -	result["timers"]["ruth"] = mRuthTimer.getElapsedTimeF32(); -	result["timers"]["invisible"] = mInvisibleTimer.getElapsedTimeF32(); -	result["timers"]["fully_loaded"] = mFullyLoadedTimer.getElapsedTimeF32(); -	result["startup"] = LLStartUp::getPhases().asLLSD(); -	 -	return result; -} -#endif -  class ViewerAppearanceChangeMetricsResponder: public LLCurl::Responder  { +	LOG_CLASS(ViewerAppearanceChangeMetricsResponder);  public:  	ViewerAppearanceChangeMetricsResponder( S32 expected_sequence,  											volatile const S32 & live_sequence, @@ -2248,32 +2114,25 @@ public:  	{  	} -	virtual void completed(U32 status, -						   const std::string& reason, -						   const LLSD& content) +private: +	/* virtual */ void httpSuccess()  	{ -		gPendingMetricsUploads--; // if we add retry, this should be moved to the isGoodStatus case. -		if (isGoodStatus(status)) -		{ -			LL_DEBUGS("Avatar") << "OK" << LL_ENDL; -			result(content); -		} -		else -		{ -			LL_WARNS("Avatar") << "Failed " << status << " reason " << reason << LL_ENDL; -			errorWithContent(status,reason,content); -		} -	} +		LL_DEBUGS("Avatar") << "OK" << LL_ENDL; -	// virtual -	void result(const LLSD & content) -	{ +		gPendingMetricsUploads--;  		if (mLiveSequence == mExpectedSequence)  		{  			mReportingStarted = true;  		}  	} +	/* virtual */ void httpFailure() +	{ +		// if we add retry, this should be removed from the httpFailure case +		LL_WARNS("Avatar") << dumpResponse() << LL_ENDL; +		gPendingMetricsUploads--; +	} +  private:  	S32 mExpectedSequence;  	volatile const S32 & mLiveSequence; @@ -2356,11 +2215,10 @@ LLSD summarize_by_buckets(std::vector<LLSD> in_records,  void LLVOAvatarSelf::sendViewerAppearanceChangeMetrics()  { -	// gAgentAvatarp->stopAllPhases();  	static volatile bool reporting_started(false);  	static volatile S32 report_sequence(0); -	LLSD msg; // = metricsData(); +	LLSD msg;  	msg["message"] = "ViewerAppearanceChangeMetrics";  	msg["session_id"] = gAgentSessionID;  	msg["agent_id"] = gAgentID; @@ -2420,63 +2278,6 @@ void LLVOAvatarSelf::sendViewerAppearanceChangeMetrics()  	}  } -class CheckAgentAppearanceServiceResponder: public LLHTTPClient::Responder -{ -public: -	CheckAgentAppearanceServiceResponder() -	{ -	} -	 -	virtual ~CheckAgentAppearanceServiceResponder() -	{ -	} - -	/* virtual */ void result(const LLSD& content) -	{ -		LL_DEBUGS("Avatar") << "status OK" << LL_ENDL; -	} - -	// Error -	/*virtual*/ void errorWithContent(U32 status, const std::string& reason, const LLSD& content) -	{ -		if (isAgentAvatarValid()) -		{ -			LL_DEBUGS("Avatar") << "failed, will rebake [status:" -					<< status << "]: " << content << LL_ENDL; -			forceAppearanceUpdate(); -		} -	}	 - -	static void forceAppearanceUpdate() -	{ -		// Trying to rebake immediately after crossing region boundary -		// seems to be failure prone; adding a delay factor. Yes, this -		// fix is ad-hoc and not guaranteed to work in all cases. -		doAfterInterval(boost::bind(&LLVOAvatarSelf::forceBakeAllTextures, -									gAgentAvatarp.get(), true), 5.0); -	} -}; - -void LLVOAvatarSelf::checkForUnsupportedServerBakeAppearance() -{ -	// Need to check only if we have a server baked appearance and are -	// in a non-baking region. -	if (!gAgentAvatarp->isUsingServerBakes()) -		return; -	if (!gAgent.getRegion() || gAgent.getRegion()->getCentralBakeVersion()!=0) -		return; - -	// if baked image service is unknown, need to refresh. -	if (LLAppearanceMgr::instance().getAppearanceServiceURL().empty()) -	{ -		CheckAgentAppearanceServiceResponder::forceAppearanceUpdate(); -	} -	// query baked image service to check status. -	std::string image_url = gAgentAvatarp->getImageURL(TEX_HEAD_BAKED, -													   getTE(TEX_HEAD_BAKED)->getID()); -	LLHTTPClient::head(image_url, new CheckAgentAppearanceServiceResponder); -} -  const LLUUID& LLVOAvatarSelf::grabBakedTexture(EBakedTextureIndex baked_index) const  {  	if (canGrabBakedTexture(baked_index)) @@ -2587,7 +2388,7 @@ void LLVOAvatarSelf::addLocalTextureStats( ETextureIndex type, LLViewerFetchedTe  				imagep->setBoostLevel(getAvatarBoostLevel());  				imagep->setAdditionalDecodePriority(SELF_ADDITIONAL_PRI) ;  				imagep->resetTextureStats(); -				imagep->setMaxVirtualSizeResetInterval(MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL); +				imagep->setMaxVirtualSizeResetInterval(MAX_TEXTURE_VIRTUAL_SIZE_RESET_INTERVAL);  				imagep->addTextureStats( desired_pixels / texel_area_ratio );  				imagep->forceUpdateBindStats() ;  				if (imagep->getDiscardLevel() < 0) @@ -2633,82 +2434,6 @@ ETextureIndex LLVOAvatarSelf::getBakedTE( const LLViewerTexLayerSet* layerset )  	return TEX_HEAD_BAKED;  } - -void LLVOAvatarSelf::setNewBakedTexture(LLAvatarAppearanceDefines::EBakedTextureIndex i, const LLUUID &uuid) -{ -	ETextureIndex index = LLAvatarAppearanceDictionary::bakedToLocalTextureIndex(i); -	setNewBakedTexture(index, uuid); -} - - -//----------------------------------------------------------------------------- -// setNewBakedTexture() -// A new baked texture has been successfully uploaded and we can start using it now. -//----------------------------------------------------------------------------- -void LLVOAvatarSelf::setNewBakedTexture( ETextureIndex te, const LLUUID& uuid ) -{ -	// Baked textures live on other sims. -	LLHost target_host = getObjectHost();	 -	setTEImage( te, LLViewerTextureManager::getFetchedTextureFromHost( uuid, FTT_HOST_BAKE, target_host ) ); -	updateMeshTextures(); -	dirtyMesh(); - -	LLVOAvatar::cullAvatarsByPixelArea(); - -	/* switch(te) -		case TEX_HEAD_BAKED: -			LL_INFOS() << "New baked texture: HEAD" << LL_ENDL; */ -	const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = LLAvatarAppearanceDictionary::getInstance()->getTexture(te); -	if (texture_dict->mIsBakedTexture) -	{ -		debugBakedTextureUpload(texture_dict->mBakedTextureIndex, TRUE); // FALSE for start of upload, TRUE for finish. -		LL_INFOS() << "New baked texture: " << texture_dict->mName << " UUID: " << uuid <<LL_ENDL; -	} -	else -	{ -		LL_WARNS() << "New baked texture: unknown te " << te << LL_ENDL; -	} -	 -	//	dumpAvatarTEs( "setNewBakedTexture() send" ); -	// RN: throttle uploads -	if (!hasPendingBakedUploads()) -	{ -		gAgent.sendAgentSetAppearance(); - -		if (gSavedSettings.getBOOL("DebugAvatarRezTime")) -		{ -			LLSD args; -			args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32()); -			args["TIME"] = llformat("%d",(U32)mDebugSelfLoadTimer.getElapsedTimeF32()); -			if (isAllLocalTextureDataFinal()) -			{ -				LLNotificationsUtil::add("AvatarRezSelfBakedDoneNotification",args); -				LL_DEBUGS("Avatar") << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() -						<< "sec ]" -						<< avString()  -						<< "RuthTimer " << (U32)mRuthDebugTimer.getElapsedTimeF32() -						<< " SelfLoadTimer " << (U32)mDebugSelfLoadTimer.getElapsedTimeF32() -						<< " Notification " << "AvatarRezSelfBakedDoneNotification" -						<< LL_ENDL; -			} -			else -			{ -				args["STATUS"] = debugDumpAllLocalTextureDataInfo(); -				LLNotificationsUtil::add("AvatarRezSelfBakedUpdateNotification",args); -				LL_DEBUGS("Avatar") << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() -						<< "sec ]" -						<< avString()  -						<< "RuthTimer " << (U32)mRuthDebugTimer.getElapsedTimeF32() -						<< " SelfLoadTimer " << (U32)mDebugSelfLoadTimer.getElapsedTimeF32() -						<< " Notification " << "AvatarRezSelfBakedUpdateNotification" -						<< LL_ENDL; -			} -		} - -		outputRezDiagnostics(); -	} -} -  // FIXME: This is not called consistently. Something may be broken.  void LLVOAvatarSelf::outputRezDiagnostics() const  { @@ -2784,89 +2509,7 @@ void LLVOAvatarSelf::reportAvatarRezTime() const  	// TODO: report mDebugSelfLoadTimer.getElapsedTimeF32() somehow.  } -//----------------------------------------------------------------------------- -// setCachedBakedTexture() -// A baked texture id was received from a cache query, make it active -//----------------------------------------------------------------------------- -void LLVOAvatarSelf::setCachedBakedTexture( ETextureIndex te, const LLUUID& uuid ) -{ -	setTETexture( te, uuid ); - -	/* switch(te) -		case TEX_HEAD_BAKED: -			if( mHeadLayerSet ) -				mHeadLayerSet->cancelUpload(); */ -	for (U32 i = 0; i < mBakedTextureDatas.size(); i++) -	{ -		LLViewerTexLayerSet *layerset = getTexLayerSet(i); -		if ( mBakedTextureDatas[i].mTextureIndex == te && layerset) -		{ -			if (mInitialBakeIDs[i] != LLUUID::null) -			{ -				if (mInitialBakeIDs[i] == uuid) -				{ -					LL_INFOS() << "baked texture correctly loaded at login! " << i << LL_ENDL; -				} -				else -				{ -					LL_WARNS() << "baked texture does not match id loaded at login!" << i << LL_ENDL; -				} -				mInitialBakeIDs[i] = LLUUID::null; -			} -			layerset->cancelUpload(); -		} -	} -} - -// static -void LLVOAvatarSelf::processRebakeAvatarTextures(LLMessageSystem* msg, void**) -{ -	LLUUID texture_id; -	msg->getUUID("TextureData", "TextureID", texture_id); -	if (!isAgentAvatarValid()) return; - -	// If this is a texture corresponding to one of our baked entries,  -	// just rebake that layer set. -	BOOL found = FALSE; - -	/* ETextureIndex baked_texture_indices[BAKED_NUM_INDICES] = -			TEX_HEAD_BAKED, -			TEX_UPPER_BAKED, */ -	for (LLAvatarAppearanceDictionary::Textures::const_iterator iter = LLAvatarAppearanceDictionary::getInstance()->getTextures().begin(); -		 iter != LLAvatarAppearanceDictionary::getInstance()->getTextures().end(); -		 ++iter) -	{ -		const ETextureIndex index = iter->first; -		const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = iter->second; -		if (texture_dict->mIsBakedTexture) -		{ -			if (texture_id == gAgentAvatarp->getTEImage(index)->getID()) -			{ -				LLViewerTexLayerSet* layer_set = gAgentAvatarp->getLayerSet(index); -				if (layer_set) -				{ -					LL_INFOS() << "TAT: rebake - matched entry " << (S32)index << LL_ENDL; -					gAgentAvatarp->invalidateComposite(layer_set, TRUE); -					found = TRUE; -					add(LLStatViewer::TEX_REBAKES, 1); -				} -			} -		} -	} - -	// If texture not found, rebake all entries. -	if (!found) -	{ -		gAgentAvatarp->forceBakeAllTextures(); -	} -	else -	{ -		// Not sure if this is necessary, but forceBakeAllTextures() does it. -		gAgentAvatarp->updateMeshTextures(); -	} -} - - +// SUNSHINE CLEANUP - not clear we need any of this, may be sufficient to request server appearance in llviewermenu.cpp:handle_rebake_textures()  void LLVOAvatarSelf::forceBakeAllTextures(bool slam_for_debug)  {  	LL_INFOS() << "TAT: forced full rebake. " << LL_ENDL; @@ -2880,10 +2523,9 @@ void LLVOAvatarSelf::forceBakeAllTextures(bool slam_for_debug)  			if (slam_for_debug)  			{  				layer_set->setUpdatesEnabled(TRUE); -				layer_set->cancelUpload();  			} -			invalidateComposite(layer_set, TRUE); +			invalidateComposite(layer_set);  			add(LLStatViewer::TEX_REBAKES, 1);  		}  		else @@ -2952,6 +2594,11 @@ void LLVOAvatarSelf::onCustomizeStart(bool disable_camera_switch)  {  	if (isAgentAvatarValid())  	{ +		if (!gAgentAvatarp->mEndCustomizeCallback.get()) +		{ +			gAgentAvatarp->mEndCustomizeCallback = new LLUpdateAppearanceOnDestroy; +		} +		  		gAgentAvatarp->mIsEditingAppearance = true;  		gAgentAvatarp->mUseLocalAppearance = true; @@ -2978,12 +2625,6 @@ void LLVOAvatarSelf::onCustomizeEnd(bool disable_camera_switch)  	if (isAgentAvatarValid())  	{  		gAgentAvatarp->mIsEditingAppearance = false; -		if (gAgentAvatarp->getRegion() && !gAgentAvatarp->getRegion()->getCentralBakeVersion()) -		{ -			// FIXME DRANO - move to sendAgentSetAppearance, make conditional on upload complete. -			gAgentAvatarp->mUseLocalAppearance = false; -		} -  		gAgentAvatarp->invalidateAll();  		if (gSavedSettings.getBOOL("AppearanceCameraMovement") && !disable_camera_switch) @@ -2991,8 +2632,11 @@ void LLVOAvatarSelf::onCustomizeEnd(bool disable_camera_switch)  			gAgentCamera.changeCameraToDefault();  			gAgentCamera.resetView();  		} -	 -		LLAppearanceMgr::instance().updateAppearanceFromCOF();	 + +		// Dereferencing the previous callback will cause +		// updateAppearanceFromCOF to be called, whenever all refs +		// have resolved. +		gAgentAvatarp->mEndCustomizeCallback = NULL;  	}  } diff --git a/indra/newview/llvoavatarself.h b/indra/newview/llvoavatarself.h index 444175b62e..e03de9fa0b 100755 --- a/indra/newview/llvoavatarself.h +++ b/indra/newview/llvoavatarself.h @@ -33,6 +33,7 @@  #include <map>  struct LocalTextureData; +class LLInventoryCallback;  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -87,21 +88,15 @@ public:  				void		resetJointPositions( void ); -	/*virtual*/ BOOL setVisualParamWeight(const LLVisualParam *which_param, F32 weight, BOOL upload_bake = FALSE ); -	/*virtual*/ BOOL setVisualParamWeight(const char* param_name, F32 weight, BOOL upload_bake = FALSE ); -	/*virtual*/ BOOL setVisualParamWeight(S32 index, F32 weight, BOOL upload_bake = FALSE ); +	/*virtual*/ BOOL setVisualParamWeight(const LLVisualParam *which_param, F32 weight); +	/*virtual*/ BOOL setVisualParamWeight(const char* param_name, F32 weight); +	/*virtual*/ BOOL setVisualParamWeight(S32 index, F32 weight);  	/*virtual*/ void updateVisualParams();  	/*virtual*/ void idleUpdateAppearanceAnimation(); -	/*virtual*/ U32  processUpdateMessage(LLMessageSystem *mesgsys, -													 void **user_data, -													 U32 block_num, -													 const EObjectUpdateType update_type, -													 LLDataPacker *dp); -  private:  	// helper function. Passed in param is assumed to be in avatar's parameter list. -	BOOL setParamWeight(const LLViewerVisualParam *param, F32 weight, BOOL upload_bake = FALSE ); +	BOOL setParamWeight(const LLViewerVisualParam *param, F32 weight); @@ -129,6 +124,7 @@ public:  public:  	/*virtual*/ BOOL 	updateCharacter(LLAgent &agent);  	/*virtual*/ void 	idleUpdateTractorBeam(); +	bool				checkStuckAppearance();  	//--------------------------------------------------------------------  	// Loading state @@ -185,12 +181,10 @@ public:  	// Loading status  	//--------------------------------------------------------------------  public: -	/*virtual*/ bool	hasPendingBakedUploads() const;  	S32					getLocalDiscardLevel(LLAvatarAppearanceDefines::ETextureIndex type, U32 index) const;  	bool				areTexturesCurrent() const;  	BOOL				isLocalTextureDataAvailable(const LLViewerTexLayerSet* layerset) const;  	BOOL				isLocalTextureDataFinal(const LLViewerTexLayerSet* layerset) const; -	BOOL				isBakedTextureFinal(const LLAvatarAppearanceDefines::EBakedTextureIndex index) const;  	// If you want to check all textures of a given type, pass gAgentWearables.getWearableCount() for index  	/*virtual*/ BOOL    isTextureDefined(LLAvatarAppearanceDefines::ETextureIndex type, U32 index) const;  	/*virtual*/ BOOL	isTextureVisible(LLAvatarAppearanceDefines::ETextureIndex type, U32 index = 0) const; @@ -225,11 +219,8 @@ private:  	//--------------------------------------------------------------------  public:  	LLAvatarAppearanceDefines::ETextureIndex getBakedTE(const LLViewerTexLayerSet* layerset ) const; -	void				setNewBakedTexture(LLAvatarAppearanceDefines::EBakedTextureIndex i, const LLUUID &uuid); -	void				setNewBakedTexture(LLAvatarAppearanceDefines::ETextureIndex i, const LLUUID& uuid); -	void				setCachedBakedTexture(LLAvatarAppearanceDefines::ETextureIndex i, const LLUUID& uuid); +	// SUNSHINE CLEANUP - dead? or update to just call request appearance update?  	void				forceBakeAllTextures(bool slam_for_debug = false); -	static void			processRebakeAvatarTextures(LLMessageSystem* msg, void**);  protected:  	/*virtual*/ void	removeMissingBakedTextures(); @@ -237,8 +228,6 @@ protected:  	// Layers  	//--------------------------------------------------------------------  public: -	void 				requestLayerSetUploads(); -	void				requestLayerSetUpload(LLAvatarAppearanceDefines::EBakedTextureIndex i);  	void				requestLayerSetUpdate(LLAvatarAppearanceDefines::ETextureIndex i);  	LLViewerTexLayerSet* getLayerSet(LLAvatarAppearanceDefines::EBakedTextureIndex baked_index) const;  	LLViewerTexLayerSet* getLayerSet(LLAvatarAppearanceDefines::ETextureIndex index) const; @@ -248,7 +237,7 @@ public:  	// Composites  	//--------------------------------------------------------------------  public: -	/* virtual */ void	invalidateComposite(LLTexLayerSet* layerset, BOOL upload_result); +	/* virtual */ void	invalidateComposite(LLTexLayerSet* layerset);  	/* virtual */ void	invalidateAll();  	/* virtual */ void	setCompositeUpdatesEnabled(bool b); // only works for self  	/* virtual */ void  setCompositeUpdatesEnabled(U32 index, bool b); @@ -290,7 +279,7 @@ protected:   **/  public: -	void				wearableUpdated(LLWearableType::EType type, BOOL upload_result); +	void				wearableUpdated(LLWearableType::EType type);  protected:  	U32 getNumWearables(LLAvatarAppearanceDefines::ETextureIndex i) const; @@ -331,6 +320,7 @@ private:  public:  	static void		onCustomizeStart(bool disable_camera_switch = false);  	static void		onCustomizeEnd(bool disable_camera_switch = false); +	LLPointer<LLInventoryCallback> mEndCustomizeCallback;  	//--------------------------------------------------------------------  	// Visibility @@ -392,7 +382,6 @@ public:  	const std::string		debugDumpLocalTextureDataInfo(const LLViewerTexLayerSet* layerset) const; // Lists out state of this particular baked texture layer  	const std::string		debugDumpAllLocalTextureDataInfo() const; // Lists out which baked textures are at highest LOD  	void					sendViewerAppearanceChangeMetrics(); // send data associated with completing a change. -	void 					checkForUnsupportedServerBakeAppearance();  private:  	LLFrameTimer    		mDebugSelfLoadTimer;  	F32						mDebugTimeWearablesLoaded; diff --git a/indra/newview/llvoicechannel.cpp b/indra/newview/llvoicechannel.cpp index 312842a70f..3c3dc33772 100755 --- a/indra/newview/llvoicechannel.cpp +++ b/indra/newview/llvoicechannel.cpp @@ -55,26 +55,27 @@ const U32 DEFAULT_RETRIES_COUNT = 3;  class LLVoiceCallCapResponder : public LLHTTPClient::Responder  { +	LOG_CLASS(LLVoiceCallCapResponder);  public:  	LLVoiceCallCapResponder(const LLUUID& session_id) : mSessionID(session_id) {}; +protected:  	// called with bad status codes -	virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content); -	virtual void result(const LLSD& content); +	virtual void httpFailure(); +	virtual void httpSuccess();  private:  	LLUUID mSessionID;  }; -void LLVoiceCallCapResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void LLVoiceCallCapResponder::httpFailure()  { -	LL_WARNS("Voice") << "LLVoiceCallCapResponder error [status:" -		<< status << "]: " << content << LL_ENDL; +	LL_WARNS("Voice") << dumpResponse() << LL_ENDL;  	LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(mSessionID);  	if ( channelp )  	{ -		if ( 403 == status ) +		if ( HTTP_FORBIDDEN == getStatus() )  		{  			//403 == no ability  			LLNotificationsUtil::add( @@ -91,12 +92,18 @@ void LLVoiceCallCapResponder::errorWithContent(U32 status, const std::string& re  	}  } -void LLVoiceCallCapResponder::result(const LLSD& content) +void LLVoiceCallCapResponder::httpSuccess()  {  	LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(mSessionID);  	if (channelp)  	{  		//*TODO: DEBUG SPAM +		const LLSD& content = getContent(); +		if (!content.isMap()) +		{ +			failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); +			return; +		}  		LLSD::map_const_iterator iter;  		for(iter = content.beginMap(); iter != content.endMap(); ++iter)  		{ diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index 09a2003ef8..9937a1c42a 100755 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -124,17 +124,19 @@ static int scale_speaker_volume(float volume)  class LLVivoxVoiceAccountProvisionResponder :  	public LLHTTPClient::Responder  { +	LOG_CLASS(LLVivoxVoiceAccountProvisionResponder);  public:  	LLVivoxVoiceAccountProvisionResponder(int retries)  	{  		mRetries = retries;  	} -	virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content) +private: +	/* virtual */ void httpFailure()  	{  		LL_WARNS("Voice") << "ProvisionVoiceAccountRequest returned an error, "  			<<  ( (mRetries > 0) ? "retrying" : "too many retries (giving up)" ) -			<< status << "]: " << content << LL_ENDL; +			<< " " << dumpResponse() << LL_ENDL;  		if ( mRetries > 0 )  		{ @@ -146,14 +148,19 @@ public:  		}  	} -	virtual void result(const LLSD& content) +	/* virtual */ void httpSuccess()  	{ -  		std::string voice_sip_uri_hostname;  		std::string voice_account_server_uri; -		LL_DEBUGS("Voice") << "ProvisionVoiceAccountRequest response:" << ll_pretty_print_sd(content) << LL_ENDL; +		LL_DEBUGS("Voice") << "ProvisionVoiceAccountRequest response:" << dumpResponse() << LL_ENDL; +		const LLSD& content = getContent(); +		if (!content.isMap()) +		{ +			failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); +			return; +		}  		if(content.has("voice_sip_uri_hostname"))  			voice_sip_uri_hostname = content["voice_sip_uri_hostname"].asString(); @@ -166,7 +173,6 @@ public:  			content["password"].asString(),  			voice_sip_uri_hostname,  			voice_account_server_uri); -  	}  private: @@ -190,33 +196,34 @@ static bool sMuteListListener_listening = false;  class LLVivoxVoiceClientCapResponder : public LLHTTPClient::Responder  { +	LOG_CLASS(LLVivoxVoiceClientCapResponder);  public:  	LLVivoxVoiceClientCapResponder(LLVivoxVoiceClient::state requesting_state) : mRequestingState(requesting_state) {}; +private:  	// called with bad status codes -	virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content); -	virtual void result(const LLSD& content); +	/* virtual */ void httpFailure(); +	/* virtual */ void httpSuccess(); -private:  	LLVivoxVoiceClient::state mRequestingState;  // state   }; -void LLVivoxVoiceClientCapResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void LLVivoxVoiceClientCapResponder::httpFailure()  { -	LL_WARNS("Voice") << "LLVivoxVoiceClientCapResponder error [status:" -		<< status << "]: " << content << LL_ENDL; +	LL_WARNS("Voice") << dumpResponse() << LL_ENDL;  	LLVivoxVoiceClient::getInstance()->sessionTerminate();  } -void LLVivoxVoiceClientCapResponder::result(const LLSD& content) +void LLVivoxVoiceClientCapResponder::httpSuccess()  {  	LLSD::map_const_iterator iter; -	LL_DEBUGS("Voice") << "ParcelVoiceInfoRequest response:" << ll_pretty_print_sd(content) << LL_ENDL; +	LL_DEBUGS("Voice") << "ParcelVoiceInfoRequest response:" << dumpResponse() << LL_ENDL;  	std::string uri;  	std::string credentials; +	const LLSD& content = getContent();  	if ( content.has("voice_credentials") )  	{  		LLSD voice_credentials = content["voice_credentials"]; @@ -2651,7 +2658,7 @@ void LLVivoxVoiceClient::loginResponse(int statusCode, std::string &statusString  	// Status code of 20200 means "bad password".  We may want to special-case that at some point. -	if ( statusCode == 401 ) +	if ( statusCode == HTTP_UNAUTHORIZED )  	{  		// Login failure which is probably caused by the delay after a user's password being updated.  		LL_INFOS("Voice") << "Account.Login response failure (" << statusCode << "): " << statusString << LL_ENDL; @@ -3153,7 +3160,7 @@ void LLVivoxVoiceClient::mediaStreamUpdatedEvent(  		switch(statusCode)  		{  			case 0: -			case 200: +			case HTTP_OK:  				// generic success  				// Don't change the saved error code (it may have been set elsewhere)  			break; @@ -3426,7 +3433,7 @@ void LLVivoxVoiceClient::messageEvent(  	LL_DEBUGS("Voice") << "Message event, session " << sessionHandle << " from " << uriString << LL_ENDL;  //	LL_DEBUGS("Voice") << "    header " << messageHeader << ", body: \n" << messageBody << LL_ENDL; -	if(messageHeader.find("text/html") != std::string::npos) +	if(messageHeader.find(HTTP_CONTENT_TEXT_HTML) != std::string::npos)  	{  		std::string message; @@ -5393,9 +5400,10 @@ void LLVivoxVoiceClient::notifyStatusObservers(LLVoiceClientStatusObserver::ESta  		{  			switch(mAudioSession->mErrorStatusCode)  			{ -				case 404:	// NOT_FOUND +				case HTTP_NOT_FOUND:	// NOT_FOUND +				// *TODO: Should this be 503?  				case 480:	// TEMPORARILY_UNAVAILABLE -				case 408:	// REQUEST_TIMEOUT +				case HTTP_REQUEST_TIME_OUT:	// REQUEST_TIMEOUT  					// call failed because other user was not available  					// treat this as an error case  					status = LLVoiceClientStatusObserver::ERROR_NOT_AVAILABLE; diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index d1108020ff..c9f03a3b7d 100755 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -82,7 +82,7 @@ const S32 MIN_QUIET_FRAMES_COALESCE = 30;  const F32 FORCE_SIMPLE_RENDER_AREA = 512.f;  const F32 FORCE_CULL_AREA = 8.f;  const F32 MAX_LOD_DISTANCE = 24.f; - +U32 JOINT_COUNT_REQUIRED_FOR_FULLRIG = 20;  BOOL gAnimateTextures = TRUE;  //extern BOOL gHideSelectedObjects; @@ -4458,7 +4458,10 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)  	bool emissive = false; -	 +	//Determine if we've received skininfo that contains an +	//alternate bind matrix - if it does then apply the translational component +	//to the joints of the avatar. +	bool pelvisGotSet = false;  	{  		LL_RECORD_BLOCK_TIME(FTM_REBUILD_VOLUME_FACE_LIST); @@ -4541,18 +4544,12 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)  					is_rigged = true;  					//get drawpool of avatar with rigged face -					LLDrawPoolAvatar* pool = get_avatar_drawpool(vobj); -				 -					//Determine if we've received skininfo that contains an -					//alternate bind matrix - if it does then apply the translational component -					//to the joints of the avatar. -					bool pelvisGotSet = false; - +					LLDrawPoolAvatar* pool = get_avatar_drawpool(vobj);				 +					  					if ( pAvatarVO )  					{ -						LLUUID currentId = vobj->getVolume()->getParams().getSculptID(); +						LLUUID currentId = vobj->getVolume()->getParams().getSculptID();						  						const LLMeshSkinInfo*  pSkinData = gMeshRepo.getSkinInfo( currentId, vobj ); -					  						if ( pSkinData )  						{  							const int bindCnt = pSkinData->mAlternateBindMatrix.size();								 @@ -4560,43 +4557,42 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)  							{					  								const int jointCnt = pSkinData->mJointNames.size();  								const F32 pelvisZOffset = pSkinData->mPelvisOffset; -								bool fullRig = (jointCnt>=20) ? true : false; +								bool fullRig = (jointCnt>=JOINT_COUNT_REQUIRED_FOR_FULLRIG) ? true : false;								  								if ( fullRig ) -								{ +								{								  									for ( int i=0; i<jointCnt; ++i )  									{  										std::string lookingForJoint = pSkinData->mJointNames[i].c_str(); -										//LL_INFOS()<<"joint name "<<lookingForJoint.c_str()<<LL_ENDL;  										LLJoint* pJoint = pAvatarVO->getJoint( lookingForJoint );  										if ( pJoint && pJoint->getId() != currentId )  										{   									  											pJoint->setId( currentId );  											const LLVector3& jointPos = pSkinData->mAlternateBindMatrix[i].getTranslation();									 +											  											//Set the joint position -											pJoint->storeCurrentXform( jointPos );																																 +											pJoint->storeCurrentXform( jointPos );					 +									  											//If joint is a pelvis then handle old/new pelvis to foot values  											if ( lookingForJoint == "mPelvis" )  											{	 -												pJoint->storeCurrentXform( jointPos );																																  												if ( !pAvatarVO->hasPelvisOffset() )  												{										  													pAvatarVO->setPelvisOffset( true, jointPos, pelvisZOffset ); -													//Trigger to rebuild viewer AV  													pelvisGotSet = true;											  												}										  											}										 -										} -									} +										}										 +									}																  								}							  							}  						}  					} -					//If we've set the pelvis to a new position we need to also rebuild some information that the -					//viewer does at launch (e.g. body size etc.) -					if ( pelvisGotSet ) +					 +					//Rebuild body data if we altered joints/pelvis +					if ( pelvisGotSet && pAvatarVO )   					{  						pAvatarVO->postPelvisSetRecalc(); -					} +					}		  					if (pool)  					{ @@ -4952,7 +4948,16 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)  			{  				drawablep->clearState(LLDrawable::RIGGED);  			} +			  		} + +		 +		 +			 +		 +					 + +		  	}  	group->mBufferUsage = useage; diff --git a/indra/newview/llwearablelist.cpp b/indra/newview/llwearablelist.cpp index 6085893129..b61fbbd073 100755 --- a/indra/newview/llwearablelist.cpp +++ b/indra/newview/llwearablelist.cpp @@ -81,6 +81,7 @@ void LLWearableList::getAsset(const LLAssetID& assetID, const std::string& weara  	LLViewerWearable* instance = get_if_there(mList, assetID, (LLViewerWearable*)NULL );  	if( instance )  	{ +		LL_DEBUGS("Avatar") << "wearable " << assetID << " found in LLWearableList" << LL_ENDL;  		asset_arrived_callback( instance, userdata );  	}  	else diff --git a/indra/newview/llwebprofile.cpp b/indra/newview/llwebprofile.cpp index 0cf0e7b9c0..ddb7f7bfce 100755 --- a/indra/newview/llwebprofile.cpp +++ b/indra/newview/llwebprofile.cpp @@ -67,9 +67,8 @@ public:  	{  	} +	// *TODO: Check for 'application/json' content type, and parse json at the base class.  	/*virtual*/ void completedRaw( -		U32 status, -		const std::string& reason,  		const LLChannelDescriptors& channels,  		const LLIOPipe::buffer_ptr_t& buffer)  	{ @@ -78,9 +77,9 @@ public:  		strstrm << istr.rdbuf();  		const std::string body = strstrm.str(); -		if (status != 200) +		if (getStatus() != HTTP_OK)  		{ -			LL_WARNS() << "Failed to get upload config (" << status << ")" << LL_ENDL; +			LL_WARNS() << "Failed to get upload config " << dumpResponse() << LL_ENDL;  			LLWebProfile::reportImageUploadStatus(false);  			return;  		} @@ -128,14 +127,12 @@ class LLWebProfileResponders::PostImageRedirectResponder : public LLHTTPClient::  public:  	/*virtual*/ void completedRaw( -		U32 status, -		const std::string& reason,  		const LLChannelDescriptors& channels,  		const LLIOPipe::buffer_ptr_t& buffer)  	{ -		if (status != 200) +		if (getStatus() != HTTP_OK)  		{ -			LL_WARNS() << "Failed to upload image: " << status << " " << reason << LL_ENDL; +			LL_WARNS() << "Failed to upload image " << dumpResponse() << LL_ENDL;  			LLWebProfile::reportImageUploadStatus(false);  			return;  		} @@ -158,33 +155,36 @@ class LLWebProfileResponders::PostImageResponder : public LLHTTPClient::Responde  	LOG_CLASS(LLWebProfileResponders::PostImageResponder);  public: -	/*virtual*/ void completedHeader(U32 status, const std::string& reason, const LLSD& content) +	/*virtual*/ void completedRaw(const LLChannelDescriptors& channels, +								  const LLIOPipe::buffer_ptr_t& buffer)  	{  		// Viewer seems to fail to follow a 303 redirect on POST request  		// (URLRequest Error: 65, Send failed since rewinding of the data stream failed).  		// Handle it manually. -		if (status == 303) +		if (getStatus() == HTTP_SEE_OTHER)  		{  			LLSD headers = LLViewerMedia::getHeaders(); -			headers["Cookie"] = LLWebProfile::getAuthCookie(); -			const std::string& redir_url = content["location"]; -			LL_DEBUGS("Snapshots") << "Got redirection URL: " << redir_url << LL_ENDL; -			LLHTTPClient::get(redir_url, new LLWebProfileResponders::PostImageRedirectResponder(), headers); +			headers[HTTP_OUT_HEADER_COOKIE] = LLWebProfile::getAuthCookie(); +			const std::string& redir_url = getResponseHeader(HTTP_IN_HEADER_LOCATION); +			if (redir_url.empty()) +			{ +				LL_WARNS() << "Received empty redirection URL " << dumpResponse() << LL_ENDL; +				LL_DEBUGS("Snapshots") << "[headers:" << getResponseHeaders() << "]" << LL_ENDL; +				LLWebProfile::reportImageUploadStatus(false); +			} +			else +			{ +				LL_DEBUGS("Snapshots") << "Got redirection URL: " << redir_url << LL_ENDL; +				LLHTTPClient::get(redir_url, new LLWebProfileResponders::PostImageRedirectResponder, headers); +			}  		}  		else  		{ -			LL_WARNS() << "Unexpected POST status: " << status << " " << reason << LL_ENDL; -			LL_DEBUGS("Snapshots") << "headers: [" << content << "]" << LL_ENDL; +			LL_WARNS() << "Unexpected POST response " << dumpResponse() << LL_ENDL; +			LL_DEBUGS("Snapshots") << "[headers:" << getResponseHeaders() << "]" << LL_ENDL;  			LLWebProfile::reportImageUploadStatus(false);  		}  	} - -	// Override just to suppress warnings. -	/*virtual*/ void completedRaw(U32 status, const std::string& reason, -							  const LLChannelDescriptors& channels, -							  const LLIOPipe::buffer_ptr_t& buffer) -	{ -	}  };  /////////////////////////////////////////////////////////////////////////////// @@ -203,7 +203,7 @@ void LLWebProfile::uploadImage(LLPointer<LLImageFormatted> image, const std::str  	LL_DEBUGS("Snapshots") << "Requesting " << config_url << LL_ENDL;  	LLSD headers = LLViewerMedia::getHeaders(); -	headers["Cookie"] = getAuthCookie(); +	headers[HTTP_OUT_HEADER_COOKIE] = getAuthCookie();  	LLHTTPClient::get(config_url, new LLWebProfileResponders::ConfigResponder(image), headers);  } @@ -227,8 +227,8 @@ void LLWebProfile::post(LLPointer<LLImageFormatted> image, const LLSD& config, c  	const std::string boundary = "----------------------------0123abcdefab";  	LLSD headers = LLViewerMedia::getHeaders(); -	headers["Cookie"] = getAuthCookie(); -	headers["Content-Type"] = "multipart/form-data; boundary=" + boundary; +	headers[HTTP_OUT_HEADER_COOKIE] = getAuthCookie(); +	headers[HTTP_OUT_HEADER_CONTENT_TYPE] = "multipart/form-data; boundary=" + boundary;  	std::ostringstream body; diff --git a/indra/newview/llwlhandlers.cpp b/indra/newview/llwlhandlers.cpp index 93eba5b604..3bedfbe502 100755 --- a/indra/newview/llwlhandlers.cpp +++ b/indra/newview/llwlhandlers.cpp @@ -95,8 +95,9 @@ LLEnvironmentRequestResponder::LLEnvironmentRequestResponder()  {  	mID = ++sCount;  } -/*virtual*/ void LLEnvironmentRequestResponder::result(const LLSD& unvalidated_content) +/*virtual*/ void LLEnvironmentRequestResponder::httpSuccess()  { +	const LLSD& unvalidated_content = getContent();  	LL_INFOS("WindlightCaps") << "Received region windlight settings" << LL_ENDL;  	if (mID != sCount) @@ -122,10 +123,10 @@ LLEnvironmentRequestResponder::LLEnvironmentRequestResponder()  	LLEnvManagerNew::getInstance()->onRegionSettingsResponse(unvalidated_content);  }  /*virtual*/ -void LLEnvironmentRequestResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void LLEnvironmentRequestResponder::httpFailure()  { -	LL_INFOS("WindlightCaps") << "Got an error, not using region windlight... [status:"  -		<< status << "]: " << content << LL_ENDL; +	LL_WARNS("WindlightCaps") << "Got an error, not using region windlight... " +			<< dumpResponse() << LL_ENDL;  	LLEnvManagerNew::getInstance()->onRegionSettingsResponse(LLSD());  } @@ -169,8 +170,14 @@ bool LLEnvironmentApply::initiateRequest(const LLSD& content)  /****   * LLEnvironmentApplyResponder   ****/ -/*virtual*/ void LLEnvironmentApplyResponder::result(const LLSD& content) +/*virtual*/ void LLEnvironmentApplyResponder::httpSuccess()  { +	const LLSD& content = getContent(); +	if (!content.isMap() || !content.has("regionID")) +	{ +		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); +		return; +	}  	if (content["regionID"].asUUID() != gAgent.getRegion()->getRegionID())  	{  		LL_WARNS("WindlightCaps") << "No longer in the region where data was sent (currently " @@ -185,7 +192,7 @@ bool LLEnvironmentApply::initiateRequest(const LLSD& content)  	}  	else  	{ -		LL_WARNS("WindlightCaps") << "Region couldn't apply windlight settings!  Reason from sim: " << content["fail_reason"].asString() << LL_ENDL; +		LL_WARNS("WindlightCaps") << "Region couldn't apply windlight settings!  " << dumpResponse() << LL_ENDL;  		LLSD args(LLSD::emptyMap());  		args["FAIL_REASON"] = content["fail_reason"].asString();  		LLNotificationsUtil::add("WLRegionApplyFail", args); @@ -193,14 +200,14 @@ bool LLEnvironmentApply::initiateRequest(const LLSD& content)  	}  }  /*virtual*/ -void LLEnvironmentApplyResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void LLEnvironmentApplyResponder::httpFailure()  { -	LL_WARNS("WindlightCaps") << "Couldn't apply windlight settings to region!  [status:" -		<< status << "]: " << content << LL_ENDL; +	LL_WARNS("WindlightCaps") << "Couldn't apply windlight settings to region! " +		<< dumpResponse() << LL_ENDL;  	LLSD args(LLSD::emptyMap());  	std::stringstream msg; -	msg << reason << " (Code " << status << ")"; +	msg << getReason() << " (Code " << getStatus() << ")";  	args["FAIL_REASON"] = msg.str();  	LLNotificationsUtil::add("WLRegionApplyFail", args);  } diff --git a/indra/newview/llwlhandlers.h b/indra/newview/llwlhandlers.h index 598ce6d52a..089c799da7 100755 --- a/indra/newview/llwlhandlers.h +++ b/indra/newview/llwlhandlers.h @@ -45,9 +45,9 @@ private:  class LLEnvironmentRequestResponder: public LLHTTPClient::Responder  {  	LOG_CLASS(LLEnvironmentRequestResponder); -public: -	virtual void result(const LLSD& content); -	virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content); +private: +	/* virtual */ void httpSuccess(); +	/* virtual */ void httpFailure();  private:  	friend class LLEnvironmentRequest; @@ -72,7 +72,7 @@ private:  class LLEnvironmentApplyResponder: public LLHTTPClient::Responder  {  	LOG_CLASS(LLEnvironmentApplyResponder); -public: +private:  	/*  	 * Expecting reply from sim in form of:  	 * { @@ -87,10 +87,10 @@ public:  	 *   fail_reason : string  	 * }  	 */ -	virtual void result(const LLSD& content); +	/* virtual */ void httpSuccess(); -	// non-200 errors only -	virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content); +	// non-2xx errors only +	/* virtual */ void httpFailure();  private:  	friend class LLEnvironmentApply; diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp index 1ef2cfff8a..b4e8114a5f 100755 --- a/indra/newview/llworld.cpp +++ b/indra/newview/llworld.cpp @@ -1149,6 +1149,8 @@ public:  					<< sim << LL_ENDL;  			return;  		} +		LL_DEBUGS("CrossingCaps") << "Calling setSeedCapability from LLEstablishAgentCommunication::post. Seed cap == " +				<< input["body"]["seed-capability"] << LL_ENDL;  		regionp->setSeedCapability(input["body"]["seed-capability"]);  	}  }; diff --git a/indra/newview/llxmlrpctransaction.cpp b/indra/newview/llxmlrpctransaction.cpp index 8e164337b6..c12c2cc24c 100755 --- a/indra/newview/llxmlrpctransaction.cpp +++ b/indra/newview/llxmlrpctransaction.cpp @@ -333,7 +333,7 @@ void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip)  	   This might help with bug #503 */  	mCurlRequest->setopt(CURLOPT_DNS_CACHE_TIMEOUT, -1); -    mCurlRequest->slist_append("Content-Type: text/xml"); +    mCurlRequest->slist_append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_TEXT_XML);  	if (useGzip)  	{ diff --git a/indra/newview/tests/llhttpretrypolicy_test.cpp b/indra/newview/tests/llhttpretrypolicy_test.cpp new file mode 100755 index 0000000000..25e6de46d9 --- /dev/null +++ b/indra/newview/tests/llhttpretrypolicy_test.cpp @@ -0,0 +1,328 @@ +/**  + * @file llhttpretrypolicy_test.cpp + * @brief Header tests to exercise the LLHTTPRetryPolicy classes. + * + * $LicenseInfo:firstyear=2013&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2013, Linden Research, Inc. + *  + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + *  + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + *  + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + *  + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA + * $/LicenseInfo$ + */ + +#include "../llviewerprecompiledheaders.h" +#include "../llhttpretrypolicy.h" +#include "lltut.h" + +namespace tut +{ +struct TestData +{ +}; + +typedef test_group<TestData>	RetryPolicyTestGroup; +typedef RetryPolicyTestGroup::object		RetryPolicyTestObject; +RetryPolicyTestGroup retryPolicyTestGroup("retry_policy"); + +template<> template<> +void RetryPolicyTestObject::test<1>() +{ +	LLAdaptiveRetryPolicy never_retry(1.0,1.0,1.0,0); +	LLSD headers; +	F32 wait_seconds; +	 +	// No retry until we've failed a try. +	ensure("never retry 0", !never_retry.shouldRetry(wait_seconds)); + +	// 0 retries max. +	never_retry.onFailure(500,headers); +	ensure("never retry 1", !never_retry.shouldRetry(wait_seconds));  +} + +template<> template<> +void RetryPolicyTestObject::test<2>() +{ +	LLSD headers; +	F32 wait_seconds; + +	// Normally only retry on server error (5xx) +	LLAdaptiveRetryPolicy noRetry404(1.0,2.0,3.0,10); +	noRetry404.onFailure(404,headers); +	ensure("no retry on 404", !noRetry404.shouldRetry(wait_seconds));  + +	// Can retry on 4xx errors if enabled by flag. +	bool do_retry_4xx = true; +	LLAdaptiveRetryPolicy doRetry404(1.0,2.0,3.0,10,do_retry_4xx); +	doRetry404.onFailure(404,headers); +	ensure("do retry on 404", doRetry404.shouldRetry(wait_seconds));  +} + +template<> template<> +void RetryPolicyTestObject::test<3>() +{ +	// Should retry after 1.0, 2.0, 3.0, 3.0 seconds. +	LLAdaptiveRetryPolicy basic_retry(1.0,3.0,2.0,4); +	LLSD headers; +	F32 wait_seconds; +	bool should_retry; +	U32 frac_bits = 6; + +	// No retry until we've failed a try. +	ensure("basic_retry 0", !basic_retry.shouldRetry(wait_seconds)); + +	// Starting wait 1.0 +	basic_retry.onFailure(500,headers); +	should_retry = basic_retry.shouldRetry(wait_seconds); +	ensure("basic_retry 1", should_retry); +	ensure_approximately_equals("basic_retry 1", wait_seconds, 1.0F, frac_bits); + +	// Double wait to 2.0 +	basic_retry.onFailure(500,headers); +	should_retry = basic_retry.shouldRetry(wait_seconds); +	ensure("basic_retry 2", should_retry); +	ensure_approximately_equals("basic_retry 2", wait_seconds, 2.0F, frac_bits); + +	// Hit max wait of 3.0 (4.0 clamped to max 3) +	basic_retry.onFailure(500,headers); +	should_retry = basic_retry.shouldRetry(wait_seconds); +	ensure("basic_retry 3", should_retry); +	ensure_approximately_equals("basic_retry 3", wait_seconds, 3.0F, frac_bits); + +	// At max wait, should stay at 3.0 +	basic_retry.onFailure(500,headers); +	should_retry = basic_retry.shouldRetry(wait_seconds); +	ensure("basic_retry 4", should_retry); +	ensure_approximately_equals("basic_retry 4", wait_seconds, 3.0F, frac_bits); + +	// Max retries, should fail now. +	basic_retry.onFailure(500,headers); +	should_retry = basic_retry.shouldRetry(wait_seconds); +	ensure("basic_retry 5", !should_retry); + +	// Max retries, should fail now. +	basic_retry.onFailure(500,headers); +	should_retry = basic_retry.shouldRetry(wait_seconds); +	ensure("basic_retry 5", !should_retry); + +	// After a success, should reset to the starting state. +	basic_retry.onSuccess(); + +	// No retry until we've failed a try. +	ensure("basic_retry 6", !basic_retry.shouldRetry(wait_seconds)); + +	// Starting wait 1.0 +	basic_retry.onFailure(500,headers); +	should_retry = basic_retry.shouldRetry(wait_seconds); +	ensure("basic_retry 7", should_retry); +	ensure_approximately_equals("basic_retry 7", wait_seconds, 1.0F, frac_bits); + +	// Double wait to 2.0 +	basic_retry.onFailure(500,headers); +	should_retry = basic_retry.shouldRetry(wait_seconds); +	ensure("basic_retry 8", should_retry); +	ensure_approximately_equals("basic_retry 8", wait_seconds, 2.0F, frac_bits); +} + +// Retries should stop as soon as a non-5xx error is received. +template<> template<> +void RetryPolicyTestObject::test<4>() +{ +	// Should retry after 1.0, 2.0, 3.0, 3.0 seconds. +	LLAdaptiveRetryPolicy killer404(1.0,3.0,2.0,4); +	LLSD headers; +	F32 wait_seconds; +	bool should_retry; +	U32 frac_bits = 6; + +	// Starting wait 1.0 +	killer404.onFailure(500,headers); +	should_retry = killer404.shouldRetry(wait_seconds); +	ensure("killer404 1", should_retry); +	ensure_approximately_equals("killer404 1", wait_seconds, 1.0F, frac_bits); + +	// Double wait to 2.0 +	killer404.onFailure(500,headers); +	should_retry = killer404.shouldRetry(wait_seconds); +	ensure("killer404 2", should_retry); +	ensure_approximately_equals("killer404 2", wait_seconds, 2.0F, frac_bits); + +	// Should fail on non-5xx +	killer404.onFailure(404,headers); +	should_retry = killer404.shouldRetry(wait_seconds); +	ensure("killer404 3", !should_retry); + +	// After a non-5xx, should keep failing. +	killer404.onFailure(500,headers); +	should_retry = killer404.shouldRetry(wait_seconds); +	ensure("killer404 4", !should_retry); +} + +// Test handling of "retry-after" header. If present, this header +// value overrides the computed delay, but does not affect the +// progression of delay values.  For example, if the normal +// progression of delays would be 1,2,4,8..., but the 2nd and 3rd calls +// get a retry header of 33, the pattern would become 1,33,33,8... +template<> template<> +void RetryPolicyTestObject::test<5>() +{ +	LLAdaptiveRetryPolicy policy(1.0,25.0,2.0,6); +	LLSD headers_with_retry; +	headers_with_retry[HTTP_IN_HEADER_RETRY_AFTER] = "666"; +	LLSD headers_without_retry; +	F32 wait_seconds; +	bool should_retry; +	U32 frac_bits = 6; + +	policy.onFailure(500,headers_without_retry); +	should_retry = policy.shouldRetry(wait_seconds); +	ensure("retry header 1", should_retry); +	ensure_approximately_equals("retry header 1", wait_seconds, 1.0F, frac_bits); + +	policy.onFailure(500,headers_without_retry); +	should_retry = policy.shouldRetry(wait_seconds); +	ensure("retry header 2", should_retry); +	ensure_approximately_equals("retry header 2", wait_seconds, 2.0F, frac_bits); + +	policy.onFailure(500,headers_with_retry); +	should_retry = policy.shouldRetry(wait_seconds); +	ensure("retry header 3", should_retry); +	// 4.0 overrides by header -> 666.0 +	ensure_approximately_equals("retry header 3", wait_seconds, 666.0F, frac_bits); + +	policy.onFailure(500,headers_with_retry); +	should_retry = policy.shouldRetry(wait_seconds); +	ensure("retry header 4", should_retry); +	// 8.0 overrides by header -> 666.0 +	ensure_approximately_equals("retry header 4", wait_seconds, 666.0F, frac_bits); + +	policy.onFailure(500,headers_without_retry); +	should_retry = policy.shouldRetry(wait_seconds); +	ensure("retry header 5", should_retry); +	ensure_approximately_equals("retry header 5", wait_seconds, 16.0F, frac_bits); + +	policy.onFailure(500,headers_without_retry); +	should_retry = policy.shouldRetry(wait_seconds); +	ensure("retry header 6", should_retry); +	ensure_approximately_equals("retry header 6", wait_seconds, 25.0F, frac_bits); + +	policy.onFailure(500,headers_with_retry); +	should_retry = policy.shouldRetry(wait_seconds); +	ensure("retry header 7", !should_retry); +} + +// Test getSecondsUntilRetryAfter(const std::string& retry_after, F32& seconds_to_wait), +// used by header parsing of the retry policy. +template<> template<> +void RetryPolicyTestObject::test<6>() +{ +	F32 seconds_to_wait; +	bool success; + +	std::string str1("0"); +	seconds_to_wait = F32_MAX; +	success = getSecondsUntilRetryAfter(str1, seconds_to_wait); +	ensure("parse 1", success); +	ensure_equals("parse 1", seconds_to_wait, 0.0); + +	std::string str2("999.9"); +	seconds_to_wait = F32_MAX; +	success = getSecondsUntilRetryAfter(str2, seconds_to_wait); +	ensure("parse 2", success); +	ensure_approximately_equals("parse 2", seconds_to_wait, 999.9F, 8); + +	time_t nowseconds; +	time(&nowseconds); +	std::string str3 = LLDate((F64)(nowseconds+44)).asRFC1123(); +	seconds_to_wait = F32_MAX; +	success = getSecondsUntilRetryAfter(str3, seconds_to_wait); +	std::cerr << " str3 [" << str3 << "]" << std::endl; +	ensure("parse 3", success); +	ensure_approximately_equals_range("parse 3", seconds_to_wait, 44.0F, 2.0F); +} + +// Test retry-after field in both llmessage and CoreHttp headers. +template<> template<> +void RetryPolicyTestObject::test<7>() +{ +	std::cerr << "7 starts" << std::endl; +	 +	LLSD sd_headers; +	time_t nowseconds; +	time(&nowseconds); +	LLAdaptiveRetryPolicy policy(17.0,644.0,3.0,5); +	F32 seconds_to_wait; +	bool should_retry; + +	// No retry until we've failed a try. +	ensure("header 0", !policy.shouldRetry(seconds_to_wait)); +	 +	// no retry header, use default. +	policy.onFailure(500,LLSD()); +	should_retry = policy.shouldRetry(seconds_to_wait); +	ensure("header 1", should_retry); +	ensure_approximately_equals("header 1", seconds_to_wait, 17.0F, 6); + +	// retry header should override, give delay of 0 +	std::string date_string = LLDate((F64)(nowseconds+7)).asRFC1123(); +	sd_headers[HTTP_IN_HEADER_RETRY_AFTER] = date_string; +	policy.onFailure(503,sd_headers); +	should_retry = policy.shouldRetry(seconds_to_wait); +	ensure("header 2", should_retry); +	ensure_approximately_equals_range("header 2", seconds_to_wait, 7.0F, 2.0F); + +	LLCore::HttpResponse *response; +	LLCore::HttpHeaders *headers; + +	response = new LLCore::HttpResponse(); +	headers = new LLCore::HttpHeaders(); +	response->setStatus(503); +	response->setHeaders(headers); +	headers->append(HTTP_IN_HEADER_RETRY_AFTER, std::string("600")); +	policy.onFailure(response); +	should_retry = policy.shouldRetry(seconds_to_wait); +	ensure("header 3",should_retry); +	ensure_approximately_equals("header 3", seconds_to_wait, 600.0F, 6); +	response->release(); + +	response = new LLCore::HttpResponse(); +	headers = new LLCore::HttpHeaders(); +	response->setStatus(503); +	response->setHeaders(headers); +	time(&nowseconds); +	date_string = LLDate((F64)(nowseconds+77)).asRFC1123(); +	std::cerr << "date_string [" << date_string << "]" << std::endl; +	headers->append(HTTP_IN_HEADER_RETRY_AFTER,date_string); +	policy.onFailure(response); +	should_retry = policy.shouldRetry(seconds_to_wait); +	ensure("header 4",should_retry); +	ensure_approximately_equals_range("header 4", seconds_to_wait, 77.0F, 2.0F); +	response->release(); + +	// Timeout should be clamped at max. +	policy.onFailure(500,LLSD()); +	should_retry = policy.shouldRetry(seconds_to_wait); +	ensure("header 5", should_retry); +	ensure_approximately_equals("header 5", seconds_to_wait, 644.0F, 6); + +	// No more retries. +	policy.onFailure(500,LLSD()); +	should_retry = policy.shouldRetry(seconds_to_wait); +	ensure("header 6", !should_retry); +} + +} + diff --git a/indra/newview/tests/llmediadataclient_test.cpp b/indra/newview/tests/llmediadataclient_test.cpp index 3e55336f2d..6f57daf151 100755 --- a/indra/newview/tests/llmediadataclient_test.cpp +++ b/indra/newview/tests/llmediadataclient_test.cpp @@ -33,7 +33,7 @@  #include "llsdserialize.h"  #include "llsdutil.h"  #include "llerrorcontrol.h" -#include "llhttpstatuscodes.h" +#include "llhttpconstants.h"  #include "../llmediadataclient.h"  #include "../llvovolume.h" @@ -129,7 +129,7 @@ void LLHTTPClient::post(  	{  		LLSD content;  		content["reason"] = "fake reason"; -		responder->errorWithContent(HTTP_SERVICE_UNAVAILABLE, "fake reason", content); +		responder->failureResult(HTTP_SERVICE_UNAVAILABLE, "fake reason", content);  		return;  	}  	else if (url == FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL_ERROR)  @@ -137,8 +137,8 @@ void LLHTTPClient::post(  		LLSD error;  		error["code"] = LLObjectMediaNavigateClient::ERROR_PERMISSION_DENIED_CODE;  		result["error"] = error; -	}	 -	responder->result(result); +	} +	responder->successResult(result);  }  const F32 HTTP_REQUEST_EXPIRY_SECS = 60.0f; diff --git a/indra/newview/tests/llremoteparcelrequest_test.cpp b/indra/newview/tests/llremoteparcelrequest_test.cpp index ed66066b0a..c49b0350e9 100755 --- a/indra/newview/tests/llremoteparcelrequest_test.cpp +++ b/indra/newview/tests/llremoteparcelrequest_test.cpp @@ -40,12 +40,14 @@ namespace {  LLCurl::Responder::Responder() { }  LLCurl::Responder::~Responder() { } -void LLCurl::Responder::error(U32,std::string const &) { } -void LLCurl::Responder::result(LLSD const &) { } -void LLCurl::Responder::errorWithContent(U32 status,std::string const &,LLSD const &) { } -void LLCurl::Responder::completedRaw(U32 status, std::string const &, LLChannelDescriptors const &,boost::shared_ptr<LLBufferArray> const &) { } -void LLCurl::Responder::completed(U32 status, std::string const &, LLSD const &) { } -void LLCurl::Responder::completedHeader(U32 status, std::string const &, LLSD const &) { } +void LLCurl::Responder::httpFailure() { } +void LLCurl::Responder::httpSuccess() { } +void LLCurl::Responder::httpCompleted() { } +void LLCurl::Responder::failureResult(S32 status, const std::string& reason, const LLSD& content) { } +void LLCurl::Responder::successResult(const LLSD& content) { } +void LLCurl::Responder::completeResult(S32 status, const std::string& reason, const LLSD& content) { } +std::string LLCurl::Responder::dumpResponse() const { return "(failure)"; } +void LLCurl::Responder::completedRaw(LLChannelDescriptors const &,boost::shared_ptr<LLBufferArray> const &) { }  void LLMessageSystem::getF32(char const *,char const *,F32 &,S32) { }  void LLMessageSystem::getU8(char const *,char const *,U8 &,S32) { }  void LLMessageSystem::getS32(char const *,char const *,S32 &,S32) { } @@ -85,7 +87,7 @@ namespace tut  		virtual void setParcelID(const LLUUID& parcel_id) { } -		virtual void setErrorStatus(U32 status, const std::string& reason) { } +		virtual void setErrorStatus(S32 status, const std::string& reason) { }  		bool mProcessed;  	}; diff --git a/indra/newview/tests/lltranslate_test.cpp b/indra/newview/tests/lltranslate_test.cpp index 8ce56326d8..5e73dbb981 100755 --- a/indra/newview/tests/lltranslate_test.cpp +++ b/indra/newview/tests/lltranslate_test.cpp @@ -34,6 +34,8 @@  #include "lltrans.h"  #include "llui.h" +#include "../../llmessage/llhttpconstants.cpp" +  static const std::string GOOGLE_VALID_RESPONSE1 =  "{\   \"data\": {\ @@ -300,12 +302,10 @@ std::string LLControlGroup::getString(const std::string& name) { return "dummy";  LLControlGroup::~LLControlGroup() {}  LLCurl::Responder::Responder() {} -void LLCurl::Responder::completedHeader(U32, std::string const&, LLSD const&) {} -void LLCurl::Responder::completedRaw(U32, const std::string&, const LLChannelDescriptors&, const LLIOPipe::buffer_ptr_t& buffer) {} -void LLCurl::Responder::completed(U32, std::string const&, LLSD const&) {} -void LLCurl::Responder::error(U32, std::string const&) {} -void LLCurl::Responder::errorWithContent(U32, std::string const&, LLSD const&) {} -void LLCurl::Responder::result(LLSD const&) {} +void LLCurl::Responder::httpFailure() { } +void LLCurl::Responder::httpSuccess() { } +void LLCurl::Responder::httpCompleted() { } +void LLCurl::Responder::completedRaw(LLChannelDescriptors const &,boost::shared_ptr<LLBufferArray> const &) { }  LLCurl::Responder::~Responder() {}  void LLHTTPClient::get(const std::string&, const LLSD&, ResponderPtr, const LLSD&, const F32, bool) {}  | 
