Split behaviour modifiers into global scope (impacts all of RLV or other objects) and local scope (modifies only the behaviour only on that particular object)

master
Kitty Barnett 2021-01-05 02:54:10 +01:00
parent 6b0838e59e
commit ab5f4be459
3 changed files with 155 additions and 35 deletions

View File

@ -1782,7 +1782,7 @@ ERlvCmdRet RlvBehaviourGenericHandler<RLV_OPTION_MODIFIER>::onCommand(const RlvC
// 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)) )
if ( (!rlvCmd.hasOption()) || (!pBhvrModifier) || (!pBhvrModifier->convertOptionValue(rlvCmd.getOption(), pBhvrModifier->getType(), modValue)) )
return RLV_RET_FAILED_OPTION;
// HACK-RLVa: reference counting doesn't happen until control returns to our caller but the modifier callbacks will happen now so we need to adjust the reference counts here
@ -1803,15 +1803,22 @@ ERlvCmdRet RlvBehaviourGenericHandler<RLV_OPTION_MODIFIER>::onCommand(const RlvC
return RLV_RET_SUCCESS;
}
// Handles: @bhvr[:<modifier>]=n|y
// Handles: @bhvr=n, @bhvr:<global modifier>=n|y and @bhvr:<local modifier>=force
template<>
ERlvCmdRet RlvBehaviourGenericHandler<RLV_OPTION_NONE_OR_MODIFIER>::onCommand(const RlvCommand& rlvCmd, bool& fRefCount)
{
// If there is an option then it should specify a valid modifier (and reference count)
if (rlvCmd.hasOption())
if ( (rlvCmd.getParamType() & RLV_TYPE_ADDREM) && (rlvCmd.hasOption()) )
{
// @bhvr:<global modifier>=n|y : if there is an option then it should specify a valid global modifier and if so we reference count
return RlvBehaviourGenericHandler<RLV_OPTION_MODIFIER>::onCommand(rlvCmd, fRefCount);
}
else if (rlvCmd.getParamType() == RLV_TYPE_FORCE)
{
// @bhvr:<local modifier>=force : local modifiers hide behind their primary behaviour which knows how to handle them
return rlvCmd.getBehaviourInfo()->processModifier(rlvCmd);
}
// Add the default option on an empty modifier if needed
// @bhvr=n : add the default option on an empty modifier if needed
RlvBehaviourModifier* pBhvrModifier = RlvBehaviourDictionary::instance().getModifierFromBehaviour(rlvCmd.getBehaviourType());
if ( (pBhvrModifier) && (pBhvrModifier->getAddDefault()) )
{
@ -2622,7 +2629,7 @@ ERlvCmdRet RlvForceGenericHandler<RLV_OPTION_MODIFIER>::onCommand(const RlvComma
// 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)) )
if ( (!rlvCmd.hasOption()) || (!pBhvrModifier) || (!pBhvrModifier->convertOptionValue(rlvCmd.getOption(), pBhvrModifier->getType(), modValue)) )
return RLV_RET_FAILED_OPTION;
pBhvrModifier->setValue(modValue, rlvCmd.getObjectID());

View File

@ -394,20 +394,36 @@ void RlvBehaviourDictionary::clearModifiers(const LLUUID& idRlvObj)
}
}
const RlvBehaviourInfo* RlvBehaviourDictionary::getBehaviourInfo(const std::string& strBhvr, ERlvParamType eParamType, bool* pfStrict) const
const RlvBehaviourInfo* RlvBehaviourDictionary::getBehaviourInfo(const std::string& strBhvr, ERlvParamType eParamType, bool* pfStrict, ERlvBehaviourModifier* peBhvrModifier) const
{
bool fStrict = boost::algorithm::ends_with(strBhvr, "_sec");
size_t idxBhvrLastPart = strBhvr.find_last_of('_');
std::string strBhvrLastPart((std::string::npos != idxBhvrLastPart) && (idxBhvrLastPart < strBhvr.size()) ? strBhvr.substr(idxBhvrLastPart + 1) : LLStringUtil::null);
bool fStrict = (strBhvrLastPart.compare("sec") == 0);
if (pfStrict)
*pfStrict = fStrict;
ERlvBehaviourModifier eBhvrModifier = RLV_MODIFIER_UNKNOWN;
rlv_string2info_map_t::const_iterator itBhvr = m_String2InfoMap.find(std::make_pair( (!fStrict) ? strBhvr : strBhvr.substr(0, strBhvr.size() - 4), (eParamType & RLV_TYPE_ADDREM) ? RLV_TYPE_ADDREM : eParamType));
return ( (itBhvr != m_String2InfoMap.end()) && ((!fStrict) || (itBhvr->second->hasStrict())) ) ? itBhvr->second : NULL;
if ( (m_String2InfoMap.end() == itBhvr) && (!fStrict) && (!strBhvrLastPart.empty()) && (RLV_TYPE_FORCE == eParamType) )
{
// No match found but it could still be a local scope modifier
auto itBhvrMod = m_String2InfoMap.find(std::make_pair(strBhvr.substr(0, idxBhvrLastPart), RLV_TYPE_ADDREM));
if ( (m_String2InfoMap.end() != itBhvrMod) && (eBhvrModifier = itBhvrMod->second->lookupBehaviourModifier(strBhvrLastPart)) != RLV_MODIFIER_UNKNOWN)
itBhvr = itBhvrMod;
}
if (peBhvrModifier)
*peBhvrModifier = eBhvrModifier;
return ( (itBhvr != m_String2InfoMap.end()) && ((!fStrict) || (itBhvr->second->hasStrict())) ) ? itBhvr->second : nullptr;
}
ERlvBehaviour RlvBehaviourDictionary::getBehaviourFromString(const std::string& strBhvr, ERlvParamType eParamType, bool* pfStrict) const
{
const RlvBehaviourInfo* pBhvrInfo = getBehaviourInfo(strBhvr, eParamType, pfStrict);
return (pBhvrInfo) ? pBhvrInfo->getBehaviourType() : RLV_BHVR_UNKNOWN;
ERlvBehaviourModifier eBhvrModifier;
const RlvBehaviourInfo* pBhvrInfo = getBehaviourInfo(strBhvr, eParamType, pfStrict, &eBhvrModifier);
// Filter out locally scoped modifier commands since they don't actually have a unique behaviour value of their own
return (pBhvrInfo && RLV_MODIFIER_UNKNOWN != eBhvrModifier) ? pBhvrInfo->getBehaviourType() : RLV_BHVR_UNKNOWN;
}
bool RlvBehaviourDictionary::getCommands(const std::string& strMatch, ERlvParamType eParamType, std::list<std::string>& cmdList) const
@ -456,6 +472,42 @@ void RlvBehaviourDictionary::toggleBehaviourFlag(const std::string& strBhvr, ERl
}
}
// ============================================================================
// RlvBehaviourInfo
//
// virtual
ERlvCmdRet RlvBehaviourInfo::processModifier(const RlvCommand& rlvCmd) const
{
// The object should be holding at least one active behaviour
if (!gRlvHandler.hasBehaviour(rlvCmd.getObjectID()))
return RLV_RET_FAILED_NOBEHAVIOUR;
auto itBhvrModifier = std::find_if(m_BhvrModifiers.begin(), m_BhvrModifiers.end(), [&rlvCmd](const modifier_lookup_t::value_type& entry) { return std::get<0>(entry.second) == rlvCmd.getBehaviourModifier(); });
if (m_BhvrModifiers.end() == itBhvrModifier)
return RLV_RET_FAILED_UNKNOWN;
ERlvCmdRet eCmdRet; const modifier_handler_func_t& fnHandler = std::get<2>(itBhvrModifier->second);
if (rlvCmd.hasOption())
{
// If there's an option parse it (and perform type checking)
RlvBehaviourModifierValue modValue;
if ( (rlvCmd.hasOption()) && (!RlvBehaviourModifier::convertOptionValue(rlvCmd.getOption(), std::get<1>(itBhvrModifier->second), modValue)) )
return RLV_RET_FAILED_OPTION;
eCmdRet = (fnHandler) ? fnHandler(rlvCmd.getObjectID(), modValue) : RLV_RET_SUCCESS;
if (RLV_RET_SUCCESS == eCmdRet)
gRlvHandler.getObject(rlvCmd.getObjectID())->setModifierValue(rlvCmd.getBehaviourModifier(), modValue);
}
else
{
eCmdRet = (fnHandler) ? fnHandler(rlvCmd.getObjectID(), boost::none) : RLV_RET_SUCCESS;
if (RLV_RET_SUCCESS == eCmdRet)
gRlvHandler.getObject(rlvCmd.getObjectID())->clearModifierValue(rlvCmd.getBehaviourModifier());
}
return eCmdRet;
}
// ============================================================================
// RlvBehaviourModifier
//
@ -570,21 +622,22 @@ void RlvBehaviourModifier::setValue(const RlvBehaviourModifierValue& modValue, c
}
}
bool RlvBehaviourModifier::convertOptionValue(const std::string& optionValue, RlvBehaviourModifierValue& modValue) const
// static
bool RlvBehaviourModifier::convertOptionValue(const std::string& optionValue, const std::type_index& modType, RlvBehaviourModifierValue& modValue)
{
try
{
if (typeid(float) == m_DefaultValue.type())
if (modType == typeid(float))
{
modValue = std::stof(optionValue);
return true;
}
else if (typeid(int) == m_DefaultValue.type())
else if (modType == typeid(int))
{
modValue = std::stoi(optionValue);
return true;
}
else if (typeid(LLVector3) == m_DefaultValue.type())
else if (modType == typeid(LLVector3))
{
LLVector3 vecOption;
if (3 == sscanf(optionValue.c_str(), "%f/%f/%f", vecOption.mV + 0, vecOption.mV + 1, vecOption.mV + 2))
@ -593,7 +646,7 @@ bool RlvBehaviourModifier::convertOptionValue(const std::string& optionValue, Rl
return true;
}
}
else if (typeid(LLUUID) == m_DefaultValue.type())
else if (modType == typeid(LLUUID))
{
LLUUID idOption;
if (LLUUID::parseUUID(optionValue, &idOption))
@ -615,7 +668,7 @@ bool RlvBehaviourModifier::convertOptionValue(const std::string& optionValue, Rl
//
RlvCommand::RlvCommand(const LLUUID& idObj, const std::string& strCommand)
: m_fValid(false), m_idObj(idObj), m_pBhvrInfo(NULL), m_eParamType(RLV_TYPE_UNKNOWN), m_fStrict(false), m_fRefCounted(false)
: m_idObj(idObj)
{
if (m_fValid = parseCommand(strCommand, m_strBehaviour, m_strOption, m_strParam))
{
@ -643,7 +696,7 @@ RlvCommand::RlvCommand(const LLUUID& idObj, const std::string& strCommand)
return;
}
m_pBhvrInfo = RlvBehaviourDictionary::instance().getBehaviourInfo(m_strBehaviour, m_eParamType, &m_fStrict);
m_pBhvrInfo = RlvBehaviourDictionary::instance().getBehaviourInfo(m_strBehaviour, m_eParamType, &m_fStrict, &m_eBhvrModifier);
}
RlvCommand::RlvCommand(const RlvCommand& rlvCmd, ERlvParamType eParamType)
@ -1074,6 +1127,20 @@ std::string RlvObject::getStatusString(const std::string& strFilter, const std::
return strStatus;
}
void RlvObject::clearModifierValue(ERlvBehaviourModifier eBhvrModifier)
{
m_Modifiers.erase(eBhvrModifier);
}
void RlvObject::setModifierValue(ERlvBehaviourModifier eBhvrModifier, const RlvBehaviourModifierValue& newValue)
{
auto itBhvrModifierValue = m_Modifiers.find(eBhvrModifier);
if (m_Modifiers.end() != itBhvrModifierValue)
itBhvrModifierValue->second = newValue;
else
m_Modifiers.insert(std::make_pair(eBhvrModifier, newValue));
}
// ============================================================================
// RlvForceWear
//

View File

@ -38,6 +38,7 @@ struct RlvBehaviourModifierComp;
class RlvBehaviourInfo
{
typedef std::function<ERlvCmdRet(const LLUUID& idRlvObj, const boost::optional<RlvBehaviourModifierValue>)> modifier_handler_func_t;
public:
enum EBehaviourFlags
{
@ -65,24 +66,29 @@ public:
: m_strBhvr(strBhvr), m_eBhvr(eBhvr), m_maskParamType(maskParamType), m_nBhvrFlags(nBhvrFlags) {}
virtual ~RlvBehaviourInfo() {}
const std::string& getBehaviour() const { return m_strBhvr; }
ERlvBehaviour getBehaviourType() const { return m_eBhvr; }
U32 getBehaviourFlags() const { return m_nBhvrFlags; }
U32 getParamTypeMask() const { return m_maskParamType; }
bool hasStrict() const { return m_nBhvrFlags & BHVR_STRICT; }
bool isBlocked() const { return m_nBhvrFlags & BHVR_BLOCKED; }
bool isExperimental() const { return m_nBhvrFlags & BHVR_EXPERIMENTAL; }
bool isExtended() const { return m_nBhvrFlags & BHVR_EXTENDED; }
bool isSynonym() const { return m_nBhvrFlags & BHVR_SYNONYM; }
void toggleBehaviourFlag(EBehaviourFlags eBhvrFlag, bool fEnable);
void addModifier(ERlvBehaviourModifier eBhvrMod, const std::type_info& valueType, const std::string& strBhvrMod, modifier_handler_func_t fnHandler = nullptr);
const std::string& getBehaviour() const { return m_strBhvr; }
ERlvBehaviour getBehaviourType() const { return m_eBhvr; }
U32 getBehaviourFlags() const { return m_nBhvrFlags; }
U32 getParamTypeMask() const { return m_maskParamType; }
bool hasStrict() const { return m_nBhvrFlags & BHVR_STRICT; }
bool isBlocked() const { return m_nBhvrFlags & BHVR_BLOCKED; }
bool isExperimental() const { return m_nBhvrFlags & BHVR_EXPERIMENTAL; }
bool isExtended() const { return m_nBhvrFlags & BHVR_EXTENDED; }
bool isSynonym() const { return m_nBhvrFlags & BHVR_SYNONYM; }
ERlvBehaviourModifier lookupBehaviourModifier(const std::string& strBhvrMod) const;
void toggleBehaviourFlag(EBehaviourFlags eBhvrFlag, bool fEnable);
virtual ERlvCmdRet processCommand(const RlvCommand& rlvCmd) const { return RLV_RET_NO_PROCESSOR; }
virtual ERlvCmdRet processModifier(const RlvCommand& rlvCmd) const;
protected:
std::string m_strBhvr;
ERlvBehaviour m_eBhvr;
U32 m_nBhvrFlags;
U32 m_maskParamType;
typedef std::map<std::string, std::tuple<ERlvBehaviourModifier, std::type_index, modifier_handler_func_t>> modifier_lookup_t;
modifier_lookup_t m_BhvrModifiers;
};
// ============================================================================
@ -106,7 +112,7 @@ public:
public:
void clearModifiers(const LLUUID& idRlvObj);
ERlvBehaviour getBehaviourFromString(const std::string& strBhvr, ERlvParamType eParamType, bool* pfStrict = NULL) const;
const RlvBehaviourInfo* getBehaviourInfo(const std::string& strBhvr, ERlvParamType eParamType, bool* pfStrict = NULL) const;
const RlvBehaviourInfo* getBehaviourInfo(const std::string& strBhvr, ERlvParamType eParamType, bool* pfStrict = nullptr, ERlvBehaviourModifier* eBhvrModifier = nullptr) const;
bool getCommands(const std::string& strMatch, ERlvParamType eParamType, std::list<std::string>& cmdList) const;
bool getHasStrict(ERlvBehaviour eBhvr) const;
RlvBehaviourModifier* getModifier(ERlvBehaviourModifier eBhvrMod) const { return (eBhvrMod < RLV_MODIFIER_COUNT) ? m_BehaviourModifiers[eBhvrMod] : nullptr; }
@ -244,12 +250,13 @@ protected:
virtual void onValueChange() const {}
public:
bool addValue(const RlvBehaviourModifierValue& modValue, const LLUUID& idRlvObj, ERlvBehaviour eBhvr = RLV_BHVR_UNKNOWN);
bool convertOptionValue(const std::string& optionValue, RlvBehaviourModifierValue& modValue) const;
static bool convertOptionValue(const std::string& optionValue, const std::type_index& modType, RlvBehaviourModifierValue& modValue);
void clearValues(const LLUUID& idRlvObj);
bool getAddDefault() const { return m_fAddDefaultOnEmpty; }
const RlvBehaviourModifierValue& getDefaultValue() const { return m_DefaultValue; }
const LLUUID& getPrimaryObject() const;
const std::string& getName() const { return m_strName; }
const std::type_info& getType() const { return m_DefaultValue.type(); }
const RlvBehaviourModifierValue& getValue() const { return (hasValue()) ? std::get<0>(m_Values.front()) : m_DefaultValue; }
template<typename T> const T& getValue() const { return boost::get<T>(getValue()); }
bool hasValue() const;
@ -289,14 +296,17 @@ public:
public:
std::string asString() const;
const std::string& getBehaviour() const { return m_strBehaviour; }
const RlvBehaviourInfo* getBehaviourInfo() const { return m_pBhvrInfo; }
ERlvBehaviour getBehaviourType() const { return (m_pBhvrInfo) ? m_pBhvrInfo->getBehaviourType() : RLV_BHVR_UNKNOWN; }
U32 getBehaviourFlags() const{ return (m_pBhvrInfo) ? m_pBhvrInfo->getBehaviourFlags() : 0; }
ERlvBehaviourModifier getBehaviourModifier() const { return m_eBhvrModifier; }
const LLUUID& getObjectID() const { return m_idObj; }
const std::string& getOption() const { return m_strOption; }
const std::string& getParam() const { return m_strParam; }
ERlvParamType getParamType() const { return m_eParamType; }
bool hasOption() const { return !m_strOption.empty(); }
bool isBlocked() const { return (m_pBhvrInfo) ? m_pBhvrInfo->isBlocked() : false; }
bool isModifier() const { return RLV_MODIFIER_UNKNOWN != m_eBhvrModifier; }
bool isRefCounted() const { return m_fRefCounted; }
bool isStrict() const { return m_fStrict; }
bool isValid() const { return m_fValid; }
@ -316,15 +326,16 @@ public:
* Member variables
*/
protected:
bool m_fValid;
bool m_fValid = false;
LLUUID m_idObj;
std::string m_strBehaviour;
const RlvBehaviourInfo* m_pBhvrInfo;
ERlvParamType m_eParamType;
bool m_fStrict;
const RlvBehaviourInfo* m_pBhvrInfo = nullptr;
ERlvParamType m_eParamType = RLV_TYPE_UNKNOWN;
ERlvBehaviourModifier m_eBhvrModifier = RLV_MODIFIER_UNKNOWN;
bool m_fStrict = false;
std::string m_strOption;
std::string m_strParam;
mutable bool m_fRefCounted;
mutable bool m_fRefCounted = false;
friend class RlvHandler;
friend class RlvObject;
@ -452,6 +463,14 @@ public:
bool hasLookup() const { return m_fLookup; }
const rlv_command_list_t& getCommandList() const { return m_Commands; }
/*
* Local-scope modifiers
*/
public:
void clearModifierValue(ERlvBehaviourModifier eBhvrMod);
template<typename T> bool getModifierValue(ERlvBehaviourModifier eBhvrModifier, T& value) const;
void setModifierValue(ERlvBehaviourModifier eBhvrMod, const RlvBehaviourModifierValue& modValue);
/*
* Member variables
*/
@ -462,6 +481,8 @@ protected:
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)
typedef std::map<ERlvBehaviourModifier, RlvBehaviourModifierValue> bhvr_modifier_map_t;
bhvr_modifier_map_t m_Modifiers; // List of (local scope) modifiers set on this object
friend class RlvHandler;
};
@ -686,6 +707,19 @@ std::string rlvGetLastParenthesisedText(const std::string& strText, std::string:
// Inlined class member functions
//
inline void RlvBehaviourInfo::addModifier(ERlvBehaviourModifier eBhvrMod, const std::type_info& valueType, const std::string& strBhvrMod, modifier_handler_func_t fnHandler)
{
RLV_ASSERT_DBG(m_BhvrModifiers.find(strBhvrMod) == m_BhvrModifiers.end());
m_BhvrModifiers.insert(std::make_pair(strBhvrMod, std::make_tuple(eBhvrMod, std::type_index(valueType), fnHandler)));
}
inline ERlvBehaviourModifier RlvBehaviourInfo::lookupBehaviourModifier(const std::string& strBhvrMod) const
{
auto itBhvrModifier = m_BhvrModifiers.find(strBhvrMod);
return (m_BhvrModifiers.end() != itBhvrModifier) ? std::get<0>(itBhvrModifier->second) : RLV_MODIFIER_UNKNOWN;
}
inline void RlvBehaviourInfo::toggleBehaviourFlag(EBehaviourFlags eBhvrFlag, bool fEnable)
{
if (fEnable)
@ -710,6 +744,18 @@ inline bool RlvCommand::operator ==(const RlvCommand& rhs) const
( (RLV_TYPE_UNKNOWN != m_eParamType) ? (m_eParamType == rhs.m_eParamType) : (m_strParam == rhs.m_strParam) );
}
template <typename T>
inline bool RlvObject::getModifierValue(ERlvBehaviourModifier eBhvrModifier, T& value) const
{
auto itBhvrModifierValue = m_Modifiers.find(eBhvrModifier);
if (m_Modifiers.end() != itBhvrModifierValue)
{
value = boost::get<T>(itBhvrModifierValue->second);
return true;
}
return false;
}
// Checked: 2010-04-05 (RLVa-1.2.0d) | Modified: RLVa-1.2.0d
inline bool RlvForceWear::isWearableItem(const LLInventoryItem* pItem)
{