diff --git a/.hgpatchinfo/.RLVa.dep b/.hgpatchinfo/.RLVa.dep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/.hgpatchinfo/RLVa.dep b/.hgpatchinfo/RLVa.dep new file mode 100644 index 0000000000000000000000000000000000000000..f7595c62c565d0106a8bcdcc1cea926dfd1f9055 --- /dev/null +++ b/.hgpatchinfo/RLVa.dep @@ -0,0 +1 @@ +54ad5d2837e09f9005b1772f2273b3ce4301ef6a \ No newline at end of file diff --git a/.hgtags b/.hgtags index 2b890cd5f5cccb61aaf1726c1c2ee176dbe230c9..55785ce20e8c9509fb51fcaf05b905905ccc7ac1 100755 --- a/.hgtags +++ b/.hgtags @@ -1147,4 +1147,14 @@ e9d350764dfbf5a46229e627547ef5c1b1eeef00 SL-4.0.2 450de775fff66a011be1a001acd117cc623c445d SL-4.0.5 4070611edd95eb3a683d1cd97c4c07fe67793812 SL-4.0.6 33981d8130f031597b4c7f4c981b18359afb61a0 SL-4.0.7 -45eaee56883df7a439ed3300c44d3126f7e3a41e SL-4.0.8 \ No newline at end of file +45eaee56883df7a439ed3300c44d3126f7e3a41e SL-4.0.8 +89532c8dfd5b6c29f1cb032665b44a74a52452e1 RLVa-1.3.0 +7bc5039ccf0b36eafbf6ce33a52b5e26332aa04c RLVa-1.3.1 +a563f7e215c7883c1cfd20908085687a0ed96284 RLVa-1.4.0 +40644beae9c4a617504163d5c9f195dc7bfff1b4 RLVa-1.4.1 +8787094c309a44ca32b7472acc9217a3c37f00c3 RLVa-1.4.2 +11c6c85ddd223bcbd6b3afc53f9a0f5fd349ba65 RLVa-1.4.3 +53b44208d44a601fe24e78c1a1909dc82356cded RLVa-1.4.4 +6522747820037cc11e5b7d0491a0a9808a958709 RLVa-1.4.5 +0c8f23b2c4cf96d1a08bd527b3ccb6339a9fdb60 RLVa-1.4.6 +674db463770b78f836fc9c87a1b2235e212a576c RLVa-1.4.7 diff --git a/indra/integration_tests/llui_libtest/llui_libtest.cpp b/indra/integration_tests/llui_libtest/llui_libtest.cpp index a0418f09d50b21867074cb178057b4a7afb1f2d4..36409a6fb7d0b04fd184c99e34d81bc03f4d5874 100644 --- a/indra/integration_tests/llui_libtest/llui_libtest.cpp +++ b/indra/integration_tests/llui_libtest/llui_libtest.cpp @@ -52,6 +52,17 @@ LLControlGroup gSavedSettings("Global"); // saved at end of session LLControlGroup gSavedPerAccountSettings("PerAccount"); // saved at end of session LLControlGroup gWarningSettings("Warnings"); // persists ignored dialogs/warnings +// [RLVa:KB] - Checked: 2010-11-12 (RLVa-1.2.2a) | Added: RLVa-1.2.2a +#include "llavatarname.h" + +// Stub for rlvGetAnonym +const std::string& rlvGetAnonym(const LLAvatarName& avName) +{ + static std::string strAnonym = "A resident"; + return strAnonym; +} +// [/RLVa:KB] + // We can't create LLImageGL objects because we have no window or rendering // context. Provide enough of an LLUIImage to test the LLUI library without // an underlying image. diff --git a/indra/llappearance/llwearabledata.cpp b/indra/llappearance/llwearabledata.cpp index 2bf3b9085b813e75a2992ede703ab60b7502954a..c826e1ff2471a9b350635afdd387deac4cd87387 100644 --- a/indra/llappearance/llwearabledata.cpp +++ b/indra/llappearance/llwearabledata.cpp @@ -103,7 +103,15 @@ void LLWearableData::pushWearable(const LLWearableType::EType type, } if (canAddWearable(type)) { - mWearableDatas[type].push_back(wearable); +// [RLVa:KB] - Checked: 2010-06-08 (RLVa-1.2.0) + // Don't add the same wearable twice + U32 idxWearable = 0; + if (!getWearableIndex(wearable, idxWearable)) + mWearableDatas[type].push_back(wearable); + else + llassert(false); // pushWearable() on an already added wearable is a bug *somewhere* +// [/RLVa:KB] +// mWearableDatas[type].push_back(wearable); mWearableDatas[type].push_back(wearable); if (trigger_updated) { const BOOL removed = FALSE; @@ -150,16 +158,16 @@ void LLWearableData::eraseWearable(const LLWearableType::EType type, U32 index) } } -void LLWearableData::clearWearableType(const LLWearableType::EType type) -{ - wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(type); - if (wearable_iter == mWearableDatas.end()) - { - return; - } - wearableentry_vec_t& wearable_vec = wearable_iter->second; - wearable_vec.clear(); -} +//void LLWearableData::clearWearableType(const LLWearableType::EType type) +//{ +// wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(type); +// if (wearable_iter == mWearableDatas.end()) +// { +// return; +// } +// wearableentry_vec_t& wearable_vec = wearable_iter->second; +// wearable_vec.clear(); +//} bool LLWearableData::swapWearables(const LLWearableType::EType type, U32 index_a, U32 index_b) { diff --git a/indra/llappearance/llwearabledata.h b/indra/llappearance/llwearabledata.h index a0c446ea9e2bc6810ff85e8249c0251e0efd7e15..cb274ca52453932f86a5ae34768ccc5b396d539c 100644 --- a/indra/llappearance/llwearabledata.h +++ b/indra/llappearance/llwearabledata.h @@ -79,7 +79,7 @@ class LLWearableData virtual void wearableUpdated(LLWearable *wearable, BOOL removed); void eraseWearable(LLWearable *wearable); void eraseWearable(const LLWearableType::EType type, U32 index); - void clearWearableType(const LLWearableType::EType type); +// void clearWearableType(const LLWearableType::EType type); bool swapWearables(const LLWearableType::EType type, U32 index_a, U32 index_b); private: diff --git a/indra/llappearance/llwearabletype.cpp b/indra/llappearance/llwearabletype.cpp index 0cc8a6975833e5913ae6b6bb78e7b12131d29701..8df4ff4de661ee3b495a4379f7d951408a98604f 100644 --- a/indra/llappearance/llwearabletype.cpp +++ b/indra/llappearance/llwearabletype.cpp @@ -73,6 +73,12 @@ class LLWearableDictionary : public LLSingleton<LLWearableDictionary>, { public: LLWearableDictionary(); + +// [RLVa:KB] - Checked: 2010-03-03 (RLVa-1.2.0a) | Added: RLVa-1.2.0a +protected: + // The default implementation asserts on 'notFound()' and returns -1 which isn't a valid EWearableType + virtual LLWearableType::EType notFound() const { return LLWearableType::WT_INVALID; } +// [/RLVa:KB] }; LLWearableDictionary::LLWearableDictionary() diff --git a/indra/llmessage/llavatarnamecache.cpp b/indra/llmessage/llavatarnamecache.cpp index 1ca5f58ae2742f568163091757ecd046d49fba0f..9ce75e739083d7faab421dd280155a60027efcea 100644 --- a/indra/llmessage/llavatarnamecache.cpp +++ b/indra/llmessage/llavatarnamecache.cpp @@ -51,6 +51,11 @@ namespace LLAvatarNameCache { use_display_name_signal_t mUseDisplayNamesSignal; +// [RLVa:KB] - Checked: 2010-12-08 (RLVa-1.4.0a) | Added: RLVa-1.2.2c + // RLVa override for display names + bool sForceDisplayNames = false; +// [/RLVa:KB] + // Cache starts in a paused state until we can determine if the // current region supports display names. bool sRunning = false; @@ -724,10 +729,30 @@ LLAvatarNameCache::callback_connection_t LLAvatarNameCache::get(const LLUUID& ag return connection; } +// [RLVa:KB] - Checked: 2010-12-08 (RLVa-1.4.0a) | Added: RLVa-1.2.2c +bool LLAvatarNameCache::getForceDisplayNames() +{ + return sForceDisplayNames; +} + +void LLAvatarNameCache::setForceDisplayNames(bool force) +{ + sForceDisplayNames = force; + if ( (!LLAvatarName::useDisplayNames()) && (force) ) + { + LLAvatarName::setUseDisplayNames(true); + } +} +// [/RLVa:KB] void LLAvatarNameCache::setUseDisplayNames(bool use) { +// [RLVa:KB] - Checked: 2010-12-08 (RLVa-1.4.0a) | Added: RLVa-1.2.2c + // We need to force the use of the "display names" cache when @shownames=n restricted (and disallow toggling it) + use |= getForceDisplayNames(); +// [/RLVa:KB] if (use != LLAvatarName::useDisplayNames()) + { LLAvatarName::setUseDisplayNames(use); mUseDisplayNamesSignal(); diff --git a/indra/llmessage/llavatarnamecache.h b/indra/llmessage/llavatarnamecache.h index bd2715e9567607d7f15d57124c63190dea6d5513..36f2d18d96ec4edfa74bb3a624bf1f783f3279a2 100644 --- a/indra/llmessage/llavatarnamecache.h +++ b/indra/llmessage/llavatarnamecache.h @@ -82,6 +82,12 @@ namespace LLAvatarNameCache void setUseUsernames(bool use); void insert(const LLUUID& agent_id, const LLAvatarName& av_name); + +// [RLVa:KB] - Checked: 2010-12-08 (RLVa-1.4.0a) | Added: RLVa-1.2.2c + bool getForceDisplayNames(); + void setForceDisplayNames(bool force); +// [/RLVa:KB] + void erase(const LLUUID& agent_id); /// Provide some fallback for agents that return errors. diff --git a/indra/llui/llchat.h b/indra/llui/llchat.h index f5b242fdfcddabbbba473dff6b405ad63103d35c..746103b9115590a9cc9400931457848ee79f57f1 100644 --- a/indra/llui/llchat.h +++ b/indra/llui/llchat.h @@ -81,6 +81,10 @@ class LLChat mChatType(CHAT_TYPE_NORMAL), mAudible(CHAT_AUDIBLE_FULLY), mMuted(FALSE), +// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Modified: RLVa-1.0.0a + mRlvLocFiltered(FALSE), + mRlvNamesFiltered(FALSE), +// [/RLVa:KB] mTime(0.0), mTimeStr(), mPosAgent(), @@ -98,6 +102,10 @@ class LLChat EChatType mChatType; EChatAudible mAudible; BOOL mMuted; // pass muted chat to maintain list of chatters +// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Modified: RLVa-1.0.0a + BOOL mRlvLocFiltered; + BOOL mRlvNamesFiltered; +// [/RLVa:KB] F64 mTime; // viewer only, seconds from viewer start std::string mTimeStr; LLVector3 mPosAgent; diff --git a/indra/llui/llflatlistview.h b/indra/llui/llflatlistview.h index 92bf429031d216a9a3e85209bb8058816cbe1713..577e4867052ec261bb86279853cf656e3515b777 100644 --- a/indra/llui/llflatlistview.h +++ b/indra/llui/llflatlistview.h @@ -469,6 +469,9 @@ class LLFlatListViewEx : public LLFlatListView // *WORKAROUND: two methods to overload appropriate Params due to localization issue: // no_items_msg & no_filtered_items_msg attributes are not defined as translatable in VLT. See EXT-5931 +// [RLVa:KB] - Checked: RLVa-2.0.3 + const std::string& getNoItemsMsg() const { return mNoItemsMsg; } +// [/RLVa:KB] void setNoItemsMsg(const std::string& msg) { mNoItemsMsg = msg; } void setNoFilteredItemsMsg(const std::string& msg) { mNoFilteredItemsMsg = msg; } diff --git a/indra/llui/llfloaterreg.cpp b/indra/llui/llfloaterreg.cpp index 9ef290abc024cd6629c876d12bad94ad768611b2..8e2dc0338c3590f135992a9d5186ac7b01efa2fd 100644 --- a/indra/llui/llfloaterreg.cpp +++ b/indra/llui/llfloaterreg.cpp @@ -45,6 +45,10 @@ std::set<std::string> LLFloaterReg::sAlwaysShowableList; static LLFloaterRegListener sFloaterRegListener; +// [RLVa:KB] - Checked: 2010-02-28 (RLVa-1.4.0a) | Modified: RLVa-1.2.0a +LLFloaterReg::validate_signal_t LLFloaterReg::mValidateSignal; +// [/RLVa:KB] + //******************************************************* //static @@ -240,12 +244,23 @@ LLFloaterReg::const_instance_list_t& LLFloaterReg::getFloaterList(const std::str // Visibility Management +// [RLVa:KB] - Checked: 2012-02-07 (RLVa-1.4.5) | Added: RLVa-1.4.5 +//static +bool LLFloaterReg::canShowInstance(const std::string& name, const LLSD& key) +{ + return mValidateSignal(name, key); +} +// [/RLVa:KB] + //static LLFloater* LLFloaterReg::showInstance(const std::string& name, const LLSD& key, BOOL focus) { - if( sBlockShowFloaters - // see EXT-7090 - && sAlwaysShowableList.find(name) == sAlwaysShowableList.end()) +// if( sBlockShowFloaters +// // see EXT-7090 +// && sAlwaysShowableList.find(name) == sAlwaysShowableList.end()) +// [RLVa:KB] - Checked: 2010-02-28 (RLVa-1.4.0a) | Modified: RLVa-1.2.0a + if ( (sBlockShowFloaters && sAlwaysShowableList.find(name) == sAlwaysShowableList.end()) || (!mValidateSignal(name, key)) ) +// [/RLVa:KB] return 0;// LLFloater* instance = getInstance(name, key); if (instance) diff --git a/indra/llui/llfloaterreg.h b/indra/llui/llfloaterreg.h index e3b17dcb4fc7507e8846984b61027732275bb0f4..5bafe6466473634237af880d650eb3e1e85e5a8a 100644 --- a/indra/llui/llfloaterreg.h +++ b/indra/llui/llfloaterreg.h @@ -32,6 +32,10 @@ #include <list> #include <boost/function.hpp> +// [RLVa:KB] - Checked: 2011-05-25 (RLVa-1.4.0a) +#include <boost/signals2.hpp> +#include "llboost.h" +// [/RLVa:KB] //******************************************************* // @@ -72,6 +76,15 @@ class LLFloaterReg */ static std::set<std::string> sAlwaysShowableList; +// [RLVa:KB] - Checked: 2010-02-28 (RLVa-1.4.0a) | Modified: RLVa-1.2.0a + // Used to determine whether a floater can be shown +public: + typedef boost::signals2::signal<bool(const std::string&, const LLSD&), boost_boolean_combiner> validate_signal_t; + static boost::signals2::connection setValidateCallback(const validate_signal_t::slot_type& cb) { return mValidateSignal.connect(cb); } +private: + static validate_signal_t mValidateSignal; +// [/RLVa:KB] + public: // Registration @@ -100,6 +113,10 @@ class LLFloaterReg static const_instance_list_t& getFloaterList(const std::string& name); // Visibility Management +// [RLVa:KB] - Checked: 2012-02-07 (RLVa-1.4.5) | Added: RLVa-1.4.5 + // return false if floater can not be shown (=doesn't pass the validation filter) + static bool canShowInstance(const std::string& name, const LLSD& key = LLSD()); +// [/RLVa:KB] // return NULL if instance not found or can't create instance (no builder) static LLFloater* showInstance(const std::string& name, const LLSD& key = LLSD(), BOOL focus = FALSE); // Close a floater (may destroy or set invisible) diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp index 0cb959a3155a4ba230f7b3b635a3da6f6c95ed77..d02adc0596ac8935511f1d2ef9a18ab7b2ec9ac9 100644 --- a/indra/llui/llnotifications.cpp +++ b/indra/llui/llnotifications.cpp @@ -918,6 +918,13 @@ std::string LLNotification::getLabel() const return (mTemplatep ? label : ""); } +// [SL:KB] - Patch: UI-Notifications | Checked: 2011-04-11 (Catznip-2.5.0a) | Added: Catznip-2.5.0a +bool LLNotification::hasLabel() const +{ + return !mTemplatep->mLabel.empty(); +} +// [/SL:KB] + std::string LLNotification::getURL() const { if (!mTemplatep) diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h index 354add0b82a0e022bc8d64f8bb53d49c463bf48e..b50938fd944fa942f36f32d67f91ecf24bff1e9e 100644 --- a/indra/llui/llnotifications.h +++ b/indra/llui/llnotifications.h @@ -532,6 +532,10 @@ friend class LLNotifications; return mTimestamp; } +// [SL:KB] - Patch: UI-Notifications | Checked: 2011-04-11 (Catznip-2.5.0a) | Added: Catznip-2.5.0a + bool hasLabel() const; +// [/SL:KB] + bool getOfferFromAgent() const { return mOfferFromAgent; diff --git a/indra/llui/lltoolbar.cpp b/indra/llui/lltoolbar.cpp index abc2b6e9cac2025efa9983566c81e7d9a81d99d1..978cecc0e362a0665be20a1d171d8f7db07bc108 100644 --- a/indra/llui/lltoolbar.cpp +++ b/indra/llui/lltoolbar.cpp @@ -1221,6 +1221,9 @@ void LLToolBarButton::setEnabled(BOOL enabled) mImageOverlayColor = mImageOverlayDisabledColor; mImageOverlaySelectedColor = mImageOverlayDisabledColor; } +// [RLVa:KB] - Checked: 2011-12-17 (RLVa-1.4.5a) | Added: RLVa-1.4.5a + LLButton::setEnabled(enabled); +// [/RLVa:KB] } const std::string LLToolBarButton::getToolTip() const diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp index aabc7ed2e423b61fc6cbff0a63b7f5cfeb4fd121..cd1572a544957aa5ceadedec472224fa6def2df4 100644 --- a/indra/llui/llui.cpp +++ b/indra/llui/llui.cpp @@ -201,6 +201,9 @@ void LLUI::initClass(const settings_map_t& settings, // Used by menus along with Floater.Toggle to display visibility as a check-mark LLUICtrl::EnableCallbackRegistry::defaultRegistrar().add("Floater.Visible", boost::bind(&LLFloaterReg::instanceVisible, _2, LLSD())); LLUICtrl::EnableCallbackRegistry::defaultRegistrar().add("Floater.IsOpen", boost::bind(&LLFloaterReg::instanceVisible, _2, LLSD())); +// [RLVa:KB] - Checked: 2012-02-07 (RLVa-1.4.5) | Added: RLVa-1.4.5 + LLUICtrl::EnableCallbackRegistry::defaultRegistrar().add("Floater.CanShow", boost::bind(&LLFloaterReg::canShowInstance, _2, LLSD())); +// [/RLVa:KB] // Parse the master list of commands LLCommandManager::load(); diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp index e4848362a76bcfd4ac0edf8f4ee52f9cfb86c798..41b6df8229daa2512b59060b56b60fd6d6808e0c 100644 --- a/indra/llui/llurlentry.cpp +++ b/indra/llui/llurlentry.cpp @@ -792,6 +792,27 @@ std::string LLUrlEntryAgentUserName::getName(const LLAvatarName& avatar_name) return avatar_name.getAccountName(); } +// [RLVa:KB] - Checked: 2010-11-01 (RLVa-1.2.2a) | Added: RLVa-1.2.2a + +// Defined in rlvcommon.cpp - redirects to RlvStrings::getAnonym() since we can't really get to that class from here +extern const std::string& rlvGetAnonym(const LLAvatarName& avName); + +// +// LLUrlEntryAgentRLVAnonymizedName Describes an RLV anonymized agent name Url, e.g., +// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/rlvanonym +// x-grid-location-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/rlvanonym +// +LLUrlEntryAgentRLVAnonymizedName::LLUrlEntryAgentRLVAnonymizedName() +{ + mPattern = boost::regex(APP_HEADER_REGEX "/agent/[\\da-f-]+/rlvanonym", boost::regex::perl|boost::regex::icase); +} + +std::string LLUrlEntryAgentRLVAnonymizedName::getName(const LLAvatarName& avatar_name) +{ + return rlvGetAnonym(avatar_name); +} +// [/RLVa:KB] + // // LLUrlEntryGroup Describes a Second Life group Url, e.g., // secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/about diff --git a/indra/llui/llurlentry.h b/indra/llui/llurlentry.h index 413c20a6577168bd3ff0478625fad6af926c5eed..8316353d2b34d1fa19dff66f44402453bda79634 100644 --- a/indra/llui/llurlentry.h +++ b/indra/llui/llurlentry.h @@ -295,6 +295,21 @@ class LLUrlEntryAgentUserName : public LLUrlEntryAgentName /*virtual*/ std::string getName(const LLAvatarName& avatar_name); }; +// [RLVa:KB] - Checked: 2010-11-01 (RLVa-1.2.2a) | Added: RLVa-1.2.2a +/// +/// LLUrlEntryAgentRLVAnonymizedName Describes an RLV anonymized agent name Url, e.g., +/// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/rlvanonym +/// that diplays an anonym (based on the display name) for an avatar +/// such as "An individual" +class LLUrlEntryAgentRLVAnonymizedName : public LLUrlEntryAgentName +{ +public: + LLUrlEntryAgentRLVAnonymizedName(); +private: + /*virtual*/ std::string getName(const LLAvatarName& avatar_name); +}; +// [/RLVa:KB] + /// /// LLUrlEntryExperienceProfile Describes a Second Life experience profile Url, e.g., /// secondlife:///app/experience/0e346d8b-4433-4d66-a6b0-fd37083abc4c/profile diff --git a/indra/llui/llurlregistry.cpp b/indra/llui/llurlregistry.cpp index 23c6d5a954cc89dd4a2eb12bf6dc1ab93baf3166..81910a5dd68b5185144c0cf59070c30ac271a0bd 100644 --- a/indra/llui/llurlregistry.cpp +++ b/indra/llui/llurlregistry.cpp @@ -38,7 +38,10 @@ void LLUrlRegistryNullCallback(const std::string &url, const std::string &label, LLUrlRegistry::LLUrlRegistry() { - mUrlEntry.reserve(20); +// mUrlEntry.reserve(20); +// [RLVa:KB] - Checked: 2010-11-01 (RLVa-1.2.2a) | Added: RLVa-1.2.2a + mUrlEntry.reserve(21); +// [/RLVa:KB] // Urls are matched in the order that they were registered mUrlEntryNoLink = new LLUrlEntryNoLink(); @@ -59,6 +62,9 @@ LLUrlRegistry::LLUrlRegistry() registerUrl(new LLUrlEntryAgentCompleteName()); registerUrl(new LLUrlEntryAgentDisplayName()); registerUrl(new LLUrlEntryAgentUserName()); +// [RLVa:KB] - Checked: 2010-11-01 (RLVa-1.2.2a) | Added: RLVa-1.2.2a + registerUrl(new LLUrlEntryAgentRLVAnonymizedName()); +// [/RLVa:KB] // LLUrlEntryAgent*Name must appear before LLUrlEntryAgent since // LLUrlEntryAgent is a less specific (catchall for agent urls) registerUrl(new LLUrlEntryAgent()); diff --git a/indra/llui/tests/llurlentry_stub.cpp b/indra/llui/tests/llurlentry_stub.cpp index f01178c374c6fac0c30026c6c9100979e5d7842c..ec6fcf4d75d8f3ff351414411a9ea527b52346cf 100644 --- a/indra/llui/tests/llurlentry_stub.cpp +++ b/indra/llui/tests/llurlentry_stub.cpp @@ -34,6 +34,15 @@ #include <string> +// [RLVa:KB] - Checked: 2010-11-12 (RLVa-1.2.2a) | Added: RLVa-1.2.2a +// Stub for rlvGetAnonym +const std::string& rlvGetAnonym(const LLAvatarName& avName) +{ + static std::string strAnonym = "A resident"; + return strAnonym; +} +// [/RLVa:KB] + // Stub for LLAvatarNameCache bool LLAvatarNameCache::get(const LLUUID& agent_id, LLAvatarName *av_name) { diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 896e87be586e246cd4e025e653798555c249fec3..9b0599435205398499077b2a3a2cde767aa0bf69 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -703,6 +703,15 @@ set(viewer_SOURCE_FILES llxmlrpctransaction.cpp noise.cpp pipeline.cpp + rlvactions.cpp + rlvhandler.cpp + rlvhelper.cpp + rlvcommon.cpp + rlvlocks.cpp + rlvinventory.cpp + rlvextensions.cpp + rlvfloaters.cpp + rlvui.cpp ) set(VIEWER_BINARY_NAME "secondlife-bin" CACHE STRING @@ -1313,6 +1322,16 @@ set(viewer_HEADER_FILES macmain.h noise.h pipeline.h + rlvactions.h + rlvdefines.h + rlvhandler.h + rlvhelper.h + rlvcommon.h + rlvlocks.h + rlvinventory.h + rlvextensions.h + rlvfloaters.h + rlvui.h roles_constants.h VertexCache.h VorbisFramework.h diff --git a/indra/newview/app_settings/commands.xml b/indra/newview/app_settings/commands.xml index a0d3dc0f998ace803f3c6dbc614f1213e2d7694b..7435bcd412e1affe0d42dcc22a522da4c625a0f3 100644 --- a/indra/newview/app_settings/commands.xml +++ b/indra/newview/app_settings/commands.xml @@ -7,6 +7,8 @@ tooltip_ref="Command_AboutLand_Tooltip" execute_function="Floater.ToggleOrBringToFront" execute_parameters="about_land" + is_enabled_function="Floater.CanShow" + is_enabled_parameters="about_land" is_running_function="Floater.IsOpen" is_running_parameters="about_land" /> @@ -98,6 +100,8 @@ tooltip_ref="Command_Inventory_Tooltip" execute_function="Floater.ToggleOrBringToFront" execute_parameters="inventory" + is_enabled_function="RLV.EnableIfNot" + is_enabled_parameters="showinv" is_running_function="Floater.IsOpen" is_running_parameters="inventory" /> @@ -108,6 +112,8 @@ tooltip_ref="Command_Map_Tooltip" execute_function="Floater.ToggleOrBringToFront" execute_parameters="world_map" + is_enabled_function="RLV.EnableIfNot" + is_enabled_parameters="showworldmap" is_running_function="Floater.IsOpen" is_running_parameters="world_map" /> @@ -137,6 +143,8 @@ tooltip_ref="Command_MiniMap_Tooltip" execute_function="Floater.ToggleOrBringToFront" execute_parameters="mini_map" + is_enabled_function="RLV.EnableIfNot" + is_enabled_parameters="showminimap" is_running_function="Floater.IsOpen" is_running_parameters="mini_map" /> diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 5f5add75b6010de336518b696443dc6a8762c5c2..bba92ad872193ac027adf33afbd8aed4ebb87766 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -2,6 +2,259 @@ <llsd xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="llsd.xsd"> <map> + <key>RestrainedLove</key> + <map> + <key>Comment</key> + <string>Toggles RLVa features (requires restart)</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <boolean>1</boolean> + </map> + <key>RestrainedLoveDebug</key> + <map> + <key>Comment</key> + <string>Toggles RLVa debug mode (displays the commands when in debug mode)</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <boolean>0</boolean> + </map> + <key>RestrainedLoveCanOOC</key> + <map> + <key>Comment</key> + <string>Allows sending OOC chat when send chat restricted, or seeing OOC chat when receive chat restricted</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <boolean>1</boolean> + </map> + <key>RestrainedLoveForbidGiveToRLV</key> + <map> + <key>Comment</key> + <string>When TRUE, forbids to give sub-folders to the #RLV folder</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <boolean>0</boolean> + </map> + <key>RestrainedLoveNoSetEnv</key> + <map> + <key>Comment</key> + <string>When TRUE, forbids to set the environment (time of day and Windlight settings) via RLVa. (requires restart)</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <boolean>0</boolean> + </map> + <key>RestrainedLoveReplaceWhenFolderBeginsWith</key> + <map> + <key>Comment</key> + <string>If a folder name begins with this string, its attach behavior will always be "replace", never "stack". Default is blank (disabled).</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>String</string> + <key>Value</key> + <string></string> + </map> + <key>RestrainedLoveShowEllipsis</key> + <map> + <key>Comment</key> + <string>When TRUE, show "..." when someone speaks, while the avatar is prevented from hearing. When FALSE, don't show anything.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <boolean>1</boolean> + </map> + <key>RestrainedLoveStackWhenFolderBeginsWith</key> + <map> + <key>Comment</key> + <string>If a folder name begins with this string, its attach behavior will always be "stack", never "replace". Default is "+".</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>String</string> + <key>Value</key> + <string>+</string> + </map> + <key>RLVaCompatibilityModeList</key> + <map> + <key>Comment</key> + <string>Contains a list of creators or partial items names that require compatibility mode handling (see wiki for more information and syntax)</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>String</string> + <key>Value</key> + <string></string> + </map> + <key>RLVaDebugDeprecateExplicitPoint</key> + <map> + <key>Comment</key> + <string>Ignore attachment point names on inventory items and categories (incomplete)</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <boolean>0</boolean> + </map> + <key>RLVaDebugHideUnsetDuplicate</key> + <map> + <key>Comment</key> + <string>Suppresses reporting "unset" or "duplicate" command restrictions when RestrainedLoveDebug is TRUE</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <boolean>0</boolean> + </map> + <key>RLVaEnableCompositeFolders</key> + <map> + <key>Comment</key> + <string>Enables composite folders for shared inventory</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <boolean>0</boolean> + </map> + <key>RLVaEnableIMQuery</key> + <map> + <key>Comment</key> + <string>Enables a limited number of configuration queries via IM (e.g. @version)</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <boolean>1</boolean> + </map> + <key>RLVaEnableLegacyNaming</key> + <map> + <key>Comment</key> + <string>Enables legacy naming convention for folders</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <boolean>1</boolean> + </map> + <key>RLVaEnableSharedWear</key> + <map> + <key>Comment</key> + <string>Attachments in the shared #RLV folder can be force-attached without needing to specify an attachment point</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <boolean>1</boolean> + </map> + <key>RLVaEnableTemporaryAttachments</key> + <map> + <key>Comment</key> + <string>Allows temporary attachments (regardless of origin) to issue RLV commands</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <boolean>1</boolean> + </map> + <key>RLVaExperimentalCommands</key> + <map> + <key>Comment</key> + <string>Enables the experimental command set</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <boolean>1</boolean> + </map> + <key>RLVaHideLockedLayers</key> + <map> + <key>Comment</key> + <string>Hides "remove outfit" restricted worn clothing layers from @getoufit</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <boolean>0</boolean> + </map> + <key>RLVaHideLockedAttachments</key> + <map> + <key>Comment</key> + <string>Hides non-detachable worn attachments from @getattach</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <boolean>0</boolean> + </map> + <key>RLVaSharedInvAutoRename</key> + <map> + <key>Comment</key> + <string>Automatically renames shared inventory items when worn</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <boolean>1</boolean> + </map> + <key>RLVaShowAssertionFailures</key> + <map> + <key>Comment</key> + <string>Notify the user when an assertion fails</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <boolean>1</boolean> + </map> + <key>RLVaTopLevelMenu</key> + <map> + <key>Comment</key> + <string>Show the RLVa specific menu as a top level menu</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <boolean>1</boolean> + </map> + <key>RLVaWearReplaceUnlocked</key> + <map> + <key>Comment</key> + <string>Don't block wear replace when at least one attachment on the target attachment point is non-detachable</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <boolean>1</boolean> + </map> <key>ImporterDebug</key> <map> <key>Comment</key> @@ -4339,6 +4592,17 @@ <key>Value</key> <integer>0</integer> </map> + <key>ForceMissingType</key> + <map> + <key>Comment</key> + <string>Force this wearable type to be missing from COF</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>U32</string> + <key>Value</key> + <integer>255</integer> + </map> <key>FreezeTime</key> <map> <key>Comment</key> @@ -6816,6 +7080,17 @@ <key>Value</key> <integer>305</integer> </map> + <key>NotificationCanEmbedInIM</key> + <map> + <key>Comment</key> + <string>Controls notification panel embedding in IMs (0 = default, 1 = focused, 2 = never)</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>S32</string> + <key>Value</key> + <integer>0</integer> + </map> <key>NotificationConferenceIMOptions</key> <map> <key>Comment</key> @@ -11129,7 +11404,7 @@ <key>Type</key> <string>Boolean</string> <key>Value</key> - <integer>1</integer> + <boolean>1</boolean> </map> <key>NearbyListShowIcons</key> <map> diff --git a/indra/newview/app_settings/settings_per_account.xml b/indra/newview/app_settings/settings_per_account.xml index fd6b1b5b3f032bfad6fd1d9819f355db2e40ac62..05ec070b12b6c7dab7c385e1b9703da9d3bb910e 100644 --- a/indra/newview/app_settings/settings_per_account.xml +++ b/indra/newview/app_settings/settings_per_account.xml @@ -1,5 +1,16 @@ <llsd> <map> + <key>RLVaLoginLastLocation</key> + <map> + <key>Comment</key> + <string>Determines whether the next login will be forced to the last logoff location (set by the viewer)</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <boolean>1</boolean> + </map> <key>AvatarHoverOffsetZ</key> <map> <key>Comment</key> diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index d933537d2e63d5dd57c4c7bf35168bfb292bbb8b..6c31e3304917a969d05f48f77aad71e0d934d647 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -93,6 +93,12 @@ #include "stringize.h" #include "boost/foreach.hpp" #include "llcorehttputil.h" +// [RLVa:KB] - Checked: 2011-11-04 (RLVa-1.4.4a) +#include "rlvactions.h" +#include "rlvhandler.h" +#include "rlvhelper.h" +#include "rlvui.h" +// [/RLVa:KB] using namespace LLAvatarAppearanceDefines; @@ -202,7 +208,10 @@ class LLTeleportRequestViaLocation : public LLTeleportRequest class LLTeleportRequestViaLocationLookAt : public LLTeleportRequestViaLocation { public: - LLTeleportRequestViaLocationLookAt(const LLVector3d &pPosGlobal); +// [RLVa:KB] - Checked: RLVa-2.0.0 + LLTeleportRequestViaLocationLookAt(const LLVector3d &pPosGlobal, const LLVector3& look_at); +// [/RLVa:KB] +// LLTeleportRequestViaLocationLookAt(const LLVector3d &pPosGlobal); virtual ~LLTeleportRequestViaLocationLookAt(); virtual bool canRestartTeleport(); @@ -211,8 +220,14 @@ class LLTeleportRequestViaLocationLookAt : public LLTeleportRequestViaLocation virtual void restartTeleport(); protected: +// [RLVa:KB] - Checked: RLVa-2.0.0 + const LLVector3& getLookAt() const { return mLookAt; } +// [/RLVa:KB] private: +// [RLVa:KB] - Checked: RLVa-2.0.0 + LLVector3 mLookAt; +// [/RLVa:KB] }; @@ -356,7 +371,10 @@ LLAgent::LLAgent() : mDoubleTapRunMode(DOUBLETAP_NONE), mbAlwaysRun(false), - mbRunning(false), +// mbRunning(false), +// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i + mbTempRun(false), +// [/RLVa:KB] mbTeleportKeepsLookAt(false), mAgentAccess(new LLAgentAccess(gSavedSettings)), @@ -525,11 +543,11 @@ LLAgent::~LLAgent() //----------------------------------------------------------------------------- void LLAgent::onAppFocusGained() { - if (CAMERA_MODE_MOUSELOOK == gAgentCamera.getCameraMode()) - { - gAgentCamera.changeCameraToDefault(); - LLToolMgr::getInstance()->clearSavedTool(); - } +// if (CAMERA_MODE_MOUSELOOK == gAgentCamera.getCameraMode()) +// { +// gAgentCamera.changeCameraToDefault(); +// LLToolMgr::getInstance()->clearSavedTool(); +// } } @@ -715,6 +733,9 @@ void LLAgent::movePitch(F32 mag) // Does this parcel allow you to fly? BOOL LLAgent::canFly() { +// [RLVa:KB] - Checked: 2010-03-02 (RLVa-1.2.0d) | Modified: RLVa-1.0.0c + if (gRlvHandler.hasBehaviour(RLV_BHVR_FLY)) return FALSE; +// [/RLVa:KB] if (isGodlike()) return TRUE; LLViewerRegion* regionp = getRegion(); @@ -763,6 +784,13 @@ void LLAgent::setFlying(BOOL fly) if (fly) { +// [RLVa:KB] - Checked: 2010-03-02 (RLVa-1.2.0d) | Modified: RLVa-1.0.0c + if (gRlvHandler.hasBehaviour(RLV_BHVR_FLY)) + { + return; + } +// [/RLVa:KB] + BOOL was_flying = getFlying(); if (!canFly() && !was_flying) { @@ -825,7 +853,14 @@ bool LLAgent::enableFlying() void LLAgent::standUp() { - setControlFlags(AGENT_CONTROL_STAND_UP); +// setControlFlags(AGENT_CONTROL_STAND_UP); +// [RLVa:KB] - Checked: 2010-03-07 (RLVa-1.2.0c) | Added: RLVa-1.2.0a + // RELEASE-RLVa: [SL-2.0.0] Check this function's callers since usually they require explicit blocking + if ( (!rlv_handler_t::isEnabled()) || (RlvActions::canStand()) ) + { + setControlFlags(AGENT_CONTROL_STAND_UP); + } +// [/RLVa:KB] } void LLAgent::changeParcels() @@ -921,7 +956,10 @@ void LLAgent::setRegion(LLViewerRegion *regionp) LLSelectMgr::getInstance()->updateSelectionCenter(); - LLFloaterMove::sUpdateFlyingStatus(); +// LLFloaterMove::sUpdateFlyingStatus(); +// [RLVa:KB] - Checked: 2011-05-27 (RLVa-1.4.0a) | Added: RLVa-1.4.0a + LLFloaterMove::sUpdateMovementStatus(); +// [/RLVa:KB] LL_DEBUGS("AgentLocation") << "Calling RegionChanged callbacks" << LL_ENDL; mRegionChangedSignal(); @@ -1149,7 +1187,14 @@ LLVector3d LLAgent::getPosGlobalFromAgent(const LLVector3 &pos_agent) const void LLAgent::sitDown() { - setControlFlags(AGENT_CONTROL_SIT_ON_GROUND); +// setControlFlags(AGENT_CONTROL_SIT_ON_GROUND); +// [RLVa:KB] - Checked: 2010-08-28 (RLVa-1.2.1a) | Added: RLVa-1.2.1a + // RELEASE-RLVa: [SL-2.0.0] Check this function's callers since usually they require explicit blocking + if ( (!rlv_handler_t::isEnabled()) || ((RlvActions::canStand()) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SIT))) ) + { + setControlFlags(AGENT_CONTROL_SIT_ON_GROUND); + } +// [/RLVa:KB] } @@ -1895,7 +1940,10 @@ std::ostream& operator<<(std::ostream &s, const LLAgent &agent) //----------------------------------------------------------------------------- BOOL LLAgent::needsRenderAvatar() { - if (gAgentCamera.cameraMouselook() && !LLVOAvatar::sVisibleInFirstPerson) +// if (gAgentCamera.cameraMouselook() && !LLVOAvatar::sVisibleInFirstPerson) +// [RLVa:KB] - Checked: RLVa-2.0.2 + if ( (gAgentCamera.cameraMouselook() && !LLVOAvatar::sVisibleInFirstPerson) || (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWSELF)) ) +// [/RLVa:KB] { return FALSE; } @@ -1906,7 +1954,10 @@ BOOL LLAgent::needsRenderAvatar() // TRUE if we need to render your own avatar's head. BOOL LLAgent::needsRenderHead() { - return (LLVOAvatar::sVisibleInFirstPerson && LLPipeline::sReflectionRender) || (mShowAvatar && !gAgentCamera.cameraMouselook()); +// [RLVa:KB] - Checked: RLVa-2.0.2 + return ((LLVOAvatar::sVisibleInFirstPerson && LLPipeline::sReflectionRender) || (mShowAvatar && !gAgentCamera.cameraMouselook())) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWSELFHEAD)); +// [/RLVa:KB] +// return (LLVOAvatar::sVisibleInFirstPerson && LLPipeline::sReflectionRender) || (mShowAvatar && !gAgentCamera.cameraMouselook()); } //----------------------------------------------------------------------------- @@ -2432,7 +2483,11 @@ void LLAgent::onAnimStop(const LLUUID& id) } else if (id == ANIM_AGENT_AWAY) { - clearAFK(); +// [RLVa:KB] - Checked: 2010-05-03 (RLVa-1.2.0g) | Added: RLVa-1.1.0g + if (!gRlvHandler.hasBehaviour(RLV_BHVR_ALLOWIDLE)) + clearAFK(); +// [/RLVa:KB] +// clearAFK(); } else if (id == ANIM_AGENT_STANDUP) { @@ -3097,7 +3152,36 @@ void LLAgent::sendRevokePermissions(const LLUUID & target, U32 permissions) } } -void LLAgent::sendWalkRun(bool running) +// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i +void LLAgent::setAlwaysRun() +{ + mbAlwaysRun = (!rlv_handler_t::isEnabled()) || (!gRlvHandler.hasBehaviour(RLV_BHVR_ALWAYSRUN)); + sendWalkRun(); +} + +void LLAgent::setTempRun() +{ + mbTempRun = (!rlv_handler_t::isEnabled()) || (!gRlvHandler.hasBehaviour(RLV_BHVR_TEMPRUN)); + sendWalkRun(); +} + +void LLAgent::clearAlwaysRun() +{ + mbAlwaysRun = false; + sendWalkRun(); +} + +void LLAgent::clearTempRun() +{ + mbTempRun = false; + sendWalkRun(); +} +// [/RLVa:KB] + +//void LLAgent::sendWalkRun(bool running) +// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i +void LLAgent::sendWalkRun() +// [/RLVa:KB] { LLMessageSystem* msgsys = gMessageSystem; if (msgsys) @@ -3106,7 +3190,10 @@ void LLAgent::sendWalkRun(bool running) msgsys->nextBlockFast(_PREHASH_AgentData); msgsys->addUUIDFast(_PREHASH_AgentID, getID()); msgsys->addUUIDFast(_PREHASH_SessionID, getSessionID()); - msgsys->addBOOLFast(_PREHASH_AlwaysRun, BOOL(running) ); +// msgsys->addBOOLFast(_PREHASH_AlwaysRun, BOOL(running) ); +// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i + msgsys->addBOOLFast(_PREHASH_AlwaysRun, BOOL(getRunning()) ); +// [/RLVa:KB] sendReliableMessage(); } } @@ -3931,10 +4018,13 @@ void LLAgent::handleTeleportFailed() } } -void LLAgent::teleportRequest( - const U64& region_handle, - const LLVector3& pos_local, - bool look_at_from_camera) +//void LLAgent::teleportRequest( +// const U64& region_handle, +// const LLVector3& pos_local, +// bool look_at_from_camera) +// [RLVa:KB] - Checked: RLVa-2.0.0 +void LLAgent::teleportRequest(const U64& region_handle, const LLVector3& pos_local, const LLVector3& look_at) +// [/RLVa:KB] { LLViewerRegion* regionp = getRegion(); bool is_local = (region_handle == regionp->getHandle()); @@ -3950,11 +4040,11 @@ void LLAgent::teleportRequest( msg->nextBlockFast(_PREHASH_Info); msg->addU64("RegionHandle", region_handle); msg->addVector3("Position", pos_local); - LLVector3 look_at(0,1,0); - if (look_at_from_camera) - { - look_at = LLViewerCamera::getInstance()->getAtAxis(); - } +// LLVector3 look_at(0,1,0); +// if (look_at_from_camera) +// { +// look_at = LLViewerCamera::getInstance()->getAtAxis(); +// } msg->addVector3("LookAt", look_at); sendReliableMessage(); } @@ -3963,6 +4053,18 @@ void LLAgent::teleportRequest( // Landmark ID = LLUUID::null means teleport home void LLAgent::teleportViaLandmark(const LLUUID& landmark_asset_id) { +// [RLVa:KB] - Checked: 2010-08-22 (RLVa-1.2.1a) | Modified: RLVa-1.2.1a + // NOTE: we'll allow teleporting home unless both @tplm=n *and* @tploc=n restricted + if ( (rlv_handler_t::isEnabled()) && + ( ( (landmark_asset_id.notNull()) ? gRlvHandler.hasBehaviour(RLV_BHVR_TPLM) + : gRlvHandler.hasBehaviour(RLV_BHVR_TPLM) && gRlvHandler.hasBehaviour(RLV_BHVR_TPLOC) ) || + ((gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) && (isAgentAvatarValid()) && (gAgentAvatarp->isSitting())) )) + { + RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_TELEPORT); + return; + } +// [/RLVa:KB] + mTeleportRequest = LLTeleportRequestPtr(new LLTeleportRequestViaLandmark(landmark_asset_id)); startTeleportRequest(); } @@ -4055,6 +4157,22 @@ void LLAgent::restoreCanceledTeleportRequest() void LLAgent::teleportViaLocation(const LLVector3d& pos_global) { +// [RLVa:KB] - Checked: RLVa-2.0.0 + if ( (RlvActions::isRlvEnabled()) && (!RlvUtil::isForceTp()) ) + { + if ( (RlvActions::isLocalTp(pos_global)) ? !RlvActions::canTeleportToLocal(pos_global) : !RlvActions::canTeleportToLocation() ) + { + RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_TELEPORT); + return; + } + + if ( (gRlvHandler.getCurrentCommand()) && (RLV_BHVR_TPTO == gRlvHandler.getCurrentCommand()->getBehaviourType()) ) + { + gRlvHandler.setCanCancelTp(false); + } + } +// [/RLVa:KB] + mTeleportRequest = LLTeleportRequestPtr(new LLTeleportRequestViaLocation(pos_global)); startTeleportRequest(); } @@ -4107,15 +4225,37 @@ void LLAgent::doTeleportViaLocation(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: RLVa-2.0.0 +void LLAgent::teleportViaLocationLookAt(const LLVector3d& pos_global, const LLVector3& look_at) { - mTeleportRequest = LLTeleportRequestPtr(new LLTeleportRequestViaLocationLookAt(pos_global)); + if ( (RlvActions::isRlvEnabled()) && (!RlvUtil::isForceTp()) ) + { + if ( (RlvActions::isLocalTp(pos_global)) ? !RlvActions::canTeleportToLocal(pos_global) : !RlvActions::canTeleportToLocation() ) + { + RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_TELEPORT); + return; + } + + if ( (gRlvHandler.getCurrentCommand()) && (RLV_BHVR_TPTO == gRlvHandler.getCurrentCommand()->getBehaviourType()) ) + { + gRlvHandler.setCanCancelTp(false); + } + } + + mTeleportRequest = LLTeleportRequestPtr(new LLTeleportRequestViaLocationLookAt(pos_global, (look_at.isExactlyZero()) ? LLViewerCamera::getInstance()->getAtAxis() : look_at)); startTeleportRequest(); } +// [/RLVa:KB] +//void LLAgent::teleportViaLocationLookAt(const LLVector3d& pos_global) +//{ +// mTeleportRequest = LLTeleportRequestPtr(new LLTeleportRequestViaLocationLookAt(pos_global)); +// startTeleportRequest(); +//} -void LLAgent::doTeleportViaLocationLookAt(const LLVector3d& pos_global) +// [RLVa:KB] - Checked: RLVa-2.0.0 +void LLAgent::doTeleportViaLocationLookAt(const LLVector3d& pos_global, const LLVector3& look_at) { - mbTeleportKeepsLookAt = true; + mbTeleportKeepsLookAt = look_at.isExactlyZero(); if(!gAgentCamera.isfollowCamLocked()) { @@ -4124,8 +4264,23 @@ void LLAgent::doTeleportViaLocationLookAt(const LLVector3d& pos_global) U64 region_handle = to_region_handle(pos_global); LLVector3 pos_local = (LLVector3)(pos_global - from_region_handle(region_handle)); - teleportRequest(region_handle, pos_local, getTeleportKeepsLookAt()); + teleportRequest(region_handle, pos_local, look_at); } +// [/RLVa:KB] +//void LLAgent::doTeleportViaLocationLookAt(const LLVector3d& pos_global, const LLVector3& look_at) +//{ +// mbTeleportKeepsLookAt = true; +// +// if(!gAgentCamera.isfollowCamLocked()) +// { +// gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE); // detach camera form avatar, so it keeps direction +// } +// +// U64 region_handle = to_region_handle(pos_global); +// LLVector3 pos_local = (LLVector3)(pos_global - from_region_handle(region_handle)); +// teleportRequest(region_handle, pos_local, look_at); +// teleportRequest(region_handle, pos_local, getTeleportKeepsLookAt()); +//} LLAgent::ETeleportState LLAgent::getTeleportState() const { @@ -4594,11 +4749,18 @@ void LLTeleportRequestViaLocation::restartTeleport() // LLTeleportRequestViaLocationLookAt //----------------------------------------------------------------------------- -LLTeleportRequestViaLocationLookAt::LLTeleportRequestViaLocationLookAt(const LLVector3d &pPosGlobal) - : LLTeleportRequestViaLocation(pPosGlobal) +// [RLVa:KB] - Checked: RLVa-2.0.0 +LLTeleportRequestViaLocationLookAt::LLTeleportRequestViaLocationLookAt(const LLVector3d &pPosGlobal, const LLVector3& look_at) + : LLTeleportRequestViaLocation(pPosGlobal), mLookAt(look_at) { LL_INFOS("Teleport") << "LLTeleportRequestViaLocationLookAt created" << LL_ENDL; } +// [/RLVa:KB] + +//LLTeleportRequestViaLocationLookAt::LLTeleportRequestViaLocationLookAt(const LLVector3d &pPosGlobal) +// : LLTeleportRequestViaLocation(pPosGlobal) +//{ +//} LLTeleportRequestViaLocationLookAt::~LLTeleportRequestViaLocationLookAt() { @@ -4614,13 +4776,19 @@ bool LLTeleportRequestViaLocationLookAt::canRestartTeleport() void LLTeleportRequestViaLocationLookAt::startTeleport() { LL_INFOS("Teleport") << "LLTeleportRequestViaLocationLookAt::startTeleport" << LL_ENDL; - gAgent.doTeleportViaLocationLookAt(getPosGlobal()); +// [RLVa:KB] - Checked: RLVa-2.0.0 + gAgent.doTeleportViaLocationLookAt(getPosGlobal(), getLookAt()); +// [/RLVa:KB] +// gAgent.doTeleportViaLocationLookAt(getPosGlobal()); } void LLTeleportRequestViaLocationLookAt::restartTeleport() { LL_INFOS("Teleport") << "LLTeleportRequestViaLocationLookAt::restartTeleport" << LL_ENDL; - gAgent.doTeleportViaLocationLookAt(getPosGlobal()); +// [RLVa:KB] - Checked: RLVa-2.0.0 + gAgent.doTeleportViaLocationLookAt(getPosGlobal(), getLookAt()); +// [/RLVa:KB] +// gAgent.doTeleportViaLocationLookAt(getPosGlobal()); } // EOF diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h index 3a533c2cba7564b981020476845af74eaab26ebd..981dda6c7a967ff92158d65fec8e6426f8b0d080 100644 --- a/indra/newview/llagent.h +++ b/indra/newview/llagent.h @@ -408,19 +408,31 @@ class LLAgent : public LLOldEvents::LLObservable DOUBLETAP_SLIDERIGHT }; - void setAlwaysRun() { mbAlwaysRun = true; } - void clearAlwaysRun() { mbAlwaysRun = false; } - void setRunning() { mbRunning = true; } - void clearRunning() { mbRunning = false; } - void sendWalkRun(bool running); +// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i + void setAlwaysRun(); + void setTempRun(); + void clearAlwaysRun(); + void clearTempRun(); + void sendWalkRun(); + bool getTempRun() { return mbTempRun; } + bool getRunning() const { return (mbAlwaysRun) || (mbTempRun); } +// [/RLVa:KB] +// void setAlwaysRun() { mbAlwaysRun = true; } +// void clearAlwaysRun() { mbAlwaysRun = false; } +// void setRunning() { mbRunning = true; } +// void clearRunning() { mbRunning = false; } +// void sendWalkRun(bool running); bool getAlwaysRun() const { return mbAlwaysRun; } - bool getRunning() const { return mbRunning; } +// bool getRunning() const { return mbRunning; } public: LLFrameTimer mDoubleTapRunTimer; EDoubleTapRunMode mDoubleTapRunMode; private: bool mbAlwaysRun; // Should the avatar run by default rather than walk? - bool mbRunning; // Is the avatar trying to run right now? +// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i + bool mbTempRun; +// [/RLVa:KB] +// bool mbRunning; // Is the avatar trying to run right now? bool mbTeleportKeepsLookAt; // Try to keep look-at after teleport is complete //-------------------------------------------------------------------- @@ -628,7 +640,10 @@ class LLAgent : public LLOldEvents::LLObservable void teleportHome() { teleportViaLandmark(LLUUID::null); } // Go home void teleportViaLure(const LLUUID& lure_id, BOOL godlike); // To an invited location void teleportViaLocation(const LLVector3d& pos_global); // To a global location - this will probably need to be deprecated - void teleportViaLocationLookAt(const LLVector3d& pos_global);// To a global location, preserving camera rotation +// [RLVa:KB] - Checked: RLVa-2.0.0 + void teleportViaLocationLookAt(const LLVector3d& pos_global, const LLVector3& look_at = LLVector3::zero);// To a global location, preserving camera rotation +// [/RLVa:KB] +// void teleportViaLocationLookAt(const LLVector3d& pos_global);// To a global location, preserving camera rotation void teleportCancel(); // May or may not be allowed by server void restoreCanceledTeleportRequest(); bool getTeleportKeepsLookAt() { return mbTeleportKeepsLookAt; } // Whether look-at reset after teleport @@ -665,13 +680,19 @@ class LLAgent : public LLOldEvents::LLObservable bool hasPendingTeleportRequest(); void startTeleportRequest(); - void teleportRequest(const U64& region_handle, - const LLVector3& pos_local, // Go to a named location home - bool look_at_from_camera = false); +// [RLVa:KB] - Checked: RLVa-2.0.0 + void teleportRequest(const U64& region_handle, const LLVector3& pos_local, const LLVector3& look_at = LLVector3(0, 1, 0)); +// [/RLVa:KB] +// void teleportRequest(const U64& region_handle, +// const LLVector3& pos_local, // Go to a named location home +// bool look_at_from_camera = false); void doTeleportViaLandmark(const LLUUID& landmark_id); // Teleport to a landmark void doTeleportViaLure(const LLUUID& lure_id, BOOL godlike); // To an invited location void doTeleportViaLocation(const LLVector3d& pos_global); // To a global location - this will probably need to be deprecated - void doTeleportViaLocationLookAt(const LLVector3d& pos_global);// To a global location, preserving camera rotation +// [RLVa:KB] - Checked: RLVa-2.0.0 + void doTeleportViaLocationLookAt(const LLVector3d& pos_global, const LLVector3& look_at);// To a global location, preserving camera rotation +// [/RLVa:KB] +// void doTeleportViaLocationLookAt(const LLVector3d& pos_global);// To a global location, preserving camera rotation void handleTeleportFinished(); void handleTeleportFailed(); diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp index fa16f02c16cc154e0c0214871b9b1bda4c204dad..0d6a6073163e37c8019cac585939d15847ac6836 100644 --- a/indra/newview/llagentcamera.cpp +++ b/indra/newview/llagentcamera.cpp @@ -50,6 +50,10 @@ #include "llvoavatarself.h" #include "llwindow.h" #include "llworld.h" +// [RLVa:KB] - Checked: 2010-05-10 (RLVa-1.2.0g) +#include "rlvactions.h" +#include "rlvhandler.h" +// [/RLVa:KB] using namespace LLAvatarAppearanceDefines; @@ -208,10 +212,18 @@ void LLAgentCamera::init() mCameraOffsetInitial[CAMERA_PRESET_REAR_VIEW] = gSavedSettings.getControl("CameraOffsetRearView"); mCameraOffsetInitial[CAMERA_PRESET_FRONT_VIEW] = gSavedSettings.getControl("CameraOffsetFrontView"); mCameraOffsetInitial[CAMERA_PRESET_GROUP_VIEW] = gSavedSettings.getControl("CameraOffsetGroupView"); +// [RLVa:KB] - Checked: RLVa-2.0.0 + mCameraOffsetInitial[CAMERA_RLV_SETCAM_VIEW] = gSavedSettings.declareVec3("CameraOffsetRLVaView", LLVector3(mCameraOffsetInitial[CAMERA_PRESET_REAR_VIEW]->getDefault()), "Declared in code", LLControlVariable::PERSIST_NO); + mCameraOffsetInitial[CAMERA_RLV_SETCAM_VIEW]->setHiddenFromSettingsEditor(true); +// [/RLVa:KB] mFocusOffsetInitial[CAMERA_PRESET_REAR_VIEW] = gSavedSettings.getControl("FocusOffsetRearView"); mFocusOffsetInitial[CAMERA_PRESET_FRONT_VIEW] = gSavedSettings.getControl("FocusOffsetFrontView"); mFocusOffsetInitial[CAMERA_PRESET_GROUP_VIEW] = gSavedSettings.getControl("FocusOffsetGroupView"); +// [RLVa:KB] - Checked: RLVa-2.0.0 + mFocusOffsetInitial[CAMERA_RLV_SETCAM_VIEW] = gSavedSettings.declareVec3("FocusOffsetRLVaView", LLVector3(mFocusOffsetInitial[CAMERA_PRESET_REAR_VIEW]->getDefault()), "Declared in code", LLControlVariable::PERSIST_NO); + mFocusOffsetInitial[CAMERA_RLV_SETCAM_VIEW]->setHiddenFromSettingsEditor(true); +// [/RLVa:KB] mCameraCollidePlane.clearVec(); mCurrentCameraDistance = getCameraOffsetInitial().magVec() * gSavedSettings.getF32("CameraOffsetScale"); @@ -809,7 +821,13 @@ void LLAgentCamera::setCameraZoomFraction(F32 fraction) LLVector3d camera_offset_dir = mCameraFocusOffsetTarget; camera_offset_dir.normalize(); - mCameraFocusOffsetTarget = camera_offset_dir * rescale(fraction, 0.f, 1.f, max_zoom, min_zoom); +// [RLVa:KB] - Checked: 2.0.0 + const LLVector3d focus_offset_target = camera_offset_dir * rescale(fraction, 0.f, 1.f, max_zoom, min_zoom); + if ( (RlvActions::isRlvEnabled()) && (!allowFocusOffsetChange(focus_offset_target)) ) + return; + mCameraFocusOffsetTarget = focus_offset_target; +// [/RLVa:KB] +// mCameraFocusOffsetTarget = camera_offset_dir * rescale(fraction, 0.f, 1.f, max_zoom, min_zoom); } startCameraAnimation(); } @@ -934,6 +952,11 @@ void LLAgentCamera::cameraZoomIn(const F32 fraction) new_distance = llclamp( new_distance, APPEARANCE_MIN_ZOOM, APPEARANCE_MAX_ZOOM ); } +// [RLVa:KB] - Checked: 2.0.0 + if ( (RlvActions::isRlvEnabled()) && (!allowFocusOffsetChange(new_distance * camera_offset_unit)) ) + return; +// [/RLVa:KB] + mCameraFocusOffsetTarget = new_distance * camera_offset_unit; } @@ -997,6 +1020,11 @@ void LLAgentCamera::cameraOrbitIn(const F32 meters) new_distance = llclamp( new_distance, APPEARANCE_MIN_ZOOM, APPEARANCE_MAX_ZOOM ); } +// [RLVa:KB] - Checked: 2.0.0 + if ( (RlvActions::isRlvEnabled()) && (!allowFocusOffsetChange(new_distance * camera_offset_unit)) ) + return; +// [/RLVa:KB] + // Compute new camera offset mCameraFocusOffsetTarget = new_distance * camera_offset_unit; cameraZoomIn(1.f); @@ -1141,6 +1169,14 @@ void LLAgentCamera::updateCamera() mCameraUpVector = LLVector3::z_axis; //LLVector3 camera_skyward(0.f, 0.f, 1.f); +// [RLVa:KB] - Checked: RLVa-2.0.0 + // Set focus back on our avie if something changed it + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_UNLOCK)) && (cameraThirdPerson()) && (!getFocusOnAvatar()) ) + { + setFocusOnAvatar(TRUE, FALSE); + } +// [/RLVa:KB] + U32 camera_mode = mCameraAnimating ? mLastCameraMode : mCameraMode; validateFocusObject(); @@ -1911,6 +1947,44 @@ LLVector3d LLAgentCamera::calcCameraPositionTargetGlobal(BOOL *hit_limit) // } } +// [RLVa:KB] - Checked: RLVa-2.0.0 + if ( (CAMERA_MODE_THIRD_PERSON == mCameraMode) && (RlvActions::isRlvEnabled()) && (RlvActions::isCameraDistanceClamped()) ) + { + m_fRlvMinDist = m_fRlvMaxDist = false; + + // Av-locked | Focus-locked | Result + // =================================================== + // T | T | skip focus => slam av + // T | F | skip focus => slam av + // F | T | skip av => slam focus + // F | F | clamp focus then av + bool fCamAvDistClamped, fCamAvDistLocked = false; float nCamAvDistLimitMin, nCamAvDistLimitMax; + if (fCamAvDistClamped = RlvActions::getCameraAvatarDistanceLimits(nCamAvDistLimitMin, nCamAvDistLimitMax)) + fCamAvDistLocked = nCamAvDistLimitMin == nCamAvDistLimitMax; + bool fCamOriginDistClamped, fCamOriginDistLocked = false; float nCamOriginDistLimitMin, nCamOriginDistLimitMax; + if (fCamOriginDistClamped = RlvActions::getCameraOriginDistanceLimits(nCamOriginDistLimitMin, nCamOriginDistLimitMax)) + fCamOriginDistLocked = nCamOriginDistLimitMin == nCamOriginDistLimitMax; + + // Check focus distance limits + if ( (fCamOriginDistClamped) && (!fCamAvDistLocked) ) + { + const LLVector3 offsetCameraLocal = mCameraZoomFraction * getCameraOffsetInitial() * gSavedSettings.getF32("CameraOffsetScale"); + const LLVector3d offsetCamera(gAgent.getFrameAgent().rotateToAbsolute(offsetCameraLocal)); + const LLVector3d posFocusCam = frame_center_global + head_offset + offsetCamera; + if (clampCameraPosition(camera_position_global, posFocusCam, nCamOriginDistLimitMin, nCamOriginDistLimitMax)) + isConstrained = TRUE; + } + + // Check avatar distance limits + if ( (fCamAvDistClamped) && (fCamAvDistLocked || !fCamOriginDistClamped) ) + { + const LLVector3d posAvatarCam = gAgent.getPosGlobalFromAgent( (isAgentAvatarValid()) ? gAgentAvatarp->mHeadp->getWorldPosition() : gAgent.getPositionAgent() ); + if (clampCameraPosition(camera_position_global, posAvatarCam, nCamAvDistLimitMin, nCamAvDistLimitMax)) + isConstrained = TRUE; + } + } +// [/RLVa:KB] + // Don't let camera go underground F32 camera_min_off_ground = getCameraMinOffGround(); @@ -1931,6 +2005,49 @@ LLVector3d LLAgentCamera::calcCameraPositionTargetGlobal(BOOL *hit_limit) return camera_position_global; } +// [RLVa:KB] - Checked: RLVa-2.0.0 +bool LLAgentCamera::allowFocusOffsetChange(const LLVector3d& offsetFocus) +{ + if (RlvActions::isCameraDistanceClamped()) + { + if ( (CAMERA_MODE_THIRD_PERSON == getCameraMode()) && ((m_fRlvMinDist) || (m_fRlvMaxDist)) ) + { + const LLVector3d posFocusGlobal = calcFocusPositionTargetGlobal(); + // Don't allow moving the focus offset if at minimum and moving closer (or if at maximum and moving further) to prevent camera warping + F32 nCurDist = llabs((posFocusGlobal + mCameraFocusOffsetTarget - m_posRlvRefGlobal).magVec()); + F32 nNewDist = llabs((posFocusGlobal + offsetFocus - m_posRlvRefGlobal).magVec()); + if ( ((m_fRlvMaxDist) && (nNewDist > nCurDist)) || ((m_fRlvMinDist) && (nNewDist < nCurDist)) ) + return false; + } + } + return true; +} + +bool LLAgentCamera::clampCameraPosition(LLVector3d& posCamGlobal, const LLVector3d posCamRefGlobal, float nDistMin, float nDistMax) +{ + const LLVector3d offsetCamera = posCamGlobal - posCamRefGlobal; + + F32 nCamAvDist = llabs(offsetCamera.magVec()), nDistMult = NAN; + if (nCamAvDist > nDistMax) + { + nDistMult = nDistMax / nCamAvDist; + m_fRlvMaxDist = true; + } + else if (nCamAvDist < nDistMin) + { + nDistMult = nDistMin / nCamAvDist; + m_fRlvMinDist = true; + } + + if (!isnan(nDistMult)) + { + posCamGlobal = posCamRefGlobal + nDistMult * offsetCamera; + m_posRlvRefGlobal = posCamRefGlobal; + return true; + } + return false; +} +// [/RLVa:KB] LLVector3 LLAgentCamera::getCameraOffsetInitial() { @@ -2033,6 +2150,10 @@ void LLAgentCamera::resetCamera() void LLAgentCamera::changeCameraToMouselook(BOOL animate) { if (!gSavedSettings.getBOOL("EnableMouselook") +// [RLVa:KB] - Checked: RLVa-2.0.0 + || ( (RlvActions::isRlvEnabled()) && (!RlvActions::canChangeToMouselook()) ) +// [/RLVa:KB] + || LLViewerJoystick::getInstance()->getOverrideCamera()) { return; @@ -2058,8 +2179,8 @@ void LLAgentCamera::changeCameraToMouselook(BOOL animate) //gViewerWindow->stopGrab(); LLSelectMgr::getInstance()->deselectAll(); - gViewerWindow->hideCursor(); - gViewerWindow->moveCursorToCenter(); +// gViewerWindow->hideCursor(); +// gViewerWindow->moveCursorToCenter(); if (mCameraMode != CAMERA_MODE_MOUSELOOK) { @@ -2253,6 +2374,13 @@ void LLAgentCamera::changeCameraToCustomizeAvatar() return; } +// [RLVa:KB] - Checked: 2010-03-07 (RLVa-1.2.0c) | Modified: RLVa-1.0.0g + if ( (rlv_handler_t::isEnabled()) && (!RlvActions::canStand()) ) + { + return; + } +// [/RLVa:KB] + gAgent.standUp(); // force stand up gViewerWindow->getWindow()->resetBusyCount(); @@ -2314,6 +2442,26 @@ void LLAgentCamera::changeCameraToCustomizeAvatar() void LLAgentCamera::switchCameraPreset(ECameraPreset preset) { +// [RLVa:KB] - Checked: RLVa-2.0.0 + if (RlvActions::isRlvEnabled()) + { + // Don't allow changing away from the our view if an object is restricting it + if (RlvActions::isCameraPresetLocked()) + preset = CAMERA_RLV_SETCAM_VIEW; + + // Don't reset anything if our view is already current + if ( (CAMERA_RLV_SETCAM_VIEW == preset) && (CAMERA_RLV_SETCAM_VIEW == mCameraPreset) ) + return; + + // Reset our view when switching away + if (CAMERA_RLV_SETCAM_VIEW != preset) + { + mCameraOffsetInitial[CAMERA_RLV_SETCAM_VIEW]->resetToDefault(); + mFocusOffsetInitial[CAMERA_RLV_SETCAM_VIEW]->resetToDefault(); + } + } +// [/RLVa:KB] + //zoom is supposed to be reset for the front and group views mCameraZoomFraction = 1.f; diff --git a/indra/newview/llagentcamera.h b/indra/newview/llagentcamera.h index ab793ff316b2ea54eef884323d6b81506b66a07b..969a86ab558ae3c0e01cabf47d176ba65e90145b 100644 --- a/indra/newview/llagentcamera.h +++ b/indra/newview/llagentcamera.h @@ -56,7 +56,12 @@ enum ECameraPreset CAMERA_PRESET_FRONT_VIEW, /** "Above and to the left, over the shoulder, pulled back a little on the zoom" */ - CAMERA_PRESET_GROUP_VIEW + CAMERA_PRESET_GROUP_VIEW, + +// [RLVa:KB] - Checked: RLVa-2.0.0 + /* Used by RLVa */ + CAMERA_RLV_SETCAM_VIEW +// [/RLVa:KB] }; //------------------------------------------------------------------------ @@ -300,6 +305,18 @@ class LLAgentCamera F32 mHUDTargetZoom; // Target zoom level for HUD objects (used when editing) F32 mHUDCurZoom; // Current animated zoom level for HUD objects +// [RLVa:KB] - Checked: RLVa-2.0.0 + //-------------------------------------------------------------------- + // RLVa + //-------------------------------------------------------------------- +protected: + bool allowFocusOffsetChange(const LLVector3d& offsetFocus); + bool clampCameraPosition(LLVector3d& posCamGlobal, const LLVector3d posCamRefGlobal, float nDistMin, float nDistMax); + + bool m_fRlvMaxDist; // True if the camera is at max distance + bool m_fRlvMinDist; // True if the camera is at min distance + LLVector3d m_posRlvRefGlobal; // Current reference point for distance calculations +// [/RLVa:KB] /******************************************************************************** ** ** diff --git a/indra/newview/llagentlistener.cpp b/indra/newview/llagentlistener.cpp index 7887184a11b01ed3968a6c4f5298c1e7d0caf0bf..85bae5cd7592f6ecf22b81b039f588250fb28687 100644 --- a/indra/newview/llagentlistener.cpp +++ b/indra/newview/llagentlistener.cpp @@ -43,6 +43,11 @@ #include "lltoolgrab.h" #include "llhudeffectlookat.h" #include "llagentcamera.h" +// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a) +#include "rlvactions.h" +#include "rlvhandler.h" +#include "llvoavatarself.h" +// [/RLVa:KB] LLAgentListener::LLAgentListener(LLAgent &agent) : LLEventAPI("LLAgent", @@ -179,8 +184,28 @@ void LLAgentListener::requestSit(LLSD const & event_data) const object = findObjectClosestTo(target_position); } +// [RLVa:KB] - Checked: 2010-03-06 (RLVa-1.2.0c) | Modified: RLVa-1.1.0j + // TODO-RLVa: [RLVa-1.2.1] Figure out how to call this? + if ( (rlv_handler_t::isEnabled()) && (!RlvActions::canSit(object)) ) + { + return; + } +// [/RLVa:KB] + if (object && object->getPCode() == LL_PCODE_VOLUME) { +// [RLVa:KB] - Checked: 2010-08-29 (RLVa-1.2.1c) | Added: RLVa-1.2.1c + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_STANDTP)) && (isAgentAvatarValid()) ) + { + if (gAgentAvatarp->isSitting()) + { + gAgent.standUp(); + return; + } + gRlvHandler.setSitSource(gAgent.getPositionGlobal()); + } +// [/RLVa:KB] + gMessageSystem->newMessageFast(_PREHASH_AgentRequestSit); gMessageSystem->nextBlockFast(_PREHASH_AgentData); gMessageSystem->addUUIDFast(_PREHASH_AgentID, mAgent.getID()); @@ -200,6 +225,14 @@ void LLAgentListener::requestSit(LLSD const & event_data) const void LLAgentListener::requestStand(LLSD const & event_data) const { +// [RLVa:KB] - Checked: 2010-03-07 (RLVa-1.2.0c) | Added: RLVa-1.2.0a + // TODO-RLVa: [RLVa-1.2.1] Figure out how to call this? + if ( (rlv_handler_t::isEnabled()) && (!RlvActions::canStand()) ) + { + return; + } +// [/RLVa:KB] + mAgent.setControlFlags(AGENT_CONTROL_STAND_UP); } diff --git a/indra/newview/llagentui.cpp b/indra/newview/llagentui.cpp index 3410a37890505052f86db52601015e878f6f469c..8258e77caa2387699a1eb8d16ec3f72fa5830a19 100644 --- a/indra/newview/llagentui.cpp +++ b/indra/newview/llagentui.cpp @@ -38,6 +38,9 @@ #include "llviewerparcelmgr.h" #include "llvoavatarself.h" #include "llslurl.h" +// [RLVa:KB] - Checked: 2010-04-04 (RLVa-1.2.0d) +#include "rlvhandler.h" +// [/RLVa:KB] //static void LLAgentUI::buildFullname(std::string& name) @@ -99,6 +102,18 @@ BOOL LLAgentUI::buildLocationString(std::string& str, ELocationFormat fmt,const // create a default name and description for the landmark std::string parcel_name = LLViewerParcelMgr::getInstance()->getAgentParcelName(); std::string region_name = region->getName(); +// [RLVa:KB] - Checked: 2010-04-04 (RLVa-1.2.0d) | Modified: RLVa-1.2.0d + // RELEASE-RLVa: [SL-2.0.0] Check ELocationFormat to make sure our switch still makes sense + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) + { + parcel_name = RlvStrings::getString(RLV_STRING_HIDDEN_PARCEL); + region_name = RlvStrings::getString(RLV_STRING_HIDDEN_REGION); + if (LOCATION_FORMAT_NO_MATURITY == fmt) + fmt = LOCATION_FORMAT_LANDMARK; + else if (LOCATION_FORMAT_FULL == fmt) + fmt = LOCATION_FORMAT_NO_COORDS; + } +// [/RLVa:KB] std::string sim_access_string = region->getSimAccessString(); std::string buffer; if( parcel_name.empty() ) diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp index 1c327b479e90a4b03562b9fb73dae62dccdfb1c0..7be674789dbddcfb2d49ff2fc106b46ef5d15eb8 100644 --- a/indra/newview/llagentwearables.cpp +++ b/indra/newview/llagentwearables.cpp @@ -51,6 +51,10 @@ #include "llviewerwearable.h" #include "llwearablelist.h" #include "llfloaterperms.h" +// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1) +#include "rlvhandler.h" +#include "rlvlocks.h" +// [/RLVa:KB] #include <boost/scoped_ptr.hpp> @@ -60,6 +64,9 @@ BOOL LLAgentWearables::mInitialWearablesUpdateReceived = FALSE; // [SL:KB] - Patch: Appearance-InitialWearablesLoadedCallback | Checked: 2010-08-14 (Catznip-2.1) bool LLAgentWearables::mInitialWearablesLoaded = false; // [/SL:KB] +// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1) +bool LLAgentWearables::mInitialAttachmentsRequested = false; +// [/RLVa:KB] using namespace LLAvatarAppearanceDefines; @@ -659,6 +666,34 @@ const LLUUID LLAgentWearables::getWearableItemID(LLWearableType::EType type, U32 return LLUUID(); } +// [RLVa:KB] - Checked: 2011-03-31 (RLVa-1.3.0) +void LLAgentWearables::getWearableItemIDs(uuid_vec_t& idItems) const +{ + for (wearableentry_map_t::const_iterator itWearableType = mWearableDatas.begin(); + itWearableType != mWearableDatas.end(); ++itWearableType) + { + getWearableItemIDs(itWearableType->first, idItems); + } +} + +void LLAgentWearables::getWearableItemIDs(LLWearableType::EType eType, uuid_vec_t& idItems) const +{ + wearableentry_map_t::const_iterator itWearableType = mWearableDatas.find(eType); + if (mWearableDatas.end() != itWearableType) + { + for (wearableentry_vec_t::const_iterator itWearable = itWearableType->second.begin(); + itWearable != itWearableType->second.end(); ++itWearable) + { + const LLViewerWearable* pWearable = dynamic_cast<LLViewerWearable*>(*itWearable); + if (pWearable) + { + idItems.push_back(pWearable->getItemID()); + } + } + } +} +// [/RLVa:KB] + const LLUUID LLAgentWearables::getWearableAssetID(LLWearableType::EType type, U32 index) const { const LLViewerWearable *wearable = getViewerWearable(type,index); @@ -960,7 +995,11 @@ void LLAgentWearables::removeWearableFinal(const LLWearableType::EType type, boo old_wearable->removeFromAvatar(); } } - clearWearableType(type); +// clearWearableType(type); +// [RLVa:KB] - Checked: 2010-05-14 (RLVa-1.2.0) + // The line above shouldn't be needed + RLV_VERIFY(0 == getWearableCount(type)); +// [/RLVa:KB] } else { @@ -1149,146 +1188,140 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it // User has picked "wear on avatar" from a menu. -void LLAgentWearables::setWearableItem(LLInventoryItem* new_item, LLViewerWearable* new_wearable, bool do_append) -{ - //LLAgentDumper dumper("setWearableItem"); - if (isWearingItem(new_item->getUUID())) - { - LL_WARNS() << "wearable " << new_item->getUUID() << " is already worn" << LL_ENDL; - return; - } - - const LLWearableType::EType type = new_wearable->getType(); - - if (!do_append) - { - // Remove old wearable, if any - // MULTI_WEARABLE: hardwired to 0 - LLViewerWearable* old_wearable = getViewerWearable(type,0); - if (old_wearable) - { - const LLUUID& old_item_id = old_wearable->getItemID(); - if ((old_wearable->getAssetID() == new_wearable->getAssetID()) && - (old_item_id == new_item->getUUID())) - { - LL_DEBUGS() << "No change to wearable asset and item: " << LLWearableType::getTypeName(type) << LL_ENDL; - return; - } - - if (old_wearable->isDirty()) - { - // Bring up modal dialog: Save changes? Yes, No, Cancel - LLSD payload; - payload["item_id"] = new_item->getUUID(); - LLNotificationsUtil::add("WearableSave", LLSD(), payload, boost::bind(onSetWearableDialog, _1, _2, new_wearable)); - return; - } - } - } - - setWearableFinal(new_item, new_wearable, do_append); -} +//void LLAgentWearables::setWearableItem(LLInventoryItem* new_item, LLViewerWearable* new_wearable, bool do_append) +//{ +// //LLAgentDumper dumper("setWearableItem"); +// if (isWearingItem(new_item->getUUID())) +// { +// LL_WARNS() << "wearable " << new_item->getUUID() << " is already worn" << LL_ENDL; +// return; +// } +// +// const LLWearableType::EType type = new_wearable->getType(); +// +// if (!do_append) +// { +// // Remove old wearable, if any +// // MULTI_WEARABLE: hardwired to 0 +// LLViewerWearable* old_wearable = getViewerWearable(type,0); +// if (old_wearable) +// { +// const LLUUID& old_item_id = old_wearable->getItemID(); +// if ((old_wearable->getAssetID() == new_wearable->getAssetID()) && +// (old_item_id == new_item->getUUID())) +// { +// LL_DEBUGS() << "No change to wearable asset and item: " << LLWearableType::getTypeName(type) << LL_ENDL; +// return; +// } +// +// if (old_wearable->isDirty()) +// { +// // Bring up modal dialog: Save changes? Yes, No, Cancel +// LLSD payload; +// payload["item_id"] = new_item->getUUID(); +// LLNotificationsUtil::add("WearableSave", LLSD(), payload, boost::bind(onSetWearableDialog, _1, _2, new_wearable)); +// return; +// } +// } +// } +// +// setWearableFinal(new_item, new_wearable, do_append); +//} // static -bool LLAgentWearables::onSetWearableDialog(const LLSD& notification, const LLSD& response, LLViewerWearable* wearable) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - LLInventoryItem* new_item = gInventory.getItem(notification["payload"]["item_id"].asUUID()); - U32 index; - if (!gAgentWearables.getWearableIndex(wearable,index)) - { - LL_WARNS() << "Wearable not found" << LL_ENDL; - delete wearable; - return false; - } - if (!new_item) - { - delete wearable; - return false; - } - - switch(option) - { - case 0: // "Save" - gAgentWearables.saveWearable(wearable->getType(),index); - gAgentWearables.setWearableFinal(new_item, wearable); - break; - - case 1: // "Don't Save" - gAgentWearables.setWearableFinal(new_item, wearable); - break; - - case 2: // "Cancel" - break; - - default: - llassert(0); - break; - } - - delete wearable; - return false; -} +//bool LLAgentWearables::onSetWearableDialog(const LLSD& notification, const LLSD& response, LLViewerWearable* wearable) +//{ +// S32 option = LLNotificationsUtil::getSelectedOption(notification, response); +// LLInventoryItem* new_item = gInventory.getItem(notification["payload"]["item_id"].asUUID()); +// U32 index; +// if (!gAgentWearables.getWearableIndex(wearable,index)) +// { +// LL_WARNS() << "Wearable not found" << LL_ENDL; +// delete wearable; +// return false; +// } +// switch(option) +// { +// case 0: // "Save" +// gAgentWearables.saveWearable(wearable->getType(),index); +// gAgentWearables.setWearableFinal(new_item, wearable); +// break; +// +// case 1: // "Don't Save" +// gAgentWearables.setWearableFinal(new_item, wearable); +// break; +// +// case 2: // "Cancel" +// break; +// +// default: +// llassert(0); +// break; +// } +// +// delete wearable; +// return false; +//} // Called from setWearableItem() and onSetWearableDialog() to actually set the wearable. // MULTI_WEARABLE: unify code after null objects are gone. -void LLAgentWearables::setWearableFinal(LLInventoryItem* new_item, LLViewerWearable* new_wearable, bool do_append) -{ - const LLWearableType::EType type = new_wearable->getType(); - - if (do_append && getWearableItemID(type,0).notNull()) - { - new_wearable->setItemID(new_item->getUUID()); - const bool trigger_updated = false; - pushWearable(type, new_wearable, trigger_updated); - LL_INFOS() << "Added additional wearable for type " << type - << " size is now " << getWearableCount(type) << LL_ENDL; - checkWearableAgainstInventory(new_wearable); - } - else - { - // Replace the old wearable with a new one. - llassert(new_item->getAssetUUID() == new_wearable->getAssetID()); - - LLViewerWearable *old_wearable = getViewerWearable(type,0); - LLUUID old_item_id; - if (old_wearable) - { - old_item_id = old_wearable->getItemID(); - } - new_wearable->setItemID(new_item->getUUID()); - setWearable(type,0,new_wearable); - - if (old_item_id.notNull()) - { - gInventory.addChangedMask(LLInventoryObserver::LABEL, old_item_id); - gInventory.notifyObservers(); - } - LL_INFOS() << "Replaced current element 0 for type " << type - << " size is now " << getWearableCount(type) << LL_ENDL; - } -} +//void LLAgentWearables::setWearableFinal(LLInventoryItem* new_item, LLViewerWearable* new_wearable, bool do_append) +//{ +// const LLWearableType::EType type = new_wearable->getType(); +// +// if (do_append && getWearableItemID(type,0).notNull()) +// { +// new_wearable->setItemID(new_item->getUUID()); +// const bool trigger_updated = false; +// pushWearable(type, new_wearable, trigger_updated); +// LL_INFOS() << "Added additional wearable for type " << type +// << " size is now " << getWearableCount(type) << LL_ENDL; +// checkWearableAgainstInventory(new_wearable); +// } +// else +// { +// // Replace the old wearable with a new one. +// llassert(new_item->getAssetUUID() == new_wearable->getAssetID()); +// +// LLViewerWearable *old_wearable = getViewerWearable(type,0); +// LLUUID old_item_id; +// if (old_wearable) +// { +// old_item_id = old_wearable->getItemID(); +// } +// new_wearable->setItemID(new_item->getUUID()); +// setWearable(type,0,new_wearable); +// +// if (old_item_id.notNull()) +// { +// gInventory.addChangedMask(LLInventoryObserver::LABEL, old_item_id); +// gInventory.notifyObservers(); +// } +// LL_INFOS() << "Replaced current element 0 for type " << type +// << " size is now " << getWearableCount(type) << LL_ENDL; +// } +//} // User has picked "remove from avatar" from a menu. // static -void LLAgentWearables::userRemoveWearable(const LLWearableType::EType &type, const U32 &index) -{ - if (!(type==LLWearableType::WT_SHAPE || type==LLWearableType::WT_SKIN || type==LLWearableType::WT_HAIR || type==LLWearableType::WT_EYES)) //&& - //!((!gAgent.isTeen()) && (type==LLWearableType::WT_UNDERPANTS || type==LLWearableType::WT_UNDERSHIRT))) - { - gAgentWearables.removeWearable(type,false,index); - } -} +//void LLAgentWearables::userRemoveWearable(const LLWearableType::EType &type, const U32 &index) +//{ +// if (!(type==LLWearableType::WT_SHAPE || type==LLWearableType::WT_SKIN || type==LLWearableType::WT_HAIR || type==LLWearableType::WT_EYES)) //&& +// //!((!gAgent.isTeen()) && (type==LLWearableType::WT_UNDERPANTS || type==LLWearableType::WT_UNDERSHIRT))) +// { +// gAgentWearables.removeWearable(type,false,index); +// } +//} //static -void LLAgentWearables::userRemoveWearablesOfType(const LLWearableType::EType &type) -{ - if (!(type==LLWearableType::WT_SHAPE || type==LLWearableType::WT_SKIN || type==LLWearableType::WT_HAIR || type==LLWearableType::WT_EYES)) //&& - //!((!gAgent.isTeen()) && (type==LLWearableType::WT_UNDERPANTS || type==LLWearableType::WT_UNDERSHIRT))) - { - gAgentWearables.removeWearable(type,true,0); - } -} +//void LLAgentWearables::userRemoveWearablesOfType(const LLWearableType::EType &type) +//{ +// if (!(type==LLWearableType::WT_SHAPE || type==LLWearableType::WT_SKIN || type==LLWearableType::WT_HAIR || type==LLWearableType::WT_EYES)) //&& +// //!((!gAgent.isTeen()) && (type==LLWearableType::WT_UNDERPANTS || type==LLWearableType::WT_UNDERSHIRT))) +// { +// gAgentWearables.removeWearable(type,true,0); +// } +//} // Given a desired set of attachments, find what objects need to be // removed, and what additional inventory items need to be added. @@ -1378,6 +1411,34 @@ void LLAgentWearables::userRemoveMultipleAttachments(llvo_vec_t& objects_to_remo { if (!isAgentAvatarValid()) return; +// [RLVa:KB] - Checked: 2010-03-04 (RLVa-1.2.0) + // RELEASE-RLVa: [SL-3.4] 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 (objects_to_remove.end() != itObj) + { + 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) + bool fInCOF = LLAppearanceMgr::instance().isLinkedInCOF(pAttachObj->getAttachmentItemID()); + RLV_ASSERT(fInCOF); + if (!fInCOF) + { + LLAppearanceMgr::instance().registerAttachment(pAttachObj->getAttachmentItemID()); + } + } + else + { + ++itObj; + } + } + } +// [/RLVa:KB] + if (objects_to_remove.empty()) return; @@ -1419,6 +1480,10 @@ void LLAgentWearables::userAttachMultipleAttachments(LLInventoryModel::item_arra const LLInventoryItem* item = *it; LLAttachmentsMgr::instance().addAttachmentRequest(item->getLinkedUUID(), 0, TRUE); } + +// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1) + mInitialAttachmentsRequested = true; +// [/RLVa:KB] } // Returns false if the given wearable is already topmost/bottommost diff --git a/indra/newview/llagentwearables.h b/indra/newview/llagentwearables.h index d3bf760ba0eadfe7ce4ce8a061f854b302ae5a53..938208cef5e39edc1345054c448ac6080f390bec 100644 --- a/indra/newview/llagentwearables.h +++ b/indra/newview/llagentwearables.h @@ -74,6 +74,9 @@ class LLAgentWearables : public LLInitClass<LLAgentWearables>, public LLWearable // [SL:KB] - Patch: Appearance-InitialWearablesLoadedCallback | Checked: 2010-08-14 (Catznip-2.1) bool areInitalWearablesLoaded() const { return mInitialWearablesLoaded; } // [/SL:KB] +// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1) + bool areInitialAttachmentsRequested() const { return mInitialAttachmentsRequested; } +// [/RLVa:KB] bool isCOFChangeInProgress() const { return mCOFChangeInProgress; } F32 getCOFChangeTime() const { return mCOFChangeTimer.getElapsedTimeF32(); } void updateWearablesLoaded(); @@ -89,6 +92,10 @@ class LLAgentWearables : public LLInitClass<LLAgentWearables>, public LLWearable // Accessors //-------------------------------------------------------------------- public: +// [RLVa:KB] - Checked: 2011-03-31 (RLVa-1.3.0) + void getWearableItemIDs(uuid_vec_t& idItems) const; + void getWearableItemIDs(LLWearableType::EType eType, uuid_vec_t& idItems) const; +// [/RLVa:KB] const LLUUID getWearableItemID(LLWearableType::EType type, U32 index /*= 0*/) const; const LLUUID getWearableAssetID(LLWearableType::EType type, U32 index /*= 0*/) const; const LLViewerWearable* getWearableFromItemID(const LLUUID& item_id) const; @@ -105,15 +112,15 @@ class LLAgentWearables : public LLInitClass<LLAgentWearables>, public LLWearable private: /*virtual*/void wearableUpdated(LLWearable *wearable, BOOL removed); public: - void setWearableItem(LLInventoryItem* new_item, LLViewerWearable* wearable, bool do_append = false); +// void setWearableItem(LLInventoryItem* new_item, LLViewerWearable* wearable, bool do_append = false); void setWearableOutfit(const LLInventoryItem::item_array_t& items, const std::vector< LLViewerWearable* >& wearables); void setWearableName(const LLUUID& item_id, const std::string& new_name); // *TODO: Move this into llappearance/LLWearableData ? void addLocalTextureObject(const LLWearableType::EType wearable_type, const LLAvatarAppearanceDefines::ETextureIndex texture_type, U32 wearable_index); protected: - void setWearableFinal(LLInventoryItem* new_item, LLViewerWearable* new_wearable, bool do_append = false); - static bool onSetWearableDialog(const LLSD& notification, const LLSD& response, LLViewerWearable* wearable); +// void setWearableFinal(LLInventoryItem* new_item, LLViewerWearable* new_wearable, bool do_append = false); +// static bool onSetWearableDialog(const LLSD& notification, const LLSD& response, LLViewerWearable* wearable); void addWearableToAgentInventory(LLPointer<LLInventoryCallback> cb, LLViewerWearable* wearable, @@ -145,8 +152,11 @@ class LLAgentWearables : public LLInitClass<LLAgentWearables>, public LLWearable // Removing wearables //-------------------------------------------------------------------- public: - void removeWearable(const LLWearableType::EType type, bool do_remove_all /*= false*/, U32 index /*= 0*/); +// void removeWearable(const LLWearableType::EType type, bool do_remove_all /*= false*/, U32 index /*= 0*/); private: +// [RLVa:KB] - Checked: 2010-05-11 (RLVa-1.2.0) + void removeWearable(const LLWearableType::EType type, bool do_remove_all /*= false*/, U32 index /*= 0*/); +// [/RLVa:KB] void removeWearableFinal(const LLWearableType::EType type, bool do_remove_all /*= false*/, U32 index /*= 0*/); protected: static bool onRemoveWearableDialog(const LLSD& notification, const LLSD& response); @@ -176,8 +186,8 @@ class LLAgentWearables : public LLInitClass<LLAgentWearables>, public LLWearable // Static UI hooks //-------------------------------------------------------------------- public: - static void userRemoveWearable(const LLWearableType::EType &type, const U32 &index); - static void userRemoveWearablesOfType(const LLWearableType::EType &type); +// static void userRemoveWearable(const LLWearableType::EType &type, const U32 &index); +// static void userRemoveWearablesOfType(const LLWearableType::EType &type); typedef std::vector<LLViewerObject*> llvo_vec_t; @@ -222,6 +232,9 @@ class LLAgentWearables : public LLInitClass<LLAgentWearables>, public LLWearable // [SL:KB] - Patch: Appearance-InitialWearablesLoadedCallback | Checked: 2010-08-14 (Catznip-2.2) static bool mInitialWearablesLoaded; // [/SL:KB] +// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1) + static bool mInitialAttachmentsRequested; +// [/RLVa:KB] BOOL mWearablesLoaded; /** diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index de8844f6d9b6281830846f9161c33ddd2d84212b..3db61d4ae073a7976ed93d2fadd8e1c1a73630c9 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -60,6 +60,12 @@ #include "llappviewer.h" #include "llcoros.h" #include "lleventcoro.h" +// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1) +#include "rlvactions.h" +#include "rlvhandler.h" +#include "rlvhelper.h" +#include "rlvlocks.h" +// [/RLVa:KB] #include "llavatarpropertiesprocessor.h" @@ -1316,6 +1322,25 @@ static void removeDuplicateItems(LLInventoryModel::item_array_t& items) //========================================================================= +// [SL:KB] - Patch: Appearance-WearableDuplicateAssets | Checked: 2015-06-30 (Catznip-3.7) +static void removeDuplicateWearableItemsByAssetID(LLInventoryModel::item_array_t& items) +{ + std::set<LLUUID> idsAsset; + items.erase(std::remove_if(items.begin(), items.end(), + [&idsAsset](const LLViewerInventoryItem* pItem) + { + if (pItem->isWearableType()) + { + const LLUUID& idAsset = pItem->getAssetUUID(); + if ( (idAsset.notNull()) && (idsAsset.end() != idsAsset.find(idAsset)) ) + return true; + idsAsset.insert(idAsset); + } + return false; + }), items.end()); +} +// [/SL:KB] + const LLUUID LLAppearanceMgr::getCOF() const { return gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); @@ -1473,6 +1498,13 @@ void LLAppearanceMgr::wearItemsOnAvatar(const uuid_vec_t& item_ids_to_wear, continue; } +// [RLVa:KB] - Checked: 2013-02-12 (RLVa-1.4.8) + if ( (rlv_handler_t::isEnabled()) && (!rlvPredCanWearItem(item_to_wear, (replace) ? RLV_WEAR_REPLACE : RLV_WEAR_ADD)) ) + { + continue; + } +// [/RLVa:KB] + switch (item_to_wear->getType()) { case LLAssetType::AT_CLOTHING: @@ -1490,9 +1522,9 @@ void LLAppearanceMgr::wearItemsOnAvatar(const uuid_vec_t& item_ids_to_wear, LLUUID item_id = gAgentWearables.getWearableItemID(item_to_wear->getWearableType(), wearable_count-1); // [SL:KB] - Patch: Appearance-AISFilter | Checked: 2015-05-02 (Catznip-3.7) - removeCOFItemLinks(item_id, NULL, true); + removeCOFItemLinks(item_id, NULL, true); // [/SL:KB] -// removeCOFItemLinks(item_id, cb); +// removeCOFItemLinks(item_id, cb); } items_to_link.push_back(item_to_wear); @@ -1868,6 +1900,13 @@ bool LLAppearanceMgr::getCanRemoveFromCOF(const LLUUID& outfit_cat_id) { return false; } +// [RLVa:KB] - Checked: RLVa-2.0.3 + if ( (RlvActions::isRlvEnabled()) && (RlvFolderLocks::instance().isLockedFolder(outfit_cat_id, RLV_LOCK_REMOVE)) ) + { + return false; + } +// [/RLVa:KB] + LLInventoryModel::cat_array_t cats; LLInventoryModel::item_array_t items; LLFindWearablesEx is_worn(/*is_worn=*/ true, /*include_body_parts=*/ false); @@ -1887,6 +1926,13 @@ bool LLAppearanceMgr::getCanAddToCOF(const LLUUID& outfit_cat_id) return false; } +// [RLVa:KB] - Checked: RLVa-2.0.3 + if ( (RlvActions::isRlvEnabled()) && (RlvFolderLocks::instance().isLockedFolder(outfit_cat_id, RLV_LOCK_ADD)) ) + { + return false; + } +// [/RLVa:KB] + LLInventoryModel::cat_array_t cats; LLInventoryModel::item_array_t items; LLFindWearablesEx not_worn(/*is_worn=*/ false, /*include_body_parts=*/ false); @@ -1907,6 +1953,14 @@ bool LLAppearanceMgr::getCanReplaceCOF(const LLUUID& outfit_cat_id) return false; } +// [RLVa:KB] - Checked: RLVa-2.0.3 + // Block "Replace Current Outfit" if the user can't wear the new folder + if ( (RlvActions::isRlvEnabled()) && (RlvFolderLocks::instance().isLockedFolder(outfit_cat_id, RLV_LOCK_ADD)) ) + { + return false; + } +// [/RLVa:KB] + // Check whether it's the base outfit. // if (outfit_cat_id.isNull() || outfit_cat_id == getBaseOutfitUUID()) // [SL:KB] - Patch: Appearance-Misc | Checked: 2010-09-21 (Catznip-2.1) @@ -2036,6 +2090,8 @@ void LLAppearanceMgr::filterWearableItems( } } +//void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append) +// [RLVa:KB] - Checked: 2010-03-05 (RLVa-1.2.0) void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append) { LLViewerInventoryCategory *pcat = gInventory.getCategory(category); @@ -2046,6 +2102,32 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append) } LL_INFOS("Avatar") << self_av_string() << "starting, cat '" << (pcat ? pcat->getName() : "[UNKNOWN]") << "'" << LL_ENDL; + LLInventoryModel::item_array_t body_items_new, wear_items_new, obj_items_new, gest_items_new; + getDescendentsOfAssetType(category, body_items_new, LLAssetType::AT_BODYPART); + getDescendentsOfAssetType(category, wear_items_new, LLAssetType::AT_CLOTHING); + getDescendentsOfAssetType(category, obj_items_new, LLAssetType::AT_OBJECT); + getDescendentsOfAssetType(category, gest_items_new, LLAssetType::AT_GESTURE); + updateCOF(body_items_new, wear_items_new, obj_items_new, gest_items_new, append, category); +} + +void LLAppearanceMgr::updateCOF(LLInventoryModel::item_array_t& body_items_new, + LLInventoryModel::item_array_t& wear_items_new, + LLInventoryModel::item_array_t& obj_items_new, + LLInventoryModel::item_array_t& gest_items_new, + bool append /*=false*/, const LLUUID& idOutfit /*=LLUUID::null*/, LLPointer<LLInventoryCallback> link_waiter /*= NULL*/) +// [/RLVa:KB] +{ +// LLViewerInventoryCategory *pcat = gInventory.getCategory(category); +// if (!pcat) +// { +// LL_WARNS() << "no category found for id " << category << LL_ENDL; +// return; +// } +// LL_INFOS("Avatar") << self_av_string() << "starting, cat '" << (pcat ? pcat->getName() : "[UNKNOWN]") << "'" << LL_ENDL; +// [RLVa:KB] - Checked: 2010-03-26 (RLVa-1.2.0) + LL_INFOS("Avatar") << "starting" << LL_ENDL; +// [/RLVa:KB] + const LLUUID cof = getCOF(); // Deactivate currently active gestures in the COF, if replacing outfit @@ -2065,39 +2147,87 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append) // Collect and filter descendents to determine new COF contents. - // - Body parts: always include COF contents as a fallback in case any - // required parts are missing. + // + // - Body parts: always include COF contents as a fallback in case any required parts are missing. + // // Preserve body parts from COF if appending. LLInventoryModel::item_array_t body_items; getDescendentsOfAssetType(cof, body_items, LLAssetType::AT_BODYPART); - getDescendentsOfAssetType(category, body_items, LLAssetType::AT_BODYPART); - if (append) - reverse(body_items.begin(), body_items.end()); +// getDescendentsOfAssetType(category, body_items, LLAssetType::AT_BODYPART); +// [RLVa:KB] - Checked: RLVa-2.0.3 + // Filter out any new body parts that can't be worn before adding them + if ( (RlvActions::isRlvEnabled()) && ((gRlvWearableLocks.hasLockedWearableType(RLV_LOCK_ANY)) || (RlvFolderLocks::instance().hasLockedFolder(RLV_LOCK_ADD))) ) + body_items_new.erase(std::remove_if(body_items_new.begin(), body_items_new.end(), RlvPredCanNotWearItem(RLV_WEAR_REPLACE)), body_items_new.end()); + body_items.insert(body_items.end(), body_items_new.begin(), body_items_new.end()); +// [/RLVa:KB] + // NOTE-RLVa: we don't actually want to favour COF body parts over the folder's body parts (if only because it breaks force wear) +// if (append) +// reverse(body_items.begin(), body_items.end()); // Reduce body items to max of one per type. removeDuplicateItems(body_items); filterWearableItems(body_items, 1, 0); + // // - Wearables: include COF contents only if appending. + // LLInventoryModel::item_array_t wear_items; if (append) getDescendentsOfAssetType(cof, wear_items, LLAssetType::AT_CLOTHING); - getDescendentsOfAssetType(category, wear_items, LLAssetType::AT_CLOTHING); +// [RLVa:KB] - Checked: RLVa-2.0.3 + else if ( (RlvActions::isRlvEnabled()) && ((gRlvWearableLocks.hasLockedWearableType(RLV_LOCK_ANY)) || (RlvFolderLocks::instance().hasLockedFolder(RLV_LOCK_REMOVE))) ) + { + // Make sure that all currently locked clothing layers remain in COF when replacing + getDescendentsOfAssetType(cof, wear_items, LLAssetType::AT_CLOTHING); + wear_items.erase(std::remove_if(wear_items.begin(), wear_items.end(), RlvPredCanRemoveItem()), wear_items.end()); + } +// [/RLVa:KB] +// getDescendentsOfAssetType(category, wear_items, LLAssetType::AT_CLOTHING); +// [RLVa:KB] - Checked: RLVa-2.0.3 + // Filter out any new wearables that can't be worn before adding them + if ( (RlvActions::isRlvEnabled()) && ((gRlvWearableLocks.hasLockedWearableType(RLV_LOCK_ANY)) || (RlvFolderLocks::instance().hasLockedFolder(RLV_LOCK_ADD))) ) + wear_items_new.erase(std::remove_if(wear_items_new.begin(), wear_items_new.end(), RlvPredCanNotWearItem(RLV_WEAR)), wear_items_new.end()); + wear_items.insert(wear_items.end(), wear_items_new.begin(), wear_items_new.end()); +// [/RLVa:KB] // Reduce wearables to max of one per type. removeDuplicateItems(wear_items); +// [SL:KB] - Patch: Appearance-WearableDuplicateAssets | Checked: 2011-07-24 (Catznip-2.6.0e) | Added: Catznip-2.6.0e + removeDuplicateWearableItemsByAssetID(wear_items); +// [/SL:KB] filterWearableItems(wear_items, 0, LLAgentWearables::MAX_CLOTHING_LAYERS); + // // - Attachments: include COF contents only if appending. + // LLInventoryModel::item_array_t obj_items; if (append) getDescendentsOfAssetType(cof, obj_items, LLAssetType::AT_OBJECT); - getDescendentsOfAssetType(category, obj_items, LLAssetType::AT_OBJECT); +// [RLVa:KB] - Checked: RLVa-2.0.3 + else if ( (RlvActions::isRlvEnabled()) && ((gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) || (RlvFolderLocks::instance().hasLockedFolder(RLV_LOCK_REMOVE))) ) + { + // Make sure that all currently locked attachments remain in COF when replacing + getDescendentsOfAssetType(cof, obj_items, LLAssetType::AT_OBJECT); + 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); +// [RLVa:KB] - Checked: RLVa-2.0.3 + // Filter out any new attachments that can't be worn before adding them + if ( (RlvActions::isRlvEnabled()) && ((gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) || (RlvFolderLocks::instance().hasLockedFolder(RLV_LOCK_ADD))) ) + obj_items_new.erase(std::remove_if(obj_items_new.begin(), obj_items_new.end(), RlvPredCanNotWearItem(RLV_WEAR)), obj_items_new.end()); + obj_items.insert(obj_items.end(), obj_items_new.begin(), obj_items_new.end()); +// [/RLVa:KB] removeDuplicateItems(obj_items); + // // - Gestures: include COF contents only if appending. + // LLInventoryModel::item_array_t gest_items; if (append) getDescendentsOfAssetType(cof, gest_items, LLAssetType::AT_GESTURE); - getDescendentsOfAssetType(category, gest_items, LLAssetType::AT_GESTURE); +// getDescendentsOfAssetType(category, gest_items, LLAssetType::AT_GESTURE); +// [RLVa:KB] - Checked: 2010-03-05 (RLVa-1.2.0) + gest_items.insert(gest_items.end(), gest_items_new.begin(), gest_items_new.end()); +// [/RLVa:KB] removeDuplicateItems(gest_items); // Create links to new COF contents. @@ -2113,7 +2243,11 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append) // Will link all the above items. // link_waiter enforce flags are false because we've already fixed everything up in updateCOF(). - LLPointer<LLInventoryCallback> link_waiter = new LLUpdateAppearanceOnDestroy(false,false); +// LLPointer<LLInventoryCallback> link_waiter = new LLUpdateAppearanceOnDestroy(false,false); +// [RLVa:KB] Checked: 2015-05-05 (RLVa-1.4.12) + if (!link_waiter) + link_waiter = new LLUpdateAppearanceOnDestroy(false, false); +// [/RLVa:KB] LLSD contents = LLSD::emptyArray(); for (LLInventoryModel::item_array_t::const_iterator it = all_items.begin(); @@ -2141,8 +2275,12 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append) item_contents["type"] = LLAssetType::AT_LINK; contents.append(item_contents); } - const LLUUID& base_id = append ? getBaseOutfitUUID() : category; - LLViewerInventoryCategory *base_cat = gInventory.getCategory(base_id); +// const LLUUID& base_id = append ? getBaseOutfitUUID() : category; +// LLViewerInventoryCategory *base_cat = gInventory.getCategory(base_id); +// [RLVa:KB] - Checked: 2014-11-02 (RLVa-1.4.11) + const LLUUID& base_id = (append) ? getBaseOutfitUUID() : idOutfit; + LLViewerInventoryCategory* base_cat = (base_id.notNull()) ? gInventory.getCategory(base_id) : NULL; +// [/RLVa:KB] if (base_cat && (base_cat->getPreferredType() == LLFolderType::FT_OUTFIT)) { LLSD base_contents; @@ -2194,6 +2332,14 @@ void LLAppearanceMgr::updateAgentWearables(LLWearableHoldingPattern* holder) LLInventoryItem::item_array_t items; std::vector< LLViewerWearable* > wearables; wearables.reserve(32); +// [RLVa:KB] - Checked: 2011-03-31 (RLVa-1.3.0) + uuid_vec_t idsCurrent; LLInventoryModel::item_array_t itemsNew; + if (rlv_handler_t::isEnabled()) + { + // Collect the item UUIDs of all currently worn wearables + gAgentWearables.getWearableItemIDs(idsCurrent); + } +// [/RLVa:KB] // For each wearable type, find the wearables of that type. for( S32 i = 0; i < LLWearableType::WT_COUNT; i++ ) @@ -2208,13 +2354,60 @@ void LLAppearanceMgr::updateAgentWearables(LLWearableHoldingPattern* holder) LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(data.mItemID); if( item && (item->getAssetUUID() == wearable->getAssetID()) ) { +// [RLVa:KB] - Checked: 2010-03-19 (RLVa-1.2.0) + // TODO-RLVa: [RLVa-1.2.1] This is fall-back code so if we don't ever trigger this code it can just be removed + // -> one way to trigger the assertion: + // 1) "Replace Outfit" on a folder with clothing and an attachment that goes @addoutfit=n + // 2) updateCOF will add/link the items into COF => no @addoutfit=n present yet => allowed + // 3) llOwnerSay("@addoutfit=n") executes + // 4) code below runs => @addoutfit=n conflicts with adding new wearables + // => if it's left as-is then the wearables won't get worn (but remain in COF which causes issues of its own) + // => if it's changed to debug-only then we make tge assumption that anything that makes it into COF is always OK +#ifdef RLV_DEBUG + // NOTE: make sure we don't accidentally block setting the initial wearables + if ( (rlv_handler_t::isEnabled()) && (RLV_WEAR_LOCKED == gRlvWearableLocks.canWear(wearable->getType())) && + (!gAgentWearables.getWearableFromItemID(item->getUUID())) && (gAgentWearables.areWearablesLoaded()) ) + { + RLV_VERIFY(RLV_WEAR_LOCKED == gRlvWearableLocks.canWear(wearable->getType())); + continue; + } +#endif // RLV_DEBUG +// [/RLVa:KB] items.push_back(item); wearables.push_back(wearable); +// [RLVa:KB] - Checked: 2011-03-31 (RLVa-1.3.0) + if ( (rlv_handler_t::isEnabled()) && (gAgentWearables.areInitalWearablesLoaded()) ) + { + // Remove the wearable from current item UUIDs if currently worn and requested, otherwise mark it as a new item + uuid_vec_t::iterator itItemID = std::find(idsCurrent.begin(), idsCurrent.end(), item->getUUID()); + if (idsCurrent.end() != itItemID) + idsCurrent.erase(itItemID); + else + itemsNew.push_back(item); + } +// [/RLVa:KB] } } } } +// [RLVa:KB] - Checked: 2011-03-31 (RLVa-1.3.0) + if ( (rlv_handler_t::isEnabled()) && (gAgentWearables.areInitalWearablesLoaded()) ) + { + // We need to report removals before additions or scripts will get confused + for (uuid_vec_t::const_iterator itItemID = idsCurrent.begin(); itItemID != idsCurrent.end(); ++itItemID) + { + const LLWearable* pWearable = gAgentWearables.getWearableFromItemID(*itItemID); + if (pWearable) + RlvBehaviourNotifyHandler::onTakeOff(pWearable->getType(), true); + } + for (S32 idxItem = 0, cntItem = itemsNew.size(); idxItem < cntItem; idxItem++) + { + RlvBehaviourNotifyHandler::onWear(itemsNew.at(idxItem)->getWearableType(), true); + } + } +// [/RLVa:KB] + if(wearables.size() > 0) { gAgentWearables.setWearableOutfit(items, wearables); @@ -2403,6 +2596,10 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool enforce_item_restrictions, removeDuplicateItems(gest_items); filterWearableItems(wear_items, LLAgentWearables::MAX_CLOTHING_LAYERS, LLAgentWearables::MAX_CLOTHING_LAYERS); // [/SL:KB] +// [SL:KB] - Patch: Appearance-WearableDuplicateAssets | Checked: 2011-07-24 (Catznip-2.6.0e) | Added: Catznip-2.6.0e + // Wearing two wearables that share the same asset causes some issues + removeDuplicateWearableItemsByAssetID(wear_items); +// [/SL:KB] dumpItemArray(wear_items,"asset_dump: wear_item"); dumpItemArray(obj_items,"asset_dump: obj_item"); @@ -2504,6 +2701,9 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool enforce_item_restrictions, // fetch failures (should be replaced by new defaults in // lost&found). U32 skip_type = gSavedSettings.getU32("ForceAssetFail"); +// [RLVa:KB] - Checked: 2010-12-11 (RLVa-1.2.2) + U32 missing_type = gSavedSettings.getU32("ForceMissingType"); +// [/RLVa:KB] if (item && item->getIsLinkType() && linked_item) { @@ -2514,10 +2714,25 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool enforce_item_restrictions, linked_item->isWearableType() ? linked_item->getWearableType() : LLWearableType::WT_INVALID ); - if (skip_type != LLWearableType::WT_INVALID && skip_type == found.mWearableType) +// [RLVa:KB] - Checked: 2010-12-15 (RLVa-1.2.2) +#ifdef LL_RELEASE_FOR_DOWNLOAD + // Don't allow forcing an invalid wearable if the initial wearables aren't set yet, or if any wearable type is currently locked + if ( (!rlv_handler_t::isEnabled()) || + ((gAgentWearables.areInitalWearablesLoaded()) && (!gRlvWearableLocks.hasLockedWearableType(RLV_LOCK_REMOVE))) ) +#endif // LL_RELEASE_FOR_DOWNLOAD { - found.mAssetID.generate(); // Replace with new UUID, guaranteed not to exist in DB + if (missing_type != LLWearableType::WT_INVALID && missing_type == found.mWearableType) + { + continue; + } +// [/RLVa:KB] + if (skip_type != LLWearableType::WT_INVALID && skip_type == found.mWearableType) + { + found.mAssetID.generate(); // Replace with new UUID, guaranteed not to exist in DB + } +// [RLVa:KB] - Checked: 2010-12-15 (RLVa-1.2.2) } +// [/RLVa:KB] //pushing back, not front, to preserve order of wearables for LLAgentWearables holder->getFoundList().push_back(found); } @@ -2897,6 +3112,13 @@ void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item, // MULTI-WEARABLES: make sure we don't go over clothing limits remove_inventory_item(inv_item->getUUID(), cb); } +// [SL:KB] - Patch: Appearance-WearableDuplicateAssets | Checked: 2011-07-24 (Catznip-2.6.0e) | Added: Catznip-2.6.0e + else if ( (vitem->getWearableType() == wearable_type) && (vitem->getAssetUUID() == inv_item->getAssetUUID()) ) + { + // Only allow one wearable per unique asset + linked_already = true; + } +// [/SL:KB] } } @@ -3006,9 +3228,15 @@ void LLAppearanceMgr::removeCOFItemLinks(const LLUUID& item_id, LLPointer<LLInve LLInventoryModel::EXCLUDE_TRASH); for (S32 i=0; i<item_array.size(); i++) { - const LLInventoryItem* item = item_array.at(i).get(); + const LLViewerInventoryItem* item = item_array.at(i).get(); if (item->getIsLinkType() && item->getLinkedUUID() == item_id) { +// [RLVa:KB] - Checked: 2013-02-12 (RLVa-1.4.8) + if (rlv_handler_t::isEnabled()) + { + RLV_ASSERT(rlvPredCanRemoveItem(item)); + } +// [/RLVa:KB] // bool immediate_delete = false; // if (item->getType() == LLAssetType::AT_OBJECT) // { @@ -3032,6 +3260,12 @@ void LLAppearanceMgr::removeCOFLinksOfType(LLWearableType::EType type, LLPointer const LLViewerInventoryItem* item = *it; if (item->getIsLinkType()) // we must operate on links only { +// [RLVa:KB] - Checked: 2013-02-12 (RLVa-1.4.8) + if (rlv_handler_t::isEnabled()) + { + RLV_ASSERT(rlvPredCanRemoveItem(item)); + } +// [/RLVa:KB] remove_inventory_item(item->getUUID(), cb); } } @@ -3896,17 +4130,18 @@ void LLAppearanceMgr::removeItemsFromAvatar(const uuid_vec_t& ids_to_remove, LLP LL_WARNS() << "called with empty list, nothing to do" << LL_ENDL; return; } -// LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy; -// [SL:KB] - Patch: Appearance-Misc | Checked: 2015-05-05 (Catznip-3.7) - if (!cb) - { - cb = new LLUpdateAppearanceOnDestroy; - } -// [/SL:KB] +// [RLVa:KB] - Checked: 2013-02-12 (RLVa-1.4.8) +// LLPointer<LLInventoryCallback> cb = NULL; for (uuid_vec_t::const_iterator it = ids_to_remove.begin(); it != ids_to_remove.end(); ++it) { const LLUUID& id_to_remove = *it; const LLUUID& linked_item_id = gInventory.getLinkedItemID(id_to_remove); + + if ( (rlv_handler_t::isEnabled()) && (!rlvPredCanRemoveItem(linked_item_id)) ) + { + continue; + } + LLViewerInventoryItem *item = gInventory.getItem(linked_item_id); if (item && item->getType() == LLAssetType::AT_OBJECT) { @@ -3916,15 +4151,33 @@ void LLAppearanceMgr::removeItemsFromAvatar(const uuid_vec_t& ids_to_remove, LLP { continue; } -// [SL:KB] - Patch: Appearance-Misc | Checked: 2015-05-05 (Catznip-3.7) + + if (!cb) + cb = new LLUpdateAppearanceOnDestroy(); removeCOFItemLinks(linked_item_id, cb, immediate_delete); -// [/SL:KB] -// removeCOFItemLinks(linked_item_id, cb); // [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2015-03-01 (Catznip-3.7) LLAttachmentsMgr::instance().clearPendingAttachmentLink(linked_item_id); // [/SL:KB] addDoomedTempAttachment(linked_item_id); } +// [/RLVa:KB] +//// LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy; +//// [SL:KB] - Patch: Appearance-Misc | Checked: 2015-05-05 (Catznip-3.7) +// if (!cb) +// { +// cb = new LLUpdateAppearanceOnDestroy; +// } +//// [/SL:KB] +// for (uuid_vec_t::const_iterator it = ids_to_remove.begin(); it != ids_to_remove.end(); ++it) +// { +// const LLUUID& id_to_remove = *it; +// const LLUUID& linked_item_id = gInventory.getLinkedItemID(id_to_remove); +//// [SL:KB] - Patch: Appearance-Misc | Checked: 2015-05-05 (Catznip-3.7) +// removeCOFItemLinks(linked_item_id, cb, immediate_delete); +//// [/SL:KB] +//// removeCOFItemLinks(linked_item_id, cb); +// addDoomedTempAttachment(linked_item_id); +// } } //void LLAppearanceMgr::removeItemFromAvatar(const LLUUID& id_to_remove) diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h index e864b953b66d49e01c8d5e7b5fd7e6ed79ee596a..8abfcf97e0754498f9f3b00437ccc1b16ceefe13 100644 --- a/indra/newview/llappearancemgr.h +++ b/indra/newview/llappearancemgr.h @@ -54,6 +54,11 @@ class LLAppearanceMgr: public LLSingleton<LLAppearanceMgr> bool enforce_ordering = true, nullary_func_t post_update_func = no_op); void updateCOF(const LLUUID& category, bool append = false); +// [RLVa:KB] - Checked: 2010-03-05 (RLVa-1.2.0a) | Added: RLVa-1.2.0a + void updateCOF(LLInventoryModel::item_array_t& body_items_new, LLInventoryModel::item_array_t& wear_items_new, + LLInventoryModel::item_array_t& obj_items_new, LLInventoryModel::item_array_t& gest_items_new, + bool append = false, const LLUUID& idOutfit = LLUUID::null, LLPointer<LLInventoryCallback> link_waiter = NULL); +// [/RLVa:KB] void wearInventoryCategory(LLInventoryCategory* category, bool copy, bool append); void wearInventoryCategoryOnAvatar(LLInventoryCategory* category, bool append); void wearCategoryFinal(LLUUID& cat_id, bool copy_items, bool append); @@ -273,6 +278,7 @@ class LLAppearanceMgr: public LLSingleton<LLAppearanceMgr> static void onOutfitRename(const LLSD& notification, const LLSD& response); + bool mAttachmentInvLinkEnabled; bool mOutfitIsDirty; bool mIsInUpdateAppearanceFromCOF; // to detect recursive calls. diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 35734384eb2d1e5cc7ea7ea161cca30f349cc1ae..490c56d983b97b34e56ddefa4d1dbb7c1046c30e 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -95,6 +95,11 @@ // [SL:KB] - Patch: Appearance-Misc | Checked: 2013-02-12 (Catznip-3.4) #include "llappearancemgr.h" // [/SL:KB] +// [RLVa:KB] - Checked: 2010-05-03 (RLVa-1.2.0g) +#include "rlvactions.h" +#include "rlvhandler.h" +// [/RLVa:KB] + #include "llweb.h" #include "llupdaterservice.h" #include "llfloatertexturefetchdebugger.h" @@ -485,7 +490,11 @@ void idle_afk_check() { // check idle timers F32 current_idle = gAwayTriggerTimer.getElapsedTimeF32(); - F32 afk_timeout = gSavedSettings.getS32("AFKTimeout"); +// [RLVa:KB] - Checked: 2010-05-03 (RLVa-1.2.0g) | Modified: RLVa-1.2.0g + // Enforce an idle time of 30 minutes if @allowidle=n restricted + F32 afk_timeout = (!gRlvHandler.hasBehaviour(RLV_BHVR_ALLOWIDLE)) ? gSavedSettings.getS32("AFKTimeout") : 60 * 30; +// [/RLVa:KB] +// F32 afk_timeout = gSavedSettings.getS32("AFKTimeout"); if (afk_timeout && (current_idle > afk_timeout) && ! gAgent.getAFK()) { LL_INFOS("IdleAway") << "Idle more than " << afk_timeout << " seconds: automatically changing to Away status" << LL_ENDL; @@ -3305,16 +3314,28 @@ LLSD LLAppViewer::getViewerInfo() const LLViewerRegion* region = gAgent.getRegion(); if (region) { - LLVector3d pos = gAgent.getPositionGlobal(); - info["POSITION"] = ll_sd_from_vector3d(pos); - info["POSITION_LOCAL"] = ll_sd_from_vector3(gAgent.getPosAgentFromGlobal(pos)); - info["REGION"] = gAgent.getRegion()->getName(); - info["HOSTNAME"] = gAgent.getRegion()->getHost().getHostName(); - info["HOSTIP"] = gAgent.getRegion()->getHost().getString(); +// [RLVa:KB] - Checked: 2014-02-24 (RLVa-1.4.10) + if (RlvActions::canShowLocation()) + { +// [/RLVa:KB] + LLVector3d pos = gAgent.getPositionGlobal(); + info["POSITION"] = ll_sd_from_vector3d(pos); + info["POSITION_LOCAL"] = ll_sd_from_vector3(gAgent.getPosAgentFromGlobal(pos)); + info["REGION"] = gAgent.getRegion()->getName(); + info["HOSTNAME"] = gAgent.getRegion()->getHost().getHostName(); + info["HOSTIP"] = gAgent.getRegion()->getHost().getString(); +// info["SERVER_VERSION"] = gLastVersionChannel; + LLSLURL slurl; + LLAgentUI::buildSLURL(slurl); + info["SLURL"] = slurl.getSLURLString(); +// [RLVa:KB] - Checked: 2014-02-24 (RLVa-1.4.10) + } + else + { + info["REGION"] = RlvStrings::getString(RLV_STRING_HIDDEN_REGION); + } info["SERVER_VERSION"] = gLastVersionChannel; - LLSLURL slurl; - LLAgentUI::buildSLURL(slurl); - info["SLURL"] = slurl.getSLURLString(); +// [/RLVa:KB] } // CPU @@ -3333,6 +3354,9 @@ LLSD LLAppViewer::getViewerInfo() const } #endif +// [RLVa:KB] - Checked: 2010-04-18 (RLVa-1.2.0) + info["RLV_VERSION"] = (rlv_handler_t::isEnabled()) ? RlvStrings::getVersionAbout() : "(disabled)"; +// [/RLVa:KB] info["OPENGL_VERSION"] = (const char*)(glGetString(GL_VERSION)); info["J2C_VERSION"] = LLImageJ2C::getEngineInfo(); @@ -3433,7 +3457,10 @@ std::string LLAppViewer::getViewerInfoString() const } if (info.has("REGION")) { - support << "\n\n" << LLTrans::getString("AboutPosition", args); +// [RLVa:KB] - Checked: 2014-02-24 (RLVa-1.4.10) + support << "\n\n" << LLTrans::getString( (RlvActions::canShowLocation()) ? "AboutPosition" : "AboutPositionRLVShowLoc", args); +// [/RLVa:KB] +// support << "\n\n" << LLTrans::getString("AboutPosition", args); } support << "\n\n" << LLTrans::getString("AboutSystem", args); support << "\n"; diff --git a/indra/newview/llattachmentsmgr.cpp b/indra/newview/llattachmentsmgr.cpp index 7ed04b7f170abbb2c6962d6cbbe3ad38d84b66f7..3f16b1501531bd5cb5528d9bee41d2f341983a0d 100644 --- a/indra/newview/llattachmentsmgr.cpp +++ b/indra/newview/llattachmentsmgr.cpp @@ -35,6 +35,10 @@ #include "llviewerinventory.h" #include "llviewerregion.h" #include "message.h" +// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a) +#include "rlvhandler.h" +#include "rlvlocks.h" +// [/RLVa:KB] const F32 COF_LINK_BATCH_TIME = 5.0F; const F32 MAX_ATTACHMENT_REQUEST_LIFETIME = 30.0F; @@ -72,9 +76,14 @@ LLAttachmentsMgr::~LLAttachmentsMgr() { } +//void LLAttachmentsMgr::addAttachmentRequest(const LLUUID& item_id, +// const U8 attachment_pt, +// const BOOL add) +// [RLVa:KB] - Checked: 2010-09-13 (RLVa-1.2.1) void LLAttachmentsMgr::addAttachmentRequest(const LLUUID& item_id, const U8 attachment_pt, - const BOOL add) + const BOOL add, const BOOL fRlvForce /*=FALSE*/) +// [/RLVa:KB] { LLViewerInventoryItem *item = gInventory.getItem(item_id); @@ -92,6 +101,26 @@ void LLAttachmentsMgr::addAttachmentRequest(const LLUUID& item_id, attachment.mItemID = item_id; attachment.mAttachmentPt = attachment_pt; attachment.mAdd = add; + +// [RLVa:KB] - Checked: 2010-09-23 (RLVa-1.2.1) + if ( (rlv_handler_t::isEnabled()) && (!fRlvForce) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) && (gAgentWearables.areInitialAttachmentsRequested()) ) + { + 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); mAttachmentRequests.addTime(item_id); diff --git a/indra/newview/llattachmentsmgr.h b/indra/newview/llattachmentsmgr.h index 3221ae25800546b616bf6cd28f024248826eca59..4aee6614755508c6e425fceef88d77931eab4b21 100644 --- a/indra/newview/llattachmentsmgr.h +++ b/indra/newview/llattachmentsmgr.h @@ -75,9 +75,14 @@ class LLAttachmentsMgr: public LLSingleton<LLAttachmentsMgr> LLAttachmentsMgr(); virtual ~LLAttachmentsMgr(); +// [RLVa:KB] - Checked: 2010-09-13 (RLVa-1.2.1) void addAttachmentRequest(const LLUUID& item_id, const U8 attachment_pt, - const BOOL add); + const BOOL add, const BOOL fRlvForce = FALSE); +// [/RLVa:KB] +// void addAttachmentRequest(const LLUUID& item_id, +// const U8 attachment_pt, +// const BOOL add); void onAttachmentRequested(const LLUUID& item_id); void requestAttachments(attachments_vec_t& attachment_requests); static void onIdle(void *); diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp index a6e745448a98c921cd4a1aa46238d01b18251426..a86a61a69c89c236fd5fcd601821034f5aaf5bea 100644 --- a/indra/newview/llavataractions.cpp +++ b/indra/newview/llavataractions.cpp @@ -74,6 +74,10 @@ #include "llsidepanelinventory.h" #include "llavatarname.h" #include "llagentui.h" +// [RLVa:KB] - Checked: 2011-04-11 (RLVa-1.3.0) +#include "rlvactions.h" +#include "rlvcommon.h" +// [/RLVa:KB] // Flags for kick message const U32 KICK_FLAGS_DEFAULT = 0x0; @@ -203,6 +207,15 @@ void LLAvatarActions::startIM(const LLUUID& id) if (id.isNull() || gAgent.getID() == id) return; +// [RLVa:KB] - Checked: 2013-05-09 (RLVa-1.4.9) + if (!RlvActions::canStartIM(id)) + { + make_ui_sound("UISndInvalidOp"); + RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTIM, LLSD().with("RECIPIENT", LLSLURL("agent", id, "completename").getSLURLString())); + return; + } +// [/RLVa:KB] + LLAvatarNameCache::get(id, boost::bind(&on_avatar_name_cache_start_im, _1, _2)); } @@ -238,6 +251,16 @@ void LLAvatarActions::startCall(const LLUUID& id) { return; } + +// [RLVa:KB] - Checked: 2013-05-09 (RLVa-1.4.9) + if (!RlvActions::canStartIM(id)) + { + make_ui_sound("UISndInvalidOp"); + RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTIM, LLSD().with("RECIPIENT", LLSLURL("agent", id, "completename").getSLURLString())); + return; + } +// [/RLVa:KB] + LLAvatarNameCache::get(id, boost::bind(&on_avatar_name_cache_start_call, _1, _2)); } @@ -254,7 +277,17 @@ void LLAvatarActions::startAdhocCall(const uuid_vec_t& ids, const LLUUID& floate id_array.reserve(ids.size()); for (uuid_vec_t::const_iterator it = ids.begin(); it != ids.end(); ++it) { - id_array.push_back(*it); +// [RLVa:KB] - Checked: 2011-04-11 (RLVa-1.3.0) + const LLUUID& idAgent = *it; + if (!RlvActions::canStartIM(idAgent)) + { + make_ui_sound("UISndInvalidOp"); + RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTCONF); + return; + } + id_array.push_back(idAgent); +// [/RLVa:KB] +// id_array.push_back(*it); } // create the new ad hoc voice session @@ -301,7 +334,17 @@ void LLAvatarActions::startConference(const uuid_vec_t& ids, const LLUUID& float id_array.reserve(ids.size()); for (uuid_vec_t::const_iterator it = ids.begin(); it != ids.end(); ++it) { - id_array.push_back(*it); +// [RLVa:KB] - Checked: 2011-04-11 (RLVa-1.3.0) + const LLUUID& idAgent = *it; + if (!RlvActions::canStartIM(idAgent)) + { + make_ui_sound("UISndInvalidOp"); + RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTCONF); + return; + } + id_array.push_back(idAgent); +// [/RLVa:KB] +// id_array.push_back(*it); } const std::string title = LLTrans::getString("conference-title"); LLUUID session_id = gIMMgr->addSession(title, IM_SESSION_CONFERENCE_START, ids[0], id_array, false, floater_id); @@ -417,6 +460,17 @@ void LLAvatarActions::teleport_request_callback(const LLSD& notification, const { LLMessageSystem* msg = gMessageSystem; +// [RLVa:KB] - Checked: RLVa-2.0.0 + const LLUUID idRecipient = notification["substitutions"]["uuid"]; + std::string strMessage = response["message"]; + + // Filter the request message if the recipients is IM-blocked + if ( (RlvActions::isRlvEnabled()) && ((!RlvActions::canStartIM(idRecipient)) || (!RlvActions::canSendIM(idRecipient))) ) + { + strMessage = RlvStrings::getString(RLV_STRING_HIDDEN); + } +// [/RLVa:KB] + msg->newMessageFast(_PREHASH_ImprovedInstantMessage); msg->nextBlockFast(_PREHASH_AgentData); msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); @@ -434,7 +488,10 @@ void LLAvatarActions::teleport_request_callback(const LLSD& notification, const LLAgentUI::buildFullname(name); msg->addStringFast(_PREHASH_FromAgentName, name); - msg->addStringFast(_PREHASH_Message, response["message"]); +// [RLVa:KB] - Checked: RLVa-2.0.0 + msg->addStringFast(_PREHASH_Message, strMessage); +// [/RLVa:KB] +// msg->addStringFast(_PREHASH_Message, response["message"]); msg->addU32Fast(_PREHASH_ParentEstateID, 0); msg->addUUIDFast(_PREHASH_RegionID, LLUUID::null); msg->addVector3Fast(_PREHASH_Position, gAgent.getPositionAgent()); @@ -453,14 +510,17 @@ void LLAvatarActions::teleportRequest(const LLUUID& id) { LLSD notification; notification["uuid"] = id; - LLAvatarName av_name; - if (!LLAvatarNameCache::get(id, &av_name)) - { - // unlikely ... they just picked this name from somewhere... - LLAvatarNameCache::get(id, boost::bind(&LLAvatarActions::teleportRequest, id)); - return; // reinvoke this when the name resolves - } - notification["NAME"] = av_name.getCompleteName(); +// [RLVa:KB] - Checked: RLVa-1.5.0 + notification["NAME"] = LLSLURL("agent", id, (RlvActions::canShowName(RlvActions::SNC_TELEPORTREQUEST, id)) ? "completename" : "rlvanonym").getSLURLString(); +// [/RLVa:KB] +// LLAvatarName av_name; +// if (!LLAvatarNameCache::get(id, &av_name)) +// { +// // unlikely ... they just picked this name from somewhere... +// LLAvatarNameCache::get(id, boost::bind(&LLAvatarActions::teleportRequest, id)); +// return; // reinvoke this when the name resolves +// } +// notification["NAME"] = av_name.getCompleteName(); LLSD payload; diff --git a/indra/newview/llavatariconctrl.cpp b/indra/newview/llavatariconctrl.cpp index c131dc641b4e78b45fa71c87f2c9dcc8f85779e8..3bcc61302fbf5596985128ecd6fb577550958e76 100644 --- a/indra/newview/llavatariconctrl.cpp +++ b/indra/newview/llavatariconctrl.cpp @@ -330,3 +330,13 @@ void LLAvatarIconCtrl::onAvatarNameCache(const LLUUID& agent_id, const LLAvatarN } } } + +// [SL:KB] - Checked: 2010-11-01 (RLVa-1.2.2a) | Added: RLVa-1.2.2a +BOOL LLAvatarIconCtrl::handleToolTip(S32 x, S32 y, MASK mask) +{ + // Don't show our tooltip if we were asked not to + if (!mDrawTooltip) + return FALSE; + return LLIconCtrl::handleToolTip(x, y, mask); +} +// [/SL:KB] diff --git a/indra/newview/llavatariconctrl.h b/indra/newview/llavatariconctrl.h index 5b5720f4ac8fd74887b723c5feefe9d36e940ae8..75d6175254ba877142cb82e6a1b18d137a7e01cf 100644 --- a/indra/newview/llavatariconctrl.h +++ b/indra/newview/llavatariconctrl.h @@ -109,6 +109,10 @@ class LLAvatarIconCtrl public: virtual ~LLAvatarIconCtrl(); +// [SL:KB] - Checked: 2010-11-01 (RLVa-1.2.2a) | Added: RLVa-1.2.2a + /*virtual*/ BOOL handleToolTip(S32 x, S32 y, MASK mask); +// [/SL:KB] + virtual void setValue(const LLSD& value); // LLAvatarPropertiesProcessor observer trigger diff --git a/indra/newview/llavatarlist.cpp b/indra/newview/llavatarlist.cpp index 513f25e3017cd2795ae16c1698fc7d63d325a7c3..ef46dd1ed965a0c06fa4240ce753f9b52ac822da 100644 --- a/indra/newview/llavatarlist.cpp +++ b/indra/newview/llavatarlist.cpp @@ -141,6 +141,9 @@ LLAvatarList::LLAvatarList(const Params& p) , mShowSpeakingIndicator(p.show_speaking_indicator) , mShowPermissions(p.show_permissions_granted) , mShowCompleteName(false) +// [RLVa:KB] - Checked: RLVa-1.2.0 +, mRlvCheckShowNames(false) +// [/RLVa:KB] { setCommitOnSelectionChange(true); @@ -207,6 +210,10 @@ void LLAvatarList::draw() void LLAvatarList::clear() { getIDs().clear(); +// [RLVa:KB] - Checked: RLVa-2.0.3 + // We need to be able to call this *somehow* and it actually makes moderate sense to call this in here + updateNoItemsMessage(mNameFilter); +// [/RLVa:KB] setDirty(true); LLFlatListViewEx::clear(); } @@ -442,6 +449,9 @@ void LLAvatarList::addNewItem(const LLUUID& id, const std::string& name, BOOL is { LLAvatarListItem* item = new LLAvatarListItem(); item->setShowCompleteName(mShowCompleteName); +// [RLVa:KB] - Checked: RLVa-1.2.0 + item->setRlvCheckShowNames(mRlvCheckShowNames); +// [/RLVa:KB] // This sets the name as a side effect item->setAvatarId(id, mSessionID, mIgnoreOnlineStatus); item->setOnline(mIgnoreOnlineStatus ? true : is_online); diff --git a/indra/newview/llavatarlist.h b/indra/newview/llavatarlist.h index 1a672c279b1d94cec40d6f2fdc8a00dea0e5c372..0613434ebb4ae76db4509c4dc1a65bfca7d86088 100644 --- a/indra/newview/llavatarlist.h +++ b/indra/newview/llavatarlist.h @@ -92,6 +92,12 @@ class LLAvatarList : public LLFlatListViewEx // Return true if filter has at least one match. bool filterHasMatches(); +// [RLVa:KB] - Checked: RLVa-1.2.0 + void setRlvCheckShowNames(bool fRlvCheckShowNames) { mRlvCheckShowNames = fRlvCheckShowNames; } + // We need this to be public since we call it from RlvUIEnabler::onToggleShowNames() + void updateAvatarNames(); +// [/RLVa:KB] + boost::signals2::connection setRefreshCompleteCallback(const commit_signal_t::slot_type& cb); boost::signals2::connection setItemDoubleClickCallback(const mouse_signal_t::slot_type& cb); @@ -114,7 +120,7 @@ class LLAvatarList : public LLFlatListViewEx void updateLastInteractionTimes(); void rebuildNames(); void onItemDoubleClicked(LLUICtrl* ctrl, S32 x, S32 y, MASK mask); - void updateAvatarNames(); +// void updateAvatarNames(); private: @@ -130,6 +136,9 @@ class LLAvatarList : public LLFlatListViewEx bool mShowSpeakingIndicator; bool mShowPermissions; bool mShowCompleteName; +// [RLVa:KB] - RLVa-1.2.0 + bool mRlvCheckShowNames; +// [/RLVa:KB] LLTimer* mLITUpdateTimer; // last interaction time update timer std::string mIconParamName; diff --git a/indra/newview/llavatarlistitem.cpp b/indra/newview/llavatarlistitem.cpp index af3fac91bc07d17da393ad3010a7c9431c37f3ca..f0613f50de928dec8687f560367875accb1ebcdd 100644 --- a/indra/newview/llavatarlistitem.cpp +++ b/indra/newview/llavatarlistitem.cpp @@ -41,6 +41,10 @@ #include "llavatariconctrl.h" #include "lloutputmonitorctrl.h" #include "lltooldraganddrop.h" +// [RLVa:KB] - Checked: RLVa-2.0.1 +#include "rlvactions.h" +#include "rlvcommon.h" +// [/RLVa:KB] bool LLAvatarListItem::sStaticInitialized = false; S32 LLAvatarListItem::sLeftPadding = 0; @@ -76,6 +80,9 @@ LLAvatarListItem::LLAvatarListItem(bool not_from_ui_factory/* = true*/) mOnlineStatus(E_UNKNOWN), mShowInfoBtn(true), mShowProfileBtn(true), +// [RLVa:KB] - Checked: RLVa-1.2.0 + mRlvCheckShowNames(false), +// [/RLVa:KB] mShowPermissions(false), mShowCompleteName(false), mHovered(false), @@ -179,8 +186,13 @@ S32 LLAvatarListItem::notifyParent(const LLSD& info) void LLAvatarListItem::onMouseEnter(S32 x, S32 y, MASK mask) { getChildView("hovered_icon")->setVisible( true); - mInfoBtn->setVisible(mShowInfoBtn); - mProfileBtn->setVisible(mShowProfileBtn); +// mInfoBtn->setVisible(mShowInfoBtn); +// mProfileBtn->setVisible(mShowProfileBtn); +// [RLVa:KB] - Checked: RLVa-1.2.0 + bool fRlvCanShowName = (!mRlvCheckShowNames) || (RlvActions::canShowName(RlvActions::SNC_DEFAULT, mAvatarId)); + mInfoBtn->setVisible( (mShowInfoBtn) && (fRlvCanShowName) ); + mProfileBtn->setVisible( (mShowProfileBtn) && (fRlvCanShowName) ); +// [/RLVa:KB] mHovered = true; LLPanel::onMouseEnter(x, y, mask); @@ -357,12 +369,18 @@ void LLAvatarListItem::onProfileBtnClick() BOOL LLAvatarListItem::handleDoubleClick(S32 x, S32 y, MASK mask) { - if(mInfoBtn->getRect().pointInRect(x, y)) +// if(mInfoBtn->getRect().pointInRect(x, y)) +// [RVLa:KB] - Checked: RLVa-1.2.2 + if ( (mInfoBtn->getVisible()) && (mInfoBtn->getEnabled()) && (mInfoBtn->getRect().pointInRect(x, y)) ) +// [/SL:KB] { onInfoBtnClick(); return TRUE; } - if(mProfileBtn->getRect().pointInRect(x, y)) +// if(mProfileBtn->getRect().pointInRect(x, y)) +// [RLVa:KB] - Checked: RLVa-1.2.2 + if ( (mProfileBtn->getVisible()) && (mProfileBtn->getEnabled()) && (mProfileBtn->getRect().pointInRect(x, y)) ) +// [/SL:KB] { onProfileBtnClick(); return TRUE; @@ -422,8 +440,16 @@ void LLAvatarListItem::onAvatarNameCache(const LLAvatarName& av_name) mGreyOutUsername = "[ " + av_name.getUserName(true) + " ]"; LLStringUtil::toLower(mGreyOutUsername); } - setAvatarName(name_string); - setAvatarToolTip(av_name.getUserName()); +// setAvatarName(name_string); +// setAvatarToolTip(av_name.getUserName()); +// [RLVa:KB] - Checked: RLVa-1.2.2 + bool fRlvCanShowName = (!mRlvCheckShowNames) || (RlvActions::canShowName(RlvActions::SNC_DEFAULT, mAvatarId)); + + setAvatarName( (fRlvCanShowName) ? name_string : RlvStrings::getAnonym(av_name) ); + setAvatarToolTip( (fRlvCanShowName) ? av_name.getUserName() : RlvStrings::getAnonym(av_name) ); + // TODO-RLVa: bit of a hack putting this here. Maybe find a better way? + mAvatarIcon->setDrawTooltip(fRlvCanShowName); +// [/RLVa:KB] //requesting the list to resort notifyParent(LLSD().with("sort", LLSD())); diff --git a/indra/newview/llavatarlistitem.h b/indra/newview/llavatarlistitem.h index 36d18114aaec80f6d6a4484b9df94c5c8b41027e..96e4fc3cc7cc8f6b9e8e147160f73a858e02af0a 100644 --- a/indra/newview/llavatarlistitem.h +++ b/indra/newview/llavatarlistitem.h @@ -107,6 +107,9 @@ class LLAvatarListItem : public LLPanel, public LLFriendObserver void showLastInteractionTime(bool show); void setAvatarIconVisible(bool visible); void setShowCompleteName(bool show) { mShowCompleteName = show;}; +// [RLVa:KB] - Checked: RLVa-1.2.0 + void setRlvCheckShowNames(bool fRlvCheckShowNames) { mRlvCheckShowNames = fRlvCheckShowNames; } +// [/RLVa:KB] const LLUUID& getAvatarId() const; std::string getAvatarName() const; @@ -212,6 +215,9 @@ class LLAvatarListItem : public LLPanel, public LLFriendObserver //Speaker indicator and avatar name coords are translated accordingly bool mShowInfoBtn; bool mShowProfileBtn; +// [RLVa:KB] - Checked: RLVa-1.2.0 + bool mRlvCheckShowNames; +// [/RLVa:KB] /// indicates whether to show icons representing permissions granted bool mShowPermissions; diff --git a/indra/newview/llchatbar.cpp b/indra/newview/llchatbar.cpp index 00fa6dd9798793d036595787ecfdfc65d3520fe0..90f5fee4d9c394e4637703a9f35d7bba9db2a407 100644 --- a/indra/newview/llchatbar.cpp +++ b/indra/newview/llchatbar.cpp @@ -59,6 +59,9 @@ #include "llui.h" #include "llviewermenu.h" #include "lluictrlfactory.h" +// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0b) +#include "rlvhandler.h" +// [/RLVa:KB] // // Globals @@ -78,7 +81,10 @@ class LLChatBarGestureObserver : public LLGestureManagerObserver }; -extern void send_chat_from_viewer(const std::string& utf8_out_text, EChatType type, S32 channel); +//extern void send_chat_from_viewer(const std::string& utf8_out_text, EChatType type, S32 channel); +// [RLVa:KB] - Checked: 2010-02-27 (RLVa-0.2.2) +extern void send_chat_from_viewer(std::string utf8_out_text, EChatType type, S32 channel); +// [/RLVa:KB] // // Functions @@ -471,7 +477,11 @@ void LLChatBar::onInputEditorKeystroke( LLLineEditor* caller, void* userdata ) S32 length = raw_text.length(); - if( (length > 0) && (raw_text[0] != '/') ) // forward slash is used for escape (eg. emote) sequences +// if( (length > 0) && (raw_text[0] != '/') ) // forward slash is used for escape (eg. emote) sequences +// [RLVa:KB] - Checked: 2010-03-26 (RLVa-1.2.0b) | Modified: RLVa-1.0.0d + // RELEASE-RLVa: [SL-2.0.0] This entire class appears to be dead/non-functional? + if ( (length > 0) && (raw_text[0] != '/') && (!gRlvHandler.hasBehaviour(RLV_BHVR_REDIRCHAT)) ) +// [/RLVa:KB] { gAgent.startTyping(); } @@ -583,6 +593,22 @@ 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.2.0b) | Modified: RLVa-1.2.0b + // RELEASE-RLVa: [SL-2.0.0] This entire class appears to be dead/non-functional? + if ( (0 == channel) && (rlv_handler_t::isEnabled()) ) + { + // Adjust the (public) chat "volume" on chat and gestures (also takes care of playing the proper animation) + if ( ((CHAT_TYPE_SHOUT == type) || (CHAT_TYPE_NORMAL == type)) && (gRlvHandler.hasBehaviour(RLV_BHVR_CHATNORMAL)) ) + type = CHAT_TYPE_WHISPER; + else if ( (CHAT_TYPE_SHOUT == type) && (gRlvHandler.hasBehaviour(RLV_BHVR_CHATSHOUT)) ) + type = CHAT_TYPE_NORMAL; + else if ( (CHAT_TYPE_WHISPER == type) && (gRlvHandler.hasBehaviour(RLV_BHVR_CHATWHISPER)) ) + type = CHAT_TYPE_NORMAL; + + animate &= !gRlvHandler.hasBehaviour( (!RlvUtil::isEmote(utf8_text)) ? RLV_BHVR_REDIRCHAT : RLV_BHVR_REDIREMOTE ); + } +// [/RLVa:KB] + // Don't animate for chats people can't hear (chat to scripts) if (animate && (channel == 0)) { diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp index 5d2997688fc2a0f172a4ed43d78263c260f45e88..bff789d3744f11ffce7efd6c359fa91743963781 100644 --- a/indra/newview/llchathistory.cpp +++ b/indra/newview/llchathistory.cpp @@ -62,6 +62,9 @@ #include "llviewercontrol.h" #include "llviewerobjectlist.h" #include "llmutelist.h" +// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) +#include "rlvcommon.h" +// [/RLVa:KB] static LLDefaultChildRegistry::Register<LLChatHistory> r("chat_history"); @@ -93,6 +96,10 @@ class LLObjectIMHandler : public LLCommandHandler LLSD payload; payload["object_id"] = object_id; payload["owner_id"] = query_map["owner"]; +// [RLVa:KB] - Checked: 2010-11-02 (RLVa-1.2.2a) | Modified: RLVa-1.2.2a + if (query_map.has("rlv_shownames")) + payload["rlv_shownames"] = query_map["rlv_shownames"]; +// [/RLVa:KB] payload["name"] = query_map["name"]; payload["slurl"] = LLWeb::escapeURL(query_map["slurl"]); payload["group_owned"] = query_map["groupowned"]; @@ -108,6 +115,10 @@ class LLChatHistoryHeader: public LLPanel LLChatHistoryHeader() : LLPanel(), mInfoCtrl(NULL), +// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.2a) | Added: RLVa-1.2.0f + mShowContextMenu(true), + mShowInfoCtrl(true), +// [/RLVa:KB] mPopupMenuHandleAvatar(), mPopupMenuHandleObject(), mAvatarID(), @@ -348,7 +359,11 @@ class LLChatHistoryHeader: public LLPanel void showInspector() { - if (mAvatarID.isNull() && CHAT_SOURCE_SYSTEM != mSourceType) return; +// if (mAvatarID.isNull() && CHAT_SOURCE_SYSTEM != mSourceType) return; +// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.2a) | Added: RLVa-1.2.0f + // Don't double-click show the inspector if we're not showing the info control + if ( (!mShowInfoCtrl) || (mAvatarID.isNull() && CHAT_SOURCE_SYSTEM != mSourceType) ) return; +// [/RLVa:KB] if (mSourceType == CHAT_SOURCE_OBJECT) { @@ -412,8 +427,24 @@ class LLChatHistoryHeader: public LLPanel // Start with blank so sample data from XUI XML doesn't // flash on the screen - user_name->setValue( LLSD() ); - fetchAvatarName(); +// user_name->setValue( LLSD() ); +// fetchAvatarName(); +// [RLVa:KB] - Checked: 2010-11-01 (RLVa-1.2.2a) | Added: RLVa-1.2.2a + if (!chat.mRlvNamesFiltered) + { + user_name->setValue( LLSD() ); + fetchAvatarName(); + } + else + { + // If the agent's chat was subject to @shownames=n we should display their anonimized name + mFrom = chat.mFromName; + user_name->setValue(mFrom); + user_name->setToolTip(mFrom); + setToolTip(mFrom); + updateMinUserNameWidth(); + } +// [/RLVa:KB] } else if (chat.mChatStyle == CHAT_STYLE_HISTORY || mSourceType == CHAT_SOURCE_AGENT) @@ -465,6 +496,15 @@ class LLChatHistoryHeader: public LLPanel if(mSourceType != CHAT_SOURCE_AGENT || mAvatarID.isNull()) icon->setDrawTooltip(false); +// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.2a) | Added: RLVa-1.2.0f + // Don't show the context menu, info control or avatar icon tooltip if this chat was subject to @shownames=n + if ( (chat.mRlvNamesFiltered) && ((CHAT_SOURCE_AGENT == mSourceType) || (CHAT_SOURCE_OBJECT == mSourceType)) ) + { + mShowInfoCtrl = mShowContextMenu = false; + icon->setDrawTooltip(false); + } +// [/RLVa:KB] + switch (mSourceType) { case CHAT_SOURCE_AGENT: @@ -541,6 +581,10 @@ class LLChatHistoryHeader: public LLPanel void showContextMenu(S32 x,S32 y) { +// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.2a) | Added: RLVa-1.2.0f + if (!mShowContextMenu) + return; +// [/RLVa:KB] if(mSourceType == CHAT_SOURCE_SYSTEM) showSystemContextMenu(x,y); if(mAvatarID.notNull() && mSourceType == CHAT_SOURCE_AGENT) @@ -615,7 +659,10 @@ class LLChatHistoryHeader: public LLPanel void showInfoCtrl() { - const bool isVisible = !mAvatarID.isNull() && !mFrom.empty() && CHAT_SOURCE_SYSTEM != mSourceType; +// const bool isVisible = !mAvatarID.isNull() && !mFrom.empty() && CHAT_SOURCE_SYSTEM != mSourceType; +// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.2a) | Added: RLVa-1.2.0f + const bool isVisible = mShowInfoCtrl && !mAvatarID.isNull() && !mFrom.empty() && CHAT_SOURCE_SYSTEM != mSourceType; +// [/RLVa:KB] if (isVisible) { const LLRect sticky_rect = mUserNameTextBox->getRect(); @@ -705,6 +752,10 @@ class LLChatHistoryHeader: public LLPanel EChatSourceType mSourceType; std::string mFrom; LLUUID mSessionID; +// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.2a) | Added: RLVa-1.2.0f + bool mShowContextMenu; + bool mShowInfoCtrl; +// [/RLVa:KB] S32 mMinUserNameWidth; const LLFontGL* mUserNameFont; @@ -989,8 +1040,18 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL // Don't hotlink any messages from the system (e.g. "Second Life:"), so just add those in plain text. if ( chat.mSourceType == CHAT_SOURCE_OBJECT && chat.mFromID.notNull()) { - // for object IMs, create a secondlife:///app/objectim SLapp - std::string url = LLViewerChat::getSenderSLURL(chat, args); +// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Added: RLVa-1.2.0f + // NOTE-RLVa: we don't need to do any @shownames or @showloc filtering here because we'll already have an existing URL + std::string url = chat.mURL; + RLV_ASSERT( (url.empty()) || (std::string::npos != url.find("objectim")) ); + if ( (url.empty()) || (std::string::npos == url.find("objectim")) ) + { +// [/RLVa:KB] + // for object IMs, create a secondlife:///app/objectim SLapp + /*std::string*/ url = LLViewerChat::getSenderSLURL(chat, args); +// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Added: RLVa-1.2.0f + } +// [/RLVa:KB] // set the link for the object name to be the objectim SLapp // (don't let object names with hyperlinks override our objectim Url) @@ -1004,7 +1065,10 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL mEditor->appendText(chat.mFromName + delimiter, prependNewLineState, link_params); prependNewLineState = false; } - else if ( chat.mFromName != SYSTEM_FROM && chat.mFromID.notNull() && !message_from_log) +// else if (chat.mFromName != SYSTEM_FROM && chat.mFromID.notNull() && !message_from_log) +// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Added: RLVa-1.2.0f + else if (chat.mFromName != SYSTEM_FROM && chat.mFromID.notNull() && !message_from_log && !chat.mRlvNamesFiltered) +// [/RLVa:KB] { LLStyle::Params link_params(body_message_params); link_params.overwriteFrom(LLStyleMap::instance().lookupAgent(chat.mFromID)); diff --git a/indra/newview/llchatitemscontainerctrl.cpp b/indra/newview/llchatitemscontainerctrl.cpp index cfc62c07b6e073a8ee36e930cb74ec6fcd465a1c..54593311df2cfc1d59f9b24eba1dd25675d0cfb7 100644 --- a/indra/newview/llchatitemscontainerctrl.cpp +++ b/indra/newview/llchatitemscontainerctrl.cpp @@ -41,6 +41,10 @@ #include "llslurl.h" +// [RLVa:KB] - Checked: 2010-04-21 (RLVa-1.2.0f) +#include "rlvhandler.h" +// [/RLVa:KB] + static const S32 msg_left_offset = 10; static const S32 msg_right_offset = 10; static const S32 msg_height_pad = 5; @@ -182,7 +186,11 @@ void LLFloaterIMNearbyChatToastPanel::init(LLSD& notification) std::string fromName = notification["from"].asString(); // agent or object name mFromID = notification["from_id"].asUUID(); // agent id or object id mFromName = fromName; - + +// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Added: RLVa-1.2.0f + mShowIconTooltip = notification.has("show_icon_tooltip") ? notification["show_icon_tooltip"].asBoolean() : true; +// [/RLVa:KB] + int sType = notification["source"].asInteger(); mSourceType = (EChatSourceType)sType; @@ -228,8 +236,15 @@ void LLFloaterIMNearbyChatToastPanel::init(LLSD& notification) style_params_name.font.name(font_name); style_params_name.font.size(font_style_size); - style_params_name.link_href = notification["sender_slurl"].asString(); - style_params_name.is_link = true; +// style_params_name.link_href = notification["sender_slurl"].asString(); +// style_params_name.is_link = true; +// [RLVa:KB] - Checked: 2011-12-13 (RLVa-1.4.6) | Added: RLVa-1.4.6 + if (notification.has("sender_slurl")) + { + style_params_name.link_href = notification["sender_slurl"].asString(); + style_params_name.is_link = true; + } +// [/RLVa:KB] mMsgText->appendText(str_sender, FALSE, style_params_name); @@ -365,7 +380,10 @@ void LLFloaterIMNearbyChatToastPanel::draw() LLAvatarIconCtrl* icon = getChild<LLAvatarIconCtrl>("avatar_icon", false); if(icon) { - icon->setDrawTooltip(mSourceType == CHAT_SOURCE_AGENT); +// icon->setDrawTooltip(mSourceType == CHAT_SOURCE_AGENT); +// [RLVa:KB] - Checked: 2010-04-200 (RLVa-1.2.0f) | Added: RLVa-1.2.0f + icon->setDrawTooltip( (mShowIconTooltip) && (mSourceType == CHAT_SOURCE_AGENT) ); +// [/RLVa:KB] if(mSourceType == CHAT_SOURCE_OBJECT) icon->setValue(LLSD("OBJECT_Icon")); else if(mSourceType == CHAT_SOURCE_SYSTEM) diff --git a/indra/newview/llchatitemscontainerctrl.h b/indra/newview/llchatitemscontainerctrl.h index f66670ec8c83a91c3ac61fce643b925261906abb..bf977002f335c25d26b3c4e423074aec996c2f09 100644 --- a/indra/newview/llchatitemscontainerctrl.h +++ b/indra/newview/llchatitemscontainerctrl.h @@ -47,6 +47,9 @@ class LLFloaterIMNearbyChatToastPanel : public LLPanel LLFloaterIMNearbyChatToastPanel() : mIsDirty(false), +// [RLVa:KB] - Checked: 2010-04-200 (RLVa-1.2.0f) | Added: RLVa-1.2.0f + mShowIconTooltip(true), +// [/RLVa:KB] mSourceType(CHAT_SOURCE_OBJECT) {}; public: @@ -91,6 +94,9 @@ class LLFloaterIMNearbyChatToastPanel : public LLPanel bool mIsDirty; +// [RLVa:KB] - Checked: 2010-04-200 (RLVa-1.2.0f) | Added: RLVa-1.2.0f + bool mShowIconTooltip; +// [/RLVa:KB] }; diff --git a/indra/newview/llchiclet.cpp b/indra/newview/llchiclet.cpp index dedb06c9459404a0b73fdfc3684949b86f62ff06..98e616f8f9b2c6ada01eb21d5e86209c773bfca5 100644 --- a/indra/newview/llchiclet.cpp +++ b/indra/newview/llchiclet.cpp @@ -36,6 +36,9 @@ #include "llsingleton.h" #include "llsyswellwindow.h" #include "llfloaternotificationstabbed.h" +// [SL:KB] - Patch: UI-Notifications | Checked: 2013-05-09 (Catznip-3.5) +#include "llchannelmanager.h" +// [/SL:KB] static LLDefaultChildRegistry::Register<LLChicletPanel> t1("chiclet_panel"); static LLDefaultChildRegistry::Register<LLNotificationChiclet> t2("chiclet_notification"); @@ -237,6 +240,15 @@ bool LLNotificationChiclet::ChicletNotificationChannel::filterNotification( LLNo { displayNotification = true; } +// [SL:KB] - Patch: UI-Notifications | Checked: 2013-05-09 (Catznip-3.5) + else if ("offer" == notification->getType()) + { + // Assume that any offer notification with "getCanBeStored() == true" is the result of RLVa routing it to the notifcation syswell + /*const*/ LLNotificationsUI::LLScreenChannel* pChannel = LLNotificationsUI::LLChannelManager::instance().getNotificationScreenChannel(); + /*const*/ LLNotificationsUI::LLToast* pToast = (pChannel) ? pChannel->getToastByNotificationID(notification->getID()) : NULL; + displayNotification = (pToast) && (pToast->getCanBeStored()); + } +// [/SL:KB] else { displayNotification = false; diff --git a/indra/newview/lldaycyclemanager.cpp b/indra/newview/lldaycyclemanager.cpp index 803e2b2fb22e9544df263b883be8b6c326b1d5b3..b8d7b8ec3c1f4c5ea686332cd3d1c17bf3336676 100644 --- a/indra/newview/lldaycyclemanager.cpp +++ b/indra/newview/lldaycyclemanager.cpp @@ -30,6 +30,10 @@ #include "lldiriterator.h" +// [RLVa:KB] - Checked: 2011-09-04 (RLVa-1.4.1a) | Added: RLVa-1.4.1a +#include <boost/algorithm/string.hpp> +// [/RLVa:KB] + void LLDayCycleManager::getPresetNames(preset_name_list_t& names) const { names.clear(); @@ -60,6 +64,18 @@ void LLDayCycleManager::getPresetNames(preset_name_list_t& user, preset_name_lis } } +// [RLVa:KB] - Checked: 2011-09-04 (RLVa-1.4.1a) | Added: RLVa-1.4.1a +const std::string& LLDayCycleManager::findPreset(const std::string& strPresetName) +{ + for (dc_map_t::const_iterator itCycle = mDayCycleMap.begin(); itCycle != mDayCycleMap.end(); ++itCycle) + { + if (boost::iequals(itCycle->first, strPresetName)) + return itCycle->first; + } + return LLStringUtil::null; +} +// [/RLVa:KB] + void LLDayCycleManager::getUserPresetNames(preset_name_list_t& user) const { preset_name_list_t sys; // unused diff --git a/indra/newview/lldaycyclemanager.h b/indra/newview/lldaycyclemanager.h index 3d2144960da160d3429ec6b039f7db70f554911a..81b31dc71c536c2644752286e8b5ff16bf816f08 100644 --- a/indra/newview/lldaycyclemanager.h +++ b/indra/newview/lldaycyclemanager.h @@ -51,6 +51,9 @@ class LLDayCycleManager : public LLSingleton<LLDayCycleManager> void getPresetNames(preset_name_list_t& names) const; void getPresetNames(preset_name_list_t& user, preset_name_list_t& sys) const; void getUserPresetNames(preset_name_list_t& user) const; +// [RLVa:KB] - Checked: 2011-09-04 (RLVa-1.4.1a) | Added: RLVa-1.4.1a + const std::string& findPreset(const std::string& strPresetName); +// [/RLVa:KB] bool getPreset(const std::string name, LLWLDayCycle& day_cycle) const; bool getPreset(const std::string name, LLSD& day_cycle) const; diff --git a/indra/newview/lldrawpoolterrain.cpp b/indra/newview/lldrawpoolterrain.cpp index b716a7654369f39b00f7465d5fd995e333c88a8a..fd3401243de2ac4bb2181dfd23e767a15aa219f7 100644 --- a/indra/newview/lldrawpoolterrain.cpp +++ b/indra/newview/lldrawpoolterrain.cpp @@ -308,10 +308,16 @@ void LLDrawPoolTerrain::renderFullShader() // Hack! Get the region that this draw pool is rendering from! LLViewerRegion *regionp = mDrawFace[0]->getDrawable()->getVObj()->getRegion(); LLVLComposition *compp = regionp->getComposition(); - LLViewerTexture *detail_texture0p = compp->mDetailTextures[0]; - LLViewerTexture *detail_texture1p = compp->mDetailTextures[1]; - LLViewerTexture *detail_texture2p = compp->mDetailTextures[2]; - LLViewerTexture *detail_texture3p = compp->mDetailTextures[3]; +// [SL:KB] - Patch: Render-TextureToggle (Catznip-4.0) + LLViewerTexture *detail_texture0p = (LLPipeline::sRenderTextures) ? compp->mDetailTextures[0] : LLViewerFetchedTexture::sDefaultDiffuseImagep; + LLViewerTexture *detail_texture1p = (LLPipeline::sRenderTextures) ? compp->mDetailTextures[1] : LLViewerFetchedTexture::sDefaultDiffuseImagep; + LLViewerTexture *detail_texture2p = (LLPipeline::sRenderTextures) ? compp->mDetailTextures[2] : LLViewerFetchedTexture::sDefaultDiffuseImagep; + LLViewerTexture *detail_texture3p = (LLPipeline::sRenderTextures) ? compp->mDetailTextures[3] : LLViewerFetchedTexture::sDefaultDiffuseImagep; +// [/SL:KB] +// LLViewerTexture *detail_texture0p = compp->mDetailTextures[0]; +// LLViewerTexture *detail_texture1p = compp->mDetailTextures[1]; +// LLViewerTexture *detail_texture2p = compp->mDetailTextures[2]; +// LLViewerTexture *detail_texture3p = compp->mDetailTextures[3]; LLVector3d region_origin_global = gAgent.getRegion()->getOriginGlobal(); F32 offset_x = (F32)fmod(region_origin_global.mdV[VX], 1.0/(F64)sDetailScale)*sDetailScale; @@ -459,10 +465,16 @@ void LLDrawPoolTerrain::renderFull4TU() // Hack! Get the region that this draw pool is rendering from! LLViewerRegion *regionp = mDrawFace[0]->getDrawable()->getVObj()->getRegion(); LLVLComposition *compp = regionp->getComposition(); - LLViewerTexture *detail_texture0p = compp->mDetailTextures[0]; - LLViewerTexture *detail_texture1p = compp->mDetailTextures[1]; - LLViewerTexture *detail_texture2p = compp->mDetailTextures[2]; - LLViewerTexture *detail_texture3p = compp->mDetailTextures[3]; +// [SL:KB] - Patch: Render-TextureToggle (Catznip-4.0) + LLViewerTexture *detail_texture0p = (LLPipeline::sRenderTextures) ? compp->mDetailTextures[0] : LLViewerFetchedTexture::sDefaultDiffuseImagep; + LLViewerTexture *detail_texture1p = (LLPipeline::sRenderTextures) ? compp->mDetailTextures[1] : LLViewerFetchedTexture::sDefaultDiffuseImagep; + LLViewerTexture *detail_texture2p = (LLPipeline::sRenderTextures) ? compp->mDetailTextures[2] : LLViewerFetchedTexture::sDefaultDiffuseImagep; + LLViewerTexture *detail_texture3p = (LLPipeline::sRenderTextures) ? compp->mDetailTextures[3] : LLViewerFetchedTexture::sDefaultDiffuseImagep; +// [/SL:KB] +// LLViewerTexture *detail_texture0p = compp->mDetailTextures[0]; +// LLViewerTexture *detail_texture1p = compp->mDetailTextures[1]; +// LLViewerTexture *detail_texture2p = compp->mDetailTextures[2]; +// LLViewerTexture *detail_texture3p = compp->mDetailTextures[3]; LLVector3d region_origin_global = gAgent.getRegion()->getOriginGlobal(); F32 offset_x = (F32)fmod(region_origin_global.mdV[VX], 1.0/(F64)sDetailScale)*sDetailScale; @@ -661,10 +673,16 @@ void LLDrawPoolTerrain::renderFull2TU() // Hack! Get the region that this draw pool is rendering from! LLViewerRegion *regionp = mDrawFace[0]->getDrawable()->getVObj()->getRegion(); LLVLComposition *compp = regionp->getComposition(); - LLViewerTexture *detail_texture0p = compp->mDetailTextures[0]; - LLViewerTexture *detail_texture1p = compp->mDetailTextures[1]; - LLViewerTexture *detail_texture2p = compp->mDetailTextures[2]; - LLViewerTexture *detail_texture3p = compp->mDetailTextures[3]; +// [SL:KB] - Patch: Render-TextureToggle (Catznip-4.0) + LLViewerTexture *detail_texture0p = (LLPipeline::sRenderTextures) ? compp->mDetailTextures[0] : LLViewerFetchedTexture::sDefaultDiffuseImagep; + LLViewerTexture *detail_texture1p = (LLPipeline::sRenderTextures) ? compp->mDetailTextures[1] : LLViewerFetchedTexture::sDefaultDiffuseImagep; + LLViewerTexture *detail_texture2p = (LLPipeline::sRenderTextures) ? compp->mDetailTextures[2] : LLViewerFetchedTexture::sDefaultDiffuseImagep; + LLViewerTexture *detail_texture3p = (LLPipeline::sRenderTextures) ? compp->mDetailTextures[3] : LLViewerFetchedTexture::sDefaultDiffuseImagep; +// [/SL:KB] +// LLViewerTexture *detail_texture0p = compp->mDetailTextures[0]; +// LLViewerTexture *detail_texture1p = compp->mDetailTextures[1]; +// LLViewerTexture *detail_texture2p = compp->mDetailTextures[2]; +// LLViewerTexture *detail_texture3p = compp->mDetailTextures[3]; LLVector3d region_origin_global = gAgent.getRegion()->getOriginGlobal(); F32 offset_x = (F32)fmod(region_origin_global.mdV[VX], 1.0/(F64)sDetailScale)*sDetailScale; diff --git a/indra/newview/lldrawpooltree.cpp b/indra/newview/lldrawpooltree.cpp index b1f40781f73e5bcdccd50ac111e41d928b8492cc..ecba1dc75db63f0df70b8933f7345010058aa050 100644 --- a/indra/newview/lldrawpooltree.cpp +++ b/indra/newview/lldrawpooltree.cpp @@ -98,7 +98,10 @@ void LLDrawPoolTree::render(S32 pass) LLGLState test(GL_ALPHA_TEST, LLGLSLShader::sNoFixedFunction ? 0 : 1); LLOverrideFaceColor color(this, 1.f, 1.f, 1.f, 1.f); - gGL.getTexUnit(sDiffTex)->bind(mTexturep); +// [SL:KB] - Patch: Render-TextureToggle (Catznip-4.0) + gGL.getTexUnit(sDiffTex)->bind( (LLPipeline::sRenderTextures) ? mTexturep : LLViewerFetchedTexture::sDefaultDiffuseImagep ); +// [/SL:KB] +// gGL.getTexUnit(sDiffTex)->bind(mTexturep); for (std::vector<LLFace*>::iterator iter = mDrawFace.begin(); iter != mDrawFace.end(); iter++) diff --git a/indra/newview/llenvmanager.cpp b/indra/newview/llenvmanager.cpp index a626ad1bffa7b9220cb290ce369c7d806a86d8bb..73b376a55e0c68649746004ac9a035f9caf8fc04 100644 --- a/indra/newview/llenvmanager.cpp +++ b/indra/newview/llenvmanager.cpp @@ -35,6 +35,10 @@ #include "llwaterparammanager.h" #include "llwlhandlers.h" #include "llwlparammanager.h" +// [RLVa:KB] - Checked: 2011-09-04 (RLVa-1.4.1a) | Added: RLVa-1.4.1a +#include <boost/algorithm/string.hpp> +#include "rlvhandler.h" +// [/RLVa:KB] std::string LLEnvPrefs::getWaterPresetName() const { @@ -479,7 +483,10 @@ void LLEnvManagerNew::onRegionSettingsResponse(const LLSD& content) LLWLParamManager::instance().refreshRegionPresets(); // If using server settings, update managers. - if (getUseRegionSettings()) +// if (getUseRegionSettings()) +// [RLVa:KB] - Checked: 2011-08-29 (RLVa-1.4.1a) | Added: RLVa-1.4.1a + if ( (getUseRegionSettings()) && (LLWLParamManager::getInstance()->mAnimator.getIsRunning()) ) +// [/RLVa:KB] { updateManagersFromPrefs(mInterpNextChangeMessage); } @@ -590,6 +597,14 @@ void LLEnvManagerNew::updateWaterFromPrefs(bool interpolate) void LLEnvManagerNew::updateManagersFromPrefs(bool interpolate) { LL_DEBUGS("Windlight")<<LL_ENDL; + +// [RLVa:KB] - Checked: 2011-09-04 (RLVa-1.4.1a) | Added: RLVa-1.4.1a + if (gRlvHandler.hasBehaviour(RLV_BHVR_SETENV)) + { + return; + } +// [/RLVa:KB] + // Apply water settings. updateWaterFromPrefs(interpolate); diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index de349a03d4cafe9878c5e53bbae42b2335995c00..b4c1fc96c514ac33c7fe2836f7b84bc07037e4f0 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -53,6 +53,9 @@ #include "llviewershadermgr.h" #include "llviewertexture.h" #include "llvoavatar.h" +// [RLVa:KB] - Checked: RLVa-2.0.0 +#include "rlvhandler.h" +// [/RLVa:KB] #if LL_LINUX // Work-around spurious used before init warning on Vector4a @@ -166,6 +169,10 @@ void LLFace::init(LLDrawable* drawablep, LLViewerObject* objp) mBoundingSphereRadius = 0.0f ; mHasMedia = FALSE ; + +// [SL:KB] - Patch: Render-TextureToggle (Catznip-4.0) + mShowDiffTexture = true; +// [/SL:KB] } void LLFace::destroy() @@ -282,6 +289,15 @@ void LLFace::setTexture(U32 ch, LLViewerTexture* tex) return ; } +// [SL:KB] - Patch: Render-TextureToggle (Catznip-4.0) + if ( (LLRender::DIFFUSE_MAP == ch) && (!mShowDiffTexture) ) + { + mOrigDiffTexture = tex; + if (LLViewerFetchedTexture::sDefaultDiffuseImagep.get() == mTexture[ch].get()) + return; + } +// [/SL:KB] + if(mTexture[ch].notNull()) { mTexture[ch]->removeFace(ch, this) ; @@ -2644,9 +2660,60 @@ LLViewerTexture* LLFace::getTexture(U32 ch) const { llassert(ch < LLRender::NUM_TEXTURE_CHANNELS); +// [SL:KB] - Patch: Render-TextureToggle (Catznip-4.0) + // Check whether the diffuse texture needs to be obscured or restored + if (mShowDiffTexture != LLPipeline::sRenderTextures) + setDefaultTexture(LLRender::DIFFUSE_MAP, !LLPipeline::sRenderTextures); +// [/SL:KB] + return mTexture[ch] ; } +// [SL:KB] - Patch: Render-TextureToggle (Catznip-4.0) +void LLFace::setDefaultTexture(U32 nChannel, bool fShowDefault) const +{ + bool fUpdated = false; + if ( (LLRender::DIFFUSE_MAP == nChannel) && (mVObjp) && (!mVObjp->isDead()) && ((LL_PCODE_VOLUME == mVObjp->getPCode()) || (LLViewerObject::LL_VO_PART_GROUP == mVObjp->getPCode())) ) + { + if ( ((mShowDiffTexture) && (fShowDefault)) || + ((!mShowDiffTexture) && (fShowDefault) && (mOrigDiffTexture.notNull()) && (mTexture[nChannel]) && (mTexture[nChannel]->getID() != LLViewerFetchedTexture::sDefaultDiffuseImagep->getID())) ) + { + if (mOrigDiffTexture.notNull()) + mShowDiffTexture = true; // Swap out the default texture + else + mOrigDiffTexture = mTexture[nChannel]; // Cache the original texture + + if ( (!gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_TEXTURES)) || (!mVObjp->isAttachment()) ) + { + if (LL_PCODE_VOLUME == mVObjp->getPCode()) + const_cast<LLFace*>(this)->switchTexture(nChannel, LLViewerFetchedTexture::sDefaultDiffuseImagep); + else + const_cast<LLFace*>(this)->setTexture(nChannel, LLViewerFetchedTexture::sDefaultDiffuseImagep); + } + mShowDiffTexture = false; fUpdated = true; + } + else if ( (!mShowDiffTexture) && (!fShowDefault) && (mOrigDiffTexture.notNull()) ) + { + mShowDiffTexture = true; + if (LL_PCODE_VOLUME == mVObjp->getPCode()) + const_cast<LLFace*>(this)->switchTexture(nChannel, mOrigDiffTexture); + else + const_cast<LLFace*>(this)->setTexture(nChannel, mOrigDiffTexture); + mOrigDiffTexture = nullptr; fUpdated = true; + } + + if ((fUpdated) && (mDrawablep)) + { + gPipeline.markTextured(mDrawablep); + const_cast<LLDrawable*>(mDrawablep.get())->updateTexture(); + } + } + + // Always flip the flag even if we didn't obscure so we don't keep wasting cycles with negative checks + mShowDiffTexture = !fShowDefault; +} +// [/SL:KB] + void LLFace::setVertexBuffer(LLVertexBuffer* buffer) { mVertexBuffer = buffer; diff --git a/indra/newview/llface.h b/indra/newview/llface.h index ee545acb94104c53bde604d81844acab02e1000f..35cfdc1f8b66f8301f97eecbf965c60acadb1362 100644 --- a/indra/newview/llface.h +++ b/indra/newview/llface.h @@ -220,6 +220,10 @@ class LLFace : public LLTrace::MemTrackableNonVirtual<LLFace, 16> BOOL switchTexture() ; +// [SL:KB] - Patch: Render-TextureToggle (Catznip-4.0) + void setDefaultTexture(U32 nChannel, bool fShowDefault) const; +// [/SL:KB] + //vertex buffer tracking void setVertexBuffer(LLVertexBuffer* buffer); void clearVertexBuffer(); //sets mVertexBuffer to NULL @@ -294,7 +298,11 @@ class LLFace : public LLTrace::MemTrackableNonVirtual<LLFace, 16> F32 mBoundingSphereRadius ; bool mHasMedia ; - +// [SL:KB] - Patch: Render-TextureToggle (Catznip-4.0) + mutable bool mShowDiffTexture; + mutable LLPointer<LLViewerTexture> mOrigDiffTexture; +// [/SL:KB] + protected: static BOOL sSafeRenderSelect; diff --git a/indra/newview/llfloateravatarpicker.cpp b/indra/newview/llfloateravatarpicker.cpp index 72892b47a492dd38623550c86fa88acfb6200598..71e5de3d97ab588a8b28acc6f04c5ba6cfe772c1 100644 --- a/indra/newview/llfloateravatarpicker.cpp +++ b/indra/newview/llfloateravatarpicker.cpp @@ -37,6 +37,10 @@ #include "llviewercontrol.h" #include "llviewerregion.h" // getCapability() #include "llworld.h" +// [RLVa:KB] - Checked: 2010-06-04 (RLVa-1.2.2a) +#include "rlvactions.h" +#include "rlvhandler.h" +// [/RLVa:KB] // Linden libraries #include "llavatarnamecache.h" // IDEVO @@ -279,6 +283,23 @@ void LLFloaterAvatarPicker::onRangeAdjust() void LLFloaterAvatarPicker::onList() { getChildView("ok_btn")->setEnabled(isSelectBtnEnabled()); + +// [RLVa:KB] - Checked: 2010-06-05 (RLVa-1.2.2a) | Modified: RLVa-1.2.0d + if (rlv_handler_t::isEnabled()) + { + LLTabContainer* pTabs = getChild<LLTabContainer>("ResidentChooserTabs"); + LLPanel* pNearMePanel = getChild<LLPanel>("NearMePanel"); + RLV_ASSERT( (pTabs) && (pNearMePanel) ); + if ( (pTabs) && (pNearMePanel) ) + { + // TODO-RLVa: check this for RlvActions::canShowName() + bool fRlvEnable = !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES); + pTabs->enableTabButton(pTabs->getIndexForPanel(pNearMePanel), fRlvEnable); + if ( (!fRlvEnable) && (pTabs->getCurrentPanel() == pNearMePanel) ) + pTabs->selectTabByName("SearchPanel"); + } + } +// [/RLVa:KB] } void LLFloaterAvatarPicker::populateNearMe() @@ -589,7 +610,10 @@ BOOL LLFloaterAvatarPicker::handleDragAndDrop(S32 x, S32 y, MASK mask, std::string avatar_name = selection->getColumn(0)->getValue().asString(); if (dest_agent_id.notNull() && dest_agent_id != gAgentID) { - if (drop) +// if (drop) +// [RLVa:KB] - Checked: 2011-04-11 (RLVa-1.3.0) + if ( (drop) && (RlvActions::canStartIM(dest_agent_id)) ) +// [/RLVa:KB] { // Start up IM before give the item session_id = gIMMgr->addSession(avatar_name, IM_NOTHING_SPECIAL, dest_agent_id); diff --git a/indra/newview/llfloaterbuy.cpp b/indra/newview/llfloaterbuy.cpp index 5a9cdbba44d6bfe3aee80e43f079528bf4e32147..fa1667de73d376c28ab9f968f674f232718f6660 100644 --- a/indra/newview/llfloaterbuy.cpp +++ b/indra/newview/llfloaterbuy.cpp @@ -104,7 +104,10 @@ void LLFloaterBuy::show(const LLSaleInfo& sale_info) // Clean up the lists... floater->reset(); floater->mSaleInfo = sale_info; - floater->mObjectSelection = LLSelectMgr::getInstance()->getEditSelection(); +// [RLVa:KB] - Checked: RLVa-2.0.0 + floater->mObjectSelection = LLSelectMgr::getInstance()->getSelection(); +// [/RLVa:KB] +// floater->mObjectSelection = LLSelectMgr::getInstance()->getEditSelection(); LLSelectNode* node = selection->getFirstRootNode(); if (!node) diff --git a/indra/newview/llfloaterbuycontents.cpp b/indra/newview/llfloaterbuycontents.cpp index b32ac860aaa57299fec019a6e4fde0061e77026c..9d0682d251f6db2f443de00c2cd00bd78f7bb375 100644 --- a/indra/newview/llfloaterbuycontents.cpp +++ b/indra/newview/llfloaterbuycontents.cpp @@ -104,7 +104,10 @@ void LLFloaterBuyContents::show(const LLSaleInfo& sale_info) if (list) list->deleteAllItems(); - floater->mObjectSelection = LLSelectMgr::getInstance()->getEditSelection(); +// [RLVa:KB] - Checked: RLVa-2.0.0 + floater->mObjectSelection = LLSelectMgr::getInstance()->getSelection(); +// [/RLVa:KB] +// floater->mObjectSelection = LLSelectMgr::getInstance()->getEditSelection(); LLUUID owner_id; std::string owner_name; diff --git a/indra/newview/llfloaterimnearbychat.cpp b/indra/newview/llfloaterimnearbychat.cpp index 7a989806a1ff2ff1ead578d21ddd1b3e6e55afc3..5f9ecbd30c156927d6b43fa0e5101b71b42698bf 100644 --- a/indra/newview/llfloaterimnearbychat.cpp +++ b/indra/newview/llfloaterimnearbychat.cpp @@ -67,6 +67,10 @@ #include "llviewerchat.h" #include "lltranslate.h" #include "llautoreplace.h" +// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0b) +#include "rlvhandler.h" +#include "rlvactions.h" +// [/RLVa:KB] S32 LLFloaterIMNearbyChat::sLastSpecialChatChannel = 0; @@ -75,7 +79,10 @@ const S32 COLLAPSED_HEIGHT = 60; const S32 EXPANDED_MIN_HEIGHT = 150; // legacy callback glue -void send_chat_from_viewer(const std::string& utf8_out_text, EChatType type, S32 channel); +//void send_chat_from_viewer(const std::string& utf8_out_text, EChatType type, S32 channel); +// [RLVa:KB] - Checked: 2010-02-27 (RLVa-0.2.2) +void send_chat_from_viewer(std::string utf8_out_text, EChatType type, S32 channel); +// [/RLVa:KB] struct LLChatTypeTrigger { std::string name; @@ -835,8 +842,57 @@ LLWString LLFloaterIMNearbyChat::stripChannelNumber(const LLWString &mesg, S32* } } -void send_chat_from_viewer(const std::string& utf8_out_text, EChatType type, S32 channel) +//void send_chat_from_viewer(const std::string& utf8_out_text, EChatType type, S32 channel) +// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0b) | Modified: RLVa-0.2.2a +void send_chat_from_viewer(std::string utf8_out_text, EChatType type, S32 channel) +// [/RLVa:KB] { +// [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) ) ) + { + if (0 == channel) + { + // (We already did this before, but LLChatHandler::handle() calls this directly) + if ( ((CHAT_TYPE_SHOUT == type) || (CHAT_TYPE_NORMAL == type)) && (gRlvHandler.hasBehaviour(RLV_BHVR_CHATNORMAL)) ) + type = CHAT_TYPE_WHISPER; + else if ( (CHAT_TYPE_SHOUT == type) && (gRlvHandler.hasBehaviour(RLV_BHVR_CHATSHOUT)) ) + type = CHAT_TYPE_NORMAL; + else if ( (CHAT_TYPE_WHISPER == type) && (gRlvHandler.hasBehaviour(RLV_BHVR_CHATWHISPER)) ) + type = CHAT_TYPE_NORMAL; + + // Redirect chat if needed + if ( ( (gRlvHandler.hasBehaviour(RLV_BHVR_REDIRCHAT) || (gRlvHandler.hasBehaviour(RLV_BHVR_REDIREMOTE)) ) && + (gRlvHandler.redirectChatOrEmote(utf8_out_text)) ) ) + { + return; + } + + // Filter public chat if sendchat restricted + if (gRlvHandler.hasBehaviour(RLV_BHVR_SENDCHAT)) + gRlvHandler.filterChat(utf8_out_text, true); + } + else + { + // Don't allow chat on a non-public channel if sendchannel restricted (unless the channel is an exception) + if (!RlvActions::canSendChannel(channel)) + return; + + // 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 = RlvUtil::isEmote(utf8_out_text); + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SENDCHAT)) || + ((!fIsEmote) && (gRlvHandler.hasBehaviour(RLV_BHVR_REDIRCHAT))) || + ((fIsEmote) && (gRlvHandler.hasBehaviour(RLV_BHVR_REDIREMOTE))) ) + { + return; + } + } + } + } +// [/RLVa:KB] + LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_ChatFromViewer); msg->nextBlockFast(_PREHASH_AgentData); diff --git a/indra/newview/llfloaterimnearbychathandler.cpp b/indra/newview/llfloaterimnearbychathandler.cpp index 9fd731ed5630e823b5df16b85086e93f09ce8670..750f410bcabac607e09bc61929889ddba9847b57 100644 --- a/indra/newview/llfloaterimnearbychathandler.cpp +++ b/indra/newview/llfloaterimnearbychathandler.cpp @@ -45,7 +45,13 @@ #include "llrootview.h" #include "lllayoutstack.h" +// [RLVa:KB] - Checked: RLVa-2.0.0 +#include "rlvactions.h" +#include "rlvcommon.h" +// [/RLVa:KB] + //add LLFloaterIMNearbyChatHandler to LLNotificationsUI namespace + using namespace LLNotificationsUI; static LLFloaterIMNearbyChatToastPanel* createToastPanel() @@ -485,6 +491,24 @@ void LLFloaterIMNearbyChatHandler::processChat(const LLChat& chat_msg, if(chat_msg.mText.empty()) return;//don't process empty messages +// [RLVa:KB] - Checked: 2010-04-20 (RLVa-1.2.0f) | Modified: RLVa-1.2.0f + if (RlvActions::isRlvEnabled()) + { + // NOTE-RLVa: we can only filter the *message* here since most everything else will already be part of "args" as well + LLChat& tmp_chat = const_cast<LLChat&>(chat_msg); + if ( (!RlvActions::canShowLocation()) && (!tmp_chat.mRlvLocFiltered) && (CHAT_SOURCE_AGENT != tmp_chat.mSourceType) ) + { + RlvUtil::filterLocation(tmp_chat.mText); + tmp_chat.mRlvLocFiltered = TRUE; + } + if ( (!RlvActions::canShowName(RlvActions::SNC_DEFAULT)) && (!tmp_chat.mRlvNamesFiltered) && (CHAT_SOURCE_AGENT != tmp_chat.mSourceType) ) + { + RlvUtil::filterNames(tmp_chat.mText); + tmp_chat.mRlvNamesFiltered = TRUE; + } + } +// [/RLVa:KB] + LLFloaterReg::getInstance("im_container"); LLFloaterIMNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLFloaterIMNearbyChat>("nearby_chat"); @@ -498,7 +522,11 @@ void LLFloaterIMNearbyChatHandler::processChat(const LLChat& chat_msg, chat["chat_type"] = (S32)chat_msg.mChatType; chat["chat_style"] = (S32)chat_msg.mChatStyle; // Pass sender info so that it can be rendered properly (STORM-1021). - chat["sender_slurl"] = LLViewerChat::getSenderSLURL(chat_msg, args); +// chat["sender_slurl"] = LLViewerChat::getSenderSLURL(chat_msg, args); +// [RLVa:KB] - Checked: 2011-12-13 (RLVa-1.4.6) | Added: RLVa-1.4.6 + if ((CHAT_SOURCE_AGENT != chat_msg.mSourceType) || (!chat_msg.mRlvNamesFiltered)) + chat["sender_slurl"] = LLViewerChat::getSenderSLURL(chat_msg, args); +// [/RLVa:KB] if (chat_msg.mChatType == CHAT_TYPE_DIRECT && chat_msg.mText.length() > 0 && @@ -547,8 +575,11 @@ void LLFloaterIMNearbyChatHandler::processChat(const LLChat& chat_msg, LLFirstUse::otherAvatarChatFirst(); // Add sender to the recent people list. - LLRecentPeople::instance().add(chat_msg.mFromID); - +// [RLVa:KB] - Checked: RLVa-2.0.0 + if ( (!RlvActions::isRlvEnabled()) || (RlvActions::canShowName(RlvActions::SNC_DEFAULT, chat_msg.mFromID)) ) + LLRecentPeople::instance().add(chat_msg.mFromID); +// [/RLVa:KB] +// LLRecentPeople::instance().add(chat_msg.mFromID); } // Send event on to LLEventStream @@ -640,6 +671,10 @@ void LLFloaterIMNearbyChatHandler::processChat(const LLChat& chat_msg, LLUUID id; id.generate(); chat["id"] = id; +// [RLVa:KB] - Checked: RLVa-1.2.0 + if (RlvActions::isRlvEnabled()) + chat["show_icon_tooltip"] = !chat_msg.mRlvNamesFiltered; +// [/RLVa:KB] std::string r_color_name = "White"; F32 r_color_alpha = 1.0f; LLViewerChat::getChatColor( chat_msg, r_color_name, r_color_alpha); diff --git a/indra/newview/llfloaterimsession.cpp b/indra/newview/llfloaterimsession.cpp index 6623ce0f807ee910d2a150f0c8e4f31565d00d12..bbcde5cc756566491b57c8f22a025105087060e0 100644 --- a/indra/newview/llfloaterimsession.cpp +++ b/indra/newview/llfloaterimsession.cpp @@ -62,6 +62,10 @@ #include "llnotificationmanager.h" #include "llautoreplace.h" #include "llcorehttputil.h" +// [RLVa:KB] - Checked: 2013-05-10 (RLVa-1.4.9) +#include "rlvactions.h" +#include "rlvcommon.h" +// [/RLVa:KB] const F32 ME_TYPING_TIMEOUT = 4.0f; const F32 OTHER_TYPING_TIMEOUT = 9.0f; @@ -268,7 +272,60 @@ void LLFloaterIMSession::sendMsgFromInputEditor() void LLFloaterIMSession::sendMsg(const std::string& msg) { - const std::string utf8_text = utf8str_truncate(msg, MAX_MSG_BUF_SIZE - 1); +// const std::string utf8_text = utf8str_truncate(msg, MAX_MSG_BUF_SIZE - 1); +// [RLVa:KB] - Checked: 2010-11-30 (RLVa-1.3.0) + std::string utf8_text = utf8str_truncate(msg, MAX_MSG_BUF_SIZE - 1); + + if ( (RlvActions::hasBehaviour(RLV_BHVR_SENDIM)) || (RlvActions::hasBehaviour(RLV_BHVR_SENDIMTO)) ) + { + const LLIMModel::LLIMSession* pIMSession = LLIMModel::instance().findIMSession(mSessionID); + RLV_ASSERT(pIMSession); + + bool fRlvFilter = !pIMSession; + if (pIMSession) + { + switch (pIMSession->mSessionType) + { + case LLIMModel::LLIMSession::P2P_SESSION: // One-on-one IM + fRlvFilter = !RlvActions::canSendIM(mOtherParticipantUUID); + break; + case LLIMModel::LLIMSession::GROUP_SESSION: // Group chat + fRlvFilter = !RlvActions::canSendIM(mSessionID); + break; + case LLIMModel::LLIMSession::ADHOC_SESSION: // Conference chat: allow if all participants can be sent an IM + { + if (!pIMSession->mSpeakers) + { + fRlvFilter = true; + break; + } + + LLSpeakerMgr::speaker_list_t speakers; + pIMSession->mSpeakers->getSpeakerList(&speakers, TRUE); + for (LLSpeakerMgr::speaker_list_t::const_iterator itSpeaker = speakers.begin(); + itSpeaker != speakers.end(); ++itSpeaker) + { + const LLSpeaker* pSpeaker = *itSpeaker; + if ( (gAgent.getID() != pSpeaker->mID) && (!RlvActions::canSendIM(pSpeaker->mID)) ) + { + fRlvFilter = true; + break; + } + } + } + break; + default: + fRlvFilter = true; + break; + } + } + + if (fRlvFilter) + { + utf8_text = RlvStrings::getString(RLV_STRING_BLOCKED_SENDIM); + } + } +// [/RLVa:KB] if (mSessionInitialized) { diff --git a/indra/newview/llfloaterinspect.cpp b/indra/newview/llfloaterinspect.cpp index 10088d20c2353e12f5c97361fac7f4cab68b032f..57a05b42fcfaada163a224376627b2c7d65393d2 100644 --- a/indra/newview/llfloaterinspect.cpp +++ b/indra/newview/llfloaterinspect.cpp @@ -42,6 +42,11 @@ #include "llviewercontrol.h" #include "llviewerobject.h" #include "lluictrlfactory.h" +// [RLVa:KB] - Checked: RLVa-2.0.1 +#include "rlvactions.h" +#include "rlvcommon.h" +#include "rlvui.h" +// [/RLVa:KB] //LLFloaterInspect* LLFloaterInspect::sInstance = NULL; @@ -101,11 +106,13 @@ void LLFloaterInspect::onOpen(const LLSD& key) mObjectSelection = LLSelectMgr::getInstance()->getSelection(); refresh(); } -void LLFloaterInspect::onClickCreatorProfile() + +// [RLVa:KB] - Checked: RLVa-2.0.1 +const LLSelectNode* LLFloaterInspect::getSelectedNode() /*const*/ { if(mObjectList->getAllSelected().size() == 0) { - return; + return NULL; } LLScrollListItem* first_selected =mObjectList->getFirstSelected(); @@ -120,32 +127,29 @@ void LLFloaterInspect::onClickCreatorProfile() return (obj_id == node->getObject()->getID()); } } func(first_selected->getUUID()); - LLSelectNode* node = mObjectSelection->getFirstNode(&func); - if(node) - { - LLAvatarActions::showProfile(node->mPermissions->getCreator()); - } + return mObjectSelection->getFirstNode(&func); } + return NULL; } -void LLFloaterInspect::onClickOwnerProfile() +void LLFloaterInspect::onClickCreatorProfile() { - if(mObjectList->getAllSelected().size() == 0) return; - LLScrollListItem* first_selected =mObjectList->getFirstSelected(); - - if (first_selected) - { - LLUUID selected_id = first_selected->getUUID(); - struct f : public LLSelectedNodeFunctor + const LLSelectNode* node = getSelectedNode(); + if(node) { - LLUUID obj_id; - f(const LLUUID& id) : obj_id(id) {} - virtual bool apply(LLSelectNode* node) + // Only anonymize the creator if they're also the owner or if they're a nearby avie + const LLUUID& idCreator = node->mPermissions->getCreator(); + if ( (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, idCreator)) && ((node->mPermissions->getOwner() == idCreator) || (RlvUtil::isNearbyAgent(idCreator))) ) { - return (obj_id == node->getObject()->getID()); + return; } - } func(selected_id); - LLSelectNode* node = mObjectSelection->getFirstNode(&func); + LLAvatarActions::showProfile(idCreator); + } +} + +void LLFloaterInspect::onClickOwnerProfile() +{ + const LLSelectNode* node = getSelectedNode(); if(node) { if(node->mPermissions->isGroupOwned()) @@ -156,21 +160,108 @@ void LLFloaterInspect::onClickOwnerProfile() else { const LLUUID& owner_id = node->mPermissions->getOwner(); + if (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, owner_id)) + return; LLAvatarActions::showProfile(owner_id); } } - } } void LLFloaterInspect::onSelectObject() { if(LLFloaterInspect::getSelectedUUID() != LLUUID::null) { - getChildView("button owner")->setEnabled(true); - getChildView("button creator")->setEnabled(true); + if (!RlvActions::isRlvEnabled()) + { + getChildView("button owner")->setEnabled(true); + getChildView("button creator")->setEnabled(true); + } + else + { + const LLSelectNode* node = getSelectedNode(); + const LLUUID& idOwner = (node) ? node->mPermissions->getOwner() : LLUUID::null; + const LLUUID& idCreator = (node) ? node->mPermissions->getCreator() : LLUUID::null; + + // See LLFloaterInspect::onClickCreatorProfile() + getChildView("button owner")->setEnabled( (RlvActions::canShowName(RlvActions::SNC_DEFAULT, idOwner)) || ((node) && (node->mPermissions->isGroupOwned())) ); + // See LLFloaterInspect::onClickOwnerProfile() + getChildView("button creator")->setEnabled( ((idOwner != idCreator) && (!RlvUtil::isNearbyAgent(idCreator))) || (RlvActions::canShowName(RlvActions::SNC_DEFAULT, idCreator)) ); + } } } +// [/RLVa:KB] + +//void LLFloaterInspect::onClickCreatorProfile() +//{ +// if(mObjectList->getAllSelected().size() == 0) +// { +// return; +// } +// LLScrollListItem* first_selected =mObjectList->getFirstSelected(); +// +// if (first_selected) +// { +// struct f : public LLSelectedNodeFunctor +// { +// LLUUID obj_id; +// f(const LLUUID& id) : obj_id(id) {} +// virtual bool apply(LLSelectNode* node) +// { +// return (obj_id == node->getObject()->getID()); +// } +// } func(first_selected->getUUID()); +// LLSelectNode* node = mObjectSelection->getFirstNode(&func); +// if(node) +// { +// LLAvatarActions::showProfile(node->mPermissions->getCreator()); +// } +// } +//} + +//void LLFloaterInspect::onClickOwnerProfile() +//{ +// if(mObjectList->getAllSelected().size() == 0) return; +// LLScrollListItem* first_selected =mObjectList->getFirstSelected(); +// +// if (first_selected) +// { +// LLUUID selected_id = first_selected->getUUID(); +// struct f : public LLSelectedNodeFunctor +// { +// LLUUID obj_id; +// f(const LLUUID& id) : obj_id(id) {} +// virtual bool apply(LLSelectNode* node) +// { +// return (obj_id == node->getObject()->getID()); +// } +// } func(selected_id); +// LLSelectNode* node = mObjectSelection->getFirstNode(&func); +// if(node) +// { +// if(node->mPermissions->isGroupOwned()) +// { +// const LLUUID& idGroup = node->mPermissions->getGroup(); +// LLGroupActions::show(idGroup); +// } +// else +// { +// const LLUUID& owner_id = node->mPermissions->getOwner(); +// LLAvatarActions::showProfile(owner_id); +// } +// +// } +// } +//} + +//void LLFloaterInspect::onSelectObject() +//{ +// if(LLFloaterInspect::getSelectedUUID() != LLUUID::null) +// { +// getChildView("button owner")->setEnabled(true); +// getChildView("button creator")->setEnabled(true); +// } +//} LLUUID LLFloaterInspect::getSelectedUUID() { @@ -254,7 +345,11 @@ void LLFloaterInspect::refresh() // actual name and set a placeholder. if (LLAvatarNameCache::get(idOwner, &av_name)) { - owner_name = av_name.getCompleteName(); +// [RLVa:KB] - Checked: RLVa-2.0.1 + bool fRlvCanShowName = (RlvActions::canShowName(RlvActions::SNC_DEFAULT, idOwner)) || (obj->mPermissions->isGroupOwned()); + owner_name = (fRlvCanShowName) ? av_name.getCompleteName() : RlvStrings::getAnonym(av_name); +// [/RLVa:KB] +// owner_name = av_name.getCompleteName(); } else { @@ -269,7 +364,12 @@ void LLFloaterInspect::refresh() if (LLAvatarNameCache::get(idCreator, &av_name)) { - creator_name = av_name.getCompleteName(); +// [RLVa:KB] - Checked: RLVa-2.0.1 + const LLUUID& idCreator = obj->mPermissions->getCreator(); + bool fRlvCanShowName = (RlvActions::canShowName(RlvActions::SNC_DEFAULT, idCreator)) || ( (obj->mPermissions->getOwner() != idCreator) && (!RlvUtil::isNearbyAgent(idCreator)) ); + creator_name = (fRlvCanShowName) ? av_name.getCompleteName() : RlvStrings::getAnonym(av_name); +// [/RLVa:KB] +// creator_name = av_name.getCompleteName(); } else { diff --git a/indra/newview/llfloaterinspect.h b/indra/newview/llfloaterinspect.h index 44381eac96f27cf64919fcae7469ba5e9ebb2dd8..7f7f7377f05d02aa8b33429fae4e0f24e7674df8 100644 --- a/indra/newview/llfloaterinspect.h +++ b/indra/newview/llfloaterinspect.h @@ -36,6 +36,9 @@ class LLObjectSelection; class LLScrollListCtrl; class LLUICtrl; +// [RLVa:KB] - Checked: RLVa-2.0.1 +class LLSelectNode; +// [/RLVa:KB] class LLFloaterInspect : public LLFloater { @@ -61,6 +64,10 @@ class LLFloaterInspect : public LLFloater void setDirty() { mDirty = TRUE; } bool mDirty; +// [RLVa:KB] - Checked: RLVa-2.0.1 + const LLSelectNode* getSelectedNode() /*const*/; +// [/RLVa:KB] + private: void onGetOwnerNameCallback(); void onGetCreatorNameCallback(); diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 36bdcf4d897e89472aad099de8f94e58749df189..760bcefecd4550b7d3501513d8a5629831fdc5c9 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -108,6 +108,10 @@ #include "llteleporthistorystorage.h" #include "llproxy.h" #include "llweb.h" +// [RLVa:KB] - Checked: 2010-03-18 (RLVa-1.2.0a) +#include "rlvactions.h" +#include "rlvhandler.h" +// [/RLVa:KB] #include "lllogininstance.h" // to check if logged in yet #include "llsdserialize.h" @@ -1239,6 +1243,13 @@ void LLFloaterPreferenceGraphicsAdvanced::refreshEnabledState() LLComboBox* ctrl_reflections = getChild<LLComboBox>("Reflections"); LLTextBox* reflections_text = getChild<LLTextBox>("ReflectionsText"); +// [RLVa:KB] - Checked: 2013-05-11 (RLVa-1.4.9) + if (rlv_handler_t::isEnabled()) + { + getChild<LLUICtrl>("do_not_disturb_response")->setEnabled(!RlvActions::hasBehaviour(RLV_BHVR_SENDIM)); + } +// [/RLVa:KB] + // Reflections BOOL reflections = gSavedSettings.getBOOL("VertexShaderEnable") && gGLManager.mHasCubeMap @@ -1282,8 +1293,14 @@ void LLFloaterPreferenceGraphicsAdvanced::refreshEnabledState() LLSliderCtrl* terrain_detail = getChild<LLSliderCtrl>("TerrainDetail"); // can be linked with control var LLTextBox* terrain_text = getChild<LLTextBox>("TerrainDetailText"); - ctrl_shader_enable->setEnabled(LLFeatureManager::getInstance()->isFeatureAvailable("VertexShaderEnable")); - +// ctrl_shader_enable->setEnabled(LLFeatureManager::getInstance()->isFeatureAvailable("VertexShaderEnable")); +// [RLVa:KB] - Checked: 2010-03-18 (RLVa-1.2.0a) | Modified: RLVa-0.2.0a + // "Basic Shaders" can't be disabled - but can be enabled - under @setenv=n + bool fCtrlShaderEnable = LLFeatureManager::getInstance()->isFeatureAvailable("VertexShaderEnable"); + ctrl_shader_enable->setEnabled( + fCtrlShaderEnable && ((!gRlvHandler.hasBehaviour(RLV_BHVR_SETENV)) || (!gSavedSettings.getBOOL("VertexShaderEnable"))) ); +// [/RLVa:KB] + BOOL shaders = ctrl_shader_enable->get(); if (shaders) { @@ -1304,7 +1321,13 @@ void LLFloaterPreferenceGraphicsAdvanced::refreshEnabledState() // *HACK just checks to see if we can use shaders... // maybe some cards that use shaders, but don't support windlight - ctrl_wind_light->setEnabled(ctrl_shader_enable->getEnabled() && shaders); +// ctrl_wind_light->setEnabled(ctrl_shader_enable->getEnabled() && shaders); +// [RLVa:KB] - Checked: 2010-03-18 (RLVa-1.2.0a) | Modified: RLVa-0.2.0a + // "Atmospheric Shaders" can't be disabled - but can be enabled - under @setenv=n + bool fCtrlWindLightEnable = fCtrlShaderEnable && shaders; + ctrl_wind_light->setEnabled( + fCtrlWindLightEnable && ((!gRlvHandler.hasBehaviour(RLV_BHVR_SETENV)) || (!gSavedSettings.getBOOL("WindLightUseAtmosShaders"))) ); +// [/RLVa:KB] sky->setEnabled(ctrl_wind_light->get() && shaders); sky_text->setEnabled(ctrl_wind_light->get() && shaders); diff --git a/indra/newview/llfloaterproperties.cpp b/indra/newview/llfloaterproperties.cpp index 6bfc7807224dcda602d4b6ef060c24832964954f..6a6f14acde80cb60226dbe3f5eb402eb5892fd07 100644 --- a/indra/newview/llfloaterproperties.cpp +++ b/indra/newview/llfloaterproperties.cpp @@ -59,6 +59,10 @@ #include "lluictrlfactory.h" +// [RLVa:KB] - Checked: RLVa-2.0.1 +#include "rlvactions.h" +#include "rlvcommon.h" +// [/RLVa:KB] //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLPropertiesObserver @@ -279,6 +283,15 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item) getChildView("BtnCreator")->setEnabled(TRUE); getChildView("LabelCreatorTitle")->setEnabled(TRUE); getChildView("LabelCreatorName")->setEnabled(TRUE); +// [RLVa:KB] - Checked: RLVa-2.0.1 + // If the object creator matches the object owner we need to anonymize the creator field as well + if ( (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, item->getCreatorUUID())) && + ( ((perm.isOwned()) && (!perm.isGroupOwned()) && (perm.getOwner() == item->getCreatorUUID()) ) || (RlvUtil::isNearbyAgent(item->getCreatorUUID())) ) ) + { + childSetEnabled("BtnCreator", FALSE); + name = RlvStrings::getAnonym(name); + } +// [/RLVa:KB] getChild<LLUICtrl>("LabelCreatorName")->setValue(name); } else @@ -294,6 +307,9 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item) //////////////// if(perm.isOwned()) { +// [RLVa:KB] - Checked: RVLa-2.0.1 + bool fRlvCanShowOwner = true; +// [/RLVa:KB] std::string name; if (perm.isGroupOwned()) { @@ -302,8 +318,19 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item) else { gCacheName->getFullName(perm.getOwner(), name); +// [RLVa:KB] - Checked: RLVa-2.0.1 + if (RlvActions::isRlvEnabled()) + { + fRlvCanShowOwner = RlvActions::canShowName(RlvActions::SNC_DEFAULT, perm.getOwner()); + if (!fRlvCanShowOwner) + name = RlvStrings::getAnonym(name); + } +// [/RLVa:KB] } - getChildView("BtnOwner")->setEnabled(TRUE); +// getChildView("BtnOwner")->setEnabled(TRUE); +// [RLVa:KB] - Checked: RLVa-2.0.1 + getChildView("BtnOwner")->setEnabled(fRlvCanShowOwner); +// [/RLVa:KB] getChildView("LabelOwnerTitle")->setEnabled(TRUE); getChildView("LabelOwnerName")->setEnabled(TRUE); getChild<LLUICtrl>("LabelOwnerName")->setValue(name); @@ -540,6 +567,17 @@ void LLFloaterProperties::onClickCreator() if(!item) return; if(!item->getCreatorUUID().isNull()) { +// [RLVa:KB] - Checked: RLVa-1.2.1 + const LLUUID& idCreator = item->getCreatorUUID(); + if ( (RlvActions::isRlvEnabled()) && (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, idCreator)) ) + { + const LLPermissions& perm = item->getPermissions(); + if ( ((perm.isOwned()) && (!perm.isGroupOwned()) && (perm.getOwner() == idCreator) ) || (RlvUtil::isNearbyAgent(idCreator)) ) + { + return; + } + } +// [/RLVa:KB] LLAvatarActions::showProfile(item->getCreatorUUID()); } } @@ -555,6 +593,10 @@ void LLFloaterProperties::onClickOwner() } else { +// [RLVa:KB] - Checked: RLVa-1.0.0 + if ( (RlvActions::isRlvEnabled()) && (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, item->getPermissions().getOwner())) ) + return; +// [/RLVa:KB] LLAvatarActions::showProfile(item->getPermissions().getOwner()); } } diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp index ed6f4ede9f4a6e86ab9abd4090b056f0e36858ac..4c1d4ca98b5f6beedd501259bedbdc52a9b5639a 100644 --- a/indra/newview/llfloaterreporter.cpp +++ b/indra/newview/llfloaterreporter.cpp @@ -318,6 +318,14 @@ void LLFloaterReporter::getObjectInfo(const LLUUID& object_id) if (regionp) { getChild<LLUICtrl>("sim_field")->setValue(regionp->getName()); +// [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0a) +/* + if ( (rlv_handler_t::isEnabled()) && (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) ) + { + childSetText("sim_field", RlvStrings::getString(RLV_STRING_HIDDEN_REGION)); + } +*/ +// [/RLVa:KB] LLVector3d global_pos; global_pos.setVec(objectp->getPositionRegion()); setPosBox(global_pos); diff --git a/indra/newview/llfloatersettingsdebug.cpp b/indra/newview/llfloatersettingsdebug.cpp index fb202b4c406189156a8a0a86de2316aec649156e..d26574b3cc6e5a64cf8828169660330c6dccdc27 100644 --- a/indra/newview/llfloatersettingsdebug.cpp +++ b/indra/newview/llfloatersettingsdebug.cpp @@ -209,6 +209,20 @@ void LLFloaterSettingsDebug::updateControl(LLControlVariable* controlp) if (controlp) { +// [RLVa:KB] - Checked: 2011-05-28 (RLVa-1.4.0a) | Modified: RLVa-1.4.0a + // If "HideFromEditor" was toggled while the floater is open then we need to manually disable access to the control + // NOTE: this runs per-frame so there's no need to explictly handle onCommitSettings() or onClickDefault() + bool fEnable = !controlp->isHiddenFromSettingsEditor(); + spinner1->setEnabled(fEnable); + spinner2->setEnabled(fEnable); + spinner3->setEnabled(fEnable); + spinner4->setEnabled(fEnable); + color_swatch->setEnabled(fEnable); + childSetEnabled("val_text", fEnable); + childSetEnabled("boolean_combo", fEnable); + childSetEnabled("default_btn", fEnable); +// [/RLVa:KB] + eControlType type = controlp->type(); //hide combo box only for non booleans, otherwise this will result in the combo box closing every frame diff --git a/indra/newview/llfloatersidepanelcontainer.cpp b/indra/newview/llfloatersidepanelcontainer.cpp index c7218ad9d59532a3440533b8440ec95b96dc03e5..43f8665eb5c512b94ae5c4ffede2ff83bcf7034b 100644 --- a/indra/newview/llfloatersidepanelcontainer.cpp +++ b/indra/newview/llfloatersidepanelcontainer.cpp @@ -39,6 +39,10 @@ //static const std::string LLFloaterSidePanelContainer::sMainPanelName("main_panel"); +// [RLVa:KB] - Checked: 2012-02-07 (RLVa-1.4.5) | Added: RLVa-1.4.5 +LLFloaterSidePanelContainer::validate_signal_t LLFloaterSidePanelContainer::mValidateSignal; +// [/RLVa:KB] + LLFloaterSidePanelContainer::LLFloaterSidePanelContainer(const LLSD& key, const Params& params) : LLFloater(key, params) { @@ -108,10 +112,25 @@ LLPanel* LLFloaterSidePanelContainer::openChildPanel(const std::string& panel_na return panel; } +// [RLVa:KB] - Checked: 2012-02-07 (RLVa-1.4.5) | Added: RLVa-1.4.5 +bool LLFloaterSidePanelContainer::canShowPanel(const std::string& floater_name, const LLSD& key) +{ + return mValidateSignal(floater_name, sMainPanelName, key); +} + +bool LLFloaterSidePanelContainer::canShowPanel(const std::string& floater_name, const std::string& panel_name, const LLSD& key) +{ + return mValidateSignal(floater_name, panel_name, key); +} +// [/RLVa:KB] + void LLFloaterSidePanelContainer::showPanel(const std::string& floater_name, const LLSD& key) { LLFloaterSidePanelContainer* floaterp = LLFloaterReg::getTypedInstance<LLFloaterSidePanelContainer>(floater_name); - if (floaterp) +// if (floaterp) +// [RLVa:KB] - Checked: 2013-04-16 (RLVa-1.4.8) + if ( (floaterp) && ((floaterp->getVisible()) || (LLFloaterReg::canShowInstance(floater_name, key))) && (canShowPanel(floater_name, key)) ) +// [/RLVa:KB] { floaterp->openChildPanel(sMainPanelName, key); } @@ -120,7 +139,10 @@ void LLFloaterSidePanelContainer::showPanel(const std::string& floater_name, con void LLFloaterSidePanelContainer::showPanel(const std::string& floater_name, const std::string& panel_name, const LLSD& key) { LLFloaterSidePanelContainer* floaterp = LLFloaterReg::getTypedInstance<LLFloaterSidePanelContainer>(floater_name); - if (floaterp) +// if (floaterp) +// [RLVa:KB] - Checked: 2013-04-16 (RLVa-1.4.8) + if ( (floaterp) && ((floaterp->getVisible()) || (LLFloaterReg::canShowInstance(floater_name, key))) && (canShowPanel(floater_name, panel_name, key)) ) +// [/RLVa:KB] { floaterp->openChildPanel(panel_name, key); } diff --git a/indra/newview/llfloatersidepanelcontainer.h b/indra/newview/llfloatersidepanelcontainer.h index d7ecd52e5746d2f432f116002b5b274b9f7da02f..f125bb94611a3f3b8c52f4690991ef727ec666cd 100644 --- a/indra/newview/llfloatersidepanelcontainer.h +++ b/indra/newview/llfloatersidepanelcontainer.h @@ -55,6 +55,11 @@ class LLFloaterSidePanelContainer : public LLFloater LLPanel* openChildPanel(const std::string& panel_name, const LLSD& params); +// [RLVa:KB] - Checked: 2012-02-07 (RLVa-1.4.5) | Added: RLVa-1.4.5 + static bool canShowPanel(const std::string& floater_name, const LLSD& key); + static bool canShowPanel(const std::string& floater_name, const std::string& panel_name, const LLSD& key); +// [/RLVa:KB] + static void showPanel(const std::string& floater_name, const LLSD& key); static void showPanel(const std::string& floater_name, const std::string& panel_name, const LLSD& key); @@ -78,6 +83,15 @@ class LLFloaterSidePanelContainer : public LLFloater } return panel; } + +// [RLVa:KB] - Checked: 2012-02-07 (RLVa-1.4.5) | Added: RLVa-1.4.5 + // Used to determine whether a sidepanel can be shown +public: + typedef boost::signals2::signal<bool(const std::string&, const std::string&, const LLSD&), boost_boolean_combiner> validate_signal_t; + static boost::signals2::connection setValidateCallback(const validate_signal_t::slot_type& cb) { return mValidateSignal.connect(cb); } +private: + static validate_signal_t mValidateSignal; +// [/RLVa:KB] }; #endif // LL_LLFLOATERSIDEPANELCONTAINER_H diff --git a/indra/newview/llfloaterworldmap.cpp b/indra/newview/llfloaterworldmap.cpp index c67feb8158ba72f95199cd4d157278911a6dd5fd..6144998ab3182b49b77052d7d6c225281065f8e8 100644 --- a/indra/newview/llfloaterworldmap.cpp +++ b/indra/newview/llfloaterworldmap.cpp @@ -76,6 +76,10 @@ #include "llwindow.h" // copyTextToClipboard() #include <algorithm> +// [RLVa:KB] - Checked: 2010-08-22 (RLVa-1.2.1a) +#include "rlvhandler.h" +// [/RLVa:KB] + //--------------------------------------------------------------------------- // Constants //--------------------------------------------------------------------------- @@ -493,6 +497,10 @@ void LLFloaterWorldMap::draw() // getChildView("Clear")->setEnabled((BOOL)tracking_status); getChildView("Show Destination")->setEnabled((BOOL)tracking_status || LLWorldMap::getInstance()->isTracking()); getChildView("copy_slurl")->setEnabled((mSLURL.isValid()) ); +// [RLVa:KB] - Checked: 2010-08-22 (RLVa-1.2.1a) | Added: RLVa-1.2.1a + childSetEnabled("Go Home", + (!rlv_handler_t::isEnabled()) || !(gRlvHandler.hasBehaviour(RLV_BHVR_TPLM) && gRlvHandler.hasBehaviour(RLV_BHVR_TPLOC))); +// [/RLVa:KB] setMouseOpaque(TRUE); getDragHandle()->setMouseOpaque(TRUE); @@ -667,7 +675,10 @@ void LLFloaterWorldMap::trackLocation(const LLVector3d& pos_global) std::string tooltip(""); mTrackedStatus = LLTracker::TRACKING_LOCATION; LLWorldMap::getInstance()->cancelTracking(); // The floater is taking over the tracking - LLTracker::trackLocation(pos_global, full_name, tooltip); +// [RLVa:KB] - Checked: 2012-02-08 (RLVa-1.4.5) | Added: RLVa-1.4.5 + LLTracker::trackLocation(pos_global, (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) ? full_name : RlvStrings::getString(RLV_STRING_HIDDEN).c_str(), tooltip); +// [/RLVa:KB] +// LLTracker::trackLocation(pos_global, full_name, tooltip); LLVector3d coord_pos = LLTracker::getTrackedPositionGlobal(); updateTeleportCoordsDisplay( coord_pos ); @@ -681,9 +692,25 @@ void LLFloaterWorldMap::trackLocation(const LLVector3d& pos_global) // enable/disable teleport destination coordinates void LLFloaterWorldMap::enableTeleportCoordsDisplay( bool enabled ) { - childSetEnabled("teleport_coordinate_x", enabled ); - childSetEnabled("teleport_coordinate_y", enabled ); - childSetEnabled("teleport_coordinate_z", enabled ); +// [RLVa:KB] - Checked: 2012-02-08 (RLVa-1.4.5) | Added: RLVa-1.4.5 + LLUICtrl* pCtrl = getChild<LLUICtrl>("events_label"); + pCtrl->setVisible(!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)); + + pCtrl = getChild<LLUICtrl>("teleport_coordinate_x"); + pCtrl->setVisible(!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)); + pCtrl->setEnabled(enabled); + + pCtrl = getChild<LLUICtrl>("teleport_coordinate_y"); + pCtrl->setVisible(!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)); + pCtrl->setEnabled(enabled); + + pCtrl = getChild<LLUICtrl>("teleport_coordinate_z"); + pCtrl->setVisible(!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)); + pCtrl->setEnabled(enabled); +// [/RLVa:KB] +// childSetEnabled("teleport_coordinate_x", enabled ); +// childSetEnabled("teleport_coordinate_y", enabled ); +// childSetEnabled("teleport_coordinate_z", enabled ); } // update display of teleport destination coordinates - pos is in global coordinates @@ -722,7 +749,22 @@ void LLFloaterWorldMap::updateLocation() // Make sure we know where we are before setting the current user position std::string agent_sim_name; gotSimName = LLWorldMap::getInstance()->simNameFromPosGlobal( agentPos, agent_sim_name ); - if ( gotSimName ) +// [RLVa:KB] - Checked: 2012-02-08 (RLVa-1.4.5) | Added: RLVa-1.4.5 + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) + { + mSetToUserPosition = FALSE; + + // Fill out the location field + getChild<LLUICtrl>("location")->setValue(RlvStrings::getString(RLV_STRING_HIDDEN_REGION)); + + // update the coordinate display with location of avatar in region + updateTeleportCoordsDisplay( agentPos ); + + mSLURL = LLSLURL(); + } + else if (gotSimName) +// [/RLVa:KB] +// if ( gotSimName ) { mSetToUserPosition = FALSE; @@ -767,7 +809,16 @@ void LLFloaterWorldMap::updateLocation() updateTeleportCoordsDisplay( coord_pos ); // simNameFromPosGlobal can fail, so don't give the user an invalid SLURL - if ( gotSimName ) +// [RLVa:KB] - Checked: 2012-02-08 (RLVa-1.4.5) | Added: RLVa-1.4.5 + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) + { + mSLURL = LLSLURL(); + + childSetValue("location", RlvStrings::getString(RLV_STRING_HIDDEN_REGION)); + } + else if (gotSimName) +// [/RLVa:KB] +// if ( gotSimName ) { mSLURL = LLSLURL(sim_name, pos_global); } diff --git a/indra/newview/llgesturemgr.cpp b/indra/newview/llgesturemgr.cpp index 950a6cfaef5b053b630bd70f9126baf8cfdcde4f..d22c40922add3d0e3c8d3a46a1fe0868e29485c3 100644 --- a/indra/newview/llgesturemgr.cpp +++ b/indra/newview/llgesturemgr.cpp @@ -56,6 +56,10 @@ #include "llappearancemgr.h" #include "llgesturelistener.h" +// [RLVa:KB] - Checked: RLVa-2.0.0 +#include "rlvactions.h" +// [/RLVa:KB] + // Longest time, in seconds, to wait for all animations to stop playing const F32 MAX_WAIT_ANIM_SECS = 30.f; @@ -527,6 +531,11 @@ void LLGestureMgr::playGesture(LLMultiGesture* gesture) { if (!gesture) return; +// [RLVa:KB] - Checked: RLVa-2.0.0 | Handles: @sendgesture + if (!RlvActions::canPlayGestures()) + return; +// [/RLVa:KB] + // Reset gesture to first step gesture->mCurrentStep = 0; diff --git a/indra/newview/llgiveinventory.cpp b/indra/newview/llgiveinventory.cpp index a9bf8a9a508e73ec6b431fdad3ec92089a26de85..eb6df9723d6b0765b513f4cb770ce0711e2669b8 100644 --- a/indra/newview/llgiveinventory.cpp +++ b/indra/newview/llgiveinventory.cpp @@ -46,6 +46,12 @@ #include "llrecentpeople.h" #include "llviewerobjectlist.h" #include "llvoavatarself.h" +// [RLVa:KB] - Checked: RLVa-1.2.2 +#include "llavatarnamecache.h" +#include "rlvactions.h" +#include "rlvcommon.h" +#include "rlvui.h" +// [/RLVa:KB] // MAX ITEMS is based on (sizeof(uuid)+2) * count must be < MTUBYTES // or 18 * count < 1200 => count < 1200/18 => 66. I've cut it down a @@ -317,6 +323,19 @@ void LLGiveInventory::logInventoryOffer(const LLUUID& to_agent, const LLUUID &im { gIMMgr->addSystemMessage(im_session_id, "inventory_item_offered", args); } +// [RLVa:KB] - Checked: RLVa-1.2.0 + else if ( (RlvActions::isRlvEnabled()) && (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, to_agent)) && (RlvUtil::isNearbyAgent(to_agent)) && (!RlvUIEnabler::hasOpenProfile(to_agent)) ) + { + // Log to chat history if the user didn't drop on an IM session or a profile to avoid revealing the name of the recipient + std::string strMsgName = "inventory_item_offered-im"; LLSD args; LLAvatarName avName; + if (LLAvatarNameCache::get(to_agent, &avName)) + { + args["NAME"] = RlvStrings::getAnonym(avName); + strMsgName = "inventory_item_offered_rlv"; + } + gIMMgr->addSystemMessage(LLUUID::null, strMsgName, args); + } +// [/RLVa:KB] // If this item was given by drag-and-drop on avatar while IM panel was open, log this action in the IM panel chat. else if (LLIMModel::getInstance()->findIMSession(session_id)) { @@ -424,7 +443,15 @@ void LLGiveInventory::commitGiveInventoryItem(const LLUUID& to_agent, logInventoryOffer(to_agent, im_session_id); // add buddy to recent people list - LLRecentPeople::instance().add(to_agent); +// LLRecentPeople::instance().add(to_agent); +// [RLVa:KB] - Checked: RLVa-2.0.0 + // Block the recent activity update if this was an in-world drop on an avatar (as opposed to a drop on an IM session or on a profile) + if ( (!RlvActions::isRlvEnabled()) || + (RlvActions::canShowName(RlvActions::SNC_DEFAULT, to_agent)) || (im_session_id.notNull()) || (!RlvUtil::isNearbyAgent(to_agent)) || (RlvUIEnabler::hasOpenProfile(to_agent)) ) + { + LLRecentPeople::instance().add(to_agent); + } +// [/RLVa:KB] } // static @@ -490,7 +517,15 @@ bool LLGiveInventory::commitGiveInventoryCategory(const LLUUID& to_agent, << cat->getUUID() << LL_ENDL; // add buddy to recent people list - LLRecentPeople::instance().add(to_agent); +// LLRecentPeople::instance().add(to_agent); +// [RLVa:KB] - Checked: RLVa-2.0.0 + // Block the recent activity update if this was an in-world drop on an avatar (as opposed to a drop on an IM session or on a profile) + if ( (!RlvActions::isRlvEnabled()) || + (RlvActions::canShowName(RlvActions::SNC_DEFAULT, to_agent)) || (im_session_id.notNull()) || (!RlvUtil::isNearbyAgent(to_agent)) || (RlvUIEnabler::hasOpenProfile(to_agent)) ) + { + LLRecentPeople::instance().add(to_agent); + } +// [/RLVa:KB] // Test out how many items are being given. LLViewerInventoryCategory::cat_array_t cats; diff --git a/indra/newview/llglsandbox.cpp b/indra/newview/llglsandbox.cpp index c80dec0e75daee1d465b996a18fe2cfd8385e297..841edc94488361808247c1904f72db8883cdf114 100644 --- a/indra/newview/llglsandbox.cpp +++ b/indra/newview/llglsandbox.cpp @@ -63,6 +63,11 @@ #include "pipeline.h" #include "llspatialpartition.h" #include "llviewershadermgr.h" +// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) +#include "rlvactions.h" +#include "rlvhandler.h" +#include "rlvhelper.h" +// [/RLVa:KB] // Height of the yellow selection highlight posts for land const F32 PARCEL_POST_HEIGHT = 0.666f; @@ -70,6 +75,18 @@ const F32 PARCEL_POST_HEIGHT = 0.666f; // Returns true if you got at least one object void LLToolSelectRect::handleRectangleSelection(S32 x, S32 y, MASK mask) { +// [RLVa:KB] - Checked: 2010-11-29 (RLVa-1.3.0c) | Modified: RLVa-1.3.0c + // Block rectangle selection if: + // - prevented from editing and no exceptions are set (see below for the case where exceptions are set) + // - prevented from interacting at all + if ( (rlv_handler_t::isEnabled()) && + ( ((gRlvHandler.hasBehaviour(RLV_BHVR_EDIT)) && (!gRlvHandler.hasException(RLV_BHVR_EDIT))) || + (gRlvHandler.hasBehaviour(RLV_BHVR_INTERACT)) ) ) + { + return; + } +// [/RLVa:KB] + LLVector3 av_pos = gAgent.getPositionAgent(); F32 select_dist_squared = gSavedSettings.getF32("MaxSelectDistance"); select_dist_squared = select_dist_squared * select_dist_squared; @@ -134,6 +151,29 @@ void LLToolSelectRect::handleRectangleSelection(S32 x, S32 y, MASK mask) LLViewerCamera::getInstance()->setFar(new_far); LLViewerCamera::getInstance()->setNear(new_near); } +// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Modified: RLVa-1.0.0g + if (gRlvHandler.hasBehaviour(RLV_BHVR_FARTOUCH)) + { + static RlvCachedBehaviourModifier<float> s_nFartouchDist(RLV_MODIFIER_FARTOUCHDIST); + + // We'll allow drag selection under fartouch, but only within the fartouch range + // (just copy/paste the code above us to make that work, thank you Lindens!) + LLVector3 relative_av_pos = av_pos; + relative_av_pos -= LLViewerCamera::getInstance()->getOrigin(); + + F32 new_far = relative_av_pos * LLViewerCamera::getInstance()->getAtAxis() + s_nFartouchDist; + F32 new_near = relative_av_pos * LLViewerCamera::getInstance()->getAtAxis() - s_nFartouchDist; + + new_near = llmax(new_near, 0.1f); + + LLViewerCamera::getInstance()->setFar(new_far); + LLViewerCamera::getInstance()->setNear(new_near); + + // Usurp these two + limit_select_distance = TRUE; + select_dist_squared = s_nFartouchDist * s_nFartouchDist; + } +// [/RLVa:KB] LLViewerCamera::getInstance()->setPerspective(FOR_SELECTION, center_x-width/2, center_y-height/2, width, height, limit_select_distance); @@ -208,6 +248,13 @@ void LLToolSelectRect::handleRectangleSelection(S32 x, S32 y, MASK mask) continue; } +// [RLVa:KB] - Checked: 2010-11-29 (RLVa-1.3.0c) | Added: RLVa-1.3.0c + if ( (RlvActions::isRlvEnabled()) && (!RlvActions::canEdit(vobjp)) ) + { + continue; + } +// [/RLVa:KB] + S32 result = LLViewerCamera::getInstance()->sphereInFrustum(drawable->getPositionAgent(), drawable->getRadius()); if (result) { diff --git a/indra/newview/llgroupactions.cpp b/indra/newview/llgroupactions.cpp index 913efd643426aa50e727377a6d9987095cd206ae..73bb8543ee5955467149ade6936574b1bdd4c746 100644 --- a/indra/newview/llgroupactions.cpp +++ b/indra/newview/llgroupactions.cpp @@ -41,6 +41,12 @@ #include "llnotificationsutil.h" #include "llstatusbar.h" // can_afford_transaction() #include "groupchatlistener.h" +// [RLVa:KB] - Checked: 2011-03-28 (RLVa-1.3.0) +#include "llslurl.h" +#include "rlvactions.h" +#include "rlvcommon.h" +#include "rlvhandler.h" +// [/RLVa:KB] // // Globals @@ -205,6 +211,15 @@ void LLGroupActions::startCall(const LLUUID& group_id) return; } +// [RLVa:KB] - Checked: 2013-05-09 (RLVa-1.4.9) + if (!RlvActions::canStartIM(group_id)) + { + make_ui_sound("UISndInvalidOp"); + RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTIM, LLSD().with("RECIPIENT", LLSLURL("group", group_id, "about").getSLURLString())); + return; + } +// [/RLVa:KB] + LLUUID session_id = gIMMgr->addSession(gdata.mName, IM_SESSION_GROUP_START, group_id, true); if (session_id == LLUUID::null) { @@ -278,7 +293,10 @@ bool LLGroupActions::onJoinGroup(const LLSD& notification, const LLSD& response) // static void LLGroupActions::leave(const LLUUID& group_id) { - if (group_id.isNull()) +// if (group_id.isNull()) +// [RLVa:KB] - Checked: RLVa-1.3.0 + if ( (group_id.isNull()) || ((gAgent.getGroupID() == group_id) && (!RlvActions::canChangeActiveGroup())) ) +// [/RLVa:KB] { return; } @@ -330,6 +348,13 @@ void LLGroupActions::processLeaveGroupDataResponse(const LLUUID group_id) // static void LLGroupActions::activate(const LLUUID& group_id) { +// [RLVa:KB] - Checked: RLVa-1.3.0 + if ( (!RlvActions::canChangeActiveGroup()) && (gRlvHandler.getAgentGroup() != group_id) ) + { + return; + } +// [/RLVa:KB] + LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_ActivateGroup); msg->nextBlockFast(_PREHASH_AgentData); @@ -426,6 +451,15 @@ LLUUID LLGroupActions::startIM(const LLUUID& group_id) { if (group_id.isNull()) return LLUUID::null; +// [RLVa:KB] - Checked: 2013-05-09 (RLVa-1.4.9) + if (!RlvActions::canStartIM(group_id)) + { + make_ui_sound("UISndInvalidOp"); + RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTIM, LLSD().with("RECIPIENT", LLSLURL("group", group_id, "about").getSLURLString())); + return LLUUID::null; + } +// [/RLVa:KB] + LLGroupData group_data; if (gAgent.getGroupData(group_id, group_data)) { diff --git a/indra/newview/llgrouplist.cpp b/indra/newview/llgrouplist.cpp index 6126db2988c98e9e3b7e47310d3e40ffbc7f925d..7343178c10bc34b5c2a66b96f926ae0eb6cd396f 100644 --- a/indra/newview/llgrouplist.cpp +++ b/indra/newview/llgrouplist.cpp @@ -43,6 +43,9 @@ #include "llviewercontrol.h" // for gSavedSettings #include "llviewermenu.h" // for gMenuHolder #include "llvoiceclient.h" +// [RLVa:KB] - Checked: RLVa-2.0.3 +#include "rlvactions.h" +// [/RLVa:KB] static LLDefaultChildRegistry::Register<LLGroupList> r("group_list"); S32 LLGroupListItem::sIconWidth = 0; @@ -281,8 +284,14 @@ bool LLGroupList::onContextMenuItemEnable(const LLSD& userdata) bool real_group_selected = selected_group_id.notNull(); // a "real" (not "none") group is selected // each group including "none" can be activated +// [RLVa:KB] - Checked: RLVa-1.3.0 if (userdata.asString() == "activate") - return gAgent.getGroupID() != selected_group_id; + return (gAgent.getGroupID() != selected_group_id) && (RlvActions::canChangeActiveGroup()); + else if (userdata.asString() == "leave") + return (real_group_selected) && ((gAgent.getGroupID() != selected_group_id) || (RlvActions::canChangeActiveGroup())); +// [/RLVa:KB] +// if (userdata.asString() == "activate") +// return gAgent.getGroupID() != selected_group_id; if (userdata.asString() == "call") return real_group_selected && LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking(); diff --git a/indra/newview/llhudtext.cpp b/indra/newview/llhudtext.cpp index 52e83fe412c78971a2f729c7e3f200f353ad765b..c35a86fc86b64b540f5258f467b71f81466f75d1 100644 --- a/indra/newview/llhudtext.cpp +++ b/indra/newview/llhudtext.cpp @@ -46,6 +46,10 @@ #include "llstatusbar.h" #include "llmenugl.h" #include "pipeline.h" +// [RLVa:KB] - Checked: RLVa-1.4.0 +#include "rlvactions.h" +#include "rlvhandler.h" +// [/RLVa:KB] #include <boost/tokenizer.hpp> const F32 HORIZONTAL_PADDING = 15.f; @@ -241,7 +245,32 @@ void LLHUDText::renderText() void LLHUDText::setString(const std::string &text_utf8) { mTextSegments.clear(); - addLine(text_utf8, mColor); +// addLine(text_utf8, mColor); +// [RLVa:KB] - Checked: RLVa-2.0.3 + // NOTE: setString() is called for debug and map beacons as well + if (RlvActions::isRlvEnabled()) + { + std::string text(text_utf8); + if (gRlvHandler.canShowHoverText(mSourceObject)) + { + if (!RlvActions::canShowLocation()) + RlvUtil::filterLocation(text); + + bool fCanShowNearby = RlvActions::canShowNearbyAgents(); + if ( (!RlvActions::canShowName(RlvActions::SNC_DEFAULT)) || (!fCanShowNearby) ) + RlvUtil::filterNames(text, true, !fCanShowNearby); + } + else + { + text = ""; + } + addLine(text, mColor); + } + else + { + addLine(text_utf8, mColor); + } +// [/RLVa:KB] } void LLHUDText::clearString() @@ -630,3 +659,17 @@ F32 LLHUDText::LLHUDTextSegment::getWidth(const LLFontGL* font) return width; } } + +// [RLVa:KB] - Checked: RLVa-2.0.3 +void LLHUDText::refreshAllObjectText(EObjectTextFilter eObjFilter) +{ + for (LLHUDText* pText : sTextObjects) + { + if ((pText) && (!pText->mObjText.empty()) && (pText->mSourceObject) && (LL_PCODE_VOLUME == pText->mSourceObject->getPCode()) && + ((OTF_NONE == eObjFilter) || ((OTF_HUD_ATTACHMENTS == eObjFilter) && (pText->mSourceObject->isHUDAttachment())))) + { + pText->setString(pText->mObjText); + } + } +} +// [/RLVa:KB] diff --git a/indra/newview/llhudtext.h b/indra/newview/llhudtext.h index 36015d51f0452fd583757928c388991885403efc..0be9eb4f2e98e5df862285deac1e16b7a7de96af 100644 --- a/indra/newview/llhudtext.h +++ b/indra/newview/llhudtext.h @@ -124,6 +124,13 @@ class LLHUDText : public LLHUDObject static void reshape(); static void setDisplayText(BOOL flag) { sDisplayText = flag ; } +// [RLVa:KB] - Checked: RLVa-2.0.3 + const std::string& getObjectText() const { return mObjText; } + void setObjectText(const std::string &utf8string) { mObjText = utf8string; } + + enum EObjectTextFilter { OTF_NONE, OTF_HUD_ATTACHMENTS }; + static void refreshAllObjectText(EObjectTextFilter eObjFilter = OTF_NONE); +// [/RLVa:KB] protected: LLHUDText(const U8 type); @@ -161,6 +168,9 @@ class LLHUDText : public LLHUDObject ETextAlignment mTextAlignment; EVertAlignment mVertAlignment; BOOL mHidden; +// [RLVa:KB] - Checked: RLVa-1.0.0 + std::string mObjText; +// [/RLVa:KB] static BOOL sDisplayText ; static std::set<LLPointer<LLHUDText> > sTextObjects; diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index 951389b8568059c8e5473d3b9ba68561bbba059e..94f8d0e8a0ca13fd705ca641f9a3dfd0c21fe122 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -69,7 +69,10 @@ #include "message.h" #include "llviewerregion.h" #include "llcorehttputil.h" - +// [RLVa:KB] - Checked: 2013-05-10 (RLVa-1.4.9) +#include "rlvactions.h" +#include "rlvcommon.h" +// [/RLVa:KB] const static std::string ADHOC_NAME_SUFFIX(" Conference"); @@ -3612,6 +3615,20 @@ class LLViewerChatterBoxInvitation : public LLHTTPNode { return; } +// [RLVa:KB] - Checked: 2010-11-30 (RLVa-1.3.0) + if ( (RlvActions::hasBehaviour(RLV_BHVR_RECVIM)) || (RlvActions::hasBehaviour(RLV_BHVR_RECVIMFROM)) ) + { + if (gAgent.isInGroup(session_id)) // Group chat: don't accept the invite if not an exception + { + if (!RlvActions::canReceiveIM(session_id)) + return; + } + else if (!RlvActions::canReceiveIM(from_id)) // Conference chat: don't block; censor if not an exception + { + message = RlvStrings::getString(RLV_STRING_BLOCKED_RECVIM); + } + } +// [/RLVa:KB] // standard message, not from system std::string saved; diff --git a/indra/newview/llinspectobject.cpp b/indra/newview/llinspectobject.cpp index 46019557f85f91be6784dd5a4a169eaa15d3264f..30275d44a4f60f819665a2dce1a8db56a3dbacf4 100644 --- a/indra/newview/llinspectobject.cpp +++ b/indra/newview/llinspectobject.cpp @@ -38,6 +38,11 @@ #include "llviewermedia.h" #include "llviewermediafocus.h" #include "llviewerobjectlist.h" // to select the requested object +// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0c) +#include "rlvactions.h" +#include "rlvhandler.h" +#include "lltoolpie.h" +// [/RLVa:KB] // Linden libraries #include "llbutton.h" // setLabel(), not virtual! @@ -358,6 +363,10 @@ void LLInspectObject::updateButtons(LLSelectNode* nodep) || (parent && parent->flagHandleTouch())) { getChild<LLUICtrl>("touch_btn")->setVisible(true); +// [RLVa:KB] - Checked: 2010-11-12 (RLVa-1.2.1g) | Added: RLVa-1.2.1g + if (rlv_handler_t::isEnabled()) + getChild<LLUICtrl>("touch_btn")->setEnabled(gRlvHandler.canTouch(object)); +// [/RLVa:KB] updateTouchLabel(nodep); } else if ( enable_object_open() ) @@ -387,6 +396,15 @@ void LLInspectObject::updateSitLabel(LLSelectNode* nodep) { sit_btn->setLabel( getString("Sit") ); } + +// [RLVa:KB] - Checked: 2010-03-06 (RLVa-1.2.0c) | Added: RLVa-1.2.0a + // RELEASE-RLVa: [SL-2.0.0] Make sure we're examining the same object that handle_sit_or_stand() will request a sit for + if (rlv_handler_t::isEnabled()) + { + const LLPickInfo& pick = LLToolPie::getInstance()->getPick(); + sit_btn->setEnabled( (pick.mObjectID.notNull()) && (RlvActions::canSit(pick.getObject(), pick.mObjectOffset)) ); + } +// [/RLVa:KB] } void LLInspectObject::updateTouchLabel(LLSelectNode* nodep) @@ -482,10 +500,15 @@ void LLInspectObject::updateCreator(LLSelectNode* nodep) // a clickable link // Objects cannot be created by a group, so use agent URL format LLUUID creator_id = nodep->mPermissions->getCreator(); - std::string creator_url = - LLSLURL("agent", creator_id, "about").getSLURLString(); +// std::string creator_url = +// LLSLURL("agent", creator_id, "about").getSLURLString(); +// [RLVa:KB] - Checked: RLVa-1.2.2 + // Only anonymize the creator if they're also the owner or if they're a nearby avie + bool fRlvHideCreator = (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, creator_id)) && ((nodep->mPermissions->getOwner() == creator_id) || (RlvUtil::isNearbyAgent(creator_id))); + const std::string creator_url = LLSLURL("agent", creator_id, (!fRlvHideCreator) ? "about" : "rlvanonym").getSLURLString(); +// [/RLVa:KB] args["[CREATOR]"] = creator_url; - + // created by one user but owned by another std::string owner_url; LLUUID owner_id; @@ -498,7 +521,11 @@ void LLInspectObject::updateCreator(LLSelectNode* nodep) else { owner_id = nodep->mPermissions->getOwner(); - owner_url = LLSLURL("agent", owner_id, "about").getSLURLString(); +// owner_url = LLSLURL("agent", owner_id, "about").getSLURLString(); +// [RLVa:KB] - Checked: RLVa-1.2.2 + bool fRlvHideOwner = (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, owner_id)); + owner_url = LLSLURL("agent", owner_id, (!fRlvHideOwner) ? "about" : "rlvanonym").getSLURLString(); +// [/RLVa:KB] } args["[OWNER]"] = owner_url; diff --git a/indra/newview/llinspectremoteobject.cpp b/indra/newview/llinspectremoteobject.cpp index b64df2bd47176affd6fcfc24bb7de8f2f3c24d1f..079975b8c7ecffccf27ca1890c0b189b4fa97310 100644 --- a/indra/newview/llinspectremoteobject.cpp +++ b/indra/newview/llinspectremoteobject.cpp @@ -35,6 +35,9 @@ #include "llui.h" #include "lluictrl.h" #include "llurlaction.h" +// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.2a) +#include "rlvhandler.h" +// [/RLVa:KB] ////////////////////////////////////////////////////////////////////////////// // LLInspectRemoteObject @@ -66,6 +69,9 @@ class LLInspectRemoteObject : public LLInspect LLUUID mOwnerID; std::string mSLurl; std::string mName; +// [RLVa:KB] - Checked: 2010-11-02 (RLVa-1.2.2a) | Added: RLVa-1.2.2a + bool mRlvHideNames; +// [/RLVa:KB] bool mGroupOwned; }; @@ -75,6 +81,9 @@ LLInspectRemoteObject::LLInspectRemoteObject(const LLSD& sd) : mOwnerID(NULL), mSLurl(""), mName(""), +// [RLVa:KB] - Checked: 2010-11-02 (RLVa-1.2.2a) | Added: RLVa-1.2.2a + mRlvHideNames(false), +// [/RLVa:KB] mGroupOwned(false) { } @@ -107,6 +116,10 @@ void LLInspectRemoteObject::onOpen(const LLSD& data) mOwnerID = data["owner_id"].asUUID(); mGroupOwned = data["group_owned"].asBoolean(); mSLurl = data["slurl"].asString(); +// [RLVa:KB] - Checked: 2010-11-02 (RLVa-1.2.2a) | Modified: RLVa-1.2.2a + if (data.has("rlv_shownames")) + mRlvHideNames = data["rlv_shownames"].asBoolean(); +// [/RLVa:KB] // update the inspector with the current object state update(); @@ -160,7 +173,10 @@ void LLInspectRemoteObject::update() } else { - owner = LLSLURL("agent", mOwnerID, "about").getSLURLString(); +// owner = LLSLURL("agent", mOwnerID, "about").getSLURLString(); +// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.2a) | Modified: RLVa-1.2.2a + owner = LLSLURL("agent", mOwnerID, (!mRlvHideNames) ? "about" : "rlvanonym").getSLURLString(); +// [/RLVa:KB] } } else @@ -182,6 +198,14 @@ void LLInspectRemoteObject::update() // disable the Block button if we don't have the object ID (will this ever happen?) getChild<LLUICtrl>("block_btn")->setEnabled(!mObjectID.isNull() && !LLMuteList::getInstance()->isMuted(mObjectID)); + +// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Added: RLVa-1.2.0f + if ( (rlv_handler_t::isEnabled()) && (RlvStrings::getString(RLV_STRING_HIDDEN_REGION) == mSLurl) ) + { + getChild<LLUICtrl>("object_slurl")->setValue(mSLurl); + getChild<LLUICtrl>("map_btn")->setEnabled(false); + } +// [/RLVa:KB] } ////////////////////////////////////////////////////////////////////////////// diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 0a5ff566055db47b5da75a06b759461df2c3133e..b08c6fd21a4046699641db7016240a7f79ef9a82 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -79,6 +79,11 @@ #include "llwearableitemslist.h" #include "lllandmarkactions.h" #include "llpanellandmarks.h" +// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1) +#include "rlvactions.h" +#include "rlvhandler.h" +#include "rlvlocks.h" +// [/RLVa:KB] #include <boost/shared_ptr.hpp> @@ -842,6 +847,20 @@ void LLInvFVBridge::buildContextMenu(LLMenuGL& menu, U32 flags) addOpenRightClickMenuOption(items); items.push_back(std::string("Properties")); +// [RLVa:KB] - Checked: 2010-03-01 (RLVa-1.2.0b) | Modified: RLVa-1.1.0a + if (rlv_handler_t::isEnabled()) + { + const LLInventoryObject* pItem = getInventoryObject(); + if ( (pItem) && + ( ((LLAssetType::AT_NOTECARD == pItem->getType()) && (gRlvHandler.hasBehaviour(RLV_BHVR_VIEWNOTE))) || + ((LLAssetType::AT_LSL_TEXT == pItem->getType()) && (gRlvHandler.hasBehaviour(RLV_BHVR_VIEWSCRIPT))) || + ((LLAssetType::AT_TEXTURE == pItem->getType()) && (gRlvHandler.hasBehaviour(RLV_BHVR_VIEWTEXTURE))) ) ) + { + disabled_items.push_back(std::string("Open")); + } + } +// [/RLVa:KB] + getClipboardEntries(true, items, disabled_items, flags); } hide_context_entries(menu, items, disabled_items); @@ -1892,6 +1911,13 @@ BOOL LLItemBridge::isItemRenameable() const return FALSE; } +// [RLVa:KB] - Checked: 2011-03-29 (RLVa-1.3.0g) | Modified: RLVa-1.3.0g + if ( (rlv_handler_t::isEnabled()) && (!RlvFolderLocks::instance().canRenameItem(mUUID)) ) + { + return FALSE; + } +// [/RLVa:KB] + return (item->getPermissions().allowModifyBy(gAgent.getID())); } return FALSE; @@ -2528,6 +2554,14 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, } } } + +// [RLVa:KB] - Checked: 2011-03-29 (RLVa-1.3.0g) | Added: RLVa-1.3.0g + if ( (is_movable) && (rlv_handler_t::isEnabled()) && (RlvFolderLocks::instance().hasLockedFolder(RLV_LOCK_ANY)) ) + { + is_movable = RlvFolderLocks::instance().canMoveFolder(cat_id, mUUID); + } +// [/RLVa:KB] + // //-------------------------------------------------------------------------------- @@ -3962,6 +3996,13 @@ void LLFolderBridge::buildContextMenuFolderOptions(U32 flags, menuentry_vec_t& { disabled_items.push_back(std::string("Replace Outfit")); } +// [RLVa:KB] - Checked: RLVa-2.0.3 + // Block "Replace Current Outfit" if the user can't wear the new folder + if ( (RlvActions::isRlvEnabled()) && (RlvFolderLocks::instance().isLockedFolder(mUUID, RLV_LOCK_ADD)) ) + { + disabled_items.push_back(std::string("Replace Outfit")); + } +// [/RLVa:KB] if (!LLAppearanceMgr::instance().getCanAddToCOF(mUUID)) { disabled_items.push_back(std::string("Add To Outfit")); @@ -4547,6 +4588,24 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, { is_movable = FALSE; } + +// [RLVa:KB] - Checked: 2011-03-29 (RLVa-1.3.0g) | Modified: RLVa-1.3.0g + if ( (rlv_handler_t::isEnabled()) && (is_movable) ) + { + if (move_is_into_current_outfit) + { + // RELEASE-RLVa: [RLVa-1.3.0] Keep sync'ed with code below => LLAppearanceMgr::wearItemOnAvatar() with "replace == true" + const LLViewerInventoryItem* pItem = dynamic_cast<const LLViewerInventoryItem*>(inv_item); + is_movable = rlvPredCanWearItem(pItem, RLV_WEAR_REPLACE); + } + if (is_movable) + { + is_movable = (!RlvFolderLocks::instance().hasLockedFolder(RLV_LOCK_ANY)) || + (RlvFolderLocks::instance().canMoveItem(inv_item->getUUID(), mUUID)); + } + } +// [/RLVa:KB] + if (move_is_into_trash) { is_movable &= inv_item->getIsLinkType() || !get_is_item_worn(inv_item->getUUID()); @@ -5360,6 +5419,16 @@ void LLCallingCardBridge::performAction(LLInventoryModel* model, std::string act { callingcard_name = av_name.getCompleteName(); } + +// [RLVa:KB] - Checked: 2013-05-08 (RLVa-1.4.9) + if (!RlvActions::canStartIM(item->getCreatorUUID())) + { + make_ui_sound("UISndInvalidOp"); + RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTIM, LLSD().with("RECIPIENT", LLSLURL("agent", item->getCreatorUUID(), "completename").getSLURLString())); + return; + } +// [/RLVa:KB] + LLUUID session_id = gIMMgr->addSession(callingcard_name, IM_NOTHING_SPECIAL, item->getCreatorUUID()); if (session_id != LLUUID::null) { @@ -5969,6 +6038,21 @@ std::string LLObjectBridge::getLabelSuffix() const void rez_attachment(LLViewerInventoryItem* item, LLViewerJointAttachment* attachment, bool replace) { +// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1) + // If no attachment point was specified, try looking it up from the item name + static LLCachedControl<bool> fRlvDeprecateAttachPt(gSavedSettings, "RLVaDebugDeprecateExplicitPoint", false); + if ( (rlv_handler_t::isEnabled()) && (!fRlvDeprecateAttachPt) && + (!attachment) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) ) + { + attachment = RlvAttachPtLookup::getAttachPoint(item); + } + + if ( (RlvActions::isRlvEnabled()) && (!rlvPredCanWearItem(item, (replace) ? RLV_WEAR_REPLACE : RLV_WEAR_ADD)) ) + { + return; + } +// [/RLVa:KB] + const LLUUID& item_id = item->getLinkedUUID(); // Check for duplicate request. @@ -6001,10 +6085,24 @@ void rez_attachment(LLViewerInventoryItem* item, LLViewerJointAttachment* attach if (replace && (attachment && attachment->getNumObjects() > 0)) { +// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1) + // 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] LLNotificationsUtil::add("ReplaceAttachment", LLSD(), payload, confirm_attachment_rez); } else { +// [RLVa:KB] - Checked: 2010-08-07 (RLVa-1.2.0) + // 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*/); } } @@ -6078,6 +6176,10 @@ void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { items.push_back(std::string("Wearable And Object Separator")); items.push_back(std::string("Detach From Yourself")); +// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a + if ( (rlv_handler_t::isEnabled()) && (!gRlvAttachmentLocks.canDetach(item)) ) + disabled_items.push_back(std::string("Detach From Yourself")); +// [/RLVa:KB] } else if (!isItemInTrash() && !isLinkedObjectInTrash() && !isLinkedObjectMissing() && !isCOFFolder()) { @@ -6096,6 +6198,17 @@ void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags) 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 + else if (rlv_handler_t::isEnabled()) + { + ERlvWearMask eWearMask = gRlvAttachmentLocks.canAttach(item); + if ((eWearMask & RLV_WEAR_REPLACE) == 0) + disabled_items.push_back(std::string("Wearable And Object Wear")); + if ((eWearMask & RLV_WEAR_ADD) == 0) + disabled_items.push_back(std::string("Wearable Add")); + } +// [/RLVa:KB] + LLMenuGL* attach_menu = menu.findChildMenuByName("Attach To", TRUE); LLMenuGL* attach_hud_menu = menu.findChildMenuByName("Attach To HUD", TRUE); if (attach_menu @@ -6340,18 +6453,36 @@ void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { disabled_items.push_back(std::string("Wearable And Object Wear")); disabled_items.push_back(std::string("Wearable Add")); +// [RLVa:KB] - Checked: 2010-04-04 (RLVa-1.2.0c) | Added: RLVa-1.2.0c + if ( (rlv_handler_t::isEnabled()) && (!gRlvWearableLocks.canRemove(item)) ) + disabled_items.push_back(std::string("Take Off")); +// [/RLVa:KB] } else { items.push_back(std::string("Wearable And Object Wear")); disabled_items.push_back(std::string("Take Off")); disabled_items.push_back(std::string("Wearable Edit")); + +// [RLVa:KB] - Checked: 2010-06-09 (RLVa-1.2.0g) | Modified: RLVa-1.2.0g + if (rlv_handler_t::isEnabled()) + { + ERlvWearMask eWearMask = gRlvWearableLocks.canWear(item); + if ((eWearMask & RLV_WEAR_REPLACE) == 0) + disabled_items.push_back(std::string("Wearable And Object Wear")); + if ((eWearMask & RLV_WEAR_ADD) == 0) + disabled_items.push_back(std::string("Wearable Add")); + } +// [/RLVa:KB] } if (LLWearableType::getAllowMultiwear(mWearableType)) { items.push_back(std::string("Wearable Add")); - if (!gAgentWearables.canAddWearable(mWearableType)) +// if (!gAgentWearables.canAddWearable(mWearableType)) +// [SL:KB] - Patch: Appearance-WearableDuplicateAssets | Checked: 2011-07-24 (Catznip-2.6.0e) | Added: Catznip-2.6.0e + if ( (!gAgentWearables.canAddWearable(mWearableType)) || (gAgentWearables.getWearableFromAssetID(item->getAssetUUID())) ) +// [/SL:KB] { disabled_items.push_back(std::string("Wearable Add")); } diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index 851d92f23ec2acbfbe3c35975f079909023be770..d11a7ea98741e1b459a2b015bfa55edb5ffef8f5 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -86,6 +86,10 @@ #include "llviewerwindow.h" #include "llvoavatarself.h" #include "llwearablelist.h" +// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a) +#include "rlvhandler.h" +#include "rlvlocks.h" +// [/RLVa:KB] #include <boost/foreach.hpp> @@ -628,6 +632,14 @@ BOOL get_is_item_removable(const LLInventoryModel* model, const LLUUID& id) } } +// [RLVa:KB] - Checked: 2011-03-29 (RLVa-1.3.0g) | Modified: RLVa-1.3.0g + if ( (rlv_handler_t::isEnabled()) && + (RlvFolderLocks::instance().hasLockedFolder(RLV_LOCK_ANY)) && (!RlvFolderLocks::instance().canRemoveItem(id)) ) + { + return FALSE; + } +// [/RLVa:KB] + const LLInventoryObject *obj = model->getItem(id); if (obj && obj->getIsLinkType()) { @@ -656,6 +668,14 @@ BOOL get_is_category_removable(const LLInventoryModel* model, const LLUUID& id) return FALSE; } +// [RLVa:KB] - Checked: 2011-03-29 (RLVa-1.3.0g) | Modified: RLVa-1.3.0g + if ( ((rlv_handler_t::isEnabled()) && + (RlvFolderLocks::instance().hasLockedFolder(RLV_LOCK_ANY)) && (!RlvFolderLocks::instance().canRemoveFolder(id))) ) + { + return FALSE; + } +// [/RLVa:KB] + if (!isAgentAvatarValid()) return FALSE; const LLInventoryCategory* category = model->getCategory(id); @@ -691,6 +711,13 @@ BOOL get_is_category_renameable(const LLInventoryModel* model, const LLUUID& id) return FALSE; } +// [RLVa:KB] - Checked: 2011-03-29 (RLVa-1.3.0g) | Modified: RLVa-1.3.0g + if ( (rlv_handler_t::isEnabled()) && (model == &gInventory) && (!RlvFolderLocks::instance().canRenameFolder(id)) ) + { + return FALSE; + } +// [/RLVa:KB] + LLViewerInventoryCategory* cat = model->getCategory(id); if (cat && !LLFolderType::lookupIsProtectedType(cat->getPreferredType()) && diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 9a33e210ff3352128e92a2a7af79aee05f82244b..b7121caaadb14871d940d7d0ea0bedb4bda55ce1 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -58,6 +58,10 @@ #include "bufferarray.h" #include "bufferstream.h" #include "llcorehttputil.h" +// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a) +#include "rlvhandler.h" +#include "rlvlocks.h" +// [/RLVa:KB] //#define DIFF_INVENTORY_FILES #ifdef DIFF_INVENTORY_FILES @@ -715,11 +719,19 @@ void LLInventoryModel::collectDescendents(const LLUUID& id, collectDescendentsIf(id, cats, items, include_trash, always); } +//void LLInventoryModel::collectDescendentsIf(const LLUUID& id, +// cat_array_t& cats, +// item_array_t& items, +// BOOL include_trash, +// LLInventoryCollectFunctor& add) +// [RLVa:KB] - Checked: 2013-04-15 (RLVa-1.4.8) 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) +// [/RLVa:KB] { // Start with categories if(!include_trash) @@ -739,7 +751,10 @@ void LLInventoryModel::collectDescendentsIf(const LLUUID& id, { cats.push_back(cat); } - collectDescendentsIf(cat->getUUID(), cats, items, include_trash, add); +// [RLVa:KB] - Checked: 2013-04-15 (RLVa-1.4.8) + collectDescendentsIf(cat->getUUID(), cats, items, include_trash, add, follow_folder_links); +// [/RLVa:KB] +// collectDescendentsIf(cat->getUUID(), cats, items, include_trash, add); } } @@ -759,6 +774,44 @@ 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'] + // 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->size(); + for(S32 i = 0; i < count; ++i) + { + item = item_array->at(i); + if (item && item->getActualType() == LLAssetType::AT_LINK_FOLDER) + { + LLViewerInventoryCategory *linked_cat = item->getLinkedCategory(); + if (linked_cat && linked_cat->getPreferredType() != LLFolderType::FT_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.push_back(LLPointer<LLViewerInventoryCategory>(linked_cat)); + } + collectDescendentsIf(linked_cat->getUUID(), cats, items, include_trash, add, false); + } + } + } + } +// [/RLVa:KB] } U32 LLInventoryModel::getDescendentsCountRecursive(const LLUUID& id, U32 max_item_limit) @@ -3024,6 +3077,14 @@ void LLInventoryModel::processSaveAssetIntoInventory(LLMessageSystem* msg, LL_INFOS() << "LLInventoryModel::processSaveAssetIntoInventory item" " not found: " << item_id << LL_ENDL; } + +// [RLVa:KB] - Checked: 2010-03-05 (RLVa-1.2.0a) | Added: RLVa-0.2.0e + if (rlv_handler_t::isEnabled()) + { + RlvAttachmentLockWatchdog::instance().onSavedAssetIntoInventory(item_id); + } +// [/RLVa:KB] + if(gViewerWindow) { gViewerWindow->getWindow()->decBusyCount(); @@ -3085,6 +3146,20 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**) { 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 diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index 826d1f880d76db5c845450e46f3808d49637df6c..9c7a68ca4d9d7d6d2ff7a20e03ba5aed96db1227 100644 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -249,11 +249,19 @@ class LLInventoryModel cat_array_t& categories, item_array_t& items, BOOL include_trash); +// [RLVa:KB] - Checked: 2013-04-15 (RLVa-1.4.8) void collectDescendentsIf(const LLUUID& id, cat_array_t& categories, item_array_t& items, BOOL include_trash, - LLInventoryCollectFunctor& add); + LLInventoryCollectFunctor& add, + bool follow_folder_links = false); +// [/RLVa:KB] +// void collectDescendentsIf(const LLUUID& id, +// cat_array_t& categories, +// item_array_t& items, +// BOOL include_trash, +// LLInventoryCollectFunctor& add); // Collect all items in inventory that are linked to item_id. // Assumes item_id is itself not a linked item. diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index f5dcbf838daf7dcbebecbe5b51e5f4b1460b31a7..100052d04bb2786121f56e421c602aecb4ffe9f7 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -50,6 +50,10 @@ #include "llviewerattachmenu.h" #include "llviewerfoldertype.h" #include "llvoavatarself.h" +// [RLVa:KB] - Checked: 2013-05-08 (RLVa-1.4.9) +#include "rlvactions.h" +#include "rlvcommon.h" +// [/RLVa:KB] static LLDefaultChildRegistry::Register<LLInventoryPanel> r("inventory_panel"); @@ -1105,7 +1109,11 @@ bool LLInventoryPanel::beginIMSession() std::string name; std::vector<LLUUID> members; - EInstantMessage type = IM_SESSION_CONFERENCE_START; +// EInstantMessage type = IM_SESSION_CONFERENCE_START; + +// [RLVa:KB] - Checked: 2013-05-08 (RLVa-1.4.9) + bool fRlvCanStartIM = true; +// [/RLVa:KB] std::set<LLFolderViewItem*>::const_iterator iter; for (iter = selected_items.begin(); iter != selected_items.end(); iter++) @@ -1144,10 +1152,17 @@ bool LLInventoryPanel::beginIMSession() for(S32 i = 0; i < count; ++i) { id = item_array.at(i)->getCreatorUUID(); - if(at.isBuddyOnline(id)) +// [RLVa:KB] - Checked: 2013-05-08 (RLVa-1.4.9) + if ( (at.isBuddyOnline(id)) && (members.end() == std::find(members.begin(), members.end(), id)) ) { + fRlvCanStartIM &= RlvActions::canStartIM(id); members.push_back(id); } +// [/RLVa:KB] +// if(at.isBuddyOnline(id)) +// { +// members.push_back(id); +// } } } } @@ -1164,10 +1179,17 @@ bool LLInventoryPanel::beginIMSession() LLAvatarTracker& at = LLAvatarTracker::instance(); LLUUID id = inv_item->getCreatorUUID(); - if(at.isBuddyOnline(id)) +// [RLVa:KB] - Checked: 2013-05-08 (RLVa-1.4.9) + if ( (at.isBuddyOnline(id)) && (members.end() == std::find(members.begin(), members.end(), id)) ) { + fRlvCanStartIM &= RlvActions::canStartIM(id); members.push_back(id); } +// [/RLVa:KB] +// if(at.isBuddyOnline(id)) +// { +// members.push_back(id); +// } } } //if IT_CALLINGCARD } //if !IT_CATEGORY @@ -1177,16 +1199,34 @@ bool LLInventoryPanel::beginIMSession() // the session_id is randomly generated UUID which will be replaced later // with a server side generated number +// [RLVa:KB] - Checked: 2013-05-08 (RLVa-1.4.9) + if (!fRlvCanStartIM) + { + make_ui_sound("UISndInvalidOp"); + RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTCONF); + return true; + } +// [/RLVa:KB] + if (name.empty()) { name = LLTrans::getString("conference-title"); } - LLUUID session_id = gIMMgr->addSession(name, type, members[0], members); - if (session_id != LLUUID::null) +// [RLVa:KB] - Checked: 2011-04-11 (RLVa-1.3.0h) | Added: RLVa-1.3.0h + if (!members.empty()) { - LLFloaterIMContainer::getInstance()->showConversation(session_id); + if (members.size() > 1) + LLAvatarActions::startConference(members); + else + LLAvatarActions::startIM(members[0]); } +// [/RLVa:KB] +// LLUUID session_id = gIMMgr->addSession(name, type, members[0], members); +// if (session_id != LLUUID::null) +// { +// LLFloaterIMContainer::getInstance()->showConversation(session_id); +// } return true; } @@ -1274,8 +1314,11 @@ LLInventoryPanel* LLInventoryPanel::getActiveInventoryPanel(BOOL auto_open) active_inv_floaterp->setMinimized(FALSE); } } - else if (auto_open) +// else if (auto_open) +// [RLVa:KB] - Checked: 2012-05-15 (RLVa-1.4.6) + else if ( (auto_open) && (LLFloaterReg::canShowInstance(floater_inventory->getInstanceName())) ) { +// [/RLVa:KB] floater_inventory->openFloater(); res = inventory_panel->getActivePanel(); diff --git a/indra/newview/lllocationinputctrl.cpp b/indra/newview/lllocationinputctrl.cpp index 53b2ca2b74a12b4ea241778edb37897409b8d3a5..cdaa6c007dfce2aec20d8e74ea59f25a2c5a5b68 100644 --- a/indra/newview/lllocationinputctrl.cpp +++ b/indra/newview/lllocationinputctrl.cpp @@ -63,6 +63,9 @@ #include "llviewermenu.h" #include "llurllineeditorctrl.h" #include "llagentui.h" +// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d) +#include "rlvhandler.h" +// [/RLVa:KB] #include "llmenuoptionpathfindingrebakenavmesh.h" #include "llpathfindingmanager.h" @@ -633,16 +636,31 @@ void LLLocationInputCtrl::reshape(S32 width, S32 height, BOOL called_from_parent void LLLocationInputCtrl::onInfoButtonClicked() { +// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.4.5) | Added: RLVa-1.2.0 + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) + return; +// [/RLVa:KB] + LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "agent")); } void LLLocationInputCtrl::onForSaleButtonClicked() { +// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.4.5) | Added: RLVa-1.2.0 + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) + return; +// [/RLVa:KB] + handle_buy_land(); } void LLLocationInputCtrl::onAddLandmarkButtonClicked() { +// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.4.5) | Added: RLVa-1.2.0 + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) + return; +// [/RLVa:KB] + LLViewerInventoryItem* landmark = LLLandmarkActions::findLandmarkForAgentPos(); // Landmark exists, open it for preview and edit if(landmark && landmark->getUUID().notNull()) @@ -770,6 +788,10 @@ void LLLocationInputCtrl::onTextEditorRightClicked(S32 x, S32 y, MASK mask) void LLLocationInputCtrl::refresh() { +// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.4.5) | Added: RLVa-1.2.0 + mInfoBtn->setEnabled(!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)); +// [/RLVa:KB] + refreshLocation(); // update location string refreshParcelIcons(); updateAddLandmarkButton(); // indicate whether current parcel has been landmarked @@ -1047,6 +1069,9 @@ void LLLocationInputCtrl::enableAddLandmarkButton(bool val) // depending on whether current parcel has been landmarked. void LLLocationInputCtrl::updateAddLandmarkButton() { +// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.4.5) | Added: RLVa-1.2.0 + mAddLandmarkBtn->setVisible(!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)); +// [/RLVa:KB] enableAddLandmarkButton(LLLandmarkActions::hasParcelLandmark()); } void LLLocationInputCtrl::updateAddLandmarkTooltip() @@ -1076,6 +1101,9 @@ void LLLocationInputCtrl::updateContextMenu(){ { landmarkItem->setLabel(LLTrans::getString("EditLandmarkNavBarMenu")); } +// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.4.5) | Added: RLVa-1.2.0 + landmarkItem->setEnabled(!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)); +// [/RLVa:KB] } } void LLLocationInputCtrl::updateWidgetlayout() @@ -1131,17 +1159,23 @@ void LLLocationInputCtrl::onLocationContextMenuItemClicked(const LLSD& userdata) } else if (item == "landmark") { - LLViewerInventoryItem* landmark = LLLandmarkActions::findLandmarkForAgentPos(); - - if(!landmark) +// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.4.5) | Added: RLVa-1.2.0 + if (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) { - LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "create_landmark")); - } - else - { - LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "landmark").with("id",landmark->getUUID())); - +// [/RLVa:KB] + LLViewerInventoryItem* landmark = LLLandmarkActions::findLandmarkForAgentPos(); + + if(!landmark) + { + LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "create_landmark")); + } + else + { + LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "landmark").with("id",landmark->getUUID())); + } +// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d } +// [/RLVa:KB] } else if (item == "cut") { diff --git a/indra/newview/lllocationinputctrl.h b/indra/newview/lllocationinputctrl.h index da71bab6c1bddc09030ae4f1588f97da072e98b7..1c4adb9e8fc5810facf74d1bead63311a9e1616c 100644 --- a/indra/newview/lllocationinputctrl.h +++ b/indra/newview/lllocationinputctrl.h @@ -109,6 +109,10 @@ class LLLocationInputCtrl LLLineEditor* getTextEntry() const { return mTextEntry; } void handleLoginComplete(); +// [RLVa:KB] - Checked: 2014-03-23 (RLVa-1.4.10) + void refresh(); +// [/RLVa:KB] + private: enum EParcelIcon @@ -135,7 +139,7 @@ class LLLocationInputCtrl * depending on whether current parcel has been landmarked. */ void enableAddLandmarkButton(bool val); - void refresh(); +// void refresh(); void refreshLocation(); void refreshParcelIcons(); // Refresh the value in the health percentage text field diff --git a/indra/newview/llmaniptranslate.cpp b/indra/newview/llmaniptranslate.cpp index b4259a456cc1e773ee58c2a49b99d99510a64da3..8dfc42c819ac2081f093fb9cf2628a5abda36a73 100644 --- a/indra/newview/llmaniptranslate.cpp +++ b/indra/newview/llmaniptranslate.cpp @@ -62,6 +62,9 @@ #include "pipeline.h" #include "llviewershadermgr.h" #include "lltrans.h" +// [RLVa:KB] - Checked: 2010-03-23 (RLVa-1.2.0a) +#include "rlvhandler.h" +// [/RLVa:KB] const S32 NUM_AXES = 3; const S32 MOUSE_DRAG_SLOP = 2; // pixels diff --git a/indra/newview/llmoveview.cpp b/indra/newview/llmoveview.cpp index 70035bcc74eff63f30436bbd7473a1d4786142b4..ae7d0d4c0b6e2822616141a6b9313235e3579126 100644 --- a/indra/newview/llmoveview.cpp +++ b/indra/newview/llmoveview.cpp @@ -50,6 +50,9 @@ #include "llviewerparcelmgr.h" #include "llviewerregion.h" #include "lltooltip.h" +// [RLVa:KB] - Checked: 2010-03-07 (RLVa-1.2.0c) +#include "rlvactions.h" +// [/RLVa:KB] // // Constants @@ -140,7 +143,10 @@ BOOL LLFloaterMove::postBuild() initMovementMode(); - gAgent.addParcelChangedCallback(LLFloaterMove::sUpdateFlyingStatus); +// gAgent.addParcelChangedCallback(LLFloaterMove::sUpdateFlyingStatus); +// [RLVa:KB] - Checked: 2011-05-27 (RLVa-1.4.0a) | Added: RLVa-1.4.0a + gAgent.addParcelChangedCallback(LLFloaterMove::sUpdateMovementStatus); +// [/RLVa:KB] return TRUE; } @@ -325,23 +331,32 @@ void LLFloaterMove::setMovementMode(const EMovementMode mode) { case MM_RUN: gAgent.setAlwaysRun(); - gAgent.setRunning(); +// gAgent.setRunning(); break; case MM_WALK: gAgent.clearAlwaysRun(); - gAgent.clearRunning(); +// gAgent.clearRunning(); break; default: //do nothing for other modes (MM_FLY) break; } // tell the simulator. - gAgent.sendWalkRun(gAgent.getAlwaysRun()); - - updateButtonsWithMovementMode(mode); +// gAgent.sendWalkRun(gAgent.getAlwaysRun()); +// +// updateButtonsWithMovementMode(mode); +// +// bool bHideModeButtons = MM_FLY == mode +// || (isAgentAvatarValid() && gAgentAvatarp->isSitting()); +// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i + // Running may have been restricted so update walk-vs-run from the agent's actual running state + if ( (MM_WALK == mode) || (MM_RUN == mode) ) + mCurrentMode = (gAgent.getRunning()) ? MM_RUN : MM_WALK; - bool bHideModeButtons = MM_FLY == mode - || (isAgentAvatarValid() && gAgentAvatarp->isSitting()); + updateButtonsWithMovementMode(mCurrentMode); + + bool bHideModeButtons = (MM_FLY == mCurrentMode) || (isAgentAvatarValid() && gAgentAvatarp->isSitting()); +// [/RLVa:KB] showModeButtons(!bHideModeButtons); @@ -444,12 +459,23 @@ void LLFloaterMove::setModeTitle(const EMovementMode mode) } //static -void LLFloaterMove::sUpdateFlyingStatus() +//void LLFloaterMove::sUpdateFlyingStatus() +//{ +// LLFloaterMove *floater = LLFloaterReg::findTypedInstance<LLFloaterMove>("moveview"); +// if (floater) floater->mModeControlButtonMap[MM_FLY]->setEnabled(gAgent.canFly()); +// +//} +// [RLVa:KB] - Checked: 2011-05-27 (RLVa-1.4.0a) | Added: RLVa-1.4.0a +void LLFloaterMove::sUpdateMovementStatus() { - LLFloaterMove *floater = LLFloaterReg::findTypedInstance<LLFloaterMove>("moveview"); - if (floater) floater->mModeControlButtonMap[MM_FLY]->setEnabled(gAgent.canFly()); - + LLFloaterMove* pFloater = LLFloaterReg::findTypedInstance<LLFloaterMove>("moveview"); + if (pFloater) + { + pFloater->mModeControlButtonMap[MM_RUN]->setEnabled(!RlvActions::hasBehaviour(RLV_BHVR_ALWAYSRUN)); + pFloater->mModeControlButtonMap[MM_FLY]->setEnabled(gAgent.canFly()); + } } +// [/RLVa:KB] void LLFloaterMove::showModeButtons(BOOL bShow) { @@ -489,7 +515,10 @@ void LLFloaterMove::onOpen(const LLSD& key) showModeButtons(FALSE); } - sUpdateFlyingStatus(); +// sUpdateFlyingStatus(); +// [RLVa:KB] - Checked: 2011-05-27 (RLVa-1.4.0a) | Added: RLVa-1.4.0a + sUpdateMovementStatus(); +// [/RLVa:KB] } void LLFloaterMove::setModeButtonToggleState(const EMovementMode mode) @@ -680,10 +709,17 @@ LLPanelStandStopFlying* LLPanelStandStopFlying::getStandStopFlyingPanel() void LLPanelStandStopFlying::onStandButtonClick() { - LLFirstUse::sit(false); +// [RLVa:KB] - Checked: 2010-03-07 (RLVa-1.2.0c) | Added: RLVa-1.2.0a + if ( (!RlvActions::isRlvEnabled()) || (RlvActions::canStand()) ) + { + LLFirstUse::sit(false); - LLSelectMgr::getInstance()->deselectAllForStandingUp(); - gAgent.setControlFlags(AGENT_CONTROL_STAND_UP); + LLSelectMgr::getInstance()->deselectAllForStandingUp(); + gAgent.setControlFlags(AGENT_CONTROL_STAND_UP); + } +// [/RLVa:KB] +// LLSelectMgr::getInstance()->deselectAllForStandingUp(); +// gAgent.setControlFlags(AGENT_CONTROL_STAND_UP); setFocus(FALSE); // EXT-482 mStandButton->setVisible(FALSE); // force visibility changing to avoid seeing Stand & Move buttons at once. diff --git a/indra/newview/llmoveview.h b/indra/newview/llmoveview.h index c525d9dfdb6580d1c5bb1ea62c89fe01a3840cb1..6f42db76a9dbab95aa4a399ba5bba462c0817cc7 100644 --- a/indra/newview/llmoveview.h +++ b/indra/newview/llmoveview.h @@ -59,7 +59,10 @@ class LLFloaterMove static void enableInstance(BOOL bEnable); /*virtual*/ void onOpen(const LLSD& key); - static void sUpdateFlyingStatus(); +// static void sUpdateFlyingStatus(); +// [RLVa:KB] - Checked: 2011-05-27 (RLVa-1.4.0a) | Added: RLVa-1.4.0a + static void sUpdateMovementStatus(); +// [/RLVa:KB] protected: void turnLeft(); diff --git a/indra/newview/llnavigationbar.cpp b/indra/newview/llnavigationbar.cpp index 84a2cd8be103559f488b4446a965209e51021764..06faa9a47403ad41e7c03042b38e5e77d31e86d6 100644 --- a/indra/newview/llnavigationbar.cpp +++ b/indra/newview/llnavigationbar.cpp @@ -699,6 +699,15 @@ void LLNavigationBar::resizeLayoutPanel() nav_bar_rect.setLeftTopAndSize(nav_bar_rect.mLeft, nav_bar_rect.mTop, nav_panel_width, nav_bar_rect.getHeight()); mNavigationPanel->handleReshape(nav_bar_rect,true); } + +// [RLVa:KB] - Checked: 2014-03-23 (RLVa-1.4.10) +void LLNavigationBar::refreshLocationCtrl() +{ + if (mCmbLocation) + mCmbLocation->refresh(); +} +// [/RLVa:KB] + void LLNavigationBar::invokeSearch(std::string search_text) { LLFloaterReg::showInstance("search", LLSD().with("category", "all").with("query", LLSD(search_text))); diff --git a/indra/newview/llnavigationbar.h b/indra/newview/llnavigationbar.h index 29dbaedf7af9c2f63b0add0d058db42614a4a169..382fd0c38446f03a7499900d2caae4a562d2c7b4 100644 --- a/indra/newview/llnavigationbar.h +++ b/indra/newview/llnavigationbar.h @@ -102,6 +102,9 @@ class LLNavigationBar int getDefNavBarHeight(); int getDefFavBarHeight(); +// [RLVa:KB] - Checked: 2014-03-23 (RLVa-1.4.10) + void refreshLocationCtrl(); +// [/RLVa:KB] private: // the distance between navigation panel and favorites panel in pixels const static S32 FAVBAR_TOP_PADDING = 10; diff --git a/indra/newview/llnetmap.cpp b/indra/newview/llnetmap.cpp index 5fc73c67d1bfbbf4c17c1f0464bdfbe096274a51..05d5cb8ffe5cb051a5b5599ac2dc1c5edebcbe59 100644 --- a/indra/newview/llnetmap.cpp +++ b/indra/newview/llnetmap.cpp @@ -60,6 +60,10 @@ #include "llviewerwindow.h" #include "llworld.h" #include "llworldmapview.h" // shared draw code +// [RLVa:KB] - Checked: RLVa-2.0.1 +#include "rlvactions.h" +#include "rlvcommon.h" +// [/RLVa:KB] static LLDefaultChildRegistry::Register<LLNetMap> r1("net_map"); @@ -350,7 +354,10 @@ void LLNetMap::draw() pos_map = globalPosToView(positions[i]); - bool show_as_friend = (LLAvatarTracker::instance().getBuddyInfo(uuid) != NULL); +// [RLVa:KB] - Checked: RLVa-1.2.0 + bool show_as_friend = (LLAvatarTracker::instance().getBuddyInfo(uuid) != NULL) && (RlvActions::canShowName(RlvActions::SNC_DEFAULT, uuid)); +// [/RLVa:KB] +// bool show_as_friend = (LLAvatarTracker::instance().getBuddyInfo(uuid) != NULL); LLColor4 color = show_as_friend ? map_avatar_friend_color : map_avatar_color; @@ -602,11 +609,20 @@ BOOL LLNetMap::handleToolTip( S32 x, S32 y, MASK mask ) // If the cursor is near an avatar on the minimap, a mini-inspector will be // shown for the avatar, instead of the normal map tooltip. - if (handleToolTipAgent(mClosestAgentToCursor)) +// if (handleToolTipAgent(mClosestAgentToCursor)) +// [RLVa:KB] - Checked: RLVa-1.2.2 + bool fRlvCanShowName = (mClosestAgentToCursor.notNull()) && (RlvActions::canShowName(RlvActions::SNC_DEFAULT, mClosestAgentToCursor)); + if ( (fRlvCanShowName) && (handleToolTipAgent(mClosestAgentToCursor)) ) +// [/RLVa:KB] { return TRUE; } +// [RLVa:KB] - Checked: RLVa-1.2.2 + LLStringUtil::format_map_t args; LLAvatarName avName; + args["[AGENT]"] = ( (!fRlvCanShowName) && (mClosestAgentToCursor.notNull()) && (LLAvatarNameCache::get(mClosestAgentToCursor, &avName)) ) ? RlvStrings::getAnonym(avName) + "\n" : ""; +// [/RLVa:KB] + LLRect sticky_rect; std::string region_name; LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal( viewPosToGlobal( x, y ) ); @@ -618,14 +634,17 @@ BOOL LLNetMap::handleToolTip( S32 x, S32 y, MASK mask ) sticky_rect.mRight = sticky_rect.mLeft + 2 * SLOP; sticky_rect.mTop = sticky_rect.mBottom + 2 * SLOP; - region_name = region->getName(); +// region_name = region->getName(); +// [RLVa:KB] - Checked: RLVa-1.2.2 + region_name = (RlvActions::canShowLocation()) ? region->getName() : RlvStrings::getString(RLV_STRING_HIDDEN_REGION); +// [/RLVa:KB] if (!region_name.empty()) { region_name += "\n"; } } - LLStringUtil::format_map_t args; +// LLStringUtil::format_map_t args; args["[REGION]"] = region_name; std::string msg = mToolTipMsg; LLStringUtil::format(msg, args); diff --git a/indra/newview/llnotificationalerthandler.cpp b/indra/newview/llnotificationalerthandler.cpp index 58a9b01a45944df8e232110ac02650f7eee0a33d..1058c3836cbf1fa5b589dc550c3ae877fadb65e9 100644 --- a/indra/newview/llnotificationalerthandler.cpp +++ b/indra/newview/llnotificationalerthandler.cpp @@ -38,6 +38,10 @@ #include "lltoastalertpanel.h" +// [RLVa:KB] - Checked: 2013-05-09 (RLVa-1.4.9) +#include "rlvactions.h" +// [/RLVa:KB] + using namespace LLNotificationsUI; //-------------------------------------------------------------------------- @@ -88,8 +92,19 @@ bool LLAlertHandler::processNotification(const LLNotificationPtr& notification) LLUUID from_id = notification->getPayload()["from_id"]; - // firstly create session... - LLHandlerUtil::spawnIMSession(name, from_id); +// [RLVa:KB] - Checked: 2013-05-09 (RLVa-1.4.9) + // Don't spawn an IM session for non-chat related events: + // - LLHandlerUtil::logToIMP2P() below will still be called with to_file_only == false + // - LLHandlerUtil::logToIM() will eventually be called as a result and without an open IM session it will log the + // same message as it would for an open session whereas to_file_only == true would take a different code path + if (RlvActions::canStartIM(from_id)) + { +// [/RLVa:KB] + // firstly create session... + LLHandlerUtil::spawnIMSession(name, from_id); +// [RLVa:KB] - Checked: 2013-05-09 (RLVa-1.4.9) + } +// [/RLVa:KB] // ...then log message to have IM Well notified about new message LLHandlerUtil::logToIMP2P(notification); diff --git a/indra/newview/llnotificationhandler.h b/indra/newview/llnotificationhandler.h index 7a183cb298e9449ba39e0014fafcbe1cb3ecb2b0..2c5c610dbb14309f9782b2b517fb5e813f031a20 100644 --- a/indra/newview/llnotificationhandler.h +++ b/indra/newview/llnotificationhandler.h @@ -332,16 +332,23 @@ class LLHandlerUtil */ static void updateIMFLoaterMesages(const LLUUID& session_id); - /** - * Updates messages of visible IM floater. - */ - static void updateVisibleIMFLoaterMesages(const LLNotificationPtr& notification); +// /** +// * Updates messages of visible IM floater. +// */ +// static void updateVisibleIMFLoaterMesages(const LLNotificationPtr& notification); /** * Decrements counter of IM messages. */ static void decIMMesageCounter(const LLNotificationPtr& notification); +// [SL:KB] - Patch: UI-Notifications | Checked: 2011-04-11 (Catznip-2.5.0a) | Added: Catznip-2.5.0a + /** + * Checks whether the user has opted to embed (certain) notifications in IM sessions + */ + static bool canEmbedNotificationInIM(const LLNotificationPtr& notification); +// [/SL:KB] + }; } diff --git a/indra/newview/llnotificationhandlerutil.cpp b/indra/newview/llnotificationhandlerutil.cpp index a078889d46569a576ecec0e343585c229cc20d52..63d62ecb4cb7162928261746fc7652eac27aeb2a 100644 --- a/indra/newview/llnotificationhandlerutil.cpp +++ b/indra/newview/llnotificationhandlerutil.cpp @@ -265,15 +265,15 @@ void LLHandlerUtil::updateIMFLoaterMesages(const LLUUID& session_id) } } -// static -void LLHandlerUtil::updateVisibleIMFLoaterMesages(const LLNotificationPtr& notification) -{ - const std::string name = LLHandlerUtil::getSubstitutionName(notification); - LLUUID from_id = notification->getPayload()["from_id"]; - LLUUID session_id = spawnIMSession(name, from_id); - - updateIMFLoaterMesages(session_id); -} +//// static +//void LLHandlerUtil::updateVisibleIMFLoaterMesages(const LLNotificationPtr& notification) +//{ +// const std::string name = LLHandlerUtil::getSubstitutionName(notification); +// LLUUID from_id = notification->getPayload()["from_id"]; +// LLUUID session_id = spawnIMSession(name, from_id); +// +// updateIMFLoaterMesages(session_id); +//} // static void LLHandlerUtil::decIMMesageCounter(const LLNotificationPtr& notification) diff --git a/indra/newview/llnotificationofferhandler.cpp b/indra/newview/llnotificationofferhandler.cpp index 2657b84ef30379962260d45674ee1bd7d33604d2..379edb19e5e2c070bdd65037a430986612dd4191 100644 --- a/indra/newview/llnotificationofferhandler.cpp +++ b/indra/newview/llnotificationofferhandler.cpp @@ -36,6 +36,9 @@ #include "llscriptfloater.h" #include "llimview.h" #include "llnotificationsutil.h" +// [RLVa:KB] - Checked: 2013-05-09 (RLVa-1.4.9) +#include "rlvactions.h" +// [/RLVa:KB] using namespace LLNotificationsUI; @@ -108,9 +111,21 @@ bool LLOfferHandler::processNotification(const LLNotificationPtr& notification) notification->playSound(); } - LLHandlerUtil::spawnIMSession(name, from_id); - LLHandlerUtil::addNotifPanelToIM(notification); - +// [RLVa:KB] - Checked: 2013-05-09 (RLVa-1.4.9) + // Don't spawn an IM session for non-chat related events + if (RlvActions::canStartIM(from_id)) + { +// [/RLVa:KB] + LLHandlerUtil::spawnIMSession(name, from_id); + LLHandlerUtil::addNotifPanelToIM(notification); +// [RLVa:KB] - Checked: 2013-05-09 (RLVa-1.4.9) + } + else + { + // Since we didn't add this notification to an IM session we want it to get routed to the notification syswell + add_notif_to_im = false; + } +// [/RLVa:KB] } if (!notification->canShowToast()) @@ -177,9 +192,18 @@ bool LLOfferHandler::processNotification(const LLNotificationPtr& notification) } else { - if (notification->canLogToIM() - && notification->hasFormElements() - && !LLHandlerUtil::isIMFloaterOpened(notification)) +// if (notification->canLogToIM() +// && notification->hasFormElements() +// && !LLHandlerUtil::isIMFloaterOpened(notification)) +// [SL:KB] - Patch: UI-Notifications | Checked: 2013-05-09 (Catznip-3.5) + // The above test won't necessarily tell us whether the notification went into an IM or to the notification syswell + // -> the one and only time we need to decrease the unread IM count is when we've clicked any of the buttons on the *toast* + // -> since LLIMFloater::updateMessages() hides the toast when we open the IM (which resets the unread count to 0) we should + // *only* decrease the unread IM count if there's a visible toast since the unread count will be at 0 otherwise anyway + LLScreenChannel* pChannel = dynamic_cast<LLScreenChannel*>(mChannel.get()); + LLToast* pToast = (pChannel) ? pChannel->getToastByNotificationID(notification->getID()) : NULL; + if ( (pToast) && (!pToast->getCanBeStored()) ) +// [/SL:KB] { LLHandlerUtil::decIMMesageCounter(notification); } diff --git a/indra/newview/llpanelappearancetab.cpp b/indra/newview/llpanelappearancetab.cpp index 8fa8867c696fca1358eda2c37a006b8899bac65c..fdb331163b2c8e1487c143a4ec8657485cace9ce 100644 --- a/indra/newview/llpanelappearancetab.cpp +++ b/indra/newview/llpanelappearancetab.cpp @@ -32,6 +32,10 @@ #include "llinventoryfunctions.h" #include "llinventorymodel.h" #include "llviewerinventory.h" +// [RLVa:KB] - Checked: 2012-07-08 (RLVa-1.4.7) +#include "rlvcommon.h" +#include "rlvhandler.h" +// [/RLVa:KB] //virtual bool LLPanelAppearanceTab::canTakeOffSelected() @@ -46,6 +50,11 @@ bool LLPanelAppearanceTab::canTakeOffSelected() LLViewerInventoryItem* item = gInventory.getItem(*it); if (!item) continue; +// [RLVa:KB] - Checked: 2012-07-08 (RLVa-1.4.7) + if ( (rlv_handler_t::isEnabled()) && (rlvPredCanNotRemoveItem(item)) ) + return false; +// [/RLVa:KB] + if (is_worn(NULL, item)) return true; } return false; diff --git a/indra/newview/llpanelcontents.cpp b/indra/newview/llpanelcontents.cpp index 451f41cd3bfe6dfa756ac9ea2f95ad97ffacacf9..07693bda99331b755bded0756e33e7dc256f6696 100644 --- a/indra/newview/llpanelcontents.cpp +++ b/indra/newview/llpanelcontents.cpp @@ -60,6 +60,10 @@ #include "llviewerwindow.h" #include "llworld.h" #include "llfloaterperms.h" +// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a) +#include "rlvhandler.h" +#include "rlvlocks.h" +// [/RLVa:KB] // // Imported globals @@ -119,6 +123,25 @@ 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] - 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 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))) ) + { + // 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); + + editable = + (pObj) && (isAgentAvatarValid()) && ((!gAgentAvatarp->isSitting()) || (gAgentAvatarp->getRoot() != pObj->getRootEdit())); + } + } +// [/RLVa:KB] + // Edit script button - ok if object is editable and there's an unambiguous destination for the object. getChildView("button new script")->setEnabled( editable && @@ -162,6 +185,21 @@ void LLPanelContents::onClickNewScript(void *userdata) LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getFirstRootObject(children_ok); if(object) { +// [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 (gRlvAttachmentLocks.isLockedAttachment(object->getRootEdit())) + { + return; // Disallow creating new scripts in a locked attachment + } + else if ( (gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SITTP)) ) + { + if ( (isAgentAvatarValid()) && (gAgentAvatarp->isSitting()) && (gAgentAvatarp->getRoot() == object->getRootEdit()) ) + return; // .. or in a linkset the avie is sitting on under @unsit=n/@sittp=n + } + } +// [/RLVa:KB] + LLPermissions perm; perm.init(gAgent.getID(), gAgent.getID(), LLUUID::null, LLUUID::null); diff --git a/indra/newview/llpanelland.cpp b/indra/newview/llpanelland.cpp index acdb16f43291807995eaeb9dfb2f99a6082c14f0..49b96fb10da4df5f70801cb9239ddc48af153a84 100644 --- a/indra/newview/llpanelland.cpp +++ b/indra/newview/llpanelland.cpp @@ -44,6 +44,10 @@ #include "lluictrlfactory.h" +// [RLVa:KB] +#include "rlvhandler.h" +// [/RLVa:KB] + LLPanelLandSelectObserver* LLPanelLandInfo::sObserver = NULL; LLPanelLandInfo* LLPanelLandInfo::sInstance = NULL; @@ -224,6 +228,14 @@ void LLPanelLandInfo::refresh() //static void LLPanelLandInfo::onClickClaim() { +// [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0a) +/* + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) + { + return; + } +*/ +// [/RLVa:KB] LLViewerParcelMgr::getInstance()->startBuyLand(); } diff --git a/indra/newview/llpanellandmarks.cpp b/indra/newview/llpanellandmarks.cpp index cd1dc0f0701de1e5173fe84d353a9449060df4c8..d0b21a6ac33d668dfe46512d19bf54140ee24a6b 100644 --- a/indra/newview/llpanellandmarks.cpp +++ b/indra/newview/llpanellandmarks.cpp @@ -56,6 +56,9 @@ #include "lltoggleablemenu.h" #include "llviewermenu.h" #include "llviewerregion.h" +// [RLVa:KB] +#include "rlvhandler.h" +// [/RLVa:KB] // Not yet implemented; need to remove buildPanel() from constructor when we switch //static LLRegisterPanelClassWrapper<LLLandmarksPanel> t_landmarks("panel_landmarks"); @@ -771,15 +774,22 @@ void LLLandmarksPanel::onAddAction(const LLSD& userdata) const std::string command_name = userdata.asString(); if("add_landmark" == command_name) { - LLViewerInventoryItem* landmark = LLLandmarkActions::findLandmarkForAgentPos(); - if(landmark) +// [RLVa:KB] - Checked: 2012-02-08 (RLVa-1.4.5) | Added: RLVa-1.4.5 + if (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) { - LLNotificationsUtil::add("LandmarkAlreadyExists"); - } - else - { - LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "create_landmark")); +// [/RLVa:KB] + LLViewerInventoryItem* landmark = LLLandmarkActions::findLandmarkForAgentPos(); + if(landmark) + { + LLNotificationsUtil::add("LandmarkAlreadyExists"); + } + else + { + LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "create_landmark")); + } +// [RLVa:KB] - Checked: 2012-02-08 (RLVa-1.4.5) | Added: RLVa-1.4.5 } +// [/RLVa:KB] } else if ("category" == command_name) { @@ -1045,6 +1055,12 @@ bool LLLandmarksPanel::isActionEnabled(const LLSD& userdata) const } return false; } +// [RLVa:KB] - Checked: 2012-02-08 (RLVa-1.4.5) | Added: RLVa-1.4.5 + else if("add_landmark" == command_name) + { + return !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC); + } +// [/RLVa:KB] else { LL_WARNS() << "Unprocessed command has come: " << command_name << LL_ENDL; diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp index 5dd44b4444f5cda6a84b02b83b93cb53ed76b044..248cddac422eb4c334f26423224b6615a98674fb 100644 --- a/indra/newview/llpanelobject.cpp +++ b/indra/newview/llpanelobject.cpp @@ -66,6 +66,10 @@ #include "llviewercontrol.h" #include "lluictrlfactory.h" //#include "llfirstuse.h" +// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a) +#include "rlvhandler.h" +#include "llvoavatarself.h" +// [/RLVa:KB] #include "lldrawpool.h" @@ -357,6 +361,14 @@ void LLPanelObject::getState( ) enable_rotate = FALSE; } +// [RLVa:KB] - Checked: 2010-03-31 (RLVa-1.2.0c) | Modified: RLVa-1.0.0g + if ( (rlv_handler_t::isEnabled()) && ((gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SITTP))) ) + { + if ( (isAgentAvatarValid()) && (gAgentAvatarp->isSitting()) && (gAgentAvatarp->getRoot() == objectp->getRootEdit()) ) + enable_move = enable_scale = enable_rotate = FALSE; + } +// [/RLVa:KB] + LLVector3 vec; if (enable_move) { diff --git a/indra/newview/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp index c4211d550806ab77b16d9729cb991061e2423e73..0ea7093128bf466b70e84d05614ea1f18683fb9d 100644 --- a/indra/newview/llpanelobjectinventory.cpp +++ b/indra/newview/llpanelobjectinventory.cpp @@ -66,6 +66,10 @@ #include "llviewerregion.h" #include "llviewerobjectlist.h" #include "llviewermessage.h" +// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a) +#include "rlvhandler.h" +#include "rlvlocks.h" +// [/RLVa:KB] const LLColor4U DEFAULT_WHITE(255, 255, 255); @@ -377,8 +381,16 @@ void LLTaskInvFVBridge::openItem() BOOL LLTaskInvFVBridge::isItemRenameable() const { - if(gAgent.isGodlike()) return TRUE; +// [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()) && (object) && (gRlvAttachmentLocks.isLockedAttachment(object->getRootEdit())) ) + { + return FALSE; + } +// [/RLVa:KB] + + if(gAgent.isGodlike()) return TRUE; +// LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); if(object) { LLInventoryItem* item = (LLInventoryItem*)(object->getInventoryObject(mUUID)); @@ -393,7 +405,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()); + if ( (rlv_handler_t::isEnabled()) && (object) && (gRlvAttachmentLocks.isLockedAttachment(object->getRootEdit())) ) + { + return FALSE; + } +// [/RLVa:KB] + +// LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); if(object) { LLViewerInventoryItem* item = NULL; @@ -420,12 +440,45 @@ BOOL LLTaskInvFVBridge::isItemMovable() const // return TRUE; //} //return FALSE; +// [RLVa:KB] - Checked: 2010-04-01 (RLVa-1.2.0c) | Modified: RLVa-1.0.5a + if (rlv_handler_t::isEnabled()) + { + const LLViewerObject* pObj = gObjectList.findObject(mPanel->getTaskUUID()); + if (pObj) + { + if (gRlvAttachmentLocks.isLockedAttachment(pObj->getRootEdit())) + { + return FALSE; + } + else if ( (gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SITTP)) ) + { + if ( (isAgentAvatarValid()) && (gAgentAvatarp->isSitting()) && (gAgentAvatarp->getRoot() == pObj->getRootEdit()) ) + return FALSE; + } + } + } +// [/RLVa:KB] return TRUE; } BOOL LLTaskInvFVBridge::isItemRemovable() const { const LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); +// [RLVa:KB] - Checked: 2010-04-01 (RLVa-1.2.0c) | Modified: RLVa-1.0.5a + if ( (object) && (rlv_handler_t::isEnabled()) ) + { + if (gRlvAttachmentLocks.isLockedAttachment(object->getRootEdit())) + { + return FALSE; + } + else if ( (gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SITTP)) ) + { + if ( (isAgentAvatarValid()) && (gAgentAvatarp->isSitting()) && (gAgentAvatarp->getRoot() == object->getRootEdit()) ) + return FALSE; + } + } +// [/RLVa:KB] + if(object && (object->permModify() || object->permYouOwner())) { @@ -574,6 +627,13 @@ 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.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()) && (gRlvAttachmentLocks.isLockedAttachment(object->getRootEdit())) ) + { + return FALSE; + } +// [/RLVa:KB] if (object->isAttachment() && !can_copy) { //RN: no copy contents of attachments cannot be dragged out @@ -689,20 +749,45 @@ void LLTaskInvFVBridge::buildContextMenu(LLMenuGL& menu, U32 flags) else if (canOpenItem()) { items.push_back(std::string("Task Open")); - } - items.push_back(std::string("Task Properties")); - if(isItemRenameable()) - { - items.push_back(std::string("Task Rename")); - if ((flags & FIRST_SELECTED_ITEM) == 0) +// [RLVa:KB] - Checked: 2010-03-01 (RLVa-1.2.0b) | Modified: RLVa-1.1.0a + if (rlv_handler_t::isEnabled()) { - disabled_items.push_back(std::string("Task Rename")); + 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")); + } } +// [/RLVa:KB] } - if(isItemRemovable()) - { - items.push_back(std::string("Task Remove")); - } + items.push_back(std::string("Task Properties")); +// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Added: RLVa-1.2.1f + items.push_back(std::string("Task Rename")); + if ( (!isItemRenameable()) || ((flags & FIRST_SELECTED_ITEM) == 0) ) + { + disabled_items.push_back(std::string("Task Rename")); + } + items.push_back(std::string("Task Remove")); + if (!isItemRemovable()) + { + disabled_items.push_back(std::string("Task Remove")); + } +// [/RLVa:KB] +// if(isItemRenameable()) +// { +// items.push_back(std::string("Task Rename")); +// if ((flags & FIRST_SELECTED_ITEM) == 0) +// { +// disabled_items.push_back(std::string("Task Rename")); +// } +// } +// if(isItemRemovable()) +// { +// items.push_back(std::string("Task Remove")); +// } hide_context_entries(menu, items, disabled_items); } @@ -1106,6 +1191,13 @@ void LLTaskLSLBridge::openItem() { return; } +// [RLVa:KB] - Checked: 2010-03-27 (RLVa-1.2.0b) | Modified: RLVa-1.1.0a + if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.isLockedAttachment(object->getRootEdit())) ) + { + RlvUtil::notifyBlockedViewXXX(LLAssetType::AT_SCRIPT); + return; + } +// [/RLVa:KB] if (object->permModify() || gAgent.isGodlike()) { LLSD floater_key; @@ -1168,6 +1260,14 @@ void LLTaskNotecardBridge::openItem() return; } +// [RLVa:KB] - Checked: 2010-03-27 (RLVa-1.2.0b) | Modified: RLVa-1.2.0b + if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.isLockedAttachment(object->getRootEdit())) ) + { + RlvUtil::notifyBlockedViewXXX(LLAssetType::AT_NOTECARD); + return; + } +// [/RLVa:KB] + // Note: even if we are not allowed to modify copyable notecard, we should be able to view it LLInventoryItem *item = dynamic_cast<LLInventoryItem*>(object->getInventoryObject(mUUID)); BOOL item_copy = item && gAgent.allowOperation(PERM_COPY, item->getPermissions(), GP_OBJECT_MANIPULATE); diff --git a/indra/newview/llpaneloutfitedit.cpp b/indra/newview/llpaneloutfitedit.cpp index 8331c152e206a34fc2f3f3c9b006e1e53963f91b..d2db4b718da97743ede76f6b470c852c6e61b7d4 100644 --- a/indra/newview/llpaneloutfitedit.cpp +++ b/indra/newview/llpaneloutfitedit.cpp @@ -73,6 +73,9 @@ #include "llwearableitemslist.h" #include "llwearabletype.h" #include "llweb.h" +// [RLVa:KB] - Checked: 2010-09-16 (RLVa-1.2.1a) +#include "rlvhandler.h" +// [/RLVa:KB] static LLPanelInjector<LLPanelOutfitEdit> t_outfit_edit("panel_outfit_edit"); @@ -602,6 +605,10 @@ void LLPanelOutfitEdit::toggleAddWearablesPanel() void LLPanelOutfitEdit::showAddWearablesPanel(bool show_add_wearables) { +// [RLVa:KB] - Checked: 2010-09-16 (RLVa-1.2.1a) | Added: RLVa-1.2.1a + show_add_wearables = (show_add_wearables) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWINV)); +// [/RLVa:KB] + mAddWearablesPanel->setVisible(show_add_wearables); getChild<LLUICtrl>("show_add_wearables_btn")->setValue(show_add_wearables); diff --git a/indra/newview/llpaneloutfitsinventory.h b/indra/newview/llpaneloutfitsinventory.h index 6a0ea04fa6a050d14e95bb9a573c1f674eb5c2d7..827c7c1c227f17f1325cf5eac4a566202cadbb19 100644 --- a/indra/newview/llpaneloutfitsinventory.h +++ b/indra/newview/llpaneloutfitsinventory.h @@ -57,6 +57,12 @@ class LLPanelOutfitsInventory : public LLPanel static LLSidepanelAppearance* getAppearanceSP(); +// [RLVa:KB] - Checked: 2010-08-24 (RLVa-1.4.0a) | Added: RLVa-1.2.1a + LLTabContainer* getAppearanceTabs() { return mAppearanceTabs; } + LLOutfitsList* getMyOutfitsPanel() { return mMyOutfitsPanel; } + LLPanelWearing* getCurrentOutfitPanel() { return mCurrentOutfitPanel; } +// [/RLVa:KB] + static LLPanelOutfitsInventory* findInstance(); protected: diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp index bc177abc57f2f377dfcab06a4195cc56fe2ac347..91e11aafb9473f3379b63820028082668ffd925d 100644 --- a/indra/newview/llpanelpeople.cpp +++ b/indra/newview/llpanelpeople.cpp @@ -74,6 +74,10 @@ #include "llagentui.h" #include "llslurl.h" +// [RLVa:KB] - Checked: RLVa-1.2.2 +#include "rlvactions.h" +// [/RLVa:KB] + #define FRIEND_LIST_UPDATE_TIMEOUT 0.5 #define NEARBY_LIST_UPDATE_INTERVAL 1 @@ -625,6 +629,9 @@ BOOL LLPanelPeople::postBuild() mNearbyList->setNoFilteredItemsMsg(getString("no_one_filtered_near")); mNearbyList->setShowIcons("NearbyListShowIcons"); mNearbyList->setShowCompleteName(!gSavedSettings.getBOOL("NearbyListHideUsernames")); +// [RLVa:KB] - Checked: RLVa-1.2.0 + mNearbyList->setRlvCheckShowNames(true); +// [/RLVa:KB] mMiniMap = (LLNetMap*)getChildView("Net Map",true); mMiniMap->setToolTipMsg(gSavedSettings.getBOOL("DoubleClickTeleport") ? getString("AltMiniMapToolTipMsg") : getString("MiniMapToolTipMsg")); @@ -830,7 +837,18 @@ void LLPanelPeople::updateNearbyList() std::vector<LLVector3d> positions; - LLWorld::getInstance()->getAvatars(&mNearbyList->getIDs(), &positions, gAgent.getPositionGlobal(), gSavedSettings.getF32("NearMeRange")); +// [RLVa:KB] - Checked: RLVa-2.0.3 + if (RlvActions::canShowNearbyAgents()) + { +// [/RLVa:KB] + LLWorld::getInstance()->getAvatars(&mNearbyList->getIDs(), &positions, gAgent.getPositionGlobal(), gSavedSettings.getF32("NearMeRange")); +// [RLVa:KB] - Checked: RLVa-2.0.3 + } + else + { + mNearbyList->getIDs().clear(); + } +// [/RLVa:KB] mNearbyList->setDirty(); DISTANCE_COMPARATOR.updateAvatarsPositions(positions, mNearbyList->getIDs()); @@ -894,6 +912,9 @@ void LLPanelPeople::updateFacebookList(bool visible) void LLPanelPeople::updateButtons() { std::string cur_tab = getActiveTabName(); +// [RLVa:KB] - Checked: RLVa-1.4.9 + bool nearby_tab_active = (cur_tab == NEARBY_TAB_NAME); +// [/RLVa:KB] bool friends_tab_active = (cur_tab == FRIENDS_TAB_NAME); bool group_tab_active = (cur_tab == GROUP_TAB_NAME); //bool recent_tab_active = (cur_tab == RECENT_TAB_NAME); @@ -934,8 +955,12 @@ void LLPanelPeople::updateButtons() LLPanel* cur_panel = mTabContainer->getCurrentPanel(); if (cur_panel) { +// [RLVa:KB] - Checked: RLVa-1.2.0 if (cur_panel->hasChild("add_friend_btn", TRUE)) - cur_panel->getChildView("add_friend_btn")->setEnabled(item_selected && !is_friend && !is_self); + cur_panel->getChildView("add_friend_btn")->setEnabled(item_selected && !is_friend && !is_self && ((!nearby_tab_active) || (RlvActions::canShowName(RlvActions::SNC_DEFAULT, selected_id)))); +// [/RLBa:KB] +// if (cur_panel->hasChild("add_friend_btn", TRUE)) +// cur_panel->getChildView("add_friend_btn")->setEnabled(item_selected && !is_friend && !is_self); if (friends_tab_active) { @@ -948,6 +973,16 @@ void LLPanelPeople::updateButtons() } } } + +// [RLVa:KB] - Checked: RLVa-1.2.0 + if ( (nearby_tab_active) && (RlvActions::isRlvEnabled()) && (!RlvActions::canShowName(RlvActions::SNC_DEFAULT)) ) + { + bool fCanShowNames = true; + std::for_each(selected_uuids.begin(), selected_uuids.end(), [&fCanShowNames](const LLUUID& idAgent) { fCanShowNames &= RlvActions::canShowName(RlvActions::SNC_DEFAULT, idAgent); }); + if (!fCanShowNames) + item_selected = multiple_selected = false; + } +// [/RLBa:KB] } std::string LLPanelPeople::getActiveTabName() const @@ -1158,6 +1193,13 @@ void LLPanelPeople::onAvatarListDoubleClicked(LLUICtrl* ctrl) return; } +// [RLVa:KB] - Checked: RLVa-2.0.1 + if ( (RlvActions::isRlvEnabled()) && (NEARBY_TAB_NAME == getActiveTabName()) && (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, clicked_id)) ) + { + return; + } +// [/RLVa:KB] + #if 0 // SJB: Useful for testing, but not currently functional or to spec LLAvatarActions::showProfile(clicked_id); #else // spec says open IM window @@ -1273,6 +1315,15 @@ void LLPanelPeople::onImButtonClicked() { uuid_vec_t selected_uuids; getCurrentItemIDs(selected_uuids); +// [RLVa:KB] - Checked: RLVa-2.0.1 + if ( (RlvActions::isRlvEnabled()) && (NEARBY_TAB_NAME == getActiveTabName()) && (!RlvActions::canShowName(RlvActions::SNC_DEFAULT)) ) + { + bool fCanShowNames = true; + std::for_each(selected_uuids.begin(), selected_uuids.end(), [&fCanShowNames](const LLUUID& idAgent) { fCanShowNames &= RlvActions::canShowName(RlvActions::SNC_DEFAULT, idAgent); }); + if (!fCanShowNames) + return; + } +// [/RLVa:KB] if ( selected_uuids.size() == 1 ) { // if selected only one person then start up IM diff --git a/indra/newview/llpanelpeople.h b/indra/newview/llpanelpeople.h index eb7e76a77299f0c042d5f26f46da3551a17c27fb..49901bb51fc10a935b06fa7b2526652507060614 100644 --- a/indra/newview/llpanelpeople.h +++ b/indra/newview/llpanelpeople.h @@ -59,6 +59,11 @@ class LLPanelPeople bool mTryToConnectToFacebook; +// [RLVa:KB] - Checked: RLVa-1.2.0 + LLAvatarList* getNearbyList() { return mNearbyList; } + void updateNearbyList(); +// [/RLVa:KB] + // internals class Updater; @@ -78,7 +83,7 @@ class LLPanelPeople void updateFriendListHelpText(); void updateFriendList(); bool updateSuggestedFriendList(); - void updateNearbyList(); +// void updateNearbyList(); void updateRecentList(); void updateFacebookList(bool visible); diff --git a/indra/newview/llpanelpeoplemenus.cpp b/indra/newview/llpanelpeoplemenus.cpp index 65769ff526490982f8e6b07eb6d22f49ba67ae59..f54127931effe165919cccb3df1bc86c06c9f214 100644 --- a/indra/newview/llpanelpeoplemenus.cpp +++ b/indra/newview/llpanelpeoplemenus.cpp @@ -46,6 +46,9 @@ #include "llviewerregion.h" #include "llvoavatarself.h" #include "roles_constants.h" +// [RLVa:KB] - Checked: RLVa-2.0.1 +#include "rlvactions.h" +// [/RLVa:KB] namespace LLPanelPeopleMenus { @@ -189,7 +192,10 @@ bool PeopleContextMenu::enableContextMenuItem(const LLSD& userdata) for (;id != uuids_end; ++id) { - if ( LLAvatarActions::isFriend(*id) ) +// if ( LLAvatarActions::isFriend(*id) ) +// [RLVa:KB] - Checked: 2014-03-31 (RLVa-2.0.1) + if ( (LLAvatarActions::isFriend(*id)) || (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, *id)) ) +// [/RLVa:KB] { result = false; break; @@ -212,7 +218,10 @@ bool PeopleContextMenu::enableContextMenuItem(const LLSD& userdata) for (;id != uuids_end; ++id) { - if ( !LLAvatarActions::isFriend(*id) ) +// if ( !LLAvatarActions::isFriend(*id) ) +// [RLVa:KB] - Checked: 2014-03-31 (RLVa-2.0.1) + if ( (!LLAvatarActions::isFriend(*id)) || (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, *id)) ) +// [/RLVa:KB] { result = false; break; @@ -315,14 +324,29 @@ void PeopleContextMenu::requestTeleport() { // boost::bind cannot recognize overloaded method LLAvatarActions::teleportRequest(), // so we have to use a wrapper. +// [RLVa:KB] - Checked: RLVa-2.0.1 + bool fRlvCanShowName = (!m_fRlvCheck) || (RlvActions::canShowName(RlvActions::SNC_DEFAULT, mUUIDs.front())); + RlvActions::setShowName(RlvActions::SNC_TELEPORTREQUEST, fRlvCanShowName); LLAvatarActions::teleportRequest(mUUIDs.front()); + RlvActions::setShowName(RlvActions::SNC_TELEPORTREQUEST, true); +// [/RLVa:KB] +// LLAvatarActions::teleportRequest(mUUIDs.front()); } void PeopleContextMenu::offerTeleport() { // boost::bind cannot recognize overloaded method LLAvatarActions::offerTeleport(), // so we have to use a wrapper. +// [RLVa:KB] - Checked: RLVa-2.0.1 + bool fRlvCanShowName = true; + if ( (m_fRlvCheck) && (RlvActions::isRlvEnabled()) ) + std::for_each(mUUIDs.begin(), mUUIDs.end(), [&fRlvCanShowName](const LLUUID& idAgent) { fRlvCanShowName &= RlvActions::canShowName(RlvActions::SNC_DEFAULT, idAgent); }); + + RlvActions::setShowName(RlvActions::SNC_TELEPORTOFFER, fRlvCanShowName); LLAvatarActions::offerTeleport(mUUIDs); + RlvActions::setShowName(RlvActions::SNC_TELEPORTOFFER, true); +// [/RLVa:KB] +// LLAvatarActions::offerTeleport(mUUIDs); } void PeopleContextMenu::eject() @@ -378,7 +402,29 @@ void NearbyPeopleContextMenu::buildContextMenu(class LLMenuGL& menu, U32 flags) menuentry_vec_t items; menuentry_vec_t disabled_items; - if (flags & ITEM_IN_MULTI_SELECTION) +// [RLVa:KB] - Checked: RLVa-1.5.0 + bool fRlvCanShowName = true; + if ( (m_fRlvCheck) && (RlvActions::isRlvEnabled()) ) + std::for_each(mUUIDs.begin(), mUUIDs.end(), [&fRlvCanShowName](const LLUUID& idAgent) { fRlvCanShowName &= RlvActions::canShowName(RlvActions::SNC_DEFAULT, idAgent); }); + + if (!fRlvCanShowName) + { + if (flags & ITEM_IN_MULTI_SELECTION) + { + items.push_back(std::string("offer_teleport")); + } + else + { + items.push_back(std::string("offer_teleport")); + items.push_back(std::string("request_teleport")); + items.push_back(std::string("separator_invite_to_group")); + items.push_back(std::string("zoom_in")); + items.push_back(std::string("block_unblock")); + } + } + else if (flags & ITEM_IN_MULTI_SELECTION) +// [/RLVa:KB] +// if (flags & ITEM_IN_MULTI_SELECTION) { items.push_back(std::string("add_friends")); items.push_back(std::string("remove_friends")); diff --git a/indra/newview/llpanelpeoplemenus.h b/indra/newview/llpanelpeoplemenus.h index 5ed20e00640c0d0ecac0ce68dae818e6f161f066..8f88bf36adab57d3c3351a475293e24e160c7cb1 100644 --- a/indra/newview/llpanelpeoplemenus.h +++ b/indra/newview/llpanelpeoplemenus.h @@ -38,6 +38,9 @@ namespace LLPanelPeopleMenus class PeopleContextMenu : public LLListContextMenu { public: +// [RLVa:KB] - Checked: RLVa-1.5.0 + PeopleContextMenu() : m_fRlvCheck(false) {} +// [/RLVa:KB] /*virtual*/ LLContextMenu* createMenu(); protected: @@ -51,6 +54,11 @@ class PeopleContextMenu : public LLListContextMenu void eject(); void startConference(); void requestTeleport(); + +// [RLVa:KB] - Checked: RLVa-1.5.0 +protected: + bool m_fRlvCheck; +// [/RLVa:KB] }; /** @@ -58,6 +66,10 @@ class PeopleContextMenu : public LLListContextMenu */ class NearbyPeopleContextMenu : public PeopleContextMenu { +// [RLVa:KB] - Checked: RLVa-1.5.0 +public: + NearbyPeopleContextMenu() : PeopleContextMenu() { m_fRlvCheck = true; } +// [/RLVa:KB] protected: /*virtual*/ void buildContextMenu(class LLMenuGL& menu, U32 flags); }; diff --git a/indra/newview/llpanelpermissions.cpp b/indra/newview/llpanelpermissions.cpp index 6e677bbce55228b0df138be22c258e5aeca0496c..da20378d13196cd041604fe2efd381dcad687a19 100644 --- a/indra/newview/llpanelpermissions.cpp +++ b/indra/newview/llpanelpermissions.cpp @@ -63,7 +63,11 @@ #include "roles_constants.h" #include "llgroupactions.h" #include "lltrans.h" - +// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.2a) +#include "llslurl.h" +#include "rlvactions.h" +#include "rlvcommon.h" +// [/RLVa:KB] U8 string_value_to_click_action(std::string p_value); std::string click_action_to_string_value( U8 action); @@ -365,11 +369,18 @@ void LLPanelPermissions::refresh() // Update creator text field getChildView("Creator:")->setEnabled(TRUE); +// [RLVa:KB] - Checked: 2010-11-02 (RLVa-1.2.2a) | Modified: RLVa-1.2.2a + BOOL creators_identical = FALSE; +// [/RLVa:KB] std::string creator_name; - LLSelectMgr::getInstance()->selectGetCreator(mCreatorID, creator_name); +// [RLVa:KB] - Checked: 2010-11-02 (RLVa-1.2.2a) | Modified: RLVa-1.2.2a + creators_identical = LLSelectMgr::getInstance()->selectGetCreator(mCreatorID, creator_name); +// [/RLVa:KB] +// LLSelectMgr::getInstance()->selectGetCreator(mCreatorID, creator_name); - getChild<LLUICtrl>("Creator Name")->setValue(creator_name); - getChildView("Creator Name")->setEnabled(TRUE); +// getChild<LLUICtrl>("Creator Name")->setValue(creator_name); +// getChildView("Creator Name")->setEnabled(TRUE); +// [RLVa:KB] - Moved further down to avoid an annoying flicker when the text is set twice in a row // Update owner text field getChildView("Owner:")->setEnabled(TRUE); @@ -397,8 +408,28 @@ void LLPanelPermissions::refresh() } } } +// getChild<LLUICtrl>("Owner Name")->setValue(owner_name); +// getChildView("Owner Name")->setEnabled(TRUE); +// [RLVa:KB] - Moved further down to avoid an annoying flicker when the text is set twice in a row + +// [RLVa:KB] - Checked: RLVa-2.0.1 + if ( (RlvActions::isRlvEnabled()) && (!RlvActions::canShowName(RlvActions::SNC_DEFAULT)) ) + { + // Only anonymize the creator if all of the selection was created by the same avie who's also the owner or they're a nearby avie + if ( (creators_identical) && (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, mCreatorID)) && ((mCreatorID == mOwnerID) || (RlvUtil::isNearbyAgent(mCreatorID))) ) + creator_name = LLSLURL("agent", mCreatorID, "rlvanonym").getSLURLString(); + + // Only anonymize the owner name if all of the selection is owned by the same avie and isn't group owned + if ( (owners_identical) && (!LLSelectMgr::getInstance()->selectIsGroupOwned()) && (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, mOwnerID)) ) + owner_name = LLSLURL("agent", mOwnerID, "rlvanonym").getSLURLString(); + } + + getChild<LLUICtrl>("Creator Name")->setValue(creator_name); + getChildView("Creator Name")->setEnabled(TRUE); + getChild<LLUICtrl>("Owner Name")->setValue(owner_name); getChildView("Owner Name")->setEnabled(TRUE); +// [/RLVa:KB] // update group text field getChildView("Group:")->setEnabled(TRUE); diff --git a/indra/newview/llpanelplaceprofile.cpp b/indra/newview/llpanelplaceprofile.cpp index 2fa4ee376a235a33824f14865476d3412f7f6beb..d5a17b77fb7aa5733a5cf7020ad10f6c9b1adfbf 100644 --- a/indra/newview/llpanelplaceprofile.cpp +++ b/indra/newview/llpanelplaceprofile.cpp @@ -52,6 +52,9 @@ #include "llviewercontrol.h" #include "llviewerparcelmgr.h" #include "llviewerregion.h" +// [RLVa:KB] - Checked: 2010-09-02 (RLVa-1.2.1b) +#include "rlvhandler.h" +// [/RLVa:KB] const F64 COVENANT_REFRESH_TIME_SEC = 60.0f; @@ -613,7 +616,10 @@ void LLPanelPlaceProfile::displaySelectedParcelInfo(LLParcel* parcel, mLastSelectedRegionID = region->getRegionID(); LLPanelPlaceInfo::processParcelInfo(parcel_data); - mYouAreHerePanel->setVisible(is_current_parcel); +// mYouAreHerePanel->setVisible(is_current_parcel); +// [RLVa:KB] - Checked: 2010-09-02 (RLVa-1.4.5) | Added: RLVa-1.2.1 + mYouAreHerePanel->setVisible(is_current_parcel && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC))); +// [/RLVa:KB] getChild<LLAccordionCtrlTab>("sales_tab")->setVisible(for_sale); mAccordionCtrl->arrange(); } @@ -681,6 +687,9 @@ void LLPanelPlaceProfile::updateYouAreHereBanner(void* userdata) BOOL display_banner = gAgent.getRegion()->getRegionID() == self->mLastSelectedRegionID && LLAgentUI::checkAgentDistance(self->mPosRegion, radius); - self->mYouAreHerePanel->setVisible(display_banner); +// self->mYouAreHerePanel->setVisible(display_banner); +// [RLVa:KB] - Checked: 2010-09-02 (RLVa-1.4.5) | Added: RLVa-1.2.1 + self->mYouAreHerePanel->setVisible(display_banner && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC))); +// [/RLVa:KB] } } diff --git a/indra/newview/llpanelprofile.h b/indra/newview/llpanelprofile.h index d97f60ed229ab16320932951e9a13c896e9b7177..63690c0e533b961dcbea164b4130a660b4065944 100644 --- a/indra/newview/llpanelprofile.h +++ b/indra/newview/llpanelprofile.h @@ -52,13 +52,17 @@ class LLPanelProfile : public LLPanel S32 notifyParent(const LLSD& info); +// [RLVa:KB] - Checked: 2010-04-20 (RLVa-1.2.0f) | Added: RVLa-1.2.0f + const LLUUID& getAvatarId() const { return mAvatarId; } +// [/RLVa:KB] + protected: LLPanelProfile(); virtual void onTabSelected(const LLSD& param); - const LLUUID& getAvatarId() { return mAvatarId; } +// const LLUUID& getAvatarId() { return mAvatarId; } void setAvatarId(const LLUUID& avatar_id) { mAvatarId = avatar_id; } diff --git a/indra/newview/llpaneltopinfobar.cpp b/indra/newview/llpaneltopinfobar.cpp index 109013498ee71b17d8a4510383003113ae365939..b0dafe5a1195a396592fcb24bcfbeea7530f414f 100644 --- a/indra/newview/llpaneltopinfobar.cpp +++ b/indra/newview/llpaneltopinfobar.cpp @@ -44,6 +44,9 @@ #include "llviewermenu.h" #include "llviewerparcelmgr.h" #include "llviewerregion.h" +// [RLVa:KB] - Checked: 2012-02-08 (RLVa-1.4.5) | Added: RLVa-1.4.5 +#include "rlvhandler.h" +// [/RLVa:KB] class LLPanelTopInfoBar::LLParcelChangeObserver : public LLParcelObserver { @@ -452,28 +455,47 @@ void LLPanelTopInfoBar::onContextMenuItemClicked(const LLSD::String& item) { if (item == "landmark") { - LLViewerInventoryItem* landmark = LLLandmarkActions::findLandmarkForAgentPos(); - - if(landmark == NULL) - { - LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "create_landmark")); - } - else +// [RLVa:KB] - Checked: 2012-02-08 (RLVa-1.4.5) | Added: RLVa-1.4.5 + if (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) { - LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "landmark").with("id",landmark->getUUID())); +// [/RLVa:KB] + LLViewerInventoryItem* landmark = LLLandmarkActions::findLandmarkForAgentPos(); + + if(landmark == NULL) + { + LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "create_landmark")); + } + else + { + LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "landmark").with("id",landmark->getUUID())); + } +// [RLVa:KB] - Checked: 2012-02-08 (RLVa-1.4.5) | Added: RLVa-1.4.5 } +// [/RLVa:KB] } else if (item == "copy") { - LLSLURL slurl; - LLAgentUI::buildSLURL(slurl, false); - LLUIString location_str(slurl.getSLURLString()); +// [RLVa:KB] - Checked: 2012-02-08 (RLVa-1.4.5) | Added: RLVa-1.4.5 + if (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) + { +// [/RLVa:KB] + LLSLURL slurl; + LLAgentUI::buildSLURL(slurl, false); + LLUIString location_str(slurl.getSLURLString()); - LLClipboard::instance().copyToClipboard(location_str,0,location_str.length()); + LLClipboard::instance().copyToClipboard(location_str,0,location_str.length()); +// [RLVa:KB] - Checked: 2012-02-08 (RLVa-1.4.5) | Added: RLVa-1.4.5 + } +// [/RLVa:KB] } } void LLPanelTopInfoBar::onInfoButtonClicked() { +// [RLVa:KB] - Checked: 2012-02-08 (RLVa-1.4.5) | Added: RLVa-1.4.5 + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) + return; +// [/RLVa:KB] + LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "agent")); } diff --git a/indra/newview/llpaneltopinfobar.h b/indra/newview/llpaneltopinfobar.h index f37bd9c048823990ffab34a7c02823ff958d5ca9..b6d2cd94df768540043cf118621e6a1e50063e9d 100644 --- a/indra/newview/llpaneltopinfobar.h +++ b/indra/newview/llpaneltopinfobar.h @@ -61,6 +61,12 @@ class LLPanelTopInfoBar : public LLPanel, public LLSingleton<LLPanelTopInfoBar>, boost::signals2::connection setResizeCallback( const resize_signal_t::slot_type& cb ); +// [RLVa:KB] - Checked: 2014-03-23 (RLVa-1.4.10) + /** + * Shorthand to call updateParcelInfoText() and updateParcelIcons(). + */ + void update(); +// [/RLV:KB] private: class LLParcelChangeObserver; @@ -110,10 +116,10 @@ class LLPanelTopInfoBar : public LLPanel, public LLSingleton<LLPanelTopInfoBar>, */ void onNavBarShowParcelPropertiesCtrlChanged(); - /** - * Shorthand to call updateParcelInfoText() and updateParcelIcons(). - */ - void update(); +// /** +// * Shorthand to call updateParcelInfoText() and updateParcelIcons(). +// */ +// void update(); /** * Updates parcel info text (mParcelInfoText). diff --git a/indra/newview/llpanelwearing.cpp b/indra/newview/llpanelwearing.cpp index d0353259a52f860da324a1383e7269cb3c115f9c..c7587b71635bfb5107af3a9b7984c01623a0bd26 100644 --- a/indra/newview/llpanelwearing.cpp +++ b/indra/newview/llpanelwearing.cpp @@ -40,6 +40,10 @@ #include "llwearableitemslist.h" #include "llsdserialize.h" #include "llclipboard.h" +// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7) +#include "rlvcommon.h" +#include "rlvhandler.h" +// [/RLVa:KB] // Context menu and Gear menu helper. static void edit_outfit() @@ -111,6 +115,9 @@ class LLWearingContextMenu : public LLListContextMenu bool bp_selected = false; // true if body parts selected bool clothes_selected = false; bool attachments_selected = false; +// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7) + S32 rlv_locked_count = 0; +// [/RLVa:KB] // See what types of wearables are selected. for (uuid_vec_t::const_iterator it = mUUIDs.begin(); it != mUUIDs.end(); ++it) @@ -136,14 +143,27 @@ class LLWearingContextMenu : public LLListContextMenu { attachments_selected = true; } +// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7) + if ( (rlv_handler_t::isEnabled()) && (!rlvPredCanRemoveItem(item)) ) + { + rlv_locked_count++; + } +// [/RLVa:KB] } // Enable/disable some menu items depending on the selection. +// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7) + bool rlv_blocked = (mUUIDs.size() == rlv_locked_count); +// [/RLVa:KB] bool allow_detach = !bp_selected && !clothes_selected && attachments_selected; bool allow_take_off = !bp_selected && clothes_selected && !attachments_selected; menu->setItemVisible("take_off", allow_take_off); menu->setItemVisible("detach", allow_detach); +// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7) + menu->setItemEnabled("take_off", !rlv_blocked); + menu->setItemEnabled("detach", !rlv_blocked); +// [/RLVa:KB] menu->setItemVisible("edit_outfit_separator", allow_take_off || allow_detach); menu->setItemVisible("show_original", mUUIDs.size() == 1); } diff --git a/indra/newview/llparcelselection.h b/indra/newview/llparcelselection.h index 1cbdfc6f74bd5eeeedfccdeb5845b240c6ab9a19..b2d64b2d6c4c54266091686eb9f1f29dad97f99c 100644 --- a/indra/newview/llparcelselection.h +++ b/indra/newview/llparcelselection.h @@ -45,7 +45,10 @@ class LLParcelSelection : public LLRefCount // this can return NULL at any time, as parcel selection // might have been invalidated. - LLParcel* getParcel() { return mParcel; } +// [RLVa:KB] - Checked: 2012-02-09 (RLVa-1.4.5) | Modified: RLVa-1.4.5 + LLParcel* getParcel() const { return mParcel; } +// [/RLVa:KB] +// LLParcel* getParcel() { return mParcel; } // Return the number of grid units that are owned by you within // the selection (computed by server). diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp index 5b1b3565978b09ba7ad0b3ae0fadb8de209f6204..1e720c308ab6ce057625f95a131ec0aadb59db0b 100644 --- a/indra/newview/llpreviewscript.cpp +++ b/indra/newview/llpreviewscript.cpp @@ -87,6 +87,10 @@ #include "llexperiencecache.h" #include "llfloaterexperienceprofile.h" #include "llviewerassetupload.h" +// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a) +#include "rlvhandler.h" +#include "rlvlocks.h" +// [/RLVa:KB] const std::string HELLO_LSL = "default\n" @@ -2021,6 +2025,14 @@ void LLLiveLSLEditor::onRunningCheckboxClicked( LLUICtrl*, void* userdata ) //self->mRunningCheckbox->get(); 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())) ) + { + RlvUtil::notifyBlockedGeneric(); + return; + } +// [/RLVa:KB] + LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_SetScriptRunning); msg->nextBlockFast(_PREHASH_AgentData); @@ -2046,6 +2058,14 @@ void LLLiveLSLEditor::onReset(void *userdata) LLViewerObject* object = gObjectList.findObject( self->mObjectUUID ); 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())) ) + { + RlvUtil::notifyBlockedGeneric(); + return; + } +// [/RLVa:KB] + LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_ScriptReset); msg->nextBlockFast(_PREHASH_AgentData); @@ -2172,6 +2192,14 @@ void LLLiveLSLEditor::saveIfNeeded(bool sync /*= true*/) return; } +// [RLVa:KB] - Checked: 2010-11-25 (RLVa-1.2.2b) | Modified: RLVa-1.2.2b + if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.isLockedAttachment(object->getRootEdit())) ) + { + RlvUtil::notifyBlockedGeneric(); + return; + } +// [/RLVa:KB] + // get the latest info about it. We used to be losing the script // name on save, because the viewer object version of the item, // and the editor version would get out of synch. Here's a good diff --git a/indra/newview/llscreenchannel.cpp b/indra/newview/llscreenchannel.cpp index ba2c37ce7cf376dd9a6e4fa35090d2cb960f1514..6448343f3e598c9bd9c772d4100fbabcd12178bc 100644 --- a/indra/newview/llscreenchannel.cpp +++ b/indra/newview/llscreenchannel.cpp @@ -1120,8 +1120,17 @@ LLToast* LLScreenChannel::getToastByNotificationID(LLUUID id) std::vector<ToastElem>::iterator it = find(mStoredToastList.begin(), mStoredToastList.end(), id); +// if (it == mStoredToastList.end()) +// return NULL; +// [SL:KB] - Patch: UI-Notifications | Checked: 2011-04-11 (Catznip-2.5.0a) | Modified: Catznip-2.5.0a if (it == mStoredToastList.end()) - return NULL; + { + // If we can't find it among the stored toasts then widen it to "all visible toasts" + it = find(mToastList.begin(), mToastList.end(), id); + if (it == mToastList.end()) + return NULL; + } +// [/SL:KB] return it->getToast(); } diff --git a/indra/newview/llscriptruntimeperms.h b/indra/newview/llscriptruntimeperms.h index 51f57afdc91a2f94a0df3dea63d09f6a51ccb3e6..9318cbb1d66e706a70913204d9eecbd8d5971d51 100644 --- a/indra/newview/llscriptruntimeperms.h +++ b/indra/newview/llscriptruntimeperms.h @@ -39,7 +39,14 @@ typedef struct _script_perm { const U32 NUM_SCRIPT_PERMISSIONS = 16; const S32 SCRIPT_PERMISSION_DEBIT = 0; +// [RLVa:KB] - Checked: RLVa-2.0.0 +const S32 SCRIPT_PERMISSION_TAKE_CONTROLS = 1; +// [/RLVa:KB] const S32 SCRIPT_PERMISSION_TRIGGER_ANIMATION = 3; +// [RLVa:KB] - Checked: RLVa-2.0.0 +const S32 SCRIPT_PERMISSION_ATTACH = 4; +const S32 SCRIPT_PERMISSION_TELEPORT = 11; +// [/RLVa:KB] const S32 SCRIPT_PERMISSION_OVERRIDE_ANIMATIONS = 14; static const boost::array<script_perm_t, NUM_SCRIPT_PERMISSIONS> SCRIPT_PERMISSIONS = {{ diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 15b24c3ace4ac3aebeb21a279bc8ebcd6a02c89b..00ddbc9c43115c523efd3c4623e0cb6944e07e19 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -93,6 +93,11 @@ #include "pipeline.h" #include "llviewershadermgr.h" #include "llpanelface.h" +// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a) +#include "rlvactions.h" +#include "rlvhandler.h" +#include "rlvhelper.h" +// [/RLVa:KB] #include "llglheaders.h" LLViewerObject* getSelectedParentObject(LLViewerObject *object) ; @@ -679,6 +684,16 @@ bool LLSelectMgr::enableLinkObjects() new_value = LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func, firstonly); } } +// [RLVa:KB] - Checked: 2011-03-19 (RLVa-1.3.0f) | Modified: RLVa-0.2.0g + if ( (new_value) && ((rlv_handler_t::isEnabled()) && (!RlvActions::canStand())) ) + { + // Allow only if the avie isn't sitting on any of the selected objects + LLObjectSelectionHandle hSel = LLSelectMgr::getInstance()->getSelection(); + RlvSelectIsSittingOn f(gAgentAvatarp); + if (hSel->getFirstRootNode(&f, TRUE) != NULL) + new_value = false; + } +// [/RLVa:KB] return new_value; } @@ -691,7 +706,16 @@ bool LLSelectMgr::enableUnlinkObjects() first_editable_object && !first_editable_object->isAttachment() && !first_editable_object->isPermanentEnforced() && ((root_object == NULL) || !root_object->isPermanentEnforced()); - +// [RLVa:KB] - Checked: 2011-03-19 (RLVa-1.3.0f) | Modified: RLVa-0.2.0g + if ( (new_value) && ((rlv_handler_t::isEnabled()) && (!RlvActions::canStand())) ) + { + // Allow only if the avie isn't sitting on any of the selected objects + LLObjectSelectionHandle hSel = LLSelectMgr::getInstance()->getSelection(); + RlvSelectIsSittingOn f(gAgentAvatarp); + if (hSel->getFirstRootNode(&f, TRUE) != NULL) + new_value = false; + } +// [/RLVa:KB] return new_value; } @@ -3500,6 +3524,16 @@ BOOL LLSelectMgr::selectGetPermissions(LLPermissions& result_perm) void LLSelectMgr::selectDelete() { +// [RLVa:KB] - Checked: 2010-03-23 (RLVa-1.2.0e) | Added: RLVa-1.2.0a + if ( (rlv_handler_t::isEnabled()) && (!rlvCanDeleteOrReturn()) ) + { + make_ui_sound("UISndInvalidOp"); + if (!gFloaterTools->getVisible()) + deselectAll(); + return; + } +// [/RLVa:KB] + S32 deleteable_count = 0; BOOL locked_but_deleteable_object = FALSE; @@ -3812,7 +3846,10 @@ struct LLDuplicateData void LLSelectMgr::selectDuplicate(const LLVector3& offset, BOOL select_copy) { - if (mSelectedObjects->isAttachment()) +// if (mSelectedObjects->isAttachment()) +// [RLVa:KB] - Checked: 2010-03-24 (RLVa-1.2.0e) | Added: RLVa-1.2.0a + if ( (mSelectedObjects->isAttachment()) || ((rlv_handler_t::isEnabled()) && (!rlvCanDeleteOrReturn())) ) +// [/RLVa:KB] { //RN: do not duplicate attachments make_ui_sound("UISndInvalidOp"); @@ -4269,11 +4306,36 @@ void LLSelectMgr::convertTransient() void LLSelectMgr::deselectAllIfTooFar() { +// [RLVa:KB] - Checked: RLVa-1.3.0 + if ( (!mSelectedObjects->isEmpty()) && ((gRlvHandler.hasBehaviour(RLV_BHVR_EDIT)) || (gRlvHandler.hasBehaviour(RLV_BHVR_EDITOBJ))) ) + { + struct NotTransientOrFocusedMediaOrEditable : public LLSelectedNodeFunctor + { + bool apply(LLSelectNode* pNode) + { + const LLViewerObject* pObj = pNode->getObject(); + return (!pNode->isTransient()) && (pObj) && (!RlvActions::canEdit(pObj)) && (pObj->getID() != LLViewerMediaFocus::getInstance()->getFocusedObjectID()); + } + } f; + if (mSelectedObjects->getFirstRootNode(&f, TRUE)) + deselectAll(); + } +// [/RLVa:KB] + if (mSelectedObjects->isEmpty() || mSelectedObjects->mSelectType == SELECT_TYPE_HUD) { return; } +// [RLVa:KB] - Checked: RLVa-1.2.0 + // [Fall-back code] Don't allow an active selection (except for HUD attachments - see above) when @interact restricted + if (gRlvHandler.hasBehaviour(RLV_BHVR_INTERACT)) + { + deselectAll(); + return; + } +// [/RLVa:KB] + // HACK: Don't deselect when we're navigating to rate an object's // owner or creator. JC if (gMenuObject->getVisible()) @@ -4282,13 +4344,22 @@ void LLSelectMgr::deselectAllIfTooFar() } LLVector3d selectionCenter = getSelectionCenterGlobal(); - if (gSavedSettings.getBOOL("LimitSelectDistance") +// if (gSavedSettings.getBOOL("LimitSelectDistance") +// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Modified: RLVa-0.2.0f + static RlvCachedBehaviourModifier<float> s_nFartouchDist(RLV_MODIFIER_FARTOUCHDIST); + + BOOL fRlvFartouch = gRlvHandler.hasBehaviour(RLV_BHVR_FARTOUCH) && gFloaterTools->getVisible(); + if ( (gSavedSettings.getBOOL("LimitSelectDistance") || (fRlvFartouch) ) +// [/RLVa:KB] && (!mSelectedObjects->getPrimaryObject() || !mSelectedObjects->getPrimaryObject()->isAvatar()) && (mSelectedObjects->getPrimaryObject() != LLViewerMediaFocus::getInstance()->getFocusedObject()) && !mSelectedObjects->isAttachment() && !selectionCenter.isExactlyZero()) { - F32 deselect_dist = gSavedSettings.getF32("MaxSelectDistance"); +// F32 deselect_dist = gSavedSettings.getF32("MaxSelectDistance"); +// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Modified: RLVa-0.2.0f + F32 deselect_dist = (!fRlvFartouch) ? gSavedSettings.getF32("MaxSelectDistance") : s_nFartouchDist; +// [/RLVa:KB] F32 deselect_dist_sq = deselect_dist * deselect_dist; LLVector3d select_delta = gAgent.getPositionGlobal() - selectionCenter; @@ -6797,7 +6868,10 @@ BOOL LLSelectMgr::canDoDelete() const can_delete = true; } } - +// [RLVa:KB] - Checked: 2010-03-23 (RLVa-1.2.0e) | Added: RLVa-1.2.0a + can_delete &= (!rlv_handler_t::isEnabled()) || (rlvCanDeleteOrReturn()); +// [/RLVa:KB] + return can_delete; } @@ -6829,7 +6903,12 @@ void LLSelectMgr::deselect() //----------------------------------------------------------------------------- BOOL LLSelectMgr::canDuplicate() const { - return const_cast<LLSelectMgr*>(this)->mSelectedObjects->getFirstCopyableObject() != NULL; // HACK: casting away constness - MG +// return const_cast<LLSelectMgr*>(this)->mSelectedObjects->getFirstCopyableObject() != NULL; // HACK: casting away constness - MG +// [RLVa:KB] - Checked: 2010-03-24 (RLVa-1.2.0e) | Added: RLVa-1.2.0a + return + (const_cast<LLSelectMgr*>(this)->mSelectedObjects->getFirstCopyableObject() != NULL) && + ( (!rlv_handler_t::isEnabled()) || (rlvCanDeleteOrReturn()) ); +// [/RLVa:KB] } //----------------------------------------------------------------------------- // duplicate() diff --git a/indra/newview/llsidepanelappearance.cpp b/indra/newview/llsidepanelappearance.cpp index 86135ee6e83a0df031548f01b87b12e6dd7b0ece..7058cd4be85aaf7cad75e596562cdb5dd0a37583 100644 --- a/indra/newview/llsidepanelappearance.cpp +++ b/indra/newview/llsidepanelappearance.cpp @@ -544,3 +544,15 @@ void LLSidepanelAppearance::updateScrollingPanelList() mEditWearable->updateScrollingPanelList(); } } + +// [RLVa:KB] - Checked: 2010-09-16 (RLVa-1.2.1a) | Added: RLVa-1.2.1a +bool LLSidepanelAppearance::isOutfitEditPanelVisible() const +{ + return (mOutfitEdit) && (mOutfitEdit->getVisible()); +} + +bool LLSidepanelAppearance::isWearableEditPanelVisible() const +{ + return (mEditWearable) && (mEditWearable->getVisible()); +} +// [/RLVa:KB] diff --git a/indra/newview/llsidepanelappearance.h b/indra/newview/llsidepanelappearance.h index 440fce07bbc281fdc70802b1efa582278d69a9f8..703b593a66088b392354d08a81b46aa6d14cb5ac 100644 --- a/indra/newview/llsidepanelappearance.h +++ b/indra/newview/llsidepanelappearance.h @@ -66,6 +66,14 @@ class LLSidepanelAppearance : public LLPanel void updateToVisibility( const LLSD& new_visibility ); LLPanelEditWearable* getWearable(){ return mEditWearable; } +// [RLVa:KB] - Checked: 2010-09-16 (RLVa-1.2.1a) | Added: RLVa-1.2.1a + bool isOutfitEditPanelVisible() const; + bool isWearableEditPanelVisible() const; + + LLPanelOutfitEdit* getOutfitEditPanel() { return mOutfitEdit; } + LLPanelEditWearable* getWearableEditPanel() { return mEditWearable; } +// [/RLVa:KB] + private: void onFilterEdit(const std::string& search_string); void onVisibilityChanged ( const LLSD& new_visibility ); diff --git a/indra/newview/llsidepaneliteminfo.cpp b/indra/newview/llsidepaneliteminfo.cpp index 12cbff888d39cb7c1c916059b07342ddf72dbea1..c43fef98cc7a315fcfe3853bd6e4f12dbdff222d 100644 --- a/indra/newview/llsidepaneliteminfo.cpp +++ b/indra/newview/llsidepaneliteminfo.cpp @@ -46,7 +46,10 @@ #include "llviewerobjectlist.h" #include "llexperiencecache.h" #include "lltrans.h" - +// [RLVa:KB] - Checked: RLVa-2.0.1 +#include "rlvactions.h" +#include "rlvcommon.h" +// [/RLVa:KB] //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLItemPropertiesObserver @@ -356,9 +359,20 @@ void LLSidepanelItemInfo::refreshFromItem(LLViewerInventoryItem* item) if (item->getCreatorUUID().notNull()) { LLUUID creator_id = item->getCreatorUUID(); - std::string name = - LLSLURL("agent", creator_id, "completename").getSLURLString(); - getChildView("BtnCreator")->setEnabled(TRUE); +// std::string name = +// LLSLURL("agent", creator_id, "completename").getSLURLString(); +// getChildView("BtnCreator")->setEnabled(TRUE); +// [RLVa:KB] - Checked: RLVa-2.0.1 + // If the object creator matches the object owner we need to anonymize the creator field as well + bool fRlvCanShowCreator = true; + if ( (RlvActions::isRlvEnabled()) && (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, creator_id)) && + ( ((perm.isOwned()) && (!perm.isGroupOwned()) && (perm.getOwner() == creator_id) ) || (RlvUtil::isNearbyAgent(item->getCreatorUUID())) ) ) + { + fRlvCanShowCreator = false; + } + std::string name = LLSLURL("agent", creator_id, (fRlvCanShowCreator) ? "completename" : "rlvanonym").getSLURLString(); + getChildView("BtnCreator")->setEnabled(fRlvCanShowCreator); +// [/RLVa:KB] getChildView("LabelCreatorTitle")->setEnabled(TRUE); getChildView("LabelCreatorName")->setEnabled(FALSE); getChild<LLUICtrl>("LabelCreatorName")->setValue(name); @@ -376,6 +390,9 @@ void LLSidepanelItemInfo::refreshFromItem(LLViewerInventoryItem* item) //////////////// if(perm.isOwned()) { +// [RLVa:KB] - Checked: RVLa-2.0.1 + bool fRlvCanShowOwner = true; +// [/RLVa:KB] std::string name; if (perm.isGroupOwned()) { @@ -384,9 +401,16 @@ void LLSidepanelItemInfo::refreshFromItem(LLViewerInventoryItem* item) else { LLUUID owner_id = perm.getOwner(); - name = LLSLURL("agent", owner_id, "completename").getSLURLString(); +// name = LLSLURL("agent", owner_id, "completename").getSLURLString(); +// [RLVa:KB] - Checked: RLVa-2.0.1 + fRlvCanShowOwner = RlvActions::canShowName(RlvActions::SNC_DEFAULT, owner_id); + name = LLSLURL("agent", owner_id, (fRlvCanShowOwner) ? "completename" : "rlvanonym").getSLURLString(); +// [/RLVa:KB] } - getChildView("BtnOwner")->setEnabled(TRUE); +// getChildView("BtnOwner")->setEnabled(TRUE); +// [RLVa:KB] - Checked: RLVa-2.0.1 + getChildView("BtnOwner")->setEnabled(fRlvCanShowOwner); +// [/RLVa:KB] getChildView("LabelOwnerTitle")->setEnabled(TRUE); getChildView("LabelOwnerName")->setEnabled(FALSE); getChild<LLUICtrl>("LabelOwnerName")->setValue(name); @@ -743,6 +767,17 @@ void LLSidepanelItemInfo::onClickCreator() if(!item) return; if(!item->getCreatorUUID().isNull()) { +// [RLVa:KB] - Checked: RLVa-1.2.1 + const LLUUID& idCreator = item->getCreatorUUID(); + if ( (RlvActions::isRlvEnabled()) && (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, idCreator)) ) + { + const LLPermissions& perm = item->getPermissions(); + if ( ((perm.isOwned()) && (!perm.isGroupOwned()) && (perm.getOwner() == idCreator) ) || (RlvUtil::isNearbyAgent(idCreator)) ) + { + return; + } + } +// [/RLVa:KB] LLAvatarActions::showProfile(item->getCreatorUUID()); } } @@ -758,6 +793,10 @@ void LLSidepanelItemInfo::onClickOwner() } else { +// [RLVa:KB] - Checked: RLVa-1.0.0 + if ( (RlvActions::isRlvEnabled()) && (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, item->getPermissions().getOwner())) ) + return; +// [/RLVa:KB] LLAvatarActions::showProfile(item->getPermissions().getOwner()); } } diff --git a/indra/newview/llsidepaneltaskinfo.cpp b/indra/newview/llsidepaneltaskinfo.cpp index 403ca7bcbf0a2adf39a30d72de180efbdf04174b..11ab8c9988729aaff575f1346c2052ca333d63a1 100644 --- a/indra/newview/llsidepaneltaskinfo.cpp +++ b/indra/newview/llsidepaneltaskinfo.cpp @@ -64,6 +64,10 @@ #include "lltextbase.h" #include "llstring.h" #include "lltrans.h" +// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.2a) +#include "llslurl.h" +#include "rlvhandler.h" +// [/RLVa:KB] ///---------------------------------------------------------------------------- /// Class llsidepaneltaskinfo @@ -370,21 +374,28 @@ void LLSidepanelTaskInfo::refresh() // Update creator text field getChildView("Creator:")->setEnabled(TRUE); +// [RLVa:KB] - Checked: 2010-11-01 (RLVa-1.2.2a) | Modified: RLVa-1.2.2a + BOOL creators_identical = FALSE; +// [/RLVa:KB] std::string creator_name; LLUUID creator_id; - LLSelectMgr::getInstance()->selectGetCreator(creator_id, creator_name); - - if(creator_id != mCreatorID ) - { - mDACreatorName->setValue(creator_name); - mCreatorID = creator_id; - } - if(mDACreatorName->getValue().asString() == LLStringUtil::null) - { - mDACreatorName->setValue(creator_name); - } - mDACreatorName->setEnabled(TRUE); +// [RLVa:KB] - Checked: 2010-11-01 (RLVa-1.2.2a) | Modified: RLVa-1.2.2a + creators_identical = LLSelectMgr::getInstance()->selectGetCreator(creator_id, creator_name); +// [/RLVa:KB] +// LLSelectMgr::getInstance()->selectGetCreator(creator_id, creator_name); + +// if(creator_id != mCreatorID ) +// { +// mDACreatorName->setValue(creator_name); +// mCreatorID = creator_id; +// } +// if(mDACreatorName->getValue().asString() == LLStringUtil::null) +// { +// mDACreatorName->setValue(creator_name); +// } +// mDACreatorName->setEnabled(TRUE); +// [RLVa:KB] - Moved further down to avoid an annoying flicker when the text is set twice in a row // Update owner text field getChildView("Owner:")->setEnabled(TRUE); @@ -414,17 +425,41 @@ void LLSidepanelTaskInfo::refresh() } } - if(owner_id.isNull() || (owner_id != mOwnerID)) +// if(owner_id.isNull() || (owner_id != mOwnerID)) +// { +// mDAOwnerName->setValue(owner_name); +// mOwnerID = owner_id; +// } +// if(mDAOwnerName->getValue().asString() == LLStringUtil::null) +// { +// mDAOwnerName->setValue(owner_name); +// } +// getChildView("Owner Name")->setEnabled(TRUE); + +// [RLVa:KB] - Checked: 2010-11-01 (RLVa-1.2.2a) | Modified: RLVa-1.2.2a + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) { - mDAOwnerName->setValue(owner_name); - mOwnerID = owner_id; + // Only anonymize the creator if all of the selection was created by the same avie who's also the owner or they're a nearby avie + if ( (creators_identical) && (mCreatorID != gAgent.getID()) && ((mCreatorID == mOwnerID) || (RlvUtil::isNearbyAgent(mCreatorID))) ) + creator_name = LLSLURL("agent", mCreatorID, "rlvanonym").getSLURLString(); + + // Only anonymize the owner name if all of the selection is owned by the same avie and isn't group owned + if ( (owners_identical) && (!LLSelectMgr::getInstance()->selectIsGroupOwned()) && (mOwnerID != gAgent.getID()) ) + owner_name = LLSLURL("agent", mOwnerID, "rlvanonym").getSLURLString(); } - if(mDAOwnerName->getValue().asString() == LLStringUtil::null) + + if(mDACreatorName->getValue().asString() == LLStringUtil::null) { - mDAOwnerName->setValue(owner_name); + mDACreatorName->setValue(creator_name); } + mDACreatorName->setEnabled(TRUE); - getChildView("Owner Name")->setEnabled(TRUE); + if(mDAOwnerName->getValue().asString() == LLStringUtil::null) + { + mDAOwnerName->setValue(owner_name); + } + mDAOwnerName->setEnabled(TRUE); +// [/RLVa:KB] // update group text field getChildView("Group:")->setEnabled(TRUE); diff --git a/indra/newview/llslurl.cpp b/indra/newview/llslurl.cpp index a8e012bfa1881eafb5eb7b8391bf1c97d7096348..c7caa8f0433e33c626cb1f16a7590e1239f92ddb 100644 --- a/indra/newview/llslurl.cpp +++ b/indra/newview/llslurl.cpp @@ -34,6 +34,9 @@ #include "llviewernetwork.h" #include "llfiltersd2xmlrpc.h" #include "curl/curl.h" +// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d) +#include "rlvhandler.h" +// [/RLVa:KB] const char* LLSLURL::SLURL_HTTP_SCHEME = "http"; const char* LLSLURL::SLURL_HTTPS_SCHEME = "https"; const char* LLSLURL::SLURL_SECONDLIFE_SCHEME = "secondlife"; @@ -389,8 +392,13 @@ std::string LLSLURL::getSLURLString() const S32 x = ll_round( (F32)mPosition[VX] ); S32 y = ll_round( (F32)mPosition[VY] ); S32 z = ll_round( (F32)mPosition[VZ] ); - return LLGridManager::getInstance()->getSLURLBase(mGrid) + - LLURI::escape(mRegion) + llformat("/%d/%d/%d",x,y,z); +// return LLGridManager::getInstance()->getSLURLBase(mGrid) + +// LLURI::escape(mRegion) + llformat("/%d/%d/%d",x,y,z); +// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d + return LLGridManager::getInstance()->getSLURLBase(mGrid) + + ( ((!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) || (!RlvUtil::isNearbyRegion(mRegion))) + ? (LLURI::escape(mRegion) + llformat("/%d/%d/%d",x,y,z)) : RlvStrings::getString(RLV_STRING_HIDDEN_REGION) ); +// [/RLVa:KB] } case APP: { diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index a2c8e7772e5e1480e4e4f32407f58a81cae21a76..178118e4bf699ff11e41d8d3558d3ba32942bd6e 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -188,6 +188,10 @@ #include "llvoicechannel.h" #include "llpathfindingmanager.h" +// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0a) +#include "rlvhandler.h" +// [/RLVa:KB] + #include "lllogin.h" #include "llevents.h" #include "llstartuplistener.h" @@ -372,6 +376,13 @@ bool idle_startup() std::string lastGPU = gSavedSettings.getString("LastGPUString"); std::string thisGPU = LLFeatureManager::getInstance()->getGPUString(); +// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0a) | Modified: RLVa-0.2.1d + if ( (gSavedSettings.controlExists(RLV_SETTING_MAIN)) && (gSavedSettings.getBOOL(RLV_SETTING_MAIN)) ) + { + rlv_handler_t::setEnabled(TRUE); + } +// [/RLVa:KB] + if (LLFeatureManager::getInstance()->isSafe()) { LLNotificationsUtil::add("DisplaySetToSafe"); @@ -957,6 +968,14 @@ bool idle_startup() // their last location, or some URL "-url //sim/x/y[/z]" // All accounts have both a home and a last location, and we don't support // more locations than that. Choose the appropriate one. JC +// [RLVa:KB] - Checked: 2010-04-01 (RLVa-1.2.0c) | Modified: RLVa-0.2.1d + if ( (rlv_handler_t::isEnabled()) && (RlvSettings::getLoginLastLocation()) ) + { + // Force login at the last location + LLStartUp::setStartSLURL(LLSLURL(LLSLURL::SIM_LOCATION_LAST)); + } +// [/RLVa:KB] + switch (LLStartUp::getStartSLURL().getType()) { case LLSLURL::LOCATION: @@ -1784,6 +1803,14 @@ bool idle_startup() LL_INFOS() << "Creating Inventory Views" << LL_ENDL; LLFloaterReg::getInstance("inventory"); display_startup(); + +// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0a) | Added: RLVa-1.1.0f + if (rlv_handler_t::isEnabled()) + { + // Regularly process a select subset of retained commands during logon + gIdleCallbacks.addFunction(RlvHandler::onIdleStartup, new LLTimer()); + } +// [/RLVa:KB] LLStartUp::setStartupState( STATE_MISC ); display_startup(); return FALSE; diff --git a/indra/newview/llstatusbar.cpp b/indra/newview/llstatusbar.cpp index 041eae4b3c9cd36af417dd1fe2a02581f667c9a2..cb85d84b3969d2390b5d0ae3cd0c1c7ceaa03d09 100644 --- a/indra/newview/llstatusbar.cpp +++ b/indra/newview/llstatusbar.cpp @@ -85,7 +85,6 @@ // system includes #include <iomanip> - // // Globals // diff --git a/indra/newview/llteleporthistory.cpp b/indra/newview/llteleporthistory.cpp index a20d69dd41c392e39589016e24d21e1dded23662..8a983e681efc00a0f4b0f9050f24f8c26b8f4fb2 100644 --- a/indra/newview/llteleporthistory.cpp +++ b/indra/newview/llteleporthistory.cpp @@ -39,6 +39,9 @@ #include "llviewerregion.h" #include "llworldmap.h" #include "llagentui.h" +// [RLVa:KB] - Checked: 2010-09-03 (RLVa-1.2.1b) +#include "rlvhandler.h" +// [/RLVa:KB] ////////////////////////////////////////////////////////////////////////////// // LLTeleportHistoryItem @@ -149,8 +152,16 @@ void LLTeleportHistory::updateCurrentLocation(const LLVector3d& new_pos) mItems.erase (mItems.begin() + mCurrentItem + 1, mItems.end()); // Append an empty item to the history and make it current. - mItems.push_back(LLTeleportHistoryItem("", LLVector3d())); - mCurrentItem++; +// mItems.push_back(LLTeleportHistoryItem("", LLVector3d())); +// mCurrentItem++; +// [RLVa:KB] - Checked: 2010-09-03 (RLVa-1.2.1b) | Added: RLVa-1.2.1b + // Only append a new item if the list is currently empty or if not @showloc=n restricted and the last entry wasn't zero'ed out + if ( (mItems.size() == 0) || ((!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) && (!mItems.back().mGlobalPos.isExactlyZero())) ) + { + mItems.push_back(LLTeleportHistoryItem("", LLVector3d())); + mCurrentItem++; + } +// [RLVa:KB] } // Update current history item. @@ -160,11 +171,23 @@ void LLTeleportHistory::updateCurrentLocation(const LLVector3d& new_pos) llassert(!"Invalid current teleport history item"); return; } - LLVector3 new_pos_local = gAgent.getPosAgentFromGlobal(new_pos); - mItems[mCurrentItem].mFullTitle = getCurrentLocationTitle(true, new_pos_local); - mItems[mCurrentItem].mTitle = getCurrentLocationTitle(false, new_pos_local); - mItems[mCurrentItem].mGlobalPos = new_pos; - mItems[mCurrentItem].mRegionID = gAgent.getRegion()->getRegionID(); + +// [RLVa:KB] - Checked: 2010-09-03 (RLVa-1.2.1b) | Added: RLVa-1.2.1b + if (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) + { +// [/RLVa:KB] + LLVector3 new_pos_local = gAgent.getPosAgentFromGlobal(new_pos); + mItems[mCurrentItem].mFullTitle = getCurrentLocationTitle(true, new_pos_local); + mItems[mCurrentItem].mTitle = getCurrentLocationTitle(false, new_pos_local); + mItems[mCurrentItem].mGlobalPos = new_pos; + mItems[mCurrentItem].mRegionID = gAgent.getRegion()->getRegionID(); +// [RLVa:KB] - Checked: 2010-09-03 (RLVa-1.2.1b) | Added: RLVa-1.2.1b + } + else + { + mItems[mCurrentItem] = LLTeleportHistoryItem(RlvStrings::getString(RLV_STRING_HIDDEN_PARCEL), LLVector3d::zero); + } +// [/RLVa:KB] } dump(); diff --git a/indra/newview/llteleporthistory.h b/indra/newview/llteleporthistory.h index e9c29c39bf3e945d91a57f4260d8ad705919f56d..401c340362b9a3092a6b3f94e6b3a6cc0c887721 100644 --- a/indra/newview/llteleporthistory.h +++ b/indra/newview/llteleporthistory.h @@ -234,6 +234,10 @@ class LLTeleportHistory: public LLSingleton<LLTeleportHistory> * Using this connection we get notified when a teleport fails. */ boost::signals2::connection mTeleportFailedConn; + +// [RLVa:KB] - Checked: 2010-09-03 (RLVa-1.2.1b) | Added: RLVa-1.2.1b + friend class RlvUIEnabler; +// [/RLVa:KB] }; #endif diff --git a/indra/newview/llteleporthistorystorage.cpp b/indra/newview/llteleporthistorystorage.cpp index 8a5704939a134f54c3ffda1aa2408f571a72c48f..593960fa6cc3a98e4a51156e9b3cea068ed9b2c7 100644 --- a/indra/newview/llteleporthistorystorage.cpp +++ b/indra/newview/llteleporthistorystorage.cpp @@ -33,6 +33,9 @@ #include "lldir.h" #include "llteleporthistory.h" #include "llagent.h" +// [RLVa:KB] - Checked: 2010-09-03 (RLVa-1.2.1b) +#include "rlvhandler.h" +// [/RLVa:KB] // Max offset for two global positions to consider them as equal const F64 MAX_GLOBAL_POS_OFFSET = 5.0f; @@ -92,6 +95,13 @@ void LLTeleportHistoryStorage::onTeleportHistoryChange() } const LLTeleportHistoryItem &item = th->getItems()[th->getCurrentItemIndex()]; +// [RLVa:KB] - Checked: 2010-09-03 (RLVa-1.2.1b) | Added: RLVa-1.2.1b + // Make sure we don't attempt to save zero'ed out teleport history items + if (item.mGlobalPos.isExactlyZero()) + { + return; + } +// [/RLVa:KB] addItem(item.mTitle, item.mGlobalPos); save(); @@ -116,6 +126,13 @@ bool LLTeleportHistoryStorage::compareByTitleAndGlobalPos(const LLTeleportHistor void LLTeleportHistoryStorage::addItem(const std::string title, const LLVector3d& global_pos, const LLDate& date) { +// [RLVa:KB] - Checked: 2010-09-03 (RLVa-1.2.1b) | Added: RLVa-1.2.1b + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) + { + return; + } +// [/RLVa:KB] + LLTeleportHistoryPersistentItem item(title, global_pos, date); slurl_list_t::iterator item_iter = std::find_if(mItems.begin(), mItems.end(), diff --git a/indra/newview/llteleporthistorystorage.h b/indra/newview/llteleporthistorystorage.h index cf4c85a9910106a91c9f69be4cfe62dea049cb0a..f0131ac897ce9939438262c6de97e15618e1bf2b 100644 --- a/indra/newview/llteleporthistorystorage.h +++ b/indra/newview/llteleporthistorystorage.h @@ -108,7 +108,11 @@ class LLTeleportHistoryStorage: public LLSingleton<LLTeleportHistoryStorage> */ void goToItem(S32 idx); -private: +//private: +// [RLVa:KB] - Checked: 2010-09-03 (RLVa-1.2.1b) | Added: RLVa-1.2.1b +protected: + friend class RlvUIEnabler; +// [/RLVa:KB] void load(); void dump() const; diff --git a/indra/newview/lltoastpanel.cpp b/indra/newview/lltoastpanel.cpp index e1b764a9438c541f142126bf9c2dd04fde1b0cab..8994d4cab90be71aa6eab38c8daf3afaa5a2b04f 100644 --- a/indra/newview/lltoastpanel.cpp +++ b/indra/newview/lltoastpanel.cpp @@ -49,7 +49,10 @@ LLToastPanel::~LLToastPanel() std::string LLToastPanel::getTitle() { // *TODO: create Title and localize it. If it will be required. - return mNotification->getMessage(); +// return mNotification->getMessage(); +// [SL:KB] - Patch: UI-Notifications | Checked: 2011-04-11 (Catznip-2.5.0a) | Added: Catznip-2.5.0a + return (mNotification->hasLabel()) ? mNotification->getLabel() : mNotification->getMessage(); +// [/SL:KB] } //virtual diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp index 3f9a1a089b4b9d936b1ba1a78258b85f0c678e32..376f51af806a3f04afd3015f2e00314d5f33a6fd 100644 --- a/indra/newview/lltooldraganddrop.cpp +++ b/indra/newview/lltooldraganddrop.cpp @@ -60,6 +60,10 @@ #include "llvoavatarself.h" #include "llworld.h" #include "llpanelface.h" +// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1) +#include "rlvhandler.h" +#include "rlvlocks.h" +// [/RLVa:KB] // syntactic sugar #define callMemberFunction(object,ptrToMember) ((object).*(ptrToMember)) @@ -1236,6 +1240,15 @@ void LLToolDragAndDrop::dropObject(LLViewerObject* raycast_target, return; } + +// [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 ( (rlv_handler_t::isEnabled()) && ((gRlvHandler.hasBehaviour(RLV_BHVR_REZ)) || (gRlvHandler.hasBehaviour(RLV_BHVR_INTERACT))) ) + { + return; + } +// [/RLVa:KB] + //LL_INFOS() << "Rezzing object" << LL_ENDL; make_ui_sound("UISndObjectRezIn"); LLViewerInventoryItem* item; @@ -1507,6 +1520,23 @@ EAcceptance LLToolDragAndDrop::willObjectAcceptInventory(LLViewerObject* obj, LL BOOL volume = (LL_PCODE_VOLUME == obj->getPCode()); BOOL attached = obj->isAttachment(); BOOL unrestricted = ((perm.getMaskBase() & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED) ? TRUE : FALSE; + +// [RLVa:KB] - Checked: 2010-03-31 (RLVa-1.2.0c) | Modified: RLVa-1.0.0c + if (rlv_handler_t::isEnabled()) + { + 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)) ) + { + if ( (isAgentAvatarValid()) && (gAgentAvatarp->isSitting()) && (gAgentAvatarp->getRoot() == pObjRoot) ) + return ACCEPT_NO_LOCKED; // ... or on a linkset the avie is sitting on under @unsit=n/@sittp=n + } + } +// [/RLVa:KB] + if(attached && !unrestricted) { return ACCEPT_NO_LOCKED; @@ -1725,6 +1755,13 @@ EAcceptance LLToolDragAndDrop::dad3dRezAttachmentFromInv( return ACCEPT_NO; } +// [RLVa:KB] - Checked: 2013-02-13 (RLVa-1.4.8) + bool fReplace = !(mask & MASK_CONTROL); + if ( (rlv_handler_t::isEnabled()) && (!rlvPredCanWearItem(item, (fReplace) ? RLV_WEAR_REPLACE : RLV_WEAR_ADD)) ) + { + return ACCEPT_NO_LOCKED; + } +// [/RLVa:KB] if( drop ) { @@ -1733,7 +1770,7 @@ EAcceptance LLToolDragAndDrop::dad3dRezAttachmentFromInv( // LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(rez_attachment_cb, _1, (LLViewerJointAttachment*)0)); // [SL:KB] - Patch: Appearance-DnDWear | Checked: 2010-09-28 (Catznip-2.2) // Make this behave consistent with dad3dWearItem - LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(rez_attachment_cb, _1, (LLViewerJointAttachment*)0, !(mask & MASK_CONTROL))); + LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(rez_attachment_cb, _1, (LLViewerJointAttachment*)0, fReplace)); // [/SL:KB] copy_inventory_item( gAgent.getID(), @@ -1759,6 +1796,14 @@ EAcceptance LLToolDragAndDrop::dad3dRezAttachmentFromInv( EAcceptance LLToolDragAndDrop::dad3dRezObjectOnLand( LLViewerObject* obj, S32 face, MASK mask, BOOL drop) { +// [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; + } +// [/RLVa:KB] + if (mSource == SOURCE_WORLD) { return dad3dRezFromObjectOnLand(obj, face, mask, drop); @@ -1821,6 +1866,18 @@ EAcceptance LLToolDragAndDrop::dad3dRezObjectOnLand( EAcceptance LLToolDragAndDrop::dad3dRezObjectOnObject( LLViewerObject* obj, S32 face, MASK mask, BOOL drop) { +// [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())) ) ) ) + { + return ACCEPT_NO_LOCKED; + } +// [/RLVa:KB] + // handle objects coming from object inventory if (mSource == SOURCE_WORLD) { @@ -2051,11 +2108,22 @@ EAcceptance LLToolDragAndDrop::dad3dWearItem( return ACCEPT_NO; } +// [RLVa:KB] - Checked: 2013-02-13 (RLVa-1.4.8) + bool fReplace = (!(mask & MASK_CONTROL)) || (LLAssetType::AT_BODYPART == item->getType()); // Body parts should always replace + if ( (rlv_handler_t::isEnabled()) && (!rlvPredCanWearItem(item, (fReplace) ? RLV_WEAR_REPLACE : RLV_WEAR_ADD)) ) + { + return ACCEPT_NO_LOCKED; + } +// [/RLVa:KB] + if( drop ) { // TODO: investigate wearables may not be loaded at this point EXT-8231 - LLAppearanceMgr::instance().wearItemOnAvatar(item->getUUID(),true, !(mask & MASK_CONTROL)); +// [RLVa:KB] - Checked: 2013-02-13 (RLVa-1.4.8) + LLAppearanceMgr::instance().wearItemOnAvatar(item->getUUID(), true, fReplace); +// [/RLVa:KB] +// LLAppearanceMgr::instance().wearItemOnAvatar(item->getUUID(),true, !(mask & MASK_CONTROL)); } return ACCEPT_YES_MULTI; } diff --git a/indra/newview/lltoolface.cpp b/indra/newview/lltoolface.cpp index a00ac10698a9798958d9d435e483c01463eef503..c1707bba30d75a90eb4e157b12b7ef41038e0ed1 100644 --- a/indra/newview/lltoolface.cpp +++ b/indra/newview/lltoolface.cpp @@ -39,6 +39,10 @@ #include "llviewerobject.h" #include "llviewerwindow.h" #include "llfloatertools.h" +// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) +#include "rlvactions.h" +#include "rlvhandler.h" +// [/RLVa:KB] // // Member functions @@ -90,6 +94,15 @@ void LLToolFace::pickCallback(const LLPickInfo& pick_info) return; } +// [RLVa:KB] - Checked: 2010-11-29 (RLVa-1.3.0c) | Modified: RLVa-1.3.0c + if ( (rlv_handler_t::isEnabled()) && + ( (!RlvActions::canEdit(hit_obj)) || + ((gRlvHandler.hasBehaviour(RLV_BHVR_FARTOUCH)) && (!gRlvHandler.canTouch(hit_obj, pick_info.mObjectOffset))) ) ) + { + return; + } +// [/RLVa:KB] + // ...clicked on a world object, try to pick the appropriate face if (pick_info.mKeyMask & MASK_SHIFT) diff --git a/indra/newview/lltoolgrab.cpp b/indra/newview/lltoolgrab.cpp index c0ca4d7a9a4737fa316e3622e3f5cbf577f124b6..ed71163cd8002d954b53063c97d58377faeee637 100644 --- a/indra/newview/lltoolgrab.cpp +++ b/indra/newview/lltoolgrab.cpp @@ -57,6 +57,9 @@ #include "llvoavatarself.h" #include "llworld.h" #include "llmenugl.h" +// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) +#include "rlvhandler.h" +// [/RLVa:KB] const S32 SLOP_DIST_SQ = 4; @@ -170,7 +173,11 @@ void LLToolGrab::pickCallback(const LLPickInfo& pick_info) } // if not over object, do nothing - if (!objectp) +// if (!objectp) +// [RLVa:KB] - Checked: 2010-03-11 (RLVa-1.2.0e) | Added: RLVa-1.1.0l + // Block initiating a drag operation on an object that can't be touched + if ( (!objectp) || ((rlv_handler_t::isEnabled()) && (!gRlvHandler.canTouch(objectp, pick_info.mObjectOffset))) ) +// [/RLVa:KB] { LLToolGrab::getInstance()->setMouseCapture(TRUE); LLToolGrab::getInstance()->mMode = GRAB_NOOBJECT; @@ -431,6 +438,22 @@ BOOL LLToolGrab::handleHover(S32 x, S32 y, MASK mask) return TRUE; } +// [RLVa:KB] - Checked: 2010-03-11 (RLVa-1.2.0e) | Modified: RLVa-1.1.0l + // Block dragging an object beyond touch range when @fartouch=n restricted + if ( (rlv_handler_t::isEnabled()) && (GRAB_INACTIVE != mMode) && (GRAB_NOOBJECT != mMode) && (hasMouseCapture()) && + (gRlvHandler.hasBehaviour(RLV_BHVR_FARTOUCH)) && (!gRlvHandler.canTouch(mGrabPick.getObject(), mGrabPick.mObjectOffset)) ) + { + if (gGrabTransientTool) + { + // Prevent the grab tool from popping up as soon as we kill the drag operation + gBasicToolset->selectTool(gGrabTransientTool); + gGrabTransientTool = NULL; + } + setMouseCapture(FALSE); + return TRUE; + } +// [/RLVa:KB] + // Do the right hover based on mode switch( mMode ) { diff --git a/indra/newview/lltoolgun.cpp b/indra/newview/lltoolgun.cpp index 6c9155be851675281d6fccc722c0cd2d25bc8571..3d72976c96f9780ac6b3984443ba440c19120148 100644 --- a/indra/newview/lltoolgun.cpp +++ b/indra/newview/lltoolgun.cpp @@ -39,6 +39,9 @@ #include "llui.h" #include "llviewertexturelist.h" #include "llviewercamera.h" +// [RLVa:KB] - Checked: 2014-02-24 (RLVa-1.4.10) +#include "llfocusmgr.h" +// [/RLVa:KB] #include "llhudmanager.h" #include "lltoolmgr.h" #include "lltoolgrab.h" @@ -54,10 +57,17 @@ LLToolGun::LLToolGun( LLToolComposite* composite ) void LLToolGun::handleSelect() { - gViewerWindow->hideCursor(); - gViewerWindow->moveCursorToCenter(); - gViewerWindow->getWindow()->setMouseClipping(TRUE); - mIsSelected = TRUE; +// [RLVa:KB] - Checked: 2014-02-24 (RLVa-1.4.10) + if (gFocusMgr.getAppHasFocus()) + { +// [/RLVa:KB] + gViewerWindow->hideCursor(); + gViewerWindow->moveCursorToCenter(); + gViewerWindow->getWindow()->setMouseClipping(TRUE); + mIsSelected = TRUE; +// [RLVa:KB] - Checked: 2014-02-24 (RLVa-1.4.10) + } +// [/RLVa:KB] } void LLToolGun::handleDeselect() diff --git a/indra/newview/lltoolmgr.cpp b/indra/newview/lltoolmgr.cpp index b0e3b5bf898b2944c8a0a575c16b397596feea13..2dc4cc086fae4f3e3a2d47b68702aba1222f8658 100644 --- a/indra/newview/lltoolmgr.cpp +++ b/indra/newview/lltoolmgr.cpp @@ -57,7 +57,10 @@ #include "llviewerjoystick.h" #include "llviewermenu.h" #include "llviewerparcelmgr.h" - +// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) +#include "rlvhandler.h" +#include "rlvui.h" +// [/RLVa:KB] // Used when app not active to avoid processing hover. LLTool* gToolNull = NULL; @@ -82,9 +85,14 @@ LLToolMgr::LLToolMgr() { // Not a panel, register these callbacks globally. LLUICtrl::EnableCallbackRegistry::currentRegistrar().add("Build.Active", boost::bind(&LLToolMgr::inEdit, this)); - LLUICtrl::EnableCallbackRegistry::currentRegistrar().add("Build.Enabled", boost::bind(&LLToolMgr::canEdit, this)); - LLUICtrl::EnableCallbackRegistry::currentRegistrar().add("Build.EnabledOrActive", boost::bind(&LLToolMgr::buildEnabledOrActive, this)); - LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Build.Toggle", boost::bind(&LLToolMgr::toggleBuildMode, this, _2)); +// LLUICtrl::EnableCallbackRegistry::currentRegistrar().add("Build.Enabled", boost::bind(&LLToolMgr::canEdit, this)); +// LLUICtrl::EnableCallbackRegistry::currentRegistrar().add("Build.EnabledOrActive", boost::bind(&LLToolMgr::buildEnabledOrActive, this)); +// LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Build.Toggle", boost::bind(&LLToolMgr::toggleBuildMode, this, _2)); +// [RLVa:KB] - Checked: 2010-09-11 (RLVa-1.2.1d) | Added: RLVa-1.2.1d + LLUICtrl::EnableCallbackRegistry::currentRegistrar().add("Build.Enabled", boost::bind(&RlvUIEnabler::isBuildEnabled)); + LLUICtrl::EnableCallbackRegistry::currentRegistrar().add("Build.EnabledOrActive", boost::bind(&RlvUIEnabler::isBuildEnabledOrActive)); + LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Build.Toggle", boost::bind(&LLToolMgr::toggleBuildMode, this)); +// [/RLVa:KB] LLUICtrl::EnableCallbackRegistry::currentRegistrar().add("Marketplace.Enabled", boost::bind(&LLToolMgr::canAccessMarketplace, this)); LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Marketplace.Toggle", boost::bind(&LLToolMgr::toggleMarketplace, this, _2)); @@ -265,20 +273,23 @@ bool LLToolMgr::canEdit() return LLViewerParcelMgr::getInstance()->allowAgentBuild(); } -bool LLToolMgr::buildEnabledOrActive() -{ - return inEdit() || canEdit(); -} +//bool LLToolMgr::buildEnabledOrActive() +//{ +// return inEdit() || canEdit(); +//} -void LLToolMgr::toggleBuildMode(const LLSD& sdname) +//void LLToolMgr::toggleBuildMode(const LLSD& sdname) +// [RLVa:KB] - Checked: 2012-04-26 (RLVa-1.4.6) | Added: RLVa-1.4.6 +void LLToolMgr::toggleBuildMode() +// [/RLVa:KB] { - const std::string& param = sdname.asString(); - - LLFloaterReg::toggleInstanceOrBringToFront("build"); - if (param == "build" && !canEdit()) - { - return; - } +// const std::string& param = sdname.asString(); +// +// LLFloaterReg::toggleInstanceOrBringToFront("build"); +// if (param == "build" && !canEdit()) +// { +// return; +// } bool build_visible = LLFloaterReg::instanceVisible("build"); if (build_visible) diff --git a/indra/newview/lltoolmgr.h b/indra/newview/lltoolmgr.h index e5b45750d900f6fb2eebe1faea562f736f0748ea..4944c6ed71c3d423d23a4b58e783a3a98d921d74 100644 --- a/indra/newview/lltoolmgr.h +++ b/indra/newview/lltoolmgr.h @@ -56,7 +56,10 @@ class LLToolMgr : public LLSingleton<LLToolMgr> bool canEdit(); bool buildEnabledOrActive(); bool canAccessMarketplace(); - void toggleBuildMode(const LLSD& sdname); +// [RLVa:KB] - Checked: 2012-04-26 (RLVa-1.4.6) | Added: RLVa-1.4.6 + void toggleBuildMode(); +// [/RLVa:KB] +// void toggleBuildMode(const LLSD& sdname); void toggleMarketplace(const LLSD& sdname); /* Determines if we are in Build mode or not. */ diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp index e17651dc911a11e2fb8fc5892711e5f9dda01f02..9f941c1aac350f1bfb9c4d61ebec88f4fe2671e6 100644 --- a/indra/newview/lltoolpie.cpp +++ b/indra/newview/lltoolpie.cpp @@ -70,6 +70,10 @@ #include "llui.h" #include "llweb.h" #include "pipeline.h" // setHighlightObject +// [RLVa:KB] - Checked: 2010-03-06 (RLVa-1.2.0c) +#include "rlvactions.h" +#include "rlvhandler.h" +// [/RLVa:KB] extern BOOL gDebugClicks; @@ -202,6 +206,15 @@ BOOL LLToolPie::handleLeftClickPick() // If it's a left-click, and we have a special action, do it. if (useClickAction(mask, object, parent)) { +// [RLVa:KB] - Checked: 2010-03-11 (RLVa-1.2.0e) | Modified: RLVa-1.1.0l + // Block left-click special actions when fartouch restricted + if ( (rlv_handler_t::isEnabled()) && + (gRlvHandler.hasBehaviour(RLV_BHVR_FARTOUCH)) && (!gRlvHandler.canTouch(object, mPick.mObjectOffset)) ) + { + return TRUE; + } +// [/RLVa:KB] + mClickAction = 0; if (object && object->getClickAction()) { @@ -323,6 +336,14 @@ BOOL LLToolPie::handleLeftClickPick() ((object->flagUsePhysics() || (parent && !parent->isAvatar() && parent->flagUsePhysics())) || touchable) ) { +// [RLVa:KB] - Checked: 2010-03-11 (RLVa-1.2.0e) | Modified: RLVa-1.1.0l + // Triggered by left-clicking on a touchable object + if ( (rlv_handler_t::isEnabled()) && (!gRlvHandler.canTouch(object, mPick.mObjectOffset)) ) + { + return LLTool::handleMouseDown(x, y, mask); + } +// [/RLVa:KB] + gGrabTransientTool = this; mMouseButtonDown = false; LLToolGrab::getInstance()->setClickedInMouselook(gAgentCamera.cameraMouselook()); @@ -438,7 +459,11 @@ ECursorType LLToolPie::cursorFromObject(LLViewerObject* object) { case CLICK_ACTION_SIT: { - if (isAgentAvatarValid() && !gAgentAvatarp->isSitting()) // not already sitting? +// if (isAgentAvatarValid() && !gAgentAvatarp->isSitting()) // not already sitting? +// [RLVa:KB] - Checked: 2010-03-06 (RLVa-1.2.0c) | Modified: RLVa-1.2.0g + if ( (isAgentAvatarValid() && !gAgentAvatarp->isSitting()) && + ((!rlv_handler_t::isEnabled()) || (RlvActions::canSit(object, LLToolPie::getInstance()->getHoverPick().mObjectOffset))) ) +// [/RLVa:KB] { cursor = UI_CURSOR_TOOLSIT; } @@ -555,7 +580,20 @@ BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask) mHoverPick = gViewerWindow->pickImmediate(x, y, FALSE, FALSE); LLViewerObject *parent = NULL; LLViewerObject *object = mHoverPick.getObject(); +// [RLVa:KB] - Checked: 2010-03-11 (RLVa-1.2.0e) | Modified: RLVa-1.1.0l + // Block all special click action cursors when: + // - @fartouch=n restricted and the object is out of range + // - @interact=n restricted and the object isn't a HUD attachment + if ( (object) && (rlv_handler_t::isEnabled()) && + ( ((gRlvHandler.hasBehaviour(RLV_BHVR_FARTOUCH))) && (!gRlvHandler.canTouch(object, mHoverPick.mObjectOffset)) || + ((gRlvHandler.hasBehaviour(RLV_BHVR_INTERACT)) && (!object->isHUDAttachment())) ) ) + { + gViewerWindow->setCursor(UI_CURSOR_ARROW); + return TRUE; + } +// [/RLVa:KB] LLSelectMgr::getInstance()->setHoverObject(object, mHoverPick.mObjectFace); + if (object) { parent = object->getRootEdit(); @@ -609,7 +647,13 @@ BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask) gViewerWindow->setCursor(cursor); LL_DEBUGS("UserInput") << "hover handled by LLToolPie (inactive)" << LL_ENDL; } - +// [RLVa:KB] - Checked: 2010-03-11 (RLVa-1.2.0e) | Added: RLVa-1.1.0l + else if ( (object) && (rlv_handler_t::isEnabled()) && (!gRlvHandler.canTouch(object)) ) + { + // Block showing the "grab" or "touch" cursor if we can't touch the object (@fartouch=n is handled above) + gViewerWindow->setCursor(UI_CURSOR_ARROW); + } +// [/RLVa:KB] else if ((object && !object->isAvatar() && object->flagUsePhysics()) || (parent && !parent->isAvatar() && parent->flagUsePhysics())) { @@ -686,10 +730,24 @@ BOOL LLToolPie::handleMouseUp(S32 x, S32 y, MASK mask) FALSE /* ignore transparent */, FALSE /* ignore particles */); - if (!mPick.mPosGlobal.isExactlyZero() // valid coordinates for pick - && (mPick.mPickType == LLPickInfo::PICK_LAND // we clicked on land - || mPick.mObjectID.notNull())) // or on an object +// if (!mPick.mPosGlobal.isExactlyZero() // valid coordinates for pick +// && (mPick.mPickType == LLPickInfo::PICK_LAND // we clicked on land +// || mPick.mObjectID.notNull())) // or on an object +// [RLVa:KB] - Checked: RLVa-2.0.0 + bool fValidPick = (!mPick.mPosGlobal.isExactlyZero() // valid coordinates for pick + && (mPick.mPickType == LLPickInfo::PICK_LAND // we clicked on land + || mPick.mObjectID.notNull())); // or on an object + + if ( (fValidPick) && (RlvActions::isRlvEnabled()) && (!RlvActions::canTeleportToLocal(mPick.mPosGlobal)) ) + { + RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_AUTOPILOT); + fValidPick = false; + } + + if (fValidPick) +// [/RLVa:KB] { + // handle special cases of steering picks LLViewerObject* avatar_object = mPick.getObject(); @@ -784,8 +842,20 @@ BOOL LLToolPie::handleDoubleClick(S32 x, S32 y, MASK mask) } } - if ((mPick.mPickType == LLPickInfo::PICK_LAND && !mPick.mPosGlobal.isExactlyZero()) || - (mPick.mObjectID.notNull() && !mPick.mPosGlobal.isExactlyZero())) +// if ((mPick.mPickType == LLPickInfo::PICK_LAND && !mPick.mPosGlobal.isExactlyZero()) || +// (mPick.mObjectID.notNull() && !mPick.mPosGlobal.isExactlyZero())) +// [RLVa:KB] - Checked: RLVa-2.0.0 + bool fValidPick = ((mPick.mPickType == LLPickInfo::PICK_LAND && !mPick.mPosGlobal.isExactlyZero()) || + (mPick.mObjectID.notNull() && !mPick.mPosGlobal.isExactlyZero())); + + if ( (fValidPick) && (RlvActions::isRlvEnabled()) && (!RlvActions::canTeleportToLocal(mPick.mPosGlobal)) ) + { + RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_AUTOPILOT); + fValidPick = false; + } + + if (fValidPick) +// [/RLVa:KB] { walkToClickedLocation(); return TRUE; @@ -1052,7 +1122,10 @@ BOOL LLToolPie::handleTooltipObject( LLViewerObject* hover_object, std::string l LLAvatarName av_name; if (LLAvatarNameCache::get(hover_object->getID(), &av_name)) { - final_name = av_name.getCompleteName(); +// final_name = av_name.getCompleteName(); +// [RLVa:KB] - Checked: RLVa-1.2.2 + final_name = (RlvActions::canShowName(RlvActions::SNC_DEFAULT, hover_object->getID())) ? av_name.getCompleteName() : RlvStrings::getAnonym(av_name); +// [/RLVa:KB] } else { @@ -1061,17 +1134,29 @@ BOOL LLToolPie::handleTooltipObject( LLViewerObject* hover_object, std::string l // *HACK: We may select this object, so pretend it was clicked mPick = mHoverPick; - LLInspector::Params p; - p.fillFrom(LLUICtrlFactory::instance().getDefaultParams<LLInspector>()); - p.message(final_name); - p.image.name("Inspector_I"); - p.click_callback(boost::bind(showAvatarInspector, hover_object->getID())); - p.visible_time_near(6.f); - p.visible_time_far(3.f); - p.delay_time(gSavedSettings.getF32("AvatarInspectorTooltipDelay")); - p.wrap(false); - - LLToolTipMgr::instance().show(p); +// [RLVa:KB] - Checked: RLVa-1.2.0 + if ( (!rlv_handler_t::isEnabled()) || + ( (gRlvHandler.canTouch(hover_object, mHoverPick.mObjectOffset)) && (RlvActions::canShowName(RlvActions::SNC_DEFAULT, hover_object->getID())) ) ) + { +// [/RLVa:KB] + LLInspector::Params p; + p.fillFrom(LLUICtrlFactory::instance().getDefaultParams<LLInspector>()); + p.message(final_name); + p.image.name("Inspector_I"); + p.click_callback(boost::bind(showAvatarInspector, hover_object->getID())); + p.visible_time_near(6.f); + p.visible_time_far(3.f); + p.delay_time(gSavedSettings.getF32("AvatarInspectorTooltipDelay")); + p.wrap(false); + + LLToolTipMgr::instance().show(p); +// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.2a) | Added: RLVa-1.2.0e + } + else + { + LLToolTipMgr::instance().show(final_name); + } +// [/RLVa:KB] } } else @@ -1174,22 +1259,34 @@ BOOL LLToolPie::handleTooltipObject( LLViewerObject* hover_object, std::string l { // We may select this object, so pretend it was clicked mPick = mHoverPick; - LLInspector::Params p; - p.fillFrom(LLUICtrlFactory::instance().getDefaultParams<LLInspector>()); - p.message(tooltip_msg); - p.image.name("Inspector_I"); - p.click_callback(boost::bind(showObjectInspector, hover_object->getID(), mHoverPick.mObjectFace)); - p.time_based_media(is_time_based_media); - p.web_based_media(is_web_based_media); - p.media_playing(is_media_playing); - p.click_playmedia_callback(boost::bind(playCurrentMedia, mHoverPick)); - p.click_homepage_callback(boost::bind(VisitHomePage, mHoverPick)); - p.visible_time_near(6.f); - p.visible_time_far(3.f); - p.delay_time(gSavedSettings.getF32("ObjectInspectorTooltipDelay")); - p.wrap(false); - - LLToolTipMgr::instance().show(p); +// [RLVa:KB] - Checked: 2010-11-12 (RLVa-1.2.1g) | Modified: RLVa-1.2.1g + if ( (!rlv_handler_t::isEnabled()) || (!gRlvHandler.hasBehaviour(RLV_BHVR_FARTOUCH)) || + (gRlvHandler.canTouch(hover_object, mHoverPick.mObjectOffset)) ) + { +// [/RLVa:KB] + LLInspector::Params p; + p.fillFrom(LLUICtrlFactory::instance().getDefaultParams<LLInspector>()); + p.message(tooltip_msg); + p.image.name("Inspector_I"); + p.click_callback(boost::bind(showObjectInspector, hover_object->getID(), mHoverPick.mObjectFace)); + p.time_based_media(is_time_based_media); + p.web_based_media(is_web_based_media); + p.media_playing(is_media_playing); + p.click_playmedia_callback(boost::bind(playCurrentMedia, mHoverPick)); + p.click_homepage_callback(boost::bind(VisitHomePage, mHoverPick)); + p.visible_time_near(6.f); + p.visible_time_far(3.f); + p.delay_time(gSavedSettings.getF32("ObjectInspectorTooltipDelay")); + p.wrap(false); + + LLToolTipMgr::instance().show(p); +// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Added: RLVa-1.2.0e + } + else + { + LLToolTipMgr::instance().show(tooltip_msg); + } +// [/RLVa:KB] } } } @@ -1203,7 +1300,15 @@ BOOL LLToolPie::handleToolTip(S32 local_x, S32 local_y, MASK mask) if (!mHoverPick.isValid()) return TRUE; LLViewerObject* hover_object = mHoverPick.getObject(); - + +// [RLVa:KB] - Checked: RLVa-1.2.0 + // NOTE: handleTooltipObject() will block HUD tooltips anyway but technically interact should only interfere with world interaction + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_INTERACT)) && (hover_object) && (!hover_object->isHUDAttachment()) ) + { + return TRUE; + } +// [/RLVa:KB] + // update hover object and hover parcel LLSelectMgr::getInstance()->setHoverObject(hover_object, mHoverPick.mObjectFace); @@ -1788,16 +1893,29 @@ BOOL LLToolPie::handleRightClickPick() mute_msg = LLTrans::getString("MuteAvatar"); } - if (is_other_attachment) +// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Modified: RLVa-1.1.0l + // Don't show the context menu on empty selection when fartouch restricted [see LLToolSelect::handleObjectSelection()] + if ( (!rlv_handler_t::isEnabled()) || (!LLSelectMgr::getInstance()->getSelection()->isEmpty()) || + (!gRlvHandler.hasBehaviour(RLV_BHVR_FARTOUCH)) ) { - gMenuAttachmentOther->getChild<LLUICtrl>("Avatar Mute")->setValue(mute_msg); - gMenuAttachmentOther->show(x, y); +// [/RLVa:KB] + if (is_other_attachment) + { + gMenuAttachmentOther->getChild<LLUICtrl>("Avatar Mute")->setValue(mute_msg); + gMenuAttachmentOther->show(x, y); + } + else + { + gMenuAvatarOther->getChild<LLUICtrl>("Avatar Mute")->setValue(mute_msg); + gMenuAvatarOther->show(x, y); + } +// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Modified: RLVa-1.1.0l } else { - gMenuAvatarOther->getChild<LLUICtrl>("Avatar Mute")->setValue(mute_msg); - gMenuAvatarOther->show(x, y); + make_ui_sound("UISndInvalidOp"); } +// [/RLVa:KB] } else if (object->isAttachment()) { @@ -1813,9 +1931,23 @@ BOOL LLToolPie::handleRightClickPick() name = node->mName; } - gMenuObject->show(x, y); +// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.el) | Modified: RLVa-1.1.0l + // Don't show the pie menu on empty selection when fartouch/interaction restricted + // (not entirely accurate in case of Tools / Select Only XXX [see LLToolSelect::handleObjectSelection()] + if ( (!rlv_handler_t::isEnabled()) || (!LLSelectMgr::getInstance()->getSelection()->isEmpty()) || + (!gRlvHandler.hasBehaviour(RLV_BHVR_FARTOUCH)) ) + { +// [/RLVa:KB] + gMenuObject->show(x, y); - showVisualContextMenuEffect(); + showVisualContextMenuEffect(); +// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.el) | Modified: RLVa-1.1.0l + } + else + { + make_ui_sound("UISndInvalidOp"); + } +// [/RLVa:KB] } } else if (mPick.mParticleOwnerID.notNull()) diff --git a/indra/newview/lltoolpie.h b/indra/newview/lltoolpie.h index 6391e675c551a7c7ffbf846097adbea8034a8352..290c5976da1652b9e5f6e79a2058267eaaf15fc7 100644 --- a/indra/newview/lltoolpie.h +++ b/indra/newview/lltoolpie.h @@ -62,6 +62,9 @@ class LLToolPie : public LLTool, public LLSingleton<LLToolPie> virtual LLTool* getOverrideTool(MASK mask); LLPickInfo& getPick() { return mPick; } +// [RLVa:KB] - Checked: 2010-03-06 (RLVa-1.2.0c) | Added: RLVa-1.2.0a + LLPickInfo& getHoverPick() { return mHoverPick; } +// [/RLVa:KB] U8 getClickAction() { return mClickAction; } LLViewerObject* getClickActionObject() { return mClickActionObject; } LLObjectSelection* getLeftClickSelection() { return (LLObjectSelection*)mLeftClickSelection; } diff --git a/indra/newview/lltoolplacer.cpp b/indra/newview/lltoolplacer.cpp index 814bade56ad675f882e2cb763cd78b7de0349cac..ea819811ef2d339dd78cf5a33dd209e9f344d3a8 100644 --- a/indra/newview/lltoolplacer.cpp +++ b/indra/newview/lltoolplacer.cpp @@ -43,6 +43,10 @@ #include "llviewerwindow.h" #include "llworld.h" #include "llui.h" +// [RLVa:KB] - Checked: 2010-03-23 (RLVa-1.2.0a) +#include "rlvhandler.h" +#include "rlvhelper.h" +// [/RLVa:KB] //Headers added for functions moved from viewer.cpp #include "llvograss.h" @@ -123,6 +127,16 @@ BOOL LLToolPlacer::raycastForNewObjPos( S32 x, S32 y, LLViewerObject** hit_obj, return FALSE; } +// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Modified: RLVa-0.2.0f + // NOTE: don't use surface_pos_global since for prims it will be the center of the prim while we need center + offset + if (gRlvHandler.hasBehaviour(RLV_BHVR_FARTOUCH)) + { + static RlvCachedBehaviourModifier<float> s_nFartouchDist(RLV_MODIFIER_FARTOUCHDIST); + if (dist_vec_squared(gAgent.getPositionGlobal(), pick.mPosGlobal) > s_nFartouchDist * s_nFartouchDist) + return FALSE; + } +// [/RLVa:KB] + // Find the sim where the surface lives. LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromPosGlobal(surface_pos_global); if (!regionp) @@ -240,7 +254,10 @@ BOOL LLToolPlacer::addObject( LLPCode pcode, S32 x, S32 y, U8 use_physics ) { flags |= FLAGS_USE_PHYSICS; } - if (create_selected) +// if (create_selected) +// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Added: RLVa-1.0.0b + if ( (create_selected) && (!gRlvHandler.hasBehaviour(RLV_BHVR_EDIT)) ) +// [/RLVa:KB] { flags |= FLAGS_CREATE_SELECTED; } @@ -498,6 +515,13 @@ BOOL LLToolPlacer::placeObject(S32 x, S32 y, MASK mask) { BOOL added = TRUE; +// [RLVa:KB] - Checked: 2010-03-23 (RLVa-1.2.0e) | Modified: RLVa-1.1.0l + if ( (rlv_handler_t::isEnabled()) && ((gRlvHandler.hasBehaviour(RLV_BHVR_REZ)) || (gRlvHandler.hasBehaviour(RLV_BHVR_INTERACT))) ) + { + return TRUE; // Callers seem to expect a "did you handle it?" so we return TRUE rather than FALSE + } +// [/RLVa:KB] + if (gSavedSettings.getBOOL("CreateToolCopySelection")) { added = addDuplicate(x, y); diff --git a/indra/newview/lltoolselect.cpp b/indra/newview/lltoolselect.cpp index 1fcc9a07113cd4f8f4948dc035e346bdabd68681..2cd221c351b9340098ff23cfec9e6d8cd823647d 100644 --- a/indra/newview/lltoolselect.cpp +++ b/indra/newview/lltoolselect.cpp @@ -47,6 +47,11 @@ #include "llviewerwindow.h" #include "llvoavatarself.h" #include "llworld.h" +// [RLVa:KB] - Checked: RLVa-2.0.0 +#include "rlvactions.h" +#include "rlvhelper.h" +#include "llfloaterreg.h" +// [/RLVa:KB] // Globals //extern BOOL gAllowSelectAvatar; @@ -80,6 +85,36 @@ LLObjectSelectionHandle LLToolSelect::handleObjectSelection(const LLPickInfo& pi { object = object->getRootEdit(); } + +// [RLVa:KB] - Checked: 2010-11-29 (RLVa-1.3.0c) | Modified: RLVa-1.3.0c + if ( (object) && (RlvActions::isRlvEnabled()) ) + { + if (!RlvActions::canEdit(object)) + { + if (!temp_select) + return LLSelectMgr::getInstance()->getSelection(); + else if (LLToolMgr::instance().inBuildMode()) + LLToolMgr::instance().toggleBuildMode(); + } + + if ( (RlvActions::hasBehaviour(RLV_BHVR_FARTOUCH)) && ((!object->isAttachment()) || (!object->permYouOwner())) ) + { + static RlvCachedBehaviourModifier<float> s_nFartouchDist(RLV_MODIFIER_FARTOUCHDIST); + float nFartouchDistSq = s_nFartouchDist * s_nFartouchDist; + // NOTE: recheck why we did it this way, might be able to simplify + if ( (dist_vec_squared(gAgent.getPositionAgent(), object->getPositionRegion()) > nFartouchDistSq) && + (dist_vec_squared(gAgent.getPositionAgent(), pick.mIntersection) > nFartouchDistSq) ) + { + if ( (LLFloaterReg::instanceVisible("build")) && (pick.mKeyMask != MASK_SHIFT) && (pick.mKeyMask != MASK_CONTROL) ) + LLSelectMgr::getInstance()->deselectAll(); + return LLSelectMgr::getInstance()->getSelection(); + } + else if (LLToolMgr::instance().inBuildMode()) + LLToolMgr::instance().toggleBuildMode(); + } + } +// [/RLVa:KB] + BOOL select_owned = gSavedSettings.getBOOL("SelectOwnedOnly"); BOOL select_movable = gSavedSettings.getBOOL("SelectMovableOnly"); diff --git a/indra/newview/lltracker.cpp b/indra/newview/lltracker.cpp index b015cde45d699f75d62f78d4ea4dfefc7909181d..5ff2771922806af651491b47b189c4377d6ed440 100644 --- a/indra/newview/lltracker.cpp +++ b/indra/newview/lltracker.cpp @@ -62,6 +62,10 @@ #include "llworldmapview.h" #include "llviewercontrol.h" +// [RLVa:KB] +#include "rlvhandler.h" +// [/RLVa:KB] + const F32 DESTINATION_REACHED_RADIUS = 3.0f; const F32 DESTINATION_VISITED_RADIUS = 6.0f; diff --git a/indra/newview/llviewercamera.cpp b/indra/newview/llviewercamera.cpp index 57a0195d23ea41ed3074e0bbb4595422460b5146..4b0a36ddcd788dfffd63cd90ff2af304e808ecb8 100644 --- a/indra/newview/llviewercamera.cpp +++ b/indra/newview/llviewercamera.cpp @@ -41,6 +41,10 @@ #include "llworld.h" #include "lltoolmgr.h" #include "llviewerjoystick.h" +// [RLVa:KB] - RLVa-2.0.0 +#include "rlvactions.h" +#include "rlvhandler.h" +// [/RLVa:KB] // Linden library includes #include "lldrawable.h" @@ -359,6 +363,11 @@ void LLViewerCamera::setPerspective(BOOL for_selection, { z_far = gAgentCamera.mDrawDistance; } + +// [RLVa:KB] - Checked: RLVa-2.0.0 + if (RlvActions::hasBehaviour(RLV_BHVR_FARTOUCH)) + z_far = RlvActions::getModifierValue<float>(RLV_MODIFIER_FARTOUCHDIST); +// [/RLVa:KB] } else { @@ -876,6 +885,12 @@ BOOL LLViewerCamera::areVertsVisible(LLViewerObject* volumep, BOOL all_verts) void LLViewerCamera::setDefaultFOV(F32 vertical_fov_rads) { +// [RLVa:KB] - Checked: RLVa-2.0.0 + F32 nCamFOVMin, nCamFOVMax; + if ( (RlvActions::isRlvEnabled()) && (RlvActions::getCameraFOVLimits(nCamFOVMin, nCamFOVMax)) ) + vertical_fov_rads = llclamp(vertical_fov_rads, nCamFOVMin, nCamFOVMax); +// [/RLVa:KB] + vertical_fov_rads = llclamp(vertical_fov_rads, getMinView(), getMaxView()); setView(vertical_fov_rads); mCameraFOVDefault = vertical_fov_rads; diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index 16f40fb747393d55ff6f6c0f177040f065062470..e267a8f31e59c517e03fdc33023f6f21ce58f69c 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -75,6 +75,9 @@ #include "llslurl.h" #include "llstartup.h" #include "llupdaterservice.h" +// [RLVa:KB] - Checked: 2015-12-27 (RLVa-1.5.0) +#include "rlvcommon.h" +// [/RLVa:KB] // Third party library includes #include <boost/algorithm/string.hpp> @@ -741,6 +744,9 @@ void settings_setup_listeners() gSavedSettings.getControl("SpellCheck")->getSignal()->connect(boost::bind(&handleSpellCheckChanged)); gSavedSettings.getControl("SpellCheckDictionary")->getSignal()->connect(boost::bind(&handleSpellCheckChanged)); gSavedSettings.getControl("LoginLocation")->getSignal()->connect(boost::bind(&handleLoginLocationChanged)); +// [RLVa:KB] - Checked: 2015-12-27 (RLVa-1.5.0) + gSavedSettings.getControl("RestrainedLove")->getSignal()->connect(boost::bind(&RlvSettings::onChangedSettingMain, _2)); +// [/RLVa:KB] } #if TEST_CACHED_CONTROL diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index afa00e3e6e54dd6c68fe34250eda3c5536381e7b..f631ecc9c2b11e8d8bbf107f1a0a4f749f2d91ca 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -78,6 +78,10 @@ #include "llwaterparammanager.h" #include "llpostprocess.h" #include "llscenemonitor.h" +// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a) +#include "rlvhandler.h" +#include "rlvlocks.h" +// [/RLVa:KB] extern LLPointer<LLViewerTexture> gStartTexture; extern bool gShiftFrame; @@ -493,6 +497,9 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) // No teleport in progress gViewerWindow->setShowProgress(FALSE); gTeleportDisplay = FALSE; +// [SL:KB] - Patch: Appearance-TeleportAttachKill | Checked: Catznip-4.0 + LLViewerParcelMgr::getInstance()->onTeleportDone(); +// [/SL:KB] break; } } @@ -1073,7 +1080,11 @@ void render_hud_attachments() glh::matrix4f current_mod = glh_get_current_modelview(); // clamp target zoom level to reasonable values - gAgentCamera.mHUDTargetZoom = llclamp(gAgentCamera.mHUDTargetZoom, 0.1f, 1.f); +// gAgentCamera.mHUDTargetZoom = llclamp(gAgentCamera.mHUDTargetZoom, 0.1f, 1.f); +// [RLVa:KB] - Checked: 2010-08-22 (RLVa-1.2.1a) | Modified: RLVa-1.0.0c + gAgentCamera.mHUDTargetZoom = llclamp(gAgentCamera.mHUDTargetZoom, (!gRlvAttachmentLocks.hasLockedHUD()) ? 0.1f : 0.85f, 1.f); +// [/RLVa:KB] + // smoothly interpolate current zoom level gAgentCamera.mHUDCurZoom = lerp(gAgentCamera.mHUDCurZoom, gAgentCamera.mHUDTargetZoom, LLSmoothInterpolation::getInterpolant(0.03f)); diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index 6d13d28e18fa45722988fda61c823b15df151024..4a4975ee9ae37144b718abf6bf097c4b4ae11576 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -156,7 +156,9 @@ #include "llsyswellwindow.h" // *NOTE: Please add files in alphabetical order to keep merges easy. - +// [RLVa:KB] - Checked: 2010-03-11 +#include "rlvfloaters.h" +// [/RLVa:KB] // handle secondlife:///app/openfloater/{NAME} URLs class LLFloaterOpenHandler : public LLCommandHandler { @@ -321,6 +323,12 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("region_debug_console", "floater_region_debug_console.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterRegionDebugConsole>); LLFloaterReg::add("region_info", "floater_region_info.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterRegionInfo>); LLFloaterReg::add("region_restarting", "floater_region_restarting.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterRegionRestarting>); +// [RLVa:KB] - Checked: 2010-03-11 (RLVa-1.2.0e) | Added: RLVa-1.2.0a + LLFloaterReg::add("rlv_behaviours", "floater_rlv_behaviours.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<RlvFloaterBehaviours>); + LLFloaterReg::add("rlv_console", "floater_rlv_console.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<RlvFloaterConsole>); + LLFloaterReg::add("rlv_locks", "floater_rlv_locks.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<RlvFloaterLocks>); + LLFloaterReg::add("rlv_strings", "floater_rlv_strings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<RlvFloaterStrings>); +// [/RLVa:KB] LLFloaterReg::add("script_debug", "floater_script_debug.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterScriptDebug>); LLFloaterReg::add("script_debug_output", "floater_script_debug_panel.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterScriptDebugOutput>); diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index 4f5e2a6568447bf74549484292392f1b19066a05..67cea002204b259cabe26bb55a73ae998923e831 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -69,6 +69,9 @@ #include "llfloaterperms.h" #include "llclipboard.h" #include "llhttpretrypolicy.h" +// [RLVa:KB] - Checked: 2014-11-02 (RLVa-1.4.11) +#include "rlvcommon.h" +// [/RLVa:KB] // do-nothing ops for use in callbacks. void no_op_inventory_func(const LLUUID&) {} @@ -1683,6 +1686,65 @@ void create_new_item(const std::string& name, cb); } +// [RLVa:KB] - Checked: 2014-11-02 (RLVa-1.4.11) +void sync_inventory_folder(const LLUUID& folder_id, const LLInventoryModel::item_array_t& items, LLInventoryModel::item_array_t& items_to_add, LLInventoryModel::item_array_t& items_to_remove) +{ + LLInventoryModel::item_array_t curItems, newItems = items; + + // Grab the current contents + LLInventoryModel::cat_array_t cats; + gInventory.collectDescendents(folder_id, cats, curItems, LLInventoryModel::EXCLUDE_TRASH); + + // Purge everything in curItems that isn't part of newItems + for (LLInventoryModel::item_array_t::const_iterator itCurItem = curItems.begin(); itCurItem != curItems.end(); ++itCurItem) + { + LLViewerInventoryItem* pItem = *itCurItem; + if (std::find_if(newItems.begin(), newItems.end(), RlvPredIsEqualOrLinkedItem(pItem)) == newItems.end()) + { + // Item doesn't exist in newItems => purge (if it's a link) + if ( (pItem->getIsLinkType()) && + (LLAssetType::AT_LINK_FOLDER != pItem->getActualType()) && + (items_to_remove.end() == std::find(items_to_remove.begin(), items_to_remove.end(), pItem)) ) + { + items_to_remove.push_back(pItem); + } + } + else + { + // Item exists in newItems => remove *all* occurances in newItems (removes duplicate COF links to this item as well) + newItems.erase(std::remove_if(newItems.begin(), newItems.end(), RlvPredIsEqualOrLinkedItem(pItem)), newItems.end()); + } + } + + // Whatever remains in newItems will need to have a link created + for (LLInventoryModel::item_array_t::const_iterator itNewItem = newItems.begin(); itNewItem != newItems.end(); ++itNewItem) + { + LLViewerInventoryItem* pItem = *itNewItem; + if (items_to_add.end() == std::find(items_to_add.begin(), items_to_add.end(), pItem)) + items_to_add.push_back(pItem); + } +} + +void link_inventory_items(const LLUUID& folder_id, const LLInventoryModel::item_array_t& items, LLPointer<LLInventoryCallback> cb) +{ + for (LLInventoryModel::item_array_t::const_iterator itItem = items.begin(); itItem != items.end(); ++itItem) + { + const LLViewerInventoryItem* pItem = *itItem; + link_inventory_object(folder_id, pItem, cb); + } +} + +void remove_inventory_items(const LLInventoryModel::item_array_t& items, LLPointer<LLInventoryCallback> cb) +{ + for (LLInventoryModel::item_array_t::const_iterator itItem = items.begin(); itItem != items.end(); ++itItem) + { + const LLViewerInventoryItem* pItem = *itItem; + if (pItem->getIsLinkType()) + remove_inventory_item(pItem->getUUID(), cb); + } +} +// [/RLVa:KB] + void slam_inventory_folder(const LLUUID& folder_id, const LLSD& contents, LLPointer<LLInventoryCallback> cb) diff --git a/indra/newview/llviewerjointattachment.cpp b/indra/newview/llviewerjointattachment.cpp index 11ee4768aaafea802940cefab0af232970a6dca5..c5d8487b6602620386b250647950c2fed83fdc7c 100644 --- a/indra/newview/llviewerjointattachment.cpp +++ b/indra/newview/llviewerjointattachment.cpp @@ -172,6 +172,12 @@ BOOL LLViewerJointAttachment::addObject(LLViewerObject* object) if (isObjectAttached(object)) { LL_INFOS() << "(same object re-attached)" << LL_ENDL; +// [SL:KB] - Patch: Appearance-TeleportAttachKill | Checked: Catznip-4.0 + if ( (object->permYouOwner()) && (gAgentAvatarp) ) + { + gAgentAvatarp->removePendingDetach(object->getID()); + } +// [/SL:KB] removeObject(object); // Pass through anyway to let setupDrawable() // re-connect object to the joint correctly diff --git a/indra/newview/llviewerjoystick.cpp b/indra/newview/llviewerjoystick.cpp index e44d80b7ceab33405c2bdbbc52c6cb9ffdea8ce3..06e1e64300527a18a9772fdee8bbef7f879903ff 100644 --- a/indra/newview/llviewerjoystick.cpp +++ b/indra/newview/llviewerjoystick.cpp @@ -326,8 +326,11 @@ void LLViewerJoystick::handleRun(F32 inc) if (1 == mJoystickRun) { ++mJoystickRun; - gAgent.setRunning(); - gAgent.sendWalkRun(gAgent.getRunning()); +// gAgent.setRunning(); +// gAgent.sendWalkRun(gAgent.getRunning()); +// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i + gAgent.setTempRun(); +// [/RLVa:KB] } else if (0 == mJoystickRun) { @@ -342,8 +345,11 @@ void LLViewerJoystick::handleRun(F32 inc) --mJoystickRun; if (0 == mJoystickRun) { - gAgent.clearRunning(); - gAgent.sendWalkRun(gAgent.getRunning()); +// gAgent.clearRunning(); +// gAgent.sendWalkRun(gAgent.getRunning()); +// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i + gAgent.clearTempRun(); +// [/RLVa:KB] } } } diff --git a/indra/newview/llviewerkeyboard.cpp b/indra/newview/llviewerkeyboard.cpp index 2186ed3c5297d508e58c800aa262d3a5ed132f23..d84c1c93c8790f747acba3aaedc0a7a0def9217e 100644 --- a/indra/newview/llviewerkeyboard.cpp +++ b/indra/newview/llviewerkeyboard.cpp @@ -42,6 +42,9 @@ #include "llvoavatarself.h" #include "llfloatercamera.h" #include "llinitparam.h" +// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i +#include "rlvhandler.h" +// [/RLVa:KB] // // Constants @@ -89,14 +92,18 @@ void agent_push_down( EKeystate s ) static void agent_check_temporary_run(LLAgent::EDoubleTapRunMode mode) { - if (gAgent.mDoubleTapRunMode == mode && - gAgent.getRunning() && - !gAgent.getAlwaysRun()) - { - // Turn off temporary running. - gAgent.clearRunning(); - gAgent.sendWalkRun(gAgent.getRunning()); - } +// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i + if ( (gAgent.mDoubleTapRunMode == mode) && (gAgent.getTempRun()) ) + gAgent.clearTempRun(); +// [/RLVa:KB] +// if (gAgent.mDoubleTapRunMode == mode && +// gAgent.getRunning() && +// !gAgent.getAlwaysRun()) +// { +// // Turn off temporary running. +// gAgent.clearRunning(); +// gAgent.sendWalkRun(gAgent.getRunning()); +// } } static void agent_handle_doubletap_run(EKeystate s, LLAgent::EDoubleTapRunMode mode) @@ -116,8 +123,11 @@ static void agent_handle_doubletap_run(EKeystate s, LLAgent::EDoubleTapRunMode m { // Same walk-key was pushed again quickly; this is a // double-tap so engage temporary running. - gAgent.setRunning(); - gAgent.sendWalkRun(gAgent.getRunning()); +// gAgent.setRunning(); +// gAgent.sendWalkRun(gAgent.getRunning()); +// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i + gAgent.setTempRun(); +// [/RLVa:KB] } // Pressing any walk-key resets the double-tap timer diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 6ed063e06637fd8c5238612c4d97742177370450..2fca1a7a13cd5163a4c31f6115895e7ffe1fed7c 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -2992,7 +2992,10 @@ void LLViewerMediaImpl::updateImagesMediaStreams() ////////////////////////////////////////////////////////////////////////////////////////// LLViewerMediaTexture* LLViewerMediaImpl::updatePlaceholderImage() { - if(mTextureId.isNull()) +// if(mTextureId.isNull()) +// [SL:KB] - Patch: Render-TextureToggle (Catznip-4.0) + if ( (mTextureId.isNull()) || ((LLViewerFetchedTexture::sDefaultDiffuseImagep.notNull()) && (LLViewerFetchedTexture::sDefaultDiffuseImagep->getID() == mTextureId)) ) +// [/SL:KB] { // The code that created this instance will read from the plugin's bits. return NULL; diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 42c6cc7758f9bd372bbc25cab1a2a790fe2d8b10..f62fcd4d6c8109612a9d4901c1cdcfe844720a55 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -133,6 +133,11 @@ #include "llpathfindingmanager.h" #include "llstartup.h" #include "boost/unordered_map.hpp" +// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a) +#include "rlvactions.h" +#include "rlvhandler.h" +#include "rlvlocks.h" +// [/RLVa:KB] using namespace LLAvatarAppearanceDefines; @@ -1208,7 +1213,24 @@ class LLAdvancedToggleWireframe : public view_listener_t { bool handleEvent(const LLSD& userdata) { - gUseWireframe = !(gUseWireframe); +// [RLVa:KB] - Checked: RLVa-2.0.0 + bool fRlvBlockWireframe = gRlvAttachmentLocks.hasLockedHUD(); + if ( (!gUseWireframe) && (fRlvBlockWireframe) ) + RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_WIREFRAME); + set_use_wireframe( (!gUseWireframe) && (!fRlvBlockWireframe) ); + return true; + } +}; + +// Called from rlvhandler.cpp +void set_use_wireframe(BOOL useWireframe) + { + if (gUseWireframe == useWireframe) + return; + + gUseWireframe = useWireframe; +// [/RLVa:KB] +// gUseWireframe = !(gUseWireframe); if (gUseWireframe) { @@ -1227,9 +1249,9 @@ class LLAdvancedToggleWireframe : public view_listener_t LLViewerShaderMgr::instance()->setShaders(); } - return true; +// return true; } -}; +//}; class LLAdvancedCheckWireframe : public view_listener_t { @@ -2599,6 +2621,15 @@ void handle_object_touch() LLPickInfo pick = LLToolPie::getInstance()->getPick(); +// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Modified: RLVa-1.1.0l + // 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; + } +// [/RLVa:KB] + // *NOTE: Hope the packets arrive safely and in order or else // there will be some problems. // *TODO: Just fix this bad assumption. @@ -2646,6 +2677,14 @@ bool enable_object_touch(LLUICtrl* ctrl) new_value = obj->flagHandleTouch() || (parent && parent->flagHandleTouch()); } +// [RLVa:KB] - Checked: 2010-11-12 (RLVa-1.2.1g) | Added: RLVa-1.2.1g + if ( (rlv_handler_t::isEnabled()) && (new_value) ) + { + // RELEASE-RLVa: [RLVa-1.2.1] Make sure this stays in sync with handle_object_touch() + new_value = gRlvHandler.canTouch(obj, LLToolPie::getInstance()->getPick().mObjectOffset); + } +// [/RLVa:KB] + std::string item_name = ctrl->getName(); init_default_item_label(item_name); @@ -2678,7 +2717,11 @@ bool enable_object_touch(LLUICtrl* ctrl) void handle_object_open() { - LLFloaterReg::showInstance("openobject"); +// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Added: RLVa-1.2.0e + if (enable_object_open()) + LLFloaterReg::showInstance("openobject"); +// [/RLVa:KB] +// LLFloaterReg::showInstance("openobject"); } bool enable_object_open() @@ -2908,7 +2951,17 @@ bool enable_object_edit() } else if (LLSelectMgr::getInstance()->selectGetAllValidAndObjectsFound()) { - enable = true; +// enable = true; +// [RLVa:KB] - Checked: 2010-11-29 (RLVa-1.3.0c) | Modified: RLVa-1.3.0c + bool fRlvCanEdit = (!gRlvHandler.hasBehaviour(RLV_BHVR_EDIT)) && (!gRlvHandler.hasBehaviour(RLV_BHVR_EDITOBJ)); + if (!fRlvCanEdit) + { + LLObjectSelectionHandle hSel = LLSelectMgr::getInstance()->getSelection(); + RlvSelectIsEditable f; + fRlvCanEdit = (hSel.notNull()) && ((hSel->getFirstRootNode(&f, TRUE)) == NULL); + } + enable = fRlvCanEdit; +// [/RLVa:KB] } return enable; @@ -2963,7 +3016,10 @@ class LLSelfEnableRemoveAllAttachments : public view_listener_t { LLVOAvatar::attachment_map_t::iterator curiter = iter++; LLViewerJointAttachment* attachment = curiter->second; - if (attachment->getNumObjects() > 0) +// 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] { new_value = true; break; @@ -3006,7 +3062,10 @@ bool enable_object_mute() bool is_linden = lastname && !LLStringUtil::compareStrings(lastname->getString(), "Linden"); bool is_self = avatar->isSelf(); - return !is_linden && !is_self; +// return !is_linden && !is_self; +// [RLVa:KB] - Checked: RLVa-1.2.1 + return !is_linden && !is_self && (RlvActions::canShowName(RlvActions::SNC_DEFAULT, avatar->getID())); +// [/RLVa:KB] } else { @@ -3115,6 +3174,10 @@ class LLObjectMute : public view_listener_t avatar->mNeedsImpostorUpdate = TRUE; id = avatar->getID(); +// [RLVa:KB] - Checked: RLVa-1.0.0 + if (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, id)) + return true; +// [/RLVa:KB] LLNameValue *firstname = avatar->getNVPair("FirstName"); LLNameValue *lastname = avatar->getNVPair("LastName"); @@ -3267,7 +3330,10 @@ void handle_avatar_freeze(const LLSD& avatar_id) if (!fullname.empty()) { LLSD args; - args["AVATAR_NAME"] = fullname; +// args["AVATAR_NAME"] = fullname; +// [RLVa:KB] - Checked: RLVa-1.0.0 + args["AVATAR_NAME"] = (RlvActions::canShowName(RlvActions::SNC_DEFAULT, avatar->getID())) ? fullname : RlvStrings::getAnonym(fullname); +// [/RLVa:KB] LLNotificationsUtil::add("FreezeAvatarFullname", args, payload, @@ -3396,7 +3462,10 @@ void handle_avatar_eject(const LLSD& avatar_id) if (!fullname.empty()) { LLSD args; - args["AVATAR_NAME"] = fullname; +// args["AVATAR_NAME"] = fullname; +// [RLVa:KB] - Checked: RLVa-1.0.0 + args["AVATAR_NAME"] = (RlvActions::canShowName(RlvActions::SNC_DEFAULT, avatar->getID())) ? fullname : RlvStrings::getAnonym(fullname); +// [/RLVa:KB] LLNotificationsUtil::add("EjectAvatarFullname", args, payload, @@ -3416,7 +3485,10 @@ void handle_avatar_eject(const LLSD& avatar_id) if (!fullname.empty()) { LLSD args; - args["AVATAR_NAME"] = fullname; +// args["AVATAR_NAME"] = fullname; +// [RLVa:KB] - Checked: RLVa-1.0.0 + args["AVATAR_NAME"] = (RlvActions::canShowName(RlvActions::SNC_DEFAULT, avatar->getID())) ? fullname : RlvStrings::getAnonym(fullname); +// [/RLVa:KB] LLNotificationsUtil::add("EjectAvatarFullnameNoBan", args, payload, @@ -3647,7 +3719,10 @@ class LLSelfStandUp : public view_listener_t bool enable_standup_self() { - return isAgentAvatarValid() && gAgentAvatarp->isSitting(); +// [RLVa:KB] - Checked: 2010-04-01 (RLVa-1.2.0c) | Modified: RLVa-1.0.0g + return isAgentAvatarValid() && gAgentAvatarp->isSitting() && !gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT); +// [/RLVa:KB] +// return isAgentAvatarValid() && gAgentAvatarp->isSitting(); } class LLSelfSitDown : public view_listener_t @@ -3661,7 +3736,10 @@ class LLSelfSitDown : public view_listener_t bool enable_sitdown_self() { - return isAgentAvatarValid() && !gAgentAvatarp->isSitting() && !gAgentAvatarp->isEditingAppearance() && !gAgent.getFlying(); +// [RLVa:KB] - Checked: 2010-08-28 (RLVa-1.2.1a) | Added: RLVa-1.2.1a + return isAgentAvatarValid() && !gAgentAvatarp->isSitting() && !gAgentAvatarp->isEditingAppearance() && !gAgent.getFlying() && !gRlvHandler.hasBehaviour(RLV_BHVR_SIT); +// [/RLVa:KB] +// return isAgentAvatarValid() && !gAgentAvatarp->isSitting() && !gAgentAvatarp->isEditingAppearance() && !gAgent.getFlying(); } class LLCheckPanelPeopleTab : public view_listener_t @@ -3905,7 +3983,10 @@ class LLAvatarEnableAddFriend : public view_listener_t bool handleEvent(const LLSD& userdata) { LLVOAvatar* avatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); - bool new_value = avatar && !LLAvatarActions::isFriend(avatar->getID()); +// bool new_value = avatar && !LLAvatarActions::isFriend(avatar->getID()); +// [RLVa:KB] - Checked: RLVa-1.2.0 + bool new_value = avatar && !LLAvatarActions::isFriend(avatar->getID()) && (RlvActions::canShowName(RlvActions::SNC_DEFAULT, avatar->getID())); +// [/RLVa:KB] return new_value; } }; @@ -3939,7 +4020,10 @@ class LLEditEnableCustomizeAvatar : public view_listener_t { bool handleEvent(const LLSD& userdata) { - bool new_value = gAgentWearables.areWearablesLoaded(); +// bool new_value = gAgentWearables.areWearablesLoaded(); +// [RLVa:KB] - Checked: 2010-04-01 (RLVa-1.2.0c) | Modified: RLVa-1.0.0g + bool new_value = gAgentWearables.areWearablesLoaded() && ((!rlv_handler_t::isEnabled()) || (RlvActions::canStand())); +// [/RLVa:KB] return new_value; } }; @@ -3971,6 +4055,16 @@ class LLEnableEditPhysics : public view_listener_t bool is_object_sittable() { +// [RLVa:KB] - Checked: 2010-03-06 (RLVa-1.2.0c) | Added: RLVa-1.1.0j + // RELEASE-RLVa: [SL-2.2.0] Make sure we're examining the same object that handle_sit_or_stand() will request a sit for + if (rlv_handler_t::isEnabled()) + { + const LLPickInfo& pick = LLToolPie::getInstance()->getPick(); + if ( (pick.mObjectID.notNull()) && (!RlvActions::canSit(pick.getObject(), pick.mObjectOffset)) ) + return false; + } +// [/RLVa:KB] + LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); if (object && object->getPCode() == LL_PCODE_VOLUME) @@ -4002,8 +4096,23 @@ void handle_object_sit_or_stand() // get object selection offset - if (object && object->getPCode() == LL_PCODE_VOLUME) +// if (object && object->getPCode() == LL_PCODE_VOLUME) +// [RLVa:KB] - Checked: 2010-03-06 (RLVa-1.2.0c) | Modified: RLVa-1.2.0c + if ( (object && object->getPCode() == LL_PCODE_VOLUME) && + ((!rlv_handler_t::isEnabled()) || (RlvActions::canSit(object, pick.mObjectOffset))) ) +// [/RLVa:KB] { +// [RLVa:KB] - Checked: 2010-08-29 (RLVa-1.2.1c) | Added: RLVa-1.2.1c + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_STANDTP)) && (isAgentAvatarValid()) ) + { + if (gAgentAvatarp->isSitting()) + { + gAgent.standUp(); + return; + } + gRlvHandler.setSitSource(gAgent.getPositionGlobal()); + } +// [/RLVa:KB] gMessageSystem->newMessageFast(_PREHASH_AgentRequestSit); gMessageSystem->nextBlockFast(_PREHASH_AgentData); @@ -4033,6 +4142,11 @@ class LLLandSit : public view_listener_t { bool handleEvent(const LLSD& userdata) { +// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.2.1f + if ( (rlv_handler_t::isEnabled()) && ((!RlvActions::canStand()) || (gRlvHandler.hasBehaviour(RLV_BHVR_SIT))) ) + return true; +// [/RLVa:KB] + gAgent.standUp(); LLViewerParcelMgr::getInstance()->deselectLand(); @@ -4577,6 +4691,17 @@ void handle_take_copy() { if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return; +// [RLVa:KB] - Checked: 2010-03-07 (RLVa-1.2.0c) | Modified: RLVa-1.2.0a + if ( (rlv_handler_t::isEnabled()) && (!RlvActions::canStand()) ) + { + // Allow only if the avie isn't sitting on any of the selected objects + LLObjectSelectionHandle hSel = LLSelectMgr::getInstance()->getSelection(); + RlvSelectIsSittingOn f(gAgentAvatarp); + if ( (hSel.notNull()) && (hSel->getFirstRootNode(&f, TRUE) != NULL) ) + return; + } +// [/RLVa:KB] + const LLUUID category_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OBJECT); derez_objects(DRD_ACQUIRE_TO_AGENT_INVENTORY, category_id); } @@ -4591,7 +4716,10 @@ class LLObjectReturn : public view_listener_t bool handleEvent(const LLSD& userdata) { if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return true; - +// [RLVa:KB] - Checked: 2010-03-24 (RLVa-1.4.0a) | Modified: RLVa-1.0.0b + if ( (rlv_handler_t::isEnabled()) && (!rlvCanDeleteOrReturn()) ) return true; +// [/RLVa:KB] + mObjectSelection = LLSelectMgr::getInstance()->getEditSelection(); // Save selected objects, so that we still know what to return after the confirmation dialog resets selection. @@ -4638,6 +4766,12 @@ class LLObjectEnableReturn : public view_listener_t // Do not enable if nothing selected return false; } +// [RLVa:KB] - Checked: 2011-05-28 (RLVa-1.4.0a) | Modified: RLVa-1.4.0a + if ( (rlv_handler_t::isEnabled()) && (!rlvCanDeleteOrReturn()) ) + { + return false; + } +// [/RLVa:KB] #ifdef HACKED_GODLIKE_VIEWER bool new_value = true; #else @@ -4666,11 +4800,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 + if ( (LLSelectMgr::getInstance()->getSelection()->isEmpty()) || ((rlv_handler_t::isEnabled()) && (!rlvCanDeleteOrReturn())) ) +// [/RLVa:KB] { return; } - + BOOL you_own_everything = TRUE; BOOL locked_but_takeable_object = FALSE; LLUUID category_id; @@ -4813,7 +4950,10 @@ bool confirm_take(const LLSD& notification, const LLSD& response, LLObjectSelect // one item selected can be copied to inventory. BOOL enable_take() { - if (sitting_on_selection()) +// if (sitting_on_selection()) +// [RLVa:KB] - Checked: 2010-03-24 (RLVa-1.2.0e) | Modified: RLVa-1.0.0b + if ( (sitting_on_selection()) || ((rlv_handler_t::isEnabled()) && (!rlvCanDeleteOrReturn())) ) +// [/RLVa:KB] { return FALSE; } @@ -5279,8 +5419,12 @@ class LLToolsReleaseKeys : public view_listener_t { bool handleEvent(const LLSD& userdata) { - gAgent.forceReleaseControls(); +// [RLVa:KB] - Checked: 2010-04-19 (RLVa-1.2.0f) | Modified: RLVa-1.0.5a + if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_REMOVE)) ) + return true; +// [/RLVa:KB] + gAgent.forceReleaseControls(); return true; } }; @@ -5289,7 +5433,11 @@ class LLToolsEnableReleaseKeys : public view_listener_t { bool handleEvent(const LLSD& userdata) { - return gAgent.anyControlGrabbed(); +// [RLVa:KB] - Checked: 2010-04-19 (RLVa-1.2.0f) | Modified: RLVa-1.0.5a + return (gAgent.anyControlGrabbed()) && + ( (!rlv_handler_t::isEnabled()) || (!gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_REMOVE)) ); +// [/RLVa:KB] +// return gAgent.anyControlGrabbed(); } }; @@ -5686,6 +5834,11 @@ void show_debug_menus() gMenuBarView->setItemVisible("Advanced", debug); // gMenuBarView->setItemEnabled("Advanced", debug); // Don't disable Advanced keyboard shortcuts when hidden + +// [RLVa:KB] - Checked: 2011-08-16 (RLVa-1.4.0b) | Modified: RLVa-1.4.0b + // NOTE: this is supposed to execute whether RLVa is enabled or not + rlvMenuToggleVisible(); +// [/RLVa:KB] gMenuBarView->setItemVisible("Debug", qamode); gMenuBarView->setItemEnabled("Debug", qamode); @@ -5801,16 +5954,16 @@ class LLWorldAlwaysRun : public view_listener_t if (gAgent.getAlwaysRun()) { gAgent.clearAlwaysRun(); - gAgent.clearRunning(); +// gAgent.clearRunning(); } else { gAgent.setAlwaysRun(); - gAgent.setRunning(); +// gAgent.setRunning(); } // tell the simulator. - gAgent.sendWalkRun(gAgent.getAlwaysRun()); +// gAgent.sendWalkRun(gAgent.getAlwaysRun()); // Update Movement Controls according to AlwaysRun mode LLFloaterMove::setAlwaysRunMode(gAgent.getAlwaysRun()); @@ -5865,6 +6018,11 @@ class LLWorldCreateLandmark : public view_listener_t { bool handleEvent(const LLSD& userdata) { +// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.4.5) | Added: RLVa-1.0.0 + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) + return true; +// [/RLVa:KB] + LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "create_landmark")); return true; @@ -5875,12 +6033,24 @@ class LLWorldPlaceProfile : public view_listener_t { bool handleEvent(const LLSD& userdata) { +// [RLVa:KB] - Checked: 2012-02-08 (RLVa-1.4.5) | Added: RLVa-1.4.5 + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) + return true; +// [/RLVa:KB] + LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "agent")); return true; } }; +// [RLVa:KB] - Checked: 2012-02-08 (RLVa-1.4.5) | Added: RLVa-1.4.5 +bool enable_place_profile() +{ + return LLFloaterSidePanelContainer::canShowPanel("places", LLSD().with("type", "agent")); +} +// [/RLVa:KB] + void handle_look_at_selection(const LLSD& param) { const F32 PADDING_FACTOR = 1.75f; @@ -5950,7 +6120,10 @@ class LLAvatarInviteToGroup : public view_listener_t bool handleEvent(const LLSD& userdata) { LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); - if(avatar) +// if(avatar) +// [RLVa:KB] - Checked: RLVa-1.2.0 + if ( (avatar) && (RlvActions::canShowName(RlvActions::SNC_DEFAULT, avatar->getID())) ) +// [/RLVa:KB] { LLAvatarActions::inviteToGroup(avatar->getID()); } @@ -5963,7 +6136,10 @@ class LLAvatarAddFriend : public view_listener_t bool handleEvent(const LLSD& userdata) { LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); - if(avatar && !LLAvatarActions::isFriend(avatar->getID())) +// if(avatar && !LLAvatarActions::isFriend(avatar->getID())) +// [RLVa:KB] - Checked: RLVa-1.2.0 + if ( (avatar && !LLAvatarActions::isFriend(avatar->getID())) && (RlvActions::canShowName(RlvActions::SNC_DEFAULT, avatar->getID())) ) +// [/RLVa:KB] { request_friendship(avatar->getID()); } @@ -6004,7 +6180,10 @@ class LLAvatarAddContact : public view_listener_t bool handleEvent(const LLSD& userdata) { LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); - if(avatar) +// if(avatar) +// [RLVa:KB] - Checked: RLVa-1.2.0 + if ( (avatar) && (RlvActions::canShowName(RlvActions::SNC_DEFAULT, avatar->getID())) ) +// [/RLVa:KB] { create_inventory_callingcard(avatar->getID()); } @@ -6068,7 +6247,10 @@ bool enable_pay_avatar() { LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); LLVOAvatar* avatar = find_avatar_from_object(obj); - return (avatar != NULL); +// return (avatar != NULL); +// [RLVa:KB] - Checked: RLVa-1.2.1 + return (avatar != NULL) && (RlvActions::canShowName(RlvActions::SNC_DEFAULT, avatar->getID())); +// [/RLVa:KB] } bool enable_pay_object() @@ -6088,7 +6270,10 @@ bool enable_pay_object() bool enable_object_stand_up() { // 'Object Stand Up' menu item is enabled when agent is sitting on selection - return sitting_on_selection(); +// return sitting_on_selection(); +// [RLVa:KB] - Checked: 2010-07-24 (RLVa-1.2.0g) | Added: RLVa-1.2.0g + return sitting_on_selection() && ( (!rlv_handler_t::isEnabled()) || (RlvActions::canStand()) ); +// [/RLVa:KB] } bool enable_object_sit(LLUICtrl* ctrl) @@ -6113,6 +6298,17 @@ bool enable_object_sit(LLUICtrl* ctrl) gMenuHolder->childSetValue(item_name, get_default_item_label(item_name)); } } + +// [RLVa:KB] - Checked: 2010-04-01 (RLVa-1.2.0c) | Modified: RLVa-1.2.0c + // RELEASE-RLVA: [SL-2.2.0] Make this match what happens in handle_object_sit_or_stand() + if (rlv_handler_t::isEnabled()) + { + const LLPickInfo& pick = LLToolPie::getInstance()->getPick(); + if (pick.mObjectID.notNull()) + sitting_on_sel = !RlvActions::canSit(pick.getObject(), pick.mObjectOffset); + } +// [/RLVa:KB] + return !sitting_on_sel && is_object_sittable(); } @@ -6367,7 +6563,10 @@ class LLShowAgentProfile : public view_listener_t } LLVOAvatar* avatar = find_avatar_from_object(agent_id); - if (avatar) +// if (avatar) +// [RLVa:KB] - Checked: RLVa-1.2.0 + if ( (avatar) && ((RlvActions::canShowName(RlvActions::SNC_DEFAULT, agent_id)) || (gAgent.getID() == agent_id)) ) +// [/RLVa:KB] { LLAvatarActions::showProfile(avatar->getID()); } @@ -6516,6 +6715,19 @@ class LLObjectAttachToAvatar : public view_listener_t LLViewerJointAttachment* attachment_point = NULL; if (index > 0) attachment_point = get_if_there(gAgentAvatarp->mAttachmentPoints, index, (LLViewerJointAttachment*)NULL); + +// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.2.1f + // 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) && (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; + } +// [/RLVa:KB] + confirmReplaceAttachment(0, attachment_point); } return true; @@ -6660,6 +6872,24 @@ class LLAttachmentDrop : public view_listener_t { bool handleEvent(const LLSD& userdata) { +// [RLVa:KB] - Checked: 2010-03-15 (RLVa-1.2.0e) | Modified: RLVa-1.0.5 + if (rlv_handler_t::isEnabled()) + { + if (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_REMOVE)) + { + // NOTE: copy/paste of the code in enable_detach() + LLObjectSelectionHandle hSelect = LLSelectMgr::getInstance()->getSelection(); + RlvSelectHasLockedAttach f; + if ( (hSelect->isAttachment()) && (hSelect->getFirstRootNode(&f, FALSE) != NULL) ) + return true; + } + if (gRlvHandler.hasBehaviour(RLV_BHVR_REZ)) + { + return true; + } + } +// [/RLVa:KB] + LLSD payload; LLViewerObject *object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); @@ -6685,14 +6915,21 @@ class LLAttachmentDetachFromPoint : public view_listener_t { uuid_vec_t ids_to_remove; const LLViewerJointAttachment *attachment = get_if_there(gAgentAvatarp->mAttachmentPoints, user_data.asInteger(), (LLViewerJointAttachment*)NULL); - if (attachment->getNumObjects() > 0) +// 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] { 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; ids_to_remove.push_back(attached_object->getAttachmentItemID()); +// [/RLVa:KB] } } if (!ids_to_remove.empty()) @@ -6705,6 +6942,10 @@ class LLAttachmentDetachFromPoint : public view_listener_t static bool onEnableAttachmentLabel(LLUICtrl* ctrl, const LLSD& data) { +// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.2.1f + // RELEASE-RLVa: [SL-2.2.0] When attaching to a specific point the object will be "add attached" [see LLSelectMgr::sendAttach()] + bool fRlvEnable = true; +// [/RLVa:KB] std::string label; LLMenuItemGL* menu = dynamic_cast<LLMenuItemGL*>(ctrl); if (menu) @@ -6729,9 +6970,18 @@ static bool onEnableAttachmentLabel(LLUICtrl* ctrl, const LLSD& data) } } } + +// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.2.1f + if (rlv_handler_t::isEnabled()) + fRlvEnable = (!gRlvAttachmentLocks.isLockedAttachmentPoint(attachment, RLV_LOCK_ADD)); +// [/RLVa:KB] + menu->setLabel(label); } - return true; +// return true; +// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0a) | Added: RLVa-1.2.0a + return fRlvEnable; +// [/RLVa:KB] } class LLAttachmentDetach : public view_listener_t @@ -6770,6 +7020,17 @@ class LLAttachmentDetach : public view_listener_t return true; } +// [RLVa:KB] - Checked: 2010-03-15 (RLVa-1.2.0a) | Modified: RLVa-1.0.5 + // NOTE: copy/paste of the code in enable_detach() + if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_REMOVE)) ) + { + LLObjectSelectionHandle hSelect = LLSelectMgr::getInstance()->getSelection(); + RlvSelectHasLockedAttach f; + if ( (hSelect->isAttachment()) && (hSelect->getFirstRootNode(&f, FALSE) != NULL) ) + return true; + } +// [/RLVa:KB] + LLAppearanceMgr::instance().removeItemFromAvatar(object->getAttachmentItemID()); return true; @@ -6846,7 +7107,10 @@ class LLAttachmentEnableDrop : public view_listener_t } //now check to make sure that the item is actually in the inventory before we enable dropping it - bool new_value = enable_detach() && can_build && item; +// bool new_value = enable_detach() && can_build && item; +// [RLVa:KB] - Checked: 2010-03-24 (RLVa-1.0.0b) | Modified: RLVa-1.0.0b + bool new_value = enable_detach() && can_build && item && (!gRlvHandler.hasBehaviour(RLV_BHVR_REZ)); +// [/RLVa:KB] return new_value; } @@ -6871,6 +7135,20 @@ BOOL enable_detach(const LLSD&) // ...if it's you, good to detach if (avatar->getID() == gAgent.getID()) { +// [RLVa:KB] - Checked: 2010-03-15 (RLVa-1.2.0a) | Modified: RLVa-1.0.5 + // 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: [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 f; + if ( (hSelect->isAttachment()) && (hSelect->getFirstRootNode(&f, FALSE) != NULL) ) + return FALSE; + } +// [/RLVa:KB] return TRUE; } @@ -6890,8 +7168,33 @@ 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() +//BOOL object_selected_and_point_valid() +// [RLVa:KB] - Checked: 2010-03-16 (RLVa-1.2.0a) | Added: RLVa-1.2.0a +BOOL object_selected_and_point_valid(const LLSD& sdParam) +// [/RLVa:KB] { +// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.2.1f + if (rlv_handler_t::isEnabled()) + { + if (!isAgentAvatarValid()) + return FALSE; + + // RELEASE-RLVa: [SL-2.2.0] Look at the caller graph for this function on every new release + // - object_is_wearable() => dead code [sdParam == 0 => default attach point => OK!] + // - enabler set up in LLVOAvatarSelf::buildMenus() => Rezzed prim / Put On / "Attach To" [sdParam == idxAttachPt] + // - "Object.EnableWear" enable => Rezzed prim / Put On / "Wear" or "Add" [sdParam blank] + // RELEASE-RLVa: [SL-2.2.0] If 'idxAttachPt != 0' then the object will be "add attached" [see LLSelectMgr::sendAttach()] + const LLViewerJointAttachment* pAttachPt = + get_if_there(gAgentAvatarp->mAttachmentPoints, sdParam.asInteger(), (LLViewerJointAttachment*)NULL); + 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; + } + } +// [/RLVa:KB] + LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); for (LLObjectSelection::root_iterator iter = selection->root_begin(); iter != selection->root_end(); iter++) @@ -6920,9 +7223,12 @@ BOOL object_selected_and_point_valid() } +// [RLVa:KB] - Checked: 2010-03-16 (RLVa-1.2.0a) | Added: RLVa-1.2.0a +/* BOOL object_is_wearable() { - if (!object_selected_and_point_valid()) +// if (!object_selected_and_point_valid()) + if (!object_selected_and_point_valid(LLSD(0))) { return FALSE; } @@ -6942,7 +7248,8 @@ BOOL object_is_wearable() } return FALSE; } - +*/ +// [/RLVa:KB] class LLAttachmentPointFilled : public view_listener_t { @@ -6952,7 +7259,12 @@ class LLAttachmentPointFilled : public view_listener_t LLVOAvatar::attachment_map_t::iterator found_it = gAgentAvatarp->mAttachmentPoints.find(user_data.asInteger()); if (found_it != gAgentAvatarp->mAttachmentPoints.end()) { - enable = found_it->second->getNumObjects() > 0; +// enable = found_it->second->getNumObjects() > 0; +// [RLVa:KB] - Checked: 2010-03-04 (RLVa-1.2.0a) | Added: RLVa-1.2.0a + // Enable the option if there is at least one attachment on this attachment point that can be detached + enable = (found_it->second->getNumObjects() > 0) && + ((!rlv_handler_t::isEnabled()) || (gRlvAttachmentLocks.canDetach(found_it->second))); +// [/RLVa:KB] } return enable; } @@ -6963,7 +7275,10 @@ class LLAvatarSendIM : public view_listener_t bool handleEvent(const LLSD& userdata) { LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); - if(avatar) +// if(avatar) +// [RLVa:KB] - Checked: RLVa-1.2.0 + if ( (avatar) && (RlvActions::canShowName(RlvActions::SNC_DEFAULT, avatar->getID())) ) +// [/RLVa:KB] { LLAvatarActions::startIM(avatar->getID()); } @@ -6976,7 +7291,10 @@ class LLAvatarCall : public view_listener_t bool handleEvent(const LLSD& userdata) { LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); - if(avatar) +// if(avatar) +// [RLVa:KB] - Checked: RLVa-1.2.0 + if ( (avatar) && (RlvActions::canShowName(RlvActions::SNC_DEFAULT, avatar->getID())) ) +// [/RLVa:KB] { LLAvatarActions::startCall(avatar->getID()); } @@ -6984,6 +7302,19 @@ class LLAvatarCall : public view_listener_t } }; +// [RLVa:KB] - Checked: RLVa-1.2.1 +bool enable_avatar_call() +{ + if (RlvActions::isRlvEnabled()) + { + const LLVOAvatar* pAvatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); + if ((!pAvatar) || (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, pAvatar->getID()))) + return false; + } + return LLAvatarActions::canCall(); +} +// [/RLVa:KB] + namespace { struct QueueObjects : public LLSelectedNodeFunctor @@ -7051,6 +7382,17 @@ class LLToolsSelectedScriptAction : public view_listener_t { bool handleEvent(const LLSD& userdata) { +// [RLVa:KB] - Checked: 2010-04-19 (RLVa-1.2.0f) | Modified: RLVa-1.0.5a + // 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()) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_REMOVE)) ) + { + LLObjectSelectionHandle hSel = LLSelectMgr::getInstance()->getSelection(); + RlvSelectHasLockedAttach f; + if ( (hSel->isAttachment()) && (hSel->getFirstNode(&f) != NULL) ) + return true; + } +// [/RLVa:KB] + std::string action = userdata.asString(); bool mono = false; std::string msg, name; @@ -7194,12 +7536,30 @@ void handle_selected_material_info() void handle_test_male(void*) { +// [RLVa:KB] - Checked: 2010-03-19 (RLVa-1.2.0c) | Modified: RLVa-1.2.0a + // 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; + } +// [/RLVa:KB] + LLAppearanceMgr::instance().wearOutfitByName("Male Shape & Outfit"); //gGestureList.requestResetFromServer( TRUE ); } void handle_test_female(void*) { +// [RLVa:KB] - Checked: 2010-03-19 (RLVa-1.2.0c) | Modified: RLVa-1.2.0a + // 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; + } +// [/RLVa:KB] + LLAppearanceMgr::instance().wearOutfitByName("Female Shape & Outfit"); //gGestureList.requestResetFromServer( FALSE ); } @@ -7368,6 +7728,22 @@ class LLSomethingSelectedNoHUD : public view_listener_t static bool is_editable_selected() { +// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.0.5a + // 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 f; + if ( (hSelection->isAttachment()) && (hSelection->getFirstRootNode(&f)) ) + { + return false; + } + } +// [/RLVa:KB] + return (LLSelectMgr::getInstance()->getSelection()->getFirstEditableObject() != NULL); } @@ -7412,7 +7788,11 @@ bool enable_object_take_copy() { virtual bool apply(LLViewerObject* obj) { - return (!obj->permCopy() || obj->isAttachment()); +// return (!obj->permCopy() || obj->isAttachment()); +// [RLVa:KB] - Checked: 2010-04-01 (RLVa-1.2.0c) | Modified: RLVa-1.0.0g + return (!obj->permCopy() || obj->isAttachment()) || + ( (gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) && (isAgentAvatarValid()) && (gAgentAvatarp->getRoot() == obj) ); +// [/RLVa:KB] } } func; const bool firstonly = true; @@ -7517,7 +7897,10 @@ class LLWorldEnableCreateLandmark : public view_listener_t { bool handleEvent(const LLSD& userdata) { - return !LLLandmarkActions::landmarkAlreadyExists(); +// return !LLLandmarkActions::landmarkAlreadyExists(); +// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.4.5) | Added: RLVa-1.2.1 + return (!LLLandmarkActions::landmarkAlreadyExists()) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)); +// [/RLVa:KB] } }; @@ -7538,6 +7921,10 @@ class LLWorldEnableTeleportHome : public view_listener_t LLViewerRegion* regionp = gAgent.getRegion(); bool agent_on_prelude = (regionp && regionp->isPrelude()); bool enable_teleport_home = gAgent.isGodlike() || !agent_on_prelude; +// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.2.1f + enable_teleport_home &= + (!rlv_handler_t::isEnabled()) || ((!gRlvHandler.hasBehaviour(RLV_BHVR_TPLM)) && (!gRlvHandler.hasBehaviour(RLV_BHVR_TPLOC))); +// [/RLVa:KB] return enable_teleport_home; } }; @@ -8008,7 +8395,10 @@ class LLViewHighlightTransparent : public view_listener_t { bool handleEvent(const LLSD& userdata) { - LLDrawPoolAlpha::sShowDebugAlpha = !LLDrawPoolAlpha::sShowDebugAlpha; +// LLDrawPoolAlpha::sShowDebugAlpha = !LLDrawPoolAlpha::sShowDebugAlpha; +// [RLVa:KB] - Checked: 2010-11-29 (RLVa-1.3.0c) | Modified: RLVa-1.3.0c + LLDrawPoolAlpha::sShowDebugAlpha = (!LLDrawPoolAlpha::sShowDebugAlpha) && (!gRlvHandler.hasBehaviour(RLV_BHVR_EDIT)); +// [/RLVa:KB] return true; } }; @@ -8220,6 +8610,11 @@ class LLViewShowHUDAttachments : public view_listener_t { bool handleEvent(const LLSD& userdata) { +// [RLVa:KB] - Checked: 2010-04-19 (RLVa-1.2.1a) | Modified: RLVa-1.0.0c + if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedHUD()) && (LLPipeline::sShowHUDAttachments) ) + return true; +// [/RLVa:KB] + LLPipeline::sShowHUDAttachments = !LLPipeline::sShowHUDAttachments; return true; } @@ -8240,8 +8635,15 @@ class LLEditEnableTakeOff : public view_listener_t { std::string clothing = userdata.asString(); LLWearableType::EType type = LLWearableType::typeNameToType(clothing); - if (type >= LLWearableType::WT_SHAPE && type < LLWearableType::WT_COUNT) +// if (type >= LLWearableType::WT_SHAPE && type < LLWearableType::WT_COUNT) +// [RLVa:KB] - Checked: 2010-03-20 (RLVa-1.2.0c) | Modified: RLVa-1.2.0a + // NOTE: see below - enable if there is at least one wearable on this type that can be removed + if ( (type >= LLWearableType::WT_SHAPE && type < LLWearableType::WT_COUNT) && + ((!rlv_handler_t::isEnabled()) || (gRlvWearableLocks.canRemove(type))) ) +// [/RLVa:KB] + { return LLAgentWearables::selfHasWearable(type); + } return false; } }; @@ -8262,6 +8664,22 @@ class LLEditTakeOff : public view_listener_t { // MULTI-WEARABLES: assuming user wanted to remove top shirt. U32 wearable_index = gAgentWearables.getWearableCount(type) - 1; + +// [RLVa:KB] - Checked: 2010-06-09 (RLVa-1.2.0g) | Added: RLVa-1.2.0g + if ( (rlv_handler_t::isEnabled()) && (gRlvWearableLocks.hasLockedWearable(type)) ) + { + // We'll use the first wearable we come across that can be removed (moving from top to bottom) + for (; wearable_index >= 0; wearable_index--) + { + const LLViewerWearable* pWearable = gAgentWearables.getViewerWearable(type, wearable_index); + if (!gRlvWearableLocks.isLockedWearable(pWearable)) + break; + } + if (wearable_index < 0) + return true; // No wearable found that can be removed + } +// [/RLVa:KB] + LLUUID item_id = gAgentWearables.getWearableItemID(type,wearable_index); LLAppearanceMgr::instance().removeItemFromAvatar(item_id); } @@ -8305,6 +8723,11 @@ class LLWorldEnvSettings : public view_listener_t { bool handleEvent(const LLSD& userdata) { +// [RLVa:KB] - Checked: 2010-03-18 (RLVa-1.2.0a) | Modified: RLVa-1.0.0g + if (gRlvHandler.hasBehaviour(RLV_BHVR_SETENV)) + return true; +// [/RLVa:KB] + std::string tod = userdata.asString(); if (tod == "editor") @@ -8569,6 +8992,9 @@ void show_topinfobar_context_menu(LLView* ctrl, S32 x, S32 y) { landmark_item->setLabel(LLTrans::getString("EditLandmarkNavBarMenu")); } +// [RLVa:KB] - Checked: 2012-02-07 (RLVa-1.4.5) | Added: RLVa-1.4.5 + landmark_item->setEnabled(!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)); +// [/RLVa:KB] if(gMenuHolder->hasVisibleMenu()) { @@ -8724,6 +9150,9 @@ void initialize_menus() view_listener_t::addMenu(new LLWorldSetDoNotDisturb(), "World.SetDoNotDisturb"); view_listener_t::addMenu(new LLWorldEnableCreateLandmark(), "World.EnableCreateLandmark"); +// [RLVa:KB] + enable.add("World.EnablePlaceProfile", boost::bind(&enable_place_profile)); +// [/RLVa:KB] view_listener_t::addMenu(new LLWorldEnableSetHomeLocation(), "World.EnableSetHomeLocation"); view_listener_t::addMenu(new LLWorldEnableTeleportHome(), "World.EnableTeleportHome"); view_listener_t::addMenu(new LLWorldEnableBuyLand(), "World.EnableBuyLand"); @@ -8989,7 +9418,10 @@ void initialize_menus() commit.add("Avatar.ShowInspector", boost::bind(&handle_avatar_show_inspector)); view_listener_t::addMenu(new LLAvatarSendIM(), "Avatar.SendIM"); view_listener_t::addMenu(new LLAvatarCall(), "Avatar.Call"); - enable.add("Avatar.EnableCall", boost::bind(&LLAvatarActions::canCall)); +// enable.add("Avatar.EnableCall", boost::bind(&LLAvatarActions::canCall)); +// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) | Added: RLVa-1.2.1b + enable.add("Avatar.EnableCall", boost::bind(&enable_avatar_call)); +// [/RLVa:KB] view_listener_t::addMenu(new LLAvatarReportAbuse(), "Avatar.ReportAbuse"); view_listener_t::addMenu(new LLAvatarToggleMyProfile(), "Avatar.ToggleMyProfile"); enable.add("Avatar.IsMyProfileOpen", boost::bind(&my_profile_visible)); @@ -9022,7 +9454,10 @@ void initialize_menus() enable.add("Object.EnableOpen", boost::bind(&enable_object_open)); enable.add("Object.EnableTouch", boost::bind(&enable_object_touch, _1)); enable.add("Object.EnableDelete", boost::bind(&enable_object_delete)); - enable.add("Object.EnableWear", boost::bind(&object_selected_and_point_valid)); +// enable.add("Object.EnableWear", boost::bind(&object_selected_and_point_valid)); +// [RLVa:KB] - Checked: 2010-03-16 (RLVa-1.2.0a) | Added: RLVa-1.2.0a + enable.add("Object.EnableWear", boost::bind(&object_selected_and_point_valid, _2)); +// [/RLVa:KB] enable.add("Object.EnableStandUp", boost::bind(&enable_object_stand_up)); enable.add("Object.EnableSit", boost::bind(&enable_object_sit, _1)); @@ -9092,4 +9527,13 @@ void initialize_menus() view_listener_t::addMenu(new LLEditableSelected(), "EditableSelected"); view_listener_t::addMenu(new LLEditableSelectedMono(), "EditableSelectedMono"); view_listener_t::addMenu(new LLToggleUIHints(), "ToggleUIHints"); + +// [RLVa:KB] - Checked: RLVa-2.0.0 + enable.add("RLV.MainToggleVisible", boost::bind(&rlvMenuMainToggleVisible, _1)); + if (RlvActions::isRlvEnabled()) + { + enable.add("RLV.CanShowName", boost::bind(&rlvMenuCanShowName)); + enable.add("RLV.EnableIfNot", boost::bind(&rlvMenuEnableIfNot, _2)); + } +// [/RLVa:KB] } diff --git a/indra/newview/llviewermenu.h b/indra/newview/llviewermenu.h index b7bdf0015775bb61bfd4814f0019267c462ef3f1..36bf472cad58c5d37d0a9837e28d6b5f8e80fb15 100644 --- a/indra/newview/llviewermenu.h +++ b/indra/newview/llviewermenu.h @@ -38,6 +38,10 @@ class LLParcelSelection; class LLObjectSelection; class LLSelectNode; +// [RLVa:KB] - Checked: RLVa-2.0.0 +void set_use_wireframe(BOOL useWireframe); +// [/RLVa:KB] + void initialize_edit_menu(); void initialize_spellcheck_menu(); void init_menus(); diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 92df3866f72634a6bf7b78a7872f29aaf07f832e..8d1f3c1c2c27e8be052954bc295115ca56d3882d 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -114,6 +114,12 @@ #include "llpanelplaceprofile.h" #include "llviewerregion.h" #include "llfloaterregionrestarting.h" +// [RLVa:KB] - Checked: 2010-03-09 (RLVa-1.2.0a) +#include "rlvactions.h" +#include "rlvhandler.h" +#include "rlvinventory.h" +#include "rlvui.h" +// [/RLVa:KB] #include <boost/algorithm/string/split.hpp> // #include <boost/regex.hpp> @@ -237,7 +243,18 @@ bool friendship_offer_callback(const LLSD& notification, const LLSD& response) // modified_form->setElementEnabled("Accept", false); // modified_form->setElementEnabled("Decline", false); // notification_ptr->updateForm(modified_form); - // notification_ptr->repost(); +// [SL:KB] - Patch: UI-Notifications | Checked: 2013-05-09 (Catznip-3.5) +// // Assume that any offer notification with "getCanBeStored() == true" is the result of RLVa routing it to the notifcation syswell +// /*const*/ LLNotificationsUI::LLScreenChannel* pChannel = LLNotificationsUI::LLChannelManager::instance().getNotificationScreenChannel(); +// /*const*/ LLNotificationsUI::LLToast* pToast = (pChannel) ? pChannel->getToastByNotificationID(notification["id"].asUUID()) : NULL; +// if ( (!pToast) || (!pToast->getCanBeStored()) ) +// { +// [/SL:KB] +// notification_ptr->repost(); +// [SL:KB] - Patch: UI-Notifications | Checked: 2013-05-09 (Catznip-3.5) +// } +// [/SL:KB] + } return false; @@ -1493,7 +1510,14 @@ void LLOfferInfo::send_auto_receive_response(void) if(IM_INVENTORY_OFFERED == mIM) { // add buddy to recent people list - LLRecentPeople::instance().add(mFromID); +// LLRecentPeople::instance().add(mFromID); +// [RLVa:KB] - Checked: RLVa-2.0.1 + // RELEASE-RLVa: [RLVa-2.0.1] Make sure this stays in sync with the condition in inventory_offer_handler() + bool fRlvCanShowName = (!RlvActions::isRlvEnabled()) || + (RlvActions::canShowName(RlvActions::SNC_DEFAULT, mFromID)) || (!RlvUtil::isNearbyAgent(mFromID)) || (RlvUIEnabler::hasOpenIM(mFromID)) || (RlvUIEnabler::hasOpenProfile(mFromID)); + if (fRlvCanShowName) + LLRecentPeople::instance().add(mFromID); +// [/RLVa:KB] } } @@ -1563,6 +1587,18 @@ 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-04-18 (RLVa-1.2.0) + if ( (rlv_handler_t::isEnabled()) && (!RlvSettings::getForbidGiveToRLV()) && (LLAssetType::AT_CATEGORY == mType) && (mDesc.find(RLV_PUTINV_PREFIX) == 0) ) + { + RlvGiveToRLVAgentOffer* pOfferObserver = new RlvGiveToRLVAgentOffer(mObjectID); + pOfferObserver->startFetch(); + if (pOfferObserver->isFinished()) + pOfferObserver->done(); + else + gInventory.addObserver(pOfferObserver); + } +// [/RLVa:KB] + if (gSavedSettings.getBOOL("ShowOfferedInventory")) { LLOpenAgentOffer* open_agent_offer = new LLOpenAgentOffer(mObjectID, from_string); @@ -1744,6 +1780,7 @@ bool LLOfferInfo::inventory_task_offer_callback(const LLSD& notification, const } else { +/* std::string full_name; if (gCacheName->getFullName(mFromID, full_name)) { @@ -1757,6 +1794,22 @@ bool LLOfferInfo::inventory_task_offer_callback(const LLSD& notification, const + mFromName + LLTrans::getString("'")+" " + LLTrans::getString("InvOfferOwnedByUnknownUser"); chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedByUnknownUser"); } +*/ +// [SL:KB] - Checked: 2010-11-02 (RLVa-1.2.2a) | Added: RLVa-1.2.2a + std::string name_slurl = LLSLURL("agent", mFromID, "about").getSLURLString(); + +// [RLVa:KB] - Checked: RLVa-2.0.1 + // RELEASE-RLVa: [RLVa-2.0.1] Make sure this stays in sync with the condition in inventory_offer_handler() + bool fRlvCanShowName = (!RlvActions::isRlvEnabled()) || + (RlvActions::canShowName(RlvActions::SNC_DEFAULT, mFromID)) || (!RlvUtil::isNearbyAgent(mFromID)) || (RlvUIEnabler::hasOpenIM(mFromID)) || (RlvUIEnabler::hasOpenProfile(mFromID)); + if (!fRlvCanShowName) + name_slurl = LLSLURL("agent", mFromID, "rlvanonym").getSLURLString(); +// [/RLVa:KB] + + from_string = LLTrans::getString("InvOfferAnObjectNamed") + " "+ LLTrans::getString("'") + mFromName + + LLTrans::getString("'")+" " + LLTrans::getString("InvOfferOwnedBy") + name_slurl; + chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedBy") + " " + name_slurl; +// [/SL:KB] } } else @@ -1766,12 +1819,38 @@ bool LLOfferInfo::inventory_task_offer_callback(const LLSD& notification, const bool is_do_not_disturb = gAgent.isDoNotDisturb(); +// [RLVa:KB] - Checked: 2010-09-23 (RLVa-1.2.1) + bool fRlvNotifyAccepted = false; +// [/RLVa:KB] switch(button) { case IOR_ACCEPT: // 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.1) + // Only treat the offer as 'Give to #RLV' 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 LLUUID& idRlvRoot = RlvInventory::instance().getSharedRootID(); + if (idRlvRoot.notNull()) + mFolderID = idRlvRoot; + + fRlvNotifyAccepted = false; // "accepted_in_rlv" is sent from RlvGiveToRLVTaskOffer *after* we have the folder + + 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)); @@ -1780,6 +1859,15 @@ bool LLOfferInfo::inventory_task_offer_callback(const LLSD& notification, const // send the message msg->sendReliable(mHost); +// [RLVa:KB] - Checked: 2010-09-23 (RLVa-1.2.1) + if (fRlvNotifyAccepted) + { + std::string::size_type idxToken = mDesc.find("' ( http://"); + if (std::string::npos != idxToken) + RlvBehaviourNotifyHandler::sendNotification("accepted_in_inv inv_offer " + mDesc.substr(1, idxToken - 1)); + } +// [/RLVa:KB] + //don't spam them if they are getting flooded if (check_offer_throttle(mFromName, true)) { @@ -1824,6 +1912,16 @@ bool LLOfferInfo::inventory_task_offer_callback(const LLSD& notification, const msg->addBinaryDataFast(_PREHASH_BinaryBucket, EMPTY_BINARY_BUCKET, EMPTY_BINARY_BUCKET_SIZE); // 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::sendNotification("declined inv_offer " + mDesc.substr(1, idxToken - 1)); + } +// [/RLVa:KB] if (gSavedSettings.getBOOL("LogInventoryDecline")) { @@ -1832,6 +1930,7 @@ bool LLOfferInfo::inventory_task_offer_callback(const LLSD& notification, const log_message_args["NAME"] = mFromName; log_message = LLTrans::getString("InvOfferDecline", log_message_args); + LLSD args; args["MESSAGE"] = log_message; LLNotificationsUtil::add("SystemMessageTip", args); @@ -1959,6 +2058,9 @@ void inventory_offer_handler(LLOfferInfo* info) } else { +// [SL:KB] - Patch: UI-Notifications | Checked: 2011-04-11 (Catznip-2.5.0a) | Added: Catznip-2.5.0a + args["NAME_LABEL"] = LLSLURL("agent", info->mFromID, "completename").getSLURLString(); +// [/SL:KB] args["NAME_SLURL"] = LLSLURL("agent", info->mFromID, "about").getSLURLString(); } std::string verb = "select?name=" + LLURI::escape(msg); @@ -1969,6 +2071,15 @@ void inventory_offer_handler(LLOfferInfo* info) // Object -> Agent Inventory Offer if (info->mFromObject && !bAutoAccept) { +// [RLVa:KB] - Checked: RLVa-1.2.2 + // Only filter if the object owner is a nearby agent + if ( (RlvActions::isRlvEnabled()) && (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, info->mFromID)) && (RlvUtil::isNearbyAgent(info->mFromID)) ) + { + payload["rlv_shownames"] = TRUE; + args["NAME_SLURL"] = LLSLURL("agent", info->mFromID, "rlvanonym").getSLURLString(); + } +// [/RLVa:KB] + // Inventory Slurls don't currently work for non agent transfers, so only display the object name. args["ITEM_SLURL"] = msg; // Note: sets inventory_task_offer_callback as the callback @@ -1983,6 +2094,18 @@ void inventory_offer_handler(LLOfferInfo* info) } else // Agent -> Agent Inventory Offer { +// [RLVa:KB] - Checked: RLVa-2.0.1 + // Only filter if the offer is from a nearby agent and if there's no open IM session (doesn't necessarily have to be focused) + bool fRlvCanShowName = (!RlvActions::isRlvEnabled()) || + (RlvActions::canShowName(RlvActions::SNC_DEFAULT, info->mFromID)) || (!RlvUtil::isNearbyAgent(info->mFromID)) || (RlvUIEnabler::hasOpenIM(info->mFromID)) || (RlvUIEnabler::hasOpenProfile(info->mFromID)); + if (!fRlvCanShowName) + { + payload["rlv_shownames"] = TRUE; + args["NAME"] = RlvStrings::getAnonym(info->mFromName); + args["NAME_SLURL"] = LLSLURL("agent", info->mFromID, "rlvanonym").getSLURLString(); + } +// [/RLVa:KB] + p.responder = info; // Note: sets inventory_offer_callback as the callback // *TODO fix memory leak @@ -2067,7 +2190,18 @@ bool lure_callback(const LLSD& notification, const LLSD& response) modified_form->setElementEnabled("Teleport", false); modified_form->setElementEnabled("Cancel", false); notification_ptr->updateForm(modified_form); - notification_ptr->repost(); + +// [SL:KB] - Patch: UI-Notifications | Checked: 2013-05-09 (Catznip-3.5) + // Assume that any offer notification with "getCanBeStored() == true" is the result of RLVa routing it to the notifcation syswell + /*const*/ LLNotificationsUI::LLScreenChannel* pChannel = LLNotificationsUI::LLChannelManager::instance().getNotificationScreenChannel(); + /*const*/ LLNotificationsUI::LLToast* pToast = (pChannel) ? pChannel->getToastByNotificationID(notification["id"].asUUID()) : NULL; + if ( (!pToast) || (!pToast->getCanBeStored()) ) + { +// [/SL:KB] + notification_ptr->repost(); +// [SL:KB] - Patch: UI-Notifications | Checked: 2013-05-09 (Catznip-3.5) + } +// [/SL:KB] } return false; @@ -2439,10 +2573,23 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) // do nothing -- don't distract newbies in // Prelude with global IMs } +// [RLVa:KB] - Checked: RLVa-2.0.3 + else if ( (RlvActions::isRlvEnabled()) && (RlvSettings::getEnableIMQuery()) && (offline == IM_ONLINE) && ("@version" == message) && (!is_muted) && ((!accept_im_from_only_friend) || (is_friend)) ) + { + RlvUtil::sendBusyMessage(from_id, RlvStrings::getVersion(LLUUID::null), session_id); + } +// [/RLVa:KB] +// else if (offline == IM_ONLINE +// && is_do_not_disturb +// && from_id.notNull() //not a system message +// && to_id.notNull()) //not global message +// [RLVa:KB] - Checked: 2010-11-30 (RLVa-1.3.0) else if (offline == IM_ONLINE && is_do_not_disturb && from_id.notNull() //not a system message - && to_id.notNull()) //not global message + && to_id.notNull() //not global message + && RlvActions::canReceiveIM(from_id)) +// [/RLVa:KB] { // now store incoming IM in chat history @@ -2512,6 +2659,17 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) mute_im = true; } + +// [RLVa:KB] - Checked: 2010-11-30 (RLVa-1.3.0) + // Don't block offline IMs, or IMs from Lindens + if ( (rlv_handler_t::isEnabled()) && (offline != IM_OFFLINE) && (!RlvActions::canReceiveIM(from_id)) && (!LLMuteList::getInstance()->isLinden(original_name) )) + { + if (!mute_im) + RlvUtil::sendBusyMessage(from_id, RlvStrings::getString(RLV_STRING_BLOCKED_RECVIM_REMOTE), session_id); + buffer = RlvStrings::getString(RLV_STRING_BLOCKED_RECVIM); + } +// [/RLVa:KB] + if (!mute_im) { gIMMgr->addMessage( @@ -2812,7 +2970,13 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) case IM_INVENTORY_ACCEPTED: { - args["NAME"] = LLSLURL("agent", from_id, "completename").getSLURLString();; +// args["NAME"] = LLSLURL("agent", from_id, "completename").getSLURLString();; +// [RLVa:KB] - Checked: RLVa-1.2.2 + // Only anonymize the name if the agent is nearby, there isn't an open IM session to them and their profile isn't open + bool fRlvCanShowName = (!RlvActions::isRlvEnabled()) || + (RlvActions::canShowName(RlvActions::SNC_DEFAULT, from_id)) || (!RlvUtil::isNearbyAgent(from_id)) || (RlvUIEnabler::hasOpenProfile(from_id)) || (RlvUIEnabler::hasOpenIM(from_id)); + args["NAME"] = LLSLURL("agent", from_id, (fRlvCanShowName) ? "completename" : "rlvanonym").getSLURLString();; +// [/RLVa:KB] LLSD payload; payload["from_id"] = from_id; // Passing the "SESSION_NAME" to use it for IM notification logging @@ -2823,7 +2987,13 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) } case IM_INVENTORY_DECLINED: { - args["NAME"] = LLSLURL("agent", from_id, "completename").getSLURLString();; +// args["NAME"] = LLSLURL("agent", from_id, "completename").getSLURLString();; +// [RLVa:KB] - Checked: RLVa-1.2.2 + // Only anonymize the name if the agent is nearby, there isn't an open IM session to them and their profile isn't open + bool fRlvCanShowName = (!RlvActions::isRlvEnabled()) || + (RlvActions::canShowName(RlvActions::SNC_DEFAULT, from_id)) || (!RlvUtil::isNearbyAgent(from_id)) || (RlvUIEnabler::hasOpenProfile(from_id)) || (RlvUIEnabler::hasOpenIM(from_id)); + args["NAME"] = LLSLURL("agent", from_id, (fRlvCanShowName) ? "completename" : "rlvanonym").getSLURLString();; +// [/RLVa:KB] LLSD payload; payload["from_id"] = from_id; LLNotificationsUtil::add("InventoryDeclined", args, payload); @@ -2885,6 +3055,25 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) LLSD query_string; query_string["owner"] = from_id; +// [RLVa:KB] - Checked: RLVa-1.2.0 + if (RlvActions::isRlvEnabled()) + { + // NOTE: the chat message itself will be filtered in LLNearbyChatHandler::processChat() + if ( (!RlvActions::canShowName(RlvActions::SNC_DEFAULT)) && (!from_group) && (RlvUtil::isNearbyAgent(from_id)) ) + { + query_string["rlv_shownames"] = TRUE; + + RlvUtil::filterNames(name); + chat.mFromName = name; + } + if (!RlvActions::canShowLocation()) + { + std::string::size_type idxPos = location.find('/'); + if ( (std::string::npos != idxPos) && (RlvUtil::isNearbyRegion(location.substr(0, idxPos))) ) + location = RlvStrings::getString(RLV_STRING_HIDDEN_REGION); + } + } +// [/RLVa:KB] query_string["slurl"] = location; query_string["name"] = name; if (from_group) @@ -2892,7 +3081,10 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) query_string["groupowned"] = "true"; } - chat.mURL = LLSLURL("objectim", session_id, "").getSLURLString(); +// chat.mURL = LLSLURL("objectim", session_id, "").getSLURLString(); +// [SL:KB] - Checked: 2010-11-02 (RLVa-1.2.2a) | Added: RLVa-1.2.2a + chat.mURL = LLSLURL("objectim", session_id, LLURI::mapToQueryString(query_string)).getSLURLString(); +// [/SL:KB] chat.mText = message; // Note: lie to Nearby Chat, pretending that this is NOT an IM, because @@ -3034,11 +3226,21 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) case IM_LURE_USER: case IM_TELEPORT_REQUEST: { +// [RLVa:KB] - Checked: RLVa-1.4.9 + // If we auto-accept the offer/request then this will override DnD status (but we'll still let the other party know later) + bool fRlvAutoAccept = (rlv_handler_t::isEnabled()) && + ( ((IM_LURE_USER == dialog) && (RlvActions::autoAcceptTeleportOffer(from_id))) || + ((IM_TELEPORT_REQUEST == dialog) && (RlvActions::autoAcceptTeleportRequest(from_id))) ); +// [/RLVa:KB] + if (is_muted) { return; } - else if (is_do_not_disturb) +// else if (is_do_not_disturb) +// [RLVa:KB] - Checked: RLVa-1.4.9 + else if ( (is_do_not_disturb) && (!fRlvAutoAccept) ) +// [/RLVa:KB] { send_do_not_disturb_message(msg, from_id); } @@ -3101,8 +3303,32 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) } } +// [RLVa:KB] - Checked: RLVa-1.4.9 + if (rlv_handler_t::isEnabled()) + { + if ( ((IM_LURE_USER == dialog) && (!RlvActions::canAcceptTpOffer(from_id))) || + ((IM_TELEPORT_REQUEST == dialog) && (!RlvActions::canAcceptTpRequest(from_id))) ) + { + RlvUtil::sendBusyMessage(from_id, RlvStrings::getString(RLV_STRING_BLOCKED_TPLUREREQ_REMOTE)); + if (is_do_not_disturb) + send_do_not_disturb_message(msg, from_id); + return; + } + + // Censor message if: 1) restricted from receiving IMs from the sender, or 2) teleport offer/request and @showloc=n restricted + if ( (!RlvActions::canReceiveIM(from_id)) || + ((gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) && (IM_LURE_USER == dialog || IM_TELEPORT_REQUEST == dialog)) ) + { + message = RlvStrings::getString(RLV_STRING_HIDDEN); + } + } +// [/RLVa:KB] + LLSD args; // *TODO: Translate -> [FIRST] [LAST] (maybe) +// [SL:KB] - Patch: UI-Notifications | Checked: 2011-04-11 (Catznip-2.5.0a) | Added: Catznip-2.5.0a + args["NAME_LABEL"] = LLSLURL("agent", from_id, "completename").getSLURLString(); +// [/SL:KB] args["NAME_SLURL"] = LLSLURL("agent", from_id, "about").getSLURLString(); args["MESSAGE"] = message; args["MATURITY_STR"] = region_access_str; @@ -3144,10 +3370,25 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) params.functor.name = "TeleportRequest"; } - params.substitutions = args; - params.payload = payload; - LLPostponedNotification::add<LLPostponedOfferNotification>( params, from_id, false); - } + params.substitutions = args; + params.payload = payload; + +// [RLVa:KB] - Checked: RLVa-1.4.9 + if (fRlvAutoAccept) + { + if (IM_LURE_USER == dialog) + gRlvHandler.setCanCancelTp(false); + if (is_do_not_disturb) + send_do_not_disturb_message(msg, from_id); + LLNotifications::instance().forceResponse(LLNotification::Params(params.name).payload(payload), 0); + } + else + { + LLPostponedNotification::add<LLPostponedOfferNotification>(params, from_id, false); + } +// [/RLVa:KB] +// LLPostponedNotification::add<LLPostponedOfferNotification>( params, from_id, false); + } } } break; @@ -3299,6 +3540,9 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) { send_do_not_disturb_message(msg, from_id); } +// [SL:KB] - Patch: UI-Notifications | Checked: 2011-04-11 (Catznip-2.5.0a) | Added: Catznip-2.5.0a + args["NAME_LABEL"] = LLSLURL("agent", from_id, "completename").getSLURLString(); +// [/SL:KB] args["NAME_SLURL"] = LLSLURL("agent", from_id, "about").getSLURLString(); if (add_notification) @@ -3581,9 +3825,14 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) chat.mPosAgent = chatter->getPositionAgent(); // Make swirly things only for talking objects. (not script debug messages, though) - if (chat.mSourceType == CHAT_SOURCE_OBJECT - && chat.mChatType != CHAT_TYPE_DEBUG_MSG - && gSavedSettings.getBOOL("EffectScriptChatParticles") ) +// if (chat.mSourceType == CHAT_SOURCE_OBJECT +// && chat.mChatType != CHAT_TYPE_DEBUG_MSG +// && gSavedSettings.getBOOL("EffectScriptChatParticles") ) +// [RLVa:KB] - Checked: 2010-03-09 (RLVa-1.2.0b) | Modified: RLVa-1.0.0g + if ( ((chat.mSourceType == CHAT_SOURCE_OBJECT) && (chat.mChatType != CHAT_TYPE_DEBUG_MSG)) && + (gSavedSettings.getBOOL("EffectScriptChatParticles")) && + ((!rlv_handler_t::isEnabled()) || (CHAT_TYPE_OWNER != chat.mChatType)) ) +// [/RLVa:KB] { LLPointer<LLViewerPartSourceChat> psc = new LLViewerPartSourceChat(chatter->getPositionAgent()); psc->setSourceObject(chatter); @@ -3613,6 +3862,75 @@ 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: 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; + BOOL is_owned_by_me = (chatter) ? chatter->permYouOwner() : 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 (never filter llOwnerSay or llRegionSayTo chat) + if ( ( (CHAT_SOURCE_AGENT == chat.mSourceType) && (from_id != gAgent.getID()) ) || + ( (CHAT_SOURCE_OBJECT == chat.mSourceType) && ((!is_owned_by_me) || (!is_attachment)) && + (CHAT_TYPE_OWNER != chat.mChatType) && (CHAT_TYPE_DIRECT != chat.mChatType) ) ) + { + bool fIsEmote = RlvUtil::isEmote(mesg); + if ((!fIsEmote) && + (((gRlvHandler.hasBehaviour(RLV_BHVR_RECVCHAT)) && (!gRlvHandler.isException(RLV_BHVR_RECVCHAT, from_id))) || + ((gRlvHandler.hasBehaviour(RLV_BHVR_RECVCHATFROM)) && (gRlvHandler.isException(RLV_BHVR_RECVCHATFROM, from_id))) )) + { + if ( (gRlvHandler.filterChat(mesg, false)) && (!gSavedSettings.getBOOL("RestrainedLoveShowEllipsis")) ) + return; + } + else if ((fIsEmote) && + (((gRlvHandler.hasBehaviour(RLV_BHVR_RECVEMOTE)) && (!gRlvHandler.isException(RLV_BHVR_RECVEMOTE, from_id))) || + ((gRlvHandler.hasBehaviour(RLV_BHVR_RECVEMOTEFROM)) && (gRlvHandler.isException(RLV_BHVR_RECVEMOTEFROM, from_id))) )) + { + if (!gSavedSettings.getBOOL("RestrainedLoveShowEllipsis")) + return; + mesg = "/me ..."; + } + } + + // Filtering "rules": + // avatar => filter only their name (unless it's this avie) + // other => filter everything + if (!RlvActions::canShowName(RlvActions::SNC_DEFAULT)) + { + if (CHAT_SOURCE_AGENT != chat.mSourceType) + { + RlvUtil::filterNames(chat.mFromName); + } + else if (chat.mFromID != gAgent.getID()) + { + chat.mFromName = RlvStrings::getAnonym(chat.mFromName); + chat.mRlvNamesFiltered = TRUE; + } + } + + // Create an "objectim" URL for objects if we're either @shownames or @showloc restricted + // (we need to do this now because we won't be have enough information to do it later on) + if ( (CHAT_SOURCE_OBJECT == chat.mSourceType) && + ( (!RlvActions::canShowName(RlvActions::SNC_DEFAULT)) || (!RlvActions::canShowLocation()) ) ) + { + LLSD sdQuery; + sdQuery["name"] = chat.mFromName; + sdQuery["owner"] = owner_id; + + if ( (!RlvActions::canShowName(RlvActions::SNC_COUNT, owner_id)) && (!is_owned_by_me) ) + sdQuery["rlv_shownames"] = true; + + const LLViewerRegion* pRegion = LLWorld::getInstance()->getRegionFromPosAgent(chat.mPosAgent); + if (pRegion) + sdQuery["slurl"] = LLSLURL(pRegion->getName(), chat.mPosAgent).getLocationString(); + + chat.mURL = LLSLURL("objectim", from_id, LLURI::mapToQueryString(sdQuery)).getSLURLString(); + } + } +// [/RLVa:KB] + BOOL ircstyle = FALSE; // Look for IRC-style emotes here so chatbubbles work @@ -3663,8 +3981,100 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) case CHAT_TYPE_WHISPER: chat.mText = LLTrans::getString("whisper") + " "; break; - case CHAT_TYPE_DEBUG_MSG: case CHAT_TYPE_OWNER: +// [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) && + ((!chatter) || (!chatter->isAttachment()) || (!chatter->isTempAttachment()) || (RlvSettings::getEnableTemporaryAttachments())) ) + { + mesg.erase(0, 1); + LLStringUtil::toLower(mesg); + + std::string strExecuted, strFailed, strRetained, *pstr; + + boost_tokenizer tokens(mesg, boost::char_separator<char>(",", "", boost::drop_empty_tokens)); + for (boost_tokenizer::iterator itToken = tokens.begin(); itToken != tokens.end(); ++itToken) + { + std::string strCmd = *itToken; + + ERlvCmdRet eRet = gRlvHandler.processCommand(from_id, strCmd, true); + 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; + else if ( RLV_RET_FAILED == (eRet & RLV_RET_FAILED) ) + pstr = &strFailed; + else if (RLV_RET_RETAINED == eRet) + pstr = &strRetained; + else + { + RLV_ASSERT(false); + pstr = &strFailed; + } + + const char* pstrSuffix = RlvStrings::getStringFromReturnCode(eRet); + if (pstrSuffix) + strCmd.append(" (").append(pstrSuffix).append(")"); + + if (!pstr->empty()) + pstr->push_back(','); + pstr->append(strCmd); + } + } + + if (RlvForceWear::instanceExists()) + RlvForceWear::instance().done(); + + if ( (!RlvSettings::getDebug()) || ((strExecuted.empty()) && (strFailed.empty()) && (strRetained.empty())) ) + return; + + // Silly people want comprehensive debug messages, blah :p + if ( (!strExecuted.empty()) && (strFailed.empty()) && (strRetained.empty()) ) + { + chat.mText = " executes: @"; + mesg = strExecuted; + } + else if ( (strExecuted.empty()) && (!strFailed.empty()) && (strRetained.empty()) ) + { + chat.mText = " failed: @"; + mesg = strFailed; + } + else if ( (strExecuted.empty()) && (strFailed.empty()) && (!strRetained.empty()) ) + { + chat.mText = " retained: @"; + mesg = strRetained; + } + else + { + chat.mText = ": @"; + if (!strExecuted.empty()) + mesg += "\n - executed: @" + strExecuted; + if (!strFailed.empty()) + mesg += "\n - failed: @" + strFailed; + if (!strRetained.empty()) + mesg += "\n - retained: @" + strRetained; + } + + break; + } +// [/RLVa:KB] +// [RLVa:KB] - Checked: 2010-03-09 (RLVa-1.2.0b) | Modified: RLVa-1.0.0g + // Copy/paste from above + if ( (rlv_handler_t::isEnabled()) && (chatter) && (chat.mSourceType == CHAT_SOURCE_OBJECT) && + (gSavedSettings.getBOOL("EffectScriptChatParticles")) ) + { + LLPointer<LLViewerPartSourceChat> psc = new LLViewerPartSourceChat(chatter->getPositionAgent()); + psc->setSourceObject(chatter); + psc->setColor(color); + //We set the particles to be owned by the object's owner, + //just in case they should be muted by the mute list + psc->setOwnerUUID(owner_id); + LLViewerPartSim::getInstance()->addPartSource(psc); + } +// [/RLVa:KB] + case CHAT_TYPE_DEBUG_MSG: case CHAT_TYPE_NORMAL: case CHAT_TYPE_DIRECT: break; @@ -3783,7 +4193,10 @@ void process_teleport_start(LLMessageSystem *msg, void**) // *NOTE: The server sends two StartTeleport packets when you are teleporting to a LM LLViewerMessage::getInstance()->mTeleportStartedSignal(); - if (teleport_flags & TELEPORT_FLAGS_DISABLE_CANCEL) +// if (teleport_flags & TELEPORT_FLAGS_DISABLE_CANCEL) +// [RLVa:KB] - Checked: 2010-04-07 (RLVa-1.2.0d) | Added: RLVa-0.2.0b + if ( (teleport_flags & TELEPORT_FLAGS_DISABLE_CANCEL) || (!gRlvHandler.getCanCancelTp()) ) +// [/RLVa:KB] { gViewerWindow->setProgressCancelButtonVisible(FALSE); } @@ -3825,7 +4238,10 @@ void process_teleport_progress(LLMessageSystem* msg, void**) } U32 teleport_flags = 0x0; msg->getU32("Info", "TeleportFlags", teleport_flags); - if (teleport_flags & TELEPORT_FLAGS_DISABLE_CANCEL) +// if (teleport_flags & TELEPORT_FLAGS_DISABLE_CANCEL) +// [RLVa:KB] - Checked: 2010-04-07 (RLVa-1.2.0d) | Added: RLVa-0.2.0b + if ( (teleport_flags & TELEPORT_FLAGS_DISABLE_CANCEL) || (!gRlvHandler.getCanCancelTp()) ) +// [/RLVa:KB] { gViewerWindow->setProgressCancelButtonVisible(FALSE); } @@ -4246,7 +4662,10 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**) } // send walk-vs-run status - gAgent.sendWalkRun(gAgent.getRunning() || gAgent.getAlwaysRun()); +// gAgent.sendWalkRun(gAgent.getRunning() || gAgent.getAlwaysRun()); +// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i + gAgent.sendWalkRun(); +// [/RLVa:KB] // If the server version has changed, display an info box and offer // to display the release notes, unless this is the initial log in. @@ -4660,6 +5079,14 @@ void process_kill_object(LLMessageSystem *mesgsys, void **user_data) LLViewerObject *objectp = gObjectList.findObject(id); if (objectp) { +// [SL:KB] - Patch: Appearance-TeleportAttachKill | Checked: Catznip-4.0 + if ( (objectp->isAttachment()) && (gAgentAvatarp) && (gAgent.getTeleportState() != LLAgent::TELEPORT_NONE) && (objectp->permYouOwner()) ) + { + gAgentAvatarp->addPendingDetach(objectp->getRootEdit()->getID()); + continue; + } +// [/SL:KB] + // Display green bubble on kill if ( gShowObjectUpdates ) { @@ -6135,6 +6562,15 @@ void process_alert_core(const std::string& message, BOOL modal) } std::string new_msg =LLNotifications::instance().getGlobalString(text); +// [RLVa:KB] - Checked: RLVa-1.4.5 + if ( (new_msg == text) && (RlvActions::isRlvEnabled()) ) + { + if (!RlvActions::canShowLocation()) + RlvUtil::filterLocation(new_msg); + if (!RlvActions::canShowName(RlvActions::SNC_DEFAULT)) + RlvUtil::filterNames(new_msg); + } +// [/RLVa:KB] args["MESSAGE"] = new_msg; LLNotificationsUtil::add("SystemMessage", args); } @@ -6142,6 +6578,15 @@ void process_alert_core(const std::string& message, BOOL modal) { LLSD args; std::string new_msg =LLNotifications::instance().getGlobalString(message); +// [RLVa:KB] - Checked: RLVa-1.4.5 + if ( (new_msg == message) && (RlvActions::isRlvEnabled()) ) + { + if (!RlvActions::canShowLocation()) + RlvUtil::filterLocation(new_msg); + if (!RlvActions::canShowName(RlvActions::SNC_DEFAULT)) + RlvUtil::filterNames(new_msg); + } +// [/RLVa:KB] args["ERROR_MESSAGE"] = new_msg; LLNotificationsUtil::add("ErrorMessage", args); } @@ -6157,6 +6602,16 @@ void process_alert_core(const std::string& message, BOOL modal) std::string localized_msg; bool is_message_localized = LLTrans::findString(localized_msg, new_msg); +// [RLVa:KB] - Checked: RLVa-1.4.5 + if ( (new_msg == message) && (RlvActions::isRlvEnabled()) ) + { + if (!RlvActions::canShowLocation()) + RlvUtil::filterLocation(new_msg); + if (!RlvActions::canShowName(RlvActions::SNC_DEFAULT)) + RlvUtil::filterNames(new_msg); + } +// [/RLVa:KB] + args["MESSAGE"] = is_message_localized ? localized_msg : new_msg; LLNotificationsUtil::add("SystemMessageTip", args); } @@ -6317,7 +6772,7 @@ void notify_cautioned_script_question(const LLSD& notification, const LLSD& resp if (viewregion) { // got the region, so include the region and 3d coordinates of the object - notice.setArg("[REGIONNAME]", viewregion->getName()); + notice.setArg("[REGIONNAME]", viewregion->getName()); std::string formatpos = llformat("%.1f, %.1f,%.1f", objpos[VX], objpos[VY], objpos[VZ]); notice.setArg("[REGIONPOS]", formatpos); @@ -6325,7 +6780,15 @@ void notify_cautioned_script_question(const LLSD& notification, const LLSD& resp } } - if (!foundpos) +// [RLVa:KB] - Checked: 2010-04-23 (RLVa-1.2.0g) | Modified: RLVa-1.0.0a + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) + { + notice.setArg("[REGIONNAME]", RlvStrings::getString(RLV_STRING_HIDDEN_REGION)); + notice.setArg("[REGIONPOS]", RlvStrings::getString(RLV_STRING_HIDDEN)); + } + else if (!foundpos) +// [/RLVa:KB] +// if (!foundpos) { // unable to determine location of the object notice.setArg("[REGIONNAME]", "(unknown region)"); @@ -6339,8 +6802,12 @@ void notify_cautioned_script_question(const LLSD& notification, const LLSD& resp std::string perms; BOOST_FOREACH(script_perm_t script_perm, SCRIPT_PERMISSIONS) { - if ((orig_questions & script_perm.permbit) - && script_perm.caution) +// if ((orig_questions & script_perm.permbit) +// && script_perm.caution) +// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7) + if ( (orig_questions & script_perm.permbit) && + ((script_perm.caution) || (notification["payload"]["rlv_notify"].asBoolean())) ) +// [/RLVa:KB] { count++; caution = TRUE; @@ -6360,11 +6827,25 @@ void notify_cautioned_script_question(const LLSD& notification, const LLSD& resp // log a chat message as long as at least one requested permission // is a caution permission +// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7) if (caution) { - LLChat chat(notice.getString()); - // LLFloaterChat::addChat(chat, FALSE, FALSE); + LLFloaterIMNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLFloaterIMNearbyChat>("nearby_chat"); + if(nearby_chat) + { + LLChat chat_msg(notice.getString()); + chat_msg.mFromName = SYSTEM_FROM; + chat_msg.mFromID = LLUUID::null; + chat_msg.mSourceType = CHAT_SOURCE_SYSTEM; + nearby_chat->addMessage(chat_msg); + } } +// [/RLVa:KB] +// if (caution) +// { +// LLChat chat(notice.getString()); +// // LLFloaterChat::addChat(chat, FALSE, FALSE); +// } } } @@ -6439,12 +6920,22 @@ bool script_question_cb(const LLSD& notification, const LLSD& response) msg->sendReliable(LLHost(notification["payload"]["sender"].asString())); // only log a chat message if caution prompts are enabled - if (gSavedSettings.getBOOL("PermissionsCautionEnabled")) +// if (gSavedSettings.getBOOL("PermissionsCautionEnabled")) +// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7) + if ( (gSavedSettings.getBOOL("PermissionsCautionEnabled")) || (notification["payload"]["rlv_notify"].asBoolean()) ) +// [/RLVa:KB] { // log a chat message, if appropriate notify_cautioned_script_question(notification, response, orig, allowed); } +// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7) + if ( (allowed) && (notification["payload"].has("rlv_blocked")) ) + { + RlvUtil::notifyBlocked(notification["payload"]["rlv_blocked"], LLSD().with("OBJECT", notification["payload"]["object_name"])); + } +// [/RLVa:KB] + if ( response["Mute"] ) // mute { script_question_mute(task_id,notification["payload"]["object_name"].asString()); @@ -6628,6 +7119,38 @@ void process_script_question(LLMessageSystem *msg, void **user_data) payload["object_name"] = object_name; payload["owner_name"] = owner_name; +// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7) + if (rlv_handler_t::isEnabled()) + { + RlvUtil::filterScriptQuestions(questions, payload); + + if ( (questions) && (gRlvHandler.hasBehaviour(RLV_BHVR_ACCEPTPERMISSION)) ) + { + const LLViewerObject* pObj = gObjectList.findObject(taskid); + if (pObj) + { + if ( (pObj->permYouOwner()) && (!pObj->isAttachment()) ) + { + questions &= ~(SCRIPT_PERMISSIONS[SCRIPT_PERMISSION_TAKE_CONTROLS].permbit | + SCRIPT_PERMISSIONS[SCRIPT_PERMISSION_ATTACH].permbit); + } + else + { + questions &= ~(SCRIPT_PERMISSIONS[SCRIPT_PERMISSION_TAKE_CONTROLS].permbit); + } + payload["rlv_notify"] = !pObj->permYouOwner(); + } + } + } + + if ( (!caution) && (!questions) ) + { + LLNotifications::instance().forceResponse( + LLNotification::Params("ScriptQuestion").substitutions(args).payload(payload), 0/*YES*/); + return; + } +// [/RLVa:KB] + // check whether cautions are even enabled or not const char* notification = "ScriptQuestion"; @@ -6992,6 +7515,16 @@ void send_lures(const LLSD& notification, const LLSD& response) LLAgentUI::buildSLURL(slurl); text.append("\r\n").append(slurl.getSLURLString()); +// [RLVa:KB] - Checked: RLVa-2.0.0 + // Filter the lure message if any of the recipients are IM-blocked + const LLSD& sdRecipients = notification["payload"]["ids"]; + if ( (gRlvHandler.isEnabled()) && + (std::any_of(sdRecipients.beginArray(), sdRecipients.endArray(), [](const LLSD& id) { return !RlvActions::canStartIM(id.asUUID()) || !RlvActions::canSendIM(id.asUUID()); })) ) + { + text = RlvStrings::getString(RLV_STRING_HIDDEN); + } +// [/RLVa:KB] + LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_StartLure); msg->nextBlockFast(_PREHASH_AgentData); @@ -7011,10 +7544,16 @@ void send_lures(const LLSD& notification, const LLSD& response) // Record the offer. { +// [RLVa:KB] - Checked: RLVa-2.0.1 + bool fRlvCanShowName = (!notification["payload"].has("rlv_shownames")) ? true : !notification["payload"]["rlv_shownames"].asBoolean(); +// [/RLVa:KB] std::string target_name; gCacheName->getFullName(target_id, target_name); // for im log filenames LLSD args; - args["TO_NAME"] = LLSLURL("agent", target_id, "displayname").getSLURLString();; +// [RLVa:KB] - Checked: RLVa-2.0.1 + args["TO_NAME"] = LLSLURL("agent", target_id, (fRlvCanShowName) ? "displayname" : "rlvanonym").getSLURLString();; +// [/RLVa:KB] +// args["TO_NAME"] = LLSLURL("agent", target_id, "displayname").getSLURLString();; LLSD payload; @@ -7024,7 +7563,11 @@ void send_lures(const LLSD& notification, const LLSD& response) LLNotificationsUtil::add("TeleportOfferSent", args, payload); // Add the recepient to the recent people list. - LLRecentPeople::instance().add(target_id); +// [RLVa:KB] - Checked: RLVa-2.0.1 + if (fRlvCanShowName) + LLRecentPeople::instance().add(target_id); +// [/RLVa:KB] +// LLRecentPeople::instance().add(target_id); } } gAgent.sendReliableMessage(); @@ -7069,15 +7612,38 @@ void handle_lure(const uuid_vec_t& ids) if (!gAgent.getRegion()) return; LLSD edit_args; - edit_args["REGION"] = gAgent.getRegion()->getName(); +// [RLVa:KB] - Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.0.0a + edit_args["REGION"] = (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) ? gAgent.getRegion()->getName() : RlvStrings::getString(RLV_STRING_HIDDEN); +// [/RLVa:KB] +// edit_args["REGION"] = gAgent.getRegion()->getName(); LLSD payload; - for (std::vector<LLUUID>::const_iterator it = ids.begin(); - it != ids.end(); - ++it) +// [RLVa:KB] - Checked: RLVa-2.0.1 + bool fRlvShouldHideNames = false; + for (const LLUUID& idAgent : ids) { - payload["ids"].append(*it); + // Only allow offering teleports if everyone is a @tplure exception or able to map this avie under @showloc=n + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) + { + const LLRelationship* pBuddyInfo = LLAvatarTracker::instance().getBuddyInfo(idAgent); + if ( (!gRlvHandler.isException(RLV_BHVR_TPLURE, idAgent, RLV_CHECK_PERMISSIVE)) && + ((!pBuddyInfo) || (!pBuddyInfo->isOnline()) || (!pBuddyInfo->isRightGrantedTo(LLRelationship::GRANT_MAP_LOCATION))) ) + { + RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_TELEPORT_OFFER); + return; + } + } + fRlvShouldHideNames |= !RlvActions::canShowName(RlvActions::SNC_TELEPORTOFFER, idAgent); + payload["ids"].append(idAgent); } + payload["rlv_shownames"] = fRlvShouldHideNames; +// [/RLVa:KB] +// for (std::vector<LLUUID>::const_iterator it = ids.begin(); +// it != ids.end(); +// ++it) +// { +// payload["ids"].append(*it); +// } if (gAgent.isGodlike()) { LLNotificationsUtil::add("OfferTeleportFromGod", edit_args, payload, handle_lure_callback); diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 5edc3c9745378c85e01928eb43d3ca760f434539..09ebecec2c04194e875a992d13c789720da19656 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -102,6 +102,11 @@ #include "llmediaentry.h" #include "llfloaterperms.h" #include "llvocache.h" +// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a) +#include "rlvactions.h" +#include "rlvhandler.h" +#include "rlvlocks.h" +// [/RLVa:KB] //#define DEBUG_UPDATE_TYPE @@ -692,6 +697,12 @@ bool LLViewerObject::isReturnable() return false; } +// [RLVa:KB] - Checked: 2011-05-28 (RLVa-1.4.0a) | Added: RLVa-1.4.0a + if ( (rlv_handler_t::isEnabled()) && (!rlvCanDeleteOrReturn(this)) ) + { + return false; + } +// [/RLVa:KB] std::vector<LLBBox> boxes; boxes.push_back(LLBBox(getPositionRegion(), getRotationRegion(), getScale() * -0.5f, getScale() * 0.5f).getAxisAligned()); for (child_list_t::iterator iter = mChildList.begin(); @@ -909,7 +920,10 @@ void LLViewerObject::addThisAndNonJointChildren(std::vector<LLViewerObject*>& ob } } -BOOL LLViewerObject::isChild(LLViewerObject *childp) const +//BOOL LLViewerObject::isChild(LLViewerObject *childp) const +// [RLVa:KB] - Checked: 2011-05-28 (RLVa-1.4.0a) | Added: RLVa-1.4.0a +BOOL LLViewerObject::isChild(const LLViewerObject *childp) const +// [/RLVa:KB] { for (child_list_t::const_iterator iter = mChildList.begin(); iter != mChildList.end(); iter++) @@ -1428,6 +1442,12 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, coloru.mV[3] = 255 - coloru.mV[3]; mText->setColor(LLColor4(coloru)); mText->setString(temp_string); +// [RLVa:KB] - Checked: 2010-03-27 (RLVa-1.4.0a) | Added: RLVa-1.0.0f + if (rlv_handler_t::isEnabled()) + { + mText->setObjectText(temp_string); + } +// [/RLVa:KB] mHudText = temp_string; mHudTextColor = LLColor4(coloru); @@ -1806,6 +1826,12 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, coloru.mV[3] = 255 - coloru.mV[3]; mText->setColor(LLColor4(coloru)); mText->setString(temp_string); +// [RLVa:KB] - Checked: 2010-03-27 (RLVa-1.4.0a) | Added: RLVa-1.0.0f + if (rlv_handler_t::isEnabled()) + { + mText->setObjectText(temp_string); + } +// [/RLVa:KB] mHudText = temp_string; mHudTextColor = LLColor4(coloru); @@ -1994,6 +2020,25 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, gObjectList.killObject(this); return retval; } +// [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 (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()) + RlvAttachmentLockWatchdog::instance().onWearAttachment(idItem, RLV_WEAR_ADD); + } + } + } +// [/RLVa:KB] sent_parentp->addChild(this); // make sure this object gets a non-damped update if (sent_parentp->mDrawable.notNull()) @@ -5786,7 +5831,10 @@ BOOL LLViewerObject::permTransfer() const // given you modify rights to. JC BOOL LLViewerObject::allowOpen() const { - return !flagInventoryEmpty() && (permYouOwner() || permModify()); +// [RLVa:KB] - Checked: 2010-11-29 (RLVa-1.3.0c) | Modified: RLVa-1.3.0c + return !flagInventoryEmpty() && (permYouOwner() || permModify()) && ((!RlvActions::isRlvEnabled()) || (RlvActions::canEdit(this))); +// [/RLVa:KB] +// return !flagInventoryEmpty() && (permYouOwner() || permModify()); } LLViewerObject::LLInventoryCallbackInfo::~LLInventoryCallbackInfo() diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index cb8acfdcf82dd9ca0fadd4889a88c329c4aec8db..c0b0209728717ecf845c5b777d5499f30e3039ef 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -259,7 +259,10 @@ class LLViewerObject S32 numChildren() const { return mChildList.size(); } void addThisAndAllChildren(std::vector<LLViewerObject*>& objects); void addThisAndNonJointChildren(std::vector<LLViewerObject*>& objects); - BOOL isChild(LLViewerObject *childp) const; +// BOOL isChild(LLViewerObject *childp) const; +// [RLVa:KB] - Checked: 2011-05-28 (RLVa-1.4.0a) | Added: RLVa-1.4.0a + BOOL isChild(const LLViewerObject *childp) const; +// [/RLVa:KB] BOOL isSeat() const; @@ -372,7 +375,10 @@ class LLViewerObject void sendShapeUpdate(); - U8 getState() { return mState; } +// U8 getState() { return mState; } +// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0a) | Added: RLVa-1.2.0a + U8 getState() const { return mState; } +// [/RLVa:KB] F32 getAppAngle() const { return mAppAngle; } F32 getPixelArea() const { return mPixelArea; } diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index 8f98d66c0c334e9acd37ed12897fcf7580426ca1..1227303497c11148585da989e4beb656c72a1e4f 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -723,6 +723,29 @@ void LLViewerObjectList::dirtyAllObjectInventory() } } +// [SL:KB] - Patch: Render-TextureToggle (Catznip-4.0) +void LLViewerObjectList::setAllObjectDefaultTextures(U32 nChannel, bool fShowDefault) +{ + LLPipeline::sRenderTextures = !fShowDefault; + + for (LLViewerObject* pObj : mObjects) + { + LLDrawable* pDrawable = pObj->mDrawable; + if ( (pDrawable) && (!pDrawable->isDead()) ) + { + for (int idxFace = 0, cntFace = pDrawable->getNumFaces(); idxFace < cntFace; idxFace++) + { + if (LLFace* pFace = pDrawable->getFace(idxFace)) + pFace->setDefaultTexture(nChannel, fShowDefault); + } + + if (LLVOVolume* pVoVolume = pDrawable->getVOVolume()) + pVoVolume->markForUpdate(true); + } + } +} +// [/SL:KB] + void LLViewerObjectList::updateApparentAngles(LLAgent &agent) { S32 i; diff --git a/indra/newview/llviewerobjectlist.h b/indra/newview/llviewerobjectlist.h index 94c751acc66b3d40b84626b60099a779d60edc08..c88bc00ac7af0df7751f50f3526715b2cdec2b33 100644 --- a/indra/newview/llviewerobjectlist.h +++ b/indra/newview/llviewerobjectlist.h @@ -123,6 +123,9 @@ class LLViewerObjectList void resetObjectBeacons(); void dirtyAllObjectInventory(); +// [SL:KB] - Patch: Render-TextureToggle (Catznip-4.0) + void setAllObjectDefaultTextures(U32 nChannel, bool fShowDefault); +// [/SL:KB] void removeFromActiveList(LLViewerObject* objectp); void updateActive(LLViewerObject *objectp); diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp index dddfb6745e48887d7b0c27a6800c834eb58fc2c2..123c4bf17a80972ba92dd2236d54931fc3784a6e 100644 --- a/indra/newview/llviewerparcelmgr.cpp +++ b/indra/newview/llviewerparcelmgr.cpp @@ -2487,6 +2487,13 @@ boost::signals2::connection LLViewerParcelMgr::setTeleportFailedCallback(telepor return mTeleportFailedSignal.connect(cb); } +// [SL:KB] - Patch: Appearance-TeleportAttachKill | Checked: Catznip-4.0 +boost::signals2::connection LLViewerParcelMgr::setTeleportDoneCallback(teleport_done_callback_t cb) +{ + return mTeleportDoneSignal.connect(cb); +} +// [/SL:KB] + /* Ok, we're notified that teleport has been finished. * We should now propagate the notification via mTeleportFinishedSignal * to all interested parties. @@ -2514,3 +2521,10 @@ void LLViewerParcelMgr::onTeleportFailed() { mTeleportFailedSignal(); } + +// [SL:KB] - Patch: Appearance-TeleportAttachKill | Checked: Catznip-4.0 +void LLViewerParcelMgr::onTeleportDone() +{ + mTeleportDoneSignal(); +} +// [/SL:KB] diff --git a/indra/newview/llviewerparcelmgr.h b/indra/newview/llviewerparcelmgr.h index bb6bbf33083127c29b7e04d8cf7d1c65b7d70ae5..9d89e6a0608ad8913ddd2c5370a223245bb09fdd 100644 --- a/indra/newview/llviewerparcelmgr.h +++ b/indra/newview/llviewerparcelmgr.h @@ -81,6 +81,10 @@ class LLViewerParcelMgr : public LLSingleton<LLViewerParcelMgr> typedef boost::signals2::signal<void (const LLVector3d&, const bool&)> teleport_finished_signal_t; typedef boost::function<void()> teleport_failed_callback_t; typedef boost::signals2::signal<void()> teleport_failed_signal_t; +// [SL:KB] - Patch: Appearance-TeleportAttachKill | Checked: Catznip-4.0 + typedef boost::function<void()> teleport_done_callback_t; + typedef boost::signals2::signal<void()> teleport_done_signal_t; +// [/SL:KB] LLViewerParcelMgr(); ~LLViewerParcelMgr(); @@ -284,8 +288,14 @@ class LLViewerParcelMgr : public LLSingleton<LLViewerParcelMgr> boost::signals2::connection setTeleportFinishedCallback(teleport_finished_callback_t cb); boost::signals2::connection setTeleportFailedCallback(teleport_failed_callback_t cb); +// [SL:KB] - Patch: Appearance-TeleportAttachKill | Checked: Catznip-4.0 + boost::signals2::connection setTeleportDoneCallback(teleport_done_callback_t cb); +// [/SL:KB] void onTeleportFinished(bool local, const LLVector3d& new_pos); void onTeleportFailed(); +// [SL:KB] - Patch: Appearance-TeleportAttachKill | Checked: Catznip-4.0 + void onTeleportDone(); +// [/SL:KB] static BOOL isParcelOwnedByAgent(const LLParcel* parcelp, U64 group_proxy_power); static BOOL isParcelModifiableByAgent(const LLParcel* parcelp, U64 group_proxy_power); @@ -340,6 +350,9 @@ class LLViewerParcelMgr : public LLSingleton<LLViewerParcelMgr> LLVector3d mTeleportInProgressPosition; teleport_finished_signal_t mTeleportFinishedSignal; teleport_failed_signal_t mTeleportFailedSignal; +// [SL:KB] - Patch: Appearance-TeleportAttachKill | Checked: Catznip-4.0 + teleport_done_signal_t mTeleportDoneSignal; +// [/SL:KB] // Array of pieces of parcel edges to potentially draw // Has (parcels_per_edge + 1) * (parcels_per_edge + 1) elements so diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index ed719ae41827b8127bc55ec813f1c541eb6a4164..f644a1c602d9186268e766b0421c07bf862b5629 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -76,6 +76,9 @@ LLPointer<LLViewerFetchedTexture> LLViewerFetchedTexture::sWhiteImagep = NULL; LLPointer<LLViewerFetchedTexture> LLViewerFetchedTexture::sDefaultImagep = NULL; LLPointer<LLViewerFetchedTexture> LLViewerFetchedTexture::sSmokeImagep = NULL; LLPointer<LLViewerFetchedTexture> LLViewerFetchedTexture::sFlatNormalImagep = NULL; +// [SL:KB] - Patch: Render-TextureToggle (Catznip-4.0) +LLPointer<LLViewerFetchedTexture> LLViewerFetchedTexture::sDefaultDiffuseImagep = NULL; +// [/SL:KB] LLViewerMediaTexture::media_map_t LLViewerMediaTexture::sMediaMap; LLTexturePipelineTester* LLViewerTextureManager::sTesterp = NULL; const std::string sTesterName("TextureTester"); diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h index 8017d8260418e27b9a366af9c848535739d40771..b5d3b556fcfdc108de67faf4e7c48f5efa3a08c5 100644 --- a/indra/newview/llviewertexture.h +++ b/indra/newview/llviewertexture.h @@ -525,6 +525,9 @@ class LLViewerFetchedTexture : public LLViewerTexture static LLPointer<LLViewerFetchedTexture> sDefaultImagep; // "Default" texture for error cases, the only case of fetched texture which is generated in local. static LLPointer<LLViewerFetchedTexture> sSmokeImagep; // Old "Default" translucent texture static LLPointer<LLViewerFetchedTexture> sFlatNormalImagep; // Flat normal map denoting no bumpiness on a surface +// [SL:KB] - Patch: Render-TextureToggle (Catznip-4.0) + static LLPointer<LLViewerFetchedTexture> sDefaultDiffuseImagep; +// [/SL:KB] }; // diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index cd9ab3e6724b7b61169919cb12b98d45f63102dd..d196b6f1edf36259b8f3d90914dc0d7ad9c00827 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -209,6 +209,10 @@ #include "llviewerwindowlistener.h" #include "llpaneltopinfobar.h" +// [RLVa:KB] - Checked: 2010-03-31 (RLVa-1.2.0c) +#include "rlvhandler.h" +// [/RLVa:KB] + #if LL_WINDOWS #include <tchar.h> // For Unicode conversion methods #endif @@ -3757,6 +3761,15 @@ void LLViewerWindow::renderSelections( BOOL for_gl_pick, BOOL pick_parcel_walls, { moveable_object_selected = TRUE; this_object_movable = TRUE; + +// [RLVa:KB] - Checked: 2010-03-31 (RLVa-1.2.0c) | Modified: RLVa-0.2.0g + if ( (rlv_handler_t::isEnabled()) && + ((gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SITTP))) ) + { + if ((isAgentAvatarValid()) && (gAgentAvatarp->isSitting()) && (gAgentAvatarp->getRoot() == object->getRootEdit())) + moveable_object_selected = this_object_movable = FALSE; + } +// [/RLVa:KB] } all_selected_objects_move = all_selected_objects_move && this_object_movable; all_selected_objects_modify = all_selected_objects_modify && object->permModify(); @@ -4049,6 +4062,13 @@ LLViewerObject* LLViewerWindow::cursorIntersect(S32 mouse_x, S32 mouse_y, F32 de found = gPipeline.lineSegmentIntersectInHUD(mh_start, mh_end, pick_transparent, face_hit, intersection, uv, normal, tangent); +// [RLVa:KB] - Checked: 2010-03-31 (RLVa-1.2.0c) | Modified: RLVa-1.2.0c + if ( (rlv_handler_t::isEnabled()) && (found) && + (LLToolCamera::getInstance()->hasMouseCapture()) && (gKeyboard->currentMask(TRUE) & MASK_ALT) ) + { + found = NULL; + } +// [/RLVa:KB] if (!found) // if not found in HUD, look in world: { found = gPipeline.lineSegmentIntersectInWorld(mw_start, mw_end, pick_transparent, pick_rigged, @@ -4058,6 +4078,23 @@ LLViewerObject* LLViewerWindow::cursorIntersect(S32 mouse_x, S32 mouse_y, F32 de gDebugRaycastIntersection = *intersection; } } + +// [RLVa:KB] - Checked: RLVa-1.2.0 + if ( (found) && ((gTeleportDisplay) || ((rlv_handler_t::isEnabled()) && (found) && (gRlvHandler.hasBehaviour(RLV_BHVR_INTERACT)))) ) + { + // Allow picking if: + // - the drag-and-drop tool is active (allows inventory offers) + // - the camera tool is active + // - the pie tool is active *and* we picked our own avie (allows "mouse steering" and the self pie menu) + LLTool* pCurTool = LLToolMgr::getInstance()->getCurrentTool(); + if ( (LLToolDragAndDrop::getInstance() != pCurTool) && + (!LLToolCamera::getInstance()->hasMouseCapture()) && + ((LLToolPie::getInstance() != pCurTool) || (gAgent.getID() != found->getID())) ) + { + found = NULL; + } + } +// [/RLVa:KB] } return found; diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index f4010b0412de4ddd29f0d70da6dcd83d61484e01..0c27296482e02c283773cfde71ddcbffabe45b99 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -97,6 +97,10 @@ #include "llanimstatelabels.h" #include "lltrans.h" #include "llappearancemgr.h" +// [RLVa:KB] - Checked: RLVa-2.0.1 +#include "rlvactions.h" +#include "rlvhandler.h" +// [/RLVa:KB] #include "llgesturemgr.h" //needed to trigger the voice gesticulations #include "llvoiceclient.h" @@ -2621,12 +2625,23 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) const F32 time_visible = mTimeVisible.getElapsedTimeF32(); const F32 NAME_SHOW_TIME = gSavedSettings.getF32("RenderNameShowTime"); // seconds const F32 FADE_DURATION = gSavedSettings.getF32("RenderNameFadeDuration"); // seconds +// [RLVa:KB] - Checked: RLVa-2.0.1 + bool fRlvShowAvTag = true, fRlvShowAvName = true; + if (RlvActions::isRlvEnabled()) + { + fRlvShowAvTag = RlvActions::canShowName(RlvActions::SNC_NAMETAG, getID()); + fRlvShowAvName = (fRlvShowAvTag) && (RlvActions::canShowName(RlvActions::SNC_DEFAULT, getID())); + } +// [/RLVa:KB] BOOL visible_avatar = isVisible() || mNeedsAnimUpdate; BOOL visible_chat = gSavedSettings.getBOOL("UseChatBubbles") && (mChats.size() || mTyping); BOOL render_name = visible_chat || - (visible_avatar && - ((sRenderName == RENDER_NAME_ALWAYS) || - (sRenderName == RENDER_NAME_FADE && time_visible < NAME_SHOW_TIME))); + (visible_avatar && +// [RLVa:KB] - Checked: RLVa-2.0.1 + (fRlvShowAvTag) && +// [/RLVa:KB] + ((sRenderName == RENDER_NAME_ALWAYS) || + (sRenderName == RENDER_NAME_FADE && time_visible < NAME_SHOW_TIME))); // If it's your own avatar, don't draw in mouselook, and don't // draw if we're specifically hiding our own name. if (isSelf()) @@ -2656,7 +2671,18 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) new_name = TRUE; } - if (sRenderGroupTitles != mRenderGroupTitles) +// [RLVa:KB] - Checked: RLVa-0.2.0 + if (!fRlvShowAvName) + { + if (mRenderGroupTitles) + { + mRenderGroupTitles = FALSE; + new_name = TRUE; + } + } + else if (sRenderGroupTitles != mRenderGroupTitles) +// [/RLVa] +// if (sRenderGroupTitles != mRenderGroupTitles) { mRenderGroupTitles = sRenderGroupTitles; new_name = TRUE; @@ -2723,6 +2749,9 @@ void LLVOAvatar::idleUpdateNameTagText(BOOL new_name) // Avatars must have a first and last name if (!firstname || !lastname) return; +// [RLVa:KB] - Checked: RLVa-2.0.1 + bool fRlvShowAvName = RlvActions::canShowName(RlvActions::SNC_DEFAULT, getID()); +// [/RLVa:KB] bool is_away = mSignaledAnimations.find(ANIM_AGENT_AWAY) != mSignaledAnimations.end(); bool is_do_not_disturb = mSignaledAnimations.find(ANIM_AGENT_DO_NOT_DISTURB) != mSignaledAnimations.end(); bool is_appearance = mSignaledAnimations.find(ANIM_AGENT_CUSTOMIZE) != mSignaledAnimations.end(); @@ -2735,7 +2764,10 @@ void LLVOAvatar::idleUpdateNameTagText(BOOL new_name) { is_muted = isInMuteList(); } - bool is_friend = LLAvatarTracker::instance().isBuddy(getID()); +// bool is_friend = LLAvatarTracker::instance().isBuddy(getID()); +// [RLVa:KB] - Checked: RLVa-1.2.2 + bool is_friend = (fRlvShowAvName) && (LLAvatarTracker::instance().isBuddy(getID())); +// [/RLVa:KB] bool is_cloud = getIsCloud(); if (is_appearance != mNameAppearance) @@ -2800,7 +2832,10 @@ void LLVOAvatar::idleUpdateNameTagText(BOOL new_name) LLFontGL::getFontSansSerifSmall()); } - if (sRenderGroupTitles +// if (sRenderGroupTitles +// [RLVa:KB] - Checked: RLVa-1.2.2 + if (sRenderGroupTitles && fRlvShowAvName +// [/RLVa:KB] && title && title->getString() && title->getString()[0] != '\0') { std::string title_str = title->getString(); @@ -2822,25 +2857,42 @@ void LLVOAvatar::idleUpdateNameTagText(BOOL new_name) clearNameTag(); } - // Might be blank if name not available yet, that's OK - if (show_display_names) +// [RLVa:KB] - Checked: RLVa-1.2.2 + if ( (fRlvShowAvName) || (isSelf()) ) { - addNameTagLine(av_name.getDisplayName(), name_tag_color, LLFontGL::NORMAL, - LLFontGL::getFontSansSerif()); +// [/RLVa:KB] + // Might be blank if name not available yet, that's OK + if (show_display_names) + { + addNameTagLine(av_name.getDisplayName(), name_tag_color, LLFontGL::NORMAL, + LLFontGL::getFontSansSerif()); + } + // Suppress SLID display if display name matches exactly (ugh) + if (show_usernames && !av_name.isDisplayNameDefault()) + { + // *HACK: Desaturate the color + LLColor4 username_color = name_tag_color * 0.83f; + addNameTagLine(av_name.getUserName(), username_color, LLFontGL::NORMAL, + LLFontGL::getFontSansSerifSmall()); + } +// [RLVa:KB] - Checked: RLVa-1.2.2 } - // Suppress SLID display if display name matches exactly (ugh) - if (show_usernames && !av_name.isDisplayNameDefault()) + else { - // *HACK: Desaturate the color - LLColor4 username_color = name_tag_color * 0.83f; - addNameTagLine(av_name.getUserName(), username_color, LLFontGL::NORMAL, - LLFontGL::getFontSansSerifSmall()); + addNameTagLine(RlvStrings::getAnonym(av_name), name_tag_color, LLFontGL::NORMAL, LLFontGL::getFontSansSerif()); } +// [/RLVa:KB] } else { const LLFontGL* font = LLFontGL::getFontSansSerif(); std::string full_name = LLCacheName::buildFullName( firstname->getString(), lastname->getString() ); +// [RLVa:KB] - Checked: RLVa-1.2.2 + if ( (!fRlvShowAvName) && (!isSelf()) ) + { + full_name = RlvStrings::getAnonym(full_name); + } +// [/RLVa:KB] addNameTagLine(full_name, name_tag_color, LLFontGL::NORMAL, font); } @@ -5973,6 +6025,13 @@ void LLVOAvatar::sitDown(BOOL bSitting) { // Update Movement Controls according to own Sitting mode LLFloaterMove::setSittingMode(bSitting); + +// [RLVa:KB] - Checked: 2010-08-29 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c + if (rlv_handler_t::isEnabled()) + { + gRlvHandler.onSitOrStand(bSitting); + } +// [/RLVa:KB] } } diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index 5f48898cb165319a53b9594cfe3d247a8b501b9a..16cbdbeeafb66506bfd545047d1a8f4eea874435 100644 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -66,6 +66,15 @@ #include "llstartup.h" #include "llsdserialize.h" #include "llcorehttputil.h" +// [RLVa:KB] - Checked: RLVa-2.0.2 +#include "rlvhandler.h" +#include "rlvhelper.h" +#include "rlvlocks.h" +// [/RLVa:KB] +// [SL:KB] - Patch: Appearance-TeleportAttachKill | Checked: Catznip-4.0 +#include "llviewerparcelmgr.h" +extern BOOL gTeleportDisplay; +// [/SL:KB] #if LL_MSVC // disable boost::lexical_cast warning @@ -161,6 +170,9 @@ LLVOAvatarSelf::LLVOAvatarSelf(const LLUUID& id, const LLPCode pcode, LLViewerRegion* regionp) : LLVOAvatar(id, pcode, regionp), +// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7) + mAttachmentSignal(NULL), +// [/RLVa:KB] mScreenp(NULL), mLastRegionHandle(0), mRegionCrossingCount(0), @@ -222,6 +234,10 @@ void LLVOAvatarSelf::initInstance() mInitialBakeIDs[i] = LLUUID::null; } +// [RLVa:KB] - Checked: 2010-12-12 (RLVa-1.2.2c) | Added: RLVa-1.2.2c + RlvAttachPtLookup::initLookupTable(); +// [/RLVa:KB] + status &= buildMenus(); if (!status) { @@ -438,6 +454,7 @@ BOOL LLVOAvatarSelf::buildMenus() item_params.name =(item_params.label ); item_params.on_click.function_name = "Object.AttachToAvatar"; item_params.on_click.parameter = iter->first; + // [RLVa:KB] - No changes, but we do need the parameter to always be idxAttachPt for object_selected_and_point_valid() item_params.on_enable.function_name = "Object.EnableWear"; item_params.on_enable.parameter = iter->first; LLMenuItemCallGL* item = LLUICtrlFactory::create<LLMenuItemCallGL>(item_params); @@ -509,6 +526,7 @@ BOOL LLVOAvatarSelf::buildMenus() item_params.name =(item_params.label ); item_params.on_click.function_name = "Object.AttachToAvatar"; item_params.on_click.parameter = iter->first; + // [RLVa:KB] - No changes, but we do need the parameter to always be idxAttachPt for object_selected_and_point_valid() item_params.on_enable.function_name = "Object.EnableWear"; item_params.on_enable.parameter = iter->first; LLMenuItemCallGL* item = LLUICtrlFactory::create<LLMenuItemCallGL>(item_params); @@ -552,6 +570,7 @@ BOOL LLVOAvatarSelf::buildMenus() item_params.name =(item_params.label ); item_params.on_click.function_name = "Object.AttachToAvatar"; item_params.on_click.parameter = iter->first; + // [RLVa:KB] - No changes, but we do need the parameter to always be idxAttachPt for object_selected_and_point_valid() item_params.on_enable.function_name = "Object.EnableWear"; item_params.on_enable.parameter = iter->first; //* TODO: Skinning: @@ -618,6 +637,7 @@ BOOL LLVOAvatarSelf::buildMenus() item_params.label = LLTrans::getString(attachment->getName()); item_params.on_click.function_name = "Object.AttachToAvatar"; item_params.on_click.parameter = attach_index; + // [RLVa:KB] - No changes, but we do need the parameter to always be idxAttachPt for object_selected_and_point_valid() item_params.on_enable.function_name = "Object.EnableWear"; item_params.on_enable.parameter = attach_index; @@ -647,6 +667,10 @@ void LLVOAvatarSelf::cleanup() LLVOAvatarSelf::~LLVOAvatarSelf() { cleanup(); + +// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7) + delete mAttachmentSignal; +// [/RLVa:KB] } /** @@ -1030,12 +1054,25 @@ void LLVOAvatarSelf::updateAttachmentVisibility(U32 camera_mode) } else { +// [RLVa:KB] - Checked: RLVa-2.0.2 + bool fRlvCanShowAttachment = true; + if (rlv_handler_t::isEnabled()) + { + fRlvCanShowAttachment = + (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWSELF)) && + ( (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWSELFHEAD)) || (RLV_ATTACHGROUP_HEAD != rlvAttachGroupFromIndex(attachment->getGroup())) ); + } +// [/RLVa:KB] + switch (camera_mode) { case CAMERA_MODE_MOUSELOOK: if (LLVOAvatar::sVisibleInFirstPerson && attachment->getVisibleInFirstPerson()) { - attachment->setAttachmentVisibility(TRUE); +// [RLVa:KB] - Checked: RLVa-2.0.2 + attachment->setAttachmentVisibility(fRlvCanShowAttachment); +// [/RLVa:KB] +// attachment->setAttachmentVisibility(TRUE); } else { @@ -1043,7 +1080,10 @@ void LLVOAvatarSelf::updateAttachmentVisibility(U32 camera_mode) } break; default: - attachment->setAttachmentVisibility(TRUE); +// [RLVa:KB] - Checked: RLVa-2.0.2 + attachment->setAttachmentVisibility(fRlvCanShowAttachment); +// [/RLVa:KB] +// attachment->setAttachmentVisibility(TRUE); break; } } @@ -1124,6 +1164,28 @@ LLViewerObject* LLVOAvatarSelf::getWornAttachment(const LLUUID& inv_item_id) return NULL; } +// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7) +boost::signals2::connection LLVOAvatarSelf::setAttachmentCallback(const attachment_signal_t::slot_type& cb) +{ + if (!mAttachmentSignal) + mAttachmentSignal = new attachment_signal_t(); + return mAttachmentSignal->connect(cb); +} +// [/RLVa:KB] +// [RLVa:KB] - Checked: 2010-03-14 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a +LLViewerJointAttachment* LLVOAvatarSelf::getWornAttachmentPoint(const LLUUID& idItem) const +{ + const LLUUID& idItemBase = gInventory.getLinkedItemID(idItem); + for (attachment_map_t::const_iterator itAttachPt = mAttachmentPoints.begin(); itAttachPt != mAttachmentPoints.end(); ++itAttachPt) + { + LLViewerJointAttachment* pAttachPt = itAttachPt->second; + if (pAttachPt->getAttachedObject(idItemBase)) + return pAttachPt; + } + return NULL; +} +// [/RLVa:KB] + bool LLVOAvatarSelf::getAttachedPointName(const LLUUID& inv_item_id, std::string& name) const { if (!gInventory.getItem(inv_item_id)) @@ -1172,6 +1234,22 @@ const LLViewerJointAttachment *LLVOAvatarSelf::attachObject(LLViewerObject *view const LLUUID& attachment_id = viewer_object->getAttachmentItemID(); LLAppearanceMgr::instance().registerAttachment(attachment_id); updateLODRiggedAttachments(); + +// [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 (mAttachmentSignal) + { + (*mAttachmentSignal)(viewer_object, attachment, ACTION_ATTACH); + } + if (rlv_handler_t::isEnabled()) + { + RlvAttachmentLockWatchdog::instance().onAttach(viewer_object, attachment); + gRlvHandler.onAttach(viewer_object, attachment); + + if ( (attachment->getIsHUDAttachment()) && (!gRlvAttachmentLocks.hasLockedHUD()) ) + gRlvAttachmentLocks.updateLockedHUD(); + } +// [/RLVa:KB] } return attachment; @@ -1181,6 +1259,27 @@ const LLViewerJointAttachment *LLVOAvatarSelf::attachObject(LLViewerObject *view BOOL LLVOAvatarSelf::detachObject(LLViewerObject *viewer_object) { const LLUUID attachment_id = viewer_object->getAttachmentItemID(); + +// [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()) + { + 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); + } + if (mAttachmentSignal) + { + (*mAttachmentSignal)(viewer_object, pAttachPt, ACTION_DETACH); + } + } + } +// [/RLVa:KB] + if ( LLVOAvatar::detachObject(viewer_object) ) { // the simulator should automatically handle permission revocation @@ -1213,6 +1312,11 @@ BOOL LLVOAvatarSelf::detachObject(LLViewerObject *viewer_object) LLAppearanceMgr::instance().unregisterAttachment(attachment_id); } +// [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] + return TRUE; } return FALSE; @@ -1222,7 +1326,10 @@ BOOL LLVOAvatarSelf::detachObject(LLViewerObject *viewer_object) BOOL LLVOAvatarSelf::detachAttachmentIntoInventory(const LLUUID &item_id) { LLInventoryItem* item = gInventory.getItem(item_id); - if (item) +// 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); @@ -2831,3 +2938,57 @@ void LLVOAvatarSelf::dumpWearableInfo(LLAPRFile& outfile) } apr_file_printf( file, "\n</wearable_info>\n" ); } + +// [SL:KB] - Patch: Appearance-TeleportAttachKill | Checked: Catznip-4.0 +void LLVOAvatarSelf::addPendingDetach(const LLUUID& idObject) +{ + if (mPendingObjectDetach.end() == std::find(mPendingObjectDetach.begin(), mPendingObjectDetach.end(), idObject)) + mPendingObjectDetach.push_back(idObject); + + if ((!mPendingObjectDetach.empty()) && (!mTeleportDoneConn.connected())) + mTeleportDoneConn = LLViewerParcelMgr::instance().setTeleportDoneCallback(boost::bind(&LLVOAvatarSelf::onTeleportDone, this)); +} + +bool LLVOAvatarSelf::isPendingDetach(const LLUUID& idObject) const +{ + return mPendingObjectDetach.end() != std::find(mPendingObjectDetach.begin(), mPendingObjectDetach.end(), idObject); +} + +void LLVOAvatarSelf::removePendingDetach(const LLUUID& idObject) +{ + auto itPendingDetach = std::find(mPendingObjectDetach.begin(), mPendingObjectDetach.end(), idObject); + if (mPendingObjectDetach.end() != itPendingDetach) + mPendingObjectDetach.erase(itPendingDetach); + + if (mPendingObjectDetach.empty()) + mTeleportDoneConn.disconnect(); +} + +void LLVOAvatarSelf::onTeleportDone() +{ + mTeleportDoneConn.disconnect(); + doAfterInterval(boost::bind(&LLVOAvatarSelf::checkPendingDetach, this), 30.f); +} + +void LLVOAvatarSelf::checkPendingDetach() +{ + if (gTeleportDisplay) + return; + + for (const LLUUID& idObj : mPendingObjectDetach) + { + LLViewerObject* pObject = gObjectList.findObject(idObj); + if (pObject) + { + gObjectList.killObject(pObject); + if (gShowObjectUpdates) + { + LLColor4 color(0.f, 1.f, 0.f, 1.f); + gPipeline.addDebugBlip(pObject->getPositionAgent(), color); + } + LLSelectMgr::getInstance()->removeObjectFromSelections(idObj); + } + } + mPendingObjectDetach.clear(); +} +// [/SL:KB] diff --git a/indra/newview/llvoavatarself.h b/indra/newview/llvoavatarself.h index a9c4ab26a9ac0762f1131ebefd092f2ba3dd1e9d..ad80dedb9787e2a1eccb664af4c42205c784bc1d 100644 --- a/indra/newview/llvoavatarself.h +++ b/indra/newview/llvoavatarself.h @@ -296,10 +296,21 @@ class LLVOAvatarSelf : BOOL isWearingAttachment(const LLUUID& inv_item_id) const; LLViewerObject* getWornAttachment(const LLUUID& inv_item_id); bool getAttachedPointName(const LLUUID& inv_item_id, std::string& name) const; +// [RLVa:KB] - Checked: 2009-12-18 (RLVa-1.1.0i) | Added: RLVa-1.1.0i + LLViewerJointAttachment* getWornAttachmentPoint(const LLUUID& inv_item_id) const; +// [/RLVa:KB] /*virtual*/ const LLViewerJointAttachment *attachObject(LLViewerObject *viewer_object); /*virtual*/ BOOL detachObject(LLViewerObject *viewer_object); static BOOL detachAttachmentIntoInventory(const LLUUID& item_id); +// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7) + enum EAttachAction { ACTION_ATTACH, ACTION_DETACH }; + typedef boost::signals2::signal<void (LLViewerObject*, const LLViewerJointAttachment*, EAttachAction)> attachment_signal_t; + boost::signals2::connection setAttachmentCallback(const attachment_signal_t::slot_type& cb); +// [/RLVa:KB] +// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7) + attachment_signal_t* mAttachmentSignal; +// [/RLVa:KB] //-------------------------------------------------------------------- // HUDs //-------------------------------------------------------------------- @@ -396,6 +407,18 @@ class LLVOAvatarSelf : F32 mDebugBakedTextureTimes[LLAvatarAppearanceDefines::BAKED_NUM_INDICES][2]; // time to start upload and finish upload of each baked texture void debugTimingLocalTexLoaded(BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata); +// [SL:KB] - Patch: Appearance-TeleportAttachKill | Checked: Catznip-4.0 +public: + void addPendingDetach(const LLUUID& idObject); + bool isPendingDetach(const LLUUID& idObject) const; + void removePendingDetach(const LLUUID& idObject); + void checkPendingDetach(); + void onTeleportDone(); +protected: + std::list<LLUUID> mPendingObjectDetach; + boost::signals2::connection mTeleportDoneConn; +// [/SL:KB] + void appearanceChangeMetricsCoro(std::string url); bool mInitialMetric; S32 mMetricSequence; diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index e69a8d1d1d121bd137753571bd8ad6830d41a9cc..0711677566e736af2c36fe2a76f8b5d91c352890 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -77,6 +77,10 @@ #include "llvoavatar.h" #include "llvocache.h" #include "llmaterialmgr.h" +// [RLVa:KB] - Checked: RLVa-2.0.0 +#include "rlvactions.h" +#include "rlvlocks.h" +// [/RLVa:KB] const F32 FORCE_SIMPLE_RENDER_AREA = 512.f; const F32 FORCE_CULL_AREA = 8.f; @@ -4432,7 +4436,14 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, LL_WARNS("RenderMaterials") << "Oh no! No binormals for this alpha blended face!" << LL_ENDL; } - if (facep->getViewerObject()->isSelected() && LLSelectMgr::getInstance()->mHideSelectedObjects) +// if (facep->getViewerObject()->isSelected() && LLSelectMgr::getInstance()->mHideSelectedObjects) +// [RLVa:KB] - Checked: 2010-11-29 (RLVa-1.3.0c) | Modified: RLVa-1.3.0c + const LLViewerObject* pObj = facep->getViewerObject(); + if ( (pObj->isSelected() && LLSelectMgr::getInstance()->mHideSelectedObjects) && + ( (!RlvActions::isRlvEnabled()) || + ( ((!pObj->isHUDAttachment()) || (!gRlvAttachmentLocks.isLockedAttachment(pObj->getRootEdit()))) && + (RlvActions::canEdit(pObj)) ) ) ) +// [/RVLa:KB] { return; } diff --git a/indra/newview/llwearableitemslist.cpp b/indra/newview/llwearableitemslist.cpp index f8981d0c51501cc03aba1e25a6237f3d8e1a8912..3324d05a93201fab6dfdadc1035654ad310c76ee 100644 --- a/indra/newview/llwearableitemslist.cpp +++ b/indra/newview/llwearableitemslist.cpp @@ -39,6 +39,10 @@ #include "lltransutil.h" #include "llviewerattachmenu.h" #include "llvoavatarself.h" +// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a) +#include "rlvhandler.h" +#include "rlvlocks.h" +// [/RLVa:KB] class LLFindOutfitItems : public LLInventoryCollectFunctor { @@ -848,6 +852,13 @@ void LLWearableItemsList::ContextMenu::updateItemsVisibility(LLContextMenu* menu bool can_be_worn = true; +// [RLVa:KB] - Checked: 2010-09-04 (RLVa-1.2.1a) | Added: RLVa-1.2.1a + // We'll enable a menu option if at least one item in the selection is wearable/removable + bool rlvCanWearReplace = !rlv_handler_t::isEnabled(); + bool rlvCanWearAdd = !rlv_handler_t::isEnabled(); + bool rlvCanRemove = !rlv_handler_t::isEnabled(); +// [/RLVa:KB] + for (uuid_vec_t::const_iterator it = ids.begin(); it != ids.end(); ++it) { LLUUID id = *it; @@ -888,6 +899,29 @@ void LLWearableItemsList::ContextMenu::updateItemsVisibility(LLContextMenu* menu { can_be_worn = get_can_item_be_worn(item->getLinkedUUID()); } + +// [RLVa:KB] - Checked: 2010-09-04 (RLVa-1.2.1a) | Added: RLVa-1.2.1a + if (rlv_handler_t::isEnabled()) + { + ERlvWearMask eWearMask = RLV_WEAR_LOCKED; + switch (item->getType()) + { + case LLAssetType::AT_BODYPART: + case LLAssetType::AT_CLOTHING: + eWearMask = gRlvWearableLocks.canWear(item); + rlvCanRemove |= (is_worn) ? gRlvWearableLocks.canRemove(item) : false; + break; + case LLAssetType::AT_OBJECT: + eWearMask = gRlvAttachmentLocks.canAttach(item); + rlvCanRemove |= (is_worn) ? gRlvAttachmentLocks.canDetach(item) : false; + break; + default: + break; + } + rlvCanWearReplace |= ((eWearMask & RLV_WEAR_REPLACE) == RLV_WEAR_REPLACE); + rlvCanWearAdd |= ((eWearMask & RLV_WEAR_ADD) == RLV_WEAR_ADD); + } +// [/RLVa:KB] } // for bool standalone = mParent ? mParent->isStandalone() : false; @@ -895,10 +929,15 @@ void LLWearableItemsList::ContextMenu::updateItemsVisibility(LLContextMenu* menu // *TODO: eliminate multiple traversals over the menu items setMenuItemVisible(menu, "wear_wear", n_already_worn == 0 && n_worn == 0 && can_be_worn); - setMenuItemEnabled(menu, "wear_wear", n_already_worn == 0 && n_worn == 0); +// setMenuItemEnabled(menu, "wear_wear", n_already_worn == 0 && n_worn == 0); setMenuItemVisible(menu, "wear_add", wear_add_visible); - setMenuItemEnabled(menu, "wear_add", LLAppearanceMgr::instance().canAddWearables(ids)); +// setMenuItemEnabled(menu, "wear_add", LLAppearanceMgr::instance().canAddWearables(ids)); setMenuItemVisible(menu, "wear_replace", n_worn == 0 && n_already_worn != 0 && can_be_worn); +// [RLVa:KB] - Checked: 2010-09-04 (RLVa-1.2.1a) | Added: RLVa-1.2.1a + setMenuItemEnabled(menu, "wear_wear", n_already_worn == 0 && n_worn == 0 && rlvCanWearReplace); + setMenuItemEnabled(menu, "wear_add", LLAppearanceMgr::instance().canAddWearables(ids) && rlvCanWearAdd); + setMenuItemEnabled(menu, "wear_replace", rlvCanWearReplace); +// [/RLVa:KB] //visible only when one item selected and this item is worn setMenuItemVisible(menu, "edit", !standalone && mask & (MASK_CLOTHING|MASK_BODYPART) && n_worn == n_items && n_worn == 1); setMenuItemEnabled(menu, "edit", n_editable == 1 && n_worn == 1 && n_items == 1); @@ -909,7 +948,12 @@ void LLWearableItemsList::ContextMenu::updateItemsVisibility(LLContextMenu* menu setMenuItemVisible(menu, "take_off", mask == MASK_CLOTHING && n_worn == n_items); setMenuItemVisible(menu, "detach", mask == MASK_ATTACHMENT && n_worn == n_items); setMenuItemVisible(menu, "take_off_or_detach", mask == (MASK_ATTACHMENT|MASK_CLOTHING)); - setMenuItemEnabled(menu, "take_off_or_detach", n_worn == n_items); +// setMenuItemEnabled(menu, "take_off_or_detach", n_worn == n_items); +// [RLVa:KB] - Checked: 2010-09-04 (RLVa-1.2.1a) | Added: RLVa-1.2.1a + setMenuItemEnabled(menu, "take_off", rlvCanRemove); + setMenuItemEnabled(menu, "detach", rlvCanRemove); + setMenuItemEnabled(menu, "take_off_or_detach", (n_worn == n_items) && (rlvCanRemove)); +// [/RLVa:KB] setMenuItemVisible(menu, "object_profile", !standalone); setMenuItemEnabled(menu, "object_profile", n_items == 1); setMenuItemVisible(menu, "--no options--", FALSE); diff --git a/indra/newview/llwlparammanager.cpp b/indra/newview/llwlparammanager.cpp index 2b6d88efef7ecc2b5e98fd9cd3e2eea3b0c32e09..37eaa9425cf12e175d5100211476081a08522a66 100644 --- a/indra/newview/llwlparammanager.cpp +++ b/indra/newview/llwlparammanager.cpp @@ -61,6 +61,10 @@ #include "curl/curl.h" #include "llstreamtools.h" +// [RLVa:KB] - Checked: 2011-09-04 (RLVa-1.4.1a) | Added: RLVa-1.4.1a +#include <boost/algorithm/string.hpp> +// [/RLVa:KB] + LLWLParamManager::LLWLParamManager() : //set the defaults for the controls @@ -644,6 +648,19 @@ void LLWLParamManager::getPresetNames(preset_name_list_t& region, preset_name_li } } +// [RLVa:KB] - Checked: 2011-09-04 (RLVa-1.4.1a) | Added: RLVa-1.4.1a +const std::string& LLWLParamManager::findPreset(const std::string& strPresetName, LLEnvKey::EScope eScope) +{ + for (std::map<LLWLParamKey, LLWLParamSet>::const_iterator itList = mParamList.begin(); itList != mParamList.end(); itList++) + { + const LLWLParamKey& wlKey = itList->first; + if ( (wlKey.scope == eScope) && (boost::iequals(wlKey.name, strPresetName)) ) + return wlKey.name; + } + return LLStringUtil::null; +} +// [/RLVa:KB] + void LLWLParamManager::getUserPresetNames(preset_name_list_t& user) const { preset_name_list_t region, sys; // unused diff --git a/indra/newview/llwlparammanager.h b/indra/newview/llwlparammanager.h index e13aed98edfc507d5bec39592e9fdc8493cc67a1..43baae3d41f599f7f482ce775043b9cb22d1cb4a 100644 --- a/indra/newview/llwlparammanager.h +++ b/indra/newview/llwlparammanager.h @@ -287,6 +287,10 @@ class LLWLParamManager : public LLSingleton<LLWLParamManager> /// @return user and system preset names as a single list void getPresetNames(preset_name_list_t& region, preset_name_list_t& user, preset_name_list_t& sys) const; +// [RLVa:KB] - Checked: 2011-09-04 (RLVa-1.4.1a) | Added: RLVa-1.4.1a + const std::string& findPreset(const std::string& strPresetName, LLEnvKey::EScope eScope); +// [/RLVa:KB] + /// @return user preset names void getUserPresetNames(preset_name_list_t& user) const; diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp index 11d3706821fa5cf20411502ce71ddd05f57c526a..a98c4145099b7062cdcbb1a070575ed78dbd7616 100644 --- a/indra/newview/llworld.cpp +++ b/indra/newview/llworld.cpp @@ -1327,6 +1327,35 @@ void LLWorld::getAvatars(uuid_vec_t* avatar_ids, std::vector<LLVector3d>* positi } } +// [RLVa:KB] - Checked: RLVa-2.0.1 +bool LLWorld::getAvatar(const LLUUID& idAvatar, LLVector3d& posAvatar) const +{ + for (const LLCharacter* pCharacter : LLCharacter::sInstances) + { + const LLVOAvatar* pAvatar = static_cast<const LLVOAvatar*>(pCharacter); + if ( (!pAvatar->isDead()) && (!pAvatar->mIsDummy) && (!pAvatar->isOrphaned()) && (idAvatar == pAvatar->getID()) ) + { + posAvatar = pAvatar->getPositionGlobal(); + return true; + } + } + + for (const LLViewerRegion* pRegion : LLWorld::getInstance()->getRegionList()) + { + for (S32 idxAgent = 0, cntAgent = pRegion->mMapAvatarIDs.size(); idxAgent < cntAgent; ++idxAgent) + { + if (idAvatar == pRegion->mMapAvatarIDs[idxAgent]) + { + posAvatar = unpackLocalToGlobalPosition(pRegion->mMapAvatars[idxAgent], pRegion->getOriginGlobal()); + return true; + } + } + } + + return false; +} +// [/RLVa:KB] + bool LLWorld::isRegionListed(const LLViewerRegion* region) const { region_list_t::const_iterator it = find(mRegionList.begin(), mRegionList.end(), region); diff --git a/indra/newview/llworld.h b/indra/newview/llworld.h index b2d84180648ddfadc41c3ce0185f9354153451d8..325a120f55b6e921c29144fc0bda040ff3a12f33 100644 --- a/indra/newview/llworld.h +++ b/indra/newview/llworld.h @@ -162,6 +162,9 @@ class LLWorld : public LLSingleton<LLWorld> uuid_vec_t* avatar_ids = NULL, std::vector<LLVector3d>* positions = NULL, const LLVector3d& relative_to = LLVector3d(), F32 radius = FLT_MAX) const; +// [RLVa:KB] - Checked: RLVa-2.0.1 + bool getAvatar(const LLUUID& idAvatar, LLVector3d& posAvatar) const; +// [/RLVa:KB] // Returns 'true' if the region is in mRegionList, // 'false' if the region has been removed due to region change diff --git a/indra/newview/llworldmapview.cpp b/indra/newview/llworldmapview.cpp index 62fad322467a1387af688ae0f98d4774956d77ac..4b61841600f81bc1933fbfd32ce4a3ba7fbd8d5b 100644 --- a/indra/newview/llworldmapview.cpp +++ b/indra/newview/llworldmapview.cpp @@ -55,6 +55,9 @@ #include "llviewerregion.h" #include "llviewerwindow.h" #include "lltrans.h" +// [RLVa:KB] - Checked: 2010-04-19 (RLVa-1.2.0f) +#include "rlvhandler.h" +// [/RLVa:KB] #include "llglheaders.h" @@ -459,7 +462,10 @@ void LLWorldMapView::draw() { mesg = info->getName(); } - if (!mesg.empty()) +// if (!mesg.empty()) +// [RLVa:KB] - Checked: 2012-02-08 (RLVa-1.4.5) | Added: RLVa-1.4.5 + if ( (!mesg.empty()) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) ) +// [/RLVa:KB] { font->renderUTF8( mesg, 0, @@ -993,7 +999,10 @@ void LLWorldMapView::drawTracking(const LLVector3d& pos_global, const LLColor4& text_x = llclamp(text_x, half_text_width + TEXT_PADDING, getRect().getWidth() - half_text_width - TEXT_PADDING); text_y = llclamp(text_y + vert_offset, TEXT_PADDING + vert_offset, getRect().getHeight() - font->getLineHeight() - TEXT_PADDING - vert_offset); - if (label != "") +// if (label != "") +// [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.4.5) | Added: RLVa-1.0.0 + if ( (label != "") && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) ) +// [/RLVa:KB] { font->renderUTF8( label, 0, @@ -1053,7 +1062,12 @@ BOOL LLWorldMapView::handleToolTip( S32 x, S32 y, MASK mask ) { LLViewerRegion *region = gAgent.getRegion(); - std::string message = llformat("%s (%s)", info->getName().c_str(), info->getAccessString().c_str()); +// [RLVa:KB] - Checked: 2010-04-19 (RLVa-1.4.5) | Modified: RLVa-1.4.5 + std::string message = llformat("%s (%s)", + (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) ? info->getName().c_str() : RlvStrings::getString(RLV_STRING_HIDDEN_REGION).c_str(), + info->getAccessString().c_str()); +// [/RLVa:KB] +// std::string message = llformat("%s (%s)", info->getName().c_str(), info->getAccessString().c_str()); if (!info->isDown()) { diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index c6bbfb1c8ffd975cd57f9642b4319dec6a68927c..a5ffdd5da99930578ddab2796df818d3ac62849a 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -114,6 +114,10 @@ #include "llpathfindingpathtool.h" #include "llscenemonitor.h" #include "llprogressview.h" +// [RLVa:KB] - Checked: RLVa-2.0.0 +#include "rlvactions.h" +#include "rlvlocks.h" +// [/RLVa:KB] #ifdef _DEBUG // Debug indices is disabled for now for debug performance - djs 4/24/02 @@ -397,6 +401,9 @@ BOOL LLPipeline::sMemAllocationThrottled = FALSE; S32 LLPipeline::sVisibleLightCount = 0; F32 LLPipeline::sMinRenderSize = 0.f; BOOL LLPipeline::sRenderingHUDs; +// [SL:KB] - Patch: Render-TextureToggle (Catznip-4.0) +bool LLPipeline::sRenderTextures = true; +// [/SL:KB] // EventHost API LLPipeline listener. static LLPipelineListener sPipelineListener; @@ -784,7 +791,17 @@ void LLPipeline::resizeScreenTexture() GLuint resX = gViewerWindow->getWorldViewWidthRaw(); GLuint resY = gViewerWindow->getWorldViewHeightRaw(); - if ((resX != mScreen.getWidth()) || (resY != mScreen.getHeight())) +// [RLVa:KB] - Checked: 2014-02-23 (RLVa-1.4.10) + U32 resMod = RenderResolutionDivisor, resAdjustedX = resX, resAdjustedY = resY; + if ( (resMod > 1) && (resMod < resX) && (resMod < resY) ) + { + resAdjustedX /= resMod; + resAdjustedY /= resMod; + } + + if ( (resAdjustedX != mScreen.getWidth()) || (resAdjustedY != mScreen.getHeight()) ) +// [/RLVa:KB] +// if ((resX != mScreen.getWidth()) || (resY != mScreen.getHeight())) { releaseScreenBuffers(); if (!allocateScreenBuffer(resX,resY)) @@ -3528,8 +3545,15 @@ void LLPipeline::stateSort(LLDrawable* drawablep, LLCamera& camera) if (LLSelectMgr::getInstance()->mHideSelectedObjects) { - if (drawablep->getVObj().notNull() && - drawablep->getVObj()->isSelected()) +// if (drawablep->getVObj().notNull() && +// drawablep->getVObj()->isSelected()) +// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.2.1f + const LLViewerObject* pObj = drawablep->getVObj(); + if ( (pObj) && (pObj->isSelected()) && + ( (!RlvActions::isRlvEnabled()) || + ( ((!pObj->isHUDAttachment()) || (!gRlvAttachmentLocks.isLockedAttachment(pObj->getRootEdit()))) && + (RlvActions::canEdit(pObj)) ) ) ) +// [/RVLa:KB] { return; } diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index bba36351d9f374e9d18fd4f82a0fcd2f78493ac5..eb21b552d7cb0e2e88db81a3afba83ef581a833f 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -587,6 +587,9 @@ class LLPipeline static S32 sVisibleLightCount; static F32 sMinRenderSize; static BOOL sRenderingHUDs; +// [SL:KB] - Patch: Render-TextureToggle (Catznip-4.0) + static bool sRenderTextures; +// [/SL:KB] static LLTrace::EventStatHandle<S64> sStatBatchSize; diff --git a/indra/newview/rlvactions.cpp b/indra/newview/rlvactions.cpp new file mode 100644 index 0000000000000000000000000000000000000000..913ded899cb48f47d7cefb0f0a255730f5b08335 --- /dev/null +++ b/indra/newview/rlvactions.cpp @@ -0,0 +1,370 @@ +/** + * + * Copyright (c) 2009-2016, Kitty Barnett + * + * The source code in this file is provided to you under the terms of the + * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt + * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.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 "llagent.h" +#include "llimview.h" +#include "llviewercamera.h" +#include "llvoavatarself.h" +#include "llworld.h" +#include "rlvactions.h" +#include "rlvhelper.h" +#include "rlvhandler.h" + +// ============================================================================ +// Camera +// + +bool RlvActions::canChangeCameraFOV(const LLUUID& idRlvObject) +{ + // NOTE: if an object has exclusive camera control then all other objects are locked out + return (!gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM)) || (gRlvHandler.hasBehaviour(idRlvObject, RLV_BHVR_SETCAM)); +} + +bool RlvActions::canChangeCameraPreset(const LLUUID& idRlvObject) +{ + // NOTE: if an object has exclusive camera control then all other objects are locked out + return + ( (!gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM)) || (gRlvHandler.hasBehaviour(idRlvObject, RLV_BHVR_SETCAM)) ) && + (!gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_EYEOFFSET)) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_FOCUSOFFSET)); +} + +bool RlvActions::canChangeToMouselook() +{ + // User can switch to mouselook if: + // - not specifically prevented from going into mouselook (NOTE: if an object has exclusive camera control only that object can prevent mouselook) + // - there is no minimum camera distance defined (or it's higher than > 0m) + const RlvBehaviourModifier* pCamDistMinModifier = RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_SETCAM_AVDISTMIN); + return + ( (!gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM)) ? !gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_MOUSELOOK) : !gRlvHandler.hasBehaviour(pCamDistMinModifier->getPrimaryObject(), RLV_BHVR_SETCAM_MOUSELOOK) ) && + ( (!pCamDistMinModifier->hasValue()) || (pCamDistMinModifier->getValue<float>() == 0.f) ); +} + +bool RlvActions::isCameraDistanceClamped() +{ + return + (gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_AVDISTMIN)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_AVDISTMAX)) || + (gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_ORIGINDISTMIN)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_ORIGINDISTMAX)); +} + +bool RlvActions::isCameraFOVClamped() +{ + return (gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_FOVMIN)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_FOVMAX)); +} + +bool RlvActions::isCameraPresetLocked() +{ + return (gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_EYEOFFSET)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_FOCUSOFFSET)); +} + +bool RlvActions::getCameraAvatarDistanceLimits(float& nDistMin, float& nDistMax) +{ + bool fDistMin = gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_AVDISTMIN), fDistMax = gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_AVDISTMAX); + if ( (fDistMin) || (fDistMax) ) + { + static RlvCachedBehaviourModifier<float> sCamDistMin(RLV_MODIFIER_SETCAM_AVDISTMIN); + static RlvCachedBehaviourModifier<float> sCamDistMax(RLV_MODIFIER_SETCAM_AVDISTMAX); + + nDistMax = (fDistMax) ? sCamDistMax : F32_MAX; + nDistMin = (fDistMin) ? sCamDistMin : 0.0; + return true; + } + return false; +} + +bool RlvActions::getCameraOriginDistanceLimits(float& nDistMin, float& nDistMax) +{ + bool fDistMin = gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_ORIGINDISTMIN), fDistMax = gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_ORIGINDISTMAX); + if ( (fDistMin) || (fDistMax) ) + { + static RlvCachedBehaviourModifier<float> sCamDistMin(RLV_MODIFIER_SETCAM_ORIGINDISTMIN); + static RlvCachedBehaviourModifier<float> sCamDistMax(RLV_MODIFIER_SETCAM_ORIGINDISTMAX); + + nDistMax = (fDistMax) ? sCamDistMax : F32_MAX; + nDistMin = (fDistMin) ? sCamDistMin : 0.0; + return true; + } + return false; +} + +bool RlvActions::getCameraFOVLimits(F32& nFOVMin, F32& nFOVMax) +{ + bool fClampMin = gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_FOVMIN), fClampMax = gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_FOVMAX); + if ( (fClampMin) || (fClampMax) ) + { + static RlvCachedBehaviourModifier<float> sCamFovMin(RLV_MODIFIER_SETCAM_FOVMIN); + static RlvCachedBehaviourModifier<float> sCamFovMax(RLV_MODIFIER_SETCAM_FOVMAX); + + nFOVMin = (fClampMin) ? sCamFovMin : LLViewerCamera::getInstance()->getMinView(); + nFOVMax = (fClampMax) ? sCamFovMax : LLViewerCamera::getInstance()->getMaxView(); + return true; + } + return false; +} + +// ============================================================================ +// Communication/Avatar interaction +// + +bool RlvActions::s_BlockNamesContexts[SNC_COUNT] = { 0 }; + +bool RlvActions::canChangeActiveGroup(const LLUUID& idRlvObject) +{ + // User can change their active group if: + // - not specifically restricted (by another object that the one specified) from changing their active group + return (idRlvObject.isNull()) ? !gRlvHandler.hasBehaviour(RLV_BHVR_SETGROUP) : !gRlvHandler.hasBehaviourExcept(RLV_BHVR_SETGROUP, idRlvObject); +} + +// Little helper function to check the IM exclusion range for @recvim, @sendim and @startim (returns: min_dist <= (pos user - pos target) <= max_dist) +static bool rlvCheckAvatarIMDistance(const LLUUID& idAvatar, ERlvBehaviourModifier eModDistMin, ERlvBehaviourModifier eModDistMax) +{ + LLVector3d posAgent; + const RlvBehaviourModifier *pBhvrModDistMin = RlvBehaviourDictionary::instance().getModifier(eModDistMin), *pBhvrModDistMax = RlvBehaviourDictionary::instance().getModifier(eModDistMax); + if ( ((pBhvrModDistMin->hasValue()) || (pBhvrModDistMax->hasValue())) && (LLWorld::getInstance()->getAvatar(idAvatar, posAgent)) ) + { + float nDist = llabs(dist_vec_squared(gAgent.getPositionGlobal(), posAgent)); + return (nDist >= pBhvrModDistMin->getValue<float>()) && (nDist <= pBhvrModDistMax->getValue<float>()); + } + return false; +} + +bool RlvActions::canReceiveIM(const LLUUID& idSender) +{ + // User can receive an IM from "sender" (could be an agent or a group) if: + // - not generally restricted from receiving IMs (or the sender is an exception or inside the exclusion range) + // - not specifically restricted from receiving an IM from the sender + return + (!isRlvEnabled()) || + ( ( (!gRlvHandler.hasBehaviour(RLV_BHVR_RECVIM)) || (gRlvHandler.isException(RLV_BHVR_RECVIM, idSender)) || (rlvCheckAvatarIMDistance(idSender, RLV_MODIFIER_RECVIMDISTMIN, RLV_MODIFIER_RECVIMDISTMAX)) ) && + ( (!gRlvHandler.hasBehaviour(RLV_BHVR_RECVIMFROM)) || (!gRlvHandler.isException(RLV_BHVR_RECVIMFROM, idSender)) ) ); +} + +bool RlvActions::canPlayGestures() +{ + return (!gRlvHandler.hasBehaviour(RLV_BHVR_SENDGESTURE)); +} + +bool RlvActions::canSendChannel(int nChannel) +{ + return + ( (!gRlvHandler.hasBehaviour(RLV_BHVR_SENDCHANNEL)) || (gRlvHandler.isException(RLV_BHVR_SENDCHANNEL, nChannel)) ) && + ( (!gRlvHandler.hasBehaviour(RLV_BHVR_SENDCHANNELEXCEPT)) || (!gRlvHandler.isException(RLV_BHVR_SENDCHANNELEXCEPT, nChannel)) ); +} + +bool RlvActions::canSendIM(const LLUUID& idRecipient) +{ + // User can send an IM to "recipient" (could be an agent or a group) if: + // - not generally restricted from sending IMs (or the recipient is an exception or inside the exclusion range) + // - not specifically restricted from sending an IM to the recipient + return + (!isRlvEnabled()) || + ( ( (!gRlvHandler.hasBehaviour(RLV_BHVR_SENDIM)) || (gRlvHandler.isException(RLV_BHVR_SENDIM, idRecipient)) || (rlvCheckAvatarIMDistance(idRecipient, RLV_MODIFIER_SENDIMDISTMIN, RLV_MODIFIER_SENDIMDISTMAX)) ) && + ( (!gRlvHandler.hasBehaviour(RLV_BHVR_SENDIMTO)) || (!gRlvHandler.isException(RLV_BHVR_SENDIMTO, idRecipient)) ) ); +} + +bool RlvActions::canStartIM(const LLUUID& idRecipient) +{ + // User can start an IM session with "recipient" (could be an agent or a group) if: + // - not generally restricted from starting IM sessions (or the recipient is an exception or inside the exclusion range) + // - not specifically restricted from starting an IM session with the recipient + // - the session already exists + return + (!isRlvEnabled()) || + ( ( (!gRlvHandler.hasBehaviour(RLV_BHVR_STARTIM)) || (gRlvHandler.isException(RLV_BHVR_STARTIM, idRecipient)) || (rlvCheckAvatarIMDistance(idRecipient, RLV_MODIFIER_STARTIMDISTMIN, RLV_MODIFIER_STARTIMDISTMAX)) ) && + ( (!gRlvHandler.hasBehaviour(RLV_BHVR_STARTIMTO)) || (!gRlvHandler.isException(RLV_BHVR_STARTIMTO, idRecipient)) ) ) || + ( (hasOpenP2PSession(idRecipient)) || (hasOpenGroupSession(idRecipient)) ); +} + +bool RlvActions::canShowName(EShowNamesContext eContext, const LLUUID& idAgent) +{ + // Handle most common case upfront + if (!s_BlockNamesContexts[eContext]) + return true; + + if (idAgent.notNull()) + { + switch (eContext) + { + // Show/hide avatar nametag + case SNC_NAMETAG: + return (gRlvHandler.isException(RLV_BHVR_SHOWNAMETAGS, idAgent)) || (gAgentID == idAgent); + // Show/hide avatar name + case SNC_DEFAULT: + case SNC_TELEPORTOFFER: + case SNC_TELEPORTREQUEST: + return gRlvHandler.isException(RLV_BHVR_SHOWNAMES, idAgent); + } + } + return false; +} + +bool RlvActions::canShowNearbyAgents() +{ + return !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNEARBY); +} + +// ============================================================================ +// Movement +// + +bool RlvActions::canAcceptTpOffer(const LLUUID& idSender) +{ + return ((!gRlvHandler.hasBehaviour(RLV_BHVR_TPLURE)) || (gRlvHandler.isException(RLV_BHVR_TPLURE, idSender))) && (canStand()); +} + +bool RlvActions::autoAcceptTeleportOffer(const LLUUID& idSender) +{ + return ((idSender.notNull()) && (gRlvHandler.isException(RLV_BHVR_ACCEPTTP, idSender))) || (gRlvHandler.hasBehaviour(RLV_BHVR_ACCEPTTP)); +} + +bool RlvActions::canAcceptTpRequest(const LLUUID& idSender) +{ + return (!gRlvHandler.hasBehaviour(RLV_BHVR_TPREQUEST)) || (gRlvHandler.isException(RLV_BHVR_TPREQUEST, idSender)); +} + +bool RlvActions::autoAcceptTeleportRequest(const LLUUID& idRequester) +{ + return ((idRequester.notNull()) && (gRlvHandler.isException(RLV_BHVR_ACCEPTTPREQUEST, idRequester))) || (gRlvHandler.hasBehaviour(RLV_BHVR_ACCEPTTPREQUEST)); +} + +// ============================================================================ +// Teleporting +// + +bool RlvActions::canTeleportToLocal(const LLVector3d& posGlobal) +{ + // User can initiate a local teleport if: + // - not restricted from "sit teleporting" (or the destination is within the allowed xy-radius) + // - not restricted from teleporting locally (or the destination is within the allowed xy-radius) + // - can stand up (or isn't sitting) + // NOTE: if we're teleporting due to an active command we should disregard any restrictions from the same object + const LLUUID& idRlvObjExcept = gRlvHandler.getCurrentObject(); + bool fCanStand = RlvActions::canStand(idRlvObjExcept); + if ( (fCanStand) && ((gRlvHandler.hasBehaviourExcept(RLV_BHVR_SITTP, gRlvHandler.getCurrentObject())) || (gRlvHandler.hasBehaviourExcept(RLV_BHVR_TPLOCAL, gRlvHandler.getCurrentObject()))) ) + { + // User can stand up but is either @sittp or @tplocal restricted so we need to distance check + const F32 nDistSq = (LLVector2(posGlobal.mdV[0], posGlobal.mdV[1]) - LLVector2(gAgent.getPositionGlobal().mdV[0], gAgent.getPositionGlobal().mdV[1])).lengthSquared(); + F32 nMaxDist = llmin(RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_TPLOCALDIST)->getValue<float>(), RLV_MODIFIER_TPLOCAL_DEFAULT); + if (gRlvHandler.hasBehaviour(RLV_BHVR_SITTP)) + nMaxDist = llmin(nMaxDist, RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_SITTPDIST)->getValue<F32>()); + return (nDistSq < nMaxDist * nMaxDist); + } + return fCanStand; +} + +bool RlvActions::canTeleportToLocation() +{ + // NOTE: if we're teleporting due to an active command we should disregard any restrictions from the same object + const LLUUID& idRlvObjExcept = gRlvHandler.getCurrentObject(); + return (!gRlvHandler.hasBehaviourExcept(RLV_BHVR_TPLOC, idRlvObjExcept)) && (RlvActions::canStand(idRlvObjExcept)); +} + +bool RlvActions::isLocalTp(const LLVector3d& posGlobal) +{ + const F32 nDistSq = (LLVector2(posGlobal.mdV[0], posGlobal.mdV[1]) - LLVector2(gAgent.getPositionGlobal().mdV[0], gAgent.getPositionGlobal().mdV[1])).lengthSquared(); + return nDistSq < RLV_MODIFIER_TPLOCAL_DEFAULT * RLV_MODIFIER_TPLOCAL_DEFAULT; +} + +// ============================================================================ +// World interaction +// + +bool RlvActions::canEdit(const LLViewerObject* pObj) +{ + // User can edit the specified object if: + // - not generally restricted from editing (or the object's root is an exception) + // - not specifically restricted from editing this object's root + return + (pObj) && + ((!hasBehaviour(RLV_BHVR_EDIT)) || (gRlvHandler.isException(RLV_BHVR_EDIT, pObj->getRootEdit()->getID()))) && + ((!hasBehaviour(RLV_BHVR_EDITOBJ)) || (!gRlvHandler.isException(RLV_BHVR_EDITOBJ, pObj->getRootEdit()->getID()))); +} + + +bool RlvActions::canSit(const LLViewerObject* pObj, const LLVector3& posOffset /*= LLVector3::zero*/) +{ + // User can sit on the specified object if: + // - not prevented from sitting + // - not prevented from standing up or not currently sitting + // - not standtp restricted or not currently sitting (if the user is sitting and tried to sit elsewhere the tp would just kick in) + // - not a regular sit (i.e. due to @sit:<uuid>=force) + // - not @sittp=n or @fartouch=n restricted or if they clicked on a point within the allowed radius + static RlvCachedBehaviourModifier<float> s_nFarTouchDist(RLV_MODIFIER_FARTOUCHDIST); + static RlvCachedBehaviourModifier<float> s_nSitTpDist(RLV_MODIFIER_SITTPDIST); + return + ( (pObj) && (LL_PCODE_VOLUME == pObj->getPCode()) ) && + (!hasBehaviour(RLV_BHVR_SIT)) && + ( ((!hasBehaviour(RLV_BHVR_UNSIT)) && (!hasBehaviour(RLV_BHVR_STANDTP))) || + ((isAgentAvatarValid()) && (!gAgentAvatarp->isSitting())) ) && + ( ( (NULL != gRlvHandler.getCurrentCommand()) && (RLV_BHVR_SIT == gRlvHandler.getCurrentCommand()->getBehaviourType()) ) || + ( ((!hasBehaviour(RLV_BHVR_SITTP)) || (dist_vec_squared(gAgent.getPositionGlobal(), pObj->getPositionGlobal() + LLVector3d(posOffset)) < s_nSitTpDist * s_nSitTpDist)) && + ((!hasBehaviour(RLV_BHVR_FARTOUCH)) || (dist_vec_squared(gAgent.getPositionGlobal(), pObj->getPositionGlobal() + LLVector3d(posOffset)) < s_nFarTouchDist * s_nFarTouchDist)) ) ); +} + +bool RlvActions::canStand() +{ + // NOTE: return FALSE only if we're @unsit=n restricted and the avie is currently sitting on something and TRUE for everything else + return (!gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) || ((isAgentAvatarValid()) && (!gAgentAvatarp->isSitting())); +} + +bool RlvActions::canStand(const LLUUID& idRlvObjExcept) +{ + // NOTE: must match generic function above + return (!gRlvHandler.hasBehaviourExcept(RLV_BHVR_UNSIT, idRlvObjExcept)) || ((isAgentAvatarValid()) && (!gAgentAvatarp->isSitting())); +} + +// Checked: 2014-02-24 (RLVa-1.4.10) +bool RlvActions::canShowLocation() +{ + return !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC); +} + +// ============================================================================ +// Helper functions +// + +template<> +const float& RlvActions::getModifierValue<float>(ERlvBehaviourModifier eBhvrMod) +{ + return RlvBehaviourDictionary::instance().getModifier(eBhvrMod)->getValue<float>(); +} + +// Checked: 2013-05-10 (RLVa-1.4.9) +bool RlvActions::hasBehaviour(ERlvBehaviour eBhvr) +{ + return gRlvHandler.hasBehaviour(eBhvr); +} + +// Checked: 2013-05-09 (RLVa-1.4.9) +bool RlvActions::hasOpenP2PSession(const LLUUID& idAgent) +{ + const LLUUID idSession = LLIMMgr::computeSessionID(IM_NOTHING_SPECIAL, idAgent); + return (idSession.notNull()) && (LLIMMgr::instance().hasSession(idSession)); +} + +// Checked: 2013-05-09 (RLVa-1.4.9) +bool RlvActions::hasOpenGroupSession(const LLUUID& idGroup) +{ + return (idGroup.notNull()) && (LLIMMgr::instance().hasSession(idGroup)); +} + +// Checked: 2013-11-08 (RLVa-1.4.9) +bool RlvActions::isRlvEnabled() +{ + return RlvHandler::isEnabled(); +} + +// ============================================================================ diff --git a/indra/newview/rlvactions.h b/indra/newview/rlvactions.h new file mode 100644 index 0000000000000000000000000000000000000000..c034e829a1a960b178975f5eeed6403497fd5cd5 --- /dev/null +++ b/indra/newview/rlvactions.h @@ -0,0 +1,224 @@ +/** + * + * Copyright (c) 2009-2016, Kitty Barnett + * + * The source code in this file is provided to you under the terms of the + * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt + * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.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. + * + */ + +#ifndef RLV_ACTIONS_H +#define RLV_ACTIONS_H + +#include "rlvdefines.h" + +// ============================================================================ +// RlvActions class declaration - developer-friendly non-RLVa code facing class, use in lieu of RlvHandler whenever possible +// + +class RlvActions +{ + // ====== + // Camera + // ====== +public: + /* + * Returns true if the specified object cannot manipulate the camera FOV + */ + static bool canChangeCameraFOV(const LLUUID& idRlvObject); + + /* + * Returns true if the specified object can manipulate the camera offset and/or focus offset values + */ + static bool canChangeCameraPreset(const LLUUID& idRlvObject); + + /* + * Returns true if the user can switch to mouselook + */ + static bool canChangeToMouselook(); + + /* + * Returns true if the camera's distance (from either the avatar of the focus) is currently restricted/clamped + */ + static bool isCameraDistanceClamped(); + + /* + * Returns true if the camera's FOV is currently restricted/clamped + */ + static bool isCameraFOVClamped(); + + /* + * Returns true if the camera offset and focus offset are locked (prevents changing the current camera preset) + */ + static bool isCameraPresetLocked(); + + /* + * Retrieves the current (avatar or focus) camera distance limits + */ + static bool getCameraAvatarDistanceLimits(float& nDistMin, float& nDistMax); + static bool getCameraOriginDistanceLimits(float& nDistMin, float& nDistMax); + + /* + * Retrieves the current camera FOV limits - returns isCameraFOVClamped() + */ + static bool getCameraFOVLimits(float& nFOVMin, float& nFOVMax); + + // ================================ + // Communication/Avatar interaction + // ================================ +public: + /* + * Returns true if the user is allowed to change their currently active group + */ + static bool canChangeActiveGroup(const LLUUID& idRlvObject = LLUUID::null); + + /* + * Returns true if the user is allowed to receive IMs from the specified sender (can be an avatar or a group) + */ + static bool canReceiveIM(const LLUUID& idSender); + + /* + * Returns true if the user is allowed to send/play gestures (whether active ones from the chat bar or using the gesture preview floater) + */ + static bool canPlayGestures(); + + /* + * Returns true if the user is allowed to chat on the specified channel + */ + static bool canSendChannel(int nChannel); + + /* + * Returns true if the user is allowed to send IMs to the specified recipient (can be an avatar or a group) + */ + static bool canSendIM(const LLUUID& idRecipient); + + /* + * Returns true if the user is allowed to start a - P2P or group - conversation with the specified UUID (or if the session already exists) + */ + static bool canStartIM(const LLUUID& idRecipient); + + /* + * Returns true if an avatar's name should be hidden for the requested operation/context + * (This is used to hide an avatar name in one case but not a near-identical case - such as teleporting a friend vs a nearby agent - + * in a way that limits the amount of code that needs to be changed to carry context from one function to another) + */ + enum EShowNamesContext { SNC_DEFAULT = 0, SNC_NAMETAG, SNC_TELEPORTOFFER, SNC_TELEPORTREQUEST, SNC_COUNT }; + static bool canShowName(EShowNamesContext eContext, const LLUUID& idAgent = LLUUID::null); + static void setShowName(EShowNamesContext eContext, bool fCanShowName) { if ( (eContext < SNC_COUNT) && (isRlvEnabled()) ) { s_BlockNamesContexts[eContext] = !fCanShowName; } } + + /* + * Returns true if the user is allowed to see the presence of nearby avatars in UI elements (anonymized or otherwise) + */ + static bool canShowNearbyAgents(); + +protected: + // Backwards logic so that we can initialize to 0 and it won't block when we forget to/don't check if RLVa is disabled + static bool s_BlockNamesContexts[SNC_COUNT]; + + // ======== + // Movement + // ======== +public: + /* + * Returns true if the user can accept an incoming teleport offer from the specified avatar + */ + static bool canAcceptTpOffer(const LLUUID& idSender); + + /* + * Returns true if a teleport offer from the specified avatar should be auto-accepted + * (pass the null UUID to check if all teleport offers should be auto-accepted regardless of sender) + */ + static bool autoAcceptTeleportOffer(const LLUUID& idSender); + + /* + * Returns true if the user can accept an incoming teleport request from the specified avatar + */ + static bool canAcceptTpRequest(const LLUUID& idSender); + + /* + * Returns true if a teleport request from the specified avatar should be auto-accepted + * (pass the null UUID to check if all teleport requests should be auto-accepted regardless of requester) + */ + static bool autoAcceptTeleportRequest(const LLUUID& idRequester); + + // =========== + // Teleporting + // =========== +public: + /* + * Returns true if the user can teleport locally (short distances) + */ + static bool canTeleportToLocal(const LLVector3d& posGlobal); + + /* + * Returns true if the user can teleport to a (remote) location + */ + static bool canTeleportToLocation(); + + /* + * Returns true if the teleport is considered local (e.g. double-click tp) + */ + static bool isLocalTp(const LLVector3d& posGlobal); + + // ================= + // World interaction + // ================= +public: + /* + * Returns true if the user can edit the specified object + */ + static bool canEdit(const LLViewerObject* pObj); + + /* + * Returns true if the user can sit up on the specified object + */ + static bool canSit(const LLViewerObject* pObj, const LLVector3& posOffset = LLVector3::zero); + + /* + * Returns true if the user can stand up (returns true if the user isn't currently sitting) + */ + static bool canStand(); + static bool canStand(const LLUUID& idRlvObjExcept); + + /* + * Returns true if the user can see their in-world location + */ + static bool canShowLocation(); + + // ================ + // Helper functions + // ================ +public: + /* + * Convenience function to get the current/active value of a behaviour modifier + */ + template<typename T> static const T& getModifierValue(ERlvBehaviourModifier eBhvrMod); + + /* + * Convenience function to check for a behaviour without having to include rlvhandler.h. + * Do NOT call this function if speed is important (i.e. per-frame) + */ + static bool hasBehaviour(ERlvBehaviour eBhvr); + + /* + * Returns true if a - P2P or group - IM session is open with the specified UUID + */ + static bool hasOpenP2PSession(const LLUUID& idAgent); + static bool hasOpenGroupSession(const LLUUID& idGroup); + + /* + * Convenience function to check if RLVa is enabled without having to include rlvhandler.h + */ + static bool isRlvEnabled(); +}; + +// ============================================================================ + +#endif // RLV_ACTIONS_H diff --git a/indra/newview/rlvcommon.cpp b/indra/newview/rlvcommon.cpp new file mode 100644 index 0000000000000000000000000000000000000000..88fde865d24e97901862ffc2ed73cf3eda8d8fca --- /dev/null +++ b/indra/newview/rlvcommon.cpp @@ -0,0 +1,846 @@ +/** + * + * Copyright (c) 2009-2011, Kitty Barnett + * + * The source code in this file is provided to you under the terms of the + * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt + * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.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 "llagent.h" +#include "llagentui.h" +#include "llavatarnamecache.h" +#include "llinstantmessage.h" +#include "llnotificationsutil.h" +#include "llregionhandle.h" +#include "llscriptruntimeperms.h" +#include "llsdserialize.h" +#include "lltrans.h" +#include "llversioninfo.h" +#include "llviewerparcelmgr.h" +#include "llviewermenu.h" +#include "llviewerobjectlist.h" +#include "llviewerregion.h" +#include "llworld.h" + +#include "rlvactions.h" +#include "rlvcommon.h" +#include "rlvhelper.h" +#include "rlvhandler.h" +#include "rlvlocks.h" + +#include <boost/algorithm/string.hpp> +#include <boost/regex.hpp> + + +// ============================================================================ +// Forward declarations +// + +// llviewermenu.cpp +LLVOAvatar* find_avatar_from_object(LLViewerObject* object); + +// ============================================================================ +// RlvNotifications +// + +// Checked: 2009-11-13 (RLVa-1.1.0b) | Modified: RLVa-1.1.0b +/* +void RlvNotifications::warnGiveToRLV() +{ + if ( (gSavedSettings.getWarning(RLV_SETTING_FIRSTUSE_GIVETORLV)) && (RlvSettings::getForbidGiveToRLV()) ) + LLNotifications::instance().add(RLV_SETTING_FIRSTUSE_GIVETORLV, LLSD(), LLSD(), &RlvNotifications::onGiveToRLVConfirmation); +} +*/ + +// Checked: 2009-11-13 (RLVa-1.1.0b) | Modified: RLVa-1.1.0b +/* +void RlvNotifications::onGiveToRLVConfirmation(const LLSD& notification, const LLSD& response) +{ + gSavedSettings.setWarning(RLV_SETTING_FIRSTUSE_GIVETORLV, FALSE); + + S32 idxOption = LLNotification::getSelectedOption(notification, response); + if ( (0 == idxOption) || (1 == idxOption) ) + gSavedSettings.setBOOL(RLV_SETTING_FORBIDGIVETORLV, (idxOption == 1)); +} +*/ + +// ========================================================================= +// RlvSettings +// + +#ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS +bool RlvSettings::s_fCompositeFolders = false; +#endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS +bool RlvSettings::s_fCanOOC = true; +bool RlvSettings::s_fLegacyNaming = true; +bool RlvSettings::s_fNoSetEnv = false; +bool RlvSettings::s_fTempAttach = true; +std::list<LLUUID> RlvSettings::s_CompatItemCreators; +std::list<std::string> RlvSettings::s_CompatItemNames; + +// Checked: 2010-02-27 (RLVa-1.2.0a) | Modified: RLVa-1.1.0i +void RlvSettings::initClass() +{ + static bool fInitialized = false; + if (!fInitialized) + { + initCompatibilityMode(LLStringUtil::null); + + s_fTempAttach = rlvGetSetting<bool>(RLV_SETTING_ENABLETEMPATTACH, true); + if (gSavedSettings.controlExists(RLV_SETTING_ENABLETEMPATTACH)) + gSavedSettings.getControl(RLV_SETTING_ENABLETEMPATTACH)->getSignal()->connect(boost::bind(&onChangedSettingBOOL, _2, &s_fTempAttach)); + + #ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS + s_fCompositeFolders = rlvGetSetting<bool>(RLV_SETTING_ENABLECOMPOSITES, false); + if (gSavedSettings.controlExists(RLV_SETTING_ENABLECOMPOSITES)) + gSavedSettings.getControl(RLV_SETTING_ENABLECOMPOSITES)->getSignal()->connect(boost::bind(&onChangedSettingBOOL, _2, &s_fCompositeFolders)); + #endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS + + s_fLegacyNaming = rlvGetSetting<bool>(RLV_SETTING_ENABLELEGACYNAMING, true); + if (gSavedSettings.controlExists(RLV_SETTING_ENABLELEGACYNAMING)) + gSavedSettings.getControl(RLV_SETTING_ENABLELEGACYNAMING)->getSignal()->connect(boost::bind(&onChangedSettingBOOL, _2, &s_fLegacyNaming)); + + s_fCanOOC = rlvGetSetting<bool>(RLV_SETTING_CANOOC, true); + s_fNoSetEnv = rlvGetSetting<bool>(RLV_SETTING_NOSETENV, false); + + // Don't allow toggling RLVaLoginLastLocation from the debug settings floater + if (gSavedPerAccountSettings.controlExists(RLV_SETTING_LOGINLASTLOCATION)) + gSavedPerAccountSettings.getControl(RLV_SETTING_LOGINLASTLOCATION)->setHiddenFromSettingsEditor(true); + + if (gSavedSettings.controlExists(RLV_SETTING_TOPLEVELMENU)) + gSavedSettings.getControl(RLV_SETTING_TOPLEVELMENU)->getSignal()->connect(boost::bind(&onChangedMenuLevel)); + + fInitialized = true; + } +} + +// Checked: 2010-04-01 (RLVa-1.2.0c) | Modified: RLVa-0.2.1d +void RlvSettings::updateLoginLastLocation() +{ + if ( (!LLApp::isQuitting()) && (gSavedPerAccountSettings.controlExists(RLV_SETTING_LOGINLASTLOCATION)) ) + { + BOOL fValue = (gRlvHandler.hasBehaviour(RLV_BHVR_TPLOC)) || (!RlvActions::canStand()); + if (gSavedPerAccountSettings.getBOOL(RLV_SETTING_LOGINLASTLOCATION) != fValue) + { + gSavedPerAccountSettings.setBOOL(RLV_SETTING_LOGINLASTLOCATION, fValue); + gSavedPerAccountSettings.saveToFile(gSavedSettings.getString("PerAccountSettingsFile"), TRUE); + } + } +} + +// Checked: 2011-08-16 (RLVa-1.4.0b) | Added: RLVa-1.4.0b +bool RlvSettings::onChangedMenuLevel() +{ + rlvMenuToggleVisible(); + return true; +} + +// Checked: 2010-02-27 (RLVa-1.2.0a) | Added: RLVa-1.1.0i +bool RlvSettings::onChangedSettingBOOL(const LLSD& sdValue, bool* pfSetting) +{ + if (pfSetting) + *pfSetting = sdValue.asBoolean(); + return true; +} + +// Checked: 2015-05-25 (RLVa-1.5.0) +void RlvSettings::onChangedSettingMain(const LLSD& sdValue) +{ + if (sdValue.asBoolean() != (bool)rlv_handler_t::isEnabled()) + { + LLNotificationsUtil::add( + "GenericAlert", + LLSD().with("MESSAGE", llformat(LLTrans::getString("RLVaToggleMessage").c_str(), + (sdValue.asBoolean()) ? LLTrans::getString("RLVaToggleEnabled").c_str() + : LLTrans::getString("RLVaToggleDisabled").c_str()))); + } +} + +void RlvSettings::initCompatibilityMode(std::string strCompatList) +{ + // NOTE: this function can be called more than once + s_CompatItemCreators.clear(); + s_CompatItemNames.clear(); + + strCompatList.append(";").append(rlvGetSetting<std::string>("RLVaCompatibilityModeList", "")); + + boost_tokenizer tokCompatList(strCompatList, boost::char_separator<char>(";", "", boost::drop_empty_tokens)); + for (const std::string& strCompatEntry : tokCompatList) + { + if (boost::starts_with(strCompatEntry, "creator:")) + { + LLUUID idCreator; + if ( (44 == strCompatEntry.size()) && (LLUUID::parseUUID(strCompatEntry.substr(8), &idCreator)) && + (s_CompatItemCreators.end() == std::find(s_CompatItemCreators.begin(), s_CompatItemCreators.end(), idCreator)) ) + { + s_CompatItemCreators.push_back(idCreator); + } + } + else if (boost::starts_with(strCompatEntry, "name:")) + { + if (strCompatEntry.size() > 5) + s_CompatItemNames.push_back(strCompatEntry.substr(5)); + } + } +} + +bool RlvSettings::isCompatibilityModeObject(const LLUUID& idRlvObject) +{ + bool fCompatMode = false; + if (idRlvObject.notNull()) + { + const LLViewerObject* pObj = gObjectList.findObject(idRlvObject); + if ( (pObj) && (pObj->isAttachment()) ) + { + const LLViewerInventoryItem* pItem = gInventory.getItem(pObj->getAttachmentItemID()); + if (pItem) + { + fCompatMode = s_CompatItemCreators.end() != std::find(s_CompatItemCreators.begin(), s_CompatItemCreators.end(), pItem->getCreatorUUID()); + if (!fCompatMode) + { + const std::string& strAttachName = pItem->getName(); + for (const std::string& strCompatName : s_CompatItemNames) + { + boost::regex regexp(strCompatName, boost::regex::perl | boost::regex::icase); + if (boost::regex_match(strAttachName, regexp)) + { + fCompatMode = true; + break; + } + } + } + } + } + } + return fCompatMode; +} + +// ============================================================================ +// RlvStrings +// + +std::vector<std::string> RlvStrings::m_Anonyms; +RlvStrings::string_map_t RlvStrings::m_StringMap; +std::string RlvStrings::m_StringMapPath; + +// Checked: 2011-11-08 (RLVa-1.5.0) +void RlvStrings::initClass() +{ + static bool fInitialized = false; + if (!fInitialized) + { + // Load the default string values + std::vector<std::string> files = gDirUtilp->findSkinnedFilenames(LLDir::XUI, RLV_STRINGS_FILE, LLDir::ALL_SKINS); + m_StringMapPath = (!files.empty()) ? files.front() : LLStringUtil::null; + for (std::vector<std::string>::const_iterator itFile = files.begin(); itFile != files.end(); ++itFile) + { + loadFromFile(*itFile, false); + } + + // Load the custom string overrides + loadFromFile(gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, RLV_STRINGS_FILE), true); + + // Sanity check + if ( (m_StringMap.empty()) || (m_Anonyms.empty()) ) + { + RLV_ERRS << "Problem parsing RLVa string XML file" << RLV_ENDL; + return; + } + + fInitialized = true; + } +} + +// Checked: 2011-11-08 (RLVa-1.5.0) +void RlvStrings::loadFromFile(const std::string& strFilePath, bool fUserOverride) +{ + llifstream fileStream(strFilePath.c_str(), std::ios::binary); LLSD sdFileData; + if ( (!fileStream.is_open()) || (!LLSDSerialize::fromXMLDocument(sdFileData, fileStream)) ) + return; + fileStream.close(); + + if (sdFileData.has("strings")) + { + const LLSD& sdStrings = sdFileData["strings"]; + for (LLSD::map_const_iterator itString = sdStrings.beginMap(); itString != sdStrings.endMap(); ++itString) + { + if ( (!itString->second.has("value")) || ((fUserOverride) && (!hasString(itString->first))) ) + continue; + + std::list<std::string>& listValues = m_StringMap[itString->first]; + if (!fUserOverride) + { + if (listValues.size() > 0) + listValues.pop_front(); + listValues.push_front(itString->second["value"].asString()); + } + else + { + while (listValues.size() > 1) + listValues.pop_back(); + listValues.push_back(itString->second["value"].asString()); + } + } + } + if (sdFileData.has("anonyms")) + { + const LLSD& sdAnonyms = sdFileData["anonyms"]; + for (LLSD::array_const_iterator itAnonym = sdAnonyms.beginArray(); itAnonym != sdAnonyms.endArray(); ++itAnonym) + { + m_Anonyms.push_back((*itAnonym).asString()); + } + } +} + +// Checked: 2011-11-08 (RLVa-1.5.0) +void RlvStrings::saveToFile(const std::string& strFilePath) +{ + LLSD sdFileData; + + LLSD& sdStrings = sdFileData["strings"]; + for (string_map_t::const_iterator itString = m_StringMap.begin(); itString != m_StringMap.end(); ++itString) + { + const std::list<std::string>& listValues = itString->second; + if (listValues.size() > 1) + sdStrings[itString->first]["value"] = listValues.back(); + } + + llofstream fileStream(strFilePath.c_str()); + if (!fileStream.good()) + return; + + LLSDSerialize::toPrettyXML(sdFileData, fileStream); + fileStream.close(); +} + +// Checked: 2009-11-11 (RLVa-1.1.0a) | Modified: RLVa-1.1.0a +const std::string& RlvStrings::getAnonym(const std::string& strName) +{ + const char* pszName = strName.c_str(); U32 nHash = 0; + + // Test with 11,264 SL names showed a 3.33% - 3.82% occurance for each so we *should* get a very even spread + for (int idx = 0, cnt = strName.length(); idx < cnt; idx++) + nHash += pszName[idx]; + + return m_Anonyms[nHash % m_Anonyms.size()]; +} + +// Checked: 2011-11-08 (RLVa-1.5.0) +const std::string& RlvStrings::getString(const std::string& strStringName) +{ + static const std::string strMissing = "(Missing RLVa string)"; + string_map_t::const_iterator itString = m_StringMap.find(strStringName); + return (itString != m_StringMap.end()) ? itString->second.back() : strMissing; +} + +// Checked: 2009-11-25 (RLVa-1.1.0f) | Added: RLVa-1.1.0f +const char* RlvStrings::getStringFromReturnCode(ERlvCmdRet eRet) +{ + // TODO-RLVa: [2009-11-25] clean this up along with the calling code in process_chat_from_simulator() once we're happy with the output + switch (eRet) + { + case RLV_RET_SUCCESS_UNSET: + return "unset"; + case RLV_RET_SUCCESS_DUPLICATE: + return "duplicate"; + case RLV_RET_SUCCESS_DELAYED: + return "delayed"; + case RLV_RET_SUCCESS_DEPRECATED: + return "deprecated"; + case RLV_RET_FAILED_SYNTAX: + return "thingy error"; + case RLV_RET_FAILED_OPTION: + return "invalid option"; + case RLV_RET_FAILED_PARAM: + return "invalid param"; + case RLV_RET_FAILED_LOCK: + return "locked command"; + case RLV_RET_FAILED_DISABLED: + return "disabled command"; + case RLV_RET_FAILED_UNKNOWN: + return "unknown command"; + case RLV_RET_FAILED_NOSHAREDROOT: + return "missing #RLV"; + case RLV_RET_FAILED_DEPRECATED: + return "deprecated and disabled"; + // The following are identified by the chat verb + case RLV_RET_RETAINED: + case RLV_RET_SUCCESS: + case RLV_RET_FAILED: + break; + // The following shouldn't occur + case RLV_RET_UNKNOWN: + default: + RLV_ASSERT(false); + break; + }; + return NULL; +} + +std::string RlvStrings::getVersion(const LLUUID& idRlvObject, bool fLegacy) +{ + bool fCompatMode = RlvSettings::isCompatibilityModeObject(idRlvObject); + return llformat("%s viewer v%d.%d.%d (RLVa %d.%d.%d)", + ( (!fLegacy) ? "RestrainedLove" : "RestrainedLife" ), + (!fCompatMode) ? RLV_VERSION_MAJOR : RLV_VERSION_MAJOR_COMPAT, (!fCompatMode) ? RLV_VERSION_MINOR : RLV_VERSION_MINOR_COMPAT, (!fCompatMode) ? RLV_VERSION_PATCH : RLV_VERSION_PATCH_COMPAT, + RLVa_VERSION_MAJOR, RLVa_VERSION_MINOR, RLVa_VERSION_PATCH); +} + +std::string RlvStrings::getVersionAbout() +{ + return llformat("RLV v%d.%d.%d / RLVa v%d.%d.%d.%d", RLV_VERSION_MAJOR, RLV_VERSION_MINOR, RLV_VERSION_PATCH, RLVa_VERSION_MAJOR, RLVa_VERSION_MINOR, RLVa_VERSION_PATCH, LLVersionInfo::getBuild()); +} + +std::string RlvStrings::getVersionNum(const LLUUID& idRlvObject) +{ + bool fCompatMode = RlvSettings::isCompatibilityModeObject(idRlvObject); + return llformat("%d%02d%02d%02d", + (!fCompatMode) ? RLV_VERSION_MAJOR : RLV_VERSION_MAJOR_COMPAT, (!fCompatMode) ? RLV_VERSION_MINOR : RLV_VERSION_MINOR_COMPAT, + (!fCompatMode) ? RLV_VERSION_PATCH : RLV_VERSION_PATCH_COMPAT, (!fCompatMode) ? RLV_VERSION_BUILD : RLV_VERSION_BUILD_COMPAT); +} + +// Checked: 2011-11-08 (RLVa-1.5.0) +bool RlvStrings::hasString(const std::string& strStringName, bool fCheckCustom) +{ + string_map_t::const_iterator itString = m_StringMap.find(strStringName); + return (itString != m_StringMap.end()) && ((!fCheckCustom) || (itString->second.size() > 0)); +} + +// Checked: 2011-11-08 (RLVa-1.5.0) +void RlvStrings::setCustomString(const std::string& strStringName, const std::string& strStringValue) +{ + if (!hasString(strStringName)) + return; + + std::list<std::string>& listValues = m_StringMap[strStringName]; + while (listValues.size() > 1) + listValues.pop_back(); + if (!strStringValue.empty()) + listValues.push_back(strStringValue); +} + +// ============================================================================ +// 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) +{ + // 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) + boost::ireplace_all(strUTF8Text, (*itRegion)->getName(), strHiddenRegion); + + // Filter any mention of the parcel name + LLViewerParcelMgr* pParcelMgr = LLViewerParcelMgr::getInstance(); + if (pParcelMgr) + boost::ireplace_all(strUTF8Text, pParcelMgr->getAgentParcelName(), RlvStrings::getString(RLV_STRING_HIDDEN_PARCEL)); +} + +// Checked: 2010-12-08 (RLVa-1.2.2c) | Modified: RLVa-1.2.2c +void RlvUtil::filterNames(std::string& strUTF8Text, bool fFilterLegacy, bool fClearMatches) +{ + uuid_vec_t idAgents; + LLWorld::getInstance()->getAvatars(&idAgents, NULL); + for (int idxAgent = 0, cntAgent = idAgents.size(); idxAgent < cntAgent; idxAgent++) + { + LLAvatarName avName; + // NOTE: if we're agressively culling nearby names then ignore exceptions + if ( (LLAvatarNameCache::get(idAgents[idxAgent], &avName)) && ((fClearMatches) || (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, idAgents[idxAgent]))) ) + { + const std::string& strDisplayName = avName.getDisplayName(); + bool fFilterDisplay = (strDisplayName.length() > 2); + const std::string& strLegacyName = avName.getLegacyName(); + fFilterLegacy &= (strLegacyName.length() > 2); + const std::string& strAnonym = (!fClearMatches) ? RlvStrings::getAnonym(avName) : LLStringUtil::null; + + // If the display name is a subset of the legacy name we need to filter that first, otherwise it's the other way around + if (boost::icontains(strLegacyName, strDisplayName)) + { + if (fFilterLegacy) + boost::ireplace_all(strUTF8Text, strLegacyName, strAnonym); + if (fFilterDisplay) + boost::ireplace_all(strUTF8Text, strDisplayName, strAnonym); + } + else + { + if (fFilterDisplay) + boost::ireplace_all(strUTF8Text, strDisplayName, strAnonym); + if (fFilterLegacy) + boost::ireplace_all(strUTF8Text, strLegacyName, strAnonym); + } + } + } +} + +// Checked: 2012-08-19 (RLVa-1.4.7) +void RlvUtil::filterScriptQuestions(S32& nQuestions, LLSD& sdPayload) +{ + // Check SCRIPT_PERMISSION_ATTACH + if ((!gRlvAttachmentLocks.canAttach()) && (SCRIPT_PERMISSIONS[SCRIPT_PERMISSION_ATTACH].permbit & nQuestions)) + { + // Notify the user that we blocked it since they're not allowed to wear any new attachments + sdPayload["rlv_blocked"] = RLV_STRING_BLOCKED_PERMATTACH; + nQuestions &= ~SCRIPT_PERMISSIONS[SCRIPT_PERMISSION_ATTACH].permbit; + } + + // Check SCRIPT_PERMISSION_TELEPORT + if ((gRlvHandler.hasBehaviour(RLV_BHVR_TPLOC)) && (SCRIPT_PERMISSIONS[SCRIPT_PERMISSION_TELEPORT].permbit & nQuestions)) + { + // Notify the user that we blocked it since they're not allowed to teleport + sdPayload["rlv_blocked"] = RLV_STRING_BLOCKED_PERMTELEPORT; + nQuestions &= ~SCRIPT_PERMISSIONS[SCRIPT_PERMISSION_TELEPORT].permbit; + } + + sdPayload["questions"] = nQuestions; +} + +// 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<LLUUID> 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: 2011-04-11 (RLVa-1.3.0h) | Modified: RLVa-1.3.0h +void RlvUtil::notifyBlocked(const std::string& strNotifcation, const LLSD& sdArgs) +{ + std::string strMsg = RlvStrings::getString(strNotifcation); + LLStringUtil::format(strMsg, sdArgs); + + LLSD sdNotify; + sdNotify["MESSAGE"] = strMsg; + LLNotificationsUtil::add("SystemMessageTip", sdNotify); +} + +// 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) +{ + // Don't show the same assertion over and over, or if the user opted out + static std::string strAssertPrev, strFilePrev; static int nLinePrev; + if ( ((strAssertPrev == strAssert) && (strFile == strFilePrev) && (nLine == nLinePrev)) || + (!rlvGetSetting<bool>(RLV_SETTING_SHOWASSERTIONFAIL, true)) ) + { + 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); + LLNotificationsUtil::add("SystemMessageTip", argsNotify); +} + +// Checked: 2010-03-27 (RLVa-1.2.0b) | 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; + LLAgentUI::buildFullname(strFullName); + + pack_instant_message(gMessageSystem, gAgent.getID(), FALSE, gAgent.getSessionID(), idTo, strFullName, + strMsg, IM_ONLINE, IM_DO_NOT_DISTURB_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, utf8str_truncate(strUTF8Text, MAX_MSG_STR_LEN)); + gMessageSystem->addU8Fast(_PREHASH_Type, CHAT_TYPE_SHOUT); + gMessageSystem->addS32("Channel", nChannel); + gAgent.sendReliableMessage(); + add(LLStatViewer::CHAT_COUNT, 1); + + return true; +} + +void RlvUtil::teleportCallback(U64 hRegion, const LLVector3& posRegion, const LLVector3& vecLookAt) +{ + if (hRegion) + { + const LLVector3d posGlobal = from_region_handle(hRegion) + (LLVector3d)posRegion; + if (vecLookAt.isExactlyZero()) + gAgent.teleportViaLocation(posGlobal); + else + gAgent.teleportViaLocationLookAt(posGlobal, vecLookAt); + } +} + +// ============================================================================ +// Generic menu enablers +// + +// Checked: 2015-05-25 (RLVa-1.5.0) +bool rlvMenuMainToggleVisible(LLUICtrl* pMenuCtrl) +{ + LLMenuItemCheckGL* pMenuItem = dynamic_cast<LLMenuItemCheckGL*>(pMenuCtrl); + if (pMenuItem) + { + static std::string strLabel = pMenuItem->getLabel(); + if (gSavedSettings.getBOOL(RLV_SETTING_MAIN) == rlv_handler_t::isEnabled()) + pMenuItem->setLabel(strLabel); + else + pMenuItem->setLabel(strLabel + " " + LLTrans::getString("RLVaPendingRestart")); + } + return true; +} + +// Checked: 2011-08-16 (RLVa-1.4.0b) | Added: RLVa-1.4.0b +void rlvMenuToggleVisible() +{ + bool fTopLevel = rlvGetSetting(RLV_SETTING_TOPLEVELMENU, true); + bool fRlvEnabled = rlv_handler_t::isEnabled(); + + LLMenuGL* pRLVaMenuMain = gMenuBarView->findChildMenuByName("RLVa Main", FALSE); + LLMenuGL* pAdvancedMenu = gMenuBarView->findChildMenuByName("Advanced", FALSE); + LLMenuGL* pRLVaMenuEmbed = pAdvancedMenu->findChildMenuByName("RLVa Embedded", FALSE); + + gMenuBarView->setItemVisible("RLVa Main", (fRlvEnabled) && (fTopLevel)); + pAdvancedMenu->setItemVisible("RLVa Embedded", (fRlvEnabled) && (!fTopLevel)); + + if ( (rlv_handler_t::isEnabled()) && (pRLVaMenuMain) && (pRLVaMenuEmbed) && + ( ((fTopLevel) && (1 == pRLVaMenuMain->getItemCount())) || ((!fTopLevel) && (1 == pRLVaMenuEmbed->getItemCount())) ) ) + { + LLMenuGL* pMenuFrom = (fTopLevel) ? pRLVaMenuEmbed : pRLVaMenuMain; + LLMenuGL* pMenuTo = (fTopLevel) ? pRLVaMenuMain : pRLVaMenuEmbed; + while (LLMenuItemGL* pItem = pMenuFrom->getItem(1)) + { + pMenuFrom->removeChild(pItem); + pMenuTo->addChild(pItem); + pItem->updateBranchParent(pMenuTo); + } + } +} + +bool rlvMenuCanShowName() +{ + const LLVOAvatar* pAvatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); + return (pAvatar) && (RlvActions::canShowName(RlvActions::SNC_DEFAULT, pAvatar->getID())); +} + +// Checked: 2010-04-23 (RLVa-1.2.0g) | Modified: RLVa-1.2.0g +bool rlvMenuEnableIfNot(const LLSD& sdParam) +{ + bool fEnable = true; + if (rlv_handler_t::isEnabled()) + { + ERlvBehaviour eBhvr = RlvBehaviourDictionary::instance().getBehaviourFromString(sdParam.asString(), RLV_TYPE_ADDREM); + fEnable = (eBhvr != RLV_BHVR_UNKNOWN) ? !gRlvHandler.hasBehaviour(eBhvr) : true; + } + return fEnable; +} + +// ============================================================================ +// Selection functors +// + +// Checked: 2011-05-28 (RLVa-1.4.6) | Modified: RLVa-1.4.0 +bool rlvCanDeleteOrReturn(const LLViewerObject* pObj) +{ + // Block if: @rez=n restricted and owned by us or a group *or* @unsit=n restricted and being sat on by us + return + ( (!gRlvHandler.hasBehaviour(RLV_BHVR_REZ)) || ((!pObj->permYouOwner()) && (!pObj->permGroupOwner())) ) && + ( (!gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) || (!isAgentAvatarValid()) || (!pObj->getRootEdit()->isChild(gAgentAvatarp)) ); +} + +// Checked: 2011-05-28 (RLVa-1.4.6) | Modified: RLVa-1.4.0 +bool rlvCanDeleteOrReturn() +{ + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_REZ)) || (gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) ) + { + struct RlvCanDeleteOrReturn : public LLSelectedObjectFunctor + { + /*virtual*/ bool apply(LLViewerObject* pObj) { return rlvCanDeleteOrReturn(pObj); } + } f; + LLObjectSelectionHandle hSel = LLSelectMgr::getInstance()->getSelection(); + return (hSel.notNull()) && (0 != hSel->getRootObjectCount()) && (hSel->applyToRootObjects(&f, false)); + } + return true; +} + +// Checked: 2010-04-20 (RLVa-1.2.0f) | Modified: RLVa-0.2.0f +bool RlvSelectHasLockedAttach::apply(LLSelectNode* pNode) +{ + return (pNode->getObject()) ? gRlvAttachmentLocks.isLockedAttachment(pNode->getObject()->getRootEdit()) : false; +} + +// Checked: 2010-11-29 (RLVa-1.3.0c) | Added: RLVa-1.3.0c +bool RlvSelectIsEditable::apply(LLSelectNode* pNode) +{ + const LLViewerObject* pObj = pNode->getObject(); + return (pObj) && (!RlvActions::canEdit(pObj)); +} + +// Checked: 2011-05-28 (RLVa-1.4.0a) | Modified: RLVa-1.4.0a +bool RlvSelectIsSittingOn::apply(LLSelectNode* pNode) +{ + return (pNode->getObject()) && (pNode->getObject()->getRootEdit()->isChild(m_pAvatar)); +} + +// ============================================================================ +// 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: 2014-11-02 (RLVa-1.4.11) +bool rlvPredCanRemoveItem(const LLUUID& idItem) +{ + // Check the inventory item if it's available + const LLViewerInventoryItem* pItem = gInventory.getItem(idItem); + if (pItem) + { + return rlvPredCanRemoveItem(pItem); + } + + // Temporary attachments don't have inventory items associated with them so check the attachment itself + if (isAgentAvatarValid()) + { + const LLViewerObject* pAttachObj = gAgentAvatarp->getWornAttachment(idItem); + return (pAttachObj) && (!gRlvAttachmentLocks.isLockedAttachment(pAttachObj)); + } + + return false; +} + +// Checked: 2010-03-22 (RLVa-1.2.0) +bool rlvPredCanRemoveItem(const LLViewerInventoryItem* pItem) +{ + if (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(!RlvForceWear::isWearableItem(pItem)); + } + } + return false; +} + +// Checked: 2010-03-22 (RLVa-1.2.0c) | Added: RLVa-1.2.0a +bool rlvPredCanNotRemoveItem(const LLViewerInventoryItem* pItem) +{ + return !rlvPredCanRemoveItem(pItem); +} + +// Checked: 2010-04-24 (RLVa-1.2.0f) | Added: RLVa-1.2.0f +RlvPredIsEqualOrLinkedItem::RlvPredIsEqualOrLinkedItem(const LLUUID& idItem) +{ + m_pItem = gInventory.getItem(idItem); +} + +// Checked: 2010-04-24 (RLVa-1.2.0f) | Added: RLVa-1.2.0f +bool RlvPredIsEqualOrLinkedItem::operator()(const LLViewerInventoryItem* pItem) const +{ + return (m_pItem) && (pItem) && (m_pItem->getLinkedUUID() == pItem->getLinkedUUID()); +} + +// ============================================================================ +// Various public helper functions +// + +// Checked: 2009-11-15 (RLVa-1.1.0c) | Added: RLVa-1.1.0c +/* +BOOL rlvEnableSharedWearEnabler(void* pParam) +{ + return false; + // Visually disable the "Enable Shared Wear" option when at least one attachment is non-detachable + return (!gRlvHandler.hasLockedAttachment(RLV_LOCK_REMOVE)); +} +*/ + +// Checked: 2010-11-01 (RLVa-1.2.2a) | Added: RLVa-1.2.2a +const std::string& rlvGetAnonym(const LLAvatarName& avName) +{ + return RlvStrings::getAnonym(avName); +} + +// ============================================================================ diff --git a/indra/newview/rlvcommon.h b/indra/newview/rlvcommon.h new file mode 100644 index 0000000000000000000000000000000000000000..5f3811873455b94047d3f19e048f504b74182cef --- /dev/null +++ b/indra/newview/rlvcommon.h @@ -0,0 +1,330 @@ +/** + * + * Copyright (c) 2009-2011, Kitty Barnett + * + * The source code in this file is provided to you under the terms of the + * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt + * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.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. + * + */ + +#ifndef RLV_COMMON_H +#define RLV_COMMON_H + +#include "llavatarname.h" +#include "llselectmgr.h" +#include "llviewercontrol.h" + +#include "rlvdefines.h" + +#ifdef LL_WINDOWS + #pragma warning (push) + #pragma warning (disable : 4702) // warning C4702: unreachable code +#endif +#include <boost/variant.hpp> +#ifdef LL_WINDOWS + #pragma warning (pop) +#endif + +// ============================================================================ +// Forward declarations +// + +// +// General viewer source +// +class LLInventoryItem; +class LLUICtrl; +class LLViewerInventoryCategory; +class LLViewerInventoryItem; +class LLViewerJointAttachment; +class LLViewerWearable; +class LLWearable; + +// +// RLVa-specific +// +class RlvCommand; +typedef std::list<RlvCommand> rlv_command_list_t; +class RlvObject; + +struct RlvException; +typedef boost::variant<std::string, LLUUID, S32, ERlvBehaviour> RlvExceptionOption; +typedef boost::variant<int, float, LLVector3, LLUUID> RlvBehaviourModifierValue; + +class RlvGCTimer; + +// ============================================================================ +// RlvSettings +// + +template<typename T> inline T rlvGetSetting(const std::string& strSetting, const T& defaultValue) +{ + RLV_ASSERT_DBG(gSavedSettings.controlExists(strSetting)); + return (gSavedSettings.controlExists(strSetting)) ? gSavedSettings.get<T>(strSetting) : defaultValue; +} + +template<typename T> inline T rlvGetPerUserSetting(const std::string& strSetting, const T& defaultValue) +{ + RLV_ASSERT_DBG(gSavedPerAccountSettings.controlExists(strSetting)); + return (gSavedPerAccountSettings.controlExists(strSetting)) ? gSavedPerAccountSettings.get<T>(strSetting) : defaultValue; +} + +class RlvSettings +{ +public: + static bool getDebug() { return rlvGetSetting<bool>(RLV_SETTING_DEBUG, false); } + static bool getCanOOC() { return s_fCanOOC; } + static bool getForbidGiveToRLV() { return rlvGetSetting<bool>(RLV_SETTING_FORBIDGIVETORLV, true); } + static bool getNoSetEnv() { return s_fNoSetEnv; } + + static std::string getWearAddPrefix() { return rlvGetSetting<std::string>(RLV_SETTING_WEARADDPREFIX, LLStringUtil::null); } + static std::string getWearReplacePrefix() { return rlvGetSetting<std::string>(RLV_SETTING_WEARREPLACEPREFIX, LLStringUtil::null); } + + static bool getDebugHideUnsetDup() { return rlvGetSetting<bool>(RLV_SETTING_DEBUGHIDEUNSETDUP, false); } + #ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS + static BOOL getEnableComposites() { return s_fCompositeFolders; } + #endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS + static bool getEnableIMQuery() { return rlvGetSetting<bool>("RLVaEnableIMQuery", true); } + static bool getEnableLegacyNaming() { return s_fLegacyNaming; } + static bool getEnableSharedWear() { return rlvGetSetting<bool>(RLV_SETTING_ENABLESHAREDWEAR, false); } + static bool getEnableTemporaryAttachments() { return s_fTempAttach; } + static bool getHideLockedLayers() { return rlvGetSetting<bool>(RLV_SETTING_HIDELOCKEDLAYER, false); } + static bool getHideLockedAttach() { return rlvGetSetting<bool>(RLV_SETTING_HIDELOCKEDATTACH, false); } + static bool getHideLockedInventory() { return rlvGetSetting<bool>(RLV_SETTING_HIDELOCKEDINVENTORY, false); } + static bool getSharedInvAutoRename() { return rlvGetSetting<bool>(RLV_SETTING_SHAREDINVAUTORENAME, true); } + + static bool getLoginLastLocation() { return rlvGetPerUserSetting<bool>(RLV_SETTING_LOGINLASTLOCATION, true); } + static void updateLoginLastLocation(); + + static void initCompatibilityMode(std::string strCompatList); + static bool isCompatibilityModeObject(const LLUUID& idRlvObject); + + static void initClass(); + static void onChangedSettingMain(const LLSD& sdValue); +protected: + static bool onChangedMenuLevel(); + static bool onChangedSettingBOOL(const LLSD& sdValue, bool* pfSetting); + + #ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS + static BOOL s_fCompositeFolders; + #endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS + + /* + * Member variables + */ +protected: + static bool s_fCanOOC; + static bool s_fLegacyNaming; + static bool s_fNoSetEnv; + static bool s_fTempAttach; + static std::list<LLUUID> s_CompatItemCreators; + static std::list<std::string> s_CompatItemNames; +}; + +// ============================================================================ +// RlvStrings +// + +class RlvStrings +{ +public: + static void initClass(); + static void loadFromFile(const std::string& strFilePath, bool fDefault); + static void saveToFile(const std::string& strFilePath); + + static const std::string& getAnonym(const LLAvatarName& avName); // @shownames + static const std::string& getAnonym(const std::string& strName); // @shownames + static const std::string& getString(const std::string& strStringName); + static const char* getStringFromReturnCode(ERlvCmdRet eRet); + static const std::string& getStringMapPath() { return m_StringMapPath; } + static std::string getVersion(const LLUUID& idRlvObject, bool fLegacy = false); + static std::string getVersionAbout(); + static std::string getVersionNum(const LLUUID& idRlvObject); + static bool hasString(const std::string& strStringName, bool fCheckCustom = false); + static void setCustomString(const std::string& strStringName, const std::string& strStringValue); + +protected: + static std::vector<std::string> m_Anonyms; + typedef std::map<std::string, std::list<std::string> > string_map_t; + static string_map_t m_StringMap; + static std::string m_StringMapPath; +}; + +// ============================================================================ +// 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, bool fFilterLegacy = true, bool fClearMatches = false); // @shownames + static void filterScriptQuestions(S32& nQuestions, LLSD& sdPayload); + + static bool isForceTp() { return m_fForceTp; } + static void forceTp(const LLVector3d& posDest); // Ignores restrictions that might otherwise prevent tp'ing + + static void notifyBlocked(const std::string& strNotifcation, const LLSD& sdArgs = LLSD()); + static void notifyBlockedGeneric() { notifyBlocked(RLV_STRING_BLOCKED_GENERIC); } + static void notifyBlockedViewXXX(LLAssetType::EType assetType) { notifyBlocked(RLV_STRING_BLOCKED_VIEWXXX, LLSD().with("[TYPE]", LLAssetType::lookup(assetType))); } + 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, bool fLoopback = false); + static bool sendChatReply(S32 nChannel, const std::string& strUTF8Text); + static bool sendChatReply(const std::string& strChannel, const std::string& strUTF8Text); + + static void teleportCallback(U64 hRegion, const LLVector3& posRegion, const LLVector3& vecLookAt); +protected: + static bool m_fForceTp; // @standtp +}; + +// ============================================================================ +// Extensibility classes +// + +class RlvExtCommandHandler +{ +public: + virtual ~RlvExtCommandHandler() {} + 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 (RlvExtCommandHandler::*rlvExtCommandHandler)(const RlvCommand& rlvCmd, ERlvCmdRet& cmdRet); + +// ============================================================================ +// Generic menu enablers +// + +bool rlvMenuMainToggleVisible(LLUICtrl* pMenuItem); +void rlvMenuToggleVisible(); +bool rlvMenuCanShowName(); +bool rlvMenuEnableIfNot(const LLSD& sdParam); + +// ============================================================================ +// Selection functors +// + +bool rlvCanDeleteOrReturn(); +bool rlvCanDeleteOrReturn(const LLViewerObject* pObj); + +struct RlvSelectHasLockedAttach : public LLSelectedNodeFunctor +{ + RlvSelectHasLockedAttach() {} + virtual bool apply(LLSelectNode* pNode); +}; + +// Filters out selected objects that can't be editable (i.e. getFirstNode() will return NULL if the selection is fully editable) +struct RlvSelectIsEditable : public LLSelectedNodeFunctor +{ + RlvSelectIsEditable() {} + /*virtual*/ bool apply(LLSelectNode* pNode); +}; + +struct RlvSelectIsSittingOn : public LLSelectedNodeFunctor +{ + RlvSelectIsSittingOn(const LLVOAvatar* pAvatar) : m_pAvatar(pAvatar) {} + /*virtual*/ bool apply(LLSelectNode* pNode); +protected: + const LLVOAvatar* m_pAvatar; +}; + +// ============================================================================ +// Predicates +// + +bool rlvPredCanWearItem(const LLViewerInventoryItem* pItem, ERlvWearMask eWearMask); +bool rlvPredCanNotWearItem(const LLViewerInventoryItem* pItem, ERlvWearMask eWearMask); +bool rlvPredCanRemoveItem(const LLUUID& idItem); +bool rlvPredCanRemoveItem(const LLViewerInventoryItem* pItem); +bool rlvPredCanNotRemoveItem(const LLUUID& idItem); +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 RlvPredCanRemoveItem +{ + RlvPredCanRemoveItem() {} + bool operator()(const LLViewerInventoryItem* pItem) { return rlvPredCanRemoveItem(pItem); } +}; + +struct RlvPredCanNotRemoveItem +{ + RlvPredCanNotRemoveItem() {} + bool operator()(const LLViewerInventoryItem* pItem) { return rlvPredCanNotRemoveItem(pItem); } +}; + +struct RlvPredIsEqualOrLinkedItem +{ + RlvPredIsEqualOrLinkedItem(const LLViewerInventoryItem* pItem) : m_pItem(pItem) {} + RlvPredIsEqualOrLinkedItem(const LLUUID& idItem); + bool operator()(const LLViewerInventoryItem* pItem) const; +protected: + const LLViewerInventoryItem* m_pItem; +}; + +template<typename T> struct RlvPredValuesEqual +{ + bool operator()(const T* pT2) const { return (pT1) && (pT2) && (*pT1 == *pT2); } + const T* pT1; +}; + +// ============================================================================ +// Inlined class member functions +// + +// Checked: 2010-10-31 (RLVa-1.2.2a) | Added: RLVa-1.2.2a +inline const std::string& RlvStrings::getAnonym(const LLAvatarName& avName) +{ + return getAnonym(avName.getDisplayName()); +} + +// 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, bool fLoopback /*=false*/) +{ + return (nChannel > ((!fLoopback) ? 0 : -1)) && (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; +} + +// ============================================================================ + +#endif // RLV_COMMON_H diff --git a/indra/newview/rlvdefines.h b/indra/newview/rlvdefines.h new file mode 100644 index 0000000000000000000000000000000000000000..9c150b9136ffb089b53645697de15caf5847e4a7 --- /dev/null +++ b/indra/newview/rlvdefines.h @@ -0,0 +1,392 @@ +/** + * + * Copyright (c) 2009-2016, Kitty Barnett + * + * The source code in this file is provided to you under the terms of the + * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt + * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.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. + * + */ + +#ifndef RLV_DEFINES_H +#define RLV_DEFINES_H + +// ============================================================================ +// Defines +// + +// Version of the specifcation we report +const S32 RLV_VERSION_MAJOR = 3; +const S32 RLV_VERSION_MINOR = 1; +const S32 RLV_VERSION_PATCH = 4; +const S32 RLV_VERSION_BUILD = 0; + +// Version of the specifcation we report (in compatibility mode) +const S32 RLV_VERSION_MAJOR_COMPAT = 2; +const S32 RLV_VERSION_MINOR_COMPAT = 8; +const S32 RLV_VERSION_PATCH_COMPAT = 0; +const S32 RLV_VERSION_BUILD_COMPAT = 0; + +// Implementation version +const S32 RLVa_VERSION_MAJOR = 2; +const S32 RLVa_VERSION_MINOR = 0; +const S32 RLVa_VERSION_PATCH = 3; + +// Uncomment before a final release +//#define RLV_RELEASE + +// Defining these makes it easier if we ever need to change our tag +#define RLV_WARNS LL_WARNS("RLV") +#define RLV_INFOS LL_INFOS("RLV") +#define RLV_DEBUGS LL_DEBUGS("RLV") +#define RLV_ENDL LL_ENDL +#define RLV_VERIFY(f) if (!(f)) { RlvUtil::notifyFailedAssertion(#f, __FILE__, __LINE__); } + +#if LL_RELEASE_WITH_DEBUG_INFO || LL_DEBUG + // Turn on extended debugging information + #define RLV_DEBUG + // Make sure we halt execution on errors + #define RLV_ERRS LL_ERRS("RLV") + // Keep our asserts separate from LL's + #define RLV_ASSERT(f) if (!(f)) { RLV_ERRS << "ASSERT (" << #f << ")" << RLV_ENDL; } + #define RLV_ASSERT_DBG(f) RLV_ASSERT(f) +#else + // Don't halt execution on errors in release + #define RLV_ERRS LL_WARNS("RLV") + // We don't want to check assertions in release builds + #ifndef RLV_RELEASE + #define RLV_ASSERT(f) RLV_VERIFY(f) + #define RLV_ASSERT_DBG(f) + #else + #define RLV_ASSERT(f) + #define RLV_ASSERT_DBG(f) + #endif // RLV_RELEASE +#endif // LL_RELEASE_WITH_DEBUG_INFO || LL_DEBUG + +#define RLV_ROOT_FOLDER "#RLV" +#define RLV_CMD_PREFIX '@' +#define RLV_MODIFIER_TPLOCAL_DEFAULT 256.f // Any teleport that's more than a region away is non-local +#define RLV_MODIFIER_FARTOUCH_DEFAULT 1.5f // Specifies the default @fartouch distance +#define RLV_MODIFIER_SITTP_DEFAULT 1.5f // Specifies the default @sittp distance +#define RLV_OPTION_SEPARATOR ";" // Default separator used in command options +#define RLV_PUTINV_PREFIX "#RLV/~" +#define RLV_PUTINV_SEPARATOR "/" +#define RLV_PUTINV_MAXDEPTH 4 +#define RLV_SETROT_OFFSET F_PI_BY_TWO // @setrot is off by 90 degrees with the rest of SL +#define RLV_STRINGS_FILE "rlva_strings.xml" + +#define RLV_FOLDER_FLAG_NOSTRIP "nostrip" +#define RLV_FOLDER_PREFIX_HIDDEN '.' +#define RLV_FOLDER_PREFIX_PUTINV '~' + +// ============================================================================ +// Enumeration declarations +// + +// NOTE: any changes to this enumeration should be reflected in the RlvBehaviourDictionary constructor +enum ERlvBehaviour { + RLV_BHVR_DETACH = 0, // "detach" + RLV_BHVR_ADDATTACH, // "addattach" + RLV_BHVR_REMATTACH, // "remattach" + RLV_BHVR_ADDOUTFIT, // "addoutfit" + RLV_BHVR_REMOUTFIT, // "remoutfit" + RLV_BHVR_SHAREDWEAR, // "sharedwear" + RLV_BHVR_SHAREDUNWEAR, // "sharedunwear" + RLV_BHVR_UNSHAREDWEAR, // "unsharedwear" + RLV_BHVR_UNSHAREDUNWEAR, // "unsharedunwear" + RLV_BHVR_EMOTE, // "emote" + RLV_BHVR_SENDCHAT, // "sendchat" + RLV_BHVR_RECVCHAT, // "recvchat" + RLV_BHVR_RECVCHATFROM, // "recvchatfrom" + RLV_BHVR_RECVEMOTE, // "recvemote" + RLV_BHVR_RECVEMOTEFROM, // "recvemotefrom" + RLV_BHVR_REDIRCHAT, // "redirchat" + RLV_BHVR_REDIREMOTE, // "rediremote" + RLV_BHVR_CHATWHISPER, // "chatwhisper" + RLV_BHVR_CHATNORMAL, // "chatnormal" + RLV_BHVR_CHATSHOUT, // "chatshout" + RLV_BHVR_SENDCHANNEL, + RLV_BHVR_SENDCHANNELEXCEPT, + RLV_BHVR_SENDIM, // "sendim" + RLV_BHVR_SENDIMTO, // "sendimto" + RLV_BHVR_RECVIM, // "recvim" + RLV_BHVR_RECVIMFROM, // "recvimfrom" + RLV_BHVR_STARTIM, // "startim" + RLV_BHVR_STARTIMTO, // "startimto" + RLV_BHVR_SENDGESTURE, + RLV_BHVR_PERMISSIVE, // "permissive" + RLV_BHVR_NOTIFY, // "notify" + RLV_BHVR_SHOWINV, // "showinv" + RLV_BHVR_SHOWMINIMAP, // "showminimap" + RLV_BHVR_SHOWWORLDMAP, // "showworldmap" + RLV_BHVR_SHOWLOC, // "showloc" + RLV_BHVR_SHOWNAMES, // "shownames" + RLV_BHVR_SHOWNAMETAGS, // "shownametags" + RLV_BHVR_SHOWNEARBY, + RLV_BHVR_SHOWHOVERTEXT, // "showhovertext" + RLV_BHVR_SHOWHOVERTEXTHUD, // "showhovertexthud" + RLV_BHVR_SHOWHOVERTEXTWORLD, // "showhovertextworld" + RLV_BHVR_SHOWHOVERTEXTALL, // "showhovertextall" + RLV_BHVR_SHOWSELF, + RLV_BHVR_SHOWSELFHEAD, + RLV_BHVR_TPLM, // "tplm" + RLV_BHVR_TPLOC, // "tploc" + RLV_BHVR_TPLOCAL, + RLV_BHVR_TPLURE, // "tplure" + RLV_BHVR_TPREQUEST, // "tprequest" + RLV_BHVR_VIEWNOTE, // "viewnote" + RLV_BHVR_VIEWSCRIPT, // "viewscript" + RLV_BHVR_VIEWTEXTURE, // "viewtexture" + RLV_BHVR_ACCEPTPERMISSION, // "acceptpermission" + RLV_BHVR_ACCEPTTP, // "accepttp" + RLV_BHVR_ACCEPTTPREQUEST, // "accepttprequest" + RLV_BHVR_ALLOWIDLE, // "allowidle" + RLV_BHVR_EDIT, // "edit" + RLV_BHVR_EDITOBJ, // "editobj" + RLV_BHVR_REZ, // "rez" + RLV_BHVR_FARTOUCH, // "fartouch" + RLV_BHVR_INTERACT, // "interact" + RLV_BHVR_TOUCHTHIS, // "touchthis" + RLV_BHVR_TOUCHATTACH, // "touchattach" + RLV_BHVR_TOUCHATTACHSELF, // "touchattachself" + RLV_BHVR_TOUCHATTACHOTHER, // "touchattachother" + RLV_BHVR_TOUCHHUD, // "touchhud" + RLV_BHVR_TOUCHWORLD, // "touchworld" + RLV_BHVR_TOUCHALL, // "touchall" + RLV_BHVR_TOUCHME, // "touchme" + RLV_BHVR_FLY, // "fly" + RLV_BHVR_SETGROUP, // "setgroup" + RLV_BHVR_UNSIT, // "unsit" + RLV_BHVR_SIT, // "sit" + RLV_BHVR_SITTP, // "sittp" + RLV_BHVR_STANDTP, // "standtp" + RLV_BHVR_SETDEBUG, // "setdebug" + RLV_BHVR_SETENV, // "setenv" + RLV_BHVR_ALWAYSRUN, // "alwaysrun" + RLV_BHVR_TEMPRUN, // "temprun" + RLV_BHVR_DETACHME, // "detachme" + RLV_BHVR_ATTACHTHIS, // "attachthis" + RLV_BHVR_ATTACHTHISEXCEPT, // "attachthis_except" + RLV_BHVR_DETACHTHIS, // "detachthis" + RLV_BHVR_DETACHTHISEXCEPT, // "detachthis_except" + RLV_BHVR_ADJUSTHEIGHT, // "adjustheight" + RLV_BHVR_TPTO, // "tpto" + RLV_BHVR_VERSION, // "version" + RLV_BHVR_VERSIONNEW, // "versionnew" + RLV_BHVR_VERSIONNUM, // "versionnum" + RLV_BHVR_GETATTACH, // "getattach" + RLV_BHVR_GETATTACHNAMES, // "getattachnames" + RLV_BHVR_GETADDATTACHNAMES, // "getaddattachnames" + RLV_BHVR_GETREMATTACHNAMES, // "getremattachnames" + RLV_BHVR_GETOUTFIT, // "getoutfit" + RLV_BHVR_GETOUTFITNAMES, // "getoutfitnames" + RLV_BHVR_GETADDOUTFITNAMES, // "getaddoutfitnames" + RLV_BHVR_GETREMOUTFITNAMES, // "getremoutfitnames" + RLV_BHVR_FINDFOLDER, // "findfolder" + RLV_BHVR_FINDFOLDERS, // "findfolders" + RLV_BHVR_GETPATH, // "getpath" + RLV_BHVR_GETPATHNEW, // "getpathnew" + RLV_BHVR_GETINV, // "getinv" + RLV_BHVR_GETINVWORN, // "getinvworn" + RLV_BHVR_GETGROUP, // "getgroup" + RLV_BHVR_GETSITID, // "getsitid" + RLV_BHVR_GETCOMMAND, // "getcommand" + RLV_BHVR_GETSTATUS, // "getstatus" + RLV_BHVR_GETSTATUSALL, // "getstatusall" + RLV_CMD_FORCEWEAR, // Internal representation of all force wear commands + + // Camera (behaviours) + RLV_BHVR_SETCAM, // Gives an object exclusive control of the user's camera + RLV_BHVR_SETCAM_AVDISTMIN, // Enforces a minimum distance from the avatar (in m) + RLV_BHVR_SETCAM_AVDISTMAX, // Enforces a maximum distance from the avatar (in m) + RLV_BHVR_SETCAM_ORIGINDISTMIN, // Enforces a minimum distance from the camera origin (in m) + RLV_BHVR_SETCAM_ORIGINDISTMAX, // Enforces a maximum distance from the camera origin (in m) + RLV_BHVR_SETCAM_EYEOFFSET, // Changes the default camera offset + RLV_BHVR_SETCAM_FOCUSOFFSET, // Changes the default camera focus offset + RLV_BHVR_SETCAM_FOCUS, // Forces the camera focus and/or position to a specific object, avatar or position + RLV_BHVR_SETCAM_FOV, // Changes the current - vertical - field of view + RLV_BHVR_SETCAM_FOVMIN, // Enforces a minimum - vertical - FOV (in degrees) + RLV_BHVR_SETCAM_FOVMAX, // Enforces a maximum - vertical - FOV (in degrees) + RLV_BHVR_SETCAM_MOUSELOOK, // Prevent the user from going into mouselook + RLV_BHVR_SETCAM_TEXTURES, // Replaces all textures with the specified texture (or the default unrezzed one) + RLV_BHVR_SETCAM_UNLOCK, // Forces the camera focus to the user's avatar + // Camera (behaviours - deprecated) + RLV_BHVR_CAMZOOMMIN, // Enforces a minimum - vertical - FOV angle of 60° / multiplier + RLV_BHVR_CAMZOOMMAX, // Enforces a maximum - vertical - FOV angle of 60° / multiplier + // Camera (reply) + RLV_BHVR_GETCAM_AVDIST, // Returns the current minimum distance between the camera and the user's avatar + RLV_BHVR_GETCAM_AVDISTMIN, // Returns the active (if any) minimum distance between the camera and the user's avatar + RLV_BHVR_GETCAM_AVDISTMAX, // Returns the active (if any) maxmimum distance between the camera and the user's avatar + RLV_BHVR_GETCAM_FOV, // Returns the current field of view angle (in radians) + RLV_BHVR_GETCAM_FOVMIN, // Returns the active (if any) minimum field of view angle (in radians) + RLV_BHVR_GETCAM_FOVMAX, // Enforces a maximum (if any) maximum field of view angle (in radians) + RLV_BHVR_GETCAM_TEXTURES, // Returns the active (if any) replace texture UUID + // Camera (force) + RLV_BHVR_SETCAM_MODE, // Switch the user's camera into the specified mode (e.g. mouselook or thirdview) + + RLV_BHVR_COUNT, + RLV_BHVR_UNKNOWN +}; + +enum ERlvBehaviourModifier +{ + RLV_MODIFIER_FARTOUCHDIST, // Radius of a sphere around the user in which they can interact with the world + RLV_MODIFIER_RECVIMDISTMIN, // Minimum distance to receive an IM from an otherwise restricted sender (squared value) + RLV_MODIFIER_RECVIMDISTMAX, // Maximum distance to receive an IM from an otherwise restricted sender (squared value) + RLV_MODIFIER_SENDIMDISTMIN, // Minimum distance to send an IM to an otherwise restricted recipient (squared value) + RLV_MODIFIER_SENDIMDISTMAX, // Maximum distance to send an IM to an otherwise restricted recipient (squared value) + RLV_MODIFIER_STARTIMDISTMIN, // Minimum distance to start an IM to an otherwise restricted recipient (squared value) + RLV_MODIFIER_STARTIMDISTMAX, // Maximum distance to start an IM to an otherwise restricted recipient (squared value) + RLV_MODIFIER_SETCAM_AVDISTMIN, // Minimum distance between the camera position and the user's avatar (normal value) + RLV_MODIFIER_SETCAM_AVDISTMAX, // Maximum distance between the camera position and the user's avatar (normal value) + RLV_MODIFIER_SETCAM_ORIGINDISTMIN, // Minimum distance between the camera position and the origin point (normal value) + RLV_MODIFIER_SETCAM_ORIGINDISTMAX, // Maximum distance between the camera position and the origin point (normal value) + RLV_MODIFIER_SETCAM_EYEOFFSET, // Specifies the default camera's offset from the camera (vector) + RLV_MODIFIER_SETCAM_FOCUSOFFSET, // Specifies the default camera's focus (vector) + RLV_MODIFIER_SETCAM_FOVMIN, // Minimum value for the camera's field of view (angle in radians) + RLV_MODIFIER_SETCAM_FOVMAX, // Maximum value for the camera's field of view (angle in radians) + RLV_MODIFIER_SETCAM_TEXTURE, // Specifies the UUID of the texture used to texture the world view + RLV_MODIFIER_SITTPDIST, + RLV_MODIFIER_TPLOCALDIST, + + RLV_MODIFIER_COUNT, + RLV_MODIFIER_UNKNOWN +}; + +enum ERlvBehaviourOptionType +{ + RLV_OPTION_NONE, // Behaviour takes no parameters + RLV_OPTION_EXCEPTION, // Behaviour requires an exception as a parameter + RLV_OPTION_NONE_OR_EXCEPTION, // Behaviour takes either no parameters or an exception + RLV_OPTION_MODIFIER, // Behaviour requires a modifier as a parameter + RLV_OPTION_NONE_OR_MODIFIER // Behaviour takes either no parameters or a modifier +}; + +enum ERlvParamType { + RLV_TYPE_UNKNOWN = 0x00, + RLV_TYPE_ADD = 0x01, // <param> == "n"|"add" + RLV_TYPE_REMOVE = 0x02, // <param> == "y"|"rem" + RLV_TYPE_FORCE = 0x04, // <param> == "force" + RLV_TYPE_REPLY = 0x08, // <param> == <number> + RLV_TYPE_CLEAR = 0x10, + RLV_TYPE_ADDREM = RLV_TYPE_ADD | RLV_TYPE_REMOVE +}; + +enum ERlvCmdRet { + RLV_RET_UNKNOWN = 0x0000, // Unknown error (should only be used internally) + RLV_RET_RETAINED, // Command was retained + RLV_RET_SUCCESS = 0x0100, // Command executed succesfully + RLV_RET_SUCCESS_UNSET, // Command executed succesfully (RLV_TYPE_REMOVE for an unrestricted behaviour) + RLV_RET_SUCCESS_DUPLICATE, // Command executed succesfully (RLV_TYPE_ADD for an already restricted behaviour) + RLV_RET_SUCCESS_DEPRECATED, // Command executed succesfully but has been marked as deprecated + RLV_RET_SUCCESS_DELAYED, // Command parsed valid but will execute at a later time + RLV_RET_FAILED = 0x0200, // Command failed (general failure) + RLV_RET_FAILED_SYNTAX, // Command failed (syntax error) + RLV_RET_FAILED_OPTION, // Command failed (invalid option) + RLV_RET_FAILED_PARAM, // Command failed (invalid param) + RLV_RET_FAILED_LOCK, // Command failed (command is locked by another object) + RLV_RET_FAILED_DISABLED, // Command failed (command disabled by user) + RLV_RET_FAILED_UNKNOWN, // Command failed (unknown command) + RLV_RET_FAILED_NOSHAREDROOT, // Command failed (missing #RLV) + RLV_RET_FAILED_DEPRECATED, // Command failed (deprecated and no longer supported) + RLV_RET_NO_PROCESSOR // Command doesn't have a template processor define (legacy code) +}; +#define RLV_RET_SUCCEEDED(eCmdRet) (((eCmdRet) & RLV_RET_SUCCESS) == RLV_RET_SUCCESS) + +enum ERlvExceptionCheck +{ + RLV_CHECK_PERMISSIVE, // Exception can be set by any object + RLV_CHECK_STRICT, // Exception must be set by all objects holding the restriction + RLV_CHECK_DEFAULT // Permissive or strict will be determined by currently enforced restrictions +}; + +enum ERlvLockMask +{ + RLV_LOCK_NONE = 0x00, + RLV_LOCK_ADD = 0x01, + RLV_LOCK_REMOVE = 0x02, + RLV_LOCK_ANY = RLV_LOCK_ADD | RLV_LOCK_REMOVE +}; + +enum ERlvWearMask +{ + RLV_WEAR_LOCKED = 0x00, // User can not wear the item at all + RLV_WEAR_ADD = 0x01, // User can wear the item in addition to what's already worn + RLV_WEAR_REPLACE = 0x02, // User can wear the item and replace what's currently worn + RLV_WEAR = 0x03 // Convenience: combines RLV_WEAR_ADD and RLV_WEAR_REPLACE +}; + +enum ERlvAttachGroupType +{ + RLV_ATTACHGROUP_HEAD = 0, + RLV_ATTACHGROUP_TORSO, + RLV_ATTACHGROUP_ARMS, + RLV_ATTACHGROUP_LEGS, + RLV_ATTACHGROUP_HUD, + RLV_ATTACHGROUP_COUNT, + RLV_ATTACHGROUP_INVALID +}; + +// ============================================================================ +// Settings +// + +#define RLV_SETTING_MAIN "RestrainedLove" +#define RLV_SETTING_DEBUG "RestrainedLoveDebug" +#define RLV_SETTING_CANOOC "RestrainedLoveCanOOC" +#define RLV_SETTING_FORBIDGIVETORLV "RestrainedLoveForbidGiveToRLV" +#define RLV_SETTING_NOSETENV "RestrainedLoveNoSetEnv" +#define RLV_SETTING_SHOWELLIPSIS "RestrainedLoveShowEllipsis" +#define RLV_SETTING_WEARADDPREFIX "RestrainedLoveStackWhenFolderBeginsWith" +#define RLV_SETTING_WEARREPLACEPREFIX "RestrainedLoveReplaceWhenFolderBeginsWith" + +#define RLV_SETTING_DEBUGHIDEUNSETDUP "RLVaDebugHideUnsetDuplicate" +#define RLV_SETTING_ENABLECOMPOSITES "RLVaEnableCompositeFolders" +#define RLV_SETTING_ENABLELEGACYNAMING "RLVaEnableLegacyNaming" +#define RLV_SETTING_ENABLESHAREDWEAR "RLVaEnableSharedWear" +#define RLV_SETTING_ENABLETEMPATTACH "RLVaEnableTemporaryAttachments" +#define RLV_SETTING_HIDELOCKEDLAYER "RLVaHideLockedLayers" +#define RLV_SETTING_HIDELOCKEDATTACH "RLVaHideLockedAttachments" +#define RLV_SETTING_HIDELOCKEDINVENTORY "RLVaHideLockedInventory" +#define RLV_SETTING_LOGINLASTLOCATION "RLVaLoginLastLocation" +#define RLV_SETTING_SHAREDINVAUTORENAME "RLVaSharedInvAutoRename" +#define RLV_SETTING_SHOWASSERTIONFAIL "RLVaShowAssertionFailures" +#define RLV_SETTING_TOPLEVELMENU "RLVaTopLevelMenu" +#define RLV_SETTING_WEARREPLACEUNLOCKED "RLVaWearReplaceUnlocked" + +#define RLV_SETTING_FIRSTUSE_PREFIX "FirstRLV" +#define RLV_SETTING_FIRSTUSE_GIVETORLV RLV_SETTING_FIRSTUSE_PREFIX"GiveToRLV" + +// ============================================================================ +// Strings (see rlva_strings.xml) +// + +#define RLV_STRING_HIDDEN "hidden_generic" +#define RLV_STRING_HIDDEN_PARCEL "hidden_parcel" +#define RLV_STRING_HIDDEN_REGION "hidden_region" + +#define RLV_STRING_BLOCKED_AUTOPILOT "blocked_autopilot" +#define RLV_STRING_BLOCKED_GENERIC "blocked_generic" +#define RLV_STRING_BLOCKED_GROUPCHANGE "blocked_groupchange" +#define RLV_STRING_BLOCKED_PERMATTACH "blocked_permattach" +#define RLV_STRING_BLOCKED_PERMTELEPORT "blocked_permteleport" +#define RLV_STRING_BLOCKED_RECVIM "blocked_recvim" +#define RLV_STRING_BLOCKED_RECVIM_REMOTE "blocked_recvim_remote" +#define RLV_STRING_BLOCKED_SENDIM "blocked_sendim" +#define RLV_STRING_BLOCKED_STARTCONF "blocked_startconf" +#define RLV_STRING_BLOCKED_STARTIM "blocked_startim" +#define RLV_STRING_BLOCKED_TELEPORT "blocked_teleport" +#define RLV_STRING_BLOCKED_TELEPORT_OFFER "blocked_teleport_offer" +#define RLV_STRING_BLOCKED_TPLUREREQ_REMOTE "blocked_tplurerequest_remote" +#define RLV_STRING_BLOCKED_VIEWXXX "blocked_viewxxx" +#define RLV_STRING_BLOCKED_WIREFRAME "blocked_wireframe" + +// ============================================================================ + +#endif // RLV_DEFINES_H diff --git a/indra/newview/rlvextensions.cpp b/indra/newview/rlvextensions.cpp new file mode 100644 index 0000000000000000000000000000000000000000..43a5f61f506efa23d95a27f03ac24f3b2463e2dc --- /dev/null +++ b/indra/newview/rlvextensions.cpp @@ -0,0 +1,640 @@ +/** + * + * Copyright (c) 2009-2011, Kitty Barnett + * + * The source code in this file is provided to you under the terms of the + * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt + * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.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 "llagent.h" +#include "llagentcamera.h" +#include "lldaycyclemanager.h" +#include "llvoavatarself.h" +#include "llwlparammanager.h" + +#include "rlvextensions.h" +#include "rlvhandler.h" +#include "rlvhelper.h" + +// ============================================================================ + +class RlvWindLightControl +{ +public: + enum EType { TYPE_COLOR, TYPE_COLOR_R, TYPE_FLOAT, TYPE_UNKNOWN }; + enum EColorComponent { COMPONENT_R, COMPONENT_G, COMPONENT_B, COMPONENT_I, COMPONENT_NONE }; +public: + RlvWindLightControl(WLColorControl* pCtrl, bool fColorR) : m_eType((!fColorR) ? TYPE_COLOR: TYPE_COLOR_R), m_pColourCtrl(pCtrl), m_pFloatCtrl(NULL) {} + RlvWindLightControl(WLFloatControl* pCtrl) : m_eType(TYPE_FLOAT), m_pColourCtrl(NULL), m_pFloatCtrl(pCtrl) {} + + EType getControlType() const { return m_eType; } + bool isColorType() const { return (TYPE_COLOR == m_eType) || (TYPE_COLOR_R == m_eType); } + bool isFloatType() const { return (TYPE_FLOAT == m_eType); } + // TYPE_COLOR and TYPE_COLOR_R + F32 getColorComponent(EColorComponent eComponent, bool& fError) const; + LLVector4 getColorVector(bool& fError) const; + bool setColorComponent(EColorComponent eComponent, F32 nValue); + // TYPE_FLOAT + F32 getFloat(bool& fError) const; + bool setFloat(F32 nValue); + + static EColorComponent getComponentFromCharacter(char ch); +protected: + EType m_eType; // Type of the WindLight control + WLColorControl* m_pColourCtrl; + WLFloatControl* m_pFloatCtrl; +}; + +// Checked: 2011-08-29 (RLVa-1.4.1a) | Added: RLVa-1.4.1a +static F32 get_intensity_from_color(const LLVector4& v) +{ + return llmax(v.mV[0], v.mV[1], v.mV[2]); +} + +// Checked: 2011-08-29 (RLVa-1.4.1a) | Added: RLVa-1.4.1a +F32 RlvWindLightControl::getColorComponent(EColorComponent eComponent, bool& fError) const +{ + switch (eComponent) + { + case COMPONENT_R: return getColorVector(fError).mV[0]; + case COMPONENT_G: return getColorVector(fError).mV[1]; + case COMPONENT_B: return getColorVector(fError).mV[2]; + case COMPONENT_I: return get_intensity_from_color(getColorVector(fError)); // SL-2.8: Always seems to be 1.0 so get it manually + default : RLV_ASSERT(false); fError = true; return 0.0; + } +} + +// Checked: 2011-08-29 (RLVa-1.4.1a) | Added: RLVa-1.4.1a +RlvWindLightControl::EColorComponent RlvWindLightControl::getComponentFromCharacter(char ch) +{ + if (('r' == ch) || ('x' == ch)) + return COMPONENT_R; + else if (('g' == ch) || ('y' == ch)) + return COMPONENT_G; + else if (('b' == ch) || ('d' == ch)) + return COMPONENT_B; + else if ('i' == ch) + return COMPONENT_I; + return COMPONENT_NONE; +} + +// Checked: 2011-08-29 (RLVa-1.4.1a) | Added: RLVa-1.4.1a +LLVector4 RlvWindLightControl::getColorVector(bool& fError) const +{ + if ((fError = !isColorType())) + return LLVector4(0, 0, 0, 0); + F32 nMult = (m_pColourCtrl->isSunOrAmbientColor) ? 3.0f : ((m_pColourCtrl->isBlueHorizonOrDensity) ? 2.0f : 1.0f); + return LLWLParamManager::getInstance()->mCurParams.getVector(m_pColourCtrl->mName, fError) / nMult; +} + +// Checked: 2011-08-28 (RLVa-1.4.1a) | Added: RLVa-1.4.1a +bool RlvWindLightControl::setColorComponent(EColorComponent eComponent, F32 nValue) +{ + if (isColorType()) + { + nValue *= (m_pColourCtrl->isSunOrAmbientColor) ? 3.0f : ((m_pColourCtrl->isBlueHorizonOrDensity) ? 2.0f : 1.0f); + if (COMPONENT_I == eComponent) // (See: LLFloaterWindLight::onColorControlIMoved) + { + if (m_pColourCtrl->hasSliderName) + { + F32 curMax = llmax(m_pColourCtrl->r, m_pColourCtrl->g, m_pColourCtrl->b); + if ( (0.0f == nValue) || (0.0f == curMax) ) + { + m_pColourCtrl->r = m_pColourCtrl->g = m_pColourCtrl->b = m_pColourCtrl->i = nValue; + } + else + { + F32 nDelta = (nValue - curMax) / curMax; + m_pColourCtrl->r *= (1.0f + nDelta); + m_pColourCtrl->g *= (1.0f + nDelta); + m_pColourCtrl->b *= (1.0f + nDelta); + m_pColourCtrl->i = nValue; + } + } + } + else // (See: LLFloaterWindLight::onColorControlRMoved) + { + F32* pnValue = (COMPONENT_R == eComponent) ? &m_pColourCtrl->r : (COMPONENT_G == eComponent) ? &m_pColourCtrl->g : (COMPONENT_B == eComponent) ? &m_pColourCtrl->b : NULL; + if (pnValue) + *pnValue = nValue; + if (m_pColourCtrl->hasSliderName) + m_pColourCtrl->i = llmax(m_pColourCtrl->r, m_pColourCtrl->g, m_pColourCtrl->b); + } + m_pColourCtrl->update(LLWLParamManager::getInstance()->mCurParams); + LLWLParamManager::getInstance()->propagateParameters(); + } + return isColorType(); +} + +// Checked: 2011-08-29 (RLVa-1.4.1a) | Added: RLVa-1.4.1a +F32 RlvWindLightControl::getFloat(bool& fError) const +{ + return (!(fError = (TYPE_FLOAT != m_eType))) ? LLWLParamManager::getInstance()->mCurParams.getVector(m_pFloatCtrl->mName, fError).mV[0] * m_pFloatCtrl->mult : 0.0; +} + +// Checked: 2011-08-28 (RLVa-1.4.1a) | Added: RLVa-1.4.1a +bool RlvWindLightControl::setFloat(F32 nValue) +{ + if (TYPE_FLOAT == m_eType) + { + m_pFloatCtrl->x = nValue / m_pFloatCtrl->mult; + m_pFloatCtrl->update(LLWLParamManager::getInstance()->mCurParams); + LLWLParamManager::getInstance()->propagateParameters(); + } + return (TYPE_FLOAT == m_eType); +} + +// ============================================================================ + +class RlvWindLight : public LLSingleton<RlvWindLight> +{ + friend class LLSingleton<RlvWindLight>; +public: + RlvWindLight(); + + std::string getValue(const std::string& strSetting, bool& fError); + bool setValue(const std::string& strRlvName, const std::string& strValue); + +protected: + std::map<std::string, RlvWindLightControl> m_ControlLookupMap; +}; + +// Checked: 2011-08-29 (RLVa-1.4.1a) | Added: RLVa-1.4.1a +RlvWindLight::RlvWindLight() +{ + LLWLParamManager* pWLParamMgr = LLWLParamManager::getInstance(); + + // TYPE_FLOAT + m_ControlLookupMap.insert(std::pair<std::string, RlvWindLightControl>("cloudcoverage", RlvWindLightControl(&pWLParamMgr->mCloudCoverage))); + m_ControlLookupMap.insert(std::pair<std::string, RlvWindLightControl>("cloudscale", RlvWindLightControl(&pWLParamMgr->mCloudScale))); + m_ControlLookupMap.insert(std::pair<std::string, RlvWindLightControl>("densitymultiplier", RlvWindLightControl(&pWLParamMgr->mDensityMult))); + m_ControlLookupMap.insert(std::pair<std::string, RlvWindLightControl>("distancemultiplier", RlvWindLightControl(&pWLParamMgr->mDistanceMult))); + m_ControlLookupMap.insert(std::pair<std::string, RlvWindLightControl>("maxaltitude", RlvWindLightControl(&pWLParamMgr->mMaxAlt))); + m_ControlLookupMap.insert(std::pair<std::string, RlvWindLightControl>("scenegamma", RlvWindLightControl(&pWLParamMgr->mWLGamma))); + m_ControlLookupMap.insert(std::pair<std::string, RlvWindLightControl>("hazedensity", RlvWindLightControl(&pWLParamMgr->mHazeDensity))); + m_ControlLookupMap.insert(std::pair<std::string, RlvWindLightControl>("hazehorizon", RlvWindLightControl(&pWLParamMgr->mHazeHorizon))); + // TYPE_COLOR + m_ControlLookupMap.insert(std::pair<std::string, RlvWindLightControl>("ambient", RlvWindLightControl(&pWLParamMgr->mAmbient, false))); + m_ControlLookupMap.insert(std::pair<std::string, RlvWindLightControl>("bluedensity", RlvWindLightControl(&pWLParamMgr->mBlueDensity, false))); + m_ControlLookupMap.insert(std::pair<std::string, RlvWindLightControl>("bluehorizon", RlvWindLightControl(&pWLParamMgr->mBlueHorizon, false))); + m_ControlLookupMap.insert(std::pair<std::string, RlvWindLightControl>("cloud", RlvWindLightControl(&pWLParamMgr->mCloudMain, false))); + m_ControlLookupMap.insert(std::pair<std::string, RlvWindLightControl>("cloudcolor", RlvWindLightControl(&pWLParamMgr->mCloudColor, false))); + m_ControlLookupMap.insert(std::pair<std::string, RlvWindLightControl>("clouddetail", RlvWindLightControl(&pWLParamMgr->mCloudDetail, false))); + m_ControlLookupMap.insert(std::pair<std::string, RlvWindLightControl>("sunmooncolor", RlvWindLightControl(&pWLParamMgr->mSunlight, false))); +} + +// Checked: 2011-08-29 (RLVa-1.4.1a) | Added: RLVa-1.4.1a +std::string RlvWindLight::getValue(const std::string& strSetting, bool& fError) +{ + LLWLParamManager* pWLParams = LLWLParamManager::getInstance(); + LLEnvManagerNew* pEnvMgr = LLEnvManagerNew::getInstance(); + + fError = false; // Assume we won't fail + if ("preset" == strSetting) + return (pEnvMgr->getUseFixedSky()) ? pEnvMgr->getSkyPresetName() : std::string(); + else if ("daycycle" == strSetting) + return (pEnvMgr->getUseDayCycle()) ? pEnvMgr->getDayCycleName() : std::string(); + + F32 nValue = 0.0f; + if ("daytime" == strSetting) + { + nValue = (pEnvMgr->getUseFixedSky()) ? pWLParams->mCurParams.getFloat("sun_angle", fError) / F_TWO_PI : -1.0f; + } + else if (("sunglowfocus" == strSetting) || ("sunglowsize" == strSetting)) + { + pWLParams->mGlow = pWLParams->mCurParams.getVector(pWLParams->mGlow.mName, fError); + RLV_ASSERT_DBG(!fError); + + if ("sunglowfocus" == strSetting) + nValue = -pWLParams->mGlow.b / 5.0f; + else + nValue = 2 - pWLParams->mGlow.r / 20.0f; + } + else if ("starbrightness" == strSetting) nValue = pWLParams->mCurParams.getStarBrightness(); + else if ("eastangle" == strSetting) nValue = pWLParams->mCurParams.getEastAngle() / F_TWO_PI; + else if ("sunmoonposition" == strSetting) nValue = pWLParams->mCurParams.getSunAngle() / F_TWO_PI; + else if ("cloudscrollx" == strSetting) nValue = pWLParams->mCurParams.getCloudScrollX() - 10.0f; + else if ("cloudscrolly" == strSetting) nValue = pWLParams->mCurParams.getCloudScrollY() - 10.0f; + else + { + std::map<std::string, RlvWindLightControl>::const_iterator itControl = m_ControlLookupMap.find(strSetting); + if (m_ControlLookupMap.end() != itControl) + { + switch (itControl->second.getControlType()) + { + case RlvWindLightControl::TYPE_FLOAT: + nValue = itControl->second.getFloat(fError); + break; + case RlvWindLightControl::TYPE_COLOR_R: + nValue = itControl->second.getColorComponent(RlvWindLightControl::COMPONENT_R, fError); + break; + default: + fError = true; + break; + } + } + else + { + // Couldn't find the exact name, check for a color control name + RlvWindLightControl::EColorComponent eComponent = RlvWindLightControl::getComponentFromCharacter(strSetting[strSetting.length() - 1]); + if (RlvWindLightControl::COMPONENT_NONE != eComponent) + itControl = m_ControlLookupMap.find(strSetting.substr(0, strSetting.length() - 1)); + if ( (m_ControlLookupMap.end() != itControl) && (itControl->second.isColorType()) ) + nValue = itControl->second.getColorComponent(eComponent, fError); + else + fError = true; + } + } + return llformat("%f", nValue); +} + +// Checked: 2011-08-29 (RLVa-1.4.1a) | Added: RLVa-1.4.1a +bool RlvWindLight::setValue(const std::string& strRlvName, const std::string& strValue) +{ + F32 nValue = 0.0f; + // Sanity check - make sure strValue specifies a number for all settings except "preset" and "daycycle" + if ( (RlvSettings::getNoSetEnv()) || + ( (!LLStringUtil::convertToF32(strValue, nValue)) && (("preset" != strRlvName) && ("daycycle" != strRlvName)) ) ) + { + return false; + } + + LLWLParamManager* pWLParams = LLWLParamManager::getInstance(); + LLEnvManagerNew* pEnvMgr = LLEnvManagerNew::getInstance(); + + if ("daytime" == strRlvName) + { + if (0.0f <= nValue) + { + pWLParams->mAnimator.deactivate(); + pWLParams->mAnimator.setDayTime(nValue); + pWLParams->mAnimator.update(pWLParams->mCurParams); + } + else + { + pEnvMgr->setUserPrefs(pEnvMgr->getWaterPresetName(), pEnvMgr->getSkyPresetName(), pEnvMgr->getDayCycleName(), false, true); + } + return true; + } + else if ("preset" == strRlvName) + { + std::string strPresetName = pWLParams->findPreset(strValue, LLEnvKey::SCOPE_LOCAL); + if (!strPresetName.empty()) + pEnvMgr->useSkyPreset(strPresetName); + return !strPresetName.empty(); + } + else if ("daycycle" == strRlvName) + { + std::string strPresetName = LLDayCycleManager::instance().findPreset(strValue); + if (!strPresetName.empty()) + pEnvMgr->useDayCycle(strValue, LLEnvKey::SCOPE_LOCAL); + return !strPresetName.empty(); + } + + bool fError = false; + pWLParams->mAnimator.deactivate(); + if (("sunglowfocus" == strRlvName) || ("sunglowsize" == strRlvName)) + { + pWLParams->mGlow = pWLParams->mCurParams.getVector(pWLParams->mGlow.mName, fError); + RLV_ASSERT_DBG(!fError); + + if ("sunglowfocus" == strRlvName) + pWLParams->mGlow.b = -nValue * 5; + else + pWLParams->mGlow.r = (2 - nValue) * 20; + + pWLParams->mGlow.update(pWLParams->mCurParams); + pWLParams->propagateParameters(); + return true; + } + else if ("starbrightness" == strRlvName) + { + pWLParams->mCurParams.setStarBrightness(nValue); + return true; + } + else if (("eastangle" == strRlvName) || ("sunmoonposition" == strRlvName)) + { + if ("eastangle" == strRlvName) + pWLParams->mCurParams.setEastAngle(F_TWO_PI * nValue); + else + pWLParams->mCurParams.setSunAngle(F_TWO_PI * nValue); + + // Set the sun vector + pWLParams->mLightnorm.r = -sin(pWLParams->mCurParams.getEastAngle()) * cos(pWLParams->mCurParams.getSunAngle()); + pWLParams->mLightnorm.g = sin(pWLParams->mCurParams.getSunAngle()); + pWLParams->mLightnorm.b = cos(pWLParams->mCurParams.getEastAngle()) * cos(pWLParams->mCurParams.getSunAngle()); + pWLParams->mLightnorm.i = 1.f; + + pWLParams->propagateParameters(); + return true; + } + else if ("cloudscrollx" == strRlvName) + { + pWLParams->mCurParams.setCloudScrollX(nValue + 10.0f); + return true; + } + else if ("cloudscrolly" == strRlvName) + { + pWLParams->mCurParams.setCloudScrollY(nValue + 10.0f); + return true; + } + + std::map<std::string, RlvWindLightControl>::iterator itControl = m_ControlLookupMap.find(strRlvName); + if (m_ControlLookupMap.end() != itControl) + { + switch (itControl->second.getControlType()) + { + case RlvWindLightControl::TYPE_FLOAT: + return itControl->second.setFloat(nValue); + case RlvWindLightControl::TYPE_COLOR_R: + return itControl->second.setColorComponent(RlvWindLightControl::COMPONENT_R, nValue); + default: + RLV_ASSERT(false); + } + } + else + { + // Couldn't find the exact name, check for a color control name + RlvWindLightControl::EColorComponent eComponent = RlvWindLightControl::getComponentFromCharacter(strRlvName[strRlvName.length() - 1]); + if (RlvWindLightControl::COMPONENT_NONE != eComponent) + itControl = m_ControlLookupMap.find(strRlvName.substr(0, strRlvName.length() - 1)); + if ( (m_ControlLookupMap.end() != itControl) && (itControl->second.isColorType()) ) + return itControl->second.setColorComponent(eComponent, nValue); + } + return false; +} + +// ============================================================================ + +std::map<std::string, S16> RlvExtGetSet::m_DbgAllowed; +std::map<std::string, std::string> RlvExtGetSet::m_PseudoDebug; + +// Checked: 2009-06-03 (RLVa-0.2.0h) | Modified: RLVa-0.2.0h +RlvExtGetSet::RlvExtGetSet() +{ + if (!m_DbgAllowed.size()) // m_DbgAllowed is static and should only be initialized once + { + m_DbgAllowed.insert(std::pair<std::string, S16>("AvatarSex", DBG_READ | DBG_WRITE | DBG_PSEUDO)); + m_DbgAllowed.insert(std::pair<std::string, S16>("RenderResolutionDivisor", DBG_READ | DBG_WRITE)); + m_DbgAllowed.insert(std::pair<std::string, S16>(RLV_SETTING_FORBIDGIVETORLV, DBG_READ)); + m_DbgAllowed.insert(std::pair<std::string, S16>(RLV_SETTING_NOSETENV, DBG_READ)); + m_DbgAllowed.insert(std::pair<std::string, S16>("WindLightUseAtmosShaders", DBG_READ)); + + // Cache persistance of every setting + LLControlVariable* pSetting; + for (std::map<std::string, S16>::iterator itDbg = m_DbgAllowed.begin(); itDbg != m_DbgAllowed.end(); ++itDbg) + { + if ( ((pSetting = gSavedSettings.getControl(itDbg->first)) != NULL) && (pSetting->isPersisted()) ) + itDbg->second |= DBG_PERSIST; + } + } +} + +// Checked: 2009-05-17 (RLVa-0.2.0a) +bool RlvExtGetSet::onForceCommand(const RlvCommand& rlvCmd, ERlvCmdRet& cmdRet) +{ + return processCommand(rlvCmd, cmdRet); +} + +// Checked: 2009-05-17 (RLVa-0.2.0a) +bool RlvExtGetSet::onReplyCommand(const RlvCommand& rlvCmd, ERlvCmdRet& cmdRet) +{ + return processCommand(rlvCmd, cmdRet); +} + +// Checked: 2009-12-23 (RLVa-1.1.0k) | Modified: RLVa-1.1.0k +bool RlvExtGetSet::processCommand(const RlvCommand& rlvCmd, ERlvCmdRet& eRet) +{ + std::string strBehaviour = rlvCmd.getBehaviour(), strGetSet, strSetting; + int idxSetting = strBehaviour.find('_'); + if ( (strBehaviour.length() >= 6) && (-1 != idxSetting) && ((int)strBehaviour.length() > idxSetting + 1) ) + { + strSetting = strBehaviour.substr(idxSetting + 1); + strBehaviour.erase(idxSetting); // Get rid of "_<setting>" + + strGetSet = strBehaviour.substr(0, 3); + strBehaviour.erase(0, 3); // Get rid of get/set + + if ("debug" == strBehaviour) + { + if ( ("get" == strGetSet) && (RLV_TYPE_REPLY == rlvCmd.getParamType()) ) + { + RlvUtil::sendChatReply(rlvCmd.getParam(), onGetDebug(strSetting)); + eRet = RLV_RET_SUCCESS; + return true; + } + else if ( ("set" == strGetSet) && (RLV_TYPE_FORCE == rlvCmd.getParamType()) ) + { + if (!gRlvHandler.hasBehaviourExcept(RLV_BHVR_SETDEBUG, rlvCmd.getObjectID())) + eRet = onSetDebug(strSetting, rlvCmd.getOption()); + else + eRet = RLV_RET_FAILED_LOCK; + return true; + } + } + else if ("env" == strBehaviour) + { + bool fError = false; + if ( ("get" == strGetSet) && (RLV_TYPE_REPLY == rlvCmd.getParamType()) ) + { + RlvUtil::sendChatReply(rlvCmd.getParam(), RlvWindLight::instance().getValue(strSetting, fError)); + eRet = (!fError) ? RLV_RET_SUCCESS : RLV_RET_FAILED_UNKNOWN; + return true; + } + else if ( ("set" == strGetSet) && (RLV_TYPE_FORCE == rlvCmd.getParamType()) ) + { + if (!gRlvHandler.hasBehaviourExcept(RLV_BHVR_SETENV, rlvCmd.getObjectID())) + eRet = (RlvWindLight::instance().setValue(strSetting, rlvCmd.getOption())) ? RLV_RET_SUCCESS : RLV_RET_FAILED_UNKNOWN; + else + eRet = RLV_RET_FAILED_LOCK; + return true; + } + } + } + else if ("setrot" == rlvCmd.getBehaviour()) + { + // NOTE: if <option> is invalid (or missing) altogether then RLV-1.17 will rotate to 0.0 (which is actually PI / 4) + F32 nAngle = 0.0f; + if (LLStringUtil::convertToF32(rlvCmd.getOption(), nAngle)) + { + nAngle = RLV_SETROT_OFFSET - nAngle; + + gAgentCamera.startCameraAnimation(); + + LLVector3 at(LLVector3::x_axis); + at.rotVec(nAngle, LLVector3::z_axis); + at.normalize(); + gAgent.resetAxes(at); + + eRet = RLV_RET_SUCCESS; + } + else + { + eRet = RLV_RET_FAILED_OPTION; + } + return true; + } + return false; +} + +// Checked: 2009-06-03 (RLVa-0.2.0h) | Modified: RLVa-0.2.0h +bool RlvExtGetSet::findDebugSetting(std::string& strSetting, S16& flags) +{ + LLStringUtil::toLower(strSetting); // Convenience for non-RLV calls + + std::string strTemp; + for (std::map<std::string, S16>::const_iterator itSetting = m_DbgAllowed.begin(); itSetting != m_DbgAllowed.end(); ++itSetting) + { + strTemp = itSetting->first; + LLStringUtil::toLower(strTemp); + + if (strSetting == strTemp) + { + strSetting = itSetting->first; + flags = itSetting->second; + return true; + } + } + return false; +} + +// Checked: 2009-06-03 (RLVa-0.2.0h) | Added: RLVa-0.2.0h +S16 RlvExtGetSet::getDebugSettingFlags(const std::string& strSetting) +{ + std::map<std::string, S16>::const_iterator itSetting = m_DbgAllowed.find(strSetting); + return (itSetting != m_DbgAllowed.end()) ? itSetting->second : 0; +} + +// Checked: 2009-06-03 (RLVa-0.2.0h) | Modified: RLVa-0.2.0h +std::string RlvExtGetSet::onGetDebug(std::string strSetting) +{ + S16 dbgFlags; + if ( (findDebugSetting(strSetting, dbgFlags)) && ((dbgFlags & DBG_READ) == DBG_READ) ) + { + if ((dbgFlags & DBG_PSEUDO) == 0) + { + LLControlVariable* pSetting = gSavedSettings.getControl(strSetting); + if (pSetting) + { + switch (pSetting->type()) + { + case TYPE_U32: + return llformat("%u", gSavedSettings.getU32(strSetting)); + case TYPE_S32: + return llformat("%d", gSavedSettings.getS32(strSetting)); + case TYPE_BOOLEAN: + return llformat("%d", gSavedSettings.getBOOL(strSetting)); + default: + RLV_ERRS << "Unexpected debug setting type" << LL_ENDL; + break; + } + } + } + else + { + return onGetPseudoDebug(strSetting); + } + } + return std::string(); +} + +// Checked: 2009-10-03 (RLVa-1.0.4e) | Added: RLVa-1.0.4e +std::string RlvExtGetSet::onGetPseudoDebug(const std::string& strSetting) +{ + // Skip sanity checking because it's all done in RlvExtGetSet::onGetDebug() already + if ("AvatarSex" == strSetting) + { + std::map<std::string, std::string>::const_iterator itPseudo = m_PseudoDebug.find(strSetting); + if (itPseudo != m_PseudoDebug.end()) + { + return itPseudo->second; + } + else + { + if (isAgentAvatarValid()) + return llformat("%d", (gAgentAvatarp->getSex() == SEX_MALE)); // [See LLFloaterCustomize::LLFloaterCustomize()] + } + } + return std::string(); +} + +// Checked: 2009-10-10 (RLVa-1.0.4e) | Modified: RLVa-1.0.4e +ERlvCmdRet RlvExtGetSet::onSetDebug(std::string strSetting, const std::string& strValue) +{ + S16 dbgFlags; ERlvCmdRet eRet = RLV_RET_FAILED_UNKNOWN; + if ( (findDebugSetting(strSetting, dbgFlags)) && ((dbgFlags & DBG_WRITE) == DBG_WRITE) ) + { + eRet = RLV_RET_FAILED_OPTION; + if ((dbgFlags & DBG_PSEUDO) == 0) + { + LLControlVariable* pSetting = gSavedSettings.getControl(strSetting); + if (pSetting) + { + U32 u32Value; S32 s32Value; BOOL fValue; + switch (pSetting->type()) + { + case TYPE_U32: + if (LLStringUtil::convertToU32(strValue, u32Value)) + { + gSavedSettings.setU32(strSetting, u32Value); + eRet = RLV_RET_SUCCESS; + } + break; + case TYPE_S32: + if (LLStringUtil::convertToS32(strValue, s32Value)) + { + gSavedSettings.setS32(strSetting, s32Value); + eRet = RLV_RET_SUCCESS; + } + break; + case TYPE_BOOLEAN: + if (LLStringUtil::convertToBOOL(strValue, fValue)) + { + gSavedSettings.setBOOL(strSetting, fValue); + eRet = RLV_RET_SUCCESS; + } + break; + default: + RLV_ERRS << "Unexpected debug setting type" << LL_ENDL; + eRet = RLV_RET_FAILED; + break; + } + + // Default settings should persist if they were marked that way, but non-default settings should never persist + pSetting->setPersist( ((pSetting->isDefault()) && ((dbgFlags & DBG_PERSIST) == DBG_PERSIST)) ? LLControlVariable::PERSIST_NONDFT : LLControlVariable::PERSIST_NO ); + } + } + else + { + eRet = onSetPseudoDebug(strSetting, strValue); + } + } + return eRet; +} + +// Checked: 2009-10-10 (RLVa-1.0.4e) | Modified: RLVa-1.0.4e +ERlvCmdRet RlvExtGetSet::onSetPseudoDebug(const std::string& strSetting, const std::string& strValue) +{ + ERlvCmdRet eRet = RLV_RET_FAILED_OPTION; + if ("AvatarSex" == strSetting) + { + BOOL fValue; + if (LLStringUtil::convertToBOOL(strValue, fValue)) + { + m_PseudoDebug[strSetting] = strValue; + eRet = RLV_RET_SUCCESS; + } + } + return eRet; +} + +// ============================================================================ diff --git a/indra/newview/rlvextensions.h b/indra/newview/rlvextensions.h new file mode 100644 index 0000000000000000000000000000000000000000..08a6d1fca7b1022e53d1fbb3b9ab2ccd642eeeea --- /dev/null +++ b/indra/newview/rlvextensions.h @@ -0,0 +1,57 @@ +/** + * + * Copyright (c) 2009-2011, Kitty Barnett + * + * The source code in this file is provided to you under the terms of the + * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt + * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.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. + * + */ + +#ifndef RLV_EXTENSIONS_H +#define RLV_EXTENSIONS_H + +#include "rlvcommon.h" + +// ============================================================================ +/* + * RlvExtGetSet + * ============ + * Implements @get_XXX:<option>=<channel> and @set_XXX:<option>=force + * + */ + +class RlvExtGetSet : public RlvExtCommandHandler +{ +public: + RlvExtGetSet(); + virtual ~RlvExtGetSet() {} + + virtual bool onForceCommand(const RlvCommand& rlvCmd, ERlvCmdRet& cmdRet); + virtual bool onReplyCommand(const RlvCommand& rlvCmd, ERlvCmdRet& cmdRet); +protected: + std::string onGetDebug(std::string strSetting); + std::string onGetPseudoDebug(const std::string& strSetting); + ERlvCmdRet onSetDebug(std::string strSetting, const std::string& strValue); + ERlvCmdRet onSetPseudoDebug(const std::string& strSetting, const std::string& strValue); + + bool processCommand(const RlvCommand& rlvCmd, ERlvCmdRet& eRet); + +public: + enum { DBG_READ = 0x01, DBG_WRITE = 0x02, DBG_PERSIST = 0x04, DBG_PSEUDO = 0x08 }; + static std::map<std::string, S16> m_DbgAllowed; + static std::map<std::string, std::string> m_PseudoDebug; + + static bool findDebugSetting(/*[in,out]*/ std::string& strSetting, /*[out]*/ S16& flags); + static S16 getDebugSettingFlags(const std::string& strSetting); +}; + +// ============================================================================ + +#endif // RLV_EXTENSIONS_H diff --git a/indra/newview/rlvfloaters.cpp b/indra/newview/rlvfloaters.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4b4303cf2789423ac4c4ed1a8e307c6abc105b1c --- /dev/null +++ b/indra/newview/rlvfloaters.cpp @@ -0,0 +1,818 @@ +/** + * + * Copyright (c) 2009-2011, Kitty Barnett + * + * The source code in this file is provided to you under the terms of the + * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt + * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.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 "llagent.h" +#include "llappearancemgr.h" +#include "llavatarnamecache.h" +#include "llclipboard.h" +#include "llcombobox.h" +#include "llinventoryfunctions.h" +#include "llnotificationsutil.h" +#include "llscrolllistctrl.h" +#include "llsdserialize.h" +#include "lltexteditor.h" +#include "llviewerjointattachment.h" +#include "llviewerobjectlist.h" +#include "llvoavatarself.h" + +#include "rlvfloaters.h" +#include "rlvhelper.h" +#include "rlvhandler.h" +#include "rlvlocks.h" + +// ============================================================================ +// Helper functions +// + +// Checked: 2012-07-14 (RLVa-1.4.7) +std::string rlvGetItemName(const LLViewerInventoryItem* pItem) +{ + if ( (pItem) && ((LLAssetType::AT_BODYPART == pItem->getType()) || (LLAssetType::AT_CLOTHING == pItem->getType())) ) + { + return llformat("%s (%s)", pItem->getName().c_str(), LLWearableType::getTypeName(pItem->getWearableType()).c_str()); + } + else if ( (pItem) && (LLAssetType::AT_OBJECT == pItem->getType()) && (isAgentAvatarValid()) ) + { + std::string strAttachPtName; + gAgentAvatarp->getAttachedPointName(pItem->getUUID(), strAttachPtName); + return llformat("%s (%s)", pItem->getName().c_str(), strAttachPtName.c_str()); + } + return (pItem) ? pItem->getName() : LLStringUtil::null; +} + +// Checked: 2012-07-14 (RLVa-1.4.7) +std::string rlvGetItemType(const LLViewerInventoryItem* pItem) +{ + if (pItem) + { + switch (pItem->getType()) + { + case LLAssetType::AT_BODYPART: + case LLAssetType::AT_CLOTHING: + return "Wearable"; + case LLAssetType::AT_OBJECT: + return "Attachment"; + default: + break; + } + } + return "Unknown"; +} + +std::string rlvGetItemNameFromObjID(const LLUUID& idObj, bool fIncludeAttachPt = true) +{ + const LLViewerObject* pObj = gObjectList.findObject(idObj); + if ( (pObj) && (pObj->isAvatar()) ) + { + LLAvatarName avName; + if (LLAvatarNameCache::get(pObj->getID(), &avName)) + return avName.getCompleteName(); + return ((LLVOAvatar*)pObj)->getFullname(); + } + + const LLViewerObject* pObjRoot = (pObj) ? pObj->getRootEdit() : NULL; + const LLViewerInventoryItem* pItem = ((pObjRoot) && (pObjRoot->isAttachment())) ? gInventory.getItem(pObjRoot->getAttachmentItemID()) : NULL; + + const std::string strItemName = (pItem) ? pItem->getName() : idObj.asString(); + if ( (!fIncludeAttachPt) || (!pObj) || (!pObj->isAttachment()) || (!isAgentAvatarValid()) ) + return strItemName; + + const LLViewerJointAttachment* pAttachPt = get_if_there(gAgentAvatarp->mAttachmentPoints, RlvAttachPtLookup::getAttachPointIndex(pObjRoot), (LLViewerJointAttachment*)NULL); + const std::string strAttachPtName = (pAttachPt) ? pAttachPt->getName() : std::string("Unknown"); + return llformat("%s (%s%s)", strItemName.c_str(), strAttachPtName.c_str(), (pObj == pObjRoot) ? "" : ", child"); +} + +// Checked: 2011-05-23 (RLVa-1.3.0c) | Added: RLVa-1.3.0c +bool rlvGetShowException(ERlvBehaviour eBhvr) +{ + switch (eBhvr) + { + case RLV_BHVR_RECVCHAT: + case RLV_BHVR_RECVEMOTE: + case RLV_BHVR_SENDIM: + case RLV_BHVR_RECVIM: + case RLV_BHVR_STARTIM: + case RLV_BHVR_TPLURE: + case RLV_BHVR_TPREQUEST: + case RLV_BHVR_ACCEPTTP: + case RLV_BHVR_ACCEPTTPREQUEST: + case RLV_BHVR_SHOWNAMES: + case RLV_BHVR_SHOWNAMETAGS: + return true; + default: + return false; + } +} + +// Checked: 2012-07-29 (RLVa-1.4.7) +std::string rlvLockMaskToString(ERlvLockMask eLockType) +{ + switch (eLockType) + { + case RLV_LOCK_ADD: + return "add"; + case RLV_LOCK_REMOVE: + return "rem"; + default: + return "unknown"; + } +} + +// Checked: 2012-07-29 (RLVa-1.4.7) +std::string rlvFolderLockPermissionToString(RlvFolderLocks::ELockPermission eLockPermission) +{ + switch (eLockPermission) + { + case RlvFolderLocks::PERM_ALLOW: + return "allow"; + case RlvFolderLocks::PERM_DENY: + return "deny"; + default: + return "unknown"; + } +} + +// Checked: 2012-07-29 (RLVa-1.4.7) +std::string rlvFolderLockScopeToString(RlvFolderLocks::ELockScope eLockScope) +{ + switch (eLockScope) + { + case RlvFolderLocks::SCOPE_NODE: + return "node"; + case RlvFolderLocks::SCOPE_SUBTREE: + return "subtree"; + default: + return "unknown"; + } +} + +// Checked: 2012-07-29 (RLVa-1.4.7) +std::string rlvFolderLockSourceToTarget(RlvFolderLocks::folderlock_source_t lockSource) +{ + switch (lockSource.first) + { + case RlvFolderLocks::ST_ATTACHMENT: + { + std::string strAttachName = rlvGetItemNameFromObjID(boost::get<LLUUID>(lockSource.second)); + return llformat("Attachment (%s)", strAttachName.c_str()); + } + case RlvFolderLocks::ST_ATTACHMENTPOINT: + { + const LLViewerJointAttachment* pAttachPt = RlvAttachPtLookup::getAttachPoint(boost::get<S32>(lockSource.second)); + return llformat("Attachment point (%s)", (pAttachPt) ? pAttachPt->getName().c_str() : "Unknown"); + } + case RlvFolderLocks::ST_FOLDER: + { + return "Folder: <todo>"; + } + case RlvFolderLocks::ST_ROOTFOLDER: + { + return "Root folder"; + } + case RlvFolderLocks::ST_SHAREDPATH: + { + const std::string& strPath = boost::get<std::string>(lockSource.second); + return llformat("Shared path (#RLV%s%s)", (!strPath.empty()) ? "/" : "", strPath.c_str()); + } + case RlvFolderLocks::ST_WEARABLETYPE: + { + const std::string& strTypeName = LLWearableType::getTypeName(boost::get<LLWearableType::EType>(lockSource.second)); + return llformat("Wearable type (%s)", strTypeName.c_str()); + } + default: + { + return "(Unknown)"; + } + } +} + +// ============================================================================ +// RlvFloaterBehaviours member functions +// + +// Checked: 2010-04-18 (RLVa-1.3.1c) | Modified: RLVa-1.2.0e +void RlvFloaterBehaviours::onOpen(const LLSD& sdKey) +{ + m_ConnRlvCommand = gRlvHandler.setCommandCallback(boost::bind(&RlvFloaterBehaviours::onCommand, this, _1, _2)); + + refreshAll(); +} + +// Checked: 2010-04-18 (RLVa-1.3.1c) | Modified: RLVa-1.2.0e +void RlvFloaterBehaviours::onClose(bool fQuitting) +{ + m_ConnRlvCommand.disconnect(); +} + +// Checked: 2010-04-18 (RLVa-1.3.1c) | Modified: RLVa-1.2.0e +void RlvFloaterBehaviours::onAvatarNameLookup(const LLUUID& idAgent, const LLAvatarName& avName) +{ + uuid_vec_t::iterator itLookup = std::find(m_PendingLookup.begin(), m_PendingLookup.end(), idAgent); + if (itLookup != m_PendingLookup.end()) + m_PendingLookup.erase(itLookup); + if (getVisible()) + refreshAll(); +} + +// Checked: 2011-05-26 (RLVa-1.3.1c) | Added: RLVa-1.3.1c +void RlvFloaterBehaviours::onBtnCopyToClipboard() +{ + std::ostringstream strRestrictions; + + strRestrictions << RlvStrings::getVersion(LLUUID::null) << "\n"; + + const RlvHandler::rlv_object_map_t* pObjects = gRlvHandler.getObjectMap(); + for (RlvHandler::rlv_object_map_t::const_iterator itObj = pObjects->begin(), endObj = pObjects->end(); itObj != endObj; ++itObj) + { + strRestrictions << "\n" << rlvGetItemNameFromObjID(itObj->first) << ":\n"; + + const rlv_command_list_t* pCommands = itObj->second.getCommandList(); + for (rlv_command_list_t::const_iterator itCmd = pCommands->begin(), endCmd = pCommands->end(); itCmd != endCmd; ++itCmd) + { + std::string strOption; LLUUID idOption; + if ( (itCmd->hasOption()) && (idOption.set(itCmd->getOption(), FALSE)) && (idOption.notNull()) ) + { + LLAvatarName avName; + if (gObjectList.findObject(idOption)) + strOption = rlvGetItemNameFromObjID(idOption, true); + else if (LLAvatarNameCache::get(idOption, &avName)) + strOption = (!avName.getAccountName().empty()) ? avName.getAccountName() : avName.getDisplayName(); + else if (!gCacheName->getGroupName(idOption, strOption)) + strOption = itCmd->getOption(); + } + + strRestrictions << " -> " << itCmd->asString(); + if ( (!strOption.empty()) && (strOption != itCmd->getOption()) ) + strRestrictions << " [" << strOption << "]"; + strRestrictions << "\n"; + } + } + + LLWString wstrRestrictions = utf8str_to_wstring(strRestrictions.str()); + LLClipboard::instance().copyToClipboard(wstrRestrictions, 0, wstrRestrictions.length()); +} + +// Checked: 2011-05-23 (RLVa-1.3.1c) | Modified: RLVa-1.3.1c +void RlvFloaterBehaviours::onCommand(const RlvCommand& rlvCmd, ERlvCmdRet eRet) +{ + if ( (RLV_TYPE_ADD == rlvCmd.getParamType()) || (RLV_TYPE_REMOVE == rlvCmd.getParamType()) ) + refreshAll(); +} + +// Checked: 2011-05-23 (RLVa-1.3.1c) | Added: RLVa-1.3.1c +BOOL RlvFloaterBehaviours::postBuild() +{ + getChild<LLUICtrl>("copy_btn")->setCommitCallback(boost::bind(&RlvFloaterBehaviours::onBtnCopyToClipboard, this)); + return TRUE; +} + +void RlvFloaterBehaviours::refreshAll() +{ + LLCtrlListInterface* pBhvrList = childGetListInterface("behaviour_list"); + LLCtrlListInterface* pExceptList = childGetListInterface("exception_list"); + LLCtrlListInterface* pModifierList = childGetListInterface("modifier_list"); + if ( (!pBhvrList) || (!pExceptList) || (!pModifierList) ) + return; + pBhvrList->operateOnAll(LLCtrlListInterface::OP_DELETE); + pExceptList->operateOnAll(LLCtrlListInterface::OP_DELETE); + pModifierList->operateOnAll(LLCtrlListInterface::OP_DELETE); + + if (!isAgentAvatarValid()) + return; + + // + // Set-up a row we can just reuse + // + LLSD sdBhvrRow; LLSD& sdBhvrColumns = sdBhvrRow["columns"]; + sdBhvrColumns[0] = LLSD().with("column", "behaviour").with("type", "text"); + sdBhvrColumns[1] = LLSD().with("column", "issuer").with("type", "text"); + + LLSD sdExceptRow; LLSD& sdExceptColumns = sdExceptRow["columns"]; + sdExceptColumns[0] = LLSD().with("column", "behaviour").with("type", "text"); + sdExceptColumns[1] = LLSD().with("column", "option").with("type", "text"); + sdExceptColumns[2] = LLSD().with("column", "issuer").with("type", "text"); + + LLSD sdModifierRow; LLSD& sdModifierColumns = sdModifierRow["columns"]; + sdModifierColumns[0] = LLSD().with("column", "modifier").with("type", "text"); + sdModifierColumns[1] = LLSD().with("column", "value").with("type", "text"); + sdModifierColumns[2] = LLSD().with("column", "primary").with("type", "text"); + + // + // List behaviours + // + const RlvHandler::rlv_object_map_t* pObjects = gRlvHandler.getObjectMap(); + for (RlvHandler::rlv_object_map_t::const_iterator itObj = pObjects->begin(), endObj = pObjects->end(); itObj != endObj; ++itObj) + { + const std::string strIssuer = rlvGetItemNameFromObjID(itObj->first); + + const rlv_command_list_t* pCommands = itObj->second.getCommandList(); + for (rlv_command_list_t::const_iterator itCmd = pCommands->begin(), endCmd = pCommands->end(); itCmd != endCmd; ++itCmd) + { + std::string strOption; LLUUID idOption; + if ( (itCmd->hasOption()) && (idOption.set(itCmd->getOption(), FALSE)) && (idOption.notNull()) ) + { + LLAvatarName avName; + if (gObjectList.findObject(idOption)) + { + strOption = rlvGetItemNameFromObjID(idOption, true); + } + else if (LLAvatarNameCache::get(idOption, &avName)) + { + strOption = (!avName.getAccountName().empty()) ? avName.getAccountName() : avName.getDisplayName(); + } + else if (!gCacheName->getGroupName(idOption, strOption)) + { + if (m_PendingLookup.end() == std::find(m_PendingLookup.begin(), m_PendingLookup.end(), idOption)) + { + LLAvatarNameCache::get(idOption, boost::bind(&RlvFloaterBehaviours::onAvatarNameLookup, this, _1, _2)); + m_PendingLookup.push_back(idOption); + } + strOption = itCmd->getOption(); + } + } + + if ( (itCmd->hasOption()) && (rlvGetShowException(itCmd->getBehaviourType())) ) + { + // List under the "Exception" tab + sdExceptRow["enabled"] = gRlvHandler.isException(itCmd->getBehaviourType(), idOption); + sdExceptColumns[0]["value"] = itCmd->getBehaviour(); + sdExceptColumns[1]["value"] = strOption; + sdExceptColumns[2]["value"] = strIssuer; + pExceptList->addElement(sdExceptRow, ADD_BOTTOM); + } + else + { + // List under the "Restrictions" tab + sdBhvrColumns[0]["value"] = (strOption.empty()) ? itCmd->asString() : itCmd->getBehaviour() + ":" + strOption; + sdBhvrColumns[1]["value"] = strIssuer; + pBhvrList->addElement(sdBhvrRow, ADD_BOTTOM); + } + } + } + + // + // List modifiers + // + for (int idxModifier = 0; idxModifier < RLV_MODIFIER_COUNT; idxModifier++) + { + const RlvBehaviourModifier* pBhvrModifier = RlvBehaviourDictionary::instance().m_BehaviourModifiers[idxModifier]; + if (pBhvrModifier) + { + sdModifierRow["enabled"] = (pBhvrModifier->hasValue()); + sdModifierColumns[0]["value"] = pBhvrModifier->getName(); + + if (pBhvrModifier->hasValue()) + { + const RlvBehaviourModifierValue& modValue = pBhvrModifier->getValue(); + if (typeid(float) == modValue.type()) + sdModifierColumns[1]["value"] = llformat("%f", boost::get<float>(modValue)); + else if (typeid(int) == modValue.type()) + sdModifierColumns[1]["value"] = llformat("%d", boost::get<int>(modValue)); + } + else + { + sdModifierColumns[1]["value"] = "(default)"; + } + + sdModifierColumns[2]["value"] = (pBhvrModifier->getPrimaryObject().notNull()) ? rlvGetItemNameFromObjID(pBhvrModifier->getPrimaryObject()) : LLStringUtil::null; + pModifierList->addElement(sdModifierRow, ADD_BOTTOM); + } + } +} + +// ============================================================================ +// RlvFloaterLocks member functions +// + +// Checked: 2010-03-11 (RLVa-1.2.0) +void RlvFloaterLocks::onOpen(const LLSD& sdKey) +{ + m_ConnRlvCommand = gRlvHandler.setCommandCallback(boost::bind(&RlvFloaterLocks::onRlvCommand, this, _1, _2)); + + refreshAll(); +} + +// Checked: 2010-03-11 (RLVa-1.2.0) +void RlvFloaterLocks::onClose(bool fQuitting) +{ + m_ConnRlvCommand.disconnect(); +} + +// Checked: 2012-07-14 (RLVa-1.4.7) +BOOL RlvFloaterLocks::postBuild() +{ + getChild<LLUICtrl>("refresh_btn")->setCommitCallback(boost::bind(&RlvFloaterLocks::refreshAll, this)); + + return TRUE; +} + +// Checked: 2010-03-11 (RLVa-1.2.0a) | Added: RLVa-1.2.0a +void RlvFloaterLocks::onRlvCommand(const RlvCommand& rlvCmd, ERlvCmdRet eRet) +{ + // Refresh on any successful @XXX=y|n command where XXX is any of the attachment or wearable locking behaviours + if ( (RLV_RET_SUCCESS == eRet) && ((RLV_TYPE_ADD == rlvCmd.getParamType()) || (RLV_TYPE_REMOVE == rlvCmd.getParamType())) ) + { + switch (rlvCmd.getBehaviourType()) + { + case RLV_BHVR_DETACH: + case RLV_BHVR_ADDATTACH: + case RLV_BHVR_REMATTACH: + case RLV_BHVR_ADDOUTFIT: + case RLV_BHVR_REMOUTFIT: + refreshAll(); + break; + default: + break; + } + } +} + +// Checked: 2010-03-18 (RLVa-1.2.0) +void RlvFloaterLocks::refreshAll() +{ + LLScrollListCtrl* pLockList = getChild<LLScrollListCtrl>("lock_list"); + pLockList->operateOnAll(LLCtrlListInterface::OP_DELETE); + + if (!isAgentAvatarValid()) + return; + + // + // Set-up a row we can just reuse + // + LLSD sdRow; + LLSD& sdColumns = sdRow["columns"]; + sdColumns[0]["column"] = "lock_type"; sdColumns[0]["type"] = "text"; + sdColumns[1]["column"] = "lock_addrem"; sdColumns[1]["type"] = "text"; + sdColumns[2]["column"] = "lock_target"; sdColumns[2]["type"] = "text"; + sdColumns[3]["column"] = "lock_origin"; sdColumns[3]["type"] = "text"; + + // + // List attachment locks + // + sdColumns[0]["value"] = "Attachment"; + sdColumns[1]["value"] = "rem"; + + const RlvAttachmentLocks::rlv_attachobjlock_map_t& attachObjRem = gRlvAttachmentLocks.getAttachObjLocks(); + for (RlvAttachmentLocks::rlv_attachobjlock_map_t::const_iterator itAttachObj = attachObjRem.begin(); + itAttachObj != attachObjRem.end(); ++itAttachObj) + { + sdColumns[2]["value"] = rlvGetItemNameFromObjID(itAttachObj->first); + sdColumns[3]["value"] = rlvGetItemNameFromObjID(itAttachObj->second); + + pLockList->addElement(sdRow, ADD_BOTTOM); + } + + // + // List attachment point locks + // + sdColumns[0]["value"] = "Attachment Point"; + + sdColumns[1]["value"] = "add"; + const RlvAttachmentLocks::rlv_attachptlock_map_t& attachPtAdd = gRlvAttachmentLocks.getAttachPtLocks(RLV_LOCK_ADD); + for (RlvAttachmentLocks::rlv_attachptlock_map_t::const_iterator itAttachPt = attachPtAdd.begin(); + itAttachPt != attachPtAdd.end(); ++itAttachPt) + { + const LLViewerJointAttachment* pAttachPt = + get_if_there(gAgentAvatarp->mAttachmentPoints, itAttachPt->first, (LLViewerJointAttachment*)NULL); + sdColumns[2]["value"] = pAttachPt->getName(); + sdColumns[3]["value"] = rlvGetItemNameFromObjID(itAttachPt->second); + + pLockList->addElement(sdRow, ADD_BOTTOM); + } + + sdColumns[1]["value"] = "rem"; + const RlvAttachmentLocks::rlv_attachptlock_map_t& attachPtRem = gRlvAttachmentLocks.getAttachPtLocks(RLV_LOCK_REMOVE); + for (RlvAttachmentLocks::rlv_attachptlock_map_t::const_iterator itAttachPt = attachPtRem.begin(); + itAttachPt != attachPtRem.end(); ++itAttachPt) + { + const LLViewerJointAttachment* pAttachPt = + get_if_there(gAgentAvatarp->mAttachmentPoints, itAttachPt->first, (LLViewerJointAttachment*)NULL); + sdColumns[2]["value"] = pAttachPt->getName(); + sdColumns[3]["value"] = rlvGetItemNameFromObjID(itAttachPt->second); + + pLockList->addElement(sdRow, ADD_BOTTOM); + } + + // + // List wearable type locks + // + sdColumns[0]["value"] = "Wearable Type"; + + sdColumns[1]["value"] = "add"; + const RlvWearableLocks::rlv_wearabletypelock_map_t& wearableTypeAdd = gRlvWearableLocks.getWearableTypeLocks(RLV_LOCK_ADD); + for (RlvWearableLocks::rlv_wearabletypelock_map_t::const_iterator itWearableType = wearableTypeAdd.begin(); + itWearableType != wearableTypeAdd.end(); ++itWearableType) + { + sdColumns[2]["value"] = LLWearableType::getTypeLabel(itWearableType->first); + sdColumns[3]["value"] = rlvGetItemNameFromObjID(itWearableType->second); + + pLockList->addElement(sdRow, ADD_BOTTOM); + } + + sdColumns[1]["value"] = "rem"; + const RlvWearableLocks::rlv_wearabletypelock_map_t& wearableTypeRem = gRlvWearableLocks.getWearableTypeLocks(RLV_LOCK_REMOVE); + for (RlvWearableLocks::rlv_wearabletypelock_map_t::const_iterator itWearableType = wearableTypeRem.begin(); + itWearableType != wearableTypeRem.end(); ++itWearableType) + { + sdColumns[2]["value"] = LLWearableType::getTypeName(itWearableType->first); + sdColumns[3]["value"] = rlvGetItemNameFromObjID(itWearableType->second); + + pLockList->addElement(sdRow, ADD_BOTTOM); + } + + // + // List "nostrip" (soft) locks + // + sdColumns[1]["value"] = "nostrip"; + sdColumns[3]["value"] = "(Agent)"; + + LLInventoryModel::cat_array_t folders; LLInventoryModel::item_array_t items; + LLFindWearablesEx f(true, true); + gInventory.collectDescendentsIf(LLAppearanceMgr::instance().getCOF(), folders, items, FALSE, f); + + for (LLInventoryModel::item_array_t::const_iterator itItem = items.begin(); itItem != items.end(); ++itItem) + { + const LLViewerInventoryItem* pItem = *itItem; + if (!RlvForceWear::instance().isStrippable(pItem->getUUID())) + { + sdColumns[0]["value"] = rlvGetItemType(pItem); + sdColumns[2]["value"] = rlvGetItemName(pItem); + + pLockList->addElement(sdRow, ADD_BOTTOM); + } + } + + // + // List folder locks + // + { + // Folder lock descriptors + const RlvFolderLocks::folderlock_list_t& folderLocks = RlvFolderLocks::instance().getFolderLocks(); + for (RlvFolderLocks::folderlock_list_t::const_iterator itFolderLock = folderLocks.begin(); + itFolderLock != folderLocks.end(); ++itFolderLock) + { + const RlvFolderLocks::folderlock_descr_t* pLockDescr = *itFolderLock; + if (pLockDescr) + { + sdColumns[0]["value"] = "Folder Descriptor"; + sdColumns[1]["value"] = + rlvLockMaskToString(pLockDescr->eLockType) + "/" + + rlvFolderLockPermissionToString(pLockDescr->eLockPermission) + "/" + + rlvFolderLockScopeToString(pLockDescr->eLockScope); + sdColumns[2]["value"] = rlvFolderLockSourceToTarget(pLockDescr->lockSource); + sdColumns[3]["value"] = rlvGetItemNameFromObjID(pLockDescr->idRlvObj); + + pLockList->addElement(sdRow, ADD_BOTTOM); + } + } + } + + { + // Folder locked attachments and wearables + uuid_vec_t idItems; + const uuid_vec_t& folderLockAttachmentsIds = RlvFolderLocks::instance().getAttachmentLookups(); + idItems.insert(idItems.end(), folderLockAttachmentsIds.begin(), folderLockAttachmentsIds.end()); + const uuid_vec_t& folderLockWearabels = RlvFolderLocks::instance().getWearableLookups(); + idItems.insert(idItems.end(), folderLockWearabels.begin(), folderLockWearabels.end()); + + for (uuid_vec_t::const_iterator itItemId = idItems.begin(); itItemId != idItems.end(); ++itItemId) + { + const LLViewerInventoryItem* pItem = gInventory.getItem(*itItemId); + if (pItem) + { + sdColumns[0]["value"] = rlvGetItemType(pItem); + sdColumns[1]["value"] = rlvLockMaskToString(RLV_LOCK_REMOVE); + sdColumns[2]["value"] = rlvGetItemName(pItem); + sdColumns[3]["value"] = "<Folder Lock>"; + + pLockList->addElement(sdRow, ADD_BOTTOM); + } + } + } +} + +// ============================================================================ +// RlvFloaterStrings member functions +// + +// Checked: 2011-11-08 (RLVa-1.5.0) +RlvFloaterStrings::RlvFloaterStrings(const LLSD& sdKey) + : LLFloater(sdKey) + , m_fDirty(false) + , m_pStringList(NULL) +{ +} + +// Checked: 2011-11-08 (RLVa-1.5.0) +BOOL RlvFloaterStrings::postBuild() +{ + // Set up the UI controls + m_pStringList = findChild<LLComboBox>("string_list"); + m_pStringList->setCommitCallback(boost::bind(&RlvFloaterStrings::checkDirty, this, true)); + + LLUICtrl* pDefaultBtn = findChild<LLUICtrl>("default_btn"); + pDefaultBtn->setCommitCallback(boost::bind(&RlvFloaterStrings::onStringRevertDefault, this)); + + // Read all string metadata from the default strings file + llifstream fileStream(RlvStrings::getStringMapPath().c_str(), std::ios::binary); LLSD sdFileData; + if ( (fileStream.is_open()) && (LLSDSerialize::fromXMLDocument(sdFileData, fileStream)) ) + { + m_sdStringsInfo = sdFileData["strings"]; + fileStream.close(); + } + + // Populate the combo box + for (LLSD::map_const_iterator itString = m_sdStringsInfo.beginMap(); itString != m_sdStringsInfo.endMap(); ++itString) + { + const LLSD& sdStringInfo = itString->second; + if ( (!sdStringInfo.has("customizable")) || (!sdStringInfo["customizable"].asBoolean()) ) + continue; + m_pStringList->add( (sdStringInfo.has("label")) ? sdStringInfo["label"].asString() : itString->first, itString->first); + } + + refresh(); + + return TRUE; +} + +// Checked: 2011-11-08 (RLVa-1.5.0) +void RlvFloaterStrings::onClose(bool fQuitting) +{ + checkDirty(false); + if (m_fDirty) + { + // Save the custom string overrides + RlvStrings::saveToFile(gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, RLV_STRINGS_FILE)); + + // Remind the user their changes require a relog to take effect + LLNotificationsUtil::add("RLVChangeStrings"); + } +} + +// Checked: 2011-11-08 (RLVa-1.5.0) +void RlvFloaterStrings::onStringRevertDefault() +{ + if (!m_strStringCurrent.empty()) + { + RlvStrings::setCustomString(m_strStringCurrent, LLStringUtil::null); + m_fDirty = true; + } + refresh(); +} + +// Checked: 2011-11-08 (RLVa-1.5.0) +void RlvFloaterStrings::checkDirty(bool fRefresh) +{ + LLTextEditor* pStringValue = findChild<LLTextEditor>("string_value"); + if (!pStringValue->isPristine()) + { + RlvStrings::setCustomString(m_strStringCurrent, pStringValue->getText()); + m_fDirty = true; + } + + if (fRefresh) + { + refresh(); + } +} + +// Checked: 2011-11-08 (RLVa-1.5.0) +void RlvFloaterStrings::refresh() +{ + m_strStringCurrent = (-1 != m_pStringList->getCurrentIndex()) ? m_pStringList->getSelectedValue().asString() : LLStringUtil::null; + + LLTextEditor* pStringDescr = findChild<LLTextEditor>("string_descr"); + pStringDescr->clear(); + LLTextEditor* pStringValue = findChild<LLTextEditor>("string_value"); + pStringValue->setEnabled(!m_strStringCurrent.empty()); + pStringValue->clear(); + if (!m_strStringCurrent.empty()) + { + if (m_sdStringsInfo[m_strStringCurrent].has("description")) + pStringDescr->setText(m_sdStringsInfo[m_strStringCurrent]["description"].asString()); + pStringValue->setText(RlvStrings::getString(m_strStringCurrent)); + pStringValue->makePristine(); + } + + findChild<LLUICtrl>("default_btn")->setEnabled(!m_strStringCurrent.empty()); +} + +// ============================================================================ +// RlvFloaterConsole +// + +static const char s_strRlvConsolePrompt[] = "> "; +static const char s_strRlvConsoleDisabled[] = "RLVa is disabled"; +static const char s_strRlvConsoleInvalid[] = "Invalid command"; + +RlvFloaterConsole::RlvFloaterConsole(const LLSD& sdKey) + : LLFloater(sdKey), m_pOutputText(nullptr) +{ +} + +RlvFloaterConsole::~RlvFloaterConsole() +{ +} + +BOOL RlvFloaterConsole::postBuild() +{ + LLLineEditor* pInputEdit = getChild<LLLineEditor>("console_input"); + pInputEdit->setEnableLineHistory(true); + pInputEdit->setCommitCallback(boost::bind(&RlvFloaterConsole::onInput, this, _1, _2)); + pInputEdit->setFocus(true); + pInputEdit->setCommitOnFocusLost(false); + + m_pOutputText = getChild<LLTextEditor>("console_output"); + m_pOutputText->appendText(s_strRlvConsolePrompt, false); + + return TRUE; +} + +void RlvFloaterConsole::onClose(bool fQuitting) +{ + gRlvHandler.processCommand(gAgent.getID(), "clear", true); +} + +void RlvFloaterConsole::addCommandReply(const std::string& strCommand, const std::string& strReply) +{ + m_pOutputText->appendText(llformat("%s: ", strCommand.c_str()), true); + m_pOutputText->appendText(strReply, false); +} + +void RlvFloaterConsole::onInput(LLUICtrl* pCtrl, const LLSD& sdParam) +{ + LLLineEditor* pInputEdit = static_cast<LLLineEditor*>(pCtrl); + std::string strInput = pInputEdit->getText(); + LLStringUtil::trim(strInput); + + m_pOutputText->appendText(strInput, false); + pInputEdit->clear(); + + if (!rlv_handler_t::isEnabled()) + { + m_pOutputText->appendText(s_strRlvConsoleDisabled, true); + } + else if ( (strInput.length() <= 3) || (RLV_CMD_PREFIX != strInput[0]) ) + { + m_pOutputText->appendText(s_strRlvConsoleInvalid, true); + } + else + { + strInput.erase(0, 1); + LLStringUtil::toLower(strInput); + + std::string strExecuted, strFailed, strRetained, *pstr; + + boost_tokenizer tokens(strInput, boost::char_separator<char>(",", "", boost::drop_empty_tokens)); + for (std::string strCmd : tokens) + { + ERlvCmdRet eRet = gRlvHandler.processCommand(gAgent.getID(), strCmd, true); + if ( RLV_RET_SUCCESS == (eRet & RLV_RET_SUCCESS) ) + pstr = &strExecuted; + else if ( RLV_RET_FAILED == (eRet & RLV_RET_FAILED) ) + pstr = &strFailed; + else if (RLV_RET_RETAINED == eRet) + pstr = &strRetained; + else + { + RLV_ASSERT(false); + pstr = &strFailed; + } + + if (const char* pstrSuffix = RlvStrings::getStringFromReturnCode(eRet)) + strCmd.append(" (").append(pstrSuffix).append(")"); + else if (RLV_RET_SUCCESS == (eRet & RLV_RET_SUCCESS)) + strCmd.clear(); // Only show feedback on successful commands when there's an informational notice + + if (!pstr->empty()) + pstr->push_back(','); + pstr->append(strCmd); + } + + if (!strExecuted.empty()) + m_pOutputText->appendText("INFO: @" + strExecuted, true); + if (!strFailed.empty()) + m_pOutputText->appendText("ERR: @" + strFailed, true); + if (!strRetained.empty()) + m_pOutputText->appendText("RET: @" + strRetained, true); + } + + m_pOutputText->appendText(s_strRlvConsolePrompt, true); +} + +// ============================================================================ diff --git a/indra/newview/rlvfloaters.h b/indra/newview/rlvfloaters.h new file mode 100644 index 0000000000000000000000000000000000000000..8238aa68885e6d1b5308c10564a8acfbd9cd44ef --- /dev/null +++ b/indra/newview/rlvfloaters.h @@ -0,0 +1,163 @@ +/** + * + * Copyright (c) 2009-2011, Kitty Barnett + * + * The source code in this file is provided to you under the terms of the + * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt + * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.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. + * + */ + +#ifndef RLV_FLOATERS_H +#define RLV_FLOATERS_H + +#include "llfloater.h" + +#include "rlvdefines.h" +#include "rlvcommon.h" + +// ============================================================================ +// Foward declarations +// +class LLComboBox; +class LLTextEditor; + +// ============================================================================ +// RlvFloaterLocks class declaration +// + +class RlvFloaterBehaviours : public LLFloater +{ + friend class LLFloaterReg; +private: + RlvFloaterBehaviours(const LLSD& sdKey) : LLFloater(sdKey) {} + + /* + * LLFloater overrides + */ +public: + /*virtual*/ void onOpen(const LLSD& sdKey); + /*virtual*/ void onClose(bool fQuitting); + /*virtual*/ BOOL postBuild(); + + /* + * Member functions + */ +protected: + void onAvatarNameLookup(const LLUUID& idAgent, const LLAvatarName& avName); + void onBtnCopyToClipboard(); + void onCommand(const RlvCommand& rlvCmd, ERlvCmdRet eRet); + void refreshAll(); + + /* + * Member variables + */ +protected: + boost::signals2::connection m_ConnRlvCommand; + uuid_vec_t m_PendingLookup; +}; + +// ============================================================================ +// RlvFloaterLocks class declaration +// + +class RlvFloaterLocks : public LLFloater +{ + friend class LLFloaterReg; +private: + RlvFloaterLocks(const LLSD& sdKey) : LLFloater(sdKey) {} + + /* + * LLFloater overrides + */ +public: + /*virtual*/ void onOpen(const LLSD& sdKey); + /*virtual*/ void onClose(bool fQuitting); + /*virtual*/ BOOL postBuild(); + + /* + * Member functions + */ +protected: + void onRlvCommand(const RlvCommand& rlvCmd, ERlvCmdRet eRet); + void refreshAll(); + + /* + * Member variables + */ +protected: + boost::signals2::connection m_ConnRlvCommand; +}; + +// ============================================================================ +// RlvFloaterStrings class declaration +// + +class RlvFloaterStrings : public LLFloater +{ + friend class LLFloaterReg; +private: + RlvFloaterStrings(const LLSD& sdKey); + + // LLFloater overrides +public: + /*virtual*/ void onClose(bool fQuitting); + /*virtual*/ BOOL postBuild(); + + // Member functions +protected: + void onStringRevertDefault(); + void checkDirty(bool fRefresh); + void refresh(); + + // Member variables +protected: + bool m_fDirty; + std::string m_strStringCurrent; + LLComboBox* m_pStringList; + LLSD m_sdStringsInfo; +}; + +// ============================================================================ +// RlvFloaterConsole - debug console to allow command execution without the need for a script +// + +class RlvFloaterConsole : public LLFloater +{ + friend class LLFloaterReg; + template<ERlvParamType> friend struct RlvCommandHandlerBaseImpl; + friend class RlvHandler; +private: + RlvFloaterConsole(const LLSD& sdKey); + ~RlvFloaterConsole() override; + + /* + * LLFloater overrides + */ +public: + BOOL postBuild() override; + void onClose(bool fQuitting) override; + + /* + * Member functions + */ +protected: + void addCommandReply(const std::string& strCommand, const std::string& strReply); + void onInput(LLUICtrl* ctrl, const LLSD& param); + + /* + * Member variables + */ +protected: + LLTextEditor* m_pOutputText; +}; + +// ============================================================================ + +#endif // RLV_FLOATERS_H diff --git a/indra/newview/rlvhandler.cpp b/indra/newview/rlvhandler.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3500252033bffcc9bcfc58eaf6dbbd30902960b8 --- /dev/null +++ b/indra/newview/rlvhandler.cpp @@ -0,0 +1,3162 @@ +/** + * + * Copyright (c) 2009-2016, Kitty Barnett + * + * The source code in this file is provided to you under the terms of the + * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt + * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.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. + * + */ + +// Generic includes +#include "llviewerprecompiledheaders.h" +#include "llagent.h" +#include "llappearancemgr.h" +#include "llappviewer.h" +#include "llgroupactions.h" +#include "llhudtext.h" +#include "llmoveview.h" +#include "llstartup.h" +#include "llviewermessage.h" +#include "llviewermenu.h" +#include "llviewerobjectlist.h" +#include "llviewerparcelmgr.h" +#include "llviewerregion.h" + +// Command specific includes +#include "llagentcamera.h" // @setcam and related +#include "llavatarnamecache.h" // @shownames +#include "llavatarlist.h" // @shownames +#include "llenvmanager.h" // @setenv +#include "llfloatersidepanelcontainer.h"// @shownames +#include "lloutfitslist.h" // @showinv - "Appearance / My Outfits" panel +#include "llpaneloutfitsinventory.h" // @showinv - "Appearance" floater +#include "llpanelpeople.h" // @shownames +#include "llpanelwearing.h" // @showinv - "Appearance / Current Outfit" panel +#include "llsidepanelappearance.h" // @showinv - "Appearance / Edit appearance" panel +#include "lltabcontainer.h" // @showinv - Tab container control for inventory tabs +#include "lltoolmgr.h" // @edit +#include "llviewercamera.h" // @setcam and related +#include "llworldmapmessage.h" // @tpto +#include "llviewertexturelist.h" // @setcam_texture + +// RLVa includes +#include "rlvactions.h" +#include "rlvfloaters.h" +#include "rlvactions.h" +#include "rlvhandler.h" +#include "rlvhelper.h" +#include "rlvinventory.h" +#include "rlvlocks.h" +#include "rlvui.h" +#include "rlvextensions.h" + +// Boost includes +#include <boost/algorithm/string.hpp> + +// ============================================================================ +// Static variable initialization +// + +BOOL RlvHandler::m_fEnabled = FALSE; + +rlv_handler_t gRlvHandler; + +// ============================================================================ +// Command specific helper functions +// + +// Checked: 2009-08-04 (RLVa-1.0.1d) | Added: RLVa-1.0.1d +static bool rlvParseNotifyOption(const std::string& strOption, S32& nChannel, std::string& strFilter) +{ + boost_tokenizer tokens(strOption, boost::char_separator<char>(";", "", boost::keep_empty_tokens)); + boost_tokenizer::const_iterator itTok = tokens.begin(); + + // Extract and sanity check the first token (required) which is the channel + if ( (itTok == tokens.end()) || (!LLStringUtil::convertToS32(*itTok, nChannel)) || (!RlvUtil::isValidReplyChannel(nChannel)) ) + return false; + + // Second token (optional) is the filter + strFilter.clear(); + if (++itTok != tokens.end()) + { + strFilter = *itTok; + ++itTok; + } + + return (itTok == tokens.end()); +} + +// Checked: 2014-02-26 (RLVa-1.4.10) +static bool rlvParseGetStatusOption(const std::string& strOption, std::string& strFilter, std::string& strSeparator) +{ + // @getstatus:[<option>][;<separator>] + // * Parameters: first and second parameters are both optional + // * Examples : @getstatus=123 ; @getstatus:tp=123 ; @getstatus:tp;|=123 ; @getstatus:;|=123 + + boost_tokenizer tokens(strOption, boost::char_separator<char>(";", "", boost::keep_empty_tokens)); + boost_tokenizer::const_iterator itTok = tokens.begin(); + + strSeparator = "/"; + strFilter.clear(); + + // <option> optional parameter (defaults to empty string if unspecified) + if (itTok != tokens.end()) + strFilter = *itTok++; + else + strFilter.clear(); + + // <separator> optional paramter (defaults to '/' if unspecified) + if ( (itTok != tokens.end()) && (!(*itTok).empty()) ) + strSeparator = *itTok++; + else + strSeparator = "/"; + + return true; +} + +// ============================================================================ +// Constructor/destructor +// + +// Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.0.1d +RlvHandler::RlvHandler() : m_fCanCancelTp(true), m_posSitSource(), m_pGCTimer(NULL) +{ + gAgent.addListener(this, "new group"); + + // Array auto-initialization to 0 is still not supported in VS2013 + memset(m_Behaviours, 0, sizeof(S16) * RLV_BHVR_COUNT); +} + +// Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.0.1d +RlvHandler::~RlvHandler() +{ + gAgent.removeListener(this); + + //delete m_pGCTimer; // <- deletes itself +} + +// ============================================================================ +// Behaviour related functions +// + +bool RlvHandler::findBehaviour(ERlvBehaviour eBhvr, std::list<const RlvObject*>& lObjects) const +{ + lObjects.clear(); + for (const auto& objEntry : m_Objects) + if (objEntry.second.hasBehaviour(eBhvr, false)) + lObjects.push_back(&objEntry.second); + return !lObjects.empty(); +} + +bool RlvHandler::hasBehaviour(const LLUUID& idRlvObj, ERlvBehaviour eBhvr, const std::string& strOption) const +{ + rlv_object_map_t::const_iterator itObj = m_Objects.find(idRlvObj); + if (m_Objects.end() != itObj) + return itObj->second.hasBehaviour(eBhvr, strOption, false); + return false; +} + +bool RlvHandler::hasBehaviourExcept(ERlvBehaviour eBhvr, const std::string& strOption, const LLUUID& idObj) const +{ + for (rlv_object_map_t::const_iterator itObj = m_Objects.begin(); itObj != m_Objects.end(); ++itObj) + if ( (idObj != itObj->second.getObjectID()) && (itObj->second.hasBehaviour(eBhvr, strOption, false)) ) + return true; + return false; +} + +// Checked: 2011-04-11 (RLVa-1.3.0h) | Added: RLVa-1.3.0h +bool RlvHandler::hasBehaviourRoot(const LLUUID& idObjRoot, ERlvBehaviour eBhvr, const std::string& strOption) const +{ + for (rlv_object_map_t::const_iterator itObj = m_Objects.begin(); itObj != m_Objects.end(); ++itObj) + if ( (idObjRoot == itObj->second.getRootID()) && (itObj->second.hasBehaviour(eBhvr, strOption, false)) ) + return true; + return false; +} + +// ============================================================================ +// Behaviour exception handling +// + +// Checked: 2009-10-04 (RLVa-1.0.4a) | Modified: RLVa-1.0.4a +void RlvHandler::addException(const LLUUID& idObj, ERlvBehaviour eBhvr, const RlvExceptionOption& varOption) +{ + m_Exceptions.insert(std::pair<ERlvBehaviour, RlvException>(eBhvr, RlvException(idObj, eBhvr, varOption))); +} + +// Checked: 2009-10-04 (RLVa-1.0.4c) | Modified: RLVa-1.0.4c +bool RlvHandler::isException(ERlvBehaviour eBhvr, const RlvExceptionOption& varOption, ERlvExceptionCheck typeCheck) const +{ + // We need to "strict check" exceptions only if: the restriction is actually in place *and* (isPermissive(eBhvr) == FALSE) + if (RLV_CHECK_DEFAULT == typeCheck) + typeCheck = ( (hasBehaviour(eBhvr)) && (!isPermissive(eBhvr)) ) ? RLV_CHECK_STRICT : RLV_CHECK_PERMISSIVE; + + uuid_vec_t objList; + if (RLV_CHECK_STRICT == typeCheck) + { + // If we're "strict checking" then we need the UUID of every object that currently has 'eBhvr' restricted + for (rlv_object_map_t::const_iterator itObj = m_Objects.begin(); itObj != m_Objects.end(); ++itObj) + if (itObj->second.hasBehaviour(eBhvr, !hasBehaviour(RLV_BHVR_PERMISSIVE))) + objList.push_back(itObj->first); + } + + for (rlv_exception_map_t::const_iterator itException = m_Exceptions.lower_bound(eBhvr), + endException = m_Exceptions.upper_bound(eBhvr); itException != endException; ++itException) + { + if (itException->second.varOption == varOption) + { + // For permissive checks we just return on the very first match + if (RLV_CHECK_PERMISSIVE == typeCheck) + return true; + + // For strict checks we don't return until the list is empty (every object with 'eBhvr' restricted also contains the exception) + uuid_vec_t::iterator itList = std::find(objList.begin(), objList.end(), itException->second.idObject); + if (itList != objList.end()) + objList.erase(itList); + if (objList.empty()) + return true; + } + } + return false; +} + +// Checked: 2009-10-04 (RLVa-1.0.4a) | Modified: RLVa-1.0.4a +bool RlvHandler::isPermissive(ERlvBehaviour eBhvr) const +{ + return (RlvBehaviourDictionary::instance().getHasStrict(eBhvr)) + ? !((hasBehaviour(RLV_BHVR_PERMISSIVE)) || (isException(RLV_BHVR_PERMISSIVE, eBhvr, RLV_CHECK_PERMISSIVE))) + : true; +} + +// Checked: 2009-10-04 (RLVa-1.0.4a) | Modified: RLVa-1.0.4a +void RlvHandler::removeException(const LLUUID& idObj, ERlvBehaviour eBhvr, const RlvExceptionOption& varOption) +{ + for (rlv_exception_map_t::iterator itException = m_Exceptions.lower_bound(eBhvr), + endException = m_Exceptions.upper_bound(eBhvr); itException != endException; ++itException) + { + if ( (itException->second.idObject == idObj) && (itException->second.varOption == varOption) ) + { + m_Exceptions.erase(itException); + break; + } + } +} + +// ============================================================================ +// Command processing functions +// + +// Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.1.0f +void RlvHandler::addCommandHandler(RlvExtCommandHandler* pCmdHandler) +{ + if ( (pCmdHandler) && (std::find(m_CommandHandlers.begin(), m_CommandHandlers.end(), pCmdHandler) == m_CommandHandlers.end()) ) + m_CommandHandlers.push_back(pCmdHandler); +} + +// Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.1.0f +void RlvHandler::removeCommandHandler(RlvExtCommandHandler* pCmdHandler) +{ + if (pCmdHandler) + m_CommandHandlers.remove(pCmdHandler); +} + +// Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.1.0a +void RlvHandler::clearCommandHandlers() +{ + std::list<RlvExtCommandHandler*>::const_iterator itHandler = m_CommandHandlers.begin(); + while (itHandler != m_CommandHandlers.end()) + { + delete *itHandler; + ++itHandler; + } + m_CommandHandlers.clear(); +} + +// Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.1.0f +bool RlvHandler::notifyCommandHandlers(rlvExtCommandHandler f, const RlvCommand& rlvCmd, ERlvCmdRet& eRet, bool fNotifyAll) const +{ + std::list<RlvExtCommandHandler*>::const_iterator itHandler = m_CommandHandlers.begin(); bool fContinue = true; eRet = RLV_RET_UNKNOWN; + while ( (itHandler != m_CommandHandlers.end()) && ((fContinue) || (fNotifyAll)) ) + { + ERlvCmdRet eCmdRet = RLV_RET_UNKNOWN; + if ((fContinue = !((*itHandler)->*f)(rlvCmd, eCmdRet)) == false) + eRet = eCmdRet; + ++itHandler; + } + RLV_ASSERT( (fContinue) || (eRet != RLV_RET_UNKNOWN) ); + return !fContinue; +} + +// Checked: 2009-11-25 (RLVa-1.1.0f) | Modified: RLVa-1.1.0f +ERlvCmdRet RlvHandler::processCommand(const RlvCommand& rlvCmd, bool fFromObj) +{ + RLV_DEBUGS << "[" << rlvCmd.getObjectID() << "]: " << rlvCmd.asString() << RLV_ENDL; + + if (!rlvCmd.isValid()) + { + RLV_DEBUGS << "\t-> invalid syntax" << RLV_ENDL; + return RLV_RET_FAILED_SYNTAX; + } + if (rlvCmd.isBlocked()) + { + RLV_DEBUGS << "\t-> blocked command" << RLV_ENDL; + return RLV_RET_FAILED_DISABLED; + } + + // Using a stack for executing commands solves a few problems: + // - if we passed RlvObject::m_idObj for idObj somewhere and process a @clear then idObj points to invalid/cleared memory at the end + // - if command X triggers command Y along the way then getCurrentCommand()/getCurrentObject() still return Y even when finished + m_CurCommandStack.push(&rlvCmd); m_CurObjectStack.push(rlvCmd.getObjectID()); + const LLUUID& idCurObj = m_CurObjectStack.top(); + + ERlvCmdRet eRet = RLV_RET_UNKNOWN; + switch (rlvCmd.getParamType()) + { + case RLV_TYPE_ADD: // Checked: 2009-11-26 (RLVa-1.1.0f) | Modified: RLVa-1.1.0f + { + if ( (m_Behaviours[rlvCmd.getBehaviourType()]) && + ( (RLV_BHVR_SETCAM == rlvCmd.getBehaviourType()) || (RLV_BHVR_SETDEBUG == rlvCmd.getBehaviourType()) || (RLV_BHVR_SETENV == rlvCmd.getBehaviourType()) ) ) + { + // Some restrictions can only be held by one single object to avoid deadlocks + RLV_DEBUGS << "\t- " << rlvCmd.getBehaviour() << " is already set by another object => discarding" << RLV_ENDL; + eRet = RLV_RET_FAILED_LOCK; + break; + } + + rlv_object_map_t::iterator itObj = m_Objects.find(idCurObj); bool fAdded = false; + if (itObj != m_Objects.end()) + { + RlvObject& rlvObj = itObj->second; + fAdded = rlvObj.addCommand(rlvCmd); + } + else + { + RlvObject rlvObj(idCurObj); + fAdded = rlvObj.addCommand(rlvCmd); + itObj = m_Objects.insert(std::pair<LLUUID, RlvObject>(idCurObj, rlvObj)).first; + } + + RLV_DEBUGS << "\t- " << ( (fAdded) ? "adding behaviour" : "skipping duplicate" ) << RLV_ENDL; + + if (fAdded) { // If FALSE then this was a duplicate, there's no need to handle those + if (!m_pGCTimer) + m_pGCTimer = new RlvGCTimer(); + eRet = processAddRemCommand(rlvCmd); + if (!RLV_RET_SUCCEEDED(eRet)) + { + RlvCommand rlvCmdRem(rlvCmd, RLV_TYPE_REMOVE); + itObj->second.removeCommand(rlvCmdRem); + } +// notifyBehaviourObservers(rlvCmd, !fFromObj); + } + else + { + eRet = RLV_RET_SUCCESS_DUPLICATE; + } + } + break; + case RLV_TYPE_REMOVE: // Checked: 2009-11-26 (RLVa-1.1.0f) | Modified: RLVa-1.1.0f + { + rlv_object_map_t::iterator itObj = m_Objects.find(idCurObj); bool fRemoved = false; + if (itObj != m_Objects.end()) + fRemoved = itObj->second.removeCommand(rlvCmd); + + RLV_DEBUGS << "\t- " << ( (fRemoved) ? "removing behaviour" + : "skipping remove (unset behaviour or unknown object)") << RLV_ENDL; + + if (fRemoved) { // Don't handle non-sensical removes + eRet = processAddRemCommand(rlvCmd); +// notifyBehaviourObservers(rlvCmd, !fFromObj); + + if (0 == itObj->second.m_Commands.size()) + { + RLV_DEBUGS << "\t- command list empty => removing " << idCurObj << RLV_ENDL; + m_Objects.erase(itObj); + } + } + else + { + eRet = RLV_RET_SUCCESS_UNSET; + } + } + break; + case RLV_TYPE_CLEAR: // Checked: 2009-11-25 (RLVa-1.1.0f) | Modified: RLVa-1.1.0f + eRet = processClearCommand(rlvCmd); + break; + case RLV_TYPE_FORCE: // Checked: 2009-11-26 (RLVa-1.1.0f) | Modified: RLVa-1.1.0f + eRet = processForceCommand(rlvCmd); + break; + case RLV_TYPE_REPLY: // Checked: 2009-11-25 (RLVa-1.1.0f) | Modified: RLVa-1.1.0f + eRet = processReplyCommand(rlvCmd); + break; + case RLV_TYPE_UNKNOWN: // Checked: 2009-11-25 (RLVa-1.1.0f) | Modified: RLVa-1.1.0f + default: + eRet = RLV_RET_FAILED_PARAM; + break; + } + RLV_ASSERT(RLV_RET_UNKNOWN != eRet); + + m_OnCommand(rlvCmd, eRet, !fFromObj); + + RLV_DEBUGS << "\t--> command " << ((eRet & RLV_RET_SUCCESS) ? "succeeded" : "failed") << RLV_ENDL; + + m_CurCommandStack.pop(); m_CurObjectStack.pop(); + return eRet; +} + +// Checked: 2009-11-25 (RLVa-1.1.0f) | Modified: RLVa-1.1.0f +ERlvCmdRet RlvHandler::processCommand(const LLUUID& idObj, const std::string& strCommand, bool fFromObj) +{ + if (STATE_STARTED != LLStartUp::getStartupState()) + { + m_Retained.push_back(RlvCommand(idObj, strCommand)); + return RLV_RET_RETAINED; + } + return processCommand(RlvCommand(idObj, strCommand), fFromObj); +} + +// Checked: 2010-02-27 (RLVa-1.2.0a) | Modified: RLVa-1.1.0f +void RlvHandler::processRetainedCommands(ERlvBehaviour eBhvrFilter /*=RLV_BHVR_UNKNOWN*/, ERlvParamType eTypeFilter /*=RLV_TYPE_UNKNOWN*/) +{ + rlv_command_list_t::iterator itCmd = m_Retained.begin(), itCurCmd; + while (itCmd != m_Retained.end()) + { + itCurCmd = itCmd++; // Point the loop iterator ahead + + const RlvCommand& rlvCmd = *itCurCmd; + if ( ((RLV_BHVR_UNKNOWN == eBhvrFilter) || (rlvCmd.getBehaviourType() == eBhvrFilter)) && + ((RLV_TYPE_UNKNOWN == eTypeFilter) || (rlvCmd.getParamType() == eTypeFilter)) ) + { + processCommand(rlvCmd, true); + m_Retained.erase(itCurCmd); + } + } +} + +ERlvCmdRet RlvHandler::processClearCommand(const RlvCommand& rlvCmd) +{ + const std::string& strFilter = rlvCmd.getParam(); std::string strCmdRem; + + rlv_object_map_t::const_iterator itObj = m_Objects.find(rlvCmd.getObjectID()); + if (itObj != m_Objects.end()) // No sense in clearing if we don't have any commands for this object + { + const RlvObject& rlvObj = itObj->second; bool fContinue = true; + for (rlv_command_list_t::const_iterator itCmd = rlvObj.m_Commands.begin(), itCurCmd; + ((fContinue) && (itCmd != rlvObj.m_Commands.end())); ) + { + itCurCmd = itCmd++; // Point itCmd ahead so it won't get invalidated if/when we erase a command + + const RlvCommand& rlvCmdRem = *itCurCmd; strCmdRem = rlvCmdRem.asString(); + if ( (strFilter.empty()) || (std::string::npos != strCmdRem.find(strFilter)) ) + { + fContinue = (rlvObj.m_Commands.size() > 1); // rlvObj will become invalid once we remove the last command + processCommand(rlvCmd.getObjectID(), strCmdRem.append("=y"), false); + } + } + } + + // Let our observers know about clear commands + ERlvCmdRet eRet = RLV_RET_SUCCESS; + notifyCommandHandlers(&RlvExtCommandHandler::onClearCommand, rlvCmd, eRet, true); + + return RLV_RET_SUCCESS; // Don't fail clear commands even if the object didn't exist since it confuses people +} + +// ============================================================================ +// Externally invoked event handlers +// + +bool RlvHandler::handleEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& sdUserdata) +{ + // NOTE: we'll fire once for every group the user belongs to so we need to manually keep track of pending changes + static LLUUID s_idLastAgentGroup = LLUUID::null; + static bool s_fGroupChanging = false; + + if (s_idLastAgentGroup != gAgent.getGroupID()) + { + s_idLastAgentGroup = gAgent.getGroupID(); + s_fGroupChanging = false; + } + + // If the user managed to change their active group (= newly joined or created group) we need to reactivate the previous one + if ( (!RlvActions::canChangeActiveGroup()) && ("new group" == event->desc()) && (m_idAgentGroup != gAgent.getGroupID()) ) + { + // Make sure they still belong to the group + if ( (m_idAgentGroup.notNull()) && (!gAgent.isInGroup(m_idAgentGroup)) ) + { + m_idAgentGroup.setNull(); + s_fGroupChanging = false; + } + + if (!s_fGroupChanging) + { + RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_GROUPCHANGE, LLSD().with("GROUP_SLURL", (m_idAgentGroup.notNull()) ? llformat("secondlife:///app/group/%s/about", m_idAgentGroup.asString()) : "(none)")); + + // [Copy/paste from LLGroupActions::activate()] + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_ActivateGroup); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addUUIDFast(_PREHASH_GroupID, m_idAgentGroup); + gAgent.sendReliableMessage(); + s_fGroupChanging = true; + return true; + } + } + else + { + m_idAgentGroup = gAgent.getGroupID(); + } + return false; +} + +// Checked: 2010-08-29 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c +void RlvHandler::onSitOrStand(bool fSitting) +{ + if (rlv_handler_t::isEnabled()) + { + RlvSettings::updateLoginLastLocation(); + } + + if ( (hasBehaviour(RLV_BHVR_STANDTP)) && (!fSitting) && (!m_posSitSource.isExactlyZero()) ) + { + // NOTE: we need to do this due to the way @standtp triggers a forced teleport: + // - when standing we're called from LLVOAvatar::sitDown() which is called from LLVOAvatar::getOffObject() + // -> at the time sitDown() is called the avatar's parent is still the linkset it was sitting on so "isRoot()" on the avatar will + // return FALSE and we will crash in LLVOAvatar::getRenderPosition() when trying to teleport + // -> postponing the teleport until the next idle tick will ensure that everything has all been properly cleaned up + doOnIdleOneTime(boost::bind(RlvUtil::forceTp, m_posSitSource)); + m_posSitSource.setZero(); + } +} + +// Checked: 2010-03-11 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a +void RlvHandler::onAttach(const LLViewerObject* pAttachObj, const LLViewerJointAttachment* pAttachPt) +{ + // Assertion - pAttachObj is never NULL always specifies the root + RLV_ASSERT( (pAttachObj) && (pAttachObj == pAttachObj->getRootEdit()) ); + // Sanity check - we need to be called *after* LLViewerJointAttachment::addObject() + RLV_ASSERT( (pAttachPt) && (pAttachPt->isObjectAttached(pAttachObj)) ); + if ( (!pAttachObj) || (!pAttachPt) || (!pAttachPt->isObjectAttached(pAttachObj)) ) + return; + + // Check if we already have an RlvObject instance for this object or one of its child prims + for (rlv_object_map_t::iterator itObj = m_Objects.begin(); itObj != m_Objects.end(); ++itObj) + { + // Only if we haven't been able to find this object (= attachment that rezzed in) or if it's a rezzed prim attached from in-world + if ( (!itObj->second.m_fLookup) || (!itObj->second.m_idxAttachPt) ) + { + const LLViewerObject* pObj = gObjectList.findObject(itObj->first); + if ( (pObj) && (pObj->getRootEdit()->getID() == pAttachObj->getID()) ) + { + // Reset any lookup information we might have for this object + itObj->second.m_fLookup = true; + itObj->second.m_idxAttachPt = RlvAttachPtLookup::getAttachPointIndex(pAttachObj); + itObj->second.m_idRoot = pAttachObj->getID(); + + // We need to check this object for an active "@detach=n" and actually lock it down now that it's been attached somewhere + if (itObj->second.hasBehaviour(RLV_BHVR_DETACH, false)) + gRlvAttachmentLocks.addAttachmentLock(pAttachObj->getID(), itObj->second.getObjectID()); + } + } + } + + // Fetch the inventory item if it isn't already (we need it in case of a reattach-on-detach) and rename it if appropriate + if ( (STATE_STARTED == LLStartUp::getStartupState()) && (gInventory.isInventoryUsable()) ) + { + RlvRenameOnWearObserver* pFetcher = new RlvRenameOnWearObserver(pAttachObj->getAttachmentItemID()); + pFetcher->startFetch(); + if (pFetcher->isFinished()) + pFetcher->done(); + else + gInventory.addObserver(pFetcher); + } +} + +// Checked: 2010-03-11 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a +void RlvHandler::onDetach(const LLViewerObject* pAttachObj, const LLViewerJointAttachment* pAttachPt) +{ + // Assertion - pAttachObj is never NULL always specifies the root + RLV_ASSERT( (pAttachObj) && (pAttachObj == pAttachObj->getRootEdit()) ); + // Sanity check - we need to be called *before* LLViewerJointAttachment::removeObject() + RLV_ASSERT( (pAttachPt) && (pAttachPt->isObjectAttached(pAttachObj)) ); + if ( (!pAttachObj) || (!pAttachPt) || (!pAttachPt->isObjectAttached(pAttachObj)) ) + return; + + // If the attachment is no longer attached then then the user "Drop"'ed this attachment somehow + if (!pAttachObj->isAttachment()) + { + // Check if we have any RlvObject instances for this object (or any of its child prims) + for (rlv_object_map_t::iterator itObj = m_Objects.begin(); itObj != m_Objects.end(); ++itObj) + { + if ( (itObj->second.m_fLookup) && (itObj->second.m_idRoot == pAttachObj->getID()) ) + { + // Clear the attachment point lookup since it's now an in-world prim + itObj->second.m_idxAttachPt = false; + + // If this object has an active "@detach=n" then we need to release the attachment lock since it's no longer attached + if (itObj->second.hasBehaviour(RLV_BHVR_DETACH, false)) + gRlvAttachmentLocks.removeAttachmentLock(pAttachObj->getID(), itObj->second.getObjectID()); + } + } + } + else + { + // If it's still attached then we need to clean up any restrictions this object (or one of its child prims) may still have set + rlv_object_map_t::iterator itObj = m_Objects.begin(), itCurObj; + while (itObj != m_Objects.end()) + { + itCurObj = itObj++; // @clear will invalidate our iterator so point it ahead now +#ifdef RLV_DEBUG + bool itObj = true; + RLV_ASSERT(itObj); // Little hack to push itObj out of scope and prevent it from being accidentally used below +#endif // RLV_DEBUG + + // NOTE: ObjectKill seems to happen in reverse (child prims are killed before the root is) so we can't use gObjectList here + if (itCurObj->second.m_idRoot == pAttachObj->getID()) + { + RLV_INFOS << "Clearing " << itCurObj->first.asString() << ":" << RLV_ENDL; + processCommand(itCurObj->second.getObjectID(), "clear", true); + RLV_INFOS << "\t-> done" << RLV_ENDL; + } + } + } +} + +// Checked: 2010-03-13 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a +bool RlvHandler::onGC() +{ + rlv_object_map_t::iterator itObj = m_Objects.begin(), itCurObj; + while (itObj != m_Objects.end()) + { + itCurObj = itObj++; // @clear will invalidate our iterator so point it ahead now +#ifdef RLV_DEBUG + bool itObj = true; + RLV_ASSERT(itObj); +#endif // RLV_DEBUG + + // Temporary sanity check + RLV_ASSERT(itCurObj->first == itCurObj->second.getObjectID()); + + const LLViewerObject* pObj = gObjectList.findObject(itCurObj->second.getObjectID()); + if (!pObj) + { + // If the RlvObject once existed in gObjectList and now doesn't then expire it right away + // If the RlvObject never existed in gObjectList and still doesn't then increase its "lookup misses" counter + // but if that reaches 20 (we run every 30 seconds so that's about 10 minutes) then we'll expire it too + if ( (itCurObj->second.m_fLookup) || (++itCurObj->second.m_nLookupMisses > 20) ) + { + RLV_INFOS << "Garbage collecting " << itCurObj->first.asString() << ":" << RLV_ENDL; + processCommand(itCurObj->first, "clear", true); + RLV_INFOS << "\t-> done" << RLV_ENDL; + } + } + else + { + // Assertion: if the GC encounters an RlvObject instance that hasn't existed in gObjectList up until now then + // it has to be a rezzed prim (if it was an attachment then RlvHandler::onAttach() should have caught it) + RLV_ASSERT( (itCurObj->second.m_fLookup) || (!pObj->isAttachment()) ); + if (!itCurObj->second.m_fLookup) + { + RLV_INFOS << "Resolved missing object " << itCurObj->first.asString() << RLV_ENDL; + itCurObj->second.m_fLookup = true; + itCurObj->second.m_idxAttachPt = RlvAttachPtLookup::getAttachPointIndex(pObj); + itCurObj->second.m_idRoot = pObj->getRootEdit()->getID(); + + // NOTE: the following code should NEVER run (see assertion above), but just to be double-triple safety sure + // -> if it does run it likely means that there's a @detach=n in a *child* prim that we couldn't look up in onAttach() + // -> since RLV doesn't currently support @detach=n from child prims it's actually not such a big deal right now but still + if ( (pObj->isAttachment()) && (itCurObj->second.hasBehaviour(RLV_BHVR_DETACH, false)) ) + gRlvAttachmentLocks.addAttachmentLock(pObj->getID(), itCurObj->second.getObjectID()); + } + } + } + + RLV_ASSERT(gRlvAttachmentLocks.verifyAttachmentLocks()); // Verify that we haven't leaked any attachment locks somehow + + return (0 != m_Objects.size()); // GC will kill itself if it has nothing to do +} + +// Checked: 2009-11-26 (RLVa-1.1.0f) | Added: RLVa-1.1.0f +void RlvHandler::onIdleStartup(void* pParam) +{ + LLTimer* pTimer = (LLTimer*)pParam; + if (LLStartUp::getStartupState() < STATE_STARTED) + { + // We don't want to run this *too* often + if ( (LLStartUp::getStartupState() >= STATE_MISC) && (pTimer->getElapsedTimeF32() >= 2.0) ) + { + gRlvHandler.processRetainedCommands(RLV_BHVR_VERSION, RLV_TYPE_REPLY); + gRlvHandler.processRetainedCommands(RLV_BHVR_VERSIONNEW, RLV_TYPE_REPLY); + gRlvHandler.processRetainedCommands(RLV_BHVR_VERSIONNUM, RLV_TYPE_REPLY); + pTimer->reset(); + } + } + else + { + // Clean-up + gIdleCallbacks.deleteFunction(onIdleStartup, pParam); + delete pTimer; + } +} + +// Checked: 2010-03-09 (RLVa-1.2.0a) | Added: RLVa-1.2.0a +void RlvHandler::onLoginComplete() +{ + RlvInventory::instance().fetchWornItems(); + RlvInventory::instance().fetchSharedInventory(); + RlvSettings::updateLoginLastLocation(); + + LLViewerParcelMgr::getInstance()->setTeleportFailedCallback(boost::bind(&RlvHandler::onTeleportFailed, this)); + LLViewerParcelMgr::getInstance()->setTeleportFinishedCallback(boost::bind(&RlvHandler::onTeleportFinished, this, _1)); + + processRetainedCommands(); +} + +// Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d +void RlvHandler::onTeleportFailed() +{ + setCanCancelTp(true); +} + +// Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d +void RlvHandler::onTeleportFinished(const LLVector3d& posArrival) +{ + setCanCancelTp(true); +} + +// ============================================================================ +// String/chat censoring functions +// + +// Checked: 2010-04-11 (RLVa-1.3.0h) | Modified: RLVa-1.3.0h +bool RlvHandler::canTouch(const LLViewerObject* pObj, const LLVector3& posOffset /*=LLVector3::zero*/) const +{ + const LLUUID& idRoot = (pObj) ? pObj->getRootEdit()->getID() : LLUUID::null; + bool fCanTouch = (idRoot.notNull()) && ((pObj->isHUDAttachment()) || (!hasBehaviour(RLV_BHVR_TOUCHALL))) && + ((!hasBehaviour(RLV_BHVR_TOUCHTHIS)) || (!isException(RLV_BHVR_TOUCHTHIS, idRoot, RLV_CHECK_PERMISSIVE))); + + static RlvCachedBehaviourModifier<float> s_nFartouchDist(RLV_MODIFIER_FARTOUCHDIST); + if (fCanTouch) + { + if ( (!pObj->isAttachment()) || (!pObj->permYouOwner()) ) + { + // User can touch an object (that's isn't one of their own attachments) if: + // - it's an in-world object and they're not prevented from touching it (or the object is an exception) + // - it's an attachment and they're not prevented from touching (another avatar's) attachments (or the attachment is an exception) + // - not fartouch restricted (or the object is within the currently enforced fartouch distance) + fCanTouch = + ( (!pObj->isAttachment()) ? (!hasBehaviour(RLV_BHVR_TOUCHWORLD)) || (isException(RLV_BHVR_TOUCHWORLD, idRoot, RLV_CHECK_PERMISSIVE)) + : ((!hasBehaviour(RLV_BHVR_TOUCHATTACH)) && (!hasBehaviour(RLV_BHVR_TOUCHATTACHOTHER))) || (isException(RLV_BHVR_TOUCHATTACH, idRoot, RLV_CHECK_PERMISSIVE)) ) && + ( (!hasBehaviour(RLV_BHVR_FARTOUCH)) || (dist_vec_squared(gAgent.getPositionGlobal(), pObj->getPositionGlobal() + LLVector3d(posOffset)) <= s_nFartouchDist * s_nFartouchDist) ); + } + else if (!pObj->isHUDAttachment()) + { + // Regular attachment worn by this avie + fCanTouch = + ((!hasBehaviour(RLV_BHVR_TOUCHATTACH)) || (isException(RLV_BHVR_TOUCHATTACH, idRoot, RLV_CHECK_PERMISSIVE))) && + ((!hasBehaviour(RLV_BHVR_TOUCHATTACHSELF)) || (isException(RLV_BHVR_TOUCHATTACH, idRoot, RLV_CHECK_PERMISSIVE))); + } + else + { + // HUD attachment + fCanTouch = (!hasBehaviour(RLV_BHVR_TOUCHHUD)) || (isException(RLV_BHVR_TOUCHHUD, idRoot, RLV_CHECK_PERMISSIVE)); + } + } + if ( (!fCanTouch) && (hasBehaviour(RLV_BHVR_TOUCHME)) ) + fCanTouch = hasBehaviourRoot(idRoot, RLV_BHVR_TOUCHME); + return fCanTouch; +} + +size_t utf8str_strlen(const std::string& utf8) +{ + const char* pUTF8 = utf8.c_str(); size_t length = 0; + for (int idx = 0, cnt = utf8.length(); idx < cnt ;idx++) + { + // We're looking for characters that don't start with 10 as their high bits + if ((pUTF8[idx] & 0xC0) != 0x80) + length++; + } + return length; +} + +std::string utf8str_chtruncate(const std::string& utf8, size_t length) +{ + if (0 == length) + return std::string(); + if (utf8.length() <= length) + return utf8; + + const char* pUTF8 = utf8.c_str(); int idx = 0; + while ( (pUTF8[idx]) && (length > 0) ) + { + // We're looking for characters that don't start with 10 as their high bits + if ((pUTF8[idx] & 0xC0) != 0x80) + length--; + idx++; + } + + return utf8.substr(0, idx); +} + +// Checked: 2010-03-26 (RLVa-1.2.0b) | Modified: RLVa-1.0.0f +bool RlvHandler::filterChat(std::string& strUTF8Text, bool fFilterEmote) const +{ + if (strUTF8Text.empty()) + return false; + + bool fFilter = false; + if (RlvUtil::isEmote(strUTF8Text)) // Check if it's an emote + { + if (fFilterEmote) // Emote filtering depends on fFilterEmote + { + if ( (strUTF8Text.find_first_of("\"()*=^_?~") != std::string::npos) || + (strUTF8Text.find(" -") != std::string::npos) || (strUTF8Text.find("- ") != std::string::npos) || + (strUTF8Text.find("''") != std::string::npos) ) + { + fFilter = true; // Emote contains illegal character (or character sequence) + } + else if (!hasBehaviour(RLV_BHVR_EMOTE)) + { + int idx = strUTF8Text.find('.'); // Truncate at 20 characters or at the dot (whichever is shorter) + strUTF8Text = utf8str_chtruncate(strUTF8Text, ( (idx > 0) && (idx < 20) ) ? idx + 1 : 20); + } + } + } + else if (strUTF8Text[0] == '/') // Not an emote, but starts with a '/' + { + fFilter = (utf8str_strlen(strUTF8Text) > 7);// Allow as long if it's 6 characters or less + } + else if ( (!RlvSettings::getCanOOC()) || + (strUTF8Text.length() < 4) || (strUTF8Text.compare(0, 2, "((")) || (strUTF8Text.compare(strUTF8Text.length() - 2, 2, "))")) ) + { + fFilter = true; // Regular chat (not OOC) + } + + if (fFilter) + strUTF8Text = (gSavedSettings.getBOOL("RestrainedLoveShowEllipsis")) ? "..." : ""; + return fFilter; +} + +// Checked: 2010-11-29 (RLVa-1.3.0c) | Added: RLVa-1.3.0c +bool RlvHandler::hasException(ERlvBehaviour eBhvr) const +{ + return (m_Exceptions.find(eBhvr) != m_Exceptions.end()); +} + +// Checked: 2010-02-27 (RLVa-1.2.0b) | Modified: RLVa-1.2.0a +bool RlvHandler::redirectChatOrEmote(const std::string& strUTF8Text) const +{ + // Sanity check - @redirchat only for chat and @rediremote only for emotes + ERlvBehaviour eBhvr = (!RlvUtil::isEmote(strUTF8Text)) ? RLV_BHVR_REDIRCHAT : RLV_BHVR_REDIREMOTE; + if ( (strUTF8Text.empty()) || (!hasBehaviour(eBhvr)) ) + return false; + + if (RLV_BHVR_REDIRCHAT == eBhvr) + { + std::string strText = strUTF8Text; + if (!filterChat(strText, false)) + return false; // @sendchat wouldn't filter it so @redirchat won't redirect it either + } + + for (rlv_exception_map_t::const_iterator itRedir = m_Exceptions.lower_bound(eBhvr), + endRedir = m_Exceptions.upper_bound(eBhvr); itRedir != endRedir; ++itRedir) + { + S32 nChannel = boost::get<S32>(itRedir->second.varOption); + if (RlvActions::canSendChannel(nChannel)) + RlvUtil::sendChatReply(nChannel, strUTF8Text); + } + + return true; +} + +// ============================================================================ +// Composite folders +// + +#ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS + // Checked: 2009-12-18 (RLVa-1.1.0k) | Modified: RLVa-1.1.0i + bool RlvHandler::getCompositeInfo(const LLInventoryCategory* pFolder, std::string* pstrName) const + { + if (pFolder) + { + // Composite folder naming: ^\.?[Folder] + const std::string& cstrFolder = pFolder->getName(); + std::string::size_type idxStart = cstrFolder.find('['), idxEnd = cstrFolder.find(']', idxStart); + if ( ((0 == idxStart) || (1 == idxStart)) && (idxEnd - idxStart > 1) ) + { + if (pstrName) + pstrName->assign(cstrFolder.substr(idxStart + 1, idxEnd - idxStart - 1)); + return true; + } + } + return false; + } + + // Checked: 2009-12-18 (RLVa-1.1.0k) | Modified: RLVa-1.1.0i + bool RlvHandler::getCompositeInfo(const LLUUID& idItem, std::string* pstrName, LLViewerInventoryCategory** ppFolder) const + { +/* + LLViewerInventoryCategory* pRlvRoot; LLViewerInventoryItem* pItem; + if ( (idItem.notNull()) && ((pRlvRoot = getSharedRoot()) != NULL) && + (gInventory.isObjectDescendentOf(idItem, pRlvRoot->getUUID())) && ((pItem = gInventory.getItem(idItem)) != NULL) ) + { + // We know it's an item in a folder under the shared root (we need its parent if it's a folded folder) + LLViewerInventoryCategory* pFolder = gInventory.getCategory(pItem->getParentUUID()); + if (isFoldedFolder(pFolder, true, false)) // Don't check if the folder is a composite folder + pFolder = gInventory.getCategory(pFolder->getParentUUID()); + + if ( (pFolder) && (getCompositeInfo(pFolder, pstrName)) ) + { + if (ppFolder) + *ppFolder = pFolder; + return true; + } + } +*/ + return false; + } +#endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS + +#ifdef RLV_EXPERIMENTAL_COMPOSITE_FOLDING + // Checked: + inline bool RlvHandler::isHiddenCompositeItem(const LLUUID& idItem, const std::string& cstrItemType) const + { + // An item that's part of a composite folder will be hidden from @getoutfit and @getattach if: + // (1) the composite name specifies either a wearable layer or an attachment point + // (2) the specified wearable layer or attachment point is worn and resides in the folder + // (3) cstrItemType isn't the specified wearable layer or attach point + // + // Example: #RLV/Separates/Shoes/ChiChi Pumps/.[shoes] with items: "Shoe Base", "Shoe (left foot)" and "Shoe (right foot)" + // -> as long as "Shoe Base" is worn, @getattach should not reflect "left foot", nor "right foot" + std::string strComposite; LLViewerInventoryCategory* pFolder; + LLWearableType::EType type; S32 idxAttachPt; + if ( (getCompositeInfo(idItem, &strComposite, &pFolder)) && (cstrItemType != strComposite) ) + { + LLUUID idCompositeItem; + if ((type = LLWearable::typeNameToType(strComposite)) != WT_INVALID) + { + idCompositeItem = gAgent.getWearableItem(type); + } + else if ((idxAttachPt = getAttachPointIndex(strComposite, true)) != 0) + { + LLVOAvatar* pAvatar; LLViewerJointAttachment* pAttachmentPt; + if ( ((pAvatar = gAgent.getAvatarObject()) != NULL) && + ((pAttachmentPt = get_if_there(pAvatar->mAttachmentPoints, idxAttachPt, (LLViewerJointAttachment*)NULL)) != NULL) ) + { + idCompositeItem = pAttachmentPt->getItemID(); + } + } + + if ( (idCompositeItem.notNull()) && (gInventory.isObjectDescendentOf(idCompositeItem, pFolder->getUUID())) ) + return true; + } + return false; + } +#endif // RLV_EXPERIMENTAL_COMPOSITEFOLDING + +#ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS + // Checked: 2009-12-18 (RLVa-1.1.0k) | Modified: RLVa-1.1.0i + bool RlvHandler::canTakeOffComposite(const LLInventoryCategory* pFolder) const + { + // Sanity check - if there's no folder or no avatar then there is nothing to take off + LLVOAvatarSelf* pAvatar = gAgent.getAvatarObject(); + if ( (!pFolder) || (!pAvatar) ) + return false; + // Sanity check - if nothing is locked then we can definitely take it off + if ( (!gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_REMOVE)) || + (!gRlvWearableLocks.hasLockedWearableType(RLV_LOCK_REMOVE)) ) + { + return true; + } + +/* + LLInventoryModel::cat_array_t folders; + LLInventoryModel::item_array_t items; + RlvWearableItemCollector functor(pFolder->getUUID(), true, false); + gInventory.collectDescendentsIf(pFolder->getUUID(), folders, items, FALSE, functor); + + for (S32 idxItem = 0, cntItem = items.count(); idxItem < cntItem; idxItem++) + { + const LLViewerInventoryItem* pItem = items.get(idxItem); + switch (pItem->getType()) + { + case LLAssetType::AT_BODYPART: + case LLAssetType::AT_CLOTHING: + { + LLWearable* pWearable = gAgent.getWearableFromWearableItem(pItem->getUUID()); + if ( (pWearable) && (!isRemovable(pWearable->getType())) ) + return false; // If one wearable in the folder is non-removeable then the entire folder should be + } + break; + case LLAssetType::AT_OBJECT: + { + LLViewerObject* pObj = pAvatar->getWornAttachment(pItem->getUUID()); + if ( (pObj != NULL) && (isLockedAttachment(pObj, RLV_LOCK_REMOVE)) ) + return false; // If one attachment in the folder is non-detachable then the entire folder should be + } + break; + default: + break; + } + } +*/ + return true; + } + + // Checked: 2009-12-18 (RLVa-1.1.0k) | Modified: RLVa-1.1.0i + bool RlvHandler::canWearComposite(const LLInventoryCategory* pFolder) const + { + // Sanity check - if there's no folder or no avatar then there is nothing to wear + LLVOAvatar* pAvatar = gAgent.getAvatarObject(); + if ( (!pFolder) || (!pAvatar) ) + return false; + // Sanity check - if nothing is locked then we can definitely wear it + if ( (!gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) || (!gRlvWearableLocks.hacLockedWearableType(RLV_LOCK_ANY)) ) + return true; + +/* + LLInventoryModel::cat_array_t folders; + LLInventoryModel::item_array_t items; + RlvWearableItemCollector functor(pFolder->getUUID(), true, false); + gInventory.collectDescendentsIf(pFolder->getUUID(), folders, items, FALSE, functor); + + for (S32 idxItem = 0, cntItem = items.count(); idxItem < cntItem; idxItem++) + { + LLViewerInventoryItem* pItem = items.get(idxItem); + + if (RlvForceWear::isWearingItem(pItem)) + continue; // Don't examine any items we're already wearing + + // A wearable layer or attachment point: + // - can't be "add locked" + // - can't be worn and "remove locked" + // - can't be worn and have its item belong to a *different* composite folder that we can't take off + switch (pItem->getType()) + { + case LLAssetType::AT_BODYPART: + case LLAssetType::AT_CLOTHING: + { + // NOTE: without its asset we don't know what type the wearable is so we need to look at the item's flags instead + LLWearableType::EType wtType = (LLWearableType::EType)(pItem->getFlags() & LLInventoryItem::II_FLAGS_WEARABLES_MASK); + LLViewerInventoryCategory* pFolder; + if ( (!isWearable(wtType)) || + ( (gAgent.getWearable(wtType)) && (!isRemovable(wtType)) ) || + ( (gRlvHandler.getCompositeInfo(gAgent.getWearableItem(wtType), NULL, &pFolder)) && + (pFolder->getUUID() != pItem->getParentUUID()) && (!gRlvHandler.canTakeOffComposite(pFolder)) ) ) + { + return false; + } + } + break; + case LLAssetType::AT_OBJECT: + { + // If we made it here then *something* is add/remove locked so we absolutely need to know its attachment point + LLViewerJointAttachment* pAttachPt = getAttachPoint(pItem, true); + LLViewerInventoryCategory* pFolder; + if ( (!pAttachPt) || (isLockedAttachment(pAttachPt, RLV_LOCK_ADD)) || + ( (pAttachPt->getObject()) && (isLockedAttachment(pAttachPt, RLV_LOCK_REMOVE)) ) || + ( (gRlvHandler.getCompositeInfo(pAttachPt->getItemID(), NULL, &pFolder)) && + (pFolder->getUUID() != pItem->getParentUUID()) && (!gRlvHandler.canTakeOffComposite(pFolder)) ) ) + { + return false; + } + } + break; + default: + break; + } + } +*/ + return true; + } +#endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS + +// ============================================================================ +// Initialization helper functions +// + +// Checked: 2010-02-27 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a +BOOL RlvHandler::setEnabled(BOOL fEnable) +{ + // TODO-RLVa: [RLVa-1.2.1] Allow toggling at runtime if we haven't seen any llOwnerSay("@...."); + if (m_fEnabled == fEnable) + return fEnable; + + if (fEnable) + { + RLV_INFOS << "Enabling Restrained Love API support - " << RlvStrings::getVersionAbout() << RLV_ENDL; + m_fEnabled = TRUE; + + // Initialize static classes + RlvSettings::initClass(); + RlvStrings::initClass(); + + gRlvHandler.addCommandHandler(new RlvExtGetSet()); + + // Make sure we get notified when login is successful + if (LLStartUp::getStartupState() < STATE_STARTED) + LLAppViewer::instance()->setOnLoginCompletedCallback(boost::bind(&RlvHandler::onLoginComplete, &gRlvHandler)); + else + gRlvHandler.onLoginComplete(); + + // Set up RlvUIEnabler + RlvUIEnabler::getInstance(); + + // Reset to show assertions if the viewer version changed + if (gSavedSettings.getString("LastRunVersion") != gLastRunVersion) + gSavedSettings.setBOOL("RLVaShowAssertionFailures", TRUE); + } + + return m_fEnabled; +} + +BOOL RlvHandler::canDisable() +{ + return FALSE; +} + +void RlvHandler::clearState() +{ +/* + // TODO-RLVa: should restore all RLV controlled debug variables to their defaults + + // Issue @clear on behalf of every object that has a currently active RLV restriction (even if it's just an exception) + LLUUID idObj; LLViewerObject* pObj; bool fDetachable; + while (m_Objects.size()) + { + idObj = m_Objects.begin()->first; // Need a copy since after @clear the data it points to will no longer exist + fDetachable = ((pObj = gObjectList.findObject(idObj)) != NULL) ? isLockedAttachment(pObj, RLV_LOCK_REMOVE) : true; + + processCommand(idObj, "clear", false); + if (!fDetachable) + processCommand(idObj, "detachme=force", false); + } + + // Sanity check - these should all be empty after we issue @clear on the last object + if ( (!m_Objects.empty()) || !(m_Exceptions.empty()) || (!m_AttachAdd.empty()) || (!m_AttachRem.empty()) ) + { + RLV_ERRS << "Object, exception or attachment map not empty after clearing state!" << LL_ENDL; + m_Objects.clear(); + m_Exceptions.clear(); + m_AttachAdd.clear(); + m_AttachRem.clear(); + } + + // These all need manual clearing + memset(m_LayersAdd, 0, sizeof(S16) * WT_COUNT); + memset(m_LayersRem, 0, sizeof(S16) * WT_COUNT); + memset(m_Behaviours, 0, sizeof(S16) * RLV_BHVR_COUNT); + m_Retained.clear(); + clearCommandHandlers(); // <- calls delete on all registered command handlers + + // Clear dynamically allocated memory + delete m_pGCTimer; + m_pGCTimer = NULL; +*/ +} + +// ============================================================================ +// Command handlers (RLV_TYPE_ADD and RLV_TYPE_REMOVE) +// + +#define VERIFY_OPTION(x) { if (!(x)) { eRet = RLV_RET_FAILED_OPTION; break; } } +#define VERIFY_OPTION_REF(x) { if (!(x)) { eRet = RLV_RET_FAILED_OPTION; break; } fRefCount = true; } + +// Checked: 2010-03-03 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a +ERlvCmdRet RlvHandler::processAddRemCommand(const RlvCommand& rlvCmd) +{ + // NOTE: - at this point the command has already been: + // * added to the RlvObject + // * removed from the RlvObject (which still exists at this point even if this is the last restriction) + // - the object's UUID may or may not exist in gObjectList (see handling of @detach=n|y) + + // Try a command processor first + ERlvCmdRet eRet = rlvCmd.processCommand(); + if (RLV_RET_NO_PROCESSOR != eRet) + { + return eRet; + } + + // Process the command the legacy way + ERlvBehaviour eBhvr = rlvCmd.getBehaviourType(); ERlvParamType eType = rlvCmd.getParamType(); + + eRet = RLV_RET_SUCCESS; bool fRefCount = false; const std::string& strOption = rlvCmd.getOption(); + switch (eBhvr) + { + case RLV_BHVR_ATTACHTHIS: // @attachthis[:<option>]=n|y + case RLV_BHVR_DETACHTHIS: // @detachthis[:<option>]=n|y + eRet = onAddRemFolderLock(rlvCmd, fRefCount); + break; + case RLV_BHVR_ATTACHTHISEXCEPT: // @attachthisexcept[:<option>]=n|y + case RLV_BHVR_DETACHTHISEXCEPT: // @detachthisexcept[:<option>]=n|y + eRet = onAddRemFolderLockException(rlvCmd, fRefCount); + break; + case RLV_BHVR_ADDOUTFIT: // @addoutfit[:<layer>]=n|y - Checked: 2010-08-29 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c + case RLV_BHVR_REMOUTFIT: // @remoutfit[:<layer>]=n|y - Checked: 2010-08-29 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c + { + // If there's an option it should specify a wearable type name (reference count on no option *and* a valid option) + RlvCommandOptionGeneric rlvCmdOption; + RlvCommandOptionHelper::parseOption(rlvCmd.getOption(), rlvCmdOption); + VERIFY_OPTION_REF( (rlvCmdOption.isEmpty()) || (rlvCmdOption.isWearableType()) ); + + // We need to flush any queued force-wear commands before changing the restrictions + if (RlvForceWear::instanceExists()) + RlvForceWear::instance().done(); + + ERlvLockMask eLock = (RLV_BHVR_ADDOUTFIT == eBhvr) ? RLV_LOCK_ADD : RLV_LOCK_REMOVE; + for (int idxType = 0; idxType < LLWearableType::WT_COUNT; idxType++) + { + if ( (rlvCmdOption.isEmpty()) || ((LLWearableType::EType)idxType == rlvCmdOption.getWearableType()) ) + { + if (RLV_TYPE_ADD == eType) + gRlvWearableLocks.addWearableTypeLock((LLWearableType::EType)idxType, rlvCmd.getObjectID(), eLock); + else + gRlvWearableLocks.removeWearableTypeLock((LLWearableType::EType)idxType, rlvCmd.getObjectID(), eLock); + } + } + } + break; + case RLV_BHVR_SHAREDWEAR: // @sharedwear=n|y - Checked: 2011-03-28 (RLVa-1.3.0g) | Added: RLVa-1.3.0g + case RLV_BHVR_SHAREDUNWEAR: // @sharedunwear=n|y - Checked: 2011-03-28 (RLVa-1.3.0g) | Added: RLVa-1.3.0g + { + VERIFY_OPTION_REF(strOption.empty()); + + RlvFolderLocks::folderlock_source_t lockSource(RlvFolderLocks::ST_SHAREDPATH, LLStringUtil::null); + RlvFolderLocks::ELockScope eLockScope = RlvFolderLocks::SCOPE_SUBTREE; + ERlvLockMask eLockType = (RLV_BHVR_SHAREDUNWEAR == eBhvr) ? RLV_LOCK_REMOVE : RLV_LOCK_ADD; + + if (RLV_TYPE_ADD == eType) + RlvFolderLocks::instance().addFolderLock(lockSource, RlvFolderLocks::PERM_DENY, eLockScope, rlvCmd.getObjectID(), eLockType); + else + RlvFolderLocks::instance().removeFolderLock(lockSource, RlvFolderLocks::PERM_DENY, eLockScope, rlvCmd.getObjectID(), eLockType); + } + break; + case RLV_BHVR_UNSHAREDWEAR: // @unsharedwear=n|y - Checked: 2011-03-28 (RLVa-1.3.0g) | Added: RLVa-1.3.0g + case RLV_BHVR_UNSHAREDUNWEAR: // @unsharedunwear=n|y - Checked: 2011-03-28 (RLVa-1.3.0g) | Added: RLVa-1.3.0g + { + VERIFY_OPTION_REF(strOption.empty()); + + // Lock down the inventory root + RlvFolderLocks::folderlock_source_t lockSource(RlvFolderLocks::ST_ROOTFOLDER, 0); + RlvFolderLocks::ELockScope eLockScope = RlvFolderLocks::SCOPE_SUBTREE; + ERlvLockMask eLockType = (RLV_BHVR_UNSHAREDUNWEAR == eBhvr) ? RLV_LOCK_REMOVE : RLV_LOCK_ADD; + + if (RLV_TYPE_ADD == eType) + RlvFolderLocks::instance().addFolderLock(lockSource, RlvFolderLocks::PERM_DENY, eLockScope, rlvCmd.getObjectID(), eLockType); + else + RlvFolderLocks::instance().removeFolderLock(lockSource, RlvFolderLocks::PERM_DENY, eLockScope, rlvCmd.getObjectID(), eLockType); + + // Add the #RLV shared folder as an exception + lockSource = RlvFolderLocks::folderlock_source_t(RlvFolderLocks::ST_SHAREDPATH, LLStringUtil::null); + if (RLV_TYPE_ADD == eType) + RlvFolderLocks::instance().addFolderLock(lockSource, RlvFolderLocks::PERM_ALLOW, eLockScope, rlvCmd.getObjectID(), eLockType); + else + RlvFolderLocks::instance().removeFolderLock(lockSource, RlvFolderLocks::PERM_ALLOW, eLockScope, rlvCmd.getObjectID(), eLockType); + } + break; + case RLV_BHVR_REDIRCHAT: // @redirchat:<channel>=n|y - Checked: 2010-03-26 (RLVa-1.2.0b) | Modified: RLVa-1.1.0h + case RLV_BHVR_REDIREMOTE: // @rediremote:<channel>=n|y - Checked: 2010-03-26 (RLVa-1.2.0b) | Modified: RLVa-1.1.0h + { + // There should be an option which should specify a valid reply channel (if there's an empty option the command is invalid) + S32 nChannel = 0; + VERIFY_OPTION_REF( (LLStringUtil::convertToS32(strOption, nChannel)) && (RlvUtil::isValidReplyChannel(nChannel)) ); + + if (RLV_TYPE_ADD == eType) + addException(rlvCmd.getObjectID(), eBhvr, nChannel); + else + removeException(rlvCmd.getObjectID(), eBhvr, nChannel); + } + break; + case RLV_BHVR_NOTIFY: // @notify:<params>=add|rem - Checked: 2010-03-03 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a + { + // There should be an option that we can successfully parse (if there's an empty option the command is invalid) + S32 nChannel; std::string strFilter; + VERIFY_OPTION_REF( (!strOption.empty()) && (rlvParseNotifyOption(strOption, nChannel, strFilter)) ); + + if (RLV_TYPE_ADD == eType) + RlvBehaviourNotifyHandler::getInstance()->addNotify(rlvCmd.getObjectID(), nChannel, strFilter); + else + RlvBehaviourNotifyHandler::getInstance()->removeNotify(rlvCmd.getObjectID(), nChannel, strFilter); + } + break; + // + // Unknown or invalid + // + case RLV_BHVR_UNKNOWN: + // Pass unknown commands on to registered command handlers + return (notifyCommandHandlers(&RlvExtCommandHandler::onAddRemCommand, rlvCmd, eRet, false)) ? eRet : RLV_RET_FAILED_UNKNOWN; + default: + // Fail with "Invalid param" if none of the above handled it + eRet = RLV_RET_FAILED_PARAM; + break; + } + + // If this command represents a behaviour restriction that's been added/removed then we need to do some additional processing + if ( (RLV_RET_SUCCESS == eRet) && (fRefCount) ) + { + if (RLV_TYPE_ADD == eType) + { + if (rlvCmd.isStrict()) + addException(rlvCmd.getObjectID(), RLV_BHVR_PERMISSIVE, eBhvr); + m_Behaviours[eBhvr]++; + rlvCmd.markRefCounted(); + } + else + { + if (rlvCmd.isStrict()) + removeException(rlvCmd.getObjectID(), RLV_BHVR_PERMISSIVE, eBhvr); + m_Behaviours[eBhvr]--; + } + + m_OnBehaviour(eBhvr, eType); + if ( ((RLV_TYPE_ADD == eType) && (1 == m_Behaviours[eBhvr])) || ((RLV_TYPE_REMOVE == eType) && (0 == m_Behaviours[eBhvr])) ) + m_OnBehaviourToggle(eBhvr, eType); + } + + return eRet; +} + +// Handles reference counting of behaviours and tracks strict exceptions for @permissive (all restriction handlers should call this function) +ERlvCmdRet RlvCommandHandlerBaseImpl<RLV_TYPE_ADDREM>::processCommand(const RlvCommand& rlvCmd, RlvBhvrHandlerFunc* pHandlerFunc, RlvBhvrToggleHandlerFunc* pToggleHandlerFunc) +{ + ERlvBehaviour eBhvr = rlvCmd.getBehaviourType(); + bool fRefCount = false, fHasBhvr = gRlvHandler.hasBehaviour(eBhvr); + + ERlvCmdRet eRet = (*pHandlerFunc)(rlvCmd, fRefCount); + + // If this command represents a restriction that's been added/removed then we need to do some additional processing + if ( (RLV_RET_SUCCESS == eRet) && (fRefCount) ) + { + if (RLV_TYPE_ADD == rlvCmd.getParamType()) + { + if (rlvCmd.isStrict()) + gRlvHandler.addException(rlvCmd.getObjectID(), RLV_BHVR_PERMISSIVE, eBhvr); + gRlvHandler.m_Behaviours[eBhvr]++; + rlvCmd.markRefCounted(); + } + else + { + if (rlvCmd.isStrict()) + gRlvHandler.removeException(rlvCmd.getObjectID(), RLV_BHVR_PERMISSIVE, eBhvr); + gRlvHandler.m_Behaviours[eBhvr]--; + } + + if (fHasBhvr != gRlvHandler.hasBehaviour(eBhvr)) + { + if (pToggleHandlerFunc) + (*pToggleHandlerFunc)(eBhvr, !fHasBhvr); + gRlvHandler.m_OnBehaviourToggle(eBhvr, rlvCmd.getParamType()); + } + } + + return eRet; +} + +// Handles: @bhvr=n|y +template<> +ERlvCmdRet RlvBehaviourGenericHandler<RLV_OPTION_NONE>::onCommand(const RlvCommand& rlvCmd, bool& fRefCount) +{ + // There should be no option + if (rlvCmd.hasOption()) + return RLV_RET_FAILED_OPTION; + + fRefCount = true; + return RLV_RET_SUCCESS; +} + +// Handles: @bhvr:<uuid>=n|y +template<> +ERlvCmdRet RlvBehaviourGenericHandler<RLV_OPTION_EXCEPTION>::onCommand(const RlvCommand& rlvCmd, bool& fRefCount) +{ + // There should be an option and it should specify a valid UUID + LLUUID idException; + if (!RlvCommandOptionHelper::parseOption(rlvCmd.getOption(), idException)) + return RLV_RET_FAILED_OPTION; + + if (RLV_TYPE_ADD == rlvCmd.getParamType()) + gRlvHandler.addException(rlvCmd.getObjectID(), rlvCmd.getBehaviourType(), idException); + else + gRlvHandler.removeException(rlvCmd.getObjectID(), rlvCmd.getBehaviourType(), idException); + + fRefCount = true; + return RLV_RET_SUCCESS; +} + +// Handles: @bhvr[:<uuid>]=n|y +template<> +ERlvCmdRet RlvBehaviourGenericHandler<RLV_OPTION_NONE_OR_EXCEPTION>::onCommand(const RlvCommand& rlvCmd, bool& fRefCount) +{ + // If there is an option then it should specify a valid UUID (but don't reference count) + if (rlvCmd.hasOption()) + { + ERlvCmdRet eRet = RlvBehaviourGenericHandler<RLV_OPTION_EXCEPTION>::onCommand(rlvCmd, fRefCount); + fRefCount = false; + return eRet; + } + return RlvBehaviourGenericHandler<RLV_OPTION_NONE>::onCommand(rlvCmd, fRefCount); +} + +// Handles: @bhvr:<modifier>=n|y +template<> +ERlvCmdRet RlvBehaviourGenericHandler<RLV_OPTION_MODIFIER>::onCommand(const RlvCommand& rlvCmd, bool& fRefCount) +{ + // There should be an option and it should specify a valid modifier (RlvBehaviourModifier performs the appropriate type checks) + RlvBehaviourModifier* pBhvrModifier = RlvBehaviourDictionary::instance().getModifierFromBehaviour(rlvCmd.getBehaviourType()); + RlvBehaviourModifierValue modValue; + if ( (!rlvCmd.hasOption()) || (!pBhvrModifier) || (!pBhvrModifier->convertOptionValue(rlvCmd.getOption(), modValue)) ) + return RLV_RET_FAILED_OPTION; + + // HACK-RLVa: reference counting doesn't happen until control returns to our caller but the modifier callbacks will happen now so we need to adjust the reference counts here + if (RLV_TYPE_ADD == rlvCmd.getParamType()) + { + gRlvHandler.m_Behaviours[rlvCmd.getBehaviourType()]++; + pBhvrModifier->addValue(modValue, rlvCmd.getObjectID()); + gRlvHandler.m_Behaviours[rlvCmd.getBehaviourType()]--; + } + else + { + gRlvHandler.m_Behaviours[rlvCmd.getBehaviourType()]--; + pBhvrModifier->removeValue(modValue, rlvCmd.getObjectID()); + gRlvHandler.m_Behaviours[rlvCmd.getBehaviourType()]++; + } + + fRefCount = true; + return RLV_RET_SUCCESS; +} + +// Handles: @bhvr[:<modifier>]=n|y +template<> +ERlvCmdRet RlvBehaviourGenericHandler<RLV_OPTION_NONE_OR_MODIFIER>::onCommand(const RlvCommand& rlvCmd, bool& fRefCount) +{ + // If there is an option then it should specify a valid modifier (and reference count) + if (rlvCmd.hasOption()) + return RlvBehaviourGenericHandler<RLV_OPTION_MODIFIER>::onCommand(rlvCmd, fRefCount); + + // Add the default option on an empty modifier if needed + RlvBehaviourModifier* pBhvrModifier = RlvBehaviourDictionary::instance().getModifierFromBehaviour(rlvCmd.getBehaviourType()); + if ( (pBhvrModifier) && (pBhvrModifier->getAddDefault()) ) + { + // HACK-RLVa: reference counting doesn't happen until control returns to our caller but the modifier callbacks will happen now so we need to adjust the reference counts here + if (RLV_TYPE_ADD == rlvCmd.getParamType()) + { + gRlvHandler.m_Behaviours[rlvCmd.getBehaviourType()]++; + pBhvrModifier->addValue(pBhvrModifier->getDefaultValue(), rlvCmd.getObjectID()); + gRlvHandler.m_Behaviours[rlvCmd.getBehaviourType()]--; + } + else + { + gRlvHandler.m_Behaviours[rlvCmd.getBehaviourType()]--; + pBhvrModifier->removeValue(pBhvrModifier->getDefaultValue(), rlvCmd.getObjectID()); + gRlvHandler.m_Behaviours[rlvCmd.getBehaviourType()]++; + } + } + + fRefCount = true; + return RLV_RET_SUCCESS; +} + +// Handles: @addattach[:<attachpt>]=n|y and @remattach[:<attachpt>]=n|y +template<> template<> +ERlvCmdRet RlvBehaviourAddRemAttachHandler::onCommand(const RlvCommand& rlvCmd, bool& fRefCount) +{ + // Sanity check - if there's an option it should specify a valid attachment point name + S32 idxAttachPt = RlvAttachPtLookup::getAttachPointIndex(rlvCmd.getOption()); + if ( (!idxAttachPt) && (!rlvCmd.getOption().empty()) ) + return RLV_RET_FAILED_OPTION; + + if (!isAgentAvatarValid()) + return RLV_RET_FAILED; + + // We need to flush any queued force-wear commands before changing the restrictions + if (RlvForceWear::instanceExists()) + RlvForceWear::instance().done(); + + ERlvLockMask eLock = (RLV_BHVR_REMATTACH == rlvCmd.getBehaviourType()) ? RLV_LOCK_REMOVE : RLV_LOCK_ADD; + for (LLVOAvatar::attachment_map_t::const_iterator itAttach = gAgentAvatarp->mAttachmentPoints.begin(); + itAttach != gAgentAvatarp->mAttachmentPoints.end(); ++itAttach) + { + if ( (0 == idxAttachPt) || (itAttach->first == idxAttachPt) ) + { + if (RLV_TYPE_ADD == rlvCmd.getParamType()) + gRlvAttachmentLocks.addAttachmentPointLock(itAttach->first, rlvCmd.getObjectID(), eLock); + else + gRlvAttachmentLocks.removeAttachmentPointLock(itAttach->first, rlvCmd.getObjectID(), eLock); + } + } + + fRefCount = rlvCmd.getOption().empty(); // Only reference count global locks + return RLV_RET_SUCCESS; +} + +// Handles: @detach[:<attachpt>]=n|y +template<> template<> +ERlvCmdRet RlvBehaviourHandler<RLV_BHVR_DETACH>::onCommand(const RlvCommand& rlvCmd, bool& fRefCount) +{ + // We need to flush any queued force-wear commands before changing the restrictions + if (RlvForceWear::instanceExists()) + RlvForceWear::instance().done(); + + if (rlvCmd.getOption().empty()) // @detach=n|y - RLV_LOCK_REMOVE locks an attachment *object* + { + // The object may or may not exist (it may not have rezzed yet, or it may have already been killed): + // * @detach=n: - if it has rezzed then we'll already have looked up what we need (see next line if it's not an attachment) + // - if it hasn't rezzed yet then it's a @detach=n from a non-attachment and RlvHandler::onAttach() takes care of it + // * @detach=y: - if it ever rezzed as an attachment we'll have cached the UUID of its root + // - if it never rezzed as an attachment there won't be a lock to remove + RlvHandler::rlv_object_map_t::const_iterator itObj = gRlvHandler.m_Objects.find(rlvCmd.getObjectID()); + if ( (itObj != gRlvHandler.m_Objects.end()) && (itObj->second.hasLookup()) && (itObj->second.getAttachPt()) ) + { + if (RLV_TYPE_ADD == rlvCmd.getParamType()) + gRlvAttachmentLocks.addAttachmentLock(itObj->second.getRootID(), itObj->first); + else + gRlvAttachmentLocks.removeAttachmentLock(itObj->second.getRootID(), itObj->first); + } + } + else // @detach:<attachpt>=n|y - RLV_LOCK_ADD and RLV_LOCK_REMOVE locks an attachment *point* + { + // The attachment point index should always be non-zero for @detach:<attachpt>=n|y + S32 idxAttachPt = RlvAttachPtLookup::getAttachPointIndex(rlvCmd.getOption()); + if (0 == idxAttachPt) + return RLV_RET_FAILED_OPTION; + + if (RLV_TYPE_ADD == rlvCmd.getParamType()) + gRlvAttachmentLocks.addAttachmentPointLock(idxAttachPt, rlvCmd.getObjectID(), (ERlvLockMask)(RLV_LOCK_ADD | RLV_LOCK_REMOVE)); + else + gRlvAttachmentLocks.removeAttachmentPointLock(idxAttachPt, rlvCmd.getObjectID(), (ERlvLockMask)(RLV_LOCK_ADD | RLV_LOCK_REMOVE)); + } + + fRefCount = false; // Don't reference count @detach[:<option>]=n + return RLV_RET_SUCCESS; +} + +// Checked: 2010-11-30 (RLVa-1.3.0b) | Added: RLVa-1.3.0b +ERlvCmdRet RlvHandler::onAddRemFolderLock(const RlvCommand& rlvCmd, bool& fRefCount) +{ + RlvCommandOptionGeneric rlvCmdOption; + RlvCommandOptionHelper::parseOption(rlvCmd.getOption(), rlvCmdOption); + + RlvFolderLocks::folderlock_source_t lockSource; + if (rlvCmdOption.isEmpty()) + { + lockSource = RlvFolderLocks::folderlock_source_t(RlvFolderLocks::ST_ATTACHMENT, rlvCmd.getObjectID()); + } + else if (rlvCmdOption.isSharedFolder()) + { + lockSource = RlvFolderLocks::folderlock_source_t(RlvFolderLocks::ST_SHAREDPATH, rlvCmd.getOption()); + } + else if (rlvCmdOption.isAttachmentPoint()) + { + lockSource = RlvFolderLocks::folderlock_source_t(RlvFolderLocks::ST_ATTACHMENTPOINT, RlvAttachPtLookup::getAttachPointIndex(rlvCmdOption.getAttachmentPoint())); + } + else if (rlvCmdOption.isWearableType()) + { + lockSource = RlvFolderLocks::folderlock_source_t(RlvFolderLocks::ST_WEARABLETYPE, rlvCmdOption.getWearableType()); + } + else + { + fRefCount = false; // Don't reference count failure + return RLV_RET_FAILED_OPTION; + } + + // Determine the lock type + ERlvLockMask eLockType = (RLV_BHVR_ATTACHTHIS == rlvCmd.getBehaviourType()) ? RLV_LOCK_ADD : RLV_LOCK_REMOVE; + + // Determine the folder lock options from the issued behaviour + RlvFolderLocks::ELockPermission eLockPermission = RlvFolderLocks::PERM_DENY; + RlvFolderLocks::ELockScope eLockScope = (RlvBehaviourInfo::FORCEWEAR_SUBTREE & rlvCmd.getBehaviourFlags()) ? RlvFolderLocks::SCOPE_SUBTREE : RlvFolderLocks::SCOPE_NODE; + + if (RLV_TYPE_ADD == rlvCmd.getParamType()) + RlvFolderLocks::instance().addFolderLock(lockSource, eLockPermission, eLockScope, rlvCmd.getObjectID(), eLockType); + else + RlvFolderLocks::instance().removeFolderLock(lockSource, eLockPermission, eLockScope, rlvCmd.getObjectID(), eLockType); + + fRefCount = true; + return RLV_RET_SUCCESS; +} + +// Checked: 2011-03-27 (RLVa-1.3.0g) | Added: RLVa-1.3.0g +ERlvCmdRet RlvHandler::onAddRemFolderLockException(const RlvCommand& rlvCmd, bool& fRefCount) +{ + // Sanity check - the option should specify a shared folder path + RlvCommandOptionGeneric rlvCmdOption; + RlvCommandOptionHelper::parseOption(rlvCmd.getOption(), rlvCmdOption); + if (!rlvCmdOption.isSharedFolder()) + return RLV_RET_FAILED_OPTION; + + ERlvBehaviour eBhvr = rlvCmd.getBehaviourType(); + + // Determine the lock type + ERlvLockMask eLockType = (RLV_BHVR_ATTACHTHISEXCEPT == eBhvr) ? RLV_LOCK_ADD : RLV_LOCK_REMOVE; + + // Determine the folder lock options from the issued behaviour + RlvFolderLocks::ELockPermission eLockPermission = RlvFolderLocks::PERM_ALLOW; + RlvFolderLocks::ELockScope eLockScope = (RlvBehaviourInfo::FORCEWEAR_SUBTREE & rlvCmd.getBehaviourFlags()) ? RlvFolderLocks::SCOPE_SUBTREE : RlvFolderLocks::SCOPE_NODE; + + RlvFolderLocks::folderlock_source_t lockSource(RlvFolderLocks::ST_SHAREDPATH, rlvCmd.getOption()); + if (RLV_TYPE_ADD == rlvCmd.getParamType()) + RlvFolderLocks::instance().addFolderLock(lockSource, eLockPermission, eLockScope, rlvCmd.getObjectID(), eLockType); + else + RlvFolderLocks::instance().removeFolderLock(lockSource, eLockPermission, eLockScope, rlvCmd.getObjectID(), eLockType); + + fRefCount = true; + return RLV_RET_SUCCESS; +} + +// Handles: @edit=n|y toggles +template<> template<> +void RlvBehaviourToggleHandler<RLV_BHVR_EDIT>::onCommandToggle(ERlvBehaviour eBhvr, bool fHasBhvr) +{ + if (fHasBhvr) + { + // Turn off "View / Highlight Transparent" + LLDrawPoolAlpha::sShowDebugAlpha = FALSE; + + // Hide the beacons floater if it's currently visible + if (LLFloaterReg::instanceVisible("beacons")) + LLFloaterReg::hideInstance("beacons"); + + // Hide the build floater if it's currently visible + if (LLFloaterReg::instanceVisible("build")) + LLToolMgr::instance().toggleBuildMode(); + } + + // Start or stop filtering opening the beacons floater + if (fHasBhvr) + RlvUIEnabler::instance().addGenericFloaterFilter("beacons"); + else + RlvUIEnabler::instance().removeGenericFloaterFilter("beacons"); +} + +// Handles: @sendchannel[:<channel>]=n|y and @sendchannel_except[:<channel>]=n|y +template<> template<> +ERlvCmdRet RlvBehaviourSendChannelHandler::onCommand(const RlvCommand& rlvCmd, bool& fRefCount) +{ + // If there's an option then it should be a valid (= positive and non-zero) chat channel + if (rlvCmd.hasOption()) + { + S32 nChannel = 0; + if ( (!RlvCommandOptionHelper::parseOption(rlvCmd.getOption(), nChannel)) || (nChannel <= 0) ) + return RLV_RET_FAILED_OPTION; + + if (RLV_TYPE_ADD == rlvCmd.getParamType()) + gRlvHandler.addException(rlvCmd.getObjectID(), rlvCmd.getBehaviourType(), nChannel); + else + gRlvHandler.removeException(rlvCmd.getObjectID(), rlvCmd.getBehaviourType(), nChannel); + } + else + { + fRefCount = true; + } + return RLV_RET_SUCCESS; +} + +// Handles: @recvim[:<uuid|range>]=n|y, @sendim[:<uuid|range>]=n|y and @startim[:<uuid|range>]=n|y +template<> template<> +ERlvCmdRet RlvBehaviourRecvSendStartIMHandler::onCommand(const RlvCommand& rlvCmd, bool& fRefCount) +{ + ERlvCmdRet eRet = RlvBehaviourGenericHandler<RLV_OPTION_NONE_OR_EXCEPTION>::onCommand(rlvCmd, fRefCount); + if ( (RLV_RET_SUCCESS != eRet) && (rlvCmd.hasOption()) ) + { + // Check for <dist_min>[;<dist_max>] option + std::vector<std::string> optionList; float nDistMin = F32_MAX, nDistMax = F32_MAX; + if ( (!RlvCommandOptionHelper::parseStringList(rlvCmd.getOption(), optionList)) || (optionList.size() > 2) || + (!RlvCommandOptionHelper::parseOption(optionList[0], nDistMin)) || (nDistMin < 0) || + ( (optionList.size() >= 2) && (!RlvCommandOptionHelper::parseOption(optionList[1], nDistMax)) ) || (nDistMax < 0) ) + { + return RLV_RET_FAILED_OPTION; + } + + // Valid option(s) - figure out which modifier(s) to change + ERlvBehaviourModifier eModDistMin, eModDistMax; + switch (rlvCmd.getBehaviourType()) + { + case RLV_BHVR_RECVIM: + eModDistMin = RLV_MODIFIER_RECVIMDISTMIN; eModDistMax = RLV_MODIFIER_RECVIMDISTMAX; + break; + case RLV_BHVR_SENDIM: + eModDistMin = RLV_MODIFIER_SENDIMDISTMIN; eModDistMax = RLV_MODIFIER_SENDIMDISTMAX; + break; + case RLV_BHVR_STARTIM: + eModDistMin = RLV_MODIFIER_STARTIMDISTMIN; eModDistMax = RLV_MODIFIER_STARTIMDISTMAX; + break; + default: + return RLV_RET_FAILED_OPTION; + } + + RlvBehaviourModifier *pBhvrModDistMin = RlvBehaviourDictionary::instance().getModifier(eModDistMin), *pBhvrModDistMax = RlvBehaviourDictionary::instance().getModifier(eModDistMax); + if (RLV_TYPE_ADD == rlvCmd.getParamType()) + { + pBhvrModDistMin->addValue(nDistMin * nDistMin, rlvCmd.getObjectID()); + if (optionList.size() >= 2) + pBhvrModDistMax->addValue(nDistMax * nDistMax, rlvCmd.getObjectID()); + } + else + { + pBhvrModDistMin->removeValue(nDistMin * nDistMin, rlvCmd.getObjectID()); + if (optionList.size() >= 2) + pBhvrModDistMax->removeValue(nDistMax * nDistMax, rlvCmd.getObjectID()); + } + + fRefCount = true; + return RLV_RET_SUCCESS; + } + return eRet; +} + +// Handles: @sendim=n|y toggles +template<> template<> +void RlvBehaviourToggleHandler<RLV_BHVR_SENDIM>::onCommandToggle(ERlvBehaviour eBhvr, bool fHasBhvr) +{ + gSavedPerAccountSettings.getControl("DoNotDisturbModeResponse")->setHiddenFromSettingsEditor(fHasBhvr); +} + +// Handles: @setcam_avdistmin:<distance>=n|y changes +template<> +void RlvBehaviourModifierHandler<RLV_MODIFIER_SETCAM_AVDISTMIN>::onValueChange() const +{ + if ( (gAgentCamera.cameraMouselook()) && (!RlvActions::canChangeToMouselook()) ) + gAgentCamera.changeCameraToThirdPerson(); +} + +// Handles: @setcam_eyeoffset:<vector3>=n|y and @setcam_focusoffset:<vector3>=n|y toggles +template<> template<> +void RlvBehaviourCamEyeFocusOffsetHandler::onCommandToggle(ERlvBehaviour eBhvr, bool fHasBhvr) +{ + if (fHasBhvr) + { + gAgentCamera.switchCameraPreset(CAMERA_RLV_SETCAM_VIEW); + } + else + { + const RlvBehaviourModifier* pBhvrEyeModifier = RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_SETCAM_EYEOFFSET); + const RlvBehaviourModifier* pBhvrOffsetModifier = RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_SETCAM_FOCUSOFFSET); + if ( (!pBhvrEyeModifier->hasValue()) && (!pBhvrOffsetModifier->hasValue()) ) + gAgentCamera.switchCameraPreset(CAMERA_PRESET_REAR_VIEW); + } +} + +// Handles: @setcam_eyeoffset:<vector3>=n|y changes +template<> +void RlvBehaviourModifierHandler<RLV_MODIFIER_SETCAM_EYEOFFSET>::onValueChange() const +{ + if (RlvBehaviourModifier* pBhvrModifier = RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_SETCAM_EYEOFFSET)) + { + LLControlVariable* pControl = gSavedSettings.getControl("CameraOffsetRLVaView"); + if (pBhvrModifier->hasValue()) + pControl->setValue(pBhvrModifier->getValue<LLVector3>().getValue()); + else + pControl->resetToDefault(); + } +} + +// Handles: @setcam_focusoffset:<vector3>=n|y changes +template<> +void RlvBehaviourModifierHandler<RLV_MODIFIER_SETCAM_FOCUSOFFSET>::onValueChange() const +{ + if (RlvBehaviourModifier* pBhvrModifier = RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_SETCAM_FOCUSOFFSET)) + { + LLControlVariable* pControl = gSavedSettings.getControl("FocusOffsetRLVaView"); + if (pBhvrModifier->hasValue()) + pControl->setValue(pBhvrModifier->getValue<LLVector3>().getValue()); + else + pControl->resetToDefault(); + } +} + +// Handles: @setcam_fovmin:<angle>=n|y and @setcam_fovmax:<angle>=n|y +template<> template<> +ERlvCmdRet RlvBehaviourSetCamFovHandler::onCommand(const RlvCommand& rlvCmd, bool& fRefCount) +{ + static float s_nLastCameraAngle = DEFAULT_FIELD_OF_VIEW; + + S32 nRefMinBhvr = gRlvHandler.m_Behaviours[RLV_BHVR_SETCAM_FOVMIN], nRefMaxBhvr = gRlvHandler.m_Behaviours[RLV_BHVR_SETCAM_FOVMAX]; + LLControlVariable* pSetting = gSavedSettings.getControl("CameraAngle"); + + // Save the user's current FOV angle if nothing's been restricted (yet) + if ( (!nRefMinBhvr) && (!nRefMaxBhvr) && (pSetting) ) + s_nLastCameraAngle = (pSetting->isPersisted()) ? LLViewerCamera::instance().getDefaultFOV() : DEFAULT_FIELD_OF_VIEW; + + // Perform default handling of the command + ERlvCmdRet eRet = RlvBehaviourGenericHandler<RLV_OPTION_MODIFIER>::onCommand(rlvCmd, fRefCount); + if ( (RLV_RET_SUCCESS == eRet) && (fRefCount) && (pSetting) ) + { + if (RLV_TYPE_ADD == rlvCmd.getParamType()) + { + // Don't persist changes from this point + pSetting->setPersist(LLControlVariable::PERSIST_NO); + } + else if ( (RLV_TYPE_REMOVE == rlvCmd.getParamType()) && (1 == nRefMinBhvr + nRefMaxBhvr) ) + { + // Restore the user's last FOV angle (and resume persistance) + LLViewerCamera::instance().setDefaultFOV(s_nLastCameraAngle); + pSetting->setPersist(LLControlVariable::PERSIST_NONDFT); + } + } + return eRet; +} + +// Handles: @setcam_fovmin:<angle>=n|y changes +template<> +void RlvBehaviourModifierHandler<RLV_MODIFIER_SETCAM_FOVMIN>::onValueChange() const +{ + LLViewerCamera::instance().setDefaultFOV(LLViewerCamera::instance().getDefaultFOV()); +} + +// Handles: @setcam_fovmax:<angle>=n|y changes +template<> +void RlvBehaviourModifierHandler<RLV_MODIFIER_SETCAM_FOVMAX>::onValueChange() const +{ + LLViewerCamera::instance().setDefaultFOV(LLViewerCamera::instance().getDefaultFOV()); +} + +// Handles: @setcam_mouselook=n|y toggles +template<> template<> +void RlvBehaviourToggleHandler<RLV_BHVR_SETCAM_MOUSELOOK>::onCommandToggle(ERlvBehaviour eBhvr, bool fHasBhvr) +{ + if ((fHasBhvr) && (gAgentCamera.cameraMouselook())) + gAgentCamera.changeCameraToThirdPerson(); +} + +// Handles: @setcam_textures[:<uuid>=n|y changes +template<> +void RlvBehaviourModifierHandler<RLV_MODIFIER_SETCAM_TEXTURE>::onValueChange() const +{ + if (RlvBehaviourModifier* pBhvrModifier = RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_SETCAM_TEXTURE)) + { + if (pBhvrModifier->hasValue()) + { + RLV_INFOS << "Toggling diffuse textures for @setcam_textures" << RLV_ENDL; + LLViewerFetchedTexture::sDefaultDiffuseImagep = LLViewerTextureManager::getFetchedTexture(pBhvrModifier->getValue<LLUUID>(), FTT_DEFAULT, MIPMAP_YES, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); + gObjectList.setAllObjectDefaultTextures(LLRender::DIFFUSE_MAP, true); + } + else + { + RLV_INFOS << "Restoring diffuse textures for @setcam_textures" << RLV_ENDL; + gObjectList.setAllObjectDefaultTextures(LLRender::DIFFUSE_MAP, false); + LLViewerFetchedTexture::sDefaultDiffuseImagep = nullptr; + } + } +} + +// Handles: @setcam_unlock=n|y toggles +template<> template<> +void RlvBehaviourToggleHandler<RLV_BHVR_SETCAM_UNLOCK>::onCommandToggle(ERlvBehaviour eBhvr, bool fHasBhvr) +{ + if (fHasBhvr) + handle_reset_view(); +} + +// Handles: @setcam=n|y toggles +template<> template<> +void RlvBehaviourToggleHandler<RLV_BHVR_SETCAM>::onCommandToggle(ERlvBehaviour eBhvr, bool fHasBhvr) +{ + // Once an object has exclusive control over the camera only its behaviours should be active. This affects: + // - behaviour modifiers => it's all handled for us once we set the primary object + // - RLV_BHVR_SETCAM_UNLOCK => manually (re)set the reference count (and possibly invoke the toggle handler) + + LLUUID idRlvObject; bool fHasCamUnlock = gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_UNLOCK); + if (fHasBhvr) + { + // Get the UUID of the primary object + std::list<const RlvObject*> lObjects; + gRlvHandler.findBehaviour(RLV_BHVR_SETCAM, lObjects); + idRlvObject = lObjects.front()->getObjectID(); + // Reset the @setcam_unlock reference count + gRlvHandler.m_Behaviours[RLV_BHVR_SETCAM_UNLOCK] = (lObjects.front()->hasBehaviour(RLV_BHVR_SETCAM_UNLOCK, false)) ? 1 : 0; + } + else + { + std::list<const RlvObject*> lObjects; + // Restore the @setcam_unlock reference count + gRlvHandler.findBehaviour(RLV_BHVR_SETCAM_UNLOCK, lObjects); + gRlvHandler.m_Behaviours[RLV_BHVR_SETCAM_UNLOCK] = lObjects.size(); + } + + // Manually invoke the @setcam_unlock toggle handler if we toggled it on/off + if (fHasCamUnlock != gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_UNLOCK)) + RlvBehaviourToggleHandler<RLV_BHVR_SETCAM_UNLOCK>::onCommandToggle(RLV_BHVR_SETCAM_UNLOCK, !fHasCamUnlock); + + gAgentCamera.switchCameraPreset( (fHasBhvr) ? CAMERA_RLV_SETCAM_VIEW : CAMERA_PRESET_REAR_VIEW ); + RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_SETCAM_AVDISTMIN)->setPrimaryObject(idRlvObject); + RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_SETCAM_AVDISTMAX)->setPrimaryObject(idRlvObject); + RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_SETCAM_ORIGINDISTMIN)->setPrimaryObject(idRlvObject); + RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_SETCAM_ORIGINDISTMAX)->setPrimaryObject(idRlvObject); + RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_SETCAM_EYEOFFSET)->setPrimaryObject(idRlvObject); + RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_SETCAM_FOCUSOFFSET)->setPrimaryObject(idRlvObject); + RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_SETCAM_FOVMIN)->setPrimaryObject(idRlvObject); + RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_SETCAM_FOVMAX)->setPrimaryObject(idRlvObject); + RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_SETCAM_TEXTURE)->setPrimaryObject(idRlvObject); +} + +// Handles: @setdebug=n|y toggles +template<> template<> +void RlvBehaviourToggleHandler<RLV_BHVR_SETDEBUG>::onCommandToggle(ERlvBehaviour eBhvr, bool fHasBhvr) +{ + for (const auto& dbgSetting : RlvExtGetSet::m_DbgAllowed) + { + if (dbgSetting.second & RlvExtGetSet::DBG_WRITE) + gSavedSettings.getControl(dbgSetting.first)->setHiddenFromSettingsEditor(fHasBhvr); + } +} + +// Handles: @edit=n|y toggles +template<> template<> +void RlvBehaviourToggleHandler<RLV_BHVR_SETENV>::onCommandToggle(ERlvBehaviour eBhvr, bool fHasBhvr) +{ + const std::string strEnvFloaters[] = { "env_post_process", "env_settings", "env_delete_preset", "env_edit_sky", "env_edit_water", "env_edit_day_cycle" }; + for (int idxFloater = 0, cntFloater = sizeof(strEnvFloaters) / sizeof(std::string); idxFloater < cntFloater; idxFloater++) + { + if (fHasBhvr) + { + // Hide the floater if it's currently visible + LLFloaterReg::const_instance_list_t envFloaters = LLFloaterReg::getFloaterList(strEnvFloaters[idxFloater]); + for (LLFloater* pFloater : envFloaters) + pFloater->closeFloater(); + RlvUIEnabler::instance().addGenericFloaterFilter(strEnvFloaters[idxFloater]); + } + else + { + RlvUIEnabler::instance().removeGenericFloaterFilter(strEnvFloaters[idxFloater]); + } + } + + // Don't allow toggling "Basic Shaders" and/or "Atmopsheric Shaders" through the debug settings under @setenv=n + gSavedSettings.getControl("VertexShaderEnable")->setHiddenFromSettingsEditor(fHasBhvr); + gSavedSettings.getControl("WindLightUseAtmosShaders")->setHiddenFromSettingsEditor(fHasBhvr); + + // Restore the user's WindLight preferences when releasing + if (!fHasBhvr) + LLEnvManagerNew::instance().usePrefs(); +} + +// Handles: @showhovertext:<uuid>=n|y +template<> template<> +ERlvCmdRet RlvBehaviourHandler<RLV_BHVR_SHOWHOVERTEXT>::onCommand(const RlvCommand& rlvCmd, bool& fRefCount) +{ + // There should be an option and it should specify a valid UUID + LLUUID idException; + if (!RlvCommandOptionHelper::parseOption(rlvCmd.getOption(), idException)) + return RLV_RET_FAILED_OPTION; + + if (RLV_TYPE_ADD == rlvCmd.getParamType()) + gRlvHandler.addException(rlvCmd.getObjectID(), rlvCmd.getBehaviourType(), idException); + else + gRlvHandler.removeException(rlvCmd.getObjectID(), rlvCmd.getBehaviourType(), idException); + + // Clear/restore the object's hover text as needed + LLViewerObject* pObj = gObjectList.findObject(idException); + if ( (pObj) && (pObj->mText.notNull()) && (!pObj->mText->getObjectText().empty()) ) + pObj->mText->setString( (RLV_TYPE_ADD == rlvCmd.getParamType()) ? "" : pObj->mText->getObjectText()); + + fRefCount = true; + return RLV_RET_SUCCESS; +} + +// Handles: @edit=n|y toggles +template<> template<> +void RlvBehaviourToggleHandler<RLV_BHVR_SHOWINV>::onCommandToggle(ERlvBehaviour eBhvr, bool fHasBhvr) +{ + if (LLApp::isQuitting()) + return; // Nothing to do if the viewer is shutting down + + // + // When disabling, close any inventory floaters that may be open + // + if (fHasBhvr) + { + LLFloaterReg::const_instance_list_t invFloaters = LLFloaterReg::getFloaterList("inventory"); + for (LLFloater* pFloater : invFloaters) + pFloater->closeFloater(); + } + + // + // Enable/disable the "My Outfits" panel on the "My Appearance" sidebar tab + // + LLPanelOutfitsInventory* pAppearancePanel = LLPanelOutfitsInventory::findInstance(); + RLV_ASSERT(pAppearancePanel); + if (pAppearancePanel) + { + LLTabContainer* pAppearanceTabs = pAppearancePanel->getAppearanceTabs(); + LLOutfitsList* pMyOutfitsPanel = pAppearancePanel->getMyOutfitsPanel(); + if ( (pAppearanceTabs) && (pMyOutfitsPanel) ) + { + S32 idxTab = pAppearanceTabs->getIndexForPanel(pMyOutfitsPanel); + RLV_ASSERT(-1 != idxTab); + pAppearanceTabs->enableTabButton(idxTab, !fHasBhvr); + + // When disabling, switch to the COF tab if "My Outfits" is currently active + if ( (fHasBhvr) && (pAppearanceTabs->getCurrentPanelIndex() == idxTab) ) + pAppearanceTabs->selectTabPanel(pAppearancePanel->getCurrentOutfitPanel()); + } + + LLSidepanelAppearance* pCOFPanel = pAppearancePanel->getAppearanceSP(); + RLV_ASSERT(pCOFPanel); + if ( (fHasBhvr) && (pCOFPanel) && (pCOFPanel->isOutfitEditPanelVisible()) ) + { + // TODO-RLVa: we should really just be collapsing the "Add more..." inventory panel (and disable the button) + pCOFPanel->showOutfitsInventoryPanel(); + } + } + + // + // Filter (or stop filtering) opening new inventory floaters + // + if (fHasBhvr) + RlvUIEnabler::instance().addGenericFloaterFilter("inventory"); + else + RlvUIEnabler::instance().removeGenericFloaterFilter("inventory"); +} + +// Handles: @shownames[:<uuid>]=n|y toggles +template<> template<> +void RlvBehaviourToggleHandler<RLV_BHVR_SHOWNAMES>::onCommandToggle(ERlvBehaviour eBhvr, bool fHasBhvr) +{ + if (LLApp::isQuitting()) + return; // Nothing to do if the viewer is shutting down + + // Update the shownames context + RlvActions::setShowName(RlvActions::SNC_DEFAULT, !fHasBhvr); + + // Refresh the nearby people list + LLPanelPeople* pPeoplePanel = LLFloaterSidePanelContainer::getPanel<LLPanelPeople>("people", "panel_people"); + RLV_ASSERT( (pPeoplePanel) && (pPeoplePanel->getNearbyList()) ); + if ( (pPeoplePanel) && (pPeoplePanel->getNearbyList()) ) + { + if (pPeoplePanel->getNearbyList()->isInVisibleChain()) + pPeoplePanel->onCommit(); + pPeoplePanel->getNearbyList()->updateAvatarNames(); + } + + // Force the use of the "display name" cache so we can filter both display and legacy names (or return back to the user's preference) + if (fHasBhvr) + { + LLAvatarNameCache::setForceDisplayNames(true); + } + else + { + LLAvatarNameCache::setForceDisplayNames(false); + LLAvatarNameCache::setUseDisplayNames(gSavedSettings.getBOOL("UseDisplayNames")); + } + + // Refresh all name tags and HUD text + LLVOAvatar::invalidateNameTags(); + LLHUDText::refreshAllObjectText(); +} + +// Handles: @shownames[:<uuid>]=n|y +template<> template<> +ERlvCmdRet RlvBehaviourHandler<RLV_BHVR_SHOWNAMES>::onCommand(const RlvCommand& rlvCmd, bool& fRefCount) +{ + ERlvCmdRet eRet = RlvBehaviourGenericHandler<RLV_OPTION_NONE_OR_EXCEPTION>::onCommand(rlvCmd, fRefCount); + if ( (RLV_RET_SUCCESS == eRet) && (rlvCmd.hasOption()) && (!LLApp::isQuitting()) ) + { + const LLUUID idAgent = RlvCommandOptionHelper::parseOption<LLUUID>(rlvCmd.getOption()); + + // Refresh the nearby people list (if necessary) + LLPanelPeople* pPeoplePanel = LLFloaterSidePanelContainer::getPanel<LLPanelPeople>("people", "panel_people"); + RLV_ASSERT( (pPeoplePanel) && (pPeoplePanel->getNearbyList()) ); + if ( (pPeoplePanel) && (pPeoplePanel->getNearbyList()) && (pPeoplePanel->getNearbyList()->contains(idAgent)) ) + { + if (pPeoplePanel->getNearbyList()->isInVisibleChain()) + pPeoplePanel->onCommit(); + pPeoplePanel->getNearbyList()->updateAvatarNames(); + } + + // Refresh that avatar's name tag and all HUD text + LLVOAvatar::invalidateNameTag(idAgent); + LLHUDText::refreshAllObjectText(); + } + return eRet; +} + +// Handles: @shownametags[:<uuid>]=n|y toggles +template<> template<> +void RlvBehaviourToggleHandler<RLV_BHVR_SHOWNAMETAGS>::onCommandToggle(ERlvBehaviour eBhvr, bool fHasBhvr) +{ + if (LLApp::isQuitting()) + return; // Nothing to do if the viewer is shutting down + + // Update the shownames context + RlvActions::setShowName(RlvActions::SNC_NAMETAG, !fHasBhvr); + + // Refresh all name tags + LLVOAvatar::invalidateNameTags(); +} + +// Handles: @shownametags[:<uuid>]=n|y +template<> template<> +ERlvCmdRet RlvBehaviourHandler<RLV_BHVR_SHOWNAMETAGS>::onCommand(const RlvCommand& rlvCmd, bool& fRefCount) +{ + ERlvCmdRet eRet = RlvBehaviourGenericHandler<RLV_OPTION_NONE_OR_EXCEPTION>::onCommand(rlvCmd, fRefCount); + if ( (RLV_RET_SUCCESS == eRet) && (rlvCmd.hasOption()) ) + LLVOAvatar::invalidateNameTag(RlvCommandOptionHelper::parseOption<LLUUID>(rlvCmd.getOption())); + return eRet; +} + +// Handles: @shownearby=n|y toggles +template<> template<> +void RlvBehaviourToggleHandler<RLV_BHVR_SHOWNEARBY>::onCommandToggle(ERlvBehaviour eBhvr, bool fHasBhvr) +{ + if (LLApp::isQuitting()) + return; // Nothing to do if the viewer is shutting down + + // Refresh the nearby people list + LLPanelPeople* pPeoplePanel = LLFloaterSidePanelContainer::getPanel<LLPanelPeople>("people", "panel_people"); + LLAvatarList* pNearbyList = (pPeoplePanel) ? pPeoplePanel->getNearbyList() : NULL; + RLV_ASSERT( (pPeoplePanel) && (pNearbyList) ); + if (pNearbyList) + { + static std::string s_strNoItemsMsg = pNearbyList->getNoItemsMsg(); + pNearbyList->setNoItemsMsg( (fHasBhvr) ? RlvStrings::getString("blocked_nearby") : s_strNoItemsMsg ); + pNearbyList->clear(); + + if (pNearbyList->isInVisibleChain()) + pPeoplePanel->onCommit(); + if (!fHasBhvr) + pPeoplePanel->updateNearbyList(); + } + + // Refresh that avatar's name tag and all HUD text + LLHUDText::refreshAllObjectText(); +} + +// Handles: @showself=n|y and @showselfhead=n|y toggles +template<> template<> +void RlvBehaviourShowSelfToggleHandler::onCommandToggle(ERlvBehaviour eBvhr, bool fHasBhvr) +{ + if (isAgentAvatarValid()) + gAgentAvatarp->updateAttachmentVisibility(gAgentCamera.getCameraMode()); +} + +// ============================================================================ +// Command handlers (RLV_TYPE_FORCE) +// + +ERlvCmdRet RlvCommandHandlerBaseImpl<RLV_TYPE_FORCE>::processCommand(const RlvCommand& rlvCmd, RlvForceHandlerFunc* pHandler) +{ + return (*pHandler)(rlvCmd); +} + +// Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.1.0j +ERlvCmdRet RlvHandler::processForceCommand(const RlvCommand& rlvCmd) const +{ + RLV_ASSERT(RLV_TYPE_FORCE == rlvCmd.getParamType()); + + // Try a command processor first + ERlvCmdRet eRet = rlvCmd.processCommand(); + if (RLV_RET_NO_PROCESSOR != eRet) + { + return eRet; + } + + // Process the command the legacy way + eRet = RLV_RET_SUCCESS; + switch (rlvCmd.getBehaviourType()) + { + case RLV_BHVR_UNSIT: // @unsit=force - Checked: 2010-03-18 (RLVa-1.2.0c) | Modified: RLVa-0.2.0g + { + VERIFY_OPTION(rlvCmd.getOption().empty()); + if ( (isAgentAvatarValid()) && (gAgentAvatarp->isSitting()) && (!hasBehaviourExcept(RLV_BHVR_UNSIT, rlvCmd.getObjectID())) ) + { + gAgent.setControlFlags(AGENT_CONTROL_STAND_UP); + send_agent_update(TRUE, TRUE); // See behaviour notes on why we have to force an agent update here + } + } + break; + case RLV_BHVR_ADJUSTHEIGHT: // @adjustheight:<options>=force - Checked: 2015-03-30 (RLVa-1.5.0) + { + RlvCommandOptionAdjustHeight rlvCmdOption(rlvCmd); + VERIFY_OPTION(rlvCmdOption.isValid()); + if (isAgentAvatarValid()) + { + F32 nValue = (rlvCmdOption.m_nPelvisToFoot - gAgentAvatarp->getPelvisToFoot()) * rlvCmdOption.m_nPelvisToFootDeltaMult; + nValue += rlvCmdOption.m_nPelvisToFootOffset; + if (gAgentAvatarp->getRegion()->avatarHoverHeightEnabled()) + { + LLVector3 avOffset(0.0f, 0.0f, llclamp<F32>(nValue, MIN_HOVER_Z, MAX_HOVER_Z)); + gSavedPerAccountSettings.setF32("AvatarHoverOffsetZ", avOffset.mV[VZ]); + gAgentAvatarp->setHoverOffset(avOffset, true); + } + else + { + eRet = RLV_RET_FAILED_DISABLED; + } + } + } + break; + case RLV_CMD_FORCEWEAR: // @forcewear[:<options>]=force - Checked: 2011-09-12 (RLVa-1.5.0) + { + if (RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE & rlvCmd.getBehaviourFlags()) + { + RlvCommandOptionGeneric rlvCmdOption; + RlvCommandOptionHelper::parseOption(rlvCmd.getOption(), rlvCmdOption); + VERIFY_OPTION(rlvCmdOption.isSharedFolder()); + eRet = onForceWear(rlvCmdOption.getSharedFolder(), rlvCmd.getBehaviourFlags()); + } + else if (RlvBehaviourInfo::FORCEWEAR_CONTEXT_OBJECT & rlvCmd.getBehaviourFlags()) + { + RlvCommandOptionGetPath rlvGetPathOption(rlvCmd, boost::bind(&RlvHandler::onForceWearCallback, this, _1, rlvCmd.getBehaviourFlags())); + VERIFY_OPTION(rlvGetPathOption.isValid()); + eRet = (!rlvGetPathOption.isCallback()) ? RLV_RET_SUCCESS : RLV_RET_SUCCESS_DELAYED; + } + } + break; + case RLV_BHVR_UNKNOWN: + // Pass unknown commands on to registered command handlers + return (notifyCommandHandlers(&RlvExtCommandHandler::onForceCommand, rlvCmd, eRet, false)) ? eRet : RLV_RET_FAILED_UNKNOWN; + default: + // Fail with "Invalid param" if none of the above handled it + eRet = RLV_RET_FAILED_PARAM; + break; + } + return eRet; +} + +// Handles: @detachme=force +template<> template<> +ERlvCmdRet RlvForceHandler<RLV_BHVR_DETACHME>::onCommand(const RlvCommand& rlvCmd) +{ + if (rlvCmd.hasOption()) + return RLV_RET_FAILED_OPTION; + + // NOTE: @detachme should respect locks but shouldn't respect things like nostrip + const LLViewerObject* pAttachObj = gObjectList.findObject(rlvCmd.getObjectID()); + if ( (pAttachObj) && (pAttachObj->isAttachment()) ) + LLVOAvatarSelf::detachAttachmentIntoInventory(pAttachObj->getAttachmentItemID()); + + return RLV_RET_SUCCESS; +} + +// Handles: @remattach[:<folder|attachpt|attachgroup>]=force +template<> template<> +ERlvCmdRet RlvForceRemAttachHandler::onCommand(const RlvCommand& rlvCmd) +{ + if (!isAgentAvatarValid()) + return RLV_RET_FAILED; + + RlvCommandOptionGeneric rlvCmdOption; + RlvCommandOptionHelper::parseOption(rlvCmd.getOption(), rlvCmdOption); + if (rlvCmdOption.isSharedFolder()) + return gRlvHandler.onForceWear(rlvCmdOption.getSharedFolder(), rlvCmd.getBehaviourFlags()); + + // @remattach:<attachpt>=force - force detach single attachment point + if (rlvCmdOption.isAttachmentPoint()) + { + RlvForceWear::instance().forceDetach(rlvCmdOption.getAttachmentPoint()); + return RLV_RET_SUCCESS; + } + // @remattach:<group>=force - force detach attachments points belonging to <group> + // @remattach=force - force detach all attachments points + else if ( (rlvCmdOption.isAttachmentPointGroup()) || (rlvCmdOption.isEmpty()) ) + { + for (const auto& entryAttachPt : gAgentAvatarp->mAttachmentPoints) + { + const LLViewerJointAttachment* pAttachPt = entryAttachPt.second; + if ( (pAttachPt) && (pAttachPt->getNumObjects()) && ((rlvCmdOption.isEmpty()) || (rlvAttachGroupFromIndex(pAttachPt->getGroup()) == rlvCmdOption.getAttachmentPointGroup())) ) + { + RlvForceWear::instance().forceDetach(pAttachPt); + } + } + return RLV_RET_SUCCESS; + } + // @remattach:<uuid>=force - force detach a specific attachment + else if (rlvCmdOption.isUUID()) + { + const LLViewerObject* pAttachObj = gObjectList.findObject(rlvCmdOption.getUUID()); + if ( (pAttachObj) && (pAttachObj->isAttachment()) && (pAttachObj->permYouOwner()) ) + RlvForceWear::instance().forceDetach(pAttachObj); + return RLV_RET_SUCCESS; + } + return RLV_RET_FAILED_OPTION; +} + +// Handles: @remoutfit[:<folder|layer>]=force +template<> template<> +ERlvCmdRet RlvForceHandler<RLV_BHVR_REMOUTFIT>::onCommand(const RlvCommand& rlvCmd) +{ + RlvCommandOptionGeneric rlvCmdOption; + RlvCommandOptionHelper::parseOption(rlvCmd.getOption(), rlvCmdOption); + if (rlvCmdOption.isSharedFolder()) + return gRlvHandler.onForceWear(rlvCmdOption.getSharedFolder(), rlvCmd.getBehaviourFlags()); + + if ( (!rlvCmdOption.isWearableType()) && (!rlvCmdOption.isEmpty()) ) + return RLV_RET_FAILED_OPTION; + + for (int idxType = 0; idxType < LLWearableType::WT_COUNT; idxType++) + { + if ( (rlvCmdOption.isEmpty()) || ((LLWearableType::EType)idxType == rlvCmdOption.getWearableType())) + RlvForceWear::instance().forceRemove((LLWearableType::EType)idxType); + } + return RLV_RET_SUCCESS; +} + +// Handles: @setcam_eyeoffset[:<vector3>]=force and @setcam_focusoffset[:<vector3>]=force +template<> template<> +ERlvCmdRet RlvForceCamEyeFocusOffsetHandler::onCommand(const RlvCommand& rlvCmd) +{ + // Enforce exclusive camera locks + if (!RlvActions::canChangeCameraPreset(rlvCmd.getObjectID())) + return RLV_RET_FAILED_LOCK; + + LLControlVariable* pOffsetControl = gSavedSettings.getControl("CameraOffsetRLVaView"); + LLControlVariable* pFocusControl = gSavedSettings.getControl("FocusOffsetRLVaView"); + LLControlVariable* pControl = (rlvCmd.getBehaviourType() == RLV_BHVR_SETCAM_EYEOFFSET) ? pOffsetControl : pFocusControl; + if (rlvCmd.hasOption()) + { + LLVector3 vecOffset; + if (!RlvCommandOptionHelper::parseOption(rlvCmd.getOption(), vecOffset)) + return RLV_RET_FAILED_OPTION; + pControl->setValue(vecOffset.getValue()); + } + else + { + pControl->resetToDefault(); + } + + gAgentCamera.switchCameraPreset( ((pOffsetControl->isDefault()) && (pFocusControl->isDefault())) ? CAMERA_PRESET_REAR_VIEW : CAMERA_RLV_SETCAM_VIEW); + return RLV_RET_SUCCESS; +} + +// Handles: @setcam_focus:<uuid>[;<dist>[;<direction>]]=force +template<> template<> +ERlvCmdRet RlvForceHandler<RLV_BHVR_SETCAM_FOCUS>::onCommand(const RlvCommand& rlvCmd) +{ + std::vector<std::string> optionList; + if (!RlvCommandOptionHelper::parseStringList(rlvCmd.getOption(), optionList)) + return RLV_RET_FAILED_OPTION; + + LLVector3 posAgent; + LLVector3d posGlobal; + F32 camDistance; + + // Get the focus position/object (and verify it is known) + LLUUID idObject; LLVector3 posRegion; + if (RlvCommandOptionHelper::parseOption(optionList[0], idObject)) + { + const LLViewerObject* pObj = gObjectList.findObject(idObject); + if (!pObj) + return RLV_RET_FAILED_OPTION; + if (!pObj->isAvatar()) + { + posAgent = pObj->getPositionAgent(); + posGlobal = pObj->getPositionGlobal(); + } + else + { + /*const*/ LLVOAvatar* pAvatar = (/*const*/ LLVOAvatar*)pObj; + if (pAvatar->mHeadp) + { + posAgent = pAvatar->mHeadp->getWorldPosition(); + posGlobal = pAvatar->getPosGlobalFromAgent(posAgent); + } + } + camDistance = pObj->getScale().magVec(); + } + else if (RlvCommandOptionHelper::parseOption(optionList[0], posRegion)) + { + const LLViewerRegion* pRegion = gAgent.getRegion(); + if (!pRegion) + return RLV_RET_FAILED_UNKNOWN; + posAgent = pRegion->getPosAgentFromRegion(posRegion); + posGlobal = pRegion->getPosGlobalFromRegion(posRegion); + camDistance = 0.0f; + } + else + { + return RLV_RET_FAILED_OPTION; + } + + // Get the camera distance + if ( (optionList.size() > 1) && (!optionList[1].empty()) ) + { + if (!RlvCommandOptionHelper::parseOption(optionList[1], camDistance)) + return RLV_RET_FAILED_OPTION; + } + + // Get the directional vector (or calculate it from the current camera position) + LLVector3 camDirection; + if ( (optionList.size() > 2) && (!optionList[2].empty()) ) + { + if (!RlvCommandOptionHelper::parseOption(optionList[2], camDirection)) + return RLV_RET_FAILED_OPTION; + } + else + { + camDirection = LLViewerCamera::getInstance()->getOrigin() - posAgent; + } + camDirection.normVec(); + + // Move the camera in place + gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE); + gAgentCamera.setCameraPosAndFocusGlobal(posGlobal + LLVector3d(camDirection * llmax(F_APPROXIMATELY_ZERO, camDistance)), posGlobal, idObject); + + return RLV_RET_SUCCESS; +} + +// Handles: @setcam_fov[:<angle>]=force +template<> template<> +ERlvCmdRet RlvForceHandler<RLV_BHVR_SETCAM_FOV>::onCommand(const RlvCommand& rlvCmd) +{ + if (!RlvActions::canChangeCameraFOV(rlvCmd.getObjectID())) + return RLV_RET_FAILED_LOCK; + + F32 nFOV = DEFAULT_FIELD_OF_VIEW; + if ( (rlvCmd.hasOption()) && (!RlvCommandOptionHelper::parseOption(rlvCmd.getOption(), nFOV)) ) + return RLV_RET_FAILED_OPTION; + + LLViewerCamera::getInstance()->setDefaultFOV(nFOV); + + // Don't persist non-default changes that are due to RLV; but do resume persistance once reset back to the default + if ( (!gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_FOVMIN)) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_FOVMAX)) ) + { + if (LLControlVariable* pSetting = gSavedSettings.getControl("CameraAngle")) + pSetting->setPersist( (pSetting->isDefault()) ? LLControlVariable::PERSIST_NONDFT : LLControlVariable::PERSIST_NO ); + } + + return RLV_RET_SUCCESS; +} + +// Handles: @setcam_mode[:<option>]=force +template<> template<> +ERlvCmdRet RlvForceHandler<RLV_BHVR_SETCAM_MODE>::onCommand(const RlvCommand& rlvCmd) +{ + const std::string& strOption = rlvCmd.getOption(); + if ("mouselook" == strOption) + gAgentCamera.changeCameraToMouselook(); + else if ("thirdperson" == strOption) + gAgentCamera.changeCameraToThirdPerson(); + else if ( ("reset" == strOption) || (strOption.empty()) ) + handle_reset_view(); + else + return RLV_RET_FAILED_OPTION; + return RLV_RET_SUCCESS; +} + +// Checked: 2010-08-30 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c +ERlvCmdRet RlvHandler::onForceWear(const LLViewerInventoryCategory* pFolder, U32 nFlags) const +{ + if ( (!pFolder) || (!RlvInventory::instance().isSharedFolder(pFolder->getUUID())) ) + return RLV_RET_FAILED_OPTION; + + RlvForceWear::EWearAction eAction = (RlvBehaviourInfo::FORCEWEAR_WEAR_REMOVE & nFlags) ? RlvForceWear::ACTION_REMOVE + : ((RlvBehaviourInfo::FORCEWEAR_WEAR_ADD & nFlags) ? RlvForceWear::ACTION_WEAR_ADD + : RlvForceWear::ACTION_WEAR_REPLACE); + RlvForceWear::EWearFlags eFlags = (RlvBehaviourInfo::FORCEWEAR_SUBTREE & nFlags) ? RlvForceWear::FLAG_MATCHALL : RlvForceWear::FLAG_DEFAULT; + + RlvForceWear::instance().forceFolder(pFolder, eAction, eFlags); + return RLV_RET_SUCCESS; +} + +void RlvHandler::onForceWearCallback(const uuid_vec_t& idItems, U32 nFlags) const +{ + LLInventoryModel::cat_array_t folders; + if (RlvInventory::instance().getPath(idItems, folders)) + { + for (S32 idxFolder = 0, cntFolder = folders.size(); idxFolder < cntFolder; idxFolder++) + onForceWear(folders.at(idxFolder), nFlags); + + // If we're not executing a command then we're a delayed callback and need to manually call done() + if ( (!getCurrentCommand()) && (RlvForceWear::instanceExists()) ) + RlvForceWear::instance().done(); + } +} + +// Handles: @setgroup:<uuid|name>=force +template<> template<> +ERlvCmdRet RlvForceHandler<RLV_BHVR_SETGROUP>::onCommand(const RlvCommand& rlvCmd) +{ + if (!RlvActions::canChangeActiveGroup(rlvCmd.getObjectID())) + { + return RLV_RET_FAILED_LOCK; + } + + LLUUID idGroup; bool fValid = false; + if (idGroup.set(rlvCmd.getOption())) + { + fValid = (idGroup.isNull()) || (gAgent.isInGroup(idGroup, true)); + } + else + { + for (S32 idxGroup = 0, cntGroup = gAgent.mGroups.size(); (idxGroup < cntGroup) && (idGroup.isNull()); idxGroup++) + if (boost::iequals(gAgent.mGroups.at(idxGroup).mName, rlvCmd.getOption())) + idGroup = gAgent.mGroups.at(idxGroup).mID; + fValid = (idGroup.notNull()) || ("none" == rlvCmd.getOption()); + } + + if (fValid) + { + gRlvHandler.m_idAgentGroup = idGroup; + LLGroupActions::activate(idGroup); + } + + return (fValid) ? RLV_RET_SUCCESS : RLV_RET_FAILED_OPTION; +} + +// Handles: @sit:<uuid>=force +template<> template<> +ERlvCmdRet RlvForceHandler<RLV_BHVR_SIT>::onCommand(const RlvCommand& rlvCmd) +{ + LLViewerObject* pObj = NULL; LLUUID idTarget(rlvCmd.getOption()); + // Sanity checking - we need to know about the object and it should identify a prim/linkset + if ( (idTarget.isNull()) || ((pObj = gObjectList.findObject(idTarget)) == NULL) || (LL_PCODE_VOLUME != pObj->getPCode()) ) + return RLV_RET_FAILED_OPTION; + + if (!RlvActions::canSit(pObj)) + return RLV_RET_FAILED_LOCK; + else if ( (gRlvHandler.hasBehaviour(RLV_BHVR_STANDTP)) && (isAgentAvatarValid()) ) + { + if (gAgentAvatarp->isSitting()) + return RLV_RET_FAILED_LOCK; + gRlvHandler.m_posSitSource = gAgent.getPositionGlobal(); + } + + // Copy/paste from handle_sit_or_stand() + gMessageSystem->newMessageFast(_PREHASH_AgentRequestSit); + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + gMessageSystem->nextBlockFast(_PREHASH_TargetObject); + gMessageSystem->addUUIDFast(_PREHASH_TargetID, pObj->mID); + gMessageSystem->addVector3Fast(_PREHASH_Offset, LLVector3::zero); + pObj->getRegion()->sendReliableMessage(); + + return RLV_RET_SUCCESS; +} + +// Handles: @tpto:<vector>[;<angle>]=force and @tpto:<region>/<vector>[;<angle>]=force +template<> template<> +ERlvCmdRet RlvForceHandler<RLV_BHVR_TPTO>::onCommand(const RlvCommand& rlvCmd) +{ + std::vector<std::string> optionList; + if (!RlvCommandOptionHelper::parseStringList(rlvCmd.getOption(), optionList)) + return RLV_RET_FAILED_OPTION; + + // We need the look-at first + LLVector3 vecLookAt = LLVector3::zero; + if (optionList.size() > 1) + { + float nAngle = 0.0f; + if (!RlvCommandOptionHelper::parseOption(optionList[1], nAngle)) + return RLV_RET_FAILED_OPTION; + + vecLookAt = LLVector3::x_axis; + vecLookAt.rotVec(nAngle, LLVector3::z_axis); + vecLookAt.normalize(); + } + + // Next figure out the destination + LLVector3d posGlobal; + if (RlvCommandOptionHelper::parseOption(optionList[0], posGlobal)) + { + if (optionList.size() == 1) + gAgent.teleportViaLocation(posGlobal); + else + gAgent.teleportViaLocationLookAt(posGlobal, vecLookAt); + } + else + { + std::vector<std::string> posList; LLVector3 posRegion; + if ( (!RlvCommandOptionHelper::parseStringList(optionList[0], posList, std::string("/"))) || (4 != posList.size()) || + (!RlvCommandOptionHelper::parseOption(optionList[0].substr(posList[0].size() + 1), posRegion)) ) + { + return RLV_RET_FAILED_OPTION; + } + + LLWorldMapMessage::url_callback_t cb = boost::bind(&RlvUtil::teleportCallback, _1, posRegion, vecLookAt); + LLWorldMapMessage::getInstance()->sendNamedRegionRequest(posList[0], cb, std::string(""), true); + } + + return RLV_RET_SUCCESS; +} + +// ============================================================================ +// Command handlers (RLV_TYPE_REPLY) +// + +ERlvCmdRet RlvCommandHandlerBaseImpl<RLV_TYPE_REPLY>::processCommand(const RlvCommand& rlvCmd, RlvReplyHandlerFunc* pHandler) +{ + // Sanity check - <param> should specify a - valid - reply channel + S32 nChannel; + if ( (!LLStringUtil::convertToS32(rlvCmd.getParam(), nChannel)) || (!RlvUtil::isValidReplyChannel(nChannel, rlvCmd.getObjectID() == gAgent.getID())) ) + return RLV_RET_FAILED_PARAM; + + std::string strReply; + ERlvCmdRet eRet = (*pHandler)(rlvCmd, strReply); + + // If we made it this far then: + // - the command was handled successfully so we send off the response + // - the command failed but we still send off an - empty - response to keep the issuing script from blocking + if (nChannel != 0) + RlvUtil::sendChatReply(nChannel, strReply); + else + { + if (RlvFloaterConsole* pConsole = LLFloaterReg::findTypedInstance<RlvFloaterConsole>("rlv_console")) + pConsole->addCommandReply(rlvCmd.getBehaviour(), strReply); + } + + return eRet; +} + +// Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.1.0f +ERlvCmdRet RlvHandler::processReplyCommand(const RlvCommand& rlvCmd) const +{ + RLV_ASSERT(RLV_TYPE_REPLY == rlvCmd.getParamType()); + + // Try a command processor first + ERlvCmdRet eRet = rlvCmd.processCommand(); + if (RLV_RET_NO_PROCESSOR != eRet) + { + return eRet; + } + + // Sanity check - <param> should specify a - valid - reply channel + S32 nChannel; + if ( (!LLStringUtil::convertToS32(rlvCmd.getParam(), nChannel)) || (!RlvUtil::isValidReplyChannel(nChannel, rlvCmd.getObjectID() == gAgent.getID())) ) + return RLV_RET_FAILED_PARAM; + + // Process the command the legacy way + eRet = RLV_RET_SUCCESS; std::string strReply; + switch (rlvCmd.getBehaviourType()) + { + case RLV_BHVR_VERSION: // @version=<channel> - Checked: 2010-03-27 (RLVa-1.4.0a) + case RLV_BHVR_VERSIONNEW: // @versionnew=<channel> - Checked: 2010-03-27 (RLVa-1.4.0a) | Added: RLVa-1.2.0b + // NOTE: RLV will respond even if there's an option + strReply = RlvStrings::getVersion(rlvCmd.getObjectID(), RLV_BHVR_VERSION == rlvCmd.getBehaviourType()); + break; + case RLV_BHVR_VERSIONNUM: // @versionnum=<channel> - Checked: 2010-03-27 (RLVa-1.4.0a) | Added: RLVa-1.0.4b + // NOTE: RLV will respond even if there's an option + strReply = RlvStrings::getVersionNum(rlvCmd.getObjectID()); + break; + case RLV_BHVR_GETATTACH: // @getattach[:<layer>]=<channel> + eRet = onGetAttach(rlvCmd, strReply); + break; + case RLV_BHVR_GETATTACHNAMES: // @getattachnames[:<grp>]=<channel> + case RLV_BHVR_GETADDATTACHNAMES:// @getaddattachnames[:<grp>]=<channel> + case RLV_BHVR_GETREMATTACHNAMES:// @getremattachnames[:<grp>]=<channel> + eRet = onGetAttachNames(rlvCmd, strReply); + break; + case RLV_BHVR_GETOUTFIT: // @getoutfit[:<layer>]=<channel> + eRet = onGetOutfit(rlvCmd, strReply); + break; + case RLV_BHVR_GETOUTFITNAMES: // @getoutfitnames=<channel> + case RLV_BHVR_GETADDOUTFITNAMES:// @getaddoutfitnames=<channel> + case RLV_BHVR_GETREMOUTFITNAMES:// @getremoutfitnames=<channel> + eRet = onGetOutfitNames(rlvCmd, strReply); + break; + case RLV_BHVR_FINDFOLDER: // @findfolder:<criteria>=<channel> + case RLV_BHVR_FINDFOLDERS: // @findfolders:<criteria>=<channel> + eRet = onFindFolder(rlvCmd, strReply); + break; + case RLV_BHVR_GETPATH: // @getpath[:<option>]=<channel> + case RLV_BHVR_GETPATHNEW: // @getpathnew[:<option>]=<channel> + eRet = onGetPath(rlvCmd, strReply); + break; + case RLV_BHVR_GETINV: // @getinv[:<path>]=<channel> + eRet = onGetInv(rlvCmd, strReply); + break; + case RLV_BHVR_GETINVWORN: // @getinvworn[:<path>]=<channel> + eRet = onGetInvWorn(rlvCmd, strReply); + break; + case RLV_BHVR_GETGROUP: // @getgroup=<channel> - Checked: 2011-03-28 (RLVa-1.4.1a) | Added: RLVa-1.3.0f + strReply = (gAgent.getGroupID().notNull()) ? gAgent.getGroupName() : "none"; + break; + case RLV_BHVR_GETSITID: // @getsitid=<channel> - Checked: 2010-03-09 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a + { + // NOTE: RLV-1.16.1 returns a NULL UUID if we're not sitting + LLUUID idSitObj; + if ( (isAgentAvatarValid()) && (gAgentAvatarp->isSitting()) ) + { + const LLViewerObject* pSeatObj = dynamic_cast<LLViewerObject*>(gAgentAvatarp->getRoot()); + if (pSeatObj) + idSitObj = pSeatObj->getID(); + } + strReply = idSitObj.asString(); + } + break; + case RLV_BHVR_GETSTATUS: // @getstatus - Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.1.0f + { + std::string strFilter, strSeparator; + if (rlvParseGetStatusOption(rlvCmd.getOption(), strFilter, strSeparator)) + { + // NOTE: specification says response should start with '/' but RLV-1.16.1 returns an empty string when no rules are set + rlv_object_map_t::const_iterator itObj = m_Objects.find(rlvCmd.getObjectID()); + if (itObj != m_Objects.end()) + strReply = itObj->second.getStatusString(strFilter, strSeparator); + } + } + break; + case RLV_BHVR_GETSTATUSALL: // @getstatusall - Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.1.0f + { + std::string strFilter, strSeparator; + if (rlvParseGetStatusOption(rlvCmd.getOption(), strFilter, strSeparator)) + { + // NOTE: specification says response should start with '/' but RLV-1.16.1 returns an empty string when no rules are set + for (rlv_object_map_t::const_iterator itObj = m_Objects.begin(); itObj != m_Objects.end(); ++itObj) + strReply += itObj->second.getStatusString(strFilter, strSeparator); + } + } + break; + case RLV_BHVR_UNKNOWN: + // Pass unknown commands on to registered command handlers + return (notifyCommandHandlers(&RlvExtCommandHandler::onReplyCommand, rlvCmd, eRet, false)) ? eRet : RLV_RET_FAILED_UNKNOWN; + default: + // Fail with "Invalid param" if none of the above handled it + return RLV_RET_FAILED_PARAM; + } + + // If we made it this far then: + // - the command was handled successfully so we send off the response + // - the command failed but we still send off an - empty - response to keep the issuing script from blocking + if (nChannel > 0) + RlvUtil::sendChatReply(nChannel, strReply); + else + { + if (RlvFloaterConsole* pConsole = LLFloaterReg::findTypedInstance<RlvFloaterConsole>("rlv_console")) + pConsole->addCommandReply(rlvCmd.getBehaviour(), strReply); + } + + return eRet; +} + +// Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.1.0f +ERlvCmdRet RlvHandler::onFindFolder(const RlvCommand& rlvCmd, std::string& strReply) const +{ + RLV_ASSERT(RLV_TYPE_REPLY == rlvCmd.getParamType()); + RLV_ASSERT( (RLV_BHVR_FINDFOLDER == rlvCmd.getBehaviourType()) || (RLV_BHVR_FINDFOLDERS == rlvCmd.getBehaviourType()) ); + + // (Compatibility: RLV 1.16.1 returns the first random folder it finds while we return a blank on no option) + if (rlvCmd.getOption().empty()) + return RLV_RET_FAILED_OPTION; + + LLInventoryModel::cat_array_t folders; + if (RlvInventory::instance().findSharedFolders(rlvCmd.getOption(), folders)) + { + if (RLV_BHVR_FINDFOLDER == rlvCmd.getBehaviourType()) + { + // We need to return an "in depth" result so whoever has the most '/' is our lucky winner + // (maxSlashes needs to be initialized to -1 since children of the #RLV folder won't have '/' in their shared path) + int maxSlashes = -1, curSlashes; std::string strFolderName; + for (S32 idxFolder = 0, cntFolder = folders.size(); idxFolder < cntFolder; idxFolder++) + { + strFolderName = RlvInventory::instance().getSharedPath(folders.at(idxFolder)); + + curSlashes = std::count(strFolderName.begin(), strFolderName.end(), '/'); + if (curSlashes > maxSlashes) + { + maxSlashes = curSlashes; + strReply = strFolderName; + } + } + } + else if (RLV_BHVR_FINDFOLDERS == rlvCmd.getBehaviourType()) + { + for (S32 idxFolder = 0, cntFolder = folders.size(); idxFolder < cntFolder; idxFolder++) + { + if (!strReply.empty()) + strReply.push_back(','); + strReply += RlvInventory::instance().getSharedPath(folders.at(idxFolder)); + } + } + } + return RLV_RET_SUCCESS; +} + +// Checked: 2010-03-19 (RLVa-1.4.0a) | Modified: RLVa-1.1.0e +ERlvCmdRet RlvHandler::onGetAttach(const RlvCommand& rlvCmd, std::string& strReply) const +{ + RLV_ASSERT(RLV_TYPE_REPLY == rlvCmd.getParamType()); + RLV_ASSERT(RLV_BHVR_GETATTACH == rlvCmd.getBehaviourType()); + + if (!isAgentAvatarValid()) + return RLV_RET_FAILED; + + // Sanity check - <option> should specify an attachment point or be empty + S32 idxAttachPt = 0; + if ( (rlvCmd.hasOption()) && ((idxAttachPt = RlvAttachPtLookup::getAttachPointIndex(rlvCmd.getOption())) == 0) ) + return RLV_RET_FAILED_OPTION; + + // If we're fetching all worn attachments then the reply should start with 0 + if (0 == idxAttachPt) + strReply.push_back('0'); + + for (LLVOAvatar::attachment_map_t::const_iterator itAttach = gAgentAvatarp->mAttachmentPoints.begin(); + itAttach != gAgentAvatarp->mAttachmentPoints.end(); ++itAttach) + { + const LLViewerJointAttachment* pAttachPt = itAttach->second; + if ( (0 == idxAttachPt) || (itAttach->first == idxAttachPt) ) + { + bool fWorn = (pAttachPt->getNumObjects() > 0) && + ( (!RlvSettings::getHideLockedAttach()) || (RlvForceWear::isForceDetachable(pAttachPt, true, rlvCmd.getObjectID())) ); + strReply.push_back( (fWorn) ? '1' : '0' ); + } + } + return RLV_RET_SUCCESS; +} + +// Checked: 2011-05-28 (RLVa-1.4.0a) | Modified: RLVa-1.4.0a +ERlvCmdRet RlvHandler::onGetAttachNames(const RlvCommand& rlvCmd, std::string& strReply) const +{ + RLV_ASSERT(RLV_TYPE_REPLY == rlvCmd.getParamType()); + RLV_ASSERT( (RLV_BHVR_GETATTACHNAMES == rlvCmd.getBehaviourType()) || (RLV_BHVR_GETADDATTACHNAMES == rlvCmd.getBehaviourType()) || + (RLV_BHVR_GETREMATTACHNAMES == rlvCmd.getBehaviourType()) ); + + if (!isAgentAvatarValid()) + return RLV_RET_FAILED; + + ERlvAttachGroupType eAttachGroup = rlvAttachGroupFromString(rlvCmd.getOption()); + for (LLVOAvatar::attachment_map_t::const_iterator itAttach = gAgentAvatarp->mAttachmentPoints.begin(); + itAttach != gAgentAvatarp->mAttachmentPoints.end(); ++itAttach) + { + const LLViewerJointAttachment* pAttachPt = itAttach->second; + if ( (RLV_ATTACHGROUP_INVALID == eAttachGroup) || (rlvAttachGroupFromIndex(pAttachPt->getGroup()) == eAttachGroup) ) + { + bool fAdd = false; + switch (rlvCmd.getBehaviourType()) + { + case RLV_BHVR_GETATTACHNAMES: // Every attachment point that has an attached object + fAdd = (pAttachPt->getNumObjects() > 0); + break; + case RLV_BHVR_GETADDATTACHNAMES: // Every attachment point that can be attached to (wear replace OR wear add) + fAdd = (gRlvAttachmentLocks.canAttach(pAttachPt) & RLV_WEAR); + break; + case RLV_BHVR_GETREMATTACHNAMES: // Every attachment point that has at least one attachment that can be force-detached + fAdd = RlvForceWear::isForceDetachable(pAttachPt); + break; + default: + break; + } + + if (fAdd) + { + if (!strReply.empty()) + strReply.push_back(','); + strReply.append(pAttachPt->getName()); + } + } + } + return RLV_RET_SUCCESS; +} + +// Handles: @getcam_avdist=<channel> +template<> template<> +ERlvCmdRet RlvReplyHandler<RLV_BHVR_GETCAM_AVDIST>::onCommand(const RlvCommand& rlvCmd, std::string& strReply) +{ + if (rlvCmd.hasOption()) + return RLV_RET_FAILED_OPTION; + strReply = llformat("%.3lf", (gAgentCamera.getCameraPositionGlobal() - gAgent.getPositionGlobal()).magVec()); + return RLV_RET_SUCCESS; +} + +// Handles: @getcam_avdistmin=<channel>, @getcam_avdistmax=<channel>, @getcam_fovmin=<channel> and @getcam_fovmax=<channel> +template<> template<> +ERlvCmdRet RlvReplyCamMinMaxModifierHandler::onCommand(const RlvCommand& rlvCmd, std::string& strReply) +{ + if ( (rlvCmd.hasOption()) || (!boost::starts_with(rlvCmd.getBehaviour(), "getcam_")) ) + return RLV_RET_FAILED_OPTION; + ERlvBehaviour eBhvr = RlvBehaviourDictionary::instance().getBehaviourFromString("setcam_" + rlvCmd.getBehaviour().substr(7), RLV_TYPE_ADDREM); + if (RlvBehaviourModifier* pBhvrModifier = RlvBehaviourDictionary::instance().getModifierFromBehaviour(eBhvr)) + strReply = (pBhvrModifier->hasValue()) ? llformat("%.3f", pBhvrModifier->getValue<float>()) : LLStringUtil::null; + return RLV_RET_SUCCESS; +} + +// Handles: @camzoommin/max[:<multiplier>]=n|y - DEPRECATED +template<> template<> +ERlvCmdRet RlvBehaviourCamZoomMinMaxHandler::onCommand(const RlvCommand& rlvCmd, bool& fRefCount) +{ + // NOTE: @camzoommin/max are implemented as semi-synonyms of @setcam_fovmin/max + F32 nMult = 1.0f; + if ( (rlvCmd.hasOption()) && (!RlvCommandOptionHelper::parseOption(rlvCmd.getOption(), nMult)) ) + return RLV_RET_FAILED_OPTION; + + RlvBehaviourModifier* pBhvrModifier = RlvBehaviourDictionary::instance().getModifier( (RLV_BHVR_CAMZOOMMIN == rlvCmd.getBehaviourType()) ? RLV_MODIFIER_SETCAM_FOVMIN : RLV_MODIFIER_SETCAM_FOVMAX); + if (pBhvrModifier) + { + if (RLV_TYPE_ADD == rlvCmd.getParamType()) + { + gRlvHandler.m_Behaviours[(RLV_BHVR_CAMZOOMMIN == rlvCmd.getBehaviourType()) ? RLV_BHVR_SETCAM_FOVMIN : RLV_BHVR_SETCAM_FOVMAX]++; + pBhvrModifier->addValue(DEFAULT_FIELD_OF_VIEW / nMult, rlvCmd.getObjectID()); + } + else + { + gRlvHandler.m_Behaviours[(RLV_BHVR_CAMZOOMMIN == rlvCmd.getBehaviourType()) ? RLV_BHVR_SETCAM_FOVMIN : RLV_BHVR_SETCAM_FOVMAX]--; + pBhvrModifier->removeValue(DEFAULT_FIELD_OF_VIEW / nMult, rlvCmd.getObjectID()); + } + } + + fRefCount = true; + return RLV_RET_SUCCESS; +} + +// Handles: @getcam_fov=<channel> +template<> template<> +ERlvCmdRet RlvReplyHandler<RLV_BHVR_GETCAM_FOV>::onCommand(const RlvCommand& rlvCmd, std::string& strReply) +{ + if (rlvCmd.hasOption()) + return RLV_RET_FAILED_OPTION; + strReply = llformat("%.3f", LLViewerCamera::getInstance()->getDefaultFOV()); + return RLV_RET_SUCCESS; +} + +// Handles: @getcam_textures=<channel> +template<> template<> +ERlvCmdRet RlvReplyHandler<RLV_BHVR_GETCAM_TEXTURES>::onCommand(const RlvCommand& rlvCmd, std::string& strReply) +{ + if (rlvCmd.hasOption()) + return RLV_RET_FAILED_OPTION; + if (RlvBehaviourModifier* pBhvrModifier = RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_SETCAM_TEXTURE)) + strReply = (pBhvrModifier->hasValue()) ? pBhvrModifier->getValue<LLUUID>().asString() : LLStringUtil::null; + return RLV_RET_SUCCESS; +} + +// Handles: @getcommand[:<behaviour>[;<type>[;<separator>]]]=<channel> +template<> template<> +ERlvCmdRet RlvReplyHandler<RLV_BHVR_GETCOMMAND>::onCommand(const RlvCommand& rlvCmd, std::string& strReply) +{ + std::vector<std::string> optionList; + RlvCommandOptionHelper::parseStringList(rlvCmd.getOption(), optionList); + + // If a second parameter is present it'll specify the command type + ERlvParamType eType = RLV_TYPE_UNKNOWN; + if (optionList.size() >= 2) + { + if ( (optionList[1] == "any") || (optionList[1].empty()) ) + eType = RLV_TYPE_UNKNOWN; + else if (optionList[1] == "add") + eType = RLV_TYPE_ADDREM; + else if (optionList[1] == "force") + eType = RLV_TYPE_FORCE; + else if (optionList[1] == "reply") + eType = RLV_TYPE_REPLY; + else + return RLV_RET_FAILED_OPTION; + } + + std::list<std::string> cmdList; + if (RlvBehaviourDictionary::instance().getCommands((optionList.size() >= 1) ? optionList[0] : LLStringUtil::null, eType, cmdList)) + strReply = boost::algorithm::join(cmdList, (optionList.size() >= 3) ? optionList[2] : std::string(RLV_OPTION_SEPARATOR) ); + return RLV_RET_SUCCESS; +} + +// Checked: 2010-03-09 (RLVa-1.2.0a) | Modified: RLVa-1.1.0f +ERlvCmdRet RlvHandler::onGetInv(const RlvCommand& rlvCmd, std::string& strReply) const +{ + RLV_ASSERT(RLV_TYPE_REPLY == rlvCmd.getParamType()); + RLV_ASSERT(RLV_BHVR_GETINV == rlvCmd.getBehaviourType()); + + const LLViewerInventoryCategory* pFolder = RlvInventory::instance().getSharedFolder(rlvCmd.getOption()); + if (!pFolder) + return (RlvInventory::instance().getSharedRoot() != NULL) ? RLV_RET_FAILED_OPTION : RLV_RET_FAILED_NOSHAREDROOT; + + LLInventoryModel::cat_array_t* pFolders; LLInventoryModel::item_array_t* pItems; + gInventory.getDirectDescendentsOf(pFolder->getUUID(), pFolders, pItems); + if (!pFolders) + return RLV_RET_FAILED; + + for (S32 idxFolder = 0, cntFolder = pFolders->size(); idxFolder < cntFolder; idxFolder++) + { + // Return all folders that: + // - aren't hidden + // - aren't a folded folder (only really matters when "Enable Legacy Naming" is enabled - see related blog post) + // (we can skip checking for .<composite> folders since the ones we'll want to hide start with '.' anyway) + const std::string& strFolder = pFolders->at(idxFolder)->getName(); + if ( (!strFolder.empty()) && (RLV_FOLDER_PREFIX_HIDDEN != strFolder[0]) && + (!RlvInventory::isFoldedFolder(pFolders->at(idxFolder).get(), false)) ) + { + if (!strReply.empty()) + strReply.push_back(','); + strReply += strFolder; + } + } + return RLV_RET_SUCCESS; +} + +struct rlv_wear_info { U32 cntWorn, cntTotal, cntChildWorn, cntChildTotal; }; + +// Checked: 2010-04-05 (RLVa-1.2.0d) | Modified: RLVa-1.1.0f +ERlvCmdRet RlvHandler::onGetInvWorn(const RlvCommand& rlvCmd, std::string& strReply) const +{ + // Sanity check - gAgentAvatarp can't be NULL [see RlvForceWear::isWearingItem()] + if (!isAgentAvatarValid()) + return RLV_RET_FAILED; + // Sanity check - folder should exist + LLViewerInventoryCategory* pFolder = RlvInventory::instance().getSharedFolder(rlvCmd.getOption()); + if (!pFolder) + return (RlvInventory::instance().getSharedRoot() != NULL) ? RLV_RET_FAILED_OPTION : RLV_RET_FAILED_NOSHAREDROOT; + + // Collect everything @attachall would be attaching + LLInventoryModel::cat_array_t folders; LLInventoryModel::item_array_t items; + RlvWearableItemCollector f(pFolder, RlvForceWear::ACTION_WEAR_REPLACE, RlvForceWear::FLAG_MATCHALL); + gInventory.collectDescendentsIf(pFolder->getUUID(), folders, items, FALSE, f, true); + + rlv_wear_info wi = {0}; + + // Add all the folders to a lookup map + std::map<LLUUID, rlv_wear_info> mapFolders; + mapFolders.insert(std::pair<LLUUID, rlv_wear_info>(pFolder->getUUID(), wi)); + for (S32 idxFolder = 0, cntFolder = folders.size(); idxFolder < cntFolder; idxFolder++) + mapFolders.insert(std::pair<LLUUID, rlv_wear_info>(folders.at(idxFolder)->getUUID(), wi)); + + // Iterate over all the found items + LLViewerInventoryItem* pItem; std::map<LLUUID, rlv_wear_info>::iterator itFolder; + for (S32 idxItem = 0, cntItem = items.size(); idxItem < cntItem; idxItem++) + { + pItem = items.at(idxItem); + if (!RlvForceWear::isWearableItem(pItem)) + continue; + + // The "folded parent" is the folder this item should be considered a direct descendent of (may or may not match actual parent) + const LLUUID& idParent = f.getFoldedParent(pItem->getParentUUID()); + + // Walk up the tree: sooner or later one of the parents will be a folder in the map + LLViewerInventoryCategory* pParent = gInventory.getCategory(idParent); + while ( (itFolder = mapFolders.find(pParent->getUUID())) == mapFolders.end() ) + pParent = gInventory.getCategory(pParent->getParentUUID()); + + U32 &cntWorn = (idParent == pParent->getUUID()) ? itFolder->second.cntWorn : itFolder->second.cntChildWorn, + &cntTotal = (idParent == pParent->getUUID()) ? itFolder->second.cntTotal : itFolder->second.cntChildTotal; + + if (RlvForceWear::isWearingItem(pItem)) + cntWorn++; + cntTotal++; + } + + // Extract the result for the main folder + itFolder = mapFolders.find(pFolder->getUUID()); + wi.cntWorn = itFolder->second.cntWorn; + wi.cntTotal = itFolder->second.cntTotal; + mapFolders.erase(itFolder); + + // Build the result for each child folder + for (itFolder = mapFolders.begin(); itFolder != mapFolders.end(); ++itFolder) + { + rlv_wear_info& wiFolder = itFolder->second; + + wi.cntChildWorn += wiFolder.cntWorn + wiFolder.cntChildWorn; + wi.cntChildTotal += wiFolder.cntTotal + wiFolder.cntChildTotal; + + strReply += llformat(",%s|%d%d", gInventory.getCategory(itFolder->first)->getName().c_str(), + (0 == wiFolder.cntTotal) ? 0 : (0 == wiFolder.cntWorn) ? 1 : (wiFolder.cntWorn != wiFolder.cntTotal) ? 2 : 3, + (0 == wiFolder.cntChildTotal) ? 0 : (0 == wiFolder.cntChildWorn) ? 1 : (wiFolder.cntChildWorn != wiFolder.cntChildTotal) ? 2 : 3 + ); + } + + // Now just prepend the root and done + strReply = llformat("|%d%d", (0 == wi.cntTotal) ? 0 : (0 == wi.cntWorn) ? 1 : (wi.cntWorn != wi.cntTotal) ? 2 : 3, + (0 == wi.cntChildTotal) ? 0 : (0 == wi.cntChildWorn) ? 1 : (wi.cntChildWorn != wi.cntChildTotal) ? 2: 3) + strReply; + + return RLV_RET_SUCCESS; +} + +// Checked: 2010-03-19 (RLVa-1.4.0a) | Modified: RLVa-1.2.0a +ERlvCmdRet RlvHandler::onGetOutfit(const RlvCommand& rlvCmd, std::string& strReply) const +{ + RLV_ASSERT(RLV_TYPE_REPLY == rlvCmd.getParamType()); + RLV_ASSERT(RLV_BHVR_GETOUTFIT == rlvCmd.getBehaviourType()); + + // (Compatibility: RLV-1.16.1 will execute @getoutfit=<channel> if <layer> is invalid while we just return failure) + LLWearableType::EType wtType = LLWearableType::WT_INVALID; + if ( (rlvCmd.hasOption()) && ((wtType = LLWearableType::typeNameToType(rlvCmd.getOption())) == LLWearableType::WT_INVALID) ) + return RLV_RET_FAILED_OPTION; + + const LLWearableType::EType wtRlvTypes[] = + { + LLWearableType::WT_GLOVES, LLWearableType::WT_JACKET, LLWearableType::WT_PANTS, LLWearableType::WT_SHIRT, + LLWearableType::WT_SHOES, LLWearableType::WT_SKIRT, LLWearableType::WT_SOCKS, LLWearableType::WT_UNDERPANTS, + LLWearableType::WT_UNDERSHIRT, LLWearableType::WT_SKIN, LLWearableType::WT_EYES, LLWearableType::WT_HAIR, + LLWearableType::WT_SHAPE, LLWearableType::WT_ALPHA, LLWearableType::WT_TATTOO, LLWearableType::WT_PHYSICS + }; + + for (int idxType = 0, cntType = sizeof(wtRlvTypes) / sizeof(LLWearableType::EType); idxType < cntType; idxType++) + { + if ( (LLWearableType::WT_INVALID == wtType) || (wtRlvTypes[idxType] == wtType) ) + { + // We never hide body parts, even if they're "locked" and we're hiding locked layers + // (nor do we hide a layer if the issuing object is the only one that has this layer locked) + bool fWorn = (gAgentWearables.getWearableCount(wtRlvTypes[idxType]) > 0) && + ( (!RlvSettings::getHideLockedLayers()) || + (LLAssetType::AT_BODYPART == LLWearableType::getAssetType(wtRlvTypes[idxType])) || + (RlvForceWear::isForceRemovable(wtRlvTypes[idxType], true, rlvCmd.getObjectID())) ); + strReply.push_back( (fWorn) ? '1' : '0' ); + } + } + return RLV_RET_SUCCESS; +} + +// Checked: 2011-05-28 (RLVa-1.4.0a) | Modified: RLVa-1.4.0a +ERlvCmdRet RlvHandler::onGetOutfitNames(const RlvCommand& rlvCmd, std::string& strReply) const +{ + RLV_ASSERT(RLV_TYPE_REPLY == rlvCmd.getParamType()); + RLV_ASSERT( (RLV_BHVR_GETOUTFITNAMES == rlvCmd.getBehaviourType()) || (RLV_BHVR_GETADDOUTFITNAMES == rlvCmd.getBehaviourType()) || + (RLV_BHVR_GETREMOUTFITNAMES == rlvCmd.getBehaviourType()) ); + + // Sanity check - all these commands are optionless + if (rlvCmd.hasOption()) + return RLV_RET_FAILED_OPTION; + + for (int idxType = 0; idxType < LLWearableType::WT_COUNT; idxType++) + { + bool fAdd = false; LLWearableType::EType wtType = (LLWearableType::EType)idxType; + switch (rlvCmd.getBehaviourType()) + { + case RLV_BHVR_GETOUTFITNAMES: // Every layer that has at least one worn wearable + fAdd = (gAgentWearables.getWearableCount(wtType) > 0); + break; + case RLV_BHVR_GETADDOUTFITNAMES: // Every layer that can be worn on (wear replace OR wear add) + fAdd = (gRlvWearableLocks.canWear(wtType) & RLV_WEAR); + break; + case RLV_BHVR_GETREMOUTFITNAMES: // Every layer that has at least one wearable that can be force-removed + fAdd = RlvForceWear::isForceRemovable(wtType); + break; + default: + break; + } + + if (fAdd) + { + if (!strReply.empty()) + strReply.push_back(','); + strReply.append(LLWearableType::getTypeName(wtType)); + } + } + return RLV_RET_SUCCESS; +} + +// Checked: 2010-08-30 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c +ERlvCmdRet RlvHandler::onGetPath(const RlvCommand& rlvCmd, std::string& strReply) const +{ + RLV_ASSERT(RLV_TYPE_REPLY == rlvCmd.getParamType()); + RLV_ASSERT( (RLV_BHVR_GETPATH == rlvCmd.getBehaviourType()) || (RLV_BHVR_GETPATHNEW == rlvCmd.getBehaviourType()) ); + + RlvCommandOptionGetPath rlvGetPathOption(rlvCmd); + if (!rlvGetPathOption.isValid()) + return RLV_RET_FAILED_OPTION; + + LLInventoryModel::cat_array_t folders; + if (RlvInventory::instance().getPath(rlvGetPathOption.getItemIDs(), folders)) + { + if (RLV_BHVR_GETPATH == rlvCmd.getBehaviourType()) + { + strReply = RlvInventory::instance().getSharedPath(folders.at(0)); + } + else if (RLV_BHVR_GETPATHNEW == rlvCmd.getBehaviourType()) + { + for (S32 idxFolder = 0, cntFolder = folders.size(); idxFolder < cntFolder; idxFolder++) + { + if (!strReply.empty()) + strReply.push_back(','); + strReply += RlvInventory::instance().getSharedPath(folders.at(idxFolder)); + } + } + } + return RLV_RET_SUCCESS; +} + +// ============================================================================ diff --git a/indra/newview/rlvhandler.h b/indra/newview/rlvhandler.h new file mode 100644 index 0000000000000000000000000000000000000000..6cac8be2bd6cfb4b721c198b4a44f95aacf82d36 --- /dev/null +++ b/indra/newview/rlvhandler.h @@ -0,0 +1,255 @@ +/** + * + * Copyright (c) 2009-2016, Kitty Barnett + * + * The source code in this file is provided to you under the terms of the + * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt + * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.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. + * + */ + +#ifndef RLV_HANDLER_H +#define RLV_HANDLER_H + +#include <stack> + +#include "rlvcommon.h" +#if LL_GNUC +#include "rlvhelper.h" // Needed to make GCC happy +#endif // LL_GNUC + +// ============================================================================ + +class RlvHandler : public LLOldEvents::LLSimpleListener +{ +public: + RlvHandler(); + ~RlvHandler(); + + // -------------------------------- + + /* + * Rule checking functions + */ + // NOTE: - to check @detach=n -> (see RlvAttachmentLocks) + // - to check @addattach=n -> (see RlvAttachmentLocks) + // - to check @remattach=n -> (see RlvAttachmentLocks) + // - to check @addoutfit=n -> (see RlvWearableLocks) + // - to check @remoutfit=n -> (see RlvWearableLocks) + // - to check exceptions -> isException() +public: + // Returns a list of all objects containing the specified behaviour + bool findBehaviour(ERlvBehaviour eBhvr, std::list<const RlvObject*>& lObjects) const; + // Returns TRUE is at least one object contains the specified behaviour (and optional option) + bool hasBehaviour(ERlvBehaviour eBhvr) const { return (eBhvr < RLV_BHVR_COUNT) ? (0 != m_Behaviours[eBhvr]) : false; } + bool hasBehaviour(ERlvBehaviour eBhvr, const std::string& strOption) const; + // Returns TRUE if the specified object contains the specified behaviour (and optional option) + bool hasBehaviour(const LLUUID& idObj, ERlvBehaviour eBhvr, const std::string& strOption = LLStringUtil::null) const; + // Returns TRUE if at least one object (except the specified one) contains the specified behaviour (and optional option) + bool hasBehaviourExcept(ERlvBehaviour eBhvr, const LLUUID& idObj) const; + bool hasBehaviourExcept(ERlvBehaviour eBhvr, const std::string& strOption, const LLUUID& idObj) const; + // Returns TRUE if at least one object in the linkset with specified root ID contains the specified behaviour (and optional option) + bool hasBehaviourRoot(const LLUUID& idObjRoot, ERlvBehaviour eBhvr, const std::string& strOption = LLStringUtil::null) const; + + // Adds or removes an exception for the specified behaviour + void addException(const LLUUID& idObj, ERlvBehaviour eBhvr, const RlvExceptionOption& varOption); + void removeException(const LLUUID& idObj, ERlvBehaviour eBhvr, const RlvExceptionOption& varOption); + // Returns TRUE if the specified behaviour has an added exception + bool hasException(ERlvBehaviour eBhvr) const; + // Returns TRUE if the specified option was added as an exception for the specified behaviour + bool isException(ERlvBehaviour eBhvr, const RlvExceptionOption& varOption, ERlvExceptionCheck typeCheck = RLV_CHECK_DEFAULT) const; + // Returns TRUE if the specified behaviour should behave "permissive" (rather than "strict"/"secure") + bool isPermissive(ERlvBehaviour eBhvr) const; + + #ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS + // Returns TRUE if the composite folder doesn't contain any "locked" items + bool canTakeOffComposite(const LLInventoryCategory* pFolder) const; + // Returns TRUE if the composite folder doesn't replace any "locked" items + bool canWearComposite(const LLInventoryCategory* pFolder) const; + // Returns TRUE if the folder is a composite folder and optionally returns the name + bool getCompositeInfo(const LLInventoryCategory* pFolder, std::string* pstrName) const; + // Returns TRUE if the inventory item belongs to a composite folder and optionally returns the name and composite folder + bool getCompositeInfo(const LLUUID& idItem, std::string* pstrName, LLViewerInventoryCategory** ppFolder) const; + // Returns TRUE if the folder is a composite folder + bool isCompositeFolder(const LLInventoryCategory* pFolder) const { return getCompositeInfo(pFolder, NULL); } + // Returns TRUE if the inventory item belongs to a composite folder + bool isCompositeDescendent(const LLUUID& idItem) const { return getCompositeInfo(idItem, NULL, NULL); } + // Returns TRUE if the inventory item is part of a folded composite folder and should be hidden from @getoufit or @getattach + bool isHiddenCompositeItem(const LLUUID& idItem, const std::string& strItemType) const; + #endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS + + // -------------------------------- + + /* + * Helper functions + */ +public: + // Accessors + const LLUUID& getAgentGroup() const { return m_idAgentGroup; } // @setgroup + bool getCanCancelTp() const { return m_fCanCancelTp; } // @accepttp and @tpto + void setCanCancelTp(bool fAllow) { m_fCanCancelTp = fAllow; } // @accepttp and @tpto + const LLVector3d& getSitSource() const { return m_posSitSource; } // @standtp + void setSitSource(const LLVector3d& posSource) { m_posSitSource = posSource; } // @standtp + + // Command specific helper functions + bool canShowHoverText(const LLViewerObject* pObj) const; // @showhovertext* command family + bool canTouch(const LLViewerObject* pObj, const LLVector3& posOffset = LLVector3::zero) const; // @touch + bool filterChat(std::string& strUTF8Text, bool fFilterEmote) const; // @sendchat, @recvchat and @redirchat + bool redirectChatOrEmote(const std::string& strUTF8Test) const; // @redirchat and @rediremote + + // Command processing helper functions + ERlvCmdRet processCommand(const LLUUID& idObj, const std::string& strCommand, bool fFromObj); + void processRetainedCommands(ERlvBehaviour eBhvrFilter = RLV_BHVR_UNKNOWN, ERlvParamType eTypeFilter = RLV_TYPE_UNKNOWN); + + // Returns a pointer to the currently executing command (do *not* save this pointer) + const RlvCommand* getCurrentCommand() const { return (!m_CurCommandStack.empty()) ? m_CurCommandStack.top() : NULL; } + // Returns the UUID of the object we're currently executing a command for + const LLUUID& getCurrentObject() const { return (!m_CurObjectStack.empty()) ? m_CurObjectStack.top() : LLUUID::null; } + + // Initialization + static BOOL canDisable(); + static BOOL isEnabled() { return m_fEnabled; } + static BOOL setEnabled(BOOL fEnable); +protected: + void clearState(); + + // -------------------------------- + + /* + * Event handling + */ +public: + // The behaviour signal is triggered whenever a command is successfully processed and resulted in adding or removing a behaviour + typedef boost::signals2::signal<void (ERlvBehaviour, ERlvParamType)> rlv_behaviour_signal_t; + boost::signals2::connection setBehaviourCallback(const rlv_behaviour_signal_t::slot_type& cb ) { return m_OnBehaviour.connect(cb); } + boost::signals2::connection setBehaviourToggleCallback(const rlv_behaviour_signal_t::slot_type& cb ) { return m_OnBehaviourToggle.connect(cb); } + // The command signal is triggered whenever a command is processed + typedef boost::signals2::signal<void (const RlvCommand&, ERlvCmdRet, bool)> rlv_command_signal_t; + boost::signals2::connection setCommandCallback(const rlv_command_signal_t::slot_type& cb ) { return m_OnCommand.connect(cb); } + + void addCommandHandler(RlvExtCommandHandler* pHandler); + void removeCommandHandler(RlvExtCommandHandler* pHandler); +protected: + void clearCommandHandlers(); + bool notifyCommandHandlers(rlvExtCommandHandler f, const RlvCommand& rlvCmd, ERlvCmdRet& eRet, bool fNotifyAll) const; + + // Externally invoked event handlers +public: + bool handleEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& sdUserdata); // Implementation of public LLSimpleListener + void onAttach(const LLViewerObject* pAttachObj, const LLViewerJointAttachment* pAttachPt); + void onDetach(const LLViewerObject* pAttachObj, const LLViewerJointAttachment* pAttachPt); + bool onGC(); + void onLoginComplete(); + void onSitOrStand(bool fSitting); + void onTeleportFailed(); + void onTeleportFinished(const LLVector3d& posArrival); + static void onIdleStartup(void* pParam); + + /* + * Command processing + */ +protected: + ERlvCmdRet processCommand(const RlvCommand& rlvCmd, bool fFromObj); + ERlvCmdRet processClearCommand(const RlvCommand& rlvCmd); + + // Command handlers (RLV_TYPE_ADD and RLV_TYPE_CLEAR) + ERlvCmdRet processAddRemCommand(const RlvCommand& rlvCmd); + ERlvCmdRet onAddRemFolderLock(const RlvCommand& rlvCmd, bool& fRefCount); + ERlvCmdRet onAddRemFolderLockException(const RlvCommand& rlvCmd, bool& fRefCount); + // Command handlers (RLV_TYPE_FORCE) + ERlvCmdRet processForceCommand(const RlvCommand& rlvCmd) const; + ERlvCmdRet onForceWear(const LLViewerInventoryCategory* pFolder, U32 nFlags) const; + void onForceWearCallback(const uuid_vec_t& idItems, U32 nFlags) const; + // Command handlers (RLV_TYPE_REPLY) + ERlvCmdRet processReplyCommand(const RlvCommand& rlvCmd) const; + ERlvCmdRet onFindFolder(const RlvCommand& rlvCmd, std::string& strReply) const; + ERlvCmdRet onGetAttach(const RlvCommand& rlvCmd, std::string& strReply) const; + ERlvCmdRet onGetAttachNames(const RlvCommand& rlvCmd, std::string& strReply) const; + ERlvCmdRet onGetInv(const RlvCommand& rlvCmd, std::string& strReply) const; + ERlvCmdRet onGetInvWorn(const RlvCommand& rlvCmd, std::string& strReply) const; + ERlvCmdRet onGetOutfit(const RlvCommand& rlvCmd, std::string& strReply) const; + ERlvCmdRet onGetOutfitNames(const RlvCommand& rlvCmd, std::string& strReply) const; + ERlvCmdRet onGetPath(const RlvCommand& rlvCmd, std::string& strReply) const; + + // -------------------------------- + + /* + * Member variables + */ +public: + typedef std::map<LLUUID, RlvObject> rlv_object_map_t; + typedef std::multimap<ERlvBehaviour, RlvException> rlv_exception_map_t; +protected: + rlv_object_map_t m_Objects; // Map of objects that have active restrictions (idObj -> RlvObject) + rlv_exception_map_t m_Exceptions; // Map of currently active restriction exceptions (ERlvBehaviour -> RlvException) + S16 m_Behaviours[RLV_BHVR_COUNT]; + + rlv_command_list_t m_Retained; + RlvGCTimer* m_pGCTimer; + + std::stack<const RlvCommand*> m_CurCommandStack;// Convenience (see @tpto) + std::stack<LLUUID> m_CurObjectStack; // Convenience (see @tpto) + + rlv_behaviour_signal_t m_OnBehaviour; + rlv_behaviour_signal_t m_OnBehaviourToggle; + rlv_command_signal_t m_OnCommand; + mutable std::list<RlvExtCommandHandler*> m_CommandHandlers; + + static BOOL m_fEnabled; // Use setEnabled() to toggle this + + bool m_fCanCancelTp; // @accepttp=n and @tpto=force + mutable LLVector3d m_posSitSource; // @standtp=n (mutable because onForceXXX handles are all declared as const) + mutable LLUUID m_idAgentGroup; // @setgroup=n + + friend class RlvSharedRootFetcher; // Fetcher needs access to m_fFetchComplete + friend class RlvGCTimer; // Timer clear its own point at destruction + template<ERlvBehaviourOptionType optionType> friend struct RlvBehaviourGenericHandler; + template<ERlvParamType> friend struct RlvCommandHandlerBaseImpl; + template<ERlvParamType, ERlvBehaviour> friend struct RlvCommandHandler; + + // -------------------------------- + + /* + * Internal access functions used by unit tests + */ +public: + const rlv_object_map_t* getObjectMap() const { return &m_Objects; } + //const rlv_exception_map_t* getExceptionMap() const { return &m_Exceptions; } +}; + +typedef RlvHandler rlv_handler_t; +extern rlv_handler_t gRlvHandler; + +// ============================================================================ +// Inlined member functions +// + +// Checked: 2010-03-27 (RLVa-1.4.0a) | Modified: RLVa-1.0.0f +inline bool RlvHandler::canShowHoverText(const LLViewerObject *pObj) const +{ + return ( (!pObj) || (LL_PCODE_VOLUME != pObj->getPCode()) || + !( (hasBehaviour(RLV_BHVR_SHOWHOVERTEXTALL)) || + ( (hasBehaviour(RLV_BHVR_SHOWHOVERTEXTWORLD)) && (!pObj->isHUDAttachment()) ) || + ( (hasBehaviour(RLV_BHVR_SHOWHOVERTEXTHUD)) && (pObj->isHUDAttachment()) ) || + (isException(RLV_BHVR_SHOWHOVERTEXT, pObj->getID(), RLV_CHECK_PERMISSIVE)) ) ); +} + +inline bool RlvHandler::hasBehaviour(ERlvBehaviour eBhvr, const std::string& strOption) const +{ + return hasBehaviourExcept(eBhvr, strOption, LLUUID::null); +} + +inline bool RlvHandler::hasBehaviourExcept(ERlvBehaviour eBhvr, const LLUUID& idObj) const +{ + return hasBehaviourExcept(eBhvr, LLStringUtil::null, idObj); +} + +// ============================================================================ + +#endif // RLV_HANDLER_H diff --git a/indra/newview/rlvhelper.cpp b/indra/newview/rlvhelper.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2f0ac47776c96f78e00698fdbd9a9335da4d2cf9 --- /dev/null +++ b/indra/newview/rlvhelper.cpp @@ -0,0 +1,1785 @@ +/** + * + * Copyright (c) 2009-2016, Kitty Barnett + * + * The source code in this file is provided to you under the terms of the + * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt + * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.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 "llappearancemgr.h" +#include "llattachmentsmgr.h" +#include "llgesturemgr.h" +#include "llnotificationsutil.h" +#include "llviewerobjectlist.h" + +#include "rlvcommon.h" +#include "rlvhelper.h" +#include "rlvhandler.h" +#include "rlvinventory.h" + +#include <boost/algorithm/string.hpp> + +// ============================================================================ +// RlvBehaviourDictionary +// + +/* + * Processing of RLVa commands used to be a big switch/case loop with one function for each command type(addrem, reply + * and force). This is slowly being replaced with templated command handling which might be more confusing intially + * (also due to my poor naming schemes) but is actually far simpler and less error-prone than the old way. + * + * In the general case you just add a definition for the command below and then write the function body in rlvhandler.cpp + * and you're done! Told you this was easy. + * + * Reply command + * ============= + * Definition: RlvReplyProcessor<RLV_BHVR_COMMANDNAME>("commandname"[, <options>])); + * Implement : ERlvCmdRet RlvReplyHandler<RLV_BHVR_COMMANDNAME>::onCommand(const RlvCommand& rlvCmd, std::string& strReply) + * + * Force command + * ============= + * Definition: new RlvForceProcessor<RLV_BHVR_COMMANDNAME>("commandname"[, <options>])); + * Implement : ERlvCmdRet RlvForceProcessor<RLV_BHVR_COMMANDNAME>::onCommand(const RlvCommand& rlvCmd) + * + * Behaviours + * ========== + * Behaviours come in many forms but the added complexity is only in the variety of choices. The implementation is as + * easy as reply or force commands. + * + * For simple behaviours that only require recordkeeping and don't run code when set/unset (see ERlvBehaviourOptionType): + * Definition: RlvBehaviourGenericProcessor<RLV_OPTION_TYPE>("commandname", RLV_BHVR_COMMANDNAME) + * Implement : nothing! (it automagically works) + * For simple behaviours that only require recordkeeping and only run code when they toggle: + * Definition: RlvBehaviourGenericToggleProcessor<RLV_BHVR_COMMANDNAME, RLV_OPTION_TYPE>("commandname")) + * Implement : void RlvBehaviourToggleHandler<RLV_BHVR_COMMANDNAME>::onCommandToggle(ERlvBehaviour eBhvr, bool fHasBhvr) + * For behaviours that require manual processing: + * Definition: RlvBehaviourProcessor<RLV_BHVR_COMMANDNAME>("commandname")) + * Implement : ERlvCmdRet RlvBehaviourHandler<RLV_BHVR_COMMANDNAME>::onCommand(const RlvCommand& rlvCmd, bool& fRefCount) + * For behaviours that run code when their modifier changes: + * Definition: addModifier(RLV_BHVR_COMMANDNAME, RLV_MODIFIER_COMMANDNAME, new RlvBehaviourModifierHandler<RLV_MODIFIER_COMMANDNAME>(<default>, <auto-add>, <comparator>)); + * Implement : void RlvBehaviourModifierHandler::onValueChanged() + * + */ +RlvBehaviourDictionary::RlvBehaviourDictionary() +{ + // Array auto-initialization to 0 is still not supported in VS2013 + memset(m_BehaviourModifiers, 0, sizeof(RlvBehaviourModifier*) * RLV_MODIFIER_COUNT); + + // + // Restrictions + // + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("acceptpermission", RLV_BHVR_ACCEPTPERMISSION)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE_OR_EXCEPTION>("accepttp", RLV_BHVR_ACCEPTTP, RlvBehaviourInfo::BHVR_STRICT)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE_OR_EXCEPTION>("accepttprequest", RLV_BHVR_ACCEPTTPREQUEST, RlvBehaviourInfo::BHVR_STRICT | RlvBehaviourInfo::BHVR_EXTENDED)); + addEntry(new RlvBehaviourProcessor<RLV_BHVR_ADDATTACH, RlvBehaviourAddRemAttachHandler>("addattach")); + addEntry(new RlvBehaviourInfo("addoutfit", RLV_BHVR_ADDOUTFIT, RLV_TYPE_ADDREM)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("allowidle", RLV_BHVR_ALLOWIDLE, RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("alwaysrun", RLV_BHVR_ALWAYSRUN)); + addEntry(new RlvBehaviourInfo("attachthis", RLV_BHVR_ATTACHTHIS, RLV_TYPE_ADDREM, RlvBehaviourInfo::FORCEWEAR_NODE)); + addEntry(new RlvBehaviourInfo("attachallthis", RLV_BHVR_ATTACHTHIS, RLV_TYPE_ADDREM, RlvBehaviourInfo::FORCEWEAR_SUBTREE)); + addEntry(new RlvBehaviourInfo("attachthis_except", RLV_BHVR_ATTACHTHISEXCEPT, RLV_TYPE_ADDREM, RlvBehaviourInfo::FORCEWEAR_NODE)); + addEntry(new RlvBehaviourInfo("attachallthis_except", RLV_BHVR_ATTACHTHISEXCEPT, RLV_TYPE_ADDREM, RlvBehaviourInfo::FORCEWEAR_SUBTREE)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("chatwhisper", RLV_BHVR_CHATWHISPER)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("chatnormal", RLV_BHVR_CHATNORMAL)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("chatshout", RLV_BHVR_CHATSHOUT)); + addEntry(new RlvBehaviourProcessor<RLV_BHVR_DETACH>("detach")); + addEntry(new RlvBehaviourInfo("detachthis", RLV_BHVR_DETACHTHIS, RLV_TYPE_ADDREM, RlvBehaviourInfo::FORCEWEAR_NODE)); + addEntry(new RlvBehaviourInfo("detachallthis", RLV_BHVR_DETACHTHIS, RLV_TYPE_ADDREM, RlvBehaviourInfo::FORCEWEAR_SUBTREE)); + addEntry(new RlvBehaviourInfo("detachthis_except", RLV_BHVR_DETACHTHISEXCEPT, RLV_TYPE_ADDREM, RlvBehaviourInfo::FORCEWEAR_NODE)); + addEntry(new RlvBehaviourInfo("detachallthis_except", RLV_BHVR_DETACHTHISEXCEPT, RLV_TYPE_ADDREM, RlvBehaviourInfo::FORCEWEAR_SUBTREE)); + addEntry(new RlvBehaviourGenericToggleProcessor<RLV_BHVR_EDIT, RLV_OPTION_NONE_OR_EXCEPTION>("edit")); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_EXCEPTION>("editobj", RLV_BHVR_EDITOBJ)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("emote", RLV_BHVR_EMOTE)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE_OR_MODIFIER>("fartouch", RLV_BHVR_FARTOUCH)); + addModifier(RLV_BHVR_FARTOUCH, RLV_MODIFIER_FARTOUCHDIST, new RlvBehaviourModifier("Fartouch Distance", RLV_MODIFIER_FARTOUCH_DEFAULT, true, new RlvBehaviourModifier_CompMin)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("fly", RLV_BHVR_FLY)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("interact", RLV_BHVR_INTERACT, RlvBehaviourInfo::BHVR_EXTENDED)); + addEntry(new RlvBehaviourInfo("notify", RLV_BHVR_NOTIFY, RLV_TYPE_ADDREM)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("permissive", RLV_BHVR_PERMISSIVE)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE_OR_EXCEPTION>("recvchat", RLV_BHVR_RECVCHAT, RlvBehaviourInfo::BHVR_STRICT)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_EXCEPTION>("recvchatfrom", RLV_BHVR_RECVCHATFROM, RlvBehaviourInfo::BHVR_STRICT)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE_OR_EXCEPTION>("recvemote", RLV_BHVR_RECVEMOTE, RlvBehaviourInfo::BHVR_STRICT)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_EXCEPTION>("recvemotefrom", RLV_BHVR_RECVEMOTEFROM, RlvBehaviourInfo::BHVR_STRICT)); + addEntry(new RlvBehaviourProcessor<RLV_BHVR_RECVIM, RlvBehaviourRecvSendStartIMHandler>("recvim", RlvBehaviourInfo::BHVR_STRICT)); + addModifier(RLV_BHVR_RECVIM, RLV_MODIFIER_RECVIMDISTMIN, new RlvBehaviourModifier("RecvIM Distance (Min)", F32_MAX, true, new RlvBehaviourModifier_CompMax)); + addModifier(RLV_BHVR_RECVIM, RLV_MODIFIER_RECVIMDISTMAX, new RlvBehaviourModifier("RecvIM Distance (Max)", F32_MAX, true, new RlvBehaviourModifier_CompMin)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_EXCEPTION>("recvimfrom", RLV_BHVR_RECVIMFROM, RlvBehaviourInfo::BHVR_STRICT)); + addEntry(new RlvBehaviourInfo("redirchat", RLV_BHVR_REDIRCHAT, RLV_TYPE_ADDREM)); + addEntry(new RlvBehaviourInfo("rediremote", RLV_BHVR_REDIREMOTE, RLV_TYPE_ADDREM)); + addEntry(new RlvBehaviourProcessor<RLV_BHVR_REMATTACH, RlvBehaviourAddRemAttachHandler>("remattach")); + addEntry(new RlvBehaviourInfo("remoutfit", RLV_BHVR_REMOUTFIT, RLV_TYPE_ADDREM)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("rez", RLV_BHVR_REZ)); + addEntry(new RlvBehaviourProcessor<RLV_BHVR_SENDCHANNEL, RlvBehaviourSendChannelHandler>("sendchannel", RlvBehaviourInfo::BHVR_STRICT)); + addEntry(new RlvBehaviourProcessor<RLV_BHVR_SENDCHANNELEXCEPT, RlvBehaviourSendChannelHandler>("sendchannel_except", RlvBehaviourInfo::BHVR_STRICT | RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("sendchat", RLV_BHVR_SENDCHAT)); + addEntry(new RlvBehaviourToggleProcessor<RLV_BHVR_SENDIM, RlvBehaviourRecvSendStartIMHandler>("sendim", RlvBehaviourInfo::BHVR_STRICT)); + addModifier(RLV_BHVR_SENDIM, RLV_MODIFIER_SENDIMDISTMIN, new RlvBehaviourModifier("SendIM Distance (Min)", F32_MAX, true, new RlvBehaviourModifier_CompMax)); + addModifier(RLV_BHVR_SENDIM, RLV_MODIFIER_SENDIMDISTMAX, new RlvBehaviourModifier("SendIM Distance (Max)", F32_MAX, true, new RlvBehaviourModifier_CompMin)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_EXCEPTION>("sendimto", RLV_BHVR_SENDIMTO, RlvBehaviourInfo::BHVR_STRICT)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("sendgesture", RLV_BHVR_SENDGESTURE, RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addEntry(new RlvBehaviourGenericToggleProcessor<RLV_BHVR_SETDEBUG, RLV_OPTION_NONE>("setdebug")); + addEntry(new RlvBehaviourGenericToggleProcessor<RLV_BHVR_SETENV, RLV_OPTION_NONE>("setenv")); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("setgroup", RLV_BHVR_SETGROUP)); + addEntry(new RlvBehaviourInfo("sharedunwear", RLV_BHVR_SHAREDUNWEAR, RLV_TYPE_ADDREM, RlvBehaviourInfo::BHVR_EXTENDED)); + addEntry(new RlvBehaviourInfo("sharedwear", RLV_BHVR_SHAREDWEAR, RLV_TYPE_ADDREM, RlvBehaviourInfo::BHVR_EXTENDED)); + addEntry(new RlvBehaviourProcessor<RLV_BHVR_SHOWHOVERTEXT>("showhovertext")); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("showhovertextall", RLV_BHVR_SHOWHOVERTEXTALL)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("showhovertexthud", RLV_BHVR_SHOWHOVERTEXTHUD)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("showhovertextworld", RLV_BHVR_SHOWHOVERTEXTWORLD)); + addEntry(new RlvBehaviourGenericToggleProcessor<RLV_BHVR_SHOWINV, RLV_OPTION_NONE>("showinv")); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("showloc", RLV_BHVR_SHOWLOC)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("showminimap", RLV_BHVR_SHOWMINIMAP)); + addEntry(new RlvBehaviourToggleProcessor<RLV_BHVR_SHOWNAMES>("shownames", RlvBehaviourInfo::BHVR_STRICT)); + addEntry(new RlvBehaviourToggleProcessor<RLV_BHVR_SHOWNAMETAGS>("shownametags", RlvBehaviourInfo::BHVR_STRICT )); + addEntry(new RlvBehaviourGenericToggleProcessor<RLV_BHVR_SHOWNEARBY, RLV_OPTION_NONE>("shownearby", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addEntry(new RlvBehaviourGenericToggleProcessor<RLV_BHVR_SHOWSELF, RLV_OPTION_NONE, RlvBehaviourShowSelfToggleHandler>("showself", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addEntry(new RlvBehaviourGenericToggleProcessor<RLV_BHVR_SHOWSELFHEAD, RLV_OPTION_NONE, RlvBehaviourShowSelfToggleHandler>("showselfhead", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("showworldmap", RLV_BHVR_SHOWWORLDMAP)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("sit", RLV_BHVR_SIT)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE_OR_MODIFIER>("sittp", RLV_BHVR_SITTP)); + addModifier(RLV_BHVR_SITTP, RLV_MODIFIER_SITTPDIST, new RlvBehaviourModifier("SitTp Distance", RLV_MODIFIER_SITTP_DEFAULT, true, new RlvBehaviourModifier_CompMin)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("standtp", RLV_BHVR_STANDTP)); + addEntry(new RlvBehaviourProcessor<RLV_BHVR_STARTIM, RlvBehaviourRecvSendStartIMHandler>("startim", RlvBehaviourInfo::BHVR_STRICT)); + addModifier(RLV_BHVR_STARTIM, RLV_MODIFIER_STARTIMDISTMIN, new RlvBehaviourModifier("StartIM Distance (Min)", F32_MAX, true, new RlvBehaviourModifier_CompMax)); + addModifier(RLV_BHVR_STARTIM, RLV_MODIFIER_STARTIMDISTMAX, new RlvBehaviourModifier("StartIM Distance (Max)", F32_MAX, true, new RlvBehaviourModifier_CompMin)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_EXCEPTION>("startimto", RLV_BHVR_STARTIMTO, RlvBehaviourInfo::BHVR_STRICT)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("temprun", RLV_BHVR_TEMPRUN)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("touchall", RLV_BHVR_TOUCHALL)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE_OR_EXCEPTION>("touchattach", RLV_BHVR_TOUCHATTACH)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("touchattachother", RLV_BHVR_TOUCHATTACHOTHER)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("touchattachself", RLV_BHVR_TOUCHATTACHSELF)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE_OR_MODIFIER>("touchfar", RLV_BHVR_FARTOUCH, RlvBehaviourInfo::BHVR_SYNONYM)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE_OR_EXCEPTION>("touchhud", RLV_BHVR_TOUCHHUD, RlvBehaviourInfo::BHVR_EXTENDED)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("touchme", RLV_BHVR_TOUCHME)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_EXCEPTION>("touchthis", RLV_BHVR_TOUCHTHIS)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE_OR_EXCEPTION>("touchworld", RLV_BHVR_TOUCHWORLD)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("tplm", RLV_BHVR_TPLM)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("tploc", RLV_BHVR_TPLOC)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE_OR_MODIFIER>("tplocal", RLV_BHVR_TPLOCAL, RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addModifier(RLV_BHVR_TPLOCAL, RLV_MODIFIER_TPLOCALDIST, new RlvBehaviourModifier("Local Teleport Distance", RLV_MODIFIER_TPLOCAL_DEFAULT, true, new RlvBehaviourModifier_CompMin)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE_OR_EXCEPTION>("tplure", RLV_BHVR_TPLURE, RlvBehaviourInfo::BHVR_STRICT)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE_OR_EXCEPTION>("tprequest", RLV_BHVR_TPREQUEST, RlvBehaviourInfo::BHVR_STRICT | RlvBehaviourInfo::BHVR_EXTENDED)); + addEntry(new RlvBehaviourInfo("unsharedunwear", RLV_BHVR_UNSHAREDUNWEAR, RLV_TYPE_ADDREM)); + addEntry(new RlvBehaviourInfo("unsharedwear", RLV_BHVR_UNSHAREDWEAR, RLV_TYPE_ADDREM)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("unsit", RLV_BHVR_UNSIT)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("viewnote", RLV_BHVR_VIEWNOTE)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("viewscript", RLV_BHVR_VIEWSCRIPT)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("viewtexture", RLV_BHVR_VIEWTEXTURE)); + // Camera + addEntry(new RlvBehaviourGenericToggleProcessor<RLV_BHVR_SETCAM, RLV_OPTION_NONE>("setcam")); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_MODIFIER>("setcam_avdistmin", RLV_BHVR_SETCAM_AVDISTMIN, RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addModifier(RLV_BHVR_SETCAM_AVDISTMIN, RLV_MODIFIER_SETCAM_AVDISTMIN, new RlvBehaviourModifierHandler<RLV_MODIFIER_SETCAM_AVDISTMIN>("Camera - Avatar Distance (Min)", 0.0f, false, new RlvBehaviourModifier_CompMax())); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_MODIFIER>("setcam_avdistmax", RLV_BHVR_SETCAM_AVDISTMAX, RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addModifier(RLV_BHVR_SETCAM_AVDISTMAX, RLV_MODIFIER_SETCAM_AVDISTMAX, new RlvBehaviourModifier("Camera - Avatar Distance (Max)", F32_MAX, false, new RlvBehaviourModifier_CompMin)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_MODIFIER>("setcam_origindistmin", RLV_BHVR_SETCAM_ORIGINDISTMIN, RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addModifier(RLV_BHVR_SETCAM_ORIGINDISTMIN, RLV_MODIFIER_SETCAM_ORIGINDISTMIN, new RlvBehaviourModifier("Camera - Focus Distance (Min)", 0.0f, true, new RlvBehaviourModifier_CompMax)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_MODIFIER>("setcam_origindistmax", RLV_BHVR_SETCAM_ORIGINDISTMAX, RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addModifier(RLV_BHVR_SETCAM_ORIGINDISTMAX, RLV_MODIFIER_SETCAM_ORIGINDISTMAX, new RlvBehaviourModifier("Camera - Focus Distance (Max)", F32_MAX, true, new RlvBehaviourModifier_CompMin)); + addEntry(new RlvBehaviourGenericToggleProcessor<RLV_BHVR_SETCAM_EYEOFFSET, RLV_OPTION_MODIFIER, RlvBehaviourCamEyeFocusOffsetHandler>("setcam_eyeoffset", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addModifier(RLV_BHVR_SETCAM_EYEOFFSET, RLV_MODIFIER_SETCAM_EYEOFFSET, new RlvBehaviourModifierHandler<RLV_MODIFIER_SETCAM_EYEOFFSET>("Camera - Eye Offset", LLVector3::zero, true, nullptr)); + addEntry(new RlvBehaviourGenericToggleProcessor<RLV_BHVR_SETCAM_FOCUSOFFSET, RLV_OPTION_MODIFIER, RlvBehaviourCamEyeFocusOffsetHandler>("setcam_focusoffset", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addModifier(RLV_BHVR_SETCAM_FOCUSOFFSET, RLV_MODIFIER_SETCAM_FOCUSOFFSET, new RlvBehaviourModifierHandler<RLV_MODIFIER_SETCAM_FOCUSOFFSET>("Camera - Focus Offset", LLVector3::zero, true, nullptr)); + addEntry(new RlvBehaviourProcessor<RLV_BHVR_SETCAM_FOVMIN, RlvBehaviourSetCamFovHandler>("setcam_fovmin")); + addModifier(RLV_BHVR_SETCAM_FOVMIN, RLV_MODIFIER_SETCAM_FOVMIN, new RlvBehaviourModifierHandler<RLV_MODIFIER_SETCAM_FOVMIN>("Camera - FOV (Min)", DEFAULT_FIELD_OF_VIEW, true, new RlvBehaviourModifier_CompMax)); + addEntry(new RlvBehaviourProcessor<RLV_BHVR_SETCAM_FOVMAX, RlvBehaviourSetCamFovHandler>("setcam_fovmax")); + addModifier(RLV_BHVR_SETCAM_FOVMAX, RLV_MODIFIER_SETCAM_FOVMAX, new RlvBehaviourModifierHandler<RLV_MODIFIER_SETCAM_FOVMAX>("Camera - FOV (Max)", DEFAULT_FIELD_OF_VIEW, true, new RlvBehaviourModifier_CompMin)); + addEntry(new RlvBehaviourGenericToggleProcessor<RLV_BHVR_SETCAM_MOUSELOOK, RLV_OPTION_NONE>("setcam_mouselook")); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE_OR_MODIFIER>("setcam_textures", RLV_BHVR_SETCAM_TEXTURES)); + addModifier(RLV_BHVR_SETCAM_TEXTURES, RLV_MODIFIER_SETCAM_TEXTURE, new RlvBehaviourModifierHandler<RLV_MODIFIER_SETCAM_TEXTURE>("Camera - Forced Texture", IMG_DEFAULT, true, nullptr)); + addEntry(new RlvBehaviourGenericToggleProcessor<RLV_BHVR_SETCAM_UNLOCK, RLV_OPTION_NONE>("setcam_unlock")); + // Camera (compatibility shim - to be deprecated) + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_MODIFIER>("camdistmin", RLV_BHVR_SETCAM_AVDISTMIN, RlvBehaviourInfo::BHVR_SYNONYM | RlvBehaviourInfo::BHVR_DEPRECATED)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_MODIFIER>("camdistmax", RLV_BHVR_SETCAM_AVDISTMAX, RlvBehaviourInfo::BHVR_SYNONYM | RlvBehaviourInfo::BHVR_DEPRECATED)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE_OR_MODIFIER>("camtextures", RLV_BHVR_SETCAM_TEXTURES, RlvBehaviourInfo::BHVR_SYNONYM | RlvBehaviourInfo::BHVR_DEPRECATED)); + addEntry(new RlvBehaviourProcessor<RLV_BHVR_CAMZOOMMIN, RlvBehaviourCamZoomMinMaxHandler>("camzoommin", RlvBehaviourInfo::BHVR_DEPRECATED)); + addEntry(new RlvBehaviourProcessor<RLV_BHVR_CAMZOOMMAX, RlvBehaviourCamZoomMinMaxHandler>("camzoommax", RlvBehaviourInfo::BHVR_DEPRECATED)); + addEntry(new RlvBehaviourGenericToggleProcessor<RLV_BHVR_SETCAM_UNLOCK, RLV_OPTION_NONE>("camunlock", RlvBehaviourInfo::BHVR_SYNONYM | RlvBehaviourInfo::BHVR_DEPRECATED)); + + // + // Force-wear + // + addEntry(new RlvBehaviourInfo("attach", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_REPLACE | RlvBehaviourInfo::FORCEWEAR_NODE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE)); + addEntry(new RlvBehaviourInfo("attachall", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_REPLACE | RlvBehaviourInfo::FORCEWEAR_SUBTREE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE)); + addEntry(new RlvBehaviourInfo("attachover", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_ADD | RlvBehaviourInfo::FORCEWEAR_NODE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE)); + addEntry(new RlvBehaviourInfo("attachallover", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_ADD | RlvBehaviourInfo::FORCEWEAR_SUBTREE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE)); + addEntry(new RlvBehaviourInfo("attachthis", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_REPLACE | RlvBehaviourInfo::FORCEWEAR_NODE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_OBJECT)); + addEntry(new RlvBehaviourInfo("attachallthis", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_REPLACE | RlvBehaviourInfo::FORCEWEAR_SUBTREE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_OBJECT)); + addEntry(new RlvBehaviourInfo("attachthisover", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_ADD | RlvBehaviourInfo::FORCEWEAR_NODE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_OBJECT)); + addEntry(new RlvBehaviourInfo("attachallthisover", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_ADD | RlvBehaviourInfo::FORCEWEAR_SUBTREE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_OBJECT)); + addEntry(new RlvForceProcessor<RLV_BHVR_DETACH, RlvForceRemAttachHandler>("detach", RlvBehaviourInfo::FORCEWEAR_WEAR_REMOVE | RlvBehaviourInfo::FORCEWEAR_NODE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE)); + addEntry(new RlvBehaviourInfo("detachall", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_REMOVE | RlvBehaviourInfo::FORCEWEAR_SUBTREE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE)); + addEntry(new RlvBehaviourInfo("detachthis", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_REMOVE | RlvBehaviourInfo::FORCEWEAR_NODE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_OBJECT)); + addEntry(new RlvBehaviourInfo("detachallthis", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_REMOVE | RlvBehaviourInfo::FORCEWEAR_SUBTREE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_OBJECT)); + addEntry(new RlvForceProcessor<RLV_BHVR_REMATTACH, RlvForceRemAttachHandler>("remattach", RlvBehaviourInfo::FORCEWEAR_WEAR_REMOVE | RlvBehaviourInfo::FORCEWEAR_NODE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE)); + addEntry(new RlvForceProcessor<RLV_BHVR_REMOUTFIT>("remoutfit", RlvBehaviourInfo::FORCEWEAR_WEAR_REMOVE | RlvBehaviourInfo::FORCEWEAR_NODE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE)); + // Synonyms (addoutfit* -> attach*) + addEntry(new RlvBehaviourInfo("addoutfit", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_REPLACE | RlvBehaviourInfo::FORCEWEAR_NODE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE | RlvBehaviourInfo::BHVR_SYNONYM)); + addEntry(new RlvBehaviourInfo("addoutfitall", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_REPLACE | RlvBehaviourInfo::FORCEWEAR_SUBTREE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE | RlvBehaviourInfo::BHVR_SYNONYM)); + addEntry(new RlvBehaviourInfo("addoutfitover", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_ADD | RlvBehaviourInfo::FORCEWEAR_NODE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE | RlvBehaviourInfo::BHVR_SYNONYM)); + addEntry(new RlvBehaviourInfo("addoutfitallover", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_ADD | RlvBehaviourInfo::FORCEWEAR_SUBTREE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE | RlvBehaviourInfo::BHVR_SYNONYM)); + addEntry(new RlvBehaviourInfo("addoutfitthis", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_REPLACE | RlvBehaviourInfo::FORCEWEAR_NODE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_OBJECT | RlvBehaviourInfo::BHVR_SYNONYM)); + addEntry(new RlvBehaviourInfo("addoutfitallthis", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_REPLACE | RlvBehaviourInfo::FORCEWEAR_SUBTREE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_OBJECT | RlvBehaviourInfo::BHVR_SYNONYM)); + addEntry(new RlvBehaviourInfo("addoutfitthisover", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_ADD | RlvBehaviourInfo::FORCEWEAR_NODE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_OBJECT | RlvBehaviourInfo::BHVR_SYNONYM)); + addEntry(new RlvBehaviourInfo("addoutfitallthisover", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_ADD | RlvBehaviourInfo::FORCEWEAR_SUBTREE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_OBJECT | RlvBehaviourInfo::BHVR_SYNONYM)); + // Synonyms (attach*overorreplace -> attach*) + addEntry(new RlvBehaviourInfo("attachoverorreplace", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_REPLACE | RlvBehaviourInfo::FORCEWEAR_NODE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE | RlvBehaviourInfo::BHVR_SYNONYM)); + addEntry(new RlvBehaviourInfo("attachalloverorreplace", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_REPLACE | RlvBehaviourInfo::FORCEWEAR_SUBTREE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE | RlvBehaviourInfo::BHVR_SYNONYM)); + addEntry(new RlvBehaviourInfo("attachthisoverorreplace",RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_REPLACE | RlvBehaviourInfo::FORCEWEAR_NODE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_OBJECT | RlvBehaviourInfo::BHVR_SYNONYM)); + addEntry(new RlvBehaviourInfo("attachallthisoverorreplace",RLV_CMD_FORCEWEAR,RLV_TYPE_FORCE,RlvBehaviourInfo::FORCEWEAR_WEAR_REPLACE | RlvBehaviourInfo::FORCEWEAR_SUBTREE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_OBJECT | RlvBehaviourInfo::BHVR_SYNONYM)); + + // + // Force-only + // + addEntry(new RlvBehaviourInfo("adjustheight", RLV_BHVR_ADJUSTHEIGHT, RLV_TYPE_FORCE)); + addEntry(new RlvForceProcessor<RLV_BHVR_DETACHME>("detachme")); + addEntry(new RlvForceProcessor<RLV_BHVR_SETCAM_FOCUS>("setcam_focus", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addEntry(new RlvForceProcessor<RLV_BHVR_SETCAM_EYEOFFSET, RlvForceCamEyeFocusOffsetHandler>("setcam_eyeoffset", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addEntry(new RlvForceProcessor<RLV_BHVR_SETCAM_FOCUSOFFSET, RlvForceCamEyeFocusOffsetHandler>("setcam_focusoffset", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addEntry(new RlvForceProcessor<RLV_BHVR_SETCAM_FOV>("setcam_fov", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addEntry(new RlvForceProcessor<RLV_BHVR_SETCAM_MODE>("setcam_mode", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addEntry(new RlvForceProcessor<RLV_BHVR_SETGROUP>("setgroup")); + addEntry(new RlvForceProcessor<RLV_BHVR_SIT>("sit")); + addEntry(new RlvForceProcessor<RLV_BHVR_TPTO>("tpto")); + addEntry(new RlvBehaviourInfo("unsit", RLV_BHVR_UNSIT, RLV_TYPE_FORCE)); + + // + // Reply-only + // + addEntry(new RlvBehaviourInfo("findfolder", RLV_BHVR_FINDFOLDER, RLV_TYPE_REPLY)); + addEntry(new RlvBehaviourInfo("findfolders", RLV_BHVR_FINDFOLDERS, RLV_TYPE_REPLY, RlvBehaviourInfo::BHVR_EXTENDED)); + addEntry(new RlvBehaviourInfo("getaddattachnames", RLV_BHVR_GETADDATTACHNAMES, RLV_TYPE_REPLY, RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addEntry(new RlvBehaviourInfo("getaddoutfitnames", RLV_BHVR_GETADDOUTFITNAMES, RLV_TYPE_REPLY, RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addEntry(new RlvBehaviourInfo("getattach", RLV_BHVR_GETATTACH, RLV_TYPE_REPLY)); + addEntry(new RlvBehaviourInfo("getattachnames", RLV_BHVR_GETATTACHNAMES, RLV_TYPE_REPLY, RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addEntry(new RlvReplyProcessor<RLV_BHVR_GETCAM_AVDIST>("getcam_avdist", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addEntry(new RlvReplyProcessor<RLV_BHVR_GETCAM_AVDISTMIN, RlvReplyCamMinMaxModifierHandler>("getcam_avdistmin", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addEntry(new RlvReplyProcessor<RLV_BHVR_GETCAM_AVDISTMAX, RlvReplyCamMinMaxModifierHandler>("getcam_avdistmax", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addEntry(new RlvReplyProcessor<RLV_BHVR_GETCAM_FOV>("getcam_fov", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addEntry(new RlvReplyProcessor<RLV_BHVR_GETCAM_FOVMIN, RlvReplyCamMinMaxModifierHandler>("getcam_fovmin", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addEntry(new RlvReplyProcessor<RLV_BHVR_GETCAM_FOVMAX, RlvReplyCamMinMaxModifierHandler>("getcam_fovmax", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addEntry(new RlvReplyProcessor<RLV_BHVR_GETCAM_TEXTURES>("getcam_textures", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addEntry(new RlvReplyProcessor<RLV_BHVR_GETCOMMAND>("getcommand", RlvBehaviourInfo::BHVR_EXTENDED)); + addEntry(new RlvBehaviourInfo("getgroup", RLV_BHVR_GETGROUP, RLV_TYPE_REPLY)); + addEntry(new RlvBehaviourInfo("getinv", RLV_BHVR_GETINV, RLV_TYPE_REPLY)); + addEntry(new RlvBehaviourInfo("getinvworn", RLV_BHVR_GETINVWORN, RLV_TYPE_REPLY)); + addEntry(new RlvBehaviourInfo("getoutfit", RLV_BHVR_GETOUTFIT, RLV_TYPE_REPLY)); + addEntry(new RlvBehaviourInfo("getoutfitnames", RLV_BHVR_GETOUTFITNAMES, RLV_TYPE_REPLY, RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addEntry(new RlvBehaviourInfo("getpath", RLV_BHVR_GETPATH, RLV_TYPE_REPLY)); + addEntry(new RlvBehaviourInfo("getpathnew", RLV_BHVR_GETPATHNEW, RLV_TYPE_REPLY)); + addEntry(new RlvBehaviourInfo("getremattachnames", RLV_BHVR_GETREMATTACHNAMES, RLV_TYPE_REPLY, RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addEntry(new RlvBehaviourInfo("getremoutfitnames", RLV_BHVR_GETREMOUTFITNAMES, RLV_TYPE_REPLY, RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addEntry(new RlvBehaviourInfo("getsitid", RLV_BHVR_GETSITID, RLV_TYPE_REPLY)); + addEntry(new RlvBehaviourInfo("getstatus", RLV_BHVR_GETSTATUS, RLV_TYPE_REPLY)); + addEntry(new RlvBehaviourInfo("getstatusall", RLV_BHVR_GETSTATUSALL, RLV_TYPE_REPLY)); + addEntry(new RlvBehaviourInfo("version", RLV_BHVR_VERSION, RLV_TYPE_REPLY)); + addEntry(new RlvBehaviourInfo("versionnew", RLV_BHVR_VERSIONNEW, RLV_TYPE_REPLY)); + addEntry(new RlvBehaviourInfo("versionnum", RLV_BHVR_VERSIONNUM, RLV_TYPE_REPLY)); + + // Populate m_String2InfoMap (the tuple <behaviour, type> should be unique) + for (const RlvBehaviourInfo* pBhvrInfo : m_BhvrInfoList) + { + RLV_VERIFY(m_String2InfoMap.insert(std::make_pair(std::make_pair(pBhvrInfo->getBehaviour(), (ERlvParamType)pBhvrInfo->getParamTypeMask()), pBhvrInfo)).second == true); + } + + // Populate m_Bhvr2InfoMap (there can be multiple entries per ERlvBehaviour) + for (const RlvBehaviourInfo* pBhvrInfo : m_BhvrInfoList) + { + if ( (pBhvrInfo->getParamTypeMask() & RLV_TYPE_ADDREM) && (!pBhvrInfo->isSynonym()) ) + { +#ifdef RLV_DEBUG + for (const rlv_bhvr2info_map_t::value_type& itBhvr : boost::make_iterator_range(m_Bhvr2InfoMap.lower_bound(pBhvrInfo->getBehaviourType()), m_Bhvr2InfoMap.upper_bound(pBhvrInfo->getBehaviourType()))) + { + RLV_ASSERT( (itBhvr.first != pBhvrInfo->getBehaviourType()) || (itBhvr.second->getBehaviourFlags() != pBhvrInfo->getBehaviourFlags()) ); + } +#endif // RLV_DEBUG + m_Bhvr2InfoMap.insert(std::pair<ERlvBehaviour, const RlvBehaviourInfo*>(pBhvrInfo->getBehaviourType(), pBhvrInfo)); + } + } + + // Process blocked commands + if (RlvSettings::getNoSetEnv()) + toggleBehaviourFlag("setenv", RLV_TYPE_ADDREM, RlvBehaviourInfo::BHVR_BLOCKED, true); +} + +RlvBehaviourDictionary::~RlvBehaviourDictionary() +{ + for (const RlvBehaviourInfo* pBhvrInfo : m_BhvrInfoList) + delete pBhvrInfo; + m_BhvrInfoList.clear(); + + for (int idxBhvrMod = 0; idxBhvrMod < RLV_MODIFIER_COUNT; idxBhvrMod++) + { + delete m_BehaviourModifiers[idxBhvrMod]; + m_BehaviourModifiers[idxBhvrMod] = nullptr; + } +} + +void RlvBehaviourDictionary::addEntry(const RlvBehaviourInfo* pEntry) +{ + // Filter experimental commands (if disabled) + static LLCachedControl<bool> sEnableExperimental(gSavedSettings, "RLVaExperimentalCommands"); + if ( (!pEntry) || ((!sEnableExperimental) && (pEntry->isExperimental())) ) + { + return; + } + + // Sanity check for duplicate entries +#ifndef LL_RELEASE_FOR_DOWNLOAD + std::for_each(m_BhvrInfoList.begin(), m_BhvrInfoList.end(), + [&pEntry](const RlvBehaviourInfo* pBhvrInfo) { + RLV_ASSERT_DBG( ((pBhvrInfo->getBehaviour()) != (pEntry->getBehaviour())) || ((pBhvrInfo->getParamTypeMask() & pEntry->getParamTypeMask()) == 0) ); + }); +#endif // LL_RELEASE_FOR_DOWNLOAD + + m_BhvrInfoList.push_back(pEntry); +} + +void RlvBehaviourDictionary::addModifier(ERlvBehaviour eBhvr, ERlvBehaviourModifier eModifier, RlvBehaviourModifier* pModifierEntry) +{ + if (eModifier < RLV_MODIFIER_COUNT) + { + m_BehaviourModifiers[eModifier] = pModifierEntry; + m_Bhvr2ModifierMap.insert(std::make_pair(eBhvr, eModifier)); + } +} + +const RlvBehaviourInfo* RlvBehaviourDictionary::getBehaviourInfo(const std::string& strBhvr, ERlvParamType eParamType, bool* pfStrict) const +{ + bool fStrict = boost::algorithm::ends_with(strBhvr, "_sec"); + if (pfStrict) + *pfStrict = fStrict; + + rlv_string2info_map_t::const_iterator itBhvr = m_String2InfoMap.find(std::make_pair( (!fStrict) ? strBhvr : strBhvr.substr(0, strBhvr.size() - 4), (eParamType & RLV_TYPE_ADDREM) ? RLV_TYPE_ADDREM : eParamType)); + return ( (itBhvr != m_String2InfoMap.end()) && ((!fStrict) || (itBhvr->second->hasStrict())) ) ? itBhvr->second : NULL; +} + +ERlvBehaviour RlvBehaviourDictionary::getBehaviourFromString(const std::string& strBhvr, ERlvParamType eParamType, bool* pfStrict) const +{ + const RlvBehaviourInfo* pBhvrInfo = getBehaviourInfo(strBhvr, eParamType, pfStrict); + return (pBhvrInfo) ? pBhvrInfo->getBehaviourType() : RLV_BHVR_UNKNOWN; +} + +bool RlvBehaviourDictionary::getCommands(const std::string& strMatch, ERlvParamType eParamType, std::list<std::string>& cmdList) const +{ + cmdList.clear(); + for (const RlvBehaviourInfo* pBhvrInfo : m_BhvrInfoList) + { + if ( (pBhvrInfo->getParamTypeMask() & eParamType) || (RLV_TYPE_UNKNOWN == eParamType) ) + { + std::string strCmd = pBhvrInfo->getBehaviour(); + if ( (std::string::npos != strCmd.find(strMatch)) || (strMatch.empty()) ) + cmdList.push_back(strCmd); + if ( (pBhvrInfo->hasStrict()) && ((std::string::npos != strCmd.append("_sec").find(strMatch)) || (strMatch.empty())) ) + cmdList.push_back(strCmd); + } + } + return !cmdList.empty(); +} + +bool RlvBehaviourDictionary::getHasStrict(ERlvBehaviour eBhvr) const +{ + for (const rlv_bhvr2info_map_t::value_type& itBhvr : boost::make_iterator_range(m_Bhvr2InfoMap.lower_bound(eBhvr), m_Bhvr2InfoMap.upper_bound(eBhvr))) + { + // Only restrictions can be strict + if (RLV_TYPE_ADDREM != itBhvr.second->getParamTypeMask()) + continue; + return itBhvr.second->hasStrict(); + } + RLV_ASSERT(false); + return false; +} + +RlvBehaviourModifier* RlvBehaviourDictionary::getModifierFromBehaviour(ERlvBehaviour eBhvr) const +{ + rlv_bhvr2mod_map_t::const_iterator itMod = m_Bhvr2ModifierMap.find(eBhvr); + ERlvBehaviourModifier eBhvrMod = (m_Bhvr2ModifierMap.end() != itMod) ? itMod->second : RLV_MODIFIER_UNKNOWN; + return (eBhvrMod < RLV_MODIFIER_UNKNOWN) ? m_BehaviourModifiers[eBhvrMod] : nullptr; +} + +void RlvBehaviourDictionary::toggleBehaviourFlag(const std::string& strBhvr, ERlvParamType eParamType, RlvBehaviourInfo::EBehaviourFlags eBhvrFlag, bool fEnable) +{ + rlv_string2info_map_t::const_iterator itBhvr = m_String2InfoMap.find(std::make_pair(strBhvr, (eParamType & RLV_TYPE_ADDREM) ? RLV_TYPE_ADDREM : eParamType)); + if (m_String2InfoMap.end() != itBhvr) + { + const_cast<RlvBehaviourInfo*>(itBhvr->second)->toggleBehaviourFlag(eBhvrFlag, fEnable); + } +} + +// ============================================================================ +// RlvBehaviourModifier +// + +RlvBehaviourModifier::RlvBehaviourModifier(std::string strName, const RlvBehaviourModifierValue& defaultValue, bool fAddDefaultOnEmpty, RlvBehaviourModifier_Comp* pValueComparator) + : m_strName(strName), m_DefaultValue(defaultValue), m_fAddDefaultOnEmpty(fAddDefaultOnEmpty), m_pValueComparator(pValueComparator) +{ + m_pValueComparator = (pValueComparator) ? pValueComparator : new RlvBehaviourModifier_Comp(); +} + +RlvBehaviourModifier::~RlvBehaviourModifier() +{ + if (m_pValueComparator) + { + delete m_pValueComparator; + m_pValueComparator = NULL; + } +} + +bool RlvBehaviourModifier::addValue(const RlvBehaviourModifierValue& modValue, const LLUUID& idObject) +{ + if (modValue.which() == m_DefaultValue.which()) + { + m_Values.insert((m_pValueComparator) ? std::lower_bound(m_Values.begin(), m_Values.end(), std::make_pair(modValue, idObject), boost::bind(&RlvBehaviourModifier_Comp::operator(), m_pValueComparator, _1, _2)) : m_Values.end(), std::make_pair(modValue, idObject)); + // NOTE: change signal needs to trigger before modifier handlers so cached values have a chance to update properly + m_ChangeSignal(getValue()); + onValueChange(); + return true; + } + return false; +} + +const LLUUID& RlvBehaviourModifier::getPrimaryObject() const +{ + return (m_pValueComparator) ? m_pValueComparator->m_idPrimaryObject : LLUUID::null; +} + +bool RlvBehaviourModifier::hasValue() const { + // If no primary object is set this returns "any value set"; otherwise it returns "any value set by the primary object" + if ( (!m_pValueComparator) || (m_pValueComparator->m_idPrimaryObject.isNull()) ) + return !m_Values.empty(); + return (!m_Values.empty()) ? m_Values.front().second == m_pValueComparator->m_idPrimaryObject : false; +} + +void RlvBehaviourModifier::removeValue(const RlvBehaviourModifierValue& modValue, const LLUUID& idObject) +{ + if ( (modValue.which() == m_DefaultValue.which()) ) + { + auto itValue = std::find(m_Values.begin(), m_Values.end(), std::make_pair(modValue, idObject)); + if (m_Values.end() != itValue) + { + m_Values.erase(itValue); + onValueChange(); + m_ChangeSignal(getValue()); + } + } +} + +void RlvBehaviourModifier::setPrimaryObject(const LLUUID& idPrimaryObject) +{ + if (m_pValueComparator) + { + m_pValueComparator->m_idPrimaryObject = idPrimaryObject; + m_Values.sort(boost::bind(&RlvBehaviourModifier_Comp::operator(), m_pValueComparator, _1, _2)); + onValueChange(); + m_ChangeSignal(getValue()); + } +} + +bool RlvBehaviourModifier::convertOptionValue(const std::string& optionValue, RlvBehaviourModifierValue& modValue) const +{ + try + { + if (typeid(float) == m_DefaultValue.type()) + { + modValue = std::stof(optionValue); + return true; + } + else if (typeid(int) == m_DefaultValue.type()) + { + modValue = std::stoi(optionValue); + return true; + } + else if (typeid(LLVector3) == m_DefaultValue.type()) + { + LLVector3 vecOption; + if (3 == sscanf(optionValue.c_str(), "%f/%f/%f", vecOption.mV + 0, vecOption.mV + 1, vecOption.mV + 2)) + { + modValue = vecOption; + return true; + } + } + else if (typeid(LLUUID) == m_DefaultValue.type()) + { + LLUUID idOption; + if (LLUUID::parseUUID(optionValue, &idOption)) + { + modValue = idOption; + return true; + } + } + return false; + } + catch (const std::invalid_argument&) + { + return false; + } +} + +// ============================================================================ +// RlvCommmand +// + +RlvCommand::RlvCommand(const LLUUID& idObj, const std::string& strCommand) + : m_fValid(false), m_idObj(idObj), m_pBhvrInfo(NULL), m_eParamType(RLV_TYPE_UNKNOWN), m_fStrict(false), m_fRefCounted(false) +{ + if (m_fValid = parseCommand(strCommand, m_strBehaviour, m_strOption, m_strParam)) + { + S32 nTemp = 0; + if ( ("n" == m_strParam) || ("add" == m_strParam) ) + m_eParamType = RLV_TYPE_ADD; + else if ( ("y" == m_strParam) || ("rem" == m_strParam) ) + m_eParamType = RLV_TYPE_REMOVE; + else if (m_strBehaviour == "clear") // clear is the odd one out so just make it its own type + m_eParamType = RLV_TYPE_CLEAR; + else if ("force" == m_strParam) + m_eParamType = RLV_TYPE_FORCE; + else if (LLStringUtil::convertToS32(m_strParam, nTemp)) // Assume it's a reply command if we can convert <param> to an S32 + m_eParamType = RLV_TYPE_REPLY; + else + { + m_eParamType = RLV_TYPE_UNKNOWN; + m_fValid = false; + } + } + + if (!m_fValid) + { + m_strOption = m_strParam = ""; + return; + } + + m_pBhvrInfo = RlvBehaviourDictionary::instance().getBehaviourInfo(m_strBehaviour, m_eParamType, &m_fStrict); +} + +RlvCommand::RlvCommand(const RlvCommand& rlvCmd, ERlvParamType eParamType) + : m_fValid(rlvCmd.m_fValid), m_idObj(rlvCmd.m_idObj), m_strBehaviour(rlvCmd.m_strBehaviour), m_pBhvrInfo(rlvCmd.m_pBhvrInfo), + m_eParamType( (RLV_TYPE_UNKNOWN == eParamType) ? rlvCmd.m_eParamType : eParamType),m_fStrict(rlvCmd.m_fStrict), m_strOption(rlvCmd.m_strOption), m_strParam(rlvCmd.m_strParam), m_fRefCounted(false) +{ +} + +bool RlvCommand::parseCommand(const std::string& strCommand, std::string& strBehaviour, std::string& strOption, std::string& strParam) +{ + // (See behaviour notes for the command parsing truth table) + + // Format: <behaviour>[:<option>]=<param> + int idxParam = strCommand.find('='); + int idxOption = (idxParam > 0) ? strCommand.find(':') : -1; + if (idxOption > idxParam - 1) + idxOption = -1; + + // If <behaviour> is missing it's always an improperly formatted command + if ( (0 == idxOption) || (0 == idxParam) ) + return false; + + strBehaviour = strCommand.substr(0, (-1 != idxOption) ? idxOption : idxParam); + strOption = strParam = ""; + + // If <param> is missing it's an improperly formatted command + if ( (-1 == idxParam) || ((int)strCommand.length() - 1 == idxParam) ) + { + // Unless "<behaviour> == "clear" AND (idxOption == 0)" + // OR <behaviour> == "clear" AND (idxParam != 0) [see table above] + if ( ("clear" == strBehaviour) && ( (!idxOption) || (idxParam) ) ) + return true; + return false; + } + + if ( (-1 != idxOption) && (idxOption + 1 != idxParam) ) + strOption = strCommand.substr(idxOption + 1, idxParam - idxOption - 1); + strParam = strCommand.substr(idxParam + 1); + + return true; +} + +// ============================================================================ +// Command option parsing utility classes +// + +template<> +bool RlvCommandOptionHelper::parseOption<LLUUID>(const std::string& strOption, LLUUID& idOption) +{ + idOption.set(strOption); + return idOption.notNull(); +} + +template<> +bool RlvCommandOptionHelper::parseOption<int>(const std::string& strOption, int& nOption) +{ + try + { + nOption = std::stoi(strOption); + } + catch (const std::invalid_argument&) + { + return false; + } + return true; +} + +template<> +bool RlvCommandOptionHelper::parseOption<float>(const std::string& strOption, float& nOption) +{ + try + { + nOption = std::stof(strOption); + } + catch (const std::invalid_argument&) + { + return false; + } + return true; +} + +template<> +bool RlvCommandOptionHelper::parseOption<LLWearableType::EType>(const std::string& strOption, LLWearableType::EType& wtOption) +{ + wtOption = LLWearableType::typeNameToType(strOption); + return (LLWearableType::WT_INVALID != wtOption) && (LLWearableType::WT_NONE != wtOption); +} + +template<> +bool RlvCommandOptionHelper::parseOption<LLViewerJointAttachment*>(const std::string& strOption, LLViewerJointAttachment*& pAttachPt) +{ + pAttachPt = RlvAttachPtLookup::getAttachPoint(strOption); + return pAttachPt != NULL; +} + +template<> +bool RlvCommandOptionHelper::parseOption<ERlvAttachGroupType>(const std::string& strOption, ERlvAttachGroupType& eAttachGroup) +{ + eAttachGroup = rlvAttachGroupFromString(strOption); + return eAttachGroup != RLV_ATTACHGROUP_INVALID; +} + +template<> +bool RlvCommandOptionHelper::parseOption<LLViewerInventoryCategory*>(const std::string& strOption, LLViewerInventoryCategory*& pFolder) +{ + pFolder = RlvInventory::instance().getSharedFolder(strOption); + return pFolder != NULL; +} + +template<> +bool RlvCommandOptionHelper::parseOption<LLVector3>(const std::string& strOption, LLVector3& vecOption) + { + if (!strOption.empty()) + { + S32 cntToken = sscanf(strOption.c_str(), "%f/%f/%f", vecOption.mV + 0, vecOption.mV + 1, vecOption.mV + 2); + return (3 == cntToken); + } + return false; +} + +template<> +bool RlvCommandOptionHelper::parseOption<LLVector3d>(const std::string& strOption, LLVector3d& vecOption) + { + if (!strOption.empty()) + { + S32 cntToken = sscanf(strOption.c_str(), "%lf/%lf/%lf", vecOption.mdV + 0, vecOption.mdV + 1, vecOption.mdV + 2); + return (3 == cntToken); + } + return false; +} + +template<> +bool RlvCommandOptionHelper::parseOption<RlvCommandOptionGeneric>(const std::string& strOption, RlvCommandOptionGeneric& genericOption) +{ + LLWearableType::EType wtType(LLWearableType::WT_INVALID); LLUUID idOption; ERlvAttachGroupType eAttachGroup(RLV_ATTACHGROUP_INVALID); + LLViewerJointAttachment* pAttachPt = NULL; LLViewerInventoryCategory* pFolder = NULL; LLVector3d posOption; float nOption; + + if (!strOption.empty()) // <option> could be an empty string + { + if (RlvCommandOptionHelper::parseOption(strOption, wtType)) + genericOption = wtType; // ... or specify a (valid) clothing layer + else if (RlvCommandOptionHelper::parseOption(strOption, pAttachPt)) + genericOption = pAttachPt; // ... or specify an attachment point + else if (RlvCommandOptionHelper::parseOption(strOption, idOption)) + genericOption = idOption; // ... or specify an UUID + else if (RlvCommandOptionHelper::parseOption(strOption, pFolder)) + genericOption = pFolder; // ... or specify a shared folder path + else if (RlvCommandOptionHelper::parseOption(strOption, eAttachGroup)) + genericOption = eAttachGroup; // ... or specify an attachment point group + else if (RlvCommandOptionHelper::parseOption(strOption, posOption)) + genericOption = posOption; // ... or specify a vector (region or global coordinates) + else if (RlvCommandOptionHelper::parseOption(strOption, nOption)) + genericOption = nOption; // ... or specify a number + else + genericOption = strOption; // ... or it might just be a string + } + return true; +} + +bool RlvCommandOptionHelper::parseStringList(const std::string& strOption, std::vector<std::string>& optionList, const std::string& strSeparator) +{ + if (!strOption.empty()) + boost::split(optionList, strOption, boost::is_any_of(strSeparator)); + return !optionList.empty(); +} + +// ============================================================================ +// RlvCommandOption structures +// + +// Checked: 2012-07-28 (RLVa-1.4.7) +class RlvCommandOptionGetPathCallback +{ +public: + RlvCommandOptionGetPathCallback(const LLUUID& idAttachObj, RlvCommandOptionGetPath::getpath_callback_t cb) + : mObjectId(idAttachObj), mCallback(cb) + { + if (isAgentAvatarValid()) + mAttachmentConnection = gAgentAvatarp->setAttachmentCallback(boost::bind(&RlvCommandOptionGetPathCallback::onAttachment, this, _1, _3)); + gIdleCallbacks.addFunction(&onIdle, this); + } + + ~RlvCommandOptionGetPathCallback() + { + if (mAttachmentConnection.connected()) + mAttachmentConnection.disconnect(); + gIdleCallbacks.deleteFunction(&onIdle, this); + } + + void onAttachment(LLViewerObject* pAttachObj, LLVOAvatarSelf::EAttachAction eAction) + { + if ( (LLVOAvatarSelf::ACTION_ATTACH == eAction) && (pAttachObj->getID() == mObjectId) ) + { + uuid_vec_t idItems(1, pAttachObj->getAttachmentItemID()); + mCallback(idItems); + delete this; + } + } + + static void onIdle(void* pData) + { + RlvCommandOptionGetPathCallback* pInstance = reinterpret_cast<RlvCommandOptionGetPathCallback*>(pData); + if (pInstance->mExpirationTimer.getElapsedTimeF32() > 30.0f) + delete pInstance; + } + +protected: + LLUUID mObjectId; + RlvCommandOptionGetPath::getpath_callback_t mCallback; + boost::signals2::connection mAttachmentConnection; + LLFrameTimer mExpirationTimer; +}; + +// Checked: 2010-11-30 (RLVa-1.3.0b) | Modified: RLVa-1.3.0b +RlvCommandOptionGetPath::RlvCommandOptionGetPath(const RlvCommand& rlvCmd, getpath_callback_t cb) + : m_fCallback(false) +{ + m_fValid = true; // Assume the option will be a valid one until we find out otherwise + + // @getpath[:<option>]=<channel> => <option> is transformed to a list of inventory item UUIDs to get the path of + RlvCommandOptionGeneric rlvCmdOption; + RlvCommandOptionHelper::parseOption(rlvCmd.getOption(), rlvCmdOption); + if (rlvCmdOption.isWearableType()) // <option> can be a clothing layer + { + getItemIDs(rlvCmdOption.getWearableType(), m_idItems); + } + else if (rlvCmdOption.isAttachmentPoint()) // ... or it can specify an attachment point + { + getItemIDs(rlvCmdOption.getAttachmentPoint(), m_idItems); + } + else if (rlvCmdOption.isUUID()) // ... or it can specify a specific attachment + { + const LLViewerObject* pAttachObj = gObjectList.findObject(rlvCmdOption.getUUID()); + if ( (pAttachObj) && (pAttachObj->isAttachment()) && (pAttachObj->permYouOwner()) ) + m_idItems.push_back(pAttachObj->getAttachmentItemID()); + else + m_fValid = false; + } + else if (rlvCmdOption.isEmpty()) // ... or it can be empty (in which case we act on the object that issued the command) + { + const LLViewerObject* pObj = gObjectList.findObject(rlvCmd.getObjectID()); + if (pObj) + { + if (pObj->isAttachment()) + m_idItems.push_back(pObj->getAttachmentItemID()); + } + else if (!cb.empty()) + { + new RlvCommandOptionGetPathCallback(rlvCmd.getObjectID(), cb); + m_fCallback = true; + return; + } + } + else // ... but anything else isn't a valid option + { + m_fValid = false; + return; + } + + if (!cb.empty()) + { + cb(getItemIDs()); + } +} + +// Checked: 2013-10-12 (RLVa-1.4.9) +bool RlvCommandOptionGetPath::getItemIDs(const LLViewerJointAttachment* pAttachPt, uuid_vec_t& idItems) +{ + uuid_vec_t::size_type cntItemsPrev = idItems.size(); + + LLInventoryModel::cat_array_t folders; LLInventoryModel::item_array_t items; + RlvFindAttachmentsOnPoint f(pAttachPt); + gInventory.collectDescendentsIf(LLAppearanceMgr::instance().getCOF(), folders, items, false, f); + for (LLInventoryModel::item_array_t::const_iterator itItem = items.begin(); itItem != items.end(); ++itItem) + { + const LLViewerInventoryItem* pItem = *itItem; + if (pItem) + idItems.push_back(pItem->getLinkedUUID()); + } + + return (cntItemsPrev != idItems.size()); +} + +// Checked: 2013-10-12 (RLVa-1.4.9) +bool RlvCommandOptionGetPath::getItemIDs(LLWearableType::EType wtType, uuid_vec_t& idItems) +{ + uuid_vec_t::size_type cntItemsPrev = idItems.size(); + + LLInventoryModel::cat_array_t folders; LLInventoryModel::item_array_t items; + LLFindWearablesOfType f(wtType); + gInventory.collectDescendentsIf(LLAppearanceMgr::instance().getCOF(), folders, items, false, f); + for (LLInventoryModel::item_array_t::const_iterator itItem = items.begin(); itItem != items.end(); ++itItem) + { + const LLViewerInventoryItem* pItem = *itItem; + if (pItem) + idItems.push_back(pItem->getLinkedUUID()); + } + + return (cntItemsPrev != idItems.size()); +} + +// Checked: 2015-03-30 (RLVa-1.5.0) +RlvCommandOptionAdjustHeight::RlvCommandOptionAdjustHeight(const RlvCommand& rlvCmd) + : m_nPelvisToFoot(0.0f), m_nPelvisToFootDeltaMult(0.0f), m_nPelvisToFootOffset(0.0f) +{ + std::vector<std::string> cmdTokens; + boost::split(cmdTokens, rlvCmd.getOption(), boost::is_any_of(std::string(";"))); + if (1 == cmdTokens.size()) + { + m_fValid = (LLStringUtil::convertToF32(cmdTokens[0], m_nPelvisToFootOffset)); + m_nPelvisToFootOffset /= 100; + } + else if ( (2 <= cmdTokens.size()) && (cmdTokens.size() <= 3) ) + { + m_fValid = (LLStringUtil::convertToF32(cmdTokens[0], m_nPelvisToFoot)) && + (LLStringUtil::convertToF32(cmdTokens[1], m_nPelvisToFootDeltaMult)) && + ( (2 == cmdTokens.size()) || (LLStringUtil::convertToF32(cmdTokens[2], m_nPelvisToFootOffset)) ); + } +} + +// ========================================================================= +// RlvObject +// + +RlvObject::RlvObject(const LLUUID& idObj) : m_idObj(idObj), m_nLookupMisses(0) +{ + LLViewerObject* pObj = gObjectList.findObject(idObj); + m_fLookup = (NULL != pObj); + m_idxAttachPt = (pObj) ? ATTACHMENT_ID_FROM_STATE(pObj->getState()) : 0; + m_idRoot = (pObj) ? pObj->getRootEdit()->getID() : LLUUID::null; +} + +bool RlvObject::addCommand(const RlvCommand& rlvCmd) +{ + RLV_ASSERT(RLV_TYPE_ADD == rlvCmd.getParamType()); + + // Don't add duplicate commands for this object (ie @detach=n followed by another @detach=n later on) + for (rlv_command_list_t::iterator itCmd = m_Commands.begin(); itCmd != m_Commands.end(); ++itCmd) + { + if ( (itCmd->getBehaviour() == rlvCmd.getBehaviour()) && (itCmd->getOption() == rlvCmd.getOption()) && + (itCmd->isStrict() == rlvCmd.isStrict() ) ) + { + return false; + } + } + + // Now that we know it's not a duplicate, add it to the end of the list + m_Commands.push_back(rlvCmd); + + return true; +} + +bool RlvObject::removeCommand(const RlvCommand& rlvCmd) +{ + RLV_ASSERT(RLV_TYPE_REMOVE == rlvCmd.getParamType()); + + for (rlv_command_list_t::iterator itCmd = m_Commands.begin(); itCmd != m_Commands.end(); ++itCmd) + { + //if (*itCmd == rlvCmd) <- commands will never be equal since one is an add and the other is a remove *rolls eyes* + if ( (itCmd->getBehaviour() == rlvCmd.getBehaviour()) && (itCmd->getOption() == rlvCmd.getOption()) && + (itCmd->isStrict() == rlvCmd.isStrict() ) ) + { + m_Commands.erase(itCmd); + return true; + } + } + return false; // Command was never added so nothing to remove now +} + +bool RlvObject::hasBehaviour(ERlvBehaviour eBehaviour, bool fStrictOnly) const +{ + for (rlv_command_list_t::const_iterator itCmd = m_Commands.begin(); itCmd != m_Commands.end(); ++itCmd) + if ( (itCmd->getBehaviourType() == eBehaviour) && (itCmd->getOption().empty()) && ((!fStrictOnly) || (itCmd->isStrict())) ) + return true; + return false; +} + +bool RlvObject::hasBehaviour(ERlvBehaviour eBehaviour, const std::string& strOption, bool fStrictOnly) const +{ + for (const RlvCommand& rlvCmd : m_Commands) + { + // The specified behaviour is contained within the current object if: + // - the (parsed) behaviour matches + // - the option matches (or we're checking for an empty option and the command was reference counted) + // - we're not matching on strict (or it is a strict command) + if ( (rlvCmd.getBehaviourType() == eBehaviour) && + ( (rlvCmd.getOption() == strOption) || ((strOption.empty()) && (rlvCmd.isRefCounted())) ) && + ( (!fStrictOnly) ||(rlvCmd.isStrict()) ) ) + { + return true; + } + } + return false; +} + +// Checked: 2009-11-27 (RLVa-1.1.0f) | Modified: RLVa-1.1.0f +std::string RlvObject::getStatusString(const std::string& strFilter, const std::string& strSeparator) const +{ + std::string strStatus, strCmd; + + for (rlv_command_list_t::const_iterator itCmd = m_Commands.begin(); itCmd != m_Commands.end(); ++itCmd) + { + strCmd = itCmd->asString(); + if ( (strFilter.empty()) || (std::string::npos != strCmd.find(strFilter)) ) + strStatus.append(strSeparator).append(strCmd); + } + + return strStatus; +} + +// ============================================================================ +// RlvForceWear +// + +// Checked: 2010-04-05 (RLVa-1.2.0d) | Modified: RLVa-1.2.0d +bool RlvForceWear::isWearingItem(const LLInventoryItem* pItem) +{ + if (pItem) + { + switch (pItem->getActualType()) + { + case LLAssetType::AT_BODYPART: + case LLAssetType::AT_CLOTHING: + return gAgentWearables.isWearingItem(pItem->getUUID()); + case LLAssetType::AT_OBJECT: + return (isAgentAvatarValid()) && (gAgentAvatarp->isWearingAttachment(pItem->getUUID())); + case LLAssetType::AT_GESTURE: + return LLGestureMgr::instance().isGestureActive(pItem->getUUID()); + case LLAssetType::AT_LINK: + return isWearingItem(gInventory.getItem(pItem->getLinkedUUID())); + default: + break; + } + } + return false; +} + +// Checked: 2010-03-21 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a +void RlvForceWear::forceFolder(const LLViewerInventoryCategory* pFolder, EWearAction eAction, EWearFlags eFlags) +{ + // [See LLWearableBridge::wearOnAvatar(): don't wear anything until initial wearables are loaded, can destroy clothing items] + if (!gAgentWearables.areWearablesLoaded()) + { + LLNotificationsUtil::add("CanNotChangeAppearanceUntilLoaded"); + return; + } + if (!isAgentAvatarValid()) + return; + + // Grab a list of all the items we'll be wearing/attaching + LLInventoryModel::cat_array_t folders; LLInventoryModel::item_array_t items; + RlvWearableItemCollector f(pFolder, eAction, eFlags); + gInventory.collectDescendentsIf(pFolder->getUUID(), folders, items, FALSE, f, true); + + // TRUE if we've already encountered this LLWearableType::EType (used only on wear actions and only for AT_CLOTHING) + bool fSeenWType[LLWearableType::WT_COUNT] = { false }; + + EWearAction eCurAction = eAction; + for (S32 idxItem = 0, cntItem = items.size(); idxItem < cntItem; idxItem++) + { + LLViewerInventoryItem* pRlvItem = items.at(idxItem); + LLViewerInventoryItem* pItem = (LLAssetType::AT_LINK == pRlvItem->getActualType()) ? pRlvItem->getLinkedItem() : pRlvItem; + + // If it's wearable it should be worn on detach +// if ( (ACTION_DETACH == eAction) && (isWearableItem(pItem)) && (!isWearingItem(pItem)) ) +// continue; + + // Each folder can specify its own EWearAction override + if (isWearAction(eAction)) + eCurAction = f.getWearAction(pRlvItem->getParentUUID()); + else + eCurAction = eAction; + + // NOTES: * if there are composite items then RlvWearableItemCollector made sure they can be worn (or taken off depending) + // * some scripts issue @remattach=force,attach:worn-items=force so we need to attach items even if they're currently worn + switch (pItem->getType()) + { + case LLAssetType::AT_BODYPART: + RLV_ASSERT(isWearAction(eAction)); // RlvWearableItemCollector shouldn't be supplying us with body parts on detach + case LLAssetType::AT_CLOTHING: + if (isWearAction(eAction)) + { + // The first time we encounter any given clothing type we use 'eCurAction' (replace or add) + // The second time we encounter a given clothing type we'll always add (rather than replace the previous iteration) + eCurAction = (!fSeenWType[pItem->getWearableType()]) ? eCurAction : ACTION_WEAR_ADD; + + ERlvWearMask eWearMask = gRlvWearableLocks.canWear(pRlvItem); + if ( ((ACTION_WEAR_REPLACE == eCurAction) && (eWearMask & RLV_WEAR_REPLACE)) || + ((ACTION_WEAR_ADD == eCurAction) && (eWearMask & RLV_WEAR_ADD)) ) + { + // The check for whether we're replacing a currently worn composite item happens in onWearableArrived() + if (!isAddWearable(pItem)) + addWearable(pRlvItem, eCurAction); + fSeenWType[pItem->getWearableType()] = true; + } + } + else + { + const LLViewerWearable* pWearable = gAgentWearables.getWearableFromItemID(pItem->getUUID()); + if ( (pWearable) && (isForceRemovable(pWearable, false)) ) + remWearable(pWearable); + } + break; + + case LLAssetType::AT_OBJECT: + if (isWearAction(eAction)) + { + ERlvWearMask eWearMask = gRlvAttachmentLocks.canAttach(pRlvItem); + if ( ((ACTION_WEAR_REPLACE == eCurAction) && (eWearMask & RLV_WEAR_REPLACE)) || + ((ACTION_WEAR_ADD == eCurAction) && (eWearMask & RLV_WEAR_ADD)) ) + { + if (!isAddAttachment(pRlvItem)) + { + #ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS + // We still need to check whether we're about to replace a currently worn composite item + // (which we're not if we're just reattaching an attachment we're already wearing) + LLViewerInventoryCategory* pCompositeFolder = NULL; + if ( (pAttachPt->getObject()) && (RlvSettings::getEnableComposites()) && + (pAttachPt->getItemID() != pItem->getUUID()) && + (gRlvHandler.getCompositeInfo(pAttachPt->getItemID(), NULL, &pCompositeFolder)) ) + { + // If we can't take off the composite folder this item would replace then don't allow it to get attached + if (gRlvHandler.canTakeOffComposite(pCompositeFolder)) + { + forceFolder(pCompositeFolder, ACTION_DETACH, FLAG_DEFAULT); + addAttachment(pRlvItem); + } + } + else + #endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS + { + addAttachment(pRlvItem, eCurAction); + } + } + } + } + else + { + const LLViewerObject* pAttachObj = gAgentAvatarp->getWornAttachment(pItem->getUUID()); + if ( (pAttachObj) && (isForceDetachable(pAttachObj, false)) ) + remAttachment(pAttachObj); + } + break; + + case LLAssetType::AT_GESTURE: + if (isWearAction(eAction)) + { + if (std::find_if(m_addGestures.begin(), m_addGestures.end(), RlvPredIsEqualOrLinkedItem(pRlvItem)) == m_addGestures.end()) + m_addGestures.push_back(pRlvItem); + } + else + { + if (std::find_if(m_remGestures.begin(), m_remGestures.end(), RlvPredIsEqualOrLinkedItem(pRlvItem)) == m_remGestures.end()) + m_remGestures.push_back(pRlvItem); + } + break; + + default: + break; + } + } +} + +// Checked: 2010-03-19 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a +bool RlvForceWear::isForceDetachable(const LLViewerObject* pAttachObj, bool fCheckComposite /*=true*/, const LLUUID& idExcept /*=LLUUID::null*/) +{ + // Attachment can be detached by an RLV command if: + // - it's not "remove locked" by anything (or anything except the object specified by pExceptObj) + // - it's strippable + // - composite folders are disabled *or* it isn't part of a composite folder that has at least one item locked + #ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS + LLViewerInventoryCategory* pFolder = NULL; + #endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS + return + ( + (pAttachObj) && (pAttachObj->isAttachment()) + && ( (idExcept.isNull()) ? (!gRlvAttachmentLocks.isLockedAttachment(pAttachObj)) + : (!gRlvAttachmentLocks.isLockedAttachmentExcept(pAttachObj, idExcept)) ) + && (isStrippable(pAttachObj->getAttachmentItemID())) + #ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS + && ( (!fCheckComposite) || (!RlvSettings::getEnableComposites()) || + (!gRlvHandler.getCompositeInfo(pAttachPt->getItemID(), NULL, &pFolder)) || (gRlvHandler.canTakeOffComposite(pFolder)) ) + #endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS + ); +} + +// Checked: 2010-03-19 (RLVa-1.2.0a) | Added: RLVa-1.2.0a +bool RlvForceWear::isForceDetachable(const LLViewerJointAttachment* pAttachPt, bool fCheckComposite /*=true*/, const LLUUID& idExcept /*=LLUUID::null*/) +{ + // Attachment point can be detached by an RLV command if there's at least one attachment that can be removed + for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator itAttachObj = pAttachPt->mAttachedObjects.begin(); + itAttachObj != pAttachPt->mAttachedObjects.end(); ++itAttachObj) + { + if (isForceDetachable(*itAttachObj, fCheckComposite, idExcept)) + return true; + } + return false; +} + +// Checked: 2010-03-19 (RLVa-1.2.0a) | Added: RLVa-1.1.0i +void RlvForceWear::forceDetach(const LLViewerObject* pAttachObj) +{ + // Sanity check - no need to process duplicate removes + if ( (!pAttachObj) || (isRemAttachment(pAttachObj)) ) + return; + + if (isForceDetachable(pAttachObj)) + { + #ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS + LLViewerInventoryCategory* pFolder = NULL; + if ( (RlvSettings::getEnableComposites()) && + (gRlvHandler.getCompositeInfo(pAttachPt->getItemID(), NULL, &pFolder)) ) + { + // Attachment belongs to a composite folder so detach the entire folder (if we can take it off) + if (gRlvHandler.canTakeOffComposite(pFolder)) + forceFolder(pFolder, ACTION_DETACH, FLAG_DEFAULT); + } + else + #endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS + { + remAttachment(pAttachObj); + } + } +} + +// Checked: 2010-03-19 (RLVa-1.2.0a) | Added: RLVa-1.2.0a +void RlvForceWear::forceDetach(const LLViewerJointAttachment* pAttachPt) +{ + for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator itAttachObj = pAttachPt->mAttachedObjects.begin(); + itAttachObj != pAttachPt->mAttachedObjects.end(); ++itAttachObj) + { + forceDetach(*itAttachObj); + } +} + +// Checked: 2010-03-19 (RLVa-1.2.0c) | Modified: RLVa-1.2.0a +bool RlvForceWear::isForceRemovable(const LLViewerWearable* pWearable, bool fCheckComposite /*=true*/, const LLUUID& idExcept /*=LLUUID::null*/) +{ + // Wearable can be removed by an RLV command if: + // - its asset type is AT_CLOTHING + // - it's not "remove locked" by anything (or anything except the object specified by idExcept) + // - it's strippable + // - composite folders are disabled *or* it isn't part of a composite folder that has at least one item locked + #ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS + LLViewerInventoryCategory* pFolder = NULL; + #endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS + return + ( + (pWearable) && (LLAssetType::AT_CLOTHING == pWearable->getAssetType()) + && ( (idExcept.isNull()) ? !gRlvWearableLocks.isLockedWearable(pWearable) + : !gRlvWearableLocks.isLockedWearableExcept(pWearable, idExcept) ) + && (isStrippable(pWearable->getItemID())) + #ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS + && ( (!fCheckComposite) || (!RlvSettings::getEnableComposites()) || + (!gRlvHandler.getCompositeInfo(pWearable->getItemID(), NULL, &pFolder)) || (gRlvHandler.canTakeOffComposite(pFolder)) ) + #endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS + ); +} + +// Checked: 2010-03-19 (RLVa-1.2.0a) | Added: RLVa-1.2.0a +bool RlvForceWear::isForceRemovable(LLWearableType::EType wtType, bool fCheckComposite /*=true*/, const LLUUID& idExcept /*=LLUUID::null*/) +{ + // Wearable type can be removed by an RLV command if there's at least one currently worn wearable that can be removed + for (U32 idxWearable = 0, cntWearable = gAgentWearables.getWearableCount(wtType); idxWearable < cntWearable; idxWearable++) + if (isForceRemovable(gAgentWearables.getViewerWearable(wtType, idxWearable), fCheckComposite, idExcept)) + return true; + return false; +} + +// Checked: 2010-03-19 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a +void RlvForceWear::forceRemove(const LLViewerWearable* pWearable) +{ + // Sanity check - no need to process duplicate removes + if ( (!pWearable) || (isRemWearable(pWearable)) ) + return; + + if (isForceRemovable(pWearable)) + { + #ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS + LLViewerInventoryCategory* pFolder = NULL; + if ( (RlvSettings::getEnableComposites()) && + (gRlvHandler.getCompositeInfo(gAgent.getWearableItem(wtType), NULL, &pFolder)) ) + { + // Wearable belongs to a composite folder so detach the entire folder (if we can take it off) + if (gRlvHandler.canTakeOffComposite(pFolder)) + forceFolder(pFolder, ACTION_DETACH, FLAG_DEFAULT); + } + else + #endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS + { + remWearable(pWearable); + } + } +} + +// Checked: 2010-03-19 (RLVa-1.2.0a) | Added: RLVa-1.2.0a +void RlvForceWear::forceRemove(LLWearableType::EType wtType) +{ + for (U32 idxWearable = 0, cntWearable = gAgentWearables.getWearableCount(wtType); idxWearable < cntWearable; idxWearable++) + forceRemove(gAgentWearables.getViewerWearable(wtType, idxWearable)); +} + +// Checked: 2010-03-19 (RLVa-1.2.0c) | Modified: RLVa-1.2.0a +bool RlvForceWear::isStrippable(const LLInventoryItem* pItem) +{ + // An item is exempt from @detach or @remoutfit if: + // - its name contains "nostrip" (anywhere in the name) + // - its parent folder contains "nostrip" (anywhere in the name) + if (pItem) + { + // If the item is an inventory link then we first examine its target before examining the link itself (and never its name) + if (LLAssetType::AT_LINK == pItem->getActualType()) + { + if (!isStrippable(pItem->getLinkedUUID())) + return false; + } + else + { + if (std::string::npos != pItem->getName().find(RLV_FOLDER_FLAG_NOSTRIP)) + return false; + } + + LLViewerInventoryCategory* pFolder = gInventory.getCategory(pItem->getParentUUID()); + while (pFolder) + { + if (std::string::npos != pFolder->getName().find(RLV_FOLDER_FLAG_NOSTRIP)) + return false; + // If the item's parent is a folded folder then we need to check its parent as well + if ( (gInventory.getRootFolderID() != pFolder->getParentUUID()) && (RlvInventory::isFoldedFolder(pFolder, true)) ) + pFolder = gInventory.getCategory(pFolder->getParentUUID()); + else + pFolder = NULL; + } + } + return true; +} + +// Checked: 2010-08-30 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c +void RlvForceWear::addAttachment(const LLViewerInventoryItem* pItem, EWearAction eAction) +{ + // Remove it from 'm_remAttachments' if it's queued for detaching + const LLViewerObject* pAttachObj = (isAgentAvatarValid()) ? gAgentAvatarp->getWornAttachment(pItem->getLinkedUUID()) : NULL; + if ( (pAttachObj) && (isRemAttachment(pAttachObj)) ) + m_remAttachments.erase(std::remove(m_remAttachments.begin(), m_remAttachments.end(), pAttachObj), m_remAttachments.end()); + + S32 idxAttachPt = RlvAttachPtLookup::getAttachPointIndex(pItem, true); + if (ACTION_WEAR_ADD == eAction) + { + // Insert it at the back if it's not already there + idxAttachPt |= ATTACHMENT_ADD; + if (!isAddAttachment(pItem)) + { + addattachments_map_t::iterator itAddAttachments = m_addAttachments.find(idxAttachPt); + if (itAddAttachments == m_addAttachments.end()) + { + m_addAttachments.insert(addattachment_pair_t(idxAttachPt, LLInventoryModel::item_array_t())); + itAddAttachments = m_addAttachments.find(idxAttachPt); + } + itAddAttachments->second.push_back((LLViewerInventoryItem*)pItem); + } + } + else if (ACTION_WEAR_REPLACE == eAction) + { + // Replace all pending attachments on this attachment point with the specified item (don't clear if it's the default attach point) + addattachments_map_t::iterator itAddAttachments = m_addAttachments.find(idxAttachPt | ATTACHMENT_ADD); + if ( (0 != idxAttachPt) && (itAddAttachments != m_addAttachments.end()) ) + itAddAttachments->second.clear(); + + itAddAttachments = m_addAttachments.find(idxAttachPt); + if (itAddAttachments == m_addAttachments.end()) + { + m_addAttachments.insert(addattachment_pair_t(idxAttachPt, LLInventoryModel::item_array_t())); + itAddAttachments = m_addAttachments.find(idxAttachPt); + } + + if (0 != idxAttachPt) + itAddAttachments->second.clear(); + itAddAttachments->second.push_back((LLViewerInventoryItem*)pItem); + } +} + +// Checked: 2010-08-30 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c +void RlvForceWear::remAttachment(const LLViewerObject* pAttachObj) +{ + // Remove it from 'm_addAttachments' if it's queued for attaching + const LLViewerInventoryItem* pItem = (pAttachObj->isAttachment()) ? gInventory.getItem(pAttachObj->getAttachmentItemID()) : NULL; + if (pItem) + { + addattachments_map_t::iterator itAddAttachments = m_addAttachments.begin(); + while (itAddAttachments != m_addAttachments.end()) + { + LLInventoryModel::item_array_t& wearItems = itAddAttachments->second; + if (std::find_if(wearItems.begin(), wearItems.end(), RlvPredIsEqualOrLinkedItem(pItem)) != wearItems.end()) + wearItems.erase(std::remove_if(wearItems.begin(), wearItems.end(), RlvPredIsEqualOrLinkedItem(pItem)), wearItems.end()); + + if (wearItems.empty()) + m_addAttachments.erase(itAddAttachments++); + else + ++itAddAttachments; + } + } + + // Add it to 'm_remAttachments' if it's not already there + if (!isRemAttachment(pAttachObj)) + { + m_remAttachments.push_back(const_cast<LLViewerObject*>(pAttachObj)); + } +} + +// Checked: 2010-08-30 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c +void RlvForceWear::addWearable(const LLViewerInventoryItem* pItem, EWearAction eAction) +{ + const LLViewerWearable* pWearable = gAgentWearables.getWearableFromItemID(pItem->getLinkedUUID()); + // When replacing remove all currently worn wearables of this type *unless* the item is currently worn + if ( (ACTION_WEAR_REPLACE == eAction) && (!pWearable) ) + forceRemove(pItem->getWearableType()); + // Remove it from 'm_remWearables' if it's pending removal + if ( (pWearable) && (isRemWearable(pWearable)) ) + m_remWearables.erase(std::remove(m_remWearables.begin(), m_remWearables.end(), pWearable), m_remWearables.end()); + + addwearables_map_t::iterator itAddWearables = m_addWearables.find(pItem->getWearableType()); + if (itAddWearables == m_addWearables.end()) + { + m_addWearables.insert(addwearable_pair_t(pItem->getWearableType(), LLInventoryModel::item_array_t())); + itAddWearables = m_addWearables.find(pItem->getWearableType()); + } + + if (ACTION_WEAR_ADD == eAction) // Add it at the back if it's not already there + { + if (!isAddWearable(pItem)) + itAddWearables->second.push_back((LLViewerInventoryItem*)pItem); + } + else if (ACTION_WEAR_REPLACE == eAction) // Replace all pending wearables of this type with the specified item + { + itAddWearables->second.clear(); + itAddWearables->second.push_back((LLViewerInventoryItem*)pItem); + } +} + +// Checked: 2010-08-30 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c +void RlvForceWear::remWearable(const LLViewerWearable* pWearable) +{ + // Remove it from 'm_addWearables' if it's queued for wearing + const LLViewerInventoryItem* pItem = gInventory.getItem(pWearable->getItemID()); + if ( (pItem) && (isAddWearable(pItem)) ) + { + addwearables_map_t::iterator itAddWearables = m_addWearables.find(pItem->getWearableType()); + + LLInventoryModel::item_array_t& wearItems = itAddWearables->second; + wearItems.erase(std::remove_if(wearItems.begin(), wearItems.end(), RlvPredIsEqualOrLinkedItem(pItem)), wearItems.end()); + if (wearItems.empty()) + m_addWearables.erase(itAddWearables); + } + + // Add it to 'm_remWearables' if it's not already there + if (!isRemWearable(pWearable)) + m_remWearables.push_back(pWearable); +} + +// Checked: 2015-05-05 (RLVa-1.4.12) +void RlvForceWear::updatePendingAttachments() +{ + if (RlvForceWear::instanceExists()) + { + RlvForceWear* pThis = RlvForceWear::getInstance(); + for (const pendingattachments_map_t::value_type& itAttach : pThis->m_pendingAttachments) + LLAttachmentsMgr::instance().addAttachmentRequest(itAttach.first, itAttach.second & ~ATTACHMENT_ADD, itAttach.second & ATTACHMENT_ADD); + pThis->m_pendingAttachments.clear(); + } +} + +// Checked: 2015-05-05 (RLVa-1.4.12) +void RlvForceWear::addPendingAttachment(const LLUUID& idItem, U8 idxPoint) +{ + auto itAttach = m_pendingAttachments.find(idItem); + if (m_pendingAttachments.end() == itAttach) + m_pendingAttachments.insert(std::make_pair(idItem, idxPoint)); + else + itAttach->second = idxPoint; +} + +// Checked: 2015-05-05 (RLVa-1.4.12) +void RlvForceWear::remPendingAttachment(const LLUUID& idItem) +{ + m_pendingAttachments.erase(idItem); +} + +// Checked: 2015-05-05 (RLVa-1.4.12) +void RlvForceWear::done() +{ + // Sanity check - don't go through all the motions below only to find out there's nothing to actually do + if ( (m_remWearables.empty()) && (m_remAttachments.empty()) && (m_remGestures.empty()) && + (m_addWearables.empty()) && (m_addAttachments.empty()) && (m_addGestures.empty()) ) + { + return; + } + + // + // Process removals + // + + uuid_vec_t remItems; + + // Wearables + if (m_remWearables.size()) + { + for (const LLViewerWearable* pWearable : m_remWearables) + remItems.push_back(pWearable->getItemID()); + m_remWearables.clear(); + } + + // Gestures + if (m_remGestures.size()) + { + // NOTE: LLGestureMgr::deactivateGesture() will call LLAppearanceMgr::removeCOFItemLinks() for us and supply its own callback + for (const LLViewerInventoryItem* pItem : m_remGestures) + LLGestureMgr::instance().deactivateGesture(pItem->getUUID()); + m_remGestures.clear(); + } + + // Attachments + if (m_remAttachments.size()) + { + LLAgentWearables::userRemoveMultipleAttachments(m_remAttachments); + for (const LLViewerObject* pAttachObj : m_remAttachments) + remItems.push_back(pAttachObj->getAttachmentItemID()); + m_remAttachments.clear(); + } + + // + // Process additions + // + + // Wearables need to be split into AT_BODYPART and AT_CLOTHING for COF + LLInventoryModel::item_array_t addBodyParts, addClothing; + for (addwearables_map_t::const_iterator itAddWearables = m_addWearables.cbegin(); itAddWearables != m_addWearables.cend(); ++itAddWearables) + { + // NOTE: LLAppearanceMgr will filter our duplicates so no need for us to check here + for (LLViewerInventoryItem* pItem : itAddWearables->second) + { + if (LLAssetType::AT_BODYPART == pItem->getType()) + addBodyParts.push_back(pItem); + else + addClothing.push_back(pItem); + } + } + m_addWearables.clear(); + + // Until LL provides a way for updateCOF to selectively attach add/replace we have to deal with attachments ourselves + for (addattachments_map_t::const_iterator itAddAttachments = m_addAttachments.cbegin(); itAddAttachments != m_addAttachments.cend(); ++itAddAttachments) + { + for (const LLViewerInventoryItem* pItem : itAddAttachments->second) + addPendingAttachment(pItem->getLinkedUUID(), itAddAttachments->first); + } + m_addAttachments.clear(); + + // + // Tie it all together + // + + // | Wearables | Attachments | Gestures | + // |======================================================| + // Add : | LLAppearanceMgr | <custom> | LLAppearanceMgr | + // Remove : | LLAppearanceMgr | LLAppearanceMgr | LLGestureMgr | + LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy(false, false, boost::bind(RlvForceWear::updatePendingAttachments)); + + if (!remItems.empty()) + { + LLAppearanceMgr::instance().removeItemsFromAvatar(remItems, cb, true); + } + + if ( (addBodyParts.empty()) && (!addClothing.empty()) && (m_addGestures.empty()) ) + { + // Clothing items only + uuid_vec_t idClothing; + for (const LLViewerInventoryItem* pItem : addClothing) + idClothing.push_back(pItem->getUUID()); + LLAppearanceMgr::instance().wearItemsOnAvatar(idClothing, false, false, cb); + } + else if ( (!addBodyParts.empty()) || (!addClothing.empty()) || (!m_addGestures.empty()) ) + { + // Mixture of body parts, clothing and/or gestures + LLInventoryModel::item_array_t addAttachments; + LLAppearanceMgr::instance().updateCOF(addBodyParts, addClothing, addAttachments, m_addGestures, true, LLUUID::null, cb); + + m_addGestures.clear(); + } + + // Make sure there are no leftovers for the next cycle + RLV_ASSERT( (m_remWearables.empty()) && (m_remAttachments.empty()) && (m_remGestures.empty()) ); + RLV_ASSERT( (m_addWearables.empty()) && (m_addAttachments.empty()) && (m_addGestures.empty()) ); +} + +// Checked: 2010-02-17 (RLVa-1.1.0o) | Modified: RLVa-1.1.0o +/* +void RlvForceWear::onWearableArrived(LLWearable* pWearable, void* pParam) +{ + #ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS + // If this wearable will end up replacing a currently worn one that belongs to a composite folder then we need to detach the composite + LLViewerInventoryCategory* pFolder = NULL; + if ( (RlvSettings::getEnableComposites()) && (pWearable) && (gAgent.getWearable(pWearable->getType())) ) + { + // If we're just rewearing the same item we're already wearing then we're not replacing a composite folder + LLWearableHoldingPattern* pWearData = (LLWearableHoldingPattern*)pParam; LLUUID idItem; + for (LLWearableHoldingPattern::found_list_t::const_iterator itWearable = pWearData->mFoundList.begin(); + itWearable != pWearData->mFoundList.end(); ++itWearable) + { + LLFoundData* pFound = *itWearable; + if (pWearable->getID() == pFound->mAssetID) + { + idItem = pFound->mItemID; + break; + } + } + if ( (idItem.notNull()) && (idItem != gAgent.getWearableItem(pWearable->getType())) && + (gRlvHandler.getCompositeInfo(gAgent.getWearableItem(pWearable->getType()), NULL, &pFolder)) ) + { + RlvForceWear rlvWear; + rlvWear.forceFolder(pFolder, ACTION_DETACH, FLAG_DEFAULT); + rlvWear.done(); + } + } + #endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS + + wear_inventory_category_on_avatar_loop(pWearable, pParam); +} +*/ + +// ============================================================================ +// RlvBehaviourNotifyObserver +// + +// Checked: 2010-03-03 (RLVa-1.2.0a) | Added: RLVa-1.2.0a +RlvBehaviourNotifyHandler::RlvBehaviourNotifyHandler() +{ + // NOTE: the reason we use rlv_command_signal_t instead of the better-suited rlv_behaviour_signal_t is because + // RLV will notify scripts about "invalid" commands so we need to as well + m_ConnCommand = gRlvHandler.setCommandCallback(boost::bind(&RlvBehaviourNotifyHandler::onCommand, this, _1, _2, _3)); +} + +// Checked: 2010-03-03 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a +void RlvBehaviourNotifyHandler::onCommand(const RlvCommand& rlvCmd, ERlvCmdRet eRet, bool fInternal) +{ + if (fInternal) + return; + + switch (rlvCmd.getParamType()) + { + case RLV_TYPE_ADD: + case RLV_TYPE_REMOVE: + sendNotification(rlvCmd.asString(), "=" + rlvCmd.getParam()); + break; + case RLV_TYPE_CLEAR: + sendNotification(rlvCmd.asString()); + break; + default: + break; + } +} + +// Checked: 2011-03-31 (RLVa-1.3.0f) | Modify: RLVa-1.3.0f +void RlvBehaviourNotifyHandler::sendNotification(const std::string& strText, const std::string& strSuffix) +{ + if (instanceExists()) + { + RlvBehaviourNotifyHandler* pThis = getInstance(); + + // NOTE: notifications have two parts (which are concatenated without token) where only the first part is subject to the filter + for (std::multimap<LLUUID, notifyData>::const_iterator itNotify = pThis->m_Notifications.begin(); + itNotify != pThis->m_Notifications.end(); ++itNotify) + { + if ( (itNotify->second.strFilter.empty()) || (boost::icontains(strText, itNotify->second.strFilter)) ) + RlvUtil::sendChatReply(itNotify->second.nChannel, "/" + strText + strSuffix); + } + } +} + +// Checked: 2011-03-31 (RLVa-1.3.0f) | Added: RLVa-1.3.0f +void RlvBehaviourNotifyHandler::onWear(LLWearableType::EType eType, bool fAllowed) +{ + sendNotification(llformat("worn %s %s", (fAllowed) ? "legally" : "illegally", LLWearableType::getTypeName(eType).c_str())); +} + +// Checked: 2011-03-31 (RLVa-1.3.0f) | Added: RLVa-1.3.0f +void RlvBehaviourNotifyHandler::onTakeOff(LLWearableType::EType eType, bool fAllowed) +{ + sendNotification(llformat("unworn %s %s", (fAllowed) ? "legally" : "illegally", LLWearableType::getTypeName(eType).c_str())); +} + +// Checked: 2011-03-31 (RLVa-1.3.0f) | Added: RLVa-1.3.0f +void RlvBehaviourNotifyHandler::onAttach(const LLViewerJointAttachment* pAttachPt, bool fAllowed) +{ + sendNotification(llformat("attached %s %s", (fAllowed) ? "legally" : "illegally", pAttachPt->getName().c_str())); +} + +// Checked: 2011-03-31 (RLVa-1.3.0f) | Added: RLVa-1.3.0f +void RlvBehaviourNotifyHandler::onDetach(const LLViewerJointAttachment* pAttachPt, bool fAllowed) +{ + sendNotification(llformat("detached %s %s", (fAllowed) ? "legally" : "illegally", pAttachPt->getName().c_str())); +} + +// Checked: 2011-03-31 (RLVa-1.3.0f) | Added: RLVa-1.3.0f +void RlvBehaviourNotifyHandler::onReattach(const LLViewerJointAttachment* pAttachPt, bool fAllowed) +{ + sendNotification(llformat("reattached %s %s", (fAllowed) ? "legally" : "illegally", pAttachPt->getName().c_str())); +} + +// ========================================================================= +// Various helper classes/timers/functors +// + +// Checked: 2010-03-13 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a +BOOL RlvGCTimer::tick() +{ + bool fContinue = gRlvHandler.onGC(); + if (!fContinue) + gRlvHandler.m_pGCTimer = NULL; + return !fContinue; +} + +// ============================================================================ +// Various helper functions +// + +// ============================================================================ +// Attachment group helper functions +// + +// Has to match the order of ERlvAttachGroupType +const std::string cstrAttachGroups[RLV_ATTACHGROUP_COUNT] = { "head", "torso", "arms", "legs", "hud" }; + +// Checked: 2009-10-19 (RLVa-1.1.0e) | Added: RLVa-1.1.0e +ERlvAttachGroupType rlvAttachGroupFromIndex(S32 idxGroup) +{ + switch (idxGroup) + { + case 0: // Right Hand + case 1: // Right Arm + case 3: // Left Arm + case 4: // Left Hand + return RLV_ATTACHGROUP_ARMS; + case 2: // Head + return RLV_ATTACHGROUP_HEAD; + case 5: // Left Leg + case 7: // Right Leg + return RLV_ATTACHGROUP_LEGS; + case 6: // Torso + return RLV_ATTACHGROUP_TORSO; + case 8: // HUD + return RLV_ATTACHGROUP_HUD; + default: + return RLV_ATTACHGROUP_INVALID; + } +} + +// Checked: 2009-10-19 (RLVa-1.1.0e) | Added: RLVa-1.1.0e +ERlvAttachGroupType rlvAttachGroupFromString(const std::string& strGroup) +{ + for (int idx = 0; idx < RLV_ATTACHGROUP_COUNT; idx++) + if (cstrAttachGroups[idx] == strGroup) + return (ERlvAttachGroupType)idx; + return RLV_ATTACHGROUP_INVALID; +} + +// ========================================================================= +// String helper functions +// + +// Checked: 2009-07-29 (RLVa-1.0.1b) | Added: RLVa-1.0.1b +std::string rlvGetFirstParenthesisedText(const std::string& strText, std::string::size_type* pidxMatch /*=NULL*/) +{ + if (pidxMatch) + *pidxMatch = std::string::npos; // Assume we won't find anything + + std::string::size_type idxIt, idxStart; int cntLevel = 1; + if ((idxStart = strText.find_first_of('(')) == std::string::npos) + return std::string(); + + const char* pstrText = strText.c_str(); idxIt = idxStart; + while ( (cntLevel > 0) && (++idxIt < strText.length()) ) + { + if ('(' == pstrText[idxIt]) + cntLevel++; + else if (')' == pstrText[idxIt]) + cntLevel--; + } + + if (idxIt < strText.length()) + { + if (pidxMatch) + *pidxMatch = idxStart; // Return the character index of the starting '(' + return strText.substr(idxStart + 1, idxIt - idxStart - 1); + } + return std::string(); +} + +// Checked: 2009-07-29 (RLVa-1.0.1b) | Added: RLVa-1.0.1b +std::string rlvGetLastParenthesisedText(const std::string& strText, std::string::size_type* pidxStart /*=NULL*/) +{ + if (pidxStart) + *pidxStart = std::string::npos; // Assume we won't find anything + + // Extracts the last - matched - parenthesised text from the input string + std::string::size_type idxIt, idxEnd; int cntLevel = 1; + if ((idxEnd = strText.find_last_of(')')) == std::string::npos) + return std::string(); + + const char* pstrText = strText.c_str(); idxIt = idxEnd; + while ( (cntLevel > 0) && (--idxIt >= 0) && (idxIt < strText.length()) ) + { + if (')' == pstrText[idxIt]) + cntLevel++; + else if ('(' == pstrText[idxIt]) + cntLevel--; + } + + if ( (idxIt >= 0) && (idxIt < strText.length()) ) // NOTE: allow for std::string::size_type to be signed or unsigned + { + if (pidxStart) + *pidxStart = idxIt; // Return the character index of the starting '(' + return strText.substr(idxIt + 1, idxEnd - idxIt - 1); + } + return std::string(); +} + +// ========================================================================= diff --git a/indra/newview/rlvhelper.h b/indra/newview/rlvhelper.h new file mode 100644 index 0000000000000000000000000000000000000000..6f9dc3c722f2f8dce59fbc178d580b17df6dee60 --- /dev/null +++ b/indra/newview/rlvhelper.h @@ -0,0 +1,825 @@ +/** + * + * Copyright (c) 2009-2016, Kitty Barnett + * + * The source code in this file is provided to you under the terms of the + * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt + * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.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. + * + */ + +#ifndef RLV_HELPER_H +#define RLV_HELPER_H + +#include "lleventtimer.h" +#include "llinventorymodel.h" +#include "llviewerinventory.h" +#include "llwearabletype.h" + +#include "rlvdefines.h" +#include "rlvcommon.h" + +// ============================================================================ +// Forward declarations +// + +class RlvBehaviourModifier; + +// ============================================================================ +// RlvBehaviourInfo class - Generic behaviour descriptor (used by restrictions, reply and force commands) +// + +class RlvBehaviourInfo +{ +public: + enum EBehaviourFlags + { + // General behaviour flags + BHVR_STRICT = 0x0001, // Behaviour has a "_sec" version + BHVR_SYNONYM = 0x0002, // Behaviour is a synonym of another + BHVR_EXTENDED = 0x0004, // Behaviour is part of the RLVa extended command set + BHVR_EXPERIMENTAL = 0x0008, // Behaviour is part of the RLVa experimental command set + BHVR_BLOCKED = 0x0010, // Behaviour is blocked + BHVR_DEPRECATED = 0x0020, // Behaviour is deprecated + BHVR_GENERAL_MASK = 0x0FFF, + + // Force-wear specific flags + FORCEWEAR_WEAR_REPLACE = 0x0001 << 16, + FORCEWEAR_WEAR_ADD = 0x0002 << 16, + FORCEWEAR_WEAR_REMOVE = 0x0004 << 16, + FORCEWEAR_NODE = 0x0010 << 16, + FORCEWEAR_SUBTREE = 0x0020 << 16, + FORCEWEAR_CONTEXT_NONE = 0x0100 << 16, + FORCEWEAR_CONTEXT_OBJECT = 0x0200 << 16, + FORCEWEAR_MASK = 0xFFFF << 16 + }; + + RlvBehaviourInfo(std::string strBhvr, ERlvBehaviour eBhvr, U32 maskParamType, U32 nBhvrFlags = 0) + : m_strBhvr(strBhvr), m_eBhvr(eBhvr), m_maskParamType(maskParamType), m_nBhvrFlags(nBhvrFlags) {} + virtual ~RlvBehaviourInfo() {} + + const std::string& getBehaviour() const { return m_strBhvr; } + ERlvBehaviour getBehaviourType() const { return m_eBhvr; } + U32 getBehaviourFlags() const { return m_nBhvrFlags; } + U32 getParamTypeMask() const { return m_maskParamType; } + bool hasStrict() const { return m_nBhvrFlags & BHVR_STRICT; } + bool isBlocked() const { return m_nBhvrFlags & BHVR_BLOCKED; } + bool isExperimental() const { return m_nBhvrFlags & BHVR_EXPERIMENTAL; } + bool isExtended() const { return m_nBhvrFlags & BHVR_EXTENDED; } + bool isSynonym() const { return m_nBhvrFlags & BHVR_SYNONYM; } + void toggleBehaviourFlag(EBehaviourFlags eBhvrFlag, bool fEnable); + + virtual ERlvCmdRet processCommand(const RlvCommand& rlvCmd) const { return RLV_RET_NO_PROCESSOR; } + +protected: + std::string m_strBhvr; + ERlvBehaviour m_eBhvr; + U32 m_nBhvrFlags; + U32 m_maskParamType; +}; + +// ============================================================================ +// RlvBehaviourDictionary and related classes +// + +class RlvBehaviourDictionary : public LLSingleton<RlvBehaviourDictionary> +{ + friend class LLSingleton<RlvBehaviourDictionary>; + friend class RlvFloaterBehaviours; +protected: + RlvBehaviourDictionary(); + ~RlvBehaviourDictionary(); +public: + void addEntry(const RlvBehaviourInfo* pEntry); + void addModifier(ERlvBehaviour eBhvr, ERlvBehaviourModifier eModifier, RlvBehaviourModifier* pModifierEntry); + + /* + * General helper functions + */ +public: + ERlvBehaviour getBehaviourFromString(const std::string& strBhvr, ERlvParamType eParamType, bool* pfStrict = NULL) const; + const RlvBehaviourInfo* getBehaviourInfo(const std::string& strBhvr, ERlvParamType eParamType, bool* pfStrict = NULL) const; + bool getCommands(const std::string& strMatch, ERlvParamType eParamType, std::list<std::string>& cmdList) const; + bool getHasStrict(ERlvBehaviour eBhvr) const; + RlvBehaviourModifier* getModifier(ERlvBehaviourModifier eBhvrMod) const { return (eBhvrMod < RLV_MODIFIER_COUNT) ? m_BehaviourModifiers[eBhvrMod] : nullptr; } + RlvBehaviourModifier* getModifierFromBehaviour(ERlvBehaviour eBhvr) const; + void toggleBehaviourFlag(const std::string& strBhvr, ERlvParamType eParamType, RlvBehaviourInfo::EBehaviourFlags eBvhrFlag, bool fEnable); + + /* + * Member variables + */ +protected: + typedef std::list<const RlvBehaviourInfo*> rlv_bhvrinfo_list_t; + typedef std::map<std::pair<std::string, ERlvParamType>, const RlvBehaviourInfo*> rlv_string2info_map_t; + typedef std::multimap<ERlvBehaviour, const RlvBehaviourInfo*> rlv_bhvr2info_map_t; + typedef std::map<ERlvBehaviour, ERlvBehaviourModifier> rlv_bhvr2mod_map_t; + + rlv_bhvrinfo_list_t m_BhvrInfoList; + rlv_string2info_map_t m_String2InfoMap; + rlv_bhvr2info_map_t m_Bhvr2InfoMap; + rlv_bhvr2mod_map_t m_Bhvr2ModifierMap; + RlvBehaviourModifier* m_BehaviourModifiers[RLV_MODIFIER_COUNT]; +}; + +// ============================================================================ +// RlvCommandHandler and related classes +// + +typedef ERlvCmdRet(RlvBhvrHandlerFunc)(const RlvCommand&, bool&); +typedef void(RlvBhvrToggleHandlerFunc)(ERlvBehaviour, bool); +typedef ERlvCmdRet(RlvForceHandlerFunc)(const RlvCommand&); +typedef ERlvCmdRet(RlvReplyHandlerFunc)(const RlvCommand&, std::string&); + +// +// RlvCommandHandlerBaseImpl - Base implementation for each command type (the old process(AddRem|Force|Reply)Command functions) +// +template<ERlvParamType paramType> struct RlvCommandHandlerBaseImpl; +template<> struct RlvCommandHandlerBaseImpl<RLV_TYPE_ADDREM> { static ERlvCmdRet processCommand(const RlvCommand&, RlvBhvrHandlerFunc*, RlvBhvrToggleHandlerFunc* = nullptr); }; +template<> struct RlvCommandHandlerBaseImpl<RLV_TYPE_FORCE> { static ERlvCmdRet processCommand(const RlvCommand&, RlvForceHandlerFunc*); }; +template<> struct RlvCommandHandlerBaseImpl<RLV_TYPE_REPLY> { static ERlvCmdRet processCommand(const RlvCommand&, RlvReplyHandlerFunc*); +}; + +// +// RlvCommandHandler - The actual command handler (Note that a handler is more general than a processor; a handler can - for instance - be used by multiple processors) +// +#if LL_WINDOWS + #define RLV_TEMPL_FIX(x) template<x> +#else + #define RLV_TEMPL_FIX(x) template<typename Placeholder = int> +#endif // LL_WINDOWS + +template <ERlvParamType templParamType, ERlvBehaviour templBhvr> +struct RlvCommandHandler +{ + RLV_TEMPL_FIX(typename = typename std::enable_if<templParamType == RLV_TYPE_ADDREM>::type) static ERlvCmdRet onCommand(const RlvCommand&, bool&); + RLV_TEMPL_FIX(typename = typename std::enable_if<templParamType == RLV_TYPE_ADDREM>::type) static void onCommandToggle(ERlvBehaviour, bool); + RLV_TEMPL_FIX(typename = typename std::enable_if<templParamType == RLV_TYPE_FORCE>::type) static ERlvCmdRet onCommand(const RlvCommand&); + RLV_TEMPL_FIX(typename = typename std::enable_if<templParamType == RLV_TYPE_REPLY>::type) static ERlvCmdRet onCommand(const RlvCommand&, std::string&); +}; + +// Aliases to improve readability in definitions +template<ERlvBehaviour templBhvr> using RlvBehaviourHandler = RlvCommandHandler<RLV_TYPE_ADDREM, templBhvr>; +template<ERlvBehaviour templBhvr> using RlvBehaviourToggleHandler = RlvBehaviourHandler<templBhvr>; +template<ERlvBehaviour templBhvr> using RlvForceHandler = RlvCommandHandler<RLV_TYPE_FORCE, templBhvr>; +template<ERlvBehaviour templBhvr> using RlvReplyHandler = RlvCommandHandler<RLV_TYPE_REPLY, templBhvr>; + +// List of shared handlers +typedef RlvBehaviourToggleHandler<RLV_BHVR_SETCAM_EYEOFFSET> RlvBehaviourCamEyeFocusOffsetHandler; // Shared between @setcam_eyeoffset and @setcam_focusoffset +typedef RlvBehaviourHandler<RLV_BHVR_REMATTACH> RlvBehaviourAddRemAttachHandler; // Shared between @addattach and @remattach +typedef RlvBehaviourHandler<RLV_BHVR_SENDCHANNEL> RlvBehaviourSendChannelHandler; // Shared between @sendchannel and @sendchannel_except +typedef RlvBehaviourHandler<RLV_BHVR_SENDIM> RlvBehaviourRecvSendStartIMHandler; // Shared between @recvim, @sendim and @startim +typedef RlvBehaviourHandler<RLV_BHVR_SETCAM_FOVMIN> RlvBehaviourSetCamFovHandler; // Shared between @setcam_fovmin and @setcam_fovmax +typedef RlvBehaviourToggleHandler<RLV_BHVR_SHOWSELF> RlvBehaviourShowSelfToggleHandler; // Shared between @showself and @showselfhead +typedef RlvBehaviourHandler<RLV_BHVR_CAMZOOMMIN> RlvBehaviourCamZoomMinMaxHandler; // Shared between @camzoommin and @camzoommax (deprecated) +typedef RlvReplyHandler<RLV_BHVR_GETCAM_AVDISTMIN> RlvReplyCamMinMaxModifierHandler; // Shared between @getcam_avdistmin and @getcam_avdistmax +typedef RlvForceHandler<RLV_BHVR_REMATTACH> RlvForceRemAttachHandler; // Shared between @remattach and @detach +typedef RlvForceHandler<RLV_BHVR_SETCAM_EYEOFFSET> RlvForceCamEyeFocusOffsetHandler; // Shared between @setcam_eyeoffset and @setcam_focusoffset + +// +// RlvCommandProcessor - Templated glue class that brings RlvBehaviourInfo, RlvCommandHandlerBaseImpl and RlvCommandHandler together +// +template <ERlvParamType templParamType, ERlvBehaviour templBhvr, typename handlerImpl = RlvCommandHandler<templParamType, templBhvr>, typename baseImpl = RlvCommandHandlerBaseImpl<templParamType>> +class RlvCommandProcessor : public RlvBehaviourInfo +{ +public: + // Default constructor used by behaviour specializations + RLV_TEMPL_FIX(typename = typename std::enable_if<templBhvr != RLV_BHVR_UNKNOWN>::type) + RlvCommandProcessor(const std::string& strBhvr, U32 nBhvrFlags = 0) : RlvBehaviourInfo(strBhvr, templBhvr, templParamType, nBhvrFlags) {} + + // Constructor used when we don't want to specialize on behaviour (see RlvBehaviourGenericProcessor) + RLV_TEMPL_FIX(typename = typename std::enable_if<templBhvr == RLV_BHVR_UNKNOWN>::type) + RlvCommandProcessor(const std::string& strBhvr, ERlvBehaviour eBhvr, U32 nBhvrFlags = 0) : RlvBehaviourInfo(strBhvr, eBhvr, templParamType, nBhvrFlags) {} + + ERlvCmdRet processCommand(const RlvCommand& rlvCmd) const override { return baseImpl::processCommand(rlvCmd, &handlerImpl::onCommand); } +}; + +// Aliases to improve readability in definitions +template<ERlvBehaviour templBhvr, typename handlerImpl = RlvCommandHandler<RLV_TYPE_ADDREM, templBhvr>> using RlvBehaviourProcessor = RlvCommandProcessor<RLV_TYPE_ADDREM, templBhvr, handlerImpl>; +template<ERlvBehaviour templBhvr, typename handlerImpl = RlvCommandHandler<RLV_TYPE_FORCE, templBhvr>> using RlvForceProcessor = RlvCommandProcessor<RLV_TYPE_FORCE, templBhvr, handlerImpl>; +template<ERlvBehaviour templBhvr, typename handlerImpl = RlvCommandHandler<RLV_TYPE_REPLY, templBhvr>> using RlvReplyProcessor = RlvCommandProcessor<RLV_TYPE_REPLY, templBhvr, handlerImpl>; + +// Provides pre-defined generic implementations of basic behaviours (template voodoo - see original commit for something that still made sense) +template<ERlvBehaviourOptionType templOptionType> struct RlvBehaviourGenericHandler { static ERlvCmdRet onCommand(const RlvCommand& rlvCmd, bool& fRefCount); }; +template<ERlvBehaviourOptionType templOptionType> using RlvBehaviourGenericProcessor = RlvBehaviourProcessor<RLV_BHVR_UNKNOWN, RlvBehaviourGenericHandler<templOptionType>>; + +// ============================================================================ +// RlvBehaviourProcessor and related classes - Handles add/rem comamnds aka "restrictions) +// + +template <ERlvBehaviour eBhvr, typename handlerImpl = RlvBehaviourHandler<eBhvr>, typename toggleHandlerImpl = RlvBehaviourToggleHandler<eBhvr>> +class RlvBehaviourToggleProcessor : public RlvBehaviourInfo +{ +public: + RlvBehaviourToggleProcessor(const std::string& strBhvr, U32 nBhvrFlags = 0) : RlvBehaviourInfo(strBhvr, eBhvr, RLV_TYPE_ADDREM, nBhvrFlags) {} + ERlvCmdRet processCommand(const RlvCommand& rlvCmd) const override { return RlvCommandHandlerBaseImpl<RLV_TYPE_ADDREM>::processCommand(rlvCmd, &handlerImpl::onCommand, &toggleHandlerImpl::onCommandToggle); } +}; +template <ERlvBehaviour eBhvr, ERlvBehaviourOptionType optionType, typename toggleHandlerImpl = RlvBehaviourToggleHandler<eBhvr>> using RlvBehaviourGenericToggleProcessor = RlvBehaviourToggleProcessor<eBhvr, RlvBehaviourGenericHandler<optionType>, toggleHandlerImpl>; + +// ============================================================================ +// RlvBehaviourModifier - stores behaviour modifiers in an - optionally - sorted list and returns the first element (or default value if there are no modifiers) +// + +typedef std::pair<RlvBehaviourModifierValue, LLUUID> RlvBehaviourModifierValueTuple; + +struct RlvBehaviourModifier_Comp +{ + virtual ~RlvBehaviourModifier_Comp() {} + virtual bool operator()(const RlvBehaviourModifierValueTuple& lhs, const RlvBehaviourModifierValueTuple& rhs) + { + // Values that match the primary object take precedence (otherwise maintain relative ordering) + if ( (rhs.second == m_idPrimaryObject) && (lhs.second != m_idPrimaryObject) ) + return false; + return true; + } + + LLUUID m_idPrimaryObject; +}; +struct RlvBehaviourModifier_CompMin : public RlvBehaviourModifier_Comp +{ + bool operator()(const RlvBehaviourModifierValueTuple& lhs, const RlvBehaviourModifierValueTuple& rhs) override + { + if ( (m_idPrimaryObject.isNull()) || ((lhs.second == m_idPrimaryObject) && (rhs.second == m_idPrimaryObject)) ) + return lhs.first < rhs.first; + return RlvBehaviourModifier_Comp::operator()(lhs, rhs); + } +}; +struct RlvBehaviourModifier_CompMax : public RlvBehaviourModifier_Comp +{ + bool operator()(const RlvBehaviourModifierValueTuple& lhs, const RlvBehaviourModifierValueTuple& rhs) override + { + if ( (m_idPrimaryObject.isNull()) || ((lhs.second == m_idPrimaryObject) && (rhs.second == m_idPrimaryObject)) ) + return rhs.first < lhs.first; + return RlvBehaviourModifier_Comp::operator()(lhs, rhs); + } +}; + +class RlvBehaviourModifier +{ +public: + RlvBehaviourModifier(const std::string strName, const RlvBehaviourModifierValue& defaultValue, bool fAddDefaultOnEmpty, RlvBehaviourModifier_Comp* pValueComparator = nullptr); + virtual ~RlvBehaviourModifier(); + + /* + * Member functions + */ +protected: + virtual void onValueChange() const {} +public: + bool addValue(const RlvBehaviourModifierValue& modValue, const LLUUID& idObject); + bool convertOptionValue(const std::string& optionValue, RlvBehaviourModifierValue& modValue) const; + bool getAddDefault() const { return m_fAddDefaultOnEmpty; } + const RlvBehaviourModifierValue& getDefaultValue() const { return m_DefaultValue; } + const LLUUID& getPrimaryObject() const; + const std::string& getName() const { return m_strName; } + const RlvBehaviourModifierValue& getValue() const { return (hasValue()) ? m_Values.front().first : m_DefaultValue; } + template<typename T> const T& getValue() const { return boost::get<T>(getValue()); } + bool hasValue() const; + void removeValue(const RlvBehaviourModifierValue& modValue, const LLUUID& idObject); + void setPrimaryObject(const LLUUID& idPrimaryObject); + + typedef boost::signals2::signal<void(const RlvBehaviourModifierValue& newValue)> change_signal_t; + change_signal_t& getSignal() { return m_ChangeSignal; } + + /* + * Member variables + */ +protected: + std::string m_strName; + RlvBehaviourModifierValue m_DefaultValue; + bool m_fAddDefaultOnEmpty; + std::list<RlvBehaviourModifierValueTuple> m_Values; + change_signal_t m_ChangeSignal; + RlvBehaviourModifier_Comp* m_pValueComparator; +}; + +template<ERlvBehaviourModifier eBhvrMod> +class RlvBehaviourModifierHandler : public RlvBehaviourModifier +{ +public: + //using RlvBehaviourModifier::RlvBehaviourModifier; // Needs VS2015 and up + RlvBehaviourModifierHandler(const std::string& strName, const RlvBehaviourModifierValue& defaultValue, bool fAddDefaultOnEmpty, RlvBehaviourModifier_Comp* pValueComparator) + : RlvBehaviourModifier(strName, defaultValue, fAddDefaultOnEmpty, pValueComparator) {} +protected: + void onValueChange() const override; +}; + +// Inspired by LLControlCache<T> +template<typename T> +class RlvBehaviourModifierCache : public LLRefCount, public LLInstanceTracker<RlvBehaviourModifierCache<T>, ERlvBehaviourModifier> +{ +public: + RlvBehaviourModifierCache(ERlvBehaviourModifier eModifier) + : LLInstanceTracker<RlvBehaviourModifierCache<T>, ERlvBehaviourModifier>(eModifier) + { + RlvBehaviourModifier* pBhvrModifier = (eModifier < RLV_MODIFIER_COUNT) ? RlvBehaviourDictionary::instance().getModifier(eModifier) : nullptr; + if (pBhvrModifier) + { + mConnection = pBhvrModifier->getSignal().connect(boost::bind(&RlvBehaviourModifierCache<T>::handleValueChange, this, _1)); + mCachedValue = pBhvrModifier->getValue<T>(); + } + else + { + mCachedValue = {}; + } + } + ~RlvBehaviourModifierCache() {} + + /* + * Member functions + */ +public: + const T& getValue() const { return mCachedValue; } +protected: + void handleValueChange(const RlvBehaviourModifierValue& newValue) { mCachedValue = boost::get<T>(newValue); } + + /* + * Member variables + */ +protected: + T mCachedValue; + boost::signals2::scoped_connection mConnection; +}; + +// Inspired by LLCachedControl<T> +template <typename T> +class RlvCachedBehaviourModifier +{ +public: + RlvCachedBehaviourModifier(ERlvBehaviourModifier eModifier) + { + if ((mCachedModifierPtr = RlvBehaviourModifierCache<T>::getInstance(eModifier)) == nullptr) + mCachedModifierPtr = new RlvBehaviourModifierCache<T>(eModifier); + } + + /* + * Operators + */ +public: + operator const T&() const { return mCachedModifierPtr->getValue(); } + const T& operator()() { return mCachedModifierPtr->getValue(); } + + /* + * Member variables + */ +protected: + LLPointer<RlvBehaviourModifierCache<T>> mCachedModifierPtr; +}; + +// ============================================================================ +// RlvCommand +// + +class RlvCommand +{ +public: + explicit RlvCommand(const LLUUID& idObj, const std::string& strCommand); + RlvCommand(const RlvCommand& rlvCmd, ERlvParamType eParamType = RLV_TYPE_UNKNOWN); + + /* + * Member functions + */ +public: + std::string asString() const; + const std::string& getBehaviour() const { return m_strBehaviour; } + ERlvBehaviour getBehaviourType() const { return (m_pBhvrInfo) ? m_pBhvrInfo->getBehaviourType() : RLV_BHVR_UNKNOWN; } + U32 getBehaviourFlags() const{ return (m_pBhvrInfo) ? m_pBhvrInfo->getBehaviourFlags() : 0; } + const LLUUID& getObjectID() const { return m_idObj; } + const std::string& getOption() const { return m_strOption; } + const std::string& getParam() const { return m_strParam; } + ERlvParamType getParamType() const { return m_eParamType; } + bool hasOption() const { return !m_strOption.empty(); } + bool isBlocked() const { return (m_pBhvrInfo) ? m_pBhvrInfo->isBlocked() : false; } + bool isRefCounted() const { return m_fRefCounted; } + bool isStrict() const { return m_fStrict; } + bool isValid() const { return m_fValid; } + ERlvCmdRet processCommand() const { return (m_pBhvrInfo) ? m_pBhvrInfo->processCommand(*this) : RLV_RET_NO_PROCESSOR; } + +protected: + static bool parseCommand(const std::string& strCommand, std::string& strBehaviour, std::string& strOption, std::string& strParam); + bool markRefCounted() const { return m_fRefCounted = true; } + + /* + * Operators + */ +public: + bool operator ==(const RlvCommand&) const; + + /* + * Member variables + */ +protected: + bool m_fValid; + LLUUID m_idObj; + std::string m_strBehaviour; + const RlvBehaviourInfo* m_pBhvrInfo; + ERlvParamType m_eParamType; + bool m_fStrict; + std::string m_strOption; + std::string m_strParam; + mutable bool m_fRefCounted; + + friend class RlvHandler; + friend class RlvObject; + template<ERlvParamType> friend struct RlvCommandHandlerBaseImpl; +}; + +// ============================================================================ +// Command option parsing utility classes +// + +class RlvCommandOptionHelper +{ +public: + // NOTE: this function is destructive (reference value may still change on parsing failure) + template<typename T> static bool parseOption(const std::string& strOption, T& valueOption); + template<typename T> static T parseOption(const std::string& strOption) + { + T value; + parseOption<T>(strOption, value); + return value; + } + static bool parseStringList(const std::string& strOption, std::vector<std::string>& optionList, const std::string& strSeparator = std::string(RLV_OPTION_SEPARATOR)); +}; + +struct RlvCommandOptionGeneric +{ + bool isAttachmentPoint() const { return (!isEmpty()) && (typeid(LLViewerJointAttachment*) == m_varOption.type()); } + bool isAttachmentPointGroup() const { return (!isEmpty()) && (typeid(ERlvAttachGroupType) == m_varOption.type()); } + bool isEmpty() const { return typeid(boost::blank) == m_varOption.type(); } + bool isNumber() const { return (!isEmpty()) && (typeid(float) == m_varOption.type()); } + bool isSharedFolder() const { return (!isEmpty()) && (typeid(LLViewerInventoryCategory*) == m_varOption.type()); } + bool isString() const { return (!isEmpty()) && (typeid(std::string) == m_varOption.type()); } + bool isUUID() const { return (!isEmpty()) && (typeid(LLUUID) == m_varOption.type()); } + bool isVector() const { return (!isEmpty()) && (typeid(LLVector3d) == m_varOption.type()); } + bool isWearableType() const { return (!isEmpty()) && (typeid(LLWearableType::EType) == m_varOption.type()); } + + LLViewerJointAttachment* getAttachmentPoint() const { return (isAttachmentPoint()) ? boost::get<LLViewerJointAttachment*>(m_varOption) : NULL; } + ERlvAttachGroupType getAttachmentPointGroup() const { return (isAttachmentPointGroup()) ? boost::get<ERlvAttachGroupType>(m_varOption) : RLV_ATTACHGROUP_INVALID; } + LLViewerInventoryCategory* getSharedFolder() const { return (isSharedFolder()) ? boost::get<LLViewerInventoryCategory*>(m_varOption) : NULL; } + float getNumber() const { return (isNumber()) ? boost::get<float>(m_varOption) : 0.0f; } + const std::string& getString() const { return (isString()) ? boost::get<std::string>(m_varOption) : LLStringUtil::null; } + const LLUUID& getUUID() const { return (isUUID()) ? boost::get<LLUUID>(m_varOption) : LLUUID::null; } + const LLVector3d& getVector() const { return (isVector()) ? boost::get<LLVector3d>(m_varOption) : LLVector3d::zero; } + LLWearableType::EType getWearableType() const { return (isWearableType()) ? boost::get<LLWearableType::EType>(m_varOption) : LLWearableType::WT_INVALID; } + + typedef boost::variant<boost::blank, LLViewerJointAttachment*, ERlvAttachGroupType, LLViewerInventoryCategory*, std::string, LLUUID, LLWearableType::EType, LLVector3d, float> rlv_option_generic_t; + void operator=(const rlv_option_generic_t& optionValue) { m_varOption = optionValue; } +protected: + rlv_option_generic_t m_varOption; +}; + +// ============================================================================ +// Command option parsing utility classes (these still need refactoring to fit the new methodology) +// + +struct RlvCommandOption +{ +protected: + RlvCommandOption() : m_fValid(false) {} +public: + virtual ~RlvCommandOption() {} + +public: + virtual bool isEmpty() const { return false; } + virtual bool isValid() const { return m_fValid; } +protected: + bool m_fValid; +}; + +struct RlvCommandOptionGetPath : public RlvCommandOption +{ + typedef boost::function<void(const uuid_vec_t&)> getpath_callback_t; + RlvCommandOptionGetPath(const RlvCommand& rlvCmd, getpath_callback_t cb = NULL); + + bool isCallback() const { return m_fCallback; } + /*virtual*/ bool isEmpty() const { return m_idItems.empty(); } + const uuid_vec_t& getItemIDs() const { return m_idItems; } + + // NOTE: Both functions are COF-based rather than items gathered from mAttachedObjects or gAgentWearables + static bool getItemIDs(const LLViewerJointAttachment* pAttachPt, uuid_vec_t& idItems); + static bool getItemIDs(LLWearableType::EType wtType, uuid_vec_t& idItems); + +protected: + bool m_fCallback; // TRUE if a callback is schedueled + uuid_vec_t m_idItems; +}; + +struct RlvCommandOptionAdjustHeight : public RlvCommandOption +{ + RlvCommandOptionAdjustHeight(const RlvCommand& rlvCmd); + + F32 m_nPelvisToFoot; + F32 m_nPelvisToFootDeltaMult; + F32 m_nPelvisToFootOffset; +}; + +// ============================================================================ +// RlvObject +// + +class RlvObject +{ +public: + RlvObject(const LLUUID& idObj); + + /* + * Member functions + */ +public: + bool addCommand(const RlvCommand& rlvCmd); + bool removeCommand(const RlvCommand& rlvCmd); + + std::string getStatusString(const std::string& strFilter, const std::string& strSeparator) const; + bool hasBehaviour(ERlvBehaviour eBehaviour, bool fStrictOnly) const; + bool hasBehaviour(ERlvBehaviour eBehaviour, const std::string& strOption, bool fStrictOnly) const; + + + /* + * Accessors + */ +public: + S32 getAttachPt() const { return m_idxAttachPt; } + const LLUUID& getObjectID() const { return m_idObj; } + const LLUUID& getRootID() const { return m_idRoot; } + bool hasLookup() const { return m_fLookup; } + const rlv_command_list_t* getCommandList() const { return &m_Commands; } + + /* + * Member variables + */ +protected: + S32 m_idxAttachPt; // The object's attachment point (or 0 if it's not an attachment) + LLUUID m_idObj; // The object's UUID + LLUUID m_idRoot; // The UUID of the object's root (may or may not be different from m_idObj) + bool m_fLookup; // TRUE if the object existed in gObjectList at one point in time + S16 m_nLookupMisses; // Count of unsuccessful lookups in gObjectList by the GC + rlv_command_list_t m_Commands; // List of behaviours held by this object (in the order they were received) + + friend class RlvHandler; +}; + +// ============================================================================ +// RlvForceWear +// + +class RlvForceWear : public LLSingleton<RlvForceWear> +{ +protected: + RlvForceWear() {} + +public: + // Folders + enum EWearAction { ACTION_WEAR_REPLACE, ACTION_WEAR_ADD, ACTION_REMOVE }; + enum EWearFlags { FLAG_NONE = 0x00, FLAG_MATCHALL = 0x01, FLAG_DEFAULT = FLAG_NONE }; + void forceFolder(const LLViewerInventoryCategory* pFolder, EWearAction eAction, EWearFlags eFlags); + + // Generic + static bool isWearAction(EWearAction eAction) { return (ACTION_WEAR_REPLACE == eAction) || (ACTION_WEAR_ADD == eAction); } + static bool isWearableItem(const LLInventoryItem* pItem); + static bool isWearingItem(const LLInventoryItem* pItem); + + // Nostrip + static bool isStrippable(const LLUUID& idItem) { return isStrippable(gInventory.getItem(idItem)); } + static bool isStrippable(const LLInventoryItem* pItem); + + // Attachments + static bool isForceDetachable(const LLViewerObject* pAttachObj, bool fCheckComposite = true, const LLUUID& idExcept = LLUUID::null); + static bool isForceDetachable(const LLViewerJointAttachment* pAttachPt, bool fCheckComposite = true, const LLUUID& idExcept = LLUUID::null); + void forceDetach(const LLViewerObject* pAttachObj); + void forceDetach(const LLViewerJointAttachment* ptAttachPt); + + // Wearables + static bool isForceRemovable(const LLViewerWearable* pWearable, bool fCheckComposite = true, const LLUUID& idExcept = LLUUID::null); + static bool isForceRemovable(LLWearableType::EType wtType, bool fCheckComposite = true, const LLUUID& idExcept = LLUUID::null); + void forceRemove(const LLViewerWearable* pWearable); + void forceRemove(LLWearableType::EType wtType); + +public: + void done(); +protected: + void addAttachment(const LLViewerInventoryItem* pItem, EWearAction eAction); + void remAttachment(const LLViewerObject* pAttachObj); + void addWearable(const LLViewerInventoryItem* pItem, EWearAction eAction); + void remWearable(const LLViewerWearable* pWearable); + + // Convenience (prevents long lines that run off the screen elsewhere) + bool isAddAttachment(const LLViewerInventoryItem* pItem) const + { + bool fFound = false; + for (addattachments_map_t::const_iterator itAddAttachments = m_addAttachments.begin(); + (!fFound) && (itAddAttachments != m_addAttachments.end()); ++itAddAttachments) + { + const LLInventoryModel::item_array_t& wearItems = itAddAttachments->second; + fFound = (std::find_if(wearItems.begin(), wearItems.end(), RlvPredIsEqualOrLinkedItem(pItem)) != wearItems.end()); + } + return fFound; + } + bool isRemAttachment(const LLViewerObject* pAttachObj) const + { + return std::find(m_remAttachments.begin(), m_remAttachments.end(), pAttachObj) != m_remAttachments.end(); + } + bool isAddWearable(const LLViewerInventoryItem* pItem) const + { + bool fFound = false; + for (addwearables_map_t::const_iterator itAddWearables = m_addWearables.begin(); + (!fFound) && (itAddWearables != m_addWearables.end()); ++itAddWearables) + { + const LLInventoryModel::item_array_t& wearItems = itAddWearables->second; + fFound = (std::find_if(wearItems.begin(), wearItems.end(), RlvPredIsEqualOrLinkedItem(pItem)) != wearItems.end()); + } + return fFound; + } + bool isRemWearable(const LLViewerWearable* pWearable) const + { + return std::find(m_remWearables.begin(), m_remWearables.end(), pWearable) != m_remWearables.end(); + } + + /* + * Pending attachments + */ +public: + static void updatePendingAttachments(); +protected: + void addPendingAttachment(const LLUUID& idItem, U8 idxPoint); + void remPendingAttachment(const LLUUID& idItem); + +protected: + typedef std::pair<LLWearableType::EType, LLInventoryModel::item_array_t> addwearable_pair_t; + typedef std::map<LLWearableType::EType, LLInventoryModel::item_array_t> addwearables_map_t; + addwearables_map_t m_addWearables; + typedef std::pair<S32, LLInventoryModel::item_array_t> addattachment_pair_t; + typedef std::map<S32, LLInventoryModel::item_array_t> addattachments_map_t; + addattachments_map_t m_addAttachments; + LLInventoryModel::item_array_t m_addGestures; + std::vector<LLViewerObject*> m_remAttachments; // This should match the definition of LLAgentWearables::llvo_vec_t + std::list<const LLViewerWearable*> m_remWearables; + LLInventoryModel::item_array_t m_remGestures; + + typedef std::map<LLUUID, U8> pendingattachments_map_t; + pendingattachments_map_t m_pendingAttachments; + +private: + friend class LLSingleton<RlvForceWear>; +}; + +// ============================================================================ +// RlvBehaviourNotifyObserver +// + +class RlvBehaviourNotifyHandler : public LLSingleton<RlvBehaviourNotifyHandler> +{ + friend class LLSingleton<RlvBehaviourNotifyHandler>; +protected: + RlvBehaviourNotifyHandler(); + virtual ~RlvBehaviourNotifyHandler() { if (m_ConnCommand.connected()) m_ConnCommand.disconnect(); } + +public: + void addNotify(const LLUUID& idObj, S32 nChannel, const std::string& strFilter) + { + m_Notifications.insert(std::pair<LLUUID, notifyData>(idObj, notifyData(nChannel, strFilter))); + } + void removeNotify(const LLUUID& idObj, S32 nChannel, const std::string& strFilter) + { + for (std::multimap<LLUUID, notifyData>::iterator itNotify = m_Notifications.lower_bound(idObj), + endNotify = m_Notifications.upper_bound(idObj); itNotify != endNotify; ++itNotify) + { + if ( (itNotify->second.nChannel == nChannel) && (itNotify->second.strFilter == strFilter) ) + { + m_Notifications.erase(itNotify); + break; + } + } + if (m_Notifications.empty()) + delete this; // Delete ourself if we have nothing to do + } + static void sendNotification(const std::string& strText, const std::string& strSuffix = LLStringUtil::null); + + /* + * Event handlers + */ +public: + static void onWear(LLWearableType::EType eType, bool fAllowed); + static void onTakeOff(LLWearableType::EType eType, bool fAllowed); + static void onAttach(const LLViewerJointAttachment* pAttachPt, bool fAllowed); + static void onDetach(const LLViewerJointAttachment* pAttachPt, bool fAllowed); + static void onReattach(const LLViewerJointAttachment* pAttachPt, bool fAllowed); +protected: + void onCommand(const RlvCommand& rlvCmd, ERlvCmdRet eRet, bool fInternal); + +protected: + struct notifyData + { + S32 nChannel; + std::string strFilter; + notifyData(S32 channel, const std::string& filter) : nChannel(channel), strFilter(filter) {} + }; + std::multimap<LLUUID, notifyData> m_Notifications; + boost::signals2::connection m_ConnCommand; +}; + +// ============================================================================ +// RlvException +// + +struct RlvException +{ +public: + LLUUID idObject; // UUID of the object that added the exception + ERlvBehaviour eBehaviour; // Behaviour the exception applies to + RlvExceptionOption varOption; // Exception data (type is dependent on eBehaviour) + + RlvException(const LLUUID& idObj, ERlvBehaviour eBhvr, const RlvExceptionOption& option) : idObject(idObj), eBehaviour(eBhvr), varOption(option) {} +private: + RlvException(); +}; + +// ============================================================================ +// Various helper classes/timers/functors +// + +class RlvGCTimer : public LLEventTimer +{ +public: + RlvGCTimer() : LLEventTimer(30.0) {} + virtual BOOL tick(); +}; + +// NOTE: Unused as of SL-3.7.2 +class RlvCallbackTimerOnce : public LLEventTimer +{ +public: + typedef boost::function<void ()> nullary_func_t; +public: + RlvCallbackTimerOnce(F32 nPeriod, nullary_func_t cb) : LLEventTimer(nPeriod), m_Callback(cb) {} + /*virtual*/ BOOL tick() + { + m_Callback(); + return TRUE; + } +protected: + nullary_func_t m_Callback; +}; + +// NOTE: Unused as of SL-3.7.2 +inline void rlvCallbackTimerOnce(F32 nPeriod, RlvCallbackTimerOnce::nullary_func_t cb) +{ + // Timer will automatically delete itself after the callback + new RlvCallbackTimerOnce(nPeriod, cb); +} + +// ============================================================================ +// Various helper functions +// + +ERlvAttachGroupType rlvAttachGroupFromIndex(S32 idxGroup); +ERlvAttachGroupType rlvAttachGroupFromString(const std::string& strGroup); + +std::string rlvGetFirstParenthesisedText(const std::string& strText, std::string::size_type* pidxMatch = NULL); +std::string rlvGetLastParenthesisedText(const std::string& strText, std::string::size_type* pidxStart = NULL); + +// ============================================================================ +// Inlined class member functions +// + +inline void RlvBehaviourInfo::toggleBehaviourFlag(EBehaviourFlags eBhvrFlag, bool fEnable) +{ + if (fEnable) + m_nBhvrFlags |= eBhvrFlag; + else + m_nBhvrFlags &= ~eBhvrFlag; +} + +// Checked: 2009-09-19 (RLVa-1.0.3d) +inline std::string RlvCommand::asString() const +{ + // NOTE: @clear=<param> should be represented as clear:<param> + return (m_eParamType != RLV_TYPE_CLEAR) + ? (!m_strOption.empty()) ? (std::string(getBehaviour())).append(":").append(m_strOption) : (std::string(getBehaviour())) + : (!m_strParam.empty()) ? (std::string(getBehaviour())).append(":").append(m_strParam) : (std::string(getBehaviour())); +} + +inline bool RlvCommand::operator ==(const RlvCommand& rhs) const +{ + // The specification notes that "@detach=n" is semantically identical to "@detach=add" (same for "y" and "rem" + return (getBehaviour() == rhs.getBehaviour()) && (m_strOption == rhs.m_strOption) && + ( (RLV_TYPE_UNKNOWN != m_eParamType) ? (m_eParamType == rhs.m_eParamType) : (m_strParam == rhs.m_strParam) ); +} + +// Checked: 2010-04-05 (RLVa-1.2.0d) | Modified: RLVa-1.2.0d +inline bool RlvForceWear::isWearableItem(const LLInventoryItem* pItem) +{ + LLAssetType::EType assetType = (pItem) ? pItem->getType() : LLAssetType::AT_NONE; + return + (LLAssetType::AT_BODYPART == assetType) || (LLAssetType::AT_CLOTHING == assetType) || + (LLAssetType::AT_OBJECT == assetType) || (LLAssetType::AT_GESTURE == assetType); +} + +// ============================================================================ + +#endif // RLV_HELPER_H diff --git a/indra/newview/rlvinventory.cpp b/indra/newview/rlvinventory.cpp new file mode 100644 index 0000000000000000000000000000000000000000..082cc6065b5d1eeeb2ed9b7a260bb0192915e838 --- /dev/null +++ b/indra/newview/rlvinventory.cpp @@ -0,0 +1,882 @@ +/** + * + * Copyright (c) 2009-2014, Kitty Barnett + * + * The source code in this file is provided to you under the terms of the + * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt + * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.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 "llagent.h" +#include "llappearancemgr.h" +#include "llstartup.h" +#include "llviewerfoldertype.h" +#include "llviewermessage.h" + +#include "rlvinventory.h" + +#include "boost/algorithm/string.hpp" + +// ============================================================================ +// Static variable initialization +// + +const std::string RlvInventory::cstrSharedRoot = RLV_ROOT_FOLDER; + +// ============================================================================ +// Helper classes +// + +// TODO-RLVa: [RLVa-1.2.1] This class really shouldn't be calling "fetchSharedLinks" directly so find a better way +class RlvSharedInventoryFetcher : public LLInventoryFetchDescendentsObserver +{ +public: + RlvSharedInventoryFetcher(const uuid_vec_t& idFolders): LLInventoryFetchDescendentsObserver(idFolders) {} + virtual ~RlvSharedInventoryFetcher() {} + + virtual void done() + { + RLV_INFOS << "Shared folders fetch completed" << LL_ENDL; + RlvInventory::instance().m_fFetchComplete = true; + RlvInventory::instance().fetchSharedLinks(); + + gInventory.removeObserver(this); + delete this; + } +}; + +// ============================================================================ +// RlvInventory member functions +// + +// Checked: 2011-03-28 (RLVa-1.3.0g) | Modified: RLVa-1.3.0g +RlvInventory::RlvInventory() + : m_fFetchStarted(false), m_fFetchComplete(false) +{ +} + +// Checked: 2011-03-28 (RLVa-1.3.0g) | Added: RLVa-1.3.0g +RlvInventory::~RlvInventory() +{ + if (gInventory.containsObserver(this)) + gInventory.removeObserver(this); +} + +// Checked: 2011-03-28 (RLVa-1.3.0g) | Added: RLVa-1.3.0g +void RlvInventory::changed(U32 mask) +{ + const LLInventoryModel::changed_items_t& idsChanged = gInventory.getChangedIDs(); + if (std::find(idsChanged.begin(), idsChanged.end(), m_idRlvRoot) != idsChanged.end()) + { + gInventory.removeObserver(this); + + LLUUID idRlvRootPrev = m_idRlvRoot; + m_idRlvRoot.setNull(); + + if (idRlvRootPrev != getSharedRootID()) + m_OnSharedRootIDChanged(); + } +} + +// Checked: 2010-02-28 (RLVa-1.2.0a) | Modified: RLVa-1.0.0h +void RlvInventory::fetchSharedInventory() +{ + // Sanity check - don't fetch if we're already fetching, or if we don't have a shared root + const LLViewerInventoryCategory* pRlvRoot = getSharedRoot(); + if ( (m_fFetchStarted) || (!pRlvRoot) ) + return; + + // Grab all the folders under the shared root + LLInventoryModel::cat_array_t folders; LLInventoryModel::item_array_t items; + gInventory.collectDescendents(pRlvRoot->getUUID(), folders, items, FALSE); + + // Add them to the "to fetch" list + uuid_vec_t idFolders; + idFolders.push_back(pRlvRoot->getUUID()); + for (S32 idxFolder = 0, cntFolder = folders.size(); idxFolder < cntFolder; idxFolder++) + idFolders.push_back(folders.at(idxFolder)->getUUID()); + + // Now fetch them all in one go + RlvSharedInventoryFetcher* pFetcher = new RlvSharedInventoryFetcher(idFolders); + + RLV_INFOS << "Starting fetch of " << idFolders.size() << " shared folders" << RLV_ENDL; + pFetcher->startFetch(); + m_fFetchStarted = true; + + if (pFetcher->isFinished()) + pFetcher->done(); + else + gInventory.addObserver(pFetcher); +} + +// Checked: 2010-02-28 (RLVa-1.2.0a) | Modified: RLVa-1.0.0h +void RlvInventory::fetchSharedLinks() +{ + // TOFIX-RLVa: [RLVa-1.2.1] Finish adding support for AT_LINK_FOLDER + const LLViewerInventoryCategory* pRlvRoot = getSharedRoot(); + if (!pRlvRoot) + return; + + // Grab all the inventory links under the shared root + LLInventoryModel::cat_array_t folders; LLInventoryModel::item_array_t items; RlvIsLinkType f; + gInventory.collectDescendentsIf(pRlvRoot->getUUID(), folders, items, FALSE, f, false); + + // Add them to the "to fetch" list based on link type + uuid_vec_t idFolders, idItems; + for (S32 idxItem = 0, cntItem = items.size(); idxItem < cntItem; idxItem++) + { + const LLViewerInventoryItem* pItem = items.at(idxItem); + switch (pItem->getActualType()) + { + case LLAssetType::AT_LINK: + idItems.push_back(pItem->getLinkedUUID()); + break; + case LLAssetType::AT_LINK_FOLDER: + idFolders.push_back(pItem->getLinkedUUID()); + break; + default: + break;; + } + } + + RLV_INFOS << "Starting link target fetch of " << idItems.size() << " items and " << idFolders.size() << " folders" << RLV_ENDL; + + // Fetch all the link item targets + LLInventoryFetchItemsObserver itemFetcher(idItems); + itemFetcher.startFetch(); + + // Fetch all the link folder targets + // TODO! +} + +// Checked: 2010-02-28 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a +void RlvInventory::fetchWornItems() +{ + uuid_vec_t idItems; + + // Fetch all currently worn clothing layers and body parts + for (int type = 0; type < LLWearableType::WT_COUNT; type++) + { + // RELEASE-RLVa: [SL-2.0.0] Needs rewriting once 'LLAgentWearables::MAX_WEARABLES_PER_TYPE > 1' + const LLUUID& idItem = gAgentWearables.getWearableItemID((LLWearableType::EType)type, 0); + if (idItem.notNull()) + idItems.push_back(idItem); + } + + // Fetch all currently worn attachments + if (isAgentAvatarValid()) + { + for (LLVOAvatar::attachment_map_t::const_iterator itAttachPt = gAgentAvatarp->mAttachmentPoints.begin(); + itAttachPt != gAgentAvatarp->mAttachmentPoints.end(); ++itAttachPt) + { + const LLViewerJointAttachment* pAttachPt = itAttachPt->second; + if (pAttachPt) + { + for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator itAttachObj = pAttachPt->mAttachedObjects.begin(); + itAttachObj != pAttachPt->mAttachedObjects.end(); ++itAttachObj) + { + const LLViewerObject* pAttachObj = (*itAttachObj); + if ( (pAttachObj) && (pAttachObj->getAttachmentItemID().notNull()) ) + idItems.push_back(pAttachObj->getAttachmentItemID()); + } + } + } + } + + LLInventoryFetchItemsObserver itemFetcher(idItems); + itemFetcher.startFetch(); +} + +// Checked: 2010-04-07 (RLVa-1.2.0a) | Modified: RLVa-1.0.0h +bool RlvInventory::findSharedFolders(const std::string& strCriteria, LLInventoryModel::cat_array_t& folders) const +{ + // Sanity check - can't do anything without a shared root + const LLViewerInventoryCategory* pRlvRoot = RlvInventory::instance().getSharedRoot(); + if (!pRlvRoot) + return false; + + folders.clear(); + LLInventoryModel::item_array_t items; + RlvCriteriaCategoryCollector f(strCriteria); + gInventory.collectDescendentsIf(pRlvRoot->getUUID(), folders, items, FALSE, f); + + return (folders.size() != 0); +} + +// Checked: 2010-08-30 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c +bool RlvInventory::getPath(const uuid_vec_t& idItems, LLInventoryModel::cat_array_t& folders) const +{ + // Sanity check - can't do anything without a shared root + const LLViewerInventoryCategory* pRlvRoot = RlvInventory::instance().getSharedRoot(); + if (!pRlvRoot) + return false; + + folders.clear(); + for (uuid_vec_t::const_iterator itItem = idItems.begin(); itItem != idItems.end(); ++itItem) + { + const LLInventoryItem* pItem = gInventory.getItem(*itItem); + if ( (pItem) && (gInventory.isObjectDescendentOf(pItem->getUUID(), pRlvRoot->getUUID())) ) + { + // If the containing folder is a folded folder we need its parent + LLViewerInventoryCategory* pFolder = gInventory.getCategory(pItem->getParentUUID()); + if (RlvInventory::instance().isFoldedFolder(pFolder, true)) + pFolder = gInventory.getCategory(pFolder->getParentUUID()); + folders.push_back(pFolder); + } + } + + return (folders.size() != 0); +} + +// Checked: 2011-10-06 (RLVa-1.4.2a) | Modified: RLVa-1.4.2a +const LLUUID& RlvInventory::getSharedRootID() const +{ + if ( (m_idRlvRoot.isNull()) && (gInventory.isInventoryUsable()) ) + { + LLInventoryModel::cat_array_t* pFolders; LLInventoryModel::item_array_t* pItems; + gInventory.getDirectDescendentsOf(gInventory.getRootFolderID(), pFolders, pItems); + if (pFolders) + { + // NOTE: we might have multiple #RLV folders (pick the first one with sub-folders; otherwise the last one with no sub-folders) + const LLViewerInventoryCategory* pFolder; + for (S32 idxFolder = 0, cntFolder = pFolders->size(); idxFolder < cntFolder; idxFolder++) + { + if ( ((pFolder = pFolders->at(idxFolder)) != NULL) && (cstrSharedRoot == pFolder->getName()) ) + { + m_idRlvRoot = pFolder->getUUID(); + if (getDirectDescendentsFolderCount(pFolder) > 0) + break; + } + } + if ( (m_idRlvRoot.notNull()) && (!gInventory.containsObserver((RlvInventory*)this)) ) + gInventory.addObserver((RlvInventory*)this); + } + } + return m_idRlvRoot; +} + +// Checked: 2010-02-28 (RLVa-1.2.0a) | Modified: RLVa-1.0.1a +LLViewerInventoryCategory* RlvInventory::getSharedFolder(const LLUUID& idParent, const std::string& strFolderName, bool fMatchPartial) const +{ + LLInventoryModel::cat_array_t* pFolders; LLInventoryModel::item_array_t* pItems; + gInventory.getDirectDescendentsOf(idParent, pFolders, pItems); + if ( (!pFolders) || (strFolderName.empty()) ) + return NULL; + + // If we can't find an exact match then we'll settle for a "contains" match + LLViewerInventoryCategory* pPartial = NULL; + for (LLInventoryModel::cat_array_t::const_iterator itFolder = pFolders->begin(); itFolder != pFolders->end(); ++itFolder) + { + LLViewerInventoryCategory* pFolder = *itFolder; + const std::string& strName = pFolder->getName(); + + if (boost::iequals(strName, strFolderName)) + return pFolder; // Found an exact match, no need to keep on going + else if ( (fMatchPartial) && (!pPartial) && (RLV_FOLDER_PREFIX_HIDDEN != strName[0]) && (boost::icontains(strName, strFolderName)) ) + pPartial = pFolder; // Found a partial (non-hidden) match, but we might still find an exact one (first partial match wins) + } + + return pPartial; +} + +// Checked: 2010-02-28 (RLVa-1.2.0a) | Modified: RLVa-0.2.0e +LLViewerInventoryCategory* RlvInventory::getSharedFolder(const std::string& strPath, bool fMatchPartial) const +{ + // Sanity check - no shared root => no shared folder + LLViewerInventoryCategory* pRlvRoot = getSharedRoot(), *pFolder = pRlvRoot; + if (!pRlvRoot) + return NULL; + + // Walk the path (starting at the root) + boost_tokenizer tokens(strPath, boost::char_separator<char>("/", "", boost::drop_empty_tokens)); + for (boost_tokenizer::const_iterator itToken = tokens.begin(); itToken != tokens.end(); ++itToken) + { + pFolder = getSharedFolder(pFolder->getUUID(), *itToken, fMatchPartial); + if (!pFolder) + return NULL; // No such folder + } + + return pFolder; // If strPath was empty or just a bunch of //// then: pFolder == pRlvRoot +} + +// Checked: 2010-03-02 (RLVa-1.2.0a) | Modified: RLVa-0.2.0g +std::string RlvInventory::getSharedPath(const LLViewerInventoryCategory* pFolder) const +{ + // Sanity check - no shared root or no folder => no path + const LLViewerInventoryCategory* pRlvRoot = getSharedRoot(); + if ( (!pRlvRoot) || (!pFolder) || (pRlvRoot->getUUID() == pFolder->getUUID()) ) + return std::string(); + + const LLUUID& idRLV = pRlvRoot->getUUID(); + const LLUUID& idRoot = gInventory.getRootFolderID(); + std::string strPath; + + // Walk up the tree until we reach the top + RLV_ASSERT(gInventory.isObjectDescendentOf(pFolder->getUUID(), pRlvRoot->getUUID())); + while (pFolder) + { + strPath = "/" + pFolder->getName() + strPath; + + const LLUUID& idParent = pFolder->getParentUUID(); + if (idRLV == idParent) // Reached the shared root, we're done + break; + else if (idRoot == idParent) // We reached the agent's inventory root (indicative of a logic error elsewhere) + return std::string(); + + pFolder = gInventory.getCategory(idParent); + } + + return strPath.erase(0, 1); +} + +// Checked: 2011-10-06 (RLVa-1.4.2a) | Added: RLVa-1.4.2a +S32 RlvInventory::getDirectDescendentsFolderCount(const LLInventoryCategory* pFolder) +{ + LLInventoryModel::cat_array_t* pFolders = NULL; LLInventoryModel::item_array_t* pItems = NULL; + if (pFolder) + gInventory.getDirectDescendentsOf(pFolder->getUUID(), pFolders, pItems); + return (pFolders) ? pFolders->size() : 0; +} + +// Checked: 2009-05-26 (RLVa-0.2.0d) | Modified: RLVa-0.2.0d +S32 RlvInventory::getDirectDescendentsItemCount(const LLInventoryCategory* pFolder, LLAssetType::EType filterType) +{ + S32 cntType = 0; + if (pFolder) + { + LLInventoryModel::cat_array_t* pFolders; LLInventoryModel::item_array_t* pItems; + gInventory.getDirectDescendentsOf(pFolder->getUUID(), pFolders, pItems); + + if (pItems) + { + for (S32 idxItem = 0, cntItem = pItems->size(); idxItem < cntItem; idxItem++) + if (pItems->at(idxItem)->getType() == filterType) + cntType++; + } + } + return cntType; +} + +// Checked: 2012-11-28 (RLVa-1.4.8) +bool RlvInventory::isGiveToRLVOffer(const LLOfferInfo& offerInfo) +{ + if ( (!RlvSettings::getForbidGiveToRLV()) && (RlvInventory::instance().getSharedRoot()) ) + { + if (offerInfo.mFromObject) + { + return + (IM_TASK_INVENTORY_OFFERED == offerInfo.mIM) && + (LLAssetType::AT_CATEGORY == offerInfo.mType) && (offerInfo.mDesc.find(RLV_PUTINV_PREFIX) == 1); + } + else + { + return + (IM_INVENTORY_OFFERED == offerInfo.mIM) && + (LLAssetType::AT_CATEGORY == offerInfo.mType) && (offerInfo.mDesc.find(RLV_PUTINV_PREFIX) == 0); + } + } + return false; +} + +// ============================================================================ +// RlvRenameOnWearObserver member functions +// + +// Checked: 2010-03-14 (RLVa-1.2.0a) | Added: RLVa-1.2.0a +void RlvRenameOnWearObserver::done() +{ + gInventory.removeObserver(this); + + // We shouldn't be messing with inventory items during LLInventoryModel::notifyObservers() + doOnIdleOneTime(boost::bind(&RlvRenameOnWearObserver::doneIdle, this)); +} + +// Checked: 2010-03-14 (RLVa-1.2.0a) | Added: RLVa-1.2.0a +void RlvRenameOnWearObserver::doneIdle() +{ + const LLViewerInventoryCategory* pRlvRoot = NULL; + if ( (RlvSettings::getEnableSharedWear()) || (!RlvSettings::getSharedInvAutoRename()) || (LLStartUp::getStartupState() < STATE_STARTED) || + (!isAgentAvatarValid()) || ((pRlvRoot = RlvInventory::instance().getSharedRoot()) == NULL) ) + { + delete this; + return; + } + + const LLViewerJointAttachment* pAttachPt = NULL; S32 idxAttachPt = 0; + RLV_ASSERT(mComplete.size() > 0); // Catch instances where we forgot to call startFetch() + for (uuid_vec_t::const_iterator itItem = mComplete.begin(); itItem != mComplete.end(); ++itItem) + { + const LLUUID& idAttachItem = *itItem; + + // If the item resides under #RLV we'll rename it directly; otherwise settle for "renaming" all of its links residing under #RLV + LLInventoryModel::item_array_t items; + if (gInventory.isObjectDescendentOf(idAttachItem, pRlvRoot->getUUID())) + items.push_back(gInventory.getItem(idAttachItem)); +// // LL kind of messed up the collectLinkedItems (now collectLinksTo) function but I'm not sure if this use-case if worth fixing it for +// else +// items = gInventory.collectLinkedItems(idAttachItem, pRlvRoot->getUUID()); + if (items.empty()) + continue; + + if ( ((pAttachPt = gAgentAvatarp->getWornAttachmentPoint(idAttachItem)) == NULL) || + ((idxAttachPt = RlvAttachPtLookup::getAttachPointIndex(pAttachPt)) == 0) ) + { + RLV_ASSERT(false); + continue; + } + + for (S32 idxItem = 0, cntItem = items.size(); idxItem < cntItem; idxItem++) + { + LLViewerInventoryItem* pItem = items.at(idxItem); + if (!pItem) + continue; + + S32 idxAttachPtItem = RlvAttachPtLookup::getAttachPointIndex(pItem); + if ( (idxAttachPt == idxAttachPtItem) || (idxAttachPtItem) ) + continue; + + std::string strAttachPt = pAttachPt->getName(); + LLStringUtil::toLower(strAttachPt); + + // If we can modify the item then we rename it directly, otherwise we create a new folder and move it + if (pItem->getPermissions().allowModifyBy(gAgent.getID())) + { + std::string strName = pItem->getName(); + LLStringUtil::truncate(strName, DB_INV_ITEM_NAME_STR_LEN - strAttachPt.length() - 3); + + strName += " (" + strAttachPt + ")"; + + pItem->rename(strName); + pItem->updateServer(FALSE); + gInventory.addChangedMask(LLInventoryObserver::LABEL, pItem->getUUID()); + } + else + { + // Don't do anything if the item is a direct descendant of the shared root, or a folded folder + LLViewerInventoryCategory* pFolder = gInventory.getCategory(pItem->getParentUUID()); + if ( (pFolder) && (pFolder->getUUID() != pRlvRoot->getUUID()) && (!RlvInventory::isFoldedFolder(pFolder, false)) ) + { + std::string strFolderName = ".(" + strAttachPt + ")"; + + // Rename the item's parent folder if it's called "New Folder", isn't directly under #RLV and contains exactly 1 object + if ( (LLViewerFolderType::lookupNewCategoryName(LLFolderType::FT_NONE) == pFolder->getName()) && + (pFolder->getParentUUID() != pRlvRoot->getUUID()) && + (1 == RlvInventory::getDirectDescendentsItemCount(pFolder, LLAssetType::AT_OBJECT)) ) + { + pFolder->rename(strFolderName); + pFolder->updateServer(FALSE); + gInventory.addChangedMask(LLInventoryObserver::LABEL, pFolder->getUUID()); + } + else + { + // "No modify" item with a non-renameable parent: create a new folder named and move the item into it + inventory_func_type f = boost::bind(RlvRenameOnWearObserver::onCategoryCreate, _1, pItem->getUUID()); + LLUUID idFolder = gInventory.createNewCategory(pFolder->getUUID(), LLFolderType::FT_NONE, strFolderName, f); + if (idFolder.notNull()) + { + // Not using the new 'CreateInventoryCategory' cap so manually invoke the callback + RlvRenameOnWearObserver::onCategoryCreate(idFolder, pItem->getUUID()); + } + } + } + } + } + } + gInventory.notifyObservers(); + + delete this; +} + +// Checked: 2012-03-22 (RLVa-1.4.6) | Added: RLVa-1.4.6 +void RlvRenameOnWearObserver::onCategoryCreate(const LLUUID& idFolder, const LLUUID idItem) +{ + if ( (idFolder.notNull()) && (idItem.notNull()) ) + move_inventory_item(gAgent.getID(), gAgent.getSessionID(), idItem, idFolder, std::string(), NULL); +} + +// ============================================================================ +// "Give to #RLV" helper classes +// + +// Checked: 2014-01-07 (RLVa-1.4.10) +bool RlvGiveToRLVOffer::createDestinationFolder(const std::string& strPath) +{ + // NOTE: derived classes will delete the instance in their onDestinationCreated override, so don't do anything after triggering the callback + + m_DestPath.clear(); + if (0 == strPath.find(RLV_PUTINV_PREFIX)) + { + boost::split(m_DestPath, strPath, boost::is_any_of(std::string(RLV_PUTINV_SEPARATOR))); + } + + if ( (m_DestPath.size() >= 2) && (m_DestPath.size() <= RLV_PUTINV_MAXDEPTH) ) + { + const std::string strFolder = m_DestPath.front(); + if (RLV_ROOT_FOLDER == strFolder) + { + m_DestPath.pop_front(); + + const LLUUID& idRlvRoot = RlvInventory::instance().getSharedRootID(); + if (idRlvRoot.notNull()) + { + onCategoryCreateCallback(idRlvRoot, this); + } + else + { + inventory_func_type f = boost::bind(RlvGiveToRLVOffer::onCategoryCreateCallback, _1, this); + const LLUUID idTemp = gInventory.createNewCategory(gInventory.getRootFolderID(), LLFolderType::FT_NONE, RLV_ROOT_FOLDER, f); + if (idTemp.notNull()) + onCategoryCreateCallback(idTemp, this); + } + return true; + } + } + m_DestPath.clear(); + return false; +} + +// Checked: 2014-01-07 (RLVa-1.4.10) +void RlvGiveToRLVOffer::onCategoryCreateCallback(LLUUID idFolder, RlvGiveToRLVOffer* pInstance) +{ + if (idFolder.isNull()) + { + // Problem encountered, abort move + pInstance->onDestinationCreated(LLUUID::null, LLStringUtil::null); + return; + } + + while (pInstance->m_DestPath.size() > 1) + { + std::string strFolder = pInstance->m_DestPath.front(); + pInstance->m_DestPath.pop_front(); + + const LLViewerInventoryCategory* pFolder = RlvInventory::instance().getSharedFolder(idFolder, strFolder, false); + if (pFolder) + { + idFolder = pFolder->getUUID(); + } + else + { + LLInventoryObject::correctInventoryName(strFolder); + inventory_func_type f = boost::bind(RlvGiveToRLVOffer::onCategoryCreateCallback, _1, pInstance); + const LLUUID idTemp = gInventory.createNewCategory(idFolder, LLFolderType::FT_NONE, strFolder, f); + if (idTemp.notNull()) + onCategoryCreateCallback(idTemp, pInstance); + return; + } + } + + // Destination folder should exist at this point (we'll be deallocated when the function returns) + pInstance->onDestinationCreated(idFolder, pInstance->m_DestPath.front()); +} + +// Checked: 2014-01-07 (RLVa-1.4.10) +void RlvGiveToRLVOffer::moveAndRename(const LLUUID& idFolder, const LLUUID& idDestination, const std::string& strName) +{ + const LLViewerInventoryCategory* pDest = gInventory.getCategory(idDestination); + const LLViewerInventoryCategory* pFolder = gInventory.getCategory(idFolder); + if ( (pDest) && (pFolder) ) + { + LLPointer<LLViewerInventoryCategory> pNewFolder = new LLViewerInventoryCategory(pFolder); + if (pDest->getUUID() != pFolder->getParentUUID()) + { + LLInventoryModel::update_list_t update; + LLInventoryModel::LLCategoryUpdate updOldParent(pFolder->getParentUUID(), -1); + update.push_back(updOldParent); + LLInventoryModel::LLCategoryUpdate updNewParent(pDest->getUUID(), 1); + update.push_back(updNewParent); + gInventory.accountForUpdate(update); + + pNewFolder->setParent(pDest->getUUID()); + pNewFolder->updateParentOnServer(FALSE); + } + + pNewFolder->rename(strName); + pNewFolder->updateServer(FALSE); + gInventory.updateCategory(pNewFolder); + + gInventory.notifyObservers(); + } +} + +// Checked: 2010-04-18 (RLVa-1.2.0) +void RlvGiveToRLVTaskOffer::changed(U32 mask) +{ + if (mask & LLInventoryObserver::ADD) + { + LLMessageSystem* pMsg = gMessageSystem; + if ( (pMsg->getMessageName()) && (0 == strcmp(pMsg->getMessageName(), "BulkUpdateInventory")) ) + { + LLUUID idTransaction; + pMsg->getUUIDFast(_PREHASH_AgentData, _PREHASH_TransactionID, idTransaction); + if (m_idTransaction == idTransaction) + { + LLUUID idInvObject; + for (S32 idxBlock = 0, cntBlock = pMsg->getNumberOfBlocksFast(_PREHASH_FolderData); idxBlock < cntBlock; idxBlock++) + { + pMsg->getUUIDFast(_PREHASH_FolderData, _PREHASH_FolderID, idInvObject, idxBlock); + if ( (idInvObject.notNull()) && (std::find(m_Folders.begin(), m_Folders.end(), idInvObject) == m_Folders.end()) ) + m_Folders.push_back(idInvObject); + } + + done(); + } + } + } +} + +// Checked: 2010-04-18 (RLVa-1.2.0) +void RlvGiveToRLVTaskOffer::done() +{ + gInventory.removeObserver(this); + + // We shouldn't be messing with inventory items during LLInventoryModel::notifyObservers() + doOnIdleOneTime(boost::bind(&RlvGiveToRLVTaskOffer::doneIdle, this)); +} + +// Checked: 2014-01-07 (RLVa-1.4.10) +void RlvGiveToRLVTaskOffer::doneIdle() +{ + const LLViewerInventoryCategory* pFolder = (m_Folders.size()) ? gInventory.getCategory(m_Folders.front()) : NULL; + if ( (!pFolder) || (!createDestinationFolder(pFolder->getName())) ) + delete this; +} + +// Checked: 2010-04-18 (RLVa-1.2.0) +void RlvGiveToRLVTaskOffer::onDestinationCreated(const LLUUID& idFolder, const std::string& strName) +{ + const LLViewerInventoryCategory* pTarget = (idFolder.notNull()) ? gInventory.getCategory(idFolder) : NULL; + if (pTarget) + { + const LLUUID& idOfferedFolder = m_Folders.front(); + moveAndRename(idOfferedFolder, idFolder, strName); + RlvBehaviourNotifyHandler::sendNotification("accepted_in_rlv inv_offer " + RlvInventory::instance().getSharedPath(idOfferedFolder)); + } + delete this; +} + +// Checked: 2010-04-18 (RLVa-1.2.0) +void RlvGiveToRLVAgentOffer::done() +{ + gInventory.removeObserver(this); + + // We shouldn't be messing with inventory items during LLInventoryModel::notifyObservers() + doOnIdleOneTime(boost::bind(&RlvGiveToRLVAgentOffer::doneIdle, this)); +} + +// Checked: 2014-01-07 (RLVa-1.4.10) +void RlvGiveToRLVAgentOffer::doneIdle() +{ + const LLViewerInventoryCategory* pFolder = (mComplete.size()) ? gInventory.getCategory(mComplete.front()) : NULL; + if ( (!pFolder) || (!createDestinationFolder(pFolder->getName())) ) + delete this; +} + +// Checked: 2010-04-18 (RLVa-1.2.0) +void RlvGiveToRLVAgentOffer::onDestinationCreated(const LLUUID& idFolder, const std::string& strName) +{ + if ( (idFolder.notNull()) && (mComplete.size()) ) + moveAndRename(mComplete[0], idFolder, strName); + delete this; +} + +// ============================================================================ +// RlvWearableItemCollector +// + +// Checked: 2010-09-25 (RLVa-1.2.1c) | Added: RLVa-1.2.1c +RlvWearableItemCollector::RlvWearableItemCollector(const LLInventoryCategory* pFolder, RlvForceWear::EWearAction eAction, RlvForceWear::EWearFlags eFlags) + : m_idFolder(pFolder->getUUID()), m_eWearAction(eAction), m_eWearFlags(eFlags), + m_strWearAddPrefix(RlvSettings::getWearAddPrefix()), m_strWearReplacePrefix(RlvSettings::getWearReplacePrefix()) +{ + m_Wearable.push_back(m_idFolder); + + // Wear prefixes can't/shouldn't start with '.' + if ( (m_strWearAddPrefix.length() > 1) && (RLV_FOLDER_PREFIX_HIDDEN == m_strWearAddPrefix[0]) ) + m_strWearAddPrefix.clear(); + if ( (m_strWearReplacePrefix.length() > 1) && (RLV_FOLDER_PREFIX_HIDDEN == m_strWearReplacePrefix[0]) ) + m_strWearReplacePrefix.clear(); + + // If there's a prefix on the "root" folder then it will override what we were passed in the constructor + m_eWearAction = getWearActionNormal(pFolder); + m_WearActionMap.insert(std::pair<LLUUID, RlvForceWear::EWearAction>(m_idFolder, m_eWearAction)); +} + +// Checked: 2010-09-25 (RLVa-1.2.1c) | Added: RLVa-1.2.1c +RlvForceWear::EWearAction RlvWearableItemCollector::getWearActionNormal(const LLInventoryCategory* pFolder) +{ + RLV_ASSERT_DBG(!RlvInventory::isFoldedFolder(pFolder, false)); + if ( (RlvForceWear::ACTION_WEAR_REPLACE == m_eWearAction) && (!m_strWearAddPrefix.empty()) && + (boost::algorithm::starts_with(pFolder->getName(), m_strWearAddPrefix))) + { + return RlvForceWear::ACTION_WEAR_ADD; + } + else if ( (RlvForceWear::ACTION_WEAR_ADD == m_eWearAction) && (!m_strWearReplacePrefix.empty()) && + (boost::algorithm::starts_with(pFolder->getName(), m_strWearReplacePrefix)) ) + { + return RlvForceWear::ACTION_WEAR_REPLACE; + } + return (pFolder->getUUID() != m_idFolder) ? getWearAction(pFolder->getParentUUID()) : m_eWearAction; +} + +// Checked: 2010-04-07 (RLVa-1.2.0d) | Added: RLVa-0.2.0e +const LLUUID& RlvWearableItemCollector::getFoldedParent(const LLUUID& idFolder) const +{ + std::map<LLUUID, LLUUID>::const_iterator itFolder = m_FoldingMap.end(), itCur = m_FoldingMap.find(idFolder); + while (itCur != m_FoldingMap.end()) + { + itFolder = itCur; + itCur = m_FoldingMap.find(itFolder->second); + } + return (m_FoldingMap.end() == itFolder) ? idFolder : itFolder->second; +} + +// Checked: 2010-09-25 (RLVa-1.2.1c) | Added: RLVa-1.2.1c +RlvForceWear::EWearAction RlvWearableItemCollector::getWearAction(const LLUUID& idFolder) const +{ + LLUUID idCurFolder(idFolder); std::map<LLUUID, RlvForceWear::EWearAction>::const_iterator itCurFolder; + while ((itCurFolder = m_WearActionMap.find(idCurFolder)) == m_WearActionMap.end()) + { + const LLViewerInventoryCategory* pFolder = gInventory.getCategory(idCurFolder); + if ((!pFolder) || (gInventory.getRootFolderID() == pFolder->getParentUUID())) + break; + idCurFolder = pFolder->getParentUUID(); + } + return (itCurFolder != m_WearActionMap.end()) ? itCurFolder->second : m_eWearAction; +} + +// Checked: 2010-09-30 (RLVa-1.2.1d) | Modified: RLVa-1.2.1d +bool RlvWearableItemCollector::onCollectFolder(const LLInventoryCategory* pFolder) +{ + // We treat folder links differently since they won't exist in the wearable folder list yet and their ancestry isn't relevant + bool fLinkedFolder = isLinkedFolder(pFolder->getUUID()); + if ( (!fLinkedFolder) && (m_Wearable.end() == std::find(m_Wearable.begin(), m_Wearable.end(), pFolder->getParentUUID())) ) + return false; // Not a linked folder or the child of a wearable folder + + const std::string& strFolder = pFolder->getName(); + if (strFolder.empty()) // Shouldn't happen but does... naughty Lindens + return false; + + bool fAttach = RlvForceWear::isWearAction(m_eWearAction); + bool fMatchAll = (!fLinkedFolder) && (m_eWearFlags & RlvForceWear::FLAG_MATCHALL); + + if ( (!fLinkedFolder) && (RlvInventory::isFoldedFolder(pFolder, false)) ) // Check for folder that should get folded under its parent + { + if ( (!fAttach) || (1 == RlvInventory::getDirectDescendentsItemCount(pFolder, LLAssetType::AT_OBJECT)) ) + { // When attaching there should only be 1 attachment in it + m_Folded.push_front(pFolder->getUUID()); + m_FoldingMap.insert(std::pair<LLUUID, LLUUID>(pFolder->getUUID(), pFolder->getParentUUID())); + } + } + else if ( (RLV_FOLDER_PREFIX_HIDDEN != strFolder[0]) && // Collect from any non-hidden child folder for *all + ( (fMatchAll) || (fLinkedFolder) ) && // ... and collect from linked folders + (!isLinkedFolder(pFolder->getParentUUID())) ) // ... but never from non-folded linked folder descendents + { + #ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS + if ( (!RlvSettings::getEnableComposites()) || // ... if we're not checking composite folders + (!gRlvHandler.isCompositeFolder(pFolder)) || // ... or if it's not a composite folder + ((m_fAttach) && (gRlvHandler.canWearComposite(pFolder))) || // ... or if we're attaching and can attach it OR + (!m_fAttach) && (gRlvHandler.canTakeOffComposite(pFolder)) ) // ... or if we're detaching and can detach it + #endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS + { + m_Wearable.push_front(pFolder->getUUID()); + m_WearActionMap.insert(std::pair<LLUUID, RlvForceWear::EWearAction>(pFolder->getUUID(), getWearActionNormal(pFolder))); + } + return (!fLinkedFolder) && (pFolder->getParentUUID() == m_idFolder); // Convenience for @getinvworn + } + #ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS + else if ( (RlvSettings::getEnableComposites()) && + (RLV_FOLDER_PREFIX_HIDDEN == strFolder[0]) && // Hidden folder that's a... + (gRlvHandler.isCompositeFolder(pFolder)) && // ... composite folder which we... + ( ((m_fAttach) && (gRlvHandler.canWearComposite(pFolder))) || // ... are attaching and can attach OR + (!m_fAttach) && (gRlvHandler.canTakeOffComposite(pFolder)) ) ) // ... are detaching and can detach + { + m_Wearable.push_front(pFolder->getUUID()); + m_FoldingMap.insert(std::pair<LLUUID, LLUUID>(pFolder->getUUID(), idParent)); + } + #endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS + + return false; +} + +// Checked: 2010-09-30 (RLVa-1.2.1d) | Modified: RLVa-1.2.1d +bool RlvWearableItemCollector::onCollectItem(const LLInventoryItem* pItem) +{ + bool fAttach = RlvForceWear::isWearAction(m_eWearAction); + + if ( (!fAttach) && (!RlvForceWear::isStrippable(pItem)) ) // Don't process "nostrip" items on detach + return false; + + const LLUUID& idParent = pItem->getParentUUID(); bool fRet = false; + switch (pItem->getType()) + { + case LLAssetType::AT_BODYPART: + if (!fAttach) + break; // Don't process body parts on detach + case LLAssetType::AT_CLOTHING: + fRet = ( (m_Wearable.end() != std::find(m_Wearable.begin(), m_Wearable.end(), idParent)) || + ( (fAttach) && (m_Folded.end() != std::find(m_Folded.begin(), m_Folded.end(), idParent)) && + (RlvForceWear::isStrippable(pItem)) ) ); + break; + case LLAssetType::AT_OBJECT: + fRet = ( (m_Wearable.end() != std::find(m_Wearable.begin(), m_Wearable.end(), idParent)) || + (m_Folded.end() != std::find(m_Folded.begin(), m_Folded.end(), idParent)) ) && + ( (!fAttach) || (RlvAttachPtLookup::hasAttachPointName(pItem)) || (RlvSettings::getEnableSharedWear()) ); + break; + case LLAssetType::AT_GESTURE: + fRet = (m_Wearable.end() != std::find(m_Wearable.begin(), m_Wearable.end(), idParent)); + break; + case LLAssetType::AT_CATEGORY: + if (LLAssetType::AT_LINK_FOLDER == pItem->getActualType()) + { + const LLUUID& idLinkedFolder = pItem->getLinkedUUID(); + LLViewerInventoryCategory* pLinkedFolder = gInventory.getCategory(idLinkedFolder); + // Link can't point to an outfit folder, or start a second level of indirection, or have the base folder as an ancestor + if ( (pLinkedFolder) && (LLFolderType::FT_OUTFIT != pLinkedFolder->getPreferredType()) && + (gInventory.isObjectDescendentOf(pItem->getUUID(), m_idFolder)) && + (!gInventory.isObjectDescendentOf(idLinkedFolder, m_idFolder)) ) + { + // Fold the contents of the linked folder under the folder the link is a child of + m_FoldingMap.insert(std::pair<LLUUID, LLUUID>(idLinkedFolder, pItem->getParentUUID())); + m_Linked.push_front(idLinkedFolder); + } + } + break; + default: + break; + } + return fRet; +} + +// Checked: 2010-03-20 (RLVa-1.2.0a) | Modified: RLVa-0.2.0d +bool RlvWearableItemCollector::operator()(LLInventoryCategory* pFolder, LLInventoryItem* pItem) +{ + // NOTE: this is used for more than was originally intended so only modify if you're sure it won't break something obscure + return (pFolder) ? onCollectFolder(pFolder) : ( (pItem) ? onCollectItem(pItem) : false ); +} + +// ============================================================================ +// General purpose inventory helper classes +// + +// Checked: 2013-10-12 (RLVa-1.4.9) +bool RlvFindAttachmentsOnPoint::operator()(LLInventoryCategory* pFolder, LLInventoryItem* pItem) +{ +#ifndef RLV_DEPRECATE_ATTACHPTNAMING + // First check if the item is attached to the attachment point; fall back to the item name otherwise + return (pItem) && (LLAssetType::AT_OBJECT == pItem->getType()) && + ( ((m_pAttachPt) && (m_pAttachPt->getAttachedObject(pItem->getLinkedUUID()))) || (RlvAttachPtLookup::getAttachPoint(pItem) == m_pAttachPt) ); +#else + return (pItem) && (LLAssetType::AT_OBJECT == pItem->getType()) && (m_pAttachPt) && (m_pAttachPt->getAttachedObject(pItem->getLinkedUUID())); +#endif // RLV_DEPRECATE_LEGACY_ATTACHPT +} + +// ============================================================================ diff --git a/indra/newview/rlvinventory.h b/indra/newview/rlvinventory.h new file mode 100644 index 0000000000000000000000000000000000000000..1d1f2ca34e12e62065b647842820bb5706e806a9 --- /dev/null +++ b/indra/newview/rlvinventory.h @@ -0,0 +1,344 @@ +/** + * + * Copyright (c) 2009-2014, Kitty Barnett + * + * The source code in this file is provided to you under the terms of the + * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt + * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.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. + * + */ + +#ifndef RLV_INVENTORY_H +#define RLV_INVENTORY_H + +#include "llinventoryfunctions.h" +#include "llinventoryobserver.h" +#include "llsingleton.h" + +#include "rlvhelper.h" +#include "rlvlocks.h" + +// ============================================================================ +// Forward declarations +// + +class LLOfferInfo; + +// ============================================================================ +// RlvInventory class declaration +// + +class RlvInventory : public LLSingleton<RlvInventory>, public LLInventoryObserver +{ +protected: + RlvInventory(); +public: + ~RlvInventory(); + + // LLInventoryObserver override + /*virtual*/ void changed(U32 mask); + + /* + * #RLV Shared inventory + */ +public: + typedef boost::signals2::signal<void (void)> callback_signal_t; + void addSharedRootIDChangedCallback(const callback_signal_t::slot_type& cb) { m_OnSharedRootIDChanged.connect(cb); } + // Find all folders that match a supplied criteria (clears the output array) + bool findSharedFolders(const std::string& strCriteria, LLInventoryModel::cat_array_t& folders) const; + // Gets the shared path for any shared items present in idItems (clears the output array) + bool getPath(const uuid_vec_t& idItems, LLInventoryModel::cat_array_t& folders) const; + // Returns a pointer to the shared root folder (if there is one) + LLViewerInventoryCategory* getSharedRoot() const; + const LLUUID& getSharedRootID() const; + // Returns a subfolder of idParent that starts with strFolderName (exact match > partial match) + LLViewerInventoryCategory* getSharedFolder(const LLUUID& idParent, const std::string& strFolderName, bool fMatchPartial = true) const; + // Looks up a folder from a path (relative to the shared root) + LLViewerInventoryCategory* getSharedFolder(const std::string& strPath, bool fMatchPartial = true) const; + // Returns the path of the supplied folder (relative to the shared root) + std::string getSharedPath(const LLViewerInventoryCategory* pFolder) const; + std::string getSharedPath(const LLUUID& idFolder) const; + // Returns TRUE if the supplied folder is a descendent of the #RLV folder + bool isSharedFolder(const LLUUID& idFolder); + // Returns TRUE if the inventory offer is a "give to #RLV" offer + bool isGiveToRLVOffer(const LLOfferInfo& offerInfo); + + /* + * Inventory fetching + */ +public: + void fetchSharedInventory(); + void fetchWornItems(); +protected: + void fetchSharedLinks(); + + /* + * General purpose helper functions + */ +public: + // Returns the number of sub-folders of the specified folder + static S32 getDirectDescendentsFolderCount(const LLInventoryCategory* pFolder); + // Returns the number of direct descendents of the specified folder that have the specified type asset type + static S32 getDirectDescendentsItemCount(const LLInventoryCategory* pFolder, LLAssetType::EType filterType); + // Returns the folder the items of the specified folder should folded into (can be the folder itself) + static const LLUUID& getFoldedParent(const LLUUID& idFolder, bool fCheckComposite); + // A "folded folder" is a folder whose items logically belong to the grandparent rather than the parent + static bool isFoldedFolder(const LLInventoryCategory* pFolder, bool fCheckComposite); + + /* + * Member variables + */ +protected: + bool m_fFetchStarted; // TRUE if we fired off an inventory fetch + bool m_fFetchComplete; // TRUE if everything was fetched + mutable LLUUID m_idRlvRoot; + callback_signal_t m_OnSharedRootIDChanged; + +private: + static const std::string cstrSharedRoot; + friend class RlvSharedInventoryFetcher; + friend class LLSingleton<RlvInventory>; +}; + +// ============================================================================ +// RlvRenameOnWearObserver - Handles "auto-rename-on-wear" for (linked) items living under #RLV +// + +class RlvRenameOnWearObserver : public LLInventoryFetchItemsObserver +{ +public: + RlvRenameOnWearObserver(const LLUUID& idItem) : LLInventoryFetchItemsObserver(idItem) {} + virtual ~RlvRenameOnWearObserver() {} + virtual void done(); +protected: + void doneIdle(); + static void onCategoryCreate(const LLUUID& idFolder, const LLUUID idItem); +}; + +// ============================================================================ +// "Give to #RLV" helper classes +// + +class RlvGiveToRLVOffer +{ +protected: + RlvGiveToRLVOffer() {} + virtual ~RlvGiveToRLVOffer() {} +protected: + bool createDestinationFolder(const std::string& strPath); + virtual void onDestinationCreated(const LLUUID& idFolder, const std::string& strName) = 0; + void moveAndRename(const LLUUID& idFolder, const LLUUID& idDestination, const std::string& strName); +private: + static void onCategoryCreateCallback(LLUUID idFolder, RlvGiveToRLVOffer* pInstance); + +private: + std::list<std::string> m_DestPath; +}; + +// [See LLInventoryTransactionObserver which says it's not entirely complete?] +// NOTE: the offer may span mulitple BulkUpdateInventory messages so if we're no longer around then (ie due to "delete this") then +// we'll miss those; in this specific case we only care about the *folder* though and that will be in the very first message +class RlvGiveToRLVTaskOffer : public LLInventoryObserver, RlvGiveToRLVOffer +{ +public: + RlvGiveToRLVTaskOffer(const LLUUID& idTransaction) : RlvGiveToRLVOffer(), m_idTransaction(idTransaction) {} + /*virtual*/ void changed(U32 mask); +protected: + /*virtual*/ void done(); + void doneIdle(); + /*virtual*/ void onDestinationCreated(const LLUUID& idFolder, const std::string& strName); + +protected: + typedef std::vector<LLUUID> folder_ref_t; + folder_ref_t m_Folders; + LLUUID m_idTransaction; +}; + +class RlvGiveToRLVAgentOffer : public LLInventoryFetchDescendentsObserver, RlvGiveToRLVOffer +{ +public: + RlvGiveToRLVAgentOffer(const LLUUID& idFolder) : RlvGiveToRLVOffer(), LLInventoryFetchDescendentsObserver(idFolder) {} + /*virtual*/ ~RlvGiveToRLVAgentOffer() {} +public: + /*virtual*/ void done(); +protected: + void doneIdle(); + /*virtual*/ void onDestinationCreated(const LLUUID& idFolder, const std::string& strName); +}; + +// ============================================================================ +// RlvCriteriaCategoryCollector - Criteria based folder matching filter used by @findfolder and @findfolders +// + +class RlvCriteriaCategoryCollector : public LLInventoryCollectFunctor +{ +public: + RlvCriteriaCategoryCollector(const std::string& strCriteria) + { + std::string::size_type idxIt, idxLast = 0; + while (idxLast < strCriteria.length()) + { + idxIt = strCriteria.find("&&", idxLast); + if (std::string::npos == idxIt) + idxIt = strCriteria.length(); + if (idxIt != idxLast) + m_Criteria.push_back(strCriteria.substr(idxLast, idxIt - idxLast)); + idxLast = idxIt + 2; + } + } + virtual ~RlvCriteriaCategoryCollector() {} + + virtual bool operator()(LLInventoryCategory* pFolder, LLInventoryItem* pItem) + { + if ( (!pFolder) || (m_Criteria.empty()) ) // We're only interested in matching folders, we don't care about items + return false; // (if there are no criteria then we don't want to return a match) + + std::string strFolderName = pFolder->getName(); + LLStringUtil::toLower(strFolderName); + + // NOTE: hidden or "give to #RLV" folders can never be a match + if ( (strFolderName.empty()) || + (RLV_FOLDER_PREFIX_HIDDEN == strFolderName[0]) || (RLV_FOLDER_PREFIX_PUTINV == strFolderName[0]) ) + { + return false; + } + + for (std::list<std::string>::const_iterator itCrit = m_Criteria.begin(); itCrit != m_Criteria.end(); ++itCrit) + if (std::string::npos == strFolderName.find(*itCrit)) + return false; + return true; + } + +protected: + std::list<std::string> m_Criteria; +}; + +// ============================================================================ +// RlvWearableItemCollector - Inventory item filter used by attach/detach/attachall/detachall/getinvworn +// + +class RlvWearableItemCollector : public LLInventoryCollectFunctor +{ +public: + RlvWearableItemCollector(const LLInventoryCategory* pFolder, RlvForceWear::EWearAction eAction, RlvForceWear::EWearFlags eFlags); + virtual ~RlvWearableItemCollector() {} + + virtual bool operator()(LLInventoryCategory* pFolder, LLInventoryItem* pItem); + + const LLUUID& getFoldedParent(const LLUUID& idFolder) const; + RlvForceWear::EWearAction getWearAction(const LLUUID& idFolder) const; + RlvForceWear::EWearAction getWearActionNormal(const LLInventoryCategory* pFolder); + RlvForceWear::EWearAction getWearActionFolded(const LLInventoryCategory* pFolder); + bool isLinkedFolder(const LLUUID& idFolder); +protected: + const LLUUID m_idFolder; + RlvForceWear::EWearAction m_eWearAction; + RlvForceWear::EWearFlags m_eWearFlags; + + bool onCollectFolder(const LLInventoryCategory* pFolder); + bool onCollectItem(const LLInventoryItem* pItem); + + std::list<LLUUID> m_Folded; + std::list<LLUUID> m_Linked; + std::list<LLUUID> m_Wearable; + std::map<LLUUID, LLUUID> m_FoldingMap; + std::map<LLUUID, RlvForceWear::EWearAction> m_WearActionMap; + + std::string m_strWearAddPrefix; + std::string m_strWearReplacePrefix; +}; + +// ============================================================================ +// General purpose inventory helper classes +// + +class RlvIsLinkType : public LLInventoryCollectFunctor +{ +public: + RlvIsLinkType() {} + /*virtual*/ ~RlvIsLinkType() {} + virtual bool operator()(LLInventoryCategory* pFolder, LLInventoryItem* pItem) { return (pItem) && (pItem->getIsLinkType()); } +}; + +// If the attachment item is linked in COF but isn't worn (or just detached) the function will return inconsistent information +class RlvFindAttachmentsOnPoint : public LLInventoryCollectFunctor +{ +public: + RlvFindAttachmentsOnPoint(const LLViewerJointAttachment* pAttachPt) : m_pAttachPt(pAttachPt) {} + /*virtual*/ ~RlvFindAttachmentsOnPoint() {} + virtual bool operator()(LLInventoryCategory* pFolder, LLInventoryItem* pItem); +protected: + const LLViewerJointAttachment* m_pAttachPt; +}; + +// ============================================================================ +// RlvInventory inlined member functions +// + +// Checked: 2011-03-28 (RLVa-1.3.0g) | Modified: RLVa-1.3.0g +inline LLViewerInventoryCategory* RlvInventory::getSharedRoot() const +{ + const LLUUID& idRlvRoot = getSharedRootID(); + return (idRlvRoot.notNull()) ? gInventory.getCategory(idRlvRoot) : NULL; +} + +// Checked: 2011-11-26 (RLVa-1.5.4a) | Added: RLVa-1.5.4a +inline const LLUUID& RlvInventory::getFoldedParent(const LLUUID& idFolder, bool fCheckComposite) +{ + LLViewerInventoryCategory* pFolder = gInventory.getCategory(idFolder); + while ((pFolder) && (isFoldedFolder(pFolder, fCheckComposite))) + pFolder = gInventory.getCategory(pFolder->getParentUUID()); + return (pFolder) ? pFolder->getUUID() : LLUUID::null; +} + +// Checked: 2011-11-26 (RLVa-1.5.4a) | Added: RLVa-1.5.4a +inline std::string RlvInventory::getSharedPath(const LLUUID& idFolder) const +{ + return getSharedPath(gInventory.getCategory(idFolder)); +} + +// Checked: 2010-03-19 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a +inline bool RlvInventory::isFoldedFolder(const LLInventoryCategory* pFolder, bool fCheckComposite) +{ + return + // If legacy naming isn't enabled we can return early if the folder name doesn't start with a '.' (= the most common case) + (pFolder) && ( (RlvSettings::getEnableLegacyNaming()) || (RLV_FOLDER_PREFIX_HIDDEN == pFolder->getName().at(0)) ) && + ( + // .(<attachpt>) type folder + (0 != RlvAttachPtLookup::getAttachPointIndex(pFolder)) + // .(nostrip) folder + || ( (pFolder) && (".(" RLV_FOLDER_FLAG_NOSTRIP ")" == pFolder->getName()) ) + // Composite folder (if composite folders are enabled and we're asked to look for them) + #ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS + || ( (fCheckComposite) && (RlvSettings::getEnableComposites()) && + (pFolder) && (RLV_FOLDER_PREFIX_HIDDEN == pFolder->getName().at(0)) && (isCompositeFolder(pFolder)) ) + #endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS + ); +} + +// Checked: 2010-08-29 (RLVa-1.2.0c) | Added: RLVa-1.2.0c +inline bool RlvInventory::isSharedFolder(const LLUUID& idFolder) +{ + const LLViewerInventoryCategory* pRlvRoot = getSharedRoot(); + return (pRlvRoot) ? (pRlvRoot->getUUID() != idFolder) && (gInventory.isObjectDescendentOf(idFolder, pRlvRoot->getUUID())) : false; +} + +// ============================================================================ +// RlvWearableItemCollector inlined member functions +// + +// Checked: 2010-09-30 (RLVa-1.2.1d) | Added: RLVa-1.2.1d +inline bool RlvWearableItemCollector::isLinkedFolder(const LLUUID& idFolder) +{ + return (!m_Linked.empty()) && (m_Linked.end() != std::find(m_Linked.begin(), m_Linked.end(), idFolder)); +} + +// ============================================================================ + +#endif // RLV_INVENTORY_H diff --git a/indra/newview/rlvlocks.cpp b/indra/newview/rlvlocks.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b7ac55da32f7d6bbef51e58837e9235c30355c9b --- /dev/null +++ b/indra/newview/rlvlocks.cpp @@ -0,0 +1,1294 @@ +/** + * + * Copyright (c) 2009-2011, Kitty Barnett + * + * The source code in this file is provided to you under the terms of the + * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt + * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.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 "llagent.h" +#include "llappearancemgr.h" +#include "llattachmentsmgr.h" +#include "lloutfitobserver.h" +#include "llviewerobjectlist.h" +#include "llviewermenu.h" +#include "pipeline.h" + +#include "rlvlocks.h" +#include "rlvhelper.h" +#include "rlvinventory.h" + + +// ============================================================================ +// RlvAttachPtLookup member functions +// + +std::map<std::string, S32> RlvAttachPtLookup::m_AttachPtLookupMap; + +// Checked: 2010-03-02 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a +void RlvAttachPtLookup::initLookupTable() +{ + static bool fInitialized = false; + if (!fInitialized) + { + if ( (gAgentAvatarp) && (gAgentAvatarp->mAttachmentPoints.size() > 0) ) + { + std::string strAttachPtName; + for (LLVOAvatar::attachment_map_t::const_iterator itAttach = gAgentAvatarp->mAttachmentPoints.begin(); + itAttach != gAgentAvatarp->mAttachmentPoints.end(); ++itAttach) + { + const LLViewerJointAttachment* pAttachPt = itAttach->second; + if (pAttachPt) + { + strAttachPtName = pAttachPt->getName(); + LLStringUtil::toLower(strAttachPtName); + m_AttachPtLookupMap.insert(std::pair<std::string, S32>(strAttachPtName, itAttach->first)); + + // HACK: the RLV API randomly renames "Avatar Center" to "Root" so make sure we add it (but keep the official name) + if ("avatar center" == strAttachPtName) + { + m_AttachPtLookupMap.insert(std::pair<std::string, S32>("root", itAttach->first)); + } + } + } + fInitialized = true; + } + } +} + +// Checked: 2010-03-03 (RLVa-1.2.0a) | Added: RLVa-0.2.2a +S32 RlvAttachPtLookup::getAttachPointIndex(const LLViewerJointAttachment* pAttachPt) +{ + if (isAgentAvatarValid()) + { + for (LLVOAvatar::attachment_map_t::const_iterator itAttach = gAgentAvatarp->mAttachmentPoints.begin(); + itAttach != gAgentAvatarp->mAttachmentPoints.end(); ++itAttach) + { + if (itAttach->second == pAttachPt) + return itAttach->first; + } + } + return 0; +} + +// Checked: 2010-03-03 (RLVa-1.2.0a) | Modified: RLVa-1.0.1b +S32 RlvAttachPtLookup::getAttachPointIndex(const LLInventoryCategory* pFolder) +{ + if (!pFolder) + return 0; + + // RLVa-1.0.1 added support for legacy matching (See http://rlva.catznip.com/blog/2009/07/attachment-point-naming-convention/) + if (RlvSettings::getEnableLegacyNaming()) + return getAttachPointIndexLegacy(pFolder); + + // Otherwise the only valid way to specify an attachment point in a folder name is: ^\.\(\s+attachpt\s+\) + std::string::size_type idxMatch; + std::string strAttachPt = rlvGetFirstParenthesisedText(pFolder->getName(), &idxMatch); + LLStringUtil::trim(strAttachPt); + + return ( (1 == idxMatch) && (RLV_FOLDER_PREFIX_HIDDEN == pFolder->getName().at(0)) ) ? getAttachPointIndex(strAttachPt) : 0; +} + +// Checked: 2010-03-03 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a +S32 RlvAttachPtLookup::getAttachPointIndex(const LLInventoryItem* pItem, bool fFollowLinks /*=true*/) +{ + // Sanity check - if it's not an object then it can't have an attachment point + if ( (!pItem) || (LLAssetType::AT_OBJECT != pItem->getType()) ) + return 0; + + // If the item is an inventory link then we first examine its target before examining the link itself + if ( (LLAssetType::AT_LINK == pItem->getActualType()) && (fFollowLinks) ) + { + S32 idxAttachPt = getAttachPointIndex(gInventory.getItem(pItem->getLinkedUUID()), false); + if (idxAttachPt) + return idxAttachPt; + } + + // The attachment point should be placed at the end of the item's name, surrounded by parenthesis + // (if there is no such text then strAttachPt will be an empty string which is fine since it means we'll look at the item's parent) + // (if the item is an inventory link then we only look at its containing folder and never examine its name) + std::string strAttachPt = + (LLAssetType::AT_LINK != pItem->getActualType()) ? rlvGetLastParenthesisedText(pItem->getName()) : LLStringUtil::null; + LLStringUtil::trim(strAttachPt); + + // If the item is modify : we look at the item's name first and only then at the containing folder + // If the item is no modify: we look at the containing folder's name first and only then at the item itself + S32 idxAttachPt = 0; + if (pItem->getPermissions().allowModifyBy(gAgent.getID())) + { + idxAttachPt = (!strAttachPt.empty()) ? getAttachPointIndex(strAttachPt) : 0; + if (!idxAttachPt) + idxAttachPt = getAttachPointIndex(gInventory.getCategory(pItem->getParentUUID())); + } + else + { + idxAttachPt = getAttachPointIndex(gInventory.getCategory(pItem->getParentUUID())); + if ( (!idxAttachPt) && (!strAttachPt.empty()) ) + idxAttachPt = getAttachPointIndex(strAttachPt); + } + return idxAttachPt; +} + +// Checked: 2010-03-03 (RLVa-1.2.0a) | Added: RLVa-1.0.1b +S32 RlvAttachPtLookup::getAttachPointIndexLegacy(const LLInventoryCategory* pFolder) +{ + // Hopefully some day this can just be deprecated (see http://rlva.catznip.com/blog/2009/07/attachment-point-naming-convention/) + if ( (!pFolder) || (pFolder->getName().empty()) ) + return 0; + + // Check for a (...) block *somewhere* in the name + std::string::size_type idxMatch; + std::string strAttachPt = rlvGetFirstParenthesisedText(pFolder->getName(), &idxMatch); + if (!strAttachPt.empty()) + { + // Could be "(attachpt)", ".(attachpt)" or "Folder name (attachpt)" + if ( (0 != idxMatch) && ((1 != idxMatch) || (RLV_FOLDER_PREFIX_HIDDEN == pFolder->getName().at(0)) ) && // No '(' or '.(' start + (idxMatch + strAttachPt.length() + 1 != pFolder->getName().length()) ) // or there's extra text + { + // It's definitely not one of the first two so assume it's the last form (in which case we need the last paranthesised block) + strAttachPt = rlvGetLastParenthesisedText(pFolder->getName()); + } + } + else + { + // There's no paranthesised block, but it could still be "attachpt" or ".attachpt" (just strip away the '.' from the last one) + strAttachPt = pFolder->getName(); + if (RLV_FOLDER_PREFIX_HIDDEN == strAttachPt[0]) + strAttachPt.erase(0, 1); + } + return getAttachPointIndex(strAttachPt); +} + +// ============================================================================ +// RlvAttachmentLocks member functions +// + +RlvAttachmentLocks gRlvAttachmentLocks; + +// Checked: 2010-02-28 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a +void RlvAttachmentLocks::addAttachmentLock(const LLUUID& idAttachObj, const LLUUID& idRlvObj) +{ +/* + // Sanity check - make sure it's an object we know about + if ( (m_Objects.find(idRlvObj) == m_Objects.end()) || (!idxAttachPt) ) + return; // If (idxAttachPt) == 0 then: (pObj == NULL) || (pObj->isAttachment() == FALSE) +*/ + +#ifndef RLV_RELEASE + LLViewerObject* pDbgObj = gObjectList.findObject(idAttachObj); + // Assertion: the object specified by idAttachObj exists/is rezzed, is an attachment and always specifies the root + RLV_VERIFY( (pDbgObj) && (pDbgObj->isAttachment()) && (pDbgObj == pDbgObj->getRootEdit()) ); +#endif // RLV_RELEASE + + m_AttachObjRem.insert(std::pair<LLUUID, LLUUID>(idAttachObj, idRlvObj)); + updateLockedHUD(); +} + +// Checked: 2010-02-28 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a +void RlvAttachmentLocks::addAttachmentPointLock(S32 idxAttachPt, const LLUUID& idRlvObj, ERlvLockMask eLock) +{ +/* + // Sanity check - make sure it's an object we know about + if ( (m_Objects.find(idRlvObj) == m_Objects.end()) || (!idxAttachPt) ) + return; // If (idxAttachPt) == 0 then: (pObj == NULL) || (pObj->isAttachment() == FALSE) +*/ + + // NOTE: m_AttachPtXXX can contain duplicate <idxAttachPt, idRlvObj> pairs (ie @detach:spine=n,detach=n from an attachment on spine) + if (eLock & RLV_LOCK_REMOVE) + { + m_AttachPtRem.insert(std::pair<S32, LLUUID>(idxAttachPt, idRlvObj)); + updateLockedHUD(); + } + if (eLock & RLV_LOCK_ADD) + m_AttachPtAdd.insert(std::pair<S32, LLUUID>(idxAttachPt, idRlvObj)); +} + +// Checked: 2011-05-22 (RLVa-1.3.1b) | Added: RLVa-1.3.1b +bool RlvAttachmentLocks::canAttach() const +{ + if (isAgentAvatarValid()) + { + for (LLVOAvatar::attachment_map_t::const_iterator itAttachPt = gAgentAvatarp->mAttachmentPoints.begin(); + itAttachPt != gAgentAvatarp->mAttachmentPoints.end(); ++itAttachPt) + { + if (!isLockedAttachmentPoint(itAttachPt->first, RLV_LOCK_ADD)) + return true; + } + } + return false; +} + +// Checked: 2010-08-07 (RLVa-1.2.0i) | Modified: RLVa-1.2.0i +bool RlvAttachmentLocks::canDetach(const LLViewerJointAttachment* pAttachPt, bool fDetachAll /*=false*/) const +{ + // (fDetachAll) | (isLockedAttachment) + // =================================== + // F | F => unlocked attachment => return true + // F | T => locked attachment => keep going + // T | F => unlocked attachment => keep going + // T | T => locked attachment => return false + // -> inside the loop : (A xor (not B)) condition and return !fDetachAll + // -> outside the loop: return fDetachAll + // fDetachAll == false : return false => all attachments are locked + // fDetachAll == true : return true => all attachments are unlocked + if (pAttachPt) + { + for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator itAttachObj = pAttachPt->mAttachedObjects.begin(); + itAttachObj != pAttachPt->mAttachedObjects.end(); ++itAttachObj) + { + if ( (fDetachAll) ^ (!isLockedAttachment(*itAttachObj)) ) + return !fDetachAll; + } + } + return (pAttachPt) && (fDetachAll); +} + +// Checked: 2010-02-28 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a +bool RlvAttachmentLocks::hasLockedAttachment(const LLViewerJointAttachment* pAttachPt) const +{ + if (pAttachPt) + { + for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator itAttachObj = pAttachPt->mAttachedObjects.begin(); + itAttachObj != pAttachPt->mAttachedObjects.end(); ++itAttachObj) + { + if (isLockedAttachment(*itAttachObj)) + return true; + } + } + return false; +} + +// Checked: 2010-03-19 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a +bool RlvAttachmentLocks::isLockedAttachmentExcept(const LLViewerObject* pObj, const LLUUID& idRlvObj) const +{ + if (idRlvObj.isNull()) + return isLockedAttachment(pObj); + + // If pObj is valid then it should always specify a root since we store root UUIDs in m_AttachObjRem + RLV_ASSERT( (!pObj) || (pObj == pObj->getRootEdit()) ); + + // Loop over every object that has the specified attachment locked (but ignore any locks owned by idRlvObj) + for (rlv_attachobjlock_map_t::const_iterator itAttachObj = m_AttachObjRem.lower_bound(pObj->getID()), + endAttachObj = m_AttachObjRem.upper_bound(pObj->getID()); itAttachObj != endAttachObj; ++itAttachObj) + { + if (itAttachObj->second != idRlvObj) + return true; + } + return isLockedAttachmentPointExcept(RlvAttachPtLookup::getAttachPointIndex(pObj), RLV_LOCK_REMOVE, idRlvObj); +} + +// Checked: 2010-03-19 (RLVa-1.2.0a) | Added: RLVa-1.0.5b +bool RlvAttachmentLocks::isLockedAttachmentPointExcept(S32 idxAttachPt, ERlvLockMask eLock, const LLUUID& idRlvObj) const +{ + if (idRlvObj.isNull()) + return isLockedAttachmentPoint(idxAttachPt, eLock); + + // Loop over every object that has the specified attachment point locked (but ignore any locks owned by idRlvObj) + if (eLock & RLV_LOCK_REMOVE) + { + for (rlv_attachptlock_map_t::const_iterator itAttachPt = m_AttachPtRem.lower_bound(idxAttachPt), + endAttachPt = m_AttachPtRem.upper_bound(idxAttachPt); itAttachPt != endAttachPt; ++itAttachPt) + { + if (itAttachPt->second != idRlvObj) + return true; + } + } + if (eLock & RLV_LOCK_ADD) + { + for (rlv_attachptlock_map_t::const_iterator itAttachPt = m_AttachPtAdd.lower_bound(idxAttachPt), + endAttachPt = m_AttachPtAdd.upper_bound(idxAttachPt); itAttachPt != endAttachPt; ++itAttachPt) + { + if (itAttachPt->second != idRlvObj) + return true; + } + } + return false; +} + +// Checked: 2010-02-28 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a +void RlvAttachmentLocks::removeAttachmentLock(const LLUUID& idAttachObj, const LLUUID& idRlvObj) +{ +/* + // Sanity check - make sure it's an object we know about + if ( (m_Objects.find(idRlvObj) == m_Objects.end()) || (!idxAttachPt) ) + return; // If (idxAttachPt) == 0 then: (pObj == NULL) || (pObj->isAttachment() == FALSE) +*/ + +#ifndef RLV_RELEASE + // NOTE: pObj *can* be NULL [see comments for @detach=n in RlvHandler::onAddRemDetach()] + const LLViewerObject* pDbgObj = gObjectList.findObject(idAttachObj); + // Assertion: if the object exists then it's an attachment and always specifies the root + RLV_VERIFY( (!pDbgObj) || ((pDbgObj->isAttachment()) && (pDbgObj == pDbgObj->getRootEdit())) ); +#endif // RLV_RELEASE + + // NOTE: try to remove the lock even if pObj isn't an attachment (ie in case the user was able to "Drop" it) + RLV_ASSERT( m_AttachObjRem.lower_bound(idAttachObj) != m_AttachObjRem.upper_bound(idAttachObj) ); // The lock should always exist + for (rlv_attachobjlock_map_t::iterator itAttachObj = m_AttachObjRem.lower_bound(idAttachObj), + endAttachObj = m_AttachObjRem.upper_bound(idAttachObj); itAttachObj != endAttachObj; ++itAttachObj) + { + if (idRlvObj == itAttachObj->second) + { + m_AttachObjRem.erase(itAttachObj); + updateLockedHUD(); + break; + } + } +} + +// Checked: 2010-02-28 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a +void RlvAttachmentLocks::removeAttachmentPointLock(S32 idxAttachPt, const LLUUID& idRlvObj, ERlvLockMask eLock) +{ +/* + // Sanity check - make sure it's an object we know about + if ( (m_Objects.find(idRlvObj) == m_Objects.end()) || (!idxAttachPt) ) + return; // If (idxAttachPt) == 0 then: (pObj == NULL) || (pObj->isAttachment() == FALSE) +*/ + + if (eLock & RLV_LOCK_REMOVE) + { + RLV_ASSERT( m_AttachPtRem.lower_bound(idxAttachPt) != m_AttachPtRem.upper_bound(idxAttachPt) ); // The lock should always exist + for (rlv_attachptlock_map_t::iterator itAttachPt = m_AttachPtRem.lower_bound(idxAttachPt), + endAttachPt = m_AttachPtRem.upper_bound(idxAttachPt); itAttachPt != endAttachPt; ++itAttachPt) + { + if (idRlvObj == itAttachPt->second) + { + m_AttachPtRem.erase(itAttachPt); + updateLockedHUD(); + break; + } + } + } + if (eLock & RLV_LOCK_ADD) + { + RLV_ASSERT( m_AttachPtAdd.lower_bound(idxAttachPt) != m_AttachPtAdd.upper_bound(idxAttachPt) ); // The lock should always exist + for (rlv_attachptlock_map_t::iterator itAttachPt = m_AttachPtAdd.lower_bound(idxAttachPt), + endAttachPt = m_AttachPtAdd.upper_bound(idxAttachPt); itAttachPt != endAttachPt; ++itAttachPt) + { + if (idRlvObj == itAttachPt->second) + { + m_AttachPtAdd.erase(itAttachPt); + break; + } + } + } +} + +// Checked: 2010-08-22 (RLVa-1.2.1a) | Modified: RLVa-1.2.1a +void RlvAttachmentLocks::updateLockedHUD() +{ + if (!isAgentAvatarValid()) + return; + + m_fHasLockedHUD = false; + for (LLVOAvatar::attachment_map_t::const_iterator itAttachPt = gAgentAvatarp->mAttachmentPoints.begin(); + itAttachPt != gAgentAvatarp->mAttachmentPoints.end(); ++itAttachPt) + { + const LLViewerJointAttachment* pAttachPt = itAttachPt->second; + if ( (pAttachPt) && (pAttachPt->getIsHUDAttachment()) && (hasLockedAttachment(pAttachPt)) ) + { + m_fHasLockedHUD = true; + break; + } + } + + // Reset HUD visibility and wireframe options if at least one HUD attachment is locked + if (m_fHasLockedHUD) + { + set_use_wireframe(false); + } +} + +// Checked: 2010-03-11 (RLVa-1.2.0a) | Added: RLVa-1.2.0a +bool RlvAttachmentLocks::verifyAttachmentLocks() +{ + bool fSuccess = true; + + // Verify attachment locks + rlv_attachobjlock_map_t::iterator itAttachObj = m_AttachObjRem.begin(), itCurrentObj; + while (itAttachObj != m_AttachObjRem.end()) + { + itCurrentObj = itAttachObj++; + + // If the attachment no longer exists (or is no longer attached) then we shouldn't be holding a lock to it + const LLViewerObject* pAttachObj = gObjectList.findObject(itCurrentObj->first); + if ( (!pAttachObj) || (!pAttachObj->isAttachment()) ) + { + m_AttachObjRem.erase(itCurrentObj); + fSuccess = false; + } + } + + return fSuccess; +} + +// ============================================================================ +// RlvAttachmentLockWatchdog member functions +// + +// Checked: 2010-09-23 (RLVa-1.2.1d) | Added: RLVa-1.2.1d +bool RlvAttachmentLockWatchdog::RlvWearInfo::isAddLockedAttachPt(S32 idxAttachPt) const +{ + // If idxAttachPt has no entry in attachPts then the attachment point wasn't RLV_LOCK_ADD restricted at the time we were instantiated + // [See RlvAttachmentLockWatchdog::onWearAttachment()] + return (attachPts.find(idxAttachPt) != attachPts.end()); +} + +// Checked: 2010-09-23 (RLVa-1.2.1d) | Added: RLVa-1.2.1d +void RlvAttachmentLockWatchdog::RlvWearInfo::dumpInstance() const +{ + const LLViewerInventoryItem* pItem = gInventory.getItem(idItem); + std::string strItemId = idItem.asString(); + + std::string strTemp = llformat("Wear %s '%s' (%s)", + (RLV_WEAR_ADD == eWearAction) ? "add" : "replace", (pItem) ? pItem->getName().c_str() : "missing", strItemId.c_str()); + RLV_INFOS << strTemp.c_str() << RLV_ENDL; + + if (!attachPts.empty()) + { + std::string strEmptyAttachPt; + for (std::map<S32, uuid_vec_t>::const_iterator itAttachPt = attachPts.begin(); itAttachPt != attachPts.end(); ++itAttachPt) + { + const LLViewerJointAttachment* pAttachPt = + get_if_there(gAgentAvatarp->mAttachmentPoints, itAttachPt->first, (LLViewerJointAttachment*)NULL); + if (!itAttachPt->second.empty()) + { + for (uuid_vec_t::const_iterator itAttach = itAttachPt->second.begin(); itAttach != itAttachPt->second.end(); ++itAttach) + { + pItem = gInventory.getItem(*itAttach); + strItemId = (*itAttach).asString(); + + strTemp = llformat(" -> %s : %s (%s)", + pAttachPt->getName().c_str(), (pItem) ? pItem->getName().c_str() : "missing", strItemId.c_str()); + RLV_INFOS << strTemp.c_str() << RLV_ENDL; + } + } + else + { + if (!strEmptyAttachPt.empty()) + strEmptyAttachPt += ", "; + strEmptyAttachPt += pAttachPt->getName(); + } + } + if (!strEmptyAttachPt.empty()) + RLV_INFOS << " -> " << strEmptyAttachPt << " : empty" << RLV_ENDL; + } + else + { + RLV_INFOS << " -> no attachment point information" << RLV_ENDL; + } +} + +// Checked: 2010-07-28 (RLVa-1.2.0i) | Modified: RLVa-1.2.0i +void RlvAttachmentLockWatchdog::detach(const LLViewerObject* pAttachObj) +{ + if (pAttachObj) + { + 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, pAttachObj->getLocalID()); + if (std::find(m_PendingDetach.begin(), m_PendingDetach.end(), pAttachObj->getAttachmentItemID()) == m_PendingDetach.end()) + m_PendingDetach.push_back(pAttachObj->getAttachmentItemID()); + + gMessageSystem->sendReliable(gAgent.getRegionHost() ); + } +} + +// Checked: 2011-06-13 (RLVa-1.3.1b) | Modified: RLVa-1.3.1b +void RlvAttachmentLockWatchdog::detach(S32 idxAttachPt, const uuid_vec_t& idsAttachObjExcept) +{ + const LLViewerJointAttachment* pAttachPt = RlvAttachPtLookup::getAttachPoint(idxAttachPt); + if (!pAttachPt) + return; + + std::vector<const LLViewerObject*> attachObjs; + for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator itAttachObj = pAttachPt->mAttachedObjects.begin(); + itAttachObj != pAttachPt->mAttachedObjects.end(); ++itAttachObj) + { + const LLViewerObject* pAttachObj = *itAttachObj; + if (idsAttachObjExcept.end() == std::find(idsAttachObjExcept.begin(), idsAttachObjExcept.end(), pAttachObj->getID())) + attachObjs.push_back(pAttachObj); + } + + if (!attachObjs.empty()) + { + gMessageSystem->newMessage("ObjectDetach"); + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + + for (std::vector<const LLViewerObject*>::const_iterator itAttachObj = attachObjs.begin(); itAttachObj != attachObjs.end(); ++itAttachObj) + { + const LLViewerObject* pAttachObj = *itAttachObj; + gMessageSystem->nextBlockFast(_PREHASH_ObjectData); + gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, pAttachObj->getLocalID()); + if (m_PendingDetach.end() == std::find(m_PendingDetach.begin(), m_PendingDetach.end(), pAttachObj->getAttachmentItemID())) + m_PendingDetach.push_back(pAttachObj->getAttachmentItemID()); + } + + gMessageSystem->sendReliable(gAgent.getRegionHost()); + } +} + +// Checked: 2010-09-23 (RLVa-1.2.1d) | Modified: RLVa-1.2.1d +void RlvAttachmentLockWatchdog::onAttach(const LLViewerObject* pAttachObj, const LLViewerJointAttachment* pAttachPt) +{ + S32 idxAttachPt = RlvAttachPtLookup::getAttachPointIndex(pAttachObj); + const LLUUID& idAttachItem = (pAttachObj) ? pAttachObj->getAttachmentItemID() : LLUUID::null; + RLV_ASSERT( (!isAgentAvatarValid()) || ((idxAttachPt) && (idAttachItem.notNull())) ); + if ( (!idxAttachPt) || (idAttachItem.isNull()) ) + return; + + // Check if the attachment point has a pending "reattach" + rlv_attach_map_t::iterator itAttach = m_PendingAttach.lower_bound(idxAttachPt), itAttachEnd = m_PendingAttach.upper_bound(idxAttachPt); + if (itAttach != itAttachEnd) + { + bool fPendingReattach = false; + for (; itAttach != itAttachEnd; ++itAttach) + { + if (idAttachItem == itAttach->second.idItem) + { + fPendingReattach = true; + RlvBehaviourNotifyHandler::onReattach(pAttachPt, true); + m_PendingAttach.erase(itAttach); + break; + } + } + if (!fPendingReattach) + { + detach(pAttachObj); + RlvBehaviourNotifyHandler::onAttach(pAttachPt, false); + } + return; + } + + // Check if the attach was allowed at the time it was requested + rlv_wear_map_t::iterator itWear = m_PendingWear.find(idAttachItem); bool fAttachAllowed = true; + if (itWear != m_PendingWear.end()) + { + // We'll need to return the attachment point to its previous state if it was non-attachable + if (itWear->second.isAddLockedAttachPt(idxAttachPt)) + { + // Get the saved state of the attachment point (but do nothing if the item itself was already worn then) + std::map<S32, uuid_vec_t>::iterator itAttachPrev = itWear->second.attachPts.find(idxAttachPt); + RLV_ASSERT(itAttachPrev != itWear->second.attachPts.end()); + if (std::find(itAttachPrev->second.begin(), itAttachPrev->second.end(), idAttachItem) == itAttachPrev->second.end()) + { + // If it was empty we need to detach everything on the attachment point; if it wasn't we need to restore it to what it was + if (itAttachPrev->second.empty()) + { + detach(idxAttachPt); + } + else + { + // Iterate over all the current attachments and force detach any that shouldn't be there + for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator itAttachObj = pAttachPt->mAttachedObjects.begin(); + itAttachObj != pAttachPt->mAttachedObjects.end(); ++itAttachObj) + { + const LLViewerObject* pAttachObj = *itAttachObj; + + uuid_vec_t::iterator itAttach = + std::find(itAttachPrev->second.begin(), itAttachPrev->second.end(), pAttachObj->getAttachmentItemID()); + if (itAttach == itAttachPrev->second.end()) + detach(pAttachObj); + else + itAttachPrev->second.erase(itAttach); + } + + // Whatever is left is something that needs to be reattached + for (uuid_vec_t::const_iterator itAttach = itAttachPrev->second.begin(); + itAttach != itAttachPrev->second.end(); ++itAttach) + { + m_PendingAttach.insert(std::pair<S32, RlvReattachInfo>(idxAttachPt, RlvReattachInfo(*itAttach))); + } + } + fAttachAllowed = false; + } + } + else if (RLV_WEAR_REPLACE == itWear->second.eWearAction) + { + // Now that we know where this attaches to, check if we can actually perform a "replace" + uuid_vec_t idsAttachObjExcept; + for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator itAttachObj = pAttachPt->mAttachedObjects.begin(); + ((itAttachObj != pAttachPt->mAttachedObjects.end()) && (fAttachAllowed)); ++itAttachObj) + { + if ( (pAttachObj != *itAttachObj) && (gRlvAttachmentLocks.isLockedAttachment(*itAttachObj)) ) + { + // Fail if we encounter a non-detachable attachment (unless we're only replacing detachable attachments) + if (gSavedSettings.getBOOL("RLVaWearReplaceUnlocked")) + idsAttachObjExcept.push_back((*itAttachObj)->getID()); + else + fAttachAllowed = false; + } + } + + if (fAttachAllowed) + { + idsAttachObjExcept.push_back(pAttachObj->getID()); // Replace == allowed: detach everything except the new attachment + detach(idxAttachPt, idsAttachObjExcept); // or detach all *unlocked* attachments except the new attachment + } + else + { + detach(pAttachObj); // Replace != allowed: detach the new attachment + } + } + m_PendingWear.erase(itWear); // No need to start the timer since it should be running already if '!m_PendingWear.empty()' + } + RlvBehaviourNotifyHandler::onAttach(pAttachPt, fAttachAllowed); +} + +// Checked: 2010-07-28 (RLVa-1.2.0i) | Modified: RLVa-1.2.0i +void RlvAttachmentLockWatchdog::onDetach(const LLViewerObject* pAttachObj, const LLViewerJointAttachment* pAttachPt) +{ + S32 idxAttachPt = RlvAttachPtLookup::getAttachPointIndex(pAttachPt); + const LLUUID& idAttachItem = (pAttachObj) ? pAttachObj->getAttachmentItemID() : LLUUID::null; + RLV_ASSERT( (!isAgentAvatarValid()) || ((idxAttachPt) && (idAttachItem.notNull())) ); + if ( (!idxAttachPt) || (idAttachItem.isNull()) ) + return; + + // If it's an attachment that's pending force-detach then we don't want to do anything (even if it's currently "remove locked") + rlv_detach_map_t::iterator itDetach = std::find(m_PendingDetach.begin(), m_PendingDetach.end(), idAttachItem); + if (itDetach != m_PendingDetach.end()) + { + m_PendingDetach.erase(itDetach); + RlvBehaviourNotifyHandler::onDetach(pAttachPt, true); + return; + } + + // If the attachment is currently "remove locked" then we should reattach it (unless it's already pending reattach) + bool fDetachAllowed = true; + if (gRlvAttachmentLocks.isLockedAttachment(pAttachObj)) + { + bool fPendingAttach = false; + for (rlv_attach_map_t::const_iterator itReattach = m_PendingAttach.lower_bound(idxAttachPt), + itReattachEnd = m_PendingAttach.upper_bound(idxAttachPt); itReattach != itReattachEnd; ++itReattach) + { + if (itReattach->second.idItem == idAttachItem) + { + fPendingAttach = true; + break; + } + } + + // TODO-RLVa: [RLVa-1.2.1] we should re-add the item to COF as well to make sure it'll reattach when the user relogs + // -> check the call order in LLVOAvatarSelf::detachObject() since COF removal happens *after* we're called + if (!fPendingAttach) + { + m_PendingAttach.insert(std::pair<S32, RlvReattachInfo>(idxAttachPt, RlvReattachInfo(idAttachItem))); + startTimer(); + } + fDetachAllowed = false; + } + RlvBehaviourNotifyHandler::onDetach(pAttachPt, fDetachAllowed); +} + +// Checked: 2010-03-05 (RLVa-1.2.0a) | Modified: RLVa-1.0.5b +void RlvAttachmentLockWatchdog::onSavedAssetIntoInventory(const LLUUID& idItem) +{ + for (rlv_attach_map_t::iterator itAttach = m_PendingAttach.begin(); itAttach != m_PendingAttach.end(); ++itAttach) + { + if ( (!itAttach->second.fAssetSaved) && (idItem == itAttach->second.idItem) ) + { + LLAttachmentsMgr::instance().addAttachmentRequest(itAttach->second.idItem, itAttach->first, true, true); + itAttach->second.tsAttach = LLFrameTimer::getElapsedSeconds(); + } + } +} + +// Checked: 2010-03-05 (RLVa-1.2.0a) | Modified: RLVa-1.0.5b +BOOL RlvAttachmentLockWatchdog::onTimer() +{ + // RELEASE-RLVa: [SL-2.0.0] This will need rewriting for "ENABLE_MULTIATTACHMENTS" + F64 tsCurrent = LLFrameTimer::getElapsedSeconds(); + + // Garbage collect (failed) wear requests older than 60 seconds + rlv_wear_map_t::iterator itWear = m_PendingWear.begin(); + while (itWear != m_PendingWear.end()) + { + if (itWear->second.tsWear + 60 < tsCurrent) + m_PendingWear.erase(itWear++); + else + ++itWear; + } + + // Walk over the pending reattach list + rlv_attach_map_t::iterator itAttach = m_PendingAttach.begin(); + while (itAttach != m_PendingAttach.end()) + { + // Sanity check - make sure the item is still in the user's inventory + if (gInventory.getItem(itAttach->second.idItem) == NULL) + { + m_PendingAttach.erase(itAttach++); + continue; + } + + // Force an attach if we haven't gotten a SavedAssetIntoInventory message after 15 seconds + // (or if it's been 30 seconds since we last tried to reattach the item) + bool fAttach = false; + if ( (!itAttach->second.fAssetSaved) && (itAttach->second.tsDetach + 15 < tsCurrent) ) + { + itAttach->second.fAssetSaved = true; + fAttach = true; + } + else if ( (itAttach->second.fAssetSaved) && (itAttach->second.tsAttach + 30 < tsCurrent) ) + { + fAttach = true; + } + + if (fAttach) + { + LLAttachmentsMgr::instance().addAttachmentRequest(itAttach->second.idItem, itAttach->first, true, true); + itAttach->second.tsAttach = tsCurrent; + } + + ++itAttach; + } + + return ( (m_PendingAttach.empty()) && (m_PendingDetach.empty()) && (m_PendingWear.empty()) ); +} + +// Checked: 2010-07-28 (RLVa-1.2.0i) | Modified: RLVa-1.2.0i +void RlvAttachmentLockWatchdog::onWearAttachment(const LLUUID& idItem, ERlvWearMask eWearAction) +{ + // We only need to keep track of user wears if there's actually anything locked + RLV_ASSERT(idItem.notNull()); + if ( (idItem.isNull()) || (!isAgentAvatarValid()) || (!gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) ) + return; + + // If the attachment point this will end up being attached to is: + // - unlocked : nothing should happen (from RLVa's point of view) + // - RLV_LOCK_ADD: the new attachment should get detached and the current one(s) reattached (unless it's currently empty) + // - RLV_LOCK_REM: + // o eWearAction == RLV_WEAR_ADD : nothing should happen (from RLVa's point of view) + // o eWearAction == RLV_WEAR_REPLACE : examine whether the new attachment can indeed replace/detach the old one + RlvWearInfo infoWear(idItem, eWearAction); + RLV_ASSERT( (RLV_WEAR_ADD == eWearAction) || (RLV_WEAR_REPLACE == eWearAction) ); // One of the two, but never both + for (LLVOAvatar::attachment_map_t::const_iterator itAttachPt = gAgentAvatarp->mAttachmentPoints.begin(); + itAttachPt != gAgentAvatarp->mAttachmentPoints.end(); ++itAttachPt) + { + const LLViewerJointAttachment* pAttachPt = itAttachPt->second; + // We only need to know which attachments were present for RLV_LOCK_ADD locked attachment points (and not RLV_LOCK_REM locked ones) + if (gRlvAttachmentLocks.isLockedAttachmentPoint(pAttachPt, RLV_LOCK_ADD)) + { + uuid_vec_t attachObjs; + for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator itAttachObj = pAttachPt->mAttachedObjects.begin(); + itAttachObj != pAttachPt->mAttachedObjects.end(); ++itAttachObj) + { + const LLViewerObject* pAttachObj = *itAttachObj; + if (std::find(m_PendingDetach.begin(), m_PendingDetach.end(), pAttachObj->getAttachmentItemID()) != m_PendingDetach.end()) + continue; // Exclude attachments that are pending a force-detach + attachObjs.push_back(pAttachObj->getAttachmentItemID()); + } + infoWear.attachPts.insert(std::pair<S32, uuid_vec_t>(itAttachPt->first, attachObjs)); + } + } + + m_PendingWear.insert(std::pair<LLUUID, RlvWearInfo>(idItem, infoWear)); +#ifdef RLV_DEBUG + infoWear.dumpInstance(); +#endif // RLV_RELEASE + startTimer(); +} + +// ============================================================================ +// RlvWearableLocks member functions +// + +RlvWearableLocks gRlvWearableLocks; + +// Checked: 2010-03-18 (RLVa-1.2.0c) | Added: RLVa-1.2.0a +void RlvWearableLocks::addWearableTypeLock(LLWearableType::EType eType, const LLUUID& idRlvObj, ERlvLockMask eLock) +{ +/* + // Sanity check - make sure it's an object we know about + if ( (m_Objects.find(idRlvObj) == m_Objects.end()) || (!idxAttachPt) ) + return; // If (idxAttachPt) == 0 then: (pObj == NULL) || (pObj->isAttachment() == FALSE) +*/ + + // NOTE: m_WearableTypeXXX can contain duplicate <eType, idRlvObj> pairs (ie @remoutfit:shirt=n,remoutfit=n from the same object) + if (eLock & RLV_LOCK_REMOVE) + m_WearableTypeRem.insert(std::pair<LLWearableType::EType, LLUUID>(eType, idRlvObj)); + if (eLock & RLV_LOCK_ADD) + m_WearableTypeAdd.insert(std::pair<LLWearableType::EType, LLUUID>(eType, idRlvObj)); +} + +// Checked: 2010-03-19 (RLVa-1.2.0c) | Added: RLVa-1.2.0a +bool RlvWearableLocks::canRemove(LLWearableType::EType eType) const +{ + // NOTE: we return TRUE if the wearable type has at least one wearable that can be removed by the user + for (U32 idxWearable = 0, cntWearable = gAgentWearables.getWearableCount(eType); idxWearable < cntWearable; idxWearable++) + if (!isLockedWearable(gAgentWearables.getViewerWearable(eType, idxWearable))) + return true; + return false; +} + +// Checked: 2010-03-19 (RLVa-1.2.0c) | Added: RLVa-1.2.0a +bool RlvWearableLocks::hasLockedWearable(LLWearableType::EType eType) const +{ + // NOTE: we return TRUE if there is at least 1 non-removable wearable currently worn on this wearable type + for (U32 idxWearable = 0, cntWearable = gAgentWearables.getWearableCount(eType); idxWearable < cntWearable; idxWearable++) + if (isLockedWearable(gAgentWearables.getViewerWearable(eType, idxWearable))) + return true; + return false; +} + +// Checked: 2010-03-19 (RLVa-1.2.0a) | Added: RLVa-1.2.0a +bool RlvWearableLocks::isLockedWearableExcept(const LLViewerWearable* pWearable, const LLUUID& idRlvObj) const +{ + if (idRlvObj.isNull()) + return isLockedWearable(pWearable); + + // TODO-RLVa: [RLVa-1.2.1] We don't have the ability to lock a specific wearable yet so rewrite this when we do + return (pWearable) && (isLockedWearableTypeExcept(pWearable->getType(), RLV_LOCK_REMOVE, idRlvObj)); +} + +// Checked: 2010-03-19 (RLVa-1.2.0a) | Added: RLVa-1.2.0a +bool RlvWearableLocks::isLockedWearableTypeExcept(LLWearableType::EType eType, ERlvLockMask eLock, const LLUUID& idRlvObj) const +{ + if (idRlvObj.isNull()) + return isLockedWearableType(eType, eLock); + + // Loop over every object that marked the specified wearable type eLock type locked and skip over anything owned by idRlvObj + if (eLock & RLV_LOCK_REMOVE) + { + for (rlv_wearabletypelock_map_t::const_iterator itWearableType = m_WearableTypeRem.lower_bound(eType), + endWearableType = m_WearableTypeRem.upper_bound(eType); itWearableType != endWearableType; ++itWearableType) + { + if (itWearableType->second != idRlvObj) + return true; + } + } + if (eLock & RLV_LOCK_ADD) + { + for (rlv_wearabletypelock_map_t::const_iterator itWearableType = m_WearableTypeAdd.lower_bound(eType), + endWearableType = m_WearableTypeAdd.upper_bound(eType); itWearableType != endWearableType; ++itWearableType) + { + if (itWearableType->second != idRlvObj) + return true; + } + } + return false; +} + +// Checked: 2010-03-18 (RLVa-1.2.0c) | Added: RLVa-1.2.0a +void RlvWearableLocks::removeWearableTypeLock(LLWearableType::EType eType, const LLUUID& idRlvObj, ERlvLockMask eLock) +{ +/* + // Sanity check - make sure it's an object we know about + if ( (m_Objects.find(idRlvObj) == m_Objects.end()) || (!idxAttachPt) ) + return; // If (idxAttachPt) == 0 then: (pObj == NULL) || (pObj->isAttachment() == FALSE) +*/ + + if (eLock & RLV_LOCK_REMOVE) + { + RLV_ASSERT( m_WearableTypeRem.lower_bound(eType) != m_WearableTypeRem.upper_bound(eType) ); // The lock should always exist + for (rlv_wearabletypelock_map_t::iterator itWearableType = m_WearableTypeRem.lower_bound(eType), + endWearableType = m_WearableTypeRem.upper_bound(eType); itWearableType != endWearableType; ++itWearableType) + { + if (idRlvObj == itWearableType->second) + { + m_WearableTypeRem.erase(itWearableType); + break; + } + } + } + if (eLock & RLV_LOCK_ADD) + { + RLV_ASSERT( m_WearableTypeAdd.lower_bound(eType) != m_WearableTypeAdd.upper_bound(eType) ); // The lock should always exist + for (rlv_wearabletypelock_map_t::iterator itWearableType = m_WearableTypeAdd.lower_bound(eType), + endWearableType = m_WearableTypeAdd.upper_bound(eType); itWearableType != endWearableType; ++itWearableType) + { + if (idRlvObj == itWearableType->second) + { + m_WearableTypeAdd.erase(itWearableType); + break; + } + } + } +} + +// ============================================================================ +// RlvFolderLocks member functions +// + +class RlvLockedDescendentsCollector : public LLInventoryCollectFunctor +{ +public: + RlvLockedDescendentsCollector(int eSourceTypeMask, RlvFolderLocks::ELockPermission ePermMask, ERlvLockMask eLockTypeMask) + : m_eSourceTypeMask(eSourceTypeMask), m_ePermMask(ePermMask), m_eLockTypeMask(eLockTypeMask) {} + /*virtual*/ ~RlvLockedDescendentsCollector() {} + /*virtual*/ bool operator()(LLInventoryCategory* pFolder, LLInventoryItem* pItem) + { + return (pFolder) && (RlvFolderLocks::instance().isLockedFolderEntry(pFolder->getUUID(), m_eSourceTypeMask, m_ePermMask, m_eLockTypeMask)); + } +protected: + RlvFolderLocks::ELockPermission m_ePermMask; + int m_eSourceTypeMask; + ERlvLockMask m_eLockTypeMask; +}; + +// Checked: 2011-03-28 (RLVa-1.3.0g) | Modified: RLVa-1.3.0g +RlvFolderLocks::RlvFolderLocks() + : m_fLookupDirty(false), m_RootLockType(RLV_LOCK_NONE), m_cntLockAdd(0), m_cntLockRem(0) +{ + LLOutfitObserver::instance().addCOFChangedCallback(boost::bind(&RlvFolderLocks::onNeedsLookupRefresh, this)); + RlvInventory::instance().addSharedRootIDChangedCallback(boost::bind(&RlvFolderLocks::onNeedsLookupRefresh, this)); +} + +// Checked: 2011-03-27 (RLVa-1.3.0g) | Modified: RLVa-1.3.0g +void RlvFolderLocks::addFolderLock(const folderlock_source_t& lockSource, ELockPermission ePerm, ELockScope eScope, + const LLUUID& idRlvObj, ERlvLockMask eLockType) +{ + // Sanity check - eLockType can be RLV_LOCK_ADD or RLV_LOCK_REMOVE but not both + RLV_ASSERT( (RLV_LOCK_ADD == eLockType) || (RLV_LOCK_REMOVE == eLockType) ); + + // NOTE: m_FolderXXX can contain duplicate folderlock_descr_t + m_FolderLocks.push_back(new folderlock_descr_t(idRlvObj, eLockType, lockSource, ePerm, eScope)); + + if (PERM_DENY == ePerm) + { + if (RLV_LOCK_REMOVE == eLockType) + m_cntLockRem++; + else if (RLV_LOCK_ADD == eLockType) + m_cntLockAdd++; + } + + if (!m_AttachmentChangeConnection.connected()) + m_AttachmentChangeConnection = gAgentAvatarp->setAttachmentCallback(boost::bind(&RlvFolderLocks::onNeedsLookupRefresh, this)); + m_fLookupDirty = true; +} + +// Checked: 2011-03-28 (RLVa-1.3.0g) | Modified: RLVa-1.3.0g +bool RlvFolderLocks::getLockedFolders(const folderlock_source_t& lockSource, LLInventoryModel::cat_array_t& lockFolders) const +{ + S32 cntFolders = lockFolders.size(); + switch (lockSource.first) + { + case ST_ATTACHMENT: + { + RLV_ASSERT(typeid(LLUUID) == lockSource.second.type()) + const LLViewerObject* pObj = gObjectList.findObject(boost::get<LLUUID>(lockSource.second)); + if ( (pObj) && (pObj->isAttachment()) ) + { + const LLViewerInventoryItem* pItem = gInventory.getItem(pObj->getAttachmentItemID()); + if ( (pItem) && (RlvInventory::instance().isSharedFolder(pItem->getParentUUID())) ) + { + LLViewerInventoryCategory* pItemFolder = gInventory.getCategory(pItem->getParentUUID()); + if (pItemFolder) + lockFolders.push_back(pItemFolder); + } + } + } + break; + case ST_FOLDER: + { + RLV_ASSERT(typeid(LLUUID) == lockSource.second.type()) + LLViewerInventoryCategory* pFolder = gInventory.getCategory(boost::get<LLUUID>(lockSource.second)); + if (pFolder) + lockFolders.push_back(pFolder); + } + break; + case ST_ROOTFOLDER: + { + LLViewerInventoryCategory* pFolder = gInventory.getCategory(gInventory.getRootFolderID()); + if (pFolder) + lockFolders.push_back(pFolder); + } + break; + case ST_SHAREDPATH: + { + RLV_ASSERT(typeid(std::string) == lockSource.second.type()) + LLViewerInventoryCategory* pSharedFolder = RlvInventory::instance().getSharedFolder(boost::get<std::string>(lockSource.second)); + if (pSharedFolder) + lockFolders.push_back(pSharedFolder); + } + break; + case ST_ATTACHMENTPOINT: + case ST_WEARABLETYPE: + { + RLV_ASSERT( ((ST_ATTACHMENTPOINT == lockSource.first) && (typeid(S32) == lockSource.second.type())) || + ((ST_WEARABLETYPE == lockSource.first) && (typeid(LLWearableType::EType) == lockSource.second.type())) ); + + uuid_vec_t idItems; + if (ST_ATTACHMENTPOINT == lockSource.first) + RlvCommandOptionGetPath::getItemIDs(RlvAttachPtLookup::getAttachPoint(boost::get<S32>(lockSource.second)), idItems); + else if (ST_WEARABLETYPE == lockSource.first) + RlvCommandOptionGetPath::getItemIDs(boost::get<LLWearableType::EType>(lockSource.second), idItems); + + LLInventoryModel::cat_array_t itemFolders; + if (RlvInventory::instance().getPath(idItems, itemFolders)) + lockFolders.insert(lockFolders.end(), itemFolders.begin(), itemFolders.end()); + } + break; + default: + return false; + }; + return cntFolders != lockFolders.size(); +} + +// Checked: 2011-11-26 (RLVa-1.5.4a) | Modified: RLVa-1.5.4a +bool RlvFolderLocks::getLockedItems(const LLUUID& idFolder, LLInventoryModel::item_array_t& lockItems) const +{ + S32 cntItems = lockItems.size(); + + LLInventoryModel::cat_array_t folders; LLInventoryModel::item_array_t items; + LLFindWearablesEx f(true, true); // Collect all worn items + gInventory.collectDescendentsIf(idFolder, folders, items, FALSE, f); + + // Generally several of the worn items will belong to the same folder so we'll cache the results of each lookup + std::map<LLUUID, bool> folderLookups; std::map<LLUUID, bool>::const_iterator itLookup; + + bool fItemLocked = false; + for (S32 idxItem = 0, cntItem = items.size(); idxItem < cntItem; idxItem++) + { + LLViewerInventoryItem* pItem = items.at(idxItem); + if (LLAssetType::AT_LINK == pItem->getActualType()) + pItem = pItem->getLinkedItem(); + if (!pItem) + continue; + + // Check the actual item's parent folder + const LLUUID& idItemParent = RlvInventory::getFoldedParent(pItem->getParentUUID(), true); + if ((itLookup = folderLookups.find(idItemParent)) != folderLookups.end()) + { + fItemLocked = itLookup->second; + } + else + { + fItemLocked = isLockedFolder(idItemParent, RLV_LOCK_REMOVE); + folderLookups.insert(std::pair<LLUUID, bool>(idItemParent, fItemLocked)); + } + + // Check the parent folders of any links to this item that exist under #RLV + if (!fItemLocked) + { + LLInventoryModel::item_array_t itemLinks; + LLInventoryModel::cat_array_t cats; + LLLinkedItemIDMatches f(pItem->getUUID()); + gInventory.collectDescendentsIf(RlvInventory::instance().getSharedRootID(), cats, itemLinks, LLInventoryModel::EXCLUDE_TRASH, f); + + for (LLInventoryModel::item_array_t::iterator itItemLink = itemLinks.begin(); + (itItemLink < itemLinks.end()) && (!fItemLocked); ++itItemLink) + { + LLViewerInventoryItem* pItemLink = *itItemLink; + + const LLUUID& idItemLinkParent = (pItemLink) ? RlvInventory::getFoldedParent(pItemLink->getParentUUID(), true) : LLUUID::null; + if ((itLookup = folderLookups.find(idItemLinkParent)) != folderLookups.end()) + { + fItemLocked = itLookup->second; + } + else + { + fItemLocked = isLockedFolder(idItemLinkParent, RLV_LOCK_REMOVE); + folderLookups.insert(std::pair<LLUUID, bool>(idItemLinkParent, fItemLocked)); + } + } + } + + if (fItemLocked) + lockItems.push_back(pItem); + } + + return cntItems != lockItems.size(); +} + +// Checked: 2011-03-29 (RLVa-1.3.0g) | Added: RLVa-1.3.0g +bool RlvFolderLocks::hasLockedFolderDescendent(const LLUUID& idFolder, int eSourceTypeMask, ELockPermission ePermMask, + ERlvLockMask eLockTypeMask, bool fCheckSelf) const +{ + if (!hasLockedFolder(eLockTypeMask)) + return false; + if (m_fLookupDirty) + refreshLockedLookups(); + if ( (fCheckSelf) && (isLockedFolderEntry(idFolder, eSourceTypeMask, ePermMask, RLV_LOCK_ANY)) ) + return true; + + LLInventoryModel::cat_array_t folders; LLInventoryModel::item_array_t items; + RlvLockedDescendentsCollector f(eSourceTypeMask, ePermMask, eLockTypeMask); + gInventory.collectDescendentsIf(idFolder, folders, items, FALSE, f, false); + return !folders.empty(); +} + +// Checked: 2011-03-29 (RLVa-1.3.0g) | Added: RLVa-1.3.0g +bool RlvFolderLocks::isLockedFolderEntry(const LLUUID& idFolder, int eSourceTypeMask, ELockPermission ePermMask, ERlvLockMask eLockTypeMask) const +{ + for (folderlock_map_t::const_iterator itFolderLock = m_LockedFolderMap.lower_bound(idFolder), + endFolderLock = m_LockedFolderMap.upper_bound(idFolder); itFolderLock != endFolderLock; ++itFolderLock) + { + const folderlock_descr_t* pLockDescr = itFolderLock->second; + if ( (pLockDescr->lockSource.first & eSourceTypeMask) && (pLockDescr->eLockPermission & ePermMask) && + (pLockDescr->eLockType & eLockTypeMask) ) + { + return true; + } + } + return false; +} + +// Checked: 2011-03-27 (RLVa-1.3.0g) | Modified: RLVa-1.3.0g +bool RlvFolderLocks::isLockedFolder(LLUUID idFolder, ERlvLockMask eLockTypeMask, int eSourceTypeMask, folderlock_source_t* plockSource) const +{ + // Sanity check - if there are no folder locks then we don't have to actually do anything + if (!hasLockedFolder(eLockTypeMask)) + return false; + + // Folded folders will be locked if their "parent" is locked + idFolder = RlvInventory::getFoldedParent(idFolder, true); + if (idFolder.isNull()) + return false; + + if (m_fLookupDirty) + refreshLockedLookups(); + + // Walk up the folder tree and check if anything has 'idFolder' locked + std::list<LLUUID> idsRlvObjRem, idsRlvObjAdd; const LLUUID& idFolderRoot = gInventory.getRootFolderID(); LLUUID idFolderCur = idFolder; + while (idFolderRoot != idFolderCur) + { + // Iterate over any folder locks for 'idFolderCur' + for (folderlock_map_t::const_iterator itFolderLock = m_LockedFolderMap.lower_bound(idFolderCur), + endFolderLock = m_LockedFolderMap.upper_bound(idFolderCur); itFolderLock != endFolderLock; ++itFolderLock) + { + const folderlock_descr_t* pLockDescr = itFolderLock->second; + + // We can skip over the current lock if: + // - the current lock type doesn't match eLockTypeMask + // - it's a node lock and the current folder doesn't match + // - we encountered a PERM_ALLOW lock from the current lock owner before which supercedes any subsequent locks + // - the lock source type doesn't match the mask passed in eSourceTypeMask + ERlvLockMask eCurLockType = (ERlvLockMask)(pLockDescr->eLockType & eLockTypeMask); + std::list<LLUUID>* pidRlvObjList = (RLV_LOCK_REMOVE == eCurLockType) ? &idsRlvObjRem : &idsRlvObjAdd; + if ( (0 == eCurLockType) || ((SCOPE_NODE == pLockDescr->eLockScope) && (idFolder != idFolderCur)) || + (pidRlvObjList->end() != std::find(pidRlvObjList->begin(), pidRlvObjList->end(), pLockDescr->idRlvObj)) || + (0 == (pLockDescr->eLockType & eSourceTypeMask)) ) + { + continue; + } + + if (PERM_DENY == pLockDescr->eLockPermission) + { + if (plockSource) + *plockSource = pLockDescr->lockSource; + return true; // Folder is explicitly denied, indicate locked folder to our caller + } + else if (PERM_ALLOW == pLockDescr->eLockPermission) + { + pidRlvObjList->push_back(pLockDescr->idRlvObj); // Folder is explicitly allowed, save the owner so we can skip it from now on + } + } + + // Move up to the folder tree + const LLViewerInventoryCategory* pParent = gInventory.getCategory(idFolderCur); + idFolderCur = (pParent) ? pParent->getParentUUID() : idFolderRoot; + } + // If we didn't encounter an explicit deny lock with no exception then the folder is locked if the entire inventory is locked down + return (m_RootLockType & eLockTypeMask) && (eSourceTypeMask & ST_ROOTFOLDER) && (idsRlvObjRem.empty()) && (idsRlvObjAdd.empty()); +} + +// Checked: 2010-11-30 (RLVa-1.3.0b) | Added: RLVa-1.3.0b +void RlvFolderLocks::onNeedsLookupRefresh() +{ + // NOTE: when removeFolderLock() removes the last folder lock we still want to refresh everything so mind the conditional OR assignment + m_fLookupDirty |= !m_FolderLocks.empty(); +} + +// Checked: 2011-03-27 (RLVa-1.3.0g) | Added: RLVa-1.3.0g +void RlvFolderLocks::refreshLockedLookups() const +{ + // + // Refresh locked folders + // + m_RootLockType = RLV_LOCK_NONE; + m_LockedFolderMap.clear(); + for (folderlock_list_t::const_iterator itFolderLock = m_FolderLocks.begin(); itFolderLock != m_FolderLocks.end(); ++itFolderLock) + { + const folderlock_descr_t* pLockDescr = *itFolderLock; + + LLInventoryModel::cat_array_t lockedFolders; const LLUUID& idFolderRoot = gInventory.getRootFolderID(); + if (getLockedFolders(pLockDescr->lockSource, lockedFolders)) + { + for (S32 idxFolder = 0, cntFolder = lockedFolders.size(); idxFolder < cntFolder; idxFolder++) + { + const LLViewerInventoryCategory* pFolder = lockedFolders.at(idxFolder); + if (idFolderRoot != pFolder->getUUID()) + m_LockedFolderMap.insert(std::pair<LLUUID, const folderlock_descr_t*>(pFolder->getUUID(), pLockDescr)); + else if (SCOPE_SUBTREE == pLockDescr->eLockScope) + m_RootLockType |= (U32)pLockDescr->eLockType; + } + } + } + m_fLookupDirty = false; + + // + // Refresh locked items (iterate over COF and filter out any items residing in a RLV_LOCK_REMOVE locked PERM_DENY folder) + // + m_LockedAttachmentRem.clear(); + m_LockedWearableRem.clear(); + + LLInventoryModel::item_array_t lockedItems; + if (getLockedItems(LLAppearanceMgr::instance().getCOF(), lockedItems)) + { + for (S32 idxItem = 0, cntItem = lockedItems.size(); idxItem < cntItem; idxItem++) + { + const LLViewerInventoryItem* pItem = lockedItems.at(idxItem); + switch (pItem->getType()) + { + case LLAssetType::AT_BODYPART: + case LLAssetType::AT_CLOTHING: + m_LockedWearableRem.push_back(pItem->getLinkedUUID()); + break; + case LLAssetType::AT_OBJECT: + m_LockedAttachmentRem.push_back(pItem->getLinkedUUID()); + break; + default: + RLV_ASSERT(true); + break; + } + } + } + + // Remove any duplicate items we may have picked up + std::sort(m_LockedAttachmentRem.begin(), m_LockedAttachmentRem.end()); + m_LockedAttachmentRem.erase(std::unique(m_LockedAttachmentRem.begin(), m_LockedAttachmentRem.end()), m_LockedAttachmentRem.end()); + std::sort(m_LockedWearableRem.begin(), m_LockedWearableRem.end()); + m_LockedWearableRem.erase(std::unique(m_LockedWearableRem.begin(), m_LockedWearableRem.end()), m_LockedWearableRem.end()); +} + +// Checked: 2011-03-27 (RLVa-1.3.0g) | Modified: RLVa-1.3.0g +void RlvFolderLocks::removeFolderLock(const folderlock_source_t& lockSource, ELockPermission ePerm, ELockScope eScope, + const LLUUID& idRlvObj, ERlvLockMask eLockType) +{ + // Sanity check - eLockType can be RLV_LOCK_ADD or RLV_LOCK_REMOVE but not both + RLV_ASSERT( (RLV_LOCK_ADD == eLockType) || (RLV_LOCK_REMOVE == eLockType) ); + + folderlock_descr_t lockDescr(idRlvObj, eLockType, lockSource, ePerm, eScope); RlvPredValuesEqual<folderlock_descr_t> f = { &lockDescr }; + folderlock_list_t::iterator itFolderLock = std::find_if(m_FolderLocks.begin(), m_FolderLocks.end(), f); + RLV_ASSERT( m_FolderLocks.end() != itFolderLock ); // The lock should always exist + if (m_FolderLocks.end() != itFolderLock) + { + delete *itFolderLock; + m_FolderLocks.erase(itFolderLock); + + if (PERM_DENY == ePerm) + { + if (RLV_LOCK_REMOVE == eLockType) + m_cntLockRem--; + else if (RLV_LOCK_ADD == eLockType) + m_cntLockAdd--; + } + m_fLookupDirty = true; + } +} + +// ============================================================================ diff --git a/indra/newview/rlvlocks.h b/indra/newview/rlvlocks.h new file mode 100644 index 0000000000000000000000000000000000000000..61ab0acbb0a802b859dc57fd503b87cc3f5031fe --- /dev/null +++ b/indra/newview/rlvlocks.h @@ -0,0 +1,711 @@ +/** + * + * Copyright (c) 2009-2011, Kitty Barnett + * + * The source code in this file is provided to you under the terms of the + * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt + * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.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. + * + */ + +#ifndef RLV_LOCKS_H +#define RLV_LOCKS_H + +#include "llagentwearables.h" +#include "lleventtimer.h" +#include "llvoavatarself.h" +#include "llviewerwearable.h" + +#include "rlvdefines.h" +#include "rlvcommon.h" + +// ============================================================================ +// RlvAttachPtLookup class declaration +// + +class RlvAttachPtLookup +{ +public: + static LLViewerJointAttachment* getAttachPoint(S32 idxAttachPt); + static LLViewerJointAttachment* getAttachPoint(const std::string& strText); + static LLViewerJointAttachment* getAttachPoint(const LLInventoryItem* pItem); + + static S32 getAttachPointIndex(std::string strText); + static S32 getAttachPointIndex(const LLViewerObject* pAttachObj); + static S32 getAttachPointIndex(const LLViewerJointAttachment* pAttachPt); + static S32 getAttachPointIndex(const LLInventoryCategory* pFolder); + static S32 getAttachPointIndex(const LLInventoryItem* pItem, bool fFollowLinks = true); + + static bool hasAttachPointName(const LLInventoryItem* pItem) { return (0 != getAttachPointIndex(pItem)); } +private: + static S32 getAttachPointIndexLegacy(const LLInventoryCategory* pFolder); + +public: + static void initLookupTable(); +private: + static std::map<std::string, S32> m_AttachPtLookupMap; +}; + +// ============================================================================ +// RlvAttachmentLocks class declaration +// + +// TODO-RLVa: [RLVa-1.2.1] Once everything is working for SL-2.0 thin out the member functions since a few of them are duplicates/unneeded +class RlvAttachmentLocks +{ +public: + RlvAttachmentLocks() : m_fHasLockedHUD(false) {} + +public: + // Adds an RLV_LOCK_REMOVE lock (held by idRlvObj) for the attachment + void addAttachmentLock(const LLUUID& idAttachObj, const LLUUID& idRlvObj); + // Adds an eLock type lock (held by idRlvObj) for the attachment point + void addAttachmentPointLock(S32 idxAttachPt, const LLUUID& idRlvObj, ERlvLockMask eLock); + + // Returns TRUE if there is at least 1 non-detachable attachment currently attached to the attachment point + bool hasLockedAttachment(const LLViewerJointAttachment* pAttachPt) const; + // Returns TRUE if there is at least 1 eLock type locked attachment point (RLV_LOCK_ANY = RLV_LOCK_ADD *or* RLV_LOCK_REMOVE) + // - RLV_LOCK_REMOVE: specific attachment locked *or* any attachment point locked (regardless of whether it currently has attachments) + bool hasLockedAttachmentPoint(ERlvLockMask eLock) const; + // Returns TRUE if there is at least 1 non-detachable HUD attachment + bool hasLockedHUD() const { return m_fHasLockedHUD; } + + // Returns TRUE if the attachment is RLV_LOCK_REMOVE locked + bool isLockedAttachment(const LLViewerObject* pAttachObj) const; + // Returns TRUE if the attachment point is RLV_LOCK_REMOVE locked by anything other than idRlvObj + bool isLockedAttachmentExcept(const LLViewerObject* pObj, const LLUUID& idRlvObj) const; + // Returns TRUE if the attachment point is eLock type locked (RLV_LOCK_ANY = RLV_LOCK_ADD *or* RLV_LOCK_REMOVE) + bool isLockedAttachmentPoint(S32 idxAttachPt, ERlvLockMask eLock) const; + bool isLockedAttachmentPoint(const LLViewerJointAttachment* pAttachPt, ERlvLockMask eLock) const; + + // Removes an RLV_LOCK_REMOVE lock (held by idRlvObj) for the attachment + void removeAttachmentLock(const LLUUID& idAttachObj, const LLUUID& idRlvObj); + // Removes an eLock type lock (held by idRlvObj) for the attachment point + void removeAttachmentPointLock(S32 idxAttachPt, const LLUUID& idRlvObj, ERlvLockMask eLock); + + // Refreshes locked HUD attachment state + void updateLockedHUD(); + // Iterates over all current attachment and attachment point locks and verifies their status (returns TRUE if verification succeeded) + bool verifyAttachmentLocks(); + +protected: + // Returns TRUE if the attachment point is eLock type locked by anything other than idRlvObj + bool isLockedAttachmentPointExcept(S32 idxAttachPt, ERlvLockMask eLock, const LLUUID& idRlvObj) const; + + /* + * canAttach/canDetach trivial helper functions (note that a more approriate name might be userCanAttach/userCanDetach) + */ +public: + // Returns TRUE if there is at least one attachment point that can be attached to + bool canAttach() const; + // Returns TRUE if the inventory item can be attached by the user (and optionally provides the attachment point - which may be NULL) + ERlvWearMask canAttach(const LLInventoryItem* pItem, LLViewerJointAttachment** ppAttachPtOut = NULL) const; + // Returns TRUE if the attachment point can be attached to by the user + ERlvWearMask canAttach(const LLViewerJointAttachment* pAttachPt) const; + + // Returns TRUE if the inventory item can be detached by the user + bool canDetach(const LLInventoryItem* pItem) const; + // Returns TRUE if the attachment point has at least one attachment that can be detached by the user + bool canDetach(const LLViewerJointAttachment* pAttachPt, bool fDetachAll = false) const; + + /* + * Member variables + */ +public: + typedef std::multimap<LLUUID, LLUUID> rlv_attachobjlock_map_t; + typedef std::multimap<S32, LLUUID> rlv_attachptlock_map_t; + // Accessors for RlvFloaterLocks + const rlv_attachptlock_map_t& getAttachPtLocks(ERlvLockMask eLock) { return (RLV_LOCK_ADD == eLock) ? m_AttachPtAdd : m_AttachPtRem; } + const rlv_attachobjlock_map_t& getAttachObjLocks() { return m_AttachObjRem; } +private: + rlv_attachptlock_map_t m_AttachPtAdd; // Map of attachment points that can't be attached to (idxAttachPt -> idObj) + rlv_attachptlock_map_t m_AttachPtRem; // Map of attachment points whose attachments can't be detached (idxAttachPt -> idObj) + rlv_attachobjlock_map_t m_AttachObjRem; // Map of attachments that can't be detached (idAttachObj -> idObj) + + bool m_fHasLockedHUD; +}; + +extern RlvAttachmentLocks gRlvAttachmentLocks; + +// ============================================================================ +// RlvAttachmentLockWatchdog - Self contained class that automagically takes care of enforcing attachment locks (ie reattach-on-detach) +// + +// TODO-RLVa: [RLVa-1.2.1] This class really looks rather cluttered so look into cleaning it up/simplifying it a bit +class RlvAttachmentLockWatchdog : public LLSingleton<RlvAttachmentLockWatchdog> +{ + friend class LLSingleton<RlvAttachmentLockWatchdog>; +protected: + RlvAttachmentLockWatchdog() : m_pTimer(NULL) {} + ~RlvAttachmentLockWatchdog() { delete m_pTimer; } + + /* + * Member functions + */ +protected: + // NOTE: detach does *not* respect attachment locks so use with care + void detach(const LLViewerObject* pAttachObj); + void detach(S32 idxAttachPt) { uuid_vec_t idsAttachObjExcept; detach(idxAttachPt, idsAttachObjExcept); } + void detach(S32 idxAttachPt, const uuid_vec_t& idsAttachObjExcept); + + void startTimer() { if (!m_pTimer) m_pTimer = new RlvAttachmentLockWatchdogTimer(this); } + + /* + * Event handlers + */ +public: + void onAttach(const LLViewerObject* pAttachObj, const LLViewerJointAttachment* pAttachPt); + void onDetach(const LLViewerObject* pAttachObj, const LLViewerJointAttachment* pAttachPt); + void onSavedAssetIntoInventory(const LLUUID& idItem); + BOOL onTimer(); + void onWearAttachment(const LLInventoryItem* pItem, ERlvWearMask eWearAction); + void onWearAttachment(const LLUUID& idItem, ERlvWearMask eWearAction); + + /* + * Member variables + */ +protected: + typedef std::list<LLUUID> rlv_detach_map_t; + rlv_detach_map_t m_PendingDetach; + + struct RlvReattachInfo + { + RlvReattachInfo(const LLUUID& itemid) : idItem(itemid), fAssetSaved(false), tsAttach(0) + { tsDetach = LLFrameTimer::getElapsedSeconds(); } + + LLUUID idItem; + bool fAssetSaved; + F64 tsDetach; + F64 tsAttach; + protected: + RlvReattachInfo(); + }; + typedef std::multimap<S32, RlvReattachInfo> rlv_attach_map_t; + rlv_attach_map_t m_PendingAttach; + + struct RlvWearInfo + { + RlvWearInfo(const LLUUID& itemid, ERlvWearMask wearaction) : idItem(itemid), eWearAction(wearaction) + { tsWear = LLFrameTimer::getElapsedSeconds(); } + + bool isAddLockedAttachPt(S32 idxAttachPt) const; + void dumpInstance() const; + + LLUUID idItem; + ERlvWearMask eWearAction; + F64 tsWear; + std::map<S32, uuid_vec_t> attachPts; + protected: + RlvWearInfo(); + }; + typedef std::map<LLUUID, RlvWearInfo> rlv_wear_map_t; + rlv_wear_map_t m_PendingWear; + + class RlvAttachmentLockWatchdogTimer : public LLEventTimer + { + public: + RlvAttachmentLockWatchdogTimer(RlvAttachmentLockWatchdog* pWatchdog) : LLEventTimer(10), m_pWatchdog(pWatchdog) {} + virtual ~RlvAttachmentLockWatchdogTimer() { m_pWatchdog->m_pTimer = NULL; } + virtual BOOL tick() { return m_pWatchdog->onTimer(); } + RlvAttachmentLockWatchdog* m_pWatchdog; + } *m_pTimer; +}; + +// ============================================================================ +// RlvWearableLocks class declaration - modelled on RlvAttachmentLocks (attach pt = wearable type - attachment = wearable) +// + +class RlvWearableLocks +{ +public: + // Adds an eLock type lock (held by idRlvObj) for the wearable type + void addWearableTypeLock(LLWearableType::EType eType, const LLUUID& idRlvObj, ERlvLockMask eLock); + + // Returns TRUE if there is at least 1 non-removable wearable currently worn on this wearable type + bool hasLockedWearable(LLWearableType::EType eType) const; + // Returns TRUE if there is at least 1 eLock type locked wearable type (RLV_LOCK_ANY = RLV_LOCK_ADD *or* RLV_LOCK_REMOVE) + // - RLV_LOCK_REMOVE: specific wearable locked *or* any wearable type locked (regardless of whether it currently has wearables) + bool hasLockedWearableType(ERlvLockMask eLock) const; + + // Removes an eLock type lock (held by idRlvObj) for the wearable type + void removeWearableTypeLock(LLWearableType::EType eType, const LLUUID& idRlvObj, ERlvLockMask eLock); + + // Returns TRUE if the wearable is RLV_LOCK_REMOVE locked + bool isLockedWearable(const LLViewerWearable* pWearable) const; + // Returns TRUE if the wearable is RLV_LOCK_REMOVE locked by anything other than idRlvObj + bool isLockedWearableExcept(const LLViewerWearable* pWearable, const LLUUID& idRlvObj) const; + + // NOTE: isLockedWearableType doesn't check if a worn wearable is a specific wearable lock so don't let these be called by the outside +protected: + // Returns TRUE if the wearable type is eLock type locked + bool isLockedWearableType(LLWearableType::EType eType, ERlvLockMask eLock) const; + // Returns TRUE if the wearable type is eLock type locked by anything other than idRlvObj + bool isLockedWearableTypeExcept(LLWearableType::EType eType, ERlvLockMask eLock, const LLUUID& idRlvObj) const; + + /* + * canWear/canRemove trivial helper functions (note that a more approriate name might be userCanWear/userCanRemove) + */ +public: + // Returns whether the inventory item can be worn by the user + ERlvWearMask canWear(const LLViewerInventoryItem* pItem) const; + // Returns whether the wearable type can be worn to by the user + ERlvWearMask canWear(LLWearableType::EType eType) const; + + // Returns TRUE if the inventory item can be removed by the user + bool canRemove(const LLInventoryItem* pItem) const; + // Returns TRUE if the wearable type has at least one wearable that can be removed by the user + bool canRemove(LLWearableType::EType eType) const; + + /* + * Member variables + */ +public: + typedef std::multimap<LLWearableType::EType, LLUUID> rlv_wearabletypelock_map_t; + // Accessors for RlvFloaterLocks + const rlv_wearabletypelock_map_t& getWearableTypeLocks(ERlvLockMask eLock) { return (RLV_LOCK_ADD == eLock) ? m_WearableTypeAdd : m_WearableTypeRem; } +protected: + rlv_wearabletypelock_map_t m_WearableTypeAdd; + rlv_wearabletypelock_map_t m_WearableTypeRem; +}; + +extern RlvWearableLocks gRlvWearableLocks; + +// ============================================================================ +// RlvFolderLocks class declaration +// + +class RlvFolderLocks : public LLSingleton<RlvFolderLocks> +{ + friend class RlvLockedDescendentsCollector; +public: + RlvFolderLocks(); + + // Specifies the source of a folder lock + enum ELockSourceType + { + ST_ATTACHMENT = 0x01, ST_ATTACHMENTPOINT = 0x02, ST_FOLDER = 0x04, ST_ROOTFOLDER = 0x08, + ST_SHAREDPATH = 0x10, ST_WEARABLETYPE = 0x20, ST_NONE= 0x00, ST_MASK_ANY = 0xFF + }; + typedef boost::variant<LLUUID, std::string, S32, LLWearableType::EType> lock_source_t; + typedef std::pair<ELockSourceType, lock_source_t> folderlock_source_t; + // Specifies options for the folder lock + enum ELockPermission { PERM_ALLOW = 0x1, PERM_DENY = 0x2, PERM_MASK_ANY = 0x3 }; + enum ELockScope { SCOPE_NODE, SCOPE_SUBTREE } ; + + struct folderlock_descr_t + { + LLUUID idRlvObj; + ERlvLockMask eLockType; + folderlock_source_t lockSource; + ELockPermission eLockPermission; + ELockScope eLockScope; + + folderlock_descr_t(const LLUUID& rlvObj, ERlvLockMask lockType, folderlock_source_t source, ELockPermission perm, ELockScope scope); + bool operator ==(const folderlock_descr_t& rhs) const; + }; + +public: + // Adds an eLock type lock (held by idRlvObj) for the specified folder source (with ePerm and eScope lock options) + void addFolderLock(const folderlock_source_t& lockSource, ELockPermission ePerm, ELockScope eScope, const LLUUID& idRlvObj, ERlvLockMask eLockType); + + // Returns TRUE if there is at least 1 non-detachable attachment as a result of a RLV_LOCK_REMOVE folder PERM_DENY lock + bool hasLockedAttachment() const; + // Returns TRUE if there is at least 1 eLock type PERM_DENY locked folder (RLV_LOCK_ANY = RLV_LOCK_ADD *or* RLV_LOCK_REMOVE) + bool hasLockedFolder(ERlvLockMask eLockTypeMask) const; + // Returns TRUE if the folder has a descendent folder lock with the specified charateristics + bool hasLockedFolderDescendent(const LLUUID& idFolder, int eSourceTypeMask, ELockPermission ePermMask, + ERlvLockMask eLockTypeMask, bool fCheckSelf) const; + // Returns TRUE if there is at least 1 non-removable wearable as a result of a RLV_LOCK_REMOVE folder PERM_DENY lock + bool hasLockedWearable() const; + // Returns TRUE if the attachment (specified by item UUID) is non-detachable as a result of a RLV_LOCK_REMOVE folder PERM_DENY lock + bool isLockedAttachment(const LLUUID& idItem) const; + // Returns TRUE if the folder is locked as a result of a RLV_LOCK_REMOVE folder PERM_DENY lock + bool isLockedFolder(LLUUID idFolder, ERlvLockMask eLock, int eSourceTypeMask = ST_MASK_ANY, folderlock_source_t* plockSource = NULL) const; + // Returns TRUE if the wearable (specified by item UUID) is non-removable as a result of a RLV_LOCK_REMOVE folder PERM_DENY lock + bool isLockedWearable(const LLUUID& idItem) const; + + // Removes an eLock type lock (held by idRlvObj) for the specified folder source (with ePerm and eScope lock options) + void removeFolderLock(const folderlock_source_t& lockSource, ELockPermission ePerm, ELockScope eScope, const LLUUID& idRlvObj, ERlvLockMask eLockType); + +protected: + // Returns TRUE if the folder has an explicit folder lock entry with the specified charateristics + bool isLockedFolderEntry(const LLUUID& idFolder, int eSourceTypeMask, ELockPermission ePermMask, ERlvLockMask eLockTypeMask) const; + + /* + * canXXX helper functions (note that a more approriate name might be userCanXXX) + */ +public: + bool canMoveFolder(const LLUUID& idFolder, const LLUUID& idFolderDest) const; + bool canRemoveFolder(const LLUUID& idFolder) const; + bool canRenameFolder(const LLUUID& idFolder) const; + bool canMoveItem(const LLUUID& idItem, const LLUUID& idFolderDest) const; + bool canRemoveItem(const LLUUID& idItem) const; + bool canRenameItem(const LLUUID& idItem) const; + + /* + * Cached item/folder look-up helper functions + */ +protected: + bool getLockedFolders(const folderlock_source_t& lockSource, LLInventoryModel::cat_array_t& lockFolders) const; + bool getLockedItems(const LLUUID& idFolder, LLInventoryModel::item_array_t& lockItems) const; + void onNeedsLookupRefresh(); + void refreshLockedLookups() const; + + /* + * Member variables + */ +public: + typedef std::list<const folderlock_descr_t*> folderlock_list_t; + // Accessors for RlvFloaterLocks + const folderlock_list_t& getFolderLocks() { return m_FolderLocks; } + const uuid_vec_t& getAttachmentLookups() { return m_LockedAttachmentRem; } + const uuid_vec_t& getWearableLookups() { return m_LockedWearableRem; } +protected: + boost::signals2::connection m_AttachmentChangeConnection; + + // Map of folder locks (idRlvObj -> lockDescr) + folderlock_list_t m_FolderLocks; // List of add and remove locked folder descriptions + S32 m_cntLockAdd; // Number of RLV_LOCK_ADD locked folders in m_FolderLocks + S32 m_cntLockRem; // Number of RLV_LOCK_REMOVE locked folders in m_FolderLocks + + // Cached item look-up variables + typedef std::multimap<LLUUID, const folderlock_descr_t*> folderlock_map_t; + mutable bool m_fLookupDirty; + mutable U32 m_RootLockType; + mutable uuid_vec_t m_LockedAttachmentRem; + mutable folderlock_map_t m_LockedFolderMap; + mutable uuid_vec_t m_LockedWearableRem; +private: + friend class LLSingleton<RlvFolderLocks>; +}; + +// ============================================================================ +// RlvAttachPtLookup inlined member functions +// + +// Checked: 2010-11-30 (RLVa-1.4.0b) | Added: RLVa-1.4.0b +inline LLViewerJointAttachment* RlvAttachPtLookup::getAttachPoint(S32 idxAttachPt) +{ + return (isAgentAvatarValid()) ? get_if_there(gAgentAvatarp->mAttachmentPoints, idxAttachPt, (LLViewerJointAttachment*)NULL) : NULL; +} + +// Checked: 2010-03-03 (RLVa-1.2.0a) | Modified: RLVa-0.2.0d +inline LLViewerJointAttachment* RlvAttachPtLookup::getAttachPoint(const std::string& strText) +{ + return (isAgentAvatarValid()) ? get_if_there(gAgentAvatarp->mAttachmentPoints, getAttachPointIndex(strText), (LLViewerJointAttachment*)NULL) : NULL; +} + +// Checked: 2010-03-03 (RLVa-1.2.0a) | Modified: RLVa-1.0.1b +inline LLViewerJointAttachment* RlvAttachPtLookup::getAttachPoint(const LLInventoryItem* pItem) +{ + return (isAgentAvatarValid()) ? get_if_there(gAgentAvatarp->mAttachmentPoints, getAttachPointIndex(pItem), (LLViewerJointAttachment*)NULL) : NULL; +} + +// Checked: 2010-03-03 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a +inline S32 RlvAttachPtLookup::getAttachPointIndex(std::string strText) +{ + LLStringUtil::toLower(strText); + RLV_ASSERT(m_AttachPtLookupMap.size() > 0); + std::map<std::string, S32>::const_iterator itAttachPt = m_AttachPtLookupMap.find(strText); + return (itAttachPt != m_AttachPtLookupMap.end()) ? itAttachPt->second : 0; +} + +// Checked: 2010-03-03 (RLVa-1.2.0a) | Modified: RLVa-0.2.0d +inline S32 RlvAttachPtLookup::getAttachPointIndex(const LLViewerObject* pObj) +{ + return (pObj) ? ATTACHMENT_ID_FROM_STATE(pObj->getState()) : 0; +} + +// ============================================================================ +// RlvAttachmentLocks inlined member functions +// + +// Checked: 2011-05-22 (RLVa-1.3.1b) | Modified: RLVa-1.3.1b +inline ERlvWearMask RlvAttachmentLocks::canAttach(const LLInventoryItem* pItem, LLViewerJointAttachment** ppAttachPtOut /*=NULL*/) const +{ + // The specified item can be attached if: + // - it doesn't specify an attachment point and there is at least one attachment point that can be attached to + // - the attachment point it specifies can be attached to + LLViewerJointAttachment* pAttachPt = RlvAttachPtLookup::getAttachPoint(pItem); + if (ppAttachPtOut) + *ppAttachPtOut = pAttachPt; + return ((canAttach()) && (pItem) && (!RlvFolderLocks::instance().isLockedFolder(pItem->getParentUUID(), RLV_LOCK_ADD))) + ? ((!pAttachPt) ? RLV_WEAR : canAttach(pAttachPt)) : RLV_WEAR_LOCKED; +} + +// Checked: 2010-08-07 (RLVa-1.2.0i) | Modified: RLVa-1.2.0i +inline ERlvWearMask RlvAttachmentLocks::canAttach(const LLViewerJointAttachment* pAttachPt) const +{ + // Non-attachable attachment point => RLV_WEAR_LOCKED + // One or more locked attachment(s) => RLV_WEAR_ADD + // Unlocked attachment(s) => RLV_WEAR_ADD | RLV_WEAR_REPLACE + // Empty attachment point => RLV_WEAR_ADD | RLV_WEAR_REPLACE + RLV_ASSERT(pAttachPt); // TODO-RLVa: [RLVa-1.2.1] Maybe it's better to just return something similar like above? + return + (ERlvWearMask)(((pAttachPt) && (!isLockedAttachmentPoint(pAttachPt, RLV_LOCK_ADD))) + ? ((canDetach(pAttachPt, true)) ? RLV_WEAR_REPLACE : 0) | RLV_WEAR_ADD + : RLV_WEAR_LOCKED); +} + +// Checked: 2010-02-28 (RLVa-1.2.0) +inline bool RlvAttachmentLocks::canDetach(const LLInventoryItem* pItem) const +{ + const LLViewerObject* pAttachObj = + ((pItem) && (isAgentAvatarValid())) ? gAgentAvatarp->getWornAttachment(pItem->getLinkedUUID()) : NULL; + return (!pAttachObj) || (!isLockedAttachment(pAttachObj)); +} + +// Checked: 2010-11-30 (RLVa-1.3.0b) | Modified: RLVa-1.3.0b +inline bool RlvAttachmentLocks::hasLockedAttachmentPoint(ERlvLockMask eLock) const +{ + // Remove locks are more common so check those first + return + ((eLock & RLV_LOCK_REMOVE) && ((!m_AttachPtRem.empty()) || (!m_AttachObjRem.empty()) || (RlvFolderLocks::instance().hasLockedAttachment()))) || + ((eLock & RLV_LOCK_ADD) && (!m_AttachPtAdd.empty()) ); +} + +// Checked: 2010-11-30 (RLVa-1.3.0b) | Modified: RLVa-1.3.0b +inline bool RlvAttachmentLocks::isLockedAttachment(const LLViewerObject* pAttachObj) const +{ + // If pObj is valid then it should always specify a root since we store root UUIDs in m_AttachObjRem + RLV_ASSERT( (!pAttachObj) || (pAttachObj == pAttachObj->getRootEdit()) ); + + // Object is locked if: + // - it's specifically marked as non-detachable (ie @detach=n) + // - it's attached to an attachment point that is RLV_LOCK_REMOVE locked (ie @remattach:<attachpt>=n) + // - it's part of a locked folder + return + (pAttachObj) && (pAttachObj->isAttachment()) && + ( (m_AttachObjRem.find(pAttachObj->getID()) != m_AttachObjRem.end()) || + (isLockedAttachmentPoint(RlvAttachPtLookup::getAttachPointIndex(pAttachObj), RLV_LOCK_REMOVE)) || + ((!pAttachObj->isTempAttachment()) && (RlvFolderLocks::instance().isLockedAttachment(pAttachObj->getAttachmentItemID()))) ); +} + +// Checked: 2010-02-28 (RLVa-1.2.0a) | Added: RLVa-1.0.5a +inline bool RlvAttachmentLocks::isLockedAttachmentPoint(S32 idxAttachPt, ERlvLockMask eLock) const +{ + return + ( (eLock & RLV_LOCK_REMOVE) && (m_AttachPtRem.find(idxAttachPt) != m_AttachPtRem.end()) ) || + ( (eLock & RLV_LOCK_ADD) && (m_AttachPtAdd.find(idxAttachPt) != m_AttachPtAdd.end()) ); +} + +// Checked: 2010-02-28 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a +inline bool RlvAttachmentLocks::isLockedAttachmentPoint(const LLViewerJointAttachment* pAttachPt, ERlvLockMask eLock) const +{ + return (pAttachPt) && (isLockedAttachmentPoint(RlvAttachPtLookup::getAttachPointIndex(pAttachPt), eLock)); +} + +// ============================================================================ +// RlvWearableLocks inlined member functions +// + +// Checked: 2010-03-19 (RLVa-1.2.0c) | Added: RLVa-1.2.0a +inline bool RlvWearableLocks::canRemove(const LLInventoryItem* pItem) const +{ + // The specified item can be removed if its wearable can be removed + RLV_ASSERT( (pItem) && (LLInventoryType::IT_WEARABLE == pItem->getInventoryType()) ); + const LLViewerWearable* pWearable = (pItem) ? gAgentWearables.getWearableFromItemID(pItem->getLinkedUUID()) : NULL; + return (pWearable) && (!isLockedWearable(pWearable)); +} + +// Checked: 2011-03-27 (RLVa-1.3.0g) | Modified: RLVa-1.3.0g +inline ERlvWearMask RlvWearableLocks::canWear(const LLViewerInventoryItem* pItem) const +{ + // The specified item can be worn if the wearable type it specifies can be worn on + RLV_ASSERT( (pItem) && (LLInventoryType::IT_WEARABLE == pItem->getInventoryType()) ); + return ((pItem) && (!RlvFolderLocks::instance().isLockedFolder(pItem->getParentUUID(), RLV_LOCK_ADD))) + ? canWear(pItem->getWearableType()) : RLV_WEAR_LOCKED; +} + +// Checked: 2010-05-14 (RLVa-1.2.0g) | Modified: RLVa-1.2.0g +inline ERlvWearMask RlvWearableLocks::canWear(LLWearableType::EType eType) const +{ + // The specified wearable type can be worn on if: + // - the wearable type itself isn't RLV_LOCK_ADD locked => RLV_WEAR_ADD + // (and there are less than the maximum amount currently worn) + // - it doesn't have any non-removable wearables => RLV_WEAR_REPLACE | RLV_WEAR_ADD = RLV_WEAR + // TODO-RLVa: [RLVa-1.2.1] We don't have the ability to lock a specific wearable yet so rewrite this when we do + return (!isLockedWearableType(eType, RLV_LOCK_ADD)) + ? ((!hasLockedWearable(eType)) + ? RLV_WEAR + : (gAgentWearables.canAddWearable(eType)) ? RLV_WEAR_ADD : RLV_WEAR_LOCKED) + : RLV_WEAR_LOCKED; +} + +// Checked: 2010-03-18 (RLVa-1.2.0c) | Modified: RLVa-1.2.0a +inline bool RlvWearableLocks::hasLockedWearableType(ERlvLockMask eLock) const +{ + // Remove locks are more common so check those first + // TODO-RLVa: [RLVa-1.2.1] We don't have the ability to lock a specific wearable yet so rewrite this when we do + return ( (eLock & RLV_LOCK_REMOVE) && (!m_WearableTypeRem.empty()) ) || ( (eLock & RLV_LOCK_ADD) && (!m_WearableTypeAdd.empty()) ); +} + +// Checked: 2010-11-30 (RLVa-1.3.0b) | Modified: RLVa-1.2.0a +inline bool RlvWearableLocks::isLockedWearable(const LLViewerWearable* pWearable) const +{ + // Wearable is locked if: + // - it's specifically marked as non-removable + // - it's worn on a wearable type that is RLV_LOCK_REMOVE locked + // - it's part of a locked folder + // TODO-RLVa: [RLVa-1.2.1] We don't have the ability to lock a specific wearable yet so rewrite this when we do + RLV_ASSERT(pWearable); + return + (pWearable) && + ( (isLockedWearableType(pWearable->getType(), RLV_LOCK_REMOVE)) || (RlvFolderLocks::instance().isLockedWearable(pWearable->getItemID())) ); +} + +// Checked: 2010-03-19 (RLVa-1.2.0c) | Added: RLVa-1.2.0a +inline bool RlvWearableLocks::isLockedWearableType(LLWearableType::EType eType, ERlvLockMask eLock) const +{ + return + ( (eLock & RLV_LOCK_REMOVE) && (m_WearableTypeRem.find(eType) != m_WearableTypeRem.end()) ) || + ( (eLock & RLV_LOCK_ADD) && (m_WearableTypeAdd.find(eType) != m_WearableTypeAdd.end()) ); +} + +// ============================================================================ +// RlvAttachmentLockWatchdog inlined member functions +// + +// Checked: 2010-08-07 (RLVa-1.2.0i) | Added: RLVa-1.2.0i +inline void RlvAttachmentLockWatchdog::onWearAttachment(const LLInventoryItem* pItem, ERlvWearMask eWearAction) +{ + onWearAttachment(pItem->getLinkedUUID(), eWearAction); +} + +// ============================================================================ +// RlvFolderLocks member functions +// + +// Checked: 2011-03-27 (RLVa-1.3.0g) | Added: RLVa-1.3.0g +inline RlvFolderLocks::folderlock_descr_t::folderlock_descr_t(const LLUUID& rlvObj, ERlvLockMask lockType, folderlock_source_t source, + ELockPermission perm, ELockScope scope) + : idRlvObj(rlvObj), eLockType(lockType), lockSource(source), eLockPermission(perm), eLockScope(scope) +{ +} + +// Checked: 2011-03-27 (RLVa-1.3.0g) | Added: RLVa-1.3.0g +inline bool RlvFolderLocks::folderlock_descr_t::operator ==(const folderlock_descr_t& rhs) const +{ + return (idRlvObj == rhs.idRlvObj) && (eLockType == rhs.eLockType) && (lockSource == rhs.lockSource) && + (eLockPermission == rhs.eLockPermission) && (eLockScope == rhs.eLockScope); +} + +// Checked: 2011-03-29 (RLVa-1.3.0g) | Added: RLVa-1.3.0g +inline bool RlvFolderLocks::canMoveFolder(const LLUUID& idFolder, const LLUUID& idFolderDest) const +{ + // Block moving the folder to destination if: + // - the folder (or one of its descendents) is explicitly locked + // - folder and destination are subject to different locks + // -> Possible combinations: + // * folder locked + destination unlocked => block move + // * folder unlocked + destination locked => block move + // * folder locked + destination locked => allow move only if both are subject to the same folder lock + // * folder unlocked + destination unlocked => allow move (special case of above since both locks are equal when there is none) + // => so the above becomes (isLockedFolder(A) == isLockedFolder(B)) && (lockA == lockB) + folderlock_source_t lockSource(ST_NONE, 0), lockSourceDest(ST_NONE, 0); + return + (!hasLockedFolderDescendent(idFolder, ST_MASK_ANY, PERM_MASK_ANY, RLV_LOCK_ANY, true)) && + ( (isLockedFolder(idFolder, RLV_LOCK_ANY, ST_MASK_ANY, &lockSource) == isLockedFolder(idFolderDest, RLV_LOCK_ANY, ST_MASK_ANY, &lockSourceDest)) && + (lockSource == lockSourceDest) ); +} + +// Checked: 2011-03-29 (RLVa-1.3.0g) | Added: RLVa-1.3.0g +inline bool RlvFolderLocks::canRemoveFolder(const LLUUID& idFolder) const +{ + // Block removing a folder if: + // - the folder (or one of its descendents) is explicitly locked + // - the folder itself is locked (but disregard root folder locks) + return + (!hasLockedFolderDescendent(idFolder, ST_MASK_ANY, PERM_MASK_ANY, RLV_LOCK_ANY, true)) && + (!isLockedFolder(idFolder, RLV_LOCK_ANY, ST_MASK_ANY & ~ST_ROOTFOLDER)); +} + +// Checked: 2011-03-29 (RLVa-1.3.0g) | Added: RLVa-1.3.0g +inline bool RlvFolderLocks::canRenameFolder(const LLUUID& idFolder) const +{ + // Block renaming a folder if: + // - the folder (or one of its descendents) is explicitly locked by: + // -> a "shared path" => renaming the folder would change the shared path and hence invalidate the lock + // -> an attachment point -| + // -> an attachment |--> renaming the folder to a "dot" (=invisible) folder would invalidate the lock + // -> a wearable type -| + return !hasLockedFolderDescendent(idFolder, ST_SHAREDPATH | ST_ATTACHMENT | ST_ATTACHMENTPOINT | ST_WEARABLETYPE, PERM_MASK_ANY, RLV_LOCK_ANY, true); +} + +// Checked: 2011-03-30 (RLVa-1.3.0g) | Added: RLVa-1.3.0g +inline bool RlvFolderLocks::canMoveItem(const LLUUID& idItem, const LLUUID& idFolderDest) const +{ + // Block moving the folder to destination if: + // - folder and destination are subject to different locks [see canMoveFolder() for more details] + const LLViewerInventoryItem* pItem = gInventory.getItem(idItem); const LLUUID& idFolder = (pItem) ? pItem->getParentUUID() : LLUUID::null; + int maskSource = ST_MASK_ANY & ~ST_ROOTFOLDER; folderlock_source_t lockSource(ST_NONE, 0), lockSourceDest(ST_NONE, 0); + return + (idFolder.notNull()) && + (isLockedFolder(idFolder, RLV_LOCK_ANY, maskSource, &lockSource) == isLockedFolder(idFolderDest, RLV_LOCK_ANY, maskSource, &lockSourceDest)) && + (lockSource == lockSourceDest); +} + +// Checked: 2011-03-30 (RLVa-1.3.0g) | Added: RLVa-1.3.0g +inline bool RlvFolderLocks::canRemoveItem(const LLUUID& idItem) const +{ + // Block removing items from locked folders (but disregard root folder locks) + const LLViewerInventoryItem* pItem = gInventory.getItem(idItem); const LLUUID& idFolder = (pItem) ? pItem->getParentUUID() : LLUUID::null; + int maskSource = ST_MASK_ANY & ~ST_ROOTFOLDER; + return (idFolder.notNull()) && (!isLockedFolder(idFolder, RLV_LOCK_ANY, maskSource)); +} + +// Checked: 2011-03-30 (RLVa-1.3.0g) | Added: RLVa-1.3.0g +inline bool RlvFolderLocks::canRenameItem(const LLUUID& idItem) const +{ + // Items can always be renamed, regardless of folder locks + return true; +} + +// Checked: 2010-11-30 (RLVa-1.3.0g) | Added: RLVa-1.3.0b +inline bool RlvFolderLocks::hasLockedAttachment() const +{ + if (m_fLookupDirty) + refreshLockedLookups(); + return !m_LockedAttachmentRem.empty(); +} + +// Checked: 2011-03-27 (RLVa-1.3.0g) | Modified: RLVa-1.3.0g +inline bool RlvFolderLocks::hasLockedFolder(ERlvLockMask eLock) const +{ + // Remove locks are more common so check those first + return ((eLock & RLV_LOCK_REMOVE) && (m_cntLockRem)) || ((eLock & RLV_LOCK_ADD) && (m_cntLockAdd)); +} + +// Checked: 2010-11-30 (RLVa-1.3.0g) | Added: RLVa-1.3.0b +inline bool RlvFolderLocks::hasLockedWearable() const +{ + if (m_fLookupDirty) + refreshLockedLookups(); + return !m_LockedWearableRem.empty(); +} + +// Checked: 2010-11-30 (RLVa-1.3.0g) | Added: RLVa-1.3.0b +inline bool RlvFolderLocks::isLockedAttachment(const LLUUID& idItem) const +{ + if (m_fLookupDirty) + refreshLockedLookups(); + return (std::find(m_LockedAttachmentRem.begin(), m_LockedAttachmentRem.end(), idItem) != m_LockedAttachmentRem.end()); +} + +// Checked: 2010-11-30 (RLVa-1.3.0g) | Added: RLVa-1.3.0b +inline bool RlvFolderLocks::isLockedWearable(const LLUUID& idItem) const +{ + if (m_fLookupDirty) + refreshLockedLookups(); + return (std::find(m_LockedWearableRem.begin(), m_LockedWearableRem.end(), idItem) != m_LockedWearableRem.end()); +} + +// ============================================================================ + +#endif // RLV_LOCKS_H diff --git a/indra/newview/rlvui.cpp b/indra/newview/rlvui.cpp new file mode 100644 index 0000000000000000000000000000000000000000..01d01a061d785471be359dd2d0527f28c917a8b9 --- /dev/null +++ b/indra/newview/rlvui.cpp @@ -0,0 +1,441 @@ +/** + * + * Copyright (c) 2009-2011, Kitty Barnett + * + * The source code in this file is provided to you under the terms of the + * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt + * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.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 "llagent.h" +#include "llavataractions.h" // LLAvatarActions::profileVisible() +#include "llfloatersidepanelcontainer.h" +#include "llhudtext.h" // LLHUDText::refreshAllObjectText() +#include "llimview.h" // LLIMMgr::computeSessionID() +#include "llmoveview.h" // Movement panel (contains "Stand" and "Stop Flying" buttons) +#include "llnavigationbar.h" // Navigation bar +#include "llparcel.h" +#include "llpaneltopinfobar.h" +#include "llteleporthistory.h" +#include "lltoolmgr.h" +#include "llviewerparcelmgr.h" +#include "llviewerregion.h" +#include "llvoavatar.h" +#include "roles_constants.h" // Group "powers" + +#include "rlvui.h" +#include "rlvhandler.h" +#include "rlvextensions.h" + +// ============================================================================ + +// Checked: 2010-02-28 (RLVa-1.4.0a) | Added: RLVa-1.2.0a +RlvUIEnabler::RlvUIEnabler() +{ + // Connect us to the behaviour toggle signal + gRlvHandler.setBehaviourToggleCallback(boost::bind(&RlvUIEnabler::onBehaviourToggle, this, _1, _2)); + + // onRefreshHoverText() + m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_SHOWLOC, boost::bind(&RlvUIEnabler::onRefreshHoverText, this))); + m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_SHOWHOVERTEXTALL, boost::bind(&RlvUIEnabler::onRefreshHoverText, this))); + m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_SHOWHOVERTEXTWORLD, boost::bind(&RlvUIEnabler::onRefreshHoverText, this))); + m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_SHOWHOVERTEXTHUD, boost::bind(&RlvUIEnabler::onRefreshHoverText, this))); + + // onToggleMovement + m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_FLY, boost::bind(&RlvUIEnabler::onToggleMovement, this))); + m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_ALWAYSRUN, boost::bind(&RlvUIEnabler::onToggleMovement, this))); + m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_TEMPRUN, boost::bind(&RlvUIEnabler::onToggleMovement, this))); + + // onToggleViewXXX + m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_VIEWNOTE, boost::bind(&RlvUIEnabler::onToggleViewXXX, this))); + m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_VIEWSCRIPT, boost::bind(&RlvUIEnabler::onToggleViewXXX, this))); + m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_VIEWTEXTURE, boost::bind(&RlvUIEnabler::onToggleViewXXX, this))); + + // onToggleXXX + m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_SHOWLOC, boost::bind(&RlvUIEnabler::onToggleShowLoc, this))); + m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_SHOWMINIMAP, boost::bind(&RlvUIEnabler::onToggleShowMinimap, this))); + m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_SHOWWORLDMAP, boost::bind(&RlvUIEnabler::onToggleShowWorldMap, this))); + m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_UNSIT, boost::bind(&RlvUIEnabler::onToggleUnsit, this))); + + // onToggleTp + m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_TPLOC, boost::bind(&RlvUIEnabler::onToggleTp, this))); + m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_TPLM, boost::bind(&RlvUIEnabler::onToggleTp, this))); + + // onUpdateLoginLastLocation + m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_TPLOC, boost::bind(&RlvUIEnabler::onUpdateLoginLastLocation, this, _1))); + m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_UNSIT, boost::bind(&RlvUIEnabler::onUpdateLoginLastLocation, this, _1))); +} + +// Checked: 2010-02-28 (RLVa-1.4.0a) | Added: RLVa-1.2.0a +void RlvUIEnabler::onBehaviourToggle(ERlvBehaviour eBhvr, ERlvParamType eType) +{ + bool fQuitting = LLApp::isQuitting(); + for (behaviour_handler_map_t::const_iterator itHandler = m_Handlers.lower_bound(eBhvr), endHandler = m_Handlers.upper_bound(eBhvr); + itHandler != endHandler; ++itHandler) + { + itHandler->second(fQuitting); + } +} + +// ============================================================================ + +// Checked: 2010-03-02 (RLVa-1.4.0a) | Added: RLVa-1.2.0a +void RlvUIEnabler::onRefreshHoverText() +{ + // Refresh all hover text each time any of the monitored behaviours get set or unset + LLHUDText::refreshAllObjectText(); +} + +// Checked: 2010-03-02 (RLVa-1.4.0a) | Modified: RLVa-1.4.0a +void RlvUIEnabler::onToggleMovement() +{ + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_FLY)) && (gAgent.getFlying()) ) + gAgent.setFlying(FALSE); + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_ALWAYSRUN)) && (gAgent.getAlwaysRun()) ) + gAgent.clearAlwaysRun(); + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_TEMPRUN)) && (gAgent.getTempRun()) ) + gAgent.clearTempRun(); + + // Force an update since the status only updates when the current parcel changes [see LLFloaterMove::postBuild()] + LLFloaterMove::sUpdateMovementStatus(); +} + +// Checked: 2010-04-22 (RLVa-1.2.0f) | Modified: RLVa-1.2.0f +void RlvUIEnabler::onToggleShowLoc() +{ + bool fEnable = !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC); + + if (LLNavigationBar::instanceExists()) + LLNavigationBar::instance().refreshLocationCtrl(); + if (LLPanelTopInfoBar::instanceExists()) + LLPanelTopInfoBar::instance().update(); + + if (!fEnable) + { + // Hide the "About Land" floater if it's currently visible + if (LLFloaterReg::instanceVisible("about_land")) + LLFloaterReg::hideInstance("about_land"); + // Hide the "Region / Estate" floater if it's currently visible + if (LLFloaterReg::instanceVisible("region_info")) + LLFloaterReg::hideInstance("region_info"); + // Hide the "God Tools" floater if it's currently visible + if (LLFloaterReg::instanceVisible("god_tools")) + LLFloaterReg::hideInstance("god_tools"); + + // + // Manipulate the teleport history + // + + // If the last entry in the persistent teleport history matches the current teleport history entry then we should remove it + LLTeleportHistory* pTpHistory = LLTeleportHistory::getInstance(); + LLTeleportHistoryStorage* pTpHistoryStg = LLTeleportHistoryStorage::getInstance(); + RLV_ASSERT( (pTpHistory) && (pTpHistoryStg) && (pTpHistory->getItems().size() > 0) && (pTpHistory->getCurrentItemIndex() >= 0) ); + if ( (pTpHistory) && (pTpHistory->getItems().size() > 0) && (pTpHistory->getCurrentItemIndex() >= 0) && + (pTpHistoryStg) && (pTpHistory->getItems().size() > 0) ) + { + const LLTeleportHistoryItem& tpItem = pTpHistory->getItems().back(); + const LLTeleportHistoryPersistentItem& tpItemStg = pTpHistoryStg->getItems().back(); + if (pTpHistoryStg->compareByTitleAndGlobalPos(tpItemStg, LLTeleportHistoryPersistentItem(tpItem.mTitle, tpItem.mGlobalPos))) + { + // TODO-RLVa: [RLVa-1.2.2] Is there a reason why LLTeleportHistoryStorage::removeItem() doesn't trigger history changed? + pTpHistoryStg->removeItem(pTpHistoryStg->getItems().size() - 1); + pTpHistoryStg->mHistoryChangedSignal(-1); + } + } + + // Clear the current location in the teleport history + if (pTpHistory) + pTpHistory->updateCurrentLocation(gAgent.getPositionGlobal()); + } + else + { + // Reset the current location in the teleport history (also takes care of adding it to the persistent teleport history) + LLTeleportHistory* pTpHistory = LLTeleportHistory::getInstance(); + if ( (pTpHistory) && (NULL != gAgent.getRegion()) ) + pTpHistory->updateCurrentLocation(gAgent.getPositionGlobal()); + } + + // Start or stop filtering the "About Land" and "Region / Estate" floaters + if ( (!fEnable) && (!m_ConnFloaterShowLoc.connected()) ) + { + m_ConnFloaterShowLoc = LLFloaterReg::setValidateCallback(boost::bind(&RlvUIEnabler::filterFloaterShowLoc, this, _1, _2)); + m_ConnPanelShowLoc = LLFloaterSidePanelContainer::setValidateCallback(boost::bind(&RlvUIEnabler::filterPanelShowLoc, this, _1, _2, _3)); + } + else if ( (fEnable) && (m_ConnFloaterShowLoc.connected()) ) + { + m_ConnFloaterShowLoc.disconnect(); + m_ConnPanelShowLoc.disconnect(); + } +} + +// Checked: 2010-02-28 (RLVa-1.4.0a) | Added: RLVa-1.2.0a +void RlvUIEnabler::onToggleShowMinimap() +{ + bool fEnable = !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWMINIMAP); + + // Start or stop filtering showing the mini-map floater + if (!fEnable) + addGenericFloaterFilter("mini_map"); + else + removeGenericFloaterFilter("mini_map"); + + // Hide the mini-map floater if it's currently visible (or restore it if it was previously visible) + static bool fPrevVisibile = false; + if ( (!fEnable) && ((fPrevVisibile = LLFloaterReg::instanceVisible("mini_map"))) ) + LLFloaterReg::hideInstance("mini_map"); + else if ( (fEnable) && (fPrevVisibile) ) + LLFloaterReg::showInstance("mini_map"); + + // Break/reestablish the visibility connection for the nearby people panel embedded minimap instance + LLPanel* pPeoplePanel = LLFloaterSidePanelContainer::getPanel("people", "panel_people"); + LLPanel* pNetMapPanel = (pPeoplePanel) ? pPeoplePanel->findChild<LLPanel>("Net Map Panel", TRUE) : NULL; + RLV_ASSERT( (pPeoplePanel) && (pNetMapPanel) ); + if (pNetMapPanel) + { + pNetMapPanel->setMakeVisibleControlVariable( (fEnable) ? gSavedSettings.getControl("NearbyListShowMap").get() : NULL); + // Reestablishing the visiblity connection will show the panel if needed so we only need to take care of hiding it when needed + if ( (!fEnable) && (pNetMapPanel->getVisible()) ) + pNetMapPanel->setVisible(false); + } +} + +// Checked: 2010-02-28 (RLVa-1.4.0a) | Added: RLVa-1.2.0a +void RlvUIEnabler::onToggleShowWorldMap() +{ + bool fEnable = !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWWORLDMAP); + + // Hide the world map if it's currently visible + if ( (!fEnable) && (LLFloaterReg::instanceVisible("world_map")) ) + LLFloaterReg::hideInstance("world_map"); + + // Start or stop filtering opening the world map + if (!fEnable) + addGenericFloaterFilter("world_map"); + else + removeGenericFloaterFilter("world_map"); +} + +// Checked: 2010-08-22 (RLVa-1.2.1a) | Added: RLVa-1.2.1a +void RlvUIEnabler::onToggleTp() +{ + // Disable the navigation bar "Home" button if both @tplm=n *and* @tploc=n restricted + LLButton* pNavBarHomeBtn = LLNavigationBar::getInstance()->findChild<LLButton>("home_btn"); + RLV_ASSERT(pNavBarHomeBtn); + if (pNavBarHomeBtn) + pNavBarHomeBtn->setEnabled(!(gRlvHandler.hasBehaviour(RLV_BHVR_TPLM) && gRlvHandler.hasBehaviour(RLV_BHVR_TPLOC))); +} + +// Checked: 2010-03-01 (RLVa-1.2.0c) | Added: RLVa-1.2.0a +void RlvUIEnabler::onToggleUnsit() +{ + bool fEnable = !gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT); + + LLPanelStandStopFlying* pPanelStand = LLPanelStandStopFlying::getInstance(); + RLV_ASSERT(pPanelStand); + if (pPanelStand) + { + LLButton* pBtnStand = pPanelStand->findChild<LLButton>("stand_btn"); + RLV_ASSERT(pBtnStand); + if (pBtnStand) + pBtnStand->setEnabled(fEnable); + } +} + +// Checked: 2010-03-01 (RLVa-1.2.0b) | Added: RLVa-1.2.0a +void RlvUIEnabler::onToggleViewXXX() +{ + // If any of the three are still active then we keep filtering + bool fHasViewXXX = (gRlvHandler.hasBehaviour(RLV_BHVR_VIEWNOTE)) || + (gRlvHandler.hasBehaviour(RLV_BHVR_VIEWSCRIPT)) || (gRlvHandler.hasBehaviour(RLV_BHVR_VIEWTEXTURE)); + + // Start or stop filtering opening the preview floaters + if ( (fHasViewXXX) && (!m_ConnFloaterViewXXX.connected()) ) + m_ConnFloaterViewXXX = LLFloaterReg::setValidateCallback(boost::bind(&RlvUIEnabler::filterFloaterViewXXX, this, _1, _2)); + else if ( (!fHasViewXXX) && (m_ConnFloaterViewXXX.connected()) ) + m_ConnFloaterViewXXX.disconnect(); +} + +// Checked: 2010-04-01 (RLVa-1.2.0c) | Added: RLVa-1.2.0c +void RlvUIEnabler::onUpdateLoginLastLocation(bool fQuitting) +{ + if (!fQuitting) + RlvSettings::updateLoginLastLocation(); +} + +// ============================================================================ + +// Checked: 2010-02-28 (RLVa-1.4.0a) | Added: RLVa-1.2.0a +void RlvUIEnabler::addGenericFloaterFilter(const std::string& strFloaterName) +{ + m_FilteredFloaters.insert(strFloaterName); + + if (!m_ConnFloaterGeneric.connected()) + m_ConnFloaterGeneric = LLFloaterReg::setValidateCallback(boost::bind(&RlvUIEnabler::filterFloaterGeneric, this, _1, _2)); +} + +// Checked: 2010-02-28 (RLVa-1.4.0a) | Added: RLVa-1.2.0a +void RlvUIEnabler::removeGenericFloaterFilter(const std::string& strFloaterName) +{ + std::multiset<std::string>::iterator itFloater = m_FilteredFloaters.find(strFloaterName); + RLV_ASSERT_DBG(itFloater != m_FilteredFloaters.end()); + m_FilteredFloaters.erase(itFloater); + + RLV_ASSERT_DBG(m_ConnFloaterGeneric.connected()); + if (m_FilteredFloaters.empty()) + m_ConnFloaterGeneric.disconnect(); +} + +// Checked: 2010-02-28 (RLVa-1.4.0a) | Added: RLVa-1.2.0a +bool RlvUIEnabler::filterFloaterGeneric(const std::string& strName, const LLSD&) +{ + return m_FilteredFloaters.end() == m_FilteredFloaters.find(strName); +} + +// Checked: 2010-04-22 (RLVa-1.4.5) | Added: RLVa-1.2.0 +bool RlvUIEnabler::filterFloaterShowLoc(const std::string& strName, const LLSD&) +{ + if ("about_land" == strName) + return canViewParcelProperties(); + else if ("region_info" == strName) + return canViewRegionProperties(); + else if ("god_tools" == strName) + return false; + return true; +} + +// Checked: 2012-02-07 (RLVa-1.4.5) | Added: RLVa-1.4.5 +bool RlvUIEnabler::filterPanelShowLoc(const std::string& strFloater, const std::string&, const LLSD& sdKey) +{ + if ("places" == strFloater) + { + const std::string strType = sdKey["type"].asString(); + if ("create_landmark" == strType) + return false; + else if ("agent" == strType) + return canViewParcelProperties(); + } + return true; +} + +// Checked: 2010-03-01 (RLVa-1.2.0b) | Added: RLVa-1.2.0a +bool RlvUIEnabler::filterFloaterViewXXX(const std::string& strName, const LLSD&) +{ + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_VIEWNOTE)) && ("preview_notecard" == strName) ) + { + RlvUtil::notifyBlockedViewXXX(LLAssetType::AT_NOTECARD); + return false; + } + else if ( (gRlvHandler.hasBehaviour(RLV_BHVR_VIEWSCRIPT)) && (("preview_script" == strName) || ("preview_scriptedit" == strName)) ) + { + RlvUtil::notifyBlockedViewXXX(LLAssetType::AT_SCRIPT); + return false; + } + else if ( (gRlvHandler.hasBehaviour(RLV_BHVR_VIEWTEXTURE)) && ("preview_texture" == strName) ) + { + RlvUtil::notifyBlockedViewXXX(LLAssetType::AT_TEXTURE); + return false; + } + return true; +} + +// ============================================================================ + +// Checked: 2012-02-09 (RLVa-1.4.5) | Modified: RLVa-1.4.5 +bool RlvUIEnabler::canViewParcelProperties() +{ + // We'll allow "About Land" as long as the user has the ability to return prims (through ownership or through group powers) + bool fShow = !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC); + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) + { + // RELEASE-RLVa: [SL-3.2] Check that opening the "About Land" floater still sets focus to the current parcel is none is selected + const LLParcel* pParcel = NULL; + if (LLViewerParcelMgr::getInstance()->selectionEmpty()) + { + pParcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + } + else + { + LLParcelSelection* pParcelSel = LLViewerParcelMgr::getInstance()->getFloatingParcelSelection(); + if (pParcelSel->hasOthersSelected()) + return false; + pParcel = pParcelSel->getParcel(); + } + + // Ideally we could just use LLViewerParcelMgr::isParcelOwnedByAgent(), but that has that sneaky exemption for "god-like" + if (pParcel) + { + const LLUUID& idOwner = pParcel->getOwnerID(); + if ( (idOwner != gAgent.getID()) ) + { + S32 count = gAgent.mGroups.size(); + for (S32 i = 0; i < count; ++i) + { + if (gAgent.mGroups.at(i).mID == idOwner) + { + fShow = ((gAgent.mGroups.at(i).mPowers & GP_LAND_RETURN) > 0); + break; + } + } + } + else + { + fShow = true; + } + } + } + return fShow; +} + +// Checked: 2010-04-20 (RLVa-1.4.5) | Modified: RLVa-1.2.0 +bool RlvUIEnabler::canViewRegionProperties() +{ + // We'll allow "Region / Estate" if the user is either the region owner or an estate manager + bool fShow = !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC); + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) + { + // [See LLRegion::canManageEstate() but without the "god-like" exception] + const LLViewerRegion* pRegion = gAgent.getRegion(); + if (pRegion) + fShow = (pRegion->isEstateManager()) || (pRegion->getOwner() == gAgent.getID()); + } + return fShow; +} + +// Checked: 2010-04-20 (RLVa-1.2.0f) | Added: RLVa-1.2.0f +bool RlvUIEnabler::hasOpenIM(const LLUUID& idAgent) +{ + LLUUID idSession = LLIMMgr::computeSessionID(IM_NOTHING_SPECIAL, idAgent); + return (NULL != LLFloaterReg::findInstance("impanel", idSession)); +} + +// Checked: 2011-11-04 (RLVa-1.4.4a) | Modified: RLVa-1.4.4a +bool RlvUIEnabler::hasOpenProfile(const LLUUID& idAgent) +{ + // -> SL-2.1.0 added the ability to "share" inventory by dropping it on the avatar picker floater so we should check for that + // -> we can drag/drop inventory onto calling cards but probably noone knows about it and it would be too involved to check for that + // TODO-RLVa: [RLVa-1.2.1] Check the avatar picker as well + + // Check if the user has the specified agent's profile open + return LLAvatarActions::profileVisible(idAgent); +} + +// Checked: 2010-09-11 (RLVa-1.2.1d) | Added: RLVa-1.2.1d +bool RlvUIEnabler::isBuildEnabled() +{ + return (gAgent.canEditParcel()) && ((!gRlvHandler.hasBehaviour(RLV_BHVR_EDIT)) || (!gRlvHandler.hasBehaviour(RLV_BHVR_REZ))); +} + +bool RlvUIEnabler::isBuildEnabledOrActive() +{ + return LLToolMgr::instance().inEdit() || isBuildEnabled(); +} + +// ============================================================================ diff --git a/indra/newview/rlvui.h b/indra/newview/rlvui.h new file mode 100644 index 0000000000000000000000000000000000000000..841904a86096138640d8167bca7e2539637869b6 --- /dev/null +++ b/indra/newview/rlvui.h @@ -0,0 +1,98 @@ +/** + * + * Copyright (c) 2009-2011, Kitty Barnett + * + * The source code in this file is provided to you under the terms of the + * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt + * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.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. + * + */ + +#ifndef RLV_UI_H +#define RLV_UI_H + +#include "llfloaterreg.h" +#include "llsingleton.h" + +#include "rlvdefines.h" + +// ============================================================================ +// RlvUIEnabler - self-contained class that handles disabling or reenabling certain aspects of the viewer's UI +// + +class RlvUIEnabler : public LLSingleton<RlvUIEnabler> +{ +protected: + RlvUIEnabler(); + friend class LLSingleton<RlvUIEnabler>; + friend class RlvHandler; + + /* + * Signal callbacks + */ +public: + void onBehaviourToggle(ERlvBehaviour eBhvr, ERlvParamType eType); // RlvHandler::rlv_behaviour_signal_t + + /* + * Behaviour handlers + */ +protected: + void onRefreshHoverText(); // showloc, shownames, showhovertext(all|world|hud) + void onToggleMovement(); // fly, alwaysrun and temprun + void onToggleShowLoc(); // showloc + void onToggleShowMinimap(); // showminimap + void onToggleShowWorldMap(); // showworldmap + void onToggleTp(); // tploc and tplm + void onToggleUnsit(); // unsit + void onToggleViewXXX(); // viewnote, viewscript, viewtexture + void onUpdateLoginLastLocation(bool fQuitting); // tploc and unsit + + /* + * Floater and sidebar validation callbacks + */ +public: + void addGenericFloaterFilter(const std::string& strFloaterName); + void removeGenericFloaterFilter(const std::string& strFloaterName); + +protected: + bool filterFloaterGeneric(const std::string&, const LLSD&); + boost::signals2::connection m_ConnFloaterGeneric; + bool filterFloaterShowLoc(const std::string&, const LLSD& ); + boost::signals2::connection m_ConnFloaterShowLoc; // showloc + bool filterFloaterViewXXX(const std::string&, const LLSD&); + boost::signals2::connection m_ConnFloaterViewXXX; // viewnote, viewscript, viewtexture + + bool filterPanelShowLoc(const std::string&, const std::string&, const LLSD& ); + boost::signals2::connection m_ConnPanelShowLoc; // showloc + + /* + * Helper functions + */ +public: + static bool canViewParcelProperties(); // showloc + static bool canViewRegionProperties(); // showloc + static bool hasOpenIM(const LLUUID& idAgent); // shownames + static bool hasOpenProfile(const LLUUID& idAgent); // shownames + static bool isBuildEnabled(); // edit and rez + static bool isBuildEnabledOrActive(); // edit and rez + + /* + * Member variables + */ +protected: + typedef boost::function<void(bool)> behaviour_handler_t; + typedef std::multimap<ERlvBehaviour, behaviour_handler_t> behaviour_handler_map_t; + behaviour_handler_map_t m_Handlers; + + std::multiset<std::string> m_FilteredFloaters; +}; + +// ============================================================================ + +#endif // RLV_UI_H diff --git a/indra/newview/skins/default/xui/de/menu_viewer.xml b/indra/newview/skins/default/xui/de/menu_viewer.xml index d83a6071f6e1a8b75810a16fdbc4597208b91515..dc1697f33fc13ed6bb3bbbe64784450f0b66d038 100644 --- a/indra/newview/skins/default/xui/de/menu_viewer.xml +++ b/indra/newview/skins/default/xui/de/menu_viewer.xml @@ -182,6 +182,30 @@ <menu_item_call label="INFO ÜBER [APP_NAME]" name="About Second Life"/> <menu_item_call label="Nach Updates suchen" name="Check for Updates"/> </menu> + + <menu label="RLVa" name="RLVa Main"> + <menu label="Entwickler" name="Debug"> + <menu_item_check label="RLVa Menü in der Leiste anzeigen" name="Show Top-level RLVa Menu" /> + <menu_item_check label="Debug Nachrichten anzeigen" name="Show Debug Messages" /> + <menu_item_check label="Hide Unset or Duplicate Messages" name="Hide Unset or Duplicate Messages" /> + <menu_item_check label="Fehlermeldungen anzeigen" name="Show Assertion Failures" /> + <menu_item_check label="Gesperrte Layer verstecken" name="Hide Locked Layers" /> + <menu_item_check label="Gesperrte Teile verstecken" name="Hide Locked Attachments" /> + <menu_item_check label="Enable Legacy Naming" name="Enable Legacy Naming" /> + <menu_item_check label="Shared Wear einschalten" name="Enable Shared Wear" /> + <menu_item_check label="Objekte beim anziehen umbenennen" name="Rename Shared Items on Wear" /> + <menu_item_check label="Sperren..." name="Locks" /> + </menu> + + <menu_item_check label="OOC Chat erlauben" name="Allow OOC Chat" /> + <menu_item_check label="Senden an #RLV verbieten" name="Forbid Give to #RLV" /> + <menu_item_check label="Gefilterten Chat anzeigen" name="Show Filtered Chat" /> + <menu_item_check label="Namensschilder anzeigen" name="Show Name Tags" /> + <menu_item_check label="Anziehen ersetzt unverschlossenes" name="Wear Replaces Unlocked" /> + <menu_item_check label="Einschränkungen..." name="Restrictions" /> + <menu_item_check label="Nachrichten..." name="Strings" /> + </menu> + <menu label="Erweitert" name="Advanced"> <menu_item_call label="Textur neu laden" name="Rebake Texture"/> <menu_item_call label="UI-Größe auf Standard setzen" name="Set UI Size to Default"/> diff --git a/indra/newview/skins/default/xui/en/floater_about.xml b/indra/newview/skins/default/xui/en/floater_about.xml index ec87b3684ed64cba38365d02cddd7ba755ae1cbb..660668390796746cd92177e5e58593b5136a23b4 100644 --- a/indra/newview/skins/default/xui/en/floater_about.xml +++ b/indra/newview/skins/default/xui/en/floater_about.xml @@ -10,6 +10,7 @@ title="ABOUT [CAPITALIZED_APP_NAME]" width="470"> +RestrainedLove API: [RLV_VERSION] <tab_container follows="all" top="25" diff --git a/indra/newview/skins/default/xui/en/floater_map.xml b/indra/newview/skins/default/xui/en/floater_map.xml index b8893e11d90207b5430afd4630aadccc0f57fc44..ad66f37d3cb8b1ee6b96fe3dee63b9f3d9d58604 100644 --- a/indra/newview/skins/default/xui/en/floater_map.xml +++ b/indra/newview/skins/default/xui/en/floater_map.xml @@ -14,9 +14,10 @@ save_rect="true" save_visibility="true" width="200"> + <!-- RLVa shows the anonymized name on the regular tooltip when @shownames=n restricted (rather than show the avatar inspector) --> <floater.string name="ToolTipMsg"> - [REGION](Double-click to open Map, shift-drag to pan) + [AGENT][REGION](Double-click to open Map, shift-drag to pan) </floater.string> <floater.string name="AltToolTipMsg"> diff --git a/indra/newview/skins/default/xui/en/floater_rlv_behaviours.xml b/indra/newview/skins/default/xui/en/floater_rlv_behaviours.xml new file mode 100644 index 0000000000000000000000000000000000000000..965b9172592aeb58b280d01b154e8370b6b0efd4 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_rlv_behaviours.xml @@ -0,0 +1,120 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater + open_positioning="cascading" + can_close="true" + can_minimize="true" + can_resize="true" + height="300" + min_height="300" + min_width="450" + name="rlv_behaviours" + save_rect="true" + save_visibility="false" + single_instance="true" + title="ACTIVE RLV RESTRICTIONS" + width="450"> + <tab_container + follows="all" + layout="topleft" + left="8" + name="behaviour_tab" + height="266" + right="-8" + tab_height="23" + tab_min_width="120" + tab_position="top" + top="0" > + <panel + follows="all" height="265" + label="RESTRICTIONS" + layout="topleft" + name="behaviour_panel" + top="0"> + <scroll_list + draw_border="false" + draw_heading="true" + draw_stripes="true" + follows="all" + height="266" + layout="topleft" + multi_select="false" + name="behaviour_list" + tool_tip="List of current RLVa restrictions." + top_pad="0" > + <scroll_list.columns label="Restriction" name="behaviour" width="70" /> + <scroll_list.columns label="Object Name" name="issuer" /> + </scroll_list> + </panel> + <panel + follows="all" height="265" + label="EXCEPTIONS" + layout="topleft" + name="exception_panel" + top="0"> + <scroll_list + draw_border="false" + draw_heading="true" + draw_stripes="true" + follows="all" + height="266" + layout="topleft" + multi_select="false" + name="exception_list" + tool_tip="List of current RLVa exceptions." + top_pad="0" > + <scroll_list.columns label="Exception" name="behaviour" width="70" /> + <scroll_list.columns label="Source" name="option" width="105" /> + <scroll_list.columns label="Object Name" name="issuer" /> + </scroll_list> + </panel> + <panel + follows="all" height="265" + label="MODIFIERS" + layout="topleft" + name="modifier_panel" + top="0"> + <scroll_list + draw_border="false" + draw_heading="true" + draw_stripes="true" + follows="all" + height="266" + layout="topleft" + multi_select="false" + name="modifier_list" + tool_tip="List of current RLVa modifiers." + top_pad="0" > + <scroll_list.columns label="Modifier" name="modifier" width="105" /> + <scroll_list.columns label="Value" name="value" width="105" /> + <scroll_list.columns label="Primary Object" name="primary" /> + </scroll_list> + </panel> + </tab_container> + <panel + background_visible="false" + follows="left|right|bottom" + height="25" + label="bottom_panel" + layout="topleft" + name="bottom_panel" + top_pad="0"> + <button + image_hover_unselected="Toolbar_Left_Over" + image_overlay="Copy" + image_overlay_alignment="left" + image_selected="Toolbar_Left_Selected" + image_unselected="Toolbar_Left_Off" + label="Copy to Clipboard" + left="0" + name="copy_btn" + top="1" + width="150" /> + <icon + follows="left|right" + image_name="Toolbar_Right_Off" + left_pad="1" + name="dummy_icon" + top="1" + right="-1" /> + </panel> +</floater> diff --git a/indra/newview/skins/default/xui/en/floater_rlv_console.xml b/indra/newview/skins/default/xui/en/floater_rlv_console.xml new file mode 100644 index 0000000000000000000000000000000000000000..30f2e1580032058d441ffe5ac1ca17146c37af84 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_rlv_console.xml @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater + can_resize="true" + height="400" + layout="topleft" + min_height="300" + min_width="300" + name="rlv_console" + title="RLVa console" + width="600" + > + <text_editor + follows="all" + left="10" + length="1" + font="Monospace" + height="366" + ignore_tab="false" + layout="topleft" + max_length="65536" + name="console_output" + read_only="true" + track_end="true" + type="string" + width="576" + word_wrap="true" + > + </text_editor> + <line_editor + border_style="line" + border_thickness="1" + bottom_delta="20" + follows="left|right|bottom" + font="SansSerif" + height="19" + layout="topleft" + max_length="127" + name="console_input" + top_delta="0" + width="576" + > + </line_editor> +</floater> diff --git a/indra/newview/skins/default/xui/en/floater_rlv_locks.xml b/indra/newview/skins/default/xui/en/floater_rlv_locks.xml new file mode 100644 index 0000000000000000000000000000000000000000..d6665bcef2a6d5dfc4b585b5c84f220d31ae9386 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_rlv_locks.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater + can_close="true" + can_minimize="true" + can_resize="true" + height="200" + min_height="200" + min_width="500" + name="rlvLocks" + save_rect="true" + save_visibility="false" + single_instance="true" + positioning="cascading" + reuse_instance="true" + title="ACTIVE RLV LOCKS" + width="500"> + <panel + class="panel_rlvLocks" + filename="panel_rlv_locks.xml" + layout="topleft" + left="9" + name="panel_rlvLocks" + right="-8" + top="0" /> +</floater> \ No newline at end of file diff --git a/indra/newview/skins/default/xui/en/floater_rlv_strings.xml b/indra/newview/skins/default/xui/en/floater_rlv_strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..2b31f99fb4eab7e8cbc7a2339cc0516b77a2d4eb --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_rlv_strings.xml @@ -0,0 +1,70 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater + can_minimize="false" + height="215" + layout="topleft" + legacy_header_height="18" + name="rlva_strings" + title="RLVa Strings" + width="340"> + <combo_box + allow_text_entry="false" + follows="top|left" + height="22" + layout="topleft" + left="12" + max_chars="255" + name="string_list" + top="25" + width="316" /> + <text_editor + enabled="false" + height="60" + layout="topleft" + left_delta="0" + name="string_descr" + top_pad="5" + width="317" + word_wrap="true" /> + <text_editor + enabled="true" + height="60" + layout="topleft" + left_delta="0" + name="string_value" + top_pad="5" + width="316" + word_wrap="true" /> + <panel + follows="top|left" + height="25" + layout="topleft" + left="10" + name="bottom_panel" + top="180" + right="-8"> + <button + follows="top|left" + image_hover_unselected="Toolbar_Left_Over" + image_overlay="Refresh_Off" + image_overlay_alignment="left" + image_selected="Toolbar_Left_Selected" + image_unselected="Toolbar_Left_Off" + label="Reset to default" + layout="topleft" + left="0" + name="default_btn" + top="1" + width="140" > + <button.commit_callback + function="ClickDefault" /> + </button> + <icon + follows="left|right" + image_name="Toolbar_Right_Off" + left_pad="1" + name="dummy_icon" + top="1" + right="-1" /> + </panel> +</floater> diff --git a/indra/newview/skins/default/xui/en/menu_attachment_other.xml b/indra/newview/skins/default/xui/en/menu_attachment_other.xml index 9e520b2d31b22c39e03acd5bf4986f2fc6a06047..ffba367061830bd2076e6bfc9d6e702c799a132c 100644 --- a/indra/newview/skins/default/xui/en/menu_attachment_other.xml +++ b/indra/newview/skins/default/xui/en/menu_attachment_other.xml @@ -9,6 +9,8 @@ <menu_item_call.on_click function="ShowAgentProfile" parameter="hit object" /> + <menu_item_call.on_enable + function="RLV.CanShowName" /> </menu_item_call> <menu_item_call enabled="false" @@ -24,6 +26,8 @@ name="Send IM..."> <menu_item_call.on_click function="Avatar.SendIM" /> + <menu_item_call.on_enable + function="RLV.CanShowName" /> </menu_item_call> <menu_item_call label="Call" @@ -36,8 +40,10 @@ <menu_item_call label="Invite to Group" name="Invite..."> - <menu_item_call.on_click + <menu_item_call.on_click function="Avatar.InviteToGroup" /> + <menu_item_call.on_enable + function="RLV.CanShowName" /> </menu_item_call> <menu_item_separator /> <menu_item_call diff --git a/indra/newview/skins/default/xui/en/menu_avatar_other.xml b/indra/newview/skins/default/xui/en/menu_avatar_other.xml index fadacbf3cb79122f42ec226343fab8bd2b8d7f68..07f20b11dd220a236952c252684cf5e078dbcd94 100644 --- a/indra/newview/skins/default/xui/en/menu_avatar_other.xml +++ b/indra/newview/skins/default/xui/en/menu_avatar_other.xml @@ -9,6 +9,8 @@ <menu_item_call.on_click function="ShowAgentProfile" parameter="hit object" /> + <menu_item_call.on_enable + function="RLV.CanShowName" /> </menu_item_call> <menu_item_call enabled="false" @@ -24,6 +26,8 @@ name="Send IM..."> <menu_item_call.on_click function="Avatar.SendIM" /> + <menu_item_call.on_enable + function="RLV.CanShowName" /> </menu_item_call> <menu_item_call label="Call" @@ -36,8 +40,10 @@ <menu_item_call label="Invite to Group" name="Invite..."> - <menu_item_call.on_click + <menu_item_call.on_click function="Avatar.InviteToGroup" /> + <menu_item_call.on_enable + function="RLV.CanShowName" /> </menu_item_call> <menu_item_separator /> @@ -101,6 +107,8 @@ name="Pay..."> <menu_item_call.on_click function="PayObject" /> + <menu_item_call.on_enable + function="EnablePayAvatar" /> </menu_item_call> <menu_item_separator /> diff --git a/indra/newview/skins/default/xui/en/menu_land.xml b/indra/newview/skins/default/xui/en/menu_land.xml index 2ad5cbbe951cd561d4b72ab58fa5afb16380842b..3a7f24fdf5bcd30725cd7fad0ff7a4e760886ea9 100644 --- a/indra/newview/skins/default/xui/en/menu_land.xml +++ b/indra/newview/skins/default/xui/en/menu_land.xml @@ -8,6 +8,9 @@ <menu_item_call.on_click function="Floater.Show" parameter="about_land" /> + <menu_item_call.on_enable + function="Floater.CanShow" + parameter="about_land" /> </menu_item_call> <!-- <menu_item_call label="Go Here" diff --git a/indra/newview/skins/default/xui/en/menu_place_add_button.xml b/indra/newview/skins/default/xui/en/menu_place_add_button.xml index e3a39a1242748c8b73874fc851b73cdd77f1db4a..bdd4e230b949b0327f107364c1ab29eabd5aae83 100644 --- a/indra/newview/skins/default/xui/en/menu_place_add_button.xml +++ b/indra/newview/skins/default/xui/en/menu_place_add_button.xml @@ -23,5 +23,8 @@ <on_click function="Places.LandmarksGear.Add.Action" parameter="add_landmark" /> + <on_enable + function="Places.LandmarksGear.Enable" + parameter="add_landmark" /> </menu_item_call> </menu> diff --git a/indra/newview/skins/default/xui/en/menu_places_gear_folder.xml b/indra/newview/skins/default/xui/en/menu_places_gear_folder.xml index 1aeb166e01570aaccb4ead89d93c7a887e3a4cad..4d59ab06317bfc97007a222ff866d8a76d0aa63e 100644 --- a/indra/newview/skins/default/xui/en/menu_places_gear_folder.xml +++ b/indra/newview/skins/default/xui/en/menu_places_gear_folder.xml @@ -13,6 +13,9 @@ <on_click function="Places.LandmarksGear.Add.Action" parameter="add_landmark" /> + <on_enable + function="Places.LandmarksGear.Enable" + parameter="add_landmark" /> </menu_item_call> <menu_item_call label="Add Folder" diff --git a/indra/newview/skins/default/xui/en/menu_places_gear_landmark.xml b/indra/newview/skins/default/xui/en/menu_places_gear_landmark.xml index ff5fdd3795322d5c3582f0b7ff7d73b3240c6d29..28c74a3d5d1813b75f8966bb9e51e2b9bfe0b95e 100644 --- a/indra/newview/skins/default/xui/en/menu_places_gear_landmark.xml +++ b/indra/newview/skins/default/xui/en/menu_places_gear_landmark.xml @@ -48,6 +48,9 @@ <on_click function="Places.LandmarksGear.Add.Action" parameter="add_landmark" /> + <on_enable + function="Places.LandmarksGear.Enable" + parameter="add_landmark" /> </menu_item_call> <menu_item_call label="Add Folder" diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index b189d1038fa7aade97566327c68992788db68e75..c1578129b711b8d26b22ec63368985945b72513f 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -492,6 +492,8 @@ name="Place Profile"> <menu_item_call.on_click function="World.PlaceProfile" /> + <menu_item_call.on_enable + function="World.EnablePlaceProfile" /> </menu_item_call> <menu_item_call label="About land" @@ -499,6 +501,9 @@ <menu_item_call.on_click function="Floater.Show" parameter="about_land" /> + <menu_item_call.on_enable + function="Floater.CanShow" + parameter="about_land" /> </menu_item_call> <menu_item_call label="Region / Estate" @@ -506,6 +511,9 @@ <menu_item_call.on_click function="Floater.Show" parameter="region_info" /> + <menu_item_call.on_enable + function="Floater.CanShow" + parameter="region_info" /> </menu_item_call> <menu_item_call label="My land holdings..." @@ -638,6 +646,9 @@ <menu_item_check.on_check function="World.EnableEnvSettings" parameter="sunrise" /> + <menu_item_check.on_enable + function="RLV.EnableIfNot" + parameter="setenv" /> </menu_item_check> <menu_item_check label="Midday" @@ -649,6 +660,9 @@ <menu_item_check.on_check function="World.EnableEnvSettings" parameter="noon" /> + <menu_item_check.on_enable + function="RLV.EnableIfNot" + parameter="setenv" /> </menu_item_check> <menu_item_check label="Sunset" @@ -660,6 +674,9 @@ <menu_item_check.on_check function="World.EnableEnvSettings" parameter="sunset" /> + <menu_item_check.on_enable + function="RLV.EnableIfNot" + parameter="setenv" /> </menu_item_check> <menu_item_check label="Midnight" @@ -670,6 +687,9 @@ <menu_item_check.on_check function="World.EnableEnvSettings" parameter="midnight" /> + <menu_item_check.on_enable + function="RLV.EnableIfNot" + parameter="setenv" /> </menu_item_check> <menu_item_separator/> <menu_item_check @@ -681,6 +701,9 @@ <menu_item_check.on_check function="World.EnableEnvSettings" parameter="region" /> + <menu_item_check.on_enable + function="RLV.EnableIfNot" + parameter="setenv" /> </menu_item_check> </menu> @@ -697,6 +720,9 @@ <menu_item_call.on_click function="World.EnvSettings" parameter="editor"/> + <menu_item_call.on_enable + function="RLV.EnableIfNot" + parameter="setenv" /> </menu_item_call> <menu_item_separator/> @@ -710,6 +736,9 @@ <menu_item_call.on_click function="World.EnvPreset" parameter="new_water"/> + <menu_item_call.on_enable + function="RLV.EnableIfNot" + parameter="setenv" /> </menu_item_call> <menu_item_call label="Edit preset..." @@ -717,7 +746,10 @@ <menu_item_call.on_click function="World.EnvPreset" parameter="edit_water"/> - </menu_item_call> + <menu_item_call.on_enable + function="RLV.EnableIfNot" + parameter="setenv" /> + </menu_item_call> <menu_item_call label="Delete preset..." name="delete_water_preset"> @@ -739,14 +771,20 @@ <menu_item_call.on_click function="World.EnvPreset" parameter="new_sky"/> - </menu_item_call> + <menu_item_call.on_enable + function="RLV.EnableIfNot" + parameter="setenv" /> + </menu_item_call> <menu_item_call label="Edit preset..." name="edit_sky_preset"> <menu_item_call.on_click function="World.EnvPreset" parameter="edit_sky"/> - </menu_item_call> + <menu_item_call.on_enable + function="RLV.EnableIfNot" + parameter="setenv" /> + </menu_item_call> <menu_item_call label="Delete preset..." name="delete_sky_preset"> @@ -768,14 +806,20 @@ <menu_item_call.on_click function="World.EnvPreset" parameter="new_day_cycle"/> - </menu_item_call> + <menu_item_call.on_enable + function="RLV.EnableIfNot" + parameter="setenv" /> + </menu_item_call> <menu_item_call label="Edit preset..." name="edit_day_preset"> <menu_item_call.on_click function="World.EnvPreset" parameter="edit_day_cycle"/> - </menu_item_call> + <menu_item_call.on_enable + function="RLV.EnableIfNot" + parameter="setenv" /> + </menu_item_call> <menu_item_call label="Delete preset..." name="delete_day_preset"> @@ -1446,6 +1490,204 @@ function="Advanced.CheckViewerUpdates"/> </menu_item_call> </menu> + <menu + create_jump_keys="true" + label="RLVa" + name="RLVa Main" + tear_off="true" + visible="true"> + <menu + label="Develop" + name="Debug" + tear_off="true"> + <menu_item_check + label="Show Top-level RLVa Menu" + name="Show Top-level RLVa Menu"> + <menu_item_check.on_check + function="CheckControl" + parameter="RLVaTopLevelMenu" /> + <menu_item_check.on_click + function="ToggleControl" + parameter="RLVaTopLevelMenu" /> + </menu_item_check> + <menu_item_separator/> + <menu_item_check + label="Show Debug Messages" + name="Show Debug Messages"> + <menu_item_check.on_check + function="CheckControl" + parameter="RestrainedLoveDebug" /> + <menu_item_check.on_click + function="ToggleControl" + parameter="RestrainedLoveDebug" /> + </menu_item_check> + <menu_item_check + label="Hide Unset or Duplicate Messages" + name="Hide Unset or Duplicate Messages"> + <menu_item_check.on_check + function="CheckControl" + parameter="RLVaDebugHideUnsetDuplicate" /> + <menu_item_check.on_click + function="ToggleControl" + parameter="RLVaDebugHideUnsetDuplicate" /> + </menu_item_check> + <menu_item_check + label="Show Assertion Failures" + name="Show Assertion Failures"> + <menu_item_check.on_check + function="CheckControl" + parameter="RLVaShowAssertionFailures" /> + <menu_item_check.on_click + function="ToggleControl" + parameter="RLVaShowAssertionFailures" /> + </menu_item_check> + <menu_item_separator/> + <menu_item_check + label="Hide Locked Layers" + name="Hide Locked Layers"> + <menu_item_check.on_check + function="CheckControl" + parameter="RLVaHideLockedLayers" /> + <menu_item_check.on_click + function="ToggleControl" + parameter="RLVaHideLockedLayers" /> + </menu_item_check> + <menu_item_check + label="Hide Locked Attachments" + name="Hide Locked Attachments"> + <menu_item_check.on_check + function="CheckControl" + parameter="RLVaHideLockedAttachments" /> + <menu_item_check.on_click + function="ToggleControl" + parameter="RLVaHideLockedAttachments" /> + </menu_item_check> + <menu_item_separator/> + <menu_item_check + label="Enable Legacy Naming" + name="Enable Legacy Naming"> + <menu_item_check.on_check + function="CheckControl" + parameter="RLVaEnableLegacyNaming" /> + <menu_item_check.on_click + function="ToggleControl" + parameter="RLVaEnableLegacyNaming" /> + </menu_item_check> + <menu_item_check + label="Enable Shared Wear" + name="Enable Shared Wear"> + <menu_item_check.on_check + function="CheckControl" + parameter="RLVaEnableSharedWear" /> + <menu_item_check.on_click + function="ToggleControl" + parameter="RLVaEnableSharedWear" /> + </menu_item_check> + <menu_item_check + label="Rename Shared Items on Wear" + name="Rename Shared Items on Wear"> + <menu_item_check.on_check + function="CheckControl" + parameter="RLVaSharedInvAutoRename" /> + <menu_item_check.on_click + function="ToggleControl" + parameter="RLVaSharedInvAutoRename" /> + </menu_item_check> + <menu_item_separator/> + <menu_item_check + label="Locks..." + name="Locks"> + <menu_item_check.on_check + function="Floater.Visible" + parameter="rlv_locks" /> + <menu_item_check.on_click + function="Floater.Toggle" + parameter="rlv_locks" /> + </menu_item_check> + </menu> + <menu_item_separator/> + <menu_item_check + label="Allow OOC Chat" + name="Allow OOC Chat"> + <menu_item_check.on_check + function="CheckControl" + parameter="RestrainedLoveCanOOC" /> + <menu_item_check.on_click + function="ToggleControl" + parameter="RestrainedLoveCanOOC" /> + </menu_item_check> + <menu_item_check + label="Allow Temporary Attachments" + name="Allow Temporary Attachments"> + <menu_item_check.on_check + function="CheckControl" + parameter="RLVaEnableTemporaryAttachments" /> + <menu_item_check.on_click + function="ToggleControl" + parameter="RLVaEnableTemporaryAttachments" /> + </menu_item_check> + <menu_item_check + label="Forbid Give to #RLV" + name="Forbid Give to #RLV"> + <menu_item_check.on_check + function="CheckControl" + parameter="RestrainedLoveForbidGiveToRLV" /> + <menu_item_check.on_click + function="ToggleControl" + parameter="RestrainedLoveForbidGiveToRLV" /> + </menu_item_check> + <menu_item_check + label="Show Filtered Chat" + name="Show Filtered Chat"> + <menu_item_check.on_check + function="CheckControl" + parameter="RestrainedLoveShowEllipsis" /> + <menu_item_check.on_click + function="ToggleControl" + parameter="RestrainedLoveShowEllipsis" /> + </menu_item_check> + <menu_item_check + label="Wear Replaces Unlocked" + name="Wear Replaces Unlocked"> + <menu_item_check.on_check + function="CheckControl" + parameter="RLVaWearReplaceUnlocked" /> + <menu_item_check.on_click + function="ToggleControl" + parameter="RLVaWearReplaceUnlocked" /> + </menu_item_check> + <menu_item_separator /> + <menu_item_check + label="Console..." + name="Console"> + <menu_item_check.on_check + function="Floater.Visible" + parameter="rlv_console" /> + <menu_item_check.on_click + function="Floater.Toggle" + parameter="rlv_console" /> + </menu_item_check> + <menu_item_check + label="Restrictions..." + name="Restrictions"> + <menu_item_check.on_check + function="Floater.Visible" + parameter="rlv_behaviours" /> + <menu_item_check.on_click + function="Floater.Toggle" + parameter="rlv_behaviours" /> + </menu_item_check> + <menu_item_check + label="Strings..." + name="Strings"> + <menu_item_check.on_check + function="Floater.Visible" + parameter="rlv_strings" /> + <menu_item_check.on_click + function="Floater.Toggle" + parameter="rlv_strings" /> + </menu_item_check> + </menu> <menu create_jump_keys="true" label="Advanced" @@ -1905,6 +2147,11 @@ parameter="flexible" /> </menu_item_check> </menu> + <menu + label="RLVa" + name="RLVa Embedded" + tear_off="true" + visible="true" /> <menu_item_check label="Use Plugin Read Thread" name="Use Plugin Read Thread"> @@ -2061,7 +2308,18 @@ </menu> <!--Shortcuts--> <menu_item_separator/> - + <menu_item_check + label="RestrainedLove API" + name="RLV API"> + <menu_item_check.on_check + function="CheckControl" + parameter="RestrainedLove" /> + <menu_item_check.on_click + function="ToggleControl" + parameter="RestrainedLove" /> + <menu_item_check.on_visible + function="RLV.MainToggleVisible" /> + </menu_item_check> <menu_item_call label="Show Debug Settings" name="Debug Settings"> diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index b2425649a4d26df701e95f9c9df8ef4df46d2318..fe898ec9e44988e77dd46b016b49d3450746f340 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -7256,6 +7256,7 @@ Your object named <nolink>[OBJECTFROMNAME]</nolink> has given you th <notification icon="notify.tga" name="UserGiveItem" + label="Inventory offer from [NAME_LABEL]" log_to_im ="true" type="offer" sound="UISndNewIncomingIMSession"> @@ -7313,6 +7314,7 @@ Your object named <nolink>[OBJECTFROMNAME]</nolink> has given you th <notification icon="notify.tga" name="TeleportOffered" + label="Teleport offer from [NAME_LABEL]" log_to_im="true" log_to_chat="false" type="offer" @@ -7428,6 +7430,7 @@ Offer a teleport? <notification icon="notify.tga" name="OfferFriendship" + label="Friendship offer from [NAME_LABEL]" log_to_im="true" type="offer"> <tag>friendship</tag> @@ -7461,6 +7464,7 @@ Offer a teleport? <notification icon="notify.tga" name="OfferFriendshipNoMessage" + label="Friendship offer from [NAME_LABEL]" persist="true" type="notify"> <tag>friendship</tag> @@ -11009,6 +11013,13 @@ An internal error prevented us from properly updating your viewer. The L$ balan <tag>fail</tag> Cannot create large prims that intersect other players. Please re-try when other players have moved. </notification> + + <notification + icon="alertmodal.tga" + name="RLVChangeStrings" + type="alertmodal"> +Changes won't take effect until after you restart [APP_NAME]. + </notification> <notification icon="alertmodal.tga" diff --git a/indra/newview/skins/default/xui/en/panel_people.xml b/indra/newview/skins/default/xui/en/panel_people.xml index 2cb06d6877c57bbc999f7568d08f5bc7bf7c7fb9..6508f5a35d9c63814e3ee69203c5713fa77c3f40 100644 --- a/indra/newview/skins/default/xui/en/panel_people.xml +++ b/indra/newview/skins/default/xui/en/panel_people.xml @@ -184,6 +184,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M layout="topleft" min_dim="100" mouse_opaque="false" + name="Net Map Panel" user_resize="true" visibility_control="NearbyListShowMap" width="313"> diff --git a/indra/newview/skins/default/xui/en/panel_rlv_locks.xml b/indra/newview/skins/default/xui/en/panel_rlv_locks.xml new file mode 100644 index 0000000000000000000000000000000000000000..80373af1f4a3fd262ecd9ad5ddac0590c8be4ef7 --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_rlv_locks.xml @@ -0,0 +1,52 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel + follows="all" + height="200" + label="ACTIVE RLV LOCKS" + layout="topleft" + name="panel_rlvLocks" + top="0" + width="500"> + <scroll_list + draw_border="false" + draw_heading="true" + draw_stripes="true" + follows="all" + height="167" + layout="topleft" + multi_select="false" + name="lock_list" + top_pad="0" > + <scroll_list.columns label="Lock Type" name="lock_type" width="100" /> + <scroll_list.columns label="Method" name="lock_addrem" width="60" /> + <scroll_list.columns label="Target Object / Point" name="lock_target" /> + <scroll_list.columns label="Lock Origin" name="lock_origin" width="150" /> + </scroll_list> + <panel + background_visible="false" + follows="left|right|bottom" + height="25" + label="bottom_panel" + layout="topleft" + name="bottom_panel" + top_pad="0" > + <button + image_hover_unselected="Toolbar_Left_Over" + image_overlay="Refresh_Off" + image_overlay_alignment="left" + image_selected="Toolbar_Left_Selected" + image_unselected="Toolbar_Left_Off" + label="Refresh" + left="0" + name="refresh_btn" + top="1" + width="90" /> + <icon + follows="left|right" + image_name="Toolbar_Right_Off" + left_pad="1" + name="dummy_icon" + top="1" + right="-1"/> + </panel> +</panel> \ No newline at end of file diff --git a/indra/newview/skins/default/xui/en/rlva_strings.xml b/indra/newview/skins/default/xui/en/rlva_strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..922173282b964fc3d1e82baddd7f08260cdb6c4c --- /dev/null +++ b/indra/newview/skins/default/xui/en/rlva_strings.xml @@ -0,0 +1,169 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<llsd> +<map> + + <key>strings</key> + <map> + <!-- Primarily used when @showloc restricted --> + <key>hidden_generic</key> + <map> + <key>value</key> + <string>(Hidden)</string> + </map> + <key>hidden_parcel</key> + <map> + <key>value</key> + <string>(Hidden parcel)</string> + </map> + <key>hidden_region</key> + <map> + <key>value</key> + <string>(Hidden region)</string> + </map> + + <!-- Received/sent IMs will be replaced by the matching string when @recvim/sendim restricted --> + <key>blocked_recvim</key> + <map> + <key>value</key> + <string>*** IM blocked by your viewer</string> + <key>description</key> + <string>Shown in place of the original message when an incoming IM is blocked</string> + <key>label</key> + <string>Blocked incoming IM message (local)</string> + <key>customizable</key> + <boolean>1</boolean> + </map> + <key>blocked_sendim</key> + <map> + <key>value</key> + <string>*** IM blocked by sender's viewer</string> + <key>description</key> + <string>Shown (and sent to the remote party) when an outgoing IM is blocked</string> + <key>label</key> + <string>Blocked outgoing IM message (local + remote)</string> + <key>customizable</key> + <boolean>1</boolean> + </map> + + <!-- Shown as notifications --> + <key>blocked_autopilot</key> + <map> + <key>value</key> + <string>Unable to use the autopilot due to RLV restrictions</string> + </map> + <key>blocked_generic</key> + <map> + <key>value</key> + <string>Unable to perform action due to RLV restrictions</string> + </map> + <key>blocked_groupchange</key> + <map> + <key>value</key> + <string>Unable to change your active group due to an RLV restriction; switching back to [GROUP_SLURL]</string> + </map> + <key>blocked_nearby</key> + <map> + <key>value</key> + <string>Unable to see the presence of nearby avatars due to RLV restrictions</string> + </map> + <key>blocked_permattach</key> + <map> + <key>value</key> + <string>Attempt to attach '[OBJECT]' was denied due to RLV restrictions</string> + </map> + <key>blocked_permteleport</key> + <map> + <key>value</key> + <string>[OBJECT]' was denied permission to teleport you due to RLV restrictions</string> + </map> + <key>blocked_startim</key> + <map> + <key>value</key> + <string>Unable to start IM session with [RECIPIENT] due to RLV restrictions</string> + </map> + <key>blocked_startconf</key> + <map> + <key>value</key> + <string>Unable to start conference with [RECIPIENT] due to RLV restrictions</string> + </map> + <key>blocked_teleport</key> + <map> + <key>value</key> + <string>Unable to initiate teleport due to RLV restrictions</string> + </map> + <key>blocked_teleport_offer</key> + <map> + <key>value</key> + <string>Unable to offer teleport due to RLV restrictions</string> + </map> + <key>blocked_viewxxx</key> + <map> + <key>value</key> + <string>Unable to open [TYPE] due to RLV restrictions</string> + </map> + <key>blocked_wireframe</key> + <map> + <key>value</key> + <string>Unable to enable wireframe mode due to RLV restrictions</string> + </map> + + <!-- Sent as "Busy" messages to the remote party --> + <key>blocked_recvim_remote</key> + <map> + <key>value</key> + <string>The Resident you messaged is currently prevented from reading your instant messages at the moment, please try again later.</string> + <key>description</key> + <string>Sent to the remote party when their IM was blocked</string> + <key>label</key> + <string>Blocked incoming IM message (remote)</string> + <key>customizable</key> + <boolean>1</boolean> + </map> + <key>blocked_tplurerequest_remote</key> + <map> + <key>value</key> + <string>The Resident is currently prevented from accepting. Please try again later.</string> + <key>description</key> + <string>Sent to the remote party when their teleport offer or request was blocked</string> + <key>label</key> + <string>Blocked teleport offer/request (remote)</string> + <key>customizable</key> + <boolean>1</boolean> + </map> + </map> + + <!-- Generic names used to replace resident names when @shownames restricted --> + <key>anonyms</key> + <array> + <string>A resident</string> + <string>This resident</string> + <string>That resident</string> + <string>An individual</string> + <string>This individual</string> + <string>That individual</string> + <string>A person</string> + <string>This person</string> + <string>That person</string> + <string>A stranger</string> + <string>This stranger</string> + <string>That stranger</string> + <string>A being</string> + <string>This being</string> + <string>That being</string> + <string>An agent</string> + <string>This agent</string> + <string>That agent</string> + <string>A soul</string> + <string>This soul</string> + <string>That soul</string> + <string>Somebody</string> + <string>Some people</string> + <string>Someone</string> + <string>Mysterious one</string> + <string>An unknown being</string> + <string>Unidentified one</string> + <string>An unknown person</string> + </array> + +</map> +</llsd> diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index 8988c3e0289916ed7f98758ae0ce5cb4ff66b0a5..c217014eefdbefe3e1a57b3df4a5ccd1e7067dac 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -32,6 +32,11 @@ You are at [POSITION_LOCAL_0,number,1], [POSITION_LOCAL_1,number,1], [POSITION_L SLURL: <nolink>[SLURL]</nolink> (global coordinates [POSITION_0,number,1], [POSITION_1,number,1], [POSITION_2,number,1]) [SERVER_VERSION] +[SERVER_RELEASE_NOTES_URL] + </string> + <string name="AboutPositionRLVShowLoc"> +You are in [REGION] +[SERVER_VERSION] [SERVER_RELEASE_NOTES_URL] </string> <!-- *NOTE: Do not translate text like GPU, Graphics Card, etc - @@ -48,6 +53,7 @@ Graphics Card: [GRAPHICS_CARD] <string name="AboutLibs"> OpenGL Version: [OPENGL_VERSION] +RestrainedLove API: [RLV_VERSION] J2C Decoder Version: [J2C_VERSION] Audio Driver Version: [AUDIO_DRIVER_VERSION] LLCEFLib/CEF Version: [LLCEFLIB_VERSION] @@ -3570,6 +3576,9 @@ If you continue to receive this message, contact the [SUPPORT_SITE]. <string name="inventory_item_offered-im"> Inventory item offered </string> + <string name="inventory_item_offered_rlv"> + Inventory item offered to [NAME] + </string> <string name="share_alert"> Drag items from inventory here </string> @@ -4091,6 +4100,12 @@ Try enclosing path to the editor with double quotes. <!-- Spell check settings floater --> <string name="UserDictionary">[User]</string> + <!-- RLVa --> + <string name="RLVaPendingRestart"> (pending restart)</string> + <string name="RLVaToggleMessage">RestrainedLove Support will be %s after you restart</string> + <string name="RLVaToggleEnabled">enabled</string> + <string name="RLVaToggleDisabled">disabled</string> + <!-- Experience Tools strings --> <string name="experience_tools_experience">Experience</string> <string name="ExperienceNameNull">(no experience)</string> diff --git a/indra/newview/tests/llslurl_test.cpp b/indra/newview/tests/llslurl_test.cpp index 4694f657b61031699ef13a45fa91ed23eb09015b..a6883f6e37406375da9a278a693288f91e230b05 100644 --- a/indra/newview/tests/llslurl_test.cpp +++ b/indra/newview/tests/llslurl_test.cpp @@ -54,6 +54,34 @@ std::string LLTrans::getString(const std::string &xml_desc, const LLStringUtil:: return std::string(); } +// [RLVa:KB] - Checked: 2010-11-12 (RLVa-1.2.2a) | Added: RLVa-1.2.2a +// Stub implementation to get the test to compile properly +#include "../rlvhandler.h" + +const std::string& RlvStrings::getString(const std::string& strStringName) +{ + static const std::string strMissing = "(Missing RLVa string)"; + return strMissing; +} + +bool RlvUtil::isNearbyRegion(const std::string& strRegion) +{ + return false; +} + +RlvHandler::RlvHandler() : m_pGCTimer(NULL), m_pWLSnapshot(NULL) +{ + // Array auto-initialization to 0 is non-standard? (Compiler warning in VC-8.0) + memset(m_Behaviours, 0, sizeof(S16) * RLV_BHVR_COUNT); +} + +RlvHandler::~RlvHandler() +{ +} + +RlvHandler gRlvHandler; +// [/RLVa:KB] + //---------------------------------------------------------------------------- // Mock objects for the dependencies of the code we're testing diff --git a/indra/viewer_components/updater/scripts/windows/update_install.bat b/indra/viewer_components/updater/scripts/windows/update_install.bat index 96687226a8d3d243cdb268707a4eecefbb1d33e1..ecb6e357b41d507036fbcaa755be92d4fd8a9269 100644 --- a/indra/viewer_components/updater/scripts/windows/update_install.bat +++ b/indra/viewer_components/updater/scripts/windows/update_install.bat @@ -1,3 +1,3 @@ -start /WAIT %1 /SKIP_DIALOGS -IF ERRORLEVEL 1 ECHO %3 > %2 -DEL %1 +start /WAIT %1 /SKIP_DIALOGS +IF ERRORLEVEL 1 ECHO %3 > %2 +DEL %1