diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index af7448526..904a77ee3 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -22,6 +22,7 @@ set(llcommon_SOURCE_FILES llbase32.cpp llbase64.cpp llcommon.cpp + llcommonutils.cpp llcrc.cpp llcriticaldamp.cpp llcursortypes.cpp @@ -96,6 +97,7 @@ set(llcommon_HEADER_FILES llchat.h llclickaction.h llcommon.h + llcommonutils.h llcrc.h llcriticaldamp.h llcursortypes.h diff --git a/indra/llcommon/indra_constants.h b/indra/llcommon/indra_constants.h index 2302ec661..2c7d701a1 100644 --- a/indra/llcommon/indra_constants.h +++ b/indra/llcommon/indra_constants.h @@ -255,6 +255,10 @@ const U8 SIM_ACCESS_MAX = SIM_ACCESS_ADULT; // group constants const S32 MAX_AGENT_GROUPS = 25; +// attachment constants +const S32 MAX_AGENT_ATTACHMENTS = 38; +const U8 ATTACHMENT_ADD = 0x80; + // god levels const U8 GOD_MAINTENANCE = 250; const U8 GOD_FULL = 200; diff --git a/indra/llcommon/llassettype.cpp b/indra/llcommon/llassettype.cpp index cf3bf89b4..9d35f1dda 100644 --- a/indra/llcommon/llassettype.cpp +++ b/indra/llcommon/llassettype.cpp @@ -70,7 +70,13 @@ asset_info_t asset_types[] = { LLAssetType::AT_ANIMATION, "ANIMATION" }, { LLAssetType::AT_GESTURE, "GESTURE" }, { LLAssetType::AT_SIMSTATE, "SIMSTATE" }, - { LLAssetType::AT_NONE, "NONE" }, + { LLAssetType::AT_FAVORITE, "FAVORITE" }, + { LLAssetType::AT_LINK, "LINK" }, + { LLAssetType::AT_LINK_FOLDER, "CURRENT" }, + { LLAssetType::AT_CURRENT_OUTFIT, "FOLDER_LINK" }, + { LLAssetType::AT_OUTFIT, "OUTFIT" }, + { LLAssetType::AT_MY_OUTFITS, "MY_OUTFITS" }, + { LLAssetType::AT_NONE, "NONE" } }; LLAssetType::EType LLAssetType::getType(const std::string& sin) @@ -129,7 +135,33 @@ const char* LLAssetType::mAssetTypeNames[LLAssetType::AT_COUNT] = "jpeg", "animatn", "gesture", - "simstate" + "simstate", + "favorite", + "link", + "link_f", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "current", + "outfit", + "my_otfts" }; // This table is meant for decoding to human readable form. Put any @@ -159,7 +191,33 @@ const char* LLAssetType::mAssetTypeHumanNames[LLAssetType::AT_COUNT] = "jpeg image", "animation", "gesture", - "simstate" + "simstate", + "", + "symbolic link", + "symbolic folder link" + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "current outfit", + "outfit", + "my outfits" }; ///---------------------------------------------------------------------------- @@ -248,6 +306,12 @@ EDragAndDropType LLAssetType::lookupDragAndDropType( EType asset ) case AT_BODYPART: return DAD_BODYPART; case AT_ANIMATION: return DAD_ANIMATION; case AT_GESTURE: return DAD_GESTURE; + case AT_FAVORITE: return DAD_CATEGORY; + case AT_LINK: return DAD_LINK; + case AT_LINK_FOLDER: return DAD_LINK; + case AT_CURRENT_OUTFIT: return DAD_LINK; + case AT_OUTFIT: return DAD_LINK; + case AT_MY_OUTFITS: return DAD_CATEGORY; default: return DAD_NONE; }; } @@ -265,3 +329,17 @@ void LLAssetType::generateDescriptionFor(LLAssetType::EType type, desc.assign(time_str); desc.append(LLAssetType::lookupHumanReadable(type)); } + +// static +bool LLAssetType::lookupCanLink(EType asset_type) +{ + return (asset_type == AT_CLOTHING || asset_type == AT_OBJECT || asset_type == AT_CATEGORY || + asset_type == AT_BODYPART || asset_type == AT_GESTURE); +} + +// static +// Not adding this to dictionary since we probably will only have these two types +bool LLAssetType::lookupIsLinkType(EType asset_type) +{ + return (asset_type == AT_LINK || asset_type == AT_LINK_FOLDER); +} diff --git a/indra/llcommon/llassettype.h b/indra/llcommon/llassettype.h index 9f611aec9..83bf8b629 100644 --- a/indra/llcommon/llassettype.h +++ b/indra/llcommon/llassettype.h @@ -131,6 +131,20 @@ public: // simstate file AT_SIMSTATE = 22, + AT_FAVORITE = 23, + + // Inventory symbolic link + AT_LINK = 24, + + // Inventory folder link + AT_LINK_FOLDER = 25, + + AT_CURRENT_OUTFIT = 46, + + AT_OUTFIT = 47, + + AT_MY_OUTFITS = 48, + // +*********************************************+ // | TO ADD AN ELEMENT TO THIS ENUM: | // +*********************************************+ @@ -140,7 +154,7 @@ public: // | 4. ADD TO LLAssetType::mAssetTypeHumanNames | // +*********************************************+ - AT_COUNT = 23, + AT_COUNT = 49, AT_NONE = -1 }; @@ -165,6 +179,9 @@ public: static EType getType(const std::string& sin); static std::string getDesc(EType type); + static bool lookupCanLink(EType asset_type); + static bool lookupIsLinkType(EType asset_type); + private: // don't instantiate or derive one of these objects LLAssetType( void ) {} diff --git a/indra/llcommon/llcommonutils.cpp b/indra/llcommon/llcommonutils.cpp new file mode 100644 index 000000000..d82554c20 --- /dev/null +++ b/indra/llcommon/llcommonutils.cpp @@ -0,0 +1,56 @@ +/** + * @file llcommonutils.h + * @brief Commin utils + * + * $LicenseInfo:firstyear=2010&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "llcommonutils.h" + +void LLCommonUtils::computeDifference( + const uuid_vec_t& vnew, + const uuid_vec_t& vcur, + uuid_vec_t& vadded, + uuid_vec_t& vremoved) +{ + uuid_vec_t vnew_copy(vnew); + uuid_vec_t vcur_copy(vcur); + + std::sort(vnew_copy.begin(), vnew_copy.end()); + std::sort(vcur_copy.begin(), vcur_copy.end()); + + size_t maxsize = llmax(vnew_copy.size(), vcur_copy.size()); + vadded.resize(maxsize); + vremoved.resize(maxsize); + + uuid_vec_t::iterator it; + // what was removed + it = set_difference(vcur_copy.begin(), vcur_copy.end(), vnew_copy.begin(), vnew_copy.end(), vremoved.begin()); + vremoved.erase(it, vremoved.end()); + + // what was added + it = set_difference(vnew_copy.begin(), vnew_copy.end(), vcur_copy.begin(), vcur_copy.end(), vadded.begin()); + vadded.erase(it, vadded.end()); +} + +// EOF diff --git a/indra/llcommon/llcommonutils.h b/indra/llcommon/llcommonutils.h new file mode 100644 index 000000000..fc1f3b044 --- /dev/null +++ b/indra/llcommon/llcommonutils.h @@ -0,0 +1,54 @@ +/** + * @file llcommonutils.h + * @brief Common utils + * + * $LicenseInfo:firstyear=2010&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLCOMMONUTILS_H +#define LL_LLCOMMONUTILS_H + +#include "llpreprocessor.h" +#include "lluuid.h" + +namespace LLCommonUtils +{ + /** + * Computes difference between 'vnew' and 'vcur' vectors. + * Items present in 'vnew' and missing in 'vcur' are treated as added and are copied into 'vadded' + * Items missing in 'vnew' and present in 'vcur' are treated as removed and are copied into 'vremoved' + * + * @param vnew[in] - incoming IDs + * @param vcur[in] - current IDs + * @param vadded[out] - difference between incoming and current IDS - added IDs + * @param vremoved[out] - difference between incoming and current IDS - removed IDs + */ + LL_COMMON_API void computeDifference( + const uuid_vec_t& vnew, + const uuid_vec_t& vcur, + uuid_vec_t& vadded, + uuid_vec_t& vremoved); +}; + +#endif //LL_LLCOMMONUTILS_H + +// EOF diff --git a/indra/llcommon/lluuid.h b/indra/llcommon/lluuid.h index c78fb1201..c54fd6be8 100644 --- a/indra/llcommon/lluuid.h +++ b/indra/llcommon/lluuid.h @@ -34,6 +34,7 @@ #include #include +#include #include "stdtypes.h" #include "llpreprocessor.h" @@ -132,7 +133,7 @@ public: U8 mData[UUID_BYTES]; }; - +typedef std::vector uuid_vec_t; // Construct inline LLUUID::LLUUID() diff --git a/indra/llcommon/stdenums.h b/indra/llcommon/stdenums.h index 41da51fce..1a5678dde 100644 --- a/indra/llcommon/stdenums.h +++ b/indra/llcommon/stdenums.h @@ -54,7 +54,8 @@ enum EDragAndDropType DAD_BODYPART = 11, DAD_ANIMATION = 12, DAD_GESTURE = 13, - DAD_COUNT = 14, // number of types in this enum + DAD_LINK = 14, + DAD_COUNT = 15, // number of types in this enum }; // Reasons for drags to be denied. diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp index b1cfd6866..bb82966fd 100644 --- a/indra/llinventory/llinventory.cpp +++ b/indra/llinventory/llinventory.cpp @@ -126,6 +126,25 @@ const std::string& LLInventoryObject::getName() const return mName; } +// To bypass linked items, since llviewerinventory's getType +// will return the linked-to item's type instead of this object's type. +LLAssetType::EType LLInventoryObject::getActualType() const +{ + return mType; +} + +BOOL LLInventoryObject::getIsLinkType() const +{ + return LLAssetType::lookupIsLinkType(mType); +} + +// See LLInventoryItem override. +// virtual +const LLUUID& LLInventoryObject::getLinkedUUID() const +{ + return mUUID; +} + LLAssetType::EType LLInventoryObject::getType() const { return mType; @@ -342,6 +361,19 @@ void LLInventoryItem::cloneItem(LLPointer& newitem) const newitem->mUUID.generate(); } +// If this is a linked item, then the UUID of the base object is +// this item's assetID. +// virtual +const LLUUID& LLInventoryItem::getLinkedUUID() const +{ + if (LLAssetType::lookupIsLinkType(getActualType())) + { + return mAssetUUID; + } + + return LLInventoryObject::getLinkedUUID(); +} + const LLPermissions& LLInventoryItem::getPermissions() const { return mPermissions; diff --git a/indra/llinventory/llinventory.h b/indra/llinventory/llinventory.h index 937e12dbc..982dad545 100644 --- a/indra/llinventory/llinventory.h +++ b/indra/llinventory/llinventory.h @@ -89,14 +89,16 @@ public: void copyObject(const LLInventoryObject* other); // LLRefCount requires custom copy // accessors - const LLUUID& getUUID() const; + virtual const LLUUID& getUUID() const; const LLUUID& getParentUUID() const; - const std::string& getName() const; - LLAssetType::EType getType() const; - + virtual const LLUUID& getLinkedUUID() const; // get the inventoryID that this item points to, else this item's inventoryID + virtual const std::string& getName() const; + virtual LLAssetType::EType getType() const; + LLAssetType::EType getActualType() const; // bypasses indirection for linked items + BOOL getIsLinkType() const; // mutators - will not call updateServer(); void setUUID(const LLUUID& new_uuid); - void rename(const std::string& new_name); + virtual void rename(const std::string& new_name); void setParent(const LLUUID& new_parent); void setType(LLAssetType::EType type); @@ -231,15 +233,16 @@ public: virtual void cloneItem(LLPointer& newitem) const; // accessors - const LLPermissions& getPermissions() const; - const LLUUID& getCreatorUUID() const; - const LLUUID& getAssetUUID() const; - const std::string& getDescription() const; - const LLSaleInfo& getSaleInfo() const; - LLInventoryType::EType getInventoryType() const; - U32 getFlags() const; - time_t getCreationDate() const; - U32 getCRC32() const; // really more of a checksum. + virtual const LLUUID& getLinkedUUID() const; + virtual const LLPermissions& getPermissions() const; + virtual const LLUUID& getCreatorUUID() const; + virtual const LLUUID& getAssetUUID() const; + virtual const std::string& getDescription() const; + virtual const LLSaleInfo& getSaleInfo() const; + virtual LLInventoryType::EType getInventoryType() const; + virtual U32 getFlags() const; + virtual time_t getCreationDate() const; + virtual U32 getCRC32() const; // really more of a checksum. // mutators - will not call updateServer(), and will never fail // (though it may correct to sane values) diff --git a/indra/llinventory/llinventorytype.cpp b/indra/llinventory/llinventorytype.cpp index a161a0ee0..3754a98b7 100644 --- a/indra/llinventory/llinventorytype.cpp +++ b/indra/llinventory/llinventorytype.cpp @@ -120,6 +120,33 @@ DEFAULT_ASSET_FOR_INV_TYPE[LLAssetType::AT_COUNT] = LLInventoryType::IT_NONE, // AT_IMAGE_JPEG LLInventoryType::IT_ANIMATION, // AT_ANIMATION LLInventoryType::IT_GESTURE, // AT_GESTURE + LLInventoryType::IT_NONE, // AT_SIMSTATE + LLInventoryType::IT_NONE, // AT_FAVORITE + LLInventoryType::IT_NONE, // AT_LINK + LLInventoryType::IT_NONE, // AT_LINK_FOLDER + LLInventoryType::IT_NONE, // FT_ENSEMBLE_START + LLInventoryType::IT_NONE, // + LLInventoryType::IT_NONE, // + LLInventoryType::IT_NONE, // + LLInventoryType::IT_NONE, // + LLInventoryType::IT_NONE, // + LLInventoryType::IT_NONE, // + LLInventoryType::IT_NONE, // + LLInventoryType::IT_NONE, // + LLInventoryType::IT_NONE, // + LLInventoryType::IT_NONE, // + LLInventoryType::IT_NONE, // + LLInventoryType::IT_NONE, // + LLInventoryType::IT_NONE, // + LLInventoryType::IT_NONE, // + LLInventoryType::IT_NONE, // + LLInventoryType::IT_NONE, // + LLInventoryType::IT_NONE, // + LLInventoryType::IT_NONE, // + LLInventoryType::IT_NONE, // FT_ENSEMBLE_END + LLInventoryType::IT_NONE, // AT_CURRENT_OUTFIT + LLInventoryType::IT_NONE, // AT_OUTFIT + LLInventoryType::IT_NONE // AT_MY_OUTFITS }; static const int MAX_POSSIBLE_ASSET_TYPES = 2; diff --git a/indra/llmessage/lltransfersourceasset.cpp b/indra/llmessage/lltransfersourceasset.cpp index a4d59275b..d1bfeb4fc 100644 --- a/indra/llmessage/lltransfersourceasset.cpp +++ b/indra/llmessage/lltransfersourceasset.cpp @@ -292,6 +292,8 @@ bool is_asset_id_knowable(LLAssetType::EType type) case LLAssetType::AT_BODYPART: case LLAssetType::AT_ANIMATION: case LLAssetType::AT_GESTURE: + case LLAssetType::AT_LINK: + case LLAssetType::AT_LINK_FOLDER: rv = true; break; default: diff --git a/indra/llmessage/message_prehash.cpp b/indra/llmessage/message_prehash.cpp index 9f10153e5..892547cab 100644 --- a/indra/llmessage/message_prehash.cpp +++ b/indra/llmessage/message_prehash.cpp @@ -174,6 +174,7 @@ char* _PREHASH_UpdateInventoryItem = LLMessageStringTable::getInstance()->getStr char* _PREHASH_UpdateCreateInventoryItem = LLMessageStringTable::getInstance()->getString("UpdateCreateInventoryItem"); char* _PREHASH_MoveInventoryItem = LLMessageStringTable::getInstance()->getString("MoveInventoryItem"); char* _PREHASH_CopyInventoryItem = LLMessageStringTable::getInstance()->getString("CopyInventoryItem"); +char* _PREHASH_LinkInventoryItem = LLMessageStringTable::getInstance()->getString("LinkInventoryItem"); char* _PREHASH_RemoveInventoryItem = LLMessageStringTable::getInstance()->getString("RemoveInventoryItem"); char* _PREHASH_CreateInventoryItem = LLMessageStringTable::getInstance()->getString("CreateInventoryItem"); char* _PREHASH_PathTwistBegin = LLMessageStringTable::getInstance()->getString("PathTwistBegin"); diff --git a/indra/llmessage/message_prehash.h b/indra/llmessage/message_prehash.h index 8d1708fad..4bf89e513 100644 --- a/indra/llmessage/message_prehash.h +++ b/indra/llmessage/message_prehash.h @@ -174,6 +174,7 @@ extern char * _PREHASH_UpdateInventoryItem; extern char * _PREHASH_UpdateCreateInventoryItem; extern char * _PREHASH_MoveInventoryItem; extern char * _PREHASH_CopyInventoryItem; +extern char * _PREHASH_LinkInventoryItem; extern char * _PREHASH_RemoveInventoryItem; extern char * _PREHASH_CreateInventoryItem; extern char * _PREHASH_PathTwistBegin; diff --git a/indra/llxml/llcontrol.cpp b/indra/llxml/llcontrol.cpp index b8e2f5c11..f57646b8e 100644 --- a/indra/llxml/llcontrol.cpp +++ b/indra/llxml/llcontrol.cpp @@ -1159,15 +1159,6 @@ U32 LLControlGroup::loadFromFile(const std::string& filename, bool set_default_v hidefromsettingseditor = false; } -// [RLVa:KB] - Checked: 2010-06-20 (RLVa-1.1.2a) | Added: RLVa-1.1.2a - // HACK-RLVa: bad code but it's just a temporary measure to provide a smooth changeover from the old to the new rebranded settings - if ( (name.length() >= 14) && (0 == name.find("RestrainedLife")) ) - { - // Transparently convert the old settings name to the new one while preserving the user override - name = "RestrainedLove" + name.substr(14); - } -// [/RLVa:KB] - // If the control exists just set the value from the input file. LLControlVariable* existing_control = getControl(name); if(existing_control) diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 12fd907e8..5d38149f8 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -64,6 +64,7 @@ include_directories( ) set(viewer_SOURCE_FILES + cofmgr.cpp ascentdaycyclemanager.cpp ascentfloatercontactgroups.cpp ascentprefssys.cpp @@ -94,6 +95,7 @@ set(viewer_SOURCE_FILES llassetconverter.cpp llassetuploadresponders.cpp llassetuploadqueue.cpp + llattachmentsmgr.cpp llaudiosourcevo.cpp llbbox.cpp llbox.cpp @@ -498,9 +500,11 @@ set(viewer_SOURCE_FILES rlvhandler.cpp rlvhelper.cpp rlvcommon.cpp - rlvmultistringsearch.cpp + rlvlocks.cpp + rlvinventory.cpp rlvextensions.cpp rlvfloaterbehaviour.cpp + rlvviewer2.cpp shcommandhandler.cpp ) @@ -525,6 +529,8 @@ endif (LINUX) set(viewer_HEADER_FILES CMakeLists.txt ViewerInstall.cmake + + cofmgr.h ascentdaycyclemanager.h ascentfloatercontactgroups.h ascentprefssys.h @@ -554,6 +560,7 @@ set(viewer_HEADER_FILES llassetconverter.h llassetuploadresponders.h llassetuploadqueue.h + llattachmentsmgr.h llaudiosourcevo.h llbbox.h llbox.h @@ -968,9 +975,11 @@ set(viewer_HEADER_FILES rlvhandler.h rlvhelper.h rlvcommon.h - rlvmultistringsearch.h + rlvlocks.h + rlvinventory.h rlvextensions.h rlvfloaterbehaviour.h + rlvviewer2.h shcommandhandler.h ) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 8aa946aae..4e370312a 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -1063,6 +1063,50 @@ Value 0 + RestrainedLoveOffsetAvatarZ + + Comment + Offset the avatar. + Persist + 1 + Type + F32 + Value + 0.0 + + RestrainedLoveReplaceWhenFolderBeginsWith + + Comment + If a folder name begins with this string, its attach behavior will always be "replace", never "stack". Default is blank (disabled). + Persist + 1 + Type + String + Value + + + RestrainedLoveStackWhenFolderBeginsWith + + Comment + If a folder name begins with this string, its attach behavior will always be "stack", never "replace". Default is "+". + Persist + 1 + Type + String + Value + + + + RLVaDebugHideUnsetDuplicate + + Comment + Suppresses reporting "unset" or "duplicate" command restrictions when RestrainedLoveDebug is TRUE + Persist + 1 + Type + Boolean + Value + 0 + RestrainedLoveForbidGiveToRLV Comment @@ -1096,21 +1140,10 @@ Value 1 - RLVaEnableWear - - Comment - Enables the "Wear" option on the inventory item context menu for attachments - Persist - 1 - Type - Boolean - Value - 1 - RLVaEnableSharedWear Comment - Attachments in the shared #RLV folder can be force-attached without needing to specify an attachment point (as long as no attachment is non-detachable) + Attachments in the shared #RLV folder can be force-attached without needing to specify an attachment point Persist 1 Type @@ -1162,39 +1195,6 @@ Value 0 - WarnFirstRLVDetach - - Comment - Enables FirstRLVDetach warning dialog - Persist - 1 - Type - Boolean - Value - 1 - - WarnFirstRLVEnableWear - - Comment - Enables RLVEnableWear warning dialog - Persist - 1 - Type - Boolean - Value - 1 - - WarnFirstRLVFartouch - - Comment - Enables FirstRLVFartouch warning dialog - Persist - 1 - Type - Boolean - Value - 1 - WarnFirstRLVGiveToRLV Comment @@ -8057,6 +8057,17 @@ Value 0 + LegacyMultiAttachmentSupport + + Comment + Converts legacy "secondary attachment points" to multi-attachments for other avatars + Persist + 1 + Type + Boolean + Value + 1 + LimitDragDistance Comment @@ -13701,6 +13712,17 @@ Value 0 + UseInventoryLinks + + Comment + When making a new outfit, use links for no-copy items + Persist + 1 + Type + Boolean + Value + 1 + UseOcclusion Comment @@ -13712,6 +13734,17 @@ Value 1 + UseOutfitFolders + + Comment + When making a new outfit, use Viewer 2 outfit folders + Persist + 1 + Type + Boolean + Value + 1 + RenderDelayVBUpdate Comment diff --git a/indra/newview/cofmgr.cpp b/indra/newview/cofmgr.cpp new file mode 100644 index 000000000..b9f3dadc7 --- /dev/null +++ b/indra/newview/cofmgr.cpp @@ -0,0 +1,508 @@ +/** + * + * Copyright (c) 2010, Kitty Barnett + * + * The source code in this file is provided to you under the terms of the + * GNU General Public License, version 2.0, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. Terms of the GPL can be found in doc/GPL-license.txt + * in this distribution, or online at http://www.gnu.org/licenses/gpl-2.0.txt + * + * By copying, modifying or distributing this software, you acknowledge that + * you have read and understood your obligations described above, and agree to + * abide by those obligations. + * + */ + +#include "llviewerprecompiledheaders.h" +#include "cofmgr.h" +#include "llagent.h" +#include "llcommonutils.h" +#include "llerror.h" +#include "llvoavatar.h" +#include "rlvviewer2.h" + +// ============================================================================ +// Inventory helper classes +// + +class LLCOFLinkTargetFetcher : public LLInventoryFetchItemsObserver +{ +public: + LLCOFLinkTargetFetcher(const uuid_vec_t& idItems) : LLInventoryFetchItemsObserver(idItems) {} + /*virtual*/ ~LLCOFLinkTargetFetcher() {} + + /*virtual*/ void done() + { + // We shouldn't be messing with inventory items during LLInventoryModel::notifyObservers() + doOnIdleOneTime(boost::bind(&LLCOFLinkTargetFetcher::doneIdle, this)); + gInventory.removeObserver(this); + } + + void doneIdle() + { + LLCOFMgr::instance().checkCOF(); + LLCOFMgr::instance().setLinkAttachments(true); + LLCOFMgr::instance().updateAttachments(); + LLCOFMgr::instance().synchWearables(); + + delete this; + } +}; + +class LLCOFFetcher : public LLInventoryFetchDescendentsObserver +{ +public: + LLCOFFetcher() {} + /*virtual*/ ~LLCOFFetcher() {} + + /*virtual*/ void done() + { + // We shouldn't be messing with inventory items during LLInventoryModel::notifyObservers() + doOnIdleOneTime(boost::bind(&LLCOFFetcher::doneIdle, this)); + gInventory.removeObserver(this); + } + + void doneIdle() + { + uuid_vec_t idItems; + + // Add the link targets for COF + LLInventoryModel::cat_array_t folders; LLInventoryModel::item_array_t items; + gInventory.collectDescendents(LLCOFMgr::getCOF(), folders, items, LLInventoryModel::EXCLUDE_TRASH); + for (S32 idxItem = 0; idxItem < items.count(); idxItem++) + { + const LLViewerInventoryItem* pItem = items.get(idxItem); + if (!pItem) + continue; + idItems.push_back(pItem->getLinkedUUID()); + } + + // Add all currently worn wearables + for (S32 idxType = 0; idxType < WT_COUNT; idxType++) + { + const LLUUID& idItem = gAgent.getWearableItem((EWearableType)idxType); + if (idItem.isNull()) + continue; + idItems.push_back(idItem); + } + + // Add all currently worn attachments + const LLVOAvatar* pAvatar = gAgent.getAvatarObject(); + if (pAvatar) + { + for (LLVOAvatar::attachment_map_t::const_iterator itAttachPt = pAvatar->mAttachmentPoints.begin(); + itAttachPt != pAvatar->mAttachmentPoints.end(); ++itAttachPt) + { + const LLViewerJointAttachment* pAttachPt = itAttachPt->second; + for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator itAttachment = pAttachPt->mAttachedObjects.begin(); + itAttachment != pAttachPt->mAttachedObjects.end(); ++itAttachment) + { + const LLUUID& idItem = (*itAttachment)->getAttachmentItemID(); + if (idItem.isNull()) + continue; + idItems.push_back(idItem); + } + } + } + + // Fetch it all + LLCOFLinkTargetFetcher* pFetcher = new LLCOFLinkTargetFetcher(idItems); + pFetcher->startFetch(); + if (pFetcher->isFinished()) + { + pFetcher->done(); + } + else + { + gInventory.addObserver(pFetcher); + + // It doesn't look like we *really* need the link targets so we can do a preliminary initialization now already + LLCOFMgr::instance().setLinkAttachments(true); + LLCOFMgr::instance().updateAttachments(); + } + + delete this; + } +}; + +class LLDeferredAddLinkTargetFetcher : public LLInventoryFetchItemsObserver +{ +public: + LLDeferredAddLinkTargetFetcher(const LLUUID& idItem, LLPointer cb) + : LLInventoryFetchItemsObserver(idItem), m_Callback(cb) + {} + LLDeferredAddLinkTargetFetcher(const uuid_vec_t& idItems, LLPointer cb) + : LLInventoryFetchItemsObserver(idItems), m_Callback(cb) + {} + /*virtual*/ ~LLDeferredAddLinkTargetFetcher() {} + + /*virtual*/ void done() + { + // We shouldn't be messing with inventory items during LLInventoryModel::notifyObservers() + doOnIdleOneTime(boost::bind(&LLDeferredAddLinkTargetFetcher::doneIdle, this)); + gInventory.removeObserver(this); + } + + void doneIdle() + { + for (uuid_vec_t::const_iterator itItemId = mComplete.begin(); itItemId != mComplete.end(); ++itItemId) + { + const LLViewerInventoryItem* pItem = gInventory.getItem(*itItemId); + if (!pItem) + continue; + LLCOFMgr::instance().addCOFItemLink(pItem, m_Callback); + } + delete this; + } +protected: + LLPointer m_Callback; +}; + +class LLLinkAttachmentCallback : public LLInventoryCallback +{ +public: + LLLinkAttachmentCallback() {} + /*virtual*/ ~LLLinkAttachmentCallback() {} + /*virtual*/ void fire(const LLUUID& idItem) { LLCOFMgr::instance().onLinkAttachmentComplete(idItem); } +}; + +class LLLinkWearableCallback : public LLInventoryCallback +{ +public: + LLLinkWearableCallback() {} + /*virtual*/ ~LLLinkWearableCallback() {} + /*virtual*/ void fire(const LLUUID& idItem) { LLCOFMgr::instance().onLinkWearableComplete(idItem); } +}; + +// ============================================================================ +// Helper functions +// + +void LLCOFMgr::checkCOF() +{ + const LLUUID idCOF = getCOF(); + const LLUUID idLAF = gInventory.findCategoryUUIDForType(LLAssetType::AT_LOST_AND_FOUND); + + // Check COF for non-links and move them to Lost&Found + LLInventoryModel::cat_array_t* pFolders; LLInventoryModel::item_array_t* pItems; + gInventory.getDirectDescendentsOf(idCOF, pFolders, pItems); + for (S32 idxFolder = 0, cntFolder = pFolders->count(); idxFolder < cntFolder; idxFolder++) + { + LLViewerInventoryCategory* pFolder = pFolders->get(idxFolder).get(); + if ( (pFolder) && (idLAF.notNull()) ) + change_category_parent(&gInventory, pFolder, idLAF, false); + } + for (S32 idxItem = 0, cntItem = pItems->count(); idxItem < cntItem; idxItem++) + { + LLViewerInventoryItem* pItem = pItems->get(idxItem).get(); + if ( (pItem) && (!pItem->getIsLinkType()) && (idLAF.notNull()) ) + change_item_parent(&gInventory, pItem, idLAF, false); + } +} + +void LLCOFMgr::fetchCOF() +{ + static bool sFetched = false; + if (!sFetched) + { + const LLUUID idCOF = getCOF(); + if (idCOF.isNull()) + { + LL_ERRS("COFMgr") << "Unable to find (or create) COF" << LL_ENDL; + return; + } + + LLInventoryFetchDescendentsObserver::folder_ref_t fetchFolders; + fetchFolders.push_back(idCOF); + + LLCOFFetcher* pFetcher = new LLCOFFetcher(); + pFetcher->fetchDescendents(fetchFolders); + if (pFetcher->isEverythingComplete()) + pFetcher->done(); + else + gInventory.addObserver(pFetcher); + + sFetched = true; + } +} + +void LLCOFMgr::getDescendentsOfAssetType(const LLUUID& idCat, LLInventoryModel::item_array_t& items, + LLAssetType::EType typeAsset, bool fFollowFolderLinks) +{ + LLInventoryModel::cat_array_t folders; + LLIsType f(typeAsset); + gInventory.collectDescendentsIf(idCat, folders, items, LLInventoryModel::EXCLUDE_TRASH, f, fFollowFolderLinks); +} + +void LLCOFMgr::addCOFItemLink(const LLUUID& idItem, LLPointer cb) +{ + const LLViewerInventoryItem *pItem = gInventory.getItem(idItem); + if (!pItem) + { + LLDeferredAddLinkTargetFetcher* pFetcher = new LLDeferredAddLinkTargetFetcher(idItem, cb); + pFetcher->startFetch(); + gInventory.addObserver(pFetcher); + return; + } + addCOFItemLink(pItem, cb); +} + +void LLCOFMgr::addCOFItemLink(const LLInventoryItem* pItem, LLPointer cb) +{ + if ( (!pItem) || (isLinkInCOF(pItem->getLinkedUUID())) ) + { + return; + } + + gInventory.addChangedMask(LLInventoryObserver::LABEL, pItem->getLinkedUUID()); + + const std::string strDescr = (pItem->getIsLinkType()) ? pItem->getDescription() : ""; + link_inventory_item(gAgent.getID(), pItem->getLinkedUUID(), getCOF(), pItem->getName(), strDescr, LLAssetType::AT_LINK, cb); +} + +bool LLCOFMgr::isLinkInCOF(const LLUUID& idItem) +{ + LLInventoryModel::cat_array_t folders; LLInventoryModel::item_array_t items; + LLLinkedItemIDMatches f(gInventory.getLinkedItemID(idItem)); + gInventory.collectDescendentsIf(getCOF(), folders, items, LLInventoryModel::EXCLUDE_TRASH, f); + return (!items.empty()); +} + +void LLCOFMgr::removeCOFItemLinks(const LLUUID& idItem) +{ + gInventory.addChangedMask(LLInventoryObserver::LABEL, idItem); + + LLInventoryModel::cat_array_t folders; LLInventoryModel::item_array_t items; + gInventory.collectDescendents(getCOF(), folders, items, LLInventoryModel::EXCLUDE_TRASH); + + for (S32 idxItem = 0; idxItem < items.count(); idxItem++) + { + const LLInventoryItem* pItem = items.get(idxItem).get(); + if ( (pItem->getIsLinkType()) && (idItem == pItem->getLinkedUUID()) ) + gInventory.purgeObject(pItem->getUUID()); + } +} + +// ============================================================================ +// Attachment functions +// + +void LLCOFMgr::addAttachment(const LLUUID& idItem) +{ + if ( (isLinkInCOF(idItem)) || (std::find(m_PendingAttachLinks.begin(), m_PendingAttachLinks.end(), idItem) != m_PendingAttachLinks.end()) ) + { + return; + } + + gInventory.addChangedMask(LLInventoryObserver::LABEL, idItem); + m_PendingAttachLinks.push_back(idItem); + + if (m_fLinkAttachments) + { + LLPointer cb = new LLLinkAttachmentCallback(); + addCOFItemLink(idItem, cb); + } +} + +void LLCOFMgr::removeAttachment(const LLUUID& idItem) +{ + gInventory.addChangedMask(LLInventoryObserver::LABEL, idItem); + + // Remove the attachment from the pending list + uuid_vec_t::iterator itPending = std::find(m_PendingAttachLinks.begin(), m_PendingAttachLinks.end(), idItem); + if (itPending != m_PendingAttachLinks.end()) + m_PendingAttachLinks.erase(itPending); + + if (m_fLinkAttachments) + { + removeCOFItemLinks(idItem); + } +} + +void LLCOFMgr::setLinkAttachments(bool fEnable) +{ + m_fLinkAttachments = fEnable; + + if (m_fLinkAttachments) + linkPendingAttachments(); +} + +void LLCOFMgr::linkPendingAttachments() +{ + LLPointer cb = NULL; + for (uuid_vec_t::const_iterator itPending = m_PendingAttachLinks.begin(); itPending != m_PendingAttachLinks.end(); ++itPending) + { + const LLUUID& idAttachItem = *itPending; + if ( (gAgent.getAvatarObject()->isWearingAttachment(idAttachItem)) && (!isLinkInCOF(idAttachItem)) ) + { + if (!cb) + cb = new LLLinkAttachmentCallback(); + addCOFItemLink(idAttachItem, cb); + } + } +} + +void LLCOFMgr::onLinkAttachmentComplete(const LLUUID& idItem) +{ + const LLUUID& idItemBase = gInventory.getLinkedItemID(idItem); + + // Remove the attachment from the pending list + uuid_vec_t::iterator itPending = std::find(m_PendingAttachLinks.begin(), m_PendingAttachLinks.end(), idItemBase); + if (itPending != m_PendingAttachLinks.end()) + m_PendingAttachLinks.erase(itPending); + + // It may have been detached already in which case we should remove the COF link + if ( (gAgent.getAvatarObject()) && (!gAgent.getAvatarObject()->isWearingAttachment(idItemBase)) ) + removeCOFItemLinks(idItemBase); +} + +void LLCOFMgr::updateAttachments() +{ + /*const*/ LLVOAvatar* pAvatar = gAgent.getAvatarObject(); + if (!pAvatar) + return; + + const LLUUID idCOF = getCOF(); + + // Grab all attachment links currently in COF + LLInventoryModel::item_array_t items; + getDescendentsOfAssetType(idCOF, items, LLAssetType::AT_OBJECT, true); + + // Include attachments which should be in COF but don't have their link created yet + uuid_vec_t::iterator itPendingAttachLink = m_PendingAttachLinks.begin(); + while (itPendingAttachLink != m_PendingAttachLinks.end()) + { + const LLUUID& idItem = *itPendingAttachLink; + if ( (!pAvatar->isWearingAttachment(idItem)) || (isLinkInCOF(idItem)) ) + { + itPendingAttachLink = m_PendingAttachLinks.erase(itPendingAttachLink); + continue; + } + + LLViewerInventoryItem* pItem = gInventory.getItem(idItem); + if (pItem) + items.push_back(pItem); + + ++itPendingAttachLink; + } + + // Don't remove attachments until avatar is fully loaded (should reduce random attaching/detaching/reattaching at log-on) + LLAgent::userUpdateAttachments(items, !pAvatar->isFullyLoaded()); +} + +// ============================================================================ +// Wearable functions +// + +void LLCOFMgr::addWearable(const LLUUID& idItem) +{ + if ( (isLinkInCOF(idItem)) || (std::find(m_PendingWearableLinks.begin(), m_PendingWearableLinks.end(), idItem) != m_PendingWearableLinks.end()) ) + { + return; + } + + gInventory.addChangedMask(LLInventoryObserver::LABEL, idItem); + m_PendingWearableLinks.push_back(idItem); + + LLPointer cb = new LLLinkWearableCallback(); + addCOFItemLink(idItem, cb); +} + +void LLCOFMgr::removeWearable(const LLUUID& idItem) +{ + gInventory.addChangedMask(LLInventoryObserver::LABEL, idItem); + + // Remove the attachment from the pending list + uuid_vec_t::iterator itPending = std::find(m_PendingWearableLinks.begin(), m_PendingWearableLinks.end(), idItem); + if (itPending != m_PendingWearableLinks.end()) + m_PendingWearableLinks.erase(itPending); + + removeCOFItemLinks(idItem); +} + +void LLCOFMgr::onLinkWearableComplete(const LLUUID& idItem) +{ + const LLUUID& idItemBase = gInventory.getLinkedItemID(idItem); + + // Remove the attachment from the pending list + uuid_vec_t::iterator itPending = std::find(m_PendingWearableLinks.begin(), m_PendingWearableLinks.end(), idItemBase); + if (itPending != m_PendingWearableLinks.end()) + m_PendingWearableLinks.erase(itPending); + + // It may have been removed already in which case we should remove the COF link + if (!gAgent.isWearingItem(idItemBase)) + removeCOFItemLinks(idItemBase); +} + +void LLCOFMgr::synchWearables() +{ + const LLUUID idCOF = getCOF(); + + // Grab all wearable links currently in COF + LLInventoryModel::item_array_t items; + getDescendentsOfAssetType(idCOF, items, LLAssetType::AT_BODYPART, true); + getDescendentsOfAssetType(idCOF, items, LLAssetType::AT_CLOTHING, true); + + // Transform collection of link LLViewerInventory pointers into collection of target LLUUIDs + uuid_vec_t curItems; + for (S32 idxItem = 0; idxItem < items.count(); idxItem++) + { + const LLViewerInventoryItem* pItem = items.get(idxItem); + if (!pItem) + continue; + curItems.push_back(pItem->getLinkedUUID()); + } + + // Grab the item UUIDs of all currently worn wearables + uuid_vec_t newItems; + for (S32 idxType = 0; idxType < WT_COUNT; idxType++) + { + const LLUUID& idItem = gAgent.getWearableItem((EWearableType)idxType); + if (idItem.isNull()) + continue; + newItems.push_back(idItem); + } + + uuid_vec_t addItems, remItems; + LLCommonUtils::computeDifference(newItems, curItems, addItems, remItems); + + // Add links for worn wearables that aren't linked yet + for (uuid_vec_t::const_iterator itItem = addItems.begin(); itItem != addItems.end(); ++itItem) + addWearable(*itItem); + + // Remove links of wearables that aren't worn anymore + for (uuid_vec_t::const_iterator itItem = remItems.begin(); itItem != remItems.end(); ++itItem) + removeWearable(*itItem); +} + +// ============================================================================ +// Base outfit folder functions +// + +void LLCOFMgr::addBOFLink(const LLUUID &idFolder, LLPointer cb) +{ + purgeBOFLink(); + + const LLViewerInventoryCategory* pFolder = gInventory.getCategory(idFolder); + if ( (pFolder) && (LLAssetType::AT_OUTFIT == pFolder->getPreferredType()) ) + link_inventory_item(gAgent.getID(), idFolder, getCOF(), pFolder->getName(), "", LLAssetType::AT_LINK_FOLDER, cb); +} + +void LLCOFMgr::purgeBOFLink() +{ + LLInventoryModel::cat_array_t* pFolders; LLInventoryModel::item_array_t* pItems; + gInventory.getDirectDescendentsOf(getCOF(), pFolders, pItems); + for (S32 idxItem = 0, cntItem = pItems->count(); idxItem < cntItem; idxItem++) + { + const LLViewerInventoryItem* pItem = pItems->get(idxItem).get(); + if ( (!pItem) || (LLAssetType::AT_LINK_FOLDER != pItem->getActualType()) ) + continue; + + const LLViewerInventoryCategory* pLinkFolder = pItem->getLinkedCategory(); + if ( (pLinkFolder) && (LLAssetType::AT_OUTFIT == pLinkFolder->getPreferredType()) ) + gInventory.purgeObject(pItem->getUUID()); + } +} + +// ============================================================================ diff --git a/indra/newview/cofmgr.h b/indra/newview/cofmgr.h new file mode 100644 index 000000000..651a3bfe1 --- /dev/null +++ b/indra/newview/cofmgr.h @@ -0,0 +1,89 @@ +/** + * + * Copyright (c) 2010, Kitty Barnett + * + * The source code in this file is provided to you under the terms of the + * GNU General Public License, version 2.0, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. Terms of the GPL can be found in doc/GPL-license.txt + * in this distribution, or online at http://www.gnu.org/licenses/gpl-2.0.txt + * + * By copying, modifying or distributing this software, you acknowledge that + * you have read and understood your obligations described above, and agree to + * abide by those obligations. + * + */ + +#include "llinventorymodel.h" +#include "llmemory.h" +#include "llviewerinventory.h" + +// ============================================================================ + +class LLCOFMgr : public LLSingleton +{ + /* + * Helper functions + */ +public: + void checkCOF(); + void fetchCOF(); + static const LLUUID getCOF() { return gInventory.findCategoryUUIDForType(LLAssetType::AT_CURRENT_OUTFIT); } + static void getDescendentsOfAssetType(const LLUUID& idCat, LLInventoryModel::item_array_t& items, + LLAssetType::EType typeAsset, bool fFollowFolderLinks); + bool isLinkInCOF(const LLUUID& idItem); +protected: + void addCOFItemLink(const LLUUID& idItem, LLPointer cb = NULL); + void addCOFItemLink(const LLInventoryItem* pItem, LLPointer cb = NULL); + void removeCOFItemLinks(const LLUUID& idItem); + + /* + * Attachment functions + */ +public: + void addAttachment(const LLUUID& idItem); + void removeAttachment(const LLUUID& idItem); + void synchAttachments(); +protected: + void onLinkAttachmentComplete(const LLUUID& idItem); + void linkPendingAttachments(); + void setLinkAttachments(bool fEnable); + void updateAttachments(); + + /* + * Wearable functions + */ +public: + void addWearable(const LLUUID& idItem); + void removeWearable(const LLUUID& idItem); + void synchWearables(); +protected: + void onLinkWearableComplete(const LLUUID& idItem); + + /* + * Base outfit folder functions + */ +public: + void addBOFLink(const LLUUID& idFolder, LLPointer cb = NULL); + void purgeBOFLink(); + + /* + * Member variables + */ +protected: + bool m_fLinkAttachments; + uuid_vec_t m_PendingAttachLinks; + uuid_vec_t m_PendingWearableLinks; + +protected: + LLCOFMgr() : m_fLinkAttachments(false) {} +private: + friend class LLCOFFetcher; + friend class LLCOFLinkTargetFetcher; + friend class LLDeferredAddLinkTargetFetcher; + friend class LLLinkAttachmentCallback; + friend class LLLinkWearableCallback; + friend class LLSingleton; +}; + +// ============================================================================ diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 46035d765..a4318a8e9 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -35,8 +35,8 @@ #include "stdtypes.h" #include "stdenums.h" +#include "cofmgr.h" #include "llagent.h" - #include "llcamera.h" #include "llcoordframe.h" #include "indra_constants.h" @@ -142,8 +142,10 @@ #include "llworldmapmessage.h" #include "llfollowcam.h" -// [RLVa:KB] +// [RLVa:KB] - Checked: 2010-09-27 (RLVa-1.1.3b) #include "rlvhandler.h" +#include "rlvinventory.h" +#include "llattachmentsmgr.h" // [/RLVa:KB] using namespace LLVOAvatarDefines; @@ -3480,13 +3482,18 @@ void LLAgent::updateCamera() { LLVOAvatar::attachment_map_t::iterator curiter = iter++; LLViewerJointAttachment* attachment = curiter->second; - LLViewerObject *attached_object = attachment->getObject(); - if (attached_object && !attached_object->isDead() && attached_object->mDrawable.notNull()) + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) { - // clear any existing "early" movements of attachment - attached_object->mDrawable->clearState(LLDrawable::EARLY_MOVE); - gPipeline.updateMoveNormalAsync(attached_object->mDrawable); - attached_object->updateText(); + LLViewerObject *attached_object = (*attachment_iter); + if (attached_object && !attached_object->isDead() && attached_object->mDrawable.notNull()) + { + // clear any existing "early" movements of attachment + attached_object->mDrawable->clearState(LLDrawable::EARLY_MOVE); + gPipeline.updateMoveNormalAsync(attached_object->mDrawable); + attached_object->updateText(); + } } } @@ -6285,6 +6292,7 @@ void LLAgent::teleportViaLandmark(const LLUUID& landmark_asset_id) ( (gRlvHandler.hasBehaviour(RLV_BHVR_TPLM)) || ((gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) && (mAvatarObject.notNull()) && (mAvatarObject->mIsSitting)) )) { + RlvNotifications::notifyBlockedTeleport(); return; } // [/RLVa:KB] @@ -6361,6 +6369,7 @@ void LLAgent::teleportViaLocation(const LLVector3d& pos_global) ( (mAvatarObject.notNull()) && (mAvatarObject->mIsSitting) && (gRlvHandler.hasBehaviourExcept(RLV_BHVR_UNSIT, gRlvHandler.getCurrentObject()))) ) { + RlvNotifications::notifyBlockedTeleport(); return; } @@ -6422,6 +6431,16 @@ void LLAgent::teleportViaLocation(const LLVector3d& pos_global) // Teleport to global position, but keep facing in the same direction void LLAgent::teleportViaLocationLookAt(const LLVector3d& pos_global) { +// [RLVa:KB] - Checked: 2010-10-07 (RLVa-1.2.1f) | Added: RLVa-1.2.1f + // RELEASE-RLVa: [SL-2.2.0] Make sure this isn't used for anything except double-click teleporting + if ( (rlv_handler_t::isEnabled()) && (!RlvUtil::isForceTp()) && + ((gRlvHandler.hasBehaviour(RLV_BHVR_SITTP)) || (!gRlvHandler.canStand())) ) + { + RlvNotifications::notifyBlockedTeleport(); + return; + } +// [/RLVa:KB] + mbTeleportKeepsLookAt = true; setFocusOnAvatar(FALSE, ANIMATE); // detach camera form avatar, so it keeps direction U64 region_handle = to_region_handle(pos_global); @@ -6690,6 +6709,9 @@ void LLAgent::sendAgentWearablesUpdate() // Then make sure the inventory is in sync with the avatar. gInventory.notifyObservers(); + // This isn't the proper place to be doing this, but it's a good "catch-all" + LLCOFMgr::instance().synchWearables(); + // Send the AgentIsNowWearing gMessageSystem->newMessageFast(_PREHASH_AgentIsNowWearing); @@ -6709,7 +6731,15 @@ void LLAgent::sendAgentWearablesUpdate() if( wearable ) { LL_DEBUGS("Wearables") << "Sending wearable " << wearable->getName() << " mItemID = " << mWearableEntry[ i ].mItemID << LL_ENDL; - gMessageSystem->addUUIDFast(_PREHASH_ItemID, mWearableEntry[ i ].mItemID ); + LLUUID item_id = mWearableEntry[i].mItemID; + const LLViewerInventoryItem *item = gInventory.getItem(item_id); + if (item && item->getIsLinkType()) + { + // Get the itemID that this item points to. i.e. make sure + // we are storing baseitems, not their links, in the database. + item_id = item->getLinkedUUID(); + } + gMessageSystem->addUUIDFast(_PREHASH_ItemID, item_id); } else { @@ -7018,7 +7048,8 @@ BOOL LLAgent::selfHasWearable( void* userdata ) BOOL LLAgent::isWearingItem( const LLUUID& item_id ) { - return (getWearableFromWearableItem( item_id ) != NULL); + const LLUUID& base_item_id = gInventory.getLinkedItemID(item_id); + return (getWearableFromWearableItem(base_item_id) != NULL); } // static @@ -7095,19 +7126,14 @@ void LLAgent::processAgentInitialWearablesUpdate( LLMessageSystem* mesgsys, void LL_DEBUGS("Wearables") << " " << LLWearable::typeToTypeLabel(type) << " " << asset_id << " item id " << gAgent.mWearableEntry[type].mItemID.asString() << LL_ENDL; } + LLCOFMgr::instance().fetchCOF(); + // now that we have the asset ids...request the wearable assets -// [RLVa:KB] - Alternate: Snowglobe-1.2.4 | Checked: 2009-08-08 (RLVa-1.0.1g) | Added: RLVa-1.0.1g - LLInventoryFetchObserver::item_ref_t rlvItems; -// [/RLVa:KB] for( i = 0; i < WT_COUNT; i++ ) { LL_DEBUGS("Wearables") << " fetching " << asset_id_array[i] << LL_ENDL; if( !gAgent.mWearableEntry[i].mItemID.isNull() ) { -// [RLVa:KB] - Alternate: Snowglobe-1.2.4 | Checked: 2009-08-08 (RLVa-1.0.1g) | Added: RLVa-1.0.1g - if (rlv_handler_t::isEnabled()) - rlvItems.push_back(gAgent.mWearableEntry[i].mItemID); -// [/RLVa:KB] gWearableList.getAsset( asset_id_array[i], LLStringUtil::null, @@ -7116,14 +7142,8 @@ void LLAgent::processAgentInitialWearablesUpdate( LLMessageSystem* mesgsys, void } } -// [RLVa:KB] - Alternate: Snowglobe-1.2.4 | Checked: 2009-08-08 (RLVa-1.0.1g) | Added: RLVa-1.0.1g - // TODO-RLVa: checking that we're in STATE_STARTED is probably not needed, but leave it until we can be absolutely sure - if ( (rlv_handler_t::isEnabled()) && (LLStartUp::getStartupState() == STATE_STARTED) ) - { - RlvCurrentlyWorn f; - f.fetchItems(rlvItems); - } -// [/RLVa:KB] + // Not really sure where else to put this + gIdleCallbacks.addFunction(&LLAttachmentsMgr::onIdle, NULL); } } @@ -7331,11 +7351,14 @@ void LLAgent::makeNewOutfit( return; } - // First, make a folder in the Clothes directory. - LLUUID folder_id = gInventory.createNewCategory( - gInventory.findCategoryUUIDForType(LLAssetType::AT_CLOTHING), - LLAssetType::AT_NONE, - new_folder_name); + BOOL fUseLinks = !gSavedSettings.getBOOL("UseInventoryLinks"); + BOOL fUseOutfits = gSavedSettings.getBOOL("UseOutfitFolders"); + + LLAssetType::EType typeDest = (fUseOutfits) ? LLAssetType::AT_MY_OUTFITS : LLAssetType::AT_CLOTHING; + LLAssetType::EType typeFolder = (fUseOutfits) ? LLAssetType::AT_OUTFIT : LLAssetType::AT_NONE; + + // First, make a folder for the outfit. + LLUUID folder_id = gInventory.createNewCategory(gInventory.findCategoryUUIDForType(typeDest), typeFolder, new_folder_name); bool found_first_item = false; @@ -7347,7 +7370,6 @@ void LLAgent::makeNewOutfit( // Then, iterate though each of the wearables and save copies of them in the folder. S32 i; S32 count = wearables_to_include.count(); - LLDynamicArray delete_items; LLPointer cbdone = NULL; for( i = 0; i < count; ++i ) { @@ -7355,53 +7377,86 @@ void LLAgent::makeNewOutfit( LLWearable* old_wearable = mWearableEntry[ index ].mWearable; if( old_wearable ) { - std::string new_name; - LLWearable* new_wearable; - new_wearable = gWearableList.createCopy(old_wearable); - if (rename_clothing) - { - new_name = new_folder_name; - new_name.append(" "); - new_name.append(old_wearable->getTypeLabel()); - LLStringUtil::truncate(new_name, DB_INV_ITEM_NAME_STR_LEN); - new_wearable->setName(new_name); - } - LLViewerInventoryItem* item = gInventory.getItem(mWearableEntry[index].mItemID); - S32 todo = addWearableToAgentInventoryCallback::CALL_NONE; - if (!found_first_item) + if (fUseOutfits) { - found_first_item = true; - /* set the focus to the first item */ - todo |= addWearableToAgentInventoryCallback::CALL_MAKENEWOUTFITDONE; - /* send the agent wearables update when done */ - cbdone = new sendAgentWearablesUpdateCallback; - } - LLPointer cb = - new addWearableToAgentInventoryCallback( - cbdone, - index, - new_wearable, - todo); - if (isWearableCopyable((EWearableType)index)) - { - copy_inventory_item( + std::string strOrdering = llformat("@%d", item->getWearableType() * 100); + + link_inventory_item( gAgent.getID(), - item->getPermissions().getOwner(), - item->getUUID(), + item->getLinkedUUID(), folder_id, - new_name, - cb); + item->getName(), + strOrdering, + LLAssetType::AT_LINK, + LLPointer(NULL)); } else { - move_inventory_item( - gAgent.getID(), - gAgent.getSessionID(), - item->getUUID(), - folder_id, - new_name, - cb); + std::string new_name = item->getName(); + if (rename_clothing) + { + new_name = new_folder_name; + new_name.append(" "); + new_name.append(old_wearable->getTypeLabel()); + LLStringUtil::truncate(new_name, DB_INV_ITEM_NAME_STR_LEN); + } + + if (fUseLinks || isWearableCopyable((EWearableType)index)) + { + LLWearable* new_wearable = gWearableList.createCopy(old_wearable); + if (rename_clothing) + { + new_wearable->setName(new_name); + } + + S32 todo = addWearableToAgentInventoryCallback::CALL_NONE; + if (!found_first_item) + { + found_first_item = true; + /* set the focus to the first item */ + todo |= addWearableToAgentInventoryCallback::CALL_MAKENEWOUTFITDONE; + /* send the agent wearables update when done */ + cbdone = new sendAgentWearablesUpdateCallback; + } + LLPointer cb = + new addWearableToAgentInventoryCallback( + cbdone, + index, + new_wearable, + todo); + if (isWearableCopyable((EWearableType)index)) + { + copy_inventory_item( + gAgent.getID(), + item->getPermissions().getOwner(), + item->getLinkedUUID(), + folder_id, + new_name, + cb); + } + else + { + move_inventory_item( + gAgent.getID(), + gAgent.getSessionID(), + item->getLinkedUUID(), + folder_id, + new_name, + cb); + } + } + else + { + link_inventory_item( + gAgent.getID(), + item->getLinkedUUID(), + folder_id, + item->getName(), // Apparently, links cannot have arbitrary names... + item->getDescription(), + LLAssetType::AT_LINK, + LLPointer(NULL)); + } } } } @@ -7414,39 +7469,71 @@ void LLAgent::makeNewOutfit( if( attachments_to_include.count() ) { - BOOL msg_started = FALSE; - LLMessageSystem* msg = gMessageSystem; for( S32 i = 0; i < attachments_to_include.count(); i++ ) { S32 attachment_pt = attachments_to_include[i]; LLViewerJointAttachment* attachment = get_if_there(mAvatarObject->mAttachmentPoints, attachment_pt, (LLViewerJointAttachment*)NULL ); if(!attachment) continue; - LLViewerObject* attached_object = attachment->getObject(); - if(!attached_object) continue; - const LLUUID& item_id = attachment->getItemID(); - if(item_id.isNull()) continue; - LLInventoryItem* item = gInventory.getItem(item_id); - if(!item) continue; - if(!msg_started) - { - msg_started = TRUE; - msg->newMessage("CreateNewOutfitAttachments"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID", getID()); - msg->addUUID("SessionID", getSessionID()); - msg->nextBlock("HeaderData"); - msg->addUUID("NewFolderID", folder_id); + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) + { + LLViewerObject *attached_object = (*attachment_iter); + if (!attached_object) continue; + const LLUUID& item_id = attached_object->getAttachmentItemID(); + if (item_id.isNull()) continue; + LLInventoryItem* item = gInventory.getItem(item_id); + if (!item) continue; + if (fUseOutfits) + { + link_inventory_item( + gAgent.getID(), + item->getLinkedUUID(), + folder_id, + item->getName(), + item->getDescription(), + LLAssetType::AT_LINK, + LLPointer(NULL)); + } + else + { + if (fUseLinks || item->getPermissions().allowCopyBy(gAgent.getID())) + { + const LLUUID& old_folder_id = item->getParentUUID(); + + move_inventory_item( + gAgent.getID(), + gAgent.getSessionID(), + item->getLinkedUUID(), + folder_id, + item->getName(), + LLPointer(NULL)); + + if (item->getPermissions().allowCopyBy(gAgent.getID())) + { + copy_inventory_item( + gAgent.getID(), + item->getPermissions().getOwner(), + item->getLinkedUUID(), + old_folder_id, + item->getName(), + LLPointer(NULL)); + } + } + else + { + link_inventory_item( + gAgent.getID(), + item->getLinkedUUID(), + folder_id, + item->getName(), + item->getDescription(), + LLAssetType::AT_LINK, + LLPointer(NULL)); + } + } } - msg->nextBlock("ObjectData"); - msg->addUUID("OldItemID", item_id); - msg->addUUID("OldFolderID", item->getParentUUID()); } - - if( msg_started ) - { - sendReliableMessage(); - } - } } @@ -7518,6 +7605,10 @@ void LLAgent::sendAgentSetAppearance() body_size.mV[VY] = body_size.mV[VY] + gSavedSettings.getF32("AscentAvatarYModifier"); body_size.mV[VZ] = body_size.mV[VZ] + gSavedSettings.getF32("AscentAvatarZModifier"); +// [RLVa:KB] - Checked: 2010-10-11 (RLVa-1.2.0e) | Added: RLVa-1.2.0e + body_size.mV[VZ] += RlvSettings::getAvatarOffsetZ(); +// [/RLVa:KB] + msg->addVector3Fast(_PREHASH_Size, body_size); // To guard against out of order packets @@ -7668,8 +7759,8 @@ void LLAgent::removeWearable( EWearableType type ) return; } -// [RLVa:KB] - Version: 1.23.4 | Checked: 2009-07-07 (RLVa-1.0.0d) - if ( (rlv_handler_t::isEnabled()) && (!gRlvHandler.isRemovable(type)) ) +// [RLVa:KB] - Checked: 2009-07-07 (RLVa-1.1.3b) + if ( (rlv_handler_t::isEnabled()) && (!gRlvWearableLocks.canRemove(type)) ) { return; } @@ -7801,19 +7892,19 @@ void LLAgent::setWearableOutfit( wearables_to_remove[WT_SKIN] = FALSE; wearables_to_remove[WT_HAIR] = FALSE; wearables_to_remove[WT_EYES] = FALSE; -// [RLVa:KB] - Checked: 2009-07-06 (RLVa-1.0.0c) | Added: RLVa-0.2.2a - wearables_to_remove[WT_SHIRT] = remove && gRlvHandler.isRemovable(WT_SHIRT); - wearables_to_remove[WT_PANTS] = remove && gRlvHandler.isRemovable(WT_PANTS); - wearables_to_remove[WT_SHOES] = remove && gRlvHandler.isRemovable(WT_SHOES); - wearables_to_remove[WT_SOCKS] = remove && gRlvHandler.isRemovable(WT_SOCKS); - wearables_to_remove[WT_JACKET] = remove && gRlvHandler.isRemovable(WT_JACKET); - wearables_to_remove[WT_GLOVES] = remove && gRlvHandler.isRemovable(WT_GLOVES); - wearables_to_remove[WT_UNDERSHIRT] = (!gAgent.isTeen()) && remove && gRlvHandler.isRemovable(WT_UNDERSHIRT); - wearables_to_remove[WT_UNDERPANTS] = (!gAgent.isTeen()) && remove && gRlvHandler.isRemovable(WT_UNDERPANTS); - wearables_to_remove[WT_SKIRT] = remove && gRlvHandler.isRemovable(WT_SKIRT); +// [RLVa:KB] - Checked: 2009-07-06 (RLVa-1.1.3b) | Added: RLVa-0.2.2a + wearables_to_remove[WT_SHIRT] = remove && gRlvWearableLocks.canRemove(WT_SHIRT); + wearables_to_remove[WT_PANTS] = remove && gRlvWearableLocks.canRemove(WT_PANTS); + wearables_to_remove[WT_SHOES] = remove && gRlvWearableLocks.canRemove(WT_SHOES); + wearables_to_remove[WT_SOCKS] = remove && gRlvWearableLocks.canRemove(WT_SOCKS); + wearables_to_remove[WT_JACKET] = remove && gRlvWearableLocks.canRemove(WT_JACKET); + wearables_to_remove[WT_GLOVES] = remove && gRlvWearableLocks.canRemove(WT_GLOVES); + wearables_to_remove[WT_UNDERSHIRT] = (!gAgent.isTeen()) && remove && gRlvWearableLocks.canRemove(WT_UNDERSHIRT); + wearables_to_remove[WT_UNDERPANTS] = (!gAgent.isTeen()) && remove && gRlvWearableLocks.canRemove(WT_UNDERPANTS); + wearables_to_remove[WT_SKIRT] = remove && gRlvWearableLocks.canRemove(WT_SKIRT); + wearables_to_remove[WT_ALPHA] = remove && gRlvWearableLocks.canRemove(WT_ALPHA); + wearables_to_remove[WT_TATTOO] = remove && gRlvWearableLocks.canRemove(WT_TATTOO); // [/RLVa:KB] - wearables_to_remove[WT_ALPHA] = remove; - wearables_to_remove[WT_TATTOO] = remove; S32 count = wearables.count(); llassert( items.count() == count ); @@ -7906,7 +7997,7 @@ void LLAgent::setWearable( LLInventoryItem* new_item, LLWearable* new_wearable ) // [RLVa:KB] - Checked: 2009-07-07 (RLVa-1.0.0d) // Block if: we can't wear on that layer; or we're already wearing something there we can't take off - if ( (rlv_handler_t::isEnabled()) && ((!gRlvHandler.isWearable(type)) || ((old_wearable) && (!gRlvHandler.isRemovable(type)))) ) + if ( (rlv_handler_t::isEnabled()) && (!gRlvWearableLocks.canWear(type)) ) { return; } @@ -8106,38 +8197,28 @@ void LLAgent::userRemoveAllAttachments( void* userdata ) return; } -// [RLVa:KB] - Checked: 2009-11-24 (RLVa-1.1.0f) | Modified: RLVa-1.1.0e - std::list LocalIDs; - for (LLVOAvatar::attachment_map_t::iterator iter = avatarp->mAttachmentPoints.begin(); iter != avatarp->mAttachmentPoints.end(); ) + llvo_vec_t objects_to_remove; + + for (LLVOAvatar::attachment_map_t::iterator iter = avatarp->mAttachmentPoints.begin(); + iter != avatarp->mAttachmentPoints.end();) { LLVOAvatar::attachment_map_t::iterator curiter = iter++; LLViewerJointAttachment* attachment = curiter->second; - LLViewerObject* objectp = attachment->getObject(); - if (objectp) + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) { - if ( (rlv_handler_t::isEnabled()) && (gRlvHandler.isLockedAttachment(curiter->first, RLV_LOCK_REMOVE)) ) - continue; - LocalIDs.push_back(objectp->getLocalID()); - } - } - - // Only send the message if we actually have something to detach - if (LocalIDs.size() > 0) - { - gMessageSystem->newMessage("ObjectDetach"); - gMessageSystem->nextBlockFast(_PREHASH_AgentData); - gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); - gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - - for (std::list::const_iterator itLocalID = LocalIDs.begin(); itLocalID != LocalIDs.end(); ++itLocalID) - { - gMessageSystem->nextBlockFast(_PREHASH_ObjectData); - gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, *itLocalID); - } - - gMessageSystem->sendReliable(gAgent.getRegionHost()); - } + LLViewerObject *attached_object = (*attachment_iter); +// if (attached_object) +// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.1.3b) | Modified: RLVa-1.1.3b + if ( (attached_object) && ((!rlv_handler_t::isEnabled()) || (!gRlvAttachmentLocks.isLockedAttachment(attached_object))) ) // [/RLVa:KB] + { + objects_to_remove.push_back(attached_object); + } + } + } + userRemoveMultipleAttachments(objects_to_remove); } void LLAgent::observeFriends() @@ -8202,6 +8283,208 @@ void LLAgent::parseTeleportMessages(const std::string& xml_filename) }//end for (all message sets in xml file) } +// Combines userRemoveAllAttachments() and userAttachMultipleAttachments() logic to +// get attachments into desired state with minimal number of adds/removes. +//void LLAgentWearables::userUpdateAttachments(LLInventoryModel::item_array_t& obj_item_array) +// [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2010-09-22 (Catznip-2.2.0a) | Added: Catznip-2.2.0a +void LLAgent::userUpdateAttachments(LLInventoryModel::item_array_t& obj_item_array, bool fAttachOnly) +// [/SL:KB] +{ + // Possible cases: + // already wearing but not in request set -> take off. + // already wearing and in request set -> leave alone. + // not wearing and in request set -> put on. + + LLVOAvatar* pAvatar = gAgent.getAvatarObject(); + if (!pAvatar) return; + + std::set requested_item_ids; + std::set current_item_ids; + for (S32 i=0; igetLinkedUUID()); + + // Build up list of objects to be removed and items currently attached. + llvo_vec_t objects_to_remove; + for (LLVOAvatar::attachment_map_t::iterator iter = pAvatar->mAttachmentPoints.begin(); + iter != pAvatar->mAttachmentPoints.end();) + { + LLVOAvatar::attachment_map_t::iterator curiter = iter++; + LLViewerJointAttachment* attachment = curiter->second; + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) + { + LLViewerObject *objectp = (*attachment_iter); + if (objectp) + { + LLUUID object_item_id = objectp->getAttachmentItemID(); + if (requested_item_ids.find(object_item_id) != requested_item_ids.end()) + { + // Object currently worn, was requested. + // Flag as currently worn so we won't have to add it again. + current_item_ids.insert(object_item_id); + } + else + { + // object currently worn, not requested. + objects_to_remove.push_back(objectp); + } + } + } + } + + LLInventoryModel::item_array_t items_to_add; + for (LLInventoryModel::item_array_t::iterator it = obj_item_array.begin(); + it != obj_item_array.end(); + ++it) + { + LLUUID linked_id = (*it).get()->getLinkedUUID(); + if (current_item_ids.find(linked_id) != current_item_ids.end()) + { + // Requested attachment is already worn. + } + else + { + // Requested attachment is not worn yet. + items_to_add.push_back(*it); + } + } + // S32 remove_count = objects_to_remove.size(); + // S32 add_count = items_to_add.size(); + // llinfos << "remove " << remove_count << " add " << add_count << llendl; + + // Remove everything in objects_to_remove +// userRemoveMultipleAttachments(objects_to_remove); +// [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2010-09-22 (Catznip-2.2.0a) | Added: Catznip-2.2.0a + if (!fAttachOnly) + { + userRemoveMultipleAttachments(objects_to_remove); + } +// [/SL:KB] + + // Add everything in items_to_add + userAttachMultipleAttachments(items_to_add); +} + +void LLAgent::userRemoveMultipleAttachments(llvo_vec_t& objects_to_remove) +{ + if (!gAgent.getAvatarObject()) return; + +// [RLVa:KB] - Checked: 2010-03-04 (RLVa-1.1.3b) | Modified: RLVa-1.2.0a + // RELEASE-RLVa: [SL-2.0.0] Check our callers and verify that erasing elements from the passed vector won't break random things + if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_REMOVE)) ) + { + llvo_vec_t::iterator itObj = objects_to_remove.begin(); + while (itObj != objects_to_remove.end()) + { + const LLViewerObject* pAttachObj = *itObj; + if (gRlvAttachmentLocks.isLockedAttachment(pAttachObj)) + { + itObj = objects_to_remove.erase(itObj); + + // Fall-back code: re-add the attachment if it got removed from COF somehow (compensates for possible bugs elsewhere) + LLInventoryModel::cat_array_t folders; LLInventoryModel::item_array_t items; + LLLinkedItemIDMatches f(pAttachObj->getAttachmentItemID()); + gInventory.collectDescendentsIf(LLCOFMgr::instance().getCOF(), folders, items, LLInventoryModel::EXCLUDE_TRASH, f); + RLV_ASSERT( 0 != items.count() ); + if (0 == items.count()) + LLCOFMgr::instance().addAttachment(pAttachObj->getAttachmentItemID()); + } + else + { + ++itObj; + } + } + } +// [/RLVa:KB] + + if (objects_to_remove.empty()) + return; + + gMessageSystem->newMessage("ObjectDetach"); + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + + for (llvo_vec_t::iterator it = objects_to_remove.begin(); + it != objects_to_remove.end(); + ++it) + { + LLViewerObject *objectp = *it; + gMessageSystem->nextBlockFast(_PREHASH_ObjectData); + gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, objectp->getLocalID()); + } + gMessageSystem->sendReliable(gAgent.getRegionHost()); +} + +void LLAgent::userAttachMultipleAttachments(LLInventoryModel::item_array_t& obj_item_array) +{ +// [RLVa:KB] - Checked: 2010-03-04 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a + // RELEASE-RLVa: [SL-2.0.0] Check our callers and verify that erasing elements from the passed vector won't break random things + if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) ) + { + // Fall-back code: everything should really already have been pruned before we get this far + for (S32 idxItem = obj_item_array.count() - 1; idxItem >= 0; idxItem--) + { + const LLInventoryItem* pItem = obj_item_array.get(idxItem).get(); + if (!gRlvAttachmentLocks.canAttach(pItem)) + { + obj_item_array.remove(idxItem); + RLV_ASSERT(false); + } + } + } +// [/RLVa:KB] + + // Build a compound message to send all the objects that need to be rezzed. + S32 obj_count = obj_item_array.count(); + + // 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 ) + { + obj_count = MAX_OBJECTS_TO_SEND; + } + + // 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.get(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() ); + } + } +} + // OGPX - This code will change when capabilities get refactored. // Right now this is used for capabilities that we get from OGP agent domain void LLAgent::setCapability(const std::string& name, const std::string& url) diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h index 4f10d3d13..71363c28c 100644 --- a/indra/newview/llagent.h +++ b/indra/newview/llagent.h @@ -46,6 +46,7 @@ #include "lldbstrings.h" #include "llhudeffectlookat.h" #include "llhudeffectpointat.h" +#include "llinventorymodel.h" #include "llmemory.h" #include "llstring.h" #include "lluuid.h" @@ -63,6 +64,7 @@ #include "llcharacter.h" #include "llinventory.h" #include "llviewerinventory.h" +#include "llviewerobject.h" #include "llagentdata.h" // Ventrella @@ -731,6 +733,14 @@ public: static void userRemoveAllAttachments( void* userdata); // userdata is NULL static BOOL selfHasWearable( void* userdata ); // userdata is EWearableType +// static void userUpdateAttachments(LLInventoryModel::item_array_t& obj_item_array); +// [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2010-09-22 (Catznip-2.2.0a) | Added: Catznip-2.2.0a + // Not the best way to go about this but other attempts changed far too much LL code to be a viable solution + static void userUpdateAttachments(LLInventoryModel::item_array_t& obj_item_array, bool fAttachOnly = false); +// [/SL:KB] + static void userRemoveMultipleAttachments(llvo_vec_t& llvo_array); + static void userAttachMultipleAttachments(LLInventoryModel::item_array_t& obj_item_array); + //debug methods static void clearVisualParams(void *); diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index bf2e07330..f8bbccf47 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -4223,20 +4223,10 @@ void LLAppViewer::handleLoginComplete() } writeDebugInfo(); -// [RLVa:KB] - Alternate: Snowglobe-1.2.4 | Checked: 2009-08-05 (RLVa-1.0.1e) | Modified: RLVa-1.0.1e - // TODO-RLVa: find some way to initialize the lookup table when we need them *and* support toggling RLVa at runtime - gRlvHandler.initLookupTables(); - +// [RLVa:KB] - Checked: 2010-09-27 (RLVa-1.1.3b) | Modified: RLVa-1.1.3b if (rlv_handler_t::isEnabled()) { - RlvCurrentlyWorn::fetchWorn(); - rlv_handler_t::fetchSharedInventory(); - - #ifdef RLV_EXTENSION_STARTLOCATION - RlvSettings::updateLoginLastLocation(); - #endif // RLV_EXTENSION_STARTLOCATION - - gRlvHandler.processRetainedCommands(); + gRlvHandler.onLoginComplete(); } // [/RLVa:KB] } diff --git a/indra/newview/llattachmentsmgr.cpp b/indra/newview/llattachmentsmgr.cpp new file mode 100644 index 000000000..56490162b --- /dev/null +++ b/indra/newview/llattachmentsmgr.cpp @@ -0,0 +1,156 @@ +/** + * @file llattachmentsmgr.cpp + * @brief Manager for initiating attachments changes on the viewer + * + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "llattachmentsmgr.h" + +#include "llagent.h" +#include "llinventorymodel.h" +#include "lltooldraganddrop.h" // pack_permissions_slam +#include "llviewerinventory.h" +#include "llviewerregion.h" +#include "message.h" +// [RLVa:KB] - Checked: 2010-09-13 (RLVa-1.2.1c) +#include "rlvhandler.h" +// [/RLVa:KB] + +LLAttachmentsMgr::LLAttachmentsMgr() +{ +} + +LLAttachmentsMgr::~LLAttachmentsMgr() +{ +} + +void LLAttachmentsMgr::addAttachment(const LLUUID& item_id, + const U8 attachment_pt, +// const BOOL add) +// [RLVa:KB] - Checked: 2010-09-13 (RLVa-1.2.1c) | Added: RLVa-1.2.1c + const BOOL add, const BOOL fRlvForce /*=FALSE*/) +// [/RLVa:KB] +{ + AttachmentsInfo attachment; + attachment.mItemID = item_id; + attachment.mAttachmentPt = attachment_pt; + attachment.mAdd = add; + +// [RLVa:KB] - Checked: 2010-09-23 (RLVa-1.2.1d) | Modified: RLVa-1.2.1d + if ( (rlv_handler_t::isEnabled()) && (!fRlvForce) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) ) + { + const LLInventoryItem* pItem = gInventory.getItem(item_id); + if (!pItem) + return; + + LLViewerJointAttachment* pAttachPt = NULL; + ERlvWearMask eWearMask = gRlvAttachmentLocks.canAttach(pItem, &pAttachPt); + if ( ((add) && ((RLV_WEAR_ADD & eWearMask) == 0)) || ((!add) && ((RLV_WEAR_REPLACE & eWearMask) == 0)) ) + return; + + if ( (0 == attachment_pt) && (NULL != pAttachPt) ) + attachment.mAttachmentPt = RlvAttachPtLookup::getAttachPointIndex(pAttachPt); + RlvAttachmentLockWatchdog::instance().onWearAttachment(pItem, (add) ? RLV_WEAR_ADD : RLV_WEAR_REPLACE); + attachment.mAdd = true; + } +// [/RLVa:KB] + + mPendingAttachments.push_back(attachment); +} + +// static +void LLAttachmentsMgr::onIdle(void *) +{ + LLAttachmentsMgr::instance().onIdle(); +} + +void LLAttachmentsMgr::onIdle() +{ + S32 obj_count = mPendingAttachments.size(); + 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 ) + { + obj_count = MAX_OBJECTS_TO_SEND; + } + + 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) + { + 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 AttachmentsInfo &attachment = (*iter); + LLViewerInventoryItem* item = gInventory.getItem(attachment.mItemID); + if (!item) + { + llinfos << "Attempted to add non-existant item ID:" << attachment.mItemID << llendl; + continue; + } + 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++; + } + + mPendingAttachments.clear(); +} diff --git a/indra/newview/llattachmentsmgr.h b/indra/newview/llattachmentsmgr.h new file mode 100644 index 000000000..768487d29 --- /dev/null +++ b/indra/newview/llattachmentsmgr.h @@ -0,0 +1,76 @@ +/** + * @file llattachmentsmgr.h + * @brief Batches up attachment requests and sends them all + * in one message. + * + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLATTACHMENTSMGR_H +#define LL_LLATTACHMENTSMGR_H + +#include "llmemory.h" + +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. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLAttachmentsMgr: public LLSingleton +{ +public: + LLAttachmentsMgr(); + virtual ~LLAttachmentsMgr(); + + void addAttachment(const LLUUID& item_id, + const U8 attachment_pt, +// const BOOL add); +// [RLVa:KB] - Checked: 2010-09-13 (RLVa-1.2.1c) | Added: RLVa-1.2.1c + const BOOL add, const BOOL fRlvForce = FALSE); +// [/RLVa:KB] + static void onIdle(void *); +protected: + void onIdle(); +private: + struct AttachmentsInfo + { + LLUUID mItemID; + U8 mAttachmentPt; + BOOL mAdd; + }; + + typedef std::vector attachments_vec_t; + attachments_vec_t mPendingAttachments; +}; + +#endif diff --git a/indra/newview/llbuildnewviewsscheduler.cpp b/indra/newview/llbuildnewviewsscheduler.cpp index d7f1cd871..964155b58 100644 --- a/indra/newview/llbuildnewviewsscheduler.cpp +++ b/indra/newview/llbuildnewviewsscheduler.cpp @@ -62,6 +62,7 @@ void LLBuildNewViewsScheduler::buildNewViews(LLInventoryPanel* panelp, LLInvento else if (objectp->getType() == LLAssetType::AT_CATEGORY) // build new view for category { LLInvFVBridge* new_listener = LLInvFVBridge::createBridge(objectp->getType(), + objectp->getType(), LLInventoryType::IT_CATEGORY, panelp, objectp->getUUID()); @@ -82,6 +83,7 @@ void LLBuildNewViewsScheduler::buildNewViews(LLInventoryPanel* panelp, LLInvento LLInventoryItem* item = (LLInventoryItem*)objectp; LLInvFVBridge* new_listener = LLInvFVBridge::createBridge( item->getType(), + item->getActualType(), item->getInventoryType(), panelp, item->getUUID(), diff --git a/indra/newview/llchatbar.cpp b/indra/newview/llchatbar.cpp index f0e0a1b06..c3a02ce54 100644 --- a/indra/newview/llchatbar.cpp +++ b/indra/newview/llchatbar.cpp @@ -674,7 +674,7 @@ void LLChatBar::sendChatFromViewer(const LLWString &wtext, EChatType type, BOOL utf8_text = utf8str_truncate(utf8_text, MAX_STRING - 1); } -// [RLVa:KB] - Checked: 2010-03-27 (RLVa-1.1.1a) | Modified: RLVa-1.2.0b +// [RLVa:KB] - Checked: 2010-03-27 (RLVa-1.2.0b) | Modified: RLVa-1.2.0b if ( (0 == channel) && (rlv_handler_t::isEnabled()) ) { // Adjust the (public) chat "volume" on chat and gestures (also takes care of playing the proper animation) @@ -685,7 +685,7 @@ void LLChatBar::sendChatFromViewer(const LLWString &wtext, EChatType type, BOOL else if ( (CHAT_TYPE_WHISPER == type) && (gRlvHandler.hasBehaviour(RLV_BHVR_CHATWHISPER)) ) type = CHAT_TYPE_NORMAL; - animate &= !gRlvHandler.hasBehaviour( (!rlvIsEmote(utf8_text)) ? RLV_BHVR_REDIRCHAT : RLV_BHVR_REDIREMOTE ); + animate &= !gRlvHandler.hasBehaviour( (!RlvUtil::isEmote(utf8_text)) ? RLV_BHVR_REDIRCHAT : RLV_BHVR_REDIREMOTE ); } // [/RLVa:KB] @@ -728,7 +728,7 @@ void LLChatBar::sendChatFromViewer(const LLWString &wtext, EChatType type, BOOL void send_chat_from_viewer(std::string utf8_out_text, EChatType type, S32 channel) // [/RLVa:KB] { -// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.1.1a) | Modified: RLVa-1.2.0a +// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0b) | Modified: RLVa-1.2.0a // Only process chat messages (ie not CHAT_TYPE_START, CHAT_TYPE_STOP, etc) if ( (rlv_handler_t::isEnabled()) && ( (CHAT_TYPE_WHISPER == type) || (CHAT_TYPE_NORMAL == type) || (CHAT_TYPE_SHOUT == type) ) ) { @@ -762,7 +762,7 @@ void send_chat_from_viewer(std::string utf8_out_text, EChatType type, S32 channe // Don't allow chat on debug channel if @sendchat, @redirchat or @rediremote restricted (shows as public chat on viewers) if (CHAT_CHANNEL_DEBUG == channel) { - bool fIsEmote = rlvIsEmote(utf8_out_text); + bool fIsEmote = RlvUtil::isEmote(utf8_out_text); if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SENDCHAT)) || ((!fIsEmote) && (gRlvHandler.hasBehaviour(RLV_BHVR_REDIRCHAT))) || ((fIsEmote) && (gRlvHandler.hasBehaviour(RLV_BHVR_REDIREMOTE))) ) diff --git a/indra/newview/llfirstuse.cpp b/indra/newview/llfirstuse.cpp index 2b7b01d16..9ee24d6d8 100644 --- a/indra/newview/llfirstuse.cpp +++ b/indra/newview/llfirstuse.cpp @@ -277,25 +277,3 @@ void LLFirstUse::useMedia() LLNotifications::instance().add("FirstMedia"); } } - -// [RLVa:KB] - Version: 1.23.4 | Checked: RLVa-1.0.3a (2009-09-10) | Added: RLVa-1.0.3a - -bool rlvHasVisibleFirstUseNotification() -{ - LLNotificationChannelPtr activeNotifications = LLNotifications::instance().getChannel("Notifications"); - for (LLNotificationChannel::Iterator itNotif = activeNotifications->begin(); itNotif != activeNotifications->end(); itNotif++) - if ((*itNotif)->getName().find(RLV_SETTING_FIRSTUSE_PREFIX) == 0) - return true; - return false; -} - -void LLFirstUse::showRlvFirstUseNotification(const std::string& strName) -{ - if ( (gSavedSettings.getWarning(strName)) && (!rlvHasVisibleFirstUseNotification()) ) - { - gSavedSettings.setWarning(strName, FALSE); - LLNotifications::instance().add(strName); - } -} - -// [/RLVa:KB] diff --git a/indra/newview/llfirstuse.h b/indra/newview/llfirstuse.h index e76d540a5..14de782ea 100644 --- a/indra/newview/llfirstuse.h +++ b/indra/newview/llfirstuse.h @@ -113,15 +113,6 @@ public: protected: static std::set sConfigVariables; - -// [RLVa:KB] - Checked: RLVa-1.0.3a (2009-09-10) | Added: RLVa-1.0.3a -public: - static void showRlvFirstUseNotification(const std::string& strName); - - static void useRlvDetach() { showRlvFirstUseNotification(RLV_SETTING_FIRSTUSE_DETACH); } - static void useRlvEnableWear() { showRlvFirstUseNotification(RLV_SETTING_FIRSTUSE_ENABLEWEAR); } - static void useRlvFartouch() { showRlvFirstUseNotification(RLV_SETTING_FIRSTUSE_FARTOUCH); } -// [/RLVa:KB] }; #endif diff --git a/indra/newview/llfloaterchat.cpp b/indra/newview/llfloaterchat.cpp index 7e52aca0a..d434ecdb8 100644 --- a/indra/newview/llfloaterchat.cpp +++ b/indra/newview/llfloaterchat.cpp @@ -251,7 +251,7 @@ void LLFloaterChat::addChatHistory(const LLChat& chat, bool log_to_file) if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) && (!chat.mRlvLocFiltered) && (CHAT_SOURCE_AGENT != chat.mSourceType) ) { LLChat& rlvChat = const_cast(chat); - gRlvHandler.filterLocation(rlvChat.mText); + RlvUtil::filterLocation(rlvChat.mText); rlvChat.mRlvLocFiltered = TRUE; } if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (!chat.mRlvNamesFiltered) ) @@ -261,7 +261,7 @@ void LLFloaterChat::addChatHistory(const LLChat& chat, bool log_to_file) if (CHAT_SOURCE_AGENT != chat.mSourceType) { // Filter object and system chat (names are filtered elsewhere to save ourselves an gObjectList lookup) - gRlvHandler.filterNames(rlvChat.mText); + RlvUtil::filterNames(rlvChat.mText); } rlvChat.mRlvNamesFiltered = TRUE; } @@ -429,7 +429,7 @@ void LLFloaterChat::addChat(const LLChat& chat, { LLChat& rlvChat = const_cast(chat); if (!from_instant_message) - gRlvHandler.filterLocation(rlvChat.mText); + RlvUtil::filterLocation(rlvChat.mText); rlvChat.mRlvLocFiltered = TRUE; } if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (!chat.mRlvNamesFiltered) ) @@ -438,7 +438,7 @@ void LLFloaterChat::addChat(const LLChat& chat, if ( (!from_instant_message) && (CHAT_SOURCE_AGENT != chat.mSourceType) ) { // Filter object and system chat (names are filtered elsewhere to save ourselves an gObjectList lookup) - gRlvHandler.filterNames(rlvChat.mText); + RlvUtil::filterNames(rlvChat.mText); } rlvChat.mRlvNamesFiltered = TRUE; } diff --git a/indra/newview/llfloatercustomize.cpp b/indra/newview/llfloatercustomize.cpp index 0c7357541..17d16bb61 100644 --- a/indra/newview/llfloatercustomize.cpp +++ b/indra/newview/llfloatercustomize.cpp @@ -223,6 +223,10 @@ public: childSetAction("Cancel", onCancel, this ); childSetAction("Check All", onCheckAll, this ); childSetAction("Uncheck All", onUncheckAll, this ); + + LLCheckBoxCtrl* pOutfitFoldersCtrl = getChild("checkbox_use_outfits"); + pOutfitFoldersCtrl->setCommitCallback(&LLMakeOutfitDialog::onOutfitFoldersToggle); + pOutfitFoldersCtrl->setCallbackUserData(this); } BOOL getRenameClothing() @@ -251,9 +255,11 @@ public: void setWearableToInclude( S32 wearable, S32 enabled, S32 selected ) { - if( (0 <= wearable) && (wearable < WT_COUNT) ) + EWearableType wtType = (EWearableType)wearable; + if ( ( (0 <= wtType) && (wtType < WT_COUNT) ) && + ( (LLAssetType::AT_BODYPART != LLWearable::typeToAssetType(wtType)) || (!gSavedSettings.getBOOL("UseOutfitFolders")) ) ) { - std::string name = std::string("checkbox_") + LLWearable::typeToTypeLabel( (EWearableType)wearable ); + std::string name = std::string("checkbox_") + LLWearable::typeToTypeLabel(wtType); childSetEnabled(name, enabled); childSetValue(name, selected); } @@ -323,6 +329,39 @@ public: LLMakeOutfitDialog* self = (LLMakeOutfitDialog*) userdata; self->close(); // destroys this object } + + BOOL postBuild() + { + refresh(); + return TRUE; + } + + void refresh() + { + BOOL fUseOutfits = gSavedSettings.getBOOL("UseOutfitFolders"); + + for (S32 idxType = 0; idxType < WT_COUNT; idxType++ ) + { + EWearableType wtType = (EWearableType)idxType; + if (LLAssetType::AT_BODYPART != LLWearable::typeToAssetType(wtType)) + continue; + LLCheckBoxCtrl* pCheckCtrl = getChild(std::string("checkbox_") + LLWearable::typeToTypeLabel(wtType)); + if (!pCheckCtrl) + continue; + + pCheckCtrl->setEnabled(!fUseOutfits); + if (fUseOutfits) + pCheckCtrl->setValue(TRUE); + } + childSetEnabled("checkbox_use_links", !fUseOutfits); + } + + static void onOutfitFoldersToggle(LLUICtrl*, void* pParam) + { + LLMakeOutfitDialog* pSelf = (LLMakeOutfitDialog*)pParam; + if (pSelf) + pSelf->refresh(); + } }; ///////////////////////////////////////////////////////////////////// diff --git a/indra/newview/llfloaterobjectiminfo.cpp b/indra/newview/llfloaterobjectiminfo.cpp index 19721ccc4..02a98511c 100644 --- a/indra/newview/llfloaterobjectiminfo.cpp +++ b/indra/newview/llfloaterobjectiminfo.cpp @@ -117,7 +117,7 @@ void LLFloaterObjectIMInfo::update(const LLUUID& object_id, const std::string& n // bool my_object = (owner_id == gAgentID); // [RLVa:KB] - Version: 1.23.4 | Checked: 2009-07-08 (RLVa-1.0.0e) | Added: RLVa-0.2.0g - bool my_object = (owner_id == gAgentID) || ((gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (gRlvHandler.isAgentNearby(owner_id))); + bool my_object = (owner_id == gAgentID) || ((gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (RlvUtil::isNearbyAgent(owner_id))); // [/RLVa:KB] childSetEnabled("Mute",!my_object); @@ -151,7 +151,7 @@ void LLFloaterObjectIMInfo::onClickOwner(void* data) } // else // [RLVa:KB] - Version: 1.23.4 | Checked: 2009-07-08 (RLVa-1.0.0e) | Added: RLVa-0.2.0g - else if ( (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) || (!gRlvHandler.isAgentNearby(self->mOwnerID)) ) + else if ( (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) || (!RlvUtil::isNearbyAgent(self->mOwnerID)) ) // [/RLVa:KB] { LLFloaterAvatarInfo::showFromObject(self->mOwnerID); @@ -165,7 +165,7 @@ void LLFloaterObjectIMInfo::onClickMute(void* data) LLMute::EType mute_type = (self->mOwnerIsGroup) ? LLMute::GROUP : LLMute::AGENT; // [RLVa:KB] - Version: 1.23.4 | Checked: 2009-07-08 (RLVa-1.0.0e) | Added: RLVa-0.2.0g - if ( (LLMute::GROUP != mute_type) && (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (gRlvHandler.isAgentNearby(self->mOwnerID)) ) + if ( (LLMute::GROUP != mute_type) && (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (RlvUtil::isNearbyAgent(self->mOwnerID)) ) { return; } @@ -188,7 +188,7 @@ void LLFloaterObjectIMInfo::nameCallback(const LLUUID& id, const std::string& fi } // [RLVa:KB] - Version: 1.23.4 | Checked: 2009-07-08 (RLVa-1.0.0e) | Added: RLVa-0.2.0g - if ( (!is_group) && (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (gRlvHandler.isAgentNearby(id)) ) + if ( (!is_group) && (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (RlvUtil::isNearbyAgent(id)) ) { self->mOwnerName = RlvStrings::getAnonym(self->mOwnerName); } diff --git a/indra/newview/llfloaterproperties.cpp b/indra/newview/llfloaterproperties.cpp index b0ba5bbad..db714ed05 100644 --- a/indra/newview/llfloaterproperties.cpp +++ b/indra/newview/llfloaterproperties.cpp @@ -332,6 +332,7 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item) GP_OBJECT_MANIPULATE); BOOL can_agent_sell = gAgent.allowOperation(PERM_OWNER, perm, GP_OBJECT_SET_SALE); + BOOL is_link = i->getIsLinkType(); // You need permission to modify the object to modify an inventory // item in it. @@ -522,7 +523,7 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item) ///////////// // Check for ability to change values. - if (is_obj_modify && can_agent_manipulate) + if (!is_link && is_obj_modify && can_agent_manipulate) { childSetEnabled("CheckShareWithGroup",TRUE); childSetEnabled("CheckEveryoneCopy",(owner_mask & PERM_COPY) && (owner_mask & PERM_TRANSFER)); diff --git a/indra/newview/llfolderview.cpp b/indra/newview/llfolderview.cpp index 5568d044f..7edaa0f4d 100644 --- a/indra/newview/llfolderview.cpp +++ b/indra/newview/llfolderview.cpp @@ -4672,6 +4672,15 @@ LLInventoryFilter::~LLInventoryFilter() BOOL LLInventoryFilter::check(LLFolderViewItem* item) { + LLFolderViewEventListener* listener = item->getListener(); + const LLUUID& item_id = listener->getUUID(); + const LLInventoryObject *obj = gInventory.getObject(item_id); + if (isActive() && obj && obj->getIsLinkType()) + { + // When filtering is active, omit links. + return FALSE; + } + time_t earliest; earliest = time_corrected() - mFilterOps.mHoursAgo * 3600; @@ -4683,8 +4692,6 @@ BOOL LLInventoryFilter::check(LLFolderViewItem* item) { earliest = 0; } - LLFolderViewEventListener* listener = item->getListener(); - const LLUUID& item_id = listener->getUUID(); //When searching for all labels, we need to explode the filter string //Into an array, and then compare each string to the label seperately diff --git a/indra/newview/llfolderview.h b/indra/newview/llfolderview.h index 3b6fce269..2726aa15d 100644 --- a/indra/newview/llfolderview.h +++ b/indra/newview/llfolderview.h @@ -100,6 +100,7 @@ public: virtual void cutToClipboard() = 0; virtual BOOL isClipboardPasteable() const = 0; virtual void pasteFromClipboard() = 0; + virtual void pasteLinkFromClipboard() = 0; virtual void buildContextMenu(LLMenuGL& menu, U32 flags) = 0; virtual BOOL isUpToDate() const = 0; virtual BOOL hasChildren() const = 0; @@ -382,13 +383,6 @@ protected: BOOL mIsLoading; LLTimer mTimeSinceRequestStart; - // This function clears the currently selected item, and records - // the specified selected item appropriately for display and use - // in the UI. If open is TRUE, then folders are opened up along - // the way to the selection. - void setSelectionFromRoot(LLFolderViewItem* selection, BOOL openitem, - BOOL take_keyboard_focus = TRUE); - // helper function to change the selection from the root. void changeSelectionFromRoot(LLFolderViewItem* selection, BOOL selected); @@ -401,6 +395,13 @@ protected: virtual BOOL addFolder(LLFolderViewFolder*) { return FALSE; } public: + // This function clears the currently selected item, and records + // the specified selected item appropriately for display and use + // in the UI. If open is TRUE, then folders are opened up along + // the way to the selection. + void setSelectionFromRoot(LLFolderViewItem* selection, BOOL openitem, + BOOL take_keyboard_focus = TRUE); + static void initClass(); static void cleanupClass(); diff --git a/indra/newview/llgesturemgr.cpp b/indra/newview/llgesturemgr.cpp index beb514993..aed12d956 100644 --- a/indra/newview/llgesturemgr.cpp +++ b/indra/newview/llgesturemgr.cpp @@ -69,7 +69,10 @@ LLGestureManager gGestureManager; // 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. LLGestureManager::LLGestureManager() @@ -216,15 +219,17 @@ void LLGestureManager::activateGestureWithAsset(const LLUUID& item_id, BOOL inform_server, BOOL deactivate_similar) { + const LLUUID& base_item_id = get_linked_uuid(item_id); + if( !gAssetStorage ) { llwarns << "LLGestureManager::activateGestureWithAsset without valid gAssetStorage" << llendl; return; } // If gesture is already active, nothing to do. - if (isGestureActive(item_id)) + if (isGestureActive(base_item_id)) { - llwarns << "Tried to loadGesture twice " << item_id << llendl; + llwarns << "Tried to loadGesture twice " << base_item_id << llendl; return; } @@ -236,13 +241,13 @@ void LLGestureManager::activateGestureWithAsset(const LLUUID& item_id, // For now, put NULL into the item map. We'll build a gesture // class object when the asset data arrives. - mActive[item_id] = NULL; + mActive[base_item_id] = NULL; // Copy the UUID if (asset_id.notNull()) { LLLoadInfo* info = new LLLoadInfo; - info->mItemID = item_id; + info->mItemID = base_item_id; info->mInformServer = inform_server; info->mDeactivateSimilar = deactivate_similar; @@ -262,10 +267,11 @@ void LLGestureManager::activateGestureWithAsset(const LLUUID& item_id, void LLGestureManager::deactivateGesture(const LLUUID& item_id) { - item_map_t::iterator it = mActive.find(item_id); + const LLUUID& base_item_id = get_linked_uuid(item_id); + item_map_t::iterator it = mActive.find(base_item_id); if (it == mActive.end()) { - llwarns << "deactivateGesture for inactive gesture " << item_id << llendl; + llwarns << "deactivateGesture for inactive gesture " << base_item_id << llendl; return; } @@ -282,7 +288,7 @@ void LLGestureManager::deactivateGesture(const LLUUID& item_id) } mActive.erase(it); - gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); + gInventory.addChangedMask(LLInventoryObserver::LABEL, base_item_id); // Inform the database of this change LLMessageSystem* msg = gMessageSystem; @@ -293,7 +299,7 @@ void LLGestureManager::deactivateGesture(const LLUUID& item_id) msg->addU32("Flags", 0x0); msg->nextBlock("Data"); - msg->addUUID("ItemID", item_id); + msg->addUUID("ItemID", base_item_id); msg->addU32("GestureFlags", 0x0); gAgent.sendReliableMessage(); @@ -304,6 +310,7 @@ void LLGestureManager::deactivateGesture(const LLUUID& item_id) void LLGestureManager::deactivateSimilarGestures(LLMultiGesture* in, const LLUUID& in_item_id) { + const LLUUID& base_in_item_id = get_linked_uuid(in_item_id); std::vector gest_item_ids; // Deactivate all gestures that match @@ -315,7 +322,7 @@ void LLGestureManager::deactivateSimilarGestures(LLMultiGesture* in, const LLUUI // Don't deactivate the gesture we are looking for duplicates of // (for replaceGesture) - if (!gest || item_id == in_item_id) + if (!gest || item_id == base_in_item_id) { // legal, can have null pointers in list ++it; @@ -390,14 +397,16 @@ void LLGestureManager::deactivateSimilarGestures(LLMultiGesture* in, const LLUUI BOOL LLGestureManager::isGestureActive(const LLUUID& item_id) { - item_map_t::iterator it = mActive.find(item_id); + const LLUUID& base_item_id = get_linked_uuid(item_id); + item_map_t::iterator it = mActive.find(base_item_id); return (it != mActive.end()); } BOOL LLGestureManager::isGesturePlaying(const LLUUID& item_id) { - item_map_t::iterator it = mActive.find(item_id); + const LLUUID& base_item_id = get_linked_uuid(item_id); + item_map_t::iterator it = mActive.find(base_item_id); if (it == mActive.end()) return FALSE; LLMultiGesture* gesture = (*it).second; @@ -408,19 +417,20 @@ BOOL LLGestureManager::isGesturePlaying(const LLUUID& item_id) void LLGestureManager::replaceGesture(const LLUUID& item_id, LLMultiGesture* new_gesture, const LLUUID& asset_id) { - item_map_t::iterator it = mActive.find(item_id); + const LLUUID& base_item_id = get_linked_uuid(item_id); + item_map_t::iterator it = mActive.find(base_item_id); if (it == mActive.end()) { - llwarns << "replaceGesture for inactive gesture " << item_id << llendl; + llwarns << "replaceGesture for inactive gesture " << base_item_id << llendl; return; } LLMultiGesture* old_gesture = (*it).second; stopGesture(old_gesture); - mActive.erase(item_id); + mActive.erase(base_item_id); - mActive[item_id] = new_gesture; + mActive[base_item_id] = new_gesture; delete old_gesture; old_gesture = NULL; @@ -431,7 +441,7 @@ void LLGestureManager::replaceGesture(const LLUUID& item_id, LLMultiGesture* new mDeactivateSimilarNames.clear(); LLLoadInfo* info = new LLLoadInfo; - info->mItemID = item_id; + info->mItemID = base_item_id; info->mInformServer = TRUE; info->mDeactivateSimilar = FALSE; @@ -448,16 +458,17 @@ void LLGestureManager::replaceGesture(const LLUUID& item_id, LLMultiGesture* new void LLGestureManager::replaceGesture(const LLUUID& item_id, const LLUUID& new_asset_id) { - item_map_t::iterator it = gGestureManager.mActive.find(item_id); + const LLUUID& base_item_id = get_linked_uuid(item_id); + item_map_t::iterator it = gGestureManager.mActive.find(base_item_id); if (it == mActive.end()) { - llwarns << "replaceGesture for inactive gesture " << item_id << llendl; + llwarns << "replaceGesture for inactive gesture " << base_item_id << llendl; return; } // mActive owns this gesture pointer, so clean up memory. LLMultiGesture* gesture = (*it).second; - gGestureManager.replaceGesture(item_id, gesture, new_asset_id); + gGestureManager.replaceGesture(base_item_id, gesture, new_asset_id); } void LLGestureManager::playGesture(LLMultiGesture* gesture) @@ -481,7 +492,8 @@ void LLGestureManager::playGesture(LLMultiGesture* gesture) // Convenience function that looks up the item_id for you. void LLGestureManager::playGesture(const LLUUID& item_id) { - item_map_t::iterator it = mActive.find(item_id); + const LLUUID& base_item_id = get_linked_uuid(item_id); + item_map_t::iterator it = mActive.find(base_item_id); if (it == mActive.end()) return; LLMultiGesture* gesture = (*it).second; @@ -1070,7 +1082,8 @@ void LLGestureManager::stopGesture(LLMultiGesture* gesture) void LLGestureManager::stopGesture(const LLUUID& item_id) { - item_map_t::iterator it = mActive.find(item_id); + const LLUUID& base_item_id = get_linked_uuid(item_id); + item_map_t::iterator it = mActive.find(base_item_id); if (it == mActive.end()) return; LLMultiGesture* gesture = (*it).second; @@ -1151,3 +1164,14 @@ void LLGestureManager::getItemIDs(std::vector* ids) ids->push_back(it->first); } } + +// 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; +} diff --git a/indra/newview/llhudtext.cpp b/indra/newview/llhudtext.cpp index f338b6175..2b9e23c15 100644 --- a/indra/newview/llhudtext.cpp +++ b/indra/newview/llhudtext.cpp @@ -571,7 +571,7 @@ void LLHUDText::renderText(BOOL for_select) void LLHUDText::setStringUTF8(const std::string &wtext) { -// [RLVa:KB] - Checked: 2009-07-09 (RLVa-1.0.0f) +// [RLVa:KB] - Checked: 2010-03-02 (RLVa-1.2.0a) | Modified: RLVa-1.0.0f // NOTE: setString() is only called for debug beacons and the floating name tags (which we don't want to censor // because you'd see "(Region hidden) LastName" if you happen to go to a sim who's name is your first name :p if (rlv_handler_t::isEnabled()) @@ -581,9 +581,9 @@ void LLHUDText::setStringUTF8(const std::string &wtext) if (gRlvHandler.canShowHoverText(mSourceObject)) { if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) - gRlvHandler.filterLocation(text); + RlvUtil::filterLocation(text); if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) - gRlvHandler.filterNames(text); + RlvUtil::filterNames(text); } else { diff --git a/indra/newview/llinventoryactions.cpp b/indra/newview/llinventoryactions.cpp index 2e3bb843f..a0998e7b7 100644 --- a/indra/newview/llinventoryactions.cpp +++ b/indra/newview/llinventoryactions.cpp @@ -93,9 +93,6 @@ //#include "llnotecardmagic.h" // -// Defined in llinventorybridge.cpp -void wear_attachments_on_avatar(const std::set& item_ids, BOOL remove); - const std::string NEW_LSL_NAME = "New Script"; // *TODO:Translate? (probably not) const std::string NEW_NOTECARD_NAME = "New Note"; // *TODO:Translate? (probably not) const std::string NEW_GESTURE_NAME = "New Gesture"; // *TODO:Translate? (probably not) @@ -126,12 +123,6 @@ bool doToSelected(LLFolderView* folder, std::string action) std::set selected_items; folder->getSelectionList(selected_items); - if ( ("attach" == action) && (selected_items.size() > 1) ) - { - wear_attachments_on_avatar(selected_items, FALSE); - return true; - } - LLMultiPreview* multi_previewp = NULL; LLMultiProperties* multi_propertiesp = NULL; @@ -794,8 +785,6 @@ class LLBeginIMSession : public inventory_panel_listener_t } }; -void rez_attachment(LLViewerInventoryItem* item, LLViewerJointAttachment* attachment); - class LLAttachObject : public inventory_panel_listener_t { bool handleEvent(LLPointer event, const LLSD& userdata) diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 5b9a1039f..4f30831fd 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -39,6 +39,7 @@ #include "message.h" +#include "cofmgr.h" #include "llagent.h" #include "llcallingcard.h" #include "llcheckboxctrl.h" // for radio buttons @@ -110,6 +111,7 @@ // [RLVa:KB] #include "rlvhandler.h" +#include "llattachmentsmgr.h" // [/RLVa:KB] // Helpers @@ -129,7 +131,7 @@ void dec_busy_count() // Function declarations struct LLWearableHoldingPattern; -void wear_inventory_category_on_avatar(LLInventoryCategory* category, BOOL append); +void wear_inventory_category_on_avatar(LLInventoryCategory* category, BOOL append, BOOL replace = FALSE); void wear_inventory_category_on_avatar_step2( BOOL proceed, void* userdata); void wear_inventory_category_on_avatar_loop(LLWearable* wearable, void*); void wear_inventory_category_on_avatar_step3(LLWearableHoldingPattern* holder, BOOL append); @@ -137,8 +139,6 @@ void remove_inventory_category_from_avatar(LLInventoryCategory* category); void remove_inventory_category_from_avatar_step2( BOOL proceed, void* userdata); bool move_task_inventory_callback(const LLSD& notification, const LLSD& response, LLMoveInv*); bool confirm_replace_attachment_rez(const LLSD& notification, const LLSD& response); -void wear_attachments_on_avatar(const std::set& item_ids, BOOL remove); -void wear_attachments_on_avatar(const LLInventoryModel::item_array_t& items, BOOL remove); // void gotImageForSaveItemAs(BOOL success, @@ -188,12 +188,16 @@ std::string ICON_NAME[ICON_NAME_COUNT] = "inv_item_animation.tga", "inv_item_gesture.tga", + + "inv_link_item.tga", + "inv_link_folder.tga" }; struct LLWearInfo { LLUUID mCategoryID; BOOL mAppend; + BOOL mReplace; }; @@ -231,7 +235,7 @@ time_t LLInvFVBridge::getCreationDate() const return 0; } -// Can be destoryed (or moved to trash) +// Can be destroyed (or moved to trash) BOOL LLInvFVBridge::isItemRemovable() { // derf @@ -242,7 +246,15 @@ BOOL LLInvFVBridge::isItemRemovable() } // LLInventoryModel* model = mInventoryPanel->getModel(); - if(!model) return FALSE; + if (!model) + { + return FALSE; + } + const LLInventoryObject *obj = model->getItem(mUUID); + if (obj && obj->getIsLinkType()) + { + return TRUE; + } if(model->isObjectDescendentOf(mUUID, gAgent.getInventoryRootID())) { return TRUE; @@ -499,14 +511,77 @@ BOOL LLInvFVBridge::isClipboardPasteable() const } // LLInventoryModel* model = mInventoryPanel->getModel(); - if(!model) return FALSE; - BOOL is_agent_inventory = model->isObjectDescendentOf(mUUID, gAgent.getInventoryRootID()); - - if(LLInventoryClipboard::instance().hasContents() && is_agent_inventory) + if (!model) { - return TRUE; + return FALSE; } - return FALSE; + + BOOL is_agent_inventory = model->isObjectDescendentOf(mUUID, gAgent.getInventoryRootID()); + if (!LLInventoryClipboard::instance().hasContents() || !is_agent_inventory) + { + return FALSE; + } + + const LLUUID &agent_id = gAgent.getID(); + LLDynamicArray objects; + LLInventoryClipboard::instance().retrieve(objects); + S32 count = objects.count(); + for(S32 i = 0; i < count; i++) + { + const LLUUID &item_id = objects.get(i); + + // Can't paste folders + const LLInventoryCategory *cat = model->getCategory(item_id); + if (cat) + { + return FALSE; + } + + const LLInventoryItem *item = model->getItem(item_id); + if (item) + { + if (!item->getPermissions().allowCopyBy(agent_id)) + { + return FALSE; + } + } + } + + return TRUE; +} + +BOOL LLInvFVBridge::isClipboardPasteableAsLink() const +{ + if (!LLInventoryClipboard::instance().hasContents() || !isAgentInventory()) + { + return FALSE; + } + const LLInventoryModel* model = mInventoryPanel->getModel(); + if (!model) + { + return FALSE; + } + + LLDynamicArray objects; + LLInventoryClipboard::instance().retrieve(objects); + S32 count = objects.count(); + for(S32 i = 0; i < count; i++) + { + const LLInventoryItem *item = model->getItem(objects.get(i)); + if (item) + { + if (!LLAssetType::lookupCanLink(item->getActualType())) + { + return FALSE; + } + } + const LLViewerInventoryCategory *cat = model->getCategory(objects.get(i)); + if (cat && LLAssetType::AT_NONE == cat->getPreferredType()) + { + return FALSE; + } + } + return TRUE; } void hideContextEntries(LLMenuGL& menu, @@ -558,37 +633,44 @@ void hideContextEntries(LLMenuGL& menu, void LLInvFVBridge::getClipboardEntries(bool show_asset_id, std::vector &items, std::vector &disabled_items, U32 flags) { - // *TODO: Translate - items.push_back(std::string("Rename")); - if (!isItemRenameable() || (flags & FIRST_SELECTED_ITEM) == 0) - { - disabled_items.push_back(std::string("Rename")); - } + const LLInventoryObject *obj = getInventoryObject(); - if (show_asset_id) + if (obj) { - items.push_back(std::string("Copy Asset UUID")); - - if ( (! ( isItemPermissive() || gAgent.isGodlike() ) ) - || (flags & FIRST_SELECTED_ITEM) == 0) + if (obj->getIsLinkType()) { - disabled_items.push_back(std::string("Copy Asset UUID")); + items.push_back(std::string("Find Original")); + if (isLinkedObjectMissing()) + { + disabled_items.push_back(std::string("Find Original")); + } } - } - + else + { + items.push_back(std::string("Rename")); + if (!isItemRenameable() || (flags & FIRST_SELECTED_ITEM) == 0) + { + disabled_items.push_back(std::string("Rename")); + } + if (show_asset_id) + { + items.push_back(std::string("Copy Asset UUID")); + if ((!( isItemPermissive() || gAgent.isGodlike())) + || (flags & FIRST_SELECTED_ITEM) == 0) + { + disabled_items.push_back(std::string("Copy Asset UUID")); + } + } + items.push_back(std::string("Copy Separator")); - - - - - items.push_back(std::string("Copy Separator")); - - items.push_back(std::string("Copy")); - if (!isItemCopyable()) - { - disabled_items.push_back(std::string("Copy")); + items.push_back(std::string("Copy")); + if (!isItemCopyable()) + { + disabled_items.push_back(std::string("Copy")); + } + } } items.push_back(std::string("Paste")); @@ -597,6 +679,12 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id, std::vector disabled_items; if(isInTrash()) { + const LLInventoryObject *obj = getInventoryObject(); + if (obj && obj->getIsLinkType()) + { + items.push_back(std::string("Find Original")); + if (isLinkedObjectMissing()) + { + disabled_items.push_back(std::string("Find Original")); + } + } items.push_back(std::string("Purge Item")); if (!isItemRemovable()) { @@ -721,6 +818,36 @@ BOOL LLInvFVBridge::isInTrash() const return model->isObjectDescendentOf(mUUID, trash_id); } +BOOL LLInvFVBridge::isLinkedObjectInTrash() const +{ + if (isInTrash()) return TRUE; + + const LLInventoryObject *obj = getInventoryObject(); + if (obj && obj->getIsLinkType()) + { + LLInventoryModel* model = mInventoryPanel->getModel(); + if(!model) return FALSE; + const LLUUID trash_id = model->findCategoryUUIDForType(LLAssetType::AT_TRASH); + return model->isObjectDescendentOf(obj->getLinkedUUID(), trash_id); + } + return FALSE; +} + +BOOL LLInvFVBridge::isLinkedObjectMissing() const +{ + const LLInventoryObject *obj = getInventoryObject(); + if (!obj) + { + return TRUE; + } + if (obj->getIsLinkType() && LLAssetType::lookupIsLinkType(obj->getType())) + { + return TRUE; + } + return FALSE; +} + + BOOL LLInvFVBridge::isAgentInventory() const { // derf @@ -806,6 +933,7 @@ const char* safe_inv_type_lookup(LLInventoryType::EType inv_type) } LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type, + LLAssetType::EType actual_asset_type, LLInventoryType::EType inv_type, LLInventoryPanel* inventory, const LLUUID& uuid, @@ -905,9 +1033,21 @@ LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type, case LLAssetType::AT_CATEGORY: case LLAssetType::AT_ROOT_CATEGORY: + if (actual_asset_type == LLAssetType::AT_LINK_FOLDER) + { + // Create a link folder handler instead. + new_listener = new LLLinkFolderBridge(inventory, uuid); + break; + } new_listener = new LLFolderBridge(inventory, uuid); break; + case LLAssetType::AT_LINK: + case LLAssetType::AT_LINK_FOLDER: + // Only should happen for broken links. + new_listener = new LLLinkItemBridge(inventory, uuid); + break; + default: llinfos << "Unhandled asset type (llassetstorage.h): " << (S32)asset_type << llendl; @@ -929,7 +1069,11 @@ LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type, void LLItemBridge::performAction(LLFolderView* folder, LLInventoryModel* model, std::string action) { - if ("open" == action) + if ("goto" == action) + { + gotoItem(folder); + } + else if ("open" == action) { openItem(); } @@ -988,6 +1132,18 @@ void LLItemBridge::performAction(LLFolderView* folder, LLInventoryModel* model, folder_view_itemp->getListener()->pasteFromClipboard(); return; } + else if ("paste_link" == action) + { + // Single item only + LLInventoryItem* itemp = model->getItem(mUUID); + if (!itemp) return; + + LLFolderViewItem* folder_view_itemp = folder->getItemByID(itemp->getParentUUID()); + if (!folder_view_itemp) return; + + folder_view_itemp->getListener()->pasteLinkFromClipboard(); + return; + } else if("reupload" == action) { LLInventoryItem* item = model->getItem(mUUID); @@ -1087,6 +1243,19 @@ void LLItemBridge::restoreToWorld() } } +void LLItemBridge::gotoItem(LLFolderView *folder) +{ + LLInventoryObject *obj = getInventoryObject(); + if (obj && obj->getIsLinkType()) + { + LLInventoryView *view = LLInventoryView::getActiveInventory(); + if (view) + { + view->getPanel()->setSelection(obj->getLinkedUUID(), TAKE_FOCUS_NO); + } + } +} + LLUIImagePtr LLItemBridge::getIcon() const { return LLUI::getUIImage(ICON_NAME[OBJECT_ICON_NAME]); @@ -1147,6 +1316,11 @@ std::string LLItemBridge::getLabelSuffix() const BOOL xfer = perm.allowOperationBy(PERM_TRANSFER, gAgent.getID()); // *TODO: Translate + static std::string LINK = " (link)"; + static std::string BROKEN_LINK = " (broken link)"; + if (LLAssetType::lookupIsLinkType(item->getType())) return BROKEN_LINK; + if (item->getIsLinkType()) return LINK; + const char* EMPTY = ""; const char* NO_COPY = " (no copy)"; const char* NO_MOD = " (no modify)"; @@ -1268,12 +1442,17 @@ BOOL LLItemBridge::removeItem() BOOL LLItemBridge::isItemCopyable() const { LLViewerInventoryItem* item = getItem(); - if (item) + if (item && !item->getIsLinkType()) { - return (item->getPermissions().allowCopyBy(gAgent.getID())); + // All items can be copied since you can + // at least paste-as-link the item, though you + // still may not be able paste the item. + return TRUE; +// return (item->getPermissions().allowCopyBy(gAgent.getID())); } return FALSE; } + BOOL LLItemBridge::copyToClipboard() const { if(isItemCopyable()) @@ -1360,8 +1539,6 @@ BOOL LLFolderBridge::isItemRemovable() { return FALSE; } - /* - // if(!model->isObjectDescendentOf(mUUID, gAgent.getInventoryRootID())) { return FALSE; @@ -1379,7 +1556,7 @@ BOOL LLFolderBridge::isItemRemovable() return FALSE; } - if( LLAssetType::AT_NONE != category->getPreferredType() ) + if ( (LLAssetType::AT_NONE != category->getPreferredType()) && (LLAssetType::AT_OUTFIT != category->getPreferredType()) ) { return FALSE; } @@ -1401,16 +1578,15 @@ BOOL LLFolderBridge::isItemRemovable() for( i = 0; i < descendent_items.count(); i++ ) { LLInventoryItem* item = descendent_items[i]; - if( (item->getType() == LLAssetType::AT_CLOTHING) || - (item->getType() == LLAssetType::AT_BODYPART) ) + if ((item->getType() == LLAssetType::AT_CLOTHING || + item->getType() == LLAssetType::AT_BODYPART) && !item->getIsLinkType()) { if( gAgent.isWearingItem( item->getUUID() ) ) { return FALSE; } } - else - if( item->getType() == LLAssetType::AT_OBJECT ) + else if (item->getType() == LLAssetType::AT_OBJECT && !item->getIsLinkType()) { if( avatar->isWearingAttachment( item->getUUID() ) ) { @@ -1418,9 +1594,6 @@ BOOL LLFolderBridge::isItemRemovable() } } } - // - */ - // return TRUE; } @@ -1448,6 +1621,64 @@ BOOL LLFolderBridge::isUpToDate() const // } +BOOL LLFolderBridge::isClipboardPasteableAsLink() const +{ + // Check normal paste-as-link permissions + if (!LLInvFVBridge::isClipboardPasteableAsLink()) + { + return FALSE; + } + + LLInventoryModel* model = mInventoryPanel->getModel(); + if (!model) + { + return FALSE; + } + + const LLViewerInventoryCategory *current_cat = getCategory(); + if (current_cat) + { +/* TODO + const BOOL is_in_friend_folder = LLFriendCardsManager::instance().isCategoryInFriendFolder(current_cat); +*/ + const LLUUID ¤t_cat_id = current_cat->getUUID(); + LLDynamicArray objects; + LLInventoryClipboard::instance().retrieve(objects); + S32 count = objects.count(); + for (S32 i = 0; i < count; i++) + { + const LLUUID &obj_id = objects.get(i); + const LLInventoryCategory *cat = model->getCategory(obj_id); + if (cat) + { + const LLUUID &cat_id = cat->getUUID(); + // Don't allow recursive pasting + if ((cat_id == current_cat_id) || + model->isObjectDescendentOf(current_cat_id, cat_id)) + { + return FALSE; + } + } +/* TODO + // Don't allow pasting duplicates to the Calling Card/Friends subfolders, see bug EXT-1599 + if (is_in_friend_folder) + { + // If object is direct descendent of current Friends subfolder than return false. + // Note: We can't use 'const LLInventoryCategory *cat', because it may be null + // in case type of obj_id is LLInventoryItem. + if (LLFriendCardsManager::instance().isObjDirectDescendentOfCategory(model->getObject(obj_id), current_cat)) + { + return FALSE; + } + } +*/ + } + } + return TRUE; + +} + + BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, BOOL drop) { @@ -1527,7 +1758,7 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, else if( item->getType() == LLAssetType::AT_OBJECT ) { - if( avatar->isWearingAttachment( item->getUUID() ) ) + if (avatar->isWearingAttachment(item->getLinkedUUID())) { is_movable = FALSE; // It's generally movable, but not into the trash! break; @@ -1897,6 +2128,10 @@ void LLFolderBridge::performAction(LLFolderView* folder, LLInventoryModel* model { pasteFromClipboard(); } + else if ("paste_link" == action) + { + pasteLinkFromClipboard(); + } else if ("properties" == action) { showProperties(); @@ -1909,6 +2144,10 @@ void LLFolderBridge::performAction(LLFolderView* folder, LLInventoryModel* model { modifyOutfit(TRUE); } + else if ("wearitems" == action) + { + modifyOutfit(TRUE, TRUE); + } else if ("removefromoutfit" == action) { // derf @@ -1964,7 +2203,7 @@ void LLFolderBridge::openItem() BOOL LLFolderBridge::isItemRenameable() const { LLViewerInventoryCategory* cat = (LLViewerInventoryCategory*)getCategory(); - if(cat && (cat->getPreferredType() == LLAssetType::AT_NONE) + if(cat && ((cat->getPreferredType() == LLAssetType::AT_NONE) || (cat->getPreferredType() == LLAssetType::AT_OUTFIT)) && (cat->getOwnerID() == gAgent.getID())) { return TRUE; @@ -2209,6 +2448,35 @@ void LLFolderBridge::pasteFromClipboard() } } +void LLFolderBridge::pasteLinkFromClipboard() +{ + const LLInventoryModel* model = mInventoryPanel->getModel(); + if(model) + { + const LLUUID parent_id(mUUID); + + LLDynamicArray objects; + LLInventoryClipboard::instance().retrieve(objects); + for (LLDynamicArray::const_iterator iter = objects.begin(); + iter != objects.end(); + ++iter) + { + const LLUUID &object_id = (*iter); + if (LLInventoryItem *item = model->getItem(object_id)) + { + link_inventory_item( + gAgent.getID(), + item->getLinkedUUID(), + parent_id, + item->getName(), + item->getDescription(), + LLAssetType::AT_LINK, + LLPointer(NULL)); + } + } + } +} + void LLFolderBridge::staticFolderOptionsMenu() { if (!sSelf) return; @@ -2233,7 +2501,7 @@ void LLFolderBridge::folderOptionsMenu() const LLInventoryCategory* category = model->getCategory(mUUID); bool is_default_folder = category && - (LLAssetType::AT_NONE != category->getPreferredType()); + (LLAssetType::AT_NONE != category->getPreferredType()) && (LLAssetType::AT_OUTFIT != category->getPreferredType()); // calling card related functionality for folders. @@ -2270,6 +2538,7 @@ void LLFolderBridge::folderOptionsMenu() { // mItems.push_back(std::string("Add To Outfit")); + mItems.push_back(std::string("Wear Items")); mItems.push_back(std::string("Replace Outfit")); // } @@ -2307,15 +2576,10 @@ void LLFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) // LLInventoryModel* model = mInventoryPanel->getModel(); if(!model) return; + LLUUID cof_id = LLCOFMgr::instance().getCOF(); LLUUID trash_id = model->findCategoryUUIDForType(LLAssetType::AT_TRASH); LLUUID lost_and_found_id = model->findCategoryUUIDForType(LLAssetType::AT_LOST_AND_FOUND); - - - - - - // [RLVa:KB] - Checked: 2009-07-10 (RLVa-1.0.0g) // Fixes LL bug mItems.clear(); @@ -2328,7 +2592,11 @@ void LLFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) mItems.push_back(std::string("Empty Lost And Found")); } - if(trash_id == mUUID) + if (cof_id == mUUID) + { + mItems.push_back(std::string("Take Off Items")); + } + else if(trash_id == mUUID) { // This is the trash. mItems.push_back(std::string("Empty Trash")); @@ -2337,6 +2605,15 @@ void LLFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { // This is a folder in the trash. mItems.clear(); // clear any items that used to exist + const LLInventoryObject *obj = getInventoryObject(); + if (obj && obj->getIsLinkType()) + { + mItems.push_back(std::string("Find Original")); + if (isLinkedObjectMissing()) + { + mDisabledItems.push_back(std::string("Find Original")); + } + } mItems.push_back(std::string("Purge Item")); if (!isItemRemovable()) { @@ -2347,18 +2624,18 @@ void LLFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) } else if(isAgentInventory()) // do not allow creating in library { - // only mature accounts can create undershirts/underwear - /*if (!gAgent.isTeen()) - { - sub_menu->append(new LLMenuItemCallGL("New Undershirt", - &createNewUndershirt, - NULL, - (void*)this)); - sub_menu->append(new LLMenuItemCallGL("New Underpants", - &createNewUnderpants, - NULL, - (void*)this)); - }*/ + // only mature accounts can create undershirts/underwear + /*if (!gAgent.isTeen()) + { + sub_menu->append(new LLMenuItemCallGL("New Undershirt", + &createNewUndershirt, + NULL, + (void*)this)); + sub_menu->append(new LLMenuItemCallGL("New Underpants", + &createNewUnderpants, + NULL, + (void*)this)); + }*/ /* BOOL contains_calling_cards = FALSE; LLInventoryModel::cat_array_t cat_array; @@ -2466,6 +2743,7 @@ BOOL LLFolderBridge::dragOrDrop(MASK mask, BOOL drop, case DAD_BODYPART: case DAD_ANIMATION: case DAD_GESTURE: + case DAD_LINK: accept = dragItemIntoFolder((LLInventoryItem*)cargo_data, drop); break; @@ -2628,7 +2906,7 @@ void LLFolderBridge::createWearable(LLUUID parent_id, EWearableType type) LLPointer(NULL)); } -void LLFolderBridge::modifyOutfit(BOOL append) +void LLFolderBridge::modifyOutfit(BOOL append, BOOL replace) { // derf if(std::find(LLInventoryPanel::sInstances.begin(), LLInventoryPanel::sInstances.end(), mInventoryPanel) == LLInventoryPanel::sInstances.end()) @@ -2642,7 +2920,7 @@ void LLFolderBridge::modifyOutfit(BOOL append) LLViewerInventoryCategory* cat = getCategory(); if(!cat) return; - wear_inventory_category_on_avatar( cat, append ); + wear_inventory_category_on_avatar(cat, append, replace); } // helper stuff @@ -2714,7 +2992,7 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, { BOOL is_movable = TRUE; - switch( inv_item->getType() ) + switch (inv_item->getActualType()) { case LLAssetType::AT_ROOT_CATEGORY: is_movable = FALSE; @@ -2728,21 +3006,36 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, } LLUUID trash_id = model->findCategoryUUIDForType(LLAssetType::AT_TRASH); + const LLUUID ¤t_outfit_id = model->findCategoryUUIDForType(LLAssetType::AT_CURRENT_OUTFIT, false); BOOL move_is_into_trash = (mUUID == trash_id) || model->isObjectDescendentOf(mUUID, trash_id); - if(is_movable && move_is_into_trash) - { - switch(inv_item->getType()) - { - case LLAssetType::AT_CLOTHING: - case LLAssetType::AT_BODYPART: - is_movable = !gAgent.isWearingItem(inv_item->getUUID()); - break; + BOOL move_is_into_current_outfit = (mUUID == current_outfit_id); + BOOL move_is_outof_current_outfit = model->isObjectDescendentOf(inv_item->getUUID(), current_outfit_id); - case LLAssetType::AT_OBJECT: - is_movable = !avatar->isWearingAttachment(inv_item->getUUID()); - break; - default: - break; + if (is_movable && move_is_outof_current_outfit) + { + is_movable = FALSE; // Don't allow dragging links out of COF + } + else if(is_movable && move_is_into_trash) + { + if (inv_item->getIsLinkType()) + { + is_movable = TRUE; + } + else + { + switch (inv_item->getType()) + { + case LLAssetType::AT_CLOTHING: + case LLAssetType::AT_BODYPART: + is_movable = !gAgent.isWearingItem(inv_item->getUUID()); + break; + + case LLAssetType::AT_OBJECT: + is_movable = !avatar->isWearingAttachment(inv_item->getUUID()); + break; + default: + break; + } } } @@ -2767,12 +3060,34 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, } } - // restamp if the move is into the trash. - LLInvFVBridge::changeItemParent( - model, - (LLViewerInventoryItem*)inv_item, - mUUID, - move_is_into_trash); + if (move_is_into_current_outfit) + { + switch (inv_item->getType()) + { + case LLAssetType::AT_BODYPART: + case LLAssetType::AT_CLOTHING: + wear_inventory_item_on_avatar(inv_item); + break; + case LLAssetType::AT_OBJECT: + rez_attachment((LLViewerInventoryItem*)inv_item, NULL, false); + break; + /* + case LLAssetType::AT_GESTURE: + break; + */ + default: + break; + } + } + else + { + // restamp if the move is into the trash. + LLInvFVBridge::changeItemParent( + model, + (LLViewerInventoryItem*)inv_item, + mUUID, + move_is_into_trash); + } } } else if(LLToolDragAndDrop::SOURCE_WORLD == source) @@ -3487,14 +3802,20 @@ LLUIImagePtr LLGestureBridge::getIcon() const LLFontGL::StyleFlags LLGestureBridge::getLabelStyle() const { - if( gGestureManager.isGestureActive(mUUID) ) + U8 font = LLFontGL::NORMAL; + + if (gGestureManager.isGestureActive(mUUID)) { - return LLFontGL::BOLD; + font |= LLFontGL::BOLD; } - else + + const LLViewerInventoryItem* item = getItem(); + if (item && item->getIsLinkType()) { - return LLFontGL::NORMAL; + font |= LLFontGL::ITALIC; } + + return (LLFontGL::StyleFlags)font; } std::string LLGestureBridge::getLabelSuffix() const @@ -3575,6 +3896,15 @@ void LLGestureBridge::buildContextMenu(LLMenuGL& menu, U32 flags) std::vector disabled_items; if(isInTrash()) { + const LLInventoryObject *obj = getInventoryObject(); + if (obj && obj->getIsLinkType()) + { + items.push_back(std::string("Find Original")); + if (isLinkedObjectMissing()) + { + disabled_items.push_back(std::string("Find Original")); + } + } items.push_back(std::string("Purge Item")); if (!isItemRemovable()) { @@ -3726,6 +4056,16 @@ LLUUID LLObjectBridge::sContextMenuItemID; BOOL LLObjectBridge::isItemRemovable() { + LLInventoryModel* model = mInventoryPanel->getModel(); + if (!model) + { + return FALSE; + } + const LLInventoryObject *obj = model->getItem(mUUID); + if (obj && obj->getIsLinkType()) + { + return TRUE; + } // //LLVOAvatar* avatar = gAgent.getAvatarObject(); //if(!avatar) return FALSE; @@ -3739,31 +4079,23 @@ LLUIImagePtr LLObjectBridge::getIcon() const return get_item_icon(LLAssetType::AT_OBJECT, mInvType, mAttachPt, mIsMultiObject ); } -void rez_attachment(LLViewerInventoryItem* item, LLViewerJointAttachment* attachment); - // virtual void LLObjectBridge::performAction(LLFolderView* folder, LLInventoryModel* model, std::string action) { - if ("attach" == action) + if ("attach" == action || "wear_add" == action) { + bool replace = ("attach" == action); // Replace if "Wear"ing. LLUUID object_id = mUUID; LLViewerInventoryItem* item; item = (LLViewerInventoryItem*)gInventory.getItem(object_id); if(item && gInventory.isObjectDescendentOf(object_id, gAgent.getInventoryRootID())) { -// [RLVa:KB] - Checked: 2009-10-10 (RLVa-1.0.5a) | Modified: RLVa-1.0.5a - // User picked "Wear" so either nothing is locked, or we need to look up the specific attach point from its name - // (NOTE: rez_attachment will take care of deciding whether or not we *can* attach) - rez_attachment(item, - ((!rlv_handler_t::isEnabled()) || (!gRlvHandler.hasLockedAttachment(RLV_LOCK_ANY)) || (RlvSettings::getEnableWear())) - ? NULL : gRlvHandler.getAttachPoint(item, true)); -// [/RLVa:KB] -// rez_attachment(item, NULL); + rez_attachment(item, NULL, replace); } else if(item && item->isComplete()) { // must be in library. copy it to our inventory and put it on. - LLPointer cb = new RezAttachmentCallback(0); + LLPointer cb = new RezAttachmentCallback(0, replace); copy_inventory_item( gAgent.getID(), item->getPermissions().getOwner(), @@ -3777,34 +4109,9 @@ void LLObjectBridge::performAction(LLFolderView* folder, LLInventoryModel* model else if ("detach" == action) { LLInventoryItem* item = gInventory.getItem(mUUID); - -// [RLVa:KB] - Checked: 2009-10-10 (RLVa-1.0.5a) | Modified: RLVa-1.0.5a - // Fall-through: if there's a "Detach from yourself" code path we missed then we'll still disallow the detach here - if ( (rlv_handler_t::isEnabled()) && (gRlvHandler.isLockedAttachment(item, RLV_LOCK_REMOVE)) ) + if(item) { - return; - } -// [/RLVa:KB] - - if( item ) - { - gMessageSystem->newMessageFast(_PREHASH_DetachAttachmentIntoInv); - gMessageSystem->nextBlockFast(_PREHASH_ObjectData ); - gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); - gMessageSystem->addUUIDFast(_PREHASH_ItemID, item->getUUID() ); - - gMessageSystem->sendReliable( gAgent.getRegion()->getHost() ); - } - // this object might have been selected, so let the selection manager know it's gone now - LLViewerObject *found_obj = - gObjectList.findObject(item->getUUID()); - if (found_obj) - { - LLSelectMgr::getInstance()->remove(found_obj); - } - else - { - llwarns << "object not found - ignoring" << llendl; + LLVOAvatar::detachAttachmentIntoInventory(item->getLinkedUUID()); } } else if ("edit" == action) @@ -3882,29 +4189,23 @@ void LLObjectBridge::openItem() } } - - - - - - - - - - - - LLFontGL::StyleFlags LLObjectBridge::getLabelStyle() const { + U8 font = LLFontGL::NORMAL; + LLVOAvatar* avatar = gAgent.getAvatarObject(); - if( avatar && avatar->isWearingAttachment( mUUID ) ) + if (avatar && avatar->isWearingAttachment(mUUID)) { - return LLFontGL::BOLD; + font |= LLFontGL::BOLD; } - else + + const LLViewerInventoryItem* item = getItem(); + if (item && item->getIsLinkType()) { - return LLFontGL::NORMAL; + font |= LLFontGL::ITALIC; } + + return (LLFontGL::StyleFlags)font; } std::string LLObjectBridge::getLabelSuffix() const @@ -3932,10 +4233,15 @@ std::string LLObjectBridge::getLabelSuffix() const } } -void rez_attachment(LLViewerInventoryItem* item, LLViewerJointAttachment* attachment) +void rez_attachment(LLViewerInventoryItem* item, LLViewerJointAttachment* attachment, bool replace) { - LLSD payload; - payload["item_id"] = item->getUUID(); +// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1a) | Added: RLVa-1.2.1a + // If no attachment point was specified, try looking it up from the item name + if ( (rlv_handler_t::isEnabled()) && (!attachment) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) ) + { + attachment = RlvAttachPtLookup::getAttachPoint(item); + } +// [/RLVa:KB] S32 attach_pt = 0; if (gAgent.getAvatarObject() && attachment) @@ -3951,35 +4257,26 @@ void rez_attachment(LLViewerInventoryItem* item, LLViewerJointAttachment* attach } } + LLSD payload; + payload["item_id"] = item->getLinkedUUID(); // Wear the base object in case this is a link. payload["attachment_point"] = attach_pt; + payload["is_add"] = !replace; - if (attachment && attachment->getObject()) + if (replace && attachment && attachment->getNumObjects() > 0) { -// [RLVa:KB] - Version: 1.23.4 | Checked: 2009-10-10 (RLVa-1.0.5a) | Modified: RLVa-1.0.5a - if ( (rlv_handler_t::isEnabled()) && // Can't replace an existing object if it's undetachable - (gRlvHandler.isLockedAttachment(attach_pt, RLV_LOCK_ANY)) ) // or if we're not allowed to attach to that attach point - { +// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1a) | Modified: RLVa-1.2.1a + // Block if we can't "replace wear" what's currently there + if ( (rlv_handler_t::isEnabled()) && ((gRlvAttachmentLocks.canAttach(attachment) & RLV_WEAR_REPLACE) == 0) ) return; - } // [/RLVa:KB] - LLNotifications::instance().add("ReplaceAttachment", LLSD(), payload, confirm_replace_attachment_rez); + LLNotifications::instance().add("ReplaceAttachment", LLSD(), payload, confirm_replace_attachment_rez); } else { -// [RLVa:KB] - Version: 1.23.4 | Checked: 2009-10-10 (RLVa-1.0.5) | Modified: RLVa-1.0.5 - if ( (rlv_handler_t::isEnabled()) && (gRlvHandler.hasLockedAttachment(RLV_LOCK_ANY)) ) - { - if (0 == attach_pt) // Can't wear on the default attachment point - { - if (!RlvSettings::getEnableWear()) // (unless "Enable Wear" is enabled) - return; - gRlvHandler.onWearAttachment(item->getUUID()); - } - else if (gRlvHandler.isLockedAttachment(attach_pt, RLV_LOCK_ADD)) // and we can never wear on a non-attachable attach point - { - return; - } - } +// [RLVa:KB] - Checked: 2010-08-07 (RLVa-1.2.0i) | Modified: RLVa-1.2.0i + // Block wearing anything on a non-attachable attachment point + if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.isLockedAttachmentPoint(attach_pt, RLV_LOCK_ADD)) ) + return; // [/RLVa:KB] LLNotifications::instance().forceResponse(LLNotification::Params("ReplaceAttachment").payload(payload), 0/*YES*/); } @@ -3987,26 +4284,29 @@ void rez_attachment(LLViewerInventoryItem* item, LLViewerJointAttachment* attach bool confirm_replace_attachment_rez(const LLSD& notification, const LLSD& response) { + if (!gAgent.getAvatarObject()->canAttachMoreObjects()) + { + LLSD args; + args["MAX_ATTACHMENTS"] = llformat("%d", MAX_AGENT_ATTACHMENTS); + LLNotifications::instance().add("MaxAttachmentsOnOutfit", args); + return false; + } + S32 option = LLNotification::getSelectedOption(notification, response); if (option == 0/*YES*/) { - LLViewerInventoryItem* itemp = gInventory.getItem(notification["payload"]["item_id"].asUUID()); + LLUUID item_id = notification["payload"]["item_id"].asUUID(); + LLViewerInventoryItem* itemp = gInventory.getItem(item_id); if (itemp) { - 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, notification["payload"]["attachment_point"].asInteger()); - 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()); + // 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); } } return false; @@ -4051,13 +4351,9 @@ void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags) items.push_back(std::string("Attach Separator")); items.push_back(std::string("Detach From Yourself")); items.push_back(std::string("Wearable Edit")); - -// [RLVa:KB] - Checked: 2009-10-10 (RLVa-1.0.5a) | Modified: RLVa-1.0.5a - if ( (rlv_handler_t::isEnabled()) && - (gRlvHandler.hasLockedAttachment(RLV_LOCK_REMOVE)) && (gRlvHandler.isLockedAttachment(item, RLV_LOCK_REMOVE)) ) - { +// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a | OK + if ( (rlv_handler_t::isEnabled()) && (!gRlvAttachmentLocks.canDetach(item)) ) disabled_items.push_back(std::string("Detach From Yourself")); - } // [/RLVa:KB] } else @@ -4069,49 +4365,42 @@ void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags) else // // don't allow attaching objects while importing attachments - - - //if( !isInTrash() ) if( !isInTrash() && !(LLXmlImport::sImportInProgress && LLXmlImport::sImportHasAttachments)) // { items.push_back(std::string("Attach Separator")); items.push_back(std::string("Object Wear")); + items.push_back(std::string("Object Add")); + if (!avatarp->canAttachMoreObjects()) + { + disabled_items.push_back(std::string("Object Add")); + } items.push_back(std::string("Attach To")); items.push_back(std::string("Attach To HUD")); // commented out for DEV-32347 - AND Commented back in for non-morons. -HgB items.push_back(std::string("Restore to Last Position")); - - - - - - - - - - - - - - -// [RLVa:KB] - Version: 1.23.4 | Checked: 2009-10-10 (RLVa-1.0.5a) | Modified: RLVa-1.0.5a - if ( (rlv_handler_t::isEnabled()) && (!RlvSettings::getEnableWear()) && (gRlvHandler.hasLockedAttachment(RLV_LOCK_ANY)) ) + + if (!avatarp->canAttachMoreObjects()) { - LLViewerJointAttachment* pAttachPt = gRlvHandler.getAttachPoint(item, true); // The item's name should specify - if ( (!pAttachPt) || // an attachment point that - (gRlvHandler.isLockedAttachment(pAttachPt->getObject(), RLV_LOCK_REMOVE)) || // doesn't have an undetachable object - (gRlvHandler.isLockedAttachment(pAttachPt, RLV_LOCK_ADD)) ) // and that can be attached to - { + disabled_items.push_back(std::string("Object Wea")); + disabled_items.push_back(std::string("Object Add")); + disabled_items.push_back(std::string("Attach To")); + disabled_items.push_back(std::string("Attach To HUD")); + } +// [RLVa:KB] - Checked: 2010-09-03 (RLVa-1.2.1a) | Modified: RLVa-1.2.1a | OK + else if (rlv_handler_t::isEnabled()) + { + ERlvWearMask eWearMask = gRlvAttachmentLocks.canAttach(item); + if ((eWearMask & RLV_WEAR_REPLACE) == 0) disabled_items.push_back(std::string("Object Wear")); - } + if ((eWearMask & RLV_WEAR_ADD) == 0) + disabled_items.push_back(std::string("Object Add")); } // [/RLVa:KB] LLMenuGL* attach_menu = menu.getChildMenuByName("Attach To", TRUE); LLMenuGL* attach_hud_menu = menu.getChildMenuByName("Attach To HUD", TRUE); - LLVOAvatar *avatarp = gAgent.getAvatarObject(); if (attach_menu && (attach_menu->getChildCount() == 0) && attach_hud_menu && (attach_hud_menu->getChildCount() == 0) && avatarp) @@ -4170,7 +4459,7 @@ void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { LLSimpleListener* callback = mInventoryPanel->getListenerByName("Inventory.AttachCustom"); new_item->addListener(callback, "on_click", LLSD()); - } + } // } } @@ -4282,12 +4571,12 @@ void wear_inventory_item_on_avatar( LLInventoryItem* item ) item->getName(), item->getType(), LLWearableBridge::onWearOnAvatarArrived, - new LLUUID(item->getUUID())); + new LLUUID(item->getLinkedUUID())); } } // [RLVa:KB] - Checked: 2009-12-18 (RLVa-1.1.0i) | Added: RLVa-1.1.0i -// Moved to llinventorybridge.h because we need it in RlvForceWear +// Moved to llinventorybridge.h because we need it in RlvForceWearLegacy /* struct LLFoundData { @@ -4382,33 +4671,6 @@ private: bool mAppend; }; - -class LLWearAttachmentsCallback : public LLInventoryCallback -{ -public: - LLWearAttachmentsCallback(bool append) : mAppend(append) {} - void fire(const LLUUID& item_id) - { - mItemIDs.insert(item_id); - } -protected: - ~LLWearAttachmentsCallback() - { - if( LLInventoryCallbackManager::is_instantiated() ) - { - wear_attachments_on_avatar(mItemIDs, mAppend); - } - else - { - llwarns << "Dropping unhandled LLWearAttachmentsCallback" << llendl; - } - } -private: - std::set mItemIDs; - bool mAppend; -}; - - void LLOutfitObserver::done() { // We now have an outfit ready to be copied to agent inventory. Do @@ -4623,7 +4885,7 @@ void wear_inventory_category(LLInventoryCategory* category, bool copy, bool appe } // *NOTE: hack to get from avatar inventory to avatar -void wear_inventory_category_on_avatar( LLInventoryCategory* category, BOOL append ) +void wear_inventory_category_on_avatar(LLInventoryCategory* category, BOOL append, BOOL replace) { // Avoid unintentionally overwriting old wearables. We have to do // this up front to avoid having to deal with the case of multiple @@ -4634,6 +4896,7 @@ void wear_inventory_category_on_avatar( LLInventoryCategory* category, BOOL appe LLWearInfo* userdata = new LLWearInfo; userdata->mAppend = append; + userdata->mReplace = replace; userdata->mCategoryID = category->getUUID(); if( gFloaterCustomize ) @@ -4671,15 +4934,9 @@ void wear_inventory_category_on_avatar_step2( BOOL proceed, void* userdata ) S32 i; S32 wearable_count = item_array.count(); - LLInventoryModel::cat_array_t obj_cat_array; - LLInventoryModel::item_array_t obj_item_array; - LLIsType is_object( LLAssetType::AT_OBJECT ); - gInventory.collectDescendentsIf(wear_info->mCategoryID, - obj_cat_array, - obj_item_array, - LLInventoryModel::EXCLUDE_TRASH, - is_object); - S32 obj_count = obj_item_array.count(); + LLInventoryModel::item_array_t obj_items_new; + LLCOFMgr::getDescendentsOfAssetType(wear_info->mCategoryID, obj_items_new, LLAssetType::AT_OBJECT, false); + S32 obj_count = obj_items_new.count(); // Find all gestures in this folder LLInventoryModel::cat_array_t gest_cat_array; @@ -4692,56 +4949,6 @@ void wear_inventory_category_on_avatar_step2( BOOL proceed, void* userdata ) is_gesture); S32 gest_count = gest_item_array.count(); - - - - - - - - - - - - - - - - - - - - - - - - - -// [RLVa:KB] - Version: 1.23.4 | Checked: 2009-10-10 (RLVa-1.0.5a) | Modified: RLVa-1.0.5a - if ( (rlv_handler_t::isEnabled()) && (gRlvHandler.hasLockedAttachment(RLV_LOCK_ANY)) ) - { - // Filter anything that we shouldn't be attaching - for (S32 idxObj = obj_item_array.count() - 1; idxObj >= 0; idxObj--) - { - if (!RlvSettings::getEnableWear()) - { - LLViewerJointAttachment* pAttachPt = gRlvHandler.getAttachPoint(obj_item_array.get(idxObj).get(), true); - if ( (!pAttachPt) || // Item should specify attachpt that - (gRlvHandler.isLockedAttachment(pAttachPt->getObject(), RLV_LOCK_REMOVE)) || // doesn't have an undetachable object - (gRlvHandler.isLockedAttachment(pAttachPt, RLV_LOCK_ADD)) ) // and that is attachable - { - obj_item_array.remove(idxObj); - } - } - else - { - gRlvHandler.onWearAttachment(obj_item_array.get(idxObj)->getUUID()); - } - } - obj_count = obj_item_array.count(); - } -// [/RLVa:KB] - if( !wearable_count && !obj_count && !gest_count) { LLNotifications::instance().add("CouldNotPutOnOutfit"); @@ -4786,7 +4993,7 @@ void wear_inventory_category_on_avatar_step2( BOOL proceed, void* userdata ) LLDynamicArray found_container; for(i = 0; i < wearable_count; ++i) { - found = new LLFoundData(item_array.get(i)->getUUID(), + found = new LLFoundData(item_array.get(i)->getLinkedUUID(), item_array.get(i)->getAssetUUID(), item_array.get(i)->getName(), item_array.get(i)->getType()); @@ -4808,19 +5015,51 @@ void wear_inventory_category_on_avatar_step2( BOOL proceed, void* userdata ) } } + const LLUUID idCOF = LLCOFMgr::instance().getCOF(); - //If not appending and the folder doesn't contain only gestures, take off all attachments. - if (!wear_info->mAppend - && !(wearable_count == 0 && obj_count == 0 && gest_count > 0) ) + // + // - Attachments: include COF contents only if appending. + // + if (!wear_info->mReplace) { - LLAgent::userRemoveAllAttachments(NULL); + LLInventoryModel::item_array_t obj_items; + if (wear_info->mAppend) + LLCOFMgr::getDescendentsOfAssetType(idCOF, obj_items, LLAssetType::AT_OBJECT, false); +// [RLVa:KB] - Checked: 2010-03-05 (RLVa-1.2.0z) | Modified: RLVa-1.2.0b + else if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) ) + { + // Make sure that all currently locked attachments remain in COF when replacing + LLCOFMgr::getDescendentsOfAssetType(idCOF, obj_items, LLAssetType::AT_OBJECT, false); + obj_items.erase(std::remove_if(obj_items.begin(), obj_items.end(), rlvPredCanRemoveItem), obj_items.end()); + } +// [/RLVa:KB] +// getDescendentsOfAssetType(category, obj_items, LLAssetType::AT_OBJECT, false); +// [RLVa:KB] - Checked: 2010-03-05 (RLVa-1.2.0z) | Modified: RLVa-1.2.0b + // Filter out any new attachments that can't be worn before adding them + if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) ) + obj_items_new.erase(std::remove_if(obj_items_new.begin(), obj_items_new.end(), RlvPredCanNotWearItem(RLV_WEAR_REPLACE)), obj_items_new.end()); + obj_items.insert(obj_items.end(), obj_items_new.begin(), obj_items_new.end()); +// [/RLVa:KB] + + LLAgent::userUpdateAttachments(obj_items); + } + else + { + for (S32 idxItem = 0, cntItem = obj_items_new.count(); idxItem < cntItem; idxItem++) + { + LLInventoryItem* pItem = obj_items_new.get(idxItem); + +// [RLVa:KB] - Checked: 2010-11-21 (RLVa-1.1.3c) | Added: RLVa-1.1.3c + if ( (rlv_handler_t::isEnabled()) && (!(RLV_WEAR_REPLACE & gRlvAttachmentLocks.canAttach(pItem))) ) + continue; +// [/RLVa:KB] + + LLAttachmentsMgr::instance().addAttachment(pItem->getLinkedUUID(), 0, false); + } } - if( obj_count > 0 ) - { - // We've found some attachements. Add these. - wear_attachments_on_avatar(obj_item_array, !wear_info->mAppend); - } + if (!wear_info->mAppend) + LLCOFMgr::instance().addBOFLink(wear_info->mCategoryID); } delete wear_info; wear_info = NULL; @@ -4894,9 +5133,8 @@ void wear_inventory_category_on_avatar_step3(LLWearableHoldingPattern* holder, B // item->setAssetUUID(wearable->getID()); // item->updateAssetOnServer(); // } -// [RLVa:KB] - Checked: 2009-07-06 (RLVa-1.0.0c) | Modified: RLVa-1.0.0c - if ( (!gRlvHandler.isWearable(wearable->getType())) || - ( (!gRlvHandler.isRemovable(wearable->getType())) && (gAgent.getWearable(wearable->getType())) ) ) +// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.1.3b) | Modified: RLVa-1.1.3b + if (!gRlvWearableLocks.canWear(wearable->getType())) { continue; } @@ -4920,281 +5158,6 @@ void wear_inventory_category_on_avatar_step3(LLWearableHoldingPattern* holder, B dec_busy_count(); } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void wear_attachments_on_avatar(const std::set& item_ids, BOOL remove) -{ - // NOTE: the inventory items can reside in the user's inventory, the library, or any combination of the two - - LLInventoryModel::item_array_t items; - LLPointer cb; - - for (std::set::const_iterator it = item_ids.begin(); it != item_ids.end(); ++it) - { - LLViewerInventoryItem* item = gInventory.getItem(*it); - if ( (item) && (LLAssetType::AT_OBJECT == item->getType()) ) - { - if ( (gInventory.isObjectDescendentOf(*it, gAgent.getInventoryRootID())) ) - { -// [RLVa:KB] - Version: 1.23.4 | Checked: 2009-10-15 (RLVa-1.0.5e) | Modified: RLVa-1.0.5e - if ( (rlv_handler_t::isEnabled()) && (gRlvHandler.hasLockedAttachment(RLV_LOCK_ANY)) ) - { - if (!RlvSettings::getEnableWear()) - { - LLViewerJointAttachment* pAttachPt = NULL; - if ( ((pAttachPt = gRlvHandler.getAttachPoint(item, true)) == NULL) || // Item should specify attachpt that - (gRlvHandler.isLockedAttachment(pAttachPt->getObject(), RLV_LOCK_REMOVE)) || // doesn't have an undetachable object - (gRlvHandler.isLockedAttachment(pAttachPt, RLV_LOCK_ADD)) ) // and that is attachable - { - continue; - } - } - else - { - gRlvHandler.onWearAttachment(item->getUUID()); - } - } -// [/RLVa:KB] - items.put(item); - } - else if ( (item->isComplete()) ) - { - if (cb.isNull()) - cb = new LLWearAttachmentsCallback(remove); - copy_inventory_item(gAgent.getID(), item->getPermissions().getOwner(), item->getUUID(), LLUUID::null, std::string(), cb); - } - } - } - - wear_attachments_on_avatar(items, remove); -} - -void wear_attachments_on_avatar(const LLInventoryModel::item_array_t& items, BOOL remove) -{ - // NOTE: all inventory items must reside in the user's inventory - - LLVOAvatar* avatarp = gAgent.getAvatarObject(); - if(!avatarp) - { - llwarns << "No avatar found." << llendl; - return; - } - - // Build a compound message to send all the objects that need to be rezzed. - - // 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; - - S32 count = items.count(); - if ( !count ) - { - return; - } - else if ( count > MAX_OBJECTS_TO_SEND ) - { - count = MAX_OBJECTS_TO_SEND; - } - - // 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 < 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, count ); -// msg->addBOOLFast(_PREHASH_FirstDetachAll, !wear_info->mAppend ); -// [RLVa:KB] - Checked: 2009-10-10 (RLVa-1.0.5a) | Added: RLVa-1.0.5a - // This really should just *always* be FALSE since TRUE can result in loss of the current asset state - msg->addBOOLFast(_PREHASH_FirstDetachAll, - (remove) && (!gRlvHandler.hasLockedAttachment(RLV_LOCK_ANY)) ); -// [/RLVa:KB] - } - - LLInventoryItem* item = items.get(i); - msg->nextBlockFast(_PREHASH_ObjectData ); - msg->addUUIDFast(_PREHASH_ItemID, item->getUUID() ); - msg->addUUIDFast(_PREHASH_OwnerID, item->getPermissions().getOwner()); -// msg->addU8Fast(_PREHASH_AttachmentPt, 0 ); // Wear at the previous or default attachment point -// [RLVa:KB] - Checked: 2009-11-16 (RLVa-1.1.0c) | Modified: RLVa-1.1.0c - // We'll attach to the default attachment point if: - // - RLV isn't enabled (or nothing is currently locked on) - // - "Enable Default Wear" is checked and the current attach isn't the direct result of an RLV command - // - "Enable Shared Wear" is checked and the current attach is the direct result of an RLV command - // RELEASE-RLVa: make sure the above assertions are still valid - msg->addU8Fast(_PREHASH_AttachmentPt, - ( (!rlv_handler_t::isEnabled()) || (!gRlvHandler.hasLockedAttachment(RLV_LOCK_ANY)) || -#ifndef RLV_WORKAROUND_REZMULTIPLEATTACH - ( (!gRlvHandler.getCurrentCommand()) && (RlvSettings::getEnableWear()) ) || - ( (gRlvHandler.getCurrentCommand()) && (RlvSettings::getEnableSharedWear()) ) ) -#else - (RlvSettings::getEnableWear()) ) -#endif // RLV_WORKAROUND_REZMULTIPLEATTACH - ? 0 - : gRlvHandler.getAttachPointIndex(gRlvHandler.getAttachPoint(item, true)) ); -// [/RLVa:KB] - pack_permissions_slam(msg, item->getFlags(), item->getPermissions()); - msg->addStringFast(_PREHASH_Name, item->getName()); - msg->addStringFast(_PREHASH_Description, item->getDescription()); - - if( (i+1 == count) || ((OBJECTS_PER_PACKET-1) == (i % OBJECTS_PER_PACKET)) ) - { - // End of message chunk - msg->sendReliable( gAgent.getRegion()->getHost() ); - } - } -} - void remove_inventory_category_from_avatar( LLInventoryCategory* category ) { if(!category) return; @@ -5218,6 +5181,14 @@ void remove_inventory_category_from_avatar( LLInventoryCategory* category ) } } +struct OnRemoveStruct +{ + LLUUID mUUID; + OnRemoveStruct(const LLUUID& uuid): + mUUID(uuid) + { + } +}; void remove_inventory_category_from_avatar_step2( BOOL proceed, void* userdata) { @@ -5265,57 +5236,28 @@ void remove_inventory_category_from_avatar_step2( BOOL proceed, void* userdata) for(i = 0; i < wearable_count; ++i) { // if( gAgent.isWearingItem (item_array.get(i)->getUUID()) ) -// [RLVa:KB] - Checked: 2009-07-07 (RLVa-1.0.0d) | Modified: RLVa-0.2.2a - LLWearable* pWearable = gAgent.getWearableFromWearableItem(item_array.get(i)->getUUID()); - if ( (pWearable) && ( (!rlv_handler_t::isEnabled()) || (gRlvHandler.isRemovable(pWearable->getType()))) ) +// [RLVa:KB] - Checked: 2009-07-07 (RLVa-1.1.3b) | Modified: RLVa-0.2.2a + LLWearable* pWearable = gAgent.getWearableFromWearableItem(item_array.get(i)->getLinkedUUID()); + if ( (pWearable) && ( (!rlv_handler_t::isEnabled()) || (gRlvWearableLocks.canRemove(pWearable->getType())) ) ) // [/RLVa:KB] { gWearableList.getAsset(item_array.get(i)->getAssetUUID(), item_array.get(i)->getName(), - item_array.get(i)->getType(), - LLWearableBridge::onRemoveFromAvatarArrived, - new LLUUID(item_array.get(i)->getUUID())); - + item_array.get(i)->getType(), + LLWearableBridge::onRemoveFromAvatarArrived, + new OnRemoveStruct(item_array.get(i)->getLinkedUUID())); } } } - - - - - if (obj_count > 0) { for(i = 0; i < obj_count; ++i) { -// [RLVa:KB] - Checked: 2009-10-10 (RLVa-1.0.5a) | Modified: RLVa-1.0.5a - if ( (rlv_handler_t::isEnabled()) && (gRlvHandler.hasLockedAttachment(RLV_LOCK_REMOVE)) ) + LLInventoryItem* item = obj_item_array.get(i); + if(item) { - LLVOAvatar* pAvatar = gAgent.getAvatarObject(); - if ( (!pAvatar) || (!pAvatar->isWearingAttachment(obj_item_array.get(i)->getUUID())) || - (gRlvHandler.isLockedAttachment(obj_item_array.get(i).get(), RLV_LOCK_REMOVE)) ) - { - continue; - } - } -// [/RVLa:KB] - gMessageSystem->newMessageFast(_PREHASH_DetachAttachmentIntoInv); - gMessageSystem->nextBlockFast(_PREHASH_ObjectData ); - gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); - gMessageSystem->addUUIDFast(_PREHASH_ItemID, obj_item_array.get(i)->getUUID() ); - - gMessageSystem->sendReliable( gAgent.getRegion()->getHost() ); - - // this object might have been selected, so let the selection manager know it's gone now - LLViewerObject *found_obj = gObjectList.findObject( obj_item_array.get(i)->getUUID()); - if (found_obj) - { - LLSelectMgr::getInstance()->remove(found_obj); - } - else - { - llwarns << "object not found, ignoring" << llendl; + LLVOAvatar::detachAttachmentIntoInventory(item->getLinkedUUID()); } } } @@ -5324,9 +5266,9 @@ void remove_inventory_category_from_avatar_step2( BOOL proceed, void* userdata) { for(i = 0; i < gest_count; ++i) { - if ( gGestureManager.isGestureActive( gest_item_array.get(i)->getUUID()) ) + if ( gGestureManager.isGestureActive( gest_item_array.get(i)->getLinkedUUID()) ) { - gGestureManager.deactivateGesture( gest_item_array.get(i)->getUUID() ); + gGestureManager.deactivateGesture( gest_item_array.get(i)->getLinkedUUID() ); gInventory.updateItem( gest_item_array.get(i) ); gInventory.notifyObservers(); } @@ -5349,33 +5291,38 @@ BOOL LLWearableBridge::renameItem(const std::string& new_name) BOOL LLWearableBridge::isItemRemovable() { + LLInventoryModel* model = mInventoryPanel->getModel(); + if (!model) + { + return FALSE; + } + const LLInventoryObject *obj = model->getItem(mUUID); + if (obj && obj->getIsLinkType()) + { + return TRUE; + } // //if(gAgent.isWearingItem(mUUID)) return FALSE; // return LLInvFVBridge::isItemRemovable(); } - - - - - - - - - - LLFontGL::StyleFlags LLWearableBridge::getLabelStyle() const { - if( gAgent.isWearingItem( mUUID ) ) + U8 font = LLFontGL::NORMAL; + + if (gAgent.isWearingItem(mUUID)) { - // llinfos << "BOLD" << llendl; - return LLFontGL::BOLD; + font |= LLFontGL::BOLD; } - else + + const LLViewerInventoryItem* item = getItem(); + if (item && item->getIsLinkType()) { - return LLFontGL::NORMAL; + font |= LLFontGL::ITALIC; } + + return (LLFontGL::StyleFlags)font; } std::string LLWearableBridge::getLabelSuffix() const @@ -5418,7 +5365,7 @@ void LLWearableBridge::performAction(LLFolderView* folder, LLInventoryModel* mod item->getName(), item->getType(), LLWearableBridge::onRemoveFromAvatarArrived, - new LLUUID(mUUID)); + new OnRemoveStruct(item->getLinkedUUID())); } } } @@ -5650,7 +5597,8 @@ void LLWearableBridge::onEditOnAvatar(void* user_data) void LLWearableBridge::editOnAvatar() { - LLWearable* wearable = gAgent.getWearableFromWearableItem(mUUID); + LLUUID linked_id = gInventory.getLinkedItemID(mUUID); + LLWearable* wearable = gAgent.getWearableFromWearableItem(linked_id); if( wearable ) { // Set the tab to the right wearable. @@ -5689,7 +5637,7 @@ void LLWearableBridge::onRemoveFromAvatar(void* user_data) item->getName(), item->getType(), onRemoveFromAvatarArrived, - new LLUUID(self->mUUID)); + new OnRemoveStruct(LLUUID(self->mUUID))); } } } @@ -5698,10 +5646,11 @@ void LLWearableBridge::onRemoveFromAvatar(void* user_data) void LLWearableBridge::onRemoveFromAvatarArrived(LLWearable* wearable, void* userdata) { - LLUUID* item_id = (LLUUID*) userdata; + OnRemoveStruct *on_remove_struct = (OnRemoveStruct*) userdata; + const LLUUID &item_id = gInventory.getLinkedItemID(on_remove_struct->mUUID); if(wearable) { - if( gAgent.isWearingItem( *item_id ) ) + if (gAgent.isWearingItem(item_id)) { EWearableType type = wearable->getType(); @@ -5712,10 +5661,9 @@ void LLWearableBridge::onRemoveFromAvatarArrived(LLWearable* wearable, } } } - delete item_id; + delete on_remove_struct; } -/* // +=================================================+ // | LLLinkItemBridge | @@ -5854,5 +5802,3 @@ const LLUUID &LLLinkFolderBridge::getFolderID() const return LLUUID::null; } -*/ - diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index 25c261edd..47ca004c5 100755 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -30,7 +30,13 @@ * $/LicenseInfo$ */ +#ifndef LL_LLINVENTORYBRIDGE_H +#define LL_LLINVENTORYBRIDGE_H + #include "llfloaterproperties.h" +#include "llfolderview.h" +#include "llinventorymodel.h" +#include "llinventoryview.h" #include "llwearable.h" #include "llviewercontrol.h" #include "llcallingcard.h" @@ -70,6 +76,9 @@ enum EInventoryIcon ANIMATION_ICON_NAME, GESTURE_ICON_NAME, + LINKITEM_ICON_NAME, + LINKFOLDER_ICON_NAME, + ICON_NAME_COUNT }; @@ -95,7 +104,7 @@ struct LLAttachmentRezAction }; // [RLVa:KB] - Checked: 2009-12-18 (RLVa-1.1.0i) | Added: RLVa-1.1.0i -// Moved from llinventorybridge.cpp because we need it in RlvForceWear +// Moved from llinventorybridge.cpp because we need it in RlvForceWearLegacy struct LLFoundData { LLFoundData(const LLUUID& item_id, @@ -187,6 +196,7 @@ public: // This method is a convenience function which creates the correct // type of bridge based on some basic information static LLInvFVBridge* createBridge(LLAssetType::EType asset_type, + LLAssetType::EType actual_asset_type, LLInventoryType::EType inv_type, LLInventoryPanel* inventory, const LLUUID& uuid, @@ -223,7 +233,9 @@ public: virtual BOOL copyToClipboard() const { return FALSE; } virtual void cutToClipboard() {} virtual BOOL isClipboardPasteable() const; + virtual BOOL isClipboardPasteableAsLink() const; virtual void pasteFromClipboard() {} + virtual void pasteLinkFromClipboard() {} void getClipboardEntries(bool show_asset_id, std::vector &items, std::vector &disabled_items, U32 flags); virtual void buildContextMenu(LLMenuGL& menu, U32 flags); @@ -242,6 +254,8 @@ protected: LLInventoryObject* getInventoryObject() const; BOOL isInTrash() const; + BOOL isLinkedObjectInTrash() const; // Is this obj or its baseobj in the trash? + BOOL isLinkedObjectMissing() const; // Is this a linked obj whose baseobj is not in inventory? // return true if the item is in agent inventory. if false, it // must be lost or in the inventory library. BOOL isAgentInventory() const; @@ -274,7 +288,7 @@ public: virtual void selectItem(); virtual void restoreItem(); virtual void restoreToWorld(); - + virtual void gotoItem(LLFolderView *folder); virtual LLUIImagePtr getIcon() const; virtual const std::string& getDisplayName() const; virtual std::string getLabelSuffix() const; @@ -320,7 +334,9 @@ public: virtual BOOL renameItem(const std::string& new_name); virtual BOOL removeItem(); virtual BOOL isClipboardPasteable() const; + virtual BOOL isClipboardPasteableAsLink() const; virtual void pasteFromClipboard(); + virtual void pasteLinkFromClipboard(); virtual void buildContextMenu(LLMenuGL& menu, U32 flags); virtual BOOL hasChildren() const; virtual BOOL dragOrDrop(MASK mask, BOOL drop, @@ -362,7 +378,7 @@ protected: BOOL checkFolderForContentsOfType(LLInventoryModel* model, LLInventoryCollectFunctor& typeToCheck); - void modifyOutfit(BOOL append); + void modifyOutfit(BOOL append, BOOL replace = FALSE); public: static LLFolderBridge* sSelf; static void staticFolderOptionsMenu(); @@ -647,3 +663,47 @@ protected: LLInventoryType::EType mInvType; EWearableType mWearableType; }; + +class LLLinkItemBridge : public LLItemBridge +{ + friend class LLInvFVBridge; +public: + virtual const std::string& getPrefix() { return sPrefix; } + + virtual LLUIImagePtr getIcon() const; + virtual void buildContextMenu(LLMenuGL& menu, U32 flags); + +protected: + LLLinkItemBridge(LLInventoryPanel* inventory, const LLUUID& uuid) : + LLItemBridge(inventory, uuid) {} + +protected: + static std::string sPrefix; +}; + + +class LLLinkFolderBridge : public LLItemBridge +{ + friend class LLInvFVBridge; +public: + virtual const std::string& getPrefix() { return sPrefix; } + + virtual LLUIImagePtr getIcon() const; + virtual void buildContextMenu(LLMenuGL& menu, U32 flags); + virtual void performAction(LLFolderView* folder, LLInventoryModel* model, std::string action); + virtual void gotoItem(LLFolderView *folder); + +protected: + LLLinkFolderBridge(LLInventoryPanel* inventory, const LLUUID& uuid) : + LLItemBridge(inventory, uuid) {} + const LLUUID &getFolderID() const; + +protected: + static std::string sPrefix; +}; + +void rez_attachment(LLViewerInventoryItem* item, + LLViewerJointAttachment* attachment, + bool replace = false); + +#endif // LL_LLINVENTORYBRIDGE_H diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 2350c876f..6c797abf4 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -87,6 +87,10 @@ S16 LLInventoryModel::sBulkFetchCount = 0; // RN: for some reason, using std::queue in the header file confuses the compiler which things it's an xmlrpc_queue static std::deque sFetchQueue; +// Increment this if the inventory contents change in a non-backwards-compatible way. +// For viewers with link items support, former caches are incorrect. +const S32 LLInventoryModel::sCurrentInvCacheVersion = 2; + ///---------------------------------------------------------------------------- /// Local function declarations, constants, enums, and typedefs ///---------------------------------------------------------------------------- @@ -120,7 +124,33 @@ const char* NEW_CATEGORY_NAMES[LLAssetType::AT_COUNT] = "Uncompressed Images", // AT_IMAGE_JPEG "Animations", // AT_ANIMATION "Gestures", // AT_GESTURE - "New Folder" // AT_SIMSTATE + "New Folder", // AT_SIMSTATE + "Favorites", + "New Folder", + "New Folder", + "New Ensemble", + "New Ensemble", + "New Ensemble", + "New Ensemble", + "New Ensemble", + "New Ensemble", + "New Ensemble", + "New Ensemble", + "New Ensemble", + "New Ensemble", + "New Ensemble", + "New Ensemble", + "New Ensemble", + "New Ensemble", + "New Ensemble", + "New Ensemble", + "New Ensemble", + "New Ensemble", + "New Ensemble", + "New Ensemble", + "Current Outfit", + "New Outfit", + "My Outfits" }; struct InventoryIDPtrLess @@ -360,6 +390,27 @@ LLUUID LLInventoryModel::findCategoryUUIDForType(LLAssetType::EType t, bool crea return rv; } +const LLViewerInventoryCategory *LLInventoryModel::getFirstNondefaultParent(const LLUUID& obj_id) const +{ + const LLInventoryObject* obj = getObject(obj_id); + + // Search up the parent chain until we get to root or an acceptable folder. + // This assumes there are no cycles in the tree else we'll get a hang. + LLUUID parent_id = obj->getParentUUID(); + while (!parent_id.isNull()) + { + const LLViewerInventoryCategory *cat = getCategory(parent_id); + if (!cat) break; + const LLAssetType::EType folder_type = cat->getPreferredType(); + if (folder_type != LLAssetType::AT_NONE && folder_type != LLAssetType::AT_ROOT_CATEGORY) + { + return cat; + } + parent_id = cat->getParentUUID(); + } + return NULL; +} + // Internal method which looks for a category with the specified // preferred type. Returns LLUUID::null if not found. LLUUID LLInventoryModel::findCatUUID(LLAssetType::EType preferred_type) @@ -467,7 +518,7 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id, name.assign(pname); } else if((preferred_type >= LLAssetType::AT_TEXTURE) && - (preferred_type < LLAssetType::AT_SIMSTATE)) + (preferred_type <= LLAssetType::AT_MY_OUTFITS)) { name.assign(NEW_CATEGORY_NAMES[preferred_type]); } @@ -531,12 +582,13 @@ void LLInventoryModel::collectDescendentsIf(const LLUUID& id, cat_array_t& cats, item_array_t& items, BOOL include_trash, - LLInventoryCollectFunctor& add) + LLInventoryCollectFunctor& add, + BOOL follow_folder_links) { // Start with categories if(!include_trash) { - LLUUID trash_id(findCatUUID(LLAssetType::AT_TRASH)); + const LLUUID trash_id = findCategoryUUIDForType(LLAssetType::AT_TRASH); if(trash_id.notNull() && (trash_id == id)) return; } @@ -555,9 +607,10 @@ void LLInventoryModel::collectDescendentsIf(const LLUUID& id, } } - // Move onto items LLViewerInventoryItem* item = NULL; item_array_t* item_array = get_ptr_in_map(mParentChildItemTree, id); + + // Move onto items if(item_array) { S32 count = item_array->count(); @@ -570,6 +623,111 @@ void LLInventoryModel::collectDescendentsIf(const LLUUID& id, } } } + +// [RLVa:KB] - Checked: 2010-09-30 (RLVa-1.2.1d) | Added: RLVa-1.2.1d + // The problem is that we want some way for the functor to know that it's being asked to decide on a folder link + // but it won't know that until after it has encountered the folder link item (which doesn't happen until *after* + // it has already collected all items from it the way the code was originally laid out) + // This breaks the "finish collecting all folders before collecting items (top to bottom and then bottom to top)" + // assumption but no functor is (currently) relying on it (and likely never should since it's an implementation detail?) + // [Only LLAppearanceMgr actually ever passes in 'follow_folder_links == TRUE'] +// [/RLVa:KB] + // Follow folder links recursively. Currently never goes more + // than one level deep (for current outfit support) + // Note: if making it fully recursive, need more checking against infinite loops. + if (follow_folder_links && item_array) + { + S32 count = item_array->count(); + for(S32 i = 0; i < count; ++i) + { + item = item_array->get(i); + if (item && item->getActualType() == LLAssetType::AT_LINK_FOLDER) + { + LLViewerInventoryCategory *linked_cat = item->getLinkedCategory(); + if (linked_cat && linked_cat->getPreferredType() != LLAssetType::AT_OUTFIT) + // BAP - was + // LLAssetType::lookupIsEnsembleCategoryType(linked_cat->getPreferredType())) + // Change back once ensemble typing is in place. + { + if(add(linked_cat,NULL)) + { + // BAP should this be added here? May not + // matter if it's only being used in current + // outfit traversal. + cats.put(LLPointer(linked_cat)); + } + collectDescendentsIf(linked_cat->getUUID(), cats, items, include_trash, add, FALSE); + } + } + } + } +} + +void LLInventoryModel::addChangedMaskForLinks(const LLUUID& object_id, U32 mask) +{ + const LLInventoryObject *obj = getObject(object_id); + if (!obj || obj->getIsLinkType()) + return; + + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + LLLinkedItemIDMatches is_linked_item_match(object_id); + collectDescendentsIf(gAgent.getInventoryRootID(), + cat_array, + item_array, + LLInventoryModel::INCLUDE_TRASH, + is_linked_item_match); + if (cat_array.empty() && item_array.empty()) + { + return; + } + for (LLInventoryModel::cat_array_t::iterator cat_iter = cat_array.begin(); + cat_iter != cat_array.end(); + cat_iter++) + { + LLViewerInventoryCategory *linked_cat = (*cat_iter); + addChangedMask(mask, linked_cat->getUUID()); + }; + + for (LLInventoryModel::item_array_t::iterator iter = item_array.begin(); + iter != item_array.end(); + iter++) + { + LLViewerInventoryItem *linked_item = (*iter); + addChangedMask(mask, linked_item->getUUID()); + }; +} + +const LLUUID& LLInventoryModel::getLinkedItemID(const LLUUID& object_id) const +{ + const LLInventoryItem *item = gInventory.getItem(object_id); + if (!item) + { + return object_id; + } + + // Find the base item in case this a link (if it's not a link, + // this will just be inv_item_id) + return item->getLinkedUUID(); +} + +LLViewerInventoryItem* LLInventoryModel::getLinkedItem(const LLUUID& object_id) const +{ + return object_id.notNull() ? getItem(getLinkedItemID(object_id)) : NULL; +} + +LLInventoryModel::item_array_t LLInventoryModel::collectLinkedItems(const LLUUID& id, + const LLUUID& start_folder_id) +{ + item_array_t items; + LLInventoryModel::cat_array_t cat_array; + LLLinkedItemIDMatches is_linked_item_match(id); + collectDescendentsIf((start_folder_id == LLUUID::null ? gAgent.getInventoryRootID() : start_folder_id), + cat_array, + items, + LLInventoryModel::INCLUDE_TRASH, + is_linked_item_match); + return items; } // Generates a string containing the path to the item specified by @@ -894,6 +1052,19 @@ void LLInventoryModel::deleteObject(const LLUUID& id) } } +// Delete a particular inventory item by ID, and remove it from the server. +void LLInventoryModel::purgeObject(const LLUUID &id) +{ + lldebugs << "LLInventoryModel::purgeObject() [ id: " << id << " ] " << llendl; + LLPointer obj = getObject(id); + if(obj) + { + obj->removeFromServer(); + LLPreview::hide(id); + deleteObject(id); + } +} + // This is a method which collects the descendents of the id // provided. If the category is not found, no action is // taken. This method goes through the long winded process of @@ -1103,6 +1274,13 @@ void LLInventoryModel::addChangedMask(U32 mask, const LLUUID& referent) { mChangedItemIDs.insert(referent); } + + // Update all linked items. Starting with just LABEL because I'm + // not sure what else might need to be accounted for this. + if (mModifyMask & LLInventoryObserver::LABEL) + { + addChangedMaskForLinks(referent, LLInventoryObserver::LABEL); + } } // This method to prepares a set of mock inventory which provides @@ -2056,16 +2234,13 @@ bool LLInventoryModel::loadSkeleton( //delete cat; // automatic when cat is reasigned or destroyed } - - - - S32 cached_category_count = 0; S32 cached_item_count = 0; if (!temp_cats.empty()) { cat_array_t categories; item_array_t items; + cat_set_t invalid_categories; // Used to mark categories that weren't successfully loaded. std::string owner_id_str; owner_id.toString(owner_id_str); std::string path(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, owner_id_str)); @@ -2092,7 +2267,8 @@ bool LLInventoryModel::loadSkeleton( llinfos << "Unable to gunzip " << gzip_filename << llendl; } } - if (loadFromFile(inventory_filename, categories, items)) + bool is_cache_obsolete = false; + if (loadFromFile(inventory_filename, categories, items, is_cache_obsolete)) { // We were able to find a cache of files. So, use what we // found to generate a set of categories we should add. We @@ -2150,6 +2326,7 @@ bool LLInventoryModel::loadSkeleton( // Add all the items loaded which are parented to a // category with a correctly cached parent count = items.count(); + S32 bad_link_count = 0; cat_map_t::iterator unparented = mCategoryMap.end(); for (int i = 0; i < count; ++i) { @@ -2160,12 +2337,29 @@ bool LLInventoryModel::loadSkeleton( LLViewerInventoryCategory* cat = cit->second; if (cat->getVersion() != NO_VERSION) { + // This can happen if the linked object's baseobj is removed from the cache but the linked object is still in the cache. + if (items[i]->getIsBrokenLink()) + { + bad_link_count++; + lldebugs << "Attempted to add cached link item without baseobj present ( name: " + << items[i]->getName() << " itemID: " << items[i]->getUUID() + << " assetID: " << items[i]->getAssetUUID() + << " ). Ignoring and invalidating " << cat->getName() << " . " << llendl; + invalid_categories.insert(cit->second); + continue; + } addItem(items[i]); cached_item_count += 1; ++child_counts[cat->getUUID()]; } } } + if (bad_link_count > 0) + { + llinfos << "Attempted to add " << bad_link_count + << " cached link items without baseobj present. " + << "The corresponding categories were invalidated." << llendl; + } } else { @@ -2179,6 +2373,17 @@ bool LLInventoryModel::loadSkeleton( } } + // Invalidate all categories that failed fetching descendents for whatever + // reason (e.g. one of the descendents was a broken link). + for (cat_set_t::iterator invalid_cat_it = invalid_categories.begin(); + invalid_cat_it != invalid_categories.end(); + invalid_cat_it++) + { + LLViewerInventoryCategory* cat = (*invalid_cat_it).get(); + cat->setVersion(NO_VERSION); + llinfos << "Invalidating category name: " << cat->getName() << " UUID: " << cat->getUUID() << " due to invalid descendents cache" << llendl; + } + // At this point, we need to set the known descendents for each // category which successfully cached so that we do not // needlessly fetch descendents for categories which we have. @@ -2206,6 +2411,12 @@ bool LLInventoryModel::loadSkeleton( // clean up the gunzipped file. LLFile::remove(inventory_filename); } + if (is_cache_obsolete) + { + // If out of date, remove the gzipped file too. + llwarns << "Inv cache out of date, removing" << llendl; + LLFile::remove(gzip_filename); + } categories.clear(); // will unref and delete entries } @@ -2276,6 +2487,7 @@ bool LLInventoryModel::loadSkeleton( { cat_array_t categories; item_array_t items; + cat_set_t invalid_categories; // Used to mark categories that weren't successfully loaded. std::string owner_id_str; owner_id.toString(owner_id_str); std::string path(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, owner_id_str)); @@ -2302,7 +2514,8 @@ bool LLInventoryModel::loadSkeleton( llinfos << "Unable to gunzip " << gzip_filename << llendl; } } - if(loadFromFile(inventory_filename, categories, items)) + bool is_cache_obsolete = false; + if (loadFromFile(inventory_filename, categories, items, is_cache_obsolete)) { // We were able to find a cache of files. So, use what we // found to generate a set of categories we should add. We @@ -2360,6 +2573,7 @@ bool LLInventoryModel::loadSkeleton( // Add all the items loaded which are parented to a // category with a correctly cached parent count = items.count(); + S32 bad_link_count = 0; cat_map_t::iterator unparented = mCategoryMap.end(); for(int i = 0; i < count; ++i) { @@ -2370,12 +2584,29 @@ bool LLInventoryModel::loadSkeleton( LLViewerInventoryCategory* cat = cit->second; if(cat->getVersion() != NO_VERSION) { + // This can happen if the linked object's baseobj is removed from the cache but the linked object is still in the cache. + if (items[i]->getIsBrokenLink()) + { + bad_link_count++; + lldebugs << "Attempted to add cached link item without baseobj present ( name: " + << items[i]->getName() << " itemID: " << items[i]->getUUID() + << " assetID: " << items[i]->getAssetUUID() + << " ). Ignoring and invalidating " << cat->getName() << " . " << llendl; + invalid_categories.insert(cit->second); + continue; + } addItem(items[i]); cached_item_count += 1; ++child_counts[cat->getUUID()]; } } } + if (bad_link_count > 0) + { + llinfos << "Attempted to add " << bad_link_count + << " cached link items without baseobj present. " + << "The corresponding categories were invalidated." << llendl; + } } else { @@ -2389,6 +2620,17 @@ bool LLInventoryModel::loadSkeleton( } } + // Invalidate all categories that failed fetching descendents for whatever + // reason (e.g. one of the descendents was a broken link). + for (cat_set_t::iterator invalid_cat_it = invalid_categories.begin(); + invalid_cat_it != invalid_categories.end(); + invalid_cat_it++) + { + LLViewerInventoryCategory* cat = (*invalid_cat_it).get(); + cat->setVersion(NO_VERSION); + llinfos << "Invalidating category name: " << cat->getName() << " UUID: " << cat->getUUID() << " due to invalid descendents cache" << llendl; + } + // At this point, we need to set the known descendents for each // category which successfully cached so that we do not // needlessly fetch descendents for categories which we have. @@ -2416,6 +2658,12 @@ bool LLInventoryModel::loadSkeleton( // clean up the gunzipped file. LLFile::remove(inventory_filename); } + if (is_cache_obsolete) + { + // If out of date, remove the gzipped file too. + llwarns << "Inv cache out of date, removing" << llendl; + LLFile::remove(gzip_filename); + } categories.clear(); // will unref and delete entries } @@ -2813,7 +3061,8 @@ bool LLUUIDAndName::operator>(const LLUUIDAndName& rhs) const // static bool LLInventoryModel::loadFromFile(const std::string& filename, LLInventoryModel::cat_array_t& categories, - LLInventoryModel::item_array_t& items) + LLInventoryModel::item_array_t& items, + bool &is_cache_obsolete) { if(filename.empty()) { @@ -2830,11 +3079,32 @@ bool LLInventoryModel::loadFromFile(const std::string& filename, // *NOTE: This buffer size is hard coded into scanf() below. char buffer[MAX_STRING]; /*Flawfinder: ignore*/ char keyword[MAX_STRING]; /*Flawfinder: ignore*/ + char value[MAX_STRING]; /*Flawfinder: ignore*/ + is_cache_obsolete = true; // Obsolete until proven current while(!feof(file) && fgets(buffer, MAX_STRING, file)) { - sscanf(buffer, " %254s", keyword); /* Flawfinder: ignore */ - if(0 == strcmp("inv_category", keyword)) + sscanf(buffer, " %126s %126s", keyword, value); /* Flawfinder: ignore */ + if (0 == strcmp("inv_cache_version", keyword)) { + S32 version; + int succ = sscanf(value,"%d",&version); + if ((1 == succ) && (version == sCurrentInvCacheVersion)) + { + // Cache is up to date + is_cache_obsolete = false; + continue; + } + else + { + // Cache is out of date + break; + } + } + else if(0 == strcmp("inv_category", keyword)) + { + if (is_cache_obsolete) + break; + LLPointer inv_cat = new LLViewerInventoryCategory(LLUUID::null); if(inv_cat->importFileLocal(file)) { @@ -2848,6 +3118,9 @@ bool LLInventoryModel::loadFromFile(const std::string& filename, } else if(0 == strcmp("inv_item", keyword)) { + if (is_cache_obsolete) + break; + LLPointer inv_item = new LLViewerInventoryItem; if( inv_item->importFileLocal(file) ) { @@ -2879,6 +3152,8 @@ bool LLInventoryModel::loadFromFile(const std::string& filename, } } fclose(file); + if (is_cache_obsolete) + return false; return true; } @@ -2900,6 +3175,7 @@ bool LLInventoryModel::saveToFile(const std::string& filename, return false; } + fprintf(file, "\tinv_cache_version\t%d\n", sCurrentInvCacheVersion); S32 count = categories.count(); S32 i; for(i = 0; i < count; ++i) @@ -3223,10 +3499,10 @@ void LLInventoryModel::processSaveAssetIntoInventory(LLMessageSystem* msg, " not found: " << item_id << llendl; } -// [RLVa:KB] - Checked: 2009-07-10 (RLVa-1.0.0g) | Added: RLVa-0.2.0e +// [RLVa:KB] - Checked: 2010-03-05 (RLVa-1.2.0a) | Added: RLVa-0.2.0e if (rlv_handler_t::isEnabled()) { - gRlvHandler.onSavedAssetIntoInventory(item_id); + RlvAttachmentLockWatchdog::instance().onSavedAssetIntoInventory(item_id); } // [/RLVa:KB] @@ -3272,29 +3548,26 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**) // << llendl; if(tfolder->getUUID().notNull()) { -// [RLVa:KB] - Checked: 2009-08-07 (RLVa-1.0.1f) | Added: RLVa-1.0.0f - // TODO-RLVa: this really shouldn't go here, but if the inventory offer spans multiple BulkUpdateInventory messages - // then the second message will cause the viewer to show the folder under its original name even though - // it is renamed properly on the inventory server - if ( (rlv_handler_t::isEnabled()) && (!RlvSettings::getForbidGiveToRLV()) ) - { - LLViewerInventoryCategory* pRlvRoot = gRlvHandler.getSharedRoot(); - std::string strName = tfolder->getName(); - if ((pRlvRoot) && (pRlvRoot->getUUID() == tfolder->getParentUUID() ) && (strName.find(RLV_PUTINV_PREFIX) == 0)) - { - strName.erase(0, strName.find(RLV_FOLDER_PREFIX_PUTINV)); // Strips the prefix while retaining while the '~' - tfolder->rename(strName); - tfolder->updateServer(FALSE); - } - } -// [/RLVa:KB] - folders.push_back(tfolder); LLViewerInventoryCategory* folderp = gInventory.getCategory(tfolder->getUUID()); if(folderp) { if(tfolder->getParentUUID() == folderp->getParentUUID()) { +// [RLVa:KB] - Checked: 2010-04-18 (RLVa-1.2.0e) | Added: RLVa-1.2.0e + // NOTE-RLVa: not sure if this is a hack or a bug-fix :o + // -> if we rename the folder on the first BulkUpdateInventory message subsequent messages will still contain + // the old folder name and gInventory.updateCategory() below will "undo" the folder name change but on the + // viewer-side *only* so the folder name actually becomes out of sync with what's on the inventory server + // -> so instead we keep the name of the existing folder and only do it for #RLV/~ in case this causes issues + // -> a better solution would be to only do the rename *after* the transaction completes but there doesn't seem + // to be any way to accomplish that either *sighs* + if ( (rlv_handler_t::isEnabled()) && (!folderp->getName().empty()) && (tfolder->getName() != folderp->getName()) && + ((tfolder->getName().find(RLV_PUTINV_PREFIX) == 0)) ) + { + tfolder->rename(folderp->getName()); + } +// [/RLVa:KB] update[tfolder->getParentUUID()]; } else @@ -3459,6 +3732,12 @@ void LLInventoryModel::processInventoryDescendents(LLMessageSystem* msg,void**) for(i = 0; i < count; ++i) { titem->unpackMessage(msg, _PREHASH_ItemData, i); + // If the item has already been added (e.g. from link prefetch), then it doesn't need to be re-added. + if (gInventory.getItem(titem->getUUID())) + { + lldebugs << "Skipping prefetched item [ Name: " << titem->getName() << " | Type: " << titem->getActualType() << " | ItemUUID: " << titem->getUUID() << " ] " << llendl; + continue; + } gInventory.updateItem(titem); } @@ -4265,6 +4544,16 @@ bool LLAssetIDMatches ::operator()(LLInventoryCategory* cat, LLInventoryItem* it } +///---------------------------------------------------------------------------- +/// LLLinkedItemIDMatches +///---------------------------------------------------------------------------- +bool LLLinkedItemIDMatches::operator()(LLInventoryCategory* cat, LLInventoryItem* item) +{ + return (item && + (item->getIsLinkType()) && + (item->getLinkedUUID() == mBaseItemID)); // A linked item's assetID will be the compared-to item's itemID. +} + ///---------------------------------------------------------------------------- /// Local function definitions ///---------------------------------------------------------------------------- diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index 187ac795d..e5a7e432c 100644 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -183,7 +183,16 @@ public: cat_array_t& categories, item_array_t& items, BOOL include_trash, - LLInventoryCollectFunctor& add); + LLInventoryCollectFunctor& add, + BOOL follow_folder_links = FALSE); + // Collect all items in inventory that are linked to item_id. + // Assumes item_id is itself not a linked item. + item_array_t collectLinkedItems(const LLUUID& item_id, + const LLUUID& start_folder_id = LLUUID::null); + + // Get the inventoryID that this item points to, else just return item_id + const LLUUID& getLinkedItemID(const LLUUID& object_id) const; + LLViewerInventoryItem* getLinkedItem(const LLUUID& object_id) const; // This method will return false if this inventory model is in an usabel state. // The inventory model usage is sensitive to the initial construction of the @@ -228,6 +237,10 @@ public: // notification, or server update is performed. void deleteObject(const LLUUID& id); + // Delete a particular inventory object by ID, and delete it from + // the server. Also updates linked items. + void purgeObject(const LLUUID& id); + // This is a method which collects the descendents of the id // provided. If the category is not found, no action is // taken. This method goes through the long winded process of @@ -263,6 +276,9 @@ public: // multiple trash can bug. LLUUID findCategoryUUIDForType(LLAssetType::EType preferred_type, bool create_folder = true); + // Get whatever special folder this object is a child of, if any. + const LLViewerInventoryCategory *getFirstNondefaultParent(const LLUUID& obj_id) const; + // Call this method when it's time to update everyone on a new // state, by default, the inventory model will not update // observers automatically. @@ -415,7 +431,8 @@ public: // static bool loadFromFile(const std::string& filename, cat_array_t& categories, - item_array_t& items); + item_array_t& items, + bool& is_cache_obsolete); static bool saveToFile(const std::string& filename, const cat_array_t& categories, const item_array_t& items); @@ -440,6 +457,9 @@ protected: bool messageUpdateCore(LLMessageSystem* msg, bool do_accounting); + // Updates all linked items pointing to this id. + void addChangedMaskForLinks(const LLUUID& object_id, U32 mask); + protected: cat_array_t* getUnlockedCatArray(const LLUUID& id); item_array_t* getUnlockedItemArray(const LLUUID& id); @@ -488,6 +508,9 @@ protected: // This flag is used to handle an invalid inventory state. bool mIsAgentInvUsable; +private: + const static S32 sCurrentInvCacheVersion; // expected inventory cache version + public: // *NOTE: DEBUG functionality void dumpInventory(); @@ -540,6 +563,23 @@ protected: }; +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLLinkedItemIDMatches +// +// This functor finds inventory items linked to the specific inventory id. +// Assumes the inventory id is itself not a linked item. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLLinkedItemIDMatches : public LLInventoryCollectFunctor +{ +public: + LLLinkedItemIDMatches(const LLUUID& item_id) : mBaseItemID(item_id) {} + virtual ~LLLinkedItemIDMatches() {} + bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); + +protected: + LLUUID mBaseItemID; +}; + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLIsType // diff --git a/indra/newview/llinventoryview.cpp b/indra/newview/llinventoryview.cpp index 852e1689d..b6edd0b22 100644 --- a/indra/newview/llinventoryview.cpp +++ b/indra/newview/llinventoryview.cpp @@ -1971,9 +1971,11 @@ void LLInventoryPanel::buildNewViews(const LLUUID& id) << " for object " << objectp->getName() << " (shouldn't happen)" << llendl; } - else if (objectp->getType() == LLAssetType::AT_CATEGORY) // build new view for category + else if ((objectp->getType() == LLAssetType::AT_CATEGORY) && + (objectp->getActualType() != LLAssetType::AT_LINK_FOLDER)) // build new view for category { LLInvFVBridge* new_listener = LLInvFVBridge::createBridge(objectp->getType(), + objectp->getType(), LLInventoryType::IT_CATEGORY, this, objectp->getUUID()); @@ -1994,6 +1996,7 @@ void LLInventoryPanel::buildNewViews(const LLUUID& id) LLInventoryItem* item = (LLInventoryItem*)objectp; LLInvFVBridge* new_listener = LLInvFVBridge::createBridge( item->getType(), + item->getActualType(), item->getInventoryType(), this, item->getUUID(), @@ -2078,6 +2081,7 @@ void LLInventoryPanel::buildNewViews(const LLInventoryObject* objectp) else if (objectp->getType() == LLAssetType::AT_CATEGORY) // build new view for category { LLInvFVBridge* new_listener = LLInvFVBridge::createBridge(objectp->getType(), + objectp->getType(), LLInventoryType::IT_CATEGORY, this, objectp->getUUID()); @@ -2098,6 +2102,7 @@ void LLInventoryPanel::buildNewViews(const LLInventoryObject* objectp) LLInventoryItem* item = (LLInventoryItem*)objectp; LLInvFVBridge* new_listener = LLInvFVBridge::createBridge( item->getType(), + item->getActualType(), item->getInventoryType(), this, item->getUUID(), diff --git a/indra/newview/llinventoryview.h b/indra/newview/llinventoryview.h index a8de648f7..68c5dc0b3 100644 --- a/indra/newview/llinventoryview.h +++ b/indra/newview/llinventoryview.h @@ -420,8 +420,6 @@ BOOL move_inv_category_world_to_agent(const LLUUID& object_id, const BOOL TAKE_FOCUS_YES = TRUE; const BOOL TAKE_FOCUS_NO = FALSE; -void rez_attachment(LLViewerInventoryItem* item, LLViewerJointAttachment* attachment); - #endif // LL_LLINVENTORYVIEW_H diff --git a/indra/newview/lllocalinventory.cpp b/indra/newview/lllocalinventory.cpp index 0960609f6..7988667c1 100644 --- a/indra/newview/lllocalinventory.cpp +++ b/indra/newview/lllocalinventory.cpp @@ -175,7 +175,8 @@ void LLLocalInventory::loadInvCache(std::string filename) LLInventoryModel::cat_array_t cats; LLInventoryModel::item_array_t items; - if(LLInventoryModel::loadFromFile(inv_filename, cats, items)) + bool is_cache_obsolete = false; + if(LLInventoryModel::loadFromFile(inv_filename, cats, items, is_cache_obsolete)) { // create a container category for everything LLViewerInventoryCategory* container = new LLViewerInventoryCategory(gAgent.getID()); diff --git a/indra/newview/llpanelcontents.cpp b/indra/newview/llpanelcontents.cpp index 02befeade..6c9651e1d 100644 --- a/indra/newview/llpanelcontents.cpp +++ b/indra/newview/llpanelcontents.cpp @@ -67,8 +67,7 @@ #include "lltoolmgr.h" #include "lltoolcomp.h" #include "llpanelinventory.h" - -// [RLVa:KB] +// [RLVa:KB] - Checked: 2010-03-31 (RLVa-1.2.0c) #include "rlvhandler.h" // [/RLVa:KB] @@ -123,19 +122,20 @@ void LLPanelContents::getState(LLViewerObject *objectp ) && ( objectp->permYouOwner() || ( !group_id.isNull() && gAgent.isInGroup(group_id) ))); // solves SL-23488 BOOL all_volume = LLSelectMgr::getInstance()->selectionAllPCode( LL_PCODE_VOLUME ); -// [RLVa:KB] - Version: 1.23.4 | Checked: 2009-10-10 (RLVa-1.0.5a) | Modified: RLVa-1.0.5a +// [RLVa:KB] - Checked: 2010-04-01 (RLVa-1.2.0c) | Modified: RLVa-1.0.5a if ( (rlv_handler_t::isEnabled()) && (editable) ) { - // Don't allow creation of new scripts if it's undetachable - editable = !gRlvHandler.isLockedAttachment(objectp, RLV_LOCK_REMOVE); + // Don't allow creation of new scripts if it's non-detachable + if (objectp->isAttachment()) + editable = !gRlvAttachmentLocks.isLockedAttachment(objectp->getRootEdit()); // Don't allow creation of new scripts if we're @unsit=n or @sittp=n restricted and we're sitting on the selection if ( (editable) && ((gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SITTP))) ) { - LLVOAvatar* pAvatar = gAgent.getAvatarObject(); // Only check the first (non-)root object because nothing else would result in enabling the button (see below) LLViewerObject* pObj = LLSelectMgr::getInstance()->getSelection()->getFirstRootObject(TRUE); + LLVOAvatar* pAvatar = gAgent.getAvatarObject(); editable = (pObj) && (pAvatar) && ((!pAvatar->mIsSitting) || (pAvatar->getRoot() != pObj->getRootEdit())); } } @@ -175,10 +175,10 @@ void LLPanelContents::onClickNewScript(void *userdata) LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getFirstRootObject(children_ok); if(object) { -// [RLVa:KB] - Checked: 2009-10-10 (RLVa-1.0.5a) +// [RLVa:KB] - Checked: 2010-03-31 (RLVa-1.2.0c) | Modified: RLVa-1.0.5a if (rlv_handler_t::isEnabled()) // Fallback code [see LLPanelContents::getState()] { - if (gRlvHandler.isLockedAttachment(object, RLV_LOCK_REMOVE)) + if (gRlvAttachmentLocks.isLockedAttachment(object->getRootEdit())) { return; // Disallow creating new scripts in a locked attachment } diff --git a/indra/newview/llpanelinventory.cpp b/indra/newview/llpanelinventory.cpp index 0055dd700..72776f41c 100644 --- a/indra/newview/llpanelinventory.cpp +++ b/indra/newview/llpanelinventory.cpp @@ -81,8 +81,7 @@ #include "llviewerobjectlist.h" #include "llviewerwindow.h" #include "llwearable.h" - -// [RLVa:KB] +// [RLVa:KB] - Checked: 2010-03-27 (RLVa-1.2.0b) #include "rlvhandler.h" // [/RLVa:KB] @@ -146,6 +145,7 @@ public: virtual void cutToClipboard(); virtual BOOL isClipboardPasteable() const; virtual void pasteFromClipboard(); + virtual void pasteLinkFromClipboard(); virtual void buildContextMenu(LLMenuGL& menu, U32 flags); virtual void performAction(LLFolderView* folder, LLInventoryModel* model, std::string action); virtual BOOL isUpToDate() const { return TRUE; } @@ -371,9 +371,9 @@ void LLTaskInvFVBridge::previewItem() BOOL LLTaskInvFVBridge::isItemRenameable() const { -// [RLVa:KB] - Checked: 2009-10-10 (RLVa-1.0.5a) | Modified: RLVa-1.0.5a +// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.0.5a LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); - if ( (rlv_handler_t::isEnabled()) && (gRlvHandler.isLockedAttachment(object, RLV_LOCK_REMOVE)) ) + if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.isLockedAttachment(object->getRootEdit())) ) { return FALSE; } @@ -396,13 +396,15 @@ BOOL LLTaskInvFVBridge::isItemRenameable() const BOOL LLTaskInvFVBridge::renameItem(const std::string& new_name) { +// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.0.5a LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); -// [RLVa:KB] - Checked: 2009-10-10 (RLVa-1.0.5a) | Modified: RLVa-1.0.5a - if ( (rlv_handler_t::isEnabled()) && (gRlvHandler.isLockedAttachment(object, RLV_LOCK_REMOVE)) ) + if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.isLockedAttachment(object->getRootEdit())) ) { - return TRUE; // Fallback code [see LLTaskInvFVBridge::isItemRenameable()] + return FALSE; } // [/RLVa:KB] + +// LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); if(object) { LLViewerInventoryItem* item = NULL; @@ -429,13 +431,13 @@ BOOL LLTaskInvFVBridge::isItemMovable() // return TRUE; //} //return FALSE; -// [RLVa:KB] - Checked: 2009-10-10 (RLVa-1.0.5a) | Modified: RLVa-1.0.5a +// [RLVa:KB] - Checked: 2010-04-01 (RLVa-1.2.0c) | Modified: RLVa-1.0.5a if (rlv_handler_t::isEnabled()) { - LLViewerObject* pObj = gObjectList.findObject(mPanel->getTaskUUID()); + const LLViewerObject* pObj = gObjectList.findObject(mPanel->getTaskUUID()); if (pObj) { - if (gRlvHandler.isLockedAttachment(pObj, RLV_LOCK_REMOVE)) + if (gRlvAttachmentLocks.isLockedAttachment(pObj->getRootEdit())) { return FALSE; } @@ -454,17 +456,18 @@ BOOL LLTaskInvFVBridge::isItemMovable() BOOL LLTaskInvFVBridge::isItemRemovable() { LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); -// [RLVa:KB] - Checked: 2009-10-10 (RLVa-1.0.5a) | Modified: RLVa-1.0.5a +// [RLVa:KB] - Checked: 2010-04-01 (RLVa-1.2.0c) | Modified: RLVa-1.0.5a if ( (object) && (rlv_handler_t::isEnabled()) ) { - if (gRlvHandler.isLockedAttachment(object, RLV_LOCK_REMOVE)) + const LLViewerObject* pObjRoot = object->getRootEdit(); + if (gRlvAttachmentLocks.isLockedAttachment(pObjRoot)) { return FALSE; } else if ( (gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SITTP)) ) { LLVOAvatar* pAvatar = gAgent.getAvatarObject(); - if ( (pAvatar) && (pAvatar->mIsSitting) && (pAvatar->getRoot() == object->getRootEdit()) ) + if ( (pAvatar) && (pAvatar->mIsSitting) && (pAvatar->getRoot() == pObjRoot) ) return FALSE; } } @@ -603,6 +606,10 @@ void LLTaskInvFVBridge::pasteFromClipboard() { } +void LLTaskInvFVBridge::pasteLinkFromClipboard() +{ +} + BOOL LLTaskInvFVBridge::startDrag(EDragAndDropType* type, LLUUID* id) const { //llinfos << "LLTaskInvFVBridge::startDrag()" << llendl; @@ -617,9 +624,9 @@ BOOL LLTaskInvFVBridge::startDrag(EDragAndDropType* type, LLUUID* id) const const LLPermissions& perm = inv->getPermissions(); bool can_copy = gAgent.allowOperation(PERM_COPY, perm, GP_OBJECT_MANIPULATE); -// [RLVa:KB] - Checked: 2009-10-10 (RLVa-1.0.5a) | Modified: RLVa-1.0.5a +// [RLVa:KB] - Checked: 2009-10-10 (RLVa-1.2.1f) | Modified: RLVa-1.0.5a // Kind of redundant due to the note below, but in case that ever gets fixed - if ( (rlv_handler_t::isEnabled()) && (gRlvHandler.isLockedAttachment(object, RLV_LOCK_REMOVE)) ) + if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.isLockedAttachment(object->getRootEdit())) ) { return FALSE; } @@ -746,12 +753,13 @@ void LLTaskInvFVBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { disabled_items.push_back(std::string("Task Open")); } -// [RLVa:KB] - Checked: 2009-11-11 (RLVa-1.1.0a) | Modified: RLVa-1.1.0a +// [RLVa:KB] - Checked: 2010-03-01 (RLVa-1.2.0b) | Modified: RLVa-1.1.0a else if (rlv_handler_t::isEnabled()) { - bool fLocked = gRlvHandler.isLockedAttachment(gObjectList.findObject(mPanel->getTaskUUID()), RLV_LOCK_REMOVE); - if ( ((LLAssetType::AT_LSL_TEXT == item->getType()) && ((gRlvHandler.hasBehaviour(RLV_BHVR_VIEWSCRIPT)) || (fLocked))) || - ((LLAssetType::AT_NOTECARD == item->getType()) && ((gRlvHandler.hasBehaviour(RLV_BHVR_VIEWNOTE)) || (fLocked))) || + LLViewerObject* pAttachObj = gObjectList.findObject(mPanel->getTaskUUID()); + bool fLocked = (pAttachObj) ? gRlvAttachmentLocks.isLockedAttachment(pAttachObj->getRootEdit()) : false; + if ( ((LLAssetType::AT_NOTECARD == item->getType()) && ((gRlvHandler.hasBehaviour(RLV_BHVR_VIEWNOTE)) || (fLocked))) || + ((LLAssetType::AT_LSL_TEXT == item->getType()) && ((gRlvHandler.hasBehaviour(RLV_BHVR_VIEWSCRIPT)) || (fLocked))) || ((LLAssetType::AT_TEXTURE == item->getType()) && (gRlvHandler.hasBehaviour(RLV_BHVR_VIEWTEXTURE))) ) { disabled_items.push_back(std::string("Task Open")); @@ -760,14 +768,26 @@ void LLTaskInvFVBridge::buildContextMenu(LLMenuGL& menu, U32 flags) // [/RLVa:KB] } items.push_back(std::string("Task Properties")); - if(isItemRenameable()) +// if(isItemRenameable()) +// { +// items.push_back(std::string("Task Rename")); +// } +// if(isItemRemovable()) +// { +// items.push_back(std::string("Task Remove")); +// } +// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Added: RLVa-1.2.1f + items.push_back(std::string("Task Rename")); + items.push_back(std::string("Task Remove")); + if (!isItemRenameable()) { - items.push_back(std::string("Task Rename")); + disabled_items.push_back(std::string("Task Rename")); } - if(isItemRemovable()) + if (!isItemRemovable()) { - items.push_back(std::string("Task Remove")); + disabled_items.push_back(std::string("Task Remove")); } +// [/RLVa:KB] hideContextEntries(menu, items, disabled_items); } @@ -849,22 +869,12 @@ BOOL LLTaskCategoryBridge::startDrag(EDragAndDropType* type, LLUUID* id) const LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); if(object) { - LLInventoryItem* inv = NULL; - if((inv = (LLInventoryItem*)object->getInventoryObject(mUUID))) + const LLInventoryObject* cat = object->getInventoryObject(mUUID); + if ( (cat) && (move_inv_category_world_to_agent(mUUID, LLUUID::null, FALSE)) ) { - const LLPermissions& perm = inv->getPermissions(); - bool can_copy = gAgent.allowOperation(PERM_COPY, perm, - GP_OBJECT_MANIPULATE); - if((can_copy && perm.allowTransferTo(gAgent.getID())) - || object->permYouOwner()) -// || gAgent.isGodlike()) - - { - *type = LLAssetType::lookupDragAndDropType(inv->getType()); - - *id = inv->getUUID(); - return TRUE; - } + *type = LLAssetType::lookupDragAndDropType(cat->getType()); + *id = mUUID; + return TRUE; } } } @@ -1279,30 +1289,25 @@ LLTaskLSLBridge::LLTaskLSLBridge( void LLTaskLSLBridge::openItem() { -// [RLVa:KB] - Checked: 2009-11-11 (RLVa-1.1.0a) | Modified: RLVa-1.1.0a + llinfos << "LLTaskLSLBridge::openItem() " << mUUID << llendl; + if(LLLiveLSLEditor::show(mUUID, mPanel->getTaskUUID())) + { + return; + } LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); - if ( (rlv_handler_t::isEnabled()) && - ((gRlvHandler.hasBehaviour(RLV_BHVR_VIEWSCRIPT)) || (gRlvHandler.isLockedAttachment(object, RLV_LOCK_REMOVE))) ) + if(!object || object->isInventoryPending()) + { + return; + } + +// [RLVa:KB] - Checked: 2010-03-27 (RLVa-1.1.3b) | Modified: RLVa-1.1.0a + if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.isLockedAttachment(object->getRootEdit())) ) { RlvNotifications::notifyBlockedViewScript(); return; } // [/RLVa:KB] - llinfos << "LLTaskLSLBridge::openItem() " << mUUID << llendl; - if(LLLiveLSLEditor::show(mUUID, mPanel->getTaskUUID())) - { - return; - } - llinfos << "LLTaskLSLBridge::openItem() " << mUUID << llendl; - if(LLLiveLSLEditor::show(mUUID, mPanel->getTaskUUID())) - { - return; - } - if(!object || object->isInventoryPending()) - { - return; - } if(object->permModify() || gAgent.isGodlike()) { std::string title("Script: "); @@ -1413,9 +1418,9 @@ void LLTaskNotecardBridge::openItem() { return; } -// [RLVa:KB] - Checked: 2009-11-11 (RLVa-1.1.0a) | Modified: RLVa-1.1.0a +// [RLVa:KB] - Checked: 2009-11-11 (RLVa-1.1.3b) | Modified: RLVa-1.1.0a if ( (rlv_handler_t::isEnabled()) && - ( (gRlvHandler.hasBehaviour(RLV_BHVR_VIEWNOTE)) || (gRlvHandler.isLockedAttachment(object, RLV_LOCK_REMOVE)) ) ) + ((gRlvHandler.hasBehaviour(RLV_BHVR_VIEWNOTE)) || (gRlvAttachmentLocks.isLockedAttachment(object->getRootEdit()))) ) { RlvNotifications::notifyBlockedViewNote(); return; diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp index bbd0524b6..3c22f15b5 100644 --- a/indra/newview/llpreviewscript.cpp +++ b/indra/newview/llpreviewscript.cpp @@ -86,8 +86,7 @@ #include "llviewercontrol.h" #include "llappviewer.h" #include "llpanelinventory.h" - -// [RLVa:KB] +// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) #include "rlvhandler.h" // [/RLVa:KB] @@ -2073,14 +2072,15 @@ void LLLiveLSLEditor::onRunningCheckboxClicked( LLUICtrl*, void* userdata ) LLCheckBoxCtrl* runningCheckbox = self->getChild("running"); BOOL running = runningCheckbox->get(); //self->mRunningCheckbox->get(); -// [RLVa:KB] - Checked: 2009-10-10 (RLVa-1.0.5a) | Modified: RLVa-1.0.5a - if ( (rlv_handler_t::isEnabled()) && (gRlvHandler.isLockedAttachment(object, RLV_LOCK_REMOVE)) ) - { - return; - } -// [/RLVa:KB] if( object ) { +// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.0.5a + if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.isLockedAttachment(object->getRootEdit())) ) + { + return; + } +// [/RLVa:KB] + LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_SetScriptRunning); msg->nextBlockFast(_PREHASH_AgentData); @@ -2104,14 +2104,15 @@ void LLLiveLSLEditor::onReset(void *userdata) LLLiveLSLEditor* self = (LLLiveLSLEditor*) userdata; LLViewerObject* object = gObjectList.findObject( self->mObjectID ); -// [RLVa:KB] - Checked: 2009-10-10 (RLVa-1.0.5a) | Modified: RLVa-1.0.5a - if ( (rlv_handler_t::isEnabled()) && (gRlvHandler.isLockedAttachment(object, RLV_LOCK_REMOVE)) ) - { - return; - } -// [/RLV:KB] if(object) { +// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.0.5a + if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.isLockedAttachment(object->getRootEdit())) ) + { + return; + } +// [/RLVa:KB] + LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_ScriptReset); msg->nextBlockFast(_PREHASH_AgentData); @@ -2536,12 +2537,13 @@ void LLLiveLSLEditor::onSave(void* userdata, BOOL close_after_save) { LLLiveLSLEditor* self = (LLLiveLSLEditor*)userdata; -// [RLVa:KB] - Checked: 2009-10-10 (RLVa-1.0.5a) | Modified: RLVa-1.0.5a - if ( (rlv_handler_t::isEnabled()) && (gRlvHandler.isLockedAttachment(gObjectList.findObject(self->mObjectID), RLV_LOCK_REMOVE)) ) +// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.0.5a + const LLViewerObject* pObject = gObjectList.findObject(self->mObjectID); + if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.isLockedAttachment(pObject->getRootEdit())) ) { return; } -// [/RLV:KB] +// [/RLVa:KB] self->mCloseAfterSave = close_after_save; self->saveIfNeeded(); diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 19b3fde46..ebd5350f3 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -3595,6 +3595,13 @@ void LLSelectMgr::sendAttach(U8 attachment_point) if (0 == attachment_point || get_if_there(gAgent.getAvatarObject()->mAttachmentPoints, (S32)attachment_point, (LLViewerJointAttachment*)NULL)) { + if (attachment_point != 0) + { + // If we know the attachment point then we got here by clicking an + // "Attach to..." context menu item, so we should add, not replace. + attachment_point |= ATTACHMENT_ADD; + } + sendListToRegions( "ObjectAttach", packAgentIDAndSessionAndAttachment, diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp index a964b6ca1..60da41529 100644 --- a/indra/newview/lltooldraganddrop.cpp +++ b/indra/newview/lltooldraganddrop.cpp @@ -47,6 +47,7 @@ #include "llgesturemgr.h" #include "llhudeffecttrail.h" #include "llhudmanager.h" +#include "llinventorybridge.h" #include "llinventorymodel.h" #include "llinventoryview.h" #include "llmutelist.h" @@ -76,7 +77,7 @@ #include "object_flags.h" #include "llimview.h" -// [RLVa:KB] +// [RLVa:KB] - Checked: 2010-03-04 (RLVa-1.2.0a) #include "rlvhandler.h" // [/RLVa:KB] @@ -483,6 +484,15 @@ LLToolDragAndDrop::dragOrDrop3dImpl LLToolDragAndDrop::sDragAndDrop3d[DAD_COUNT] &LLToolDragAndDrop::dad3dUpdateInventory, // Dest: DT_OBJECT &LLToolDragAndDrop::dad3dNULL,//dad3dAssetOnLand, // Dest: DT_LAND }, + // Source: DAD_LINK + // TODO: gesture on self could play it? edit it? + { + &LLToolDragAndDrop::dad3dNULL, // Dest: DT_NONE + &LLToolDragAndDrop::dad3dNULL, // Dest: DT_SELF + &LLToolDragAndDrop::dad3dNULL, // Dest: DT_AVATAR + &LLToolDragAndDrop::dad3dNULL, // Dest: DT_OBJECT + &LLToolDragAndDrop::dad3dNULL,//dad3dAssetOnLand, // Dest: DT_LAND + }, }; LLToolDragAndDrop::LLToolDragAndDrop() @@ -1290,9 +1300,9 @@ void LLToolDragAndDrop::dropObject(LLViewerObject* raycast_target, } -// [RLVa:KB] - Checked: 2009-07-05 (RLVa-1.0.0b) +// [RLVa:KB] - Checked: 2010-03-23 (RLVa-1.2.0e) | Modified: RLVa-1.2.0a // Fallback in case there's a new code path that leads here (see behaviour notes) - if (gRlvHandler.hasBehaviour(RLV_BHVR_REZ)) + if ( (rlv_handler_t::isEnabled()) && ((gRlvHandler.hasBehaviour(RLV_BHVR_REZ)) || (gRlvHandler.hasBehaviour(RLV_BHVR_INTERACT))) ) { return; } @@ -2000,6 +2010,7 @@ EAcceptance LLToolDragAndDrop::willObjectAcceptInventory(LLViewerObject* obj, LL //if(!vitem->isComplete()) return ACCEPT_NO; if(!vitem->isComplete() && !(gInventory.isObjectDescendentOf(vitem->getUUID(), gSystemFolderRoot))) return ACCEPT_NO; // + if (vitem->getIsLinkType()) return ACCEPT_NO; // No giving away links // deny attempts to drop from an object onto itself. This is to // help make sure that drops that are from an object to an object @@ -2046,17 +2057,18 @@ EAcceptance LLToolDragAndDrop::willObjectAcceptInventory(LLViewerObject* obj, LL BOOL attached = obj->isAttachment(); BOOL unrestricted = ((perm.getMaskBase() & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED) ? TRUE : FALSE; -// [RLVa:KB] - Checked: 2009-07-06 (RLVa-1.0.0c) +// [RLVa:KB] - Checked: 2010-03-31 (RLVa-1.2.0c) | Modified: RLVa-1.0.0c if (rlv_handler_t::isEnabled()) { - if (gRlvHandler.isLockedAttachment(obj, RLV_LOCK_REMOVE)) + const LLViewerObject* pObjRoot = obj->getRootEdit(); + if (gRlvAttachmentLocks.isLockedAttachment(pObjRoot)) { return ACCEPT_NO_LOCKED; // Disallow inventory drops on a locked attachment } else if ( (gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SITTP)) ) { LLVOAvatar* pAvatar = gAgent.getAvatarObject(); - if ( (pAvatar) && (pAvatar->mIsSitting) && (pAvatar->getRoot() == obj->getRootEdit()) ) + if ( (pAvatar) && (pAvatar->mIsSitting) && (pAvatar->getRoot() == pObjRoot) ) return ACCEPT_NO_LOCKED; // ... or on a linkset the avie is sitting on under @unsit=n/@sittp=n } } @@ -2195,14 +2207,12 @@ EAcceptance LLToolDragAndDrop::dad3dRezAttachmentFromInv( //} // -// [RLVa:KB] - Checked: 2009-10-10 (RLVa-1.0.5) | Modified: RLVa-1.0.5 - LLViewerJointAttachment* pAttachPt = NULL; - if ( (rlv_handler_t::isEnabled()) && (gRlvHandler.hasLockedAttachment(RLV_LOCK_ANY)) && (!RlvSettings::getEnableWear()) && - ( ((pAttachPt = gRlvHandler.getAttachPoint(item, true)) == NULL) || // Item should specify an attachpt that - (gRlvHandler.isLockedAttachment(pAttachPt->getObject(), RLV_LOCK_REMOVE)) || // doesn't have an undetachable object - (gRlvHandler.isLockedAttachment(pAttachPt, RLV_LOCK_ADD)) ) ) // and that is attachable +// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.2.1f + if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) ) { - return ACCEPT_NO_LOCKED; + ERlvWearMask eWearMask = gRlvAttachmentLocks.canAttach(item); bool fReplace = !(mask & MASK_CONTROL); + if ( ((!fReplace) && ((RLV_WEAR_ADD & eWearMask) == 0)) || ((fReplace) && ((RLV_WEAR_REPLACE & eWearMask) == 0)) ) + return ACCEPT_NO_LOCKED; } // [/RLVa:KB] @@ -2210,7 +2220,11 @@ EAcceptance LLToolDragAndDrop::dad3dRezAttachmentFromInv( { if(mSource == SOURCE_LIBRARY) { - LLPointer cb = new RezAttachmentCallback(0); +// LLPointer cb = new RezAttachmentCallback(0); +// [SL:KB] - Patch: Appearance-Misc | Checked: 2010-09-08 (Catznip-2.2.0a) | Added: Catznip-2.2.0a + // Make this behave consistent with dad3dWearItem + LLPointer cb = new RezAttachmentCallback(0, !(mask & MASK_CONTROL)); +// [/SL:KB] copy_inventory_item( gAgent.getID(), item->getPermissions().getOwner(), @@ -2221,10 +2235,11 @@ EAcceptance LLToolDragAndDrop::dad3dRezAttachmentFromInv( } else { -// [RLVa:KB] - Checked: 2009-07-06 (RLVa-1.0.0c) | Added: RLVa-1.0.0c - rez_attachment(item, pAttachPt); -// [/RLVa:KB] - //rez_attachment(item, 0); +// rez_attachment(item, 0); +// [SL:KB] - Patch: Appearance-Misc | Checked: 2010-09-08 (Catznip-2.2.0a) | Added: Catznip-2.2.0a + // Make this behave consistent with dad3dWearItem + rez_attachment(item, 0, !(mask & MASK_CONTROL)); +// [/SL:KB] } } return ACCEPT_YES_SINGLE; @@ -2234,7 +2249,8 @@ EAcceptance LLToolDragAndDrop::dad3dRezAttachmentFromInv( EAcceptance LLToolDragAndDrop::dad3dRezObjectOnLand( LLViewerObject* obj, S32 face, MASK mask, BOOL drop) { -// [RLVa:KB] - Checked: 2010-01-02 (RLVa-1.1.0l) | Modified: RLVa-1.1.0l +// [RLVa:KB] - Checked: 2010-03-23 (RLVa-1.2.0e) | Modified: RLVa-1.1.0l + // RELEASE-RLVa: [SL-2.2.0] Make sure the code below is the only code path to LLToolDragAndDrop::dad3dRezFromObjectOnLand() if ( (rlv_handler_t::isEnabled()) && ((gRlvHandler.hasBehaviour(RLV_BHVR_REZ)) || (gRlvHandler.hasBehaviour(RLV_BHVR_INTERACT))) ) { return ACCEPT_NO_LOCKED; @@ -2305,9 +2321,10 @@ EAcceptance LLToolDragAndDrop::dad3dRezObjectOnLand( EAcceptance LLToolDragAndDrop::dad3dRezObjectOnObject( LLViewerObject* obj, S32 face, MASK mask, BOOL drop) { -// [RLVa:KB] - Checked: 2010-01-02 (RLVa-1.1.0l) | Modified: RLVa-1.1.0l +// [RLVa:KB] - Checked: 2010-03-23 (RLVa-1.2.0e) | Modified: RLVa-1.1.0l // NOTE: if (mask & MASK_CONTROL) then it's a drop rather than a rez, so we let that pass through when @rez=n restricted // (but not when @interact=n restricted unless the drop target is a HUD attachment) + // RELEASE-RLVa: [SL-2.2.0] Make sure the code below is the only code path to LLToolDragAndDrop::dad3dRezFromObjectOnObject() if ( (rlv_handler_t::isEnabled()) && ( ( (gRlvHandler.hasBehaviour(RLV_BHVR_REZ)) && ((mask & MASK_CONTROL) == 0) ) || ( (gRlvHandler.hasBehaviour(RLV_BHVR_INTERACT)) && (((mask & MASK_CONTROL) == 0) || (!obj->isHUDAttachment())) ) ) ) @@ -2530,17 +2547,10 @@ EAcceptance LLToolDragAndDrop::dad3dWearItem( return ACCEPT_NO; } -// [RLVa:KB] - Checked: 2009-07-07 (RLVa-1.0.0d) - // (See behaviour notes for the "code path", this is just to give a visual indication on whether or not the drop is allowed) - if (rlv_handler_t::isEnabled()) +// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.2.1f + if ( (rlv_handler_t::isEnabled()) && (RLV_WEAR_REPLACE != gRlvWearableLocks.canWear(item)) ) { - EWearableType type = (EWearableType)item->getFlags(); - - // Block if: 1) we can't wear on that layer; 2) or if we're already wearing something there we can't take off - if ( (!gRlvHandler.isWearable(type)) || ((gAgent.getWearable(type)) && (!gRlvHandler.isRemovable(type))) ) - { - return ACCEPT_NO_LOCKED; - } + return ACCEPT_NO_LOCKED; } // [/RLVa:KB] @@ -2908,14 +2918,6 @@ EAcceptance LLToolDragAndDrop::dad3dGiveInventoryCategory( EAcceptance LLToolDragAndDrop::dad3dRezFromObjectOnLand( LLViewerObject* obj, S32 face, MASK mask, BOOL drop) { -// [RLVa:KB] - Checked: 2010-01-02 (RLVa-1.1.0l) | Modified: RLVa-1.1.0l - // [Fall-back code] Looks like this is only ever called from LLToolDragAndDrop::dad3dRezObjectOnObject() - if ( (rlv_handler_t::isEnabled()) && ((gRlvHandler.hasBehaviour(RLV_BHVR_REZ)) || (gRlvHandler.hasBehaviour(RLV_BHVR_INTERACT))) ) - { - return ACCEPT_NO_LOCKED; - } -// [/RLVa:KB] - lldebugs << "LLToolDragAndDrop::dad3dRezFromObjectOnLand()" << llendl; LLViewerInventoryItem* item = NULL; LLViewerInventoryCategory* cat = NULL; @@ -2937,14 +2939,6 @@ EAcceptance LLToolDragAndDrop::dad3dRezFromObjectOnLand( EAcceptance LLToolDragAndDrop::dad3dRezFromObjectOnObject( LLViewerObject* obj, S32 face, MASK mask, BOOL drop) { -// [RLVa:KB] - Checked: 2010-01-02 (RLVa-1.1.0l) | Modified: RLVa-1.1.0l - // [Fall-back code] Looks like this is only ever called from LLToolDragAndDrop::dad3dRezObjectOnObject() - if ( (rlv_handler_t::isEnabled()) && ((gRlvHandler.hasBehaviour(RLV_BHVR_REZ)) || (gRlvHandler.hasBehaviour(RLV_BHVR_INTERACT))) ) - { - return ACCEPT_NO_LOCKED; - } -// [/RLVa:KB] - lldebugs << "LLToolDragAndDrop::dad3dRezFromObjectOnObject()" << llendl; LLViewerInventoryItem* item; LLViewerInventoryCategory* cat; diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index c1dea53b7..09aef8a22 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -804,8 +804,8 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) } // if(gUseWireframe) -// [RLVa:KB] - Checked: 2009-10-10 (RLVa-1.0.5a) | Modified: RLVa-1.0.5a - if ( (gUseWireframe) && ( (!rlv_handler_t::isEnabled()) || (!gRlvHandler.hasLockedAttachment(RLV_LOCK_REMOVE)) ) ) +// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.1.3b) | Modified: RLVa-1.1.3b + if ( (gUseWireframe) && ((!rlv_handler_t::isEnabled()) || (!gRlvAttachmentLocks.hasLockedHUD())) ) // [/RLVa:KB] { glClearColor(0.5f, 0.5f, 0.5f, 0.f); @@ -965,12 +965,10 @@ void render_hud_attachments() glh::matrix4f current_mod = glh_get_current_modelview(); // clamp target zoom level to reasonable values -// [RLVa:KB] - Checked: 2009-07-06 (RLVa-1.0.0c) - // TODO-RLVa: while hasLockedHUD() isn't slow this is called per frame so find a better way - gAgent.mHUDTargetZoom = llclamp(gAgent.mHUDTargetZoom, - ( (!rlv_handler_t::isEnabled()) || (!gRlvHandler.hasLockedHUD()) ) ? 0.1f : 0.85f, 1.f); +// gAgent.mHUDTargetZoom = llclamp(gAgent.mHUDTargetZoom, 0.1f, 1.f); +// [RLVa:KB] - Checked: 2010-08-22 (RLVa-1.2.1a) | Modified: RLVa-1.0.0c + gAgent.mHUDTargetZoom = llclamp(gAgent.mHUDTargetZoom, (!gRlvAttachmentLocks.hasLockedHUD()) ? 0.1f : 0.85f, 1.f); // [/RLVa:KB] - //gAgent.mHUDTargetZoom = llclamp(gAgent.mHUDTargetZoom, 0.1f, 1.f); // smoothly interpolate current zoom level gAgent.mHUDCurZoom = lerp(gAgent.mHUDCurZoom, gAgent.mHUDTargetZoom, LLCriticalDamp::getInterpolant(0.03f)); diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index 8126fa887..522a7c5fa 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -44,6 +44,7 @@ #include "llimview.h" #include "llgesturemgr.h" +#include "llinventorybridge.h" #include "llinventoryview.h" #include "llviewerregion.h" @@ -359,6 +360,22 @@ void LLViewerInventoryItem::updateParentOnServer(BOOL restamp) const // return mClones; //} +// [RLVa:KB] - Checked: 2010-09-27 (RLVa-1.1.3a) | Added: RLVa-1.1.3a +bool LLViewerInventoryItem::isWearableType() const +{ + return (getInventoryType() == LLInventoryType::IT_WEARABLE); +} + +EWearableType LLViewerInventoryItem::getWearableType() const +{ + if (!isWearableType()) + { + return WT_INVALID; + } + return EWearableType(getFlags() & II_FLAGS_WEARABLES_MASK); +} +// [/RLVa:KB] + ///---------------------------------------------------------------------------- /// Class LLViewerInventoryCategory ///---------------------------------------------------------------------------- @@ -424,7 +441,7 @@ void LLViewerInventoryCategory::updateParentOnServer(BOOL restamp) const void LLViewerInventoryCategory::updateServer(BOOL is_new) const { // communicate that change with the server. - if(LLAssetType::AT_NONE != mPreferredType) + if ( (LLAssetType::AT_NONE != mPreferredType) && (LLAssetType::AT_OUTFIT != mPreferredType) ) { LLNotifications::instance().add("CannotModifyProtectedCategories"); return; @@ -448,7 +465,7 @@ void LLViewerInventoryCategory::removeFromServer( void ) llinfos << "Removing inventory category " << mUUID << " from server." << llendl; // communicate that change with the server. - if(LLAssetType::AT_NONE != mPreferredType) + if ( (LLAssetType::AT_NONE != mPreferredType) && (LLAssetType::AT_OUTFIT != mPreferredType) ) { LLNotifications::instance().add("CannotRemoveProtectedCategories"); return; @@ -672,9 +689,10 @@ void WearOnAvatarCallback::fire(const LLUUID& inv_item) } } -RezAttachmentCallback::RezAttachmentCallback(LLViewerJointAttachment *attachmentp) +RezAttachmentCallback::RezAttachmentCallback(LLViewerJointAttachment *attachmentp, bool replace) { mAttach = attachmentp; + mReplace = replace; } RezAttachmentCallback::~RezAttachmentCallback() { @@ -688,7 +706,7 @@ void RezAttachmentCallback::fire(const LLUUID& inv_item) LLViewerInventoryItem *item = gInventory.getItem(inv_item); if (item) { - rez_attachment(item, mAttach); + rez_attachment(item, mAttach, mReplace); } } @@ -772,6 +790,72 @@ void copy_inventory_item( gAgent.sendReliableMessage(); } +void link_inventory_item( + const LLUUID& agent_id, + const LLUUID& item_id, + const LLUUID& parent_id, + const std::string& new_name, + const std::string& new_description, + const LLAssetType::EType asset_type, + LLPointer cb) +{ + const LLInventoryObject *baseobj = gInventory.getObject(item_id); + if (!baseobj) + { + llwarns << "attempt to link to unknown item, linked-to-item's itemID " << item_id << llendl; + return; + } + if (baseobj && baseobj->getIsLinkType()) + { + llwarns << "attempt to create a link to a link, linked-to-item's itemID " << item_id << llendl; + return; + } + + if (baseobj && !LLAssetType::lookupCanLink(baseobj->getType())) + { + // Fail if item can be found but is of a type that can't be linked. + // Arguably should fail if the item can't be found too, but that could + // be a larger behavioral change. + llwarns << "attempt to link an unlinkable item, type = " << baseobj->getActualType() << llendl; + return; + } + + LLUUID transaction_id; + LLInventoryType::EType inv_type = LLInventoryType::IT_NONE; + if (dynamic_cast(baseobj)) + { + inv_type = LLInventoryType::IT_CATEGORY; + } + else + { + const LLViewerInventoryItem *baseitem = dynamic_cast(baseobj); + if (baseitem) + { + inv_type = baseitem->getInventoryType(); + } + } + + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_LinkInventoryItem); + msg->nextBlock(_PREHASH_AgentData); + { + msg->addUUIDFast(_PREHASH_AgentID, agent_id); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + } + msg->nextBlock(_PREHASH_InventoryBlock); + { + msg->addU32Fast(_PREHASH_CallbackID, gInventoryCallbacks.registerCB(cb)); + msg->addUUIDFast(_PREHASH_FolderID, parent_id); + msg->addUUIDFast(_PREHASH_TransactionID, transaction_id); + msg->addUUIDFast(_PREHASH_OldItemID, item_id); + msg->addS8Fast(_PREHASH_Type, (S8)asset_type); + msg->addS8Fast(_PREHASH_InvType, (S8)inv_type); + msg->addStringFast(_PREHASH_Name, new_name); + msg->addStringFast(_PREHASH_Description, new_description); + } + gAgent.sendReliableMessage(); +} + void move_inventory_item( const LLUUID& agent_id, const LLUUID& session_id, @@ -846,3 +930,140 @@ void copy_inventory_from_notecard(const LLUUID& object_id, const LLUUID& notecar } } } + + +LLAssetType::EType LLViewerInventoryItem::getType() const +{ + if (const LLViewerInventoryItem *linked_item = getLinkedItem()) + { + return linked_item->getType(); + } + if (const LLViewerInventoryCategory *linked_category = getLinkedCategory()) + { + return linked_category->getType(); + } + return LLInventoryItem::getType(); +} + +const LLUUID& LLViewerInventoryItem::getAssetUUID() const +{ + if (const LLViewerInventoryItem *linked_item = getLinkedItem()) + { + return linked_item->getAssetUUID(); + } + + return LLInventoryItem::getAssetUUID(); +} + +const std::string& LLViewerInventoryItem::getName() const +{ + if (const LLViewerInventoryItem *linked_item = getLinkedItem()) + { + return linked_item->getName(); + } + if (const LLViewerInventoryCategory *linked_category = getLinkedCategory()) + { + return linked_category->getName(); + } + + return LLInventoryItem::getName(); +} + +const LLPermissions& LLViewerInventoryItem::getPermissions() const +{ + // Use the actual permissions of the symlink, not its parent. + return LLInventoryItem::getPermissions(); +} + +const LLUUID& LLViewerInventoryItem::getCreatorUUID() const +{ + if (const LLViewerInventoryItem *linked_item = getLinkedItem()) + { + return linked_item->getCreatorUUID(); + } + + return LLInventoryItem::getCreatorUUID(); +} + +const std::string& LLViewerInventoryItem::getDescription() const +{ + if (const LLViewerInventoryItem *linked_item = getLinkedItem()) + { + return linked_item->getDescription(); + } + + return LLInventoryItem::getDescription(); +} + +const LLSaleInfo& LLViewerInventoryItem::getSaleInfo() const +{ + if (const LLViewerInventoryItem *linked_item = getLinkedItem()) + { + return linked_item->getSaleInfo(); + } + + return LLInventoryItem::getSaleInfo(); +} + +LLInventoryType::EType LLViewerInventoryItem::getInventoryType() const +{ + if (const LLViewerInventoryItem *linked_item = getLinkedItem()) + { + return linked_item->getInventoryType(); + } + + // Categories don't have types. If this item is an AT_FOLDER_LINK, + // treat it as a category. + if (getLinkedCategory()) + { + return LLInventoryType::IT_CATEGORY; + } + + return LLInventoryItem::getInventoryType(); +} + +U32 LLViewerInventoryItem::getFlags() const +{ + if (const LLViewerInventoryItem *linked_item = getLinkedItem()) + { + return linked_item->getFlags(); + } + return LLInventoryItem::getFlags(); +} + + +// This returns true if the item that this item points to +// doesn't exist in memory (i.e. LLInventoryModel). The baseitem +// might still be in the database but just not loaded yet. +bool LLViewerInventoryItem::getIsBrokenLink() const +{ + // If the item's type resolves to be a link, that means either: + // A. It wasn't able to perform indirection, i.e. the baseobj doesn't exist in memory. + // B. It's pointing to another link, which is illegal. + return LLAssetType::lookupIsLinkType(getType()); +} + +LLViewerInventoryItem *LLViewerInventoryItem::getLinkedItem() const +{ + if (mType == LLAssetType::AT_LINK) + { + LLViewerInventoryItem *linked_item = gInventory.getItem(mAssetUUID); + if (linked_item && linked_item->getIsLinkType()) + { + llwarns << "Warning: Accessing link to link" << llendl; + return NULL; + } + return linked_item; + } + return NULL; +} + +LLViewerInventoryCategory *LLViewerInventoryItem::getLinkedCategory() const +{ + if (mType == LLAssetType::AT_LINK_FOLDER) + { + LLViewerInventoryCategory *linked_category = gInventory.getCategory(mAssetUUID); + return linked_category; + } + return NULL; +} diff --git a/indra/newview/llviewerinventory.h b/indra/newview/llviewerinventory.h index 1ddf8a58f..ba3aee49a 100644 --- a/indra/newview/llviewerinventory.h +++ b/indra/newview/llviewerinventory.h @@ -37,6 +37,8 @@ #include "llframetimer.h" #include "llwearable.h" +class LLViewerInventoryCategory; + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLViewerInventoryItem // @@ -53,6 +55,16 @@ protected: ~LLViewerInventoryItem( void ); // ref counted public: + virtual LLAssetType::EType getType() const; + virtual const LLUUID& getAssetUUID() const; + virtual const std::string& getName() const; + virtual const LLPermissions& getPermissions() const; + virtual const LLUUID& getCreatorUUID() const; + virtual const std::string& getDescription() const; + virtual const LLSaleInfo& getSaleInfo() const; + virtual LLInventoryType::EType getInventoryType() const; + virtual U32 getFlags() const; + // construct a complete viewer inventory item LLViewerInventoryItem(const LLUUID& uuid, const LLUUID& parent_uuid, const LLPermissions& permissions, @@ -113,6 +125,10 @@ public: BOOL isComplete() const { return mIsComplete; } void setComplete(BOOL complete) { mIsComplete = complete; } //void updateAssetOnServer() const; +// [RLVa:KB] - Checked: 2010-09-27 (RLVa-1.1.3a) | Added: RLVa-1.1.3a + virtual bool isWearableType() const; + virtual EWearableType getWearableType() const; +// [/RLVa:KB] virtual void packMessage(LLMessageSystem* msg) const; virtual void setTransactionID(const LLTransactionID& transaction_id); @@ -125,6 +141,10 @@ public: }; LLTransactionID getTransactionID() const { return mTransactionID; } + bool getIsBrokenLink() const; // true if the baseitem this points to doesn't exist in memory. + LLViewerInventoryItem *getLinkedItem() const; + LLViewerInventoryCategory *getLinkedCategory() const; + protected: BOOL mIsComplete; LLTransactionID mTransactionID; @@ -208,7 +228,7 @@ class LLViewerJointAttachment; class RezAttachmentCallback : public LLInventoryCallback { public: - RezAttachmentCallback(LLViewerJointAttachment *attachmentp); + RezAttachmentCallback(LLViewerJointAttachment *attachmentp, bool replace = false); void fire(const LLUUID& inv_item); protected: @@ -216,6 +236,7 @@ protected: private: LLViewerJointAttachment* mAttach; + bool mReplace; }; class ActivateGestureCallback : public LLInventoryCallback @@ -272,6 +293,15 @@ void copy_inventory_item( const std::string& new_name, LLPointer cb); +void link_inventory_item( + const LLUUID& agent_id, + const LLUUID& item_id, + const LLUUID& parent_id, + const std::string& new_name, + const std::string& new_description, + const LLAssetType::EType asset_type, + LLPointer cb); + void move_inventory_item( const LLUUID& agent_id, const LLUUID& session_id, diff --git a/indra/newview/llviewerjointattachment.cpp b/indra/newview/llviewerjointattachment.cpp index 63c63e554..608be31ec 100644 --- a/indra/newview/llviewerjointattachment.cpp +++ b/indra/newview/llviewerjointattachment.cpp @@ -57,7 +57,6 @@ extern LLPipeline gPipeline; // LLViewerJointAttachment() //----------------------------------------------------------------------------- LLViewerJointAttachment::LLViewerJointAttachment() : -mAttachedObject(NULL), mVisibleInFirst(FALSE), mGroup(0), mIsHUDAttachment(FALSE), @@ -65,6 +64,7 @@ mPieSlice(-1) { mValid = FALSE; mUpdateXform = FALSE; + mAttachedObjects.clear(); } //----------------------------------------------------------------------------- @@ -103,12 +103,19 @@ U32 LLViewerJointAttachment::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_ return 0; } -void LLViewerJointAttachment::setupDrawable(LLDrawable* drawablep) +void LLViewerJointAttachment::setupDrawable(LLViewerObject *object) { - drawablep->mXform.setParent(&mXform); // LLViewerJointAttachment::lazyAttach - drawablep->makeActive(); - LLVector3 current_pos = mAttachedObject->getRenderPosition(); - LLQuaternion current_rot = mAttachedObject->getRenderRotation(); + if (!object->mDrawable) + return; + if (object->mDrawable->isActive()) + { + object->mDrawable->makeStatic(FALSE); + } + + object->mDrawable->mXform.setParent(getXform()); // LLViewerJointAttachment::lazyAttach + object->mDrawable->makeActive(); + LLVector3 current_pos = object->getRenderPosition(); + LLQuaternion current_rot = object->getRenderRotation(); LLQuaternion attachment_pt_inv_rot = ~getWorldRotation(); current_pos -= getWorldPosition(); @@ -116,21 +123,21 @@ void LLViewerJointAttachment::setupDrawable(LLDrawable* drawablep) current_rot = current_rot * attachment_pt_inv_rot; - drawablep->mXform.setPosition(current_pos); - drawablep->mXform.setRotation(current_rot); - gPipeline.markMoved(drawablep); - gPipeline.markTextured(drawablep); // face may need to change draw pool to/from POOL_HUD - drawablep->setState(LLDrawable::USE_BACKLIGHT); + object->mDrawable->mXform.setPosition(current_pos); + object->mDrawable->mXform.setRotation(current_rot); + gPipeline.markMoved(object->mDrawable); + gPipeline.markTextured(object->mDrawable); // face may need to change draw pool to/from POOL_HUD + object->mDrawable->setState(LLDrawable::USE_BACKLIGHT); if(mIsHUDAttachment) { - for (S32 face_num = 0; face_num < drawablep->getNumFaces(); face_num++) + for (S32 face_num = 0; face_num < object->mDrawable->getNumFaces(); face_num++) { - drawablep->getFace(face_num)->setState(LLFace::HUD_RENDER); + object->mDrawable->getFace(face_num)->setState(LLFace::HUD_RENDER); } } - LLViewerObject::const_child_list_t& child_list = mAttachedObject->getChildren(); + LLViewerObject::const_child_list_t& child_list = object->getChildren(); for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); iter != child_list.end(); iter++) { @@ -157,54 +164,18 @@ void LLViewerJointAttachment::setupDrawable(LLDrawable* drawablep) //----------------------------------------------------------------------------- BOOL LLViewerJointAttachment::addObject(LLViewerObject* object) { - if (mAttachedObject) - { - llwarns << "Attempted to attach object where an attachment already exists!" << llendl; - - if (mAttachedObject == object) { - llinfos << "(same object re-attached)" << llendl; - removeObject(mAttachedObject); - // Pass through anyway to let setupDrawable() - // re-connect object to the joint correctly - } - else { - llinfos << "(objects differ, removing existing object)" << llendl; - // Rather hacky, but no-one can think of something - // better to do for this case. - gObjectList.killObject(mAttachedObject); - // Proceed with new object attachment - } - } - mAttachedObject = object; - - LLUUID item_id; + object->extractAttachmentItemID(); - // Find the inventory item ID of the attached object - LLNameValue* item_id_nv = object->getNVPair("AttachItemID"); - if( item_id_nv ) + if (isObjectAttached(object)) { - const char* s = item_id_nv->getString(); - if( s ) - { - item_id.set( s ); - lldebugs << "getNVPair( AttachItemID ) = " << item_id << llendl; - } + llinfos << "(same object re-attached)" << llendl; + removeObject(object); + // Pass through anyway to let setupDrawable() + // re-connect object to the joint correctly } - mItemID = item_id; - - LLDrawable* drawablep = object->mDrawable; - - if (drawablep) - { - //if object is active, make it static - if(drawablep->isActive()) - { - drawablep->makeStatic(FALSE) ; - } - - setupDrawable(drawablep); - } + mAttachedObjects.push_back(object); + setupDrawable(object); if (mIsHUDAttachment) { @@ -234,9 +205,27 @@ BOOL LLViewerJointAttachment::addObject(LLViewerObject* object) //----------------------------------------------------------------------------- void LLViewerJointAttachment::removeObject(LLViewerObject *object) { + attachedobjs_vec_t::iterator iter; + for (iter = mAttachedObjects.begin(); + iter != mAttachedObjects.end(); + ++iter) + { + LLViewerObject *attached_object = (*iter); + if (attached_object == object) + { + break; + } + } + if (iter == mAttachedObjects.end()) + { + llwarns << "Could not find object to detach" << llendl; + return; + } + // force object visibile setAttachmentVisibility(TRUE); + mAttachedObjects.erase(iter); if (object->mDrawable.notNull()) { //if object is active, make it static @@ -299,10 +288,11 @@ void LLViewerJointAttachment::removeObject(LLViewerObject *object) } } } - - mAttachedObject = NULL; - mUpdateXform = FALSE; - mItemID.setNull(); + if (mAttachedObjects.size() == 0) + { + mUpdateXform = FALSE; + } + object->setAttachmentItemID(LLUUID::null); } //----------------------------------------------------------------------------- @@ -310,20 +300,26 @@ void LLViewerJointAttachment::removeObject(LLViewerObject *object) //----------------------------------------------------------------------------- void LLViewerJointAttachment::setAttachmentVisibility(BOOL visible) { - if (!mAttachedObject || mAttachedObject->mDrawable.isNull() || - !(mAttachedObject->mDrawable->getSpatialBridge())) - return; - - if (visible) + for (attachedobjs_vec_t::const_iterator iter = mAttachedObjects.begin(); + iter != mAttachedObjects.end(); + ++iter) { - // Hack to make attachments not visible by disabling their type mask! - // This will break if you can ever attach non-volumes! - djs 02/14/03 - mAttachedObject->mDrawable->getSpatialBridge()->mDrawableType = - mAttachedObject->isHUDAttachment() ? LLPipeline::RENDER_TYPE_HUD : LLPipeline::RENDER_TYPE_VOLUME; - } - else - { - mAttachedObject->mDrawable->getSpatialBridge()->mDrawableType = 0; + LLViewerObject *attached_obj = (*iter); + if (!attached_obj || attached_obj->mDrawable.isNull() || + !(attached_obj->mDrawable->getSpatialBridge())) + continue; + + if (visible) + { + // Hack to make attachments not visible by disabling their type mask! + // This will break if you can ever attach non-volumes! - djs 02/14/03 + attached_obj->mDrawable->getSpatialBridge()->mDrawableType = + attached_obj->isHUDAttachment() ? LLPipeline::RENDER_TYPE_HUD : LLPipeline::RENDER_TYPE_VOLUME; + } + else + { + attached_obj->mDrawable->getSpatialBridge()->mDrawableType = 0; + } } } @@ -341,14 +337,19 @@ void LLViewerJointAttachment::setOriginalPosition(LLVector3& position) //----------------------------------------------------------------------------- void LLViewerJointAttachment::clampObjectPosition() { - if (mAttachedObject) + for (attachedobjs_vec_t::const_iterator iter = mAttachedObjects.begin(); + iter != mAttachedObjects.end(); + ++iter) { - // *NOTE: object can drift when hitting maximum radius - LLVector3 attachmentPos = mAttachedObject->getPosition(); - F32 dist = attachmentPos.normVec(); - dist = llmin(dist, MAX_ATTACHMENT_DIST); - attachmentPos *= dist; - mAttachedObject->setPosition(attachmentPos); + if (LLViewerObject *attached_object = (*iter)) + { + // *NOTE: object can drift when hitting maximum radius + LLVector3 attachmentPos = attached_object->getPosition(); + F32 dist = attachmentPos.normVec(); + dist = llmin(dist, MAX_ATTACHMENT_DIST); + attachmentPos *= dist; + attached_object->setPosition(attachmentPos); + } } } @@ -357,14 +358,23 @@ void LLViewerJointAttachment::clampObjectPosition() //----------------------------------------------------------------------------- void LLViewerJointAttachment::calcLOD() { - F32 maxarea = mAttachedObject->getMaxScale() * mAttachedObject->getMidScale(); - LLViewerObject::const_child_list_t& child_list = mAttachedObject->getChildren(); - for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); - iter != child_list.end(); iter++) + F32 maxarea = 0; + for (attachedobjs_vec_t::const_iterator iter = mAttachedObjects.begin(); + iter != mAttachedObjects.end(); + ++iter) { - LLViewerObject* childp = *iter; - F32 area = childp->getMaxScale() * childp->getMidScale(); - maxarea = llmax(maxarea, area); + if (LLViewerObject *attached_object = (*iter)) + { + maxarea = llmax(maxarea,attached_object->getMaxScale() * attached_object->getMidScale()); + LLViewerObject::const_child_list_t& child_list = attached_object->getChildren(); + for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); + iter != child_list.end(); ++iter) + { + LLViewerObject* childp = *iter; + F32 area = childp->getMaxScale() * childp->getMidScale(); + maxarea = llmax(maxarea, area); + } + } } maxarea = llclamp(maxarea, .01f*.01f, 1.f); F32 avatar_area = (4.f * 4.f); // pixels for an avatar sized attachment @@ -386,3 +396,48 @@ BOOL LLViewerJointAttachment::updateLOD(F32 pixel_area, BOOL activate) return res; } + +BOOL LLViewerJointAttachment::isObjectAttached(const LLViewerObject *viewer_object) const +{ + for (attachedobjs_vec_t::const_iterator iter = mAttachedObjects.begin(); + iter != mAttachedObjects.end(); + ++iter) + { + const LLViewerObject* attached_object = (*iter); + if (attached_object == viewer_object) + { + return TRUE; + } + } + return FALSE; +} + +const LLViewerObject *LLViewerJointAttachment::getAttachedObject(const LLUUID &object_id) const +{ + for (attachedobjs_vec_t::const_iterator iter = mAttachedObjects.begin(); + iter != mAttachedObjects.end(); + ++iter) + { + const LLViewerObject* attached_object = (*iter); + if (attached_object->getAttachmentItemID() == object_id) + { + return attached_object; + } + } + return NULL; +} + +LLViewerObject *LLViewerJointAttachment::getAttachedObject(const LLUUID &object_id) +{ + for (attachedobjs_vec_t::iterator iter = mAttachedObjects.begin(); + iter != mAttachedObjects.end(); + ++iter) + { + LLViewerObject* attached_object = (*iter); + if (attached_object->getAttachmentItemID() == object_id) + { + return attached_object; + } + } + return NULL; +} diff --git a/indra/newview/llviewerjointattachment.h b/indra/newview/llviewerjointattachment.h index 4847ac7a7..f640e8ee0 100644 --- a/indra/newview/llviewerjointattachment.h +++ b/indra/newview/llviewerjointattachment.h @@ -76,15 +76,21 @@ public: void setOriginalPosition(LLVector3 &position); void setAttachmentVisibility(BOOL visible); void setIsHUDAttachment(BOOL is_hud) { mIsHUDAttachment = is_hud; } - BOOL getIsHUDAttachment() { return mIsHUDAttachment; } +// BOOL getIsHUDAttachment() { return mIsHUDAttachment; } +// [RLVa:KB] - Checked: 2010-09-26 (RLVa-1.3.0a) | Added: RLVa-1.3.0a + BOOL getIsHUDAttachment() const { return mIsHUDAttachment; } +// [/RLVa:KB] BOOL isAnimatable() { return FALSE; } - S32 getGroup() { return mGroup; } - S32 getPieSlice() { return mPieSlice; } - LLViewerObject *getObject() { return mAttachedObject; } - S32 getNumObjects() { return (mAttachedObject ? 1 : 0); } - const LLUUID& getItemID() { return mItemID; } +// S32 getGroup() { return mGroup; } +// S32 getPieSlice() { return mPieSlice; } +// S32 getNumObjects() { return mAttachedObjects.size(); } +// [RLVa:KB] - Checked: 2010-09-26 (RLVa-1.3.0a) | Added: RLVa-1.3.0a + S32 getGroup() const { return mGroup; } + S32 getPieSlice() const { return mPieSlice; } + S32 getNumObjects() const { return mAttachedObjects.size(); } +// [/RLVa:KB] // // unique methods @@ -92,21 +98,29 @@ public: BOOL addObject(LLViewerObject* object); void removeObject(LLViewerObject *object); - void setupDrawable(LLDrawable* drawable); void clampObjectPosition(); + // + // attachments operations + // + BOOL isObjectAttached(const LLViewerObject *viewer_object) const; + const LLViewerObject *getAttachedObject(const LLUUID &object_id) const; + LLViewerObject *getAttachedObject(const LLUUID &object_id); + + // list of attachments for this joint + typedef std::vector attachedobjs_vec_t; + attachedobjs_vec_t mAttachedObjects; + protected: void calcLOD(); + void setupDrawable(LLViewerObject *object); protected: - // Backlink only; don't make this an LLPointer. - LLViewerObject* mAttachedObject; BOOL mVisibleInFirst; LLVector3 mOriginalPos; S32 mGroup; BOOL mIsHUDAttachment; S32 mPieSlice; - LLUUID mItemID; // Inventory item id of the attached item (null if not in inventory) }; #endif // LL_LLVIEWERJOINTATTACHMENT_H diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 1356ea36b..37f6862e7 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -1003,7 +1003,7 @@ void init_client_menu(LLMenuGL* menu) menu->appendMenu(sub_menu); } -// [RLVa:KB] - Alternate: Snowglobe-1.2.4 | Checked: 2009-07-08 (RLVa-1.0.0e) | Modified: RLVa-0.2.1b +// [RLVa:KB] - Checked: 2009-07-08 (RLVa-1.0.0e) | Modified: RLVa-0.2.1b | OK #ifdef RLV_ADVANCED_MENU if (rlv_handler_t::isEnabled()) { @@ -1124,7 +1124,7 @@ void init_client_menu(LLMenuGL* menu) &menu_check_control, (void*)"ShowConsoleWindow")); -// [RLVa:KB] - Checked: 2009-07-08 (RLVa-1.0.0e) | Modified: RLVa-1.0.0e +// [RLVa:KB] - Checked: 2009-07-08 (RLVa-1.0.0e) | Modified: RLVa-1.0.0e | OK #ifdef RLV_ADVANCED_TOGGLE_RLVA if (gSavedSettings.controlExists(RLV_SETTING_MAIN)) menu->append(new LLMenuItemCheckGL("RestrainedLove API", &rlvToggleEnabled, NULL, &rlvGetEnabled, NULL)); @@ -1601,7 +1601,7 @@ void init_debug_baked_texture_menu(LLMenuGL* menu) menu->createJumpKeys(); } -// [RLVa:KB] - Version: 1.23.4 | Checked: 2009-11-17 (RLVa-1.1.0d) | Modified: RLVa-1.1.0d +// [RLVa:KB] - Checked: 2009-11-17 (RLVa-1.1.0d) | Modified: RLVa-1.1.0d | OK void init_debug_rlva_menu(LLMenuGL* menu) { // Debug options @@ -1610,7 +1610,6 @@ void init_debug_rlva_menu(LLMenuGL* menu) if (gSavedSettings.controlExists(RLV_SETTING_DEBUG)) pDbgMenu->append(new LLMenuItemCheckGL("Show Debug Messages", menu_toggle_control, NULL, menu_check_control, (void*)RLV_SETTING_DEBUG)); - pDbgMenu->append(new LLMenuItemCallGL("Dump Attachment Locks", RlvHandler::dumpAttachmentLocks, NULL, NULL)); pDbgMenu->appendSeparator(); if (gSavedSettings.controlExists(RLV_SETTING_ENABLELEGACYNAMING)) pDbgMenu->append(new LLMenuItemCheckGL("Enable Legacy Naming", menu_toggle_control, NULL, menu_check_control, (void*)RLV_SETTING_ENABLELEGACYNAMING)); @@ -1621,12 +1620,8 @@ void init_debug_rlva_menu(LLMenuGL* menu) menu->appendSeparator(); } - if (gSavedSettings.controlExists(RLV_SETTING_ENABLEWEAR)) - menu->append(new LLMenuItemCheckGL("Enable Default Wear", menu_toggle_control, rlvEnableWearEnabler, menu_check_control, (void*)RLV_SETTING_ENABLEWEAR)); -#ifndef RLV_WORKAROUND_REZMULTIPLEATTACH if (gSavedSettings.controlExists(RLV_SETTING_ENABLESHAREDWEAR)) - menu->append(new LLMenuItemCheckGL("Enable Shared Wear", menu_toggle_control, rlvEnableSharedWearEnabler, menu_check_control, (void*)RLV_SETTING_ENABLESHAREDWEAR)); -#endif // RLV_WORKAROUND_REZMULTIPLEATTACH + menu->append(new LLMenuItemCheckGL("Enable Shared Wear", menu_toggle_control, NULL, menu_check_control, (void*)RLV_SETTING_ENABLESHAREDWEAR)); menu->appendSeparator(); #ifdef RLV_EXTENSION_HIDELOCKED @@ -1802,9 +1797,11 @@ class LLObjectTouch : public view_listener_t LLPickInfo pick = LLToolPie::getInstance()->getPick(); -// [RLVa:KB] - Checked: 2010-01-01 (RLVa-1.1.0l) | Modified: RLVa-1.1.0l +// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Modified: RLVa-1.1.0l | OK + // NOTE: fallback code since we really shouldn't be getting an active selection if we can't touch this if ( (rlv_handler_t::isEnabled()) && (!gRlvHandler.canTouch(object, pick.mObjectOffset)) ) { + RLV_ASSERT(false); return true; } // [/RLVa:KB] @@ -1911,7 +1908,7 @@ class LLObjectOpen : public view_listener_t { bool handleEvent(LLPointer event, const LLSD& userdata) { -// [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0b) +// [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0b) | OK // TODO-RLVa: shouldn't we be checking for fartouch here as well? if (gRlvHandler.hasBehaviour(RLV_BHVR_EDIT)) { @@ -1938,11 +1935,6 @@ class LLObjectEnableOpen : public view_listener_t else new_value = root->allowOpen(); } -// [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0b) | Modified: RLVa-1.0.0b - // TODO-RLV: shouldn't we be checking for fartouch here as well? (and LLViewerObject::allowOpen() makes this redundant?) - new_value &= !gRlvHandler.hasBehaviour(RLV_BHVR_EDIT); -// [/RLVa:KB] - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); return true; } @@ -2354,10 +2346,9 @@ class LLSelfEnableRemoveAllAttachments : public view_listener_t { LLVOAvatar::attachment_map_t::iterator curiter = iter++; LLViewerJointAttachment* attachment = curiter->second; -// if (attachment->getObject()) -// [RLVa:KB] - Checked: 2009-10-10 (RLVa-1.0.5a) | Modified: RLVa-1.0.5a - if ( (attachment->getObject()) && - ((!rlv_handler_t::isEnabled()) || (!gRlvHandler.isLockedAttachment(curiter->first, RLV_LOCK_REMOVE))) ) +// if (attachment->getNumObjects() > 0) +// [RLVa:KB] - Checked: 2010-03-04 (RLVa-1.2.0a) | Added: RLVa-1.2.0a | OK + if ( (attachment->getNumObjects() > 0) && ((!rlv_handler_t::isEnabled()) || (gRlvAttachmentLocks.canDetach(attachment))) ) // [/RLVa:KB] { new_value = true; @@ -2405,7 +2396,7 @@ class LLObjectEnableMute : public view_listener_t BOOL is_linden = lastname && !LLStringUtil::compareStrings(lastname->getString(), "Linden"); BOOL is_self = avatar->isSelf(); new_value = !is_linden && !is_self; -// [RLVa:KB] - Checked: 2009-07-08 (RLVa-1.0.0e) +// [RLVa:KB] - Checked: 2009-07-08 (RLVa-1.0.0e) | OK new_value &= (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)); // [/RLVa:KB] } @@ -2428,7 +2419,7 @@ class LLObjectMute : public view_listener_t LLVOAvatar* avatar = find_avatar_from_object(object); if (avatar) { -// [RLVa:KB] - Checked: 2009-07-08 (RLVa-1.0.0e) | Added: RLVa-1.0.0e +// [RLVa:KB] - Checked: 2009-07-08 (RLVa-1.0.0e) | Added: RLVa-1.0.0e | OK if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) { return true; // Fallback code [see LLObjectEnableMute::handleEvent()] @@ -2767,10 +2758,12 @@ class LLAvatarAnims : public view_listener_t bool handle_go_to() { // [RLVa:KB] - Checked: 2009-10-10 (RLVa-1.0.5a) | Modified: RLVa-1.0.5a +/* if ( (rlv_handler_t::isEnabled()) && (gAgent.forwardGrabbed()) && (gRlvHandler.hasLockedAttachment(RLV_LOCK_REMOVE)) ) { return true; } +*/ // [/RLVa:KB] // JAMESDEBUG try simulator autopilot @@ -2930,7 +2923,7 @@ class LLAvatarFreeze : public view_listener_t { LLSD args; // args["AVATAR_NAME"] = fullname; -// [RLVa:KB] - Version: 1.23.4 | Checked: 2009-07-08 (RLVa-1.0.0e) +// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.0.0e | OK args["AVATAR_NAME"] = (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) ? fullname : RlvStrings::getAnonym(fullname); // [/RLVa:KB] LLNotifications::instance().add("FreezeAvatarFullname", @@ -3061,12 +3054,6 @@ class LLAvatarEject : public view_listener_t LLSD payload; payload["avatar_id"] = avatar->getID(); std::string fullname = avatar->getFullname(); -// [RLVa:KB] - Version: 1.23.4 | Checked: 2009-07-08 (RLVa-1.0.0e) - if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (!fullname.empty()) ) - { - fullname = RlvStrings::getAnonym(fullname); - } -// [/RLVa:KB] const LLVector3d& pos = avatar->getPositionGlobal(); LLParcel* parcel = LLViewerParcelMgr::getInstance()->selectParcelAt(pos)->getParcel(); @@ -3077,7 +3064,10 @@ class LLAvatarEject : public view_listener_t if (!fullname.empty()) { LLSD args; - args["AVATAR_NAME"] = fullname; +// args["AVATAR_NAME"] = fullname; +// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.0.0e | OK + args["AVATAR_NAME"] = (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) ? fullname : RlvStrings::getAnonym(fullname); +// [/RLVa:KB] LLNotifications::instance().add("EjectAvatarFullname", args, payload, @@ -3097,7 +3087,10 @@ class LLAvatarEject : public view_listener_t if (!fullname.empty()) { LLSD args; - args["AVATAR_NAME"] = fullname; +// args["AVATAR_NAME"] = fullname; +// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.0.0e | OK + args["AVATAR_NAME"] = (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) ? fullname : RlvStrings::getAnonym(fullname); +// [/RLVa:KB] LLNotifications::instance().add("EjectAvatarFullnameNoBan", args, payload, @@ -3181,16 +3174,12 @@ class LLAvatarGiveCard : public view_listener_t { bool handleEvent(LLPointer event, const LLSD& userdata) { -// [RLVa:KB] - Checked: 2009-07-08 (RLVa-1.0.0e) - if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) - { - return true; - } -// [/RLVa:KB] - llinfos << "handle_give_card()" << llendl; LLViewerObject* dest = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if(dest && dest->isAvatar()) +// if(dest && dest->isAvatar()) +// [RLVa:KB] - Checked: 2010-06-04 (RLVa-1.2.0d) | Modified: RLVa-1.2.0d | OK + if ( (dest && dest->isAvatar()) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) ) +// [/RLVa:KB] { bool found_name = false; LLSD args; @@ -3449,7 +3438,7 @@ class LLSelfSitOrStand : public view_listener_t { if (gAgent.getAvatarObject() && gAgent.getAvatarObject()->mIsSitting) { -// [RLVa:KB] - Alternate: Snowglobe-1.3.X | Checked: 2009-12-29 (RLVa-1.1.0k) | Added: RLVa-1.1.0k +// [RLVa:KB] - Alternate: Snowglobe-1.3.X | Checked: 2009-12-29 (RLVa-1.1.0k) | Added: RLVa-1.1.0k | OK if (gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) return true; // [/RLVa:KB] @@ -3457,7 +3446,7 @@ class LLSelfSitOrStand : public view_listener_t } else { -// [RLVa:KB] - Alternate: Snowglobe-1.3.X | Checked: 2009-12-29 (RLVa-1.1.0k) | Added: RLVa-1.1.0k +// [RLVa:KB] - Alternate: Snowglobe-1.3.X | Checked: 2009-12-29 (RLVa-1.1.0k) | Added: RLVa-1.1.0k | OK if (gRlvHandler.hasBehaviour(RLV_BHVR_SIT)) return true; // [/RLVa:KB] @@ -3491,20 +3480,20 @@ class LLSelfEnableSitOrStand : public view_listener_t if (gAgent.getAvatarObject() && gAgent.getAvatarObject()->mIsSitting) { -// [RLVa:KB] - Alternate: Snowglobe-1.3.X | Checked: 2009-12-29 (RLVa-1.1.0k) | Added: RLVa-1.1.0k +// [RLVa:KB] - Alternate: Snowglobe-1.3.X | Checked: 2009-12-29 (RLVa-1.1.0k) | Added: RLVa-1.1.0k | OK new_value &= (!gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)); // [/RLVa:KB] label = stand_text; } else { -// [RLVa:KB] - Alternate: Snowglobe-1.3.X | Checked: 2009-12-29 (RLVa-1.1.0k) | Added: RLVa-1.1.0k +// [RLVa:KB] - Alternate: Snowglobe-1.3.X | Checked: 2009-12-29 (RLVa-1.1.0k) | Added: RLVa-1.1.0k | OK new_value &= (!gRlvHandler.hasBehaviour(RLV_BHVR_SIT)); // [/RLVa:KB] label = sit_text; } -// [RLVa:KB] - Alternate: Snowglobe-1.3.X | Checked: 2009-12-29 (RLVa-1.1.0k) | Added: RLVa-1.1.0k +// [RLVa:KB] - Alternate: Snowglobe-1.3.X | Checked: 2009-12-29 (RLVa-1.1.0k) | Added: RLVa-1.1.0k | OK gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); // [/RLVa:KB] gMenuHolder->childSetText("Self Sit", label); @@ -3861,7 +3850,7 @@ class LLAvatarEnableAddFriend : public view_listener_t LLVOAvatar* avatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); bool new_value = avatar && !is_agent_friend(avatar->getID()); -// [RLVa:KB] - Checked: 2009-07-08 (RLVa-1.0.0e) +// [RLVa:KB] - Checked: 2009-07-08 (RLVa-1.0.0e) | OK new_value &= (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)); // [/RLVa:KB] @@ -3924,7 +3913,7 @@ bool handle_sit_or_stand() return true; } -// [RLVa:KB] - Checked: 2009-12-22 (RLVa-1.1.0k) | Modified: RLVa-1.1.0j +// [RLVa:KB] - Checked: 2009-12-22 (RLVa-1.1.0k) | Modified: RLVa-1.1.0j | OK // Block if we can't sit on the selected object (also handles sitting and prevented from standing up) if ( (rlv_handler_t::isEnabled()) && (!gRlvHandler.canSit(object, pick.mObjectOffset)) ) { @@ -3942,6 +3931,19 @@ bool handle_sit_or_stand() if (object && object->getPCode() == LL_PCODE_VOLUME) { +// [RLVa:KB] - Checked: 2010-08-29 (RLVa-1.1.3b) | Added: RLVa-1.2.1c | OK + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_STANDTP)) && (gAgent.getAvatarObject()) ) + { + if (gAgent.getAvatarObject()->mIsSitting) + { + if (gRlvHandler.canStand()) + gAgent.setControlFlags(AGENT_CONTROL_STAND_UP); + return true; + } + gRlvHandler.setSitSource(gAgent.getPositionGlobal()); + } +// [/RLVa:KB] + // gReSitTargetID = object->mID; gReSitOffset = pick.mObjectOffset; @@ -3983,8 +3985,8 @@ class LLLandSit : public view_listener_t { bool handleEvent(LLPointer event, const LLSD& userdata) { -// [RLVa:KB] - Checked: 2010-03-31 (RLVa-1.1.1a) | Modified: RLVa-1.2.0c - if ( (rlv_handler_t::isEnabled()) && ((gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SIT))) ) +// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.2.1f | OK + if ( (rlv_handler_t::isEnabled()) && ((!gRlvHandler.canStand()) || (gRlvHandler.hasBehaviour(RLV_BHVR_SIT))) ) { return true; } @@ -4654,7 +4656,7 @@ class LLToolsTakeCopy : public view_listener_t bool handleEvent(LLPointer event, const LLSD& userdata) { if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return true; -// [RLVa:KB] - Checked: 2009-07-05 (RLVa-1.0.0b) | Modified: RLVa-1.0.0b +// [RLVa:KB] - Checked: 2009-07-05 (RLVa-1.0.0b) | Modified: RLVa-1.0.0b | OK // NOTE: we need to handle "Take Copy" because it will force a sim-side unsit if we're sitting on the selection, // but we do want to allow "Take Copy" under @rez=n so that's why we explicitly check for @unsit=n here if ( (gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) && (!rlvCanDeleteOrReturn()) ) return true; @@ -4674,7 +4676,7 @@ class LLObjectReturn : public view_listener_t bool handleEvent(LLPointer event, const LLSD& userdata) { if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return true; -// [RLVa:KB] - Version: 1.23.4 | Checked: 2009-07-05 (RLVa-1.0.0b) +// [RLVa:KB] - Checked: 2010-03-24 (RLVa-1.2.0e) | Modified: RLVa-1.0.0b | OK if ( (rlv_handler_t::isEnabled()) && (!rlvCanDeleteOrReturn()) ) return true; // [/RLVa:KB] @@ -4744,14 +4746,9 @@ class LLObjectEnableReturn : public view_listener_t } } #endif - -// [RLVa:KB] - Checked: 2009-07-05 (RLVa-1.0.0b) - if ( (new_value) && (rlv_handler_t::isEnabled()) ) - { - new_value = rlvCanDeleteOrReturn(); - } +// [RLVa:KB] - Checked: 2010-03-24 (RLVa-1.2.0e) | Modified: RLVa-1.0.0b | OK + new_value &= (!rlv_handler_t::isEnabled()) || (rlvCanDeleteOrReturn()); // [/RLVa:KB] - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); return true; } @@ -4768,18 +4765,14 @@ void handle_take() { // we want to use the folder this was derezzed from if it's // available. Otherwise, derez to the normal place. - if(LLSelectMgr::getInstance()->getSelection()->isEmpty()) +// if(LLSelectMgr::getInstance()->getSelection()->isEmpty()) +// [RLVa:KB] - Checked: 2010-03-24 (RLVa-1.2.0e) | Modified: RLVa-1.0.0b | OK + if ( (LLSelectMgr::getInstance()->getSelection()->isEmpty()) || ((rlv_handler_t::isEnabled()) && (!rlvCanDeleteOrReturn())) ) +// [/RLVa:KB] { return; } -// [RLVa:KB] - Checked: 2009-07-05 (RLVa-1.0.0b) - if ( (rlv_handler_t::isEnabled()) && (!rlvCanDeleteOrReturn()) ) - { - return; - } -// [/RLVa:KB] - BOOL you_own_everything = TRUE; BOOL locked_but_takeable_object = FALSE; LLUUID category_id; @@ -4894,17 +4887,13 @@ bool confirm_take(const LLSD& notification, const LLSD& response) // one item selected can be copied to inventory. BOOL enable_take() { - if (sitting_on_selection()) - { - return FALSE; - } - -// [RLVa:KB] - Checked: 2009-07-05 (RLVa-1.0.0b) - if ( (rlv_handler_t::isEnabled()) && (!rlvCanDeleteOrReturn()) ) - { - return FALSE; - } +// if (sitting_on_selection()) +// [RLVa:KB] - Checked: 2010-03-24 (RLVa-1.2.0e) | Modified: RLVa-1.0.0b | OK + if ( (sitting_on_selection()) || ((rlv_handler_t::isEnabled()) && (!rlvCanDeleteOrReturn())) ) // [/RLVa:KB] + { + return FALSE; + } for (LLObjectSelection::valid_root_iterator iter = LLSelectMgr::getInstance()->getSelection()->valid_root_begin(); iter != LLSelectMgr::getInstance()->getSelection()->valid_root_end(); iter++) @@ -5404,14 +5393,13 @@ class LLToolsEnableUnlink : public view_listener_t bool new_value = LLSelectMgr::getInstance()->selectGetAllRootsValid() && LLSelectMgr::getInstance()->getSelection()->getFirstEditableObject() && !LLSelectMgr::getInstance()->getSelection()->getFirstEditableObject()->isAttachment(); -// [RLVa:KB] - Checked: 2009-07-10 (RLVa-1.0.0g) | Modified: RLVa-0.2.0g - if ( (new_value) && (gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) && - (gAgent.getAvatarObject()) && (gAgent.getAvatarObject()->mIsSitting) ) +// [RLVa:KB] - Checked: 2010-04-01 (RLVa-1.1.3b) | Modified: RLVa-0.2.0g | OK + if ( (new_value) && (!gRlvHandler.canStand()) ) { - // Allow if the avie isn't sitting on any of the selected objects + // Allow only if the avie isn't sitting on any of the selected objects LLObjectSelectionHandle handleSel = LLSelectMgr::getInstance()->getSelection(); - RlvSelectIsSittingOn func(gAgent.getAvatarObject()->getRoot()); - if (handleSel->getFirstRootNode(&func, TRUE)) + RlvSelectIsSittingOn f(gAgent.getAvatarObject()->getRoot()); + if (handleSel->getFirstRootNode(&f, TRUE) != NULL) new_value = false; } // [/RLVa:KB] @@ -5424,13 +5412,13 @@ class LLToolsUnlink : public view_listener_t { bool handleEvent(LLPointer event, const LLSD& userdata) { -// [RLVa:KB] - Checked: 2009-07-10 (RLVa-1.0.0g) | Modified: RLVa-0.2.0g - if ( (gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) && (gAgent.getAvatarObject()) && (gAgent.getAvatarObject()->mIsSitting) ) +// [RLVa:KB] - Checked: 2010-04-01 (RLVa-1.1.3b) | Modified: RLVa-0.2.0g | OK + if ( (rlv_handler_t::isEnabled()) && (!gRlvHandler.canStand()) ) { - // Allow if the avie isn't sitting on any of the selected objects - LLObjectSelectionHandle handleSel = LLSelectMgr::getInstance()->getSelection(); - RlvSelectIsSittingOn func(gAgent.getAvatarObject()->getRoot()); - if (handleSel->getFirstRootNode(&func, TRUE)) + // Allow only if the avie isn't sitting on any of the selected objects + LLObjectSelectionHandle hSel = LLSelectMgr::getInstance()->getSelection(); + RlvSelectIsSittingOn f(gAgent.getAvatarObject()->getRoot()); + if ( (hSel.notNull()) && (hSel->getFirstRootNode(&f, TRUE)) ) return true; } // [/RLVa:KB] @@ -5454,11 +5442,9 @@ class LLToolsReleaseKeys : public view_listener_t { bool handleEvent(LLPointer event, const LLSD& userdata) { -// [RLVa:KB] - Checked: 2009-10-10 (RLVa-1.0.5a) | Modified: RLVa-1.0.5a - if ( (rlv_handler_t::isEnabled()) && (gRlvHandler.hasLockedAttachment(RLV_LOCK_REMOVE)) ) - { +// [RLVa:KB] - Checked: 2010-04-19 (RLVa-1.2.0f) | Modified: RLVa-1.0.5a | OK + if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_REMOVE)) ) return true; - } // [/RLVa:KB] gAgent.forceReleaseControls(); @@ -5471,9 +5457,9 @@ class LLToolsEnableReleaseKeys : public view_listener_t { bool handleEvent(LLPointer event, const LLSD& userdata) { -// [RLVa:KB] - Checked: 2009-10-10 (RLVa-1.0.5a) | Modified: RLVa-1.0.5a +// [RLVa:KB] - Checked: 2010-04-19 (RLVa-1.2.0f) | Modified: RLVa-1.0.5a | OK gMenuHolder->findControl(userdata["control"].asString())->setValue( - gAgent.anyControlGrabbed() && ( (!rlv_handler_t::isEnabled()) || (!gRlvHandler.hasLockedAttachment(RLV_LOCK_REMOVE) ) ) ); + gAgent.anyControlGrabbed() && ((!rlv_handler_t::isEnabled()) || (!gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_REMOVE))) ); // [/RLVa:KB] //gMenuHolder->findControl(userdata["control"].asString())->setValue( gAgent.anyControlGrabbed() ); return true; @@ -6075,12 +6061,13 @@ class LLWorldCreateLandmark : public view_listener_t { bool handleEvent(LLPointer event, const LLSD& userdata) { -// [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0a) +// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Added: RLVa-1.0.0a | OK if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) { return true; } // [/RLVa:KB] + LLViewerRegion* agent_region = gAgent.getRegion(); if(!agent_region) { @@ -6181,7 +6168,7 @@ class LLAvatarInviteToGroup : public view_listener_t { bool handleEvent(LLPointer event, const LLSD& userdata) { -// [RLVa:KB] - Checked: 2009-07-08 (RLVa-1.0.0e) +// [RLVa:KB] - Checked: 2009-07-08 (RLVa-1.0.0e) | OK if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) { return true; @@ -6201,7 +6188,7 @@ class LLAvatarAddFriend : public view_listener_t { bool handleEvent(LLPointer event, const LLSD& userdata) { -// [RLVa:KB] - Checked: 2009-07-08 (RLVa-1.0.0e) +// [RLVa:KB] - Checked: 2009-07-08 (RLVa-1.0.0e) | OK if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) { return true; // Fallback code [see LLAvatarEnableAddFriend::handleEvent()] @@ -6924,13 +6911,12 @@ private: if (index > 0) attachment_point = get_if_there(gAgent.getAvatarObject()->mAttachmentPoints, index, (LLViewerJointAttachment*)NULL); -// [RLVa:KB] - Checked: 2009-10-10 (RLVa-1.0.5a) | Modified: RLVa-1.0.5a +// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.2.1f | OK + // RELEASE-RLVa: [SL-2.2.0] If 'index != 0' then the object will be "add attached" [see LLSelectMgr::sendAttach()] if ( (rlv_handler_t::isEnabled()) && - ( ((index == 0) && (gRlvHandler.hasLockedAttachment(RLV_LOCK_ANY))) || // Can't wear on default attach point - ((index > 0) && // or replace a locked attachment - ((gRlvHandler.isLockedAttachment(attachment_point->getObject(), RLV_LOCK_REMOVE)) || - (gRlvHandler.isLockedAttachment(attachment_point, RLV_LOCK_ADD)) ) ) || // or wear on a non-attachable attach point - (gRlvHandler.hasBehaviour(RLV_BHVR_REZ)) ) ) // Attach on rezzed object == "Take" + ( ((!index) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY))) || // Can't wear on default + ((index) && ((RLV_WEAR_ADD & gRlvAttachmentLocks.canAttach(attachment_point)) == 0)) || // or non-attachable attachpt + (gRlvHandler.hasBehaviour(RLV_BHVR_REZ)) ) ) // Attach on object == "Take" { setObjectSelection(NULL); // Clear the selection or it'll get stuck return true; @@ -7044,18 +7030,18 @@ class LLAttachmentDrop : public view_listener_t return true; } -// [RLVa:KB] - Checked: 2009-10-10 (RLVa-1.0.5a) | Modified: RLVa-1.0.5a - if (rlv_handler_t::isEnabled()) +// [RLVa:KB] - Checked: 2010-03-15 (RLVa-1.2.0e) | Modified: RLVa-1.0.5 | OK + if (rlv_handler_t::isEnabled()) { - if (gRlvHandler.hasLockedAttachment(RLV_LOCK_REMOVE)) + if (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_REMOVE)) { // NOTE: copy/paste of the code in enable_detach() - LLObjectSelectionHandle hSelection = LLSelectMgr::getInstance()->getSelection(); - RlvSelectHasLockedAttach functor(RLV_LOCK_REMOVE); - if ( (hSelection->isAttachment()) && (hSelection->getFirstRootNode(&functor, FALSE)) ) + LLObjectSelectionHandle hSelect = LLSelectMgr::getInstance()->getSelection(); + RlvSelectHasLockedAttach f; + if ( (hSelect->isAttachment()) && (hSelect->getFirstRootNode(&f, FALSE) != NULL) ) return true; } - else if (gRlvHandler.hasBehaviour(RLV_BHVR_REZ)) + if (gRlvHandler.hasBehaviour(RLV_BHVR_REZ)) { return true; } @@ -7074,42 +7060,53 @@ class LLAttachmentDrop : public view_listener_t // called from avatar pie menu void handle_detach_from_avatar(void* user_data) { - LLViewerJointAttachment *attachment = (LLViewerJointAttachment *)user_data; + const LLViewerJointAttachment *attachment = (LLViewerJointAttachment*)user_data; - LLViewerObject* attached_object = attachment->getObject(); - - if (attached_object) - { -// [RLVa:KB] - Checked: 2009-10-10 (RLVa-1.0.5a) | Modified: RLVa-1.0.5a - if ( (rlv_handler_t::isEnabled()) && (gRlvHandler.isLockedAttachment(attached_object, RLV_LOCK_REMOVE)) ) - { - return; - } +// if (attachment->getNumObjects() > 0) +// [RLVa:KB] - Checked: 2010-03-04 (RLVa-1.2.0a) | Added: RLVa-1.2.0a + if ( (attachment->getNumObjects() > 0) && ((!rlv_handler_t::isEnabled()) || (gRlvAttachmentLocks.canDetach(attachment))) ) // [/RLVa:KB] - + { gMessageSystem->newMessage("ObjectDetach"); gMessageSystem->nextBlockFast(_PREHASH_AgentData); gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - - gMessageSystem->nextBlockFast(_PREHASH_ObjectData); - gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, attached_object->getLocalID()); + + for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator iter = attachment->mAttachedObjects.begin(); + iter != attachment->mAttachedObjects.end(); + iter++) + { + LLViewerObject *attached_object = (*iter); +// [RLVa:KB] - Checked: 2010-03-04 (RLVa-1.2.0a) | Added: RLVa-1.2.0a + if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.isLockedAttachment(attached_object)) ) + continue; +// [/RLVa:KB] + gMessageSystem->nextBlockFast(_PREHASH_ObjectData); + gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, attached_object->getLocalID()); + } gMessageSystem->sendReliable( gAgent.getRegionHost() ); } } void attach_label(std::string& label, void* user_data) { - LLViewerJointAttachment* attachmentp = (LLViewerJointAttachment*)user_data; - if (attachmentp) + LLViewerJointAttachment *attachment = (LLViewerJointAttachment*)user_data; + if (attachment) { - label = attachmentp->getName(); - if (attachmentp->getObject()) + label = attachment->getName(); + for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) { - LLViewerInventoryItem* itemp = gInventory.getItem(attachmentp->getItemID()); - if (itemp) + const LLViewerObject* attached_object = (*attachment_iter); + if (attached_object) { - label += std::string(" (") + itemp->getName() + std::string(")"); + LLViewerInventoryItem* itemp = gInventory.getItem(attached_object->getAttachmentItemID()); + if (itemp) + { + label += std::string(" (") + itemp->getName() + std::string(")"); + break; + } } } } @@ -7117,16 +7114,23 @@ void attach_label(std::string& label, void* user_data) void detach_label(std::string& label, void* user_data) { - LLViewerJointAttachment* attachmentp = (LLViewerJointAttachment*)user_data; - if (attachmentp) + LLViewerJointAttachment *attachment = (LLViewerJointAttachment*)user_data; + if (attachment) { - label = attachmentp->getName(); - if (attachmentp->getObject()) + label = attachment->getName(); + for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) { - LLViewerInventoryItem* itemp = gInventory.getItem(attachmentp->getItemID()); - if (itemp) + const LLViewerObject* attached_object = (*attachment_iter); + if (attached_object) { - label += std::string(" (") + itemp->getName() + std::string(")"); + LLViewerInventoryItem* itemp = gInventory.getItem(attached_object->getAttachmentItemID()); + if (itemp) + { + label += std::string(" (") + itemp->getName() + std::string(")"); + break; + } } } } @@ -7169,14 +7173,14 @@ class LLAttachmentDetach : public view_listener_t return true; } -// [RLVa:KB] - Checked: 2009-10-10 (RLVa-1.0.5) | Modified: RLVa-1.0.5 +// [RLVa:KB] - Checked: 2010-03-15 (RLVa-1.2.0a) | Modified: RLVa-1.0.5 | OK // NOTE: copy/paste of the code in enable_detach() - if ( (rlv_handler_t::isEnabled()) && (gRlvHandler.hasLockedAttachment(RLV_LOCK_REMOVE)) ) + if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_REMOVE)) ) { LLObjectSelectionHandle hSelect = LLSelectMgr::getInstance()->getSelection(); - RlvSelectHasLockedAttach functor(RLV_LOCK_REMOVE); - if ( (hSelect->isAttachment()) && (hSelect->getFirstRootNode(&functor, FALSE)) ) - return FALSE; + RlvSelectHasLockedAttach f; + if ( (hSelect->isAttachment()) && (hSelect->getFirstRootNode(&f, FALSE) != NULL) ) + return true; } // [/RLVa:KB] @@ -7240,27 +7244,31 @@ class LLAttachmentEnableDrop : public view_listener_t if ( attachment_pt ) { - // make sure item is in your inventory (it could be a delayed attach message being sent from the sim) - // so check to see if the item is in the inventory already - item = gInventory.getItem(attachment_pt->getItemID()); - - if ( !item ) + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment_pt->mAttachedObjects.begin(); + attachment_iter != attachment_pt->mAttachedObjects.end(); + ++attachment_iter) { - // Item does not exist, make an observer to enable the pie menu - // when the item finishes fetching worst case scenario - // if a fetch is already out there (being sent from a slow sim) - // we refetch and there are 2 fetches - LLWornItemFetchedObserver* wornItemFetched = new LLWornItemFetchedObserver(); - LLInventoryFetchObserver::item_ref_t items; //add item to the inventory item to be fetched + // make sure item is in your inventory (it could be a delayed attach message being sent from the sim) + // so check to see if the item is in the inventory already + item = gInventory.getItem((*attachment_iter)->getAttachmentItemID()); + if (!item) + { + // Item does not exist, make an observer to enable the pie menu + // when the item finishes fetching worst case scenario + // if a fetch is already out there (being sent from a slow sim) + // we refetch and there are 2 fetches + LLWornItemFetchedObserver* wornItemFetched = new LLWornItemFetchedObserver(); + LLInventoryFetchObserver::item_ref_t items; //add item to the inventory item to be fetched - items.push_back(attachment_pt->getItemID()); - - wornItemFetched->fetchItems(items); - gInventory.addObserver(wornItemFetched); + items.push_back((*attachment_iter)->getAttachmentItemID()); + + wornItemFetched->fetchItems(items); + gInventory.addObserver(wornItemFetched); + } } } } - + //now check to make sure that the item is actually in the inventory before we enable dropping it // bool new_value = enable_detach(NULL) && can_build && item; // [RLVa:KB] - Checked: 2009-07-05 (RLVa-1.0.0b) @@ -7285,17 +7293,17 @@ BOOL enable_detach(void*) // ...if it's you, good to detach if (avatar->getID() == gAgent.getID()) { -// [RLVa:KB] - Checked: 2009-10-10 (RLVa-1.0.5) | Modified: RLVa-1.0.5 +// [RLVa:KB] - Checked: 2010-03-15 (RLVa-1.2.0a) | Modified: RLVa-1.0.5 | OK // NOTE: this code is reused as-is in LLAttachmentDetach::handleEvent() and LLAttachmentDrop::handleEvent() // so any changes here should be reflected there as well - // RELEASE-RLVa: LLSelectMgr::sendDetach() and LLSelectMgr::sendDropAttachment() call sendListToRegions with - // SEND_ONLY_ROOTS so we only need to examine the roots which saves us time - if ( (rlv_handler_t::isEnabled()) && (gRlvHandler.hasLockedAttachment(RLV_LOCK_REMOVE)) ) + // RELEASE-RLVa: [SL-2.2.0] LLSelectMgr::sendDetach() and LLSelectMgr::sendDropAttachment() call sendListToRegions with + // SEND_ONLY_ROOTS so we only need to examine the roots which saves us time + if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_REMOVE)) ) { LLObjectSelectionHandle hSelect = LLSelectMgr::getInstance()->getSelection(); - RlvSelectHasLockedAttach functor(RLV_LOCK_REMOVE); - if ( (hSelect->isAttachment()) && (hSelect->getFirstRootNode(&functor, FALSE)) ) + RlvSelectHasLockedAttach f; + if ( (hSelect->isAttachment()) && (hSelect->getFirstRootNode(&f, FALSE) != NULL) ) return FALSE; } // [/RLVa:KB] @@ -7321,7 +7329,7 @@ class LLAttachmentEnableDetach : public view_listener_t // Used to tell if the selected object can be attached to your avatar. BOOL object_selected_and_point_valid(void *user_data) { -// [RLVa:KB] - Checked: 2009-10-10 (RLVa-1.0.5) | Modified: RLVa-1.0.5 +// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.2.1f | OK if (rlv_handler_t::isEnabled()) { // RELEASE-RLVa: look at the caller graph for this function on every new release @@ -7330,12 +7338,10 @@ BOOL object_selected_and_point_valid(void *user_data) // - LLObjectEnableWear::handleEvent() => Rezzed prim / right-click / "Wear" [user_data == NULL => see above] // - enabler set up in LLVOAvatar::buildCharacter() => Rezzed prim / right-click / "Attach >" [user_data == pAttachPt] // - enabler set up in LLVOAvatar::buildCharacter() => Rezzed prim / Edit menu / "Attach Object" [user_data == pAttachPt] - LLViewerJointAttachment* pAttachPt = (LLViewerJointAttachment*)user_data; - if ( ( (!pAttachPt) && (gRlvHandler.hasLockedAttachment(RLV_LOCK_ANY)) ) || // Don't allow attach to default attach point - ( (pAttachPt) && // Don't allow replacing of a locked attachment - ( (gRlvHandler.isLockedAttachment(pAttachPt->getObject(), RLV_LOCK_REMOVE)) || - (gRlvHandler.isLockedAttachment(pAttachPt, RLV_LOCK_ADD)) ) ) || // or wear on a non-attachable attach point - (gRlvHandler.hasBehaviour(RLV_BHVR_REZ)) ) // Attaching a rezzed object == "Take" + const LLViewerJointAttachment* pAttachPt = (const LLViewerJointAttachment*)user_data; + if ( ((!pAttachPt) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY))) || // Can't wear on default attach point + ((pAttachPt) && ((RLV_WEAR_ADD & gRlvAttachmentLocks.canAttach(pAttachPt)) == 0)) || // or non-attachable attach point + (gRlvHandler.hasBehaviour(RLV_BHVR_REZ)) ) // Attach on object == "Take" { return FALSE; } @@ -7413,13 +7419,13 @@ BOOL object_attached(void *user_data) { LLViewerJointAttachment *attachment = (LLViewerJointAttachment *)user_data; -// [RLVa:KB] - Checked: 2009-07-06 (RLVa-1.0.0c) +// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.1.3b) | Modified: RLVa-1.1.3b return ( - (attachment->getObject() != NULL) && - ( (!rlv_handler_t::isEnabled()) || (!gRlvHandler.isLockedAttachment(attachment->getObject(), RLV_LOCK_REMOVE)) ) + (attachment->getNumObjects() > 0) && + ( (!rlv_handler_t::isEnabled()) || (gRlvAttachmentLocks.canDetach(attachment)) ) ); // [/RLVa:KB] -// return attachment->getObject() != NULL; +// return attachment->getNumObjects() > 0; } class LLAvatarSendIM : public view_listener_t @@ -7427,7 +7433,7 @@ class LLAvatarSendIM : public view_listener_t bool handleEvent(LLPointer event, const LLSD& userdata) { LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); -// [RLVa:KB] - Checked: 2009-07-08 (RLVa-1.0.0e) +// [RLVa:KB] - Checked: 2009-07-08 (RLVa-1.0.0e) | OK if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) { return true; @@ -7558,13 +7564,13 @@ class LLToolsSelectedScriptAction : public view_listener_t { bool handleEvent(LLPointer event, const LLSD& userdata) { -// [RLVa:KB] - Checked: 2009-10-10 (RLVa-1.0.5a) | Modified: RLVa-1.0.5a +// [RLVa:KB] - Checked: 2010-04-19 (RLVa-1.2.0f) | Modified: RLVa-1.0.5a | OK // We'll allow resetting the scripts of objects on a non-attachable attach point since they wouldn't be able to circumvent anything - if ( (rlv_handler_t::isEnabled()) && (gRlvHandler.hasLockedAttachment(RLV_LOCK_REMOVE)) ) + if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_REMOVE)) ) { - LLObjectSelectionHandle hSelection = LLSelectMgr::getInstance()->getSelection(); - RlvSelectHasLockedAttach functor(RLV_LOCK_REMOVE); - if ( (hSelection->isAttachment()) && (hSelection->getFirstNode(&functor)) ) + LLObjectSelectionHandle hSel = LLSelectMgr::getInstance()->getSelection(); + RlvSelectHasLockedAttach f; + if ( (hSel->isAttachment()) && (hSel->getFirstNode(&f) != NULL) ) return true; } // [/RLVa:KB] @@ -7670,10 +7676,10 @@ void handle_dump_image_list(void*) void handle_test_male(void*) { -// [RLVa:KB] - Checked: 2009-10-10 (RLVa-1.0.5a) | Modified: RLVa-1.0.5a - if ( (rlv_handler_t::isEnabled()) && - ( (gRlvHandler.hasLockedAttachment(RLV_LOCK_ANY)) || - (gRlvHandler.hasBehaviour(RLV_BHVR_ADDOUTFIT)) || (gRlvHandler.hasBehaviour(RLV_BHVR_REMOUTFIT)) ) ) +// [RLVa:KB] - Checked: 2010-03-19 (RLVa-1.2.0c) | Modified: RLVa-1.2.0a | OK + // TODO-RLVa: [RLVa-1.2.1] Is there any reason to still block this? + if ( (rlv_handler_t::isEnabled()) && + ((gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) || (gRlvWearableLocks.hasLockedWearableType(RLV_LOCK_ANY))) ) { return; } @@ -7685,10 +7691,10 @@ void handle_test_male(void*) void handle_test_female(void*) { -// [RLVa:KB] - Checked: 2009-10-10 (RLVa-1.0.5a) | Modified: RLVa-1.0.5a - if ( (rlv_handler_t::isEnabled()) && - ( (gRlvHandler.hasLockedAttachment(RLV_LOCK_ANY)) || - (gRlvHandler.hasBehaviour(RLV_BHVR_ADDOUTFIT)) || (gRlvHandler.hasBehaviour(RLV_BHVR_REMOUTFIT)) ) ) +// [RLVa:KB] - Checked: 2010-03-19 (RLVa-1.2.0c) | Modified: RLVa-1.2.0a | OK + // TODO-RLVa: [RLVa-1.2.1] Is there any reason to still block this? + if ( (rlv_handler_t::isEnabled()) && + ((gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) || (gRlvWearableLocks.hasLockedWearableType(RLV_LOCK_ANY))) ) { return; } @@ -7722,17 +7728,23 @@ void handle_dump_attachments(void*) LLVOAvatar::attachment_map_t::iterator curiter = iter++; LLViewerJointAttachment* attachment = curiter->second; S32 key = curiter->first; - BOOL visible = (attachment->getObject() != NULL && - attachment->getObject()->mDrawable.notNull() && - !attachment->getObject()->mDrawable->isRenderType(0)); - LLVector3 pos; - if (visible) pos = attachment->getObject()->mDrawable->getPosition(); - llinfos << "ATTACHMENT " << key << ": item_id=" << attachment->getItemID() - << (attachment->getObject() ? " present " : " absent ") - << (visible ? "visible " : "invisible ") - << " at " << pos - << " and " << (visible ? attachment->getObject()->getPosition() : LLVector3::zero) - << llendl; + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) + { + LLViewerObject *attached_object = (*attachment_iter); + BOOL visible = (attached_object != NULL && + attached_object->mDrawable.notNull() && + !attached_object->mDrawable->isRenderType(0)); + LLVector3 pos; + if (visible) pos = attached_object->mDrawable->getPosition(); + llinfos << "ATTACHMENT " << key << ": item_id=" << attached_object->getAttachmentItemID() + << (attached_object ? " present " : " absent ") + << (visible ? "visible " : "invisible ") + << " at " << pos + << " and " << (visible ? attached_object->getPosition() : LLVector3::zero) + << llendl; + } } } @@ -7850,16 +7862,16 @@ BOOL enable_more_than_one_selected(void* ) static bool is_editable_selected() { -// [RLVa:KB] - Checked: 2009-10-10 (RLVa-1.0.5a) | Modified: RLVa-1.0.5a - // RELEASE-RLVa: check that this still isn't called by anything but script actions in the Tools menu - if ( (rlv_handler_t::isEnabled()) && (gRlvHandler.hasLockedAttachment(RLV_LOCK_REMOVE)) ) +// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.0.5a | OK + // RELEASE-RLVa: [SL-2.2.0] Check that this still isn't called by anything but script actions in the Build menu + if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_REMOVE)) ) { LLObjectSelectionHandle hSelection = LLSelectMgr::getInstance()->getSelection(); // NOTE: this is called for 5 different menu items so we'll trade accuracy for efficiency and only // examine root nodes (LLToolsSelectedScriptAction::handleEvent() will catch what we miss) - RlvSelectHasLockedAttach functor(RLV_LOCK_REMOVE); - if ( (hSelection->isAttachment()) && (hSelection->getFirstRootNode(&functor)) ) + RlvSelectHasLockedAttach f; + if ( (hSelection->isAttachment()) && (hSelection->getFirstRootNode(&f)) ) { return false; } @@ -8129,7 +8141,7 @@ class LLWorldEnableCreateLandmark : public view_listener_t { bool new_value = gAgent.isGodlike() || (gAgent.getRegion() && gAgent.getRegion()->getAllowLandmark()); -// [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0a) +// [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0a) | OK new_value &= !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC); // [/RLVa:KB] gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); @@ -8736,11 +8748,9 @@ class LLViewHighlightTransparent : public view_listener_t { bool handleEvent(LLPointer event, const LLSD& userdata) { -// [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0b) - if (gRlvHandler.hasBehaviour(RLV_BHVR_EDIT)) - { +// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Modified: RLVa-1.0.0b | OK + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_EDIT)) && (!LLDrawPoolAlpha::sShowDebugAlpha)) return true; - } // [/RLVa:KB] LLDrawPoolAlpha::sShowDebugAlpha = !LLDrawPoolAlpha::sShowDebugAlpha; @@ -8790,11 +8800,9 @@ class LLViewShowHUDAttachments : public view_listener_t { bool handleEvent(LLPointer event, const LLSD& userdata) { -// [RLVa:KB] - Checked: 2009-07-06 (RLVa-1.0.0c) - if ( (LLPipeline::sShowHUDAttachments) && (rlv_handler_t::isEnabled()) && (gRlvHandler.hasLockedHUD()) ) - { +// [RLVa:KB] - Checked: 2010-04-19 (RLVa-1.2.1a) | Modified: RLVa-1.0.0c | OK + if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedHUD()) && (LLPipeline::sShowHUDAttachments) ) return true; - } // [/RLVa:KB] LLPipeline::sShowHUDAttachments = !LLPipeline::sShowHUDAttachments; @@ -8864,9 +8872,9 @@ class LLEditEnableTakeOff : public view_listener_t new_value = LLAgent::selfHasWearable((void *)WT_TATTOO); } -// [RLVa:KB] - Checked: 2009-07-07 (RLVa-1.0.0d) +// [RLVa:KB] - Checked: 2009-07-07 (RLVa-1.1.3b) | Modified: RLVa-1.1.3b | OK // Why aren't they using LLWearable::typeNameToType()? *confuzzled* - if ( (rlv_handler_t::isEnabled()) && (!gRlvHandler.isRemovable(LLWearable::typeNameToType(clothing))) ) + if ( (rlv_handler_t::isEnabled()) && (!gRlvWearableLocks.canRemove(LLWearable::typeNameToType(clothing))) ) { new_value = false; } @@ -8977,11 +8985,9 @@ class LLWorldEnvSettings : public view_listener_t { bool handleEvent(LLPointer event, const LLSD& userdata) { -// [RLVa:KB] - Checked: 2009-07-10 (RLVa-1.0.0g) +// [RLVa:KB] - Checked: 2010-03-18 (RLVa-1.2.0a) | Modified: RLVa-1.0.0g | OK if (gRlvHandler.hasBehaviour(RLV_BHVR_SETENV)) - { return true; - } // [/RLVa:KB] std::string tod = userdata.asString(); @@ -10499,7 +10505,7 @@ void initialize_menus() addMenu(new LLEditableSelected(), "EditableSelected"); addMenu(new LLEditableSelectedMono(), "EditableSelectedMono"); -// [RLVa:KB] - Checked: 2010-01-18 (RLVa-1.1.0m) | Added: RLVa-1.1.0m +// [RLVa:KB] - Checked: 2010-01-18 (RLVa-1.1.0m) | Added: RLVa-1.1.0m | OK if (rlv_handler_t::isEnabled()) { addMenu(new RlvEnableIfNot(), "RLV.EnableIfNot"); diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index ba738df77..9ab7d1f22 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -145,6 +145,7 @@ // [RLVa:KB] #include "rlvhandler.h" +#include "rlvinventory.h" // [/RLVa:KB] #if SHY_MOD //Group Title script access @@ -178,6 +179,7 @@ extern BOOL gDebugClicks; // function prototypes void open_offer(const std::vector& items, const std::string& from_name); +bool highlight_offered_object(const LLUUID& obj_id); bool check_offer_throttle(const std::string& from_name, bool check_only); void callbackCacheEstateOwnerName(const LLUUID& id, const std::string& first, const std::string& last, @@ -887,7 +889,6 @@ void open_offer(const std::vector& items, const std::string& from_name) { std::vector::const_iterator it = items.begin(); std::vector::const_iterator end = items.end(); - LLUUID trash_id(gInventory.findCategoryUUIDForType(LLAssetType::AT_TRASH)); LLInventoryItem* item; for(; it != end; ++it) { @@ -897,7 +898,7 @@ void open_offer(const std::vector& items, const std::string& from_name) LL_WARNS("Messaging") << "Unable to show inventory item: " << *it << LL_ENDL; continue; } - if(gInventory.isObjectDescendentOf(*it, trash_id)) + if(!highlight_offered_object(item->getUUID())) { continue; } @@ -971,6 +972,41 @@ void open_offer(const std::vector& items, const std::string& from_name) } } +bool highlight_offered_object(const LLUUID& obj_id) +{ + const LLInventoryObject* obj = gInventory.getObject(obj_id); + if(!obj) + { + LL_WARNS("Messaging") << "Unable to show inventory item: " << obj_id << LL_ENDL; + return false; + } + + //////////////////////////////////////////////////////////////////////////////// + // Don't highlight if it's in certain "quiet" folders which don't need UI + // notification (e.g. trash, cof, lost-and-found). + if(!gAgent.getAFK()) + { + const LLViewerInventoryCategory *parent = gInventory.getFirstNondefaultParent(obj_id); + if (parent) + { + const LLAssetType::EType parent_type = parent->getPreferredType(); + switch (parent_type) + { + case LLAssetType::AT_TRASH: + case LLAssetType::AT_LOST_AND_FOUND: + case LLAssetType::AT_CURRENT_OUTFIT: + case LLAssetType::AT_OUTFIT: + case LLAssetType::AT_MY_OUTFITS: + return false; + default: + break; + } + } + } + + return true; +} + void inventory_offer_mute_callback(const LLUUID& blocked_id, const std::string& first_name, const std::string& last_name, @@ -1120,7 +1156,7 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& { // [RLVa:KB] - Version: 1.23.4 | Checked: 2009-07-08 (RLVa-1.0.0e) std::string full_name = first_name + " " + last_name; - if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (gRlvHandler.isAgentNearby(mFromID)) ) + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (RlvUtil::isNearbyAgent(mFromID)) ) { full_name = RlvStrings::getAnonym(full_name); } @@ -1144,27 +1180,40 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& bool busy=FALSE; +// [RLVa:KB] - Checked: 2010-09-23 (RLVa-1.2.1e) | Added: RLVa-1.2.1e + bool fRlvNotifyAccepted = false; +// [/RLVa:KB] switch(button) { case IOR_ACCEPT: -// [RLVa:KB] - Version: 1.23.4 | Checked: 2009-07-10 (RLVa-1.0.0g) | Added: RLVa-0.2.2a - // Only change the inventory offer's destination folder to the shared root if: - // - the user has enabled the feature - // - the inventory offer came from a script (and specifies a folder) - // - the name starts with the prefix [mDesc format (quotes are part of the string): "[OBJECTNAME] ( http://slurl.com/... )"] - if ( (rlv_handler_t::isEnabled()) && (!RlvSettings::getForbidGiveToRLV()) && - (IM_TASK_INVENTORY_OFFERED == mIM) && (LLAssetType::AT_CATEGORY == mType) && (mDesc.find(RLV_PUTINV_PREFIX) == 1) ) - { - LLViewerInventoryCategory* pRlvRoot = gRlvHandler.getSharedRoot(); - if (pRlvRoot) - { - mFolderID = pRlvRoot->getUUID(); - } - } -// [/RLVa:KB] // ACCEPT. The math for the dialog works, because the accept // for inventory_offered, task_inventory_offer or // group_notice_inventory is 1 greater than the offer integer value. + +// [RLVa:KB] - Checked: 2010-09-23 (RLVa-1.2.1e) | Modified: RLVa-1.2.1e + // Only change the inventory offer's destination folder to the shared root if: + // - the user has enabled the feature + // - the inventory offer came from a script (and specifies a folder) + // - the name starts with the prefix - mDesc format: '[OBJECTNAME]' ( http://slurl.com/... ) + if ( (rlv_handler_t::isEnabled()) && + (IM_TASK_INVENTORY_OFFERED == mIM) && (LLAssetType::AT_CATEGORY == mType) && (mDesc.find(RLV_PUTINV_PREFIX) == 1) ) + { + fRlvNotifyAccepted = true; + if (!RlvSettings::getForbidGiveToRLV()) + { + const LLViewerInventoryCategory* pRlvRoot = RlvInventory::instance().getSharedRoot(); + if (pRlvRoot) + { + fRlvNotifyAccepted = false; // "accepted_in_rlv" is sent from RlvGiveToRLVTaskOffer *after* we have the folder + mFolderID = pRlvRoot->getUUID(); + + RlvGiveToRLVTaskOffer* pOfferObserver = new RlvGiveToRLVTaskOffer(mTransactionID); + gInventory.addObserver(pOfferObserver); + } + } + } +// [/RLVa:KB] + // Generates IM_INVENTORY_ACCEPTED, IM_TASK_INVENTORY_ACCEPTED, // or IM_GROUP_NOTICE_INVENTORY_ACCEPTED msg->addU8Fast(_PREHASH_Dialog, (U8)(mIM + 1)); @@ -1191,10 +1240,10 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& // This is an offer from an agent. In this case, the back // end has already copied the items into your inventory, // so we can fetch it out of our inventory. -// [RLVa:KB] - Checked: 2010-01-01 (RLVa-1.1.0l) | Added: RLVa-1.1.0l +// [RLVa:KB] - Checked: 2010-04-18 (RLVa-1.2.0e) | Modified: RLVa-1.2.0e #ifdef RLV_EXTENSION_GIVETORLV_A2A - if ( (rlv_handler_t::isEnabled()) && (!RlvSettings::getForbidGiveToRLV()) && - (LLAssetType::AT_CATEGORY == mType) && (mDesc.find(RLV_PUTINV_PREFIX) == 0) ) + if ( (rlv_handler_t::isEnabled()) && (!RlvSettings::getForbidGiveToRLV()) && (LLAssetType::AT_CATEGORY == mType) && + (RlvInventory::instance().getSharedRoot()) && (mDesc.find(RLV_PUTINV_PREFIX) == 0) ) { RlvGiveToRLVAgentOffer* pOffer = new RlvGiveToRLVAgentOffer(); LLInventoryFetchComboObserver::folder_ref_t folders; @@ -1256,12 +1305,19 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& // send the message msg->sendReliable(mHost); +// [RLVa:KB] - Checked: 2010-09-23 (RLVa-1.2.1e) | Added: RLVa-1.2.1e + if ( (rlv_handler_t::isEnabled()) && + (IM_TASK_INVENTORY_OFFERED == mIM) && (LLAssetType::AT_CATEGORY == mType) && (mDesc.find(RLV_PUTINV_PREFIX) == 1) ) + { + std::string::size_type idxToken = mDesc.find("' ( http://"); + if (std::string::npos != idxToken) + RlvBehaviourNotifyHandler::instance().sendNotification("declined inv_offer " + mDesc.substr(1, idxToken - 1)); + } +// [/RLVa:KB] + log_message = "You decline " + mDesc + " from " + mFromName + "."; chat.mText = log_message; - // - //if( LLMuteList::getInstance()->isMuted(mFromID ) && ! LLMuteList::getInstance()->isLinden(mFromName) ) // muting for SL-42269 - if( LLMuteList::getInstance()->isMuted(mFromID) ) // muting for SL-42269 - // + if( LLMuteList::getInstance()->isMuted(mFromID ) && ! LLMuteList::getInstance()->isLinden(mFromName) ) // muting for SL-42269 { chat.mMuted = TRUE; } @@ -1353,7 +1409,7 @@ void inventory_offer_handler(LLOfferInfo* info, BOOL from_task) // TODO-RLVa: needs revisiting when LL saves open notifications to disk to accept them on the next relog if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) { - gRlvHandler.filterLocation(info->mDesc); + RlvUtil::filterLocation(info->mDesc); } // [/RLVa:KB] } @@ -1399,7 +1455,7 @@ void inventory_offer_handler(LLOfferInfo* info, BOOL from_task) if (gCacheName->getName(info->mFromID, first_name, last_name)) { // [RLVa:KB] - Version: 1.23.4 | Checked: 2009-07-08 (RLVa-1.0.0e) - if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (gRlvHandler.isAgentNearby(info->mFromID)) ) + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (RlvUtil::isNearbyAgent(info->mFromID)) ) { first_name = RlvStrings::getAnonym(first_name.append(" ").append(last_name)); last_name.clear(); @@ -1425,7 +1481,7 @@ void inventory_offer_handler(LLOfferInfo* info, BOOL from_task) else { // [RLVa:KB] - Version: 1.23.4 | Checked: 2009-07-08 (RLVa-1.0.0e) - if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (gRlvHandler.isAgentNearby(info->mFromID)) ) + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (RlvUtil::isNearbyAgent(info->mFromID)) ) { args["NAME"] = RlvStrings::getAnonym(info->mFromName); } @@ -1817,17 +1873,18 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) // do nothing -- don't distract newbies in // Prelude with global IMs } -// [RLVa:KB] - Checked: 2009-07-10 (RLVa-1.0.0g) +// [RLVa:KB] - Checked: 2010-03-27 (RLVa-1.1.3a) | Modified: RLVa-1.2.0b else if ( (rlv_handler_t::isEnabled()) && (offline == IM_ONLINE) && ("@version" == message) ) { - rlvSendBusyMessage(from_id, RlvStrings::getVersion(), session_id); + // TODO-RLVa: [RLVa-1.2.1] Should we send our version string if the other party is muted? + RlvUtil::sendBusyMessage(from_id, RlvStrings::getVersion(), session_id); // We won't receive a typing stop message, so do that manually (see comment at the end of LLFloaterIMPanel::sendMsg) LLPointer im_info = new LLIMInfo(gMessageSystem); gIMMgr->processIMTypingStop(im_info); } // [/RLVa:KB] // else if (offline == IM_ONLINE && !is_linden && is_busy && name != SYSTEM_FROM) -// [RLVa:KB] - Checked: 2009-07-10 (RLVa-1.0.0g) +// [RLVa:KB] - Checked: 2010-03-23 (RLVa-1.2.0a) | Modified: RLVa-1.0.0g else if ( (offline == IM_ONLINE && !is_linden && is_busy && name != SYSTEM_FROM) && ( (!gRlvHandler.hasBehaviour(RLV_BHVR_RECVIM)) || (gRlvHandler.isException(RLV_BHVR_RECVIM, from_id))) ) // [/RLVa:KB] @@ -1904,11 +1961,11 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) (!LLMuteList::getInstance()->isLinden(name)) && (from_id != gAgent.getID()) ) { if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) - gRlvHandler.filterLocation(message); + RlvUtil::filterLocation(message); if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) { name = RlvStrings::getAnonym(name); - gRlvHandler.filterNames(message); + RlvUtil::filterNames(message); } } // [/RLVa:KB] @@ -1928,11 +1985,13 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) else { // standard message, not from system -// [RLVa:KB] - Checked: 2009-07-10 (RLVa-1.0.0g) - if ( (gRlvHandler.hasBehaviour(RLV_BHVR_RECVIM)) && (!gRlvHandler.isException(RLV_BHVR_RECVIM, from_id)) ) +// [RLVa:KB] - Checked: 2010-03-23 (RLVa-1.1.3a) | Modified: RLVa-1.2.0a + // Don't block offline IMs, or IMs from Lindens + if ( (rlv_handler_t::isEnabled()) && (offline != IM_OFFLINE) && (!is_linden) && + (gRlvHandler.hasBehaviour(RLV_BHVR_RECVIM)) && (!gRlvHandler.isException(RLV_BHVR_RECVIM, from_id)) ) { if (!is_muted) - rlvSendBusyMessage(from_id, RlvStrings::getString(RLV_STRING_BLOCKED_RECVIM_REMOTE), session_id); + RlvUtil::sendBusyMessage(from_id, RlvStrings::getString(RLV_STRING_BLOCKED_RECVIM_REMOTE), session_id); message = message.substr(0, message_offset) + RlvStrings::getString(RLV_STRING_BLOCKED_RECVIM); } // [/RLVa:KB] @@ -2156,7 +2215,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) info->mObjectID = bucketp->object_id; // [RLVa:KB] - Checked: 2009-07-08 (RLVa-1.0.0e) - if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (gRlvHandler.isAgentNearby(from_id)) ) + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (RlvUtil::isNearbyAgent(from_id)) ) { name = RlvStrings::getAnonym(name); } @@ -2206,7 +2265,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) || ((IM_INVENTORY_OFFERED == dialog) && (info->mDesc.find(RLV_PUTINV_PREFIX) == 0)) #endif // RLV_EXTENSION_GIVETORLV_A2A ) && - (gRlvHandler.getSharedRoot()) ) + (RlvInventory::instance().getSharedRoot()) ) { RlvNotifications::warnGiveToRLV(); } @@ -2221,7 +2280,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) { // [RLVa:KB] - Version: 1.23.4 | Checked: 2009-07-08 (RLVa-1.0.0e) | Modified: RLVa-0.2.0b bool fRlvObfuscate = (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && - (gRlvHandler.isAgentNearby(from_id)) && (!gAvatarInfoInstances.checkData(from_id)); + (RlvUtil::isNearbyAgent(from_id)) && (!gAvatarInfoInstances.checkData(from_id)); args["NAME"] = (!fRlvObfuscate) ? name : RlvStrings::getAnonym(name); // [/RLVa:KB] //args["NAME"] = name; @@ -2232,7 +2291,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) { // [RLVa:KB] - Version: 1.23.4 | Checked: 2009-07-08 (RLVa-1.0.0e) | Modified: RLVa-0.2.0b bool fRlvObfuscate = (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && - (gRlvHandler.isAgentNearby(from_id)) && (!gAvatarInfoInstances.checkData(from_id)); + (RlvUtil::isNearbyAgent(from_id)) && (!gAvatarInfoInstances.checkData(from_id)); args["NAME"] = (!fRlvObfuscate) ? name : RlvStrings::getAnonym(name); // [/RLVa:KB] //args["NAME"] = name; @@ -2375,9 +2434,9 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) if (rlv_handler_t::isEnabled()) { if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) - gRlvHandler.filterLocation(message); + RlvUtil::filterLocation(message); if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) - gRlvHandler.filterNames(message); + RlvUtil::filterNames(message); } // [/RLVa:KB] // Construct a viewer alert for this message. @@ -2412,19 +2471,19 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) } else { -// [RLVa:KB] - Version: 1.23.4 | Checked: 2009-07-07 (RLVa-1.0.0d) +// [RLVa:KB] - Checked: 2010-04-01 (RLVa-1.1.3a) | Modified: RLVa-1.0.0d if (rlv_handler_t::isEnabled()) { - // Disallow if: 1) @tplure=n restricted (sender isn't an exception), or 2) @unsit=n restricted and currently sitting + // Block if: 1) @tplure=n restricted (and sender isn't an exception), or 2) @unsit=n restricted and currently sitting LLVOAvatar* pAvatar = gAgent.getAvatarObject(); if ( ( (gRlvHandler.hasBehaviour(RLV_BHVR_TPLURE)) && (!gRlvHandler.isException(RLV_BHVR_TPLURE, from_id)) ) || ( (gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) && (pAvatar) && (pAvatar->mIsSitting) ) ) { - rlvSendBusyMessage(from_id, RlvStrings::getString(RLV_STRING_BLOCKED_TPLURE_REMOTE)); + RlvUtil::sendBusyMessage(from_id, RlvStrings::getString(RLV_STRING_BLOCKED_TPLURE_REMOTE)); return; } - // Censor teleport message if: 1) @revcim=n restricted (sender isn't an exception), or 2) @showloc=n restricted + // Censor lure message if: 1) @revcim=n restricted (and sender isn't an exception), or 2) @showloc=n restricted if ( ( (gRlvHandler.hasBehaviour(RLV_BHVR_RECVIM)) && (!gRlvHandler.isException(RLV_BHVR_RECVIM, from_id)) ) || (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) ) { @@ -2956,20 +3015,20 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) color.setVec(1.f,1.f,1.f,1.f); msg->getStringFast(_PREHASH_ChatData, _PREHASH_Message, mesg); -// [RLVa:KB] - Checked: 2009-10-06 (RLVa-1.0.4d) | Modified: RLVa-1.0.4d - if ( (rlv_handler_t::isEnabled()) && - (CHAT_TYPE_START != chat.mChatType) && (CHAT_TYPE_STOP != chat.mChatType) && (CHAT_TYPE_OWNER != chat.mChatType) ) +// [RLVa:KB] - Checked: 2010-04-23 (RLVa-1.2.0f) | Modified: RLVa-1.2.0f + if ( (rlv_handler_t::isEnabled()) && (CHAT_TYPE_START != chat.mChatType) && (CHAT_TYPE_STOP != chat.mChatType) ) { // NOTE: chatter can be NULL (may not have rezzed yet, or could be another avie's HUD attachment) BOOL is_attachment = (chatter) ? chatter->isAttachment() : FALSE; // Filtering "rules": // avatar => filter all avie text (unless it's this avie or they're an exemption) - // objects => filter everything except attachments this avie owns + // objects => filter everything except attachments this avie owns (never filter llOwnerSay chat) if ( ( (CHAT_SOURCE_AGENT == chat.mSourceType) && (from_id != gAgent.getID()) ) || - ( (CHAT_SOURCE_OBJECT == chat.mSourceType) && ((!is_owned_by_me) || (!is_attachment)) ) ) + ( (CHAT_SOURCE_OBJECT == chat.mSourceType) && ((!is_owned_by_me) || (!is_attachment)) && + (CHAT_TYPE_OWNER != chat.mChatType) ) ) { - if (!rlvIsEmote(mesg)) + if (!RlvUtil::isEmote(mesg)) { if ( (gRlvHandler.hasBehaviour(RLV_BHVR_RECVCHAT)) && (!gRlvHandler.isException(RLV_BHVR_RECVCHAT, from_id)) ) gRlvHandler.filterChat(mesg, false); @@ -2980,23 +3039,21 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) } } - if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) + // Filtering "rules": + // avatar => filter only their name (unless it's this avie) + // other => filter everything except attachments this avie owns but then we still do filter their text + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && + ((CHAT_SOURCE_AGENT != chat.mSourceType) || (chat.mFromID != gAgent.getID())) ) { - // Filtering "rules": - // avatar => filter only their name (unless it's this avie) - // other => filter everything except attachments this avie owns but then we still do filter their text if (CHAT_SOURCE_AGENT == chat.mSourceType) { - if (chat.mFromID != gAgent.getID()) - from_name = RlvStrings::getAnonym(from_name); + chat.mFromName = RlvStrings::getAnonym(from_name); + chat.mRlvNamesFiltered = TRUE; } - else + else if ( (!is_owned_by_me) || (!is_attachment) ) { - if ( (!is_owned_by_me) || (!is_attachment) ) - gRlvHandler.filterNames(from_name); - gRlvHandler.filterNames(mesg); + RlvUtil::filterNames(chat.mFromName); } - chat.mRlvNamesFiltered = true; } } // [/RLVa:KB] @@ -3064,8 +3121,8 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) verb = " " + LLTrans::getString("whisper") + " "; break; case CHAT_TYPE_OWNER: -// [RLVa:KB] - Checked: 2009-11-25 (RLVa-1.1.0f) | Modified: RLVa-1.1.0f - // TODO-RLVa: [2009-11-25] this could really use some rewriting +// [RLVa:KB] - Checked: 2010-02-XX (RLVa-1.2.0a) | Modified: RLVa-1.1.0f + // TODO-RLVa: [RLVa-1.2.0] consider rewriting this before a RLVa-1.2.0 release if ( (rlv_handler_t::isEnabled()) && (mesg.length() > 3) && (RLV_CMD_PREFIX == mesg[0]) && (CHAT_TYPE_OWNER == chat.mChatType) ) { mesg.erase(0, 1); @@ -3079,7 +3136,9 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) std::string strCmd = *itToken; ERlvCmdRet eRet = gRlvHandler.processCommand(from_id, strCmd, true); - if (RlvSettings::getDebug()) + if ( (RlvSettings::getDebug()) && + ( (!RlvSettings::getDebugHideUnsetDup()) || + ((RLV_RET_SUCCESS_UNSET != eRet) && (RLV_RET_SUCCESS_DUPLICATE != eRet)) ) ) { if ( RLV_RET_SUCCESS == (eRet & RLV_RET_SUCCESS) ) pstr = &strExecuted; @@ -3103,7 +3162,9 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) } } - if (!RlvSettings::getDebug()) + RlvForceWear::instance().done(); + + if ( (!RlvSettings::getDebug()) || ((strExecuted.empty()) && (strFailed.empty()) && (strRetained.empty())) ) return; // Silly people want comprehensive debug messages, blah :p @@ -3122,7 +3183,7 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) verb = " retained: @"; mesg = strRetained; } - else + else { verb = ": @"; if (!strExecuted.empty()) diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 5d7e29712..36149fc85 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -207,7 +207,8 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe mJointInfo(NULL), mState(0), mMedia(NULL), - mClickAction(0) + mClickAction(0), + mAttachmentItemID(LLUUID::null) { if(!is_global) { @@ -508,9 +509,20 @@ BOOL LLViewerObject::isOverGroupOwnedLand() const && mRegionp->getParcelOverlay()->isOwnedGroup(getPositionRegion()); } -void LLViewerObject::setParent(LLViewerObject* parent) +BOOL LLViewerObject::setParent(LLViewerObject* parent) { - LLPrimitive::setParent(parent); + if (mParent != parent) + { + LLViewerObject* old_parent = (LLViewerObject*)mParent ; + BOOL ret = LLPrimitive::setParent(parent); + if (ret && old_parent && parent) + { + old_parent->removeChild(this) ; + } + return ret ; + } + + return FALSE ; } void LLViewerObject::addChild(LLViewerObject *childp) @@ -529,8 +541,10 @@ void LLViewerObject::addChild(LLViewerObject *childp) childp->mbCanSelect = mbCanSelect; } - childp->setParent(this); - mChildList.push_back(childp); + if (childp->setParent(this)) + { + mChildList.push_back(childp); + } } void LLViewerObject::removeChild(LLViewerObject *childp) @@ -627,11 +641,15 @@ BOOL LLViewerObject::setDrawableParent(LLDrawable* parentp) return FALSE; } + BOOL ret = mDrawable->mXform.setParent(parentp ? &parentp->mXform : NULL); + if (!ret) + { + return FALSE ; + } LLDrawable* old_parent = mDrawable->mParent; mDrawable->mParent = parentp; - BOOL ret = mDrawable->mXform.setParent(parentp ? &parentp->mXform : NULL); gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE); if( (old_parent != parentp && old_parent) || (parentp && parentp->isActive())) @@ -1621,20 +1639,21 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, gObjectList.killObject(this); return retval; } -// [RLVa:KB] - Checked: 2009-12-27 (RLVa-1.1.0k) | Added: RLVa-1.1.0k +// [RLVa:KB] - Checked: 2010-03-16 (RLVa-1.1.0k) | Added: RLVa-1.1.0k if ( (rlv_handler_t::isEnabled()) && (sent_parentp->isAvatar()) && (sent_parentp->getID() == gAgent.getID()) ) { // Rezzed object that's being worn as an attachment (we're assuming this will be due to llAttachToAvatar()) S32 idxAttachPt = ATTACHMENT_ID_FROM_STATE(getState()); - if (gRlvHandler.isLockedAttachment(idxAttachPt, RLV_LOCK_ANY)) + if (gRlvAttachmentLocks.isLockedAttachmentPoint(idxAttachPt, RLV_LOCK_ADD)) { // If this will end up on an "add locked" attachment point then treat the attach as a user action LLNameValue* nvItem = getNVPair("AttachItemID"); if (nvItem) { LLUUID idItem(nvItem->getString()); + // URGENT-RLVa: [RLVa-1.2.0] At the moment llAttachToAvatar always seems to *add* if (idItem.notNull()) - gRlvHandler.onWearAttachment(idItem); + RlvAttachmentLockWatchdog::instance().onWearAttachment(idItem, RLV_WEAR_ADD); } } } @@ -5214,3 +5233,21 @@ std::string LLViewerObject::getAttachmentPointName() return llformat("unsupported point %d", point); } // + + +const LLUUID &LLViewerObject::extractAttachmentItemID() +{ + LLUUID item_id = LLUUID::null; + LLNameValue* item_id_nv = getNVPair("AttachItemID"); + if (item_id_nv) + { + const char* s = item_id_nv->getString(); + if (s) + { + item_id.set(s); + } + } + setAttachmentItemID(item_id); + return getAttachmentItemID(); +} + diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index ace0c2354..2eb8819dd 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -236,7 +236,7 @@ public: BOOL isProbablyModifiable() const; */ - virtual void setParent(LLViewerObject* parent); + virtual BOOL setParent(LLViewerObject* parent); virtual void addChild(LLViewerObject *childp); virtual void removeChild(LLViewerObject *childp); const_child_list_t& getChildren() const { return mChildList; } @@ -321,7 +321,10 @@ public: void sendShapeUpdate(); - U8 getState() { return mState; } +// U8 getState() { return mState; } +// [RLVa:KB] - Checked: 2010-09-26 (RLVa-1.3.0a) | Added: RLVa-1.3.0a + U8 getState() const { return mState; } +// [/RLVa:KB] F32 getAppAngle() const { return mAppAngle; } F32 getPixelArea() const { return mPixelArea; } @@ -662,13 +665,20 @@ protected: private: static S32 sNumObjects; -// public: +// S32 getAttachmentPoint(); std::string getAttachmentPointName(); // + const LLUUID &getAttachmentItemID() const { return mAttachmentItemID; } + void setAttachmentItemID(const LLUUID &id) { mAttachmentItemID = id; } + const LLUUID &extractAttachmentItemID(); // find&set the inventory item ID of the attached object +private: + LLUUID mAttachmentItemID; // ItemID when item is in user inventory. }; +typedef std::vector llvo_vec_t; + /////////////////// // // Inlines diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index d45580395..44fa54177 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -1244,18 +1244,22 @@ void LLViewerObjectList::generatePickList(LLCamera &camera) LLViewerJointAttachment* attachmentp = curiter->second; if (attachmentp->getIsHUDAttachment()) { - LLViewerObject* objectp = attachmentp->getObject(); - if (objectp) + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachmentp->mAttachedObjects.begin(); + attachment_iter != attachmentp->mAttachedObjects.end(); + ++attachment_iter) { - mSelectPickList.insert(objectp); - LLViewerObject::const_child_list_t& child_list = objectp->getChildren(); - for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); - iter != child_list.end(); iter++) + if (LLViewerObject* objectp = (*attachment_iter)) { - LLViewerObject* childp = *iter; - if (childp) + mSelectPickList.insert(objectp); + LLViewerObject::const_child_list_t& child_list = objectp->getChildren(); + for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); + iter != child_list.end(); iter++) { - mSelectPickList.insert(childp); + LLViewerObject* childp = *iter; + if (childp) + { + mSelectPickList.insert(childp); + } } } } diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 091e3a084..0b4ddfff9 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -39,7 +39,9 @@ #include "llaudioengine.h" #include "noise.h" +#include "llsdserialize.h" +#include "cofmgr.h" #include "llagent.h" // Get state values from here #include "llviewercontrol.h" #include "lldrawpoolavatar.h" @@ -53,6 +55,7 @@ #include "llhudeffecttrail.h" #include "llhudmanager.h" +#include "llinventorybridge.h" #include "llinventoryview.h" #include "llkeyframefallmotion.h" #include "llkeyframestandmotion.h" @@ -100,7 +103,7 @@ #include "llavatarname.h" #include "llavatarnamecache.h" -// [RLVa:KB] +// [RLVa:KB] - Checked: 2010-04-01 (RLVa-1.2.0c) #include "rlvhandler.h" // [/RLVa:KB] @@ -1649,28 +1652,32 @@ void LLVOAvatar::getSpatialExtents(LLVector3& newMin, LLVector3& newMax) { continue ; } - - LLViewerObject* object = attachment->getObject(); - if (object && !object->isHUDAttachment()) + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) { - LLDrawable* drawable = object->mDrawable; - if (drawable) + const LLViewerObject* attached_object = (*attachment_iter); + if (attached_object && !attached_object->isHUDAttachment()) { - LLSpatialBridge* bridge = drawable->getSpatialBridge(); - if (bridge) + LLDrawable* drawable = attached_object->mDrawable; + if (drawable) { - const LLVector3* ext = bridge->getSpatialExtents(); - LLVector3 distance = (ext[1] - ext[0]); - - // Only add the prim to spatial extents calculations if it isn't a megaprim. - // max_attachment_span calculated at the start of the function - // (currently 5 times our max prim size) - if (distance.mV[0] < max_attachment_span - && distance.mV[1] < max_attachment_span - && distance.mV[2] < max_attachment_span) + LLSpatialBridge* bridge = drawable->getSpatialBridge(); + if (bridge) { - update_min_max(newMin,newMax,ext[0]); - update_min_max(newMin,newMax,ext[1]); + const LLVector3* ext = bridge->getSpatialExtents(); + LLVector3 distance = (ext[1] - ext[0]); + + // Only add the prim to spatial extents calculations if it isn't a megaprim. + // max_attachment_span calculated at the start of the function + // (currently 5 times our max prim size) + if (distance.mV[0] < max_attachment_span + && distance.mV[1] < max_attachment_span + && distance.mV[2] < max_attachment_span) + { + update_min_max(newMin,newMax,ext[0]); + update_min_max(newMin,newMax,ext[1]); + } } } } @@ -2735,6 +2742,12 @@ BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) // attach objects that were waiting for a drawable lazyAttach(); +/* + if (mIsSelf) + { + checkAttachments(); + } +*/ // animate the character // store off last frame's root position to be consistent with camera position @@ -2771,6 +2784,38 @@ BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) return TRUE; } +// static +BOOL LLVOAvatar::detachAttachmentIntoInventory(const LLUUID &item_id) +{ + LLInventoryItem* item = gInventory.getLinkedItem(item_id); + if ( (item) && (gAgent.getAvatarObject()) && (!gAgent.getAvatarObject()->isWearingAttachment(item->getUUID())) ) + { + LLCOFMgr::instance().removeAttachment(item->getUUID()); + return FALSE; + } +// if (item) +// [RLVa:KB] - Checked: 2010-09-04 (RLVa-1.2.1c) | Added: RLVa-1.2.1c + if ( (item) && ((!rlv_handler_t::isEnabled()) || (gRlvAttachmentLocks.canDetach(item))) ) +// [/RLVa:KB] + { + gMessageSystem->newMessageFast(_PREHASH_DetachAttachmentIntoInv); + gMessageSystem->nextBlockFast(_PREHASH_ObjectData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + gMessageSystem->addUUIDFast(_PREHASH_ItemID, item_id); + gMessageSystem->sendReliable(gAgent.getRegion()->getHost()); + + // This object might have been selected, so let the selection manager know it's gone now + LLViewerObject *found_obj = gObjectList.findObject(item_id); + if (found_obj) + { + LLSelectMgr::getInstance()->remove(found_obj); + } + + return TRUE; + } + return FALSE; +} + void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled) { // disable voice visualizer when in mouselook @@ -2887,30 +2932,35 @@ void LLVOAvatar::idleUpdateMisc(bool detailed_update) { attachment_map_t::iterator curiter = iter++; LLViewerJointAttachment* attachment = curiter->second; - LLViewerObject *attached_object = attachment->getObject(); - BOOL visibleAttachment = visible || (attached_object && - !(attached_object->mDrawable->getSpatialBridge() && - attached_object->mDrawable->getSpatialBridge()->getRadius() < 2.0)); - - if (visibleAttachment && attached_object && !attached_object->isDead() && attachment->getValid()) + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) { - // if selecting any attachments, update all of them as non-damped - if (LLSelectMgr::getInstance()->getSelection()->getObjectCount() && LLSelectMgr::getInstance()->getSelection()->isAttachment()) - { - gPipeline.updateMoveNormalAsync(attached_object->mDrawable); - } - else - { - gPipeline.updateMoveDampedAsync(attached_object->mDrawable); - } + LLViewerObject* attached_object = (*attachment_iter); + BOOL visibleAttachment = visible || (attached_object && + !(attached_object->mDrawable->getSpatialBridge() && + attached_object->mDrawable->getSpatialBridge()->getRadius() < 2.0)); - LLSpatialBridge* bridge = attached_object->mDrawable->getSpatialBridge(); - if (bridge) + if (visibleAttachment && attached_object && !attached_object->isDead() && attachment->getValid()) { - gPipeline.updateMoveNormalAsync(bridge); + // if selecting any attachments, update all of them as non-damped + if (LLSelectMgr::getInstance()->getSelection()->getObjectCount() && LLSelectMgr::getInstance()->getSelection()->isAttachment()) + { + gPipeline.updateMoveNormalAsync(attached_object->mDrawable); + } + else + { + gPipeline.updateMoveDampedAsync(attached_object->mDrawable); + } + + LLSpatialBridge* bridge = attached_object->mDrawable->getSpatialBridge(); + if (bridge) + { + gPipeline.updateMoveNormalAsync(bridge); + } + attached_object->updateText(); } - attached_object->updateText(); } } } @@ -4753,19 +4803,24 @@ void LLVOAvatar::updateVisibility() /*llinfos << "SPA: " << sel_pos_agent << llendl; llinfos << "WPA: " << wrist_right_pos_agent << llendl;*/ for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); - iter != mAttachmentPoints.end(); ) + iter != mAttachmentPoints.end(); iter++) { - attachment_map_t::iterator curiter = iter++; - LLViewerJointAttachment* attachment = curiter->second; - if (attachment->getObject()) + LLViewerJointAttachment* attachment = iter->second; + + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) { - if(attachment->getObject()->mDrawable->isVisible()) + if (LLViewerObject *attached_object = (*attachment_iter)) { - llinfos << attachment->getName() << " visible" << llendl; - } - else - { - llinfos << attachment->getName() << " not visible at " << mDrawable->getWorldPosition() << " and radius " << mDrawable->getRadius() << llendl; + if (attached_object->mDrawable->isVisible()) + { + llinfos << attachment->getName() << " visible" << llendl; + } + else + { + llinfos << attachment->getName() << " not visible at " << mDrawable->getWorldPosition() << " and radius " << mDrawable->getRadius() << llendl; + } } } } @@ -6933,12 +6988,13 @@ void LLVOAvatar::requestLayerSetUpdate(ETextureIndex index ) } } -void LLVOAvatar::setParent(LLViewerObject* parent) +BOOL LLVOAvatar::setParent(LLViewerObject* parent) { + BOOL ret ; if (parent == NULL) { getOffObject(); - LLViewerObject::setParent(parent); + ret = LLViewerObject::setParent(parent); if (isSelf()) { gAgent.resetCamera(); @@ -6946,13 +7002,18 @@ void LLVOAvatar::setParent(LLViewerObject* parent) } else { - LLViewerObject::setParent(parent); - sitOnObject(parent); + ret = LLViewerObject::setParent(parent); + if (ret) + { + sitOnObject(parent); + } } + return ret ; } void LLVOAvatar::addChild(LLViewerObject *childp) { + childp->extractAttachmentItemID(); // find the inventory item this object is associated with. LLViewerObject::addChild(childp); if (childp->mDrawable) { @@ -6970,15 +7031,33 @@ void LLVOAvatar::removeChild(LLViewerObject *childp) detachObject(childp); } -LLViewerJointAttachment* LLVOAvatar::getTargetAttachmentPoint(LLViewerObject* viewer_object) +//LLViewerJointAttachment* LLVOAvatar::getTargetAttachmentPoint(LLViewerObject* viewer_object) +// [RLVa:KB] - Checked: 2009-12-18 (RLVa-1.1.0i) | Added: RLVa-1.1.0i +LLViewerJointAttachment* LLVOAvatar::getTargetAttachmentPoint(const LLViewerObject* viewer_object) const +// [/RLVa:KB] { S32 attachmentID = ATTACHMENT_ID_FROM_STATE(viewer_object->getState()); + // This should never happen unless the server didn't process the attachment point + // correctly, but putting this check in here to be safe. + if (attachmentID & ATTACHMENT_ADD) + { + llwarns << "Got an attachment with ATTACHMENT_ADD mask, removing ( attach pt:" << attachmentID << " )" << llendl; + attachmentID &= ~ATTACHMENT_ADD; + } + LLViewerJointAttachment* attachment = get_if_there(mAttachmentPoints, attachmentID, (LLViewerJointAttachment*)NULL); if (!attachment) { llwarns << "Object attachment point invalid: " << attachmentID << llendl; +// attachment = get_if_there(mAttachmentPoints, 1, (LLViewerJointAttachment*)NULL); // Arbitrary using 1 (chest) +// [SL:KB] - Patch: Appearance-LegacyMultiAttachment | Checked: 2010-08-28 (Catznip-2.2.0a) | Added: Catznip2.1.2a + S32 idxAttachPt = 1; + if ( (!isSelf()) && (gSavedSettings.getBOOL("LegacyMultiAttachmentSupport")) && (attachmentID > 38) && (attachmentID <= 68) ) + idxAttachPt = attachmentID - 38; + attachment = get_if_there(mAttachmentPoints, idxAttachPt, (LLViewerJointAttachment*)NULL); +// [/SL:KB] } return attachment; @@ -7040,21 +7119,53 @@ BOOL LLVOAvatar::attachObject(LLViewerObject *viewer_object) { updateAttachmentVisibility(gAgent.getCameraMode()); -// [RLVa:KB] - Checked: 2009-10-10 (RLVa-1.0.5a) | Modified: RLVa-1.0.5a +// [RLVa:KB] - Checked: 2010-08-22 (RLVa-1.2.1a) | Modified: RLVa-1.2.1a + // NOTE: RLVa event handlers should be invoked *after* LLVOAvatar::attachObject() calls LLViewerJointAttachment::addObject() if (rlv_handler_t::isEnabled()) { - gRlvHandler.onAttach(attachment); + RlvAttachmentLockWatchdog::instance().onAttach(viewer_object, attachment); + gRlvHandler.onAttach(viewer_object, attachment); + + if ( (attachment->getIsHUDAttachment()) && (!gRlvAttachmentLocks.hasLockedHUD()) ) + gRlvAttachmentLocks.updateLockedHUD(); } // [/RLVa:KB] // Then make sure the inventory is in sync with the avatar. - gInventory.addChangedMask( LLInventoryObserver::LABEL, attachment->getItemID() ); + gInventory.addChangedMask(LLInventoryObserver::LABEL, viewer_object->getAttachmentItemID()); gInventory.notifyObservers(); + + // Should just be the last object added + if (attachment->isObjectAttached(viewer_object)) + { + LLCOFMgr::instance().addAttachment(viewer_object->getAttachmentItemID()); + } } return TRUE; } +U32 LLVOAvatar::getNumAttachments() const +{ + U32 num_attachments = 0; + for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); + ++iter) + { + LLViewerJointAttachment *attachment_pt = (*iter).second; + num_attachments += attachment_pt->getNumObjects(); + } + return num_attachments; +} + +//----------------------------------------------------------------------------- +// canAttachMoreObjects() +//----------------------------------------------------------------------------- +BOOL LLVOAvatar::canAttachMoreObjects() const +{ + return (getNumAttachments() < MAX_AGENT_ATTACHMENTS); +} + //----------------------------------------------------------------------------- // lazyAttach() //----------------------------------------------------------------------------- @@ -7079,17 +7190,21 @@ void LLVOAvatar::lazyAttach() void LLVOAvatar::resetHUDAttachments() { - for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); - iter != mAttachmentPoints.end(); ) + for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); iter++) { - attachment_map_t::iterator curiter = iter++; - LLViewerJointAttachment* attachment = curiter->second; + LLViewerJointAttachment* attachment = iter->second; if (attachment->getIsHUDAttachment()) { - LLViewerObject* obj = attachment->getObject(); - if (obj && obj->mDrawable.notNull()) + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) { - gPipeline.markMoved(obj->mDrawable); + const LLViewerObject* attached_object = (*attachment_iter); + if (attached_object && attached_object->mDrawable.notNull()) + { + gPipeline.markMoved(attached_object->mDrawable); + } } } } @@ -7106,17 +7221,25 @@ BOOL LLVOAvatar::detachObject(LLViewerObject *viewer_object) attachment_map_t::iterator curiter = iter++; LLViewerJointAttachment* attachment = curiter->second; // only one object per attachment point for now - if (attachment->getObject() == viewer_object) + if (attachment->isObjectAttached(viewer_object)) { -// [RLVa:KB] - Checked: 2009-07-10 (RLVa-1.0.0g) - // URGENT-RLV: it looks like LLApp::isExiting() isn't always accurate so find something better (if it exists) - if ( (rlv_handler_t::isEnabled()) && (!LLApp::isExiting()) && (mIsSelf) ) +// [RLVa:KB] - Checked: 2010-03-05 (RLVa-1.2.0a) | Added: RLVa-1.2.0a + // NOTE: RLVa event handlers should be invoked *before* LLVOAvatar::detachObject() calls LLViewerJointAttachment::removeObject() + if ( (rlv_handler_t::isEnabled()) && (mIsSelf) ) { - gRlvHandler.onDetach(attachment); + for (attachment_map_t::const_iterator itAttachPt = mAttachmentPoints.begin(); itAttachPt != mAttachmentPoints.end(); ++itAttachPt) + { + const LLViewerJointAttachment* pAttachPt = itAttachPt->second; + if (pAttachPt->isObjectAttached(viewer_object)) + { + RlvAttachmentLockWatchdog::instance().onDetach(viewer_object, pAttachPt); + gRlvHandler.onDetach(viewer_object, pAttachPt); + } + } } // [/RLVa:KB] - LLUUID item_id = attachment->getItemID(); + LLUUID item_id = viewer_object->getAttachmentItemID(); attachment->removeObject(viewer_object); if (mIsSelf) { @@ -7138,6 +7261,10 @@ BOOL LLVOAvatar::detachObject(LLViewerObject *viewer_object) LLFollowCamMgr::setCameraActive(child_objectp->getID(), FALSE); } +// [RLVa:KB] - Checked: 2010-08-22 (RLVa-1.2.1a) | Added: RLVa-1.2.1a + if ( (rlv_handler_t::isEnabled()) && (viewer_object->isHUDAttachment()) && (gRlvAttachmentLocks.hasLockedHUD()) ) + gRlvAttachmentLocks.updateLockedHUD(); +// [/RLVa:KB] } lldebugs << "Detaching object " << viewer_object->mID << " from " << attachment->getName() << llendl; if (mIsSelf) @@ -7145,6 +7272,12 @@ BOOL LLVOAvatar::detachObject(LLViewerObject *viewer_object) // Then make sure the inventory is in sync with the avatar. gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); gInventory.notifyObservers(); + + // Update COF contents (unless the avatar is being destroyed) + if ( (getRegion()) && (!isDead()) ) + { + LLCOFMgr::instance().removeAttachment(item_id); + } } return TRUE; } @@ -7231,13 +7364,11 @@ void LLVOAvatar::sitOnObject(LLViewerObject *sit_object) if (mIsSelf) { -// [RLVa:KB] - Checked: 2009-07-08 (RLVa-1.0.0e) | Added: RLVa-0.2.1d - #ifdef RLV_EXTENSION_STARTLOCATION +// [RLVa:KB] - Checked: 2010-08-29 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c if (rlv_handler_t::isEnabled()) { - RlvSettings::updateLoginLastLocation(); + gRlvHandler.onSitOrStand(true); } - #endif // RLV_EXTENSION_STARTLOCATION // [/RLVa:KB] // Might be first sit @@ -7304,13 +7435,11 @@ void LLVOAvatar::getOffObject() if (mIsSelf) { -// [RLVa:KB] - Checked: 2009-07-08 (RLVa-1.0.0e) | Added: RLVa-0.2.1d - #ifdef RLV_EXTENSION_STARTLOCATION +// [RLVa:KB] - Checked: 2010-08-29 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c if (rlv_handler_t::isEnabled()) { - RlvSettings::updateLoginLastLocation(); + gRlvHandler.onSitOrStand(false); } - #endif // RLV_EXTENSION_STARTLOCATION // [/RLVa:KB] LLQuaternion av_rot = gAgent.getFrameAgent().getQuaternion(); @@ -7379,12 +7508,13 @@ LLVOAvatar* LLVOAvatar::findAvatarFromAttachment( LLViewerObject* obj ) //----------------------------------------------------------------------------- BOOL LLVOAvatar::isWearingAttachment( const LLUUID& inv_item_id ) { + const LLUUID& base_inv_item_id = gInventory.getLinkedItemID(inv_item_id); for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); iter != mAttachmentPoints.end(); ) { attachment_map_t::iterator curiter = iter++; LLViewerJointAttachment* attachment = curiter->second; - if( attachment->getItemID() == inv_item_id ) + if(attachment->getAttachedObject(base_inv_item_id)) { return TRUE; } @@ -7410,27 +7540,28 @@ BOOL LLVOAvatar::isWearingUnsupportedAttachment( const LLUUID& inv_item_id ) //----------------------------------------------------------------------------- LLViewerObject* LLVOAvatar::getWornAttachment( const LLUUID& inv_item_id ) { + const LLUUID& base_inv_item_id = gInventory.getLinkedItemID(inv_item_id); for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); iter != mAttachmentPoints.end(); ) { attachment_map_t::iterator curiter = iter++; LLViewerJointAttachment* attachment = curiter->second; - if( attachment->getItemID() == inv_item_id ) + if (LLViewerObject *attached_object = attachment->getAttachedObject(base_inv_item_id)) { - return attachment->getObject(); + return attached_object; } } return NULL; } -// [RLVa:KB] - Checked: 2009-12-18 (RLVa-1.1.0i) | Added: RLVa-1.1.0i -LLViewerJointAttachment* LLVOAvatar::getWornAttachmentPoint(const LLUUID& inv_item_id) +// [RLVa:KB] - Checked: 2010-03-14 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a +LLViewerJointAttachment* LLVOAvatar::getWornAttachmentPoint(const LLUUID& idItem) const { - for (attachment_map_t::const_iterator itAttach = mAttachmentPoints.begin(); - itAttach != mAttachmentPoints.end(); ++itAttach) + const LLUUID& idItemBase = gInventory.getLinkedItemID(idItem); + for (attachment_map_t::const_iterator itAttachPt = mAttachmentPoints.begin(); itAttachPt != mAttachmentPoints.end(); ++itAttachPt) { - LLViewerJointAttachment* pAttachPt = itAttach->second; - if (pAttachPt->getItemID() == inv_item_id) + LLViewerJointAttachment* pAttachPt = itAttachPt->second; + if (pAttachPt->getAttachedObject(idItemBase)) return pAttachPt; } return NULL; @@ -7439,12 +7570,13 @@ LLViewerJointAttachment* LLVOAvatar::getWornAttachmentPoint(const LLUUID& inv_it const std::string LLVOAvatar::getAttachedPointName(const LLUUID& inv_item_id) { + const LLUUID& base_inv_item_id = gInventory.getLinkedItemID(inv_item_id); for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); iter != mAttachmentPoints.end(); ) { attachment_map_t::iterator curiter = iter++; LLViewerJointAttachment* attachment = curiter->second; - if( attachment->getItemID() == inv_item_id ) + if (attachment->getAttachedObject(base_inv_item_id)) { return attachment->getName(); } @@ -7891,9 +8023,6 @@ BOOL LLVOAvatar::updateIsFullyLoaded() loading = TRUE; } } - - - // we wait a little bit before giving the all clear, // to let textures settle down @@ -7951,10 +8080,13 @@ void LLVOAvatar::updateRuthTimer(bool loading) BOOL LLVOAvatar::isFullyLoaded() { - if (gSavedSettings.getBOOL("RenderUnloadedAvatar")) +// [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2010-09-22 (Catznip-2.2.0a) | Added: Catznip-2.2.0a + // Changes to LLAppearanceMgr::updateAppearanceFromCOF() expect this function to actually return mFullyLoaded for gAgentAvatarp + if ( (!isSelf()) && (gSavedSettings.getBOOL("RenderUnloadedAvatar")) ) return TRUE; else - return mFullyLoaded; + return mFullyLoaded; +// [/SL:KB] } @@ -9009,11 +9141,10 @@ void LLVOAvatar::clampAttachmentPositions() BOOL LLVOAvatar::hasHUDAttachment() const { for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin(); - iter != mAttachmentPoints.end(); ) + iter != mAttachmentPoints.end(); ++iter) { - attachment_map_t::const_iterator curiter = iter++; - LLViewerJointAttachment* attachment = curiter->second; - if (attachment->getIsHUDAttachment() && attachment->getObject()) + LLViewerJointAttachment* attachment = iter->second; + if (attachment->getIsHUDAttachment() && attachment->getNumObjects() > 0) { return TRUE; } @@ -9025,24 +9156,33 @@ LLBBox LLVOAvatar::getHUDBBox() const { LLBBox bbox; for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin(); - iter != mAttachmentPoints.end(); ) + iter != mAttachmentPoints.end(); ++iter) { - attachment_map_t::const_iterator curiter = iter++; - LLViewerJointAttachment* attachment = curiter->second; - if (attachment->getIsHUDAttachment() && attachment->getObject()) + LLViewerJointAttachment* attachment = iter->second; + if (attachment->getIsHUDAttachment()) { - LLViewerObject* hud_object = attachment->getObject(); - - // initialize bounding box to contain identity orientation and center point for attached object - bbox.addPointLocal(hud_object->getPosition()); - // add rotated bounding box for attached object - bbox.addBBoxAgent(hud_object->getBoundingBoxAgent()); - LLViewerObject::const_child_list_t& child_list = hud_object->getChildren(); - for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); - iter != child_list.end(); iter++) + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) { - LLViewerObject* child_objectp = *iter; - bbox.addBBoxAgent(child_objectp->getBoundingBoxAgent()); + const LLViewerObject* attached_object = (*attachment_iter); + if (attached_object == NULL) + { + llwarns << "HUD attached object is NULL!" << llendl; + continue; + } + // initialize bounding box to contain identity orientation and center point for attached object + bbox.addPointLocal(attached_object->getPosition()); + // add rotated bounding box for attached object + bbox.addBBoxAgent(attached_object->getBoundingBoxAgent()); + LLViewerObject::const_child_list_t& child_list = attached_object->getChildren(); + for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); + iter != child_list.end(); + ++iter) + { + const LLViewerObject* child_objectp = *iter; + bbox.addBBoxAgent(child_objectp->getBoundingBoxAgent()); + } } } } @@ -10493,17 +10633,22 @@ void LLVOAvatar::idleUpdateRenderCost() ++iter) { LLViewerJointAttachment* attachment = iter->second; - LLViewerObject* object = attachment->getObject(); - if (object && !object->isHUDAttachment()) + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) { - LLDrawable* drawable = object->mDrawable; - if (drawable) + const LLViewerObject* attached_object = (*attachment_iter); + if (attached_object && !attached_object->isHUDAttachment()) { - shame += 10; - LLVOVolume* volume = drawable->getVOVolume(); - if (volume) + const LLDrawable* drawable = attached_object->mDrawable; + if (drawable) { - shame += calc_shame(volume, textures); + shame += 10; + LLVOVolume* volume = drawable->getVOVolume(); + if (volume) + { + shame += calc_shame(volume, textures); + } } } } diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 1b9f3381d..aacfac2ee 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -160,6 +160,7 @@ public: void updateAttachmentVisibility(U32 camera_mode); void clampAttachmentPositions(); S32 getAttachmentCount(); // Warning: order(N) not order(1) + BOOL canAttachMoreObjects() const; // HUD functions BOOL hasHUDAttachment() const; @@ -297,15 +298,19 @@ public: void hideSkirt(); - virtual void setParent(LLViewerObject* parent); + virtual BOOL setParent(LLViewerObject* parent); virtual void addChild(LLViewerObject *childp); virtual void removeChild(LLViewerObject *childp); - LLViewerJointAttachment* getTargetAttachmentPoint(LLViewerObject* viewer_object); +// [RLVa:KB] - Checked: 2009-12-18 (RLVa-1.1.0i) | Added: RLVa-1.1.0i + LLViewerJointAttachment* getTargetAttachmentPoint(const LLViewerObject* viewer_object) const; +// [/RLVa:KB] BOOL attachObject(LLViewerObject *viewer_object); BOOL detachObject(LLViewerObject *viewer_object); void lazyAttach(); + static BOOL detachAttachmentIntoInventory(const LLUUID& item_id); + void sitOnObject(LLViewerObject *sit_object); void getOffObject(); @@ -314,8 +319,8 @@ public: BOOL isWearingUnsupportedAttachment( const LLUUID& inv_item_id ); // LLViewerObject* getWornAttachment( const LLUUID& inv_item_id ); -// [RLVa:KB] - Checked: 2009-12-18 (RLVa-1.1.0i) | Added: RLVa-1.1.0i - LLViewerJointAttachment* getWornAttachmentPoint(const LLUUID& inv_item_id); +// [RLVa:KB] - Checked: 2010-03-14 (RLVa-1.2.0a) | Added: RLVa-1.1.0i + LLViewerJointAttachment* getWornAttachmentPoint(const LLUUID& inv_item_id) const; // [/RLVa:KB] const std::string getAttachedPointName(const LLUUID& inv_item_id); @@ -599,6 +604,8 @@ public: // std::map mUnsupportedAttachmentPoints; // +protected: + U32 getNumAttachments() const; // O(N), not O(1) //-------------------------------------------------------------------- // static preferences that are controlled by user settings/menus diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index ffad1db70..b4d0dd3cd 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -63,8 +63,7 @@ #include "llworld.h" #include "llselectmgr.h" #include "pipeline.h" - -// [RLVa:KB] +// [RLVa:KB] - Checked: 2010-04-04 (RLVa-1.2.0d) #include "rlvhandler.h" // [/RLVa:KB] @@ -885,17 +884,20 @@ void LLVOVolume::updateFaceFlags() } } -void LLVOVolume::setParent(LLViewerObject* parent) +BOOL LLVOVolume::setParent(LLViewerObject* parent) { + BOOL ret = FALSE ; if (parent != getParent()) { - LLViewerObject::setParent(parent); + ret = LLViewerObject::setParent(parent); if (mDrawable) { gPipeline.markMoved(mDrawable); gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE); } } + + return ret ; } // NOTE: regenFaces() MUST be followed by genTriangles()! @@ -1941,9 +1943,9 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& e { if (!mbCanSelect || // (gHideSelectedObjects && isSelected()) || -// [RLVa:KB] - Checked: 2009-10-10 (RLVa-1.0.5a) | Modified: RLVa-1.0.5a +// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.1.3b) | Modified: RLVa-1.1.3b ( (gHideSelectedObjects && isSelected()) && - ((!rlv_handler_t::isEnabled()) || (!isHUDAttachment()) || (!gRlvHandler.isLockedAttachment(this, RLV_LOCK_REMOVE))) ) || + ((!rlv_handler_t::isEnabled()) || (!isHUDAttachment()) || (!gRlvAttachmentLocks.isLockedAttachment(getRootEdit()))) ) || // [/RLVa:KB] mDrawable->isDead() || !gPipeline.hasRenderType(mDrawable->getRenderType())) @@ -2087,17 +2089,14 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); // if (facep->getViewerObject()->isSelected() && gHideSelectedObjects) -// { -// return; -// } -// [RLVa:KB] - Checked: 2009-10-10 (RLVa-1.0.5a) | Modified: RLVa-1.0.5a - LLViewerObject* pObj = facep->getViewerObject(); +// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.1.3b) | Modified: RLVa-1.2.1f + const LLViewerObject* pObj = facep->getViewerObject(); if ( (pObj->isSelected() && gHideSelectedObjects) && - ((!rlv_handler_t::isEnabled()) || (!pObj->isHUDAttachment()) || (!gRlvHandler.isLockedAttachment(pObj, RLV_LOCK_REMOVE))) ) + ((!rlv_handler_t::isEnabled()) || (!pObj->isHUDAttachment()) || (!gRlvAttachmentLocks.isLockedAttachment(pObj->getRootEdit()))) ) +// [/RVLa:KB] { return; } -// [/RVLa:KB] //add face to drawmap LLSpatialGroup::drawmap_elem_t& draw_vec = group->mDrawMap[type]; diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h index 960f6da80..8cfb9698b 100644 --- a/indra/newview/llvovolume.h +++ b/indra/newview/llvovolume.h @@ -105,7 +105,7 @@ public: /*virtual*/ BOOL isHUDAttachment() const; void generateSilhouette(LLSelectNode* nodep, const LLVector3& view_point); - /*virtual*/ void setParent(LLViewerObject* parent); + /*virtual*/ BOOL setParent(LLViewerObject* parent); S32 getLOD() const { return mLOD; } const LLVector3 getPivotPositionAgent() const; const LLMatrix4& getRelativeXform() const { return mRelativeXform; } diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 6f72cacc9..eba3f2fe1 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -1980,10 +1980,10 @@ void LLPipeline::stateSort(LLDrawable* drawablep, LLCamera& camera) { // if (drawablep->getVObj().notNull() && // drawablep->getVObj()->isSelected()) -// [RLVa:KB] - Checked: 2009-10-10 (RLVa-1.0.5a) | Modified: RLVa-1.0.5a - LLViewerObject* pObj = drawablep->getVObj(); +// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.2.1f + const LLViewerObject* pObj = drawablep->getVObj(); if ( (pObj) && (pObj->isSelected()) && - ((!rlv_handler_t::isEnabled()) || (!pObj->isHUDAttachment()) || (!gRlvHandler.isLockedAttachment(pObj, RLV_LOCK_REMOVE))) ) + ((!rlv_handler_t::isEnabled()) || (!pObj->isHUDAttachment()) || (!gRlvAttachmentLocks.isLockedAttachment(pObj->getRootEdit()))) ) // [/RVLa:KB] { return; @@ -3366,41 +3366,45 @@ void LLPipeline::renderForSelect(std::set& objects, BOOL render LLViewerJointAttachment* attachmentp = curiter->second; if (attachmentp->getIsHUDAttachment()) { - LLViewerObject* objectp = attachmentp->getObject(); - if (objectp) + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachmentp->mAttachedObjects.begin(); + attachment_iter != attachmentp->mAttachedObjects.end(); + ++attachment_iter) { - LLDrawable* drawable = objectp->mDrawable; - if (drawable->isDead()) + if (LLViewerObject* objectp = (*attachment_iter)) { - continue; - } - - for (S32 j = 0; j < drawable->getNumFaces(); ++j) - { - LLFace* facep = drawable->getFace(j); - if (!facep->getPool()) + LLDrawable* drawable = objectp->mDrawable; + if (drawable->isDead()) { - facep->renderForSelect(prim_mask); + continue; } - } - //render child faces - LLViewerObject::const_child_list_t& child_list = objectp->getChildren(); - for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); - iter != child_list.end(); iter++) - { - LLViewerObject* child = *iter; - LLDrawable* child_drawable = child->mDrawable; - for (S32 l = 0; l < child_drawable->getNumFaces(); ++l) + for (S32 j = 0; j < drawable->getNumFaces(); ++j) { - LLFace* facep = child_drawable->getFace(l); + LLFace* facep = drawable->getFace(j); if (!facep->getPool()) { facep->renderForSelect(prim_mask); } } + + //render child faces + LLViewerObject::const_child_list_t& child_list = objectp->getChildren(); + for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); + iter != child_list.end(); iter++) + { + LLViewerObject* child = *iter; + LLDrawable* child_drawable = child->mDrawable; + for (S32 l = 0; l < child_drawable->getNumFaces(); ++l) + { + LLFace* facep = child_drawable->getFace(l); + if (!facep->getPool()) + { + facep->renderForSelect(prim_mask); + } + } + } } - } + } } } @@ -6562,10 +6566,15 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar) iter != avatar->mAttachmentPoints.end(); ++iter) { - LLViewerObject* object = iter->second->getObject(); - if (object) + LLViewerJointAttachment *attachment = iter->second; + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) { - markVisible(object->mDrawable->getSpatialBridge(), *LLViewerCamera::getInstance()); + if (LLViewerObject* attached_object = (*attachment_iter)) + { + markVisible(attached_object->mDrawable->getSpatialBridge(), *LLViewerCamera::getInstance()); + } } } diff --git a/indra/newview/rlvcommon.cpp b/indra/newview/rlvcommon.cpp index d3f4e84ea..88d1ab5a7 100644 --- a/indra/newview/rlvcommon.cpp +++ b/indra/newview/rlvcommon.cpp @@ -20,7 +20,11 @@ #include "lluictrlfactory.h" #include "llversionviewer.h" #include "llviewermenu.h" +#include "llviewerparcelmgr.h" +#include "llviewerregion.h" +#include "llviewerstats.h" #include "llvoavatar.h" +#include "llworld.h" #include "rlvcommon.h" #include "rlvhandler.h" @@ -43,6 +47,14 @@ void RlvNotifications::notifyBehaviour(ERlvBehaviour eBhvr, ERlvParamType eType) } #endif // RLV_EXTENSION_NOTIFY_BEHAVIOUR +// Checked: 2010-10-11 (RLVa-1.1.3c) | Added: RLVa-1.1.3c +void RlvNotifications::notifyBlocked(const std::string& strRlvString) +{ + LLSD argsNotify; + argsNotify["MESSAGE"] = RlvStrings::getString(strRlvString); + LLNotifications::instance().add("SystemMessageTip", argsNotify); +} + // Checked: 2009-11-11 (RLVa-1.1.0a) | Added: RLVa-1.1.0a void RlvNotifications::notifyBlockedViewXXX(const char* pstrAssetType) { @@ -105,37 +117,20 @@ void RlvSettings::initClass() if (gSavedSettings.controlExists(RLV_SETTING_SHOWNAMETAGS)) gSavedSettings.getControl(RLV_SETTING_SHOWNAMETAGS)->getSignal()->connect(boost::bind(&onChangedSettingBOOL, _1, &fShowNameTags)); + if (gSavedSettings.controlExists(RLV_SETTING_AVATAROFFSET_Z)) + gSavedSettings.getControl(RLV_SETTING_AVATAROFFSET_Z)->getSignal()->connect(boost::bind(&onChangedAvatarOffset, _1)); + fInitialized = true; } } -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()] -} - -#ifndef RLV_WORKAROUND_REZMULTIPLEATTACH -BOOL RlvSettings::getEnableSharedWear() -{ - // NOTE-RLVa: it's not proper but some code relies on the fact that getEnableSharedWear() returns FALSE if any attach point is locked - return - (rlvGetSettingBOOL(RLV_SETTING_ENABLESHAREDWEAR, FALSE)) && // "Enable Shared Wear" is toggled on and... - (!gRlvHandler.hasLockedAttachment(RLV_LOCK_ANY)); // no attachment point is non-attachable or non-detachable -} -#endif // RLV_WORKAROUND_REZMULTIPLEATTACH - #ifdef RLV_EXTENSION_STARTLOCATION - // Checked: 2009-07-08 (RLVa-1.0.0e) | Modified: RLVa-0.2.1d + // Checked: 2010-04-01 (RLVa-1.2.0c) | 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) ); + BOOL fValue = (gRlvHandler.hasBehaviour(RLV_BHVR_TPLOC)) || (!gRlvHandler.canStand()); if (gSavedPerAccountSettings.getBOOL(RLV_SETTING_LOGINLASTLOCATION) != fValue) { gSavedPerAccountSettings.setBOOL(RLV_SETTING_LOGINLASTLOCATION, fValue); @@ -145,6 +140,13 @@ BOOL RlvSettings::getEnableSharedWear() } #endif // RLV_EXTENSION_STARTLOCATION +// Checked: 2010-10-11 (RLVa-1.2.0e) | Added: RLVa-1.2.0e +bool RlvSettings::onChangedAvatarOffset(const LLSD& sdValue) +{ + gAgent.sendAgentSetAppearance(); + return true; +} + // Checked: 2009-12-18 (RLVa-1.1.0k) | Added: RLVa-1.1.0i bool RlvSettings::onChangedSettingBOOL(const LLSD& newvalue, BOOL* pfSetting) { @@ -164,7 +166,7 @@ std::map RlvStrings::m_BhvrAddMap; std::map RlvStrings::m_BhvrRemMap; #endif // RLV_EXTENSION_NOTIFY_BEHAVIOUR -// Checked: 2009-12-05 (RLVa-1.1.0h) | Added: RLVa-1.1.0h +// Checked: 2010-03-09 (RLVa-1.2.0a) | Added: RLVa-1.1.0h void RlvStrings::initClass() { static bool fInitialized = false; @@ -173,7 +175,7 @@ void RlvStrings::initClass() LLXMLNodePtr xmlRoot; if ( (!LLUICtrlFactory::getLayeredXMLNode("rlva_strings.xml", xmlRoot)) || (xmlRoot.isNull()) || (!xmlRoot->hasName("rlva_strings")) ) { - llerrs << "Problem reading RLVa string XML file" << llendl; + RLV_ERRS << "Problem reading RLVa string XML file" << RLV_ENDL; return; } @@ -221,7 +223,7 @@ void RlvStrings::initClass() if ( (m_StringMap.empty()) || (m_Anonyms.empty()) ) { - llerrs << "Problem parsing RLVa string XML file" << llendl; + RLV_ERRS << "Problem parsing RLVa string XML file" << RLV_ENDL; return; } @@ -325,12 +327,143 @@ std::string RlvStrings::getVersionAbout() RLVa_VERSION_MAJOR, RLVa_VERSION_MINOR, RLVa_VERSION_PATCH, 'a' + RLVa_VERSION_BUILD); } -// Checked: 2009-11-11 (RLVa-1.1.0a) | Modified: RLVa-1.1.0a +// Checked: 2010-03-27 (RLVa-1.2.0b) | Modified: RLVa-1.1.0a std::string RlvStrings::getVersionNum() { return llformat("%d%02d%02d%02d", RLV_VERSION_MAJOR, RLV_VERSION_MINOR, RLV_VERSION_PATCH, RLV_VERSION_BUILD); } +// Checked: 2010-05-26 (RLVa-1.2.0h) | Added: RLVa-1.2.0g +bool RlvStrings::hasString(const std::string& strStringName) +{ + return m_StringMap.find(strStringName) != m_StringMap.end(); +} + +// ============================================================================ +// RlvUtil +// + +bool RlvUtil::m_fForceTp = false; + +// Checked: 2009-07-04 (RLVa-1.0.0a) | Modified: RLVa-1.0.0a +void RlvUtil::filterLocation(std::string& strUTF8Text) +{ + // TODO-RLVa: if either the region or parcel name is a simple word such as "a" or "the" then confusion will ensue? + // -> not sure how you would go about preventing this though :|... + + // Filter any mention of the surrounding region names + LLWorld::region_list_t regions = LLWorld::getInstance()->getRegionList(); + const std::string& strHiddenRegion = RlvStrings::getString(RLV_STRING_HIDDEN_REGION); + for (LLWorld::region_list_t::const_iterator itRegion = regions.begin(); itRegion != regions.end(); ++itRegion) + rlvStringReplace(strUTF8Text, (*itRegion)->getName(), strHiddenRegion); + + // Filter any mention of the parcel name + LLViewerParcelMgr* pParcelMgr = LLViewerParcelMgr::getInstance(); + if (pParcelMgr) + rlvStringReplace(strUTF8Text, pParcelMgr->getAgentParcelName(), RlvStrings::getString(RLV_STRING_HIDDEN_PARCEL)); +} + +// Checked: 2010-04-22 (RLVa-1.2.0f) | Modified: RLVa-1.2.0f +void RlvUtil::filterNames(std::string& strUTF8Text) +{ + std::vector idAgents; + LLWorld::getInstance()->getAvatars(&idAgents, NULL); + + std::string strFullName; + for (int idxAgent = 0, cntAgent = idAgents.size(); idxAgent < cntAgent; idxAgent++) + { + // LLCacheName::getFullName() will add the UUID to the lookup queue if we don't know it yet + if (gCacheName->getFullName(idAgents[idxAgent], strFullName)) + rlvStringReplace(strUTF8Text, strFullName, RlvStrings::getAnonym(strFullName)); + } +} + +// Checked: 2010-08-29 (RLVa-1.2.1c) | Added: RLVa-1.2.1c +void RlvUtil::forceTp(const LLVector3d& posDest) +{ + m_fForceTp = true; + gAgent.teleportViaLocationLookAt(posDest); + m_fForceTp = false; +} + +// Checked: 2010-04-22 (RLVa-1.2.0f) | Modified: RLVa-1.2.0f +bool RlvUtil::isNearbyAgent(const LLUUID& idAgent) +{ + // Sanity check since we call this with notification payloads as well and those strings tend to change from one release to another + RLV_ASSERT(idAgent.notNull()); + if ( (idAgent.notNull()) && (gAgent.getID() != idAgent) ) + { + std::vector idAgents; + LLWorld::getInstance()->getAvatars(&idAgents, NULL); + + for (int idxAgent = 0, cntAgent = idAgents.size(); idxAgent < cntAgent; idxAgent++) + if (idAgents[idxAgent] == idAgent) + return true; + } + return false; +} + +// Checked: 2010-04-05 (RLVa-1.2.0d) | Modified: RLVa-1.2.0d +bool RlvUtil::isNearbyRegion(const std::string& strRegion) +{ + LLWorld::region_list_t regions = LLWorld::getInstance()->getRegionList(); + for (LLWorld::region_list_t::const_iterator itRegion = regions.begin(); itRegion != regions.end(); ++itRegion) + if ((*itRegion)->getName() == strRegion) + return true; + return false; +} + +// Checked: 2010-11-11 (RLVa-1.2.1g) | Added: RLVa-1.2.1g +void RlvUtil::notifyFailedAssertion(const std::string& strAssert, const std::string& strFile, int nLine) +{ + static std::string strAssertPrev, strFilePrev; static int nLinePrev; + if ( (strAssertPrev == strAssert) && (strFile == strFilePrev) && (nLine == nLinePrev) ) + { + // Don't show the same assertion over and over + return; + } + strAssertPrev = strAssert; + strFilePrev = strFile; + nLinePrev = nLine; + + LLSD argsNotify; + argsNotify["MESSAGE"] = llformat("RLVa assertion failure: %s (%s - %d)", strAssert.c_str(), strFile.c_str(), nLine); + LLNotifications::instance().add("SystemMessageTip", argsNotify); +} + +// Checked: 2010-03-27 (RLVa-1.1.3a) | Modified: RLVa-1.2.0b +void RlvUtil::sendBusyMessage(const LLUUID& idTo, const std::string& strMsg, const LLUUID& idSession) +{ + // [See process_improved_im()] + std::string strFullName; + gAgent.buildFullname(strFullName); + + pack_instant_message(gMessageSystem, gAgent.getID(), FALSE, gAgent.getSessionID(), idTo, strFullName, + strMsg, IM_ONLINE, IM_BUSY_AUTO_RESPONSE, idSession); + gAgent.sendReliableMessage(); +} + +// Checked: 2010-03-09 (RLVa-1.2.0a) | Modified: RLVa-1.0.1e +bool RlvUtil::sendChatReply(S32 nChannel, const std::string& strUTF8Text) +{ + if (!isValidReplyChannel(nChannel)) + return false; + + // Copy/paste from send_chat_from_viewer() + gMessageSystem->newMessageFast(_PREHASH_ChatFromViewer); + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + gMessageSystem->nextBlockFast(_PREHASH_ChatData); + gMessageSystem->addStringFast(_PREHASH_Message, strUTF8Text); + gMessageSystem->addU8Fast(_PREHASH_Type, CHAT_TYPE_SHOUT); + gMessageSystem->addS32("Channel", nChannel); + gAgent.sendReliableMessage(); + LLViewerStats::getInstance()->incStat(LLViewerStats::ST_CHAT_COUNT); + + return true; +} + // ============================================================================ // Generic menu enablers // @@ -351,10 +484,10 @@ bool RlvEnableIfNot::handleEvent(LLPointer, const LLSD& userdata) // Selection functors // -// Checked: 2009-07-06 (RLVa-1.0.0c) | Modified: RLVa-0.2.0f +// Checked: 2010-04-20 (RLVa-1.2.0f) | Modified: RLVa-0.2.0f bool RlvSelectHasLockedAttach::apply(LLSelectNode* pNode) { - return (pNode->getObject()) ? gRlvHandler.isLockedAttachment(pNode->getObject(), m_eLock) : false; + return (pNode->getObject()) ? gRlvAttachmentLocks.isLockedAttachment(pNode->getObject()->getRootEdit()) : false; } // Checked: 2009-07-05 (RLVa-1.0.0b) | Modified: RLVa-0.2.0f @@ -363,39 +496,87 @@ bool RlvSelectIsOwnedByOrGroupOwned::apply(LLSelectNode* pNode) return (pNode->mPermissions->isGroupOwned()) || (pNode->mPermissions->getOwner() == m_idAgent); } -// Checked: 2009-05-31 (RLVa-0.2.0f) | Modified: RLVa-0.2.0f +// Checked: 2010-04-01 (RLVa-1.2.0c) | Modified: RLVa-0.2.0f bool RlvSelectIsSittingOn::apply(LLSelectNode* pNode) { return (pNode->getObject()) && (pNode->getObject()->getRootEdit() == m_pObject); } +// ============================================================================ +// Predicates +// + +// Checked: 2010-11-11 (RLVa-1.2.1g) | Modified: RLVa-1.2.1g +bool rlvPredCanWearItem(const LLViewerInventoryItem* pItem, ERlvWearMask eWearMask) +{ + if ( (pItem) && (RlvForceWear::isWearableItem(pItem)) ) + { + if (RlvForceWear::isWearingItem(pItem)) + return true; // Special exception for currently worn items + switch (pItem->getType()) + { + case LLAssetType::AT_BODYPART: + // NOTE: only one body part of each type is allowed so the only way to wear one is if we can replace the current one + return (RLV_WEAR_LOCKED != (gRlvWearableLocks.canWear(pItem) & RLV_WEAR_REPLACE & eWearMask)); + case LLAssetType::AT_CLOTHING: + return (RLV_WEAR_LOCKED != (gRlvWearableLocks.canWear(pItem) & eWearMask)); + case LLAssetType::AT_OBJECT: + return (RLV_WEAR_LOCKED != (gRlvAttachmentLocks.canAttach(pItem) & eWearMask)); + case LLAssetType::AT_GESTURE: + return true; + default: + RLV_ASSERT(false); + } + } + return false; +} + +// Checked: 2010-03-22 (RLVa-1.2.0c) | Added: RLVa-1.2.0a +bool rlvPredCanNotWearItem(const LLViewerInventoryItem* pItem, ERlvWearMask eWearMask) +{ + return !rlvPredCanWearItem(pItem, eWearMask); +} + +// Checked: 2010-03-22 (RLVa-1.2.0c) | Added: RLVa-1.2.0a +bool rlvPredCanRemoveItem(const LLViewerInventoryItem* pItem) +{ + if ( (pItem) && (RlvForceWear::isWearableItem(pItem)) ) + { + switch (pItem->getType()) + { + case LLAssetType::AT_BODYPART: + case LLAssetType::AT_CLOTHING: + return gRlvWearableLocks.canRemove(pItem); + case LLAssetType::AT_OBJECT: + return gRlvAttachmentLocks.canDetach(pItem); + case LLAssetType::AT_GESTURE: + return true; + default: + RLV_ASSERT(false); + } + } + return false; +} + +// Checked: 2010-03-22 (RLVa-1.2.0c) | Added: RLVa-1.2.0a +bool rlvPredCanNotRemoveItem(const LLViewerInventoryItem* pItem) +{ + return !rlvPredCanRemoveItem(pItem); +} + // ============================================================================ // Various public helper functions // -// Checked: 2009-10-10 (RLVa-1.0.5a) | Modified: RLVa-1.0.5a +// Checked: 2010-09-28 (RLVa-1.1.3b) | Modified: RLVa-1.1.3b BOOL rlvAttachToEnabler(void* pParam) { // Visually 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-10-04 (RLVa-1.0.4b) | Modified: RLVa-1.0.4b -BOOL rlvEnableWearEnabler(void* pParam) -{ - // Visually disable the "Enable Wear" option when restricted from toggling it - return (!gRlvHandler.hasBehaviour(RLV_BHVR_DEFAULTWEAR)); -} - -// Checked: 2009-11-15 (RLVa-1.1.0c) | Added: RLVa-1.1.0c -BOOL rlvEnableSharedWearEnabler(void* pParam) -{ - // Visually disable the "Enable Shared Wear" option when at least one attachment is non-detachable - return (!gRlvHandler.hasLockedAttachment(RLV_LOCK_REMOVE)); + (!gRlvAttachmentLocks.hasLockedAttachment((LLViewerJointAttachment*)pParam)) && + (!gRlvAttachmentLocks.isLockedAttachmentPoint((LLViewerJointAttachment*)pParam, RLV_LOCK_ADD)); } // ============================================================================ diff --git a/indra/newview/rlvcommon.h b/indra/newview/rlvcommon.h index 14b750b5a..2712b765a 100644 --- a/indra/newview/rlvcommon.h +++ b/indra/newview/rlvcommon.h @@ -18,9 +18,13 @@ #define RLV_COMMON_H #include "llmemberlistener.h" +#include "llinventorymodel.h" #include "llselectmgr.h" +#include "llview.h" #include "llviewercontrol.h" +#include "llviewerinventory.h" #include "rlvdefines.h" +#include "rlvviewer2.h" // ============================================================================ // Forward declarations @@ -28,6 +32,8 @@ class RlvCommand; +typedef std::vector c_llvo_vec_t; + // ============================================================================ // RlvNotifications // @@ -36,12 +42,14 @@ class RlvNotifications { public: static void notifyBehaviour(ERlvBehaviour eBhvr, ERlvParamType eType); + static void notifyBlockedTeleport() { notifyBlocked("blocked_teleport"); } static void notifyBlockedViewNote() { notifyBlockedViewXXX(LLAssetType::lookup(LLAssetType::AT_NOTECARD)); } static void notifyBlockedViewScript() { notifyBlockedViewXXX(LLAssetType::lookup(LLAssetType::AT_SCRIPT)); } static void notifyBlockedViewTexture() { notifyBlockedViewXXX(LLAssetType::lookup(LLAssetType::AT_TEXTURE)); } static void warnGiveToRLV(); protected: + static void notifyBlocked(const std::string& strRlvString); static void notifyBlockedViewXXX(const char* pstrAssetType); static void onGiveToRLVConfirmation(const LLSD& notification, const LLSD& response); @@ -59,33 +67,47 @@ inline BOOL rlvGetPerUserSettingsBOOL(const std::string& strSetting, BOOL fDefau { return (gSavedPerAccountSettings.controlExists(strSetting)) ? gSavedPerAccountSettings.getBOOL(strSetting) : fDefault; } +inline BOOL rlvGetSettingF32(const std::string& strSetting, F32 nDefault) +{ + return (gSavedSettings.controlExists(strSetting)) ? gSavedSettings.getF32(strSetting) : nDefault; +} +inline std::string rlvGetSettingString(const std::string& strSetting, const std::string& strDefault) +{ + return (gSavedSettings.controlExists(strSetting)) ? gSavedSettings.getString(strSetting) : strDefault; +} class RlvSettings { public: - static BOOL getDebug() { return rlvGetSettingBOOL(RLV_SETTING_DEBUG, FALSE); } - static BOOL getForbidGiveToRLV() { return rlvGetSettingBOOL(RLV_SETTING_FORBIDGIVETORLV, TRUE); } - static BOOL getNoSetEnv() { return fNoSetEnv; } + static F32 getAvatarOffsetZ() { return rlvGetSettingF32(RLV_SETTING_AVATAROFFSET_Z, 0.0); } + static BOOL getDebug() { return rlvGetSettingBOOL(RLV_SETTING_DEBUG, FALSE); } + static BOOL getForbidGiveToRLV() { return rlvGetSettingBOOL(RLV_SETTING_FORBIDGIVETORLV, TRUE); } + static BOOL getNoSetEnv() { return fNoSetEnv; } + static std::string getWearAddPrefix() { return rlvGetSettingString(RLV_SETTING_WEARADDPREFIX, LLStringUtil::null); } + static std::string getWearReplacePrefix() { return rlvGetSettingString(RLV_SETTING_WEARREPLACEPREFIX, LLStringUtil::null); } + + static bool getDebugHideUnsetDup() { return rlvGetSettingBOOL(RLV_SETTING_DEBUGHIDEUNSETDUP, FALSE); } #ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS - static BOOL getEnableComposites() { return fCompositeFolders; } + static BOOL getEnableComposites() { return fCompositeFolders; } #endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS - static BOOL getEnableLegacyNaming() { return fLegacyNaming; } - static BOOL getEnableWear(); - static BOOL getEnableSharedWear(); - static BOOL getHideLockedLayers() { return rlvGetSettingBOOL(RLV_SETTING_HIDELOCKEDLAYER, FALSE); } - static BOOL getHideLockedAttach() { return rlvGetSettingBOOL(RLV_SETTING_HIDELOCKEDATTACH, FALSE); } - static BOOL getHideLockedInventory() { return rlvGetSettingBOOL(RLV_SETTING_HIDELOCKEDINVENTORY, FALSE); } - static BOOL getSharedInvAutoRename() { return rlvGetSettingBOOL(RLV_SETTING_SHAREDINVAUTORENAME, TRUE); } - static BOOL getShowNameTags() { return fShowNameTags; } + static BOOL getEnableLegacyNaming() { return fLegacyNaming; } + static BOOL getEnableWear() { return TRUE; } + static BOOL getEnableSharedWear() { return rlvGetSettingBOOL(RLV_SETTING_ENABLESHAREDWEAR, FALSE); } + static BOOL getHideLockedLayers() { return rlvGetSettingBOOL(RLV_SETTING_HIDELOCKEDLAYER, FALSE); } + static BOOL getHideLockedAttach() { return rlvGetSettingBOOL(RLV_SETTING_HIDELOCKEDATTACH, FALSE); } + static BOOL getHideLockedInventory() { return rlvGetSettingBOOL(RLV_SETTING_HIDELOCKEDINVENTORY, FALSE); } + static BOOL getSharedInvAutoRename() { return rlvGetSettingBOOL(RLV_SETTING_SHAREDINVAUTORENAME, TRUE); } + static BOOL getShowNameTags() { return fShowNameTags; } #ifdef RLV_EXTENSION_STARTLOCATION - static BOOL getLoginLastLocation() { return rlvGetPerUserSettingsBOOL(RLV_SETTING_LOGINLASTLOCATION, TRUE); } + static BOOL getLoginLastLocation() { return rlvGetPerUserSettingsBOOL(RLV_SETTING_LOGINLASTLOCATION, TRUE); } static void updateLoginLastLocation(); #endif // RLV_EXTENSION_STARTLOCATION static void initClass(); protected: + static bool onChangedAvatarOffset(const LLSD& sdValue); static bool onChangedSettingBOOL(const LLSD& newvalue, BOOL* pfSetting); #ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS @@ -96,13 +118,6 @@ protected: static BOOL fShowNameTags; }; -#ifdef RLV_WORKAROUND_REZMULTIPLEATTACH -inline BOOL RlvSettings::getEnableSharedWear() -{ - return FALSE; -} -#endif // RLV_WORKAROUND_REZMULTIPLEATTACH - // ============================================================================ // RlvStrings // @@ -119,6 +134,7 @@ public: static std::string getVersion(bool fLegacy = false); // @version static std::string getVersionAbout(); // Shown in Help / About static std::string getVersionNum(); // @versionnum + static bool hasString(const std::string& strStringName); protected: static std::vector m_Anonyms; @@ -129,6 +145,34 @@ protected: #endif // RLV_EXTENSION_NOTIFY_BEHAVIOUR }; +// ============================================================================ +// RlvUtil - Collection of (static) helper functions +// + +class RlvUtil +{ +public: + static bool isEmote(const std::string& strUTF8Text); + static bool isNearbyAgent(const LLUUID& idAgent); // @shownames + static bool isNearbyRegion(const std::string& strRegion); // @showloc + + static void filterLocation(std::string& strUTF8Text); // @showloc + static void filterNames(std::string& strUTF8Text); // @shownames + + static bool isForceTp() { return m_fForceTp; } + static void forceTp(const LLVector3d& posDest); // Ignores restrictions that might otherwise prevent tp'ing + + static void notifyFailedAssertion(const std::string& strAssert, const std::string& strFile, int nLine); + + static void sendBusyMessage(const LLUUID& idTo, const std::string& strMsg, const LLUUID& idSession = LLUUID::null); + static bool isValidReplyChannel(S32 nChannel); + static bool sendChatReply(S32 nChannel, const std::string& strUTF8Text); + static bool sendChatReply(const std::string& strChannel, const std::string& strUTF8Text); + +protected: + static bool m_fForceTp; // @standtp +}; + // ============================================================================ // Extensibility classes // @@ -144,12 +188,12 @@ class RlvCommandHandler { public: virtual ~RlvCommandHandler() {} - virtual bool onAddRemCommand(const LLUUID& idObj, const RlvCommand& rlvCmd, ERlvCmdRet& cmdRet) { return false; } - virtual bool onClearCommand(const LLUUID& idObj, const RlvCommand& rlvCmd, ERlvCmdRet& cmdRet) { return false; } - virtual bool onReplyCommand(const LLUUID& idObj, const RlvCommand& rlvCmd, ERlvCmdRet& cmdRet) { return false; } - virtual bool onForceCommand(const LLUUID& idObj, const RlvCommand& rlvCmd, ERlvCmdRet& cmdRet) { return false; } + virtual bool onAddRemCommand(const RlvCommand& rlvCmd, ERlvCmdRet& cmdRet) { return false; } + virtual bool onClearCommand(const RlvCommand& rlvCmd, ERlvCmdRet& cmdRet) { return false; } + virtual bool onReplyCommand(const RlvCommand& rlvCmd, ERlvCmdRet& cmdRet) { return false; } + virtual bool onForceCommand(const RlvCommand& rlvCmd, ERlvCmdRet& cmdRet) { return false; } }; -typedef bool (RlvCommandHandler::*rlvCommandHandler)(const LLUUID& idObj, const RlvCommand& rlvCmd, ERlvCmdRet& cmdRet); +typedef bool (RlvCommandHandler::*rlvCommandHandler)(const RlvCommand& rlvCmd, ERlvCmdRet& cmdRet); // ============================================================================ // Generic menu enablers @@ -166,16 +210,15 @@ class RlvEnableIfNot : public LLMemberListener struct RlvSelectHasLockedAttach : public LLSelectedNodeFunctor { - RlvSelectHasLockedAttach(ERlvLockMask eLock) : m_eLock(eLock) {} + RlvSelectHasLockedAttach() {} virtual bool apply(LLSelectNode* pNode); -protected: - ERlvLockMask m_eLock; }; struct RlvSelectIsOwnedByOrGroupOwned : public LLSelectedNodeFunctor { RlvSelectIsOwnedByOrGroupOwned(const LLUUID& uuid) : m_idAgent(uuid) {} virtual bool apply(LLSelectNode* pNode); +protected: LLUUID m_idAgent; }; @@ -183,6 +226,7 @@ struct RlvSelectIsSittingOn : public LLSelectedNodeFunctor { RlvSelectIsSittingOn(LLXform* pObject) : m_pObject(pObject) {} virtual bool apply(LLSelectNode* pNode); +protected: LLXform* m_pObject; }; @@ -191,8 +235,67 @@ struct RlvSelectIsSittingOn : public LLSelectedNodeFunctor // BOOL rlvAttachToEnabler(void* pParam); -BOOL rlvEnableWearEnabler(void* pParam); -BOOL rlvEnableSharedWearEnabler(void* pParam); + +// ============================================================================ +// Predicates +// + +bool rlvPredCanWearItem(const LLViewerInventoryItem* pItem, ERlvWearMask eWearMask); +bool rlvPredCanNotWearItem(const LLViewerInventoryItem* pItem, ERlvWearMask eWearMask); +bool rlvPredCanRemoveItem(const LLViewerInventoryItem* pItem); +bool rlvPredCanNotRemoveItem(const LLViewerInventoryItem* pItem); + +struct RlvPredCanWearItem +{ + RlvPredCanWearItem(ERlvWearMask eWearMask) : m_eWearMask(eWearMask) {} + bool operator()(const LLViewerInventoryItem* pItem) { return rlvPredCanWearItem(pItem, m_eWearMask); } +protected: + ERlvWearMask m_eWearMask; +}; + +struct RlvPredCanNotWearItem +{ + RlvPredCanNotWearItem(ERlvWearMask eWearMask) : m_eWearMask(eWearMask) {} + bool operator()(const LLViewerInventoryItem* pItem) { return rlvPredCanNotWearItem(pItem, m_eWearMask); } +protected: + ERlvWearMask m_eWearMask; +}; + +struct RlvPredIsEqualOrLinkedItem +{ + RlvPredIsEqualOrLinkedItem(const LLViewerInventoryItem* pItem) : m_pItem(pItem) {} + RlvPredIsEqualOrLinkedItem(const LLUUID& idItem) { m_pItem = gInventory.getItem(idItem); } + + bool operator()(const LLViewerInventoryItem* pItem) const + { + return (m_pItem) && (pItem) && (m_pItem->getLinkedUUID() == pItem->getLinkedUUID()); + } +protected: + const LLViewerInventoryItem* m_pItem; +}; + +// ============================================================================ +// Inlined class member functions +// + +// Checked: 2010-03-26 (RLVa-1.2.0b) | Modified: RLVa-1.0.2a +inline bool RlvUtil::isEmote(const std::string& strUTF8Text) +{ + return (strUTF8Text.length() > 4) && ( (strUTF8Text.compare(0, 4, "/me ") == 0) || (strUTF8Text.compare(0, 4, "/me'") == 0) ); +} + +// Checked: 2010-03-09 (RLVa-1.2.0b) | Added: RLVa-1.0.2a +inline bool RlvUtil::isValidReplyChannel(S32 nChannel) +{ + return (nChannel > 0) && (CHAT_CHANNEL_DEBUG != nChannel); +} + +// Checked: 2009-08-05 (RLVa-1.0.1e) | Added: RLVa-1.0.0e +inline bool RlvUtil::sendChatReply(const std::string& strChannel, const std::string& strUTF8Text) +{ + S32 nChannel; + return (LLStringUtil::convertToS32(strChannel, nChannel)) ? sendChatReply(nChannel, strUTF8Text) : false; +} // ============================================================================ diff --git a/indra/newview/rlvdefines.h b/indra/newview/rlvdefines.h index db11eeff2..bddb4ccfa 100644 --- a/indra/newview/rlvdefines.h +++ b/indra/newview/rlvdefines.h @@ -33,80 +33,84 @@ // Extensions #define RLV_EXTENSION_CMD_GETSETDEBUG_EX // Extends the debug variables accessible through @getdebug_xxx/@setdebug_xxx #define RLV_EXTENSION_CMD_FINDFOLDERS // @findfolders: