Merge
commit
9b64867d8b
1
.hgtags
1
.hgtags
|
|
@ -504,3 +504,4 @@ afd8d4756e8eda3c8f760625d1c17a2ad40ad6c8 3.7.27-release
|
|||
d07f76c5b9860fb87924d00ca729f7d4532534d6 3.7.29-release
|
||||
67edc442c80b8d2fadd2a6c4a7184b469906cdbf 3.7.30-release
|
||||
797ed69e6134ef48bb922577ab2540fb2d964668 3.8.0-release
|
||||
3f61ed662347dc7c6941b8266e72746a66d90e2a 3.8.1-release
|
||||
|
|
|
|||
|
|
@ -119,6 +119,7 @@ namespace {
|
|||
LL_INFOS() << "Error setting log file to " << filename << LL_ENDL;
|
||||
}
|
||||
mWantsTime = true;
|
||||
mWantsTags = true;
|
||||
}
|
||||
|
||||
~RecordToFile()
|
||||
|
|
@ -558,7 +559,7 @@ namespace LLError
|
|||
mFunctionString += std::string(mFunction) + ":";
|
||||
for (size_t i = 0; i < mTagCount; i++)
|
||||
{
|
||||
mTagString += std::string("#") + mTags[i] + ((i == mTagCount - 1) ? "" : " ");
|
||||
mTagString += std::string("#") + mTags[i] + ((i == mTagCount - 1) ? "" : ",");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -931,14 +932,19 @@ namespace
|
|||
}
|
||||
|
||||
if (show_level && r->wantsLevel())
|
||||
{
|
||||
message_stream << site.mLevelString << " ";
|
||||
}
|
||||
{
|
||||
message_stream << site.mLevelString;
|
||||
}
|
||||
|
||||
if (show_tags && r->wantsTags())
|
||||
{
|
||||
message_stream << site.mTagString << " ";
|
||||
message_stream << site.mTagString;
|
||||
}
|
||||
if ((show_level && r->wantsLevel())||
|
||||
(show_tags && r->wantsTags()))
|
||||
{
|
||||
message_stream << " ";
|
||||
}
|
||||
|
||||
if (show_function && r->wantsFunctionName())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
3.8.1
|
||||
3.8.2
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include "llviewerprecompiledheaders.h"
|
||||
#include "llagentwearables.h"
|
||||
|
||||
#include "llattachmentsmgr.h"
|
||||
#include "llaccordionctrltab.h"
|
||||
#include "llagent.h"
|
||||
#include "llagentcamera.h"
|
||||
|
|
@ -1353,6 +1354,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());
|
||||
|
|
@ -1366,6 +1368,10 @@ void LLAgentWearables::userRemoveMultipleAttachments(llvo_vec_t& objects_to_remo
|
|||
//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());
|
||||
}
|
||||
|
|
@ -1374,51 +1380,18 @@ void LLAgentWearables::userAttachMultipleAttachments(LLInventoryModel::item_arra
|
|||
{
|
||||
// Build a compound message to send all the objects that need to be rezzed.
|
||||
S32 obj_count = obj_item_array.size();
|
||||
|
||||
// Limit number of packets to send
|
||||
const S32 MAX_PACKETS_TO_SEND = 10;
|
||||
const S32 OBJECTS_PER_PACKET = 4;
|
||||
const S32 MAX_OBJECTS_TO_SEND = MAX_PACKETS_TO_SEND * OBJECTS_PER_PACKET;
|
||||
if( obj_count > MAX_OBJECTS_TO_SEND )
|
||||
if (obj_count > 0)
|
||||
{
|
||||
obj_count = MAX_OBJECTS_TO_SEND;
|
||||
LL_DEBUGS("Avatar") << "ATT attaching multiple, total obj_count " << obj_count << LL_ENDL;
|
||||
}
|
||||
|
||||
// Create an id to keep the parts of the compound message together
|
||||
LLUUID compound_msg_id;
|
||||
compound_msg_id.generate();
|
||||
LLMessageSystem* msg = gMessageSystem;
|
||||
|
||||
for(S32 i = 0; i < obj_count; ++i)
|
||||
{
|
||||
if( 0 == (i % OBJECTS_PER_PACKET) )
|
||||
{
|
||||
// Start a new message chunk
|
||||
msg->newMessageFast(_PREHASH_RezMultipleAttachmentsFromInv);
|
||||
msg->nextBlockFast(_PREHASH_AgentData);
|
||||
msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
|
||||
msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
|
||||
msg->nextBlockFast(_PREHASH_HeaderData);
|
||||
msg->addUUIDFast(_PREHASH_CompoundMsgID, compound_msg_id );
|
||||
msg->addU8Fast(_PREHASH_TotalObjects, obj_count );
|
||||
msg->addBOOLFast(_PREHASH_FirstDetachAll, false );
|
||||
}
|
||||
|
||||
const LLInventoryItem* item = obj_item_array.at(i).get();
|
||||
msg->nextBlockFast(_PREHASH_ObjectData );
|
||||
msg->addUUIDFast(_PREHASH_ItemID, item->getLinkedUUID());
|
||||
msg->addUUIDFast(_PREHASH_OwnerID, item->getPermissions().getOwner());
|
||||
msg->addU8Fast(_PREHASH_AttachmentPt, 0 | ATTACHMENT_ADD); // Wear at the previous or default attachment point
|
||||
pack_permissions_slam(msg, item->getFlags(), item->getPermissions());
|
||||
msg->addStringFast(_PREHASH_Name, item->getName());
|
||||
msg->addStringFast(_PREHASH_Description, item->getDescription());
|
||||
|
||||
if( (i+1 == obj_count) || ((OBJECTS_PER_PACKET-1) == (i % OBJECTS_PER_PACKET)) )
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
// Returns false if the given wearable is already topmost/bottommost
|
||||
|
|
|
|||
|
|
@ -528,6 +528,15 @@ LLUpdateAppearanceAndEditWearableOnDestroy::LLUpdateAppearanceAndEditWearableOnD
|
|||
{
|
||||
}
|
||||
|
||||
LLRequestServerAppearanceUpdateOnDestroy::~LLRequestServerAppearanceUpdateOnDestroy()
|
||||
{
|
||||
LL_DEBUGS("Avatar") << "ATT requesting server appearance update" << LL_ENDL;
|
||||
if (!LLApp::isExiting())
|
||||
{
|
||||
LLAppearanceMgr::instance().requestServerAppearanceUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
void edit_wearable_and_customize_avatar(LLUUID item_id)
|
||||
{
|
||||
// Start editing the item if previously requested.
|
||||
|
|
@ -831,6 +840,12 @@ void LLWearableHoldingPattern::onAllComplete()
|
|||
// pre-attachment states.
|
||||
gAgentAvatarp->clearAttachmentPosOverrides();
|
||||
|
||||
if (objects_to_remove.size() || items_to_add.size())
|
||||
{
|
||||
LL_DEBUGS("Avatar") << "ATT will remove " << objects_to_remove.size()
|
||||
<< " and add " << items_to_add.size() << " items" << LL_ENDL;
|
||||
}
|
||||
|
||||
// Take off the attachments that will no longer be in the outfit.
|
||||
LLAgentWearables::userRemoveMultipleAttachments(objects_to_remove);
|
||||
|
||||
|
|
@ -1361,28 +1376,46 @@ void LLAppearanceMgr::wearItemsOnAvatar(const uuid_vec_t& item_ids_to_wear,
|
|||
|
||||
const LLUUID& item_id_to_wear = *it;
|
||||
|
||||
if (item_id_to_wear.isNull()) continue;
|
||||
if (item_id_to_wear.isNull())
|
||||
{
|
||||
LL_DEBUGS("Avatar") << "null id " << item_id_to_wear << LL_ENDL;
|
||||
continue;
|
||||
}
|
||||
|
||||
LLViewerInventoryItem* item_to_wear = gInventory.getItem(item_id_to_wear);
|
||||
if (!item_to_wear) continue;
|
||||
if (!item_to_wear)
|
||||
{
|
||||
LL_DEBUGS("Avatar") << "inventory item not found for id " << item_id_to_wear << LL_ENDL;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (gInventory.isObjectDescendentOf(item_to_wear->getUUID(), gInventory.getLibraryRootFolderID()))
|
||||
{
|
||||
LL_DEBUGS("Avatar") << "inventory item in library, will copy and wear "
|
||||
<< item_to_wear->getName() << " id " << item_id_to_wear << LL_ENDL;
|
||||
LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(wear_on_avatar_cb,_1,replace));
|
||||
copy_inventory_item(gAgent.getID(), item_to_wear->getPermissions().getOwner(), item_to_wear->getUUID(), LLUUID::null, std::string(), cb);
|
||||
copy_inventory_item(gAgent.getID(), item_to_wear->getPermissions().getOwner(),
|
||||
item_to_wear->getUUID(), LLUUID::null, std::string(), cb);
|
||||
continue;
|
||||
}
|
||||
else if (!gInventory.isObjectDescendentOf(item_to_wear->getUUID(), gInventory.getRootFolderID()))
|
||||
{
|
||||
continue; // not in library and not in agent's inventory
|
||||
// not in library and not in agent's inventory
|
||||
LL_DEBUGS("Avatar") << "inventory item not in user inventory or library, skipping "
|
||||
<< item_to_wear->getName() << " id " << item_id_to_wear << LL_ENDL;
|
||||
continue;
|
||||
}
|
||||
else if (gInventory.isObjectDescendentOf(item_to_wear->getUUID(), gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH)))
|
||||
{
|
||||
LLNotificationsUtil::add("CannotWearTrash");
|
||||
LL_DEBUGS("Avatar") << "inventory item is in trash, skipping "
|
||||
<< item_to_wear->getName() << " id " << item_id_to_wear << LL_ENDL;
|
||||
continue;
|
||||
}
|
||||
else if (isLinkedInCOF(item_to_wear->getUUID())) // EXT-84911
|
||||
{
|
||||
LL_DEBUGS("Avatar") << "inventory item is already in COF, skipping "
|
||||
<< item_to_wear->getName() << " id " << item_id_to_wear << LL_ENDL;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -2716,28 +2749,23 @@ void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item,
|
|||
|
||||
LLInventoryModel::item_array_t LLAppearanceMgr::findCOFItemLinks(const LLUUID& item_id)
|
||||
{
|
||||
|
||||
LLInventoryModel::item_array_t result;
|
||||
const LLViewerInventoryItem *vitem =
|
||||
dynamic_cast<const LLViewerInventoryItem*>(gInventory.getItem(item_id));
|
||||
|
||||
if (vitem)
|
||||
{
|
||||
LLInventoryModel::cat_array_t cat_array;
|
||||
LLInventoryModel::item_array_t item_array;
|
||||
gInventory.collectDescendents(LLAppearanceMgr::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->getLinkedUUID() == vitem->getLinkedUUID())
|
||||
{
|
||||
result.push_back(item_array.at(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
LLUUID linked_id = gInventory.getLinkedItemID(item_id);
|
||||
LLInventoryModel::cat_array_t cat_array;
|
||||
LLInventoryModel::item_array_t item_array;
|
||||
gInventory.collectDescendents(LLAppearanceMgr::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->getLinkedUUID() == linked_id)
|
||||
{
|
||||
result.push_back(item_array.at(i));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -3616,6 +3644,11 @@ void LLAppearanceMgr::removeItemsFromAvatar(const uuid_vec_t& ids_to_remove)
|
|||
{
|
||||
const LLUUID& id_to_remove = *it;
|
||||
const LLUUID& linked_item_id = gInventory.getLinkedItemID(id_to_remove);
|
||||
LLViewerInventoryItem *item = gInventory.getItem(linked_item_id);
|
||||
if (item && item->getType() == LLAssetType::AT_OBJECT)
|
||||
{
|
||||
LL_DEBUGS("Avatar") << "ATT removing attachment " << item->getName() << " id " << item->getUUID() << LL_ENDL;
|
||||
}
|
||||
removeCOFItemLinks(linked_item_id, cb);
|
||||
addDoomedTempAttachment(linked_item_id);
|
||||
}
|
||||
|
|
@ -3623,10 +3656,9 @@ void LLAppearanceMgr::removeItemsFromAvatar(const uuid_vec_t& ids_to_remove)
|
|||
|
||||
void LLAppearanceMgr::removeItemFromAvatar(const LLUUID& id_to_remove)
|
||||
{
|
||||
LLUUID linked_item_id = gInventory.getLinkedItemID(id_to_remove);
|
||||
LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy;
|
||||
removeCOFItemLinks(linked_item_id, cb);
|
||||
addDoomedTempAttachment(linked_item_id);
|
||||
uuid_vec_t ids_to_remove;
|
||||
ids_to_remove.push_back(id_to_remove);
|
||||
removeItemsFromAvatar(ids_to_remove);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -3814,37 +3846,32 @@ void dumpAttachmentSet(const std::set<LLUUID>& atts, const std::string& msg)
|
|||
|
||||
void LLAppearanceMgr::registerAttachment(const LLUUID& item_id)
|
||||
{
|
||||
gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id);
|
||||
LLViewerInventoryItem *item = gInventory.getItem(item_id);
|
||||
LL_DEBUGS("Avatar") << "ATT registering attachment "
|
||||
<< (item ? item->getName() : "UNKNOWN") << " " << item_id << LL_ENDL;
|
||||
gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id);
|
||||
|
||||
if (mAttachmentInvLinkEnabled)
|
||||
{
|
||||
// we have to pass do_update = true to call LLAppearanceMgr::updateAppearanceFromCOF.
|
||||
// it will trigger gAgentWariables.notifyLoadingFinished()
|
||||
// But it is not acceptable solution. See EXT-7777
|
||||
if (!isLinkedInCOF(item_id))
|
||||
{
|
||||
LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy();
|
||||
LLAppearanceMgr::addCOFItemLink(item_id, cb); // Add COF link for item.
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//LL_INFOS() << "no link changes, inv link not enabled" << LL_ENDL;
|
||||
}
|
||||
LLAttachmentsMgr::instance().onAttachmentArrived(item_id);
|
||||
}
|
||||
|
||||
void LLAppearanceMgr::unregisterAttachment(const LLUUID& item_id)
|
||||
{
|
||||
gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id);
|
||||
LLViewerInventoryItem *item = gInventory.getItem(item_id);
|
||||
LL_DEBUGS("Avatar") << "ATT unregistering attachment "
|
||||
<< (item ? item->getName() : "UNKNOWN") << " " << item_id << LL_ENDL;
|
||||
gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id);
|
||||
|
||||
if (mAttachmentInvLinkEnabled)
|
||||
{
|
||||
LLAppearanceMgr::removeCOFItemLinks(item_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
//LL_INFOS() << "no link changes, inv link not enabled" << LL_ENDL;
|
||||
}
|
||||
LLAttachmentsMgr::instance().onDetachCompleted(item_id);
|
||||
if (mAttachmentInvLinkEnabled && isLinkedInCOF(item_id))
|
||||
{
|
||||
LL_DEBUGS("Avatar") << "ATT removing COF link for attachment "
|
||||
<< (item ? item->getName() : "UNKNOWN") << " " << item_id << LL_ENDL;
|
||||
LLAppearanceMgr::removeCOFItemLinks(item_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
//LL_INFOS() << "no link changes, inv link not enabled" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL LLAppearanceMgr::getIsInCOF(const LLUUID& obj_id) const
|
||||
|
|
@ -3858,14 +3885,6 @@ BOOL LLAppearanceMgr::getIsInCOF(const LLUUID& obj_id) const
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
// static
|
||||
bool LLAppearanceMgr::isLinkInCOF(const LLUUID& obj_id)
|
||||
{
|
||||
const LLUUID& target_id = gInventory.getLinkedItemID(obj_id);
|
||||
LLLinkedItemIDMatches find_links(target_id);
|
||||
return gInventory.hasMatchingDirectDescendent(LLAppearanceMgr::instance().getCOF(), find_links);
|
||||
}
|
||||
|
||||
BOOL LLAppearanceMgr::getIsProtectedCOFItem(const LLUUID& obj_id) const
|
||||
{
|
||||
if (!getIsInCOF(obj_id)) return FALSE;
|
||||
|
|
@ -3984,10 +4003,56 @@ void callAfterCategoryFetch(const LLUUID& cat_id, nullary_func_t cb)
|
|||
}
|
||||
}
|
||||
|
||||
void add_wearable_type_counts(const uuid_vec_t& ids,
|
||||
S32& clothing_count,
|
||||
S32& bodypart_count,
|
||||
S32& object_count,
|
||||
S32& other_count)
|
||||
{
|
||||
for (uuid_vec_t::const_iterator it = ids.begin(); it != ids.end(); ++it)
|
||||
{
|
||||
const LLUUID& item_id_to_wear = *it;
|
||||
LLViewerInventoryItem* item_to_wear = gInventory.getItem(item_id_to_wear);
|
||||
if (item_to_wear)
|
||||
{
|
||||
if (item_to_wear->getType() == LLAssetType::AT_CLOTHING)
|
||||
{
|
||||
clothing_count++;
|
||||
}
|
||||
else if (item_to_wear->getType() == LLAssetType::AT_BODYPART)
|
||||
{
|
||||
bodypart_count++;
|
||||
}
|
||||
else if (item_to_wear->getType() == LLAssetType::AT_OBJECT)
|
||||
{
|
||||
object_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
other_count++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
other_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void wear_multiple(const uuid_vec_t& ids, bool replace)
|
||||
{
|
||||
LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy;
|
||||
LLAppearanceMgr::instance().wearItemsOnAvatar(ids, false, replace, cb);
|
||||
S32 clothing_count = 0;
|
||||
S32 bodypart_count = 0;
|
||||
S32 object_count = 0;
|
||||
S32 other_count = 0;
|
||||
add_wearable_type_counts(ids, clothing_count, bodypart_count, object_count, other_count);
|
||||
|
||||
LLPointer<LLInventoryCallback> cb = NULL;
|
||||
if (clothing_count > 0 || bodypart_count > 0)
|
||||
{
|
||||
cb = new LLUpdateAppearanceOnDestroy;
|
||||
}
|
||||
LLAppearanceMgr::instance().wearItemsOnAvatar(ids, true, replace, cb);
|
||||
}
|
||||
|
||||
// SLapp for easy-wearing of a stock (library) avatar
|
||||
|
|
|
|||
|
|
@ -285,11 +285,6 @@ public:
|
|||
BOOL getIsInCOF(const LLUUID& obj_id) const;
|
||||
// Is this in the COF and can the user delete it from the COF?
|
||||
BOOL getIsProtectedCOFItem(const LLUUID& obj_id) const;
|
||||
|
||||
/**
|
||||
* Checks if COF contains link to specified object.
|
||||
*/
|
||||
static bool isLinkInCOF(const LLUUID& obj_id);
|
||||
};
|
||||
|
||||
class LLUpdateAppearanceOnDestroy: public LLInventoryCallback
|
||||
|
|
@ -321,6 +316,15 @@ private:
|
|||
LLUUID mItemID;
|
||||
};
|
||||
|
||||
class LLRequestServerAppearanceUpdateOnDestroy: public LLInventoryCallback
|
||||
{
|
||||
public:
|
||||
LLRequestServerAppearanceUpdateOnDestroy() {}
|
||||
~LLRequestServerAppearanceUpdateOnDestroy();
|
||||
|
||||
/* virtual */ void fire(const LLUUID& item_id) {}
|
||||
};
|
||||
|
||||
LLUUID findDescendentCategoryIDByName(const LLUUID& parent_id,const std::string& name);
|
||||
|
||||
// Invoke a given callable after category contents are fully fetched.
|
||||
|
|
|
|||
|
|
@ -27,15 +27,24 @@
|
|||
#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"
|
||||
#include "llviewerregion.h"
|
||||
#include "message.h"
|
||||
|
||||
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;
|
||||
|
||||
LLAttachmentsMgr::LLAttachmentsMgr()
|
||||
LLAttachmentsMgr::LLAttachmentsMgr():
|
||||
mAttachmentRequests("attach",MIN_RETRY_REQUEST_TIME),
|
||||
mDetachRequests("detach",MIN_RETRY_REQUEST_TIME),
|
||||
mQuestionableCOFLinks("badcof",MAX_BAD_COF_TIME)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -43,15 +52,37 @@ LLAttachmentsMgr::~LLAttachmentsMgr()
|
|||
{
|
||||
}
|
||||
|
||||
void LLAttachmentsMgr::addAttachment(const LLUUID& item_id,
|
||||
const U8 attachment_pt,
|
||||
const BOOL add)
|
||||
void LLAttachmentsMgr::addAttachmentRequest(const LLUUID& item_id,
|
||||
const U8 attachment_pt,
|
||||
const BOOL add)
|
||||
{
|
||||
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;
|
||||
mPendingAttachments.push_back(attachment);
|
||||
|
||||
mAttachmentRequests.addTime(item_id);
|
||||
}
|
||||
|
||||
void LLAttachmentsMgr::onAttachmentRequested(const LLUUID& item_id)
|
||||
{
|
||||
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
|
||||
|
|
@ -68,31 +99,79 @@ void LLAttachmentsMgr::onIdle()
|
|||
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;
|
||||
}
|
||||
|
||||
|
||||
// Limit number of packets to send
|
||||
const S32 MAX_PACKETS_TO_SEND = 10;
|
||||
const S32 OBJECTS_PER_PACKET = 4;
|
||||
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;
|
||||
|
||||
|
||||
S32 i = 0;
|
||||
for (attachments_vec_t::const_iterator iter = mPendingAttachments.begin();
|
||||
iter != mPendingAttachments.end();
|
||||
++iter)
|
||||
{
|
||||
// by construction above, obj_count <= attachment_requests.size(), so no
|
||||
// check against attachment_requests.empty() is needed.
|
||||
llassert(obj_count <= attachment_requests.size());
|
||||
|
||||
for (S32 i=0; i<obj_count; i++)
|
||||
{
|
||||
if( 0 == (i % OBJECTS_PER_PACKET) )
|
||||
{
|
||||
// Start a new message chunk
|
||||
|
|
@ -106,32 +185,337 @@ 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_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());
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_INFOS() << "Attempted to add non-existant item ID:" << attachment.mItemID << LL_ENDL;
|
||||
continue;
|
||||
LL_WARNS("Avatar") << "ATT Attempted to add non-existent item ID:" << attachment.mItemID << 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());
|
||||
|
||||
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())
|
||||
{
|
||||
// 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())
|
||||
{
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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,42 +32,101 @@
|
|||
|
||||
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.
|
||||
//
|
||||
// The intent of this batching is to reduce viewer->server
|
||||
// traffic.
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// This class manages batching up of requests at two stages of
|
||||
// attachment rezzing.
|
||||
//
|
||||
// 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);
|
||||
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();
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
|
||||
// Attachments that are linked in the COF but may be invalid.
|
||||
LLItemRequestTimes mQuestionableCOFLinks;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -59,10 +59,6 @@
|
|||
// Longest time, in seconds, to wait for all animations to stop playing
|
||||
const F32 MAX_WAIT_ANIM_SECS = 30.f;
|
||||
|
||||
// If this gesture is a link, get the base gesture that this link points to,
|
||||
// otherwise just return this id.
|
||||
static const LLUUID& get_linked_uuid(const LLUUID& item_id);
|
||||
|
||||
// Lightweight constructor.
|
||||
// init() does the heavy lifting.
|
||||
LLGestureMgr::LLGestureMgr()
|
||||
|
|
@ -253,7 +249,7 @@ void LLGestureMgr::activateGestureWithAsset(const LLUUID& item_id,
|
|||
BOOL inform_server,
|
||||
BOOL deactivate_similar)
|
||||
{
|
||||
const LLUUID& base_item_id = get_linked_uuid(item_id);
|
||||
const LLUUID& base_item_id = gInventory.getLinkedItemID(item_id);
|
||||
|
||||
if( !gAssetStorage )
|
||||
{
|
||||
|
|
@ -307,7 +303,7 @@ void notify_update_label(const LLUUID& base_item_id)
|
|||
|
||||
void LLGestureMgr::deactivateGesture(const LLUUID& item_id)
|
||||
{
|
||||
const LLUUID& base_item_id = get_linked_uuid(item_id);
|
||||
const LLUUID& base_item_id = gInventory.getLinkedItemID(item_id);
|
||||
item_map_t::iterator it = mActive.find(base_item_id);
|
||||
if (it == mActive.end())
|
||||
{
|
||||
|
|
@ -353,7 +349,7 @@ void LLGestureMgr::deactivateGesture(const LLUUID& item_id)
|
|||
|
||||
void LLGestureMgr::deactivateSimilarGestures(LLMultiGesture* in, const LLUUID& in_item_id)
|
||||
{
|
||||
const LLUUID& base_in_item_id = get_linked_uuid(in_item_id);
|
||||
const LLUUID& base_in_item_id = gInventory.getLinkedItemID(in_item_id);
|
||||
uuid_vec_t gest_item_ids;
|
||||
|
||||
// Deactivate all gestures that match
|
||||
|
|
@ -440,7 +436,7 @@ void LLGestureMgr::deactivateSimilarGestures(LLMultiGesture* in, const LLUUID& i
|
|||
|
||||
BOOL LLGestureMgr::isGestureActive(const LLUUID& item_id)
|
||||
{
|
||||
const LLUUID& base_item_id = get_linked_uuid(item_id);
|
||||
const LLUUID& base_item_id = gInventory.getLinkedItemID(item_id);
|
||||
item_map_t::iterator it = mActive.find(base_item_id);
|
||||
return (it != mActive.end());
|
||||
}
|
||||
|
|
@ -448,7 +444,7 @@ BOOL LLGestureMgr::isGestureActive(const LLUUID& item_id)
|
|||
|
||||
BOOL LLGestureMgr::isGesturePlaying(const LLUUID& item_id)
|
||||
{
|
||||
const LLUUID& base_item_id = get_linked_uuid(item_id);
|
||||
const LLUUID& base_item_id = gInventory.getLinkedItemID(item_id);
|
||||
|
||||
item_map_t::iterator it = mActive.find(base_item_id);
|
||||
if (it == mActive.end()) return FALSE;
|
||||
|
|
@ -471,7 +467,7 @@ BOOL LLGestureMgr::isGesturePlaying(LLMultiGesture* gesture)
|
|||
|
||||
void LLGestureMgr::replaceGesture(const LLUUID& item_id, LLMultiGesture* new_gesture, const LLUUID& asset_id)
|
||||
{
|
||||
const LLUUID& base_item_id = get_linked_uuid(item_id);
|
||||
const LLUUID& base_item_id = gInventory.getLinkedItemID(item_id);
|
||||
|
||||
item_map_t::iterator it = mActive.find(base_item_id);
|
||||
if (it == mActive.end())
|
||||
|
|
@ -513,7 +509,7 @@ void LLGestureMgr::replaceGesture(const LLUUID& item_id, LLMultiGesture* new_ges
|
|||
|
||||
void LLGestureMgr::replaceGesture(const LLUUID& item_id, const LLUUID& new_asset_id)
|
||||
{
|
||||
const LLUUID& base_item_id = get_linked_uuid(item_id);
|
||||
const LLUUID& base_item_id = gInventory.getLinkedItemID(item_id);
|
||||
|
||||
item_map_t::iterator it = LLGestureMgr::instance().mActive.find(base_item_id);
|
||||
if (it == mActive.end())
|
||||
|
|
@ -608,7 +604,7 @@ void LLGestureMgr::playGesture(LLMultiGesture* gesture)
|
|||
// Convenience function that looks up the item_id for you.
|
||||
void LLGestureMgr::playGesture(const LLUUID& item_id)
|
||||
{
|
||||
const LLUUID& base_item_id = get_linked_uuid(item_id);
|
||||
const LLUUID& base_item_id = gInventory.getLinkedItemID(item_id);
|
||||
|
||||
item_map_t::iterator it = mActive.find(base_item_id);
|
||||
if (it == mActive.end()) return;
|
||||
|
|
@ -1297,7 +1293,7 @@ void LLGestureMgr::stopGesture(LLMultiGesture* gesture)
|
|||
|
||||
void LLGestureMgr::stopGesture(const LLUUID& item_id)
|
||||
{
|
||||
const LLUUID& base_item_id = get_linked_uuid(item_id);
|
||||
const LLUUID& base_item_id = gInventory.getLinkedItemID(item_id);
|
||||
|
||||
item_map_t::iterator it = mActive.find(base_item_id);
|
||||
if (it == mActive.end()) return;
|
||||
|
|
@ -1457,14 +1453,4 @@ void LLGestureMgr::done()
|
|||
}
|
||||
}
|
||||
|
||||
// static
|
||||
const LLUUID& get_linked_uuid(const LLUUID &item_id)
|
||||
{
|
||||
LLViewerInventoryItem* item = gInventory.getItem(item_id);
|
||||
if (item && item->getIsLinkType())
|
||||
{
|
||||
return item->getLinkedUUID();
|
||||
}
|
||||
return item_id;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5434,13 +5434,11 @@ void rez_attachment(LLViewerInventoryItem* item, LLViewerJointAttachment* attach
|
|||
|
||||
// Check for duplicate request.
|
||||
if (isAgentAvatarValid() &&
|
||||
(gAgentAvatarp->attachmentWasRequested(item_id) ||
|
||||
gAgentAvatarp->isWearingAttachment(item_id)))
|
||||
gAgentAvatarp->isWearingAttachment(item_id))
|
||||
{
|
||||
LL_WARNS() << "duplicate attachment request, ignoring" << LL_ENDL;
|
||||
LL_WARNS() << "ATT duplicate attachment request, ignoring" << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
gAgentAvatarp->addAttachmentRequest(item_id);
|
||||
|
||||
S32 attach_pt = 0;
|
||||
if (isAgentAvatarValid() && attachment)
|
||||
|
|
@ -5490,36 +5488,14 @@ bool confirm_attachment_rez(const LLSD& notification, const LLSD& response)
|
|||
|
||||
if (itemp)
|
||||
{
|
||||
/*
|
||||
{
|
||||
U8 attachment_pt = notification["payload"]["attachment_point"].asInteger();
|
||||
|
||||
LLMessageSystem* msg = gMessageSystem;
|
||||
msg->newMessageFast(_PREHASH_RezSingleAttachmentFromInv);
|
||||
msg->nextBlockFast(_PREHASH_AgentData);
|
||||
msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
|
||||
msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
|
||||
msg->nextBlockFast(_PREHASH_ObjectData);
|
||||
msg->addUUIDFast(_PREHASH_ItemID, itemp->getUUID());
|
||||
msg->addUUIDFast(_PREHASH_OwnerID, itemp->getPermissions().getOwner());
|
||||
msg->addU8Fast(_PREHASH_AttachmentPt, attachment_pt);
|
||||
pack_permissions_slam(msg, itemp->getFlags(), itemp->getPermissions());
|
||||
msg->addStringFast(_PREHASH_Name, itemp->getName());
|
||||
msg->addStringFast(_PREHASH_Description, itemp->getDescription());
|
||||
msg->sendReliable(gAgent.getRegion()->getHost());
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
|
||||
// Queue up attachments to be sent in next idle tick, this way the
|
||||
// attachments are batched up all into one message versus each attachment
|
||||
// being sent in its own separate attachments message.
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -690,6 +690,12 @@ void hide_context_entries(LLMenuGL& menu,
|
|||
const menuentry_vec_t &entries_to_show,
|
||||
const menuentry_vec_t &disabled_entries);
|
||||
|
||||
// Helper functions to classify actions.
|
||||
bool isAddAction(const std::string& action);
|
||||
bool isRemoveAction(const std::string& action);
|
||||
bool isMarketplaceCopyAction(const std::string& action);
|
||||
bool isMarketplaceSendAction(const std::string& action);
|
||||
|
||||
class LLFolderViewGroupedItemBridge: public LLFolderViewGroupedItemModel
|
||||
{
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -231,7 +231,7 @@ BOOL get_is_item_worn(const LLUUID& id)
|
|||
return FALSE;
|
||||
|
||||
// Consider the item as worn if it has links in COF.
|
||||
if (LLAppearanceMgr::instance().isLinkInCOF(id))
|
||||
if (LLAppearanceMgr::instance().isLinkedInCOF(id))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
|
@ -265,7 +265,7 @@ BOOL get_can_item_be_worn(const LLUUID& id)
|
|||
if (!item)
|
||||
return FALSE;
|
||||
|
||||
if (LLAppearanceMgr::isLinkInCOF(item->getLinkedUUID()))
|
||||
if (LLAppearanceMgr::instance().isLinkedInCOF(item->getLinkedUUID()))
|
||||
{
|
||||
// an item having links in COF (i.e. a worn item)
|
||||
return FALSE;
|
||||
|
|
@ -1061,6 +1061,34 @@ void LLOpenFoldersWithSelection::doFolder(LLFolderViewFolder* folder)
|
|||
}
|
||||
}
|
||||
|
||||
// Succeeds iff all selected items are bridges to objects, in which
|
||||
// case returns their corresponding uuids.
|
||||
bool get_selection_object_uuids(LLFolderView *root, uuid_vec_t& ids)
|
||||
{
|
||||
uuid_vec_t results;
|
||||
S32 non_object = 0;
|
||||
LLFolderView::selected_items_t selectedItems = root->getSelectedItems();
|
||||
for(LLFolderView::selected_items_t::iterator it = selectedItems.begin(); it != selectedItems.end(); ++it)
|
||||
{
|
||||
LLObjectBridge *view_model = dynamic_cast<LLObjectBridge *>((*it)->getViewModelItem());
|
||||
|
||||
if(view_model && view_model->getUUID().notNull())
|
||||
{
|
||||
results.push_back(view_model->getUUID());
|
||||
}
|
||||
else
|
||||
{
|
||||
non_object++;
|
||||
}
|
||||
}
|
||||
if (non_object == 0)
|
||||
{
|
||||
ids = results;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root, const std::string& action)
|
||||
{
|
||||
if ("rename" == action)
|
||||
|
|
@ -1115,7 +1143,6 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root
|
|||
LLFloater::setFloaterHost(multi_propertiesp);
|
||||
}
|
||||
|
||||
|
||||
std::set<LLUUID> selected_uuid_set = LLAvatarActions::getInventorySelectedUUIDs();
|
||||
uuid_vec_t ids;
|
||||
std::copy(selected_uuid_set.begin(), selected_uuid_set.end(), std::back_inserter(ids));
|
||||
|
|
@ -1128,7 +1155,7 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root
|
|||
{
|
||||
wear_multiple(ids, false);
|
||||
}
|
||||
else if (action == "take_off" || action == "detach")
|
||||
else if (isRemoveAction(action))
|
||||
{
|
||||
LLAppearanceMgr::instance().removeItemsFromAvatar(ids);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@
|
|||
// viewer includes
|
||||
#include "llagent.h"
|
||||
#include "llagentcamera.h"
|
||||
#include "llattachmentsmgr.h"
|
||||
#include "llviewerwindow.h"
|
||||
#include "lldrawable.h"
|
||||
#include "llfloaterinspect.h"
|
||||
|
|
@ -2343,6 +2344,7 @@ void LLSelectMgr::selectionSetIncludeInSearch(bool include_in_search)
|
|||
"ObjectIncludeInSearch",
|
||||
packAgentAndSessionID,
|
||||
packObjectIncludeInSearch,
|
||||
logNoOp,
|
||||
&include_in_search,
|
||||
SEND_ONLY_ROOTS);
|
||||
}
|
||||
|
|
@ -2392,6 +2394,7 @@ void LLSelectMgr::selectionSetClickAction(U8 action)
|
|||
sendListToRegions("ObjectClickAction",
|
||||
packAgentAndSessionID,
|
||||
packObjectClickAction,
|
||||
logNoOp,
|
||||
&action,
|
||||
SEND_INDIVIDUALS);
|
||||
}
|
||||
|
|
@ -2427,7 +2430,7 @@ void LLSelectMgr::sendGodlikeRequest(const std::string& request, const std::stri
|
|||
}
|
||||
else
|
||||
{
|
||||
sendListToRegions(message_type, packGodlikeHead, packObjectIDAsParam, &data, SEND_ONLY_ROOTS);
|
||||
sendListToRegions(message_type, packGodlikeHead, packObjectIDAsParam, logNoOp, &data, SEND_ONLY_ROOTS);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2455,6 +2458,23 @@ void LLSelectMgr::packGodlikeHead(void* user_data)
|
|||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void LLSelectMgr::logNoOp(LLSelectNode* node, void *)
|
||||
{
|
||||
}
|
||||
|
||||
// static
|
||||
void LLSelectMgr::logAttachmentRequest(LLSelectNode* node, void *)
|
||||
{
|
||||
LLAttachmentsMgr::instance().onAttachmentRequested(node->mItemID);
|
||||
}
|
||||
|
||||
// static
|
||||
void LLSelectMgr::logDetachRequest(LLSelectNode* node, void *)
|
||||
{
|
||||
LLAttachmentsMgr::instance().onDetachRequested(node->mItemID);
|
||||
}
|
||||
|
||||
// static
|
||||
void LLSelectMgr::packObjectIDAsParam(LLSelectNode* node, void *)
|
||||
{
|
||||
|
|
@ -3561,10 +3581,11 @@ bool LLSelectMgr::confirmDelete(const LLSD& notification, const LLSD& response,
|
|||
// attempt to derez into the trash.
|
||||
LLDeRezInfo info(DRD_TRASH, trash_id);
|
||||
LLSelectMgr::getInstance()->sendListToRegions("DeRezObject",
|
||||
packDeRezHeader,
|
||||
packObjectLocalID,
|
||||
(void*) &info,
|
||||
SEND_ONLY_ROOTS);
|
||||
packDeRezHeader,
|
||||
packObjectLocalID,
|
||||
logNoOp,
|
||||
(void*) &info,
|
||||
SEND_ONLY_ROOTS);
|
||||
// VEFFECT: Delete Object - one effect for all deletes
|
||||
if (LLSelectMgr::getInstance()->mSelectedObjects->mSelectType != SELECT_TYPE_HUD)
|
||||
{
|
||||
|
|
@ -3596,6 +3617,7 @@ void LLSelectMgr::selectForceDelete()
|
|||
"ObjectDelete",
|
||||
packDeleteHeader,
|
||||
packObjectLocalID,
|
||||
logNoOp,
|
||||
(void*)TRUE,
|
||||
SEND_ONLY_ROOTS);
|
||||
}
|
||||
|
|
@ -3766,7 +3788,7 @@ void LLSelectMgr::selectDuplicate(const LLVector3& offset, BOOL select_copy)
|
|||
data.offset = offset;
|
||||
data.flags = (select_copy ? FLAGS_CREATE_SELECTED : 0x0);
|
||||
|
||||
sendListToRegions("ObjectDuplicate", packDuplicateHeader, packDuplicate, &data, SEND_ONLY_ROOTS);
|
||||
sendListToRegions("ObjectDuplicate", packDuplicateHeader, packDuplicate, logNoOp, &data, SEND_ONLY_ROOTS);
|
||||
|
||||
if (select_copy)
|
||||
{
|
||||
|
|
@ -3821,7 +3843,7 @@ void LLSelectMgr::repeatDuplicate()
|
|||
data.offset = LLVector3::zero;
|
||||
data.flags = 0x0;
|
||||
|
||||
sendListToRegions("ObjectDuplicate", packDuplicateHeader, packDuplicate, &data, SEND_ONLY_ROOTS);
|
||||
sendListToRegions("ObjectDuplicate", packDuplicateHeader, packDuplicate, logNoOp, &data, SEND_ONLY_ROOTS);
|
||||
|
||||
// move current selection based on delta from duplication position and update duplication position
|
||||
for (LLObjectSelection::root_iterator iter = getSelection()->root_begin();
|
||||
|
|
@ -3900,7 +3922,7 @@ void LLSelectMgr::selectDuplicateOnRay(const LLVector3 &ray_start_region,
|
|||
data.mFlags = (select_copy ? FLAGS_CREATE_SELECTED : 0x0);
|
||||
|
||||
sendListToRegions("ObjectDuplicateOnRay",
|
||||
packDuplicateOnRayHead, packObjectLocalID, &data, SEND_ONLY_ROOTS);
|
||||
packDuplicateOnRayHead, packObjectLocalID, logNoOp, &data, SEND_ONLY_ROOTS);
|
||||
|
||||
if (select_copy)
|
||||
{
|
||||
|
|
@ -3950,6 +3972,7 @@ void LLSelectMgr::sendMultipleUpdate(U32 type)
|
|||
"MultipleObjectUpdate",
|
||||
packAgentAndSessionID,
|
||||
packMultipleUpdate,
|
||||
logNoOp,
|
||||
&type,
|
||||
send_type);
|
||||
}
|
||||
|
|
@ -4013,7 +4036,7 @@ void LLSelectMgr::sendOwner(const LLUUID& owner_id,
|
|||
data.group_id = group_id;
|
||||
data.override = override;
|
||||
|
||||
sendListToRegions("ObjectOwner", packOwnerHead, packObjectLocalID, &data, SEND_ONLY_ROOTS);
|
||||
sendListToRegions("ObjectOwner", packOwnerHead, packObjectLocalID, logNoOp, &data, SEND_ONLY_ROOTS);
|
||||
}
|
||||
|
||||
// static
|
||||
|
|
@ -4037,7 +4060,7 @@ void LLSelectMgr::packOwnerHead(void *user_data)
|
|||
void LLSelectMgr::sendGroup(const LLUUID& group_id)
|
||||
{
|
||||
LLUUID local_group_id(group_id);
|
||||
sendListToRegions("ObjectGroup", packAgentAndSessionAndGroupID, packObjectLocalID, &local_group_id, SEND_ONLY_ROOTS);
|
||||
sendListToRegions("ObjectGroup", packAgentAndSessionAndGroupID, packObjectLocalID, logNoOp, &local_group_id, SEND_ONLY_ROOTS);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -4061,7 +4084,7 @@ void LLSelectMgr::sendBuy(const LLUUID& buyer_id, const LLUUID& category_id, con
|
|||
LLBuyData buy;
|
||||
buy.mCategoryID = category_id;
|
||||
buy.mSaleInfo = sale_info;
|
||||
sendListToRegions("ObjectBuy", packAgentGroupAndCatID, packBuyObjectIDs, &buy, SEND_ONLY_ROOTS);
|
||||
sendListToRegions("ObjectBuy", packAgentGroupAndCatID, packBuyObjectIDs, logNoOp, &buy, SEND_ONLY_ROOTS);
|
||||
}
|
||||
|
||||
// static
|
||||
|
|
@ -4105,7 +4128,7 @@ void LLSelectMgr::selectionSetObjectPermissions(U8 field,
|
|||
data.mMask = mask;
|
||||
data.mOverride = override;
|
||||
|
||||
sendListToRegions("ObjectPermissions", packPermissionsHead, packPermissions, &data, SEND_ONLY_ROOTS);
|
||||
sendListToRegions("ObjectPermissions", packPermissionsHead, packPermissions, logNoOp, &data, SEND_ONLY_ROOTS);
|
||||
}
|
||||
|
||||
void LLSelectMgr::packPermissionsHead(void* user_data)
|
||||
|
|
@ -4148,6 +4171,7 @@ void LLSelectMgr::deselectAll()
|
|||
"ObjectDeselect",
|
||||
packAgentAndSessionID,
|
||||
packObjectLocalID,
|
||||
logNoOp,
|
||||
NULL,
|
||||
SEND_INDIVIDUALS);
|
||||
|
||||
|
|
@ -4178,6 +4202,7 @@ void LLSelectMgr::deselectAllForStandingUp()
|
|||
"ObjectDeselect",
|
||||
packAgentAndSessionID,
|
||||
packObjectLocalID,
|
||||
logNoOp,
|
||||
NULL,
|
||||
SEND_INDIVIDUALS);
|
||||
|
||||
|
|
@ -4259,6 +4284,7 @@ void LLSelectMgr::selectionSetObjectName(const std::string& name)
|
|||
sendListToRegions("ObjectName",
|
||||
packAgentAndSessionID,
|
||||
packObjectName,
|
||||
logNoOp,
|
||||
(void*)(&name_copy),
|
||||
SEND_ONLY_ROOTS);
|
||||
}
|
||||
|
|
@ -4267,6 +4293,7 @@ void LLSelectMgr::selectionSetObjectName(const std::string& name)
|
|||
sendListToRegions("ObjectName",
|
||||
packAgentAndSessionID,
|
||||
packObjectName,
|
||||
logNoOp,
|
||||
(void*)(&name_copy),
|
||||
SEND_INDIVIDUALS);
|
||||
}
|
||||
|
|
@ -4282,6 +4309,7 @@ void LLSelectMgr::selectionSetObjectDescription(const std::string& desc)
|
|||
sendListToRegions("ObjectDescription",
|
||||
packAgentAndSessionID,
|
||||
packObjectDescription,
|
||||
logNoOp,
|
||||
(void*)(&desc_copy),
|
||||
SEND_ONLY_ROOTS);
|
||||
}
|
||||
|
|
@ -4290,6 +4318,7 @@ void LLSelectMgr::selectionSetObjectDescription(const std::string& desc)
|
|||
sendListToRegions("ObjectDescription",
|
||||
packAgentAndSessionID,
|
||||
packObjectDescription,
|
||||
logNoOp,
|
||||
(void*)(&desc_copy),
|
||||
SEND_INDIVIDUALS);
|
||||
}
|
||||
|
|
@ -4303,6 +4332,7 @@ void LLSelectMgr::selectionSetObjectCategory(const LLCategory& category)
|
|||
sendListToRegions("ObjectCategory",
|
||||
packAgentAndSessionID,
|
||||
packObjectCategory,
|
||||
logNoOp,
|
||||
(void*)(&category),
|
||||
SEND_ONLY_ROOTS);
|
||||
}
|
||||
|
|
@ -4312,6 +4342,7 @@ void LLSelectMgr::selectionSetObjectSaleInfo(const LLSaleInfo& sale_info)
|
|||
sendListToRegions("ObjectSaleInfo",
|
||||
packAgentAndSessionID,
|
||||
packObjectSaleInfo,
|
||||
logNoOp,
|
||||
(void*)(&sale_info),
|
||||
SEND_ONLY_ROOTS);
|
||||
}
|
||||
|
|
@ -4345,6 +4376,7 @@ void LLSelectMgr::sendAttach(U8 attachment_point, bool replace)
|
|||
"ObjectAttach",
|
||||
packAgentIDAndSessionAndAttachment,
|
||||
packObjectIDAndRotation,
|
||||
logAttachmentRequest,
|
||||
&attachment_point,
|
||||
SEND_ONLY_ROOTS );
|
||||
if (!build_mode)
|
||||
|
|
@ -4365,6 +4397,7 @@ void LLSelectMgr::sendDetach()
|
|||
"ObjectDetach",
|
||||
packAgentAndSessionID,
|
||||
packObjectLocalID,
|
||||
logDetachRequest,
|
||||
NULL,
|
||||
SEND_ONLY_ROOTS );
|
||||
}
|
||||
|
|
@ -4381,6 +4414,7 @@ void LLSelectMgr::sendDropAttachment()
|
|||
"ObjectDrop",
|
||||
packAgentAndSessionID,
|
||||
packObjectLocalID,
|
||||
logDetachRequest,
|
||||
NULL,
|
||||
SEND_ONLY_ROOTS);
|
||||
}
|
||||
|
|
@ -4400,6 +4434,7 @@ void LLSelectMgr::sendLink()
|
|||
"ObjectLink",
|
||||
packAgentAndSessionID,
|
||||
packObjectLocalID,
|
||||
logNoOp,
|
||||
NULL,
|
||||
SEND_ONLY_ROOTS);
|
||||
}
|
||||
|
|
@ -4437,6 +4472,7 @@ void LLSelectMgr::sendDelink()
|
|||
"ObjectDelink",
|
||||
packAgentAndSessionID,
|
||||
packObjectLocalID,
|
||||
logNoOp,
|
||||
NULL,
|
||||
SEND_INDIVIDUALS);
|
||||
}
|
||||
|
|
@ -4489,6 +4525,7 @@ void LLSelectMgr::sendSelect()
|
|||
"ObjectSelect",
|
||||
packAgentAndSessionID,
|
||||
packObjectLocalID,
|
||||
logNoOp,
|
||||
NULL,
|
||||
SEND_INDIVIDUALS);
|
||||
}
|
||||
|
|
@ -4885,6 +4922,7 @@ void LLSelectMgr::packPermissions(LLSelectNode* node, void *user_data)
|
|||
void LLSelectMgr::sendListToRegions(const std::string& message_name,
|
||||
void (*pack_header)(void *user_data),
|
||||
void (*pack_body)(LLSelectNode* node, void *user_data),
|
||||
void (*log_func)(LLSelectNode* node, void *user_data),
|
||||
void *user_data,
|
||||
ESendType send_type)
|
||||
{
|
||||
|
|
@ -5006,6 +5044,8 @@ void LLSelectMgr::sendListToRegions(const std::string& message_name,
|
|||
{
|
||||
// add another instance of the body of the data
|
||||
(*pack_body)(node, user_data);
|
||||
// do any related logging
|
||||
(*log_func)(node, user_data);
|
||||
++objects_sent;
|
||||
++objects_in_this_packet;
|
||||
|
||||
|
|
@ -6656,7 +6696,7 @@ void LLSelectMgr::undo()
|
|||
{
|
||||
BOOL select_linked_set = !gSavedSettings.getBOOL("EditLinkedParts");
|
||||
LLUUID group_id(gAgent.getGroupID());
|
||||
sendListToRegions("Undo", packAgentAndSessionAndGroupID, packObjectID, &group_id, select_linked_set ? SEND_ONLY_ROOTS : SEND_CHILDREN_FIRST);
|
||||
sendListToRegions("Undo", packAgentAndSessionAndGroupID, packObjectID, logNoOp, &group_id, select_linked_set ? SEND_ONLY_ROOTS : SEND_CHILDREN_FIRST);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
@ -6674,7 +6714,7 @@ void LLSelectMgr::redo()
|
|||
{
|
||||
BOOL select_linked_set = !gSavedSettings.getBOOL("EditLinkedParts");
|
||||
LLUUID group_id(gAgent.getGroupID());
|
||||
sendListToRegions("Redo", packAgentAndSessionAndGroupID, packObjectID, &group_id, select_linked_set ? SEND_ONLY_ROOTS : SEND_CHILDREN_FIRST);
|
||||
sendListToRegions("Redo", packAgentAndSessionAndGroupID, packObjectID, logNoOp, &group_id, select_linked_set ? SEND_ONLY_ROOTS : SEND_CHILDREN_FIRST);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -759,6 +759,7 @@ private:
|
|||
void sendListToRegions( const std::string& message_name,
|
||||
void (*pack_header)(void *user_data),
|
||||
void (*pack_body)(LLSelectNode* node, void *user_data),
|
||||
void (*log_func)(LLSelectNode* node, void *user_data),
|
||||
void *user_data,
|
||||
ESendType send_type);
|
||||
|
||||
|
|
@ -794,6 +795,9 @@ private:
|
|||
static void packHingeHead(void *user_data);
|
||||
static void packPermissionsHead(void* user_data);
|
||||
static void packGodlikeHead(void* user_data);
|
||||
static void logNoOp(LLSelectNode* node, void *user_data);
|
||||
static void logAttachmentRequest(LLSelectNode* node, void *user_data);
|
||||
static void logDetachRequest(LLSelectNode* node, void *user_data);
|
||||
static bool confirmDelete(const LLSD& notification, const LLSD& response, LLObjectSelectionHandle handle);
|
||||
|
||||
// Get the first ID that matches test and whether or not all ids are identical in selected objects.
|
||||
|
|
|
|||
|
|
@ -2299,5 +2299,3 @@ BOOL LLViewerInventoryItem::regenerateLink()
|
|||
gInventory.notifyObservers();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -6632,7 +6632,7 @@ class LLAttachmentDetachFromPoint : public view_listener_t
|
|||
LLViewerObject *attached_object = (*iter);
|
||||
ids_to_remove.push_back(attached_object->getAttachmentItemID());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!ids_to_remove.empty())
|
||||
{
|
||||
LLAppearanceMgr::instance().removeItemsFromAvatar(ids_to_remove);
|
||||
|
|
|
|||
|
|
@ -1958,6 +1958,11 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
|
|||
|
||||
if (sent_parentp && (sent_parentp != this) && !sent_parentp->isDead())
|
||||
{
|
||||
if (((LLViewerObject*)sent_parentp)->isAvatar())
|
||||
{
|
||||
//LL_DEBUGS("Avatar") << "ATT got object update for attachment " << LL_ENDL;
|
||||
}
|
||||
|
||||
//
|
||||
// We have a viewer object for the parent, and it's not dead.
|
||||
// Do the actual reparenting here.
|
||||
|
|
|
|||
|
|
@ -475,13 +475,13 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
|
|||
{
|
||||
U32 flags = 0;
|
||||
mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_UpdateFlags, flags, i);
|
||||
|
||||
|
||||
if(flags & FLAGS_TEMPORARY_ON_REZ)
|
||||
{
|
||||
compressed_dp.unpackUUID(fullid, "ID");
|
||||
compressed_dp.unpackU32(local_id, "LocalID");
|
||||
compressed_dp.unpackU8(pcode, "PCode");
|
||||
}
|
||||
compressed_dp.unpackUUID(fullid, "ID");
|
||||
compressed_dp.unpackU32(local_id, "LocalID");
|
||||
compressed_dp.unpackU8(pcode, "PCode");
|
||||
}
|
||||
else //send to object cache
|
||||
{
|
||||
regionp->cacheFullUpdate(compressed_dp, flags);
|
||||
|
|
@ -498,7 +498,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
|
|||
gMessageSystem->getSenderPort());
|
||||
if (fullid.isNull())
|
||||
{
|
||||
// LL_WARNS() << "update for unknown localid " << local_id << " host " << gMessageSystem->getSender() << ":" << gMessageSystem->getSenderPort() << LL_ENDL;
|
||||
LL_DEBUGS() << "update for unknown localid " << local_id << " host " << gMessageSystem->getSender() << ":" << gMessageSystem->getSenderPort() << LL_ENDL;
|
||||
mNumUnknownUpdates++;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -722,7 +722,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
|
|||
const BOOL needsSendToSim = false; // currently, this HUD effect doesn't need to pack and unpack data to do its job
|
||||
mVoiceVisualizer = ( LLVoiceVisualizer *)LLHUDManager::getInstance()->createViewerEffect( LLHUDObject::LL_HUD_EFFECT_VOICE_VISUALIZER, needsSendToSim );
|
||||
|
||||
LL_DEBUGS("Avatar") << "LLVOAvatar Constructor (0x" << this << ") id:" << mID << LL_ENDL;
|
||||
LL_DEBUGS("Avatar","Message") << "LLVOAvatar Constructor (0x" << this << ") id:" << mID << LL_ENDL;
|
||||
|
||||
mPelvisp = NULL;
|
||||
|
||||
|
|
@ -5734,12 +5734,20 @@ BOOL LLVOAvatar::setParent(LLViewerObject* parent)
|
|||
void LLVOAvatar::addChild(LLViewerObject *childp)
|
||||
{
|
||||
childp->extractAttachmentItemID(); // find the inventory item this object is associated with.
|
||||
if (isSelf())
|
||||
{
|
||||
const LLUUID& item_id = childp->getAttachmentItemID();
|
||||
LLViewerInventoryItem *item = gInventory.getItem(item_id);
|
||||
LL_DEBUGS("Avatar") << "ATT attachment child added " << (item ? item->getName() : "UNKNOWN") << " id " << item_id << LL_ENDL;
|
||||
|
||||
}
|
||||
|
||||
LLViewerObject::addChild(childp);
|
||||
if (childp->mDrawable)
|
||||
{
|
||||
if (!attachObject(childp))
|
||||
{
|
||||
LL_WARNS() << "addChild() failed for "
|
||||
LL_WARNS() << "ATT addChild() failed for "
|
||||
<< childp->getID()
|
||||
<< " item " << childp->getAttachmentItemID()
|
||||
<< LL_ENDL;
|
||||
|
|
@ -5809,10 +5817,21 @@ LLViewerJointAttachment* LLVOAvatar::getTargetAttachmentPoint(LLViewerObject* vi
|
|||
//-----------------------------------------------------------------------------
|
||||
const LLViewerJointAttachment *LLVOAvatar::attachObject(LLViewerObject *viewer_object)
|
||||
{
|
||||
if (isSelf())
|
||||
{
|
||||
const LLUUID& item_id = viewer_object->getAttachmentItemID();
|
||||
LLViewerInventoryItem *item = gInventory.getItem(item_id);
|
||||
LL_DEBUGS("Avatar") << "ATT attaching object "
|
||||
<< (item ? item->getName() : "UNKNOWN") << " id " << item_id << LL_ENDL;
|
||||
}
|
||||
LLViewerJointAttachment* attachment = getTargetAttachmentPoint(viewer_object);
|
||||
|
||||
if (!attachment || !attachment->addObject(viewer_object))
|
||||
{
|
||||
const LLUUID& item_id = viewer_object->getAttachmentItemID();
|
||||
LLViewerInventoryItem *item = gInventory.getItem(item_id);
|
||||
LL_WARNS("Avatar") << "ATT attach failed "
|
||||
<< (item ? item->getName() : "UNKNOWN") << " id " << item_id << LL_ENDL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -5872,6 +5891,13 @@ void LLVOAvatar::lazyAttach()
|
|||
LLPointer<LLViewerObject> cur_attachment = mPendingAttachment[i];
|
||||
if (cur_attachment->mDrawable)
|
||||
{
|
||||
if (isSelf())
|
||||
{
|
||||
const LLUUID& item_id = cur_attachment->getAttachmentItemID();
|
||||
LLViewerInventoryItem *item = gInventory.getItem(item_id);
|
||||
LL_DEBUGS("Avatar") << "ATT attaching object "
|
||||
<< (item ? item->getName() : "UNKNOWN") << " id " << item_id << LL_ENDL;
|
||||
}
|
||||
if (!attachObject(cur_attachment))
|
||||
{ // Drop it
|
||||
LL_WARNS() << "attachObject() failed for "
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@
|
|||
#include "pipeline.h"
|
||||
|
||||
#include "llagent.h" // Get state values from here
|
||||
#include "llattachmentsmgr.h"
|
||||
#include "llagentcamera.h"
|
||||
#include "llagentwearables.h"
|
||||
#include "llhudeffecttrail.h"
|
||||
|
|
@ -1104,44 +1105,6 @@ BOOL LLVOAvatarSelf::isWearingAttachment(const LLUUID& inv_item_id) const
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
BOOL LLVOAvatarSelf::attachmentWasRequested(const LLUUID& inv_item_id) const
|
||||
{
|
||||
const F32 REQUEST_EXPIRATION_SECONDS = 5.0; // any request older than this is ignored/removed.
|
||||
std::map<LLUUID,LLTimer>::iterator it = mAttachmentRequests.find(inv_item_id);
|
||||
if (it != mAttachmentRequests.end())
|
||||
{
|
||||
const LLTimer& request_time = it->second;
|
||||
F32 request_time_elapsed = request_time.getElapsedTimeF32();
|
||||
if (request_time_elapsed > REQUEST_EXPIRATION_SECONDS)
|
||||
{
|
||||
mAttachmentRequests.erase(it);
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void LLVOAvatarSelf::addAttachmentRequest(const LLUUID& inv_item_id)
|
||||
{
|
||||
LLTimer current_time;
|
||||
mAttachmentRequests[inv_item_id] = current_time;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void LLVOAvatarSelf::removeAttachmentRequest(const LLUUID& inv_item_id)
|
||||
{
|
||||
mAttachmentRequests.erase(inv_item_id);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// getWornAttachment()
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
@ -1208,8 +1171,6 @@ const LLViewerJointAttachment *LLVOAvatarSelf::attachObject(LLViewerObject *view
|
|||
{
|
||||
const LLUUID& attachment_id = viewer_object->getAttachmentItemID();
|
||||
LLAppearanceMgr::instance().registerAttachment(attachment_id);
|
||||
// Clear any pending requests once the attachment arrives.
|
||||
removeAttachmentRequest(attachment_id);
|
||||
updateLODRiggedAttachments();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -293,19 +293,12 @@ protected:
|
|||
public:
|
||||
void updateAttachmentVisibility(U32 camera_mode);
|
||||
BOOL isWearingAttachment(const LLUUID& inv_item_id) const;
|
||||
BOOL attachmentWasRequested(const LLUUID& inv_item_id) const;
|
||||
void addAttachmentRequest(const LLUUID& inv_item_id);
|
||||
void removeAttachmentRequest(const LLUUID& inv_item_id);
|
||||
LLViewerObject* getWornAttachment(const LLUUID& inv_item_id);
|
||||
bool getAttachedPointName(const LLUUID& inv_item_id, std::string& name) const;
|
||||
/*virtual*/ const LLViewerJointAttachment *attachObject(LLViewerObject *viewer_object);
|
||||
/*virtual*/ BOOL detachObject(LLViewerObject *viewer_object);
|
||||
static BOOL detachAttachmentIntoInventory(const LLUUID& item_id);
|
||||
|
||||
private:
|
||||
// Track attachments that have been requested but have not arrived yet.
|
||||
mutable std::map<LLUUID,LLTimer> mAttachmentRequests;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// HUDs
|
||||
//--------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ void LLPanelWearableOutfitItem::updateItem(const std::string& name,
|
|||
// We don't use get_is_item_worn() here because this update is triggered by
|
||||
// an inventory observer upon link in COF beind added or removed so actual
|
||||
// worn status of a linked item may still remain unchanged.
|
||||
if (mWornIndicationEnabled && LLAppearanceMgr::instance().isLinkInCOF(mInventoryItemUUID))
|
||||
if (mWornIndicationEnabled && LLAppearanceMgr::instance().isLinkedInCOF(mInventoryItemUUID))
|
||||
{
|
||||
search_label += LLTrans::getString("worn");
|
||||
item_state = IS_WORN;
|
||||
|
|
|
|||
Loading…
Reference in New Issue