mirror of
https://github.com/overte-org/overte.git
synced 2025-04-08 05:52:38 +02:00
staging avatar inputs for ignore radius
This commit is contained in:
parent
087f613d60
commit
d382893e75
10 changed files with 232 additions and 9 deletions
|
@ -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");
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) \
|
||||
|
|
|
@ -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 };
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 };
|
||||
};
|
||||
|
|
|
@ -1477,6 +1477,7 @@ protected:
|
|||
glm::vec3 _globalBoundingBoxOffset;
|
||||
|
||||
AABox _defaultBubbleBox;
|
||||
AABox _fitBoundingBox;
|
||||
|
||||
mutable ReadWriteLockable _avatarEntitiesLock;
|
||||
AvatarEntityIDs _avatarEntityRemoved; // recently removed AvatarEntity ids
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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",
|
||||
|
|
Loading…
Reference in a new issue