Pave the way for a brighter future where behaviour modifiers aren't behaviours themselves

--HG--
branch : RLVa
meow-7.2.2
Kitty Barnett 2018-05-01 23:04:12 +02:00
parent 4de0c86332
commit 9a92faa176
6 changed files with 102 additions and 25 deletions

View File

@ -305,6 +305,7 @@ enum ERlvCmdRet {
RLV_RET_FAILED_UNKNOWN, // Command failed (unknown command)
RLV_RET_FAILED_NOSHAREDROOT, // Command failed (missing #RLV)
RLV_RET_FAILED_DEPRECATED, // Command failed (deprecated and no longer supported)
RLV_RET_FAILED_NOBEHAVIOUR, // Command failed (force modifier on an object with no active restrictions)
RLV_RET_NO_PROCESSOR // Command doesn't have a template processor define (legacy code)
};
#define RLV_RET_SUCCEEDED(eCmdRet) (((eCmdRet) & RLV_RET_SUCCESS) == RLV_RET_SUCCESS)

View File

@ -750,6 +750,7 @@ BOOL RlvFloaterConsole::postBuild()
void RlvFloaterConsole::onClose(bool fQuitting)
{
RlvBehaviourDictionary::instance().clearModifiers(gAgent.getID());
gRlvHandler.processCommand(gAgent.getID(), "clear", true);
}

View File

@ -387,6 +387,7 @@ ERlvCmdRet RlvHandler::processCommand(const RlvCommand& rlvCmd, bool fFromObj)
if (0 == itObj->second.m_Commands.size())
{
RLV_DEBUGS << "\t- command list empty => removing " << idCurObj << RLV_ENDL;
RlvBehaviourDictionary::instance().clearModifiers(idCurObj);
m_Objects.erase(itObj);
}
}
@ -1519,13 +1520,13 @@ ERlvCmdRet RlvBehaviourGenericHandler<RLV_OPTION_MODIFIER>::onCommand(const RlvC
if (RLV_TYPE_ADD == rlvCmd.getParamType())
{
gRlvHandler.m_Behaviours[rlvCmd.getBehaviourType()]++;
pBhvrModifier->addValue(modValue, rlvCmd.getObjectID());
pBhvrModifier->addValue(modValue, rlvCmd.getObjectID(), rlvCmd.getBehaviourType());
gRlvHandler.m_Behaviours[rlvCmd.getBehaviourType()]--;
}
else
{
gRlvHandler.m_Behaviours[rlvCmd.getBehaviourType()]--;
pBhvrModifier->removeValue(modValue, rlvCmd.getObjectID());
pBhvrModifier->removeValue(modValue, rlvCmd.getObjectID(), rlvCmd.getBehaviourType());
gRlvHandler.m_Behaviours[rlvCmd.getBehaviourType()]++;
}
@ -1549,13 +1550,13 @@ ERlvCmdRet RlvBehaviourGenericHandler<RLV_OPTION_NONE_OR_MODIFIER>::onCommand(co
if (RLV_TYPE_ADD == rlvCmd.getParamType())
{
gRlvHandler.m_Behaviours[rlvCmd.getBehaviourType()]++;
pBhvrModifier->addValue(pBhvrModifier->getDefaultValue(), rlvCmd.getObjectID());
pBhvrModifier->addValue(pBhvrModifier->getDefaultValue(), rlvCmd.getObjectID(), rlvCmd.getBehaviourType());
gRlvHandler.m_Behaviours[rlvCmd.getBehaviourType()]--;
}
else
{
gRlvHandler.m_Behaviours[rlvCmd.getBehaviourType()]--;
pBhvrModifier->removeValue(pBhvrModifier->getDefaultValue(), rlvCmd.getObjectID());
pBhvrModifier->removeValue(pBhvrModifier->getDefaultValue(), rlvCmd.getObjectID(), rlvCmd.getBehaviourType());
gRlvHandler.m_Behaviours[rlvCmd.getBehaviourType()]++;
}
}
@ -1828,15 +1829,15 @@ ERlvCmdRet RlvBehaviourRecvSendStartIMHandler::onCommand(const RlvCommand& rlvCm
RlvBehaviourModifier *pBhvrModDistMin = RlvBehaviourDictionary::instance().getModifier(eModDistMin), *pBhvrModDistMax = RlvBehaviourDictionary::instance().getModifier(eModDistMax);
if (RLV_TYPE_ADD == rlvCmd.getParamType())
{
pBhvrModDistMin->addValue(nDistMin * nDistMin, rlvCmd.getObjectID());
pBhvrModDistMin->addValue(nDistMin * nDistMin, rlvCmd.getObjectID(), rlvCmd.getBehaviourType());
if (optionList.size() >= 2)
pBhvrModDistMax->addValue(nDistMax * nDistMax, rlvCmd.getObjectID());
pBhvrModDistMax->addValue(nDistMax * nDistMax, rlvCmd.getObjectID(), rlvCmd.getBehaviourType());
}
else
{
pBhvrModDistMin->removeValue(nDistMin * nDistMin, rlvCmd.getObjectID());
pBhvrModDistMin->removeValue(nDistMin * nDistMin, rlvCmd.getObjectID(), rlvCmd.getBehaviourType());
if (optionList.size() >= 2)
pBhvrModDistMax->removeValue(nDistMax * nDistMax, rlvCmd.getObjectID());
pBhvrModDistMax->removeValue(nDistMax * nDistMax, rlvCmd.getObjectID(), rlvCmd.getBehaviourType());
}
fRefCount = true;
@ -2279,6 +2280,24 @@ ERlvCmdRet RlvCommandHandlerBaseImpl<RLV_TYPE_FORCE>::processCommand(const RlvCo
return (*pHandler)(rlvCmd);
}
// Handles: @bhvr:<modifier>=force
template<>
ERlvCmdRet RlvForceGenericHandler<RLV_OPTION_MODIFIER>::onCommand(const RlvCommand& rlvCmd)
{
// The object should be holding at least one active behaviour
if (!gRlvHandler.hasBehaviour(rlvCmd.getObjectID()))
return RLV_RET_FAILED_NOBEHAVIOUR;
// 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;
pBhvrModifier->setValue(modValue, rlvCmd.getObjectID());
return RLV_RET_SUCCESS;
}
// Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.1.0j
ERlvCmdRet RlvHandler::processForceCommand(const RlvCommand& rlvCmd) const
{
@ -3048,12 +3067,12 @@ ERlvCmdRet RlvBehaviourCamZoomMinMaxHandler::onCommand(const RlvCommand& rlvCmd,
if (RLV_TYPE_ADD == rlvCmd.getParamType())
{
gRlvHandler.m_Behaviours[(RLV_BHVR_CAMZOOMMIN == rlvCmd.getBehaviourType()) ? RLV_BHVR_SETCAM_FOVMIN : RLV_BHVR_SETCAM_FOVMAX]++;
pBhvrModifier->addValue(DEFAULT_FIELD_OF_VIEW / nMult, rlvCmd.getObjectID());
pBhvrModifier->addValue(DEFAULT_FIELD_OF_VIEW / nMult, rlvCmd.getObjectID(), rlvCmd.getBehaviourType());
}
else
{
gRlvHandler.m_Behaviours[(RLV_BHVR_CAMZOOMMIN == rlvCmd.getBehaviourType()) ? RLV_BHVR_SETCAM_FOVMIN : RLV_BHVR_SETCAM_FOVMAX]--;
pBhvrModifier->removeValue(DEFAULT_FIELD_OF_VIEW / nMult, rlvCmd.getObjectID());
pBhvrModifier->removeValue(DEFAULT_FIELD_OF_VIEW / nMult, rlvCmd.getObjectID(), rlvCmd.getBehaviourType());
}
}
@ -3352,7 +3371,7 @@ bool RlvHandler::hitTestOverlay(const LLCoordGL& ptMouse) const
void RlvHandler::renderOverlay()
{
if (m_pOverlayImage)
if ( (hasBehaviour(RLV_BHVR_SETOVERLAY)) && (m_pOverlayImage) )
{
if (LLGLSLShader::sNoFixedFunction)
{

View File

@ -59,6 +59,8 @@ public:
// 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)

View File

@ -369,6 +369,16 @@ void RlvBehaviourDictionary::addModifier(const RlvBehaviourInfo* pBhvrEntry, ERl
addModifier(pBhvrEntry->getBehaviourType(), eModifier, pModifierEntry);
}
// TODO: this shouldn't be in this class - find a better spot for it
void RlvBehaviourDictionary::clearModifiers(const LLUUID& idRlvObj)
{
for (int idxModifier = 0; idxModifier < RLV_MODIFIER_COUNT; idxModifier++)
{
if (m_BehaviourModifiers[idxModifier])
m_BehaviourModifiers[idxModifier]->clearValues(idRlvObj);
}
}
const RlvBehaviourInfo* RlvBehaviourDictionary::getBehaviourInfo(const std::string& strBhvr, ERlvParamType eParamType, bool* pfStrict) const
{
bool fStrict = boost::algorithm::ends_with(strBhvr, "_sec");
@ -450,11 +460,11 @@ RlvBehaviourModifier::~RlvBehaviourModifier()
}
}
bool RlvBehaviourModifier::addValue(const RlvBehaviourModifierValue& modValue, const LLUUID& idObject)
bool RlvBehaviourModifier::addValue(const RlvBehaviourModifierValue& modValue, const LLUUID& idRlvObj, ERlvBehaviour eBhvr)
{
if (modValue.which() == m_DefaultValue.which())
{
m_Values.insert((m_pValueComparator) ? std::lower_bound(m_Values.begin(), m_Values.end(), std::make_pair(modValue, idObject), boost::bind(&RlvBehaviourModifier_Comp::operator(), m_pValueComparator, _1, _2)) : m_Values.end(), std::make_pair(modValue, idObject));
m_Values.insert((m_pValueComparator) ? std::lower_bound(m_Values.begin(), m_Values.end(), std::make_tuple(modValue, idRlvObj, eBhvr), boost::bind(&RlvBehaviourModifier_Comp::operator(), m_pValueComparator, _1, _2)) : m_Values.end(), std::make_tuple(modValue, idRlvObj, eBhvr));
// NOTE: change signal needs to trigger before modifier handlers so cached values have a chance to update properly
m_ChangeSignal(getValue());
onValueChange();
@ -463,6 +473,20 @@ bool RlvBehaviourModifier::addValue(const RlvBehaviourModifierValue& modValue, c
return false;
}
void RlvBehaviourModifier::clearValues(const LLUUID& idRlvObj)
{
size_t origCount = m_Values.size();
m_Values.erase(std::remove_if(m_Values.begin(), m_Values.end(),
[&idRlvObj](const RlvBehaviourModifierValueTuple& modValue) {
return (std::get<1>(modValue) == idRlvObj) && (std::get<2>(modValue) == RLV_BHVR_UNKNOWN);
}), m_Values.end());
if (origCount != m_Values.size())
{
onValueChange();
m_ChangeSignal(getValue());
}
}
const LLUUID& RlvBehaviourModifier::getPrimaryObject() const
{
return (m_pValueComparator) ? m_pValueComparator->m_idPrimaryObject : LLUUID::null;
@ -472,14 +496,14 @@ bool RlvBehaviourModifier::hasValue() const {
// If no primary object is set this returns "any value set"; otherwise it returns "any value set by the primary object"
if ( (!m_pValueComparator) || (m_pValueComparator->m_idPrimaryObject.isNull()) )
return !m_Values.empty();
return (!m_Values.empty()) ? m_Values.front().second == m_pValueComparator->m_idPrimaryObject : false;
return (!m_Values.empty()) ? std::get<1>(m_Values.front()) == m_pValueComparator->m_idPrimaryObject : false;
}
void RlvBehaviourModifier::removeValue(const RlvBehaviourModifierValue& modValue, const LLUUID& idObject)
void RlvBehaviourModifier::removeValue(const RlvBehaviourModifierValue& modValue, const LLUUID& idRlvObj, ERlvBehaviour eBhvr)
{
if ( (modValue.which() == m_DefaultValue.which()) )
{
auto itValue = std::find(m_Values.begin(), m_Values.end(), std::make_pair(modValue, idObject));
auto itValue = std::find(m_Values.begin(), m_Values.end(), std::make_tuple(modValue, idRlvObj, eBhvr));
if (m_Values.end() != itValue)
{
m_Values.erase(itValue);
@ -500,6 +524,31 @@ void RlvBehaviourModifier::setPrimaryObject(const LLUUID& idPrimaryObject)
}
}
void RlvBehaviourModifier::setValue(const RlvBehaviourModifierValue& modValue, const LLUUID& idRlvObj)
{
if ( (modValue.which() == m_DefaultValue.which()) )
{
auto itValue = std::find_if(m_Values.begin(), m_Values.end(),
[&idRlvObj](const RlvBehaviourModifierValueTuple& cmpValue) {
return (std::get<1>(cmpValue) == idRlvObj) && (std::get<2>(cmpValue) == RLV_BHVR_UNKNOWN);
});
if (m_Values.end() != itValue)
{
// The object already has a modifier value set => change it
std::get<0>(*itValue) = modValue;
if (m_pValueComparator)
m_Values.sort(boost::bind(&RlvBehaviourModifier_Comp::operator(), m_pValueComparator, _1, _2));
onValueChange();
m_ChangeSignal(getValue());
}
else
{
// The command doesn't have a modifier value yet => add it
addValue(modValue, idRlvObj, RLV_BHVR_UNKNOWN);
}
}
}
bool RlvBehaviourModifier::convertOptionValue(const std::string& optionValue, RlvBehaviourModifierValue& modValue) const
{
try

View File

@ -103,6 +103,7 @@ public:
* General helper functions
*/
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;
bool getCommands(const std::string& strMatch, ERlvParamType eParamType, std::list<std::string>& cmdList) const;
@ -207,6 +208,8 @@ template<ERlvBehaviour templBhvr, typename handlerImpl = RlvCommandHandler<RLV_T
// Provides pre-defined generic implementations of basic behaviours (template voodoo - see original commit for something that still made sense)
template<ERlvBehaviourOptionType templOptionType> struct RlvBehaviourGenericHandler { static ERlvCmdRet onCommand(const RlvCommand& rlvCmd, bool& fRefCount); };
template<ERlvBehaviourOptionType templOptionType> using RlvBehaviourGenericProcessor = RlvBehaviourProcessor<RLV_BHVR_UNKNOWN, RlvBehaviourGenericHandler<templOptionType>>;
template<ERlvBehaviourOptionType templOptionType> struct RlvForceGenericHandler { static ERlvCmdRet onCommand(const RlvCommand& rlvCmd); };
template<ERlvBehaviourOptionType templOptionType> using RlvForceGenericProcessor = RlvForceProcessor<RLV_BHVR_UNKNOWN, RlvForceGenericHandler<templOptionType>>;
// ============================================================================
// RlvBehaviourProcessor and related classes - Handles add/rem comamnds aka "restrictions)
@ -225,7 +228,7 @@ template <ERlvBehaviour eBhvr, ERlvBehaviourOptionType optionType, typename togg
// RlvBehaviourModifier - stores behaviour modifiers in an - optionally - sorted list and returns the first element (or default value if there are no modifiers)
//
typedef std::pair<RlvBehaviourModifierValue, LLUUID> RlvBehaviourModifierValueTuple;
typedef std::tuple<RlvBehaviourModifierValue, LLUUID, ERlvBehaviour> RlvBehaviourModifierValueTuple;
struct RlvBehaviourModifier_Comp
{
@ -233,7 +236,7 @@ struct RlvBehaviourModifier_Comp
virtual bool operator()(const RlvBehaviourModifierValueTuple& lhs, const RlvBehaviourModifierValueTuple& rhs)
{
// Values that match the primary object take precedence (otherwise maintain relative ordering)
if ( (rhs.second == m_idPrimaryObject) && (lhs.second != m_idPrimaryObject) )
if ( (std::get<1>(rhs) == m_idPrimaryObject) && (std::get<1>(lhs) != m_idPrimaryObject) )
return false;
return true;
}
@ -244,8 +247,8 @@ struct RlvBehaviourModifier_CompMin : public RlvBehaviourModifier_Comp
{
bool operator()(const RlvBehaviourModifierValueTuple& lhs, const RlvBehaviourModifierValueTuple& rhs) override
{
if ( (m_idPrimaryObject.isNull()) || ((lhs.second == m_idPrimaryObject) && (rhs.second == m_idPrimaryObject)) )
return lhs.first < rhs.first;
if ( (m_idPrimaryObject.isNull()) || ((std::get<1>(lhs) == m_idPrimaryObject) && (std::get<1>(rhs) == m_idPrimaryObject)) )
return std::get<0>(lhs) < std::get<0>(rhs);
return RlvBehaviourModifier_Comp::operator()(lhs, rhs);
}
};
@ -253,8 +256,8 @@ struct RlvBehaviourModifier_CompMax : public RlvBehaviourModifier_Comp
{
bool operator()(const RlvBehaviourModifierValueTuple& lhs, const RlvBehaviourModifierValueTuple& rhs) override
{
if ( (m_idPrimaryObject.isNull()) || ((lhs.second == m_idPrimaryObject) && (rhs.second == m_idPrimaryObject)) )
return rhs.first < lhs.first;
if ( (m_idPrimaryObject.isNull()) || ((std::get<1>(lhs) == m_idPrimaryObject) && (std::get<1>(rhs) == m_idPrimaryObject)) )
return std::get<0>(rhs) < std::get<0>(lhs);
return RlvBehaviourModifier_Comp::operator()(lhs, rhs);
}
};
@ -271,16 +274,18 @@ public:
protected:
virtual void onValueChange() const {}
public:
bool addValue(const RlvBehaviourModifierValue& modValue, const LLUUID& idObject);
bool addValue(const RlvBehaviourModifierValue& modValue, const LLUUID& idRlvObj, ERlvBehaviour eBhvr = RLV_BHVR_UNKNOWN);
bool convertOptionValue(const std::string& optionValue, RlvBehaviourModifierValue& modValue) const;
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 RlvBehaviourModifierValue& getValue() const { return (hasValue()) ? m_Values.front().first : m_DefaultValue; }
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;
void removeValue(const RlvBehaviourModifierValue& modValue, const LLUUID& idObject);
void removeValue(const RlvBehaviourModifierValue& modValue, const LLUUID& idRlvObj, ERlvBehaviour eBhvr = RLV_BHVR_UNKNOWN);
void setValue(const RlvBehaviourModifierValue& modValue, const LLUUID& idRlvObj);
void setPrimaryObject(const LLUUID& idPrimaryObject);
typedef boost::signals2::signal<void(const RlvBehaviourModifierValue& newValue)> change_signal_t;