diff --git a/.hgpatchinfo/RLVa.dep b/.hgpatchinfo/RLVa.dep new file mode 100644 index 0000000000000000000000000000000000000000..09b266c2d8d5ba9d7240f692265e30dd5463f58b --- /dev/null +++ b/.hgpatchinfo/RLVa.dep @@ -0,0 +1 @@ +dd7f770961c9455fbd6b7c74c82b7048f9ebef4d \ No newline at end of file diff --git a/.hgtags b/.hgtags index 9139aae9a4ac2ec79d98a995cd93944c6d0d954a..bad12f4d7fbb5c2d7a36bbce76adcd358927b7de 100644 --- a/.hgtags +++ b/.hgtags @@ -27,6 +27,7 @@ d2382d374139850efa5bb6adfb229e3e656cfc40 howard-demo d40ac9dd949cba6dab1cc386da6a2027690c2519 alpha-5 d6781e22543acd7e21b967209f3c6e7003d380e3 fork to viewer-2-0 c6e6324f5be1401f077ad18a4a0f6b46451c2f7b last_sprint +425f96b1e81e01644bf5e951961e7d1023bffb89 RLVa-1.2.0 0000000000000000000000000000000000000000 v2start 0000000000000000000000000000000000000000 2-1rn1 0000000000000000000000000000000000000000 2-1-beta-2 diff --git a/indra/llcommon/llchat.h b/indra/llcommon/llchat.h index 52b85c7bba132691d43b7022a1e73b44cdd106ab..c64d9a13b3f62565c63b3e4b40488f2f695f3abc 100644 --- a/indra/llcommon/llchat.h +++ b/indra/llcommon/llchat.h @@ -81,6 +81,10 @@ public: 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 @@ public: 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/llfloaterreg.cpp b/indra/llui/llfloaterreg.cpp index ccffe98c9653c3bf3874f712b4a7ac7d3d4044e7..1936bbefe6cbb849cac294392e852d21953b19f4 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.2.0a) | Modified: RLVa-1.2.0a +LLFloaterReg::validate_signal_t LLFloaterReg::mValidateSignal; +// [/RLVa:KB] + //******************************************************* //static @@ -214,9 +218,12 @@ LLFloaterReg::const_instance_list_t& LLFloaterReg::getFloaterList(const std::str //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.2.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 94387fb41a5b18e2b065eaf36eddc04c9b0b4a2d..c2c82de70cea11385079e3606132b8e6e40a9827 100644 --- a/indra/llui/llfloaterreg.h +++ b/indra/llui/llfloaterreg.h @@ -75,6 +75,15 @@ private: */ static std::set<std::string> sAlwaysShowableList; +// [RLVa:KB] - Checked: 2010-02-28 (RLVa-1.2.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 diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index ac710dea48c36e80accaaa18ccf8785f198b1930..e07b2cc9fa61c4d25d97c2762b400a68ae523be2 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -564,6 +564,14 @@ set(viewer_SOURCE_FILES llxmlrpctransaction.cpp noise.cpp pipeline.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 @@ -1087,6 +1095,15 @@ set(viewer_HEADER_FILES macmain.h noise.h pipeline.h + rlvdefines.h + rlvhandler.h + rlvhelper.h + rlvcommon.h + rlvlocks.h + rlvinventory.h + rlvextensions.h + rlvfloaters.h + rlvui.h VertexCache.h VorbisFramework.h ) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 91d5e6e724ee9605c07c46c9fa8ad74e3fd7bd46..2821d30c97a7bf49bef5da59fab20d3b7a4ee4a9 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -1,6 +1,149 @@ <?xml version="1.0" ?> <llsd> <map> + <key>RestrainedLove</key> + <map> + <key>Comment</key> + <string>Toggles the RestrainedLove features (BDSM lockable toys support). Needs a restart of the viewer.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> + <key>RestrainedLoveDebug</key> + <map> + <key>Comment</key> + <string>Toggles the RestrainedLove 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> + <integer>0</integer> + </map> + <key>RestrainedLoveNoSetEnv</key> + <map> + <key>Comment</key> + <string>When TRUE, forbids to set the environment (time of day and Windlight settings) via RestrainedLove. Needs a restart of the viewer.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> + <key>RestrainedLoveForbidGiveToRLV</key> + <map> + <key>Comment</key> + <string>When FALSE, allows to give sub-folders to the #RLV RestrainedLove folder.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </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> + <integer>0</integer> + </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> + <integer>0</integer> + </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> + <integer>1</integer> + </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> + <integer>0</integer> + </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> + <integer>0</integer> + </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> + <integer>0</integer> + </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> + <integer>1</integer> + </map> + <key>RLVaShowNameTags</key> + <map> + <key>Comment</key> + <string>Display of names above avatars is subject to the general "Show Names" setting when @shownames=n restricted</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> + <key>WarnFirstRLVGiveToRLV</key> + <map> + <key>Comment</key> + <string>Enables FirstRLVGiveToRLV warning dialog</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> <key>CrashHostUrl</key> <map> <key>Comment</key> diff --git a/indra/newview/app_settings/settings_per_account.xml b/indra/newview/app_settings/settings_per_account.xml index dc76a4e5183ad137b5917aaa933d311b46c7369f..0b18994aff2831d448518adf13f14d3661496f9d 100644 --- a/indra/newview/app_settings/settings_per_account.xml +++ b/indra/newview/app_settings/settings_per_account.xml @@ -1,6 +1,17 @@ <llsd> <map> - <key>BusyResponseChanged</key> + <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> + <integer>1</integer> + </map> + <key>BusyResponseChanged</key> <map> <key>Comment</key> <string>Does user's busy mode message differ from default?</string> diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index fe7e883d8382a8e525e6ac31fd7bab9f6bcc41f6..42a3da88735604fbcdf566c94f4e3c0ebcd4cd02 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -75,6 +75,9 @@ #include "llwindow.h" #include "llworld.h" #include "llworldmap.h" +// [RLVa:KB] - Checked: 2010-03-07 (RLVa-1.2.0c) +#include "rlvhandler.h" +// [/RLVa:KB] using namespace LLVOAvatarDefines; @@ -451,6 +454,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(); @@ -499,6 +505,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) { @@ -553,7 +566,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()) || (gRlvHandler.canStand()) ) + { + setControlFlags(AGENT_CONTROL_STAND_UP); + } +// [/RLVa:KB] } @@ -829,7 +849,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()) || ((gRlvHandler.canStand()) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SIT))) ) + { + setControlFlags(AGENT_CONTROL_SIT_ON_GROUND); + } +// [/RLVa:KB] } @@ -2076,7 +2103,15 @@ 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 +#ifdef RLV_EXTENSION_CMD_ALLOWIDLE + if (!gRlvHandler.hasBehaviour(RLV_BHVR_ALLOWIDLE)) + clearAFK(); +#else clearAFK(); +#endif // RLV_EXTENSION_CMD_ALLOWIDLE +// [/RLVa:KB] } else if (id == ANIM_AGENT_STANDUP) { @@ -3292,6 +3327,17 @@ 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())) )) + { + return; + } +// [/RLVa:KB] + LLViewerRegion *regionp = getRegion(); if(regionp && teleportCore()) { @@ -3356,6 +3402,24 @@ void LLAgent::teleportCancel() void LLAgent::teleportViaLocation(const LLVector3d& pos_global) { +// [RLVa:KB] - Checked: 2010-03-02 (RLVa-1.2.0c) | Modified: RLVa-1.2.0a + if ( (rlv_handler_t::isEnabled()) && (!RlvUtil::isForceTp()) ) + { + // If we're getting teleported due to @tpto we should disregard any @tploc=n or @unsit=n restrictions from the same object + if ( (gRlvHandler.hasBehaviourExcept(RLV_BHVR_TPLOC, gRlvHandler.getCurrentObject())) || + ( (isAgentAvatarValid()) && (gAgentAvatarp->isSitting()) && + (gRlvHandler.hasBehaviourExcept(RLV_BHVR_UNSIT, gRlvHandler.getCurrentObject()))) ) + { + return; + } + + if ( (gRlvHandler.getCurrentCommand()) && (RLV_BHVR_TPTO == gRlvHandler.getCurrentCommand()->getBehaviourType()) ) + { + gRlvHandler.setCanCancelTp(false); + } + } +// [/RLVa:KB] + LLViewerRegion* regionp = getRegion(); U64 handle = to_region_handle(pos_global); LLSimInfo* info = LLWorldMap::getInstance()->simInfoFromHandle(handle); diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp index 68e408d3e4aa9264e31cc8f6f465cba1e4e8c8cc..1f87f53191b68ba313c312755a56a7c81a63c2ce 100644 --- a/indra/newview/llagentcamera.cpp +++ b/indra/newview/llagentcamera.cpp @@ -48,6 +48,9 @@ #include "llvoavatarself.h" #include "llwindow.h" #include "llworld.h" +// [RLVa:KB] - Checked: 2010-05-10 (RLVa-1.2.0g) +#include "rlvhandler.h" +// [/RLVa:KB] using namespace LLVOAvatarDefines; @@ -2253,6 +2256,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()) && (!gRlvHandler.canStand()) ) + { + return; + } +// [/RLVa:KB] + gAgent.standUp(); // force stand up gViewerWindow->getWindow()->resetBusyCount(); diff --git a/indra/newview/llagentlistener.cpp b/indra/newview/llagentlistener.cpp index d520debc31f9f37e70b53f552b815f2c75661b09..66f3853e792d4f5dc36fc85526f1e13ca0ca3f2a 100644 --- a/indra/newview/llagentlistener.cpp +++ b/indra/newview/llagentlistener.cpp @@ -37,6 +37,9 @@ #include "llviewerobject.h" #include "llviewerobjectlist.h" #include "llviewerregion.h" +// [RLVa:KB] - Checked: 2010-03-06 (RLVa-1.2.0c) +#include "rlvhandler.h" +// [/RLVa:KB] LLAgentListener::LLAgentListener(LLAgent &agent) : LLEventAPI("LLAgent", @@ -85,8 +88,28 @@ void LLAgentListener::requestSit(LLSD const & event_data) const // *TODO - find a permanent place to share this code properly. LLViewerObject *object = gObjectList.findObject(event_data["obj_uuid"]); +// [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()) && (!gRlvHandler.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()); @@ -101,6 +124,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()) && (!gRlvHandler.canStand()) ) + { + return; + } +// [/RLVa:KB] + mAgent.setControlFlags(AGENT_CONTROL_STAND_UP); } diff --git a/indra/newview/llagentui.cpp b/indra/newview/llagentui.cpp index f52f1361181f948a011312c35832d2a8f8f8dfd1..c2c23f30fa31bcd3d89600ed90f70b4af4a1998f 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::buildName(std::string& name) @@ -122,6 +125,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 d7d2cadfe6a6e79c910a35a519d846be12a72570..b79e70c768b3b034ea49b56e71787b146bd58770 100644 --- a/indra/newview/llagentwearables.cpp +++ b/indra/newview/llagentwearables.cpp @@ -49,6 +49,9 @@ #include "llvoavatarself.h" #include "llwearable.h" #include "llwearablelist.h" +// [RLVa:KB] - Checked: RLVa-1.2.0a (2010-03-04) +#include "rlvhandler.h" +// [/RLVa:KB] #include <boost/scoped_ptr.hpp> @@ -763,12 +766,28 @@ U32 LLAgentWearables::pushWearable(const LLWearableType::EType type, LLWearable llwarns << "Null wearable sent for type " << type << llendl; return MAX_CLOTHING_PER_TYPE; } - if (type < LLWearableType::WT_COUNT || mWearableDatas[type].size() < MAX_CLOTHING_PER_TYPE) - { - mWearableDatas[type].push_back(wearable); +// if (type < LLWearableType::WT_COUNT || mWearableDatas[type].size() < MAX_CLOTHING_PER_TYPE) +// { +// mWearableDatas[type].push_back(wearable); +// wearableUpdated(wearable); +// checkWearableAgainstInventory(wearable); +// return mWearableDatas[type].size()-1; +// } +// [RLVa:KB] - Checked: 2010-06-08 (RLVa-1.2.0g) | Added: RLVa-1.2.0g + if ( (type < LLWearableType::WT_COUNT) && (mWearableDatas[type].size() < MAX_CLOTHING_PER_TYPE) ) + { + // Don't add the same wearable twice + U32 idxWearable = getWearableIndex(wearable); + RLV_ASSERT(MAX_CLOTHING_PER_TYPE == idxWearable); // pushWearable() on an already added wearable is a bug *somewhere* + if (MAX_CLOTHING_PER_TYPE == idxWearable) + { + mWearableDatas[type].push_back(wearable); + idxWearable = mWearableDatas[type].size() - 1; + } wearableUpdated(wearable); checkWearableAgainstInventory(wearable); - return mWearableDatas[type].size()-1; + return idxWearable; +// [/RLVa:KB] } return MAX_CLOTHING_PER_TYPE; } @@ -1302,7 +1321,11 @@ void LLAgentWearables::removeWearable(const LLWearableType::EType type, bool do_ { LLWearable* old_wearable = getWearable(type,index); - if (old_wearable) +// if (old_wearable) +// [RLVa:KB] - Checked: 2010-05-11 (RLVa-1.2.0c) | Modified: RLVa-1.2.0g + // NOTE: we block actual removal in removeWearableFinal(); all we really want here is to avoid showing the save notice + if ( (old_wearable) && ((!rlv_handler_t::isEnabled()) || (!gRlvWearableLocks.isLockedWearable(old_wearable))) ) +// [/RLVa:KB] { if (old_wearable->isDirty()) { @@ -1360,20 +1383,30 @@ void LLAgentWearables::removeWearableFinal(const LLWearableType::EType type, boo { LLWearable* old_wearable = getWearable(type,i); //queryWearableCache(); // moved below - if (old_wearable) +// if (old_wearable) +// [RLVa:KB] - Checked: 2010-05-14 (RLVa-1.2.0g) | Added: RLVa-1.2.0g + if ( (old_wearable) && ((!rlv_handler_t::isEnabled()) || (!gRlvWearableLocks.isLockedWearable(old_wearable))) ) +// [/RLVa:KB] { popWearable(old_wearable); old_wearable->removeFromAvatar(TRUE); } } - mWearableDatas[type].clear(); +// mWearableDatas[type].clear(); +// [RLVa:KB] - Checked: 2010-05-14 (RLVa-1.2.0g) | Added: RLVa-1.2.0g + // The line above shouldn't be needed and would cause issues if we block removing one of the wearables + RLV_VERIFY( ((!rlv_handler_t::isEnabled()) || (!gRlvWearableLocks.hasLockedWearable(type))) ? mWearableDatas[type].empty() : true ); +// [/RLVa:KB] } else { LLWearable* old_wearable = getWearable(type, index); //queryWearableCache(); // moved below - if (old_wearable) +// if (old_wearable) +// [RLVa:KB] - Checked: 2010-05-14 (RLVa-1.2.0g) | Added: RLVa-1.2.0g + if ( (old_wearable) && ((!rlv_handler_t::isEnabled()) || (!gRlvWearableLocks.isLockedWearable(old_wearable))) ) +// [/RLVa:KB] { popWearable(old_wearable); old_wearable->removeFromAvatar(TRUE); @@ -1411,6 +1444,12 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it S32 count = wearables.count(); llassert(items.count() == count); +// [RLVa:KB] - Checked: 2010-06-08 (RLVa-1.2.0g) | Added: RLVa-1.2.0g + // If the user is @add/remoutfit restricted in any way then this function won't just work as-is, so instead of removing and re-adding + // we're stuck with any wearable type potentially having left-over (remove locked) clothing that we'll need to reorder in-place + S32 idxCurPerType[LLWearableType::WT_COUNT] = { 0 }; +// [/RLVa:KB] + S32 i; for (i = 0; i < count; i++) { @@ -1430,10 +1469,51 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it // exactly one wearable per body part setWearable(type,0,new_wearable); } - else +// else +// { +// pushWearable(type,new_wearable); +// } +// [RLVa:KB] - Checked: 2010-06-08 (RLVa-1.2.0g) | Added: RLVa-1.2.0g + else if ( (!rlv_handler_t::isEnabled()) || (!gRlvWearableLocks.hasLockedWearable(type)) || (!remove) ) { + // Sanity check: there shouldn't be any worn wearables for this type the first time we encounter it + RLV_ASSERT( (!remove) || (0 != idxCurPerType[type]) || (0 == getWearableCount(type)) ); pushWearable(type,new_wearable); } + else + { + // Get the current index of the wearable (or add it if doesn't exist yet) + S32 idxCur = getWearableIndex(new_wearable); + if (MAX_CLOTHING_PER_TYPE == idxCur) + { + // Skip adding if @addoutfit=n restricted *unless* the wearable made it into COF [see LLAppMgr::updateAgentWearables()] + if ( (RLV_WEAR_LOCKED == gRlvWearableLocks.canWear(type)) && + (!gInventory.isObjectDescendentOf(new_item->getUUID(), LLAppearanceMgr::instance().getCOF())) ) + { + continue; + } + idxCur = pushWearable(type,new_wearable); + } + + // Since we're moving up from index 0 we just swap the two wearables and things will work out in the end (hopefully) + if (idxCurPerType[type] != idxCur) + { + wearableentry_map_t::iterator itWearable = mWearableDatas.find(type); + RLV_ASSERT(itWearable != mWearableDatas.end()); + if (itWearable == mWearableDatas.end()) continue; + wearableentry_vec_t& typeWearable = itWearable->second; + RLV_ASSERT(typeWearable.size() >= 2); + if (typeWearable.size() < 2) continue; + + typeWearable[idxCur] = typeWearable[idxCurPerType[type]]; + typeWearable[idxCurPerType[type]] = new_wearable; + //wearableUpdated(new_wearable); + //checkWearableAgainstInventory(new_wearable); + } + } + idxCurPerType[type]++; +// [/RLVa:KB] + wearableUpdated(new_wearable); checkWearableAgainstInventory(new_wearable); } @@ -1473,6 +1553,16 @@ void LLAgentWearables::setWearableItem(LLInventoryItem* new_item, LLWearable* ne const LLWearableType::EType type = new_wearable->getType(); +// [RLVa:KB] - Checked: 2010-03-19 (RLVa-1.2.0a) | Modified: RLVa-1.2.0g + // TODO-RLVa: [RLVa-1.2.1] This looks like dead code in SL-2.0.2 so we can't really check to see if it works :| + if (rlv_handler_t::isEnabled()) + { + ERlvWearMask eWear = gRlvWearableLocks.canWear(type); + if ( (RLV_WEAR_LOCKED == eWear) || ((!do_append) && (!(eWear & RLV_WEAR_REPLACE))) ) + return; + } +// [/RLVa:KB] + if (!do_append) { // Remove old wearable, if any @@ -1800,6 +1890,34 @@ void LLAgentWearables::userRemoveMultipleAttachments(llvo_vec_t& objects_to_remo { if (!isAgentAvatarValid()) return; +// [RLVa:KB] - Checked: 2010-03-04 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a + // RELEASE-RLVa: [SL-2.0.0] Check our callers and verify that erasing elements from the passed vector won't break random things + if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_REMOVE)) ) + { + llvo_vec_t::iterator itObj = objects_to_remove.begin(); + while (itObj != objects_to_remove.end()) + { + const LLViewerObject* pAttachObj = *itObj; + if (gRlvAttachmentLocks.isLockedAttachment(pAttachObj)) + { + itObj = objects_to_remove.erase(itObj); + + // Fall-back code: re-add the attachment if it got removed from COF somehow (compensates for possible bugs elsewhere) + LLInventoryModel::cat_array_t folders; LLInventoryModel::item_array_t items; + LLLinkedItemIDMatches f(pAttachObj->getAttachmentItemID()); + gInventory.collectDescendentsIf(LLAppearanceMgr::instance().getCOF(), folders, items, LLInventoryModel::EXCLUDE_TRASH, f); + RLV_ASSERT( 0 != items.count() ); + if (0 == items.count()) + LLAppearanceMgr::instance().registerAttachment(pAttachObj->getAttachmentItemID()); + } + else + { + ++itObj; + } + } + } +// [/RLVa:KB] + if (objects_to_remove.empty()) return; @@ -1846,6 +1964,23 @@ void LLAgentWearables::userRemoveAllAttachments() void LLAgentWearables::userAttachMultipleAttachments(LLInventoryModel::item_array_t& obj_item_array) { +// [RLVa:KB] - Checked: 2010-03-04 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a + // RELEASE-RLVa: [SL-2.0.0] Check our callers and verify that erasing elements from the passed vector won't break random things + if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) ) + { + // Fall-back code: everything should really already have been pruned before we get this far + for (S32 idxItem = obj_item_array.count() - 1; idxItem >= 0; idxItem--) + { + const LLInventoryItem* pItem = obj_item_array.get(idxItem).get(); + if (!gRlvAttachmentLocks.canAttach(pItem)) + { + obj_item_array.remove(idxItem); + RLV_ASSERT(false); + } + } + } +// [/RLVa:KB] + // Build a compound message to send all the objects that need to be rezzed. S32 obj_count = obj_item_array.count(); @@ -1882,7 +2017,18 @@ void LLAgentWearables::userAttachMultipleAttachments(LLInventoryModel::item_arra msg->nextBlockFast(_PREHASH_ObjectData ); msg->addUUIDFast(_PREHASH_ItemID, item->getLinkedUUID()); msg->addUUIDFast(_PREHASH_OwnerID, item->getPermissions().getOwner()); - msg->addU8Fast(_PREHASH_AttachmentPt, 0 ); // Wear at the previous or default attachment point + +// msg->addU8Fast(_PREHASH_AttachmentPt, 0 ); // Wear at the previous or default attachment point +// [RLVa:KB] - Checked: 2010-07-28 (RLVa-1.2.0i) | Added: RLVa-1.2.0i + bool fWearAdd = false; + if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) ) + { + fWearAdd = true; + RlvAttachmentLockWatchdog::instance().onWearAttachment(item, (fWearAdd) ? RLV_WEAR_ADD : RLV_WEAR_REPLACE); + } + msg->addU8Fast(_PREHASH_AttachmentPt, (fWearAdd) ? 0 | ATTACHMENT_ADD : 0); +// [/RLVa:KB] + pack_permissions_slam(msg, item->getFlags(), item->getPermissions()); msg->addStringFast(_PREHASH_Name, item->getName()); msg->addStringFast(_PREHASH_Description, item->getDescription()); diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index f846e9e32e7931c8ee05d49350db1bbe41c11a95..88fee221adf904493f0ae27cd67ef7fdf4c8b617 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -48,6 +48,9 @@ #include "llvoavatarself.h" #include "llviewerregion.h" #include "llwearablelist.h" +// [RLVa:KB] - Checked: 2010-03-05 (RLVa-1.2.0b) +#include "rlvhandler.h" +// [/RLVa:KB] // RAII thingy to guarantee that a variable gets reset when the Setter // goes out of scope. More general utility would be handy - TODO: @@ -1006,6 +1009,34 @@ bool LLAppearanceMgr::wearItemOnAvatar(const LLUUID& item_id_to_wear, bool do_up return false; } +// [RLVa:KB] - Checked: 2010-06-08 (RLVa-1.2.0g) | Added: RLVa-1.2.0g + if ( (rlv_handler_t::isEnabled()) && + ((gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) || (gRlvWearableLocks.hasLockedWearableType(RLV_LOCK_ANY))) ) + { + switch (item_to_wear->getType()) + { + case LLAssetType::AT_BODYPART: + case LLAssetType::AT_CLOTHING: + { + ERlvWearMask eWear = gRlvWearableLocks.canWear(item_to_wear); + if (RLV_WEAR_LOCKED == eWear) + return false; + replace &= ((RLV_WEAR_REPLACE & eWear) == RLV_WEAR_REPLACE); + } + break; + case LLAssetType::AT_OBJECT: + { + // TODO-RLVa: [SL-2.1.0] Rewrite for MULTI_ATTACHMENTS + if (!gRlvAttachmentLocks.canAttach(item_to_wear)) + return false; + } + break; + default: + return false; + } + } +// [/RLVa:KB] + switch (item_to_wear->getType()) { case LLAssetType::AT_CLOTHING: @@ -1367,6 +1398,45 @@ void LLAppearanceMgr::purgeCategory(const LLUUID& category, bool keep_outfit_lin } } +// [SL:KB] - Checked: 2010-04-24 (RLVa-1.2.0f) | Added: RLVa-1.2.0f +void LLAppearanceMgr::syncCOF(const LLInventoryModel::item_array_t& items, LLAssetType::EType type, LLPointer<LLInventoryCallback> cb) +{ + const LLUUID idCOF = getCOF(); + LLInventoryModel::item_array_t cur_cof_items, new_cof_items = items; + + // Grab the current COF contents + LLIsType f(type); + LLInventoryModel::cat_array_t cats; + gInventory.collectDescendentsIf(getCOF(), cats, cur_cof_items, LLInventoryModel::EXCLUDE_TRASH, f); + + // Purge everything in cur_cof_items that isn't part of new_cof_items + for (S32 idxCurItem = 0, cntCurItem = cur_cof_items.count(); idxCurItem < cntCurItem; idxCurItem++) + { + const LLViewerInventoryItem* pItem = cur_cof_items.get(idxCurItem); + if (std::find_if(new_cof_items.begin(), new_cof_items.end(), RlvPredIsEqualOrLinkedItem(pItem)) == new_cof_items.end()) + { + // Item doesn't exist in new_cof_items => purge (if it's a link) + if (pItem->getIsLinkType()) + gInventory.purgeObject(pItem->getUUID()); + } + else + { + // Item exists in new_cof_items => remove *all* occurances in new_cof_items (removes duplicate COF links to this item as well) + new_cof_items.erase( + std::remove_if(new_cof_items.begin(), new_cof_items.end(), RlvPredIsEqualOrLinkedItem(pItem)), new_cof_items.end()); + } + } + + // Link to whatever remains in new_cof_items + for (S32 idxNewItem = 0, cntNewItem = new_cof_items.count(); idxNewItem < cntNewItem; idxNewItem++) + { + const LLInventoryItem* pItem = new_cof_items.get(idxNewItem); + link_inventory_item( + gAgent.getID(), pItem->getLinkedUUID(), idCOF, pItem->getName(), pItem->getDescription(), LLAssetType::AT_LINK, cb); + } +} +// [/SL:KB] + // Keep the last N wearables of each type. For viewer 2.0, N is 1 for // both body parts and clothing items. void LLAppearanceMgr::filterWearableItems( @@ -1419,10 +1489,31 @@ void LLAppearanceMgr::linkAll(const LLUUID& cat_uuid, } } +//void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append) +// [RLVa:KB] - Checked: 2010-03-05 (RLVa-1.2.0b) | Added: RLVa-1.2.0b void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append) { - LLViewerInventoryCategory *pcat = gInventory.getCategory(category); - llinfos << "starting, cat " << (pcat ? pcat->getName() : "[UNKNOWN]") << llendl; + LLInventoryModel::item_array_t body_items_new, wear_items_new, obj_items_new, gest_items_new; + getDescendentsOfAssetType(category, body_items_new, LLAssetType::AT_BODYPART, false); + getDescendentsOfAssetType(category, wear_items_new, LLAssetType::AT_CLOTHING, false); + getDescendentsOfAssetType(category, obj_items_new, LLAssetType::AT_OBJECT, false); + getDescendentsOfAssetType(category, gest_items_new, LLAssetType::AT_GESTURE, false); + 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*/) +// [/RLVa:KB] +{ +// LLViewerInventoryCategory *pcat = gInventory.getCategory(category); +// llinfos << "starting, cat " << (pcat ? pcat->getName() : "[UNKNOWN]") << llendl; +// [RLVa:KB] - Checked: 2010-03-26 (RLVa-1.2.0b) | Added: RLVa-1.2.0b + // RELEASE-RLVa: [SL-2.0.0] If pcat ever gets used for anything further down the beta we'll know about it + llinfos << "starting" << llendl; +// [/RLVa:KB] const LLUUID cof = getCOF(); @@ -1443,75 +1534,142 @@ 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, false); - getDescendentsOfAssetType(category, body_items, LLAssetType::AT_BODYPART, false); +// getDescendentsOfAssetType(category, body_items, LLAssetType::AT_BODYPART, false); +// [RLVa:KB] - Checked: 2010-03-19 (RLVa-1.2.0c) | Modified: RLVa-1.2.0b + // Filter out any new body parts that can't be worn before adding them + if ( (rlv_handler_t::isEnabled()) && (gRlvWearableLocks.hasLockedWearableType(RLV_LOCK_ANY)) ) + body_items_new.erase(std::remove_if(body_items_new.begin(), body_items_new.end(), rlvPredIsNotWearableItem), body_items_new.end()); + body_items.insert(body_items.end(), body_items_new.begin(), body_items_new.end()); +// [/RLVa:KB] 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); + // // - Wearables: include COF contents only if appending. + // LLInventoryModel::item_array_t wear_items; if (append) getDescendentsOfAssetType(cof, wear_items, LLAssetType::AT_CLOTHING, false); - getDescendentsOfAssetType(category, wear_items, LLAssetType::AT_CLOTHING, false); +// [RLVa:KB] - Checked: 2010-03-19 (RLVa-1.2.0c) | Modified: RLVa-1.2.0b + else if ( (rlv_handler_t::isEnabled()) && (gRlvWearableLocks.hasLockedWearableType(RLV_LOCK_ANY)) ) + { + // Make sure that all currently locked clothing layers remain in COF when replacing + getDescendentsOfAssetType(cof, wear_items, LLAssetType::AT_CLOTHING, false); + wear_items.erase(std::remove_if(wear_items.begin(), wear_items.end(), rlvPredIsRemovableItem), wear_items.end()); + } +// [/RLVa:KB] +// getDescendentsOfAssetType(category, wear_items, LLAssetType::AT_CLOTHING, false); +// [RLVa:KB] - Checked: 2010-03-19 (RLVa-1.2.0c) | Modified: RLVa-1.2.0b + // Filter out any new wearables that can't be worn before adding them + if ( (rlv_handler_t::isEnabled()) && (gRlvWearableLocks.hasLockedWearableType(RLV_LOCK_ANY)) ) + wear_items_new.erase(std::remove_if(wear_items_new.begin(), wear_items_new.end(), rlvPredIsNotWearableItem), 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); filterWearableItems(wear_items, LLAgentWearables::MAX_CLOTHING_PER_TYPE); + // // - Attachments: include COF contents only if appending. + // LLInventoryModel::item_array_t obj_items; if (append) getDescendentsOfAssetType(cof, obj_items, LLAssetType::AT_OBJECT, false); - getDescendentsOfAssetType(category, obj_items, LLAssetType::AT_OBJECT, false); +// [RLVa:KB] - Checked: 2010-03-05 (RLVa-1.2.0z) | Modified: RLVa-1.2.0b + else if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) ) + { + // Make sure that all currently locked attachments remain in COF when replacing + getDescendentsOfAssetType(cof, obj_items, LLAssetType::AT_OBJECT, false); + obj_items.erase(std::remove_if(obj_items.begin(), obj_items.end(), rlvPredIsRemovableItem), obj_items.end()); + } +// [/RLVa:KB] +// getDescendentsOfAssetType(category, obj_items, LLAssetType::AT_OBJECT, false); +// [RLVa:KB] - Checked: 2010-03-05 (RLVa-1.2.0z) | Modified: RLVa-1.2.0b + // Filter out any new attachments that can't be worn before adding them + if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) ) + obj_items_new.erase(std::remove_if(obj_items_new.begin(), obj_items_new.end(), rlvPredIsNotWearableItem), 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, false); - getDescendentsOfAssetType(category, gest_items, LLAssetType::AT_GESTURE, false); +// getDescendentsOfAssetType(category, gest_items, LLAssetType::AT_GESTURE, false); +// [RLVa:KB] - Checked: 2010-03-05 (RLVa-1.2.0z) | Added: RLVa-1.2.0b + gest_items.insert(gest_items.end(), gest_items_new.begin(), gest_items_new.end()); +// [/RLVa:KB] removeDuplicateItems(gest_items); - // Remove current COF contents. - bool keep_outfit_links = append; - purgeCategory(cof, keep_outfit_links); - gInventory.notifyObservers(); - // Create links to new COF contents. llinfos << "creating LLUpdateAppearanceOnDestroy" << llendl; LLPointer<LLInventoryCallback> link_waiter = new LLUpdateAppearanceOnDestroy(!append); -#ifndef LL_RELEASE_FOR_DOWNLOAD - llinfos << "Linking body items" << llendl; -#endif - linkAll(cof, body_items, link_waiter); - -#ifndef LL_RELEASE_FOR_DOWNLOAD - llinfos << "Linking wear items" << llendl; -#endif - linkAll(cof, wear_items, link_waiter); - -#ifndef LL_RELEASE_FOR_DOWNLOAD - llinfos << "Linking obj items" << llendl; -#endif - linkAll(cof, obj_items, link_waiter); - -#ifndef LL_RELEASE_FOR_DOWNLOAD - llinfos << "Linking gesture items" << llendl; -#endif - linkAll(cof, gest_items, link_waiter); +// [SL:KB] - Checked: 2010-04-24 (RLVa-1.2.0f) | Added: RLVa-1.2.0f + if (!append) + { +// [/SL:KB] + // Remove current COF contents. + bool keep_outfit_links = append; + purgeCategory(cof, keep_outfit_links); + gInventory.notifyObservers(); + #ifndef LL_RELEASE_FOR_DOWNLOAD + llinfos << "Linking body items" << llendl; + #endif + linkAll(cof, body_items, link_waiter); + + #ifndef LL_RELEASE_FOR_DOWNLOAD + llinfos << "Linking wear items" << llendl; + #endif + linkAll(cof, wear_items, link_waiter); + + #ifndef LL_RELEASE_FOR_DOWNLOAD + llinfos << "Linking obj items" << llendl; + #endif + linkAll(cof, obj_items, link_waiter); + + #ifndef LL_RELEASE_FOR_DOWNLOAD + llinfos << "Linking gesture items" << llendl; + #endif + linkAll(cof, gest_items, link_waiter); +// [SL:KB] - Checked: 2010-04-24 (RLVa-1.2.0f) | Added: RLVa-1.2.0f + } + else + { + // Synchronize COF + // -> it's possible that we don't link to any new items in which case 'link_waiter' fires when it goes out of scope below + syncCOF(body_items, LLAssetType::AT_BODYPART, link_waiter); + syncCOF(wear_items, LLAssetType::AT_CLOTHING, link_waiter); + syncCOF(obj_items, LLAssetType::AT_OBJECT, link_waiter); + syncCOF(gest_items, LLAssetType::AT_GESTURE, link_waiter); + gInventory.notifyObservers(); + } +// [/SL:KB] // Add link to outfit if category is an outfit. - if (!append) +// [RLVa:KB] - Checked: 2010-03-05 (RLVa-1.2.0z) | Added: RLVa-1.2.0b + if ( (!append) && (idOutfit.notNull()) ) { - createBaseOutfitLink(category, link_waiter); + createBaseOutfitLink(idOutfit, link_waiter); } +// [/RLVa:KB] +// if (!append) +// { +// createBaseOutfitLink(category, link_waiter); +// } + llinfos << "waiting for LLUpdateAppearanceOnDestroy" << llendl; } @@ -1562,6 +1720,25 @@ void LLAppearanceMgr::updateAgentWearables(LLWearableHoldingPattern* holder, boo LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(data.mItemID); if( item && (item->getAssetUUID() == wearable->getAssetID()) ) { +// [RLVa:KB] - Checked: 2010-03-19 (RLVa-1.2.0g) | Modified: RLVa-1.2.0g + // 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.put(item); wearables.put(wearable); } diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h index 64e161e1dec687e34bab39de1ecfc1fbdf2e69fa..b4796dd3db02db4bf5768939235489ac742ede7b 100644 --- a/indra/newview/llappearancemgr.h +++ b/indra/newview/llappearancemgr.h @@ -56,6 +56,11 @@ public: // [/SL:KB] bool needToSaveCOF(); 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); +// [/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); @@ -208,6 +213,10 @@ private: void setOutfitLocked(bool locked); +// [SL:KB] - Checked: 2010-04-24 (RLVa-1.2.0f) | Added: RLVa-1.2.0f + void syncCOF(const LLInventoryModel::item_array_t& items, LLAssetType::EType type, LLPointer<LLInventoryCallback> cb); +// [/SL:KB] + bool mAttachmentInvLinkEnabled; bool mOutfitIsDirty; bool mIsInUpdateAppearanceFromCOF; // to detect recursive calls. diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index bfe3e52657019fbb34f4f832005bf51a5706d821..a295d02dde7136851ef740229e1dedd1200218b9 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -80,6 +80,10 @@ #include "llurlmatch.h" #include "lltextutil.h" +// [RLVa:KB] - Checked: 2010-05-03 (RLVa-1.2.0g) +#include "rlvhandler.h" +// [/RLVa:KB] + #include "llweb.h" #include "llsecondlifeurls.h" @@ -334,7 +338,16 @@ LLAppViewer::LLUpdaterInfo *LLAppViewer::sUpdaterInfo = NULL ; void idle_afk_check() { // check idle timers +// if (gSavedSettings.getS32("AFKTimeout") && (gAwayTriggerTimer.getElapsedTimeF32() > gSavedSettings.getS32("AFKTimeout"))) +// [RLVa:KB] - Checked: 2010-05-03 (RLVa-1.2.0g) | Modified: RLVa-1.2.0g +#ifdef RLV_EXTENSION_CMD_ALLOWIDLE + // Enforce an idle time of 30 minutes if @allowidle=n restricted + S32 nAFKTimeout = (gRlvHandler.hasBehaviour(RLV_BHVR_ALLOWIDLE)) ? gSavedSettings.getS32("AFKTimeout") : 60 * 30; + if ( (nAFKTimeout) && (gAwayTriggerTimer.getElapsedTimeF32() > nAFKTimeout) ) +#else if (gSavedSettings.getS32("AFKTimeout") && (gAwayTriggerTimer.getElapsedTimeF32() > gSavedSettings.getS32("AFKTimeout"))) +#endif // RLV_EXTENSION_CMD_ALLOWIDLE +// [/RLVa:KB] { gAgent.setAFK(); } diff --git a/indra/newview/llavatarlist.cpp b/indra/newview/llavatarlist.cpp index 1cd705c2f9d8b555f56a83cbb388e029083a00a2..ddc8eec79bb774407f468cf1709a9a273b259c19 100644 --- a/indra/newview/llavatarlist.cpp +++ b/indra/newview/llavatarlist.cpp @@ -45,6 +45,9 @@ #include "lluuid.h" #include "llvoiceclient.h" #include "llviewercontrol.h" // for gSavedSettings +// [RLVa:KB] - Checked: 2010-06-04 (RLVa-1.2.0d) +#include "rlvhandler.h" +// [/RLVa:KB] static LLDefaultChildRegistry::Register<LLAvatarList> r("avatar_list"); @@ -121,6 +124,9 @@ LLAvatarList::LLAvatarList(const Params& p) , mShowInfoBtn(p.show_info_btn) , mShowProfileBtn(p.show_profile_btn) , mShowSpeakingIndicator(p.show_speaking_indicator) +// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d +, mRlvCheckShowNames(false) +// [/RLVa:KB] { setCommitOnSelectionChange(true); @@ -368,6 +374,9 @@ S32 LLAvatarList::notifyParent(const LLSD& info) void LLAvatarList::addNewItem(const LLUUID& id, const std::string& name, BOOL is_online, EAddPosition pos) { LLAvatarListItem* item = new LLAvatarListItem(); +// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d + item->setRlvCheckShowNames(mRlvCheckShowNames); +// [/RLVa:KB] item->setName(name); item->setAvatarId(id, mSessionID, mIgnoreOnlineStatus); item->setOnline(mIgnoreOnlineStatus ? true : is_online); @@ -387,7 +396,10 @@ void LLAvatarList::addNewItem(const LLUUID& id, const std::string& name, BOOL is BOOL LLAvatarList::handleRightMouseDown(S32 x, S32 y, MASK mask) { BOOL handled = LLUICtrl::handleRightMouseDown(x, y, mask); - if ( mContextMenu ) +// if ( mContextMenu ) +// [RLVa:KB] - Checked: 2010-06-04 (RLVa-1.2.0d) | Modified: RLVa-1.2.0d + if ( (mContextMenu) && ((!mRlvCheckShowNames) || (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES))) ) +// [/RLVa:KB] { uuid_vec_t selected_uuids; getSelectedUUIDs(selected_uuids); @@ -443,9 +455,32 @@ void LLAvatarList::updateLastInteractionTimes() void LLAvatarList::onItemDoubleClicked(LLUICtrl* ctrl, S32 x, S32 y, MASK mask) { - mItemDoubleClickSignal(ctrl, x, y, mask); +// mItemDoubleClickSignal(ctrl, x, y, mask); +// [RLVa:KB] - Checked: 2010-06-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d + if ( (!mRlvCheckShowNames) || (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) ) + mItemDoubleClickSignal(ctrl, x, y, mask); +// [/RLVa:KB] } +// [RLVa:KB] - Checked: 2010-06-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d +void LLAvatarList::refreshNames() +{ + std::vector<LLPanel*> items; + getItems(items); + + std::string strFullName; + for (std::vector<LLPanel*>::const_iterator itItem = items.begin(); itItem != items.end(); ++itItem) + { + LLAvatarListItem* pItem = static_cast<LLAvatarListItem*>(*itItem); + if (gCacheName->getFullName(pItem->getAvatarId(), strFullName)) + pItem->setName(strFullName); + } + + if (&NAME_COMPARATOR == mItemComparator) + sort(); +} +// [/RLVa:KB] + bool LLAvatarItemComparator::compare(const LLPanel* item1, const LLPanel* item2) const { const LLAvatarListItem* avatar_item1 = dynamic_cast<const LLAvatarListItem*>(item1); diff --git a/indra/newview/llavatarlist.h b/indra/newview/llavatarlist.h index 83faa53c281a6f309899ca8902cfb3130160f1ce..f02bc4bd07245c746ac58b65cbc0dba2bebc0932 100644 --- a/indra/newview/llavatarlist.h +++ b/indra/newview/llavatarlist.h @@ -87,6 +87,11 @@ public: // Return true if filter has at least one match. bool filterHasMatches(); +// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d + void setRlvCheckShowNames(bool fRlvCheckShowNames) { mRlvCheckShowNames = fRlvCheckShowNames; } + void refreshNames(); +// [/RLVa:KB] + boost::signals2::connection setRefreshCompleteCallback(const commit_signal_t::slot_type& cb); boost::signals2::connection setItemDoubleClickCallback(const mouse_signal_t::slot_type& cb); @@ -115,6 +120,9 @@ private: bool mShowInfoBtn; bool mShowProfileBtn; bool mShowSpeakingIndicator; +// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d + 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 341913edf7b80723677976545d18e01a94c7d011..11e852bd561dafadb2c3f0750fd6ae03610912a9 100644 --- a/indra/newview/llavatarlistitem.cpp +++ b/indra/newview/llavatarlistitem.cpp @@ -37,6 +37,9 @@ #include "llagent.h" #include "llavatariconctrl.h" #include "lloutputmonitorctrl.h" +// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d) +#include "rlvhandler.h" +// [/RLVa:KB] bool LLAvatarListItem::sStaticInitialized = false; S32 LLAvatarListItem::sLeftPadding = 0; @@ -65,7 +68,11 @@ LLAvatarListItem::LLAvatarListItem(bool not_from_ui_factory/* = true*/) mProfileBtn(NULL), mOnlineStatus(E_UNKNOWN), mShowInfoBtn(true), - mShowProfileBtn(true) +// mShowProfileBtn(true) +// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d + mShowProfileBtn(true), + mRlvCheckShowNames(false) +// [/RLVa:KB] { if (not_from_ui_factory) { @@ -122,8 +129,12 @@ 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: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d + mInfoBtn->setVisible( (mShowInfoBtn) && ((!mRlvCheckShowNames) || (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES))) ); + mProfileBtn->setVisible( (mShowProfileBtn) && ((!mRlvCheckShowNames) || (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES))) ); +// [/RLVa:KB] LLPanel::onMouseEnter(x, y, mask); @@ -163,7 +174,11 @@ void LLAvatarListItem::setOnline(bool online) void LLAvatarListItem::setName(const std::string& name) { - setNameInternal(name, mHighlihtSubstring); +// setNameInternal(name, mHighlihtSubstring); +// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d + bool fRlvFilter = (mRlvCheckShowNames) && (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)); + setNameInternal( (!fRlvFilter) ? name : RlvStrings::getAnonym(name), mHighlihtSubstring); +// [/RLVa:KB] } void LLAvatarListItem::setHighlight(const std::string& highlight) diff --git a/indra/newview/llavatarlistitem.h b/indra/newview/llavatarlistitem.h index e252e69ea9b614852d87c55aed039281808e6d2d..79f29546586770ee8baeb0d05976589333ec80f3 100644 --- a/indra/newview/llavatarlistitem.h +++ b/indra/newview/llavatarlistitem.h @@ -96,6 +96,9 @@ public: void showSpeakingIndicator(bool show); void showLastInteractionTime(bool show); void setAvatarIconVisible(bool visible); +// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d + void setRlvCheckShowNames(bool fRlvCheckShowNames) { mRlvCheckShowNames = fRlvCheckShowNames; } +// [/RLVa:KB] const LLUUID& getAvatarId() const; const std::string getAvatarName() const; @@ -180,6 +183,9 @@ private: //Speaker indicator and avatar name coords are translated accordingly bool mShowInfoBtn; bool mShowProfileBtn; +// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d + bool mRlvCheckShowNames; +// [/RLVa:KB] static bool sStaticInitialized; // this variable is introduced to improve code readability static S32 sLeftPadding; // padding to first left visible child (icon or name) diff --git a/indra/newview/llcallfloater.cpp b/indra/newview/llcallfloater.cpp index c78f73c3b88d1e41ab9a19201a7383a17ca27667..7b0b53735524fddf64e11dd7df5cb340ca039a6b 100644 --- a/indra/newview/llcallfloater.cpp +++ b/indra/newview/llcallfloater.cpp @@ -307,6 +307,10 @@ void LLCallFloater::updateSession() setVisible(true); } } + +// [RLVa:KB] - Checked: 2010-06-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d + mAvatarList->setRlvCheckShowNames(is_local_chat); +// [/RLVa:KB] } void LLCallFloater::refreshParticipantList() diff --git a/indra/newview/llcallfloater.h b/indra/newview/llcallfloater.h index 881f777b4826152be0c4a626ea1f50b953f83bcf..28d8310242c9289f43444022880ec9dbc16adbe2 100644 --- a/indra/newview/llcallfloater.h +++ b/indra/newview/llcallfloater.h @@ -73,6 +73,10 @@ public: static void sOnCurrentChannelChanged(const LLUUID& session_id); +// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d + LLAvatarList* getAvatarCallerList() { return mAvatarList; } +// [/RLVa:KB] + private: typedef enum e_voice_controls_type { diff --git a/indra/newview/llchatbar.cpp b/indra/newview/llchatbar.cpp index 967db212447f87493714e757056ccc7dbef083cc..8dcb7efbce9ae23cb3667f7aa0b070b16c562bf3 100644 --- a/indra/newview/llchatbar.cpp +++ b/indra/newview/llchatbar.cpp @@ -61,6 +61,9 @@ #include "llviewermenu.h" #include "lluictrlfactory.h" #include "llbottomtray.h" +// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0b) +#include "rlvhandler.h" +// [/RLVa:KB] // // Globals @@ -80,7 +83,10 @@ private: }; -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-1.2.0b) | Modified: RLVa-0.2.2a +extern void send_chat_from_viewer(std::string utf8_out_text, EChatType type, S32 channel); +// [/RLVa:KB] // // Functions @@ -473,7 +479,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(); } @@ -577,6 +587,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 1f67a659bd2a101bceef36f5c60729e31a86ab0e..90ce43d8b3f1328f55ce9c018facda9f488ecad2 100644 --- a/indra/newview/llchathistory.cpp +++ b/indra/newview/llchathistory.cpp @@ -52,7 +52,9 @@ #include "llviewertexteditor.h" #include "llworld.h" #include "lluiconstants.h" - +// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) +#include "rlvcommon.h" +// [/RLVa:KB] #include "llsidetray.h"//for blocked objects panel @@ -86,6 +88,10 @@ public: LLSD payload; payload["object_id"] = object_id; payload["owner_id"] = query_map["owner"]; +// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Added: RLVa-1.2.0f + if (query_map.has("owner_name")) + payload["owner_name"] = query_map["owner_name"]; +// [/RLVa:KB] payload["name"] = query_map["name"]; payload["slurl"] = LLWeb::escapeURL(query_map["slurl"]); payload["group_owned"] = query_map["groupowned"]; @@ -97,6 +103,10 @@ LLObjectIMHandler gObjectIMHandler; class LLChatHistoryHeader: public LLPanel { +// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Added: RLVa-1.2.0f + LLChatHistoryHeader() : mShowContextMenu(true), mShowInfoCtrl(true) {} +// [/RLVa:KB] + public: static LLChatHistoryHeader* createInstance(const std::string& file_name) { @@ -209,7 +219,11 @@ public: 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.0f) | 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) { @@ -271,6 +285,15 @@ public: if(mSourceType != CHAT_SOURCE_AGENT) icon->setDrawTooltip(false); +// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | 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: @@ -328,6 +351,10 @@ protected: void showContextMenu(S32 x,S32 y) { +// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | 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) @@ -378,7 +405,10 @@ protected: void showInfoCtrl() { - if (mAvatarID.isNull() || mFrom.empty() || SYSTEM_FROM == mFrom) return; +// if (mAvatarID.isNull() || mFrom.empty() || SYSTEM_FROM == mFrom) return; +// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Added: RLVa-1.2.0f + if ( (!mShowInfoCtrl) || (mAvatarID.isNull() || mFrom.empty() || SYSTEM_FROM == mFrom) ) return; +// [/RLVa:KB] if (!sInfoCtrl) { @@ -447,6 +477,10 @@ protected: EChatSourceType mSourceType; std::string mFrom; LLUUID mSessionID; +// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Added: RLVa-1.2.0f + bool mShowContextMenu; + bool mShowInfoCtrl; +// [/RLVa:KB] S32 mMinUserNameWidth; }; @@ -664,22 +698,32 @@ 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 = LLSLURL("objectim", chat.mFromID, "").getSLURLString(); - url += "?name=" + chat.mFromName; - url += "&owner=" + chat.mOwnerID.asString(); - - std::string slurl = args["slurl"].asString(); - if (slurl.empty()) +// [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")) ) { - LLViewerRegion *region = LLWorld::getInstance()->getRegionFromPosAgent(chat.mPosAgent); - if(region) - { - LLSLURL region_slurl(region->getName(), chat.mPosAgent); - slurl = region_slurl.getLocationString(); - } +// [/RLVa:KB] + // for object IMs, create a secondlife:///app/objectim SLapp + /*std::string*/ url = LLSLURL("objectim", chat.mFromID, "").getSLURLString(); + url += "?name=" + chat.mFromName; + url += "&owner=" + chat.mOwnerID.asString(); + + std::string slurl = args["slurl"].asString(); + if (slurl.empty()) + { + LLViewerRegion *region = LLWorld::getInstance()->getRegionFromPosAgent(chat.mPosAgent); + if(region) + { + LLSLURL region_slurl(region->getName(), chat.mPosAgent); + slurl = region_slurl.getLocationString(); + } + } + url += "&slurl=" + LLURI::escape(slurl); +// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Added: RLVa-1.2.0f } - url += "&slurl=" + LLURI::escape(slurl); +// [/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) @@ -689,7 +733,10 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL mEditor->appendText("<nolink>" + chat.mFromName + "</nolink>" + delimiter, false, link_params); } - 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(style_params); link_params.overwriteFrom(LLStyleMap::instance().lookupAgent(chat.mFromID)); diff --git a/indra/newview/llchatitemscontainerctrl.cpp b/indra/newview/llchatitemscontainerctrl.cpp index 67b7ac53838147914e018c4f27cce0fb941668bf..f2451d5c440b15f3602648563cbce97f99fd56aa 100644 --- a/indra/newview/llchatitemscontainerctrl.cpp +++ b/indra/newview/llchatitemscontainerctrl.cpp @@ -40,6 +40,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; @@ -141,7 +145,11 @@ void LLNearbyChatToastPanel::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; @@ -186,7 +194,11 @@ void LLNearbyChatToastPanel::init(LLSD& notification) style_params_name.font.name(font_name); style_params_name.font.size(font_style_size); - style_params_name.link_href = LLSLURL("agent",mFromID,"about").getSLURLString(); +// style_params_name.link_href = LLSLURL("agent",mFromID,"about").getSLURLString(); +// [RLVa:KB] - Checked: 2010-06-04 (RLVa-1.2.0d) | Added: RLVa-1.2.0d + if (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) + style_params_name.link_href = LLSLURL("agent",mFromID,"about").getSLURLString(); +// [/RLVa:KB] msg_text->appendText(str_sender, FALSE, style_params_name); @@ -319,7 +331,10 @@ void LLNearbyChatToastPanel::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 1d700dcedefd0abbfd52c421852e6b2e9f9d1485..f1ae1fe283d8e4c30cf381a9d4be8afbd36a77c2 100644 --- a/indra/newview/llchatitemscontainerctrl.h +++ b/indra/newview/llchatitemscontainerctrl.h @@ -46,6 +46,9 @@ protected: LLNearbyChatToastPanel() : 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: @@ -89,6 +92,9 @@ private: 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/llfloaterabout.cpp b/indra/newview/llfloaterabout.cpp index 5ac006302e2efcb5288d66fc5789af9a7024a3e3..883269e55a4751ff008eabff42f36ebda2ec98fe 100644 --- a/indra/newview/llfloaterabout.cpp +++ b/indra/newview/llfloaterabout.cpp @@ -41,6 +41,9 @@ #include "llviewerregion.h" #include "llversioninfo.h" #include "llweb.h" +// [RLVa:KB] - Checked: 2010-04-18 (RLVa-1.2.0e) +#include "rlvhandler.h" +// [/RLVa:KB] // Linden library includes #include "llaudioengine.h" @@ -255,6 +258,12 @@ LLSD LLFloaterAbout::getInfo() } #endif +// [RLVa:KB] - Checked: 2010-04-18 (RLVa-1.2.0e) | Added: RLVa-1.2.0e + if (rlv_handler_t::isEnabled()) + info["RLV_VERSION"] = RlvStrings::getVersionAbout(); + else + info["RLV_VERSION"] = "(disabled)"; +// [/RLVa:KB] info["OPENGL_VERSION"] = (const char*)(glGetString(GL_VERSION)); info["LIBCURL_VERSION"] = LLCurl::getVersionString(); info["J2C_VERSION"] = LLImageJ2C::getEngineInfo(); diff --git a/indra/newview/llfloateravatarpicker.cpp b/indra/newview/llfloateravatarpicker.cpp index 9391c761b72381ce727ca67a8e650637437a231c..22b4e1fec6c9877ac4fa74ba802e5560dac7fb51 100644 --- a/indra/newview/llfloateravatarpicker.cpp +++ b/indra/newview/llfloateravatarpicker.cpp @@ -36,6 +36,9 @@ #include "lltooldraganddrop.h" // for LLToolDragAndDrop #include "llviewercontrol.h" #include "llworld.h" +// [RLVa:KB] - Checked: 2010-06-04 (RLVa-1.2.0d) +#include "rlvhandler.h" +// [/RLVa:KB] // Linden libraries #include "llbutton.h" @@ -234,6 +237,21 @@ void LLFloaterAvatarPicker::onRangeAdjust() void LLFloaterAvatarPicker::onList() { getChildView("ok_btn")->setEnabled(isSelectBtnEnabled()); + +// [RLVa:KB] - Checked: 2010-06-05 (RLVa-1.2.0d) | Modified: RLVa-1.2.0d + if (rlv_handler_t::isEnabled()) + { + LLTabContainer* pTabs = getChild<LLTabContainer>("ResidentChooserTabs"); + LLPanel* pNearMePanel = getChild<LLPanel>("NearMePanel"); + if ( (pTabs) && (pNearMePanel) ) + { + 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() diff --git a/indra/newview/llfloaterinspect.cpp b/indra/newview/llfloaterinspect.cpp index 8e7f7e083ce8249c62c7c8d12491792ed0e04e2f..41d63c368e04354e6826e58d37651929f4008e52 100644 --- a/indra/newview/llfloaterinspect.cpp +++ b/indra/newview/llfloaterinspect.cpp @@ -40,6 +40,9 @@ #include "llviewercontrol.h" #include "llviewerobject.h" #include "lluictrlfactory.h" +// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) +#include "rlvhandler.h" +// [/RLVa:KB] //LLFloaterInspect* LLFloaterInspect::sInstance = NULL; @@ -113,7 +116,16 @@ void LLFloaterInspect::onClickCreatorProfile() LLSelectNode* node = mObjectSelection->getFirstNode(&func); if(node) { - LLAvatarActions::showProfile(node->mPermissions->getCreator()); +// LLAvatarActions::showProfile(node->mPermissions->getCreator()); +// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) | Modified: RLVa-1.0.0e + const LLUUID& idCreator = node->mPermissions->getCreator(); + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && + ((node->mPermissions->getOwner() == idCreator) || (RlvUtil::isNearbyAgent(idCreator))) ) + { + return; + } + LLAvatarActions::showProfile(idCreator); +// [/RLVa:KB] } } } @@ -139,6 +151,10 @@ void LLFloaterInspect::onClickOwnerProfile() if(node) { const LLUUID& owner_id = node->mPermissions->getOwner(); +// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) | Modified: RLVa-1.0.0e + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) + return; +// [/RLVa:KB] LLAvatarActions::showProfile(owner_id); } } @@ -148,8 +164,13 @@ void LLFloaterInspect::onSelectObject() { if(LLFloaterInspect::getSelectedUUID() != LLUUID::null) { - getChildView("button owner")->setEnabled(true); +// getChildView("button owner")->setEnabled(true); +// getChildView("button creator")->setEnabled(true); +// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) | Modified: RLVa-1.0.0e + getChildView("button owner")->setEnabled(!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)); + // TODO-RLVa: [RLVa-1.2.2] Is it worth checking the selected node just to selectively disable this button? getChildView("button creator")->setEnabled(true); +// [/RLVa:KB] } } @@ -208,6 +229,19 @@ void LLFloaterInspect::refresh() gCacheName->getFullName(obj->mPermissions->getOwner(), owner_name); gCacheName->getFullName(obj->mPermissions->getCreator(), creator_name); + +// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) | Modified: RLVa-1.2.1b + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) + { + if (!obj->mPermissions->isGroupOwned()) + owner_name = RlvStrings::getAnonym(owner_name); + + const LLUUID& idCreator = obj->mPermissions->getCreator(); + if ( (obj->mPermissions->getOwner() == idCreator) || (RlvUtil::isNearbyAgent(idCreator)) ) + creator_name = RlvStrings::getAnonym(creator_name); + } +// [/RLVa:KB] + row["id"] = obj->getObject()->getID(); row["columns"][0]["column"] = "object_name"; row["columns"][0]["type"] = "text"; diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 3804a1b85840db0d9959b06eb1f4786ca830e5d3..6dae540aa3189543aae6ebfec61ec3521a8f5149 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -101,6 +101,9 @@ #include "llviewermedia.h" #include "llpluginclassmedia.h" #include "llteleporthistorystorage.h" +// [RLVa:KB] - Checked: 2010-03-18 (RLVa-1.2.0a) +#include "rlvhandler.h" +// [/RLVa:KB] #include "lllogininstance.h" // to check if logged in yet @@ -841,6 +844,11 @@ void LLFloaterPreference::refreshEnabledState() LLComboBox* ctrl_reflections = getChild<LLComboBox>("Reflections"); LLRadioGroup* radio_reflection_detail = getChild<LLRadioGroup>("ReflectionDetailRadio"); +// [RLVa:KB] - Checked: 2010-04-09 (RLVa-1.2.0e) | Modified: RLVa-1.2.0e + if (rlv_handler_t::isEnabled()) + childSetEnabled("busy_response", !gRlvHandler.hasBehaviour(RLV_BHVR_SENDIM)); +// [/RLVa:KB] + // Reflections BOOL reflections = gSavedSettings.getBOOL("VertexShaderEnable") && gGLManager.mHasCubeMap @@ -878,8 +886,14 @@ void LLFloaterPreference::refreshEnabledState() // radio set for terrain detail mode LLRadioGroup* mRadioTerrainDetail = getChild<LLRadioGroup>("TerrainDetailRadio"); // can be linked with control var - 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) { @@ -896,7 +910,13 @@ void LLFloaterPreference::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] //Deferred/SSAO/Shadows LLCheckBoxCtrl* ctrl_deferred = getChild<LLCheckBoxCtrl>("UseLightShaders"); diff --git a/indra/newview/llfloaterproperties.cpp b/indra/newview/llfloaterproperties.cpp index e4e4713dbca833d2e43103066acec9b3e5880580..34cb273c5b9e7c5429960336e02149d55838d85b 100644 --- a/indra/newview/llfloaterproperties.cpp +++ b/indra/newview/llfloaterproperties.cpp @@ -58,6 +58,9 @@ #include "lluictrlfactory.h" +// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) +#include "rlvhandler.h" +// [/RLVa:KB] //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLPropertiesObserver @@ -280,6 +283,16 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item) getChildView("BtnCreator")->setEnabled(TRUE); getChildView("LabelCreatorTitle")->setEnabled(TRUE); getChildView("LabelCreatorName")->setEnabled(TRUE); +// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) | Modified: RLVa-1.0.0e + // If the object creator matches the object owner we need to anonimize the creator field as well + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && + ( ((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 @@ -303,8 +316,15 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item) else { gCacheName->getFullName(perm.getOwner(), name); +// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) | Modified: RLVa-1.0.0e + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) + name = RlvStrings::getAnonym(name); +// [/RLVa:KB] } - getChildView("BtnOwner")->setEnabled(TRUE); +// getChildView("BtnOwner")->setEnabled(TRUE); +// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) | Added: RLVa-1.0.0e + getChildView("BtnOwner")->setEnabled(!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)); +// [/RLVa:KB] getChildView("LabelOwnerTitle")->setEnabled(TRUE); getChildView("LabelOwnerName")->setEnabled(TRUE); getChild<LLUICtrl>("LabelOwnerName")->setValue(name); @@ -541,6 +561,17 @@ void LLFloaterProperties::onClickCreator() if(!item) return; if(!item->getCreatorUUID().isNull()) { +// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) | Added: RLVa-1.2.1b + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) + { + const LLPermissions& perm = item->getPermissions(); + if ( ((perm.isOwned()) && (!perm.isGroupOwned()) && (perm.getOwner() == item->getCreatorUUID()) ) || + (RlvUtil::isNearbyAgent(item->getCreatorUUID())) ) + { + return; + } + } +// [/RLVa:KB] LLAvatarActions::showProfile(item->getCreatorUUID()); } } @@ -556,6 +587,10 @@ void LLFloaterProperties::onClickOwner() } else { +// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) | Modified: RLVa-1.0.0e + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) + return; +// [/RLVa:KB] LLAvatarActions::showProfile(item->getPermissions().getOwner()); } } diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp index 97f192a70830089b93d2bb25d20e8e642af51696..bbd4a24664c12444f4c74fa3737a424a5b4c8b2e 100644 --- a/indra/newview/llfloaterreporter.cpp +++ b/indra/newview/llfloaterreporter.cpp @@ -254,6 +254,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 41a05055feff21da841317f9af9c4da87448ce61..f1131144a73557ee6dfa55dce67d24509aaba6c2 100644 --- a/indra/newview/llfloatersettingsdebug.cpp +++ b/indra/newview/llfloatersettingsdebug.cpp @@ -34,6 +34,10 @@ #include "llcolorswatch.h" #include "llviewercontrol.h" #include "lltexteditor.h" +// [RLVa:KB] - Checked: 2010-03-18 (RLVa-1.2.0a) +#include "rlvhandler.h" +#include "rlvextensions.h" +// [/RLVa:KB] LLFloaterSettingsDebug::LLFloaterSettingsDebug(const LLSD& key) @@ -210,6 +214,33 @@ void LLFloaterSettingsDebug::updateControl(LLControlVariable* controlp) if (controlp) { +// [RLVa:KB] - Checked: 2010-03-18 (RLVa-1.2.0e) | Modified: RLVa-0.2.1d + // TODO-RLVa: [RLVa-1.2.1] Look into rewriting the whole debug setting blocking code + if (rlv_handler_t::isEnabled()) + { + // Don't allow changing DBG_WRITE debug settings under @setdebug=n + bool fEnable = !( (gRlvHandler.hasBehaviour(RLV_BHVR_SETDEBUG)) && + (RlvExtGetSet::getDebugSettingFlags(controlp->getName()) & RlvExtGetSet::DBG_WRITE) ); + // Don't allow toggling "Basic Shaders" and/or "Atmopsheric Shaders" through the debug settings under @setenv=n + fEnable &= !((gRlvHandler.hasBehaviour(RLV_BHVR_SETENV)) && + (("VertexShaderEnable" == controlp->getName()) || ("WindLightUseAtmosShaders" == controlp->getName()))); +#ifdef RLV_EXTENSION_STARTLOCATION + // Don't allow toggling RestrainedLoveLoginLastLocation + fEnable &= !(RLV_SETTING_LOGINLASTLOCATION == controlp->getName()); +#endif // RLV_EXTENSION_STARTLOCATION + + // NOTE: this runs per-frame so there's no need to explictly handle onCommitSettings() or onClickDefault() + 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/llfloaterwindlight.cpp b/indra/newview/llfloaterwindlight.cpp index 7131cb5de3b704ce36d6b8761798c9faa72fcd5b..6c58efd9ab8d2bc651e15f07e46e6c8fcea1868e 100644 --- a/indra/newview/llfloaterwindlight.cpp +++ b/indra/newview/llfloaterwindlight.cpp @@ -270,6 +270,17 @@ void LLFloaterWindLight::syncMenu() LLWLParamSet& currentParams = param_mgr->mCurParams; //std::map<std::string, LLVector4> & currentParams = param_mgr->mCurParams.mParamValues; +// [RLVa:KB] - Checked: 2009-07-10 (RLVa-1.0.0g) +/* + // Fixes LL "bug" (preset name isn't kept synchronized) + LLComboBox* comboBox = getChild<LLComboBox>("WLPresetsCombo"); + if (comboBox->getSelectedItemLabel() != currentParams.mName) + { + comboBox->setSimple(currentParams.mName); + } +*/ +// [/RLVa:KB] + // blue horizon param_mgr->mBlueHorizon = currentParams.getVector(param_mgr->mBlueHorizon.mName, err); getChild<LLUICtrl>("WLBlueHorizonR")->setValue(param_mgr->mBlueHorizon.r / 2.0); diff --git a/indra/newview/llfloaterworldmap.cpp b/indra/newview/llfloaterworldmap.cpp index 3afa31b873c0ecea0c744f689b9d61a1e1a48f25..a375f452eca8912e507a16303d7afedc28a0c7c1 100644 --- a/indra/newview/llfloaterworldmap.cpp +++ b/indra/newview/llfloaterworldmap.cpp @@ -75,6 +75,10 @@ #include "llwindow.h" // copyTextToClipboard() +// [RLVa:KB] - Checked: 2010-08-22 (RLVa-1.2.1a) +#include "rlvhandler.h" +// [/RLVa:KB] + //--------------------------------------------------------------------------- // Constants //--------------------------------------------------------------------------- @@ -434,6 +438,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); @@ -716,6 +724,16 @@ void LLFloaterWorldMap::updateLocation() { // Empty SLURL will disable the "Copy SLURL to clipboard" button mSLURL = LLSLURL(); } + +// [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0a) +/* + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) + { + childSetValue("location", RlvStrings::getString(RLV_STRING_HIDDEN_REGION)); + mSLURL.clear(); + } +*/ +// [/RLVa:KB] } } diff --git a/indra/newview/llgiveinventory.cpp b/indra/newview/llgiveinventory.cpp index 260e15c714c735aacb67251689a707653e7774a5..fe650bc3447d85a6d265cbf4e078170c4d7ed1c6 100644 --- a/indra/newview/llgiveinventory.cpp +++ b/indra/newview/llgiveinventory.cpp @@ -46,6 +46,10 @@ #include "llrecentpeople.h" #include "llviewerobjectlist.h" #include "llvoavatarself.h" +// [RLVa:KB] - Checked: 2010-03-04 (RLVa-1.2.0a) +#include "rlvhandler.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 @@ -300,6 +304,20 @@ void LLGiveInventory::logInventoryOffer(const LLUUID& to_agent, const LLUUID &im { gIMMgr->addSystemMessage(im_session_id, "inventory_item_offered", args); } +// [RLVa:KB] - Checked: 2010-05-26 (RLVa-1.2.0h) | Modified: RLVa-1.2.0h + else if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (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 strName, strMsgName = "inventory_item_offered-im"; LLSD args; + if (gCacheName->getFullName(to_agent, strName)) + { + args["NAME"] = RlvStrings::getAnonym(strName); + 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)) { @@ -397,7 +415,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: 2010-04-21 (RLVa-1.2.0f) | Added: RLVa-1.2.0f + // 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 ( (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) || (im_session_id.notNull()) || (!RlvUtil::isNearbyAgent(to_agent)) || + (RlvUIEnabler::hasOpenProfile(to_agent)) ) + { + LLRecentPeople::instance().add(to_agent); + } +// [/RLVa:KB] } // static @@ -452,7 +478,15 @@ void LLGiveInventory::commitGiveInventoryCategory(const LLUUID& to_agent, << cat->getUUID() << llendl; // add buddy to recent people list - LLRecentPeople::instance().add(to_agent); +// LLRecentPeople::instance().add(to_agent); +// [RLVa:KB] - Checked: 2010-04-20 (RLVa-1.2.0f) | Added: RLVa-1.2.0f + // 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 ( (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) || (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 83846f5b619d294de6b340150cf88d58d17e40a6..6a567578664241a1f2d9d680e842ad0daa1164cf 100644 --- a/indra/newview/llglsandbox.cpp +++ b/indra/newview/llglsandbox.cpp @@ -61,6 +61,9 @@ #include "llresmgr.h" #include "pipeline.h" #include "llspatialpartition.h" +// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) +#include "rlvhandler.h" +// [/RLVa:KB] // Height of the yellow selection highlight posts for land const F32 PARCEL_POST_HEIGHT = 0.666f; @@ -68,6 +71,13 @@ 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-04-11 (RLVa-1.2.0e) | Modified: RLVa-1.1.0l + if ( (rlv_handler_t::isEnabled()) && ((gRlvHandler.hasBehaviour(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; @@ -132,6 +142,27 @@ 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)) + { + // 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() + 1.5f; + F32 new_near = relative_av_pos * LLViewerCamera::getInstance()->getAtAxis() - 1.5f; + + 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 = 1.5f * 1.5f; + } +// [/RLVa:KB] LLViewerCamera::getInstance()->setPerspective(FOR_SELECTION, center_x-width/2, center_y-height/2, width, height, limit_select_distance); diff --git a/indra/newview/llhudtext.cpp b/indra/newview/llhudtext.cpp index 96638018c4b0921bf667c6cbbf45d1d015e937e4..6b0801f6db2d725e9724d2ae4794289d29453287 100644 --- a/indra/newview/llhudtext.cpp +++ b/indra/newview/llhudtext.cpp @@ -47,9 +47,11 @@ #include "llstatusbar.h" #include "llmenugl.h" #include "pipeline.h" +// [RLVa:KB] - Checked: 2010-03-27 (RLVa-1.2.0b) +#include "rlvhandler.h" +// [/RLVa:KB] #include <boost/tokenizer.hpp> - const F32 SPRING_STRENGTH = 0.7f; const F32 RESTORATION_SPRING_TIME_CONSTANT = 0.1f; const F32 HORIZONTAL_PADDING = 15.f; @@ -558,6 +560,30 @@ void LLHUDText::renderText(BOOL for_select) void LLHUDText::setStringUTF8(const std::string &wtext) { +// [RLVa:KB] - Checked: 2010-03-02 (RLVa-1.2.0a) | Modified: RLVa-1.0.0f + // NOTE: setString() is only called for debug beacons and the floating name tags (which we don't want to censor + // because you'd see "(Region hidden) LastName" if you happen to go to a sim who's name is your first name :p + if (rlv_handler_t::isEnabled()) + { + std::string text(wtext); + + if (gRlvHandler.canShowHoverText(mSourceObject)) + { + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) + RlvUtil::filterLocation(text); + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) + RlvUtil::filterNames(text); + } + else + { + text = ""; + } + + setString(utf8str_to_wstring(text)); + return; + } +// [/RLVa:KB] + setString(utf8str_to_wstring(wtext)); } @@ -1133,3 +1159,18 @@ F32 LLHUDText::LLHUDTextSegment::getWidth(const LLFontGL* font) return width; } } + +// [RLVa:KB] - Checked: 2010-03-27 (RLVa-1.2.0b) | Added: RLVa-1.0.0f +void LLHUDText::refreshAllObjectText() +{ + for (TextObjectIterator itText = sTextObjects.begin(); itText != sTextObjects.end(); itText++) + { + LLHUDText* pText = *itText; + if ( (pText) && (!pText->mObjText.empty() && ("" != pText->mObjText) ) && + (pText->mSourceObject) && (LL_PCODE_VOLUME == pText->mSourceObject->getPCode()) ) + { + pText->setStringUTF8(pText->mObjText); + } + } +} +// [/RLVa:KB] diff --git a/indra/newview/llhudtext.h b/indra/newview/llhudtext.h index 4f4ee55a614a8cb503d711122ce415b5bb135cef..64b8dbf369fcace6572a04b238682f35b41fc659 100644 --- a/indra/newview/llhudtext.h +++ b/indra/newview/llhudtext.h @@ -125,6 +125,11 @@ public: static void addPickable(std::set<LLViewerObject*> &pick_list); static void reshape(); static void setDisplayText(BOOL flag) { sDisplayText = flag ; } +// [RLVa:KB] - Checked: 2010-03-27 (RLVa-1.2.0b) | Added: RLVa-1.0.0f + const std::string& getObjectText() const { return mObjText; } + void setObjectText(const std::string &utf8string) { mObjText = utf8string; } + static void refreshAllObjectText(); +// [/RLVa:KB] protected: LLHUDText(const U8 type); @@ -170,6 +175,9 @@ private: EVertAlignment mVertAlignment; S32 mLOD; BOOL mHidden; +// [RLVa:KB] - Checked: 2010-03-27 (RLVa-1.2.0b) | Added: RLVa-1.0.0f + std::string mObjText; +// [/RLVa:KB] static BOOL sDisplayText ; static std::set<LLPointer<LLHUDText> > sTextObjects; diff --git a/indra/newview/llimfloater.cpp b/indra/newview/llimfloater.cpp index 658e9403d874a85666980fe8c7d204e83f992910..c828b1d29e71319de8a5d0ea37bb42fbcf5bf4e5 100644 --- a/indra/newview/llimfloater.cpp +++ b/indra/newview/llimfloater.cpp @@ -56,6 +56,9 @@ #include "llspeakers.h" #include "llsidetray.h" +// [RLVa:KB] - Checked: 2010-04-09 (RLVa-1.2.0e) +#include "rlvhandler.h" +// [/RLVa:KB] static const S32 RECT_PADDING_NOT_INIT = -1; static const S32 RECT_PADDING_NEED_RECALC = -2; @@ -210,6 +213,56 @@ void LLIMFloater::sendMsg() std::string utf8_text = wstring_to_utf8str(text); utf8_text = utf8str_truncate(utf8_text, MAX_MSG_BUF_SIZE - 1); +// [RLVa:KB] - Checked: 2010-04-09 (RLVa-1.2.0e) | Modified: RLVa-1.2.0e + if (gRlvHandler.hasBehaviour(RLV_BHVR_SENDIM)) + { + 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: allow if recipient is a sendim exception + fRlvFilter = !gRlvHandler.isException(RLV_BHVR_SENDIM, mOtherParticipantUUID); + break; + case LLIMModel::LLIMSession::GROUP_SESSION: // Group chat: allow if group is a sendim exception + fRlvFilter = !gRlvHandler.isException(RLV_BHVR_SENDIM, mSessionID); + break; + case LLIMModel::LLIMSession::ADHOC_SESSION: // Conference chat: allow if all participants are sendim exceptions + { + 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) && (!gRlvHandler.isException(RLV_BHVR_SENDIM, pSpeaker->mID)) ) + { + fRlvFilter = true; + break; + } + } + } + break; + default: + fRlvFilter = true; + break; + } + } + + if (fRlvFilter) + utf8_text = RlvStrings::getString(RLV_STRING_BLOCKED_SENDIM); + } +// [/RLVa:KB] + if (mSessionInitialized) { LLIMModel::sendMessage(utf8_text, mSessionID, diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index 129c9aec142de34d4d4392368a8aa9068b4d0a3b..3403521246a2fdb0801eb99ec92f5d08f71d4d60 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -62,7 +62,9 @@ #include "lltextbox.h" #include "llviewercontrol.h" #include "llviewerparcelmgr.h" - +// [RLVa:KB] - Checked: 2010-04-09 (RLVa-1.2.0e) +#include "rlvhandler.h" +// [/RLVa:KB] const static std::string IM_TIME("time"); const static std::string IM_TEXT("message"); @@ -3072,6 +3074,20 @@ public: { return; } +// [RLVa:KB] - Checked: 2010-03-23 (RLVa-1.2.0e) | Modified: RLVa-1.2.0a + if (gRlvHandler.hasBehaviour(RLV_BHVR_RECVIM)) + { + if (gAgent.isInGroup(session_id)) // Group chat: don't accept the invite if not an exception + { + if (!gRlvHandler.isException(RLV_BHVR_RECVIM, session_id)) + return; + } + else if (!gRlvHandler.isException(RLV_BHVR_RECVIM, 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 532ffca4be5357a55d175725b844cf62a7490091..6d0d9b9ab264ad686c1f314e9573ad8c70ae0195 100644 --- a/indra/newview/llinspectobject.cpp +++ b/indra/newview/llinspectobject.cpp @@ -37,6 +37,10 @@ #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 "rlvhandler.h" +#include "lltoolpie.h" +// [/RLVa:KB] // Linden libraries #include "llbutton.h" // setLabel(), not virtual! @@ -377,6 +381,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()) && (gRlvHandler.canSit(pick.getObject(), pick.mObjectOffset)) ); + } +// [/RLVa:KB] } void LLInspectObject::updateTouchLabel(LLSelectNode* nodep) @@ -472,10 +485,26 @@ 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(); - args["[CREATOR]"] = creator_url; - +// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) | Added: RLVa-1.2.1b + // Only anonimize the creator if they're also the owner or if they're a nearby avie + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && + ((nodep->mPermissions->getOwner() == creator_id) || (RlvUtil::isNearbyAgent(creator_id))) ) + { + // TODO-RLVa: [RLVa-1.2.2] We need to put a callback here in case the name hasn't previously resolved + std::string strFullName; + args["[CREATOR]"] = (gCacheName->getFullName(creator_id, strFullName)) ? RlvStrings::getAnonym(strFullName) + : LLTrans::getString("Unknown"); + } + else + { +// [/RLVa:KB] + std::string creator_url = + LLSLURL("agent", creator_id, "about").getSLURLString(); + args["[CREATOR]"] = creator_url; +// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) | Added: RLVa-1.2.1b + } +// [/RLVa:KB] + // created by one user but owned by another std::string owner_url; LLUUID owner_id; @@ -488,7 +517,21 @@ void LLInspectObject::updateCreator(LLSelectNode* nodep) else { owner_id = nodep->mPermissions->getOwner(); - owner_url = LLSLURL("agent", owner_id, "about").getSLURLString(); +// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) | Added: RLVa-1.2.1b + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) + { + // TODO-RLVa: [RLVa-1.2.2] We need to put a callback here in case the name hasn't previously resolved + std::string strFullName; + owner_url = (gCacheName->getFullName(owner_id, strFullName)) ? RlvStrings::getAnonym(strFullName) + : LLTrans::getString("Unknown"); + } + else + { +// [/RLVa:KB] + owner_url = LLSLURL("agent", owner_id, "about").getSLURLString(); +// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) | Added: RLVa-1.2.1b + } +// [/RLVa:KB] } args["[OWNER]"] = owner_url; diff --git a/indra/newview/llinspectremoteobject.cpp b/indra/newview/llinspectremoteobject.cpp index e956b3b8dec81bf600bef7a8358e23588f457c70..807b764adb5327e3c1fc8fc04b47c728d6a53c54 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.0f) +#include "rlvhandler.h" +// [/RLVa:KB] ////////////////////////////////////////////////////////////////////////////// // LLInspectRemoteObject @@ -112,8 +115,12 @@ void LLInspectRemoteObject::onOpen(const LLSD& data) mSLurl = data["slurl"].asString(); // work out the owner's name - mOwner = ""; - if (gCacheName) +// mOwner = ""; +// if (gCacheName) +// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Added: RLVa-1.2.0f + mOwner = (data.has("owner_name")) ? data["owner_name"].asString() : ""; + if ( (gCacheName) && (mOwnerID.notNull()) ) +// [/RLVa:KB] { gCacheName->get(mOwnerID, mGroupOwned, nameCallback, this); } @@ -186,7 +193,10 @@ void LLInspectRemoteObject::update() owner = LLSLURL("agent", mOwnerID, "about").getSLURLString(); } } - else +// else +// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Added: RLVa-1.2.0f + else if (mOwner.empty()) // If "objectim" was subject to @shownames then we passed an anonimized owner name so use that if available +// [/RLVa:KB] { owner = LLTrans::getString("Unknown"); } @@ -205,6 +215,14 @@ void LLInspectRemoteObject::update() // disable the Block button if we don't have the owner ID getChild<LLUICtrl>("block_btn")->setEnabled(! mOwnerID.isNull()); + +// [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 81174730c702c7a89ca93933734ec9e3846c3573..3683b7eaacdc4472a7cdfd525bdddb08e28ebf1b 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -66,6 +66,9 @@ #include "llviewerwindow.h" #include "llvoavatarself.h" #include "llwearablelist.h" +// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0b) +#include "rlvhandler.h" +// [/RLVa:KB] typedef std::pair<LLUUID, LLUUID> two_uuids_t; typedef std::list<two_uuids_t> two_uuids_list_t; @@ -618,6 +621,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); @@ -2897,6 +2914,15 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, { is_movable = FALSE; } + +// [RLVa:KB] - Checked: 2010-05-27 (RLVa-1.2.0h) | Added: RLVa-1.2.0h + if ( (rlv_handler_t::isEnabled()) && (move_is_into_current_outfit) ) + { + const LLViewerInventoryItem* pItem = dynamic_cast<const LLViewerInventoryItem*>(inv_item); + is_movable = rlvPredIsWearableItem(pItem); + } +// [/RLVa:KB] + if (move_is_into_trash) { is_movable &= inv_item->getIsLinkType() || !get_is_item_worn(inv_item->getUUID()); @@ -3959,7 +3985,10 @@ void LLObjectBridge::performAction(LLInventoryModel* model, std::string action) else if (isRemoveAction(action)) { LLInventoryItem* item = gInventory.getItem(mUUID); - if(item) +// if(item) +// [RLVa:KB] - Checked: 2010-03-04 (RLVa-1.2.0a) | Added: RLVa-1.2.0a + if ( (item) && ((!rlv_handler_t::isEnabled()) || (gRlvAttachmentLocks.canDetach(item))) ) +// [/RLVa:KB] { LLVOAvatarSelf::detachAttachmentIntoInventory(item->getLinkedUUID()); } @@ -3998,6 +4027,14 @@ std::string LLObjectBridge::getLabelSuffix() const void rez_attachment(LLViewerInventoryItem* item, LLViewerJointAttachment* attachment, bool replace) { +// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1a) | Added: RLVa-1.2.1a + // If no attachment point was specified, try looking it up from the item name + if ( (rlv_handler_t::isEnabled()) && (!attachment) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) ) + { + attachment = RlvAttachPtLookup::getAttachPoint(item); + } +// [/RLVa:KB] + const LLUUID& item_id = item->getLinkedUUID(); // Check for duplicate request. @@ -4036,10 +4073,20 @@ void rez_attachment(LLViewerInventoryItem* item, LLViewerJointAttachment* attach if (replace && (attachment && attachment->getNumObjects() > 0)) { +// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1a) | Modified: RLVa-1.2.1a + // Block if we can't "replace wear" what's currently there + if ( (rlv_handler_t::isEnabled()) && ((gRlvAttachmentLocks.canAttach(attachment) & RLV_WEAR_REPLACE) == 0) ) + return; +// [/RLVa:KB] LLNotificationsUtil::add("ReplaceAttachment", LLSD(), payload, confirm_replace_attachment_rez); } else { +// [RLVa:KB] - Checked: 2010-08-07 (RLVa-1.2.0i) | Modified: RLVa-1.2.0i + // Block wearing anything on a non-attachable attachment point + if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.isLockedAttachmentPoint(attach_pt, RLV_LOCK_ADD)) ) + return; +// [/RLVa:KB] LLNotifications::instance().forceResponse(LLNotification::Params("ReplaceAttachment").payload(payload), 0/*YES*/); } } @@ -4063,7 +4110,17 @@ bool confirm_replace_attachment_rez(const LLSD& notification, const LLSD& respon if (itemp) { U8 attachment_pt = notification["payload"]["attachment_point"].asInteger(); - +// [RLVa:KB] - Checked: 2010-08-06 (RLVa-1.2.0i) | Added: RLVa-1.2.0i + // NOTE: we're letting our callers decide whether or not to use ATTACHMENT_ADD + if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) && + ((!notification["payload"].has("rlv_force")) || (!notification["payload"]["rlv_force"].asBoolean())) ) + { + ERlvWearMask eWearAction = (attachment_pt & ATTACHMENT_ADD) ? RLV_WEAR_ADD : RLV_WEAR_REPLACE; + RlvAttachmentLockWatchdog::instance().onWearAttachment(itemp, eWearAction);; + + attachment_pt |= ATTACHMENT_ADD; + } +// [/RLVa:KB] LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_RezSingleAttachmentFromInv); @@ -4115,6 +4172,11 @@ 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()) { @@ -4133,6 +4195,13 @@ 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-02-27 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a + else if ( (rlv_handler_t::isEnabled()) && (!gRlvAttachmentLocks.canAttach(item)) ) + { + disabled_items.push_back(std::string("Object Wear")); + } +// [/RLVa:KB] + LLMenuGL* attach_menu = menu.findChildMenuByName("Attach To", TRUE); LLMenuGL* attach_hud_menu = menu.findChildMenuByName("Attach To HUD", TRUE); if (attach_menu @@ -4317,6 +4386,10 @@ void remove_inventory_category_from_avatar_step2( BOOL proceed, LLUUID category_ if (get_is_item_worn(item->getUUID())) { /* +// [RLVa:KB] - Checked: 2010-04-04 (RLVa-1.2.0c) | Modified: RLVa-0.2.2a + if ( (rlv_handler_t::isEnabled()) && (!gRlvWearableLocks.canRemove(item)) ) + continue; +// [/RLVa:KB] LLWearableList::instance().getAsset(item->getAssetUUID(), item->getName(), item->getType(), @@ -4335,7 +4408,10 @@ void remove_inventory_category_from_avatar_step2( BOOL proceed, LLUUID category_ for(i = 0; i < obj_count; ++i) { LLViewerInventoryItem *obj_item = obj_item_array.get(i); - if (get_is_item_worn(obj_item->getUUID())) +// if (get_is_item_worn(obj_item->getUUID())) +// [RLVa:KB] - Checked: 2010-03-16 (RLVa-1.2.0a) | Modified: RLVa-1.0.5a + if ((get_is_item_worn(obj_item->getUUID())) && ((!rlv_handler_t::isEnabled()) || (gRlvAttachmentLocks.canDetach(obj_item)))) +// [/RVLa:KB] { LLVOAvatarSelf::detachAttachmentIntoInventory(obj_item->getLinkedUUID()); } @@ -4493,6 +4569,12 @@ 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 { @@ -4500,6 +4582,17 @@ void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags) items.push_back(std::string("Wearable Add")); 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 Wear")); + if ((eWearMask & RLV_WEAR_ADD) == 0) + disabled_items.push_back(std::string("Wearable Add")); + } +// [/RLVa:KB] } break; default: @@ -4675,6 +4768,15 @@ void LLWearableBridge::onRemoveFromAvatarArrived(LLWearable* wearable, { OnRemoveStruct *on_remove_struct = (OnRemoveStruct*) userdata; const LLUUID &item_id = gInventory.getLinkedItemID(on_remove_struct->mUUID); + +// [RLVa:KB] - Checked: 2010-03-20 (RLVa-1.2.0c) | Modified: RLVa-1.2.0a + if ( (rlv_handler_t::isEnabled()) && ((!wearable) || (!gRlvWearableLocks.canRemove(gInventory.getItem(item_id)))) ) + { + delete on_remove_struct; + return; + } +// [/RLVa:KB] + if(wearable) { if( get_is_item_worn( item_id ) ) @@ -4718,6 +4820,11 @@ void LLWearableBridge::removeAllClothesFromAvatar() const LLWearable *wearable = gAgentWearables.getWearableFromItemID(item_id); if (!wearable) continue; + +// [RLVa:KB] - Checked: 2010-05-14 (RLVa-1.2.0g) | Modified: RLVa-1.2.0g + if ( (rlv_handler_t::isEnabled()) && (!gRlvWearableLocks.canRemove(item)) ) + continue; +// [/RLVa:KB] // Find and remove this item from the COF. LLAppearanceMgr::instance().removeCOFItemLinks(item_id,false); @@ -4726,7 +4833,10 @@ void LLWearableBridge::removeAllClothesFromAvatar() gInventory.notifyObservers(); // Remove wearables from gAgentWearables - LLAgentWearables::userRemoveAllClothes(); +// LLAgentWearables::userRemoveAllClothes(); +// [RLVa:KB] - Checked: 2010-05-14 (RLVa-1.2.0g) | Modified: RLVa-1.2.0g + LLAppearanceMgr::instance().updateAppearanceFromCOF(); +// [/RLVa:KB] } // static diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 53835f0166ebed6a4cb51644243d84661d3f8527..04f9ba731cb8db9cb52ea0cbf8f27a13062ceff6 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -46,6 +46,9 @@ #include "llviewerregion.h" #include "llcallbacklist.h" #include "llvoavatarself.h" +// [RLVa:KB] - Checked: RLVa-1.2.0a (2010-03-05) +#include "rlvhandler.h" +// [/RLVa:KB] //#define DIFF_INVENTORY_FILES #ifdef DIFF_INVENTORY_FILES @@ -2442,6 +2445,14 @@ void LLInventoryModel::processSaveAssetIntoInventory(LLMessageSystem* msg, llinfos << "LLInventoryModel::processSaveAssetIntoInventory item" " not found: " << item_id << llendl; } + +// [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(); @@ -2492,6 +2503,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/lllocationinputctrl.cpp b/indra/newview/lllocationinputctrl.cpp index d714cae872de955a119a0c14f163170dd7204bc8..7126bcf28ab69ecb8a582867cc0bbd1e8964c0a0 100644 --- a/indra/newview/lllocationinputctrl.cpp +++ b/indra/newview/lllocationinputctrl.cpp @@ -59,6 +59,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] //============================================================================ /* @@ -589,16 +592,31 @@ void LLLocationInputCtrl::reshape(S32 width, S32 height, BOOL called_from_parent void LLLocationInputCtrl::onInfoButtonClicked() { +// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) + return; +// [/RLVa:KB] + LLSideTray::getInstance()->showPanel("panel_places", LLSD().with("type", "agent")); } void LLLocationInputCtrl::onForSaleButtonClicked() { +// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) + return; +// [/RLVa:KB] + handle_buy_land(); } void LLLocationInputCtrl::onAddLandmarkButtonClicked() { +// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d + 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()) @@ -715,6 +733,10 @@ void LLLocationInputCtrl::onTextEditorRightClicked(S32 x, S32 y, MASK mask) void LLLocationInputCtrl::refresh() { +// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d + mInfoBtn->setEnabled(!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)); +// [/RLVa:KB] + refreshLocation(); // update location string refreshParcelIcons(); updateAddLandmarkButton(); // indicate whether current parcel has been landmarked @@ -986,6 +1008,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.2.0d) | Added: RLVa-1.2.0d + mAddLandmarkBtn->setVisible(!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)); +// [/RLVa:KB] enableAddLandmarkButton(LLLandmarkActions::hasParcelLandmark()); } void LLLocationInputCtrl::updateAddLandmarkTooltip() @@ -1015,6 +1040,9 @@ void LLLocationInputCtrl::updateContextMenu(){ { landmarkItem->setLabel(LLTrans::getString("EditLandmarkNavBarMenu")); } +// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d + landmarkItem->setEnabled(!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)); +// [/RLVa:KB] } } void LLLocationInputCtrl::updateWidgetlayout() @@ -1070,17 +1098,24 @@ void LLLocationInputCtrl::onLocationContextMenuItemClicked(const LLSD& userdata) } else if (item == "landmark") { - LLViewerInventoryItem* landmark = LLLandmarkActions::findLandmarkForAgentPos(); - - if(!landmark) +// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d + if (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) { - LLSideTray::getInstance()->showPanel("panel_places", LLSD().with("type", "create_landmark")); - } - else - { - LLSideTray::getInstance()->showPanel("panel_places", - LLSD().with("type", "landmark").with("id",landmark->getUUID())); +// [/RLVa:KB] + LLViewerInventoryItem* landmark = LLLandmarkActions::findLandmarkForAgentPos(); + + if(!landmark) + { + LLSideTray::getInstance()->showPanel("panel_places", LLSD().with("type", "create_landmark")); + } + else + { + LLSideTray::getInstance()->showPanel("panel_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/llmaniptranslate.cpp b/indra/newview/llmaniptranslate.cpp index 5eb3b789f2656991e8bd7a92fd66b7970bb06f98..4dd90f07940d3a5b23c2478feb513cd35422dcbf 100644 --- a/indra/newview/llmaniptranslate.cpp +++ b/indra/newview/llmaniptranslate.cpp @@ -60,6 +60,9 @@ #include "llworld.h" #include "llui.h" #include "pipeline.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 3d0f4cc1ed40528d8d96987522f24b2ba9dcee42..e52ac79d3905280fca5ef2e128dad5b708124427 100644 --- a/indra/newview/llmoveview.cpp +++ b/indra/newview/llmoveview.cpp @@ -48,6 +48,9 @@ #include "llviewerparcelmgr.h" #include "llviewerregion.h" #include "lltooltip.h" +// [RLVa:KB] - Checked: 2010-03-07 (RLVa-1.2.0c) +#include "rlvhandler.h" +// [/RLVa:KB] // // Constants @@ -701,8 +704,15 @@ LLPanelStandStopFlying* LLPanelStandStopFlying::getStandStopFlyingPanel() void LLPanelStandStopFlying::onStandButtonClick() { - LLSelectMgr::getInstance()->deselectAllForStandingUp(); - gAgent.setControlFlags(AGENT_CONTROL_STAND_UP); +// [RLVa:KB] - Checked: 2010-03-07 (RLVa-1.2.0c) | Added: RLVa-1.2.0a + if ( (!rlv_handler_t::isEnabled()) || (gRlvHandler.canStand()) ) + { + 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/llnearbychatbar.cpp b/indra/newview/llnearbychatbar.cpp index 4f9845d704297aeef8599bb2ffdbb91fe31d77a3..d343d9049be234fd02d3b846fa8ea8371cd2e509 100644 --- a/indra/newview/llnearbychatbar.cpp +++ b/indra/newview/llnearbychatbar.cpp @@ -46,11 +46,17 @@ #include "llwindow.h" #include "llviewerwindow.h" #include "llrootview.h" +// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0b) +#include "rlvhandler.h" +// [/RLVa:KB] S32 LLNearbyChatBar::sLastSpecialChatChannel = 0; // 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-1.2.0b) | Modified: RLVa-0.2.2a +void send_chat_from_viewer(std::string utf8_out_text, EChatType type, S32 channel); +// [/RLVa:KB] static LLDefaultChildRegistry::Register<LLGestureComboList> r("gesture_combo_list"); @@ -495,7 +501,10 @@ void LLNearbyChatBar::onChatBoxKeystroke(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 + if ( (length > 0) && (raw_text[0] != '/') && (!gRlvHandler.hasBehaviour(RLV_BHVR_REDIRCHAT)) ) +// [/RLVa:KB] { gAgent.startTyping(); } @@ -708,6 +717,21 @@ void LLNearbyChatBar::sendChatFromViewer(const LLWString &wtext, EChatType type, utf8_text = utf8str_truncate(utf8_text, MAX_STRING - 1); } +// [RLVa:KB] - Checked: 2010-03-27 (RLVa-1.2.0b) | Modified: RLVa-1.2.0b + if ( (0 == channel) && (rlv_handler_t::isEnabled()) ) + { + // Adjust the (public) chat "volume" on chat and gestures (also takes care of playing the proper animation) + 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)) { @@ -838,8 +862,57 @@ LLWString LLNearbyChatBar::stripChannelNumber(const LLWString &mesg, S32* channe } } -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 ( (gRlvHandler.hasBehaviour(RLV_BHVR_SENDCHANNEL)) && (!gRlvHandler.isException(RLV_BHVR_SENDCHANNEL, 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/llnearbychathandler.cpp b/indra/newview/llnearbychathandler.cpp index a747c228a6683ea35bb23d8c78d89236ae598710..284b27d22d1d8781138bdde1560730e7e54a599e 100644 --- a/indra/newview/llnearbychathandler.cpp +++ b/indra/newview/llnearbychathandler.cpp @@ -40,6 +40,10 @@ #include "llfloaterreg.h"//for LLFloaterReg::getTypedInstance #include "llviewerwindow.h"//for screen channel position +// [RLVa:KB] - Checked: 2010-04-21 (RLVa-1.2.0f) +#include "rlvhandler.h" +// [/RLVa:KB] + //add LLNearbyChatHandler to LLNotificationsUI namespace using namespace LLNotificationsUI; @@ -340,7 +344,10 @@ void LLNearbyChatHandler::processChat(const LLChat& chat_msg, const LLSD &args) { if(chat_msg.mMuted == TRUE) return; - if(chat_msg.mSourceType == CHAT_SOURCE_AGENT && chat_msg.mFromID.notNull()) +// if(chat_msg.mSourceType == CHAT_SOURCE_AGENT && chat_msg.mFromID.notNull()) +// [RLVa:KB] - Checked: 2010-04-20 (RLVa-1.2.0f) | Added: RLVa-1.2.0f + if ( (chat_msg.mSourceType == CHAT_SOURCE_AGENT && chat_msg.mFromID.notNull()) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) ) +// [/RLVa:KB] LLRecentPeople::instance().add(chat_msg.mFromID); if(chat_msg.mText.empty()) @@ -348,6 +355,23 @@ void LLNearbyChatHandler::processChat(const LLChat& chat_msg, const LLSD &args) LLChat& tmp_chat = const_cast<LLChat&>(chat_msg); +// [RLVa:KB] - Checked: 2010-04-20 (RLVa-1.2.0f) | Modified: RLVa-1.2.0f + if (rlv_handler_t::isEnabled()) + { + // NOTE-RLVa: we can only filter the *message* here since most everything else will already be part of "args" as well + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) && (!tmp_chat.mRlvLocFiltered) && (CHAT_SOURCE_AGENT != tmp_chat.mSourceType) ) + { + RlvUtil::filterLocation(tmp_chat.mText); + tmp_chat.mRlvLocFiltered = TRUE; + } + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (!tmp_chat.mRlvNamesFiltered) && (CHAT_SOURCE_AGENT != tmp_chat.mSourceType) ) + { + RlvUtil::filterNames(tmp_chat.mText); + tmp_chat.mRlvNamesFiltered = TRUE; + } + } +// [/RLVa:KB] + LLNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLNearbyChat>("nearby_chat", LLSD()); { //sometimes its usefull to have no name at all... @@ -434,6 +458,10 @@ void LLNearbyChatHandler::processChat(const LLChat& chat_msg, const LLSD &args) notification["source"] = (S32)chat_msg.mSourceType; notification["chat_type"] = (S32)chat_msg.mChatType; notification["chat_style"] = (S32)chat_msg.mChatStyle; +// [RLVa:KB] - Checked: 2010-04-20 (RLVa-1.2.0f) | Added: RLVa-1.2.0f + if (rlv_handler_t::isEnabled()) + notification["show_icon_tooltip"] = !chat_msg.mRlvNamesFiltered; +// [/RLVa:KB] std::string r_color_name = "White"; F32 r_color_alpha = 1.0f; diff --git a/indra/newview/llnetmap.cpp b/indra/newview/llnetmap.cpp index 6db8001d57a1d8130d3c414ebbebc8aabeace7e9..36b7e2c07639d0b8841d4e2f3bf12f842b9e438d 100644 --- a/indra/newview/llnetmap.cpp +++ b/indra/newview/llnetmap.cpp @@ -58,6 +58,9 @@ #include "llviewerwindow.h" #include "llworld.h" #include "llworldmapview.h" // shared draw code +// [RLVa:KB] - Checked: 2010-04-19 (RLVa-1.2.0f) +#include "rlvhandler.h" +// [/RLVa:KB] static LLDefaultChildRegistry::Register<LLNetMap> r1("net_map"); @@ -354,7 +357,11 @@ void LLNetMap::draw() BOOL show_as_friend = FALSE; if( i < regionp->mMapAvatarIDs.count()) { - show_as_friend = (LLAvatarTracker::instance().getBuddyInfo(regionp->mMapAvatarIDs.get(i)) != NULL); +// [RLVa:KB] - Checked: 2010-04-19 (RLVa-1.2.0f) | Modified: RLVa-1.2.0f + show_as_friend = (LLAvatarTracker::instance().getBuddyInfo(regionp->mMapAvatarIDs.get(i)) != NULL) && + (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)); +// [/RLVa:KB] +// show_as_friend = (LLAvatarTracker::instance().getBuddyInfo(regionp->mMapAvatarIDs.get(i)) != NULL); } LLWorldMapView::drawAvatar( pos_map.mV[VX], pos_map.mV[VY], @@ -568,35 +575,57 @@ BOOL LLNetMap::handleToolTip( S32 x, S32 y, MASK mask ) return FALSE; } + LLStringUtil::format_map_t args; std::string avatar_name; if(mClosestAgentToCursor.notNull() && gCacheName->getFullName(mClosestAgentToCursor, avatar_name)) { - // only show tooltip if same inspector not already open - LLFloater* existing_inspector = LLFloaterReg::findInstance("inspect_avatar"); - if (!existing_inspector - || !existing_inspector->getVisible() - || existing_inspector->getKey()["avatar_id"].asUUID() != mClosestAgentToCursor) +// [RLVa:KB] - Checked: 2010-08-08 (RLVa-1.2.0h) | Added: RLVa-1.2.0h | RLVa-1.2.0-final + if (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) { - LLInspector::Params p; - p.fillFrom(LLUICtrlFactory::instance().getDefaultParams<LLInspector>()); - p.message(avatar_name); - p.image.name("Inspector_I"); - p.click_callback(boost::bind(showAvatarInspector, mClosestAgentToCursor)); - p.visible_time_near(6.f); - p.visible_time_far(3.f); - p.delay_time(0.35f); - p.wrap(false); - - LLToolTipMgr::instance().show(p); +// [/RLVa:KB] + // only show tooltip if same inspector not already open + LLFloater* existing_inspector = LLFloaterReg::findInstance("inspect_avatar"); + if (!existing_inspector + || !existing_inspector->getVisible() + || existing_inspector->getKey()["avatar_id"].asUUID() != mClosestAgentToCursor) + { + LLInspector::Params p; + p.fillFrom(LLUICtrlFactory::instance().getDefaultParams<LLInspector>()); + p.message(avatar_name); + p.image.name("Inspector_I"); + p.click_callback(boost::bind(showAvatarInspector, mClosestAgentToCursor)); + p.visible_time_near(6.f); + p.visible_time_far(3.f); + p.delay_time(0.35f); + p.wrap(false); + + LLToolTipMgr::instance().show(p); + } + return TRUE; +// [RLVa:KB] - Checked: 2010-08-08 (RLVa-1.2.0h) | Added: RLVa-1.2.0h | RLVa-1.2.0-final } - return TRUE; + else + { + args["[AGENT]"] = RlvStrings::getAnonym(avatar_name) + "\n"; + } +// [/RLVa:KB] + } +// [RLVa:KB] - Checked: 2010-08-08 (RLVa-1.2.0h) | Added: RLVa-1.2.0h | RLVa-1.2.0-final + else + { + args["[AGENT]"] = ""; } +// [/RLVa:KB] - LLStringUtil::format_map_t args; +// LLStringUtil::format_map_t args; LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal( viewPosToGlobal( x, y ) ); if( region ) { - args["[REGION]"] = region->getName() + "\n"; +// [RLVa:KB] - Checked: 2010-04-19 (RLVa-1.2.0f) | Modified: RLVa-1.2.0f + args["[REGION]"] = + ((!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) ? region->getName() : RlvStrings::getString(RLV_STRING_HIDDEN_REGION)) + "\n"; +// [/RLVa:KB] +// args["[REGION]"] = region->getName() + "\n"; } else { diff --git a/indra/newview/llnotificationofferhandler.cpp b/indra/newview/llnotificationofferhandler.cpp index 85f95bd0c718ef0a2f395e6df1ca24d4e9210bed..be9ff2813224dd68b1e653895048e3e3e65c5116 100644 --- a/indra/newview/llnotificationofferhandler.cpp +++ b/indra/newview/llnotificationofferhandler.cpp @@ -100,7 +100,13 @@ bool LLOfferHandler::processNotification(const LLSD& notify) notification->setReusable(LLHandlerUtil::isNotificationReusable(notification)); LLUUID session_id; - if (LLHandlerUtil::canSpawnIMSession(notification)) +// if (LLHandlerUtil::canSpawnIMSession(notification)) +// [RLVa:KB] - Checked: 2010-04-20 (RLVa-1.2.0f) | Added: RLVa-1.2.0f + // Don't spawn a new IM session for inventory offers if this notification was subject to @shownames=n + // RELEASE-RLVa: [SL-2.0.1] Test on every new release to make sure the notification gets routed the way we want it to be + bool fSpawnIM = (LLHandlerUtil::canSpawnIMSession(notification)) && (!notification->getPayload().has("rlv_shownames")); + if (fSpawnIM) +// [/RLVa:KB] { const std::string name = LLHandlerUtil::getSubstitutionName(notification); @@ -110,7 +116,12 @@ bool LLOfferHandler::processNotification(const LLSD& notify) } bool show_toast = LLHandlerUtil::canSpawnToast(notification); - bool add_notid_to_im = LLHandlerUtil::canAddNotifPanelToIM(notification); +// bool add_notid_to_im = LLHandlerUtil::canAddNotifPanelToIM(notification); +// [RLVa:KB] - Checked: 2010-04-20 (RLVa-1.2.0f) | Added: RLVa-1.2.0f + // NOTE: add_notid_to_im needs to be FALSE if we suppressed spawning an IM because in that case the notification needs to + // be routed to the "syswell" or the inventory offer floater will dissapear and the user won't be able to accept it + bool add_notid_to_im = (fSpawnIM) && (LLHandlerUtil::canAddNotifPanelToIM(notification)); +// [/RLVa:KB] if (add_notid_to_im) { LLHandlerUtil::addNotifPanelToIM(notification); @@ -149,7 +160,15 @@ bool LLOfferHandler::processNotification(const LLSD& notify) if (LLHandlerUtil::canLogToIM(notification)) { // log only to file if notif panel can be embedded to IM and IM is opened - if (add_notid_to_im && LLHandlerUtil::isIMFloaterOpened(notification)) +// [RLVa:KB] - Checked: 2010-04-20 (RLVa-1.2.0f) | Added: RLVa-1.2.0f + if (notification->getPayload().has("rlv_shownames")) + { + // Log to chat history if this notification was subject to @shownames=n + LLHandlerUtil::logToNearbyChat(notification, CHAT_SOURCE_SYSTEM); + } + else if (add_notid_to_im && LLHandlerUtil::isIMFloaterOpened(notification)) +// [/RLVa:KB] +// if (add_notid_to_im && LLHandlerUtil::isIMFloaterOpened(notification)) { LLHandlerUtil::logToIMP2P(notification, true); } @@ -170,8 +189,25 @@ bool LLOfferHandler::processNotification(const LLSD& notify) } else { - if (LLHandlerUtil::canAddNotifPanelToIM(notification) - && !LLHandlerUtil::isIMFloaterOpened(notification)) +// if (LLHandlerUtil::canAddNotifPanelToIM(notification) +// && !LLHandlerUtil::isIMFloaterOpened(notification)) +// [SL:KB] - Checked: 2010-04-20 (RLVa-1.2.0f) | Added: RLVa-1.2.0f + // Repro: + // 1) have someone drop you 2 inventory items (new IM session will be spawned) + // 2) accept/decline the inventory offers as they come in + // -> unread IM counter shows 0 + // 3) toggle "Enable plain text chat history" while the IM session with the inventory offers isn't the active session + // -> unread IM counter shows -2 + // -> LLHandlerUtil::decIMMesageCounter() really should be fixed to check for "0" before decreasing the count but + // there are enough bugfixes in RLVa as it is already :( + // Fix: + // - 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); + LLToast* pToast = (pChannel) ? pChannel->getToastByNotificationID(notification->getID()) : NULL; + if ( (pToast) && (!pToast->getCanBeStored()) ) +// [/SL:KB] { LLHandlerUtil::decIMMesageCounter(notification); } @@ -186,7 +222,11 @@ bool LLOfferHandler::processNotification(const LLSD& notify) void LLOfferHandler::onDeleteToast(LLToast* toast) { - if (!LLHandlerUtil::canAddNotifPanelToIM(toast->getNotification())) +// if (!LLHandlerUtil::canAddNotifPanelToIM(toast->getNotification())) +// [RLVa:KB] - Checked: 2010-04-20 (RLVa-1.2.0f) | Added: RLVa-1.2.0f + // BUGFIX: LLHandlerUtil::canAddNotifPanelToIM() won't necessarily tell us whether the notification went into an IM or to the syswell + if (toast->getCanBeStored()) +// [/RLVa:KB] { // send a signal to the counter manager mDelNotificationSignal(); diff --git a/indra/newview/lloverlaybar.cpp b/indra/newview/lloverlaybar.cpp index c2bbec04700ed77ec65745199c7d76c6cb9033d9..f79ec6432d1920d51cd92640133f0d0c50cdf359 100644 --- a/indra/newview/lloverlaybar.cpp +++ b/indra/newview/lloverlaybar.cpp @@ -297,6 +297,13 @@ void LLOverlayBar::onClickMouselook(void*) //static void LLOverlayBar::onClickStandUp(void*) { +// [RLVa:KB] - Checked: 2009-07-10 (RLVa-1.0.0g) + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) && (gAgent.getAvatarObject()) && (gAgent.getAvatarObject()->mIsSitting) ) + { + return; + } +// [/RLVa:KB] + LLSelectMgr::getInstance()->deselectAllForStandingUp(); gAgent.setControlFlags(AGENT_CONTROL_STAND_UP); } diff --git a/indra/newview/llpanelcontents.cpp b/indra/newview/llpanelcontents.cpp index bf3bf38863e8f95c7ec80fcc18235999101baac0..31f60bee9cd376649a3d2b6aca9093b5383dd7fe 100644 --- a/indra/newview/llpanelcontents.cpp +++ b/indra/newview/llpanelcontents.cpp @@ -59,6 +59,9 @@ #include "llviewerregion.h" #include "llviewerwindow.h" #include "llworld.h" +// [RLVa:KB] - Checked: 2010-03-31 (RLVa-1.2.0c) +#include "rlvhandler.h" +// [/RLVa:KB] // // Imported globals @@ -120,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 && @@ -154,6 +176,22 @@ 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()] + { + const LLViewerObject* pObjRoot = object->getRootEdit(); + if (gRlvAttachmentLocks.isLockedAttachment(pObjRoot)) + { + 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() == pObjRoot) ) + 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); perm.initMasks( diff --git a/indra/newview/llpanelland.cpp b/indra/newview/llpanelland.cpp index 04c1a86f69fd73fee2dfc166aba0e7ea25ab45b2..70ea2905000b05eb99a1a0db6ba7d6592222bcbb 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/llpanelobject.cpp b/indra/newview/llpanelobject.cpp index d756a1b931abd4f508728ee86b7055b36d2bb4cb..5d80f9fcc87eaff2853c9a98ffa52d2a0f000165 100644 --- a/indra/newview/llpanelobject.cpp +++ b/indra/newview/llpanelobject.cpp @@ -68,6 +68,9 @@ #include "llviewercontrol.h" #include "lluictrlfactory.h" //#include "llfirstuse.h" +// [RLVa:KB] - Checked: 2010-03-31 (RLVa-1.2.0c) +#include "rlvhandler.h" +// [/RLVa:KB] #include "lldrawpool.h" @@ -383,6 +386,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 211b9cf4b1a281fa23089b9386b1825daba8a6b1..c801ac5cfbf23608b23ab510b4a750cca1eda26a 100644 --- a/indra/newview/llpanelobjectinventory.cpp +++ b/indra/newview/llpanelobjectinventory.cpp @@ -63,7 +63,10 @@ #include "llviewerregion.h" #include "llviewerobjectlist.h" #include "llviewermessage.h" - +// [RLVa:KB] - Checked: 2010-03-27 (RLVa-1.2.0b) +#include "rlvhandler.h" +#include "rlvui.h" +// [/RLVa:KB] ///---------------------------------------------------------------------------- /// Class LLTaskInvFVBridge @@ -398,12 +401,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)) + { + 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)) + { + 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())) { @@ -669,6 +705,19 @@ void LLTaskInvFVBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { disabled_items.push_back(std::string("Task Open")); } +// [RLVa:KB] - Checked: 2010-03-01 (RLVa-1.2.0b) | Modified: RLVa-1.1.0a + else if (rlv_handler_t::isEnabled()) + { + 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] } items.push_back(std::string("Task Properties")); if(isItemRenameable()) @@ -1070,6 +1119,15 @@ 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())) ) + { + RlvUIEnabler::notifyBlockedViewXXX(LLAssetType::AT_SCRIPT); + return; + } +// [/RLVa:KB] + if (object->permModify() || gAgent.isGodlike()) { LLLiveLSLEditor* preview = LLFloaterReg::showTypedInstance<LLLiveLSLEditor>("preview_scriptedit", LLSD(mUUID), TAKE_FOCUS_YES); @@ -1128,6 +1186,13 @@ 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())) ) + { + RlvUIEnabler::notifyBlockedViewXXX(LLAssetType::AT_NOTECARD); + return; + } +// [/RLVa:KB] if(object->permModify() || gAgent.isGodlike()) { LLPreviewNotecard* preview = LLFloaterReg::showTypedInstance<LLPreviewNotecard>("preview_notecard", LLSD(mUUID), TAKE_FOCUS_YES); diff --git a/indra/newview/llpaneloutfitsinventory.h b/indra/newview/llpaneloutfitsinventory.h index f1ca1dbfeb20b48787dfcda47a96b82fd331ecc6..a6443c4dca75d0665e974ee0fd4cdf3801012cfd 100644 --- a/indra/newview/llpaneloutfitsinventory.h +++ b/indra/newview/llpaneloutfitsinventory.h @@ -56,6 +56,12 @@ public: static LLSidepanelAppearance* getAppearanceSP(); +// [RLVa:KB] - Checked: 2010-08-24 (RLVa-1.2.1a) | 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 06ba08b51c9ca4b90a8cca81a50aa767552e2ba7..c813ec8bc8f3db64776c3feb4ff2af8520201e50 100644 --- a/indra/newview/llpanelpeople.cpp +++ b/indra/newview/llpanelpeople.cpp @@ -60,6 +60,9 @@ #include "llvoiceclient.h" #include "llworld.h" #include "llspeakers.h" +// [RLVa:KB] - Checked: 2010-06-04 (RLVa-1.2.0d) +#include "rlvhandler.h" +// [/RLVa:KB] #define FRIEND_LIST_UPDATE_TIMEOUT 0.5 #define NEARBY_LIST_UPDATE_INTERVAL 1 @@ -532,6 +535,9 @@ BOOL LLPanelPeople::postBuild() mNearbyList->setNoItemsMsg(getString("no_one_near")); mNearbyList->setNoFilteredItemsMsg(getString("no_one_filtered_near")); mNearbyList->setShowIcons("NearbyListShowIcons"); +// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d + mNearbyList->setRlvCheckShowNames(true); +// [/RLVa:KB] mRecentList = getChild<LLPanel>(RECENT_TAB_NAME)->getChild<LLAvatarList>("avatar_list"); mRecentList->setNoItemsCommentText(getString("no_recent_people")); @@ -827,7 +833,11 @@ void LLPanelPeople::updateButtons() LLPanel* cur_panel = mTabContainer->getCurrentPanel(); if (cur_panel) { - cur_panel->getChildView("add_friend_btn")->setEnabled(!is_friend); +// cur_panel->getChildView("add_friend_btn")->setEnabled(!is_friend); +// [RLVa:KB] - Checked: 2010-07-20 (RLVa-1.2.0h) | Added: RLVa-1.2.0h + cur_panel->getChildView("add_friend_btn")->setEnabled( + !is_friend && ((!nearby_tab_active) || (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)))); +// [/RLBa:KB] if (friends_tab_active) { cur_panel->getChildView("del_btn")->setEnabled(multiple_selected); @@ -837,6 +847,13 @@ void LLPanelPeople::updateButtons() bool enable_calls = LLVoiceClient::getInstance()->isVoiceWorking() && LLVoiceClient::getInstance()->voiceEnabled(); +// [RLVa:KB] - Checked: 2010-06-04 (RLVa-1.2.0d) | Modified: RLVa-1.2.0d + if ( (nearby_tab_active) && (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) ) + { + item_selected = multiple_selected = false; + } +// [/RLBa:KB] + buttonSetEnabled("view_profile_btn",item_selected); buttonSetEnabled("share_btn", item_selected); buttonSetEnabled("im_btn", multiple_selected); // allow starting the friends conference for multiple selection diff --git a/indra/newview/llpanelpeople.h b/indra/newview/llpanelpeople.h index d0913ee756c7740bfc0b5a8a39951534791462d5..794909f8fb79783d4362011fcdaf2c33ddcba656 100644 --- a/indra/newview/llpanelpeople.h +++ b/indra/newview/llpanelpeople.h @@ -53,6 +53,10 @@ public: // when voice is available /*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal); +// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d + LLAvatarList* getNearbyList() { return mNearbyList; } +// [/RLVa:KB] + // internals class Updater; diff --git a/indra/newview/llpanelpermissions.cpp b/indra/newview/llpanelpermissions.cpp index e35574be6cadf6dbe9ef8537822fe53d2e1d8519..839bd3044521666f8d74649b5b946152c4123292 100644 --- a/indra/newview/llpanelpermissions.cpp +++ b/indra/newview/llpanelpermissions.cpp @@ -62,7 +62,9 @@ #include "llspinctrl.h" #include "roles_constants.h" #include "llgroupactions.h" - +// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) +#include "rlvhandler.h" +// [/RLVa:KB] U8 string_value_to_click_action(std::string p_value); std::string click_action_to_string_value( U8 action); @@ -329,8 +331,9 @@ void LLPanelPermissions::refresh() creators_identical = 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); @@ -358,8 +361,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: 2010-08-25 (RLVa-1.2.1b) | Modified: RLVa-1.2.1b + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) + { + // Only anonimize 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 == mOwnerID) || (RlvUtil::isNearbyAgent(mCreatorID))) ) + creator_name = RlvStrings::getAnonym(creator_name); + + // Only anonimize 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()) ) + owner_name = RlvStrings::getAnonym(owner_name); + } + + 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/llpanelprofile.h b/indra/newview/llpanelprofile.h index 0546c1858337300983bf31ad65aa86e3a7530ccf..f7a005be6a2daef480424c5e0c4f88a168f7fcc0 100644 --- a/indra/newview/llpanelprofile.h +++ b/indra/newview/llpanelprofile.h @@ -53,6 +53,10 @@ public: 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(); @@ -63,7 +67,7 @@ protected: LLTabContainer* getTabCtrl() { return mTabCtrl; } - const LLUUID& getAvatarId() { return mAvatarId; } +// const LLUUID& getAvatarId() { return mAvatarId; } void setAvatarId(const LLUUID& avatar_id) { mAvatarId = avatar_id; } diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp index d280cf162541e59728bef11446f246dae24f68a0..e36f151d18633824127415737f13ed0dcfd8759b 100644 --- a/indra/newview/llpreviewscript.cpp +++ b/indra/newview/llpreviewscript.cpp @@ -2116,6 +2116,16 @@ void LLLiveLSLEditor::onLoad(void* userdata) void LLLiveLSLEditor::onSave(void* userdata, BOOL close_after_save) { LLLiveLSLEditor* self = (LLLiveLSLEditor*)userdata; + +// [RLVa:KB] - Checked: 2009-10-10 (RLVa-1.0.5a) | Modified: RLVa-1.0.5a +/* + if ( (rlv_handler_t::isEnabled()) && (gRlvHandler.isLockedAttachment(gObjectList.findObject(self->mObjectID), RLV_LOCK_REMOVE)) ) + { + return; + } +*/ +// [/RLVa:KB] + self->mCloseAfterSave = close_after_save; self->saveIfNeeded(); } diff --git a/indra/newview/llscreenchannel.cpp b/indra/newview/llscreenchannel.cpp index 5c923a040950a02199f674e8ec36f914d9d62800..f18db49d0336fba66f52772c233f68c6d697dd90 100644 --- a/indra/newview/llscreenchannel.cpp +++ b/indra/newview/llscreenchannel.cpp @@ -882,8 +882,18 @@ LLToast* LLScreenChannel::getToastByNotificationID(LLUUID id) std::vector<ToastElem>::iterator it = find(mStoredToastList.begin(), mStoredToastList.end(), id); +// if (it == mStoredToastList.end()) +// return NULL; +// [SL:KB] - Checked: 2010-04-21 (RLVa-1.2.0f) | Added: RLVa-1.2.0f + // BUGFIX-SL: we need to get the visible toast in LLOfferHandler::processNotification() whether it's "stored" or not 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->toast; } diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index c9b60bf7f5e213920884db082ffe355ed93393ee..1ed93c7ca2f5bf832e1d1f8a4ae65bf5bb4bad48 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -87,6 +87,9 @@ #include "llvoavatarself.h" #include "llvovolume.h" #include "pipeline.h" +// [RLVa:KB] - Checked: 2010-03-23 (RLVa-1.2.0a) +#include "rlvhandler.h" +// [/RLVa:KB] #include "llglheaders.h" @@ -2736,6 +2739,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; @@ -3048,7 +3061,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"); @@ -3502,11 +3518,38 @@ void LLSelectMgr::convertTransient() void LLSelectMgr::deselectAllIfTooFar() { +// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Added: RLVa-1.2.0e + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_EDIT)) && (!mSelectedObjects->isEmpty()) ) + { + struct NotTransientOrFocusedMedia : public LLSelectedNodeFunctor + { + bool apply(LLSelectNode* node) + { + return (node) && (node->getObject()) && + ( (!node->isTransient()) && (node->getObject()->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: 2010-05-03 (RLVa-1.2.0g) | Modified: RLVa-1.1.0l +#ifdef RLV_EXTENSION_CMD_INTERACT + // [Fall-back code] Don't allow an active selection (except for HUD attachments - see above) when @interact=n restricted + if (gRlvHandler.hasBehaviour(RLV_BHVR_INTERACT)) + { + deselectAll(); + return; + } +#endif // RLV_EXTENSION_CMD_INTERACT +// [/RLVa:KB] + // HACK: Don't deselect when we're navigating to rate an object's // owner or creator. JC if (gMenuObject->getVisible()) @@ -3515,13 +3558,20 @@ 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 + 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") : 1.5f; +// [/RLVa:KB] F32 deselect_dist_sq = deselect_dist * deselect_dist; LLVector3d select_delta = gAgent.getPositionGlobal() - selectionCenter; @@ -5798,7 +5848,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; } @@ -5830,7 +5883,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/llsidepaneliteminfo.cpp b/indra/newview/llsidepaneliteminfo.cpp index 731079fb5d6fc6a45c2e503e706903111f273ce9..33d61216322ac5b51f4a276639dcc343e4122757 100644 --- a/indra/newview/llsidepaneliteminfo.cpp +++ b/indra/newview/llsidepaneliteminfo.cpp @@ -42,7 +42,9 @@ #include "llviewercontrol.h" #include "llviewerinventory.h" #include "llviewerobjectlist.h" - +// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) +#include "rlvhandler.h" +// [/RLVa:KB] //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLItemPropertiesObserver @@ -280,6 +282,16 @@ void LLSidepanelItemInfo::refreshFromItem(LLViewerInventoryItem* item) getChildView("BtnCreator")->setEnabled(TRUE); getChildView("LabelCreatorTitle")->setEnabled(TRUE); getChildView("LabelCreatorName")->setEnabled(TRUE); +// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) | Modified: RLVa-1.0.0e + // If the object creator matches the object owner we need to anonimize the creator field as well + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && + ( ((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 @@ -303,8 +315,15 @@ void LLSidepanelItemInfo::refreshFromItem(LLViewerInventoryItem* item) else { gCacheName->getFullName(perm.getOwner(), name); +// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) | Modified: RLVa-1.0.0e + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) + name = RlvStrings::getAnonym(name); +// [/RLVa:KB] } - getChildView("BtnOwner")->setEnabled(TRUE); +// getChildView("BtnOwner")->setEnabled(TRUE); +// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) | Added: RLVa-1.0.0e + getChildView("BtnOwner")->setEnabled(!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)); +// [/RLVa:KB] getChildView("LabelOwnerTitle")->setEnabled(TRUE); getChildView("LabelOwnerName")->setEnabled(TRUE); getChild<LLUICtrl>("LabelOwnerName")->setValue(name); @@ -606,6 +625,17 @@ void LLSidepanelItemInfo::onClickCreator() if(!item) return; if(!item->getCreatorUUID().isNull()) { +// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) | Added: RLVa-1.2.1b + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) + { + const LLPermissions& perm = item->getPermissions(); + if ( ((perm.isOwned()) && (!perm.isGroupOwned()) && (perm.getOwner() == item->getCreatorUUID()) ) || + (RlvUtil::isNearbyAgent(item->getCreatorUUID())) ) + { + return; + } + } +// [/RLVa:KB] LLAvatarActions::showProfile(item->getCreatorUUID()); } } @@ -621,6 +651,10 @@ void LLSidepanelItemInfo::onClickOwner() } else { +// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) | Modified: RLVa-1.0.0e + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) + return; +// [/RLVa:KB] LLAvatarActions::showProfile(item->getPermissions().getOwner()); } } diff --git a/indra/newview/llsidepaneltaskinfo.cpp b/indra/newview/llsidepaneltaskinfo.cpp index 4552088cadfee9a602d180898175bb7c8f0f705a..2b46c0fbef3030876e053291a000f8789638d575 100644 --- a/indra/newview/llsidepaneltaskinfo.cpp +++ b/indra/newview/llsidepaneltaskinfo.cpp @@ -61,6 +61,9 @@ #include "llspinctrl.h" #include "roles_constants.h" #include "llgroupactions.h" +// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) +#include "rlvhandler.h" +// [/RLVa:KB] ///---------------------------------------------------------------------------- /// Class llsidepaneltaskinfo @@ -295,8 +298,9 @@ void LLSidepanelTaskInfo::refresh() creators_identical = 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); @@ -324,8 +328,28 @@ void LLSidepanelTaskInfo::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: 2010-08-25 (RLVa-1.2.1b) | Added: RLVa-1.2.1b + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) + { + // Only anonimize 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 == mOwnerID) || (RlvUtil::isNearbyAgent(mCreatorID))) ) + creator_name = RlvStrings::getAnonym(creator_name); + + // Only anonimize 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()) ) + owner_name = RlvStrings::getAnonym(owner_name); + } + + 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/llsidetray.cpp b/indra/newview/llsidetray.cpp index 85b6e0dec45d378a27fc17a53ee745a9097eba12..9fe006ae29ac173cdb9b280f719c0f3d8b7f559e 100644 --- a/indra/newview/llsidetray.cpp +++ b/indra/newview/llsidetray.cpp @@ -502,6 +502,11 @@ bool LLSideTray::selectTabByName (const std::string& name) if (new_tab == mActiveTab) return false; +// [RLVa:KB] - Checked: 2010-03-01 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a + if ( (mValidateSignal) && (!(*mValidateSignal)(new_tab, LLSD(name))) ) + return false; +// [/RLVa:KB] + //deselect old tab if (mActiveTab) { @@ -926,7 +931,15 @@ LLPanel* LLSideTray::showPanel (const std::string& panel_name, const LLSD& para LLView* view = (*child_it)->findChildView(panel_name,true); if(view) { - selectTabByName ((*child_it)->getName()); +// [RLVa:KB] - Checked: 2010-03-01 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a + // NOTE: - selectTabByName() returns false if the tab is currently active so we can't use its return value to make a decision + // - "panel_name" is a name of a panel *inside* of the tab, not the name of the tab that's being switched to + const std::string& tab_name = (*child_it)->getName(); + if ( (mValidateSignal) && (!(*mValidateSignal)(getTab(tab_name), LLSD(tab_name))) ) + continue; + selectTabByName(tab_name); +// [/RLVa:KB] +// selectTabByName ((*child_it)->getName()); if(mCollapsed) expandSideBar(); @@ -1037,3 +1050,9 @@ void LLSideTray::updateSidetrayVisibility() } } +// [RLVa:KB] - Checked: 2010-03-01 (RLVa-1.2.0a) | Added: RLVa-1.2.0a +const LLPanel* LLSideTray::getActiveTab() const +{ + return mActiveTab; +} +// [/RLVa:KB] diff --git a/indra/newview/llsidetray.h b/indra/newview/llsidetray.h index f0cc2c11469a25b3f85408b9cdd8865eefa314b7..358ff89b959da981ebd8fe347f75626174f18cb1 100644 --- a/indra/newview/llsidetray.h +++ b/indra/newview/llsidetray.h @@ -109,7 +109,11 @@ public: /* * get currently active tab */ - const LLSideTrayTab* getActiveTab() const { return mActiveTab; } +// const LLSideTrayTab* getActiveTab() const { return mActiveTab; } +// [RLVa:KB] - Checked: 2010-03-01 (RLVa-1.2.0a) | Added: RLVa-1.2.0a + // *sighs* LLSideTrayTab is defined in llsidetray.cpp... we can make do with an LLPanel* though + const LLPanel* getActiveTab() const; +// [/RLVa:KB] /* * collapse SideBar, hiding visible tab and moving tab buttons @@ -134,6 +138,13 @@ public: } LLPanel* getButtonsPanel() { return mButtonsPanel; } +// [RLVa:KB] - Checked: 2010-02-28 (RLVa-1.2.0a) | Added: RLVa-1.2.0a + LLButton* getButtonFromName(const std::string& strName) + { + std::map<std::string, LLButton*>::const_iterator itBtn = mTabButtons.find(strName); + return (mTabButtons.end() != itBtn) ? itBtn->second : NULL; + } +// [/RLVa:KB] bool getCollapsed() { return mCollapsed; } diff --git a/indra/newview/llslurl.cpp b/indra/newview/llslurl.cpp index 4cf1df165555ce3098f91a3c64902d5e3ce3e479..4ac2e7ef6ea2068c2d95ca3c2d08e8735c4204ab 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"; @@ -381,8 +384,13 @@ std::string LLSLURL::getSLURLString() const S32 x = llround( (F32)mPosition[VX] ); S32 y = llround( (F32)mPosition[VY] ); S32 z = llround( (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 975d1f9f32cf77eebfca8057baf5fde16890fdff..58d65905df9b7542f3d01c4f33e9ad12314f74a3 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -186,6 +186,10 @@ #include "llavatariconctrl.h" #include "llvoicechannel.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" @@ -367,6 +371,13 @@ bool idle_startup() // Initialize stuff that doesn't need data from simulators // +// [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"); @@ -906,6 +917,18 @@ 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 +#ifndef RLV_EXTENSION_STARTLOCATION + if (rlv_handler_t::isEnabled()) +#else + if ( (rlv_handler_t::isEnabled()) && (RlvSettings::getLoginLastLocation()) ) +#endif // RLV_EXTENSION_STARTLOCATION + { + // Force login at the last location + LLStartUp::setStartSLURL(LLSLURL(LLSLURL::SIM_LOCATION_LAST)); + } +// [/RLVa:KB] + switch (LLStartUp::getStartSLURL().getType()) { case LLSLURL::LOCATION: @@ -1664,6 +1687,14 @@ bool idle_startup() llinfos << "Creating Inventory Views" << llendl; LLFloaterReg::getInstance("inventory"); +// [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 ); return FALSE; } diff --git a/indra/newview/llstatusbar.cpp b/indra/newview/llstatusbar.cpp index b622e9897126979517a9da81c10e96d9ecde42f7..112b058183601a7f1b7780ca0564eb3d3aa7b98f 100644 --- a/indra/newview/llstatusbar.cpp +++ b/indra/newview/llstatusbar.cpp @@ -84,7 +84,6 @@ // system includes #include <iomanip> - // // Globals // diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp index 54484a1dbb523821d12699e07a1fc2d47a5b1ad8..62d67a794efcbecec46edb5933267136cdb5178e 100644 --- a/indra/newview/lltooldraganddrop.cpp +++ b/indra/newview/lltooldraganddrop.cpp @@ -58,6 +58,9 @@ #include "llviewerwindow.h" #include "llvoavatarself.h" #include "llworld.h" +// [RLVa:KB] - Checked: 2010-03-04 (RLVa-1.2.0a) +#include "rlvhandler.h" +// [/RLVa:KB] // syntactic sugar #define callMemberFunction(object,ptrToMember) ((object).*(ptrToMember)) @@ -1135,6 +1138,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] + //llinfos << "Rezzing object" << llendl; make_ui_sound("UISndObjectRezIn"); LLViewerInventoryItem* item; @@ -1400,6 +1412,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; @@ -1574,6 +1603,14 @@ EAcceptance LLToolDragAndDrop::dad3dRezAttachmentFromInv( return ACCEPT_NO; } +// [RLVa:KB] - Checked: 2010-03-04 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a + // RELEASE-RLVa: [SL-2.0.0] This will need revisiting for "ENABLE_MULTIATTACHMENTS" + if ( (rlv_handler_t::isEnabled()) && (!gRlvAttachmentLocks.canAttach(item)) ) + { + return ACCEPT_NO_LOCKED; + } +// [/RLVa:KB] + if (drop) { if (mSource == SOURCE_LIBRARY) @@ -1599,6 +1636,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.0.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); @@ -1660,6 +1705,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.0.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) { @@ -1863,6 +1920,13 @@ EAcceptance LLToolDragAndDrop::dad3dWearItem( return ACCEPT_NO; } +// [RLVa:KB] - Checked: 2010-03-20 (RLVa-1.2.0c) | Modified: RLVa-1.2.0a + if ( (rlv_handler_t::isEnabled()) && (RLV_WEAR_LOCKED == gRlvWearableLocks.canWear(item)) ) + { + return ACCEPT_NO_LOCKED; + } +// [/RLVa:KB] + if (drop) { // TODO: investigate wearables may not be loaded at this point EXT-8231 diff --git a/indra/newview/lltoolface.cpp b/indra/newview/lltoolface.cpp index a00ac10698a9798958d9d435e483c01463eef503..20fffb3012cf5c71068df72a33a9ef9fdf320000 100644 --- a/indra/newview/lltoolface.cpp +++ b/indra/newview/lltoolface.cpp @@ -39,6 +39,9 @@ #include "llviewerobject.h" #include "llviewerwindow.h" #include "llfloatertools.h" +// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) +#include "rlvhandler.h" +// [/RLVa:KB] // // Member functions @@ -90,6 +93,15 @@ void LLToolFace::pickCallback(const LLPickInfo& pick_info) return; } +// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Modified: RLVa-1.1.0l + if ( (rlv_handler_t::isEnabled()) && + ( (gRlvHandler.hasBehaviour(RLV_BHVR_EDIT)) || + ((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 b6c0f662e5a8e7cfbd1ce096ddb603842a633c7a..477a3d572b1920890bee23cd382910830aef1845 100644 --- a/indra/newview/lltoolgrab.cpp +++ b/indra/newview/lltoolgrab.cpp @@ -57,6 +57,9 @@ #include "llviewerwindow.h" #include "llvoavatarself.h" #include "llworld.h" +// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) +#include "rlvhandler.h" +// [/RLVa:KB] const S32 SLOP_DIST_SQ = 4; @@ -158,7 +161,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; @@ -428,6 +435,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/lltoolmgr.cpp b/indra/newview/lltoolmgr.cpp index 51c0e2eeed31cbd433c9c740fc7f6aed93172942..8f25ec4e9f765a1e018d5515327855bc08d2a173 100644 --- a/indra/newview/lltoolmgr.cpp +++ b/indra/newview/lltoolmgr.cpp @@ -55,7 +55,9 @@ #include "llviewerjoystick.h" #include "llviewermenu.h" #include "llviewerparcelmgr.h" - +// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) +#include "rlvhandler.h" +// [/RLVa:KB] // Used when app not active to avoid processing hover. LLTool* gToolNull = NULL; @@ -291,7 +293,14 @@ void LLToolMgr::toggleBuildMode() } } - +// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Modified: RLVa-1.0.0b + // TODO-RLVa: [RLVa-1.2.1] Does this code actually still ever trigger? + if (gRlvHandler.hasBehaviour(RLV_BHVR_EDIT)) + { + LLSelectMgr::getInstance()->deselectAll(); + } +// [/RLVa:KB] + setCurrentToolset(gBasicToolset); getCurrentToolset()->selectTool( LLToolCompCreate::getInstance() ); diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp index d8be70e54698b36ca8b3e7a438609811742aa33d..0d1a56b49457195948d2ecd3aef0b6c4d9ff067b 100644 --- a/indra/newview/lltoolpie.cpp +++ b/indra/newview/lltoolpie.cpp @@ -68,6 +68,9 @@ #include "llui.h" #include "llweb.h" #include "pipeline.h" // setHighlightObject +// [RLVa:KB] - Checked: 2010-03-06 (RLVa-1.2.0c) +#include "rlvhandler.h" +// [/RLVa:KB] extern BOOL gDebugClicks; @@ -184,6 +187,15 @@ BOOL LLToolPie::pickLeftMouseDownCallback() // 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()) { @@ -293,6 +305,14 @@ BOOL LLToolPie::pickLeftMouseDownCallback() ((object->usePhysics() || (parent && !parent->isAvatar() && parent->usePhysics())) || 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; LLToolMgr::getInstance()->getCurrentToolset()->selectTool( LLToolGrab::getInstance() ); return LLToolGrab::getInstance()->handleObjectHit( mPick ); @@ -405,7 +425,11 @@ ECursorType cursor_from_object(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()) || (gRlvHandler.canSit(object, LLToolPie::getInstance()->getHoverPick().mObjectOffset))) ) +// [/RLVa:KB] { cursor = UI_CURSOR_TOOLSIT; } @@ -500,6 +524,19 @@ BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask) 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] + if (object) { parent = object->getRootEdit(); @@ -521,7 +558,13 @@ BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask) gViewerWindow->setCursor(cursor); lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolPie (inactive)" << llendl; } - +// [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->usePhysics()) || (parent && !parent->isAvatar() && parent->usePhysics())) { @@ -861,6 +904,10 @@ BOOL LLToolPie::handleTooltipObject( LLViewerObject* hover_object, std::string l if (firstname && lastname) { avatar_name = llformat("%s %s", firstname->getString(), lastname->getString()); +// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Added: RLVa-1.2.0e + if ( (rlv_handler_t::isEnabled()) && (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) ) + avatar_name = RlvStrings::getAnonym(avatar_name); +// [/RLVa:KB] } else { @@ -869,17 +916,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(avatar_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(0.35f); - p.wrap(false); - - LLToolTipMgr::instance().show(p); +// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Added: RLVa-1.2.0e + if ( (!rlv_handler_t::isEnabled()) || + ( (gRlvHandler.canTouch(hover_object, mHoverPick.mObjectOffset)) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) ) ) + { +// [/RLVa:KB] + LLInspector::Params p; + p.fillFrom(LLUICtrlFactory::instance().getDefaultParams<LLInspector>()); + p.message(avatar_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(0.35f); + 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(avatar_name); + } +// [/RLVa:KB] } } else @@ -982,22 +1041,33 @@ 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(0.35f); - p.wrap(false); - - LLToolTipMgr::instance().show(p); +// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Added: RLVa-1.2.0e + if ( (!rlv_handler_t::isEnabled()) || (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(0.35f); + 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] } } } @@ -1009,6 +1079,11 @@ BOOL LLToolPie::handleToolTip(S32 local_x, S32 local_y, MASK mask) { if (!LLUI::sSettingGroups["config"]->getBOOL("ShowHoverTips")) return TRUE; if (!mHoverPick.isValid()) return TRUE; +// [RLVa:KB] - Checked: 2010-05-03 (RLVa-1.2.0g) | Modified: RLVa-1.2.0g +#ifdef RLV_EXTENSION_CMD_INTERACT + if (gRlvHandler.hasBehaviour(RLV_BHVR_INTERACT)) return TRUE; +#endif // RLV_EXTENSION_CMD_INTERACT +// [/RLVa:KB] LLViewerObject* hover_object = mHoverPick.getObject(); @@ -1520,16 +1595,29 @@ BOOL LLToolPie::pickRightMouseDownCallback() 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()) { @@ -1554,10 +1642,24 @@ BOOL LLToolPie::pickRightMouseDownCallback() mute_msg = LLTrans::getString("MuteObject2"); } - gMenuHolder->getChild<LLUICtrl>("Object Mute")->setValue(mute_msg); - 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] + gMenuHolder->getChild<LLUICtrl>("Object Mute")->setValue(mute_msg); + 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] } } diff --git a/indra/newview/lltoolpie.h b/indra/newview/lltoolpie.h index 65cb3e36a768d140375a97090a48f295c4d185b5..1d3453ba0b6428457d2500e50c74042325861f35 100644 --- a/indra/newview/lltoolpie.h +++ b/indra/newview/lltoolpie.h @@ -60,6 +60,9 @@ public: 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 93ba3b25587c79ecd6334255ccd5bec27a1b467e..5f2ab5fe5164b8f2c991adf1069864c17935fb55 100644 --- a/indra/newview/lltoolplacer.cpp +++ b/indra/newview/lltoolplacer.cpp @@ -43,6 +43,9 @@ #include "llviewerwindow.h" #include "llworld.h" #include "llui.h" +// [RLVa:KB] - Checked: 2010-03-23 (RLVa-1.2.0a) +#include "rlvhandler.h" +// [/RLVa:KB] //Headers added for functions moved from viewer.cpp #include "llvograss.h" @@ -123,6 +126,14 @@ 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)) && (dist_vec_squared(gAgent.getPositionGlobal(), pick.mPosGlobal) > 1.5f * 1.5f) ) + { + return FALSE; + } +// [/RLVa:KB] + // Find the sim where the surface lives. LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromPosGlobal(surface_pos_global); if (!regionp) @@ -240,7 +251,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 +512,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 7c604a04bf7b53f2e130028a5b0c3cc6c5c5a218..3ff7b5cf4848f5db79ce4e195025b531bf06b674 100644 --- a/indra/newview/lltoolselect.cpp +++ b/indra/newview/lltoolselect.cpp @@ -45,6 +45,10 @@ #include "llviewerwindow.h" #include "llvoavatarself.h" #include "llworld.h" +// [RLVa:KB] - Checked: 2010-03-06 (RLVa-1.2.0c) +#include "rlvhandler.h" +#include "llfloaterreg.h" +// [/RLVa:KB] // Globals //extern BOOL gAllowSelectAvatar; @@ -78,6 +82,35 @@ LLObjectSelectionHandle LLToolSelect::handleObjectSelection(const LLPickInfo& pi { object = object->getRootEdit(); } + +// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Modified: RLVa-1.1.0l + if (rlv_handler_t::isEnabled()) + { + if (gRlvHandler.hasBehaviour(RLV_BHVR_EDIT)) + { + if (!temp_select) + return LLSelectMgr::getInstance()->getSelection(); + else if (LLToolMgr::instance().inBuildMode()) + LLToolMgr::instance().toggleBuildMode(); + } + + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_FARTOUCH)) && (object) && ((!object->isAttachment()) || (!object->permYouOwner())) && + (dist_vec_squared(gAgent.getPositionAgent(), object->getPositionRegion()) > 1.5f * 1.5f) ) + { + // NOTE: see behaviour notes for a rather lengthy explanation of why we're doing things this way + //if (dist_vec_squared(gAgent.getPositionAgent(), object->getPositionRegion() + pick.mObjectOffset) > 1.5f * 1.5f) + if (dist_vec_squared(gAgent.getPositionAgent(), pick.mIntersection) > 1.5f * 1.5f) + { + if ( (LLFloaterReg::floaterInstanceVisible("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 8391c0f832a5bff6d41bcf0ac3d21da6165d9423..e2e229ac0aefbfc580eee2325db5e89de9fa3fe0 100644 --- a/indra/newview/lltracker.cpp +++ b/indra/newview/lltracker.cpp @@ -61,6 +61,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 cbb1d25f78e51609ad0d4a69900cb5f1ff2d5ea8..f124d717c3453e1433c6d77f8c3c1cd01053c7fa 100644 --- a/indra/newview/llviewercamera.cpp +++ b/indra/newview/llviewercamera.cpp @@ -40,6 +40,9 @@ #include "llworld.h" #include "lltoolmgr.h" #include "llviewerjoystick.h" +// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) +#include "rlvhandler.h" +// [/RLVa:KB] // Linden library includes #include "lldrawable.h" @@ -345,7 +348,10 @@ void LLViewerCamera::setPerspective(BOOL for_selection, if (limit_select_distance) { // ...select distance from control - z_far = gSavedSettings.getF32("MaxSelectDistance"); +// z_far = gSavedSettings.getF32("MaxSelectDistance"); +// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Added: RLVa-1.2.0e + z_far = (!gRlvHandler.hasBehaviour(RLV_BHVR_FARTOUCH)) ? gSavedSettings.getF32("MaxSelectDistance") : 1.5; +// [/RLVa:KB] } else { diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index d0ad918c58b05dd954e791a5c21b54e36c0f74a1..ddc313fb6494c2b277c89ebfc5ff911fb779bc5d 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -77,6 +77,9 @@ #include "llwlparammanager.h" #include "llwaterparammanager.h" #include "llpostprocess.h" +// [RLVa:KB] - Checked: 2010-08-22 (RLVa-1.2.1a) +#include "rlvhandler.h" +// [/RLVa:KB] extern LLPointer<LLViewerTexture> gStartTexture; @@ -908,7 +911,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, LLCriticalDamp::getInterpolant(0.03f)); diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index 87282985751572617025722faa36479c19d26ac2..d76a70de238bfb9ce8448cffdd75457aaae37fdc 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -120,7 +120,9 @@ #include "llsyswellwindow.h" #include "llscriptfloater.h" // *NOTE: Please add files in alphabetical order to keep merges easy. - +// [RLVa:KB] - Checked: 2010-03-11 +#include "rlvfloaters.h" +// [/RLVa:KB] void LLViewerFloaterReg::registerFloaters() { @@ -227,6 +229,10 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("reporter", "floater_report_abuse.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterReporter>); LLFloaterReg::add("reset_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterResetQueue>); LLFloaterReg::add("region_info", "floater_region_info.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterRegionInfo>); +// [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_locks", "floater_rlv_locks.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<RlvFloaterLocks>); +// [/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/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index daeace0ec5c9f2bf1e856dc13615bcac4e6d891e..bc8ddaa44eae4f8a8cdd2b088e96e797032f3e37 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -104,6 +104,10 @@ #include "lleconomy.h" #include "boost/unordered_map.hpp" +// [RLVa:KB] - Checked: 2010-03-09 (RLVa-1.2.0a) +#include "rlvhandler.h" +// [/RLVa:KB] + using namespace LLVOAvatarDefines; static boost::unordered_map<std::string, LLStringExplicit> sDefaultItemLabels; @@ -1076,7 +1080,10 @@ class LLAdvancedToggleWireframe : public view_listener_t { bool handleEvent(const LLSD& userdata) { - gUseWireframe = !(gUseWireframe); +// gUseWireframe = !(gUseWireframe); +// [RLVa:KB] - Checked: 2010-08-22 (RLVa-1.2.1a) | Added: RLVa-1.2.1a + gUseWireframe = (!gUseWireframe) && (!gRlvAttachmentLocks.hasLockedHUD()); +// [/RLVa:KB] LLPipeline::updateRenderDeferred(); gPipeline.resetVertexBuffers(); return true; @@ -2365,6 +2372,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] + LLMessageSystem *msg = gMessageSystem; msg->newMessageFast(_PREHASH_ObjectGrab); @@ -2468,7 +2484,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() @@ -2695,7 +2715,10 @@ bool enable_object_edit() } else if (LLSelectMgr::getInstance()->selectGetAllValidAndObjectsFound()) { - enable = true; +// enable = true; +// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Added: RLVa-1.2.0e + enable = !gRlvHandler.hasBehaviour(RLV_BHVR_EDIT); +// [/RLVa:KB] } return enable; @@ -2728,7 +2751,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; @@ -2771,7 +2797,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: 2010-08-25 (RLVa-1.2.1b) | Added: RLVa-1.2.1b + return !is_linden && !is_self && !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES); +// [/RLVa:KB] } else { @@ -2794,6 +2823,10 @@ class LLObjectMute : public view_listener_t LLVOAvatar* avatar = find_avatar_from_object(object); if (avatar) { +// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) | Added: RLVa-1.0.0e + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) + return true; +// [/RLVa:KB] id = avatar->getID(); LLNameValue *firstname = avatar->getNVPair("FirstName"); @@ -3067,6 +3100,14 @@ void handle_avatar_eject(const LLSD& avatar_id) LLSD payload; payload["avatar_id"] = avatar->getID(); std::string fullname = avatar->getFullname(); +// [RLVa:KB] - Version: 1.23.4 | Checked: 2009-07-08 (RLVa-1.0.0e) +/* + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (!fullname.empty()) ) + { + fullname = RlvStrings::getAnonym(fullname); + } +*/ +// [/RLVa:KB] const LLVector3d& pos = avatar->getPositionGlobal(); LLParcel* parcel = LLViewerParcelMgr::getInstance()->selectParcelAt(pos)->getParcel(); @@ -3154,7 +3195,10 @@ class LLAvatarGiveCard : public view_listener_t { llinfos << "handle_give_card()" << llendl; LLViewerObject* dest = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if(dest && dest->isAvatar()) +// if(dest && dest->isAvatar()) +// [RLVa:KB] - Checked: 2010-06-04 (RLVa-1.2.0d) | Modified: RLVa-1.2.0d + if ( (dest && dest->isAvatar()) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) ) +// [/RLVa:KB] { bool found_name = false; LLSD args; @@ -3383,7 +3427,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 @@ -3397,7 +3444,10 @@ class LLSelfSitDown : public view_listener_t bool enable_sitdown_self() { - return isAgentAvatarValid() && !gAgentAvatarp->isSitting() && !gAgent.getFlying(); +// [RLVa:KB] - Checked: 2010-08-28 (RLVa-1.2.1a) | Added: RLVa-1.2.1a + return isAgentAvatarValid() && !gAgentAvatarp->isSitting() && !gAgent.getFlying() && !gRlvHandler.hasBehaviour(RLV_BHVR_SIT); +// [/RLVa:KB] +// return isAgentAvatarValid() && !gAgentAvatarp->isSitting() && !gAgent.getFlying(); } // Used from the login screen to aid in UI work on side tray @@ -3612,7 +3662,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: 2010-04-20 (RLVa-1.2.0f) | Modified: RLVa-1.2.0f + bool new_value = avatar && !LLAvatarActions::isFriend(avatar->getID()) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)); +// [/RLVa:KB] return new_value; } }; @@ -3650,7 +3703,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()) || (gRlvHandler.canStand())); +// [/RLVa:KB] return new_value; } }; @@ -3665,6 +3721,16 @@ class LLEnableEditShape : 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.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(); + if ( (pick.mObjectID.notNull()) && (!gRlvHandler.canSit(pick.getObject(), pick.mObjectOffset)) ) + return false; + } +// [/RLVa:KB] + LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); if (object && object->getPCode() == LL_PCODE_VOLUME) @@ -3696,8 +3762,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()) || (gRlvHandler.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); @@ -3727,6 +3808,13 @@ class LLLandSit : public view_listener_t { bool handleEvent(const LLSD& userdata) { +// [RLVa:KB] - Checked: 2010-03-31 (RLVa-1.2.0c) | Modified: RLVa-1.2.0c + if ( (rlv_handler_t::isEnabled()) && ((gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SIT))) ) + { + return true; + } +// [/RLVa:KB] + gAgent.standUp(); LLViewerParcelMgr::getInstance()->deselectLand(); @@ -4173,6 +4261,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()) && (!gRlvHandler.canStand()) ) + { + // Allow only if the avie isn't sitting on any of the selected objects + LLObjectSelectionHandle hSel = LLSelectMgr::getInstance()->getSelection(); + RlvSelectIsSittingOn f(gAgentAvatarp->getRoot()); + if ( (hSel.notNull()) && (hSel->getFirstRootNode(&f, TRUE)) ) + return; + } +// [/RLVa:KB] + const LLUUID category_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OBJECT); derez_objects(DRD_ACQUIRE_TO_AGENT_INVENTORY, category_id); } @@ -4183,6 +4282,9 @@ 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.2.0e) | Modified: RLVa-1.0.0b + if ( (rlv_handler_t::isEnabled()) && (!rlvCanDeleteOrReturn()) ) return true; +// [/RLVa:KB] mObjectSelection = LLSelectMgr::getInstance()->getEditSelection(); @@ -4250,6 +4352,9 @@ class LLObjectEnableReturn : public view_listener_t } } #endif +// [RLVa:KB] - Checked: 2010-03-24 (RLVa-1.2.0e) | Modified: RLVa-1.0.0b + new_value &= (!rlv_handler_t::isEnabled()) || (rlvCanDeleteOrReturn()); +// [/RLVa:KB] return new_value; } }; @@ -4265,11 +4370,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; @@ -4382,7 +4490,10 @@ bool confirm_take(const LLSD& notification, const LLSD& response) // 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; } @@ -4882,6 +4993,17 @@ class LLToolsEnableUnlink : public view_listener_t bool new_value = LLSelectMgr::getInstance()->selectGetAllRootsValid() && first_editable_object && !first_editable_object->isAttachment(); +// [RLVa:KB] - Checked: 2010-04-01 (RLVa-1.2.0c) | Modified: RLVa-0.2.0g + if ( (new_value) && (gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) && + (isAgentAvatarValid()) && (gAgentAvatarp->isSitting()) ) + { + // Allow only if the avie isn't sitting on any of the selected objects + LLObjectSelectionHandle handleSel = LLSelectMgr::getInstance()->getSelection(); + RlvSelectIsSittingOn f(gAgentAvatarp->getRoot()); + if (handleSel->getFirstRootNode(&f, TRUE)) + new_value = false; + } +// [/RLVa:KB] return new_value; } }; @@ -4890,6 +5012,17 @@ class LLToolsUnlink : public view_listener_t { bool handleEvent(const LLSD& userdata) { +// [RLVa:KB] - Checked: 2010-03-07 (RLVa-1.2.0c) | Modified: RLVa-0.2.0g + if ( (rlv_handler_t::isEnabled()) && (!gRlvHandler.canStand()) ) + { + // Allow only if the avie isn't sitting on any of the selected objects + LLObjectSelectionHandle hSel = LLSelectMgr::getInstance()->getSelection(); + RlvSelectIsSittingOn f(gAgentAvatarp->getRoot()); + if ( (hSel.notNull()) && (hSel->getFirstRootNode(&f, TRUE)) ) + return true; + } +// [/RLVa:KB] + LLSelectMgr::getInstance()->sendDelink(); return true; } @@ -4909,8 +5042,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; } }; @@ -4919,7 +5056,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(); } }; @@ -5195,6 +5336,16 @@ void show_debug_menus() gMenuBarView->setItemVisible("Advanced", debug); // gMenuBarView->setItemEnabled("Advanced", debug); // Don't disable Advanced keyboard shortcuts when hidden + +// [RLVa:KB] - Checked: 2010-03-09 (RLVa-1.2.0a) | Added: RLVa-1.2.0a + // NOTE: this is supposed to execute whether RLVa is enabled or not + LLMenuGL* pAdvancedMenu = gMenuBarView->findChildMenuByName("Advanced", FALSE); + if (pAdvancedMenu) + { + pAdvancedMenu->setItemVisible("RLVa", rlv_handler_t::isEnabled()); + pAdvancedMenu->setItemEnabled("RLVa", rlv_handler_t::isEnabled()); + } +// [/RLVa:KB] gMenuBarView->setItemVisible("Debug", qamode); gMenuBarView->setItemEnabled("Debug", qamode); @@ -5442,7 +5593,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: 2010-06-04 (RLVa-1.2.0d) | Added: RLVa-1.2.0d + if ( (avatar) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) ) +// [/RLVa:KB] { LLAvatarActions::inviteToGroup(avatar->getID()); } @@ -5455,7 +5609,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: 2010-04-20 (RLVa-1.2.0f) | Modified: RLVa-1.2.0f + if ( (avatar && !LLAvatarActions::isFriend(avatar->getID())) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) ) +// [/RLVa:KB] { request_friendship(avatar->getID()); } @@ -5468,7 +5625,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: 2010-04-20 (RLVa-1.2.0f) | Modified: RLVa-1.2.0f + if ( (avatar) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) ) +// [/RLVa:KB] { create_inventory_callingcard(avatar->getID()); } @@ -5532,7 +5692,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: 2010-08-25 (RLVa-1.2.1b) | Added: RLVa-1.2.1b + return (avatar != NULL) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)); +// [/RLVa:KB] } bool enable_pay_object() @@ -5552,7 +5715,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()) || (gRlvHandler.canStand()) ); +// [/RLVa:KB] } bool enable_object_sit(LLUICtrl* ctrl) @@ -5577,6 +5743,17 @@ bool enable_object_sit(LLUICtrl* ctrl) gMenuHolder->childSetText(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.0.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 = !gRlvHandler.canSit(pick.getObject(), pick.mObjectOffset); + } +// [/RLVa:KB] + return !sitting_on_sel && is_object_sittable(); } @@ -5791,7 +5968,10 @@ class LLShowAgentProfile : public view_listener_t } LLVOAvatar* avatar = find_avatar_from_object(agent_id); - if (avatar) +// if (avatar) +// [RLVa:KB] - Checked: 2010-06-04 (RLVa-1.2.0d) | Modified: RLVa-1.2.0d + if ( (avatar) && ((!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) || (gAgent.getID() == agent_id)) ) +// [/RLVa:KB] { LLAvatarActions::showProfile(avatar->getID()); } @@ -5875,6 +6055,19 @@ private: LLViewerJointAttachment* attachment_point = NULL; if (index > 0) attachment_point = get_if_there(gAgentAvatarp->mAttachmentPoints, index, (LLViewerJointAttachment*)NULL); + +// [RLVa:KB] - Checked: 2010-03-16 (RLVa-1.2.0e) | Modified: RLVa-1.2.0a + // RELEASE-RLVa: [SL-2.1.2] This will need revisiting when LL deprecates the "MultipleAttachment" debug setting + if ( (rlv_handler_t::isEnabled()) && + ( ((index == 0) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY))) || // Can't wear on default attach point + ((index > 0) && (RLV_WEAR_LOCKED == gRlvAttachmentLocks.canAttach(attachment_point))) || // or replace a locked attachment + (gRlvHandler.hasBehaviour(RLV_BHVR_REZ)) ) ) // Attach on rezzed object == "Take" + { + setObjectSelection(NULL); // Clear the selection or it'll get stuck + return true; + } +// [/RLVa:KB] + confirmReplaceAttachment(0, attachment_point); } return true; @@ -6019,6 +6212,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)) ) + return true; + } + if (gRlvHandler.hasBehaviour(RLV_BHVR_REZ)) + { + return true; + } + } +// [/RLVa:KB] + LLSD payload; LLViewerObject *object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); @@ -6043,7 +6254,10 @@ class LLAttachmentDetachFromPoint : public view_listener_t bool handleEvent(const LLSD& user_data) { 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] { gMessageSystem->newMessage("ObjectDetach"); gMessageSystem->nextBlockFast(_PREHASH_AgentData); @@ -6055,6 +6269,10 @@ class LLAttachmentDetachFromPoint : public view_listener_t iter++) { LLViewerObject *attached_object = (*iter); +// [RLVa:KB] - Checked: 2010-03-04 (RLVa-1.2.0a) | Added: RLVa-1.2.0a + if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.isLockedAttachment(attached_object)) ) + continue; +// [/RLVa:KB] gMessageSystem->nextBlockFast(_PREHASH_ObjectData); gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, attached_object->getLocalID()); } @@ -6066,6 +6284,11 @@ class LLAttachmentDetachFromPoint : public view_listener_t static bool onEnableAttachmentLabel(LLUICtrl* ctrl, const LLSD& data) { +// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0a) | Added: RLVa-1.2.0a + // RELEASE-RLVa: [2010-02-27] This will need rewriting once multiple attachments can be attached to the same point + bool fRlvEnable = true; + bool fRlvHasLockedAttachment = false; // Remove once multiple attachments can be attached to the same point +// [/RLVa:KB] std::string label; LLMenuItemGL* menu = dynamic_cast<LLMenuItemGL*>(ctrl); if (menu) @@ -6081,6 +6304,12 @@ static bool onEnableAttachmentLabel(LLUICtrl* ctrl, const LLSD& data) const LLViewerObject* attached_object = (*attachment_iter); if (attached_object) { +// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0a) | Added: RLVa-1.2.0a + // RELEASE-RLVa: [SL-2.0.0] This will need removing for "ENABLE_MULTIATTACHMENTS" + if (rlv_handler_t::isEnabled()) + fRlvHasLockedAttachment |= gRlvAttachmentLocks.isLockedAttachment(attached_object); +// [/RLVa:KB] + LLViewerInventoryItem* itemp = gInventory.getItem(attached_object->getAttachmentItemID()); if (itemp) { @@ -6090,9 +6319,19 @@ static bool onEnableAttachmentLabel(LLUICtrl* ctrl, const LLSD& data) } } } + +// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0a) | Added: RLVa-1.2.0a + // Remove fHasLockedAttachment once multiple attachments can be attached to the same point + if (rlv_handler_t::isEnabled()) + fRlvEnable = (!fRlvHasLockedAttachment) && (!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 @@ -6131,6 +6370,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)) ) + return true; + } +// [/RLVa:KB] + // The sendDetach() method works on the list of selected // objects. Thus we need to clear the list, make sure it only // contains the object the user clicked, send the message, @@ -6216,7 +6466,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; } @@ -6241,6 +6494,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.0.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)) ) + return FALSE; + } +// [/RLVa:KB] return TRUE; } @@ -6260,8 +6527,32 @@ 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-03-16 (RLVa-1.2.0e) | Modified: RLVa-1.2.0a + if (rlv_handler_t::isEnabled()) + { + if (!isAgentAvatarValid()) + return FALSE; + + // RELEASE-RLVa: [SL-2.1.1] 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] + // RELEASE-RLVa: [SL-2.1.2] This will need revisiting when LL deprecates the "MultipleAttachment" debug setting + 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_LOCKED == gRlvAttachmentLocks.canAttach(pAttachPt))) || // or replace a locked attachment + (gRlvHandler.hasBehaviour(RLV_BHVR_REZ)) ) // Attach on rezzed object == "Take" + { + return FALSE; + } + } +// [/RLVa:KB] + LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); for (LLObjectSelection::root_iterator iter = selection->root_begin(); iter != selection->root_end(); iter++) @@ -6289,9 +6580,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; } @@ -6311,7 +6605,8 @@ BOOL object_is_wearable() } return FALSE; } - +*/ +// [/RLVa:KB] class LLAttachmentPointFilled : public view_listener_t { @@ -6321,7 +6616,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; } @@ -6332,7 +6632,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: 2010-06-04 (RLVa-1.2.0d) | Added: RLVa-1.2.0d + if ( (avatar) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) ) +// [/RLVa:KB] { LLAvatarActions::startIM(avatar->getID()); } @@ -6345,7 +6648,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: 2010-06-04 (RLVa-1.2.0d) | Added: RLVa-1.2.0d + if ( (avatar) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) ) +// [/RLVa:KB] { LLAvatarActions::startCall(avatar->getID()); } @@ -6353,6 +6659,13 @@ class LLAvatarCall : public view_listener_t } }; +// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) | Added: RLVa-1.2.1b +bool enable_avatar_call() +{ + return (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (LLAvatarActions::canCall()); +} +// [/RLVa:KB] + namespace { struct QueueObjects : public LLSelectedObjectFunctor @@ -6415,6 +6728,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)) ) + return true; + } +// [/RLVa:KB] + std::string action = userdata.asString(); bool mono = false; std::string msg, name; @@ -6515,12 +6839,30 @@ void handle_selected_texture_info(void*) 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 ); } @@ -6722,7 +7064,12 @@ 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; @@ -6876,6 +7223,9 @@ 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-04-07 (RLVa-1.2.0d) | Added: RLVa-1.1.0j + enable_teleport_home &= !gRlvHandler.hasBehaviour(RLV_BHVR_TPLM); +// [/RLVa:KB] return enable_teleport_home; } }; @@ -7337,6 +7687,11 @@ class LLViewHighlightTransparent : public view_listener_t { bool handleEvent(const LLSD& userdata) { +// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Modified: RLVa-1.0.0b + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_EDIT)) && (!LLDrawPoolAlpha::sShowDebugAlpha)) + return true; +// [/RLVa:KB] + LLDrawPoolAlpha::sShowDebugAlpha = !LLDrawPoolAlpha::sShowDebugAlpha; return true; } @@ -7523,6 +7878,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; } @@ -7543,8 +7903,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; } }; @@ -7565,6 +7932,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 LLWearable* pWearable = gAgentWearables.getWearable(type, wearable_index); + if (!gRlvWearableLocks.isLockedWearable(pWearable)) + break; + } + if (wearable_index < 0) + return true; // No wearable found that can be removed + } +// [/RLVa:KB] + LLViewerInventoryItem *item = dynamic_cast<LLViewerInventoryItem*>(gAgentWearables.getWearableInventoryItem(type,wearable_index)); LLWearableBridge::removeItemFromAvatar(item); } @@ -7618,6 +8001,12 @@ class LLWorldEnvSettings : public view_listener_t return true; } +// [RLVa:KB] - Checked: 2010-03-18 (RLVa-1.2.0a) | Modified: RLVa-1.0.0g + if (gRlvHandler.hasBehaviour(RLV_BHVR_SETENV)) + { + return true; + } else +// [/RLVa:KB] if (tod == "sunrise") { // set the value, turn off animation @@ -8137,7 +8526,10 @@ void initialize_menus() commit.add("Avatar.Eject", boost::bind(&handle_avatar_eject, LLSD())); 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 LLAvatarEnableAddFriend(), "Avatar.EnableAddFriend"); @@ -8165,7 +8557,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)); @@ -8220,4 +8615,12 @@ void initialize_menus() view_listener_t::addMenu(new LLEditableSelected(), "EditableSelected"); view_listener_t::addMenu(new LLEditableSelectedMono(), "EditableSelectedMono"); +// [RLVa:KB] - Checked: 2010-04-23 (RLVa-1.2.0g) | Added: RLVa-1.2.0 + commit.add("RLV.ToggleEnabled", boost::bind(&rlvMenuToggleEnabled)); + enable.add("RLV.CheckEnabled", boost::bind(&rlvMenuCheckEnabled)); + if (rlv_handler_t::isEnabled()) + { + enable.add("RLV.EnableIfNot", boost::bind(&rlvMenuEnableIfNot, _2)); + } +// [/RLVa:KB] } diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 82bc084f6820f144c54fe4284062497ae1c99fd3..4c34792dc6f1964e24ddfbb0c762233da06fc998 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -99,6 +99,11 @@ #include "llagentui.h" #include "llpanelblockedlist.h" #include "llpanelplaceprofile.h" +// [RLVa:KB] - Checked: 2010-03-09 (RLVa-1.2.0a) +#include "rlvhandler.h" +#include "rlvinventory.h" +#include "rlvui.h" +// [/RLVa:KB] #include <boost/algorithm/string/split.hpp> // #include <boost/regex.hpp> @@ -1376,7 +1381,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: 2010-04-20 (RLVa-1.2.0f) | Added: RLVa-1.2.0f + // RELEASE-RLVa: [RLVa-1.2.0] Make sure this stays in sync with the condition in inventory_offer_handler() + if ((!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) || (!RlvUtil::isNearbyAgent(mFromID)) || (RlvUIEnabler::hasOpenIM(mFromID))) + { + LLRecentPeople::instance().add(mFromID); + } +// [/RLVa:KB] } } @@ -1447,6 +1459,21 @@ 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.0e) | Modified: RLVa-1.2.0e +#ifdef RLV_EXTENSION_GIVETORLV_A2A + if ( (rlv_handler_t::isEnabled()) && (!RlvSettings::getForbidGiveToRLV()) && (LLAssetType::AT_CATEGORY == mType) && + (RlvInventory::instance().getSharedRoot()) && (mDesc.find(RLV_PUTINV_PREFIX) == 0) ) + { + RlvGiveToRLVAgentOffer* pOfferObserver = new RlvGiveToRLVAgentOffer(mObjectID); + pOfferObserver->startFetch(); + if (pOfferObserver->isFinished()) + pOfferObserver->done(); + else + gInventory.addObserver(pOfferObserver); + } +#endif // RLV_EXTENSION_GIVETORLV_A2A +// [/RLVa:KB] + LLOpenAgentOffer* open_agent_offer = new LLOpenAgentOffer(mObjectID, from_string); open_agent_offer->startFetch(); if(catp || (itemp && itemp->isFinished())) @@ -1611,12 +1638,27 @@ bool LLOfferInfo::inventory_task_offer_callback(const LLSD& notification, const } else { - std::string first_name, last_name; - if (gCacheName->getName(mFromID, first_name, last_name)) +// std::string first_name, last_name; +// if (gCacheName->getName(mFromID, first_name, last_name)) +// [RLVa:KB] - Checked: 2010-04-022 (RLVa-1.2.0f) | Modified: RLVa-1.2.0f + std::string strFullName; + if (gCacheName->getFullName(mFromID, strFullName)) +// [/RLVa:KB] { +// [RLVa:KB] - Checked: 2010-04-022 (RLVa-1.2.0f) | Modified: RLVa-1.2.0f + // RELEASE-RLVa: [RLVa-1.2.0] Make sure this stays in sync with the condition in inventory_offer_handler() + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (RlvUtil::isNearbyAgent(mFromID)) && + (!RlvUIEnabler::hasOpenIM(mFromID)) ) + { + strFullName = RlvStrings::getAnonym(strFullName); + } from_string = LLTrans::getString("InvOfferAnObjectNamed") + " "+ LLTrans::getString("'") + mFromName - + LLTrans::getString("'")+" " + LLTrans::getString("InvOfferOwnedBy") + first_name + " " + last_name; - chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedBy") + " " + first_name + " " + last_name; + + LLTrans::getString("'")+" " + LLTrans::getString("InvOfferOwnedBy") + strFullName; + chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedBy") + " " + strFullName; +// [/RLVa:KB] +// from_string = LLTrans::getString("InvOfferAnObjectNamed") + " "+ LLTrans::getString("'") + mFromName +// + LLTrans::getString("'")+" " + LLTrans::getString("InvOfferOwnedBy") + first_name + " " + last_name; +// chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedBy") + " " + first_name + " " + last_name; } else { @@ -1639,6 +1681,26 @@ bool LLOfferInfo::inventory_task_offer_callback(const LLSD& notification, const // 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-04-18 (RLVa-1.2.0e) | Modified: RLVa-1.2.0e + // Only change the inventory offer's destination folder to the shared root if: + // - the user has enabled the feature + // - the inventory offer came from a script (and specifies a folder) + // - the name starts with the prefix - mDesc format: '[OBJECTNAME]' ( http://slurl.com/... ) + if ( (rlv_handler_t::isEnabled()) && (!RlvSettings::getForbidGiveToRLV()) && + (IM_TASK_INVENTORY_OFFERED == mIM) && (LLAssetType::AT_CATEGORY == mType) && (mDesc.find(RLV_PUTINV_PREFIX) == 1) ) + { + const LLViewerInventoryCategory* pRlvRoot = RlvInventory::instance().getSharedRoot(); + if (pRlvRoot) + { + mFolderID = pRlvRoot->getUUID(); + + RlvGiveToRLVTaskOffer* pOfferObserver = new RlvGiveToRLVTaskOffer(mTransactionID); + gInventory.addObserver(pOfferObserver); + } + } +// [/RLVa:KB] + // Generates IM_INVENTORY_ACCEPTED, IM_TASK_INVENTORY_ACCEPTED, // or IM_GROUP_NOTICE_INVENTORY_ACCEPTED msg->addU8Fast(_PREHASH_Dialog, (U8)(mIM + 1)); @@ -1829,6 +1891,15 @@ void inventory_offer_handler(LLOfferInfo* info) // Object -> Agent Inventory Offer if (info->mFromObject) { +// [RLVa:KB] - Checked: 2010-04-20 (RLVa-1.2.0f) | Added: RLVa-1.2.0f + // Only filter if the object owner is a nearby agent + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (RlvUtil::isNearbyAgent(info->mFromID)) ) + { + payload["rlv_shownames"] = TRUE; + args["NAME"] = args["NAME_SLURL"] = RlvStrings::getAnonym(info->mFromName); + } +// [/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 @@ -1840,6 +1911,16 @@ void inventory_offer_handler(LLOfferInfo* info) } else // Agent -> Agent Inventory Offer { +// [RLVa:KB] - Checked: 2010-04-20 (RLVa-1.2.0f) | Added: RLVa-1.2.0f + // 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) + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (RlvUtil::isNearbyAgent(info->mFromID)) && + (!RlvUIEnabler::hasOpenIM(info->mFromID)) ) + { + payload["rlv_shownames"] = TRUE; + args["NAME"] = args["NAME_SLURL"] = RlvStrings::getAnonym(info->mFromName); + } +// [/RLVa:KB] + p.responder = info; // Note: sets inventory_offer_callback as the callback // *TODO fix memory leak @@ -2109,7 +2190,18 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) // do nothing -- don't distract newbies in // Prelude with global IMs } - else if (offline == IM_ONLINE && !is_linden && is_busy && name != SYSTEM_FROM) +// [RLVa:KB] - Checked: 2010-03-27 (RLVa-1.2.0b) | Modified: RLVa-1.2.0b + else if ( (rlv_handler_t::isEnabled()) && (offline == IM_ONLINE) && ("@version" == message) ) + { + // TODO-RLVa: [RLVa-1.2.1] Should we send our version string if the other party is muted? + RlvUtil::sendBusyMessage(from_id, RlvStrings::getVersion(), session_id); + } +// [/RLVa:KB] +// else if (offline == IM_ONLINE && !is_linden && is_busy && name != SYSTEM_FROM) +// [RLVa:KB] - Checked: 2010-03-23 (RLVa-1.2.0a) | Modified: RLVa-1.0.0g + else if ( (offline == IM_ONLINE && !is_linden && is_busy && name != SYSTEM_FROM) && + ( (!gRlvHandler.hasBehaviour(RLV_BHVR_RECVIM)) || (gRlvHandler.isException(RLV_BHVR_RECVIM, from_id))) ) +// [/RLVa:KB] { // return a standard "busy" message, but only do it to online IM // (i.e. not other auto responses and not store-and-forward IM) @@ -2180,6 +2272,23 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) else { // standard message, not from system + bool mute_im = is_muted; + if(accept_im_from_only_friend&&!is_friend) + { + mute_im = true; + } + +// [RLVa:KB] - Checked: 2010-03-23 (RLVa-1.2.0e) | Modified: RLVa-1.2.0a + // Don't block offline IMs, or IMs from Lindens + if ( (rlv_handler_t::isEnabled()) && (offline != IM_OFFLINE) && (!is_linden) && + (gRlvHandler.hasBehaviour(RLV_BHVR_RECVIM)) && (!gRlvHandler.isException(RLV_BHVR_RECVIM, from_id)) ) + { + if (!mute_im) + RlvUtil::sendBusyMessage(from_id, RlvStrings::getString(RLV_STRING_BLOCKED_RECVIM_REMOTE), session_id); + message = RlvStrings::getString(RLV_STRING_BLOCKED_RECVIM); + } +// [/RLVa:KB] + std::string saved; if(offline == IM_OFFLINE) { @@ -2191,11 +2300,13 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) LL_INFOS("Messaging") << "process_improved_im: session_id( " << session_id << " ), from_id( " << from_id << " )" << LL_ENDL; +/* bool mute_im = is_muted; if(accept_im_from_only_friend&&!is_friend) { mute_im = true; } +*/ if (!mute_im || is_linden) { gIMMgr->addMessage( @@ -2412,6 +2523,15 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) bucketp = (struct offer_agent_bucket_t*) &binary_bucket[0]; info->mType = (LLAssetType::EType) bucketp->asset_type; info->mObjectID = bucketp->object_id; + +// [RLVa:KB] - Checked: 2009-07-08 (RLVa-1.0.0e) +/* + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (gRlvHandler.isAgentNearby(from_id)) ) + { + name = RlvStrings::getAnonym(name); + } +*/ +// [/RLVa:KB] } else { @@ -2462,7 +2582,13 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) case IM_INVENTORY_ACCEPTED: { - args["NAME"] = name; +// args["NAME"] = name; +// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Modified: RLVa-1.2.0f + // Only filter the name if the agent is nearby, there isn't an open IM session to them and their profile isn't open + bool fRlvFilterName = (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (RlvUtil::isNearbyAgent(from_id)) && + (!RlvUIEnabler::hasOpenProfile(from_id)) && (!RlvUIEnabler::hasOpenIM(from_id)); + args["NAME"] = (!fRlvFilterName) ? name : RlvStrings::getAnonym(name); +// [/RLVa:KB] LLSD payload; payload["from_id"] = from_id; LLNotificationsUtil::add("InventoryAccepted", args, payload); @@ -2470,7 +2596,13 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) } case IM_INVENTORY_DECLINED: { - args["NAME"] = name; +// args["NAME"] = name; +// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Modified: RLVa-1.2.0f + // Only filter the name if the agent is nearby, there isn't an open IM session to them and their profile isn't open + bool fRlvFilterName = (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (RlvUtil::isNearbyAgent(from_id)) && + (!RlvUIEnabler::hasOpenProfile(from_id)) && (!RlvUIEnabler::hasOpenIM(from_id)); + args["NAME"] = (!fRlvFilterName) ? name : RlvStrings::getAnonym(name); +// [/RLVa:KB] LLSD payload; payload["from_id"] = from_id; LLNotificationsUtil::add("InventoryDeclined", args, payload); @@ -2498,10 +2630,37 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) // Only show messages if we have a session open (which // should happen after you get an "invitation" +/* if ( !gIMMgr->hasSession(session_id) ) { return; } +*/ +// [RLVa:KB] - Checked: 2010-03-23 (RLVa-1.2.0e) | Modified: RLVa-1.2.0a + LLIMModel::LLIMSession* pIMSession = LLIMModel::instance().findIMSession(session_id); + if (!pIMSession) + { + return; + } + + if (gRlvHandler.hasBehaviour(RLV_BHVR_RECVIM)) + { + switch (pIMSession->mSessionType) + { + case LLIMModel::LLIMSession::GROUP_SESSION: // Group chat: allow if group is a sendim exception + if ( (from_id != gAgent.getID()) && (!gRlvHandler.isException(RLV_BHVR_RECVIM, session_id)) ) + return; + break; + case LLIMModel::LLIMSession::ADHOC_SESSION: // Conference chat: allow if the sender is a sendim exception + if ( (from_id != gAgent.getID()) && (!gRlvHandler.isException(RLV_BHVR_RECVIM, from_id)) ) + message = RlvStrings::getString(RLV_STRING_BLOCKED_RECVIM); + break; + default: + RLV_ASSERT(false); + return; + } + } +// [/RLVa:KB] // standard message, not from system std::string saved; @@ -2564,6 +2723,30 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) LLSD query_string; query_string["owner"] = from_id; +// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Added: RLVa-1.2.0f + if (rlv_handler_t::isEnabled()) + { + // NOTE: the chat message itself will be filtered in LLNearbyChatHandler::processChat() + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (!from_group) && (RlvUtil::isNearbyAgent(from_id)) ) + { + std::string strOwnerName; + if (gCacheName->getFullName(from_id, strOwnerName)) + { + query_string["owner"] = LLUUID::null; + query_string["owner_name"] = RlvStrings::getAnonym(strOwnerName); + } + + RlvUtil::filterNames(name); + chat.mFromName = name; + } + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) + { + 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) @@ -2664,6 +2847,26 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) region_access_icn = LLViewerRegion::getAccessIcon(region_access); } +// [RLVa:KB] - Checked: 2010-04-01 (RLVa-1.2.0c) | Modified: RLVa-1.0.0d + if (rlv_handler_t::isEnabled()) + { + // Block if: 1) @tplure=n restricted (and sender isn't an exception), or 2) @unsit=n restricted and currently sitting + if ( ( (gRlvHandler.hasBehaviour(RLV_BHVR_TPLURE)) && (!gRlvHandler.isException(RLV_BHVR_TPLURE, from_id)) ) || + ( (gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) && (isAgentAvatarValid()) && (gAgentAvatarp->isSitting()) ) ) + { + RlvUtil::sendBusyMessage(from_id, RlvStrings::getString(RLV_STRING_BLOCKED_TPLURE_REMOTE)); + return; + } + + // Censor lure message if: 1) @revcim=n restricted (and sender isn't an exception), or 2) @showloc=n restricted + if ( ( (gRlvHandler.hasBehaviour(RLV_BHVR_RECVIM)) && (!gRlvHandler.isException(RLV_BHVR_RECVIM, from_id)) ) || + (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) ) + { + message = RlvStrings::getString(RLV_STRING_HIDDEN); + } + } +// [/RLVa:KB] + LLSD args; // *TODO: Translate -> [FIRST] [LAST] (maybe) args["NAME_SLURL"] = LLSLURL("agent", from_id, "about").getSLURLString(); @@ -2675,10 +2878,23 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) payload["lure_id"] = session_id; payload["godlike"] = FALSE; - LLNotification::Params params("TeleportOffered"); - params.substitutions = args; - params.payload = payload; - LLPostponedNotification::add<LLPostponedOfferNotification>( params, from_id, false); + LLNotification::Params params("TeleportOffered"); + params.substitutions = args; + params.payload = payload; + +// [RLVa:KB] - Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-0.2.0b + if ( (rlv_handler_t::isEnabled()) && + ((gRlvHandler.hasBehaviour(RLV_BHVR_ACCEPTTP)) || (gRlvHandler.isException(RLV_BHVR_ACCEPTTP, from_id))) ) + { + gRlvHandler.setCanCancelTp(false); + LLNotifications::instance().forceResponse(LLNotification::Params("TeleportOffered").payload(payload), 0); + } + else + { + LLPostponedNotification::add<LLPostponedOfferNotification>( params, from_id, false); + } +// [/RLVa:KB] +// LLPostponedNotification::add<LLPostponedOfferNotification>( params, from_id, false); } } break; @@ -2963,8 +3179,13 @@ 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) +// if (chat.mSourceType == CHAT_SOURCE_OBJECT +// && chat.mChatType != CHAT_TYPE_DEBUG_MSG) +// [RLVa:KB] - Checked: 2010-03-09 (RLVa-1.2.0b) | Modified: RLVa-1.0.0g + // Don't show swirly things for llOwnerSay() chat here because we handle those further down + if ( ((chat.mSourceType == CHAT_SOURCE_OBJECT) && (chat.mChatType != CHAT_TYPE_DEBUG_MSG)) && + ((!rlv_handler_t::isEnabled()) || (CHAT_TYPE_OWNER != chat.mChatType)) ) +// [/RLVa:KB] { LLPointer<LLViewerPartSourceChat> psc = new LLViewerPartSourceChat(chatter->getPositionAgent()); psc->setSourceObject(chatter); @@ -2997,6 +3218,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; + + // 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 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) ) ) + { + if (!RlvUtil::isEmote(mesg)) + { + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_RECVCHAT)) && (!gRlvHandler.isException(RLV_BHVR_RECVCHAT, from_id)) ) + gRlvHandler.filterChat(mesg, false); + } + else if ( (gRlvHandler.hasBehaviour(RLV_BHVR_RECVEMOTE)) && (!gRlvHandler.isException(RLV_BHVR_RECVEMOTE, from_id)) ) + { + mesg = "/me ..."; + } + } + + // Filtering "rules": + // avatar => filter only their name (unless it's this avie) + // other => filter everything except attachments this avie owns but then we still do filter their text + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && + ((CHAT_SOURCE_AGENT != chat.mSourceType) || (chat.mFromID != gAgent.getID())) ) + { + if (CHAT_SOURCE_AGENT == chat.mSourceType) + { + chat.mFromName = RlvStrings::getAnonym(from_name); + chat.mRlvNamesFiltered = TRUE; + } + else if ( (!is_owned_by_me) || (!is_attachment) ) + { + RlvUtil::filterNames(chat.mFromName); + } + } + + // 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) && + ((gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC))) ) + { + LLSD sdQuery; std::string strOwnerName, strQuery; + sdQuery["name"] = chat.mFromName; + + sdQuery["owner"] = owner_id; + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && + (!is_owned_by_me) && (gCacheName->getFullName(owner_id, strOwnerName)) ) + { + sdQuery["owner"] = LLUUID::null; + sdQuery["owner_name"] = RlvStrings::getAnonym(strOwnerName); + } + + const LLViewerRegion* pRegion = LLWorld::getInstance()->getRegionFromPosAgent(chat.mPosAgent); + if (pRegion) + { + sdQuery["slurl"] = LLSLURL(pRegion->getName(), LLVector3d(chat.mPosAgent)).getSLURLString(); + } + + strQuery = LLURI::mapToQueryString(sdQuery); + chat.mURL = LLSLURL("objectim", from_id, strQuery).getSLURLString(); + } + } +// [/RLVa:KB] + BOOL ircstyle = FALSE; // Look for IRC-style emotes here so chatbubbles work @@ -3046,8 +3336,98 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) case CHAT_TYPE_WHISPER: verb = 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) ) + { + 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()) ) + { + verb = " executes: @"; + mesg = strExecuted; + } + else if ( (strExecuted.empty()) && (!strFailed.empty()) && (strRetained.empty()) ) + { + verb = " failed: @"; + mesg = strFailed; + } + else if ( (strExecuted.empty()) && (strFailed.empty()) && (!strRetained.empty()) ) + { + verb = " retained: @"; + mesg = strRetained; + } + else + { + verb = ": @"; + 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) ) + { + 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: verb = ""; break; @@ -3128,7 +3508,10 @@ void process_teleport_start(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); } @@ -3163,7 +3546,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); } @@ -5352,7 +5738,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); @@ -5360,7 +5746,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)"); @@ -5565,8 +5959,32 @@ void process_script_question(LLMessageSystem *msg, void **user_data) payload["object_name"] = object_name; payload["owner_name"] = owner_name; +// [RLVa:KB] - Checked: 2009-07-10 (RLVa-1.0.0g) | Modified: RLVa-0.2.0e + S32 rlvQuestionsOther = questions; + + if (gRlvHandler.hasBehaviour(RLV_BHVR_ACCEPTPERMISSION)) + { + const LLViewerObject* pObj = gObjectList.findObject(taskid); + if (pObj) + { +// if (pObj->permYouOwner()) +// { + // PERMISSION_TAKE_CONTROLS and PERMISSION_ATTACH are only auto-granted to objects this avie owns + rlvQuestionsOther &= ~(LSCRIPTRunTimePermissionBits[SCRIPT_PERMISSION_TAKE_CONTROLS] | + LSCRIPTRunTimePermissionBits[SCRIPT_PERMISSION_ATTACH]); +// } + } + } + + if ( (!caution) && (!rlvQuestionsOther) ) + { + LLNotifications::instance().forceResponse( + LLNotification::Params("ScriptQuestion").substitutions(args).payload(payload), 0/*YES*/); + } + else if (gSavedSettings.getBOOL("PermissionsCautionEnabled")) +// [/RLVa:KB] // check whether cautions are even enabled or not - if (gSavedSettings.getBOOL("PermissionsCautionEnabled")) +// if (gSavedSettings.getBOOL("PermissionsCautionEnabled")) { // display the caution permissions prompt LLNotificationsUtil::add(caution ? "ScriptQuestionCaution" : "ScriptQuestion", args, payload); @@ -5914,6 +6332,22 @@ bool handle_lure_callback(const LLSD& notification, const LLSD& response) if(0 == option) { +// [RLVa:KB] - Checked: 2010-04-09 (RLVa-1.2.0e) | Modified: RLVa-0.2.0b + if (gRlvHandler.hasBehaviour(RLV_BHVR_SENDIM)) + { + // Filter the teleport offer text unless everyone is a sendim exception + for (LLSD::array_const_iterator it = notification["payload"]["ids"].beginArray(); + it != notification["payload"]["ids"].endArray(); ++it) + { + if (!gRlvHandler.isException(RLV_BHVR_SENDIM, it->asUUID())) + { + text = RlvStrings::getString(RLV_STRING_HIDDEN); + break; + } + } + } +// [/RLVa:KB] + LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_StartLure); msg->nextBlockFast(_PREHASH_AgentData); @@ -5968,13 +6402,29 @@ 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 (LLDynamicArray<LLUUID>::const_iterator it = ids.begin(); it != ids.end(); ++it) { +// [RLVa:KB] - Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.0.0a + // 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(*it); + if ( (!gRlvHandler.isException(RLV_BHVR_TPLURE, *it, RLV_CHECK_PERMISSIVE)) && + ((!pBuddyInfo) || (!pBuddyInfo->isOnline()) || (!pBuddyInfo->isRightGrantedTo(LLRelationship::GRANT_MAP_LOCATION))) ) + { + return; + } + } +// [/RLVa:KB] payload["ids"].append(*it); } if (gAgent.isGodlike()) diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 25cc24da95c36f85c0dc0d15cd4d03d2b01e1971..b3194ecdc7b965e961377f23277f122464ecebdc 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -99,6 +99,9 @@ #include "lltrans.h" #include "llsdutil.h" #include "llmediaentry.h" +// [RLVa:KB] - Checked: 2010-03-27 (RLVa-1.2.0b) +#include "rlvhandler.h" +// [/RLVa:KB] //#define DEBUG_UPDATE_TYPE @@ -1093,6 +1096,12 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, coloru.mV[3] = 255 - coloru.mV[3]; mText->setColor(LLColor4(coloru)); mText->setStringUTF8(temp_string); +// [RLVa:KB] - Checked: 2010-03-27 (RLVa-1.2.0b) | Added: RLVa-1.0.0f + if (rlv_handler_t::isEnabled()) + { + mText->setObjectText(temp_string); + } +// [/RLVa:KB] if (mDrawable.notNull()) { @@ -1485,6 +1494,12 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, coloru.mV[3] = 255 - coloru.mV[3]; mText->setColor(LLColor4(coloru)); mText->setStringUTF8(temp_string); +// [RLVa:KB] - Checked: 2010-03-27 (RLVa-1.2.0b) | Added: RLVa-1.0.0f + if (rlv_handler_t::isEnabled()) + { + mText->setObjectText(temp_string); + } +// [/RLVa:KB] setChanged(TEXTURE); } @@ -1655,6 +1670,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()) @@ -4897,7 +4931,10 @@ BOOL LLViewerObject::permTransfer() const // given you modify rights to. JC BOOL LLViewerObject::allowOpen() const { - return !flagInventoryEmpty() && (permYouOwner() || permModify()); +// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Modified: RLVa-1.0.0b + return !flagInventoryEmpty() && (permYouOwner() || permModify()) && (!gRlvHandler.hasBehaviour(RLV_BHVR_EDIT)); +// [/RLVa:KB] +// return !flagInventoryEmpty() && (permYouOwner() || permModify()); } LLViewerObject::LLInventoryCallbackInfo::~LLInventoryCallbackInfo() diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index bcc2cb164f2804cf0ce7a83f798f39c4c7a64b25..b50785ca594485f8cac1a144ade4e3cdf6816990 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -328,7 +328,10 @@ public: 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/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 13db913f605255feff69c80d6d26e85d73311389..e0b08ebc1fd61c31c3e65287e659779b7a65c984 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -197,6 +197,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 @@ -3168,6 +3172,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(); @@ -3435,17 +3448,42 @@ LLViewerObject* LLViewerWindow::cursorIntersect(S32 mouse_x, S32 mouse_y, F32 de } else // check ALL objects - { + { found = gPipeline.lineSegmentIntersectInHUD(mouse_hud_start, mouse_hud_end, pick_transparent, face_hit, intersection, uv, normal, binormal); - if (!found) // if not found in HUD, look in world: +// [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(mouse_world_start, mouse_world_end, pick_transparent, face_hit, intersection, uv, normal, binormal); - } +// [RLVa:KB] - Checked: 2010-01-02 (RLVa-1.1.0l) | Added: RLVa-1.1.0l +#ifdef RLV_EXTENSION_CMD_INTERACT + if ( (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; + } + } +#endif // RLV_EXTENSION_CMD_INTERACT +// [/RLVa:KB] + } } return found; diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 8b9a511f9db2e0e68955bf9e6970c8c06eeb0e1d..53e85713380a70936b921c37f0ca743986f3029c 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -85,6 +85,9 @@ #include "llanimstatelabels.h" #include "lltrans.h" #include "llappearancemgr.h" +// [RLVa:KB] - Checked: 2010-04-01 (RLVa-1.2.0c) +#include "rlvhandler.h" +// [/RLVa:KB] #include "llgesturemgr.h" //needed to trigger the voice gesticulations #include "llvoiceclient.h" @@ -2757,12 +2760,18 @@ 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: 2010-04-04 (RLVa-1.2.0d) | Added: RLVa-0.2.0b + bool fRlvShowNames = gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES); +// [/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: 2010-04-04 (RLVa-1.2.0d) | Added: RLVa-1.0.0h + ( (!fRlvShowNames) || (RlvSettings::getShowNameTags()) ) && +// [/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()) @@ -2782,7 +2791,18 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) new_name = TRUE; } - if (sRenderGroupTitles != mRenderGroupTitles) +// [RLVa:KB] - Checked: 2010-04-04 (RLVa-1.2.0d) | Added: RLVa-0.2.0b + if (fRlvShowNames) + { + if (mRenderGroupTitles) + { + mRenderGroupTitles = FALSE; + new_name = TRUE; + } + } + else if (sRenderGroupTitles != mRenderGroupTitles) +// [/RLVa] +// if (sRenderGroupTitles != mRenderGroupTitles) { mRenderGroupTitles = sRenderGroupTitles; new_name = TRUE; @@ -2905,27 +2925,38 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) ) { std::string line; - if (!sRenderGroupTitles) +// [RLVa:KB] - Checked: 2010-04-04 (RLVa-1.2.0d) | Added: RLVa-0.2.0b + if (!fRlvShowNames) { - // If all group titles are turned off, stack first name - // on a line above last name - line += firstname->getString(); - line += "\n"; - } - else if (title && title->getString() && title->getString()[0] != '\0') - { - line += title->getString(); - LLStringFn::replace_ascii_controlchars(line,LL_UNKNOWN_CHAR); - line += "\n"; - line += firstname->getString(); +// [/RLVa:KB] + if (!sRenderGroupTitles) + { + // If all group titles are turned off, stack first name + // on a line above last name + line += firstname->getString(); + line += "\n"; + } + else if (title && title->getString() && title->getString()[0] != '\0') + { + line += title->getString(); + LLStringFn::replace_ascii_controlchars(line,LL_UNKNOWN_CHAR); + line += "\n"; + line += firstname->getString(); + } + else + { + line += firstname->getString(); + } + + line += " "; + line += lastname->getString(); +// [RLVa:KB] - Checked: 2010-04-04 (RLVa-1.2.0d) | Added: RLVa-0.2.0b } else { - line += firstname->getString(); + line = RlvStrings::getAnonym(line.assign(firstname->getString()).append(" ").append(lastname->getString())); } - - line += " "; - line += lastname->getString(); +// [/RLVa:KB] BOOL need_comma = FALSE; if (is_away || is_muted || is_busy) @@ -5727,6 +5758,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 1a5d7289f4d52bf35a897bb199527b1481e5d933..4adb65b2d957ef9d3cc7c54a0d6c2f74e851f4aa 100644 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -57,6 +57,9 @@ #include "llviewerstats.h" #include "llviewerregion.h" #include "llappearancemgr.h" +// [RLVa:KB] - Checked: 2010-03-05 (RLVa-1.2.0a) +#include "rlvhandler.h" +// [/RLVa:KB] #if LL_MSVC // disable boost::lexical_cast warning @@ -326,6 +329,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); @@ -400,6 +404,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); @@ -443,6 +448,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: @@ -509,6 +515,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; @@ -1067,6 +1074,20 @@ LLViewerObject* LLVOAvatarSelf::getWornAttachment(const LLUUID& inv_item_id) return NULL; } +// [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] + const std::string LLVOAvatarSelf::getAttachedPointName(const LLUUID& inv_item_id) const { const LLUUID& base_inv_item_id = gInventory.getLinkedItemID(inv_item_id); @@ -1104,6 +1125,18 @@ const LLViewerJointAttachment *LLVOAvatarSelf::attachObject(LLViewerObject *view LLAppearanceMgr::instance().registerAttachment(attachment_id); // Clear any pending requests once the attachment arrives. removeAttachmentRequest(attachment_id); + +// [RLVa:KB] - Checked: 2010-08-22 (RLVa-1.2.1a) | Modified: RLVa-1.2.1a + // NOTE: RLVa event handlers should be invoked *after* LLVOAvatar::attachObject() calls LLViewerJointAttachment::addObject() + if (rlv_handler_t::isEnabled()) + { + RlvAttachmentLockWatchdog::instance().onAttach(viewer_object, attachment); + gRlvHandler.onAttach(viewer_object, attachment); + + if ( (attachment->getIsHUDAttachment()) && (!gRlvAttachmentLocks.hasLockedHUD()) ) + gRlvAttachmentLocks.updateLockedHUD(); + } +// [/RLVa:KB] } return attachment; @@ -1113,6 +1146,23 @@ 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); + } + } + } +// [/RLVa:KB] + if (LLVOAvatar::detachObject(viewer_object)) { // the simulator should automatically handle permission revocation @@ -1145,6 +1195,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; diff --git a/indra/newview/llvoavatarself.h b/indra/newview/llvoavatarself.h index eb2475f666022181efc42456a912c95e15b03a54..9911cb4997ae0f636c490b36af2e17d086b25923 100644 --- a/indra/newview/llvoavatarself.h +++ b/indra/newview/llvoavatarself.h @@ -289,6 +289,9 @@ public: void addAttachmentRequest(const LLUUID& inv_item_id); void removeAttachmentRequest(const LLUUID& inv_item_id); LLViewerObject* getWornAttachment(const LLUUID& inv_item_id); +// [RLVa:KB] - Checked: 2009-12-18 (RLVa-1.1.0i) | Added: RLVa-1.1.0i + LLViewerJointAttachment* getWornAttachmentPoint(const LLUUID& inv_item_id) const; +// [/RLVa:KB] const std::string getAttachedPointName(const LLUUID& inv_item_id) const; /*virtual*/ const LLViewerJointAttachment *attachObject(LLViewerObject *viewer_object); /*virtual*/ BOOL detachObject(LLViewerObject *viewer_object); diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 761e12020bb3ed36776c6acb351a08a4a32d0fa2..55dfbbf6776ad434b91005560119e415bba489bf 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -63,6 +63,9 @@ #include "llmediadataclient.h" #include "llagent.h" #include "llviewermediafocus.h" +// [RLVa:KB] - Checked: 2010-04-04 (RLVa-1.2.0d) +#include "rlvhandler.h" +// [/RLVa:KB] const S32 MIN_QUIET_FRAMES_COALESCE = 30; const F32 FORCE_SIMPLE_RENDER_AREA = 512.f; @@ -3222,7 +3225,12 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, { LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); - if (facep->getViewerObject()->isSelected() && LLSelectMgr::getInstance()->mHideSelectedObjects) +// if (facep->getViewerObject()->isSelected() && LLSelectMgr::getInstance()->mHideSelectedObjects) +// [RLVa:KB] - Checked: 2010-04-04 (RLVa-1.2.0d) | Modified: RLVa-1.0.5a + const LLViewerObject* pObj = facep->getViewerObject(); + if ( (pObj->isSelected() && LLSelectMgr::getInstance()->mHideSelectedObjects) && + ((!rlv_handler_t::isEnabled()) || (!pObj->isHUDAttachment()) || (!gRlvAttachmentLocks.isLockedAttachment(pObj))) ) +// [/RVLa:KB] { return; } diff --git a/indra/newview/llwearabletype.cpp b/indra/newview/llwearabletype.cpp index d2e62c86ab788aee5b6b9a9adf0dc584959db6a7..0435f24f5418b28337a9eb9dea27cfb3015965db 100644 --- a/indra/newview/llwearabletype.cpp +++ b/indra/newview/llwearabletype.cpp @@ -58,6 +58,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() @@ -94,6 +100,10 @@ const std::string& LLWearableType::getTypeName(LLWearableType::EType type) { const LLWearableDictionary *dict = LLWearableDictionary::getInstance(); const WearableEntry *entry = dict->lookup(type); +// [RLVa:KB] - Checked: 2010-05-15 (RLVa-1.2.0g) | Added: RLVa-1.2.0g + if (!entry) + entry = dict->lookup(WT_INVALID); +// [/RLVa:KB] return entry->mName; } @@ -102,6 +112,10 @@ const std::string& LLWearableType::getTypeDefaultNewName(LLWearableType::EType t { const LLWearableDictionary *dict = LLWearableDictionary::getInstance(); const WearableEntry *entry = dict->lookup(type); +// [RLVa:KB] - Checked: 2010-05-15 (RLVa-1.2.0g) | Added: RLVa-1.2.0g + if (!entry) + entry = dict->lookup(WT_INVALID); +// [/RLVa:KB] return entry->mDefaultNewName; } @@ -110,6 +124,10 @@ const std::string& LLWearableType::getTypeLabel(LLWearableType::EType type) { const LLWearableDictionary *dict = LLWearableDictionary::getInstance(); const WearableEntry *entry = dict->lookup(type); +// [RLVa:KB] - Checked: 2010-05-15 (RLVa-1.2.0g) | Added: RLVa-1.2.0g + if (!entry) + entry = dict->lookup(WT_INVALID); +// [/RLVa:KB] return entry->mLabel; } @@ -118,6 +136,10 @@ LLAssetType::EType LLWearableType::getAssetType(LLWearableType::EType type) { const LLWearableDictionary *dict = LLWearableDictionary::getInstance(); const WearableEntry *entry = dict->lookup(type); +// [RLVa:KB] - Checked: 2010-05-15 (RLVa-1.2.0g) | Added: RLVa-1.2.0g + if (!entry) + entry = dict->lookup(WT_INVALID); +// [/RLVa:KB] return entry->mAssetType; } @@ -126,6 +148,10 @@ LLInventoryIcon::EIconName LLWearableType::getIconName(LLWearableType::EType typ { const LLWearableDictionary *dict = LLWearableDictionary::getInstance(); const WearableEntry *entry = dict->lookup(type); +// [RLVa:KB] - Checked: 2010-05-15 (RLVa-1.2.0g) | Added: RLVa-1.2.0g + if (!entry) + entry = dict->lookup(WT_INVALID); +// [/RLVa:KB] return entry->mIconName; } diff --git a/indra/newview/llworldmapview.cpp b/indra/newview/llworldmapview.cpp index 0c17b5e297c00e4001b731d62fa3b5d9e6758718..717b909a55dbc35cd7b902ac797d3b7372ae643e 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" @@ -992,7 +995,13 @@ 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() - llround(font->getLineHeight()) - TEXT_PADDING - vert_offset); +// if (label != "") +// [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0a) | Added: RLVa-1.0.0a if (label != "") +/* + if ( (label != "") && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) ) +*/ +// [/RLVa:KB] { font->renderUTF8( label, 0, @@ -1052,7 +1061,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.2.0f) | Modified: RLVa-1.2.0f + 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 e4c2ca9ae39ec5a408a5209332dfabbcc1095093..d347335a6e095de18c0c2c9e9b0bed64d75f6404 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -98,7 +98,9 @@ #include "llspatialpartition.h" #include "llmutelist.h" #include "lltoolpie.h" - +// [RLVa:KB] - Checked: 2010-04-04 (RLVa-1.2.0d) +#include "rlvhandler.h" +// [/RLVa:KB] #ifdef _DEBUG // Debug indices is disabled for now for debug performance - djs 4/24/02 @@ -2330,8 +2332,13 @@ 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-04-04 (RLVa-1.2.0d) | Modified: RLVa-1.0.5a + const LLViewerObject* pObj = drawablep->getVObj(); + if ( (pObj) && (pObj->isSelected()) && + ((!rlv_handler_t::isEnabled()) || (!pObj->isHUDAttachment()) || (!gRlvAttachmentLocks.isLockedAttachment(pObj))) ) +// [/RVLa:KB] { return; } diff --git a/indra/newview/rlvcommon.cpp b/indra/newview/rlvcommon.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4dae07fdf6286002a0996e5a63df530992889170 --- /dev/null +++ b/indra/newview/rlvcommon.cpp @@ -0,0 +1,578 @@ +/** + * + * Copyright (c) 2009-2010, 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 "llappviewer.h" +#include "llinstantmessage.h" +#include "llnotificationsutil.h" +#include "lluictrlfactory.h" +#include "llversionviewer.h" +#include "llviewerparcelmgr.h" +#include "llviewerregion.h" +#include "llviewerstats.h" +#include "llworld.h" + +#include "rlvcommon.h" +#include "rlvhandler.h" +#include "rlvlocks.h" + +// ============================================================================ +// RlvNotifications +// + +#ifdef RLV_EXTENSION_NOTIFY_BEHAVIOUR +// Checked: 2009-12-05 (RLVa-1.1.0h) | Added: RLVa-1.1.0h +/* +void RlvNotifications::notifyBehaviour(ERlvBehaviour eBhvr, ERlvParamType eType) +{ + const std::string& strMsg = RlvStrings::getBehaviourNotificationString(eBhvr, eType); + if (!strMsg.empty()) + { + LLSD argsNotify; + argsNotify["MESSAGE"] = strMsg; + LLNotifications::instance().add("SystemMessageTip", argsNotify); + } +} +*/ +#endif // RLV_EXTENSION_NOTIFY_BEHAVIOUR + +// 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::fCompositeFolders = FALSE; +#endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS +BOOL RlvSettings::fLegacyNaming = TRUE; +BOOL RlvSettings::fNoSetEnv = FALSE; +BOOL RlvSettings::fShowNameTags = FALSE; + +// Checked: 2010-02-27 (RLVa-1.2.0a) | Modified: RLVa-1.1.0i +void RlvSettings::initClass() +{ + static bool fInitialized = false; + if (!fInitialized) + { + #ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS + fCompositeFolders = rlvGetSettingBOOL(RLV_SETTING_ENABLECOMPOSITES, FALSE); + if (gSavedSettings.controlExists(RLV_SETTING_ENABLECOMPOSITES)) + gSavedSettings.getControl(RLV_SETTING_ENABLECOMPOSITES)->getSignal()->connect(boost::bind(&onChangedSettingBOOL, _2, &fCompositeFolders)); + #endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS + + fLegacyNaming = rlvGetSettingBOOL(RLV_SETTING_ENABLELEGACYNAMING, TRUE); + if (gSavedSettings.controlExists(RLV_SETTING_ENABLELEGACYNAMING)) + gSavedSettings.getControl(RLV_SETTING_ENABLELEGACYNAMING)->getSignal()->connect(boost::bind(&onChangedSettingBOOL, _2, &fLegacyNaming)); + + fNoSetEnv = rlvGetSettingBOOL(RLV_SETTING_NOSETENV, FALSE); + + fShowNameTags = rlvGetSettingBOOL(RLV_SETTING_SHOWNAMETAGS, FALSE); + if (gSavedSettings.controlExists(RLV_SETTING_SHOWNAMETAGS)) + gSavedSettings.getControl(RLV_SETTING_SHOWNAMETAGS)->getSignal()->connect(boost::bind(&onChangedSettingBOOL, _2, &fShowNameTags)); + + fInitialized = true; + } +} + +#ifndef RLV_WORKAROUND_REZMULTIPLEATTACH +BOOL RlvSettings::getEnableSharedWear() +{ + // NOTE-RLVa: it's not proper but some code relies on the fact that getEnableSharedWear() returns FALSE if any attach point is locked + return + (rlvGetSettingBOOL(RLV_SETTING_ENABLESHAREDWEAR, FALSE)) && // "Enable Shared Wear" is toggled on and... + (!gRlvHandler.hasLockedAttachment(RLV_LOCK_ANY)); // no attachment point is non-attachable or non-detachable +} +#endif // RLV_WORKAROUND_REZMULTIPLEATTACH + +#ifdef RLV_EXTENSION_STARTLOCATION + // Checked: 2010-04-01 (RLVa-1.2.0c) | Modified: RLVa-0.2.1d + void RlvSettings::updateLoginLastLocation() + { + if (gSavedPerAccountSettings.controlExists(RLV_SETTING_LOGINLASTLOCATION)) + { + BOOL fValue = (gRlvHandler.hasBehaviour(RLV_BHVR_TPLOC)) || (!gRlvHandler.canStand()); + if (gSavedPerAccountSettings.getBOOL(RLV_SETTING_LOGINLASTLOCATION) != fValue) + { + gSavedPerAccountSettings.setBOOL(RLV_SETTING_LOGINLASTLOCATION, fValue); + gSavedPerAccountSettings.saveToFile(gSavedSettings.getString("PerAccountSettingsFile"), TRUE); + } + } + } +#endif // RLV_EXTENSION_STARTLOCATION + +// 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; +} + +// ============================================================================ +// RlvStrings +// + +std::vector<std::string> RlvStrings::m_Anonyms; +std::map<std::string, std::string> RlvStrings::m_StringMap; +#ifdef RLV_EXTENSION_NOTIFY_BEHAVIOUR +std::map<ERlvBehaviour, std::string> RlvStrings::m_BhvrAddMap; +std::map<ERlvBehaviour, std::string> RlvStrings::m_BhvrRemMap; +#endif // RLV_EXTENSION_NOTIFY_BEHAVIOUR + +// Checked: 2010-03-09 (RLVa-1.2.0a) | Added: RLVa-1.1.0h +void RlvStrings::initClass() +{ + static bool fInitialized = false; + if (!fInitialized) + { + LLXMLNodePtr xmlRoot; + if ( (!LLUICtrlFactory::getLayeredXMLNode("rlva_strings.xml", xmlRoot)) || (xmlRoot.isNull()) || (!xmlRoot->hasName("rlva_strings")) ) + { + RLV_ERRS << "Problem reading RLVa string XML file" << RLV_ENDL; + return; + } + + for (LLXMLNode* pNode = xmlRoot->getFirstChild(); pNode != NULL; pNode = pNode->getNextSibling()) + { + if (pNode->hasName("strings")) + { + std::string strName; + for (LLXMLNode* pStringNode = pNode->getFirstChild(); pStringNode != NULL; pStringNode = pStringNode->getNextSibling()) + { + if ( (!pStringNode->hasName("string")) || (!pStringNode->getAttributeString("name", strName)) ) + continue; + m_StringMap[strName] = pStringNode->getTextContents(); + } + } + else if (pNode->hasName("anonyms")) + { + for (LLXMLNode* pAnonymNode = pNode->getFirstChild(); pAnonymNode != NULL; pAnonymNode = pAnonymNode->getNextSibling()) + { + if (!pAnonymNode->hasName("anonym")) + continue; + m_Anonyms.push_back(pAnonymNode->getTextContents()); + } + } + #ifdef RLV_EXTENSION_NOTIFY_BEHAVIOUR + else if (pNode->hasName("behaviour-notifications")) + { + std::string strBhvr, strType; ERlvBehaviour eBhvr; + for (LLXMLNode* pNotifyNode = pNode->getFirstChild(); pNotifyNode != NULL; pNotifyNode = pNotifyNode->getNextSibling()) + { + if ( (!pNotifyNode->hasName("notification")) || (!pNotifyNode->getAttributeString("type", strType)) || + (!pNotifyNode->getAttributeString("behaviour", strBhvr)) || + ((eBhvr = RlvCommand::getBehaviourFromString(strBhvr)) == RLV_BHVR_UNKNOWN) ) + { + continue; + } + if ("add" == strType) + m_BhvrAddMap.insert(std::pair<ERlvBehaviour, std::string>(eBhvr, pNotifyNode->getTextContents())); + else if ("rem" == strType) + m_BhvrRemMap.insert(std::pair<ERlvBehaviour, std::string>(eBhvr, pNotifyNode->getTextContents())); + } + } + #endif // RLV_EXTENSION_NOTIFY_BEHAVIOUR + } + + if ( (m_StringMap.empty()) || (m_Anonyms.empty()) ) + { + RLV_ERRS << "Problem parsing RLVa string XML file" << RLV_ENDL; + return; + } + + fInitialized = true; + } +} + +// 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()]; +} + +#ifdef RLV_EXTENSION_NOTIFY_BEHAVIOUR +// Checked: 2009-12-05 (RLVa-1.1.0h) | Added: RLVa-1.1.0h +const std::string& RlvStrings::getBehaviourNotificationString(ERlvBehaviour eBhvr, ERlvParamType eType) +{ + if (RLV_TYPE_ADD == eType) + { + std::map<ERlvBehaviour, std::string>::const_iterator itString = m_BhvrAddMap.find(eBhvr); + return (itString != m_BhvrAddMap.end()) ? itString->second : LLStringUtil::null; + } + else if (RLV_TYPE_REMOVE == eType) + { + std::map<ERlvBehaviour, std::string>::const_iterator itString = m_BhvrRemMap.find(eBhvr); + return (itString != m_BhvrRemMap.end()) ? itString->second : LLStringUtil::null; + } + return LLStringUtil::null; +} +#endif // RLV_EXTENSION_NOTIFY_BEHAVIOUR + +// Checked: 2009-11-11 (RLVa-1.1.0a) | Added: RLVa-1.1.0a +const std::string& RlvStrings::getString(const std::string& strStringName) +{ + static const std::string strMissing = "(Missing RLVa string)"; + std::map<std::string, std::string>::const_iterator itString = m_StringMap.find(strStringName); + return (itString != m_StringMap.end()) ? itString->second : 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_FAILED_SYNTAX: + return "syntax 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"; + // 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; +} + +// Checked: 2010-03-27 (RLVa-1.2.0b) | Modified: RLVa-1.2.0b +std::string RlvStrings::getVersion(bool fLegacy /*=false*/) +{ + return llformat("%s viewer v%d.%d.%d (%s %d.%d.%d.%d - RLVa %d.%d.%d)", + ( (!fLegacy) ? "RestrainedLove" : "RestrainedLife" ), + RLV_VERSION_MAJOR, RLV_VERSION_MINOR, RLV_VERSION_PATCH, + LLAppViewer::instance()->getSecondLifeTitle().c_str(), LL_VERSION_MAJOR, LL_VERSION_MINOR, LL_VERSION_PATCH, LL_VERSION_BUILD, + RLVa_VERSION_MAJOR, RLVa_VERSION_MINOR, RLVa_VERSION_PATCH); +} + +// Checked: 2010-04-18 (RLVa-1.2.0e) | Added: RLVa-1.2.0e +std::string RlvStrings::getVersionAbout() +{ + return llformat("RLV v%d.%d.%d / RLVa v%d.%d.%d%c" , + RLV_VERSION_MAJOR, RLV_VERSION_MINOR, RLV_VERSION_PATCH, + RLVa_VERSION_MAJOR, RLVa_VERSION_MINOR, RLVa_VERSION_PATCH, 'a' + RLVa_VERSION_BUILD); +} + + +// Checked: 2010-03-27 (RLVa-1.2.0b) | Modified: RLVa-1.1.0a +std::string RlvStrings::getVersionNum() +{ + return llformat("%d%02d%02d%02d", RLV_VERSION_MAJOR, RLV_VERSION_MINOR, RLV_VERSION_PATCH, RLV_VERSION_BUILD); +} + +// Checked: 2010-05-26 (RLVa-1.2.0h) | Added: RLVa-1.2.0g +bool RlvStrings::hasString(const std::string& strStringName) +{ + return m_StringMap.find(strStringName) != m_StringMap.end(); +} + +// ============================================================================ +// RlvUtil +// + +bool RlvUtil::m_fForceTp = false; + +// Checked: 2009-07-04 (RLVa-1.0.0a) | Modified: RLVa-1.0.0a +void RlvUtil::filterLocation(std::string& strUTF8Text) +{ + // TODO-RLVa: if either the region or parcel name is a simple word such as "a" or "the" then confusion will ensue? + // -> not sure how you would go about preventing this though :|... + + // Filter any mention of the surrounding region names + LLWorld::region_list_t regions = LLWorld::getInstance()->getRegionList(); + const std::string& strHiddenRegion = RlvStrings::getString(RLV_STRING_HIDDEN_REGION); + for (LLWorld::region_list_t::const_iterator itRegion = regions.begin(); itRegion != regions.end(); ++itRegion) + rlvStringReplace(strUTF8Text, (*itRegion)->getName(), strHiddenRegion); + + // Filter any mention of the parcel name + LLViewerParcelMgr* pParcelMgr = LLViewerParcelMgr::getInstance(); + if (pParcelMgr) + rlvStringReplace(strUTF8Text, pParcelMgr->getAgentParcelName(), RlvStrings::getString(RLV_STRING_HIDDEN_PARCEL)); +} + +// Checked: 2010-04-22 (RLVa-1.2.0f) | Modified: RLVa-1.2.0f +void RlvUtil::filterNames(std::string& strUTF8Text) +{ + std::vector<LLUUID> idAgents; + LLWorld::getInstance()->getAvatars(&idAgents, NULL); + + std::string strFullName; + for (int idxAgent = 0, cntAgent = idAgents.size(); idxAgent < cntAgent; idxAgent++) + { + // LLCacheName::getFullName() will add the UUID to the lookup queue if we don't know it yet + if (gCacheName->getFullName(idAgents[idxAgent], strFullName)) + rlvStringReplace(strUTF8Text, strFullName, RlvStrings::getAnonym(strFullName)); + } +} + +// Checked: 2010-08-29 (RLVa-1.2.1c) | Added: RLVa-1.2.1c +void RlvUtil::forceTp(const LLVector3d &posDest) +{ + m_fForceTp = true; + gAgent.teleportViaLocation(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: 2010-04-08 (RLVa-1.2.0d) | Added: RLVa-1.2.0d +void RlvUtil::notifyFailedAssertion(const char* pstrAssert, const char* pstrFile, int nLine) +{ + LLSD argsNotify; + argsNotify["MESSAGE"] = llformat("RLVa assertion failure: %s (%s - %d)", pstrAssert, pstrFile, 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_BUSY_AUTO_RESPONSE, idSession); + gAgent.sendReliableMessage(); +} + +// Checked: 2010-03-09 (RLVa-1.2.0a) | Modified: RLVa-1.0.1e +bool RlvUtil::sendChatReply(S32 nChannel, const std::string& strUTF8Text) +{ + if (!isValidReplyChannel(nChannel)) + return false; + + // Copy/paste from send_chat_from_viewer() + gMessageSystem->newMessageFast(_PREHASH_ChatFromViewer); + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + gMessageSystem->nextBlockFast(_PREHASH_ChatData); + gMessageSystem->addStringFast(_PREHASH_Message, strUTF8Text); + gMessageSystem->addU8Fast(_PREHASH_Type, CHAT_TYPE_SHOUT); + gMessageSystem->addS32("Channel", nChannel); + gAgent.sendReliableMessage(); + LLViewerStats::getInstance()->incStat(LLViewerStats::ST_CHAT_COUNT); + + return true; +} + +// ============================================================================ +// Generic menu enablers +// + +// Checked: 2010-04-23 (RLVa-1.2.0g) | Modified: RLVa-1.2.0g +bool rlvMenuCheckEnabled() +{ + return rlv_handler_t::isEnabled(); +} + +// Checked: 2010-04-23 (RLVa-1.2.0g) | Modified: RLVa-1.2.0g +bool rlvMenuToggleEnabled() +{ + gSavedSettings.setBOOL(RLV_SETTING_MAIN, !rlv_handler_t::isEnabled()); + + LLSD args; + args["MESSAGE"] = + llformat("RestrainedLove Support will be %s after you restart", (rlv_handler_t::isEnabled()) ? "disabled" : "enabled" ); + LLNotificationsUtil::add("GenericAlert", args); + + return true; +} + +// 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 = RlvCommand::getBehaviourFromString(sdParam.asString()); + fEnable = (eBhvr != RLV_BHVR_UNKNOWN) ? !gRlvHandler.hasBehaviour(eBhvr) : true; + } + return fEnable; +} + +// ============================================================================ +// Selection functors +// + +// 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: 2009-07-05 (RLVa-1.0.0b) | Modified: RLVa-0.2.0f +bool RlvSelectIsOwnedByOrGroupOwned::apply(LLSelectNode* pNode) +{ + return (pNode->mPermissions->isGroupOwned()) || (pNode->mPermissions->getOwner() == m_idAgent); +} + +// Checked: 2010-04-01 (RLVa-1.2.0c) | Modified: RLVa-0.2.0f +bool RlvSelectIsSittingOn::apply(LLSelectNode* pNode) +{ + return (pNode->getObject()) && (pNode->getObject()->getRootEdit() == m_pObject); +} + +// ============================================================================ +// Predicates +// + +// Checked: 2010-05-14 (RLVa-1.2.0g) | Modified: RLVa-1.2.0g +bool rlvPredIsWearableItem(const LLViewerInventoryItem* pItem) +{ + // RELEASE-RLVa: [SL-2.0.0] This will need rewriting for "ENABLE_MULTIATTACHMENTS" + if (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 (gRlvWearableLocks.canWear(pItem) & RLV_WEAR_REPLACE); + case LLAssetType::AT_CLOTHING: + return (RLV_WEAR_LOCKED != gRlvWearableLocks.canWear(pItem)); + case LLAssetType::AT_OBJECT: + return gRlvAttachmentLocks.canAttach(pItem); + case LLAssetType::AT_GESTURE: + return true; + default: + RLV_ASSERT(false); + } + } + return false; +} + +// Checked: 2010-03-22 (RLVa-1.2.0c) | Added: RLVa-1.2.0a +bool rlvPredIsNotWearableItem(const LLViewerInventoryItem* pItem) +{ + return !rlvPredIsWearableItem(pItem); +} + +// Checked: 2010-03-22 (RLVa-1.2.0c) | Added: RLVa-1.2.0a +bool rlvPredIsRemovableItem(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(false); + } + } + return false; +} + +// Checked: 2010-03-22 (RLVa-1.2.0c) | Added: RLVa-1.2.0a +bool rlvPredIsNotRemovableItem(const LLViewerInventoryItem* pItem) +{ + return !rlvPredIsRemovableItem(pItem); +} + +// ============================================================================ +// 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)); +} +*/ + +// ============================================================================ diff --git a/indra/newview/rlvcommon.h b/indra/newview/rlvcommon.h new file mode 100644 index 0000000000000000000000000000000000000000..f29fe3abb48ac09630066c5717b38daa9f7f9cce --- /dev/null +++ b/indra/newview/rlvcommon.h @@ -0,0 +1,242 @@ +/** + * + * Copyright (c) 2009-2010, 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 "llinventorymodel.h" +#include "llselectmgr.h" +#include "llviewercontrol.h" +#include "llviewerinventory.h" + +#include "rlvdefines.h" + +// ============================================================================ +// Forward declarations +// + +class RlvCommand; + +// ============================================================================ +// RlvSettings +// + +inline BOOL rlvGetSettingBOOL(const std::string& strSetting, BOOL fDefault) +{ + RLV_ASSERT_DBG(gSavedSettings.controlExists(strSetting)); + return (gSavedSettings.controlExists(strSetting)) ? gSavedSettings.getBOOL(strSetting) : fDefault; +} +inline BOOL rlvGetPerUserSettingsBOOL(const std::string& strSetting, BOOL fDefault) +{ + RLV_ASSERT_DBG(gSavedPerAccountSettings.controlExists(strSetting)); + return (gSavedPerAccountSettings.controlExists(strSetting)) ? gSavedPerAccountSettings.getBOOL(strSetting) : fDefault; +} + +class RlvSettings +{ +public: + static BOOL getDebug() { return rlvGetSettingBOOL(RLV_SETTING_DEBUG, FALSE); } + static BOOL getForbidGiveToRLV() { return rlvGetSettingBOOL(RLV_SETTING_FORBIDGIVETORLV, TRUE); } + static BOOL getNoSetEnv() { return fNoSetEnv; } + + static BOOL getDebugHideUnsetDup() { return rlvGetSettingBOOL(RLV_SETTING_DEBUGHIDEUNSETDUP, FALSE); } + #ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS + static BOOL getEnableComposites() { return fCompositeFolders; } + #endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS + static BOOL getEnableLegacyNaming() { return fLegacyNaming; } + static BOOL getEnableSharedWear(); + static BOOL getHideLockedLayers() { return rlvGetSettingBOOL(RLV_SETTING_HIDELOCKEDLAYER, FALSE); } + static BOOL getHideLockedAttach() { return rlvGetSettingBOOL(RLV_SETTING_HIDELOCKEDATTACH, FALSE); } + static BOOL getHideLockedInventory() { return rlvGetSettingBOOL(RLV_SETTING_HIDELOCKEDINVENTORY, FALSE); } + static BOOL getSharedInvAutoRename() { return rlvGetSettingBOOL(RLV_SETTING_SHAREDINVAUTORENAME, TRUE); } + static BOOL getShowNameTags() { return fShowNameTags; } + + #ifdef RLV_EXTENSION_STARTLOCATION + static BOOL getLoginLastLocation() { return rlvGetPerUserSettingsBOOL(RLV_SETTING_LOGINLASTLOCATION, TRUE); } + static void updateLoginLastLocation(); + #endif // RLV_EXTENSION_STARTLOCATION + + static void initClass(); +protected: + static bool onChangedSettingBOOL(const LLSD& sdValue, BOOL* pfSetting); + + #ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS + static BOOL fCompositeFolders; + #endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS + static BOOL fLegacyNaming; + static BOOL fNoSetEnv; + static BOOL fShowNameTags; +}; + +#ifdef RLV_WORKAROUND_REZMULTIPLEATTACH +inline BOOL RlvSettings::getEnableSharedWear() +{ + return FALSE; +} +#endif // RLV_WORKAROUND_REZMULTIPLEATTACH + +// ============================================================================ +// RlvStrings +// + +class RlvStrings +{ +public: + static void initClass(); + + static const std::string& getAnonym(const std::string& strName); // @shownames + static const std::string& getBehaviourNotificationString(ERlvBehaviour eBhvr, ERlvParamType eType); + static const std::string& getString(const std::string& strStringName); + static const char* getStringFromReturnCode(ERlvCmdRet eRet); + static std::string getVersion(bool fLegacy = false); // @version + static std::string getVersionAbout(); // Shown in Help / About + static std::string getVersionNum(); // @versionnum + static bool hasString(const std::string& strStringName); + +protected: + static std::vector<std::string> m_Anonyms; + static std::map<std::string, std::string> m_StringMap; + #ifdef RLV_EXTENSION_NOTIFY_BEHAVIOUR + static std::map<ERlvBehaviour, std::string> m_BhvrAddMap; + static std::map<ERlvBehaviour, std::string> m_BhvrRemMap; + #endif // RLV_EXTENSION_NOTIFY_BEHAVIOUR +}; + +// ============================================================================ +// RlvUtil - Collection of (static) helper functions +// + +class RlvUtil +{ +public: + static bool isEmote(const std::string& strUTF8Text); + static bool isNearbyAgent(const LLUUID& idAgent); // @shownames + static bool isNearbyRegion(const std::string& strRegion); // @showloc + + static void filterLocation(std::string& strUTF8Text); // @showloc + static void filterNames(std::string& strUTF8Text); // @shownames + + static bool isForceTp() { return m_fForceTp; } + static void forceTp(const LLVector3d& posDest); // Ignores restrictions that might otherwise prevent tp'ing + + static void notifyFailedAssertion(const char* pstrAssert, const char* pstrFile, int nLine); + + static void sendBusyMessage(const LLUUID& idTo, const std::string& strMsg, const LLUUID& idSession = LLUUID::null); + static bool isValidReplyChannel(S32 nChannel); + static bool sendChatReply(S32 nChannel, const std::string& strUTF8Text); + static bool sendChatReply(const std::string& strChannel, const std::string& strUTF8Text); + +protected: + static bool m_fForceTp; // @standtp +}; + +// ============================================================================ +// Extensibility classes +// + +class RlvCommandHandler +{ +public: + virtual ~RlvCommandHandler() {} + virtual bool onAddRemCommand(const RlvCommand& rlvCmd, ERlvCmdRet& cmdRet) { return false; } + virtual bool onClearCommand(const RlvCommand& rlvCmd, ERlvCmdRet& cmdRet) { return false; } + virtual bool onReplyCommand(const RlvCommand& rlvCmd, ERlvCmdRet& cmdRet) { return false; } + virtual bool onForceCommand(const RlvCommand& rlvCmd, ERlvCmdRet& cmdRet) { return false; } +}; +typedef bool (RlvCommandHandler::*rlvCommandHandler)(const RlvCommand& rlvCmd, ERlvCmdRet& cmdRet); + +// ============================================================================ +// Generic menu enablers +// + +bool rlvMenuCheckEnabled(); +bool rlvMenuToggleEnabled(); +bool rlvMenuEnableIfNot(const LLSD& sdParam); + +// ============================================================================ +// Selection functors +// + +struct RlvSelectHasLockedAttach : public LLSelectedNodeFunctor +{ + RlvSelectHasLockedAttach() {} + virtual bool apply(LLSelectNode* pNode); +}; + +struct RlvSelectIsOwnedByOrGroupOwned : public LLSelectedNodeFunctor +{ + RlvSelectIsOwnedByOrGroupOwned(const LLUUID& uuid) : m_idAgent(uuid) {} + virtual bool apply(LLSelectNode* pNode); +protected: + LLUUID m_idAgent; +}; + +struct RlvSelectIsSittingOn : public LLSelectedNodeFunctor +{ + RlvSelectIsSittingOn(LLXform* pObject) : m_pObject(pObject) {} + virtual bool apply(LLSelectNode* pNode); +protected: + LLXform* m_pObject; +}; + +// ============================================================================ +// Predicates +// + +bool rlvPredIsWearableItem(const LLViewerInventoryItem* pItem); +bool rlvPredIsNotWearableItem(const LLViewerInventoryItem* pItem); +bool rlvPredIsRemovableItem(const LLViewerInventoryItem* pItem); +bool rlvPredIsNotRemovableItem(const LLViewerInventoryItem* pItem); + +struct RlvPredIsEqualOrLinkedItem +{ + RlvPredIsEqualOrLinkedItem(const LLViewerInventoryItem* pItem) : m_pItem(pItem) {} + RlvPredIsEqualOrLinkedItem(const LLUUID& idItem) { m_pItem = gInventory.getItem(idItem); } + + bool operator()(const LLViewerInventoryItem* pItem) const + { + return (m_pItem) && (pItem) && (m_pItem->getLinkedUUID() == pItem->getLinkedUUID()); + } +protected: + const LLViewerInventoryItem* m_pItem; +}; + +// ============================================================================ +// Inlined class member functions +// + +// Checked: 2010-03-26 (RLVa-1.2.0b) | Modified: RLVa-1.0.2a +inline bool RlvUtil::isEmote(const std::string& strUTF8Text) +{ + return (strUTF8Text.length() > 4) && ( (strUTF8Text.compare(0, 4, "/me ") == 0) || (strUTF8Text.compare(0, 4, "/me'") == 0) ); +} + +// Checked: 2010-03-09 (RLVa-1.2.0b) | Added: RLVa-1.0.2a +inline bool RlvUtil::isValidReplyChannel(S32 nChannel) +{ + return (nChannel > 0) && (CHAT_CHANNEL_DEBUG != nChannel); +} + +// Checked: 2009-08-05 (RLVa-1.0.1e) | Added: RLVa-1.0.0e +inline bool RlvUtil::sendChatReply(const std::string& strChannel, const std::string& strUTF8Text) +{ + S32 nChannel; + return (LLStringUtil::convertToS32(strChannel, nChannel)) ? sendChatReply(nChannel, strUTF8Text) : false; +} + +// ============================================================================ + +#endif // RLV_COMMON_H diff --git a/indra/newview/rlvdefines.h b/indra/newview/rlvdefines.h new file mode 100644 index 0000000000000000000000000000000000000000..6ce241fd6e70d0f824e242791cbcb7c59c850101 --- /dev/null +++ b/indra/newview/rlvdefines.h @@ -0,0 +1,316 @@ +/** + * + * Copyright (c) 2009-2010, 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 + +// ============================================================================ +// Extensions +// + +// Provides access to "advanced" features through the RLVa debug menu +#define RLV_EXTENSION_FLOATER_RESTRICTIONS // Enables the Advanced / RLVa / Restrictions... floater +#define RLV_EXTENSION_HIDELOCKED // "Hide locked layers", "Hide locked attachments" and "Hide locked inventory" + +// Extensions +#define RLV_EXTENSION_CMD_GETSETDEBUG_EX // Extends the debug variables accessible through @getdebug_xxx/@setdebug_xxx +#define RLV_EXTENSION_CMD_FINDFOLDERS // @findfolders:<option>=<channel> - @findfolder with multiple results +#define RLV_EXTENSION_FLAG_NOSTRIP // Layers and attachments marked as "nostrip" are exempt from @detach/@remoutfit +#define RLV_EXTENSION_FORCEWEAR_GESTURES // @attach*/detach* commands also (de)activate gestures +#define RLV_EXTENSION_GIVETORLV_A2A // Allow "Give to #RLV" on avatar-to-avatar inventory offers +#define RLV_EXTENSION_NOTIFY_BEHAVIOUR // Provides the option to show a customizable notification whenever a behaviour gets (un)set +#define RLV_EXTENSION_STARTLOCATION // Reenables "Start Location" at login if not @tploc=n or @unsit=n restricted at last logoff +//#define RLV_EXPERIMENTAL // Enables/disables experimental features en masse +#define RLV_EXPERIMENTAL_CMDS // Enables/disables experimental commands en masse + +// Experimental features +#ifdef RLV_EXPERIMENTAL + // Stable (will mature to RLV_EXTENSION_XXX in next release if no bugs are found) + + // Under testing (stable, but requires further testing - safe for public release but may be quirky) + #define RLV_EXPERIMENTAL_COMPOSITEFOLDERS + + // Under development (don't include in public release) + #if LL_RELEASE_WITH_DEBUG_INFO || LL_DEBUG + #define RLV_EXPERIMENTAL_FIRSTUSE // Enables a number of "first use" popups + #endif // LL_RELEASE_WITH_DEBUG_INFO || LL_DEBUG +#endif // RLV_EXPERIMENTAL + +// Experimental commands (not part of the RLV API spec, disabled on public releases) +#ifdef RLV_EXPERIMENTAL_CMDS + #define RLV_EXTENSION_CMD_ALLOWIDLE // Forces "Away" status when idle (effect is the same as setting AllowIdleAFK to TRUE) +// #define RLV_EXTENSION_CMD_GETXXXNAMES // @get[add|rem]attachnames:<option>=<channel> and @get[add|rem]outfitnames=<channel> + #define RLV_EXTENSION_CMD_INTERACT // @interact=n + #define RLV_EXTENSION_CMD_TOUCHXXX // @touch:uuid=n|y, @touchworld[:<uuid>]=n|y, @touchattach[:<uuid>]=n|y, @touchud[:<uuid>]=n|y +#endif // RLV_EXPERIMENTAL_CMDS + +// Workarounds +#define RLV_WORKAROUND_REZMULTIPLEATTACH // See http://jira.secondlife.com/browse/SVC-5383 ; disables "Shared Wear" + +// ============================================================================ +// Defines +// + +// Version of the specifcation we support +const S32 RLV_VERSION_MAJOR = 2; +const S32 RLV_VERSION_MINOR = 1; +const S32 RLV_VERSION_PATCH = 2; +const S32 RLV_VERSION_BUILD = 0; + +// Implementation version +const S32 RLVa_VERSION_MAJOR = 1; +const S32 RLVa_VERSION_MINOR = 2; +const S32 RLVa_VERSION_PATCH = 1; +const S32 RLVa_VERSION_BUILD = 2; + +// Uncomment before a final release +//#define RLV_RELEASE + +// The official viewer version we're patching against +#define RLV_MAKE_TARGET(x, y, z) ((x << 16) | (y << 8) | z) +#define RLV_TARGET RLV_MAKE_TARGET(2, 1, 2) + +// 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 + #ifdef 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_PUTINV_PREFIX "#RLV/~" +#define RLV_SETROT_OFFSET F_PI_BY_TWO // @setrot is off by 90° with the rest of SL + +#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 RlvCommand::initLookupTable() +enum ERlvBehaviour { + RLV_BHVR_DETACH = 0, // "detach" + RLV_BHVR_ATTACH, // "attach" + RLV_BHVR_ADDATTACH, // "addattach" + RLV_BHVR_REMATTACH, // "remattach" + RLV_BHVR_ADDOUTFIT, // "addoutfit" + RLV_BHVR_REMOUTFIT, // "remoutfit" + RLV_BHVR_EMOTE, // "emote" + RLV_BHVR_SENDCHAT, // "sendchat" + RLV_BHVR_RECVCHAT, // "recvchat" + RLV_BHVR_RECVEMOTE, // "recvemote" + RLV_BHVR_REDIRCHAT, // "redirchat" + RLV_BHVR_REDIREMOTE, // "rediremote" + RLV_BHVR_CHATWHISPER, // "chatwhisper" + RLV_BHVR_CHATNORMAL, // "chatnormal" + RLV_BHVR_CHATSHOUT, // "chatshout" + RLV_BHVR_SENDCHANNEL, // "sendchannel" + RLV_BHVR_SENDIM, // "sendim" + RLV_BHVR_RECVIM, // "recvim" + 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_SHOWHOVERTEXT, // "showhovertext" + RLV_BHVR_SHOWHOVERTEXTHUD, // "showhovertexthud" + RLV_BHVR_SHOWHOVERTEXTWORLD, // "showhovertextworld" + RLV_BHVR_SHOWHOVERTEXTALL, // "showhovertextall" + RLV_BHVR_TPLM, // "tplm" + RLV_BHVR_TPLOC, // "tploc" + RLV_BHVR_TPLURE, // "tplure" + RLV_BHVR_VIEWNOTE, // "viewnote" + RLV_BHVR_VIEWSCRIPT, // "viewscript" + RLV_BHVR_VIEWTEXTURE, // "viewtexture" + RLV_BHVR_ACCEPTPERMISSION, // "acceptpermission" + RLV_BHVR_ACCEPTTP, // "accepttp" + RLV_BHVR_ALLOWIDLE, // "allowidle" + RLV_BHVR_EDIT, // "edit" + RLV_BHVR_REZ, // "rez" + RLV_BHVR_FARTOUCH, // "fartouch" + RLV_BHVR_INTERACT, // "interact" + RLV_BHVR_TOUCH, // "touch" + RLV_BHVR_TOUCHATTACH, // "touchattach" + RLV_BHVR_TOUCHHUD, // "touchhud" + RLV_BHVR_TOUCHWORLD, // "touchworld" + RLV_BHVR_FLY, // "fly" + 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_DETACHME, // "detachme" + RLV_BHVR_ATTACHOVER, // "attachover" + RLV_BHVR_ATTACHTHIS, // "attachthis" + RLV_BHVR_ATTACHTHISOVER, // "attachthisover" + RLV_BHVR_DETACHTHIS, // "detachthis" + RLV_BHVR_ATTACHALL, // "attachall" + RLV_BHVR_ATTACHALLOVER, // "attachallover" + RLV_BHVR_DETACHALL, // "detachall" + RLV_BHVR_ATTACHALLTHIS, // "attachallthis" + RLV_BHVR_ATTACHALLTHISOVER, // "attachallthisover" + RLV_BHVR_DETACHALLTHIS, // "detachallthis" + 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_GETSITID, // "getsitid" + RLV_BHVR_GETSTATUS, // "getstatus" + RLV_BHVR_GETSTATUSALL, // "getstatusall" + + RLV_BHVR_COUNT, + RLV_BHVR_UNKNOWN +}; + +enum ERlvParamType { + RLV_TYPE_UNKNOWN, + RLV_TYPE_ADD, // <param> == "n"|"add" + RLV_TYPE_REMOVE, // <param> == "y"|"rem" + RLV_TYPE_FORCE, // <param> == "force" + RLV_TYPE_REPLY, // <param> == <number> + RLV_TYPE_CLEAR +}; + +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_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) +}; + +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_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_NOSETENV "RestrainedLoveNoSetEnv" +#define RLV_SETTING_FORBIDGIVETORLV "RestrainedLoveForbidGiveToRLV" + +#define RLV_SETTING_DEBUGHIDEUNSETDUP "RLVaDebugHideUnsetDuplicate" +#define RLV_SETTING_ENABLECOMPOSITES "RLVaEnableCompositeFolders" +#define RLV_SETTING_ENABLELEGACYNAMING "RLVaEnableLegacyNaming" +#define RLV_SETTING_ENABLESHAREDWEAR "RLVaEnableSharedWear" +#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_SHOWNAMETAGS "RLVaShowNameTags" + +#define RLV_SETTING_FIRSTUSE_PREFIX "FirstRLV" +#define RLV_SETTING_FIRSTUSE_GIVETORLV RLV_SETTING_FIRSTUSE_PREFIX"GiveToRLV" + +// ============================================================================ +// Strings +// + +#define RLV_STRING_HIDDEN "hidden_generic" +#define RLV_STRING_HIDDEN_PARCEL "hidden_parcel" +#define RLV_STRING_HIDDEN_REGION "hidden_region" + +#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_VIEWXXX "blocked_viewxxx" +#define RLV_STRING_BLOCKED_TPLURE_REMOTE "blocked_tplure_remote" + +// ============================================================================ + +#endif // RLV_DEFINES_H diff --git a/indra/newview/rlvextensions.cpp b/indra/newview/rlvextensions.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2e38ecd06b5d93164b43fc3f3f5001a8e0d54e6d --- /dev/null +++ b/indra/newview/rlvextensions.cpp @@ -0,0 +1,552 @@ +/** + * + * Copyright (c) 2009-2010, 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 "llviewercontrol.h" +//#include "llviewerwindow.h" +//#include "llvoavatar.h" +#include "llwlparammanager.h" + +#include "rlvextensions.h" +#include "rlvhandler.h" + +// ============================================================================ + +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)); + #ifdef RLV_EXTENSION_CMD_GETSETDEBUG_EX + 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)); + #endif // RLV_EXTENSION_CMD_GETSETDEBUG_EX + + // 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()); + return true; + } + } + else if ("env" == strBehaviour) + { + if ( ("get" == strGetSet) && (RLV_TYPE_REPLY == rlvCmd.getParamType()) ) + { + RlvUtil::sendChatReply(rlvCmd.getParam(), onGetEnv(strSetting)); + eRet = RLV_RET_SUCCESS; + return true; + } + else if ( ("set" == strGetSet) && (RLV_TYPE_FORCE == rlvCmd.getParamType()) ) + { + if (!gRlvHandler.hasBehaviourExcept(RLV_BHVR_SETENV, rlvCmd.getObjectID())) + eRet = onSetEnv(strSetting, rlvCmd.getOption()); + 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) : false ); + } + } + 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; +} + +// Checked: 2010-04-18 (RLVa-1.2.0e) | Modified: RLVa-1.2.0e +std::string RlvExtGetSet::onGetEnv(std::string strSetting) +{ + LLWLParamManager* pWLParams = LLWLParamManager::instance(); bool fErr; + WLFloatControl* pFloat = NULL; + WLColorControl* pColour = NULL; + + F32 nValue = 0.0f; + if ("daytime" == strSetting) + { + nValue = (pWLParams->mAnimator.mIsRunning && pWLParams->mAnimator.mUseLindenTime) ? -1.0f : pWLParams->mAnimator.getDayTime(); + } + else if ("preset" == strSetting) + { + return (pWLParams->mAnimator.mIsRunning && pWLParams->mAnimator.mUseLindenTime) ? std::string() : pWLParams->mCurParams.mName; + } + else if ( ("sunglowfocus" == strSetting) || ("sunglowsize" == strSetting) ) + { + pWLParams->mGlow = pWLParams->mCurParams.getVector(pWLParams->mGlow.mName, fErr); + RLV_ASSERT_DBG(!fErr); + + 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; + // Float controls + else if ("cloudcoverage" == strSetting) pFloat = &pWLParams->mCloudCoverage; + else if ("cloudscale" == strSetting) pFloat = &pWLParams->mCloudScale; + else if ("densitymultiplier" == strSetting) pFloat = &pWLParams->mDensityMult; + else if ("distancemultiplier" == strSetting) pFloat = &pWLParams->mDistanceMult; + else if ("maxaltitude" == strSetting) pFloat = &pWLParams->mMaxAlt; + else if ("scenegamma" == strSetting) pFloat = &pWLParams->mWLGamma; + // Colour controls + else if ("hazedensity" == strSetting) pColour = &pWLParams->mHazeDensity; + else if ("hazehorizon" == strSetting) pColour = &pWLParams->mHazeHorizon; + else + { + char ch = strSetting[strSetting.length() - 1]; + // HACK-RLVa: not entirely proper (creates new synonyms) + if ('x' == ch) ch = 'r'; + else if ('y' == ch) ch = 'g'; + else if ('d' == ch) ch = 'b'; + + if ( ('r' == ch) || ('g' == ch) || ('b' == ch) || ('i' == ch) ) + { + strSetting.erase(strSetting.length() - 1, 1); + + if ("ambient" == strSetting) pColour = &pWLParams->mAmbient; + else if ("bluedensity" == strSetting) pColour = &pWLParams->mBlueDensity; + else if ("bluehorizon" == strSetting) pColour = &pWLParams->mBlueHorizon; + else if ("sunmooncolor" == strSetting) pColour = &pWLParams->mSunlight; + else if ("cloudcolor" == strSetting) pColour = &pWLParams->mCloudColor; + else if ("cloud" == strSetting) pColour = &pWLParams->mCloudMain; + else if ("clouddetail" == strSetting) pColour = &pWLParams->mCloudDetail; + + if (pColour) + { + *pColour = pWLParams->mCurParams.getVector(pColour->mName, fErr); + RLV_ASSERT_DBG(!fErr); + + if ('r' == ch) nValue = pColour->r; + else if ('g' == ch) nValue = pColour->g; + else if ('b' == ch) nValue = pColour->b; + else if (('i' == ch) && (pColour->hasSliderName)) nValue = llmax(pColour->r, pColour->g, pColour->b); + + if (pColour->isBlueHorizonOrDensity) nValue /= 2.0f; + else if (pColour->isSunOrAmbientColor) nValue /= 3.0f; + } + } + } + + if (pFloat) + { + *pFloat = pWLParams->mCurParams.getVector(pFloat->mName, fErr); + RLV_ASSERT_DBG(!fErr); + nValue = pFloat->x * pFloat->mult;; + } + else if (pColour) + { + *pColour = pWLParams->mCurParams.getVector(pColour->mName, fErr); + RLV_ASSERT_DBG(!fErr); + nValue = pColour->r; + } + + return llformat("%f", nValue); +} + +// Checked: 2010-04-18 (RLVa-1.2.0e) | Modified: RLVa-1.2.0e +ERlvCmdRet RlvExtGetSet::onSetEnv(std::string strSetting, const std::string& strValue) +{ + LLWLParamManager* pWLParams = LLWLParamManager::instance(); bool fErr; + WLFloatControl* pFloat = NULL; + WLColorControl* pColour = NULL; + + F32 nValue = 0.0f; + // Sanity check - make sure strValue specifies a number for all settings except "preset" + if ( (RlvSettings::getNoSetEnv()) || ( (!LLStringUtil::convertToF32(strValue, nValue)) && ("preset" != strSetting) )) + return RLV_RET_FAILED_OPTION; + + // Not quite correct, but RLV-1.16.0 will halt the default daytime cycle on invalid commands so we need to as well + pWLParams->mAnimator.mIsRunning = false; + pWLParams->mAnimator.mUseLindenTime = false; + + // See LLWorldEnvSettings::handleEvent() + if ("daytime" == strSetting) + { + if (0.0f <= nValue) + { + pWLParams->mAnimator.setDayTime(llmin(nValue, 1.0f)); + pWLParams->mAnimator.update(pWLParams->mCurParams); + } + else + { + pWLParams->mAnimator.mIsRunning = true; + pWLParams->mAnimator.mUseLindenTime = true; + } + return RLV_RET_SUCCESS; + } + // See LLFloaterWindLight::onChangePresetName() + else if ("preset" == strSetting) + { + pWLParams->loadPreset(strValue, true); + return RLV_RET_SUCCESS; + } + // See LLFloaterWindLight::onGlowRMoved() / LLFloaterWindLight::onGlowBMoved() + else if ( ("sunglowfocus" == strSetting) || ("sunglowsize" == strSetting) ) + { + pWLParams->mGlow = pWLParams->mCurParams.getVector(pWLParams->mGlow.mName, fErr); + RLV_ASSERT_DBG(!fErr); + + if ("sunglowfocus" == strSetting) + pWLParams->mGlow.b = -nValue * 5; + else + pWLParams->mGlow.r = (2 - nValue) * 20; + pWLParams->mGlow.update(pWLParams->mCurParams); + + pWLParams->propagateParameters(); + return RLV_RET_SUCCESS; + } + // See LLFloaterWindLight::onStarAlphaMoved + else if ("starbrightness" == strSetting) + { + pWLParams->mCurParams.setStarBrightness(nValue); + return RLV_RET_SUCCESS; + } + // See LLFloaterWindLight::onSunMoved() + else if ( ("eastangle" == strSetting) || ("sunmoonposition" == strSetting) ) + { + if ("eastangle" == strSetting) + pWLParams->mCurParams.setEastAngle(F_TWO_PI * nValue); + else + pWLParams->mCurParams.setSunAngle(F_TWO_PI * nValue); + + pWLParams->propagateParameters(); + return RLV_RET_SUCCESS; + } + // See LLFloaterWindLight::onCloudScrollXMoved() / LLFloaterWindLight::onCloudScrollYMoved() + else if ("cloudscrollx" == strSetting) + { + pWLParams->mCurParams.setCloudScrollX(nValue + 10.0f); + return RLV_RET_SUCCESS; + } + else if ("cloudscrolly" == strSetting) + { + pWLParams->mCurParams.setCloudScrollY(nValue + 10.0f); + return RLV_RET_SUCCESS; + } + // See LLFloaterWindLight::onFloatControlMoved() + else if ("cloudcoverage" == strSetting) pFloat = &pWLParams->mCloudCoverage; + else if ("cloudscale" == strSetting) pFloat = &pWLParams->mCloudScale; + else if ("densitymultiplier" == strSetting) pFloat = &pWLParams->mDensityMult; + else if ("distancemultiplier" == strSetting) pFloat = &pWLParams->mDistanceMult; + else if ("maxaltitude" == strSetting) pFloat = &pWLParams->mMaxAlt; + else if ("scenegamma" == strSetting) pFloat = &pWLParams->mWLGamma; + // See LLFloaterWindLight::onColorControlRMoved() + else if ("hazedensity" == strSetting) pColour = &pWLParams->mHazeDensity; + else if ("hazehorizon" == strSetting) pColour = &pWLParams->mHazeHorizon; + + if (pFloat) + { + *pFloat = pWLParams->mCurParams.getVector(pFloat->mName, fErr); + RLV_ASSERT_DBG(!fErr); + + pFloat->x = nValue / pFloat->mult; + pFloat->update(pWLParams->mCurParams); + pWLParams->propagateParameters(); + return RLV_RET_SUCCESS; + } + else if (pColour) + { + *pColour = pWLParams->mCurParams.getVector(pColour->mName, fErr); + RLV_ASSERT_DBG(!fErr); + + pColour->r = nValue; + pColour->update(pWLParams->mCurParams); + pWLParams->propagateParameters(); + return RLV_RET_SUCCESS; + } + + // RGBI settings + char ch = strSetting[strSetting.length() - 1]; + if ('x' == ch) ch = 'r'; + else if ('y' == ch) ch = 'g'; + else if ('d' == ch) ch = 'b'; + + if ( ('r' == ch) || ('g' == ch) || ('b' == ch) || ('i' == ch) ) + { + strSetting.erase(strSetting.length() - 1, 1); + + if ("ambient" == strSetting) pColour = &pWLParams->mAmbient; + else if ("bluedensity" == strSetting) pColour = &pWLParams->mBlueDensity; + else if ("bluehorizon" == strSetting) pColour = &pWLParams->mBlueHorizon; + else if ("sunmooncolor" == strSetting) pColour = &pWLParams->mSunlight; + else if ("cloudcolor" == strSetting) pColour = &pWLParams->mCloudColor; + else if ("cloud" == strSetting) pColour = &pWLParams->mCloudMain; + else if ("clouddetail" == strSetting) pColour = &pWLParams->mCloudDetail; + + if (pColour) + { + *pColour = pWLParams->mCurParams.getVector(pColour->mName, fErr); + RLV_ASSERT_DBG(!fErr); + + if (pColour->isBlueHorizonOrDensity) nValue *= 2.0f; + else if (pColour->isSunOrAmbientColor) nValue *= 3.0f; + + if ('i' == ch) // (See: LLFloaterWindLight::onColorControlIMoved) + { + if (!pColour->hasSliderName) + return RLV_RET_FAILED_UNKNOWN; + + F32 curMax = llmax(pColour->r, pColour->g, pColour->b); + if ( (0.0f == nValue) || (0.0f == curMax) ) + pColour->r = pColour->g = pColour->b = pColour->i = nValue; + else + { + F32 nDelta = (nValue - curMax) / curMax; + pColour->r *= (1.0f + nDelta); + pColour->g *= (1.0f + nDelta); + pColour->b *= (1.0f + nDelta); + pColour->i = nValue; + } + } + else // (See: LLFloaterWindLight::onColorControlRMoved) + { + F32* pnValue = ('r' == ch) ? &pColour->r : ('g' == ch) ? &pColour->g : ('b' == ch) ? &pColour->b : NULL; + if (pnValue) + *pnValue = nValue; + pColour->i = llmax(pColour->r, pColour->g, pColour->b); + } + + pColour->update(pWLParams->mCurParams); + pWLParams->propagateParameters(); + + return RLV_RET_SUCCESS; + } + } + return RLV_RET_FAILED_UNKNOWN; +} + +// ============================================================================ diff --git a/indra/newview/rlvextensions.h b/indra/newview/rlvextensions.h new file mode 100644 index 0000000000000000000000000000000000000000..ed6bfc4928ae6fba54ecab51dad7fd2cb9d16658 --- /dev/null +++ b/indra/newview/rlvextensions.h @@ -0,0 +1,60 @@ +/** + * + * Copyright (c) 2009-2010, 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 RlvCommandHandler +{ +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); + + std::string onGetEnv(std::string strSetting); + ERlvCmdRet onSetEnv(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..16b8b857cdcd617d926e9be26de635fe1f247677 --- /dev/null +++ b/indra/newview/rlvfloaters.cpp @@ -0,0 +1,280 @@ +/** + * + * Copyright (c) 2009-2010, 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 "llscrolllistctrl.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: 2010-03-11 (RLVa-1.2.0a) | Modified: RLVa-1.2.0g +std::string rlvGetItemNameFromObjID(const LLUUID& idObj, bool fIncludeAttachPt = true) +{ + const LLViewerObject* pObj = gObjectList.findObject(idObj); + const LLViewerObject* pObjRoot = (pObj) ? pObj->getRootEdit() : NULL; + const LLViewerInventoryItem* pItem = ((pObjRoot) && (pObjRoot->isAttachment())) ? gInventory.getItem(pObjRoot->getAttachmentItemID()) : NULL; + + 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); + std::string strAttachPtName = (pAttachPt) ? pAttachPt->getName() : std::string("Unknown"); + return llformat("%s (%s, %s)", strItemName.c_str(), strAttachPtName.c_str(), (pObj == pObjRoot) ? "root" : "child"); +} + +// ============================================================================ +// RlvFloaterLocks member functions +// + +// Checked: 2010-04-18 (RLVa-1.2.0e) | Modified: RLVa-1.2.0e +void RlvFloaterBehaviours::onOpen(const LLSD& sdKey) +{ + m_ConnRlvCommand = gRlvHandler.setCommandCallback(boost::bind(&RlvFloaterBehaviours::onRlvCommand, this, _1, _2)); + + refreshAll(); +} + +// Checked: 2010-04-18 (RLVa-1.2.0e) | Modified: RLVa-1.2.0e +void RlvFloaterBehaviours::onClose(bool fQuitting) +{ + m_ConnRlvCommand.disconnect(); + + // LLFloaterPay::~LLFloaterPay(): Name callbacks will be automatically disconnected since LLFloater is trackable <- how does that work? +} + +// Checked: 2010-04-18 (RLVa-1.2.0e) | Modified: RLVa-1.2.0e +void RlvFloaterBehaviours::onRlvCommand(const RlvCommand& rlvCmd, ERlvCmdRet eRet) +{ + // Refresh on any successful @XXX=y|n command + if ( (RLV_RET_SUCCESS == eRet) && ((RLV_TYPE_ADD == rlvCmd.getParamType()) || (RLV_TYPE_REMOVE == rlvCmd.getParamType())) ) + { + refreshAll(); + } +} + +// Checked: 2010-04-18 (RLVa-1.2.0e) | Modified: RLVa-1.2.0e +void RlvFloaterBehaviours::refreshAll() +{ + LLCtrlListInterface* pBhvrList = childGetListInterface("behaviour_list"); + if (!pBhvrList) + return; + pBhvrList->operateOnAll(LLCtrlListInterface::OP_DELETE); + + if (!isAgentAvatarValid()) + return; + + // + // Set-up a row we can just reuse + // + LLSD sdRow; + LLSD& sdColumns = sdRow["columns"]; + sdColumns[0]["column"] = "behaviour"; sdColumns[0]["type"] = "text"; + sdColumns[1]["column"] = "name"; sdColumns[1]["type"] = "text"; + + // + // List behaviours + // + const RlvHandler::rlv_object_map_t* pRlvObjects = gRlvHandler.getObjectMap(); + for (RlvHandler::rlv_object_map_t::const_iterator itObj = pRlvObjects->begin(), endObj = pRlvObjects->end(); itObj != endObj; ++itObj) + { + sdColumns[1]["value"] = 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 strBhvr = itCmd->asString(); + + LLUUID idOption(itCmd->getOption()); + if (idOption.notNull()) + { + std::string strLookup; + if ( (gCacheName->getFullName(idOption, strLookup)) || (gCacheName->getGroupName(idOption, strLookup)) ) + { + if (strLookup.find("???") == std::string::npos) + strBhvr.assign(itCmd->getBehaviour()).append(":").append(strLookup); + } + else if (m_PendingLookup.end() == std::find(m_PendingLookup.begin(), m_PendingLookup.end(), idOption)) + { + gCacheName->get(idOption, FALSE, boost::bind(&RlvFloaterBehaviours::onAvatarNameLookup, this, _1, _2, _3, _4)); + m_PendingLookup.push_back(idOption); + } + } + + sdColumns[0]["value"] = strBhvr; + + pBhvrList->addElement(sdRow, ADD_BOTTOM); + } + } +} + +// Checked: 2010-04-18 (RLVa-1.2.0e) | Modified: RLVa-1.2.0e +void RlvFloaterBehaviours::onAvatarNameLookup(const LLUUID& idAgent, const std::string& strFirst, const std::string& strLast, BOOL fGroup) +{ + std::list<LLUUID>::iterator itLookup = std::find(m_PendingLookup.begin(), m_PendingLookup.end(), idAgent); + if (itLookup != m_PendingLookup.end()) + m_PendingLookup.erase(itLookup); + + if (getVisible()) + refreshAll(); +} + +// ============================================================================ +// RlvFloaterLocks member functions +// + +// Checked: 2010-03-11 (RLVa-1.2.0a) | Added: RLVa-1.2.0a +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.0a) | Added: RLVa-1.2.0a +void RlvFloaterLocks::onClose(bool fQuitting) +{ + m_ConnRlvCommand.disconnect(); +} + +// 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.0a) | Added: RLVa-1.2.0a +void RlvFloaterLocks::refreshAll() +{ + LLCtrlListInterface* pLockList = childGetListInterface("lock_list"); + if (!pLockList) + return; + 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); + } +} + +// ============================================================================ diff --git a/indra/newview/rlvfloaters.h b/indra/newview/rlvfloaters.h new file mode 100644 index 0000000000000000000000000000000000000000..dbb1fa321275266ba9a1b48db51950447462047a --- /dev/null +++ b/indra/newview/rlvfloaters.h @@ -0,0 +1,101 @@ +/** + * + * Copyright (c) 2009-2010, 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" + +// ============================================================================ +// 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); + + /* + * Event handlers + */ +protected: + void onRlvCommand(const RlvCommand& rlvCmd, ERlvCmdRet eRet); + void onAvatarNameLookup(const LLUUID& idAgent, const std::string& strFirst, const std::string& strLast, BOOL fGroup); + + /* + * Member functions + */ +protected: + void refreshAll(); + + /* + * Member variables + */ +protected: + boost::signals2::connection m_ConnRlvCommand; + std::list<LLUUID> 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); + + /* + * Event handlers + */ +protected: + void onRlvCommand(const RlvCommand& rlvCmd, ERlvCmdRet eRet); + + /* + * Member functions + */ +protected: + void refreshAll(); + + /* + * Member variables + */ +protected: + boost::signals2::connection m_ConnRlvCommand; +}; + +// ============================================================================ + +#endif // RLV_FLOATERS_H \ No newline at end of file diff --git a/indra/newview/rlvhandler.cpp b/indra/newview/rlvhandler.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d19da6c10c9a62ef18167ef3548b4ab3495a701b --- /dev/null +++ b/indra/newview/rlvhandler.cpp @@ -0,0 +1,1946 @@ +/** + * + * Copyright (c) 2009-2010, 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 "llagentwearables.h" +#include "llappviewer.h" +#include "llcallbacklist.h" +#include "llviewermessage.h" +#include "llviewerobjectlist.h" +#include "llviewerparcelmgr.h" +#include "llviewerregion.h" + +#include "rlvhandler.h" +#include "rlvinventory.h" +#include "rlvlocks.h" +#include "rlvui.h" +#include "rlvextensions.h" + +// ============================================================================ +// 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()); +} + +// ============================================================================ +// 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), 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); +} + +// Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.0.1d +RlvHandler::~RlvHandler() +{ + //delete m_pGCTimer; // <- deletes itself + delete m_pWLSnapshot; // <- delete on NULL is harmless +} + +// ============================================================================ +// Behaviour related functions +// + +bool RlvHandler::hasBehaviourExcept(ERlvBehaviour eBehaviour, 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.m_UUID) && (itObj->second.hasBehaviour(eBehaviour, strOption, false)) ) + return true; + return false; +} + +// 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; + + std::list<LLUUID> 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) + std::list<LLUUID>::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; +} + +// ============================================================================ +// Command processing functions +// + +// Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.1.0f +void RlvHandler::addCommandHandler(RlvCommandHandler* 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(RlvCommandHandler* 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<RlvCommandHandler*>::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(rlvCommandHandler f, const RlvCommand& rlvCmd, ERlvCmdRet& eRet, bool fNotifyAll) const +{ + std::list<RlvCommandHandler*>::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) +{ + #ifdef RLV_DEBUG + RLV_INFOS << "[" << rlvCmd.getObjectID() << "]: " << rlvCmd.asString() << RLV_ENDL; + #endif // RLV_DEBUG + + if (!rlvCmd.isValid()) + { + #ifdef RLV_DEBUG + RLV_INFOS << "\t-> invalid syntax" << RLV_ENDL; + #endif // RLV_DEBUG + return RLV_RET_FAILED_SYNTAX; + } + + // Using a stack for executing commands solves a few problems: + // - if we passed RlvObject::m_UUID 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_SETDEBUG == rlvCmd.getBehaviourType()) || (RLV_BHVR_SETENV == rlvCmd.getBehaviourType()) ) ) + { + // Some restrictions can only be held by one single object to avoid deadlocks + #ifdef RLV_DEBUG + RLV_INFOS << "\t- " << rlvCmd.getBehaviour() << " is already set by another object => discarding" << RLV_ENDL; + #endif // RLV_DEBUG + 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); + m_Objects.insert(std::pair<LLUUID, RlvObject>(idCurObj, rlvObj)); + } + + #ifdef RLV_DEBUG + RLV_INFOS << "\t- " << ( (fAdded) ? "adding behaviour" : "skipping duplicate" ) << RLV_ENDL; + #endif // RLV_DEBUG + + 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); +// 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); + + #ifdef RLV_DEBUG + RLV_INFOS << "\t- " << ( (fRemoved) ? "removing behaviour" + : "skipping remove (unset behaviour or unknown object)") << RLV_ENDL; + #endif // RLV_DEBUG + + if (fRemoved) { // Don't handle non-sensical removes + eRet = processAddRemCommand(rlvCmd); +// notifyBehaviourObservers(rlvCmd, !fFromObj); + + if (0 == itObj->second.m_Commands.size()) + { + #ifdef RLV_DEBUG + RLV_INFOS << "\t- command list empty => removing " << idCurObj << RLV_ENDL; + #endif // RLV_DEBUG + 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); + + #ifdef RLV_DEBUG + RLV_INFOS << "\t--> command " << ((eRet & RLV_RET_SUCCESS) ? "succeeded" : "failed") << RLV_ENDL; + #endif // RLV_DEBUG + + m_CurCommandStack.pop(); m_CurObjectStack.pop(); + return eRet; +} + +// 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(&RlvCommandHandler::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 +// + +// Checked: 2010-08-29 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c +void RlvHandler::onSitOrStand(bool fSitting) +{ + #ifdef RLV_EXTENSION_STARTLOCATION + if (rlv_handler_t::isEnabled()) + { + RlvSettings::updateLoginLastLocation(); + } + #endif // RLV_EXTENSION_STARTLOCATION + + if ( (hasBehaviour(RLV_BHVR_STANDTP)) && (!fSitting) && (!m_posSitSource.isExactlyZero()) ) + { + 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.m_UUID); + } + } + } + + // 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.m_UUID); + } + } + } + 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.m_UUID, "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 + + const LLViewerObject* pObj = gObjectList.findObject(itCurObj->second.m_UUID); + 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.m_UUID); + } + } + } + + 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() +{ + RlvAttachPtLookup::initLookupTable(); + + RlvInventory::instance().fetchWornItems(); + RlvInventory::instance().fetchSharedInventory(); + + #ifdef RLV_EXTENSION_STARTLOCATION + RlvSettings::updateLoginLastLocation(); + #endif // RLV_EXTENSION_STARTLOCATION + + 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 +// + +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 +void RlvHandler::filterChat(std::string& strUTF8Text, bool fFilterEmote) const +{ + if (strUTF8Text.empty()) + return; + + 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) ) + { + strUTF8Text = "..."; // 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 '/' + { + if (utf8str_strlen(strUTF8Text) > 7) // Allow as long if it's 6 characters or less + strUTF8Text = "..."; + } + else if ((strUTF8Text.length() < 4) || (strUTF8Text.compare(0, 2, "((")) || (strUTF8Text.compare(strUTF8Text.length() - 2, 2, "))"))) + { + strUTF8Text = "..."; // Regular chat (not OOC) + } +} + +// 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 (!hasBehaviour(eBhvr)) + return false; + + if (RLV_BHVR_REDIRCHAT == eBhvr) + { + std::string strText = strUTF8Text; + filterChat(strText, false); + if (strText != "...") + 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 ( (!hasBehaviour(RLV_BHVR_SENDCHANNEL)) || (isException(RLV_BHVR_SENDCHANNEL, 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::getVersion() << RLV_ENDL; + m_fEnabled = TRUE; + + // Initialize the command lookup table + RlvCommand::initLookupTable(); + + // 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(); + } + + 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; + delete m_pWLSnapshot; + m_pWLSnapshot = 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) + ERlvBehaviour eBhvr = rlvCmd.getBehaviourType(); ERlvParamType eType = rlvCmd.getParamType(); + + ERlvCmdRet eRet = RLV_RET_SUCCESS; bool fRefCount = false; const std::string& strOption = rlvCmd.getOption(); + switch (eBhvr) + { + case RLV_BHVR_DETACH: // @detach[:<option>]=n|y + eRet = onAddRemDetach(rlvCmd, fRefCount); + break; + case RLV_BHVR_ADDATTACH: // @addattach[:<option>]=n|y + case RLV_BHVR_REMATTACH: // @addattach[:<option>]=n|y + eRet = onAddRemAttach(rlvCmd, fRefCount); + break; + case RLV_BHVR_SETENV: // @setenv=n|y + eRet = onAddRemSetEnv(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(rlvCmd.getOption()); + VERIFY_OPTION_REF( (rlvCmdOption.isEmpty()) || (rlvCmdOption.isWearableType()) ); + + 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_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_SENDCHANNEL: // @sendchannel[:<channel>]=n|y - Checked: 2010-03-26 (RLVa-1.2.0b) | Modified: RLVa-1.1.0h + { + // If there's an option then it should be a valid (= positive and non-zero) chat channel + S32 nChannel = 0; + if ( (LLStringUtil::convertToS32(strOption, nChannel)) && (nChannel > 0) ) + { + if (RLV_TYPE_ADD == eType) + addException(rlvCmd.getObjectID(), eBhvr, nChannel); + else + removeException(rlvCmd.getObjectID(), eBhvr, nChannel); + break; + } + VERIFY_OPTION_REF(strOption.empty()); + } + 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; + case RLV_BHVR_SHOWHOVERTEXT: // @showhovertext:<uuid>=n|y - Checked: 2010-03-27 (RLVa-1.2.0b) | Modified: RLVa-1.1.0h + { + // There should be an option and it should specify a valid UUID + LLUUID idException(strOption); + VERIFY_OPTION_REF(idException.notNull()); + + if (RLV_TYPE_ADD == eType) + addException(rlvCmd.getObjectID(), eBhvr, idException); + else + removeException(rlvCmd.getObjectID(), eBhvr, 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->setStringUTF8( (RLV_TYPE_ADD == eType) ? "" : pObj->mText->getObjectText()); + } + break; +#ifdef RLV_EXTENSION_CMD_TOUCHXXX + case RLV_BHVR_TOUCH: // @touch:<uuid>=n - Checked: 2010-01-01 (RLVa-1.1.0l) | Added: RLVa-1.1.0l + { + // There should be an option and it should specify a valid UUID + LLUUID idException(strOption); + VERIFY_OPTION_REF(idException.notNull()); + + if (RLV_TYPE_ADD == eType) + addException(rlvCmd.getObjectID(), eBhvr, idException); + else + removeException(rlvCmd.getObjectID(), eBhvr, idException); + } + break; +#endif // RLV_EXTENSION_CMD_TOUCHXXX + // The following block is only valid if there's no option + case RLV_BHVR_SHOWLOC: // @showloc=n|y - Checked: 2009-12-05 (RLVa-1.1.0h) | Modified: RLVa-1.1.0h + case RLV_BHVR_SHOWNAMES: // @shownames=n|y - Checked: 2009-12-05 (RLVa-1.1.0h) | Modified: RLVa-1.1.0h + case RLV_BHVR_EMOTE: // @emote=n|y - Checked: 2010-03-26 (RLVa-1.2.0b) + case RLV_BHVR_SENDCHAT: // @sendchat=n|y - Checked: 2010-03-26 (RLVa-1.2.0b) + case RLV_BHVR_CHATWHISPER: // @chatwhisper=n|y - Checked: 2010-03-26 (RLVa-1.2.0b) + case RLV_BHVR_CHATNORMAL: // @chatnormal=n|y - Checked: 2010-03-26 (RLVa-1.2.0b) + case RLV_BHVR_CHATSHOUT: // @chatshout=n|y - Checked: 2010-03-26 (RLVa-1.2.0b) + case RLV_BHVR_PERMISSIVE: // @permissive=n|y - Checked: 2009-12-05 (RLVa-1.1.0h) | Modified: RLVa-1.1.0h + case RLV_BHVR_SHOWINV: // @showinv=n|y - Checked: 2010-03-01 (RLVa-1.2.0a) + case RLV_BHVR_SHOWMINIMAP: // @showminimap=n|y - Checked: 2010-02-28 (RLVa-1.2.0a) + case RLV_BHVR_SHOWWORLDMAP: // @showworldmap=n|y - Checked: 2010-02-28 (RLVa-1.2.0a) + case RLV_BHVR_SHOWHOVERTEXTHUD: // @showhovertexthud=n|y - Checked: 2010-03-27 (RLVa-1.2.0b) + case RLV_BHVR_SHOWHOVERTEXTWORLD: // @showhovertextworld=n|y - Checked: 2010-03-27 (RLVa-1.2.0b) + case RLV_BHVR_SHOWHOVERTEXTALL: // @showhovertextall=n|y - Checked: 2010-03-27 (RLVa-1.2.0b) + case RLV_BHVR_STANDTP: // @standtp=n|y - Checked: 2010-08-29 (RLVa-1.2.1c) + case RLV_BHVR_TPLM: // @tplm=n|y - Checked: 2009-12-05 (RLVa-1.1.0h) | Modified: RLVa-1.1.0h + case RLV_BHVR_TPLOC: // @tploc=n|y - Checked: 2009-12-05 (RLVa-1.1.0h) | Modified: RLVa-1.1.0h + case RLV_BHVR_VIEWNOTE: // @viewnote=n|y - Checked: 2010-03-27 (RLVa-1.2.0b) + case RLV_BHVR_VIEWSCRIPT: // @viewscript=n|y - Checked: 2010-03-27 (RLVa-1.2.0b) + case RLV_BHVR_VIEWTEXTURE: // @viewtexture=n|y - Checked: 2010-03-27 (RLVa-1.2.0b) + case RLV_BHVR_ACCEPTPERMISSION: // @acceptpermission=n|y - Checked: 2009-12-05 (RLVa-1.1.0h) | Modified: RLVa-1.1.0h +#ifdef RLV_EXTENSION_CMD_ALLOWIDLE + case RLV_BHVR_ALLOWIDLE: // @allowidle=n|y - Checked: 2010-05-03 (RLVa-1.2.0g) | Modified: RLVa-1.1.0h +#endif // RLV_EXTENSION_CMD_ALLOWIDLE + case RLV_BHVR_EDIT: // @edit=n|y - Checked: 2009-12-05 (RLVa-1.1.0h) | Modified: RLVa-1.1.0h + case RLV_BHVR_REZ: // @rez=n|y - Checked: 2009-12-05 (RLVa-1.1.0h) | Modified: RLVa-1.1.0h + case RLV_BHVR_FARTOUCH: // @fartouch=n|y - Checked: 2009-12-05 (RLVa-1.1.0h) | Modified: RLVa-1.1.0h +#ifdef RLV_EXTENSION_CMD_INTERACT + case RLV_BHVR_INTERACT: // @interact=n|y - Checked: 2010-01-01 (RLVa-1.1.0l) | Added: RLVa-1.1.0l +#endif // RLV_EXTENSION_CMD_INTERACT + case RLV_BHVR_FLY: // @fly=n|y - Checked: 2010-03-02 (RLVa-1.2.0a) + case RLV_BHVR_UNSIT: // @unsit=n|y - Checked: 2009-12-05 (RLVa-1.1.0h) | Modified: RLVa-1.1.0h + case RLV_BHVR_SIT: // @sit=n|y - Checked: 2009-12-05 (RLVa-1.1.0h) | Modified: RLVa-1.1.0h + case RLV_BHVR_SITTP: // @sittp=n|y - Checked: 2009-12-05 (RLVa-1.1.0h) | Modified: RLVa-1.1.0h + case RLV_BHVR_SETDEBUG: // @setdebug=n|y - Checked: 2009-12-05 (RLVa-1.1.0h) | Modified: RLVa-1.1.0h + VERIFY_OPTION_REF(strOption.empty()); + break; + // The following block is only valid if there's no option (= restriction) or if it specifies a valid UUID (= behaviour exception) + case RLV_BHVR_RECVCHAT: // @recvchat[:<uuid>]=n|y - Checked: 2010-03-26 (RLVa-1.2.0b) + case RLV_BHVR_RECVEMOTE: // @recvemote[:<uuid>]=n|y - Checked: 2010-03-26 (RLVa-1.2.0b) + case RLV_BHVR_SENDIM: // @sendim[:<uuid>]=n|y - Checked: 2009-12-05 (RLVa-1.1.0h) | Modified: RLVa-1.1.0h + case RLV_BHVR_RECVIM: // @recvim[:<uuid>]=n|y - Checked: 2009-12-05 (RLVa-1.1.0h) | Modified: RLVa-1.1.0h + case RLV_BHVR_TPLURE: // @tplure[:<uuid>]=n|y - Checked: 2009-12-05 (RLVa-1.1.0h) | Modified: RLVa-1.1.0h + case RLV_BHVR_ACCEPTTP: // @accepttp[:<uuid>]=n|y - Checked: 2009-12-05 (RLVa-1.1.0h) | Modified: RLVa-1.1.0h +#ifdef RLV_EXTENSION_CMD_TOUCHXXX + case RLV_BHVR_TOUCHWORLD: // @touchworld[:<uuid>=n|y - Checked: 2010-01-01 (RLVa-1.1.0l) | Added: RLVa-1.1.0l + case RLV_BHVR_TOUCHATTACH: // @touchattach[:<uuid>=n|y - Checked: 2010-01-01 (RLVa-1.1.0l) | Added: RLVa-1.1.0l + case RLV_BHVR_TOUCHHUD: // @touchhud[:<uuid>=n|y - Checked: 2010-01-01 (RLVa-1.1.0l) | Added: RLVa-1.1.0l +#endif // RLV_EXTENSION_CMD_TOUCHXXX + { + LLUUID idException(strOption); + if (idException.notNull()) // If there's an option then it should specify a valid UUID + { + if (RLV_TYPE_ADD == eType) + addException(rlvCmd.getObjectID(), eBhvr, idException); + else + removeException(rlvCmd.getObjectID(), eBhvr, idException); + break; + } + VERIFY_OPTION_REF(strOption.empty()); + } + break; + case RLV_BHVR_UNKNOWN: + // Pass unknown commands on to registered command handlers + return (notifyCommandHandlers(&RlvCommandHandler::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]++; + } + else + { + if (rlvCmd.isStrict()) + removeException(rlvCmd.getObjectID(), RLV_BHVR_PERMISSIVE, eBhvr); + m_Behaviours[eBhvr]--; + } + + m_OnBehaviour(eBhvr, eType); + + // Show an - optional - notification on every global behaviour change + #ifdef RLV_EXTENSION_NOTIFY_BEHAVIOUR +/* + if ( ((RLV_TYPE_ADD == eType) && (1 == m_Behaviours[eBhvr])) || (0 == m_Behaviours[eBhvr]) ) + { + RlvNotifications::notifyBehaviour(eBhvr, eType); + } +*/ + #endif // RLV_EXTENSION_NOTIFY_BEHAVIOUR + } + + return eRet; +} + +// Checked: 2010-03-03 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a +ERlvCmdRet RlvHandler::onAddRemAttach(const RlvCommand& rlvCmd, bool& fRefCount) +{ + RLV_ASSERT( (RLV_TYPE_ADD == rlvCmd.getParamType()) || (RLV_TYPE_REMOVE == rlvCmd.getParamType()) ); + RLV_ASSERT( (RLV_BHVR_ADDATTACH == rlvCmd.getBehaviourType()) || (RLV_BHVR_REMATTACH == rlvCmd.getBehaviourType()) ); + + // 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; + + 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; +} + +// Checked: 2010-02-28 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a +ERlvCmdRet RlvHandler::onAddRemDetach(const RlvCommand& rlvCmd, bool& fRefCount) +{ + RLV_ASSERT( (RLV_TYPE_ADD == rlvCmd.getParamType()) || (RLV_TYPE_REMOVE == rlvCmd.getParamType()) ); + RLV_ASSERT(RLV_BHVR_DETACH == rlvCmd.getBehaviourType()); + + 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 + rlv_object_map_t::const_iterator itObj = m_Objects.find(rlvCmd.getObjectID()); + if ( (itObj != m_Objects.end()) && (itObj->second.m_fLookup) && (itObj->second.m_idxAttachPt) ) + { + if (RLV_TYPE_ADD == rlvCmd.getParamType()) + gRlvAttachmentLocks.addAttachmentLock(itObj->second.m_idRoot, itObj->first); + else + gRlvAttachmentLocks.removeAttachmentLock(itObj->second.m_idRoot, 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-03-18 (RLVa-1.2.0e) | Modified: RLVa-1.2.0a +ERlvCmdRet RlvHandler::onAddRemSetEnv(const RlvCommand& rlvCmd, bool& fRefCount) +{ + // Sanity check - there shouldn't be an option + if (!rlvCmd.getOption().empty()) + return RLV_RET_FAILED_OPTION; + if (RlvSettings::getNoSetEnv()) + return RLV_RET_FAILED_DISABLED; + + if (RLV_TYPE_ADD == rlvCmd.getParamType()) + { + // Save the current WindLight params so we can restore them on @setenv=y + RLV_ASSERT(!m_pWLSnapshot); + if (m_pWLSnapshot) + delete m_pWLSnapshot; + m_pWLSnapshot = RlvWLSnapshot::takeSnapshot(); + } + else + { + // Restore WindLight parameters to what they were before @setenv=n was issued + RlvWLSnapshot::restoreSnapshot(m_pWLSnapshot); + delete m_pWLSnapshot; + m_pWLSnapshot = NULL; + } + fRefCount = true; + + return RLV_RET_SUCCESS; +} + +// ============================================================================ +// Command handlers (RLV_TYPE_FORCE) +// + +// 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()); + + ERlvCmdRet eRet = RLV_RET_SUCCESS; + switch (rlvCmd.getBehaviourType()) + { + case RLV_BHVR_DETACH: // @detach[:<option>]=force - Checked: 2010-08-30 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c + { + RlvCommandOptionGeneric rlvCmdOption(rlvCmd.getOption()); + if (rlvCmdOption.isSharedFolder()) + eRet = onForceWear(rlvCmdOption.getSharedFolder(), rlvCmd.getBehaviourType()); + else + eRet = onForceRemAttach(rlvCmd); + } + break; + case RLV_BHVR_REMATTACH: // @remattach[:<option>]=force + eRet = onForceRemAttach(rlvCmd); + break; + case RLV_BHVR_REMOUTFIT: // @remoutfit[:<option>]=force + eRet = onForceRemOutfit(rlvCmd); + break; + 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_SIT: // @sit:<option>=force + eRet = onForceSit(rlvCmd); + break; + case RLV_BHVR_TPTO: // @tpto:<option>=force - Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.0.0h + { + eRet = RLV_RET_FAILED_OPTION; + if ( (!rlvCmd.getOption().empty()) && (std::string::npos == rlvCmd.getOption().find_first_not_of("0123456789/.")) ) + { + LLVector3d posGlobal; + + boost_tokenizer tokens(rlvCmd.getOption(), boost::char_separator<char>("/", "", boost::keep_empty_tokens)); int idx = 0; + for (boost_tokenizer::const_iterator itToken = tokens.begin(); itToken != tokens.end(); ++itToken) + { + if (idx < 3) + LLStringUtil::convertToF64(*itToken, posGlobal[idx++]); + } + + if (idx == 3) + { + gAgent.teleportViaLocation(posGlobal); + eRet = RLV_RET_SUCCESS; + } + } + } + break; + case RLV_BHVR_ATTACH: + case RLV_BHVR_ATTACHOVER: + case RLV_BHVR_ATTACHALL: + case RLV_BHVR_ATTACHALLOVER: + case RLV_BHVR_DETACHALL: + { + RlvCommandOptionGeneric rlvCmdOption(rlvCmd.getOption()); + VERIFY_OPTION(rlvCmdOption.isSharedFolder()); + + eRet = onForceWear(rlvCmdOption.getSharedFolder(), rlvCmd.getBehaviourType()); + } + break; + case RLV_BHVR_ATTACHTHIS: + case RLV_BHVR_ATTACHTHISOVER: + case RLV_BHVR_DETACHTHIS: + case RLV_BHVR_ATTACHALLTHIS: + case RLV_BHVR_ATTACHALLTHISOVER: + case RLV_BHVR_DETACHALLTHIS: + { + RlvCommandOptionGetPath rlvGetPathOption(rlvCmd); + VERIFY_OPTION(rlvGetPathOption.isValid()); + + LLInventoryModel::cat_array_t folders; + if (RlvInventory::instance().getPath(rlvGetPathOption.getItemIDs(), folders)) + { + for (S32 idxFolder = 0, cntFolder = folders.count(); idxFolder < cntFolder; idxFolder++) + onForceWear(folders.get(idxFolder), rlvCmd.getBehaviourType()); + } + } + break; + case RLV_BHVR_DETACHME: // @detachme=force - Checked: 2010-04-04 (RLVa-1.2.0c) | Modified: RLVa-1.2.0c + { + VERIFY_OPTION(rlvCmd.getOption().empty()); + // NOTE: @detachme should respect locks but shouldn't respect things like nostrip + const LLViewerObject* pAttachObj = gObjectList.findObject(rlvCmd.getObjectID()); + if ( (pAttachObj) && (pAttachObj->isAttachment()) && (!gRlvAttachmentLocks.isLockedAttachment(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()); + gMessageSystem->sendReliable( gAgent.getRegionHost() ); + } + } + break; + case RLV_BHVR_UNKNOWN: + // Pass unknown commands on to registered command handlers + return (notifyCommandHandlers(&RlvCommandHandler::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; +} + +// Checked: 2010-08-29 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c +ERlvCmdRet RlvHandler::onForceRemAttach(const RlvCommand& rlvCmd) const +{ + RLV_ASSERT(RLV_TYPE_FORCE == rlvCmd.getParamType()); + RLV_ASSERT( (RLV_BHVR_REMATTACH == rlvCmd.getBehaviourType()) || (RLV_BHVR_DETACH == rlvCmd.getBehaviourType()) ); + + if (!isAgentAvatarValid()) + return RLV_RET_FAILED; + + RlvCommandOptionGeneric rlvCmdOption(rlvCmd.getOption()); + // @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 (LLVOAvatar::attachment_map_t::const_iterator itAttach = gAgentAvatarp->mAttachmentPoints.begin(); + itAttach != gAgentAvatarp->mAttachmentPoints.end(); ++itAttach) + { + const LLViewerJointAttachment* pAttachPt = itAttach->second; + if ( (pAttachPt) && (pAttachPt->getNumObjects()) && + ((rlvCmdOption.isEmpty()) || (rlvAttachGroupFromIndex(pAttachPt->getGroup()) == rlvCmdOption.getAttachmentPointGroup())) ) + { + RlvForceWear::instance().forceDetach(pAttachPt); + } + } + return RLV_RET_SUCCESS; + } + return RLV_RET_FAILED_OPTION; +} + +// Checked: 2010-08-29 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c +ERlvCmdRet RlvHandler::onForceRemOutfit(const RlvCommand& rlvCmd) const +{ + RlvCommandOptionGeneric rlvCmdOption(rlvCmd.getOption()); + 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; +} + +// Checked: 2010-03-18 (RLVa-1.2.0c) | Modified: RLVa-1.1.0j +ERlvCmdRet RlvHandler::onForceSit(const RlvCommand& rlvCmd) const +{ + 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 (!canSit(pObj)) + return RLV_RET_FAILED_LOCK; + else if ( (hasBehaviour(RLV_BHVR_STANDTP)) && (isAgentAvatarValid()) ) + { + if (gAgentAvatarp->isSitting()) + return RLV_RET_FAILED_LOCK; + m_posSitSource = gAgent.getPositionGlobal(); + } + + // Copy/paste from handle_sit_or_stand() [see http://wiki.secondlife.com/wiki/AgentRequestSit] + 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); + // Offset: "a rough position in local coordinates for the edge to sit on" + // (we might not even be looking at the object so I don't think we can supply the offset to an edge) + gMessageSystem->addVector3Fast(_PREHASH_Offset, LLVector3::zero); + pObj->getRegion()->sendReliableMessage(); + + return RLV_RET_SUCCESS; +} + +// Checked: 2010-08-30 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c +ERlvCmdRet RlvHandler::onForceWear(const LLViewerInventoryCategory* pFolder, ERlvBehaviour eBhvr) const +{ + if ( (pFolder) && (!RlvInventory::instance().isSharedFolder(pFolder->getUUID())) ) + return RLV_RET_FAILED_OPTION; + + RlvForceWear::EWearAction eAction = RlvForceWear::ACTION_WEAR_REPLACE; + if ( (RLV_BHVR_ATTACHOVER == eBhvr) || (RLV_BHVR_ATTACHTHISOVER == eBhvr) || + (RLV_BHVR_ATTACHALLOVER == eBhvr) || (RLV_BHVR_ATTACHALLTHISOVER == eBhvr) ) + { + eAction = RlvForceWear::ACTION_WEAR_ADD; + } + else if ( (RLV_BHVR_DETACH == eBhvr) || (RLV_BHVR_DETACHTHIS == eBhvr) || + (RLV_BHVR_DETACHALL == eBhvr) || (RLV_BHVR_DETACHALLTHIS == eBhvr) ) + { + eAction = RlvForceWear::ACTION_REMOVE; + } + + RlvForceWear::EWearFlags eFlags = RlvForceWear::FLAG_DEFAULT; + if ( (RLV_BHVR_ATTACHALL == eBhvr) || (RLV_BHVR_ATTACHALLOVER == eBhvr) || (RLV_BHVR_DETACHALL == eBhvr) || + (RLV_BHVR_ATTACHALLTHIS == eBhvr) || (RLV_BHVR_ATTACHALLTHISOVER == eBhvr) || (RLV_BHVR_DETACHALLTHIS == eBhvr) ) + { + eFlags = (RlvForceWear::EWearFlags)(eFlags | RlvForceWear::FLAG_MATCHALL); + } + + RlvForceWear::instance().forceFolder(pFolder, eAction, eFlags); + return RLV_RET_SUCCESS; +} + +// ============================================================================ +// Command handlers (RLV_TYPE_REPLY) +// + +// 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()); + + // Sanity check - <param> should specify a - valid - reply channel + S32 nChannel; + if ( (!LLStringUtil::convertToS32(rlvCmd.getParam(), nChannel)) || (!RlvUtil::isValidReplyChannel(nChannel)) ) + return RLV_RET_FAILED_PARAM; + + ERlvCmdRet eRet = RLV_RET_SUCCESS; std::string strReply; + switch (rlvCmd.getBehaviourType()) + { + case RLV_BHVR_VERSION: // @version=<channel> - Checked: 2010-03-27 (RLVa-1.2.0b) + case RLV_BHVR_VERSIONNEW: // @versionnew=<channel> - Checked: 2010-03-27 (RLVa-1.2.0b) | Added: RLVa-1.2.0b + // NOTE: RLV will respond even if there's an option + strReply = RlvStrings::getVersion(RLV_BHVR_VERSION == rlvCmd.getBehaviourType()); + break; + case RLV_BHVR_VERSIONNUM: // @versionnum=<channel> - Checked: 2010-03-27 (RLVa-1.2.0b) | Added: RLVa-1.0.4b + // NOTE: RLV will respond even if there's an option + strReply = RlvStrings::getVersionNum(); + break; + case RLV_BHVR_GETATTACH: // @getattach[:<layer>]=<channel> + eRet = onGetAttach(rlvCmd, strReply); + break; +#ifdef RLV_EXTENSION_CMD_GETXXXNAMES + case RLV_BHVR_GETATTACHNAMES: // @getattachnames[:<grp>]=<channel> + case RLV_BHVR_GETADDATTACHNAMES:// @getaddattachnames[:<grp>]=<channel> + case RLV_BHVR_GETREMATTACHNAMES:// @getremattachnames[:<grp>]=<channel> + eRet = onGetAttachNames(idObj, rlvCmd, strReply); + break; +#endif // RLV_EXTENSION_CMD_GETXXXNAMES + case RLV_BHVR_GETOUTFIT: // @getoutfit[:<layer>]=<channel> + eRet = onGetOutfit(rlvCmd, strReply); + break; +#ifdef RLV_EXTENSION_CMD_GETXXXNAMES + case RLV_BHVR_GETOUTFITNAMES: // @getoutfitnames=<channel> + case RLV_BHVR_GETADDOUTFITNAMES:// @getaddoutfitnames=<channel> + case RLV_BHVR_GETREMOUTFITNAMES:// @getremoutfitnames=<channel> + eRet = onGetOutfitNames(idObj, rlvCmd, strReply); + break; +#endif // RLV_EXTENSION_CMD_GETXXXNAMES + case RLV_BHVR_FINDFOLDER: // @findfolder:<criteria>=<channel> +#ifdef RLV_EXTENSION_CMD_FINDFOLDERS + case RLV_BHVR_FINDFOLDERS: // @findfolders:<criteria>=<channel> +#endif // RLV_EXTENSION_CMD_FINDFOLDERS + 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_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[:<option>]=<channel> - Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.1.0f + { + // 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(rlvCmd.getOption()); + } + break; + case RLV_BHVR_GETSTATUSALL: // @getstatusall[:<option>]=<channel> - Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.1.0f + { + // 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(rlvCmd.getOption()); + } + break; + case RLV_BHVR_UNKNOWN: + // Pass unknown commands on to registered command handlers + return (notifyCommandHandlers(&RlvCommandHandler::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 + RlvUtil::sendChatReply(nChannel, 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.count(); idxFolder < cntFolder; idxFolder++) + { + strFolderName = RlvInventory::instance().getSharedPath(folders.get(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.count(); idxFolder < cntFolder; idxFolder++) + { + if (!strReply.empty()) + strReply.push_back(','); + strReply += RlvInventory::instance().getSharedPath(folders.get(idxFolder)); + } + } + } + return RLV_RET_SUCCESS; +} + +// Checked: 2010-03-19 (RLVa-1.2.0c) | 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 = RlvAttachPtLookup::getAttachPointIndex(rlvCmd.getOption()); + if ( (idxAttachPt == 0) && (!rlvCmd.getOption().empty()) ) + 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()) && + ( (!RlvSettings::getHideLockedAttach()) || (RlvForceWear::isForceDetachable(pAttachPt, true, rlvCmd.getObjectID())) ); + strReply.push_back( (fWorn) ? '1' : '0' ); + } + } + return RLV_RET_SUCCESS; +} + +// Checked: 2010-03-19 (RLVa-1.2.0a) | Added: RLVa-1.1.0e +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 (locked or unlocked) + fAdd = (pAttachPt->getNumObjects()); + break; +/* + case RLV_BHVR_GETADDATTACHNAMES: // Every attachment point that can be worn on (but ignore any locks set by the issuer) + fAdd = (!isLockedAttachmentExcept(itAttach->first, RLV_LOCK_ADD, gObjectList.findObject(idObj))) && + ( (pAttachPt->getObject() == NULL) || + (!isLockedAttachmentExcept(itAttach->first, RLV_LOCK_REMOVE, gObjectList.findObject(idObj))) ); + break; +*/ + case RLV_BHVR_GETREMATTACHNAMES: // Every attachment point that can be detached (but ignore any locks set by the issuer) + fAdd = RlvForceWear::isForceDetachable(pAttachPt, true, rlvCmd.getObjectID()); + break; + default: + break; + } + + if (fAdd) + { + if (!strReply.empty()) + strReply.push_back(','); + strReply.append(pAttachPt->getName()); + } + } + } + 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->count(); 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->get(idxFolder)->getName(); + if ( (!strFolder.empty()) && (RLV_FOLDER_PREFIX_HIDDEN != strFolder[0]) && + (!RlvInventory::isFoldedFolder(pFolders->get(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 and not be hidden + LLViewerInventoryCategory* pFolder = RlvInventory::instance().getSharedFolder(rlvCmd.getOption()); + if ( (!pFolder) || (pFolder->getName().empty()) || (RLV_FOLDER_PREFIX_HIDDEN == pFolder->getName()[0]) ) + 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->getUUID(), true, true); + gInventory.collectDescendentsIf(pFolder->getUUID(), folders, items, FALSE, f); + + 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.count(); idxFolder < cntFolder; idxFolder++) + mapFolders.insert(std::pair<LLUUID, rlv_wear_info>(folders.get(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.count(); idxItem < cntItem; idxItem++) + { + pItem = items.get(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.2.0c) | 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::typeNameToType(rlvCmd.getOption()); + if ( (LLWearableType::WT_INVALID == wtType) && (!rlvCmd.getOption().empty()) ) + 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 + }; + + 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: 2009-11-21 (RLVa-1.1.0f) | Added: RLVa-1.1.0e +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.getOption().empty()) + return RLV_RET_FAILED_OPTION; + + // RELEASE-RLVa: [SL-2.0.0] Needs revisiting/rewriting once 'LLAgentWearables::MAX_WEARABLES_PER_TYPE > 1' + 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's worn + fAdd = (gAgentWearables.getWearableCount(wtType) > 0); + break; +/* + case RLV_BHVR_GETADDOUTFITNAMES: // Every layer that can be worn on (but ignore any locks set by the issuer) + fAdd = (isWearable(wtType)) && ( (gAgent.getWearable(wtType) == NULL) || (isRemovableExcept(wtType, idObj)) ); + break; +*/ + case RLV_BHVR_GETREMOUTFITNAMES: // Every layer that can be removed (but ignore any locks set by the issuer) + fAdd = RlvForceWear::isForceRemovable(wtType); + break; + default: + break; + } + + if (fAdd) + { + if (!strReply.empty()) + strReply.push_back(','); + strReply.append(LLWearableType::getTypeName((LLWearableType::EType)idxType)); + } + } + 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.get(0)); + } + else if (RLV_BHVR_GETPATHNEW == rlvCmd.getBehaviourType()) + { + for (S32 idxFolder = 0, cntFolder = folders.count(); idxFolder < cntFolder; idxFolder++) + { + if (!strReply.empty()) + strReply.push_back(','); + strReply += RlvInventory::instance().getSharedPath(folders.get(idxFolder)); + } + } + } + return RLV_RET_SUCCESS; +} + +// ============================================================================ diff --git a/indra/newview/rlvhandler.h b/indra/newview/rlvhandler.h new file mode 100644 index 0000000000000000000000000000000000000000..306c8ba39e89339745cb58fa975c58ed55099ae5 --- /dev/null +++ b/indra/newview/rlvhandler.h @@ -0,0 +1,356 @@ +/** + * + * Copyright (c) 2009-2010, 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 "llagentconstants.h" +#include "llstartup.h" +#include "llviewerjointattachment.h" +#include "llviewerobject.h" + +#include "rlvcommon.h" +#include "rlvhelper.h" +#include "rlvlocks.h" + +// ============================================================================ + +class RlvHandler +{ +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 TRUE is at least one object contains the specified behaviour (and optional option) + bool hasBehaviour(ERlvBehaviour eBehaviour) const { return (eBehaviour < RLV_BHVR_COUNT) ? (0 != m_Behaviours[eBehaviour]) : false; } + bool hasBehaviour(ERlvBehaviour eBehaviour, const std::string& strOption) const; + // Returns TRUE if at least one object (except the specified one) contains the specified behaviour (and optional option) + bool hasBehaviourExcept(ERlvBehaviour eBehaviour, const LLUUID& idObj) const; + bool hasBehaviourExcept(ERlvBehaviour eBehaviour, const std::string& strOption, const LLUUID& idObj) 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 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 + 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(LLViewerObject* pObj) const; // @showhovertext* command family + bool canSit(LLViewerObject* pObj, const LLVector3& posOffset = LLVector3::zero) const; + bool canStand() const; + bool canTouch(LLViewerObject* pObj, const LLVector3& posOffset = LLVector3::zero) const; // @touch + void 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); } + // 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(RlvCommandHandler* pHandler); + void removeCommandHandler(RlvCommandHandler* pHandler); +protected: + void clearCommandHandlers(); + bool notifyCommandHandlers(rlvCommandHandler f, const RlvCommand& rlvCmd, ERlvCmdRet& eRet, bool fNotifyAll) const; + + // Externally invoked event handlers +public: + 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 onAddRemAttach(const RlvCommand& rlvCmd, bool& fRefCount); + ERlvCmdRet onAddRemDetach(const RlvCommand& rlvCmd, bool& fRefCount); + ERlvCmdRet onAddRemSetEnv(const RlvCommand& rlvCmd, bool& fRefCount); + // Command handlers (RLV_TYPE_FORCE) + ERlvCmdRet processForceCommand(const RlvCommand& rlvCmd) const; + ERlvCmdRet onForceRemAttach(const RlvCommand& rlvCmd) const; + ERlvCmdRet onForceRemOutfit(const RlvCommand& rlvCmd) const; + ERlvCmdRet onForceSit(const RlvCommand& rlvCmd) const; + ERlvCmdRet onForceWear(const LLViewerInventoryCategory* pFolder, ERlvBehaviour eBhvr) 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; + RlvWLSnapshot* m_pWLSnapshot; + + std::stack<const RlvCommand*> m_CurCommandStack;// Convenience (see @tpto) + std::stack<LLUUID> m_CurObjectStack; // Convenience (see @tpto) + + rlv_behaviour_signal_t m_OnBehaviour; + rlv_command_signal_t m_OnCommand; + mutable std::list<RlvCommandHandler*> m_CommandHandlers; + + static BOOL m_fEnabled; // Use setEnabled() to toggle this + + bool m_fCanCancelTp; // @accepttp and @tpto + mutable LLVector3d m_posSitSource; // @standtp (mutable because onForceXXX handles are all declared as const) + + friend class RlvSharedRootFetcher; // Fetcher needs access to m_fFetchComplete + friend class RlvGCTimer; // Timer clear its own point at destruction + + // -------------------------------- + + /* + * 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: 2009-10-04 (RLVa-1.0.4a) | Modified: RLVa-1.0.4a +inline void RlvHandler::addException(const LLUUID& idObj, ERlvBehaviour eBhvr, const RlvExceptionOption& varOption) +{ + m_Exceptions.insert(std::pair<ERlvBehaviour, RlvException>(eBhvr, RlvException(idObj, eBhvr, varOption))); +} + +// Checked: 2010-03-27 (RLVa-1.2.0b) | Modified: RLVa-1.0.0f +inline bool RlvHandler::canShowHoverText(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)) ) ); +} + +// Checked: 2010-03-06 (RLVa-1.2.0c) | Added: RLVa-1.1.0j +inline bool RlvHandler::canSit(LLViewerObject* pObj, const LLVector3& posOffset /*= LLVector3::zero*/) const +{ + // The 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) + // - [regular sit] not @sittp=n or @fartouch=n restricted or if they clicked on a point within 1.5m of the avie's current position + // - [force sit] not @sittp=n restricted by a *different* object than the one that issued the command or the object is within 1.5m + return + ( (pObj) && (LL_PCODE_VOLUME == pObj->getPCode()) ) && + (!hasBehaviour(RLV_BHVR_SIT)) && + ( ((!hasBehaviour(RLV_BHVR_UNSIT)) && (!hasBehaviour(RLV_BHVR_STANDTP))) || + ((isAgentAvatarValid()) && (!gAgentAvatarp->isSitting())) ) && + ( ((NULL == getCurrentCommand() || (RLV_BHVR_SIT != getCurrentCommand()->getBehaviourType())) + ? ((!hasBehaviour(RLV_BHVR_SITTP)) && (!hasBehaviour(RLV_BHVR_FARTOUCH))) // [regular sit] + : (!hasBehaviourExcept(RLV_BHVR_SITTP, getCurrentObject()))) || // [force sit] + (dist_vec_squared(gAgent.getPositionGlobal(), pObj->getPositionGlobal() + LLVector3d(posOffset)) < 1.5f * 1.5f) ); +} + +// Checked: 2010-03-07 (RLVa-1.2.0c) | Added: RLVa-1.2.0a +inline bool RlvHandler::canStand() const +{ + // NOTE: return FALSE only if we're @unsit=n restricted and the avie is currently sitting on something and TRUE for everything else + return (!hasBehaviour(RLV_BHVR_UNSIT)) || ((isAgentAvatarValid()) && (!gAgentAvatarp->isSitting())); +} + +// Checked: 2010-04-11 (RLVa-1.2.0e) | Modified: RLVa-1.1.0l +inline bool RlvHandler::canTouch(LLViewerObject* pObj, const LLVector3& posOffset /*=LLVector3::zero*/) const +{ +#ifdef RLV_EXTENSION_CMD_TOUCHXXX + bool fCanTouch = (pObj) && + ( (!hasBehaviour(RLV_BHVR_TOUCH)) || (!isException(RLV_BHVR_TOUCH, pObj->getRootEdit()->getID(), RLV_CHECK_PERMISSIVE)) ); + + if (fCanTouch) + { + if ( (!pObj->isAttachment()) || (!pObj->permYouOwner()) ) + { + // Rezzed prim or attachment worn by another avie + fCanTouch = + ( (!hasBehaviour(RLV_BHVR_TOUCHWORLD)) || + (isException(RLV_BHVR_TOUCHWORLD, pObj->getRootEdit()->getID(), RLV_CHECK_PERMISSIVE)) ) && + ( (!hasBehaviour(RLV_BHVR_FARTOUCH)) || + (dist_vec_squared(gAgent.getPositionGlobal(), pObj->getPositionGlobal() + LLVector3d(posOffset)) <= 1.5f * 1.5f) ); + } + else if (pObj->isHUDAttachment()) + { + // HUD attachment + fCanTouch = (!hasBehaviour(RLV_BHVR_TOUCHHUD)) || + (isException(RLV_BHVR_TOUCHHUD, pObj->getRootEdit()->getID(), RLV_CHECK_PERMISSIVE)); + } + else + { + // Regular attachment worn by this avie + fCanTouch = + ( (!hasBehaviour(RLV_BHVR_TOUCHATTACH)) || + (isException(RLV_BHVR_TOUCHATTACH, pObj->getRootEdit()->getID(), RLV_CHECK_PERMISSIVE)) ); + } + } + return fCanTouch; +#else + return (pObj) && + ( + ((pObj->isAttachment()) && (pObj->permYouOwner())) || + ( (!hasBehaviour(RLV_BHVR_FARTOUCH)) || + (dist_vec_squared(gAgent.getPositionGlobal(), pObj->getPositionGlobal() + LLVector3d(posOffset)) <= 1.5f * 1.5f) ) + ); +#endif // RLV_EXTENSION_CMD_TOUCHXXX +} + +inline bool RlvHandler::hasBehaviour(ERlvBehaviour eBehaviour, const std::string& strOption) const +{ + return hasBehaviourExcept(eBehaviour, strOption, LLUUID::null); +} + +inline bool RlvHandler::hasBehaviourExcept(ERlvBehaviour eBehaviour, const LLUUID& idObj) const +{ + return hasBehaviourExcept(eBehaviour, std::string(), idObj); +} + +inline bool RlvHandler::isPermissive(ERlvBehaviour eBhvr) const +{ + return (RlvCommand::hasStrictVariant(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 +inline 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; + } + } +} + +// Checked: 2009-11-25 (RLVa-1.1.0f) | Modified: RLVa-1.1.0f +inline 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); +} + +// ============================================================================ + +#endif // RLV_HANDLER_H diff --git a/indra/newview/rlvhelper.cpp b/indra/newview/rlvhelper.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8073e4378476c950f5de292832b5e25ba3fc0b0b --- /dev/null +++ b/indra/newview/rlvhelper.cpp @@ -0,0 +1,1122 @@ +/** + * + * Copyright (c) 2009-2010, 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 "llagentwearables.h" +#include "llappearancemgr.h" +#include "llgesturemgr.h" +#include "llnotifications.h" +#include "llnotificationsutil.h" +#include "llviewerobject.h" +#include "llviewerobjectlist.h" +#include "llwlparammanager.h" + +#include "rlvhelper.h" +#include "rlvhandler.h" +#include "rlvinventory.h" + +// ============================================================================ +// RlvCommmand +// + +RlvCommand::RlvBhvrTable RlvCommand::m_BhvrMap; + +// Checked: 2009-12-27 (RLVa-1.1.0k) | Modified: RLVa-1.1.0k +RlvCommand::RlvCommand(const LLUUID& idObj, const std::string& strCommand) + : m_idObj(idObj), m_eBehaviour(RLV_BHVR_UNKNOWN), m_fStrict(false), m_eParamType(RLV_TYPE_UNKNOWN) +{ + 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_strBehaviour = m_strOption = m_strParam = ""; + return; + } + + // HACK: all those @addoutfit* synonyms are rather tedious (and error-prone) to deal with so replace them their @attach* equivalent + if ( (RLV_TYPE_FORCE == m_eParamType) && (0 == m_strBehaviour.find("addoutfit")) ) + m_strBehaviour.replace(0, 9, "attach"); + m_eBehaviour = getBehaviourFromString(m_strBehaviour, &m_fStrict); +} + + +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; +} + +// Checked: 2009-12-05 (RLVa-1.1.0h) | Added: RLVa-1.1.0h +ERlvBehaviour RlvCommand::getBehaviourFromString(const std::string& strBhvr, bool* pfStrict /*=NULL*/) +{ + std::string::size_type idxStrict = strBhvr.find("_sec"); + bool fStrict = (std::string::npos != idxStrict) && (idxStrict + 4 == strBhvr.length()); + if (pfStrict) + *pfStrict = fStrict; + + RLV_ASSERT(m_BhvrMap.size() > 0); + RlvBhvrTable::const_iterator itBhvr = m_BhvrMap.find( (!fStrict) ? strBhvr : strBhvr.substr(0, idxStrict)); + if ( (itBhvr != m_BhvrMap.end()) && ((!fStrict) || (hasStrictVariant(itBhvr->second))) ) + return itBhvr->second; + return RLV_BHVR_UNKNOWN; +} + +// Checked: 2010-02-27 (RLVa-1.2.0a) | Modified: RLVa-1.1.0h +void RlvCommand::initLookupTable() +{ + static bool fInitialized = false; + if (!fInitialized) + { + // NOTE: keep this matched with the enumeration at all times + std::string arBehaviours[RLV_BHVR_COUNT] = + { + "detach", "attach", "addattach", "remattach", "addoutfit", "remoutfit", "emote", "sendchat", "recvchat", "recvemote", + "redirchat", "rediremote", "chatwhisper", "chatnormal", "chatshout", "sendchannel", "sendim", "recvim", "permissive", + "notify", "showinv", "showminimap", "showworldmap", "showloc", "shownames", "showhovertext", "showhovertexthud", + "showhovertextworld", "showhovertextall", "tplm", "tploc", "tplure", "viewnote", "viewscript", "viewtexture", + "acceptpermission", "accepttp", "allowidle", "edit", "rez", "fartouch", "interact", "touch", "touchattach", "touchhud", + "touchworld", "fly", "unsit", "sit", "sittp", "standtp", "setdebug", "setenv", "detachme", "attachover", "attachthis", + "attachthisover", "detachthis", "attachall", "attachallover", "detachall", "attachallthis", "attachallthisover", + "detachallthis", "tpto", "version", "versionnew", "versionnum", "getattach", "getattachnames", "getaddattachnames", + "getremattachnames", "getoutfit", "getoutfitnames", "getaddoutfitnames", "getremoutfitnames", "findfolder", "findfolders", + "getpath", "getpathnew", "getinv", "getinvworn", "getsitid", "getstatus", "getstatusall" + }; + + for (int idxBvhr = 0; idxBvhr < RLV_BHVR_COUNT; idxBvhr++) + m_BhvrMap.insert(std::pair<std::string, ERlvBehaviour>(arBehaviours[idxBvhr], (ERlvBehaviour)idxBvhr)); + + fInitialized = true; + } +} + +// ============================================================================ +// RlvCommandOption +// + +// Checked: 2010-09-28 (RLVa-1.2.1c) | Added: RLVa-1.2.1c +RlvCommandOptionGeneric::RlvCommandOptionGeneric(const std::string& strOption) +{ + LLWearableType::EType wtType(LLWearableType::WT_INVALID); LLUUID idOption; ERlvAttachGroupType eAttachGroup(RLV_ATTACHGROUP_INVALID); + LLViewerJointAttachment* pAttachPt = NULL; LLViewerInventoryCategory* pFolder = NULL; + + if (!(m_fEmpty = strOption.empty())) // <option> could be an empty string + { + if ((wtType = LLWearableType::typeNameToType(strOption)) != LLWearableType::WT_INVALID) + m_varOption = wtType; // ... or specify a clothing layer + else if ((pAttachPt = RlvAttachPtLookup::getAttachPoint(strOption)) != NULL) + m_varOption = pAttachPt; // ... or specify an attachment point + else if (idOption.set(strOption)) + m_varOption = idOption; // ... or specify an UUID + else if ((pFolder = RlvInventory::instance().getSharedFolder(strOption)) != NULL) + m_varOption = pFolder; // ... or specify a shared folder path + else if ((eAttachGroup = rlvAttachGroupFromString(strOption)) != RLV_ATTACHGROUP_INVALID) + m_varOption = eAttachGroup; // ... or specify an attachment point group + else + m_varOption = strOption; // ... or it might just be a string + } +} + +// Checked: 2010-09-28 (RLVa-1.2.1c) | Added: RLVa-1.2.1c +RlvCommandOptionGetPath::RlvCommandOptionGetPath(const RlvCommand& rlvCmd) + : 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(rlvCmd.getOption()); + if (rlvCmdOption.isWearableType()) // <option> can be a clothing layer + { + LLWearableType::EType wtType = rlvCmdOption.getWearableType(); + for (S32 idxWearable = 0, cntWearable = gAgentWearables.getWearableCount(wtType); idxWearable < cntWearable; idxWearable++) + m_idItems.push_back(gAgentWearables.getWearableItemID(wtType, idxWearable)); + } + else if (rlvCmdOption.isAttachmentPoint()) // ... or it can specify an attachment point + { + const LLViewerJointAttachment* pAttachPt = rlvCmdOption.getAttachmentPoint(); + for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator itAttachObj = pAttachPt->mAttachedObjects.begin(); + itAttachObj != pAttachPt->mAttachedObjects.end(); ++itAttachObj) + { + m_idItems.push_back((*itAttachObj)->getAttachmentItemID()); + } + } + 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) || (pObj->isAttachment()) ) + m_idItems.push_back(pObj->getAttachmentItemID()); + } + else // ... but anything else isn't a valid option + { + m_fValid = false; + } +} + +// ========================================================================= +// RlvObject +// + +RlvObject::RlvObject(const LLUUID& idObj) : m_UUID(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 (rlv_command_list_t::const_iterator itCmd = m_Commands.begin(); itCmd != m_Commands.end(); ++itCmd) + if ( (itCmd->getBehaviourType() == eBehaviour) && (itCmd->getOption() == strOption) && ((!fStrictOnly) || (itCmd->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& strMatch) 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 ( (strMatch.empty()) || (std::string::npos != strCmd.find(strMatch)) ) + { + strStatus.push_back('/'); + strStatus += 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->getUUID(), isWearAction(eAction), (eFlags & FLAG_MATCHALL)); + gInventory.collectDescendentsIf(pFolder->getUUID(), folders, items, FALSE, f); + + for (S32 idxItem = 0, cntItem = items.count(); idxItem < cntItem; idxItem++) + { + LLViewerInventoryItem* pRlvItem = items.get(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; + + // 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 check for whether we're replacing a currently worn composite item happens in onWearableArrived() + if (!isAddWearable(pItem)) + addWearable(pRlvItem, eAction); + } + else + { + const LLWearable* pWearable = gAgentWearables.getWearableFromItemID(pItem->getUUID()); + if ( (pWearable) && (isForceRemovable(pWearable, false)) ) + remWearable(pWearable); + } + break; + + case LLAssetType::AT_OBJECT: + if (isWearAction(eAction)) + { + if ( (gRlvAttachmentLocks.canAttach(pRlvItem)) || (RlvSettings::getEnableSharedWear()) ) + { + 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, eAction); + } + } + } + } + else + { + const LLViewerObject* pAttachObj = gAgentAvatarp->getWornAttachment(pItem->getUUID()); + if ( (pAttachObj) && (isForceDetachable(pAttachObj, false)) ) + remAttachment(pAttachObj); + } + break; + + #ifdef RLV_EXTENSION_FORCEWEAR_GESTURES + 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; + #endif // RLV_EXTENSION_FORCEWEAR_GESTURES + + 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)) ) + #ifdef RLV_EXTENSION_FLAG_NOSTRIP + && (isStrippable(pAttachObj->getAttachmentItemID())) + #endif // RLV_EXTENSION_FLAG_NOSTRIP + #ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS + && ( (!fCheckComposite) || (!RlvSettings::getEnableComposites()) || + (!gRlvHandler.getCompositeInfo(pAttachPt->getItemID(), NULL, &pFolder)) || (gRlvHandler.canTakeOffComposite(pFolder)) ) + #endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS + ); +} + +// Checked: 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 LLWearable* 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) ) + #ifdef RLV_EXTENSION_FLAG_NOSTRIP + && (isStrippable(pWearable->getItemID())) + #endif // RLV_EXTENSION_FLAG_NOSTRIP + #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.getWearable(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 LLWearable* 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.getWearable(wtType, idxWearable)); +} + +#ifdef RLV_EXTENSION_FLAG_NOSTRIP +// 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) && (gInventory.getRootFolderID() != pFolder->getParentUUID()) ) + { + 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 + pFolder = + (RlvInventory::isFoldedFolder(pFolder, true)) ? gInventory.getCategory(pFolder->getParentUUID()) : NULL; + } + } + return true; +} +#endif // RLV_EXTENSION_FLAG_NOSTRIP + +// 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(pAttachObj); +} + +// Checked: 2010-08-30 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c +void RlvForceWear::addWearable(const LLViewerInventoryItem* pItem, EWearAction eAction) +{ + const LLWearable* 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 LLWearable* 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: 2010-03-22 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a +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; + } + + LLAppearanceMgr* pAppearanceMgr = LLAppearanceMgr::getInstance(); + bool fUpdateAppearance = false; + + // + // Process removals + // + + // Wearables + if (m_remWearables.size()) + { + for (std::list<const LLWearable*>::const_iterator itWearable = m_remWearables.begin(); itWearable != m_remWearables.end(); ++itWearable) + pAppearanceMgr->removeCOFItemLinks((*itWearable)->getItemID(), false); + m_remWearables.clear(); + fUpdateAppearance = true; + } + + // Gestures + if (m_remGestures.size()) + { + for (S32 idxItem = 0, cntItem = m_remGestures.count(); idxItem < cntItem; idxItem++) + pAppearanceMgr->removeCOFItemLinks(m_remGestures.get(idxItem)->getUUID(), false); + m_remGestures.clear(); + fUpdateAppearance = true; + } + + // Attachments + if (m_remAttachments.size()) + { + // Don't bother with COF if all we're doing is detaching some attachments (keeps people from rebaking on every @remattach=force) + fUpdateAppearance = (fUpdateAppearance) || (!m_addWearables.empty()) || (!m_addAttachments.empty()) || (!m_addGestures.empty()); + if (!fUpdateAppearance) + { + gMessageSystem->newMessage("ObjectDetach"); + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + + for (std::list<const LLViewerObject*>::const_iterator itAttachObj = m_remAttachments.begin(); + itAttachObj != m_remAttachments.end(); ++itAttachObj) + { + gMessageSystem->nextBlockFast(_PREHASH_ObjectData); + gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, (*itAttachObj)->getLocalID()); + } + + gMessageSystem->sendReliable(gAgent.getRegionHost()); + } + + for (std::list<const LLViewerObject*>::const_iterator itAttachObj = m_remAttachments.begin(); + itAttachObj != m_remAttachments.end(); ++itAttachObj) + { + pAppearanceMgr->removeCOFItemLinks((*itAttachObj)->getAttachmentItemID(), false); + } + + 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.begin(); itAddWearables != m_addWearables.end(); ++itAddWearables) + { + const LLInventoryModel::item_array_t& wearItems = itAddWearables->second; + for (S32 idxItem = 0, cntItem = wearItems.count(); idxItem < cntItem; idxItem++) + { + LLViewerInventoryItem* pItem = wearItems.get(idxItem); + if (!pAppearanceMgr->isLinkInCOF(pItem->getUUID())) // It's important to examine COF here and *not* gAgentWearables + { + 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 + if (m_addAttachments.size()) + { + for (addattachments_map_t::const_iterator itAddAttachments = m_addAttachments.begin(); + itAddAttachments != m_addAttachments.end(); ++itAddAttachments) + { + const LLInventoryModel::item_array_t& wearItems = itAddAttachments->second; + for (S32 idxItem = 0, cntItem = wearItems.count(); idxItem < cntItem; idxItem++) + { + const LLUUID& idItem = wearItems.get(idxItem)->getLinkedUUID(); + if (gAgentAvatarp->attachmentWasRequested(idItem)) + continue; + gAgentAvatarp->addAttachmentRequest(idItem); + + LLSD payload; + payload["item_id"] = idItem; + payload["attachment_point"] = itAddAttachments->first; + LLNotifications::instance().forceResponse(LLNotification::Params("ReplaceAttachment").payload(payload), 0/*YES*/); + } + } + m_addAttachments.clear(); + } + + // If there are additions we need to call LLAppearanceManager::updateCOF(), otherwise LLAppearanceManager::updateAppearanceFromCOF() + if ( (!addBodyParts.empty()) || (!addClothing.empty()) || (!m_addGestures.empty()) ) + { + pAppearanceMgr->updateCOF(addBodyParts, addClothing, LLInventoryModel::item_array_t(), m_addGestures, true); + + m_addGestures.clear(); + } + else if (fUpdateAppearance) + { + pAppearanceMgr->updateAppearanceFromCOF(); + } + + // Since RlvForceWear is a singleton now we want to be sure there aren't any leftovers + 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; + + std::string strCmd = rlvCmd.asString(), strNotify; ERlvParamType eCmdType = rlvCmd.getParamType(); + if ( (RLV_TYPE_ADD == eCmdType) || (RLV_TYPE_REMOVE == eCmdType) ) + strNotify = llformat("/%s=%s", strCmd.c_str(), rlvCmd.getParam().c_str()); + else if (RLV_TYPE_CLEAR == eCmdType) + strNotify = llformat("/%s", strCmd.c_str()); + else + return; + + for (std::multimap<LLUUID, notifyData>::const_iterator itNotify = m_Notifications.begin(); + itNotify != m_Notifications.end(); ++itNotify) + { + if ( (itNotify->second.strFilter.empty()) || (std::string::npos != strCmd.find(itNotify->second.strFilter)) ) + RlvUtil::sendChatReply(itNotify->second.nChannel, strNotify); + } +} + +// ============================================================================ +// RlvWLSnapshot +// + +// Checked: 2010-03-18 (RLVa-1.2.0e) | Added: RLVa-0.2.0h +void RlvWLSnapshot::restoreSnapshot(const RlvWLSnapshot* pWLSnapshot) +{ + LLWLParamManager* pWLParams = LLWLParamManager::instance(); + if ( (pWLSnapshot) && (pWLParams) ) + { + pWLParams->mAnimator.mIsRunning = pWLSnapshot->fIsRunning; + pWLParams->mAnimator.mUseLindenTime = pWLSnapshot->fUseLindenTime; + pWLParams->mCurParams = pWLSnapshot->WLParams; + pWLParams->propagateParameters(); + } +} + +// Checked: 2010-03-18 (RLVa-1.2.0e) | Modified: RLVa-1.2.0e +RlvWLSnapshot* RlvWLSnapshot::takeSnapshot() +{ + RlvWLSnapshot* pWLSnapshot = NULL; + LLWLParamManager* pWLParams = LLWLParamManager::instance(); + if (pWLParams) + { + pWLSnapshot = new RlvWLSnapshot(); + pWLSnapshot->fIsRunning = pWLParams->mAnimator.mIsRunning; + pWLSnapshot->fUseLindenTime = pWLParams->mAnimator.mUseLindenTime; + pWLSnapshot->WLParams = pWLParams->mCurParams; + } + return pWLSnapshot; +} + +// ========================================================================= +// 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 +// + +// Checked: 2010-04-11 (RLVa-1.2.0b) | Modified: RLVa-0.2.0g +bool rlvCanDeleteOrReturn() +{ + bool fIsAllowed = true; + + if (gRlvHandler.hasBehaviour(RLV_BHVR_REZ)) + { + // We'll allow if none of the prims are owned by the avie or group owned + LLObjectSelectionHandle handleSel = LLSelectMgr::getInstance()->getSelection(); + RlvSelectIsOwnedByOrGroupOwned f(gAgent.getID()); + if ( (handleSel.notNull()) && ((0 == handleSel->getRootObjectCount()) || (NULL != handleSel->getFirstRootNode(&f, FALSE))) ) + fIsAllowed = false; + } + + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) && (isAgentAvatarValid()) ) + { + // We'll allow if the avie isn't sitting on any of the selected objects + LLObjectSelectionHandle handleSel = LLSelectMgr::getInstance()->getSelection(); + RlvSelectIsSittingOn f(gAgentAvatarp->getRoot()); + if ( (handleSel.notNull()) && (handleSel->getFirstRootNode(&f, TRUE)) ) + fIsAllowed = false; + } + + return fIsAllowed; +} + +// ============================================================================ +// 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-04 (RLVa-1.0.0a) +void rlvStringReplace(std::string& strText, std::string strFrom, const std::string& strTo) +{ + if (strFrom.empty()) + return; + + size_t lenFrom = strFrom.length(); + size_t lenTo = strTo.length(); + + std::string strTemp(strText); + LLStringUtil::toLower(strTemp); + LLStringUtil::toLower(strFrom); + + std::string::size_type idxCur, idxStart = 0, idxOffset = 0; + while ( (idxCur = strTemp.find(strFrom, idxStart)) != std::string::npos) + { + strText.replace(idxCur + idxOffset, lenFrom, strTo); + idxStart = idxCur + lenFrom; + idxOffset += lenTo - lenFrom; + } +} + +// 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) ) + { + 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..ade4b58b161e00647910a0e7af8e9bbed13c003b --- /dev/null +++ b/indra/newview/rlvhelper.h @@ -0,0 +1,453 @@ +/** + * + * Copyright (c) 2009-2010, 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 "llwlparamset.h" + +#include "rlvdefines.h" +#include "rlvcommon.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 + +// ============================================================================ +// RlvCommand +// + +class RlvCommand +{ +public: + explicit RlvCommand(const LLUUID& idObj, const std::string& strCommand); + + /* + * Member functions + */ +public: + std::string asString() const; + const std::string& getBehaviour() const { return m_strBehaviour; } + ERlvBehaviour getBehaviourType() const { return m_eBehaviour; } + 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 isStrict() const { return m_fStrict; } + bool isValid() const { return m_fValid; } + + static ERlvBehaviour getBehaviourFromString(const std::string& strBhvr, bool* pfStrict = NULL); + static const std::string& getStringFromBehaviour(ERlvBehaviour eBhvr); + static bool hasStrictVariant(ERlvBehaviour eBhvr); + + static void initLookupTable(); +protected: + static bool parseCommand(const std::string& strCommand, std::string& strBehaviour, std::string& strOption, std::string& strParam); + + /* + * Operators + */ +public: + bool operator ==(const RlvCommand&) const; + + /* + * Member variables + */ +protected: + bool m_fValid; + LLUUID m_idObj; + std::string m_strBehaviour; + ERlvBehaviour m_eBehaviour; + bool m_fStrict; + std::string m_strOption; + std::string m_strParam; + ERlvParamType m_eParamType; + + typedef std::map<std::string, ERlvBehaviour> RlvBhvrTable; + static RlvBhvrTable m_BhvrMap; + + friend class RlvHandler; +}; +typedef std::list<RlvCommand> rlv_command_list_t; + +// ============================================================================ +// RlvCommandOption (and derived classed) +// + +class RlvCommandOption +{ +protected: + RlvCommandOption() {} +public: + virtual ~RlvCommandOption() {} + +public: + virtual bool isAttachmentPoint() const { return false; } + virtual bool isAttachmentPointGroup() const { return false; } + virtual bool isEmpty() const = 0; + virtual bool isSharedFolder() const { return false; } + virtual bool isString() const { return false; } + virtual bool isUUID() const { return false; } + virtual bool isValid() const = 0; + virtual bool isWearableType() const { return false; } + + virtual LLViewerJointAttachment* getAttachmentPoint() const { return NULL; } + virtual ERlvAttachGroupType getAttachmentPointGroup() const { return RLV_ATTACHGROUP_INVALID; } + virtual LLViewerInventoryCategory* getSharedFolder() const { return NULL; } + virtual const std::string& getString() const { return LLStringUtil::null; } + virtual const LLUUID& getUUID() const { return LLUUID::null; } + virtual LLWearableType::EType getWearableType() const { return LLWearableType::WT_INVALID; } +}; + +class RlvCommandOptionGeneric : public RlvCommandOption +{ +public: + explicit RlvCommandOptionGeneric(const std::string& strOption); + RlvCommandOptionGeneric(LLViewerJointAttachment* pAttachPt) : m_fEmpty(false) { m_varOption = pAttachPt; } + RlvCommandOptionGeneric(LLViewerInventoryCategory* pFolder) : m_fEmpty(false) { m_varOption = pFolder; } + RlvCommandOptionGeneric(const LLUUID& idOption) : m_fEmpty(false) { m_varOption = idOption; } + RlvCommandOptionGeneric(LLWearableType::EType wtType) : m_fEmpty(false) { m_varOption = wtType; } + /*virtual*/ ~RlvCommandOptionGeneric() {} + +public: + /*virtual*/ bool isAttachmentPoint() const { return typeid(LLViewerJointAttachment*) == m_varOption.type(); } + /*virtual*/ bool isAttachmentPointGroup() const { return typeid(ERlvAttachGroupType) == m_varOption.type(); } + /*virtual*/ bool isEmpty() const { return m_fEmpty; } + /*virtual*/ bool isSharedFolder() const { return typeid(LLViewerInventoryCategory*) == m_varOption.type(); } + /*virtual*/ bool isString() const { return typeid(std::string) == m_varOption.type(); } + /*virtual*/ bool isUUID() const { return typeid(LLUUID) == m_varOption.type(); } + /*virtual*/ bool isValid() const { return true; } // This doesn't really have any significance for the generic class + /*virtual*/ bool isWearableType() const { return typeid(LLWearableType::EType) == m_varOption.type(); } + + /*virtual*/ LLViewerJointAttachment* getAttachmentPoint() const + { return (isAttachmentPoint()) ? boost::get<LLViewerJointAttachment*>(m_varOption) : RlvCommandOption::getAttachmentPoint(); } + /*virtual*/ ERlvAttachGroupType getAttachmentPointGroup() const + { return (isAttachmentPointGroup()) ? boost::get<ERlvAttachGroupType>(m_varOption) : RlvCommandOption::getAttachmentPointGroup(); } + /*virtual*/ LLViewerInventoryCategory* getSharedFolder() const + { return (isSharedFolder()) ? boost::get<LLViewerInventoryCategory*>(m_varOption) : RlvCommandOption::getSharedFolder(); } + /*virtual*/ const std::string& getString() const + { return (isString()) ? boost::get<std::string>(m_varOption) : RlvCommandOption::getString(); } + /*virtual*/ const LLUUID& getUUID() const + { return (isUUID()) ? boost::get<LLUUID>(m_varOption) : RlvCommandOption::getUUID(); } + /*virtual*/ LLWearableType::EType getWearableType() const + { return (isWearableType()) ? boost::get<LLWearableType::EType>(m_varOption) : RlvCommandOption::getWearableType(); } + +protected: + bool m_fEmpty; + boost::variant<LLViewerJointAttachment*, ERlvAttachGroupType, LLViewerInventoryCategory*, std::string, LLUUID, LLWearableType::EType> m_varOption; +}; + +class RlvCommandOptionGetPath : public RlvCommandOption +{ +public: + RlvCommandOptionGetPath(const RlvCommand& rlvCmd); + /*virtual*/ ~RlvCommandOptionGetPath() {} + + /*virtual*/ bool isEmpty() const { return m_idItems.empty(); } + /*virtual*/ bool isValid() const { return m_fValid; } + const uuid_vec_t& getItemIDs() const { return m_idItems; } + +protected: + bool m_fValid; + uuid_vec_t m_idItems; +}; + +// ============================================================================ +// 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& strMatch) const; + bool hasBehaviour(ERlvBehaviour eBehaviour, bool fStrictOnly) const; + bool hasBehaviour(ERlvBehaviour eBehaviour, const std::string& strOption, bool fStrictOnly) const; + + const rlv_command_list_t* getCommandList() const { return &m_Commands; } + + /* + * Member variables + */ +protected: + LLUUID m_UUID; // The object's UUID + S32 m_idxAttachPt; // The object's attachment point (or 0 if it's not an attachment) + LLUUID m_idRoot; // The UUID of the object's root (may or may not be different from m_UUID) + 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 LLWearable* 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 LLWearable* 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 LLWearable* 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 LLWearable* pWearable) const + { + return std::find(m_remWearables.begin(), m_remWearables.end(), pWearable) != m_remWearables.end(); + } + +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::list<const LLViewerObject*> m_remAttachments; + std::list<const LLWearable*> m_remWearables; + LLInventoryModel::item_array_t m_remGestures; + +private: + friend class LLSingleton<RlvForceWear>; +}; + +// ============================================================================ +// RlvBehaviourNotifyObserver +// + +// TODO-RLVa: [RLVa-1.2.1] See about just reintegrating this back into RlvHandler +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 + } +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 +// + +typedef boost::variant<std::string, LLUUID, S32, ERlvBehaviour> RlvExceptionOption; + +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(); +}; + +// ============================================================================ +// RlvWLSnapshot +// + +struct RlvWLSnapshot +{ +public: + static void restoreSnapshot(const RlvWLSnapshot* pWLSnapshot); + static RlvWLSnapshot* takeSnapshot(); +private: + RlvWLSnapshot() {} + + bool fIsRunning; + bool fUseLindenTime; + LLWLParamSet WLParams; +}; + +// ============================================================================ +// Various helper classes/timers/functors +// + +class RlvGCTimer : public LLEventTimer +{ +public: + RlvGCTimer() : LLEventTimer(30.0) {} + virtual BOOL tick(); +}; + +// ============================================================================ +// Various helper functions +// + +bool rlvCanDeleteOrReturn(); + +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); +void rlvStringReplace(std::string& strText, std::string strFrom, const std::string& strTo); + +// ============================================================================ +// Inlined class member functions +// + +// 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(m_strBehaviour)).append(":").append(m_strOption) : (std::string(m_strBehaviour)) + : (!m_strParam.empty()) ? (std::string(m_strBehaviour)).append(":").append(m_strParam) : (std::string(m_strBehaviour)); +} + +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 (m_strBehaviour == rhs.m_strBehaviour) && (m_strOption == rhs.m_strOption) && + ( (RLV_TYPE_UNKNOWN != m_eParamType) ? (m_eParamType == rhs.m_eParamType) : (m_strParam == rhs.m_strParam) ); +} + +inline bool RlvCommand::hasStrictVariant(ERlvBehaviour eBhvr) +{ + switch (eBhvr) + { + case RLV_BHVR_RECVCHAT: + case RLV_BHVR_RECVEMOTE: + case RLV_BHVR_RECVIM: + case RLV_BHVR_SENDIM: + case RLV_BHVR_TPLURE: + case RLV_BHVR_SENDCHANNEL: + return true; + default: + return false; + } +} + +// Checked: 2010-04-05 (RLVa-1.2.0d) | Modified: RLVa-1.2.0d +inline bool RlvForceWear::isWearableItem(const LLInventoryItem* pItem) +{ + LLAssetType::EType assetType = pItem->getType(); + 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..b2a29e4c116f9689a41e0e9258d1be03e6a24ca0 --- /dev/null +++ b/indra/newview/rlvinventory.cpp @@ -0,0 +1,654 @@ +/** + * + * Copyright (c) 2009-2010, 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 "llinventoryobserver.h" +#include "llstartup.h" +#include "llviewerfoldertype.h" +#include "llviewerobject.h" +#include "llvoavatarself.h" + +#include "rlvdefines.h" +#include "rlvcommon.h" +#include "rlvlocks.h" +#include "rlvinventory.h" +#include "rlvhandler.h" + +// ============================================================================ +// 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: 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.count(); idxFolder < cntFolder; idxFolder++) + idFolders.push_back(folders.get(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.count(); idxItem < cntItem; idxItem++) + { + const LLViewerInventoryItem* pItem = items.get(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.count() != 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.count() != 0); +} + +// Checked: 2010-02-28 (RLVa-1.2.0a) | Modified: RLVa-1.0.0h +LLViewerInventoryCategory* RlvInventory::getSharedRoot() const +{ + if (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 so we'll just go with the first one we come across + LLViewerInventoryCategory* pFolder; + for (S32 idxFolder = 0, cntFolder = pFolders->count(); idxFolder < cntFolder; idxFolder++) + { + if ( ((pFolder = pFolders->get(idxFolder)) != NULL) && (RlvInventory::cstrSharedRoot == pFolder->getName()) ) + return pFolder; + } + } + } + return NULL; +} + +// Checked: 2010-02-28 (RLVa-1.2.0a) | Modified: RLVa-1.0.1a +LLViewerInventoryCategory* RlvInventory::getSharedFolder(const LLUUID& idParent, const std::string& strFolderName) 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; + + //LLStringUtil::toLower(strFolderName); <- everything was already converted to lower case before + + std::string strName; + for (S32 idxFolder = 0, cntFolder = pFolders->count(); idxFolder < cntFolder; idxFolder++) + { + LLViewerInventoryCategory* pFolder = pFolders->get(idxFolder); + + strName = pFolder->getName(); + if (strName.empty()) + continue; + LLStringUtil::toLower(strName); + + if (strFolderName == strName) + return pFolder; // Found an exact match, no need to keep on going + else if ( (!pPartial) && (RLV_FOLDER_PREFIX_HIDDEN != strName[0]) && (std::string::npos != strName.find(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) 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); + 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: 2009-05-26 (RLVa-0.2.0d) | Modified: RLVa-0.2.0d +S32 RlvInventory::getDirectDescendentsCount(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->count(); idxItem < cntItem; idxItem++) + if (pItems->get(idxItem)->getType() == filterType) + cntType++; + } + } + return cntType; +} + +// ============================================================================ +// 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)); + 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.count(); idxItem < cntItem; idxItem++) + { + LLViewerInventoryItem* pItem = items.get(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::getDirectDescendentsCount(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 + LLUUID idAttachFolder = gInventory.createNewCategory(pFolder->getUUID(), LLFolderType::FT_NONE, strFolderName); + move_inventory_item(gAgent.getID(), gAgent.getSessionID(), pItem->getUUID(), idAttachFolder, std::string(), NULL); + } + } + } + } + } + gInventory.notifyObservers(); + + delete this; +} + +// ============================================================================ +// "Give to #RLV" helper classes +// + +// Checked: 2010-04-18 (RLVa-1.2.0e) | Added: RLVa-1.2.0e +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.0e) | Added: RLVa-1.2.0e +void RlvGiveToRLVTaskOffer::done() +{ + gInventory.removeObserver(this); + + // We shouldn't be messing with inventory items during LLInventoryModel::notifyObservers() + doOnIdleOneTime(boost::bind(&RlvGiveToRLVTaskOffer::doneIdle, this)); +} + +// Checked: 2010-04-18 (RLVa-1.2.0e) | Added: RLVa-1.2.0e +void RlvGiveToRLVTaskOffer::doneIdle() +{ + const LLViewerInventoryCategory* pRlvRoot = RlvInventory::instance().getSharedRoot(); + if (pRlvRoot) + { + for (folder_ref_t::const_iterator itFolder = m_Folders.begin(); itFolder != m_Folders.end(); ++itFolder) + { + const LLViewerInventoryCategory* pFolder = gInventory.getCategory(*itFolder); + if (!pFolder) + continue; + + std::string strFolder = pFolder->getName(); + if ( (pRlvRoot->getUUID() == pFolder->getParentUUID() ) && (strFolder.find(RLV_PUTINV_PREFIX) == 0)) + { + LLPointer<LLViewerInventoryCategory> pNewFolder = new LLViewerInventoryCategory(pFolder); + pNewFolder->rename(strFolder.erase(0, strFolder.find(RLV_FOLDER_PREFIX_PUTINV))); + pNewFolder->updateServer(FALSE); + gInventory.updateCategory(pNewFolder); + + gInventory.notifyObservers(); + break; + } + } + } + delete this; +} + +// Checked: 2010-04-18 (RLVa-1.2.0e) | Modified: RLVa-1.2.0e +void RlvGiveToRLVAgentOffer::done() +{ + gInventory.removeObserver(this); + + // We shouldn't be messing with inventory items during LLInventoryModel::notifyObservers() + doOnIdleOneTime(boost::bind(&RlvGiveToRLVAgentOffer::doneIdle, this)); +} + +// Checked: 2010-04-18 (RLVa-1.2.0e) | Modified: RLVa-1.2.0e +void RlvGiveToRLVAgentOffer::doneIdle() +{ + const LLViewerInventoryCategory* pRlvRoot = RlvInventory::instance().getSharedRoot(); + const LLViewerInventoryCategory* pFolder = (mComplete.size()) ? gInventory.getCategory(mComplete[0]) : NULL; + if ( (pRlvRoot) && (pFolder) ) + { + std::string strName = pFolder->getName(); + if (strName.find(RLV_PUTINV_PREFIX) == 0) + { + LLInventoryModel::update_list_t update; + LLInventoryModel::LLCategoryUpdate updOldParent(pFolder->getParentUUID(), -1); + update.push_back(updOldParent); + LLInventoryModel::LLCategoryUpdate updNewParent(pRlvRoot->getUUID(), 1); + update.push_back(updNewParent); + gInventory.accountForUpdate(update); + + LLPointer<LLViewerInventoryCategory> pNewFolder = new LLViewerInventoryCategory(pFolder); + pNewFolder->setParent(pRlvRoot->getUUID()); + pNewFolder->updateParentOnServer(FALSE); + pNewFolder->rename(strName.erase(0, strName.find(RLV_FOLDER_PREFIX_PUTINV))); + pNewFolder->updateServer(FALSE); + gInventory.updateCategory(pNewFolder); + + gInventory.notifyObservers(); + } + } + delete this; +} + +// ============================================================================ +// RlvWearableItemCollector +// + +// 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-03-20 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a +bool RlvWearableItemCollector::onCollectFolder(const LLInventoryCategory* pFolder) +{ + const LLUUID& idParent = pFolder->getParentUUID(); + if (m_Wearable.end() == std::find(m_Wearable.begin(), m_Wearable.end(), idParent)) + return false; // Not the child of a wearable folder == skip + + const std::string& strFolder = pFolder->getName(); + if (strFolder.empty()) // Shouldn't happen but does... naughty Lindens + return false; + + if (RlvInventory::isFoldedFolder(pFolder, false)) // Check for folder that should get folded under its parent + { + if ( (!m_fAttach) || (1 == RlvInventory::getDirectDescendentsCount(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(), idParent)); + } + } + else if ( (RLV_FOLDER_PREFIX_HIDDEN != strFolder[0]) && (m_fMatchAll) ) // Collect from any non-hidden child folder for *all + { + #ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS + if ( (!RlvSettings::getEnableComposites()) || // ... if we're not checking composite folders + (!gRlvHandler.isCompositeFolder(pFolder)) || // ... or if it's not a composite folder + ((m_fAttach) && (gRlvHandler.canWearComposite(pFolder))) || // ... or if we're attaching and can attach it OR + (!m_fAttach) && (gRlvHandler.canTakeOffComposite(pFolder)) ) // ... or if we're detaching and can detach it + #endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS + { + m_Wearable.push_front(pFolder->getUUID()); + } + return (idParent == m_idFolder); // (Convenience for @getinvworn) + } + #ifdef RLV_EXPERIMENTAL_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-03-20 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a +bool RlvWearableItemCollector::onCollectItem(const LLInventoryItem* pItem) +{ + #ifdef RLV_EXTENSION_FLAG_NOSTRIP + if ( (!m_fAttach) && (!RlvForceWear::isStrippable(pItem)) ) // Don't process "nostrip" items on detach + return false; + #endif // RLV_EXTENSION_FLAG_NOSTRIP + + const LLUUID& idParent = pItem->getParentUUID(); bool fRet = false; + switch (pItem->getType()) + { + case LLAssetType::AT_BODYPART: + if (!m_fAttach) + break; // Don't process body parts on detach + case LLAssetType::AT_CLOTHING: + #ifdef RLV_EXTENSION_FLAG_NOSTRIP + fRet = ( (m_Wearable.end() != std::find(m_Wearable.begin(), m_Wearable.end(), idParent)) || + ( (m_fAttach) && (m_Folded.end() != std::find(m_Folded.begin(), m_Folded.end(), idParent)) && + (RlvForceWear::isStrippable(pItem)) ) ); + #else + fRet = (m_Wearable.end() != std::find(m_Wearable.begin(), m_Wearable.end(), idParent)); + #endif // RLV_EXTENSION_FLAG_NOSTRIP + 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)) ) && + ( (!m_fAttach) || (RlvAttachPtLookup::hasAttachPointName(pItem)) || (RlvSettings::getEnableSharedWear()) ); + break; + #ifdef RLV_EXTENSION_FORCEWEAR_GESTURES + case LLAssetType::AT_GESTURE: + fRet = (m_Wearable.end() != std::find(m_Wearable.begin(), m_Wearable.end(), idParent)); + break; + #endif // RLV_EXTENSION_FORCEWEAR_GESTURES + 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 ); +} + +// ============================================================================ diff --git a/indra/newview/rlvinventory.h b/indra/newview/rlvinventory.h new file mode 100644 index 0000000000000000000000000000000000000000..22e451bcfb93c034a39b1534cf294c3f9d9d0ecf --- /dev/null +++ b/indra/newview/rlvinventory.h @@ -0,0 +1,256 @@ +/** + * + * Copyright (c) 2009-2010, 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 "llviewerinventory.h" + +#include "rlvhelper.h" +#include "rlvlocks.h" + +// ============================================================================ +// RlvInventory class declaration +// + +// TODO-RLVa: [RLVa-1.2.0] Make all of this static rather than a singleton? +class RlvInventory : public LLSingleton<RlvInventory> +{ +protected: + RlvInventory() : m_fFetchStarted(false), m_fFetchComplete(false) {} + + /* + * #RLV Shared inventory + */ +public: + // 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; + // Returns a subfolder of idParent that starts with strFolderName (exact match > partial match) + LLViewerInventoryCategory* getSharedFolder(const LLUUID& idParent, const std::string& strFolderName) const; + // Looks up a folder from a path (relative to the shared root) + LLViewerInventoryCategory* getSharedFolder(const std::string& strPath) const; + // Returns the path of the supplied folder (relative to the shared root) + std::string getSharedPath(const LLViewerInventoryCategory* pFolder) const; + // Returns TRUE if the supplied folder is a descendent of the #RLV folder + bool isSharedFolder(const LLUUID& idFolder); + + /* + * Inventory fetching + */ +public: + void fetchSharedInventory(); + void fetchWornItems(); +protected: + void fetchSharedLinks(); + + /* + * General purpose helper functions + */ +public: + // Returns the number of direct descendents of pFolder that have the specified type asset type + static S32 getDirectDescendentsCount(const LLInventoryCategory* pFolder, LLAssetType::EType filterType); + // 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 + +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(); +}; + +// ============================================================================ +// "Give to #RLV" helper classes +// + +// [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 +{ +public: + RlvGiveToRLVTaskOffer(const LLUUID& idTransaction) : m_idTransaction(idTransaction) {} + /*virtual*/ void changed(U32 mask); +protected: + /*virtual*/ void done(); + void doneIdle(); + + typedef std::vector<LLUUID> folder_ref_t; + folder_ref_t m_Folders; + LLUUID m_idTransaction; +}; + +class RlvGiveToRLVAgentOffer : public LLInventoryFetchDescendentsObserver +{ +public: + RlvGiveToRLVAgentOffer(const LLUUID& idFolder) : LLInventoryFetchDescendentsObserver(idFolder) {} + /*virtual*/ void done(); +protected: + void doneIdle(); +}; + +// ============================================================================ +// 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 LLUUID& idFolder, bool fAttach, bool fMatchAll) + : m_idFolder(idFolder), m_fAttach(fAttach), m_fMatchAll(fMatchAll) + { + m_Wearable.push_back(idFolder); + } + virtual ~RlvWearableItemCollector() {} + + virtual bool operator()(LLInventoryCategory* pFolder, LLInventoryItem* pItem); + + const LLUUID& getFoldedParent(const LLUUID& idFolder) const; +protected: + bool m_fAttach; + bool m_fMatchAll; + const LLUUID m_idFolder; + + bool onCollectFolder(const LLInventoryCategory* pFolder); + bool onCollectItem(const LLInventoryItem* pItem); + + std::list<LLUUID> m_Folded; + std::list<LLUUID> m_Wearable; + + std::map<LLUUID, LLUUID> m_FoldingMap; +}; + +// ============================================================================ +// General purpose inventory helper classes +// + +class RlvIsLinkType : public LLInventoryCollectFunctor +{ +public: + RlvIsLinkType() {} + virtual ~RlvIsLinkType() {} + virtual bool operator()(LLInventoryCategory* pFolder, LLInventoryItem* pItem) { return (pItem) && (pItem->getIsLinkType()); } +}; + +// ============================================================================ +// RlvInventory inlined member functions +// + +// 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)) + #ifdef RLV_EXTENSION_FLAG_NOSTRIP + // .(nostrip) folder + || ( (pFolder) && (".("RLV_FOLDER_FLAG_NOSTRIP")" == pFolder->getName()) ) + #endif // RLV_EXTENSION_FLAG_NOSTRIP + // 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; +} + +// ============================================================================ + +#endif // RLV_INVENTORY_H diff --git a/indra/newview/rlvlocks.cpp b/indra/newview/rlvlocks.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6001a926459f4d87a2fe0abdafa0a863e4cbdba2 --- /dev/null +++ b/indra/newview/rlvlocks.cpp @@ -0,0 +1,869 @@ +/** + * + * Copyright (c) 2009-2010, 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 "llnotifications.h" +#include "llviewerobjectlist.h" +#include "pipeline.h" + +#include "rlvhelper.h" +#include "rlvlocks.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 (isAgentAvatarValid()) + { + 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)); + } + } + 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: 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) + { + LLPipeline::sShowHUDAttachments = TRUE; + gUseWireframe = 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-07-28 (RLVa-1.2.0i) | Modified: RLVa-1.2.0i +void RlvAttachmentLockWatchdog::attach(S32 idxAttachPt, const LLUUID& idItem) +{ + // RELEASE-RLVa: [SL-2.0.0] This will need rewriting for "ENABLE_MULTIATTACHMENTS" + LLSD payload; + payload["item_id"] = idItem; + payload["attachment_point"] = idxAttachPt | ATTACHMENT_ADD; + payload["rlv_force"] = true; + LLNotifications::instance().forceResponse(LLNotification::Params("ReplaceAttachment").payload(payload), 0); +} + +// 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() ); + + // HACK-RLVa: force the region to send out an ObjectUpdate for the old attachment so obsolete viewers will remember it exists + S32 idxAttachPt = RlvAttachPtLookup::getAttachPointIndex(pAttachObj); + const LLViewerJointAttachment* pAttachPt = + (isAgentAvatarValid()) ? get_if_there(gAgentAvatarp->mAttachmentPoints, (S32)idxAttachPt, (LLViewerJointAttachment*)NULL) : NULL; + if ( (pAttachPt) && (!pAttachPt->getIsHUDAttachment()) && (pAttachPt->mAttachedObjects.size() > 1) ) + { + for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator itAttachObj = pAttachPt->mAttachedObjects.begin(); + itAttachObj != pAttachPt->mAttachedObjects.end(); ++itAttachObj) + { + if (pAttachObj != *itAttachObj) + { + LLSelectMgr::instance().deselectAll(); + LLSelectMgr::instance().selectObjectAndFamily(*itAttachObj); + LLSelectMgr::instance().deselectAll(); + break; + } + } + } + } +} + +// Checked: 2010-07-28 (RLVa-1.2.0i) | Added: RLVa-1.2.0i +void RlvAttachmentLockWatchdog::detach(S32 idxAttachPt, const LLViewerObject* pAttachObjExcept /*=NULL*/) +{ + const LLViewerJointAttachment* pAttachPt = + (isAgentAvatarValid()) ? get_if_there(gAgentAvatarp->mAttachmentPoints, (S32)idxAttachPt, (LLViewerJointAttachment*)NULL) : NULL; + if (!pAttachPt) + return; + + std::list<const LLViewerObject*> attachObjs; + for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator itAttachObj = pAttachPt->mAttachedObjects.begin(); + itAttachObj != pAttachPt->mAttachedObjects.end(); ++itAttachObj) + { + const LLViewerObject* pAttachObj = *itAttachObj; + if (pAttachObj != pAttachObjExcept) + 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::list<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 (std::find(m_PendingDetach.begin(), m_PendingDetach.end(), pAttachObj->getAttachmentItemID()) == m_PendingDetach.end()) + m_PendingDetach.push_back(pAttachObj->getAttachmentItemID()); + } + + gMessageSystem->sendReliable(gAgent.getRegionHost()); + + // HACK-RLVa: force the region to send out an ObjectUpdate for the old attachment so obsolete viewers will remember it exists + if ( (!pAttachPt->getIsHUDAttachment()) && (pAttachPt->mAttachedObjects.size() > attachObjs.size()) ) + { + for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator itAttachObj = pAttachPt->mAttachedObjects.begin(); + itAttachObj != pAttachPt->mAttachedObjects.end(); ++itAttachObj) + { + if (std::find(attachObjs.begin(), attachObjs.end(), *itAttachObj) == attachObjs.end()) + { + LLSelectMgr::instance().deselectAll(); + LLSelectMgr::instance().selectObjectAndFamily(*itAttachObj); + LLSelectMgr::instance().deselectAll(); + break; + } + } + } + } +} + +// Checked: 2010-07-28 (RLVa-1.2.0i) | Modified: RLVa-1.2.0i +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; + m_PendingAttach.erase(itAttach); + break; + } + } + if (!fPendingReattach) + detach(pAttachObj); + return; + } + + // Check if the attach is the result of a user action (="Wear") + rlv_wear_map_t::iterator itWear = m_PendingWear.find(idAttachItem); + if (itWear != m_PendingWear.end()) + { + // We need to return the attachment point to its previous state if an attachment was added to a non-attachable attachment point + if (gRlvAttachmentLocks.isLockedAttachmentPoint(idxAttachPt, RLV_LOCK_ADD)) + { + // Get the state of the attachment point at the time the user picked "Wear" (but do nothing if the item itself was worn then) + std::map<S32, std::list<LLUUID> >::iterator itAttachPrev = itWear->second.attachPts.find(idxAttachPt); + RLV_ASSERT(itAttachPrev != itWear->second.attachPts.end()); + if ( (itAttachPrev != itWear->second.attachPts.end()) && + (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 + std::list<const LLViewerObject*> attachObjs; + for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator itAttachObj = pAttachPt->mAttachedObjects.begin(); + itAttachObj != pAttachPt->mAttachedObjects.end(); ++itAttachObj) + { + const LLViewerObject* pAttachObj = *itAttachObj; + + std::list<LLUUID>::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 (std::list<LLUUID>::iterator itAttach = itAttachPrev->second.begin(); + itAttach != itAttachPrev->second.end(); ++itAttach) + { + m_PendingAttach.insert(std::pair<S32, RlvReattachInfo>(idxAttachPt, RlvReattachInfo(*itAttach))); + } + } + } + } + else if (RLV_WEAR_REPLACE == itWear->second.eWearAction) + { + // Now that we know where this attaches to check if we can actually perform a "replace" + bool fCanReplace = true; + for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator itAttachObj = pAttachPt->mAttachedObjects.begin(); + ((itAttachObj != pAttachPt->mAttachedObjects.end()) && (fCanReplace)); ++itAttachObj) + { + if (pAttachObj != *itAttachObj) + fCanReplace &= !gRlvAttachmentLocks.isLockedAttachment(*itAttachObj); + } + + if (fCanReplace) + detach(idxAttachPt, pAttachObj); // Replace == allowed: detach everything 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()' + } +} + +// 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); + return; + } + + // If the attachment is currently "remove locked" then we should reattach it (unless it's already pending reattach) + 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(); + } + } +} + +// 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) ) + { + attach(itAttach->first, itAttach->second.idItem); + 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) + { + attach(itAttach->first, itAttach->second.idItem); + 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)) + { + std::list<LLUUID> 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, std::list<LLUUID> >(itAttachPt->first, attachObjs)); + } + } + + m_PendingWear.insert(std::pair<LLUUID, RlvWearInfo>(idItem, infoWear)); + 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.getWearable(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.getWearable(eType, idxWearable))) + return true; + return false; +} + +// Checked: 2010-03-19 (RLVa-1.2.0a) | Added: RLVa-1.2.0a +bool RlvWearableLocks::isLockedWearableExcept(const LLWearable* 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; + } + } + } +} + +// ============================================================================ diff --git a/indra/newview/rlvlocks.h b/indra/newview/rlvlocks.h new file mode 100644 index 0000000000000000000000000000000000000000..262570a7ada99fa2a5da145aad7c309d7dc4bd76 --- /dev/null +++ b/indra/newview/rlvlocks.h @@ -0,0 +1,459 @@ +/** + * + * Copyright (c) 2009-2010, 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 "rlvdefines.h" +#include "rlvcommon.h" + +// ============================================================================ +// RlvAttachPtLookup class declaration +// + +#include "llagent.h" +#include "llviewerjointattachment.h" +#include "llviewerobject.h" +#include "llvoavatarself.h" + +#include "rlvdefines.h" + +class RlvAttachPtLookup +{ +public: + static LLViewerJointAttachment* getAttachPoint(const std::string& strText); + static LLViewerJointAttachment* getAttachPoint(const LLInventoryItem* pItem); + + static S32 getAttachPointIndex(std::string strText); + static S32 getAttachPointIndex(const LLViewerObject* pObj); + static S32 getAttachPointIndex(const LLViewerJointAttachment* pObj); + 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* pObj) const; + bool isLockedAttachment(const LLInventoryItem* pItem) 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 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 { return !isLockedAttachment(pItem); } + // 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: attach/detach do *not* respect attachment locks so use with care + void attach(S32 idxAttachPt, const LLUUID& idItem); + void detach(const LLViewerObject* pAttachObj); + void detach(S32 idxAttachPt, const LLViewerObject* pAttachObjExcept = NULL); + + 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(); } + + LLUUID idItem; + ERlvWearMask eWearAction; + F64 tsWear; + std::map<S32, std::list<LLUUID> > 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 LLWearable* pWearable) const; + bool isLockedWearable(const LLInventoryItem* pItem) const; + // Returns TRUE if the wearable is RLV_LOCK_REMOVE locked by anything other than idRlvObj + bool isLockedWearableExcept(const LLWearable* 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; + +// ============================================================================ +// RlvAttachPtLookup inlined member functions +// + +// 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: 2010-08-07 (RLVa-1.2.0i) | Modified: RLVa-1.2.0i +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 + // - the attachment point it specifies can be attached to + LLViewerJointAttachment* pAttachPt = RlvAttachPtLookup::getAttachPoint(pItem); + if (ppAttachPtOut) + *ppAttachPtOut = pAttachPt; + return (!pAttachPt) ? (ERlvWearMask)(RLV_WEAR_REPLACE | RLV_WEAR_ADD) : canAttach(pAttachPt); +} + +// 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_LOCKED (or RLV_WEAR_ADD) + // Unlocked attachment(s) => RLV_WEAR_REPLACE (or RLV_WEAR_ADD | RLV_WEAR_REPLACE) + // Empty attachment point => RLV_WEAR_REPLACE (or 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.0a) | Modified: RLVa-1.2.0a +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())) ) || + ( (eLock & RLV_LOCK_ADD) && (!m_AttachPtAdd.empty()) ); +} + +// Checked: 2010-02-28 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a +inline bool RlvAttachmentLocks::isLockedAttachment(const LLViewerObject* pObj) const +{ + // 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()) ); + + // 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) + return + (pObj) && (pObj->isAttachment()) && + ( (m_AttachObjRem.find(pObj->getID()) != m_AttachObjRem.end()) || + (isLockedAttachmentPoint(RlvAttachPtLookup::getAttachPointIndex(pObj), RLV_LOCK_REMOVE)) ); +} + +// Checked: 2010-02-28 (RLVa-1.2.0a) | Added: RLVa-1.0.5a +inline bool RlvAttachmentLocks::isLockedAttachment(const LLInventoryItem* pItem) const +{ + return (pItem) && (isAgentAvatarValid()) && (isLockedAttachment(gAgentAvatarp->getWornAttachment(pItem->getLinkedUUID()))); +} + +// 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()) ); + return (pItem) ? !isLockedWearable(gAgentWearables.getWearableFromItemID(pItem->getLinkedUUID())) : false; +} + +// Checked: 2010-05-14 (RLVa-1.2.0g) | Modified: RLVa-1.2.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) ? 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.getWearableCount(eType) < LLAgentWearables::MAX_CLOTHING_PER_TYPE) ? 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-03-19 (RLVa-1.2.0c) | Added: RLVa-1.2.0a +inline bool RlvWearableLocks::isLockedWearable(const LLWearable* 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 + // 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)); +} + +// 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); +} + +// ============================================================================ + +#endif // RLV_LOCKS_H diff --git a/indra/newview/rlvui.cpp b/indra/newview/rlvui.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5b5eb9ef6de1fc8845585e0be04d8949a44ab49c --- /dev/null +++ b/indra/newview/rlvui.cpp @@ -0,0 +1,550 @@ +/** + * + * Copyright (c) 2009-2010, 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 "llavatarlist.h" // Avatar list control used by the "Nearby" tab in the "People" sidebar panel +#include "llbottomtray.h" +#include "llbutton.h" +#include "llcallfloater.h" +#include "llinventorypanel.h" +#include "llimview.h" // LLIMMgr +#include "llmoveview.h" // Movement panel (contains "Stand" and "Stop Flying" buttons) +#include "llnavigationbar.h" // Navigation bar +#include "llnotificationsutil.h" +#include "lloutfitslist.h" // "My Outfits" sidebar panel +#include "llpaneloutfitsinventory.h" // "My Appearance" sidebar panel +#include "llpanelpeople.h" // "People" sidebar panel +#include "llpanelprofile.h" // "Profile" sidebar panel +#include "llpanelwearing.h" // "Current Outfit" sidebar panel +#include "llparcel.h" +#include "llsidetray.h" +#include "llsidetraypanelcontainer.h" +#include "lltabcontainer.h" +#include "lltoolmgr.h" +#include "llviewerparcelmgr.h" +#include "roles_constants.h" // Group "powers" + +#include "rlvui.h" +#include "rlvhandler.h" + +// ============================================================================ + +// Checked: 2010-02-28 (RLVa-1.2.0a) | Added: RLVa-1.2.0a +RlvUIEnabler::RlvUIEnabler() +{ + // Connect us to the behaviour toggle signal + gRlvHandler.setBehaviourCallback(boost::bind(&RlvUIEnabler::onBehaviour, 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_SHOWNAMES, 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))); + + // 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_EDIT, boost::bind(&RlvUIEnabler::onToggleEdit, this))); + m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_FLY, boost::bind(&RlvUIEnabler::onToggleFly, this))); + m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_SETENV, boost::bind(&RlvUIEnabler::onToggleSetEnv, this))); + m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_SHOWINV, boost::bind(&RlvUIEnabler::onToggleShowInv, this))); + 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_SHOWNAMES, boost::bind(&RlvUIEnabler::onToggleShowNames, 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 + #ifdef RLV_EXTENSION_STARTLOCATION + m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_TPLOC, boost::bind(&RlvUIEnabler::onUpdateLoginLastLocation, this))); + m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_UNSIT, boost::bind(&RlvUIEnabler::onUpdateLoginLastLocation, this))); + #endif // RLV_EXTENSION_STARTLOCATION +} + +// Checked: 2010-02-28 (RLVa-1.2.0b) | Added: RLVa-1.2.0a +void RlvUIEnabler::onBehaviour(ERlvBehaviour eBhvr, ERlvParamType eType) +{ + // We're only interested in behaviour toggles (ie on->off or off->on) + if ( ((RLV_TYPE_ADD == eType) && (1 == gRlvHandler.hasBehaviour(eBhvr))) || + ((RLV_TYPE_REMOVE == eType) && (0 == gRlvHandler.hasBehaviour(eBhvr))) ) + { + for (behaviour_handler_map_t::const_iterator itHandler = m_Handlers.lower_bound(eBhvr), endHandler = m_Handlers.upper_bound(eBhvr); + itHandler != endHandler; ++itHandler) + { + itHandler->second(); + } + } +} + +// ============================================================================ + +// Checked: 2010-03-02 (RLVa-1.2.0b) | 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-17 (RLVa-1.2.0a) | Added: RLVa-1.2.0a +void RlvUIEnabler::onToggleEdit() +{ + bool fEnable = !gRlvHandler.hasBehaviour(RLV_BHVR_EDIT); + + if (!fEnable) + { + // Turn off "View / Highlight Transparent" + LLDrawPoolAlpha::sShowDebugAlpha = FALSE; + + // Hide the beacons floater if it's currently visible + if (LLFloaterReg::floaterInstanceVisible("beacons")) + LLFloaterReg::hideInstance("beacons"); + + // Hide the build floater if it's currently visible + if (LLToolMgr::instance().inBuildMode()) + LLToolMgr::instance().toggleBuildMode(); + } + + // Start or stop filtering opening the beacons floater + if (!fEnable) + addGenericFloaterFilter("beacons"); + else + removeGenericFloaterFilter("beacons"); +} + +// Checked: 2010-03-02 (RLVa-1.2.0d) | Added: RLVa-1.2.0a +void RlvUIEnabler::onToggleFly() +{ + bool fEnable = !gRlvHandler.hasBehaviour(RLV_BHVR_FLY); + + // Drop the avie out of the sky if currently flying and restricted + if ( (!fEnable) && (gAgent.getFlying()) ) + gAgent.setFlying(FALSE); + + // Force an update since the status only updates when the current parcel changes [see LLFloaterMove::postBuild()] + LLFloaterMove::sUpdateFlyingStatus(); +} + +// Checked: 2010-03-17 (RLVa-1.2.0a) | Added: RLVa-1.2.0a +void RlvUIEnabler::onToggleSetEnv() +{ + bool fEnable = !gRlvHandler.hasBehaviour(RLV_BHVR_SETENV); + + const std::string strEnvFloaters[] = { "env_day_cycle", /*"env_post_process",*/ "env_settings", "env_water", "env_windlight" }; + for (int idxFloater = 0, cntFloater = sizeof(strEnvFloaters) / sizeof(std::string); idxFloater < cntFloater; idxFloater++) + { + if (!fEnable) + { + // Hide the floater if it's currently visible + if (LLFloaterReg::floaterInstanceVisible(strEnvFloaters[idxFloater])) + LLFloaterReg::hideInstance(strEnvFloaters[idxFloater]); + + addGenericFloaterFilter(strEnvFloaters[idxFloater]); + } + else + { + removeGenericFloaterFilter(strEnvFloaters[idxFloater]); + } + } +} + +// Checked: 2010-08-24 (RLVa-1.2.1a) | Modified: RLVa-1.2.1a +void RlvUIEnabler::onToggleShowInv() +{ + bool fEnable = !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWINV); + + // + // Enable/disable the "My Inventory" button on the sidebar button panel + // + LLSideTray* pSideTray = LLSideTray::getInstance(); + RLV_ASSERT(pSideTray); + if (pSideTray) + { + LLButton* pInvBtn = pSideTray->getButtonFromName("sidebar_inventory"); + RLV_ASSERT(pInvBtn); + if (pInvBtn) + pInvBtn->setEnabled(fEnable); + + // When disabling, switch to the "Home" sidebar tab if "My Inventory" is currently active + // NOTE: when collapsed 'isPanelActive' will return FALSE even if the panel is currently active so we have to sidestep that + const LLPanel* pActiveTab = pSideTray->getActiveTab(); + if ( (!fEnable) && (pActiveTab) && ("sidebar_inventory" == pActiveTab->getName()) ) + { + pSideTray->selectTabByName("sidebar_home"); // Using selectTabByName() instead of showPanel() will prevent it from expanding + if (pSideTray->getCollapsed()) + pSideTray->collapseSideBar(); // Fixes a button highlighting glitch when changing the active tab while collapsed + } + + // Start or stop filtering opening the inventory sidebar tab + RLV_ASSERT_DBG( (fEnable) || (!m_ConnSidePanelInventory.connected()) ); + if (!fEnable) + m_ConnSidePanelInventory = pSideTray->setValidateCallback(boost::bind(&RlvUIEnabler::canOpenSidebarTab, this, RLV_BHVR_SHOWINV, "sidebar_inventory", _1, _2)); + else + m_ConnSidePanelInventory.disconnect(); + } + + // + // Enable/disable the "My Outfits" panel on the "My Appearance" sidebar tab + // + LLPanelOutfitsInventory* pAppearancePanel = LLPanelOutfitsInventory::findInstance(); + 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, fEnable); + + // When disabling, switch to the COF tab if "My Outfits" is currently active + if ( (!fEnable) && (pAppearanceTabs->getCurrentPanelIndex() == idxTab) ) + pAppearanceTabs->selectTabPanel(pAppearancePanel->getCurrentOutfitPanel()); + } + } + + // + // When disabling, hide any old style inventory floaters that may be open + // + if (!fEnable) + { + LLFloaterReg::const_instance_list_t lFloaters = LLFloaterReg::getFloaterList("inventory"); + for (LLFloaterReg::const_instance_list_t::const_iterator itFloater = lFloaters.begin(); itFloater != lFloaters.end(); ++itFloater) + (*itFloater)->closeFloater(); + } + + // Filter out (or stop filtering) newly spawned old style inventory floaters + if (!fEnable) + addGenericFloaterFilter("inventory"); + else + removeGenericFloaterFilter("inventory"); +} + +// Checked: 2010-04-22 (RLVa-1.2.0f) | Modified: RLVa-1.2.0f +void RlvUIEnabler::onToggleShowLoc() +{ + bool fEnable = !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC); + + // RELEASE-RLVa: [SL-2.0.1] Check that the code below still evaluates to *only* LLNavigationBar::instance().mCmbLocation->refresh() + LLNavigationBar::instance().handleLoginComplete(); + + if (!fEnable) + { + // Hide the "About Land" floater if it's currently visible + if (LLFloaterReg::floaterInstanceVisible("about_land")) + LLFloaterReg::hideInstance("about_land"); + // Hide the "Region / Estate" floater if it's currently visible + if (LLFloaterReg::floaterInstanceVisible("region_info")) + LLFloaterReg::hideInstance("region_info"); + // Hide the "God Tools" floater if it's currently visible + if (LLFloaterReg::floaterInstanceVisible("god_tools")) + LLFloaterReg::hideInstance("god_tools"); + } + + // 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)); + else if ( (fEnable) && (m_ConnFloaterShowLoc.connected()) ) + m_ConnFloaterShowLoc.disconnect(); +} + +// Checked: 2010-02-28 (RLVa-1.2.0b) | Added: RLVa-1.2.0a +void RlvUIEnabler::onToggleShowMinimap() +{ + bool fEnable = !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWMINIMAP); + + // Hide the mini-map if it's currently visible + if ( (!fEnable) && (LLFloaterReg::floaterInstanceVisible("mini_map")) ) + LLFloaterReg::hideFloaterInstance("mini_map"); + + // Enable/disable the "Mini-Map" bottom tray button + const LLBottomTray* pTray = LLBottomTray::getInstance(); + LLView* pBtnView = (pTray) ? pTray->getChildView("mini_map_btn") : NULL; + if (pBtnView) + pBtnView->setEnabled(fEnable); + + // Start or stop filtering opening the mini-map + if (!fEnable) + addGenericFloaterFilter("mini_map"); + else + removeGenericFloaterFilter("mini_map"); +} + +// Checked: 2010-06-05 (RLVa-1.2.0d) | Modified: RLVa-1.2.0d +void RlvUIEnabler::onToggleShowNames() +{ + // Refresh the nearby people list + LLPanelPeople* pPeoplePanel = dynamic_cast<LLPanelPeople*>(LLSideTray::getInstance()->getPanel("panel_people")); + RLV_ASSERT( (pPeoplePanel) && (pPeoplePanel->getNearbyList()) ); + if ( (pPeoplePanel) && (pPeoplePanel->getNearbyList()) ) + pPeoplePanel->getNearbyList()->refreshNames(); + + // Refresh the speaker list + LLCallFloater* pCallFloater = LLFloaterReg::findTypedInstance<LLCallFloater>("voice_controls"); + if (pCallFloater) + pCallFloater->getAvatarCallerList()->refreshNames(); +} + +// Checked: 2010-02-28 (RLVa-1.2.0b) | 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::floaterInstanceVisible("world_map")) ) + LLFloaterReg::hideFloaterInstance("world_map"); + + // Enable/disable the "Map" bottom tray button + const LLBottomTray* pTray = LLBottomTray::getInstance(); + LLView* pBtnView = (pTray) ? pTray->getChildView("world_map_btn") : NULL; + if (pBtnView) + pBtnView->setEnabled(fEnable); + + // 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()->getChild<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->getChild<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 fEnable = (!gRlvHandler.hasBehaviour(RLV_BHVR_VIEWNOTE)) && + (!gRlvHandler.hasBehaviour(RLV_BHVR_VIEWSCRIPT)) && (!gRlvHandler.hasBehaviour(RLV_BHVR_VIEWTEXTURE)); + + // Start or stop filtering opening the preview floaters + if ( (!fEnable) && (!m_ConnFloaterViewXXX.connected()) ) + m_ConnFloaterViewXXX = LLFloaterReg::setValidateCallback(boost::bind(&RlvUIEnabler::filterFloaterViewXXX, this, _1, _2)); + else if ( (fEnable) && (m_ConnFloaterViewXXX.connected()) ) + m_ConnFloaterViewXXX.disconnect(); +} + +// Checked: 2010-04-01 (RLVa-1.2.0c) | Added: RLVa-1.2.0c +void RlvUIEnabler::onUpdateLoginLastLocation() +{ + RlvSettings::updateLoginLastLocation(); +} + +// ============================================================================ + +// Checked: 2010-02-28 (RLVa-1.2.0b) | Added: RLVa-1.2.0a +inline 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.2.0b) | Added: RLVa-1.2.0a +inline 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.2.0b) | Added: RLVa-1.2.0a +bool RlvUIEnabler::filterFloaterGeneric(const std::string& strName, const LLSD&) +{ + return m_FilteredFloaters.find(strName) == m_FilteredFloaters.end(); +} + +// Checked: 2010-04-22 (RLVa-1.2.0f) | Added: RLVa-1.2.0f +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: 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) ) + { + notifyBlockedViewXXX(LLAssetType::AT_NOTECARD); + return false; + } + else if ( (gRlvHandler.hasBehaviour(RLV_BHVR_VIEWSCRIPT)) && (("preview_script" == strName) || ("preview_scriptedit" == strName)) ) + { + notifyBlockedViewXXX(LLAssetType::AT_SCRIPT); + return false; + } + else if ( (gRlvHandler.hasBehaviour(RLV_BHVR_VIEWTEXTURE)) && ("preview_texture" == strName) ) + { + notifyBlockedViewXXX(LLAssetType::AT_TEXTURE); + return false; + } + return true; +} + +// ============================================================================ + +// Checked: 2010-03-01 (RLVa-1.2.0a) | Added: RLVa-1.2.0a +bool RlvUIEnabler::canOpenSidebarTab(ERlvBehaviour eBhvrFilter, const std::string& strNameFilter, LLUICtrl* pCtrl, const LLSD& sdParam) +{ + return (!gRlvHandler.hasBehaviour(eBhvrFilter)) || (strNameFilter != sdParam.asString()); +} + +// ============================================================================ + +// Checked: 2010-03-01 (RLVa-1.2.0b) | Added: RLVa-1.2.0a +void RlvUIEnabler::notifyBlockedViewXXX(LLAssetType::EType assetType) +{ + LLStringUtil::format_map_t argsMsg; std::string strMsg = RlvStrings::getString(RLV_STRING_BLOCKED_VIEWXXX); + argsMsg["[TYPE]"] = LLAssetType::lookup(assetType); + LLStringUtil::format(strMsg, argsMsg); + + LLSD argsNotify; + argsNotify["MESSAGE"] = strMsg; + LLNotificationsUtil::add("SystemMessageTip", argsNotify); +} + +// ============================================================================ + +// Checked: 2010-04-20 (RLVa-1.2.0f) | Modified: RLVa-1.2.0f +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-2.0.0] Check that ôpening the "About Land" floater still sets focus to the current parcel is none is selected + LLParcelSelection* pParcelSel = LLViewerParcelMgr::getInstance()->getFloatingParcelSelection(); + LLParcel* pParcel = (pParcelSel) ? pParcelSel->getParcel() : LLViewerParcelMgr::getInstance()->getAgentParcel(); + if ( ((pParcelSel) && (pParcelSel->hasOthersSelected())) || (!pParcel) ) + return false; + + // Ideally we could just use LLViewerParcelMgr::isParcelOwnedByAgent(), but that has that sneaky exemption for "god-like" + // RELEASE-RLVa: [SL-2.0.0] Check that the "inlining" of "isParcelOwnedByAgent" and "LLAgent::hasPowerInGroup()" still matches + const LLUUID& idOwner = pParcel->getOwnerID(); + if ( (idOwner != gAgent.getID()) ) + { + // LLAgent::hasPowerInGroup() has it too so copy/paste from there + S32 count = gAgent.mGroups.count(); + for (S32 i = 0; i < count; ++i) + { + if (gAgent.mGroups.get(i).mID == idOwner) + { + fShow |= ((gAgent.mGroups.get(i).mPowers & GP_LAND_RETURN) > 0); + break; + } + } + } + else + { + fShow = true; + } + } + return fShow; +} + +// Checked: 2010-04-20 (RLVa-1.2.0f) | Modified: RLVa-1.2.0f +bool RlvUIEnabler::canViewRegionProperties() +{ + // We'll allow "Region / Estate" if the user is either the sim 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: 2010-04-20 (RLVa-1.2.0h) | Added: RLVa-1.2.0f +bool RlvUIEnabler::hasOpenProfile(const LLUUID& idAgent) +{ + // NOTE: despite its name this function is used to determine whether or not we'll obfuscate names for inventory drops on nearby agents + // -> 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 + LLSideTray* pSideTray = LLSideTray::getInstance(); + RLV_ASSERT(pSideTray); + if ( (pSideTray) && (!pSideTray->getCollapsed()) ) + { + /*const*/ LLSideTrayPanelContainer* pPanelContainer = dynamic_cast</*const*/ LLSideTrayPanelContainer*>(pSideTray->getActivePanel()); + if (pPanelContainer) + { + const LLPanel* pActivePanel = pPanelContainer->getCurrentPanel(); + if ( (pActivePanel) && ("panel_profile_view" == pActivePanel->getName()) ) + { + const LLPanelProfile* pProfilePanel = dynamic_cast<const LLPanelProfile*>(pActivePanel); + RLV_ASSERT(pProfilePanel); + if (pProfilePanel) + return (idAgent == pProfilePanel->getAvatarId()); + } + } + } + return false; +} + +// ============================================================================ diff --git a/indra/newview/rlvui.h b/indra/newview/rlvui.h new file mode 100644 index 0000000000000000000000000000000000000000..6c6a6a40eb2ebdba22854c7fccd143502d3e8891 --- /dev/null +++ b/indra/newview/rlvui.h @@ -0,0 +1,109 @@ +/** + * + * Copyright (c) 2009-2010, 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 onBehaviour(ERlvBehaviour eBhvr, ERlvParamType eType); // RlvHandler::rlv_behaviour_signal_t + + /* + * Behaviour handlers + */ +protected: + void onRefreshHoverText(); // showloc, shownames, showhovertext(all|world|hud) + void onToggleEdit(); // edit + void onToggleFly(); // fly + void onToggleSetEnv(); // setenv + void onToggleShowInv(); // showinv + void onToggleShowLoc(); // showloc + void onToggleShowMinimap(); // showminimap + void onToggleShowNames(); // shownames + void onToggleShowWorldMap(); // showworldmap + void onToggleTp(); // tploc and tplm + void onToggleUnsit(); // unsit + void onToggleViewXXX(); // viewnote, viewscript, viewtexture + void onUpdateLoginLastLocation(); // tploc and unsit + + /* + * Floater validation callbacks + */ +protected: + void addGenericFloaterFilter(const std::string& strFloaterName); + void removeGenericFloaterFilter(const std::string& strFloaterName); + 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 + + /* + * Sidebar panel change validation + */ +protected: + bool canOpenSidebarTab(ERlvBehaviour, const std::string&, LLUICtrl*, const LLSD&); + boost::signals2::connection m_ConnSidePanelInventory; // showinv + + /* + * User feedback functions + */ +public: + static void notifyBlockedViewXXX(LLAssetType::EType assetType); + + /* + * 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 + + /* + * Member variables + */ +protected: + typedef boost::function<void()> 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/en/floater_about.xml b/indra/newview/skins/default/xui/en/floater_about.xml index f4d65bdb3aadde2659ca38cbef70cc067f394cb0..4c8f9210c554220600dd7f40c97ce214ebed2cbf 100644 --- a/indra/newview/skins/default/xui/en/floater_about.xml +++ b/indra/newview/skins/default/xui/en/floater_about.xml @@ -45,6 +45,7 @@ Windows Graphics Driver Version: [GRAPHICS_DRIVER_VERSION] name="AboutLibs"> OpenGL Version: [OPENGL_VERSION] +RestrainedLove API: [RLV_VERSION] libcurl Version: [LIBCURL_VERSION] J2C Decoder Version: [J2C_VERSION] Audio Driver Version: [AUDIO_DRIVER_VERSION] diff --git a/indra/newview/skins/default/xui/en/floater_map.xml b/indra/newview/skins/default/xui/en/floater_map.xml index 6370ff92438cf701c45dc4bcd88d2a704098dbaf..e2f60cec2303b640f5b1f9acb64f5b14d5fcd398 100644 --- a/indra/newview/skins/default/xui/en/floater_map.xml +++ b/indra/newview/skins/default/xui/en/floater_map.xml @@ -18,9 +18,10 @@ left="0" top="0" width="200"> + <!-- RLVa shows the anonimized 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="mini_map_caption"> MINIMAP 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..becdbd2bd38cdd0cfa3f20f7d94ff3464e1daf7f --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_rlv_behaviours.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater can_close="true" can_drag_on_left="false" can_minimize="true" can_resize="true" + height="425" min_height="200" min_width="375" name="rlv_behaviours" title="Active RLV Restrictions" width="350" + save_rect="true" save_visibility="true" single_instance="true"> + <scroll_list top="0" draw_border="false" follows="top|left|bottom|right" height="400" multi_select="false" + name="behaviour_list" draw_heading="true" draw_stripes="true" layout="topleft"> + <scroll_list.columns label="Restriction" name="behaviour" width="170" /> + <scroll_list.columns label="Object Name" name="name" width="170" /> + </scroll_list> +</floater> \ No newline at end of file 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..9472da598191bda8021f3de21348c366c5461643 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_rlv_locks.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater can_close="true" can_drag_on_left="false" can_minimize="true" can_resize="true" + height="425" min_height="200" min_width="375" name="rlvLocks" title="Active RLV Locks" width="350" + save_rect="true" save_visibility="true" single_instance="true"> + <scroll_list top="0" draw_border="false" follows="top|left|bottom|right" height="400" multi_select="false" + name="lock_list" draw_heading="true" draw_stripes="true" layout="topleft"> + <scroll_list.columns label="Lock Type" name="lock_type" width="110" /> + <scroll_list.columns label="Add / Rem" name="lock_addrem" width="75" /> + <scroll_list.columns label="Lock Target" name="lock_target" width="150" /> + <scroll_list.columns label="Held By" name="lock_origin" width="150" /> + </scroll_list> +</floater> \ No newline at end of file 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 b46b62ec4d18e69f5a174b883953467977d8fd87..f7f1bf3c5f9cd75e778224e9a06bc134520c1537 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,9 @@ <menu_item_call.on_click function="ShowAgentProfile" parameter="hit object" /> + <menu_item_call.on_enable + function="RLV.EnableIfNot" + parameter="shownames" /> </menu_item_call> <menu_item_call enabled="false" @@ -24,6 +27,9 @@ name="Send IM..."> <menu_item_call.on_click function="Avatar.SendIM" /> + <menu_item_call.on_enable + function="RLV.EnableIfNot" + parameter="shownames" /> </menu_item_call> <menu_item_call label="Call" @@ -36,8 +42,11 @@ <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.EnableIfNot" + parameter="shownames" /> </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 276b5f106f785799b6b829be611030b47b3e65c3..e344d873e5cb98b427079602c6c5b5589daac778 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,9 @@ <menu_item_call.on_click function="ShowAgentProfile" parameter="hit object" /> + <menu_item_call.on_enable + function="RLV.EnableIfNot" + parameter="shownames" /> </menu_item_call> <menu_item_call enabled="false" @@ -24,6 +27,9 @@ name="Send IM..."> <menu_item_call.on_click function="Avatar.SendIM" /> + <menu_item_call.on_enable + function="RLV.EnableIfNot" + parameter="shownames" /> </menu_item_call> <menu_item_call label="Call" @@ -36,8 +42,11 @@ <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.EnableIfNot" + parameter="shownames" /> </menu_item_call> <menu_item_separator /> <menu_item_call diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index c79a484ef63d5b46f00b71bfe17a8dd3433f152d..c1a3548fd1f4a18abfb01afb522abd161283f38e 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -1426,6 +1426,112 @@ parameter="flexible" /> </menu_item_check> </menu> + <menu + label="RLVa" + name="RLVa" + tear_off="true" + visible="false"> + <menu + label="Debug" + name="Debug" + tear_off="true"> + <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_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="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="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="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 Name Tags" + name="Show Name Tags"> + <menu_item_check.on_check + function="CheckControl" + parameter="RLVaShowNameTags" /> + <menu_item_check.on_click + function="ToggleControl" + parameter="RLVaShowNameTags" /> + </menu_item_check> + <menu_item_separator/> + <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> <menu_item_check label="Use Plugin Read Thread" name="Use Plugin Read Thread"> @@ -1687,7 +1793,14 @@ </menu> <!--Shortcuts--> <menu_item_separator/> - + <menu_item_check + label="RestrainedLove API" + name="RLV API"> + <menu_item_check.on_check + function="RLV.CheckEnabled" /> + <menu_item_check.on_click + function="RLV.ToggleEnabled" /> + </menu_item_check> <menu_item_call label="Show Debug Settings" name="Debug Settings"> 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..aba11e6645bdef6704b7ad881c85a29d50bcaf1d --- /dev/null +++ b/indra/newview/skins/default/xui/en/rlva_strings.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<rlva_strings> + + <strings> + <!-- Primarily used when @showloc restricted --> + <string name="hidden_generic">(Hidden)</string> + <string name="hidden_parcel">(Hidden parcel)</string> + <string name="hidden_region">(Hidden region)</string> + + <!-- Received/sent IMs will be replaced by the matching string when @recvim/sendim restricted --> + <string name="blocked_recvim">*** IM blocked by your viewer</string> + <string name="blocked_sendim">*** IM blocked by sender's viewer</string> + + <!-- Shown as notifications --> + <string name="blocked_viewxxx">Unable to open [TYPE] due to RLV restrictions</string> + + <!-- Sent as "Busy" messages to the remote party --> + <string name="blocked_recvim_remote"> + The Resident you messaged is prevented from reading your instant messages at the moment, please try again later. + </string> + <string name="blocked_tplure_remote"> + The Resident you invited is prevented from accepting teleport offers. Please try again later. + </string> + + <!-- Shown in local chat when dropping inventory onto a nearby agent (moved to strings.xml since it needs to be accesible by LLTrans) --> + <!-- + <string name="inventory_item_offered_rlv"> + Inventory item offered to [NAME] + </string> + --> + </strings> + + <!-- Generic names used to replace resident names when @shownames restricted --> + <anonyms> + <anonym>A resident</anonym> + <anonym>This resident</anonym> + <anonym>That resident</anonym> + <anonym>An individual</anonym> + <anonym>This individual</anonym> + <anonym>That individual</anonym> + <anonym>A person</anonym> + <anonym>This person</anonym> + <anonym>That person</anonym> + <anonym>A stranger</anonym> + <anonym>This stranger</anonym> + <anonym>That stranger</anonym> + <anonym>A being</anonym> + <anonym>This being</anonym> + <anonym>That being</anonym> + <anonym>An agent</anonym> + <anonym>This agent</anonym> + <anonym>That agent</anonym> + <anonym>A soul</anonym> + <anonym>This soul</anonym> + <anonym>That soul</anonym> + <anonym>Somebody</anonym> + <anonym>Some people</anonym> + <anonym>Someone</anonym> + <anonym>Mysterious one</anonym> + <anonym>An unknown being</anonym> + <anonym>Unidentified one</anonym> + <anonym>An unknown person</anonym> + </anonyms> + + <behaviour-notifications> + <!-- + <notification behaviour="defaultwear" type="add">Text goes here</notification> + <notification behaviour="defaultwear" type="rem">Text goes here</notification> + --> + </behaviour-notifications> + +</rlva_strings> diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index cf040b10c7a5add2a8bfc9759c51e6a53d5a6da1..0e813549d9b261b47bf31deb0231022da8cae348 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -3034,6 +3034,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>