diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index b271439662..22cfeb3674 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -53,14 +53,13 @@ void EntityItem::initFromEntityItemID(const EntityItemID& entityItemID) { _creatorTokenID = entityItemID.creatorTokenID; // init values with defaults before calling setProperties - //uint64_t now = usecTimestampNow(); _lastEdited = 0; _lastEditedFromRemote = 0; _lastEditedFromRemoteInRemoteTime = 0; _lastSimulated = 0; _lastUpdated = 0; - _created = 0; // TODO: when do we actually want to make this "now" + _created = usecTimestampNow(); _changedOnServer = 0; _position = glm::vec3(0,0,0); @@ -99,16 +98,20 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) { EntityItem::EntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) { _type = EntityTypes::Unknown; - _lastEdited = 0; + quint64 now = usecTimestampNow(); + _created = properties.getCreated() < now ? properties.getCreated() : now; + _lastEdited = _lastEditedFromRemote = _lastSimulated = _lastUpdated = _lastEditedFromRemoteInRemoteTime = _created; _lastEditedFromRemote = 0; _lastEditedFromRemoteInRemoteTime = 0; _lastSimulated = 0; _lastUpdated = 0; - _created = properties.getCreated(); _dirtyFlags = 0; _changedOnServer = 0; initFromEntityItemID(entityItemID); setProperties(properties, true); // force copy + if (_lastEdited == 0) { + _lastEdited = _created; + } } EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& params) const { @@ -367,7 +370,12 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef bytesRead += sizeof(createdFromBuffer); createdFromBuffer -= clockSkew; - _created = createdFromBuffer; // TODO: do we ever want to discard this??? + if (createdFromBuffer < _created) { + // the server claims that this entity has an older creation time + // so we accept it and clear _lastEdited + _created = createdFromBuffer; + _lastEdited = 0; + } if (wantDebug) { quint64 lastEdited = getLastEdited(); @@ -416,14 +424,14 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef if (fromSameServerEdit) { // If this is from the same sever packet, then check against any local changes since we got // the most recent packet from this server time - if (_lastEdited > _lastEditedFromRemote) { + if (_lastEdited >= _lastEditedFromRemote) { ignoreServerPacket = true; } } else { // If this isn't from the same sever packet, then honor our skew adjusted times... // If we've changed our local tree more recently than the new data from this packet // then we will not be changing our values, instead we just read and skip the data - if (_lastEdited > lastEditedFromBufferAdjusted) { + if (_lastEdited >= lastEditedFromBufferAdjusted) { ignoreServerPacket = true; } } @@ -439,7 +447,8 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef qDebug() << "USING NEW data from server!!! ****************"; } - _lastEdited = lastEditedFromBufferAdjusted; + // don't allow _lastEdited to be in the future + _lastEdited = lastEditedFromBufferAdjusted < now ? lastEditedFromBufferAdjusted : now; _lastEditedFromRemote = now; _lastEditedFromRemoteInRemoteTime = lastEditedFromBuffer; @@ -451,7 +460,8 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef ByteCountCoded updateDeltaCoder = encodedUpdateDelta; quint64 updateDelta = updateDeltaCoder; if (overwriteLocalData) { - _lastSimulated = _lastUpdated = lastEditedFromBufferAdjusted + updateDelta; // don't adjust for clock skew since we already did that for _lastEdited + _lastUpdated = lastEditedFromBufferAdjusted + updateDelta; // don't adjust for clock skew since we already did that for _lastEdited + _lastSimulated = now; if (wantDebug) { qDebug() << "_lastUpdated =" << _lastUpdated; qDebug() << "_lastEdited=" << _lastEdited; @@ -576,7 +586,7 @@ void EntityItem::simulate(const quint64& now) { float timeElapsed = (float)(now - _lastSimulated) / (float)(USECS_PER_SECOND); if (wantDebug) { - qDebug() << "********** EntityItem::update()"; + qDebug() << "********** EntityItem::simulate()"; qDebug() << " entity ID=" << getEntityItemID(); qDebug() << " now=" << now; qDebug() << " _lastSimulated=" << _lastSimulated; @@ -612,10 +622,8 @@ void EntityItem::simulate(const quint64& now) { } } - _lastSimulated = now; - if (wantDebug) { - qDebug() << " ********** EntityItem::update() .... SETTING _lastSimulated=" << _lastSimulated; + qDebug() << " ********** EntityItem::simulate() .... SETTING _lastSimulated=" << _lastSimulated; } if (hasAngularVelocity()) { @@ -645,13 +653,13 @@ void EntityItem::simulate(const quint64& now) { } } - if (hasVelocity() || hasGravity()) { + if (hasVelocity()) { glm::vec3 position = getPosition(); glm::vec3 velocity = getVelocity(); glm::vec3 newPosition = position + (velocity * timeElapsed); if (wantDebug) { - qDebug() << " EntityItem::update()...."; + qDebug() << " EntityItem::simulate()...."; qDebug() << " timeElapsed:" << timeElapsed; qDebug() << " old AACube:" << getMaximumAACube(); qDebug() << " old position:" << position; @@ -677,15 +685,15 @@ void EntityItem::simulate(const quint64& now) { } // handle gravity.... - if (hasGravity() && !isRestingOnSurface()) { - velocity += getGravity() * timeElapsed; - } - - // handle resting on surface case, this is definitely a bit of a hack, and it only works on the - // "ground" plane of the domain, but for now it - if (hasGravity() && isRestingOnSurface()) { - velocity.y = 0.0f; - position.y = getDistanceToBottomOfEntity(); + if (hasGravity()) { + // handle resting on surface case, this is definitely a bit of a hack, and it only works on the + // "ground" plane of the domain, but for now it what we've got + if (isRestingOnSurface()) { + velocity.y = 0.0f; + position.y = getDistanceToBottomOfEntity(); + } else { + velocity += getGravity() * timeElapsed; + } } // handle damping for velocity @@ -721,10 +729,12 @@ void EntityItem::simulate(const quint64& now) { qDebug() << " old getAABox:" << getAABox(); } } + + _lastSimulated = now; } bool EntityItem::isMoving() const { - return hasVelocity() || (hasGravity() && !isRestingOnSurface()) || hasAngularVelocity(); + return hasVelocity() || hasAngularVelocity(); } bool EntityItem::lifetimeHasExpired() const { @@ -773,10 +783,13 @@ bool EntityItem::setProperties(const EntityItemProperties& properties, bool forc // handle the setting of created timestamps for the basic new entity case if (forceCopy) { + quint64 now = usecTimestampNow(); if (properties.getCreated() == UNKNOWN_CREATED_TIME) { - _created = usecTimestampNow(); + _created = now; } else if (properties.getCreated() != USE_EXISTING_CREATED_TIME) { - _created = properties.getCreated(); + quint64 created = properties.getCreated(); + // don't allow _created to be in the future + _created = created < now ? created : now; } } @@ -803,13 +816,17 @@ bool EntityItem::setProperties(const EntityItemProperties& properties, bool forc if (somethingChanged) { somethingChangedNotification(); // notify derived classes that something has changed bool wantDebug = false; + uint64_t now = usecTimestampNow(); if (wantDebug) { - uint64_t now = usecTimestampNow(); int elapsed = now - getLastEdited(); qDebug() << "EntityItem::setProperties() AFTER update... edited AGO=" << elapsed << "now=" << now << " getLastEdited()=" << getLastEdited(); } - setLastEdited(properties._lastEdited); + // don't allow _lastEdited to be in the future + setLastEdited(properties._lastEdited < now ? properties._lastEdited : now); + if (getDirtyFlags() & EntityItem::DIRTY_POSITION) { + _lastSimulated = usecTimestampNow(); + } } return somethingChanged; diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index d5a4689657..7455b96f6b 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -85,7 +85,7 @@ public: /// Last edited time of this entity universal usecs quint64 getLastEdited() const { return _lastEdited; } void setLastEdited(quint64 lastEdited) - { _lastEdited = _lastSimulated = _lastUpdated = lastEdited; _changedOnServer = glm::max(lastEdited, _changedOnServer); } + { _lastEdited = _lastUpdated = lastEdited; _changedOnServer = glm::max(lastEdited, _changedOnServer); } float getEditedAgo() const /// Elapsed seconds since this entity was last edited { return (float)(usecTimestampNow() - getLastEdited()) / (float)USECS_PER_SECOND; } @@ -120,9 +120,6 @@ public: static int expectedBytes(); - static bool encodeEntityEditMessageDetails(PacketType command, EntityItemID id, const EntityItemProperties& details, - unsigned char* bufferOut, int sizeIn, int& sizeOut); - static void adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, size_t length, int clockSkew); // perform update diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 642e24beec..e5f78e8fc7 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -95,8 +95,8 @@ enum EntityPropertyList { typedef PropertyFlags EntityPropertyFlags; -const quint64 UNKNOWN_CREATED_TIME = (quint64)(-1); -const quint64 USE_EXISTING_CREATED_TIME = (quint64)(-2); +const quint64 UNKNOWN_CREATED_TIME = 0; +const quint64 USE_EXISTING_CREATED_TIME = 1; /// A collection of properties of an entity item used in the scripting API. Translates between the actual properties of an diff --git a/libraries/entities/src/EntityTypes.cpp b/libraries/entities/src/EntityTypes.cpp index 194df024e0..f7806445bc 100644 --- a/libraries/entities/src/EntityTypes.cpp +++ b/libraries/entities/src/EntityTypes.cpp @@ -71,7 +71,6 @@ bool EntityTypes::registerEntityType(EntityType entityType, const char* name, En EntityItem* EntityTypes::constructEntityItem(EntityType entityType, const EntityItemID& entityID, const EntityItemProperties& properties) { - EntityItem* newEntityItem = NULL; EntityTypeFactory factory = NULL; if (entityType >= 0 && entityType <= LAST) { @@ -129,7 +128,12 @@ EntityItem* EntityTypes::constructEntityItem(const unsigned char* data, int byte EntityItemID tempEntityID(actualID); EntityItemProperties tempProperties; - tempProperties.setCreated(usecTimestampNow()); // this is temporary... + + // we set the Creation and Edit times to 'now', but if the server submits an earlier Creation time + // then it will be accepted + quint64 now = usecTimestampNow(); + tempProperties.setCreated(now); + tempProperties.setLastEdited(now); return constructEntityItem(entityType, tempEntityID, tempProperties); }