diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 1ebde85d65..91aef39eea 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -140,9 +140,17 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet ByteCountCoded typeCoder = getType(); QByteArray encodedType = typeCoder; - quint64 updateDelta = getLastSimulated() <= getLastEdited() ? 0 : getLastSimulated() - getLastEdited(); + // last updated (animations, non-physics changes) + quint64 updateDelta = getLastUpdated() <= getLastEdited() ? 0 : getLastUpdated() - getLastEdited(); ByteCountCoded updateDeltaCoder = updateDelta; QByteArray encodedUpdateDelta = updateDeltaCoder; + + // last simulated (velocity, angular velocity, physics changes) + quint64 simulatedDelta = getLastSimulated() <= getLastEdited() ? 0 : getLastSimulated() - getLastEdited(); + ByteCountCoded simulatedDeltaCoder = simulatedDelta; + QByteArray encodedSimulatedDelta = simulatedDeltaCoder; + + EntityPropertyFlags propertyFlags(PROP_LAST_ITEM); EntityPropertyFlags requestedProperties = getEntityProperties(params); EntityPropertyFlags propertiesDidntFit = requestedProperties; @@ -170,6 +178,7 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet bool successCreatedFits = false; bool successLastEditedFits = false; bool successLastUpdatedFits = false; + bool successLastSimulatedFits = false; bool successPropertyFlagsFits = false; int propertyFlagsOffset = 0; int oldPropertyFlagsLength = 0; @@ -189,8 +198,11 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet if (successLastEditedFits) { successLastUpdatedFits = packetData->appendValue(encodedUpdateDelta); } - if (successLastUpdatedFits) { + successLastSimulatedFits = packetData->appendValue(encodedSimulatedDelta); + } + + if (successLastSimulatedFits) { propertyFlagsOffset = packetData->getUncompressedByteOffset(); encodedPropertyFlags = propertyFlags; oldPropertyFlagsLength = encodedPropertyFlags.length(); @@ -458,6 +470,25 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef encodedUpdateDelta = updateDeltaCoder; // determine true length dataAt += encodedUpdateDelta.size(); bytesRead += encodedUpdateDelta.size(); + + // Newer bitstreams will have a last simulated and a last updated value + if (args.bitstreamVersion >= VERSION_ENTITIES_HAS_LAST_SIMULATED_TIME) { + // last simulated is stored as ByteCountCoded delta from lastEdited + QByteArray encodedSimulatedDelta = originalDataBuffer.mid(bytesRead); // maximum possible size + ByteCountCoded simulatedDeltaCoder = encodedSimulatedDelta; + quint64 simulatedDelta = simulatedDeltaCoder; + if (overwriteLocalData) { + _lastSimulated = lastEditedFromBufferAdjusted + simulatedDelta; // don't adjust for clock skew since we already did that + if (wantDebug) { + qDebug() << "_lastSimulated =" << _lastSimulated; + qDebug() << "_lastEdited=" << _lastEdited; + qDebug() << "lastEditedFromBufferAdjusted=" << lastEditedFromBufferAdjusted; + } + } + encodedSimulatedDelta = simulatedDeltaCoder; // determine true length + dataAt += encodedSimulatedDelta.size(); + bytesRead += encodedSimulatedDelta.size(); + } // Property Flags QByteArray encodedPropertyFlags = originalDataBuffer.mid(bytesRead); // maximum possible size @@ -521,6 +552,12 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef recalculateCollisionShape(); if (overwriteLocalData && (getDirtyFlags() & (EntityItem::DIRTY_POSITION | EntityItem::DIRTY_VELOCITY))) { + // TODO: Andrew & Brad to discuss -- this probably should not be "now" but instead should be the last + // simulated time from server. The logic should maybe be: the position changed from the server, so the + // position we just set can be thought of as the position at the time it was last simulated by the + // server (clock skew adjusted). By setting it to "now" we are saying that the last position is to be + // considered to be the correct position for "now" which is likely in the future from when it actually + // was at that last known positition. _lastSimulated = now; } } @@ -833,6 +870,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) { setLastEdited(now); } if (getDirtyFlags() & (EntityItem::DIRTY_POSITION | EntityItem::DIRTY_VELOCITY)) { + // TODO: Andrew & Brad to discuss. Is this correct? Maybe it is. Need to think through all cases. _lastSimulated = now; } } diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index d266a30f62..df619e2f69 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -126,6 +126,7 @@ public: // perform update virtual void update(const quint64& now) { _lastUpdated = now; } + quint64 getLastUpdated() const { return _lastUpdated; } // perform linear extrapolation for SimpleEntitySimulation void simulate(const quint64& now); @@ -296,9 +297,10 @@ protected: QUuid _id; uint32_t _creatorTokenID; bool _newlyCreated; - quint64 _lastSimulated; // last time this entity called simulate() - quint64 _lastUpdated; // last time this entity called update() + quint64 _lastSimulated; // last time this entity called simulate(), this includes velocity, angular velocity, and physics changes + quint64 _lastUpdated; // last time this entity called update(), this includes animations and non-physics changes quint64 _lastEdited; // last official local or remote edit time + quint64 _lastEditedFromRemote; // last time we received and edit from the server quint64 _lastEditedFromRemoteInRemoteTime; // last time we received and edit from the server (in server-time-frame) quint64 _created; diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index e8c8a93165..405cbecd99 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -60,7 +60,8 @@ public: // own definition. Implement these to allow your octree based server to support editing virtual bool getWantSVOfileVersions() const { return true; } virtual PacketType expectedDataPacketType() const { return PacketTypeEntityData; } - virtual bool canProcessVersion(PacketVersion thisVersion) const { return true; } // we support all versions + virtual bool canProcessVersion(PacketVersion thisVersion) const + { return thisVersion >= VERSION_ENTITIES_SUPPORT_SPLIT_MTU; } // we support all versions with split mtu virtual bool handlesEditPacketType(PacketType packetType) const; virtual int processEditPacketData(PacketType packetType, const unsigned char* packetData, int packetLength, const unsigned char* editData, int maxLength, const SharedNodePointer& senderNode); diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index 4cdec0f29a..2c3dcd0600 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -81,17 +81,6 @@ bool ModelEntityItem::setProperties(const EntityItemProperties& properties) { return somethingChanged; } - - -int ModelEntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args) { - if (args.bitstreamVersion < VERSION_ENTITIES_SUPPORT_SPLIT_MTU) { - return oldVersionReadEntityDataFromBuffer(data, bytesLeftToRead, args); - } - - // let our base class do most of the work... it will call us back for our porition... - return EntityItem::readEntityDataFromBuffer(data, bytesLeftToRead, args); -} - int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args, EntityPropertyFlags& propertyFlags, bool overwriteLocalData) { @@ -131,122 +120,6 @@ int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, return bytesRead; } -int ModelEntityItem::oldVersionReadEntityDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args) { - - int bytesRead = 0; - if (bytesLeftToRead >= expectedBytes()) { - int clockSkew = args.sourceNode ? args.sourceNode->getClockSkewUsec() : 0; - - const unsigned char* dataAt = data; - - // id - // this old bitstream format had 32bit IDs. They are obsolete and need to be replaced with our new UUID - // format. We can simply read and ignore the old ID since they should not be repeated. This code should only - // run on loading from an old file. - quint32 oldID; - memcpy(&oldID, dataAt, sizeof(oldID)); - dataAt += sizeof(oldID); - bytesRead += sizeof(oldID); - _id = QUuid::createUuid(); - - // _lastUpdated - memcpy(&_lastUpdated, dataAt, sizeof(_lastUpdated)); - dataAt += sizeof(_lastUpdated); - bytesRead += sizeof(_lastUpdated); - _lastUpdated -= clockSkew; - - // _lastEdited - memcpy(&_lastEdited, dataAt, sizeof(_lastEdited)); - dataAt += sizeof(_lastEdited); - bytesRead += sizeof(_lastEdited); - _lastEdited -= clockSkew; - _created = _lastEdited; // NOTE: old models didn't have age or created time, assume their last edit was a create - - QString ageAsString = formatSecondsElapsed(getAge()); - qDebug() << "Loading old model file, _created = _lastEdited =" << _created - << " age=" << getAge() << "seconds - " << ageAsString - << "old ID=" << oldID << "new ID=" << _id; - - // radius - float radius; - memcpy(&radius, dataAt, sizeof(radius)); - dataAt += sizeof(radius); - bytesRead += sizeof(radius); - setRadius(radius); - - // position - memcpy(&_position, dataAt, sizeof(_position)); - dataAt += sizeof(_position); - bytesRead += sizeof(_position); - - // color - memcpy(&_color, dataAt, sizeof(_color)); - 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 - 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; - memcpy(&modelURLLength, dataAt, sizeof(modelURLLength)); - dataAt += sizeof(modelURLLength); - bytesRead += sizeof(modelURLLength); - QString modelURLString((const char*)dataAt); - setModelURL(modelURLString); - dataAt += modelURLLength; - bytesRead += modelURLLength; - - // rotation - int bytes = unpackOrientationQuatFromBytes(dataAt, _rotation); - dataAt += bytes; - bytesRead += bytes; - - if (args.bitstreamVersion >= VERSION_ENTITIES_HAVE_ANIMATION) { - // animationURL - uint16_t animationURLLength; - memcpy(&animationURLLength, dataAt, sizeof(animationURLLength)); - dataAt += sizeof(animationURLLength); - bytesRead += sizeof(animationURLLength); - QString animationURLString((const char*)dataAt); - setAnimationURL(animationURLString); - dataAt += animationURLLength; - bytesRead += animationURLLength; - - // animationIsPlaying - bool animationIsPlaying; - memcpy(&animationIsPlaying, dataAt, sizeof(animationIsPlaying)); - dataAt += sizeof(animationIsPlaying); - bytesRead += sizeof(animationIsPlaying); - setAnimationIsPlaying(animationIsPlaying); - - // animationFrameIndex - float animationFrameIndex; - memcpy(&animationFrameIndex, dataAt, sizeof(animationFrameIndex)); - dataAt += sizeof(animationFrameIndex); - bytesRead += sizeof(animationFrameIndex); - setAnimationFrameIndex(animationFrameIndex); - - // animationFPS - float animationFPS; - memcpy(&animationFPS, dataAt, sizeof(animationFPS)); - dataAt += sizeof(animationFPS); - bytesRead += sizeof(animationFPS); - setAnimationFPS(animationFPS); - } - } - return bytesRead; -} - - // TODO: eventually only include properties changed since the params.lastViewFrustumSent time EntityPropertyFlags ModelEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); diff --git a/libraries/entities/src/ModelEntityItem.h b/libraries/entities/src/ModelEntityItem.h index dc236644b7..a607745475 100644 --- a/libraries/entities/src/ModelEntityItem.h +++ b/libraries/entities/src/ModelEntityItem.h @@ -40,7 +40,6 @@ public: OctreeElement::AppendState& appendState) const; - virtual int readEntityDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args); virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args, EntityPropertyFlags& propertyFlags, bool overwriteLocalData); @@ -116,8 +115,6 @@ public: protected: - /// For reading models from pre V3 bitstreams - int oldVersionReadEntityDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args); bool isAnimatingSomething() const; rgbColor _color; diff --git a/libraries/networking/src/PacketHeaders.cpp b/libraries/networking/src/PacketHeaders.cpp index 110892a106..07228c8351 100644 --- a/libraries/networking/src/PacketHeaders.cpp +++ b/libraries/networking/src/PacketHeaders.cpp @@ -72,7 +72,7 @@ PacketVersion versionForPacketType(PacketType type) { return 1; case PacketTypeEntityAddOrEdit: case PacketTypeEntityData: - return VERSION_ENTITIES_HAVE_USER_DATA; + return VERSION_ENTITIES_HAS_LAST_SIMULATED_TIME; case PacketTypeEntityErase: return 2; case PacketTypeAudioStreamStats: diff --git a/libraries/networking/src/PacketHeaders.h b/libraries/networking/src/PacketHeaders.h index 87d93b931f..f0d21ca9f8 100644 --- a/libraries/networking/src/PacketHeaders.h +++ b/libraries/networking/src/PacketHeaders.h @@ -126,6 +126,7 @@ const PacketVersion VERSION_ENTITIES_HAS_FILE_BREAKS = VERSION_ENTITIES_SUPPORT_ const PacketVersion VERSION_ENTITIES_SUPPORT_DIMENSIONS = 4; const PacketVersion VERSION_ENTITIES_MODELS_HAVE_ANIMATION_SETTINGS = 5; const PacketVersion VERSION_ENTITIES_HAVE_USER_DATA = 6; +const PacketVersion VERSION_ENTITIES_HAS_LAST_SIMULATED_TIME = 7; const PacketVersion VERSION_OCTREE_HAS_FILE_BREAKS = 1; #endif // hifi_PacketHeaders_h diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index f22487b8ea..96897ff527 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -217,6 +217,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ if (_numNonMovingUpdates <= 1) { // we only update lastEdited when we're sending new physics data // (i.e. NOT when we just simulate the positions forward, nore when we resend non-moving data) + // NOTE: Andrew & Brad to discuss. Let's make sure we're using lastEdited, lastSimulated, and lastUpdated correctly quint64 lastSimulated = _entity->getLastSimulated(); _entity->setLastEdited(lastSimulated); properties.setLastEdited(lastSimulated);