330 lines
16 KiB
C++
330 lines
16 KiB
C++
/**
|
|
*
|
|
* Copyright (c) 2009-2018, Kitty Barnett
|
|
*
|
|
* The source code in this file is provided to you under the terms of the
|
|
* GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY;
|
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
|
* PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt
|
|
* in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt
|
|
*
|
|
* By copying, modifying or distributing this software, you acknowledge that
|
|
* you have read and understood your obligations described above, and agree to
|
|
* abide by those obligations.
|
|
*
|
|
*/
|
|
|
|
#ifndef RLV_HANDLER_H
|
|
#define RLV_HANDLER_H
|
|
|
|
#include "llgroupmgr.h"
|
|
#include <stack>
|
|
|
|
#include "rlvcommon.h"
|
|
#include "rlvhelper.h"
|
|
|
|
// ============================================================================
|
|
// RlvHandler class
|
|
//
|
|
|
|
class RlvHandler : public LLOldEvents::LLSimpleListener, public LLParticularGroupObserver
|
|
{
|
|
// Temporary LLSingleton look-alike
|
|
public:
|
|
static RlvHandler& instance();
|
|
static RlvHandler* getInstance();
|
|
|
|
public:
|
|
RlvHandler();
|
|
~RlvHandler();
|
|
|
|
// --------------------------------
|
|
|
|
/*
|
|
* Rule checking functions
|
|
*/
|
|
// NOTE: - to check @detach=n -> (see RlvAttachmentLocks)
|
|
// - to check @addattach=n -> (see RlvAttachmentLocks)
|
|
// - to check @remattach=n -> (see RlvAttachmentLocks)
|
|
// - to check @addoutfit=n -> (see RlvWearableLocks)
|
|
// - to check @remoutfit=n -> (see RlvWearableLocks)
|
|
// - to check exceptions -> isException()
|
|
public:
|
|
// Returns a list of all objects containing the specified behaviour
|
|
bool findBehaviour(ERlvBehaviour eBhvr, std::list<const RlvObject*>& lObjects) const;
|
|
// Returns a pointer to an RLV object instance (DO NOT STORE THIS!)
|
|
RlvObject* getObject(const LLUUID& idRlvObj) const;
|
|
// Returns TRUE is at least one object contains the specified behaviour (and optional option)
|
|
bool hasBehaviour(ERlvBehaviour eBhvr) const { return (eBhvr < RLV_BHVR_COUNT) ? (0 != m_Behaviours[eBhvr]) : false; }
|
|
bool hasBehaviour(ERlvBehaviour eBhvr, const std::string& strOption) const;
|
|
// Returns TRUE if the specified object has at least one active behaviour
|
|
bool hasBehaviour(const LLUUID& idObj) { return m_Objects.end() != m_Objects.find(idObj); }
|
|
// Returns TRUE if the specified object contains the specified behaviour (and optional option)
|
|
bool hasBehaviour(const LLUUID& idObj, ERlvBehaviour eBhvr, const std::string& strOption = LLStringUtil::null) const;
|
|
// Returns TRUE if at least one object (except the specified one) contains the specified behaviour (and optional option)
|
|
bool hasBehaviourExcept(ERlvBehaviour eBhvr, const LLUUID& idObj) const;
|
|
bool hasBehaviourExcept(ERlvBehaviour eBhvr, const std::string& strOption, const LLUUID& idObj) const;
|
|
// Returns TRUE if at least one object in the linkset with specified root ID contains the specified behaviour (and optional option)
|
|
bool hasBehaviourRoot(const LLUUID& idObjRoot, ERlvBehaviour eBhvr, const std::string& strOption = LLStringUtil::null) const;
|
|
// Returns TRUE if the specified object is the only object containing the specified behaviour
|
|
bool ownsBehaviour(const LLUUID& idObj, ERlvBehaviour eBhvr) const;
|
|
|
|
// Adds or removes an exception for the specified behaviour
|
|
void addException(const LLUUID& idObj, ERlvBehaviour eBhvr, const RlvExceptionOption& varOption);
|
|
void removeException(const LLUUID& idObj, ERlvBehaviour eBhvr, const RlvExceptionOption& varOption);
|
|
// Returns TRUE if the specified behaviour has an added exception
|
|
bool hasException(ERlvBehaviour eBhvr) const;
|
|
// Returns TRUE if the specified option was added as an exception for the specified behaviour
|
|
bool isException(ERlvBehaviour eBhvr, const RlvExceptionOption& varOption, ERlvExceptionCheck eCheckType = ERlvExceptionCheck::Default) const;
|
|
// Returns TRUE if the specified behaviour should behave "permissive" (rather than "strict"/"secure")
|
|
bool isPermissive(ERlvBehaviour eBhvr) const;
|
|
|
|
#ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS
|
|
// Returns TRUE if the composite folder doesn't contain any "locked" items
|
|
bool canTakeOffComposite(const LLInventoryCategory* pFolder) const;
|
|
// Returns TRUE if the composite folder doesn't replace any "locked" items
|
|
bool canWearComposite(const LLInventoryCategory* pFolder) const;
|
|
// Returns TRUE if the folder is a composite folder and optionally returns the name
|
|
bool getCompositeInfo(const LLInventoryCategory* pFolder, std::string* pstrName) const;
|
|
// Returns TRUE if the inventory item belongs to a composite folder and optionally returns the name and composite folder
|
|
bool getCompositeInfo(const LLUUID& idItem, std::string* pstrName, LLViewerInventoryCategory** ppFolder) const;
|
|
// Returns TRUE if the folder is a composite folder
|
|
bool isCompositeFolder(const LLInventoryCategory* pFolder) const { return getCompositeInfo(pFolder, NULL); }
|
|
// Returns TRUE if the inventory item belongs to a composite folder
|
|
bool isCompositeDescendent(const LLUUID& idItem) const { return getCompositeInfo(idItem, NULL, NULL); }
|
|
// Returns TRUE if the inventory item is part of a folded composite folder and should be hidden from @getoufit or @getattach
|
|
bool isHiddenCompositeItem(const LLUUID& idItem, const std::string& strItemType) const;
|
|
#endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS
|
|
|
|
public:
|
|
// Adds a blocked object (= object that is blocked from issuing commands) by UUID (can be null) and/or name
|
|
void addBlockedObject(const LLUUID& idObj, const std::string& strObjName);
|
|
// Returns TRUE if there's an unresolved blocked object (known name but unknown UUID)
|
|
bool hasUnresolvedBlockedObject() const;
|
|
// Returns TRUE if the object with the specified UUID is blocked from issuing commands
|
|
bool isBlockedObject(const LLUUID& idObj) const;
|
|
// Removes a blocked object
|
|
void removeBlockedObject(const LLUUID& idObj);
|
|
|
|
// --------------------------------
|
|
|
|
/*
|
|
* Helper functions
|
|
*/
|
|
public:
|
|
// Accessors/Mutators
|
|
const LLUUID& getAgentGroup() const { return m_idAgentGroup; } // @setgroup
|
|
bool getCanCancelTp() const { return m_fCanCancelTp; } // @accepttp and @tpto
|
|
void setCanCancelTp(bool fAllow) { m_fCanCancelTp = fAllow; } // @accepttp and @tpto
|
|
const LLVector3d& getSitSource() const { return m_posSitSource; } // @standtp
|
|
void setSitSource(const LLVector3d& posSource) { m_posSitSource = posSource; } // @standtp
|
|
|
|
// Command specific helper functions
|
|
bool filterChat(std::string& strUTF8Text, bool fFilterEmote) const; // @sendchat, @recvchat and @redirchat
|
|
bool redirectChatOrEmote(const std::string& strUTF8Test) const; // @redirchat and @rediremote
|
|
|
|
// Command processing helper functions
|
|
ERlvCmdRet processCommand(const LLUUID& idObj, const std::string& strCommand, bool fFromObj);
|
|
void processRetainedCommands(ERlvBehaviour eBhvrFilter = RLV_BHVR_UNKNOWN, ERlvParamType eTypeFilter = RLV_TYPE_UNKNOWN);
|
|
bool processIMQuery(const LLUUID& idSender, const std::string& strCommand);
|
|
|
|
// Returns a pointer to the currently executing command (do *not* save this pointer)
|
|
const RlvCommand* getCurrentCommand() const { return (!m_CurCommandStack.empty()) ? &m_CurCommandStack.top().get() : nullptr; }
|
|
// Returns the UUID of the object we're currently executing a command for
|
|
const LLUUID& getCurrentObject() const { return (!m_CurObjectStack.empty()) ? m_CurObjectStack.top() : LLUUID::null; }
|
|
|
|
// Initialization
|
|
static bool canEnable();
|
|
static bool isEnabled() { return m_fEnabled; }
|
|
static bool setEnabled(bool fEnable);
|
|
protected:
|
|
// Command specific helper functions (NOTE: these generally do not perform safety checks)
|
|
bool checkActiveGroupThrottle(const LLUUID& idRlvObj); // @setgroup=force
|
|
void setActiveGroup(const LLUUID& idGroup); // @setgroup=force
|
|
void setActiveGroupRole(const LLUUID& idGroup, const std::string& strRole); // @setgroup=force
|
|
void setCameraOverride(bool fOverride); // @setcam family
|
|
|
|
void onIMQueryListResponse(const LLSD& sdNotification, const LLSD sdResponse);
|
|
|
|
// --------------------------------
|
|
|
|
/*
|
|
* Event handling
|
|
*/
|
|
public:
|
|
// The behaviour signal is triggered whenever a command is successfully processed and resulted in adding or removing a behaviour
|
|
typedef boost::signals2::signal<void (ERlvBehaviour, ERlvParamType)> rlv_behaviour_signal_t;
|
|
boost::signals2::connection setBehaviourCallback(const rlv_behaviour_signal_t::slot_type& cb ) { return m_OnBehaviour.connect(cb); }
|
|
boost::signals2::connection setBehaviourToggleCallback(const rlv_behaviour_signal_t::slot_type& cb ) { return m_OnBehaviourToggle.connect(cb); }
|
|
// The command signal is triggered whenever a command is processed
|
|
typedef boost::signals2::signal<void (const RlvCommand&, ERlvCmdRet, bool)> rlv_command_signal_t;
|
|
boost::signals2::connection setCommandCallback(const rlv_command_signal_t::slot_type& cb ) { return m_OnCommand.connect(cb); }
|
|
|
|
void addCommandHandler(RlvExtCommandHandler* pHandler);
|
|
void removeCommandHandler(RlvExtCommandHandler* pHandler);
|
|
protected:
|
|
void clearCommandHandlers();
|
|
bool notifyCommandHandlers(rlvExtCommandHandler f, const RlvCommand& rlvCmd, ERlvCmdRet& eRet, bool fNotifyAll) const;
|
|
|
|
// Externally invoked event handlers
|
|
public:
|
|
void cleanup();
|
|
void onActiveGroupChanged();
|
|
void onAttach(const LLViewerObject* pAttachObj, const LLViewerJointAttachment* pAttachPt);
|
|
void onDetach(const LLViewerObject* pAttachObj, const LLViewerJointAttachment* pAttachPt);
|
|
void onExperienceAttach(const LLSD& sdExperience, const std::string& strObjName);
|
|
void onExperienceEvent(const LLSD& sdEvent);
|
|
bool onGC();
|
|
void onLoginComplete();
|
|
void onSitOrStand(bool fSitting);
|
|
void onTeleportFailed();
|
|
void onTeleportFinished(const LLVector3d& posArrival);
|
|
static void cleanupClass();
|
|
static void onIdleStartup(void* pParam);
|
|
protected:
|
|
void getAttachmentResourcesCoro(const std::string& strUrl);
|
|
void onTeleportCallback(U64 hRegion, const LLVector3& posRegion, const LLVector3& vecLookAt, const LLUUID& idRlvObj);
|
|
|
|
/*
|
|
* Base class overrides
|
|
*/
|
|
public:
|
|
// LLParticularGroupObserver implementation
|
|
void changed(const LLUUID& group_id, LLGroupChange gc) override;
|
|
// LLOldEvents::LLSimpleListener implementation
|
|
bool handleEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& sdUserdata) override;
|
|
|
|
/*
|
|
* Command processing
|
|
*/
|
|
protected:
|
|
ERlvCmdRet processCommand(std::reference_wrapper<const RlvCommand> rlvCmdRef, bool fFromObj);
|
|
ERlvCmdRet processClearCommand(const RlvCommand& rlvCmd);
|
|
|
|
// Command handlers (RLV_TYPE_ADD and RLV_TYPE_CLEAR)
|
|
ERlvCmdRet processAddRemCommand(const RlvCommand& rlvCmd);
|
|
ERlvCmdRet onAddRemFolderLock(const RlvCommand& rlvCmd, bool& fRefCount);
|
|
ERlvCmdRet onAddRemFolderLockException(const RlvCommand& rlvCmd, bool& fRefCount);
|
|
// Command handlers (RLV_TYPE_FORCE)
|
|
ERlvCmdRet processForceCommand(const RlvCommand& rlvCmd) const;
|
|
ERlvCmdRet onForceWear(const LLViewerInventoryCategory* pFolder, U32 nFlags) const;
|
|
void onForceWearCallback(const uuid_vec_t& idItems, U32 nFlags) const;
|
|
// Command handlers (RLV_TYPE_REPLY)
|
|
ERlvCmdRet processReplyCommand(const RlvCommand& rlvCmd) const;
|
|
ERlvCmdRet onFindFolder(const RlvCommand& rlvCmd, std::string& strReply) const;
|
|
ERlvCmdRet onGetAttach(const RlvCommand& rlvCmd, std::string& strReply) const;
|
|
ERlvCmdRet onGetAttachNames(const RlvCommand& rlvCmd, std::string& strReply) const;
|
|
ERlvCmdRet onGetInv(const RlvCommand& rlvCmd, std::string& strReply) const;
|
|
ERlvCmdRet onGetInvWorn(const RlvCommand& rlvCmd, std::string& strReply) const;
|
|
ERlvCmdRet onGetOutfit(const RlvCommand& rlvCmd, std::string& strReply) const;
|
|
ERlvCmdRet onGetOutfitNames(const RlvCommand& rlvCmd, std::string& strReply) const;
|
|
ERlvCmdRet onGetPath(const RlvCommand& rlvCmd, std::string& strReply) const;
|
|
|
|
// --------------------------------
|
|
|
|
/*
|
|
* Member variables
|
|
*/
|
|
public:
|
|
typedef std::map<LLUUID, RlvObject> rlv_object_map_t;
|
|
typedef std::tuple<LLUUID, std::string, double> rlv_blocked_object_t;
|
|
typedef std::list<rlv_blocked_object_t> rlv_blocked_object_list_t;
|
|
|
|
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();
|
|
};
|
|
typedef std::multimap<ERlvBehaviour, RlvException> rlv_exception_map_t;
|
|
protected:
|
|
rlv_object_map_t m_Objects; // Map of objects that have active restrictions (idObj -> RlvObject)
|
|
rlv_blocked_object_list_t m_BlockedObjects; // List of (attached) objects that can't issue commands
|
|
rlv_exception_map_t m_Exceptions; // Map of currently active restriction exceptions (ERlvBehaviour -> RlvException)
|
|
S16 m_Behaviours[RLV_BHVR_COUNT];
|
|
|
|
rlv_command_list_t m_Retained;
|
|
RlvGCTimer* m_pGCTimer;
|
|
|
|
std::stack<std::reference_wrapper<const RlvCommand>> m_CurCommandStack; // Convenience (see @tpto)
|
|
std::stack<LLUUID> m_CurObjectStack; // Convenience (see @tpto)
|
|
|
|
rlv_behaviour_signal_t m_OnBehaviour;
|
|
rlv_behaviour_signal_t m_OnBehaviourToggle;
|
|
rlv_command_signal_t m_OnCommand;
|
|
mutable std::list<RlvExtCommandHandler*> m_CommandHandlers;
|
|
boost::signals2::scoped_connection m_ExperienceEventConn;
|
|
boost::signals2::scoped_connection m_TeleportFailedConn;
|
|
boost::signals2::scoped_connection m_TeleportFinishedConn;
|
|
|
|
static bool m_fEnabled; // Use setEnabled() to toggle this
|
|
|
|
bool m_fCanCancelTp; // @accepttp=n and @tpto=force
|
|
mutable LLVector3d m_posSitSource; // @standtp=n (mutable because onForceXXX handles are all declared as const)
|
|
bool m_fPendingGroundSit = false; // @sitground=force
|
|
LLUUID m_idPendingSitActor; // @sit=force and @sitground=force
|
|
LLUUID m_idPendingUnsitActor; // @unsit=force
|
|
mutable LLUUID m_idAgentGroup; // @setgroup=n
|
|
std::pair<LLUUID, std::string> m_PendingGroupChange; // @setgroup=force
|
|
std::pair<LLTimer, LLUUID> m_GroupChangeExpiration; // @setgroup=force
|
|
|
|
std::string m_strCameraPresetRestore; // @setcam_eyeoffset, @setcam_eyeoffsetscale and @setcam_focusoffset
|
|
|
|
friend class RlvSharedRootFetcher; // Fetcher needs access to m_fFetchComplete
|
|
friend class RlvGCTimer; // Timer clear its own point at destruction
|
|
template<ERlvBehaviourOptionType> friend struct RlvBehaviourGenericHandler;
|
|
template<ERlvParamType> friend struct RlvCommandHandlerBaseImpl;
|
|
template<ERlvParamType, ERlvBehaviour> friend struct RlvCommandHandler;
|
|
template<ERlvBehaviourModifier> friend class RlvBehaviourModifierHandler;
|
|
|
|
// --------------------------------
|
|
|
|
/*
|
|
* Internal access functions
|
|
*/
|
|
public:
|
|
const rlv_object_map_t& getObjectMap() const { return m_Objects; }
|
|
};
|
|
|
|
typedef RlvHandler rlv_handler_t;
|
|
extern rlv_handler_t gRlvHandler;
|
|
|
|
// ============================================================================
|
|
// Inlined member functions
|
|
//
|
|
|
|
inline RlvHandler& RlvHandler::instance()
|
|
{
|
|
return gRlvHandler;
|
|
}
|
|
|
|
inline RlvHandler* RlvHandler::getInstance()
|
|
{
|
|
return &gRlvHandler;
|
|
}
|
|
|
|
inline RlvObject* RlvHandler::getObject(const LLUUID& idRlvObj) const
|
|
{
|
|
auto itObj = m_Objects.find(idRlvObj);
|
|
return (m_Objects.end() != itObj) ? const_cast<RlvObject*>(&itObj->second) : nullptr;
|
|
}
|
|
|
|
inline bool RlvHandler::hasBehaviour(ERlvBehaviour eBhvr, const std::string& strOption) const
|
|
{
|
|
return hasBehaviourExcept(eBhvr, strOption, LLUUID::null);
|
|
}
|
|
|
|
inline bool RlvHandler::hasBehaviourExcept(ERlvBehaviour eBhvr, const LLUUID& idObj) const
|
|
{
|
|
return hasBehaviourExcept(eBhvr, LLStringUtil::null, idObj);
|
|
}
|
|
|
|
// ============================================================================
|
|
|
|
#endif // RLV_HANDLER_H
|