From 8940db0e19cda4b70ccd151e849e392c97485fb0 Mon Sep 17 00:00:00 2001 From: Kitty Barnett Date: Sun, 17 Jun 2018 13:46:52 +0200 Subject: [PATCH] Experiences shouldn't have limitless access to RLVa by default --HG-- branch : RLVa --- indra/newview/rlvcommon.cpp | 2 + indra/newview/rlvdefines.h | 1 + indra/newview/rlvhandler.cpp | 137 ++++++++++++++++++++++++++++++++++- indra/newview/rlvhandler.h | 19 +++++ 4 files changed, 157 insertions(+), 2 deletions(-) diff --git a/indra/newview/rlvcommon.cpp b/indra/newview/rlvcommon.cpp index 130e4e7931..a4eddc5aeb 100644 --- a/indra/newview/rlvcommon.cpp +++ b/indra/newview/rlvcommon.cpp @@ -374,6 +374,8 @@ const char* RlvStrings::getStringFromReturnCode(ERlvCmdRet eRet) return "deprecated and disabled"; case RLV_RET_FAILED_NOBEHAVIOUR: return "no active behaviours"; + case RLV_RET_FAILED_BLOCKED: + return "blocked object"; // The following are identified by the chat verb case RLV_RET_RETAINED: case RLV_RET_SUCCESS: diff --git a/indra/newview/rlvdefines.h b/indra/newview/rlvdefines.h index 056e0303de..be07ab78e7 100644 --- a/indra/newview/rlvdefines.h +++ b/indra/newview/rlvdefines.h @@ -311,6 +311,7 @@ enum ERlvCmdRet { RLV_RET_FAILED_NOSHAREDROOT, // Command failed (missing #RLV) RLV_RET_FAILED_DEPRECATED, // Command failed (deprecated and no longer supported) RLV_RET_FAILED_NOBEHAVIOUR, // Command failed (force modifier on an object with no active restrictions) + RLV_RET_FAILED_BLOCKED, // Command failed (object is blocked) RLV_RET_NO_PROCESSOR // Command doesn't have a template processor define (legacy code) }; #define RLV_RET_SUCCEEDED(eCmdRet) (((eCmdRet) & RLV_RET_SUCCESS) == RLV_RET_SUCCESS) diff --git a/indra/newview/rlvhandler.cpp b/indra/newview/rlvhandler.cpp index 6fcc808666..88beb6a00f 100644 --- a/indra/newview/rlvhandler.cpp +++ b/indra/newview/rlvhandler.cpp @@ -19,6 +19,8 @@ #include "llagent.h" #include "llappearancemgr.h" #include "llappviewer.h" +#include "llexperiencecache.h" +#include "llexperiencelog.h" #include "llgroupactions.h" #include "llhudtext.h" #include "llmoveview.h" @@ -259,6 +261,78 @@ void RlvHandler::removeException(const LLUUID& idObj, ERlvBehaviour eBhvr, const } } +// ============================================================================ +// Blocked object handling +// + +void RlvHandler::addBlockedObject(const LLUUID& idObj, const std::string& strName) +{ + m_BlockedObjects.push_back(std::make_tuple(idObj, strName, LLTimer::getTotalSeconds())); +} + +bool RlvHandler::hasUnresolvedBlockedObject() const +{ + return std::any_of(m_BlockedObjects.begin(), m_BlockedObjects.end(), [](const rlv_blocked_object_t& entry) { return std::get<0>(entry).isNull(); }); +} + +bool RlvHandler::isBlockedObject(const LLUUID& idObj) const +{ + return std::any_of(m_BlockedObjects.begin(), m_BlockedObjects.end(), [&idObj](const rlv_blocked_object_t& entry) { return std::get<0>(entry) == idObj; }); +} + +void RlvHandler::removeBlockedObject(const LLUUID& idObj) +{ + m_BlockedObjects.erase(std::remove_if(m_BlockedObjects.begin(), m_BlockedObjects.end(), + [&idObj](const rlv_blocked_object_t& entry) { + return (idObj.notNull()) ? std::get<0>(entry) == idObj : false; + }), m_BlockedObjects.end()); +} + +void RlvHandler::getAttachmentResourcesCoro(const std::string& strUrl) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("RlvHandler::getAttachmentResourcesCoro", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + const LLSD sdResult = httpAdapter->getAndSuspend(httpRequest, strUrl); + + const LLCore::HttpStatus httpStatus = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(sdResult[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]); + if ( (httpStatus) && (sdResult.has("attachments")) ) + { + const LLSD& sdAttachments = sdResult["attachments"]; + for (auto& itAttach = sdAttachments.beginArray(), endAttach = sdAttachments.endArray(); itAttach != endAttach; ++itAttach) + { + if (!itAttach->has("objects")) + continue; + + const LLSD& sdAttachObjects = itAttach->get("objects"); + for (auto& itAttachObj = sdAttachObjects.beginArray(), endAttachObj = sdAttachObjects.endArray(); itAttachObj != endAttachObj; ++itAttachObj) + { + const LLUUID idObj = itAttachObj->get("id").asUUID(); + const std::string& strObjName = itAttachObj->get("name").asStringRef(); + + // If it's an attachment, it should be a temporary one (NOTE: we might catch it before it's had a chance to attach) + const LLViewerObject* pObj = gObjectList.findObject(idObj); + if ( (pObj) && ((!pObj->isAttachment()) || (!pObj->isTempAttachment()) || (isBlockedObject(idObj))) ) + continue; + + // Find it by object name + auto itBlockedObj = std::find_if(m_BlockedObjects.begin(), m_BlockedObjects.end(), + [&strObjName](const rlv_blocked_object_t& entry) { + return (std::get<0>(entry).isNull()) && (std::get<1>(entry) == strObjName); + }); + if (m_BlockedObjects.end() != itBlockedObj) + { + std::get<0>(*itBlockedObj) = idObj; + + RLV_INFOS << "Clearing restrictions from blocked object " << idObj.asString() << RLV_ENDL; + processCommand(idObj, "clear", true); + return; + } + } + } + } +} + // ============================================================================ // Command processing functions // @@ -309,6 +383,11 @@ ERlvCmdRet RlvHandler::processCommand(const RlvCommand& rlvCmd, bool fFromObj) { RLV_DEBUGS << "[" << rlvCmd.getObjectID() << "]: " << rlvCmd.asString() << RLV_ENDL; + if ( (isBlockedObject(rlvCmd.getObjectID())) && (RLV_TYPE_REMOVE != rlvCmd.getParamType()) && (RLV_TYPE_CLEAR != rlvCmd.getParamType()) ) + { + RLV_DEBUGS << "\t-> blocked object" << RLV_ENDL; + return RLV_RET_FAILED_BLOCKED; + } if (!rlvCmd.isValid()) { RLV_DEBUGS << "\t-> invalid syntax" << RLV_ENDL; @@ -794,6 +873,42 @@ void RlvHandler::onDetach(const LLViewerObject* pAttachObj, const LLViewerJointA RLV_INFOS << "\t-> done" << RLV_ENDL; } } + + if (pAttachObj->isTempAttachment()) + { + removeBlockedObject(pAttachObj->getID()); + } + } +} + +void RlvHandler::onExperienceAttach(const LLSD& sdExperience, const std::string& strObjName) +{ + if (sdExperience["maturity"].asInteger() != SIM_ACCESS_ADULT) + { + addBlockedObject(LLUUID::null, strObjName); + + const std::string strUrl = gAgent.getRegionCapability("AttachmentResources"); + if (!strUrl.empty()) + { + LLCoros::instance().launch("RlvHandler::getAttachmentResourcesCoro", boost::bind(&RlvHandler::getAttachmentResourcesCoro, this, strUrl)); + } + } +} + +void RlvHandler::onExperienceEvent(const LLSD& sdEvent) +{ + const int nPermission = sdEvent["Permission"].asInteger(); + switch (nPermission) + { + case 4: // Attach + { + const LLUUID& idExperience = sdEvent["public_id"].asUUID(); + const std::string strObjName = sdEvent["ObjectName"].asString(); + LLExperienceCache::instance().get(idExperience, boost::bind(&RlvHandler::onExperienceAttach, this, _1, strObjName)); + } + break; + default: + break; } } @@ -848,6 +963,23 @@ bool RlvHandler::onGC() RLV_ASSERT(gRlvAttachmentLocks.verifyAttachmentLocks()); // Verify that we haven't leaked any attachment locks somehow + // Clean up pending temp attachments that we were never able to resolve + rlv_blocked_object_list_t::const_iterator itBlocked = m_BlockedObjects.cbegin(), itCurBlocked; + while (itBlocked != m_BlockedObjects.end()) + { + itCurBlocked = itBlocked++; +#ifdef RLV_DEBUG + bool itBlocked = true; + RLV_ASSERT(itBlocked); +#endif // RLV_DEBUG + + const LLUUID& idObj = std::get<0>(*itCurBlocked); + if ( (idObj.notNull()) || (LLTimer::getTotalSeconds() - std::get<2>(*itCurBlocked) < 300.f) ) + continue; + + m_BlockedObjects.erase(itCurBlocked); + } + return (0 != m_Objects.size()); // GC will kill itself if it has nothing to do } @@ -881,8 +1013,9 @@ void RlvHandler::onLoginComplete() RlvInventory::instance().fetchSharedInventory(); RlvSettings::updateLoginLastLocation(); - LLViewerParcelMgr::getInstance()->setTeleportFailedCallback(boost::bind(&RlvHandler::onTeleportFailed, this)); - LLViewerParcelMgr::getInstance()->setTeleportFinishedCallback(boost::bind(&RlvHandler::onTeleportFinished, this, _1)); + m_ExperienceEventConn = LLExperienceLog::instance().addUpdateSignal(boost::bind(&RlvHandler::onExperienceEvent, this, _1)); + m_TeleportFailedConn = LLViewerParcelMgr::getInstance()->setTeleportFailedCallback(boost::bind(&RlvHandler::onTeleportFailed, this)); + m_TeleportFinishedConn = LLViewerParcelMgr::getInstance()->setTeleportFinishedCallback(boost::bind(&RlvHandler::onTeleportFinished, this, _1)); processRetainedCommands(); } diff --git a/indra/newview/rlvhandler.h b/indra/newview/rlvhandler.h index 7c48d0c276..0601cf1977 100644 --- a/indra/newview/rlvhandler.h +++ b/indra/newview/rlvhandler.h @@ -96,6 +96,16 @@ public: bool isHiddenCompositeItem(const LLUUID& idItem, const std::string& strItemType) const; #endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS +public: + // Adds a blocked object (= object that is blocked from issuing commands) by UUID (can be null) and/or name + void addBlockedObject(const LLUUID& idObj, const std::string& strObjName); + // Returns TRUE if there's an unresolved blocked object (known name but unknown UUID) + bool hasUnresolvedBlockedObject() const; + // Returns TRUE if the object with the specified UUID is blocked from issuing commands + bool isBlockedObject(const LLUUID& idObj) const; + // Removes a blocked object + void removeBlockedObject(const LLUUID& idObj); + // -------------------------------- /* @@ -163,6 +173,8 @@ public: void onActiveGroupChanged(); void onAttach(const LLViewerObject* pAttachObj, const LLViewerJointAttachment* pAttachPt); void onDetach(const LLViewerObject* pAttachObj, const LLViewerJointAttachment* pAttachPt); + void onExperienceAttach(const LLSD& sdExperience, const std::string& strObjName); + void onExperienceEvent(const LLSD& sdEvent); bool onGC(); void onLoginComplete(); void onSitOrStand(bool fSitting); @@ -170,6 +182,7 @@ public: void onTeleportFinished(const LLVector3d& posArrival); static void onIdleStartup(void* pParam); protected: + void getAttachmentResourcesCoro(const std::string& strUrl); void onTeleportCallback(U64 hRegion, const LLVector3& posRegion, const LLVector3& vecLookAt, const LLUUID& idRlvObj); /* @@ -214,9 +227,12 @@ protected: */ public: typedef std::map rlv_object_map_t; + typedef std::tuple rlv_blocked_object_t; + typedef std::list rlv_blocked_object_list_t; typedef std::multimap rlv_exception_map_t; protected: rlv_object_map_t m_Objects; // Map of objects that have active restrictions (idObj -> RlvObject) + rlv_blocked_object_list_t m_BlockedObjects; // List of (attached) objects that can't issue commands rlv_exception_map_t m_Exceptions; // Map of currently active restriction exceptions (ERlvBehaviour -> RlvException) S16 m_Behaviours[RLV_BHVR_COUNT]; @@ -230,6 +246,9 @@ protected: rlv_behaviour_signal_t m_OnBehaviourToggle; rlv_command_signal_t m_OnCommand; mutable std::list m_CommandHandlers; + boost::signals2::scoped_connection m_ExperienceEventConn; + boost::signals2::scoped_connection m_TeleportFailedConn; + boost::signals2::scoped_connection m_TeleportFinishedConn; static bool m_fEnabled; // Use setEnabled() to toggle this