staging avatar inputs for ignore radius

This commit is contained in:
Wayne Chen 2019-02-28 16:51:19 -08:00
parent 087f613d60
commit d382893e75
10 changed files with 232 additions and 9 deletions

View file

@ -211,6 +211,7 @@
#include "ui/UpdateDialog.h"
#include "ui/DomainConnectionModel.h"
#include "ui/Keyboard.h"
#include "ui/PrivacyShield.h"
#include "Util.h"
#include "InterfaceParentFinder.h"
#include "ui/OctreeStatsProvider.h"
@ -927,6 +928,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
DependencyManager::set<KeyboardScriptingInterface>();
DependencyManager::set<GrabManager>();
DependencyManager::set<AvatarPackager>();
DependencyManager::set<PrivacyShield>();
return previousSessionCrashed;
}
@ -2650,6 +2652,9 @@ void Application::cleanupBeforeQuit() {
nodeList->getPacketReceiver().setShouldDropPackets(true);
}
// destroy privacy shield before entity shutdown.
DependencyManager::get<PrivacyShield>()->destroyPrivacyShield();
getEntities()->shutdown(); // tell the entities system we're shutting down, so it will stop running scripts
// Clear any queued processing (I/O, FBX/OBJ/Texture parsing)
@ -2728,6 +2733,7 @@ void Application::cleanupBeforeQuit() {
DependencyManager::destroy<PickManager>();
DependencyManager::destroy<KeyboardScriptingInterface>();
DependencyManager::destroy<Keyboard>();
DependencyManager::destroy<PrivacyShield>();
DependencyManager::destroy<AvatarPackager>();
qCDebug(interfaceapp) << "Application::cleanupBeforeQuit() complete";
@ -5528,6 +5534,8 @@ void Application::resumeAfterLoginDialogActionTaken() {
menu->getMenu("Developer")->setVisible(_developerMenuVisible);
_myCamera.setMode(_previousCameraMode);
cameraModeChanged();
DependencyManager::get<PrivacyShield>()->createPrivacyShield();
}
void Application::loadAvatarScripts(const QVector<QString>& urls) {
@ -6486,6 +6494,8 @@ void Application::update(float deltaTime) {
updateLoginDialogPosition();
}
DependencyManager::get<PrivacyShield>()->update(deltaTime);
{
PROFILE_RANGE_EX(app, "Overlays", 0xffff0000, (uint64_t)getActiveDisplayPlugin()->presentCount());
PerformanceTimer perfTimer("overlays");

View file

@ -38,6 +38,7 @@
#include <UsersScriptingInterface.h>
#include <UUID.h>
#include <shared/ConicalViewFrustum.h>
#include <ui/AvatarInputs.h>
#include "Application.h"
#include "InterfaceLogging.h"
@ -536,6 +537,7 @@ void AvatarManager::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar
avatar->removeAvatarEntitiesFromTree();
if (removalReason == KillAvatarReason::TheirAvatarEnteredYourBubble) {
emit AvatarInputs::getInstance()->avatarEnteredIgnoreRadius(avatar->getSessionUUID());
emit DependencyManager::get<UsersScriptingInterface>()->enteredIgnoreRadius();
} else if (removalReason == KillAvatarReason::AvatarDisconnected) {
// remove from node sets, if present

View file

@ -12,6 +12,7 @@
#include <AudioClient.h>
#include <SettingHandle.h>
#include <trackers/FaceTracker.h>
#include <UsersScriptingInterface.h>
#include "Application.h"
#include "Menu.h"
@ -31,7 +32,9 @@ AvatarInputs* AvatarInputs::getInstance() {
AvatarInputs::AvatarInputs(QObject* parent) : QObject(parent) {
_showAudioTools = showAudioToolsSetting.get();
auto nodeList = DependencyManager::get<NodeList>();
auto usersScriptingInterface = DependencyManager::get<UsersScriptingInterface>();
connect(nodeList.data(), &NodeList::ignoreRadiusEnabledChanged, this, &AvatarInputs::ignoreRadiusEnabledChanged);
connect(usersScriptingInterface.data(), &UsersScriptingInterface::enteredIgnoreRadius, this, &AvatarInputs::enteredIgnoreRadiusChanged);
}
#define AI_UPDATE(name, src) \

View file

@ -43,6 +43,7 @@ class AvatarInputs : public QObject {
Q_PROPERTY(bool showAudioTools READ showAudioTools WRITE setShowAudioTools NOTIFY showAudioToolsChanged)
Q_PROPERTY(bool ignoreRadiusEnabled READ getIgnoreRadiusEnabled NOTIFY ignoreRadiusEnabledChanged)
//Q_PROPERTY(bool enteredIgnoreRadius READ getEnteredIgnoreRadius NOTIFY enteredIgnoreRadiusChanged)
public:
static AvatarInputs* getInstance();
@ -58,6 +59,7 @@ public:
void update();
bool showAudioTools() const { return _showAudioTools; }
bool getIgnoreRadiusEnabled() const;
//bool getEnteredIgnoreRadius() const;
public slots:
@ -95,6 +97,20 @@ signals:
*/
void showAudioToolsChanged(bool show);
/**jsdoc
* @function AvatarInputs.avatarEnteredIgnoreRadius
* @param {QUuid} avatarID
* @returns {Signal}
*/
void avatarEnteredIgnoreRadius(QUuid avatarID);
/**jsdoc
* @function AvatarInputs.avatarLeftIgnoreRadius
* @param {QUuid} avatarID
* @returns {Signal}
*/
void avatarLeftIgnoreRadius(QUuid avatarID);
/**jsdoc
* @function AvatarInputs.ignoreRadiusEnabledChanged
* @param {boolean} enabled
@ -102,6 +118,13 @@ signals:
*/
void ignoreRadiusEnabledChanged(bool enabled);
/**jsdoc
* @function AvatarInputs.enteredIgnoreRadiusChanged
* @param {boolean} enabled
* @returns {Signal}
*/
void enteredIgnoreRadiusChanged();
protected:
/**jsdoc
@ -115,6 +138,8 @@ protected:
Q_INVOKABLE void toggleCameraMute();
private:
void onAvatarEnteredIgnoreRadius();
void onAvatarLeftIgnoreRadius();
float _trailingAudioLoudness{ 0 };
bool _showAudioTools { false };
};

View file

@ -10,3 +10,150 @@
//
#include "PrivacyShield.h"
#include <avatar/AvatarManager.h>
#include <EntityScriptingInterface.h>
#include <SoundCacheScriptingInterface.h>
#include <UserActivityLoggerScriptingInterface.h>
#include <UsersScriptingInterface.h>
#include <AudioInjectorManager.h>
#include "Application.h"
#include "PathUtils.h"
#include "GLMHelpers.h"
const int PRIVACY_SHIELD_VISIBLE_DURATION_MS = 3000;
const int PRIVACY_SHIELD_RAISE_ANIMATION_DURATION_MS = 750;
const int PRIVACY_SHIELD_SOUND_RATE_LIMIT_MS = 15000;
const float PRIVACY_SHIELD_HEIGHT_SCALE = 0.15f;
PrivacyShield::PrivacyShield() {
auto usersScriptingInterface = DependencyManager::get<UsersScriptingInterface>();
//connect(usersScriptingInterface.data(), &UsersScriptingInterface::ignoreRadiusEnabledChanged, [this](bool enabled) {
// onPrivacyShieldToggled(enabled);
//});
//connect(usersScriptingInterface.data(), &UsersScriptingInterface::enteredIgnoreRadius, this, &PrivacyShield::enteredIgnoreRadius);
}
void PrivacyShield::createPrivacyShield() {
// Affects bubble height
auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
auto avatarScale = myAvatar->getTargetScale();
auto avatarSensorToWorldScale = myAvatar->getSensorToWorldScale();
auto avatarWorldPosition = myAvatar->getWorldPosition();
auto avatarWorldOrientation = myAvatar->getWorldOrientation();
EntityItemProperties properties;
properties.setName("Privacy-Shield");
properties.setModelURL(PathUtils::resourcesUrl("assets/models/Bubble-v14.fbx").toString());
properties.setDimensions(glm::vec3(avatarSensorToWorldScale, 0.75 * avatarSensorToWorldScale, avatarSensorToWorldScale));
properties.setPosition(glm::vec3(avatarWorldPosition.x,
-avatarScale * 2 + avatarWorldPosition.y + avatarScale * PRIVACY_SHIELD_HEIGHT_SCALE, avatarWorldPosition.z));
properties.setRotation(avatarWorldOrientation * Quaternions::Y_180);
properties.setModelScale(glm::vec3(2.0, 0.5 * (avatarScale + 1.0), 2.0));
properties.setVisible(false);
_localPrivacyShieldID = DependencyManager::get<EntityScriptingInterface>()->addEntityInternal(properties, entity::HostType::LOCAL);
//_bubbleActivateSound = DependencyManager::get<SoundCache>()->getSound(PathUtils::resourcesUrl() + "assets/sounds/bubble.wav");
//onPrivacyShieldToggled(DependencyManager::get<UsersScriptingInterface>()->getIgnoreRadiusEnabled(), true);
}
void PrivacyShield::destroyPrivacyShield() {
DependencyManager::get<EntityScriptingInterface>()->deleteEntity(_localPrivacyShieldID);
}
void PrivacyShield::update(float deltaTime) {
if (_updateConnected) {
auto now = usecTimestampNow();
auto delay = (now - _privacyShieldTimestamp);
auto privacyShieldAlpha = 1.0 - (delay / PRIVACY_SHIELD_VISIBLE_DURATION_MS);
if (privacyShieldAlpha > 0) {
auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
auto avatarScale = myAvatar->getTargetScale();
auto avatarSensorToWorldScale = myAvatar->getSensorToWorldScale();
auto avatarWorldPosition = myAvatar->getWorldPosition();
auto avatarWorldOrientation = myAvatar->getWorldOrientation();
EntityItemProperties properties;
properties.setDimensions(glm::vec3(avatarSensorToWorldScale, 0.75 * avatarSensorToWorldScale, avatarSensorToWorldScale));
properties.setRotation(avatarWorldOrientation * Quaternions::Y_180);
if (delay < PRIVACY_SHIELD_RAISE_ANIMATION_DURATION_MS) {
properties.setPosition(glm::vec3(avatarWorldPosition.x,
(-((PRIVACY_SHIELD_RAISE_ANIMATION_DURATION_MS - delay) / PRIVACY_SHIELD_RAISE_ANIMATION_DURATION_MS)) * avatarScale * 2.0 +
avatarWorldPosition.y + avatarScale * PRIVACY_SHIELD_HEIGHT_SCALE, avatarWorldPosition.z));
properties.setModelScale(glm::vec3(2.0,
((1 - ((PRIVACY_SHIELD_RAISE_ANIMATION_DURATION_MS - delay) / PRIVACY_SHIELD_RAISE_ANIMATION_DURATION_MS)) *
(0.5 * (avatarScale + 1.0))), 2.0));
} else {
properties.setPosition(glm::vec3(avatarWorldPosition.x, avatarWorldPosition.y + avatarScale * PRIVACY_SHIELD_HEIGHT_SCALE, avatarWorldPosition.z));
properties.setModelScale(glm::vec3(2.0, 0.5 * (avatarScale + 1.0), 2.0));
}
DependencyManager::get<EntityScriptingInterface>()->editEntity(_localPrivacyShieldID, properties);
}
else {
hidePrivacyShield();
if (_updateConnected) {
_updateConnected = false;
}
}
}
}
void PrivacyShield::enteredIgnoreRadius() {
showPrivacyShield();
DependencyManager::get<UserActivityLoggerScriptingInterface>()->privacyShieldActivated();
}
void PrivacyShield::onPrivacyShieldToggled(bool enabled, bool doNotLog) {
if (!doNotLog) {
DependencyManager::get<UserActivityLoggerScriptingInterface>()->privacyShieldToggled(enabled);
}
if (enabled) {
showPrivacyShield();
} else {
hidePrivacyShield();
if (_updateConnected) {
_updateConnected = false;
}
}
}
void PrivacyShield::showPrivacyShield() {
auto now = usecTimestampNow();
auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
auto avatarScale = myAvatar->getTargetScale();
auto avatarSensorToWorldScale = myAvatar->getSensorToWorldScale();
auto avatarWorldPosition = myAvatar->getWorldPosition();
auto avatarWorldOrientation = myAvatar->getWorldOrientation();
if (now - _lastPrivacyShieldSoundTimestamp >= PRIVACY_SHIELD_SOUND_RATE_LIMIT_MS) {
AudioInjectorOptions options;
options.position = avatarWorldPosition;
options.localOnly = true;
options.volume = 0.2f;
AudioInjector::playSoundAndDelete(_bubbleActivateSound, options);
_lastPrivacyShieldSoundTimestamp = now;
}
hidePrivacyShield();
if (_updateConnected) {
_updateConnected = false;
}
EntityItemProperties properties;
properties.setDimensions(glm::vec3(avatarSensorToWorldScale, 0.75 * avatarSensorToWorldScale, avatarSensorToWorldScale));
properties.setPosition(glm::vec3(avatarWorldPosition.x,
-avatarScale * 2 + avatarWorldPosition.y + avatarScale * PRIVACY_SHIELD_HEIGHT_SCALE, avatarWorldPosition.z));
properties.setModelScale(glm::vec3(2.0, 0.5 * (avatarScale + 1.0), 2.0));
properties.setVisible(true);
DependencyManager::get<EntityScriptingInterface>()->editEntity(_localPrivacyShieldID, properties);
_privacyShieldTimestamp = now;
_updateConnected = true;
}
void PrivacyShield::hidePrivacyShield() {
EntityTreePointer entityTree = qApp->getEntities()->getTree();
EntityItemPointer privacyShieldEntity = entityTree->findEntityByEntityItemID(EntityItemID(_localPrivacyShieldID));
if (privacyShieldEntity) {
privacyShieldEntity->setVisible(false);
}
}

View file

@ -10,3 +10,38 @@
//
#pragma once
#include <QtCore/QObject>
#include <QtCore/QUuid>
#include <QtGlobal>
#include <DependencyManager.h>
#include <Sound.h>
class PrivacyShield : public QObject, public Dependency {
Q_OBJECT
SINGLETON_DEPENDENCY
public:
PrivacyShield();
void createPrivacyShield();
void destroyPrivacyShield();
bool isVisible() const { return _visible; }
void update(float deltaTime);
protected slots:
void enteredIgnoreRadius();
void onPrivacyShieldToggled(bool enabled, bool doNotLog = false);
private:
void showPrivacyShield();
void hidePrivacyShield();
SharedSoundPointer _bubbleActivateSound;
QUuid _localPrivacyShieldID;
quint64 _privacyShieldTimestamp;
quint64 _lastPrivacyShieldSoundTimestamp;
bool _visible { false };
bool _updateConnected { false };
};

View file

@ -1477,6 +1477,7 @@ protected:
glm::vec3 _globalBoundingBoxOffset;
AABox _defaultBubbleBox;
AABox _fitBoundingBox;
mutable ReadWriteLockable _avatarEntitiesLock;
AvatarEntityIDs _avatarEntityRemoved; // recently removed AvatarEntity ids

View file

@ -71,12 +71,12 @@ void UserActivityLoggerScriptingInterface::makeUserConnection(QString otherID, b
doLogAction("makeUserConnection", payload);
}
void UserActivityLoggerScriptingInterface::bubbleToggled(bool newValue) {
doLogAction(newValue ? "bubbleOn" : "bubbleOff");
void UserActivityLoggerScriptingInterface::privacyShieldToggled(bool newValue) {
doLogAction(newValue ? "privacyShieldOn" : "privacyShieldOff");
}
void UserActivityLoggerScriptingInterface::bubbleActivated() {
doLogAction("bubbleActivated");
void UserActivityLoggerScriptingInterface::privacyShieldActivated() {
doLogAction("privacyShieldActivated");
}
void UserActivityLoggerScriptingInterface::logAction(QString action, QVariantMap details) {

View file

@ -30,8 +30,8 @@ public:
Q_INVOKABLE void palAction(QString action, QString target);
Q_INVOKABLE void palOpened(float secondsOpen);
Q_INVOKABLE void makeUserConnection(QString otherUser, bool success, QString details = "");
Q_INVOKABLE void bubbleToggled(bool newValue);
Q_INVOKABLE void bubbleActivated();
Q_INVOKABLE void privacyShieldToggled(bool newValue);
Q_INVOKABLE void privacyShieldActivated();
Q_INVOKABLE void logAction(QString action, QVariantMap details = QVariantMap{});
Q_INVOKABLE void commercePurchaseSuccess(QString marketplaceID, QString contentCreator, int cost, bool firstPurchaseOfThisItem);
Q_INVOKABLE void commercePurchaseFailure(QString marketplaceID, QString contentCreator, int cost, bool firstPurchaseOfThisItem, QString errorDetails);

View file

@ -90,7 +90,7 @@
// Called from the C++ scripting interface to show the bubble overlay
function enteredIgnoreRadius() {
createOverlays();
UserActivityLogger.bubbleActivated();
UserActivityLogger.privacyShieldActivated();
}
// Used to set the state of the bubble HUD button
@ -160,7 +160,7 @@
function onBubbleToggled(enabled, doNotLog) {
writeButtonProperties(enabled);
if (doNotLog !== true) {
UserActivityLogger.bubbleToggled(enabled);
UserActivityLogger.privacyShieldToggled(enabled);
}
if (enabled) {
createOverlays();
@ -174,7 +174,7 @@
}
// Setup the bubble button
var buttonName = "BUBBLE";
var buttonName = "SHIELD";
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
button = tablet.addButton({
icon: "icons/tablet-icons/bubble-i.svg",