Pave the way for a brighter future where behaviour modifiers aren't behaviours themselves
--HG-- branch : RLVameow-7.2.2
parent
4de0c86332
commit
9a92faa176
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -750,6 +750,7 @@ BOOL RlvFloaterConsole::postBuild()
|
|||
|
||||
void RlvFloaterConsole::onClose(bool fQuitting)
|
||||
{
|
||||
RlvBehaviourDictionary::instance().clearModifiers(gAgent.getID());
|
||||
gRlvHandler.processCommand(gAgent.getID(), "clear", true);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue