More of the last, this time update llattachmentsmgr.cpp to the latest.
Hopefully it'll compile now?
This commit is contained in:
@@ -27,11 +27,13 @@
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
#include "llagentwearables.h"
|
||||
|
||||
#include "llattachmentsmgr.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"
|
||||
@@ -51,7 +53,6 @@
|
||||
#include "llwearablelist.h"
|
||||
#include "lllocaltextureobject.h"
|
||||
|
||||
#include "llfloatercustomize.h"
|
||||
#include "llfloaterperms.h"
|
||||
|
||||
|
||||
@@ -246,7 +247,7 @@ void LLAgentWearables::setAvatarObject(LLVOAvatarSelf *avatar)
|
||||
*
|
||||
* Would like to pass the agent in here, but we can't safely
|
||||
* count on it being around later. Just use gAgent directly.
|
||||
* @param cb callback to execute on completion (??? unused ???)
|
||||
* @param cb callback to execute on completion (? unused ?)
|
||||
* @param type Type for the wearable in the agent
|
||||
* @param wearable The wearable data.
|
||||
* @param todo Bitmask of actions to take on completion.
|
||||
@@ -413,7 +414,6 @@ void LLAgentWearables::sendAgentWearablesUpdate()
|
||||
void LLAgentWearables::saveWearable(const LLWearableType::EType type, const U32 index, BOOL send_update,
|
||||
const std::string new_name)
|
||||
{
|
||||
//llassert_always(index == 0);
|
||||
LLViewerWearable* old_wearable = getViewerWearable(type, index);
|
||||
if(!old_wearable) return;
|
||||
bool name_changed = !new_name.empty() && (new_name != old_wearable->getName());
|
||||
@@ -641,7 +641,6 @@ void LLAgentWearables::nameOrDescriptionChanged(LLUUID const& item_id)
|
||||
|
||||
BOOL LLAgentWearables::isWearableModifiable(LLWearableType::EType type, U32 index) const
|
||||
{
|
||||
//llassert_always(index == 0);
|
||||
LLUUID item_id = getWearableItemID(type, index);
|
||||
return item_id.notNull() ? isWearableModifiable(item_id) : FALSE;
|
||||
}
|
||||
@@ -652,7 +651,7 @@ BOOL LLAgentWearables::isWearableModifiable(const LLUUID& item_id) const
|
||||
if (linked_id.notNull())
|
||||
{
|
||||
LLInventoryItem* item = gInventory.getItem(linked_id);
|
||||
if(item && item->getPermissions().allowModifyBy(gAgent.getID(),
|
||||
if (item && item->getPermissions().allowModifyBy(gAgent.getID(),
|
||||
gAgent.getGroupID()))
|
||||
{
|
||||
return TRUE;
|
||||
@@ -663,12 +662,11 @@ BOOL LLAgentWearables::isWearableModifiable(const LLUUID& item_id) const
|
||||
|
||||
BOOL LLAgentWearables::isWearableCopyable(LLWearableType::EType type, U32 index) const
|
||||
{
|
||||
//llassert_always(index == 0);
|
||||
LLUUID item_id = getWearableItemID(type, index);
|
||||
if (!item_id.isNull())
|
||||
{
|
||||
LLInventoryItem* item = gInventory.getItem(item_id);
|
||||
if(item && item->getPermissions().allowCopyBy(gAgent.getID(),
|
||||
if (item && item->getPermissions().allowCopyBy(gAgent.getID(),
|
||||
gAgent.getGroupID()))
|
||||
{
|
||||
return TRUE;
|
||||
@@ -681,24 +679,23 @@ BOOL LLAgentWearables::isWearableCopyable(LLWearableType::EType type, U32 index)
|
||||
U32 LLAgentWearables::getWearablePermMask(LLWearableType::EType type)
|
||||
{
|
||||
LLUUID item_id = getWearableItemID(type);
|
||||
if(!item_id.isNull())
|
||||
if (!item_id.isNull())
|
||||
{
|
||||
LLInventoryItem* item = gInventory.getItem(item_id);
|
||||
if(item)
|
||||
if (item)
|
||||
{
|
||||
return item->getPermissions().getMaskOwner();
|
||||
}
|
||||
}
|
||||
return PERM_NONE;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
LLInventoryItem* LLAgentWearables::getWearableInventoryItem(LLWearableType::EType type, U32 index)
|
||||
{
|
||||
//llassert_always(index == 0);
|
||||
LLUUID item_id = getWearableItemID(type,index);
|
||||
LLInventoryItem* item = NULL;
|
||||
if(item_id.notNull())
|
||||
if (item_id.notNull())
|
||||
{
|
||||
item = gInventory.getItem(item_id);
|
||||
}
|
||||
@@ -785,8 +782,7 @@ void LLAgentWearables::wearableUpdated(LLWearable *wearable, BOOL removed)
|
||||
{
|
||||
if (isAgentAvatarValid())
|
||||
{
|
||||
const BOOL upload_result = removed;
|
||||
gAgentAvatarp->wearableUpdated(wearable->getType(), upload_result);
|
||||
gAgentAvatarp->wearableUpdated(wearable->getType(), removed);
|
||||
}
|
||||
|
||||
LLWearableData::wearableUpdated(wearable, removed);
|
||||
@@ -821,7 +817,6 @@ void LLAgentWearables::wearableUpdated(LLWearable *wearable, BOOL removed)
|
||||
|
||||
checkWearableAgainstInventory(viewer_wearable);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1225,7 +1220,6 @@ void LLAgentWearables::createStandardWearablesAllDone()
|
||||
LL_INFOS() << "all done?" << LL_ENDL;
|
||||
|
||||
mWearablesLoaded = TRUE;
|
||||
checkWearablesLoaded();
|
||||
notifyLoadingFinished();
|
||||
|
||||
updateServer();
|
||||
@@ -1340,14 +1334,13 @@ bool LLAgentWearables::onRemoveWearableDialog(const LLSD& notification, const LL
|
||||
// Called by removeWearable() and onRemoveWearableDialog() to actually do the removal.
|
||||
void LLAgentWearables::removeWearableFinal( LLWearableType::EType type, bool do_remove_all, U32 index)
|
||||
{
|
||||
//llassert_always(index == 0);
|
||||
//LLAgentDumper dumper("removeWearable");
|
||||
if (do_remove_all)
|
||||
{
|
||||
S32 max_entry = getWearableCount(type)-1;
|
||||
for (S32 i=max_entry; i>=0; i--)
|
||||
{
|
||||
LLViewerWearable* old_wearable = getViewerWearable(type,i);
|
||||
//queryWearableCache(); // moved below
|
||||
if (old_wearable)
|
||||
{
|
||||
eraseWearable(old_wearable);
|
||||
@@ -1363,7 +1356,6 @@ void LLAgentWearables::removeWearableFinal( LLWearableType::EType type, bool do_
|
||||
else
|
||||
{
|
||||
LLViewerWearable* old_wearable = getViewerWearable(type, index);
|
||||
//queryWearableCache(); // moved below
|
||||
|
||||
if (old_wearable)
|
||||
{
|
||||
@@ -1459,7 +1451,7 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it
|
||||
<< curr_wearable->getName() << " vs " << new_item->getName()
|
||||
<< " item ids " << curr_wearable->getItemID() << " vs " << new_item->getUUID()
|
||||
<< LL_ENDL;
|
||||
mismatched++;
|
||||
update_inventory = TRUE;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
@@ -1488,6 +1480,7 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it
|
||||
return;
|
||||
}
|
||||
|
||||
// updating inventory
|
||||
|
||||
// TODO: Removed check for ensuring that teens don't remove undershirt and underwear. Handle later
|
||||
// note: shirt is the first non-body part wearable item. Update if wearable order changes.
|
||||
@@ -1538,7 +1531,7 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it
|
||||
|
||||
// Start rendering & update the server
|
||||
mWearablesLoaded = TRUE;
|
||||
checkWearablesLoaded();
|
||||
|
||||
// [SL:KB] - Patch: Appearance-InitialWearablesLoadedCallback | Checked: 2010-09-22 (Catznip-2.2)
|
||||
if (!mInitialWearablesLoaded)
|
||||
{
|
||||
@@ -1556,141 +1549,119 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it
|
||||
|
||||
|
||||
// User has picked "wear on avatar" from a menu.
|
||||
/*void LLAgentWearables::setWearableItem(LLInventoryItem* new_item, LLViewerWearable* new_wearable, bool do_append)
|
||||
{
|
||||
//LLAgentDumper dumper("setWearableItem");
|
||||
if (isWearingItem(new_item->getUUID()))
|
||||
{
|
||||
LL_WARNS() << "wearable " << new_item->getUUID() << " is already worn" << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
const LLWearableType::EType type = new_wearable->getType();
|
||||
|
||||
// [RLVa:KB] - Checked: 2010-03-19 (RLVa-1.2.0a) | Modified: RLVa-1.2.0g
|
||||
// TODO-RLVa: [RLVa-1.2.1] This looks like dead code in SL-2.0.2 so we can't really check to see if it works :|
|
||||
if (rlv_handler_t::isEnabled())
|
||||
{
|
||||
ERlvWearMask eWear = gRlvWearableLocks.canWear(type);
|
||||
if ( (RLV_WEAR_LOCKED == eWear) || ((!do_append) && (!(eWear & RLV_WEAR_REPLACE))) )
|
||||
return;
|
||||
}
|
||||
// [/RLVa:KB]
|
||||
|
||||
if (!do_append)
|
||||
{
|
||||
// Remove old wearable, if any
|
||||
// MULTI_WEARABLE: hardwired to 0
|
||||
LLViewerWearable* old_wearable = getViewerWearable(type,0);
|
||||
if( old_wearable )
|
||||
{
|
||||
const LLUUID& old_item_id = old_wearable->getItemID();
|
||||
if( (old_wearable->getAssetID() == new_wearable->getAssetID()) &&
|
||||
(old_item_id == new_item->getUUID()) )
|
||||
{
|
||||
LL_DEBUGS() << "No change to wearable asset and item: " << LLWearableType::getTypeName( type ) << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
if( old_wearable->isDirty() )
|
||||
{
|
||||
// Bring up modal dialog: Save changes? Yes, No, Cancel
|
||||
LLSD payload;
|
||||
payload["item_id"] = new_item->getUUID();
|
||||
LLNotificationsUtil::add( "WearableSave", LLSD(), payload, boost::bind(onSetWearableDialog, _1, _2, new_wearable));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setWearableFinal(new_item, new_wearable, do_append);
|
||||
}*/
|
||||
//void LLAgentWearables::setWearableItem(LLInventoryItem* new_item, LLViewerWearable* new_wearable, bool do_append)
|
||||
//{
|
||||
// //LLAgentDumper dumper("setWearableItem");
|
||||
// if (isWearingItem(new_item->getUUID()))
|
||||
// {
|
||||
// LL_WARNS() << "wearable " << new_item->getUUID() << " is already worn" << LL_ENDL;
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// const LLWearableType::EType type = new_wearable->getType();
|
||||
//
|
||||
// if (!do_append)
|
||||
// {
|
||||
// // Remove old wearable, if any
|
||||
// // MULTI_WEARABLE: hardwired to 0
|
||||
// LLViewerWearable* old_wearable = getViewerWearable(type,0);
|
||||
// if (old_wearable)
|
||||
// {
|
||||
// const LLUUID& old_item_id = old_wearable->getItemID();
|
||||
// if ((old_wearable->getAssetID() == new_wearable->getAssetID()) &&
|
||||
// (old_item_id == new_item->getUUID()))
|
||||
// {
|
||||
// LL_DEBUGS() << "No change to wearable asset and item: " << LLWearableType::getTypeName(type) << LL_ENDL;
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// if (old_wearable->isDirty())
|
||||
// {
|
||||
// // Bring up modal dialog: Save changes? Yes, No, Cancel
|
||||
// LLSD payload;
|
||||
// payload["item_id"] = new_item->getUUID();
|
||||
// LLNotificationsUtil::add("WearableSave", LLSD(), payload, boost::bind(onSetWearableDialog, _1, _2, new_wearable));
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// setWearableFinal(new_item, new_wearable, do_append);
|
||||
//}
|
||||
|
||||
// static
|
||||
bool LLAgentWearables::onSetWearableDialog(const LLSD& notification, const LLSD& response, LLViewerWearable* wearable)
|
||||
{
|
||||
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
|
||||
LLInventoryItem* new_item = gInventory.getItem( notification["payload"]["item_id"].asUUID());
|
||||
U32 index;
|
||||
if (!gAgentWearables.getWearableIndex(wearable,index))
|
||||
{
|
||||
LL_WARNS() << "Wearable not found" << LL_ENDL;
|
||||
delete wearable;
|
||||
return false;
|
||||
}
|
||||
if( !new_item )
|
||||
{
|
||||
delete wearable;
|
||||
return false;
|
||||
}
|
||||
|
||||
switch( option )
|
||||
{
|
||||
case 0: // "Save"
|
||||
gAgentWearables.saveWearable(wearable->getType(),index);
|
||||
gAgentWearables.setWearableFinal( new_item, wearable );
|
||||
break;
|
||||
|
||||
case 1: // "Don't Save"
|
||||
gAgentWearables.setWearableFinal( new_item, wearable );
|
||||
break;
|
||||
|
||||
case 2: // "Cancel"
|
||||
break;
|
||||
|
||||
default:
|
||||
llassert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
delete wearable;
|
||||
return false;
|
||||
}
|
||||
//bool LLAgentWearables::onSetWearableDialog(const LLSD& notification, const LLSD& response, LLViewerWearable* wearable)
|
||||
//{
|
||||
// S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
|
||||
// LLInventoryItem* new_item = gInventory.getItem(notification["payload"]["item_id"].asUUID());
|
||||
// U32 index;
|
||||
// if (!gAgentWearables.getWearableIndex(wearable,index))
|
||||
// {
|
||||
// LL_WARNS() << "Wearable not found" << LL_ENDL;
|
||||
// delete wearable;
|
||||
// return false;
|
||||
// }
|
||||
// switch(option)
|
||||
// {
|
||||
// case 0: // "Save"
|
||||
// gAgentWearables.saveWearable(wearable->getType(),index);
|
||||
// gAgentWearables.setWearableFinal(new_item, wearable);
|
||||
// break;
|
||||
//
|
||||
// case 1: // "Don't Save"
|
||||
// gAgentWearables.setWearableFinal(new_item, wearable);
|
||||
// break;
|
||||
//
|
||||
// case 2: // "Cancel"
|
||||
// break;
|
||||
//
|
||||
// default:
|
||||
// llassert(0);
|
||||
// break;
|
||||
// }
|
||||
//
|
||||
// delete wearable;
|
||||
// return false;
|
||||
//}
|
||||
|
||||
// Called from setWearableItem() and onSetWearableDialog() to actually set the wearable.
|
||||
// MULTI_WEARABLE: unify code after null objects are gone.
|
||||
void LLAgentWearables::setWearableFinal(LLInventoryItem* new_item, LLViewerWearable* new_wearable, bool do_append)
|
||||
{
|
||||
const LLWearableType::EType type = new_wearable->getType();
|
||||
|
||||
if (do_append && getWearableItemID(type,0).notNull())
|
||||
{
|
||||
new_wearable->setItemID(new_item->getUUID());
|
||||
const bool trigger_updated = false;
|
||||
pushWearable(type, new_wearable, trigger_updated);
|
||||
LL_INFOS() << "Added additional wearable for type " << type
|
||||
<< " size is now " << getWearableCount(type) << LL_ENDL;
|
||||
checkWearableAgainstInventory(new_wearable);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Replace the old wearable with a new one.
|
||||
llassert(new_item->getAssetUUID() == new_wearable->getAssetID());
|
||||
|
||||
LLViewerWearable *old_wearable = getViewerWearable(type,0);
|
||||
LLUUID old_item_id;
|
||||
if (old_wearable)
|
||||
{
|
||||
old_item_id = old_wearable->getItemID();
|
||||
}
|
||||
new_wearable->setItemID(new_item->getUUID());
|
||||
setWearable(type,0,new_wearable);
|
||||
|
||||
if (old_item_id.notNull())
|
||||
{
|
||||
gInventory.addChangedMask(LLInventoryObserver::LABEL, old_item_id);
|
||||
gInventory.notifyObservers();
|
||||
}
|
||||
LL_INFOS() << "Replaced current element 0 for type " << type
|
||||
<< " size is now " << getWearableCount(type) << LL_ENDL;
|
||||
}
|
||||
|
||||
//LL_INFOS() << "LLVOAvatar::setWearableItem()" << LL_ENDL;
|
||||
queryWearableCache();
|
||||
//new_wearable->writeToAvatar(TRUE);
|
||||
|
||||
updateServer();
|
||||
}
|
||||
//void LLAgentWearables::setWearableFinal(LLInventoryItem* new_item, LLViewerWearable* new_wearable, bool do_append)
|
||||
//{
|
||||
// const LLWearableType::EType type = new_wearable->getType();
|
||||
//
|
||||
// if (do_append && getWearableItemID(type,0).notNull())
|
||||
// {
|
||||
// new_wearable->setItemID(new_item->getUUID());
|
||||
// const bool trigger_updated = false;
|
||||
// pushWearable(type, new_wearable, trigger_updated);
|
||||
// LL_INFOS() << "Added additional wearable for type " << type
|
||||
// << " size is now " << getWearableCount(type) << LL_ENDL;
|
||||
// checkWearableAgainstInventory(new_wearable);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// // Replace the old wearable with a new one.
|
||||
// llassert(new_item->getAssetUUID() == new_wearable->getAssetID());
|
||||
//
|
||||
// LLViewerWearable *old_wearable = getViewerWearable(type,0);
|
||||
// LLUUID old_item_id;
|
||||
// if (old_wearable)
|
||||
// {
|
||||
// old_item_id = old_wearable->getItemID();
|
||||
// }
|
||||
// new_wearable->setItemID(new_item->getUUID());
|
||||
// setWearable(type,0,new_wearable);
|
||||
//
|
||||
// if (old_item_id.notNull())
|
||||
// {
|
||||
// gInventory.addChangedMask(LLInventoryObserver::LABEL, old_item_id);
|
||||
// gInventory.notifyObservers();
|
||||
// }
|
||||
// LL_INFOS() << "Replaced current element 0 for type " << type
|
||||
// << " size is now " << getWearableCount(type) << LL_ENDL;
|
||||
// }
|
||||
//}
|
||||
|
||||
void LLAgentWearables::queryWearableCache()
|
||||
{
|
||||
@@ -1749,17 +1720,28 @@ void LLAgentWearables::queryWearableCache()
|
||||
}
|
||||
}
|
||||
|
||||
// virtual
|
||||
void LLAgentWearables::invalidateBakedTextureHash(LLMD5& hash) const
|
||||
{
|
||||
// Add some garbage into the hash so that it becomes invalid.
|
||||
if (isAgentAvatarValid())
|
||||
{
|
||||
hash.update((const unsigned char*)gAgentAvatarp->getID().mData, UUID_BYTES);
|
||||
}
|
||||
}
|
||||
// User has picked "remove from avatar" from a menu.
|
||||
// static
|
||||
//void LLAgentWearables::userRemoveWearable(const LLWearableType::EType &type, const U32 &index)
|
||||
//{
|
||||
// if (!(type==LLWearableType::WT_SHAPE || type==LLWearableType::WT_SKIN || type==LLWearableType::WT_HAIR || type==LLWearableType::WT_EYES)) //&&
|
||||
// //!((!gAgent.isTeen()) && (type==LLWearableType::WT_UNDERPANTS || type==LLWearableType::WT_UNDERSHIRT)))
|
||||
// {
|
||||
// gAgentWearables.removeWearable(type,false,index);
|
||||
// }
|
||||
//}
|
||||
|
||||
/// Given a desired set of attachments, find what objects need to be
|
||||
//static
|
||||
//void LLAgentWearables::userRemoveWearablesOfType(const LLWearableType::EType &type)
|
||||
//{
|
||||
// if (!(type==LLWearableType::WT_SHAPE || type==LLWearableType::WT_SKIN || type==LLWearableType::WT_HAIR || type==LLWearableType::WT_EYES)) //&&
|
||||
// //!((!gAgent.isTeen()) && (type==LLWearableType::WT_UNDERPANTS || type==LLWearableType::WT_UNDERSHIRT)))
|
||||
// {
|
||||
// gAgentWearables.removeWearable(type,true,0);
|
||||
// }
|
||||
//}
|
||||
|
||||
// Given a desired set of attachments, find what objects need to be
|
||||
// removed, and what additional inventory items need to be added.
|
||||
void LLAgentWearables::findAttachmentsAddRemoveInfo(LLInventoryModel::item_array_t& obj_item_array,
|
||||
llvo_vec_t& objects_to_remove,
|
||||
@@ -1859,7 +1841,7 @@ void LLAgentWearables::userRemoveMultipleAttachments(llvo_vec_t& objects_to_remo
|
||||
itObj = objects_to_remove.erase(itObj);
|
||||
|
||||
// Fall-back code: re-add the attachment if it got removed from COF somehow (compensates for possible bugs elsewhere)
|
||||
bool fInCOF = LLAppearanceMgr::isLinkInCOF(pAttachObj->getAttachmentItemID());
|
||||
bool fInCOF = LLAppearanceMgr::instance().isLinkedInCOF(pAttachObj->getAttachmentItemID());
|
||||
RLV_ASSERT(fInCOF);
|
||||
if (!fInCOF)
|
||||
{
|
||||
@@ -1877,6 +1859,7 @@ void LLAgentWearables::userRemoveMultipleAttachments(llvo_vec_t& objects_to_remo
|
||||
if (objects_to_remove.empty())
|
||||
return;
|
||||
|
||||
LL_DEBUGS("Avatar") << "ATT [ObjectDetach] removing " << objects_to_remove.size() << " objects" << LL_ENDL;
|
||||
gMessageSystem->newMessage("ObjectDetach");
|
||||
gMessageSystem->nextBlockFast(_PREHASH_AgentData);
|
||||
gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
|
||||
@@ -1887,8 +1870,13 @@ void LLAgentWearables::userRemoveMultipleAttachments(llvo_vec_t& objects_to_remo
|
||||
++it)
|
||||
{
|
||||
LLViewerObject *objectp = *it;
|
||||
//gAgentAvatarp->resetJointPositionsOnDetach(objectp);
|
||||
gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
|
||||
gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, objectp->getLocalID());
|
||||
const LLUUID& item_id = objectp->getAttachmentItemID();
|
||||
LLViewerInventoryItem *item = gInventory.getItem(item_id);
|
||||
LL_DEBUGS("Avatar") << "ATT removing object, item is " << (item ? item->getName() : "UNKNOWN") << " " << item_id << LL_ENDL;
|
||||
LLAttachmentsMgr::instance().onDetachRequested(item_id);
|
||||
}
|
||||
gMessageSystem->sendReliable(gAgent.getRegionHost());
|
||||
}
|
||||
@@ -1960,24 +1948,21 @@ void LLAgentWearables::userAttachMultipleAttachments(LLInventoryModel::item_arra
|
||||
// End of message chunk
|
||||
msg->sendReliable( gAgent.getRegion()->getHost() );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for(LLInventoryModel::item_array_t::const_iterator it = obj_item_array.begin();
|
||||
it != obj_item_array.end();
|
||||
++it)
|
||||
{
|
||||
const LLInventoryItem* item = *it;
|
||||
LLAttachmentsMgr::instance().addAttachmentRequest(item->getLinkedUUID(), 0, TRUE);
|
||||
}
|
||||
|
||||
// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1)
|
||||
sInitialAttachmentsRequested = true;
|
||||
// [/RLVa:KB]
|
||||
}
|
||||
|
||||
void LLAgentWearables::checkWearablesLoaded() const
|
||||
{
|
||||
#ifdef SHOW_ASSERT
|
||||
U32 item_pend_count = itemUpdatePendingCount();
|
||||
if (mWearablesLoaded)
|
||||
{
|
||||
llassert(item_pend_count==0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Returns false if the given wearable is already topmost/bottommost
|
||||
// (depending on closer_to_body parameter).
|
||||
bool LLAgentWearables::canMoveWearable(const LLUUID& item_id, bool closer_to_body) const
|
||||
@@ -1994,7 +1979,6 @@ bool LLAgentWearables::canMoveWearable(const LLUUID& item_id, bool closer_to_bod
|
||||
|
||||
BOOL LLAgentWearables::areWearablesLoaded() const
|
||||
{
|
||||
checkWearablesLoaded();
|
||||
return mWearablesLoaded;
|
||||
}
|
||||
|
||||
|
||||
@@ -170,7 +170,6 @@ public:
|
||||
|
||||
protected:
|
||||
|
||||
/*virtual*/ void invalidateBakedTextureHash(LLMD5& hash) const;
|
||||
void sendAgentWearablesUpdate();
|
||||
void sendAgentWearablesRequest();
|
||||
void queryWearableCache();
|
||||
|
||||
@@ -2588,6 +2588,7 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool enforce_item_restrictions,
|
||||
<< " descendent_count " << cof->getDescendentCount()
|
||||
<< " viewer desc count " << cof->getViewerDescendentCount() << LL_ENDL;
|
||||
}
|
||||
|
||||
// [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2010-09-22 (Catznip-2.2)
|
||||
// Update attachments to match those requested.
|
||||
if (isAgentAvatarValid())
|
||||
|
||||
@@ -27,7 +27,9 @@
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
#include "llattachmentsmgr.h"
|
||||
|
||||
#include "llvoavatarself.h"
|
||||
#include "llagent.h"
|
||||
#include "llappearancemgr.h"
|
||||
#include "llinventorymodel.h"
|
||||
#include "lltooldraganddrop.h" // pack_permissions_slam
|
||||
#include "llviewerinventory.h"
|
||||
@@ -38,7 +40,35 @@
|
||||
#include "rlvlocks.h"
|
||||
// [/RLVa:KB]
|
||||
|
||||
LLAttachmentsMgr::LLAttachmentsMgr()
|
||||
const F32 COF_LINK_BATCH_TIME = 5.0F;
|
||||
const F32 MAX_ATTACHMENT_REQUEST_LIFETIME = 30.0F;
|
||||
const F32 MIN_RETRY_REQUEST_TIME = 5.0F;
|
||||
const F32 MAX_BAD_COF_TIME = 30.0F;
|
||||
|
||||
// [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2015-06-24 (Catznip-3.7)
|
||||
class LLRegisterAttachmentCallback : public LLRequestServerAppearanceUpdateOnDestroy
|
||||
{
|
||||
public:
|
||||
LLRegisterAttachmentCallback()
|
||||
: LLRequestServerAppearanceUpdateOnDestroy()
|
||||
{
|
||||
}
|
||||
|
||||
/*virtual*/ ~LLRegisterAttachmentCallback()
|
||||
{
|
||||
}
|
||||
|
||||
/*virtual*/ void fire(const LLUUID& idItem)
|
||||
{
|
||||
LLAttachmentsMgr::instance().onRegisterAttachmentComplete(idItem);
|
||||
}
|
||||
};
|
||||
// [/SL:KB]
|
||||
|
||||
LLAttachmentsMgr::LLAttachmentsMgr():
|
||||
mAttachmentRequests("attach",MIN_RETRY_REQUEST_TIME),
|
||||
mDetachRequests("detach",MIN_RETRY_REQUEST_TIME)
|
||||
// , mQuestionableCOFLinks("badcof",MAX_BAD_COF_TIME)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -46,20 +76,34 @@ LLAttachmentsMgr::~LLAttachmentsMgr()
|
||||
{
|
||||
}
|
||||
|
||||
void LLAttachmentsMgr::addAttachment(const LLUUID& item_id,
|
||||
const U8 attachment_pt,
|
||||
//void LLAttachmentsMgr::addAttachmentRequest(const LLUUID& item_id,
|
||||
// const U8 attachment_pt,
|
||||
// const BOOL add)
|
||||
// [RLVa:KB] - Checked: 2010-09-13 (RLVa-1.2.1)
|
||||
void LLAttachmentsMgr::addAttachmentRequest(const LLUUID& item_id,
|
||||
const U8 attachment_pt,
|
||||
const BOOL add, const BOOL fRlvForce /*=FALSE*/)
|
||||
// [/RLVa:KB]
|
||||
{
|
||||
LLViewerInventoryItem *item = gInventory.getItem(item_id);
|
||||
|
||||
if (mAttachmentRequests.wasRequestedRecently(item_id))
|
||||
{
|
||||
LL_DEBUGS("Avatar") << "ATT not adding attachment to mPendingAttachments, recent request is already pending: "
|
||||
<< (item ? item->getName() : "UNKNOWN") << " id " << item_id << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
LL_DEBUGS("Avatar") << "ATT adding attachment to mPendingAttachments "
|
||||
<< (item ? item->getName() : "UNKNOWN") << " id " << item_id << LL_ENDL;
|
||||
|
||||
AttachmentsInfo attachment;
|
||||
attachment.mItemID = item_id;
|
||||
attachment.mAttachmentPt = attachment_pt;
|
||||
attachment.mAdd = add;
|
||||
|
||||
// [RLVa:KB] - Checked: 2010-09-23 (RLVa-1.2.1)
|
||||
if ( (rlv_handler_t::isEnabled()) && (!fRlvForce) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) )
|
||||
if ( (rlv_handler_t::isEnabled()) && (!fRlvForce) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) && (gAgentWearables.areInitialAttachmentsRequested()) )
|
||||
{
|
||||
const LLInventoryItem* pItem = gInventory.getItem(item_id);
|
||||
if (!pItem)
|
||||
@@ -78,6 +122,21 @@ void LLAttachmentsMgr::addAttachment(const LLUUID& item_id,
|
||||
// [/RLVa:KB]
|
||||
|
||||
mPendingAttachments.push_back(attachment);
|
||||
|
||||
mAttachmentRequests.addTime(item_id);
|
||||
}
|
||||
|
||||
void LLAttachmentsMgr::onAttachmentRequested(const LLUUID& item_id)
|
||||
{
|
||||
// [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2015-06-24 (Catznip-3.7)
|
||||
if (item_id.isNull())
|
||||
return;
|
||||
// [/SL:KB]
|
||||
|
||||
LLViewerInventoryItem *item = gInventory.getItem(item_id);
|
||||
LL_DEBUGS("Avatar") << "ATT attachment was requested "
|
||||
<< (item ? item->getName() : "UNKNOWN") << " id " << item_id << LL_ENDL;
|
||||
mAttachmentRequests.addTime(item_id);
|
||||
}
|
||||
|
||||
// static
|
||||
@@ -88,10 +147,55 @@ void LLAttachmentsMgr::onIdle(void *)
|
||||
|
||||
void LLAttachmentsMgr::onIdle()
|
||||
{
|
||||
if(!gAgent.getRegion())
|
||||
// Make sure we got a region before trying anything else
|
||||
if( !gAgent.getRegion() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
S32 obj_count = mPendingAttachments.size();
|
||||
if (LLApp::isExiting())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
requestPendingAttachments();
|
||||
|
||||
linkRecentlyArrivedAttachments();
|
||||
|
||||
expireOldAttachmentRequests();
|
||||
|
||||
expireOldDetachRequests();
|
||||
|
||||
// checkInvalidCOFLinks();
|
||||
|
||||
spamStatusInfo();
|
||||
}
|
||||
|
||||
void LLAttachmentsMgr::requestPendingAttachments()
|
||||
{
|
||||
if (mPendingAttachments.size())
|
||||
{
|
||||
requestAttachments(mPendingAttachments);
|
||||
}
|
||||
}
|
||||
|
||||
// Send request(s) for a group of attachments. As coded, this can
|
||||
// request at most 40 attachments and the rest will be
|
||||
// ignored. Currently the max attachments per avatar is 38, so the 40
|
||||
// limit should not be hit in practice.
|
||||
void LLAttachmentsMgr::requestAttachments(attachments_vec_t& attachment_requests)
|
||||
{
|
||||
// Make sure we got a region before trying anything else
|
||||
if( !gAgent.getRegion() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// For unknown reasons, requesting many attachments at once causes
|
||||
// frequent server-side failures. Here we're limiting the number
|
||||
// of attachments requested per idle loop.
|
||||
const S32 max_objects_per_request = 5;
|
||||
S32 obj_count = llmin((S32)attachment_requests.size(),max_objects_per_request);
|
||||
if (obj_count == 0)
|
||||
{
|
||||
return;
|
||||
@@ -103,18 +207,24 @@ void LLAttachmentsMgr::onIdle()
|
||||
const S32 MAX_OBJECTS_TO_SEND = MAX_PACKETS_TO_SEND * OBJECTS_PER_PACKET;
|
||||
if( obj_count > MAX_OBJECTS_TO_SEND )
|
||||
{
|
||||
LL_WARNS() << "ATT Too many attachments requested: " << obj_count
|
||||
<< " exceeds limit of " << MAX_OBJECTS_TO_SEND << LL_ENDL;
|
||||
|
||||
obj_count = MAX_OBJECTS_TO_SEND;
|
||||
}
|
||||
|
||||
LL_DEBUGS("Avatar") << "ATT [RezMultipleAttachmentsFromInv] attaching multiple from attachment_requests,"
|
||||
" total obj_count " << obj_count << LL_ENDL;
|
||||
|
||||
LLUUID compound_msg_id;
|
||||
compound_msg_id.generate();
|
||||
LLMessageSystem* msg = gMessageSystem;
|
||||
|
||||
// by construction above, obj_count <= attachment_requests.size(), so no
|
||||
// check against attachment_requests.empty() is needed.
|
||||
llassert(obj_count <= attachment_requests.size());
|
||||
|
||||
S32 i = 0;
|
||||
for (attachments_vec_t::const_iterator iter = mPendingAttachments.begin();
|
||||
iter != mPendingAttachments.end();
|
||||
++iter)
|
||||
for (S32 i=0; i<obj_count; i++)
|
||||
{
|
||||
if( 0 == (i % OBJECTS_PER_PACKET) )
|
||||
{
|
||||
@@ -129,32 +239,395 @@ void LLAttachmentsMgr::onIdle()
|
||||
msg->addBOOLFast(_PREHASH_FirstDetachAll, false );
|
||||
}
|
||||
|
||||
const AttachmentsInfo &attachment = (*iter);
|
||||
const AttachmentsInfo& attachment = attachment_requests.front();
|
||||
LLViewerInventoryItem* item = gInventory.getItem(attachment.mItemID);
|
||||
if (!item)
|
||||
if (item)
|
||||
{
|
||||
LL_INFOS() << "Attempted to add non-existant item ID:" << attachment.mItemID << LL_ENDL;
|
||||
continue;
|
||||
}
|
||||
S32 attachment_pt = attachment.mAttachmentPt;
|
||||
if (attachment.mAdd)
|
||||
attachment_pt |= ATTACHMENT_ADD;
|
||||
LL_DEBUGS("Avatar") << "ATT requesting from attachment_requests " << item->getName()
|
||||
<< " " << item->getLinkedUUID() << LL_ENDL;
|
||||
S32 attachment_pt = attachment.mAttachmentPt;
|
||||
if (attachment.mAdd)
|
||||
attachment_pt |= ATTACHMENT_ADD;
|
||||
|
||||
msg->nextBlockFast(_PREHASH_ObjectData );
|
||||
msg->addUUIDFast(_PREHASH_ItemID, item->getLinkedUUID());
|
||||
msg->addUUIDFast(_PREHASH_OwnerID, item->getPermissions().getOwner());
|
||||
msg->addU8Fast(_PREHASH_AttachmentPt, attachment_pt);
|
||||
pack_permissions_slam(msg, item->getFlags(), item->getPermissions());
|
||||
msg->addStringFast(_PREHASH_Name, item->getName());
|
||||
msg->addStringFast(_PREHASH_Description, item->getDescription());
|
||||
msg->nextBlockFast(_PREHASH_ObjectData );
|
||||
msg->addUUIDFast(_PREHASH_ItemID, item->getLinkedUUID());
|
||||
msg->addUUIDFast(_PREHASH_OwnerID, item->getPermissions().getOwner());
|
||||
msg->addU8Fast(_PREHASH_AttachmentPt, attachment_pt);
|
||||
pack_permissions_slam(msg, item->getFlags(), item->getPermissions());
|
||||
msg->addStringFast(_PREHASH_Name, item->getName());
|
||||
msg->addStringFast(_PREHASH_Description, item->getDescription());
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("Avatar") << "ATT Attempted to add non-existent item ID:" << attachment.mItemID << LL_ENDL;
|
||||
}
|
||||
|
||||
if( (i+1 == obj_count) || ((OBJECTS_PER_PACKET-1) == (i % OBJECTS_PER_PACKET)) )
|
||||
{
|
||||
// End of message chunk
|
||||
msg->sendReliable( gAgent.getRegion()->getHost() );
|
||||
}
|
||||
i++;
|
||||
attachment_requests.pop_front();
|
||||
}
|
||||
|
||||
mPendingAttachments.clear();
|
||||
}
|
||||
|
||||
void LLAttachmentsMgr::linkRecentlyArrivedAttachments()
|
||||
{
|
||||
if (mRecentlyArrivedAttachments.size())
|
||||
{
|
||||
// [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2015-06-24 (Catznip-3.7)
|
||||
if (!LLAppearanceMgr::instance().getAttachmentInvLinkEnable())
|
||||
{
|
||||
return;
|
||||
}
|
||||
// [/SL:KB]
|
||||
|
||||
// One or more attachments have arrived but have not yet been
|
||||
// processed for COF links
|
||||
if (mAttachmentRequests.empty())
|
||||
{
|
||||
// Not waiting for any more.
|
||||
LL_DEBUGS("Avatar") << "ATT all pending attachments have arrived after "
|
||||
<< mCOFLinkBatchTimer.getElapsedTimeF32() << " seconds" << LL_ENDL;
|
||||
}
|
||||
else if (mCOFLinkBatchTimer.getElapsedTimeF32() > COF_LINK_BATCH_TIME)
|
||||
{
|
||||
LL_DEBUGS("Avatar") << "ATT " << mAttachmentRequests.size()
|
||||
<< " pending attachments have not arrived, but wait time exceeded" << LL_ENDL;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
LL_DEBUGS("Avatar") << "ATT checking COF linkability for " << mRecentlyArrivedAttachments.size()
|
||||
<< " recently arrived items" << LL_ENDL;
|
||||
|
||||
uuid_vec_t ids_to_link;
|
||||
for (std::set<LLUUID>::iterator it = mRecentlyArrivedAttachments.begin();
|
||||
it != mRecentlyArrivedAttachments.end(); ++it)
|
||||
{
|
||||
if (isAgentAvatarValid() &&
|
||||
gAgentAvatarp->isWearingAttachment(*it) &&
|
||||
!LLAppearanceMgr::instance().isLinkedInCOF(*it))
|
||||
{
|
||||
LLUUID item_id = *it;
|
||||
LLViewerInventoryItem *item = gInventory.getItem(item_id);
|
||||
LL_DEBUGS("Avatar") << "ATT adding COF link for attachment "
|
||||
<< (item ? item->getName() : "UNKNOWN") << " " << item_id << LL_ENDL;
|
||||
ids_to_link.push_back(item_id);
|
||||
}
|
||||
}
|
||||
if (ids_to_link.size())
|
||||
{
|
||||
// [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2015-06-24 (Catznip-3.7)
|
||||
LLPointer<LLInventoryCallback> cb = new LLRegisterAttachmentCallback();
|
||||
for (const LLUUID& idAttach : ids_to_link)
|
||||
{
|
||||
if (std::find(mPendingAttachLinks.begin(), mPendingAttachLinks.end(), idAttach) == mPendingAttachLinks.end())
|
||||
{
|
||||
LLAppearanceMgr::instance().addCOFItemLink(idAttach, cb);
|
||||
mPendingAttachLinks.insert(idAttach);
|
||||
}
|
||||
}
|
||||
// [/SL:KB]
|
||||
// LLPointer<LLInventoryCallback> cb = new LLRequestServerAppearanceUpdateOnDestroy();
|
||||
// for (uuid_vec_t::const_iterator uuid_it = ids_to_link.begin();
|
||||
// uuid_it != ids_to_link.end(); ++uuid_it)
|
||||
// {
|
||||
// LLAppearanceMgr::instance().addCOFItemLink(*uuid_it, cb);
|
||||
// }
|
||||
}
|
||||
mRecentlyArrivedAttachments.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2010-09-18 (Catznip-2.2)
|
||||
bool LLAttachmentsMgr::getPendingAttachments(std::set<LLUUID>& ids) const
|
||||
{
|
||||
ids.clear();
|
||||
|
||||
// Returns the union of the LL maintained list of attachments that are waiting for link creation and our maintained list of attachments that are pending link creation
|
||||
set_union(mRecentlyArrivedAttachments.begin(), mRecentlyArrivedAttachments.end(), mPendingAttachLinks.begin(), mPendingAttachLinks.end(), std::inserter(ids, ids.begin()));
|
||||
|
||||
return !ids.empty();
|
||||
}
|
||||
|
||||
void LLAttachmentsMgr::clearPendingAttachmentLink(const LLUUID& idItem)
|
||||
{
|
||||
mPendingAttachLinks.erase(idItem);
|
||||
}
|
||||
|
||||
void LLAttachmentsMgr::onRegisterAttachmentComplete(const LLUUID& idAttachLink)
|
||||
{
|
||||
const LLViewerInventoryItem* pAttachLink = gInventory.getItem(idAttachLink);
|
||||
if (!pAttachLink)
|
||||
return;
|
||||
|
||||
const LLUUID& idAttachBase = pAttachLink->getLinkedUUID();
|
||||
|
||||
// Remove the attachment from the pending list
|
||||
clearPendingAttachmentLink(idAttachBase);
|
||||
|
||||
// It may have been detached already in which case we should remove the COF link
|
||||
if ( (isAgentAvatarValid()) && (!gAgentAvatarp->isWearingAttachment(idAttachBase)) )
|
||||
{
|
||||
LLAppearanceMgr::instance().removeCOFItemLinks(idAttachBase, NULL, true);
|
||||
}
|
||||
}
|
||||
// [/SL:KB]
|
||||
|
||||
LLAttachmentsMgr::LLItemRequestTimes::LLItemRequestTimes(const std::string& op_name, F32 timeout):
|
||||
mOpName(op_name),
|
||||
mTimeout(timeout)
|
||||
{
|
||||
}
|
||||
|
||||
void LLAttachmentsMgr::LLItemRequestTimes::addTime(const LLUUID& inv_item_id)
|
||||
{
|
||||
LLInventoryItem *item = gInventory.getItem(inv_item_id);
|
||||
LL_DEBUGS("Avatar") << "ATT " << mOpName << " adding request time " << (item ? item->getName() : "UNKNOWN") << " " << inv_item_id << LL_ENDL;
|
||||
LLTimer current_time;
|
||||
(*this)[inv_item_id] = current_time;
|
||||
}
|
||||
|
||||
void LLAttachmentsMgr::LLItemRequestTimes::removeTime(const LLUUID& inv_item_id)
|
||||
{
|
||||
LLInventoryItem *item = gInventory.getItem(inv_item_id);
|
||||
S32 remove_count = (*this).erase(inv_item_id);
|
||||
if (remove_count)
|
||||
{
|
||||
LL_DEBUGS("Avatar") << "ATT " << mOpName << " removing request time "
|
||||
<< (item ? item->getName() : "UNKNOWN") << " " << inv_item_id << LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL LLAttachmentsMgr::LLItemRequestTimes::getTime(const LLUUID& inv_item_id, LLTimer& timer) const
|
||||
{
|
||||
std::map<LLUUID,LLTimer>::const_iterator it = (*this).find(inv_item_id);
|
||||
if (it != (*this).end())
|
||||
{
|
||||
timer = it->second;
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL LLAttachmentsMgr::LLItemRequestTimes::wasRequestedRecently(const LLUUID& inv_item_id) const
|
||||
{
|
||||
LLTimer request_time;
|
||||
if (getTime(inv_item_id, request_time))
|
||||
{
|
||||
F32 request_time_elapsed = request_time.getElapsedTimeF32();
|
||||
return request_time_elapsed < mTimeout;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
// If we've been waiting for an attachment a long time, we want to
|
||||
// forget the request, because if the request is invalid (say the
|
||||
// object does not exist), the existence of a request that never goes
|
||||
// away will gum up the COF batch logic, causing it to always wait for
|
||||
// the timeout. Expiring a request means if the item does show up
|
||||
// late, the COF link request may not get properly batched up, but
|
||||
// behavior will be no worse than before we had the batching mechanism
|
||||
// in place; the COF link will still be created, but extra
|
||||
// requestServerAppearanceUpdate() calls may occur.
|
||||
void LLAttachmentsMgr::expireOldAttachmentRequests()
|
||||
{
|
||||
for (std::map<LLUUID,LLTimer>::iterator it = mAttachmentRequests.begin();
|
||||
it != mAttachmentRequests.end(); )
|
||||
{
|
||||
std::map<LLUUID,LLTimer>::iterator curr_it = it;
|
||||
++it;
|
||||
if (curr_it->second.getElapsedTimeF32() > MAX_ATTACHMENT_REQUEST_LIFETIME)
|
||||
{
|
||||
LLInventoryItem *item = gInventory.getItem(curr_it->first);
|
||||
LL_WARNS("Avatar") << "ATT expiring request for attachment "
|
||||
<< (item ? item->getName() : "UNKNOWN") << " item_id " << curr_it->first
|
||||
<< " after " << MAX_ATTACHMENT_REQUEST_LIFETIME << " seconds" << LL_ENDL;
|
||||
mAttachmentRequests.erase(curr_it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLAttachmentsMgr::expireOldDetachRequests()
|
||||
{
|
||||
for (std::map<LLUUID,LLTimer>::iterator it = mDetachRequests.begin();
|
||||
it != mDetachRequests.end(); )
|
||||
{
|
||||
std::map<LLUUID,LLTimer>::iterator curr_it = it;
|
||||
++it;
|
||||
if (curr_it->second.getElapsedTimeF32() > MAX_ATTACHMENT_REQUEST_LIFETIME)
|
||||
{
|
||||
LLInventoryItem *item = gInventory.getItem(curr_it->first);
|
||||
LL_WARNS("Avatar") << "ATT expiring request for detach "
|
||||
<< (item ? item->getName() : "UNKNOWN") << " item_id " << curr_it->first
|
||||
<< " after " << MAX_ATTACHMENT_REQUEST_LIFETIME << " seconds" << LL_ENDL;
|
||||
mDetachRequests.erase(curr_it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// When an attachment arrives, we want to stop waiting for it, and add
|
||||
// it to the set of recently arrived items.
|
||||
void LLAttachmentsMgr::onAttachmentArrived(const LLUUID& inv_item_id)
|
||||
{
|
||||
LLTimer timer;
|
||||
bool expected = mAttachmentRequests.getTime(inv_item_id, timer);
|
||||
if (!expected)
|
||||
{
|
||||
LLInventoryItem *item = gInventory.getItem(inv_item_id);
|
||||
LL_WARNS() << "ATT Attachment was unexpected or arrived after " << MAX_ATTACHMENT_REQUEST_LIFETIME << " seconds: "
|
||||
<< (item ? item->getName() : "UNKNOWN") << " id " << inv_item_id << LL_ENDL;
|
||||
}
|
||||
mAttachmentRequests.removeTime(inv_item_id);
|
||||
if (expected && mAttachmentRequests.empty())
|
||||
{
|
||||
// mAttachmentRequests just emptied out
|
||||
LL_DEBUGS("Avatar") << "ATT all active attachment requests have completed" << LL_ENDL;
|
||||
}
|
||||
if (mRecentlyArrivedAttachments.empty())
|
||||
{
|
||||
// Start the timer for sending off a COF link batch.
|
||||
mCOFLinkBatchTimer.reset();
|
||||
}
|
||||
mRecentlyArrivedAttachments.insert(inv_item_id);
|
||||
}
|
||||
|
||||
void LLAttachmentsMgr::onDetachRequested(const LLUUID& inv_item_id)
|
||||
{
|
||||
mDetachRequests.addTime(inv_item_id);
|
||||
}
|
||||
|
||||
void LLAttachmentsMgr::onDetachCompleted(const LLUUID& inv_item_id)
|
||||
{
|
||||
// [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2010-10-05 (Catznip-2.2)
|
||||
// (mRecentlyArrivedAttachments doesn't need pruning since it'll check the attachment is actually worn before linking)
|
||||
clearPendingAttachmentLink(inv_item_id);
|
||||
// [/SL:KB]
|
||||
|
||||
LLTimer timer;
|
||||
LLInventoryItem *item = gInventory.getItem(inv_item_id);
|
||||
if (mDetachRequests.getTime(inv_item_id, timer))
|
||||
{
|
||||
LL_DEBUGS("Avatar") << "ATT detach completed after " << timer.getElapsedTimeF32()
|
||||
<< " seconds for " << (item ? item->getName() : "UNKNOWN") << " " << inv_item_id << LL_ENDL;
|
||||
mDetachRequests.removeTime(inv_item_id);
|
||||
if (mDetachRequests.empty())
|
||||
{
|
||||
LL_DEBUGS("Avatar") << "ATT all detach requests have completed" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS() << "ATT unexpected detach for "
|
||||
<< (item ? item->getName() : "UNKNOWN") << " id " << inv_item_id << LL_ENDL;
|
||||
}
|
||||
|
||||
// LL_DEBUGS("Avatar") << "ATT detached item flagging as questionable for COF link checking "
|
||||
// << (item ? item->getName() : "UNKNOWN") << " id " << inv_item_id << LL_ENDL;
|
||||
// mQuestionableCOFLinks.addTime(inv_item_id);
|
||||
}
|
||||
|
||||
// Check for attachments that are (a) linked in COF and (b) not
|
||||
// attached to the avatar. This is a rotten function to have to
|
||||
// include, because it runs the risk of either repeatedly spamming out
|
||||
// COF link removals if they're failing for some reason, or getting
|
||||
// into a tug of war with some other sequence of events that's in the
|
||||
// process of adding the attachment in question. However, it's needed
|
||||
// because we have no definitive source of authority for what things
|
||||
// are actually supposed to be attached. Scripts, run on the server
|
||||
// side, can remove an attachment without our expecting it. If this
|
||||
// happens to an attachment that's just been added, then the COF link
|
||||
// creation may still be in flight, and we will have to delete the
|
||||
// link after it shows up.
|
||||
//
|
||||
// Note that we only flag items for possible link removal if they have
|
||||
// been previously detached. This means that an attachment failure
|
||||
// will leave the link in the COF, where it will hopefully resolve
|
||||
// correctly on relog.
|
||||
//
|
||||
// See related: MAINT-5070, MAINT-4409
|
||||
//
|
||||
//void LLAttachmentsMgr::checkInvalidCOFLinks()
|
||||
//{
|
||||
// LLInventoryModel::cat_array_t cat_array;
|
||||
// LLInventoryModel::item_array_t item_array;
|
||||
// gInventory.collectDescendents(LLAppearanceMgr::instance().getCOF(),
|
||||
// cat_array,item_array,LLInventoryModel::EXCLUDE_TRASH);
|
||||
// for (S32 i=0; i<item_array.size(); i++)
|
||||
// {
|
||||
// const LLViewerInventoryItem* inv_item = item_array.at(i).get();
|
||||
// const LLUUID& item_id = inv_item->getLinkedUUID();
|
||||
// if (inv_item->getType() == LLAssetType::AT_OBJECT)
|
||||
// {
|
||||
// LLTimer timer;
|
||||
// bool is_flagged_questionable = mQuestionableCOFLinks.getTime(item_id,timer);
|
||||
// bool is_wearing_attachment = isAgentAvatarValid() && gAgentAvatarp->isWearingAttachment(item_id);
|
||||
// if (is_wearing_attachment && is_flagged_questionable)
|
||||
// {
|
||||
// LL_DEBUGS("Avatar") << "ATT was flagged questionable but is now "
|
||||
// << (is_wearing_attachment ? "attached " : "")
|
||||
// <<"removing flag after "
|
||||
// << timer.getElapsedTimeF32() << " item "
|
||||
// << inv_item->getName() << " id " << item_id << LL_ENDL;
|
||||
// mQuestionableCOFLinks.removeTime(item_id);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// for(LLItemRequestTimes::iterator it = mQuestionableCOFLinks.begin();
|
||||
// it != mQuestionableCOFLinks.end(); )
|
||||
// {
|
||||
// LLItemRequestTimes::iterator curr_it = it;
|
||||
// ++it;
|
||||
// const LLUUID& item_id = curr_it->first;
|
||||
// LLViewerInventoryItem *inv_item = gInventory.getItem(item_id);
|
||||
// if (curr_it->second.getElapsedTimeF32() > MAX_BAD_COF_TIME)
|
||||
// {
|
||||
// if (LLAppearanceMgr::instance().isLinkedInCOF(item_id))
|
||||
// {
|
||||
// LL_DEBUGS("Avatar") << "ATT Linked in COF but not attached or requested, deleting link after "
|
||||
// << curr_it->second.getElapsedTimeF32() << " seconds for "
|
||||
// << (inv_item ? inv_item->getName() : "UNKNOWN") << " id " << item_id << LL_ENDL;
|
||||
// LLAppearanceMgr::instance().removeCOFItemLinks(item_id);
|
||||
// }
|
||||
// mQuestionableCOFLinks.erase(curr_it);
|
||||
// continue;
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
void LLAttachmentsMgr::spamStatusInfo()
|
||||
{
|
||||
#if 0
|
||||
static LLTimer spam_timer;
|
||||
const F32 spam_frequency = 100.0F;
|
||||
|
||||
if (spam_timer.getElapsedTimeF32() > spam_frequency)
|
||||
{
|
||||
spam_timer.reset();
|
||||
|
||||
LLInventoryModel::cat_array_t cat_array;
|
||||
LLInventoryModel::item_array_t item_array;
|
||||
gInventory.collectDescendents(LLAppearanceMgr::instance().getCOF(),
|
||||
cat_array,item_array,LLInventoryModel::EXCLUDE_TRASH);
|
||||
for (S32 i=0; i<item_array.size(); i++)
|
||||
{
|
||||
const LLViewerInventoryItem* inv_item = item_array.at(i).get();
|
||||
if (inv_item->getType() == LLAssetType::AT_OBJECT)
|
||||
{
|
||||
LL_DEBUGS("Avatar") << "item_id: " << inv_item->getUUID()
|
||||
<< " linked_item_id: " << inv_item->getLinkedUUID()
|
||||
<< " name: " << inv_item->getName()
|
||||
<< " parent: " << inv_item->getParentUUID()
|
||||
<< LL_ENDL;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -32,45 +32,120 @@
|
||||
|
||||
class LLViewerInventoryItem;
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//--------------------------------------------------------------------------------
|
||||
// LLAttachmentsMgr
|
||||
//
|
||||
// The sole purpose of this class is to take attachment
|
||||
// requests, queue them up, and send them all at once.
|
||||
// This handles situations where the viewer may request
|
||||
// a bunch of attachments at once in a short period of
|
||||
// time, where each of the requests would normally be
|
||||
// sent as a separate message versus being batched into
|
||||
// one single message.
|
||||
// This class manages batching up of requests at two stages of
|
||||
// attachment rezzing.
|
||||
//
|
||||
// The intent of this batching is to reduce viewer->server
|
||||
// traffic.
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// First, attachments requested to rez get saved in
|
||||
// mPendingAttachments and sent as a single
|
||||
// RezMultipleAttachmentsFromInv request. This batching is needed
|
||||
// mainly because of weaknessing the UI element->inventory item
|
||||
// handling, such that we don't always know when we are requesting
|
||||
// multiple items. Now they just pile up and get swept into a single
|
||||
// request during the idle loop.
|
||||
//
|
||||
// Second, after attachments arrive, we need to generate COF links for
|
||||
// them. There are both efficiency and UI correctness reasons why it
|
||||
// is better to request all the COF links at once and run a single
|
||||
// callback after they all complete. Given the vagaries of the
|
||||
// attachment system, there is no guarantee that we will get all the
|
||||
// attachments we ask for, but we frequently do. So in the common case
|
||||
// that all the desired attachments arrive fairly quickly, we generate
|
||||
// a single batched request for COF links. If attachments arrive late
|
||||
// or not at all, we will still issue COF link requests once a timeout
|
||||
// value has been exceeded.
|
||||
//
|
||||
// To handle attachments that never arrive, we forget about requests
|
||||
// that exceed a timeout value.
|
||||
//--------------------------------------------------------------------------------
|
||||
class LLAttachmentsMgr: public LLSingleton<LLAttachmentsMgr>
|
||||
{
|
||||
public:
|
||||
LLAttachmentsMgr();
|
||||
virtual ~LLAttachmentsMgr();
|
||||
|
||||
void addAttachment(const LLUUID& item_id,
|
||||
const U8 attachment_pt,
|
||||
// const BOOL add);
|
||||
// [RLVa:KB] - Checked: 2010-09-13 (RLVa-1.2.1c) | Added: RLVa-1.2.1c
|
||||
const BOOL add, const BOOL fRlvForce = FALSE);
|
||||
// [/RLVa:KB]
|
||||
static void onIdle(void *);
|
||||
protected:
|
||||
void onIdle();
|
||||
private:
|
||||
// Stores info for attachments that will be requested during idle.
|
||||
struct AttachmentsInfo
|
||||
{
|
||||
LLUUID mItemID;
|
||||
U8 mAttachmentPt;
|
||||
BOOL mAdd;
|
||||
};
|
||||
typedef std::deque<AttachmentsInfo> attachments_vec_t;
|
||||
|
||||
typedef std::vector<AttachmentsInfo> attachments_vec_t;
|
||||
LLAttachmentsMgr();
|
||||
virtual ~LLAttachmentsMgr();
|
||||
|
||||
// [RLVa:KB] - Checked: 2010-09-13 (RLVa-1.2.1)
|
||||
void addAttachmentRequest(const LLUUID& item_id,
|
||||
const U8 attachment_pt,
|
||||
const BOOL add, const BOOL fRlvForce = FALSE);
|
||||
// [/RLVa:KB]
|
||||
// void addAttachmentRequest(const LLUUID& item_id,
|
||||
// const U8 attachment_pt,
|
||||
// const BOOL add);
|
||||
void onAttachmentRequested(const LLUUID& item_id);
|
||||
void requestAttachments(attachments_vec_t& attachment_requests);
|
||||
static void onIdle(void *);
|
||||
|
||||
void onAttachmentArrived(const LLUUID& inv_item_id);
|
||||
|
||||
void onDetachRequested(const LLUUID& inv_item_id);
|
||||
void onDetachCompleted(const LLUUID& inv_item_id);
|
||||
|
||||
// [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2010-09-18 (Catznip-2.1)
|
||||
public:
|
||||
void clearPendingAttachmentLink(const LLUUID& idItem);
|
||||
bool getPendingAttachments(std::set<LLUUID>& ids) const;
|
||||
protected:
|
||||
void onRegisterAttachmentComplete(const LLUUID& idAttachLink);
|
||||
friend class LLRegisterAttachmentCallback;
|
||||
// [/SL:KB]
|
||||
|
||||
private:
|
||||
|
||||
class LLItemRequestTimes: public std::map<LLUUID,LLTimer>
|
||||
{
|
||||
public:
|
||||
LLItemRequestTimes(const std::string& op_name, F32 timeout);
|
||||
void addTime(const LLUUID& inv_item_id);
|
||||
void removeTime(const LLUUID& inv_item_id);
|
||||
BOOL wasRequestedRecently(const LLUUID& item_id) const;
|
||||
BOOL getTime(const LLUUID& inv_item_id, LLTimer& timer) const;
|
||||
|
||||
private:
|
||||
F32 mTimeout;
|
||||
std::string mOpName;
|
||||
};
|
||||
|
||||
void removeAttachmentRequestTime(const LLUUID& inv_item_id);
|
||||
void onIdle();
|
||||
void requestPendingAttachments();
|
||||
void linkRecentlyArrivedAttachments();
|
||||
void expireOldAttachmentRequests();
|
||||
void expireOldDetachRequests();
|
||||
// void checkInvalidCOFLinks();
|
||||
void spamStatusInfo();
|
||||
|
||||
// Attachments that we are planning to rez but haven't requested from the server yet.
|
||||
attachments_vec_t mPendingAttachments;
|
||||
|
||||
// Attachments that have been requested from server but have not arrived yet.
|
||||
LLItemRequestTimes mAttachmentRequests;
|
||||
|
||||
// Attachments that have been requested to detach but have not gone away yet.
|
||||
LLItemRequestTimes mDetachRequests;
|
||||
|
||||
// Attachments that have arrived but have not been linked in the COF yet.
|
||||
std::set<LLUUID> mRecentlyArrivedAttachments;
|
||||
LLTimer mCOFLinkBatchTimer;
|
||||
|
||||
// [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2010-09-18 (Catznip-2.1)
|
||||
// Attachments that have pending link creation
|
||||
std::set<LLUUID> mPendingAttachLinks;
|
||||
// [/SL:KB]
|
||||
|
||||
// // Attachments that are linked in the COF but may be invalid.
|
||||
// LLItemRequestTimes mQuestionableCOFLinks;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -5545,9 +5545,8 @@ bool confirm_attachment_rez(const LLSD& notification, const LLSD& response)
|
||||
U8 attachment_pt = notification["payload"]["attachment_point"].asInteger();
|
||||
BOOL is_add = notification["payload"]["is_add"].asBoolean();
|
||||
|
||||
LLAttachmentsMgr::instance().addAttachment(item_id,
|
||||
attachment_pt,
|
||||
is_add);
|
||||
LL_DEBUGS("Avatar") << "ATT calling addAttachmentRequest " << (itemp ? itemp->getName() : "UNKNOWN") << " id " << item_id << LL_ENDL;
|
||||
LLAttachmentsMgr::instance().addAttachmentRequest(item_id, attachment_pt, is_add);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
Reference in New Issue
Block a user