mirror of
https://github.com/Armored-Dragon/overte.git
synced 2025-03-11 16:13:16 +01:00
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:
commit
18e0a91ea8
8 changed files with 49 additions and 136 deletions
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue