mirror of
https://github.com/overte-org/overte.git
synced 2025-08-10 05:23:09 +02:00
Merge pull request #15044 from sethalves/lock-wearables
case 21149: add a button to Avatar panel to lock or unlock wearables; allow others to grab unlocked wearables
This commit is contained in:
commit
a83b90cdc6
13 changed files with 157 additions and 98 deletions
|
@ -16,6 +16,8 @@ Rectangle {
|
||||||
property bool keyboardRaised: false
|
property bool keyboardRaised: false
|
||||||
property bool punctuationMode: false
|
property bool punctuationMode: false
|
||||||
|
|
||||||
|
HifiConstants { id: hifi }
|
||||||
|
|
||||||
HifiControls.Keyboard {
|
HifiControls.Keyboard {
|
||||||
id: keyboard
|
id: keyboard
|
||||||
z: 1000
|
z: 1000
|
||||||
|
@ -48,6 +50,7 @@ Rectangle {
|
||||||
|
|
||||||
property var jointNames: []
|
property var jointNames: []
|
||||||
property var currentAvatarSettings;
|
property var currentAvatarSettings;
|
||||||
|
property bool wearablesFrozen;
|
||||||
|
|
||||||
function fetchAvatarModelName(marketId, avatar) {
|
function fetchAvatarModelName(marketId, avatar) {
|
||||||
var xmlhttp = new XMLHttpRequest();
|
var xmlhttp = new XMLHttpRequest();
|
||||||
|
@ -187,6 +190,8 @@ Rectangle {
|
||||||
updateCurrentAvatarInBookmarks(currentAvatar);
|
updateCurrentAvatarInBookmarks(currentAvatar);
|
||||||
} else if (message.method === 'selectAvatarEntity') {
|
} else if (message.method === 'selectAvatarEntity') {
|
||||||
adjustWearables.selectWearableByID(message.entityID);
|
adjustWearables.selectWearableByID(message.entityID);
|
||||||
|
} else if (message.method === 'wearablesFrozenChanged') {
|
||||||
|
wearablesFrozen = message.wearablesFrozen;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -507,6 +512,7 @@ Rectangle {
|
||||||
}
|
}
|
||||||
|
|
||||||
SquareLabel {
|
SquareLabel {
|
||||||
|
id: adjustLabel
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.verticalCenter: wearablesLabel.verticalCenter
|
anchors.verticalCenter: wearablesLabel.verticalCenter
|
||||||
glyphText: "\ue02e"
|
glyphText: "\ue02e"
|
||||||
|
@ -515,6 +521,17 @@ Rectangle {
|
||||||
adjustWearables.open(currentAvatar);
|
adjustWearables.open(currentAvatar);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SquareLabel {
|
||||||
|
anchors.right: adjustLabel.left
|
||||||
|
anchors.verticalCenter: wearablesLabel.verticalCenter
|
||||||
|
anchors.rightMargin: 15
|
||||||
|
glyphText: wearablesFrozen ? hifi.glyphs.lock : hifi.glyphs.unlock;
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
emitSendToScript({'method' : 'toggleWearablesFrozen'});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
|
|
|
@ -113,6 +113,7 @@ Rectangle {
|
||||||
} else if (prop === 'dimensions') {
|
} else if (prop === 'dimensions') {
|
||||||
scalespinner.set(wearable[prop].x / wearable.naturalDimensions.x);
|
scalespinner.set(wearable[prop].x / wearable.naturalDimensions.x);
|
||||||
}
|
}
|
||||||
|
modified = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -344,6 +344,7 @@ Item {
|
||||||
readonly property string stop_square: "\ue01e"
|
readonly property string stop_square: "\ue01e"
|
||||||
readonly property string avatarTPose: "\ue01f"
|
readonly property string avatarTPose: "\ue01f"
|
||||||
readonly property string lock: "\ue006"
|
readonly property string lock: "\ue006"
|
||||||
|
readonly property string unlock: "\ue039"
|
||||||
readonly property string checkmark: "\ue020"
|
readonly property string checkmark: "\ue020"
|
||||||
readonly property string leftRightArrows: "\ue021"
|
readonly property string leftRightArrows: "\ue021"
|
||||||
readonly property string hfc: "\ue022"
|
readonly property string hfc: "\ue022"
|
||||||
|
|
|
@ -330,6 +330,7 @@ QtObject {
|
||||||
readonly property string stop_square: "\ue01e"
|
readonly property string stop_square: "\ue01e"
|
||||||
readonly property string avatarTPose: "\ue01f"
|
readonly property string avatarTPose: "\ue01f"
|
||||||
readonly property string lock: "\ue006"
|
readonly property string lock: "\ue006"
|
||||||
|
readonly property string unlock: "\ue039"
|
||||||
readonly property string checkmark: "\ue020"
|
readonly property string checkmark: "\ue020"
|
||||||
readonly property string leftRightArrows: "\ue021"
|
readonly property string leftRightArrows: "\ue021"
|
||||||
readonly property string hfc: "\ue022"
|
readonly property string hfc: "\ue022"
|
||||||
|
|
|
@ -2170,7 +2170,7 @@ private:
|
||||||
bool getEnableStepResetRotation() const { return _stepResetRotationEnabled; }
|
bool getEnableStepResetRotation() const { return _stepResetRotationEnabled; }
|
||||||
void setEnableDrawAverageFacing(bool drawAverage) { _drawAverageFacingEnabled = drawAverage; }
|
void setEnableDrawAverageFacing(bool drawAverage) { _drawAverageFacingEnabled = drawAverage; }
|
||||||
bool getEnableDrawAverageFacing() const { return _drawAverageFacingEnabled; }
|
bool getEnableDrawAverageFacing() const { return _drawAverageFacingEnabled; }
|
||||||
bool isMyAvatar() const override { return true; }
|
virtual bool isMyAvatar() const override { return true; }
|
||||||
virtual int parseDataFromBuffer(const QByteArray& buffer) override;
|
virtual int parseDataFromBuffer(const QByteArray& buffer) override;
|
||||||
virtual glm::vec3 getSkeletonPosition() const override;
|
virtual glm::vec3 getSkeletonPosition() const override;
|
||||||
int _skeletonModelChangeCount { 0 };
|
int _skeletonModelChangeCount { 0 };
|
||||||
|
|
|
@ -365,7 +365,7 @@ void OtherAvatar::handleChangedAvatarEntityData() {
|
||||||
// AVATAR ENTITY UPDATE FLOW
|
// AVATAR ENTITY UPDATE FLOW
|
||||||
// - if queueEditEntityMessage() sees "AvatarEntity" HostType it calls _myAvatar->storeAvatarEntityDataPayload()
|
// - if queueEditEntityMessage() sees "AvatarEntity" HostType it calls _myAvatar->storeAvatarEntityDataPayload()
|
||||||
// - storeAvatarEntityDataPayload() saves the payload and flags the trait instance for the entity as updated,
|
// - storeAvatarEntityDataPayload() saves the payload and flags the trait instance for the entity as updated,
|
||||||
// - ClientTraitsHandler::sendChangedTraitsToMixea() sends the entity bytes to the mixer which relays them to other interfaces
|
// - ClientTraitsHandler::sendChangedTraitsToMixer() sends the entity bytes to the mixer which relays them to other interfaces
|
||||||
// - AvatarHashMap::processBulkAvatarTraits() on other interfaces calls avatar->processTraitInstance()
|
// - AvatarHashMap::processBulkAvatarTraits() on other interfaces calls avatar->processTraitInstance()
|
||||||
// - AvatarData::processTraitInstance() calls storeAvatarEntityDataPayload(), which sets _avatarEntityDataChanged = true
|
// - AvatarData::processTraitInstance() calls storeAvatarEntityDataPayload(), which sets _avatarEntityDataChanged = true
|
||||||
// - (My)Avatar::simulate() calls handleChangedAvatarEntityData() every frame which checks _avatarEntityDataChanged
|
// - (My)Avatar::simulate() calls handleChangedAvatarEntityData() every frame which checks _avatarEntityDataChanged
|
||||||
|
@ -495,6 +495,18 @@ void OtherAvatar::handleChangedAvatarEntityData() {
|
||||||
const QUuid NULL_ID = QUuid("{00000000-0000-0000-0000-000000000005}");
|
const QUuid NULL_ID = QUuid("{00000000-0000-0000-0000-000000000005}");
|
||||||
entity->setParentID(NULL_ID);
|
entity->setParentID(NULL_ID);
|
||||||
entity->setParentID(oldParentID);
|
entity->setParentID(oldParentID);
|
||||||
|
|
||||||
|
if (entity->stillHasMyGrabAction()) {
|
||||||
|
// For this case: we want to ignore transform+velocities coming from authoritative OtherAvatar
|
||||||
|
// because the MyAvatar is grabbing and we expect the local grab state
|
||||||
|
// to have enough information to prevent simulation drift.
|
||||||
|
//
|
||||||
|
// Clever readers might realize this could cause problems. For example,
|
||||||
|
// if an ignored OtherAvagtar were to simultanously grab the object then there would be
|
||||||
|
// a noticeable discrepancy between participants in the distributed physics simulation,
|
||||||
|
// however the difference would be stable and would not drift.
|
||||||
|
properties.clearTransformOrVelocityChanges();
|
||||||
|
}
|
||||||
if (entityTree->updateEntity(entityID, properties)) {
|
if (entityTree->updateEntity(entityID, properties)) {
|
||||||
entity->updateLastEditedFromRemote();
|
entity->updateLastEditedFromRemote();
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -372,13 +372,6 @@ bool Avatar::applyGrabChanges() {
|
||||||
target->removeGrab(grab);
|
target->removeGrab(grab);
|
||||||
_avatarGrabs.erase(itr);
|
_avatarGrabs.erase(itr);
|
||||||
grabAddedOrRemoved = true;
|
grabAddedOrRemoved = true;
|
||||||
if (isMyAvatar()) {
|
|
||||||
const EntityItemPointer& entity = std::dynamic_pointer_cast<EntityItem>(target);
|
|
||||||
if (entity && entity->getEntityHostType() == entity::HostType::AVATAR && entity->getSimulationOwner().getID() == getID()) {
|
|
||||||
EntityItemProperties properties = entity->getProperties();
|
|
||||||
sendPacket(entity->getID());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
undeleted.push_back(id);
|
undeleted.push_back(id);
|
||||||
}
|
}
|
||||||
|
|
|
@ -180,7 +180,6 @@ public:
|
||||||
/// Returns the distance to use as a LOD parameter.
|
/// Returns the distance to use as a LOD parameter.
|
||||||
float getLODDistance() const;
|
float getLODDistance() const;
|
||||||
|
|
||||||
virtual bool isMyAvatar() const override { return false; }
|
|
||||||
virtual void createOrb() { }
|
virtual void createOrb() { }
|
||||||
|
|
||||||
enum class LoadingStatus {
|
enum class LoadingStatus {
|
||||||
|
|
|
@ -789,8 +789,10 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
||||||
|
|
||||||
auto lastEdited = lastEditedFromBufferAdjusted;
|
auto lastEdited = lastEditedFromBufferAdjusted;
|
||||||
bool otherOverwrites = overwriteLocalData && !weOwnSimulation;
|
bool otherOverwrites = overwriteLocalData && !weOwnSimulation;
|
||||||
auto shouldUpdate = [this, lastEdited, otherOverwrites, filterRejection](quint64 updatedTimestamp, bool valueChanged) {
|
// calculate hasGrab once outside the lambda rather than calling it every time inside
|
||||||
if (stillHasGrabActions()) {
|
bool hasGrab = stillHasGrabAction();
|
||||||
|
auto shouldUpdate = [this, lastEdited, otherOverwrites, filterRejection, hasGrab](quint64 updatedTimestamp, bool valueChanged) {
|
||||||
|
if (hasGrab) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
bool simulationChanged = lastEdited > updatedTimestamp;
|
bool simulationChanged = lastEdited > updatedTimestamp;
|
||||||
|
@ -957,12 +959,18 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
||||||
// by doing this parsing here... but it's not likely going to fully recover the content.
|
// by doing this parsing here... but it's not likely going to fully recover the content.
|
||||||
//
|
//
|
||||||
|
|
||||||
if (overwriteLocalData && (getDirtyFlags() & (Simulation::DIRTY_TRANSFORM | Simulation::DIRTY_VELOCITIES))) {
|
if (overwriteLocalData &&
|
||||||
|
!hasGrab &&
|
||||||
|
(getDirtyFlags() & (Simulation::DIRTY_TRANSFORM | Simulation::DIRTY_VELOCITIES))) {
|
||||||
// NOTE: This code is attempting to "repair" the old data we just got from the server to make it more
|
// NOTE: This code is attempting to "repair" the old data we just got from the server to make it more
|
||||||
// closely match where the entities should be if they'd stepped forward in time to "now". The server
|
// closely match where the entities should be if they'd stepped forward in time to "now". The server
|
||||||
// is sending us data with a known "last simulated" time. That time is likely in the past, and therefore
|
// is sending us data with a known "last simulated" time. That time is likely in the past, and therefore
|
||||||
// this "new" data is actually slightly out of date. We calculate the time we need to skip forward and
|
// this "new" data is actually slightly out of date. We calculate the time we need to skip forward and
|
||||||
// use our simulation helper routine to get a best estimate of where the entity should be.
|
// use our simulation helper routine to get a best estimate of where the entity should be.
|
||||||
|
//
|
||||||
|
// NOTE: We don't want to do this in the hasGrab case because grabs "know best"
|
||||||
|
// (e.g. grabs will prevent drift between distributed physics simulations).
|
||||||
|
//
|
||||||
float skipTimeForward = (float)(now - lastSimulatedFromBufferAdjusted) / (float)(USECS_PER_SECOND);
|
float skipTimeForward = (float)(now - lastSimulatedFromBufferAdjusted) / (float)(USECS_PER_SECOND);
|
||||||
|
|
||||||
// we want to extrapolate the motion forward to compensate for packet travel time, but
|
// we want to extrapolate the motion forward to compensate for packet travel time, but
|
||||||
|
@ -1426,7 +1434,7 @@ void EntityItem::getTransformAndVelocityProperties(EntityItemProperties& propert
|
||||||
|
|
||||||
void EntityItem::upgradeScriptSimulationPriority(uint8_t priority) {
|
void EntityItem::upgradeScriptSimulationPriority(uint8_t priority) {
|
||||||
uint8_t newPriority = glm::max(priority, _scriptSimulationPriority);
|
uint8_t newPriority = glm::max(priority, _scriptSimulationPriority);
|
||||||
if (newPriority < SCRIPT_GRAB_SIMULATION_PRIORITY && stillHasGrabActions()) {
|
if (newPriority < SCRIPT_GRAB_SIMULATION_PRIORITY && stillHasMyGrabAction()) {
|
||||||
newPriority = SCRIPT_GRAB_SIMULATION_PRIORITY;
|
newPriority = SCRIPT_GRAB_SIMULATION_PRIORITY;
|
||||||
}
|
}
|
||||||
if (newPriority != _scriptSimulationPriority) {
|
if (newPriority != _scriptSimulationPriority) {
|
||||||
|
@ -1439,7 +1447,7 @@ void EntityItem::upgradeScriptSimulationPriority(uint8_t priority) {
|
||||||
void EntityItem::clearScriptSimulationPriority() {
|
void EntityItem::clearScriptSimulationPriority() {
|
||||||
// DO NOT markDirtyFlags(Simulation::DIRTY_SIMULATION_OWNERSHIP_PRIORITY) here, because this
|
// DO NOT markDirtyFlags(Simulation::DIRTY_SIMULATION_OWNERSHIP_PRIORITY) here, because this
|
||||||
// is only ever called from the code that actually handles the dirty flags, and it knows best.
|
// is only ever called from the code that actually handles the dirty flags, and it knows best.
|
||||||
_scriptSimulationPriority = stillHasGrabActions() ? SCRIPT_GRAB_SIMULATION_PRIORITY : 0;
|
_scriptSimulationPriority = stillHasMyGrabAction() ? SCRIPT_GRAB_SIMULATION_PRIORITY : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityItem::setPendingOwnershipPriority(uint8_t priority) {
|
void EntityItem::setPendingOwnershipPriority(uint8_t priority) {
|
||||||
|
@ -2186,7 +2194,7 @@ void EntityItem::enableNoBootstrap() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityItem::disableNoBootstrap() {
|
void EntityItem::disableNoBootstrap() {
|
||||||
if (!stillHasGrabActions()) {
|
if (!stillHasMyGrabAction()) {
|
||||||
_flags &= ~Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING;
|
_flags &= ~Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING;
|
||||||
_flags |= Simulation::DIRTY_COLLISION_GROUP; // may need to not collide with own avatar
|
_flags |= Simulation::DIRTY_COLLISION_GROUP; // may need to not collide with own avatar
|
||||||
|
|
||||||
|
@ -2272,7 +2280,13 @@ bool EntityItem::removeAction(EntitySimulationPointer simulation, const QUuid& a
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EntityItem::stillHasGrabActions() const {
|
bool EntityItem::stillHasGrabAction() const {
|
||||||
|
return !_grabActions.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
// retutrns 'true' if there exists an action that returns 'true' for EntityActionInterface::isMine()
|
||||||
|
// (e.g. the action belongs to the MyAvatar instance)
|
||||||
|
bool EntityItem::stillHasMyGrabAction() const {
|
||||||
QList<EntityDynamicPointer> holdActions = getActionsOfType(DYNAMIC_TYPE_HOLD);
|
QList<EntityDynamicPointer> holdActions = getActionsOfType(DYNAMIC_TYPE_HOLD);
|
||||||
QList<EntityDynamicPointer>::const_iterator i = holdActions.begin();
|
QList<EntityDynamicPointer>::const_iterator i = holdActions.begin();
|
||||||
while (i != holdActions.end()) {
|
while (i != holdActions.end()) {
|
||||||
|
@ -2700,20 +2714,6 @@ void EntityItem::setLastEdited(quint64 lastEdited) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
quint64 EntityItem::getLastBroadcast() const {
|
|
||||||
quint64 result;
|
|
||||||
withReadLock([&] {
|
|
||||||
result = _lastBroadcast;
|
|
||||||
});
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EntityItem::setLastBroadcast(quint64 lastBroadcast) {
|
|
||||||
withWriteLock([&] {
|
|
||||||
_lastBroadcast = lastBroadcast;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void EntityItem::markAsChangedOnServer() {
|
void EntityItem::markAsChangedOnServer() {
|
||||||
withWriteLock([&] {
|
withWriteLock([&] {
|
||||||
_changedOnServer = usecTimestampNow();
|
_changedOnServer = usecTimestampNow();
|
||||||
|
@ -3479,6 +3479,9 @@ void EntityItem::addGrab(GrabPointer grab) {
|
||||||
simulation->addDynamic(action);
|
simulation->addDynamic(action);
|
||||||
markDirtyFlags(Simulation::DIRTY_MOTION_TYPE);
|
markDirtyFlags(Simulation::DIRTY_MOTION_TYPE);
|
||||||
simulation->changeEntity(getThisPointer());
|
simulation->changeEntity(getThisPointer());
|
||||||
|
|
||||||
|
// don't forget to set isMine() for locally-created grabs
|
||||||
|
action->setIsMine(grab->getOwnerID() == Physics::getSessionUUID());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -124,8 +124,8 @@ public:
|
||||||
{ return (float)(usecTimestampNow() - getLastEdited()) / (float)USECS_PER_SECOND; }
|
{ return (float)(usecTimestampNow() - getLastEdited()) / (float)USECS_PER_SECOND; }
|
||||||
|
|
||||||
/// Last time we sent out an edit packet for this entity
|
/// Last time we sent out an edit packet for this entity
|
||||||
quint64 getLastBroadcast() const;
|
quint64 getLastBroadcast() const { return _lastBroadcast; }
|
||||||
void setLastBroadcast(quint64 lastBroadcast);
|
void setLastBroadcast(quint64 lastBroadcast) { _lastBroadcast = lastBroadcast; }
|
||||||
|
|
||||||
void markAsChangedOnServer();
|
void markAsChangedOnServer();
|
||||||
quint64 getLastChangedOnServer() const;
|
quint64 getLastChangedOnServer() const;
|
||||||
|
@ -562,6 +562,8 @@ public:
|
||||||
static void setPrimaryViewFrustumPositionOperator(std::function<glm::vec3()> getPrimaryViewFrustumPositionOperator) { _getPrimaryViewFrustumPositionOperator = getPrimaryViewFrustumPositionOperator; }
|
static void setPrimaryViewFrustumPositionOperator(std::function<glm::vec3()> getPrimaryViewFrustumPositionOperator) { _getPrimaryViewFrustumPositionOperator = getPrimaryViewFrustumPositionOperator; }
|
||||||
static glm::vec3 getPrimaryViewFrustumPosition() { return _getPrimaryViewFrustumPositionOperator(); }
|
static glm::vec3 getPrimaryViewFrustumPosition() { return _getPrimaryViewFrustumPositionOperator(); }
|
||||||
|
|
||||||
|
bool stillHasMyGrabAction() const;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void requestRenderUpdate();
|
void requestRenderUpdate();
|
||||||
void spaceUpdate(std::pair<int32_t, glm::vec4> data);
|
void spaceUpdate(std::pair<int32_t, glm::vec4> data);
|
||||||
|
@ -574,7 +576,7 @@ protected:
|
||||||
void setSimulated(bool simulated) { _simulated = simulated; }
|
void setSimulated(bool simulated) { _simulated = simulated; }
|
||||||
|
|
||||||
const QByteArray getDynamicDataInternal() const;
|
const QByteArray getDynamicDataInternal() const;
|
||||||
bool stillHasGrabActions() const;
|
bool stillHasGrabAction() const;
|
||||||
void setDynamicDataInternal(QByteArray dynamicData);
|
void setDynamicDataInternal(QByteArray dynamicData);
|
||||||
|
|
||||||
virtual void dimensionsChanged() override;
|
virtual void dimensionsChanged() override;
|
||||||
|
|
|
@ -1101,13 +1101,13 @@ void EntityScriptingInterface::handleEntityScriptCallMethodPacket(QSharedPointer
|
||||||
|
|
||||||
void EntityScriptingInterface::onAddingEntity(EntityItem* entity) {
|
void EntityScriptingInterface::onAddingEntity(EntityItem* entity) {
|
||||||
if (entity->isWearable()) {
|
if (entity->isWearable()) {
|
||||||
emit addingWearable(entity->getEntityItemID());
|
QMetaObject::invokeMethod(this, "addingWearable", Q_ARG(QUuid, entity->getEntityItemID()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityScriptingInterface::onDeletingEntity(EntityItem* entity) {
|
void EntityScriptingInterface::onDeletingEntity(EntityItem* entity) {
|
||||||
if (entity->isWearable()) {
|
if (entity->isWearable()) {
|
||||||
emit deletingWearable(entity->getEntityItemID());
|
QMetaObject::invokeMethod(this, "deletingWearable", Q_ARG(QUuid, entity->getEntityItemID()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
/*jslint vars:true, plusplus:true, forin:true*/
|
/*jslint vars:true, plusplus:true, forin:true*/
|
||||||
/*global Tablet, Settings, Script, AvatarList, Users, Entities, MyAvatar, Camera, Overlays, Vec3, Quat, HMD, Controller, Account, UserActivityLogger, Messages, Window, XMLHttpRequest, print, location, getControllerWorldLocation*/
|
/*global Tablet, Script, Entities, MyAvatar, Camera, Quat, HMD, Account, UserActivityLogger, Messages, print,
|
||||||
|
AvatarBookmarks, ContextOverlay, AddressManager
|
||||||
|
*/
|
||||||
/* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */
|
/* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */
|
||||||
//
|
//
|
||||||
// avatarapp.js
|
// avatarapp.js
|
||||||
|
@ -14,7 +16,6 @@
|
||||||
|
|
||||||
(function() { // BEGIN LOCAL_SCOPE
|
(function() { // BEGIN LOCAL_SCOPE
|
||||||
|
|
||||||
var request = Script.require('request').request;
|
|
||||||
var AVATARAPP_QML_SOURCE = "hifi/AvatarApp.qml";
|
var AVATARAPP_QML_SOURCE = "hifi/AvatarApp.qml";
|
||||||
Script.include("/~/system/libraries/controllers.js");
|
Script.include("/~/system/libraries/controllers.js");
|
||||||
|
|
||||||
|
@ -22,7 +23,6 @@ Script.include("/~/system/libraries/controllers.js");
|
||||||
var ENTRY_AVATAR_URL = "avatarUrl";
|
var ENTRY_AVATAR_URL = "avatarUrl";
|
||||||
var ENTRY_AVATAR_ENTITIES = "avatarEntites";
|
var ENTRY_AVATAR_ENTITIES = "avatarEntites";
|
||||||
var ENTRY_AVATAR_SCALE = "avatarScale";
|
var ENTRY_AVATAR_SCALE = "avatarScale";
|
||||||
var ENTRY_VERSION = "version";
|
|
||||||
|
|
||||||
function executeLater(callback) {
|
function executeLater(callback) {
|
||||||
Script.setTimeout(callback, 300);
|
Script.setTimeout(callback, 300);
|
||||||
|
@ -44,7 +44,7 @@ function getMyAvatarWearables() {
|
||||||
}
|
}
|
||||||
|
|
||||||
var localRotation = entity.properties.localRotation;
|
var localRotation = entity.properties.localRotation;
|
||||||
entity.properties.localRotationAngles = Quat.safeEulerAngles(localRotation)
|
entity.properties.localRotationAngles = Quat.safeEulerAngles(localRotation);
|
||||||
wearablesArray.push(entity);
|
wearablesArray.push(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ function getMyAvatarWearables() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function getMyAvatar() {
|
function getMyAvatar() {
|
||||||
var avatar = {}
|
var avatar = {};
|
||||||
avatar[ENTRY_AVATAR_URL] = MyAvatar.skeletonModelURL;
|
avatar[ENTRY_AVATAR_URL] = MyAvatar.skeletonModelURL;
|
||||||
avatar[ENTRY_AVATAR_SCALE] = MyAvatar.getAvatarScale();
|
avatar[ENTRY_AVATAR_SCALE] = MyAvatar.getAvatarScale();
|
||||||
avatar[ENTRY_AVATAR_ENTITIES] = getMyAvatarWearables();
|
avatar[ENTRY_AVATAR_ENTITIES] = getMyAvatarWearables();
|
||||||
|
@ -68,7 +68,7 @@ function getMyAvatarSettings() {
|
||||||
collisionSoundUrl : MyAvatar.collisionSoundURL,
|
collisionSoundUrl : MyAvatar.collisionSoundURL,
|
||||||
animGraphUrl: MyAvatar.getAnimGraphUrl(),
|
animGraphUrl: MyAvatar.getAnimGraphUrl(),
|
||||||
animGraphOverrideUrl : MyAvatar.getAnimGraphOverrideUrl(),
|
animGraphOverrideUrl : MyAvatar.getAnimGraphOverrideUrl(),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateAvatarWearables(avatar, callback, wearablesOverride) {
|
function updateAvatarWearables(avatar, callback, wearablesOverride) {
|
||||||
|
@ -76,7 +76,8 @@ function updateAvatarWearables(avatar, callback, wearablesOverride) {
|
||||||
var wearables = wearablesOverride ? wearablesOverride : getMyAvatarWearables();
|
var wearables = wearablesOverride ? wearablesOverride : getMyAvatarWearables();
|
||||||
avatar[ENTRY_AVATAR_ENTITIES] = wearables;
|
avatar[ENTRY_AVATAR_ENTITIES] = wearables;
|
||||||
|
|
||||||
sendToQml({'method' : 'wearablesUpdated', 'wearables' : wearables})
|
sendToQml({'method' : 'wearablesUpdated', 'wearables' : wearables});
|
||||||
|
sendToQml({ 'method' : 'wearablesFrozenChanged', 'wearablesFrozen' : getWearablesFrozen()});
|
||||||
|
|
||||||
if(callback)
|
if(callback)
|
||||||
callback();
|
callback();
|
||||||
|
@ -101,7 +102,7 @@ var adjustWearables = {
|
||||||
this.opened = value;
|
this.opened = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
var currentAvatarWearablesBackup = null;
|
var currentAvatarWearablesBackup = null;
|
||||||
var currentAvatar = null;
|
var currentAvatar = null;
|
||||||
|
@ -112,7 +113,7 @@ function onTargetScaleChanged() {
|
||||||
if(currentAvatar.scale !== MyAvatar.getAvatarScale()) {
|
if(currentAvatar.scale !== MyAvatar.getAvatarScale()) {
|
||||||
currentAvatar.scale = MyAvatar.getAvatarScale();
|
currentAvatar.scale = MyAvatar.getAvatarScale();
|
||||||
if(notifyScaleChanged) {
|
if(notifyScaleChanged) {
|
||||||
sendToQml({'method' : 'scaleChanged', 'value' : currentAvatar.scale})
|
sendToQml({'method' : 'scaleChanged', 'value' : currentAvatar.scale});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -126,7 +127,7 @@ function onSkeletonModelURLChanged() {
|
||||||
function onDominantHandChanged(dominantHand) {
|
function onDominantHandChanged(dominantHand) {
|
||||||
if(currentAvatarSettings.dominantHand !== dominantHand) {
|
if(currentAvatarSettings.dominantHand !== dominantHand) {
|
||||||
currentAvatarSettings.dominantHand = dominantHand;
|
currentAvatarSettings.dominantHand = dominantHand;
|
||||||
sendToQml({'method' : 'settingChanged', 'name' : 'dominantHand', 'value' : dominantHand})
|
sendToQml({'method' : 'settingChanged', 'name' : 'dominantHand', 'value' : dominantHand});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,37 +141,37 @@ function onHmdAvatarAlignmentTypeChanged(type) {
|
||||||
function onCollisionsEnabledChanged(enabled) {
|
function onCollisionsEnabledChanged(enabled) {
|
||||||
if(currentAvatarSettings.collisionsEnabled !== enabled) {
|
if(currentAvatarSettings.collisionsEnabled !== enabled) {
|
||||||
currentAvatarSettings.collisionsEnabled = enabled;
|
currentAvatarSettings.collisionsEnabled = enabled;
|
||||||
sendToQml({'method' : 'settingChanged', 'name' : 'collisionsEnabled', 'value' : enabled})
|
sendToQml({'method' : 'settingChanged', 'name' : 'collisionsEnabled', 'value' : enabled});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onOtherAvatarsCollisionsEnabledChanged(enabled) {
|
function onOtherAvatarsCollisionsEnabledChanged(enabled) {
|
||||||
if (currentAvatarSettings.otherAvatarsCollisionsEnabled !== enabled) {
|
if (currentAvatarSettings.otherAvatarsCollisionsEnabled !== enabled) {
|
||||||
currentAvatarSettings.otherAvatarsCollisionsEnabled = enabled;
|
currentAvatarSettings.otherAvatarsCollisionsEnabled = enabled;
|
||||||
sendToQml({ 'method': 'settingChanged', 'name': 'otherAvatarsCollisionsEnabled', 'value': enabled })
|
sendToQml({ 'method': 'settingChanged', 'name': 'otherAvatarsCollisionsEnabled', 'value': enabled });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onNewCollisionSoundUrl(url) {
|
function onNewCollisionSoundUrl(url) {
|
||||||
if(currentAvatarSettings.collisionSoundUrl !== url) {
|
if(currentAvatarSettings.collisionSoundUrl !== url) {
|
||||||
currentAvatarSettings.collisionSoundUrl = url;
|
currentAvatarSettings.collisionSoundUrl = url;
|
||||||
sendToQml({'method' : 'settingChanged', 'name' : 'collisionSoundUrl', 'value' : url})
|
sendToQml({'method' : 'settingChanged', 'name' : 'collisionSoundUrl', 'value' : url});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onAnimGraphUrlChanged(url) {
|
function onAnimGraphUrlChanged(url) {
|
||||||
if (currentAvatarSettings.animGraphUrl !== url) {
|
if (currentAvatarSettings.animGraphUrl !== url) {
|
||||||
currentAvatarSettings.animGraphUrl = url;
|
currentAvatarSettings.animGraphUrl = url;
|
||||||
sendToQml({ 'method': 'settingChanged', 'name': 'animGraphUrl', 'value': currentAvatarSettings.animGraphUrl })
|
sendToQml({ 'method': 'settingChanged', 'name': 'animGraphUrl', 'value': currentAvatarSettings.animGraphUrl });
|
||||||
|
|
||||||
if (currentAvatarSettings.animGraphOverrideUrl !== MyAvatar.getAnimGraphOverrideUrl()) {
|
if (currentAvatarSettings.animGraphOverrideUrl !== MyAvatar.getAnimGraphOverrideUrl()) {
|
||||||
currentAvatarSettings.animGraphOverrideUrl = MyAvatar.getAnimGraphOverrideUrl();
|
currentAvatarSettings.animGraphOverrideUrl = MyAvatar.getAnimGraphOverrideUrl();
|
||||||
sendToQml({ 'method': 'settingChanged', 'name': 'animGraphOverrideUrl', 'value': currentAvatarSettings.animGraphOverrideUrl })
|
sendToQml({ 'method': 'settingChanged', 'name': 'animGraphOverrideUrl',
|
||||||
|
'value': currentAvatarSettings.animGraphOverrideUrl });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var selectedAvatarEntityGrabbable = false;
|
|
||||||
var selectedAvatarEntityID = null;
|
var selectedAvatarEntityID = null;
|
||||||
var grabbedAvatarEntityChangeNotifier = null;
|
var grabbedAvatarEntityChangeNotifier = null;
|
||||||
|
|
||||||
|
@ -178,6 +179,33 @@ var MARKETPLACE_PURCHASES_QML_PATH = "hifi/commerce/wallet/Wallet.qml";
|
||||||
var MARKETPLACE_URL = Account.metaverseServerURL + "/marketplace";
|
var MARKETPLACE_URL = Account.metaverseServerURL + "/marketplace";
|
||||||
var MARKETPLACES_INJECT_SCRIPT_URL = Script.resolvePath("html/js/marketplacesInject.js");
|
var MARKETPLACES_INJECT_SCRIPT_URL = Script.resolvePath("html/js/marketplacesInject.js");
|
||||||
|
|
||||||
|
function getWearablesFrozen() {
|
||||||
|
var wearablesFrozen = true;
|
||||||
|
var wearablesArray = getMyAvatarWearables();
|
||||||
|
wearablesArray.forEach(function(wearable) {
|
||||||
|
if (isGrabbable(wearable.id)) {
|
||||||
|
wearablesFrozen = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return wearablesFrozen;
|
||||||
|
}
|
||||||
|
|
||||||
|
function freezeWearables() {
|
||||||
|
var wearablesArray = getMyAvatarWearables();
|
||||||
|
wearablesArray.forEach(function(wearable) {
|
||||||
|
setGrabbable(wearable.id, false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function unfreezeWearables() {
|
||||||
|
var wearablesArray = getMyAvatarWearables();
|
||||||
|
wearablesArray.forEach(function(wearable) {
|
||||||
|
setGrabbable(wearable.id, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function fromQml(message) { // messages are {method, params}, like json-rpc. See also sendToQml.
|
function fromQml(message) { // messages are {method, params}, like json-rpc. See also sendToQml.
|
||||||
switch (message.method) {
|
switch (message.method) {
|
||||||
case 'getAvatars':
|
case 'getAvatars':
|
||||||
|
@ -201,7 +229,7 @@ function fromQml(message) { // messages are {method, params}, like json-rpc. See
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sendToQml(message)
|
sendToQml(message);
|
||||||
break;
|
break;
|
||||||
case 'selectAvatar':
|
case 'selectAvatar':
|
||||||
Entities.addingWearable.disconnect(onAddingWearable);
|
Entities.addingWearable.disconnect(onAddingWearable);
|
||||||
|
@ -209,6 +237,7 @@ function fromQml(message) { // messages are {method, params}, like json-rpc. See
|
||||||
AvatarBookmarks.loadBookmark(message.name);
|
AvatarBookmarks.loadBookmark(message.name);
|
||||||
Entities.addingWearable.connect(onAddingWearable);
|
Entities.addingWearable.connect(onAddingWearable);
|
||||||
Entities.deletingWearable.connect(onDeletingWearable);
|
Entities.deletingWearable.connect(onDeletingWearable);
|
||||||
|
sendToQml({ 'method' : 'wearablesFrozenChanged', 'wearablesFrozen' : getWearablesFrozen()});
|
||||||
break;
|
break;
|
||||||
case 'deleteAvatar':
|
case 'deleteAvatar':
|
||||||
AvatarBookmarks.removeBookmark(message.name);
|
AvatarBookmarks.removeBookmark(message.name);
|
||||||
|
@ -228,11 +257,12 @@ function fromQml(message) { // messages are {method, params}, like json-rpc. See
|
||||||
message.properties.localRotationAngles = Quat.safeEulerAngles(message.properties.localRotation);
|
message.properties.localRotationAngles = Quat.safeEulerAngles(message.properties.localRotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
sendToQml({'method' : 'wearableUpdated', 'entityID' : message.entityID, wearableIndex : message.wearableIndex, properties : message.properties, updateUI : false})
|
sendToQml({'method' : 'wearableUpdated', 'entityID' : message.entityID, wearableIndex : message.wearableIndex, properties : message.properties, updateUI : false});
|
||||||
break;
|
break;
|
||||||
case 'adjustWearablesOpened':
|
case 'adjustWearablesOpened':
|
||||||
currentAvatarWearablesBackup = getMyAvatarWearables();
|
currentAvatarWearablesBackup = getMyAvatarWearables();
|
||||||
adjustWearables.setOpened(true);
|
adjustWearables.setOpened(true);
|
||||||
|
unfreezeWearables();
|
||||||
|
|
||||||
Entities.mousePressOnEntity.connect(onSelectedEntity);
|
Entities.mousePressOnEntity.connect(onSelectedEntity);
|
||||||
Messages.subscribe('Hifi-Object-Manipulation');
|
Messages.subscribe('Hifi-Object-Manipulation');
|
||||||
|
@ -305,11 +335,11 @@ function fromQml(message) { // messages are {method, params}, like json-rpc. See
|
||||||
var currentAvatarURL = MyAvatar.getFullAvatarURLFromPreferences();
|
var currentAvatarURL = MyAvatar.getFullAvatarURLFromPreferences();
|
||||||
if(currentAvatarURL !== message.avatarURL) {
|
if(currentAvatarURL !== message.avatarURL) {
|
||||||
MyAvatar.useFullAvatarURL(message.avatarURL);
|
MyAvatar.useFullAvatarURL(message.avatarURL);
|
||||||
sendToQml({'method' : 'externalAvatarApplied', 'avatarURL' : message.avatarURL})
|
sendToQml({'method' : 'externalAvatarApplied', 'avatarURL' : message.avatarURL});
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'navigate':
|
case 'navigate':
|
||||||
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system")
|
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||||
if(message.url.indexOf('app://') === 0) {
|
if(message.url.indexOf('app://') === 0) {
|
||||||
if (message.url === 'app://marketplace') {
|
if (message.url === 'app://marketplace') {
|
||||||
tablet.gotoWebScreen(MARKETPLACE_URL, MARKETPLACES_INJECT_SCRIPT_URL);
|
tablet.gotoWebScreen(MARKETPLACE_URL, MARKETPLACES_INJECT_SCRIPT_URL);
|
||||||
|
@ -345,7 +375,17 @@ function fromQml(message) { // messages are {method, params}, like json-rpc. See
|
||||||
MyAvatar.collisionSoundURL = message.settings.collisionSoundUrl;
|
MyAvatar.collisionSoundURL = message.settings.collisionSoundUrl;
|
||||||
MyAvatar.setAnimGraphOverrideUrl(message.settings.animGraphOverrideUrl);
|
MyAvatar.setAnimGraphOverrideUrl(message.settings.animGraphOverrideUrl);
|
||||||
|
|
||||||
settings = getMyAvatarSettings();
|
currentAvatarSettings = getMyAvatarSettings();
|
||||||
|
break;
|
||||||
|
case 'toggleWearablesFrozen':
|
||||||
|
var wearablesFrozen = getWearablesFrozen();
|
||||||
|
wearablesFrozen = !wearablesFrozen;
|
||||||
|
if (wearablesFrozen) {
|
||||||
|
freezeWearables();
|
||||||
|
} else {
|
||||||
|
unfreezeWearables();
|
||||||
|
}
|
||||||
|
sendToQml({'method' : 'wearablesFrozenChanged', 'wearablesFrozen' : wearablesFrozen});
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
print('Unrecognized message from AvatarApp.qml');
|
print('Unrecognized message from AvatarApp.qml');
|
||||||
|
@ -366,9 +406,11 @@ function isGrabbable(entityID) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function setGrabbable(entityID, grabbable) {
|
function setGrabbable(entityID, grabbable) {
|
||||||
var properties = Entities.getEntityProperties(entityID, ['avatarEntity']);
|
var properties = Entities.getEntityProperties(entityID, ['avatarEntity', 'grab.grabbable']);
|
||||||
if (properties.avatarEntity) {
|
if (properties.avatarEntity && properties.grab.grabbable != grabbable) {
|
||||||
Entities.editEntity(entityID, { grab: { grabbable: grabbable }});
|
var editProps = { grab: { grabbable: grabbable }};
|
||||||
|
Entities.editEntity(entityID, editProps);
|
||||||
|
sendToQml({ 'method' : 'wearablesFrozenChanged', 'wearablesFrozen' : getWearablesFrozen()});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -378,18 +420,7 @@ function ensureWearableSelected(entityID) {
|
||||||
Script.clearInterval(grabbedAvatarEntityChangeNotifier);
|
Script.clearInterval(grabbedAvatarEntityChangeNotifier);
|
||||||
grabbedAvatarEntityChangeNotifier = null;
|
grabbedAvatarEntityChangeNotifier = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(selectedAvatarEntityID !== null) {
|
|
||||||
setGrabbable(selectedAvatarEntityID, selectedAvatarEntityGrabbable);
|
|
||||||
}
|
|
||||||
|
|
||||||
selectedAvatarEntityID = entityID;
|
selectedAvatarEntityID = entityID;
|
||||||
selectedAvatarEntityGrabbable = isGrabbable(entityID);
|
|
||||||
|
|
||||||
if(selectedAvatarEntityID !== null) {
|
|
||||||
setGrabbable(selectedAvatarEntityID, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -398,7 +429,7 @@ function ensureWearableSelected(entityID) {
|
||||||
|
|
||||||
function isEntityBeingWorn(entityID) {
|
function isEntityBeingWorn(entityID) {
|
||||||
return Entities.getEntityProperties(entityID, 'parentID').parentID === MyAvatar.sessionUUID;
|
return Entities.getEntityProperties(entityID, 'parentID').parentID === MyAvatar.sessionUUID;
|
||||||
};
|
}
|
||||||
|
|
||||||
function onSelectedEntity(entityID, pointerEvent) {
|
function onSelectedEntity(entityID, pointerEvent) {
|
||||||
if(selectedAvatarEntityID !== entityID && isEntityBeingWorn(entityID))
|
if(selectedAvatarEntityID !== entityID && isEntityBeingWorn(entityID))
|
||||||
|
@ -413,12 +444,14 @@ function onAddingWearable(entityID) {
|
||||||
updateAvatarWearables(currentAvatar, function() {
|
updateAvatarWearables(currentAvatar, function() {
|
||||||
sendToQml({'method' : 'updateAvatarInBookmarks'});
|
sendToQml({'method' : 'updateAvatarInBookmarks'});
|
||||||
});
|
});
|
||||||
|
sendToQml({ 'method' : 'wearablesFrozenChanged', 'wearablesFrozen' : getWearablesFrozen()});
|
||||||
}
|
}
|
||||||
|
|
||||||
function onDeletingWearable(entityID) {
|
function onDeletingWearable(entityID) {
|
||||||
updateAvatarWearables(currentAvatar, function() {
|
updateAvatarWearables(currentAvatar, function() {
|
||||||
sendToQml({'method' : 'updateAvatarInBookmarks'});
|
sendToQml({'method' : 'updateAvatarInBookmarks'});
|
||||||
});
|
});
|
||||||
|
sendToQml({ 'method' : 'wearablesFrozenChanged', 'wearablesFrozen' : getWearablesFrozen()});
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleWearableMessages(channel, message, sender) {
|
function handleWearableMessages(channel, message, sender) {
|
||||||
|
@ -435,30 +468,35 @@ function handleWearableMessages(channel, message, sender) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var entityID = parsedMessage.grabbedEntity;
|
var entityID = parsedMessage.grabbedEntity;
|
||||||
|
|
||||||
|
var updateWearable = function() {
|
||||||
|
// for some reasons Entities.getEntityProperties returns more than was asked..
|
||||||
|
var propertyNames = ['localPosition', 'localRotation', 'dimensions', 'naturalDimensions'];
|
||||||
|
var entityProperties = Entities.getEntityProperties(selectedAvatarEntityID, propertyNames);
|
||||||
|
var properties = {};
|
||||||
|
|
||||||
|
propertyNames.forEach(function(propertyName) {
|
||||||
|
properties[propertyName] = entityProperties[propertyName];
|
||||||
|
});
|
||||||
|
|
||||||
|
properties.localRotationAngles = Quat.safeEulerAngles(properties.localRotation);
|
||||||
|
sendToQml({'method' : 'wearableUpdated', 'entityID' : selectedAvatarEntityID,
|
||||||
|
'wearableIndex' : -1, 'properties' : properties, updateUI : true});
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
if(parsedMessage.action === 'grab') {
|
if(parsedMessage.action === 'grab') {
|
||||||
if(selectedAvatarEntityID !== entityID) {
|
if(selectedAvatarEntityID !== entityID) {
|
||||||
ensureWearableSelected(entityID);
|
ensureWearableSelected(entityID);
|
||||||
sendToQml({'method' : 'selectAvatarEntity', 'entityID' : selectedAvatarEntityID});
|
sendToQml({'method' : 'selectAvatarEntity', 'entityID' : selectedAvatarEntityID});
|
||||||
}
|
}
|
||||||
|
|
||||||
grabbedAvatarEntityChangeNotifier = Script.setInterval(function() {
|
grabbedAvatarEntityChangeNotifier = Script.setInterval(updateWearable, 1000);
|
||||||
// for some reasons Entities.getEntityProperties returns more than was asked..
|
|
||||||
var propertyNames = ['localPosition', 'localRotation', 'dimensions', 'naturalDimensions'];
|
|
||||||
var entityProperties = Entities.getEntityProperties(selectedAvatarEntityID, propertyNames);
|
|
||||||
var properties = {}
|
|
||||||
|
|
||||||
propertyNames.forEach(function(propertyName) {
|
|
||||||
properties[propertyName] = entityProperties[propertyName];
|
|
||||||
})
|
|
||||||
|
|
||||||
properties.localRotationAngles = Quat.safeEulerAngles(properties.localRotation);
|
|
||||||
sendToQml({'method' : 'wearableUpdated', 'entityID' : selectedAvatarEntityID, 'wearableIndex' : -1, 'properties' : properties, updateUI : true})
|
|
||||||
|
|
||||||
}, 1000);
|
|
||||||
} else if(parsedMessage.action === 'release') {
|
} else if(parsedMessage.action === 'release') {
|
||||||
if(grabbedAvatarEntityChangeNotifier !== null) {
|
if(grabbedAvatarEntityChangeNotifier !== null) {
|
||||||
Script.clearInterval(grabbedAvatarEntityChangeNotifier);
|
Script.clearInterval(grabbedAvatarEntityChangeNotifier);
|
||||||
grabbedAvatarEntityChangeNotifier = null;
|
grabbedAvatarEntityChangeNotifier = null;
|
||||||
|
updateWearable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -481,8 +519,8 @@ function onBookmarkDeleted(bookmarkName) {
|
||||||
function onBookmarkAdded(bookmarkName) {
|
function onBookmarkAdded(bookmarkName) {
|
||||||
var bookmark = AvatarBookmarks.getBookmark(bookmarkName);
|
var bookmark = AvatarBookmarks.getBookmark(bookmarkName);
|
||||||
bookmark.avatarEntites.forEach(function(avatarEntity) {
|
bookmark.avatarEntites.forEach(function(avatarEntity) {
|
||||||
avatarEntity.properties.localRotationAngles = Quat.safeEulerAngles(avatarEntity.properties.localRotation)
|
avatarEntity.properties.localRotationAngles = Quat.safeEulerAngles(avatarEntity.properties.localRotation);
|
||||||
})
|
});
|
||||||
|
|
||||||
sendToQml({ 'method': 'bookmarkAdded', 'bookmarkName': bookmarkName, 'bookmark': bookmark });
|
sendToQml({ 'method': 'bookmarkAdded', 'bookmarkName': bookmarkName, 'bookmark': bookmark });
|
||||||
}
|
}
|
||||||
|
@ -601,14 +639,8 @@ function onTabletScreenChanged(type, url) {
|
||||||
onAvatarAppScreen = onAvatarAppScreenNow;
|
onAvatarAppScreen = onAvatarAppScreenNow;
|
||||||
|
|
||||||
if(onAvatarAppScreenNow) {
|
if(onAvatarAppScreenNow) {
|
||||||
var message = {
|
sendToQml({ 'method' : 'initialize', 'data' : { jointNames : MyAvatar.getJointNames() }});
|
||||||
'method' : 'initialize',
|
sendToQml({ 'method' : 'wearablesFrozenChanged', 'wearablesFrozen' : getWearablesFrozen()});
|
||||||
'data' : {
|
|
||||||
'jointNames' : MyAvatar.getJointNames()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
sendToQml(message)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -341,8 +341,6 @@ entityIsGrabbable = function (eigProps) {
|
||||||
var grabbable = getGrabbableData(eigProps).grabbable;
|
var grabbable = getGrabbableData(eigProps).grabbable;
|
||||||
if (!grabbable ||
|
if (!grabbable ||
|
||||||
eigProps.locked ||
|
eigProps.locked ||
|
||||||
isAnothersAvatarEntity(eigProps) ||
|
|
||||||
isAnothersChildEntity(eigProps) ||
|
|
||||||
FORBIDDEN_GRAB_TYPES.indexOf(eigProps.type) >= 0) {
|
FORBIDDEN_GRAB_TYPES.indexOf(eigProps.type) >= 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue