Added behaviour modifiers as a prelude to camera restrictions and other fun goodies

--HG--
branch : RLVa
master
Kitty Barnett 2016-05-15 00:35:54 +02:00
parent 8b6b3be823
commit 68025f9e1d
5 changed files with 244 additions and 7 deletions

View File

@ -56,6 +56,7 @@ class RlvObject;
struct RlvException;
typedef boost::variant<std::string, LLUUID, S32, ERlvBehaviour> RlvExceptionOption;
typedef boost::variant<int, float> RlvBehaviourModifierValue;
class RlvGCTimer;

View File

@ -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 {

View File

@ -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<RLV_OPTION_NONE_OR_EXCEPTION>::onCommand(c
return RlvBehaviourGenericHandler<RLV_OPTION_NONE>::onCommand(rlvCmd, fRefCount);
}
// Handles: @bhvr:<modifier>=n|y
ERlvCmdRet RlvBehaviourGenericHandler<RLV_OPTION_MODIFIER>::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[:<modifier>]=n|y
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())
return RlvBehaviourGenericHandler<RLV_OPTION_MODIFIER>::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[:<attachpt>]=n|y and @remattach[:<attachpt>]=n|y
template<> template<>
ERlvCmdRet RlvBehaviourAddRemAttachHandler::onCommand(const RlvCommand& rlvCmd, bool& fRefCount)

View File

@ -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
//

View File

@ -141,14 +141,14 @@ template<ERlvBehaviour eBhvr, typename handlerImpl = RlvCommandHandler<RLV_TYPE_
template<ERlvBehaviour eBhvr, typename handlerImpl = RlvCommandHandler<RLV_TYPE_REPLY, eBhvr>> using RlvReplyProcessor = RlvCommandProcessor<RLV_TYPE_REPLY, eBhvr, handlerImpl>;
// Provides pre-defined generic implementations of basic behaviours (template voodoo - see original commit for something that still made sense)
template<RlvBehaviourOptionType optionType> struct RlvBehaviourGenericHandler { static ERlvCmdRet onCommand(const RlvCommand& rlvCmd, bool& fRefCount); };
template<RlvBehaviourOptionType optionType> using RlvBehaviourGenericProcessor = RlvBehaviourProcessor<RLV_BHVR_UNKNOWN, RlvBehaviourGenericHandler<optionType>>;
template<ERlvBehaviourOptionType optionType> struct RlvBehaviourGenericHandler { static ERlvCmdRet onCommand(const RlvCommand& rlvCmd, bool& fRefCount); };
template<ERlvBehaviourOptionType optionType> using RlvBehaviourGenericProcessor = RlvBehaviourProcessor<RLV_BHVR_UNKNOWN, RlvBehaviourGenericHandler<optionType>>;
// ============================================================================
// RlvBehaviourProcessor and related classes - Handles add/rem comamnds aka "restrictions)
//
template <ERlvBehaviour eBhvr, RlvBehaviourOptionType optionType, typename toggleHandlerImpl = RlvBehaviourToggleHandler<eBhvr>>
template <ERlvBehaviour eBhvr, ERlvBehaviourOptionType optionType, typename toggleHandlerImpl = RlvBehaviourToggleHandler<eBhvr>>
class RlvBehaviourToggleProcessor : public RlvBehaviourInfo
{
public:
@ -156,6 +156,107 @@ public:
ERlvCmdRet processCommand(const RlvCommand& rlvCmd) const override { return RlvCommandHandlerBaseImpl<RLV_TYPE_ADDREM>::processCommand(rlvCmd, &RlvBehaviourGenericHandler<optionType>::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<typename T> const T& getValue() const { return boost::get<T>(getValue()); }
void removeValue(const RlvBehaviourModifierValue& modValue);
typedef boost::signals2::signal<void(const RlvBehaviourModifierValue& newValue)> change_signal_t;
change_signal_t& getSignal() { return m_ChangeSignal; }
/*
* Member variables
*/
protected:
RlvBehaviourModifierValue m_DefaultValue;
bool m_fAddDefaultOnEmpty;
std::list<RlvBehaviourModifierValue> m_Values;
change_signal_t m_ChangeSignal;
RlvBehaviourModifier_Comp* m_pValueComparator;
};
// Inspired by LLControlCache<T>
template<typename T>
class RlvBehaviourModifierCache : public LLRefCount, public LLInstanceTracker<RlvBehaviourModifierCache<T>, ERlvBehaviourModifier>
{
public:
RlvBehaviourModifierCache(ERlvBehaviourModifier eModifier)
: LLInstanceTracker<RlvBehaviourModifierCache<T>, ERlvBehaviourModifier>(eModifier)
{
RlvBehaviourModifier* pBhvrModifier = (eModifier < RLV_MODIFIER_COUNT) ? RlvBehaviourDictionary::instance().getModifier(eModifier) : nullptr;
if (pBhvrModifier)
{
mConnection = pBhvrModifier->getSignal().connect(boost::bind(&RlvBehaviourModifierCache<T>::handleValueChange, this, _1));
mCachedValue = pBhvrModifier->getValue<T>();
}
else
{
mCachedValue = {};
}
}
~RlvBehaviourModifierCache() {}
/*
* Member functions
*/
public:
const T& getValue() const { return mCachedValue; }
protected:
void handleValueChange(const RlvBehaviourModifierValue& newValue) { mCachedValue = boost::get<T>(newValue); }
/*
* Member variables
*/
protected:
T mCachedValue;
boost::signals2::scoped_connection mConnection;
};
// Inspired by LLCachedControl<T>
template <typename T>
class RlvCachedBehaviourModifier
{
public:
RlvCachedBehaviourModifier(ERlvBehaviourModifier eModifier)
{
if ((mCachedModifierPtr = RlvBehaviourModifierCache<T>::getInstance(eModifier)) == nullptr)
mCachedModifierPtr = new RlvBehaviourModifierCache<T>(eModifier);
}
/*
* Operators
*/
public:
operator const T&() const { return mCachedModifierPtr->getValue(); }
const T& operator()() { return mCachedModifierPtr->getValue(); }
/*
* Member variables
*/
protected:
LLPointer<RlvBehaviourModifierCache<T>> 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<std::string>& 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<const RlvBehaviourInfo*> rlv_bhvrinfo_list_t;
typedef std::map<std::pair<std::string, ERlvParamType>, const RlvBehaviourInfo*> rlv_string2info_map_t;
typedef std::multimap<ERlvBehaviour, const RlvBehaviourInfo*> rlv_bhvr2info_map_t;
typedef std::map<ERlvBehaviour, ERlvBehaviourModifier> 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];
};
// ============================================================================