From 49e616dd49a441b26d1cbde2ba469ca83e8afc3e Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 13 Aug 2014 14:11:56 -0700 Subject: [PATCH] first cut at using erase entity message to delete entities --- .../octree/OctreeInboundPacketProcessor.cpp | 10 +- .../entities/src/EntityEditPacketSender.cpp | 42 +++-- .../entities/src/EntityEditPacketSender.h | 6 +- libraries/entities/src/EntityItem.cpp | 40 ----- libraries/entities/src/EntityItem.h | 4 - .../entities/src/EntityItemProperties.cpp | 80 ++++------ libraries/entities/src/EntityItemProperties.h | 12 +- .../entities/src/EntityScriptingInterface.cpp | 13 +- libraries/entities/src/EntityTree.cpp | 144 ++++++++++++------ libraries/entities/src/EntityTree.h | 7 +- libraries/entities/src/EntityTreeElement.cpp | 45 ------ libraries/entities/src/EntityTreeElement.h | 1 - libraries/entities/src/ModelEntityItem.cpp | 12 +- libraries/networking/src/PacketHeaders.cpp | 2 +- .../octree/src/OctreeEditPacketSender.cpp | 22 ++- 15 files changed, 207 insertions(+), 233 deletions(-) diff --git a/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp b/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp index 7716f9e2aa..786e0a46d8 100644 --- a/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp +++ b/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp @@ -78,7 +78,7 @@ void OctreeInboundPacketProcessor::processPacket(const SharedNodePointer& sendin return; } - bool debugProcessPacket = _myServer->wantsVerboseDebug(); + bool debugProcessPacket = true;// _myServer->wantsVerboseDebug(); if (debugProcessPacket) { qDebug("OctreeInboundPacketProcessor::processPacket() packetData=%p packetLength=%d", &packet, packet.size()); @@ -103,7 +103,7 @@ void OctreeInboundPacketProcessor::processPacket(const SharedNodePointer& sendin quint64 processTime = 0; quint64 lockWaitTime = 0; - if (_myServer->wantsDebugReceiving()) { + if (debugProcessPacket || _myServer->wantsDebugReceiving()) { qDebug() << "PROCESSING THREAD: got '" << packetType << "' packet - " << _receivedPacketCount << " command from client receivedBytes=" << packet.size() << " sequence=" << sequence << " transitTime=" << transitTime << " usecs"; @@ -126,6 +126,12 @@ void OctreeInboundPacketProcessor::processPacket(const SharedNodePointer& sendin reinterpret_cast(packet.data()), packet.size(), editData, maxSize, sendingNode); + + if (debugProcessPacket) { + qDebug() << "OctreeInboundPacketProcessor::processPacket() after processEditPacketData()..." + << "editDataBytesRead=" << editDataBytesRead; + } + _myServer->getOctree()->unlock(); quint64 endProcess = usecTimestampNow(); diff --git a/libraries/entities/src/EntityEditPacketSender.cpp b/libraries/entities/src/EntityEditPacketSender.cpp index d8e392676d..cee8a65b0e 100644 --- a/libraries/entities/src/EntityEditPacketSender.cpp +++ b/libraries/entities/src/EntityEditPacketSender.cpp @@ -17,32 +17,10 @@ #include "EntityItem.h" -void EntityEditPacketSender::sendEditEntityMessage(PacketType type, EntityItemID modelID, const EntityItemProperties& properties) { - // allows app to disable sending if for example voxels have been disabled - if (!_shouldSend) { - return; // bail early - } - - static unsigned char bufferOut[MAX_PACKET_SIZE]; - int sizeOut = 0; - - // This encodes the voxel edit message into a buffer... - if (EntityItemProperties::encodeEntityEditPacket(type, modelID, properties, &bufferOut[0], _maxPacketSize, sizeOut)){ - // If we don't have voxel jurisdictions, then we will simply queue up these packets and wait till we have - // jurisdictions for processing - if (!serversExist()) { - queuePendingPacketToNodes(type, bufferOut, sizeOut); - } else { - queuePacketToNodes(bufferOut, sizeOut); - } - } -} - void EntityEditPacketSender::adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, ssize_t length, int clockSkew) { EntityItem::adjustEditPacketForClockSkew(codeColorBuffer, length, clockSkew); } - void EntityEditPacketSender::queueEditEntityMessage(PacketType type, EntityItemID modelID, const EntityItemProperties& properties) { if (!_shouldSend) { @@ -58,3 +36,23 @@ void EntityEditPacketSender::queueEditEntityMessage(PacketType type, EntityItemI } } +void EntityEditPacketSender::queueEraseEntityMessage(const EntityItemID& entityItemID) { + if (!_shouldSend) { + return; // bail early + } + +qDebug() << "EntityEditPacketSender::queueEraseEntityMessage() entityItemID=" << entityItemID; + + // use MAX_PACKET_SIZE since it's static and guaranteed to be larger than _maxPacketSize + static unsigned char bufferOut[MAX_PACKET_SIZE]; + size_t sizeOut = 0; + +qDebug() << " _maxPacketSize=" << _maxPacketSize; + + if (EntityItemProperties::encodeEraseEntityMessage(entityItemID, &bufferOut[0], _maxPacketSize, sizeOut)) { + +qDebug() << " encodeEraseEntityMessage()... sizeOut=" << sizeOut; + + queueOctreeEditMessage(PacketTypeEntityErase, bufferOut, sizeOut); + } +} diff --git a/libraries/entities/src/EntityEditPacketSender.h b/libraries/entities/src/EntityEditPacketSender.h index b727f74519..57ea1493b1 100644 --- a/libraries/entities/src/EntityEditPacketSender.h +++ b/libraries/entities/src/EntityEditPacketSender.h @@ -20,16 +20,14 @@ class EntityEditPacketSender : public OctreeEditPacketSender { Q_OBJECT public: - /// Send model add message immediately - /// NOTE: EntityItemProperties assumes that all distances are in meter units - void sendEditEntityMessage(PacketType type, EntityItemID modelID, const EntityItemProperties& properties); - /// Queues an array of several voxel edit messages. Will potentially send a pending multi-command packet. Determines /// which voxel-server node or nodes the packet should be sent to. Can be called even before voxel servers are known, in /// which case up to MaxPendingMessages will be buffered and processed when voxel servers are known. /// NOTE: EntityItemProperties assumes that all distances are in meter units void queueEditEntityMessage(PacketType type, EntityItemID modelID, const EntityItemProperties& properties); + void queueEraseEntityMessage(const EntityItemID& entityItemID); + // My server type is the model server virtual char getMyNodeType() const { return NodeType::EntityServer; } virtual void adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, ssize_t length, int clockSkew); diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index a6e74793cc..394c3bd17a 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -54,7 +54,6 @@ void EntityItem::initFromEntityItemID(const EntityItemID& entityItemID) { _position = glm::vec3(0,0,0); _radius = 0; _rotation = ENTITY_DEFAULT_ROTATION; - _shouldBeDeleted = false; _glowLevel = DEFAULT_GLOW_LEVEL; _mass = DEFAULT_MASS; @@ -220,26 +219,6 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet propertiesDidntFit -= PROP_ROTATION; } - // PROP_SHOULD_BE_DELETED - if (requestedProperties.getHasProperty(PROP_SHOULD_BE_DELETED)) { - //qDebug() << "PROP_SHOULD_BE_DELETED requested..."; - LevelDetails propertyLevel = packetData->startLevel(); - successPropertyFits = packetData->appendValue(getShouldBeDeleted()); - if (successPropertyFits) { - propertyFlags |= PROP_SHOULD_BE_DELETED; - propertiesDidntFit -= PROP_SHOULD_BE_DELETED; - propertyCount++; - packetData->endLevel(propertyLevel); - } else { - //qDebug() << "PROP_SHOULD_BE_DELETED didn't fit..."; - packetData->discardLevel(propertyLevel); - appendState = OctreeElement::PARTIAL; - } - } else { - //qDebug() << "PROP_SHOULD_BE_DELETED NOT requested..."; - propertiesDidntFit -= PROP_SHOULD_BE_DELETED; - } - // PROP_MASS, if (requestedProperties.getHasProperty(PROP_MASS)) { LevelDetails propertyLevel = packetData->startLevel(); @@ -545,17 +524,6 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef } } - // PROP_SHOULD_BE_DELETED - if (propertyFlags.getHasProperty(PROP_SHOULD_BE_DELETED)) { - bool shouldBeDeleted; - memcpy(&shouldBeDeleted, dataAt, sizeof(shouldBeDeleted)); - dataAt += sizeof(shouldBeDeleted); - bytesRead += sizeof(shouldBeDeleted); - if (overwriteLocalData) { - _shouldBeDeleted = shouldBeDeleted; - } - } - // PROP_MASS, if (propertyFlags.getHasProperty(PROP_MASS)) { float value; @@ -641,7 +609,6 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef void EntityItem::debugDump() const { qDebug() << "EntityItem id:" << getEntityItemID(); qDebug(" edited ago:%f", getEditedAgo()); - qDebug(" should die:%s", debug::valueOf(getShouldBeDeleted())); qDebug(" position:%f,%f,%f", _position.x, _position.y, _position.z); qDebug(" radius:%f", getRadius()); } @@ -802,7 +769,6 @@ EntityItemProperties EntityItem::getProperties() const { properties._position = getPosition() * (float) TREE_SCALE; properties._radius = getRadius() * (float) TREE_SCALE; properties._rotation = getRotation(); - properties._shouldBeDeleted = getShouldBeDeleted(); properties._mass = getMass(); properties._velocity = getVelocity() * (float) TREE_SCALE; @@ -814,7 +780,6 @@ EntityItemProperties EntityItem::getProperties() const { properties._positionChanged = false; properties._radiusChanged = false; properties._rotationChanged = false; - properties._shouldBeDeletedChanged = false; properties._massChanged = false; properties._velocityChanged = false; properties._gravityChanged = false; @@ -848,11 +813,6 @@ void EntityItem::setProperties(const EntityItemProperties& properties, bool forc somethingChanged = true; } - if (properties._shouldBeDeletedChanged || forceCopy) { - setShouldBeDeleted(properties._shouldBeDeleted); - somethingChanged = true; - } - if (properties._massChanged || forceCopy) { setMass(properties._mass); somethingChanged = true; diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index e792332fdc..a17172ba74 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -111,9 +111,6 @@ public: const glm::quat& getRotation() const { return _rotation; } void setRotation(const glm::quat& rotation) { _rotation = rotation; } - bool getShouldBeDeleted() const { return _shouldBeDeleted; } - void setShouldBeDeleted(bool shouldBeDeleted) { _shouldBeDeleted = shouldBeDeleted; } - static const float DEFAULT_GLOW_LEVEL; float getGlowLevel() const { return _glowLevel; } void setGlowLevel(float glowLevel) { _glowLevel = glowLevel; } @@ -182,7 +179,6 @@ protected: glm::vec3 _position; float _radius; glm::quat _rotation; - bool _shouldBeDeleted; float _glowLevel; float _mass; glm::vec3 _velocity; diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 48325211d4..638a245197 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -28,7 +28,6 @@ EntityItemProperties::EntityItemProperties() : _position(0), _radius(ENTITY_DEFAULT_RADIUS), _rotation(ENTITY_DEFAULT_ROTATION), - _shouldBeDeleted(false), _mass(EntityItem::DEFAULT_MASS), _velocity(EntityItem::DEFAULT_VELOCITY), _gravity(EntityItem::DEFAULT_GRAVITY), @@ -39,7 +38,6 @@ EntityItemProperties::EntityItemProperties() : _positionChanged(false), _radiusChanged(false), _rotationChanged(false), - _shouldBeDeletedChanged(false), _massChanged(false), _velocityChanged(false), _gravityChanged(false), @@ -89,11 +87,6 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { changedProperties += PROP_ROTATION; } - if (_shouldBeDeletedChanged) { - changedProperties += PROP_SHOULD_BE_DELETED; - } - - if (_massChanged) { changedProperties += PROP_MASS; } @@ -161,7 +154,6 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine) cons properties.setProperty("radius", _radius); QScriptValue rotation = quatToScriptValue(engine, _rotation); properties.setProperty("rotation", rotation); - properties.setProperty("shouldBeDeleted", _shouldBeDeleted); properties.setProperty("mass", _mass); QScriptValue velocity = vec3toScriptValue(engine, _velocity); properties.setProperty("velocity", velocity); @@ -251,16 +243,6 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) { } } - QScriptValue shouldBeDeleted = object.property("shouldBeDeleted"); - if (shouldBeDeleted.isValid()) { - bool newShouldBeDeleted; - newShouldBeDeleted = shouldBeDeleted.toVariant().toBool(); - if (_defaultSettings || newShouldBeDeleted != _shouldBeDeleted) { - _shouldBeDeleted = newShouldBeDeleted; - _shouldBeDeletedChanged = true; - } - } - QScriptValue mass = object.property("mass"); if (mass.isValid()) { float newValue; @@ -600,26 +582,6 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem propertiesDidntFit -= PROP_ROTATION; } - // PROP_SHOULD_BE_DELETED - if (requestedProperties.getHasProperty(PROP_SHOULD_BE_DELETED)) { - //qDebug() << "PROP_SHOULD_BE_DELETED requested..."; - LevelDetails propertyLevel = packetData.startLevel(); - successPropertyFits = packetData.appendValue(properties.getShouldBeDeleted()); - if (successPropertyFits) { - propertyFlags |= PROP_SHOULD_BE_DELETED; - propertiesDidntFit -= PROP_SHOULD_BE_DELETED; - propertyCount++; - packetData.endLevel(propertyLevel); - } else { - //qDebug() << "PROP_SHOULD_BE_DELETED didn't fit..."; - packetData.discardLevel(propertyLevel); - appendState = OctreeElement::PARTIAL; - } - } else { - //qDebug() << "PROP_SHOULD_BE_DELETED NOT requested..."; - propertiesDidntFit -= PROP_SHOULD_BE_DELETED; - } - // PROP_MASS, if (requestedProperties.getHasProperty(PROP_MASS)) { LevelDetails propertyLevel = packetData.startLevel(); @@ -913,7 +875,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int EntityItemID& entityID, EntityItemProperties& properties) { bool valid = false; - bool wantDebug = false; + bool wantDebug = true; if (wantDebug) { qDebug() << "EntityItemProperties::decodeEntityEditPacket() bytesToRead=" << bytesToRead; } @@ -1045,15 +1007,6 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int properties.setRotation(rotation); } - // PROP_SHOULD_BE_DELETED - if (propertyFlags.getHasProperty(PROP_SHOULD_BE_DELETED)) { - bool shouldBeDeleted; - memcpy(&shouldBeDeleted, dataAt, sizeof(shouldBeDeleted)); - dataAt += sizeof(shouldBeDeleted); - processedBytes += sizeof(shouldBeDeleted); - properties.setShouldBeDeleted(shouldBeDeleted); - } - // PROP_MASS, if (propertyFlags.getHasProperty(PROP_MASS)) { float value; @@ -1186,4 +1139,35 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int } return valid; +} + + +// NOTE: This version will only encode the portion of the edit message immediately following the +// header it does not include the send times and sequence number because that is handled by the +// edit packet sender... +bool EntityItemProperties::encodeEraseEntityMessage(const EntityItemID& entityItemID, + unsigned char* outputBuffer, size_t maxLength, size_t& outputLength) { + + qDebug() << "EntityItemProperties::encodeEraseEntityMessage()"; + + unsigned char* copyAt = outputBuffer; + + uint16_t numberOfIds = 1; // only one entity ID in this message + memcpy(copyAt, &numberOfIds, sizeof(numberOfIds)); + copyAt += sizeof(numberOfIds); + outputLength += sizeof(numberOfIds); + + qDebug() << " numberOfIds=" << numberOfIds; + + QUuid entityID = entityItemID.id; + QByteArray encodedEntityID = entityID.toRfc4122(); + memcpy(copyAt, encodedEntityID.constData(), NUM_BYTES_RFC4122_UUID); + copyAt += NUM_BYTES_RFC4122_UUID; + outputLength += NUM_BYTES_RFC4122_UUID; + + qDebug() << " entityID=" << entityID; + + qDebug() << " outputLength=" << outputLength; + + return true; } \ No newline at end of file diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index aa7898dd94..73f6cbb6d5 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -63,8 +63,8 @@ enum EntityPropertyList { PROP_ANIMATION_FPS, PROP_ANIMATION_FRAME_INDEX, PROP_ANIMATION_PLAYING, - PROP_SHOULD_BE_DELETED, - PROP_LAST_ITEM = PROP_SHOULD_BE_DELETED + + PROP_LAST_ITEM = PROP_ANIMATION_PLAYING }; typedef PropertyFlags EntityPropertyFlags; @@ -122,14 +122,12 @@ public: float getMaxDimension() const { return _radius * 2.0f; } glm::vec3 getDimensions() const { return glm::vec3(_radius, _radius, _radius) * 2.0f; } const glm::quat& getRotation() const { return _rotation; } - bool getShouldBeDeleted() const { return _shouldBeDeleted; } void setType(EntityTypes::EntityType type) { _type = type; } /// set position in meter units void setPosition(const glm::vec3& value) { _position = value; _positionChanged = true; } void setRadius(float value) { _radius = value; _radiusChanged = true; } void setRotation(const glm::quat& rotation) { _rotation = rotation; _rotationChanged = true; } - void setShouldBeDeleted(bool shouldBeDeleted) { _shouldBeDeleted = shouldBeDeleted; _shouldBeDeletedChanged = true; } float getMass() const { return _mass; } void setMass(float value) { _mass = value; _massChanged = true; } @@ -175,6 +173,10 @@ public: static bool encodeEntityEditPacket(PacketType command, EntityItemID id, const EntityItemProperties& properties, unsigned char* bufferOut, int sizeIn, int& sizeOut); + static bool encodeEraseEntityMessage(const EntityItemID& entityItemID, + unsigned char* outputBuffer, size_t maxLength, size_t& outputLength); + + static bool decodeEntityEditPacket(const unsigned char* data, int bytesToRead, int& processedBytes, EntityItemID& entityID, EntityItemProperties& properties); @@ -189,7 +191,6 @@ private: glm::vec3 _position; float _radius; glm::quat _rotation; - bool _shouldBeDeleted; float _mass; glm::vec3 _velocity; glm::vec3 _gravity; @@ -200,7 +201,6 @@ private: bool _positionChanged; bool _radiusChanged; bool _rotationChanged; - bool _shouldBeDeletedChanged; bool _massChanged; bool _velocityChanged; bool _gravityChanged; diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 77de68a8bd..a91d18d108 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -123,10 +123,6 @@ EntityItemID EntityScriptingInterface::editEntity(EntityItemID entityID, const E // message which takes a list of model id's to delete. void EntityScriptingInterface::deleteEntity(EntityItemID entityID) { - // setup properties to kill the model - EntityItemProperties properties; - properties.setShouldBeDeleted(true); - EntityItemID actualID = entityID; // if the model is unknown, attempt to look it up @@ -138,8 +134,13 @@ void EntityScriptingInterface::deleteEntity(EntityItemID entityID) { if (actualID.id != UNKNOWN_ENTITY_ID) { entityID.id = actualID.id; entityID.isKnownID = true; - //qDebug() << "EntityScriptingInterface::deleteEntity()... isKnownID=" << entityID.isKnownID << "id=" << entityID.id << "creatorTokenID=" << entityID.creatorTokenID; - queueEntityMessage(PacketTypeEntityAddOrEdit, entityID, properties); + + qDebug() << "EntityScriptingInterface::deleteEntity()... " + << "isKnownID=" << entityID.isKnownID + << "id=" << entityID.id + << "creatorTokenID=" << entityID.creatorTokenID; + + getEntityPacketSender()->queueEraseEntityMessage(entityID); } // If we have a local model tree set, then also update it. diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index ea1b738cb5..4f7b352b8f 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -302,9 +302,9 @@ UpdateEntityOperator::UpdateEntityOperator(EntityTree* tree, // does this entity tree element contain the old entity bool UpdateEntityOperator::subTreeContainsOldEntity(OctreeElement* element) { bool elementContainsOldBox = element->getAACube().contains(_oldEntityBox); - bool elementContainsOldCube = element->getAACube().contains(_oldEntityCube); /* + bool elementContainsOldCube = element->getAACube().contains(_oldEntityCube); qDebug() << "UpdateEntityOperator::subTreeContainsOldEntity()...."; qDebug() << " element->getAACube()=" << element->getAACube(); qDebug() << " _oldEntityCube=" << _oldEntityCube; @@ -318,9 +318,9 @@ bool UpdateEntityOperator::subTreeContainsOldEntity(OctreeElement* element) { bool UpdateEntityOperator::subTreeContainsNewEntity(OctreeElement* element) { bool elementContainsNewBox = element->getAACube().contains(_newEntityBox); - bool elementContainsNewCube = element->getAACube().contains(_newEntityCube); /* + bool elementContainsNewCube = element->getAACube().contains(_newEntityCube); qDebug() << "UpdateEntityOperator::subTreeContainsNewEntity()...."; qDebug() << " element->getAACube()=" << element->getAACube(); qDebug() << " _newEntityCube=" << _newEntityCube; @@ -511,7 +511,10 @@ bool EntityTree::updateEntity(const EntityItemID& entityID, const EntityItemProp // You should not call this on existing entities that are already part of the tree! Call updateEntity() EntityTreeElement* containingElement = getContainingElement(entityID); if (!containingElement) { - assert(containingElement); // don't call updateEntity() on entity items that don't exist + //assert(containingElement); // don't call updateEntity() on entity items that don't exist + + qDebug() << "UNEXPECTED!!!! EntityTree::updateEntity() entityID doesn't exist!!! entityID=" << entityID; + return false; } @@ -633,10 +636,23 @@ void DeleteEntityOperator::addEntityIDToDeleteList(const EntityItemID& searchEnt details.cube = details.containingElement->getAACube(); _entitiesToDelete << details; _lookingCount++; + + _tree->trackDeletedEntity(searchEntityID); } } } +void EntityTree::trackDeletedEntity(const EntityItemID& entityID) { + // this is only needed on the server to send delete messages for recently deleted entities to the viewers + if (getIsServer()) { + // set up the deleted entities ID + quint64 deletedAt = usecTimestampNow(); + _recentlyDeletedEntitiesLock.lockForWrite(); + _recentlyDeletedEntityItemIDs.insert(deletedAt, entityID.id); + _recentlyDeletedEntitiesLock.unlock(); + } +} + // does this entity tree element contain the old entity bool DeleteEntityOperator::subTreeContainsSomeEntitiesToDelete(OctreeElement* element) { @@ -1046,8 +1062,15 @@ int EntityTree::processEditPacketData(PacketType packetType, const unsigned char int processedBytes = 0; // we handle these types of "edit" packets switch (packetType) { + case PacketTypeEntityErase: { + qDebug() << "EntityTree::processEditPacketData().... PacketTypeEntityErase ****** packetLength=" << packetLength; + QByteArray dataByteArray((const char*)packetData, packetLength); + processEraseMessageDetails(dataByteArray, senderNode); + break; + } + case PacketTypeEntityAddOrEdit: { - //qDebug() << "EntityTree::processEditPacketData()...."; + qDebug() << "EntityTree::processEditPacketData()...."; EntityItemID entityItemID; EntityItemProperties properties; @@ -1071,21 +1094,10 @@ int EntityTree::processEditPacketData(PacketType packetType, const unsigned char qDebug() << "User attempted to edit an unknown entity."; } } else { - - -// -// NOTE: We need to fix this... we can't have the creator tokens in the server side map... because if we do that -// then we will have multiple creator tokens with the same id from different editors... since assignEntityID() -// checks for the ID already existing in the map, this will assert/abort. -// -// But we do want the creator tokens in the client side version of the map... -// so maybe the fix is just to .... - - // this is a new entity... assign a new entityID -qDebug() << "EntityTree::processEditPacketData() ... BEFORE assignEntityID()... entityItemID=" << entityItemID; + qDebug() << "EntityTree::processEditPacketData() ... BEFORE assignEntityID()... entityItemID=" << entityItemID; entityItemID = assignEntityID(entityItemID); -qDebug() << "EntityTree::processEditPacketData() ... AFTER assignEntityID()... entityItemID=" << entityItemID; + qDebug() << "EntityTree::processEditPacketData() ... AFTER assignEntityID()... entityItemID=" << entityItemID; EntityItem* newEntity = addEntity(entityItemID, properties); if (newEntity) { @@ -1130,13 +1142,6 @@ void EntityTree::removeNewlyCreatedHook(NewlyCreatedEntityHook* hook) { } -bool EntityTree::updateOperation(OctreeElement* element, void* extraData) { - EntityTreeUpdateArgs* args = static_cast(extraData); - EntityTreeElement* entityTreeElement = static_cast(element); - entityTreeElement->update(*args); - return true; -} - void EntityTree::changeEntityState(EntityItem* const entity, EntityItem::SimuationState oldState, EntityItem::SimuationState newState) { bool wantDebug = false; @@ -1302,7 +1307,7 @@ bool EntityTree::hasEntitiesDeletedSince(quint64 sinceTime) { bool hasSomethingNewer = false; _recentlyDeletedEntitiesLock.lockForRead(); - QMultiMap::const_iterator iterator = _recentlyDeletedEntityItemIDs.constBegin(); + QMultiMap::const_iterator iterator = _recentlyDeletedEntityItemIDs.constBegin(); while (iterator != _recentlyDeletedEntityItemIDs.constEnd()) { //qDebug() << "considering... time/key:" << iterator.key(); if (iterator.key() > sinceTime) { @@ -1357,28 +1362,30 @@ qDebug() << "EntityTree::encodeEntitiesDeletedSince()"; // we keep a multi map of entity IDs to timestamps, we only want to include the entity IDs that have been // deleted since we last sent to this node _recentlyDeletedEntitiesLock.lockForRead(); - QMultiMap::const_iterator iterator = _recentlyDeletedEntityItemIDs.constBegin(); + QMultiMap::const_iterator iterator = _recentlyDeletedEntityItemIDs.constBegin(); while (iterator != _recentlyDeletedEntityItemIDs.constEnd()) { - QList values = _recentlyDeletedEntityItemIDs.values(iterator.key()); + QList values = _recentlyDeletedEntityItemIDs.values(iterator.key()); for (int valueItem = 0; valueItem < values.size(); ++valueItem) { // if the timestamp is more recent then out last sent time, include it if (iterator.key() > sinceTime) { - uint32_t entityID = values.at(valueItem); - memcpy(copyAt, &entityID, sizeof(entityID)); - copyAt += sizeof(entityID); - outputLength += sizeof(entityID); + QUuid entityID = values.at(valueItem); + + QByteArray encodedEntityID = entityID.toRfc4122(); + memcpy(copyAt, encodedEntityID.constData(), NUM_BYTES_RFC4122_UUID); + copyAt += NUM_BYTES_RFC4122_UUID; + outputLength += NUM_BYTES_RFC4122_UUID; numberOfIds++; // check to make sure we have room for one more id... - if (outputLength + sizeof(uint32_t) > maxLength) { + if (outputLength + NUM_BYTES_RFC4122_UUID > maxLength) { break; } } } // check to make sure we have room for one more id... - if (outputLength + sizeof(uint32_t) > maxLength) { + if (outputLength + NUM_BYTES_RFC4122_UUID > maxLength) { // let our caller know how far we got sinceTime = iterator.key(); @@ -1398,14 +1405,14 @@ qDebug() << "EntityTree::encodeEntitiesDeletedSince()"; return hasMoreToSend; } -// called by the server when it knows all nodes have been sent deleted packets +// called by the server when it knows all nodes have been sent deleted packets void EntityTree::forgetEntitiesDeletedBefore(quint64 sinceTime) { //qDebug() << "forgetEntitiesDeletedBefore()"; QSet keysToRemove; _recentlyDeletedEntitiesLock.lockForWrite(); - QMultiMap::iterator iterator = _recentlyDeletedEntityItemIDs.begin(); + QMultiMap::iterator iterator = _recentlyDeletedEntityItemIDs.begin(); // First find all the keys in the map that are older and need to be deleted while (iterator != _recentlyDeletedEntityItemIDs.end()) { @@ -1426,10 +1433,6 @@ void EntityTree::forgetEntitiesDeletedBefore(quint64 sinceTime) { void EntityTree::processEraseMessage(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode) { - -#if 0 /////////////// - - qDebug() << "EntityTree::processEraseMessage()..."; const unsigned char* packetData = (const unsigned char*)dataByteArray.constData(); @@ -1449,18 +1452,25 @@ void EntityTree::processEraseMessage(const QByteArray& dataByteArray, const Shar dataAt += sizeof(numberOfIds); processedBytes += sizeof(numberOfIds); + qDebug() << "EntityTree::processEraseMessage().... numberOfIds=" << numberOfIds; + qDebug() << "EntityTree::processEraseMessage().... processedBytes=" << processedBytes; + qDebug() << "EntityTree::processEraseMessage().... packetLength=" << packetLength; + if (numberOfIds > 0) { QSet entityItemIDsToDelete; for (size_t i = 0; i < numberOfIds; i++) { - if (processedBytes + sizeof(uint32_t) > packetLength) { + + + if (processedBytes + NUM_BYTES_RFC4122_UUID > packetLength) { + qDebug() << "EntityTree::processEraseMessage().... bailing because not enough bytes in buffer"; break; // bail to prevent buffer overflow } - uint32_t entityID = 0; // placeholder for now - memcpy(&entityID, dataAt, sizeof(entityID)); - dataAt += sizeof(entityID); - processedBytes += sizeof(entityID); + QByteArray encodedID = dataByteArray.mid(processedBytes, NUM_BYTES_RFC4122_UUID); + QUuid entityID = QUuid::fromRfc4122(encodedID); + dataAt += encodedID.size(); + processedBytes += encodedID.size(); EntityItemID entityItemID(entityID); entityItemIDsToDelete << entityItemID; @@ -1469,9 +1479,49 @@ void EntityTree::processEraseMessage(const QByteArray& dataByteArray, const Shar qDebug() << "EntityTree::processEraseMessage()... deleteEntities(entityItemIDsToDelete)"; deleteEntities(entityItemIDsToDelete); } - -#endif // 0 /////////////// - +} + +// This version skips over the header +void EntityTree::processEraseMessageDetails(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode) { + qDebug() << "EntityTree::processEraseMessageDetails()..."; + + const unsigned char* packetData = (const unsigned char*)dataByteArray.constData(); + const unsigned char* dataAt = packetData; + size_t packetLength = dataByteArray.size(); + size_t processedBytes = 0; + + uint16_t numberOfIds = 0; // placeholder for now + memcpy(&numberOfIds, dataAt, sizeof(numberOfIds)); + dataAt += sizeof(numberOfIds); + processedBytes += sizeof(numberOfIds); + + qDebug() << "EntityTree::processEraseMessageDetails().... numberOfIds=" << numberOfIds; + qDebug() << "EntityTree::processEraseMessageDetails().... processedBytes=" << processedBytes; + qDebug() << "EntityTree::processEraseMessageDetails().... packetLength=" << packetLength; + + if (numberOfIds > 0) { + QSet entityItemIDsToDelete; + + for (size_t i = 0; i < numberOfIds; i++) { + + + if (processedBytes + NUM_BYTES_RFC4122_UUID > packetLength) { + qDebug() << "EntityTree::processEraseMessageDetails().... bailing because not enough bytes in buffer"; + break; // bail to prevent buffer overflow + } + + QByteArray encodedID = dataByteArray.mid(processedBytes, NUM_BYTES_RFC4122_UUID); + QUuid entityID = QUuid::fromRfc4122(encodedID); + dataAt += encodedID.size(); + processedBytes += encodedID.size(); + + EntityItemID entityItemID(entityID); + entityItemIDsToDelete << entityItemID; + qDebug() << "EntityTree::processEraseMessageDetails()... entityItemIDsToDelete << entityItemID=" << entityItemID; + } + qDebug() << "EntityTree::processEraseMessageDetails()... deleteEntities(entityItemIDsToDelete)"; + deleteEntities(entityItemIDsToDelete); + } } diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 97016ed922..769589f1e7 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -101,6 +101,7 @@ public: void forgetEntitiesDeletedBefore(quint64 sinceTime); void processEraseMessage(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode); + void processEraseMessageDetails(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode); void handleAddEntityResponse(const QByteArray& packet); EntityItemFBXService* getFBXService() const { return _fbxService; } @@ -119,9 +120,10 @@ public: void changeEntityState(EntityItem* const entity, EntityItem::SimuationState oldState, EntityItem::SimuationState newState); + void trackDeletedEntity(const EntityItemID& entityID); + private: - static bool updateOperation(OctreeElement* element, void* extraData); static bool findAndUpdateOperation(OctreeElement* element, void* extraData); static bool findAndUpdateWithIDandPropertiesOperation(OctreeElement* element, void* extraData); static bool findNearPointOperation(OctreeElement* element, void* extraData); @@ -137,8 +139,9 @@ private: QReadWriteLock _newlyCreatedHooksLock; QVector _newlyCreatedHooks; + QReadWriteLock _recentlyDeletedEntitiesLock; - QMultiMap _recentlyDeletedEntityItemIDs; + QMultiMap _recentlyDeletedEntityItemIDs; EntityItemFBXService* _fbxService; QHash _entityToElementMap; diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 377735df82..a940fd4f1d 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -280,51 +280,6 @@ bool EntityTreeElement::bestFitBounds(const glm::vec3& minPoint, const glm::vec3 return false; } - -void EntityTreeElement::update(EntityTreeUpdateArgs& args) { - args._totalElements++; - // update our contained entities - QList::iterator entityItr = _entityItems->begin(); - while(entityItr != _entityItems->end()) { - EntityItem* entity = (*entityItr); - args._totalItems++; - - // TODO: this _lastChanged isn't actually changing because we're not marking this element as changed. - // how do we want to handle this??? We really only want to consider an element changed when it is - // edited... not just animated... - entity->update(_lastChanged); - - - // If the entity wants to die, or if it's left our bounding box, then move it - // into the arguments moving entities. These will be added back or deleted completely - if (entity->getShouldBeDeleted() || !bestFitEntityBounds(entity)) { - qDebug() << "EntityTreeElement::update()... OLD DELETE LOGIC CALLED BUT NOT IMPLEMENTED..."; - - /*** - // TODO: What to do about this??? - - args._movingEntities.push_back(entity); - - // erase this entity - entityItr = _entityItems->erase(entityItr); - - args._movingItems++; - - // this element has changed so mark it... - markWithChangedTime(); - - // TODO: is this a good place to change the containing element map??? - qDebug() << "EntityTreeElement::update()... calling _myTree->setContainingElement(entity.getEntityItemID(), NULL); ********"; - _myTree->setContainingElement(entity->getEntityItemID(), NULL); - **/ - - - } else { - ++entityItr; - } - } -} - bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, void** intersectedObject) { diff --git a/libraries/entities/src/EntityTreeElement.h b/libraries/entities/src/EntityTreeElement.h index 3125a968a4..4a4b5009ad 100644 --- a/libraries/entities/src/EntityTreeElement.h +++ b/libraries/entities/src/EntityTreeElement.h @@ -114,7 +114,6 @@ public: QList& getEntities() { return *_entityItems; } bool hasEntities() const { return _entityItems ? _entityItems->size() > 0 : false; } - void update(EntityTreeUpdateArgs& args); void setTree(EntityTree* tree) { _myTree = tree; } bool updateEntity(const EntityItem& entity); diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index fd73e6a7d3..55aea9713e 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -255,10 +255,16 @@ int ModelEntityItem::oldVersionReadEntityDataFromBuffer(const unsigned char* dat dataAt += sizeof(_color); bytesRead += sizeof(_color); + // TODO: how to handle this? Presumable, this would only ever be true if the model file was saved with + // a model being in a shouldBeDeleted state. Which seems unlikely. But if it happens, maybe we should delete the entity after loading? // shouldBeDeleted - memcpy(&_shouldBeDeleted, dataAt, sizeof(_shouldBeDeleted)); - dataAt += sizeof(_shouldBeDeleted); - bytesRead += sizeof(_shouldBeDeleted); + bool shouldBeDeleted = false; + memcpy(&shouldBeDeleted, dataAt, sizeof(shouldBeDeleted)); + dataAt += sizeof(shouldBeDeleted); + bytesRead += sizeof(shouldBeDeleted); + if (shouldBeDeleted) { + qDebug() << "UNEXPECTED - read shouldBeDeleted=TRUE from an old format file"; + } // modelURL uint16_t modelURLLength; diff --git a/libraries/networking/src/PacketHeaders.cpp b/libraries/networking/src/PacketHeaders.cpp index f9cbed70b8..ffe6e8e2de 100644 --- a/libraries/networking/src/PacketHeaders.cpp +++ b/libraries/networking/src/PacketHeaders.cpp @@ -77,7 +77,7 @@ PacketVersion versionForPacketType(PacketType type) { case PacketTypeEntityData: return VERSION_ENTITIES_SUPPORT_SPLIT_MTU; case PacketTypeEntityErase: - return 1; + return 2; case PacketTypeAudioStreamStats: return 1; default: diff --git a/libraries/octree/src/OctreeEditPacketSender.cpp b/libraries/octree/src/OctreeEditPacketSender.cpp index 48a0ecf9a1..e4410942b1 100644 --- a/libraries/octree/src/OctreeEditPacketSender.cpp +++ b/libraries/octree/src/OctreeEditPacketSender.cpp @@ -251,8 +251,10 @@ void OctreeEditPacketSender::queueOctreeEditMessage(PacketType type, unsigned ch if (node->getActiveSocket() && node->getType() == getMyNodeType()) { QUuid nodeUUID = node->getUUID(); bool isMyJurisdiction = true; - - if (_serverJurisdictions) { + + if (type == PacketTypeEntityErase) { + isMyJurisdiction = true; // send erase messages to all servers + } else if (_serverJurisdictions) { // we need to get the jurisdiction for this // here we need to get the "pending packet" for this server _serverJurisdictions->lockForRead(); @@ -265,6 +267,9 @@ void OctreeEditPacketSender::queueOctreeEditMessage(PacketType type, unsigned ch _serverJurisdictions->unlock(); } if (isMyJurisdiction) { + +qDebug() << "OctreeEditPacketSender::queueOctreeEditMessage()... isMyJurisidiction...."; + EditPacketBuffer& packetBuffer = _pendingEditPackets[nodeUUID]; packetBuffer._nodeUUID = nodeUUID; @@ -272,11 +277,17 @@ void OctreeEditPacketSender::queueOctreeEditMessage(PacketType type, unsigned ch if ((type != packetBuffer._currentType && packetBuffer._currentSize > 0) || (packetBuffer._currentSize + length >= _maxPacketSize)) { releaseQueuedPacket(packetBuffer); + +qDebug() << "OctreeEditPacketSender::queueOctreeEditMessage()... SWITCHING TYPE...initializePacket()...."; + initializePacket(packetBuffer, type); } // If the buffer is empty and not correctly initialized for our type... if (type != packetBuffer._currentType && packetBuffer._currentSize == 0) { + +qDebug() << "OctreeEditPacketSender::queueOctreeEditMessage()... SWITCHING TYPE...initializePacket()...."; + initializePacket(packetBuffer, type); } @@ -285,12 +296,19 @@ void OctreeEditPacketSender::queueOctreeEditMessage(PacketType type, unsigned ch // We call this virtual function that allows our specific type of EditPacketSender to // fixup the buffer for any clock skew if (node->getClockSkewUsec() != 0) { +qDebug() << "OctreeEditPacketSender::queueOctreeEditMessage()... adjustEditPacketForClockSkew()...."; adjustEditPacketForClockSkew(editPacketBuffer, length, node->getClockSkewUsec()); } +qDebug() << "OctreeEditPacketSender::queueOctreeEditMessage()... memcpy(&packetBuffer...)...."; +qDebug() << " BEFORE packetBuffer._currentSize=" << packetBuffer._currentSize; + memcpy(&packetBuffer._currentBuffer[packetBuffer._currentSize], editPacketBuffer, length); packetBuffer._currentSize += length; packetBuffer._satoshiCost += satoshiCost; + +qDebug() << " AFTER packetBuffer._currentSize=" << packetBuffer._currentSize; + } } }