commit
bba457e889
|
|
@ -35,8 +35,9 @@
|
|||
|
||||
#include <string>
|
||||
#include "llrect.h"
|
||||
#include "lluictrl.h"
|
||||
#include "lluicolor.h"
|
||||
|
||||
class LLUICtrl;
|
||||
class LLUICtrlFactory;
|
||||
class LLUIImage;
|
||||
class LLButton;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
|
||||
#include "llinventory.h"
|
||||
#include "llinventorybridge.h"
|
||||
#include "llinventoryfunctions.h"
|
||||
#include "llinventorymodel.h"
|
||||
#include "llinventoryclipboard.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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 );
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
#include "llviewerprecompiledheaders.h"
|
||||
|
||||
#include "llinventory.h"
|
||||
#include "llinventoryfunctions.h"
|
||||
#include "llinventoryobserver.h"
|
||||
#include "lltrans.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@
|
|||
#include "llhudeffectbeam.h"
|
||||
#include "llhudeffecttrail.h"
|
||||
#include "llhudeffectlookat.h"
|
||||
#include "llhudeffectpointat.h"
|
||||
|
||||
#include "llvoicevisualizer.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
|
||||
#include "llfloaterreg.h"
|
||||
#include "llfontgl.h"
|
||||
#include "llgl.h"
|
||||
#include "llrect.h"
|
||||
#include "llerror.h"
|
||||
#include "llbutton.h"
|
||||
|
|
|
|||
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
///----------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
#include "roles_constants.h"
|
||||
|
||||
#include "llinventory.h"
|
||||
#include "llinventoryfunctions.h"
|
||||
#include "lllandmark.h"
|
||||
#include "llparcel.h"
|
||||
#include "llregionhandle.h"
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
|
||||
#include "llcombobox.h"
|
||||
#include "lliconctrl.h"
|
||||
#include "llinventoryfunctions.h"
|
||||
#include "lllineeditor.h"
|
||||
#include "lltextbox.h"
|
||||
#include "lltexteditor.h"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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 ||
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
#include "llviewerprecompiledheaders.h"
|
||||
|
||||
//LLPanelPrimMediaControls
|
||||
#include "llagent.h"
|
||||
#include "llagentcamera.h"
|
||||
#include "llparcel.h"
|
||||
#include "llpanel.h"
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue