/**
*
* Copyright (c) 2009-2016, 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 "llgesturemgr.h"
#include "llnotificationsutil.h"
#include "llviewerobjectlist.h"
// FIRE-4453 bridge detached by the RLV command @remattach=force
#include "fslslbridge.h"
// FIRE-4453
#include "rlvcommon.h"
#include "rlvhelper.h"
#include "rlvhandler.h"
#include "rlvinventory.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 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("editobj", RLV_BHVR_EDITOBJ));
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 RlvBehaviourModifier_CompMin));
addEntry(new RlvBehaviourGenericProcessor("fly", RLV_BHVR_FLY));
addEntry(new RlvBehaviourGenericProcessor("interact", RLV_BHVR_INTERACT, RlvBehaviourInfo::BHVR_EXTENDED));
addEntry(new RlvBehaviourInfo("notify", RLV_BHVR_NOTIFY, RLV_TYPE_ADDREM));
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 RlvBehaviourModifier_CompMax));
addModifier(RLV_BHVR_RECVIM, RLV_MODIFIER_RECVIMDISTMAX, new RlvBehaviourModifier("RecvIM Distance (Max)", F32_MAX, true, new RlvBehaviourModifier_CompMin));
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 RlvBehaviourModifier_CompMax));
addModifier(RLV_BHVR_SENDIM, RLV_MODIFIER_SENDIMDISTMAX, new RlvBehaviourModifier("SendIM Distance (Max)", F32_MAX, true, new RlvBehaviourModifier_CompMin));
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 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 RlvBehaviourToggleProcessor("shownametags", RlvBehaviourInfo::BHVR_STRICT ));
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 RlvBehaviourModifier_CompMin));
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 RlvBehaviourModifier_CompMax));
addModifier(RLV_BHVR_STARTIM, RLV_MODIFIER_STARTIMDISTMAX, new RlvBehaviourModifier("StartIM Distance (Max)", F32_MAX, true, new RlvBehaviourModifier_CompMin));
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 RlvBehaviourModifier_CompMin));
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_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 RlvBehaviourModifier_CompMax()));
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 RlvBehaviourModifier_CompMin));
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 RlvBehaviourModifier_CompMax));
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 RlvBehaviourModifier_CompMin));
addEntry(new RlvBehaviourGenericToggleProcessor("setcam_eyeoffset", RlvBehaviourInfo::BHVR_EXPERIMENTAL));
addModifier(RLV_BHVR_SETCAM_EYEOFFSET, RLV_MODIFIER_SETCAM_EYEOFFSET, new RlvBehaviourModifierHandler("Camera - Eye Offset", LLVector3::zero, true, nullptr));
addEntry(new RlvBehaviourGenericToggleProcessor("setcam_focusoffset", RlvBehaviourInfo::BHVR_EXPERIMENTAL));
addModifier(RLV_BHVR_SETCAM_FOCUSOFFSET, RLV_MODIFIER_SETCAM_FOCUSOFFSET, new RlvBehaviourModifierHandler("Camera - Focus Offset", LLVector3::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 RlvBehaviourModifier_CompMax));
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 RlvBehaviourModifier_CompMin));
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("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));
//
// 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("setcam_focus", RlvBehaviourInfo::BHVR_EXPERIMENTAL));
addEntry(new RlvForceProcessor("setcam_eyeoffset", RlvBehaviourInfo::BHVR_EXPERIMENTAL));
addEntry(new RlvForceProcessor("setcam_focusoffset", RlvBehaviourInfo::BHVR_EXPERIMENTAL));
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("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 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));
}
}
const RlvBehaviourInfo* RlvBehaviourDictionary::getBehaviourInfo(const std::string& strBhvr, ERlvParamType eParamType, bool* pfStrict) const
{
bool fStrict = boost::algorithm::ends_with(strBhvr, "_sec");
if (pfStrict)
*pfStrict = fStrict;
rlv_string2info_map_t::const_iterator itBhvr = m_String2InfoMap.find(std::make_pair( (!fStrict) ? strBhvr : strBhvr.substr(0, strBhvr.size() - 4), (eParamType & RLV_TYPE_ADDREM) ? RLV_TYPE_ADDREM : eParamType));
return ( (itBhvr != m_String2InfoMap.end()) && ((!fStrict) || (itBhvr->second->hasStrict())) ) ? itBhvr->second : NULL;
}
ERlvBehaviour RlvBehaviourDictionary::getBehaviourFromString(const std::string& strBhvr, ERlvParamType eParamType, bool* pfStrict) const
{
const RlvBehaviourInfo* pBhvrInfo = getBehaviourInfo(strBhvr, eParamType, pfStrict);
return (pBhvrInfo) ? pBhvrInfo->getBehaviourType() : RLV_BHVR_UNKNOWN;
}
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);
}
}
// ============================================================================
// RlvBehaviourModifier
//
RlvBehaviourModifier::RlvBehaviourModifier(std::string strName, const RlvBehaviourModifierValue& defaultValue, bool fAddDefaultOnEmpty, RlvBehaviourModifier_Comp* pValueComparator)
: m_strName(strName), m_DefaultValue(defaultValue), m_fAddDefaultOnEmpty(fAddDefaultOnEmpty), m_pValueComparator(pValueComparator)
{
m_pValueComparator = (pValueComparator) ? pValueComparator : new RlvBehaviourModifier_Comp();
}
RlvBehaviourModifier::~RlvBehaviourModifier()
{
if (m_pValueComparator)
{
delete m_pValueComparator;
m_pValueComparator = NULL;
}
}
bool RlvBehaviourModifier::addValue(const RlvBehaviourModifierValue& modValue, const LLUUID& idObject)
{
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));
// 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;
}
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()) ? m_Values.front().second == m_pValueComparator->m_idPrimaryObject : false;
}
void RlvBehaviourModifier::removeValue(const RlvBehaviourModifierValue& modValue, const LLUUID& idObject)
{
if ( (modValue.which() == m_DefaultValue.which()) )
{
auto itValue = std::find(m_Values.begin(), m_Values.end(), std::make_pair(modValue, idObject));
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(&RlvBehaviourModifier_Comp::operator(), m_pValueComparator, _1, _2));
onValueChange();
m_ChangeSignal(getValue());
}
}
bool RlvBehaviourModifier::convertOptionValue(const std::string& optionValue, RlvBehaviourModifierValue& modValue) const
{
try
{
if (typeid(float) == m_DefaultValue.type())
{
modValue = std::stof(optionValue);
return true;
}
else if (typeid(int) == m_DefaultValue.type())
{
modValue = std::stoi(optionValue);
return true;
}
else if (typeid(LLVector3) == m_DefaultValue.type())
{
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 (typeid(LLUUID) == m_DefaultValue.type())
{
LLUUID idOption;
if (LLUUID::parseUUID(optionValue, &idOption))
{
modValue = idOption;
return true;
}
}
return false;
}
catch (const std::invalid_argument&)
{
return false;
}
}
// ============================================================================
// RlvCommmand
//
RlvCommand::RlvCommand(const LLUUID& idObj, const std::string& strCommand)
: m_fValid(false), m_idObj(idObj), m_pBhvrInfo(NULL), m_eParamType(RLV_TYPE_UNKNOWN), m_fStrict(false), m_fRefCounted(false)
{
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);
}
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_fStrict(rlvCmd.m_fStrict), m_strOption(rlvCmd.m_strOption), m_strParam(rlvCmd.m_strParam), m_fRefCounted(false)
{
}
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: [: