Added info toast as a reminder that there is a followcam script holding camera controls when trying to use shift+esc to reset camera view.

master
Zi Ree 2022-05-03 15:40:19 +02:00
parent 7c0f0a2dfc
commit fdb2e35f0b
7 changed files with 385 additions and 0 deletions

View File

@ -857,6 +857,7 @@ set(viewer_SOURCE_FILES
llxmlrpctransaction.cpp
noise.cpp
particleeditor.cpp
permissionstracker.cpp
piemenu.cpp
pieseparator.cpp
pieslice.cpp
@ -1630,6 +1631,7 @@ set(viewer_HEADER_FILES
macmain.h
noise.h
particleeditor.h
permissionstracker.h
piemenu.h
pieseparator.h
pieslice.h

View File

@ -29,6 +29,8 @@
#include "llfollowcam.h"
#include "llagent.h"
#include "permissionstracker.h"
//-------------------------------------------------------
// constants
//-------------------------------------------------------
@ -829,11 +831,13 @@ void LLFollowCamMgr::setCameraActive( const LLUUID& source, bool active )
if (found_it != mParamStack.end())
{
mParamStack.erase(found_it);
PermissionsTracker::instance().removePermissionsEntry(source, PermissionsTracker::PERM_FOLLOWCAM);
}
// put on top of stack
if(active)
{
mParamStack.push_back(params);
PermissionsTracker::instance().addPermissionsEntry(source, PermissionsTracker::PERM_FOLLOWCAM);
}
}
@ -843,6 +847,8 @@ void LLFollowCamMgr::removeFollowCamParams(const LLUUID& source)
LLFollowCamParams* params = getParamsForID(source);
mParamMap.erase(source);
delete params;
PermissionsTracker::instance().removePermissionsEntry(source, PermissionsTracker::PERM_FOLLOWCAM);
}
bool LLFollowCamMgr::isScriptedCameraSource(const LLUUID& source)

View File

@ -166,6 +166,7 @@
#include "lltexturecache.h"
#include "llvovolume.h"
#include "particleeditor.h"
#include "permissionstracker.h"
using namespace LLAvatarAppearanceDefines;
@ -5424,6 +5425,9 @@ void handle_reset_camera_angles()
// Camera focus and offset with CTRL/SHIFT + Scroll wheel
gSavedSettings.getControl("FocusOffsetRearView")->resetToDefault();
gSavedSettings.getControl("CameraOffsetRearView")->resetToDefault();
// warn the user if there is a scripted followcam active that might stop a camera reset
PermissionsTracker::instance().warnFollowcam();
}
// </FS:Zi>

View File

@ -150,6 +150,7 @@
#include "llfloaterbump.h"
#include "llfloaterreg.h"
#include "llfriendcard.h"
#include "permissionstracker.h" // <FS:Zi> Permissions Tracker
#include "tea.h" // <FS:AW opensim currency support>
#include "NACLantispam.h"
#include "chatbar_as_cmdline.h"
@ -4733,6 +4734,8 @@ void process_object_properties(LLMessageSystem *msg, void**user_data)
{
explorer->requestNameCallback(msg);
}
PermissionsTracker::instance().objectPropertiesCallback(msg);
}
// </FS:Techwolf Lupindo> area search

View File

@ -0,0 +1,274 @@
/**
* @file permissionstracker.cpp
* @brief Permissions Tracker implementation - Initially it's only tracking
* camera control permissions, to warn users about attachments or seats that
* took camera control permissions and might interfere with resetting the
* camera view.
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
* Copyright (C) 2022, Zi Ree @ Second Life
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "llviewerprecompiledheaders.h"
#include "llagentdata.h" // for gAgentID anf gAgentSessionID
#include "llnotificationsutil.h"
#include "llslurl.h"
#include "lltrans.h"
#include "llviewermenu.h" // for handle_object_edit()
#include "llviewerregion.h"
#include "llviewerobject.h"
#include "llviewerobjectlist.h" // for gObjectList
#include "llvoavatarself.h" // for gAgentAvatarp
#include "llworld.h"
#include "permissionstracker.h"
#define PERMISSION_ENTRY_EXPIRY_TIME 3600.0
PermissionsTracker::PermissionsTracker()
: LLSingleton<PermissionsTracker>()
{
}
PermissionsTracker::~PermissionsTracker()
{
}
void PermissionsTracker::addPermissionsEntry(const LLUUID& source_id, PermissionsTracker::PERM_TYPE permission_type)
{
// find out if this is a new entry in the list
if (mPermissionsList.find(source_id) == mPermissionsList.end())
{
LL_DEBUGS("PermissionsTracker") << "Creating list entry for source " << source_id << LL_ENDL;
mPermissionsList[source_id].objectName = LLTrans::getString("LoadingData");
// find out if the object is still in reach
LLViewerObject* vo = gObjectList.findObject(source_id);
if (!vo)
{
mPermissionsList[source_id].objectName = LLTrans::getString("ObjectOutOfRange");
}
else
{
mPermissionsList[source_id].attachmentID = vo->getAttachmentItemID();
LL_DEBUGS("PermissionsTracker") << "Requesting ObjectProperties for source " << source_id << LL_ENDL;
// remember which object names we already requested
mRequestedIDs.push_back(source_id);
// send a request out to get this object's details
LLMessageSystem* msg = gMessageSystem;
msg->newMessageFast(_PREHASH_ObjectSelect);
msg->nextBlockFast(_PREHASH_AgentData);
msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
msg->nextBlockFast(_PREHASH_ObjectData);
msg->addU32Fast(_PREHASH_ObjectLocalID, vo->getLocalID());
msg->sendReliable(gAgentAvatarp->getRegion()->getHost());
msg->newMessageFast(_PREHASH_ObjectDeselect);
msg->nextBlockFast(_PREHASH_AgentData);
msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
msg->nextBlockFast(_PREHASH_ObjectData);
msg->addU32Fast(_PREHASH_ObjectLocalID, vo->getLocalID());
msg->sendReliable(gAgentAvatarp->getRegion()->getHost());
}
}
LL_DEBUGS("PermissionsTracker") << "Adding permission type " << permission_type << " to source " << source_id << LL_ENDL;
mPermissionsList[source_id].type |= permission_type;
mPermissionsList[source_id].time = LLDate(LLTimer::getTotalSeconds());
purgePermissionsEntries();
}
void PermissionsTracker::removePermissionsEntry(const LLUUID& source_id, PermissionsTracker::PERM_TYPE permission_type)
{
if (mPermissionsList.find(source_id) == mPermissionsList.end())
{
LL_DEBUGS("PermissionsTracker") << "Could not find list entry for source " << source_id << LL_ENDL;
return;
}
LL_DEBUGS("PermissionsTracker") << "Removing permissions type " << permission_type << " from source " << source_id << LL_ENDL;
mPermissionsList[source_id].type &= ~permission_type;
mPermissionsList[source_id].time = LLDate(LLTimer::getTotalSeconds());
purgePermissionsEntries();
}
void PermissionsTracker::purgePermissionsEntries()
{
F64 expiry_time = LLDate(LLTimer::getTotalSeconds()).secondsSinceEpoch() - PERMISSION_ENTRY_EXPIRY_TIME;
auto it = mPermissionsList.begin();
while (it != mPermissionsList.end())
{
if (it->second.type == PERM_TYPE::PERM_NONE && it->second.time.secondsSinceEpoch() < expiry_time)
{
LL_DEBUGS("PermissionsTracker") << "Erasing list entry for source " << it->first << LL_ENDL;
it = mPermissionsList.erase(it);
}
else
{
++it;
}
}
}
void PermissionsTracker::warnFollowcam()
{
std::string followcamList;
for (auto entry : mPermissionsList)
{
if (entry.second.type & PermissionsTracker::PERM_FOLLOWCAM)
{
if (entry.second.attachmentID.notNull())
{
std::string attachment_point = "???";
gAgentAvatarp->getAttachedPointName(entry.second.attachmentID, attachment_point);
LLSD args;
args["ATTACHMENT_POINT"] = attachment_point;
std::string verb = "select?name=" + LLURI::escape(entry.second.objectName);
followcamList += LLSLURL("inventory", entry.second.attachmentID, verb.c_str()).getSLURLString() + " " +
LLTrans::getString("WornOnAttachmentPoint", args) + "\n";
}
else
{
followcamList += LLSLURL("objectim", entry.first, "").getSLURLString() +
"?name=" + LLURI::escape(entry.second.objectName) +
"&owner=" + entry.second.ownerID.asString();
LLSD args;
std::string slurl = args["slurl"].asString();
if (slurl.empty())
{
LLViewerRegion* region = LLWorld::instance().getRegionFromPosAgent(gAgentAvatarp->getPositionAgent());
if(region)
{
LLSLURL region_slurl(region->getName(), gAgentAvatarp->getPositionAgent());
slurl = region_slurl.getLocationString();
}
}
followcamList += "&slurl=" + LLURI::escape(slurl) + "\n";
}
}
}
if (followcamList.empty())
{
return;
}
LLSD args;
args["SOURCES"] = followcamList;
LLNotificationsUtil::add("WarnScriptedCamera", args);
}
void PermissionsTracker::objectPropertiesCallback(LLMessageSystem* msg)
{
LL_DEBUGS("PermissionsTracker") << "Received ObjectProperties message." << LL_ENDL;
// if we weren't looking for any IDs, ignore this callback
if (mRequestedIDs.empty())
{
LL_DEBUGS("PermissionsTracker") << "No objects in request list." << LL_ENDL;
return;
}
// we might have received more than one answer in one block
S32 num = msg->getNumberOfBlocksFast(_PREHASH_ObjectData);
for (S32 index = 0; index < num; ++index)
{
LLUUID source_id;
msg->getUUIDFast(_PREHASH_ObjectData, _PREHASH_ObjectID, source_id, index);
auto iter = std::find(mRequestedIDs.begin(), mRequestedIDs.end(), source_id);
// if this is one of the objects we were looking for, process the data
if (iter != mRequestedIDs.end())
{
// get the name of the object
std::string object_name;
msg->getStringFast(_PREHASH_ObjectData, _PREHASH_Name, object_name, index);
LLUUID object_owner;
msg->getUUIDFast(_PREHASH_ObjectData, _PREHASH_OwnerID, object_owner, index);
LL_DEBUGS("PermissionsTracker") << "Received object name " << object_name
<< " and owner " << object_owner.asString() << " for source " << source_id << LL_ENDL;
// remove the object from the lookup list and add it to the known names list
mRequestedIDs.erase(iter);
mPermissionsList[source_id].objectName = object_name;
mPermissionsList[source_id].ownerID = object_owner;
LLAvatarName avatar_name;
if (LLAvatarNameCache::get(object_owner, &avatar_name))
{
LL_DEBUGS("PermissionsTracker") << "Found cached entry for owner " << object_owner.asString()
<< ": " << avatar_name.getCompleteName() << LL_ENDL;
mPermissionsList[source_id].ownerName = avatar_name.getCompleteName();
}
else
{
if (mAvatarNameCacheConnections.find(object_owner) != mAvatarNameCacheConnections.end())
{
boost::signals2::connection cb_connection = LLAvatarNameCache::get(object_owner, boost::bind(&PermissionsTracker::avatarNameCallback, this, _1, _2));
mAvatarNameCacheConnections.insert(std::make_pair(object_owner, cb_connection));
LL_DEBUGS("PermissionsTracker") << "Requesting avatar name for owner " << object_owner.asString() << LL_ENDL;
}
}
}
}
}
void PermissionsTracker::avatarNameCallback(const LLUUID& avatar_id, const LLAvatarName& avatar_name)
{
LL_DEBUGS("PermissionsTracker") << "Received avatar name " << avatar_name.getCompleteName() << LL_ENDL;
auto iter = mAvatarNameCacheConnections.find(avatar_id);
if (iter != mAvatarNameCacheConnections.end())
{
if (iter->second.connected())
{
iter->second.disconnect();
}
mAvatarNameCacheConnections.erase(iter);
}
for (auto entry : mPermissionsList)
{
if (entry.second.ownerID == avatar_id)
{
LL_DEBUGS("PermissionsTracker") << "Saved avatar name " << avatar_name.getCompleteName()<< " for source " << entry.first.asString() << LL_ENDL;
entry.second.ownerName = avatar_name.getCompleteName();
}
}
}

View File

@ -0,0 +1,86 @@
/**
* @file permissionstracker.h
* @brief Permissions Tracker declaration
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
* Copyright (C) 2022, Zi Ree @ Second Life
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef PERMISSIONSTRACKER_H
#define PERMISSIONSTRACKER_H
#include "llfloater.h"
#include "llsingleton.h"
// --------------------------------------------------------------------------
// PermissionsTracker: holds a list of requested script permissions to be
// referred to e.g. when trying to reset the camera view and a script is
// holding a follow cam which micht prevent it from working.
// --------------------------------------------------------------------------
class PermissionsTracker
: public LLSingleton<PermissionsTracker>
{
LLSINGLETON(PermissionsTracker);
~PermissionsTracker();
public:
enum PERM_TYPE
{
PERM_NONE = 0,
PERM_FOLLOWCAM = 1,
};
struct PermissionsEntry
{
LLUUID ownerID; // agent who owns the requesting object
LLUUID attachmentID; // attachment ID in inventory for attached objects
std::string ownerName;
std::string objectName;
LLDate time; // time when the permission was granted
U32 type; // what kind of permissions were granted
};
std::map<LLUUID, PermissionsEntry> mPermissionsList; // UUID of the requesting object
void addPermissionsEntry(
const LLUUID& source_id,
PermissionsTracker::PERM_TYPE permission_type); // called in llviewermessage.cpp
void removePermissionsEntry(
const LLUUID& source_id,
PermissionsTracker::PERM_TYPE permission_type); // called in llviewermessage.cpp
void purgePermissionsEntries();
void objectPropertiesCallback(LLMessageSystem* msg);
void avatarNameCallback(const LLUUID& avatar_id, const LLAvatarName& av_name);
void warnFollowcam(); // Warn the user if a script is holding followcam parameters
std::vector<LLUUID> mRequestedIDs; // list of object IDs we requested named for
typedef std::map<LLUUID, boost::signals2::connection> avatar_name_cache_connection_map_t;
avatar_name_cache_connection_map_t mAvatarNameCacheConnections;
};
#endif // PERMISSIONSTRACKER_H

View File

@ -13790,4 +13790,14 @@ Reset the URL to default?
notext="Remind me next time"
yestext="Reset"/>
</notification>
<notification
icon="notifytip.tga"
name="WarnScriptedCamera"
type="notifytip">
Camera reset might be inhibited by the following objects:
[SOURCES]
</notification>
</notifications>