From 7da0935db2bd50633a04ba24f3e6b54b2bd9df65 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 13 Apr 2016 12:41:49 -0700 Subject: [PATCH 01/14] grab.js will do heart-beat in userData so handControllerGrab.js wont see it as an abandoned grab --- examples/grab.js | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/examples/grab.js b/examples/grab.js index f9d1f41b97..8857b5f611 100644 --- a/examples/grab.js +++ b/examples/grab.js @@ -29,6 +29,10 @@ var IDENTITY_QUAT = { var GRABBABLE_DATA_KEY = "grabbableKey"; // shared with handControllerGrab.js var GRAB_USER_DATA_KEY = "grabKey"; // shared with handControllerGrab.js +var MSECS_PER_SEC = 1000.0; +var HEART_BEAT_INTERVAL = 5 * MSECS_PER_SEC; +var HEART_BEAT_TIMEOUT = 15 * MSECS_PER_SEC; + var DEFAULT_GRABBABLE_DATA = { grabbable: true, invertSolidWhileHeld: false @@ -335,6 +339,9 @@ Grabber.prototype.pressEvent = function(event) { mouse.startDrag(event); + var now = Date.now(); + this.lastHeartBeat = 0; + var clickedEntity = pickResults.entityID; var entityProperties = Entities.getEntityProperties(clickedEntity) this.startPosition = entityProperties.position; @@ -399,12 +406,26 @@ Grabber.prototype.releaseEvent = function(event) { } } + +Grabber.prototype.heartBeat = function(entityID) { + var now = Date.now(); + if (now - this.lastHeartBeat > HEART_BEAT_INTERVAL) { + var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {}); + data["heartBeat"] = now; + setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data); + this.lastHeartBeat = now; + } +}; + + Grabber.prototype.moveEvent = function(event) { if (!this.isGrabbing) { return; } mouse.updateDrag(event); + this.heartBeat(this.entityID); + // see if something added/restored gravity var entityProperties = Entities.getEntityProperties(this.entityID); if (Vec3.length(entityProperties.gravity) != 0) { From 000d6c8a68d89063648147dc7ce1500208bd71bf Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 13 Apr 2016 12:48:05 -0700 Subject: [PATCH 02/14] when doing a parenting grab of something that already has an action, set the parent back to null when releasing --- examples/controllers/handControllerGrab.js | 27 ++++++++++++---------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 4b20651899..f0966ac53b 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -102,7 +102,6 @@ var ZERO_VEC = { }; var NULL_UUID = "{00000000-0000-0000-0000-000000000000}"; -var MSEC_PER_SEC = 1000.0; // these control how long an abandoned pointer line or action will hang around var LIFETIME = 10; @@ -837,7 +836,7 @@ function MyController(hand) { this.search = function() { this.grabbedEntity = null; this.isInitialGrab = false; - this.doubleParentGrab = false; + this.shouldResetParentOnRelease = false; this.checkForStrayChildren(); @@ -914,7 +913,7 @@ function MyController(hand) { candidateEntities = rayPickedCandidateEntities.concat(nearPickedCandidateEntities); var forbiddenNames = ["Grab Debug Entity", "grab pointer"]; - var forbiddenTypes = ['Unknown', 'Light', 'ParticleEffect', 'PolyLine', 'Zone']; + var forbiddenTypes = ['Unknown', 'Light', 'PolyLine', 'Zone']; var minDistance = PICK_MAX_DISTANCE; var i, props, distance, grabbableData; @@ -1019,6 +1018,10 @@ function MyController(hand) { if (this.state == STATE_SEARCHING) { this.setState(STATE_NEAR_GRABBING); } else { // (this.state == STATE_HOLD_SEARCHING) + // if there was already an action, we'll need to set the parent back to null once we release + this.shouldResetParentOnRelease = true; + this.previousParentID = props.parentID; + this.previousParentJointIndex = props.parentJointIndex; this.setState(STATE_HOLD); } return; @@ -1064,7 +1067,7 @@ function MyController(hand) { // it's not physical and it's already held via parenting. go ahead and grab it, but // save off the current parent and joint. this wont always be right if there are more than // two grabs and the order of release isn't opposite of the order of grabs. - this.doubleParentGrab = true; + this.shouldResetParentOnRelease = true; this.previousParentID = props.parentID; this.previousParentJointIndex = props.parentJointIndex; if (this.state == STATE_SEARCHING) { @@ -1149,7 +1152,7 @@ function MyController(hand) { if (this.actionID === NULL_UUID) { this.actionID = null; } - this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); + this.actionTimeout = now + (ACTION_TTL * MSECS_PER_SEC); if (this.actionID !== null) { this.setState(STATE_CONTINUE_DISTANCE_HOLDING); @@ -1184,7 +1187,7 @@ function MyController(hand) { var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); var now = Date.now(); - var deltaTime = (now - this.currentObjectTime) / MSEC_PER_SEC; // convert to seconds + var deltaTime = (now - this.currentObjectTime) / MSECS_PER_SEC; // convert to seconds this.currentObjectTime = now; // the action was set up when this.distanceHolding was called. update the targets. @@ -1302,7 +1305,7 @@ function MyController(hand) { ttl: ACTION_TTL }); if (success) { - this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); + this.actionTimeout = now + (ACTION_TTL * MSECS_PER_SEC); } else { print("continueDistanceHolding -- updateAction failed"); } @@ -1327,7 +1330,7 @@ function MyController(hand) { return false; } var now = Date.now(); - this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); + this.actionTimeout = now + (ACTION_TTL * MSECS_PER_SEC); return true; }; @@ -1563,7 +1566,7 @@ function MyController(hand) { var now = Date.now(); var deltaPosition = Vec3.subtract(handControllerPosition, this.currentHandControllerTipPosition); // meters - var deltaTime = (now - this.currentObjectTime) / MSEC_PER_SEC; // convert to seconds + var deltaTime = (now - this.currentObjectTime) / MSECS_PER_SEC; // convert to seconds if (deltaTime > 0.0) { var worldDeltaPosition = Vec3.subtract(props.position, this.currentObjectPosition); @@ -1590,7 +1593,7 @@ function MyController(hand) { this.callEntityMethodOnGrabbed("continueNearGrab"); } - if (this.actionID && this.actionTimeout - now < ACTION_TTL_REFRESH * MSEC_PER_SEC) { + if (this.actionID && this.actionTimeout - now < ACTION_TTL_REFRESH * MSECS_PER_SEC) { // if less than a 5 seconds left, refresh the actions ttl var success = Entities.updateAction(this.grabbedEntity, this.actionID, { hand: this.hand === RIGHT_HAND ? "right" : "left", @@ -1603,7 +1606,7 @@ function MyController(hand) { ignoreIK: this.ignoreIK }); if (success) { - this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); + this.actionTimeout = now + (ACTION_TTL * MSECS_PER_SEC); } else { print("continueNearGrabbing -- updateAction failed"); Entities.deleteAction(this.grabbedEntity, this.actionID); @@ -1881,7 +1884,7 @@ function MyController(hand) { } data = null; - } else if (this.doubleParentGrab) { + } else if (this.shouldResetParentOnRelease) { // we parent-grabbed this from another parent grab. try to put it back where we found it. var deactiveProps = { parentID: this.previousParentID, From 3186984586b3c40f37c660bf7a6fc0d9ebc3f53b Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 13 Apr 2016 13:39:06 -0700 Subject: [PATCH 03/14] don't give velocity to non-physical things when they are released --- examples/controllers/handControllerGrab.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index f0966ac53b..f79773fe6c 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -739,10 +739,6 @@ function MyController(hand) { }; this.propsArePhysical = function(props) { - if (!props.dynamic && props.parentID != MyAvatar.sessionUUID) { - // if we have parented something, don't do this check on dynamic. - return false; - } var isPhysical = (props.shapeType && props.shapeType != 'none'); return isPhysical; } @@ -1841,12 +1837,12 @@ function MyController(hand) { // things that are held by parenting and dropped with no velocity will end up as "static" in bullet. If // it looks like the dropped thing should fall, give it a little velocity. - var props = Entities.getEntityProperties(entityID, ["parentID", "velocity"]) + var props = Entities.getEntityProperties(entityID, ["parentID", "velocity", "dynamic", "shapeType"]) var parentID = props.parentID; var forceVelocity = false; var doSetVelocity = false; - if (parentID != NULL_UUID && deactiveProps.parentID == NULL_UUID) { + if (parentID != NULL_UUID && deactiveProps.parentID == NULL_UUID && this.propsArePhysical(props)) { // TODO: EntityScriptingInterface::convertLocationToScriptSemantics should be setting up // props.velocity to be a world-frame velocity and localVelocity to be vs parent. Until that // is done, we use a measured velocity here so that things held via a bumper-grab / parenting-grab From 6591329b0cb5adf3956d03cbce0f09bfa0166bb3 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 26 Apr 2016 13:04:08 -0700 Subject: [PATCH 04/14] grab script calls startDistanceGrab and releaseGrab entity methods and sends grab/release messages to Hifi-Object-Manipulation channel --- examples/grab.js | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/examples/grab.js b/examples/grab.js index 8857b5f611..2134616f89 100644 --- a/examples/grab.js +++ b/examples/grab.js @@ -383,7 +383,16 @@ Grabber.prototype.pressEvent = function(event) { if(!entityIsGrabbedByOther(this.entityID)){ this.moveEvent(event); } - + + var args = "mouse"; + Entities.callEntityMethod(this.entityID, "startDistanceGrab", args); + + Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({ + action: 'grab', + grabbedEntity: this.entityID + })); + + // TODO: play sounds again when we aren't leaking AudioInjector threads //Audio.playSound(grabSound, { position: entityProperties.position, volume: VOLUME }); } @@ -401,6 +410,16 @@ Grabber.prototype.releaseEvent = function(event) { beacon.disable(); + var args = "mouse"; + Entities.callEntityMethod(this.entityID, "releaseGrab", args); + + Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({ + action: 'release', + grabbedEntity: this.entityID, + joint: "mouse" + })); + + // TODO: play sounds again when we aren't leaking AudioInjector threads //Audio.playSound(releaseSound, { position: entityProperties.position, volume: VOLUME }); } From 5b8960e43c74443baecb3e0d6e4d6c4711f49ee4 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 26 Apr 2016 13:04:37 -0700 Subject: [PATCH 05/14] send a grab message for action grabs, not just parenting ones --- examples/controllers/handControllerGrab.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index f79773fe6c..8a7399abc2 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -1435,6 +1435,10 @@ function MyController(hand) { if (!this.setupHoldAction()) { return; } + Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({ + action: 'grab', + grabbedEntity: this.grabbedEntity + })); } else { // grab entity via parenting this.actionID = null; From 9e53055d439f9336b976182641f1b23d982d9bc5 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 3 May 2016 15:48:50 -0700 Subject: [PATCH 06/14] parentID and parentJointIndex are now protected by simulation ownership --- libraries/entities/src/EntityItem.cpp | 9 +++++++-- libraries/entities/src/EntityItemProperties.cpp | 2 +- libraries/entities/src/EntityTree.cpp | 10 ++++++++++ 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index dc017f81e6..7bdd88ae5a 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -705,8 +705,13 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef READ_ENTITY_PROPERTY(PROP_DESCRIPTION, QString, setDescription); READ_ENTITY_PROPERTY(PROP_ACTION_DATA, QByteArray, setActionData); - READ_ENTITY_PROPERTY(PROP_PARENT_ID, QUuid, setParentID); - READ_ENTITY_PROPERTY(PROP_PARENT_JOINT_INDEX, quint16, setParentJointIndex); + { // parentID and parentJointIndex are also protected by simulation ownership + bool oldOverwrite = overwriteLocalData; + overwriteLocalData = overwriteLocalData && !weOwnSimulation; + READ_ENTITY_PROPERTY(PROP_PARENT_ID, QUuid, setParentID); + READ_ENTITY_PROPERTY(PROP_PARENT_JOINT_INDEX, quint16, setParentJointIndex); + overwriteLocalData = oldOverwrite; + } READ_ENTITY_PROPERTY(PROP_QUERY_AA_CUBE, AACube, setQueryAACube); diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 92849d6e2f..738e8910fe 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -1615,7 +1615,7 @@ void EntityItemProperties::setSimulationOwner(const QByteArray& data) { QList EntityItemProperties::listChangedProperties() { QList out; if (containsPositionChange()) { - out += "posistion"; + out += "position"; } if (dimensionsChanged()) { out += "dimensions"; diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index b4f0c484d5..27655e2a98 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -213,6 +213,8 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI properties.setVelocityChanged(false); properties.setAngularVelocityChanged(false); properties.setAccelerationChanged(false); + properties.setParentID(false); + properties.setParentJointIndex(false); if (wantTerseEditLogging()) { qCDebug(entities) << (senderNode ? senderNode->getUUID() : "null") << "physical edits suppressed"; @@ -848,6 +850,14 @@ void EntityTree::fixupTerseEditLogging(EntityItemProperties& properties, QList Date: Wed, 4 May 2016 11:29:17 -0700 Subject: [PATCH 07/14] try having all spring derived actions agree on a target --- interface/src/avatar/AvatarActionHold.cpp | 63 ++--------- interface/src/avatar/AvatarActionHold.h | 7 +- libraries/physics/src/ObjectActionSpring.cpp | 106 +++++++++++++++--- libraries/physics/src/ObjectActionSpring.h | 10 ++ .../system/controllers/handControllerGrab.js | 4 +- 5 files changed, 112 insertions(+), 78 deletions(-) diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index 629b3aac12..c84cfecb40 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -93,13 +93,13 @@ void AvatarActionHold::prepareForPhysicsSimulation() { activateBody(true); } -std::shared_ptr AvatarActionHold::getTarget(float deltaTimeStep, glm::quat& rotation, glm::vec3& position, - glm::vec3& linearVelocity, glm::vec3& angularVelocity) { +bool AvatarActionHold::getTarget(float deltaTimeStep, glm::quat& rotation, glm::vec3& position, + glm::vec3& linearVelocity, glm::vec3& angularVelocity) { auto avatarManager = DependencyManager::get(); auto holdingAvatar = std::static_pointer_cast(avatarManager->getAvatarBySessionID(_holderID)); if (!holdingAvatar) { - return holdingAvatar; + return false;; } withReadLock([&]{ @@ -171,62 +171,17 @@ std::shared_ptr AvatarActionHold::getTarget(float deltaTimeStep, glm::qu linearVelocity = linearVelocity + glm::cross(angularVelocity, position - palmPosition); }); - return holdingAvatar; + return true; } void AvatarActionHold::updateActionWorker(float deltaTimeStep) { - glm::quat rotation; - glm::vec3 position; - glm::vec3 linearVelocity; - glm::vec3 angularVelocity; - bool valid = false; - int holdCount = 0; - - auto ownerEntity = _ownerEntity.lock(); - if (!ownerEntity) { - return; - } - QList holdActions = ownerEntity->getActionsOfType(ACTION_TYPE_HOLD); - foreach (EntityActionPointer action, holdActions) { - std::shared_ptr holdAction = std::static_pointer_cast(action); - glm::quat rotationForAction; - glm::vec3 positionForAction; - glm::vec3 linearVelocityForAction, angularVelocityForAction; - std::shared_ptr holdingAvatar = holdAction->getTarget(deltaTimeStep, rotationForAction, positionForAction, linearVelocityForAction, angularVelocityForAction); - if (holdingAvatar) { - holdCount ++; - if (holdAction.get() == this) { - // only use the rotation for this action - valid = true; - rotation = rotationForAction; - } - - position += positionForAction; - linearVelocity += linearVelocityForAction; - angularVelocity += angularVelocityForAction; - } - } - - if (valid && holdCount > 0) { - position /= holdCount; - linearVelocity /= holdCount; - angularVelocity /= holdCount; - - withWriteLock([&]{ - _positionalTarget = position; - _rotationalTarget = rotation; - _linearVelocityTarget = linearVelocity; - _angularVelocityTarget = angularVelocity; - _positionalTargetSet = true; - _rotationalTargetSet = true; - _active = true; - }); - if (_kinematic) { + if (_kinematic) { + if (prepareForSpringUpdate(deltaTimeStep)) { doKinematicUpdate(deltaTimeStep); - } else { - forceBodyNonStatic(); - ObjectActionSpring::updateActionWorker(deltaTimeStep); } + } else { + forceBodyNonStatic(); + ObjectActionSpring::updateActionWorker(deltaTimeStep); } } diff --git a/interface/src/avatar/AvatarActionHold.h b/interface/src/avatar/AvatarActionHold.h index 0ad9cff257..609fd57ff3 100644 --- a/interface/src/avatar/AvatarActionHold.h +++ b/interface/src/avatar/AvatarActionHold.h @@ -36,8 +36,8 @@ public: virtual bool shouldSuppressLocationEdits() override { return _active && !_ownerEntity.expired(); } bool getAvatarRigidBodyLocation(glm::vec3& avatarRigidBodyPosition, glm::quat& avatarRigidBodyRotation); - std::shared_ptr getTarget(float deltaTimeStep, glm::quat& rotation, glm::vec3& position, - glm::vec3& linearVelocity, glm::vec3& angularVelocity); + virtual bool getTarget(float deltaTimeStep, glm::quat& rotation, glm::vec3& position, + glm::vec3& linearVelocity, glm::vec3& angularVelocity) override; virtual void prepareForPhysicsSimulation() override; @@ -51,9 +51,6 @@ private: QString _hand { "right" }; QUuid _holderID; - glm::vec3 _linearVelocityTarget; - glm::vec3 _angularVelocityTarget; - bool _kinematic { false }; bool _kinematicSetVelocity { false }; bool _previousSet { false }; diff --git a/libraries/physics/src/ObjectActionSpring.cpp b/libraries/physics/src/ObjectActionSpring.cpp index dcd77c1010..563733ea2d 100644 --- a/libraries/physics/src/ObjectActionSpring.cpp +++ b/libraries/physics/src/ObjectActionSpring.cpp @@ -21,9 +21,11 @@ const uint16_t ObjectActionSpring::springVersion = 1; ObjectActionSpring::ObjectActionSpring(const QUuid& id, EntityItemPointer ownerEntity) : ObjectAction(ACTION_TYPE_SPRING, id, ownerEntity), _positionalTarget(glm::vec3(0.0f)), + _desiredPositionalTarget(glm::vec3(0.0f)), _linearTimeScale(FLT_MAX), _positionalTargetSet(true), _rotationalTarget(glm::quat()), + _desiredRotationalTarget(glm::quat()), _angularTimeScale(FLT_MAX), _rotationalTargetSet(true) { #if WANT_DEBUG @@ -37,9 +39,82 @@ ObjectActionSpring::~ObjectActionSpring() { #endif } +bool ObjectActionSpring::getTarget(float deltaTimeStep, glm::quat& rotation, glm::vec3& position, + glm::vec3& linearVelocity, glm::vec3& angularVelocity) { + rotation = _desiredRotationalTarget; + position = _desiredPositionalTarget; + linearVelocity = glm::vec3(); + angularVelocity = glm::vec3(); + return true; +} + + +bool ObjectActionSpring::prepareForSpringUpdate(btScalar deltaTimeStep) { + glm::quat rotation; + glm::vec3 position; + glm::vec3 linearVelocity; + glm::vec3 angularVelocity; + + bool valid = false; + int springCount = 0; + + auto ownerEntity = _ownerEntity.lock(); + if (!ownerEntity) { + return false; + } + + QList springDerivedActions; + springDerivedActions.append(ownerEntity->getActionsOfType(ACTION_TYPE_SPRING)); + springDerivedActions.append(ownerEntity->getActionsOfType(ACTION_TYPE_HOLD)); + + foreach (EntityActionPointer action, springDerivedActions) { + std::shared_ptr springAction = std::static_pointer_cast(action); + glm::quat rotationForAction; + glm::vec3 positionForAction; + glm::vec3 linearVelocityForAction, angularVelocityForAction; + bool success = springAction->getTarget(deltaTimeStep, rotationForAction, + positionForAction, linearVelocityForAction, + angularVelocityForAction); + if (success) { + springCount ++; + if (springAction.get() == this) { + // only use the rotation for this action + valid = true; + rotation = rotationForAction; + } + + position += positionForAction; + linearVelocity += linearVelocityForAction; + angularVelocity += angularVelocityForAction; + } + } + + if (valid && springCount > 0) { + position /= springCount; + linearVelocity /= springCount; + angularVelocity /= springCount; + + withWriteLock([&]{ + _positionalTarget = position; + _rotationalTarget = rotation; + _linearVelocityTarget = linearVelocity; + _angularVelocityTarget = angularVelocity; + _positionalTargetSet = true; + _rotationalTargetSet = true; + _active = true; + }); + } + + return valid; +} + + void ObjectActionSpring::updateActionWorker(btScalar deltaTimeStep) { - // don't risk hanging the thread running the physics simulation - auto lockResult = withTryReadLock([&]{ + if (!prepareForSpringUpdate(deltaTimeStep)) { + return; + } + + withReadLock([&]{ auto ownerEntity = _ownerEntity.lock(); if (!ownerEntity) { return; @@ -101,9 +176,6 @@ void ObjectActionSpring::updateActionWorker(btScalar deltaTimeStep) { rigidBody->setAngularVelocity(targetVelocity); } }); - if (!lockResult) { - qDebug() << "ObjectActionSpring::updateActionWorker lock failed"; - } } const float MIN_TIMESCALE = 0.1f; @@ -122,7 +194,7 @@ bool ObjectActionSpring::updateArguments(QVariantMap arguments) { bool ok = true; positionalTarget = EntityActionInterface::extractVec3Argument("spring action", arguments, "targetPosition", ok, false); if (!ok) { - positionalTarget = _positionalTarget; + positionalTarget = _desiredPositionalTarget; } ok = true; linearTimeScale = EntityActionInterface::extractFloatArgument("spring action", arguments, "linearTimeScale", ok, false); @@ -133,7 +205,7 @@ bool ObjectActionSpring::updateArguments(QVariantMap arguments) { ok = true; rotationalTarget = EntityActionInterface::extractQuatArgument("spring action", arguments, "targetRotation", ok, false); if (!ok) { - rotationalTarget = _rotationalTarget; + rotationalTarget = _desiredRotationalTarget; } ok = true; @@ -144,9 +216,9 @@ bool ObjectActionSpring::updateArguments(QVariantMap arguments) { } if (somethingChanged || - positionalTarget != _positionalTarget || + positionalTarget != _desiredPositionalTarget || linearTimeScale != _linearTimeScale || - rotationalTarget != _rotationalTarget || + rotationalTarget != _desiredRotationalTarget || angularTimeScale != _angularTimeScale) { // something changed needUpdate = true; @@ -155,9 +227,9 @@ bool ObjectActionSpring::updateArguments(QVariantMap arguments) { if (needUpdate) { withWriteLock([&] { - _positionalTarget = positionalTarget; + _desiredPositionalTarget = positionalTarget; _linearTimeScale = glm::max(MIN_TIMESCALE, glm::abs(linearTimeScale)); - _rotationalTarget = rotationalTarget; + _desiredRotationalTarget = rotationalTarget; _angularTimeScale = glm::max(MIN_TIMESCALE, glm::abs(angularTimeScale)); _active = true; @@ -177,9 +249,9 @@ QVariantMap ObjectActionSpring::getArguments() { QVariantMap arguments = ObjectAction::getArguments(); withReadLock([&] { arguments["linearTimeScale"] = _linearTimeScale; - arguments["targetPosition"] = glmToQMap(_positionalTarget); + arguments["targetPosition"] = glmToQMap(_desiredPositionalTarget); - arguments["targetRotation"] = glmToQMap(_rotationalTarget); + arguments["targetRotation"] = glmToQMap(_desiredRotationalTarget); arguments["angularTimeScale"] = _angularTimeScale; }); return arguments; @@ -194,10 +266,10 @@ QByteArray ObjectActionSpring::serialize() const { dataStream << ObjectActionSpring::springVersion; withReadLock([&] { - dataStream << _positionalTarget; + dataStream << _desiredPositionalTarget; dataStream << _linearTimeScale; dataStream << _positionalTargetSet; - dataStream << _rotationalTarget; + dataStream << _desiredRotationalTarget; dataStream << _angularTimeScale; dataStream << _rotationalTargetSet; dataStream << localTimeToServerTime(_expires); @@ -226,11 +298,11 @@ void ObjectActionSpring::deserialize(QByteArray serializedArguments) { } withWriteLock([&] { - dataStream >> _positionalTarget; + dataStream >> _desiredPositionalTarget; dataStream >> _linearTimeScale; dataStream >> _positionalTargetSet; - dataStream >> _rotationalTarget; + dataStream >> _desiredRotationalTarget; dataStream >> _angularTimeScale; dataStream >> _rotationalTargetSet; diff --git a/libraries/physics/src/ObjectActionSpring.h b/libraries/physics/src/ObjectActionSpring.h index 96bb900bf6..4f9443121e 100644 --- a/libraries/physics/src/ObjectActionSpring.h +++ b/libraries/physics/src/ObjectActionSpring.h @@ -27,16 +27,26 @@ public: virtual QByteArray serialize() const override; virtual void deserialize(QByteArray serializedArguments) override; + virtual bool getTarget(float deltaTimeStep, glm::quat& rotation, glm::vec3& position, + glm::vec3& linearVelocity, glm::vec3& angularVelocity); + protected: static const uint16_t springVersion; glm::vec3 _positionalTarget; + glm::vec3 _desiredPositionalTarget; float _linearTimeScale; bool _positionalTargetSet; glm::quat _rotationalTarget; + glm::quat _desiredRotationalTarget; float _angularTimeScale; bool _rotationalTargetSet; + + glm::vec3 _linearVelocityTarget; + glm::vec3 _angularVelocityTarget; + + virtual bool ObjectActionSpring::prepareForSpringUpdate(btScalar deltaTimeStep); }; #endif // hifi_ObjectActionSpring_h diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index 2ac07e5c3d..8bbbfcdd88 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -12,7 +12,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html /*global print, MyAvatar, Entities, AnimationCache, SoundCache, Scene, Camera, Overlays, Audio, HMD, AvatarList, AvatarManager, Controller, UndoStack, Window, Account, GlobalServices, Script, ScriptDiscoveryService, LODManager, Menu, Vec3, Quat, AudioDevice, Paths, Clipboard, Settings, XMLHttpRequest, randFloat, randInt, pointInExtents, vec3equal, setEntityCustomData, getEntityCustomData */ -Script.include("../libraries/utils.js"); +Script.include("/~/system/libraries/utils.js"); // @@ -28,7 +28,7 @@ var WANT_DEBUG_SEARCH_NAME = null; var TRIGGER_SMOOTH_RATIO = 0.1; // Time averaging of trigger - 0.0 disables smoothing var TRIGGER_ON_VALUE = 0.4; // Squeezed just enough to activate search or near grab -var TRIGGER_GRAB_VALUE = 0.85; // Squeezed far enough to complete distant grab +var TRIGGER_GRAB_VALUE = 0.75; // Squeezed far enough to complete distant grab var TRIGGER_OFF_VALUE = 0.15; var BUMPER_ON_VALUE = 0.5; From b6918f59a693acdcbc40f9bd15beb604756f413f Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 4 May 2016 11:33:41 -0700 Subject: [PATCH 08/14] remove extra qualification --- libraries/physics/src/ObjectActionSpring.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/physics/src/ObjectActionSpring.h b/libraries/physics/src/ObjectActionSpring.h index 4f9443121e..498bb6c1f5 100644 --- a/libraries/physics/src/ObjectActionSpring.h +++ b/libraries/physics/src/ObjectActionSpring.h @@ -46,7 +46,7 @@ protected: glm::vec3 _linearVelocityTarget; glm::vec3 _angularVelocityTarget; - virtual bool ObjectActionSpring::prepareForSpringUpdate(btScalar deltaTimeStep); + virtual bool prepareForSpringUpdate(btScalar deltaTimeStep); }; #endif // hifi_ObjectActionSpring_h From 382a0c48da96c51a1f66e7533f3cf19bf5f6077e Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 4 May 2016 12:09:26 -0700 Subject: [PATCH 09/14] fix warning --- libraries/entities/src/EntityTree.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 27655e2a98..6a0d0c968f 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -213,7 +213,7 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI properties.setVelocityChanged(false); properties.setAngularVelocityChanged(false); properties.setAccelerationChanged(false); - properties.setParentID(false); + properties.setParentID(QUuid()); properties.setParentJointIndex(false); if (wantTerseEditLogging()) { From 9db839bc138c3acd01f6ed2b4a4e020772bee8f4 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 4 May 2016 15:01:00 -0700 Subject: [PATCH 10/14] don't allow someone else to delete an action that I own. reset dynamic property when releasing and entity, even if refCount isn't 0 --- libraries/entities/src/EntityItem.cpp | 7 +++++-- libraries/entities/src/EntityTree.cpp | 4 ++-- libraries/physics/src/ObjectActionSpring.cpp | 6 ++++-- scripts/system/controllers/handControllerGrab.js | 3 ++- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 7bdd88ae5a..f0022245ad 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1740,6 +1740,7 @@ bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulation* s EntityActionPointer action = _objectActions[actionID]; action->setOwnerEntity(nullptr); + action->setIsMine(false); _objectActions.remove(actionID); if (simulation) { @@ -1846,8 +1847,10 @@ void EntityItem::deserializeActionsInternal() { QUuid id = i.key(); if (!updated.contains(id)) { EntityActionPointer action = i.value(); - // if we've just added this action, don't remove it due to lack of mention in an incoming packet. - if (! action->locallyAddedButNotYetReceived) { + // don't let someone else delete my action. + if (!action->isMine() && + // if we've just added this action, don't remove it due to lack of mention in an incoming packet. + !action->locallyAddedButNotYetReceived) { _actionsToRemove << id; _previouslyDeletedActions.insert(id, now); } diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 6a0d0c968f..8a3395f9dc 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -213,8 +213,8 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI properties.setVelocityChanged(false); properties.setAngularVelocityChanged(false); properties.setAccelerationChanged(false); - properties.setParentID(QUuid()); - properties.setParentJointIndex(false); + properties.setParentIDChanged(false); + properties.setParentJointIndexChanged(false); if (wantTerseEditLogging()) { qCDebug(entities) << (senderNode ? senderNode->getUUID() : "null") << "physical edits suppressed"; diff --git a/libraries/physics/src/ObjectActionSpring.cpp b/libraries/physics/src/ObjectActionSpring.cpp index 563733ea2d..49944d6ed9 100644 --- a/libraries/physics/src/ObjectActionSpring.cpp +++ b/libraries/physics/src/ObjectActionSpring.cpp @@ -45,10 +45,9 @@ bool ObjectActionSpring::getTarget(float deltaTimeStep, glm::quat& rotation, glm position = _desiredPositionalTarget; linearVelocity = glm::vec3(); angularVelocity = glm::vec3(); - return true; + return true; } - bool ObjectActionSpring::prepareForSpringUpdate(btScalar deltaTimeStep) { glm::quat rotation; glm::vec3 position; @@ -140,10 +139,13 @@ void ObjectActionSpring::updateActionWorker(btScalar deltaTimeStep) { float speed = glm::min(offsetLength / _linearTimeScale, SPRING_MAX_SPEED); targetVelocity = (-speed / offsetLength) * offset; if (speed > rigidBody->getLinearSleepingThreshold()) { + qDebug() << "HERE"; + forceBodyNonStatic(); rigidBody->activate(); } } // this action is aggresively critically damped and defeats the current velocity + qDebug() << targetVelocity.x() << targetVelocity.y() << targetVelocity.z(); rigidBody->setLinearVelocity(targetVelocity); } diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index 8bbbfcdd88..0fdaed58f2 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -1895,7 +1895,8 @@ function MyController(hand) { Entities.editEntity(entityID, deactiveProps); } else if (noVelocity) { Entities.editEntity(entityID, {velocity: {x: 0.0, y: 0.0, z: 0.0}, - angularVelocity: {x: 0.0, y: 0.0, z: 0.0}}); + angularVelocity: {x: 0.0, y: 0.0, z: 0.0}, + dynamic: data["dynamic"]}); } } else { data = null; From 91af732516a8613c7f6198dc5ed617bbd534a71b Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 4 May 2016 16:30:38 -0700 Subject: [PATCH 11/14] if we receive an update from the entity-server that doesn't include one of our actions, resend the action data --- libraries/entities/src/EntityItem.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index f0022245ad..4bf7aefb7b 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1847,6 +1847,12 @@ void EntityItem::deserializeActionsInternal() { QUuid id = i.key(); if (!updated.contains(id)) { EntityActionPointer action = i.value(); + + if (action->isMine()) { + // we just received an update that didn't include one of our actions. tell the server about it. + setActionDataNeedsTransmit(true); + } + // don't let someone else delete my action. if (!action->isMine() && // if we've just added this action, don't remove it due to lack of mention in an incoming packet. From d76b8f23358be65174411253308d967d27226f29 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 5 May 2016 06:44:52 -0700 Subject: [PATCH 12/14] action->locallyAddedButNotYetReceived is unneeded with isMine available --- libraries/entities/src/EntityActionInterface.h | 2 -- libraries/entities/src/EntityItem.cpp | 14 ++++---------- libraries/physics/src/ObjectActionSpring.cpp | 2 -- 3 files changed, 4 insertions(+), 14 deletions(-) diff --git a/libraries/entities/src/EntityActionInterface.h b/libraries/entities/src/EntityActionInterface.h index c634326a31..34de87cca4 100644 --- a/libraries/entities/src/EntityActionInterface.h +++ b/libraries/entities/src/EntityActionInterface.h @@ -57,8 +57,6 @@ public: virtual bool isMine() { return _isMine; } virtual void setIsMine(bool value) { _isMine = value; } - bool locallyAddedButNotYetReceived = false; - virtual bool shouldSuppressLocationEdits() { return false; } virtual void prepareForPhysicsSimulation() { } diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 4bf7aefb7b..908e64708e 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1666,7 +1666,7 @@ bool EntityItem::addAction(EntitySimulation* simulation, EntityActionPointer act if (!result) { removeActionInternal(action->getID()); } else { - action->locallyAddedButNotYetReceived = true; + action->setIsMine(true); } }); @@ -1821,7 +1821,6 @@ void EntityItem::deserializeActionsInternal() { if (!action->isMine()) { action->deserialize(serializedAction); } - action->locallyAddedButNotYetReceived = false; updated << actionID; } else { auto actionFactory = DependencyManager::get(); @@ -1829,7 +1828,6 @@ void EntityItem::deserializeActionsInternal() { EntityActionPointer action = actionFactory->factoryBA(entity, serializedAction); if (action) { entity->addActionInternal(simulation, action); - action->locallyAddedButNotYetReceived = false; updated << actionID; } else { static QString repeatedMessage = @@ -1849,14 +1847,10 @@ void EntityItem::deserializeActionsInternal() { EntityActionPointer action = i.value(); if (action->isMine()) { - // we just received an update that didn't include one of our actions. tell the server about it. + // we just received an update that didn't include one of our actions. tell the server about it (again). setActionDataNeedsTransmit(true); - } - - // don't let someone else delete my action. - if (!action->isMine() && - // if we've just added this action, don't remove it due to lack of mention in an incoming packet. - !action->locallyAddedButNotYetReceived) { + } else { + // don't let someone else delete my action. _actionsToRemove << id; _previouslyDeletedActions.insert(id, now); } diff --git a/libraries/physics/src/ObjectActionSpring.cpp b/libraries/physics/src/ObjectActionSpring.cpp index 49944d6ed9..22b7ade979 100644 --- a/libraries/physics/src/ObjectActionSpring.cpp +++ b/libraries/physics/src/ObjectActionSpring.cpp @@ -139,13 +139,11 @@ void ObjectActionSpring::updateActionWorker(btScalar deltaTimeStep) { float speed = glm::min(offsetLength / _linearTimeScale, SPRING_MAX_SPEED); targetVelocity = (-speed / offsetLength) * offset; if (speed > rigidBody->getLinearSleepingThreshold()) { - qDebug() << "HERE"; forceBodyNonStatic(); rigidBody->activate(); } } // this action is aggresively critically damped and defeats the current velocity - qDebug() << targetVelocity.x() << targetVelocity.y() << targetVelocity.z(); rigidBody->setLinearVelocity(targetVelocity); } From cd934bab90a2bf639af2915e17c9ddd31b1f4ccb Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 5 May 2016 14:16:13 -0700 Subject: [PATCH 13/14] set _actionDataDirty when adding an action. --- libraries/entities/src/EntityItem.cpp | 21 ++++++++++++++++++--- libraries/entities/src/EntityItem.h | 1 + 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 8f54273600..deae6bc47b 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1705,16 +1705,31 @@ void EntityItem::setPendingOwnershipPriority(quint8 priority, const quint64& tim _simulationOwner.setPendingPriority(priority, timestamp); } +QString EntityItem::actionsToDebugString() { + QString result; + QVector serializedActions; + QHash::const_iterator i = _objectActions.begin(); + while (i != _objectActions.end()) { + const QUuid id = i.key(); + EntityActionPointer action = _objectActions[id]; + EntityActionType actionType = action->getType(); + result += QString("") + actionType + ":" + action->getID().toString() + " "; + i++; + } + return result; +} + bool EntityItem::addAction(EntitySimulation* simulation, EntityActionPointer action) { bool result; withWriteLock([&] { checkWaitingToRemove(simulation); result = addActionInternal(simulation, action); - if (!result) { - removeActionInternal(action->getID()); - } else { + if (result) { action->setIsMine(true); + _actionDataDirty = true; + } else { + removeActionInternal(action->getID()); } }); diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index ecb9800e70..64c87bde27 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -378,6 +378,7 @@ public: void grabSimulationOwnership(); void flagForMotionStateChange() { _dirtyFlags |= Simulation::DIRTY_MOTION_TYPE; } + QString actionsToDebugString(); bool addAction(EntitySimulation* simulation, EntityActionPointer action); bool updateAction(EntitySimulation* simulation, const QUuid& actionID, const QVariantMap& arguments); bool removeAction(EntitySimulation* simulation, const QUuid& actionID); From f80333ee9e010737008896e4dd864a0f301c1cb7 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 6 May 2016 10:06:51 -0700 Subject: [PATCH 14/14] fix indentation, move an early exit to earlier --- libraries/physics/src/ObjectActionSpring.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libraries/physics/src/ObjectActionSpring.cpp b/libraries/physics/src/ObjectActionSpring.cpp index 22b7ade979..e67a681481 100644 --- a/libraries/physics/src/ObjectActionSpring.cpp +++ b/libraries/physics/src/ObjectActionSpring.cpp @@ -49,6 +49,11 @@ bool ObjectActionSpring::getTarget(float deltaTimeStep, glm::quat& rotation, glm } bool ObjectActionSpring::prepareForSpringUpdate(btScalar deltaTimeStep) { + auto ownerEntity = _ownerEntity.lock(); + if (!ownerEntity) { + return false; + } + glm::quat rotation; glm::vec3 position; glm::vec3 linearVelocity; @@ -57,12 +62,7 @@ bool ObjectActionSpring::prepareForSpringUpdate(btScalar deltaTimeStep) { bool valid = false; int springCount = 0; - auto ownerEntity = _ownerEntity.lock(); - if (!ownerEntity) { - return false; - } - - QList springDerivedActions; + QList springDerivedActions; springDerivedActions.append(ownerEntity->getActionsOfType(ACTION_TYPE_SPRING)); springDerivedActions.append(ownerEntity->getActionsOfType(ACTION_TYPE_HOLD));