mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-04-07 10:02:24 +02:00
Merge pull request #12191 from druiz17/entity-attachment-bookmark
Bookmark avatar entities
This commit is contained in:
commit
264aa7f4d2
7 changed files with 260 additions and 0 deletions
|
@ -68,6 +68,7 @@
|
|||
#include <Midi.h>
|
||||
#include <AudioInjectorManager.h>
|
||||
#include <AvatarBookmarks.h>
|
||||
#include <AvatarEntitiesBookmarks.h>
|
||||
#include <CursorManager.h>
|
||||
#include <DebugDraw.h>
|
||||
#include <DeferredLightingEffect.h>
|
||||
|
@ -763,6 +764,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
|
|||
DependencyManager::set<GooglePolyScriptingInterface>();
|
||||
DependencyManager::set<OctreeStatsProvider>(nullptr, qApp->getOcteeSceneStats());
|
||||
DependencyManager::set<AvatarBookmarks>();
|
||||
DependencyManager::set<AvatarEntitiesBookmarks>();
|
||||
DependencyManager::set<LocationBookmarks>();
|
||||
DependencyManager::set<Snapshot>();
|
||||
DependencyManager::set<CloseEventSender>();
|
||||
|
@ -2443,6 +2445,7 @@ void Application::initializeUi() {
|
|||
surfaceContext->setContextProperty("Settings", SettingsScriptingInterface::getInstance());
|
||||
surfaceContext->setContextProperty("ScriptDiscoveryService", DependencyManager::get<ScriptEngines>().data());
|
||||
surfaceContext->setContextProperty("AvatarBookmarks", DependencyManager::get<AvatarBookmarks>().data());
|
||||
surfaceContext->setContextProperty("AvatarEntitiesBookmarks", DependencyManager::get<AvatarEntitiesBookmarks>().data());
|
||||
surfaceContext->setContextProperty("LocationBookmarks", DependencyManager::get<LocationBookmarks>().data());
|
||||
|
||||
// Caches
|
||||
|
@ -5851,6 +5854,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe
|
|||
scriptEngine->registerGlobalObject("AudioStats", DependencyManager::get<AudioClient>()->getStats().data());
|
||||
scriptEngine->registerGlobalObject("AudioScope", DependencyManager::get<AudioScope>().data());
|
||||
scriptEngine->registerGlobalObject("AvatarBookmarks", DependencyManager::get<AvatarBookmarks>().data());
|
||||
scriptEngine->registerGlobalObject("AvatarEntitiesBookmarks", DependencyManager::get<AvatarEntitiesBookmarks>().data());
|
||||
scriptEngine->registerGlobalObject("LocationBookmarks", DependencyManager::get<LocationBookmarks>().data());
|
||||
|
||||
scriptEngine->registerGlobalObject("RayPick", DependencyManager::get<RayPickScriptingInterface>().data());
|
||||
|
|
168
interface/src/AvatarEntitiesBookmarks.cpp
Normal file
168
interface/src/AvatarEntitiesBookmarks.cpp
Normal file
|
@ -0,0 +1,168 @@
|
|||
//
|
||||
// AvatarEntitiesBookmarks.cpp
|
||||
// interface/src
|
||||
//
|
||||
// Created by Dante Ruiz on 15/01/18.
|
||||
// Copyright 2018 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <QAction>
|
||||
#include <QInputDialog>
|
||||
#include <QMessageBox>
|
||||
#include <QStandardPaths>
|
||||
#include <QQmlContext>
|
||||
#include <QList>
|
||||
|
||||
#include <Application.h>
|
||||
#include <OffscreenUi.h>
|
||||
#include <EntityItemProperties.h>
|
||||
#include <GLMHelpers.h>
|
||||
#include <avatar/AvatarManager.h>
|
||||
#include <EntityItemID.h>
|
||||
#include <EntityTree.h>
|
||||
#include <PhysicalEntitySimulation.h>
|
||||
#include <EntityEditPacketSender.h>
|
||||
#include <VariantMapToScriptValue.h>
|
||||
|
||||
#include "MainWindow.h"
|
||||
#include "Menu.h"
|
||||
#include "AvatarEntitiesBookmarks.h"
|
||||
#include "InterfaceLogging.h"
|
||||
|
||||
#include "QVariantGLM.h"
|
||||
|
||||
#include <QtQuick/QQuickWindow>
|
||||
|
||||
void addAvatarEntities(const QVariantList& avatarEntities) {
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
const QUuid myNodeID = nodeList->getSessionUUID();
|
||||
EntityTreePointer entityTree = DependencyManager::get<EntityTreeRenderer>()->getTree();
|
||||
if (!entityTree) {
|
||||
return;
|
||||
}
|
||||
EntitySimulationPointer entitySimulation = entityTree->getSimulation();
|
||||
PhysicalEntitySimulationPointer physicalEntitySimulation = std::static_pointer_cast<PhysicalEntitySimulation>(entitySimulation);
|
||||
EntityEditPacketSender* entityPacketSender = physicalEntitySimulation->getPacketSender();
|
||||
QScriptEngine scriptEngine;
|
||||
for (int index = 0; index < avatarEntities.count(); index++) {
|
||||
const QVariantMap& avatarEntityProperties = avatarEntities.at(index).toMap();
|
||||
QVariant variantProperties = avatarEntityProperties["properties"];
|
||||
QVariantMap asMap = variantProperties.toMap();
|
||||
QScriptValue scriptProperties = variantMapToScriptValue(asMap, scriptEngine);
|
||||
EntityItemProperties entityProperties;
|
||||
EntityItemPropertiesFromScriptValueHonorReadOnly(scriptProperties, entityProperties);
|
||||
|
||||
entityProperties.setParentID(myNodeID);
|
||||
entityProperties.setClientOnly(true);
|
||||
entityProperties.setOwningAvatarID(myNodeID);
|
||||
entityProperties.setSimulationOwner(myNodeID, AVATAR_ENTITY_SIMULATION_PRIORITY);
|
||||
entityProperties.markAllChanged();
|
||||
|
||||
EntityItemID id = EntityItemID(QUuid::createUuid());
|
||||
bool success = true;
|
||||
entityTree->withWriteLock([&] {
|
||||
EntityItemPointer entity = entityTree->addEntity(id, entityProperties);
|
||||
if (entity) {
|
||||
if (entityProperties.queryAACubeRelatedPropertyChanged()) {
|
||||
// due to parenting, the server may not know where something is in world-space, so include the bounding cube.
|
||||
bool success;
|
||||
AACube queryAACube = entity->getQueryAACube(success);
|
||||
if (success) {
|
||||
entityProperties.setQueryAACube(queryAACube);
|
||||
}
|
||||
}
|
||||
|
||||
entity->setLastBroadcast(usecTimestampNow());
|
||||
// since we're creating this object we will immediately volunteer to own its simulation
|
||||
entity->flagForOwnershipBid(VOLUNTEER_SIMULATION_PRIORITY);
|
||||
entityProperties.setLastEdited(entity->getLastEdited());
|
||||
} else {
|
||||
qCDebug(entities) << "AvatarEntitiesBookmark failed to add new Entity to local Octree";
|
||||
success = false;
|
||||
}
|
||||
});
|
||||
|
||||
if (success) {
|
||||
entityPacketSender->queueEditEntityMessage(PacketType::EntityAdd, entityTree, id, entityProperties);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AvatarEntitiesBookmarks::AvatarEntitiesBookmarks() {
|
||||
_bookmarksFilename = PathUtils::getAppDataPath() + "/" + AVATAR_ENTITIES_BOOKMARKS_FILENAME;
|
||||
Bookmarks::readFromFile();
|
||||
}
|
||||
|
||||
void AvatarEntitiesBookmarks::setupMenus(Menu* menubar, MenuWrapper* menu) {
|
||||
auto bookmarkAction = menubar->addActionToQMenuAndActionHash(menu, MenuOption::BookmarkAvatarEntities);
|
||||
QObject::connect(bookmarkAction, SIGNAL(triggered()), this, SLOT(addBookmark()), Qt::QueuedConnection);
|
||||
_bookmarksMenu = menu->addMenu(MenuOption::AvatarEntitiesBookmarks);
|
||||
_deleteBookmarksAction = menubar->addActionToQMenuAndActionHash(menu, MenuOption::DeleteAvatarEntitiesBookmark);
|
||||
QObject::connect(_deleteBookmarksAction, SIGNAL(triggered()), this, SLOT(deleteBookmark()), Qt::QueuedConnection);
|
||||
|
||||
for (auto it = _bookmarks.begin(); it != _bookmarks.end(); ++it) {
|
||||
addBookmarkToMenu(menubar, it.key(), it.value());
|
||||
}
|
||||
|
||||
Bookmarks::sortActions(menubar, _bookmarksMenu);
|
||||
}
|
||||
|
||||
void AvatarEntitiesBookmarks::applyBookmarkedAvatarEntities() {
|
||||
QAction* action = qobject_cast<QAction*>(sender());
|
||||
auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
|
||||
const QMap<QString, QVariant> bookmark = action->data().toMap();
|
||||
|
||||
if (bookmark.value(ENTRY_VERSION) == AVATAR_ENTITIES_BOOKMARK_VERSION) {
|
||||
myAvatar->removeAvatarEntities();
|
||||
const QString& avatarUrl = bookmark.value(ENTRY_AVATAR_URL, "").toString();
|
||||
myAvatar->useFullAvatarURL(avatarUrl);
|
||||
const QVariantList& avatarEntities = bookmark.value(ENTRY_AVATAR_ENTITIES, QVariantList()).toList();
|
||||
addAvatarEntities(avatarEntities);
|
||||
const float& avatarScale = bookmark.value(ENTRY_AVATAR_SCALE, 1.0f).toFloat();
|
||||
myAvatar->setAvatarScale(avatarScale);
|
||||
} else {
|
||||
qCDebug(interfaceapp) << " Bookmark entry does not match client version, make sure client has a handler for the new AvatarEntitiesBookmark";
|
||||
}
|
||||
}
|
||||
|
||||
void AvatarEntitiesBookmarks::addBookmark() {
|
||||
ModalDialogListener* dlg = OffscreenUi::getTextAsync(OffscreenUi::ICON_PLACEMARK, "Bookmark Avatar Entities", "Name", QString());
|
||||
connect(dlg, &ModalDialogListener::response, this, [=] (QVariant response) {
|
||||
disconnect(dlg, &ModalDialogListener::response, this, nullptr);
|
||||
auto bookmarkName = response.toString();
|
||||
bookmarkName = bookmarkName.trimmed().replace(QRegExp("(\r\n|[\r\n\t\v ])+"), " ");
|
||||
if (bookmarkName.length() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
|
||||
const QString& avatarUrl = myAvatar->getSkeletonModelURL().toString();
|
||||
const QVariant& avatarScale = myAvatar->getAvatarScale();
|
||||
|
||||
QVariantMap *bookmark = new QVariantMap;
|
||||
bookmark->insert(ENTRY_VERSION, AVATAR_ENTITIES_BOOKMARK_VERSION);
|
||||
bookmark->insert(ENTRY_AVATAR_URL, avatarUrl);
|
||||
bookmark->insert(ENTRY_AVATAR_SCALE, avatarScale);
|
||||
bookmark->insert(ENTRY_AVATAR_ENTITIES, myAvatar->getAvatarEntitiesVariant());
|
||||
|
||||
Bookmarks::addBookmarkToFile(bookmarkName, *bookmark);
|
||||
});
|
||||
}
|
||||
|
||||
void AvatarEntitiesBookmarks::addBookmarkToMenu(Menu* menubar, const QString& name, const QVariant& bookmark) {
|
||||
QAction* changeAction = _bookmarksMenu->newAction();
|
||||
changeAction->setData(bookmark);
|
||||
connect(changeAction, SIGNAL(triggered()), this, SLOT(applyBookmarkedAvatarEntities()));
|
||||
if (!_isMenuSorted) {
|
||||
menubar->addActionToQMenuAndActionHash(_bookmarksMenu, changeAction, name, 0, QAction::NoRole);
|
||||
} else {
|
||||
// TODO: this is aggressive but other alternatives have proved less fruitful so far.
|
||||
menubar->addActionToQMenuAndActionHash(_bookmarksMenu, changeAction, name, 0, QAction::NoRole);
|
||||
Bookmarks::sortActions(menubar, _bookmarksMenu);
|
||||
}
|
||||
}
|
45
interface/src/AvatarEntitiesBookmarks.h
Normal file
45
interface/src/AvatarEntitiesBookmarks.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
//
|
||||
// AvatarEntitiesBookmarks.h
|
||||
// interface/src
|
||||
//
|
||||
// Created by Dante Ruiz on 15/01/18.
|
||||
// Copyright 2018 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_AvatarEntitiesBookmarks_h
|
||||
#define hifi_AvatarEntitiesBookmarks_h
|
||||
|
||||
#include <DependencyManager.h>
|
||||
#include "Bookmarks.h"
|
||||
|
||||
class AvatarEntitiesBookmarks: public Bookmarks, public Dependency {
|
||||
Q_OBJECT
|
||||
SINGLETON_DEPENDENCY
|
||||
|
||||
public:
|
||||
AvatarEntitiesBookmarks();
|
||||
void setupMenus(Menu* menubar, MenuWrapper* menu) override;
|
||||
|
||||
public slots:
|
||||
void addBookmark();
|
||||
|
||||
protected:
|
||||
void addBookmarkToMenu(Menu* menubar, const QString& name, const QVariant& bookmark) override;
|
||||
|
||||
private:
|
||||
const QString AVATAR_ENTITIES_BOOKMARKS_FILENAME = "AvatarEntitiesBookmarks.json";
|
||||
const QString ENTRY_AVATAR_URL = "AvatarUrl";
|
||||
const QString ENTRY_AVATAR_SCALE = "AvatarScale";
|
||||
const QString ENTRY_AVATAR_ENTITIES = "AvatarEntities";
|
||||
const QString ENTRY_VERSION = "version";
|
||||
|
||||
const int AVATAR_ENTITIES_BOOKMARK_VERSION = 1;
|
||||
|
||||
private slots:
|
||||
void applyBookmarkedAvatarEntities();
|
||||
};
|
||||
|
||||
#endif
|
|
@ -34,6 +34,7 @@
|
|||
#include "audio/AudioScope.h"
|
||||
#include "avatar/AvatarManager.h"
|
||||
#include "AvatarBookmarks.h"
|
||||
#include "AvatarEntitiesBookmarks.h"
|
||||
#include "devices/DdeFaceTracker.h"
|
||||
#include "MainWindow.h"
|
||||
#include "render/DrawStatus.h"
|
||||
|
@ -206,6 +207,9 @@ Menu::Menu() {
|
|||
auto avatarBookmarks = DependencyManager::get<AvatarBookmarks>();
|
||||
avatarBookmarks->setupMenus(this, avatarMenu);
|
||||
|
||||
auto avatarEntitiesBookmarks = DependencyManager::get<AvatarEntitiesBookmarks>();
|
||||
avatarEntitiesBookmarks->setupMenus(this, avatarMenu);
|
||||
|
||||
// Display menu ----------------------------------
|
||||
// FIXME - this is not yet matching Alan's spec because it doesn't have
|
||||
// menus for "2D"/"3D" - we need to add support for detecting the appropriate
|
||||
|
|
|
@ -46,9 +46,11 @@ namespace MenuOption {
|
|||
const QString AutoMuteAudio = "Auto Mute Microphone";
|
||||
const QString AvatarReceiveStats = "Show Receive Stats";
|
||||
const QString AvatarBookmarks = "Avatar Bookmarks";
|
||||
const QString AvatarEntitiesBookmarks = "Avatar Entities Bookmarks";
|
||||
const QString Back = "Back";
|
||||
const QString BinaryEyelidControl = "Binary Eyelid Control";
|
||||
const QString BookmarkAvatar = "Bookmark Avatar";
|
||||
const QString BookmarkAvatarEntities = "Bookmark Avatar Entities";
|
||||
const QString BookmarkLocation = "Bookmark Location";
|
||||
const QString CalibrateCamera = "Calibrate Camera";
|
||||
const QString CameraEntityMode = "Entity Mode";
|
||||
|
@ -78,6 +80,7 @@ namespace MenuOption {
|
|||
const QString DecreaseAvatarSize = "Decrease Avatar Size";
|
||||
const QString DefaultSkybox = "Default Skybox";
|
||||
const QString DeleteAvatarBookmark = "Delete Avatar Bookmark...";
|
||||
const QString DeleteAvatarEntitiesBookmark = "Delete Avatar Entities Bookmark";
|
||||
const QString DeleteBookmark = "Delete Bookmark...";
|
||||
const QString DisableActivityLogger = "Disable Activity Logger";
|
||||
const QString DisableEyelidAdjustment = "Disable Eyelid Adjustment";
|
||||
|
|
|
@ -35,6 +35,8 @@
|
|||
#include <PerfStat.h>
|
||||
#include <SharedUtil.h>
|
||||
#include <SoundCache.h>
|
||||
#include <ModelEntityItem.h>
|
||||
#include <GLMHelpers.h>
|
||||
#include <TextRenderer3D.h>
|
||||
#include <UserActivityLogger.h>
|
||||
#include <AnimDebugDraw.h>
|
||||
|
@ -1421,6 +1423,37 @@ void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
|
|||
|
||||
}
|
||||
|
||||
void MyAvatar::removeAvatarEntities() {
|
||||
auto treeRenderer = DependencyManager::get<EntityTreeRenderer>();
|
||||
EntityTreePointer entityTree = treeRenderer ? treeRenderer->getTree() : nullptr;
|
||||
if (entityTree) {
|
||||
entityTree->withWriteLock([&] {
|
||||
AvatarEntityMap avatarEntities = getAvatarEntityData();
|
||||
for (auto entityID : avatarEntities.keys()) {
|
||||
entityTree->deleteEntity(entityID, true, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
QVariantList MyAvatar::getAvatarEntitiesVariant() {
|
||||
QVariantList avatarEntitiesData;
|
||||
QScriptEngine scriptEngine;
|
||||
forEachChild([&](SpatiallyNestablePointer child) {
|
||||
if (child->getNestableType() == NestableType::Entity) {
|
||||
auto modelEntity = std::dynamic_pointer_cast<ModelEntityItem>(child);
|
||||
if (modelEntity) {
|
||||
QVariantMap avatarEntityData;
|
||||
EntityItemProperties entityProperties = modelEntity->getProperties();
|
||||
QScriptValue scriptProperties = EntityItemPropertiesToScriptValue(&scriptEngine, entityProperties);
|
||||
avatarEntityData["properties"] = scriptProperties.toVariant();
|
||||
avatarEntitiesData.append(QVariant(avatarEntityData));
|
||||
}
|
||||
}
|
||||
});
|
||||
return avatarEntitiesData;
|
||||
}
|
||||
|
||||
|
||||
void MyAvatar::resetFullAvatarURL() {
|
||||
auto lastAvatarURL = getFullAvatarURLFromPreferences();
|
||||
|
|
|
@ -512,6 +512,9 @@ public:
|
|||
|
||||
bool hasDriveInput() const;
|
||||
|
||||
QVariantList getAvatarEntitiesVariant();
|
||||
void removeAvatarEntities();
|
||||
|
||||
Q_INVOKABLE bool isFlying();
|
||||
Q_INVOKABLE bool isInAir();
|
||||
Q_INVOKABLE void setFlyingEnabled(bool enabled);
|
||||
|
|
Loading…
Reference in a new issue