diff options
Diffstat (limited to 'linden/indra/newview/rlvhandler.cpp')
-rw-r--r-- | linden/indra/newview/rlvhandler.cpp | 519 |
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 |
40 | extern const char* NEW_CATEGORY_NAME; | 35 | extern const char* NEW_CATEGORY_NAME; |
41 | 36 | ||
@@ -66,8 +61,8 @@ const std::string RlvHandler::cstrMsgTpLure = | |||
66 | const std::string RlvHandler::cstrAnonyms[] = | 61 | const 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 | ||
258 | bool RlvHandler::isDetachable(const LLInventoryItem* pItem) const | 254 | // Checked: 2009-10-10 (RLVa-1.0.5a) | Added: RLVa-1.0.5a |
255 | bool 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 |
265 | bool RlvHandler::isDetachableExcept(S32 idxAttachPt, LLViewerObject *pObj) const | 262 | bool 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 |
279 | bool RlvHandler::setDetachable(S32 idxAttachPt, const LLUUID& idRlvObj, bool fDetachable) | 288 | void 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 | ||
310 | void 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: |
416 | BOOL RlvHandler::processCommand(const LLUUID& uuid, const std::string& strCmd, bool fFromObj) | 445 | BOOL 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 | ||
943 | BOOL RlvHandler::processClearCommand(const LLUUID& idObj, const RlvCommand& rlvCmd) | 945 | BOOL 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 |
1330 | void RlvHandler::onAttach(LLViewerJointAttachment* pAttachPt, bool fFullyLoaded) | 1335 | void 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 | ||
1552 | void 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 |
2102 | void 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 | ||
2143 | void RlvHandler::onForceRemOutfit(const LLUUID& idObj, const std::string& strOption) const | 2034 | void 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 | ||
2212 | void RlvHandler::onForceWear(const std::string& strPath, bool fAttach, bool fMatchAll) const | 2104 | void 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 | ||
2476 | ERlvCmdRet 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 | ||
2509 | ERlvCmdRet 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 | ||
2552 | ERlvCmdRet 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 | ||
2569 | ERlvCmdRet 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 | // ============================================================================ |