aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/rlvhandler.cpp
diff options
context:
space:
mode:
authorMcCabe Maxsted2009-11-08 13:23:54 -0700
committerMcCabe Maxsted2009-11-08 13:23:54 -0700
commitd9ecd6fde8f588d8be9a54a3ebc301bab1e99754 (patch)
tree1f595f7577a5134b29e4933d1ce6b4b52e9c1f57 /linden/indra/newview/rlvhandler.cpp
parentMerged working branch of 1.2 into LL 1.23 merge (diff)
parentChanged version to 1.20 in other files (diff)
downloadmeta-impy-d9ecd6fde8f588d8be9a54a3ebc301bab1e99754.zip
meta-impy-d9ecd6fde8f588d8be9a54a3ebc301bab1e99754.tar.gz
meta-impy-d9ecd6fde8f588d8be9a54a3ebc301bab1e99754.tar.bz2
meta-impy-d9ecd6fde8f588d8be9a54a3ebc301bab1e99754.tar.xz
Merged almost-final version of Imprudence 1.2 into 1.3
Diffstat (limited to 'linden/indra/newview/rlvhandler.cpp')
-rw-r--r--linden/indra/newview/rlvhandler.cpp519
1 files changed, 267 insertions, 252 deletions
diff --git a/linden/indra/newview/rlvhandler.cpp b/linden/indra/newview/rlvhandler.cpp
index 69e2e2f..88cd174 100644
--- a/linden/indra/newview/rlvhandler.cpp
+++ b/linden/indra/newview/rlvhandler.cpp
@@ -31,11 +31,6 @@
31#include "rlvextensions.h" 31#include "rlvextensions.h"
32#include "rlvhandler.h" 32#include "rlvhandler.h"
33 33
34// Only defined in llinventorybridge.cpp
35#if RLV_TARGET < RLV_MAKE_TARGET(1, 23, 0) // Version: 1.22.11
36 #include "llinventorybridge.h"
37 void confirm_replace_attachment_rez(S32 option, void* user_data);
38#endif
39// Only defined in llinventorymodel.cpp 34// Only defined in llinventorymodel.cpp
40extern const char* NEW_CATEGORY_NAME; 35extern const char* NEW_CATEGORY_NAME;
41 36
@@ -66,8 +61,8 @@ const std::string RlvHandler::cstrMsgTpLure =
66const std::string RlvHandler::cstrAnonyms[] = 61const std::string RlvHandler::cstrAnonyms[] =
67{ 62{
68 "A resident", "This resident", "That resident", "An individual", "This individual", "That individual", "A person", 63 "A resident", "This resident", "That resident", "An individual", "This individual", "That individual", "A person",
69 "This person", "That person", "A stranger", "This stranger", "That stranger", "A human being", "This human being", 64 "This person", "That person", "A stranger", "This stranger", "That stranger", "A being", "This being",
70 "That human being", "An agent", "This agent", "That agent", "A soul", "This soul", "That soul", "Somebody", 65 "That being", "An agent", "This agent", "That agent", "A soul", "This soul", "That soul", "Somebody",
71 "Some people", "Someone", "Mysterious one", "An unknown being", "Unidentified one", "An unknown person" 66 "Some people", "Someone", "Mysterious one", "An unknown being", "Unidentified one", "An unknown person"
72}; 67};
73 68
@@ -131,6 +126,7 @@ RlvHandler::~RlvHandler()
131 //delete m_pGCTimer; // <- deletes itself 126 //delete m_pGCTimer; // <- deletes itself
132 delete m_pWLSnapshot; // <- delete on NULL is harmless 127 delete m_pWLSnapshot; // <- delete on NULL is harmless
133 delete m_pBhvrNotify; 128 delete m_pBhvrNotify;
129 delete m_pAttachMgr;
134} 130}
135 131
136// ============================================================================ 132// ============================================================================
@@ -246,7 +242,7 @@ bool RlvHandler::hasLockedHUD() const
246 return false; 242 return false;
247 243
248 LLViewerJointAttachment* pAttachPt; 244 LLViewerJointAttachment* pAttachPt;
249 for (rlv_detach_map_t::const_iterator itAttachPt = m_Attachments.begin(); itAttachPt != m_Attachments.end(); ++itAttachPt) 245 for (rlv_attachlock_map_t::const_iterator itAttachPt = m_AttachRem.begin(); itAttachPt != m_AttachRem.end(); ++itAttachPt)
250 { 246 {
251 pAttachPt = get_if_there(pAvatar->mAttachmentPoints, (S32)itAttachPt->first, (LLViewerJointAttachment*)NULL); 247 pAttachPt = get_if_there(pAvatar->mAttachmentPoints, (S32)itAttachPt->first, (LLViewerJointAttachment*)NULL);
252 if ( (pAttachPt) && (pAttachPt->getIsHUDAttachment()) ) 248 if ( (pAttachPt) && (pAttachPt->getIsHUDAttachment()) )
@@ -255,61 +251,94 @@ bool RlvHandler::hasLockedHUD() const
255 return false; // None of our locked attachments is a HUD 251 return false; // None of our locked attachments is a HUD
256} 252}
257 253
258bool RlvHandler::isDetachable(const LLInventoryItem* pItem) const 254// Checked: 2009-10-10 (RLVa-1.0.5a) | Added: RLVa-1.0.5a
255bool RlvHandler::isLockedAttachment(const LLInventoryItem* pItem, ERlvLockMask eLock) const
259{ 256{
260 LLVOAvatar* pAvatar = gAgent.getAvatarObject(); 257 LLVOAvatar* pAvatar = gAgent.getAvatarObject();
261 return ( (pItem) && (pAvatar) ) ? isDetachable(pAvatar->getWornAttachment(pItem->getUUID())) : true; 258 return (pItem) && (pAvatar) && (isLockedAttachment(pAvatar->getWornAttachment(pItem->getUUID()), eLock));
262} 259}
263 260
264// Checked: 2009-08-11 (RLVa-1.0.1h) | Added: RLVa-1.0.1h 261// Checked: 2009-10-13 (RLVa-1.0.5b) | Added: RLVa-1.0.5b
265bool RlvHandler::isDetachableExcept(S32 idxAttachPt, LLViewerObject *pObj) const 262bool RlvHandler::isLockedAttachmentExcept(S32 idxAttachPt, ERlvLockMask eLock, LLViewerObject *pObj) const
266{ 263{
267 // Loop over every object that marked the specific attachment point undetachable (but ignore pObj and any of its children) 264 // Loop over every object that marked the specific attachment point eLock type locked (but ignore pObj and any of its children)
268 for (rlv_detach_map_t::const_iterator itAttach = m_Attachments.lower_bound(idxAttachPt), 265 LLViewerObject* pTempObj;
269 endAttach = m_Attachments.upper_bound(idxAttachPt); itAttach != endAttach; ++itAttach) 266 if (eLock & RLV_LOCK_REMOVE)
270 { 267 {
271 LLViewerObject* pTempObj = gObjectList.findObject(itAttach->second); 268 for (rlv_attachlock_map_t::const_iterator itAttach = m_AttachRem.lower_bound(idxAttachPt),
272 if ( (!pTempObj) || (pTempObj->getRootEdit()->getID() != pObj->getID()) ) 269 endAttach = m_AttachRem.upper_bound(idxAttachPt); itAttach != endAttach; ++itAttach)
273 return false; 270 {
271 if ( ((pTempObj = gObjectList.findObject(itAttach->second)) == NULL) || (pTempObj->getRootEdit()->getID() != pObj->getID()) )
272 return true;
273 }
274 } 274 }
275 return true; 275 if (eLock & RLV_LOCK_ADD)
276 {
277 for (rlv_attachlock_map_t::const_iterator itAttach = m_AttachAdd.lower_bound(idxAttachPt),
278 endAttach = m_AttachAdd.upper_bound(idxAttachPt); itAttach != endAttach; ++itAttach)
279 {
280 if ( ((pTempObj = gObjectList.findObject(itAttach->second)) == NULL) || (pTempObj->getRootEdit()->getID() != pObj->getID()) )
281 return true;
282 }
283 }
284 return false;
276} 285}
277 286
278// Checked: 2009-09-06 (RLVa-1.0.2b) | Modified: RLVa-1.0.2b 287// Checked: 2009-10-10 (RLVa-1.0.5a) | Added: RLVa-1.0.5a
279bool RlvHandler::setDetachable(S32 idxAttachPt, const LLUUID& idRlvObj, bool fDetachable) 288void RlvHandler::addAttachmentLock(S32 idxAttachPt, const LLUUID &idRlvObj, ERlvLockMask eLock)
280{ 289{
281 // Sanity check - make sure it's an object we know about 290 // Sanity check - make sure it's an object we know about
282 rlv_object_map_t::const_iterator itObj = m_Objects.find(idRlvObj); 291 if ( (m_Objects.find(idRlvObj) == m_Objects.end()) || (!idxAttachPt) )
283 if ( (itObj == m_Objects.end()) || (!idxAttachPt) ) 292 return; // If (idxAttachPt) == 0 then: (pObj == NULL) || (pObj->isAttachment() == FALSE)
284 return false; // If (idxAttachPt) == 0 then: (pObj == NULL) || (pObj->isAttachment() == FALSE)
285 293
286 if (!fDetachable) 294 // NOTE: m_AttachXXX can contain duplicate <idxAttachPt, idRlvObj> pairs (ie @detach:spine=n,detach=n from an attachment on spine)
295 if (eLock & RLV_LOCK_REMOVE)
287 { 296 {
288 #ifdef RLV_EXPERIMENTAL_FIRSTUSE 297 #ifdef RLV_EXPERIMENTAL_FIRSTUSE
289 //LLFirstUse::useRlvDetach(); 298 //LLFirstUse::useRlvDetach();
290 #endif // RLV_EXPERIMENTAL_FIRSTUSE 299 #endif // RLV_EXPERIMENTAL_FIRSTUSE
291 300
292 // NOTE: m_Attachments can contain duplicate <idxAttachPt, idRlvObj> pairs (ie @detach:spine=n,detach=n from an attachment on spine) 301 m_AttachRem.insert(std::pair<S32, LLUUID>(idxAttachPt, idRlvObj));
293 m_Attachments.insert(std::pair<S32, LLUUID>(idxAttachPt, itObj->second.m_UUID));
294 return true;
295 } 302 }
296 else 303 if (eLock & RLV_LOCK_ADD)
297 { 304 {
298 for (rlv_detach_map_t::iterator itAttach = m_Attachments.lower_bound(idxAttachPt), 305 m_AttachAdd.insert(std::pair<S32, LLUUID>(idxAttachPt, idRlvObj));
299 endAttach = m_Attachments.upper_bound(idxAttachPt); itAttach != endAttach; ++itAttach) 306 }
307}
308
309// Checked: 2009-10-10 (RLVa-1.0.5a) | Added: RLVa-1.0.5a
310void RlvHandler::removeAttachmentLock(S32 idxAttachPt, const LLUUID &idRlvObj, ERlvLockMask eLock)
311{
312 // Sanity check - make sure it's an object we know about
313 if ( (m_Objects.find(idRlvObj) == m_Objects.end()) || (!idxAttachPt) )
314 return; // If (idxAttachPt) == 0 then: (pObj == NULL) || (pObj->isAttachment() == FALSE)
315
316 if (eLock & RLV_LOCK_REMOVE)
317 {
318 for (rlv_attachlock_map_t::iterator itAttach = m_AttachRem.lower_bound(idxAttachPt),
319 endAttach = m_AttachRem.upper_bound(idxAttachPt); itAttach != endAttach; ++itAttach)
300 { 320 {
301 if (itObj->second.m_UUID == itAttach->second) 321 if (idRlvObj == itAttach->second)
302 { 322 {
303 m_Attachments.erase(itAttach); 323 m_AttachRem.erase(itAttach);
304 return true; 324 break;
325 }
326 }
327 }
328 if (eLock & RLV_LOCK_ADD)
329 {
330 for (rlv_attachlock_map_t::iterator itAttach = m_AttachAdd.lower_bound(idxAttachPt),
331 endAttach = m_AttachAdd.upper_bound(idxAttachPt); itAttach != endAttach; ++itAttach)
332 {
333 if (idRlvObj == itAttach->second)
334 {
335 m_AttachAdd.erase(itAttach);
336 break;
305 } 337 }
306 } 338 }
307 } 339 }
308 return false; // Fall-through for (fDetachable == TRUE) - if the object wasn't undetachable then we consider it a failure
309} 340}
310 341
311
312
313#ifdef RLV_EXTENSION_FLAG_NOSTRIP 342#ifdef RLV_EXTENSION_FLAG_NOSTRIP
314 // Checked: 2009-05-26 (RLVa-0.2.0d) | Modified: RLVa-0.2.0d 343 // Checked: 2009-05-26 (RLVa-0.2.0d) | Modified: RLVa-0.2.0d
315 bool RlvHandler::isStrippable(const LLUUID& idItem) const 344 bool RlvHandler::isStrippable(const LLUUID& idItem) const
@@ -413,10 +442,10 @@ void RlvHandler::notifyBehaviourObservers(const RlvCommand& rlvCmd, bool fIntern
413} 442}
414 443
415// Checked: 444// Checked:
416BOOL RlvHandler::processCommand(const LLUUID& uuid, const std::string& strCmd, bool fFromObj) 445BOOL RlvHandler::processCommand(const LLUUID& idObj, const std::string& strCmd, bool fFromObj)
417{ 446{
418 #ifdef RLV_DEBUG 447 #ifdef RLV_DEBUG
419 RLV_INFOS << "[" << uuid << "]: " << strCmd << LL_ENDL; 448 RLV_INFOS << "[" << idObj << "]: " << strCmd << LL_ENDL;
420 #endif // RLV_DEBUG 449 #endif // RLV_DEBUG
421 450
422 RlvCommand rlvCmd(strCmd); 451 RlvCommand rlvCmd(strCmd);
@@ -427,7 +456,10 @@ BOOL RlvHandler::processCommand(const LLUUID& uuid, const std::string& strCmd, b
427 #endif // RLV_DEBUG 456 #endif // RLV_DEBUG
428 return FALSE; 457 return FALSE;
429 } 458 }
430 m_pCurCommand = &rlvCmd; m_idCurObject = uuid; 459
460 // NOTE: if we pass RlvObject::m_UUID for idObj somewhere and process a @clear then it will point to invalid/cleared memory at the end
461 // so make sure to *always* pass our private copy to other functions
462 m_pCurCommand = &rlvCmd; m_idCurObject = idObj;
431 463
432 BOOL fRet = FALSE; 464 BOOL fRet = FALSE;
433 switch (rlvCmd.getParamType()) 465 switch (rlvCmd.getParamType())
@@ -444,7 +476,7 @@ BOOL RlvHandler::processCommand(const LLUUID& uuid, const std::string& strCmd, b
444 break; 476 break;
445 } 477 }
446 478
447 rlv_object_map_t::iterator itObj = m_Objects.find(uuid); 479 rlv_object_map_t::iterator itObj = m_Objects.find(m_idCurObject);
448 if (itObj != m_Objects.end()) 480 if (itObj != m_Objects.end())
449 { 481 {
450 RlvObject& rlvObj = itObj->second; 482 RlvObject& rlvObj = itObj->second;
@@ -452,9 +484,9 @@ BOOL RlvHandler::processCommand(const LLUUID& uuid, const std::string& strCmd, b
452 } 484 }
453 else 485 else
454 { 486 {
455 RlvObject rlvObj(uuid); 487 RlvObject rlvObj(m_idCurObject);
456 fRet = rlvObj.addCommand(rlvCmd); 488 fRet = rlvObj.addCommand(rlvCmd);
457 m_Objects.insert(std::pair<LLUUID, RlvObject>(uuid, rlvObj)); 489 m_Objects.insert(std::pair<LLUUID, RlvObject>(m_idCurObject, rlvObj));
458 } 490 }
459 491
460 #ifdef RLV_DEBUG 492 #ifdef RLV_DEBUG
@@ -464,14 +496,14 @@ BOOL RlvHandler::processCommand(const LLUUID& uuid, const std::string& strCmd, b
464 if (fRet) { // If FALSE then this was a duplicate, there's no need to handle those 496 if (fRet) { // If FALSE then this was a duplicate, there's no need to handle those
465 if (!m_pGCTimer) 497 if (!m_pGCTimer)
466 m_pGCTimer = new RlvGCTimer(); 498 m_pGCTimer = new RlvGCTimer();
467 processAddCommand(uuid, rlvCmd); 499 processAddCommand(m_idCurObject, rlvCmd);
468 notifyBehaviourObservers(rlvCmd, !fFromObj); 500 notifyBehaviourObservers(rlvCmd, !fFromObj);
469 } 501 }
470 } 502 }
471 break; 503 break;
472 case RLV_TYPE_REMOVE: // Checked: 504 case RLV_TYPE_REMOVE: // Checked:
473 { 505 {
474 rlv_object_map_t::iterator itObj = m_Objects.find(uuid); 506 rlv_object_map_t::iterator itObj = m_Objects.find(m_idCurObject);
475 if (itObj != m_Objects.end()) 507 if (itObj != m_Objects.end())
476 fRet = itObj->second.removeCommand(rlvCmd); 508 fRet = itObj->second.removeCommand(rlvCmd);
477 509
@@ -481,13 +513,13 @@ BOOL RlvHandler::processCommand(const LLUUID& uuid, const std::string& strCmd, b
481 #endif // RLV_DEBUG 513 #endif // RLV_DEBUG
482 514
483 if (fRet) { // Don't handle non-sensical removes 515 if (fRet) { // Don't handle non-sensical removes
484 processRemoveCommand(uuid, rlvCmd); 516 processRemoveCommand(m_idCurObject, rlvCmd);
485 notifyBehaviourObservers(rlvCmd, !fFromObj); 517 notifyBehaviourObservers(rlvCmd, !fFromObj);
486 518
487 if (0 == itObj->second.m_Commands.size()) 519 if (0 == itObj->second.m_Commands.size())
488 { 520 {
489 #ifdef RLV_DEBUG 521 #ifdef RLV_DEBUG
490 RLV_INFOS << "\t- command list empty => removing " << uuid << LL_ENDL; 522 RLV_INFOS << "\t- command list empty => removing " << m_idCurObject << LL_ENDL;
491 #endif // RLV_DEBUG 523 #endif // RLV_DEBUG
492 m_Objects.erase(itObj); 524 m_Objects.erase(itObj);
493 } 525 }
@@ -495,14 +527,14 @@ BOOL RlvHandler::processCommand(const LLUUID& uuid, const std::string& strCmd, b
495 } 527 }
496 break; 528 break;
497 case RLV_TYPE_CLEAR: 529 case RLV_TYPE_CLEAR:
498 fRet = processClearCommand(uuid, rlvCmd); 530 fRet = processClearCommand(m_idCurObject, rlvCmd);
499 notifyBehaviourObservers(rlvCmd, !fFromObj); 531 notifyBehaviourObservers(rlvCmd, !fFromObj);
500 break; 532 break;
501 case RLV_TYPE_FORCE: // Checked: 533 case RLV_TYPE_FORCE: // Checked:
502 fRet = processForceCommand(uuid, rlvCmd); 534 fRet = processForceCommand(m_idCurObject, rlvCmd);
503 break; 535 break;
504 case RLV_TYPE_REPLY: // Checked: 536 case RLV_TYPE_REPLY: // Checked:
505 fRet = processReplyCommand(uuid, rlvCmd); 537 fRet = processReplyCommand(m_idCurObject, rlvCmd);
506 break; 538 break;
507 case RLV_TYPE_UNKNOWN: // Checked: 539 case RLV_TYPE_UNKNOWN: // Checked:
508 break; 540 break;
@@ -535,35 +567,15 @@ BOOL RlvHandler::processAddCommand(const LLUUID& uuid, const RlvCommand& rlvCmd)
535 m_Behaviours[eBehaviour]++; 567 m_Behaviours[eBehaviour]++;
536 } 568 }
537 569
570 bool fRefCount = false; // Unused for the moment
538 switch (eBehaviour) 571 switch (eBehaviour)
539 { 572 {
540 case RLV_BHVR_DETACH: // @detach[:<option>]=n - Checked: 2009-08-04 (RLVa-1.0.1d) | Modified: RLVa-1.0.1d 573 case RLV_BHVR_DETACH: // @detach[:<option>]=n - Checked: 2009-10-10 (RLVa-1.0.5a) | Modified: RLVa-1.0.5a
541 { 574 onAddRemDetach(uuid, rlvCmd, fRefCount);
542 LLViewerObject* pObj = NULL; S32 idxAttachPt = 0; 575 break;
543 if (strOption.empty()) // @detach=n 576 case RLV_BHVR_ADDATTACH: // @addattach[:<option>]=n - Checked: 2009-10-10 (RLVa-1.0.5a) | Added: RLVa-1.0.5a
544 { 577 case RLV_BHVR_REMATTACH: // @addattach[:<option>]=n - Checked: 2009-10-10 (RLVa-1.0.5a) | Added: RLVa-1.0.5a
545 // If the object rezzed before we received @detach=n from it then we can just do our thing here 578 onAddRemAttach(uuid, rlvCmd, fRefCount);
546 // If the object hasn't rezzed yet then we need to wait until RlvHandler::onAttach()
547 // If @detach=n were possible for non-attachments another copy/paste would be needed in RlvHandler::onGC()
548 if ((pObj = gObjectList.findObject(uuid)) != NULL)
549 setDetachable(pObj, uuid, false);
550 }
551 else if ((idxAttachPt = getAttachPointIndex(strOption, true)) != 0) // @detach:<attachpt>=n
552 {
553 setDetachable(idxAttachPt, uuid, false);
554
555 // (See below)
556 LLViewerJointAttachment* pAttachPt = getAttachPoint(strOption, true);
557 if (pAttachPt)
558 pObj = pAttachPt->getObject();
559 }
560
561 // When at least one HUD attachment is locked we want to make sure they're all visible (ie prevent hiding a blindfold HUD)
562 // However, since @detach:<attachpt>=n might lock a HUD attachment point that doesn't currently have an object we
563 // have to do this here *and* in RlvHandler::onAttach()
564 if ( (pObj) && (pObj->isHUDAttachment()) )
565 LLPipeline::sShowHUDAttachments = TRUE;
566 }
567 break; 579 break;
568 case RLV_BHVR_REDIRCHAT: // @redirchat:<option>=n - Checked: 2009-07-07 (RLVa-1.0.0d) 580 case RLV_BHVR_REDIRCHAT: // @redirchat:<option>=n - Checked: 2009-07-07 (RLVa-1.0.0d)
569 case RLV_BHVR_REDIREMOTE: // @rediremote:<option>=n - Checked: 2009-07-07 (RLVa-1.0.0d) | Added: RLVa-0.2.2a 581 case RLV_BHVR_REDIREMOTE: // @rediremote:<option>=n - Checked: 2009-07-07 (RLVa-1.0.0d) | Added: RLVa-0.2.2a
@@ -797,25 +809,15 @@ BOOL RlvHandler::processRemoveCommand(const LLUUID& uuid, const RlvCommand& rlvC
797 m_Behaviours[eBehaviour]--; 809 m_Behaviours[eBehaviour]--;
798 } 810 }
799 811
812 bool fRefCount = false; // Unused for the moment
800 switch (eBehaviour) 813 switch (eBehaviour)
801 { 814 {
802 case RLV_BHVR_DETACH: // @detach[:<option>]=y - Checked: 2009-08-04 (RLVa-1.0.1d) | Modified: RLVa-1.0.1d 815 case RLV_BHVR_DETACH: // @detach[:<option>]=y - Checked: 2009-10-10 (RLVa-1.0.5a) | Modified: RLVa-1.0.5a
803 { 816 onAddRemDetach(uuid, rlvCmd, fRefCount);
804 S32 idxAttachPt = 0; 817 break;
805 if (strOption.empty()) // @detach=y 818 case RLV_BHVR_ADDATTACH: // @addattach[:<option>]=y - Checked: 2009-10-10 (RLVa-1.0.5a) | Added: RLVa-1.0.5a
806 { 819 case RLV_BHVR_REMATTACH: // @addattach[:<option>]=y - Checked: 2009-10-10 (RLVa-1.0.5a) | Added: RLVa-1.0.5a
807 // The object may or may not (if it got detached) still exist 820 onAddRemAttach(uuid, rlvCmd, fRefCount);
808 rlv_object_map_t::const_iterator itObj = m_Objects.find(uuid);
809 if (itObj != m_Objects.end())
810 idxAttachPt = itObj->second.m_idxAttachPt;
811 if (idxAttachPt)
812 setDetachable(idxAttachPt, uuid, true);
813 }
814 else if ((idxAttachPt = getAttachPointIndex(strOption, true))) // @detach:<attachpt>=y
815 {
816 setDetachable(idxAttachPt, uuid, true);
817 }
818 }
819 break; 821 break;
820 case RLV_BHVR_REDIRCHAT: // @redirchat:<option>=y - Checked: 2009-07-07 (RLVa-1.0.0d) 822 case RLV_BHVR_REDIRCHAT: // @redirchat:<option>=y - Checked: 2009-07-07 (RLVa-1.0.0d)
821 case RLV_BHVR_REDIREMOTE: // @rediremote:<option>=y - Checked: 2009-07-07 (RLVa-1.0.0d) | Added: RLVa-0.2.2a 823 case RLV_BHVR_REDIREMOTE: // @rediremote:<option>=y - Checked: 2009-07-07 (RLVa-1.0.0d) | Added: RLVa-0.2.2a
@@ -940,7 +942,7 @@ BOOL RlvHandler::processRemoveCommand(const LLUUID& uuid, const RlvCommand& rlvC
940 return TRUE; // Remove commands don't fail, doesn't matter what we return here 942 return TRUE; // Remove commands don't fail, doesn't matter what we return here
941} 943}
942 944
943BOOL RlvHandler::processClearCommand(const LLUUID& idObj, const RlvCommand& rlvCmd) 945BOOL RlvHandler::processClearCommand(const LLUUID idObj, const RlvCommand& rlvCmd)
944{ 946{
945 const std::string& strFilter = rlvCmd.getParam(); std::string strCmdRem; 947 const std::string& strFilter = rlvCmd.getParam(); std::string strCmdRem;
946 948
@@ -976,8 +978,11 @@ BOOL RlvHandler::processForceCommand(const LLUUID& idObj, const RlvCommand& rlvC
976 978
977 switch (rlvCmd.getBehaviourType()) 979 switch (rlvCmd.getBehaviourType())
978 { 980 {
979 case RLV_BHVR_DETACH: // @detach[:<option>]=force - Checked: 981 case RLV_BHVR_DETACH: // @detach[:<option>]=force - Checked: 2009-10-12 (RLVa-1.0.5a) | Modified: RLVa-1.0.5a
980 onForceDetach(idObj, strOption); 982 onForceDetach(idObj, rlvCmd);
983 break;
984 case RLV_BHVR_REMATTACH: // @remattach[:<option>]=force - Checked: 2009-10-12 (RLVa-1.0.5a) | Modified: RLVa-1.0.5a
985 onForceRemAttach(idObj, rlvCmd);
981 break; 986 break;
982 case RLV_BHVR_REMOUTFIT: // @remoutfit:<option>=force - Checked: 987 case RLV_BHVR_REMOUTFIT: // @remoutfit:<option>=force - Checked:
983 onForceRemOutfit(idObj, strOption); 988 onForceRemOutfit(idObj, strOption);
@@ -1125,7 +1130,7 @@ BOOL RlvHandler::processReplyCommand(const LLUUID& uuid, const RlvCommand& rlvCm
1125 #endif // RLV_EXPERIMENTAL_COMPOSITE_FOLDING 1130 #endif // RLV_EXPERIMENTAL_COMPOSITE_FOLDING
1126 } 1131 }
1127 break; 1132 break;
1128 case RLV_BHVR_GETATTACH: // @getattach[:<layer>]=<channel> - Checked: 2009-07-12 (RLVa-1.0.0h) | Modified: RLVa-0.2.0d 1133 case RLV_BHVR_GETATTACH: // @getattach[:<layer>]=<channel> - Checked: 2009-10-10 (RLVa-1.0.5a) | Modified: RLVa-1.0.5a
1129 { 1134 {
1130 // If we're fetching all worn attachments then the reply should start with 0 1135 // If we're fetching all worn attachments then the reply should start with 0
1131 if (strOption.empty()) 1136 if (strOption.empty())
@@ -1155,9 +1160,9 @@ BOOL RlvHandler::processReplyCommand(const LLUUID& uuid, const RlvCommand& rlvCm
1155 { 1160 {
1156 bool fWorn = (pAttachment->getItemID().notNull()) && 1161 bool fWorn = (pAttachment->getItemID().notNull()) &&
1157 ( (!RlvSettings::getHideLockedAttach()) || 1162 ( (!RlvSettings::getHideLockedAttach()) ||
1158 ( (isDetachable(itAttach->first)) && (isStrippable(pAttachment->getItemID())) ) ); 1163 ( (!isLockedAttachmentExcept(itAttach->first, RLV_LOCK_REMOVE, gObjectList.findObject(uuid))) &&
1164 (isStrippable(pAttachment->getItemID())) ) );
1159 strReply.push_back( (fWorn) ? '1' : '0' ); 1165 strReply.push_back( (fWorn) ? '1' : '0' );
1160 //strReply.push_back( (pAttachment->getItemID().notNull()) ? '1' : '0' );
1161 } 1166 }
1162 #endif // RLV_EXPERIMENTAL_COMPOSITE_FOLDING 1167 #endif // RLV_EXPERIMENTAL_COMPOSITE_FOLDING
1163 } 1168 }
@@ -1327,7 +1332,7 @@ void RlvHandler::initLookupTables()
1327} 1332}
1328 1333
1329// Checked: 2009-08-11 (RLVa-1.0.1h) | Modified: RLVa-1.0.1h 1334// Checked: 2009-08-11 (RLVa-1.0.1h) | Modified: RLVa-1.0.1h
1330void RlvHandler::onAttach(LLViewerJointAttachment* pAttachPt, bool fFullyLoaded) 1335void RlvHandler::onAttach(LLViewerJointAttachment* pAttachPt)
1331{ 1336{
1332 // Sanity check - LLVOAvatar::attachObject() should call us *after* calling LLViewerJointAttachment::addObject() 1337 // Sanity check - LLVOAvatar::attachObject() should call us *after* calling LLViewerJointAttachment::addObject()
1333 LLViewerObject* pObj = pAttachPt->getObject(); 1338 LLViewerObject* pObj = pAttachPt->getObject();
@@ -1338,30 +1343,8 @@ void RlvHandler::onAttach(LLViewerJointAttachment* pAttachPt, bool fFullyLoaded)
1338 return; 1343 return;
1339 } 1344 }
1340 1345
1341 // Check if this attachment point has a pending "reattach-on-detach" 1346 // Let the attachment manager know
1342 rlv_reattach_map_t::iterator itReattach = m_AttachPending.find(idxAttachPt); 1347 m_pAttachMgr->onAttach(pAttachPt);
1343 if (itReattach != m_AttachPending.end())
1344 {
1345 if (itReattach->second == pAttachPt->getItemID())
1346 {
1347 RLV_INFOS << "Reattached " << pAttachPt->getItemID().asString() << " to " << idxAttachPt << LL_ENDL;
1348 m_AttachPending.erase(itReattach);
1349 }
1350 }
1351 else if ( (fFullyLoaded) && (!isDetachableExcept(idxAttachPt, pObj)) )
1352 {
1353 // We're fully loaded with no pending reattach on this attach point but it's "undetachable" -> force detach the new attachment
1354
1355 // Assertion: the only way the attachment point could be locked at this point is if some object locked it with @detach:attachpt=n
1356 // - previous attachments on this attachment point might have issued @detach=n but those were all cleaned up at detach
1357 // - the new attachment might have issued @detach=n but that won't actually lock down the attachment point until further down
1358 // NOTE 1: "some object" may no longer exist if it was not an attachment and the GC hasn't cleaned it up yet (informative)
1359 // NOTE 2: "some object" may refer to the new attachment - ie @detach:spine=n from object on spine (problematic, causes reattach)
1360 // -> solved by using isDetachableExcept(idxAttachPt, pObj) instead of isDetachable(idxAttachPt)
1361
1362 m_DetachPending.insert(std::pair<S32, LLUUID>(idxAttachPt, pObj->getID()));
1363 rlvForceDetach(pAttachPt);
1364 }
1365 1348
1366 // Check if we already have an RlvObject instance for this object (rezzed prim attached from in-world, or an attachment that rezzed in) 1349 // Check if we already have an RlvObject instance for this object (rezzed prim attached from in-world, or an attachment that rezzed in)
1367 rlv_object_map_t::iterator itObj = m_Objects.find(pObj->getID()); 1350 rlv_object_map_t::iterator itObj = m_Objects.find(pObj->getID());
@@ -1378,7 +1361,7 @@ void RlvHandler::onAttach(LLViewerJointAttachment* pAttachPt, bool fFullyLoaded)
1378 if (itObj->second.hasBehaviour(RLV_BHVR_DETACH, false)) 1361 if (itObj->second.hasBehaviour(RLV_BHVR_DETACH, false))
1379 { 1362 {
1380 // (Copy/paste from processAddCommand) 1363 // (Copy/paste from processAddCommand)
1381 setDetachable(idxAttachPt, pObj->getID(), false); 1364 addAttachmentLock(idxAttachPt, itObj->second.m_UUID, RLV_LOCK_REMOVE);
1382 1365
1383 if (pObj->isHUDAttachment()) 1366 if (pObj->isHUDAttachment())
1384 LLPipeline::sShowHUDAttachments = TRUE; // Prevents hiding of locked HUD attachments 1367 LLPipeline::sShowHUDAttachments = TRUE; // Prevents hiding of locked HUD attachments
@@ -1469,44 +1452,19 @@ void RlvHandler::onDetach(LLViewerJointAttachment* pAttachPt)
1469 //RLV_INFOS << "Clean up for '" << pDbgAttachmentPt->getName() << "'" << LL_ENDL; 1452 //RLV_INFOS << "Clean up for '" << pDbgAttachmentPt->getName() << "'" << LL_ENDL;
1470 #endif // RLV_DEBUG 1453 #endif // RLV_DEBUG
1471 1454
1472 // If the attachment was locked then we should reattach it (unless we're already trying to reattach to this attachment point) 1455 // Let the attachment manager know
1473 // (unless we forcefully detached it else in which case we do not want to reattach it) 1456 m_pAttachMgr->onDetach(pAttachPt);
1474 rlv_reattach_map_t::iterator itDetach = m_DetachPending.find(idxAttachPt);
1475 if (itDetach != m_DetachPending.end())
1476 {
1477 // RLVa-TODO: we should really be comparing item UUIDs but is it even possible to end up here and not have them match?
1478 m_DetachPending.erase(itDetach);
1479 }
1480 else if ( (!isDetachable(idxAttachPt)) && (m_AttachPending.find(idxAttachPt) == m_AttachPending.end()) )
1481 {
1482 // In an ideal world we would simply set up an LLInventoryObserver but there's no specific "asset updated" changed flag *sighs*
1483 // NOTE: attachments *always* know their "inventory item UUID" so we don't have to worry about fetched vs unfetched inventory
1484 m_AttachPending.insert(std::pair<S32, LLUUID>(idxAttachPt, pAttachPt->getItemID()));
1485 }
1486 1457
1487 // We can't - easily - clean up child prims that never issued @detach=n but the GC will get those eventually 1458 // Clean up any restriction this object (or one of its child prims) may have
1488 rlv_detach_map_t::iterator itAttach = m_Attachments.find(idxAttachPt); 1459 rlv_object_map_t::iterator itObj = m_Objects.begin(), itCurrent;
1489 while ( (itAttach != m_Attachments.upper_bound(idxAttachPt)) && (itAttach != m_Attachments.end()) ) 1460 while (itObj != m_Objects.end())
1490 { 1461 {
1491 LLViewerObject* pTempObj = gObjectList.findObject(itAttach->second); 1462 itCurrent = itObj++; // @clear will invalidate our iterator so point it ahead now
1492 if ( (pTempObj) && (pTempObj->getRootEdit()->getID() == pObj->getID()) )
1493 {
1494 // Iterator points to the object (or to a child prim) so issue a clear on behalf of the object (there's the
1495 // possibility of going into an eternal loop, but that's ok since it indicates a bug in @clear that needs fixing)
1496 processCommand(itAttach->second, "clear", true);
1497 1463
1498 itAttach = m_Attachments.find(idxAttachPt); // @clear will invalidate all iterators so we have to start anew 1464 // NOTE: ObjectKill seems to happen in reverse (child prims are killed before the root is) so we can't use gObjectList here
1499 } 1465 if (itCurrent->second.m_idxAttachPt == idxAttachPt)
1500 else 1466 processCommand(itCurrent->second.m_UUID, "clear", true);
1501 {
1502 itAttach++;
1503 }
1504 } 1467 }
1505
1506 // Clean up in case there was never a @detach=n (only works for the root prim - see above)
1507 rlv_object_map_t::iterator itObj = m_Objects.find(pObj->getID());
1508 if (itObj != m_Objects.end())
1509 processCommand(itObj->second.m_UUID, "clear", true);
1510} 1468}
1511 1469
1512// Checked: 2009-07-30 (RLVa-1.0.1c) | Modified: RLVa-1.0.1c 1470// Checked: 2009-07-30 (RLVa-1.0.1c) | Modified: RLVa-1.0.1c
@@ -1548,32 +1506,6 @@ bool RlvHandler::onGC()
1548 return (0 != m_Objects.size()); // GC will kill itself if it has nothing to do 1506 return (0 != m_Objects.size()); // GC will kill itself if it has nothing to do
1549} 1507}
1550 1508
1551// Checked: 2009-08-08 (RLVa-1.0.1g) | Modified: RLVa-1.0.1g
1552void RlvHandler::onSavedAssetIntoInventory(const LLUUID& idItem)
1553{
1554 for (rlv_reattach_map_t::iterator itAttach = m_AttachPending.begin(); itAttach != m_AttachPending.end(); ++itAttach)
1555 {
1556 if (idItem == itAttach->second)
1557 {
1558 RLV_INFOS << "Reattaching " << idItem.asString() << " to " << itAttach->first << LL_ENDL;
1559
1560 #if RLV_TARGET < RLV_MAKE_TARGET(1, 23, 0) // Version: 1.22.11
1561 LLAttachmentRezAction* rez_action = new LLAttachmentRezAction;
1562 rez_action->mItemID = itAttach->second;
1563 rez_action->mAttachPt = itAttach->first;
1564
1565 confirm_replace_attachment_rez(0/*YES*/, (void*)rez_action); // (Will call delete on rez_action)
1566 #else // Version: 1.23.4
1567 LLSD payload;
1568 payload["item_id"] = itAttach->second;
1569 payload["attachment_point"] = itAttach->first;
1570
1571 LLNotifications::instance().forceResponse(LLNotification::Params("ReplaceAttachment").payload(payload), 0/*YES*/);
1572 #endif
1573 }
1574 }
1575}
1576
1577// ============================================================================ 1509// ============================================================================
1578// String/chat censoring functions 1510// String/chat censoring functions
1579// 1511//
@@ -2099,47 +2031,6 @@ std::string RlvHandler::getSharedPath(const LLViewerInventoryCategory* pFolder)
2099// 2031//
2100 2032
2101// Checked: 2009-07-12 (RLVa-1.0.0h) | Modified: RLVa-0.2.0d 2033// Checked: 2009-07-12 (RLVa-1.0.0h) | Modified: RLVa-0.2.0d
2102void RlvHandler::onForceDetach(const LLUUID& idObj, const std::string& strOption) const
2103{
2104 U16 nParam;
2105 if (strOption.empty())
2106 {
2107 // Simulate right-click / Take Off > Detach All
2108 LLAgent::userRemoveAllAttachments(NULL);
2109 }
2110 else if (m_AttachLookup.getExactMatchParam(strOption, nParam))
2111 {
2112 // Simulate right-click / Take Off > Detach > ...
2113 LLVOAvatar* pAvatar; LLViewerJointAttachment* pAttachmentPt;
2114 if ( ((pAvatar = gAgent.getAvatarObject()) != NULL) && // Make sure we're actually wearing something on the attachment point
2115 ((pAttachmentPt = get_if_there(pAvatar->mAttachmentPoints, (S32)nParam, (LLViewerJointAttachment*)NULL)) != NULL) &&
2116 (isStrippable(pAttachmentPt->getItemID())) ) // ... and that it's not marked as "nostrip"
2117 {
2118 #ifdef RLV_EXPERIMENTAL_COMPOSITES
2119 // If we're stripping something that's part of a composite folder then we should @detachthis instead
2120 if (isCompositeDescendent(pAttachmentPt->getItemID()))
2121 {
2122 std::string strCmd = "detachthis:" + strOption + "=force";
2123 #ifdef RLV_DEBUG
2124 RLV_INFOS << "\t- '" << strOption << "' belongs to composite folder: @" << strCmd << LL_ENDL;
2125 #endif // RLV_DEBUG
2126 processForceCommand(idObj, RlvCommand(strCmd));
2127 }
2128 else
2129 #endif // RLV_EXPERIMENTAL_COMPOSITES
2130 {
2131 handle_detach_from_avatar(pAttachmentPt);
2132 }
2133 }
2134 }
2135 else
2136 {
2137 // Force detach single folder
2138 onForceWear(strOption, false, false);
2139 }
2140}
2141
2142// Checked: 2009-07-12 (RLVa-1.0.0h) | Modified: RLVa-0.2.0d
2143void RlvHandler::onForceRemOutfit(const LLUUID& idObj, const std::string& strOption) const 2034void RlvHandler::onForceRemOutfit(const LLUUID& idObj, const std::string& strOption) const
2144{ 2035{
2145 EWearableType typeOption = LLWearable::typeNameToType(strOption), type; 2036 EWearableType typeOption = LLWearable::typeNameToType(strOption), type;
@@ -2209,6 +2100,7 @@ bool RlvHandler::onForceSit(const LLUUID& idObj, const std::string& strOption) c
2209 return true; 2100 return true;
2210} 2101}
2211 2102
2103// Checked: 2009-10-10 (RLVa-1.0.5a) | Modified: RLVa-1.0.5a
2212void RlvHandler::onForceWear(const std::string& strPath, bool fAttach, bool fMatchAll) const 2104void RlvHandler::onForceWear(const std::string& strPath, bool fAttach, bool fMatchAll) const
2213{ 2105{
2214 // See LLWearableBridge::wearOnAvatar(): don't wear anything until initial wearables are loaded, can destroy clothing items 2106 // See LLWearableBridge::wearOnAvatar(): don't wear anything until initial wearables are loaded, can destroy clothing items
@@ -2281,22 +2173,11 @@ void RlvHandler::onForceWear(const std::string& strPath, bool fAttach, bool fMat
2281 // Simulate wearing an object to a specific attachment point (copy/paste to suppress replacement dialog) 2173 // Simulate wearing an object to a specific attachment point (copy/paste to suppress replacement dialog)
2282 // LLAttachObject::handleEvent() => rez_attachment() 2174 // LLAttachObject::handleEvent() => rez_attachment()
2283 LLViewerJointAttachment* pAttachPt = getAttachPoint(pItem, true); 2175 LLViewerJointAttachment* pAttachPt = getAttachPoint(pItem, true);
2284 if ( (pAttachPt) && (isDetachable(pAttachPt)) ) 2176 if ( (pAttachPt) && // Need a specific attach pt that
2177 ( (!isLockedAttachment(pAttachPt->getObject(), RLV_LOCK_REMOVE)) && // doesn't have locked object
2178 (!isLockedAttachment(pAttachPt, RLV_LOCK_ADD)) ) ) // and that can be attached to
2285 { 2179 {
2286 #if RLV_TARGET < RLV_MAKE_TARGET(1, 23, 0) // Version: 1.22.11 2180 RlvAttachmentManager::forceAttach(pItem->getUUID(), getAttachPointIndex(pAttachPt->getName(), true));
2287 LLAttachmentRezAction* rez_action = new LLAttachmentRezAction;
2288 rez_action->mItemID = pItem->getUUID();
2289 rez_action->mAttachPt = getAttachPointIndex(pAttachPt->getName(), true);
2290
2291 confirm_replace_attachment_rez(0/*YES*/, (void*)rez_action); // (Will call delete on rez_action)
2292 #else // Version: 1.23.4
2293 LLSD payload;
2294 payload["item_id"] = pItem->getUUID();
2295 payload["attachment_point"] = getAttachPointIndex(pAttachPt->getName(), true);
2296
2297 LLNotifications::instance().forceResponse(
2298 LLNotification::Params("ReplaceAttachment").payload(payload), 0/*YES*/);
2299 #endif
2300 } 2181 }
2301 } 2182 }
2302 else 2183 else
@@ -2504,6 +2385,7 @@ BOOL RlvHandler::setEnabled(BOOL fEnable)
2504 RlvSettings::fShowNameTags = gSavedSettings.getBOOL(RLV_SETTING_SHOWNAMETAGS); 2385 RlvSettings::fShowNameTags = gSavedSettings.getBOOL(RLV_SETTING_SHOWNAMETAGS);
2505 2386
2506 RlvCommand::initLookupTable(); 2387 RlvCommand::initLookupTable();
2388 gRlvHandler.m_pAttachMgr = new RlvAttachmentManager();
2507 gRlvHandler.addObserver(new RlvExtGetSet()); 2389 gRlvHandler.addObserver(new RlvExtGetSet());
2508 2390
2509 if (LLStartUp::getStartupState() >= STATE_CLEANUP) 2391 if (LLStartUp::getStartupState() >= STATE_CLEANUP)
@@ -2553,7 +2435,7 @@ void RlvHandler::clearState()
2553 while (m_Objects.size()) 2435 while (m_Objects.size())
2554 { 2436 {
2555 idObj = m_Objects.begin()->first; // Need a copy since after @clear the data it points to will no longer exist 2437 idObj = m_Objects.begin()->first; // Need a copy since after @clear the data it points to will no longer exist
2556 fDetachable = ((pObj = gObjectList.findObject(idObj)) != NULL) ? isDetachable(pObj) : true; 2438 fDetachable = ((pObj = gObjectList.findObject(idObj)) != NULL) ? isLockedAttachment(pObj, RLV_LOCK_REMOVE) : true;
2557 2439
2558 processCommand(idObj, "clear", false); 2440 processCommand(idObj, "clear", false);
2559 if (!fDetachable) 2441 if (!fDetachable)
@@ -2561,32 +2443,165 @@ void RlvHandler::clearState()
2561 } 2443 }
2562 2444
2563 // Sanity check - these should all be empty after we issue @clear on the last object 2445 // Sanity check - these should all be empty after we issue @clear on the last object
2564 if ( (!m_Objects.empty()) || !(m_Exceptions.empty()) || (!m_Attachments.empty()) ) 2446 if ( (!m_Objects.empty()) || !(m_Exceptions.empty()) || (!m_AttachAdd.empty()) || (!m_AttachRem.empty()) )
2565 { 2447 {
2566 RLV_ERRS << "Object, exception or attachment map not empty after clearing state!" << LL_ENDL; 2448 RLV_ERRS << "Object, exception or attachment map not empty after clearing state!" << LL_ENDL;
2567 m_Objects.clear(); 2449 m_Objects.clear();
2568 m_Exceptions.clear(); 2450 m_Exceptions.clear();
2569 m_Attachments.clear(); 2451 m_AttachAdd.clear();
2452 m_AttachRem.clear();
2570 } 2453 }
2571 2454
2572 // These all need manual clearing 2455 // These all need manual clearing
2573 memset(m_LayersAdd, 0, sizeof(S16) * WT_COUNT); 2456 memset(m_LayersAdd, 0, sizeof(S16) * WT_COUNT);
2574 memset(m_LayersRem, 0, sizeof(S16) * WT_COUNT); 2457 memset(m_LayersRem, 0, sizeof(S16) * WT_COUNT);
2575 memset(m_Behaviours, 0, sizeof(S16) * RLV_BHVR_COUNT); 2458 memset(m_Behaviours, 0, sizeof(S16) * RLV_BHVR_COUNT);
2576 m_AttachPending.clear(); 2459 m_Retained.clear();
2577 m_Emitter.clearObservers(); // <- calls delete on all active observers 2460 m_Emitter.clearObservers(); // <- calls delete on all active observers
2578 2461
2579 // Clear dynamically allocated memory 2462 // Clear dynamically allocated memory
2580 if (m_pGCTimer) 2463 delete m_pGCTimer;
2464 m_pGCTimer = NULL;
2465 delete m_pWLSnapshot;
2466 m_pWLSnapshot = NULL;
2467 delete m_pAttachMgr;
2468 m_pAttachMgr = NULL;
2469}
2470
2471// ============================================================================
2472// Command handlers (RLV_TYPE_ADD and RLV_TYPE_REMOVE)
2473//
2474
2475// Checked: 2009-10-10 (RLVa-1.0.5a) | Added: RLVa-1.0.5a
2476ERlvCmdRet RlvHandler::onAddRemAttach(const LLUUID& idObj, const RlvCommand& rlvCmd, bool& fRefCount)
2477{
2478 // Sanity check - if there's an option it should specify a valid attachment point name
2479 S32 idxAttachPt = getAttachPointIndex(rlvCmd.getOption(), true);
2480 if ( (!idxAttachPt) && (!rlvCmd.getOption().empty()) )
2481 return RLV_RET_FAILED_OPTION;
2482
2483 LLVOAvatar* pAvatar = gAgent.getAvatarObject();
2484 if (!pAvatar)
2485 return RLV_RET_FAILED;
2486
2487 ERlvLockMask eLock = (RLV_BHVR_REMATTACH == rlvCmd.getBehaviourType()) ? RLV_LOCK_REMOVE : RLV_LOCK_ADD;
2488 for (LLVOAvatar::attachment_map_t::const_iterator itAttach = pAvatar->mAttachmentPoints.begin();
2489 itAttach != pAvatar->mAttachmentPoints.end(); ++itAttach)
2581 { 2490 {
2582 delete m_pGCTimer; 2491 if ( (0 == idxAttachPt) || (itAttach->first == idxAttachPt) )
2583 m_pGCTimer = NULL; 2492 {
2493 if (RLV_TYPE_ADD == rlvCmd.getParamType())
2494 addAttachmentLock(itAttach->first, idObj, eLock);
2495 else
2496 removeAttachmentLock(itAttach->first, idObj, eLock);
2497 }
2584 } 2498 }
2585 if (m_pWLSnapshot) 2499
2500 // Refresh HUD visibility if needed
2501 if ( (RLV_BHVR_REMATTACH == rlvCmd.getBehaviourType()) && (hasLockedHUD()) )
2502 LLPipeline::sShowHUDAttachments = TRUE;
2503
2504 fRefCount = rlvCmd.getOption().empty(); // Only reference count global locks
2505 return RLV_RET_NOERROR;
2506}
2507
2508// Checked: 2009-10-10 (RLVa-1.0.5a) | Added: RLVa-1.0.5a
2509ERlvCmdRet RlvHandler::onAddRemDetach(const LLUUID& idObj, const RlvCommand& rlvCmd, bool& fRefCount)
2510{
2511 S32 idxAttachPt = 0;
2512 if (rlvCmd.getOption().empty()) // @detach=n|y
2586 { 2513 {
2587 delete m_pWLSnapshot; 2514 // The object may or may not exist (it may not have rezzed yet, or it may have already been killed):
2588 m_pWLSnapshot = NULL; 2515 // * @detach=n: - if it has rezzed then we'll already have its attachment point
2516 // - if it hasn't rezzed yet then it's a @detach=n from a non-attachment and RlvHandler::onAttach() takes care of it
2517 // * @detach=y: - if it ever rezzed as an attachment we'll have cached its attach point
2518 // - if it never rezzed as an attachment there won't be a lock to remove
2519 rlv_object_map_t::const_iterator itObj = m_Objects.find(idObj);
2520 if (itObj != m_Objects.end())
2521 idxAttachPt = itObj->second.m_idxAttachPt;
2522 }
2523 else // @detach:<attachpt>=n|y
2524 {
2525 idxAttachPt = getAttachPointIndex(rlvCmd.getOption(), true);
2526 }
2527
2528 // The attach point can be zero for @detach=n|y (i.e. non-attachment) but should always be non-zero for @detach:<attachpt>=n|y
2529 if (0 == idxAttachPt)
2530 return (rlvCmd.getOption().empty()) ? RLV_RET_NOERROR : RLV_RET_FAILED_OPTION;
2531
2532 // Actually lock the attachment point (@detach=n locks remove only; @detach:<attachpt>=n locks both remove and add)
2533 ERlvLockMask eLock = (rlvCmd.getOption().empty()) ? RLV_LOCK_REMOVE : (ERlvLockMask)(RLV_LOCK_ADD | RLV_LOCK_REMOVE);
2534 if (RLV_TYPE_ADD == rlvCmd.getParamType())
2535 addAttachmentLock(idxAttachPt, idObj, eLock);
2536 else
2537 removeAttachmentLock(idxAttachPt, idObj, eLock);
2538
2539 // Refresh HUD visibility if needed
2540 if ( (RLV_TYPE_ADD == rlvCmd.getParamType()) && (hasLockedHUD()) )
2541 LLPipeline::sShowHUDAttachments = TRUE;
2542
2543 fRefCount = false; // Don't reference count @detach[:<option>]=n
2544 return RLV_RET_NOERROR;
2545}
2546
2547// ============================================================================
2548// Command handlers (RLV_TYPE_FORCE)
2549//
2550
2551// Checked: 2009-10-12 (RLVa-1.0.5b) | Modified: RLVa-1.0.5b
2552ERlvCmdRet RlvHandler::onForceDetach(const LLUUID& idObj, const RlvCommand& rlvCmd) const
2553{
2554 // TODO-RLVA: this still needs a rewrite to conform to the new event handler system
2555 if ( (rlvCmd.getOption().empty()) || (getAttachPointIndex(rlvCmd.getOption(), true)) )
2556 {
2557 onForceRemAttach(idObj, rlvCmd);
2558 }
2559 else
2560 {
2561 // Force detach single folder
2562 onForceWear(rlvCmd.getOption(), false, false);
2563 }
2564
2565 return RLV_RET_NOERROR;
2566}
2567
2568// Checked: 2009-10-12 (RLVa-1.0.5b) | Added: RLVa-1.0.5b
2569ERlvCmdRet RlvHandler::onForceRemAttach(const LLUUID& idObj, const RlvCommand& rlvCmd) const
2570{
2571 S32 idxAttachPt = 0;
2572 if (rlvCmd.getOption().empty())
2573 {
2574 // Simulate right-click / Take Off > Detach All
2575 LLAgent::userRemoveAllAttachments(NULL);
2576 return RLV_RET_NOERROR;
2577 }
2578 else if ((idxAttachPt = getAttachPointIndex(rlvCmd.getOption(), true)) != 0)
2579 {
2580 // Simulate right-click / Take Off > Detach > ...
2581 LLVOAvatar* pAvatar; LLViewerJointAttachment* pAttachmentPt;
2582 if ( ((pAvatar = gAgent.getAvatarObject()) != NULL) && // Make sure we're actually wearing something on the attachment point
2583 ((pAttachmentPt = get_if_there(pAvatar->mAttachmentPoints, (S32)idxAttachPt, (LLViewerJointAttachment*)NULL)) != NULL) &&
2584 (isStrippable(pAttachmentPt->getItemID())) ) // ... and that it's not marked as "nostrip"
2585 {
2586 #ifdef RLV_EXPERIMENTAL_COMPOSITES
2587 // If we're stripping something that's part of a composite folder then we should @detachthis instead
2588 if (isCompositeDescendent(pAttachmentPt->getItemID()))
2589 {
2590 std::string strCmd = "detachthis:" + strOption + "=force";
2591 #ifdef RLV_DEBUG
2592 RLV_INFOS << "\t- '" << strOption << "' belongs to composite folder: @" << strCmd << LL_ENDL;
2593 #endif // RLV_DEBUG
2594 processForceCommand(idObj, RlvCommand(strCmd));
2595 }
2596 else
2597 #endif // RLV_EXPERIMENTAL_COMPOSITES
2598 {
2599 handle_detach_from_avatar(pAttachmentPt);
2600 }
2601 }
2602 return RLV_RET_NOERROR;
2589 } 2603 }
2604 return RLV_RET_FAILED_OPTION;
2590} 2605}
2591 2606
2592// ============================================================================ 2607// ============================================================================