From 68025f9e1d15e45f7efc94e66f7ea067eed471ad Mon Sep 17 00:00:00 2001 From: Kitty Barnett Date: Sun, 15 May 2016 00:35:54 +0200 Subject: [PATCH] Added behaviour modifiers as a prelude to camera restrictions and other fun goodies --HG-- branch : RLVa --- indra/newview/rlvcommon.h | 1 + indra/newview/rlvdefines.h | 12 +++- indra/newview/rlvhandler.cpp | 41 ++++++++++++- indra/newview/rlvhelper.cpp | 83 +++++++++++++++++++++++++ indra/newview/rlvhelper.h | 114 +++++++++++++++++++++++++++++++++-- 5 files changed, 244 insertions(+), 7 deletions(-) diff --git a/indra/newview/rlvcommon.h b/indra/newview/rlvcommon.h index fd52640290..89da91c9d0 100644 --- a/indra/newview/rlvcommon.h +++ b/indra/newview/rlvcommon.h @@ -56,6 +56,7 @@ class RlvObject; struct RlvException; typedef boost::variant RlvExceptionOption; +typedef boost::variant RlvBehaviourModifierValue; class RlvGCTimer; diff --git a/indra/newview/rlvdefines.h b/indra/newview/rlvdefines.h index 012ff3efbc..a2d4864e69 100644 --- a/indra/newview/rlvdefines.h +++ b/indra/newview/rlvdefines.h @@ -192,11 +192,19 @@ enum ERlvBehaviour { RLV_BHVR_UNKNOWN }; -enum RlvBehaviourOptionType +enum ERlvBehaviourModifier +{ + RLV_MODIFIER_COUNT, + RLV_MODIFIER_UNKNOWN +}; + +enum ERlvBehaviourOptionType { RLV_OPTION_NONE, RLV_OPTION_EXCEPTION, - RLV_OPTION_NONE_OR_EXCEPTION + RLV_OPTION_NONE_OR_EXCEPTION, + RLV_OPTION_MODIFIER, + RLV_OPTION_NONE_OR_MODIFIER }; enum ERlvParamType { diff --git a/indra/newview/rlvhandler.cpp b/indra/newview/rlvhandler.cpp index 0da5daeee2..5cc7257afd 100644 --- a/indra/newview/rlvhandler.cpp +++ b/indra/newview/rlvhandler.cpp @@ -119,7 +119,7 @@ RlvHandler::RlvHandler() : m_fCanCancelTp(true), m_posSitSource(), m_pGCTimer(NU { gAgent.addListener(this, "new group"); - // Array auto-initialization to 0 is non-standard? (Compiler warning in VC-8.0) + // Array auto-initialization to 0 is still not supported in VS2013 memset(m_Behaviours, 0, sizeof(S16) * RLV_BHVR_COUNT); } @@ -1360,6 +1360,45 @@ ERlvCmdRet RlvBehaviourGenericHandler::onCommand(c return RlvBehaviourGenericHandler::onCommand(rlvCmd, fRefCount); } +// Handles: @bhvr:=n|y +ERlvCmdRet RlvBehaviourGenericHandler::onCommand(const RlvCommand& rlvCmd, bool& fRefCount) +{ + // There should be an option and it should specify a valid modifier (RlvBehaviourModifier performs the appropriate type checks) + RlvBehaviourModifier* pBhvrModifier = RlvBehaviourDictionary::instance().getModifierFromBehaviour(rlvCmd.getBehaviourType()); + RlvBehaviourModifierValue modValue; + if ( (!rlvCmd.hasOption()) || (!pBhvrModifier) || (!pBhvrModifier->convertOptionValue(rlvCmd.getOption(), modValue)) ) + return RLV_RET_FAILED_OPTION; + + if (RLV_TYPE_ADD == rlvCmd.getParamType()) + pBhvrModifier->addValue(modValue); + else + pBhvrModifier->removeValue(modValue); + + fRefCount = true; + return RLV_RET_SUCCESS; +} + +// Handles: @bhvr[:]=n|y +ERlvCmdRet RlvBehaviourGenericHandler::onCommand(const RlvCommand& rlvCmd, bool& fRefCount) +{ + // If there is an option then it should specify a valid modifier (and reference count) + if (rlvCmd.hasOption()) + return RlvBehaviourGenericHandler::onCommand(rlvCmd, fRefCount); + + // Add the default option on an empty modifier if needed + RlvBehaviourModifier* pBhvrModifier = RlvBehaviourDictionary::instance().getModifierFromBehaviour(rlvCmd.getBehaviourType()); + if ( (pBhvrModifier) && (pBhvrModifier->getAddDefault()) ) + { + if (RLV_TYPE_ADD == rlvCmd.getParamType()) + pBhvrModifier->addValue(pBhvrModifier->getDefaultValue()); + else + pBhvrModifier->removeValue(pBhvrModifier->getDefaultValue()); + } + + fRefCount = true; + return RLV_RET_SUCCESS; +} + // Handles: @addattach[:]=n|y and @remattach[:]=n|y template<> template<> ERlvCmdRet RlvBehaviourAddRemAttachHandler::onCommand(const RlvCommand& rlvCmd, bool& fRefCount) diff --git a/indra/newview/rlvhelper.cpp b/indra/newview/rlvhelper.cpp index cfbf085d75..7960683e16 100644 --- a/indra/newview/rlvhelper.cpp +++ b/indra/newview/rlvhelper.cpp @@ -32,8 +32,14 @@ // RlvBehaviourDictionary // +static RlvBehaviourModifier_CompMin s_RlvBehaviourModifier_CompMin; +static RlvBehaviourModifier_CompMax s_RlvBehaviourModifier_CompMax; + RlvBehaviourDictionary::RlvBehaviourDictionary() { + // Array auto-initialization to 0 is still not supported in VS2013 + memset(m_BehaviourModifiers, 0, sizeof(RlvBehaviourModifier*) * RLV_MODIFIER_COUNT); + // // Restrictions // @@ -219,6 +225,12 @@ RlvBehaviourDictionary::~RlvBehaviourDictionary() for (const RlvBehaviourInfo* pBhvrInfo : m_BhvrInfoList) delete pBhvrInfo; m_BhvrInfoList.clear(); + + for (int idxBhvrMod = 0; idxBhvrMod < RLV_MODIFIER_COUNT; idxBhvrMod++) + { + delete m_BehaviourModifiers[idxBhvrMod]; + m_BehaviourModifiers[idxBhvrMod] = nullptr; + } } void RlvBehaviourDictionary::addEntry(const RlvBehaviourInfo* pEntry) @@ -241,6 +253,15 @@ void RlvBehaviourDictionary::addEntry(const RlvBehaviourInfo* pEntry) m_BhvrInfoList.push_back(pEntry); } +void RlvBehaviourDictionary::addModifier(ERlvBehaviour eBhvr, ERlvBehaviourModifier eModifier, RlvBehaviourModifier* pModifierEntry) +{ + if (eModifier < RLV_MODIFIER_COUNT) + { + m_BehaviourModifiers[eModifier] = pModifierEntry; + m_Bhvr2ModifierMap.insert(std::make_pair(eBhvr, eModifier)); + } +} + const RlvBehaviourInfo* RlvBehaviourDictionary::getBehaviourInfo(const std::string& strBhvr, ERlvParamType eParamType, bool* pfStrict) const { bool fStrict = boost::algorithm::ends_with(strBhvr, "_sec"); @@ -287,6 +308,13 @@ bool RlvBehaviourDictionary::getHasStrict(ERlvBehaviour eBhvr) const return false; } +RlvBehaviourModifier* RlvBehaviourDictionary::getModifierFromBehaviour(ERlvBehaviour eBhvr) const +{ + rlv_bhvr2mod_map_t::const_iterator itMod = m_Bhvr2ModifierMap.find(eBhvr); + ERlvBehaviourModifier eBhvrMod = (m_Bhvr2ModifierMap.end() != itMod) ? itMod->second : RLV_MODIFIER_UNKNOWN; + return (eBhvrMod < RLV_MODIFIER_UNKNOWN) ? m_BehaviourModifiers[eBhvrMod] : nullptr; +} + void RlvBehaviourDictionary::toggleBehaviourFlag(const std::string& strBhvr, ERlvParamType eParamType, RlvBehaviourInfo::EBehaviourFlags eBhvrFlag, bool fEnable) { rlv_string2info_map_t::const_iterator itBhvr = m_String2InfoMap.find(std::make_pair(strBhvr, (eParamType & RLV_TYPE_ADDREM) ? RLV_TYPE_ADDREM : eParamType)); @@ -296,6 +324,61 @@ void RlvBehaviourDictionary::toggleBehaviourFlag(const std::string& strBhvr, ERl } } +// ============================================================================ +// RlvBehaviourModifier +// + +RlvBehaviourModifier::RlvBehaviourModifier(const RlvBehaviourModifierValue& defaultValue, bool fAddDefaultOnEmpty, RlvBehaviourModifier_Comp* pValueComparator) + : m_DefaultValue(defaultValue), m_fAddDefaultOnEmpty(fAddDefaultOnEmpty), m_pValueComparator(pValueComparator) +{ +} + +bool RlvBehaviourModifier::addValue(const RlvBehaviourModifierValue& modValue) +{ + if (modValue.which() == m_DefaultValue.which()) + { + m_Values.insert((m_pValueComparator) ? std::lower_bound(m_Values.begin(), m_Values.end(), modValue, boost::bind(&RlvBehaviourModifier_Comp::operator(), m_pValueComparator, _1, _2)) : m_Values.end(), modValue); + m_ChangeSignal(getValue()); + return true; + } + return false; +} + +void RlvBehaviourModifier::removeValue(const RlvBehaviourModifierValue& modValue) +{ + if ( (modValue.which() == m_DefaultValue.which()) ) + { + auto itValue = std::find(m_Values.begin(), m_Values.end(), modValue); + if (m_Values.end() != itValue) + { + m_Values.erase(itValue); + m_ChangeSignal(getValue()); + } + } +} + +bool RlvBehaviourModifier::convertOptionValue(const std::string& optionValue, RlvBehaviourModifierValue& modValue) const +{ + try + { + if (typeid(float) == m_DefaultValue.type()) + { + modValue = std::stof(optionValue.c_str()); + return true; + } + else if (typeid(int) == m_DefaultValue.type()) + { + modValue = std::stoi(optionValue.c_str()); + return true; + } + return false; + } + catch (const std::invalid_argument&) + { + return false; + } +} + // ============================================================================ // RlvCommmand // diff --git a/indra/newview/rlvhelper.h b/indra/newview/rlvhelper.h index f3deb05cc6..6d07f03dc6 100644 --- a/indra/newview/rlvhelper.h +++ b/indra/newview/rlvhelper.h @@ -141,14 +141,14 @@ template> using RlvReplyProcessor = RlvCommandProcessor; // Provides pre-defined generic implementations of basic behaviours (template voodoo - see original commit for something that still made sense) -template struct RlvBehaviourGenericHandler { static ERlvCmdRet onCommand(const RlvCommand& rlvCmd, bool& fRefCount); }; -template using RlvBehaviourGenericProcessor = RlvBehaviourProcessor>; +template struct RlvBehaviourGenericHandler { static ERlvCmdRet onCommand(const RlvCommand& rlvCmd, bool& fRefCount); }; +template using RlvBehaviourGenericProcessor = RlvBehaviourProcessor>; // ============================================================================ // RlvBehaviourProcessor and related classes - Handles add/rem comamnds aka "restrictions) // -template > +template > class RlvBehaviourToggleProcessor : public RlvBehaviourInfo { public: @@ -156,6 +156,107 @@ public: ERlvCmdRet processCommand(const RlvCommand& rlvCmd) const override { return RlvCommandHandlerBaseImpl::processCommand(rlvCmd, &RlvBehaviourGenericHandler::onCommand, &toggleHandlerImpl::onCommandToggle); } }; +// ============================================================================ +// RlvBehaviourModifier - stores behaviour modifiers in an - optionally - sorted list and returns the first element (or default value if there are no modifiers) +// + +struct RlvBehaviourModifier_Comp { virtual bool operator()(const RlvBehaviourModifierValue& lhs, const RlvBehaviourModifierValue& rhs) = 0; }; +struct RlvBehaviourModifier_CompMin : public RlvBehaviourModifier_Comp { bool operator()(const RlvBehaviourModifierValue& lhs, const RlvBehaviourModifierValue& rhs) override { return lhs < rhs; } }; +struct RlvBehaviourModifier_CompMax : public RlvBehaviourModifier_Comp { bool operator()(const RlvBehaviourModifierValue& lhs, const RlvBehaviourModifierValue& rhs) override { return rhs < lhs; } }; + +class RlvBehaviourModifier +{ +public: + RlvBehaviourModifier(const RlvBehaviourModifierValue& defaultValue, bool fAddDefaultOnEmpty, RlvBehaviourModifier_Comp* pValueComparator); + + /* + * Member functions + */ +public: + bool addValue(const RlvBehaviourModifierValue& modValue); + bool convertOptionValue(const std::string& optionValue, RlvBehaviourModifierValue& modValue) const; + bool getAddDefault() const { return m_fAddDefaultOnEmpty; } + const RlvBehaviourModifierValue& getDefaultValue() const { return m_DefaultValue; } + const RlvBehaviourModifierValue& getValue() const { return (!m_Values.empty()) ? m_Values.front() : m_DefaultValue; } + template const T& getValue() const { return boost::get(getValue()); } + void removeValue(const RlvBehaviourModifierValue& modValue); + + typedef boost::signals2::signal change_signal_t; + change_signal_t& getSignal() { return m_ChangeSignal; } + + /* + * Member variables + */ +protected: + RlvBehaviourModifierValue m_DefaultValue; + bool m_fAddDefaultOnEmpty; + std::list m_Values; + change_signal_t m_ChangeSignal; + RlvBehaviourModifier_Comp* m_pValueComparator; +}; + +// Inspired by LLControlCache +template +class RlvBehaviourModifierCache : public LLRefCount, public LLInstanceTracker, ERlvBehaviourModifier> +{ +public: + RlvBehaviourModifierCache(ERlvBehaviourModifier eModifier) + : LLInstanceTracker, ERlvBehaviourModifier>(eModifier) + { + RlvBehaviourModifier* pBhvrModifier = (eModifier < RLV_MODIFIER_COUNT) ? RlvBehaviourDictionary::instance().getModifier(eModifier) : nullptr; + if (pBhvrModifier) + { + mConnection = pBhvrModifier->getSignal().connect(boost::bind(&RlvBehaviourModifierCache::handleValueChange, this, _1)); + mCachedValue = pBhvrModifier->getValue(); + } + else + { + mCachedValue = {}; + } + } + ~RlvBehaviourModifierCache() {} + + /* + * Member functions + */ +public: + const T& getValue() const { return mCachedValue; } +protected: + void handleValueChange(const RlvBehaviourModifierValue& newValue) { mCachedValue = boost::get(newValue); } + + /* + * Member variables + */ +protected: + T mCachedValue; + boost::signals2::scoped_connection mConnection; +}; + +// Inspired by LLCachedControl +template +class RlvCachedBehaviourModifier +{ +public: + RlvCachedBehaviourModifier(ERlvBehaviourModifier eModifier) + { + if ((mCachedModifierPtr = RlvBehaviourModifierCache::getInstance(eModifier)) == nullptr) + mCachedModifierPtr = new RlvBehaviourModifierCache(eModifier); + } + + /* + * Operators + */ +public: + operator const T&() const { return mCachedModifierPtr->getValue(); } + const T& operator()() { return mCachedModifierPtr->getValue(); } + + /* + * Member variables + */ +protected: + LLPointer> mCachedModifierPtr; +}; + // ============================================================================ // RlvBehaviourDictionary and related classes // @@ -168,6 +269,7 @@ protected: ~RlvBehaviourDictionary(); public: void addEntry(const RlvBehaviourInfo* pEntry); + void addModifier(ERlvBehaviour eBhvr, ERlvBehaviourModifier eModifier, RlvBehaviourModifier* pModifierEntry); /* * General helper functions @@ -177,7 +279,8 @@ public: const RlvBehaviourInfo* getBehaviourInfo(const std::string& strBhvr, ERlvParamType eParamType, bool* pfStrict = NULL) const; bool getCommands(const std::string& strMatch, ERlvParamType eParamType, std::list& cmdList) const; bool getHasStrict(ERlvBehaviour eBhvr) const; - const std::string& getStringFromBehaviour(ERlvBehaviour eBhvr, ERlvParamType eParamType, bool fStrict = false) const; + RlvBehaviourModifier* getModifier(ERlvBehaviourModifier eBhvrMod) const { return (eBhvrMod < RLV_MODIFIER_COUNT) ? m_BehaviourModifiers[eBhvrMod] : nullptr; } + RlvBehaviourModifier* getModifierFromBehaviour(ERlvBehaviour eBhvr) const; void toggleBehaviourFlag(const std::string& strBhvr, ERlvParamType eParamType, RlvBehaviourInfo::EBehaviourFlags eBvhrFlag, bool fEnable); /* @@ -187,10 +290,13 @@ protected: typedef std::list rlv_bhvrinfo_list_t; typedef std::map, const RlvBehaviourInfo*> rlv_string2info_map_t; typedef std::multimap rlv_bhvr2info_map_t; + typedef std::map rlv_bhvr2mod_map_t; rlv_bhvrinfo_list_t m_BhvrInfoList; rlv_string2info_map_t m_String2InfoMap; rlv_bhvr2info_map_t m_Bhvr2InfoMap; + rlv_bhvr2mod_map_t m_Bhvr2ModifierMap; + RlvBehaviourModifier* m_BehaviourModifiers[RLV_MODIFIER_COUNT]; }; // ============================================================================