/** * * Copyright (c) 2009-2020, Kitty Barnett * * The source code in this file is provided to you under the terms of the * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt * * By copying, modifying or distributing this software, you acknowledge that * you have read and understood your obligations described above, and agree to * abide by those obligations. * */ #include "llviewerprecompiledheaders.h" #include "llappearancemgr.h" #include "llattachmentsmgr.h" #include "llfeaturemanager.h" #include "llgesturemgr.h" #include "llnotificationsutil.h" #include "llviewerobjectlist.h" #include "pipeline.h" // FIRE-4453 bridge detached by the RLV command @remattach=force #include "fslslbridge.h" // FIRE-4453 #include "rlvcommon.h" #include "rlveffects.h" #include "rlvhelper.h" #include "rlvhandler.h" #include "rlvinventory.h" #include "rlvmodifiers.h" #include // ============================================================================ // RlvBehaviourDictionary // /* * Processing of RLVa commands used to be a big switch/case loop with one function for each command type(addrem, reply * and force). This is slowly being replaced with templated command handling which might be more confusing intially * (also due to my poor naming schemes) but is actually far simpler and less error-prone than the old way. * * In the general case you just add a definition for the command below and then write the function body in rlvhandler.cpp * and you're done! Told you this was easy. * * Reply command * ============= * Definition: RlvReplyProcessor("commandname"[, ])); * Implement : ERlvCmdRet RlvReplyHandler::onCommand(const RlvCommand& rlvCmd, std::string& strReply) * * Force command * ============= * Definition: new RlvForceProcessor("commandname"[, ])); * Implement : ERlvCmdRet RlvForceProcessor::onCommand(const RlvCommand& rlvCmd) * * Behaviours * ========== * Behaviours come in many forms but the added complexity is only in the variety of choices. The implementation is as * easy as reply or force commands. * * For simple behaviours that only require recordkeeping and don't run code when set/unset (see ERlvBehaviourOptionType): * Definition: RlvBehaviourGenericProcessor("commandname", RLV_BHVR_COMMANDNAME) * Implement : nothing! (it automagically works) * For simple behaviours that only require recordkeeping and only run code when they toggle: * Definition: RlvBehaviourGenericToggleProcessor("commandname")) * Implement : void RlvBehaviourToggleHandler::onCommandToggle(ERlvBehaviour eBhvr, bool fHasBhvr) * For behaviours that require manual processing: * Definition: RlvBehaviourProcessor("commandname")) * Implement : ERlvCmdRet RlvBehaviourHandler::onCommand(const RlvCommand& rlvCmd, bool& fRefCount) * For behaviours that run code when their modifier changes: * Definition: addModifier(RLV_BHVR_COMMANDNAME, RLV_MODIFIER_COMMANDNAME, new RlvBehaviourModifierHandler(, , )); * Implement : void RlvBehaviourModifierHandler::onValueChanged() * */ RlvBehaviourDictionary::RlvBehaviourDictionary() { // Array auto-initialization to 0 is still not supported in VS2013 memset(m_BehaviourModifiers, 0, sizeof(RlvBehaviourModifier*) * RLV_MODIFIER_COUNT); // // Restrictions // addEntry(new RlvBehaviourGenericProcessor("acceptpermission", RLV_BHVR_ACCEPTPERMISSION)); addEntry(new RlvBehaviourGenericProcessor("accepttp", RLV_BHVR_ACCEPTTP, RlvBehaviourInfo::BHVR_STRICT)); addEntry(new RlvBehaviourGenericProcessor("accepttprequest", RLV_BHVR_ACCEPTTPREQUEST, RlvBehaviourInfo::BHVR_STRICT | RlvBehaviourInfo::BHVR_EXTENDED)); addEntry(new RlvBehaviourProcessor("addattach")); addEntry(new RlvBehaviourInfo("addoutfit", RLV_BHVR_ADDOUTFIT, RLV_TYPE_ADDREM)); addEntry(new RlvBehaviourGenericProcessor("allowidle", RLV_BHVR_ALLOWIDLE, RlvBehaviourInfo::BHVR_EXPERIMENTAL)); addEntry(new RlvBehaviourGenericProcessor("alwaysrun", RLV_BHVR_ALWAYSRUN)); addEntry(new RlvBehaviourInfo("attachthis", RLV_BHVR_ATTACHTHIS, RLV_TYPE_ADDREM, RlvBehaviourInfo::FORCEWEAR_NODE)); addEntry(new RlvBehaviourInfo("attachallthis", RLV_BHVR_ATTACHTHIS, RLV_TYPE_ADDREM, RlvBehaviourInfo::FORCEWEAR_SUBTREE)); addEntry(new RlvBehaviourInfo("attachthis_except", RLV_BHVR_ATTACHTHISEXCEPT, RLV_TYPE_ADDREM, RlvBehaviourInfo::FORCEWEAR_NODE)); addEntry(new RlvBehaviourInfo("attachallthis_except", RLV_BHVR_ATTACHTHISEXCEPT, RLV_TYPE_ADDREM, RlvBehaviourInfo::FORCEWEAR_SUBTREE)); addEntry(new RlvBehaviourGenericToggleProcessor("buy")); addEntry(new RlvBehaviourGenericProcessor("chatwhisper", RLV_BHVR_CHATWHISPER)); addEntry(new RlvBehaviourGenericProcessor("chatnormal", RLV_BHVR_CHATNORMAL)); addEntry(new RlvBehaviourGenericProcessor("chatshout", RLV_BHVR_CHATSHOUT)); addEntry(new RlvBehaviourProcessor("detach")); addEntry(new RlvBehaviourInfo("detachthis", RLV_BHVR_DETACHTHIS, RLV_TYPE_ADDREM, RlvBehaviourInfo::FORCEWEAR_NODE)); addEntry(new RlvBehaviourInfo("detachallthis", RLV_BHVR_DETACHTHIS, RLV_TYPE_ADDREM, RlvBehaviourInfo::FORCEWEAR_SUBTREE)); addEntry(new RlvBehaviourInfo("detachthis_except", RLV_BHVR_DETACHTHISEXCEPT, RLV_TYPE_ADDREM, RlvBehaviourInfo::FORCEWEAR_NODE)); addEntry(new RlvBehaviourInfo("detachallthis_except", RLV_BHVR_DETACHTHISEXCEPT, RLV_TYPE_ADDREM, RlvBehaviourInfo::FORCEWEAR_SUBTREE)); addEntry(new RlvBehaviourGenericToggleProcessor("edit")); addEntry(new RlvBehaviourGenericProcessor("editattach", RLV_BHVR_EDITATTACH)); addEntry(new RlvBehaviourGenericProcessor("editobj", RLV_BHVR_EDITOBJ)); addEntry(new RlvBehaviourGenericProcessor("editworld", RLV_BHVR_EDITWORLD)); addEntry(new RlvBehaviourGenericToggleProcessor("viewtransparent", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); addEntry(new RlvBehaviourGenericToggleProcessor("viewwireframe", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); addEntry(new RlvBehaviourGenericProcessor("emote", RLV_BHVR_EMOTE)); addEntry(new RlvBehaviourGenericProcessor("fartouch", RLV_BHVR_FARTOUCH)); addModifier(RLV_BHVR_FARTOUCH, RLV_MODIFIER_FARTOUCHDIST, new RlvBehaviourModifier("Fartouch Distance", RLV_MODIFIER_FARTOUCH_DEFAULT, true, new RlvBehaviourModifierCompMin)); addEntry(new RlvBehaviourGenericProcessor("fly", RLV_BHVR_FLY)); addEntry(new RlvBehaviourGenericProcessor("interact", RLV_BHVR_INTERACT, RlvBehaviourInfo::BHVR_EXTENDED)); addEntry(new RlvBehaviourGenericProcessor("jump", RLV_BHVR_JUMP)); addEntry(new RlvBehaviourInfo("notify", RLV_BHVR_NOTIFY, RLV_TYPE_ADDREM)); addEntry(new RlvBehaviourGenericToggleProcessor("pay")); addEntry(new RlvBehaviourGenericProcessor("permissive", RLV_BHVR_PERMISSIVE)); addEntry(new RlvBehaviourGenericProcessor("recvchat", RLV_BHVR_RECVCHAT, RlvBehaviourInfo::BHVR_STRICT)); addEntry(new RlvBehaviourGenericProcessor("recvchatfrom", RLV_BHVR_RECVCHATFROM, RlvBehaviourInfo::BHVR_STRICT)); addEntry(new RlvBehaviourGenericProcessor("recvemote", RLV_BHVR_RECVEMOTE, RlvBehaviourInfo::BHVR_STRICT)); addEntry(new RlvBehaviourGenericProcessor("recvemotefrom", RLV_BHVR_RECVEMOTEFROM, RlvBehaviourInfo::BHVR_STRICT)); addEntry(new RlvBehaviourProcessor("recvim", RlvBehaviourInfo::BHVR_STRICT)); addModifier(RLV_BHVR_RECVIM, RLV_MODIFIER_RECVIMDISTMIN, new RlvBehaviourModifier("RecvIM Distance (Min)", F32_MAX, true, new RlvBehaviourModifierCompMax)); addModifier(RLV_BHVR_RECVIM, RLV_MODIFIER_RECVIMDISTMAX, new RlvBehaviourModifier("RecvIM Distance (Max)", F32_MAX, true, new RlvBehaviourModifierCompMin)); addEntry(new RlvBehaviourGenericProcessor("recvimfrom", RLV_BHVR_RECVIMFROM, RlvBehaviourInfo::BHVR_STRICT)); addEntry(new RlvBehaviourInfo("redirchat", RLV_BHVR_REDIRCHAT, RLV_TYPE_ADDREM)); addEntry(new RlvBehaviourInfo("rediremote", RLV_BHVR_REDIREMOTE, RLV_TYPE_ADDREM)); addEntry(new RlvBehaviourProcessor("remattach")); addEntry(new RlvBehaviourInfo("remoutfit", RLV_BHVR_REMOUTFIT, RLV_TYPE_ADDREM)); addEntry(new RlvBehaviourGenericProcessor("rez", RLV_BHVR_REZ)); addEntry(new RlvBehaviourProcessor("sendchannel", RlvBehaviourInfo::BHVR_STRICT)); addEntry(new RlvBehaviourProcessor("sendchannel_except", RlvBehaviourInfo::BHVR_STRICT | RlvBehaviourInfo::BHVR_EXPERIMENTAL)); addEntry(new RlvBehaviourGenericProcessor("sendchat", RLV_BHVR_SENDCHAT)); addEntry(new RlvBehaviourToggleProcessor("sendim", RlvBehaviourInfo::BHVR_STRICT)); addModifier(RLV_BHVR_SENDIM, RLV_MODIFIER_SENDIMDISTMIN, new RlvBehaviourModifier("SendIM Distance (Min)", F32_MAX, true, new RlvBehaviourModifierCompMax)); addModifier(RLV_BHVR_SENDIM, RLV_MODIFIER_SENDIMDISTMAX, new RlvBehaviourModifier("SendIM Distance (Max)", F32_MAX, true, new RlvBehaviourModifierCompMin)); addEntry(new RlvBehaviourGenericProcessor("sendimto", RLV_BHVR_SENDIMTO, RlvBehaviourInfo::BHVR_STRICT)); addEntry(new RlvBehaviourGenericProcessor("sendgesture", RLV_BHVR_SENDGESTURE, RlvBehaviourInfo::BHVR_EXPERIMENTAL)); addEntry(new RlvBehaviourGenericToggleProcessor("setdebug")); addEntry(new RlvBehaviourGenericToggleProcessor("setenv")); addEntry(new RlvBehaviourGenericProcessor("setgroup", RLV_BHVR_SETGROUP)); addEntry(new RlvBehaviourGenericProcessor("share", RLV_BHVR_SHARE, RlvBehaviourInfo::BHVR_STRICT)); addEntry(new RlvBehaviourInfo("sharedunwear", RLV_BHVR_SHAREDUNWEAR, RLV_TYPE_ADDREM, RlvBehaviourInfo::BHVR_EXTENDED)); addEntry(new RlvBehaviourInfo("sharedwear", RLV_BHVR_SHAREDWEAR, RLV_TYPE_ADDREM, RlvBehaviourInfo::BHVR_EXTENDED)); addEntry(new RlvBehaviourProcessor("showhovertext")); addEntry(new RlvBehaviourGenericProcessor("showhovertextall", RLV_BHVR_SHOWHOVERTEXTALL)); addEntry(new RlvBehaviourGenericProcessor("showhovertexthud", RLV_BHVR_SHOWHOVERTEXTHUD)); addEntry(new RlvBehaviourGenericProcessor("showhovertextworld", RLV_BHVR_SHOWHOVERTEXTWORLD)); addEntry(new RlvBehaviourGenericToggleProcessor("showinv")); addEntry(new RlvBehaviourGenericProcessor("showloc", RLV_BHVR_SHOWLOC)); addEntry(new RlvBehaviourGenericProcessor("showminimap", RLV_BHVR_SHOWMINIMAP)); addEntry(new RlvBehaviourToggleProcessor("shownames", RlvBehaviourInfo::BHVR_STRICT)); addEntry(new RlvBehaviourProcessor("shownametags", RlvBehaviourInfo::BHVR_STRICT)); addModifier(RLV_BHVR_SHOWNAMETAGS, RLV_MODIFIER_SHOWNAMETAGSDIST, new RlvBehaviourModifierHandler("Name Tags - Visible Distance", 0.0f, true, new RlvBehaviourModifierCompMin)); addEntry(new RlvBehaviourGenericToggleProcessor("shownearby", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); addEntry(new RlvBehaviourGenericToggleProcessor("showself", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); addEntry(new RlvBehaviourGenericToggleProcessor("showselfhead", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); addEntry(new RlvBehaviourGenericProcessor("showworldmap", RLV_BHVR_SHOWWORLDMAP)); addEntry(new RlvBehaviourGenericProcessor("sit", RLV_BHVR_SIT)); addEntry(new RlvBehaviourGenericProcessor("sittp", RLV_BHVR_SITTP)); addModifier(RLV_BHVR_SITTP, RLV_MODIFIER_SITTPDIST, new RlvBehaviourModifier("SitTp Distance", RLV_MODIFIER_SITTP_DEFAULT, true, new RlvBehaviourModifierCompMin)); addEntry(new RlvBehaviourGenericProcessor("standtp", RLV_BHVR_STANDTP)); addEntry(new RlvBehaviourProcessor("startim", RlvBehaviourInfo::BHVR_STRICT)); addModifier(RLV_BHVR_STARTIM, RLV_MODIFIER_STARTIMDISTMIN, new RlvBehaviourModifier("StartIM Distance (Min)", F32_MAX, true, new RlvBehaviourModifierCompMax)); addModifier(RLV_BHVR_STARTIM, RLV_MODIFIER_STARTIMDISTMAX, new RlvBehaviourModifier("StartIM Distance (Max)", F32_MAX, true, new RlvBehaviourModifierCompMin)); addEntry(new RlvBehaviourGenericProcessor("startimto", RLV_BHVR_STARTIMTO, RlvBehaviourInfo::BHVR_STRICT)); addEntry(new RlvBehaviourGenericProcessor("temprun", RLV_BHVR_TEMPRUN)); addEntry(new RlvBehaviourGenericProcessor("touchall", RLV_BHVR_TOUCHALL)); addEntry(new RlvBehaviourGenericProcessor("touchattach", RLV_BHVR_TOUCHATTACH)); addEntry(new RlvBehaviourGenericProcessor("touchattachother", RLV_BHVR_TOUCHATTACHOTHER)); addEntry(new RlvBehaviourGenericProcessor("touchattachself", RLV_BHVR_TOUCHATTACHSELF)); addEntry(new RlvBehaviourGenericProcessor("touchfar", RLV_BHVR_FARTOUCH, RlvBehaviourInfo::BHVR_SYNONYM)); addEntry(new RlvBehaviourGenericProcessor("touchhud", RLV_BHVR_TOUCHHUD, RlvBehaviourInfo::BHVR_EXTENDED)); addEntry(new RlvBehaviourGenericProcessor("touchme", RLV_BHVR_TOUCHME)); addEntry(new RlvBehaviourGenericProcessor("touchthis", RLV_BHVR_TOUCHTHIS)); addEntry(new RlvBehaviourGenericProcessor("touchworld", RLV_BHVR_TOUCHWORLD)); addEntry(new RlvBehaviourGenericProcessor("tplm", RLV_BHVR_TPLM)); addEntry(new RlvBehaviourGenericProcessor("tploc", RLV_BHVR_TPLOC)); addEntry(new RlvBehaviourGenericProcessor("tplocal", RLV_BHVR_TPLOCAL, RlvBehaviourInfo::BHVR_EXPERIMENTAL)); addModifier(RLV_BHVR_TPLOCAL, RLV_MODIFIER_TPLOCALDIST, new RlvBehaviourModifier("Local Teleport Distance", RLV_MODIFIER_TPLOCAL_DEFAULT, true, new RlvBehaviourModifierCompMin)); addEntry(new RlvBehaviourGenericProcessor("tplure", RLV_BHVR_TPLURE, RlvBehaviourInfo::BHVR_STRICT)); addEntry(new RlvBehaviourGenericProcessor("tprequest", RLV_BHVR_TPREQUEST, RlvBehaviourInfo::BHVR_STRICT | RlvBehaviourInfo::BHVR_EXTENDED)); addEntry(new RlvBehaviourInfo("unsharedunwear", RLV_BHVR_UNSHAREDUNWEAR, RLV_TYPE_ADDREM)); addEntry(new RlvBehaviourInfo("unsharedwear", RLV_BHVR_UNSHAREDWEAR, RLV_TYPE_ADDREM)); addEntry(new RlvBehaviourGenericProcessor("unsit", RLV_BHVR_UNSIT)); addEntry(new RlvBehaviourGenericProcessor("viewnote", RLV_BHVR_VIEWNOTE)); addEntry(new RlvBehaviourGenericProcessor("viewscript", RLV_BHVR_VIEWSCRIPT)); addEntry(new RlvBehaviourGenericProcessor("viewtexture", RLV_BHVR_VIEWTEXTURE)); // Camera addEntry(new RlvBehaviourGenericToggleProcessor("setcam")); addEntry(new RlvBehaviourGenericProcessor("setcam_avdist", RLV_BHVR_SETCAM_AVDIST)); addModifier(RLV_BHVR_SETCAM_AVDIST, RLV_MODIFIER_SETCAM_AVDIST, new RlvBehaviourModifier("Camera - Silhouette Distance", 0.0f, false, new RlvBehaviourModifierCompMax())); addEntry(new RlvBehaviourGenericProcessor("setcam_avdistmin", RLV_BHVR_SETCAM_AVDISTMIN, RlvBehaviourInfo::BHVR_EXPERIMENTAL)); addModifier(RLV_BHVR_SETCAM_AVDISTMIN, RLV_MODIFIER_SETCAM_AVDISTMIN, new RlvBehaviourModifierHandler("Camera - Avatar Distance (Min)", 0.0f, false, new RlvBehaviourModifierCompMax())); addEntry(new RlvBehaviourGenericProcessor("setcam_avdistmax", RLV_BHVR_SETCAM_AVDISTMAX, RlvBehaviourInfo::BHVR_EXPERIMENTAL)); addModifier(RLV_BHVR_SETCAM_AVDISTMAX, RLV_MODIFIER_SETCAM_AVDISTMAX, new RlvBehaviourModifier("Camera - Avatar Distance (Max)", F32_MAX, false, new RlvBehaviourModifierCompMin)); addEntry(new RlvBehaviourGenericProcessor("setcam_origindistmin", RLV_BHVR_SETCAM_ORIGINDISTMIN, RlvBehaviourInfo::BHVR_EXPERIMENTAL)); addModifier(RLV_BHVR_SETCAM_ORIGINDISTMIN, RLV_MODIFIER_SETCAM_ORIGINDISTMIN, new RlvBehaviourModifier("Camera - Focus Distance (Min)", 0.0f, true, new RlvBehaviourModifierCompMax)); addEntry(new RlvBehaviourGenericProcessor("setcam_origindistmax", RLV_BHVR_SETCAM_ORIGINDISTMAX, RlvBehaviourInfo::BHVR_EXPERIMENTAL)); addModifier(RLV_BHVR_SETCAM_ORIGINDISTMAX, RLV_MODIFIER_SETCAM_ORIGINDISTMAX, new RlvBehaviourModifier("Camera - Focus Distance (Max)", F32_MAX, true, new RlvBehaviourModifierCompMin)); addEntry(new RlvBehaviourGenericToggleProcessor("setcam_eyeoffset")); addModifier(RLV_BHVR_SETCAM_EYEOFFSET, RLV_MODIFIER_SETCAM_EYEOFFSET, new RlvBehaviourModifierHandler("Camera - Eye Offset", LLVector3::zero, true, nullptr)); addEntry(new RlvBehaviourGenericToggleProcessor("setcam_eyeoffsetscale")); addModifier(RLV_BHVR_SETCAM_EYEOFFSETSCALE, RLV_MODIFIER_SETCAM_EYEOFFSETSCALE, new RlvBehaviourModifierHandler("Camera - Eye Offset Scale", 0.0f, true, nullptr)); addEntry(new RlvBehaviourGenericToggleProcessor("setcam_focusoffset")); addModifier(RLV_BHVR_SETCAM_FOCUSOFFSET, RLV_MODIFIER_SETCAM_FOCUSOFFSET, new RlvBehaviourModifierHandler("Camera - Focus Offset", LLVector3d::zero, true, nullptr)); addEntry(new RlvBehaviourProcessor("setcam_fovmin")); addModifier(RLV_BHVR_SETCAM_FOVMIN, RLV_MODIFIER_SETCAM_FOVMIN, new RlvBehaviourModifierHandler("Camera - FOV (Min)", DEFAULT_FIELD_OF_VIEW, true, new RlvBehaviourModifierCompMax)); addEntry(new RlvBehaviourProcessor("setcam_fovmax")); addModifier(RLV_BHVR_SETCAM_FOVMAX, RLV_MODIFIER_SETCAM_FOVMAX, new RlvBehaviourModifierHandler("Camera - FOV (Max)", DEFAULT_FIELD_OF_VIEW, true, new RlvBehaviourModifierCompMin)); addEntry(new RlvBehaviourGenericToggleProcessor("setcam_mouselook")); addEntry(new RlvBehaviourGenericProcessor("setcam_textures", RLV_BHVR_SETCAM_TEXTURES)); addModifier(RLV_BHVR_SETCAM_TEXTURES, RLV_MODIFIER_SETCAM_TEXTURE, new RlvBehaviourModifierHandler("Camera - Forced Texture", IMG_DEFAULT, true, nullptr)); addEntry(new RlvBehaviourGenericToggleProcessor("setcam_unlock")); // Camera (compatibility shim - to be deprecated) addEntry(new RlvBehaviourGenericProcessor("camavdist", RLV_BHVR_SETCAM_AVDIST, RlvBehaviourInfo::BHVR_SYNONYM | RlvBehaviourInfo::BHVR_DEPRECATED)); addEntry(new RlvBehaviourGenericProcessor("camdistmin", RLV_BHVR_SETCAM_AVDISTMIN, RlvBehaviourInfo::BHVR_SYNONYM | RlvBehaviourInfo::BHVR_DEPRECATED)); addEntry(new RlvBehaviourGenericProcessor("camdistmax", RLV_BHVR_SETCAM_AVDISTMAX, RlvBehaviourInfo::BHVR_SYNONYM | RlvBehaviourInfo::BHVR_DEPRECATED)); addEntry(new RlvBehaviourGenericProcessor("camtextures", RLV_BHVR_SETCAM_TEXTURES, RlvBehaviourInfo::BHVR_SYNONYM | RlvBehaviourInfo::BHVR_DEPRECATED)); addEntry(new RlvBehaviourProcessor("camzoommin", RlvBehaviourInfo::BHVR_DEPRECATED)); addEntry(new RlvBehaviourProcessor("camzoommax", RlvBehaviourInfo::BHVR_DEPRECATED)); addEntry(new RlvBehaviourGenericToggleProcessor("camunlock", RlvBehaviourInfo::BHVR_SYNONYM | RlvBehaviourInfo::BHVR_DEPRECATED)); // Overlay RlvBehaviourInfo* pSetOverlayBhvr = new RlvBehaviourProcessor("setoverlay"); pSetOverlayBhvr->addModifier(ERlvLocalBhvrModifier::OverlayAlpha, typeid(float), "alpha", &RlvOverlayEffect::onAlphaValueChanged); pSetOverlayBhvr->addModifier(ERlvLocalBhvrModifier::OverlayTexture, typeid(LLUUID), "texture", &RlvOverlayEffect::onTextureChanged); pSetOverlayBhvr->addModifier(ERlvLocalBhvrModifier::OverlayTint, typeid(LLVector3), "tint", &RlvOverlayEffect::onColorValueChanged); addEntry(pSetOverlayBhvr); addEntry(new RlvBehaviourProcessor("setoverlay_touch")); addEntry(new RlvForceProcessor("setoverlay_tween")); // Sphere RlvBehaviourInfo* pSetSphereBhvr = new RlvBehaviourProcessor("setsphere"); pSetSphereBhvr->addModifier(ERlvLocalBhvrModifier::SphereMode, typeid(int), "mode", &RlvSphereEffect::onModeChanged); pSetSphereBhvr->addModifier(ERlvLocalBhvrModifier::SphereOrigin, typeid(int), "origin", &RlvSphereEffect::onOriginChanged); pSetSphereBhvr->addModifier(ERlvLocalBhvrModifier::SphereColor, typeid(LLVector3), "color", &RlvSphereEffect::onColorChanged); pSetSphereBhvr->addModifier(ERlvLocalBhvrModifier::SphereDistMin, typeid(float), "distmin", &RlvSphereEffect::onDistMinChanged); pSetSphereBhvr->addModifier(ERlvLocalBhvrModifier::SphereDistMax, typeid(float), "distmax", &RlvSphereEffect::onDistMaxChanged); pSetSphereBhvr->addModifier(ERlvLocalBhvrModifier::SphereDistExtend, typeid(int), "distextend", &RlvSphereEffect::onDistExtendChanged); pSetSphereBhvr->addModifier(ERlvLocalBhvrModifier::SphereParams, typeid(LLVector4), "param", &RlvSphereEffect::onParamsChanged); pSetSphereBhvr->addModifier(ERlvLocalBhvrModifier::SphereTween, typeid(float), "tween", &RlvSphereEffect::onTweenDurationChanged); pSetSphereBhvr->addModifier(ERlvLocalBhvrModifier::SphereValueMin, typeid(float), "valuemin", &RlvSphereEffect::onValueMinChanged); pSetSphereBhvr->addModifier(ERlvLocalBhvrModifier::SphereValueMax, typeid(float), "valuemax", &RlvSphereEffect::onValueMaxChanged); addEntry(pSetSphereBhvr); // // Force-wear // addEntry(new RlvBehaviourInfo("attach", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_REPLACE | RlvBehaviourInfo::FORCEWEAR_NODE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE)); addEntry(new RlvBehaviourInfo("attachall", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_REPLACE | RlvBehaviourInfo::FORCEWEAR_SUBTREE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE)); addEntry(new RlvBehaviourInfo("attachover", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_ADD | RlvBehaviourInfo::FORCEWEAR_NODE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE)); addEntry(new RlvBehaviourInfo("attachallover", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_ADD | RlvBehaviourInfo::FORCEWEAR_SUBTREE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE)); addEntry(new RlvBehaviourInfo("attachthis", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_REPLACE | RlvBehaviourInfo::FORCEWEAR_NODE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_OBJECT)); addEntry(new RlvBehaviourInfo("attachallthis", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_REPLACE | RlvBehaviourInfo::FORCEWEAR_SUBTREE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_OBJECT)); addEntry(new RlvBehaviourInfo("attachthisover", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_ADD | RlvBehaviourInfo::FORCEWEAR_NODE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_OBJECT)); addEntry(new RlvBehaviourInfo("attachallthisover", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_ADD | RlvBehaviourInfo::FORCEWEAR_SUBTREE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_OBJECT)); addEntry(new RlvForceProcessor("detach", RlvBehaviourInfo::FORCEWEAR_WEAR_REMOVE | RlvBehaviourInfo::FORCEWEAR_NODE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE)); addEntry(new RlvBehaviourInfo("detachall", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_REMOVE | RlvBehaviourInfo::FORCEWEAR_SUBTREE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE)); addEntry(new RlvBehaviourInfo("detachthis", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_REMOVE | RlvBehaviourInfo::FORCEWEAR_NODE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_OBJECT)); addEntry(new RlvBehaviourInfo("detachallthis", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_REMOVE | RlvBehaviourInfo::FORCEWEAR_SUBTREE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_OBJECT)); addEntry(new RlvForceProcessor("remattach", RlvBehaviourInfo::FORCEWEAR_WEAR_REMOVE | RlvBehaviourInfo::FORCEWEAR_NODE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE)); addEntry(new RlvForceProcessor("remoutfit", RlvBehaviourInfo::FORCEWEAR_WEAR_REMOVE | RlvBehaviourInfo::FORCEWEAR_NODE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE)); // Synonyms (addoutfit* -> attach*) addEntry(new RlvBehaviourInfo("addoutfit", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_REPLACE | RlvBehaviourInfo::FORCEWEAR_NODE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE | RlvBehaviourInfo::BHVR_SYNONYM)); addEntry(new RlvBehaviourInfo("addoutfitall", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_REPLACE | RlvBehaviourInfo::FORCEWEAR_SUBTREE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE | RlvBehaviourInfo::BHVR_SYNONYM)); addEntry(new RlvBehaviourInfo("addoutfitover", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_ADD | RlvBehaviourInfo::FORCEWEAR_NODE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE | RlvBehaviourInfo::BHVR_SYNONYM)); addEntry(new RlvBehaviourInfo("addoutfitallover", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_ADD | RlvBehaviourInfo::FORCEWEAR_SUBTREE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE | RlvBehaviourInfo::BHVR_SYNONYM)); addEntry(new RlvBehaviourInfo("addoutfitthis", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_REPLACE | RlvBehaviourInfo::FORCEWEAR_NODE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_OBJECT | RlvBehaviourInfo::BHVR_SYNONYM)); addEntry(new RlvBehaviourInfo("addoutfitallthis", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_REPLACE | RlvBehaviourInfo::FORCEWEAR_SUBTREE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_OBJECT | RlvBehaviourInfo::BHVR_SYNONYM)); addEntry(new RlvBehaviourInfo("addoutfitthisover", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_ADD | RlvBehaviourInfo::FORCEWEAR_NODE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_OBJECT | RlvBehaviourInfo::BHVR_SYNONYM)); addEntry(new RlvBehaviourInfo("addoutfitallthisover", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_ADD | RlvBehaviourInfo::FORCEWEAR_SUBTREE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_OBJECT | RlvBehaviourInfo::BHVR_SYNONYM)); // Synonyms (attach*overorreplace -> attach*) addEntry(new RlvBehaviourInfo("attachoverorreplace", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_REPLACE | RlvBehaviourInfo::FORCEWEAR_NODE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE | RlvBehaviourInfo::BHVR_SYNONYM)); addEntry(new RlvBehaviourInfo("attachalloverorreplace", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_REPLACE | RlvBehaviourInfo::FORCEWEAR_SUBTREE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE | RlvBehaviourInfo::BHVR_SYNONYM)); addEntry(new RlvBehaviourInfo("attachthisoverorreplace",RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_REPLACE | RlvBehaviourInfo::FORCEWEAR_NODE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_OBJECT | RlvBehaviourInfo::BHVR_SYNONYM)); addEntry(new RlvBehaviourInfo("attachallthisoverorreplace",RLV_CMD_FORCEWEAR,RLV_TYPE_FORCE,RlvBehaviourInfo::FORCEWEAR_WEAR_REPLACE | RlvBehaviourInfo::FORCEWEAR_SUBTREE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_OBJECT | RlvBehaviourInfo::BHVR_SYNONYM)); // // Force-only // addEntry(new RlvBehaviourInfo("adjustheight", RLV_BHVR_ADJUSTHEIGHT, RLV_TYPE_FORCE)); addEntry(new RlvForceProcessor("detachme")); addEntry(new RlvForceProcessor("fly")); addEntry(new RlvForceProcessor("setcam_focus", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); addEntry(new RlvForceProcessor("setcam_eyeoffset")); addEntry(new RlvForceProcessor("setcam_eyeoffsetscale")); addEntry(new RlvForceProcessor("setcam_focusoffset")); addEntry(new RlvForceProcessor("setcam_fov", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); addEntry(new RlvForceProcessor("setcam_mode", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); addEntry(new RlvForceProcessor("setgroup")); addEntry(new RlvForceProcessor("sit")); addEntry(new RlvForceProcessor("sitground")); addEntry(new RlvForceProcessor("tpto")); addEntry(new RlvBehaviourInfo("unsit", RLV_BHVR_UNSIT, RLV_TYPE_FORCE)); // // Reply-only // addEntry(new RlvBehaviourInfo("findfolder", RLV_BHVR_FINDFOLDER, RLV_TYPE_REPLY)); addEntry(new RlvBehaviourInfo("findfolders", RLV_BHVR_FINDFOLDERS, RLV_TYPE_REPLY, RlvBehaviourInfo::BHVR_EXTENDED)); addEntry(new RlvBehaviourInfo("getaddattachnames", RLV_BHVR_GETADDATTACHNAMES, RLV_TYPE_REPLY, RlvBehaviourInfo::BHVR_EXPERIMENTAL)); addEntry(new RlvBehaviourInfo("getaddoutfitnames", RLV_BHVR_GETADDOUTFITNAMES, RLV_TYPE_REPLY, RlvBehaviourInfo::BHVR_EXPERIMENTAL)); addEntry(new RlvBehaviourInfo("getattach", RLV_BHVR_GETATTACH, RLV_TYPE_REPLY)); addEntry(new RlvBehaviourInfo("getattachnames", RLV_BHVR_GETATTACHNAMES, RLV_TYPE_REPLY, RlvBehaviourInfo::BHVR_EXPERIMENTAL)); addEntry(new RlvReplyProcessor("getcam_avdist", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); addEntry(new RlvReplyProcessor("getcam_avdistmin", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); addEntry(new RlvReplyProcessor("getcam_avdistmax", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); addEntry(new RlvReplyProcessor("getcam_fov", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); addEntry(new RlvReplyProcessor("getcam_fovmin", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); addEntry(new RlvReplyProcessor("getcam_fovmax", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); addEntry(new RlvReplyProcessor("getcam_textures", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); addEntry(new RlvReplyProcessor("getcommand", RlvBehaviourInfo::BHVR_EXTENDED)); addEntry(new RlvBehaviourInfo("getgroup", RLV_BHVR_GETGROUP, RLV_TYPE_REPLY)); addEntry(new RlvReplyProcessor("getheightoffset", RlvBehaviourInfo::BHVR_EXTENDED)); addEntry(new RlvBehaviourInfo("getinv", RLV_BHVR_GETINV, RLV_TYPE_REPLY)); addEntry(new RlvBehaviourInfo("getinvworn", RLV_BHVR_GETINVWORN, RLV_TYPE_REPLY)); addEntry(new RlvBehaviourInfo("getoutfit", RLV_BHVR_GETOUTFIT, RLV_TYPE_REPLY)); addEntry(new RlvBehaviourInfo("getoutfitnames", RLV_BHVR_GETOUTFITNAMES, RLV_TYPE_REPLY, RlvBehaviourInfo::BHVR_EXPERIMENTAL)); addEntry(new RlvBehaviourInfo("getpath", RLV_BHVR_GETPATH, RLV_TYPE_REPLY)); addEntry(new RlvBehaviourInfo("getpathnew", RLV_BHVR_GETPATHNEW, RLV_TYPE_REPLY)); addEntry(new RlvBehaviourInfo("getremattachnames", RLV_BHVR_GETREMATTACHNAMES, RLV_TYPE_REPLY, RlvBehaviourInfo::BHVR_EXPERIMENTAL)); addEntry(new RlvBehaviourInfo("getremoutfitnames", RLV_BHVR_GETREMOUTFITNAMES, RLV_TYPE_REPLY, RlvBehaviourInfo::BHVR_EXPERIMENTAL)); addEntry(new RlvBehaviourInfo("getsitid", RLV_BHVR_GETSITID, RLV_TYPE_REPLY)); addEntry(new RlvBehaviourInfo("getstatus", RLV_BHVR_GETSTATUS, RLV_TYPE_REPLY)); addEntry(new RlvBehaviourInfo("getstatusall", RLV_BHVR_GETSTATUSALL, RLV_TYPE_REPLY)); addEntry(new RlvBehaviourInfo("version", RLV_BHVR_VERSION, RLV_TYPE_REPLY)); addEntry(new RlvBehaviourInfo("versionnew", RLV_BHVR_VERSIONNEW, RLV_TYPE_REPLY)); addEntry(new RlvBehaviourInfo("versionnum", RLV_BHVR_VERSIONNUM, RLV_TYPE_REPLY)); // Populate m_String2InfoMap (the tuple should be unique) for (const RlvBehaviourInfo* pBhvrInfo : m_BhvrInfoList) { RLV_VERIFY(m_String2InfoMap.insert(std::make_pair(std::make_pair(pBhvrInfo->getBehaviour(), (ERlvParamType)pBhvrInfo->getParamTypeMask()), pBhvrInfo)).second == true); } // Populate m_Bhvr2InfoMap (there can be multiple entries per ERlvBehaviour) for (const RlvBehaviourInfo* pBhvrInfo : m_BhvrInfoList) { if ( (pBhvrInfo->getParamTypeMask() & RLV_TYPE_ADDREM) && (!pBhvrInfo->isSynonym()) ) { #ifdef RLV_DEBUG for (const rlv_bhvr2info_map_t::value_type& itBhvr : boost::make_iterator_range(m_Bhvr2InfoMap.lower_bound(pBhvrInfo->getBehaviourType()), m_Bhvr2InfoMap.upper_bound(pBhvrInfo->getBehaviourType()))) { RLV_ASSERT( (itBhvr.first != pBhvrInfo->getBehaviourType()) || (itBhvr.second->getBehaviourFlags() != pBhvrInfo->getBehaviourFlags()) ); } #endif // RLV_DEBUG m_Bhvr2InfoMap.insert(std::pair(pBhvrInfo->getBehaviourType(), pBhvrInfo)); } } // Process blocked commands if (RlvSettings::getNoSetEnv()) toggleBehaviourFlag("setenv", RLV_TYPE_ADDREM, RlvBehaviourInfo::BHVR_BLOCKED, true); } 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) { // Filter experimental commands (if disabled) static LLCachedControl sEnableExperimental(gSavedSettings, "RLVaExperimentalCommands"); if ( (!pEntry) || ((!sEnableExperimental) && (pEntry->isExperimental())) ) { return; } // Sanity check for duplicate entries #ifndef LL_RELEASE_FOR_DOWNLOAD std::for_each(m_BhvrInfoList.begin(), m_BhvrInfoList.end(), [&pEntry](const RlvBehaviourInfo* pBhvrInfo) { RLV_ASSERT_DBG( ((pBhvrInfo->getBehaviour()) != (pEntry->getBehaviour())) || ((pBhvrInfo->getParamTypeMask() & pEntry->getParamTypeMask()) == 0) ); }); #endif // LL_RELEASE_FOR_DOWNLOAD 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)); } } // Convenience function to add both the behaviour entry as well as the corresponding modifier entry void RlvBehaviourDictionary::addModifier(const RlvBehaviourInfo* pBhvrEntry, ERlvBehaviourModifier eModifier, RlvBehaviourModifier* pModifierEntry) { addEntry(pBhvrEntry); 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(ERlvBehaviour eBhvr, ERlvParamType eParamType) const { const RlvBehaviourInfo* pBhvrInfo = nullptr; for (auto itBhvrLower = m_Bhvr2InfoMap.lower_bound(eBhvr), itBhvrUpper = m_Bhvr2InfoMap.upper_bound(eBhvr); std::find_if(itBhvrLower, itBhvrUpper, [eParamType](const rlv_bhvr2info_map_t::value_type& bhvrEntry) { return bhvrEntry.second->getParamTypeMask() == eParamType; }) != itBhvrUpper; ++itBhvrLower) { if (pBhvrInfo) return nullptr; pBhvrInfo = itBhvrLower->second; } return pBhvrInfo; } const RlvBehaviourInfo* RlvBehaviourDictionary::getBehaviourInfo(const std::string& strBhvr, ERlvParamType eParamType, bool* pfStrict, ERlvLocalBhvrModifier* peBhvrModifier) const { 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; ERlvLocalBhvrModifier eBhvrModifier = ERlvLocalBhvrModifier::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)); 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)) != ERlvLocalBhvrModifier::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 { ERlvLocalBhvrModifier 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 && ERlvLocalBhvrModifier::Unknown == eBhvrModifier) ? pBhvrInfo->getBehaviourType() : RLV_BHVR_UNKNOWN; } bool RlvBehaviourDictionary::getCommands(const std::string& strMatch, ERlvParamType eParamType, std::list& cmdList) const { cmdList.clear(); for (const RlvBehaviourInfo* pBhvrInfo : m_BhvrInfoList) { if ( (pBhvrInfo->getParamTypeMask() & eParamType) || (RLV_TYPE_UNKNOWN == eParamType) ) { std::string strCmd = pBhvrInfo->getBehaviour(); if ( (std::string::npos != strCmd.find(strMatch)) || (strMatch.empty()) ) cmdList.push_back(strCmd); if ( (pBhvrInfo->hasStrict()) && ((std::string::npos != strCmd.append("_sec").find(strMatch)) || (strMatch.empty())) ) cmdList.push_back(strCmd); } } return !cmdList.empty(); } bool RlvBehaviourDictionary::getHasStrict(ERlvBehaviour eBhvr) const { for (const rlv_bhvr2info_map_t::value_type& itBhvr : boost::make_iterator_range(m_Bhvr2InfoMap.lower_bound(eBhvr), m_Bhvr2InfoMap.upper_bound(eBhvr))) { // Only restrictions can be strict if (RLV_TYPE_ADDREM != itBhvr.second->getParamTypeMask()) continue; return itBhvr.second->hasStrict(); } RLV_ASSERT(false); 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)); if (m_String2InfoMap.end() != itBhvr) { const_cast(itBhvr->second)->toggleBehaviourFlag(eBhvrFlag, fEnable); } } // ============================================================================ // RlvBehaviourInfo // // virtual ERlvCmdRet RlvBehaviourInfo::processModifier(const RlvCommand& rlvCmd) const { // The object should have the base behaviour set (or else there's nothing to modify) if (!gRlvHandler.hasBehaviour(rlvCmd.getObjectID(), rlvCmd.getBehaviourType())) return RLV_RET_FAILED_UNHELDBEHAVIOUR; 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 // RlvBehaviourModifier::RlvBehaviourModifier(std::string strName, const RlvBehaviourModifierValue& defaultValue, bool fAddDefaultOnEmpty, RlvBehaviourModifierComp* pValueComparator) : m_strName(strName), m_DefaultValue(defaultValue), m_fAddDefaultOnEmpty(fAddDefaultOnEmpty), m_pValueComparator(pValueComparator) { m_pValueComparator = (pValueComparator) ? pValueComparator : new RlvBehaviourModifierComp(); } RlvBehaviourModifier::~RlvBehaviourModifier() { if (m_pValueComparator) { delete m_pValueComparator; m_pValueComparator = NULL; } } 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_tuple(modValue, idRlvObj, eBhvr), boost::bind(&RlvBehaviourModifierComp::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(); return true; } 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; } 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()) ? std::get<1>(m_Values.front()) == m_pValueComparator->m_idPrimaryObject : false; } bool RlvBehaviourModifier::hasValue(const LLUUID& idRlvObj) const { return m_Values.end() != std::find_if(m_Values.begin(), m_Values.end(), [&idRlvObj](const RlvBehaviourModifierValueTuple& cmpValue) { return std::get<1>(cmpValue) == idRlvObj; }); } 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_tuple(modValue, idRlvObj, eBhvr)); if (m_Values.end() != itValue) { m_Values.erase(itValue); onValueChange(); m_ChangeSignal(getValue()); } } } void RlvBehaviourModifier::setPrimaryObject(const LLUUID& idPrimaryObject) { if (m_pValueComparator) { m_pValueComparator->m_idPrimaryObject = idPrimaryObject; m_Values.sort(boost::bind(&RlvBehaviourModifierComp::operator(), m_pValueComparator, _1, _2)); onValueChange(); m_ChangeSignal(getValue()); } } 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(&RlvBehaviourModifierComp::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); } } } // static bool RlvBehaviourModifier::convertOptionValue(const std::string& optionValue, const std::type_index& modType, RlvBehaviourModifierValue& modValue) { try { if (modType == typeid(float)) { modValue = std::stof(optionValue); return true; } else if (modType == typeid(int)) { modValue = std::stoi(optionValue); return true; } 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)) { modValue = vecOption; return true; } } else if (modType == typeid(LLVector4)) { LLVector4 vecOption; if (4 == sscanf(optionValue.c_str(), "%f/%f/%f/%f", vecOption.mV + 0, vecOption.mV + 1, vecOption.mV + 2, vecOption.mV + 3)) { modValue = vecOption; return true; } } else if (modType == typeid(LLUUID)) { LLUUID idOption; if (LLUUID::parseUUID(optionValue, &idOption)) { modValue = idOption; return true; } } return false; } catch (const std::invalid_argument&) { return false; } catch (const std::out_of_range&) { return false; } } // ============================================================================ // RlvCommmand // RlvCommand::RlvCommand(const LLUUID& idObj, const std::string& strCommand) : m_idObj(idObj) { if ((m_fValid = parseCommand(strCommand, m_strBehaviour, m_strOption, m_strParam))) { S32 nTemp = 0; if ( ("n" == m_strParam) || ("add" == m_strParam) ) m_eParamType = RLV_TYPE_ADD; else if ( ("y" == m_strParam) || ("rem" == m_strParam) ) m_eParamType = RLV_TYPE_REMOVE; else if (m_strBehaviour == "clear") // clear is the odd one out so just make it its own type m_eParamType = RLV_TYPE_CLEAR; else if ("force" == m_strParam) m_eParamType = RLV_TYPE_FORCE; else if (LLStringUtil::convertToS32(m_strParam, nTemp)) // Assume it's a reply command if we can convert to an S32 m_eParamType = RLV_TYPE_REPLY; else { m_eParamType = RLV_TYPE_UNKNOWN; m_fValid = false; } } if (!m_fValid) { m_strOption = m_strParam = ""; return; } m_pBhvrInfo = RlvBehaviourDictionary::instance().getBehaviourInfo(m_strBehaviour, m_eParamType, &m_fStrict, &m_eBhvrModifier); } RlvCommand::RlvCommand(const RlvCommand& rlvCmd, ERlvParamType eParamType) : m_fValid(rlvCmd.m_fValid), m_idObj(rlvCmd.m_idObj), m_strBehaviour(rlvCmd.m_strBehaviour), m_pBhvrInfo(rlvCmd.m_pBhvrInfo) , m_eParamType( (RLV_TYPE_UNKNOWN == eParamType) ? rlvCmd.m_eParamType : eParamType), m_eBhvrModifier(rlvCmd.m_eBhvrModifier) , m_fStrict(rlvCmd.m_fStrict), m_strOption(rlvCmd.m_strOption), m_strParam(rlvCmd.m_strParam), m_fRefCounted(rlvCmd.m_fRefCounted) { } bool RlvCommand::parseCommand(const std::string& strCommand, std::string& strBehaviour, std::string& strOption, std::string& strParam) { // (See behaviour notes for the command parsing truth table) // Format: [: