diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index d2e3acb86d..7819063074 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); @@ -100,17 +99,17 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) { EntityItem::EntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) { _type = EntityTypes::Unknown; - _lastEdited = 0; - _lastEditedFromRemote = 0; - _lastEditedFromRemoteInRemoteTime = 0; - _lastSimulated = 0; - _lastUpdated = 0; - _created = properties.getCreated(); + quint64 now = usecTimestampNow(); + _created = properties.getCreated() < now ? properties.getCreated() : now; + _lastEdited = _lastEditedFromRemote = _lastSimulated = _lastUpdated = _lastEditedFromRemoteInRemoteTime = _created; _physicsInfo = NULL; _dirtyFlags = 0; _changedOnServer = 0; initFromEntityItemID(entityItemID); setProperties(properties, true); // force copy + if (_lastEdited == 0) { + _lastEdited = _created; + } } EntityItem::~EntityItem() { @@ -142,7 +141,6 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packetData, EncodeBitstreamParams& params, EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData) const { - // ALL this fits... // object ID [16 bytes] // ByteCountCoded(type code) [~1 byte] @@ -372,7 +370,10 @@ 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) { + _created = createdFromBuffer; + _lastEdited = 0; + } if (wantDebug) { quint64 lastEdited = getLastEdited(); @@ -390,8 +391,6 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef quint64 lastEditedFromBuffer = 0; quint64 lastEditedFromBufferAdjusted = 0; - // BOOKMARK: TODO: figure out if we can catch remote updates to EntityItems and build a list in the Tree - // that is then relayed to the physics engine (and other data structures that cache EntityItem data) // TODO: we could make this encoded as a delta from _created // _lastEdited memcpy(&lastEditedFromBuffer, dataAt, sizeof(lastEditedFromBuffer)); @@ -423,14 +422,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; } } @@ -446,7 +445,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; @@ -783,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; } } @@ -813,13 +816,14 @@ 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(); } diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 2aaa7a4528..24759ba4ba 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..397fd15a2f 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,10 @@ EntityItem* EntityTypes::constructEntityItem(const unsigned char* data, int byte EntityItemID tempEntityID(actualID); EntityItemProperties tempProperties; - tempProperties.setCreated(usecTimestampNow()); // this is temporary... + + quint64 now = usecTimestampNow(); + tempProperties.setCreated(now); + tempProperties.setLastEdited(now); return constructEntityItem(entityType, tempEntityID, tempProperties); } diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index bb87155bc3..acfbb954e2 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -113,65 +113,58 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ if (_outgoingPacketFlags) { EntityItemProperties properties = _entity->getProperties(); - if (_outgoingPacketFlags == OUTGOING_DIRTY_PHYSICS_FLAGS) { - // all outgoing physics flags are set - // This is the common case: physics engine has changed object position/velocity. - + if (_outgoingPacketFlags & EntityItem::DIRTY_POSITION) { btTransform worldTrans = _body->getWorldTransform(); bulletToGLM(worldTrans.getOrigin(), _sentPosition); properties.setPosition(_sentPosition + ObjectMotionState::getWorldOffset()); bulletToGLM(worldTrans.getRotation(), _sentRotation); properties.setRotation(_sentRotation); - + } + + if (_outgoingPacketFlags & EntityItem::DIRTY_VELOCITY) { if (_body->isActive()) { bulletToGLM(_body->getLinearVelocity(), _sentVelocity); bulletToGLM(_body->getAngularVelocity(), _sentAngularVelocity); - bulletToGLM(_body->getGravity(), _sentAcceleration); + + // if the speeds are very small we zero them out + const float MINIMUM_EXTRAPOLATION_SPEED_SQUARED = 4.0e-6f; // 2mm/sec + bool zeroSpeed = (glm::length2(_sentVelocity) < MINIMUM_EXTRAPOLATION_SPEED_SQUARED); + if (zeroSpeed) { + _sentVelocity = glm::vec3(0.0f); + } + const float MINIMUM_EXTRAPOLATION_SPIN_SQUARED = 0.004f; // ~0.01 rotation/sec + bool zeroSpin = glm::length2(_sentAngularVelocity) < MINIMUM_EXTRAPOLATION_SPIN_SQUARED; + if (zeroSpin) { + _sentAngularVelocity = glm::vec3(0.0f); + } + + _sentMoving = ! (zeroSpeed && zeroSpin); } else { - _sentVelocity = _sentAngularVelocity = _sentAcceleration = glm::vec3(0.0f); + _sentVelocity = _sentAngularVelocity = glm::vec3(0.0f); + _sentMoving = false; } properties.setVelocity(_sentVelocity); + bulletToGLM(_body->getGravity(), _sentAcceleration); properties.setGravity(_sentAcceleration); properties.setAngularVelocity(_sentAngularVelocity); - } else { - // subset of outgoing physics flags are set - // This is an uncommon case: physics engine change collided with incoming external change - // we only send data for flags that haven't been cleared. - - if (_outgoingPacketFlags & EntityItem::DIRTY_POSITION) { - btTransform worldTrans = _body->getWorldTransform(); - bulletToGLM(worldTrans.getOrigin(), _sentPosition); - properties.setPosition(_sentPosition + ObjectMotionState::getWorldOffset()); - - bulletToGLM(worldTrans.getRotation(), _sentRotation); - properties.setRotation(_sentRotation); - } - - if (_outgoingPacketFlags & EntityItem::DIRTY_VELOCITY) { - if (_body->isActive()) { - bulletToGLM(_body->getLinearVelocity(), _sentVelocity); - bulletToGLM(_body->getAngularVelocity(), _sentAngularVelocity); - bulletToGLM(_body->getGravity(), _sentAcceleration); - } else { - _sentVelocity = _sentAngularVelocity = _sentAcceleration = glm::vec3(0.0f); - } - properties.setVelocity(_sentVelocity); - properties.setAngularVelocity(_sentAngularVelocity); - properties.setGravity(_sentAcceleration); - } } - // TODO: Figure out what LastEdited is used for... - //properties.setLastEdited(now); - glm::vec3 zero(0.0f); - _sentMoving = !(_sentVelocity == zero && _sentAngularVelocity == zero && _sentAcceleration == zero); // RELIABLE_SEND_HACK: count number of updates for entities at rest so we can stop sending them after some limit. if (_sentMoving) { _numNonMovingUpdates = 0; } else { _numNonMovingUpdates++; } + 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) + quint64 lastSimulated = _entity->getLastSimulated(); + _entity->setLastEdited(lastSimulated); + properties.setLastEdited(lastSimulated); + } else { + properties.setLastEdited(_entity->getLastEdited()); + } EntityItemID id(_entity->getID()); EntityEditPacketSender* entityPacketSender = static_cast(packetSender);