Merge from default branch

--HG--
branch : product-engine
master
Mike Antipov 2010-03-31 10:08:50 +03:00
commit bba457e889
45 changed files with 2109 additions and 1967 deletions

View File

@ -35,8 +35,9 @@
#include <string>
#include "llrect.h"
#include "lluictrl.h"
#include "lluicolor.h"
class LLUICtrl;
class LLUICtrlFactory;
class LLUIImage;
class LLButton;

View File

@ -74,6 +74,7 @@ set(viewer_SOURCE_FILES
llagentpilot.cpp
llagentui.cpp
llagentwearables.cpp
llagentwearablesfetch.cpp
llanimstatelabels.cpp
llappearancemgr.cpp
llappviewer.cpp
@ -253,6 +254,7 @@ set(viewer_SOURCE_FILES
llinventoryfilter.cpp
llinventoryfunctions.cpp
llinventorymodel.cpp
llinventorymodelbackgroundfetch.cpp
llinventoryobserver.cpp
llinventorypanel.cpp
lljoystickbutton.cpp
@ -573,6 +575,7 @@ set(viewer_HEADER_FILES
llagentpilot.h
llagentui.h
llagentwearables.h
llagentwearablesfetch.h
llanimstatelabels.h
llappearance.h
llappearancemgr.h
@ -754,6 +757,7 @@ set(viewer_HEADER_FILES
llinventoryfilter.h
llinventoryfunctions.h
llinventorymodel.h
llinventorymodelbackgroundfetch.h
llinventoryobserver.h
llinventorypanel.h
lljoystickbutton.h

View File

@ -44,7 +44,6 @@
#include "llcallingcard.h"
#include "llchannelmanager.h"
#include "llconsole.h"
//#include "llfirstuse.h"
#include "llfloatercamera.h"
#include "llfloatercustomize.h"
#include "llfloaterreg.h"
@ -90,41 +89,18 @@ const BOOL ANIMATE = TRUE;
const U8 AGENT_STATE_TYPING = 0x04;
const U8 AGENT_STATE_EDITING = 0x10;
//drone wandering constants
const F32 MAX_WANDER_TIME = 20.f; // seconds
const F32 MAX_HEADING_HALF_ERROR = 0.2f; // radians
const F32 WANDER_MAX_SLEW_RATE = 2.f * DEG_TO_RAD; // radians / frame
const F32 WANDER_TARGET_MIN_DISTANCE = 10.f; // meters
// Autopilot constants
const F32 AUTOPILOT_HEADING_HALF_ERROR = 10.f * DEG_TO_RAD; // radians
const F32 AUTOPILOT_MAX_SLEW_RATE = 1.f * DEG_TO_RAD; // radians / frame
const F32 AUTOPILOT_STOP_DISTANCE = 2.f; // meters
const F32 AUTOPILOT_HEIGHT_ADJUST_DISTANCE = 8.f; // meters
const F32 AUTOPILOT_MIN_TARGET_HEIGHT_OFF_GROUND = 1.f; // meters
const F32 AUTOPILOT_MAX_TIME_NO_PROGRESS = 1.5f; // seconds
// face editing constants
const LLVector3d FACE_EDIT_CAMERA_OFFSET(0.4f, -0.05f, 0.07f);
const LLVector3d FACE_EDIT_TARGET_OFFSET(0.f, 0.f, 0.05f);
const F32 METERS_PER_WHEEL_CLICK = 1.f;
const F32 MAX_TIME_DELTA = 1.f;
const F32 MAX_VELOCITY_AUTO_LAND_SQUARED = 4.f * 4.f;
const F64 CHAT_AGE_FAST_RATE = 3.0;
// fidget constants
const F32 MIN_FIDGET_TIME = 8.f; // seconds
const F32 MAX_FIDGET_TIME = 20.f; // seconds
const S32 MAX_NUM_CHAT_POSITIONS = 10;
const F32 MAX_VELOCITY_AUTO_LAND_SQUARED = 4.f * 4.f;
const F32 MAX_FOCUS_OFFSET = 20.f;
const F32 MIN_RADIUS_ALPHA_SIZZLE = 0.5f;
const F64 CHAT_AGE_FAST_RATE = 3.0;
// The agent instance.
LLAgent gAgent;
@ -218,13 +194,6 @@ LLAgent::LLAgent() :
mIsBusy(FALSE),
mAtKey(0), // Either 1, 0, or -1... indicates that movement-key is pressed
mWalkKey(0), // like AtKey, but causes less forward thrust
mLeftKey(0),
mUpKey(0),
mYawKey(0.f),
mPitchKey(0.f),
mControlFlags(0x00000000),
mbFlagsDirty(FALSE),
mbFlagsNeedReset(FALSE),
@ -339,7 +308,7 @@ void LLAgent::moveAt(S32 direction, bool reset)
// age chat timer so it fades more quickly when you are intentionally moving
ageChat();
setKey(direction, mAtKey);
gAgentCamera.setAtKey(LLAgentCamera::directionToKey(direction));
if (direction > 0)
{
@ -364,7 +333,7 @@ void LLAgent::moveAtNudge(S32 direction)
// age chat timer so it fades more quickly when you are intentionally moving
ageChat();
setKey(direction, mWalkKey);
gAgentCamera.setWalkKey(LLAgentCamera::directionToKey(direction));
if (direction > 0)
{
@ -386,7 +355,7 @@ void LLAgent::moveLeft(S32 direction)
// age chat timer so it fades more quickly when you are intentionally moving
ageChat();
setKey(direction, mLeftKey);
gAgentCamera.setLeftKey(LLAgentCamera::directionToKey(direction));
if (direction > 0)
{
@ -408,7 +377,7 @@ void LLAgent::moveLeftNudge(S32 direction)
// age chat timer so it fades more quickly when you are intentionally moving
ageChat();
setKey(direction, mLeftKey);
gAgentCamera.setLeftKey(LLAgentCamera::directionToKey(direction));
if (direction > 0)
{
@ -430,7 +399,7 @@ void LLAgent::moveUp(S32 direction)
// age chat timer so it fades more quickly when you are intentionally moving
ageChat();
setKey(direction, mUpKey);
gAgentCamera.setUpKey(LLAgentCamera::directionToKey(direction));
if (direction > 0)
{
@ -449,7 +418,7 @@ void LLAgent::moveUp(S32 direction)
//-----------------------------------------------------------------------------
void LLAgent::moveYaw(F32 mag, bool reset_view)
{
mYawKey = mag;
gAgentCamera.setYawKey(mag);
if (mag > 0)
{
@ -471,7 +440,7 @@ void LLAgent::moveYaw(F32 mag, bool reset_view)
//-----------------------------------------------------------------------------
void LLAgent::movePitch(F32 mag)
{
mPitchKey = mag;
gAgentCamera.setPitchKey(mag);
if (mag > 0)
{
@ -1048,26 +1017,6 @@ LLQuaternion LLAgent::getQuat() const
return mFrameAgent.getQuaternion();
}
//-----------------------------------------------------------------------------
// setKey()
//-----------------------------------------------------------------------------
void LLAgent::setKey(const S32 direction, S32 &key)
{
if (direction > 0)
{
key = 1;
}
else if (direction < 0)
{
key = -1;
}
else
{
key = 0;
}
}
//-----------------------------------------------------------------------------
// getControlFlags()
//-----------------------------------------------------------------------------
@ -1537,20 +1486,20 @@ void LLAgent::propagate(const F32 dt)
LLFloaterMove *floater_move = LLFloaterReg::findTypedInstance<LLFloaterMove>("moveview");
if (floater_move)
{
floater_move->mForwardButton ->setToggleState( mAtKey > 0 || mWalkKey > 0 );
floater_move->mBackwardButton ->setToggleState( mAtKey < 0 || mWalkKey < 0 );
floater_move->mTurnLeftButton ->setToggleState( mYawKey > 0.f );
floater_move->mTurnRightButton ->setToggleState( mYawKey < 0.f );
floater_move->mMoveUpButton ->setToggleState( mUpKey > 0 );
floater_move->mMoveDownButton ->setToggleState( mUpKey < 0 );
floater_move->mForwardButton ->setToggleState( gAgentCamera.getAtKey() > 0 || gAgentCamera.getWalkKey() > 0 );
floater_move->mBackwardButton ->setToggleState( gAgentCamera.getAtKey() < 0 || gAgentCamera.getWalkKey() < 0 );
floater_move->mTurnLeftButton ->setToggleState( gAgentCamera.getYawKey() > 0.f );
floater_move->mTurnRightButton ->setToggleState( gAgentCamera.getYawKey() < 0.f );
floater_move->mMoveUpButton ->setToggleState( gAgentCamera.getUpKey() > 0 );
floater_move->mMoveDownButton ->setToggleState( gAgentCamera.getUpKey() < 0 );
}
// handle rotation based on keyboard levels
const F32 YAW_RATE = 90.f * DEG_TO_RAD; // radians per second
yaw(YAW_RATE * mYawKey * dt);
yaw(YAW_RATE * gAgentCamera.getYawKey() * dt);
const F32 PITCH_RATE = 90.f * DEG_TO_RAD; // radians per second
pitch(PITCH_RATE * mPitchKey * dt);
pitch(PITCH_RATE * gAgentCamera.getPitchKey() * dt);
// handle auto-land behavior
if (isAgentAvatarValid())
@ -1560,7 +1509,7 @@ void LLAgent::propagate(const F32 dt)
land_vel.mV[VZ] = 0.f;
if (!in_air
&& mUpKey < 0
&& gAgentCamera.getUpKey() < 0
&& land_vel.magVecSquared() < MAX_VELOCITY_AUTO_LAND_SQUARED
&& gSavedSettings.getBOOL("AutomaticFly"))
{
@ -1569,13 +1518,7 @@ void LLAgent::propagate(const F32 dt)
}
}
// clear keys
mAtKey = 0;
mWalkKey = 0;
mLeftKey = 0;
mUpKey = 0;
mYawKey = 0.f;
mPitchKey = 0.f;
gAgentCamera.clearGeneralKeys();
}
//-----------------------------------------------------------------------------

View File

@ -39,9 +39,6 @@
#include "llagentconstants.h"
#include "llagentdata.h" // gAgentID, gAgentSessionID
#include "llcharacter.h" // LLAnimPauseRequest
#include "llfollowcam.h" // Ventrella
#include "llhudeffectlookat.h" // EPointAtType
#include "llhudeffectpointat.h" // ELookAtType
#include "llpointer.h"
#include "lluicolor.h"
#include "llvoavatardefines.h"
@ -434,19 +431,6 @@ private:
** **
** MOVEMENT
**/
//--------------------------------------------------------------------
// Keys
//--------------------------------------------------------------------
public:
void setKey(const S32 direction, S32 &key); // Sets key to +1 for +direction, -1 for -direction
private:
S32 mAtKey; // Either 1, 0, or -1. Indicates that movement key is pressed
S32 mWalkKey; // Like AtKey, but causes less forward thrust
S32 mLeftKey;
S32 mUpKey;
F32 mYawKey;
F32 mPitchKey;
//--------------------------------------------------------------------
// Movement from user input

View File

@ -35,50 +35,25 @@
#include "pipeline.h"
#include "llagentlistener.h"
#include "llagentwearables.h"
#include "llagentui.h"
#include "llagent.h"
#include "llanimationstates.h"
#include "llbottomtray.h"
#include "llcallingcard.h"
#include "llchannelmanager.h"
#include "llconsole.h"
//#include "llfirstuse.h"
#include "llfloatercamera.h"
#include "llfloatercustomize.h"
#include "llfloaterreg.h"
#include "llfloatertools.h"
#include "llgroupactions.h"
#include "llgroupmgr.h"
#include "llhomelocationresponder.h"
#include "llhudmanager.h"
#include "lljoystickbutton.h"
#include "llmorphview.h"
#include "llmoveview.h"
#include "llnavigationbar.h" // to show/hide navigation bar when changing mouse look state
#include "llnearbychatbar.h"
#include "llnotificationsutil.h"
#include "llparcel.h"
#include "llsdutil.h"
#include "llsidetray.h"
#include "llsky.h"
#include "llselectmgr.h"
#include "llsmoothstep.h"
#include "llstatusbar.h"
#include "llteleportflags.h"
#include "lltool.h"
#include "lltoolmgr.h"
#include "lltrans.h"
#include "llviewercamera.h"
#include "llviewercontrol.h"
#include "llviewerdisplay.h"
#include "llviewerjoystick.h"
#include "llviewermediafocus.h"
#include "llviewerobjectlist.h"
#include "llviewerparcelmgr.h"
#include "llviewerstats.h"
#include "llviewerregion.h"
#include "llviewerwindow.h"
#include "llvoavatarself.h"
#include "llwindow.h"
#include "llworld.h"
#include "llworldmap.h"
using namespace LLVOAvatarDefines;
@ -181,6 +156,13 @@ LLAgentCamera::LLAgentCamera() :
mTrackFocusObject(TRUE),
mUIOffset(0.f),
mAtKey(0), // Either 1, 0, or -1... indicates that movement-key is pressed
mWalkKey(0), // like AtKey, but causes less forward thrust
mLeftKey(0),
mUpKey(0),
mYawKey(0.f),
mPitchKey(0.f),
mOrbitLeftKey(0.f),
mOrbitRightKey(0.f),
mOrbitUpKey(0.f),
@ -196,6 +178,10 @@ LLAgentCamera::LLAgentCamera() :
mPanOutKey(0.f)
{
mFollowCam.setMaxCameraDistantFromSubject( MAX_CAMERA_DISTANCE_FROM_AGENT );
clearGeneralKeys();
clearOrbitKeys();
clearPanKeys();
}
// Requires gSavedSettings to be initialized.
@ -1204,17 +1190,15 @@ void LLAgentCamera::updateCamera()
LLFloaterCamera* camera_floater = LLFloaterReg::findTypedInstance<LLFloaterCamera>("camera");
if (camera_floater)
{
camera_floater->mRotate->setToggleState(
mOrbitRightKey > 0.f, // left
mOrbitUpKey > 0.f, // top
mOrbitLeftKey > 0.f, // right
mOrbitDownKey > 0.f); // bottom
camera_floater->mTrack->setToggleState(
mPanLeftKey > 0.f, // left
mPanUpKey > 0.f, // top
mPanRightKey > 0.f, // right
mPanDownKey > 0.f); // bottom
camera_floater->mRotate->setToggleState(gAgentCamera.getOrbitRightKey() > 0.f, // left
gAgentCamera.getOrbitUpKey() > 0.f, // top
gAgentCamera.getOrbitLeftKey() > 0.f, // right
gAgentCamera.getOrbitDownKey() > 0.f); // bottom
camera_floater->mTrack->setToggleState(gAgentCamera.getPanLeftKey() > 0.f, // left
gAgentCamera.getPanUpKey() > 0.f, // top
gAgentCamera.getPanRightKey() > 0.f, // right
gAgentCamera.getPanDownKey() > 0.f); // bottom
}
// Handle camera movement based on keyboard.
@ -1222,21 +1206,21 @@ void LLAgentCamera::updateCamera()
const F32 ORBIT_AROUND_RATE = 90.f * DEG_TO_RAD; // radians per second
const F32 PAN_RATE = 5.f; // meters per second
if( mOrbitUpKey || mOrbitDownKey )
if (gAgentCamera.getOrbitUpKey() || gAgentCamera.getOrbitDownKey())
{
F32 input_rate = mOrbitUpKey - mOrbitDownKey;
F32 input_rate = gAgentCamera.getOrbitUpKey() - gAgentCamera.getOrbitDownKey();
cameraOrbitOver( input_rate * ORBIT_OVER_RATE / gFPSClamped );
}
if( mOrbitLeftKey || mOrbitRightKey)
if (gAgentCamera.getOrbitLeftKey() || gAgentCamera.getOrbitRightKey())
{
F32 input_rate = mOrbitLeftKey - mOrbitRightKey;
cameraOrbitAround( input_rate * ORBIT_AROUND_RATE / gFPSClamped );
F32 input_rate = gAgentCamera.getOrbitLeftKey() - gAgentCamera.getOrbitRightKey();
cameraOrbitAround(input_rate * ORBIT_AROUND_RATE / gFPSClamped);
}
if( mOrbitInKey || mOrbitOutKey )
if (gAgentCamera.getOrbitInKey() || gAgentCamera.getOrbitOutKey())
{
F32 input_rate = mOrbitInKey - mOrbitOutKey;
F32 input_rate = gAgentCamera.getOrbitInKey() - gAgentCamera.getOrbitOutKey();
LLVector3d to_focus = gAgent.getPosGlobalFromAgent(LLViewerCamera::getInstance()->getOrigin()) - calcFocusPositionTargetGlobal();
F32 distance_to_focus = (F32)to_focus.magVec();
@ -1244,38 +1228,27 @@ void LLAgentCamera::updateCamera()
cameraOrbitIn( input_rate * distance_to_focus / gFPSClamped );
}
if( mPanInKey || mPanOutKey )
if (gAgentCamera.getPanInKey() || gAgentCamera.getPanOutKey())
{
F32 input_rate = mPanInKey - mPanOutKey;
cameraPanIn( input_rate * PAN_RATE / gFPSClamped );
F32 input_rate = gAgentCamera.getPanInKey() - gAgentCamera.getPanOutKey();
cameraPanIn(input_rate * PAN_RATE / gFPSClamped);
}
if( mPanRightKey || mPanLeftKey )
if (gAgentCamera.getPanRightKey() || gAgentCamera.getPanLeftKey())
{
F32 input_rate = mPanRightKey - mPanLeftKey;
cameraPanLeft( input_rate * -PAN_RATE / gFPSClamped );
F32 input_rate = gAgentCamera.getPanRightKey() - gAgentCamera.getPanLeftKey();
cameraPanLeft(input_rate * -PAN_RATE / gFPSClamped );
}
if( mPanUpKey || mPanDownKey )
if (gAgentCamera.getPanUpKey() || gAgentCamera.getPanDownKey())
{
F32 input_rate = mPanUpKey - mPanDownKey;
cameraPanUp( input_rate * PAN_RATE / gFPSClamped );
F32 input_rate = gAgentCamera.getPanUpKey() - gAgentCamera.getPanDownKey();
cameraPanUp(input_rate * PAN_RATE / gFPSClamped );
}
// Clear camera keyboard keys.
mOrbitLeftKey = 0.f;
mOrbitRightKey = 0.f;
mOrbitUpKey = 0.f;
mOrbitDownKey = 0.f;
mOrbitInKey = 0.f;
mOrbitOutKey = 0.f;
mPanRightKey = 0.f;
mPanLeftKey = 0.f;
mPanUpKey = 0.f;
mPanDownKey = 0.f;
mPanInKey = 0.f;
mPanOutKey = 0.f;
gAgentCamera.clearOrbitKeys();
gAgentCamera.clearPanKeys();
// lerp camera focus offset
mCameraFocusOffset = lerp(mCameraFocusOffset, mCameraFocusOffsetTarget, LLCriticalDamp::getInterpolant(CAMERA_FOCUS_HALF_LIFE));
@ -2850,5 +2823,44 @@ EPointAtType LLAgentCamera::getPointAtType()
return POINTAT_TARGET_NONE;
}
void LLAgentCamera::clearGeneralKeys()
{
mAtKey = 0;
mWalkKey = 0;
mLeftKey = 0;
mUpKey = 0;
mYawKey = 0.f;
mPitchKey = 0.f;
}
void LLAgentCamera::clearOrbitKeys()
{
mOrbitLeftKey = 0.f;
mOrbitRightKey = 0.f;
mOrbitUpKey = 0.f;
mOrbitDownKey = 0.f;
mOrbitInKey = 0.f;
mOrbitOutKey = 0.f;
}
void LLAgentCamera::clearPanKeys()
{
mPanRightKey = 0.f;
mPanLeftKey = 0.f;
mPanUpKey = 0.f;
mPanDownKey = 0.f;
mPanInKey = 0.f;
mPanOutKey = 0.f;
}
// static
S32 LLAgentCamera::directionToKey(S32 direction)
{
if (direction > 0) return 1;
if (direction < 0) return -1;
return 0;
}
// EOF

View File

@ -33,32 +33,12 @@
#ifndef LL_LLAGENTCAMERA_H
#define LL_LLAGENTCAMERA_H
#include "indra_constants.h"
#include "llevent.h" // LLObservable base class
#include "llagent.h"
#include "llagentaccess.h"
#include "llagentconstants.h"
#include "llagentdata.h" // gAgentID, gAgentSessionID
#include "llcharacter.h" // LLAnimPauseRequest
#include "llfollowcam.h" // Ventrella
#include "llhudeffectlookat.h" // EPointAtType
#include "llhudeffectpointat.h" // ELookAtType
#include "llpointer.h"
#include "lluicolor.h"
#include "llvoavatardefines.h"
class LLChat;
class LLVOAvatarSelf;
class LLViewerRegion;
class LLMotion;
class LLToolset;
class LLMessageSystem;
class LLPermissions;
class LLHost;
class LLFriendObserver;
class LLPickInfo;
class LLViewerObject;
class LLAgentDropGroupViewerNode;
class LLVOAvatarSelf;
//--------------------------------------------------------------------
// Types
@ -175,42 +155,6 @@ private:
LLVector3 mCameraLag; // Third person camera lag
LLVector3 mCameraUpVector; // Camera's up direction in world coordinates (determines the 'roll' of the view)
//--------------------------------------------------------------------
// Orbit
//--------------------------------------------------------------------
public:
void setOrbitLeftKey(F32 mag) { mOrbitLeftKey = mag; }
void setOrbitRightKey(F32 mag) { mOrbitRightKey = mag; }
void setOrbitUpKey(F32 mag) { mOrbitUpKey = mag; }
void setOrbitDownKey(F32 mag) { mOrbitDownKey = mag; }
void setOrbitInKey(F32 mag) { mOrbitInKey = mag; }
void setOrbitOutKey(F32 mag) { mOrbitOutKey = mag; }
private:
F32 mOrbitLeftKey;
F32 mOrbitRightKey;
F32 mOrbitUpKey;
F32 mOrbitDownKey;
F32 mOrbitInKey;
F32 mOrbitOutKey;
//--------------------------------------------------------------------
// Pan
//--------------------------------------------------------------------
public:
void setPanLeftKey(F32 mag) { mPanLeftKey = mag; }
void setPanRightKey(F32 mag) { mPanRightKey = mag; }
void setPanUpKey(F32 mag) { mPanUpKey = mag; }
void setPanDownKey(F32 mag) { mPanDownKey = mag; }
void setPanInKey(F32 mag) { mPanInKey = mag; }
void setPanOutKey(F32 mag) { mPanOutKey = mag; }
private:
F32 mPanUpKey;
F32 mPanDownKey;
F32 mPanLeftKey;
F32 mPanRightKey;
F32 mPanInKey;
F32 mPanOutKey;
//--------------------------------------------------------------------
// Follow
//--------------------------------------------------------------------
@ -358,6 +302,97 @@ private:
public:
F32 mHUDTargetZoom; // Target zoom level for HUD objects (used when editing)
F32 mHUDCurZoom; // Current animated zoom level for HUD objects
/********************************************************************************
** **
** KEYS
**/
public:
S32 getAtKey() const { return mAtKey; }
S32 getWalkKey() const { return mWalkKey; }
S32 getLeftKey() const { return mLeftKey; }
S32 getUpKey() const { return mUpKey; }
F32 getYawKey() const { return mYawKey; }
F32 getPitchKey() const { return mPitchKey; }
void setAtKey(S32 mag) { mAtKey = mag; }
void setWalkKey(S32 mag) { mWalkKey = mag; }
void setLeftKey(S32 mag) { mLeftKey = mag; }
void setUpKey(S32 mag) { mUpKey = mag; }
void setYawKey(F32 mag) { mYawKey = mag; }
void setPitchKey(F32 mag) { mPitchKey = mag; }
void clearGeneralKeys();
static S32 directionToKey(S32 direction); // Changes direction to -1/0/1
private:
S32 mAtKey; // Either 1, 0, or -1. Indicates that movement key is pressed
S32 mWalkKey; // Like AtKey, but causes less forward thrust
S32 mLeftKey;
S32 mUpKey;
F32 mYawKey;
F32 mPitchKey;
//--------------------------------------------------------------------
// Orbit
//--------------------------------------------------------------------
public:
F32 getOrbitLeftKey() const { return mOrbitLeftKey; }
F32 getOrbitRightKey() const { return mOrbitRightKey; }
F32 getOrbitUpKey() const { return mOrbitUpKey; }
F32 getOrbitDownKey() const { return mOrbitDownKey; }
F32 getOrbitInKey() const { return mOrbitInKey; }
F32 getOrbitOutKey() const { return mOrbitOutKey; }
void setOrbitLeftKey(F32 mag) { mOrbitLeftKey = mag; }
void setOrbitRightKey(F32 mag) { mOrbitRightKey = mag; }
void setOrbitUpKey(F32 mag) { mOrbitUpKey = mag; }
void setOrbitDownKey(F32 mag) { mOrbitDownKey = mag; }
void setOrbitInKey(F32 mag) { mOrbitInKey = mag; }
void setOrbitOutKey(F32 mag) { mOrbitOutKey = mag; }
void clearOrbitKeys();
private:
F32 mOrbitLeftKey;
F32 mOrbitRightKey;
F32 mOrbitUpKey;
F32 mOrbitDownKey;
F32 mOrbitInKey;
F32 mOrbitOutKey;
//--------------------------------------------------------------------
// Pan
//--------------------------------------------------------------------
public:
F32 getPanLeftKey() const { return mPanLeftKey; }
F32 getPanRightKey() const { return mPanRightKey; }
F32 getPanUpKey() const { return mPanUpKey; }
F32 getPanDownKey() const { return mPanDownKey; }
F32 getPanInKey() const { return mPanInKey; }
F32 getPanOutKey() const { return mPanOutKey; }
void setPanLeftKey(F32 mag) { mPanLeftKey = mag; }
void setPanRightKey(F32 mag) { mPanRightKey = mag; }
void setPanUpKey(F32 mag) { mPanUpKey = mag; }
void setPanDownKey(F32 mag) { mPanDownKey = mag; }
void setPanInKey(F32 mag) { mPanInKey = mag; }
void setPanOutKey(F32 mag) { mPanOutKey = mag; }
void clearPanKeys();
private:
F32 mPanUpKey;
F32 mPanDownKey;
F32 mPanLeftKey;
F32 mPanRightKey;
F32 mPanInKey;
F32 mPanOutKey;
/** Keys
** **
*******************************************************************************/
};
extern LLAgentCamera gAgentCamera;

View File

@ -31,102 +31,33 @@
*/
#include "llviewerprecompiledheaders.h"
#include "llagent.h"
#include "llagentcamera.h"
#include "llagentwearables.h"
#include "llaccordionctrltab.h"
#include "llagent.h"
#include "llagentcamera.h"
#include "llagentwearablesfetch.h"
#include "llappearancemgr.h"
#include "llcallbacklist.h"
#include "llfloatercustomize.h"
#include "llfolderview.h"
#include "llgesturemgr.h"
#include "llinventorybridge.h"
#include "llinventoryfunctions.h"
#include "llinventoryobserver.h"
#include "llinventorypanel.h"
#include "llmd5.h"
#include "llnotificationsutil.h"
#include "llpaneloutfitsinventory.h"
#include "llsidetray.h"
#include "lltexlayer.h"
#include "llviewerregion.h"
#include "llvoavatarself.h"
#include "llwearable.h"
#include "llwearablelist.h"
#include "llgesturemgr.h"
#include "llappearancemgr.h"
#include "lltexlayer.h"
#include "llsidetray.h"
#include "llpaneloutfitsinventory.h"
#include "llfolderview.h"
#include "llaccordionctrltab.h"
#include <boost/scoped_ptr.hpp>
//--------------------------------------------------------------------
// Classes for fetching initial wearables data
//--------------------------------------------------------------------
// Outfit folder fetching callback structure.
class LLInitialWearablesFetch : public LLInventoryFetchDescendentsObserver
{
public:
LLInitialWearablesFetch() {}
~LLInitialWearablesFetch();
virtual void done();
struct InitialWearableData
{
EWearableType mType;
LLUUID mItemID;
LLUUID mAssetID;
InitialWearableData(EWearableType type, LLUUID& itemID, LLUUID& assetID) :
mType(type),
mItemID(itemID),
mAssetID(assetID)
{}
};
typedef std::vector<InitialWearableData> initial_wearable_data_vec_t;
initial_wearable_data_vec_t mCOFInitialWearables; // Wearables from the Current Outfit Folder
initial_wearable_data_vec_t mAgentInitialWearables; // Wearables from the old agent wearables msg
protected:
void processWearablesMessage();
void processContents();
};
class LLLibraryOutfitsFetch : public LLInventoryFetchDescendentsObserver
{
public:
enum ELibraryOutfitFetchStep {
LOFS_FOLDER = 0,
LOFS_OUTFITS,
LOFS_LIBRARY,
LOFS_IMPORTED,
LOFS_CONTENTS
};
LLLibraryOutfitsFetch() : mCurrFetchStep(LOFS_FOLDER), mOutfitsPopulated(false)
{
mMyOutfitsID = LLUUID::null;
mClothingID = LLUUID::null;
mLibraryClothingID = LLUUID::null;
mImportedClothingID = LLUUID::null;
mImportedClothingName = "Imported Library Clothing";
}
~LLLibraryOutfitsFetch() {}
virtual void done();
void doneIdle();
LLUUID mMyOutfitsID;
void importedFolderFetch();
protected:
void folderDone(void);
void outfitsDone(void);
void libraryDone(void);
void importedFolderDone(void);
void contentsDone(void);
enum ELibraryOutfitFetchStep mCurrFetchStep;
uuid_vec_t mLibraryClothingFolders;
uuid_vec_t mImportedClothingFolders;
bool mOutfitsPopulated;
LLUUID mClothingID;
LLUUID mLibraryClothingID;
LLUUID mImportedClothingID;
std::string mImportedClothingName;
};
LLAgentWearables gAgentWearables;
BOOL LLAgentWearables::mInitialWearablesUpdateReceived = FALSE;
@ -1013,8 +944,7 @@ void LLAgentWearables::processAgentInitialWearablesUpdate(LLMessageSystem* mesgs
// 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); // MULTI-WEARABLE: update
outfit->mAgentInitialWearables.push_back(wearable_data);
outfit->add(wearable_data);
}
lldebugs << " " << LLWearableDictionary::getTypeLabel(type) << llendl;
@ -1514,6 +1444,7 @@ void LLAgentWearables::removeWearable(const EWearableType type, bool do_remove_a
{
LLSD payload;
payload["wearable_type"] = (S32)type;
payload["wearable_index"] = (S32)index;
// Bring up view-modal dialog: Save changes? Yes, No, Cancel
LLNotificationsUtil::add("WearableSave", LLSD(), payload, &LLAgentWearables::onRemoveWearableDialog);
return;
@ -1527,22 +1458,21 @@ void LLAgentWearables::removeWearable(const EWearableType type, bool do_remove_a
}
// MULTI_WEARABLE: assuming one wearable per type.
// MULTI_WEARABLE: hardwiring 0th elt for now - notification needs to change.
// static
bool LLAgentWearables::onRemoveWearableDialog(const LLSD& notification, const LLSD& response)
{
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
EWearableType type = (EWearableType)notification["payload"]["wearable_type"].asInteger();
S32 index = (S32)notification["payload"]["wearable_index"].asInteger();
switch(option)
{
case 0: // "Save"
gAgentWearables.saveWearable(type, 0);
gAgentWearables.removeWearableFinal(type, false, 0);
gAgentWearables.saveWearable(type, index);
gAgentWearables.removeWearableFinal(type, false, index);
break;
case 1: // "Don't Save"
gAgentWearables.removeWearableFinal(type, false, 0);
gAgentWearables.removeWearableFinal(type, false, index);
break;
case 2: // "Cancel"
@ -1601,23 +1531,19 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it
{
llinfos << "setWearableOutfit() start" << llendl;
BOOL wearables_to_remove[WT_COUNT];
wearables_to_remove[WT_SHAPE] = FALSE;
wearables_to_remove[WT_SKIN] = FALSE;
wearables_to_remove[WT_HAIR] = FALSE;
wearables_to_remove[WT_EYES] = FALSE;
wearables_to_remove[WT_SHIRT] = remove;
wearables_to_remove[WT_PANTS] = remove;
wearables_to_remove[WT_SHOES] = remove;
wearables_to_remove[WT_SOCKS] = remove;
wearables_to_remove[WT_JACKET] = remove;
wearables_to_remove[WT_GLOVES] = remove;
wearables_to_remove[WT_UNDERSHIRT] = (!gAgent.isTeen()) & remove;
wearables_to_remove[WT_UNDERPANTS] = (!gAgent.isTeen()) & remove;
wearables_to_remove[WT_SKIRT] = remove;
wearables_to_remove[WT_ALPHA] = remove;
wearables_to_remove[WT_TATTOO] = remove;
// 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 type = 0; type < (S32)WT_COUNT; type++)
{
if (LLWearableDictionary::getAssetType((EWearableType)type) == LLAssetType::AT_CLOTHING)
{
removeWearable((EWearableType)type, true, 0);
}
}
}
S32 count = wearables.count();
llassert(items.count() == count);
@ -1632,77 +1558,26 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it
if (new_wearable)
{
const EWearableType type = new_wearable->getType();
wearables_to_remove[type] = FALSE;
// MULTI_WEARABLE: using 0th
LLWearable* old_wearable = getWearable(type, 0);
if (old_wearable)
{
// Special case where you're putting on a wearable that has the same assetID
// as the previous (e.g. wear a shirt then wear a copy of that shirt) since in this
// case old_wearable == new_wearable.
if (old_wearable == new_wearable)
{
old_wearable->setLabelUpdated();
new_wearable->setName(new_item->getName());
new_wearable->setItemID(new_item->getUUID());
}
const LLUUID& old_item_id = getWearableItemID(type, 0);
if ((old_wearable->getAssetID() == new_wearable->getAssetID()) &&
(old_item_id == new_item->getUUID()))
{
lldebugs << "No change to wearable asset and item: " << LLWearableDictionary::getInstance()->getWearableEntry(type) << llendl;
continue;
}
// Assumes existing wearables are not dirty.
if (old_wearable->isDirty())
{
llassert(0);
continue;
}
}
new_wearable->setName(new_item->getName());
new_wearable->setItemID(new_item->getUUID());
setWearable(type,0,new_wearable);
}
}
std::vector<LLWearable*> wearables_being_removed;
for (i = 0; i < WT_COUNT; i++)
{
if (wearables_to_remove[i])
{
// MULTI_WEARABLE: assuming 0th
LLWearable* wearable = getWearable((EWearableType)i, 0);
const LLUUID &item_id = getWearableItemID((EWearableType)i,0);
gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id);
if (wearable)
if (LLWearableDictionary::getAssetType(type) == LLAssetType::AT_BODYPART)
{
wearables_being_removed.push_back(wearable);
// exactly one wearable per body part
setWearable(type,0,new_wearable);
}
removeWearable((EWearableType)i,true,0);
else
{
pushWearable(type,new_wearable);
}
wearableUpdated(new_wearable);
checkWearableAgainstInventory(new_wearable);
}
}
gInventory.notifyObservers();
std::vector<LLWearable*>::iterator wearable_iter;
for (wearable_iter = wearables_being_removed.begin();
wearable_iter != wearables_being_removed.end();
++wearable_iter)
{
LLWearable* wearablep = *wearable_iter;
if (wearablep)
{
wearablep->removeFromAvatar(TRUE);
}
}
if (isAgentAvatarValid())
{
gAgentAvatarp->setCompositeUpdatesEnabled(TRUE);
@ -1766,6 +1641,7 @@ bool LLAgentWearables::onSetWearableDialog(const LLSD& notification, const LLSD&
{
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
LLInventoryItem* new_item = gInventory.getItem(notification["payload"]["item_id"].asUUID());
U32 index = gAgentWearables.getWearableIndex(wearable);
if (!new_item)
{
delete wearable;
@ -1775,8 +1651,7 @@ bool LLAgentWearables::onSetWearableDialog(const LLSD& notification, const LLSD&
switch(option)
{
case 0: // "Save"
// MULTI_WEARABLE: assuming 0th
gAgentWearables.saveWearable(wearable->getType(),0);
gAgentWearables.saveWearable(wearable->getType(),index);
gAgentWearables.setWearableFinal(new_item, wearable);
break;
@ -1866,30 +1741,35 @@ void LLAgentWearables::queryWearableCache()
for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++)
{
const LLVOAvatarDictionary::BakedEntry *baked_dict = LLVOAvatarDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)baked_index);
LLUUID hash;
LLMD5 hash;
bool hash_computed = false;
for (U8 i=0; i < baked_dict->mWearables.size(); i++)
{
const EWearableType baked_type = baked_dict->mWearables[i];
// MULTI_WEARABLE: not order-dependent
const U32 num_wearables = getWearableCount(baked_type);
for (U32 index = 0; index < num_wearables; ++index)
{
const LLWearable* wearable = getWearable(baked_type,index);
if (wearable)
{
hash ^= wearable->getAssetID();
LLUUID asset_id = wearable->getAssetID();
hash.update((const unsigned char*)asset_id.mData, UUID_BYTES);
hash_computed = true;
}
}
}
if (hash.notNull())
hash.finalize();
if (hash_computed)
{
hash ^= baked_dict->mWearablesHashID;
LLUUID hash_id;
hash.raw_digest(hash_id.mData);
hash_id ^= baked_dict->mWearablesHashID;
num_queries++;
// *NOTE: make sure at least one request gets packed
//llinfos << "Requesting texture for hash " << hash << " in baked texture slot " << baked_index << llendl;
gMessageSystem->nextBlockFast(_PREHASH_WearableData);
gMessageSystem->addUUIDFast(_PREHASH_ID, hash);
gMessageSystem->addUUIDFast(_PREHASH_ID, hash_id);
gMessageSystem->addU8Fast(_PREHASH_TextureIndex, (U8)baked_index);
}
@ -2189,463 +2069,3 @@ void LLAgentWearables::populateMyOutfitsFolder(void)
outfits->done();
}
}
void LLLibraryOutfitsFetch::done()
{
// Delay this until idle() routine, since it's a heavy operation and
// we also can't have it run within notifyObservers.
doOnIdle(boost::bind(&LLLibraryOutfitsFetch::doneIdle,this));
gInventory.removeObserver(this); // Prevent doOnIdle from being added twice.
}
void LLLibraryOutfitsFetch::doneIdle()
{
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:
llwarns << "Got invalid state for outfit fetch: " << mCurrFetchStep << llendl;
mOutfitsPopulated = TRUE;
break;
}
// We're completely done. Cleanup.
if (mOutfitsPopulated)
{
gInventory.removeObserver(this);
delete this;
return;
}
}
void LLLibraryOutfitsFetch::folderDone(void)
{
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.
if (cat_array.count() > 0 || wearable_array.count() > 0)
{
mOutfitsPopulated = true;
return;
}
mClothingID = gInventory.findCategoryUUIDForType(LLFolderType::FT_CLOTHING);
mLibraryClothingID = gInventory.findCategoryUUIDForType(LLFolderType::FT_CLOTHING, false, true);
// If Library->Clothing->Initial Outfits exists, use that.
LLNameCategoryCollector matchFolderFunctor("Initial Outfits");
gInventory.collectDescendentsIf(mLibraryClothingID,
cat_array, wearable_array,
LLInventoryModel::EXCLUDE_TRASH,
matchFolderFunctor);
if (cat_array.count() > 0)
{
const LLViewerInventoryCategory *cat = cat_array.get(0);
mLibraryClothingID = cat->getUUID();
}
mCompleteFolders.clear();
// Get the complete information on the items in the inventory.
uuid_vec_t folders;
folders.push_back(mClothingID);
folders.push_back(mLibraryClothingID);
fetchDescendents(folders);
if (isEverythingComplete())
{
done();
}
}
void LLLibraryOutfitsFetch::outfitsDone(void)
{
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.count() > 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.get(0);
mImportedClothingID = cat->getUUID();
}
mCompleteFolders.clear();
fetchDescendents(folders);
if (isEverythingComplete())
{
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(void)
{
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)
{
llwarns << "Library folder import for uuid:" << src_folder_id << " failed to find folder." << llendl;
continue;
}
if (!LLAppearanceMgr::getInstance()->getCanMakeFolderIntoOutfit(src_folder_id))
{
llinfos << "Skipping non-outfit folder name:" << cat->getName() << llendl;
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(void)
{
// Fetch the contents of the Imported Clothing Folder
uuid_vec_t folders;
folders.push_back(mImportedClothingID);
mCompleteFolders.clear();
fetchDescendents(folders);
if (isEverythingComplete())
{
done();
}
}
void LLLibraryOutfitsFetch::importedFolderDone(void)
{
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());
}
mCompleteFolders.clear();
fetchDescendents(folders);
if (isEverythingComplete())
{
done();
}
}
void LLLibraryOutfitsFetch::contentsDone(void)
{
LLInventoryModel::cat_array_t cat_array;
LLInventoryModel::item_array_t wearable_array;
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)
{
llwarns << "Library folder import for uuid:" << folder_id << " failed to find folder." << llendl;
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(),
LLAssetType::AT_LINK,
NULL);
}
}
mOutfitsPopulated = true;
}
//--------------------------------------------------------------------
// 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.
//--------------------------------------------------------------------
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);
doOnIdle(boost::bind(&LLInitialWearablesFetch::processContents,this));
}
void LLInitialWearablesFetch::processContents()
{
// Fetch the wearable items from the Current Outfit Folder
LLInventoryModel::cat_array_t cat_array;
LLInventoryModel::item_array_t wearable_array;
LLFindWearables is_wearable;
gInventory.collectDescendentsIf(mCompleteFolders.front(), cat_array, wearable_array,
LLInventoryModel::EXCLUDE_TRASH, is_wearable);
LLAppearanceMgr::instance().setAttachmentInvLinkEnable(true);
if (wearable_array.count() > 0)
{
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 LLInventoryFetchObserver
{
public:
LLFetchAndLinkObserver(LLInventoryFetchObserver::item_ref_t& ids):
m_ids(ids),
LLInventoryFetchObserver(true) // retry for missing items
{
}
~LLFetchAndLinkObserver()
{
}
virtual void done()
{
gInventory.removeObserver(this);
// Link to all fetched items in COF.
LLPointer<LLInventoryCallback> link_waiter = new LLUpdateAppearanceOnDestroy;
for (LLInventoryFetchObserver::item_ref_t::iterator it = m_ids.begin();
it != m_ids.end();
++it)
{
LLUUID id = *it;
LLViewerInventoryItem *item = gInventory.getItem(*it);
if (!item)
{
llwarns << "fetch failed!" << llendl;
continue;
}
link_inventory_item(gAgent.getID(),
item->getLinkedUUID(),
LLAppearanceMgr::instance().getCOF(),
item->getName(),
LLAssetType::AT_LINK,
link_waiter);
}
}
private:
LLInventoryFetchObserver::item_ref_t m_ids;
};
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();
LLInventoryFetchObserver::item_ref_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
{
llinfos << "Invalid wearable, type " << wearable_data->mType << " itemID "
<< wearable_data->mItemID << " assetID " << wearable_data->mAssetID << llendl;
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->getItemID();
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->fetchItems(ids);
// If no items to be fetched, done will never be triggered.
// TODO: Change LLInventoryFetchObserver::fetchItems to trigger done() on this condition.
if (fetcher->isEverythingComplete())
{
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;
}
}

View File

@ -0,0 +1,516 @@
/**
* @file llagentwearablesfetch.cpp
* @brief LLAgentWearblesFetch class implementation
*
* $LicenseInfo:firstyear=2001&license=viewergpl$
*
* Copyright (c) 2001-2009, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
#include "llviewerprecompiledheaders.h"
#include "llagentwearablesfetch.h"
#include "llagent.h"
#include "llagentwearables.h"
#include "llappearancemgr.h"
#include "llinventoryfunctions.h"
#include "llvoavatarself.h"
LLInitialWearablesFetch::LLInitialWearablesFetch()
{
}
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);
doOnIdle(boost::bind(&LLInitialWearablesFetch::processContents,this));
}
void LLInitialWearablesFetch::add(InitialWearableData &data)
{
mAgentInitialWearables.push_back(data);
}
void LLInitialWearablesFetch::processContents()
{
// Fetch the wearable items from the Current Outfit Folder
LLInventoryModel::cat_array_t cat_array;
LLInventoryModel::item_array_t wearable_array;
LLFindWearables is_wearable;
gInventory.collectDescendentsIf(mCompleteFolders.front(), cat_array, wearable_array,
LLInventoryModel::EXCLUDE_TRASH, is_wearable);
LLAppearanceMgr::instance().setAttachmentInvLinkEnable(true);
if (wearable_array.count() > 0)
{
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 LLInventoryFetchObserver
{
public:
LLFetchAndLinkObserver(LLInventoryFetchObserver::item_ref_t& ids):
m_ids(ids),
LLInventoryFetchObserver(true) // retry for missing items
{
}
~LLFetchAndLinkObserver()
{
}
virtual void done()
{
gInventory.removeObserver(this);
// Link to all fetched items in COF.
LLPointer<LLInventoryCallback> link_waiter = new LLUpdateAppearanceOnDestroy;
for (LLInventoryFetchObserver::item_ref_t::iterator it = m_ids.begin();
it != m_ids.end();
++it)
{
LLUUID id = *it;
LLViewerInventoryItem *item = gInventory.getItem(*it);
if (!item)
{
llwarns << "fetch failed!" << llendl;
continue;
}
link_inventory_item(gAgent.getID(),
item->getLinkedUUID(),
LLAppearanceMgr::instance().getCOF(),
item->getName(),
LLAssetType::AT_LINK,
link_waiter);
}
}
private:
LLInventoryFetchObserver::item_ref_t m_ids;
};
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();
LLInventoryFetchObserver::item_ref_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
{
llinfos << "Invalid wearable, type " << wearable_data->mType << " itemID "
<< wearable_data->mItemID << " assetID " << wearable_data->mAssetID << llendl;
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->getItemID();
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->fetchItems(ids);
// If no items to be fetched, done will never be triggered.
// TODO: Change LLInventoryFetchObserver::fetchItems to trigger done() on this condition.
if (fetcher->isEverythingComplete())
{
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() :
mCurrFetchStep(LOFS_FOLDER),
mOutfitsPopulated(false)
{
mMyOutfitsID = LLUUID::null;
mClothingID = LLUUID::null;
mLibraryClothingID = LLUUID::null;
mImportedClothingID = LLUUID::null;
mImportedClothingName = "Imported Library Clothing";
}
LLLibraryOutfitsFetch::~LLLibraryOutfitsFetch()
{
}
void LLLibraryOutfitsFetch::done()
{
// Delay this until idle() routine, since it's a heavy operation and
// we also can't have it run within notifyObservers.
doOnIdle(boost::bind(&LLLibraryOutfitsFetch::doneIdle,this));
gInventory.removeObserver(this); // Prevent doOnIdle from being added twice.
}
void LLLibraryOutfitsFetch::doneIdle()
{
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:
llwarns << "Got invalid state for outfit fetch: " << mCurrFetchStep << llendl;
mOutfitsPopulated = TRUE;
break;
}
// We're completely done. Cleanup.
if (mOutfitsPopulated)
{
gInventory.removeObserver(this);
delete this;
return;
}
}
void LLLibraryOutfitsFetch::folderDone(void)
{
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.
if (cat_array.count() > 0 || wearable_array.count() > 0)
{
mOutfitsPopulated = true;
return;
}
mClothingID = gInventory.findCategoryUUIDForType(LLFolderType::FT_CLOTHING);
mLibraryClothingID = gInventory.findCategoryUUIDForType(LLFolderType::FT_CLOTHING, false, true);
// If Library->Clothing->Initial Outfits exists, use that.
LLNameCategoryCollector matchFolderFunctor("Initial Outfits");
gInventory.collectDescendentsIf(mLibraryClothingID,
cat_array, wearable_array,
LLInventoryModel::EXCLUDE_TRASH,
matchFolderFunctor);
if (cat_array.count() > 0)
{
const LLViewerInventoryCategory *cat = cat_array.get(0);
mLibraryClothingID = cat->getUUID();
}
mCompleteFolders.clear();
// Get the complete information on the items in the inventory.
uuid_vec_t folders;
folders.push_back(mClothingID);
folders.push_back(mLibraryClothingID);
fetchDescendents(folders);
if (isEverythingComplete())
{
done();
}
}
void LLLibraryOutfitsFetch::outfitsDone(void)
{
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.count() > 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.get(0);
mImportedClothingID = cat->getUUID();
}
mCompleteFolders.clear();
fetchDescendents(folders);
if (isEverythingComplete())
{
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(void)
{
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)
{
llwarns << "Library folder import for uuid:" << src_folder_id << " failed to find folder." << llendl;
continue;
}
if (!LLAppearanceMgr::getInstance()->getCanMakeFolderIntoOutfit(src_folder_id))
{
llinfos << "Skipping non-outfit folder name:" << cat->getName() << llendl;
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(void)
{
// Fetch the contents of the Imported Clothing Folder
uuid_vec_t folders;
folders.push_back(mImportedClothingID);
mCompleteFolders.clear();
fetchDescendents(folders);
if (isEverythingComplete())
{
done();
}
}
void LLLibraryOutfitsFetch::importedFolderDone(void)
{
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());
}
mCompleteFolders.clear();
fetchDescendents(folders);
if (isEverythingComplete())
{
done();
}
}
void LLLibraryOutfitsFetch::contentsDone(void)
{
LLInventoryModel::cat_array_t cat_array;
LLInventoryModel::item_array_t wearable_array;
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)
{
llwarns << "Library folder import for uuid:" << folder_id << " failed to find folder." << llendl;
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(),
LLAssetType::AT_LINK,
NULL);
}
}
mOutfitsPopulated = true;
}

View File

@ -0,0 +1,118 @@
/**
* @file llagentwearablesinitialfetch.h
* @brief LLAgentWearablesInitialFetch class header file
*
* $LicenseInfo:firstyear=2000&license=viewergpl$
*
* Copyright (c) 2000-2009, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
#ifndef LL_LLAGENTWEARABLESINITIALFETCH_H
#define LL_LLAGENTWEARABLESINITIALFETCH_H
#include "llinventoryobserver.h"
#include "llwearabledictionary.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
{
public:
LLInitialWearablesFetch();
~LLInitialWearablesFetch();
virtual void done();
struct InitialWearableData
{
EWearableType mType;
LLUUID mItemID;
LLUUID mAssetID;
InitialWearableData(EWearableType 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();
~LLLibraryOutfitsFetch();
virtual void done();
void doneIdle();
LLUUID mMyOutfitsID;
void importedFolderFetch();
protected:
void folderDone(void);
void outfitsDone(void);
void libraryDone(void);
void importedFolderDone(void);
void contentsDone(void);
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

View File

@ -39,6 +39,7 @@
#include "llfloatercustomize.h"
#include "llgesturemgr.h"
#include "llinventorybridge.h"
#include "llinventoryfunctions.h"
#include "llinventoryobserver.h"
#include "llnotificationsutil.h"
#include "llsidepanelappearance.h"
@ -1032,7 +1033,7 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append)
getDescendentsOfAssetType(category, wear_items, LLAssetType::AT_CLOTHING, false);
// Reduce wearables to max of one per type.
removeDuplicateItems(wear_items);
filterWearableItems(wear_items, 1);
filterWearableItems(wear_items, 5);
// - Attachments: include COF contents only if appending.
LLInventoryModel::item_array_t obj_items;
@ -1122,7 +1123,6 @@ void LLAppearanceMgr::updateAgentWearables(LLWearableHoldingPattern* holder, boo
items.put(item);
wearables.put(wearable);
}
break;
}
}
}

View File

@ -31,7 +31,6 @@
*/
#include "llviewerprecompiledheaders.h"
#include "llfavoritesbar.h"
#include "llfloaterreg.h"
@ -47,6 +46,7 @@
#include "llclipboard.h"
#include "llinventoryclipboard.h"
#include "llinventorybridge.h"
#include "llinventoryfunctions.h"
#include "llfloaterworldmap.h"
#include "lllandmarkactions.h"
#include "llnotificationsutil.h"

View File

@ -36,6 +36,7 @@
#include "llinventory.h"
#include "llinventorybridge.h"
#include "llinventoryfunctions.h"
#include "llinventorymodel.h"
#include "llinventoryclipboard.h"

View File

@ -51,7 +51,9 @@
//#include "llfirstuse.h"
#include "llfloaterreg.h" // getTypedInstance()
#include "llfocusmgr.h"
#include "llinventoryfunctions.h"
#include "llinventorymodel.h"
#include "llinventorymodelbackgroundfetch.h"
#include "llinventoryobserver.h"
#include "lllandmarklist.h"
#include "lllineeditor.h"
@ -322,7 +324,7 @@ void LLFloaterWorldMap::onOpen(const LLSD& key)
// Start speculative download of landmarks
const LLUUID landmark_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK);
gInventory.startBackgroundFetch(landmark_folder_id);
LLInventoryModelBackgroundFetch::instance().start(landmark_folder_id);
childSetFocus("location", TRUE);
gFocusMgr.triggerFocusFlash();

View File

@ -39,6 +39,7 @@
#include "llinventoryclipboard.h" // *TODO: remove this once hack below gone.
#include "llinventoryfilter.h"
#include "llinventoryfunctions.h"
#include "llinventorymodelbackgroundfetch.h"
#include "llinventorypanel.h"
#include "llfoldertype.h"
#include "llfloaterinventory.h"// hacked in for the bonus context menu items.
@ -943,7 +944,7 @@ void LLFolderView::draw()
}
else
{
if (gInventory.backgroundFetchActive() || mCompletedFilterGeneration < mFilter->getMinRequiredGeneration())
if (LLInventoryModelBackgroundFetch::instance().backgroundFetchActive() || mCompletedFilterGeneration < mFilter->getMinRequiredGeneration())
{
mStatusText = LLTrans::getString("Searching");
//font->renderUTF8(mStatusText, 0, 2, 1, sSearchStatusColor, LLFontGL::LEFT, LLFontGL::TOP, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE );

View File

@ -38,6 +38,7 @@
#include "llfoldervieweventlistener.h"
#include "llinventorybridge.h" // for LLItemBridge in LLInventorySort::operator()
#include "llinventoryfilter.h"
#include "llinventorymodelbackgroundfetch.h"
#include "llpanel.h"
#include "llviewercontrol.h" // gSavedSettings
#include "llviewerwindow.h" // Argh, only for setCursor()
@ -992,16 +993,16 @@ void LLFolderViewItem::draw()
if (getListener() && gInventory.isObjectDescendentOf(getListener()->getUUID(),gInventory.getRootFolderID()))
{
// Descendent of my inventory.
root_is_loading = gInventory.myInventoryFetchInProgress();
root_is_loading = LLInventoryModelBackgroundFetch::instance().inventoryFetchInProgress();
}
if (getListener() && gInventory.isObjectDescendentOf(getListener()->getUUID(),gInventory.getLibraryRootFolderID()))
{
// Descendent of library
root_is_loading = gInventory.libraryFetchInProgress();
root_is_loading = LLInventoryModelBackgroundFetch::instance().libraryFetchInProgress();
}
if ( (mIsLoading && mTimeSinceRequestStart.getElapsedTimeF32() >= gSavedSettings.getF32("FolderLoadingMessageWaitTime"))
|| (LLInventoryModel::backgroundFetchActive() && root_is_loading && mShowLoadStatus) )
|| (LLInventoryModelBackgroundFetch::instance().backgroundFetchActive() && root_is_loading && mShowLoadStatus) )
{
std::string load_string = " ( " + LLTrans::getString("LoadingData") + " ) ";
font->renderUTF8(load_string, 0, right_x, y, sSearchStatusColor,
@ -1317,7 +1318,7 @@ void LLFolderViewFolder::filter( LLInventoryFilter& filter)
// when applying a filter, matching folders get their contents downloaded first
if (filter.isNotDefault() && getFiltered(filter.getMinRequiredGeneration()) && (mListener && !gInventory.isCategoryComplete(mListener->getUUID())))
{
gInventory.startBackgroundFetch(mListener->getUUID());
LLInventoryModelBackgroundFetch::instance().start(mListener->getUUID());
}
// now query children

View File

@ -33,6 +33,7 @@
#include "llviewerprecompiledheaders.h"
#include "llinventory.h"
#include "llinventoryfunctions.h"
#include "llinventoryobserver.h"
#include "lltrans.h"

View File

@ -43,6 +43,7 @@
#include "llhudeffectbeam.h"
#include "llhudeffecttrail.h"
#include "llhudeffectlookat.h"
#include "llhudeffectpointat.h"
#include "llvoicevisualizer.h"

View File

@ -44,6 +44,7 @@
#include "llchiclet.h"
#include "llfloaterreg.h"
#include "llimfloatercontainer.h" // to replace separate IM Floaters with multifloater container
#include "llinventoryfunctions.h"
#include "lllayoutstack.h"
#include "lllineeditor.h"
#include "lllogchat.h"

View File

@ -36,6 +36,7 @@
#include "llfloaterreg.h"
#include "llfontgl.h"
#include "llgl.h"
#include "llrect.h"
#include "llerror.h"
#include "llbutton.h"

View File

@ -31,10 +31,12 @@
*/
#include "llviewerprecompiledheaders.h"
#include "llinventorybridge.h"
// external projects
#include "lltransfersourceasset.h"
#include "llinventorybridge.h"
#include "llagent.h"
#include "llagentcamera.h"
@ -52,6 +54,7 @@
#include "llinventoryclipboard.h"
#include "llinventoryfunctions.h"
#include "llinventorymodel.h"
#include "llinventorymodelbackgroundfetch.h"
#include "llinventorypanel.h"
#include "llnotifications.h"
#include "llnotificationsutil.h"
@ -729,7 +732,7 @@ BOOL LLInvFVBridge::startDrag(EDragAndDropType* type, LLUUID* id) const
if (*type == DAD_CATEGORY)
{
gInventory.startBackgroundFetch(obj->getUUID());
LLInventoryModelBackgroundFetch::instance().start(obj->getUUID());
}
rv = TRUE;
@ -1922,50 +1925,6 @@ BOOL move_inv_category_world_to_agent(const LLUUID& object_id,
return accept;
}
bool LLFindCOFValidItems::operator()(LLInventoryCategory* cat,
LLInventoryItem* item)
{
// Valid COF items are:
// - links to wearables (body parts or clothing)
// - links to attachments
// - links to gestures
// - links to ensemble folders
LLViewerInventoryItem *linked_item = ((LLViewerInventoryItem*)item)->getLinkedItem();
if (linked_item)
{
LLAssetType::EType type = linked_item->getType();
return (type == LLAssetType::AT_CLOTHING ||
type == LLAssetType::AT_BODYPART ||
type == LLAssetType::AT_GESTURE ||
type == LLAssetType::AT_OBJECT);
}
else
{
LLViewerInventoryCategory *linked_category = ((LLViewerInventoryItem*)item)->getLinkedCategory();
// BAP remove AT_NONE support after ensembles are fully working?
return (linked_category &&
((linked_category->getPreferredType() == LLFolderType::FT_NONE) ||
(LLFolderType::lookupIsEnsembleType(linked_category->getPreferredType()))));
}
}
bool LLFindWearables::operator()(LLInventoryCategory* cat,
LLInventoryItem* item)
{
if(item)
{
if((item->getType() == LLAssetType::AT_CLOTHING)
|| (item->getType() == LLAssetType::AT_BODYPART))
{
return TRUE;
}
}
return FALSE;
}
//Used by LLFolderBridge as callback for directory recursion.
class LLRightClickInventoryFetchObserver : public LLInventoryFetchObserver
{
@ -4946,9 +4905,9 @@ void LLWearableBridge::onRemoveFromAvatarArrived(LLWearable* wearable,
if( !(type==WT_SHAPE || type==WT_SKIN || type==WT_HAIR || type==WT_EYES ) ) //&&
//!((!gAgent.isTeen()) && ( type==WT_UNDERPANTS || type==WT_UNDERSHIRT )) )
{
// MULTI_WEARABLE: FIXME HACK - always remove all
bool do_remove_all = false;
gAgentWearables.removeWearable( type, do_remove_all, 0 );
U32 index = gAgentWearables.getWearableIndex(wearable);
gAgentWearables.removeWearable( type, do_remove_all, index );
}
}
}

View File

@ -37,7 +37,8 @@
// viewer includes
#include "llfoldervieweventlistener.h"
#include "llfolderviewitem.h"
#include "llinventorymodel.h" // gInventory.backgroundFetchActive()
#include "llinventorymodel.h"
#include "llinventorymodelbackgroundfetch.h"
#include "llviewercontrol.h"
#include "llfolderview.h"
@ -713,7 +714,7 @@ const std::string& LLInventoryFilter::getFilterText()
filtered_by_all_types = FALSE;
}
if (!gInventory.backgroundFetchActive()
if (!LLInventoryModelBackgroundFetch::instance().backgroundFetchActive()
&& filtered_by_type
&& !filtered_by_all_types)
{

View File

@ -86,6 +86,218 @@
BOOL LLInventoryState::sWearNewClothing = FALSE;
LLUUID LLInventoryState::sWearNewClothingTransactionID;
///----------------------------------------------------------------------------
/// LLInventoryCollectFunctor implementations
///----------------------------------------------------------------------------
// static
bool LLInventoryCollectFunctor::itemTransferCommonlyAllowed(LLInventoryItem* item)
{
if (!item)
return false;
bool allowed = false;
switch(item->getType())
{
case LLAssetType::AT_CALLINGCARD:
// not allowed
break;
case LLAssetType::AT_OBJECT:
if (isAgentAvatarValid() && !gAgentAvatarp->isWearingAttachment(item->getUUID()))
{
allowed = true;
}
break;
case LLAssetType::AT_BODYPART:
case LLAssetType::AT_CLOTHING:
if(!gAgentWearables.isWearingItem(item->getUUID()))
{
allowed = true;
}
break;
default:
allowed = true;
break;
}
return allowed;
}
bool LLIsType::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
{
if(mType == LLAssetType::AT_CATEGORY)
{
if(cat) return TRUE;
}
if(item)
{
if(item->getType() == mType) return TRUE;
}
return FALSE;
}
bool LLIsNotType::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
{
if(mType == LLAssetType::AT_CATEGORY)
{
if(cat) return FALSE;
}
if(item)
{
if(item->getType() == mType) return FALSE;
else return TRUE;
}
return TRUE;
}
bool LLIsTypeWithPermissions::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
{
if(mType == LLAssetType::AT_CATEGORY)
{
if(cat)
{
return TRUE;
}
}
if(item)
{
if(item->getType() == mType)
{
LLPermissions perm = item->getPermissions();
if ((perm.getMaskBase() & mPerm) == mPerm)
{
return TRUE;
}
}
}
return FALSE;
}
bool LLBuddyCollector::operator()(LLInventoryCategory* cat,
LLInventoryItem* item)
{
if(item)
{
if((LLAssetType::AT_CALLINGCARD == item->getType())
&& (!item->getCreatorUUID().isNull())
&& (item->getCreatorUUID() != gAgent.getID()))
{
return true;
}
}
return false;
}
bool LLUniqueBuddyCollector::operator()(LLInventoryCategory* cat,
LLInventoryItem* item)
{
if(item)
{
if((LLAssetType::AT_CALLINGCARD == item->getType())
&& (item->getCreatorUUID().notNull())
&& (item->getCreatorUUID() != gAgent.getID()))
{
mSeen.insert(item->getCreatorUUID());
return true;
}
}
return false;
}
bool LLParticularBuddyCollector::operator()(LLInventoryCategory* cat,
LLInventoryItem* item)
{
if(item)
{
if((LLAssetType::AT_CALLINGCARD == item->getType())
&& (item->getCreatorUUID() == mBuddyID))
{
return TRUE;
}
}
return FALSE;
}
bool LLNameCategoryCollector::operator()(
LLInventoryCategory* cat, LLInventoryItem* item)
{
if(cat)
{
if (!LLStringUtil::compareInsensitive(mName, cat->getName()))
{
return true;
}
}
return false;
}
bool LLFindCOFValidItems::operator()(LLInventoryCategory* cat,
LLInventoryItem* item)
{
// Valid COF items are:
// - links to wearables (body parts or clothing)
// - links to attachments
// - links to gestures
// - links to ensemble folders
LLViewerInventoryItem *linked_item = ((LLViewerInventoryItem*)item)->getLinkedItem();
if (linked_item)
{
LLAssetType::EType type = linked_item->getType();
return (type == LLAssetType::AT_CLOTHING ||
type == LLAssetType::AT_BODYPART ||
type == LLAssetType::AT_GESTURE ||
type == LLAssetType::AT_OBJECT);
}
else
{
LLViewerInventoryCategory *linked_category = ((LLViewerInventoryItem*)item)->getLinkedCategory();
// BAP remove AT_NONE support after ensembles are fully working?
return (linked_category &&
((linked_category->getPreferredType() == LLFolderType::FT_NONE) ||
(LLFolderType::lookupIsEnsembleType(linked_category->getPreferredType()))));
}
}
bool LLFindWearables::operator()(LLInventoryCategory* cat,
LLInventoryItem* item)
{
if(item)
{
if((item->getType() == LLAssetType::AT_CLOTHING)
|| (item->getType() == LLAssetType::AT_BODYPART))
{
return TRUE;
}
}
return FALSE;
}
///----------------------------------------------------------------------------
/// LLAssetIDMatches
///----------------------------------------------------------------------------
bool LLAssetIDMatches::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
{
return (item && item->getAssetUUID() == mAssetID);
}
///----------------------------------------------------------------------------
/// LLLinkedItemIDMatches
///----------------------------------------------------------------------------
bool LLLinkedItemIDMatches::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
{
return (item &&
(item->getIsLinkType()) &&
(item->getLinkedUUID() == mBaseItemID)); // A linked item's assetID will be the compared-to item's itemID.
}
void LLSaveFolderState::setApply(BOOL apply)
{
mApply = apply;

View File

@ -38,15 +38,221 @@
#include "llfolderview.h"
#include "llfolderviewitem.h"
/********************************************************************************
** **
** INVENTORY COLLECTOR FUNCTIONS
**/
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLInventoryCollectFunctor
//
// This is a collection of miscellaneous functions and classes
// that don't fit cleanly into any other class header. Eventually,
// we should figure out where to put these functions so that we can
// get rid of this generic file.
//
// Base class for LLInventoryModel::collectDescendentsIf() method
// which accepts an instance of one of these objects to use as the
// function to determine if it should be added. Derive from this class
// and override the () operator to return TRUE if you want to collect
// the category or item passed in.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLInventoryCollectFunctor
{
public:
virtual ~LLInventoryCollectFunctor(){};
virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) = 0;
static bool itemTransferCommonlyAllowed(LLInventoryItem* item);
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLAssetIDMatches
//
// This functor finds inventory items pointing to the specified asset
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLViewerInventoryItem;
class LLAssetIDMatches : public LLInventoryCollectFunctor
{
public:
LLAssetIDMatches(const LLUUID& asset_id) : mAssetID(asset_id) {}
virtual ~LLAssetIDMatches() {}
bool operator()(LLInventoryCategory* cat, LLInventoryItem* item);
protected:
LLUUID mAssetID;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLLinkedItemIDMatches
//
// This functor finds inventory items linked to the specific inventory id.
// Assumes the inventory id is itself not a linked item.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLLinkedItemIDMatches : public LLInventoryCollectFunctor
{
public:
LLLinkedItemIDMatches(const LLUUID& item_id) : mBaseItemID(item_id) {}
virtual ~LLLinkedItemIDMatches() {}
bool operator()(LLInventoryCategory* cat, LLInventoryItem* item);
protected:
LLUUID mBaseItemID;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLIsType
//
// Implementation of a LLInventoryCollectFunctor which returns TRUE if
// the type is the type passed in during construction.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLIsType : public LLInventoryCollectFunctor
{
public:
LLIsType(LLAssetType::EType type) : mType(type) {}
virtual ~LLIsType() {}
virtual bool operator()(LLInventoryCategory* cat,
LLInventoryItem* item);
protected:
LLAssetType::EType mType;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLIsNotType
//
// Implementation of a LLInventoryCollectFunctor which returns FALSE if the
// type is the type passed in during construction, otherwise false.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLIsNotType : public LLInventoryCollectFunctor
{
public:
LLIsNotType(LLAssetType::EType type) : mType(type) {}
virtual ~LLIsNotType() {}
virtual bool operator()(LLInventoryCategory* cat,
LLInventoryItem* item);
protected:
LLAssetType::EType mType;
};
class LLIsTypeWithPermissions : public LLInventoryCollectFunctor
{
public:
LLIsTypeWithPermissions(LLAssetType::EType type, const PermissionBit perms, const LLUUID &agent_id, const LLUUID &group_id)
: mType(type), mPerm(perms), mAgentID(agent_id), mGroupID(group_id) {}
virtual ~LLIsTypeWithPermissions() {}
virtual bool operator()(LLInventoryCategory* cat,
LLInventoryItem* item);
protected:
LLAssetType::EType mType;
PermissionBit mPerm;
LLUUID mAgentID;
LLUUID mGroupID;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLBuddyCollector
//
// Simple class that collects calling cards that are not null, and not
// the agent. Duplicates are possible.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLBuddyCollector : public LLInventoryCollectFunctor
{
public:
LLBuddyCollector() {}
virtual ~LLBuddyCollector() {}
virtual bool operator()(LLInventoryCategory* cat,
LLInventoryItem* item);
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLUniqueBuddyCollector
//
// Simple class that collects calling cards that are not null, and not
// the agent. Duplicates are discarded.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLUniqueBuddyCollector : public LLInventoryCollectFunctor
{
public:
LLUniqueBuddyCollector() {}
virtual ~LLUniqueBuddyCollector() {}
virtual bool operator()(LLInventoryCategory* cat,
LLInventoryItem* item);
protected:
std::set<LLUUID> mSeen;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLParticularBuddyCollector
//
// Simple class that collects calling cards that match a particular uuid
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLParticularBuddyCollector : public LLInventoryCollectFunctor
{
public:
LLParticularBuddyCollector(const LLUUID& id) : mBuddyID(id) {}
virtual ~LLParticularBuddyCollector() {}
virtual bool operator()(LLInventoryCategory* cat,
LLInventoryItem* item);
protected:
LLUUID mBuddyID;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLNameCategoryCollector
//
// Collects categories based on case-insensitive match of prefix
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLNameCategoryCollector : public LLInventoryCollectFunctor
{
public:
LLNameCategoryCollector(const std::string& name) : mName(name) {}
virtual ~LLNameCategoryCollector() {}
virtual bool operator()(LLInventoryCategory* cat,
LLInventoryItem* item);
protected:
std::string mName;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLFindCOFValidItems
//
// Collects items that can be legitimately linked to in the COF.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLFindCOFValidItems : public LLInventoryCollectFunctor
{
public:
LLFindCOFValidItems() {}
virtual ~LLFindCOFValidItems() {}
virtual bool operator()(LLInventoryCategory* cat,
LLInventoryItem* item);
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLFindWearables
//
// Collects wearables based on item type.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLFindWearables : public LLInventoryCollectFunctor
{
public:
LLFindWearables() {}
virtual ~LLFindWearables() {}
virtual bool operator()(LLInventoryCategory* cat,
LLInventoryItem* item);
};
/** Inventory Collector Functions
** **
*******************************************************************************/
class LLInventoryState
{
public:

View File

@ -57,32 +57,16 @@
#include "process.h"
#endif
BOOL LLInventoryModel::sBackgroundFetchActive = FALSE;
BOOL LLInventoryModel::sAllFoldersFetched = FALSE;
BOOL LLInventoryModel::sMyInventoryFetchStarted = FALSE;
BOOL LLInventoryModel::sLibraryFetchStarted = FALSE;
S32 LLInventoryModel::sNumFetchRetries = 0;
F32 LLInventoryModel::sMinTimeBetweenFetches = 0.3f;
F32 LLInventoryModel::sMaxTimeBetweenFetches = 10.f;
BOOL LLInventoryModel::sTimelyFetchPending = FALSE;
LLFrameTimer LLInventoryModel::sFetchTimer;
S16 LLInventoryModel::sBulkFetchCount = 0;
BOOL LLInventoryModel::sFirstTimeInViewer2 = TRUE;
// Increment this if the inventory contents change in a non-backwards-compatible way.
// For viewer 2, the addition of link items makes a pre-viewer-2 cache incorrect.
const S32 LLInventoryModel::sCurrentInvCacheVersion = 2;
// RN: for some reason, using std::queue in the header file confuses the compiler which things it's an xmlrpc_queue
static std::deque<LLUUID> sFetchQueue;
BOOL LLInventoryModel::sFirstTimeInViewer2 = TRUE;
///----------------------------------------------------------------------------
/// Local function declarations, constants, enums, and typedefs
///----------------------------------------------------------------------------
//BOOL decompress_file(const char* src_filename, const char* dst_filename);
const F32 MAX_TIME_FOR_SINGLE_FETCH = 10.f;
const S32 MAX_FETCH_RETRIES = 10;
const char CACHE_FORMAT_STRING[] = "%s.inv";
struct InventoryIDPtrLess
@ -1345,542 +1329,6 @@ bool LLInventoryModel::fetchDescendentsOf(const LLUUID& folder_id)
return cat->fetchDescendents();
}
//Initialize statics.
bool LLInventoryModel::isBulkFetchProcessingComplete()
{
return sFetchQueue.empty() && sBulkFetchCount<=0;
}
class LLInventoryModelFetchDescendentsResponder: public LLHTTPClient::Responder
{
public:
LLInventoryModelFetchDescendentsResponder(const LLSD& request_sd) : mRequestSD(request_sd) {};
//LLInventoryModelFetchDescendentsResponder() {};
void result(const LLSD& content);
void error(U32 status, const std::string& reason);
public:
typedef std::vector<LLViewerInventoryCategory*> folder_ref_t;
protected:
LLSD mRequestSD;
};
//If we get back a normal response, handle it here
void LLInventoryModelFetchDescendentsResponder::result(const LLSD& content)
{
if (content.has("folders"))
{
for(LLSD::array_const_iterator folder_it = content["folders"].beginArray();
folder_it != content["folders"].endArray();
++folder_it)
{
LLSD folder_sd = *folder_it;
//LLUUID agent_id = folder_sd["agent_id"];
//if(agent_id != gAgent.getID()) //This should never happen.
//{
// llwarns << "Got a UpdateInventoryItem for the wrong agent."
// << llendl;
// break;
//}
LLUUID parent_id = folder_sd["folder_id"];
LLUUID owner_id = folder_sd["owner_id"];
S32 version = (S32)folder_sd["version"].asInteger();
S32 descendents = (S32)folder_sd["descendents"].asInteger();
LLPointer<LLViewerInventoryCategory> tcategory = new LLViewerInventoryCategory(owner_id);
if (parent_id.isNull())
{
LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem;
for(LLSD::array_const_iterator item_it = folder_sd["items"].beginArray();
item_it != folder_sd["items"].endArray();
++item_it)
{
const LLUUID lost_uuid = gInventory.findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND);
if (lost_uuid.notNull())
{
LLSD item = *item_it;
titem->unpackMessage(item);
LLInventoryModel::update_list_t update;
LLInventoryModel::LLCategoryUpdate new_folder(lost_uuid, 1);
update.push_back(new_folder);
gInventory.accountForUpdate(update);
titem->setParent(lost_uuid);
titem->updateParentOnServer(FALSE);
gInventory.updateItem(titem);
gInventory.notifyObservers("fetchDescendents");
}
}
}
LLViewerInventoryCategory* pcat = gInventory.getCategory(parent_id);
if (!pcat)
{
continue;
}
for(LLSD::array_const_iterator category_it = folder_sd["categories"].beginArray();
category_it != folder_sd["categories"].endArray();
++category_it)
{
LLSD category = *category_it;
tcategory->fromLLSD(category);
if (LLInventoryModel::sMyInventoryFetchStarted ||
LLInventoryModel::sLibraryFetchStarted)
{
sFetchQueue.push_back(tcategory->getUUID());
}
else if ( !gInventory.isCategoryComplete(tcategory->getUUID()) )
{
gInventory.updateCategory(tcategory);
}
}
LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem;
for(LLSD::array_const_iterator item_it = folder_sd["items"].beginArray();
item_it != folder_sd["items"].endArray();
++item_it)
{
LLSD item = *item_it;
titem->unpackMessage(item);
gInventory.updateItem(titem);
}
// set version and descendentcount according to message.
LLViewerInventoryCategory* cat = gInventory.getCategory(parent_id);
if(cat)
{
cat->setVersion(version);
cat->setDescendentCount(descendents);
cat->determineFolderType();
}
}
}
if (content.has("bad_folders"))
{
for(LLSD::array_const_iterator folder_it = content["bad_folders"].beginArray();
folder_it != content["bad_folders"].endArray();
++folder_it)
{
LLSD folder_sd = *folder_it;
//These folders failed on the dataserver. We probably don't want to retry them.
llinfos << "Folder " << folder_sd["folder_id"].asString()
<< "Error: " << folder_sd["error"].asString() << llendl;
}
}
LLInventoryModel::incrBulkFetch(-1);
if (LLInventoryModel::isBulkFetchProcessingComplete())
{
llinfos << "Inventory fetch completed" << llendl;
LLInventoryModel::setAllFoldersFetched();
}
gInventory.notifyObservers("fetchDescendents");
}
//If we get back an error (not found, etc...), handle it here
void LLInventoryModelFetchDescendentsResponder::error(U32 status, const std::string& reason)
{
llinfos << "LLInventoryModelFetchDescendentsResponder::error "
<< status << ": " << reason << llendl;
LLInventoryModel::incrBulkFetch(-1);
if (status==499) //timed out. Let's be awesome!
{
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"];
sFetchQueue.push_front(folder_id);
}
}
else
{
if (LLInventoryModel::isBulkFetchProcessingComplete())
{
LLInventoryModel::setAllFoldersFetched();
}
}
gInventory.notifyObservers("fetchDescendents");
}
//static Bundle up a bunch of requests to send all at once.
void LLInventoryModel::bulkFetch(std::string url)
{
//Background fetch is called from gIdleCallbacks in a loop until background fetch is stopped.
//If there are items in sFetchQueue, we want to check the time since the last bulkFetch was
//sent. If it exceeds our retry time, go ahead and fire off another batch.
//Stopbackgroundfetch will be run from the Responder instead of here.
S16 max_concurrent_fetches=8;
F32 new_min_time = 0.5f; //HACK! Clean this up when old code goes away entirely.
if (sMinTimeBetweenFetches < new_min_time) sMinTimeBetweenFetches=new_min_time; //HACK! See above.
if(gDisconnected
|| sBulkFetchCount > max_concurrent_fetches
|| sFetchTimer.getElapsedTimeF32() < sMinTimeBetweenFetches)
{
return; // just bail if we are disconnected.
}
U32 folder_count=0;
U32 max_batch_size=5;
U32 sort_order = gSavedSettings.getU32(LLInventoryPanel::DEFAULT_SORT_ORDER) & 0x1;
LLSD body;
LLSD body_lib;
while( !(sFetchQueue.empty() ) && (folder_count < max_batch_size) )
{
if (sFetchQueue.front().isNull()) //DEV-17797
{
LLSD folder_sd;
folder_sd["folder_id"] = LLUUID::null.asString();
folder_sd["owner_id"] = gAgent.getID();
folder_sd["sort_order"] = (LLSD::Integer)sort_order;
folder_sd["fetch_folders"] = (LLSD::Boolean)FALSE;
folder_sd["fetch_items"] = (LLSD::Boolean)TRUE;
body["folders"].append(folder_sd);
folder_count++;
}
else
{
LLViewerInventoryCategory* cat = gInventory.getCategory(sFetchQueue.front());
if (cat)
{
if ( LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion())
{
LLSD folder_sd;
folder_sd["folder_id"] = cat->getUUID();
folder_sd["owner_id"] = cat->getOwnerID();
folder_sd["sort_order"] = (LLSD::Integer)sort_order;
folder_sd["fetch_folders"] = TRUE; //(LLSD::Boolean)sFullFetchStarted;
folder_sd["fetch_items"] = (LLSD::Boolean)TRUE;
if (ALEXANDRIA_LINDEN_ID == cat->getOwnerID())
body_lib["folders"].append(folder_sd);
else
body["folders"].append(folder_sd);
folder_count++;
}
if (sMyInventoryFetchStarted ||
sLibraryFetchStarted)
{ //Already have this folder but append child folders to list.
// add all children to queue
parent_cat_map_t::iterator cat_it = gInventory.mParentChildCategoryTree.find(cat->getUUID());
if (cat_it != gInventory.mParentChildCategoryTree.end())
{
cat_array_t* child_categories = cat_it->second;
for (S32 child_num = 0; child_num < child_categories->count(); child_num++)
{
sFetchQueue.push_back(child_categories->get(child_num)->getUUID());
}
}
}
}
}
sFetchQueue.pop_front();
}
if (folder_count > 0)
{
sBulkFetchCount++;
if (body["folders"].size())
{
LLHTTPClient::post(url, body, new LLInventoryModelFetchDescendentsResponder(body),300.0);
}
if (body_lib["folders"].size())
{
std::string url_lib = gAgent.getRegion()->getCapability("FetchLibDescendents");
LLHTTPClient::post(url_lib, body_lib, new LLInventoryModelFetchDescendentsResponder(body_lib),300.0);
}
sFetchTimer.reset();
}
else if (isBulkFetchProcessingComplete())
{
setAllFoldersFetched();
}
}
bool fetchQueueContainsNoDescendentsOf(const LLUUID& cat_id)
{
for (std::deque<LLUUID>::iterator it = sFetchQueue.begin();
it != sFetchQueue.end(); ++it)
{
const LLUUID& fetch_id = *it;
if (gInventory.isObjectDescendentOf(fetch_id, cat_id))
return false;
}
return true;
}
/* static */
bool LLInventoryModel::libraryFetchStarted()
{
return sLibraryFetchStarted;
}
/* static */
bool LLInventoryModel::libraryFetchCompleted()
{
return libraryFetchStarted() && fetchQueueContainsNoDescendentsOf(gInventory.getLibraryRootFolderID());
}
/* static */
bool LLInventoryModel::libraryFetchInProgress()
{
return libraryFetchStarted() && !libraryFetchCompleted();
}
/* static */
bool LLInventoryModel::myInventoryFetchStarted()
{
return sMyInventoryFetchStarted;
}
/* static */
bool LLInventoryModel::myInventoryFetchCompleted()
{
return myInventoryFetchStarted() && fetchQueueContainsNoDescendentsOf(gInventory.getRootFolderID());
}
/* static */
bool LLInventoryModel::myInventoryFetchInProgress()
{
return myInventoryFetchStarted() && !myInventoryFetchCompleted();
}
// static
bool LLInventoryModel::isEverythingFetched()
{
return sAllFoldersFetched;
}
//static
BOOL LLInventoryModel::backgroundFetchActive()
{
return sBackgroundFetchActive;
}
void LLInventoryModel::startBackgroundFetch(const LLUUID& cat_id)
{
if (!sAllFoldersFetched)
{
sBackgroundFetchActive = TRUE;
if (cat_id.isNull())
{
if (!sMyInventoryFetchStarted)
{
sMyInventoryFetchStarted = TRUE;
sFetchQueue.push_back(gInventory.getRootFolderID());
gIdleCallbacks.addFunction(&LLInventoryModel::backgroundFetch, NULL);
}
if (!sLibraryFetchStarted)
{
sLibraryFetchStarted = TRUE;
sFetchQueue.push_back(gInventory.getLibraryRootFolderID());
gIdleCallbacks.addFunction(&LLInventoryModel::backgroundFetch, NULL);
}
}
else
{
// specific folder requests go to front of queue
if (sFetchQueue.empty() || sFetchQueue.front() != cat_id)
{
sFetchQueue.push_front(cat_id);
gIdleCallbacks.addFunction(&LLInventoryModel::backgroundFetch, NULL);
}
if (cat_id == gInventory.getLibraryRootFolderID())
{
sLibraryFetchStarted = TRUE;
}
if (cat_id == gInventory.getRootFolderID())
{
sMyInventoryFetchStarted = TRUE;
}
}
}
}
//static
void LLInventoryModel::findLostItems()
{
sBackgroundFetchActive = TRUE;
sFetchQueue.push_back(LLUUID::null);
gIdleCallbacks.addFunction(&LLInventoryModel::backgroundFetch, NULL);
}
//static
void LLInventoryModel::stopBackgroundFetch()
{
if (sBackgroundFetchActive)
{
sBackgroundFetchActive = FALSE;
gIdleCallbacks.deleteFunction(&LLInventoryModel::backgroundFetch, NULL);
sBulkFetchCount=0;
sMinTimeBetweenFetches=0.0f;
}
}
// static
void LLInventoryModel::setAllFoldersFetched()
{
if (sMyInventoryFetchStarted &&
sLibraryFetchStarted)
{
sAllFoldersFetched = TRUE;
}
stopBackgroundFetch();
}
//static
void LLInventoryModel::backgroundFetch(void*)
{
if (sBackgroundFetchActive && gAgent.getRegion())
{
//If we'll be using the capability, we'll be sending batches and the background thing isn't as important.
std::string url = gAgent.getRegion()->getCapability("WebFetchInventoryDescendents");
if (!url.empty())
{
bulkFetch(url);
return;
}
//DEPRECATED OLD CODE FOLLOWS.
// no more categories to fetch, stop fetch process
if (sFetchQueue.empty())
{
llinfos << "Inventory fetch completed" << llendl;
setAllFoldersFetched();
return;
}
F32 fast_fetch_time = lerp(sMinTimeBetweenFetches, sMaxTimeBetweenFetches, 0.1f);
F32 slow_fetch_time = lerp(sMinTimeBetweenFetches, sMaxTimeBetweenFetches, 0.5f);
if (sTimelyFetchPending && sFetchTimer.getElapsedTimeF32() > slow_fetch_time)
{
// double timeouts on failure
sMinTimeBetweenFetches = llmin(sMinTimeBetweenFetches * 2.f, 10.f);
sMaxTimeBetweenFetches = llmin(sMaxTimeBetweenFetches * 2.f, 120.f);
llinfos << "Inventory fetch times grown to (" << sMinTimeBetweenFetches << ", " << sMaxTimeBetweenFetches << ")" << llendl;
// fetch is no longer considered "timely" although we will wait for full time-out
sTimelyFetchPending = FALSE;
}
while(1)
{
if (sFetchQueue.empty())
{
break;
}
if(gDisconnected)
{
// just bail if we are disconnected.
break;
}
LLViewerInventoryCategory* cat = gInventory.getCategory(sFetchQueue.front());
// category has been deleted, remove from queue.
if (!cat)
{
sFetchQueue.pop_front();
continue;
}
if (sFetchTimer.getElapsedTimeF32() > sMinTimeBetweenFetches &&
LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion())
{
// category exists but has no children yet, fetch the descendants
// for now, just request every time and rely on retry timer to throttle
if (cat->fetchDescendents())
{
sFetchTimer.reset();
sTimelyFetchPending = TRUE;
}
else
{
// The catagory also tracks if it has expired and here it says it hasn't
// yet. Get out of here because nothing is going to happen until we
// update the timers.
break;
}
}
// do I have all my children?
else if (gInventory.isCategoryComplete(sFetchQueue.front()))
{
// finished with this category, remove from queue
sFetchQueue.pop_front();
// add all children to queue
parent_cat_map_t::iterator cat_it = gInventory.mParentChildCategoryTree.find(cat->getUUID());
if (cat_it != gInventory.mParentChildCategoryTree.end())
{
cat_array_t* child_categories = cat_it->second;
for (S32 child_num = 0; child_num < child_categories->count(); child_num++)
{
sFetchQueue.push_back(child_categories->get(child_num)->getUUID());
}
}
// we received a response in less than the fast time
if (sTimelyFetchPending && sFetchTimer.getElapsedTimeF32() < fast_fetch_time)
{
// shrink timeouts based on success
sMinTimeBetweenFetches = llmax(sMinTimeBetweenFetches * 0.8f, 0.3f);
sMaxTimeBetweenFetches = llmax(sMaxTimeBetweenFetches * 0.8f, 10.f);
//llinfos << "Inventory fetch times shrunk to (" << sMinTimeBetweenFetches << ", " << sMaxTimeBetweenFetches << ")" << llendl;
}
sTimelyFetchPending = FALSE;
continue;
}
else if (sFetchTimer.getElapsedTimeF32() > sMaxTimeBetweenFetches)
{
// received first packet, but our num descendants does not match db's num descendants
// so try again later
LLUUID fetch_id = sFetchQueue.front();
sFetchQueue.pop_front();
if (sNumFetchRetries++ < MAX_FETCH_RETRIES)
{
// push on back of queue
sFetchQueue.push_back(fetch_id);
}
sTimelyFetchPending = FALSE;
sFetchTimer.reset();
break;
}
// not enough time has elapsed to do a new fetch
break;
}
}
}
void LLInventoryModel::cache(
const LLUUID& parent_folder_id,
@ -3763,205 +3211,6 @@ void LLInventoryModel::dumpInventory() const
llinfos << "\n**********************\nEnd Inventory Dump" << llendl;
}
///----------------------------------------------------------------------------
/// LLInventoryCollectFunctor implementations
///----------------------------------------------------------------------------
// static
bool LLInventoryCollectFunctor::itemTransferCommonlyAllowed(LLInventoryItem* item)
{
if (!item)
return false;
bool allowed = false;
switch(item->getType())
{
case LLAssetType::AT_CALLINGCARD:
// not allowed
break;
case LLAssetType::AT_OBJECT:
if (isAgentAvatarValid() && !gAgentAvatarp->isWearingAttachment(item->getUUID()))
{
allowed = true;
}
break;
case LLAssetType::AT_BODYPART:
case LLAssetType::AT_CLOTHING:
if(!gAgentWearables.isWearingItem(item->getUUID()))
{
allowed = true;
}
break;
default:
allowed = true;
break;
}
return allowed;
}
bool LLIsType::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
{
if(mType == LLAssetType::AT_CATEGORY)
{
if(cat) return TRUE;
}
if(item)
{
if(item->getType() == mType) return TRUE;
}
return FALSE;
}
bool LLIsNotType::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
{
if(mType == LLAssetType::AT_CATEGORY)
{
if(cat) return FALSE;
}
if(item)
{
if(item->getType() == mType) return FALSE;
else return TRUE;
}
return TRUE;
}
bool LLIsTypeWithPermissions::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
{
if(mType == LLAssetType::AT_CATEGORY)
{
if(cat)
{
return TRUE;
}
}
if(item)
{
if(item->getType() == mType)
{
LLPermissions perm = item->getPermissions();
if ((perm.getMaskBase() & mPerm) == mPerm)
{
return TRUE;
}
}
}
return FALSE;
}
//bool LLIsClone::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
//{
// if(cat) return FALSE;
// if(item)
// {
// if(mItemMap->getType() == LLAssetType::AT_CALLINGCARD)
// {
// if((item->getType() == LLAssetType::AT_CALLINGCARD)
// && !(item->getCreatorUUID().isNull())
// && (item->getCreatorUUID() == mItemMap->getCreatorUUID()))
// {
// return TRUE;
// }
// }
// else
// {
// if((item->getType() == mItemMap->getType())
// && !(item->getAssetUUID().isNull())
// && (item->getAssetUUID() == mItemMap->getAssetUUID())
// && (item->getName() == mItemMap->getName()))
// {
// return TRUE;
// }
// }
// }
// return FALSE;
//}
bool LLBuddyCollector::operator()(LLInventoryCategory* cat,
LLInventoryItem* item)
{
if(item)
{
if((LLAssetType::AT_CALLINGCARD == item->getType())
&& (!item->getCreatorUUID().isNull())
&& (item->getCreatorUUID() != gAgent.getID()))
{
return true;
}
}
return false;
}
bool LLUniqueBuddyCollector::operator()(LLInventoryCategory* cat,
LLInventoryItem* item)
{
if(item)
{
if((LLAssetType::AT_CALLINGCARD == item->getType())
&& (item->getCreatorUUID().notNull())
&& (item->getCreatorUUID() != gAgent.getID()))
{
mSeen.insert(item->getCreatorUUID());
return true;
}
}
return false;
}
bool LLParticularBuddyCollector::operator()(LLInventoryCategory* cat,
LLInventoryItem* item)
{
if(item)
{
if((LLAssetType::AT_CALLINGCARD == item->getType())
&& (item->getCreatorUUID() == mBuddyID))
{
return TRUE;
}
}
return FALSE;
}
bool LLNameCategoryCollector::operator()(
LLInventoryCategory* cat, LLInventoryItem* item)
{
if(cat)
{
if (!LLStringUtil::compareInsensitive(mName, cat->getName()))
{
return true;
}
}
return false;
}
///----------------------------------------------------------------------------
/// LLAssetIDMatches
///----------------------------------------------------------------------------
bool LLAssetIDMatches::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
{
return (item && item->getAssetUUID() == mAssetID);
}
///----------------------------------------------------------------------------
/// LLLinkedItemIDMatches
///----------------------------------------------------------------------------
bool LLLinkedItemIDMatches::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
{
return (item &&
(item->getIsLinkType()) &&
(item->getLinkedUUID() == mBaseItemID)); // A linked item's assetID will be the compared-to item's itemID.
}
///----------------------------------------------------------------------------
/// Local function definitions
///----------------------------------------------------------------------------

View File

@ -81,7 +81,6 @@ public:
CHILDREN_MAYBE
};
// These are used a lot...
typedef LLDynamicArray<LLPointer<LLViewerInventoryCategory> > cat_array_t;
typedef LLDynamicArray<LLPointer<LLViewerInventoryItem> > item_array_t;
typedef std::set<LLUUID> changed_items_t;
@ -368,8 +367,6 @@ public:
// Utility Functions
void removeItem(const LLUUID& item_id);
static void findLostItems();
// Data about the agent's root folder and root library folder
// are stored here, rather than in LLAgent where it used to be, because
// gInventory is a singleton and represents the agent's inventory.
@ -501,12 +498,6 @@ private:
LLUUID mLibraryRootFolderID;
LLUUID mLibraryOwnerID;
static BOOL sTimelyFetchPending;
static S32 sNumFetchRetries;
static LLFrameTimer sFetchTimer;
static F32 sMinTimeBetweenFetches;
static F32 sMaxTimeBetweenFetches;
// Expected inventory cache version
const static S32 sCurrentInvCacheVersion;
@ -532,41 +523,6 @@ public:
// *NOTE: DEBUG functionality
void dumpInventory() const;
////////////////////////////////////////////////////////////////////////////////
// Bulk fetch
public:
// Start and stop background breadth-first fetching of inventory contents.
// This gets triggered when performing a filter-search
void startBackgroundFetch(const LLUUID& cat_id = LLUUID::null);
static BOOL backgroundFetchActive();
static bool isEverythingFetched();
static void backgroundFetch(void*); // background fetch idle function
static void incrBulkFetch(S16 fetching) { sBulkFetchCount+=fetching; if (sBulkFetchCount<0) sBulkFetchCount=0; }
static void stopBackgroundFetch(); // stop fetch process
static bool isBulkFetchProcessingComplete();
// Add categories to a list to be fetched in bulk.
static void bulkFetch(std::string url);
static bool libraryFetchStarted();
static bool libraryFetchCompleted();
static bool libraryFetchInProgress();
static bool myInventoryFetchStarted();
static bool myInventoryFetchCompleted();
static bool myInventoryFetchInProgress();
private:
static BOOL sMyInventoryFetchStarted;
static BOOL sLibraryFetchStarted;
static BOOL sAllFoldersFetched;
static void setAllFoldersFetched();
// completing the fetch once per session should be sufficient
static BOOL sBackgroundFetchActive;
static S16 sBulkFetchCount;
////////////////////////////////////////////////////////////////////////////////
// Login status
public:
@ -578,234 +534,5 @@ private:
// a special inventory model for the agent
extern LLInventoryModel gInventory;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLInventoryCollectFunctor
//
// Base class for LLInventoryModel::collectDescendentsIf() method
// which accepts an instance of one of these objects to use as the
// function to determine if it should be added. Derive from this class
// and override the () operator to return TRUE if you want to collect
// the category or item passed in.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLInventoryCollectFunctor
{
public:
virtual ~LLInventoryCollectFunctor(){};
virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) = 0;
static bool itemTransferCommonlyAllowed(LLInventoryItem* item);
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLAssetIDMatches
//
// This functor finds inventory items pointing to the specified asset
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLViewerInventoryItem;
class LLAssetIDMatches : public LLInventoryCollectFunctor
{
public:
LLAssetIDMatches(const LLUUID& asset_id) : mAssetID(asset_id) {}
virtual ~LLAssetIDMatches() {}
bool operator()(LLInventoryCategory* cat, LLInventoryItem* item);
protected:
LLUUID mAssetID;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLLinkedItemIDMatches
//
// This functor finds inventory items linked to the specific inventory id.
// Assumes the inventory id is itself not a linked item.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLLinkedItemIDMatches : public LLInventoryCollectFunctor
{
public:
LLLinkedItemIDMatches(const LLUUID& item_id) : mBaseItemID(item_id) {}
virtual ~LLLinkedItemIDMatches() {}
bool operator()(LLInventoryCategory* cat, LLInventoryItem* item);
protected:
LLUUID mBaseItemID;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLIsType
//
// Implementation of a LLInventoryCollectFunctor which returns TRUE if
// the type is the type passed in during construction.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLIsType : public LLInventoryCollectFunctor
{
public:
LLIsType(LLAssetType::EType type) : mType(type) {}
virtual ~LLIsType() {}
virtual bool operator()(LLInventoryCategory* cat,
LLInventoryItem* item);
protected:
LLAssetType::EType mType;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLIsNotType
//
// Implementation of a LLInventoryCollectFunctor which returns FALSE if the
// type is the type passed in during construction, otherwise false.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLIsNotType : public LLInventoryCollectFunctor
{
public:
LLIsNotType(LLAssetType::EType type) : mType(type) {}
virtual ~LLIsNotType() {}
virtual bool operator()(LLInventoryCategory* cat,
LLInventoryItem* item);
protected:
LLAssetType::EType mType;
};
class LLIsTypeWithPermissions : public LLInventoryCollectFunctor
{
public:
LLIsTypeWithPermissions(LLAssetType::EType type, const PermissionBit perms, const LLUUID &agent_id, const LLUUID &group_id)
: mType(type), mPerm(perms), mAgentID(agent_id), mGroupID(group_id) {}
virtual ~LLIsTypeWithPermissions() {}
virtual bool operator()(LLInventoryCategory* cat,
LLInventoryItem* item);
protected:
LLAssetType::EType mType;
PermissionBit mPerm;
LLUUID mAgentID;
LLUUID mGroupID;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLIsClone
//
// Implementation of a LLInventoryCollectFunctor which returns TRUE if
// the object is a clone of the item passed in during
// construction.
//
// *NOTE: Since clone information is determined based off of asset id
// (or creator with calling cards), if the id is NULL, it has no
// clones - even itself.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//class LLIsClone : public LLInventoryCollectFunctor
//{
//public:
// LLIsClone(LLViewerInventoryItem* item) : mItem(item) {}
// virtual ~LLIsClone() {}
// virtual bool operator()(LLViewerInventoryCategory* cat,
// LLViewerInventoryItem* item);
//protected:
// LLPointer<LLViewerInventoryItem> mItem;
//};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLBuddyCollector
//
// Simple class that collects calling cards that are not null, and not
// the agent. Duplicates are possible.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLBuddyCollector : public LLInventoryCollectFunctor
{
public:
LLBuddyCollector() {}
virtual ~LLBuddyCollector() {}
virtual bool operator()(LLInventoryCategory* cat,
LLInventoryItem* item);
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLUniqueBuddyCollector
//
// Simple class that collects calling cards that are not null, and not
// the agent. Duplicates are discarded.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLUniqueBuddyCollector : public LLInventoryCollectFunctor
{
public:
LLUniqueBuddyCollector() {}
virtual ~LLUniqueBuddyCollector() {}
virtual bool operator()(LLInventoryCategory* cat,
LLInventoryItem* item);
protected:
std::set<LLUUID> mSeen;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLParticularBuddyCollector
//
// Simple class that collects calling cards that match a particular uuid
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLParticularBuddyCollector : public LLInventoryCollectFunctor
{
public:
LLParticularBuddyCollector(const LLUUID& id) : mBuddyID(id) {}
virtual ~LLParticularBuddyCollector() {}
virtual bool operator()(LLInventoryCategory* cat,
LLInventoryItem* item);
protected:
LLUUID mBuddyID;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLNameCategoryCollector
//
// Collects categories based on case-insensitive match of prefix
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLNameCategoryCollector : public LLInventoryCollectFunctor
{
public:
LLNameCategoryCollector(const std::string& name) : mName(name) {}
virtual ~LLNameCategoryCollector() {}
virtual bool operator()(LLInventoryCategory* cat,
LLInventoryItem* item);
protected:
std::string mName;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLFindCOFValidItems
//
// Collects items that can be legitimately linked to in the COF.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLFindCOFValidItems : public LLInventoryCollectFunctor
{
public:
LLFindCOFValidItems() {}
virtual ~LLFindCOFValidItems() {}
virtual bool operator()(LLInventoryCategory* cat,
LLInventoryItem* item);
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLFindWearables
//
// Collects wearables based on item type.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLFindWearables : public LLInventoryCollectFunctor
{
public:
LLFindWearables() {}
virtual ~LLFindWearables() {}
virtual bool operator()(LLInventoryCategory* cat,
LLInventoryItem* item);
};
#endif // LL_LLINVENTORYMODEL_H

View File

@ -0,0 +1,603 @@
/**
* @file llinventorymodel.cpp
* @brief Implementation of the inventory model used to track agent inventory.
*
* $LicenseInfo:firstyear=2002&license=viewergpl$
*
* Copyright (c) 2002-2009, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
#include "llviewerprecompiledheaders.h"
#include "llinventorymodelbackgroundfetch.h"
// Seraph clean this up
#include "llagent.h"
#include "llinventorypanel.h"
#include "llviewercontrol.h"
#include "llviewermessage.h"
#include "llviewerwindow.h"
#include "llappviewer.h"
#include "llviewerregion.h"
#include "llcallbacklist.h"
const F32 MAX_TIME_FOR_SINGLE_FETCH = 10.f;
const S32 MAX_FETCH_RETRIES = 10;
// RN: for some reason, using std::queue in the header file confuses the compiler which thinks it's an xmlrpc_queue
static std::deque<LLUUID> sFetchQueue;
bool fetchQueueContainsNoDescendentsOf(const LLUUID& cat_id)
{
for (std::deque<LLUUID>::iterator it = sFetchQueue.begin();
it != sFetchQueue.end(); ++it)
{
const LLUUID& fetch_id = *it;
if (gInventory.isObjectDescendentOf(fetch_id, cat_id))
return false;
}
return true;
}
LLInventoryModelBackgroundFetch::LLInventoryModelBackgroundFetch() :
mBackgroundFetchActive(FALSE),
mAllFoldersFetched(FALSE),
mInventoryFetchStarted(FALSE),
mLibraryFetchStarted(FALSE),
mNumFetchRetries(0),
mMinTimeBetweenFetches(0.3f),
mMaxTimeBetweenFetches(10.f),
mTimelyFetchPending(FALSE),
mBulkFetchCount(0)
{
}
LLInventoryModelBackgroundFetch::~LLInventoryModelBackgroundFetch()
{
}
bool LLInventoryModelBackgroundFetch::isBulkFetchProcessingComplete()
{
return sFetchQueue.empty() && mBulkFetchCount<=0;
}
bool LLInventoryModelBackgroundFetch::libraryFetchStarted()
{
return mLibraryFetchStarted;
}
bool LLInventoryModelBackgroundFetch::libraryFetchCompleted()
{
return libraryFetchStarted() && fetchQueueContainsNoDescendentsOf(gInventory.getLibraryRootFolderID());
}
bool LLInventoryModelBackgroundFetch::libraryFetchInProgress()
{
return libraryFetchStarted() && !libraryFetchCompleted();
}
bool LLInventoryModelBackgroundFetch::inventoryFetchStarted()
{
return mInventoryFetchStarted;
}
bool LLInventoryModelBackgroundFetch::inventoryFetchCompleted()
{
return inventoryFetchStarted() && fetchQueueContainsNoDescendentsOf(gInventory.getRootFolderID());
}
bool LLInventoryModelBackgroundFetch::inventoryFetchInProgress()
{
return inventoryFetchStarted() && !inventoryFetchCompleted();
}
bool LLInventoryModelBackgroundFetch::isEverythingFetched()
{
return mAllFoldersFetched;
}
BOOL LLInventoryModelBackgroundFetch::backgroundFetchActive()
{
return mBackgroundFetchActive;
}
void LLInventoryModelBackgroundFetch::start(const LLUUID& cat_id)
{
if (!mAllFoldersFetched)
{
mBackgroundFetchActive = TRUE;
if (cat_id.isNull())
{
if (!mInventoryFetchStarted)
{
mInventoryFetchStarted = TRUE;
sFetchQueue.push_back(gInventory.getRootFolderID());
gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
}
if (!mLibraryFetchStarted)
{
mLibraryFetchStarted = TRUE;
sFetchQueue.push_back(gInventory.getLibraryRootFolderID());
gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
}
}
else
{
// specific folder requests go to front of queue
if (sFetchQueue.empty() || sFetchQueue.front() != cat_id)
{
sFetchQueue.push_front(cat_id);
gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
}
if (cat_id == gInventory.getLibraryRootFolderID())
{
mLibraryFetchStarted = TRUE;
}
if (cat_id == gInventory.getRootFolderID())
{
mInventoryFetchStarted = TRUE;
}
}
}
}
void LLInventoryModelBackgroundFetch::findLostItems()
{
mBackgroundFetchActive = TRUE;
sFetchQueue.push_back(LLUUID::null);
gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
}
void LLInventoryModelBackgroundFetch::stopBackgroundFetch()
{
if (mBackgroundFetchActive)
{
mBackgroundFetchActive = FALSE;
gIdleCallbacks.deleteFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
mBulkFetchCount=0;
mMinTimeBetweenFetches=0.0f;
}
}
void LLInventoryModelBackgroundFetch::setAllFoldersFetched()
{
if (mInventoryFetchStarted &&
mLibraryFetchStarted)
{
mAllFoldersFetched = TRUE;
}
stopBackgroundFetch();
}
void LLInventoryModelBackgroundFetch::backgroundFetchCB(void *)
{
LLInventoryModelBackgroundFetch::instance().backgroundFetch();
}
void LLInventoryModelBackgroundFetch::backgroundFetch()
{
if (mBackgroundFetchActive && gAgent.getRegion())
{
//If we'll be using the capability, we'll be sending batches and the background thing isn't as important.
std::string url = gAgent.getRegion()->getCapability("WebFetchInventoryDescendents");
if (!url.empty())
{
bulkFetch(url);
return;
}
//DEPRECATED OLD CODE FOLLOWS.
// no more categories to fetch, stop fetch process
if (sFetchQueue.empty())
{
llinfos << "Inventory fetch completed" << llendl;
setAllFoldersFetched();
return;
}
F32 fast_fetch_time = lerp(mMinTimeBetweenFetches, mMaxTimeBetweenFetches, 0.1f);
F32 slow_fetch_time = lerp(mMinTimeBetweenFetches, mMaxTimeBetweenFetches, 0.5f);
if (mTimelyFetchPending && mFetchTimer.getElapsedTimeF32() > slow_fetch_time)
{
// double timeouts on failure
mMinTimeBetweenFetches = llmin(mMinTimeBetweenFetches * 2.f, 10.f);
mMaxTimeBetweenFetches = llmin(mMaxTimeBetweenFetches * 2.f, 120.f);
llinfos << "Inventory fetch times grown to (" << mMinTimeBetweenFetches << ", " << mMaxTimeBetweenFetches << ")" << llendl;
// fetch is no longer considered "timely" although we will wait for full time-out
mTimelyFetchPending = FALSE;
}
while(1)
{
if (sFetchQueue.empty())
{
break;
}
if(gDisconnected)
{
// just bail if we are disconnected.
break;
}
LLViewerInventoryCategory* cat = gInventory.getCategory(sFetchQueue.front());
// category has been deleted, remove from queue.
if (!cat)
{
sFetchQueue.pop_front();
continue;
}
if (mFetchTimer.getElapsedTimeF32() > mMinTimeBetweenFetches &&
LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion())
{
// category exists but has no children yet, fetch the descendants
// for now, just request every time and rely on retry timer to throttle
if (cat->fetchDescendents())
{
mFetchTimer.reset();
mTimelyFetchPending = TRUE;
}
else
{
// The catagory also tracks if it has expired and here it says it hasn't
// yet. Get out of here because nothing is going to happen until we
// update the timers.
break;
}
}
// do I have all my children?
else if (gInventory.isCategoryComplete(sFetchQueue.front()))
{
// finished with this category, remove from queue
sFetchQueue.pop_front();
// add all children to queue
LLInventoryModel::cat_array_t* categories;
LLInventoryModel::item_array_t* items;
gInventory.getDirectDescendentsOf(cat->getUUID(), categories, items);
for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin();
it != categories->end();
++it)
{
sFetchQueue.push_back((*it)->getUUID());
}
// we received a response in less than the fast time
if (mTimelyFetchPending && mFetchTimer.getElapsedTimeF32() < fast_fetch_time)
{
// shrink timeouts based on success
mMinTimeBetweenFetches = llmax(mMinTimeBetweenFetches * 0.8f, 0.3f);
mMaxTimeBetweenFetches = llmax(mMaxTimeBetweenFetches * 0.8f, 10.f);
//llinfos << "Inventory fetch times shrunk to (" << mMinTimeBetweenFetches << ", " << mMaxTimeBetweenFetches << ")" << llendl;
}
mTimelyFetchPending = FALSE;
continue;
}
else if (mFetchTimer.getElapsedTimeF32() > mMaxTimeBetweenFetches)
{
// received first packet, but our num descendants does not match db's num descendants
// so try again later
LLUUID fetch_id = sFetchQueue.front();
sFetchQueue.pop_front();
if (mNumFetchRetries++ < MAX_FETCH_RETRIES)
{
// push on back of queue
sFetchQueue.push_back(fetch_id);
}
mTimelyFetchPending = FALSE;
mFetchTimer.reset();
break;
}
// not enough time has elapsed to do a new fetch
break;
}
}
}
void LLInventoryModelBackgroundFetch::incrBulkFetch(S16 fetching)
{
mBulkFetchCount += fetching;
if (mBulkFetchCount < 0)
{
mBulkFetchCount = 0;
}
}
class LLInventoryModelFetchDescendentsResponder: public LLHTTPClient::Responder
{
public:
LLInventoryModelFetchDescendentsResponder(const LLSD& request_sd) : mRequestSD(request_sd) {};
//LLInventoryModelFetchDescendentsResponder() {};
void result(const LLSD& content);
void error(U32 status, const std::string& reason);
public:
typedef std::vector<LLViewerInventoryCategory*> folder_ref_t;
protected:
LLSD mRequestSD;
};
//If we get back a normal response, handle it here
void LLInventoryModelFetchDescendentsResponder::result(const LLSD& content)
{
if (content.has("folders"))
{
for(LLSD::array_const_iterator folder_it = content["folders"].beginArray();
folder_it != content["folders"].endArray();
++folder_it)
{
LLSD folder_sd = *folder_it;
//LLUUID agent_id = folder_sd["agent_id"];
//if(agent_id != gAgent.getID()) //This should never happen.
//{
// llwarns << "Got a UpdateInventoryItem for the wrong agent."
// << llendl;
// break;
//}
LLUUID parent_id = folder_sd["folder_id"];
LLUUID owner_id = folder_sd["owner_id"];
S32 version = (S32)folder_sd["version"].asInteger();
S32 descendents = (S32)folder_sd["descendents"].asInteger();
LLPointer<LLViewerInventoryCategory> tcategory = new LLViewerInventoryCategory(owner_id);
if (parent_id.isNull())
{
LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem;
for(LLSD::array_const_iterator item_it = folder_sd["items"].beginArray();
item_it != folder_sd["items"].endArray();
++item_it)
{
const LLUUID lost_uuid = gInventory.findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND);
if (lost_uuid.notNull())
{
LLSD item = *item_it;
titem->unpackMessage(item);
LLInventoryModel::update_list_t update;
LLInventoryModel::LLCategoryUpdate new_folder(lost_uuid, 1);
update.push_back(new_folder);
gInventory.accountForUpdate(update);
titem->setParent(lost_uuid);
titem->updateParentOnServer(FALSE);
gInventory.updateItem(titem);
gInventory.notifyObservers("fetchDescendents");
}
}
}
LLViewerInventoryCategory* pcat = gInventory.getCategory(parent_id);
if (!pcat)
{
continue;
}
for(LLSD::array_const_iterator category_it = folder_sd["categories"].beginArray();
category_it != folder_sd["categories"].endArray();
++category_it)
{
LLSD category = *category_it;
tcategory->fromLLSD(category);
if (LLInventoryModelBackgroundFetch::instance().inventoryFetchStarted() ||
LLInventoryModelBackgroundFetch::instance().libraryFetchStarted())
{
sFetchQueue.push_back(tcategory->getUUID());
}
else if ( !gInventory.isCategoryComplete(tcategory->getUUID()) )
{
gInventory.updateCategory(tcategory);
}
}
LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem;
for(LLSD::array_const_iterator item_it = folder_sd["items"].beginArray();
item_it != folder_sd["items"].endArray();
++item_it)
{
LLSD item = *item_it;
titem->unpackMessage(item);
gInventory.updateItem(titem);
}
// set version and descendentcount according to message.
LLViewerInventoryCategory* cat = gInventory.getCategory(parent_id);
if(cat)
{
cat->setVersion(version);
cat->setDescendentCount(descendents);
cat->determineFolderType();
}
}
}
if (content.has("bad_folders"))
{
for(LLSD::array_const_iterator folder_it = content["bad_folders"].beginArray();
folder_it != content["bad_folders"].endArray();
++folder_it)
{
LLSD folder_sd = *folder_it;
//These folders failed on the dataserver. We probably don't want to retry them.
llinfos << "Folder " << folder_sd["folder_id"].asString()
<< "Error: " << folder_sd["error"].asString() << llendl;
}
}
LLInventoryModelBackgroundFetch::instance().incrBulkFetch(-1);
if (LLInventoryModelBackgroundFetch::instance().isBulkFetchProcessingComplete())
{
llinfos << "Inventory fetch completed" << llendl;
LLInventoryModelBackgroundFetch::instance().setAllFoldersFetched();
}
gInventory.notifyObservers("fetchDescendents");
}
//If we get back an error (not found, etc...), handle it here
void LLInventoryModelFetchDescendentsResponder::error(U32 status, const std::string& reason)
{
llinfos << "LLInventoryModelFetchDescendentsResponder::error "
<< status << ": " << reason << llendl;
LLInventoryModelBackgroundFetch::instance().incrBulkFetch(-1);
if (status==499) //timed out. Let's be awesome!
{
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"];
sFetchQueue.push_front(folder_id);
}
}
else
{
if (LLInventoryModelBackgroundFetch::instance().isBulkFetchProcessingComplete())
{
LLInventoryModelBackgroundFetch::instance().setAllFoldersFetched();
}
}
gInventory.notifyObservers("fetchDescendents");
}
//static Bundle up a bunch of requests to send all at once.
void LLInventoryModelBackgroundFetch::bulkFetch(std::string url)
{
//Background fetch is called from gIdleCallbacks in a loop until background fetch is stopped.
//If there are items in sFetchQueue, we want to check the time since the last bulkFetch was
//sent. If it exceeds our retry time, go ahead and fire off another batch.
//Stopbackgroundfetch will be run from the Responder instead of here.
S16 max_concurrent_fetches=8;
F32 new_min_time = 0.5f; //HACK! Clean this up when old code goes away entirely.
if (mMinTimeBetweenFetches < new_min_time)
{
mMinTimeBetweenFetches=new_min_time; //HACK! See above.
}
if (gDisconnected ||
(mBulkFetchCount > max_concurrent_fetches) ||
(mFetchTimer.getElapsedTimeF32() < mMinTimeBetweenFetches))
{
return; // just bail if we are disconnected.
}
U32 folder_count=0;
U32 max_batch_size=5;
U32 sort_order = gSavedSettings.getU32(LLInventoryPanel::DEFAULT_SORT_ORDER) & 0x1;
LLSD body;
LLSD body_lib;
while (!(sFetchQueue.empty()) && (folder_count < max_batch_size))
{
if (sFetchQueue.front().isNull()) //DEV-17797
{
LLSD folder_sd;
folder_sd["folder_id"] = LLUUID::null.asString();
folder_sd["owner_id"] = gAgent.getID();
folder_sd["sort_order"] = (LLSD::Integer)sort_order;
folder_sd["fetch_folders"] = (LLSD::Boolean)FALSE;
folder_sd["fetch_items"] = (LLSD::Boolean)TRUE;
body["folders"].append(folder_sd);
folder_count++;
}
else
{
LLViewerInventoryCategory* cat = gInventory.getCategory(sFetchQueue.front());
if (cat)
{
if (LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion())
{
LLSD folder_sd;
folder_sd["folder_id"] = cat->getUUID();
folder_sd["owner_id"] = cat->getOwnerID();
folder_sd["sort_order"] = (LLSD::Integer)sort_order;
folder_sd["fetch_folders"] = TRUE; //(LLSD::Boolean)sFullFetchStarted;
folder_sd["fetch_items"] = (LLSD::Boolean)TRUE;
if (ALEXANDRIA_LINDEN_ID == cat->getOwnerID())
body_lib["folders"].append(folder_sd);
else
body["folders"].append(folder_sd);
folder_count++;
}
if (mInventoryFetchStarted || mLibraryFetchStarted)
{ //Already have this folder but append child folders to list.
// add all children to queue
LLInventoryModel::cat_array_t* categories;
LLInventoryModel::item_array_t* items;
gInventory.getDirectDescendentsOf(cat->getUUID(), categories, items);
for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin();
it != categories->end();
++it)
{
sFetchQueue.push_back((*it)->getUUID());
}
}
}
}
sFetchQueue.pop_front();
}
if (folder_count > 0)
{
mBulkFetchCount++;
if (body["folders"].size())
{
LLHTTPClient::post(url, body, new LLInventoryModelFetchDescendentsResponder(body),300.0);
}
if (body_lib["folders"].size())
{
std::string url_lib = gAgent.getRegion()->getCapability("FetchLibDescendents");
LLHTTPClient::post(url_lib, body_lib, new LLInventoryModelFetchDescendentsResponder(body_lib),300.0);
}
mFetchTimer.reset();
}
else if (isBulkFetchProcessingComplete())
{
setAllFoldersFetched();
}
}

View File

@ -0,0 +1,119 @@
/**
* @file llinventorymodelbackgroundfetch.h
* @brief LLInventoryModelBackgroundFetch class header file
*
* $LicenseInfo:firstyear=2002&license=viewergpl$
*
* Copyright (c) 2002-2009, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
#ifndef LL_LLINVENTORYMODELBACKGROUNDFETCH_H
#define LL_LLINVENTORYMODELBACKGROUNDFETCH_H
// Seraph clean this up
#include "llassettype.h"
#include "llfoldertype.h"
#include "lldarray.h"
#include "llframetimer.h"
#include "llhttpclient.h"
#include "lluuid.h"
#include "llpermissionsflags.h"
#include "llstring.h"
#include <map>
#include <set>
#include <string>
#include <vector>
// Seraph clean this up
class LLInventoryObserver;
class LLInventoryObject;
class LLInventoryItem;
class LLInventoryCategory;
class LLViewerInventoryItem;
class LLViewerInventoryCategory;
class LLViewerInventoryItem;
class LLViewerInventoryCategory;
class LLMessageSystem;
class LLInventoryCollectFunctor;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLInventoryModelBackgroundFetch
//
// This class handles background fetch.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLInventoryModelBackgroundFetch : public LLSingleton<LLInventoryModelBackgroundFetch>
{
public:
LLInventoryModelBackgroundFetch();
~LLInventoryModelBackgroundFetch();
// Start and stop background breadth-first fetching of inventory contents.
// This gets triggered when performing a filter-search
void start(const LLUUID& cat_id = LLUUID::null);
BOOL backgroundFetchActive();
bool isEverythingFetched();
void incrBulkFetch(S16 fetching);
void stopBackgroundFetch(); // stop fetch process
bool isBulkFetchProcessingComplete();
// Add categories to a list to be fetched in bulk.
void bulkFetch(std::string url);
bool libraryFetchStarted();
bool libraryFetchCompleted();
bool libraryFetchInProgress();
bool inventoryFetchStarted();
bool inventoryFetchCompleted();
bool inventoryFetchInProgress();
void findLostItems();
void setAllFoldersFetched();
static void backgroundFetchCB(void*); // background fetch idle function
void backgroundFetch();
private:
BOOL mInventoryFetchStarted;
BOOL mLibraryFetchStarted;
BOOL mAllFoldersFetched;
// completing the fetch once per session should be sufficient
BOOL mBackgroundFetchActive;
S16 mBulkFetchCount;
BOOL mTimelyFetchPending;
S32 mNumFetchRetries;
LLFrameTimer mFetchTimer;
F32 mMinTimeBetweenFetches;
F32 mMaxTimeBetweenFetches;
};
#endif // LL_LLINVENTORYMODELBACKGROUNDFETCH_H

View File

@ -43,6 +43,8 @@
#include "llimfloater.h"
#include "llimview.h"
#include "llinventorybridge.h"
#include "llinventoryfunctions.h"
#include "llinventorymodelbackgroundfetch.h"
#include "llsidepanelinventory.h"
#include "llsidetray.h"
#include "llscrollcontainer.h"
@ -643,7 +645,7 @@ BOOL LLInventoryPanel::handleHover(S32 x, S32 y, MASK mask)
if(handled)
{
ECursorType cursor = getWindow()->getCursor();
if (LLInventoryModel::backgroundFetchActive() && cursor == UI_CURSOR_ARROW)
if (LLInventoryModelBackgroundFetch::instance().backgroundFetchActive() && cursor == UI_CURSOR_ARROW)
{
// replace arrow cursor with arrow and hourglass cursor
getWindow()->setCursor(UI_CURSOR_WORKING);

View File

@ -36,6 +36,7 @@
#include "roles_constants.h"
#include "llinventory.h"
#include "llinventoryfunctions.h"
#include "lllandmark.h"
#include "llparcel.h"
#include "llregionhandle.h"

View File

@ -36,6 +36,7 @@
#include "llcombobox.h"
#include "lliconctrl.h"
#include "llinventoryfunctions.h"
#include "lllineeditor.h"
#include "lltextbox.h"
#include "lltexteditor.h"

View File

@ -49,6 +49,7 @@
#include "lldndbutton.h"
#include "llfloaterworldmap.h"
#include "llfolderviewitem.h"
#include "llinventorymodelbackgroundfetch.h"
#include "llinventorypanel.h"
#include "lllandmarkactions.h"
#include "llplacesinventorybridge.h"
@ -556,7 +557,7 @@ void LLLandmarksPanel::initLibraryInventoryPanel()
const LLUUID &landmarks_cat = gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK, false, true);
if (landmarks_cat.notNull())
{
gInventory.startBackgroundFetch(landmarks_cat);
LLInventoryModelBackgroundFetch::instance().start(landmarks_cat);
}
// Expanding "Library" tab for new users who have no landmarks in "My Inventory".
@ -620,7 +621,7 @@ void LLLandmarksPanel::onAccordionExpandedCollapsed(const LLSD& param, LLPlacesI
if (!gInventory.isCategoryComplete(cat_id))
*/
{
gInventory.startBackgroundFetch(cat_id);
LLInventoryModelBackgroundFetch::instance().start(cat_id);
}
// Apply filter substring because it might have been changed

View File

@ -40,6 +40,7 @@
#include "llfloaterinventory.h"
#include "llinventorybridge.h"
#include "llinventoryfunctions.h"
#include "llinventorymodelbackgroundfetch.h"
#include "llinventorypanel.h"
#include "llfiltereditor.h"
#include "llfloaterreg.h"
@ -419,7 +420,7 @@ void LLPanelMainInventory::onFilterEdit(const std::string& search_string )
return;
}
gInventory.startBackgroundFetch();
LLInventoryModelBackgroundFetch::instance().start();
mFilterSubString = search_string;
if (mActivePanel->getFilterSubString().empty() && mFilterSubString.empty())
@ -499,7 +500,7 @@ void LLPanelMainInventory::onFilterSelected()
if (filter->isActive())
{
// If our filter is active we may be the first thing requiring a fetch so we better start it here.
gInventory.startBackgroundFetch();
LLInventoryModelBackgroundFetch::instance().start();
}
setFilterTextFromFilter();
}
@ -566,11 +567,11 @@ void LLPanelMainInventory::updateItemcountText()
std::string text = "";
if (LLInventoryModel::backgroundFetchActive())
if (LLInventoryModelBackgroundFetch::instance().backgroundFetchActive())
{
text = getString("ItemcountFetching", string_args);
}
else if (LLInventoryModel::isEverythingFetched())
else if (LLInventoryModelBackgroundFetch::instance().isEverythingFetched())
{
text = getString("ItemcountCompleted", string_args);
}
@ -600,7 +601,7 @@ void LLPanelMainInventory::toggleFindOptions()
if (parent_floater) // Seraph: Fix this, shouldn't be null even for sidepanel
parent_floater->addDependentFloater(mFinderHandle);
// start background fetch of folders
gInventory.startBackgroundFetch();
LLInventoryModelBackgroundFetch::instance().start();
}
else
{

View File

@ -53,6 +53,7 @@
#include "llfloaterinventory.h"
#include "llinventorybridge.h"
#include "llinventorymodel.h"
#include "llinventorymodelbackgroundfetch.h"
#include "lluiconstants.h"
#include "llscrolllistctrl.h"
#include "lltextbox.h"
@ -245,7 +246,7 @@ void LLPanelOutfitEdit::onTypeFilterChanged(LLUICtrl* ctrl)
mInventoryItemsPanel->getRootFolder()->applyFunctorRecursively(opener);
mInventoryItemsPanel->getRootFolder()->scrollToShowSelection();
gInventory.startBackgroundFetch();
LLInventoryModelBackgroundFetch::instance().start();
}
void LLPanelOutfitEdit::onSearchEdit(const std::string& string)
@ -271,7 +272,7 @@ void LLPanelOutfitEdit::onSearchEdit(const std::string& string)
mInventoryItemsPanel->getRootFolder()->scrollToShowSelection();
}
gInventory.startBackgroundFetch();
LLInventoryModelBackgroundFetch::instance().start();
if (mInventoryItemsPanel->getFilterSubString().empty() && mSearchString.empty())
{

View File

@ -43,6 +43,7 @@
#include "llfloaterinventory.h"
#include "llfoldervieweventlistener.h"
#include "llinventoryfunctions.h"
#include "llinventorymodelbackgroundfetch.h"
#include "llinventorypanel.h"
#include "lllandmark.h"
#include "lllineeditor.h"
@ -217,7 +218,7 @@ void LLPanelOutfitsInventory::onSearchEdit(const std::string& string)
getRootFolder()->scrollToShowSelection();
}
gInventory.startBackgroundFetch();
LLInventoryModelBackgroundFetch::instance().start();
if (mActivePanel->getFilterSubString().empty() && string.empty())
{

View File

@ -551,7 +551,9 @@ void LLPanelPlaces::onTeleportButtonClicked()
{
LLSD payload;
payload["asset_id"] = mItem->getAssetUUID();
LLNotificationsUtil::add("TeleportFromLandmark", LLSD(), payload);
LLSD args;
args["LOCATION"] = mItem->getName();
LLNotificationsUtil::add("TeleportFromLandmark", args, payload);
}
else if (mPlaceInfoType == AGENT_INFO_TYPE ||
mPlaceInfoType == REMOTE_PLACE_INFO_TYPE ||

View File

@ -32,6 +32,7 @@
#include "llviewerprecompiledheaders.h"
//LLPanelPrimMediaControls
#include "llagent.h"
#include "llagentcamera.h"
#include "llparcel.h"
#include "llpanel.h"

View File

@ -42,6 +42,8 @@
#include "llstring.h"
#include "lldir.h"
#include "llfloaterreg.h"
#include "llinventoryfunctions.h"
#include "llinventorymodelbackgroundfetch.h"
#include "llmultigesture.h"
#include "llnotificationsutil.h"
#include "llvfile.h"
@ -131,10 +133,10 @@ LLPreviewGesture* LLPreviewGesture::show(const LLUUID& item_id, const LLUUID& ob
// Start speculative download of sounds and animations
const LLUUID animation_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_ANIMATION);
gInventory.startBackgroundFetch(animation_folder_id);
LLInventoryModelBackgroundFetch::instance().start(animation_folder_id);
const LLUUID sound_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_SOUND);
gInventory.startBackgroundFetch(sound_folder_id);
LLInventoryModelBackgroundFetch::instance().start(sound_folder_id);
// this will call refresh when we have everything.
LLViewerInventoryItem* item = (LLViewerInventoryItem*)preview->getItem();

View File

@ -358,11 +358,13 @@ void LLSidepanelAppearance::fetchInventory()
LLUUID item_id;
for(S32 type = (S32)WT_SHAPE; type < (S32)WT_COUNT; ++type)
{
// MULTI_WEARABLE:
item_id = gAgentWearables.getWearableItemID((EWearableType)type,0);
if(item_id.notNull())
for (U32 index = 0; index < gAgentWearables.getWearableCount((EWearableType)type); ++index)
{
ids.push_back(item_id);
item_id = gAgentWearables.getWearableItemID((EWearableType)type, index);
if(item_id.notNull())
{
ids.push_back(item_id);
}
}
}

View File

@ -62,6 +62,7 @@
#include "llimfloater.h"
#include "lllocationhistory.h"
#include "llimageworker.h"
#include "llloginflags.h"
#include "llmd5.h"
#include "llmemorystream.h"
@ -116,6 +117,7 @@
#include "llimagebmp.h"
#include "llinventorybridge.h"
#include "llinventorymodel.h"
#include "llinventorymodelbackgroundfetch.h"
#include "llfriendcard.h"
#include "llkeyboard.h"
#include "llloginhandler.h" // gLoginHandler, SLURL support
@ -1846,7 +1848,7 @@ bool idle_startup()
}
//DEV-17797. get null folder. Any items found here moved to Lost and Found
LLInventoryModel::findLostItems();
LLInventoryModelBackgroundFetch::instance().findLostItems();
LLStartUp::setStartupState( STATE_PRECACHE );
timeout.reset();

View File

@ -48,6 +48,7 @@
#include "llfoldervieweventlistener.h"
#include "llinventory.h"
#include "llinventoryfunctions.h"
#include "llinventorymodelbackgroundfetch.h"
#include "llinventoryobserver.h"
#include "llinventorypanel.h"
#include "llfloaterinventory.h"
@ -1053,7 +1054,7 @@ public:
{
// We need to find textures in all folders, so get the main
// background download going.
gInventory.startBackgroundFetch();
LLInventoryModelBackgroundFetch::instance().start();
gInventory.removeObserver(this);
delete this;
}
@ -1074,9 +1075,9 @@ BOOL LLTextureCtrl::handleMouseDown(S32 x, S32 y, MASK mask)
{
showPicker(FALSE);
//grab textures first...
gInventory.startBackgroundFetch(gInventory.findCategoryUUIDForType(LLFolderType::FT_TEXTURE));
LLInventoryModelBackgroundFetch::instance().start(gInventory.findCategoryUUIDForType(LLFolderType::FT_TEXTURE));
//...then start full inventory fetch.
gInventory.startBackgroundFetch();
LLInventoryModelBackgroundFetch::instance().start();
handled = TRUE;
}

View File

@ -50,6 +50,7 @@
#include "llhudeffecttrail.h"
#include "llimview.h"
#include "llinventorybridge.h"
#include "llinventoryfunctions.h"
#include "llmutelist.h"
#include "llpreviewnotecard.h"
#include "llrecentpeople.h"

View File

@ -44,7 +44,9 @@
#include "llfolderview.h"
#include "llviewercontrol.h"
#include "llconsole.h"
#include "llinventoryfunctions.h"
#include "llinventorymodel.h"
#include "llinventorymodelbackgroundfetch.h"
#include "llgesturemgr.h"
#include "llsidetray.h"
@ -538,7 +540,7 @@ bool LLViewerInventoryCategory::fetchDescendents()
std::string url = gAgent.getRegion()->getCapability("WebFetchInventoryDescendents");
if (!url.empty()) //Capability found. Build up LLSD and use it.
{
gInventory.startBackgroundFetch(mUUID);
LLInventoryModelBackgroundFetch::instance().start(mUUID);
}
else
{ //Deprecated, but if we don't have a capability, use the old system.

View File

@ -73,6 +73,7 @@
#include "llhudmanager.h"
#include "llimview.h"
#include "llinventorybridge.h"
#include "llinventoryfunctions.h"
#include "llpanellogin.h"
#include "llpanelblockedlist.h"
#include "llmenucommands.h"

View File

@ -63,6 +63,7 @@
#include "llfloaterpreference.h"
#include "llhudeffecttrail.h"
#include "llhudmanager.h"
#include "llinventoryfunctions.h"
#include "llinventoryobserver.h"
#include "llinventorypanel.h"
#include "llnearbychat.h"

View File

@ -48,6 +48,7 @@
#include "llagentwearables.h"
#include "llhudeffecttrail.h"
#include "llhudmanager.h"
#include "llinventoryfunctions.h"
#include "llselectmgr.h"
#include "lltoolgrab.h" // for needsRenderBeam
#include "lltoolmgr.h" // for needsRenderBeam