diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 4f2b290635..330e1fa854 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1832,39 +1832,8 @@ void EntityItem::computeCollisionGroupAndFinalMask(int16_t& group, int16_t& mask } } - if (userMask & USER_COLLISION_GROUP_MY_AVATAR) { - bool iAmHoldingThis = false; - // if this entity is a descendant of MyAvatar, don't collide with MyAvatar. This avoids the - // "bootstrapping" problem where you can shoot yourself across the room by grabbing something - // and holding it against your own avatar. - if (isChildOfMyAvatar()) { - iAmHoldingThis = true; - } - // also, don't bootstrap our own avatar with a hold action - QList holdActions = getActionsOfType(DYNAMIC_TYPE_HOLD); - QList::const_iterator i = holdActions.begin(); - while (i != holdActions.end()) { - EntityDynamicPointer action = *i; - if (action->isMine()) { - iAmHoldingThis = true; - break; - } - i++; - } - QList farGrabActions = getActionsOfType(DYNAMIC_TYPE_FAR_GRAB); - i = farGrabActions.begin(); - while (i != farGrabActions.end()) { - EntityDynamicPointer action = *i; - if (action->isMine()) { - iAmHoldingThis = true; - break; - } - i++; - } - - if (iAmHoldingThis) { - userMask &= ~USER_COLLISION_GROUP_MY_AVATAR; - } + if (_dirtyFlags & Simulation::DIRTY_IGNORE_MY_AVATAR) { + userMask &= ~USER_COLLISION_GROUP_MY_AVATAR; } mask = Physics::getDefaultCollisionMask(group) & (int16_t)(userMask); } @@ -1960,6 +1929,17 @@ bool EntityItem::addActionInternal(EntitySimulationPointer simulation, EntityDyn _allActionsDataCache = newDataCache; _dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION; _dirtyFlags |= Simulation::DIRTY_COLLISION_GROUP; // may need to not collide with own avatar + + auto actionType = action->getType(); + if (actionType == DYNAMIC_TYPE_HOLD || actionType == DYNAMIC_TYPE_FAR_GRAB) { + _dirtyFlags |= Simulation::DIRTY_IGNORE_MY_AVATAR; + forEachDescendant([&](SpatiallyNestablePointer child) { + if (child->getNestableType() == NestableType::Entity) { + EntityItemPointer entity = std::static_pointer_cast(child); + entity->markDirtyFlags(Simulation::DIRTY_IGNORE_MY_AVATAR); + } + }); + } } else { qCDebug(entities) << "EntityItem::addActionInternal -- serializeActions failed"; } @@ -2000,6 +1980,32 @@ bool EntityItem::removeAction(EntitySimulationPointer simulation, const QUuid& a return success; } +bool EntityItem::stillHasGrabActions() { + bool stillHasGrabAction = false; + QList holdActions = getActionsOfType(DYNAMIC_TYPE_HOLD); + QList::const_iterator i = holdActions.begin(); + while (i != holdActions.end()) { + EntityDynamicPointer action = *i; + if (action->isMine()) { + stillHasGrabAction = true; + break; + } + i++; + } + QList farGrabActions = getActionsOfType(DYNAMIC_TYPE_FAR_GRAB); + i = farGrabActions.begin(); + while (i != farGrabActions.end()) { + EntityDynamicPointer action = *i; + if (action->isMine()) { + stillHasGrabAction = true; + break; + } + i++; + } + + return stillHasGrabAction; +} + bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulationPointer simulation) { _previouslyDeletedActions.insert(actionID, usecTimestampNow()); if (_objectActions.contains(actionID)) { @@ -2023,6 +2029,15 @@ bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulationPoi serializeActions(success, _allActionsDataCache); _dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION; _dirtyFlags |= Simulation::DIRTY_COLLISION_GROUP; // may need to not collide with own avatar + if (stillHasGrabActions()) { + _dirtyFlags |= Simulation::DIRTY_IGNORE_MY_AVATAR; + forEachDescendant([&](SpatiallyNestablePointer child) { + if (child->getNestableType() == NestableType::Entity) { + EntityItemPointer entity = std::static_pointer_cast(child); + entity->markDirtyFlags(Simulation::DIRTY_IGNORE_MY_AVATAR); + } + }); + } setDynamicDataNeedsTransmit(true); return success; } diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 882b8e6812..ab6df1ab33 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -437,6 +437,7 @@ public: // if this entity is client-only, which avatar is it associated with? QUuid getOwningAvatarID() const { return _owningAvatarID; } void setOwningAvatarID(const QUuid& owningAvatarID) { _owningAvatarID = owningAvatarID; } + bool stillHasGrabActions(); virtual bool wantsHandControllerPointerEvents() const { return false; } virtual bool wantsKeyboardFocus() const { return false; } diff --git a/libraries/entities/src/SimulationFlags.h b/libraries/entities/src/SimulationFlags.h index e2b2224b4a..aeee1ae01b 100644 --- a/libraries/entities/src/SimulationFlags.h +++ b/libraries/entities/src/SimulationFlags.h @@ -27,6 +27,7 @@ namespace Simulation { const uint32_t DIRTY_PHYSICS_ACTIVATION = 0x0800; // should activate object in physics engine const uint32_t DIRTY_SIMULATOR_ID = 0x1000; // the simulatorID has changed const uint32_t DIRTY_SIMULATION_OWNERSHIP_PRIORITY = 0x2000; // our own bid priority has changed + const uint32_t DIRTY_IGNORE_MY_AVATAR = 0x4000; const uint32_t DIRTY_TRANSFORM = DIRTY_POSITION | DIRTY_ROTATION; const uint32_t DIRTY_VELOCITIES = DIRTY_LINEAR_VELOCITY | DIRTY_ANGULAR_VELOCITY; diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index 0b91ede574..ae5496b076 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -47,7 +47,7 @@ enum MotionStateType { // The update flags trigger two varieties of updates: "hard" which require the body to be pulled // and re-added to the physics engine and "easy" which just updates the body properties. const uint32_t HARD_DIRTY_PHYSICS_FLAGS = (uint32_t)(Simulation::DIRTY_MOTION_TYPE | Simulation::DIRTY_SHAPE | - Simulation::DIRTY_COLLISION_GROUP); + Simulation::DIRTY_COLLISION_GROUP | Simulation::DIRTY_IGNORE_MY_AVATAR); const uint32_t EASY_DIRTY_PHYSICS_FLAGS = (uint32_t)(Simulation::DIRTY_TRANSFORM | Simulation::DIRTY_VELOCITIES | Simulation::DIRTY_MASS | Simulation::DIRTY_MATERIAL | Simulation::DIRTY_SIMULATOR_ID | Simulation::DIRTY_SIMULATION_OWNERSHIP_PRIORITY |