From 1866bc2af39189c17b636970d4df7edc983c1830 Mon Sep 17 00:00:00 2001 From: McCabe Maxsted Date: Sat, 9 Oct 2010 03:27:47 -0700 Subject: Applied RLVa-1.1.2-Imprudence.patch by Kitty Barnett --- linden/indra/newview/rlvhelper.cpp | 649 ++++++++++++++++++++++++++++++------- 1 file changed, 526 insertions(+), 123 deletions(-) (limited to 'linden/indra/newview/rlvhelper.cpp') diff --git a/linden/indra/newview/rlvhelper.cpp b/linden/indra/newview/rlvhelper.cpp index f509a43..9ef74ac 100644 --- a/linden/indra/newview/rlvhelper.cpp +++ b/linden/indra/newview/rlvhelper.cpp @@ -1,27 +1,31 @@ #include "llviewerprecompiledheaders.h" -#include "llagent.h" #include "llfloaterwindlight.h" +#include "llgesturemgr.h" +#include "llinventoryview.h" +#include "llinventorybridge.h" #include "llviewerobject.h" +#include "llviewerobjectlist.h" +#include "llviewerregion.h" #include "llviewerstats.h" #include "llviewerwindow.h" #include "llvoavatar.h" +#include "llwearablelist.h" #include "llwlparammanager.h" #include "rlvhelper.h" -#include "rlvevent.h" #include "rlvhandler.h" -// ============================================================================ -// Static variable initialization -// - -RlvCommand::RlvBhvrTable RlvCommand::m_BhvrMap; +// Defined in llinventorybridge.cpp +void wear_attachments_on_avatar(const LLInventoryModel::item_array_t& items, BOOL remove); +void wear_inventory_category_on_avatar_loop(LLWearable* wearable, void*); // ============================================================================ // RlvCommmand // -// Checked: 2009-09-10 (RLVa-1.0.3a) | Modified: RLVa-1.0.3a +RlvCommand::RlvBhvrTable RlvCommand::m_BhvrMap; + +// Checked: 2009-12-27 (RLVa-1.1.0k) | Modified: RLVa-1.1.0k RlvCommand::RlvCommand(const std::string& strCommand) : m_eBehaviour(RLV_BHVR_UNKNOWN), m_fStrict(false), m_eParamType(RLV_TYPE_UNKNOWN) { @@ -32,12 +36,12 @@ RlvCommand::RlvCommand(const std::string& strCommand) m_eParamType = RLV_TYPE_ADD; else if ( ("y" == m_strParam) || ("rem" == m_strParam) ) m_eParamType = RLV_TYPE_REMOVE; + else if (m_strBehaviour == "clear") // clear is the odd one out so just make it its own type + m_eParamType = RLV_TYPE_CLEAR; else if ("force" == m_strParam) m_eParamType = RLV_TYPE_FORCE; else if (LLStringUtil::convertToS32(m_strParam, nTemp)) // Assume it's a reply command if we can convert to an S32 m_eParamType = RLV_TYPE_REPLY; - else if (m_strBehaviour == "clear") // clear is the odd one out so just make it its own type - m_eParamType = RLV_TYPE_CLEAR; else { m_eParamType = RLV_TYPE_UNKNOWN; @@ -51,13 +55,7 @@ RlvCommand::RlvCommand(const std::string& strCommand) return; } - // Check if this is the "strict" (aka "secure") variation of a behaviour - std::string::size_type idxStrict = m_strBehaviour.find("_sec"); - m_fStrict = (std::string::npos != idxStrict) && (idxStrict + 4 == m_strBehaviour.length()); - - RlvBhvrTable::const_iterator itBhvr = m_BhvrMap.find( (!m_fStrict) ? m_strBehaviour : m_strBehaviour.substr(0, idxStrict)); - if ( (itBhvr != m_BhvrMap.end()) && ((!m_fStrict) || (hasStrictVariant(itBhvr->second))) ) - m_eBehaviour = itBhvr->second; + m_eBehaviour = getBehaviourFromString(m_strBehaviour, &m_fStrict); } @@ -95,6 +93,20 @@ bool RlvCommand::parseCommand(const std::string& strCommand, std::string& strBeh return true; } +// Checked: 2009-12-05 (RLVa-1.1.0h) | Added: RLVa-1.1.0h +ERlvBehaviour RlvCommand::getBehaviourFromString(const std::string& strBhvr, bool* pfStrict /*=NULL*/) +{ + std::string::size_type idxStrict = strBhvr.find("_sec"); + bool fStrict = (std::string::npos != idxStrict) && (idxStrict + 4 == strBhvr.length()); + if (pfStrict) + *pfStrict = fStrict; + + RlvBhvrTable::const_iterator itBhvr = m_BhvrMap.find( (!fStrict) ? strBhvr : strBhvr.substr(0, idxStrict)); + if ( (itBhvr != m_BhvrMap.end()) && ((!fStrict) || (hasStrictVariant(itBhvr->second))) ) + return itBhvr->second; + return RLV_BHVR_UNKNOWN; +} + void RlvCommand::initLookupTable() { static bool fInitialized = false; @@ -103,14 +115,16 @@ void RlvCommand::initLookupTable() // NOTE: keep this matched with the enumeration at all times std::string arBehaviours[RLV_BHVR_COUNT] = { - "version", "detach", "sendchat", "emote", "chatshout", "chatnormal", "chatwhisper", "redirchat", "rediremote", - "sendim", "recvchat", "recvemote", "recvim", "tplm", "tploc", "tplure", "sittp", "edit", "rez", - "addoutfit", "remoutfit", "getoutfit", "addattach", "remattach", "getattach", "showinv", "viewnote", "unsit", "sit", - "sendchannel", "getstatus", "getstatusall", "getinv", "getinvworn", "findfolder", "findfolders", - "attach", "attachall", "detachall", "getpath", "attachthis", "attachallthis", "detachthis", "detachallthis", - "fartouch", "showworldmap", "showminimap", "showloc", "tpto", "accepttp", "acceptpermission", "shownames", "fly", - "getsitid", "setdebug", "setenv", "detachme", "showhovertextall", "showhovertextworld", "showhovertexthud", - "showhovertext", "notify", "defaultwear", "versionnum", "permissive", "viewscript", "viewtexture" + "detach", "attach", "addattach", "remattach", "addoutfit", "remoutfit", "emote", "sendchat", "recvchat", "recvemote", + "redirchat", "rediremote", "chatwhisper", "chatnormal", "chatshout", "sendchannel", "sendim", "recvim", "permissive", + "notify", "showinv", "showminimap", "showworldmap", "showloc", "shownames", "showhovertext", "showhovertexthud", + "showhovertextworld", "showhovertextall", "tplm", "tploc", "tplure", "viewnote", "viewscript", "viewtexture", + "acceptpermission", "accepttp", "defaultwear", "allowidle", "edit", "rez", "fartouch", "interact", "touch", + "touchattach", "touchhud", "touchworld", "fly", "unsit", "sit", "sittp", "setdebug", "setenv", "detachme", "detachthis", + "detachall", "detachallthis", "attachthis", "attachall", "attachallthis", "tpto", "version", "versionnew", "versionnum", + "getattach", "getattachnames", "getaddattachnames", "getremattachnames", "getoutfit", "getoutfitnames", + "getaddoutfitnames", "getremoutfitnames", "findfolder", "findfolders", "getpath", "getinv", "getinvworn", "getsitid", + "getstatus", "getstatusall" }; for (int idxBvhr = 0; idxBvhr < RLV_BHVR_COUNT; idxBvhr++) @@ -133,9 +147,7 @@ RlvObject::RlvObject(const LLUUID& idObj) : m_UUID(idObj), m_nLookupMisses(0) bool RlvObject::addCommand(const RlvCommand& rlvCmd) { - // Sanity checking - if (RLV_TYPE_ADD != rlvCmd.getParamType()) - return false; + RLV_ASSERT(RLV_TYPE_ADD == rlvCmd.getParamType()); // Don't add duplicate commands for this object (ie @detach=n followed by another @detach=n later on) for (rlv_command_list_t::iterator itCmd = m_Commands.begin(); itCmd != m_Commands.end(); ++itCmd) @@ -155,9 +167,7 @@ bool RlvObject::addCommand(const RlvCommand& rlvCmd) bool RlvObject::removeCommand(const RlvCommand& rlvCmd) { - // Sanity checking - if (RLV_TYPE_REMOVE != rlvCmd.getParamType()) - return false; + RLV_ASSERT(RLV_TYPE_REMOVE == rlvCmd.getParamType()); for (rlv_command_list_t::iterator itCmd = m_Commands.begin(); itCmd != m_Commands.end(); ++itCmd) { @@ -188,7 +198,7 @@ bool RlvObject::hasBehaviour(ERlvBehaviour eBehaviour, const std::string& strOpt return false; } -// Checked: 2009-06-07 (RLVa-0.2.1c) +// Checked: 2009-11-27 (RLVa-1.1.0f) | Modified: RLVa-1.1.0f std::string RlvObject::getStatusString(const std::string& strMatch) const { std::string strStatus, strCmd; @@ -198,8 +208,7 @@ std::string RlvObject::getStatusString(const std::string& strMatch) const strCmd = itCmd->asString(); if ( (strMatch.empty()) || (std::string::npos != strCmd.find(strMatch)) ) { - if (!strStatus.empty()) - strStatus.push_back('/'); + strStatus.push_back('/'); strStatus += strCmd; } } @@ -212,7 +221,7 @@ std::string RlvObject::getStatusString(const std::string& strMatch) const // // Checked: 2009-10-12 (RLVa-1.0.5b) | Modified: RLVa-1.0.5b -void RlvAttachmentManager::forceAttach(const LLUUID& idItem, S32 idxAttachPt) +void RlvAttachmentManager::attach(const LLUUID& idItem, S32 idxAttachPt) { #if RLV_TARGET < RLV_MAKE_TARGET(1, 23, 0) // Version: 1.22.11 LLAttachmentRezAction* rez_action = new LLAttachmentRezAction(); @@ -224,18 +233,15 @@ void RlvAttachmentManager::forceAttach(const LLUUID& idItem, S32 idxAttachPt) LLSD payload; payload["item_id"] = idItem; payload["attachment_point"] = idxAttachPt; - - LLNotifications::instance().forceResponse( - LLNotification::Params("ReplaceAttachment").payload(payload), 0/*YES*/); + LLNotifications::instance().forceResponse(LLNotification::Params("ReplaceAttachment").payload(payload), 0/*YES*/); #endif } -// Checked: 2009-10-12 (RLVa-1.0.5b) | Modified: RLVa-1.0.5b -void RlvAttachmentManager::forceDetach(LLViewerJointAttachment* pAttachPt) +// Checked: 2009-11-24 (RLVa-1.1.0k) | Added: RLVa-1.1.0e +void RlvAttachmentManager::detach(LLViewerJointAttachment* pAttachPt) { - // Copy/paste from handle_detach_from_avatar() - LLViewerObject* attached_object = pAttachPt->getObject(); - if (attached_object) + // [See handle_detach_from_avatar()] + if ( (pAttachPt) && (pAttachPt->getObject()) ) { gMessageSystem->newMessage("ObjectDetach"); gMessageSystem->nextBlockFast(_PREHASH_AgentData); @@ -243,7 +249,7 @@ void RlvAttachmentManager::forceDetach(LLViewerJointAttachment* pAttachPt) gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); gMessageSystem->nextBlockFast(_PREHASH_ObjectData); - gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, attached_object->getLocalID()); + gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, pAttachPt->getObject()->getLocalID()); gMessageSystem->sendReliable( gAgent.getRegionHost() ); } } @@ -278,7 +284,7 @@ void RlvAttachmentManager::onAttach(LLViewerJointAttachment* pAttachPt) // If it was empty we need to force detach the new attachment; if it wasn't we need to reattach the old one if (itAttachPrev->second.isNull()) { - forceDetach(pAttachPt); + detach(pAttachPt); m_PendingDetach.insert(std::pair(idxAttachPt, pAttachPt->getItemID())); } else if (m_PendingAttach.find(idxAttachPt) == m_PendingAttach.end()) // (only if we're not reattaching something else there) @@ -321,7 +327,7 @@ void RlvAttachmentManager::onSavedAssetIntoInventory(const LLUUID& idItem) { if ( (!itAttach->second.fAssetSaved) && (idItem == itAttach->second.idItem) ) { - forceAttach(itAttach->second.idItem, itAttach->first); + attach(itAttach->second.idItem, itAttach->first); itAttach->second.tsAttach = LLFrameTimer::getElapsedSeconds(); } } @@ -368,7 +374,7 @@ BOOL RlvAttachmentManager::onTimer() if (fAttach) { - forceAttach(itAttach->second.idItem, itAttach->first); + attach(itAttach->second.idItem, itAttach->first); itAttach->second.tsAttach = tsCurrent; } @@ -421,7 +427,7 @@ const LLUUID& RlvWearableItemCollector::getFoldedParent(const LLUUID& idFolder) return (m_Folding.end() == itFolder) ? idFolder : itFolder->second; } -// Checked: 2009-07-29 (RLVa-1.0.1b) | Modified: RLVa-1.0.1b +// Checked: 2009-12-18 (RLVa-1.1.0k) | Modified: RLVa-1.1.0i bool RlvWearableItemCollector::onCollectFolder(const LLInventoryCategory* pFolder) { const LLUUID& idParent = pFolder->getParentUUID(); @@ -437,25 +443,35 @@ bool RlvWearableItemCollector::onCollectFolder(const LLInventoryCategory* pFolde return false; #endif // RLV_EXTENSION_FLAG_NOSTRIP - if (gRlvHandler.isFoldedFolder(pFolder, m_fAttach)) // Check for folder that should get folded under its parent + if (gRlvHandler.isFoldedFolder(pFolder, m_fAttach, false)) // Check for folder that should get folded under its parent { m_Tentative.push_front(pFolder->getUUID()); m_Folding.insert(std::pair(pFolder->getUUID(), idParent)); } else if ( (RLV_FOLDER_PREFIX_HIDDEN != strFolder[0]) && (m_fMatchAll) ) // Collect from any non-hidden child folder for *all { - m_Wearable.push_front(pFolder->getUUID()); + #ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS + if ( (!RlvSettings::getEnableComposites()) || // ... if we're not checking composite folders + (!gRlvHandler.isCompositeFolder(pFolder)) || // ... or if it's not a composite folder + ((m_fAttach) && (gRlvHandler.canWearComposite(pFolder))) || // ... or if we're attaching and can attach it OR + (!m_fAttach) && (gRlvHandler.canTakeOffComposite(pFolder)) ) // ... or if we're detaching and can detach it + #endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS + { + m_Wearable.push_front(pFolder->getUUID()); + } return (idParent == m_idFolder); // (Convenience for @getinvworn) } - #ifdef RLV_EXPERIMENTAL_COMPOSITES - else if ( (RLV_FOLDER_PREFIX_HIDDEN == strFolder[0]) && // Hidden folder that's a... + #ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS + else if ( (RlvSettings::getEnableComposites()) && + (RLV_FOLDER_PREFIX_HIDDEN == strFolder[0]) && // Hidden folder that's a... (gRlvHandler.isCompositeFolder(pFolder)) && // ... composite folder which we... - ((m_fAttach) || (gRlvHandler.canTakeOffComposite(pFolder))) ) // ... attach or can detach (see composite locking) + ( ((m_fAttach) && (gRlvHandler.canWearComposite(pFolder))) || // ... are attaching and can attach OR + (!m_fAttach) && (gRlvHandler.canTakeOffComposite(pFolder)) ) ) // ... are detaching and can detach { m_Wearable.push_front(pFolder->getUUID()); m_Folding.insert(std::pair(pFolder->getUUID(), idParent)); } - #endif // RLV_EXPERIMENTAL_COMPOSITES + #endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS return false; } @@ -486,13 +502,13 @@ bool RlvWearableItemCollector::onCollectItem(const LLInventoryItem* pItem) case LLAssetType::AT_OBJECT: fRet = ( (m_Wearable.end() != std::find(m_Wearable.begin(), m_Wearable.end(), idParent)) || (m_Tentative.end() != std::find(m_Tentative.begin(), m_Tentative.end(), idParent)) ) && - ( (!m_fAttach) || (gRlvHandler.hasAttachPointName(pItem, true)) ); // Only care about attach point on attach* + ( (!m_fAttach) || (gRlvHandler.hasAttachPointName(pItem, true)) || (RlvSettings::getEnableSharedWear()) ); break; - #ifdef RLV_EXPERIMENTAL_FORCEWEAR_GESTURES + #ifdef RLV_EXTENSION_FORCEWEAR_GESTURES case LLAssetType::AT_GESTURE: fRet = (m_Wearable.end() != std::find(m_Wearable.begin(), m_Wearable.end(), idParent)); break; - #endif // RLV_EXPERIMENTAL_FORCEWEAR_GESTURES + #endif // RLV_EXTENSION_FORCEWEAR_GESTURES default: break; } @@ -507,6 +523,431 @@ bool RlvWearableItemCollector::operator()(LLInventoryCategory* pFolder, LLInvent } // ============================================================================ +// RlvForceWear +// + +// Checked: 2010-02-17 (RLVa-1.1.0o) | Modified: RLVa-1.1.0o +void RlvForceWear::forceFolder(const LLViewerInventoryCategory* pFolder, eWearAction eAction, eWearFlags eFlags) +{ + // [See LLWearableBridge::wearOnAvatar(): don't wear anything until initial wearables are loaded, can destroy clothing items] + if (!gAgent.areWearablesLoaded()) + { + LLNotifications::instance().add("CanNotChangeAppearanceUntilLoaded"); + return; + } + // Sanity check - getAvatarObject() can't be NULL [see RlvForceWear::isWearingItem()] + LLVOAvatar* pAvatar = gAgent.getAvatarObject(); + if (!pAvatar) + return; + + LLInventoryModel::cat_array_t folders; + LLInventoryModel::item_array_t items; + RlvWearableItemCollector functor(pFolder->getUUID(), (ACTION_ATTACH == eAction), (FLAG_MATCHALL & eFlags)); + + // Grab a list of all the items we'll be wearing/attaching + gInventory.collectDescendentsIf(pFolder->getUUID(), folders, items, FALSE, functor); + + for (S32 idxItem = 0, cntItem = items.count(); idxItem < cntItem; idxItem++) + { + LLViewerInventoryItem* pItem = items.get(idxItem); + + // If it's wearable it should be worn on detach + if ( (ACTION_DETACH == eAction) && (isWearableItem(pItem)) && (!isWearingItem(pItem)) ) + continue; + + // NOTES: * if there are composite items then RlvWearableItemCollector made sure they can be worn (or taken off depending) + // * some scripts issue @remattach=force,attach:worn-items=force so we need to attach items even if they're currently worn + switch (pItem->getType()) + { + case LLAssetType::AT_BODYPART: + RLV_ASSERT(ACTION_ATTACH == eAction); // RlvWearableItemCollector shouldn't be supplying us with body parts on detach + case LLAssetType::AT_CLOTHING: + if (ACTION_ATTACH == eAction) + { + // The check for whether we're replacing a currently worn composite item happens in onWearableArrived() + if (std::find(m_addWearables.begin(), m_addWearables.end(), pItem) == m_addWearables.end()) + m_addWearables.push_back(pItem); + } + else + { + LLWearable* pWearable = gAgent.getWearableFromWearableItem(pItem->getUUID()); + if ( (pWearable) && (isForceRemovable(pWearable->getType(), false)) ) + { + if (std::find(m_remWearables.begin(), m_remWearables.end(), pWearable->getType()) == m_remWearables.end()) + m_remWearables.push_back(pWearable->getType()); + } + } + break; + + case LLAssetType::AT_OBJECT: + if (ACTION_ATTACH == eAction) + { + LLViewerJointAttachment* pAttachPt = gRlvHandler.getAttachPoint(pItem, true); + if ( ( (pAttachPt) && // Need a specific attach pt that + (!gRlvHandler.isLockedAttachment(pAttachPt->getObject(), RLV_LOCK_REMOVE)) && // doesn't have a locked object + (!gRlvHandler.isLockedAttachment(pAttachPt, RLV_LOCK_ADD)) ) || // and that can be attached to + (RlvSettings::getEnableSharedWear()) ) + { + if (std::find(m_addAttachments.begin(), m_addAttachments.end(), pItem) == m_addAttachments.end()) + { + #ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS + // We still need to check whether we're about to replace a currently worn composite item + // (which we're not if we're just reattaching an attachment we're already wearing) + LLViewerInventoryCategory* pCompositeFolder = NULL; + if ( (pAttachPt->getObject()) && (RlvSettings::getEnableComposites()) && + (pAttachPt->getItemID() != pItem->getUUID()) && + (gRlvHandler.getCompositeInfo(pAttachPt->getItemID(), NULL, &pCompositeFolder)) ) + { + // If we can't take off the composite folder this item would replace then don't allow it to get attached + if (gRlvHandler.canTakeOffComposite(pCompositeFolder)) + { + forceFolder(pCompositeFolder, ACTION_DETACH, FLAG_DEFAULT); + m_addAttachments.push_back(pItem); + } + } + else + #endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS + { + m_addAttachments.push_back(pItem); + } + } + } + } + else + { + LLViewerJointAttachment* pAttachPt = pAvatar->getWornAttachmentPoint(pItem->getUUID()); + if ( (pAttachPt) && (isForceDetachable(pAttachPt, false)) ) + { + if (std::find(m_remAttachments.begin(), m_remAttachments.end(), pAttachPt) == m_remAttachments.end()) + m_remAttachments.push_back(pAttachPt); + } + } + break; + + #ifdef RLV_EXTENSION_FORCEWEAR_GESTURES + case LLAssetType::AT_GESTURE: + if (ACTION_ATTACH == eAction) + { + if (std::find(m_addGestures.begin(), m_addGestures.end(), pItem) == m_addGestures.end()) + m_addGestures.push_back(pItem); + } + else + { + if (std::find(m_remGestures.begin(), m_remGestures.end(), pItem) == m_remGestures.end()) + m_remGestures.push_back(pItem); + } + break; + #endif // RLV_EXTENSION_FORCEWEAR_GESTURES + + default: + break; + } + } +} + +// Checked: 2009-12-18 (RLVa-1.1.0k) | Added: RLVa-1.1.0i +bool RlvForceWear::isForceDetachable(LLViewerJointAttachment* pAttachPt, bool fCheckComposite /*=true*/, LLViewerObject* pExceptObj /*=NULL*/) +{ + // Attachment point can be detached by an RLV command if: + // - something is worn on the attachment point + // - what's worn isn't "remove locked" by anything (or anything except the object specified by pExceptObj) + // - what's worn is strippable + // - composite folders are disabled *or* what's worn isn't part of a composite folder that has at least one item locked + #ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS + LLViewerInventoryCategory* pFolder = NULL; + #endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS + return + ( + (pAttachPt) && (pAttachPt->getObject()) && + ( (!pExceptObj) ? (!gRlvHandler.isLockedAttachment(pAttachPt->getObject(), RLV_LOCK_REMOVE)) + : (!gRlvHandler.isLockedAttachmentExcept(pAttachPt->getObject(), RLV_LOCK_REMOVE, pExceptObj)) ) + #ifdef RLV_EXTENSION_FLAG_NOSTRIP + && (gRlvHandler.isStrippable(pAttachPt->getItemID())) + #endif // RLV_EXTENSION_FLAG_NOSTRIP + #ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS + && ( (!fCheckComposite) || (!RlvSettings::getEnableComposites()) || + (!gRlvHandler.getCompositeInfo(pAttachPt->getItemID(), NULL, &pFolder)) || (gRlvHandler.canTakeOffComposite(pFolder)) ) + #endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS + ); +} + +// Checked: 2009-12-18 (RLVa-1.1.0k) | Added: RLVa-1.1.0i +void RlvForceWear::forceDetach(LLViewerJointAttachment* pAttachPt) +{ + // Sanity check - no need to process duplicate removes + if ( (!pAttachPt) || (std::find(m_remAttachments.begin(), m_remAttachments.end(), pAttachPt) != m_remAttachments.end()) ) + return; + + if (isForceDetachable(pAttachPt)) + { + #ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS + LLViewerInventoryCategory* pFolder = NULL; + if ( (RlvSettings::getEnableComposites()) && + (gRlvHandler.getCompositeInfo(pAttachPt->getItemID(), NULL, &pFolder)) ) + { + // Attachment belongs to a composite folder so detach the entire folder (if we can take it off) + if (gRlvHandler.canTakeOffComposite(pFolder)) + forceFolder(pFolder, ACTION_DETACH, FLAG_DEFAULT); + } + else + #endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS + { + m_remAttachments.push_back(pAttachPt); + } + } +} + +// Checked: 2009-12-18 (RLVa-1.1.0k) | Added: RLVa-1.1.0i +bool RlvForceWear::isForceRemovable(EWearableType wtType, bool fCheckComposite /*=true*/, const LLUUID& idExcept /*=LLUUID::null*/) +{ + // Wearable type can be removed by an RLV command if: + // - something is worn on that layer + // - its asset type is AT_CLOTHING + // - what's worn isn't "remove locked" by anything (or anything except the object specified by idExcept) + // - what's worn is strippable + // - composite folders are disabled *or* what's worn isn't part of a composite folder that has at least one item locked + LLWearable* pWearable = gAgent.getWearable(wtType); + #ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS + LLViewerInventoryCategory* pFolder = NULL; + #endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS + return + ( + (pWearable) && + (LLAssetType::AT_CLOTHING == LLWearable::typeToAssetType(wtType)) && + ( (idExcept.notNull()) ? (gRlvHandler.isRemovable(wtType)) + : (gRlvHandler.isRemovableExcept(wtType, idExcept)) ) + #ifdef RLV_EXTENSION_FLAG_NOSTRIP + && (gRlvHandler.isStrippable(gAgent.getWearableItem(wtType))) + #endif // RLV_EXTENSION_FLAG_NOSTRIP + #ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS + && ( (!fCheckComposite) || (!RlvSettings::getEnableComposites()) || + (!gRlvHandler.getCompositeInfo(gAgent.getWearableItem(wtType), NULL, &pFolder)) || (gRlvHandler.canTakeOffComposite(pFolder)) ) + #endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS + ); +} + +// Checked: 2009-12-18 (RLVa-1.1.0k) | Added: RLVa-1.1.0i +void RlvForceWear::forceRemove(EWearableType wtType) +{ + // Sanity check - no need to process duplicate removes + if ( (WT_INVALID == wtType) || (std::find(m_remWearables.begin(), m_remWearables.end(), wtType) != m_remWearables.end()) ) + return; + + if (isForceRemovable(wtType)) + { + #ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS + LLViewerInventoryCategory* pFolder = NULL; + if ( (RlvSettings::getEnableComposites()) && + (gRlvHandler.getCompositeInfo(gAgent.getWearableItem(wtType), NULL, &pFolder)) ) + { + // Wearable belongs to a composite folder so detach the entire folder (if we can take it off) + if (gRlvHandler.canTakeOffComposite(pFolder)) + forceFolder(pFolder, ACTION_DETACH, FLAG_DEFAULT); + } + else + #endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS + { + m_remWearables.push_back(wtType); + } + } +} + +// Checked: 2009-12-18 (RLVa-1.1.0k) | Added: RLVa-1.1.0i +void RlvForceWear::processAdd() +{ + // Process attachments + if (m_addAttachments.size()) + { + // Workaround for RezMultipleAttachmentsFromInv bug (see http://jira.secondlife.com/browse/SVC-5383) + #ifndef RLV_WORKAROUND_REZMULTIPLEATTACH + wear_attachments_on_avatar(m_addAttachments, FALSE); + #else + for (S32 idxItem = 0, cntItem = m_addAttachments.count(); idxItem < cntItem; idxItem++) + { + LLViewerInventoryItem* pItem = m_addAttachments.get(idxItem); + + S32 idxAttachPt = gRlvHandler.getAttachPointIndex(pItem, true); + if (0 != idxAttachPt) + { + #if RLV_TARGET < RLV_MAKE_TARGET(1, 23, 0) // Version: 1.22.11 + LLAttachmentRezAction* rez_action = new LLAttachmentRezAction(); + rez_action->mItemID = pItem->getUUID(); + rez_action->mAttachPt = idxAttachPt; + + confirm_replace_attachment_rez(0/*YES*/, (void*)rez_action); // (Will call delete on rez_action) + #else // Version: 1.23.4 + LLSD payload; + payload["item_id"] = pItem->getUUID(); + payload["attachment_point"] = idxAttachPt; + + LLNotifications::instance().forceResponse(LLNotification::Params("ReplaceAttachment").payload(payload), 0/*YES*/); + #endif + } + } + #endif // RLV_WORKAROUND_REZMULTIPLEATTACH + + m_addAttachments.clear(); + } + + // Process wearables + if (m_addWearables.size()) + { + // [See wear_inventory_category_on_avatar_step2()] + LLWearableHoldingPattern* pWearData = new LLWearableHoldingPattern(TRUE); + + // We need to populate 'pWearData->mFoundList' before doing anything else because (some of) the assets might already be available + for (S32 idxItem = 0, cntItem = m_addWearables.count(); idxItem < cntItem; idxItem++) + { + LLViewerInventoryItem* pItem = m_addWearables.get(idxItem); + if ( (pItem) && ((LLAssetType::AT_BODYPART == pItem->getType()) || (LLAssetType::AT_CLOTHING == pItem->getType())) ) + { + LLFoundData* pFound = new LLFoundData(pItem->getUUID(), pItem->getAssetUUID(), pItem->getName(), pItem->getType()); + pWearData->mFoundList.push_front(pFound); + } + } + + if (!pWearData->mFoundList.size()) + { + delete pWearData; + return; + } + + // If all the assets are available locally then "pWearData" will be freed *before* the last "gWearableList.getAsset()" call returns + bool fContinue = true; LLWearableHoldingPattern::found_list_t::const_iterator itWearable = pWearData->mFoundList.begin(); + while ( (fContinue) && (itWearable != pWearData->mFoundList.end()) ) + { + const LLFoundData* pFound = *itWearable; + ++itWearable; + fContinue = (itWearable != pWearData->mFoundList.end()); + gWearableList.getAsset(pFound->mAssetID, pFound->mName, pFound->mAssetType, onWearableArrived, (void*)pWearData); + } + + m_addWearables.clear(); + } + + // Process gestures + if (m_addGestures.size()) + { + gGestureManager.activateGestures(m_addGestures); + for (S32 idxGesture = 0, cntGesture = m_addGestures.count(); idxGesture < cntGesture; idxGesture++) + gInventory.updateItem(m_addGestures.get(idxGesture)); + gInventory.notifyObservers(); + + m_addGestures.clear(); + } +} + +// Checked: 2009-12-18 (RLVa-1.1.0k) | Added: RLVa-1.1.0i +void RlvForceWear::processRem() +{ + // Process attachments + if (m_remAttachments.size()) + { + // [See LLAgent::userRemoveAllAttachments()] + gMessageSystem->newMessage("ObjectDetach"); + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + + for (std::list::const_iterator itAttachPt = m_remAttachments.begin(); + itAttachPt != m_remAttachments.end(); ++itAttachPt) + { + LLViewerJointAttachment* pAttachPt = *itAttachPt; + if (pAttachPt->getObject()) + { + gMessageSystem->nextBlockFast(_PREHASH_ObjectData); + gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, pAttachPt->getObject()->getLocalID()); + } + } + + gMessageSystem->sendReliable(gAgent.getRegionHost()); + + m_remAttachments.clear(); + } + + // Process wearables + if (m_remWearables.size()) + { + for (std::list::const_iterator itWearable = m_remWearables.begin(); itWearable != m_remWearables.end(); ++itWearable) + gAgent.removeWearable(*itWearable); + + m_remWearables.clear(); + } + + // Process gestures + if (m_remGestures.size()) + { + for (S32 idxGesture = 0, cntGesture = m_remGestures.count(); idxGesture < cntGesture; idxGesture++) + { + LLViewerInventoryItem* pItem = m_remGestures.get(idxGesture); + gGestureManager.deactivateGesture(pItem->getUUID()); + gInventory.updateItem(pItem); + gInventory.notifyObservers(); + } + + m_remGestures.clear(); + } +} + +// Checked: 2010-02-17 (RLVa-1.1.0o) | Modified: RLVa-1.1.0o +void RlvForceWear::onWearableArrived(LLWearable* pWearable, void* pParam) +{ + #ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS + // If this wearable will end up replacing a currently worn one that belongs to a composite folder then we need to detach the composite + LLViewerInventoryCategory* pFolder = NULL; + if ( (RlvSettings::getEnableComposites()) && (pWearable) && (gAgent.getWearable(pWearable->getType())) ) + { + // If we're just rewearing the same item we're already wearing then we're not replacing a composite folder + LLWearableHoldingPattern* pWearData = (LLWearableHoldingPattern*)pParam; LLUUID idItem; + for (LLWearableHoldingPattern::found_list_t::const_iterator itWearable = pWearData->mFoundList.begin(); + itWearable != pWearData->mFoundList.end(); ++itWearable) + { + LLFoundData* pFound = *itWearable; + if (pWearable->getID() == pFound->mAssetID) + { + idItem = pFound->mItemID; + break; + } + } + if ( (idItem.notNull()) && (idItem != gAgent.getWearableItem(pWearable->getType())) && + (gRlvHandler.getCompositeInfo(gAgent.getWearableItem(pWearable->getType()), NULL, &pFolder)) ) + { + RlvForceWear rlvWear; + rlvWear.forceFolder(pFolder, ACTION_DETACH, FLAG_DEFAULT); + rlvWear.done(); + } + } + #endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS + + wear_inventory_category_on_avatar_loop(pWearable, pParam); +} + +// ============================================================================ +// RlvBehaviourNotifyObserver +// + +void RlvBehaviourNotifyObserver::changed(const RlvCommand& rlvCmd, bool fInternal) +{ + if (fInternal) + return; + + std::string strCmd = rlvCmd.asString(), strNotify; ERlvParamType eCmdType = rlvCmd.getParamType(); + if ( (RLV_TYPE_ADD == eCmdType) || (RLV_TYPE_REMOVE == eCmdType) ) + strNotify = llformat("/%s=%s", strCmd.c_str(), rlvCmd.getParam().c_str()); + else if (RLV_TYPE_CLEAR == eCmdType) + strNotify = llformat("/%s", strCmd.c_str()); + else + return; + + for (std::multimap::const_iterator itNotify = m_Notifications.begin(); + itNotify != m_Notifications.end(); ++itNotify) + { + if ( (itNotify->second.strFilter.empty()) || (std::string::npos != strCmd.find(itNotify->second.strFilter)) ) + rlvSendChatReply(itNotify->second.nChannel, strNotify); + } +} + +// ============================================================================ // RlvWLSnapshot // @@ -546,38 +987,6 @@ RlvWLSnapshot* RlvWLSnapshot::takeSnapshot() } // ========================================================================= -// RlvSettings -// - -BOOL RlvSettings::fShowNameTags = FALSE; - -BOOL RlvSettings::getEnableWear() -{ - return - rlvGetSettingBOOL(RLV_SETTING_ENABLEWEAR, TRUE) && // "Enable Wear" is toggled on and... - (!gRlvHandler.hasBehaviour(RLV_BHVR_DEFAULTWEAR)) && // not restricted and... - (!gRlvHandler.hasBehaviour(RLV_BHVR_ADDATTACH)); // we have attach points we can attach to [see RlvHandler::onAddRemAttach()] -} - -#ifdef RLV_EXTENSION_STARTLOCATION - // Checked: 2009-07-08 (RLVa-1.0.0e) | Modified: RLVa-0.2.1d - void RlvSettings::updateLoginLastLocation() - { - if (gSavedPerAccountSettings.controlExists(RLV_SETTING_LOGINLASTLOCATION)) - { - BOOL fValue = (gRlvHandler.hasBehaviour(RLV_BHVR_TPLOC)) || - ( (gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) && - (gAgent.getAvatarObject()) && (!gAgent.getAvatarObject()->mIsSitting) ); - if (gSavedPerAccountSettings.getBOOL(RLV_SETTING_LOGINLASTLOCATION) != fValue) - { - gSavedPerAccountSettings.setBOOL(RLV_SETTING_LOGINLASTLOCATION, fValue); - gSavedPerAccountSettings.saveToFile(gSavedSettings.getString("PerAccountSettingsFile"), TRUE); - } - } - } -#endif // RLV_EXTENSION_STARTLOCATION - -// ========================================================================= // Various helper classes/timers/functors // @@ -618,39 +1027,40 @@ void RlvCurrentlyWorn::fetchWorn() f.fetchItems(idItems); } -// Checked: 2009-07-06 (RLVa-1.0.0c) | Modified: RLVa-0.2.0f -bool RlvSelectHasLockedAttach::apply(LLSelectNode* pNode) -{ - return (pNode->getObject()) ? gRlvHandler.isLockedAttachment(pNode->getObject(), m_eLock) : false; -} - -// Checked: 2009-07-05 (RLVa-1.0.0b) | Modified: RLVa-0.2.0f -bool RlvSelectIsOwnedByOrGroupOwned::apply(LLSelectNode* pNode) +void RlvGiveToRLVAgentOffer::done() { - return (pNode->mPermissions->isGroupOwned()) || (pNode->mPermissions->getOwner() == m_idAgent); -} + LLViewerInventoryCategory* pRlvRoot = gRlvHandler.getSharedRoot(); + LLViewerInventoryCategory* pFolder = (mCompleteFolders.size()) ? gInventory.getCategory(mCompleteFolders[0]) : NULL; + if ( (pRlvRoot) && (pFolder) ) + { + std::string strName = pFolder->getName(); + if (strName.find(RLV_PUTINV_PREFIX) == 0) + { + LLInventoryModel::update_list_t update; + LLInventoryModel::LLCategoryUpdate updOldParent(pFolder->getParentUUID(), -1); + update.push_back(updOldParent); + LLInventoryModel::LLCategoryUpdate updNewParent(pRlvRoot->getUUID(), 1); + update.push_back(updNewParent); + gInventory.accountForUpdate(update); + + LLPointer pNewFolder = new LLViewerInventoryCategory(pFolder); + pNewFolder->setParent(pRlvRoot->getUUID()); + pNewFolder->updateParentOnServer(FALSE); + pNewFolder->rename(strName.erase(0, strName.find(RLV_FOLDER_PREFIX_PUTINV))); + pNewFolder->updateServer(FALSE); + gInventory.updateCategory(pNewFolder); + } + } -// Checked: 2009-05-31 (RLVa-0.2.0f) | Modified: RLVa-0.2.0f -bool RlvSelectIsSittingOn::apply(LLSelectNode* pNode) -{ - return (pNode->getObject()) && (pNode->getObject()->getRootEdit() == m_pObject); + gInventory.removeObserver(this); + gInventory.notifyObservers(); + delete this; } // ============================================================================ // Various helper functions // -// Checked: 2009-10-10 (RLVa-1.0.5a) | Modified: RLVa-1.0.5a -BOOL rlvAttachToEnabler(void* pParam) -{ - // Disable an option on the "Attach to (HUD)" submenu if: - // - the attachment point is locked non-detachable with an object attached - // - the attachment point is locked non-attachable - return (pParam != NULL) && - (!gRlvHandler.isLockedAttachment(((LLViewerJointAttachment*)pParam)->getObject(), RLV_LOCK_REMOVE)) && - (!gRlvHandler.isLockedAttachment((LLViewerJointAttachment*)pParam, RLV_LOCK_ADD)); -} - // Checked: 2009-07-05 (RLVa-1.0.0b) | Modified: RLVa-0.2.0g bool rlvCanDeleteOrReturn() { @@ -677,13 +1087,6 @@ bool rlvCanDeleteOrReturn() return fIsAllowed; } -// Checked: 2009-10-04 (RLVa-1.0.4b) | Modified: RLVa-1.0.4b -BOOL rlvEnableWearEnabler(void* pParam) -{ - // Visually disables the "Enable Wear" option when restricted from toggling it - return (!gRlvHandler.hasBehaviour(RLV_BHVR_DEFAULTWEAR)); -} - // Checked: 2009-05-26 (RLVa-0.2.0d) | Modified: RLVa-0.2.0d S32 rlvGetDirectDescendentsCount(const LLInventoryCategory* pFolder, LLAssetType::EType type) { @@ -712,12 +1115,12 @@ S32 rlvGetDirectDescendentsCount(const LLInventoryCategory* pFolder, LLAssetType #if RLV_TARGET < RLV_MAKE_TARGET(1, 23, 0) // Version: 1.22.11 LLStringUtil::format_map_t args; - args["[MESSAGE]"] = llformat("Restrained Life Support will be %s after you restart", + args["[MESSAGE]"] = llformat("RestrainedLove Support will be %s after you restart", (rlv_handler_t::isEnabled()) ? "disabled" : "enabled" ); gViewerWindow->alertXml("GenericAlert", args); #else // Version: 1.23.4 LLSD args; - args["MESSAGE"] = llformat("Restrained Life Support will be %s after you restart", + args["MESSAGE"] = llformat("RestrainedLove Support will be %s after you restart", (rlv_handler_t::isEnabled()) ? "disabled" : "enabled" ); LLNotifications::instance().add("GenericAlert", args); #endif -- cgit v1.1