1ea7389, 49be412, ed4c8e6 & 7ce9521 - changed : "Give to #RLV" agent-to-agent and script-to-agent offers can contain subfolders -> limited to 3 levels (e.g. #RLV/~FolderA/FolderB/FolderC) -> #RLV folder is auto-created if it doesn't currently exist 8780d84 - Incremented version number to RLVa-1.4.10 f078067 - internal : boolean (custom) debug settings should have a boolean type 72a8ad8 & 401ca14 - internal : added supporting code for "Detach Folder" RLVa lock checks 05718b5 - fixed : RenderResolutionDivisor is non-functional -> RenderResolutionDivisor isn't actually taken into account when checking the new screen resolution against the current screen buffer size 4fa138b - fixed : viewer clips mouse to its rectangle when switching into mouselook while it's not the active application -> Repro: * rez a prim with a script to llForceMouseLook(TRUE) and force-sit when clicked (with a slight delay) * click the prim and give focus to another application => the viewer will center the mouse cursor on itself and restrict movement to within its own rectangle (requires alt-tab to escape) + Singu Note: Thanks to Kitty for this, it is possible that this would happen in our last release 14132c9 - fixed : region name and global coordinates are shown on the About floater when @showloc restricted + Singu Note: RLV version is now shown in help->about 9a2af62 - changed : llRegionSayTo messages are no longer subject to @recvchat(from) or @recvemote(from) 2dc4b89 - fixed : @getstatus and @getstatusall should specify an (optional) separator -> added support for both @getstatus:tp;|=123 and @getstatus:;|=123 fbb3fb1 - Incremented API version number to 2.8.0 92c39b9 - internal : quick and dirty hack fix for RlvUtil::filterNames() but there's no time to do a proper backport from RLVa-1.5 2580f1c - internal : remove hack for legacy viewers without multi-attachment support
750 lines
26 KiB
C++
750 lines
26 KiB
C++
/**
|
|
*
|
|
* Copyright (c) 2009-2011, 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 "llagent.h"
|
|
#include "llagentui.h"
|
|
#include "llavatarnamecache.h"
|
|
#include "llinstantmessage.h"
|
|
#include "llnotificationsutil.h"
|
|
#include "llsdserialize.h"
|
|
#include "lluictrlfactory.h"
|
|
#include "llviewermenu.h"
|
|
#include "llviewerparcelmgr.h"
|
|
#include "llviewermenu.h"
|
|
#include "llviewerregion.h"
|
|
#include "llviewerstats.h"
|
|
#include "llworld.h"
|
|
|
|
#include "rlvactions.h"
|
|
#include "rlvcommon.h"
|
|
#include "rlvhelper.h"
|
|
#include "rlvhandler.h"
|
|
#include "rlvlocks.h"
|
|
|
|
#include "../lscript/lscript_byteformat.h" //Need LSCRIPTRunTimePermissionBits and SCRIPT_PERMISSION_*
|
|
#include <boost/algorithm/string.hpp>
|
|
|
|
// ============================================================================
|
|
// RlvNotifications
|
|
//
|
|
|
|
// Checked: 2009-11-13 (RLVa-1.1.0b) | Modified: RLVa-1.1.0b
|
|
/*
|
|
void RlvNotifications::warnGiveToRLV()
|
|
{
|
|
if ( (gSavedSettings.getWarning(RLV_SETTING_FIRSTUSE_GIVETORLV)) && (RlvSettings::getForbidGiveToRLV()) )
|
|
LLNotifications::instance().add(RLV_SETTING_FIRSTUSE_GIVETORLV, LLSD(), LLSD(), &RlvNotifications::onGiveToRLVConfirmation);
|
|
}
|
|
*/
|
|
|
|
// Checked: 2009-11-13 (RLVa-1.1.0b) | Modified: RLVa-1.1.0b
|
|
/*
|
|
void RlvNotifications::onGiveToRLVConfirmation(const LLSD& notification, const LLSD& response)
|
|
{
|
|
gSavedSettings.setWarning(RLV_SETTING_FIRSTUSE_GIVETORLV, FALSE);
|
|
|
|
S32 idxOption = LLNotification::getSelectedOption(notification, response);
|
|
if ( (0 == idxOption) || (1 == idxOption) )
|
|
gSavedSettings.setBOOL(RLV_SETTING_FORBIDGIVETORLV, (idxOption == 1));
|
|
}
|
|
*/
|
|
|
|
// =========================================================================
|
|
// RlvSettings
|
|
//
|
|
|
|
#ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS
|
|
bool RlvSettings::fCompositeFolders = false;
|
|
#endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS
|
|
bool RlvSettings::fCanOOC = true;
|
|
bool RlvSettings::fLegacyNaming = true;
|
|
bool RlvSettings::fNoSetEnv = false;
|
|
bool RlvSettings::fShowNameTags = false;
|
|
|
|
// Checked: 2010-02-27 (RLVa-1.2.0a) | Modified: RLVa-1.1.0i
|
|
void RlvSettings::initClass()
|
|
{
|
|
static bool fInitialized = false;
|
|
if (!fInitialized)
|
|
{
|
|
#ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS
|
|
fCompositeFolders = rlvGetSetting<bool>(RLV_SETTING_ENABLECOMPOSITES, false);
|
|
if (gSavedSettings.controlExists(RLV_SETTING_ENABLECOMPOSITES))
|
|
gSavedSettings.getControl(RLV_SETTING_ENABLECOMPOSITES)->getSignal()->connect(boost::bind(&onChangedSettingBOOL, _2, &fCompositeFolders));
|
|
#endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS
|
|
|
|
fLegacyNaming = rlvGetSetting<bool>(RLV_SETTING_ENABLELEGACYNAMING, true);
|
|
if (gSavedSettings.controlExists(RLV_SETTING_ENABLELEGACYNAMING))
|
|
gSavedSettings.getControl(RLV_SETTING_ENABLELEGACYNAMING)->getSignal()->connect(boost::bind(&onChangedSettingBOOL, _2, &fLegacyNaming));
|
|
|
|
fCanOOC = rlvGetSetting<bool>(RLV_SETTING_CANOOC, true);
|
|
fNoSetEnv = rlvGetSetting<bool>(RLV_SETTING_NOSETENV, false);
|
|
|
|
fShowNameTags = rlvGetSetting<bool>(RLV_SETTING_SHOWNAMETAGS, false);
|
|
if (gSavedSettings.controlExists(RLV_SETTING_SHOWNAMETAGS))
|
|
gSavedSettings.getControl(RLV_SETTING_SHOWNAMETAGS)->getSignal()->connect(boost::bind(&onChangedSettingBOOL, _2, &fShowNameTags));
|
|
|
|
#ifdef RLV_EXTENSION_STARTLOCATION
|
|
// Don't allow toggling RLVaLoginLastLocation from the debug settings floater
|
|
if (gSavedPerAccountSettings.controlExists(RLV_SETTING_LOGINLASTLOCATION))
|
|
gSavedPerAccountSettings.getControl(RLV_SETTING_LOGINLASTLOCATION)->setHiddenFromSettingsEditor(true);
|
|
#endif // RLV_EXTENSION_STARTLOCATION
|
|
|
|
if (gSavedSettings.controlExists(RLV_SETTING_TOPLEVELMENU))
|
|
gSavedSettings.getControl(RLV_SETTING_TOPLEVELMENU)->getSignal()->connect(boost::bind(&onChangedMenuLevel));
|
|
|
|
fInitialized = true;
|
|
}
|
|
}
|
|
|
|
#ifdef RLV_EXTENSION_STARTLOCATION
|
|
// Checked: 2010-04-01 (RLVa-1.2.0c) | Modified: RLVa-0.2.1d
|
|
void RlvSettings::updateLoginLastLocation()
|
|
{
|
|
if ( (!LLApp::isQuitting()) && (gSavedPerAccountSettings.controlExists(RLV_SETTING_LOGINLASTLOCATION)) )
|
|
{
|
|
BOOL fValue = (gRlvHandler.hasBehaviour(RLV_BHVR_TPLOC)) || (!RlvActions::canStand());
|
|
if (gSavedPerAccountSettings.getBOOL(RLV_SETTING_LOGINLASTLOCATION) != fValue)
|
|
{
|
|
gSavedPerAccountSettings.setBOOL(RLV_SETTING_LOGINLASTLOCATION, fValue);
|
|
gSavedPerAccountSettings.saveToFile(gSavedSettings.getString("PerAccountSettingsFile"), TRUE);
|
|
}
|
|
}
|
|
}
|
|
#endif // RLV_EXTENSION_STARTLOCATION
|
|
|
|
// Checked: 2013-04-17 (RLVa-1.4.8)
|
|
bool RlvSettings::onChangedAvatarOffset(const LLSD& sdValue)
|
|
{
|
|
if ( (isAgentAvatarValid()) && (!gAgentAvatarp->isUsingServerBakes()) )
|
|
{
|
|
gAgentAvatarp->computeBodySize();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Checked: 2011-08-16 (RLVa-1.4.0b) | Added: RLVa-1.4.0b
|
|
bool RlvSettings::onChangedMenuLevel()
|
|
{
|
|
rlvMenuToggleVisible();
|
|
return true;
|
|
}
|
|
|
|
// Checked: 2010-02-27 (RLVa-1.2.0a) | Added: RLVa-1.1.0i
|
|
bool RlvSettings::onChangedSettingBOOL(const LLSD& sdValue, bool* pfSetting)
|
|
{
|
|
if (pfSetting)
|
|
*pfSetting = sdValue.asBoolean();
|
|
return true;
|
|
}
|
|
|
|
// ============================================================================
|
|
// RlvStrings
|
|
//
|
|
|
|
std::vector<std::string> RlvStrings::m_Anonyms;
|
|
RlvStrings::string_map_t RlvStrings::m_StringMap;
|
|
std::string RlvStrings::m_StringMapPath;
|
|
|
|
// Checked: 2011-11-08 (RLVa-1.5.0)
|
|
void RlvStrings::initClass()
|
|
{
|
|
static bool fInitialized = false;
|
|
if (!fInitialized)
|
|
{
|
|
// Load the default string values
|
|
/* Singu TODO: findSkinnedFilenames/LLDir update
|
|
std::vector<std::string> files = gDirUtilp->findSkinnedFilenames(LLDir::XUI, RLV_STRINGS_FILE, LLDir::ALL_SKINS);
|
|
m_StringMapPath = (!files.empty()) ? files.front() : LLStringUtil::null;
|
|
for (auto itFile = files.cbegin(); itFile != files.cend(); ++itFile)
|
|
*/
|
|
std::string itFile = gDirUtilp->findSkinnedFilename(LLUICtrlFactory::getXUIPaths().front(), RLV_STRINGS_FILE);
|
|
if (!itFile.empty())
|
|
{
|
|
loadFromFile(itFile, false);
|
|
}
|
|
m_StringMapPath = itFile; // Singu TODO: Remove this when updating to the above LLDir impl.
|
|
|
|
// Load the custom string overrides
|
|
loadFromFile(gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, RLV_STRINGS_FILE), true);
|
|
|
|
// Sanity check
|
|
if ( (m_StringMap.empty()) || (m_Anonyms.empty()) )
|
|
{
|
|
RLV_ERRS << "Problem parsing RLVa string XML file" << RLV_ENDL;
|
|
return;
|
|
}
|
|
|
|
fInitialized = true;
|
|
}
|
|
}
|
|
|
|
// Checked: 2011-11-08 (RLVa-1.5.0)
|
|
void RlvStrings::loadFromFile(const std::string& strFilePath, bool fUserOverride)
|
|
{
|
|
llifstream fileStream(strFilePath, std::ios::binary); LLSD sdFileData;
|
|
if ( (!fileStream.is_open()) || (!LLSDSerialize::fromXMLDocument(sdFileData, fileStream)) )
|
|
return;
|
|
fileStream.close();
|
|
|
|
if (sdFileData.has("strings"))
|
|
{
|
|
const LLSD& sdStrings = sdFileData["strings"];
|
|
for (LLSD::map_const_iterator itString = sdStrings.beginMap(); itString != sdStrings.endMap(); ++itString)
|
|
{
|
|
if ( (!itString->second.has("value")) || ((fUserOverride) && (!hasString(itString->first))) )
|
|
continue;
|
|
|
|
std::list<std::string>& listValues = m_StringMap[itString->first];
|
|
if (!fUserOverride)
|
|
{
|
|
if (listValues.size() > 0)
|
|
listValues.pop_front();
|
|
listValues.push_front(itString->second["value"].asString());
|
|
}
|
|
else
|
|
{
|
|
while (listValues.size() > 1)
|
|
listValues.pop_back();
|
|
listValues.push_back(itString->second["value"].asString());
|
|
}
|
|
}
|
|
}
|
|
if (sdFileData.has("anonyms"))
|
|
{
|
|
const LLSD& sdAnonyms = sdFileData["anonyms"];
|
|
for (LLSD::array_const_iterator itAnonym = sdAnonyms.beginArray(); itAnonym != sdAnonyms.endArray(); ++itAnonym)
|
|
{
|
|
m_Anonyms.push_back((*itAnonym).asString());
|
|
}
|
|
}
|
|
}
|
|
|
|
// Checked: 2011-11-08 (RLVa-1.5.0)
|
|
void RlvStrings::saveToFile(const std::string& strFilePath)
|
|
{
|
|
LLSD sdFileData;
|
|
|
|
LLSD& sdStrings = sdFileData["strings"];
|
|
for (string_map_t::const_iterator itString = m_StringMap.begin(); itString != m_StringMap.end(); ++itString)
|
|
{
|
|
const std::list<std::string>& listValues = itString->second;
|
|
if (listValues.size() > 1)
|
|
sdStrings[itString->first]["value"] = listValues.back();
|
|
}
|
|
|
|
llofstream fileStream(strFilePath);
|
|
if (!fileStream.good())
|
|
return;
|
|
|
|
LLSDSerialize::toPrettyXML(sdFileData, fileStream);
|
|
fileStream.close();
|
|
}
|
|
|
|
// Checked: 2009-11-11 (RLVa-1.1.0a) | Modified: RLVa-1.1.0a
|
|
const std::string& RlvStrings::getAnonym(const std::string& strName)
|
|
{
|
|
const char* pszName = strName.c_str(); U32 nHash = 0;
|
|
|
|
// Test with 11,264 SL names showed a 3.33% - 3.82% occurance for each so we *should* get a very even spread
|
|
for (int idx = 0, cnt = strName.length(); idx < cnt; idx++)
|
|
nHash += pszName[idx];
|
|
|
|
return m_Anonyms[nHash % m_Anonyms.size()];
|
|
}
|
|
|
|
// Checked: 2011-11-08 (RLVa-1.5.0)
|
|
const std::string& RlvStrings::getString(const std::string& strStringName)
|
|
{
|
|
static const std::string strMissing = "(Missing RLVa string)";
|
|
string_map_t::const_iterator itString = m_StringMap.find(strStringName);
|
|
return (itString != m_StringMap.end()) ? itString->second.back() : strMissing;
|
|
}
|
|
|
|
// Checked: 2009-11-25 (RLVa-1.1.0f) | Added: RLVa-1.1.0f
|
|
const char* RlvStrings::getStringFromReturnCode(ERlvCmdRet eRet)
|
|
{
|
|
// TODO-RLVa: [2009-11-25] clean this up along with the calling code in process_chat_from_simulator() once we're happy with the output
|
|
switch (eRet)
|
|
{
|
|
case RLV_RET_SUCCESS_UNSET:
|
|
return "unset";
|
|
case RLV_RET_SUCCESS_DUPLICATE:
|
|
return "duplicate";
|
|
case RLV_RET_SUCCESS_DELAYED:
|
|
return "delayed";
|
|
case RLV_RET_FAILED_SYNTAX:
|
|
return "syntax error";
|
|
case RLV_RET_FAILED_OPTION:
|
|
return "invalid option";
|
|
case RLV_RET_FAILED_PARAM:
|
|
return "invalid param";
|
|
case RLV_RET_FAILED_LOCK:
|
|
return "locked command";
|
|
case RLV_RET_FAILED_DISABLED:
|
|
return "disabled command";
|
|
case RLV_RET_FAILED_UNKNOWN:
|
|
return "unknown command";
|
|
case RLV_RET_FAILED_NOSHAREDROOT:
|
|
return "missing #RLV";
|
|
case RLV_RET_DEPRECATED:
|
|
return "deprecated";
|
|
// The following are identified by the chat verb
|
|
case RLV_RET_RETAINED:
|
|
case RLV_RET_SUCCESS:
|
|
case RLV_RET_FAILED:
|
|
break;
|
|
// The following shouldn't occur
|
|
case RLV_RET_UNKNOWN:
|
|
default:
|
|
RLV_ASSERT(false);
|
|
break;
|
|
};
|
|
return NULL;
|
|
}
|
|
|
|
// Checked: 2012-02-25 (RLVa-1.4.5) | Modified: RLVa-1.4.5
|
|
std::string RlvStrings::getVersion(bool fLegacy)
|
|
{
|
|
return llformat("%s viewer v%d.%d.%d (RLVa %d.%d.%d)",
|
|
( (!fLegacy) ? "RestrainedLove" : "RestrainedLife" ),
|
|
RLV_VERSION_MAJOR, RLV_VERSION_MINOR, RLV_VERSION_PATCH,
|
|
RLVa_VERSION_MAJOR, RLVa_VERSION_MINOR, RLVa_VERSION_PATCH);
|
|
}
|
|
|
|
// Checked: 2010-04-18 (RLVa-1.4.0a) | Added: RLVa-1.2.0e
|
|
std::string RlvStrings::getVersionAbout()
|
|
{
|
|
return llformat("RLV v%d.%d.%d / RLVa v%d.%d.%d%c" ,
|
|
RLV_VERSION_MAJOR, RLV_VERSION_MINOR, RLV_VERSION_PATCH,
|
|
RLVa_VERSION_MAJOR, RLVa_VERSION_MINOR, RLVa_VERSION_PATCH, 'a' + RLVa_VERSION_BUILD);
|
|
}
|
|
|
|
// Checked: 2010-03-27 (RLVa-1.4.0a) | Modified: RLVa-1.1.0a
|
|
std::string RlvStrings::getVersionNum()
|
|
{
|
|
return llformat("%d%02d%02d%02d", RLV_VERSION_MAJOR, RLV_VERSION_MINOR, RLV_VERSION_PATCH, RLV_VERSION_BUILD);
|
|
}
|
|
|
|
// Checked: 2011-11-08 (RLVa-1.5.0)
|
|
bool RlvStrings::hasString(const std::string& strStringName, bool fCheckCustom)
|
|
{
|
|
string_map_t::const_iterator itString = m_StringMap.find(strStringName);
|
|
return (itString != m_StringMap.end()) && ((!fCheckCustom) || (itString->second.size() > 0));
|
|
}
|
|
|
|
// Checked: 2011-11-08 (RLVa-1.5.0)
|
|
void RlvStrings::setCustomString(const std::string& strStringName, const std::string& strStringValue)
|
|
{
|
|
if (!hasString(strStringName))
|
|
return;
|
|
|
|
std::list<std::string>& listValues = m_StringMap[strStringName];
|
|
while (listValues.size() > 1)
|
|
listValues.pop_back();
|
|
if (!strStringValue.empty())
|
|
listValues.push_back(strStringValue);
|
|
}
|
|
|
|
// ============================================================================
|
|
// RlvUtil
|
|
//
|
|
|
|
bool RlvUtil::m_fForceTp = false;
|
|
|
|
// Checked: 2009-07-04 (RLVa-1.0.0a) | Modified: RLVa-1.0.0a
|
|
void RlvUtil::filterLocation(std::string& strUTF8Text)
|
|
{
|
|
// Filter any mention of the surrounding region names
|
|
LLWorld::region_list_t regions = LLWorld::getInstance()->getRegionList();
|
|
const std::string& strHiddenRegion = RlvStrings::getString(RLV_STRING_HIDDEN_REGION);
|
|
for (LLWorld::region_list_t::const_iterator itRegion = regions.begin(); itRegion != regions.end(); ++itRegion)
|
|
boost::ireplace_all(strUTF8Text, (*itRegion)->getName(), strHiddenRegion);
|
|
|
|
// Filter any mention of the parcel name
|
|
LLViewerParcelMgr* pParcelMgr = LLViewerParcelMgr::getInstance();
|
|
if (pParcelMgr)
|
|
boost::ireplace_all(strUTF8Text, pParcelMgr->getAgentParcelName(), RlvStrings::getString(RLV_STRING_HIDDEN_PARCEL));
|
|
}
|
|
|
|
// Checked: 2010-12-08 (RLVa-1.2.2c) | Modified: RLVa-1.2.2c
|
|
void RlvUtil::filterNames(std::string& strUTF8Text, bool fFilterLegacy)
|
|
{
|
|
uuid_vec_t idAgents;
|
|
LLWorld::getInstance()->getAvatars(&idAgents, NULL);
|
|
for (int idxAgent = 0, cntAgent = idAgents.size(); idxAgent < cntAgent; idxAgent++)
|
|
{
|
|
LLAvatarName avName;
|
|
if (LLAvatarNameCache::get(idAgents[idxAgent], &avName))
|
|
{
|
|
const std::string& strDisplayName = avName.mDisplayName;
|
|
bool fFilterDisplay = (strDisplayName.length() > 2);
|
|
const std::string& strLegacyName = avName.getLegacyName();
|
|
fFilterLegacy &= (strLegacyName.length() > 2);
|
|
const std::string& strAnonym = RlvStrings::getAnonym(avName);
|
|
|
|
// If the display name is a subset of the legacy name we need to filter that first, otherwise it's the other way around
|
|
if (boost::icontains(strLegacyName, strDisplayName))
|
|
{
|
|
if (fFilterLegacy)
|
|
boost::ireplace_all(strUTF8Text, strLegacyName, strAnonym);
|
|
if (fFilterDisplay)
|
|
boost::ireplace_all(strUTF8Text, strDisplayName, strAnonym);
|
|
}
|
|
else
|
|
{
|
|
if (fFilterDisplay)
|
|
boost::ireplace_all(strUTF8Text, strDisplayName, strAnonym);
|
|
if (fFilterLegacy)
|
|
boost::ireplace_all(strUTF8Text, strLegacyName, strAnonym);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Checked: 2012-08-19 (RLVa-1.4.7)
|
|
void RlvUtil::filterScriptQuestions(S32& nQuestions, LLSD& sdPayload)
|
|
{
|
|
// Check SCRIPT_PERMISSION_ATTACH
|
|
if ( (!gRlvAttachmentLocks.canAttach()) && (LSCRIPTRunTimePermissionBits[SCRIPT_PERMISSION_ATTACH] & nQuestions) )
|
|
{
|
|
// Notify the user that we blocked it since they're not allowed to wear any new attachments
|
|
sdPayload["rlv_blocked"] = RLV_STRING_BLOCKED_PERMATTACH;
|
|
nQuestions &= ~LSCRIPTRunTimePermissionBits[SCRIPT_PERMISSION_ATTACH];
|
|
}
|
|
|
|
// Check SCRIPT_PERMISSION_TELEPORT
|
|
if ( (gRlvHandler.hasBehaviour(RLV_BHVR_TPLOC)) && (LSCRIPTRunTimePermissionBits[SCRIPT_PERMISSION_TELEPORT] & nQuestions) )
|
|
{
|
|
// Notify the user that we blocked it since they're not allowed to teleport
|
|
sdPayload["rlv_blocked"] = RLV_STRING_BLOCKED_PERMTELEPORT;
|
|
nQuestions &= ~LSCRIPTRunTimePermissionBits[SCRIPT_PERMISSION_TELEPORT];
|
|
}
|
|
|
|
sdPayload["questions"] = nQuestions;
|
|
}
|
|
|
|
// Checked: 2010-08-29 (RLVa-1.2.1c) | Added: RLVa-1.2.1c
|
|
void RlvUtil::forceTp(const LLVector3d& posDest)
|
|
{
|
|
m_fForceTp = true;
|
|
gAgent.teleportViaLocationLookAt(posDest);
|
|
m_fForceTp = false;
|
|
}
|
|
|
|
// Checked: 2010-04-22 (RLVa-1.2.0f) | Modified: RLVa-1.2.0f
|
|
bool RlvUtil::isNearbyAgent(const LLUUID& idAgent)
|
|
{
|
|
// Sanity check since we call this with notification payloads as well and those strings tend to change from one release to another
|
|
RLV_ASSERT(idAgent.notNull());
|
|
if ( (idAgent.notNull()) && (gAgent.getID() != idAgent) )
|
|
{
|
|
std::vector<LLUUID> idAgents;
|
|
LLWorld::getInstance()->getAvatars(&idAgents, NULL);
|
|
|
|
for (int idxAgent = 0, cntAgent = idAgents.size(); idxAgent < cntAgent; idxAgent++)
|
|
if (idAgents[idxAgent] == idAgent)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Checked: 2010-04-05 (RLVa-1.2.0d) | Modified: RLVa-1.2.0d
|
|
bool RlvUtil::isNearbyRegion(const std::string& strRegion)
|
|
{
|
|
LLWorld::region_list_t regions = LLWorld::getInstance()->getRegionList();
|
|
for (LLWorld::region_list_t::const_iterator itRegion = regions.begin(); itRegion != regions.end(); ++itRegion)
|
|
if ((*itRegion)->getName() == strRegion)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
// Checked: 2011-04-11 (RLVa-1.3.0h) | Modified: RLVa-1.3.0h
|
|
void RlvUtil::notifyBlocked(const std::string& strNotifcation, const LLSD& sdArgs)
|
|
{
|
|
std::string strMsg = RlvStrings::getString(strNotifcation);
|
|
LLStringUtil::format(strMsg, sdArgs);
|
|
|
|
LLSD sdNotify;
|
|
sdNotify["MESSAGE"] = strMsg;
|
|
LLNotificationsUtil::add("SystemMessageTip", sdNotify);
|
|
}
|
|
|
|
// Checked: 2010-11-11 (RLVa-1.2.1g) | Added: RLVa-1.2.1g
|
|
void RlvUtil::notifyFailedAssertion(const std::string& strAssert, const std::string& strFile, int nLine)
|
|
{
|
|
// Don't show the same assertion over and over, or if the user opted out
|
|
static std::string strAssertPrev, strFilePrev; static int nLinePrev;
|
|
if ( ((strAssertPrev == strAssert) && (strFile == strFilePrev) && (nLine == nLinePrev)) ||
|
|
(!rlvGetSetting<bool>(RLV_SETTING_SHOWASSERTIONFAIL, true)) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
strAssertPrev = strAssert;
|
|
strFilePrev = strFile;
|
|
nLinePrev = nLine;
|
|
|
|
LLSD argsNotify;
|
|
argsNotify["MESSAGE"] = llformat("RLVa assertion failure: %s (%s - %d)", strAssert.c_str(), strFile.c_str(), nLine);
|
|
LLNotificationsUtil::add("SystemMessageTip", argsNotify);
|
|
}
|
|
|
|
// Checked: 2010-03-27 (RLVa-1.2.0b) | Modified: RLVa-1.2.0b
|
|
void RlvUtil::sendBusyMessage(const LLUUID& idTo, const std::string& strMsg, const LLUUID& idSession)
|
|
{
|
|
// [See process_improved_im()]
|
|
std::string strFullName;
|
|
LLAgentUI::buildFullname(strFullName);
|
|
|
|
pack_instant_message(gMessageSystem, gAgent.getID(), FALSE, gAgent.getSessionID(), idTo, strFullName,
|
|
strMsg, IM_ONLINE, IM_BUSY_AUTO_RESPONSE, idSession);
|
|
gAgent.sendReliableMessage();
|
|
}
|
|
|
|
// Checked: 2010-03-09 (RLVa-1.2.0a) | Modified: RLVa-1.0.1e
|
|
bool RlvUtil::sendChatReply(S32 nChannel, const std::string& strUTF8Text)
|
|
{
|
|
if (!isValidReplyChannel(nChannel))
|
|
return false;
|
|
|
|
// Copy/paste from send_chat_from_viewer()
|
|
gMessageSystem->newMessageFast(_PREHASH_ChatFromViewer);
|
|
gMessageSystem->nextBlockFast(_PREHASH_AgentData);
|
|
gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
|
|
gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
|
|
gMessageSystem->nextBlockFast(_PREHASH_ChatData);
|
|
gMessageSystem->addStringFast(_PREHASH_Message, utf8str_truncate(strUTF8Text, MAX_MSG_STR_LEN));
|
|
gMessageSystem->addU8Fast(_PREHASH_Type, CHAT_TYPE_SHOUT);
|
|
gMessageSystem->addS32("Channel", nChannel);
|
|
gAgent.sendReliableMessage();
|
|
LLViewerStats::getInstance()->incStat(LLViewerStats::ST_CHAT_COUNT);
|
|
|
|
return true;
|
|
}
|
|
|
|
// ============================================================================
|
|
// Generic menu enablers
|
|
//
|
|
|
|
// Checked: 2010-04-23 (RLVa-1.2.0g) | Modified: RLVa-1.2.0g
|
|
BOOL rlvMenuCheckEnabled(void*)
|
|
{
|
|
return rlv_handler_t::isEnabled();
|
|
}
|
|
|
|
// Checked: 2010-04-23 (RLVa-1.2.0g) | Modified: RLVa-1.2.0g
|
|
void rlvMenuToggleEnabled(void*)
|
|
{
|
|
gSavedSettings.setBOOL(RLV_SETTING_MAIN, !rlv_handler_t::isEnabled());
|
|
|
|
LLSD args;
|
|
args["MESSAGE"] =
|
|
llformat("RestrainedLove Support will be %s after you restart", (rlv_handler_t::isEnabled()) ? "disabled" : "enabled" );
|
|
LLNotificationsUtil::add("GenericAlert", args);
|
|
|
|
return;
|
|
}
|
|
|
|
// Checked: 2011-08-16 (RLVa-1.4.0b) | Added: RLVa-1.4.0b
|
|
void rlvMenuToggleVisible()
|
|
{
|
|
bool fTopLevel = rlvGetSetting(RLV_SETTING_TOPLEVELMENU, true);
|
|
bool fRlvEnabled = rlv_handler_t::isEnabled();
|
|
|
|
//LLMenuGL* pRLVaMenuMain = gMenuBarView->getChildMenuByName("RLVa Main", FALSE);
|
|
// RELEASE-RLVa: LL defines CLIENT_MENU_NAME but we can't get to it from here so we need to keep those two in sync manually
|
|
LLMenuGL* pAdvancedMenu = gMenuBarView->getChildMenuByName("Advanced", FALSE);
|
|
//LLMenuGL* pRLVaMenuEmbed = pAdvancedMenu->getChildMenuByName("RLVa Embedded", FALSE);
|
|
|
|
gMenuBarView->setItemVisible("RLVa Main", (fRlvEnabled) && (fTopLevel));
|
|
if (!pAdvancedMenu) return;
|
|
pAdvancedMenu->setItemVisible("RLVa Embedded", (fRlvEnabled) && (!fTopLevel));
|
|
|
|
/* Singu Note: In the future when we have advanced menu in xml, we will want to use this to move the menu.
|
|
if ( (rlv_handler_t::isEnabled()) && (pRLVaMenuMain) && (pRLVaMenuEmbed) &&
|
|
( ((fTopLevel) && (1 == pRLVaMenuMain->getItemCount())) || ((!fTopLevel) && (1 == pRLVaMenuEmbed->getItemCount())) ) )
|
|
{
|
|
LLMenuGL* pMenuFrom = (fTopLevel) ? pRLVaMenuEmbed : pRLVaMenuMain;
|
|
LLMenuGL* pMenuTo = (fTopLevel) ? pRLVaMenuMain : pRLVaMenuEmbed;
|
|
while (LLMenuItemGL* pItem = pMenuFrom->getItem(1))
|
|
{
|
|
pMenuFrom->removeChild(pItem);
|
|
pMenuTo->addChild(pItem);
|
|
pItem->updateBranchParent(pMenuTo);
|
|
}
|
|
}*/
|
|
}
|
|
|
|
// Checked: 2010-04-23 (RLVa-1.2.0g) | Modified: RLVa-1.2.0g
|
|
bool RlvEnableIfNot::handleEvent(LLPointer<LLEvent>, const LLSD& sdParam)
|
|
{
|
|
bool fEnable = true;
|
|
if (rlv_handler_t::isEnabled())
|
|
{
|
|
ERlvBehaviour eBhvr = RlvCommand::getBehaviourFromString(sdParam["data"].asString());
|
|
fEnable = (eBhvr != RLV_BHVR_UNKNOWN) ? !gRlvHandler.hasBehaviour(eBhvr) : true;
|
|
}
|
|
gMenuHolder->findControl(sdParam["control"].asString())->setValue(fEnable);
|
|
return true;
|
|
}
|
|
|
|
// ============================================================================
|
|
// Selection functors
|
|
//
|
|
|
|
// Checked: 2011-05-28 (RLVa-1.4.6) | Modified: RLVa-1.4.0
|
|
bool rlvCanDeleteOrReturn(const LLViewerObject* pObj)
|
|
{
|
|
// Block if: @rez=n restricted and owned by us or a group *or* @unsit=n restricted and being sat on by us
|
|
return
|
|
( (!gRlvHandler.hasBehaviour(RLV_BHVR_REZ)) || ((!pObj->permYouOwner()) && (!pObj->permGroupOwner())) ) &&
|
|
( (!gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) || (!isAgentAvatarValid()) || (!pObj->getRootEdit()->isChild(gAgentAvatarp)) );
|
|
}
|
|
|
|
// Checked: 2011-05-28 (RLVa-1.4.6) | Modified: RLVa-1.4.0
|
|
bool rlvCanDeleteOrReturn()
|
|
{
|
|
if ( (gRlvHandler.hasBehaviour(RLV_BHVR_REZ)) || (gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) )
|
|
{
|
|
struct RlvCanDeleteOrReturn : public LLSelectedObjectFunctor
|
|
{
|
|
/*virtual*/ bool apply(LLViewerObject* pObj) { return rlvCanDeleteOrReturn(pObj); }
|
|
} f;
|
|
LLObjectSelectionHandle hSel = LLSelectMgr::getInstance()->getSelection();
|
|
return (hSel.notNull()) && (0 != hSel->getRootObjectCount()) && (hSel->applyToRootObjects(&f, false));
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Checked: 2010-04-20 (RLVa-1.2.0f) | Modified: RLVa-0.2.0f
|
|
bool RlvSelectHasLockedAttach::apply(LLSelectNode* pNode)
|
|
{
|
|
return (pNode->getObject()) ? gRlvAttachmentLocks.isLockedAttachment(pNode->getObject()->getRootEdit()) : false;
|
|
}
|
|
|
|
// Checked: 2010-11-29 (RLVa-1.3.0c) | Added: RLVa-1.3.0c
|
|
bool RlvSelectIsEditable::apply(LLSelectNode* pNode)
|
|
{
|
|
const LLViewerObject* pObj = pNode->getObject();
|
|
return (pObj) && (!gRlvHandler.canEdit(pObj));
|
|
}
|
|
|
|
// Checked: 2011-05-28 (RLVa-1.4.0a) | Modified: RLVa-1.4.0a
|
|
bool RlvSelectIsSittingOn::apply(LLSelectNode* pNode)
|
|
{
|
|
return (pNode->getObject()) && (pNode->getObject()->getRootEdit()->isChild(m_pAvatar));
|
|
}
|
|
|
|
// ============================================================================
|
|
// Predicates
|
|
//
|
|
|
|
// Checked: 2010-11-11 (RLVa-1.2.1g) | Modified: RLVa-1.2.1g
|
|
bool rlvPredCanWearItem(const LLViewerInventoryItem* pItem, ERlvWearMask eWearMask)
|
|
{
|
|
if ( (pItem) && (RlvForceWear::isWearableItem(pItem)) )
|
|
{
|
|
if (RlvForceWear::isWearingItem(pItem))
|
|
return true; // Special exception for currently worn items
|
|
switch (pItem->getType())
|
|
{
|
|
case LLAssetType::AT_BODYPART:
|
|
// NOTE: only one body part of each type is allowed so the only way to wear one is if we can replace the current one
|
|
return (RLV_WEAR_LOCKED != (gRlvWearableLocks.canWear(pItem) & RLV_WEAR_REPLACE & eWearMask));
|
|
case LLAssetType::AT_CLOTHING:
|
|
return (RLV_WEAR_LOCKED != (gRlvWearableLocks.canWear(pItem) & eWearMask));
|
|
case LLAssetType::AT_OBJECT:
|
|
return (RLV_WEAR_LOCKED != (gRlvAttachmentLocks.canAttach(pItem) & eWearMask));
|
|
case LLAssetType::AT_GESTURE:
|
|
return true;
|
|
default:
|
|
RLV_ASSERT(false);
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Checked: 2010-03-22 (RLVa-1.2.0c) | Added: RLVa-1.2.0a
|
|
bool rlvPredCanNotWearItem(const LLViewerInventoryItem* pItem, ERlvWearMask eWearMask)
|
|
{
|
|
return !rlvPredCanWearItem(pItem, eWearMask);
|
|
}
|
|
|
|
// Checked: 2010-03-22 (RLVa-1.2.0c) | Added: RLVa-1.2.0a
|
|
bool rlvPredCanRemoveItem(const LLViewerInventoryItem* pItem)
|
|
{
|
|
if ( (pItem) && (RlvForceWear::isWearableItem(pItem)) )
|
|
{
|
|
switch (pItem->getType())
|
|
{
|
|
case LLAssetType::AT_BODYPART:
|
|
case LLAssetType::AT_CLOTHING:
|
|
return gRlvWearableLocks.canRemove(pItem);
|
|
case LLAssetType::AT_OBJECT:
|
|
return gRlvAttachmentLocks.canDetach(pItem);
|
|
case LLAssetType::AT_GESTURE:
|
|
return true;
|
|
default:
|
|
RLV_ASSERT(false);
|
|
}
|
|
}
|
|
// HACK-RLVa: Until LL supports temporary attachment detection assume that no inventory item means a temporary
|
|
// attachment which are always removeable
|
|
return true;
|
|
}
|
|
|
|
// Checked: 2010-03-22 (RLVa-1.2.0c) | Added: RLVa-1.2.0a
|
|
bool rlvPredCanNotRemoveItem(const LLViewerInventoryItem* pItem)
|
|
{
|
|
return !rlvPredCanRemoveItem(pItem);
|
|
}
|
|
|
|
// Checked: 2010-04-24 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
|
|
RlvPredIsEqualOrLinkedItem::RlvPredIsEqualOrLinkedItem(const LLUUID& idItem)
|
|
{
|
|
m_pItem = gInventory.getItem(idItem);
|
|
}
|
|
|
|
// Checked: 2010-04-24 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
|
|
bool RlvPredIsEqualOrLinkedItem::operator()(const LLViewerInventoryItem* pItem) const
|
|
{
|
|
return (m_pItem) && (pItem) && (m_pItem->getLinkedUUID() == pItem->getLinkedUUID());
|
|
}
|
|
|
|
// ============================================================================
|
|
// Various public helper functions
|
|
//
|
|
|
|
// Checked: 2009-11-15 (RLVa-1.1.0c) | Added: RLVa-1.1.0c
|
|
/*
|
|
BOOL rlvEnableSharedWearEnabler(void* pParam)
|
|
{
|
|
return false;
|
|
// Visually disable the "Enable Shared Wear" option when at least one attachment is non-detachable
|
|
return (!gRlvHandler.hasLockedAttachment(RLV_LOCK_REMOVE));
|
|
}
|
|
*/
|
|
|
|
// Checked: 2010-11-01 (RLVa-1.2.2a) | Added: RLVa-1.2.2a
|
|
const std::string& rlvGetAnonym(const LLAvatarName& avName)
|
|
{
|
|
return RlvStrings::getAnonym(avName);
|
|
}
|
|
|
|
// ============================================================================
|