diff --git a/assignment-client/src/AssignmentDynamic.h b/assignment-client/src/AssignmentDynamic.h index 477b8ea1d6..604c418c13 100644 --- a/assignment-client/src/AssignmentDynamic.h +++ b/assignment-client/src/AssignmentDynamic.h @@ -24,7 +24,7 @@ public: AssignmentDynamic(EntityDynamicType type, const QUuid& id, EntityItemPointer ownerEntity); virtual ~AssignmentDynamic(); - virtual void remapIDs(QHash* map) override {}; + virtual void remapIDs(QHash& map) override {}; virtual void removeFromSimulation(EntitySimulationPointer simulation) const override; virtual EntityItemWeakPointer getOwnerEntity() const override { return _ownerEntity; } diff --git a/libraries/entities/src/EntityDynamicInterface.h b/libraries/entities/src/EntityDynamicInterface.h index ccfbafec2e..ef20f84da4 100644 --- a/libraries/entities/src/EntityDynamicInterface.h +++ b/libraries/entities/src/EntityDynamicInterface.h @@ -47,7 +47,7 @@ public: const QUuid& getID() const { return _id; } EntityDynamicType getType() const { return _type; } - virtual void remapIDs(QHash* map) = 0; + virtual void remapIDs(QHash& map) = 0; virtual bool isAction() const { return false; } virtual bool isConstraint() const { return false; } diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 76483d0786..22bde03100 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -25,6 +25,8 @@ #include "RecurseOctreeToMapOperator.h" #include "LogHandler.h" #include "EntityEditFilters.h" +#include "EntityDynamicFactoryInterface.h" + static const quint64 DELETED_ENTITIES_EXTRA_USECS_TO_CONSIDER = USECS_PER_MSEC * 50; const float EntityTree::DEFAULT_MAX_TMP_ENTITY_LIFETIME = 60 * 60; // 1 hour @@ -1549,13 +1551,23 @@ QVector EntityTree::sendEntities(EntityEditPacketSender* packetSen bool EntityTree::sendEntitiesOperation(OctreeElementPointer element, void* extraData) { SendEntitiesOperationArgs* args = static_cast(extraData); EntityTreeElementPointer entityTreeElement = std::static_pointer_cast(element); - std::function getMapped = [&](EntityItemPointer& item) -> const EntityItemID { - EntityItemID oldID = item->getEntityItemID(); - if (args->map->contains(oldID)) { // Already been handled (e.g., as a parent of somebody that we've processed). - return args->map->value(oldID); + + auto getMapped = [&](EntityItemID oldID) { + if (oldID.isNull()) { + return EntityItemID(); } - EntityItemID newID = QUuid::createUuid(); - args->map->insert(oldID, newID); + if (args->map->contains(oldID)) { + return args->map->value(oldID); + } else { + EntityItemID newID = QUuid::createUuid(); + args->map->insert(oldID, newID); + return newID; + } + }; + + entityTreeElement->forEachEntity([&](EntityItemPointer item) { + EntityItemID oldID = item->getEntityItemID(); + EntityItemID newID = getMapped(oldID); EntityItemProperties properties = item->getProperties(); EntityItemID oldParentID = properties.getParentID(); @@ -1564,8 +1576,7 @@ bool EntityTree::sendEntitiesOperation(OctreeElementPointer element, void* extra } else { EntityItemPointer parentEntity = args->ourTree->findEntityByEntityItemID(oldParentID); if (parentEntity) { // map the parent - // Warning: (non-tail) recursion of getMapped could blow the call stack if the parent hierarchy is VERY deep. - properties.setParentID(getMapped(parentEntity)); + properties.setParentID(getMapped(parentEntity->getID())); // But do not add root offset in this case. } else { // Should not happen, but let's try to be helpful... item->globalizeProperties(properties, "Cannot find %3 parent of %2 %1", args->root); @@ -1573,40 +1584,63 @@ bool EntityTree::sendEntitiesOperation(OctreeElementPointer element, void* extra } if (!properties.getXNNeighborID().isInvalidID()) { - auto neighborEntity = args->ourTree->findEntityByEntityItemID(properties.getXNNeighborID()); - if (neighborEntity) { - properties.setXNNeighborID(getMapped(neighborEntity)); - } + properties.setXNNeighborID(getMapped(properties.getXNNeighborID())); } if (!properties.getXPNeighborID().isInvalidID()) { - auto neighborEntity = args->ourTree->findEntityByEntityItemID(properties.getXPNeighborID()); - if (neighborEntity) { - properties.setXPNeighborID(getMapped(neighborEntity)); - } + properties.setXPNeighborID(getMapped(properties.getXPNeighborID())); } if (!properties.getYNNeighborID().isInvalidID()) { - auto neighborEntity = args->ourTree->findEntityByEntityItemID(properties.getYNNeighborID()); - if (neighborEntity) { - properties.setYNNeighborID(getMapped(neighborEntity)); - } + properties.setYNNeighborID(getMapped(properties.getYNNeighborID())); } if (!properties.getYPNeighborID().isInvalidID()) { - auto neighborEntity = args->ourTree->findEntityByEntityItemID(properties.getYPNeighborID()); - if (neighborEntity) { - properties.setYPNeighborID(getMapped(neighborEntity)); - } + properties.setYPNeighborID(getMapped(properties.getYPNeighborID())); } if (!properties.getZNNeighborID().isInvalidID()) { - auto neighborEntity = args->ourTree->findEntityByEntityItemID(properties.getZNNeighborID()); - if (neighborEntity) { - properties.setZNNeighborID(getMapped(neighborEntity)); - } + properties.setZNNeighborID(getMapped(properties.getZNNeighborID())); } if (!properties.getZPNeighborID().isInvalidID()) { - auto neighborEntity = args->ourTree->findEntityByEntityItemID(properties.getZPNeighborID()); - if (neighborEntity) { - properties.setZPNeighborID(getMapped(neighborEntity)); + properties.setZPNeighborID(getMapped(properties.getZPNeighborID())); + } + + QByteArray actionData = properties.getActionData(); + if (!actionData.isEmpty()) { + QDataStream serializedActionsStream(actionData); + QVector serializedActions; + serializedActionsStream >> serializedActions; + + auto actionFactory = DependencyManager::get(); + + QHash remappedActions; + foreach(QByteArray serializedAction, serializedActions) { + QDataStream serializedActionStream(serializedAction); + EntityDynamicType actionType; + QUuid oldActionID; + serializedActionStream >> actionType; + serializedActionStream >> oldActionID; + QUuid actionID = QUuid::createUuid(); // give the action a new ID + (*args->map)[oldActionID] = actionID; + EntityDynamicPointer action = actionFactory->factoryBA(nullptr, serializedAction); + if (action) { + action->remapIDs(*args->map); + remappedActions[actionID] = action; + } } + + QVector remappedSerializedActions; + + QHash::const_iterator i = remappedActions.begin(); + while (i != remappedActions.end()) { + const QUuid id = i.key(); + EntityDynamicPointer action = remappedActions[id]; + QByteArray bytesForAction = action->serialize(); + remappedSerializedActions << bytesForAction; + i++; + } + + QByteArray result; + QDataStream remappedSerializedActionsStream(&result, QIODevice::WriteOnly); + remappedSerializedActionsStream << remappedSerializedActions; + properties.setActionData(result); } // set creation time to "now" for imported entities @@ -1623,13 +1657,26 @@ bool EntityTree::sendEntitiesOperation(OctreeElementPointer element, void* extra // also update the local tree instantly (note: this is not our tree, but an alternate tree) if (args->otherTree) { args->otherTree->withWriteLock([&] { - args->otherTree->addEntity(newID, properties); + EntityItemPointer entity = args->otherTree->addEntity(newID, properties); + entity->deserializeActions(); }); } return newID; - }; + }); + + + + QHash::iterator i = (*args->map).begin(); + while (i != (*args->map).end()) { + EntityItemID newID = i.value(); + if (args->otherTree->findEntityByEntityItemID(newID)) { + i++; + } else { + EntityItemID oldID = i.key(); + i = (*args->map).erase(i); + } + } - entityTreeElement->forEachEntity(getMapped); return true; } diff --git a/libraries/physics/src/ObjectConstraintHinge.cpp b/libraries/physics/src/ObjectConstraintHinge.cpp index cf91ca904b..fa89107f6f 100644 --- a/libraries/physics/src/ObjectConstraintHinge.cpp +++ b/libraries/physics/src/ObjectConstraintHinge.cpp @@ -275,18 +275,20 @@ bool ObjectConstraintHinge::updateArguments(QVariantMap arguments) { QVariantMap ObjectConstraintHinge::getArguments() { QVariantMap arguments = ObjectDynamic::getArguments(); withReadLock([&] { + arguments["pivot"] = glmToQMap(_pivotInA); + arguments["axis"] = glmToQMap(_axisInA); + arguments["otherEntityID"] = _otherEntityID; + arguments["otherPivot"] = glmToQMap(_pivotInB); + arguments["otherAxis"] = glmToQMap(_axisInB); + arguments["low"] = _low; + arguments["high"] = _high; + arguments["softness"] = _softness; + arguments["biasFactor"] = _biasFactor; + arguments["relaxationFactor"] = _relaxationFactor; if (_constraint) { - arguments["pivot"] = glmToQMap(_pivotInA); - arguments["axis"] = glmToQMap(_axisInA); - arguments["otherEntityID"] = _otherEntityID; - arguments["otherPivot"] = glmToQMap(_pivotInB); - arguments["otherAxis"] = glmToQMap(_axisInB); - arguments["low"] = _low; - arguments["high"] = _high; - arguments["softness"] = _softness; - arguments["biasFactor"] = _biasFactor; - arguments["relaxationFactor"] = _relaxationFactor; arguments["angle"] = static_cast(_constraint)->getHingeAngle(); // [-PI,PI] + } else { + arguments["angle"] = 0.0f; } }); return arguments; diff --git a/libraries/physics/src/ObjectDynamic.cpp b/libraries/physics/src/ObjectDynamic.cpp index 3bad6b135b..0982c9825d 100644 --- a/libraries/physics/src/ObjectDynamic.cpp +++ b/libraries/physics/src/ObjectDynamic.cpp @@ -24,14 +24,17 @@ ObjectDynamic::ObjectDynamic(EntityDynamicType type, const QUuid& id, EntityItem ObjectDynamic::~ObjectDynamic() { } -void ObjectDynamic::remapIDs(QHash* map) { +void ObjectDynamic::remapIDs(QHash& map) { withWriteLock([&]{ - if (map->contains(_id)) { - _id = (*map)[_id]; + if (!map.contains(_id)) { + map[_id] = QUuid::createUuid(); } - if (map->contains(_otherID)) { - _otherID = (*map)[_otherID]; + _id = map[_id]; + + if (!map.contains(_otherID)) { + map[_otherID] = QUuid::createUuid(); } + _otherID = map[_otherID]; }); } diff --git a/libraries/physics/src/ObjectDynamic.h b/libraries/physics/src/ObjectDynamic.h index 06cea4e525..582f47db77 100644 --- a/libraries/physics/src/ObjectDynamic.h +++ b/libraries/physics/src/ObjectDynamic.h @@ -29,7 +29,7 @@ public: ObjectDynamic(EntityDynamicType type, const QUuid& id, EntityItemPointer ownerEntity); virtual ~ObjectDynamic(); - virtual void remapIDs(QHash* map) override; + virtual void remapIDs(QHash& map) override; virtual void removeFromSimulation(EntitySimulationPointer simulation) const override; virtual EntityItemWeakPointer getOwnerEntity() const override { return _ownerEntity; }