541 lines
16 KiB
C++
541 lines
16 KiB
C++
#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 <boost/variant.hpp>
|
|
#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<std::string, ERlvBehaviour> RlvBhvrTable;
|
|
static RlvBhvrTable m_BhvrMap;
|
|
|
|
friend class RlvHandler;
|
|
};
|
|
typedef std::list<RlvCommand> 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<S32, LLUUID> rlv_detach_map_t;
|
|
rlv_detach_map_t m_PendingDetach;
|
|
|
|
struct RlvReattachInfo
|
|
{
|
|
RlvReattachInfo(const LLUUID& itemid) : idItem(itemid), fAssetSaved(false), tsAttach(0)
|
|
{ tsDetach = LLFrameTimer::getElapsedSeconds(); }
|
|
|
|
LLUUID idItem;
|
|
bool fAssetSaved;
|
|
F64 tsDetach;
|
|
F64 tsAttach;
|
|
protected:
|
|
RlvReattachInfo();
|
|
};
|
|
typedef std::map<S32, RlvReattachInfo> 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<S32, LLUUID> attachPts;
|
|
protected:
|
|
RlvWearInfo();
|
|
};
|
|
typedef std::map<LLUUID, RlvWearInfo> 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<std::string>::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<std::string> m_Criteria;
|
|
};
|
|
|
|
// ============================================================================
|
|
// RlvWearableItemCollector - Inventory item filter used by attach/detach/attachall/detachall/getinvworn
|
|
//
|
|
|
|
class RlvWearableItemCollector : public LLInventoryCollectFunctor
|
|
{
|
|
public:
|
|
RlvWearableItemCollector(const LLUUID& idFolder, bool fAttach, bool fMatchAll)
|
|
: m_idFolder(idFolder), m_fAttach(fAttach), m_fMatchAll(fMatchAll)
|
|
{
|
|
m_Wearable.push_back(idFolder);
|
|
}
|
|
virtual ~RlvWearableItemCollector() {}
|
|
|
|
virtual bool operator()(LLInventoryCategory* pFolder, LLInventoryItem* pItem);
|
|
|
|
const LLUUID& getFoldedParent(const LLUUID& idFolder) const;
|
|
protected:
|
|
bool m_fAttach;
|
|
bool m_fMatchAll;
|
|
const LLUUID m_idFolder;
|
|
|
|
bool onCollectFolder(const LLInventoryCategory* pFolder);
|
|
bool onCollectItem(const LLInventoryItem* pItem);
|
|
|
|
std::list<LLUUID> m_Tentative;
|
|
std::list<LLUUID> m_Wearable;
|
|
|
|
std::map<LLUUID, LLUUID> 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<LLViewerJointAttachment*> m_remAttachments;
|
|
std::list<EWearableType> 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<LLUUID, notifyData>(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<LLUUID, notifyData>::iterator itNotify = m_Notifications.lower_bound(idObj),
|
|
endNotify = m_Notifications.upper_bound(idObj); itNotify != endNotify; ++itNotify)
|
|
{
|
|
if ( (itNotify->second.nChannel == nChannel) && (itNotify->second.strFilter == strFilter) )
|
|
{
|
|
m_Notifications.erase(itNotify);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
protected:
|
|
struct notifyData
|
|
{
|
|
S32 nChannel;
|
|
std::string strFilter;
|
|
notifyData(S32 channel, const std::string& filter) : nChannel(channel), strFilter(filter) {}
|
|
};
|
|
std::multimap<LLUUID, notifyData> m_Notifications;
|
|
};
|
|
|
|
// ============================================================================
|
|
// RlvRetainedCommand
|
|
//
|
|
|
|
struct RlvRetainedCommand
|
|
{
|
|
public:
|
|
LLUUID idObject;
|
|
RlvCommand rlvCmd;
|
|
|
|
RlvRetainedCommand(const LLUUID& uuid, const RlvCommand& cmd) : idObject(uuid), rlvCmd(cmd) {}
|
|
private:
|
|
RlvRetainedCommand();
|
|
};
|
|
typedef std::list<RlvRetainedCommand> rlv_retained_list_t;
|
|
|
|
// ============================================================================
|
|
// RlvException
|
|
//
|
|
|
|
typedef boost::variant<std::string, LLUUID, S32, ERlvBehaviour> RlvExceptionOption;
|
|
|
|
struct RlvException
|
|
{
|
|
public:
|
|
LLUUID idObject; // UUID of the object that added the exception
|
|
ERlvBehaviour eBehaviour; // Behaviour the exception applies to
|
|
RlvExceptionOption varOption; // Exception data (type is dependent on eBehaviour)
|
|
|
|
RlvException(const LLUUID& idObj, ERlvBehaviour eBhvr, const RlvExceptionOption& option) : idObject(idObj), eBehaviour(eBhvr), varOption(option) {}
|
|
private:
|
|
RlvException();
|
|
};
|
|
|
|
// ============================================================================
|
|
// RlvWLSnapshot
|
|
//
|
|
|
|
struct RlvWLSnapshot
|
|
{
|
|
public:
|
|
static void restoreSnapshot(const RlvWLSnapshot* pWLSnapshot);
|
|
static RlvWLSnapshot* takeSnapshot();
|
|
private:
|
|
RlvWLSnapshot() {}
|
|
|
|
bool fIsRunning;
|
|
bool fUseLindenTime;
|
|
LLWLParamSet WLParams;
|
|
};
|
|
|
|
// ============================================================================
|
|
// Various helper classes/timers/functors
|
|
//
|
|
|
|
class RlvGCTimer : public LLEventTimer
|
|
{
|
|
public:
|
|
RlvGCTimer() : LLEventTimer(30.0) {}
|
|
virtual BOOL tick();
|
|
};
|
|
|
|
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=<param> should be represented as clear:<param>
|
|
return (m_eParamType != RLV_TYPE_CLEAR)
|
|
? (!m_strOption.empty()) ? (std::string(m_strBehaviour)).append(":").append(m_strOption) : (std::string(m_strBehaviour))
|
|
: (!m_strParam.empty()) ? (std::string(m_strBehaviour)).append(":").append(m_strParam) : (std::string(m_strBehaviour));
|
|
}
|
|
|
|
inline bool RlvCommand::operator ==(const RlvCommand& rhs) const
|
|
{
|
|
// The specification notes that "@detach=n" is semantically identical to "@detach=add" (same for "y" and "rem"
|
|
return (m_strBehaviour == rhs.m_strBehaviour) && (m_strOption == rhs.m_strOption) &&
|
|
( (RLV_TYPE_UNKNOWN != m_eParamType) ? (m_eParamType == rhs.m_eParamType) : (m_strParam == rhs.m_strParam) );
|
|
}
|
|
|
|
inline bool RlvCommand::hasStrictVariant(ERlvBehaviour eBhvr)
|
|
{
|
|
switch (eBhvr)
|
|
{
|
|
case RLV_BHVR_RECVCHAT:
|
|
case RLV_BHVR_RECVEMOTE:
|
|
case RLV_BHVR_RECVIM:
|
|
case RLV_BHVR_SENDIM:
|
|
case RLV_BHVR_TPLURE:
|
|
case RLV_BHVR_SENDCHANNEL:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
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
|