Merge pull request #4158 from ZappoMan/fixGlitches

fix last simulated and last updated to correctly be sent over the wire
This commit is contained in:
Andrew Meadows 2015-01-23 16:45:27 -08:00
commit 18e0a91ea8
8 changed files with 49 additions and 136 deletions

View file

@ -140,9 +140,17 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet
ByteCountCoded<quint32> 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<quint64> updateDeltaCoder = updateDelta;
QByteArray encodedUpdateDelta = updateDeltaCoder;
// last simulated (velocity, angular velocity, physics changes)
quint64 simulatedDelta = getLastSimulated() <= getLastEdited() ? 0 : getLastSimulated() - getLastEdited();
ByteCountCoded<quint64> 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<quint64> 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;
}
}

View file

@ -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;

View file

@ -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);

View file

@ -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);

View file

@ -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;

View file

@ -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:

View file

@ -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

View file

@ -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);