#ifndef RLV_HELPER_H #define RLV_HELPER_H #include "llagent.h" #include "llboost.h" #include "llgesturemgr.h" #include "llinventorymodel.h" #include "llviewerinventory.h" #include "llvoavatar.h" #include "llwlparamset.h" #include "rlvdefines.h" #include "rlvcommon.h" #ifdef LL_WINDOWS #pragma warning (push) #pragma warning (disable : 4702) // warning C4702: unreachable code #endif #include #ifdef LL_WINDOWS #pragma warning (pop) #endif // ============================================================================ // RlvCommand // class RlvCommand { public: explicit RlvCommand(const std::string& strCommand); /* * Member functions */ public: std::string asString() const; const std::string& getBehaviour() const { return m_strBehaviour; } ERlvBehaviour getBehaviourType() const { return m_eBehaviour; } const std::string& getOption() const { return m_strOption; } const std::string& getParam() const { return m_strParam; } ERlvParamType getParamType() const { return m_eParamType; } bool isStrict() const { return m_fStrict; } bool isValid() const { return m_fValid; } static ERlvBehaviour getBehaviourFromString(const std::string& strBhvr, bool* pfStrict = NULL); static const std::string& getStringFromBehaviour(ERlvBehaviour eBhvr); static bool hasStrictVariant(ERlvBehaviour eBhvr); static void initLookupTable(); protected: static bool parseCommand(const std::string& strCommand, std::string& strBehaviour, std::string& strOption, std::string& strParam); /* * Operators */ public: bool operator ==(const RlvCommand&) const; /* * Member variables */ protected: bool m_fValid; std::string m_strBehaviour; ERlvBehaviour m_eBehaviour; bool m_fStrict; std::string m_strOption; std::string m_strParam; ERlvParamType m_eParamType; typedef std::map RlvBhvrTable; static RlvBhvrTable m_BhvrMap; friend class RlvHandler; }; typedef std::list rlv_command_list_t; // ============================================================================ // RlvObject // class RlvObject { public: RlvObject(const LLUUID& idObj); /* * Member functions */ public: bool addCommand(const RlvCommand& rlvCmd); bool removeCommand(const RlvCommand& rlvCmd); std::string getStatusString(const std::string& strMatch) const; bool hasBehaviour(ERlvBehaviour eBehaviour, bool fStrictOnly) const; bool hasBehaviour(ERlvBehaviour eBehaviour, const std::string& strOption, bool fStrictOnly) const; const rlv_command_list_t* getCommandList() const { return &m_Commands; } /* * Member variables */ protected: LLUUID m_UUID; // The object's UUID S32 m_idxAttachPt; // The object's attachment point (or 0 if it's not an attachment) bool m_fLookup; // TRUE if the object existed in gObjectList at one point in time S16 m_nLookupMisses; // Count of unsuccessful lookups in gObjectList by the GC rlv_command_list_t m_Commands; // List of behaviours held by this object (in the order they were received) friend class RlvHandler; }; // ============================================================================ // RlvAttachmentManager - Self contained helper class that automagically takes care of the nitty gritty of force detaching/reattaching // class RlvAttachmentManager { public: RlvAttachmentManager() : m_pTimer(NULL) {} ~RlvAttachmentManager() { delete m_pTimer; } /* * Member functions */ public: // NOTE: the following two do *not* respect attachment locks so use with care static void attach(const LLUUID& idItem, S32 idxAttachPt); static void detach(LLViewerJointAttachment* pAttachPt); protected: void startTimer() { if (!m_pTimer) m_pTimer = new RlvAttachmentManagerTimer(this); } /* * Event handlers */ public: void onAttach(LLViewerJointAttachment* pAttachPt); void onDetach(LLViewerJointAttachment* pAttachPt); void onSavedAssetIntoInventory(const LLUUID& idItem); BOOL onTimer(); void onWearAttachment(const LLUUID& idItem); /* * Member variables */ protected: typedef std::map rlv_detach_map_t; rlv_detach_map_t m_PendingDetach; struct RlvReattachInfo { RlvReattachInfo(const LLUUID& itemid) : idItem(itemid), fAssetSaved(false), tsAttach(0) { tsDetach = LLFrameTimer::getElapsedSeconds(); } LLUUID idItem; bool fAssetSaved; F64 tsDetach; F64 tsAttach; protected: RlvReattachInfo(); }; typedef std::map rlv_attach_map_t; rlv_attach_map_t m_PendingAttach; struct RlvWearInfo { RlvWearInfo(LLUUID itemid) : idItem(itemid) { tsWear = LLFrameTimer::getElapsedSeconds(); } LLUUID idItem; F64 tsWear; std::map attachPts; protected: RlvWearInfo(); }; typedef std::map rlv_wear_map_t; rlv_wear_map_t m_PendingWear; class RlvAttachmentManagerTimer : public LLEventTimer { public: RlvAttachmentManagerTimer(RlvAttachmentManager* pMgr) : LLEventTimer(10), m_pMgr(pMgr) {} virtual ~RlvAttachmentManagerTimer() { m_pMgr->m_pTimer = NULL; } virtual BOOL tick() { return m_pMgr->onTimer(); } RlvAttachmentManager* m_pMgr; } *m_pTimer; }; // ============================================================================ // RlvCriteriaCategoryCollector - Criteria based folder matching filter used by @findfolder and @findfolders // class RlvCriteriaCategoryCollector : public LLInventoryCollectFunctor { public: RlvCriteriaCategoryCollector(const std::string& strCriteria) { std::string::size_type idxIt, idxLast = 0; while (idxLast < strCriteria.length()) { idxIt = strCriteria.find("&&", idxLast); if (std::string::npos == idxIt) idxIt = strCriteria.length(); if (idxIt != idxLast) m_Criteria.push_back(strCriteria.substr(idxLast, idxIt - idxLast)); idxLast = idxIt + 2; } } virtual ~RlvCriteriaCategoryCollector() {} virtual bool operator()(LLInventoryCategory* pFolder, LLInventoryItem* pItem) { if ( (!pFolder) || (m_Criteria.empty()) ) // We're only interested in matching folders, we don't care about items return false; // (if there are no criteria then we don't want to return a match) std::string strFolderName = pFolder->getName(); LLStringUtil::toLower(strFolderName); // NOTE: hidden or "give to #RLV" folders can never be a match if ( (strFolderName.empty()) || (RLV_FOLDER_PREFIX_HIDDEN == strFolderName[0]) || (RLV_FOLDER_PREFIX_PUTINV == strFolderName[0]) ) { return false; } for (std::list::const_iterator itCrit = m_Criteria.begin(); itCrit != m_Criteria.end(); ++itCrit) if (std::string::npos == strFolderName.find(*itCrit)) // Return false on the first mismatch return false; return true; } protected: std::list m_Criteria; }; // ============================================================================ // RlvWearableItemCollector - Inventory item filter used by attach/detach/attachall/detachall/getinvworn // class RlvWearableItemCollector : public LLInventoryCollectFunctor { public: RlvWearableItemCollector(const LLUUID& idFolder, bool fAttach, bool fMatchAll) : m_idFolder(idFolder), m_fAttach(fAttach), m_fMatchAll(fMatchAll) { m_Wearable.push_back(idFolder); } virtual ~RlvWearableItemCollector() {} virtual bool operator()(LLInventoryCategory* pFolder, LLInventoryItem* pItem); const LLUUID& getFoldedParent(const LLUUID& idFolder) const; protected: bool m_fAttach; bool m_fMatchAll; const LLUUID m_idFolder; bool onCollectFolder(const LLInventoryCategory* pFolder); bool onCollectItem(const LLInventoryItem* pItem); std::list m_Tentative; std::list m_Wearable; std::map m_Folding; }; // ============================================================================ // RlvForceWear // class RlvForceWear { public: // Folders enum eWearAction { ACTION_ATTACH, ACTION_DETACH }; enum eWearFlags { FLAG_NONE = 0x00, FLAG_MATCHALL = 0x01, FLAG_DEFAULT = FLAG_NONE }; void forceFolder(const LLViewerInventoryCategory* pFolder, eWearAction eAction, eWearFlags eFlags); // Attachments static bool isForceDetachable(LLViewerJointAttachment* pAttachPt, bool fCheckComposite = true, LLViewerObject* pExceptObj = NULL); void forceDetach(LLViewerJointAttachment* ptAttachPt); // Wearables static bool isForceRemovable(EWearableType wtType, bool fCheckComposite = true, const LLUUID& idExcept = LLUUID::null); void forceRemove(EWearableType wtType); // General purpose static bool isWearableItem(const LLInventoryItem* pItem); static bool isWearingItem(const LLInventoryItem* pItem); public: void done() { processRem(); processAdd(); } protected: void processAdd(); void processRem(); static void onWearableArrived(LLWearable* pWearable, void* pParam); protected: LLInventoryModel::item_array_t m_addAttachments, m_addWearables, m_addGestures, m_remGestures; std::list m_remAttachments; std::list m_remWearables; }; // ============================================================================ // RlvBehaviourNotifyObserver // class RlvBehaviourNotifyObserver : public RlvBehaviourObserver { public: virtual ~RlvBehaviourNotifyObserver() { } virtual void changed(const RlvCommand& rlvCmd, bool fInternal); void addNotify(const LLUUID& idObj, S32 nChannel, const std::string& strFilter) { m_Notifications.insert(std::pair(idObj, notifyData(nChannel, strFilter))); } void clearNotify(const LLUUID& idObj) { m_Notifications.erase(idObj); } bool hasNotify() { return (m_Notifications.size() != 0); } void removeNotify(const LLUUID& idObj, S32 nChannel, const std::string& strFilter) { for (std::multimap::iterator itNotify = m_Notifications.lower_bound(idObj), endNotify = m_Notifications.upper_bound(idObj); itNotify != endNotify; ++itNotify) { if ( (itNotify->second.nChannel == nChannel) && (itNotify->second.strFilter == strFilter) ) { m_Notifications.erase(itNotify); break; } } } protected: struct notifyData { S32 nChannel; std::string strFilter; notifyData(S32 channel, const std::string& filter) : nChannel(channel), strFilter(filter) {} }; std::multimap m_Notifications; }; // ============================================================================ // RlvRetainedCommand // struct RlvRetainedCommand { public: LLUUID idObject; RlvCommand rlvCmd; RlvRetainedCommand(const LLUUID& uuid, const RlvCommand& cmd) : idObject(uuid), rlvCmd(cmd) {} private: RlvRetainedCommand(); }; typedef std::list rlv_retained_list_t; // ============================================================================ // RlvException // typedef boost::variant RlvExceptionOption; struct RlvException { public: LLUUID idObject; // UUID of the object that added the exception ERlvBehaviour eBehaviour; // Behaviour the exception applies to RlvExceptionOption varOption; // Exception data (type is dependent on eBehaviour) RlvException(const LLUUID& idObj, ERlvBehaviour eBhvr, const RlvExceptionOption& option) : idObject(idObj), eBehaviour(eBhvr), varOption(option) {} private: RlvException(); }; // ============================================================================ // RlvWLSnapshot // struct RlvWLSnapshot { public: static void restoreSnapshot(const RlvWLSnapshot* pWLSnapshot); static RlvWLSnapshot* takeSnapshot(); private: RlvWLSnapshot() {} bool fIsRunning; bool fUseLindenTime; LLWLParamSet WLParams; }; // ============================================================================ // Various helper classes/timers/functors // class RlvGCTimer : public LLEventTimer { public: RlvGCTimer() : LLEventTimer(30.0) {} virtual BOOL tick(); }; class RlvCurrentlyWorn : public LLInventoryFetchObserver { public: RlvCurrentlyWorn() {} ~RlvCurrentlyWorn() {} virtual void done() {} static void fetchWorn(); void fetchItem(const LLUUID& idItem); }; class RlvGiveToRLVAgentOffer : public LLInventoryFetchDescendentsObserver { public: RlvGiveToRLVAgentOffer() {} virtual void done(); }; // ============================================================================ // Various helper functions // bool rlvCanDeleteOrReturn(); S32 rlvGetDirectDescendentsCount(const LLInventoryCategory* pFolder, LLAssetType::EType type); bool rlvIsEmote(const std::string& strUTF8Text); bool rlvIsValidReplyChannel(S32 nChannel); void rlvSendBusyMessage(const LLUUID& idTo, const std::string& strMsg, const LLUUID& idSession = LLUUID::null); bool rlvSendChatReply(const std::string& strChannel, const std::string& strReply); bool rlvSendChatReply(S32 nChannel, const std::string& strReply); std::string rlvGetFirstParenthesisedText(const std::string& strText, std::string::size_type* pidxMatch = NULL); std::string rlvGetLastParenthesisedText(const std::string& strText, std::string::size_type* pidxStart = NULL); void rlvStringReplace(std::string& strText, std::string strFrom, const std::string& strTo); #ifdef RLV_ADVANCED_TOGGLE_RLVA // "Advanced / RLVa / Enable RLV" menu option void rlvToggleEnabled(void*); BOOL rlvGetEnabled(void*); #endif // RLV_ADVANCED_TOGGLE_RLVA // ============================================================================ // Debug helper functions // // ============================================================================ // Inlined class member functions // // Checked: 2009-09-19 (RLVa-1.0.3d) inline std::string RlvCommand::asString() const { // NOTE: @clear= should be represented as clear: return (m_eParamType != RLV_TYPE_CLEAR) ? (!m_strOption.empty()) ? (std::string(m_strBehaviour)).append(":").append(m_strOption) : (std::string(m_strBehaviour)) : (!m_strParam.empty()) ? (std::string(m_strBehaviour)).append(":").append(m_strParam) : (std::string(m_strBehaviour)); } inline bool RlvCommand::operator ==(const RlvCommand& rhs) const { // The specification notes that "@detach=n" is semantically identical to "@detach=add" (same for "y" and "rem" return (m_strBehaviour == rhs.m_strBehaviour) && (m_strOption == rhs.m_strOption) && ( (RLV_TYPE_UNKNOWN != m_eParamType) ? (m_eParamType == rhs.m_eParamType) : (m_strParam == rhs.m_strParam) ); } inline bool RlvCommand::hasStrictVariant(ERlvBehaviour eBhvr) { switch (eBhvr) { case RLV_BHVR_RECVCHAT: case RLV_BHVR_RECVEMOTE: case RLV_BHVR_RECVIM: case RLV_BHVR_SENDIM: case RLV_BHVR_TPLURE: case RLV_BHVR_SENDCHANNEL: return true; default: return false; } } inline void RlvCurrentlyWorn::fetchItem(const LLUUID& idItem) { if (idItem.notNull()) { LLInventoryFetchObserver::item_ref_t idItems; idItems.push_back(idItem); fetchItems(idItems); } } // Checked: 2009-12-18 (RLVa-1.1.0k) | Added: RLVa-1.1.0i inline bool RlvForceWear::isWearableItem(const LLInventoryItem* pItem) { return (LLAssetType::AT_OBJECT == pItem->getType()) || (LLAssetType::AT_GESTURE == pItem->getType()) || (LLAssetType::AT_BODYPART == pItem->getType()) || (LLAssetType::AT_CLOTHING == pItem->getType()); } // Checked: 2009-12-18 (RLVa-1.1.0k) | Modified: RLVa-1.1.0i inline bool RlvForceWear::isWearingItem(const LLInventoryItem* pItem) { return ((LLAssetType::AT_OBJECT == pItem->getType()) && (gAgent.getAvatarObject()->isWearingAttachment(pItem->getUUID()))) || ((LLAssetType::AT_GESTURE == pItem->getType()) && (gGestureManager.isGestureActive(pItem->getUUID()))) || (gAgent.isWearingItem(pItem->getUUID())); } // ============================================================================ // Inlined helper functions // inline bool rlvIsEmote(const std::string& strUTF8Text) { return (strUTF8Text.length() > 4) && ( (strUTF8Text.compare(0, 4, "/me ") == 0) || (strUTF8Text.compare(0, 4, "/me'") == 0) ); } // Checked: 2009-09-05 (RLVa-1.0.2a) | Added: RLVa-1.0.2a inline bool rlvIsValidReplyChannel(S32 nChannel) { return (nChannel > 0) && (CHAT_CHANNEL_DEBUG != nChannel); } // Checked: 2009-08-05 (RLVa-1.0.1e) | Added: RLVa-1.0.0e inline bool rlvSendChatReply(const std::string& strChannel, const std::string& strReply) { S32 nChannel; return (LLStringUtil::convertToS32(strChannel, nChannel)) ? rlvSendChatReply(nChannel, strReply) : false; } // ============================================================================ #endif // RLV_HELPER_H