diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index d78d83bc09..a7cd5ccb5e 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -75,8 +75,11 @@ size_t AvatarDataPacket::maxJointDataSize(size_t numJoints, bool hasGrabJoints) totalSize += numJoints * sizeof(SixByteTrans); // Translations size_t NUM_FAUX_JOINT = 2; - size_t num_grab_joints = (hasGrabJoints ? 2 : 0); - totalSize += (NUM_FAUX_JOINT + num_grab_joints) * (sizeof(SixByteQuat) + sizeof(SixByteTrans)); // faux joints + totalSize += NUM_FAUX_JOINT * (sizeof(SixByteQuat) + sizeof(SixByteTrans)); // faux joints + + if (hasGrabJoints) { + totalSize += sizeof(AvatarDataPacket::FarGrabJoints); + } return totalSize; } @@ -690,7 +693,7 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent if (hasGrabJoints) { // the far-grab joints may range further than 3 meters, so we can't use packFloatVec3ToSignedTwoByteFixed etc auto startSection = destinationBuffer; - auto data = reinterpret_cast(destinationBuffer); + glm::vec3 leftFarGrabPosition = extractTranslation(leftFarGrabMatrix); glm::quat leftFarGrabRotation = extractRotation(leftFarGrabMatrix); glm::vec3 rightFarGrabPosition = extractTranslation(rightFarGrabMatrix); @@ -698,28 +701,17 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent glm::vec3 mouseFarGrabPosition = extractTranslation(mouseFarGrabMatrix); glm::quat mouseFarGrabRotation = extractRotation(mouseFarGrabMatrix); - AVATAR_MEMCPY(leftFarGrabPosition); - // Can't do block copy as struct order is x, y, z, w. - data->leftFarGrabRotation[0] = leftFarGrabRotation.w; - data->leftFarGrabRotation[1] = leftFarGrabRotation.x; - data->leftFarGrabRotation[2] = leftFarGrabRotation.y; - data->leftFarGrabRotation[3] = leftFarGrabRotation.z; - destinationBuffer += sizeof(data->leftFarGrabPosition); - - AVATAR_MEMCPY(rightFarGrabPosition); - data->rightFarGrabRotation[0] = rightFarGrabRotation.w; - data->rightFarGrabRotation[1] = rightFarGrabRotation.x; - data->rightFarGrabRotation[2] = rightFarGrabRotation.y; - data->rightFarGrabRotation[3] = rightFarGrabRotation.z; - destinationBuffer += sizeof(data->rightFarGrabRotation); - - AVATAR_MEMCPY(mouseFarGrabPosition); - data->mouseFarGrabRotation[0] = mouseFarGrabRotation.w; - data->mouseFarGrabRotation[1] = mouseFarGrabRotation.x; - data->mouseFarGrabRotation[2] = mouseFarGrabRotation.y; - data->mouseFarGrabRotation[3] = mouseFarGrabRotation.z; - destinationBuffer += sizeof(data->mouseFarGrabRotation); + AvatarDataPacket::FarGrabJoints farGrabJoints = { + { leftFarGrabPosition.x, leftFarGrabPosition.y, leftFarGrabPosition.z }, + { leftFarGrabRotation.w, leftFarGrabRotation.x, leftFarGrabRotation.y, leftFarGrabRotation.z }, + { rightFarGrabPosition.x, rightFarGrabPosition.y, rightFarGrabPosition.z }, + { rightFarGrabRotation.w, rightFarGrabRotation.x, rightFarGrabRotation.y, rightFarGrabRotation.z }, + { mouseFarGrabPosition.x, mouseFarGrabPosition.y, mouseFarGrabPosition.z }, + { mouseFarGrabRotation.w, mouseFarGrabRotation.x, mouseFarGrabRotation.y, mouseFarGrabRotation.z } + }; + memcpy(destinationBuffer, &farGrabJoints, sizeof(farGrabJoints)); + destinationBuffer += sizeof(AvatarDataPacket::FarGrabJoints); int numBytes = destinationBuffer - startSection; if (outboundDataRateOut) { @@ -1250,25 +1242,37 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { auto startSection = sourceBuffer; PACKET_READ_CHECK(FarGrabJoints, sizeof(AvatarDataPacket::FarGrabJoints)); - auto data = reinterpret_cast(sourceBuffer); - glm::vec3 leftFarGrabPosition = glm::vec3(data->leftFarGrabPosition[0], data->leftFarGrabPosition[1], - data->leftFarGrabPosition[2]); - glm::quat leftFarGrabRotation = glm::quat(data->leftFarGrabRotation[0], data->leftFarGrabRotation[1], - data->leftFarGrabRotation[2], data->leftFarGrabRotation[3]); - glm::vec3 rightFarGrabPosition = glm::vec3(data->rightFarGrabPosition[0], data->rightFarGrabPosition[1], - data->rightFarGrabPosition[2]); - glm::quat rightFarGrabRotation = glm::quat(data->rightFarGrabRotation[0], data->rightFarGrabRotation[1], - data->rightFarGrabRotation[2], data->rightFarGrabRotation[3]); - glm::vec3 mouseFarGrabPosition = glm::vec3(data->mouseFarGrabPosition[0], data->mouseFarGrabPosition[1], - data->mouseFarGrabPosition[2]); - glm::quat mouseFarGrabRotation = glm::quat(data->mouseFarGrabRotation[0], data->mouseFarGrabRotation[1], - data->mouseFarGrabRotation[2], data->mouseFarGrabRotation[3]); + + AvatarDataPacket::FarGrabJoints farGrabJoints; + memcpy(&farGrabJoints, sourceBuffer, sizeof(farGrabJoints)); // to avoid misaligned floats + + glm::vec3 leftFarGrabPosition = glm::vec3(farGrabJoints.leftFarGrabPosition[0], + farGrabJoints.leftFarGrabPosition[1], + farGrabJoints.leftFarGrabPosition[2]); + glm::quat leftFarGrabRotation = glm::quat(farGrabJoints.leftFarGrabRotation[0], + farGrabJoints.leftFarGrabRotation[1], + farGrabJoints.leftFarGrabRotation[2], + farGrabJoints.leftFarGrabRotation[3]); + glm::vec3 rightFarGrabPosition = glm::vec3(farGrabJoints.rightFarGrabPosition[0], + farGrabJoints.rightFarGrabPosition[1], + farGrabJoints.rightFarGrabPosition[2]); + glm::quat rightFarGrabRotation = glm::quat(farGrabJoints.rightFarGrabRotation[0], + farGrabJoints.rightFarGrabRotation[1], + farGrabJoints.rightFarGrabRotation[2], + farGrabJoints.rightFarGrabRotation[3]); + glm::vec3 mouseFarGrabPosition = glm::vec3(farGrabJoints.mouseFarGrabPosition[0], + farGrabJoints.mouseFarGrabPosition[1], + farGrabJoints.mouseFarGrabPosition[2]); + glm::quat mouseFarGrabRotation = glm::quat(farGrabJoints.mouseFarGrabRotation[0], + farGrabJoints.mouseFarGrabRotation[1], + farGrabJoints.mouseFarGrabRotation[2], + farGrabJoints.mouseFarGrabRotation[3]); _farGrabLeftMatrixCache.set(createMatFromQuatAndPos(leftFarGrabRotation, leftFarGrabPosition)); _farGrabRightMatrixCache.set(createMatFromQuatAndPos(rightFarGrabRotation, rightFarGrabPosition)); _farGrabMouseMatrixCache.set(createMatFromQuatAndPos(mouseFarGrabRotation, mouseFarGrabPosition)); - sourceBuffer += sizeof(AvatarDataPacket::AvatarGlobalPosition); + sourceBuffer += sizeof(AvatarDataPacket::FarGrabJoints); int numBytesRead = sourceBuffer - startSection; _farGrabJointRate.increment(numBytesRead); _farGrabJointUpdateRate.increment(); diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 184bb054ea..91f31a386f 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -131,6 +131,10 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param requestedProperties += PROP_CLONE_AVATAR_ENTITY; requestedProperties += PROP_CLONE_ORIGIN_ID; + withReadLock([&] { + requestedProperties += _grabProperties.getEntityProperties(params); + }); + return requestedProperties; } @@ -168,6 +172,9 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet EntityPropertyFlags propertyFlags(PROP_LAST_ITEM); EntityPropertyFlags requestedProperties = getEntityProperties(params); + requestedProperties -= PROP_CLIENT_ONLY; + requestedProperties -= PROP_OWNING_AVATAR_ID; + // If we are being called for a subsequent pass at appendEntityData() that failed to completely encode this item, // then our entityTreeElementExtraEncodeData should include data about which properties we need to append. if (entityTreeElementExtraEncodeData && entityTreeElementExtraEncodeData->entities.contains(getEntityItemID())) { @@ -300,7 +307,12 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet APPEND_ENTITY_PROPERTY(PROP_CLONE_LIMIT, getCloneLimit()); APPEND_ENTITY_PROPERTY(PROP_CLONE_DYNAMIC, getCloneDynamic()); APPEND_ENTITY_PROPERTY(PROP_CLONE_AVATAR_ENTITY, getCloneAvatarEntity()); - APPEND_ENTITY_PROPERTY(PROP_CLONE_ORIGIN_ID, getCloneOriginID()); + APPEND_ENTITY_PROPERTY(PROP_CLONE_ORIGIN_ID, getCloneOriginID()); + + withReadLock([&] { + _grabProperties.appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, requestedProperties, + propertyFlags, propertiesDidntFit, propertyCount, appendState); + }); appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, requestedProperties, @@ -892,7 +904,15 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef READ_ENTITY_PROPERTY(PROP_CLONE_LIMIT, float, setCloneLimit); READ_ENTITY_PROPERTY(PROP_CLONE_DYNAMIC, bool, setCloneDynamic); READ_ENTITY_PROPERTY(PROP_CLONE_AVATAR_ENTITY, bool, setCloneAvatarEntity); - READ_ENTITY_PROPERTY(PROP_CLONE_ORIGIN_ID, QUuid, setCloneOriginID); + READ_ENTITY_PROPERTY(PROP_CLONE_ORIGIN_ID, QUuid, setCloneOriginID); + + withWriteLock([&] { + int bytesFromGrab = _grabProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, + propertyFlags, overwriteLocalData, + somethingChanged); + bytesRead += bytesFromGrab; + dataAt += bytesFromGrab; + }); bytesRead += readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, propertyFlags, overwriteLocalData, somethingChanged); @@ -1329,6 +1349,10 @@ EntityItemProperties EntityItem::getProperties(const EntityPropertyFlags& desire COPY_ENTITY_PROPERTY_TO_PROPERTIES(cloneAvatarEntity, getCloneAvatarEntity); COPY_ENTITY_PROPERTY_TO_PROPERTIES(cloneOriginID, getCloneOriginID); + withReadLock([&] { + _grabProperties.getProperties(properties); + }); + properties._defaultSettings = false; return properties; @@ -1465,6 +1489,11 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(cloneAvatarEntity, setCloneAvatarEntity); SET_ENTITY_PROPERTY_FROM_PROPERTIES(cloneOriginID, setCloneOriginID); + withWriteLock([&] { + bool grabPropertiesChanged = _grabProperties.setProperties(properties); + somethingChanged |= grabPropertiesChanged; + }); + if (updateQueryAACube()) { somethingChanged = true; } diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 0e5cae66b6..6d99f3e3c7 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -35,6 +35,7 @@ #include "SimulationOwner.h" #include "SimulationFlags.h" #include "EntityDynamicInterface.h" +#include "GrabPropertyGroup.h" #include "graphics/Material.h" @@ -533,6 +534,8 @@ public: void setCloneIDs(const QVector& cloneIDs); void setVisuallyReady(bool visuallyReady) { _visuallyReady = visuallyReady; } + const GrabPropertyGroup& getGrabProperties() const { return _grabProperties; } + signals: void requestRenderUpdate(); void spaceUpdate(std::pair data); @@ -711,6 +714,8 @@ protected: QUuid _cloneOriginID; QVector _cloneIDs; + GrabPropertyGroup _grabProperties; + private: std::unordered_map _materials; std::mutex _materialsLock; diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 7e404afa3f..07dacf4cf3 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -40,6 +40,7 @@ HazePropertyGroup EntityItemProperties::_staticHaze; BloomPropertyGroup EntityItemProperties::_staticBloom; KeyLightPropertyGroup EntityItemProperties::_staticKeyLight; AmbientLightPropertyGroup EntityItemProperties::_staticAmbientLight; +GrabPropertyGroup EntityItemProperties::_staticGrab; EntityPropertyList PROP_LAST_ITEM = (EntityPropertyList)(PROP_AFTER_LAST_ITEM - 1); @@ -86,6 +87,7 @@ void EntityItemProperties::debugDump() const { getKeyLight().debugDump(); getAmbientLight().debugDump(); getBloom().debugDump(); + getGrab().debugDump(); qCDebug(entities) << " changed properties..."; EntityPropertyFlags props = getChangedProperties(); @@ -471,6 +473,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { changedProperties += _skybox.getChangedProperties(); changedProperties += _haze.getChangedProperties(); changedProperties += _bloom.getChangedProperties(); + changedProperties += _grab.getChangedProperties(); return changedProperties; } @@ -628,6 +631,8 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { * avatar entities: their clientOnly property will be set to true. * @property {Uuid} cloneOriginID - The ID of the entity that this entity was cloned from. * + * @property {Entities.Grab} grab - The grab-related properties. + * * @property {string} itemName="" - Certifiable name of the Marketplace item. * @property {string} itemDescription="" - Certifiable description of the Marketplace item. * @property {string} itemCategories="" - Certifiable category of the Marketplace item. @@ -1530,6 +1535,8 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CLONE_AVATAR_ENTITY, cloneAvatarEntity); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CLONE_ORIGIN_ID, cloneOriginID); + _grab.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties); + // Rendering info if (!skipDefaults && !strictSemantics && (!psuedoPropertyFlagsActive || psueudoPropertyFlags.test(EntityPsuedoPropertyFlag::RenderInfo))) { @@ -1700,7 +1707,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(strokeColors, qVectorVec3, setStrokeColors); COPY_PROPERTY_FROM_QSCRIPTVALUE(strokeWidths,qVectorFloat, setStrokeWidths); COPY_PROPERTY_FROM_QSCRIPTVALUE(isUVModeStretch, bool, setIsUVModeStretch); - + if (!honorReadOnly) { // this is used by the json reader to set things that we don't want javascript to able to affect. @@ -1718,6 +1725,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool _skybox.copyFromScriptValue(object, _defaultSettings); _haze.copyFromScriptValue(object, _defaultSettings); _bloom.copyFromScriptValue(object, _defaultSettings); + _grab.copyFromScriptValue(object, _defaultSettings); COPY_PROPERTY_FROM_QSCRIPTVALUE(xTextureURL, QString, setXTextureURL); COPY_PROPERTY_FROM_QSCRIPTVALUE(yTextureURL, QString, setYTextureURL); @@ -1883,6 +1891,7 @@ void EntityItemProperties::merge(const EntityItemProperties& other) { _skybox.merge(other._skybox); _haze.merge(other._haze); _bloom.merge(other._bloom); + _grab.merge(other._grab); COPY_PROPERTY_IF_CHANGED(xTextureURL); COPY_PROPERTY_IF_CHANGED(yTextureURL); @@ -2172,6 +2181,26 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue ADD_PROPERTY_TO_MAP(PROP_CLONE_AVATAR_ENTITY, CloneAvatarEntity, cloneAvatarEntity, bool); ADD_PROPERTY_TO_MAP(PROP_CLONE_ORIGIN_ID, CloneOriginID, cloneOriginID, QUuid); + ADD_GROUP_PROPERTY_TO_MAP(PROP_GRAB_GRABBABLE, Grab, grab, Grabbable, grabbable); + ADD_GROUP_PROPERTY_TO_MAP(PROP_GRAB_KINEMATIC, Grab, grab, GrabKinematic, grabKinematic); + ADD_GROUP_PROPERTY_TO_MAP(PROP_GRAB_FOLLOWS_CONTROLLER, Grab, grab, GrabFollowsController, grabFollowsController); + ADD_GROUP_PROPERTY_TO_MAP(PROP_GRAB_TRIGGERABLE, Grab, grab, Triggerable, triggerable); + ADD_GROUP_PROPERTY_TO_MAP(PROP_GRAB_EQUIPPABLE, Grab, grab, Equippable, equippable); + ADD_GROUP_PROPERTY_TO_MAP(PROP_GRAB_LEFT_EQUIPPABLE_POSITION_OFFSET, Grab, grab, + EquippableLeftPosition, equippableLeftPosition); + ADD_GROUP_PROPERTY_TO_MAP(PROP_GRAB_LEFT_EQUIPPABLE_ROTATION_OFFSET, Grab, grab, + EquippableLeftRotation, equippableLeftRotation); + ADD_GROUP_PROPERTY_TO_MAP(PROP_GRAB_RIGHT_EQUIPPABLE_POSITION_OFFSET, Grab, grab, + EquippableRightPosition, equippableRightPosition); + ADD_GROUP_PROPERTY_TO_MAP(PROP_GRAB_RIGHT_EQUIPPABLE_ROTATION_OFFSET, Grab, grab, + EquippableRightRotation, equippableRightRotation); + ADD_GROUP_PROPERTY_TO_MAP(PROP_GRAB_EQUIPPABLE_INDICATOR_URL, Grab, grab, + EquippableIndicatorURL, equippableIndicatorURL); + ADD_GROUP_PROPERTY_TO_MAP(PROP_GRAB_EQUIPPABLE_INDICATOR_SCALE, Grab, grab, + EquippableIndicatorScale, equippableIndicatorScale); + ADD_GROUP_PROPERTY_TO_MAP(PROP_GRAB_EQUIPPABLE_INDICATOR_OFFSET, Grab, grab, + EquippableIndicatorOffset, equippableIndicatorOffset); + // FIXME - these are not yet handled //ADD_PROPERTY_TO_MAP(PROP_CREATED, Created, created, quint64); @@ -2501,6 +2530,10 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy APPEND_ENTITY_PROPERTY(PROP_CLONE_LIMIT, properties.getCloneLimit()); APPEND_ENTITY_PROPERTY(PROP_CLONE_DYNAMIC, properties.getCloneDynamic()); APPEND_ENTITY_PROPERTY(PROP_CLONE_AVATAR_ENTITY, properties.getCloneAvatarEntity()); + + _staticGrab.setProperties(properties); + _staticGrab.appendToEditPacket(packetData, requestedProperties, propertyFlags, + propertiesDidntFit, propertyCount, appendState); } if (propertyCount > 0) { @@ -2794,7 +2827,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_FLYING_ALLOWED, bool, setFlyingAllowed); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_GHOSTING_ALLOWED, bool, setGhostingAllowed); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_FILTER_URL, QString, setFilterURL); - + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_HAZE_MODE, uint32_t, setHazeMode); properties.getHaze().decodeFromEditPacket(propertyFlags, dataAt, processedBytes); @@ -2881,6 +2914,8 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CLONE_DYNAMIC, bool, setCloneDynamic); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CLONE_AVATAR_ENTITY, bool, setCloneAvatarEntity); + properties.getGrab().decodeFromEditPacket(propertyFlags, dataAt, processedBytes); + return valid; } @@ -3120,6 +3155,7 @@ void EntityItemProperties::markAllChanged() { _skybox.markAllChanged(); _haze.markAllChanged(); _bloom.markAllChanged(); + _grab.markAllChanged(); _sourceUrlChanged = true; _voxelVolumeSizeChanged = true; @@ -3654,6 +3690,7 @@ QList EntityItemProperties::listChangedProperties() { getSkybox().listChangedProperties(out); getHaze().listChangedProperties(out); getBloom().listChangedProperties(out); + getGrab().listChangedProperties(out); return out; } diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 338ec5e071..b33d11efc0 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -292,6 +292,8 @@ public: DEFINE_PROPERTY(PROP_CLONE_AVATAR_ENTITY, CloneAvatarEntity, cloneAvatarEntity, bool, ENTITY_ITEM_DEFAULT_CLONE_AVATAR_ENTITY); DEFINE_PROPERTY_REF(PROP_CLONE_ORIGIN_ID, CloneOriginID, cloneOriginID, QUuid, ENTITY_ITEM_DEFAULT_CLONE_ORIGIN_ID); + DEFINE_PROPERTY_GROUP(Grab, grab, GrabPropertyGroup); + static QString getComponentModeString(uint32_t mode); static QString getComponentModeAsString(uint32_t mode); diff --git a/libraries/entities/src/EntityPropertyFlags.cpp b/libraries/entities/src/EntityPropertyFlags.cpp new file mode 100644 index 0000000000..c077b153b8 --- /dev/null +++ b/libraries/entities/src/EntityPropertyFlags.cpp @@ -0,0 +1,207 @@ + +#include "EntityPropertyFlags.h" + + +QDebug& operator<<(QDebug& dbg, const EntityPropertyFlags& f) { + QString result = "[ "; + + result = f.getHasProperty(PROP_PAGED_PROPERTY) ? result + "pagedProperty " : result; + result = f.getHasProperty(PROP_CUSTOM_PROPERTIES_INCLUDED) ? result + "customPropertiesIncluded " : result; + result = f.getHasProperty(PROP_VISIBLE) ? result + "visible " : result; + result = f.getHasProperty(PROP_CAN_CAST_SHADOW) ? result + "canCastShadow " : result; + result = f.getHasProperty(PROP_POSITION) ? result + "position " : result; + result = f.getHasProperty(PROP_DIMENSIONS) ? result + "dimensions " : result; + result = f.getHasProperty(PROP_ROTATION) ? result + "rotation " : result; + result = f.getHasProperty(PROP_DENSITY) ? result + "density " : result; + result = f.getHasProperty(PROP_VELOCITY) ? result + "velocity " : result; + result = f.getHasProperty(PROP_GRAVITY) ? result + "gravity " : result; + result = f.getHasProperty(PROP_DAMPING) ? result + "damping " : result; + result = f.getHasProperty(PROP_LIFETIME) ? result + "lifetime " : result; + result = f.getHasProperty(PROP_SCRIPT) ? result + "script " : result; + result = f.getHasProperty(PROP_COLOR) ? result + "color " : result; + result = f.getHasProperty(PROP_MODEL_URL) ? result + "modelUrl " : result; + result = f.getHasProperty(PROP_ANIMATION_URL) ? result + "animationUrl " : result; + result = f.getHasProperty(PROP_ANIMATION_FPS) ? result + "animationFps " : result; + result = f.getHasProperty(PROP_ANIMATION_FRAME_INDEX) ? result + "animationFrameIndex " : result; + result = f.getHasProperty(PROP_ANIMATION_PLAYING) ? result + "animationPlaying " : result; + result = f.getHasProperty(PROP_ANIMATION_ALLOW_TRANSLATION) ? result + "animationAllowTranslation " : result; + result = f.getHasProperty(PROP_RELAY_PARENT_JOINTS) ? result + "relayParentJoints " : result; + result = f.getHasProperty(PROP_REGISTRATION_POINT) ? result + "registrationPoint " : result; + result = f.getHasProperty(PROP_ANGULAR_VELOCITY) ? result + "angularVelocity " : result; + result = f.getHasProperty(PROP_ANGULAR_DAMPING) ? result + "angularDamping " : result; + result = f.getHasProperty(PROP_COLLISIONLESS) ? result + "collisionless " : result; + result = f.getHasProperty(PROP_DYNAMIC) ? result + "dynamic " : result; + result = f.getHasProperty(PROP_IS_SPOTLIGHT) ? result + "isSpotlight " : result; + result = f.getHasProperty(PROP_DIFFUSE_COLOR) ? result + "diffuseColor " : result; + result = f.getHasProperty(PROP_AMBIENT_COLOR_UNUSED) ? result + "ambientColorUnused " : result; + result = f.getHasProperty(PROP_SPECULAR_COLOR_UNUSED) ? result + "specularColorUnused " : result; + result = f.getHasProperty(PROP_INTENSITY) ? result + "intensity " : result; + result = f.getHasProperty(PROP_LINEAR_ATTENUATION_UNUSED) ? result + "linearAttenuationUnused " : result; + result = f.getHasProperty(PROP_QUADRATIC_ATTENUATION_UNUSED) ? result + "quadraticAttenuationUnused " : result; + result = f.getHasProperty(PROP_EXPONENT) ? result + "exponent " : result; + result = f.getHasProperty(PROP_CUTOFF) ? result + "cutoff " : result; + result = f.getHasProperty(PROP_LOCKED) ? result + "locked " : result; + result = f.getHasProperty(PROP_TEXTURES) ? result + "textures " : result; + result = f.getHasProperty(PROP_ANIMATION_SETTINGS_UNUSED) ? result + "animationSettingsUnused " : result; + result = f.getHasProperty(PROP_USER_DATA) ? result + "userData " : result; + result = f.getHasProperty(PROP_SHAPE_TYPE) ? result + "shapeType " : result; + result = f.getHasProperty(PROP_MAX_PARTICLES) ? result + "maxParticles " : result; + result = f.getHasProperty(PROP_LIFESPAN) ? result + "lifespan " : result; + result = f.getHasProperty(PROP_EMIT_RATE) ? result + "emitRate " : result; + result = f.getHasProperty(PROP_EMIT_SPEED) ? result + "emitSpeed " : result; + result = f.getHasProperty(PROP_EMIT_STRENGTH) ? result + "emitStrength " : result; + result = f.getHasProperty(PROP_EMIT_ACCELERATION) ? result + "emitAcceleration " : result; + result = f.getHasProperty(PROP_PARTICLE_RADIUS) ? result + "particleRadius " : result; + result = f.getHasProperty(PROP_COMPOUND_SHAPE_URL) ? result + "compoundShapeUrl " : result; + result = f.getHasProperty(PROP_MARKETPLACE_ID) ? result + "marketplaceID " : result; + result = f.getHasProperty(PROP_ACCELERATION) ? result + "acceleration " : result; + result = f.getHasProperty(PROP_SIMULATION_OWNER) ? result + "simulationOwner " : result; + result = f.getHasProperty(PROP_NAME) ? result + "name " : result; + result = f.getHasProperty(PROP_COLLISION_SOUND_URL) ? result + "collisionSoundUrl " : result; + result = f.getHasProperty(PROP_RESTITUTION) ? result + "restitution " : result; + result = f.getHasProperty(PROP_FRICTION) ? result + "friction " : result; + result = f.getHasProperty(PROP_VOXEL_VOLUME_SIZE) ? result + "voxelVolumeSize " : result; + result = f.getHasProperty(PROP_VOXEL_DATA) ? result + "voxelData " : result; + result = f.getHasProperty(PROP_VOXEL_SURFACE_STYLE) ? result + "voxelSurfaceStyle " : result; + result = f.getHasProperty(PROP_LINE_WIDTH) ? result + "lineWidth " : result; + result = f.getHasProperty(PROP_LINE_POINTS) ? result + "linePoints " : result; + result = f.getHasProperty(PROP_HREF) ? result + "href " : result; + result = f.getHasProperty(PROP_DESCRIPTION) ? result + "description " : result; + result = f.getHasProperty(PROP_FACE_CAMERA) ? result + "faceCamera " : result; + result = f.getHasProperty(PROP_SCRIPT_TIMESTAMP) ? result + "scriptTimestamp " : result; + result = f.getHasProperty(PROP_ACTION_DATA) ? result + "actionData " : result; + result = f.getHasProperty(PROP_X_TEXTURE_URL) ? result + "xTextureUrl " : result; + result = f.getHasProperty(PROP_Y_TEXTURE_URL) ? result + "yTextureUrl " : result; + result = f.getHasProperty(PROP_Z_TEXTURE_URL) ? result + "zTextureUrl " : result; + result = f.getHasProperty(PROP_NORMALS) ? result + "normals " : result; + result = f.getHasProperty(PROP_STROKE_COLORS) ? result + "strokeColors " : result; + result = f.getHasProperty(PROP_STROKE_WIDTHS) ? result + "strokeWidths " : result; + result = f.getHasProperty(PROP_IS_UV_MODE_STRETCH) ? result + "isUvModeStretch " : result; + result = f.getHasProperty(PROP_SPEED_SPREAD) ? result + "speedSpread " : result; + result = f.getHasProperty(PROP_ACCELERATION_SPREAD) ? result + "accelerationSpread " : result; + result = f.getHasProperty(PROP_X_N_NEIGHBOR_ID) ? result + "xNNeighborID " : result; + result = f.getHasProperty(PROP_Y_N_NEIGHBOR_ID) ? result + "yNNeighborID " : result; + result = f.getHasProperty(PROP_Z_N_NEIGHBOR_ID) ? result + "zNNeighborID " : result; + result = f.getHasProperty(PROP_X_P_NEIGHBOR_ID) ? result + "xPNeighborID " : result; + result = f.getHasProperty(PROP_Y_P_NEIGHBOR_ID) ? result + "yPNeighborID " : result; + result = f.getHasProperty(PROP_Z_P_NEIGHBOR_ID) ? result + "zPNeighborID " : result; + result = f.getHasProperty(PROP_RADIUS_SPREAD) ? result + "radiusSpread " : result; + result = f.getHasProperty(PROP_RADIUS_START) ? result + "radiusStart " : result; + result = f.getHasProperty(PROP_RADIUS_FINISH) ? result + "radiusFinish " : result; + result = f.getHasProperty(PROP_ALPHA) ? result + "alpha " : result; + result = f.getHasProperty(PROP_COLOR_SPREAD) ? result + "colorSpread " : result; + result = f.getHasProperty(PROP_COLOR_START) ? result + "colorStart " : result; + result = f.getHasProperty(PROP_COLOR_FINISH) ? result + "colorFinish " : result; + result = f.getHasProperty(PROP_ALPHA_SPREAD) ? result + "alphaSpread " : result; + result = f.getHasProperty(PROP_ALPHA_START) ? result + "alphaStart " : result; + result = f.getHasProperty(PROP_ALPHA_FINISH) ? result + "alphaFinish " : result; + result = f.getHasProperty(PROP_EMIT_ORIENTATION) ? result + "emitOrientation " : result; + result = f.getHasProperty(PROP_EMIT_DIMENSIONS) ? result + "emitDimensions " : result; + result = f.getHasProperty(PROP_EMIT_RADIUS_START) ? result + "emitRadiusStart " : result; + result = f.getHasProperty(PROP_POLAR_START) ? result + "polarStart " : result; + result = f.getHasProperty(PROP_POLAR_FINISH) ? result + "polarFinish " : result; + result = f.getHasProperty(PROP_AZIMUTH_START) ? result + "azimuthStart " : result; + result = f.getHasProperty(PROP_AZIMUTH_FINISH) ? result + "azimuthFinish " : result; + result = f.getHasProperty(PROP_ANIMATION_LOOP) ? result + "animationLoop " : result; + result = f.getHasProperty(PROP_ANIMATION_FIRST_FRAME) ? result + "animationFirstFrame " : result; + result = f.getHasProperty(PROP_ANIMATION_LAST_FRAME) ? result + "animationLastFrame " : result; + result = f.getHasProperty(PROP_ANIMATION_HOLD) ? result + "animationHold " : result; + result = f.getHasProperty(PROP_ANIMATION_START_AUTOMATICALLY) ? result + "animationStartAutomatically " : result; + result = f.getHasProperty(PROP_EMITTER_SHOULD_TRAIL) ? result + "emitterShouldTrail " : result; + result = f.getHasProperty(PROP_PARENT_ID) ? result + "parentID " : result; + result = f.getHasProperty(PROP_PARENT_JOINT_INDEX) ? result + "parentJointIndex " : result; + result = f.getHasProperty(PROP_LOCAL_POSITION) ? result + "localPosition " : result; + result = f.getHasProperty(PROP_LOCAL_ROTATION) ? result + "localRotation " : result; + result = f.getHasProperty(PROP_QUERY_AA_CUBE) ? result + "queryAaCube " : result; + result = f.getHasProperty(PROP_JOINT_ROTATIONS_SET) ? result + "jointRotationsSet " : result; + result = f.getHasProperty(PROP_JOINT_ROTATIONS) ? result + "jointRotations " : result; + result = f.getHasProperty(PROP_JOINT_TRANSLATIONS_SET) ? result + "jointTranslationsSet " : result; + result = f.getHasProperty(PROP_JOINT_TRANSLATIONS) ? result + "jointTranslations " : result; + result = f.getHasProperty(PROP_COLLISION_MASK) ? result + "collisionMask " : result; + result = f.getHasProperty(PROP_FALLOFF_RADIUS) ? result + "falloffRadius " : result; + result = f.getHasProperty(PROP_FLYING_ALLOWED) ? result + "flyingAllowed " : result; + result = f.getHasProperty(PROP_GHOSTING_ALLOWED) ? result + "ghostingAllowed " : result; + result = f.getHasProperty(PROP_CLIENT_ONLY) ? result + "clientOnly " : result; + result = f.getHasProperty(PROP_OWNING_AVATAR_ID) ? result + "owningAvatarID " : result; + result = f.getHasProperty(PROP_SHAPE) ? result + "shape " : result; + result = f.getHasProperty(PROP_DPI) ? result + "dpi " : result; + result = f.getHasProperty(PROP_LOCAL_VELOCITY) ? result + "localVelocity " : result; + result = f.getHasProperty(PROP_LOCAL_ANGULAR_VELOCITY) ? result + "localAngularVelocity " : result; + result = f.getHasProperty(PROP_LAST_EDITED_BY) ? result + "lastEditedBy " : result; + result = f.getHasProperty(PROP_SERVER_SCRIPTS) ? result + "serverScripts " : result; + result = f.getHasProperty(PROP_FILTER_URL) ? result + "filterUrl " : result; + result = f.getHasProperty(PROP_ITEM_NAME) ? result + "itemName " : result; + result = f.getHasProperty(PROP_ITEM_DESCRIPTION) ? result + "itemDescription " : result; + result = f.getHasProperty(PROP_ITEM_CATEGORIES) ? result + "itemCategories " : result; + result = f.getHasProperty(PROP_ITEM_ARTIST) ? result + "itemArtist " : result; + result = f.getHasProperty(PROP_ITEM_LICENSE) ? result + "itemLicense " : result; + result = f.getHasProperty(PROP_LIMITED_RUN) ? result + "limitedRun " : result; + result = f.getHasProperty(PROP_EDITION_NUMBER) ? result + "editionNumber " : result; + result = f.getHasProperty(PROP_ENTITY_INSTANCE_NUMBER) ? result + "entityInstanceNumber " : result; + result = f.getHasProperty(PROP_CERTIFICATE_ID) ? result + "certificateID " : result; + result = f.getHasProperty(PROP_STATIC_CERTIFICATE_VERSION) ? result + "staticCertificateVersion " : result; + result = f.getHasProperty(PROP_CLONEABLE) ? result + "cloneable " : result; + result = f.getHasProperty(PROP_CLONE_LIFETIME) ? result + "cloneLifetime " : result; + result = f.getHasProperty(PROP_CLONE_LIMIT) ? result + "cloneLimit " : result; + result = f.getHasProperty(PROP_CLONE_DYNAMIC) ? result + "cloneDynamic " : result; + result = f.getHasProperty(PROP_CLONE_AVATAR_ENTITY) ? result + "cloneAvatarEntity " : result; + result = f.getHasProperty(PROP_CLONE_ORIGIN_ID) ? result + "cloneOriginID " : result; + result = f.getHasProperty(PROP_HAZE_MODE) ? result + "hazeMode " : result; + result = f.getHasProperty(PROP_KEYLIGHT_COLOR) ? result + "keylightColor " : result; + result = f.getHasProperty(PROP_KEYLIGHT_INTENSITY) ? result + "keylightIntensity " : result; + result = f.getHasProperty(PROP_KEYLIGHT_DIRECTION) ? result + "keylightDirection " : result; + result = f.getHasProperty(PROP_KEYLIGHT_CAST_SHADOW) ? result + "keylightCastShadow " : result; + result = f.getHasProperty(PROP_HAZE_RANGE) ? result + "hazeRange " : result; + result = f.getHasProperty(PROP_HAZE_COLOR) ? result + "hazeColor " : result; + result = f.getHasProperty(PROP_HAZE_GLARE_COLOR) ? result + "hazeGlareColor " : result; + result = f.getHasProperty(PROP_HAZE_ENABLE_GLARE) ? result + "hazeEnableGlare " : result; + result = f.getHasProperty(PROP_HAZE_GLARE_ANGLE) ? result + "hazeGlareAngle " : result; + result = f.getHasProperty(PROP_HAZE_ALTITUDE_EFFECT) ? result + "hazeAltitudeEffect " : result; + result = f.getHasProperty(PROP_HAZE_CEILING) ? result + "hazeCeiling " : result; + result = f.getHasProperty(PROP_HAZE_BASE_REF) ? result + "hazeBaseRef " : result; + result = f.getHasProperty(PROP_HAZE_BACKGROUND_BLEND) ? result + "hazeBackgroundBlend " : result; + result = f.getHasProperty(PROP_HAZE_ATTENUATE_KEYLIGHT) ? result + "hazeAttenuateKeylight " : result; + result = f.getHasProperty(PROP_HAZE_KEYLIGHT_RANGE) ? result + "hazeKeylightRange " : result; + result = f.getHasProperty(PROP_HAZE_KEYLIGHT_ALTITUDE) ? result + "hazeKeylightAltitude " : result; + result = f.getHasProperty(PROP_KEY_LIGHT_MODE) ? result + "keyLightMode " : result; + result = f.getHasProperty(PROP_AMBIENT_LIGHT_MODE) ? result + "ambientLightMode " : result; + result = f.getHasProperty(PROP_SKYBOX_MODE) ? result + "skyboxMode " : result; + result = f.getHasProperty(PROP_LOCAL_DIMENSIONS) ? result + "localDimensions " : result; + result = f.getHasProperty(PROP_MATERIAL_URL) ? result + "materialUrl " : result; + result = f.getHasProperty(PROP_MATERIAL_MAPPING_MODE) ? result + "materialMappingMode " : result; + result = f.getHasProperty(PROP_MATERIAL_PRIORITY) ? result + "materialPriority " : result; + result = f.getHasProperty(PROP_PARENT_MATERIAL_NAME) ? result + "parentMaterialName " : result; + result = f.getHasProperty(PROP_MATERIAL_MAPPING_POS) ? result + "materialMappingPos " : result; + result = f.getHasProperty(PROP_MATERIAL_MAPPING_SCALE) ? result + "materialMappingScale " : result; + result = f.getHasProperty(PROP_MATERIAL_MAPPING_ROT) ? result + "materialMappingRot " : result; + result = f.getHasProperty(PROP_MATERIAL_DATA) ? result + "materialData " : result; + result = f.getHasProperty(PROP_VISIBLE_IN_SECONDARY_CAMERA) ? result + "visibleInSecondaryCamera " : result; + result = f.getHasProperty(PROP_PARTICLE_SPIN) ? result + "particleSpin " : result; + result = f.getHasProperty(PROP_SPIN_START) ? result + "spinStart " : result; + result = f.getHasProperty(PROP_SPIN_FINISH) ? result + "spinFinish " : result; + result = f.getHasProperty(PROP_SPIN_SPREAD) ? result + "spinSpread " : result; + result = f.getHasProperty(PROP_PARTICLE_ROTATE_WITH_ENTITY) ? result + "particleRotateWithEntity " : result; + result = f.getHasProperty(PROP_BLOOM_INTENSITY) ? result + "bloomIntensity " : result; + result = f.getHasProperty(PROP_BLOOM_THRESHOLD) ? result + "bloomThreshold " : result; + result = f.getHasProperty(PROP_BLOOM_SIZE) ? result + "bloomSize " : result; + result = f.getHasProperty(PROP_GRAB_GRABBABLE) ? result + "grab.Grabbable " : result; + result = f.getHasProperty(PROP_GRAB_KINEMATIC) ? result + "grab.Kinematic " : result; + result = f.getHasProperty(PROP_GRAB_FOLLOWS_CONTROLLER) ? result + "grab.FollowsController " : result; + result = f.getHasProperty(PROP_GRAB_TRIGGERABLE) ? result + "grab.Triggerable " : result; + result = f.getHasProperty(PROP_GRAB_EQUIPPABLE) ? result + "grab.Equippable " : result; + result = + f.getHasProperty(PROP_GRAB_LEFT_EQUIPPABLE_POSITION_OFFSET) ? result + "grab.LeftEquippablePositionOffset " : result; + result = + f.getHasProperty(PROP_GRAB_LEFT_EQUIPPABLE_ROTATION_OFFSET) ? result + "grab.LeftEquippableRotationOffset " : result; + result = + f.getHasProperty(PROP_GRAB_RIGHT_EQUIPPABLE_POSITION_OFFSET) ? result + "grab.RightEquippablePositionOffset " : result; + result = + f.getHasProperty(PROP_GRAB_RIGHT_EQUIPPABLE_ROTATION_OFFSET) ? result + "grab.RightEquippableRotationOffset " : result; + result = f.getHasProperty(PROP_GRAB_EQUIPPABLE_INDICATOR_URL) ? result + "grab.EquippableIndicatorURL " : result; + result = f.getHasProperty(PROP_GRAB_EQUIPPABLE_INDICATOR_SCALE) ? result + "grab.EquippableIndicatorScale " : result; + result = f.getHasProperty(PROP_GRAB_EQUIPPABLE_INDICATOR_OFFSET) ? result + "grab.EquippableIndicatorOffset " : result; + + result += "]"; + dbg.nospace() << result; + return dbg; +} diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index 3932730661..d2f687fbd3 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -262,6 +262,19 @@ enum EntityPropertyList { PROP_BLOOM_THRESHOLD, PROP_BLOOM_SIZE, + PROP_GRAB_GRABBABLE, + PROP_GRAB_KINEMATIC, + PROP_GRAB_FOLLOWS_CONTROLLER, + PROP_GRAB_TRIGGERABLE, + PROP_GRAB_EQUIPPABLE, + PROP_GRAB_LEFT_EQUIPPABLE_POSITION_OFFSET, + PROP_GRAB_LEFT_EQUIPPABLE_ROTATION_OFFSET, + PROP_GRAB_RIGHT_EQUIPPABLE_POSITION_OFFSET, + PROP_GRAB_RIGHT_EQUIPPABLE_ROTATION_OFFSET, + PROP_GRAB_EQUIPPABLE_INDICATOR_URL, + PROP_GRAB_EQUIPPABLE_INDICATOR_SCALE, + PROP_GRAB_EQUIPPABLE_INDICATOR_OFFSET, + //////////////////////////////////////////////////////////////////////////////////////////////////// // ATTENTION: add new properties to end of list just ABOVE this line PROP_AFTER_LAST_ITEM, @@ -304,5 +317,10 @@ typedef PropertyFlags EntityPropertyFlags; // one greater than the last item property due to the enum's auto-incrementing. extern EntityPropertyList PROP_LAST_ITEM; +QString EntityPropertyFlagsToString(EntityPropertyFlags propertiesFlags); + + +QDebug& operator<<(QDebug& dbg, const EntityPropertyFlags& f); + #endif // hifi_EntityPropertyFlags_h diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index a7c88ddc7d..cf899d7653 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -668,7 +668,7 @@ void EntityTree::unhookChildAvatar(const EntityItemID entityID) { void EntityTree::cleanupCloneIDs(const EntityItemID& entityID) { EntityItemPointer entity = findEntityByEntityItemID(entityID); if (entity) { - // remove clone ID from it's clone origin's clone ID list if clone origin exists + // remove clone ID from its clone origin's clone ID list if clone origin exists const QUuid& cloneOriginID = entity->getCloneOriginID(); if (!cloneOriginID.isNull()) { EntityItemPointer cloneOrigin = findEntityByID(cloneOriginID); @@ -2558,7 +2558,7 @@ bool EntityTree::readFromMap(QVariantMap& map) { if (needsConversion && (properties.getType() == EntityTypes::EntityType::Zone)) { // The legacy version had no keylight mode - this is set to on properties.setKeyLightMode(COMPONENT_MODE_ENABLED); - + // The ambient URL has been moved from "keyLight" to "ambientLight" if (entityMap.contains("keyLight")) { QVariantMap keyLightObject = entityMap["keyLight"].toMap(); @@ -2629,6 +2629,108 @@ bool EntityTree::readFromMap(QVariantMap& map) { } } + // convert old grab-related userData to new grab properties + if (contentVersion < (int)EntityVersion::GrabProperties) { + QJsonObject userData = QJsonDocument::fromJson(properties.getUserData().toUtf8()).object(); + QJsonObject grabbableKey = userData["grabbableKey"].toObject(); + QJsonValue wantsTrigger = grabbableKey["wantsTrigger"]; + + GrabPropertyGroup& grabProperties = properties.getGrab(); + + if (wantsTrigger.isBool()) { + grabProperties.setTriggerable(wantsTrigger.toBool()); + } + QJsonValue triggerable = grabbableKey["triggerable"]; + if (triggerable.isBool()) { + grabProperties.setTriggerable(triggerable.toBool()); + } + QJsonValue grabbable = grabbableKey["grabbable"]; + if (grabbable.isBool()) { + grabProperties.setGrabbable(grabbable.toBool()); + } + QJsonValue ignoreIK = grabbableKey["ignoreIK"]; + if (ignoreIK.isBool()) { + grabProperties.setGrabFollowsController(ignoreIK.toBool()); + } + QJsonValue kinematic = grabbableKey["kinematic"]; + if (kinematic.isBool()) { + grabProperties.setGrabKinematic(kinematic.toBool()); + } + + if (grabbableKey["spatialKey"].isObject()) { + QJsonObject spatialKey = grabbableKey["spatialKey"].toObject(); + grabProperties.setEquippable(true); + if (spatialKey["leftRelativePosition"].isObject()) { + grabProperties.setEquippableLeftPosition(qMapToVec3(spatialKey["leftRelativePosition"].toVariant())); + } + if (spatialKey["rightRelativePosition"].isObject()) { + grabProperties.setEquippableRightPosition(qMapToVec3(spatialKey["rightRelativePosition"].toVariant())); + } + if (spatialKey["relativeRotation"].isObject()) { + grabProperties.setEquippableLeftRotation(qMapToQuat(spatialKey["relativeRotation"].toVariant())); + grabProperties.setEquippableRightRotation(qMapToQuat(spatialKey["relativeRotation"].toVariant())); + } + } + + QJsonObject wearable = userData["wearable"].toObject(); + QJsonObject joints = wearable["joints"].toObject(); + if (joints["LeftHand"].isArray()) { + QJsonArray leftHand = joints["LeftHand"].toArray(); + if (leftHand.size() == 2) { + grabProperties.setEquippable(true); + grabProperties.setEquippableLeftPosition(qMapToVec3(leftHand[0].toVariant())); + grabProperties.setEquippableLeftRotation(qMapToQuat(leftHand[1].toVariant())); + } + } + if (joints["RightHand"].isArray()) { + QJsonArray rightHand = joints["RightHand"].toArray(); + if (rightHand.size() == 2) { + grabProperties.setEquippable(true); + grabProperties.setEquippableRightPosition(qMapToVec3(rightHand[0].toVariant())); + grabProperties.setEquippableRightRotation(qMapToQuat(rightHand[1].toVariant())); + } + } + + if (userData["equipHotspots"].isArray()) { + QJsonArray equipHotspots = userData["equipHotspots"].toArray(); + if (equipHotspots.size() > 0) { + // just take the first one + QJsonObject firstHotSpot = equipHotspots[0].toObject(); + QJsonObject joints = firstHotSpot["joints"].toObject(); + if (joints["LeftHand"].isArray()) { + QJsonArray leftHand = joints["LeftHand"].toArray(); + if (leftHand.size() == 2) { + grabProperties.setEquippable(true); + grabProperties.setEquippableLeftPosition(qMapToVec3(leftHand[0].toVariant())); + grabProperties.setEquippableLeftRotation(qMapToQuat(leftHand[1].toVariant())); + } + } + if (joints["RightHand"].isArray()) { + QJsonArray rightHand = joints["RightHand"].toArray(); + if (rightHand.size() == 2) { + grabProperties.setEquippable(true); + grabProperties.setEquippableRightPosition(qMapToVec3(rightHand[0].toVariant())); + grabProperties.setEquippableRightRotation(qMapToQuat(rightHand[1].toVariant())); + } + } + QJsonValue indicatorURL = firstHotSpot["modelURL"]; + if (indicatorURL.isString()) { + grabProperties.setEquippableIndicatorURL(indicatorURL.toString()); + } + QJsonValue indicatorScale = firstHotSpot["modelScale"]; + if (indicatorScale.isDouble()) { + grabProperties.setEquippableIndicatorScale(glm::vec3((float)indicatorScale.toDouble())); + } else if (indicatorScale.isObject()) { + grabProperties.setEquippableIndicatorScale(qMapToVec3(indicatorScale.toVariant())); + } + QJsonValue indicatorOffset = firstHotSpot["position"]; + if (indicatorOffset.isObject()) { + grabProperties.setEquippableIndicatorOffset(qMapToVec3(indicatorOffset.toVariant())); + } + } + } + } + // Zero out the spread values that were fixed in version ParticleEntityFix so they behave the same as before if (contentVersion < (int)EntityVersion::ParticleEntityFix) { properties.setRadiusSpread(0.0f); diff --git a/libraries/entities/src/GrabPropertyGroup.cpp b/libraries/entities/src/GrabPropertyGroup.cpp new file mode 100644 index 0000000000..c433043e31 --- /dev/null +++ b/libraries/entities/src/GrabPropertyGroup.cpp @@ -0,0 +1,303 @@ +// +// GrabPropertyGroup.h +// libraries/entities/src +// +// Created by Seth Alves on 2018-8-8. +// 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 "GrabPropertyGroup.h" + +#include + +#include "EntityItemProperties.h" +#include "EntityItemPropertiesMacros.h" + +void GrabPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, + QScriptEngine* engine, bool skipDefaults, + EntityItemProperties& defaultEntityProperties) const { + COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_GRAB_GRABBABLE, Grab, grab, Grabbable, grabbable); + COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_GRAB_KINEMATIC, Grab, grab, GrabKinematic, grabKinematic); + COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_GRAB_FOLLOWS_CONTROLLER, Grab, grab, GrabFollowsController, grabFollowsController); + COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_GRAB_TRIGGERABLE, Grab, grab, Triggerable, triggerable); + COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_GRAB_EQUIPPABLE, Grab, grab, Equippable, equippable); + COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_GRAB_LEFT_EQUIPPABLE_POSITION_OFFSET, Grab, grab, + EquippableLeftPosition, equippableLeftPosition); + COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_GRAB_LEFT_EQUIPPABLE_ROTATION_OFFSET, Grab, grab, + EquippableLeftRotation, equippableLeftRotation); + COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_GRAB_RIGHT_EQUIPPABLE_POSITION_OFFSET, Grab, grab, + EquippableRightPosition, equippableRightPosition); + COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_GRAB_RIGHT_EQUIPPABLE_ROTATION_OFFSET, Grab, grab, + EquippableRightRotation, equippableRightRotation); + COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_GRAB_EQUIPPABLE_INDICATOR_URL, Grab, grab, + EquippableIndicatorURL, equippableIndicatorURL); + COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_GRAB_EQUIPPABLE_INDICATOR_SCALE, Grab, grab, + EquippableIndicatorScale, equippableIndicatorScale); + COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_GRAB_EQUIPPABLE_INDICATOR_OFFSET, Grab, grab, + EquippableIndicatorOffset, equippableIndicatorOffset); + +} + +void GrabPropertyGroup::copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings) { + COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(grab, grabbable, bool, setGrabbable); + COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(grab, grabKinematic, bool, setGrabKinematic); + COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(grab, grabFollowsController, bool, setGrabFollowsController); + COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(grab, triggerable, bool, setTriggerable); + COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(grab, equippable, bool, setEquippable); + COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(grab, equippableLeftPosition, vec3, setEquippableLeftPosition); + COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(grab, equippableLeftRotation, quat, setEquippableLeftRotation); + COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(grab, equippableRightPosition, vec3, setEquippableRightPosition); + COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(grab, equippableRightRotation, quat, setEquippableRightRotation); +} + +void GrabPropertyGroup::merge(const GrabPropertyGroup& other) { + COPY_PROPERTY_IF_CHANGED(grabbable); + COPY_PROPERTY_IF_CHANGED(grabKinematic); + COPY_PROPERTY_IF_CHANGED(grabFollowsController); + COPY_PROPERTY_IF_CHANGED(triggerable); + COPY_PROPERTY_IF_CHANGED(equippable); + COPY_PROPERTY_IF_CHANGED(equippableLeftPosition); + COPY_PROPERTY_IF_CHANGED(equippableLeftRotation); + COPY_PROPERTY_IF_CHANGED(equippableRightPosition); + COPY_PROPERTY_IF_CHANGED(equippableRightRotation); +} + +void GrabPropertyGroup::debugDump() const { + qCDebug(entities) << " GrabPropertyGroup: ---------------------------------------------"; + + qCDebug(entities) << " _grabbable:" << _grabbable; + qCDebug(entities) << " _grabKinematic:" << _grabKinematic; + qCDebug(entities) << " _grabFollowsController:" << _grabFollowsController; + qCDebug(entities) << " _triggerable:" << _triggerable; + qCDebug(entities) << " _equippable:" << _equippable; + qCDebug(entities) << " _equippableLeftPosition:" << _equippableLeftPosition; + qCDebug(entities) << " _equippableLeftRotation:" << _equippableLeftRotation; + qCDebug(entities) << " _equippableRightPosition:" << _equippableRightPosition; + qCDebug(entities) << " _equippableRightRotation:" << _equippableRightRotation; +} + +void GrabPropertyGroup::listChangedProperties(QList& out) { + if (grabbableChanged()) { + out << "grab-grabbable"; + } + if (grabKinematicChanged()) { + out << "grab-grabKinematic"; + } + if (grabFollowsControllerChanged()) { + out << "grab-followsController"; + } + if (triggerableChanged()) { + out << "grab-triggerable"; + } + if (equippableChanged()) { + out << "grab-equippable"; + } + if (equippableLeftPositionChanged()) { + out << "grab-equippableLeftPosition"; + } + if (equippableLeftRotationChanged()) { + out << "grab-equippableLeftRotation"; + } + if (equippableRightPositionChanged()) { + out << "grab-equippableRightPosition"; + } + if (equippableRightRotationChanged()) { + out << "grab-equippableRightRotation"; + } +} + +bool GrabPropertyGroup::appendToEditPacket(OctreePacketData* packetData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const { + + bool successPropertyFits = true; + + APPEND_ENTITY_PROPERTY(PROP_GRAB_GRABBABLE, getGrabbable()); + APPEND_ENTITY_PROPERTY(PROP_GRAB_KINEMATIC, getGrabKinematic()); + APPEND_ENTITY_PROPERTY(PROP_GRAB_FOLLOWS_CONTROLLER, getGrabFollowsController()); + APPEND_ENTITY_PROPERTY(PROP_GRAB_TRIGGERABLE, getTriggerable()); + APPEND_ENTITY_PROPERTY(PROP_GRAB_EQUIPPABLE, getEquippable()); + APPEND_ENTITY_PROPERTY(PROP_GRAB_LEFT_EQUIPPABLE_POSITION_OFFSET, getEquippableLeftPosition()); + APPEND_ENTITY_PROPERTY(PROP_GRAB_LEFT_EQUIPPABLE_ROTATION_OFFSET, getEquippableLeftRotation()); + APPEND_ENTITY_PROPERTY(PROP_GRAB_RIGHT_EQUIPPABLE_POSITION_OFFSET, getEquippableRightPosition()); + APPEND_ENTITY_PROPERTY(PROP_GRAB_RIGHT_EQUIPPABLE_ROTATION_OFFSET, getEquippableRightRotation()); + APPEND_ENTITY_PROPERTY(PROP_GRAB_EQUIPPABLE_INDICATOR_URL, getEquippableIndicatorURL()); + APPEND_ENTITY_PROPERTY(PROP_GRAB_EQUIPPABLE_INDICATOR_SCALE, getEquippableIndicatorScale()); + APPEND_ENTITY_PROPERTY(PROP_GRAB_EQUIPPABLE_INDICATOR_OFFSET, getEquippableIndicatorOffset()); + + return true; +} + +bool GrabPropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyFlags, + const unsigned char*& dataAt , int& processedBytes) { + + int bytesRead = 0; + bool overwriteLocalData = true; + bool somethingChanged = false; + + READ_ENTITY_PROPERTY(PROP_GRAB_GRABBABLE, bool, setGrabbable); + READ_ENTITY_PROPERTY(PROP_GRAB_KINEMATIC, bool, setGrabKinematic); + READ_ENTITY_PROPERTY(PROP_GRAB_FOLLOWS_CONTROLLER, bool, setGrabFollowsController); + READ_ENTITY_PROPERTY(PROP_GRAB_TRIGGERABLE, bool, setTriggerable); + READ_ENTITY_PROPERTY(PROP_GRAB_EQUIPPABLE, bool, setEquippable); + READ_ENTITY_PROPERTY(PROP_GRAB_LEFT_EQUIPPABLE_POSITION_OFFSET, glm::vec3, setEquippableLeftPosition); + READ_ENTITY_PROPERTY(PROP_GRAB_LEFT_EQUIPPABLE_ROTATION_OFFSET, glm::quat, setEquippableLeftRotation); + READ_ENTITY_PROPERTY(PROP_GRAB_RIGHT_EQUIPPABLE_POSITION_OFFSET, glm::vec3, setEquippableRightPosition); + READ_ENTITY_PROPERTY(PROP_GRAB_RIGHT_EQUIPPABLE_ROTATION_OFFSET, glm::quat, setEquippableRightRotation); + READ_ENTITY_PROPERTY(PROP_GRAB_EQUIPPABLE_INDICATOR_URL, QString, setEquippableIndicatorURL); + READ_ENTITY_PROPERTY(PROP_GRAB_EQUIPPABLE_INDICATOR_SCALE, glm::vec3, setEquippableIndicatorScale); + READ_ENTITY_PROPERTY(PROP_GRAB_EQUIPPABLE_INDICATOR_OFFSET, glm::vec3, setEquippableIndicatorOffset); + + DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_GRAB_GRABBABLE, Grabbable); + DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_GRAB_KINEMATIC, GrabKinematic); + DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_GRAB_FOLLOWS_CONTROLLER, GrabFollowsController); + DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_GRAB_TRIGGERABLE, Triggerable); + DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_GRAB_EQUIPPABLE, Equippable); + DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_GRAB_LEFT_EQUIPPABLE_POSITION_OFFSET, EquippableLeftPosition); + DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_GRAB_LEFT_EQUIPPABLE_ROTATION_OFFSET, EquippableLeftRotation); + DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_GRAB_RIGHT_EQUIPPABLE_POSITION_OFFSET, EquippableRightPosition); + DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_GRAB_RIGHT_EQUIPPABLE_ROTATION_OFFSET, EquippableRightRotation); + DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_GRAB_EQUIPPABLE_INDICATOR_URL, EquippableIndicatorURL); + DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_GRAB_EQUIPPABLE_INDICATOR_SCALE, EquippableIndicatorScale); + DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_GRAB_EQUIPPABLE_INDICATOR_OFFSET, EquippableIndicatorOffset); + + processedBytes += bytesRead; + + Q_UNUSED(somethingChanged); + + return true; +} + +void GrabPropertyGroup::markAllChanged() { + _grabbableChanged = true; + _grabKinematicChanged = true; + _grabFollowsControllerChanged = true; + _triggerableChanged = true; + _equippableChanged = true; + _equippableLeftPositionChanged = true; + _equippableLeftRotationChanged = true; + _equippableRightPositionChanged = true; + _equippableRightRotationChanged = true; +} + +EntityPropertyFlags GrabPropertyGroup::getChangedProperties() const { + EntityPropertyFlags changedProperties; + + CHECK_PROPERTY_CHANGE(PROP_GRAB_GRABBABLE, grabbable); + CHECK_PROPERTY_CHANGE(PROP_GRAB_KINEMATIC, grabKinematic); + CHECK_PROPERTY_CHANGE(PROP_GRAB_FOLLOWS_CONTROLLER, grabFollowsController); + CHECK_PROPERTY_CHANGE(PROP_GRAB_TRIGGERABLE, triggerable); + CHECK_PROPERTY_CHANGE(PROP_GRAB_EQUIPPABLE, equippable); + CHECK_PROPERTY_CHANGE(PROP_GRAB_LEFT_EQUIPPABLE_POSITION_OFFSET, equippableLeftPosition); + CHECK_PROPERTY_CHANGE(PROP_GRAB_LEFT_EQUIPPABLE_ROTATION_OFFSET, equippableLeftRotation); + CHECK_PROPERTY_CHANGE(PROP_GRAB_RIGHT_EQUIPPABLE_POSITION_OFFSET, equippableRightPosition); + CHECK_PROPERTY_CHANGE(PROP_GRAB_RIGHT_EQUIPPABLE_ROTATION_OFFSET, equippableRightRotation); + CHECK_PROPERTY_CHANGE(PROP_GRAB_EQUIPPABLE_INDICATOR_URL, equippableIndicatorURL); + CHECK_PROPERTY_CHANGE(PROP_GRAB_EQUIPPABLE_INDICATOR_SCALE, equippableIndicatorScale); + CHECK_PROPERTY_CHANGE(PROP_GRAB_EQUIPPABLE_INDICATOR_OFFSET, equippableIndicatorOffset); + + return changedProperties; +} + +void GrabPropertyGroup::getProperties(EntityItemProperties& properties) const { + COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Grab, Grabbable, getGrabbable); + COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Grab, GrabKinematic, getGrabKinematic); + COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Grab, GrabFollowsController, getGrabFollowsController); + COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Grab, Triggerable, getTriggerable); + COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Grab, Equippable, getEquippable); + COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Grab, EquippableLeftPosition, getEquippableLeftPosition); + COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Grab, EquippableLeftRotation, getEquippableLeftRotation); + COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Grab, EquippableRightPosition, getEquippableRightPosition); + COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Grab, EquippableRightRotation, getEquippableRightRotation); +} + +bool GrabPropertyGroup::setProperties(const EntityItemProperties& properties) { + bool somethingChanged = false; + + SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Grab, Grabbable, grabbable, setGrabbable); + SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Grab, GrabKinematic, grabKinematic, setGrabKinematic); + SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Grab, GrabFollowsController, grabFollowsController, setGrabFollowsController); + SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Grab, Triggerable, triggerable, setTriggerable); + SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Grab, Equippable, equippable, setEquippable); + SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Grab, EquippableLeftPosition, equippableLeftPosition, setEquippableLeftPosition); + SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Grab, EquippableLeftRotation, equippableLeftRotation, setEquippableLeftRotation); + SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Grab, EquippableRightPosition, equippableRightPosition, + setEquippableRightPosition); + SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Grab, EquippableRightRotation, equippableRightRotation, + setEquippableRightRotation); + + return somethingChanged; +} + +EntityPropertyFlags GrabPropertyGroup::getEntityProperties(EncodeBitstreamParams& params) const { + EntityPropertyFlags requestedProperties; + + requestedProperties += PROP_GRAB_GRABBABLE; + requestedProperties += PROP_GRAB_KINEMATIC; + requestedProperties += PROP_GRAB_FOLLOWS_CONTROLLER; + requestedProperties += PROP_GRAB_TRIGGERABLE; + requestedProperties += PROP_GRAB_EQUIPPABLE; + requestedProperties += PROP_GRAB_LEFT_EQUIPPABLE_POSITION_OFFSET; + requestedProperties += PROP_GRAB_LEFT_EQUIPPABLE_ROTATION_OFFSET; + requestedProperties += PROP_GRAB_RIGHT_EQUIPPABLE_POSITION_OFFSET; + requestedProperties += PROP_GRAB_RIGHT_EQUIPPABLE_ROTATION_OFFSET; + requestedProperties += PROP_GRAB_EQUIPPABLE_INDICATOR_URL; + requestedProperties += PROP_GRAB_EQUIPPABLE_INDICATOR_SCALE; + requestedProperties += PROP_GRAB_EQUIPPABLE_INDICATOR_OFFSET; + + return requestedProperties; +} + +void GrabPropertyGroup::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, + EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const { + + bool successPropertyFits = true; + + APPEND_ENTITY_PROPERTY(PROP_GRAB_GRABBABLE, getGrabbable()); + APPEND_ENTITY_PROPERTY(PROP_GRAB_KINEMATIC, getGrabKinematic()); + APPEND_ENTITY_PROPERTY(PROP_GRAB_FOLLOWS_CONTROLLER, getGrabFollowsController()); + APPEND_ENTITY_PROPERTY(PROP_GRAB_TRIGGERABLE, getTriggerable()); + APPEND_ENTITY_PROPERTY(PROP_GRAB_EQUIPPABLE, getEquippable()); + APPEND_ENTITY_PROPERTY(PROP_GRAB_LEFT_EQUIPPABLE_POSITION_OFFSET, getEquippableLeftPosition()); + APPEND_ENTITY_PROPERTY(PROP_GRAB_LEFT_EQUIPPABLE_ROTATION_OFFSET, getEquippableLeftRotation()); + APPEND_ENTITY_PROPERTY(PROP_GRAB_RIGHT_EQUIPPABLE_POSITION_OFFSET, getEquippableRightPosition()); + APPEND_ENTITY_PROPERTY(PROP_GRAB_RIGHT_EQUIPPABLE_ROTATION_OFFSET, getEquippableRightRotation()); + APPEND_ENTITY_PROPERTY(PROP_GRAB_EQUIPPABLE_INDICATOR_URL, getEquippableIndicatorURL()); + APPEND_ENTITY_PROPERTY(PROP_GRAB_EQUIPPABLE_INDICATOR_SCALE, getEquippableIndicatorScale()); + APPEND_ENTITY_PROPERTY(PROP_GRAB_EQUIPPABLE_INDICATOR_OFFSET, getEquippableIndicatorOffset()); +} + +int GrabPropertyGroup::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData, + bool& somethingChanged) { + + int bytesRead = 0; + const unsigned char* dataAt = data; + + READ_ENTITY_PROPERTY(PROP_GRAB_GRABBABLE, bool, setGrabbable); + READ_ENTITY_PROPERTY(PROP_GRAB_KINEMATIC, bool, setGrabKinematic); + READ_ENTITY_PROPERTY(PROP_GRAB_FOLLOWS_CONTROLLER, bool, setGrabFollowsController); + READ_ENTITY_PROPERTY(PROP_GRAB_TRIGGERABLE, bool, setTriggerable); + READ_ENTITY_PROPERTY(PROP_GRAB_EQUIPPABLE, bool, setEquippable); + READ_ENTITY_PROPERTY(PROP_GRAB_LEFT_EQUIPPABLE_POSITION_OFFSET, glm::vec3, setEquippableLeftPosition); + READ_ENTITY_PROPERTY(PROP_GRAB_LEFT_EQUIPPABLE_ROTATION_OFFSET, glm::quat, setEquippableLeftRotation); + READ_ENTITY_PROPERTY(PROP_GRAB_RIGHT_EQUIPPABLE_POSITION_OFFSET, glm::vec3, setEquippableRightPosition); + READ_ENTITY_PROPERTY(PROP_GRAB_RIGHT_EQUIPPABLE_ROTATION_OFFSET, glm::quat, setEquippableRightRotation); + READ_ENTITY_PROPERTY(PROP_GRAB_EQUIPPABLE_INDICATOR_URL, QString, setEquippableIndicatorURL); + READ_ENTITY_PROPERTY(PROP_GRAB_EQUIPPABLE_INDICATOR_SCALE, glm::vec3, setEquippableIndicatorScale); + READ_ENTITY_PROPERTY(PROP_GRAB_EQUIPPABLE_INDICATOR_OFFSET, glm::vec3, setEquippableIndicatorOffset); + + return bytesRead; +} diff --git a/libraries/entities/src/GrabPropertyGroup.h b/libraries/entities/src/GrabPropertyGroup.h new file mode 100644 index 0000000000..37b157de06 --- /dev/null +++ b/libraries/entities/src/GrabPropertyGroup.h @@ -0,0 +1,141 @@ +// +// GrabPropertyGroup.h +// libraries/entities/src +// +// Created by Seth Alves on 2018-8-8. +// 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_GrabPropertyGroup_h +#define hifi_GrabPropertyGroup_h + +#include + +#include + +#include + +#include "PropertyGroup.h" +#include "EntityItemPropertiesMacros.h" + +class EntityItemProperties; +class EncodeBitstreamParams; +class OctreePacketData; +class ReadBitstreamToTreeParams; + +static const bool INITIAL_GRABBABLE { true }; +static const bool INITIAL_KINEMATIC { true }; +static const bool INITIAL_FOLLOWS_CONTROLLER { true }; +static const bool INITIAL_TRIGGERABLE { false }; +static const bool INITIAL_EQUIPPABLE { false }; +static const glm::vec3 INITIAL_LEFT_EQUIPPABLE_POSITION { glm::vec3(0.0f) }; +static const glm::quat INITIAL_LEFT_EQUIPPABLE_ROTATION { glm::quat() }; +static const glm::vec3 INITIAL_RIGHT_EQUIPPABLE_POSITION { glm::vec3(0.0f) }; +static const glm::quat INITIAL_RIGHT_EQUIPPABLE_ROTATION { glm::quat() }; +static const glm::vec3 INITIAL_EQUIPPABLE_INDICATOR_SCALE { glm::vec3(1.0f) }; +static const glm::vec3 INITIAL_EQUIPPABLE_INDICATOR_OFFSET { glm::vec3(0.0f) }; + + +/**jsdoc + * Grab is defined by the following properties. + * @typedef {object} Entities.Grab + * + * @property {boolean} grabbable=true - If true the entity can be grabbed. + * @property {boolean} grabKinematic=true - If true the entity is updated in a kinematic manner. + * If false it will be grabbed using a tractor action. A kinematic grab will make the item appear more + * tightly held, but will cause it to behave poorly when interacting with dynamic entities. + * @property {boolean} grabFollowsController=true - If true the entity will follow the motions of the + * hand-controller even if the avatar's hand can't get to the implied position. This should be true + * for tools, pens, etc and false for things meant to decorate the hand. + * + * @property {boolean} triggerable=false - If true the entity will receive calls to trigger + * {@link Controller|Controller entity methods}. + * + * @property {boolean} equippable=true - If true the entity can be equipped. + * @property {Vec3} equippableLeftPosition=0,0,0 - Positional offset from the left hand, when equipped. + * @property {Quat} equippableLeftRotation=0,0,0,1 - Rotational offset from the left hand, when equipped. + * @property {Vec3} equippableRightPosition=0,0,0 - Positional offset from the right hand, when equipped. + * @property {Quat} equippableRightRotation=0,0,0,1 - Rotational offset from the right hand, when equipped. + * + * @property {string} equippableIndicatorURL="" - If non-empty, this model will be used to indicate that an + * entity is equippable, rather than the default. + * @property {Vec3} equippableIndicatorScale=1,1,1 - If equippableIndicatorURL is non-empty, this controls the + scale of the displayed overlay. + * @property {Vec3} equippableIndicatorOffset=0,0,0 - If equippableIndicatorURL is non-empty, this controls the + relative offset of the displayed overlay from the equippable entity. + */ + + +class GrabPropertyGroup : public PropertyGroup { +public: + // EntityItemProperty related helpers + virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, + QScriptEngine* engine, bool skipDefaults, + EntityItemProperties& defaultEntityProperties) const override; + virtual void copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings) override; + + void merge(const GrabPropertyGroup& other); + + virtual void debugDump() const override; + virtual void listChangedProperties(QList& out) override; + + virtual bool appendToEditPacket(OctreePacketData* packetData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const override; + + virtual bool decodeFromEditPacket(EntityPropertyFlags& propertyFlags, + const unsigned char*& dataAt, int& processedBytes) override; + virtual void markAllChanged() override; + virtual EntityPropertyFlags getChangedProperties() const override; + + // EntityItem related helpers + // methods for getting/setting all properties of an entity + virtual void getProperties(EntityItemProperties& propertiesOut) const override; + + // returns true if something changed + virtual bool setProperties(const EntityItemProperties& properties) override; + + virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; + + virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, + EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const override; + + virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData, + bool& somethingChanged) override; + + // grab properties + DEFINE_PROPERTY(PROP_GRAB_GRABBABLE, Grabbable, grabbable, bool, INITIAL_GRABBABLE); + DEFINE_PROPERTY(PROP_GRAB_KINEMATIC, GrabKinematic, grabKinematic, bool, INITIAL_KINEMATIC); + DEFINE_PROPERTY(PROP_GRAB_FOLLOWS_CONTROLLER, GrabFollowsController, grabFollowsController, bool, + INITIAL_FOLLOWS_CONTROLLER); + DEFINE_PROPERTY(PROP_GRAB_TRIGGERABLE, Triggerable, triggerable, bool, INITIAL_TRIGGERABLE); + DEFINE_PROPERTY(PROP_GRAB_EQUIPPABLE, Equippable, equippable, bool, INITIAL_EQUIPPABLE); + DEFINE_PROPERTY_REF(PROP_GRAB_LEFT_EQUIPPABLE_POSITION_OFFSET, EquippableLeftPosition, equippableLeftPosition, + glm::vec3, INITIAL_LEFT_EQUIPPABLE_POSITION); + DEFINE_PROPERTY_REF(PROP_GRAB_LEFT_EQUIPPABLE_ROTATION_OFFSET, EquippableLeftRotation, equippableLeftRotation, + glm::quat, INITIAL_LEFT_EQUIPPABLE_ROTATION); + DEFINE_PROPERTY_REF(PROP_GRAB_RIGHT_EQUIPPABLE_POSITION_OFFSET, EquippableRightPosition, equippableRightPosition, + glm::vec3, INITIAL_RIGHT_EQUIPPABLE_POSITION); + DEFINE_PROPERTY_REF(PROP_GRAB_RIGHT_EQUIPPABLE_ROTATION_OFFSET, EquippableRightRotation, equippableRightRotation, + glm::quat, INITIAL_RIGHT_EQUIPPABLE_ROTATION); + DEFINE_PROPERTY_REF(PROP_GRAB_EQUIPPABLE_INDICATOR_URL, EquippableIndicatorURL, equippableIndicatorURL, QString, ""); + DEFINE_PROPERTY_REF(PROP_GRAB_EQUIPPABLE_INDICATOR_SCALE, EquippableIndicatorScale, equippableIndicatorScale, + glm::vec3, INITIAL_EQUIPPABLE_INDICATOR_SCALE); + DEFINE_PROPERTY_REF(PROP_GRAB_EQUIPPABLE_INDICATOR_OFFSET, EquippableIndicatorOffset, equippableIndicatorOffset, + glm::vec3, INITIAL_EQUIPPABLE_INDICATOR_OFFSET); +}; + +#endif // hifi_GrabPropertyGroup_h diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 8cb7c9aaa4..62c62b62f9 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -33,14 +33,14 @@ PacketVersion versionForPacketType(PacketType packetType) { case PacketType::EntityEdit: case PacketType::EntityData: case PacketType::EntityPhysics: - return static_cast(EntityVersion::BloomEffect); + return static_cast(EntityVersion::GrabProperties); case PacketType::EntityQuery: return static_cast(EntityQueryPacketVersion::ConicalFrustums); case PacketType::AvatarIdentity: case PacketType::AvatarData: case PacketType::BulkAvatarData: case PacketType::KillAvatar: - return static_cast(AvatarMixerPacketVersion::MigrateAvatarEntitiesToTraits); + return static_cast(AvatarMixerPacketVersion::FarGrabJointsRedux); case PacketType::MessagesData: return static_cast(MessageDataVersion::TextOrBinaryData); // ICE packets diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 84a93ac939..f075b26dab 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -242,7 +242,8 @@ enum class EntityVersion : PacketVersion { YieldSimulationOwnership, ParticleEntityFix, ParticleSpin, - BloomEffect + BloomEffect, + GrabProperties }; enum class EntityScriptCallMethodVersion : PacketVersion { @@ -293,7 +294,8 @@ enum class AvatarMixerPacketVersion : PacketVersion { ProceduralFaceMovementFlagsAndBlendshapes, FarGrabJoints, MigrateSkeletonURLToTraits, - MigrateAvatarEntitiesToTraits + MigrateAvatarEntitiesToTraits, + FarGrabJointsRedux }; enum class DomainConnectRequestVersion : PacketVersion { diff --git a/libraries/octree/src/OctreePacketData.cpp b/libraries/octree/src/OctreePacketData.cpp index b938850684..6f8e5b55b8 100644 --- a/libraries/octree/src/OctreePacketData.cpp +++ b/libraries/octree/src/OctreePacketData.cpp @@ -198,17 +198,17 @@ const unsigned char* OctreePacketData::getFinalizedData() { int OctreePacketData::getFinalizedSize() { if (!_enableCompression) { - return _bytesInUse; + return _bytesInUse; } if (_dirty) { if (_debug) { qCDebug(octree, "getFinalizedSize() _compressedBytes=%d _bytesInUse=%d",_compressedBytes, _bytesInUse); } - compressContent(); + compressContent(); } - return _compressedBytes; + return _compressedBytes; } @@ -604,6 +604,9 @@ bool OctreePacketData::compressContent() { memcpy(_compressed, compressedData.constData(), _compressedBytes); _dirty = false; success = true; + } else { + qCWarning(octree) << "OctreePacketData::compressContent -- compressedData.size >= MAX_OCTREE_PACKET_DATA_SIZE"; + assert(false); } return success; } @@ -623,11 +626,16 @@ void OctreePacketData::loadFinalizedContent(const unsigned char* data, int lengt memcpy(compressedData.data(), data, _compressedBytes); QByteArray uncompressedData = qUncompress(compressedData); - if (uncompressedData.size() <= _bytesAvailable) { - _bytesInUse = uncompressedData.size(); - _bytesAvailable -= uncompressedData.size(); - memcpy(_uncompressed, uncompressedData.constData(), _bytesInUse); + if (uncompressedData.size() > _bytesAvailable) { + int moreNeeded = uncompressedData.size() - _bytesAvailable; + _uncompressedByteArray.resize(_uncompressedByteArray.size() + moreNeeded); + _uncompressed = (unsigned char*)_uncompressedByteArray.data(); + _bytesAvailable += moreNeeded; } + + _bytesInUse = uncompressedData.size(); + _bytesAvailable -= uncompressedData.size(); + memcpy(_uncompressed, uncompressedData.constData(), _bytesInUse); } else { memcpy(_uncompressed, data, length); memcpy(_compressed, data, length); diff --git a/scripts/developer/tests/ambientSoundTest.js b/scripts/developer/tests/ambientSoundTest.js index d048d5f73d..98dbf8bba0 100644 --- a/scripts/developer/tests/ambientSoundTest.js +++ b/scripts/developer/tests/ambientSoundTest.js @@ -10,7 +10,7 @@ var uuid = Entities.addEntity({ maxVolume: 0.1, range: 25, disabled: true, - grabbableKey: { wantsTrigger: true }, + grab: { triggerable: true } }), lifetime: 600, }); diff --git a/scripts/developer/tests/controllerTableTest.js b/scripts/developer/tests/controllerTableTest.js index 239c7fd0ce..517ff0ab1a 100644 --- a/scripts/developer/tests/controllerTableTest.js +++ b/scripts/developer/tests/controllerTableTest.js @@ -1,7 +1,7 @@ "use strict"; /* jslint bitwise: true */ -/* global Script, Entities, MyAvatar, Vec3, Quat, Mat4 */ +/* global Script, Entities, MyAvatar, Vec3, Quat, Mat4, Overlays */ (function() { // BEGIN LOCAL_SCOPE @@ -19,7 +19,7 @@ var sectionCenterB = 0; var sectionCenterSign = 0; var yFlip = 0; - + var objects = []; var overlays = []; @@ -35,41 +35,41 @@ createPropsCube(index, false, false, true, true); createPropsModel(index, false, false, true, true); createSign(index, "Clone Dynamic Entity"); - }; + } function createCloneEntity(index) { createPropsCube(index, false, false, true, false); createPropsModel(index, false, false, true, false); createSign(index, "Clone Non-Dynamic Entity"); - }; + } function createNearGrabOverlay(index) { createPropsCubeOverlay(index, false, false, true, true); createPropsModelOverlay(index, false, false, true, true); createSign(index, "Near Grab Overlay"); - }; + } function createNearGrabEntity(index) { createPropsCube(index, false, false, false, false); createPropsModel(index, false, false, false, false); createSign(index, "Near Grab Entity"); - }; + } function createFarGrabEntity(index) { createPropsCube(index, true, false, false, false); createPropsModel(index, true, false, false, false); createSign(index, "Far Grab Entity"); - }; + } function createPropsModel(i, dynamic, collisionless, clone, cloneDynamic) { var propsModel = { name: "controller-tests model object " + i, type: "Model", modelURL: "http://headache.hungry.com/~seth/hifi/controller-tests/color-cube.obj", - + position: sectionCenterA, rotation: sectionRotation, - + gravity: (dynamic && !collisionless) ? { x: 0, y: -1, z: 0 } : { x: 0, y: 0, z: 0 }, dimensions: { x: 0.2, y: 0.2, z: 0.2 }, userData: JSON.stringify({ @@ -270,8 +270,8 @@ Entities.deleteEntity(nearbyID); } - for (var i = 0; i < overlays.length; i++) { - var overlayID = overlays[i]; + for (var j = 0; j < overlays.length; j++) { + var overlayID = overlays[j]; Overlays.deleteOverlay(overlayID); } }); diff --git a/scripts/system/avatarapp.js b/scripts/system/avatarapp.js index 10ccb66d96..ece35acce7 100644 --- a/scripts/system/avatarapp.js +++ b/scripts/system/avatarapp.js @@ -329,36 +329,18 @@ function isGrabbable(entityID) { return false; } - var properties = Entities.getEntityProperties(entityID, ['clientOnly', 'userData']); + var properties = Entities.getEntityProperties(entityID, ['clientOnly', 'grab.grabbable']); if (properties.clientOnly) { - var userData; - try { - userData = JSON.parse(properties.userData); - } catch (e) { - userData = {}; - } - - return userData.grabbableKey && userData.grabbableKey.grabbable; + return properties.grab.grabbable; } return false; } function setGrabbable(entityID, grabbable) { - var properties = Entities.getEntityProperties(entityID, ['clientOnly', 'userData']); + var properties = Entities.getEntityProperties(entityID, ['clientOnly']); if (properties.clientOnly) { - var userData; - try { - userData = JSON.parse(properties.userData); - } catch (e) { - userData = {}; - } - - if (userData.grabbableKey === undefined) { - userData.grabbableKey = {}; - } - userData.grabbableKey.grabbable = grabbable; - Entities.editEntity(entityID, {userData: JSON.stringify(userData)}); + Entities.editEntity(entityID, { grab: { grabbable: grabbable }}); } } diff --git a/scripts/system/controllers/controllerDispatcher.js b/scripts/system/controllers/controllerDispatcher.js index db622a6724..62db965444 100644 --- a/scripts/system/controllers/controllerDispatcher.js +++ b/scripts/system/controllers/controllerDispatcher.js @@ -10,9 +10,8 @@ /* global Script, Entities, Overlays, Controller, Vec3, Quat, getControllerWorldLocation, controllerDispatcherPlugins:true, controllerDispatcherPluginsNeedSort:true, LEFT_HAND, RIGHT_HAND, NEAR_GRAB_PICK_RADIUS, DEFAULT_SEARCH_SPHERE_DISTANCE, DISPATCHER_PROPERTIES, - getGrabPointSphereOffset, HMD, MyAvatar, Messages, findHandChildEntities, Picks, PickType, Pointers, COLORS_GRAB_SEARCHING_HALF_SQUEEZE - COLORS_GRAB_SEARCHING_FULL_SQUEEZE, COLORS_GRAB_DISTANCE_HOLD, TRIGGER_ON_VALUE, PointerManager, print getGrabPointSphereOffset, HMD, MyAvatar, Messages, findHandChildEntities, Picks, PickType, Pointers, + PointerManager, getGrabPointSphereOffset, HMD, MyAvatar, Messages, findHandChildEntities, Picks, PickType, Pointers, PointerManager, print, Selection, DISPATCHER_HOVERING_LIST, DISPATCHER_HOVERING_STYLE */ @@ -34,6 +33,8 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); var PROFILE = false; var DEBUG = false; + var SHOW_GRAB_SPHERE = false; + if (typeof Test !== "undefined") { PROFILE = true; @@ -51,6 +52,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); this.tabletID = null; this.blacklist = []; this.pointerManager = new PointerManager(); + this.grabSphereOverlays = [null, null]; // a module can occupy one or more "activity" slots while it's running. If all the required slots for a module are // not set to false (not in use), a module cannot start. When a module is using a slot, that module's name @@ -251,7 +253,28 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); for (h = LEFT_HAND; h <= RIGHT_HAND; h++) { if (controllerLocations[h].valid) { var controllerPosition = controllerLocations[h].position; - var nearbyEntityIDs = Entities.findEntities(controllerPosition, NEAR_MAX_RADIUS * sensorScaleFactor); + var findRadius = NEAR_MAX_RADIUS * sensorScaleFactor; + + if (SHOW_GRAB_SPHERE) { + if (this.grabSphereOverlays[h]) { + Overlays.editOverlay(this.grabSphereOverlays[h], { position: controllerLocations[h].position }); + } else { + var grabSphereSize = findRadius * 2; + this.grabSphereOverlays[h] = Overlays.addOverlay("sphere", { + position: controllerLocations[h].position, + dimensions: { x: grabSphereSize, y: grabSphereSize, z: grabSphereSize }, + color: { red: 30, green: 30, blue: 255 }, + alpha: 0.3, + solid: true, + visible: true, + // lineWidth: 2.0, + drawInFront: false, + grabbable: false + }); + } + } + + var nearbyEntityIDs = Entities.findEntities(controllerPosition, findRadius); for (var j = 0; j < nearbyEntityIDs.length; j++) { var entityID = nearbyEntityIDs[j]; var props = Entities.getEntityProperties(entityID, DISPATCHER_PROPERTIES); diff --git a/scripts/system/controllers/controllerDisplay.js b/scripts/system/controllers/controllerDisplay.js index 8aa0393357..e40b761307 100644 --- a/scripts/system/controllers/controllerDisplay.js +++ b/scripts/system/controllers/controllerDisplay.js @@ -7,7 +7,7 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -/* globals createControllerDisplay:true deleteControllerDisplay:true */ +/* globals createControllerDisplay:true, deleteControllerDisplay:true, Controller, Overlays, Vec3, MyAvatar, Quat */ function clamp(value, min, max) { if (value < min) { @@ -188,7 +188,7 @@ createControllerDisplay = function(config) { for (var partName in controller.parts) { var part = controller.parts[partName]; var localPosition = Vec3.subtract(part.naturalPosition, controller.naturalPosition); - var localRotation = { x: 0, y: 0, z: 0, w: 1 } + var localRotation = { x: 0, y: 0, z: 0, w: 1 }; controllerDisplay.parts[partName] = controller.parts[partName]; @@ -203,7 +203,7 @@ createControllerDisplay = function(config) { if (part.defaultTextureLayer) { var textures = {}; textures[part.textureName] = part.textureLayers[part.defaultTextureLayer].defaultTextureURL; - properties['textures'] = textures; + properties.textures = textures; } var overlayID = Overlays.addOverlay("model", properties); diff --git a/scripts/system/controllers/controllerDisplayManager.js b/scripts/system/controllers/controllerDisplayManager.js index e3fd74e05b..f93f8b1624 100644 --- a/scripts/system/controllers/controllerDisplayManager.js +++ b/scripts/system/controllers/controllerDisplayManager.js @@ -7,8 +7,9 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -/* globals ControllerDisplayManager:true createControllerDisplay deleteControllerDisplay - VIVE_CONTROLLER_CONFIGURATION_LEFT VIVE_CONTROLLER_CONFIGURATION_RIGHT */ +/* globals ControllerDisplayManager:true, createControllerDisplay, deleteControllerDisplay, + VIVE_CONTROLLER_CONFIGURATION_LEFT, VIVE_CONTROLLER_CONFIGURATION_RIGHT, Script, HMD, Controller, + MyAvatar, Overlays, TOUCH_CONTROLLER_CONFIGURATION_LEFT, TOUCH_CONTROLLER_CONFIGURATION_RIGHT, Messages */ /* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ (function () { @@ -93,7 +94,7 @@ ControllerDisplayManager = function() { if (controllerRight) { controllerRight.resize(sensorScaleFactor); } - }; + } var handleMessages = function(channel, message, sender) { var i, data, name, visible; diff --git a/scripts/system/controllers/controllerModules/disableOtherModule.js b/scripts/system/controllers/controllerModules/disableOtherModule.js index 0928b29d5d..7636c56f65 100644 --- a/scripts/system/controllers/controllerModules/disableOtherModule.js +++ b/scripts/system/controllers/controllerModules/disableOtherModule.js @@ -58,18 +58,16 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); if (channel === 'Hifi-Hand-Disabler') { if (message === 'left') { leftDisableModules.disableModules = true; - } - if (message === 'right') { + } else if (message === 'right') { rightDisableModules.disableModules = true; - } - if (message === 'both' || message === 'none') { - if (message === 'both') { - leftDisableModules.disableModules = true; - rightDisableModules.disableModules = true; - } else if (message === 'none') { - leftDisableModules.disableModules = false; - rightDisableModules.disableModules = false; - } + } else if (message === 'both') { + leftDisableModules.disableModules = true; + rightDisableModules.disableModules = true; + } else if (message === 'none') { + leftDisableModules.disableModules = false; + rightDisableModules.disableModules = false; + } else { + print("disableOtherModule -- unknown command: " + message); } } } diff --git a/scripts/system/controllers/controllerModules/equipEntity.js b/scripts/system/controllers/controllerModules/equipEntity.js index 91c8d89daf..f4d9c731b7 100644 --- a/scripts/system/controllers/controllerModules/equipEntity.js +++ b/scripts/system/controllers/controllerModules/equipEntity.js @@ -6,11 +6,11 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -/* global Script, Entities, MyAvatar, Controller, RIGHT_HAND, LEFT_HAND, Camera, +/* global Script, Entities, MyAvatar, Controller, RIGHT_HAND, LEFT_HAND, Camera, print, getControllerJointIndex, enableDispatcherModule, disableDispatcherModule, entityIsFarGrabbedByOther, Messages, makeDispatcherModuleParameters, makeRunningValues, Settings, entityHasActions, Vec3, Overlays, flatten, Xform, getControllerWorldLocation, ensureDynamic, entityIsCloneable, - cloneEntity, DISPATCHER_PROPERTIES, Uuid, unhighlightTargetEntity, isInEditMode + cloneEntity, DISPATCHER_PROPERTIES, Uuid, unhighlightTargetEntity, isInEditMode, getGrabbableData */ Script.include("/~/system/libraries/Xform.js"); @@ -66,12 +66,16 @@ EquipHotspotBuddy.prototype.updateHotspot = function(hotspot, timestamp) { overlays: [] }; - var diameter = hotspot.radius * 2; + var dimensions = hotspot.radius * 2 * EQUIP_SPHERE_SCALE_FACTOR; + + if (hotspot.indicatorURL) { + dimensions = hotspot.indicatorScale; + } // override default sphere with a user specified model, if it exists. overlayInfoSet.overlays.push(Overlays.addOverlay("model", { name: "hotspot overlay", - url: hotspot.modelURL ? hotspot.modelURL : DEFAULT_SPHERE_MODEL_URL, + url: hotspot.indicatorURL ? hotspot.indicatorURL : DEFAULT_SPHERE_MODEL_URL, position: hotspot.worldPosition, rotation: { x: 0, @@ -79,8 +83,7 @@ EquipHotspotBuddy.prototype.updateHotspot = function(hotspot, timestamp) { z: 0, w: 1 }, - dimensions: diameter * EQUIP_SPHERE_SCALE_FACTOR, - scale: hotspot.modelScale, + dimensions: dimensions, ignoreRayIntersection: true })); overlayInfoSet.type = "model"; @@ -137,8 +140,13 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa var position = entityXform.xformPoint(overlayInfoSet.localPosition); var dimensions; - if (overlayInfoSet.type === "sphere") { - dimensions = (overlayInfoSet.hotspot.radius / 2) * overlayInfoSet.currentSize * EQUIP_SPHERE_SCALE_FACTOR; + if (overlayInfoSet.hotspot.indicatorURL) { + var ratio = overlayInfoSet.currentSize / overlayInfoSet.targetSize; + dimensions = { + x: overlayInfoSet.hotspot.dimensions.x * ratio, + y: overlayInfoSet.hotspot.dimensions.y * ratio, + z: overlayInfoSet.hotspot.dimensions.z * ratio + }; } else { dimensions = (overlayInfoSet.hotspot.radius / 2) * overlayInfoSet.currentSize; } @@ -158,12 +166,21 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa } }; + +var alreadyWarned = {}; +function warnAboutUserData(props) { + if (alreadyWarned[props.id]) { + return; + } + print("Warning -- overriding grab properties with userData for " + props.id + " / " + props.name); + alreadyWarned[props.id] = true; +} + + (function() { var ATTACH_POINT_SETTINGS = "io.highfidelity.attachPoints"; - var EQUIP_RADIUS = 1.0; // radius used for palm vs equip-hotspot for equipping. - var HAPTIC_PULSE_STRENGTH = 1.0; var HAPTIC_PULSE_DURATION = 13.0; var HAPTIC_TEXTURE_STRENGTH = 0.1; @@ -176,36 +193,86 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa var TRIGGER_OFF_VALUE = 0.1; var TRIGGER_ON_VALUE = TRIGGER_OFF_VALUE + 0.05; // Squeezed just enough to activate search or near grab var BUMPER_ON_VALUE = 0.5; - + var EMPTY_PARENT_ID = "{00000000-0000-0000-0000-000000000000}"; - + var UNEQUIP_KEY = "u"; function getWearableData(props) { - var wearable = {}; - try { - if (!props.userDataParsed) { - props.userDataParsed = JSON.parse(props.userData); - } + if (props.grab.equippable) { + // if equippable is true, we know this was already converted from the old userData style to properties + return { + joints: { + LeftHand: [ props.grab.equippableLeftPosition, props.grab.equippableLeftRotation ], + RightHand: [ props.grab.equippableRightPosition, props.grab.equippableRightRotation ] + }, + indicatorURL: props.grab.equippableIndicatorURL, + indicatorScale: props.grab.equippableIndicatorScale, + indicatorOffset: props.grab.equippableIndicatorOffset + }; + } else { + // check for old userData equippability. The JSON reader will convert userData to properties + // in EntityTree.cpp, but this won't catch things created from scripts or some items in + // the market. Eventually we'll remove this section. + try { + if (!props.userDataParsed) { + props.userDataParsed = JSON.parse(props.userData); + } + var userDataParsed = props.userDataParsed; - wearable = props.userDataParsed.wearable ? props.userDataParsed.wearable : {}; - } catch (err) { - // don't want to spam the logs - } - return wearable; - } - function getEquipHotspotsData(props) { - var equipHotspots = []; - try { - if (!props.userDataParsed) { - props.userDataParsed = JSON.parse(props.userData); - } + // userData: { wearable: { joints: { LeftHand: {...}, RightHand: {...} } } } + if (userDataParsed.wearable && userDataParsed.wearable.joints) { + warnAboutUserData(props); + userDataParsed.wearable.indicatorURL = ""; + userDataParsed.wearable.indicatorScale = { x: 1, y: 1, z: 1 }; + userDataParsed.wearable.indicatorOffset = { x: 0, y: 0, z: 0 }; + return userDataParsed.wearable; + } - equipHotspots = props.userDataParsed.equipHotspots ? props.userDataParsed.equipHotspots : []; - } catch (err) { - // don't want to spam the logs + // userData: { equipHotspots: { joints: { LeftHand: {...}, RightHand: {...} } } } + // https://highfidelity.atlassian.net/wiki/spaces/HOME/pages/51085337/Authoring+Equippable+Entities + if (userDataParsed.equipHotspots && + userDataParsed.equipHotspots.length > 0 && + userDataParsed.equipHotspots[0].joints) { + warnAboutUserData(props); + var hotSpot = userDataParsed.equipHotspots[0]; + + var indicatorScale = { x: hotSpot.radius, y: hotSpot.radius, z: hotSpot.radius }; + if (hotSpot.modelURL && hotSpot.modelURL !== "") { + indicatorScale = hotSpot.modelScale; + } + + return { + joints: hotSpot.joints, + indicatorURL: hotSpot.modelURL, + indicatorScale: indicatorScale, + indicatorOffset: hotSpot.position, + }; + } + + // userData:{grabbableKey:{spatialKey:{leftRelativePosition:{...},rightRelativePosition:{...}}}} + if (userDataParsed.grabbableKey && + userDataParsed.grabbableKey.spatialKey) { + warnAboutUserData(props); + var joints = {}; + joints.LeftHand = [ { x: 0, y: 0, z: 0 }, { x: 0, y: 0, z: 0, w: 1 } ]; + joints.RightHand = [ { x: 0, y: 0, z: 0 }, { x: 0, y: 0, z: 0, w: 1 } ]; + if (userDataParsed.grabbableKey.spatialKey.leftRelativePosition) { + joints.LeftHand = [userDataParsed.grabbableKey.spatialKey.leftRelativePosition, + userDataParsed.grabbableKey.spatialKey.relativeRotation]; + } + if (userDataParsed.grabbableKey.spatialKey.rightRelativePosition) { + joints.RightHand = [userDataParsed.grabbableKey.spatialKey.rightRelativePosition, + userDataParsed.grabbableKey.spatialKey.relativeRotation]; + } + return { joints: joints }; + } + + } catch (err) { + // don't spam logs + } + return null; } - return equipHotspots; } function getAttachPointSettings() { @@ -275,7 +342,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa this.handHasBeenRightsideUp = false; this.parameters = makeDispatcherModuleParameters( - 300, + 115, this.hand === RIGHT_HAND ? ["rightHand", "rightHandEquip"] : ["leftHand", "leftHandEquip"], [], 100); @@ -299,51 +366,29 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa // * radius {number} radius of equip hotspot // * joints {Object} keys are joint names values are arrays of two elements: // offset position {Vec3} and offset rotation {Quat}, both are in the coordinate system of the joint. - // * modelURL {string} url for model to use instead of default sphere. - // * modelScale {Vec3} scale factor for model + // * indicatorURL {string} url for model to use instead of default sphere. + // * indicatorScale {Vec3} scale factor for model this.collectEquipHotspots = function(props) { var result = []; var entityID = props.id; var entityXform = new Xform(props.rotation, props.position); - var equipHotspotsProps = getEquipHotspotsData(props); - if (equipHotspotsProps && equipHotspotsProps.length > 0) { - var i, length = equipHotspotsProps.length; - for (i = 0; i < length; i++) { - var hotspot = equipHotspotsProps[i]; - if (hotspot.position && hotspot.radius && hotspot.joints) { - result.push({ - key: entityID.toString() + i.toString(), - entityID: entityID, - localPosition: hotspot.position, - worldPosition: entityXform.xformPoint(hotspot.position), - radius: hotspot.radius, - joints: hotspot.joints, - modelURL: hotspot.modelURL, - modelScale: hotspot.modelScale - }); - } - } - } else { - var wearableProps = getWearableData(props); - var sensorToScaleFactor = MyAvatar.sensorToWorldScale; - if (wearableProps && wearableProps.joints) { - - result.push({ - key: entityID.toString() + "0", - entityID: entityID, - localPosition: { - x: 0, - y: 0, - z: 0 - }, - worldPosition: entityXform.pos, - radius: EQUIP_RADIUS * sensorToScaleFactor, - joints: wearableProps.joints, - modelURL: null, - modelScale: null - }); - } + var wearableProps = getWearableData(props); + var sensorToScaleFactor = MyAvatar.sensorToWorldScale; + if (wearableProps && wearableProps.joints) { + result.push({ + key: entityID.toString() + "0", + entityID: entityID, + localPosition: wearableProps.indicatorOffset, + worldPosition: entityXform.pos, + radius: ((wearableProps.indicatorScale.x + + wearableProps.indicatorScale.y + + wearableProps.indicatorScale.z) / 3) * sensorToScaleFactor, + dimensions: wearableProps.indicatorScale, + joints: wearableProps.joints, + indicatorURL: wearableProps.indicatorURL, + indicatorScale: wearableProps.indicatorScale, + }); } return result; }; @@ -492,7 +537,8 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa }; Messages.sendLocalMessage('Hifi-unhighlight-entity', JSON.stringify(message)); - var grabbedProperties = Entities.getEntityProperties(this.targetEntityID); + var grabbedProperties = Entities.getEntityProperties(this.targetEntityID, DISPATCHER_PROPERTIES); + var grabData = getGrabbableData(grabbedProperties); // if an object is "equipped" and has a predefined offset, use it. if (this.grabbedHotspot) { @@ -510,7 +556,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa } var handJointIndex; - if (this.ignoreIK) { + if (grabData.grabFollowsController) { handJointIndex = this.controllerJointIndex; } else { handJointIndex = MyAvatar.getJointIndex(this.hand === RIGHT_HAND ? "RightHand" : "LeftHand"); @@ -796,7 +842,8 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa if (intersection.intersects) { var entityID = intersection.entityID; var entityProperties = Entities.getEntityProperties(entityID, DISPATCHER_PROPERTIES); - var hasEquipData = getWearableData(entityProperties).joints || getEquipHotspotsData(entityProperties).length > 0; + entityProperties.id = entityID; + var hasEquipData = getWearableData(entityProperties); if (hasEquipData && entityProperties.parentID === EMPTY_PARENT_ID && !entityIsFarGrabbedByOther(entityID)) { entityProperties.id = entityID; var rightHandPosition = MyAvatar.getJointPosition("RightHand"); @@ -804,7 +851,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa var distanceToRightHand = Vec3.distance(entityProperties.position, rightHandPosition); var distanceToLeftHand = Vec3.distance(entityProperties.position, leftHandPosition); var leftHandAvailable = leftEquipEntity.targetEntityID === null; - var rightHandAvailable = rightEquipEntity.targetEntityID === null; + var rightHandAvailable = rightEquipEntity.targetEntityID === null; if (rightHandAvailable && (distanceToRightHand < distanceToLeftHand || !leftHandAvailable)) { // clear any existing grab actions on the entity now (their later removal could affect bootstrapping flags) clearGrabActions(entityID); @@ -817,7 +864,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa } } }; - + var onKeyPress = function(event) { if (event.text.toLowerCase() === UNEQUIP_KEY) { if (rightEquipEntity.targetEntityID) { @@ -828,7 +875,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa } } }; - + var deleteEntity = function(entityID) { if (rightEquipEntity.targetEntityID === entityID) { rightEquipEntity.endEquipEntity(); @@ -837,7 +884,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa leftEquipEntity.endEquipEntity(); } }; - + var clearEntities = function() { if (rightEquipEntity.targetEntityID) { rightEquipEntity.endEquipEntity(); @@ -846,7 +893,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa leftEquipEntity.endEquipEntity(); } }; - + Messages.subscribe('Hifi-Hand-Grab'); Messages.subscribe('Hifi-Hand-Drop'); Messages.messageReceived.connect(handleMessage); diff --git a/scripts/system/controllers/controllerModules/farActionGrabEntity.js b/scripts/system/controllers/controllerModules/farActionGrabEntity.js index 2e73526728..4b5b11bdb5 100644 --- a/scripts/system/controllers/controllerModules/farActionGrabEntity.js +++ b/scripts/system/controllers/controllerModules/farActionGrabEntity.js @@ -8,38 +8,19 @@ /* jslint bitwise: true */ /* global Script, Controller, RIGHT_HAND, LEFT_HAND, Mat4, MyAvatar, Vec3, Camera, Quat, - getGrabPointSphereOffset, getEnabledModuleByName, makeRunningValues, Entities, + getEnabledModuleByName, makeRunningValues, Entities, enableDispatcherModule, disableDispatcherModule, entityIsDistanceGrabbable, entityIsGrabbable, makeDispatcherModuleParameters, MSECS_PER_SEC, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, - PICK_MAX_DISTANCE, COLORS_GRAB_SEARCHING_HALF_SQUEEZE, COLORS_GRAB_SEARCHING_FULL_SQUEEZE, COLORS_GRAB_DISTANCE_HOLD, - DEFAULT_SEARCH_SPHERE_DISTANCE, TRIGGER_OFF_VALUE, TRIGGER_ON_VALUE, ZERO_VEC, ensureDynamic, - getControllerWorldLocation, projectOntoEntityXYPlane, ContextOverlay, HMD, Reticle, Overlays, isPointingAtUI - Picks, makeLaserLockInfo Xform, makeLaserParams, AddressManager, getEntityParents, Selection, DISPATCHER_HOVERING_LIST, - worldPositionToRegistrationFrameMatrix + TRIGGER_OFF_VALUE, TRIGGER_ON_VALUE, ZERO_VEC, ensureDynamic, + getControllerWorldLocation, projectOntoEntityXYPlane, ContextOverlay, HMD, + Picks, makeLaserLockInfo, makeLaserParams, AddressManager, getEntityParents, Selection, DISPATCHER_HOVERING_LIST, + worldPositionToRegistrationFrameMatrix, DISPATCHER_PROPERTIES, Uuid, Picks */ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); Script.include("/~/system/libraries/controllers.js"); -Script.include("/~/system/libraries/Xform.js"); (function() { - var GRABBABLE_PROPERTIES = [ - "position", - "registrationPoint", - "rotation", - "gravity", - "collidesWith", - "dynamic", - "collisionless", - "locked", - "name", - "shapeType", - "parentID", - "parentJointIndex", - "density", - "dimensions", - "userData" - ]; var MARGIN = 25; @@ -106,9 +87,9 @@ Script.include("/~/system/libraries/Xform.js"); this.locked = false; this.highlightedEntity = null; this.reticleMinX = MARGIN; - this.reticleMaxX; + this.reticleMaxX = null; this.reticleMinY = MARGIN; - this.reticleMaxY; + this.reticleMaxY = null; this.ignoredEntities = []; @@ -212,7 +193,7 @@ Script.include("/~/system/libraries/Xform.js"); var worldToSensorMat = Mat4.inverse(MyAvatar.getSensorToWorldMatrix()); var roomControllerPosition = Mat4.transformPoint(worldToSensorMat, worldControllerPosition); - var grabbedProperties = Entities.getEntityProperties(this.grabbedThingID, GRABBABLE_PROPERTIES); + var grabbedProperties = Entities.getEntityProperties(this.grabbedThingID, DISPATCHER_PROPERTIES); var now = Date.now(); var deltaObjectTime = (now - this.currentObjectTime) / MSECS_PER_SEC; // convert to seconds this.currentObjectTime = now; @@ -329,7 +310,7 @@ Script.include("/~/system/libraries/Xform.js"); this.notPointingAtEntity = function(controllerData) { var intersection = controllerData.rayPicks[this.hand]; - var entityProperty = Entities.getEntityProperties(intersection.objectID); + var entityProperty = Entities.getEntityProperties(intersection.objectID, DISPATCHER_PROPERTIES); var entityType = entityProperty.type; var hudRayPick = controllerData.hudRayPicks[this.hand]; var point2d = this.calculateNewReticlePosition(hudRayPick.intersection); @@ -373,7 +354,7 @@ Script.include("/~/system/libraries/Xform.js"); var worldControllerPosition = controllerLocation.position; var worldControllerRotation = controllerLocation.orientation; - var grabbedProperties = Entities.getEntityProperties(intersection.objectID, GRABBABLE_PROPERTIES); + var grabbedProperties = Entities.getEntityProperties(intersection.objectID, DISPATCHER_PROPERTIES); this.currentObjectPosition = grabbedProperties.position; this.grabRadius = intersection.distance; @@ -395,7 +376,7 @@ Script.include("/~/system/libraries/Xform.js"); }; this.targetIsNull = function() { - var properties = Entities.getEntityProperties(this.grabbedThingID); + var properties = Entities.getEntityProperties(this.grabbedThingID, DISPATCHER_PROPERTIES); if (Object.keys(properties).length === 0 && this.distanceHolding) { return true; } @@ -460,8 +441,8 @@ Script.include("/~/system/libraries/Xform.js"); // if we are doing a distance grab and the object or tablet gets close enough to the controller, // stop the far-grab so the near-grab or equip can take over. for (var k = 0; k < nearGrabReadiness.length; k++) { - if (nearGrabReadiness[k].active && (nearGrabReadiness[k].targets[0] === this.grabbedThingID - || HMD.tabletID && nearGrabReadiness[k].targets[0] === HMD.tabletID)) { + if (nearGrabReadiness[k].active && (nearGrabReadiness[k].targets[0] === this.grabbedThingID || + HMD.tabletID && nearGrabReadiness[k].targets[0] === HMD.tabletID)) { this.endFarGrabAction(); this.restoreIgnoredEntities(); return makeRunningValues(false, [], []); @@ -487,11 +468,7 @@ Script.include("/~/system/libraries/Xform.js"); Selection.removeFromSelectedItemsList(DISPATCHER_HOVERING_LIST, "entity", this.highlightedEntity); this.highlightedEntity = null; - var targetProps = Entities.getEntityProperties(entityID, [ - "dynamic", "shapeType", "position", - "rotation", "dimensions", "density", - "userData", "locked", "type", "href" - ]); + var targetProps = Entities.getEntityProperties(entityID, DISPATCHER_PROPERTIES); if (targetProps.href !== "") { AddressManager.handleLookupString(targetProps.href); this.restoreIgnoredEntities(); @@ -540,11 +517,7 @@ Script.include("/~/system/libraries/Xform.js"); if (this.highlightedEntity !== targetEntityID) { Selection.removeFromSelectedItemsList(DISPATCHER_HOVERING_LIST, "entity", this.highlightedEntity); - var selectionTargetProps = Entities.getEntityProperties(targetEntityID, [ - "dynamic", "shapeType", "position", - "rotation", "dimensions", "density", - "userData", "locked", "type", "href" - ]); + var selectionTargetProps = Entities.getEntityProperties(targetEntityID, DISPATCHER_PROPERTIES); var selectionTargetObject = new TargetObject(targetEntityID, selectionTargetProps); selectionTargetObject.parentProps = getEntityParents(selectionTargetProps); @@ -574,11 +547,12 @@ Script.include("/~/system/libraries/Xform.js"); if (!_this.entityWithContextOverlay && _this.contextOverlayTimer && _this.potentialEntityWithContextOverlay === rayPickInfo.objectID) { - var props = Entities.getEntityProperties(rayPickInfo.objectID); + var props = Entities.getEntityProperties(rayPickInfo.objectID, DISPATCHER_PROPERTIES); var pointerEvent = { type: "Move", id: _this.hand + 1, // 0 is reserved for hardware mouse - pos2D: projectOntoEntityXYPlane(rayPickInfo.objectID, rayPickInfo.intersection, props), + pos2D: projectOntoEntityXYPlane(rayPickInfo.objectID, + rayPickInfo.intersection, props), pos3D: rayPickInfo.intersection, normal: rayPickInfo.surfaceNormal, direction: Vec3.subtract(ZERO_VEC, rayPickInfo.surfaceNormal), diff --git a/scripts/system/controllers/controllerModules/farActionGrabEntityDynOnly.js b/scripts/system/controllers/controllerModules/farActionGrabEntityDynOnly.js index 78abcb9b20..571b8feda3 100644 --- a/scripts/system/controllers/controllerModules/farActionGrabEntityDynOnly.js +++ b/scripts/system/controllers/controllerModules/farActionGrabEntityDynOnly.js @@ -11,32 +11,14 @@ makeRunningValues, Entities, enableDispatcherModule, disableDispatcherModule, entityIsGrabbable, makeDispatcherModuleParameters, MSECS_PER_SEC, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, TRIGGER_OFF_VALUE, TRIGGER_ON_VALUE, ZERO_VEC, getControllerWorldLocation, projectOntoEntityXYPlane, ContextOverlay, HMD, - Picks, makeLaserLockInfo, Xform, makeLaserParams, AddressManager, getEntityParents, Selection, DISPATCHER_HOVERING_LIST, - Uuid, worldPositionToRegistrationFrameMatrix + Picks, makeLaserLockInfo, makeLaserParams, AddressManager, getEntityParents, Selection, DISPATCHER_HOVERING_LIST, + Uuid, worldPositionToRegistrationFrameMatrix, DISPATCHER_PROPERTIES */ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); Script.include("/~/system/libraries/controllers.js"); -Script.include("/~/system/libraries/Xform.js"); (function() { - var GRABBABLE_PROPERTIES = [ - "position", - "registrationPoint", - "rotation", - "gravity", - "collidesWith", - "dynamic", - "collisionless", - "locked", - "name", - "shapeType", - "parentID", - "parentJointIndex", - "density", - "dimensions", - "userData" - ]; var MARGIN = 25; @@ -45,7 +27,6 @@ Script.include("/~/system/libraries/Xform.js"); this.entityProps = entityProps; this.targetEntityID = null; this.targetEntityProps = null; - this.previousCollisionStatus = null; this.getTargetEntity = function() { var parentPropsLength = this.parentProps.length; @@ -74,7 +55,6 @@ Script.include("/~/system/libraries/Xform.js"); this.potentialEntityWithContextOverlay = false; this.entityWithContextOverlay = false; this.contextOverlayTimer = false; - this.previousCollisionStatus = false; this.locked = false; this.highlightedEntity = null; this.reticleMinX = MARGIN; @@ -182,7 +162,7 @@ Script.include("/~/system/libraries/Xform.js"); var worldToSensorMat = Mat4.inverse(MyAvatar.getSensorToWorldMatrix()); var roomControllerPosition = Mat4.transformPoint(worldToSensorMat, worldControllerPosition); - var grabbedProperties = Entities.getEntityProperties(this.grabbedThingID, GRABBABLE_PROPERTIES); + var grabbedProperties = Entities.getEntityProperties(this.grabbedThingID, DISPATCHER_PROPERTIES); var now = Date.now(); var deltaObjectTime = (now - this.currentObjectTime) / MSECS_PER_SEC; // convert to seconds this.currentObjectTime = now; @@ -284,7 +264,7 @@ Script.include("/~/system/libraries/Xform.js"); this.notPointingAtEntity = function(controllerData) { var intersection = controllerData.rayPicks[this.hand]; - var entityProperty = Entities.getEntityProperties(intersection.objectID); + var entityProperty = Entities.getEntityProperties(intersection.objectID, DISPATCHER_PROPERTIES); var entityType = entityProperty.type; var hudRayPick = controllerData.hudRayPicks[this.hand]; var point2d = this.calculateNewReticlePosition(hudRayPick.intersection); @@ -319,7 +299,7 @@ Script.include("/~/system/libraries/Xform.js"); var worldControllerPosition = controllerLocation.position; var worldControllerRotation = controllerLocation.orientation; - var grabbedProperties = Entities.getEntityProperties(intersection.objectID, GRABBABLE_PROPERTIES); + var grabbedProperties = Entities.getEntityProperties(intersection.objectID, DISPATCHER_PROPERTIES); this.currentObjectPosition = grabbedProperties.position; this.grabRadius = intersection.distance; @@ -341,7 +321,7 @@ Script.include("/~/system/libraries/Xform.js"); }; this.targetIsNull = function() { - var properties = Entities.getEntityProperties(this.grabbedThingID); + var properties = Entities.getEntityProperties(this.grabbedThingID, DISPATCHER_PROPERTIES); if (Object.keys(properties).length === 0 && this.distanceHolding) { return true; } @@ -351,7 +331,7 @@ Script.include("/~/system/libraries/Xform.js"); this.getTargetProps = function (controllerData) { var targetEntityID = controllerData.rayPicks[this.hand].objectID; if (targetEntityID) { - return Entities.getEntityProperties(targetEntityID); + return Entities.getEntityProperties(targetEntityID, DISPATCHER_PROPERTIES); } return null; }; @@ -435,11 +415,7 @@ Script.include("/~/system/libraries/Xform.js"); Selection.removeFromSelectedItemsList(DISPATCHER_HOVERING_LIST, "entity", this.highlightedEntity); this.highlightedEntity = null; - var targetProps = Entities.getEntityProperties(entityID, [ - "dynamic", "shapeType", "position", - "rotation", "dimensions", "density", - "userData", "locked", "type", "href" - ]); + var targetProps = Entities.getEntityProperties(entityID, DISPATCHER_PROPERTIES); if (targetProps.href !== "") { AddressManager.handleLookupString(targetProps.href); return makeRunningValues(false, [], []); @@ -488,11 +464,7 @@ Script.include("/~/system/libraries/Xform.js"); if (this.highlightedEntity !== targetEntityID) { Selection.removeFromSelectedItemsList(DISPATCHER_HOVERING_LIST, "entity", this.highlightedEntity); - var selectionTargetProps = Entities.getEntityProperties(targetEntityID, [ - "dynamic", "shapeType", "position", - "rotation", "dimensions", "density", - "userData", "locked", "type", "href" - ]); + var selectionTargetProps = Entities.getEntityProperties(targetEntityID, DISPATCHER_PROPERTIES); var selectionTargetObject = new TargetObject(targetEntityID, selectionTargetProps); selectionTargetObject.parentProps = getEntityParents(selectionTargetProps); @@ -522,7 +494,8 @@ Script.include("/~/system/libraries/Xform.js"); if (!_this.entityWithContextOverlay && _this.contextOverlayTimer && _this.potentialEntityWithContextOverlay === rayPickInfo.objectID) { - var pEvProps = Entities.getEntityProperties(rayPickInfo.objectID); + var pEvProps = Entities.getEntityProperties(rayPickInfo.objectID, + DISPATCHER_PROPERTIES); var pointerEvent = { type: "Move", id: _this.hand + 1, // 0 is reserved for hardware mouse diff --git a/scripts/system/controllers/controllerModules/farParentGrabEntity.js b/scripts/system/controllers/controllerModules/farParentGrabEntity.js index a9ec246a32..45fe606c0f 100644 --- a/scripts/system/controllers/controllerModules/farParentGrabEntity.js +++ b/scripts/system/controllers/controllerModules/farParentGrabEntity.js @@ -10,34 +10,15 @@ /* global Script, Controller, RIGHT_HAND, LEFT_HAND, Mat4, MyAvatar, Vec3, Quat, getEnabledModuleByName, makeRunningValues, Entities, enableDispatcherModule, disableDispatcherModule, entityIsGrabbable, makeDispatcherModuleParameters, MSECS_PER_SEC, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, TRIGGER_OFF_VALUE, TRIGGER_ON_VALUE, ZERO_VEC, getControllerWorldLocation, - projectOntoEntityXYPlane, ContextOverlay, HMD, Picks, makeLaserLockInfo, Xform, makeLaserParams, AddressManager, + projectOntoEntityXYPlane, ContextOverlay, HMD, Picks, makeLaserLockInfo, makeLaserParams, AddressManager, getEntityParents, Selection, DISPATCHER_HOVERING_LIST, unhighlightTargetEntity, Messages, Uuid, findGroupParent, - worldPositionToRegistrationFrameMatrix + worldPositionToRegistrationFrameMatrix, DISPATCHER_PROPERTIES, findFarGrabJointChildEntities */ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); Script.include("/~/system/libraries/controllers.js"); -Script.include("/~/system/libraries/Xform.js"); (function() { - var GRABBABLE_PROPERTIES = [ - "position", - "registrationPoint", - "rotation", - "gravity", - "collidesWith", - "dynamic", - "collisionless", - "locked", - "name", - "shapeType", - "parentID", - "parentJointIndex", - "density", - "dimensions", - "userData" - ]; - var MARGIN = 25; function TargetObject(entityID, entityProps) { @@ -68,6 +49,7 @@ Script.include("/~/system/libraries/Xform.js"); this.hand = hand; this.targetEntityID = null; this.targetObject = null; + this.previouslyUnhooked = {}; this.previousParentID = {}; this.previousParentJointIndex = {}; this.potentialEntityWithContextOverlay = false; @@ -78,6 +60,7 @@ Script.include("/~/system/libraries/Xform.js"); this.reticleMaxX = 0; this.reticleMinY = MARGIN; this.reticleMaxY = 0; + this.lastUnexpectedChildrenCheckTime = 0; var FAR_GRAB_JOINTS = [65527, 65528]; // FARGRAB_LEFTHAND_INDEX, FARGRAB_RIGHTHAND_INDEX @@ -214,7 +197,7 @@ Script.include("/~/system/libraries/Xform.js"); var worldToSensorMat = Mat4.inverse(MyAvatar.getSensorToWorldMatrix()); var roomControllerPosition = Mat4.transformPoint(worldToSensorMat, worldControllerPosition); - var grabbedProperties = Entities.getEntityProperties(this.targetEntityID, GRABBABLE_PROPERTIES); + var grabbedProperties = Entities.getEntityProperties(this.targetEntityID, DISPATCHER_PROPERTIES); var now = Date.now(); var deltaObjectTime = (now - this.currentObjectTime) / MSECS_PER_SEC; // convert to seconds this.currentObjectTime = now; @@ -275,7 +258,7 @@ Script.include("/~/system/libraries/Xform.js"); this.endFarParentGrab = function (controllerData) { this.hapticTargetID = null; // var endProps = controllerData.nearbyEntityPropertiesByID[this.targetEntityID]; - var endProps = Entities.getEntityProperties(this.targetEntityID, GRABBABLE_PROPERTIES); + var endProps = Entities.getEntityProperties(this.targetEntityID, DISPATCHER_PROPERTIES); if (this.thisFarGrabJointIsParent(endProps)) { Entities.editEntity(this.targetEntityID, { parentID: this.previousParentID[this.targetEntityID], @@ -313,7 +296,7 @@ Script.include("/~/system/libraries/Xform.js"); this.notPointingAtEntity = function(controllerData) { var intersection = controllerData.rayPicks[this.hand]; - var entityProperty = Entities.getEntityProperties(intersection.objectID); + var entityProperty = Entities.getEntityProperties(intersection.objectID, DISPATCHER_PROPERTIES); var entityType = entityProperty.type; var hudRayPick = controllerData.hudRayPicks[this.hand]; var point2d = this.calculateNewReticlePosition(hudRayPick.intersection); @@ -348,7 +331,7 @@ Script.include("/~/system/libraries/Xform.js"); var worldControllerPosition = controllerLocation.position; var worldControllerRotation = controllerLocation.orientation; - var grabbedProperties = Entities.getEntityProperties(intersection.objectID, GRABBABLE_PROPERTIES); + var grabbedProperties = Entities.getEntityProperties(intersection.objectID, DISPATCHER_PROPERTIES); this.currentObjectPosition = grabbedProperties.position; this.grabRadius = intersection.distance; @@ -369,8 +352,51 @@ Script.include("/~/system/libraries/Xform.js"); } }; + this.checkForUnexpectedChildren = function (controllerData) { + // sometimes things can get parented to a hand and this script is unaware. Search for such entities and + // unhook them. + + var now = Date.now(); + var UNEXPECTED_CHILDREN_CHECK_TIME = 0.1; // seconds + if (now - this.lastUnexpectedChildrenCheckTime > MSECS_PER_SEC * UNEXPECTED_CHILDREN_CHECK_TIME) { + this.lastUnexpectedChildrenCheckTime = now; + + var children = findFarGrabJointChildEntities(this.hand); + var _this = this; + + children.forEach(function(childID) { + // we appear to be holding something and this script isn't in a state that would be holding something. + // unhook it. if we previously took note of this entity's parent, put it back where it was. This + // works around some problems that happen when more than one hand or avatar is passing something around. + if (_this.previousParentID[childID]) { + var previousParentID = _this.previousParentID[childID]; + var previousParentJointIndex = _this.previousParentJointIndex[childID]; + + // The main flaw with keeping track of previous parentage in individual scripts is: + // (1) A grabs something (2) B takes it from A (3) A takes it from B (4) A releases it + // now A and B will take turns passing it back to the other. Detect this and stop the loop here... + var UNHOOK_LOOP_DETECT_MS = 200; + if (_this.previouslyUnhooked[childID]) { + if (now - _this.previouslyUnhooked[childID] < UNHOOK_LOOP_DETECT_MS) { + previousParentID = Uuid.NULL; + previousParentJointIndex = -1; + } + } + _this.previouslyUnhooked[childID] = now; + + Entities.editEntity(childID, { + parentID: previousParentID, + parentJointIndex: previousParentJointIndex + }); + } else { + Entities.editEntity(childID, { parentID: Uuid.NULL }); + } + }); + } + }; + this.targetIsNull = function() { - var properties = Entities.getEntityProperties(this.targetEntityID, GRABBABLE_PROPERTIES); + var properties = Entities.getEntityProperties(this.targetEntityID, DISPATCHER_PROPERTIES); if (Object.keys(properties).length === 0 && this.distanceHolding) { return true; } @@ -380,7 +406,7 @@ Script.include("/~/system/libraries/Xform.js"); this.getTargetProps = function (controllerData) { var targetEntity = controllerData.rayPicks[this.hand].objectID; if (targetEntity) { - var gtProps = Entities.getEntityProperties(targetEntity, GRABBABLE_PROPERTIES); + var gtProps = Entities.getEntityProperties(targetEntity, DISPATCHER_PROPERTIES); if (entityIsGrabbable(gtProps)) { // give haptic feedback if (gtProps.id !== this.hapticTargetID) { @@ -416,6 +442,7 @@ Script.include("/~/system/libraries/Xform.js"); return makeRunningValues(true, [], []); } } else { + this.checkForUnexpectedChildren(controllerData); this.destroyContextOverlay(); return makeRunningValues(false, [], []); } @@ -480,11 +507,7 @@ Script.include("/~/system/libraries/Xform.js"); var entityID = rayPickInfo.objectID; Selection.removeFromSelectedItemsList(DISPATCHER_HOVERING_LIST, "entity", this.highlightedEntity); this.highlightedEntity = null; - var targetProps = Entities.getEntityProperties(entityID, [ - "dynamic", "shapeType", "position", - "rotation", "dimensions", "density", - "userData", "locked", "type", "href" - ]); + var targetProps = Entities.getEntityProperties(entityID, DISPATCHER_PROPERTIES); if (targetProps.href !== "") { AddressManager.handleLookupString(targetProps.href); return makeRunningValues(false, [], []); @@ -533,11 +556,7 @@ Script.include("/~/system/libraries/Xform.js"); var targetEntityID = rayPickInfo.objectID; if (this.highlightedEntity !== targetEntityID) { Selection.removeFromSelectedItemsList(DISPATCHER_HOVERING_LIST, "entity", this.highlightedEntity); - var selectionTargetProps = Entities.getEntityProperties(targetEntityID, [ - "dynamic", "shapeType", "position", - "rotation", "dimensions", "density", - "userData", "locked", "type", "href" - ]); + var selectionTargetProps = Entities.getEntityProperties(targetEntityID, DISPATCHER_PROPERTIES); var selectionTargetObject = new TargetObject(targetEntityID, selectionTargetProps); selectionTargetObject.parentProps = getEntityParents(selectionTargetProps); @@ -567,7 +586,8 @@ Script.include("/~/system/libraries/Xform.js"); if (!_this.entityWithContextOverlay && _this.contextOverlayTimer && _this.potentialEntityWithContextOverlay === rayPickInfo.objectID) { - var cotProps = Entities.getEntityProperties(rayPickInfo.objectID); + var cotProps = Entities.getEntityProperties(rayPickInfo.objectID, + DISPATCHER_PROPERTIES); var pointerEvent = { type: "Move", id: _this.hand + 1, // 0 is reserved for hardware mouse diff --git a/scripts/system/controllers/controllerModules/farTrigger.js b/scripts/system/controllers/controllerModules/farTrigger.js index 25df17ee84..2b003e4732 100644 --- a/scripts/system/controllers/controllerModules/farTrigger.js +++ b/scripts/system/controllers/controllerModules/farTrigger.js @@ -6,19 +6,18 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -/* global Script, Controller, RIGHT_HAND, LEFT_HAND, MyAvatar, getGrabPointSphereOffset, +/* global Script, RIGHT_HAND, LEFT_HAND, MyAvatar, makeRunningValues, Entities, enableDispatcherModule, disableDispatcherModule, makeDispatcherModuleParameters, - PICK_MAX_DISTANCE, COLORS_GRAB_SEARCHING_HALF_SQUEEZE, COLORS_GRAB_SEARCHING_FULL_SQUEEZE, COLORS_GRAB_DISTANCE_HOLD, - DEFAULT_SEARCH_SPHERE_DISTANCE, getGrabbableData, makeLaserParams + getGrabbableData, makeLaserParams, DISPATCHER_PROPERTIES */ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); Script.include("/~/system/libraries/controllers.js"); (function() { - function entityWantsNearTrigger(props) { + function entityWantsFarTrigger(props) { var grabbableData = getGrabbableData(props); - return grabbableData.triggerable || grabbableData.wantsTrigger; + return grabbableData.triggerable; } function FarTriggerEntity(hand) { @@ -37,11 +36,10 @@ Script.include("/~/system/libraries/controllers.js"); makeLaserParams(this.hand, false)); this.getTargetProps = function (controllerData) { - // nearbyEntityProperties is already sorted by length from controller var targetEntity = controllerData.rayPicks[this.hand].objectID; if (targetEntity) { - var targetProperties = Entities.getEntityProperties(targetEntity); - if (entityWantsNearTrigger(targetProperties)) { + var targetProperties = Entities.getEntityProperties(targetEntity, DISPATCHER_PROPERTIES); + if (entityWantsFarTrigger(targetProperties)) { return targetProperties; } } diff --git a/scripts/system/controllers/controllerModules/highlightNearbyEntities.js b/scripts/system/controllers/controllerModules/highlightNearbyEntities.js index bc09ebee7a..403b5d5149 100644 --- a/scripts/system/controllers/controllerModules/highlightNearbyEntities.js +++ b/scripts/system/controllers/controllerModules/highlightNearbyEntities.js @@ -8,11 +8,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -/* global Script, Controller, RIGHT_HAND, LEFT_HAND, MyAvatar, getGrabPointSphereOffset, - makeRunningValues, Entities, enableDispatcherModule, disableDispatcherModule, makeDispatcherModuleParameters, - PICK_MAX_DISTANCE, COLORS_GRAB_SEARCHING_HALF_SQUEEZE, COLORS_GRAB_SEARCHING_FULL_SQUEEZE, COLORS_GRAB_DISTANCE_HOLD, - DEFAULT_SEARCH_SPHERE_DISTANCE, getGrabbableData, makeLaserParams, entityIsCloneable, Messages, print -*/ +/* global Script, MyAvatar, entityIsCloneable, Messages, print */ "use strict"; @@ -134,7 +130,7 @@ rightHighlightNearbyEntities.removeEntityFromHighlightList(data.entityID); } } catch (e) { - print("Failed to parse message"); + print("highlightNearbyEntities -- Failed to parse message: " + JSON.stringify(message)); } } else if (channel === 'Hifi-unhighlight-all') { leftHighlightNearbyEntities.clearAll(); diff --git a/scripts/system/controllers/controllerModules/hudOverlayPointer.js b/scripts/system/controllers/controllerModules/hudOverlayPointer.js index 04a3911e0b..6181414084 100644 --- a/scripts/system/controllers/controllerModules/hudOverlayPointer.js +++ b/scripts/system/controllers/controllerModules/hudOverlayPointer.js @@ -10,16 +10,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -/* global Script, Controller, RIGHT_HAND, LEFT_HAND, Mat4, MyAvatar, Vec3, Camera, Quat, - getGrabPointSphereOffset, getEnabledModuleByName, makeRunningValues, Entities, - enableDispatcherModule, disableDispatcherModule, entityIsDistanceGrabbable, - makeDispatcherModuleParameters, MSECS_PER_SEC, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, - PICK_MAX_DISTANCE, COLORS_GRAB_SEARCHING_HALF_SQUEEZE, COLORS_GRAB_SEARCHING_FULL_SQUEEZE, COLORS_GRAB_DISTANCE_HOLD, - DEFAULT_SEARCH_SPHERE_DISTANCE, TRIGGER_OFF_VALUE, TRIGGER_ON_VALUE, ZERO_VEC, ensureDynamic, - getControllerWorldLocation, projectOntoEntityXYPlane, ContextOverlay, HMD, Reticle, Overlays, isPointingAtUI, - makeLaserParams - -*/ +/* global Script, Controller, RIGHT_HAND, LEFT_HAND, HMD, makeLaserParams */ (function() { Script.include("/~/system/libraries/controllers.js"); var ControllerDispatcherUtils = Script.require("/~/system/libraries/controllerDispatcherUtils.js"); @@ -72,7 +63,7 @@ this.processLaser = function(controllerData) { var controllerLocation = controllerData.controllerLocations[this.hand]; - var otherModuleRunning = this.getOtherModule().running; + // var otherModuleRunning = this.getOtherModule().running; if ((controllerData.triggerValues[this.hand] < ControllerDispatcherUtils.TRIGGER_ON_VALUE || !controllerLocation.valid) || this.pointingAtTablet(controllerData)) { return false; diff --git a/scripts/system/controllers/controllerModules/inEditMode.js b/scripts/system/controllers/controllerModules/inEditMode.js index 15da1537a1..4b6eb7e313 100644 --- a/scripts/system/controllers/controllerModules/inEditMode.js +++ b/scripts/system/controllers/controllerModules/inEditMode.js @@ -8,9 +8,8 @@ /* jslint bitwise: true */ /* global Script, Controller, RIGHT_HAND, LEFT_HAND, enableDispatcherModule, disableDispatcherModule, makeRunningValues, - Messages, makeDispatcherModuleParameters, HMD, getGrabPointSphereOffset, COLORS_GRAB_SEARCHING_HALF_SQUEEZE, - COLORS_GRAB_SEARCHING_FULL_SQUEEZE, COLORS_GRAB_DISTANCE_HOLD, DEFAULT_SEARCH_SPHERE_DISTANCE, TRIGGER_ON_VALUE, - getEnabledModuleByName, PICK_MAX_DISTANCE, isInEditMode, Picks, makeLaserParams, Entities + Messages, makeDispatcherModuleParameters, HMD, getEnabledModuleByName, TRIGGER_ON_VALUE, isInEditMode, Picks, + makeLaserParams */ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); @@ -24,9 +23,9 @@ Script.include("/~/system/libraries/utils.js"); this.triggerClicked = false; this.selectedTarget = null; this.reticleMinX = MARGIN; - this.reticleMaxX; + this.reticleMaxX = null; this.reticleMinY = MARGIN; - this.reticleMaxY; + this.reticleMaxY = null; this.parameters = makeDispatcherModuleParameters( 160, @@ -49,8 +48,8 @@ Script.include("/~/system/libraries/utils.js"); }; this.pointingAtTablet = function(objectID) { - return (HMD.tabletScreenID && objectID === HMD.tabletScreenID) - || (HMD.homeButtonID && objectID === HMD.homeButtonID); + return (HMD.tabletScreenID && objectID === HMD.tabletScreenID) || + (HMD.homeButtonID && objectID === HMD.homeButtonID); }; this.calculateNewReticlePosition = function(intersection) { diff --git a/scripts/system/controllers/controllerModules/inVREditMode.js b/scripts/system/controllers/controllerModules/inVREditMode.js index 7b78d5e1c4..ef02e41ef3 100644 --- a/scripts/system/controllers/controllerModules/inVREditMode.js +++ b/scripts/system/controllers/controllerModules/inVREditMode.js @@ -8,7 +8,7 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -/* global Script, MyAvatar, RIGHT_HAND, LEFT_HAND, enableDispatcherModule, disableDispatcherModule, +/* global Script, HMD, Messages, MyAvatar, RIGHT_HAND, LEFT_HAND, enableDispatcherModule, disableDispatcherModule, makeDispatcherModuleParameters, makeRunningValues, getEnabledModuleByName, makeLaserParams */ @@ -22,17 +22,17 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); var NO_HAND_LASER = -1; // Invalid hand parameter so that default laser is not displayed. this.parameters = makeDispatcherModuleParameters( 200, // Not too high otherwise the tablet laser doesn't work. - this.hand === RIGHT_HAND - ? ["rightHand", "rightHandEquip", "rightHandTrigger"] - : ["leftHand", "leftHandEquip", "leftHandTrigger"], + this.hand === RIGHT_HAND ? + ["rightHand", "rightHandEquip", "rightHandTrigger"] : + ["leftHand", "leftHandEquip", "leftHandTrigger"], [], 100, makeLaserParams(NO_HAND_LASER, false) ); this.pointingAtTablet = function (objectID) { - return (HMD.tabletScreenID && objectID === HMD.tabletScreenID) - || (HMD.homeButtonID && objectID === HMD.homeButtonID); + return (HMD.tabletScreenID && objectID === HMD.tabletScreenID) || + (HMD.homeButtonID && objectID === HMD.homeButtonID); }; this.isReady = function (controllerData) { @@ -49,9 +49,9 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); } // Tablet stylus. - var tabletStylusInput = getEnabledModuleByName(this.hand === RIGHT_HAND - ? "RightTabletStylusInput" - : "LeftTabletStylusInput"); + var tabletStylusInput = getEnabledModuleByName(this.hand === RIGHT_HAND ? + "RightTabletStylusInput" : + "LeftTabletStylusInput"); if (tabletStylusInput) { var tabletReady = tabletStylusInput.isReady(controllerData); if (tabletReady.active) { @@ -60,9 +60,9 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); } // Tablet surface. - var overlayLaser = getEnabledModuleByName(this.hand === RIGHT_HAND - ? "RightWebSurfaceLaserInput" - : "LeftWebSurfaceLaserInput"); + var overlayLaser = getEnabledModuleByName(this.hand === RIGHT_HAND ? + "RightWebSurfaceLaserInput" : + "LeftWebSurfaceLaserInput"); if (overlayLaser) { var overlayLaserReady = overlayLaser.isReady(controllerData); var target = controllerData.rayPicks[this.hand].objectID; @@ -72,9 +72,9 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); } // Tablet grabbing. - var nearOverlay = getEnabledModuleByName(this.hand === RIGHT_HAND - ? "RightNearParentingGrabOverlay" - : "LeftNearParentingGrabOverlay"); + var nearOverlay = getEnabledModuleByName(this.hand === RIGHT_HAND ? + "RightNearParentingGrabOverlay" : + "LeftNearParentingGrabOverlay"); if (nearOverlay) { var nearOverlayReady = nearOverlay.isReady(controllerData); if (nearOverlayReady.active && HMD.tabletID && nearOverlay.grabbedThingID === HMD.tabletID) { @@ -83,9 +83,9 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); } // Teleport. - var teleporter = getEnabledModuleByName(this.hand === RIGHT_HAND - ? "RightTeleporter" - : "LeftTeleporter"); + var teleporter = getEnabledModuleByName(this.hand === RIGHT_HAND ? + "RightTeleporter" : + "LeftTeleporter"); if (teleporter) { var teleporterReady = teleporter.isReady(controllerData); if (teleporterReady.active) { diff --git a/scripts/system/controllers/controllerModules/mouseHMD.js b/scripts/system/controllers/controllerModules/mouseHMD.js index 101a3502e1..27fe82ca19 100644 --- a/scripts/system/controllers/controllerModules/mouseHMD.js +++ b/scripts/system/controllers/controllerModules/mouseHMD.js @@ -10,6 +10,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +/* global Script, HMD, Reticle, Vec3, Controller */ + (function() { var ControllerDispatcherUtils = Script.require("/~/system/libraries/controllerDispatcherUtils.js"); @@ -121,7 +123,7 @@ if (this.mouseActivity.expired(now) || this.triggersPressed(controllerData, now) || !hmdActive) { if (!hmdActive) { Reticle.visible = true; - } else { + } else { Reticle.visible = false; } diff --git a/scripts/system/controllers/controllerModules/mouseHighlightEntities.js b/scripts/system/controllers/controllerModules/mouseHighlightEntities.js index ac57c8691f..59a68d98a4 100644 --- a/scripts/system/controllers/controllerModules/mouseHighlightEntities.js +++ b/scripts/system/controllers/controllerModules/mouseHighlightEntities.js @@ -12,7 +12,7 @@ /* jslint bitwise: true */ -/* global Script, print, Entities, Picks, HMD, Controller, MyAvatar, isInEditMode*/ +/* global Script, print, Entities, Messages, Picks, HMD, MyAvatar, isInEditMode, DISPATCHER_PROPERTIES */ (function() { @@ -46,11 +46,7 @@ var targetEntityID = pickResult.objectID; if (this.highlightedEntity !== targetEntityID) { - var targetProps = Entities.getEntityProperties(targetEntityID, [ - "dynamic", "shapeType", "position", - "rotation", "dimensions", "density", - "userData", "locked", "type", "href" - ]); + var targetProps = Entities.getEntityProperties(targetEntityID, DISPATCHER_PROPERTIES); if (this.highlightedEntity) { dispatcherUtils.unhighlightTargetEntity(this.highlightedEntity); diff --git a/scripts/system/controllers/controllerModules/nearActionGrabEntity.js b/scripts/system/controllers/controllerModules/nearActionGrabEntity.js index a8de76aebd..5ced6080a2 100644 --- a/scripts/system/controllers/controllerModules/nearActionGrabEntity.js +++ b/scripts/system/controllers/controllerModules/nearActionGrabEntity.js @@ -10,7 +10,8 @@ propsArePhysical, Messages, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, entityIsGrabbable, Quat, Vec3, MSECS_PER_SEC, getControllerWorldLocation, makeDispatcherModuleParameters, makeRunningValues, TRIGGER_OFF_VALUE, NEAR_GRAB_RADIUS, findGroupParent, entityIsCloneable, propsAreCloneDynamic, cloneEntity, - HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, BUMPER_ON_VALUE, unhighlightTargetEntity, Uuid + HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, BUMPER_ON_VALUE, unhighlightTargetEntity, Uuid, + DISPATCHER_PROPERTIES */ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); @@ -62,12 +63,12 @@ Script.include("/~/system/libraries/cloneEntityUtils.js"); Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand); var grabbableData = getGrabbableData(targetProps); - this.ignoreIK = grabbableData.ignoreIK; - this.kinematicGrab = grabbableData.kinematic; + this.grabFollowsController = grabbableData.grabFollowsController; + this.kinematicGrab = grabbableData.grabKinematic; var handRotation; var handPosition; - if (this.ignoreIK) { + if (this.grabFollowsController) { var controllerID = (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand; var controllerLocation = getControllerWorldLocation(controllerID, false); @@ -99,7 +100,7 @@ Script.include("/~/system/libraries/cloneEntityUtils.js"); ttl: ACTION_TTL, kinematic: this.kinematicGrab, kinematicSetVelocity: true, - ignoreIK: this.ignoreIK + ignoreIK: this.grabFollowsController }); if (this.actionID === Uuid.NULL) { this.actionID = null; @@ -136,7 +137,7 @@ Script.include("/~/system/libraries/cloneEntityUtils.js"); ttl: ACTION_TTL, kinematic: this.kinematicGrab, kinematicSetVelocity: true, - ignoreIK: this.ignoreIK + ignoreIK: this.grabFollowsController }); if (success) { this.actionTimeout = now + (ACTION_TTL * MSECS_PER_SEC); @@ -238,7 +239,7 @@ Script.include("/~/system/libraries/cloneEntityUtils.js"); var targetCloneable = entityIsCloneable(targetProps); if (targetCloneable) { var cloneID = cloneEntity(targetProps); - var cloneProps = Entities.getEntityProperties(cloneID); + var cloneProps = Entities.getEntityProperties(cloneID, DISPATCHER_PROPERTIES); this.targetEntityID = cloneID; this.startNearGrabAction(controllerData, cloneProps); } else { diff --git a/scripts/system/controllers/controllerModules/nearParentGrabEntity.js b/scripts/system/controllers/controllerModules/nearParentGrabEntity.js index cc88371441..bbdcbaaa64 100644 --- a/scripts/system/controllers/controllerModules/nearParentGrabEntity.js +++ b/scripts/system/controllers/controllerModules/nearParentGrabEntity.js @@ -12,7 +12,7 @@ findGroupParent, Vec3, cloneEntity, entityIsCloneable, propsAreCloneDynamic, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, BUMPER_ON_VALUE, findHandChildEntities, TEAR_AWAY_DISTANCE, MSECS_PER_SEC, TEAR_AWAY_CHECK_TIME, TEAR_AWAY_COUNT, distanceBetweenPointAndEntityBoundingBox, print, Uuid, highlightTargetEntity, unhighlightTargetEntity, - distanceBetweenEntityLocalPositionAndBoundingBox, GRAB_POINT_SPHERE_OFFSET + distanceBetweenEntityLocalPositionAndBoundingBox, getGrabbableData, getGrabPointSphereOffset, DISPATCHER_PROPERTIES */ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); @@ -28,16 +28,8 @@ Script.include("/~/system/libraries/controllers.js"); var GRAB_POINT_SPHERE_OFFSET = { x: 0.04, y: 0.13, z: 0.039 }; // x = upward, y = forward, z = lateral function getGrabOffset(handController) { - var offset = GRAB_POINT_SPHERE_OFFSET; - if (handController === Controller.Standard.LeftHand) { - offset = { - x: -GRAB_POINT_SPHERE_OFFSET.x, - y: GRAB_POINT_SPHERE_OFFSET.y, - z: GRAB_POINT_SPHERE_OFFSET.z - }; - } - - offset.y = -GRAB_POINT_SPHERE_OFFSET.y; + var offset = getGrabPointSphereOffset(handController, true); + offset.y = -offset.y; return Vec3.multiply(MyAvatar.sensorToWorldScale, offset); } @@ -101,6 +93,7 @@ Script.include("/~/system/libraries/controllers.js"); }; this.startNearParentingGrabEntity = function (controllerData, targetProps) { + var grabData = getGrabbableData(targetProps); Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand); unhighlightTargetEntity(this.targetEntityID); this.highlightedEntity = null; @@ -111,12 +104,11 @@ Script.include("/~/system/libraries/controllers.js"); Messages.sendLocalMessage('Hifi-unhighlight-entity', JSON.stringify(message)); var handJointIndex; - // if (this.ignoreIK) { - // handJointIndex = this.controllerJointIndex; - // } else { - // handJointIndex = MyAvatar.getJointIndex(this.hand === RIGHT_HAND ? "RightHand" : "LeftHand"); - // } - handJointIndex = getControllerJointIndex(this.hand); + if (grabData.grabFollowsController) { + handJointIndex = getControllerJointIndex(this.hand); + } else { + handJointIndex = MyAvatar.getJointIndex(this.hand === RIGHT_HAND ? "RightHand" : "LeftHand"); + } var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; Entities.callEntityMethod(targetProps.id, "startNearGrab", args); @@ -368,7 +360,7 @@ Script.include("/~/system/libraries/controllers.js"); if (this.cloneAllowed) { var cloneID = cloneEntity(targetProps); if (cloneID !== null) { - var cloneProps = Entities.getEntityProperties(cloneID); + var cloneProps = Entities.getEntityProperties(cloneID, DISPATCHER_PROPERTIES); this.grabbing = true; this.targetEntityID = cloneID; this.startNearParentingGrabEntity(controllerData, cloneProps); diff --git a/scripts/system/controllers/controllerModules/nearTrigger.js b/scripts/system/controllers/controllerModules/nearTrigger.js index 6a9cd9fbcd..f4e39cfbb9 100644 --- a/scripts/system/controllers/controllerModules/nearTrigger.js +++ b/scripts/system/controllers/controllerModules/nearTrigger.js @@ -16,7 +16,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); function entityWantsNearTrigger(props) { var grabbableData = getGrabbableData(props); - return grabbableData.triggerable || grabbableData.wantsTrigger; + return grabbableData.triggerable; } function NearTriggerEntity(hand) { diff --git a/scripts/system/controllers/controllerModules/scaleEntity.js b/scripts/system/controllers/controllerModules/scaleEntity.js index 9d54eef98e..24c05a1394 100644 --- a/scripts/system/controllers/controllerModules/scaleEntity.js +++ b/scripts/system/controllers/controllerModules/scaleEntity.js @@ -7,7 +7,7 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -/* global Script, Vec3, MyAvatar, RIGHT_HAND */ +/* global Script, Vec3, MyAvatar, Entities, RIGHT_HAND */ (function() { var dispatcherUtils = Script.require("/~/system/libraries/controllerDispatcherUtils.js"); diff --git a/scripts/system/controllers/controllerModules/stylusInput.js b/scripts/system/controllers/controllerModules/stylusInput.js index 0ca6cd1b04..1d36fb687f 100644 --- a/scripts/system/controllers/controllerModules/stylusInput.js +++ b/scripts/system/controllers/controllerModules/stylusInput.js @@ -5,11 +5,9 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -/* global Script, Entities, MyAvatar, Controller, RIGHT_HAND, LEFT_HAND, - enableDispatcherModule, disableDispatcherModule, makeRunningValues, - Messages, Quat, Vec3, getControllerWorldLocation, makeDispatcherModuleParameters, Overlays, ZERO_VEC, - HMD, INCHES_TO_METERS, DEFAULT_REGISTRATION_POINT, Settings, getGrabPointSphereOffset, - getEnabledModuleByName, Pointers, Picks, PickType +/* global Script, MyAvatar, Controller, Uuid, RIGHT_HAND, LEFT_HAND, enableDispatcherModule, disableDispatcherModule, + makeRunningValues, Vec3, makeDispatcherModuleParameters, Overlays, HMD, Settings, getEnabledModuleByName, Pointers, + Picks, PickType */ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); @@ -200,7 +198,7 @@ Script.include("/~/system/libraries/controllers.js"); Overlays.hoverEnterOverlay.connect(mouseHoverEnter); Overlays.hoverLeaveOverlay.connect(mouseHoverLeave); - Overlays.mousePressOnOverlay.connect(mousePress); + Overlays.mousePressOnOverlay.connect(mousePress); this.cleanup = function () { leftTabletStylusInput.cleanup(); diff --git a/scripts/system/controllers/controllerModules/teleport.js b/scripts/system/controllers/controllerModules/teleport.js index bf5022cdaf..20a1e47bf2 100644 --- a/scripts/system/controllers/controllerModules/teleport.js +++ b/scripts/system/controllers/controllerModules/teleport.js @@ -10,7 +10,7 @@ /* jslint bitwise: true */ -/* global Script, Entities, MyAvatar, Controller, RIGHT_HAND, LEFT_HAND, +/* global Script, Entities, MyAvatar, Controller, Quat, RIGHT_HAND, LEFT_HAND, enableDispatcherModule, disableDispatcherModule, Messages, makeDispatcherModuleParameters, makeRunningValues, Vec3, HMD, Uuid, AvatarList, Picks, Pointers, PickType */ @@ -680,8 +680,8 @@ Script.include("/~/system/libraries/controllers.js"); this.teleportLocked = function () { // Lock teleport if in advanced movement mode and have just transitioned from pressing a direction button. - return Controller.getValue(Controller.Hardware.Application.AdvancedMovement) - && (_this.axisButtonStateX !== 0 || _this.axisButtonStateY !== 0); + return Controller.getValue(Controller.Hardware.Application.AdvancedMovement) && + (_this.axisButtonStateX !== 0 || _this.axisButtonStateY !== 0); }; this.buttonPress = function (value) { diff --git a/scripts/system/controllers/controllerModules/webSurfaceLaserInput.js b/scripts/system/controllers/controllerModules/webSurfaceLaserInput.js index 2412e2fa1c..3d66e84d1f 100644 --- a/scripts/system/controllers/controllerModules/webSurfaceLaserInput.js +++ b/scripts/system/controllers/controllerModules/webSurfaceLaserInput.js @@ -5,11 +5,9 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -/* global Script, Entities, Controller, RIGHT_HAND, LEFT_HAND, enableDispatcherModule, disableDispatcherModule, - makeRunningValues, Messages, Quat, Vec3, makeDispatcherModuleParameters, Overlays, ZERO_VEC, HMD, - INCHES_TO_METERS, DEFAULT_REGISTRATION_POINT, getGrabPointSphereOffset, COLORS_GRAB_SEARCHING_HALF_SQUEEZE, - COLORS_GRAB_SEARCHING_FULL_SQUEEZE, COLORS_GRAB_DISTANCE_HOLD, DEFAULT_SEARCH_SPHERE_DISTANCE, TRIGGER_ON_VALUE, - TRIGGER_OFF_VALUE, getEnabledModuleByName, PICK_MAX_DISTANCE, ContextOverlay, Picks, makeLaserParams +/* global Script, Entities, enableDispatcherModule, disableDispatcherModule, makeRunningValues, + makeDispatcherModuleParameters, Overlays, HMD, TRIGGER_ON_VALUE, TRIGGER_OFF_VALUE, getEnabledModuleByName, + ContextOverlay, Picks, makeLaserParams, Settings, MyAvatar, RIGHT_HAND, LEFT_HAND, DISPATCHER_PROPERTIES */ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); @@ -82,7 +80,7 @@ Script.include("/~/system/libraries/controllers.js"); return overlayType === "web3d" || triggerPressed; } } else if (intersection.type === Picks.INTERSECTED_ENTITY) { - var entityProperties = Entities.getEntityProperties(objectID); + var entityProperties = Entities.getEntityProperties(objectID, DISPATCHER_PROPERTIES); var entityType = entityProperties.type; var isLocked = entityProperties.locked; return entityType === "Web" && (!isLocked || triggerPressed); @@ -91,8 +89,9 @@ Script.include("/~/system/libraries/controllers.js"); }; this.deleteContextOverlay = function() { - var farGrabModule = getEnabledModuleByName(this.hand === RIGHT_HAND - ? "RightFarActionGrabEntity" : "LeftFarActionGrabEntity"); + var farGrabModule = getEnabledModuleByName(this.hand === RIGHT_HAND ? + "RightFarActionGrabEntity" : + "LeftFarActionGrabEntity"); if (farGrabModule) { var entityWithContextOverlay = farGrabModule.entityWithContextOverlay; diff --git a/scripts/system/controllers/controllerScripts.js b/scripts/system/controllers/controllerScripts.js index 6899577de2..73938af0d3 100644 --- a/scripts/system/controllers/controllerScripts.js +++ b/scripts/system/controllers/controllerScripts.js @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +/* global Script, Menu */ + var CONTOLLER_SCRIPTS = [ "squeezeHands.js", "controllerDisplayManager.js", @@ -19,8 +21,8 @@ var CONTOLLER_SCRIPTS = [ "controllerModules/nearParentGrabEntity.js", "controllerModules/nearParentGrabOverlay.js", "controllerModules/nearActionGrabEntity.js", - // "controllerModules/farActionGrabEntity.js", - // "controllerModules/farParentGrabEntity.js", + "controllerModules/farActionGrabEntityDynOnly.js", + "controllerModules/farParentGrabEntity.js", "controllerModules/stylusInput.js", "controllerModules/equipEntity.js", "controllerModules/nearTrigger.js", @@ -38,25 +40,22 @@ var CONTOLLER_SCRIPTS = [ "controllerModules/mouseHighlightEntities.js" ]; -if (Settings.getValue("useFarGrabJoints", false)) { - CONTOLLER_SCRIPTS.push("controllerModules/farActionGrabEntityDynOnly.js"); - CONTOLLER_SCRIPTS.push("controllerModules/farParentGrabEntity.js"); -} else { - CONTOLLER_SCRIPTS.push("controllerModules/farActionGrabEntity.js"); -} - var DEBUG_MENU_ITEM = "Debug defaultScripts.js"; function runDefaultsTogether() { for (var j in CONTOLLER_SCRIPTS) { - Script.include(CONTOLLER_SCRIPTS[j]); + if (CONTOLLER_SCRIPTS.hasOwnProperty(j)) { + Script.include(CONTOLLER_SCRIPTS[j]); + } } } function runDefaultsSeparately() { for (var i in CONTOLLER_SCRIPTS) { - Script.load(CONTOLLER_SCRIPTS[i]); + if (CONTOLLER_SCRIPTS.hasOwnProperty(i)) { + Script.load(CONTOLLER_SCRIPTS[i]); + } } } diff --git a/scripts/system/controllers/grab.js b/scripts/system/controllers/grab.js index 48229ac9d9..a78a2971e9 100644 --- a/scripts/system/controllers/grab.js +++ b/scripts/system/controllers/grab.js @@ -14,9 +14,11 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -/* global MyAvatar, Entities, Script, Camera, Vec3, Reticle, Overlays, getEntityCustomData, Messages, Quat, Controller, - isInEditMode, HMD entityIsGrabbable, Picks, PickType, Pointers, unhighlightTargetEntity*/ - +/* global MyAvatar, Entities, Script, HMD, Camera, Vec3, Reticle, Overlays, getEntityCustomData, Messages, Quat, Controller, + isInEditMode, entityIsGrabbable, Picks, PickType, Pointers, unhighlightTargetEntity, DISPATCHER_PROPERTIES, + entityIsGrabbable, entityIsEquipped, getMainTabletIDs +*/ +/* jslint bitwise: true */ (function() { // BEGIN LOCAL_SCOPE @@ -37,7 +39,6 @@ var IDENTITY_QUAT = { z: 0, w: 0 }; -var GRABBABLE_DATA_KEY = "grabbableKey"; // shared with handControllerGrab.js var DEFAULT_GRABBABLE_DATA = { grabbable: true, @@ -339,16 +340,14 @@ Grabber.prototype.pressEvent = function(event) { return; } - var props = Entities.getEntityProperties(pickResults.objectID, ["dynamic", "userData", "locked", "type"]); + var props = Entities.getEntityProperties(pickResults.objectID, DISPATCHER_PROPERTIES); var isDynamic = props.dynamic; - var isGrabbable = props.grabbable; if (!entityIsGrabbable(props)) { // only grab grabbable objects return; } - var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, pickResults.objectID, DEFAULT_GRABBABLE_DATA); - if (grabbableData.grabbable === false) { + if (!props.grab.grabbable) { return; } @@ -359,7 +358,7 @@ Grabber.prototype.pressEvent = function(event) { mouse.startDrag(event); var clickedEntity = pickResults.objectID; - var entityProperties = Entities.getEntityProperties(clickedEntity); + var entityProperties = Entities.getEntityProperties(clickedEntity, DISPATCHER_PROPERTIES); this.startPosition = entityProperties.position; this.lastRotation = entityProperties.rotation; this.madeDynamic = false; @@ -484,7 +483,7 @@ Grabber.prototype.moveEvent = function(event) { Grabber.prototype.moveEventProcess = function() { this.moveEventTimer = null; // see if something added/restored gravity - var entityProperties = Entities.getEntityProperties(this.entityID); + var entityProperties = Entities.getEntityProperties(this.entityID, DISPATCHER_PROPERTIES); if (!entityProperties || !entityProperties.gravity || HMD.active) { return; } diff --git a/scripts/system/controllers/handTouch.js b/scripts/system/controllers/handTouch.js index 97a24cb3f2..c706d054c1 100644 --- a/scripts/system/controllers/handTouch.js +++ b/scripts/system/controllers/handTouch.js @@ -11,7 +11,7 @@ /* jslint bitwise: true */ -/* global Script, Overlays, Controller, Vec3, MyAvatar, Entities +/* global Script, Overlays, Controller, Vec3, MyAvatar, Entities, RayPick */ (function () { @@ -22,8 +22,8 @@ var MSECONDS_AFTER_LOAD = 2000; var updateFingerWithIndex = 0; var untouchableEntities = []; - - // Keys to access finger data + + // Keys to access finger data var fingerKeys = ["pinky", "ring", "middle", "index", "thumb"]; // Additionally close the hands to achieve a grabbing effect @@ -47,7 +47,7 @@ left: new Palm(), right: new Palm() }; - + var handJointNames = {left: "LeftHand", right: "RightHand"}; // Store which fingers are touching - if all false restate the default poses diff --git a/scripts/system/controllers/squeezeHands.js b/scripts/system/controllers/squeezeHands.js index c9de473e28..69f44f46a9 100644 --- a/scripts/system/controllers/squeezeHands.js +++ b/scripts/system/controllers/squeezeHands.js @@ -11,6 +11,7 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +/* global Script, MyAvatar, Messages, Controller */ /* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ (function() { // BEGIN LOCAL_SCOPE @@ -20,7 +21,7 @@ var lastRightTrigger = 0; var leftHandOverlayAlpha = 0; var rightHandOverlayAlpha = 0; -var CONTROLLER_DEAD_SPOT = 0.25; +// var CONTROLLER_DEAD_SPOT = 0.25; var TRIGGER_SMOOTH_TIMESCALE = 0.1; var OVERLAY_RAMP_RATE = 8.0; @@ -42,9 +43,9 @@ function clamp(val, min, max) { return Math.min(Math.max(val, min), max); } -function normalizeControllerValue(val) { - return clamp((val - CONTROLLER_DEAD_SPOT) / (1 - CONTROLLER_DEAD_SPOT), 0, 1); -} +// function normalizeControllerValue(val) { +// return clamp((val - CONTROLLER_DEAD_SPOT) / (1 - CONTROLLER_DEAD_SPOT), 0, 1); +// } function lerp(a, b, alpha) { return a * (1 - alpha) + b * alpha; diff --git a/scripts/system/controllers/touchControllerConfiguration.js b/scripts/system/controllers/touchControllerConfiguration.js index f22252f646..991b77b8af 100644 --- a/scripts/system/controllers/touchControllerConfiguration.js +++ b/scripts/system/controllers/touchControllerConfiguration.js @@ -8,7 +8,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -/* globals TOUCH_CONTROLLER_CONFIGURATION_LEFT:true TOUCH_CONTROLLER_CONFIGURATION_RIGHT:true */ +/* globals TOUCH_CONTROLLER_CONFIGURATION_LEFT:true, TOUCH_CONTROLLER_CONFIGURATION_RIGHT:true, + Quat, Vec3, Script, MyAvatar, Controller */ /* eslint camelcase: ["error", { "properties": "never" }] */ var leftBaseRotation = Quat.multiply( @@ -22,9 +23,9 @@ var rightBaseRotation = Quat.multiply( // keep these in sync with the values from OculusHelpers.cpp var CONTROLLER_LENGTH_OFFSET = 0.0762; -var CONTROLLER_LATERAL_OFFSET = 0.0381; -var CONTROLLER_VERTICAL_OFFSET = 0.0381; -var CONTROLLER_FORWARD_OFFSET = 0.1524; +// var CONTROLLER_LATERAL_OFFSET = 0.0381; +// var CONTROLLER_VERTICAL_OFFSET = 0.0381; +// var CONTROLLER_FORWARD_OFFSET = 0.1524; var leftBasePosition = Vec3.multiplyQbyV(leftBaseRotation, { x: -CONTROLLER_LENGTH_OFFSET / 2.0, diff --git a/scripts/system/controllers/viveControllerConfiguration.js b/scripts/system/controllers/viveControllerConfiguration.js index 60f0b6b88a..09fd8adacc 100644 --- a/scripts/system/controllers/viveControllerConfiguration.js +++ b/scripts/system/controllers/viveControllerConfiguration.js @@ -8,11 +8,12 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -/* globals VIVE_CONTROLLER_CONFIGURATION_LEFT:true VIVE_CONTROLLER_CONFIGURATION_RIGHT:true */ +/* globals VIVE_CONTROLLER_CONFIGURATION_LEFT:true, VIVE_CONTROLLER_CONFIGURATION_RIGHT:true, + MyAvatar, Quat, Script, Vec3, Controller */ /* eslint camelcase: ["error", { "properties": "never" }] */ -var LEFT_JOINT_INDEX = MyAvatar.getJointIndex("_CONTROLLER_LEFTHAND"); -var RIGHT_JOINT_INDEX = MyAvatar.getJointIndex("_CONTROLLER_RIGHTHAND"); +// var LEFT_JOINT_INDEX = MyAvatar.getJointIndex("_CONTROLLER_LEFTHAND"); +// var RIGHT_JOINT_INDEX = MyAvatar.getJointIndex("_CONTROLLER_RIGHTHAND"); var leftBaseRotation = Quat.multiply( Quat.fromPitchYawRollDegrees(0, 0, 45), @@ -58,10 +59,10 @@ var viveNaturalPosition = { }; var BASE_URL = Script.resourcesPath(); -var TIP_TEXTURE_BASE_URL = BASE_URL + "meshes/controller/vive_tips.fbm/"; +// var TIP_TEXTURE_BASE_URL = BASE_URL + "meshes/controller/vive_tips.fbm/"; var viveModelURL = BASE_URL + "meshes/controller/vive_body.fbx"; -var viveTipsModelURL = BASE_URL + "meshes/controller/vive_tips.fbx"; +// var viveTipsModelURL = BASE_URL + "meshes/controller/vive_tips.fbx"; var viveTriggerModelURL = "meshes/controller/vive_trigger.fbx"; VIVE_CONTROLLER_CONFIGURATION_LEFT = { @@ -340,4 +341,3 @@ VIVE_CONTROLLER_CONFIGURATION_RIGHT = { } ] }; - diff --git a/scripts/system/edit.js b/scripts/system/edit.js index 27858722ec..b4684a0fd4 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -345,11 +345,15 @@ var toolBar = (function () { position = grid.snapToSurface(grid.snapToGrid(position, false, dimensions), dimensions); properties.position = position; + + if (!properties.grab) { + properties.grab = {}; + } if (Menu.isOptionChecked(MENU_CREATE_ENTITIES_GRABBABLE) && !(properties.type === "Zone" || properties.type === "Light" || properties.type === "ParticleEffect")) { - properties.userData = JSON.stringify({ grabbableKey: { grabbable: true } }); + properties.grab.grabbable = true; } else { - properties.userData = JSON.stringify({ grabbableKey: { grabbable: false } }); + properties.grab.grabbable = false; } SelectionManager.saveProperties(); diff --git a/scripts/system/html/entityProperties.html b/scripts/system/html/entityProperties.html index 744150253d..8b27efa1fe 100644 --- a/scripts/system/html/entityProperties.html +++ b/scripts/system/html/entityProperties.html @@ -134,8 +134,8 @@
- - + +
diff --git a/scripts/system/html/js/entityProperties.js b/scripts/system/html/js/entityProperties.js index de9027586e..2d2e4d5675 100644 --- a/scripts/system/html/js/entityProperties.js +++ b/scripts/system/html/js/entityProperties.js @@ -6,8 +6,8 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -/* global alert, augmentSpinButtons, clearTimeout, console, document, Element, EventBridge, - HifiEntityUI, JSONEditor, openEventBridge, setTimeout, window, _ $ */ +/* global alert, augmentSpinButtons, clearTimeout, document, Element, EventBridge, + JSONEditor, openEventBridge, setTimeout, window, $ */ var PI = 3.14159265358979; var DEGREES_TO_RADIANS = PI / 180.0; @@ -364,12 +364,6 @@ function multiDataUpdater(groupName, updateKeyPair, userDataElement, defaults, r updateProperties(properties); } -function userDataChanger(groupName, keyName, values, userDataElement, defaultValue, removeKeys) { - var val = {}, def = {}; - val[keyName] = values; - def[keyName] = defaultValue; - multiDataUpdater(groupName, val, userDataElement, def, removeKeys); -} function setMaterialDataFromEditor(noUpdate) { var json = null; @@ -712,6 +706,8 @@ function loaded() { var elCollisionSoundURL = document.getElementById("property-collision-sound-url"); var elGrabbable = document.getElementById("property-grabbable"); + var elTriggerable = document.getElementById("property-triggerable"); + var elGrabFollowsController = document.getElementById("property-grab-follows-controller"); var elCloneable = document.getElementById("property-cloneable"); var elCloneableDynamic = document.getElementById("property-cloneable-dynamic"); @@ -720,9 +716,6 @@ function loaded() { var elCloneableLifetime = document.getElementById("property-cloneable-lifetime"); var elCloneableLimit = document.getElementById("property-cloneable-limit"); - var elTriggerable = document.getElementById("property-triggerable"); - var elIgnoreIK = document.getElementById("property-ignore-ik"); - var elLifetime = document.getElementById("property-lifetime"); var elScriptURL = document.getElementById("property-script-url"); var elScriptTimestamp = document.getElementById("property-script-timestamp"); @@ -992,7 +985,7 @@ function loaded() { elGrabbable.checked = false; elTriggerable.checked = false; - elIgnoreIK.checked = false; + elGrabFollowsController.checked = false; elCloneable.checked = false; elCloneableDynamic.checked = false; @@ -1037,7 +1030,7 @@ function loaded() { elCompoundShapeURL.value = ""; elShapeType.value = "none"; setDropdownText(elShapeType); - elModelAnimationURL.value = "" + elModelAnimationURL.value = ""; elModelAnimationPlaying.checked = false; elModelAnimationFPS.value = ""; elModelAnimationFrame.value = ""; @@ -1254,10 +1247,9 @@ function loaded() { elCollideMyAvatar.checked = properties.collidesWith.indexOf("myAvatar") > -1; elCollideOtherAvatar.checked = properties.collidesWith.indexOf("otherAvatar") > -1; - elGrabbable.checked = properties.dynamic; - - elTriggerable.checked = false; - elIgnoreIK.checked = true; + elGrabbable.checked = properties.grab.grabbable; + elTriggerable.checked = properties.grab.triggerable; + elGrabFollowsController.checked = properties.grab.grabFollowsController; elCloneable.checked = properties.cloneable; elCloneableDynamic.checked = properties.cloneDynamic; @@ -1266,42 +1258,6 @@ function loaded() { elCloneableLimit.value = properties.cloneLimit; elCloneableLifetime.value = properties.cloneLifetime; - var grabbablesSet = false; - var parsedUserData = {}; - try { - parsedUserData = JSON.parse(properties.userData); - - if ("grabbableKey" in parsedUserData) { - grabbablesSet = true; - var grabbableData = parsedUserData.grabbableKey; - if ("grabbable" in grabbableData) { - elGrabbable.checked = grabbableData.grabbable; - } else { - elGrabbable.checked = true; - } - if ("triggerable" in grabbableData) { - elTriggerable.checked = grabbableData.triggerable; - } else if ("wantsTrigger" in grabbableData) { - elTriggerable.checked = grabbableData.wantsTrigger; - } else { - elTriggerable.checked = false; - } - if ("ignoreIK" in grabbableData) { - elIgnoreIK.checked = grabbableData.ignoreIK; - } else { - elIgnoreIK.checked = true; - } - } - } catch (e) { - // TODO: What should go here? - } - if (!grabbablesSet) { - elGrabbable.checked = true; - elTriggerable.checked = false; - elIgnoreIK.checked = true; - elCloneable.checked = false; - } - elCollisionSoundURL.value = properties.collisionSoundURL; elLifetime.value = properties.lifetime; elScriptURL.value = properties.script; @@ -1669,26 +1625,18 @@ function loaded() { updateCheckedSubProperty("collidesWith", properties.collidesWith, elCollideOtherAvatar, 'otherAvatar'); }); - elGrabbable.addEventListener('change', function() { - if (elCloneable.checked) { - elGrabbable.checked = false; - } - userDataChanger("grabbableKey", "grabbable", elGrabbable, elUserData, true); - }); - + + elGrabbable.addEventListener('change', createEmitGroupCheckedPropertyUpdateFunction('grab', 'grabbable')); + elTriggerable.addEventListener('change', createEmitGroupCheckedPropertyUpdateFunction('grab', 'triggerable')); + elGrabFollowsController.addEventListener('change', + createEmitGroupCheckedPropertyUpdateFunction('grab', 'grabFollowsController')); + elCloneable.addEventListener('change', createEmitCheckedPropertyUpdateFunction('cloneable')); elCloneableDynamic.addEventListener('change', createEmitCheckedPropertyUpdateFunction('cloneDynamic')); elCloneableAvatarEntity.addEventListener('change', createEmitCheckedPropertyUpdateFunction('cloneAvatarEntity')); elCloneableLifetime.addEventListener('change', createEmitNumberPropertyUpdateFunction('cloneLifetime')); elCloneableLimit.addEventListener('change', createEmitNumberPropertyUpdateFunction('cloneLimit')); - elTriggerable.addEventListener('change', function() { - userDataChanger("grabbableKey", "triggerable", elTriggerable, elUserData, false, ['wantsTrigger']); - }); - elIgnoreIK.addEventListener('change', function() { - userDataChanger("grabbableKey", "ignoreIK", elIgnoreIK, elUserData, true); - }); - elCollisionSoundURL.addEventListener('change', createEmitTextPropertyUpdateFunction('collisionSoundURL')); elLifetime.addEventListener('change', createEmitNumberPropertyUpdateFunction('lifetime')); diff --git a/scripts/system/libraries/WebTablet.js b/scripts/system/libraries/WebTablet.js index c201a251d0..8e5b41deda 100644 --- a/scripts/system/libraries/WebTablet.js +++ b/scripts/system/libraries/WebTablet.js @@ -129,9 +129,7 @@ WebTablet = function (url, width, dpi, hand, clientOnly, location, visible) { url: modelURL, // for overlay grabbable: true, // for overlay loadPriority: 10.0, // for overlay - userData: JSON.stringify({ - "grabbableKey": {"grabbable": true} - }), + grab: { grabbable: true }, dimensions: { x: tabletWidth, y: tabletHeight, z: tabletDepth }, parentID: MyAvatar.SELF_ID, visible: visible, diff --git a/scripts/system/libraries/controllerDispatcherUtils.js b/scripts/system/libraries/controllerDispatcherUtils.js index c34fd76802..e9d5255d28 100644 --- a/scripts/system/libraries/controllerDispatcherUtils.js +++ b/scripts/system/libraries/controllerDispatcherUtils.js @@ -48,6 +48,7 @@ BUMPER_ON_VALUE:true, getEntityParents:true, findHandChildEntities:true, + findFarGrabJointChildEntities:true, makeLaserParams:true, TEAR_AWAY_DISTANCE:true, TEAR_AWAY_COUNT:true, @@ -127,13 +128,25 @@ DISPATCHER_PROPERTIES = [ "parentJointIndex", "density", "dimensions", - "userData", "type", "href", "cloneable", "cloneDynamic", "localPosition", - "localRotation" + "localRotation", + "grab.grabbable", + "grab.grabKinematic", + "grab.grabFollowsController", + "grab.triggerable", + "grab.equippable", + "grab.equippableLeftPosition", + "grab.equippableLeftRotation", + "grab.equippableRightPosition", + "grab.equippableRightRotation", + "grab.equippableIndicatorURL", + "grab.equippableIndicatorScale", + "grab.equippableIndicatorOffset", + "userData" ]; // priority -- a lower priority means the module will be asked sooner than one with a higher priority in a given update step @@ -215,25 +228,56 @@ getGrabbableData = function (ggdProps) { } catch (err) { userDataParsed = {}; } + if (userDataParsed.grabbableKey) { grabbableData = userDataParsed.grabbableKey; + } else { + grabbableData = ggdProps.grab; } + + // extract grab-related properties, provide defaults if any are missing if (!grabbableData.hasOwnProperty("grabbable")) { grabbableData.grabbable = true; } - if (!grabbableData.hasOwnProperty("ignoreIK")) { - grabbableData.ignoreIK = true; + // kinematic has been renamed to grabKinematic + if (!grabbableData.hasOwnProperty("grabKinematic") && + !grabbableData.hasOwnProperty("kinematic")) { + grabbableData.grabKinematic = true; } - if (!grabbableData.hasOwnProperty("kinematic")) { - grabbableData.kinematic = true; + if (!grabbableData.hasOwnProperty("grabKinematic")) { + grabbableData.grabKinematic = grabbableData.kinematic; } - if (!grabbableData.hasOwnProperty("wantsTrigger")) { - grabbableData.wantsTrigger = false; + // ignoreIK has been renamed to grabFollowsController + if (!grabbableData.hasOwnProperty("grabFollowsController") && + !grabbableData.hasOwnProperty("ignoreIK")) { + grabbableData.grabFollowsController = true; } - if (!grabbableData.hasOwnProperty("triggerable")) { + if (!grabbableData.hasOwnProperty("grabFollowsController")) { + grabbableData.grabFollowsController = grabbableData.ignoreIK; + } + // wantsTrigger has been renamed to triggerable + if (!grabbableData.hasOwnProperty("triggerable") && + !grabbableData.hasOwnProperty("wantsTrigger")) { grabbableData.triggerable = false; } - + if (!grabbableData.hasOwnProperty("triggerable")) { + grabbableData.triggerable = grabbableData.wantsTrigger; + } + if (!grabbableData.hasOwnProperty("equippable")) { + grabbableData.equippable = false; + } + if (!grabbableData.hasOwnProperty("equippableLeftPosition")) { + grabbableData.equippableLeftPosition = { x: 0, y: 0, z: 0 }; + } + if (!grabbableData.hasOwnProperty("equippableLeftRotation")) { + grabbableData.equippableLeftPosition = { x: 0, y: 0, z: 0, w: 1 }; + } + if (!grabbableData.hasOwnProperty("equippableRightPosition")) { + grabbableData.equippableRightPosition = { x: 0, y: 0, z: 0 }; + } + if (!grabbableData.hasOwnProperty("equippableRightRotation")) { + grabbableData.equippableRightPosition = { x: 0, y: 0, z: 0, w: 1 }; + } return grabbableData; }; @@ -417,6 +461,18 @@ findHandChildEntities = function(hand) { }); }; +findFarGrabJointChildEntities = function(hand) { + // find children of avatar's far-grab joint + var farGrabJointIndex = MyAvatar.getJointIndex(hand === RIGHT_HAND ? "_FARGRAB_RIGHTHAND" : "_FARGRAB_LEFTHAND"); + var children = Entities.getChildrenIDsOfJoint(MyAvatar.sessionUUID, farGrabJointIndex); + children = children.concat(Entities.getChildrenIDsOfJoint(MyAvatar.SELF_ID, farGrabJointIndex)); + + return children.filter(function (childID) { + var childType = Entities.getNestableType(childID); + return childType == "entity"; + }); +}; + distanceBetweenEntityLocalPositionAndBoundingBox = function(entityProps, jointGrabOffset) { var DEFAULT_REGISTRATION_POINT = { x: 0.5, y: 0.5, z: 0.5 }; var rotInv = Quat.inverse(entityProps.localRotation); diff --git a/scripts/system/libraries/controllers.js b/scripts/system/libraries/controllers.js index cc20c196aa..be7d22e073 100644 --- a/scripts/system/libraries/controllers.js +++ b/scripts/system/libraries/controllers.js @@ -5,20 +5,25 @@ // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -/* global MyAvatar, Vec3, Controller, Quat */ +/* global MyAvatar, Vec3, HMD, Controller, Camera, Quat, Settings, + getGrabPointSphereOffset:true, + setGrabCommunications:true, + getGrabCommunications:true, + getControllerWorldLocation:true + */ var GRAB_COMMUNICATIONS_SETTING = "io.highfidelity.isFarGrabbing"; setGrabCommunications = function setFarGrabCommunications(on) { Settings.setValue(GRAB_COMMUNICATIONS_SETTING, on ? "on" : ""); -} +}; getGrabCommunications = function getFarGrabCommunications() { return !!Settings.getValue(GRAB_COMMUNICATIONS_SETTING, ""); -} +}; // this offset needs to match the one in libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp:378 -var GRAB_POINT_SPHERE_OFFSET = { x: 0.04, y: 0.13, z: 0.039 }; // x = upward, y = forward, z = lateral getGrabPointSphereOffset = function(handController, ignoreSensorToWorldScale) { + var GRAB_POINT_SPHERE_OFFSET = { x: 0.04, y: 0.13, z: 0.039 }; // x = upward, y = forward, z = lateral var offset = GRAB_POINT_SPHERE_OFFSET; if (handController === Controller.Standard.LeftHand) { offset = { @@ -39,7 +44,7 @@ getControllerWorldLocation = function (handController, doOffset) { var orientation; var position; var valid = false; - + if (handController >= 0) { var pose = Controller.getPoseValue(handController); valid = pose.valid; diff --git a/scripts/system/libraries/entitySelectionTool.js b/scripts/system/libraries/entitySelectionTool.js index a13c645b81..5f5225418f 100644 --- a/scripts/system/libraries/entitySelectionTool.js +++ b/scripts/system/libraries/entitySelectionTool.js @@ -215,7 +215,9 @@ SelectionManager = (function() { var grabJointNames = [ 'RightHand', 'LeftHand', '_CONTROLLER_RIGHTHAND', '_CONTROLLER_LEFTHAND', - '_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND', '_CAMERA_RELATIVE_CONTROLLER_LEFTHAND']; + '_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND', '_CAMERA_RELATIVE_CONTROLLER_LEFTHAND', + '_FARGRAB_RIGHTHAND', '_FARGRAB_LEFTHAND', '_FARGRAB_MOUSE' + ]; for (var i = 0; i < grabJointNames.length; ++i) { if (avatar.getJointIndex(grabJointNames[i]) === properties.parentJointIndex) { diff --git a/scripts/system/snapshot.js b/scripts/system/snapshot.js index 3d744b3bd2..09f3e5fbfe 100644 --- a/scripts/system/snapshot.js +++ b/scripts/system/snapshot.js @@ -312,9 +312,7 @@ function printToPolaroid(image_url) { "dynamic": true, "collisionsWillMove": true, - "userData": { - "grabbableKey": { "grabbable" : true } - } + "grab": { "grabbable": true } }; var polaroid = Entities.addEntity(properties); diff --git a/scripts/tutorials/createCow.js b/scripts/tutorials/createCow.js index 16498e0e8c..0f034ecefa 100644 --- a/scripts/tutorials/createCow.js +++ b/scripts/tutorials/createCow.js @@ -45,11 +45,7 @@ var cow = Entities.addEntity({ lifetime: 3600, shapeType: "box", script: SCRIPT_URL, - userData: JSON.stringify({ - grabbableKey: { - grabbable: true - } - }) + grab: { grabbable: true } }); -Script.stop(); \ No newline at end of file +Script.stop(); diff --git a/scripts/tutorials/createFlashlight.js b/scripts/tutorials/createFlashlight.js index f3e1e72182..329be56af7 100644 --- a/scripts/tutorials/createFlashlight.js +++ b/scripts/tutorials/createFlashlight.js @@ -37,11 +37,6 @@ var flashlight = Entities.addEntity({ shapeType: 'box', lifetime: 3600, script: SCRIPT_URL, - userData: JSON.stringify({ - grabbableKey: { - invertSolidWhileHeld: true - } - }) }); -Script.stop(); \ No newline at end of file +Script.stop(); diff --git a/scripts/tutorials/createGolfClub.js b/scripts/tutorials/createGolfClub.js index 21e60f26ef..4135b6680d 100644 --- a/scripts/tutorials/createGolfClub.js +++ b/scripts/tutorials/createGolfClub.js @@ -53,35 +53,34 @@ var golfClubProperties = { y: -5.0, z: 0 }, - userData: JSON.stringify({ - wearable: { - joints: { - LeftHand: [{ - x: -0.1631782054901123, - y: 0.44648152589797974, - z: 0.10100018978118896 - }, { - x: -0.9181621670722961, - y: -0.0772884339094162, - z: -0.3870723247528076, - w: -0.0343472845852375 - }], - RightHand: [{ - x: 0.16826771199703217, - y: 0.4757269620895386, - z: 0.07139724493026733 - }, { - x: -0.7976328134536743, - y: -0.0011603273451328278, - z: 0.6030101776123047, - w: -0.012610925361514091 - }] - } + grab: { + equippable: true, + equippableLeftPosition: { + x: -0.1631782054901123, + y: 0.44648152589797974, + z: 0.10100018978118896 + }, + equippableLeftRotation: { + x: -0.9181621670722961, + y: -0.0772884339094162, + z: -0.3870723247528076, + w: -0.0343472845852375 + }, + equippableRightPosition: { + x: 0.16826771199703217, + y: 0.4757269620895386, + z: 0.07139724493026733 + }, + equippableRightRotation: { + x: -0.7976328134536743, + y: -0.0011603273451328278, + z: 0.6030101776123047, + w: -0.012610925361514091 } - }) -} + } +}; var golfClub = Entities.addEntity(golfClubProperties); -Script.stop(); \ No newline at end of file +Script.stop(); diff --git a/scripts/tutorials/createPingPongGun.js b/scripts/tutorials/createPingPongGun.js index c86a78e96d..927738f29e 100644 --- a/scripts/tutorials/createPingPongGun.js +++ b/scripts/tutorials/createPingPongGun.js @@ -37,35 +37,31 @@ var pingPongGunProperties = { }, lifetime: 3600, dynamic: true, - userData: JSON.stringify({ - grabbableKey: { - invertSolidWhileHeld: true + grab: { + equippable: true, + equippableLeftPosition: { + x: 0.09151676297187805, + y: 0.13639454543590546, + z: 0.09354984760284424 }, - wearable: { - joints: { - RightHand: [{ - x: 0.1177130937576294, - y: 0.12922893464565277, - z: 0.08307232707738876 - }, { - x: 0.4934672713279724, - y: 0.3605862259864807, - z: 0.6394805908203125, - w: -0.4664038419723511 - }], - LeftHand: [{ - x: 0.09151676297187805, - y: 0.13639454543590546, - z: 0.09354984760284424 - }, { - x: -0.19628101587295532, - y: 0.6418180465698242, - z: 0.2830369472503662, - w: 0.6851521730422974 - }] - } + equippableLeftRotation: { + x: -0.19628101587295532, + y: 0.6418180465698242, + z: 0.2830369472503662, + w: 0.6851521730422974 + }, + equippableRightPosition: { + x: 0.1177130937576294, + y: 0.12922893464565277, + z: 0.08307232707738876 + }, + equippableRightRotation: { + x: 0.4934672713279724, + y: 0.3605862259864807, + z: 0.6394805908203125, + w: -0.4664038419723511 } - }) + } } var pingPongGun = Entities.addEntity(pingPongGunProperties); diff --git a/scripts/tutorials/createPistol.js b/scripts/tutorials/createPistol.js index 8851f53d09..0912645c35 100644 --- a/scripts/tutorials/createPistol.js +++ b/scripts/tutorials/createPistol.js @@ -37,38 +37,34 @@ var pistolProperties = { restitution: 0, damping: 0.5, collisionSoundURL: COLLISION_SOUND_URL, - userData: JSON.stringify({ - grabbableKey: { - invertSolidWhileHeld: true + grab: { + equippable: true, + equippableLeftPosition: { + x: 0.1802254319190979, + y: 0.13442856073379517, + z: 0.08504903316497803 }, - wearable: { - joints: { - RightHand: [{ - x: 0.07079616189002991, - y: 0.20177987217903137, - z: 0.06374628841876984 - }, { - x: -0.5863648653030396, - y: -0.46007341146469116, - z: 0.46949487924575806, - w: -0.4733745753765106 - }], - LeftHand: [{ - x: 0.1802254319190979, - y: 0.13442856073379517, - z: 0.08504903316497803 - }, { - x: 0.2198076844215393, - y: -0.7377811074256897, - z: 0.2780133783817291, - w: 0.574519157409668 - }] - } + equippableLeftRotation: { + x: 0.2198076844215393, + y: -0.7377811074256897, + z: 0.2780133783817291, + w: 0.574519157409668 + }, + equippableRightPosition: { + x: 0.07079616189002991, + y: 0.20177987217903137, + z: 0.06374628841876984 + }, + equippableRightRotation: { + x: -0.5863648653030396, + y: -0.46007341146469116, + z: 0.46949487924575806, + w: -0.4733745753765106 } - }) + } }; var pistol = Entities.addEntity(pistolProperties); -Script.stop(); \ No newline at end of file +Script.stop(); diff --git a/scripts/tutorials/createSwords.js b/scripts/tutorials/createSwords.js index 749df3c5ed..f375939dc8 100644 --- a/scripts/tutorials/createSwords.js +++ b/scripts/tutorials/createSwords.js @@ -29,11 +29,7 @@ var sword1 = Entities.addEntity({ angularDamping: 0, damping: 0, script: SCRIPT_URL, - userData:JSON.stringify({ - grabbableKey:{ - grabbable:true - } - }) + grab: { grabbable: true } }); var sword2 = Entities.addEntity({ @@ -45,11 +41,7 @@ var sword2 = Entities.addEntity({ angularDamping: 0, damping: 0, script: SCRIPT_URL, - userData:JSON.stringify({ - grabbableKey:{ - grabbable:true - } - }) + grab: { grabbable: true } }); Script.scriptEnding.connect(function scriptEnding() { diff --git a/scripts/tutorials/createTetherballStick.js b/scripts/tutorials/createTetherballStick.js index 1b5bc36932..b940762137 100644 --- a/scripts/tutorials/createTetherballStick.js +++ b/scripts/tutorials/createTetherballStick.js @@ -1,6 +1,6 @@ "use strict"; /* jslint vars: true, plusplus: true, forin: true*/ -/* globals Tablet, Script, AvatarList, Users, Entities, MyAvatar, Camera, Overlays, Vec3, Quat, Controller, print, getControllerWorldLocation */ +/* globals Script, Entities, MyAvatar, Vec3, Quat */ /* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ // // createTetherballStick.js @@ -59,11 +59,7 @@ var ballID = Entities.addEntity({ restitution: BALL_RESTITUTION, dynamic: true, collidesWith: "static,dynamic,otherAvatar,", - userData: JSON.stringify({ - grabbableKey: { - grabbable: false - } - }) + grab: { grabbable: false } }); var lineID = Entities.addEntity({ @@ -109,43 +105,38 @@ var STICK_PROPERTIES = { }, shapeType: 'box', lifetime: LIFETIME, - userData: JSON.stringify({ - grabbableKey: { - invertSolidWhileHeld: true, - ignoreIK: false + grab: { + grabbable: false, + grabFollowsController: false, + equippable: true, + equippableLeftPosition: { + x: -0.14998853206634521, + y: 0.17033983767032623, + z: 0.023199155926704407 }, - wearable: { - joints: { - RightHand: [{ - x: 0.15539926290512085, - y: 0.14493153989315033, - z: 0.023641478270292282 - }, { - x: 0.5481458902359009, - y: -0.4470711946487427, - z: -0.3148134648799896, - w: 0.6328644752502441 - }], - LeftHand: [{ - x: -0.14998853206634521, - y: 0.17033983767032623, - z: 0.023199155926704407 - }, - { - x: 0.6623835563659668, - y: -0.1671387255191803, - z: 0.7071226835250854, - w: 0.1823924481868744 - }] - } + equippableLeftRotation: { + x: 0.6623835563659668, + y: -0.1671387255191803, + z: 0.7071226835250854, + w: 0.1823924481868744 }, - ownerID: MyAvatar.sessionUUID, - ballID: ballID, - lineID: lineID, - actionID: actionID, - lifetime: LIFETIME, - maxDistanceBetweenBallAndStick: ACTION_DISTANCE * MAX_DISTANCE_MULTIPLIER - }) + equippableRightPosition: { + x: 0.15539926290512085, + y: 0.14493153989315033, + z: 0.023641478270292282 + }, + equippableRightRotation: { + x: 0.5481458902359009, + y: -0.4470711946487427, + z: -0.3148134648799896, + w: 0.6328644752502441 + } + }, + ownerID: MyAvatar.sessionUUID, + ballID: ballID, + lineID: lineID, + actionID: actionID, + maxDistanceBetweenBallAndStick: ACTION_DISTANCE * MAX_DISTANCE_MULTIPLIER }; Entities.addEntity(STICK_PROPERTIES); diff --git a/scripts/tutorials/entity_scripts/ambientSound.js b/scripts/tutorials/entity_scripts/ambientSound.js index dd964fb4e0..eab268f9bb 100644 --- a/scripts/tutorials/entity_scripts/ambientSound.js +++ b/scripts/tutorials/entity_scripts/ambientSound.js @@ -32,7 +32,7 @@ range: DEFAULT_RANGE, maxVolume: DEFAULT_VOLUME, disabled: true, - grabbableKey: { wantsTrigger: true }, + grab: { triggerable: true } }; var soundURL = ""; @@ -182,7 +182,7 @@ entity = entityID; _this = this; - var props = Entities.getEntityProperties(entity, [ "userData" ]); + var props = Entities.getEntityProperties(entity, [ "userData", "grab.triggerable" ]); var data = {}; if (props.userData) { data = JSON.parse(props.userData); @@ -194,14 +194,15 @@ changed = true; } } - if (!data.grabbableKey.wantsTrigger) { - data.grabbableKey.wantsTrigger = true; - changed = true; - } if (changed) { debugPrint("applying default values to userData"); Entities.editEntity(entity, { userData: JSON.stringify(data) }); } + + if (!props.grab.triggerable) { + Entities.editEntity(entity, { grab: { triggerable: true } }); + } + this._updateColor(data.disabled); this.updateSettings(); diff --git a/scripts/tutorials/entity_scripts/magneticBlock.js b/scripts/tutorials/entity_scripts/magneticBlock.js index 1ec5f2a6c6..2f073a5f41 100644 --- a/scripts/tutorials/entity_scripts/magneticBlock.js +++ b/scripts/tutorials/entity_scripts/magneticBlock.js @@ -52,32 +52,8 @@ It will behave as the constructor */ preload: function(id) { - /* - We will now override any existing userdata with the grabbable property. - Only retrieving userData - */ - var entityProperties = Entities.getEntityProperties(id, ['userData']); - var userData = { - grabbableKey: {} - }; - // Check if existing userData field exists. - if (entityProperties.userData && entityProperties.userData.length > 0) { - try { - userData = JSON.parse(entityProperties.userData); - if (!userData.grabbableKey) { - userData.grabbableKey = {}; // If by random change there is no grabbableKey in the userData. - } - } catch (e) { - // if user data is not valid json, we will simply overwrite it. - } - } - // Object must be triggerable inorder to bind releaseGrabEvent - userData.grabbableKey.grabbable = true; - // Apply the new properties to entity of id - Entities.editEntity(id, { - userData: JSON.stringify(userData) - }); + Entities.editEntity(id, { grab: { grabbable: true } }); Script.scriptEnding.connect(function() { Script.removeEventHandler(id, "releaseGrab", this.releaseGrab); }); diff --git a/scripts/tutorials/entity_scripts/springHold.js b/scripts/tutorials/entity_scripts/springHold.js index 059ea2cc6f..dbf0ceafeb 100644 --- a/scripts/tutorials/entity_scripts/springHold.js +++ b/scripts/tutorials/entity_scripts/springHold.js @@ -62,11 +62,7 @@ position: originalProps.position, shapeType: originalProps.shapeType, visible: true, - userData:JSON.stringify({ - grabbableKey:{ - grabbable:false - } - }) + grab: { grabbable: false } }; _this.copy = Entities.addEntity(props); } diff --git a/scripts/tutorials/entity_scripts/touch.js b/scripts/tutorials/entity_scripts/touch.js index 1d0586b350..6e1974a4fd 100644 --- a/scripts/tutorials/entity_scripts/touch.js +++ b/scripts/tutorials/entity_scripts/touch.js @@ -142,11 +142,7 @@ position: originalProps.position, shapeType: originalProps.shapeType, visible: true, - userData:JSON.stringify({ - grabbableKey:{ - grabbable:false - } - }) + grab: { grabbable: false } }; _this.copy = Entities.addEntity(props); } diff --git a/scripts/tutorials/makeBlocks.js b/scripts/tutorials/makeBlocks.js index 432f7444c4..c7d0425863 100644 --- a/scripts/tutorials/makeBlocks.js +++ b/scripts/tutorials/makeBlocks.js @@ -53,14 +53,10 @@ y: SIZE, z: SIZE }, - userData: JSON.stringify({ - grabbableKey: { - cloneable: true, - grabbable: true, - cloneLifetime: LIFETIME, - cloneLimit: 9999 - } - }), + grab: { grabbable: true }, + cloneable: true, + cloneLifetime: LIFETIME, + cloneLimit: 9999 position: Vec3.sum(MyAvatar.position, Vec3.sum(forwardOffset, forwardVector)), color: newColor(), script: SCRIPT_URL